@trainstar/synchro-react-native 0.1.2 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -24
- package/SynchroReactNative.podspec +3 -2
- package/android/build.gradle +8 -3
- package/android/src/main/kotlin/com/trainstar/synchro/rn/SynchroModule.kt +1106 -238
- package/ios/SynchroModule.mm +178 -51
- package/ios/SynchroModule.swift +1382 -295
- package/lib/module/NativeSynchro.js +5 -0
- package/lib/module/NativeSynchro.js.map +1 -1
- package/lib/module/SynchroClient.js +637 -65
- package/lib/module/SynchroClient.js.map +1 -1
- package/lib/module/digest.js +82 -0
- package/lib/module/digest.js.map +1 -0
- package/lib/module/errors.js +165 -22
- package/lib/module/errors.js.map +1 -1
- package/lib/module/hooks/useQuery.js +37 -3
- package/lib/module/hooks/useQuery.js.map +1 -1
- package/lib/module/hooks/useSyncStatus.js +51 -6
- package/lib/module/hooks/useSyncStatus.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/inspection.js +121 -0
- package/lib/module/inspection.js.map +1 -0
- package/lib/module/sqliteValues.js +87 -0
- package/lib/module/sqliteValues.js.map +1 -0
- package/lib/module/types.js +10 -0
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/example/e2e/corpus-harness.d.ts +34 -0
- package/lib/typescript/example/e2e/corpus-harness.d.ts.map +1 -0
- package/lib/typescript/example/src/conformance/runner.d.ts +125 -0
- package/lib/typescript/example/src/conformance/runner.d.ts.map +1 -0
- package/lib/typescript/example/src/conformance/types.d.ts +71 -0
- package/lib/typescript/example/src/conformance/types.d.ts.map +1 -0
- package/lib/typescript/example/src/timeouts.d.ts +2 -0
- package/lib/typescript/example/src/timeouts.d.ts.map +1 -0
- package/lib/typescript/src/NativeSynchro.d.ts +59 -17
- package/lib/typescript/src/NativeSynchro.d.ts.map +1 -1
- package/lib/typescript/src/SynchroClient.d.ts +27 -10
- package/lib/typescript/src/SynchroClient.d.ts.map +1 -1
- package/lib/typescript/src/digest.d.ts +3 -0
- package/lib/typescript/src/digest.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +37 -9
- package/lib/typescript/src/errors.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useQuery.d.ts +2 -2
- package/lib/typescript/src/hooks/useQuery.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useSyncStatus.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/inspection.d.ts +43 -0
- package/lib/typescript/src/inspection.d.ts.map +1 -0
- package/lib/typescript/src/sqliteValues.d.ts +8 -0
- package/lib/typescript/src/sqliteValues.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +203 -11
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +20 -8
- package/src/NativeSynchro.ts +93 -26
- package/src/SynchroClient.ts +900 -120
- package/src/digest.ts +93 -0
- package/src/errors.ts +273 -33
- package/src/hooks/useQuery.ts +59 -16
- package/src/hooks/useSyncStatus.ts +40 -7
- package/src/index.ts +44 -3
- package/src/inspection.ts +226 -0
- package/src/sqliteValues.ts +105 -0
- package/src/types.ts +318 -16
package/README.md
CHANGED
|
@@ -4,19 +4,31 @@ React Native TurboModule bridge for Synchro. The package wraps the native Swift
|
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
- React Native `0.83.x`
|
|
7
|
+
- React Native `0.83.x`. Use `0.83.5` or later with Xcode `26.4` or later.
|
|
8
8
|
- iOS `16.0+`
|
|
9
9
|
- Android `minSdk 24`
|
|
10
|
-
- Node `20+`
|
|
10
|
+
- Node `20.19.4+`
|
|
11
11
|
- Android development and CI should use JDK `17`
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
+
Install the published package only after Synchro `0.3.2` is available. Before that,
|
|
16
|
+
use the local artifact flow in
|
|
17
|
+
[Client Consumption](https://trainstar.github.io/synchro/clients/consumption/).
|
|
18
|
+
|
|
15
19
|
```sh
|
|
16
|
-
npm install @trainstar/synchro-react-native
|
|
20
|
+
npm install @trainstar/synchro-react-native@0.3.2
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Before you run `pod install`, add these published Synchro `0.3.2` dependencies to the
|
|
24
|
+
application `ios/Podfile`:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
pod 'Synchro', :git => 'https://github.com/trainstar/synchro.git', :tag => 'v0.3.2'
|
|
28
|
+
pod 'GRDB.swift', :git => 'https://github.com/groue/GRDB.swift.git', :tag => 'v7.0.0'
|
|
17
29
|
```
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
Then install the pods:
|
|
20
32
|
|
|
21
33
|
```sh
|
|
22
34
|
cd ios
|
|
@@ -25,25 +37,83 @@ pod install
|
|
|
25
37
|
|
|
26
38
|
Android autolinks through the React Native Gradle plugin. No manual `MainApplication` edits are required.
|
|
27
39
|
|
|
40
|
+
The Android library resolves the native SDK from Maven Central.
|
|
41
|
+
Local Maven resolution is explicit in `example/android/build.gradle` for development.
|
|
42
|
+
|
|
28
43
|
## Usage
|
|
29
44
|
|
|
30
45
|
```ts
|
|
46
|
+
import { Platform } from 'react-native';
|
|
31
47
|
import { SynchroClient } from '@trainstar/synchro-react-native';
|
|
32
48
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
export async function syncQuickstart(
|
|
50
|
+
accessToken: string,
|
|
51
|
+
clientID: string,
|
|
52
|
+
databaseFileName: string
|
|
53
|
+
): Promise<void> {
|
|
54
|
+
const serverURL = Platform.OS === 'android'
|
|
55
|
+
? 'http://10.0.2.2:8091'
|
|
56
|
+
: 'http://127.0.0.1:8091';
|
|
57
|
+
const noteID = '00000000-0000-4000-8000-000000000001';
|
|
58
|
+
const client = new SynchroClient({
|
|
59
|
+
dbPath: databaseFileName,
|
|
60
|
+
serverURL,
|
|
61
|
+
authProvider: async () => accessToken,
|
|
62
|
+
clientID,
|
|
63
|
+
appVersion: '0.3.0',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await client.initialize();
|
|
68
|
+
await client.start();
|
|
69
|
+
await client.syncNow();
|
|
70
|
+
|
|
71
|
+
const note = await client.queryOne(
|
|
72
|
+
'SELECT id, body FROM notes WHERE id = ?',
|
|
73
|
+
[noteID]
|
|
74
|
+
);
|
|
75
|
+
if (note === null || typeof note.id !== 'string' || note.id !== noteID) {
|
|
76
|
+
throw new Error('The first pull did not contain the quickstart note');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await client.stop();
|
|
80
|
+
await client.execute(
|
|
81
|
+
'UPDATE notes SET body = ? WHERE id = ?',
|
|
82
|
+
['Edited offline', noteID]
|
|
83
|
+
);
|
|
84
|
+
await client.start();
|
|
85
|
+
await client.syncNow();
|
|
86
|
+
|
|
87
|
+
const updated = await client.queryOne(
|
|
88
|
+
'SELECT body FROM notes WHERE id = ?',
|
|
89
|
+
[noteID]
|
|
90
|
+
);
|
|
91
|
+
if (
|
|
92
|
+
updated === null ||
|
|
93
|
+
typeof updated.body !== 'string' ||
|
|
94
|
+
updated.body !== 'Edited offline'
|
|
95
|
+
) {
|
|
96
|
+
throw new Error('The synced note did not contain the offline edit');
|
|
97
|
+
}
|
|
98
|
+
} finally {
|
|
99
|
+
await client.close();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
40
103
|
|
|
41
|
-
|
|
42
|
-
|
|
104
|
+
The example uses the local tutorial adapter only. Android emulators reach the
|
|
105
|
+
host at `10.0.2.2`; iOS simulators use `127.0.0.1`. The example app permits
|
|
106
|
+
that cleartext development traffic. Production applications must use HTTPS and
|
|
107
|
+
must not copy the cleartext network configuration.
|
|
43
108
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
109
|
+
`start()` arms the lifecycle. Do not use it as a schema-readiness signal.
|
|
110
|
+
`syncNow()` completes the requested cycle before this example reads the local
|
|
111
|
+
database.
|
|
112
|
+
|
|
113
|
+
SQL bind params are passed as native typed arrays, not as JSON strings. Supported React Native bind values are `null`, `string`, `number`, `boolean`, `{ type: 'int64', value: '...' }`, and `{ type: 'bytes', base64: '...' }`. Positional `null` values are preserved across iOS and Android for direct queries, batch execution, transactions, and query observers.
|
|
114
|
+
|
|
115
|
+
`queryOne()` returns `Row | null`, and each row value is `unknown`. Check for
|
|
116
|
+
both a non-null row and a string `id` before using the value as a note ID.
|
|
47
117
|
|
|
48
118
|
## Public API
|
|
49
119
|
|
|
@@ -67,11 +137,18 @@ Events and hooks:
|
|
|
67
137
|
|
|
68
138
|
- `onStatusChange(callback)`
|
|
69
139
|
- `onConflict(callback)`
|
|
70
|
-
- `onSnapshotRequired(handler)`
|
|
71
140
|
- `useQuery(client, sql, params?, tables?)`
|
|
72
141
|
- `useSyncStatus(client)`
|
|
73
142
|
- `usePendingChanges(client, pollInterval?)`
|
|
74
143
|
|
|
144
|
+
`useQuery` compares `int64` and `bytes` parameters by tag type and payload.
|
|
145
|
+
Equivalent tag objects do not restart the query or subscription.
|
|
146
|
+
|
|
147
|
+
`useSyncStatus` subscribes before it reads current native status.
|
|
148
|
+
New events take priority over the initial snapshot.
|
|
149
|
+
Changing clients resets the displayed status until the new client supplies state.
|
|
150
|
+
Snapshot failures reach the React error boundary unless a newer status event has arrived.
|
|
151
|
+
|
|
75
152
|
## Transactions
|
|
76
153
|
|
|
77
154
|
`writeTransaction()` and `readTransaction()` mirror the native SDKs through a bridge-held transaction session.
|
|
@@ -85,8 +162,8 @@ Contract:
|
|
|
85
162
|
```ts
|
|
86
163
|
await client.writeTransaction(async (tx) => {
|
|
87
164
|
await tx.execute(
|
|
88
|
-
'
|
|
89
|
-
['
|
|
165
|
+
'UPDATE notes SET body = ? WHERE id = ?',
|
|
166
|
+
['Edited offline', '00000000-0000-4000-8000-000000000001']
|
|
90
167
|
);
|
|
91
168
|
});
|
|
92
169
|
```
|
|
@@ -100,7 +177,6 @@ Native errors are normalized to typed JS errors, including:
|
|
|
100
177
|
- `TableNotSyncedError`
|
|
101
178
|
- `UpgradeRequiredError`
|
|
102
179
|
- `SchemaMismatchError`
|
|
103
|
-
- `SnapshotRequiredError`
|
|
104
180
|
- `PushRejectedError`
|
|
105
181
|
- `NetworkError`
|
|
106
182
|
- `ServerError`
|
|
@@ -110,13 +186,16 @@ Native errors are normalized to typed JS errors, including:
|
|
|
110
186
|
- `NotStartedError`
|
|
111
187
|
- `TransactionTimeoutError`
|
|
112
188
|
|
|
189
|
+
The iOS schema bridge rejects malformed JSON with the existing `UNKNOWN` error code.
|
|
190
|
+
|
|
113
191
|
## Development
|
|
114
192
|
|
|
193
|
+
The published package accepts Node `20.19.4` or later. Repository development
|
|
194
|
+
uses the Node `22.20.0` pin in `.nvmrc`.
|
|
195
|
+
|
|
115
196
|
```sh
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
npm run prepare
|
|
119
|
-
npm run pack:dry-run
|
|
197
|
+
make lint-rn
|
|
198
|
+
make test-rn-unit
|
|
120
199
|
```
|
|
121
200
|
|
|
122
201
|
The example app in [`example/`](./example) is the end-to-end harness used for RN bridge verification on iOS and Android.
|
|
@@ -11,12 +11,13 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
13
|
s.platforms = { :ios => "16.0" }
|
|
14
|
-
s.source = { :git => "https://github.com/trainstar/synchro.git", :tag => "#{s.version}" }
|
|
14
|
+
s.source = { :git => "https://github.com/trainstar/synchro.git", :tag => "v#{s.version}" }
|
|
15
15
|
|
|
16
16
|
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
17
17
|
s.private_header_files = "ios/**/*.h"
|
|
18
|
+
s.compiler_flags = "-Werror=protocol"
|
|
18
19
|
|
|
19
|
-
s.dependency "Synchro", "
|
|
20
|
+
s.dependency "Synchro", "= #{s.version}"
|
|
20
21
|
|
|
21
22
|
install_modules_dependencies(s)
|
|
22
23
|
end
|
package/android/build.gradle
CHANGED
|
@@ -17,7 +17,6 @@ buildscript {
|
|
|
17
17
|
repositories {
|
|
18
18
|
google()
|
|
19
19
|
mavenCentral()
|
|
20
|
-
mavenLocal()
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
dependencies {
|
|
@@ -33,6 +32,9 @@ apply plugin: "kotlin-android"
|
|
|
33
32
|
|
|
34
33
|
apply plugin: "com.facebook.react"
|
|
35
34
|
|
|
35
|
+
def defaultSynchroVersion = "0.3.2"
|
|
36
|
+
def resolvedSynchroVersion = findProperty("synchroVersion")?.toString() ?: defaultSynchroVersion
|
|
37
|
+
|
|
36
38
|
android {
|
|
37
39
|
namespace "com.trainstar.synchro.rn"
|
|
38
40
|
|
|
@@ -66,16 +68,19 @@ android {
|
|
|
66
68
|
compileOptions {
|
|
67
69
|
sourceCompatibility JavaVersion.VERSION_1_8
|
|
68
70
|
targetCompatibility JavaVersion.VERSION_1_8
|
|
71
|
+
coreLibraryDesugaringEnabled true
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
repositories {
|
|
73
|
-
|
|
76
|
+
mavenCentral()
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
dependencies {
|
|
80
|
+
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
|
|
77
81
|
implementation "com.facebook.react:react-android"
|
|
78
|
-
implementation "
|
|
82
|
+
implementation "fit.trainstar:synchro:${resolvedSynchroVersion}"
|
|
83
|
+
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
|
|
79
84
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0"
|
|
80
85
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0"
|
|
81
86
|
}
|