@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
@@ -5,7 +5,7 @@ import {
5
5
  LedgerStore,
6
6
  applyPatch,
7
7
  computePatch
8
- } from "./chunk-56DJ7JVK.js";
8
+ } from "./chunk-BR3AMFGS.js";
9
9
  import {
10
10
  canonicalJson,
11
11
  envelopePayloadHash,
@@ -14,7 +14,7 @@ import {
14
14
  parseIndex,
15
15
  sha256Hex
16
16
  } from "./chunk-Z6FNBOTC.js";
17
- import "./chunk-GC4V7RU7.js";
17
+ import "./chunk-F3BPIPLS.js";
18
18
  import "./chunk-YULZKK4F.js";
19
19
  import "./chunk-535SSHBS.js";
20
20
  export {
@@ -30,4 +30,4 @@ export {
30
30
  parseIndex,
31
31
  sha256Hex
32
32
  };
33
- //# sourceMappingURL=ledger-CWSE3BLF.js.map
33
+ //# sourceMappingURL=ledger-A3LL253R.js.map
@@ -160,10 +160,14 @@ function summarizeQueryPlan(query) {
160
160
  });
161
161
  }
162
162
  function summarizeUnionPlan(spec) {
163
- const arms = (spec.unionSources ?? []).map((s) => s.collection).join(",");
163
+ const arms = (spec.unionSources ?? []).map((s) => {
164
+ const joins = s.join?.length ? `[${s.join.map((j) => `${j.field}\u2192${j.as}`).join(";")}]` : "";
165
+ return `${s.collection}${joins}`;
166
+ }).join(",");
164
167
  const groupBy = Array.isArray(spec.groupBy) ? [...spec.groupBy].sort().join(",") : typeof spec.groupBy === "string" ? spec.groupBy : "";
165
168
  const aggKeys = spec.aggregate ? Object.keys(spec.aggregate).sort().join(",") : "";
166
- return `union(${arms})|groupBy(${groupBy})|aggregate(${aggKeys})`;
169
+ const moneyKeys = spec.moneyFields ? Object.keys(spec.moneyFields).sort().join(",") : "";
170
+ return `union(${arms})|groupBy(${groupBy})|aggregate(${aggKeys})|money(${moneyKeys})`;
167
171
  }
168
172
  var init_dependency_analyzer = __esm({
169
173
  "src/materialized-views/dependency-analyzer.ts"() {
@@ -297,6 +301,7 @@ var init_registry = __esm({
297
301
  let isQuery = false;
298
302
  if (spec.unionSources) {
299
303
  dependencies = new Set(spec.unionSources.map((s) => s.collection));
304
+ if (spec.sources) for (const s of spec.sources) dependencies.add(s);
300
305
  queryPlanSummary = summarizeUnionPlan(spec);
301
306
  } else {
302
307
  const q = spec.query(dbForQuery);
@@ -427,6 +432,189 @@ var init_registry = __esm({
427
432
  }
428
433
  });
429
434
 
435
+ // src/money/fixed-point.ts
436
+ function expandExponent(s) {
437
+ const m = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
438
+ if (!m) return s;
439
+ const sign = m[1] === "-" ? "-" : "";
440
+ const intp = m[2];
441
+ const frac = m[3] ?? "";
442
+ const exp = Number(m[4]);
443
+ const digits = intp + frac;
444
+ const pointPos = intp.length + exp;
445
+ let body;
446
+ if (pointPos <= 0) {
447
+ body = "0." + "0".repeat(-pointPos) + digits;
448
+ } else if (pointPos >= digits.length) {
449
+ body = digits + "0".repeat(pointPos - digits.length);
450
+ } else {
451
+ body = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
452
+ }
453
+ return sign + body;
454
+ }
455
+ function toCanonicalDecimalString(input) {
456
+ let s;
457
+ if (typeof input === "number") {
458
+ if (!Number.isFinite(input)) return null;
459
+ s = String(input);
460
+ } else {
461
+ s = input.trim();
462
+ }
463
+ s = expandExponent(s);
464
+ if (s.startsWith("+")) s = s.slice(1);
465
+ if (!/^-?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null;
466
+ return s;
467
+ }
468
+ function shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, mode) {
469
+ switch (mode) {
470
+ case "up":
471
+ return true;
472
+ case "down":
473
+ return false;
474
+ case "ceil":
475
+ return !negative;
476
+ case "floor":
477
+ return negative;
478
+ case "half-up":
479
+ return firstDiscarded >= 5;
480
+ case "half-down":
481
+ return firstDiscarded > 5 || firstDiscarded === 5 && hasMoreNonZeroAfterFirst;
482
+ case "half-even":
483
+ if (firstDiscarded > 5) return true;
484
+ if (firstDiscarded < 5) return false;
485
+ return hasMoreNonZeroAfterFirst || lastKeptDigit % 2 === 1;
486
+ }
487
+ }
488
+ function parseToScaledInt(input, scale, rounding) {
489
+ const canonical = toCanonicalDecimalString(input);
490
+ if (canonical === null) return { ok: false, reason: "nonfinite" };
491
+ const negative = canonical.startsWith("-");
492
+ const unsigned = negative ? canonical.slice(1) : canonical;
493
+ const dot = unsigned.indexOf(".");
494
+ const intPart = dot === -1 ? unsigned : unsigned.slice(0, dot);
495
+ const fracPart = dot === -1 ? "" : unsigned.slice(dot + 1);
496
+ const intDigits = intPart === "" ? "0" : intPart;
497
+ if (fracPart.length <= scale) {
498
+ const keep2 = fracPart.padEnd(scale, "0");
499
+ const magnitude2 = BigInt(intDigits + keep2);
500
+ return { ok: true, value: negative && magnitude2 !== 0n ? -magnitude2 : magnitude2 };
501
+ }
502
+ const keep = fracPart.slice(0, scale);
503
+ const tail = fracPart.slice(scale);
504
+ const magnitudeDigits = intDigits + keep;
505
+ let magnitude = BigInt(magnitudeDigits);
506
+ if (/^0+$/.test(tail)) {
507
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
508
+ }
509
+ if (rounding === void 0) return { ok: false, reason: "precision" };
510
+ const lastKeptDigit = Number(magnitudeDigits[magnitudeDigits.length - 1]);
511
+ const firstDiscarded = Number(tail[0]);
512
+ const hasMoreNonZeroAfterFirst = /[1-9]/.test(tail.slice(1));
513
+ if (shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, rounding)) {
514
+ magnitude += 1n;
515
+ }
516
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
517
+ }
518
+ function formatScaledInt(value, scale) {
519
+ const negative = value < 0n;
520
+ const abs = (negative ? -value : value).toString();
521
+ if (scale === 0) return (negative ? "-" : "") + abs;
522
+ const padded = abs.padStart(scale + 1, "0");
523
+ const cut = padded.length - scale;
524
+ const intPart = padded.slice(0, cut);
525
+ const fracPart = padded.slice(cut);
526
+ return (negative ? "-" : "") + intPart + "." + fracPart;
527
+ }
528
+ var init_fixed_point = __esm({
529
+ "src/money/fixed-point.ts"() {
530
+ "use strict";
531
+ }
532
+ });
533
+
534
+ // src/money/iso4217.ts
535
+ function scaleForCurrency(code) {
536
+ const v = MINOR_UNITS[code];
537
+ return v === void 0 ? null : v;
538
+ }
539
+ var MINOR_UNITS;
540
+ var init_iso4217 = __esm({
541
+ "src/money/iso4217.ts"() {
542
+ "use strict";
543
+ MINOR_UNITS = {
544
+ // 2-decimal majors
545
+ EUR: 2,
546
+ USD: 2,
547
+ GBP: 2,
548
+ CHF: 2,
549
+ CAD: 2,
550
+ AUD: 2,
551
+ NZD: 2,
552
+ SGD: 2,
553
+ HKD: 2,
554
+ CNY: 2,
555
+ INR: 2,
556
+ BRL: 2,
557
+ MXN: 2,
558
+ ZAR: 2,
559
+ RUB: 2,
560
+ TRY: 2,
561
+ PLN: 2,
562
+ SEK: 2,
563
+ NOK: 2,
564
+ DKK: 2,
565
+ CZK: 2,
566
+ HUF: 2,
567
+ RON: 2,
568
+ ILS: 2,
569
+ THB: 2,
570
+ PHP: 2,
571
+ MYR: 2,
572
+ IDR: 2,
573
+ AED: 2,
574
+ SAR: 2,
575
+ QAR: 2,
576
+ EGP: 2,
577
+ // 0-decimal
578
+ JPY: 0,
579
+ KRW: 0,
580
+ ISK: 0,
581
+ CLP: 0,
582
+ VND: 0,
583
+ XOF: 0,
584
+ XAF: 0,
585
+ PYG: 0,
586
+ // 3-decimal
587
+ BHD: 3,
588
+ KWD: 3,
589
+ OMR: 3,
590
+ TND: 3,
591
+ JOD: 3,
592
+ IQD: 3,
593
+ LYD: 3
594
+ };
595
+ }
596
+ });
597
+
598
+ // src/money/descriptor.ts
599
+ var MoneyUnsupportedError;
600
+ var init_descriptor = __esm({
601
+ "src/money/descriptor.ts"() {
602
+ "use strict";
603
+ init_errors();
604
+ MoneyUnsupportedError = class extends NoydbError {
605
+ constructor(field, message) {
606
+ super(
607
+ "MONEY_UNSUPPORTED",
608
+ message ?? `money: operation is not supported on field "${field}" \u2014 use sum() and count() and divide at the boundary`
609
+ );
610
+ this.field = field;
611
+ this.name = "MoneyUnsupportedError";
612
+ }
613
+ field;
614
+ };
615
+ }
616
+ });
617
+
430
618
  // src/query/predicate.ts
431
619
  function readPath(record, path) {
432
620
  if (record === null || record === void 0) return void 0;
@@ -464,6 +652,200 @@ var init_canonical_key = __esm({
464
652
  }
465
653
  });
466
654
 
655
+ // src/money/money-reducer.ts
656
+ function toScaledIntFromAny(v, scale) {
657
+ if (typeof v === "bigint") return v;
658
+ if (typeof v === "number") {
659
+ const r = parseToScaledInt(v, scale);
660
+ return r.ok ? r.value : null;
661
+ }
662
+ if (typeof v === "string") {
663
+ if (!v.includes(".")) {
664
+ try {
665
+ return BigInt(v);
666
+ } catch {
667
+ return null;
668
+ }
669
+ }
670
+ const r = parseToScaledInt(v, scale);
671
+ return r.ok ? r.value : null;
672
+ }
673
+ return null;
674
+ }
675
+ function readMoney(record, field, desc) {
676
+ const raw = readPath(record, field);
677
+ if (raw === null || raw === void 0) return null;
678
+ if (desc.mode === "fixed") {
679
+ const cur = desc.fixedCurrency;
680
+ const value2 = toScaledIntFromAny(raw, desc.scaleFor(cur));
681
+ return value2 === null ? null : { currency: cur, value: value2 };
682
+ }
683
+ if (typeof raw !== "object") return null;
684
+ const o = raw;
685
+ if (typeof o.currency !== "string") return null;
686
+ const scale = desc.allows(o.currency) ? desc.scaleFor(o.currency) : 0;
687
+ const value = toScaledIntFromAny(o.amount, scale);
688
+ return value === null ? null : { currency: o.currency, value };
689
+ }
690
+ function targetScaleFor(desc, currency) {
691
+ if (desc.allows(currency)) return desc.scaleFor(currency);
692
+ const s = scaleForCurrency(currency);
693
+ if (s === null) {
694
+ throw new Error(`money: cannot determine scale for conversion target "${currency}"`);
695
+ }
696
+ return s;
697
+ }
698
+ function parseRate(rate) {
699
+ const s = String(rate).trim();
700
+ const neg = s.startsWith("-");
701
+ const body = neg ? s.slice(1) : s;
702
+ const dot = body.indexOf(".");
703
+ const intPart = dot === -1 ? body : body.slice(0, dot);
704
+ const fracPart = dot === -1 ? "" : body.slice(dot + 1);
705
+ const int = BigInt((intPart === "" ? "0" : intPart) + fracPart);
706
+ return { int: neg ? -int : int, scale: fracPart.length };
707
+ }
708
+ function divRoundHalfEven(n, d) {
709
+ const q = n / d;
710
+ const r = n % d;
711
+ const twiceR = (r < 0n ? -r : r) * 2n;
712
+ if (twiceR < d) return q;
713
+ if (twiceR > d) return q + (n < 0n ? -1n : 1n);
714
+ return q % 2n === 0n ? q : q + (n < 0n ? -1n : 1n);
715
+ }
716
+ function convertScaled(value, srcScale, rate, targetScale) {
717
+ const { int: rateInt, scale: rateScale } = parseRate(rate);
718
+ const product = value * rateInt;
719
+ const curScale = srcScale + rateScale;
720
+ if (curScale === targetScale) return product;
721
+ if (curScale < targetScale) return product * 10n ** BigInt(targetScale - curScale);
722
+ return divRoundHalfEven(product, 10n ** BigInt(curScale - targetScale));
723
+ }
724
+ function finalizeSum(state, desc, convertTo, fx) {
725
+ if (convertTo !== void 0) {
726
+ if (fx === void 0) {
727
+ throw new Error(`money: sum convertTo "${convertTo}" requires an fx rate map`);
728
+ }
729
+ const targetScale = targetScaleFor(desc, convertTo);
730
+ let total = 0n;
731
+ for (const [cur, v] of state) {
732
+ if (cur === convertTo) {
733
+ total += convertScaled(v, desc.scaleFor(cur), 1, targetScale);
734
+ continue;
735
+ }
736
+ const rate = fx[`${cur}->${convertTo}`];
737
+ if (rate === void 0) {
738
+ throw new Error(`money: no fx rate for "${cur}->${convertTo}"`);
739
+ }
740
+ total += convertScaled(v, desc.scaleFor(cur), rate, targetScale);
741
+ }
742
+ return formatScaledInt(total, targetScale);
743
+ }
744
+ if (desc.mode === "fixed") {
745
+ const cur = desc.fixedCurrency;
746
+ return formatScaledInt(state.get(cur) ?? 0n, desc.scaleFor(cur));
747
+ }
748
+ const out = {};
749
+ for (const [cur, v] of state) out[cur] = formatScaledInt(v, desc.scaleFor(cur));
750
+ return out;
751
+ }
752
+ function moneySumReducer(field, desc, convertTo, fx) {
753
+ return {
754
+ op: "sum",
755
+ field,
756
+ init: () => /* @__PURE__ */ new Map(),
757
+ step: (state, record) => {
758
+ const m = readMoney(record, field, desc);
759
+ if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) + m.value);
760
+ return state;
761
+ },
762
+ remove: (state, record) => {
763
+ const m = readMoney(record, field, desc);
764
+ if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) - m.value);
765
+ return state;
766
+ },
767
+ finalize: (state) => finalizeSum(state, desc, convertTo, fx)
768
+ };
769
+ }
770
+ function extremum(values, op) {
771
+ let out = values[0];
772
+ for (let i = 1; i < values.length; i++) {
773
+ const v = values[i];
774
+ if (op === "min" ? v < out : v > out) out = v;
775
+ }
776
+ return out;
777
+ }
778
+ function moneyMinMaxReducer(op, field, desc) {
779
+ return {
780
+ op,
781
+ field,
782
+ init: () => /* @__PURE__ */ new Map(),
783
+ step: (state, record) => {
784
+ const m = readMoney(record, field, desc);
785
+ if (m) {
786
+ const arr = state.get(m.currency);
787
+ if (arr) arr.push(m.value);
788
+ else state.set(m.currency, [m.value]);
789
+ }
790
+ return state;
791
+ },
792
+ remove: (state, record) => {
793
+ const m = readMoney(record, field, desc);
794
+ if (m) {
795
+ const arr = state.get(m.currency);
796
+ if (arr) {
797
+ const idx = arr.indexOf(m.value);
798
+ if (idx >= 0) arr.splice(idx, 1);
799
+ }
800
+ }
801
+ return state;
802
+ },
803
+ finalize: (state) => {
804
+ if (desc.mode === "fixed") {
805
+ const cur = desc.fixedCurrency;
806
+ const arr = state.get(cur);
807
+ if (!arr || arr.length === 0) return null;
808
+ return formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
809
+ }
810
+ const out = {};
811
+ for (const [cur, arr] of state) {
812
+ if (arr.length > 0) out[cur] = formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
813
+ }
814
+ return out;
815
+ }
816
+ };
817
+ }
818
+ function wrapMoneyReducers(spec, moneyFields) {
819
+ let changed = false;
820
+ const out = {};
821
+ for (const [key, reducer] of Object.entries(spec)) {
822
+ const field = reducer.field;
823
+ const desc = field ? moneyFields[field] : void 0;
824
+ if (desc && reducer.op === "avg") {
825
+ throw new MoneyUnsupportedError(
826
+ field,
827
+ `avg() is not supported on money field "${field}" in v1 \u2014 use sum() and count() and divide at the boundary.`
828
+ );
829
+ }
830
+ if (desc && (reducer.op === "sum" || reducer.op === "min" || reducer.op === "max")) {
831
+ changed = true;
832
+ out[key] = reducer.op === "sum" ? moneySumReducer(field, desc, reducer.convertTo, reducer.fx) : moneyMinMaxReducer(reducer.op, field, desc);
833
+ } else {
834
+ out[key] = reducer;
835
+ }
836
+ }
837
+ return changed ? out : spec;
838
+ }
839
+ var init_money_reducer = __esm({
840
+ "src/money/money-reducer.ts"() {
841
+ "use strict";
842
+ init_predicate();
843
+ init_fixed_point();
844
+ init_iso4217();
845
+ init_descriptor();
846
+ }
847
+ });
848
+
467
849
  // src/aggregate/groupby.ts
468
850
  function warnCardinalityApproaching(fields, observed) {
469
851
  const key = JSON.stringify([...fields].sort());
@@ -474,11 +856,14 @@ function warnCardinalityApproaching(fields, observed) {
474
856
  `[noy-db] .groupBy(${label}) produced ${observed} distinct groups, ${Math.round(observed / GROUPBY_MAX_CARDINALITY * 100)}% of the ${GROUPBY_MAX_CARDINALITY}-group ceiling. Narrow the query with .where() before grouping, or switch to a lower-cardinality field.`
475
857
  );
476
858
  }
477
- function groupAndReduce(records, fieldOrFields, spec) {
859
+ function groupAndReduce(records, fieldOrFields, spec, moneyFields) {
478
860
  const fields = typeof fieldOrFields === "string" ? [fieldOrFields] : fieldOrFields;
479
861
  if (fields.length === 0) {
480
862
  throw new Error(".groupBy() requires at least one field");
481
863
  }
864
+ if (moneyFields) {
865
+ spec = wrapMoneyReducers(spec, moneyFields);
866
+ }
482
867
  const buckets = /* @__PURE__ */ new Map();
483
868
  const fieldLabel = fields.length === 1 ? fields[0] : `[${fields.join(", ")}]`;
484
869
  for (const record of records) {
@@ -534,6 +919,7 @@ var init_groupby = __esm({
534
919
  init_predicate();
535
920
  init_canonical_key();
536
921
  init_errors();
922
+ init_money_reducer();
537
923
  GROUPBY_WARN_CARDINALITY = 1e4;
538
924
  GROUPBY_MAX_CARDINALITY = 1e5;
539
925
  warnedCardinalityFields = /* @__PURE__ */ new Set();
@@ -564,7 +950,13 @@ async function materializeUnionResult(spec, db) {
564
950
  const unified = [];
565
951
  for (const arm of spec.unionSources) {
566
952
  const coll = db.collection(arm.collection);
567
- const sourceRows = coll.query().toArray();
953
+ let q = coll.query();
954
+ if (arm.join?.length) {
955
+ for (const leg of arm.join) {
956
+ q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
957
+ }
958
+ }
959
+ const sourceRows = q.toArray();
568
960
  for (const r of sourceRows) {
569
961
  const mapped = arm.map(r);
570
962
  if (mapped == null) continue;
@@ -581,7 +973,7 @@ async function materializeUnionResult(spec, db) {
581
973
  }
582
974
  return [...seen.values()];
583
975
  }
584
- return groupAndReduce(unified, groupFields, spec.aggregate);
976
+ return groupAndReduce(unified, groupFields, spec.aggregate, spec.moneyFields);
585
977
  }
586
978
  async function listOutputIds(outputColl) {
587
979
  const cAny = outputColl;
@@ -761,6 +1153,16 @@ function withMaterializedView(spec) {
761
1153
  `withMaterializedView "${spec.name}": UNION strategy with aggregate requires groupBy \u2014 use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`
762
1154
  );
763
1155
  }
1156
+ if (spec.moneyFields && !spec.aggregate) {
1157
+ throw new MaterializedViewConfigError(
1158
+ `withMaterializedView "${spec.name}": moneyFields requires aggregate \u2014 moneyFields rewrites sum/min/max reducers over money output fields, so it is meaningless without an aggregate spec`
1159
+ );
1160
+ }
1161
+ if (spec.unionSources.some((s) => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {
1162
+ throw new MaterializedViewConfigError(
1163
+ `withMaterializedView "${spec.name}": a unionSources arm declares join(s) but no \`sources\` are listed \u2014 declare sources: [...] with the right-side (join-target) collection names so writes to them trigger MV refresh`
1164
+ );
1165
+ }
764
1166
  if (spec.predicates) {
765
1167
  throw new MaterializedViewConfigError(
766
1168
  `withMaterializedView "${spec.name}": predicates are not supported on UNION strategies \u2014 UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. Use the query() form, or open an issue if per-arm predicates are needed`