@rocicorp/zero 1.12.0-canary.12 → 1.12.0-canary.13

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 (211) hide show
  1. package/out/replicache/src/btree/diff.d.ts.map +1 -1
  2. package/out/replicache/src/btree/diff.js +1 -2
  3. package/out/replicache/src/btree/diff.js.map +1 -1
  4. package/out/replicache/src/btree/read.d.ts +31 -1
  5. package/out/replicache/src/btree/read.d.ts.map +1 -1
  6. package/out/replicache/src/btree/read.js +74 -19
  7. package/out/replicache/src/btree/read.js.map +1 -1
  8. package/out/replicache/src/btree/splice.d.ts.map +1 -1
  9. package/out/replicache/src/btree/splice.js +2 -1
  10. package/out/replicache/src/btree/splice.js.map +1 -1
  11. package/out/replicache/src/btree/write.d.ts.map +1 -1
  12. package/out/replicache/src/btree/write.js +2 -1
  13. package/out/replicache/src/btree/write.js.map +1 -1
  14. package/out/replicache/src/persist/collect-idb-databases.d.ts +1 -0
  15. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  16. package/out/replicache/src/persist/collect-idb-databases.js +13 -5
  17. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  18. package/out/replicache/src/scan-iterator.js +1 -1
  19. package/out/replicache/src/sync/request-id.js +2 -2
  20. package/out/replicache/src/sync/request-id.js.map +1 -1
  21. package/out/shared/src/bigint-json.d.ts.map +1 -1
  22. package/out/shared/src/bigint-json.js +1 -0
  23. package/out/shared/src/bigint-json.js.map +1 -1
  24. package/out/shared/src/btree-set.d.ts +21 -0
  25. package/out/shared/src/btree-set.d.ts.map +1 -1
  26. package/out/shared/src/btree-set.js +54 -0
  27. package/out/shared/src/btree-set.js.map +1 -1
  28. package/out/shared/src/headers.js +20 -0
  29. package/out/shared/src/headers.js.map +1 -0
  30. package/out/shared/src/natural-runs.d.ts +191 -0
  31. package/out/shared/src/natural-runs.d.ts.map +1 -0
  32. package/out/shared/src/natural-runs.js +337 -0
  33. package/out/shared/src/natural-runs.js.map +1 -0
  34. package/out/shared/src/random-uint64.d.ts.map +1 -1
  35. package/out/shared/src/random-uint64.js +2 -2
  36. package/out/shared/src/random-uint64.js.map +1 -1
  37. package/out/shared/src/random-values.d.ts +19 -1
  38. package/out/shared/src/random-values.d.ts.map +1 -1
  39. package/out/shared/src/random-values.js +38 -4
  40. package/out/shared/src/random-values.js.map +1 -1
  41. package/out/shared/src/tuple-map.d.ts +22 -0
  42. package/out/shared/src/tuple-map.d.ts.map +1 -0
  43. package/out/shared/src/tuple-map.js +48 -0
  44. package/out/shared/src/tuple-map.js.map +1 -0
  45. package/out/zero/package.js +1 -1
  46. package/out/zero/package.js.map +1 -1
  47. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  48. package/out/zero-cache/src/auth/auth.js +5 -0
  49. package/out/zero-cache/src/auth/auth.js.map +1 -1
  50. package/out/zero-cache/src/config/zero-config.d.ts +21 -0
  51. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  52. package/out/zero-cache/src/config/zero-config.js +47 -9
  53. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  54. package/out/zero-cache/src/custom-queries/transform-query.js +2 -2
  55. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  56. package/out/zero-cache/src/db/pg-to-lite.d.ts.map +1 -1
  57. package/out/zero-cache/src/db/pg-to-lite.js +3 -2
  58. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  59. package/out/zero-cache/src/db/pg-type-parser.js +55 -2
  60. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  61. package/out/zero-cache/src/server/change-streamer.js +5 -2
  62. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  63. package/out/zero-cache/src/server/inspector-delegate.js +6 -29
  64. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  65. package/out/zero-cache/src/server/main.js +5 -0
  66. package/out/zero-cache/src/server/main.js.map +1 -1
  67. package/out/zero-cache/src/server/replicator.js +3 -2
  68. package/out/zero-cache/src/server/replicator.js.map +1 -1
  69. package/out/zero-cache/src/server/syncer.js +5 -4
  70. package/out/zero-cache/src/server/syncer.js.map +1 -1
  71. package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
  72. package/out/zero-cache/src/server/worker-dispatcher.js +2 -1
  73. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  74. package/out/zero-cache/src/services/admin-auth.d.ts +22 -0
  75. package/out/zero-cache/src/services/admin-auth.d.ts.map +1 -0
  76. package/out/zero-cache/src/services/admin-auth.js +42 -0
  77. package/out/zero-cache/src/services/admin-auth.js.map +1 -0
  78. package/out/zero-cache/src/services/auth-attempt-counter.d.ts +33 -0
  79. package/out/zero-cache/src/services/auth-attempt-counter.d.ts.map +1 -0
  80. package/out/zero-cache/src/services/auth-attempt-counter.js +61 -0
  81. package/out/zero-cache/src/services/auth-attempt-counter.js.map +1 -0
  82. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +1 -1
  83. package/out/zero-cache/src/services/change-source/pg/change-source.js +110 -13
  84. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  85. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +13 -7
  86. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  87. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +38 -5
  88. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  89. package/out/zero-cache/src/services/change-source/pg/schema/init.js +10 -1
  90. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  91. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +4 -0
  92. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  93. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +10 -3
  94. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  95. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +23 -2
  96. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  97. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +2 -2
  98. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  99. package/out/zero-cache/src/services/change-streamer/change-streamer.js +10 -3
  100. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  101. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  102. package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
  103. package/out/zero-cache/src/services/heapz.js +4 -5
  104. package/out/zero-cache/src/services/heapz.js.map +1 -1
  105. package/out/zero-cache/src/services/mutagen/error.d.ts +5 -0
  106. package/out/zero-cache/src/services/mutagen/error.d.ts.map +1 -1
  107. package/out/zero-cache/src/services/mutagen/error.js +7 -1
  108. package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
  109. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  110. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  111. package/out/zero-cache/src/services/mutagen/pusher.js +1 -1
  112. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  113. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
  114. package/out/zero-cache/src/services/plannerz.js +3 -7
  115. package/out/zero-cache/src/services/plannerz.js.map +1 -1
  116. package/out/zero-cache/src/services/profz.d.ts.map +1 -1
  117. package/out/zero-cache/src/services/profz.js +4 -13
  118. package/out/zero-cache/src/services/profz.js.map +1 -1
  119. package/out/zero-cache/src/services/replicator/change-processor.js +29 -2
  120. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  121. package/out/zero-cache/src/services/replicator/incremental-sync.js +3 -3
  122. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  123. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  124. package/out/zero-cache/src/services/statz.js +2 -7
  125. package/out/zero-cache/src/services/statz.js.map +1 -1
  126. package/out/zero-cache/src/services/view-syncer/client-handler.js +22 -1
  127. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  128. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +40 -2
  129. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  130. package/out/zero-cache/src/services/view-syncer/cvr-store.js +54 -17
  131. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  132. package/out/zero-cache/src/services/view-syncer/cvr.js +11 -0
  133. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  134. package/out/zero-cache/src/services/view-syncer/inspect-auth-limiter.js +107 -0
  135. package/out/zero-cache/src/services/view-syncer/inspect-auth-limiter.js.map +1 -0
  136. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +11 -6
  137. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  138. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -1
  139. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  140. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +16 -14
  141. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  142. package/out/zero-cache/src/services/view-syncer/schema/cvr.js +4 -1
  143. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  144. package/out/zero-cache/src/services/view-syncer/schema/init.js +3 -0
  145. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
  146. package/out/zero-cache/src/services/view-syncer/view-syncer.js +89 -51
  147. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  148. package/out/zero-cache/src/types/client-group-log-id.d.ts +9 -0
  149. package/out/zero-cache/src/types/client-group-log-id.d.ts.map +1 -0
  150. package/out/zero-cache/src/types/client-group-log-id.js +16 -0
  151. package/out/zero-cache/src/types/client-group-log-id.js.map +1 -0
  152. package/out/zero-cache/src/types/lite.d.ts.map +1 -1
  153. package/out/zero-cache/src/types/lite.js +1 -0
  154. package/out/zero-cache/src/types/lite.js.map +1 -1
  155. package/out/zero-cache/src/types/pg.d.ts +13 -2
  156. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  157. package/out/zero-cache/src/types/pg.js +2 -2
  158. package/out/zero-cache/src/types/pg.js.map +1 -1
  159. package/out/zero-cache/src/types/poke-chunk.d.ts +25 -4
  160. package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
  161. package/out/zero-cache/src/types/poke-chunk.js +46 -5
  162. package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
  163. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  164. package/out/zero-cache/src/workers/connection.js +10 -3
  165. package/out/zero-cache/src/workers/connection.js.map +1 -1
  166. package/out/zero-cache/src/workers/rehome.d.ts +10 -0
  167. package/out/zero-cache/src/workers/rehome.d.ts.map +1 -1
  168. package/out/zero-cache/src/workers/rehome.js +4 -2
  169. package/out/zero-cache/src/workers/rehome.js.map +1 -1
  170. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +3 -2
  171. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  172. package/out/zero-cache/src/workers/syncer.js +15 -15
  173. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  174. package/out/zero-client/src/client/inspector/inspector.d.ts +4 -0
  175. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  176. package/out/zero-client/src/client/inspector/inspector.js +4 -0
  177. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  178. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +10 -2
  179. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
  180. package/out/zero-client/src/client/inspector/lazy-inspector.js +38 -31
  181. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  182. package/out/zero-client/src/client/inspector/query.d.ts +2 -2
  183. package/out/zero-client/src/client/inspector/query.d.ts.map +1 -1
  184. package/out/zero-client/src/client/inspector/query.js +4 -4
  185. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  186. package/out/zero-client/src/client/ivm-branch.d.ts +3 -0
  187. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  188. package/out/zero-client/src/client/ivm-branch.js +10 -5
  189. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  190. package/out/zero-client/src/client/reconnect-backoff.d.ts +31 -0
  191. package/out/zero-client/src/client/reconnect-backoff.d.ts.map +1 -0
  192. package/out/zero-client/src/client/reconnect-backoff.js +44 -0
  193. package/out/zero-client/src/client/reconnect-backoff.js.map +1 -0
  194. package/out/zero-client/src/client/version.js +1 -1
  195. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  196. package/out/zero-client/src/client/zero.js +7 -0
  197. package/out/zero-client/src/client/zero.js.map +1 -1
  198. package/out/zero-client/src/util/nanoid.js +2 -2
  199. package/out/zero-client/src/util/nanoid.js.map +1 -1
  200. package/out/zero-protocol/src/up.d.ts +42 -42
  201. package/out/zero-server/src/process-mutations.d.ts +10 -0
  202. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  203. package/out/zero-server/src/process-mutations.js +39 -6
  204. package/out/zero-server/src/process-mutations.js.map +1 -1
  205. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  206. package/out/zql/src/ivm/memory-source.js +89 -6
  207. package/out/zql/src/ivm/memory-source.js.map +1 -1
  208. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  209. package/out/zql/src/planner/planner-connection.js +37 -3
  210. package/out/zql/src/planner/planner-connection.js.map +1 -1
  211. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- import { getNonCryptoRandomValues } from "../../../shared/src/random-values.js";
1
+ import { getRandomValues } from "../../../shared/src/random-values.js";
2
2
  //#region ../zero-client/src/util/nanoid.ts
3
3
  function nanoid(size = 21) {
4
- return getNonCryptoRandomValues(new Uint8Array(size)).reduce((id, byte) => {
4
+ return getRandomValues(new Uint8Array(size)).reduce((id, byte) => {
5
5
  byte &= 63;
6
6
  if (byte < 36) id += byte.toString(36);
7
7
  else if (byte < 62) id += (byte - 26).toString(36).toUpperCase();
@@ -1 +1 @@
1
- {"version":3,"file":"nanoid.js","names":[],"sources":["../../../../../zero-client/src/util/nanoid.ts"],"sourcesContent":["// This is taken from https://github.com/ai/nanoid/blob/main/index.browser.js We\n// copy this because we want to use `--platform=neutral` which doesn't work with\n// the npm package.\n// Also we changed the random number generator to use Math.random() for compat\n// with React Native.\n\nimport {getNonCryptoRandomValues} from '../../../shared/src/random-values.ts';\n\nexport function nanoid(size = 21): string {\n // Use our custom getRandomValues function to fill a Uint8Array with random values.\n const randomBytes = getNonCryptoRandomValues(new Uint8Array(size));\n\n return randomBytes.reduce((id, byte) => {\n // It is incorrect to use bytes exceeding the alphabet size.\n // The following mask reduces the random byte in the 0-255 value\n // range to the 0-63 value range. Therefore, adding hacks, such\n // as empty string fallback or magic numbers, is unneccessary because\n // the bitmask trims bytes down to the alphabet size.\n byte &= 63;\n if (byte < 36) {\n // `0-9a-z`\n id += byte.toString(36);\n } else if (byte < 62) {\n // `A-Z`\n id += (byte - 26).toString(36).toUpperCase();\n } else if (byte > 62) {\n id += '-';\n } else {\n id += '_';\n }\n return id;\n }, '');\n}\n"],"mappings":";;AAQA,SAAgB,OAAO,OAAO,IAAY;CAIxC,OAFoB,yBAAyB,IAAI,WAAW,IAAI,CAEzD,CAAA,CAAY,QAAQ,IAAI,SAAS;EAMtC,QAAQ;EACR,IAAI,OAAO,IAET,MAAM,KAAK,SAAS,EAAE;OACjB,IAAI,OAAO,IAEhB,OAAO,OAAO,GAAA,CAAI,SAAS,EAAE,CAAC,CAAC,YAAY;OACtC,IAAI,OAAO,IAChB,MAAM;OAEN,MAAM;EAER,OAAO;CACT,GAAG,EAAE;AACP"}
1
+ {"version":3,"file":"nanoid.js","names":[],"sources":["../../../../../zero-client/src/util/nanoid.ts"],"sourcesContent":["// This is taken from https://github.com/ai/nanoid/blob/main/index.browser.js We\n// copy this because we want to use `--platform=neutral` which doesn't work with\n// the npm package.\n// Also we changed the random number generator to one that falls back to\n// Math.random() on runtimes without WebCrypto (e.g. React Native).\n\nimport {getRandomValues} from '../../../shared/src/random-values.ts';\n\nexport function nanoid(size = 21): string {\n // Use our custom getRandomValues function to fill a Uint8Array with random values.\n const randomBytes = getRandomValues(new Uint8Array(size));\n\n return randomBytes.reduce((id, byte) => {\n // It is incorrect to use bytes exceeding the alphabet size.\n // The following mask reduces the random byte in the 0-255 value\n // range to the 0-63 value range. Therefore, adding hacks, such\n // as empty string fallback or magic numbers, is unneccessary because\n // the bitmask trims bytes down to the alphabet size.\n byte &= 63;\n if (byte < 36) {\n // `0-9a-z`\n id += byte.toString(36);\n } else if (byte < 62) {\n // `A-Z`\n id += (byte - 26).toString(36).toUpperCase();\n } else if (byte > 62) {\n id += '-';\n } else {\n id += '_';\n }\n return id;\n }, '');\n}\n"],"mappings":";;AAQA,SAAgB,OAAO,OAAO,IAAY;CAIxC,OAFoB,gBAAgB,IAAI,WAAW,IAAI,CAEhD,CAAA,CAAY,QAAQ,IAAI,SAAS;EAMtC,QAAQ;EACR,IAAI,OAAO,IAET,MAAM,KAAK,SAAS,EAAE;OACjB,IAAI,OAAO,IAEhB,OAAO,OAAO,GAAA,CAAI,SAAS,EAAE,CAAC,CAAC,YAAY;OACtC,IAAI,OAAO,IAChB,MAAM;OAEN,MAAM;EAER,OAAO;CACT,GAAG,EAAE;AACP"}
@@ -85,6 +85,13 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
85
85
  }] | ["push", {
86
86
  clientGroupID: string;
87
87
  mutations: ({
88
+ type: "custom";
89
+ id: number;
90
+ clientID: string;
91
+ name: string;
92
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
93
+ timestamp: number;
94
+ } | {
88
95
  type: "crud";
89
96
  id: number;
90
97
  clientID: string;
@@ -113,13 +120,6 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
113
120
  })[];
114
121
  }];
115
122
  timestamp: number;
116
- } | {
117
- type: "custom";
118
- id: number;
119
- clientID: string;
120
- name: string;
121
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
122
- timestamp: number;
123
123
  })[];
124
124
  pushVersion: number;
125
125
  schemaVersion?: number | undefined;
@@ -216,6 +216,13 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
216
216
  }] | ["push", {
217
217
  clientGroupID: string;
218
218
  mutations: ({
219
+ type: "custom";
220
+ id: number;
221
+ clientID: string;
222
+ name: string;
223
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
224
+ timestamp: number;
225
+ } | {
219
226
  type: "crud";
220
227
  id: number;
221
228
  clientID: string;
@@ -244,13 +251,6 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
244
251
  })[];
245
252
  }];
246
253
  timestamp: number;
247
- } | {
248
- type: "custom";
249
- id: number;
250
- clientID: string;
251
- name: string;
252
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
253
- timestamp: number;
254
254
  })[];
255
255
  pushVersion: number;
256
256
  schemaVersion?: number | undefined;
@@ -346,6 +346,13 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
346
346
  }] | ["push", {
347
347
  clientGroupID: string;
348
348
  mutations: ({
349
+ type: "custom";
350
+ id: number;
351
+ clientID: string;
352
+ name: string;
353
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
354
+ timestamp: number;
355
+ } | {
349
356
  type: "crud";
350
357
  id: number;
351
358
  clientID: string;
@@ -374,13 +381,6 @@ export declare const upstreamSchema: v.Type<v.UnrecognizedTuple | ["ackMutationR
374
381
  })[];
375
382
  }];
376
383
  timestamp: number;
377
- } | {
378
- type: "custom";
379
- id: number;
380
- clientID: string;
381
- name: string;
382
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
383
- timestamp: number;
384
384
  })[];
385
385
  pushVersion: number;
386
386
  schemaVersion?: number | undefined;
@@ -478,6 +478,13 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
478
478
  }] | ["push", {
479
479
  clientGroupID: string;
480
480
  mutations: ({
481
+ type: "custom";
482
+ id: number;
483
+ clientID: string;
484
+ name: string;
485
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
486
+ timestamp: number;
487
+ } | {
481
488
  type: "crud";
482
489
  id: number;
483
490
  clientID: string;
@@ -506,13 +513,6 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
506
513
  })[];
507
514
  }];
508
515
  timestamp: number;
509
- } | {
510
- type: "custom";
511
- id: number;
512
- clientID: string;
513
- name: string;
514
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
515
- timestamp: number;
516
516
  })[];
517
517
  pushVersion: number;
518
518
  schemaVersion?: number | undefined;
@@ -609,6 +609,13 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
609
609
  }] | ["push", {
610
610
  clientGroupID: string;
611
611
  mutations: ({
612
+ type: "custom";
613
+ id: number;
614
+ clientID: string;
615
+ name: string;
616
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
617
+ timestamp: number;
618
+ } | {
612
619
  type: "crud";
613
620
  id: number;
614
621
  clientID: string;
@@ -637,13 +644,6 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
637
644
  })[];
638
645
  }];
639
646
  timestamp: number;
640
- } | {
641
- type: "custom";
642
- id: number;
643
- clientID: string;
644
- name: string;
645
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
646
- timestamp: number;
647
647
  })[];
648
648
  pushVersion: number;
649
649
  schemaVersion?: number | undefined;
@@ -739,6 +739,13 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
739
739
  }] | ["push", {
740
740
  clientGroupID: string;
741
741
  mutations: ({
742
+ type: "custom";
743
+ id: number;
744
+ clientID: string;
745
+ name: string;
746
+ args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
747
+ timestamp: number;
748
+ } | {
742
749
  type: "crud";
743
750
  id: number;
744
751
  clientID: string;
@@ -767,13 +774,6 @@ export declare const upstreamSchemaWithUnparsedAnalyzeQuery: v.Type<v.Unrecogniz
767
774
  })[];
768
775
  }];
769
776
  timestamp: number;
770
- } | {
771
- type: "custom";
772
- id: number;
773
- clientID: string;
774
- name: string;
775
- args: import("../../shared/src/json.ts").ReadonlyJSONValue[];
776
- timestamp: number;
777
777
  })[];
778
778
  pushVersion: number;
779
779
  schemaVersion?: number | undefined;
@@ -13,6 +13,11 @@ export interface TransactionProviderHooks {
13
13
  lastMutationID: number | bigint;
14
14
  }>;
15
15
  writeMutationResult: (result: MutationResponse) => Promise<void>;
16
+ /**
17
+ * `args.clientGroupID` is always the client group of the push being
18
+ * processed; a cleanup that names any other client group fails the push
19
+ * before this is called.
20
+ */
16
21
  deleteMutationResults: (args: CleanupResultsArg) => Promise<void>;
17
22
  }
18
23
  export interface TransactionProviderInput {
@@ -107,6 +112,11 @@ export declare function handleMutateRequest<D extends Database<ExtractTransactio
107
112
  */
108
113
  export declare const MAX_MUTATOR_RUNS = 5;
109
114
  export declare class OutOfOrderMutation extends Error {
115
+ /**
116
+ * The mutation ID the client should have sent. Kept out of the message,
117
+ * which is returned to the client; the server logs it separately.
118
+ */
119
+ readonly lastMutationID: number | bigint;
110
120
  constructor(clientID: string, receivedMutationID: number, lastMutationID: number | bigint);
111
121
  }
112
122
  /** @deprecated Use getMutator instead */
@@ -1 +1 @@
1
- {"version":3,"file":"process-mutations.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/process-mutations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process-mutations.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/process-mutations.ts"],"names":[],"mappings":"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"}
@@ -95,13 +95,15 @@ async function handleMutateRequest(inputOrDbProvider, maybeHandler, requestOrQue
95
95
  let processedCount = 0;
96
96
  try {
97
97
  const transactor = new Transactor(normalized.dbProvider, pushBody, parsedQueryParams, lc);
98
+ for (const m of pushBody.mutations) if (m.type === "custom" && m.name === "_zero_cleanupResults") assertCleanupClientGroup(m, pushBody.clientGroupID);
98
99
  for (const m of pushBody.mutations) {
99
100
  if (m.type === "custom" && m.name === "_zero_cleanupResults") {
100
101
  lc.debug?.(`Processing internal mutation '${m.name}' (clientID=${m.clientID})`);
101
102
  try {
102
- await processCleanupResultsMutation(normalized.dbProvider, m, parsedQueryParams, lc);
103
+ await processCleanupResultsMutation(normalized.dbProvider, m, pushBody.clientGroupID, parsedQueryParams, lc);
103
104
  processedCount++;
104
105
  } catch (error) {
106
+ if (error instanceof CleanupClientGroupMismatch) throw error;
105
107
  lc.warn?.(`Failed to process cleanup mutation for client ${m.clientID}`, error);
106
108
  processedCount++;
107
109
  }
@@ -247,11 +249,11 @@ var Transactor = class {
247
249
  return ret;
248
250
  } catch (error) {
249
251
  if (error instanceof OutOfOrderMutation) {
250
- this.#lc.error?.(error);
252
+ this.#lc.error?.(`Expected mutation ID ${error.lastMutationID}`, error);
251
253
  throw error;
252
254
  }
253
255
  if (error instanceof MutationAlreadyProcessedError) {
254
- this.#lc.warn?.(error);
256
+ this.#lc.warn?.(`Expected mutation ID ${error.lastMutationID}`, error);
255
257
  return {
256
258
  id: {
257
259
  clientID: mutation.clientID,
@@ -332,10 +334,35 @@ var Transactor = class {
332
334
  }
333
335
  };
334
336
  var OutOfOrderMutation = class extends Error {
337
+ /**
338
+ * The mutation ID the client should have sent. Kept out of the message,
339
+ * which is returned to the client; the server logs it separately.
340
+ */
341
+ lastMutationID;
335
342
  constructor(clientID, receivedMutationID, lastMutationID) {
336
- super(`Client ${clientID} sent mutation ID ${receivedMutationID} but expected ${lastMutationID}`);
343
+ super(`Client ${clientID} sent mutation ID ${receivedMutationID} out of order`);
344
+ this.lastMutationID = lastMutationID;
345
+ }
346
+ };
347
+ /**
348
+ * A cleanup mutation named a client group other than the one the push is
349
+ * for. A push may only clean up results of its own client group, so this
350
+ * fails the push instead of being ignored like other cleanup errors.
351
+ */
352
+ var CleanupClientGroupMismatch = class extends Error {
353
+ constructor() {
354
+ super("Cleanup mutation does not target the client group of this push");
337
355
  }
338
356
  };
357
+ /**
358
+ * Throws {@link CleanupClientGroupMismatch} when a cleanup mutation names a
359
+ * client group other than `clientGroupID`, the client group of the push.
360
+ * Arguments that do not parse are left for the processing step to report.
361
+ */
362
+ function assertCleanupClientGroup(mutation, clientGroupID) {
363
+ const parseResult = test(mutation.args[0], cleanupResultsArgSchema);
364
+ if (parseResult.ok && parseResult.value.clientGroupID !== clientGroupID) throw new CleanupClientGroupMismatch();
365
+ }
339
366
  function makeAppErrorResponse(m, error) {
340
367
  return {
341
368
  id: {
@@ -372,20 +399,26 @@ function getObjectAtPath(obj, path) {
372
399
  * Processes internal cleanup mutation that deletes acknowledged mutation results
373
400
  * from the upstream database. This runs without LMID tracking since it's an
374
401
  * internal operation.
402
+ *
403
+ * `clientGroupID` is the client group of the push. The cleanup must name the
404
+ * same client group; otherwise it throws {@link CleanupClientGroupMismatch}
405
+ * without touching the database. The push is checked for this before any
406
+ * mutation runs; the check here only guards this function's own callers.
375
407
  */
376
- async function processCleanupResultsMutation(dbProvider, mutation, queryParams, lc) {
408
+ async function processCleanupResultsMutation(dbProvider, mutation, clientGroupID, queryParams, lc) {
377
409
  const parseResult = test(mutation.args[0], cleanupResultsArgSchema);
378
410
  if (!parseResult.ok) {
379
411
  lc.warn?.("Cleanup mutation has invalid args", parseResult.error);
380
412
  return;
381
413
  }
382
414
  const args = parseResult.value;
415
+ if (args.clientGroupID !== clientGroupID) throw new CleanupClientGroupMismatch();
383
416
  const clientID = "type" in args && args.type === "bulk" ? args.clientIDs[0] : args.clientID;
384
417
  await dbProvider.transaction(async (_, hooks) => {
385
418
  await hooks.deleteMutationResults(args);
386
419
  }, {
387
420
  upstreamSchema: queryParams.schema,
388
- clientGroupID: args.clientGroupID,
421
+ clientGroupID,
389
422
  clientID,
390
423
  mutationID: 0
391
424
  });
@@ -1 +1 @@
1
- {"version":3,"file":"process-mutations.js","names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","v.test"],"sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import {\n consoleLogSink,\n type LogContext,\n type LogLevel,\n type LogSink,\n} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {getErrorDetails, getErrorMessage} from '../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {promiseVoid} from '../../shared/src/resolved-promises.ts';\nimport type {MaybePromise} from '../../shared/src/types.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {MutationAlreadyProcessedError} from '../../zero-cache/src/services/mutagen/error.ts';\nimport type {ApplicationError} from '../../zero-protocol/src/application-error.ts';\nimport {\n isApplicationError,\n wrapWithApplicationError,\n} from '../../zero-protocol/src/application-error.ts';\nimport {ErrorKind} from '../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../zero-protocol/src/error-reason.ts';\nimport type {PushFailedBody} from '../../zero-protocol/src/error.ts';\nimport {\n mutateParamsSchema,\n type MutateResponse,\n} from '../../zero-protocol/src/mutate-server.ts';\nimport type {MutationID} from '../../zero-protocol/src/mutation-id.ts';\nimport {\n CLEANUP_RESULTS_MUTATION_NAME,\n cleanupResultsArgSchema,\n type CleanupResultsArg,\n type CustomMutation,\n type Mutation,\n} from '../../zero-protocol/src/mutation.ts';\nimport {\n pushBodySchema,\n type MutationResponse,\n type PushBody,\n} from '../../zero-protocol/src/push.ts';\nimport type {RetryPredicate} from '../../zql/src/mutate/custom.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {createLogContext} from './logging.ts';\nimport {separatorRe} from './push-processor.ts';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n deleteMutationResults: (args: CleanupResultsArg) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\n /**\n * Receives each predicate the mutator registers with `tx.retryOn()`. A\n * `Database` passes it on to the server transaction it creates.\n */\n addRetryPredicate?: ((shouldRetry: RetryPredicate) => void) | undefined;\n}\n\n/**\n * Defines the abstract interface for a database that PushProcessor can execute\n * transactions against.\n */\nexport interface Database<T> {\n transaction: <R>(\n callback: (\n tx: T,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ) => Promise<R>;\n}\n\nexport type ExtractTransactionType<D> = D extends Database<infer T> ? T : never;\nexport type Params = v.Infer<typeof mutateParamsSchema>;\n\nexport type TransactFn<D extends Database<ExtractTransactionType<D>>> = (\n cb: TransactFnCallback<D>,\n) => Promise<MutationResponse>;\n\nexport type TransactFnCallback<D extends Database<ExtractTransactionType<D>>> =\n (\n tx: ExtractTransactionType<D>,\n mutatorName: string,\n mutatorArgs: ReadonlyJSONValue | undefined,\n ) => Promise<ReadonlyJSONValue | void>;\n\nexport type Parsed<D extends Database<ExtractTransactionType<D>>> = {\n transact: TransactFn<D>;\n mutations: CustomMutation[];\n};\n\ntype MutationPhase = 'preTransaction' | 'transactionPending' | 'postCommit';\n\nconst applicationErrorWrapper = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (\n error instanceof DatabaseTransactionError ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError ||\n isApplicationError(error)\n ) {\n throw error;\n }\n\n throw wrapWithApplicationError(error);\n }\n};\n\n/**\n * @deprecated Use {@link handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\n/**\n * Parsed query params accepted by {@link handleMutateRequest} when the\n * incoming request URL has already been handled by your framework.\n */\nexport type MutateSearchParams = URLSearchParams | Record<string, string>;\n\n/**\n * Runs once per custom mutation in a `/mutate` request.\n *\n * Call `transact` to execute database work for the mutation. Throwing before\n * `transact` persists an application error; throwing after `transact` resolves\n * only affects server-side logging because the mutation is already committed.\n */\nexport type MutateRequestHandler<\n D extends Database<ExtractTransactionType<D>>,\n> = (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n) => Promise<MutationResponse>;\n\nexport type HandleMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n> = {\n /** Database used to run transactions and store mutation results. */\n dbProvider: D;\n handler: MutateRequestHandler<D>;\n /**\n * Authenticated user ID. Null or undefined means the user is logged out.\n */\n userID: string | null | undefined;\n /** Optional log level for request parsing and execution. */\n logLevel?: LogLevel | undefined;\n /**\n * Destination for this request's log output. When omitted, logs are written\n * with `console.log`/`info`/`warn`/`error` etc.\n *\n * Provide a custom {@link LogSink} to redirect logs — for example into an\n * application's own structured logging pipeline, so that records emitted while\n * processing a push carry the same fields as the rest of the server's logs.\n */\n logSink?: LogSink | undefined;\n} & (\n | {\n /** Fetch request containing both query params and the JSON body. */\n request: Request;\n }\n | {\n /** Parsed query params from the `/mutate` request URL. */\n query: MutateSearchParams;\n /** Parsed JSON body from the `/mutate` request. */\n body: ReadonlyJSONValue;\n }\n);\n\ntype NormalizedMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n> = {\n readonly dbProvider: D;\n readonly handler: MutateRequestHandler<D>;\n // Note: semantics of undefined differ from HandleMutateRequestArgs.userID.\n // Here, undefined means the app didn't provide a user ID - we do not know if\n // the user is logged in or not. This is legacy behavior needed to support\n // deprecated signatures of handleMutateRequest which did not receive userID\n // from app.\n readonly userID: string | null | undefined;\n readonly logLevel: LogLevel;\n readonly logSink: LogSink;\n} & (\n | {\n readonly type: 'request';\n readonly request: Request;\n }\n | {\n readonly type: 'body';\n readonly queryParams: Record<string, string>;\n readonly jsonBody: ReadonlyJSONValue;\n }\n);\n\n/**\n * Process a `/mutate` request from a Fetch `Request`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(input: HandleMutateRequestArgs<D>): Promise<MutateResponse>;\n\n/**\n * @deprecated Pass a single object instead:\n * `handleMutateRequest({dbProvider, handler, query, body, userID, logLevel})`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D>,\n query: MutateSearchParams,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n logSink?: LogSink,\n): Promise<MutateResponse>;\n\n/**\n * @deprecated Pass a single object instead:\n * `handleMutateRequest({dbProvider, handler, request, userID, logLevel})`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D>,\n request: Request,\n logLevel?: LogLevel,\n logSink?: LogSink,\n): Promise<MutateResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n inputOrDbProvider: HandleMutateRequestArgs<D> | D,\n maybeHandler?: MutateRequestHandler<D> | undefined,\n requestOrQuery?: Request | MutateSearchParams | undefined,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel | undefined,\n logLevelOrLogSink?: LogLevel | LogSink | undefined,\n maybeLogSink?: LogSink | undefined,\n): Promise<MutateResponse> {\n const normalized =\n typeof inputOrDbProvider === 'object' && 'handler' in inputOrDbProvider\n ? normalizeMutateRequestInput(inputOrDbProvider)\n : normalizeLegacyMutateRequestArgs(\n inputOrDbProvider,\n maybeHandler,\n requestOrQuery,\n bodyOrLogLevel,\n logLevelOrLogSink,\n maybeLogSink,\n );\n\n const lc = createLogContext(\n normalized.logLevel,\n normalized.logSink,\n ).withContext('PushProcessor');\n let jsonBody: unknown;\n\n if (normalized.type === 'request') {\n try {\n jsonBody = await normalized.request.json();\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs: [],\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n } else {\n jsonBody = normalized.jsonBody;\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema, 'passthrough');\n mutationIDs = pushBody.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n let parsedQueryParams: Params;\n try {\n parsedQueryParams = v.parse(\n normalized.type === 'request'\n ? Object.fromEntries(new URL(normalized.request.url).searchParams)\n : normalized.queryParams,\n mutateParamsSchema,\n 'passthrough',\n );\n } catch (error) {\n lc.error?.('Failed to parse push query parameters', error);\n const message = `Failed to parse push query parameters: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n if (pushBody.pushVersion !== 1) {\n const response = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version: ${pushBody.pushVersion}`,\n } as const satisfies PushFailedBody;\n return response;\n }\n\n const responses: MutationResponse[] = [];\n let processedCount = 0;\n\n try {\n const transactor = new Transactor(\n normalized.dbProvider,\n pushBody,\n parsedQueryParams,\n lc,\n );\n\n // Each mutation goes through three phases:\n // 1. Pre-transaction: user logic that runs before `transact` is called. If\n // this throws we still advance LMID and persist the failure result.\n // 2. Transaction: the callback passed to `transact`, which can be retried\n // if it fails with an ApplicationError.\n // 3. Post-commit: any logic that runs after `transact` resolves. Failures\n // here are logged but the mutation remains committed.\n for (const m of pushBody.mutations) {\n // Handle internal mutations (like cleanup) directly without user dispatch\n if (m.type === 'custom' && m.name === CLEANUP_RESULTS_MUTATION_NAME) {\n lc.debug?.(\n `Processing internal mutation '${m.name}' (clientID=${m.clientID})`,\n );\n try {\n await processCleanupResultsMutation(\n normalized.dbProvider,\n m,\n parsedQueryParams,\n lc,\n );\n // No response added - this is fire-and-forget\n processedCount++;\n } catch (error) {\n lc.warn?.(\n `Failed to process cleanup mutation for client ${m.clientID}`,\n error,\n );\n // Don't fail the whole push for cleanup errors\n processedCount++;\n }\n continue;\n }\n\n assert(m.type === 'custom', 'Expected custom mutation');\n lc.debug?.(\n `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,\n );\n\n let mutationPhase: MutationPhase = 'preTransaction';\n\n const transactProxy: TransactFn<D> = async innerCb => {\n mutationPhase = 'transactionPending';\n const result = await transactor.transact(m, innerCb);\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() =>\n normalized.handler(transactProxy, m),\n );\n responses.push(res);\n lc.debug?.(`Mutation '${m.name}' (id=${m.id}) completed successfully`);\n\n processedCount++;\n } catch (error) {\n if (!isApplicationError(error)) {\n throw error;\n }\n\n if (mutationPhase === 'preTransaction') {\n // Pre-transaction\n await transactor.persistPreTransactionFailure(m, error);\n } else if (mutationPhase === 'postCommit') {\n // Post-commit\n lc.error?.(\n `Post-commit mutation handler failed for mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n }\n\n lc.warn?.(\n `Application error processing mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n responses.push(makeAppErrorResponse(m, error));\n\n processedCount++;\n }\n }\n\n return {\n kind: 'MutateResponse',\n mutations: responses,\n ...(typeof normalized.userID !== 'undefined'\n ? {userID: normalized.userID}\n : {}),\n } as const satisfies MutateResponse;\n } catch (error) {\n lc.error?.('Failed to process push request', error);\n // only include mutationIDs for mutations that were not processed\n const unprocessedMutationIDs = mutationIDs.slice(processedCount);\n\n const message = getErrorMessage(error);\n const details = getErrorDetails(error);\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason:\n error instanceof OutOfOrderMutation\n ? ErrorReason.OutOfOrderMutation\n : error instanceof DatabaseTransactionError\n ? ErrorReason.Database\n : ErrorReason.Internal,\n message,\n mutationIDs: unprocessedMutationIDs,\n ...(details ? {details} : {}),\n };\n }\n}\n\nfunction normalizeMutateRequestInput<\n D extends Database<ExtractTransactionType<D>>,\n>(input: HandleMutateRequestArgs<D>): NormalizedMutateRequestArgs<D> {\n if ('request' in input) {\n return {\n type: 'request',\n dbProvider: input.dbProvider,\n handler: input.handler,\n request: input.request,\n userID: input.userID ?? null,\n logLevel: input.logLevel ?? 'info',\n logSink: input.logSink ?? consoleLogSink,\n };\n }\n\n return {\n type: 'body',\n dbProvider: input.dbProvider,\n handler: input.handler,\n jsonBody: input.body,\n userID: input.userID ?? null,\n queryParams:\n input.query instanceof URLSearchParams\n ? Object.fromEntries(input.query)\n : input.query,\n logLevel: input.logLevel ?? 'info',\n logSink: input.logSink ?? consoleLogSink,\n };\n}\n\nfunction normalizeLegacyMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D> | undefined,\n requestOrQuery: Request | MutateSearchParams | undefined,\n bodyOrLogLevel: ReadonlyJSONValue | LogLevel | undefined,\n logLevelOrLogSink: LogLevel | LogSink | undefined,\n maybeLogSink: LogSink | undefined,\n): NormalizedMutateRequestArgs<D> {\n assert(typeof handler === 'function', 'Handler function is required');\n assert(\n typeof requestOrQuery !== 'undefined',\n 'Request or query parameters are required',\n );\n\n if (requestOrQuery instanceof Request) {\n return {\n type: 'request',\n dbProvider,\n handler,\n request: requestOrQuery,\n userID: undefined,\n logLevel: (bodyOrLogLevel as LogLevel | undefined) ?? 'info',\n // The `request` overload has no `body` slot, so the sink arrives one\n // position earlier than it does in the `query`/`body` overload.\n logSink: (logLevelOrLogSink as LogSink | undefined) ?? consoleLogSink,\n };\n }\n\n assert(\n typeof bodyOrLogLevel !== 'undefined',\n 'JSON body cannot be undefined',\n );\n\n return {\n type: 'body',\n dbProvider,\n handler,\n jsonBody: bodyOrLogLevel,\n userID: undefined,\n queryParams:\n requestOrQuery instanceof URLSearchParams\n ? Object.fromEntries(requestOrQuery)\n : requestOrQuery,\n logLevel: (logLevelOrLogSink as LogLevel | undefined) ?? 'info',\n logSink: maybeLogSink ?? consoleLogSink,\n };\n}\n\n/**\n * The most times a mutator runs for one mutation within one push when its\n * `tx.retryOn()` predicate keeps answering yes: the first run and four\n * re-runs.\n */\nexport const MAX_MUTATOR_RUNS = 5;\n\nclass Transactor<D extends Database<ExtractTransactionType<D>>> {\n readonly #dbProvider: D;\n readonly #req: PushBody;\n readonly #params: Params;\n readonly #lc: LogContext;\n\n constructor(dbProvider: D, req: PushBody, params: Params, lc: LogContext) {\n this.#dbProvider = dbProvider;\n this.#req = req;\n this.#params = params;\n this.#lc = lc;\n }\n\n /**\n * Asks all of the run's `tx.retryOn()` predicates at once whether to run\n * the mutator again. The first to answer yes decides it and the other\n * answers are ignored; it is no once every predicate has answered no. A\n * predicate that throws or rejects answers no: escaping here would skip\n * recording the mutation's result, and the client would send it again.\n */\n #shouldRetry(\n predicates: readonly RetryPredicate[],\n error: unknown,\n attempt: number,\n ): Promise<boolean> {\n if (predicates.length === 0) {\n return Promise.resolve(false);\n }\n const ask = async (shouldRetry: RetryPredicate): Promise<boolean> => {\n try {\n return (await shouldRetry(error, attempt)) === true;\n } catch (retryError) {\n this.#lc.warn?.(\n 'retryOn predicate threw; treating it as no',\n retryError,\n );\n return false;\n }\n };\n return new Promise(resolve => {\n let pending = predicates.length;\n for (const shouldRetry of predicates) {\n void ask(shouldRetry).then(yes => {\n if (yes) {\n resolve(true);\n } else if (--pending === 0) {\n resolve(false);\n }\n });\n }\n });\n }\n\n transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n // Which run of the mutator this is: 1, then 2 for the first re-run, and so\n // on. When a run fails, it is also the number of the re-run being decided.\n let attempt = 1;\n for (;;) {\n // What this run registers with `tx.retryOn()`. Each run starts empty.\n const predicates: RetryPredicate[] = [];\n try {\n const ret = await this.#transactImpl(\n mutation,\n cb,\n appError,\n shouldRetry => {\n predicates.push(shouldRetry);\n },\n );\n if (appError !== undefined) {\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Mutation ${mutation.id} for client ${mutation.clientID} was retried after an error`,\n appError,\n );\n return makeAppErrorResponse(mutation, appError);\n }\n\n return ret;\n } catch (error) {\n if (error instanceof OutOfOrderMutation) {\n this.#lc.error?.(error);\n throw error;\n }\n\n if (error instanceof MutationAlreadyProcessedError) {\n this.#lc.warn?.(error);\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {\n error: 'alreadyProcessed',\n details: error.message,\n },\n };\n }\n\n if (appError !== undefined) {\n // Retry also failed → internal error, cannot skip mutation\n this.#lc.error?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Retry also failed for mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n throw error;\n }\n\n // What the mutator or the database threw, without the wrapper. This\n // includes errors raised at COMMIT, which the mutator cannot catch.\n const originalError =\n error instanceof DatabaseTransactionError\n ? (error.cause ?? error)\n : error;\n\n // One of the run's `tx.retryOn()` predicates says to run it again → do\n // so, in a fresh transaction.\n //\n // `continue` WITHOUT setting `appError` is the whole mechanism: it is\n // `appError` being set that makes the next `#transactImpl` skip\n // `cb(...)`. `#transactImpl` opens a new transaction each pass, so the\n // re-run gets a new snapshot. `#checkAndIncrementLastMutationID` re-runs\n // safely because the failed run rolled its increment back.\n if (\n attempt < MAX_MUTATOR_RUNS &&\n (await this.#shouldRetry(predicates, originalError, attempt))\n ) {\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Mutation ${mutation.id} for client ${mutation.clientID} failed, re-running mutator (retry ${attempt})`,\n originalError,\n );\n attempt++;\n continue;\n }\n\n // Not re-run → store error and retry without mutator\n appError = wrapWithApplicationError(originalError);\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Error processing mutation ${mutation.id} for client ${mutation.clientID}, retrying without mutator`,\n appError,\n );\n continue;\n }\n }\n };\n\n async persistPreTransactionFailure(\n mutation: CustomMutation,\n appError: ApplicationError<ReadonlyJSONValue | undefined>,\n ): Promise<MutationResponse> {\n // User-land code threw before calling `transact`. We still need to bump the\n // LMID for this mutation and persist the error so that the client knows it failed.\n const ret = await this.#transactImpl(\n mutation,\n // noop callback since there's no transaction to execute\n () => promiseVoid,\n appError,\n undefined,\n );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | undefined,\n addRetryPredicate: ((shouldRetry: RetryPredicate) => void) | undefined,\n ): Promise<MutationResponse> {\n let transactionPhase: DatabaseTransactionPhase = 'open';\n\n try {\n const ret = await this.#dbProvider.transaction(\n async (dbTx, transactionHooks) => {\n // update the transaction phase to 'execute' after the transaction is opened\n transactionPhase = 'execute';\n\n await this.#checkAndIncrementLastMutationID(\n transactionHooks,\n mutation.clientID,\n mutation.id,\n );\n\n if (appError === undefined) {\n this.#lc.debug?.(\n // log-leak-ignore -- mutator name and mutation id, not row data\n `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n const data = (await cb(dbTx, mutation.name, mutation.args[0])) as\n | ReadonlyJSONValue\n | undefined;\n const id = {clientID: mutation.clientID, id: mutation.id};\n if (data === undefined) {\n return {id, result: {}};\n }\n // Persisted so the data still reaches the client if the push\n // response is lost. A mutator that returns nothing writes no row.\n const successResult: MutationResponse = {id, result: {data}};\n await transactionHooks.writeMutationResult(successResult);\n return successResult;\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n return mutationResult;\n }\n },\n this.#getTransactionInput(mutation, addRetryPredicate),\n );\n\n return ret;\n } catch (error) {\n if (\n isApplicationError(error) ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError\n ) {\n throw error;\n }\n\n throw new DatabaseTransactionError(transactionPhase, {cause: error});\n }\n }\n\n #getTransactionInput(\n mutation: CustomMutation,\n addRetryPredicate: ((shouldRetry: RetryPredicate) => void) | undefined,\n ): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\n addRetryPredicate,\n };\n }\n\n async #checkAndIncrementLastMutationID(\n transactionHooks: TransactionProviderHooks,\n clientID: string,\n receivedMutationID: number,\n ) {\n const {lastMutationID} = await transactionHooks.updateClientMutationID();\n\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new OutOfOrderMutation(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n }\n }\n}\n\nexport class OutOfOrderMutation extends Error {\n constructor(\n clientID: string,\n receivedMutationID: number,\n lastMutationID: number | bigint,\n ) {\n super(\n `Client ${clientID} sent mutation ID ${receivedMutationID} but expected ${lastMutationID}`,\n );\n }\n}\n\nfunction makeAppErrorResponse(\n m: Mutation,\n error: ApplicationError<ReadonlyJSONValue | undefined>,\n): MutationResponse {\n return {\n id: {\n clientID: m.clientID,\n id: m.id,\n },\n result: {\n error: 'app',\n message: error.message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\n/** @deprecated Use getMutator instead */\nexport function getMutation(\n // oxlint-disable-next-line no-explicit-any\n mutators: AnyMutatorRegistry | CustomMutatorDefs<any>,\n name: string,\n // oxlint-disable-next-line no-explicit-any\n): CustomMutatorImpl<any> {\n const path = name.split(separatorRe);\n const mutator = getObjectAtPath(mutators, path);\n assert(typeof mutator === 'function', `could not find mutator ${name}`);\n\n if (isMutator(mutator)) {\n // mutator needs to be called with {tx, args, ctx}\n // CustomMutatorImpl is called with (tx, args, ctx)\n return (tx, args, ctx) => mutator.fn({args, ctx, tx});\n }\n\n // oxlint-disable-next-line no-explicit-any\n return mutator as CustomMutatorImpl<any>;\n}\n\nfunction getObjectAtPath(\n obj: Record<string, unknown>,\n path: string[],\n): unknown {\n let current: unknown = obj;\n for (const part of path) {\n if (typeof current !== 'object' || current === null || !(part in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\n/**\n * Processes internal cleanup mutation that deletes acknowledged mutation results\n * from the upstream database. This runs without LMID tracking since it's an\n * internal operation.\n */\nasync function processCleanupResultsMutation<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n mutation: CustomMutation,\n queryParams: Params,\n lc: LogContext,\n): Promise<void> {\n const parseResult = v.test(mutation.args[0], cleanupResultsArgSchema);\n if (!parseResult.ok) {\n // log-leak-ignore -- valita reports the failing type, not the value\n lc.warn?.('Cleanup mutation has invalid args', parseResult.error);\n return;\n }\n const args: CleanupResultsArg = parseResult.value;\n\n // Determine clientID for transaction input based on cleanup type\n // Note: legacy format without type field is treated as single\n const clientID =\n 'type' in args && args.type === 'bulk' ? args.clientIDs[0] : args.clientID;\n\n // Run in a transaction, using the hook for DB-specific operation.\n // Note: only upstreamSchema is used by deleteMutationResults; the other\n // fields are required by the interface but ignored for this operation.\n await dbProvider.transaction(\n async (_, hooks) => {\n await hooks.deleteMutationResults(args);\n },\n {\n upstreamSchema: queryParams.schema,\n clientGroupID: args.clientGroupID,\n clientID,\n mutationID: 0,\n },\n );\n}\n\ntype DatabaseTransactionPhase = 'open' | 'execute';\nclass DatabaseTransactionError extends Error {\n constructor(phase: DatabaseTransactionPhase, options?: ErrorOptions) {\n super(\n phase === 'open'\n ? `Failed to open database transaction: ${getErrorMessage(options?.cause)}`\n : `Database transaction failed after opening: ${getErrorMessage(options?.cause)}`,\n options,\n );\n this.name = 'DatabaseTransactionError';\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"process-mutations.js","names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","v.test"],"sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import {\n consoleLogSink,\n type LogContext,\n type LogLevel,\n type LogSink,\n} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {getErrorDetails, getErrorMessage} from '../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {promiseVoid} from '../../shared/src/resolved-promises.ts';\nimport type {MaybePromise} from '../../shared/src/types.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {MutationAlreadyProcessedError} from '../../zero-cache/src/services/mutagen/error.ts';\nimport type {ApplicationError} from '../../zero-protocol/src/application-error.ts';\nimport {\n isApplicationError,\n wrapWithApplicationError,\n} from '../../zero-protocol/src/application-error.ts';\nimport {ErrorKind} from '../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../zero-protocol/src/error-reason.ts';\nimport type {PushFailedBody} from '../../zero-protocol/src/error.ts';\nimport {\n mutateParamsSchema,\n type MutateResponse,\n} from '../../zero-protocol/src/mutate-server.ts';\nimport type {MutationID} from '../../zero-protocol/src/mutation-id.ts';\nimport {\n CLEANUP_RESULTS_MUTATION_NAME,\n cleanupResultsArgSchema,\n type CleanupResultsArg,\n type CustomMutation,\n type Mutation,\n} from '../../zero-protocol/src/mutation.ts';\nimport {\n pushBodySchema,\n type MutationResponse,\n type PushBody,\n} from '../../zero-protocol/src/push.ts';\nimport type {RetryPredicate} from '../../zql/src/mutate/custom.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {createLogContext} from './logging.ts';\nimport {separatorRe} from './push-processor.ts';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n /**\n * `args.clientGroupID` is always the client group of the push being\n * processed; a cleanup that names any other client group fails the push\n * before this is called.\n */\n deleteMutationResults: (args: CleanupResultsArg) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\n /**\n * Receives each predicate the mutator registers with `tx.retryOn()`. A\n * `Database` passes it on to the server transaction it creates.\n */\n addRetryPredicate?: ((shouldRetry: RetryPredicate) => void) | undefined;\n}\n\n/**\n * Defines the abstract interface for a database that PushProcessor can execute\n * transactions against.\n */\nexport interface Database<T> {\n transaction: <R>(\n callback: (\n tx: T,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ) => Promise<R>;\n}\n\nexport type ExtractTransactionType<D> = D extends Database<infer T> ? T : never;\nexport type Params = v.Infer<typeof mutateParamsSchema>;\n\nexport type TransactFn<D extends Database<ExtractTransactionType<D>>> = (\n cb: TransactFnCallback<D>,\n) => Promise<MutationResponse>;\n\nexport type TransactFnCallback<D extends Database<ExtractTransactionType<D>>> =\n (\n tx: ExtractTransactionType<D>,\n mutatorName: string,\n mutatorArgs: ReadonlyJSONValue | undefined,\n ) => Promise<ReadonlyJSONValue | void>;\n\nexport type Parsed<D extends Database<ExtractTransactionType<D>>> = {\n transact: TransactFn<D>;\n mutations: CustomMutation[];\n};\n\ntype MutationPhase = 'preTransaction' | 'transactionPending' | 'postCommit';\n\nconst applicationErrorWrapper = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (\n error instanceof DatabaseTransactionError ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError ||\n isApplicationError(error)\n ) {\n throw error;\n }\n\n throw wrapWithApplicationError(error);\n }\n};\n\n/**\n * @deprecated Use {@link handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\n/**\n * Parsed query params accepted by {@link handleMutateRequest} when the\n * incoming request URL has already been handled by your framework.\n */\nexport type MutateSearchParams = URLSearchParams | Record<string, string>;\n\n/**\n * Runs once per custom mutation in a `/mutate` request.\n *\n * Call `transact` to execute database work for the mutation. Throwing before\n * `transact` persists an application error; throwing after `transact` resolves\n * only affects server-side logging because the mutation is already committed.\n */\nexport type MutateRequestHandler<\n D extends Database<ExtractTransactionType<D>>,\n> = (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n) => Promise<MutationResponse>;\n\nexport type HandleMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n> = {\n /** Database used to run transactions and store mutation results. */\n dbProvider: D;\n handler: MutateRequestHandler<D>;\n /**\n * Authenticated user ID. Null or undefined means the user is logged out.\n */\n userID: string | null | undefined;\n /** Optional log level for request parsing and execution. */\n logLevel?: LogLevel | undefined;\n /**\n * Destination for this request's log output. When omitted, logs are written\n * with `console.log`/`info`/`warn`/`error` etc.\n *\n * Provide a custom {@link LogSink} to redirect logs — for example into an\n * application's own structured logging pipeline, so that records emitted while\n * processing a push carry the same fields as the rest of the server's logs.\n */\n logSink?: LogSink | undefined;\n} & (\n | {\n /** Fetch request containing both query params and the JSON body. */\n request: Request;\n }\n | {\n /** Parsed query params from the `/mutate` request URL. */\n query: MutateSearchParams;\n /** Parsed JSON body from the `/mutate` request. */\n body: ReadonlyJSONValue;\n }\n);\n\ntype NormalizedMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n> = {\n readonly dbProvider: D;\n readonly handler: MutateRequestHandler<D>;\n // Note: semantics of undefined differ from HandleMutateRequestArgs.userID.\n // Here, undefined means the app didn't provide a user ID - we do not know if\n // the user is logged in or not. This is legacy behavior needed to support\n // deprecated signatures of handleMutateRequest which did not receive userID\n // from app.\n readonly userID: string | null | undefined;\n readonly logLevel: LogLevel;\n readonly logSink: LogSink;\n} & (\n | {\n readonly type: 'request';\n readonly request: Request;\n }\n | {\n readonly type: 'body';\n readonly queryParams: Record<string, string>;\n readonly jsonBody: ReadonlyJSONValue;\n }\n);\n\n/**\n * Process a `/mutate` request from a Fetch `Request`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(input: HandleMutateRequestArgs<D>): Promise<MutateResponse>;\n\n/**\n * @deprecated Pass a single object instead:\n * `handleMutateRequest({dbProvider, handler, query, body, userID, logLevel})`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D>,\n query: MutateSearchParams,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n logSink?: LogSink,\n): Promise<MutateResponse>;\n\n/**\n * @deprecated Pass a single object instead:\n * `handleMutateRequest({dbProvider, handler, request, userID, logLevel})`.\n */\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D>,\n request: Request,\n logLevel?: LogLevel,\n logSink?: LogSink,\n): Promise<MutateResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n inputOrDbProvider: HandleMutateRequestArgs<D> | D,\n maybeHandler?: MutateRequestHandler<D> | undefined,\n requestOrQuery?: Request | MutateSearchParams | undefined,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel | undefined,\n logLevelOrLogSink?: LogLevel | LogSink | undefined,\n maybeLogSink?: LogSink | undefined,\n): Promise<MutateResponse> {\n const normalized =\n typeof inputOrDbProvider === 'object' && 'handler' in inputOrDbProvider\n ? normalizeMutateRequestInput(inputOrDbProvider)\n : normalizeLegacyMutateRequestArgs(\n inputOrDbProvider,\n maybeHandler,\n requestOrQuery,\n bodyOrLogLevel,\n logLevelOrLogSink,\n maybeLogSink,\n );\n\n const lc = createLogContext(\n normalized.logLevel,\n normalized.logSink,\n ).withContext('PushProcessor');\n let jsonBody: unknown;\n\n if (normalized.type === 'request') {\n try {\n jsonBody = await normalized.request.json();\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs: [],\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n } else {\n jsonBody = normalized.jsonBody;\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema, 'passthrough');\n mutationIDs = pushBody.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n let parsedQueryParams: Params;\n try {\n parsedQueryParams = v.parse(\n normalized.type === 'request'\n ? Object.fromEntries(new URL(normalized.request.url).searchParams)\n : normalized.queryParams,\n mutateParamsSchema,\n 'passthrough',\n );\n } catch (error) {\n lc.error?.('Failed to parse push query parameters', error);\n const message = `Failed to parse push query parameters: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n if (pushBody.pushVersion !== 1) {\n const response = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version: ${pushBody.pushVersion}`,\n } as const satisfies PushFailedBody;\n return response;\n }\n\n const responses: MutationResponse[] = [];\n let processedCount = 0;\n\n try {\n const transactor = new Transactor(\n normalized.dbProvider,\n pushBody,\n parsedQueryParams,\n lc,\n );\n\n // A cleanup that names another client group fails the push before any\n // mutation in it runs, so the push changes nothing at all.\n for (const m of pushBody.mutations) {\n if (m.type === 'custom' && m.name === CLEANUP_RESULTS_MUTATION_NAME) {\n assertCleanupClientGroup(m, pushBody.clientGroupID);\n }\n }\n\n // Each mutation goes through three phases:\n // 1. Pre-transaction: user logic that runs before `transact` is called. If\n // this throws we still advance LMID and persist the failure result.\n // 2. Transaction: the callback passed to `transact`, which can be retried\n // if it fails with an ApplicationError.\n // 3. Post-commit: any logic that runs after `transact` resolves. Failures\n // here are logged but the mutation remains committed.\n for (const m of pushBody.mutations) {\n // Handle internal mutations (like cleanup) directly without user dispatch\n if (m.type === 'custom' && m.name === CLEANUP_RESULTS_MUTATION_NAME) {\n lc.debug?.(\n `Processing internal mutation '${m.name}' (clientID=${m.clientID})`,\n );\n try {\n await processCleanupResultsMutation(\n normalized.dbProvider,\n m,\n pushBody.clientGroupID,\n parsedQueryParams,\n lc,\n );\n // No response added - this is fire-and-forget\n processedCount++;\n } catch (error) {\n if (error instanceof CleanupClientGroupMismatch) {\n throw error;\n }\n lc.warn?.(\n `Failed to process cleanup mutation for client ${m.clientID}`,\n error,\n );\n // Don't fail the whole push for cleanup errors\n processedCount++;\n }\n continue;\n }\n\n assert(m.type === 'custom', 'Expected custom mutation');\n lc.debug?.(\n `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,\n );\n\n let mutationPhase: MutationPhase = 'preTransaction';\n\n const transactProxy: TransactFn<D> = async innerCb => {\n mutationPhase = 'transactionPending';\n const result = await transactor.transact(m, innerCb);\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() =>\n normalized.handler(transactProxy, m),\n );\n responses.push(res);\n lc.debug?.(`Mutation '${m.name}' (id=${m.id}) completed successfully`);\n\n processedCount++;\n } catch (error) {\n if (!isApplicationError(error)) {\n throw error;\n }\n\n if (mutationPhase === 'preTransaction') {\n // Pre-transaction\n await transactor.persistPreTransactionFailure(m, error);\n } else if (mutationPhase === 'postCommit') {\n // Post-commit\n lc.error?.(\n `Post-commit mutation handler failed for mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n }\n\n lc.warn?.(\n `Application error processing mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n responses.push(makeAppErrorResponse(m, error));\n\n processedCount++;\n }\n }\n\n return {\n kind: 'MutateResponse',\n mutations: responses,\n ...(typeof normalized.userID !== 'undefined'\n ? {userID: normalized.userID}\n : {}),\n } as const satisfies MutateResponse;\n } catch (error) {\n lc.error?.('Failed to process push request', error);\n // only include mutationIDs for mutations that were not processed\n const unprocessedMutationIDs = mutationIDs.slice(processedCount);\n\n const message = getErrorMessage(error);\n const details = getErrorDetails(error);\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason:\n error instanceof OutOfOrderMutation\n ? ErrorReason.OutOfOrderMutation\n : error instanceof DatabaseTransactionError\n ? ErrorReason.Database\n : ErrorReason.Internal,\n message,\n mutationIDs: unprocessedMutationIDs,\n ...(details ? {details} : {}),\n };\n }\n}\n\nfunction normalizeMutateRequestInput<\n D extends Database<ExtractTransactionType<D>>,\n>(input: HandleMutateRequestArgs<D>): NormalizedMutateRequestArgs<D> {\n if ('request' in input) {\n return {\n type: 'request',\n dbProvider: input.dbProvider,\n handler: input.handler,\n request: input.request,\n userID: input.userID ?? null,\n logLevel: input.logLevel ?? 'info',\n logSink: input.logSink ?? consoleLogSink,\n };\n }\n\n return {\n type: 'body',\n dbProvider: input.dbProvider,\n handler: input.handler,\n jsonBody: input.body,\n userID: input.userID ?? null,\n queryParams:\n input.query instanceof URLSearchParams\n ? Object.fromEntries(input.query)\n : input.query,\n logLevel: input.logLevel ?? 'info',\n logSink: input.logSink ?? consoleLogSink,\n };\n}\n\nfunction normalizeLegacyMutateRequestArgs<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n handler: MutateRequestHandler<D> | undefined,\n requestOrQuery: Request | MutateSearchParams | undefined,\n bodyOrLogLevel: ReadonlyJSONValue | LogLevel | undefined,\n logLevelOrLogSink: LogLevel | LogSink | undefined,\n maybeLogSink: LogSink | undefined,\n): NormalizedMutateRequestArgs<D> {\n assert(typeof handler === 'function', 'Handler function is required');\n assert(\n typeof requestOrQuery !== 'undefined',\n 'Request or query parameters are required',\n );\n\n if (requestOrQuery instanceof Request) {\n return {\n type: 'request',\n dbProvider,\n handler,\n request: requestOrQuery,\n userID: undefined,\n logLevel: (bodyOrLogLevel as LogLevel | undefined) ?? 'info',\n // The `request` overload has no `body` slot, so the sink arrives one\n // position earlier than it does in the `query`/`body` overload.\n logSink: (logLevelOrLogSink as LogSink | undefined) ?? consoleLogSink,\n };\n }\n\n assert(\n typeof bodyOrLogLevel !== 'undefined',\n 'JSON body cannot be undefined',\n );\n\n return {\n type: 'body',\n dbProvider,\n handler,\n jsonBody: bodyOrLogLevel,\n userID: undefined,\n queryParams:\n requestOrQuery instanceof URLSearchParams\n ? Object.fromEntries(requestOrQuery)\n : requestOrQuery,\n logLevel: (logLevelOrLogSink as LogLevel | undefined) ?? 'info',\n logSink: maybeLogSink ?? consoleLogSink,\n };\n}\n\n/**\n * The most times a mutator runs for one mutation within one push when its\n * `tx.retryOn()` predicate keeps answering yes: the first run and four\n * re-runs.\n */\nexport const MAX_MUTATOR_RUNS = 5;\n\nclass Transactor<D extends Database<ExtractTransactionType<D>>> {\n readonly #dbProvider: D;\n readonly #req: PushBody;\n readonly #params: Params;\n readonly #lc: LogContext;\n\n constructor(dbProvider: D, req: PushBody, params: Params, lc: LogContext) {\n this.#dbProvider = dbProvider;\n this.#req = req;\n this.#params = params;\n this.#lc = lc;\n }\n\n /**\n * Asks all of the run's `tx.retryOn()` predicates at once whether to run\n * the mutator again. The first to answer yes decides it and the other\n * answers are ignored; it is no once every predicate has answered no. A\n * predicate that throws or rejects answers no: escaping here would skip\n * recording the mutation's result, and the client would send it again.\n */\n #shouldRetry(\n predicates: readonly RetryPredicate[],\n error: unknown,\n attempt: number,\n ): Promise<boolean> {\n if (predicates.length === 0) {\n return Promise.resolve(false);\n }\n const ask = async (shouldRetry: RetryPredicate): Promise<boolean> => {\n try {\n return (await shouldRetry(error, attempt)) === true;\n } catch (retryError) {\n this.#lc.warn?.(\n 'retryOn predicate threw; treating it as no',\n retryError,\n );\n return false;\n }\n };\n return new Promise(resolve => {\n let pending = predicates.length;\n for (const shouldRetry of predicates) {\n void ask(shouldRetry).then(yes => {\n if (yes) {\n resolve(true);\n } else if (--pending === 0) {\n resolve(false);\n }\n });\n }\n });\n }\n\n transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n // Which run of the mutator this is: 1, then 2 for the first re-run, and so\n // on. When a run fails, it is also the number of the re-run being decided.\n let attempt = 1;\n for (;;) {\n // What this run registers with `tx.retryOn()`. Each run starts empty.\n const predicates: RetryPredicate[] = [];\n try {\n const ret = await this.#transactImpl(\n mutation,\n cb,\n appError,\n shouldRetry => {\n predicates.push(shouldRetry);\n },\n );\n if (appError !== undefined) {\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Mutation ${mutation.id} for client ${mutation.clientID} was retried after an error`,\n appError,\n );\n return makeAppErrorResponse(mutation, appError);\n }\n\n return ret;\n } catch (error) {\n if (error instanceof OutOfOrderMutation) {\n this.#lc.error?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Expected mutation ID ${error.lastMutationID}`,\n error,\n );\n throw error;\n }\n\n if (error instanceof MutationAlreadyProcessedError) {\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Expected mutation ID ${error.lastMutationID}`,\n error,\n );\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {\n error: 'alreadyProcessed',\n details: error.message,\n },\n };\n }\n\n if (appError !== undefined) {\n // Retry also failed → internal error, cannot skip mutation\n this.#lc.error?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Retry also failed for mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n throw error;\n }\n\n // What the mutator or the database threw, without the wrapper. This\n // includes errors raised at COMMIT, which the mutator cannot catch.\n const originalError =\n error instanceof DatabaseTransactionError\n ? (error.cause ?? error)\n : error;\n\n // One of the run's `tx.retryOn()` predicates says to run it again → do\n // so, in a fresh transaction.\n //\n // `continue` WITHOUT setting `appError` is the whole mechanism: it is\n // `appError` being set that makes the next `#transactImpl` skip\n // `cb(...)`. `#transactImpl` opens a new transaction each pass, so the\n // re-run gets a new snapshot. `#checkAndIncrementLastMutationID` re-runs\n // safely because the failed run rolled its increment back.\n if (\n attempt < MAX_MUTATOR_RUNS &&\n (await this.#shouldRetry(predicates, originalError, attempt))\n ) {\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Mutation ${mutation.id} for client ${mutation.clientID} failed, re-running mutator (retry ${attempt})`,\n originalError,\n );\n attempt++;\n continue;\n }\n\n // Not re-run → store error and retry without mutator\n appError = wrapWithApplicationError(originalError);\n this.#lc.warn?.(\n // log-leak-ignore -- mutation and client ids, not row data\n `Error processing mutation ${mutation.id} for client ${mutation.clientID}, retrying without mutator`,\n appError,\n );\n continue;\n }\n }\n };\n\n async persistPreTransactionFailure(\n mutation: CustomMutation,\n appError: ApplicationError<ReadonlyJSONValue | undefined>,\n ): Promise<MutationResponse> {\n // User-land code threw before calling `transact`. We still need to bump the\n // LMID for this mutation and persist the error so that the client knows it failed.\n const ret = await this.#transactImpl(\n mutation,\n // noop callback since there's no transaction to execute\n () => promiseVoid,\n appError,\n undefined,\n );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | undefined,\n addRetryPredicate: ((shouldRetry: RetryPredicate) => void) | undefined,\n ): Promise<MutationResponse> {\n let transactionPhase: DatabaseTransactionPhase = 'open';\n\n try {\n const ret = await this.#dbProvider.transaction(\n async (dbTx, transactionHooks) => {\n // update the transaction phase to 'execute' after the transaction is opened\n transactionPhase = 'execute';\n\n await this.#checkAndIncrementLastMutationID(\n transactionHooks,\n mutation.clientID,\n mutation.id,\n );\n\n if (appError === undefined) {\n this.#lc.debug?.(\n // log-leak-ignore -- mutator name and mutation id, not row data\n `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n const data = (await cb(dbTx, mutation.name, mutation.args[0])) as\n | ReadonlyJSONValue\n | undefined;\n const id = {clientID: mutation.clientID, id: mutation.id};\n if (data === undefined) {\n return {id, result: {}};\n }\n // Persisted so the data still reaches the client if the push\n // response is lost. A mutator that returns nothing writes no row.\n const successResult: MutationResponse = {id, result: {data}};\n await transactionHooks.writeMutationResult(successResult);\n return successResult;\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n return mutationResult;\n }\n },\n this.#getTransactionInput(mutation, addRetryPredicate),\n );\n\n return ret;\n } catch (error) {\n if (\n isApplicationError(error) ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError\n ) {\n throw error;\n }\n\n throw new DatabaseTransactionError(transactionPhase, {cause: error});\n }\n }\n\n #getTransactionInput(\n mutation: CustomMutation,\n addRetryPredicate: ((shouldRetry: RetryPredicate) => void) | undefined,\n ): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\n addRetryPredicate,\n };\n }\n\n async #checkAndIncrementLastMutationID(\n transactionHooks: TransactionProviderHooks,\n clientID: string,\n receivedMutationID: number,\n ) {\n const {lastMutationID} = await transactionHooks.updateClientMutationID();\n\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new OutOfOrderMutation(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n }\n }\n}\n\nexport class OutOfOrderMutation extends Error {\n /**\n * The mutation ID the client should have sent. Kept out of the message,\n * which is returned to the client; the server logs it separately.\n */\n readonly lastMutationID: number | bigint;\n\n constructor(\n clientID: string,\n receivedMutationID: number,\n lastMutationID: number | bigint,\n ) {\n super(\n `Client ${clientID} sent mutation ID ${receivedMutationID} out of order`,\n );\n this.lastMutationID = lastMutationID;\n }\n}\n\n/**\n * A cleanup mutation named a client group other than the one the push is\n * for. A push may only clean up results of its own client group, so this\n * fails the push instead of being ignored like other cleanup errors.\n */\nclass CleanupClientGroupMismatch extends Error {\n constructor() {\n super('Cleanup mutation does not target the client group of this push');\n }\n}\n\n/**\n * Throws {@link CleanupClientGroupMismatch} when a cleanup mutation names a\n * client group other than `clientGroupID`, the client group of the push.\n * Arguments that do not parse are left for the processing step to report.\n */\nfunction assertCleanupClientGroup(\n mutation: CustomMutation,\n clientGroupID: string,\n): void {\n const parseResult = v.test(mutation.args[0], cleanupResultsArgSchema);\n if (parseResult.ok && parseResult.value.clientGroupID !== clientGroupID) {\n throw new CleanupClientGroupMismatch();\n }\n}\n\nfunction makeAppErrorResponse(\n m: Mutation,\n error: ApplicationError<ReadonlyJSONValue | undefined>,\n): MutationResponse {\n return {\n id: {\n clientID: m.clientID,\n id: m.id,\n },\n result: {\n error: 'app',\n message: error.message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\n/** @deprecated Use getMutator instead */\nexport function getMutation(\n // oxlint-disable-next-line no-explicit-any\n mutators: AnyMutatorRegistry | CustomMutatorDefs<any>,\n name: string,\n // oxlint-disable-next-line no-explicit-any\n): CustomMutatorImpl<any> {\n const path = name.split(separatorRe);\n const mutator = getObjectAtPath(mutators, path);\n assert(typeof mutator === 'function', `could not find mutator ${name}`);\n\n if (isMutator(mutator)) {\n // mutator needs to be called with {tx, args, ctx}\n // CustomMutatorImpl is called with (tx, args, ctx)\n return (tx, args, ctx) => mutator.fn({args, ctx, tx});\n }\n\n // oxlint-disable-next-line no-explicit-any\n return mutator as CustomMutatorImpl<any>;\n}\n\nfunction getObjectAtPath(\n obj: Record<string, unknown>,\n path: string[],\n): unknown {\n let current: unknown = obj;\n for (const part of path) {\n if (typeof current !== 'object' || current === null || !(part in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\n/**\n * Processes internal cleanup mutation that deletes acknowledged mutation results\n * from the upstream database. This runs without LMID tracking since it's an\n * internal operation.\n *\n * `clientGroupID` is the client group of the push. The cleanup must name the\n * same client group; otherwise it throws {@link CleanupClientGroupMismatch}\n * without touching the database. The push is checked for this before any\n * mutation runs; the check here only guards this function's own callers.\n */\nasync function processCleanupResultsMutation<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n mutation: CustomMutation,\n clientGroupID: string,\n queryParams: Params,\n lc: LogContext,\n): Promise<void> {\n const parseResult = v.test(mutation.args[0], cleanupResultsArgSchema);\n if (!parseResult.ok) {\n // log-leak-ignore -- valita reports the failing type, not the value\n lc.warn?.('Cleanup mutation has invalid args', parseResult.error);\n return;\n }\n const args: CleanupResultsArg = parseResult.value;\n\n if (args.clientGroupID !== clientGroupID) {\n throw new CleanupClientGroupMismatch();\n }\n\n // Determine clientID for transaction input based on cleanup type\n // Note: legacy format without type field is treated as single\n const clientID =\n 'type' in args && args.type === 'bulk' ? args.clientIDs[0] : args.clientID;\n\n // Run in a transaction, using the hook for DB-specific operation.\n // Note: only upstreamSchema is used by deleteMutationResults; the other\n // fields are required by the interface but ignored for this operation.\n await dbProvider.transaction(\n async (_, hooks) => {\n await hooks.deleteMutationResults(args);\n },\n {\n upstreamSchema: queryParams.schema,\n clientGroupID,\n clientID,\n mutationID: 0,\n },\n );\n}\n\ntype DatabaseTransactionPhase = 'open' | 'execute';\nclass DatabaseTransactionError extends Error {\n constructor(phase: DatabaseTransactionPhase, options?: ErrorOptions) {\n super(\n phase === 'open'\n ? `Failed to open database transaction: ${getErrorMessage(options?.cause)}`\n : `Database transaction failed after opening: ${getErrorMessage(options?.cause)}`,\n options,\n );\n this.name = 'DatabaseTransactionError';\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-source.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/memory-source.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-source.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/memory-source.ts"],"names":[],"mappings":"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"}