on-zero 0.4.23 → 0.4.24

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 (93) hide show
  1. package/dist/cjs/combineZeroClients.cjs +101 -0
  2. package/dist/cjs/combineZeroClients.native.js +150 -0
  3. package/dist/cjs/combineZeroClients.native.js.map +1 -0
  4. package/dist/cjs/createUseQuery.cjs +92 -4
  5. package/dist/cjs/createUseQuery.native.js +130 -4
  6. package/dist/cjs/createUseQuery.native.js.map +1 -1
  7. package/dist/cjs/createZeroClient.cjs +41 -13
  8. package/dist/cjs/createZeroClient.native.js +75 -43
  9. package/dist/cjs/createZeroClient.native.js.map +1 -1
  10. package/dist/cjs/index.cjs +1 -0
  11. package/dist/cjs/index.native.js +1 -0
  12. package/dist/cjs/index.native.js.map +1 -1
  13. package/dist/cjs/instanceRegistry.cjs +65 -0
  14. package/dist/cjs/instanceRegistry.native.js +111 -0
  15. package/dist/cjs/instanceRegistry.native.js.map +1 -0
  16. package/dist/cjs/multiInstance.test.cjs +322 -0
  17. package/dist/cjs/multiInstance.test.native.js +387 -0
  18. package/dist/cjs/multiInstance.test.native.js.map +1 -0
  19. package/dist/cjs/multiInstanceNested.test.cjs +206 -0
  20. package/dist/cjs/multiInstanceNested.test.native.js +254 -0
  21. package/dist/cjs/multiInstanceNested.test.native.js.map +1 -0
  22. package/dist/cjs/run.cjs +5 -5
  23. package/dist/cjs/run.native.js +6 -5
  24. package/dist/cjs/run.native.js.map +1 -1
  25. package/dist/cjs/zeroRunner.cjs +4 -1
  26. package/dist/cjs/zeroRunner.native.js +4 -1
  27. package/dist/cjs/zeroRunner.native.js.map +1 -1
  28. package/dist/esm/combineZeroClients.mjs +76 -0
  29. package/dist/esm/combineZeroClients.mjs.map +1 -0
  30. package/dist/esm/combineZeroClients.native.js +122 -0
  31. package/dist/esm/combineZeroClients.native.js.map +1 -0
  32. package/dist/esm/createUseQuery.mjs +92 -5
  33. package/dist/esm/createUseQuery.mjs.map +1 -1
  34. package/dist/esm/createUseQuery.native.js +130 -5
  35. package/dist/esm/createUseQuery.native.js.map +1 -1
  36. package/dist/esm/createZeroClient.mjs +42 -14
  37. package/dist/esm/createZeroClient.mjs.map +1 -1
  38. package/dist/esm/createZeroClient.native.js +76 -44
  39. package/dist/esm/createZeroClient.native.js.map +1 -1
  40. package/dist/esm/index.js +1 -0
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/esm/index.mjs +1 -0
  43. package/dist/esm/index.mjs.map +1 -1
  44. package/dist/esm/index.native.js +1 -0
  45. package/dist/esm/index.native.js.map +1 -1
  46. package/dist/esm/instanceRegistry.mjs +38 -0
  47. package/dist/esm/instanceRegistry.mjs.map +1 -0
  48. package/dist/esm/instanceRegistry.native.js +81 -0
  49. package/dist/esm/instanceRegistry.native.js.map +1 -0
  50. package/dist/esm/multiInstance.test.mjs +323 -0
  51. package/dist/esm/multiInstance.test.mjs.map +1 -0
  52. package/dist/esm/multiInstance.test.native.js +385 -0
  53. package/dist/esm/multiInstance.test.native.js.map +1 -0
  54. package/dist/esm/multiInstanceNested.test.mjs +207 -0
  55. package/dist/esm/multiInstanceNested.test.mjs.map +1 -0
  56. package/dist/esm/multiInstanceNested.test.native.js +252 -0
  57. package/dist/esm/multiInstanceNested.test.native.js.map +1 -0
  58. package/dist/esm/run.mjs +5 -5
  59. package/dist/esm/run.mjs.map +1 -1
  60. package/dist/esm/run.native.js +6 -5
  61. package/dist/esm/run.native.js.map +1 -1
  62. package/dist/esm/zeroRunner.mjs +4 -1
  63. package/dist/esm/zeroRunner.mjs.map +1 -1
  64. package/dist/esm/zeroRunner.native.js +4 -1
  65. package/dist/esm/zeroRunner.native.js.map +1 -1
  66. package/package.json +5 -3
  67. package/readme.md +59 -0
  68. package/src/combineZeroClients.tsx +186 -0
  69. package/src/createUseQuery.tsx +175 -12
  70. package/src/createZeroClient.tsx +107 -42
  71. package/src/index.ts +1 -0
  72. package/src/instanceRegistry.ts +75 -0
  73. package/src/multiInstance.test.tsx +284 -0
  74. package/src/multiInstanceNested.test.tsx +205 -0
  75. package/src/run.ts +7 -6
  76. package/src/zeroRunner.ts +7 -1
  77. package/types/combineZeroClients.d.ts +38 -0
  78. package/types/combineZeroClients.d.ts.map +1 -0
  79. package/types/createUseQuery.d.ts +15 -0
  80. package/types/createUseQuery.d.ts.map +1 -1
  81. package/types/createZeroClient.d.ts +7 -2
  82. package/types/createZeroClient.d.ts.map +1 -1
  83. package/types/index.d.ts +1 -0
  84. package/types/index.d.ts.map +1 -1
  85. package/types/instanceRegistry.d.ts +15 -0
  86. package/types/instanceRegistry.d.ts.map +1 -0
  87. package/types/multiInstance.test.d.ts +2 -0
  88. package/types/multiInstance.test.d.ts.map +1 -0
  89. package/types/multiInstanceNested.test.d.ts +5 -0
  90. package/types/multiInstanceNested.test.d.ts.map +1 -0
  91. package/types/run.d.ts.map +1 -1
  92. package/types/zeroRunner.d.ts +3 -1
  93. package/types/zeroRunner.d.ts.map +1 -1
@@ -0,0 +1,322 @@
1
+ var import_zero = require("@rocicorp/zero");
2
+ var import_helpers = require("@take-out/helpers");
3
+ var import_vitest = require("vitest");
4
+ var import_combineZeroClients = require("./combineZeroClients.cjs");
5
+ var import_createZeroClient = require("./createZeroClient.cjs");
6
+ var import_instanceRegistry = require("./instanceRegistry.cjs");
7
+ var import_queryRegistry = require("./queryRegistry.cjs");
8
+ var import_run = require("./run.cjs");
9
+ var import_zeroRunner = require("./zeroRunner.cjs");
10
+ const userTable = (0, import_zero.table)("user").columns({
11
+ id: (0, import_zero.string)(),
12
+ name: (0, import_zero.string)()
13
+ }).primaryKey("id");
14
+ const taskTable = (0, import_zero.table)("task").columns({
15
+ id: (0, import_zero.string)(),
16
+ title: (0, import_zero.string)()
17
+ }).primaryKey("id");
18
+ const schema = (0, import_zero.createSchema)({
19
+ tables: [userTable, taskTable]
20
+ });
21
+ const makeQueryFn = () => args => args;
22
+ function makeClient(instanceName, namespace) {
23
+ const byId = makeQueryFn();
24
+ return {
25
+ byId,
26
+ client: (0, import_createZeroClient.createZeroClient)({
27
+ schema,
28
+ models: {},
29
+ groupedQueries: {
30
+ [namespace]: {
31
+ byId
32
+ }
33
+ },
34
+ instanceName
35
+ })
36
+ };
37
+ }
38
+ function fakeClient(name, namespaces, zeroStub) {
39
+ (0, import_instanceRegistry.registerClientInstance)({
40
+ name,
41
+ namespaces,
42
+ // boundary stub: dispatch tests never resolve queries through it
43
+ customQueries: {}
44
+ });
45
+ return {
46
+ instanceName: name,
47
+ useQuery: import_vitest.vi.fn(() => `${name}-useQuery`),
48
+ useQueryDirect: import_vitest.vi.fn(() => `${name}-useQueryDirect`),
49
+ usePermission: import_vitest.vi.fn(() => `${name}-usePermission`),
50
+ usePermissionDirect: import_vitest.vi.fn(() => `${name}-usePermissionDirect`),
51
+ zero: zeroStub,
52
+ preload: import_vitest.vi.fn(() => `${name}-preload`),
53
+ getQuery: import_vitest.vi.fn(() => `${name}-getQuery`),
54
+ zeroEvents: (0, import_helpers.createEmitter)(`zero:test-${name}`, null),
55
+ ControlQueries: ({
56
+ children
57
+ }) => children
58
+ };
59
+ }
60
+ (0, import_vitest.describe)("multi-instance namespace dispatch", () => {
61
+ (0, import_vitest.test)("run() dispatches named queries to the owning instance runner", async () => {
62
+ const control = makeClient("run-control", "runUser");
63
+ const project = makeClient("run-project", "runTask");
64
+ const controlRunner = import_vitest.vi.fn(async (..._args) => ({
65
+ from: "control"
66
+ }));
67
+ const projectRunner = import_vitest.vi.fn(async (..._args) => ({
68
+ from: "project"
69
+ }));
70
+ (0, import_instanceRegistry.getInstanceForNamespace)("runUser").runner = controlRunner;
71
+ (0, import_instanceRegistry.getInstanceForNamespace)("runTask").runner = projectRunner;
72
+ const ambientRunner = import_vitest.vi.fn(async (..._args) => ({
73
+ from: "ambient"
74
+ }));
75
+ (0, import_zeroRunner.setRunner)(ambientRunner);
76
+ await (0, import_vitest.expect)((0, import_run.run)(control.byId, {
77
+ id: "1"
78
+ })).resolves.toEqual({
79
+ from: "control"
80
+ });
81
+ await (0, import_vitest.expect)((0, import_run.run)(project.byId, {
82
+ id: "2"
83
+ })).resolves.toEqual({
84
+ from: "project"
85
+ });
86
+ (0, import_vitest.expect)(ambientRunner).not.toHaveBeenCalled();
87
+ const request = controlRunner.mock.calls[0][0];
88
+ (0, import_vitest.expect)(request.query.queryName).toBe("runUser.byId");
89
+ });
90
+ (0, import_vitest.test)("a claimed namespace with an unmounted instance uses the ambient runner (server path)", async () => {
91
+ const {
92
+ byId
93
+ } = makeClient("srv-instance", "srvThing");
94
+ const ambient = import_vitest.vi.fn(async (..._args) => ({
95
+ from: "ambient"
96
+ }));
97
+ (0, import_zeroRunner.setRunner)(ambient);
98
+ await (0, import_vitest.expect)((0, import_run.run)(byId, {
99
+ id: "1"
100
+ })).resolves.toEqual({
101
+ from: "ambient"
102
+ });
103
+ (0, import_vitest.expect)(ambient).toHaveBeenCalledTimes(1);
104
+ });
105
+ (0, import_vitest.test)("duplicate namespace claim throws at create time", () => {
106
+ makeClient("dup-a", "dupNs");
107
+ (0, import_vitest.expect)(() => makeClient("dup-b", "dupNs")).toThrow(/already claimed/);
108
+ });
109
+ (0, import_vitest.test)("re-creating an instance under the same name re-claims without throwing (hmr)", () => {
110
+ makeClient("hmr", "hmrNs");
111
+ (0, import_vitest.expect)(() => makeClient("hmr", "hmrNs")).not.toThrow();
112
+ (0, import_vitest.expect)((0, import_instanceRegistry.getInstanceForNamespace)("hmrNs")?.name).toBe("hmr");
113
+ });
114
+ (0, import_vitest.test)("model namespaces are claimed too", () => {
115
+ const models = {
116
+ mdlThing: {
117
+ mutate: {
118
+ insert: async () => {}
119
+ }
120
+ }
121
+ };
122
+ (0, import_createZeroClient.createZeroClient)({
123
+ schema,
124
+ models,
125
+ groupedQueries: {},
126
+ instanceName: "mdl-a"
127
+ });
128
+ (0, import_vitest.expect)((0, import_instanceRegistry.getInstanceForNamespace)("mdlThing")?.name).toBe("mdl-a");
129
+ (0, import_vitest.expect)(() => (0, import_createZeroClient.createZeroClient)({
130
+ schema,
131
+ models,
132
+ groupedQueries: {},
133
+ instanceName: "mdl-b"
134
+ })).toThrow(/already claimed/);
135
+ });
136
+ });
137
+ (0, import_vitest.describe)("multi-instance isolation", () => {
138
+ (0, import_vitest.test)("each instance has an isolated zeroEvents emitter", () => {
139
+ const {
140
+ client: a
141
+ } = makeClient("emit-a", "emitA");
142
+ const {
143
+ client: b
144
+ } = makeClient("emit-b", "emitB");
145
+ (0, import_vitest.expect)(a.zeroEvents).not.toBe(b.zeroEvents);
146
+ (0, import_vitest.expect)(a.zeroEvents.options?.name).toBe("zero:emit-a");
147
+ (0, import_vitest.expect)(b.zeroEvents.options?.name).toBe("zero:emit-b");
148
+ const seenByB = [];
149
+ b.zeroEvents.listen(event => seenByB.push(event));
150
+ a.zeroEvents.emit({
151
+ type: "error",
152
+ message: "a-only"
153
+ });
154
+ (0, import_vitest.expect)(seenByB).toEqual([]);
155
+ (0, import_vitest.expect)(a.zeroEvents.value).toEqual({
156
+ type: "error",
157
+ message: "a-only"
158
+ });
159
+ (0, import_vitest.expect)(b.zeroEvents.value).toBe(null);
160
+ });
161
+ (0, import_vitest.test)("the default instance keeps the legacy emitter name", () => {
162
+ const {
163
+ client
164
+ } = makeClient("default", "defaultNs");
165
+ (0, import_vitest.expect)(client.zeroEvents.options?.name).toBe("zero");
166
+ });
167
+ (0, import_vitest.test)("each instance has its own unmounted zero proxy", () => {
168
+ const {
169
+ client: a
170
+ } = makeClient("proxy-a", "proxyA");
171
+ const {
172
+ client: b
173
+ } = makeClient("proxy-b", "proxyB");
174
+ (0, import_vitest.expect)(a.zero === b.zero).toBe(false);
175
+ (0, import_vitest.expect)(() => a.zero.clientID).toThrow(/not initialized/);
176
+ (0, import_vitest.expect)(() => b.zero.clientID).toThrow(/not initialized/);
177
+ });
178
+ });
179
+ (0, import_vitest.describe)("combineZeroClients facade", () => {
180
+ (0, import_vitest.test)("zero.mutate dispatches by model namespace, rest forwards to primary", () => {
181
+ const insertSpy = import_vitest.vi.fn();
182
+ const updateSpy = import_vitest.vi.fn();
183
+ const control = fakeClient("fz-control", ["fzUser"], {
184
+ mutate: {
185
+ fzUser: {
186
+ insert: insertSpy
187
+ }
188
+ },
189
+ userID: "primary-user"
190
+ });
191
+ const project = fakeClient("fz-project", ["fzTask"], {
192
+ mutate: {
193
+ fzTask: {
194
+ update: updateSpy
195
+ }
196
+ },
197
+ userID: "project-user"
198
+ });
199
+ const combined = (0, import_combineZeroClients.combineZeroClients)(control, project);
200
+ const zero = combined.zero;
201
+ zero.mutate.fzUser.insert({
202
+ id: "1"
203
+ });
204
+ zero.mutate.fzTask.update({
205
+ id: "2"
206
+ });
207
+ (0, import_vitest.expect)(insertSpy).toHaveBeenCalledWith({
208
+ id: "1"
209
+ });
210
+ (0, import_vitest.expect)(updateSpy).toHaveBeenCalledWith({
211
+ id: "2"
212
+ });
213
+ (0, import_vitest.expect)(zero.userID).toBe("primary-user");
214
+ (0, import_vitest.expect)(zero.mutate.unknownNs).toBe(void 0);
215
+ });
216
+ (0, import_vitest.test)("useQuery/preload/getQuery/usePermission dispatch by namespace", () => {
217
+ const control = fakeClient("fq-control", ["fqUser"], {});
218
+ const project = fakeClient("fq-project", ["fqTask"], {});
219
+ const userQuery = makeQueryFn();
220
+ const taskQuery = makeQueryFn();
221
+ (0, import_queryRegistry.registerQuery)(userQuery, "fqUser.byId");
222
+ (0, import_queryRegistry.registerQuery)(taskQuery, "fqTask.byId");
223
+ const combined = (0, import_combineZeroClients.combineZeroClients)(control, project);
224
+ const useQuery = combined.useQuery;
225
+ const preload = combined.preload;
226
+ const getQuery = combined.getQuery;
227
+ const usePermission = combined.usePermission;
228
+ useQuery(userQuery, {
229
+ id: "1"
230
+ });
231
+ (0, import_vitest.expect)(control.useQueryDirect).toHaveBeenCalledWith(userQuery, {
232
+ id: "1"
233
+ });
234
+ (0, import_vitest.expect)(control.useQuery).not.toHaveBeenCalled();
235
+ (0, import_vitest.expect)(project.useQuery).not.toHaveBeenCalled();
236
+ useQuery(taskQuery, {
237
+ id: "2"
238
+ });
239
+ (0, import_vitest.expect)(project.useQuery).toHaveBeenCalledWith(taskQuery, {
240
+ id: "2"
241
+ });
242
+ (0, import_vitest.expect)(project.useQueryDirect).not.toHaveBeenCalled();
243
+ preload(taskQuery, {
244
+ id: "3"
245
+ });
246
+ (0, import_vitest.expect)(project.preload).toHaveBeenCalledWith(taskQuery, {
247
+ id: "3"
248
+ });
249
+ (0, import_vitest.expect)(control.preload).not.toHaveBeenCalled();
250
+ getQuery(userQuery, {
251
+ id: "4"
252
+ });
253
+ (0, import_vitest.expect)(control.getQuery).toHaveBeenCalledWith(userQuery, {
254
+ id: "4"
255
+ });
256
+ (0, import_vitest.expect)(project.getQuery).not.toHaveBeenCalled();
257
+ const anonymous = makeQueryFn();
258
+ useQuery(anonymous, {
259
+ id: "5"
260
+ });
261
+ (0, import_vitest.expect)(control.useQueryDirect).toHaveBeenCalledWith(anonymous, {
262
+ id: "5"
263
+ });
264
+ usePermission("fqTask", "row-1");
265
+ (0, import_vitest.expect)(project.usePermission).toHaveBeenCalledWith("fqTask", "row-1");
266
+ (0, import_vitest.expect)(project.usePermissionDirect).not.toHaveBeenCalled();
267
+ usePermission("fqUser", "row-2");
268
+ (0, import_vitest.expect)(control.usePermissionDirect).toHaveBeenCalledWith("fqUser", "row-2");
269
+ (0, import_vitest.expect)(control.usePermission).not.toHaveBeenCalled();
270
+ });
271
+ (0, import_vitest.test)("the inner option overrides which client uses the context path", () => {
272
+ const a = fakeClient("inner-a", ["innerA"], {});
273
+ const b = fakeClient("inner-b", ["innerB"], {});
274
+ const aQuery = makeQueryFn();
275
+ const bQuery = makeQueryFn();
276
+ (0, import_queryRegistry.registerQuery)(aQuery, "innerA.byId");
277
+ (0, import_queryRegistry.registerQuery)(bQuery, "innerB.byId");
278
+ const combined = (0, import_combineZeroClients.combineZeroClients)(a, b, {
279
+ inner: "inner-a"
280
+ });
281
+ const useQuery = combined.useQuery;
282
+ useQuery(aQuery, {
283
+ id: "1"
284
+ });
285
+ (0, import_vitest.expect)(a.useQuery).toHaveBeenCalledWith(aQuery, {
286
+ id: "1"
287
+ });
288
+ (0, import_vitest.expect)(a.useQueryDirect).not.toHaveBeenCalled();
289
+ useQuery(bQuery, {
290
+ id: "2"
291
+ });
292
+ (0, import_vitest.expect)(b.useQueryDirect).toHaveBeenCalledWith(bQuery, {
293
+ id: "2"
294
+ });
295
+ (0, import_vitest.expect)(b.useQuery).not.toHaveBeenCalled();
296
+ (0, import_vitest.expect)(() => (0, import_combineZeroClients.combineZeroClients)(a, b, {
297
+ inner: "nope"
298
+ })).toThrow(/not one of the passed clients/);
299
+ });
300
+ (0, import_vitest.test)("combined zeroEvents relays every instance", () => {
301
+ const {
302
+ client: a
303
+ } = makeClient("relay-a", "relayA");
304
+ const {
305
+ client: b
306
+ } = makeClient("relay-b", "relayB");
307
+ const combined = (0, import_combineZeroClients.combineZeroClients)(a, b);
308
+ const seen = [];
309
+ combined.zeroEvents.listen(event => seen.push(event));
310
+ a.zeroEvents.emit({
311
+ type: "error",
312
+ message: "from-a"
313
+ });
314
+ b.zeroEvents.emit({
315
+ type: "error",
316
+ message: "from-b"
317
+ });
318
+ (0, import_vitest.expect)(seen.map(event => event?.message)).toEqual(["from-a", "from-b"]);
319
+ (0, import_vitest.expect)(a.zeroEvents.value?.message).toBe("from-a");
320
+ (0, import_vitest.expect)(b.zeroEvents.value?.message).toBe("from-b");
321
+ });
322
+ });