on-zero 0.16.17 → 0.16.19
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/dist/cjs/createZeroClient.cjs +44 -11
- package/dist/cjs/createZeroClient.native.js +54 -17
- package/dist/cjs/createZeroClient.native.js.map +1 -1
- package/dist/cjs/createZeroClient.recovery.test.cjs +49 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js +53 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/cjs/generate-helpers.cjs +28 -0
- package/dist/cjs/generate-helpers.native.js +36 -0
- package/dist/cjs/generate-helpers.native.js.map +1 -1
- package/dist/cjs/generate-layout.cjs +62 -53
- package/dist/cjs/generate-layout.native.js +62 -54
- package/dist/cjs/generate-layout.native.js.map +1 -1
- package/dist/cjs/generate-lite.cjs +28 -0
- package/dist/cjs/generate-lite.native.js +89 -33
- package/dist/cjs/generate-lite.native.js.map +1 -1
- package/dist/cjs/generate-lite.test.cjs +46 -0
- package/dist/cjs/generate-lite.test.native.js +46 -0
- package/dist/cjs/generate-lite.test.native.js.map +1 -1
- package/dist/cjs/generate.cjs +237 -243
- package/dist/cjs/generate.native.js +352 -353
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +35 -0
- package/dist/cjs/generate.test.native.js +35 -0
- package/dist/cjs/generate.test.native.js.map +1 -1
- package/dist/cjs/helpers/createMutators.cjs +2 -1
- package/dist/cjs/helpers/createMutators.native.js +3 -1
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.cjs +8 -2
- package/dist/cjs/helpers/recoverZeroClient.native.js +10 -2
- package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.test.cjs +53 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js +55 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/cjs/native-typescript.cjs +190 -0
- package/dist/cjs/native-typescript.native.js +255 -0
- package/dist/cjs/native-typescript.native.js.map +1 -0
- package/dist/esm/createZeroClient.mjs +44 -11
- package/dist/esm/createZeroClient.mjs.map +1 -1
- package/dist/esm/createZeroClient.native.js +54 -17
- package/dist/esm/createZeroClient.native.js.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.mjs +50 -1
- package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.native.js +54 -1
- package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/esm/generate-helpers.mjs +27 -1
- package/dist/esm/generate-helpers.mjs.map +1 -1
- package/dist/esm/generate-helpers.native.js +35 -1
- package/dist/esm/generate-helpers.native.js.map +1 -1
- package/dist/esm/generate-layout.mjs +52 -54
- package/dist/esm/generate-layout.mjs.map +1 -1
- package/dist/esm/generate-layout.native.js +52 -55
- package/dist/esm/generate-layout.native.js.map +1 -1
- package/dist/esm/generate-lite.mjs +29 -1
- package/dist/esm/generate-lite.mjs.map +1 -1
- package/dist/esm/generate-lite.native.js +90 -34
- package/dist/esm/generate-lite.native.js.map +1 -1
- package/dist/esm/generate-lite.test.mjs +46 -0
- package/dist/esm/generate-lite.test.mjs.map +1 -1
- package/dist/esm/generate-lite.test.native.js +46 -0
- package/dist/esm/generate-lite.test.native.js.map +1 -1
- package/dist/esm/generate.mjs +238 -244
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +353 -354
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +35 -0
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +35 -0
- package/dist/esm/generate.test.native.js.map +1 -1
- package/dist/esm/helpers/createMutators.mjs +2 -1
- package/dist/esm/helpers/createMutators.mjs.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +3 -1
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.mjs +8 -2
- package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.native.js +10 -2
- package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.mjs +53 -0
- package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.native.js +55 -0
- package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/native-typescript.mjs +164 -0
- package/dist/esm/native-typescript.mjs.map +1 -0
- package/dist/esm/native-typescript.native.js +226 -0
- package/dist/esm/native-typescript.native.js.map +1 -0
- package/package.json +4 -3
- package/src/createZeroClient.recovery.test.tsx +56 -1
- package/src/createZeroClient.tsx +54 -15
- package/src/generate-helpers.ts +79 -0
- package/src/generate-layout.ts +64 -108
- package/src/generate-lite.test.ts +49 -0
- package/src/generate-lite.ts +44 -0
- package/src/generate.test.ts +52 -0
- package/src/generate.ts +313 -366
- package/src/helpers/createMutators.ts +14 -3
- package/src/helpers/recoverZeroClient.test.ts +50 -0
- package/src/helpers/recoverZeroClient.ts +12 -2
- package/src/native-typescript.ts +176 -0
- package/types/createZeroClient.d.ts.map +1 -1
- package/types/generate-helpers.d.ts +13 -0
- package/types/generate-helpers.d.ts.map +1 -1
- package/types/generate-layout.d.ts +2 -1
- package/types/generate-layout.d.ts.map +1 -1
- package/types/generate-lite.d.ts +1 -0
- package/types/generate-lite.d.ts.map +1 -1
- package/types/generate.d.ts.map +1 -1
- package/types/helpers/createMutators.d.ts.map +1 -1
- package/types/helpers/recoverZeroClient.d.ts.map +1 -1
- package/types/native-typescript.d.ts +11 -0
- package/types/native-typescript.d.ts.map +1 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import { parse } from "@babel/parser";
|
|
4
|
+
import { API } from "typescript/unstable/async";
|
|
5
|
+
var _process_env;
|
|
6
|
+
var _GOMAXPROCS;
|
|
7
|
+
(_GOMAXPROCS = (_process_env = process.env).GOMAXPROCS) !== null && _GOMAXPROCS !== void 0 ? _GOMAXPROCS : _process_env.GOMAXPROCS = "2";
|
|
8
|
+
var compiler = null;
|
|
9
|
+
var compilerClose = null;
|
|
10
|
+
var compilerCloseTimer = null;
|
|
11
|
+
var compilerTurn = Promise.resolve();
|
|
12
|
+
async function closeCompiler(session) {
|
|
13
|
+
try {
|
|
14
|
+
if (session.paths.size > 0) {
|
|
15
|
+
var snapshot = await session.api.updateSnapshot({
|
|
16
|
+
closeFiles: [...session.paths]
|
|
17
|
+
});
|
|
18
|
+
await snapshot.dispose();
|
|
19
|
+
}
|
|
20
|
+
} finally {
|
|
21
|
+
await session.api.close();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function acquireCompiler(root, sourcePaths) {
|
|
25
|
+
var previousTurn = compilerTurn;
|
|
26
|
+
var releaseTurn = function releaseTurn2() {};
|
|
27
|
+
compilerTurn = new Promise(function (resolveTurn) {
|
|
28
|
+
releaseTurn = resolveTurn;
|
|
29
|
+
});
|
|
30
|
+
await previousTurn;
|
|
31
|
+
if (compilerCloseTimer) {
|
|
32
|
+
clearTimeout(compilerCloseTimer);
|
|
33
|
+
compilerCloseTimer = null;
|
|
34
|
+
}
|
|
35
|
+
if (compilerClose) await compilerClose;
|
|
36
|
+
if (compiler && compiler.root !== root) {
|
|
37
|
+
var previous = compiler;
|
|
38
|
+
compiler = null;
|
|
39
|
+
await closeCompiler(previous);
|
|
40
|
+
}
|
|
41
|
+
compiler !== null && compiler !== void 0 ? compiler : compiler = {
|
|
42
|
+
api: new API({
|
|
43
|
+
cwd: root
|
|
44
|
+
}),
|
|
45
|
+
paths: /* @__PURE__ */new Set(),
|
|
46
|
+
root
|
|
47
|
+
};
|
|
48
|
+
compiler.api.clearSourceFileCache();
|
|
49
|
+
var previousPaths = compiler.paths;
|
|
50
|
+
var nextPaths = new Set(sourcePaths);
|
|
51
|
+
compiler.paths = nextPaths;
|
|
52
|
+
if (previousPaths.size > 0) {
|
|
53
|
+
var closedSnapshot = await compiler.api.updateSnapshot({
|
|
54
|
+
closeFiles: [...previousPaths],
|
|
55
|
+
fileChanges: {
|
|
56
|
+
invalidateAll: true
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
await closedSnapshot.dispose();
|
|
60
|
+
compiler.api.clearSourceFileCache();
|
|
61
|
+
}
|
|
62
|
+
var snapshot = await compiler.api.updateSnapshot({
|
|
63
|
+
openFiles: sourcePaths,
|
|
64
|
+
fileChanges: {
|
|
65
|
+
invalidateAll: true
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
compiler.api.clearSourceFileCache();
|
|
69
|
+
return {
|
|
70
|
+
session: compiler,
|
|
71
|
+
snapshot,
|
|
72
|
+
releaseTurn
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function releaseCompiler(session, releaseTurn) {
|
|
76
|
+
var _compilerCloseTimer_unref;
|
|
77
|
+
releaseTurn();
|
|
78
|
+
compilerCloseTimer = setTimeout(function () {
|
|
79
|
+
compilerCloseTimer = null;
|
|
80
|
+
if (compiler !== session) return;
|
|
81
|
+
compiler = null;
|
|
82
|
+
compilerClose = closeCompiler(session).finally(function () {
|
|
83
|
+
compilerClose = null;
|
|
84
|
+
});
|
|
85
|
+
}, 25);
|
|
86
|
+
(_compilerCloseTimer_unref = compilerCloseTimer.unref) === null || _compilerCloseTimer_unref === void 0 ? void 0 : _compilerCloseTimer_unref.call(compilerCloseTimer);
|
|
87
|
+
}
|
|
88
|
+
function collectTypeScriptSourcePaths(roots) {
|
|
89
|
+
var paths = /* @__PURE__ */new Set();
|
|
90
|
+
var visited = /* @__PURE__ */new Set();
|
|
91
|
+
var walk = function walk1(dir) {
|
|
92
|
+
if (visited.has(dir) || !existsSync(dir)) return;
|
|
93
|
+
visited.add(dir);
|
|
94
|
+
var _iteratorNormalCompletion2 = true,
|
|
95
|
+
_didIteratorError2 = false,
|
|
96
|
+
_iteratorError2 = void 0;
|
|
97
|
+
try {
|
|
98
|
+
for (var _iterator2 = readdirSync(dir, {
|
|
99
|
+
withFileTypes: true
|
|
100
|
+
})[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
101
|
+
var entry = _step2.value;
|
|
102
|
+
if (entry.name === "node_modules") continue;
|
|
103
|
+
var path = resolve(dir, entry.name);
|
|
104
|
+
if (entry.isDirectory()) {
|
|
105
|
+
walk(path);
|
|
106
|
+
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
107
|
+
paths.add(path);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
_didIteratorError2 = true;
|
|
112
|
+
_iteratorError2 = err;
|
|
113
|
+
} finally {
|
|
114
|
+
try {
|
|
115
|
+
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
|
|
116
|
+
_iterator2.return();
|
|
117
|
+
}
|
|
118
|
+
} finally {
|
|
119
|
+
if (_didIteratorError2) {
|
|
120
|
+
throw _iteratorError2;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var _iteratorNormalCompletion = true,
|
|
126
|
+
_didIteratorError = false,
|
|
127
|
+
_iteratorError = void 0;
|
|
128
|
+
try {
|
|
129
|
+
for (var _iterator = roots[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
130
|
+
var root = _step.value;
|
|
131
|
+
walk(resolve(root));
|
|
132
|
+
}
|
|
133
|
+
} catch (err) {
|
|
134
|
+
_didIteratorError = true;
|
|
135
|
+
_iteratorError = err;
|
|
136
|
+
} finally {
|
|
137
|
+
try {
|
|
138
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
139
|
+
_iterator.return();
|
|
140
|
+
}
|
|
141
|
+
} finally {
|
|
142
|
+
if (_didIteratorError) {
|
|
143
|
+
throw _iteratorError;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return [...paths].sort();
|
|
148
|
+
}
|
|
149
|
+
async function createNativeTypeScriptProject(root, sourcePaths) {
|
|
150
|
+
if (sourcePaths.length === 0) {
|
|
151
|
+
throw new Error(`[on-zero] no TypeScript source files found under ${root}`);
|
|
152
|
+
}
|
|
153
|
+
var {
|
|
154
|
+
session,
|
|
155
|
+
snapshot,
|
|
156
|
+
releaseTurn
|
|
157
|
+
} = await acquireCompiler(root, sourcePaths);
|
|
158
|
+
var sources = /* @__PURE__ */new Map();
|
|
159
|
+
var projectsByFile = /* @__PURE__ */new Map();
|
|
160
|
+
var parseErrors = /* @__PURE__ */new Set();
|
|
161
|
+
try {
|
|
162
|
+
var _iteratorNormalCompletion = true,
|
|
163
|
+
_didIteratorError = false,
|
|
164
|
+
_iteratorError = void 0;
|
|
165
|
+
try {
|
|
166
|
+
for (var _iterator = sourcePaths[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
167
|
+
var path = _step.value;
|
|
168
|
+
var project = await snapshot.getDefaultProjectForFile(path);
|
|
169
|
+
if (!project) throw new Error(`[on-zero] TypeScript did not open ${path}`);
|
|
170
|
+
var source = await project.program.getSourceFile(path);
|
|
171
|
+
if (!source) throw new Error(`[on-zero] TypeScript did not parse ${path}`);
|
|
172
|
+
sources.set(path, source);
|
|
173
|
+
projectsByFile.set(path, project);
|
|
174
|
+
try {
|
|
175
|
+
parse(readFileSync(path, "utf8"), {
|
|
176
|
+
plugins: ["jsx", "typescript"],
|
|
177
|
+
sourceType: "module"
|
|
178
|
+
});
|
|
179
|
+
} catch (unused) {
|
|
180
|
+
parseErrors.add(path);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} catch (err) {
|
|
184
|
+
_didIteratorError = true;
|
|
185
|
+
_iteratorError = err;
|
|
186
|
+
} finally {
|
|
187
|
+
try {
|
|
188
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
189
|
+
_iterator.return();
|
|
190
|
+
}
|
|
191
|
+
} finally {
|
|
192
|
+
if (_didIteratorError) {
|
|
193
|
+
throw _iteratorError;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
await snapshot.dispose();
|
|
199
|
+
releaseCompiler(session, releaseTurn);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
var closed = false;
|
|
203
|
+
return {
|
|
204
|
+
projectForFile(path2) {
|
|
205
|
+
var project2 = projectsByFile.get(resolve(path2));
|
|
206
|
+
if (!project2) throw new Error(`[on-zero] TypeScript project does not contain ${path2}`);
|
|
207
|
+
return project2;
|
|
208
|
+
},
|
|
209
|
+
sourceFile(path2) {
|
|
210
|
+
var source2 = sources.get(resolve(path2));
|
|
211
|
+
if (!source2) throw new Error(`[on-zero] TypeScript project does not contain ${path2}`);
|
|
212
|
+
return source2;
|
|
213
|
+
},
|
|
214
|
+
hasParseErrors(path2) {
|
|
215
|
+
return parseErrors.has(resolve(path2));
|
|
216
|
+
},
|
|
217
|
+
async close() {
|
|
218
|
+
if (closed) return;
|
|
219
|
+
closed = true;
|
|
220
|
+
await snapshot.dispose();
|
|
221
|
+
releaseCompiler(session, releaseTurn);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
export { collectTypeScriptSourcePaths, createNativeTypeScriptProject };
|
|
226
|
+
//# sourceMappingURL=native-typescript.native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["existsSync","readFileSync","readdirSync","resolve","parse","API","_process_env","_GOMAXPROCS","process","env","GOMAXPROCS","compiler","compilerClose","compilerCloseTimer","compilerTurn","Promise","closeCompiler","session","paths","size","snapshot","api","updateSnapshot","closeFiles","dispose","close","acquireCompiler","root","sourcePaths","previousTurn","releaseTurn","releaseTurn2","resolveTurn","clearTimeout","previous","cwd","Set","clearSourceFileCache","previousPaths","nextPaths","closedSnapshot","fileChanges","invalidateAll","openFiles","releaseCompiler","_compilerCloseTimer_unref","setTimeout","finally","unref","call","collectTypeScriptSourcePaths","roots","visited","walk","walk1","dir","has","add","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_iterator2","withFileTypes","Symbol","iterator","_step2","next","done","entry","value","name","path","isDirectory","isFile","endsWith","err","return","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","_step"],"sources":["../../src/native-typescript.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "on-zero",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.19",
|
|
4
4
|
"description": "A typed layer over @rocicorp/zero with queries, mutations, and permissions",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -101,11 +101,13 @@
|
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
103
|
"dependencies": {
|
|
104
|
+
"@babel/parser": "7.29.7",
|
|
104
105
|
"@rocicorp/logger": "6.2.0",
|
|
105
106
|
"chokidar": "^4.0.3",
|
|
106
107
|
"citty": "^0.1.6",
|
|
107
108
|
"dequal": "^2.0.3",
|
|
108
|
-
"orez-lite": "0.16.
|
|
109
|
+
"orez-lite": "0.16.19",
|
|
110
|
+
"typescript": "7.0.2",
|
|
109
111
|
"valibot": "^1.1.0"
|
|
110
112
|
},
|
|
111
113
|
"peerDependencies": {
|
|
@@ -136,7 +138,6 @@
|
|
|
136
138
|
"react": "^19.0.0",
|
|
137
139
|
"react-dom": "^19.0.0",
|
|
138
140
|
"react-native": "*",
|
|
139
|
-
"typescript": "^5.9.3",
|
|
140
141
|
"vitest": "^3.1.1"
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
2
|
|
|
3
|
-
import { createSchema, string, table } from '@rocicorp/zero'
|
|
3
|
+
import { createSchema, string, table, UpdateNeededReasonType } from '@rocicorp/zero'
|
|
4
4
|
import { act, Suspense, useLayoutEffect } from 'react'
|
|
5
5
|
import { createRoot, type Root } from 'react-dom/client'
|
|
6
6
|
import { afterEach, beforeEach, expect, test, vi } from 'vitest'
|
|
@@ -137,6 +137,37 @@ test('remint drops local state and reconstructs a fresh instance in place', asyn
|
|
|
137
137
|
expect(fakeZero.instances.at(-1)).not.toBe(first)
|
|
138
138
|
})
|
|
139
139
|
|
|
140
|
+
test('closed headless connection ignores a late update without a recovery error', async () => {
|
|
141
|
+
const isolated = createZeroClient({
|
|
142
|
+
schema,
|
|
143
|
+
models: {},
|
|
144
|
+
groupedQueries: {},
|
|
145
|
+
instanceName: 'closed-headless-recovery-test',
|
|
146
|
+
})
|
|
147
|
+
const connection = isolated.connectHeadless({
|
|
148
|
+
cacheURL: 'http://127.0.0.1:7777/zero',
|
|
149
|
+
userID: 'closed-headless-recovery',
|
|
150
|
+
kvStore: 'mem',
|
|
151
|
+
storageKey: 'closed-headless-recovery',
|
|
152
|
+
})
|
|
153
|
+
const instance = fakeZero.instances.at(-1)
|
|
154
|
+
expect(instance).toBeDefined()
|
|
155
|
+
await connection.close()
|
|
156
|
+
|
|
157
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
158
|
+
try {
|
|
159
|
+
instance?.options.onUpdateNeeded({
|
|
160
|
+
type: UpdateNeededReasonType.NewClientGroup,
|
|
161
|
+
})
|
|
162
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
163
|
+
expect(consoleError).not.toHaveBeenCalledWith(
|
|
164
|
+
'[on-zero] recovery could not reload or reconstruct the client'
|
|
165
|
+
)
|
|
166
|
+
} finally {
|
|
167
|
+
consoleError.mockRestore()
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
140
171
|
test('provider generation changes with the actual instance during remint', async () => {
|
|
141
172
|
const generationClient = createZeroClient({
|
|
142
173
|
schema,
|
|
@@ -431,3 +462,27 @@ test('retire tears down on every sign-out, including inside remint guard window'
|
|
|
431
462
|
expect(second?.delete).toHaveBeenCalledTimes(1)
|
|
432
463
|
expect(fakeZero.instances.at(-1)).not.toBe(second)
|
|
433
464
|
})
|
|
465
|
+
|
|
466
|
+
test('headless NewClientGroup recovery reconstructs its client without a provider', async () => {
|
|
467
|
+
const isolated = createZeroClient({
|
|
468
|
+
schema,
|
|
469
|
+
models: {},
|
|
470
|
+
groupedQueries: {},
|
|
471
|
+
instanceName: 'headless-recovery-test',
|
|
472
|
+
})
|
|
473
|
+
const connection = isolated.connectHeadless({
|
|
474
|
+
cacheURL: 'http://127.0.0.1:7777/zero',
|
|
475
|
+
userID: 'headless-recovery',
|
|
476
|
+
})
|
|
477
|
+
const first = fakeZero.instances.at(-1)!
|
|
478
|
+
const countBefore = fakeZero.instances.length
|
|
479
|
+
|
|
480
|
+
first.options.onUpdateNeeded({ type: 'NewClientGroup' })
|
|
481
|
+
|
|
482
|
+
await vi.waitFor(() => expect(fakeZero.instances).toHaveLength(countBefore + 1))
|
|
483
|
+
expect(connection.zero).not.toBe(first)
|
|
484
|
+
expect(await isolated.waitForZero()).toBe(connection.zero)
|
|
485
|
+
expect(first.close).toHaveBeenCalledOnce()
|
|
486
|
+
|
|
487
|
+
await connection.close()
|
|
488
|
+
})
|
package/src/createZeroClient.tsx
CHANGED
|
@@ -350,6 +350,8 @@ export function createZeroClientInternal<
|
|
|
350
350
|
scheduleReload?: (ctx: ScheduleReloadContext) => void
|
|
351
351
|
guardStorage?: RecoveryGuardStorage
|
|
352
352
|
benignLogPatterns?: readonly ZeroLogPattern[]
|
|
353
|
+
recoverInPlace?: () => Promise<boolean>
|
|
354
|
+
reload?: () => void | boolean
|
|
353
355
|
}
|
|
354
356
|
|
|
355
357
|
// build a Zero instance with on-zero's recovery wiring. shared by the
|
|
@@ -363,6 +365,8 @@ export function createZeroClientInternal<
|
|
|
363
365
|
scheduleReload,
|
|
364
366
|
guardStorage,
|
|
365
367
|
benignLogPatterns,
|
|
368
|
+
recoverInPlace,
|
|
369
|
+
reload,
|
|
366
370
|
}: ConstructZeroInstanceArgs): ZeroInstance {
|
|
367
371
|
let installedTransport: Pick<HttpPullTransport, 'subscribeLifecycle'> | undefined
|
|
368
372
|
// install before construction so the instance's first connect goes through
|
|
@@ -392,7 +396,8 @@ export function createZeroClientInternal<
|
|
|
392
396
|
...(benignLogPatterns ?? []),
|
|
393
397
|
],
|
|
394
398
|
onRecovery: () => mutationLifecycle.fence(),
|
|
395
|
-
recoverInPlace: () => remint({ dropLocalState: false }),
|
|
399
|
+
recoverInPlace: recoverInPlace ?? (() => remint({ dropLocalState: false })),
|
|
400
|
+
reload,
|
|
396
401
|
}
|
|
397
402
|
const recovery = makeZeroRecovery(recoveryDeps)
|
|
398
403
|
const createdInstance = new ZeroClient<Schema, ZeroMutators>({
|
|
@@ -1215,28 +1220,62 @@ export function createZeroClientInternal<
|
|
|
1215
1220
|
// mutations read auth dynamically through getAuthData(), so this has to be
|
|
1216
1221
|
// set before the first mutation exactly as the provider sets it in render.
|
|
1217
1222
|
setAuthData((authData ?? null) as AuthData)
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1223
|
+
let closed = false
|
|
1224
|
+
let activeInstance: ZeroInstance
|
|
1225
|
+
let unwatch = () => {}
|
|
1226
|
+
const construct = () =>
|
|
1227
|
+
constructZeroInstance({
|
|
1228
|
+
options,
|
|
1229
|
+
transport,
|
|
1230
|
+
beforeReload,
|
|
1231
|
+
scheduleReload,
|
|
1232
|
+
guardStorage,
|
|
1233
|
+
benignLogPatterns,
|
|
1234
|
+
// a headless host has no provider state to bump and no page it owns to
|
|
1235
|
+
// reload. replace the disabled instance directly, then republish the
|
|
1236
|
+
// stable module facade and move the connection watcher with it.
|
|
1237
|
+
recoverInPlace: async () => {
|
|
1238
|
+
// an update can arrive after the host intentionally closed this
|
|
1239
|
+
// connection during preview turnover. there is no live client left
|
|
1240
|
+
// to reconstruct, so recovery is already satisfied.
|
|
1241
|
+
if (closed) return true
|
|
1242
|
+
const outgoing = activeInstance
|
|
1243
|
+
unwatch()
|
|
1244
|
+
clearZeroInstanceReferences(outgoing)
|
|
1245
|
+
mutationLifecycle.fence()
|
|
1246
|
+
try {
|
|
1247
|
+
outgoing.close()
|
|
1248
|
+
} catch {}
|
|
1249
|
+
activeInstance = construct()
|
|
1250
|
+
publishZeroInstance(activeInstance)
|
|
1251
|
+
zeroInstanceVersion?.emit(zeroInstanceVersion.value + 1)
|
|
1252
|
+
unwatch = watchZeroConnection({
|
|
1253
|
+
zeroInstance: activeInstance,
|
|
1254
|
+
auth: options.auth,
|
|
1255
|
+
refreshAuth,
|
|
1256
|
+
})
|
|
1257
|
+
return true
|
|
1258
|
+
},
|
|
1259
|
+
reload: () => false,
|
|
1260
|
+
})
|
|
1261
|
+
activeInstance = construct()
|
|
1262
|
+
publishZeroInstance(activeInstance)
|
|
1227
1263
|
zeroInstanceVersion?.emit(zeroInstanceVersion.value + 1)
|
|
1228
|
-
|
|
1229
|
-
zeroInstance,
|
|
1264
|
+
unwatch = watchZeroConnection({
|
|
1265
|
+
zeroInstance: activeInstance,
|
|
1230
1266
|
auth: options.auth,
|
|
1231
1267
|
refreshAuth,
|
|
1232
1268
|
})
|
|
1233
1269
|
return {
|
|
1234
|
-
zero
|
|
1270
|
+
get zero() {
|
|
1271
|
+
return activeInstance
|
|
1272
|
+
},
|
|
1235
1273
|
close: async () => {
|
|
1274
|
+
closed = true
|
|
1236
1275
|
unwatch()
|
|
1237
|
-
clearZeroInstanceReferences(
|
|
1276
|
+
clearZeroInstanceReferences(activeInstance)
|
|
1238
1277
|
mutationLifecycle.fence()
|
|
1239
|
-
await
|
|
1278
|
+
await activeInstance.close()
|
|
1240
1279
|
},
|
|
1241
1280
|
}
|
|
1242
1281
|
}
|
package/src/generate-helpers.ts
CHANGED
|
@@ -820,3 +820,82 @@ ${modelDefs}
|
|
|
820
820
|
}
|
|
821
821
|
`
|
|
822
822
|
}
|
|
823
|
+
|
|
824
|
+
export type DrizzleSchemaRelationTable = {
|
|
825
|
+
key: string
|
|
826
|
+
properties: readonly string[]
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// membership-filtered drizzle input consumed by generated/schema.ts.
|
|
830
|
+
// schemaImportPath is relative to data/generated/.
|
|
831
|
+
export function renderDrizzleSchemaInputModule(options: {
|
|
832
|
+
schemaImportPath: string
|
|
833
|
+
tableNames: readonly string[]
|
|
834
|
+
relationTables: readonly DrizzleSchemaRelationTable[]
|
|
835
|
+
}): string {
|
|
836
|
+
const tableNames = [...new Set(options.tableNames)].sort()
|
|
837
|
+
const relationEntries = options.relationTables
|
|
838
|
+
.filter((table) => table.properties.length > 0)
|
|
839
|
+
.map((table) => {
|
|
840
|
+
const body = table.properties.map((property) => ` ${property},`).join('\n')
|
|
841
|
+
return ` ${table.key}: {\n${body}\n },`
|
|
842
|
+
})
|
|
843
|
+
return [
|
|
844
|
+
'// auto-generated from the on-zero data layout',
|
|
845
|
+
`import { defineRelations } from 'drizzle-orm'`,
|
|
846
|
+
`import * as schema from ${JSON.stringify(options.schemaImportPath)}`,
|
|
847
|
+
'',
|
|
848
|
+
`export { ${tableNames.join(', ')} } from ${JSON.stringify(options.schemaImportPath)}`,
|
|
849
|
+
`export const relations = defineRelations(schema, (r) => ({`,
|
|
850
|
+
...relationEntries,
|
|
851
|
+
`}))`,
|
|
852
|
+
'',
|
|
853
|
+
].join('\n')
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// keep the emitted module identical to drizzle-zero-sqlite's
|
|
857
|
+
// generateDrizzleZeroSqliteSchemaFile. that package is the runtime owner;
|
|
858
|
+
// this copy exists so generate-lite can emit the file without importing it.
|
|
859
|
+
export function renderDrizzleZeroSqliteSchemaModule(options: {
|
|
860
|
+
importPath: string
|
|
861
|
+
tableNames: readonly string[]
|
|
862
|
+
}): string {
|
|
863
|
+
const tableNames = [...new Set(options.tableNames)].sort()
|
|
864
|
+
const typeNames = new Set<string>()
|
|
865
|
+
const rowAliases = tableNames.map((tableName) => {
|
|
866
|
+
const typeName = tableName
|
|
867
|
+
.replace(/(?:^|[^A-Za-z0-9]+)([A-Za-z0-9])/g, (_, character: string) =>
|
|
868
|
+
character.toUpperCase()
|
|
869
|
+
)
|
|
870
|
+
.replace(/^([a-z])/, (character) => character.toUpperCase())
|
|
871
|
+
if (!/^[$A-Z_a-z][$\w]*$/.test(typeName)) {
|
|
872
|
+
throw new TypeError(`table name cannot produce a TypeScript alias: ${tableName}`)
|
|
873
|
+
}
|
|
874
|
+
if (typeNames.has(typeName)) {
|
|
875
|
+
throw new TypeError(`table names produce duplicate TypeScript alias: ${typeName}`)
|
|
876
|
+
}
|
|
877
|
+
typeNames.add(typeName)
|
|
878
|
+
return `export type ${typeName} = Row<(typeof schema)['tables'][${JSON.stringify(tableName)}]>`
|
|
879
|
+
})
|
|
880
|
+
return [
|
|
881
|
+
'// auto-generated by drizzle-zero-sqlite',
|
|
882
|
+
`import { createBuilder, type Row } from '@rocicorp/zero'`,
|
|
883
|
+
`import { drizzleZeroConfig } from 'drizzle-zero-sqlite'`,
|
|
884
|
+
`import * as drizzleSchema from ${JSON.stringify(options.importPath)}`,
|
|
885
|
+
'',
|
|
886
|
+
`export const schema = drizzleZeroConfig(drizzleSchema, { suppressDefaultsWarning: true })`,
|
|
887
|
+
'',
|
|
888
|
+
`export type Schema = typeof schema`,
|
|
889
|
+
...rowAliases,
|
|
890
|
+
'',
|
|
891
|
+
`export const zql = createBuilder(schema)`,
|
|
892
|
+
'export const builder = zql',
|
|
893
|
+
'',
|
|
894
|
+
`declare module '@rocicorp/zero' {`,
|
|
895
|
+
' interface DefaultTypes {',
|
|
896
|
+
' schema: Schema',
|
|
897
|
+
' }',
|
|
898
|
+
'}',
|
|
899
|
+
'',
|
|
900
|
+
].join('\n')
|
|
901
|
+
}
|