mcp-usage-control 1.0.0

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 (47) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +141 -0
  3. package/dist/index.d.ts +533 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +2131 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/observability.d.ts +154 -0
  8. package/dist/observability.d.ts.map +1 -0
  9. package/dist/observability.js +171 -0
  10. package/dist/observability.js.map +1 -0
  11. package/dist/operational.d.ts +87 -0
  12. package/dist/operational.d.ts.map +1 -0
  13. package/dist/operational.js +193 -0
  14. package/dist/operational.js.map +1 -0
  15. package/dist/progressive-store-conformance.d.ts +4 -0
  16. package/dist/progressive-store-conformance.d.ts.map +1 -0
  17. package/dist/progressive-store-conformance.js +333 -0
  18. package/dist/progressive-store-conformance.js.map +1 -0
  19. package/dist/reconciliation-conformance.d.ts +36 -0
  20. package/dist/reconciliation-conformance.d.ts.map +1 -0
  21. package/dist/reconciliation-conformance.js +211 -0
  22. package/dist/reconciliation-conformance.js.map +1 -0
  23. package/dist/settlement-outcomes.d.ts +24 -0
  24. package/dist/settlement-outcomes.d.ts.map +1 -0
  25. package/dist/settlement-outcomes.js +68 -0
  26. package/dist/settlement-outcomes.js.map +1 -0
  27. package/dist/store-conformance.d.ts +50 -0
  28. package/dist/store-conformance.d.ts.map +1 -0
  29. package/dist/store-conformance.js +378 -0
  30. package/dist/store-conformance.js.map +1 -0
  31. package/dist/thresholds.d.ts +26 -0
  32. package/dist/thresholds.d.ts.map +1 -0
  33. package/dist/thresholds.js +56 -0
  34. package/dist/thresholds.js.map +1 -0
  35. package/dist/vector-store-conformance.d.ts +4 -0
  36. package/dist/vector-store-conformance.d.ts.map +1 -0
  37. package/dist/vector-store-conformance.js +297 -0
  38. package/dist/vector-store-conformance.js.map +1 -0
  39. package/dist/weighted-credits.d.ts +41 -0
  40. package/dist/weighted-credits.d.ts.map +1 -0
  41. package/dist/weighted-credits.js +143 -0
  42. package/dist/weighted-credits.js.map +1 -0
  43. package/dist/windowed-budget-keys.d.ts +36 -0
  44. package/dist/windowed-budget-keys.d.ts.map +1 -0
  45. package/dist/windowed-budget-keys.js +178 -0
  46. package/dist/windowed-budget-keys.js.map +1 -0
  47. package/package.json +113 -0
@@ -0,0 +1,297 @@
1
+ /** Portable proof suite for the optional atomic heterogeneous usage capability. */
2
+ export async function runVectorUsageStoreConformance(harness) {
3
+ const ttlMs = harness.leaseTtlMs ?? 40;
4
+ const concurrency = harness.concurrency ?? 8;
5
+ positive(ttlMs, 'leaseTtlMs');
6
+ positive(concurrency, 'concurrency');
7
+ const cases = [];
8
+ await runCase(harness, cases, 'vector-atomic-denial', async (store) => {
9
+ const blocker = await store.reserve({
10
+ request: request('blocker', 'blocker'),
11
+ units: 1,
12
+ budgets: [{ key: 'vector:blocked', limit: 1 }],
13
+ ttlMs: 5_000,
14
+ });
15
+ scalarAccepted(blocker, 'blocker');
16
+ const denied = await store.reserveVector({
17
+ request: request('denied'),
18
+ dimensions: [
19
+ { key: 'requests', units: 1, budgets: [{ key: 'vector:free', limit: 1 }] },
20
+ { key: 'tokens', units: 7, budgets: [{ key: 'vector:blocked', limit: 1 }] },
21
+ ],
22
+ ttlMs: 5_000,
23
+ });
24
+ vectorDenied(denied, 'atomic denial');
25
+ assert(denied.limitingDimensionKey === 'tokens', 'wrong limiting dimension');
26
+ const probe = await store.reserve({
27
+ request: request('probe'),
28
+ units: 1,
29
+ budgets: [{ key: 'vector:free', limit: 1 }],
30
+ ttlMs: 5_000,
31
+ });
32
+ scalarAccepted(probe, 'denial partially consumed free dimension');
33
+ });
34
+ await runCase(harness, cases, 'vector-concurrent-admission', async (store) => {
35
+ const results = await Promise.all(Array.from({ length: concurrency }, (_, index) => store.reserveVector({
36
+ request: request(`concurrent-${index}`, `u-${index}`),
37
+ dimensions: [
38
+ { key: 'requests', units: 1, budgets: [{ key: 'vector:shared', limit: 1 }] },
39
+ { key: 'tokens', units: 3, budgets: [{ key: `vector:tok:${index}`, limit: 3 }] },
40
+ ],
41
+ ttlMs: 5_000,
42
+ })));
43
+ assert(results.filter(result => result.accepted).length === 1, 'vector admission oversubscribed');
44
+ assert(results.filter(result => !result.accepted).every(result => result.reason === 'quota_exceeded'), 'losers must be quota_exceeded');
45
+ });
46
+ await runCase(harness, cases, 'vector-scalar-operation-collision', async (store) => {
47
+ await reserveVector(store, 'same-op', dimensions('collision'));
48
+ const scalar = await store.reserve({
49
+ request: request('same-op'),
50
+ units: 0,
51
+ budgets: [{ key: 'vector:collision:scalar', limit: 1 }],
52
+ ttlMs: 5_000,
53
+ });
54
+ scalarDenied(scalar, 'duplicate_operation', 'scalar/vector replay domains diverged');
55
+ });
56
+ await runCase(harness, cases, 'vector-growth-replay-concurrency', async (store) => {
57
+ const admission = await reserveVector(store, 'growth', dimensions('growth', 2, 20));
58
+ const cursor = vectorCursor(admission);
59
+ const input = {
60
+ reservationId: admission.reservation.id,
61
+ incrementId: 'inc-1',
62
+ expectedGrowthCursor: cursor,
63
+ dimensions: growth('growth', 0, 5, 2, 20),
64
+ };
65
+ const first = await store.growVectorReservation(input);
66
+ growthAccepted(first, 'first growth');
67
+ assertReserved(first, 'requests', 1);
68
+ assertReserved(first, 'tokens', 10);
69
+ const replay = await store.growVectorReservation(input);
70
+ growthAccepted(replay, 'growth replay');
71
+ assert(replay.replayed, 'exact growth retry did not replay');
72
+ await rejects(() => store.growVectorReservation({ ...input, dimensions: growth('growth', 0, 6, 2, 20) }), 'conflicting replay must fail');
73
+ const concurrent = await reserveVector(store, 'growth-concurrent', dimensions('growth-concurrent', 3, 30));
74
+ const concurrentCursor = vectorCursor(concurrent);
75
+ const attempts = await Promise.allSettled([
76
+ store.growVectorReservation({
77
+ reservationId: concurrent.reservation.id,
78
+ incrementId: 'a',
79
+ expectedGrowthCursor: concurrentCursor,
80
+ dimensions: growth('growth-concurrent', 1, 1, 3, 30),
81
+ }),
82
+ store.growVectorReservation({
83
+ reservationId: concurrent.reservation.id,
84
+ incrementId: 'b',
85
+ expectedGrowthCursor: concurrentCursor,
86
+ dimensions: growth('growth-concurrent', 1, 1, 3, 30),
87
+ }),
88
+ ]);
89
+ assert(attempts.filter(result => result.status === 'fulfilled').length === 1, 'one growth must win');
90
+ assert(attempts.filter(result => result.status === 'rejected').length === 1, 'stale growth must fail');
91
+ });
92
+ await runCase(harness, cases, 'vector-growth-denial-atomic', async (store) => {
93
+ const admission = await reserveVector(store, 'growth-denial', [
94
+ { key: 'requests', units: 1, budgets: [{ key: 'vector:gd:req', limit: 2 }] },
95
+ { key: 'tokens', units: 4, budgets: [{ key: 'vector:gd:tok', limit: 4 }] },
96
+ ]);
97
+ const cursor = vectorCursor(admission);
98
+ const input = {
99
+ reservationId: admission.reservation.id,
100
+ incrementId: 'denied',
101
+ expectedGrowthCursor: cursor,
102
+ dimensions: [
103
+ { key: 'requests', additionalUnits: 1, budgets: [{ key: 'vector:gd:req', limit: 2 }] },
104
+ { key: 'tokens', additionalUnits: 1, budgets: [{ key: 'vector:gd:tok', limit: 4 }] },
105
+ ],
106
+ };
107
+ const denied = await store.growVectorReservation(input);
108
+ growthDenied(denied, 'growth denial');
109
+ assert(denied.growthCursor !== cursor, 'denial must rotate cursor');
110
+ const replay = await store.growVectorReservation(input);
111
+ growthDenied(replay, 'growth denial replay');
112
+ assert(replay.replayed, 'denied retry did not replay');
113
+ const probe = await store.reserve({
114
+ request: request('growth-denial-probe'),
115
+ units: 1,
116
+ budgets: [{ key: 'vector:gd:req', limit: 2 }],
117
+ ttlMs: 5_000,
118
+ });
119
+ scalarAccepted(probe, 'denied growth partially consumed request dimension');
120
+ });
121
+ await runCase(harness, cases, 'vector-pending-liable-expiry', async (store) => {
122
+ await reserveVector(store, 'pending-expiry', dimensions('pending-expiry', 1, 5), ttlMs);
123
+ await harness.waitForLeaseExpiry(ttlMs, 'vector-pending-liable-expiry');
124
+ await reserveVector(store, 'pending-replacement', dimensions('pending-expiry', 1, 5));
125
+ const liable = await reserveVector(store, 'liable-expiry', dimensions('liable-expiry', 1, 5), ttlMs);
126
+ await store.markLiable({ reservationId: liable.reservation.id });
127
+ await harness.waitForLeaseExpiry(ttlMs, 'vector-pending-liable-expiry');
128
+ const denied = await store.reserveVector({
129
+ request: request('liable-replacement'),
130
+ dimensions: dimensions('liable-expiry', 1, 5),
131
+ ttlMs: 5_000,
132
+ });
133
+ vectorDenied(denied, 'liable expiry must retain vector capacity');
134
+ });
135
+ await runCase(harness, cases, 'vector-settlement-bound-replay-terminal', async (store) => {
136
+ const admission = await reserveVector(store, 'settlement', dimensions('settlement', 2, 10));
137
+ const grown = await store.growVectorReservation({
138
+ reservationId: admission.reservation.id,
139
+ incrementId: 'settle-grow',
140
+ expectedGrowthCursor: vectorCursor(admission),
141
+ dimensions: growth('settlement', 1, 3, 2, 10),
142
+ });
143
+ growthAccepted(grown, 'settlement growth');
144
+ await rejects(() => store.settleVector({
145
+ reservationId: admission.reservation.id,
146
+ actualByDimension: [
147
+ { key: 'requests', actualUnits: 3 },
148
+ { key: 'tokens', actualUnits: 8 },
149
+ ],
150
+ outcome: 'invalid',
151
+ }), 'actual above one vector dimension must fail');
152
+ const input = {
153
+ reservationId: admission.reservation.id,
154
+ actualByDimension: [
155
+ { key: 'requests', actualUnits: 2 },
156
+ { key: 'tokens', actualUnits: 7 },
157
+ ],
158
+ outcome: 'completed',
159
+ };
160
+ const first = await store.settleVector(input);
161
+ const replay = await store.settleVector(input);
162
+ assert(JSON.stringify(first) === JSON.stringify(replay), 'vector settlement replay changed result');
163
+ await rejects(() => store.growVectorReservation({
164
+ reservationId: admission.reservation.id,
165
+ incrementId: 'after-settlement',
166
+ expectedGrowthCursor: grown.growthCursor,
167
+ dimensions: growth('settlement', 0, 1, 2, 10),
168
+ }), 'growth after settlement must fail');
169
+ });
170
+ await runCase(harness, cases, 'vector-growth-vs-settle-race', async (store) => {
171
+ const admission = await reserveVector(store, 'race', dimensions('race', 2, 10));
172
+ const results = await Promise.allSettled([
173
+ store.growVectorReservation({
174
+ reservationId: admission.reservation.id,
175
+ incrementId: 'race-growth',
176
+ expectedGrowthCursor: vectorCursor(admission),
177
+ dimensions: growth('race', 1, 1, 2, 10),
178
+ }),
179
+ store.settleVector({
180
+ reservationId: admission.reservation.id,
181
+ actualByDimension: [
182
+ { key: 'requests', actualUnits: 1 },
183
+ { key: 'tokens', actualUnits: 5 },
184
+ ],
185
+ outcome: 'race',
186
+ }),
187
+ ]);
188
+ assert(results[1].status === 'fulfilled', `settlement side of race must complete${results[1].status === 'rejected' ? `: ${errorMessage(results[1].reason)}` : ''}`);
189
+ if (results[0].status === 'fulfilled' && results[1].status === 'fulfilled') {
190
+ growthAccepted(results[0].value, 'race growth');
191
+ const requests = results[1].value.dimensions.find(item => item.key === 'requests');
192
+ assert(requests?.reservedUnits === 2, 'settlement did not observe prior growth');
193
+ }
194
+ });
195
+ return { passed: cases.every(result => result.passed), cases };
196
+ }
197
+ async function runCase(harness, cases, name, body) {
198
+ try {
199
+ const store = await harness.createStore(name);
200
+ if (!isVectorStore(store))
201
+ throw new Error('Store does not support atomic vector usage');
202
+ await body(store);
203
+ cases.push({ name, passed: true });
204
+ }
205
+ catch (error) {
206
+ cases.push({ name, passed: false, error: errorMessage(error) });
207
+ }
208
+ finally {
209
+ try {
210
+ await harness.cleanup?.(name);
211
+ }
212
+ catch (error) {
213
+ cases.push({ name: `${name}:cleanup`, passed: false, error: errorMessage(error) });
214
+ }
215
+ }
216
+ }
217
+ function isVectorStore(store) {
218
+ const candidate = store;
219
+ return (typeof candidate.reserveVector === 'function' &&
220
+ typeof candidate.growVectorReservation === 'function' &&
221
+ typeof candidate.settleVector === 'function');
222
+ }
223
+ async function reserveVector(store, operationId, vector, ttlMs = 5_000) {
224
+ const result = await store.reserveVector({ request: request(operationId), dimensions: vector, ttlMs });
225
+ vectorAccepted(result, operationId);
226
+ vectorCursor(result);
227
+ return result;
228
+ }
229
+ function dimensions(suffix, requestLimit = 10, tokenLimit = 50) {
230
+ return [
231
+ { key: 'requests', units: 1, budgets: [{ key: `vector:${suffix}:requests`, limit: requestLimit }] },
232
+ { key: 'tokens', units: 5, budgets: [{ key: `vector:${suffix}:tokens`, limit: tokenLimit }] },
233
+ ];
234
+ }
235
+ function growth(suffix, requestUnits, tokenUnits, requestLimit = 10, tokenLimit = 50) {
236
+ return [
237
+ {
238
+ key: 'requests',
239
+ additionalUnits: requestUnits,
240
+ budgets: [{ key: `vector:${suffix}:requests`, limit: requestLimit }],
241
+ },
242
+ {
243
+ key: 'tokens',
244
+ additionalUnits: tokenUnits,
245
+ budgets: [{ key: `vector:${suffix}:tokens`, limit: tokenLimit }],
246
+ },
247
+ ];
248
+ }
249
+ function request(operationId, principalId = 'user-1') {
250
+ return {
251
+ operationId,
252
+ principal: { id: principalId, tenantId: 'tenant-1' },
253
+ tool: 'vector-conformance',
254
+ args: { conformance: true },
255
+ };
256
+ }
257
+ function vectorCursor(result) {
258
+ const cursor = result.reservation.growthCursor;
259
+ assert(typeof cursor === 'string' && cursor.length > 0, 'vector reservation missing growthCursor');
260
+ return cursor;
261
+ }
262
+ function assertReserved(result, key, expected) {
263
+ assert(result.reservedByDimension.find(item => item.key === key)?.reservedUnits === expected, `wrong reserved ${key}`);
264
+ }
265
+ function scalarAccepted(result, context) {
266
+ assert(result.accepted, `${context}: expected scalar admission`);
267
+ }
268
+ function scalarDenied(result, reason, context) {
269
+ assert(!result.accepted && result.reason === reason, `${context}: expected ${reason}`);
270
+ }
271
+ function vectorAccepted(result, context) {
272
+ assert(result.accepted, `${context}: expected vector admission`);
273
+ }
274
+ function vectorDenied(result, context) {
275
+ assert(!result.accepted && result.reason === 'quota_exceeded', `${context}: expected quota denial`);
276
+ }
277
+ function growthAccepted(result, context) {
278
+ assert(result.accepted, `${context}: expected vector growth`);
279
+ }
280
+ function growthDenied(result, context) {
281
+ assert(!result.accepted && result.reason === 'quota_exceeded', `${context}: expected vector growth denial`);
282
+ }
283
+ async function rejects(action, message) {
284
+ try {
285
+ await action();
286
+ }
287
+ catch {
288
+ return;
289
+ }
290
+ throw new Error(message);
291
+ }
292
+ function assert(condition, message) { if (!condition)
293
+ throw new Error(message); }
294
+ function positive(value, name) { if (!Number.isSafeInteger(value) || value <= 0)
295
+ throw new RangeError(`${name} must be positive`); }
296
+ function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
297
+ //# sourceMappingURL=vector-store-conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector-store-conformance.js","sourceRoot":"","sources":["../src/vector-store-conformance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { Budget, UsagePolicy, UsageRequest } from './index.js';
2
+ export type UnknownWeightedCreditTool = 'deny' | Readonly<{
3
+ fallbackUnits: number;
4
+ }>;
5
+ export type WeightedCreditPlanConfig = Readonly<{
6
+ limits: Readonly<Record<string, number>>;
7
+ }>;
8
+ export type WeightedCreditPolicyConfig = Readonly<{
9
+ tools: Readonly<Record<string, number>>;
10
+ plans: Readonly<Record<string, WeightedCreditPlanConfig>>;
11
+ unknownTool: UnknownWeightedCreditTool;
12
+ }>;
13
+ export type WeightedCreditBudgetContext = Readonly<{
14
+ request: UsageRequest;
15
+ plan: string;
16
+ /** Resolve one configured plan limit by name; unknown names fail closed. */
17
+ limit(name: string): number;
18
+ }>;
19
+ export type WeightedCreditBudgetResolver = (context: WeightedCreditBudgetContext) => Budget | readonly Budget[] | Promise<Budget | readonly Budget[]>;
20
+ export type WeightedCreditPlanResolver = (request: UsageRequest) => string | undefined | Promise<string | undefined>;
21
+ export type WeightedCreditsPolicyOptions = Readonly<{
22
+ /** Already-loaded trusted configuration. File/network loading remains application-owned. */
23
+ config: WeightedCreditPolicyConfig;
24
+ /** Maps the selected plan limits to one or more application-owned budget identities. */
25
+ budgets: WeightedCreditBudgetResolver;
26
+ /** Defaults to request.principal.plan. Unknown/missing plans deny closed. */
27
+ resolvePlan?: WeightedCreditPlanResolver;
28
+ reservationTtlMs?: number;
29
+ }>;
30
+ /**
31
+ * Validate and snapshot an already-loaded weighted-credit configuration.
32
+ *
33
+ * This helper intentionally does not parse JSON/YAML, resolve entitlements, derive
34
+ * accounting windows, or persist pricing/subscription state. Because duplicate
35
+ * textual JSON keys are lost before an object reaches this API, duplicate-key
36
+ * rejection (when required) belongs to the application's config loader.
37
+ */
38
+ export declare function defineWeightedCreditPolicyConfig(config: WeightedCreditPolicyConfig): WeightedCreditPolicyConfig;
39
+ /** Build a deterministic weighted-credit UsagePolicy over application-owned budgets. */
40
+ export declare function createWeightedCreditsPolicy(options: WeightedCreditsPolicyOptions): UsagePolicy;
41
+ //# sourceMappingURL=weighted-credits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weighted-credits.d.ts","sourceRoot":"","sources":["../src/weighted-credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,QAAQ,CAAC;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAErF,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC;IAC1D,WAAW,EAAE,yBAAyB,CAAC;CACxC,CAAC,CAAC;AAEH,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IACjD,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,CACzC,OAAO,EAAE,2BAA2B,KACjC,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC;AAEtE,MAAM,MAAM,0BAA0B,GAAG,CACvC,OAAO,EAAE,YAAY,KAClB,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,4FAA4F;IAC5F,MAAM,EAAE,0BAA0B,CAAC;IACnC,wFAAwF;IACxF,OAAO,EAAE,4BAA4B,CAAC;IACtC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,0BAA0B,GACjC,0BAA0B,CAwD5B;AAED,wFAAwF;AACxF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,4BAA4B,GAAG,WAAW,CAqD9F"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Validate and snapshot an already-loaded weighted-credit configuration.
3
+ *
4
+ * This helper intentionally does not parse JSON/YAML, resolve entitlements, derive
5
+ * accounting windows, or persist pricing/subscription state. Because duplicate
6
+ * textual JSON keys are lost before an object reaches this API, duplicate-key
7
+ * rejection (when required) belongs to the application's config loader.
8
+ */
9
+ export function defineWeightedCreditPolicyConfig(config) {
10
+ assertPlainRecord(config, 'config');
11
+ assertExactKeys(config, ['tools', 'plans', 'unknownTool'], 'config');
12
+ assertPlainRecord(config.tools, 'config.tools');
13
+ const tools = Object.create(null);
14
+ for (const [tool, units] of Object.entries(config.tools)) {
15
+ assertNonEmptyKey(tool, 'tool');
16
+ assertNonNegativeSafeInteger(units, `config.tools[${JSON.stringify(tool)}]`);
17
+ tools[tool] = units;
18
+ }
19
+ assertPlainRecord(config.plans, 'config.plans');
20
+ const plans = Object.create(null);
21
+ for (const [plan, entry] of Object.entries(config.plans)) {
22
+ assertNonEmptyKey(plan, 'plan');
23
+ assertPlainRecord(entry, `config.plans[${JSON.stringify(plan)}]`);
24
+ assertExactKeys(entry, ['limits'], `config.plans[${JSON.stringify(plan)}]`);
25
+ assertPlainRecord(entry.limits, `config.plans[${JSON.stringify(plan)}].limits`);
26
+ const limits = Object.create(null);
27
+ for (const [name, limit] of Object.entries(entry.limits)) {
28
+ assertNonEmptyKey(name, 'limit');
29
+ assertNonNegativeSafeInteger(limit, `config.plans[${JSON.stringify(plan)}].limits[${JSON.stringify(name)}]`);
30
+ limits[name] = limit;
31
+ }
32
+ if (Object.keys(limits).length === 0) {
33
+ throw new RangeError(`config.plans[${JSON.stringify(plan)}].limits must not be empty`);
34
+ }
35
+ plans[plan] = Object.freeze({ limits: Object.freeze(limits) });
36
+ }
37
+ if (Object.keys(plans).length === 0) {
38
+ throw new RangeError('config.plans must not be empty');
39
+ }
40
+ let unknownTool;
41
+ if (config.unknownTool === 'deny') {
42
+ unknownTool = 'deny';
43
+ }
44
+ else {
45
+ assertPlainRecord(config.unknownTool, 'config.unknownTool');
46
+ assertExactKeys(config.unknownTool, ['fallbackUnits'], 'config.unknownTool');
47
+ assertNonNegativeSafeInteger(config.unknownTool.fallbackUnits, 'config.unknownTool.fallbackUnits');
48
+ unknownTool = Object.freeze({ fallbackUnits: config.unknownTool.fallbackUnits });
49
+ }
50
+ return Object.freeze({
51
+ tools: Object.freeze(tools),
52
+ plans: Object.freeze(plans),
53
+ unknownTool,
54
+ });
55
+ }
56
+ /** Build a deterministic weighted-credit UsagePolicy over application-owned budgets. */
57
+ export function createWeightedCreditsPolicy(options) {
58
+ assertPlainRecord(options, 'options');
59
+ assertExactKeys(options, ['config', 'budgets', 'resolvePlan', 'reservationTtlMs'], 'options');
60
+ if (typeof options.budgets !== 'function')
61
+ throw new TypeError('options.budgets must be a function');
62
+ if (options.resolvePlan !== undefined && typeof options.resolvePlan !== 'function') {
63
+ throw new TypeError('options.resolvePlan must be a function when provided');
64
+ }
65
+ if (options.reservationTtlMs !== undefined) {
66
+ assertPositiveSafeInteger(options.reservationTtlMs, 'options.reservationTtlMs');
67
+ }
68
+ const config = defineWeightedCreditPolicyConfig(options.config);
69
+ const budgets = options.budgets;
70
+ const resolvePlan = options.resolvePlan ?? ((request) => request.principal.plan);
71
+ const reservationTtlMs = options.reservationTtlMs;
72
+ return Object.freeze({
73
+ async quote(request) {
74
+ const configuredUnits = config.tools[request.tool];
75
+ const units = configuredUnits ??
76
+ (config.unknownTool === 'deny' ? undefined : config.unknownTool.fallbackUnits);
77
+ if (units === undefined)
78
+ return { decision: 'deny', reason: 'unknown_tool' };
79
+ const plan = await resolvePlan(request);
80
+ if (plan !== undefined && (typeof plan !== 'string' || plan.length === 0)) {
81
+ throw new TypeError('resolvePlan must return a non-empty string or undefined');
82
+ }
83
+ if (plan === undefined || config.plans[plan] === undefined) {
84
+ return { decision: 'deny', reason: 'unknown_plan' };
85
+ }
86
+ const planLimits = config.plans[plan].limits;
87
+ const resolved = await budgets({
88
+ request,
89
+ plan,
90
+ limit(name) {
91
+ const value = planLimits[name];
92
+ if (value === undefined) {
93
+ throw new RangeError(`unknown configured limit ${JSON.stringify(name)} for plan ${JSON.stringify(plan)}`);
94
+ }
95
+ return value;
96
+ },
97
+ });
98
+ const normalizedBudgets = Array.isArray(resolved) ? resolved : [resolved];
99
+ return {
100
+ decision: 'allow',
101
+ units,
102
+ budgets: normalizedBudgets,
103
+ ...(reservationTtlMs === undefined ? {} : { reservationTtlMs }),
104
+ };
105
+ },
106
+ });
107
+ }
108
+ function assertPlainRecord(value, name) {
109
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
110
+ throw new TypeError(`${name} must be a plain object`);
111
+ }
112
+ const proto = Object.getPrototypeOf(value);
113
+ if (proto !== Object.prototype && proto !== null) {
114
+ throw new TypeError(`${name} must be a plain object`);
115
+ }
116
+ }
117
+ function assertExactKeys(value, allowed, name) {
118
+ const allowedSet = new Set(allowed);
119
+ for (const key of Object.keys(value)) {
120
+ if (!allowedSet.has(key))
121
+ throw new TypeError(`${name} contains unknown field ${JSON.stringify(key)}`);
122
+ }
123
+ for (const key of allowed) {
124
+ if (!(key in value) && (key === 'config' || key === 'budgets' || key === 'tools' || key === 'plans' || key === 'unknownTool' || key === 'limits')) {
125
+ throw new TypeError(`${name}.${key} is required`);
126
+ }
127
+ }
128
+ }
129
+ function assertNonEmptyKey(value, kind) {
130
+ if (value.trim().length === 0)
131
+ throw new TypeError(`${kind} key must not be empty`);
132
+ }
133
+ function assertNonNegativeSafeInteger(value, name) {
134
+ if (!Number.isSafeInteger(value) || value < 0) {
135
+ throw new RangeError(`${name} must be a non-negative safe integer`);
136
+ }
137
+ }
138
+ function assertPositiveSafeInteger(value, name) {
139
+ if (!Number.isSafeInteger(value) || value <= 0) {
140
+ throw new RangeError(`${name} must be a positive safe integer`);
141
+ }
142
+ }
143
+ //# sourceMappingURL=weighted-credits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weighted-credits.js","sourceRoot":"","sources":["../src/weighted-credits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export type AccountingWindowPeriod = 'calendar-day' | 'calendar-month';
2
+ export type AccountingWindowInstant = number | Date;
3
+ export type WindowedBudgetKeyConfig = Readonly<{
4
+ period: AccountingWindowPeriod;
5
+ timeZone: string;
6
+ namespace: string;
7
+ /** Optional trusted clock. `key({ now })` / `window({ now })` override it. */
8
+ clock?: () => AccountingWindowInstant;
9
+ }>;
10
+ export type WindowedBudgetKeyInput = Readonly<{
11
+ scope: string;
12
+ id: string;
13
+ now?: AccountingWindowInstant;
14
+ }>;
15
+ export type AccountingWindowProjection = Readonly<{
16
+ key: string;
17
+ /** Inclusive epoch-millisecond start of the selected calendar window. */
18
+ startsAt: number;
19
+ /** Exclusive epoch-millisecond end; this is the next reset boundary for this window. */
20
+ endsAt: number;
21
+ }>;
22
+ export type WindowedBudgetKey = Readonly<{
23
+ key(input: WindowedBudgetKeyInput): string;
24
+ /** Derive the exact key and matching calendar boundary from one trusted calculation. */
25
+ window(input: WindowedBudgetKeyInput): AccountingWindowProjection;
26
+ }>;
27
+ /**
28
+ * Create a pure calendar-window budget-key helper.
29
+ *
30
+ * The Store never observes wall-clock rollover. A caller selects a new accounting
31
+ * bucket only by deriving a new key from explicit inputs. The configured time-zone
32
+ * literal is part of key identity, so changing it intentionally selects fresh state
33
+ * instead of silently reusing an old bucket with different boundary semantics.
34
+ */
35
+ export declare function createWindowedBudgetKey(config: WindowedBudgetKeyConfig): WindowedBudgetKey;
36
+ //# sourceMappingURL=windowed-budget-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowed-budget-keys.d.ts","sourceRoot":"","sources":["../src/windowed-budget-keys.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,gBAAgB,CAAC;AACvE,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,IAAI,CAAC;AAEpD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,uBAAuB,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,GAAG,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAAC;IAC3C,wFAAwF;IACxF,MAAM,CAAC,KAAK,EAAE,sBAAsB,GAAG,0BAA0B,CAAC;CACnE,CAAC,CAAC;AAKH;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,uBAAuB,GAAG,iBAAiB,CA6E1F"}