@noy-db/hub 0.2.0-pre.15 → 0.2.0-pre.16

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 (197) hide show
  1. package/dist/aggregate/index.cjs +106 -10
  2. package/dist/aggregate/index.cjs.map +1 -1
  3. package/dist/aggregate/index.d.cts +2 -2
  4. package/dist/aggregate/index.d.ts +2 -2
  5. package/dist/aggregate/index.js +1 -1
  6. package/dist/attestation/index.cjs.map +1 -1
  7. package/dist/attestation/index.d.cts +3 -3
  8. package/dist/attestation/index.d.ts +3 -3
  9. package/dist/attestation/index.js +4 -4
  10. package/dist/blobs/index.cjs.map +1 -1
  11. package/dist/blobs/index.d.cts +4 -4
  12. package/dist/blobs/index.d.ts +4 -4
  13. package/dist/blobs/index.js +3 -3
  14. package/dist/bundle/index.cjs +181 -46
  15. package/dist/bundle/index.cjs.map +1 -1
  16. package/dist/bundle/index.d.cts +5 -5
  17. package/dist/bundle/index.d.ts +5 -5
  18. package/dist/bundle/index.js +7 -7
  19. package/dist/{chunk-BIYRQQV6.js → chunk-3YWP3WBP.js} +3 -3
  20. package/dist/{chunk-VU7SWWT5.js → chunk-42FEUPZQ.js} +10 -6
  21. package/dist/chunk-42FEUPZQ.js.map +1 -0
  22. package/dist/{chunk-7EFFHEN5.js → chunk-667MB6AH.js} +118 -47
  23. package/dist/chunk-667MB6AH.js.map +1 -0
  24. package/dist/{chunk-A5ZOOZFB.js → chunk-6H2ZUNR7.js} +2 -2
  25. package/dist/{chunk-7HT2MEZ5.js → chunk-7BQ4QWYX.js} +3 -3
  26. package/dist/{chunk-DQU36Q7I.js → chunk-7Z7KSVA5.js} +13 -4
  27. package/dist/chunk-7Z7KSVA5.js.map +1 -0
  28. package/dist/{chunk-WBAYSNUQ.js → chunk-BI6ETQPF.js} +2 -2
  29. package/dist/{chunk-56DJ7JVK.js → chunk-BR3AMFGS.js} +2 -2
  30. package/dist/{chunk-COFPAMX6.js → chunk-DLZ2ONOD.js} +3 -3
  31. package/dist/{chunk-EYVQHAGH.js → chunk-DUREQF5W.js} +2 -2
  32. package/dist/{chunk-PE4AQGFH.js → chunk-E2CDVKMH.js} +3 -3
  33. package/dist/{chunk-GC4V7RU7.js → chunk-F3BPIPLS.js} +1 -1
  34. package/dist/{chunk-GC4V7RU7.js.map → chunk-F3BPIPLS.js.map} +1 -1
  35. package/dist/{chunk-L2FE64BU.js → chunk-FFXM3ZIF.js} +2 -2
  36. package/dist/{chunk-5LQG6ZO2.js → chunk-G4SCICH5.js} +8 -3
  37. package/dist/chunk-G4SCICH5.js.map +1 -0
  38. package/dist/{chunk-WGHU7BLI.js → chunk-GNI5STXQ.js} +2 -2
  39. package/dist/{chunk-C5T5AFWN.js → chunk-HBXJ37ZY.js} +11 -5
  40. package/dist/chunk-HBXJ37ZY.js.map +1 -0
  41. package/dist/{chunk-7PS7EOCF.js → chunk-IXBIFDEW.js} +2 -2
  42. package/dist/{chunk-LX3CB26H.js → chunk-KABJXG2F.js} +2 -2
  43. package/dist/{chunk-3EWXMOK3.js → chunk-L2BNJ6HM.js} +26 -11
  44. package/dist/chunk-L2BNJ6HM.js.map +1 -0
  45. package/dist/{chunk-DKO2QFSA.js → chunk-OB2ZJQ2D.js} +2 -2
  46. package/dist/{chunk-KIP6JLTF.js → chunk-OMAMZKKD.js} +2 -2
  47. package/dist/{chunk-EGD5DXFT.js → chunk-OQSRJG6A.js} +13 -1
  48. package/dist/chunk-OQSRJG6A.js.map +1 -0
  49. package/dist/{chunk-KI6HAJWL.js → chunk-QSUK7YWK.js} +2 -2
  50. package/dist/{chunk-YHPM5D7Y.js → chunk-QVIEAYTP.js} +61 -2
  51. package/dist/chunk-QVIEAYTP.js.map +1 -0
  52. package/dist/{chunk-NSCVNK5K.js → chunk-SCJPI4Z5.js} +3 -3
  53. package/dist/{chunk-NU6Q3FOR.js → chunk-TKIY625R.js} +11 -1
  54. package/dist/{chunk-NU6Q3FOR.js.map → chunk-TKIY625R.js.map} +1 -1
  55. package/dist/{chunk-OHVFWCJP.js → chunk-VLMPU56Q.js} +48 -18
  56. package/dist/chunk-VLMPU56Q.js.map +1 -0
  57. package/dist/{chunk-6AJBSQU4.js → chunk-XL35NSEN.js} +2 -2
  58. package/dist/consent/index.d.cts +4 -4
  59. package/dist/consent/index.d.ts +4 -4
  60. package/dist/derivations/index.cjs +24 -3
  61. package/dist/derivations/index.cjs.map +1 -1
  62. package/dist/derivations/index.d.cts +5 -5
  63. package/dist/derivations/index.d.ts +5 -5
  64. package/dist/derivations/index.js +2 -2
  65. package/dist/{dev-unlock-nVkuRLLe.d.cts → dev-unlock-8XzcD2Z4.d.cts} +1 -1
  66. package/dist/{dev-unlock-iAS8z9jc.d.ts → dev-unlock-DR3upLd1.d.ts} +1 -1
  67. package/dist/{executor-HSSRXDOB.js → executor-AZLS3KBK.js} +4 -4
  68. package/dist/{fanout-sidecar-N6OJX6QR.js → fanout-sidecar-67CMI3UT.js} +2 -2
  69. package/dist/guards/index.cjs +9 -5
  70. package/dist/guards/index.cjs.map +1 -1
  71. package/dist/guards/index.d.cts +5 -5
  72. package/dist/guards/index.d.ts +5 -5
  73. package/dist/guards/index.js +1 -1
  74. package/dist/{hash-DHOnRarj.d.ts → hash-CDjye9KV.d.ts} +1 -1
  75. package/dist/{hash-Cv6byZs7.d.cts → hash-DuQ88_5W.d.cts} +1 -1
  76. package/dist/history/index.cjs.map +1 -1
  77. package/dist/history/index.d.cts +5 -5
  78. package/dist/history/index.d.ts +5 -5
  79. package/dist/history/index.js +2 -2
  80. package/dist/i18n/index.cjs.map +1 -1
  81. package/dist/i18n/index.d.cts +4 -4
  82. package/dist/i18n/index.d.ts +4 -4
  83. package/dist/i18n/index.js +3 -3
  84. package/dist/{immutable-guard-yBEOYmif.d.cts → immutable-guard-CRPvu24K.d.cts} +16 -1
  85. package/dist/{immutable-guard-BehB1YGB.d.ts → immutable-guard-Dov3WvwF.d.ts} +16 -1
  86. package/dist/{index-D95VK1Qy.d.cts → index-C8Bk3-VF.d.cts} +1 -1
  87. package/dist/{index-XNB2r6bX.d.ts → index-nP99bXLg.d.ts} +1 -1
  88. package/dist/index.cjs +273 -52
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +13 -12
  91. package/dist/index.d.ts +13 -12
  92. package/dist/index.js +27 -25
  93. package/dist/index.js.map +1 -1
  94. package/dist/{issue-ADVS4OVP.js → issue-RZP3VI6O.js} +4 -4
  95. package/dist/{ledger-CWSE3BLF.js → ledger-A3LL253R.js} +3 -3
  96. package/dist/materialized-views/index.cjs +407 -5
  97. package/dist/materialized-views/index.cjs.map +1 -1
  98. package/dist/materialized-views/index.d.cts +5 -5
  99. package/dist/materialized-views/index.d.ts +5 -5
  100. package/dist/materialized-views/index.js +5 -5
  101. package/dist/noydb-WCMY2ZOW.js +35 -0
  102. package/dist/overlay-views/index.cjs +47 -17
  103. package/dist/overlay-views/index.cjs.map +1 -1
  104. package/dist/overlay-views/index.d.cts +26 -8
  105. package/dist/overlay-views/index.d.ts +26 -8
  106. package/dist/overlay-views/index.js +1 -1
  107. package/dist/periods/index.cjs.map +1 -1
  108. package/dist/periods/index.d.cts +4 -4
  109. package/dist/periods/index.d.ts +4 -4
  110. package/dist/periods/index.js +3 -3
  111. package/dist/{public-envelope-SYHEYQ3X.js → public-envelope-YP2UWMLG.js} +3 -3
  112. package/dist/query/index.cjs +24 -10
  113. package/dist/query/index.cjs.map +1 -1
  114. package/dist/query/index.d.cts +2 -2
  115. package/dist/query/index.d.ts +2 -2
  116. package/dist/query/index.js +2 -2
  117. package/dist/{registry-XGLNADIE.js → registry-EB6SISTA.js} +2 -2
  118. package/dist/{registry-DK5YWAAA.js → registry-UTA4CLQS.js} +2 -2
  119. package/dist/{revoke-ZDFKMR5E.js → revoke-HNMQZSCL.js} +4 -4
  120. package/dist/session/index.d.cts +5 -5
  121. package/dist/session/index.d.ts +5 -5
  122. package/dist/shadow/index.d.cts +4 -4
  123. package/dist/shadow/index.d.ts +4 -4
  124. package/dist/{signer-P5D7Y72U.js → signer-DCMNKXSF.js} +3 -3
  125. package/dist/snapshots/index.d.cts +4 -4
  126. package/dist/snapshots/index.d.ts +4 -4
  127. package/dist/snapshots/index.js +3 -3
  128. package/dist/{stale-JH67FU57.js → stale-W5PQTRYH.js} +2 -2
  129. package/dist/store/index.d.cts +4 -4
  130. package/dist/store/index.d.ts +4 -4
  131. package/dist/{strategy-CbneC7bS.d.ts → strategy-BtW8fAjz.d.cts} +1 -1
  132. package/dist/{strategy-CbneC7bS.d.cts → strategy-BtW8fAjz.d.ts} +1 -1
  133. package/dist/sync/index.cjs.map +1 -1
  134. package/dist/sync/index.d.cts +3 -3
  135. package/dist/sync/index.d.ts +3 -3
  136. package/dist/sync/index.js +2 -2
  137. package/dist/team/index.cjs.map +1 -1
  138. package/dist/team/index.d.cts +4 -4
  139. package/dist/team/index.d.ts +4 -4
  140. package/dist/team/index.js +5 -5
  141. package/dist/tx/index.cjs +66 -3
  142. package/dist/tx/index.cjs.map +1 -1
  143. package/dist/tx/index.d.cts +22 -6
  144. package/dist/tx/index.d.ts +22 -6
  145. package/dist/tx/index.js +7 -3
  146. package/dist/tx/index.js.map +1 -1
  147. package/dist/{types-BpPV5uyy.d.cts → types-Bze6vkwm.d.cts} +371 -139
  148. package/dist/{types-4t1-tWS4.d.ts → types-DrmBTscX.d.ts} +371 -139
  149. package/dist/{ulid-DAfenvFd.d.ts → ulid-DbBVrNSt.d.ts} +1 -1
  150. package/dist/{ulid-CiPrpGqm.d.cts → ulid-DfZlAh0u.d.cts} +1 -1
  151. package/dist/{vault-group-KOM7QRJG.js → vault-group-DX2HFQMX.js} +2 -2
  152. package/dist/{with-derivation-DBqJB3dQ.d.cts → with-derivation-CCqAchD5.d.cts} +1 -1
  153. package/dist/{with-derivation-OK9M2sJE.d.ts → with-derivation-_lySGdlm.d.ts} +1 -1
  154. package/dist/{with-materialized-view-NzuxYPDF.d.cts → with-materialized-view--4PsvMDu.d.cts} +1 -1
  155. package/dist/{with-materialized-view-Dt-ufPWQ.d.ts → with-materialized-view-QT1Tp7NO.d.ts} +1 -1
  156. package/dist/{with-overlayed-view-eDvMs6LO.d.ts → with-overlayed-view-BEXfpzSb.d.ts} +1 -1
  157. package/dist/{with-overlayed-view-CC0_ocy-.d.cts → with-overlayed-view-DlH5qmeB.d.cts} +1 -1
  158. package/package.json +3 -3
  159. package/dist/chunk-3EWXMOK3.js.map +0 -1
  160. package/dist/chunk-5LQG6ZO2.js.map +0 -1
  161. package/dist/chunk-7EFFHEN5.js.map +0 -1
  162. package/dist/chunk-C5T5AFWN.js.map +0 -1
  163. package/dist/chunk-DQU36Q7I.js.map +0 -1
  164. package/dist/chunk-EGD5DXFT.js.map +0 -1
  165. package/dist/chunk-OHVFWCJP.js.map +0 -1
  166. package/dist/chunk-VU7SWWT5.js.map +0 -1
  167. package/dist/chunk-YHPM5D7Y.js.map +0 -1
  168. package/dist/noydb-GZGFBA4E.js +0 -35
  169. /package/dist/{chunk-BIYRQQV6.js.map → chunk-3YWP3WBP.js.map} +0 -0
  170. /package/dist/{chunk-A5ZOOZFB.js.map → chunk-6H2ZUNR7.js.map} +0 -0
  171. /package/dist/{chunk-7HT2MEZ5.js.map → chunk-7BQ4QWYX.js.map} +0 -0
  172. /package/dist/{chunk-WBAYSNUQ.js.map → chunk-BI6ETQPF.js.map} +0 -0
  173. /package/dist/{chunk-56DJ7JVK.js.map → chunk-BR3AMFGS.js.map} +0 -0
  174. /package/dist/{chunk-COFPAMX6.js.map → chunk-DLZ2ONOD.js.map} +0 -0
  175. /package/dist/{chunk-EYVQHAGH.js.map → chunk-DUREQF5W.js.map} +0 -0
  176. /package/dist/{chunk-PE4AQGFH.js.map → chunk-E2CDVKMH.js.map} +0 -0
  177. /package/dist/{chunk-L2FE64BU.js.map → chunk-FFXM3ZIF.js.map} +0 -0
  178. /package/dist/{chunk-WGHU7BLI.js.map → chunk-GNI5STXQ.js.map} +0 -0
  179. /package/dist/{chunk-7PS7EOCF.js.map → chunk-IXBIFDEW.js.map} +0 -0
  180. /package/dist/{chunk-LX3CB26H.js.map → chunk-KABJXG2F.js.map} +0 -0
  181. /package/dist/{chunk-DKO2QFSA.js.map → chunk-OB2ZJQ2D.js.map} +0 -0
  182. /package/dist/{chunk-KIP6JLTF.js.map → chunk-OMAMZKKD.js.map} +0 -0
  183. /package/dist/{chunk-KI6HAJWL.js.map → chunk-QSUK7YWK.js.map} +0 -0
  184. /package/dist/{chunk-NSCVNK5K.js.map → chunk-SCJPI4Z5.js.map} +0 -0
  185. /package/dist/{chunk-6AJBSQU4.js.map → chunk-XL35NSEN.js.map} +0 -0
  186. /package/dist/{executor-HSSRXDOB.js.map → executor-AZLS3KBK.js.map} +0 -0
  187. /package/dist/{fanout-sidecar-N6OJX6QR.js.map → fanout-sidecar-67CMI3UT.js.map} +0 -0
  188. /package/dist/{issue-ADVS4OVP.js.map → issue-RZP3VI6O.js.map} +0 -0
  189. /package/dist/{ledger-CWSE3BLF.js.map → ledger-A3LL253R.js.map} +0 -0
  190. /package/dist/{noydb-GZGFBA4E.js.map → noydb-WCMY2ZOW.js.map} +0 -0
  191. /package/dist/{public-envelope-SYHEYQ3X.js.map → public-envelope-YP2UWMLG.js.map} +0 -0
  192. /package/dist/{registry-DK5YWAAA.js.map → registry-EB6SISTA.js.map} +0 -0
  193. /package/dist/{registry-XGLNADIE.js.map → registry-UTA4CLQS.js.map} +0 -0
  194. /package/dist/{revoke-ZDFKMR5E.js.map → revoke-HNMQZSCL.js.map} +0 -0
  195. /package/dist/{signer-P5D7Y72U.js.map → signer-DCMNKXSF.js.map} +0 -0
  196. /package/dist/{stale-JH67FU57.js.map → stale-W5PQTRYH.js.map} +0 -0
  197. /package/dist/{vault-group-KOM7QRJG.js.map → vault-group-DX2HFQMX.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/materialized-views/executor.ts"],"sourcesContent":["import type { Collection } from '../collection.js'\nimport type { TxContext } from '../tx/transaction.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport { MaterializedViewTooLargeError } from '../errors.js'\nimport type { MaterializedFromMeta, MVQueryContext, MaterializedViewStrategy } from './types.js'\nimport type { RegisteredMV } from './registry.js'\nimport { wrapDbWithPredicates } from './registry.js'\nimport { groupAndReduce } from '../aggregate/groupby.js'\nimport { canonicalGroupKey } from '../aggregate/canonical-key.js'\n\n/**\n * Accessor shape passed in from the owning Vault. Mirrors v1's\n * `DerivationStaleAccessor` — provides the per-collection resolver\n * and the active TxContext so refresh writes/tombstones register on\n * `_executed` for rollback symmetry.\n */\nexport interface MVExecutorAccessor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n /**\n * Vault-shaped accessor passed to the MV's `query()` callback at\n * each refresh. Same instance the registry used at registration\n * time; threading through the executor lets the refresh path\n * re-evaluate the closure against the live vault state.\n */\n getQueryContext(): MVQueryContext\n}\n\nexport interface RefreshResult {\n /** Rows newly written / overwritten. */\n written: number\n /** Rows tombstoned via `_internalDelete` (only when `onEmpty: 'delete'`). */\n deleted: number\n /** Failed row writes (non-strict mode). */\n failed: number\n}\n\n/** Default cost ceiling — overridable per-MV via `spec.maxRows`. */\nconst DEFAULT_MAX_ROWS = 100_000\n\n/**\n * Materialize a query terminal that may be a `Query<T>` (call\n * `.toArray()`), an `Aggregation<R>` (call `.run()` returning a\n * single object — wrap as a one-row array), or a `GroupedAggregation<R>`\n * (call `.run()` returning an array of grouped rows). Branches on\n * available terminal at runtime — no type-discrimination at registration.\n */\nasync function materializeQueryResult(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n q: any,\n mvName: string,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n if (typeof q?.toArray === 'function') {\n // Query<T> — non-aggregate path. `.toArray()` returns Promise<T[]>.\n return await q.toArray()\n }\n if (typeof q?.run === 'function') {\n // Aggregation<R> or GroupedAggregation<R>. `.run()` is synchronous\n // and returns either a single object (Aggregation) or an array of\n // rows (GroupedAggregation). Promise.resolve() normalizes both\n // sync and async (future) variants.\n const result: unknown = await Promise.resolve(q.run())\n if (Array.isArray(result)) {\n return result as ReadonlyArray<Record<string, unknown>>\n }\n // Single-aggregate result — wrap as one-row array. The consumer's\n // `rowKey()` should return a stable identity (often a literal\n // constant like `'total'`) since there's only one row.\n return [result as Record<string, unknown>]\n }\n throw new Error(\n `MV \"${mvName}\": query() must return a Query<T>, Aggregation, or GroupedAggregation. ` +\n `Got something without a .toArray() or .run() terminal.`,\n )\n}\n\n/**\n * Materialize a UNION-form MV: read every arm's source\n * collection, apply each arm's `map` to project rows into the unified\n * MV row shape, concatenate the mapped streams, then optionally run\n * `groupBy` + `aggregate` over the result.\n *\n * Modes (driven by `spec.groupBy` / `spec.aggregate`):\n *\n * - No `groupBy` → return the concatenated mapped rows unchanged.\n * - `groupBy` without `aggregate` → dedupe by composite group key,\n * keep the first row seen per key (later arms don't overwrite\n * earlier arms — Map insertion order rules).\n * - `groupBy` + `aggregate` → delegate to the shared `groupAndReduce`\n * pipeline used by `Query.groupBy().aggregate()`.\n *\n * Per-arm `map` is the schema-unification boundary; the strategy's\n * `TRow` type parameter enforces that every arm projects into the\n * same shape at compile time.\n *\n * @internal\n */\nasync function materializeUnionResult<TRow extends Record<string, unknown>>(\n spec: MaterializedViewStrategy<TRow>,\n db: MVQueryContext,\n): Promise<ReadonlyArray<Record<string, unknown>>> {\n const unified: TRow[] = []\n for (const arm of spec.unionSources!) {\n const coll = db.collection<Record<string, unknown>>(arm.collection)\n const sourceRows = coll.query().toArray()\n for (const r of sourceRows) {\n const mapped = arm.map(r)\n // null / undefined means \"omit this source row\" — skip without\n // pushing so groupBy/aggregate never see a null entry (#297).\n if (mapped == null) continue\n unified.push(mapped)\n }\n }\n\n if (!spec.groupBy) return unified\n\n const groupFields: readonly string[] =\n typeof spec.groupBy === 'string' ? [spec.groupBy] : spec.groupBy\n\n // groupBy without aggregate — dedupe by composite key, keep first\n // seen row per key. Useful for cross-arm uniqueness (e.g. unify two\n // sibling collections, keeping one row per natural key).\n if (!spec.aggregate) {\n const seen = new Map<string, TRow>()\n for (const row of unified) {\n const k = canonicalGroupKey(groupFields, row as Record<string, unknown>)\n if (!seen.has(k)) seen.set(k, row)\n }\n return [...seen.values()]\n }\n\n // groupBy + aggregate — delegate to the shared pipeline used by\n // `Query.groupBy().aggregate()`. Result rows carry each grouped\n // field in declaration order followed by the spec's reducer outputs.\n return groupAndReduce<Record<string, unknown>>(unified, groupFields, spec.aggregate)\n}\n\n/**\n * Run an MV's `query()` and write the result rows to the output\n * collection. Same-DEK encryption: routes through the standard\n * `Collection.put` pipeline, so the output collection's DEK is what\n * gets used (matches the v2 spec's \"same DEK as the left-most source\"\n * invariant — `Collection.put` looks up the DEK by collection name,\n * and the output collection IS the MV's owned collection).\n *\n * Stamps `_materializedFrom` onto every emitted row.\n *\n * **Tombstoning:** when `spec.onEmpty: 'delete'` (default), rows\n * that existed in a prior refresh but no longer appear in the new\n * materialized result are deleted via `Collection._internalDelete` —\n * the housekeeping bypass primitive prevents user\n * `onDelete` guards on the output collection from firing on these\n * system-internal deletes. `onEmpty: 'keep'` opts out (rows from\n * prior refreshes linger even when the new result lacks them).\n *\n * **Cost ceiling:** if the materialized row count exceeds\n * `spec.maxRows` (default 100k), throws `MaterializedViewTooLargeError`\n * before any writes hit the store — so strict-mode rollback is\n * clean.\n *\n * **Strict mode:** `spec.strict === true` re-throws on any\n * row-write failure; the active TxContext registration means the\n * source-write rolls back atomically via `revertExecuted`.\n *\n * @internal\n */\nexport const MaterializedViewExecutor = {\n async refresh(\n reg: RegisteredMV,\n accessor: MVExecutorAccessor,\n ): Promise<RefreshResult> {\n const spec = reg.spec\n const outputColl = accessor.getCollection(reg.outputCollection)\n const maxRows = spec.maxRows ?? DEFAULT_MAX_ROWS\n const onEmpty = spec.onEmpty ?? 'delete'\n const strict = spec.strict ?? false\n\n // 1. Materialize the query (branches on terminal shape). If the\n // MV declared predicates, wrap the query context the same way\n // the registry did at registration time so `.wherePredicate()`\n // calls resolve to the registered functions.\n const baseCtx = accessor.getQueryContext()\n const ctxForQuery: MVQueryContext = spec.predicates\n ? wrapDbWithPredicates(baseCtx, spec.predicates)\n : baseCtx\n // UNION-form strategies: read every arm, map to the unified\n // row shape, concatenate, then optionally groupBy + aggregate. The\n // single-source `query()` path is untouched.\n let rows: ReadonlyArray<Record<string, unknown>>\n if (spec.unionSources) {\n rows = await materializeUnionResult(spec, ctxForQuery)\n } else {\n const q = spec.query!(ctxForQuery)\n rows = await materializeQueryResult(q, spec.name)\n }\n\n // 2. Cost ceiling check BEFORE any writes — keeps the rollback\n // clean if the source-write is wrapped in a transaction.\n if (rows.length > maxRows) {\n throw new MaterializedViewTooLargeError(spec.name, rows.length, maxRows)\n }\n\n const txCtx = accessor.getActiveTxContext()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const adapter = (outputColl as any).adapter as {\n get(v: string, c: string, i: string): Promise<EncryptedEnvelope | null>\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const vaultName = (outputColl as any).vault as string\n\n // 3. Compute the post-refresh id set so we can diff against the\n // prior-emitted id set for tombstoning (when onEmpty === 'delete').\n const newIds = new Set<string>()\n const enrichedRows: Array<{ id: string; record: Record<string, unknown> }> = []\n for (const row of rows) {\n const id = spec.rowKey(row)\n newIds.add(id)\n const meta: MaterializedFromMeta = {\n mvName: spec.name,\n queryHash: reg.queryHash,\n sourceVersions: {},\n materializedAt: new Date().toISOString(),\n }\n enrichedRows.push({ id, record: { ...row, _materializedFrom: meta } })\n }\n\n // 4. Write the new rows.\n let written = 0\n let failed = 0\n for (const { id, record } of enrichedRows) {\n try {\n if (txCtx !== null) {\n const prior = await adapter.get(vaultName, reg.outputCollection, id)\n txCtx._executed.push({\n op: { type: 'put', vaultName, collectionName: reg.outputCollection, id },\n priorEnvelope: prior,\n })\n }\n await outputColl.put(id, record)\n written++\n } catch (err) {\n failed++\n if (strict) throw err\n \n console.warn(`[mv] \"${spec.name}\" row write failed:`, err)\n }\n }\n\n // 5. Tombstone rows that existed before but don't appear now.\n // `onEmpty: 'keep'` skips this pass entirely. Uses\n // `_internalDelete` so a user-registered `onDelete` on the\n // output collection does NOT fire on housekeeping (composition fix).\n let deleted = 0\n if (onEmpty === 'delete') {\n const priorIds = await listOutputIds(outputColl)\n for (const priorId of priorIds) {\n if (newIds.has(priorId)) continue\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const outAny = outputColl as any\n if (typeof outAny._internalDelete === 'function') {\n await outAny._internalDelete(priorId, txCtx)\n deleted++\n } else {\n // Defensive fallback — should never hit in real flow since\n // every Collection has `_internalDelete`.\n await outputColl.delete(priorId)\n deleted++\n }\n } catch (err) {\n failed++\n if (strict) throw err\n \n console.warn(`[mv] \"${spec.name}\" tombstone failed for id=\"${priorId}\":`, err)\n }\n }\n }\n\n return { written, deleted, failed }\n },\n}\n\n/**\n * List ids currently present in the MV's output collection via the\n * adapter directly (avoids triggering the lazy resolve-on-read path\n * we're INSIDE). Returns an empty array if the collection doesn't\n * exist or the adapter doesn't surface a list method.\n *\n * @internal\n */\nasync function listOutputIds(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n outputColl: Collection<any>,\n): Promise<string[]> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cAny = outputColl as any\n const adapter = cAny.adapter as { list?: (v: string, c: string) => Promise<readonly string[]> }\n const vault = cAny.vault as string\n const name = cAny.name as string\n if (typeof adapter?.list !== 'function') return []\n try {\n const ids = await adapter.list(vault, name)\n return [...ids]\n } catch {\n return []\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/derivations/strategy-hash.ts","../src/derivations/registry.ts"],"sourcesContent":["/**\n * Deterministic hash of a derivation strategy's \"shape\": source\n * collection, output keys, derive function source. Used to detect\n * strategy drift: a record whose `_derivedFrom.strategyHash` doesn't\n * match the current strategy is considered stale.\n *\n * Web Crypto SHA-256 — no extra deps.\n */\nexport async function computeStrategyHash(\n source: string,\n outputKeys: readonly string[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n derive: (...args: any[]) => any,\n): Promise<string> {\n const canonical = JSON.stringify({\n source,\n outputs: [...outputKeys].sort(),\n derive: derive.toString(),\n })\n const bytes = new TextEncoder().encode(canonical)\n const digest = await crypto.subtle.digest('SHA-256', bytes)\n return Array.from(new Uint8Array(digest))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","import { DerivationCycleError } from '../errors.js'\nimport { computeStrategyHash } from './strategy-hash.js'\nimport type { DerivationStrategy } from './types.js'\n\ninterface RegisteredStrategy {\n // Type-erased to allow the registry to hold heterogeneous strategies.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n spec: DerivationStrategy<any, any>\n strategyHash: string\n}\n\n/**\n * Vault-internal registry of derivation strategies. Owned by `Vault`;\n * not exported.\n *\n * @internal\n */\nexport class DerivationRegistry {\n private readonly _bySource = new Map<string, RegisteredStrategy[]>()\n private readonly _byOutput = new Map<string, RegisteredStrategy[]>()\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async register(spec: DerivationStrategy<any, any>): Promise<void> {\n const outputKeys = Object.keys(spec.outputs)\n const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive)\n const reg: RegisteredStrategy = { spec, strategyHash }\n\n const fromSource = this._bySource.get(spec.source)\n if (fromSource) fromSource.push(reg)\n else this._bySource.set(spec.source, [reg])\n\n for (const key of outputKeys) {\n const output = spec.outputs[key]\n if (!output) continue\n const outputCollection = output.collection\n const arr = this._byOutput.get(outputCollection)\n if (arr) arr.push(reg)\n else this._byOutput.set(outputCollection, [reg])\n }\n }\n\n strategiesForSource(source: string): ReadonlyArray<RegisteredStrategy> {\n return this._bySource.get(source) ?? []\n }\n\n strategiesProducingOutput(collection: string): ReadonlyArray<RegisteredStrategy> {\n return this._byOutput.get(collection) ?? []\n }\n\n /**\n * All registered strategies as a flat, deduplicated array.\n * Each strategy is indexed once per source (not once per output key),\n * so iterating `_bySource.values()` naturally yields each strategy\n * exactly once per source — deduplication is handled by flattening\n * the per-source arrays and collecting into a Set by identity.\n *\n * Used by `dumpSchema()` / `describeDerivations()` in the introspection\n * walker to populate the derivations map.\n */\n all(): ReadonlyArray<RegisteredStrategy> {\n const seen = new Set<RegisteredStrategy>()\n for (const strategies of this._bySource.values()) {\n for (const s of strategies) seen.add(s)\n }\n return [...seen]\n }\n\n /**\n * Cycle detection over the source → output → … graph. Call after all\n * `register()` calls complete (i.e. at vault open). Throws\n * `DerivationCycleError` on the first cycle found.\n */\n validate(): void {\n const visited = new Set<string>()\n const stack: string[] = []\n\n const visit = (node: string): void => {\n if (stack.includes(node)) {\n const cycle = stack.slice(stack.indexOf(node)).concat(node)\n throw new DerivationCycleError(cycle)\n }\n if (visited.has(node)) return\n stack.push(node)\n const strategies = this._bySource.get(node)\n if (strategies) {\n for (const s of strategies) {\n for (const key of Object.keys(s.spec.outputs)) {\n const output = s.spec.outputs[key]\n if (!output) continue\n visit(output.collection)\n }\n }\n }\n stack.pop()\n visited.add(node)\n }\n\n for (const src of this._bySource.keys()) visit(src)\n }\n}\n"],"mappings":";;;;;AAQA,eAAsB,oBACpB,QACA,YAEA,QACiB;AACjB,QAAM,YAAY,KAAK,UAAU;AAAA,IAC/B;AAAA,IACA,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK;AAAA,IAC9B,QAAQ,OAAO,SAAS;AAAA,EAC1B,CAAC;AACD,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,SAAS;AAChD,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,SAAO,MAAM,KAAK,IAAI,WAAW,MAAM,CAAC,EACrC,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACxC,KAAK,EAAE;AACZ;;;ACPO,IAAM,qBAAN,MAAyB;AAAA,EACb,YAAY,oBAAI,IAAkC;AAAA,EAClD,YAAY,oBAAI,IAAkC;AAAA;AAAA,EAGnE,MAAM,SAAS,MAAmD;AAChE,UAAM,aAAa,OAAO,KAAK,KAAK,OAAO;AAC3C,UAAM,eAAe,MAAM,oBAAoB,KAAK,QAAQ,YAAY,KAAK,MAAM;AACnF,UAAM,MAA0B,EAAE,MAAM,aAAa;AAErD,UAAM,aAAa,KAAK,UAAU,IAAI,KAAK,MAAM;AACjD,QAAI,WAAY,YAAW,KAAK,GAAG;AAAA,QAC9B,MAAK,UAAU,IAAI,KAAK,QAAQ,CAAC,GAAG,CAAC;AAE1C,eAAW,OAAO,YAAY;AAC5B,YAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,UAAI,CAAC,OAAQ;AACb,YAAM,mBAAmB,OAAO;AAChC,YAAM,MAAM,KAAK,UAAU,IAAI,gBAAgB;AAC/C,UAAI,IAAK,KAAI,KAAK,GAAG;AAAA,UAChB,MAAK,UAAU,IAAI,kBAAkB,CAAC,GAAG,CAAC;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,oBAAoB,QAAmD;AACrE,WAAO,KAAK,UAAU,IAAI,MAAM,KAAK,CAAC;AAAA,EACxC;AAAA,EAEA,0BAA0B,YAAuD;AAC/E,WAAO,KAAK,UAAU,IAAI,UAAU,KAAK,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAyC;AACvC,UAAM,OAAO,oBAAI,IAAwB;AACzC,eAAW,cAAc,KAAK,UAAU,OAAO,GAAG;AAChD,iBAAW,KAAK,WAAY,MAAK,IAAI,CAAC;AAAA,IACxC;AACA,WAAO,CAAC,GAAG,IAAI;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAiB;AACf,UAAM,UAAU,oBAAI,IAAY;AAChC,UAAM,QAAkB,CAAC;AAEzB,UAAM,QAAQ,CAAC,SAAuB;AACpC,UAAI,MAAM,SAAS,IAAI,GAAG;AACxB,cAAM,QAAQ,MAAM,MAAM,MAAM,QAAQ,IAAI,CAAC,EAAE,OAAO,IAAI;AAC1D,cAAM,IAAI,qBAAqB,KAAK;AAAA,MACtC;AACA,UAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAM,KAAK,IAAI;AACf,YAAM,aAAa,KAAK,UAAU,IAAI,IAAI;AAC1C,UAAI,YAAY;AACd,mBAAW,KAAK,YAAY;AAC1B,qBAAW,OAAO,OAAO,KAAK,EAAE,KAAK,OAAO,GAAG;AAC7C,kBAAM,SAAS,EAAE,KAAK,QAAQ,GAAG;AACjC,gBAAI,CAAC,OAAQ;AACb,kBAAM,OAAO,UAAU;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AACA,YAAM,IAAI;AACV,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,eAAW,OAAO,KAAK,UAAU,KAAK,EAAG,OAAM,GAAG;AAAA,EACpD;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/derivations/with-derivation.ts"],"sourcesContent":["import { ValidationError } from '../errors.js'\nimport type { DerivationStrategy, DerivationStrategyHandle } from './types.js'\n\n/**\n * Register a deterministic derivation: one source collection → one or\n * more typed outputs, computed by the user's `derive` function on\n * plaintext after DEK unwrap. Outputs are encrypted with the same DEK\n * as the source and written via the standard `Collection.put` path.\n *\n * See docs/superpowers/specs/2026-05-01-dim14-derivation-v1-design.md.\n */\nexport function withDerivation<\n TSource extends Record<string, unknown>,\n TOutputs extends Record<string, Record<string, unknown>>,\n>(spec: DerivationStrategy<TSource, TOutputs>): DerivationStrategyHandle {\n if (!spec.source || spec.source.length === 0) {\n throw new ValidationError('withDerivation: source collection name is required')\n }\n if (!spec.outputs || Object.keys(spec.outputs).length === 0) {\n throw new ValidationError('withDerivation: outputs map must declare at least one output')\n }\n if (spec.deterministic !== true) {\n throw new ValidationError('withDerivation: v1 only supports deterministic derivations')\n }\n if (typeof spec.derive !== 'function') {\n throw new ValidationError('withDerivation: derive must be a function')\n }\n\n // Validate array-shape outputs.\n const lifecycleMode = typeof spec.lifecycle === 'string' ? spec.lifecycle : spec.lifecycle.mode\n for (const [outputKey, outputSpec] of Object.entries(spec.outputs)) {\n if (outputSpec.shape === 'array') {\n if (lifecycleMode !== 'eager') {\n throw new ValidationError(\n `withDerivation: shape 'array' supports lifecycle 'eager' only in this release `\n + `Output \"${outputKey}\" declared lifecycle '${lifecycleMode}'. `\n + 'Switch to `lifecycle: \"eager\"` or use shape: \"record\".',\n )\n }\n if (typeof outputSpec.key !== 'function') {\n throw new ValidationError(\n `withDerivation: shape 'array' output \"${outputKey}\" requires \\`key: (out) => string\\`.`,\n )\n }\n if (outputSpec.maxFanout !== undefined) {\n if (!Number.isInteger(outputSpec.maxFanout) || outputSpec.maxFanout < 1) {\n throw new ValidationError(\n `withDerivation: maxFanout for output \"${outputKey}\" must be a positive integer `\n + `(got ${String(outputSpec.maxFanout)}).`,\n )\n }\n }\n }\n }\n\n return {\n __noydb_strategy: 'derivation',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n spec: spec as DerivationStrategy<any, any>,\n }\n}\n"],"mappings":";;;;;AAWO,SAAS,eAGd,MAAuE;AACvE,MAAI,CAAC,KAAK,UAAU,KAAK,OAAO,WAAW,GAAG;AAC5C,UAAM,IAAI,gBAAgB,oDAAoD;AAAA,EAChF;AACA,MAAI,CAAC,KAAK,WAAW,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW,GAAG;AAC3D,UAAM,IAAI,gBAAgB,8DAA8D;AAAA,EAC1F;AACA,MAAI,KAAK,kBAAkB,MAAM;AAC/B,UAAM,IAAI,gBAAgB,4DAA4D;AAAA,EACxF;AACA,MAAI,OAAO,KAAK,WAAW,YAAY;AACrC,UAAM,IAAI,gBAAgB,2CAA2C;AAAA,EACvE;AAGA,QAAM,gBAAgB,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,KAAK,UAAU;AAC3F,aAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,KAAK,OAAO,GAAG;AAClE,QAAI,WAAW,UAAU,SAAS;AAChC,UAAI,kBAAkB,SAAS;AAC7B,cAAM,IAAI;AAAA,UACR,yFACa,SAAS,yBAAyB,aAAa;AAAA,QAE9D;AAAA,MACF;AACA,UAAI,OAAO,WAAW,QAAQ,YAAY;AACxC,cAAM,IAAI;AAAA,UACR,yCAAyC,SAAS;AAAA,QACpD;AAAA,MACF;AACA,UAAI,WAAW,cAAc,QAAW;AACtC,YAAI,CAAC,OAAO,UAAU,WAAW,SAAS,KAAK,WAAW,YAAY,GAAG;AACvE,gBAAM,IAAI;AAAA,YACR,yCAAyC,SAAS,qCACxC,OAAO,WAAW,SAAS,CAAC;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,kBAAkB;AAAA;AAAA,IAElB;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/overlay-views/virtual-collection.ts"],"sourcesContent":["import { OverlayIdMismatchError } from '../errors.js'\nimport type { Collection } from '../collection.js'\nimport type { OverlayedViewStrategy } from './types.js'\n\n/**\n * Virtual-collection proxy returned by `vault.collection(overlayName)`\n * when `overlayName` is a registered `withOverlayedView`.\n *\n * Implements the core `Collection<T>`-shaped read/write surface with\n * merge-on-read semantics:\n * - `get(id)`: overlay row wins iff `overlay[shadowField] === shadowValue`\n * - `list()` / `.query()`: union of ids, per-id merge applied\n * - `put(record)` / `put(id, record)`: routes to overlay; id derived\n * via the base MV's `rowKey` (validated on the two-arg form)\n * - `delete(id)`: removes the overlay row only; base stays\n *\n * Reactive APIs (`live`, `subscribe`, `query().live()`) are out of\n * scope for this release and surface as \"not yet implemented\" — wired in a\n * future sub-issue.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class OverlayedCollection<T extends Record<string, unknown> = any> {\n constructor(\n private readonly spec: OverlayedViewStrategy,\n private readonly baseCollection: Collection<T>,\n private readonly overlayCollection: Collection<T>,\n private readonly baseRowKey: ((row: Record<string, unknown>) => string) | undefined,\n ) {}\n\n /**\n * Convenience accessors for advanced callers that need to bypass the\n * virtual layer (bulk imports, direct overlay queries). Mirrors the\n * spec's \"direct writes to the underlying overlay collection skip\n * the validation\" escape hatch.\n */\n readonly overlay = {\n rowKey: (row: Record<string, unknown>): string => {\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\": base \"${this.spec.base}\" is not an MV — ` +\n `cannot auto-derive id from the row. Use \\`put(id, record)\\` instead.`,\n )\n }\n return this.baseRowKey(row)\n },\n }\n\n /** Get the merged row by id. */\n async get(id: string): Promise<T | null> {\n const overlayRow = await this.overlayCollection.get(id)\n if (overlayRow !== null && this.shadowPredicateApplies(overlayRow)) {\n return overlayRow\n }\n const baseRow = await this.baseCollection.get(id)\n if (baseRow !== null) return baseRow\n // No base row — but if an overlay row exists with the shadow\n // predicate true, we returned it above. If overlay exists but\n // predicate is false, return null (overlay exists but doesn't\n // qualify, and there's no base to fall back to) — per spec\n // operations table row \"overlay exists, predicate false, no base\".\n return null\n }\n\n /** List union of base + overlay ids, applying the merge per row. */\n async list(): Promise<T[]> {\n const baseRows = await this.baseCollection.list()\n const overlayRows = await this.overlayCollection.list()\n // Build id → merged row, base-first then overlay applies shadow rule.\n const merged = new Map<string, T>()\n const idOf = (row: T): string => {\n // Best-effort: use baseRowKey if available, else assume the row\n // has a `.id` field (common pattern). The spec requires every\n // base MV to declare `rowKey`, so the first branch is the\n // canonical path.\n if (this.baseRowKey) return this.baseRowKey(row as Record<string, unknown>)\n const idField = (row as Record<string, unknown>).id\n return typeof idField === 'string' ? idField : ''\n }\n for (const row of baseRows) {\n const id = idOf(row)\n if (id) merged.set(id, row)\n }\n for (const row of overlayRows) {\n const id = idOf(row)\n if (!id) continue\n if (this.shadowPredicateApplies(row)) {\n merged.set(id, row) // overlay shadow wins\n } else if (!merged.has(id)) {\n // Overlay-only + predicate false + no base → don't surface\n // (matches spec operations table)\n continue\n }\n // else: overlay exists but predicate is false and base is\n // present → keep the base row already in `merged`\n }\n return [...merged.values()]\n }\n\n /**\n * Write to the overlay. Two forms:\n * - `put(record)`: id is derived via the base MV's `rowKey(record)`.\n * Throws if the base isn't an MV.\n * - `put(id, record)`: validates `id === rowKey(record)`; throws\n * `OverlayIdMismatchError` on mismatch.\n */\n async put(idOrRecord: string | T, maybeRecord?: T): Promise<void> {\n let id: string\n let record: T\n if (maybeRecord === undefined) {\n // Single-arg form: put(record). Derive id via base rowKey.\n record = idOrRecord as T\n if (!this.baseRowKey) {\n throw new Error(\n `Overlay \"${this.spec.name}\".put(record): base \"${this.spec.base}\" is not an MV. ` +\n `Use put(id, record) explicitly.`,\n )\n }\n id = this.baseRowKey(record as Record<string, unknown>)\n } else {\n // Two-arg form: put(id, record). Validate against rowKey.\n id = idOrRecord as string\n record = maybeRecord\n if (this.baseRowKey) {\n const expected = this.baseRowKey(record as Record<string, unknown>)\n if (id !== expected) {\n throw new OverlayIdMismatchError(id, expected)\n }\n }\n }\n await this.overlayCollection.put(id, record)\n }\n\n /**\n * Remove the overlay row only. Idempotent (no-op on absent).\n * The base row is untouched — if a base row exists for `id`,\n * subsequent reads return it.\n */\n async delete(id: string): Promise<void> {\n await this.overlayCollection.delete(id)\n }\n\n /** True when `overlay[shadowField] === shadowValue`. */\n private shadowPredicateApplies(row: T): boolean {\n return (row as Record<string, unknown>)[this.spec.shadowField] === this.spec.shadowValue\n }\n\n // ─── Throw-stubs for the unimplemented Collection<T> surface ───────\n //\n // `Vault.collection(name)` widens the return type to `Collection<T>`\n // for the overlay intercept, but `OverlayedCollection` doesn't\n // implement the full surface. These stubs catch the common\n // reactive / chainable APIs with a clear \"not yet implemented\"\n // error pointing at the relevant issue — so consumers don't hit a\n // cryptic `undefined is not a function` runtime crash.\n //\n // Throw-stubs so consumers get actionable errors rather than cryptic crashes.\n\n /** @throws — chainable Query<T> over a virtual collection is deferred. */\n query(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".query() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` + filter for now, or read from the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections directly. ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — change-stream subscription over a virtual collection is deferred. */\n subscribe(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".subscribe() is not yet implemented for overlay views (#154). ` +\n `Subscribe to the underlying \\`${this.spec.base}\\` / \\`${this.spec.overlay}\\` collections individually for now. ` +\n `Merged change-stream lands in a future MV sub-issue.`,\n )\n }\n\n /** @throws — live query over a virtual collection is deferred. */\n live(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".live() is not yet implemented for overlay views (#154). ` +\n `Reactive APIs land in a future MV sub-issue.`,\n )\n }\n\n /** @throws — async iteration over a virtual collection is deferred. */\n scan(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".scan() is not yet implemented for overlay views (#154). ` +\n `Use \\`list()\\` for now (no row-count ceiling at niwat scale), or scan the underlying collections directly.`,\n )\n }\n\n /** @throws — lazy-mode query is not applicable to virtual collections. */\n lazyQuery(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".lazyQuery() is not supported. ` +\n `Virtual collections always materialize through base + overlay reads — lazy-mode indexed lookups don't apply.`,\n )\n }\n\n /** @throws — bulk-atomic put is deferred to a future MV sub-issue. */\n putManyAtomic(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".putManyAtomic() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.put(record)\\` calls for now, or write to \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — bulk delete is deferred to a future MV sub-issue. */\n deleteMany(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".deleteMany() is not yet implemented for overlay views (#154). ` +\n `Use sequential \\`.delete(id)\\` calls for now, or operate on \\`${this.spec.overlay}\\` directly.`,\n )\n }\n\n /** @throws — `.first()` over a virtual collection is deferred. */\n first(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".first() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list())[0]\\` for now.`,\n )\n }\n\n /** @throws — `.count()` over a virtual collection is deferred. */\n count(): never {\n throw new Error(\n `OverlayedCollection \"${this.spec.name}\".count() is not yet implemented for overlay views (#154). ` +\n `Use \\`(await list()).length\\` for now.`,\n )\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/guards/with-guard.ts","../src/guards/immutable-guard.ts"],"sourcesContent":["import { ValidationError } from '../errors.js'\nimport type { GuardStrategy, GuardStrategyHandle } from './types.js'\n\n/**\n * Register a guard for a collection. Guards run on every `put()` /\n * `delete()` for the named collection (after permissions, before\n * encryption) and may:\n *\n * - `check` — block writes by throwing (typically `RecordLockedError`)\n * - `frozenFields` — freeze specific fields once a condition is true\n * - `amendment` — declare an authorized-override path with invariant\n *\n * Pass the returned handle to `createNoydb({ strategies: [...] })`.\n *\n * @see docs/superpowers/specs/2026-05-18-guards-design.md\n */\nexport function withGuard<T extends Record<string, unknown>>(\n strategy: GuardStrategy<T>,\n): GuardStrategyHandle<T> {\n if (!strategy.collection || strategy.collection.length === 0) {\n throw new ValidationError('withGuard: collection name is required')\n }\n return {\n __noydb_strategy: 'guard',\n spec: strategy,\n }\n}\n","/**\n * `immutableGuard` — declarative WORM / append-only sugar over the guard\n * subsystem.\n *\n * Issued fiscal documents (invoices, DDTs) must be immutable after issue.\n * That is expressible today with a hand-rolled `withGuard` (block on\n * `check`/`onDelete`, allow an admin `amendment`), but the boilerplate is\n * repetitive and easy to get subtly wrong. `immutableGuard` generates\n * exactly that guard from a declarative config, reusing the guard\n * machinery wholesale — `check`/`onDelete` rejection, the ledgered\n * `amendment` override, and composition with `periods`/`history`.\n *\n * ```ts\n * createNoydb({ guardStrategies: [\n * immutableGuard({\n * collection: 'invoices',\n * after: (r) => r.status === 'issued', // immutable once issued\n * }),\n * ] })\n * ```\n *\n * A record is mutable until `after(record)` holds; from then on, updates\n * and deletes throw `RecordLockedError` unless performed inside an\n * `amendment` transaction by an authorized role (the override is\n * ledgered by the guard amendment mechanism). `appendOnly: true` is\n * shorthand for `after: () => true` — immutable from creation.\n */\n\nimport { withGuard } from './with-guard.js'\nimport type { GuardStrategy, GuardStrategyHandle, GuardContext } from './types.js'\nimport { RecordLockedError, ValidationError } from '../errors.js'\n\nexport interface ImmutableGuardConfig<T extends Record<string, unknown>> {\n /** The collection to make WORM. */\n collection: string\n /**\n * A record becomes immutable once this predicate holds. Evaluated on\n * the *existing* (already-persisted) record, so the write that first\n * makes it true is still allowed; subsequent writes are blocked.\n * Mutually exclusive with `appendOnly`.\n */\n after?: (record: T) => boolean\n /** Shorthand for `after: () => true` — immutable from creation. */\n appendOnly?: boolean\n /** Roles permitted to override via an amendment transaction. Default `['admin', 'owner']`. */\n amendmentRoles?: ReadonlyArray<'admin' | 'owner'>\n}\n\nfunction recordId(record: Record<string, unknown> | null): string {\n const id = record?.id\n return typeof id === 'string' ? id : ''\n}\n\n/**\n * Build an immutability guard. Pass the returned handle to\n * `createNoydb({ guardStrategies: [...] })`.\n */\nexport function immutableGuard<T extends Record<string, unknown>>(\n config: ImmutableGuardConfig<T>,\n): GuardStrategyHandle<T> {\n const { collection, after, appendOnly, amendmentRoles } = config\n if (appendOnly && after !== undefined) {\n throw new ValidationError('immutableGuard: `after` and `appendOnly` are mutually exclusive')\n }\n if (!appendOnly && after === undefined) {\n throw new ValidationError('immutableGuard: provide `after` or `appendOnly: true`')\n }\n\n const isImmutable: (record: T) => boolean = appendOnly ? () => true : after!\n const reason = appendOnly ? 'append-only collection' : 'record is immutable after issue'\n\n const spec: GuardStrategy<T> = {\n collection,\n // Block updates to an already-immutable record. Inserts (existing\n // null) and the transition write that first makes the record\n // immutable are allowed — `after` reads the prior state.\n check: (incoming: T, ctx: GuardContext<T>) => {\n if (ctx.existing !== null && isImmutable(ctx.existing)) {\n throw new RecordLockedError(collection, recordId(incoming as Record<string, unknown>), reason)\n }\n },\n // Block deletes of an immutable record.\n onDelete: (existing: T) => {\n if (isImmutable(existing)) {\n throw new RecordLockedError(collection, recordId(existing as Record<string, unknown>), reason)\n }\n },\n // The authorized override: inside an amendment transaction the\n // check/onDelete are skipped and the change is ledgered. No extra\n // invariant — the amendment itself is the sanctioned exception.\n amendment: {\n roles: amendmentRoles ?? ['admin', 'owner'],\n invariant: () => {\n /* allow — the amendment is the override, and is ledgered */\n },\n },\n }\n\n return withGuard<T>(spec)\n}\n"],"mappings":";;;;;;AAgBO,SAAS,UACd,UACwB;AACxB,MAAI,CAAC,SAAS,cAAc,SAAS,WAAW,WAAW,GAAG;AAC5D,UAAM,IAAI,gBAAgB,wCAAwC;AAAA,EACpE;AACA,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,MAAM;AAAA,EACR;AACF;;;ACsBA,SAAS,SAAS,QAAgD;AAChE,QAAM,KAAK,QAAQ;AACnB,SAAO,OAAO,OAAO,WAAW,KAAK;AACvC;AAMO,SAAS,eACd,QACwB;AACxB,QAAM,EAAE,YAAY,OAAO,YAAY,eAAe,IAAI;AAC1D,MAAI,cAAc,UAAU,QAAW;AACrC,UAAM,IAAI,gBAAgB,iEAAiE;AAAA,EAC7F;AACA,MAAI,CAAC,cAAc,UAAU,QAAW;AACtC,UAAM,IAAI,gBAAgB,uDAAuD;AAAA,EACnF;AAEA,QAAM,cAAsC,aAAa,MAAM,OAAO;AACtE,QAAM,SAAS,aAAa,2BAA2B;AAEvD,QAAM,OAAyB;AAAA,IAC7B;AAAA;AAAA;AAAA;AAAA,IAIA,OAAO,CAAC,UAAa,QAAyB;AAC5C,UAAI,IAAI,aAAa,QAAQ,YAAY,IAAI,QAAQ,GAAG;AACtD,cAAM,IAAI,kBAAkB,YAAY,SAAS,QAAmC,GAAG,MAAM;AAAA,MAC/F;AAAA,IACF;AAAA;AAAA,IAEA,UAAU,CAAC,aAAgB;AACzB,UAAI,YAAY,QAAQ,GAAG;AACzB,cAAM,IAAI,kBAAkB,YAAY,SAAS,QAAmC,GAAG,MAAM;AAAA,MAC/F;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAIA,WAAW;AAAA,MACT,OAAO,kBAAkB,CAAC,SAAS,OAAO;AAAA,MAC1C,WAAW,MAAM;AAAA,MAEjB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,UAAa,IAAI;AAC1B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tx/transaction.ts"],"sourcesContent":["/**\n * Multi-record atomic transactions.\n *\n * Lets an application stage writes across two or more collections (or\n * vaults) and commit them all-or-nothing.\n *\n * ```ts\n * await db.transaction(async (tx) => {\n * const inv = tx.vault('acme').collection<Invoice>('invoices')\n * const pay = tx.vault('acme').collection<Payment>('payments')\n * await inv.put(invoiceId, { ...invoice, status: 'paid' })\n * await pay.put(paymentId, { invoiceId, amount, paidAt })\n * })\n * // If the body throws before returning: nothing persisted.\n * // If the body returns: all puts committed; any CAS mismatch rolls\n * // the batch back and surfaces as ConflictError.\n * ```\n *\n * ## Atomicity semantics\n *\n * Ops are buffered during the body. On body-return the hub:\n *\n * 1. **Pre-flight** — re-reads every touched envelope and enforces\n * any caller-supplied `expectedVersion`. A mismatch throws\n * `ConflictError` with *no* writes performed.\n * 2. **Execute** — calls `Collection.put()` / `.delete()` for each\n * staged op in declaration order. History snapshots, ledger\n * appends, and change events fire as normal per op.\n * 3. **Unwind on failure** — if step 2 throws mid-batch, each\n * already-committed op is reverted via the raw store (restoring\n * the captured prior envelope, or deleting if none existed). The\n * ledger is NOT rewritten — audit history preserves the partial\n * commit and the revert.\n *\n * **Crash window.** Steps 2–3 are not a storage-layer transaction —\n * if the process dies between two executed ops, the on-disk state is\n * partial. True all-or-nothing atomicity requires a store that\n * implements `NoydbStore.tx()` (DynamoDB `TransactWriteItems`,\n * IndexedDB `readwrite` transaction, …). This executor declares\n * that future integration point via the `tx?()` method + the\n * `StoreCapabilities.txAtomic` bit, but does not yet delegate\n * to it — the cascade into `Fork · Stores` tracks the per-adapter\n * wire-up.\n *\n * ## Not covered\n *\n * - Cross-sync-peer atomicity. Transactions commit against the\n * primary store only; the sync engine pushes on its normal\n * schedule. For cross-peer two-phase commit use `SyncTransaction`\n * via `db.transaction(vaultName)`.\n * - Read-your-writes within the body. `tx.collection().get(id)`\n * returns the most-recently-staged value for that id when one\n * exists; if no staged op has touched the id, it reads the current\n * committed state. Version numbers returned by `get` reflect the\n * pre-transaction state (staged puts have no version yet).\n *\n * @module\n */\n\nimport type { Noydb } from '../noydb.js'\nimport type { Vault } from '../vault.js'\nimport type { Collection } from '../collection.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport {\n AmendmentForbiddenError,\n ConflictError,\n InvariantError,\n ValidationError,\n} from '../errors.js'\nimport { generateULID } from '../bundle/ulid.js'\nimport type { GuardExecutor as GuardExecutorModule } from '../guards/executor.js'\nimport type { LedgerEntry } from '../history/ledger/entry.js'\n\n/** One op buffered inside a running `TxContext`. @internal */\nexport interface StagedOp {\n type: 'put' | 'delete'\n vaultName: string\n collectionName: string\n id: string\n record?: unknown\n expectedVersion?: number\n /**\n * Optional human-readable tag forwarded to the resulting ledger\n * entry's `reason` field. Set by callers via\n * `tx.vault(v).collection(c).put(id, record, { reason })`.\n */\n reason?: string\n}\n\n/**\n * One executed op (main staged op or recursive side-effect like a\n * derivation output) paired with the envelope captured before the write.\n * `revertExecuted` walks this array in reverse on rollback.\n * @internal\n */\nexport interface ExecutedOp {\n op: StagedOp\n priorEnvelope: EncryptedEnvelope | null\n}\n\n/**\n * Options accepted by `db.transaction({ amendment, reason }, fn)`.\n * Only the amendment variant uses these — a plain `db.transaction(fn)`\n * never sees this shape.\n */\nexport interface AmendmentTxOptions {\n /** Opt into amendment mode. Required to be `true`. */\n readonly amendment: true\n /** Human-readable rationale recorded in the ledger entry. Required. */\n readonly reason: string\n}\n\n/**\n * Transaction handle passed to the user's body. Use\n * `tx.vault(name).collection<T>(name)` to get a per-collection\n * facade; its `put`/`delete`/`get` calls stage ops against the tx.\n */\nexport class TxContext {\n /** Stable id for this transaction; shared by all writes it performs. */\n readonly txId: string = generateULID()\n /** @internal */\n readonly _ops: StagedOp[] = []\n /**\n * @internal — write log built up in Phase 2. Each entry records the\n * envelope captured BEFORE the write so a mid-batch failure can\n * restore prior state via `revertExecuted`. Side-effect writes (e.g.\n * recursive derivation outputs fired inside `Collection.put`) are\n * appended here in execution order so they roll back alongside the\n * main staged ops.\n */\n readonly _executed: ExecutedOp[] = []\n /** @internal */\n readonly _db: Noydb\n /**\n * @internal — true when this TxContext was opened in amendment\n * mode. Toggles the lazy-`beginAmendment` + role-check path on first\n * `tx.vault(name)` and unlocks the post-Phase-2 invariant + audit run.\n */\n readonly _amendment: boolean\n /** @internal — vaults that have already had `beginAmendment` called. */\n readonly _amendmentVaults = new Map<string, Vault>()\n\n /** @internal */\n constructor(db: Noydb, amendment = false) {\n this._db = db\n this._amendment = amendment\n }\n\n /** Scope subsequent `collection()` calls to the named vault. */\n vault(name: string): TxVault {\n const v = this._db.vault(name)\n if (this._amendment && !this._amendmentVaults.has(name)) {\n // Role check is per-vault. The task spec (\"only admin or owner\n // can open an amendment\") is implemented lazy-on-first-touch\n // because the role lives on the vault's keyring, and `tx.vault()`\n // is the first place we know which vault we're addressing. The\n // observable effect is identical to an eager check in the single-\n // vault case the tests exercise; multi-vault amendments check\n // each touched vault as they first appear.\n const role = v.role\n if (role !== 'admin' && role !== 'owner') {\n throw new AmendmentForbiddenError(v.userId, role)\n }\n // Amendments require an initialised guard registry — they\n // produce a structured invariant + change-set audit. A vault\n // opened without `guardStrategies` (or via the sync fallback\n // path) has a null registry and cannot run an amendment.\n const reg = v._getGuardRegistry()\n if (reg === null) {\n throw new ValidationError(\n `Vault \"${name}\": amendment mode requires at least one ` +\n `guardStrategy registered via createNoydb({ guardStrategies }). ` +\n `Open the vault with guardStrategies before calling ` +\n `db.transaction({ amendment: true }).`,\n )\n }\n reg.beginAmendment()\n this._amendmentVaults.set(name, v)\n }\n return new TxVault(this, v)\n }\n}\n\n/** Per-vault facade inside a running transaction. */\nexport class TxVault {\n /** @internal */\n readonly _ctx: TxContext\n /** @internal */\n readonly _vault: Vault\n\n /** @internal */\n constructor(ctx: TxContext, vault: Vault) {\n this._ctx = ctx\n this._vault = vault\n }\n\n /** Scope subsequent op calls to the named collection. */\n collection<T>(name: string): TxCollection<T> {\n const c = this._vault.collection<T>(name)\n return new TxCollection<T>(this._ctx, this._vault, c, name)\n }\n}\n\n/** Per-collection facade inside a running transaction. */\nexport class TxCollection<T> {\n /** @internal */\n readonly _ctx: TxContext\n /** @internal */\n readonly _vault: Vault\n /** @internal */\n readonly _coll: Collection<T>\n /** @internal */\n readonly _name: string\n\n /** @internal */\n constructor(ctx: TxContext, vault: Vault, coll: Collection<T>, name: string) {\n this._ctx = ctx\n this._vault = vault\n this._coll = coll\n this._name = name\n }\n\n /**\n * Read the current committed value, or the most-recently-staged\n * value from the same transaction if one exists.\n */\n async get(id: string): Promise<T | null> {\n for (let i = this._ctx._ops.length - 1; i >= 0; i--) {\n const op = this._ctx._ops[i]!\n if (\n op.vaultName === this._vault.name &&\n op.collectionName === this._name &&\n op.id === id\n ) {\n if (op.type === 'delete') return null\n return op.record as T\n }\n }\n return this._coll.get(id)\n }\n\n /**\n * Stage a put. Does not write until the transaction body returns.\n * Supply `{ expectedVersion }` to enforce optimistic concurrency\n * during the commit pre-flight.\n */\n put(id: string, record: T, options?: { expectedVersion?: number; reason?: string }): void {\n const op: StagedOp = {\n type: 'put',\n vaultName: this._vault.name,\n collectionName: this._name,\n id,\n record,\n }\n if (options?.expectedVersion !== undefined) op.expectedVersion = options.expectedVersion\n if (options?.reason !== undefined) op.reason = options.reason\n this._ctx._ops.push(op)\n }\n\n /**\n * Stage a delete. Does not write until the transaction body returns.\n * Supply `{ expectedVersion }` to enforce optimistic concurrency\n * during the commit pre-flight.\n */\n delete(id: string, options?: { expectedVersion?: number }): void {\n const op: StagedOp = {\n type: 'delete',\n vaultName: this._vault.name,\n collectionName: this._name,\n id,\n }\n if (options?.expectedVersion !== undefined) op.expectedVersion = options.expectedVersion\n this._ctx._ops.push(op)\n }\n}\n\n/**\n * Commit plan: pre-flight check + execution + revert plan.\n *\n * @internal — driven by `withTransactions()` (via `tx/active.ts`) for\n * user-facing `db.transaction(...)` calls and by the `amendment` path\n * in `noydb.ts`. `Collection.putManyAtomic` runs its own Phase 2 loop\n * but shares the `_activeTxContext` mechanism (and the `revertExecuted`\n * helper) so nested side-effect derivation writes get registered for\n * revert alongside the bulk-put source ops.\n */\nexport async function runTransaction<T>(\n db: Noydb,\n fn: (tx: TxContext) => Promise<T> | T,\n options?: AmendmentTxOptions,\n): Promise<T> {\n // ─── Amendment-mode pre-flight ───────────────────────────────\n // `reason` is the only thing we can validate before the body runs;\n // the per-vault role check happens lazily on first `tx.vault(name)`\n // because we don't know which vaults the body will touch ahead of\n // time. Throwing here keeps the failure mode close to the call site\n // so the developer doesn't have to walk an async stack to find the\n // missing-reason mistake.\n if (options?.amendment) {\n if (typeof options.reason !== 'string' || options.reason.trim().length === 0) {\n throw new ValidationError(\n 'db.transaction({ amendment: true }) requires a non-empty `reason` string.',\n )\n }\n }\n\n const ctx = new TxContext(db, options?.amendment === true)\n const bodyResult = await fn(ctx)\n\n if (ctx._ops.length === 0) {\n // Body produced no ops. If amendment mode was active we still\n // need to close any opened windows so a subsequent (unrelated)\n // write doesn't surprise-collect into a stale change-set. Each\n // `beginAmendment` is matched by exactly one `consumeChanges`.\n if (ctx._amendment) {\n for (const v of ctx._amendmentVaults.values()) {\n // Registry is guaranteed non-null here — `tx.vault(name)`\n // threw above if it was null before adding to\n // `_amendmentVaults`.\n const reg = v._getGuardRegistry()\n if (reg !== null) {\n reg.consumeChanges()\n reg.consumeMeta()\n }\n }\n }\n return bodyResult\n }\n\n // Phase 1 — pre-flight: snapshot every touched envelope and enforce\n // any caller-supplied expectedVersion. Same (vault, coll, id) touched\n // more than once in one tx snapshots only the *initial* committed\n // state; the in-order replay in Phase 2 takes care of successor ops.\n const priorEnvelopes = new Map<string, EncryptedEnvelope | null>()\n const store = db._store\n for (const op of ctx._ops) {\n const key = keyOf(op)\n if (!priorEnvelopes.has(key)) {\n const env = await store.get(op.vaultName, op.collectionName, op.id)\n priorEnvelopes.set(key, env)\n }\n if (op.expectedVersion !== undefined) {\n const env = priorEnvelopes.get(key) ?? null\n const actual = env?._v ?? 0\n if (actual !== op.expectedVersion) {\n throw new ConflictError(\n actual,\n `Transaction pre-flight: ${op.vaultName}/${op.collectionName}/${op.id} ` +\n `expected v${op.expectedVersion}, found v${actual}`,\n )\n }\n }\n }\n\n // Phase 2 — execute via the Collection layer so history snapshots,\n // ledger entries, and change events fire normally. We capture each\n // successful op so a mid-batch throw can revert in Phase 3.\n //\n // `_activeTxContext` is published on the Noydb instance for the\n // duration of Phase 2 so recursive writes triggered inside\n // `Collection.put` (today: eager derivation outputs) can register\n // their own envelopes onto `ctx._executed` and roll back alongside\n // the main staged ops. The `finally` clears it before the\n // amendment commit phase runs.\n db._setActiveTxContext(ctx)\n try {\n try {\n for (const op of ctx._ops) {\n const coll = db.vault(op.vaultName).collection(op.collectionName)\n const key = keyOf(op)\n const prior = priorEnvelopes.get(key) ?? null\n // Record the revert plan BEFORE the call so a mid-`coll.put` throw\n // (e.g. strict-mode derivation failure firing after `store.put`\n // has already committed the envelope) still has its source write\n // reverted. `revertExecuted` is best-effort: putting prior back is\n // idempotent when the failing op never actually wrote, and\n // `_invalidateCacheEntry` is a no-op when the collection isn't\n // hydrated.\n ctx._executed.push({ op, priorEnvelope: prior })\n if (op.type === 'put') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await coll.put(op.id, op.record as any, op.reason !== undefined ? { reason: op.reason } : undefined)\n } else {\n await coll.delete(op.id)\n }\n }\n } catch (err) {\n // Phase 3 — best-effort revert. See helper docstring.\n await revertExecuted(ctx._executed, store, db)\n // Drain amendment windows so the next transaction starts clean.\n if (ctx._amendment) {\n for (const v of ctx._amendmentVaults.values()) {\n const reg = v._getGuardRegistry()\n if (reg !== null) {\n reg.consumeChanges()\n reg.consumeMeta()\n }\n }\n }\n throw err\n }\n } finally {\n db._clearActiveTxContext(ctx)\n }\n\n // ─── Amendment commit phase (only if amendment === true) ────\n // Body succeeded — now run each touched vault's invariants over the\n // collected change-set, then append a structured ledger entry. If\n // any invariant throws, treat it exactly like a mid-Phase-2 failure:\n // revert every executed op and re-throw the InvariantError.\n if (ctx._amendment) {\n // Lazy-load GuardExecutor at the dispatch site — keeps the floor\n // bundle free of the guards subsystem when amendments aren't used.\n // Mirrors the deferred-load pattern from elsewhere in this module.\n const { GuardExecutor } = (await import('../guards/executor.js')) as {\n GuardExecutor: typeof GuardExecutorModule\n }\n try {\n for (const [vaultName, v] of ctx._amendmentVaults) {\n const registry = v._getGuardRegistry()\n // Registry is guaranteed non-null at this point — the\n // `tx.vault(name)` path that populates `_amendmentVaults`\n // throws if the registry is null. The defensive check here\n // is for TypeScript's narrowing.\n if (registry === null) continue\n const changesByCollection = registry.consumeChanges()\n const meta = registry.consumeMeta()\n if (changesByCollection.size === 0) continue\n\n const readOnlyVault = v._getReadOnlyFacade()\n if (readOnlyVault === null) continue\n\n // Build the invariant ctx once per vault — it's the same shape\n // every guard sees on the normal `check` path, just with a\n // synthetic `existing: null` (invariants get the full change\n // set in their first parameter; `existing` is a per-record\n // concept that doesn't apply here).\n const invariantsPassed: string[] = []\n for (const [collection, changes] of changesByCollection) {\n const guards = registry.guardsFor(collection).filter(g => g.amendment !== undefined)\n for (const guard of guards) {\n await GuardExecutor.runInvariant(guard, changes, {\n existing: null,\n vault: readOnlyVault,\n userId: v.userId,\n role: v.role,\n })\n }\n if (guards.length > 0) invariantsPassed.push(collection)\n }\n\n // Append the audit ledger entry. Silent no-op when the\n // history strategy isn't configured — the records still\n // committed, only the multi-record summary is unavailable.\n const ledger = v._getLedgerOrNull()\n if (ledger) {\n const role = v.role as 'admin' | 'owner'\n const amendment: NonNullable<LedgerEntry['amendment']> = {\n reason: options!.reason,\n role,\n changes: meta,\n invariantsPassed,\n }\n await ledger.append({\n op: 'amendment',\n collection: '',\n id: '',\n version: 0,\n actor: v.userId,\n // No payload to hash — the per-record entries already\n // captured `payloadHash` at their own append time. We use\n // a sha256 of the canonical reason string so the field is\n // populated with something deterministic and non-empty.\n payloadHash: '',\n amendment,\n })\n }\n void vaultName\n }\n } catch (err) {\n await revertExecuted(ctx._executed, store, db)\n throw err instanceof InvariantError ? err : new InvariantError(\n err instanceof Error ? err.message : `invariant violated: ${String(err)}`,\n )\n }\n }\n\n return bodyResult\n}\n\n/**\n * Phase 3 helper — restore captured prior envelopes via the raw store\n * to avoid re-firing Collection-level side effects (we don't want a\n * cascade of change events undoing themselves). The ledger is left\n * as-is: each committed op appended an entry; the revert is\n * deliberately NOT recorded as a compensating entry because the\n * caller-facing contract is \"atomic or not at all,\" not \"every write\n * visible in the audit trail.\" Auditors who need the intermediate\n * state can still reconstruct it by walking the ledger through the\n * failed-tx timestamp.\n *\n * @internal — shared between `runTransaction` and\n * `Collection.putManyAtomic`. Both register source ops + nested\n * derivation side-effect ops onto `_executed`; this helper unwinds the\n * combined list in reverse on rollback.\n */\nexport async function revertExecuted(\n executed: ReadonlyArray<ExecutedOp>,\n store: Noydb['_store'],\n db?: Noydb,\n): Promise<void> {\n for (const { op, priorEnvelope } of executed.slice().reverse()) {\n try {\n if (priorEnvelope) {\n await store.put(op.vaultName, op.collectionName, op.id, priorEnvelope)\n } else {\n await store.delete(op.vaultName, op.collectionName, op.id)\n }\n // Sync the Collection-layer cache with what we just wrote at\n // the raw store. Without this, eager-mode `get` would still\n // return the rolled-back record from its in-memory map. The\n // Collection's `_invalidateCacheEntry` is a no-op when the\n // collection hasn't yet been hydrated.\n if (db) {\n const coll = db.vault(op.vaultName).collection(op.collectionName)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await (coll as any)._invalidateCacheEntry(op.id)\n }\n } catch {\n // swallow — best-effort. Surfacing the revert error would mask\n // the original one that triggered the rollback.\n }\n }\n}\n\nfunction keyOf(op: StagedOp): string {\n return `${op.vaultName}\\x00${op.collectionName}\\x00${op.id}`\n}\n"],"mappings":"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","names":[]}
@@ -1,35 +0,0 @@
1
- import {
2
- Noydb,
3
- createNoydb
4
- } from "./chunk-7EFFHEN5.js";
5
- import "./chunk-ZC7J6ZYV.js";
6
- import "./chunk-EMIGCR7X.js";
7
- import "./chunk-YHPM5D7Y.js";
8
- import "./chunk-OHVFWCJP.js";
9
- import "./chunk-CZI2A4MQ.js";
10
- import "./chunk-WGHU7BLI.js";
11
- import "./chunk-DKO2QFSA.js";
12
- import "./chunk-KI6HAJWL.js";
13
- import "./chunk-UF3BUNQZ.js";
14
- import "./chunk-7HT2MEZ5.js";
15
- import "./chunk-COFPAMX6.js";
16
- import "./chunk-4TBBMHVC.js";
17
- import "./chunk-A5ZOOZFB.js";
18
- import "./chunk-2QR2PQTT.js";
19
- import "./chunk-FZU343FL.js";
20
- import "./chunk-56DJ7JVK.js";
21
- import "./chunk-Z6FNBOTC.js";
22
- import "./chunk-EYVQHAGH.js";
23
- import "./chunk-XWH4MXIU.js";
24
- import "./chunk-IQLVUT37.js";
25
- import "./chunk-3EWXMOK3.js";
26
- import "./chunk-CJORTUJ2.js";
27
- import "./chunk-6AJBSQU4.js";
28
- import "./chunk-GC4V7RU7.js";
29
- import "./chunk-YULZKK4F.js";
30
- import "./chunk-535SSHBS.js";
31
- export {
32
- Noydb,
33
- createNoydb
34
- };
35
- //# sourceMappingURL=noydb-GZGFBA4E.js.map