@trainstar/synchro-react-native 0.1.0
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/LICENSE +20 -0
- package/README.md +122 -0
- package/SynchroReactNative.podspec +22 -0
- package/android/build.gradle +81 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/kotlin/com/trainstar/synchro/rn/SynchroModule.kt +808 -0
- package/android/src/main/kotlin/com/trainstar/synchro/rn/SynchroPackage.kt +32 -0
- package/ios/SynchroModule.mm +368 -0
- package/ios/SynchroModule.swift +970 -0
- package/lib/module/NativeSynchro.js +5 -0
- package/lib/module/NativeSynchro.js.map +1 -0
- package/lib/module/SynchroClient.js +295 -0
- package/lib/module/SynchroClient.js.map +1 -0
- package/lib/module/errors.js +150 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/hooks/index.js +6 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/usePendingChanges.js +25 -0
- package/lib/module/hooks/usePendingChanges.js.map +1 -0
- package/lib/module/hooks/useQuery.js +74 -0
- package/lib/module/hooks/useQuery.js.map +1 -0
- package/lib/module/hooks/useSyncStatus.js +15 -0
- package/lib/module/hooks/useSyncStatus.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeSynchro.d.ts +84 -0
- package/lib/typescript/src/NativeSynchro.d.ts.map +1 -0
- package/lib/typescript/src/SynchroClient.d.ts +30 -0
- package/lib/typescript/src/SynchroClient.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +61 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +4 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/usePendingChanges.d.ts +3 -0
- package/lib/typescript/src/hooks/usePendingChanges.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useQuery.d.ts +12 -0
- package/lib/typescript/src/hooks/useQuery.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useSyncStatus.d.ts +4 -0
- package/lib/typescript/src/hooks/useSyncStatus.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +8 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +55 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +146 -0
- package/src/NativeSynchro.ts +114 -0
- package/src/SynchroClient.ts +424 -0
- package/src/errors.ts +205 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/usePendingChanges.ts +32 -0
- package/src/hooks/useQuery.ts +93 -0
- package/src/hooks/useSyncStatus.ts +17 -0
- package/src/index.ts +41 -0
- package/src/types.ts +71 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import type { SynchroClient } from '../SynchroClient';
|
|
3
|
+
import type { Row } from '../types';
|
|
4
|
+
import type { SynchroError } from '../errors';
|
|
5
|
+
|
|
6
|
+
interface UseQueryResult {
|
|
7
|
+
data: Row[];
|
|
8
|
+
loading: boolean;
|
|
9
|
+
error: SynchroError | null;
|
|
10
|
+
refresh: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function arraysEqual<T>(
|
|
14
|
+
a?: readonly T[],
|
|
15
|
+
b?: readonly T[]
|
|
16
|
+
): boolean {
|
|
17
|
+
if (a === b) return true;
|
|
18
|
+
if (!a || !b) return !a && !b;
|
|
19
|
+
if (a.length !== b.length) return false;
|
|
20
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
21
|
+
if (a[i] !== b[i]) return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function useStableArray<T>(value?: readonly T[]): readonly T[] | undefined {
|
|
27
|
+
const ref = useRef<readonly T[] | undefined>(value);
|
|
28
|
+
if (!arraysEqual(ref.current, value)) {
|
|
29
|
+
ref.current = value ? [...value] : value;
|
|
30
|
+
}
|
|
31
|
+
return ref.current;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useQuery(
|
|
35
|
+
client: SynchroClient,
|
|
36
|
+
sql: string,
|
|
37
|
+
params?: unknown[],
|
|
38
|
+
tables?: string[]
|
|
39
|
+
): UseQueryResult {
|
|
40
|
+
const [data, setData] = useState<Row[]>([]);
|
|
41
|
+
const [loading, setLoading] = useState(true);
|
|
42
|
+
const [error, setError] = useState<SynchroError | null>(null);
|
|
43
|
+
const refreshCounter = useRef(0);
|
|
44
|
+
const [, setRefreshTrigger] = useState(0);
|
|
45
|
+
const stableParams = useStableArray(params);
|
|
46
|
+
const stableTables = useStableArray(tables);
|
|
47
|
+
|
|
48
|
+
const refresh = useCallback(() => {
|
|
49
|
+
refreshCounter.current += 1;
|
|
50
|
+
setRefreshTrigger(refreshCounter.current);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (stableTables && stableTables.length > 0) {
|
|
55
|
+
// Reactive mode: use watch()
|
|
56
|
+
setLoading(true);
|
|
57
|
+
let firstResult = true;
|
|
58
|
+
const unsubscribe = client.watch(sql, stableParams as unknown[] | undefined, stableTables as string[], (rows) => {
|
|
59
|
+
setData(rows);
|
|
60
|
+
setError(null);
|
|
61
|
+
if (firstResult) {
|
|
62
|
+
setLoading(false);
|
|
63
|
+
firstResult = false;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return unsubscribe;
|
|
67
|
+
} else {
|
|
68
|
+
// One-shot mode: use query()
|
|
69
|
+
let cancelled = false;
|
|
70
|
+
setLoading(true);
|
|
71
|
+
client
|
|
72
|
+
.query(sql, stableParams as unknown[] | undefined)
|
|
73
|
+
.then((rows) => {
|
|
74
|
+
if (!cancelled) {
|
|
75
|
+
setData(rows);
|
|
76
|
+
setError(null);
|
|
77
|
+
setLoading(false);
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.catch((err) => {
|
|
81
|
+
if (!cancelled) {
|
|
82
|
+
setError(err);
|
|
83
|
+
setLoading(false);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return () => {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}, [client, sql, stableParams, stableTables, refreshCounter.current]);
|
|
91
|
+
|
|
92
|
+
return { data, loading, error, refresh };
|
|
93
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import type { SynchroClient } from '../SynchroClient';
|
|
3
|
+
import type { SyncStatus } from '../types';
|
|
4
|
+
|
|
5
|
+
export function useSyncStatus(client: SynchroClient): SyncStatus {
|
|
6
|
+
const [status, setStatus] = useState<SyncStatus>({
|
|
7
|
+
status: 'idle',
|
|
8
|
+
retryAt: null,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const unsubscribe = client.onStatusChange(setStatus);
|
|
13
|
+
return unsubscribe;
|
|
14
|
+
}, [client]);
|
|
15
|
+
|
|
16
|
+
return status;
|
|
17
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export { SynchroClient } from './SynchroClient';
|
|
2
|
+
export { useQuery } from './hooks/useQuery';
|
|
3
|
+
export { useSyncStatus } from './hooks/useSyncStatus';
|
|
4
|
+
export { usePendingChanges } from './hooks/usePendingChanges';
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
Row,
|
|
8
|
+
ExecResult,
|
|
9
|
+
BatchResult,
|
|
10
|
+
SQLStatement,
|
|
11
|
+
ColumnDef,
|
|
12
|
+
TableOptions,
|
|
13
|
+
Transaction,
|
|
14
|
+
CheckpointMode,
|
|
15
|
+
SyncStatus,
|
|
16
|
+
SyncStatusType,
|
|
17
|
+
ConflictEvent,
|
|
18
|
+
SynchroConfig,
|
|
19
|
+
Unsubscribe,
|
|
20
|
+
} from './types';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
SynchroError,
|
|
24
|
+
NotConnectedError,
|
|
25
|
+
SchemaNotLoadedError,
|
|
26
|
+
TableNotSyncedError,
|
|
27
|
+
UpgradeRequiredError,
|
|
28
|
+
SchemaMismatchError,
|
|
29
|
+
SnapshotRequiredError,
|
|
30
|
+
PushRejectedError,
|
|
31
|
+
NetworkError,
|
|
32
|
+
ServerError,
|
|
33
|
+
DatabaseError,
|
|
34
|
+
InvalidResponseError,
|
|
35
|
+
AlreadyStartedError,
|
|
36
|
+
NotStartedError,
|
|
37
|
+
TransactionTimeoutError,
|
|
38
|
+
mapNativeError,
|
|
39
|
+
} from './errors';
|
|
40
|
+
|
|
41
|
+
export type { PushResultItem } from './errors';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export type Row = Record<string, unknown>;
|
|
2
|
+
|
|
3
|
+
export interface ExecResult {
|
|
4
|
+
rowsAffected: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface BatchResult {
|
|
8
|
+
totalRowsAffected: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SQLStatement {
|
|
12
|
+
sql: string;
|
|
13
|
+
params?: unknown[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ColumnDef {
|
|
17
|
+
name: string;
|
|
18
|
+
type: string;
|
|
19
|
+
nullable?: boolean;
|
|
20
|
+
primaryKey?: boolean;
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TableOptions {
|
|
25
|
+
ifNotExists?: boolean;
|
|
26
|
+
withoutRowid?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface Transaction {
|
|
30
|
+
query(sql: string, params?: unknown[]): Promise<Row[]>;
|
|
31
|
+
queryOne(sql: string, params?: unknown[]): Promise<Row | null>;
|
|
32
|
+
execute(sql: string, params?: unknown[]): Promise<ExecResult>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type CheckpointMode = 'passive' | 'full' | 'restart' | 'truncate';
|
|
36
|
+
|
|
37
|
+
export type SyncStatusType =
|
|
38
|
+
| 'idle'
|
|
39
|
+
| 'connecting'
|
|
40
|
+
| 'syncing'
|
|
41
|
+
| 'error'
|
|
42
|
+
| 'stopped';
|
|
43
|
+
|
|
44
|
+
export interface SyncStatus {
|
|
45
|
+
status: SyncStatusType;
|
|
46
|
+
retryAt: Date | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ConflictEvent {
|
|
50
|
+
table: string;
|
|
51
|
+
recordID: string;
|
|
52
|
+
clientData: Row | null;
|
|
53
|
+
serverData: Row | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface SynchroConfig {
|
|
57
|
+
dbPath: string;
|
|
58
|
+
serverURL: string;
|
|
59
|
+
authProvider: () => Promise<string>;
|
|
60
|
+
clientID: string;
|
|
61
|
+
platform?: string;
|
|
62
|
+
appVersion: string;
|
|
63
|
+
syncInterval?: number;
|
|
64
|
+
pushDebounce?: number;
|
|
65
|
+
maxRetryAttempts?: number;
|
|
66
|
+
pullPageSize?: number;
|
|
67
|
+
pushBatchSize?: number;
|
|
68
|
+
snapshotPageSize?: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type Unsubscribe = () => void;
|