@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.2

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 (138) hide show
  1. package/out/shared/src/custom-key-map.d.ts +4 -4
  2. package/out/shared/src/custom-key-map.d.ts.map +1 -1
  3. package/out/shared/src/custom-key-map.js.map +1 -1
  4. package/out/shared/src/iterables.d.ts +6 -8
  5. package/out/shared/src/iterables.d.ts.map +1 -1
  6. package/out/shared/src/iterables.js +13 -7
  7. package/out/shared/src/iterables.js.map +1 -1
  8. package/out/shared/src/options.d.ts +1 -0
  9. package/out/shared/src/options.d.ts.map +1 -1
  10. package/out/shared/src/options.js +5 -1
  11. package/out/shared/src/options.js.map +1 -1
  12. package/out/zero/package.json.js +1 -1
  13. package/out/zero/src/zero-cache-dev.js +7 -3
  14. package/out/zero/src/zero-cache-dev.js.map +1 -1
  15. package/out/zero-cache/src/config/zero-config.d.ts +10 -1
  16. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  17. package/out/zero-cache/src/config/zero-config.js +27 -7
  18. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  19. package/out/zero-cache/src/observability/events.d.ts.map +1 -1
  20. package/out/zero-cache/src/observability/events.js +15 -5
  21. package/out/zero-cache/src/observability/events.js.map +1 -1
  22. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  23. package/out/zero-cache/src/server/change-streamer.js +10 -2
  24. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  25. package/out/zero-cache/src/server/syncer.d.ts +1 -0
  26. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  27. package/out/zero-cache/src/server/syncer.js +22 -4
  28. package/out/zero-cache/src/server/syncer.js.map +1 -1
  29. package/out/zero-cache/src/services/change-source/custom/change-source.js +0 -4
  30. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  31. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  32. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -10
  33. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  34. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  35. package/out/zero-cache/src/services/change-source/pg/schema/init.js +8 -2
  36. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  37. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  38. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -14
  39. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  40. package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
  41. package/out/zero-cache/src/services/change-source/replica-schema.js +8 -1
  42. package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
  43. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
  44. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  45. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +5 -3
  46. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  47. package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
  48. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  49. package/out/zero-cache/src/services/change-streamer/storer.js +16 -5
  50. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  51. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  52. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  53. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  54. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/litestream/commands.js +3 -1
  56. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  57. package/out/zero-cache/src/services/litestream/config.yml +1 -0
  58. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
  59. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  60. package/out/zero-cache/src/services/mutagen/mutagen.js +9 -24
  61. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  62. package/out/zero-cache/src/services/mutagen/pusher.d.ts +1 -2
  63. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  64. package/out/zero-cache/src/services/mutagen/pusher.js +51 -12
  65. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  66. package/out/zero-cache/src/services/replicator/change-processor.js +4 -3
  67. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  68. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -2
  69. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  70. package/out/zero-cache/src/services/replicator/schema/change-log.js +36 -31
  71. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  72. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
  73. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  74. package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
  75. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  76. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  77. package/out/zero-cache/src/services/view-syncer/cvr-store.js +6 -4
  78. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  79. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -8
  80. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  81. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -11
  82. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  83. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
  84. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  85. package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -10
  86. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  87. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -2
  88. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  89. package/out/zero-cache/src/services/view-syncer/view-syncer.js +40 -42
  90. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  91. package/out/zero-cache/src/workers/connect-params.d.ts +0 -1
  92. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  93. package/out/zero-cache/src/workers/connect-params.js +0 -2
  94. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  95. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  96. package/out/zero-cache/src/workers/replicator.js +2 -5
  97. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  98. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  99. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +1 -4
  100. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  101. package/out/zero-client/src/client/context.js +1 -0
  102. package/out/zero-client/src/client/context.js.map +1 -1
  103. package/out/zero-client/src/client/options.d.ts +1 -1
  104. package/out/zero-client/src/client/options.js.map +1 -1
  105. package/out/zero-client/src/client/version.js +1 -1
  106. package/out/zero-client/src/client/zero.d.ts +2 -4
  107. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  108. package/out/zero-client/src/client/zero.js +1 -1
  109. package/out/zero-client/src/client/zero.js.map +1 -1
  110. package/out/zero-protocol/src/push.d.ts +7 -0
  111. package/out/zero-protocol/src/push.d.ts.map +1 -1
  112. package/out/zero-protocol/src/push.js +9 -1
  113. package/out/zero-protocol/src/push.js.map +1 -1
  114. package/out/zero-server/src/process-mutations.d.ts +1 -0
  115. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  116. package/out/zero-server/src/process-mutations.js +41 -2
  117. package/out/zero-server/src/process-mutations.js.map +1 -1
  118. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  119. package/out/zero-server/src/zql-database.js +9 -0
  120. package/out/zero-server/src/zql-database.js.map +1 -1
  121. package/out/zero-solid/src/solid-view.js +1 -0
  122. package/out/zero-solid/src/solid-view.js.map +1 -1
  123. package/out/zero-solid/src/use-query.js +1 -0
  124. package/out/zero-solid/src/use-query.js.map +1 -1
  125. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  126. package/out/zql/src/ivm/stream.js +1 -1
  127. package/out/zql/src/ivm/stream.js.map +1 -1
  128. package/out/zql/src/mutate/mutator.js +4 -4
  129. package/out/zql/src/mutate/mutator.js.map +1 -1
  130. package/out/zql/src/query/create-builder.js +3 -5
  131. package/out/zql/src/query/create-builder.js.map +1 -1
  132. package/out/zql/src/query/query-registry.js +4 -4
  133. package/out/zql/src/query/query-registry.js.map +1 -1
  134. package/package.json +3 -3
  135. package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
  136. package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
  137. package/out/zero-cache/src/types/schema-versions.js +0 -28
  138. package/out/zero-cache/src/types/schema-versions.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../../zero-protocol/src/push.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../../zero-protocol/src/push.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,14 @@ import { pushFailedBodySchema } from "./error.js";
5
5
  import { mutationIDSchema } from "./mutation-id.js";
6
6
  import { CRUD, Custom } from "./mutation-type-enum.js";
7
7
  import { primaryKeySchema, primaryKeyValueRecordSchema } from "./primary-key.js";
8
- import { object, string, literal, union, array, tuple, number } from "@badrap/valita";
8
+ import { object, number, string, literal, union, array, tuple } from "@badrap/valita";
9
9
  const CRUD_MUTATION_NAME = "_zero_crud";
10
+ const CLEANUP_RESULTS_MUTATION_NAME = "_zero_cleanupResults";
11
+ const cleanupResultsArgSchema = object({
12
+ clientGroupID: string(),
13
+ clientID: string(),
14
+ upToMutationID: number()
15
+ });
10
16
  const insertOpSchema = object({
11
17
  op: literal("insert"),
12
18
  tableName: string(),
@@ -170,8 +176,10 @@ function mapCRUD(arg, map) {
170
176
  };
171
177
  }
172
178
  export {
179
+ CLEANUP_RESULTS_MUTATION_NAME,
173
180
  CRUD_MUTATION_NAME,
174
181
  ackMutationResponsesMessageSchema,
182
+ cleanupResultsArgSchema,
175
183
  crudMutationSchema,
176
184
  customMutationSchema,
177
185
  mapCRUD,
@@ -1 +1 @@
1
- {"version":3,"file":"push.js","sources":["../../../../zero-protocol/src/push.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport type {NameMapper} from '../../zero-types/src/name-mapper.ts';\nimport {rowSchema} from './data.ts';\nimport {pushFailedBodySchema} from './error.ts';\nimport {mutationIDSchema} from './mutation-id.ts';\nimport * as MutationType from './mutation-type-enum.ts';\nimport {primaryKeySchema, primaryKeyValueRecordSchema} from './primary-key.ts';\n\n// NOTE! If you change this name you must also change the\n// string in `replicache-impl.ts` But CRUD mutators are being\n// deleted soon so this should not happen.\nexport const CRUD_MUTATION_NAME = '_zero_crud';\n\n/**\n * Inserts if entity with id does not already exist.\n */\nconst insertOpSchema = v.object({\n op: v.literal('insert'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n value: rowSchema,\n});\n\n/**\n * Upsert semantics. Inserts if entity with id does not already exist,\n * otherwise updates existing entity with id.\n */\nconst upsertOpSchema = v.object({\n op: v.literal('upsert'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n value: rowSchema,\n});\n\n/**\n * Updates if entity with id exists, otherwise does nothing.\n */\nconst updateOpSchema = v.object({\n op: v.literal('update'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n // Partial value with at least the primary key fields\n value: rowSchema,\n});\n\n/**\n * Deletes entity with id if it exists, otherwise does nothing.\n */\nconst deleteOpSchema = v.object({\n op: v.literal('delete'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n // Partial value representing the primary key\n value: primaryKeyValueRecordSchema,\n});\n\nconst crudOpSchema = v.union(\n insertOpSchema,\n upsertOpSchema,\n updateOpSchema,\n deleteOpSchema,\n);\n\nconst crudArgSchema = v.object({\n ops: v.array(crudOpSchema),\n});\n\nconst crudArgsSchema = v.tuple([crudArgSchema]);\n\nexport const crudMutationSchema = v.object({\n type: v.literal(MutationType.CRUD),\n id: v.number(),\n clientID: v.string(),\n name: v.literal(CRUD_MUTATION_NAME),\n args: crudArgsSchema,\n timestamp: v.number(),\n});\n\nexport const customMutationSchema = v.object({\n type: v.literal(MutationType.Custom),\n id: v.number(),\n clientID: v.string(),\n name: v.string(),\n args: v.array(jsonSchema),\n timestamp: v.number(),\n});\n\nexport const mutationSchema = v.union(crudMutationSchema, customMutationSchema);\n\nexport const pushBodySchema = v.object({\n clientGroupID: v.string(),\n mutations: v.array(mutationSchema),\n pushVersion: v.number(),\n // For legacy (CRUD) mutations, the schema is tied to the client group /\n // sync connection. For custom mutations, schema versioning is delegated\n // to the custom protocol / api-server.\n schemaVersion: v.number().optional(),\n timestamp: v.number(),\n requestID: v.string(),\n});\n\nexport const pushMessageSchema = v.tuple([v.literal('push'), pushBodySchema]);\n\nconst appErrorSchema = v.object({\n error: v.literal('app'),\n // The user can return any additional data here\n message: v.string().optional(),\n details: jsonSchema.optional(),\n});\nconst zeroErrorSchema = v.object({\n error: v.union(\n /** @deprecated push oooMutation errors are now represented as ['error', { ... }] messages */\n v.literal('oooMutation'),\n v.literal('alreadyProcessed'),\n ),\n details: jsonSchema.optional(),\n});\n\nconst mutationOkSchema = v.object({\n // The user can return any additional data here\n data: jsonSchema.optional(),\n});\nconst mutationErrorSchema = v.union(appErrorSchema, zeroErrorSchema);\n\nexport const mutationResultSchema = v.union(\n mutationOkSchema,\n mutationErrorSchema,\n);\n\nexport const mutationResponseSchema = v.object({\n id: mutationIDSchema,\n result: mutationResultSchema,\n});\n\nconst pushOkSchema = v.object({\n mutations: v.array(mutationResponseSchema),\n});\n\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst unsupportedPushVersionSchema = v.object({\n /** @deprecated */\n error: v.literal('unsupportedPushVersion'),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst unsupportedSchemaVersionSchema = v.object({\n /** @deprecated */\n error: v.literal('unsupportedSchemaVersion'),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push http errors are now represented as ['error', { ... }] messages\n */\nconst httpErrorSchema = v.object({\n /** @deprecated */\n error: v.literal('http'),\n /** @deprecated */\n status: v.number(),\n /** @deprecated */\n details: v.string(),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push zero errors are now represented as ['error', { ... }] messages\n */\nconst zeroPusherErrorSchema = v.object({\n /** @deprecated */\n error: v.literal('zeroPusher'),\n /** @deprecated */\n details: v.string(),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst pushErrorSchema = v.union(\n unsupportedPushVersionSchema,\n unsupportedSchemaVersionSchema,\n httpErrorSchema,\n zeroPusherErrorSchema,\n);\n\nexport const pushResponseBodySchema = v.union(pushOkSchema, pushErrorSchema);\n\nexport const pushResponseSchema = v.union(\n pushResponseBodySchema,\n pushFailedBodySchema,\n);\nexport const pushResponseMessageSchema = v.tuple([\n v.literal('pushResponse'),\n pushResponseBodySchema,\n]);\n\nexport const ackMutationResponsesMessageSchema = v.tuple([\n v.literal('ackMutationResponses'),\n mutationIDSchema,\n]);\n\n/**\n * The schema for the querystring parameters of the custom push endpoint.\n */\nexport const pushParamsSchema = v.object({\n schema: v.string(),\n appID: v.string(),\n});\n\nexport type InsertOp = v.Infer<typeof insertOpSchema>;\nexport type UpsertOp = v.Infer<typeof upsertOpSchema>;\nexport type UpdateOp = v.Infer<typeof updateOpSchema>;\nexport type DeleteOp = v.Infer<typeof deleteOpSchema>;\nexport type CRUDOp = v.Infer<typeof crudOpSchema>;\nexport type CRUDOpKind = CRUDOp['op'];\nexport type CRUDMutationArg = v.Infer<typeof crudArgSchema>;\nexport type CRUDMutation = v.Infer<typeof crudMutationSchema>;\nexport type CustomMutation = v.Infer<typeof customMutationSchema>;\nexport type Mutation = v.Infer<typeof mutationSchema>;\nexport type PushBody = v.Infer<typeof pushBodySchema>;\nexport type PushMessage = v.Infer<typeof pushMessageSchema>;\nexport type PushResponseBody = v.Infer<typeof pushResponseBodySchema>;\nexport type PushResponse = v.Infer<typeof pushResponseSchema>;\nexport type PushResponseMessage = v.Infer<typeof pushResponseMessageSchema>;\nexport type MutationResponse = v.Infer<typeof mutationResponseSchema>;\nexport type MutationOk = v.Infer<typeof mutationOkSchema>;\nexport type MutationError = v.Infer<typeof mutationErrorSchema>;\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nexport type PushError = v.Infer<typeof pushErrorSchema>;\nexport type PushOk = v.Infer<typeof pushOkSchema>;\nexport type MutationResult = v.Infer<typeof mutationResultSchema>;\nexport type AckMutationMessage = v.Infer<\n typeof ackMutationResponsesMessageSchema\n>;\nexport type {MutationID} from './mutation-id.ts';\n\nexport function mapCRUD(\n arg: CRUDMutationArg,\n map: NameMapper,\n): CRUDMutationArg {\n return {\n ops: arg.ops.map(\n ({op, tableName, primaryKey, value}) =>\n ({\n op,\n tableName: map.tableName(tableName),\n primaryKey: map.columns(tableName, primaryKey),\n value: map.row(tableName, value),\n // The cast is necessary because ts objects to the `value` field\n // for \"delete\" ops being different.\n }) as unknown as CRUDOp,\n ),\n };\n}\n"],"names":["v.object","v.literal","v.string","v.union","v.array","v.tuple","MutationType.CRUD","v.number","MutationType.Custom"],"mappings":"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"}
1
+ {"version":3,"file":"push.js","sources":["../../../../zero-protocol/src/push.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport type {NameMapper} from '../../zero-types/src/name-mapper.ts';\nimport {rowSchema} from './data.ts';\nimport {pushFailedBodySchema} from './error.ts';\nimport {mutationIDSchema} from './mutation-id.ts';\nimport * as MutationType from './mutation-type-enum.ts';\nimport {primaryKeySchema, primaryKeyValueRecordSchema} from './primary-key.ts';\n\n// NOTE! If you change this name you must also change the\n// string in `replicache-impl.ts` But CRUD mutators are being\n// deleted soon so this should not happen.\nexport const CRUD_MUTATION_NAME = '_zero_crud';\n\n// Internal mutation name for cleaning up mutation results.\n// This mutation is sent from zero-cache to zero-server to delete\n// acknowledged mutation results from the upstream database.\nexport const CLEANUP_RESULTS_MUTATION_NAME = '_zero_cleanupResults';\n\nexport const cleanupResultsArgSchema = v.object({\n clientGroupID: v.string(),\n clientID: v.string(),\n upToMutationID: v.number(),\n});\n\n/**\n * Inserts if entity with id does not already exist.\n */\nconst insertOpSchema = v.object({\n op: v.literal('insert'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n value: rowSchema,\n});\n\n/**\n * Upsert semantics. Inserts if entity with id does not already exist,\n * otherwise updates existing entity with id.\n */\nconst upsertOpSchema = v.object({\n op: v.literal('upsert'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n value: rowSchema,\n});\n\n/**\n * Updates if entity with id exists, otherwise does nothing.\n */\nconst updateOpSchema = v.object({\n op: v.literal('update'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n // Partial value with at least the primary key fields\n value: rowSchema,\n});\n\n/**\n * Deletes entity with id if it exists, otherwise does nothing.\n */\nconst deleteOpSchema = v.object({\n op: v.literal('delete'),\n tableName: v.string(),\n primaryKey: primaryKeySchema,\n // Partial value representing the primary key\n value: primaryKeyValueRecordSchema,\n});\n\nconst crudOpSchema = v.union(\n insertOpSchema,\n upsertOpSchema,\n updateOpSchema,\n deleteOpSchema,\n);\n\nconst crudArgSchema = v.object({\n ops: v.array(crudOpSchema),\n});\n\nconst crudArgsSchema = v.tuple([crudArgSchema]);\n\nexport const crudMutationSchema = v.object({\n type: v.literal(MutationType.CRUD),\n id: v.number(),\n clientID: v.string(),\n name: v.literal(CRUD_MUTATION_NAME),\n args: crudArgsSchema,\n timestamp: v.number(),\n});\n\nexport const customMutationSchema = v.object({\n type: v.literal(MutationType.Custom),\n id: v.number(),\n clientID: v.string(),\n name: v.string(),\n args: v.array(jsonSchema),\n timestamp: v.number(),\n});\n\nexport const mutationSchema = v.union(crudMutationSchema, customMutationSchema);\n\nexport const pushBodySchema = v.object({\n clientGroupID: v.string(),\n mutations: v.array(mutationSchema),\n pushVersion: v.number(),\n // For legacy (CRUD) mutations, the schema is tied to the client group /\n // sync connection. For custom mutations, schema versioning is delegated\n // to the custom protocol / api-server.\n schemaVersion: v.number().optional(),\n timestamp: v.number(),\n requestID: v.string(),\n});\n\nexport const pushMessageSchema = v.tuple([v.literal('push'), pushBodySchema]);\n\nconst appErrorSchema = v.object({\n error: v.literal('app'),\n // The user can return any additional data here\n message: v.string().optional(),\n details: jsonSchema.optional(),\n});\nconst zeroErrorSchema = v.object({\n error: v.union(\n /** @deprecated push oooMutation errors are now represented as ['error', { ... }] messages */\n v.literal('oooMutation'),\n v.literal('alreadyProcessed'),\n ),\n details: jsonSchema.optional(),\n});\n\nconst mutationOkSchema = v.object({\n // The user can return any additional data here\n data: jsonSchema.optional(),\n});\nconst mutationErrorSchema = v.union(appErrorSchema, zeroErrorSchema);\n\nexport const mutationResultSchema = v.union(\n mutationOkSchema,\n mutationErrorSchema,\n);\n\nexport const mutationResponseSchema = v.object({\n id: mutationIDSchema,\n result: mutationResultSchema,\n});\n\nconst pushOkSchema = v.object({\n mutations: v.array(mutationResponseSchema),\n});\n\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst unsupportedPushVersionSchema = v.object({\n /** @deprecated */\n error: v.literal('unsupportedPushVersion'),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst unsupportedSchemaVersionSchema = v.object({\n /** @deprecated */\n error: v.literal('unsupportedSchemaVersion'),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push http errors are now represented as ['error', { ... }] messages\n */\nconst httpErrorSchema = v.object({\n /** @deprecated */\n error: v.literal('http'),\n /** @deprecated */\n status: v.number(),\n /** @deprecated */\n details: v.string(),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push zero errors are now represented as ['error', { ... }] messages\n */\nconst zeroPusherErrorSchema = v.object({\n /** @deprecated */\n error: v.literal('zeroPusher'),\n /** @deprecated */\n details: v.string(),\n /** @deprecated */\n mutationIDs: v.array(mutationIDSchema).optional(),\n});\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nconst pushErrorSchema = v.union(\n unsupportedPushVersionSchema,\n unsupportedSchemaVersionSchema,\n httpErrorSchema,\n zeroPusherErrorSchema,\n);\n\nexport const pushResponseBodySchema = v.union(pushOkSchema, pushErrorSchema);\n\nexport const pushResponseSchema = v.union(\n pushResponseBodySchema,\n pushFailedBodySchema,\n);\nexport const pushResponseMessageSchema = v.tuple([\n v.literal('pushResponse'),\n pushResponseBodySchema,\n]);\n\nexport const ackMutationResponsesMessageSchema = v.tuple([\n v.literal('ackMutationResponses'),\n mutationIDSchema,\n]);\n\n/**\n * The schema for the querystring parameters of the custom push endpoint.\n */\nexport const pushParamsSchema = v.object({\n schema: v.string(),\n appID: v.string(),\n});\n\nexport type InsertOp = v.Infer<typeof insertOpSchema>;\nexport type UpsertOp = v.Infer<typeof upsertOpSchema>;\nexport type UpdateOp = v.Infer<typeof updateOpSchema>;\nexport type DeleteOp = v.Infer<typeof deleteOpSchema>;\nexport type CRUDOp = v.Infer<typeof crudOpSchema>;\nexport type CRUDOpKind = CRUDOp['op'];\nexport type CRUDMutationArg = v.Infer<typeof crudArgSchema>;\nexport type CRUDMutation = v.Infer<typeof crudMutationSchema>;\nexport type CustomMutation = v.Infer<typeof customMutationSchema>;\nexport type Mutation = v.Infer<typeof mutationSchema>;\nexport type PushBody = v.Infer<typeof pushBodySchema>;\nexport type PushMessage = v.Infer<typeof pushMessageSchema>;\nexport type PushResponseBody = v.Infer<typeof pushResponseBodySchema>;\nexport type PushResponse = v.Infer<typeof pushResponseSchema>;\nexport type PushResponseMessage = v.Infer<typeof pushResponseMessageSchema>;\nexport type MutationResponse = v.Infer<typeof mutationResponseSchema>;\nexport type MutationOk = v.Infer<typeof mutationOkSchema>;\nexport type MutationError = v.Infer<typeof mutationErrorSchema>;\n/**\n * @deprecated push errors are now represented as ['error', { ... }] messages\n */\nexport type PushError = v.Infer<typeof pushErrorSchema>;\nexport type PushOk = v.Infer<typeof pushOkSchema>;\nexport type MutationResult = v.Infer<typeof mutationResultSchema>;\nexport type AckMutationMessage = v.Infer<\n typeof ackMutationResponsesMessageSchema\n>;\nexport type CleanupResultsArg = v.Infer<typeof cleanupResultsArgSchema>;\nexport type {MutationID} from './mutation-id.ts';\n\nexport function mapCRUD(\n arg: CRUDMutationArg,\n map: NameMapper,\n): CRUDMutationArg {\n return {\n ops: arg.ops.map(\n ({op, tableName, primaryKey, value}) =>\n ({\n op,\n tableName: map.tableName(tableName),\n primaryKey: map.columns(tableName, primaryKey),\n value: map.row(tableName, value),\n // The cast is necessary because ts objects to the `value` field\n // for \"delete\" ops being different.\n }) as unknown as CRUDOp,\n ),\n };\n}\n"],"names":["v.object","v.string","v.number","v.literal","v.union","v.array","v.tuple","MutationType.CRUD","MutationType.Custom"],"mappings":"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"}
@@ -10,6 +10,7 @@ export interface TransactionProviderHooks {
10
10
  lastMutationID: number | bigint;
11
11
  }>;
12
12
  writeMutationResult: (result: MutationResponse) => Promise<void>;
13
+ deleteMutationResults: (clientGroupID: string, clientID: string, upToMutationID: number) => Promise<void>;
13
14
  }
14
15
  export interface TransactionProviderInput {
15
16
  upstreamSchema: string;
@@ -1 +1 @@
1
- {"version":3,"file":"process-mutations.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/process-mutations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAG3D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,CAAC,MAAM,4BAA4B,CAAC;AAWhD,OAAO,EAEL,gBAAgB,EAChB,KAAK,cAAc,EAGnB,KAAK,gBAAgB,EAErB,KAAK,YAAY,EAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0CAA0C,CAAC;AAEjF,OAAO,KAAK,EAAC,iBAAiB,EAAE,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAGtE,MAAM,WAAW,wBAAwB;IACvC,sBAAsB,EAAE,MAAM,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,CAAC,CAAC;IACzE,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,WAAW,EAAE,CAAC,CAAC,EACb,QAAQ,EAAE,CACR,EAAE,EAAE,CAAC,EACL,gBAAgB,EAAE,wBAAwB,KACvC,YAAY,CAAC,CAAC,CAAC,EACpB,gBAAgB,CAAC,EAAE,wBAAwB,KACxC,OAAO,CAAC,CAAC,CAAC,CAAC;CACjB;AAED,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAChF,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEtD,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAAI,CACtE,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC,KACtB,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE/B,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAC1E,CACE,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC,EAC7B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,iBAAiB,GAAG,SAAS,KACvC,OAAO,CAAC,IAAI,CAAC,CAAC;AAErB,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAAI;IAClE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACxB,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B,CAAC;AAqBF;;GAEG;AACH,eAAO,MAAM,qBAAqB,4BAAsB,CAAC;AAEzD,wBAAgB,mBAAmB,CACjC,CAAC,SAAS,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAE7C,UAAU,EAAE,CAAC,EACb,EAAE,EAAE,CACF,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,EACvB,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,gBAAgB,CAAC,EAC9B,WAAW,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACrD,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAAC,YAAY,CAAC,CAAC;AAEzB,wBAAgB,mBAAmB,CACjC,CAAC,SAAS,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAE7C,UAAU,EAAE,CAAC,EACb,EAAE,EAAE,CACF,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,EACvB,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,gBAAgB,CAAC,EAC9B,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAAC,YAAY,CAAC,CAAC;AAsXzB,qBAAa,kBAAmB,SAAQ,KAAK;gBAEzC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,MAAM,EAC1B,cAAc,EAAE,MAAM,GAAG,MAAM;CAMlC;AAmBD,yCAAyC;AACzC,wBAAgB,WAAW,CAEzB,QAAQ,EAAE,kBAAkB,GAAG,iBAAiB,CAAC,GAAG,CAAC,EACrD,IAAI,EAAE,MAAM,GAEX,iBAAiB,CAAC,GAAG,CAAC,CAaxB"}
1
+ {"version":3,"file":"process-mutations.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/process-mutations.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,13 @@
1
1
  import { assert } from "../../shared/src/asserts.js";
2
2
  import { getErrorMessage, getErrorDetails } from "../../shared/src/error.js";
3
3
  import { promiseVoid } from "../../shared/src/resolved-promises.js";
4
- import { parse } from "../../shared/src/valita.js";
4
+ import { parse, test } from "../../shared/src/valita.js";
5
5
  import { MutationAlreadyProcessedError } from "../../zero-cache/src/services/mutagen/error.js";
6
6
  import { isApplicationError, wrapWithApplicationError } from "../../zero-protocol/src/application-error.js";
7
7
  import { PushFailed } from "../../zero-protocol/src/error-kind-enum.js";
8
8
  import { Server } from "../../zero-protocol/src/error-origin-enum.js";
9
9
  import { Parse, UnsupportedPushVersion, OutOfOrderMutation as OutOfOrderMutation$1, Database, Internal } from "../../zero-protocol/src/error-reason-enum.js";
10
- import { pushBodySchema, pushParamsSchema } from "../../zero-protocol/src/push.js";
10
+ import { pushBodySchema, pushParamsSchema, CLEANUP_RESULTS_MUTATION_NAME, cleanupResultsArgSchema } from "../../zero-protocol/src/push.js";
11
11
  import { isMutator } from "../../zql/src/mutate/mutator.js";
12
12
  import { createLogContext } from "./logging.js";
13
13
  const applicationErrorWrapper = async (fn) => {
@@ -107,6 +107,22 @@ async function handleMutateRequest(dbProvider, cb, queryStringOrRequest, bodyOrL
107
107
  try {
108
108
  const transactor = new Transactor(dbProvider, pushBody, queryParams, lc);
109
109
  for (const m of pushBody.mutations) {
110
+ if (m.type === "custom" && m.name === CLEANUP_RESULTS_MUTATION_NAME) {
111
+ lc.debug?.(
112
+ `Processing internal mutation '${m.name}' (clientID=${m.clientID})`
113
+ );
114
+ try {
115
+ await processCleanupResultsMutation(dbProvider, m, queryParams, lc);
116
+ processedCount++;
117
+ } catch (error) {
118
+ lc.warn?.(
119
+ `Failed to process cleanup mutation for client ${m.clientID}`,
120
+ error
121
+ );
122
+ processedCount++;
123
+ }
124
+ continue;
125
+ }
110
126
  assert(m.type === "custom", "Expected custom mutation");
111
127
  lc.debug?.(
112
128
  `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,
@@ -338,6 +354,29 @@ function getObjectAtPath(obj, path) {
338
354
  }
339
355
  return current;
340
356
  }
357
+ async function processCleanupResultsMutation(dbProvider, mutation, queryParams, lc) {
358
+ const parseResult = test(mutation.args[0], cleanupResultsArgSchema);
359
+ if (!parseResult.ok) {
360
+ lc.warn?.("Cleanup mutation has invalid args", parseResult.error);
361
+ return;
362
+ }
363
+ const args = parseResult.value;
364
+ await dbProvider.transaction(
365
+ async (_, hooks) => {
366
+ await hooks.deleteMutationResults(
367
+ args.clientGroupID,
368
+ args.clientID,
369
+ args.upToMutationID
370
+ );
371
+ },
372
+ {
373
+ upstreamSchema: queryParams.schema,
374
+ clientGroupID: args.clientGroupID,
375
+ clientID: args.clientID,
376
+ mutationID: 0
377
+ }
378
+ );
379
+ }
341
380
  class DatabaseTransactionError extends Error {
342
381
  constructor(phase, options) {
343
382
  super(
@@ -1 +1 @@
1
- {"version":3,"file":"process-mutations.js","sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import type {LogContext, LogLevel} 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 pushBodySchema,\n pushParamsSchema,\n type CustomMutation,\n type Mutation,\n type MutationID,\n type MutationResponse,\n type PushBody,\n type PushResponse,\n} from '../../zero-protocol/src/push.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';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\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 pushParamsSchema>;\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<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 {@linkcode handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n request: Request,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryStringOrRequest: Request | URLSearchParams | Record<string, string>,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel,\n logLevel?: LogLevel,\n): Promise<PushResponse> {\n // Parse overload arguments\n const isRequestOverload = queryStringOrRequest instanceof Request;\n\n let request: Request | undefined;\n let queryString: URLSearchParams | Record<string, string>;\n let jsonBody: unknown;\n\n let lc: LogContext;\n\n if (isRequestOverload) {\n request = queryStringOrRequest;\n const level = (bodyOrLogLevel as LogLevel | undefined) ?? 'info';\n\n // Create log context early, before extracting JSON from Request\n lc = createLogContext(level).withContext('PushProcessor');\n\n const url = new URL(request.url);\n queryString = url.searchParams;\n\n try {\n jsonBody = await 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 queryString = queryStringOrRequest;\n jsonBody = bodyOrLogLevel;\n const level = logLevel ?? 'info';\n lc = createLogContext(level).withContext('PushProcessor');\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema);\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 queryParams: Params;\n try {\n const queryStringObj =\n queryString instanceof URLSearchParams\n ? Object.fromEntries(queryString)\n : queryString;\n queryParams = v.parse(queryStringObj, pushParamsSchema, 'passthrough');\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(dbProvider, pushBody, queryParams, lc);\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 assert(m.type === 'custom', 'Expected custom mutation');\n lc.debug?.(\n `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,\n m.args,\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, (tx, name, args) =>\n applicationErrorWrapper(() => innerCb(tx, name, args)),\n );\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() => cb(transactProxy, m));\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 mutations: responses,\n };\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\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 transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n for (;;) {\n try {\n const ret = await this.#transactImpl(mutation, cb, appError);\n if (appError !== undefined) {\n this.#lc.warn?.(\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 (isApplicationError(error)) {\n appError = error;\n this.#lc.warn?.(\n `Application error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n appError,\n );\n continue;\n }\n\n this.#lc.error?.(\n `Unexpected error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n\n throw error;\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 );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | 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 `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n try {\n await cb(dbTx, mutation.name, mutation.args[0]);\n } catch (appError) {\n throw wrapWithApplicationError(appError);\n }\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n }\n\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {},\n };\n },\n this.#getTransactionInput(mutation),\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(mutation: CustomMutation): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\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(/\\.|\\|/);\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\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"],"names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","appError"],"mappings":"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"}
1
+ {"version":3,"file":"process-mutations.js","sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import type {LogContext, LogLevel} 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 CLEANUP_RESULTS_MUTATION_NAME,\n cleanupResultsArgSchema,\n pushBodySchema,\n pushParamsSchema,\n type CleanupResultsArg,\n type CustomMutation,\n type Mutation,\n type MutationID,\n type MutationResponse,\n type PushBody,\n type PushResponse,\n} from '../../zero-protocol/src/push.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';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n deleteMutationResults: (\n clientGroupID: string,\n clientID: string,\n upToMutationID: number,\n ) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\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 pushParamsSchema>;\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<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 {@linkcode handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n request: Request,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryStringOrRequest: Request | URLSearchParams | Record<string, string>,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel,\n logLevel?: LogLevel,\n): Promise<PushResponse> {\n // Parse overload arguments\n const isRequestOverload = queryStringOrRequest instanceof Request;\n\n let request: Request | undefined;\n let queryString: URLSearchParams | Record<string, string>;\n let jsonBody: unknown;\n\n let lc: LogContext;\n\n if (isRequestOverload) {\n request = queryStringOrRequest;\n const level = (bodyOrLogLevel as LogLevel | undefined) ?? 'info';\n\n // Create log context early, before extracting JSON from Request\n lc = createLogContext(level).withContext('PushProcessor');\n\n const url = new URL(request.url);\n queryString = url.searchParams;\n\n try {\n jsonBody = await 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 queryString = queryStringOrRequest;\n jsonBody = bodyOrLogLevel;\n const level = logLevel ?? 'info';\n lc = createLogContext(level).withContext('PushProcessor');\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema);\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 queryParams: Params;\n try {\n const queryStringObj =\n queryString instanceof URLSearchParams\n ? Object.fromEntries(queryString)\n : queryString;\n queryParams = v.parse(queryStringObj, pushParamsSchema, 'passthrough');\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(dbProvider, pushBody, queryParams, lc);\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(dbProvider, m, queryParams, lc);\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 m.args,\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, (tx, name, args) =>\n applicationErrorWrapper(() => innerCb(tx, name, args)),\n );\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() => cb(transactProxy, m));\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 mutations: responses,\n };\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\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 transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n for (;;) {\n try {\n const ret = await this.#transactImpl(mutation, cb, appError);\n if (appError !== undefined) {\n this.#lc.warn?.(\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 (isApplicationError(error)) {\n appError = error;\n this.#lc.warn?.(\n `Application error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n appError,\n );\n continue;\n }\n\n this.#lc.error?.(\n `Unexpected error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n\n throw error;\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 );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | 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 `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n try {\n await cb(dbTx, mutation.name, mutation.args[0]);\n } catch (appError) {\n throw wrapWithApplicationError(appError);\n }\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n }\n\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {},\n };\n },\n this.#getTransactionInput(mutation),\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(mutation: CustomMutation): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\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(/\\.|\\|/);\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 lc.warn?.('Cleanup mutation has invalid args', parseResult.error);\n return;\n }\n const args: CleanupResultsArg = parseResult.value;\n\n // Run in a transaction, using the hook for DB-specific operation\n await dbProvider.transaction(\n async (_, hooks) => {\n await hooks.deleteMutationResults(\n args.clientGroupID,\n args.clientID,\n args.upToMutationID,\n );\n },\n {\n upstreamSchema: queryParams.schema,\n clientGroupID: args.clientGroupID,\n clientID: args.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"],"names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","appError","v.test"],"mappings":";;;;;;;;;;;;AAuFA,MAAM,0BAA0B,OAAU,OAAqC;AAC7E,MAAI;AACF,WAAO,MAAM,GAAA;AAAA,EACf,SAAS,OAAO;AACd,QACE,iBAAiB,4BACjB,iBAAiB,sBACjB,iBAAiB,iCACjB,mBAAmB,KAAK,GACxB;AACA,YAAM;AAAA,IACR;AAEA,UAAM,yBAAyB,KAAK;AAAA,EACtC;AACF;AAKO,MAAM,wBAAwB;AA2BrC,eAAsB,oBAGpB,YACA,IAIA,sBACA,gBACA,UACuB;AAEvB,QAAM,oBAAoB,gCAAgC;AAE1D,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,MAAI;AAEJ,MAAI,mBAAmB;AACrB,cAAU;AACV,UAAM,QAAS,kBAA2C;AAG1D,SAAK,iBAAiB,KAAK,EAAE,YAAY,eAAe;AAExD,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,kBAAc,IAAI;AAElB,QAAI;AACF,iBAAW,MAAM,QAAQ,KAAA;AAAA,IAC3B,SAAS,OAAO;AACd,SAAG,QAAQ,6BAA6B,KAAK;AAC7C,YAAM,UAAU,8BAA8B,gBAAgB,KAAK,CAAC;AACpE,YAAM,UAAU,gBAAgB,KAAK;AACrC,aAAO;AAAA,QACL,MAAMA;AAAAA,QACN,QAAQC;AAAAA,QACR,QAAQC;AAAAA,QACR;AAAA,QACA,aAAa,CAAA;AAAA,QACb,GAAI,UAAU,EAAC,YAAW,CAAA;AAAA,MAAC;AAAA,IAE/B;AAAA,EACF,OAAO;AACL,kBAAc;AACd,eAAW;AACX,UAAM,QAAQ,YAAY;AAC1B,SAAK,iBAAiB,KAAK,EAAE,YAAY,eAAe;AAAA,EAC1D;AAEA,MAAI,cAA4B,CAAA;AAEhC,MAAI;AACJ,MAAI;AACF,eAAWC,MAAQ,UAAU,cAAc;AAC3C,kBAAc,SAAS,UAAU,IAAI,CAAA,OAAM;AAAA,MACzC,IAAI,EAAE;AAAA,MACN,UAAU,EAAE;AAAA,IAAA,EACZ;AAAA,EACJ,SAAS,OAAO;AACd,OAAG,QAAQ,6BAA6B,KAAK;AAC7C,UAAM,UAAU,8BAA8B,gBAAgB,KAAK,CAAC;AACpE,UAAM,UAAU,gBAAgB,KAAK;AACrC,WAAO;AAAA,MACL,MAAMH;AAAAA,MACN,QAAQC;AAAAA,MACR,QAAQC;AAAAA,MACR;AAAA,MACA;AAAA,MACA,GAAI,UAAU,EAAC,YAAW,CAAA;AAAA,IAAC;AAAA,EAE/B;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,iBACJ,uBAAuB,kBACnB,OAAO,YAAY,WAAW,IAC9B;AACN,kBAAcC,MAAQ,gBAAgB,kBAAkB,aAAa;AAAA,EACvE,SAAS,OAAO;AACd,OAAG,QAAQ,yCAAyC,KAAK;AACzD,UAAM,UAAU,0CAA0C,gBAAgB,KAAK,CAAC;AAChF,UAAM,UAAU,gBAAgB,KAAK;AACrC,WAAO;AAAA,MACL,MAAMH;AAAAA,MACN,QAAQC;AAAAA,MACR,QAAQC;AAAAA,MACR;AAAA,MACA;AAAA,MACA,GAAI,UAAU,EAAC,YAAW,CAAA;AAAA,IAAC;AAAA,EAE/B;AAEA,MAAI,SAAS,gBAAgB,GAAG;AAC9B,UAAM,WAAW;AAAA,MACf,MAAMF;AAAAA,MACN,QAAQC;AAAAA,MACR,QAAQG;AAAAA,MACR;AAAA,MACA,SAAS,6BAA6B,SAAS,WAAW;AAAA,IAAA;AAE5D,WAAO;AAAA,EACT;AAEA,QAAM,YAAgC,CAAA;AACtC,MAAI,iBAAiB;AAErB,MAAI;AACF,UAAM,aAAa,IAAI,WAAW,YAAY,UAAU,aAAa,EAAE;AASvE,eAAW,KAAK,SAAS,WAAW;AAElC,UAAI,EAAE,SAAS,YAAY,EAAE,SAAS,+BAA+B;AACnE,WAAG;AAAA,UACD,iCAAiC,EAAE,IAAI,eAAe,EAAE,QAAQ;AAAA,QAAA;AAElE,YAAI;AACF,gBAAM,8BAA8B,YAAY,GAAG,aAAa,EAAE;AAElE;AAAA,QACF,SAAS,OAAO;AACd,aAAG;AAAA,YACD,iDAAiD,EAAE,QAAQ;AAAA,YAC3D;AAAA,UAAA;AAGF;AAAA,QACF;AACA;AAAA,MACF;AAEA,aAAO,EAAE,SAAS,UAAU,0BAA0B;AACtD,SAAG;AAAA,QACD,wBAAwB,EAAE,IAAI,SAAS,EAAE,EAAE,cAAc,EAAE,QAAQ;AAAA,QACnE,EAAE;AAAA,MAAA;AAGJ,UAAI,gBAA+B;AAEnC,YAAM,gBAA+B,OAAM,YAAW;AACpD,wBAAgB;AAChB,cAAM,SAAS,MAAM,WAAW;AAAA,UAAS;AAAA,UAAG,CAAC,IAAI,MAAM,SACrD,wBAAwB,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC;AAAA,QAAA;AAEvD,wBAAgB;AAChB,eAAO;AAAA,MACT;AAEA,UAAI;AACF,cAAM,MAAM,MAAM,wBAAwB,MAAM,GAAG,eAAe,CAAC,CAAC;AACpE,kBAAU,KAAK,GAAG;AAClB,WAAG,QAAQ,aAAa,EAAE,IAAI,SAAS,EAAE,EAAE,0BAA0B;AAErE;AAAA,MACF,SAAS,OAAO;AACd,YAAI,CAAC,mBAAmB,KAAK,GAAG;AAC9B,gBAAM;AAAA,QACR;AAEA,YAAI,kBAAkB,kBAAkB;AAEtC,gBAAM,WAAW,6BAA6B,GAAG,KAAK;AAAA,QACxD,WAAW,kBAAkB,cAAc;AAEzC,aAAG;AAAA,YACD,oDAAoD,EAAE,EAAE,eAAe,EAAE,QAAQ;AAAA,YACjF;AAAA,UAAA;AAAA,QAEJ;AAEA,WAAG;AAAA,UACD,yCAAyC,EAAE,EAAE,eAAe,EAAE,QAAQ;AAAA,UACtE;AAAA,QAAA;AAEF,kBAAU,KAAK,qBAAqB,GAAG,KAAK,CAAC;AAE7C;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,IAAA;AAAA,EAEf,SAAS,OAAO;AACd,OAAG,QAAQ,kCAAkC,KAAK;AAElD,UAAM,yBAAyB,YAAY,MAAM,cAAc;AAE/D,UAAM,UAAU,gBAAgB,KAAK;AACrC,UAAM,UAAU,gBAAgB,KAAK;AAErC,WAAO;AAAA,MACL,MAAMJ;AAAAA,MACN,QAAQC;AAAAA,MACR,QACE,iBAAiB,qBACbI,uBACA,iBAAiB,2BACfC,WACAC;AAAAA,MACR;AAAA,MACA,aAAa;AAAA,MACb,GAAI,UAAU,EAAC,YAAW,CAAA;AAAA,IAAC;AAAA,EAE/B;AACF;AAEA,MAAM,WAA0D;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,YAAe,KAAe,QAAgB,IAAgB;AACxE,SAAK,cAAc;AACnB,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,WAAW,OACT,UACA,OAC8B;AAC9B,QAAI,WAAyC;AAC7C,eAAS;AACP,UAAI;AACF,cAAM,MAAM,MAAM,KAAK,cAAc,UAAU,IAAI,QAAQ;AAC3D,YAAI,aAAa,QAAW;AAC1B,eAAK,IAAI;AAAA,YACP,YAAY,SAAS,EAAE,eAAe,SAAS,QAAQ;AAAA,YACvD;AAAA,UAAA;AAEF,iBAAO,qBAAqB,UAAU,QAAQ;AAAA,QAChD;AAEA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI,iBAAiB,oBAAoB;AACvC,eAAK,IAAI,QAAQ,KAAK;AACtB,gBAAM;AAAA,QACR;AAEA,YAAI,iBAAiB,+BAA+B;AAClD,eAAK,IAAI,OAAO,KAAK;AACrB,iBAAO;AAAA,YACL,IAAI;AAAA,cACF,UAAU,SAAS;AAAA,cACnB,IAAI,SAAS;AAAA,YAAA;AAAA,YAEf,QAAQ;AAAA,cACN,OAAO;AAAA,cACP,SAAS,MAAM;AAAA,YAAA;AAAA,UACjB;AAAA,QAEJ;AAEA,YAAI,mBAAmB,KAAK,GAAG;AAC7B,qBAAW;AACX,eAAK,IAAI;AAAA,YACP,yCAAyC,SAAS,EAAE,eAAe,SAAS,QAAQ;AAAA,YACpF;AAAA,UAAA;AAEF;AAAA,QACF;AAEA,aAAK,IAAI;AAAA,UACP,wCAAwC,SAAS,EAAE,eAAe,SAAS,QAAQ;AAAA,UACnF;AAAA,QAAA;AAGF,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,6BACJ,UACA,UAC2B;AAG3B,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA;AAAA,MAEA,MAAM;AAAA,MACN;AAAA,IAAA;AAEF,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cACJ,UACA,IACA,UAC2B;AAC3B,QAAI,mBAA6C;AAEjD,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,YAAY;AAAA,QACjC,OAAO,MAAM,qBAAqB;AAEhC,6BAAmB;AAEnB,gBAAM,KAAK;AAAA,YACT;AAAA,YACA,SAAS;AAAA,YACT,SAAS;AAAA,UAAA;AAGX,cAAI,aAAa,QAAW;AAC1B,iBAAK,IAAI;AAAA,cACP,sBAAsB,SAAS,IAAI,SAAS,SAAS,EAAE;AAAA,YAAA;AAEzD,gBAAI;AACF,oBAAM,GAAG,MAAM,SAAS,MAAM,SAAS,KAAK,CAAC,CAAC;AAAA,YAChD,SAASC,WAAU;AACjB,oBAAM,yBAAyBA,SAAQ;AAAA,YACzC;AAAA,UACF,OAAO;AACL,kBAAM,iBAAiB,qBAAqB,UAAU,QAAQ;AAC9D,kBAAM,iBAAiB,oBAAoB,cAAc;AAAA,UAC3D;AAEA,iBAAO;AAAA,YACL,IAAI;AAAA,cACF,UAAU,SAAS;AAAA,cACnB,IAAI,SAAS;AAAA,YAAA;AAAA,YAEf,QAAQ,CAAA;AAAA,UAAC;AAAA,QAEb;AAAA,QACA,KAAK,qBAAqB,QAAQ;AAAA,MAAA;AAGpC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UACE,mBAAmB,KAAK,KACxB,iBAAiB,sBACjB,iBAAiB,+BACjB;AACA,cAAM;AAAA,MACR;AAEA,YAAM,IAAI,yBAAyB,kBAAkB,EAAC,OAAO,OAAM;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,qBAAqB,UAAoD;AACvE,WAAO;AAAA,MACL,gBAAgB,KAAK,QAAQ;AAAA,MAC7B,eAAe,KAAK,KAAK;AAAA,MACzB,UAAU,SAAS;AAAA,MACnB,YAAY,SAAS;AAAA,IAAA;AAAA,EAEzB;AAAA,EAEA,MAAM,iCACJ,kBACA,UACA,oBACA;AACA,UAAM,EAAC,eAAA,IAAkB,MAAM,iBAAiB,uBAAA;AAEhD,QAAI,qBAAqB,gBAAgB;AACvC,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ,WAAW,qBAAqB,gBAAgB;AAC9C,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAEO,MAAM,2BAA2B,MAAM;AAAA,EAC5C,YACE,UACA,oBACA,gBACA;AACA;AAAA,MACE,UAAU,QAAQ,qBAAqB,kBAAkB,iBAAiB,cAAc;AAAA,IAAA;AAAA,EAE5F;AACF;AAEA,SAAS,qBACP,GACA,OACkB;AAClB,SAAO;AAAA,IACL,IAAI;AAAA,MACF,UAAU,EAAE;AAAA,MACZ,IAAI,EAAE;AAAA,IAAA;AAAA,IAER,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,SAAS,MAAM;AAAA,MACf,GAAI,MAAM,UAAU,EAAC,SAAS,MAAM,QAAA,IAAW,CAAA;AAAA,IAAC;AAAA,EAClD;AAEJ;AAGO,SAAS,YAEd,UACA,MAEwB;AACxB,QAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,QAAM,UAAU,gBAAgB,UAAU,IAAI;AAC9C,SAAO,OAAO,YAAY,YAAY,0BAA0B,IAAI,EAAE;AAEtE,MAAI,UAAU,OAAO,GAAG;AAGtB,WAAO,CAAC,IAAI,MAAM,QAAQ,QAAQ,GAAG,EAAC,MAAM,KAAK,IAAG;AAAA,EACtD;AAGA,SAAO;AACT;AAEA,SAAS,gBACP,KACA,MACS;AACT,MAAI,UAAmB;AACvB,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,EAAE,QAAQ,UAAU;AACzE,aAAO;AAAA,IACT;AACA,cAAW,QAAoC,IAAI;AAAA,EACrD;AACA,SAAO;AACT;AAOA,eAAe,8BAGb,YACA,UACA,aACA,IACe;AACf,QAAM,cAAcC,KAAO,SAAS,KAAK,CAAC,GAAG,uBAAuB;AACpE,MAAI,CAAC,YAAY,IAAI;AACnB,OAAG,OAAO,qCAAqC,YAAY,KAAK;AAChE;AAAA,EACF;AACA,QAAM,OAA0B,YAAY;AAG5C,QAAM,WAAW;AAAA,IACf,OAAO,GAAG,UAAU;AAClB,YAAM,MAAM;AAAA,QACV,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,MAAA;AAAA,IAET;AAAA,IACA;AAAA,MACE,gBAAgB,YAAY;AAAA,MAC5B,eAAe,KAAK;AAAA,MACpB,UAAU,KAAK;AAAA,MACf,YAAY;AAAA,IAAA;AAAA,EACd;AAEJ;AAGA,MAAM,iCAAiC,MAAM;AAAA,EAC3C,YAAY,OAAiC,SAAwB;AACnE;AAAA,MACE,UAAU,SACN,wCAAwC,gBAAgB,SAAS,KAAK,CAAC,KACvE,8CAA8C,gBAAgB,SAAS,KAAK,CAAC;AAAA,MACjF;AAAA,IAAA;AAEF,SAAK,OAAO;AAAA,EACd;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"zql-database.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/zql-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAgB,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EACV,aAAa,EACb,KAAK,EACL,UAAU,EACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAqB,KAAK,eAAe,EAAC,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EACV,QAAQ,EACR,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;GAMG;AACH,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,mBAAmB,CAClE,YAAW,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;;IAElE,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,CAAC;gBAG3C,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,OAAO;IAK1E,WAAW,CAAC,CAAC,EACX,QAAQ,EAAE,CACR,EAAE,EAAE,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,EACjD,gBAAgB,EAAE,wBAAwB,KACvC,YAAY,CAAC,CAAC,CAAC,EACpB,gBAAgB,CAAC,EAAE,wBAAwB,GAC1C,OAAO,CAAC,CAAC,CAAC;IAyDb,GAAG,CAAC,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,EAC1D,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EACtC,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;CAGnC"}
1
+ {"version":3,"file":"zql-database.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/zql-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAgB,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EACV,aAAa,EACb,KAAK,EACL,UAAU,EACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAqB,KAAK,eAAe,EAAC,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EACV,QAAQ,EACR,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;GAMG;AACH,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,mBAAmB,CAClE,YAAW,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;;IAElE,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,CAAC;gBAG3C,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,OAAO;IAK1E,WAAW,CAAC,CAAC,EACX,QAAQ,EAAE,CACR,EAAE,EAAE,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,EACjD,gBAAgB,EAAE,wBAAwB,KACvC,YAAY,CAAC,CAAC,CAAC,EACpB,gBAAgB,CAAC,EAAE,wBAAwB,GAC1C,OAAO,CAAC,CAAC,CAAC;IAuEb,GAAG,CAAC,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,EAC1D,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EACtC,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;CAGnC"}
@@ -45,6 +45,15 @@ class ZQLDatabase {
45
45
  )}::text::json)`
46
46
  );
47
47
  await dbTx.query(formatted.text, formatted.values);
48
+ },
49
+ async deleteMutationResults(targetClientGroupID, targetClientID, upToMutationID) {
50
+ const formatted = formatPg(
51
+ sql`DELETE FROM ${sql.ident(upstreamSchema)}."mutations"
52
+ WHERE "clientGroupID" = ${targetClientGroupID}
53
+ AND "clientID" = ${targetClientID}
54
+ AND "mutationID" <= ${upToMutationID}`
55
+ );
56
+ await dbTx.query(formatted.text, formatted.values);
48
57
  }
49
58
  });
50
59
  });
@@ -1 +1 @@
1
- {"version":3,"file":"zql-database.js","sources":["../../../../zero-server/src/zql-database.ts"],"sourcesContent":["import type {MaybePromise} from '../../shared/src/types.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {DBConnection, DBTransaction} from '../../zql/src/mutate/custom.ts';\nimport type {\n HumanReadable,\n Query,\n RunOptions,\n} from '../../zql/src/query/query.ts';\nimport {CRUDMutatorFactory, type TransactionImpl} from './custom.ts';\nimport type {\n Database,\n TransactionProviderHooks,\n TransactionProviderInput,\n} from './process-mutations.ts';\n\n/**\n * Implements a Database for use with PushProcessor that is backed by Postgres.\n *\n * This implementation also implements the same ZQL interfaces for reading and\n * writing data that the Zero client does, so that mutator functions can be\n * shared across client and server.\n */\nexport class ZQLDatabase<TSchema extends Schema, TWrappedTransaction>\n implements Database<TransactionImpl<TSchema, TWrappedTransaction>>\n{\n readonly connection: DBConnection<TWrappedTransaction>;\n readonly #crudFactory: CRUDMutatorFactory<TSchema>;\n\n constructor(connection: DBConnection<TWrappedTransaction>, schema: TSchema) {\n this.connection = connection;\n this.#crudFactory = new CRUDMutatorFactory(schema);\n }\n\n transaction<R>(\n callback: (\n tx: TransactionImpl<TSchema, TWrappedTransaction>,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ): Promise<R> {\n // Icky hack. This is just here to have user not have to do this.\n // These interfaces need to be factored better.\n const {\n upstreamSchema = '',\n clientGroupID = '',\n clientID = '',\n mutationID = 0,\n } = transactionInput ?? {};\n return this.connection.transaction(async dbTx => {\n const zeroTx = await this.#makeServerTransaction(\n dbTx,\n clientID,\n mutationID,\n );\n\n return callback(zeroTx, {\n async updateClientMutationID() {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"`,\n );\n\n const [{lastMutationID}] = (await dbTx.query(\n formatted.text,\n formatted.values,\n )) as {lastMutationID: bigint}[];\n\n return {lastMutationID};\n },\n\n async writeMutationResult(result) {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.mutations\n (\"clientGroupID\", \"clientID\", \"mutationID\", \"result\")\n VALUES (${clientGroupID}, ${result.id.clientID}, ${result.id.id}, ${JSON.stringify(\n result.result,\n )}::text::json)`,\n );\n await dbTx.query(formatted.text, formatted.values);\n },\n });\n });\n }\n\n #makeServerTransaction(\n dbTx: DBTransaction<TWrappedTransaction>,\n clientID: string,\n mutationID: number,\n ) {\n return this.#crudFactory.createTransaction(dbTx, clientID, mutationID);\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.transaction(tx => tx.run(query, options));\n }\n}\n"],"names":[],"mappings":";;AAuBO,MAAM,YAEb;AAAA,EACW;AAAA,EACA;AAAA,EAET,YAAY,YAA+C,QAAiB;AAC1E,SAAK,aAAa;AAClB,SAAK,eAAe,IAAI,mBAAmB,MAAM;AAAA,EACnD;AAAA,EAEA,YACE,UAIA,kBACY;AAGZ,UAAM;AAAA,MACJ,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,IAAA,IACX,oBAAoB,CAAA;AACxB,WAAO,KAAK,WAAW,YAAY,OAAM,SAAQ;AAC/C,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAGF,aAAO,SAAS,QAAQ;AAAA,QACtB,MAAM,yBAAyB;AAC7B,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,kCAErB,aAAa,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA,UAAA;AAMxD,gBAAM,CAAC,EAAC,eAAA,CAAe,IAAK,MAAM,KAAK;AAAA,YACrC,UAAU;AAAA,YACV,UAAU;AAAA,UAAA;AAGZ,iBAAO,EAAC,eAAA;AAAA,QACV;AAAA,QAEA,MAAM,oBAAoB,QAAQ;AAChC,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,0BAE7B,aAAa,KAAK,OAAO,GAAG,QAAQ,KAAK,OAAO,GAAG,EAAE,KAAK,KAAK;AAAA,cACvE,OAAO;AAAA,YAAA,CACR;AAAA,UAAA;AAEP,gBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,QACnD;AAAA,MAAA,CACD;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,uBACE,MACA,UACA,YACA;AACA,WAAO,KAAK,aAAa,kBAAkB,MAAM,UAAU,UAAU;AAAA,EACvE;AAAA,EAEA,IACE,OACA,SACiC;AACjC,WAAO,KAAK,YAAY,CAAA,OAAM,GAAG,IAAI,OAAO,OAAO,CAAC;AAAA,EACtD;AACF;"}
1
+ {"version":3,"file":"zql-database.js","sources":["../../../../zero-server/src/zql-database.ts"],"sourcesContent":["import type {MaybePromise} from '../../shared/src/types.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {DBConnection, DBTransaction} from '../../zql/src/mutate/custom.ts';\nimport type {\n HumanReadable,\n Query,\n RunOptions,\n} from '../../zql/src/query/query.ts';\nimport {CRUDMutatorFactory, type TransactionImpl} from './custom.ts';\nimport type {\n Database,\n TransactionProviderHooks,\n TransactionProviderInput,\n} from './process-mutations.ts';\n\n/**\n * Implements a Database for use with PushProcessor that is backed by Postgres.\n *\n * This implementation also implements the same ZQL interfaces for reading and\n * writing data that the Zero client does, so that mutator functions can be\n * shared across client and server.\n */\nexport class ZQLDatabase<TSchema extends Schema, TWrappedTransaction>\n implements Database<TransactionImpl<TSchema, TWrappedTransaction>>\n{\n readonly connection: DBConnection<TWrappedTransaction>;\n readonly #crudFactory: CRUDMutatorFactory<TSchema>;\n\n constructor(connection: DBConnection<TWrappedTransaction>, schema: TSchema) {\n this.connection = connection;\n this.#crudFactory = new CRUDMutatorFactory(schema);\n }\n\n transaction<R>(\n callback: (\n tx: TransactionImpl<TSchema, TWrappedTransaction>,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ): Promise<R> {\n // Icky hack. This is just here to have user not have to do this.\n // These interfaces need to be factored better.\n const {\n upstreamSchema = '',\n clientGroupID = '',\n clientID = '',\n mutationID = 0,\n } = transactionInput ?? {};\n return this.connection.transaction(async dbTx => {\n const zeroTx = await this.#makeServerTransaction(\n dbTx,\n clientID,\n mutationID,\n );\n\n return callback(zeroTx, {\n async updateClientMutationID() {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"`,\n );\n\n const [{lastMutationID}] = (await dbTx.query(\n formatted.text,\n formatted.values,\n )) as {lastMutationID: bigint}[];\n\n return {lastMutationID};\n },\n\n async writeMutationResult(result) {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.mutations\n (\"clientGroupID\", \"clientID\", \"mutationID\", \"result\")\n VALUES (${clientGroupID}, ${result.id.clientID}, ${result.id.id}, ${JSON.stringify(\n result.result,\n )}::text::json)`,\n );\n await dbTx.query(formatted.text, formatted.values);\n },\n\n async deleteMutationResults(\n targetClientGroupID,\n targetClientID,\n upToMutationID,\n ) {\n const formatted = formatPg(\n sql`DELETE FROM ${sql.ident(upstreamSchema)}.\"mutations\"\n WHERE \"clientGroupID\" = ${targetClientGroupID}\n AND \"clientID\" = ${targetClientID}\n AND \"mutationID\" <= ${upToMutationID}`,\n );\n await dbTx.query(formatted.text, formatted.values);\n },\n });\n });\n }\n\n #makeServerTransaction(\n dbTx: DBTransaction<TWrappedTransaction>,\n clientID: string,\n mutationID: number,\n ) {\n return this.#crudFactory.createTransaction(dbTx, clientID, mutationID);\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.transaction(tx => tx.run(query, options));\n }\n}\n"],"names":[],"mappings":";;AAuBO,MAAM,YAEb;AAAA,EACW;AAAA,EACA;AAAA,EAET,YAAY,YAA+C,QAAiB;AAC1E,SAAK,aAAa;AAClB,SAAK,eAAe,IAAI,mBAAmB,MAAM;AAAA,EACnD;AAAA,EAEA,YACE,UAIA,kBACY;AAGZ,UAAM;AAAA,MACJ,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,IAAA,IACX,oBAAoB,CAAA;AACxB,WAAO,KAAK,WAAW,YAAY,OAAM,SAAQ;AAC/C,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAGF,aAAO,SAAS,QAAQ;AAAA,QACtB,MAAM,yBAAyB;AAC7B,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,kCAErB,aAAa,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA,UAAA;AAMxD,gBAAM,CAAC,EAAC,eAAA,CAAe,IAAK,MAAM,KAAK;AAAA,YACrC,UAAU;AAAA,YACV,UAAU;AAAA,UAAA;AAGZ,iBAAO,EAAC,eAAA;AAAA,QACV;AAAA,QAEA,MAAM,oBAAoB,QAAQ;AAChC,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,0BAE7B,aAAa,KAAK,OAAO,GAAG,QAAQ,KAAK,OAAO,GAAG,EAAE,KAAK,KAAK;AAAA,cACvE,OAAO;AAAA,YAAA,CACR;AAAA,UAAA;AAEP,gBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,QACnD;AAAA,QAEA,MAAM,sBACJ,qBACA,gBACA,gBACA;AACA,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA,0CACb,mBAAmB;AAAA,qCACxB,cAAc;AAAA,wCACX,cAAc;AAAA,UAAA;AAE5C,gBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,QACnD;AAAA,MAAA,CACD;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,uBACE,MACA,UACA,YACA;AACA,WAAO,KAAK,aAAa,kBAAkB,MAAM,UAAU,UAAU;AAAA,EACvE;AAAA,EAEA,IACE,OACA,SACiC;AACjC,WAAO,KAAK,YAAY,CAAA,OAAM,GAAG,IAAI,OAAO,OAAO,CAAC;AAAA,EACtD;AACF;"}
@@ -19,6 +19,7 @@ import "../../zero-protocol/src/custom-queries.js";
19
19
  import "../../zero-protocol/src/client-schema.js";
20
20
  import "../../zero-schema/src/permissions.js";
21
21
  import "../../shared/src/document-visible.js";
22
+ import "../../shared/src/iterables.js";
22
23
  import "../../replicache/src/btree/node.js";
23
24
  import "compare-utf8";
24
25
  import "../../replicache/src/sync/push.js";
@@ -1 +1 @@
1
- {"version":3,"file":"solid-view.js","sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\n\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n this.#setState(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n #onTransactionCommit = () => {\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#setState(prev => [builderRoot, prev[1]]);\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(change, this.#builderRoot);\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change.type) {\n case 'add':\n return {type: 'add', node: materializeNodeRelationships(change.node)};\n case 'remove':\n return {type: 'remove', node: materializeNodeRelationships(change.node)};\n case 'child':\n return {\n type: 'child',\n node: {row: change.node.row},\n child: {\n relationshipName: change.child.relationshipName,\n change: materializeRelationships(change.child.change),\n },\n };\n case 'edit':\n return {\n type: 'edit',\n node: {row: change.node.row},\n oldNode: {row: change.oldNode.row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"solid-view.js","sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\n\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n this.#setState(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n #onTransactionCommit = () => {\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#setState(prev => [builderRoot, prev[1]]);\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(change, this.#builderRoot);\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change.type) {\n case 'add':\n return {type: 'add', node: materializeNodeRelationships(change.node)};\n case 'remove':\n return {type: 'remove', node: materializeNodeRelationships(change.node)};\n case 'child':\n return {\n type: 'child',\n node: {row: change.node.row},\n child: {\n relationshipName: change.child.relationshipName,\n change: materializeRelationships(change.child.change),\n },\n };\n case 'edit':\n return {\n type: 'edit',\n node: {row: change.node.row},\n oldNode: {row: change.oldNode.row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@ import "../../zero-protocol/src/custom-queries.js";
23
23
  import "../../zero-protocol/src/client-schema.js";
24
24
  import "../../zero-schema/src/permissions.js";
25
25
  import "../../shared/src/document-visible.js";
26
+ import "../../shared/src/iterables.js";
26
27
  import "../../replicache/src/btree/node.js";
27
28
  import "../../replicache/src/sync/push.js";
28
29
  import "../../shared/src/valita.js";
@@ -1 +1 @@
1
- {"version":3,"file":"use-query.js","sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type DefaultContext,\n type DefaultSchema,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type Schema,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n const q = createMemo(() => addContextToQuery(querySignal(), zero().context));\n const qi = createMemo(() => asQueryInternals(q()));\n const hash = createMemo(() => qi().hash());\n const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);\n\n const initialTTL = ttl();\n\n const view = createMemo(() => {\n // Depend on hash instead of query to avoid recreating the view when the\n // query object changes but the hash is the same.\n hash();\n refetchKey();\n const untrackedQuery = untrack(q);\n\n const v = zero().materialize(\n untrackedQuery,\n createSolidViewFactory(setState, refetch),\n {\n ttl: initialTTL,\n },\n );\n\n onCleanup(() => v.destroy());\n\n return v;\n });\n\n // Update TTL on existing view when it changes.\n createEffect(\n on(\n ttl,\n currentTTL => {\n view().updateTTL(currentTTL);\n },\n {defer: true},\n ),\n );\n\n return [() => state[0][''] as HumanReadable<TReturn>, () => state[1]];\n}\n\nfunction normalize<T>(options?: T | Accessor<T | undefined>): T | undefined {\n return typeof options === 'function' ? (options as Accessor<T>)() : options;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDO,SAAS,YAQd,aAGA,SACsB;AACtB,SAAO,SAAS,aAAa,OAAO;AACtC;AAEO,SAAS,SAQd,aAGA,SACsB;AACtB,QAAM,CAAC,OAAO,QAAQ,IAAI,YAAmB;AAAA,IAC3C;AAAA,MACE,IAAI;AAAA,IAAA;AAAA,IAEN;AAAA,EAAA,CACD;AACD,QAAM,oBAAoB;AAC1B,QAAM,CAAC,YAAY,aAAa,IAAI,aAAa,iBAAiB;AAElE,QAAM,UAAU,MAAM;AACpB,kBAAc,CAAA,MAAK,IAAI,CAAC;AAAA,EAC1B;AAEA,QAAM,OAAO,QAAA;AACb,QAAM,IAAI,WAAW,MAAM,kBAAkB,eAAe,KAAA,EAAO,OAAO,CAAC;AAC3E,QAAM,KAAK,WAAW,MAAM,iBAAiB,EAAA,CAAG,CAAC;AACjD,QAAM,OAAO,WAAW,MAAM,GAAA,EAAK,MAAM;AACzC,QAAM,MAAM,WAAW,MAAM,UAAU,OAAO,GAAG,OAAO,cAAc;AAEtE,QAAM,aAAa,IAAA;AAEnB,QAAM,OAAO,WAAW,MAAM;AAG5B,SAAA;AACA,eAAA;AACA,UAAM,iBAAiB,QAAQ,CAAC;AAEhC,UAAM,IAAI,OAAO;AAAA,MACf;AAAA,MACA,uBAAuB,UAAU,OAAO;AAAA,MACxC;AAAA,QACE,KAAK;AAAA,MAAA;AAAA,IACP;AAGF,cAAU,MAAM,EAAE,SAAS;AAE3B,WAAO;AAAA,EACT,CAAC;AAGD;AAAA,IACE;AAAA,MACE;AAAA,MACA,CAAA,eAAc;AACZ,aAAA,EAAO,UAAU,UAAU;AAAA,MAC7B;AAAA,MACA,EAAC,OAAO,KAAA;AAAA,IAAI;AAAA,EACd;AAGF,SAAO,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE,GAA6B,MAAM,MAAM,CAAC,CAAC;AACtE;AAEA,SAAS,UAAa,SAAsD;AAC1E,SAAO,OAAO,YAAY,aAAc,QAAA,IAA4B;AACtE;"}
1
+ {"version":3,"file":"use-query.js","sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type DefaultContext,\n type DefaultSchema,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type Schema,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n const q = createMemo(() => addContextToQuery(querySignal(), zero().context));\n const qi = createMemo(() => asQueryInternals(q()));\n const hash = createMemo(() => qi().hash());\n const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);\n\n const initialTTL = ttl();\n\n const view = createMemo(() => {\n // Depend on hash instead of query to avoid recreating the view when the\n // query object changes but the hash is the same.\n hash();\n refetchKey();\n const untrackedQuery = untrack(q);\n\n const v = zero().materialize(\n untrackedQuery,\n createSolidViewFactory(setState, refetch),\n {\n ttl: initialTTL,\n },\n );\n\n onCleanup(() => v.destroy());\n\n return v;\n });\n\n // Update TTL on existing view when it changes.\n createEffect(\n on(\n ttl,\n currentTTL => {\n view().updateTTL(currentTTL);\n },\n {defer: true},\n ),\n );\n\n return [() => state[0][''] as HumanReadable<TReturn>, () => state[1]];\n}\n\nfunction normalize<T>(options?: T | Accessor<T | undefined>): T | undefined {\n return typeof options === 'function' ? (options as Accessor<T>)() : options;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDO,SAAS,YAQd,aAGA,SACsB;AACtB,SAAO,SAAS,aAAa,OAAO;AACtC;AAEO,SAAS,SAQd,aAGA,SACsB;AACtB,QAAM,CAAC,OAAO,QAAQ,IAAI,YAAmB;AAAA,IAC3C;AAAA,MACE,IAAI;AAAA,IAAA;AAAA,IAEN;AAAA,EAAA,CACD;AACD,QAAM,oBAAoB;AAC1B,QAAM,CAAC,YAAY,aAAa,IAAI,aAAa,iBAAiB;AAElE,QAAM,UAAU,MAAM;AACpB,kBAAc,CAAA,MAAK,IAAI,CAAC;AAAA,EAC1B;AAEA,QAAM,OAAO,QAAA;AACb,QAAM,IAAI,WAAW,MAAM,kBAAkB,eAAe,KAAA,EAAO,OAAO,CAAC;AAC3E,QAAM,KAAK,WAAW,MAAM,iBAAiB,EAAA,CAAG,CAAC;AACjD,QAAM,OAAO,WAAW,MAAM,GAAA,EAAK,MAAM;AACzC,QAAM,MAAM,WAAW,MAAM,UAAU,OAAO,GAAG,OAAO,cAAc;AAEtE,QAAM,aAAa,IAAA;AAEnB,QAAM,OAAO,WAAW,MAAM;AAG5B,SAAA;AACA,eAAA;AACA,UAAM,iBAAiB,QAAQ,CAAC;AAEhC,UAAM,IAAI,OAAO;AAAA,MACf;AAAA,MACA,uBAAuB,UAAU,OAAO;AAAA,MACxC;AAAA,QACE,KAAK;AAAA,MAAA;AAAA,IACP;AAGF,cAAU,MAAM,EAAE,SAAS;AAE3B,WAAO;AAAA,EACT,CAAC;AAGD;AAAA,IACE;AAAA,MACE;AAAA,MACA,CAAA,eAAc;AACZ,aAAA,EAAO,UAAU,UAAU;AAAA,MAC7B;AAAA,MACA,EAAC,OAAO,KAAA;AAAA,IAAI;AAAA,EACd;AAGF,SAAO,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE,GAA6B,MAAM,MAAM,CAAC,CAAC;AACtE;AAEA,SAAS,UAAa,SAAsD;AAC1E,SAAO,OAAO,YAAY,aAAc,QAAA,IAA4B;AACtE;"}
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/stream.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpC,wBAAiB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAWpE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAKzD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAE3C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAC1C,GAAG,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,CAMR"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/stream.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpC,wBAAiB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAWpE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAKzD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAGlD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAC1C,GAAG,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,CAMR"}
@@ -5,7 +5,7 @@ function first(stream) {
5
5
  return value;
6
6
  }
7
7
  function consume(stream) {
8
- [...stream];
8
+ for (const _ of stream) ;
9
9
  }
10
10
  export {
11
11
  consume,
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sources":["../../../../../zql/src/ivm/stream.ts"],"sourcesContent":["/**\n * streams are lazy forward-only iterables.\n * Once a stream reaches the end it can't be restarted.\n * They are iterable, not iterator, so that they can be used in for-each,\n * and so that we know when consumer has stopped iterating the stream. This allows us\n * to clean up resources like sql statements.\n */\nexport type Stream<T> = Iterable<T>;\n\nexport function* take<T>(stream: Stream<T>, limit: number): Stream<T> {\n if (limit < 1) {\n return;\n }\n let count = 0;\n for (const v of stream) {\n yield v;\n if (++count === limit) {\n break;\n }\n }\n}\n\nexport function first<T>(stream: Stream<T>): T | undefined {\n const it = stream[Symbol.iterator]();\n const {value} = it.next();\n it.return?.();\n return value;\n}\n\nexport function consume<T>(stream: Stream<T>) {\n [...stream];\n}\n\nexport function drainGenerator<Yield, Return>(\n gen: Generator<Yield, Return, unknown>,\n): Return {\n let result = gen.next();\n while (!result.done) {\n result = gen.next();\n }\n return result.value;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,MAAS,QAAkC;AACzD,QAAM,KAAK,OAAO,OAAO,QAAQ,EAAA;AACjC,QAAM,EAAC,MAAA,IAAS,GAAG,KAAA;AACnB,KAAG,SAAA;AACH,SAAO;AACT;AAEO,SAAS,QAAW,QAAmB;AAC5C,GAAC,GAAG,MAAM;AACZ;"}
1
+ {"version":3,"file":"stream.js","sources":["../../../../../zql/src/ivm/stream.ts"],"sourcesContent":["/**\n * streams are lazy forward-only iterables.\n * Once a stream reaches the end it can't be restarted.\n * They are iterable, not iterator, so that they can be used in for-each,\n * and so that we know when consumer has stopped iterating the stream. This allows us\n * to clean up resources like sql statements.\n */\nexport type Stream<T> = Iterable<T>;\n\nexport function* take<T>(stream: Stream<T>, limit: number): Stream<T> {\n if (limit < 1) {\n return;\n }\n let count = 0;\n for (const v of stream) {\n yield v;\n if (++count === limit) {\n break;\n }\n }\n}\n\nexport function first<T>(stream: Stream<T>): T | undefined {\n const it = stream[Symbol.iterator]();\n const {value} = it.next();\n it.return?.();\n return value;\n}\n\nexport function consume<T>(stream: Stream<T>): void {\n // Required to prevent some minifiers (e.g. Terser) from removing this empty loop\n for (const _ of stream);\n}\n\nexport function drainGenerator<Yield, Return>(\n gen: Generator<Yield, Return, unknown>,\n): Return {\n let result = gen.next();\n while (!result.done) {\n result = gen.next();\n }\n return result.value;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,MAAS,QAAkC;AACzD,QAAM,KAAK,OAAO,OAAO,QAAQ,EAAA;AACjC,QAAM,EAAC,MAAA,IAAS,GAAG,KAAA;AACnB,KAAG,SAAA;AACH,SAAO;AACT;AAEO,SAAS,QAAW,QAAyB;AAElD,aAAW,KAAK,OAAO;AACzB;"}
@@ -5,12 +5,12 @@ function isMutatorDefinition(f) {
5
5
  function defineMutator(validatorOrMutator, mutator) {
6
6
  let validator;
7
7
  let actualMutator;
8
- if (typeof validatorOrMutator === "function") {
9
- validator = void 0;
10
- actualMutator = validatorOrMutator;
11
- } else {
8
+ if ("~standard" in validatorOrMutator) {
12
9
  validator = validatorOrMutator;
13
10
  actualMutator = must(mutator);
11
+ } else {
12
+ validator = void 0;
13
+ actualMutator = validatorOrMutator;
14
14
  }
15
15
  const mutatorDefinition = {
16
16
  "fn": actualMutator,