@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.
- package/dist/aggregate/index.cjs +106 -10
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +2 -2
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/aggregate/index.js +1 -1
- package/dist/attestation/index.cjs.map +1 -1
- package/dist/attestation/index.d.cts +3 -3
- package/dist/attestation/index.d.ts +3 -3
- package/dist/attestation/index.js +4 -4
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +4 -4
- package/dist/blobs/index.d.ts +4 -4
- package/dist/blobs/index.js +3 -3
- package/dist/bundle/index.cjs +181 -46
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +5 -5
- package/dist/bundle/index.d.ts +5 -5
- package/dist/bundle/index.js +7 -7
- package/dist/{chunk-BIYRQQV6.js → chunk-3YWP3WBP.js} +3 -3
- package/dist/{chunk-VU7SWWT5.js → chunk-42FEUPZQ.js} +10 -6
- package/dist/chunk-42FEUPZQ.js.map +1 -0
- package/dist/{chunk-7EFFHEN5.js → chunk-667MB6AH.js} +118 -47
- package/dist/chunk-667MB6AH.js.map +1 -0
- package/dist/{chunk-A5ZOOZFB.js → chunk-6H2ZUNR7.js} +2 -2
- package/dist/{chunk-7HT2MEZ5.js → chunk-7BQ4QWYX.js} +3 -3
- package/dist/{chunk-DQU36Q7I.js → chunk-7Z7KSVA5.js} +13 -4
- package/dist/chunk-7Z7KSVA5.js.map +1 -0
- package/dist/{chunk-WBAYSNUQ.js → chunk-BI6ETQPF.js} +2 -2
- package/dist/{chunk-56DJ7JVK.js → chunk-BR3AMFGS.js} +2 -2
- package/dist/{chunk-COFPAMX6.js → chunk-DLZ2ONOD.js} +3 -3
- package/dist/{chunk-EYVQHAGH.js → chunk-DUREQF5W.js} +2 -2
- package/dist/{chunk-PE4AQGFH.js → chunk-E2CDVKMH.js} +3 -3
- package/dist/{chunk-GC4V7RU7.js → chunk-F3BPIPLS.js} +1 -1
- package/dist/{chunk-GC4V7RU7.js.map → chunk-F3BPIPLS.js.map} +1 -1
- package/dist/{chunk-L2FE64BU.js → chunk-FFXM3ZIF.js} +2 -2
- package/dist/{chunk-5LQG6ZO2.js → chunk-G4SCICH5.js} +8 -3
- package/dist/chunk-G4SCICH5.js.map +1 -0
- package/dist/{chunk-WGHU7BLI.js → chunk-GNI5STXQ.js} +2 -2
- package/dist/{chunk-C5T5AFWN.js → chunk-HBXJ37ZY.js} +11 -5
- package/dist/chunk-HBXJ37ZY.js.map +1 -0
- package/dist/{chunk-7PS7EOCF.js → chunk-IXBIFDEW.js} +2 -2
- package/dist/{chunk-LX3CB26H.js → chunk-KABJXG2F.js} +2 -2
- package/dist/{chunk-3EWXMOK3.js → chunk-L2BNJ6HM.js} +26 -11
- package/dist/chunk-L2BNJ6HM.js.map +1 -0
- package/dist/{chunk-DKO2QFSA.js → chunk-OB2ZJQ2D.js} +2 -2
- package/dist/{chunk-KIP6JLTF.js → chunk-OMAMZKKD.js} +2 -2
- package/dist/{chunk-EGD5DXFT.js → chunk-OQSRJG6A.js} +13 -1
- package/dist/chunk-OQSRJG6A.js.map +1 -0
- package/dist/{chunk-KI6HAJWL.js → chunk-QSUK7YWK.js} +2 -2
- package/dist/{chunk-YHPM5D7Y.js → chunk-QVIEAYTP.js} +61 -2
- package/dist/chunk-QVIEAYTP.js.map +1 -0
- package/dist/{chunk-NSCVNK5K.js → chunk-SCJPI4Z5.js} +3 -3
- package/dist/{chunk-NU6Q3FOR.js → chunk-TKIY625R.js} +11 -1
- package/dist/{chunk-NU6Q3FOR.js.map → chunk-TKIY625R.js.map} +1 -1
- package/dist/{chunk-OHVFWCJP.js → chunk-VLMPU56Q.js} +48 -18
- package/dist/chunk-VLMPU56Q.js.map +1 -0
- package/dist/{chunk-6AJBSQU4.js → chunk-XL35NSEN.js} +2 -2
- package/dist/consent/index.d.cts +4 -4
- package/dist/consent/index.d.ts +4 -4
- package/dist/derivations/index.cjs +24 -3
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +5 -5
- package/dist/derivations/index.d.ts +5 -5
- package/dist/derivations/index.js +2 -2
- package/dist/{dev-unlock-nVkuRLLe.d.cts → dev-unlock-8XzcD2Z4.d.cts} +1 -1
- package/dist/{dev-unlock-iAS8z9jc.d.ts → dev-unlock-DR3upLd1.d.ts} +1 -1
- package/dist/{executor-HSSRXDOB.js → executor-AZLS3KBK.js} +4 -4
- package/dist/{fanout-sidecar-N6OJX6QR.js → fanout-sidecar-67CMI3UT.js} +2 -2
- package/dist/guards/index.cjs +9 -5
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +5 -5
- package/dist/guards/index.d.ts +5 -5
- package/dist/guards/index.js +1 -1
- package/dist/{hash-DHOnRarj.d.ts → hash-CDjye9KV.d.ts} +1 -1
- package/dist/{hash-Cv6byZs7.d.cts → hash-DuQ88_5W.d.cts} +1 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +5 -5
- package/dist/history/index.d.ts +5 -5
- package/dist/history/index.js +2 -2
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +4 -4
- package/dist/i18n/index.d.ts +4 -4
- package/dist/i18n/index.js +3 -3
- package/dist/{immutable-guard-yBEOYmif.d.cts → immutable-guard-CRPvu24K.d.cts} +16 -1
- package/dist/{immutable-guard-BehB1YGB.d.ts → immutable-guard-Dov3WvwF.d.ts} +16 -1
- package/dist/{index-D95VK1Qy.d.cts → index-C8Bk3-VF.d.cts} +1 -1
- package/dist/{index-XNB2r6bX.d.ts → index-nP99bXLg.d.ts} +1 -1
- package/dist/index.cjs +273 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -12
- package/dist/index.d.ts +13 -12
- package/dist/index.js +27 -25
- package/dist/index.js.map +1 -1
- package/dist/{issue-ADVS4OVP.js → issue-RZP3VI6O.js} +4 -4
- package/dist/{ledger-CWSE3BLF.js → ledger-A3LL253R.js} +3 -3
- package/dist/materialized-views/index.cjs +407 -5
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +5 -5
- package/dist/materialized-views/index.d.ts +5 -5
- package/dist/materialized-views/index.js +5 -5
- package/dist/noydb-WCMY2ZOW.js +35 -0
- package/dist/overlay-views/index.cjs +47 -17
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +26 -8
- package/dist/overlay-views/index.d.ts +26 -8
- package/dist/overlay-views/index.js +1 -1
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +4 -4
- package/dist/periods/index.d.ts +4 -4
- package/dist/periods/index.js +3 -3
- package/dist/{public-envelope-SYHEYQ3X.js → public-envelope-YP2UWMLG.js} +3 -3
- package/dist/query/index.cjs +24 -10
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{registry-XGLNADIE.js → registry-EB6SISTA.js} +2 -2
- package/dist/{registry-DK5YWAAA.js → registry-UTA4CLQS.js} +2 -2
- package/dist/{revoke-ZDFKMR5E.js → revoke-HNMQZSCL.js} +4 -4
- package/dist/session/index.d.cts +5 -5
- package/dist/session/index.d.ts +5 -5
- package/dist/shadow/index.d.cts +4 -4
- package/dist/shadow/index.d.ts +4 -4
- package/dist/{signer-P5D7Y72U.js → signer-DCMNKXSF.js} +3 -3
- package/dist/snapshots/index.d.cts +4 -4
- package/dist/snapshots/index.d.ts +4 -4
- package/dist/snapshots/index.js +3 -3
- package/dist/{stale-JH67FU57.js → stale-W5PQTRYH.js} +2 -2
- package/dist/store/index.d.cts +4 -4
- package/dist/store/index.d.ts +4 -4
- package/dist/{strategy-CbneC7bS.d.ts → strategy-BtW8fAjz.d.cts} +1 -1
- package/dist/{strategy-CbneC7bS.d.cts → strategy-BtW8fAjz.d.ts} +1 -1
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +3 -3
- package/dist/sync/index.d.ts +3 -3
- package/dist/sync/index.js +2 -2
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +4 -4
- package/dist/team/index.d.ts +4 -4
- package/dist/team/index.js +5 -5
- package/dist/tx/index.cjs +66 -3
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +22 -6
- package/dist/tx/index.d.ts +22 -6
- package/dist/tx/index.js +7 -3
- package/dist/tx/index.js.map +1 -1
- package/dist/{types-BpPV5uyy.d.cts → types-Bze6vkwm.d.cts} +371 -139
- package/dist/{types-4t1-tWS4.d.ts → types-DrmBTscX.d.ts} +371 -139
- package/dist/{ulid-DAfenvFd.d.ts → ulid-DbBVrNSt.d.ts} +1 -1
- package/dist/{ulid-CiPrpGqm.d.cts → ulid-DfZlAh0u.d.cts} +1 -1
- package/dist/{vault-group-KOM7QRJG.js → vault-group-DX2HFQMX.js} +2 -2
- package/dist/{with-derivation-DBqJB3dQ.d.cts → with-derivation-CCqAchD5.d.cts} +1 -1
- package/dist/{with-derivation-OK9M2sJE.d.ts → with-derivation-_lySGdlm.d.ts} +1 -1
- package/dist/{with-materialized-view-NzuxYPDF.d.cts → with-materialized-view--4PsvMDu.d.cts} +1 -1
- package/dist/{with-materialized-view-Dt-ufPWQ.d.ts → with-materialized-view-QT1Tp7NO.d.ts} +1 -1
- package/dist/{with-overlayed-view-eDvMs6LO.d.ts → with-overlayed-view-BEXfpzSb.d.ts} +1 -1
- package/dist/{with-overlayed-view-CC0_ocy-.d.cts → with-overlayed-view-DlH5qmeB.d.cts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-3EWXMOK3.js.map +0 -1
- package/dist/chunk-5LQG6ZO2.js.map +0 -1
- package/dist/chunk-7EFFHEN5.js.map +0 -1
- package/dist/chunk-C5T5AFWN.js.map +0 -1
- package/dist/chunk-DQU36Q7I.js.map +0 -1
- package/dist/chunk-EGD5DXFT.js.map +0 -1
- package/dist/chunk-OHVFWCJP.js.map +0 -1
- package/dist/chunk-VU7SWWT5.js.map +0 -1
- package/dist/chunk-YHPM5D7Y.js.map +0 -1
- package/dist/noydb-GZGFBA4E.js +0 -35
- /package/dist/{chunk-BIYRQQV6.js.map → chunk-3YWP3WBP.js.map} +0 -0
- /package/dist/{chunk-A5ZOOZFB.js.map → chunk-6H2ZUNR7.js.map} +0 -0
- /package/dist/{chunk-7HT2MEZ5.js.map → chunk-7BQ4QWYX.js.map} +0 -0
- /package/dist/{chunk-WBAYSNUQ.js.map → chunk-BI6ETQPF.js.map} +0 -0
- /package/dist/{chunk-56DJ7JVK.js.map → chunk-BR3AMFGS.js.map} +0 -0
- /package/dist/{chunk-COFPAMX6.js.map → chunk-DLZ2ONOD.js.map} +0 -0
- /package/dist/{chunk-EYVQHAGH.js.map → chunk-DUREQF5W.js.map} +0 -0
- /package/dist/{chunk-PE4AQGFH.js.map → chunk-E2CDVKMH.js.map} +0 -0
- /package/dist/{chunk-L2FE64BU.js.map → chunk-FFXM3ZIF.js.map} +0 -0
- /package/dist/{chunk-WGHU7BLI.js.map → chunk-GNI5STXQ.js.map} +0 -0
- /package/dist/{chunk-7PS7EOCF.js.map → chunk-IXBIFDEW.js.map} +0 -0
- /package/dist/{chunk-LX3CB26H.js.map → chunk-KABJXG2F.js.map} +0 -0
- /package/dist/{chunk-DKO2QFSA.js.map → chunk-OB2ZJQ2D.js.map} +0 -0
- /package/dist/{chunk-KIP6JLTF.js.map → chunk-OMAMZKKD.js.map} +0 -0
- /package/dist/{chunk-KI6HAJWL.js.map → chunk-QSUK7YWK.js.map} +0 -0
- /package/dist/{chunk-NSCVNK5K.js.map → chunk-SCJPI4Z5.js.map} +0 -0
- /package/dist/{chunk-6AJBSQU4.js.map → chunk-XL35NSEN.js.map} +0 -0
- /package/dist/{executor-HSSRXDOB.js.map → executor-AZLS3KBK.js.map} +0 -0
- /package/dist/{fanout-sidecar-N6OJX6QR.js.map → fanout-sidecar-67CMI3UT.js.map} +0 -0
- /package/dist/{issue-ADVS4OVP.js.map → issue-RZP3VI6O.js.map} +0 -0
- /package/dist/{ledger-CWSE3BLF.js.map → ledger-A3LL253R.js.map} +0 -0
- /package/dist/{noydb-GZGFBA4E.js.map → noydb-WCMY2ZOW.js.map} +0 -0
- /package/dist/{public-envelope-SYHEYQ3X.js.map → public-envelope-YP2UWMLG.js.map} +0 -0
- /package/dist/{registry-DK5YWAAA.js.map → registry-EB6SISTA.js.map} +0 -0
- /package/dist/{registry-XGLNADIE.js.map → registry-UTA4CLQS.js.map} +0 -0
- /package/dist/{revoke-ZDFKMR5E.js.map → revoke-HNMQZSCL.js.map} +0 -0
- /package/dist/{signer-P5D7Y72U.js.map → signer-DCMNKXSF.js.map} +0 -0
- /package/dist/{stale-JH67FU57.js.map → stale-W5PQTRYH.js.map} +0 -0
- /package/dist/{vault-group-KOM7QRJG.js.map → vault-group-DX2HFQMX.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -2879,13 +2879,22 @@ var init_predicate = __esm({
|
|
|
2879
2879
|
});
|
|
2880
2880
|
|
|
2881
2881
|
// src/money/money-reducer.ts
|
|
2882
|
-
function
|
|
2883
|
-
if (typeof v === "
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2882
|
+
function toScaledIntFromAny(v, scale) {
|
|
2883
|
+
if (typeof v === "bigint") return v;
|
|
2884
|
+
if (typeof v === "number") {
|
|
2885
|
+
const r = parseToScaledInt(v, scale);
|
|
2886
|
+
return r.ok ? r.value : null;
|
|
2887
|
+
}
|
|
2888
|
+
if (typeof v === "string") {
|
|
2889
|
+
if (!v.includes(".")) {
|
|
2890
|
+
try {
|
|
2891
|
+
return BigInt(v);
|
|
2892
|
+
} catch {
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2888
2895
|
}
|
|
2896
|
+
const r = parseToScaledInt(v, scale);
|
|
2897
|
+
return r.ok ? r.value : null;
|
|
2889
2898
|
}
|
|
2890
2899
|
return null;
|
|
2891
2900
|
}
|
|
@@ -2893,13 +2902,15 @@ function readMoney(record, field, desc) {
|
|
|
2893
2902
|
const raw = readPath(record, field);
|
|
2894
2903
|
if (raw === null || raw === void 0) return null;
|
|
2895
2904
|
if (desc.mode === "fixed") {
|
|
2896
|
-
const
|
|
2897
|
-
|
|
2905
|
+
const cur = desc.fixedCurrency;
|
|
2906
|
+
const value2 = toScaledIntFromAny(raw, desc.scaleFor(cur));
|
|
2907
|
+
return value2 === null ? null : { currency: cur, value: value2 };
|
|
2898
2908
|
}
|
|
2899
2909
|
if (typeof raw !== "object") return null;
|
|
2900
2910
|
const o = raw;
|
|
2901
2911
|
if (typeof o.currency !== "string") return null;
|
|
2902
|
-
const
|
|
2912
|
+
const scale = desc.allows(o.currency) ? desc.scaleFor(o.currency) : 0;
|
|
2913
|
+
const value = toScaledIntFromAny(o.amount, scale);
|
|
2903
2914
|
return value === null ? null : { currency: o.currency, value };
|
|
2904
2915
|
}
|
|
2905
2916
|
function targetScaleFor(desc, currency) {
|
|
@@ -3217,11 +3228,14 @@ function warnCardinalityApproaching(fields, observed) {
|
|
|
3217
3228
|
`[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.`
|
|
3218
3229
|
);
|
|
3219
3230
|
}
|
|
3220
|
-
function groupAndReduce(records, fieldOrFields, spec) {
|
|
3231
|
+
function groupAndReduce(records, fieldOrFields, spec, moneyFields) {
|
|
3221
3232
|
const fields = typeof fieldOrFields === "string" ? [fieldOrFields] : fieldOrFields;
|
|
3222
3233
|
if (fields.length === 0) {
|
|
3223
3234
|
throw new Error(".groupBy() requires at least one field");
|
|
3224
3235
|
}
|
|
3236
|
+
if (moneyFields) {
|
|
3237
|
+
spec = wrapMoneyReducers(spec, moneyFields);
|
|
3238
|
+
}
|
|
3225
3239
|
const buckets = /* @__PURE__ */ new Map();
|
|
3226
3240
|
const fieldLabel = fields.length === 1 ? fields[0] : `[${fields.join(", ")}]`;
|
|
3227
3241
|
for (const record of records) {
|
|
@@ -3664,10 +3678,14 @@ function summarizeQueryPlan(query) {
|
|
|
3664
3678
|
});
|
|
3665
3679
|
}
|
|
3666
3680
|
function summarizeUnionPlan(spec) {
|
|
3667
|
-
const arms = (spec.unionSources ?? []).map((s) =>
|
|
3681
|
+
const arms = (spec.unionSources ?? []).map((s) => {
|
|
3682
|
+
const joins = s.join?.length ? `[${s.join.map((j) => `${j.field}\u2192${j.as}`).join(";")}]` : "";
|
|
3683
|
+
return `${s.collection}${joins}`;
|
|
3684
|
+
}).join(",");
|
|
3668
3685
|
const groupBy = Array.isArray(spec.groupBy) ? [...spec.groupBy].sort().join(",") : typeof spec.groupBy === "string" ? spec.groupBy : "";
|
|
3669
3686
|
const aggKeys = spec.aggregate ? Object.keys(spec.aggregate).sort().join(",") : "";
|
|
3670
|
-
|
|
3687
|
+
const moneyKeys = spec.moneyFields ? Object.keys(spec.moneyFields).sort().join(",") : "";
|
|
3688
|
+
return `union(${arms})|groupBy(${groupBy})|aggregate(${aggKeys})|money(${moneyKeys})`;
|
|
3671
3689
|
}
|
|
3672
3690
|
var init_dependency_analyzer = __esm({
|
|
3673
3691
|
"src/materialized-views/dependency-analyzer.ts"() {
|
|
@@ -3794,6 +3812,7 @@ var init_registry = __esm({
|
|
|
3794
3812
|
let isQuery = false;
|
|
3795
3813
|
if (spec.unionSources) {
|
|
3796
3814
|
dependencies = new Set(spec.unionSources.map((s) => s.collection));
|
|
3815
|
+
if (spec.sources) for (const s of spec.sources) dependencies.add(s);
|
|
3797
3816
|
queryPlanSummary = summarizeUnionPlan(spec);
|
|
3798
3817
|
} else {
|
|
3799
3818
|
const q = spec.query(dbForQuery);
|
|
@@ -3948,7 +3967,13 @@ async function materializeUnionResult(spec, db) {
|
|
|
3948
3967
|
const unified = [];
|
|
3949
3968
|
for (const arm of spec.unionSources) {
|
|
3950
3969
|
const coll = db.collection(arm.collection);
|
|
3951
|
-
|
|
3970
|
+
let q = coll.query();
|
|
3971
|
+
if (arm.join?.length) {
|
|
3972
|
+
for (const leg of arm.join) {
|
|
3973
|
+
q = q.join(leg.field, { as: leg.as, maxRows: leg.maxRows, strategy: leg.strategy });
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
const sourceRows = q.toArray();
|
|
3952
3977
|
for (const r of sourceRows) {
|
|
3953
3978
|
const mapped = arm.map(r);
|
|
3954
3979
|
if (mapped == null) continue;
|
|
@@ -3965,7 +3990,7 @@ async function materializeUnionResult(spec, db) {
|
|
|
3965
3990
|
}
|
|
3966
3991
|
return [...seen.values()];
|
|
3967
3992
|
}
|
|
3968
|
-
return groupAndReduce(unified, groupFields, spec.aggregate);
|
|
3993
|
+
return groupAndReduce(unified, groupFields, spec.aggregate, spec.moneyFields);
|
|
3969
3994
|
}
|
|
3970
3995
|
async function listOutputIds(outputColl) {
|
|
3971
3996
|
const cAny = outputColl;
|
|
@@ -4520,11 +4545,15 @@ var init_read_only_facade = __esm({
|
|
|
4520
4545
|
});
|
|
4521
4546
|
|
|
4522
4547
|
// src/derivations/strategy-hash.ts
|
|
4523
|
-
async function computeStrategyHash(source, outputKeys, derive) {
|
|
4548
|
+
async function computeStrategyHash(source, outputKeys, derive, sources) {
|
|
4524
4549
|
const canonical2 = JSON.stringify({
|
|
4525
4550
|
source,
|
|
4526
4551
|
outputs: [...outputKeys].sort(),
|
|
4527
|
-
derive: derive.toString()
|
|
4552
|
+
derive: derive.toString(),
|
|
4553
|
+
// Declared sibling sources (#344) — adding/removing a trigger
|
|
4554
|
+
// collection invalidates cached derived records. Omitted when empty
|
|
4555
|
+
// so strategies without siblings keep their existing hash.
|
|
4556
|
+
...sources?.length ? { sources: [...sources].sort() } : {}
|
|
4528
4557
|
});
|
|
4529
4558
|
const bytes = new TextEncoder().encode(canonical2);
|
|
4530
4559
|
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
@@ -4553,11 +4582,16 @@ var init_registry3 = __esm({
|
|
|
4553
4582
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4554
4583
|
async register(spec) {
|
|
4555
4584
|
const outputKeys = Object.keys(spec.outputs);
|
|
4556
|
-
const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive);
|
|
4585
|
+
const strategyHash = await computeStrategyHash(spec.source, outputKeys, spec.derive, spec.sources);
|
|
4557
4586
|
const reg = { spec, strategyHash };
|
|
4558
4587
|
const fromSource = this._bySource.get(spec.source);
|
|
4559
4588
|
if (fromSource) fromSource.push(reg);
|
|
4560
4589
|
else this._bySource.set(spec.source, [reg]);
|
|
4590
|
+
for (const extra of spec.sources ?? []) {
|
|
4591
|
+
const fromExtra = this._bySource.get(extra);
|
|
4592
|
+
if (fromExtra) fromExtra.push(reg);
|
|
4593
|
+
else this._bySource.set(extra, [reg]);
|
|
4594
|
+
}
|
|
4561
4595
|
for (const key of outputKeys) {
|
|
4562
4596
|
const output = spec.outputs[key];
|
|
4563
4597
|
if (!output) continue;
|
|
@@ -5892,6 +5926,7 @@ __export(src_exports, {
|
|
|
5892
5926
|
resolveI18nText: () => resolveI18nText,
|
|
5893
5927
|
resolvePolicy: () => resolvePolicy,
|
|
5894
5928
|
resolvePublicEnvelopeSchema: () => resolveSchema,
|
|
5929
|
+
resolveSequenceKey: () => resolveSequenceKey,
|
|
5895
5930
|
resolveSession: () => resolveSession,
|
|
5896
5931
|
revokeAllSessions: () => revokeAllSessions,
|
|
5897
5932
|
revokeDelegation: () => revokeDelegation,
|
|
@@ -7990,6 +8025,21 @@ init_crypto();
|
|
|
7990
8025
|
init_errors();
|
|
7991
8026
|
var SEQUENCE_COLLECTION = "_sequences";
|
|
7992
8027
|
var MAX_NEXT_ATTEMPTS = 16;
|
|
8028
|
+
function resolveSequenceKey(series, opts) {
|
|
8029
|
+
const partition = opts?.partition;
|
|
8030
|
+
if (!partition || partition.length === 0) return series;
|
|
8031
|
+
const parts = partition.map((p) => {
|
|
8032
|
+
if (typeof p === "number" && !Number.isFinite(p)) {
|
|
8033
|
+
throw new ValidationError(`sequence partition component must be a finite number, got ${p}`);
|
|
8034
|
+
}
|
|
8035
|
+
const s = String(p);
|
|
8036
|
+
if (s === "") {
|
|
8037
|
+
throw new ValidationError("sequence partition component must not be empty");
|
|
8038
|
+
}
|
|
8039
|
+
return encodeURIComponent(s);
|
|
8040
|
+
});
|
|
8041
|
+
return `${series}\0${parts.join("/")}`;
|
|
8042
|
+
}
|
|
7993
8043
|
async function sleepBackoff(attempt) {
|
|
7994
8044
|
const ceil = Math.min(2 ** attempt, 32);
|
|
7995
8045
|
const ms = Math.floor(Math.random() * ceil);
|
|
@@ -8020,7 +8070,8 @@ var SequenceStore = class {
|
|
|
8020
8070
|
handle(name) {
|
|
8021
8071
|
return {
|
|
8022
8072
|
next: () => this.next(name),
|
|
8023
|
-
peek: () => this.peek(name)
|
|
8073
|
+
peek: () => this.peek(name),
|
|
8074
|
+
seedTo: (n) => this.seedTo(name, n)
|
|
8024
8075
|
};
|
|
8025
8076
|
}
|
|
8026
8077
|
assertOnline() {
|
|
@@ -8073,6 +8124,30 @@ var SequenceStore = class {
|
|
|
8073
8124
|
void lastConflict;
|
|
8074
8125
|
throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS);
|
|
8075
8126
|
}
|
|
8127
|
+
async seedTo(name, n) {
|
|
8128
|
+
this.assertOnline();
|
|
8129
|
+
if (n <= 0) return;
|
|
8130
|
+
let lastConflict;
|
|
8131
|
+
for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {
|
|
8132
|
+
const { env, value } = await this.read(name);
|
|
8133
|
+
if (value >= n) return;
|
|
8134
|
+
const expectedVersion = env?._v ?? 0;
|
|
8135
|
+
const envelope = await this.encryptState({ value: n }, expectedVersion + 1);
|
|
8136
|
+
try {
|
|
8137
|
+
await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion);
|
|
8138
|
+
return;
|
|
8139
|
+
} catch (err) {
|
|
8140
|
+
if (err instanceof ConflictError) {
|
|
8141
|
+
lastConflict = err;
|
|
8142
|
+
if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt);
|
|
8143
|
+
continue;
|
|
8144
|
+
}
|
|
8145
|
+
throw err;
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
void lastConflict;
|
|
8149
|
+
throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS);
|
|
8150
|
+
}
|
|
8076
8151
|
};
|
|
8077
8152
|
|
|
8078
8153
|
// src/numbering/descriptor.ts
|
|
@@ -14599,7 +14674,7 @@ var TxCollection = class {
|
|
|
14599
14674
|
this._ctx._ops.push(op);
|
|
14600
14675
|
}
|
|
14601
14676
|
};
|
|
14602
|
-
async function runTransaction(db, fn, options) {
|
|
14677
|
+
async function runTransaction(db, fn, options, txInvariants) {
|
|
14603
14678
|
if (options?.amendment) {
|
|
14604
14679
|
if (typeof options.reason !== "string" || options.reason.trim().length === 0) {
|
|
14605
14680
|
throw new ValidationError(
|
|
@@ -14623,12 +14698,19 @@ async function runTransaction(db, fn, options) {
|
|
|
14623
14698
|
}
|
|
14624
14699
|
const priorEnvelopes = /* @__PURE__ */ new Map();
|
|
14625
14700
|
const store = db._store;
|
|
14701
|
+
const invariants = txInvariants ?? [];
|
|
14702
|
+
const watchedScopes = new Set(invariants.map((i) => i.scope));
|
|
14703
|
+
const plainBefore = /* @__PURE__ */ new Map();
|
|
14626
14704
|
for (const op of ctx._ops) {
|
|
14627
14705
|
const key = keyOf(op);
|
|
14628
14706
|
if (!priorEnvelopes.has(key)) {
|
|
14629
14707
|
const env = await store.get(op.vaultName, op.collectionName, op.id);
|
|
14630
14708
|
priorEnvelopes.set(key, env);
|
|
14631
14709
|
}
|
|
14710
|
+
if (watchedScopes.has(op.collectionName) && !plainBefore.has(key)) {
|
|
14711
|
+
const prior = await db.vault(op.vaultName).collection(op.collectionName).get(op.id);
|
|
14712
|
+
plainBefore.set(key, prior ?? null);
|
|
14713
|
+
}
|
|
14632
14714
|
if (op.expectedVersion !== void 0) {
|
|
14633
14715
|
const env = priorEnvelopes.get(key) ?? null;
|
|
14634
14716
|
const actual = env?._v ?? 0;
|
|
@@ -14726,6 +14808,58 @@ async function runTransaction(db, fn, options) {
|
|
|
14726
14808
|
);
|
|
14727
14809
|
}
|
|
14728
14810
|
}
|
|
14811
|
+
if (invariants.length > 0) {
|
|
14812
|
+
const lastOp = /* @__PURE__ */ new Map();
|
|
14813
|
+
const order = [];
|
|
14814
|
+
for (const op of ctx._ops) {
|
|
14815
|
+
const key = keyOf(op);
|
|
14816
|
+
if (!lastOp.has(key)) order.push(key);
|
|
14817
|
+
lastOp.set(key, op);
|
|
14818
|
+
}
|
|
14819
|
+
const changesByScope = /* @__PURE__ */ new Map();
|
|
14820
|
+
const scopeVault = /* @__PURE__ */ new Map();
|
|
14821
|
+
for (const key of order) {
|
|
14822
|
+
const op = lastOp.get(key);
|
|
14823
|
+
if (!watchedScopes.has(op.collectionName)) continue;
|
|
14824
|
+
const before = plainBefore.get(key) ?? null;
|
|
14825
|
+
const after = op.type === "delete" ? null : op.record ?? null;
|
|
14826
|
+
const change = { before, after };
|
|
14827
|
+
const arr = changesByScope.get(op.collectionName);
|
|
14828
|
+
if (arr) arr.push(change);
|
|
14829
|
+
else changesByScope.set(op.collectionName, [change]);
|
|
14830
|
+
scopeVault.set(op.collectionName, op.vaultName);
|
|
14831
|
+
}
|
|
14832
|
+
try {
|
|
14833
|
+
for (const inv of invariants) {
|
|
14834
|
+
const changes = changesByScope.get(inv.scope);
|
|
14835
|
+
if (changes === void 0 || changes.length === 0) continue;
|
|
14836
|
+
const vaultName = scopeVault.get(inv.scope);
|
|
14837
|
+
const v = db.vault(vaultName);
|
|
14838
|
+
const facade = v._getReadOnlyFacade() ?? {
|
|
14839
|
+
collection(name) {
|
|
14840
|
+
const c = v.collection(name);
|
|
14841
|
+
return {
|
|
14842
|
+
get: (id) => c.get(id),
|
|
14843
|
+
list: () => c.list(),
|
|
14844
|
+
query: () => c.query()
|
|
14845
|
+
};
|
|
14846
|
+
}
|
|
14847
|
+
};
|
|
14848
|
+
const ctxForInv = {
|
|
14849
|
+
existing: null,
|
|
14850
|
+
vault: facade,
|
|
14851
|
+
userId: v.userId,
|
|
14852
|
+
role: v.role
|
|
14853
|
+
};
|
|
14854
|
+
await inv.check(changes, ctxForInv);
|
|
14855
|
+
}
|
|
14856
|
+
} catch (err) {
|
|
14857
|
+
await revertExecuted(ctx._executed, store, db);
|
|
14858
|
+
throw err instanceof InvariantError ? err : new InvariantError(
|
|
14859
|
+
err instanceof Error ? err.message : `invariant violated: ${String(err)}`
|
|
14860
|
+
);
|
|
14861
|
+
}
|
|
14862
|
+
}
|
|
14729
14863
|
return bodyResult;
|
|
14730
14864
|
}
|
|
14731
14865
|
async function revertExecuted(executed, store, db) {
|
|
@@ -15731,9 +15865,18 @@ var Collection = class {
|
|
|
15731
15865
|
if (DerivationExecutor2 === null) {
|
|
15732
15866
|
({ DerivationExecutor: DerivationExecutor2 } = await Promise.resolve().then(() => (init_executor2(), executor_exports2)));
|
|
15733
15867
|
}
|
|
15734
|
-
|
|
15868
|
+
let sourceWithId;
|
|
15869
|
+
let sourceVersion = version;
|
|
15870
|
+
if (spec.source === this.name) {
|
|
15871
|
+
sourceWithId = { ...incoming, id };
|
|
15872
|
+
} else {
|
|
15873
|
+
const primary = await this.derivationSource.getCollection(spec.source).get(id);
|
|
15874
|
+
if (primary === null || primary === void 0) continue;
|
|
15875
|
+
sourceWithId = { ...primary, id };
|
|
15876
|
+
sourceVersion = 0;
|
|
15877
|
+
}
|
|
15735
15878
|
const ctx = { vault: this.derivationSource.getReadOnlyFacade() };
|
|
15736
|
-
const result = await DerivationExecutor2.run(spec, sourceWithId,
|
|
15879
|
+
const result = await DerivationExecutor2.run(spec, sourceWithId, sourceVersion, strategyHash, ctx);
|
|
15737
15880
|
for (const key of Object.keys(spec.outputs)) {
|
|
15738
15881
|
const out = result.outputs[key];
|
|
15739
15882
|
if (!out) continue;
|
|
@@ -17716,37 +17859,34 @@ var OverlayedCollection = class {
|
|
|
17716
17859
|
/** Get the merged row by id. */
|
|
17717
17860
|
async get(id) {
|
|
17718
17861
|
const overlayRow = await this.overlayCollection.get(id);
|
|
17719
|
-
if (overlayRow !== null && this.shadowPredicateApplies(overlayRow)) {
|
|
17720
|
-
return overlayRow;
|
|
17721
|
-
}
|
|
17722
17862
|
const baseRow = await this.baseCollection.get(id);
|
|
17723
|
-
|
|
17724
|
-
return null;
|
|
17863
|
+
return this.mergeRows(overlayRow, baseRow);
|
|
17725
17864
|
}
|
|
17726
17865
|
/** List union of base + overlay ids, applying the merge per row. */
|
|
17727
17866
|
async list() {
|
|
17728
17867
|
const baseRows = await this.baseCollection.list();
|
|
17729
17868
|
const overlayRows = await this.overlayCollection.list();
|
|
17730
|
-
const merged = /* @__PURE__ */ new Map();
|
|
17731
17869
|
const idOf = (row) => {
|
|
17732
17870
|
if (this.baseRowKey) return this.baseRowKey(row);
|
|
17733
17871
|
const idField = row.id;
|
|
17734
17872
|
return typeof idField === "string" ? idField : "";
|
|
17735
17873
|
};
|
|
17874
|
+
const baseById = /* @__PURE__ */ new Map();
|
|
17875
|
+
const overlayById = /* @__PURE__ */ new Map();
|
|
17736
17876
|
for (const row of baseRows) {
|
|
17737
17877
|
const id = idOf(row);
|
|
17738
|
-
if (id)
|
|
17878
|
+
if (id) baseById.set(id, row);
|
|
17739
17879
|
}
|
|
17740
17880
|
for (const row of overlayRows) {
|
|
17741
17881
|
const id = idOf(row);
|
|
17742
|
-
if (
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17882
|
+
if (id) overlayById.set(id, row);
|
|
17883
|
+
}
|
|
17884
|
+
const out = [];
|
|
17885
|
+
for (const id of /* @__PURE__ */ new Set([...baseById.keys(), ...overlayById.keys()])) {
|
|
17886
|
+
const merged = this.mergeRows(overlayById.get(id) ?? null, baseById.get(id) ?? null);
|
|
17887
|
+
if (merged !== null) out.push(merged);
|
|
17748
17888
|
}
|
|
17749
|
-
return
|
|
17889
|
+
return out;
|
|
17750
17890
|
}
|
|
17751
17891
|
/**
|
|
17752
17892
|
* Write to the overlay. Two forms:
|
|
@@ -17786,9 +17926,42 @@ var OverlayedCollection = class {
|
|
|
17786
17926
|
async delete(id) {
|
|
17787
17927
|
await this.overlayCollection.delete(id);
|
|
17788
17928
|
}
|
|
17789
|
-
/**
|
|
17790
|
-
|
|
17791
|
-
|
|
17929
|
+
/**
|
|
17930
|
+
* Merge a single id's overlay + base rows into the visible row.
|
|
17931
|
+
*
|
|
17932
|
+
* Priority (first match wins):
|
|
17933
|
+
* 1. Binary shadow win — overlay present AND
|
|
17934
|
+
* `overlay[shadowField] === shadowValue` → return the overlay row
|
|
17935
|
+
* entirely. This stays FIRST so the original binary behaviour is
|
|
17936
|
+
* unchanged whether or not `mergeMode` is configured.
|
|
17937
|
+
* 2. Field-level merge — overlay present, `mergeMode` configured,
|
|
17938
|
+
* and a rule whose `whenStatus` equals `overlay[shadowField]`.
|
|
17939
|
+
* The matched rule pulls its `overlayFields` (those present on
|
|
17940
|
+
* the overlay row) on top of the base row. With no base row, the
|
|
17941
|
+
* overlay row is returned as-is.
|
|
17942
|
+
* 3. Fallback — return the base row (possibly `null`). An
|
|
17943
|
+
* overlay-only row that qualifies under neither (1) nor (2) and
|
|
17944
|
+
* has no base is therefore NOT surfaced.
|
|
17945
|
+
*/
|
|
17946
|
+
mergeRows(overlayRow, baseRow) {
|
|
17947
|
+
const shadowField = this.spec.shadowField;
|
|
17948
|
+
if (overlayRow !== null && overlayRow[shadowField] === this.spec.shadowValue) {
|
|
17949
|
+
return overlayRow;
|
|
17950
|
+
}
|
|
17951
|
+
if (overlayRow !== null && this.spec.mergeMode) {
|
|
17952
|
+
const status = overlayRow[shadowField];
|
|
17953
|
+
const rule = this.spec.mergeMode.rules.find((r) => r.whenStatus === status);
|
|
17954
|
+
if (rule) {
|
|
17955
|
+
if (baseRow === null) return overlayRow;
|
|
17956
|
+
const overlaySrc = overlayRow;
|
|
17957
|
+
const picked = {};
|
|
17958
|
+
for (const field of rule.overlayFields) {
|
|
17959
|
+
if (field in overlaySrc) picked[field] = overlaySrc[field];
|
|
17960
|
+
}
|
|
17961
|
+
return { ...baseRow, ...picked };
|
|
17962
|
+
}
|
|
17963
|
+
}
|
|
17964
|
+
return baseRow;
|
|
17792
17965
|
}
|
|
17793
17966
|
// ─── Throw-stubs for the unimplemented Collection<T> surface ───────
|
|
17794
17967
|
//
|
|
@@ -20212,17 +20385,23 @@ var Vault = class {
|
|
|
20212
20385
|
* const cur = await vault.sequence('invoice-2026').peek() // current value, no allocation
|
|
20213
20386
|
* ```
|
|
20214
20387
|
*/
|
|
20215
|
-
sequence(
|
|
20216
|
-
if (
|
|
20388
|
+
sequence(series, opts) {
|
|
20389
|
+
if (series.includes("\0")) {
|
|
20390
|
+
throw new ValidationError(`sequence("${series}"): series name must not contain a null byte (\\x00).`);
|
|
20391
|
+
}
|
|
20392
|
+
if (this.numberingConfigs.has(series)) {
|
|
20217
20393
|
const eng = this.deferred();
|
|
20218
20394
|
return {
|
|
20219
|
-
next: async (
|
|
20220
|
-
if (!
|
|
20221
|
-
throw new ValidationError(`sequence("${
|
|
20395
|
+
next: async (nextOpts) => {
|
|
20396
|
+
if (!nextOpts?.for) {
|
|
20397
|
+
throw new ValidationError(`sequence("${series}") is a deferred-numbering series; call next({ for: recordId }).`);
|
|
20222
20398
|
}
|
|
20223
|
-
return (await eng.enqueue(
|
|
20399
|
+
return (await eng.enqueue(series, nextOpts.for)).assigned;
|
|
20224
20400
|
},
|
|
20225
|
-
peek: () => eng.peek(
|
|
20401
|
+
peek: () => eng.peek(series),
|
|
20402
|
+
seedTo: () => {
|
|
20403
|
+
throw new ValidationError(`sequence("${series}") is a deferred-numbering series; seedTo is CAS-only.`);
|
|
20404
|
+
}
|
|
20226
20405
|
};
|
|
20227
20406
|
}
|
|
20228
20407
|
if (!this.sequenceStore) {
|
|
@@ -20234,7 +20413,7 @@ var Vault = class {
|
|
|
20234
20413
|
actor: this.keyring.userId
|
|
20235
20414
|
});
|
|
20236
20415
|
}
|
|
20237
|
-
return this.sequenceStore.handle(
|
|
20416
|
+
return this.sequenceStore.handle(resolveSequenceKey(series, opts));
|
|
20238
20417
|
}
|
|
20239
20418
|
/** @internal — lazily build the deferred-numbering engine with a cache-coherent stamp. */
|
|
20240
20419
|
deferred() {
|
|
@@ -20526,9 +20705,24 @@ var Vault = class {
|
|
|
20526
20705
|
});
|
|
20527
20706
|
}
|
|
20528
20707
|
if (rule.mode === "cascade") {
|
|
20708
|
+
const txCtx = this.noydb._activeTxContextOrNull;
|
|
20529
20709
|
for (const match of matches) {
|
|
20530
20710
|
const matchId = match["id"] ?? null;
|
|
20531
20711
|
if (matchId === null) continue;
|
|
20712
|
+
if (txCtx !== null) {
|
|
20713
|
+
const prior = await this.adapter.get(this.name, rule.collection, matchId);
|
|
20714
|
+
if (prior !== null) {
|
|
20715
|
+
txCtx._executed.push({
|
|
20716
|
+
op: {
|
|
20717
|
+
type: "delete",
|
|
20718
|
+
vaultName: this.name,
|
|
20719
|
+
collectionName: rule.collection,
|
|
20720
|
+
id: matchId
|
|
20721
|
+
},
|
|
20722
|
+
priorEnvelope: prior
|
|
20723
|
+
});
|
|
20724
|
+
}
|
|
20725
|
+
}
|
|
20532
20726
|
await fromCollection.delete(matchId);
|
|
20533
20727
|
}
|
|
20534
20728
|
}
|
|
@@ -22727,7 +22921,7 @@ var NOT_ENABLED6 = new Error(
|
|
|
22727
22921
|
'Multi-record transactions require the tx strategy. Import `{ withTransactions }` from "@noy-db/hub/tx" and pass it to `createNoydb({ txStrategy: withTransactions() })`.'
|
|
22728
22922
|
);
|
|
22729
22923
|
var NO_TX = {
|
|
22730
|
-
async runTransaction() {
|
|
22924
|
+
async runTransaction(_db, _fn, _options, _txInvariants) {
|
|
22731
22925
|
throw NOT_ENABLED6;
|
|
22732
22926
|
},
|
|
22733
22927
|
async runDryRun() {
|
|
@@ -26045,7 +26239,7 @@ function recordId2(record) {
|
|
|
26045
26239
|
return typeof id === "string" ? id : "";
|
|
26046
26240
|
}
|
|
26047
26241
|
function immutableGuard(config) {
|
|
26048
|
-
const { collection, after, appendOnly, amendmentRoles } = config;
|
|
26242
|
+
const { collection, after, appendOnly, amendmentRoles, amendmentInvariant } = config;
|
|
26049
26243
|
if (appendOnly && after !== void 0) {
|
|
26050
26244
|
throw new ValidationError("immutableGuard: `after` and `appendOnly` are mutually exclusive");
|
|
26051
26245
|
}
|
|
@@ -26071,12 +26265,16 @@ function immutableGuard(config) {
|
|
|
26071
26265
|
}
|
|
26072
26266
|
},
|
|
26073
26267
|
// The authorized override: inside an amendment transaction the
|
|
26074
|
-
// check/onDelete are skipped and the change is ledgered.
|
|
26075
|
-
// invariant — the amendment itself is the
|
|
26268
|
+
// check/onDelete are skipped and the change is ledgered. By default
|
|
26269
|
+
// there is no extra invariant — the amendment itself is the
|
|
26270
|
+
// sanctioned exception. Callers may supply `amendmentInvariant` to
|
|
26271
|
+
// keep a constraint inviolable even under amendment (e.g. forbid
|
|
26272
|
+
// deletes, or preserve a cross-record sum); a throw reverts the
|
|
26273
|
+
// amendment and surfaces as `InvariantError`.
|
|
26076
26274
|
amendment: {
|
|
26077
26275
|
roles: amendmentRoles ?? ["admin", "owner"],
|
|
26078
|
-
invariant: () => {
|
|
26079
|
-
}
|
|
26276
|
+
invariant: amendmentInvariant ?? (() => {
|
|
26277
|
+
})
|
|
26080
26278
|
}
|
|
26081
26279
|
};
|
|
26082
26280
|
return withGuard(spec);
|
|
@@ -26097,6 +26295,18 @@ function withDerivation(spec) {
|
|
|
26097
26295
|
if (typeof spec.derive !== "function") {
|
|
26098
26296
|
throw new ValidationError("withDerivation: derive must be a function");
|
|
26099
26297
|
}
|
|
26298
|
+
if (spec.sources !== void 0) {
|
|
26299
|
+
for (const extra of spec.sources) {
|
|
26300
|
+
if (typeof extra !== "string" || extra.length === 0) {
|
|
26301
|
+
throw new ValidationError("withDerivation: each entry in sources[] must be a non-empty string");
|
|
26302
|
+
}
|
|
26303
|
+
if (extra === spec.source) {
|
|
26304
|
+
throw new ValidationError(
|
|
26305
|
+
`withDerivation: sources[] must not contain the primary source "${spec.source}"`
|
|
26306
|
+
);
|
|
26307
|
+
}
|
|
26308
|
+
}
|
|
26309
|
+
}
|
|
26100
26310
|
const lifecycleMode = typeof spec.lifecycle === "string" ? spec.lifecycle : spec.lifecycle.mode;
|
|
26101
26311
|
for (const [outputKey, outputSpec] of Object.entries(spec.outputs)) {
|
|
26102
26312
|
if (outputSpec.shape === "array") {
|
|
@@ -26183,6 +26393,16 @@ function withMaterializedView(spec) {
|
|
|
26183
26393
|
`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`
|
|
26184
26394
|
);
|
|
26185
26395
|
}
|
|
26396
|
+
if (spec.moneyFields && !spec.aggregate) {
|
|
26397
|
+
throw new MaterializedViewConfigError(
|
|
26398
|
+
`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`
|
|
26399
|
+
);
|
|
26400
|
+
}
|
|
26401
|
+
if (spec.unionSources.some((s) => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {
|
|
26402
|
+
throw new MaterializedViewConfigError(
|
|
26403
|
+
`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`
|
|
26404
|
+
);
|
|
26405
|
+
}
|
|
26186
26406
|
if (spec.predicates) {
|
|
26187
26407
|
throw new MaterializedViewConfigError(
|
|
26188
26408
|
`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`
|
|
@@ -27438,6 +27658,7 @@ function shortJSON(value) {
|
|
|
27438
27658
|
resolveI18nText,
|
|
27439
27659
|
resolvePolicy,
|
|
27440
27660
|
resolvePublicEnvelopeSchema,
|
|
27661
|
+
resolveSequenceKey,
|
|
27441
27662
|
resolveSession,
|
|
27442
27663
|
revokeAllSessions,
|
|
27443
27664
|
revokeDelegation,
|