@noy-db/hub 0.6.0-pre.4 → 0.6.0-pre.7
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/codemods/0.4.0-pre.json +40 -0
- package/dist/broker/index.js +3 -3
- package/dist/cargo/index.js +4 -4
- package/dist/{chunk-AHCSWNVL.js → chunk-4R55OPT2.js} +3 -3
- package/dist/{chunk-XMC2ZTRD.js → chunk-ADW22QSB.js} +3 -3
- package/dist/chunk-GOLN6LQ5.js +123 -0
- package/dist/chunk-GOLN6LQ5.js.map +1 -0
- package/dist/{chunk-RW3XKAF3.js → chunk-JRKZTEZZ.js} +60 -4
- package/dist/chunk-JRKZTEZZ.js.map +1 -0
- package/dist/{chunk-MZ5ZFO2D.js → chunk-NNYENE7N.js} +50 -112
- package/dist/chunk-NNYENE7N.js.map +1 -0
- package/dist/{chunk-WDDHMAAO.js → chunk-NPP5R7FF.js} +2 -2
- package/dist/{chunk-O42AUQCP.js → chunk-O2ERS4UJ.js} +2 -2
- package/dist/{chunk-MYG6WIRJ.js → chunk-PXCBVDFY.js} +49 -12
- package/dist/chunk-PXCBVDFY.js.map +1 -0
- package/dist/{chunk-LWSJG3LI.js → chunk-RTAMLDWP.js} +6 -2
- package/dist/chunk-RTAMLDWP.js.map +1 -0
- package/dist/{chunk-HY6Y2P4Y.js → chunk-WNFZI3I5.js} +3 -3
- package/dist/{chunk-VZUVORWV.js → chunk-XBRNBG4Z.js} +2 -2
- package/dist/{chunk-IQRP74OO.js → chunk-YJ6IONGA.js} +2 -2
- package/dist/{chunk-7V2OGKES.js → chunk-YM75S6N6.js} +112 -61
- package/dist/chunk-YM75S6N6.js.map +1 -0
- package/dist/{chunk-Q2VEFHDQ.js → chunk-ZMSE2ZZ4.js} +26 -1
- package/dist/chunk-ZMSE2ZZ4.js.map +1 -0
- package/dist/custody/index.js +2 -2
- package/dist/{dispatch-5DN7ZJGM.js → dispatch-4NSDG6EP.js} +5 -5
- package/dist/{executor-TZNM4GCW.js → executor-HYQBNG6J.js} +3 -2
- package/dist/guards/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +24 -20
- package/dist/index.js.map +1 -1
- package/dist/kernel/vault.d.ts +9 -11
- package/dist/{liberate-BAHOP2TQ.js → liberate-GFN4C7RR.js} +3 -3
- package/dist/materialized-views/index.js +3 -2
- package/dist/money/index.js +10 -6
- package/dist/{noydb-QGPKEDXK.js → noydb-LYIAD4CW.js} +6 -6
- package/dist/periods/index.js +5 -1
- package/dist/pod/index.js +6 -6
- package/dist/{seed-NPF3BZGQ.js → seed-GDV5PT4R.js} +2 -2
- package/dist/{stale-4E3VZXGV.js → stale-C27ICSB4.js} +2 -2
- package/dist/team/index.js +3 -3
- package/dist/via/money/exact.d.ts +44 -0
- package/dist/via/money/index.d.ts +2 -0
- package/dist/with-audit/guards/immutable-guard.d.ts +14 -0
- package/dist/with-audit/periods/active.d.ts +28 -1
- package/dist/with-audit/periods/index.d.ts +4 -2
- package/dist/with-audit/periods/periods.d.ts +79 -4
- package/dist/with-audit/periods/strategy.d.ts +13 -4
- package/dist/with-audit/periods/vault-facade.d.ts +36 -10
- package/dist/with-formula/materialized-views/types.d.ts +52 -0
- package/dist/with-party/team/keyring.d.ts +10 -1
- package/package.json +3 -3
- package/dist/chunk-7V2OGKES.js.map +0 -1
- package/dist/chunk-LWSJG3LI.js.map +0 -1
- package/dist/chunk-MYG6WIRJ.js.map +0 -1
- package/dist/chunk-MZ5ZFO2D.js.map +0 -1
- package/dist/chunk-Q2VEFHDQ.js.map +0 -1
- package/dist/chunk-RW3XKAF3.js.map +0 -1
- /package/dist/{chunk-AHCSWNVL.js.map → chunk-4R55OPT2.js.map} +0 -0
- /package/dist/{chunk-XMC2ZTRD.js.map → chunk-ADW22QSB.js.map} +0 -0
- /package/dist/{chunk-WDDHMAAO.js.map → chunk-NPP5R7FF.js.map} +0 -0
- /package/dist/{chunk-O42AUQCP.js.map → chunk-O2ERS4UJ.js.map} +0 -0
- /package/dist/{chunk-HY6Y2P4Y.js.map → chunk-WNFZI3I5.js.map} +0 -0
- /package/dist/{chunk-VZUVORWV.js.map → chunk-XBRNBG4Z.js.map} +0 -0
- /package/dist/{chunk-IQRP74OO.js.map → chunk-YJ6IONGA.js.map} +0 -0
- /package/dist/{dispatch-5DN7ZJGM.js.map → dispatch-4NSDG6EP.js.map} +0 -0
- /package/dist/{executor-TZNM4GCW.js.map → executor-HYQBNG6J.js.map} +0 -0
- /package/dist/{liberate-BAHOP2TQ.js.map → liberate-GFN4C7RR.js.map} +0 -0
- /package/dist/{noydb-QGPKEDXK.js.map → noydb-LYIAD4CW.js.map} +0 -0
- /package/dist/{seed-NPF3BZGQ.js.map → seed-GDV5PT4R.js.map} +0 -0
- /package/dist/{stale-4E3VZXGV.js.map → stale-C27ICSB4.js.map} +0 -0
package/codemods/0.4.0-pre.json
CHANGED
|
@@ -654,6 +654,46 @@
|
|
|
654
654
|
"safeGlobalReplace": true,
|
|
655
655
|
"section": "§3",
|
|
656
656
|
"note": "Pod-write option; refused rather than ignored as of 0.6.0-pre.3 (#991)."
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
"from": "sum",
|
|
660
|
+
"to": "@noy-db/hub/reduce",
|
|
661
|
+
"kind": "import-move",
|
|
662
|
+
"safeGlobalReplace": false,
|
|
663
|
+
"section": "§5",
|
|
664
|
+
"note": "Same name, new home: the reducer factories were pruned off the root barrel and republished at `@noy-db/hub/reduce` in the 0.4.0-pre line (§5). Edit the import, not the identifier — and note these names are ordinary English, so this row is NOT safe to replace globally."
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
"from": "count",
|
|
668
|
+
"to": "@noy-db/hub/reduce",
|
|
669
|
+
"kind": "import-move",
|
|
670
|
+
"safeGlobalReplace": false,
|
|
671
|
+
"section": "§5",
|
|
672
|
+
"note": "Same name, new home: the reducer factories were pruned off the root barrel and republished at `@noy-db/hub/reduce` in the 0.4.0-pre line (§5). Edit the import, not the identifier — and note these names are ordinary English, so this row is NOT safe to replace globally."
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"from": "avg",
|
|
676
|
+
"to": "@noy-db/hub/reduce",
|
|
677
|
+
"kind": "import-move",
|
|
678
|
+
"safeGlobalReplace": false,
|
|
679
|
+
"section": "§5",
|
|
680
|
+
"note": "Same name, new home: the reducer factories were pruned off the root barrel and republished at `@noy-db/hub/reduce` in the 0.4.0-pre line (§5). Edit the import, not the identifier — and note these names are ordinary English, so this row is NOT safe to replace globally."
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
"from": "min",
|
|
684
|
+
"to": "@noy-db/hub/reduce",
|
|
685
|
+
"kind": "import-move",
|
|
686
|
+
"safeGlobalReplace": false,
|
|
687
|
+
"section": "§5",
|
|
688
|
+
"note": "Same name, new home: the reducer factories were pruned off the root barrel and republished at `@noy-db/hub/reduce` in the 0.4.0-pre line (§5). Edit the import, not the identifier — and note these names are ordinary English, so this row is NOT safe to replace globally."
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
"from": "max",
|
|
692
|
+
"to": "@noy-db/hub/reduce",
|
|
693
|
+
"kind": "import-move",
|
|
694
|
+
"safeGlobalReplace": false,
|
|
695
|
+
"section": "§5",
|
|
696
|
+
"note": "Same name, new home: the reducer factories were pruned off the root barrel and republished at `@noy-db/hub/reduce` in the 0.4.0-pre line (§5). Edit the import, not the identifier — and note these names are ordinary English, so this row is NOT safe to replace globally."
|
|
657
697
|
}
|
|
658
698
|
]
|
|
659
699
|
}
|
package/dist/broker/index.js
CHANGED
|
@@ -30,7 +30,7 @@ function withBroker(config) {
|
|
|
30
30
|
const cache = /* @__PURE__ */ new Map();
|
|
31
31
|
return {
|
|
32
32
|
async enroll(ctx) {
|
|
33
|
-
const { enrollSeed } = await import("../seed-
|
|
33
|
+
const { enrollSeed } = await import("../seed-GDV5PT4R.js");
|
|
34
34
|
return enrollSeed({ ...ctx, config });
|
|
35
35
|
},
|
|
36
36
|
async rotate(ctx) {
|
|
@@ -39,7 +39,7 @@ function withBroker(config) {
|
|
|
39
39
|
const inFlight = scoped.map(([, e]) => e.inFlight).filter((p) => p !== void 0);
|
|
40
40
|
await Promise.allSettled(inFlight);
|
|
41
41
|
for (const [key] of scoped) cache.delete(key);
|
|
42
|
-
const { rotateSeed } = await import("../seed-
|
|
42
|
+
const { rotateSeed } = await import("../seed-GDV5PT4R.js");
|
|
43
43
|
return rotateSeed({ ...ctx, config });
|
|
44
44
|
},
|
|
45
45
|
credentialSource(ctx, profile) {
|
|
@@ -56,7 +56,7 @@ function withBroker(config) {
|
|
|
56
56
|
const skewMs = config.skewMs ?? DEFAULT_SKEW_MS;
|
|
57
57
|
const capturedEntry = entry;
|
|
58
58
|
const inFlight = (async () => {
|
|
59
|
-
const { mintStoreCredentials } = await import("../seed-
|
|
59
|
+
const { mintStoreCredentials } = await import("../seed-GDV5PT4R.js");
|
|
60
60
|
const creds = await mintStoreCredentials({ ...ctx, config }, profile);
|
|
61
61
|
capturedEntry.cached = { creds, validUntil: cacheFloor(creds, skewMs) };
|
|
62
62
|
return creds;
|
package/dist/cargo/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
diffVault,
|
|
7
7
|
unsealDeks,
|
|
8
8
|
withCargo
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-WNFZI3I5.js";
|
|
10
10
|
import {
|
|
11
11
|
extractPartition,
|
|
12
12
|
walkClosure
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
isDeedVault,
|
|
17
17
|
liberateVault,
|
|
18
18
|
loadDeedMarker
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-NPP5R7FF.js";
|
|
20
20
|
import "../chunk-FZ6NYJ7L.js";
|
|
21
21
|
import "../chunk-FFDNKRCY.js";
|
|
22
22
|
import "../chunk-PL2GHSCM.js";
|
|
@@ -33,7 +33,7 @@ import "../chunk-XWX7GL56.js";
|
|
|
33
33
|
import "../chunk-CDB2HVQW.js";
|
|
34
34
|
import {
|
|
35
35
|
CustodyApi
|
|
36
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-ADW22QSB.js";
|
|
37
37
|
import "../chunk-4VUPLMZ6.js";
|
|
38
38
|
import "../chunk-2BMRJ6LQ.js";
|
|
39
39
|
import {
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
} from "../chunk-IGJCYUT5.js";
|
|
47
47
|
import "../chunk-7G6VDWXB.js";
|
|
48
48
|
import "../chunk-UHXCLPGC.js";
|
|
49
|
-
import "../chunk-
|
|
49
|
+
import "../chunk-JRKZTEZZ.js";
|
|
50
50
|
import "../chunk-5JY5TSVY.js";
|
|
51
51
|
import "../chunk-AHLJSVRL.js";
|
|
52
52
|
import {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createNoydb
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YM75S6N6.js";
|
|
4
4
|
import {
|
|
5
5
|
deriveSchemaManifest
|
|
6
6
|
} from "./chunk-2DHSSLOD.js";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-4VUPLMZ6.js";
|
|
17
17
|
import {
|
|
18
18
|
loadKeyring
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-JRKZTEZZ.js";
|
|
20
20
|
import {
|
|
21
21
|
ConflictError,
|
|
22
22
|
MigrationRequiredError,
|
|
@@ -290,4 +290,4 @@ export {
|
|
|
290
290
|
followRedirects,
|
|
291
291
|
open
|
|
292
292
|
};
|
|
293
|
-
//# sourceMappingURL=chunk-
|
|
293
|
+
//# sourceMappingURL=chunk-4R55OPT2.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
grant,
|
|
3
3
|
revoke
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JRKZTEZZ.js";
|
|
5
5
|
import {
|
|
6
6
|
CustodyNotEnabledError
|
|
7
7
|
} from "./chunk-HNGSV2YC.js";
|
|
@@ -16,7 +16,7 @@ function withCustody() {
|
|
|
16
16
|
return host._revokeCustodianImpl(revoke, vault, options, factors);
|
|
17
17
|
},
|
|
18
18
|
async liberate(vault, opts) {
|
|
19
|
-
const { liberateVault } = await import("./liberate-
|
|
19
|
+
const { liberateVault } = await import("./liberate-GFN4C7RR.js");
|
|
20
20
|
return liberateVault(vault, opts);
|
|
21
21
|
}
|
|
22
22
|
};
|
|
@@ -74,4 +74,4 @@ export {
|
|
|
74
74
|
withCustody,
|
|
75
75
|
CustodyApi
|
|
76
76
|
};
|
|
77
|
-
//# sourceMappingURL=chunk-
|
|
77
|
+
//# sourceMappingURL=chunk-ADW22QSB.js.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MoneyUnsupportedError,
|
|
3
|
+
decimalScaleOf,
|
|
4
|
+
formatScaledInt,
|
|
5
|
+
parseToScaledInt,
|
|
6
|
+
rescaleScaledInt
|
|
7
|
+
} from "./chunk-NNYENE7N.js";
|
|
8
|
+
|
|
9
|
+
// src/via/money/arith.ts
|
|
10
|
+
function parseAmount(label, amount, scale, rounding) {
|
|
11
|
+
const r = parseToScaledInt(amount, scale, rounding);
|
|
12
|
+
if (!r.ok) {
|
|
13
|
+
throw new MoneyUnsupportedError(
|
|
14
|
+
r.reason === "precision" ? `${label}: amount ${JSON.stringify(amount)} has more precision than scale ${scale} and no rounding mode is configured` : `${label}: amount ${JSON.stringify(amount)} is not a finite decimal`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return r.value;
|
|
18
|
+
}
|
|
19
|
+
function resolveScale(label, amount, explicit) {
|
|
20
|
+
if (explicit !== void 0) {
|
|
21
|
+
if (!Number.isInteger(explicit) || explicit < 0) {
|
|
22
|
+
throw new MoneyUnsupportedError(`${label}: scale must be a non-negative integer`);
|
|
23
|
+
}
|
|
24
|
+
return explicit;
|
|
25
|
+
}
|
|
26
|
+
const inferred = decimalScaleOf(amount);
|
|
27
|
+
if (inferred === null) {
|
|
28
|
+
throw new MoneyUnsupportedError(`${label}: amount ${JSON.stringify(amount)} is not a finite decimal`);
|
|
29
|
+
}
|
|
30
|
+
return inferred;
|
|
31
|
+
}
|
|
32
|
+
function mulRate(amount, rate, opts = {}) {
|
|
33
|
+
const scale = resolveScale("mulRate", amount, opts.scale);
|
|
34
|
+
const rounding = opts.rounding ?? "half-up";
|
|
35
|
+
const a = parseAmount("mulRate", amount, scale, rounding);
|
|
36
|
+
const rateScale = decimalScaleOf(rate);
|
|
37
|
+
if (rateScale === null) {
|
|
38
|
+
throw new MoneyUnsupportedError(`mulRate: rate ${JSON.stringify(rate)} is not a finite decimal`);
|
|
39
|
+
}
|
|
40
|
+
const r = parseToScaledInt(rate, rateScale);
|
|
41
|
+
if (!r.ok) {
|
|
42
|
+
throw new MoneyUnsupportedError(`mulRate: rate ${JSON.stringify(rate)} is not a finite decimal`);
|
|
43
|
+
}
|
|
44
|
+
const product = a * r.value;
|
|
45
|
+
return formatScaledInt(rescaleScaledInt(product, scale + rateScale, scale, rounding), scale);
|
|
46
|
+
}
|
|
47
|
+
function allocate(amount, weights, opts = {}) {
|
|
48
|
+
if (weights.length === 0) {
|
|
49
|
+
throw new MoneyUnsupportedError("allocate: weights must not be empty");
|
|
50
|
+
}
|
|
51
|
+
const scale = resolveScale("allocate", amount, opts.scale);
|
|
52
|
+
const a = parseAmount("allocate", amount, scale);
|
|
53
|
+
let weightScale = 0;
|
|
54
|
+
for (const w of weights) {
|
|
55
|
+
const s = decimalScaleOf(w);
|
|
56
|
+
if (s === null) {
|
|
57
|
+
throw new MoneyUnsupportedError(`allocate: weight ${JSON.stringify(w)} is not a finite decimal`);
|
|
58
|
+
}
|
|
59
|
+
if (s > weightScale) weightScale = s;
|
|
60
|
+
}
|
|
61
|
+
const scaledWeights = weights.map((w) => {
|
|
62
|
+
const r = parseToScaledInt(w, weightScale);
|
|
63
|
+
if (!r.ok || r.value < 0n) {
|
|
64
|
+
throw new MoneyUnsupportedError(`allocate: weight ${JSON.stringify(w)} must be a non-negative decimal`);
|
|
65
|
+
}
|
|
66
|
+
return r.value;
|
|
67
|
+
});
|
|
68
|
+
const sumW = scaledWeights.reduce((acc, w) => acc + w, 0n);
|
|
69
|
+
if (sumW === 0n) {
|
|
70
|
+
throw new MoneyUnsupportedError("allocate: weights must not all be zero");
|
|
71
|
+
}
|
|
72
|
+
const negative = a < 0n;
|
|
73
|
+
const mag = negative ? -a : a;
|
|
74
|
+
const base = [];
|
|
75
|
+
const remainders = [];
|
|
76
|
+
let distributed = 0n;
|
|
77
|
+
for (let i = 0; i < scaledWeights.length; i++) {
|
|
78
|
+
const product = mag * scaledWeights[i];
|
|
79
|
+
const share = product / sumW;
|
|
80
|
+
base.push(share);
|
|
81
|
+
distributed += share;
|
|
82
|
+
remainders.push({ index: i, rem: product % sumW });
|
|
83
|
+
}
|
|
84
|
+
let leftover = mag - distributed;
|
|
85
|
+
remainders.sort((x, y) => y.rem > x.rem ? 1 : y.rem < x.rem ? -1 : x.index - y.index);
|
|
86
|
+
for (const { index } of remainders) {
|
|
87
|
+
if (leftover === 0n) break;
|
|
88
|
+
base[index] = base[index] + 1n;
|
|
89
|
+
leftover -= 1n;
|
|
90
|
+
}
|
|
91
|
+
return base.map((p) => formatScaledInt(negative && p !== 0n ? -p : p, scale));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/via/money/branded.ts
|
|
95
|
+
function asMoney(value) {
|
|
96
|
+
if (!isMoneyLike(value)) {
|
|
97
|
+
throw new MoneyUnsupportedError(`asMoney: ${JSON.stringify(value)} is not a finite decimal`);
|
|
98
|
+
}
|
|
99
|
+
return String(value).trim();
|
|
100
|
+
}
|
|
101
|
+
function isMoneyString(value) {
|
|
102
|
+
return typeof value === "string" && isMoneyLike(value);
|
|
103
|
+
}
|
|
104
|
+
function moneyNumber(value) {
|
|
105
|
+
if (!isMoneyLike(value)) {
|
|
106
|
+
throw new MoneyUnsupportedError(`moneyNumber: ${JSON.stringify(value)} is not a finite decimal`);
|
|
107
|
+
}
|
|
108
|
+
return Number(value);
|
|
109
|
+
}
|
|
110
|
+
function isMoneyLike(value) {
|
|
111
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
112
|
+
if (typeof value !== "string") return false;
|
|
113
|
+
return decimalScaleOf(value) !== null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
mulRate,
|
|
118
|
+
allocate,
|
|
119
|
+
asMoney,
|
|
120
|
+
isMoneyString,
|
|
121
|
+
moneyNumber
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=chunk-GOLN6LQ5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/via/money/arith.ts","../src/via/money/branded.ts"],"sourcesContent":["/**\n * Exact money arithmetic helpers — `mulRate` and `allocate`.\n *\n * Both operate on the canonical decoded string form that `get()`\n * returns (`'10000.00'`), entirely in scaled-`BigInt` space — no\n * floating-point step anywhere, exact past 2^53. They are pure\n * functions with no vault or descriptor dependency: the working scale\n * is inferred from the amount's fractional digits (a canonical money\n * string always carries exactly the field's scale) or pinned with\n * `opts.scale`.\n *\n * Why these two: app-side invariants of the form\n * `Σ parts === whole` (receipt totals, net-zero WHT pairs, proration)\n * carry ±0.01 tolerances ONLY because the math is major-unit floats +\n * round2. `mulRate` (VAT-style rate application with explicit\n * rounding) and `allocate` (largest-remainder split — parts sum to the\n * input EXACTLY, by construction) make those tolerances zero.\n */\n\nimport {\n parseToScaledInt,\n formatScaledInt,\n rescaleScaledInt,\n decimalScaleOf,\n type RoundingMode,\n} from './fixed-point.js'\nimport { MoneyUnsupportedError } from './descriptor.js'\n\nexport interface MulRateOptions {\n /**\n * Output scale (fraction digits). Defaults to the amount's own\n * fractional digits — for a canonical money string that IS the\n * field's scale.\n */\n readonly scale?: number\n /** Rounding for the final re-scale. Default `'half-up'`. */\n readonly rounding?: RoundingMode\n}\n\nexport interface AllocateOptions {\n /** Working scale. Defaults to the amount's own fractional digits. */\n readonly scale?: number\n}\n\n/** Parse `amount` at `scale` or throw the standard money TypeError. */\nfunction parseAmount(label: string, amount: number | string, scale: number, rounding?: RoundingMode): bigint {\n const r = parseToScaledInt(amount, scale, rounding)\n if (!r.ok) {\n throw new MoneyUnsupportedError(\n r.reason === 'precision'\n ? `${label}: amount ${JSON.stringify(amount)} has more precision than scale ${scale} and no rounding mode is configured`\n : `${label}: amount ${JSON.stringify(amount)} is not a finite decimal`,\n )\n }\n return r.value\n}\n\nfunction resolveScale(label: string, amount: number | string, explicit: number | undefined): number {\n if (explicit !== undefined) {\n if (!Number.isInteger(explicit) || explicit < 0) {\n throw new MoneyUnsupportedError(`${label}: scale must be a non-negative integer`)\n }\n return explicit\n }\n const inferred = decimalScaleOf(amount)\n if (inferred === null) {\n throw new MoneyUnsupportedError(`${label}: amount ${JSON.stringify(amount)} is not a finite decimal`)\n }\n return inferred\n}\n\n/**\n * Multiply a money amount by a decimal rate, exactly.\n *\n * The rate is parsed at its OWN full precision (`0.07` → `7` at scale\n * 2), the product computed in `BigInt` at `amountScale + rateScale`,\n * then re-scaled back to the output scale with the requested rounding —\n * one rounding step, at the very end.\n *\n * ```ts\n * mulRate('10000.00', 0.07) // '700.00' (VAT)\n * mulRate('33.33', '0.07') // '2.33' (half-up)\n * mulRate('33.33', 0.07, { rounding: 'floor' }) // '2.33'\n * mulRate(100, 0.07, { scale: 2 }) // '7.00'\n * ```\n */\nexport function mulRate(\n amount: number | string,\n rate: number | string,\n opts: MulRateOptions = {},\n): string {\n const scale = resolveScale('mulRate', amount, opts.scale)\n const rounding = opts.rounding ?? 'half-up'\n const a = parseAmount('mulRate', amount, scale, rounding)\n\n const rateScale = decimalScaleOf(rate)\n if (rateScale === null) {\n throw new MoneyUnsupportedError(`mulRate: rate ${JSON.stringify(rate)} is not a finite decimal`)\n }\n const r = parseToScaledInt(rate, rateScale)\n if (!r.ok) {\n throw new MoneyUnsupportedError(`mulRate: rate ${JSON.stringify(rate)} is not a finite decimal`)\n }\n\n const product = a * r.value // scaled at scale + rateScale\n return formatScaledInt(rescaleScaledInt(product, scale + rateScale, scale, rounding), scale)\n}\n\n/**\n * Split a money amount across weighted buckets with ZERO drift: the\n * returned parts sum to the input exactly, by construction\n * (largest-remainder method).\n *\n * Each bucket gets `floor(amount × weightᵢ / Σweights)`; the leftover\n * minor units (always fewer than the bucket count) go one each to the\n * buckets with the largest truncated remainders — ties broken by\n * position, earlier bucket first. Weights are parsed as exact decimals\n * (no float division anywhere); they must be non-negative with a\n * positive sum.\n *\n * ```ts\n * allocate('100.00', [1, 1, 1]) // ['33.34', '33.33', '33.33']\n * allocate('0.05', [3, 7]) // ['0.02', '0.03']\n * allocate('-100.00', [1, 1, 1]) // ['-33.34', '-33.33', '-33.33']\n * ```\n */\nexport function allocate(\n amount: number | string,\n weights: ReadonlyArray<number | string>,\n opts: AllocateOptions = {},\n): string[] {\n if (weights.length === 0) {\n throw new MoneyUnsupportedError('allocate: weights must not be empty')\n }\n const scale = resolveScale('allocate', amount, opts.scale)\n const a = parseAmount('allocate', amount, scale)\n\n // Parse every weight as an exact decimal at a common scale, so the\n // proportion arithmetic below is pure BigInt.\n let weightScale = 0\n for (const w of weights) {\n const s = decimalScaleOf(w)\n if (s === null) {\n throw new MoneyUnsupportedError(`allocate: weight ${JSON.stringify(w)} is not a finite decimal`)\n }\n if (s > weightScale) weightScale = s\n }\n const scaledWeights = weights.map(w => {\n const r = parseToScaledInt(w, weightScale)\n if (!r.ok || r.value < 0n) {\n throw new MoneyUnsupportedError(`allocate: weight ${JSON.stringify(w)} must be a non-negative decimal`)\n }\n return r.value\n })\n const sumW = scaledWeights.reduce((acc, w) => acc + w, 0n)\n if (sumW === 0n) {\n throw new MoneyUnsupportedError('allocate: weights must not all be zero')\n }\n\n // Largest-remainder over the MAGNITUDE; a negative amount negates the\n // parts at the end, so Σparts === amount holds for both signs.\n const negative = a < 0n\n const mag = negative ? -a : a\n\n const base: bigint[] = []\n const remainders: Array<{ index: number; rem: bigint }> = []\n let distributed = 0n\n for (let i = 0; i < scaledWeights.length; i++) {\n const product = mag * scaledWeights[i]!\n const share = product / sumW\n base.push(share)\n distributed += share\n remainders.push({ index: i, rem: product % sumW })\n }\n\n // Leftover minor units: strictly fewer than the bucket count.\n let leftover = mag - distributed\n remainders.sort((x, y) => (y.rem > x.rem ? 1 : y.rem < x.rem ? -1 : x.index - y.index))\n for (const { index } of remainders) {\n if (leftover === 0n) break\n base[index] = base[index]! + 1n\n leftover -= 1n\n }\n\n return base.map(p => formatScaledInt(negative && p !== 0n ? -p : p, scale))\n}\n","/**\n * Branded money output type.\n *\n * The decoded read shape of a money field is an exact decimal STRING\n * (`'10000.00'`) — but a hand-written schema types it `string | number`,\n * which is honest about the input side and unhelpful on the output\n * side: every read site hand-coerces, and a missed coercion passes\n * typecheck silently (then surfaces as a runtime template warning, or\n * worse, as `'10000.00' * 100` arithmetic).\n *\n * {@link MoneyString} is the output-side brand: a `string` that has\n * been through noy-db's decode (or {@link asMoney}'s guard). Branding\n * is type-level only — zero runtime cost on the read path.\n *\n * ## Wiring the brand through a validator (the input/output asymmetry)\n *\n * Keep the permissive `string | number` on the INPUT side so write\n * sites are untouched, and brand the OUTPUT side. With Zod:\n *\n * ```ts\n * import type { MoneyString } from '@noy-db/hub'\n *\n * const moneyValue = z.union([z.number(), z.string()]) as unknown as\n * z.ZodType<MoneyString, z.ZodTypeDef, string | number>\n *\n * const Invoice = z.object({ id: z.string(), total: moneyValue })\n * type InvoiceOut = z.output<typeof Invoice> // total: MoneyString\n * type InvoiceIn = z.input<typeof Invoice> // total: string | number\n * ```\n *\n * The cast is sound for fields declared in `moneyFields`: reads pass\n * through `decodeMoneyFields`, which always produces the canonical\n * decimal string.\n */\n\nimport { decimalScaleOf } from './fixed-point.js'\nimport { MoneyUnsupportedError } from './descriptor.js'\n\ndeclare const MONEY_BRAND: unique symbol\n\n/**\n * An exact decimal string produced by noy-db's money decode\n * (`'10000.00'`). The brand exists only at the type level — at runtime\n * a `MoneyString` is a plain string.\n */\nexport type MoneyString = string & { readonly [MONEY_BRAND]: true }\n\n/**\n * Runtime-guarded cast to {@link MoneyString}. Accepts a decimal string\n * or a number, returns the canonical decimal string branded — throws\n * `MoneyUnsupportedError` on anything non-finite / non-decimal. Use at\n * trust boundaries (deserialized JSON, route params); values read\n * through `get()`/`list()` are already canonical.\n */\nexport function asMoney(value: string | number): MoneyString {\n if (!isMoneyLike(value)) {\n throw new MoneyUnsupportedError(`asMoney: ${JSON.stringify(value)} is not a finite decimal`)\n }\n return String(value).trim() as MoneyString\n}\n\n/** Type guard: is `value` a decimal string acceptable as money? */\nexport function isMoneyString(value: unknown): value is MoneyString {\n return typeof value === 'string' && isMoneyLike(value)\n}\n\n/**\n * The ONE sanctioned escape hatch to a JS `number` — explicit because\n * the conversion is lossy past 2^53. For display math and chart axes;\n * never feed the result back into stored amounts (use `mulRate` /\n * `allocate` for exact arithmetic).\n */\nexport function moneyNumber(value: MoneyString | string | number): number {\n if (!isMoneyLike(value)) {\n throw new MoneyUnsupportedError(`moneyNumber: ${JSON.stringify(value)} is not a finite decimal`)\n }\n return Number(value)\n}\n\nfunction isMoneyLike(value: unknown): boolean {\n if (typeof value === 'number') return Number.isFinite(value)\n if (typeof value !== 'string') return false\n return decimalScaleOf(value) !== null\n}\n"],"mappings":"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","names":[]}
|
|
@@ -449,6 +449,12 @@ async function grant(store, vault, callerKeyring, options) {
|
|
|
449
449
|
`Role "${callerKeyring.role}" cannot grant role "${options.role}"`
|
|
450
450
|
);
|
|
451
451
|
}
|
|
452
|
+
const secret = options.secret;
|
|
453
|
+
if (typeof secret !== "string" || secret.trim() === "") {
|
|
454
|
+
throw new ValidationError(
|
|
455
|
+
`grant: \`secret\` is required and must be a non-empty string (got ${secret === void 0 ? "undefined" : typeof secret === "string" ? "an empty string" : typeof secret}). The grantee's key is derived from it, so a missing secret produces a keyring slot nobody can unlock. Note the 0.4.0-pre rename: the option is \`secret\`, not \`passphrase\`.`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
452
458
|
if (options.validateSecret && !options.allowWeakSecret) {
|
|
453
459
|
assertStrongSecret(options.secret);
|
|
454
460
|
}
|
|
@@ -456,15 +462,26 @@ async function grant(store, vault, callerKeyring, options) {
|
|
|
456
462
|
const newSalt = generateSalt();
|
|
457
463
|
const newKek = await deriveKey(options.secret, newSalt);
|
|
458
464
|
const granteeMayHoldSecrets = options.role === "owner" || options.role === "admin";
|
|
465
|
+
let mintedForGrant = false;
|
|
466
|
+
for (const collName of Object.keys(permissions)) {
|
|
467
|
+
if (collName === PERMISSION_WILDCARD) continue;
|
|
468
|
+
if (isSecretBearingReservedCollection(collName) && !granteeMayHoldSecrets) continue;
|
|
469
|
+
if (callerKeyring.deks.has(collName)) continue;
|
|
470
|
+
if (await collectionHasRecords(store, vault, collName)) continue;
|
|
471
|
+
callerKeyring.deks.set(collName, await generateDEK());
|
|
472
|
+
mintedForGrant = true;
|
|
473
|
+
}
|
|
474
|
+
if (mintedForGrant) await persistKeyring(store, vault, callerKeyring);
|
|
459
475
|
const wrappedDeks = {};
|
|
460
476
|
for (const collName of Object.keys(permissions)) {
|
|
477
|
+
if (collName === PERMISSION_WILDCARD) continue;
|
|
461
478
|
if (isSecretBearingReservedCollection(collName) && !granteeMayHoldSecrets) continue;
|
|
462
479
|
const dek = callerKeyring.deks.get(collName);
|
|
463
480
|
if (dek) {
|
|
464
481
|
wrappedDeks[collName] = await wrapKey(dek, newKek);
|
|
465
482
|
}
|
|
466
483
|
}
|
|
467
|
-
if (options.role === "owner" || options.role === "admin" || options.role === "custodian" || options.role === "viewer") {
|
|
484
|
+
if (options.role === "owner" || options.role === "admin" || options.role === "custodian" || options.role === "viewer" || permissionsAreWildcard(options.permissions)) {
|
|
468
485
|
for (const [collName, dek] of callerKeyring.deks) {
|
|
469
486
|
if (collName in wrappedDeks) continue;
|
|
470
487
|
if (isSecretBearingReservedCollection(collName) && !granteeMayHoldSecrets) continue;
|
|
@@ -817,6 +834,23 @@ async function listUsersWithEnvelopes(store, vault, userEnvelopeDek, callerRole,
|
|
|
817
834
|
}
|
|
818
835
|
return out;
|
|
819
836
|
}
|
|
837
|
+
async function collectionHasRecords(store, vault, collectionName) {
|
|
838
|
+
const ids = await store.list(vault, collectionName);
|
|
839
|
+
return ids.length > 0;
|
|
840
|
+
}
|
|
841
|
+
async function reloadPersistedDEK(store, vault, keyring, collectionName) {
|
|
842
|
+
if (!keyring.kek) return null;
|
|
843
|
+
const found = await readKeyringFile(store, vault, keyring.userId);
|
|
844
|
+
const wrapped = found?.file.deks[collectionName];
|
|
845
|
+
if (wrapped === void 0) return null;
|
|
846
|
+
try {
|
|
847
|
+
const dek = await unwrapKey(wrapped, keyring.kek);
|
|
848
|
+
keyring.deks.set(collectionName, dek);
|
|
849
|
+
return dek;
|
|
850
|
+
} catch {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
820
854
|
async function ensureCollectionDEK(store, vault, keyring) {
|
|
821
855
|
const inFlight = /* @__PURE__ */ new Map();
|
|
822
856
|
return async (collectionName) => {
|
|
@@ -825,6 +859,20 @@ async function ensureCollectionDEK(store, vault, keyring) {
|
|
|
825
859
|
const pending = inFlight.get(collectionName);
|
|
826
860
|
if (pending) return pending;
|
|
827
861
|
const promise = (async () => {
|
|
862
|
+
if (!collectionName.startsWith("_")) {
|
|
863
|
+
if (!hasAccess(keyring, collectionName)) {
|
|
864
|
+
throw new NoAccessError(
|
|
865
|
+
`No access \u2014 user does not have a key for collection "${collectionName}". Grant them this collection in \`permissions\` to give them one.`
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
if (await collectionHasRecords(store, vault, collectionName)) {
|
|
869
|
+
const refreshed = await reloadPersistedDEK(store, vault, keyring, collectionName);
|
|
870
|
+
if (refreshed) return refreshed;
|
|
871
|
+
throw new NoAccessError(
|
|
872
|
+
`No access \u2014 user "${keyring.userId}" is entitled to collection "${collectionName}" but holds no key for it, because the collection was created AFTER their grant. A collection DEK can only be wrapped at grant time (wrapping needs the grantee's secret, which the vault never stores), so this cannot be back-filled \u2014 re-grant the user to give them the key.`
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
828
876
|
const dek = await generateDEK();
|
|
829
877
|
keyring.deks.set(collectionName, dek);
|
|
830
878
|
await persistKeyring(store, vault, keyring);
|
|
@@ -838,14 +886,20 @@ async function ensureCollectionDEK(store, vault, keyring) {
|
|
|
838
886
|
}
|
|
839
887
|
};
|
|
840
888
|
}
|
|
889
|
+
var PERMISSION_WILDCARD = "*";
|
|
890
|
+
function permissionsAreWildcard(permissions) {
|
|
891
|
+
return permissions !== void 0 && PERMISSION_WILDCARD in permissions;
|
|
892
|
+
}
|
|
841
893
|
function hasWritePermission(keyring, collectionName) {
|
|
842
894
|
if (keyring.role === "owner" || keyring.role === "admin" || keyring.role === "custodian") return true;
|
|
843
895
|
if (keyring.role === "viewer" || keyring.role === "client") return false;
|
|
896
|
+
if (keyring.permissions[PERMISSION_WILDCARD] === "rw") return true;
|
|
844
897
|
return keyring.permissions[collectionName] === "rw";
|
|
845
898
|
}
|
|
846
899
|
function hasAccess(keyring, collectionName) {
|
|
847
900
|
if (keyring.role === "owner" || keyring.role === "admin" || keyring.role === "custodian" || keyring.role === "viewer")
|
|
848
901
|
return true;
|
|
902
|
+
if (PERMISSION_WILDCARD in keyring.permissions) return true;
|
|
849
903
|
return collectionName in keyring.permissions;
|
|
850
904
|
}
|
|
851
905
|
async function persistKeyring(store, vault, keyring) {
|
|
@@ -856,6 +910,8 @@ async function persistKeyring(store, vault, keyring) {
|
|
|
856
910
|
}
|
|
857
911
|
const existingFound = await readKeyringFile(store, vault, keyring.userId);
|
|
858
912
|
const existingEcho = existingFound?.file.echo;
|
|
913
|
+
const existingGrantedBy = existingFound?.file.granted_by;
|
|
914
|
+
const existingCreatedAt = existingFound?.file.created_at;
|
|
859
915
|
const wrappedDeks = {};
|
|
860
916
|
for (const [collName, dek] of keyring.deks) {
|
|
861
917
|
wrappedDeks[collName] = await wrapKey(dek, keyring.kek);
|
|
@@ -869,8 +925,8 @@ async function persistKeyring(store, vault, keyring) {
|
|
|
869
925
|
permissions: keyring.permissions,
|
|
870
926
|
deks: wrappedDeks,
|
|
871
927
|
salt: bufferToBase64(keyring.salt),
|
|
872
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
873
|
-
granted_by: keyring.userId,
|
|
928
|
+
created_at: existingCreatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
929
|
+
granted_by: existingGrantedBy ?? keyring.userId,
|
|
874
930
|
canary,
|
|
875
931
|
...keyring.exportCapability !== void 0 && { export_capability: keyring.exportCapability },
|
|
876
932
|
...keyring.importCapability !== void 0 && { import_capability: keyring.importCapability },
|
|
@@ -968,4 +1024,4 @@ export {
|
|
|
968
1024
|
hasImportCapability,
|
|
969
1025
|
evaluateImportCapability
|
|
970
1026
|
};
|
|
971
|
-
//# sourceMappingURL=chunk-
|
|
1027
|
+
//# sourceMappingURL=chunk-JRKZTEZZ.js.map
|