@noy-db/hub 0.2.0-pre.14 → 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 (219) hide show
  1. package/dist/aggregate/index.cjs +160 -64
  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 +3 -3
  6. package/dist/attestation/index.cjs.map +1 -1
  7. package/dist/attestation/index.d.cts +5 -5
  8. package/dist/attestation/index.d.ts +5 -5
  9. package/dist/attestation/index.js +4 -4
  10. package/dist/blobs/index.cjs.map +1 -1
  11. package/dist/blobs/index.d.cts +6 -6
  12. package/dist/blobs/index.d.ts +6 -6
  13. package/dist/blobs/index.js +3 -3
  14. package/dist/bundle/index.cjs +607 -114
  15. package/dist/bundle/index.cjs.map +1 -1
  16. package/dist/bundle/index.d.cts +7 -7
  17. package/dist/bundle/index.d.ts +7 -7
  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-ACKFRSAH.js → chunk-667MB6AH.js} +132 -54
  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-CJORTUJ2.js +524 -0
  31. package/dist/chunk-CJORTUJ2.js.map +1 -0
  32. package/dist/{chunk-YNTBADIY.js → chunk-CZI2A4MQ.js} +2 -2
  33. package/dist/{chunk-COFPAMX6.js → chunk-DLZ2ONOD.js} +3 -3
  34. package/dist/{chunk-KGCORI4L.js → chunk-DUREQF5W.js} +266 -66
  35. package/dist/chunk-DUREQF5W.js.map +1 -0
  36. package/dist/{chunk-PE4AQGFH.js → chunk-E2CDVKMH.js} +3 -3
  37. package/dist/{chunk-GC4V7RU7.js → chunk-F3BPIPLS.js} +1 -1
  38. package/dist/{chunk-GC4V7RU7.js.map → chunk-F3BPIPLS.js.map} +1 -1
  39. package/dist/{chunk-L2FE64BU.js → chunk-FFXM3ZIF.js} +2 -2
  40. package/dist/{chunk-5LQG6ZO2.js → chunk-G4SCICH5.js} +8 -3
  41. package/dist/chunk-G4SCICH5.js.map +1 -0
  42. package/dist/{chunk-WGHU7BLI.js → chunk-GNI5STXQ.js} +2 -2
  43. package/dist/{chunk-UWNYBOOO.js → chunk-HBXJ37ZY.js} +11 -5
  44. package/dist/chunk-HBXJ37ZY.js.map +1 -0
  45. package/dist/{chunk-NP6EZT44.js → chunk-IQLVUT37.js} +2 -2
  46. package/dist/{chunk-7PS7EOCF.js → chunk-IXBIFDEW.js} +2 -2
  47. package/dist/{chunk-LX3CB26H.js → chunk-KABJXG2F.js} +2 -2
  48. package/dist/{chunk-3EWA37FV.js → chunk-L2BNJ6HM.js} +32 -276
  49. package/dist/chunk-L2BNJ6HM.js.map +1 -0
  50. package/dist/{chunk-DKO2QFSA.js → chunk-OB2ZJQ2D.js} +2 -2
  51. package/dist/{chunk-4PEFEETV.js → chunk-OMAMZKKD.js} +2 -2
  52. package/dist/{chunk-EGD5DXFT.js → chunk-OQSRJG6A.js} +13 -1
  53. package/dist/chunk-OQSRJG6A.js.map +1 -0
  54. package/dist/{chunk-KI6HAJWL.js → chunk-QSUK7YWK.js} +2 -2
  55. package/dist/{chunk-YHPM5D7Y.js → chunk-QVIEAYTP.js} +61 -2
  56. package/dist/chunk-QVIEAYTP.js.map +1 -0
  57. package/dist/{chunk-NSCVNK5K.js → chunk-SCJPI4Z5.js} +3 -3
  58. package/dist/{chunk-ZWTNWAO4.js → chunk-TKIY625R.js} +13 -3
  59. package/dist/chunk-TKIY625R.js.map +1 -0
  60. package/dist/{chunk-OHVFWCJP.js → chunk-VLMPU56Q.js} +48 -18
  61. package/dist/chunk-VLMPU56Q.js.map +1 -0
  62. package/dist/{chunk-6AJBSQU4.js → chunk-XL35NSEN.js} +2 -2
  63. package/dist/{chunk-WIBHRONM.js → chunk-XWH4MXIU.js} +2 -2
  64. package/dist/consent/index.d.cts +6 -6
  65. package/dist/consent/index.d.ts +6 -6
  66. package/dist/derivations/index.cjs +24 -3
  67. package/dist/derivations/index.cjs.map +1 -1
  68. package/dist/derivations/index.d.cts +7 -7
  69. package/dist/derivations/index.d.ts +7 -7
  70. package/dist/derivations/index.js +2 -2
  71. package/dist/{dev-unlock-BF4OSxRv.d.cts → dev-unlock-8XzcD2Z4.d.cts} +1 -1
  72. package/dist/{dev-unlock-DV7ujTCI.d.ts → dev-unlock-DR3upLd1.d.ts} +1 -1
  73. package/dist/executor-AZLS3KBK.js +11 -0
  74. package/dist/{fanout-sidecar-N6OJX6QR.js → fanout-sidecar-67CMI3UT.js} +2 -2
  75. package/dist/guards/index.cjs +9 -5
  76. package/dist/guards/index.cjs.map +1 -1
  77. package/dist/guards/index.d.cts +7 -7
  78. package/dist/guards/index.d.ts +7 -7
  79. package/dist/guards/index.js +1 -1
  80. package/dist/{hash-DswxkLtW.d.ts → hash-CDjye9KV.d.ts} +1 -1
  81. package/dist/{hash-BcF5WQXl.d.cts → hash-DuQ88_5W.d.cts} +1 -1
  82. package/dist/history/index.cjs.map +1 -1
  83. package/dist/history/index.d.cts +7 -7
  84. package/dist/history/index.d.ts +7 -7
  85. package/dist/history/index.js +2 -2
  86. package/dist/i18n/index.cjs.map +1 -1
  87. package/dist/i18n/index.d.cts +6 -6
  88. package/dist/i18n/index.d.ts +6 -6
  89. package/dist/i18n/index.js +3 -3
  90. package/dist/{immutable-guard-7KqslW2K.d.cts → immutable-guard-CRPvu24K.d.cts} +16 -1
  91. package/dist/{immutable-guard-C8IYdzfu.d.ts → immutable-guard-Dov3WvwF.d.ts} +16 -1
  92. package/dist/{index-Cqzp4tt9.d.ts → index-C8Bk3-VF.d.cts} +11 -3
  93. package/dist/{index-CUVOMtgg.d.cts → index-nP99bXLg.d.ts} +11 -3
  94. package/dist/index.cjs +840 -122
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.d.cts +146 -15
  97. package/dist/index.d.ts +146 -15
  98. package/dist/index.js +153 -35
  99. package/dist/index.js.map +1 -1
  100. package/dist/indexing/index.cjs +92 -31
  101. package/dist/indexing/index.cjs.map +1 -1
  102. package/dist/indexing/index.d.cts +3 -3
  103. package/dist/indexing/index.d.ts +3 -3
  104. package/dist/indexing/index.js +3 -3
  105. package/dist/{issue-ADVS4OVP.js → issue-RZP3VI6O.js} +4 -4
  106. package/dist/{lazy-builder-D5GU14TS.d.ts → lazy-builder-ChSqcF5t.d.ts} +1 -1
  107. package/dist/{lazy-builder-Ci5_YG73.d.cts → lazy-builder-eYZzLEL1.d.cts} +1 -1
  108. package/dist/{ledger-CWSE3BLF.js → ledger-A3LL253R.js} +3 -3
  109. package/dist/materialized-views/index.cjs +409 -7
  110. package/dist/materialized-views/index.cjs.map +1 -1
  111. package/dist/materialized-views/index.d.cts +7 -7
  112. package/dist/materialized-views/index.d.ts +7 -7
  113. package/dist/materialized-views/index.js +6 -6
  114. package/dist/noydb-WCMY2ZOW.js +35 -0
  115. package/dist/overlay-views/index.cjs +47 -17
  116. package/dist/overlay-views/index.cjs.map +1 -1
  117. package/dist/overlay-views/index.d.cts +28 -10
  118. package/dist/overlay-views/index.d.ts +28 -10
  119. package/dist/overlay-views/index.js +1 -1
  120. package/dist/periods/index.cjs.map +1 -1
  121. package/dist/periods/index.d.cts +6 -6
  122. package/dist/periods/index.d.ts +6 -6
  123. package/dist/periods/index.js +3 -3
  124. package/dist/{predicate-Bt5ft-9c.d.cts → predicate-BmhBSPCH.d.cts} +59 -2
  125. package/dist/{predicate-Bt5ft-9c.d.ts → predicate-BmhBSPCH.d.ts} +59 -2
  126. package/dist/{public-envelope-SYHEYQ3X.js → public-envelope-YP2UWMLG.js} +3 -3
  127. package/dist/query/index.cjs +604 -205
  128. package/dist/query/index.cjs.map +1 -1
  129. package/dist/query/index.d.cts +3 -3
  130. package/dist/query/index.d.ts +3 -3
  131. package/dist/query/index.js +5 -5
  132. package/dist/{registry-XGLNADIE.js → registry-EB6SISTA.js} +2 -2
  133. package/dist/{registry-DK5YWAAA.js → registry-UTA4CLQS.js} +2 -2
  134. package/dist/{revoke-ZDFKMR5E.js → revoke-HNMQZSCL.js} +4 -4
  135. package/dist/session/index.d.cts +7 -7
  136. package/dist/session/index.d.ts +7 -7
  137. package/dist/shadow/index.d.cts +6 -6
  138. package/dist/shadow/index.d.ts +6 -6
  139. package/dist/{signer-P5D7Y72U.js → signer-DCMNKXSF.js} +3 -3
  140. package/dist/snapshots/index.d.cts +6 -6
  141. package/dist/snapshots/index.d.ts +6 -6
  142. package/dist/snapshots/index.js +3 -3
  143. package/dist/{stale-7FRJVHN6.js → stale-W5PQTRYH.js} +2 -2
  144. package/dist/store/index.d.cts +6 -6
  145. package/dist/store/index.d.ts +6 -6
  146. package/dist/{strategy-CrS7PnbE.d.cts → strategy-BtW8fAjz.d.cts} +2 -2
  147. package/dist/{strategy-CrS7PnbE.d.ts → strategy-BtW8fAjz.d.ts} +2 -2
  148. package/dist/sync/index.cjs.map +1 -1
  149. package/dist/sync/index.d.cts +5 -5
  150. package/dist/sync/index.d.ts +5 -5
  151. package/dist/sync/index.js +2 -2
  152. package/dist/team/index.cjs.map +1 -1
  153. package/dist/team/index.d.cts +6 -6
  154. package/dist/team/index.d.ts +6 -6
  155. package/dist/team/index.js +5 -5
  156. package/dist/tx/index.cjs +66 -3
  157. package/dist/tx/index.cjs.map +1 -1
  158. package/dist/tx/index.d.cts +24 -8
  159. package/dist/tx/index.d.ts +24 -8
  160. package/dist/tx/index.js +7 -3
  161. package/dist/tx/index.js.map +1 -1
  162. package/dist/{types-V5R2-pd4.d.cts → types-Bze6vkwm.d.cts} +391 -144
  163. package/dist/{types-BFHQUjdy.d.ts → types-DrmBTscX.d.ts} +391 -144
  164. package/dist/{ulid-p2nKiiKg.d.ts → ulid-DbBVrNSt.d.ts} +1 -1
  165. package/dist/{ulid-CwNf9e6-.d.cts → ulid-DfZlAh0u.d.cts} +1 -1
  166. package/dist/{vault-group-W7QC4UYW.js → vault-group-DX2HFQMX.js} +3 -3
  167. package/dist/{with-derivation-C9K43BOB.d.cts → with-derivation-CCqAchD5.d.cts} +1 -1
  168. package/dist/{with-derivation-Ds9yZgCj.d.ts → with-derivation-_lySGdlm.d.ts} +1 -1
  169. package/dist/{with-materialized-view-DgQcAjYv.d.cts → with-materialized-view--4PsvMDu.d.cts} +1 -1
  170. package/dist/{with-materialized-view-DwR4jkV5.d.ts → with-materialized-view-QT1Tp7NO.d.ts} +1 -1
  171. package/dist/{with-overlayed-view-ByyhHdVr.d.ts → with-overlayed-view-BEXfpzSb.d.ts} +1 -1
  172. package/dist/{with-overlayed-view-7-rUB3vD.d.cts → with-overlayed-view-DlH5qmeB.d.cts} +1 -1
  173. package/package.json +3 -3
  174. package/dist/chunk-3EWA37FV.js.map +0 -1
  175. package/dist/chunk-5LQG6ZO2.js.map +0 -1
  176. package/dist/chunk-ACKFRSAH.js.map +0 -1
  177. package/dist/chunk-DQU36Q7I.js.map +0 -1
  178. package/dist/chunk-EGD5DXFT.js.map +0 -1
  179. package/dist/chunk-KGCORI4L.js.map +0 -1
  180. package/dist/chunk-OHVFWCJP.js.map +0 -1
  181. package/dist/chunk-TV3YZ35S.js +0 -90
  182. package/dist/chunk-TV3YZ35S.js.map +0 -1
  183. package/dist/chunk-UWNYBOOO.js.map +0 -1
  184. package/dist/chunk-VU7SWWT5.js.map +0 -1
  185. package/dist/chunk-YHPM5D7Y.js.map +0 -1
  186. package/dist/chunk-ZWTNWAO4.js.map +0 -1
  187. package/dist/executor-723ZP6TH.js +0 -11
  188. package/dist/noydb-VZ4JVW55.js +0 -35
  189. /package/dist/{chunk-BIYRQQV6.js.map → chunk-3YWP3WBP.js.map} +0 -0
  190. /package/dist/{chunk-A5ZOOZFB.js.map → chunk-6H2ZUNR7.js.map} +0 -0
  191. /package/dist/{chunk-7HT2MEZ5.js.map → chunk-7BQ4QWYX.js.map} +0 -0
  192. /package/dist/{chunk-WBAYSNUQ.js.map → chunk-BI6ETQPF.js.map} +0 -0
  193. /package/dist/{chunk-56DJ7JVK.js.map → chunk-BR3AMFGS.js.map} +0 -0
  194. /package/dist/{chunk-YNTBADIY.js.map → chunk-CZI2A4MQ.js.map} +0 -0
  195. /package/dist/{chunk-COFPAMX6.js.map → chunk-DLZ2ONOD.js.map} +0 -0
  196. /package/dist/{chunk-PE4AQGFH.js.map → chunk-E2CDVKMH.js.map} +0 -0
  197. /package/dist/{chunk-L2FE64BU.js.map → chunk-FFXM3ZIF.js.map} +0 -0
  198. /package/dist/{chunk-WGHU7BLI.js.map → chunk-GNI5STXQ.js.map} +0 -0
  199. /package/dist/{chunk-NP6EZT44.js.map → chunk-IQLVUT37.js.map} +0 -0
  200. /package/dist/{chunk-7PS7EOCF.js.map → chunk-IXBIFDEW.js.map} +0 -0
  201. /package/dist/{chunk-LX3CB26H.js.map → chunk-KABJXG2F.js.map} +0 -0
  202. /package/dist/{chunk-DKO2QFSA.js.map → chunk-OB2ZJQ2D.js.map} +0 -0
  203. /package/dist/{chunk-4PEFEETV.js.map → chunk-OMAMZKKD.js.map} +0 -0
  204. /package/dist/{chunk-KI6HAJWL.js.map → chunk-QSUK7YWK.js.map} +0 -0
  205. /package/dist/{chunk-NSCVNK5K.js.map → chunk-SCJPI4Z5.js.map} +0 -0
  206. /package/dist/{chunk-6AJBSQU4.js.map → chunk-XL35NSEN.js.map} +0 -0
  207. /package/dist/{chunk-WIBHRONM.js.map → chunk-XWH4MXIU.js.map} +0 -0
  208. /package/dist/{executor-723ZP6TH.js.map → executor-AZLS3KBK.js.map} +0 -0
  209. /package/dist/{fanout-sidecar-N6OJX6QR.js.map → fanout-sidecar-67CMI3UT.js.map} +0 -0
  210. /package/dist/{issue-ADVS4OVP.js.map → issue-RZP3VI6O.js.map} +0 -0
  211. /package/dist/{ledger-CWSE3BLF.js.map → ledger-A3LL253R.js.map} +0 -0
  212. /package/dist/{noydb-VZ4JVW55.js.map → noydb-WCMY2ZOW.js.map} +0 -0
  213. /package/dist/{public-envelope-SYHEYQ3X.js.map → public-envelope-YP2UWMLG.js.map} +0 -0
  214. /package/dist/{registry-DK5YWAAA.js.map → registry-EB6SISTA.js.map} +0 -0
  215. /package/dist/{registry-XGLNADIE.js.map → registry-UTA4CLQS.js.map} +0 -0
  216. /package/dist/{revoke-ZDFKMR5E.js.map → revoke-HNMQZSCL.js.map} +0 -0
  217. /package/dist/{signer-P5D7Y72U.js.map → signer-DCMNKXSF.js.map} +0 -0
  218. /package/dist/{stale-7FRJVHN6.js.map → stale-W5PQTRYH.js.map} +0 -0
  219. /package/dist/{vault-group-W7QC4UYW.js.map → vault-group-DX2HFQMX.js.map} +0 -0
@@ -162,63 +162,89 @@ function buildLiveAggregation(recompute, upstreams) {
162
162
  return new LiveAggregationImpl(recompute, upstreams);
163
163
  }
164
164
 
165
- // src/query/predicate.ts
166
- function readPath(record, path) {
167
- if (record === null || record === void 0) return void 0;
168
- if (!path.includes(".")) {
169
- return record[path];
170
- }
171
- const segments = path.split(".");
172
- let cursor = record;
173
- for (const segment of segments) {
174
- if (cursor === null || cursor === void 0) return void 0;
175
- cursor = cursor[segment];
176
- }
177
- return cursor;
165
+ // src/money/fixed-point.ts
166
+ function expandExponent(s) {
167
+ const m = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
168
+ if (!m) return s;
169
+ const sign = m[1] === "-" ? "-" : "";
170
+ const intp = m[2];
171
+ const frac = m[3] ?? "";
172
+ const exp = Number(m[4]);
173
+ const digits = intp + frac;
174
+ const pointPos = intp.length + exp;
175
+ let body;
176
+ if (pointPos <= 0) {
177
+ body = "0." + "0".repeat(-pointPos) + digits;
178
+ } else if (pointPos >= digits.length) {
179
+ body = digits + "0".repeat(pointPos - digits.length);
180
+ } else {
181
+ body = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
182
+ }
183
+ return sign + body;
178
184
  }
179
-
180
- // src/aggregate/canonical-key.ts
181
- function canonicalGroupKey(fields, row) {
182
- const sorted = [...fields].sort();
183
- const parts = [];
184
- for (const name of sorted) {
185
- const v = row[name];
186
- const serialised = v === void 0 ? "undefined" : JSON.stringify(v);
187
- parts.push(`${name}=${serialised}`);
188
- }
189
- return parts.join("|");
185
+ function toCanonicalDecimalString(input) {
186
+ let s;
187
+ if (typeof input === "number") {
188
+ if (!Number.isFinite(input)) return null;
189
+ s = String(input);
190
+ } else {
191
+ s = input.trim();
192
+ }
193
+ s = expandExponent(s);
194
+ if (s.startsWith("+")) s = s.slice(1);
195
+ if (!/^-?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null;
196
+ return s;
190
197
  }
191
-
192
- // src/errors.ts
193
- var NoydbError = class extends Error {
194
- /** Machine-readable error code. Stable across library versions. */
195
- code;
196
- constructor(code, message) {
197
- super(message);
198
- this.name = "NoydbError";
199
- this.code = code;
200
- }
201
- };
202
- var GroupCardinalityError = class extends NoydbError {
203
- /** The field being grouped on. */
204
- field;
205
- /** Observed number of distinct groups at the moment the cap tripped. */
206
- cardinality;
207
- /** The cap that was exceeded. */
208
- maxGroups;
209
- constructor(field, cardinality, maxGroups) {
210
- super(
211
- "GROUP_CARDINALITY",
212
- `.groupBy("${field}") produced ${cardinality} distinct groups, exceeding the ${maxGroups}-group ceiling. This is almost always a query mistake \u2014 grouping on a high-uniqueness field like "id" or "createdAt" produces one bucket per record. Narrow the query with .where() before grouping, or group on a lower-cardinality field (status, category, clientId). If you genuinely need high-cardinality grouping, file an issue with your use case.`
213
- );
214
- this.name = "GroupCardinalityError";
215
- this.field = field;
216
- this.cardinality = cardinality;
217
- this.maxGroups = maxGroups;
198
+ function shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, mode) {
199
+ switch (mode) {
200
+ case "up":
201
+ return true;
202
+ case "down":
203
+ return false;
204
+ case "ceil":
205
+ return !negative;
206
+ case "floor":
207
+ return negative;
208
+ case "half-up":
209
+ return firstDiscarded >= 5;
210
+ case "half-down":
211
+ return firstDiscarded > 5 || firstDiscarded === 5 && hasMoreNonZeroAfterFirst;
212
+ case "half-even":
213
+ if (firstDiscarded > 5) return true;
214
+ if (firstDiscarded < 5) return false;
215
+ return hasMoreNonZeroAfterFirst || lastKeptDigit % 2 === 1;
218
216
  }
219
- };
220
-
221
- // src/money/fixed-point.ts
217
+ }
218
+ function parseToScaledInt(input, scale, rounding) {
219
+ const canonical = toCanonicalDecimalString(input);
220
+ if (canonical === null) return { ok: false, reason: "nonfinite" };
221
+ const negative = canonical.startsWith("-");
222
+ const unsigned = negative ? canonical.slice(1) : canonical;
223
+ const dot = unsigned.indexOf(".");
224
+ const intPart = dot === -1 ? unsigned : unsigned.slice(0, dot);
225
+ const fracPart = dot === -1 ? "" : unsigned.slice(dot + 1);
226
+ const intDigits = intPart === "" ? "0" : intPart;
227
+ if (fracPart.length <= scale) {
228
+ const keep2 = fracPart.padEnd(scale, "0");
229
+ const magnitude2 = BigInt(intDigits + keep2);
230
+ return { ok: true, value: negative && magnitude2 !== 0n ? -magnitude2 : magnitude2 };
231
+ }
232
+ const keep = fracPart.slice(0, scale);
233
+ const tail = fracPart.slice(scale);
234
+ const magnitudeDigits = intDigits + keep;
235
+ let magnitude = BigInt(magnitudeDigits);
236
+ if (/^0+$/.test(tail)) {
237
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
238
+ }
239
+ if (rounding === void 0) return { ok: false, reason: "precision" };
240
+ const lastKeptDigit = Number(magnitudeDigits[magnitudeDigits.length - 1]);
241
+ const firstDiscarded = Number(tail[0]);
242
+ const hasMoreNonZeroAfterFirst = /[1-9]/.test(tail.slice(1));
243
+ if (shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, rounding)) {
244
+ magnitude += 1n;
245
+ }
246
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
247
+ }
222
248
  function formatScaledInt(value, scale) {
223
249
  const negative = value < 0n;
224
250
  const abs = (negative ? -value : value).toString();
@@ -288,6 +314,35 @@ function scaleForCurrency(code) {
288
314
  return v === void 0 ? null : v;
289
315
  }
290
316
 
317
+ // src/errors.ts
318
+ var NoydbError = class extends Error {
319
+ /** Machine-readable error code. Stable across library versions. */
320
+ code;
321
+ constructor(code, message) {
322
+ super(message);
323
+ this.name = "NoydbError";
324
+ this.code = code;
325
+ }
326
+ };
327
+ var GroupCardinalityError = class extends NoydbError {
328
+ /** The field being grouped on. */
329
+ field;
330
+ /** Observed number of distinct groups at the moment the cap tripped. */
331
+ cardinality;
332
+ /** The cap that was exceeded. */
333
+ maxGroups;
334
+ constructor(field, cardinality, maxGroups) {
335
+ super(
336
+ "GROUP_CARDINALITY",
337
+ `.groupBy("${field}") produced ${cardinality} distinct groups, exceeding the ${maxGroups}-group ceiling. This is almost always a query mistake \u2014 grouping on a high-uniqueness field like "id" or "createdAt" produces one bucket per record. Narrow the query with .where() before grouping, or group on a lower-cardinality field (status, category, clientId). If you genuinely need high-cardinality grouping, file an issue with your use case.`
338
+ );
339
+ this.name = "GroupCardinalityError";
340
+ this.field = field;
341
+ this.cardinality = cardinality;
342
+ this.maxGroups = maxGroups;
343
+ }
344
+ };
345
+
291
346
  // src/money/descriptor.ts
292
347
  var MoneyUnsupportedError = class extends NoydbError {
293
348
  constructor(field, message) {
@@ -301,14 +356,50 @@ var MoneyUnsupportedError = class extends NoydbError {
301
356
  field;
302
357
  };
303
358
 
359
+ // src/query/predicate.ts
360
+ function readPath(record, path) {
361
+ if (record === null || record === void 0) return void 0;
362
+ if (!path.includes(".")) {
363
+ return record[path];
364
+ }
365
+ const segments = path.split(".");
366
+ let cursor = record;
367
+ for (const segment of segments) {
368
+ if (cursor === null || cursor === void 0) return void 0;
369
+ cursor = cursor[segment];
370
+ }
371
+ return cursor;
372
+ }
373
+
374
+ // src/aggregate/canonical-key.ts
375
+ function canonicalGroupKey(fields, row) {
376
+ const sorted = [...fields].sort();
377
+ const parts = [];
378
+ for (const name of sorted) {
379
+ const v = row[name];
380
+ const serialised = v === void 0 ? "undefined" : JSON.stringify(v);
381
+ parts.push(`${name}=${serialised}`);
382
+ }
383
+ return parts.join("|");
384
+ }
385
+
304
386
  // src/money/money-reducer.ts
305
- function toScaledInt(v) {
306
- if (typeof v === "string" || typeof v === "number" || typeof v === "bigint") {
307
- try {
308
- return BigInt(v);
309
- } catch {
310
- return null;
387
+ function toScaledIntFromAny(v, scale) {
388
+ if (typeof v === "bigint") return v;
389
+ if (typeof v === "number") {
390
+ const r = parseToScaledInt(v, scale);
391
+ return r.ok ? r.value : null;
392
+ }
393
+ if (typeof v === "string") {
394
+ if (!v.includes(".")) {
395
+ try {
396
+ return BigInt(v);
397
+ } catch {
398
+ return null;
399
+ }
311
400
  }
401
+ const r = parseToScaledInt(v, scale);
402
+ return r.ok ? r.value : null;
312
403
  }
313
404
  return null;
314
405
  }
@@ -316,13 +407,15 @@ function readMoney(record, field, desc) {
316
407
  const raw = readPath(record, field);
317
408
  if (raw === null || raw === void 0) return null;
318
409
  if (desc.mode === "fixed") {
319
- const value2 = toScaledInt(raw);
320
- return value2 === null ? null : { currency: desc.fixedCurrency, value: value2 };
410
+ const cur = desc.fixedCurrency;
411
+ const value2 = toScaledIntFromAny(raw, desc.scaleFor(cur));
412
+ return value2 === null ? null : { currency: cur, value: value2 };
321
413
  }
322
414
  if (typeof raw !== "object") return null;
323
415
  const o = raw;
324
416
  if (typeof o.currency !== "string") return null;
325
- const value = toScaledInt(o.amount);
417
+ const scale = desc.allows(o.currency) ? desc.scaleFor(o.currency) : 0;
418
+ const value = toScaledIntFromAny(o.amount, scale);
326
419
  return value === null ? null : { currency: o.currency, value };
327
420
  }
328
421
  function targetScaleFor(desc, currency) {
@@ -543,11 +636,14 @@ var GroupedQueryN = class extends GroupedQueryBase {
543
636
  );
544
637
  }
545
638
  };
546
- function groupAndReduce(records, fieldOrFields, spec) {
639
+ function groupAndReduce(records, fieldOrFields, spec, moneyFields) {
547
640
  const fields = typeof fieldOrFields === "string" ? [fieldOrFields] : fieldOrFields;
548
641
  if (fields.length === 0) {
549
642
  throw new Error(".groupBy() requires at least one field");
550
643
  }
644
+ if (moneyFields) {
645
+ spec = wrapMoneyReducers(spec, moneyFields);
646
+ }
551
647
  const buckets = /* @__PURE__ */ new Map();
552
648
  const fieldLabel = fields.length === 1 ? fields[0] : `[${fields.join(", ")}]`;
553
649
  for (const record of records) {