@trainstar/synchro-react-native 0.4.0-rc.1 → 0.4.0-rc.3
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 +62 -11
- package/SynchroReactNative.podspec +13 -1
- package/android/build.gradle +1 -1
- package/android/src/androidTest/kotlin/com/trainstar/synchro/rn/SynchroModuleTransactionTest.kt +10 -11
- package/android/src/main/kotlin/com/trainstar/synchro/rn/SynchroModule.kt +22 -2
- package/ios/SynchroModule.swift +292 -270
- package/ios-test-host/main.m +48 -0
- package/ios-tests/SynchroModuleTransactionTests.swift +267 -1
- package/lib/module/NativeSynchro.js.map +1 -1
- package/lib/module/SynchroClient.js +26 -0
- package/lib/module/SynchroClient.js.map +1 -1
- package/lib/module/inspection.js +69 -6
- package/lib/module/inspection.js.map +1 -1
- package/lib/typescript/example/e2e/schema-check.test.d.ts +2 -0
- package/lib/typescript/example/e2e/schema-check.test.d.ts.map +1 -0
- package/lib/typescript/example/src/conformance/runner.d.ts +16 -2
- package/lib/typescript/example/src/conformance/runner.d.ts.map +1 -1
- package/lib/typescript/src/NativeSynchro.d.ts +13 -14
- package/lib/typescript/src/NativeSynchro.d.ts.map +1 -1
- package/lib/typescript/src/SynchroClient.d.ts.map +1 -1
- package/lib/typescript/src/inspection.d.ts +11 -4
- package/lib/typescript/src/inspection.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +18 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +24 -9
- package/src/NativeSynchro.ts +13 -17
- package/src/SynchroClient.ts +32 -0
- package/src/inspection.ts +95 -8
- package/src/types.ts +21 -0
- package/tooling-patches/apply.cjs +163 -0
- package/tooling-patches/cli-clean-20.2.0.patch +21 -0
- package/tooling-patches/cli-config-android-20.2.0.patch +13 -0
- package/tooling-patches/react-native-builder-bob-0.40.18.patch +74 -0
- package/tooling-patches/stream-json-1.9.1.patch +40 -0
package/README.md
CHANGED
|
@@ -4,28 +4,78 @@ React Native TurboModule bridge for Synchro. The package wraps the native Swift
|
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
- React Native
|
|
8
|
-
-
|
|
7
|
+
- React Native `>=0.82.1 <0.89.0` and React `>=19.1.1 <20.0.0`.
|
|
8
|
+
- React Native `0.88.0` requires React `19.3.0` and Node `^22.13.0 || ^24.3.0 || >=26.0.0`.
|
|
9
|
+
- React Native `0.82.1` needs the [fmt 12.1.0 backport](https://trainstar.github.io/synchro/reference/support-policy/#react-native-0821-fmt-backport) with Xcode 27.
|
|
10
|
+
- Applications built with Xcode 27 must adopt the [UIKit scene lifecycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle).
|
|
11
|
+
- iOS `17.0+`
|
|
9
12
|
- Android `minSdk 24`
|
|
10
|
-
- Node `20.19.4+`
|
|
11
13
|
- Android development and CI should use JDK `17`
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
|
-
Install the published package only after Synchro `0.4.0-rc.
|
|
17
|
+
Install the published package only after Synchro `0.4.0-rc.3` is available. Before that,
|
|
16
18
|
use the local artifact flow in
|
|
17
19
|
[Client Consumption](https://trainstar.github.io/synchro/clients/consumption/).
|
|
18
20
|
|
|
19
21
|
```sh
|
|
20
|
-
npm install @trainstar/synchro-react-native@0.4.0-rc.
|
|
22
|
+
npm install @trainstar/synchro-react-native@0.4.0-rc.3
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
Apply the delivered React Native CLI correction after each fresh npm install and
|
|
26
|
+
before you run Codegen, bundle, or native build commands:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install --save-dev --save-exact \
|
|
30
|
+
@react-native-community/cli@20.2.0 \
|
|
31
|
+
@react-native-community/cli-platform-android@20.2.0 \
|
|
32
|
+
@react-native-community/cli-platform-ios@20.2.0
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Pin these CLI packages before the patch command. Default React Native templates
|
|
36
|
+
can install an older CLI.
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
node node_modules/@trainstar/synchro-react-native/tooling-patches/apply.cjs cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The command resolves the CLI from the application that calls it. It verifies
|
|
43
|
+
the expected `20.2.0` source and post-patch SHA-256 values. It rejects another
|
|
44
|
+
version, a missing target, or a target outside the application installation.
|
|
45
|
+
The correction escapes the documented `jsSrcsDir` directory before the CLI
|
|
46
|
+
adds its fixed source-extension glob. It also preserves the CLI's authored
|
|
47
|
+
temporary-cache suffix patterns while treating the host temporary directory as
|
|
48
|
+
a literal prefix. It does not change the upstream version.
|
|
49
|
+
|
|
50
|
+
Applications that use `bunyamin` 1.6.3 with `stream-json` 1.9.1 must also apply
|
|
51
|
+
the delivered correction before they run that tooling:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
node node_modules/@trainstar/synchro-react-native/tooling-patches/apply.cjs stream-json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This correction backports upstream commit
|
|
58
|
+
`2f2d35bbb547306991ded6487a279154d865a358` for both Assembler writes. It
|
|
59
|
+
preserves the installed `stream-json` version and its 1.9.1 reviver behavior.
|
|
60
|
+
|
|
61
|
+
Library projects that run `bob build` must apply the delivered Bob correction
|
|
62
|
+
after each fresh npm installation and before they build:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
node node_modules/@trainstar/synchro-react-native/tooling-patches/apply.cjs bob
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The correction replaces Bob's glob-based removal of its resolved output and
|
|
69
|
+
TypeScript build-info paths with its installed `fs-extra` literal operation.
|
|
70
|
+
It rejects the current project directory and paths outside it before removal.
|
|
71
|
+
It does not change compilation or TypeScript generation.
|
|
72
|
+
|
|
73
|
+
Before you run `pod install`, add these published Synchro `0.4.0-rc.3` dependencies to the
|
|
24
74
|
application `ios/Podfile`:
|
|
25
75
|
|
|
26
76
|
```ruby
|
|
27
|
-
pod 'Synchro', :git => 'https://github.com/trainstar/synchro.git', :tag => 'v0.4.0-rc.
|
|
28
|
-
pod 'GRDB.swift', :git => 'https://github.com/groue/GRDB.swift.git', :tag => 'v7.
|
|
77
|
+
pod 'Synchro', :git => 'https://github.com/trainstar/synchro.git', :tag => 'v0.4.0-rc.3'
|
|
78
|
+
pod 'GRDB.swift', :git => 'https://github.com/groue/GRDB.swift.git', :tag => 'v7.8.0'
|
|
29
79
|
```
|
|
30
80
|
|
|
31
81
|
Then install the pods:
|
|
@@ -214,7 +264,7 @@ When one mutation in a group does not apply, the server applies no mutation of t
|
|
|
214
264
|
|
|
215
265
|
After a failed group with a conflict, local state holds the server row for the conflicting member. It holds local values for every other member. The SDK does not revert those local values. Use `inspectRejectedMutations()` to find them and write new intent.
|
|
216
266
|
|
|
217
|
-
The atomic API requires the Synchro `0.4.0-rc.
|
|
267
|
+
The atomic API requires the Synchro `0.4.0-rc.3` extension and adapter. Use this deployment order:
|
|
218
268
|
|
|
219
269
|
1. Install the `0.4.0` extension and adapter on the server.
|
|
220
270
|
2. Release the client code that calls `atomicWriteTransaction()`.
|
|
@@ -244,8 +294,9 @@ The iOS schema bridge rejects malformed JSON with the existing `UNKNOWN` error c
|
|
|
244
294
|
|
|
245
295
|
## Development
|
|
246
296
|
|
|
247
|
-
The published package
|
|
248
|
-
|
|
297
|
+
The published package requires Node `20.19.4` or later.
|
|
298
|
+
React Native `0.88.0` adds the higher Node requirement listed above.
|
|
299
|
+
Repository development uses the Node `22.20.0` pin in `.nvmrc`.
|
|
249
300
|
|
|
250
301
|
```sh
|
|
251
302
|
make lint-rn
|
|
@@ -10,20 +10,32 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
|
-
s.platforms = { :ios => "
|
|
13
|
+
s.platforms = { :ios => "17.0" }
|
|
14
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
18
|
s.compiler_flags = "-Werror=protocol"
|
|
19
|
+
s.libraries = "c++"
|
|
19
20
|
|
|
20
21
|
s.dependency "Synchro", "= #{s.version}"
|
|
21
22
|
|
|
22
23
|
install_modules_dependencies(s)
|
|
23
24
|
|
|
25
|
+
s.app_spec "TestHost" do |app_spec|
|
|
26
|
+
app_spec.source_files = "ios-test-host/main.m"
|
|
27
|
+
app_spec.info_plist = {
|
|
28
|
+
"UIApplicationSceneManifest" => {
|
|
29
|
+
"UIApplicationSupportsMultipleScenes" => false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
24
34
|
# Test sources stay outside source_files, so production targets never compile them.
|
|
25
35
|
s.test_spec "Tests" do |test_spec|
|
|
26
36
|
test_spec.source_files = "ios-tests/**/*.swift"
|
|
27
37
|
test_spec.requires_app_host = true
|
|
38
|
+
test_spec.app_host_name = "SynchroReactNative/TestHost"
|
|
39
|
+
test_spec.dependency "SynchroReactNative/TestHost"
|
|
28
40
|
end
|
|
29
41
|
end
|
package/android/build.gradle
CHANGED
|
@@ -32,7 +32,7 @@ apply plugin: "kotlin-android"
|
|
|
32
32
|
|
|
33
33
|
apply plugin: "com.facebook.react"
|
|
34
34
|
|
|
35
|
-
def defaultSynchroVersion = "0.4.0-rc.
|
|
35
|
+
def defaultSynchroVersion = "0.4.0-rc.3"
|
|
36
36
|
def resolvedSynchroVersion = findProperty("synchroVersion")?.toString() ?: defaultSynchroVersion
|
|
37
37
|
|
|
38
38
|
android {
|
package/android/src/androidTest/kotlin/com/trainstar/synchro/rn/SynchroModuleTransactionTest.kt
CHANGED
|
@@ -268,7 +268,9 @@ class SynchroModuleTransactionTest {
|
|
|
268
268
|
assertEquals("first", rows.getMap(0)!!.getString("name"))
|
|
269
269
|
val inspection = JSONObject(result.getString("inspection")!!)
|
|
270
270
|
assertEquals(
|
|
271
|
-
setOf("client_state", "retained_mutations", "rejected_mutations"
|
|
271
|
+
setOf("client_state", "retained_mutations", "rejected_mutations", "migration_journal",
|
|
272
|
+
"migration_journal_truncated", "physical_schema", "physical_schema_truncated",
|
|
273
|
+
"accepted_mutation_outcomes", "accepted_mutation_outcomes_truncated"),
|
|
272
274
|
inspection.keys().asSequence().toSet(),
|
|
273
275
|
)
|
|
274
276
|
// bridge_items is a local table, so the mutation ledger stays empty.
|
|
@@ -405,10 +407,7 @@ class SynchroModuleTransactionTest {
|
|
|
405
407
|
}
|
|
406
408
|
|
|
407
409
|
/**
|
|
408
|
-
*
|
|
409
|
-
* @VisibleForTesting subclass. Its legacy-architecture assertion is inert only because the pinned
|
|
410
|
-
* react-android 0.83.0 debug artifact sets UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE to false.
|
|
411
|
-
* This context runs no JavaScript, so these tests do not cover the bridgeless JavaScript host.
|
|
410
|
+
* This context exercises native SQLite calls. The application tests verify JavaScript dispatch.
|
|
412
411
|
*/
|
|
413
412
|
@Suppress("DEPRECATION")
|
|
414
413
|
internal fun bridgeTestContext(context: android.content.Context): BridgeReactContext = BridgeReactContext(context)
|
|
@@ -440,14 +439,14 @@ private class RecordingPromise(val name: String) : Promise {
|
|
|
440
439
|
}
|
|
441
440
|
|
|
442
441
|
override fun resolve(value: Any?) = record { resolved.add(value) }
|
|
443
|
-
override fun reject(code: String
|
|
444
|
-
override fun reject(code: String
|
|
445
|
-
override fun reject(code: String
|
|
442
|
+
override fun reject(code: String?, message: String?) = rejectWith(code, null)
|
|
443
|
+
override fun reject(code: String?, throwable: Throwable?) = rejectWith(code, throwable)
|
|
444
|
+
override fun reject(code: String?, message: String?, throwable: Throwable?) = rejectWith(code, throwable)
|
|
446
445
|
override fun reject(throwable: Throwable) = rejectWith(null, throwable)
|
|
447
446
|
override fun reject(throwable: Throwable, userInfo: WritableMap) = rejectWith(null, throwable)
|
|
448
|
-
override fun reject(code: String
|
|
449
|
-
override fun reject(code: String
|
|
450
|
-
override fun reject(code: String
|
|
447
|
+
override fun reject(code: String?, userInfo: WritableMap) = rejectWith(code, null)
|
|
448
|
+
override fun reject(code: String?, throwable: Throwable?, userInfo: WritableMap) = rejectWith(code, throwable)
|
|
449
|
+
override fun reject(code: String?, message: String?, userInfo: WritableMap) = rejectWith(code, null)
|
|
451
450
|
override fun reject(code: String?, message: String?, throwable: Throwable?, userInfo: WritableMap?) =
|
|
452
451
|
rejectWith(code, throwable)
|
|
453
452
|
|
|
@@ -13,6 +13,9 @@ import com.trainstar.synchro.inspection.SynchroInspection
|
|
|
13
13
|
import com.trainstar.synchro.inspection.TransportObservationCollector
|
|
14
14
|
import com.trainstar.synchro.inspection.TransportObservationSnapshot
|
|
15
15
|
import com.trainstar.synchro.inspection.TransportOperationClass
|
|
16
|
+
import com.trainstar.synchro.inspection.MigrationCheckpoint
|
|
17
|
+
import com.trainstar.synchro.inspection.MigrationJournalInspection
|
|
18
|
+
import com.trainstar.synchro.inspection.PhysicalSchemaColumnInspection
|
|
16
19
|
import com.trainstar.synchro.inspection.withTransportObservation
|
|
17
20
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
18
21
|
import kotlinx.coroutines.*
|
|
@@ -1127,6 +1130,16 @@ class SynchroModule(reactContext: ReactApplicationContext) :
|
|
|
1127
1130
|
}
|
|
1128
1131
|
val inspection = JSONObject().apply {
|
|
1129
1132
|
put("client_state", clientStateJson(snapshot.capture))
|
|
1133
|
+
put("migration_journal", snapshot.capture.migrationJournal?.let {
|
|
1134
|
+
JSONObject(Json.encodeToString(MigrationJournalInspection.serializer(), it))
|
|
1135
|
+
} ?: JSONObject.NULL)
|
|
1136
|
+
put("migration_journal_truncated", snapshot.capture.migrationJournalTruncated)
|
|
1137
|
+
put("physical_schema", JSONArray(snapshot.capture.physicalSchema.map {
|
|
1138
|
+
JSONObject(Json.encodeToString(PhysicalSchemaColumnInspection.serializer(), it))
|
|
1139
|
+
}))
|
|
1140
|
+
put("physical_schema_truncated", snapshot.capture.physicalSchemaTruncated)
|
|
1141
|
+
put("accepted_mutation_outcomes", JSONObject(snapshot.capture.acceptedMutationOutcomes))
|
|
1142
|
+
put("accepted_mutation_outcomes_truncated", snapshot.capture.acceptedMutationOutcomesTruncated)
|
|
1130
1143
|
put("retained_mutations", snapshot.retainedMutations?.let { JSONArray(it.map(::retainedMutationJson)) } ?: JSONObject.NULL)
|
|
1131
1144
|
put("rejected_mutations", snapshot.rejectedMutations?.let { JSONArray(it.map(::retainedRejectionJson)) } ?: JSONObject.NULL)
|
|
1132
1145
|
}
|
|
@@ -1202,7 +1215,8 @@ class SynchroModule(reactContext: ReactApplicationContext) :
|
|
|
1202
1215
|
override fun armTransportPause(operationClass: String, promise: Promise) {
|
|
1203
1216
|
try {
|
|
1204
1217
|
val collector = transportObservationCollector ?: error("Transport observation is not configured")
|
|
1205
|
-
|
|
1218
|
+
val checkpoint = MigrationCheckpoint.fromWire(operationClass)
|
|
1219
|
+
if (checkpoint != null) collector.armPause(checkpoint) else collector.armPause(transportOperationClass(operationClass))
|
|
1206
1220
|
promise.resolve(null)
|
|
1207
1221
|
} catch (error: Exception) {
|
|
1208
1222
|
rejectWithError(promise, error)
|
|
@@ -1220,7 +1234,12 @@ class SynchroModule(reactContext: ReactApplicationContext) :
|
|
|
1220
1234
|
timeoutMs % 1.0 == 0.0,
|
|
1221
1235
|
) { "Transport pause timeout is invalid" }
|
|
1222
1236
|
val collector = transportObservationCollector ?: error("Transport observation is not configured")
|
|
1223
|
-
|
|
1237
|
+
val checkpoint = MigrationCheckpoint.fromWire(operationClass)
|
|
1238
|
+
if (checkpoint != null) {
|
|
1239
|
+
collector.awaitPause(checkpoint, timeoutMs.toLong())
|
|
1240
|
+
} else {
|
|
1241
|
+
collector.awaitPause(transportOperationClass(operationClass), timeoutMs.toLong())
|
|
1242
|
+
}
|
|
1224
1243
|
promise.resolve(null)
|
|
1225
1244
|
} catch (error: Exception) {
|
|
1226
1245
|
rejectWithError(promise, error)
|
|
@@ -1532,6 +1551,7 @@ class SynchroModule(reactContext: ReactApplicationContext) :
|
|
|
1532
1551
|
put("row_metadata_count", capture.rowMetadataCount)
|
|
1533
1552
|
put("rebuild_attempt_count", capture.rebuildAttemptCount)
|
|
1534
1553
|
put("rebuild_receipt_count", capture.rebuildReceiptCount)
|
|
1554
|
+
put("capture_overflowed", capture.overflowed)
|
|
1535
1555
|
put(
|
|
1536
1556
|
"provenance_maintenance_work_cursor",
|
|
1537
1557
|
capture.provenanceMaintenanceWorkCursor.toString(),
|