@trainstar/synchro-react-native 0.1.2 → 0.3.1
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 +1105 -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/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 +899 -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 +317 -16
package/src/types.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
export type Row = Record<string, unknown>;
|
|
2
2
|
|
|
3
|
+
/** A lossless SQLite BLOB value at the React Native boundary. */
|
|
4
|
+
export interface SQLiteBytes {
|
|
5
|
+
readonly type: 'bytes';
|
|
6
|
+
readonly base64: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** A lossless SQLite INTEGER value outside JavaScript's safe integer range. */
|
|
10
|
+
export interface SQLiteInt64 {
|
|
11
|
+
readonly type: 'int64';
|
|
12
|
+
readonly value: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SQLiteTaggedValue = SQLiteBytes | SQLiteInt64;
|
|
16
|
+
|
|
17
|
+
export type SQLiteBindValue = null | string | number | boolean | SQLiteTaggedValue;
|
|
18
|
+
|
|
3
19
|
export interface ExecResult {
|
|
4
20
|
rowsAffected: number;
|
|
5
21
|
}
|
|
@@ -10,7 +26,7 @@ export interface BatchResult {
|
|
|
10
26
|
|
|
11
27
|
export interface SQLStatement {
|
|
12
28
|
sql: string;
|
|
13
|
-
params?:
|
|
29
|
+
params?: readonly SQLiteBindValue[];
|
|
14
30
|
}
|
|
15
31
|
|
|
16
32
|
export interface ColumnDef {
|
|
@@ -26,26 +42,310 @@ export interface TableOptions {
|
|
|
26
42
|
withoutRowid?: boolean;
|
|
27
43
|
}
|
|
28
44
|
|
|
29
|
-
export interface
|
|
30
|
-
query(sql: string, params?:
|
|
31
|
-
queryOne(sql: string, params?:
|
|
32
|
-
|
|
45
|
+
export interface ReadTransaction {
|
|
46
|
+
query(sql: string, params?: readonly SQLiteBindValue[]): Promise<Row[]>;
|
|
47
|
+
queryOne(sql: string, params?: readonly SQLiteBindValue[]): Promise<Row | null>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Transaction extends ReadTransaction {
|
|
51
|
+
execute(sql: string, params?: readonly SQLiteBindValue[]): Promise<ExecResult>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const SYNC_STATUS_TYPES = [
|
|
55
|
+
'uninitialized',
|
|
56
|
+
'local_ready',
|
|
57
|
+
'connecting',
|
|
58
|
+
'schema_applying',
|
|
59
|
+
'ready',
|
|
60
|
+
'pushing',
|
|
61
|
+
'pulling',
|
|
62
|
+
'rebuilding',
|
|
63
|
+
'backoff',
|
|
64
|
+
'error',
|
|
65
|
+
'stopped',
|
|
66
|
+
] as const;
|
|
67
|
+
|
|
68
|
+
export type SyncStatusType = (typeof SYNC_STATUS_TYPES)[number];
|
|
69
|
+
|
|
70
|
+
export const SYNC_OPERATION_KINDS = [
|
|
71
|
+
'opening',
|
|
72
|
+
'connecting',
|
|
73
|
+
'schema',
|
|
74
|
+
'pushing',
|
|
75
|
+
'pulling',
|
|
76
|
+
'rebuilding',
|
|
77
|
+
'lifecycle',
|
|
78
|
+
'database',
|
|
79
|
+
] as const;
|
|
80
|
+
|
|
81
|
+
export type SyncOperationKind = (typeof SYNC_OPERATION_KINDS)[number];
|
|
82
|
+
|
|
83
|
+
export const SYNC_RECOVERY_ACTIONS = ['retry', 'schema_reset', 'none'] as const;
|
|
84
|
+
|
|
85
|
+
export type SyncRecoveryAction = (typeof SYNC_RECOVERY_ACTIONS)[number];
|
|
86
|
+
|
|
87
|
+
export const SYNC_FAILURE_CODES = [
|
|
88
|
+
'auth_required',
|
|
89
|
+
'client_retired',
|
|
90
|
+
'idempotency_conflict',
|
|
91
|
+
'invalid_request',
|
|
92
|
+
'invalid_response',
|
|
93
|
+
'invalid_schema_reference',
|
|
94
|
+
'invalid_state_transition',
|
|
95
|
+
'local_database',
|
|
96
|
+
'schema_application_failed',
|
|
97
|
+
'sync_integrity_failure',
|
|
98
|
+
'unsupported_schema',
|
|
99
|
+
'upgrade_required',
|
|
100
|
+
'schema_mismatch',
|
|
101
|
+
'server_error',
|
|
102
|
+
'network_error',
|
|
103
|
+
'database_error',
|
|
104
|
+
'local_failure',
|
|
105
|
+
] as const;
|
|
106
|
+
|
|
107
|
+
export type SyncFailureCode = (typeof SYNC_FAILURE_CODES)[number];
|
|
108
|
+
|
|
109
|
+
export const PROTOCOL_ERROR_CODES = [
|
|
110
|
+
'invalid_request',
|
|
111
|
+
'invalid_schema_reference',
|
|
112
|
+
'upgrade_required',
|
|
113
|
+
'auth_required',
|
|
114
|
+
'idempotency_conflict',
|
|
115
|
+
'client_retired',
|
|
116
|
+
'client_generation_expired',
|
|
117
|
+
'rebuild_restart_required',
|
|
118
|
+
'schema_mismatch',
|
|
119
|
+
'retry_later',
|
|
120
|
+
'sync_integrity_failure',
|
|
121
|
+
'capture_pending',
|
|
122
|
+
'temporary_unavailable',
|
|
123
|
+
] as const;
|
|
124
|
+
|
|
125
|
+
export type ProtocolErrorCode = (typeof PROTOCOL_ERROR_CODES)[number];
|
|
126
|
+
|
|
127
|
+
export interface SyncFailure {
|
|
128
|
+
operation: SyncOperationKind;
|
|
129
|
+
code: SyncFailureCode;
|
|
130
|
+
retryable: boolean;
|
|
131
|
+
message: string;
|
|
132
|
+
recoveryAction: SyncRecoveryAction;
|
|
133
|
+
metadata: Record<string, string>;
|
|
33
134
|
}
|
|
34
135
|
|
|
35
|
-
|
|
136
|
+
type DetailFreeSyncStatus = {
|
|
137
|
+
[K in Exclude<SyncStatusType, 'backoff' | 'error'>]: {
|
|
138
|
+
status: K;
|
|
139
|
+
retryAt: null;
|
|
140
|
+
operation: null;
|
|
141
|
+
failure: null;
|
|
142
|
+
};
|
|
143
|
+
}[Exclude<SyncStatusType, 'backoff' | 'error'>];
|
|
144
|
+
|
|
145
|
+
export type SyncStatus =
|
|
146
|
+
| DetailFreeSyncStatus
|
|
147
|
+
| {
|
|
148
|
+
status: 'backoff';
|
|
149
|
+
retryAt: Date;
|
|
150
|
+
operation: SyncOperationKind;
|
|
151
|
+
failure: null;
|
|
152
|
+
}
|
|
153
|
+
| {
|
|
154
|
+
status: 'error';
|
|
155
|
+
retryAt: null;
|
|
156
|
+
operation: null;
|
|
157
|
+
failure: SyncFailure;
|
|
158
|
+
};
|
|
36
159
|
|
|
37
|
-
export type
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
160
|
+
export type JSONValue =
|
|
161
|
+
| null
|
|
162
|
+
| boolean
|
|
163
|
+
| number
|
|
164
|
+
| string
|
|
165
|
+
| JSONValue[]
|
|
166
|
+
| { [key: string]: JSONValue };
|
|
43
167
|
|
|
44
|
-
export
|
|
45
|
-
|
|
46
|
-
|
|
168
|
+
export type MutationOperation = 'insert' | 'upsert' | 'update' | 'delete';
|
|
169
|
+
|
|
170
|
+
export type LocalMutationStatus =
|
|
171
|
+
| 'pending'
|
|
172
|
+
| 'sealed'
|
|
173
|
+
| 'superseded_before_send'
|
|
174
|
+
| 'cancelled_before_send'
|
|
175
|
+
| 'blocked_by_predecessor'
|
|
176
|
+
| 'server_rejected';
|
|
177
|
+
|
|
178
|
+
export type MutationStatus = 'applied' | 'conflict' | 'rejected_terminal';
|
|
179
|
+
|
|
180
|
+
export type MutationRejectionCode =
|
|
181
|
+
| 'version_conflict'
|
|
182
|
+
| 'row_already_exists'
|
|
183
|
+
| 'row_deleted'
|
|
184
|
+
| 'row_not_found'
|
|
185
|
+
| 'schema_incompatible'
|
|
186
|
+
| 'policy_rejected'
|
|
187
|
+
| 'validation_failed'
|
|
188
|
+
| 'table_not_synced';
|
|
189
|
+
|
|
190
|
+
export interface SchemaRef {
|
|
191
|
+
version: number;
|
|
192
|
+
hash: string;
|
|
47
193
|
}
|
|
48
194
|
|
|
195
|
+
export interface AuthoredMutationField {
|
|
196
|
+
fieldID: string;
|
|
197
|
+
logicalType: string;
|
|
198
|
+
value: JSONValue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface PendingMutationInspection {
|
|
202
|
+
mutationID: string;
|
|
203
|
+
localOrder: number;
|
|
204
|
+
tableID: string;
|
|
205
|
+
tableName: string;
|
|
206
|
+
recordID: string;
|
|
207
|
+
primaryKeyFieldID: string;
|
|
208
|
+
primaryKeyLogicalType: string;
|
|
209
|
+
operation: MutationOperation;
|
|
210
|
+
authoredSchema: SchemaRef;
|
|
211
|
+
baseVersion: string | null;
|
|
212
|
+
clientVersion: string;
|
|
213
|
+
status: LocalMutationStatus;
|
|
214
|
+
sourceKind: string;
|
|
215
|
+
dependsOnMutationID: string | null;
|
|
216
|
+
normalizedMutationID: string | null;
|
|
217
|
+
sealedBatchID: string | null;
|
|
218
|
+
sealedOrdinal: number | null;
|
|
219
|
+
authoredFields: AuthoredMutationField[];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface RejectedMutationInspection {
|
|
223
|
+
mutationID: string;
|
|
224
|
+
tableName: string;
|
|
225
|
+
recordID: string;
|
|
226
|
+
status: MutationStatus;
|
|
227
|
+
code: MutationRejectionCode;
|
|
228
|
+
message: string | null;
|
|
229
|
+
serverRowJSON: string | null;
|
|
230
|
+
serverVersion: string | null;
|
|
231
|
+
mutationJSON: string;
|
|
232
|
+
rejectionJSON: string;
|
|
233
|
+
createdAt: string;
|
|
234
|
+
updatedAt: string;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface ScopeStateInspection {
|
|
238
|
+
scopeID: string;
|
|
239
|
+
cursor: string | null;
|
|
240
|
+
checksum: string | null;
|
|
241
|
+
localChecksum: string;
|
|
242
|
+
generation: number;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface ScopeRowInspection {
|
|
246
|
+
scopeID: string;
|
|
247
|
+
tableName: string;
|
|
248
|
+
recordID: string;
|
|
249
|
+
checksum: string;
|
|
250
|
+
generation: number;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface RebuildAttemptInspection {
|
|
254
|
+
scopeID: string;
|
|
255
|
+
rebuildID: string;
|
|
256
|
+
clientGeneration: number;
|
|
257
|
+
schemaVersion: number;
|
|
258
|
+
schemaHash: string;
|
|
259
|
+
generation: number;
|
|
260
|
+
cursor: string | null;
|
|
261
|
+
pageLimit: number;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface ClientStateInspection {
|
|
265
|
+
schema: SchemaRef | null;
|
|
266
|
+
scopeStates: ScopeStateInspection[];
|
|
267
|
+
scopeRows: ScopeRowInspection[];
|
|
268
|
+
rebuildAttempts: RebuildAttemptInspection[];
|
|
269
|
+
applicationRowCount: number;
|
|
270
|
+
mutationLedgerCount: number;
|
|
271
|
+
mutationOutcomeCount: number;
|
|
272
|
+
sealedBatchCount: number;
|
|
273
|
+
rejectedMutationCount: number;
|
|
274
|
+
scopeStateCount: number;
|
|
275
|
+
scopeRowCount: number;
|
|
276
|
+
provenanceCount: number;
|
|
277
|
+
rowMetadataCount: number;
|
|
278
|
+
rebuildAttemptCount: number;
|
|
279
|
+
rebuildReceiptCount: number;
|
|
280
|
+
provenanceMaintenanceWorkCursor: string;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export type TransportOperationClass =
|
|
284
|
+
| 'connect'
|
|
285
|
+
| 'pull'
|
|
286
|
+
| 'push'
|
|
287
|
+
| 'checkpoint'
|
|
288
|
+
| 'schemas'
|
|
289
|
+
| 'rebuild'
|
|
290
|
+
| 'other';
|
|
291
|
+
|
|
292
|
+
export interface TransportObservation {
|
|
293
|
+
sequence: number;
|
|
294
|
+
operationClass: TransportOperationClass;
|
|
295
|
+
statusCode: number;
|
|
296
|
+
durationNanoseconds: number;
|
|
297
|
+
cursorFingerprints?: string[];
|
|
298
|
+
cursorFingerprintsComplete?: boolean;
|
|
299
|
+
requestFacts?: Record<string, JSONValue>;
|
|
300
|
+
rebuildResponseFacts?: Record<string, JSONValue>;
|
|
301
|
+
pullResponseFacts?: Record<string, JSONValue>;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface TransportObservationSnapshot {
|
|
305
|
+
observations: TransportObservation[];
|
|
306
|
+
overflowed: boolean;
|
|
307
|
+
sequenceCheckpoint: number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export type SchemaAction = 'none' | 'replace' | 'rebuild_local' | 'unsupported';
|
|
311
|
+
|
|
312
|
+
export interface SyncSchemaEvent {
|
|
313
|
+
source: SchemaRef;
|
|
314
|
+
target: SchemaRef;
|
|
315
|
+
action: SchemaAction;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export interface SyncMutationEvent {
|
|
319
|
+
mutationID: string;
|
|
320
|
+
tableID: string;
|
|
321
|
+
status: MutationStatus;
|
|
322
|
+
rejectionCode: MutationRejectionCode | null;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export interface SyncRebuildEvent {
|
|
326
|
+
scopeID: string;
|
|
327
|
+
rebuildID: string;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export type SyncEvent =
|
|
331
|
+
| {
|
|
332
|
+
type: 'state_changed';
|
|
333
|
+
from: SyncStatusType;
|
|
334
|
+
to: SyncStatusType;
|
|
335
|
+
}
|
|
336
|
+
| ({ type: 'backoff' } & {
|
|
337
|
+
operation: SyncOperationKind;
|
|
338
|
+
attempt: number;
|
|
339
|
+
retryAt: Date;
|
|
340
|
+
})
|
|
341
|
+
| ({ type: 'schema_applying' | 'schema_applied' } & SyncSchemaEvent)
|
|
342
|
+
| ({ type: 'mutation_accepted' | 'mutation_rejected' } & SyncMutationEvent)
|
|
343
|
+
| ({ type: 'rebuild_requested' | 'rebuild_completed' } & SyncRebuildEvent)
|
|
344
|
+
| {
|
|
345
|
+
type: 'failure';
|
|
346
|
+
failure: SyncFailure;
|
|
347
|
+
};
|
|
348
|
+
|
|
49
349
|
export interface ConflictEvent {
|
|
50
350
|
table: string;
|
|
51
351
|
recordID: string;
|
|
@@ -65,7 +365,8 @@ export interface SynchroConfig {
|
|
|
65
365
|
maxRetryAttempts?: number;
|
|
66
366
|
pullPageSize?: number;
|
|
67
367
|
pushBatchSize?: number;
|
|
68
|
-
|
|
368
|
+
seedDatabasePath?: string;
|
|
69
369
|
}
|
|
70
370
|
|
|
71
371
|
export type Unsubscribe = () => void;
|
|
372
|
+
export type AsyncUnsubscribe = () => Promise<void>;
|