@syncular/react 0.15.29 → 0.15.30
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 +7 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime-version.d.ts +6 -0
- package/dist/runtime-version.js +6 -0
- package/dist/vite-config.d.ts +6 -0
- package/dist/vite-config.js +12 -0
- package/dist/vite-hmr.d.ts +14 -5
- package/dist/vite-hmr.js +34 -8
- package/package.json +11 -4
- package/src/index.ts +1 -0
- package/src/runtime-version.ts +6 -0
- package/src/vite-config.ts +12 -0
- package/src/vite-hmr.ts +56 -12
package/README.md
CHANGED
|
@@ -154,11 +154,13 @@ worker can briefly compete for the same persistent OPFS directory. Never wipe
|
|
|
154
154
|
or rename the database in response to a retryable startup error.
|
|
155
155
|
|
|
156
156
|
For Vite, use `retainViteSyncClientResource(hot.data, schema.version,
|
|
157
|
-
createClient)`. It retains a `{ schemaVersion, resource }`
|
|
158
|
-
same-schema HMR
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
157
|
+
createClient)`. It retains a `{ schemaVersion, runtimeVersion, resource }`
|
|
158
|
+
record, reuses it for same-schema HMR on the same published Syncular runtime,
|
|
159
|
+
and awaits old-resource disposal before creating a schema-bump or
|
|
160
|
+
package-upgrade replacement. Request `hot.invalidate()` only when its
|
|
161
|
+
`ownerChanged` result is true and `disposalError` is absent; the official
|
|
162
|
+
example, optimizer exclusion, and upgrade workflow are in the
|
|
163
|
+
[Vite guide](https://syncular.dev/guide-vite/). The helper may close
|
|
162
164
|
the retained client before React runs cleanup for the old provider; Syncular
|
|
163
165
|
absorbs that teardown-only window-release race while still surfacing failures
|
|
164
166
|
from closing the resource itself.
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { normalizeClient } from './client.js';
|
|
|
12
12
|
export { inferTables } from './infer-tables.js';
|
|
13
13
|
export { type SyncBoundaryActions, type SyncBoundaryState, SyncContext, SyncProvider, type SyncProviderProps, SyncStoreContext, } from './provider.js';
|
|
14
14
|
export { createSyncClientResource, isSyncClientResource, type SyncClientResource, type SyncClientResourceSnapshot, } from './resource.js';
|
|
15
|
+
export { SYNCULAR_REACT_RUNTIME_VERSION } from './runtime-version.js';
|
|
15
16
|
export { useReactiveStore, useSyncClient } from './use-client.js';
|
|
16
17
|
export { type UseCommitOutcomesResult, useCommitOutcomes, } from './use-commit-outcomes.js';
|
|
17
18
|
export { type UseConflictsResult, useConflicts } from './use-conflicts.js';
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { normalizeClient } from './client.js';
|
|
|
5
5
|
export { inferTables } from './infer-tables.js';
|
|
6
6
|
export { SyncContext, SyncProvider, SyncStoreContext, } from './provider.js';
|
|
7
7
|
export { createSyncClientResource, isSyncClientResource, } from './resource.js';
|
|
8
|
+
export { SYNCULAR_REACT_RUNTIME_VERSION } from './runtime-version.js';
|
|
8
9
|
export { useReactiveStore, useSyncClient } from './use-client.js';
|
|
9
10
|
export { useCommitOutcomes, } from './use-commit-outcomes.js';
|
|
10
11
|
export { useConflicts } from './use-conflicts.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialized from the repository release version by scripts/version.ts.
|
|
3
|
+
* Vite HMR uses it to replace a worker owner after a Syncular package upgrade
|
|
4
|
+
* even when the application's generated schema version did not change.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SYNCULAR_REACT_RUNTIME_VERSION = "0.15.30";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialized from the repository release version by scripts/version.ts.
|
|
3
|
+
* Vite HMR uses it to replace a worker owner after a Syncular package upgrade
|
|
4
|
+
* even when the application's generated schema version did not change.
|
|
5
|
+
*/
|
|
6
|
+
export const SYNCULAR_REACT_RUNTIME_VERSION = '0.15.30';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-party Syncular browser packages are already ESM. Keeping them out of
|
|
3
|
+
* Vite's dependency optimizer prevents a live worker from referring to a
|
|
4
|
+
* retired hashed optimizer chunk after a package upgrade.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SYNCULAR_VITE_OPTIMIZE_DEPS_EXCLUDE: readonly ["@syncular/client", "@syncular/client/worker", "@syncular/core", "@syncular/crypto", "@syncular/react"];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-party Syncular browser packages are already ESM. Keeping them out of
|
|
3
|
+
* Vite's dependency optimizer prevents a live worker from referring to a
|
|
4
|
+
* retired hashed optimizer chunk after a package upgrade.
|
|
5
|
+
*/
|
|
6
|
+
export const SYNCULAR_VITE_OPTIMIZE_DEPS_EXCLUDE = [
|
|
7
|
+
'@syncular/client',
|
|
8
|
+
'@syncular/client/worker',
|
|
9
|
+
'@syncular/core',
|
|
10
|
+
'@syncular/crypto',
|
|
11
|
+
'@syncular/react',
|
|
12
|
+
];
|
package/dist/vite-hmr.d.ts
CHANGED
|
@@ -3,20 +3,29 @@ import { type SyncClientResource } from './resource.js';
|
|
|
3
3
|
/** The exact value retained in `import.meta.hot.data.syncularClientResource`. */
|
|
4
4
|
export interface RetainedSyncularResource {
|
|
5
5
|
readonly schemaVersion: number;
|
|
6
|
+
readonly runtimeVersion: string;
|
|
6
7
|
readonly resource: SyncClientResource;
|
|
7
8
|
}
|
|
8
9
|
export interface ViteSyncClientResourceResult {
|
|
9
10
|
readonly resource: SyncClientResource;
|
|
10
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Compatibility signal used by existing integrations to invalidate HMR.
|
|
13
|
+
* True when either the schema or Syncular runtime identity changed.
|
|
14
|
+
*/
|
|
11
15
|
readonly schemaChanged: boolean;
|
|
16
|
+
/** True only when a retained owner came from another Syncular release. */
|
|
17
|
+
readonly runtimeChanged: boolean;
|
|
18
|
+
/** True whenever an incompatible retained owner was replaced. */
|
|
19
|
+
readonly ownerChanged: boolean;
|
|
12
20
|
/** A failed close is exposed by `resource` as a startup error. */
|
|
13
21
|
readonly disposalError?: Error;
|
|
14
22
|
}
|
|
15
23
|
type HotData = Record<string, unknown>;
|
|
16
24
|
/**
|
|
17
|
-
* Reuse a Vite-owned client only while its captured generated schema
|
|
18
|
-
*
|
|
19
|
-
* resource
|
|
25
|
+
* Reuse a Vite-owned client only while both its captured generated schema and
|
|
26
|
+
* materialized Syncular runtime identity match. On either change, the prior
|
|
27
|
+
* resource is fully disposed before the replacement resource (and therefore
|
|
28
|
+
* its worker) is constructed.
|
|
20
29
|
*/
|
|
21
|
-
export declare function retainViteSyncClientResource(hotData: HotData | undefined, schemaVersion: number, factory: () => SyncClientLike | Promise<SyncClientLike
|
|
30
|
+
export declare function retainViteSyncClientResource(hotData: HotData | undefined, schemaVersion: number, factory: () => SyncClientLike | Promise<SyncClientLike>, runtimeVersion?: string): Promise<ViteSyncClientResourceResult>;
|
|
22
31
|
export {};
|
package/dist/vite-hmr.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSyncClientResource } from './resource.js';
|
|
2
|
+
import { SYNCULAR_REACT_RUNTIME_VERSION } from './runtime-version.js';
|
|
2
3
|
function errorOf(value) {
|
|
3
4
|
return value instanceof Error ? value : new Error(String(value));
|
|
4
5
|
}
|
|
@@ -23,22 +24,39 @@ function retainedFrom(hotData) {
|
|
|
23
24
|
}
|
|
24
25
|
return {
|
|
25
26
|
schemaVersion: candidate.schemaVersion,
|
|
27
|
+
...(typeof candidate.runtimeVersion === 'string'
|
|
28
|
+
? { runtimeVersion: candidate.runtimeVersion }
|
|
29
|
+
: {}),
|
|
26
30
|
resource: candidate.resource,
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
/**
|
|
30
|
-
* Reuse a Vite-owned client only while its captured generated schema
|
|
31
|
-
*
|
|
32
|
-
* resource
|
|
34
|
+
* Reuse a Vite-owned client only while both its captured generated schema and
|
|
35
|
+
* materialized Syncular runtime identity match. On either change, the prior
|
|
36
|
+
* resource is fully disposed before the replacement resource (and therefore
|
|
37
|
+
* its worker) is constructed.
|
|
33
38
|
*/
|
|
34
|
-
export async function retainViteSyncClientResource(hotData, schemaVersion, factory) {
|
|
39
|
+
export async function retainViteSyncClientResource(hotData, schemaVersion, factory, runtimeVersion = SYNCULAR_REACT_RUNTIME_VERSION) {
|
|
35
40
|
if (!Number.isInteger(schemaVersion) || schemaVersion < 1) {
|
|
36
41
|
throw new TypeError('schemaVersion must be a positive integer');
|
|
37
42
|
}
|
|
43
|
+
if (typeof runtimeVersion !== 'string' ||
|
|
44
|
+
runtimeVersion.length === 0 ||
|
|
45
|
+
runtimeVersion.length > 96) {
|
|
46
|
+
throw new TypeError('runtimeVersion must be a bounded non-empty string');
|
|
47
|
+
}
|
|
38
48
|
const retained = retainedFrom(hotData);
|
|
39
|
-
if (retained?.schemaVersion === schemaVersion
|
|
40
|
-
|
|
49
|
+
if (retained?.schemaVersion === schemaVersion &&
|
|
50
|
+
retained.runtimeVersion === runtimeVersion) {
|
|
51
|
+
return {
|
|
52
|
+
resource: retained.resource,
|
|
53
|
+
schemaChanged: false,
|
|
54
|
+
runtimeChanged: false,
|
|
55
|
+
ownerChanged: false,
|
|
56
|
+
};
|
|
41
57
|
}
|
|
58
|
+
const ownerChanged = retained !== undefined;
|
|
59
|
+
const runtimeChanged = retained !== undefined && retained.runtimeVersion !== runtimeVersion;
|
|
42
60
|
let disposalError;
|
|
43
61
|
if (retained !== undefined) {
|
|
44
62
|
try {
|
|
@@ -52,12 +70,20 @@ export async function retainViteSyncClientResource(hotData, schemaVersion, facto
|
|
|
52
70
|
// whose ordinary provider startup boundary reports the close failure.
|
|
53
71
|
const resource = createSyncClientResource(disposalError === undefined ? factory : () => Promise.reject(disposalError));
|
|
54
72
|
if (hotData !== undefined) {
|
|
55
|
-
const record = {
|
|
73
|
+
const record = {
|
|
74
|
+
schemaVersion,
|
|
75
|
+
runtimeVersion,
|
|
76
|
+
resource,
|
|
77
|
+
};
|
|
56
78
|
hotData.syncularClientResource = record;
|
|
57
79
|
}
|
|
58
80
|
return {
|
|
59
81
|
resource,
|
|
60
|
-
|
|
82
|
+
// Existing apps already invalidate on this property. Preserve that
|
|
83
|
+
// recovery behavior for a same-schema package upgrade.
|
|
84
|
+
schemaChanged: ownerChanged,
|
|
85
|
+
runtimeChanged,
|
|
86
|
+
ownerChanged,
|
|
61
87
|
...(disposalError !== undefined ? { disposalError } : {}),
|
|
62
88
|
};
|
|
63
89
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/react",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.30",
|
|
4
4
|
"description": "React hooks for Syncular offline-first sync",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -33,6 +33,13 @@
|
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
34
34
|
"default": "./dist/index.js"
|
|
35
35
|
}
|
|
36
|
+
},
|
|
37
|
+
"./vite": {
|
|
38
|
+
"bun": "./src/vite-config.ts",
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./dist/vite-config.d.ts",
|
|
41
|
+
"default": "./dist/vite-config.js"
|
|
42
|
+
}
|
|
36
43
|
}
|
|
37
44
|
},
|
|
38
45
|
"files": [
|
|
@@ -48,15 +55,15 @@
|
|
|
48
55
|
"test": "bun test --preload ./test/setup.ts"
|
|
49
56
|
},
|
|
50
57
|
"dependencies": {
|
|
51
|
-
"@syncular/client": "0.15.
|
|
58
|
+
"@syncular/client": "0.15.30"
|
|
52
59
|
},
|
|
53
60
|
"peerDependencies": {
|
|
54
61
|
"react": ">=18.0.0"
|
|
55
62
|
},
|
|
56
63
|
"devDependencies": {
|
|
57
64
|
"@happy-dom/global-registrator": "^20.0.0",
|
|
58
|
-
"@syncular/core": "0.15.
|
|
59
|
-
"@syncular/server": "0.15.
|
|
65
|
+
"@syncular/core": "0.15.30",
|
|
66
|
+
"@syncular/server": "0.15.30",
|
|
60
67
|
"@testing-library/react": "^16.1.0",
|
|
61
68
|
"@types/react": "^18.3.0",
|
|
62
69
|
"react": "^18.3.1",
|
package/src/index.ts
CHANGED
|
@@ -30,6 +30,7 @@ export {
|
|
|
30
30
|
type SyncClientResource,
|
|
31
31
|
type SyncClientResourceSnapshot,
|
|
32
32
|
} from './resource';
|
|
33
|
+
export { SYNCULAR_REACT_RUNTIME_VERSION } from './runtime-version';
|
|
33
34
|
export { useReactiveStore, useSyncClient } from './use-client';
|
|
34
35
|
export {
|
|
35
36
|
type UseCommitOutcomesResult,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialized from the repository release version by scripts/version.ts.
|
|
3
|
+
* Vite HMR uses it to replace a worker owner after a Syncular package upgrade
|
|
4
|
+
* even when the application's generated schema version did not change.
|
|
5
|
+
*/
|
|
6
|
+
export const SYNCULAR_REACT_RUNTIME_VERSION = '0.15.30';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-party Syncular browser packages are already ESM. Keeping them out of
|
|
3
|
+
* Vite's dependency optimizer prevents a live worker from referring to a
|
|
4
|
+
* retired hashed optimizer chunk after a package upgrade.
|
|
5
|
+
*/
|
|
6
|
+
export const SYNCULAR_VITE_OPTIMIZE_DEPS_EXCLUDE = [
|
|
7
|
+
'@syncular/client',
|
|
8
|
+
'@syncular/client/worker',
|
|
9
|
+
'@syncular/core',
|
|
10
|
+
'@syncular/crypto',
|
|
11
|
+
'@syncular/react',
|
|
12
|
+
] as const;
|
package/src/vite-hmr.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import type { SyncClientLike } from './client';
|
|
2
2
|
import { createSyncClientResource, type SyncClientResource } from './resource';
|
|
3
|
+
import { SYNCULAR_REACT_RUNTIME_VERSION } from './runtime-version';
|
|
3
4
|
|
|
4
5
|
/** The exact value retained in `import.meta.hot.data.syncularClientResource`. */
|
|
5
6
|
export interface RetainedSyncularResource {
|
|
6
7
|
readonly schemaVersion: number;
|
|
8
|
+
readonly runtimeVersion: string;
|
|
7
9
|
readonly resource: SyncClientResource;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export interface ViteSyncClientResourceResult {
|
|
11
13
|
readonly resource: SyncClientResource;
|
|
12
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Compatibility signal used by existing integrations to invalidate HMR.
|
|
16
|
+
* True when either the schema or Syncular runtime identity changed.
|
|
17
|
+
*/
|
|
13
18
|
readonly schemaChanged: boolean;
|
|
19
|
+
/** True only when a retained owner came from another Syncular release. */
|
|
20
|
+
readonly runtimeChanged: boolean;
|
|
21
|
+
/** True whenever an incompatible retained owner was replaced. */
|
|
22
|
+
readonly ownerChanged: boolean;
|
|
14
23
|
/** A failed close is exposed by `resource` as a startup error. */
|
|
15
24
|
readonly disposalError?: Error;
|
|
16
25
|
}
|
|
@@ -29,10 +38,12 @@ function isResource(value: unknown): value is SyncClientResource {
|
|
|
29
38
|
);
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
function retainedFrom(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
function retainedFrom(hotData: HotData | undefined):
|
|
42
|
+
| {
|
|
43
|
+
readonly schemaVersion?: number;
|
|
44
|
+
readonly runtimeVersion?: string;
|
|
45
|
+
readonly resource: SyncClientResource;
|
|
46
|
+
}
|
|
36
47
|
| undefined {
|
|
37
48
|
const value = hotData?.syncularClientResource;
|
|
38
49
|
if (isResource(value)) {
|
|
@@ -42,6 +53,7 @@ function retainedFrom(
|
|
|
42
53
|
if (typeof value !== 'object' || value === null) return undefined;
|
|
43
54
|
const candidate = value as {
|
|
44
55
|
readonly schemaVersion?: unknown;
|
|
56
|
+
readonly runtimeVersion?: unknown;
|
|
45
57
|
readonly resource?: unknown;
|
|
46
58
|
};
|
|
47
59
|
if (
|
|
@@ -53,29 +65,53 @@ function retainedFrom(
|
|
|
53
65
|
}
|
|
54
66
|
return {
|
|
55
67
|
schemaVersion: candidate.schemaVersion,
|
|
68
|
+
...(typeof candidate.runtimeVersion === 'string'
|
|
69
|
+
? { runtimeVersion: candidate.runtimeVersion }
|
|
70
|
+
: {}),
|
|
56
71
|
resource: candidate.resource,
|
|
57
72
|
};
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
/**
|
|
61
|
-
* Reuse a Vite-owned client only while its captured generated schema
|
|
62
|
-
*
|
|
63
|
-
* resource
|
|
76
|
+
* Reuse a Vite-owned client only while both its captured generated schema and
|
|
77
|
+
* materialized Syncular runtime identity match. On either change, the prior
|
|
78
|
+
* resource is fully disposed before the replacement resource (and therefore
|
|
79
|
+
* its worker) is constructed.
|
|
64
80
|
*/
|
|
65
81
|
export async function retainViteSyncClientResource(
|
|
66
82
|
hotData: HotData | undefined,
|
|
67
83
|
schemaVersion: number,
|
|
68
84
|
factory: () => SyncClientLike | Promise<SyncClientLike>,
|
|
85
|
+
runtimeVersion = SYNCULAR_REACT_RUNTIME_VERSION,
|
|
69
86
|
): Promise<ViteSyncClientResourceResult> {
|
|
70
87
|
if (!Number.isInteger(schemaVersion) || schemaVersion < 1) {
|
|
71
88
|
throw new TypeError('schemaVersion must be a positive integer');
|
|
72
89
|
}
|
|
90
|
+
if (
|
|
91
|
+
typeof runtimeVersion !== 'string' ||
|
|
92
|
+
runtimeVersion.length === 0 ||
|
|
93
|
+
runtimeVersion.length > 96
|
|
94
|
+
) {
|
|
95
|
+
throw new TypeError('runtimeVersion must be a bounded non-empty string');
|
|
96
|
+
}
|
|
73
97
|
|
|
74
98
|
const retained = retainedFrom(hotData);
|
|
75
|
-
if (
|
|
76
|
-
|
|
99
|
+
if (
|
|
100
|
+
retained?.schemaVersion === schemaVersion &&
|
|
101
|
+
retained.runtimeVersion === runtimeVersion
|
|
102
|
+
) {
|
|
103
|
+
return {
|
|
104
|
+
resource: retained.resource,
|
|
105
|
+
schemaChanged: false,
|
|
106
|
+
runtimeChanged: false,
|
|
107
|
+
ownerChanged: false,
|
|
108
|
+
};
|
|
77
109
|
}
|
|
78
110
|
|
|
111
|
+
const ownerChanged = retained !== undefined;
|
|
112
|
+
const runtimeChanged =
|
|
113
|
+
retained !== undefined && retained.runtimeVersion !== runtimeVersion;
|
|
114
|
+
|
|
79
115
|
let disposalError: Error | undefined;
|
|
80
116
|
if (retained !== undefined) {
|
|
81
117
|
try {
|
|
@@ -91,12 +127,20 @@ export async function retainViteSyncClientResource(
|
|
|
91
127
|
disposalError === undefined ? factory : () => Promise.reject(disposalError),
|
|
92
128
|
);
|
|
93
129
|
if (hotData !== undefined) {
|
|
94
|
-
const record: RetainedSyncularResource = {
|
|
130
|
+
const record: RetainedSyncularResource = {
|
|
131
|
+
schemaVersion,
|
|
132
|
+
runtimeVersion,
|
|
133
|
+
resource,
|
|
134
|
+
};
|
|
95
135
|
hotData.syncularClientResource = record;
|
|
96
136
|
}
|
|
97
137
|
return {
|
|
98
138
|
resource,
|
|
99
|
-
|
|
139
|
+
// Existing apps already invalidate on this property. Preserve that
|
|
140
|
+
// recovery behavior for a same-schema package upgrade.
|
|
141
|
+
schemaChanged: ownerChanged,
|
|
142
|
+
runtimeChanged,
|
|
143
|
+
ownerChanged,
|
|
100
144
|
...(disposalError !== undefined ? { disposalError } : {}),
|
|
101
145
|
};
|
|
102
146
|
}
|