fix: capacitor iOS Buffer read error#933
Conversation
🦋 Changeset detectedLatest commit: 152ea89 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Out of interest, is it RSocket that uses the Buffer polyfill? It would be great if it would use plain Uint8Array natively, but that's probably not easy to change. Looks like there is an open issue for that, but hasn't seen much activity lately: rsocket/rsocket-js#273
Regardless of that, the Capacitor Uint8Array handling is likely still quite slow, but using a native Uint8Array is a step in the right direction at least.
Yeah that is the case. We might be able to override
Indeed 😄 |
This is an alternative solution to the one provided in #905.
Overview
Users have reported errors of the form
When using the PowerSync Capacitor SDK to connect to a PowerSync service.
Background
The PowerSync SDK sync stream client sends binary payloads from the PowerSync service to the PowerSync Rust core by making SQL queries of the form
The RSocket client we use to connect to the PowerSync service requires a polyfill for
Bufferwhich is provided and bundled in the@powersync/commonpackage. This results in thepayloadabove being an instance of the polyfilledBuffer.The Capacitor Community SQLite lib accepts buffer payloads as a dictionary mapping of numerical array indexes to numerical byte values.
/// Parameter parsing logic in the `run`/`execute` method. } else if let obj = value as? [String: Any] { if var keys = Array(obj.keys) as? [String] { if #available(iOS 15.0, *) { keys.sort(using: .localizedStandard) var valuesArr: [UInt8] = [] for key in keys { if let mVal = obj[key] { if let iVal = mVal as? Int { valuesArr.append(UInt8(iVal)) } else { let msg: String = "Error in reading buffer" throw CapacitorSQLiteError.failed(message: msg) } } else { let msg: String = "Error in reading buffer" throw CapacitorSQLiteError.failed(message: msg) } } val.append(valuesArr) } else { let msg: String = "Error buffer sorted not implemented" throw CapacitorSQLiteError.failed(message: msg) } }The above parsing logic will fail with a
Error in reading buffererror if either:InttypeThe
Bufferpolyfil in@powersync/commondefines a few additional fields in it's implementation, which are passed through the native bridge to the Swift SQLite layer. These additional parameters don't meet the above parsing requirements, which cause the error above.For example: in the polyfil, we see an
parentmember being declared.When debugging the Swift parsing logic, we can see this value propagates from JS to Swift
Notice the value for

keyisparentwhich has a value which could not be cast to a numericalIntvalueThe Fix
Only the
Bufferpolyfil contains these incompatible member values. We can create aUint8Arrayview over theBufferand pass that to the SQLite lib instead. This should have minimal overhead.Testing
For some reason, I have not been able to reproduce this issue previously... On the current
mainbranch with an updatedcapacitorpackage from7.4.xto7.6.xI have been able to reproduce the issue.I've confirmed manually that the
example-capacitordemo connects and syncs correctly to a PowerSync service after applying these changes.