on-zero 0.6.7 → 0.6.9

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 (150) hide show
  1. package/dist/cjs/combineZeroClients.native.js.map +1 -1
  2. package/dist/cjs/createPermissions.native.js.map +1 -1
  3. package/dist/cjs/createSchemaFromDrizzle.native.js.map +1 -1
  4. package/dist/cjs/createUseQuery.native.js.map +1 -1
  5. package/dist/cjs/createUseQueryDirect.native.js.map +1 -1
  6. package/dist/cjs/createZeroClient.authData.test.native.js.map +1 -1
  7. package/dist/cjs/createZeroClient.cjs +6 -8
  8. package/dist/cjs/createZeroClient.connection.test.native.js.map +1 -1
  9. package/dist/cjs/createZeroClient.native.js +11 -8
  10. package/dist/cjs/createZeroClient.native.js.map +1 -1
  11. package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
  12. package/dist/cjs/createZeroServer.native.js.map +1 -1
  13. package/dist/cjs/createZeroServer.test.native.js.map +1 -1
  14. package/dist/cjs/generate-helpers.native.js.map +1 -1
  15. package/dist/cjs/generate-lite.native.js.map +1 -1
  16. package/dist/cjs/generate-lite.test.native.js.map +1 -1
  17. package/dist/cjs/generate.cjs +6 -0
  18. package/dist/cjs/generate.native.js +11 -2
  19. package/dist/cjs/generate.native.js.map +1 -1
  20. package/dist/cjs/generate.test.native.js.map +1 -1
  21. package/dist/cjs/helpers/batchQuery.native.js.map +1 -1
  22. package/dist/cjs/helpers/clearZeroClientData.native.js.map +1 -1
  23. package/dist/cjs/helpers/createMutators.cjs +7 -2
  24. package/dist/cjs/helpers/createMutators.native.js +7 -2
  25. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  26. package/dist/cjs/helpers/createMutators.test.cjs +43 -0
  27. package/dist/cjs/helpers/createMutators.test.native.js +46 -0
  28. package/dist/cjs/helpers/createMutators.test.native.js.map +1 -0
  29. package/dist/cjs/helpers/didRunPermissionCheck.native.js.map +1 -1
  30. package/dist/cjs/helpers/ensureLoggedIn.native.js.map +1 -1
  31. package/dist/cjs/helpers/getAuth.native.js.map +1 -1
  32. package/dist/cjs/helpers/mutatorContext.native.js.map +1 -1
  33. package/dist/cjs/helpers/prettyFormatZeroQuery.native.js.map +1 -1
  34. package/dist/cjs/helpers/queryContext.native.js.map +1 -1
  35. package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
  36. package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
  37. package/dist/cjs/helpers/showZeroClientError.native.js.map +1 -1
  38. package/dist/cjs/helpers/useMutation.native.js.map +1 -1
  39. package/dist/cjs/helpers/useMutation.test.native.js.map +1 -1
  40. package/dist/cjs/helpers/useZeroDebug.native.js.map +1 -1
  41. package/dist/cjs/httpPull/auth.test.native.js.map +1 -1
  42. package/dist/cjs/httpPull/churn.test.native.js.map +1 -1
  43. package/dist/cjs/httpPull/completeAck.test.cjs +69 -0
  44. package/dist/cjs/httpPull/completeAck.test.native.js +76 -0
  45. package/dist/cjs/httpPull/completeAck.test.native.js.map +1 -0
  46. package/dist/cjs/httpPull/fixtureSchema.native.js.map +1 -1
  47. package/dist/cjs/httpPull/fixtureServer.native.js.map +1 -1
  48. package/dist/cjs/httpPull/integration.test.native.js.map +1 -1
  49. package/dist/cjs/httpPull/rebase.test.native.js.map +1 -1
  50. package/dist/cjs/httpPull/relations.test.native.js.map +1 -1
  51. package/dist/cjs/httpPull/testHarness.native.js.map +1 -1
  52. package/dist/cjs/httpPull/transport.test.cjs +177 -1
  53. package/dist/cjs/httpPull/transport.test.native.js +192 -0
  54. package/dist/cjs/httpPull/transport.test.native.js.map +1 -1
  55. package/dist/cjs/httpPullTransport.cjs +138 -12
  56. package/dist/cjs/httpPullTransport.native.js +173 -13
  57. package/dist/cjs/httpPullTransport.native.js.map +1 -1
  58. package/dist/cjs/index.native.js.map +1 -1
  59. package/dist/cjs/instanceRegistry.cjs +18 -1
  60. package/dist/cjs/instanceRegistry.native.js +71 -12
  61. package/dist/cjs/instanceRegistry.native.js.map +1 -1
  62. package/dist/cjs/modelRegistry.native.js.map +1 -1
  63. package/dist/cjs/multi.native.js.map +1 -1
  64. package/dist/cjs/multiInstance.test.cjs +6 -6
  65. package/dist/cjs/multiInstance.test.native.js +7 -7
  66. package/dist/cjs/multiInstance.test.native.js.map +1 -1
  67. package/dist/cjs/multiInstanceNested.test.native.js.map +1 -1
  68. package/dist/cjs/multiPartition.test.native.js.map +1 -1
  69. package/dist/cjs/mutations.native.js.map +1 -1
  70. package/dist/cjs/provideZero.hydration.test.native.js.map +1 -1
  71. package/dist/cjs/queryRegistry.native.js.map +1 -1
  72. package/dist/cjs/resolveQuery.native.js.map +1 -1
  73. package/dist/cjs/run.native.js.map +1 -1
  74. package/dist/cjs/serverWhere.native.js.map +1 -1
  75. package/dist/cjs/serverWhere.test.native.js.map +1 -1
  76. package/dist/cjs/state.native.js.map +1 -1
  77. package/dist/cjs/testSetup.native.js.map +1 -1
  78. package/dist/cjs/types.native.js.map +1 -1
  79. package/dist/cjs/usePermission.test.native.js.map +1 -1
  80. package/dist/cjs/useQuery.empty.test.cjs +10 -3
  81. package/dist/cjs/useQuery.empty.test.native.js +12 -3
  82. package/dist/cjs/useQuery.empty.test.native.js.map +1 -1
  83. package/dist/cjs/useQuery.ssr.test.native.js.map +1 -1
  84. package/dist/cjs/vite-plugin.native.js.map +1 -1
  85. package/dist/cjs/where.native.js.map +1 -1
  86. package/dist/cjs/zeroRunner.native.js.map +1 -1
  87. package/dist/cjs/zql.native.js.map +1 -1
  88. package/dist/esm/createZeroClient.mjs +6 -8
  89. package/dist/esm/createZeroClient.mjs.map +1 -1
  90. package/dist/esm/createZeroClient.native.js +11 -8
  91. package/dist/esm/createZeroClient.native.js.map +1 -1
  92. package/dist/esm/generate.mjs +6 -0
  93. package/dist/esm/generate.mjs.map +1 -1
  94. package/dist/esm/generate.native.js +11 -2
  95. package/dist/esm/generate.native.js.map +1 -1
  96. package/dist/esm/helpers/createMutators.mjs +7 -2
  97. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  98. package/dist/esm/helpers/createMutators.native.js +7 -2
  99. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  100. package/dist/esm/helpers/createMutators.test.mjs +44 -0
  101. package/dist/esm/helpers/createMutators.test.mjs.map +1 -0
  102. package/dist/esm/helpers/createMutators.test.native.js +44 -0
  103. package/dist/esm/helpers/createMutators.test.native.js.map +1 -0
  104. package/dist/esm/httpPull/completeAck.test.mjs +70 -0
  105. package/dist/esm/httpPull/completeAck.test.mjs.map +1 -0
  106. package/dist/esm/httpPull/completeAck.test.native.js +74 -0
  107. package/dist/esm/httpPull/completeAck.test.native.js.map +1 -0
  108. package/dist/esm/httpPull/transport.test.mjs +176 -0
  109. package/dist/esm/httpPull/transport.test.mjs.map +1 -1
  110. package/dist/esm/httpPull/transport.test.native.js +192 -0
  111. package/dist/esm/httpPull/transport.test.native.js.map +1 -1
  112. package/dist/esm/httpPullTransport.mjs +138 -12
  113. package/dist/esm/httpPullTransport.mjs.map +1 -1
  114. package/dist/esm/httpPullTransport.native.js +173 -13
  115. package/dist/esm/httpPullTransport.native.js.map +1 -1
  116. package/dist/esm/instanceRegistry.mjs +18 -1
  117. package/dist/esm/instanceRegistry.mjs.map +1 -1
  118. package/dist/esm/instanceRegistry.native.js +71 -12
  119. package/dist/esm/instanceRegistry.native.js.map +1 -1
  120. package/dist/esm/multiInstance.test.mjs +7 -7
  121. package/dist/esm/multiInstance.test.mjs.map +1 -1
  122. package/dist/esm/multiInstance.test.native.js +8 -8
  123. package/dist/esm/multiInstance.test.native.js.map +1 -1
  124. package/dist/esm/useQuery.empty.test.mjs +7 -0
  125. package/dist/esm/useQuery.empty.test.mjs.map +1 -1
  126. package/dist/esm/useQuery.empty.test.native.js +9 -0
  127. package/dist/esm/useQuery.empty.test.native.js.map +1 -1
  128. package/package.json +2 -2
  129. package/src/createZeroClient.tsx +7 -6
  130. package/src/generate.ts +10 -1
  131. package/src/helpers/createMutators.test.ts +51 -0
  132. package/src/helpers/createMutators.ts +7 -2
  133. package/src/httpPull/completeAck.test.ts +80 -0
  134. package/src/httpPull/transport.test.ts +134 -0
  135. package/src/httpPullTransport.ts +198 -13
  136. package/src/instanceRegistry.ts +27 -2
  137. package/src/multiInstance.test.tsx +11 -9
  138. package/src/useQuery.empty.test.tsx +8 -0
  139. package/types/createZeroClient.d.ts.map +1 -1
  140. package/types/generate.d.ts.map +1 -1
  141. package/types/helpers/createMutators.d.ts.map +1 -1
  142. package/types/helpers/createMutators.test.d.ts +2 -0
  143. package/types/helpers/createMutators.test.d.ts.map +1 -0
  144. package/types/httpPull/completeAck.test.d.ts +2 -0
  145. package/types/httpPull/completeAck.test.d.ts.map +1 -0
  146. package/types/httpPullTransport.d.ts +4 -0
  147. package/types/httpPullTransport.d.ts.map +1 -1
  148. package/types/instanceRegistry.d.ts +2 -1
  149. package/types/instanceRegistry.d.ts.map +1 -1
  150. package/types/useQuery.empty.test.d.ts.map +1 -1
@@ -662,3 +662,137 @@ function defer<T>() {
662
662
  })
663
663
  return { promise, resolve, reject }
664
664
  }
665
+
666
+ // installs the transport with the query-aware extension on (a queryTransform
667
+ // resolver), pushing it for afterEach cleanup.
668
+ function installWithQueries(
669
+ fetch: typeof globalThis.fetch,
670
+ queryTransform: (name: string, args: readonly unknown[]) => unknown,
671
+ ) {
672
+ const transport = installHttpPullTransport({ origin: ORIGIN, fetch, queryTransform })
673
+ transports.push(transport)
674
+ return transport
675
+ }
676
+
677
+ describe('zero-http query-aware extension', () => {
678
+ test('ships desired queries with pull state (transformed AST) and emits server got-query ack', async () => {
679
+ const requests: RequestRecord[] = []
680
+ const fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
681
+ const request = recordRequest(input, init)
682
+ requests.push(request)
683
+ return jsonResponse({
684
+ cookie: 1,
685
+ lastMutationIDChanges: {},
686
+ rowsPatch: [{ op: 'clear' }],
687
+ gotQueries: { version: 1, patch: [{ op: 'put', hash: 'h1' }] },
688
+ })
689
+ })
690
+ installWithQueries(fetch, (name, args) => ({ resolved: name, args }))
691
+
692
+ const { messages } = openRawSocketWithMessages({
693
+ desiredQueriesPatch: [
694
+ { op: 'put', hash: 'h1', name: 'byOwner', args: [{ ownerId: 'u1' }] },
695
+ ],
696
+ })
697
+
698
+ await eventually(() => expect(requests.length).toBeGreaterThan(0))
699
+ // the pull body ships {queries:{version, patch:[{op:'put',hash,ast}]}} with
700
+ // name+args resolved to the AST by the transform
701
+ expect(requests[0].body.queries).toEqual({
702
+ version: 1,
703
+ patch: [
704
+ {
705
+ op: 'put',
706
+ hash: 'h1',
707
+ ast: { resolved: 'byOwner', args: [{ ownerId: 'u1' }] },
708
+ },
709
+ ],
710
+ })
711
+ // the server's got-query ack is emitted to the client (not synthesized)
712
+ await eventually(() => {
713
+ const poke = messages.find(
714
+ (m) => m[0] === 'pokePart' && Array.isArray(m[1].gotQueriesPatch),
715
+ )
716
+ expect(poke?.[1].gotQueriesPatch).toEqual([{ op: 'put', hash: 'h1' }])
717
+ })
718
+ })
719
+
720
+ test('an ad-hoc put with an inline ast ships that ast unchanged', async () => {
721
+ const requests: RequestRecord[] = []
722
+ const fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
723
+ requests.push(recordRequest(input, init))
724
+ return jsonResponse({ cookie: 1, unchanged: true })
725
+ })
726
+ // a transform that would throw if called — an inline ast must bypass it
727
+ installWithQueries(fetch, () => {
728
+ throw new Error('transform should not run for an inline ast')
729
+ })
730
+
731
+ openRawSocketWithMessages({
732
+ desiredQueriesPatch: [{ op: 'put', hash: 'h2', ast: { inline: true } }],
733
+ })
734
+
735
+ await eventually(() => expect(requests.length).toBeGreaterThan(0))
736
+ expect(requests[0].body.queries.patch).toEqual([
737
+ { op: 'put', hash: 'h2', ast: { inline: true } },
738
+ ])
739
+ })
740
+
741
+ test('reconnect re-ships the desired set', async () => {
742
+ const requests: RequestRecord[] = []
743
+ const fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
744
+ requests.push(recordRequest(input, init))
745
+ // never ack the query version, so the desire stays un-acked
746
+ return jsonResponse({ cookie: 1, unchanged: true })
747
+ })
748
+ installWithQueries(fetch, (name) => ({ resolved: name }))
749
+
750
+ const desired = [{ op: 'put', hash: 'h1', name: 'byOwner', args: [] }]
751
+ const first = openRawSocketWithMessages({ desiredQueriesPatch: desired })
752
+ await eventually(() => expect(requests.length).toBeGreaterThan(0))
753
+ first.socket.close()
754
+
755
+ const before = requests.length
756
+ openRawSocketWithMessages({ desiredQueriesPatch: desired })
757
+ await eventually(() => expect(requests.length).toBeGreaterThan(before))
758
+ // the reconnected socket re-ships the (still un-acked) desired query
759
+ const replay = requests[requests.length - 1].body.queries
760
+ expect(replay.patch).toEqual([
761
+ { op: 'put', hash: 'h1', ast: { resolved: 'byOwner' } },
762
+ ])
763
+ })
764
+
765
+ test('queryForward ships name+args for the server to resolve (no client transform)', async () => {
766
+ const requests: RequestRecord[] = []
767
+ const fetch = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
768
+ requests.push(recordRequest(input, init))
769
+ return jsonResponse({ cookie: 1, unchanged: true })
770
+ })
771
+ // queryForward on, no transform: the permission transform stays server-side
772
+ const transport = installHttpPullTransport({
773
+ origin: ORIGIN,
774
+ fetch,
775
+ queryForward: true,
776
+ })
777
+ transports.push(transport)
778
+
779
+ openRawSocketWithMessages({
780
+ desiredQueriesPatch: [
781
+ {
782
+ op: 'put',
783
+ hash: 'h3',
784
+ name: 'byOwner',
785
+ args: [{ ownerId: 'u1' }],
786
+ // Zero may include a locally evaluable AST on a named query put.
787
+ // queryForward must discard it so the server remains authoritative.
788
+ ast: { table: 'secret' },
789
+ },
790
+ ],
791
+ })
792
+
793
+ await eventually(() => expect(requests.length).toBeGreaterThan(0))
794
+ expect(requests[0].body.queries.patch).toEqual([
795
+ { op: 'put', hash: 'h3', name: 'byOwner', args: [{ ownerId: 'u1' }] },
796
+ ])
797
+ })
798
+ })
@@ -25,16 +25,36 @@ type DesiredQueryPatchOp =
25
25
 
26
26
  type GotQueryPatchOp = { op: 'clear' } | { op: 'put' | 'del'; hash: string }
27
27
 
28
+ // a shipped desired-query put carries an AST (client-resolved by a
29
+ // queryTransform, or an ad-hoc query's inline ast) OR name+args for the server
30
+ // to resolve. name+args is the auth-sensitive path: the permission transform
31
+ // stays server-side, so a client cannot forge the AST.
32
+ type QueryPatchOp =
33
+ | { op: 'put'; hash: string; ast: unknown }
34
+ | { op: 'put'; hash: string; name: string; args: readonly unknown[] }
35
+ | { op: 'del'; hash: string }
36
+ | { op: 'clear' }
37
+
38
+ // transforms a named query's (name, args) into its Zero v51 AST. providing one
39
+ // turns the query-aware extension on and resolves desired queries CLIENT-side
40
+ // (ship the AST). use for a native host with no query registry, or a trusted
41
+ // harness. omit it (with queryForward) to ship name+args and resolve SERVER-side.
42
+ export type QueryTransform = (name: string, args: readonly unknown[]) => unknown
43
+
44
+ type ServerGotQueries = { version: number; patch: GotQueryPatchOp[] }
45
+
28
46
  type PullResponse =
29
47
  | {
30
48
  cookie: number
31
49
  lastMutationIDChanges: Record<string, number>
32
50
  rowsPatch: unknown[]
33
51
  unchanged?: false
52
+ gotQueries?: ServerGotQueries
34
53
  }
35
54
  | {
36
55
  cookie: number | null
37
56
  unchanged: true
57
+ gotQueries?: ServerGotQueries
38
58
  }
39
59
 
40
60
  type TransportState = {
@@ -44,6 +64,10 @@ type TransportState = {
44
64
  readonly nativeWebSocket: WebSocketConstructor | undefined
45
65
  readonly sockets: Set<ZeroHttpSocket>
46
66
  readonly pullIntervalMs: number | undefined
67
+ readonly wakeEnabled: boolean
68
+ readonly queryTransform: QueryTransform | undefined
69
+ readonly queryForward: boolean
70
+ readonly queryAware: boolean
47
71
  nextPokeID: number
48
72
  transientFailureCount: number
49
73
  }
@@ -64,6 +88,20 @@ export type HttpPullTransportOptions = {
64
88
  // when set, every open connection also pulls on this interval so
65
89
  // server-initiated changes arrive without a client-side trigger
66
90
  pullIntervalMs?: number
91
+ // when true, each connection also opens a notification-only wake socket to
92
+ // <origin>/wake and pulls immediately on any wake, demoting the interval
93
+ // poll to a safety net. the wake channel carries no data ("pull now" only)
94
+ // and zero correctness weight: a lost or duplicated wake can never cause
95
+ // missed or wrong data because convergence comes from the pull protocol.
96
+ wake?: boolean
97
+ // when provided, the query-aware extension is on and desired queries are
98
+ // resolved client-side to an AST before shipping (native host / trusted
99
+ // harness). omit for the baseline dialect (client-local got-query synthesis).
100
+ queryTransform?: QueryTransform
101
+ // turns the query-aware extension on WITHOUT a client-side transform: desired
102
+ // queries ship as name+args for the SERVER (consumer worker) to resolve with
103
+ // auth. the production path for permission-transformed queries.
104
+ queryForward?: boolean
67
105
  }
68
106
 
69
107
  export function installHttpPullTransport(
@@ -85,6 +123,10 @@ export function installHttpPullTransport(
85
123
  nativeWebSocket: previousWebSocket,
86
124
  sockets: new Set(),
87
125
  pullIntervalMs: opts.pullIntervalMs,
126
+ wakeEnabled: opts.wake ?? false,
127
+ queryTransform: opts.queryTransform,
128
+ queryForward: opts.queryForward === true,
129
+ queryAware: opts.queryTransform !== undefined || opts.queryForward === true,
88
130
  nextPokeID: 0,
89
131
  transientFailureCount: 0,
90
132
  }
@@ -161,12 +203,22 @@ class ZeroHttpSocket {
161
203
  private readonly wsid: string
162
204
  private cookie: string | null
163
205
  private pendingGotQueriesPatch: GotQueryPatchOp[] = []
206
+ // query-aware extension state: the accumulated un-acked desired-query delta
207
+ // to ship, a client-side query-state version that bumps on each change, and
208
+ // the version/length of the delta the in-flight pull sent (to clear the
209
+ // acked prefix on the server's ack).
210
+ private desiredQueryPatch: QueryPatchOp[] = []
211
+ private queryVersion = 0
212
+ private sentQueryVersion: number | undefined
213
+ private sentQueryPatchLen = 0
164
214
  private pullInFlight: Promise<void> | undefined
165
215
  private pullAfterCurrent = false
166
216
  private pushChain: Promise<void> = Promise.resolve()
167
217
  private nextLocalCookieID: number
168
218
  private openTimer: ReturnType<typeof setTimeout> | undefined
169
219
  private pullTimer: ReturnType<typeof setInterval> | undefined
220
+ private wakeSocket: { close(): void } | undefined
221
+ private wakeReconnectTimer: ReturnType<typeof setTimeout> | undefined
170
222
 
171
223
  constructor(
172
224
  private readonly state: TransportState,
@@ -245,6 +297,7 @@ class ZeroHttpSocket {
245
297
  if (this.readyState === this.CLOSED) return
246
298
  if (this.openTimer) clearTimeout(this.openTimer)
247
299
  if (this.pullTimer) clearInterval(this.pullTimer)
300
+ this.closeWakeChannel()
248
301
  this.readyState = this.CLOSED
249
302
  this.state.sockets.delete(this)
250
303
  this.emit('close', { code, reason, wasClean: code <= 1001 })
@@ -253,8 +306,9 @@ class ZeroHttpSocket {
253
306
  pull(): Promise<void> {
254
307
  if (this.readyState !== this.OPEN) return Promise.resolve()
255
308
  if (this.pullInFlight) return this.pullInFlight
256
- this.pullInFlight = this.fetchPull(this.clientGroupID, this.cookie)
309
+ this.pullInFlight = this.fetchPull(this.clientGroupID, this.cookie, true)
257
310
  .then((response) => {
311
+ if (this.state.queryAware) this.applyServerGotQueries(response)
258
312
  if (response.unchanged) {
259
313
  this.emitGotQueriesPatch(response.cookie)
260
314
  return
@@ -285,13 +339,104 @@ class ZeroHttpSocket {
285
339
  this.run(this.pull())
286
340
  }, this.state.pullIntervalMs)
287
341
  }
342
+ if (this.state.wakeEnabled) this.openWakeChannel()
343
+ }
344
+
345
+ // notification-only wake channel: a real WebSocket to <origin>/wake that
346
+ // carries no data. any frame means "pull now", so a wake triggers an
347
+ // immediate (coalesced) pull — push-shaped propagation without waiting on
348
+ // the poll interval. advisory only: if it drops we reconnect, and the
349
+ // interval poll remains the safety net that guarantees convergence.
350
+ private openWakeChannel() {
351
+ const Native = this.state.nativeWebSocket
352
+ if (!Native || this.wakeSocket || this.readyState !== this.OPEN) return
353
+ const wsBase = this.state.originString.replace(/^http/, 'ws')
354
+ const url = `${wsBase}/wake?clientID=${encodeURIComponent(this.clientID)}`
355
+ let socket: {
356
+ onmessage: (() => void) | null
357
+ onclose: (() => void) | null
358
+ onerror: (() => void) | null
359
+ close(): void
360
+ }
361
+ try {
362
+ socket = new Native(url) as unknown as typeof socket
363
+ } catch {
364
+ return
365
+ }
366
+ this.wakeSocket = socket
367
+ const reconnect = () => {
368
+ if (this.wakeSocket !== socket) return
369
+ this.wakeSocket = undefined
370
+ if (this.readyState !== this.OPEN || this.wakeReconnectTimer) return
371
+ this.wakeReconnectTimer = setTimeout(() => {
372
+ this.wakeReconnectTimer = undefined
373
+ this.openWakeChannel()
374
+ }, 500)
375
+ }
376
+ // route through requestPullAfterCurrent, NOT pull() directly: a wake that
377
+ // lands while a pull is already in flight must set pullAfterCurrent so the
378
+ // in-flight pull re-runs and picks up the woken change. calling pull()
379
+ // directly would return the existing promise and silently drop the wake,
380
+ // leaving convergence to the safety poll (a burst-storm latency bug).
381
+ socket.onmessage = () => this.requestPullAfterCurrent()
382
+ socket.onclose = reconnect
383
+ socket.onerror = reconnect
384
+ }
385
+
386
+ private closeWakeChannel() {
387
+ if (this.wakeReconnectTimer) {
388
+ clearTimeout(this.wakeReconnectTimer)
389
+ this.wakeReconnectTimer = undefined
390
+ }
391
+ const socket = this.wakeSocket
392
+ this.wakeSocket = undefined
393
+ if (socket) {
394
+ try {
395
+ socket.close()
396
+ } catch {
397
+ // best effort: an already-closing wake socket is harmless
398
+ }
399
+ }
288
400
  }
289
401
 
290
402
  private queueDesiredQueries(body: unknown) {
291
403
  const desiredQueriesPatch = (body as { desiredQueriesPatch?: unknown })
292
404
  ?.desiredQueriesPatch
293
405
  if (!Array.isArray(desiredQueriesPatch)) return
294
- this.pendingGotQueriesPatch.push(...gotQueriesPatch(desiredQueriesPatch))
406
+ if (!this.state.queryAware) {
407
+ // baseline dialect: synthesize the got-query ack locally
408
+ this.pendingGotQueriesPatch.push(...gotQueriesPatch(desiredQueriesPatch))
409
+ return
410
+ }
411
+ // query-aware: accumulate the desired-query delta to ship to the server. a
412
+ // put ships its inline ast, or a client-resolved ast (queryTransform), or
413
+ // name+args for the server to resolve (queryForward). the server owns the
414
+ // got-query ack.
415
+ const transform = this.state.queryTransform
416
+ for (const op of desiredQueriesPatch as DesiredQueryPatchOp[]) {
417
+ if (op.op === 'clear') {
418
+ this.desiredQueryPatch.push({ op: 'clear' })
419
+ } else if (op.op === 'del') {
420
+ this.desiredQueryPatch.push({ op: 'del', hash: op.hash })
421
+ } else if (op.op === 'put') {
422
+ const inline = (op as { ast?: unknown }).ast
423
+ const name = (op as { name?: string }).name ?? ''
424
+ const args = ((op as { args?: readonly unknown[] }).args ??
425
+ []) as readonly unknown[]
426
+ if (this.state.queryForward) {
427
+ this.desiredQueryPatch.push({ op: 'put', hash: op.hash, name, args })
428
+ } else if (inline !== undefined) {
429
+ this.desiredQueryPatch.push({ op: 'put', hash: op.hash, ast: inline })
430
+ } else if (transform) {
431
+ this.desiredQueryPatch.push({
432
+ op: 'put',
433
+ hash: op.hash,
434
+ ast: transform(name, args),
435
+ })
436
+ }
437
+ }
438
+ }
439
+ this.queryVersion++
295
440
  }
296
441
 
297
442
  private async push(body: unknown) {
@@ -328,12 +473,30 @@ class ZeroHttpSocket {
328
473
  this.run(this.pull())
329
474
  }
330
475
 
476
+ // in query-aware mode the got-query ack is authoritative from the server:
477
+ // take the server's gotQueries.patch as the got patch to emit (replacing
478
+ // local synthesis), and clear the acked prefix of the shipped desired delta
479
+ // once the server acks that version (the ack never leads its row effects —
480
+ // invariant 13 — so the client marks a query got only after its rows land).
481
+ private applyServerGotQueries(response: PullResponse) {
482
+ const got = response.gotQueries
483
+ this.pendingGotQueriesPatch = got ? got.patch : []
484
+ if (
485
+ got &&
486
+ this.sentQueryVersion !== undefined &&
487
+ got.version >= this.sentQueryVersion
488
+ ) {
489
+ this.desiredQueryPatch.splice(0, this.sentQueryPatchLen)
490
+ this.sentQueryVersion = undefined
491
+ }
492
+ }
493
+
331
494
  private async answerMutationRecoveryPull(body: {
332
495
  clientGroupID: string
333
496
  cookie: string | null
334
497
  requestID: string
335
498
  }) {
336
- const response = await this.fetchPull(body.clientGroupID, body.cookie)
499
+ const response = await this.fetchPull(body.clientGroupID, body.cookie, false)
337
500
  const cookie = toWebSocketCookie(response.cookie)
338
501
  this.emitMessage([
339
502
  'pull',
@@ -345,12 +508,27 @@ class ZeroHttpSocket {
345
508
  ])
346
509
  }
347
510
 
348
- private async fetchPull(clientGroupID: string, cookie: string | null) {
349
- return (await this.postJSON('/pull', {
511
+ private async fetchPull(
512
+ clientGroupID: string,
513
+ cookie: string | null,
514
+ includeQueries: boolean,
515
+ ) {
516
+ const body: Record<string, unknown> = {
350
517
  clientID: this.clientID,
351
518
  clientGroupID,
352
519
  cookie: toHttpCookie(cookie),
353
- })) as PullResponse
520
+ }
521
+ // ship the un-acked desired-query delta with the pull; remember what we
522
+ // sent so the server ack can clear exactly that prefix. a recovery pull
523
+ // (includeQueries=false) never carries desires.
524
+ if (includeQueries && this.state.queryAware && this.desiredQueryPatch.length > 0) {
525
+ this.sentQueryVersion = this.queryVersion
526
+ this.sentQueryPatchLen = this.desiredQueryPatch.length
527
+ body.queries = { version: this.queryVersion, patch: [...this.desiredQueryPatch] }
528
+ } else {
529
+ this.sentQueryVersion = undefined
530
+ }
531
+ return (await this.postJSON('/pull', body)) as PullResponse
354
532
  }
355
533
 
356
534
  private async postJSON(path: '/pull' | '/push', body: unknown) {
@@ -410,11 +588,23 @@ class ZeroHttpSocket {
410
588
  }
411
589
 
412
590
  private emitPoke(response: Exclude<PullResponse, { unchanged: true }>) {
413
- const nextCookie = toWebSocketCookie(response.cookie)
414
- if (isStaleCookie(this.cookie, response.cookie)) {
591
+ const currentServer = toHttpCookie(this.cookie)
592
+ let nextCookie: string
593
+ if (currentServer !== null && response.cookie < currentServer) {
594
+ // the server watermark is BEHIND the client: a real reset/restore. mirror
595
+ // the 409 stale path instead of poking the client backwards.
415
596
  throw new Error(
416
597
  `zero-http pull returned stale cookie ${response.cookie} for ${this.cookie}`,
417
598
  )
599
+ } else if (currentServer !== null && response.cookie === currentServer) {
600
+ // same server watermark but a non-empty patch: a query-aware membership
601
+ // delta (a desired-query change recomputes rows without advancing the
602
+ // change log). bump a client-local cookie id so replicache sees a changed
603
+ // cookie — otherwise it trips "cookie did not change, but patch is not
604
+ // empty" and drops the patch.
605
+ nextCookie = toLocalWebSocketCookie(response.cookie, ++this.nextLocalCookieID)
606
+ } else {
607
+ nextCookie = toWebSocketCookie(response.cookie) as string
418
608
  }
419
609
 
420
610
  const pokeID = `zero-http-${++this.state.nextPokeID}`
@@ -576,11 +766,6 @@ function toLocalWebSocketCookie(cookie: number, localID: number): string {
576
766
  )}`
577
767
  }
578
768
 
579
- function isStaleCookie(current: string | null, next: number) {
580
- const currentNumber = toHttpCookie(current)
581
- return currentNumber !== null && next <= currentNumber
582
- }
583
-
584
769
  function errorMessage(error: unknown) {
585
770
  return error instanceof Error ? error.message : String(error)
586
771
  }
@@ -8,9 +8,7 @@
8
8
  // matching the package's other cross-module registries.
9
9
 
10
10
  import { globalValue } from '@take-out/helpers'
11
-
12
11
  import { getQueryName } from './queryRegistry'
13
-
14
12
  import type { ZeroRunner } from './zeroRunner'
15
13
  import type { AnyQueryRegistry } from '@rocicorp/zero'
16
14
 
@@ -28,16 +26,25 @@ const getInstancesByNamespace = () =>
28
26
  () => new Map(),
29
27
  )
30
28
 
29
+ const getInstancesByQueryName = () =>
30
+ globalValue<Map<string, ZeroClientInstance>>(
31
+ 'on-zero:instances-by-query-name',
32
+ () => new Map(),
33
+ )
34
+
31
35
  export function registerClientInstance({
32
36
  name,
33
37
  namespaces,
34
38
  customQueries,
39
+ queryNames = [],
35
40
  }: {
36
41
  name: string
37
42
  namespaces: string[]
38
43
  customQueries: AnyQueryRegistry
44
+ queryNames?: string[]
39
45
  }): ZeroClientInstance {
40
46
  const instancesByNamespace = getInstancesByNamespace()
47
+ const instancesByQueryName = getInstancesByQueryName()
41
48
 
42
49
  // re-creating an instance under the same name (hmr) replaces its claims
43
50
  for (const [namespace, owner] of instancesByNamespace) {
@@ -45,6 +52,11 @@ export function registerClientInstance({
45
52
  instancesByNamespace.delete(namespace)
46
53
  }
47
54
  }
55
+ for (const [queryName, owner] of instancesByQueryName) {
56
+ if (owner.name === name) {
57
+ instancesByQueryName.delete(queryName)
58
+ }
59
+ }
48
60
 
49
61
  const instance: ZeroClientInstance = { name, customQueries, runner: null }
50
62
 
@@ -59,6 +71,17 @@ export function registerClientInstance({
59
71
  instancesByNamespace.set(namespace, instance)
60
72
  }
61
73
 
74
+ for (const queryName of queryNames) {
75
+ const existing = instancesByQueryName.get(queryName)
76
+ if (existing) {
77
+ throw new Error(
78
+ `[on-zero] query '${queryName}' is already claimed by zero client instance '${existing.name}' ` +
79
+ `(while creating instance '${name}'). Each query function must belong to exactly one createZeroClient instance.`,
80
+ )
81
+ }
82
+ instancesByQueryName.set(queryName, instance)
83
+ }
84
+
62
85
  return instance
63
86
  }
64
87
 
@@ -71,5 +94,7 @@ export function getInstanceForNamespace(
71
94
  export function getInstanceForQueryFn(fn: Function): ZeroClientInstance | undefined {
72
95
  const queryName = getQueryName(fn)
73
96
  if (!queryName) return undefined
97
+ const queryOwner = getInstancesByQueryName().get(queryName)
98
+ if (queryOwner) return queryOwner
74
99
  return getInstanceForNamespace(queryName.split('.', 1)[0])
75
100
  }
@@ -1,16 +1,18 @@
1
1
  import { createSchema, string, table } from '@rocicorp/zero'
2
2
  import { createEmitter } from '@take-out/helpers'
3
3
  import { describe, expect, test, vi } from 'vitest'
4
-
5
4
  import { combineZeroClients } from './combineZeroClients'
6
5
  import { createZeroClient } from './createZeroClient'
7
6
  import { runWithContext } from './helpers/mutatorContext'
8
- import { getInstanceForNamespace, registerClientInstance } from './instanceRegistry'
7
+ import {
8
+ getInstanceForNamespace,
9
+ getInstanceForQueryFn,
10
+ registerClientInstance,
11
+ } from './instanceRegistry'
9
12
  import { registerQuery } from './queryRegistry'
10
13
  import { run } from './run'
11
14
  import { setRunner, type ZeroRunner } from './zeroRunner'
12
15
  import { zql } from './zql'
13
-
14
16
  import type { ZeroEvent } from './types'
15
17
  import type { AnyQueryRegistry, Query } from '@rocicorp/zero'
16
18
  import type { ReactNode } from 'react'
@@ -74,8 +76,8 @@ describe('multi-instance namespace dispatch', () => {
74
76
  // simulate each instance's provider mount (SetZeroInstance)
75
77
  const controlRunner = vi.fn(async (..._args: unknown[]) => ({ from: 'control' }))
76
78
  const projectRunner = vi.fn(async (..._args: unknown[]) => ({ from: 'project' }))
77
- getInstanceForNamespace('runUser')!.runner = controlRunner as ZeroRunner
78
- getInstanceForNamespace('runTask')!.runner = projectRunner as ZeroRunner
79
+ getInstanceForQueryFn(control.byId)!.runner = controlRunner as ZeroRunner
80
+ getInstanceForQueryFn(project.byId)!.runner = projectRunner as ZeroRunner
79
81
 
80
82
  // the last mount also claims the ambient runner — owned namespaces must
81
83
  // not use it (this is the "second mount steals run()" bug)
@@ -94,7 +96,7 @@ describe('multi-instance namespace dispatch', () => {
94
96
  test('run() rejects named queries inside server mutation context', async () => {
95
97
  const { byId } = makeClient('run-ctx-owner', 'runCtxThing')
96
98
  const ownerRunner = vi.fn(async (..._args: unknown[]) => ({ from: 'owner' }))
97
- getInstanceForNamespace('runCtxThing')!.runner = ownerRunner as ZeroRunner
99
+ getInstanceForQueryFn(byId)!.runner = ownerRunner as ZeroRunner
98
100
  const txRun = vi.fn(async (..._args: unknown[]) => ({ from: 'tx' }))
99
101
 
100
102
  await expect(
@@ -116,7 +118,7 @@ describe('multi-instance namespace dispatch', () => {
116
118
  test('run() keeps named queries on their owning client runner when browser context leaks', async () => {
117
119
  const { byId } = makeClient('run-client-leak-owner', 'runClientLeakThing')
118
120
  const ownerRunner = vi.fn(async (..._args: unknown[]) => ({ from: 'owner' }))
119
- getInstanceForNamespace('runClientLeakThing')!.runner = ownerRunner as ZeroRunner
121
+ getInstanceForQueryFn(byId)!.runner = ownerRunner as ZeroRunner
120
122
  const txRun = vi.fn(async (..._args: unknown[]) => ({ from: 'tx' }))
121
123
 
122
124
  await expect(
@@ -173,9 +175,9 @@ describe('multi-instance namespace dispatch', () => {
173
175
  })
174
176
 
175
177
  test('re-creating an instance under the same name re-claims without throwing (hmr)', () => {
176
- makeClient('hmr', 'hmrNs')
178
+ const first = makeClient('hmr', 'hmrNs')
177
179
  expect(() => makeClient('hmr', 'hmrNs')).not.toThrow()
178
- expect(getInstanceForNamespace('hmrNs')?.name).toBe('hmr')
180
+ expect(getInstanceForQueryFn(first.byId)?.name).toBe('hmr')
179
181
  })
180
182
 
181
183
  test('model namespaces are claimed too', () => {
@@ -7,6 +7,7 @@
7
7
  // queries get `[undefined, info]` instead (the established zero-react shape).
8
8
 
9
9
  import { createSchema, number, string, table } from '@rocicorp/zero'
10
+ import { useQuery as useRawZeroQuery } from '@rocicorp/zero/react'
10
11
  import { IS_SERVER, IS_SERVER_RUNTIME } from '@take-out/helpers'
11
12
  import { act } from 'react'
12
13
  import { createRoot, type Root } from 'react-dom/client'
@@ -102,3 +103,10 @@ test('useQuery returns undefined (not null) for singular queries under DisabledC
102
103
  expect(data).toBeUndefined()
103
104
  expect(info?.type).toBe('unknown')
104
105
  })
106
+
107
+ test('raw zero-react useQuery stays inert under a disabled provider', () => {
108
+ const query = client.getQuery(allTodos)
109
+ const [data, info] = renderWithDisabled(() => useRawZeroQuery(query))
110
+ expect(data).toEqual([])
111
+ expect(info?.type).toBe('unknown')
112
+ })
@@ -1 +1 @@
1
- {"version":3,"file":"createZeroClient.d.ts","sourceRoot":"","sources":["../src/createZeroClient.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAO/E,OAAO,EAAoC,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAClF,OAAO,EAQL,KAAK,OAAO,EACZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAId,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE3B,MAAM,6BAA6B,CAAA;AAIpC,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAOhE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAClF,OAAO,KAAK,EACV,gBAAgB,EAChB,KAAK,EACL,GAAG,EAEH,WAAW,EACX,MAAM,IAAI,UAAU,EACrB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,cAAc,GAAG;IAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAEvE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;AAMpF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,CAAA;AAEtF,MAAM,MAAM,uBAAuB,CACjC,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,IAC1B;IACF,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;IAC9B,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IAIvC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,MAAM,SAAS,UAAU,IAAI,CAAC,KAAK,EAAE;IAClE,eAAe,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC1C,aAAa,EAAE,gBAAgB,CAAA;IAC/B,OAAO,EAAE,MAAM,GAAG,CAAA;IAClB,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAC7B,KAAK,YAAY,CAAC,MAAM,CAAC,CAAA;AA+B1B,wBAAgB,gBAAgB,CAAC,MAAM,SAAS,UAAU,EAAE,MAAM,SAAS,aAAa,EACtF,OAAO,EAAE,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC;;;;kBA4YpC,SAAS;;kBAUT,OAAO;oBAIL,WAAW;yBAGN,MAAM;8BAGF,OAAO,CAAC,IAAI,CAAC;gCAIX,qBAAqB,KAAK,IAAI;uBAGtC,oBAAoB;qCAGP,MAAM,KAAK,OAAO;6BAG1B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;4BAI3B,OAAO;;;kBAgYjB,SAAS;iBACV,QAAQ,GAAG,SAAS;uBACd,OAAO,GAAG,YAAY;;;;uFAjlBxB,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,YACrC,OAAO,UACT,OAAO,KACZ,OAAO,GAAG,IAAI;6FAHR,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,YACrC,OAAO,UACT,OAAO,KACZ,OAAO,GAAG,IAAI;;;SAqiBN,IAAI,EAAE,MAAM,0CAA0C,OAAO,kFAGlE,cAAc;2BACN,IAAI;sBAAY,OAAO,CAAC,IAAI,CAAC;;SAChC,MAAM,0CAA0C,OAAO,oEAE5D,cAAc;2BACN,IAAI;sBAAY,OAAO,CAAC,IAAI,CAAC;;;;SAe/B,IAAI,EAAE,MAAM,0CAA0C,OAAO,yEAG5E,UAAU,CAAC,OAAO,YAAY,QAAQ,CAAC;SACxB,MAAM,0CAA0C,OAAO,2DAEtE,UAAU,CAAC,OAAO,YAAY,QAAQ,CAAC;;;yBAldK,OAAO;UAAU,OAAO,CAAC,OAAO,CAAC;EAlVjF;AAED,wBAAgB,wBAAwB,CACtC,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,EAC5B,EACA,MAAM,EACN,MAAM,EACN,cAAc,EACd,kBAAiC,EACjC,YAAwB,EACxB,oBAAoB,GACrB,EAAE,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;IAC3C,oBAAoB,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAA;CAClD;;;;kBA2Xa,SAAS;mBACR,QAAQ,GAAG,IAAI;kBAShB,OAAO;oBAIL,WAAW;yBAGN,MAAM;uBAGR,MAAM,OAAO,CAAC,IAAI,CAAC;yBAIjB,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI;uBAGtC,oBAAoB;0BAGjB,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO;sBAGhC,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;4BAI3B,OAAO;;0DA+X1B;QACD,QAAQ,EAAE,SAAS,CAAA;QACnB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;QAC7B,YAAY,CAAC,EAAE,OAAO,GAAG,YAAY,CAAA;KACtC;;;2BAnlBY,oCAAY,CAAC,MAAM,GAAG,EAAE,CAAC,WACvB,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,YACrC,OAAO,UACT,OAAO,KACZ,OAAO,GAAG,IAAI;iCAJV,oCAAY,CAAC,MAAM,GAAG,EAAE,CAAC,WACvB,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,YACrC,OAAO,UACT,OAAO,KACZ,OAAO,GAAG,IAAI;;;SAqiBN,IAAI,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,MACxE,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,UAC9C,IAAI,YACF,cAAc,GACvB;YAAE,OAAO,EAAE,MAAM,IAAI,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE;SAClC,MAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,MAClE,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,YAC5C,cAAc,GACvB;YAAE,OAAO,EAAE,MAAM,IAAI,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE;;;SAejC,IAAI,EAAE,MAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,MACzE,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,UAC9C,IAAI,GACX,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;SACxB,MAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,MACnE,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,GACrD,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;;oBAldd;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,KAAQ,OAAO,CAAC,OAAO,CAAC;EAkfjF"}
1
+ {"version":3,"file":"createZeroClient.d.ts","sourceRoot":"","sources":["../src/createZeroClient.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAqC,YAAY,EAAE,MAAM,oBAAoB,CAAA;AA4kBzF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACrC,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,KAAK,GAAG,MAAM,CAAA;CAC5B,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;CACnE,CAAA;AAkCD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAiF3E;AAED,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAgXhF;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,yCAmChD"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAqC,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAslBzF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACrC,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,KAAK,GAAG,MAAM,CAAA;CAC5B,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;CACnE,CAAA;AAkCD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAiF3E;AAED,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAgXhF;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,yCAmChD"}
@@ -1 +1 @@
1
- {"version":3,"file":"createMutators.d.ts","sourceRoot":"","sources":["../../src/helpers/createMutators.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,QAAQ,EACR,GAAG,EACH,aAAa,EACb,eAAe,EAGhB,MAAM,UAAU,CAAA;AAEjB,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1B,YAAY,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,CAAA;AAE9D,wBAAgB,cAAc,CAAC,MAAM,SAAS,aAAa,EAAE,EAC3D,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,UAAe,EACf,GAAG,EACH,MAAM,EACN,gBAAgB,EAChB,kBAAkB,GACnB,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/C,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;IACrC,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;CACzD,GAAG,eAAe,CAAC,MAAM,CAAC,CAkK1B"}
1
+ {"version":3,"file":"createMutators.d.ts","sourceRoot":"","sources":["../../src/helpers/createMutators.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,QAAQ,EACR,GAAG,EACH,aAAa,EACb,eAAe,EAGhB,MAAM,UAAU,CAAA;AAEjB,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1B,YAAY,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,CAAA;AAE9D,wBAAgB,cAAc,CAAC,MAAM,SAAS,aAAa,EAAE,EAC3D,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,UAAe,EACf,GAAG,EACH,MAAM,EACN,gBAAgB,EAChB,kBAAkB,GACnB,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/C,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;IACrC,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;CACzD,GAAG,eAAe,CAAC,MAAM,CAAC,CAuK1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createMutators.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMutators.test.d.ts","sourceRoot":"","sources":["../../src/helpers/createMutators.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=completeAck.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completeAck.test.d.ts","sourceRoot":"","sources":["../../src/httpPull/completeAck.test.ts"],"names":[],"mappings":""}