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.
Files changed (110) hide show
  1. package/dist/cjs/createZeroClient.cjs +44 -11
  2. package/dist/cjs/createZeroClient.native.js +54 -17
  3. package/dist/cjs/createZeroClient.native.js.map +1 -1
  4. package/dist/cjs/createZeroClient.recovery.test.cjs +49 -0
  5. package/dist/cjs/createZeroClient.recovery.test.native.js +53 -0
  6. package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
  7. package/dist/cjs/generate-helpers.cjs +28 -0
  8. package/dist/cjs/generate-helpers.native.js +36 -0
  9. package/dist/cjs/generate-helpers.native.js.map +1 -1
  10. package/dist/cjs/generate-layout.cjs +62 -53
  11. package/dist/cjs/generate-layout.native.js +62 -54
  12. package/dist/cjs/generate-layout.native.js.map +1 -1
  13. package/dist/cjs/generate-lite.cjs +28 -0
  14. package/dist/cjs/generate-lite.native.js +89 -33
  15. package/dist/cjs/generate-lite.native.js.map +1 -1
  16. package/dist/cjs/generate-lite.test.cjs +46 -0
  17. package/dist/cjs/generate-lite.test.native.js +46 -0
  18. package/dist/cjs/generate-lite.test.native.js.map +1 -1
  19. package/dist/cjs/generate.cjs +237 -243
  20. package/dist/cjs/generate.native.js +352 -353
  21. package/dist/cjs/generate.native.js.map +1 -1
  22. package/dist/cjs/generate.test.cjs +35 -0
  23. package/dist/cjs/generate.test.native.js +35 -0
  24. package/dist/cjs/generate.test.native.js.map +1 -1
  25. package/dist/cjs/helpers/createMutators.cjs +2 -1
  26. package/dist/cjs/helpers/createMutators.native.js +3 -1
  27. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  28. package/dist/cjs/helpers/recoverZeroClient.cjs +8 -2
  29. package/dist/cjs/helpers/recoverZeroClient.native.js +10 -2
  30. package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
  31. package/dist/cjs/helpers/recoverZeroClient.test.cjs +53 -0
  32. package/dist/cjs/helpers/recoverZeroClient.test.native.js +55 -0
  33. package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
  34. package/dist/cjs/native-typescript.cjs +190 -0
  35. package/dist/cjs/native-typescript.native.js +255 -0
  36. package/dist/cjs/native-typescript.native.js.map +1 -0
  37. package/dist/esm/createZeroClient.mjs +44 -11
  38. package/dist/esm/createZeroClient.mjs.map +1 -1
  39. package/dist/esm/createZeroClient.native.js +54 -17
  40. package/dist/esm/createZeroClient.native.js.map +1 -1
  41. package/dist/esm/createZeroClient.recovery.test.mjs +50 -1
  42. package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
  43. package/dist/esm/createZeroClient.recovery.test.native.js +54 -1
  44. package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
  45. package/dist/esm/generate-helpers.mjs +27 -1
  46. package/dist/esm/generate-helpers.mjs.map +1 -1
  47. package/dist/esm/generate-helpers.native.js +35 -1
  48. package/dist/esm/generate-helpers.native.js.map +1 -1
  49. package/dist/esm/generate-layout.mjs +52 -54
  50. package/dist/esm/generate-layout.mjs.map +1 -1
  51. package/dist/esm/generate-layout.native.js +52 -55
  52. package/dist/esm/generate-layout.native.js.map +1 -1
  53. package/dist/esm/generate-lite.mjs +29 -1
  54. package/dist/esm/generate-lite.mjs.map +1 -1
  55. package/dist/esm/generate-lite.native.js +90 -34
  56. package/dist/esm/generate-lite.native.js.map +1 -1
  57. package/dist/esm/generate-lite.test.mjs +46 -0
  58. package/dist/esm/generate-lite.test.mjs.map +1 -1
  59. package/dist/esm/generate-lite.test.native.js +46 -0
  60. package/dist/esm/generate-lite.test.native.js.map +1 -1
  61. package/dist/esm/generate.mjs +238 -244
  62. package/dist/esm/generate.mjs.map +1 -1
  63. package/dist/esm/generate.native.js +353 -354
  64. package/dist/esm/generate.native.js.map +1 -1
  65. package/dist/esm/generate.test.mjs +35 -0
  66. package/dist/esm/generate.test.mjs.map +1 -1
  67. package/dist/esm/generate.test.native.js +35 -0
  68. package/dist/esm/generate.test.native.js.map +1 -1
  69. package/dist/esm/helpers/createMutators.mjs +2 -1
  70. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  71. package/dist/esm/helpers/createMutators.native.js +3 -1
  72. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  73. package/dist/esm/helpers/recoverZeroClient.mjs +8 -2
  74. package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
  75. package/dist/esm/helpers/recoverZeroClient.native.js +10 -2
  76. package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
  77. package/dist/esm/helpers/recoverZeroClient.test.mjs +53 -0
  78. package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
  79. package/dist/esm/helpers/recoverZeroClient.test.native.js +55 -0
  80. package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
  81. package/dist/esm/index.native.js.map +1 -1
  82. package/dist/esm/native-typescript.mjs +164 -0
  83. package/dist/esm/native-typescript.mjs.map +1 -0
  84. package/dist/esm/native-typescript.native.js +226 -0
  85. package/dist/esm/native-typescript.native.js.map +1 -0
  86. package/package.json +4 -3
  87. package/src/createZeroClient.recovery.test.tsx +56 -1
  88. package/src/createZeroClient.tsx +54 -15
  89. package/src/generate-helpers.ts +79 -0
  90. package/src/generate-layout.ts +64 -108
  91. package/src/generate-lite.test.ts +49 -0
  92. package/src/generate-lite.ts +44 -0
  93. package/src/generate.test.ts +52 -0
  94. package/src/generate.ts +313 -366
  95. package/src/helpers/createMutators.ts +14 -3
  96. package/src/helpers/recoverZeroClient.test.ts +50 -0
  97. package/src/helpers/recoverZeroClient.ts +12 -2
  98. package/src/native-typescript.ts +176 -0
  99. package/types/createZeroClient.d.ts.map +1 -1
  100. package/types/generate-helpers.d.ts +13 -0
  101. package/types/generate-helpers.d.ts.map +1 -1
  102. package/types/generate-layout.d.ts +2 -1
  103. package/types/generate-layout.d.ts.map +1 -1
  104. package/types/generate-lite.d.ts +1 -0
  105. package/types/generate-lite.d.ts.map +1 -1
  106. package/types/generate.d.ts.map +1 -1
  107. package/types/helpers/createMutators.d.ts.map +1 -1
  108. package/types/helpers/recoverZeroClient.d.ts.map +1 -1
  109. package/types/native-typescript.d.ts +11 -0
  110. 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.17",
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.17",
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
+ })
@@ -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
- const zeroInstance = constructZeroInstance({
1219
- options,
1220
- transport,
1221
- beforeReload,
1222
- scheduleReload,
1223
- guardStorage,
1224
- benignLogPatterns,
1225
- })
1226
- publishZeroInstance(zeroInstance)
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
- const unwatch = watchZeroConnection({
1229
- zeroInstance,
1264
+ unwatch = watchZeroConnection({
1265
+ zeroInstance: activeInstance,
1230
1266
  auth: options.auth,
1231
1267
  refreshAuth,
1232
1268
  })
1233
1269
  return {
1234
- zero: zeroInstance,
1270
+ get zero() {
1271
+ return activeInstance
1272
+ },
1235
1273
  close: async () => {
1274
+ closed = true
1236
1275
  unwatch()
1237
- clearZeroInstanceReferences(zeroInstance)
1276
+ clearZeroInstanceReferences(activeInstance)
1238
1277
  mutationLifecycle.fence()
1239
- await zeroInstance.close()
1278
+ await activeInstance.close()
1240
1279
  },
1241
1280
  }
1242
1281
  }
@@ -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
+ }