@peac/control 0.10.9 → 0.10.10

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/LICENSE CHANGED
@@ -175,7 +175,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
175
175
 
176
176
  END OF TERMS AND CONDITIONS
177
177
 
178
- Copyright 2025 PEAC Protocol Contributors
178
+ Copyright 2025-2026 PEAC Protocol Contributors
179
179
 
180
180
  Licensed under the Apache License, Version 2.0 (the "License");
181
181
  you may not use this file except in compliance with the License.
@@ -1 +1 @@
1
- {"version":3,"file":"enforcement.d.ts","sourceRoot":"","sources":["../src/enforcement.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,2BAA2B,EAC3B,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,KAAK,iBAAiB,GAAG,2BAA2B,CAAC;AAErD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,GAAE,MAAsC,GAClD,iBAAiB,CAiCnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,KAAK,CAAC,EAAE,YAAY,GACnB,iBAAiB,CAgCnB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,EACzB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,iBAAiB,CA4CnB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAmDnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,UAAU,EACnB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAsBnB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAEnB"}
1
+ {"version":3,"file":"enforcement.d.ts","sourceRoot":"","sources":["../src/enforcement.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,2BAA2B,EAC3B,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,KAAK,iBAAiB,GAAG,2BAA2B,CAAC;AAErD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,GAAE,MAAsC,GAClD,iBAAiB,CAiCnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,KAAK,CAAC,EAAE,YAAY,GACnB,iBAAiB,CAgCnB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,EACzB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,iBAAiB,CA4CnB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAmDnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,UAAU,EACnB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAuBnB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,YAAY,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,MAAM,GACnB,iBAAiB,CAEnB"}
package/dist/index.cjs ADDED
@@ -0,0 +1,466 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ var schema = require('@peac/schema');
5
+
6
+ // src/adapter.ts
7
+ var ControlEngineRegistry = class {
8
+ engines = /* @__PURE__ */ new Map();
9
+ /**
10
+ * Register a control engine
11
+ *
12
+ * @param engine - Control engine adapter
13
+ * @throws Error if engine with same ID already registered
14
+ */
15
+ register(engine) {
16
+ if (this.engines.has(engine.engineId)) {
17
+ throw new Error(`Control engine already registered: ${engine.engineId}`);
18
+ }
19
+ this.engines.set(engine.engineId, engine);
20
+ }
21
+ /**
22
+ * Get control engine by ID
23
+ *
24
+ * @param engineId - Engine identifier
25
+ * @returns Control engine adapter
26
+ * @throws Error if engine not found
27
+ */
28
+ get(engineId) {
29
+ const engine = this.engines.get(engineId);
30
+ if (!engine) {
31
+ throw new Error(`Control engine not found: ${engineId}`);
32
+ }
33
+ return engine;
34
+ }
35
+ /**
36
+ * Check if engine is registered
37
+ *
38
+ * @param engineId - Engine identifier
39
+ * @returns True if engine is registered
40
+ */
41
+ has(engineId) {
42
+ return this.engines.has(engineId);
43
+ }
44
+ /**
45
+ * Get all registered engine IDs
46
+ *
47
+ * @returns Array of engine IDs
48
+ */
49
+ list() {
50
+ return Array.from(this.engines.keys());
51
+ }
52
+ };
53
+ var TemporalConstraintBaseSchema = zod.z.object({
54
+ type: zod.z.literal("temporal"),
55
+ valid_from: zod.z.number().int().positive().optional(),
56
+ valid_until: zod.z.number().int().positive().optional(),
57
+ duration: zod.z.number().int().positive().optional()
58
+ });
59
+ var UsageConstraintBaseSchema = zod.z.object({
60
+ type: zod.z.literal("usage"),
61
+ max_uses: zod.z.number().int().positive(),
62
+ current_uses: zod.z.number().int().nonnegative().optional(),
63
+ window: zod.z.number().int().positive().optional()
64
+ });
65
+ var BudgetConstraintBaseSchema = zod.z.object({
66
+ type: zod.z.literal("budget"),
67
+ max_amount: zod.z.number().int().positive(),
68
+ current_amount: zod.z.number().int().nonnegative().optional(),
69
+ window: zod.z.number().int().positive().optional(),
70
+ currency: zod.z.string().length(3).toUpperCase()
71
+ });
72
+ var CombinedConstraintBaseSchema = zod.z.object({
73
+ type: zod.z.literal("combined"),
74
+ temporal: zod.z.object({
75
+ valid_from: zod.z.number().int().positive().optional(),
76
+ valid_until: zod.z.number().int().positive().optional(),
77
+ duration: zod.z.number().int().positive().optional()
78
+ }).optional(),
79
+ usage: zod.z.object({
80
+ max_uses: zod.z.number().int().positive(),
81
+ current_uses: zod.z.number().int().nonnegative().optional(),
82
+ window: zod.z.number().int().positive().optional()
83
+ }).optional(),
84
+ budget: zod.z.object({
85
+ max_amount: zod.z.number().int().positive(),
86
+ current_amount: zod.z.number().int().nonnegative().optional(),
87
+ window: zod.z.number().int().positive().optional(),
88
+ currency: zod.z.string().length(3).toUpperCase()
89
+ }).optional()
90
+ });
91
+ var TemporalConstraintSchema = TemporalConstraintBaseSchema.refine(
92
+ (data) => {
93
+ return data.valid_from !== void 0 || data.valid_until !== void 0 || data.duration !== void 0;
94
+ },
95
+ {
96
+ message: "At least one temporal constraint (valid_from, valid_until, duration) must be specified"
97
+ }
98
+ ).refine(
99
+ (data) => {
100
+ if (data.valid_from !== void 0 && data.valid_until !== void 0) {
101
+ return data.valid_until > data.valid_from;
102
+ }
103
+ return true;
104
+ },
105
+ {
106
+ message: "valid_until must be after valid_from"
107
+ }
108
+ );
109
+ var UsageConstraintSchema = UsageConstraintBaseSchema.refine(
110
+ (data) => {
111
+ if (data.current_uses !== void 0) {
112
+ return data.current_uses <= data.max_uses;
113
+ }
114
+ return true;
115
+ },
116
+ {
117
+ message: "current_uses cannot exceed max_uses"
118
+ }
119
+ );
120
+ var BudgetConstraintSchema = BudgetConstraintBaseSchema.refine(
121
+ (data) => {
122
+ if (data.current_amount !== void 0) {
123
+ return data.current_amount <= data.max_amount;
124
+ }
125
+ return true;
126
+ },
127
+ {
128
+ message: "current_amount cannot exceed max_amount"
129
+ }
130
+ );
131
+ var CombinedConstraintSchema = CombinedConstraintBaseSchema.refine(
132
+ (data) => {
133
+ return data.temporal !== void 0 || data.usage !== void 0 || data.budget !== void 0;
134
+ },
135
+ {
136
+ message: "At least one mandate (temporal, usage, budget) must be specified in combined type"
137
+ }
138
+ );
139
+ var ConstraintSchema = zod.z.discriminatedUnion("type", [
140
+ TemporalConstraintBaseSchema,
141
+ UsageConstraintBaseSchema,
142
+ BudgetConstraintBaseSchema,
143
+ CombinedConstraintBaseSchema
144
+ ]);
145
+ var ControlBlockSchema2 = zod.z.object({
146
+ mandate: ConstraintSchema,
147
+ scope: zod.z.string().url().optional(),
148
+ metadata: zod.z.record(zod.z.unknown()).optional()
149
+ });
150
+ var ControlStateSchema = zod.z.object({
151
+ receipt_id: zod.z.string().uuid(),
152
+ constraint: ConstraintSchema,
153
+ usage_count: zod.z.number().int().nonnegative().optional(),
154
+ spent_amount: zod.z.number().int().nonnegative().optional(),
155
+ first_use: zod.z.number().int().positive().optional(),
156
+ last_use: zod.z.number().int().positive().optional(),
157
+ metadata: zod.z.record(zod.z.unknown()).optional()
158
+ });
159
+
160
+ // src/enforcement.ts
161
+ function enforceTemporalConstraint(mandate, currentTime = Math.floor(Date.now() / 1e3)) {
162
+ if (mandate.valid_from !== void 0 && currentTime < mandate.valid_from) {
163
+ const remaining = mandate.valid_from - currentTime;
164
+ return {
165
+ allowed: false,
166
+ reason: `Access not yet valid (starts in ${remaining}s)`,
167
+ remaining: { seconds: remaining }
168
+ };
169
+ }
170
+ if (mandate.valid_until !== void 0 && currentTime > mandate.valid_until) {
171
+ return {
172
+ allowed: false,
173
+ reason: "Access has expired",
174
+ remaining: { seconds: 0 }
175
+ };
176
+ }
177
+ let remainingSeconds;
178
+ if (mandate.valid_until !== void 0) {
179
+ remainingSeconds = mandate.valid_until - currentTime;
180
+ } else if (mandate.duration !== void 0 && mandate.valid_from !== void 0) {
181
+ const expiresAt = mandate.valid_from + mandate.duration;
182
+ remainingSeconds = expiresAt - currentTime;
183
+ }
184
+ return {
185
+ allowed: true,
186
+ remaining: remainingSeconds !== void 0 ? { seconds: remainingSeconds } : void 0
187
+ };
188
+ }
189
+ function enforceUsageConstraint(mandate, state) {
190
+ const currentUses = state?.usage_count ?? mandate.current_uses ?? 0;
191
+ if (currentUses >= mandate.max_uses) {
192
+ return {
193
+ allowed: false,
194
+ reason: `Usage limit exceeded (${currentUses}/${mandate.max_uses})`,
195
+ remaining: { uses: 0 }
196
+ };
197
+ }
198
+ if (mandate.window !== void 0 && state?.first_use !== void 0) {
199
+ const currentTime = Math.floor(Date.now() / 1e3);
200
+ const windowExpiry = state.first_use + mandate.window;
201
+ if (currentTime > windowExpiry) {
202
+ return {
203
+ allowed: false,
204
+ reason: "Usage window expired",
205
+ remaining: { uses: 0 }
206
+ };
207
+ }
208
+ }
209
+ const remainingUses = mandate.max_uses - currentUses;
210
+ return {
211
+ allowed: true,
212
+ remaining: { uses: remainingUses }
213
+ };
214
+ }
215
+ function enforceBudgetConstraint(mandate, state, requestedAmount) {
216
+ const currentAmount = state?.spent_amount ?? mandate.current_amount ?? 0;
217
+ if (currentAmount >= mandate.max_amount) {
218
+ return {
219
+ allowed: false,
220
+ reason: `Budget limit exceeded (${currentAmount}/${mandate.max_amount} ${mandate.currency})`,
221
+ remaining: { amount: 0 }
222
+ };
223
+ }
224
+ if (requestedAmount !== void 0) {
225
+ if (currentAmount + requestedAmount > mandate.max_amount) {
226
+ const remaining = mandate.max_amount - currentAmount;
227
+ return {
228
+ allowed: false,
229
+ reason: `Requested amount would exceed budget (${requestedAmount} > ${remaining} ${mandate.currency} remaining)`,
230
+ remaining: { amount: remaining }
231
+ };
232
+ }
233
+ }
234
+ if (mandate.window !== void 0 && state?.first_use !== void 0) {
235
+ const currentTime = Math.floor(Date.now() / 1e3);
236
+ const windowExpiry = state.first_use + mandate.window;
237
+ if (currentTime > windowExpiry) {
238
+ return {
239
+ allowed: false,
240
+ reason: "Budget window expired",
241
+ remaining: { amount: 0 }
242
+ };
243
+ }
244
+ }
245
+ const remainingAmount = mandate.max_amount - currentAmount;
246
+ return {
247
+ allowed: true,
248
+ remaining: { amount: remainingAmount }
249
+ };
250
+ }
251
+ function enforceCombinedConstraint(mandate, state, requestedAmount, currentTime) {
252
+ const results = [];
253
+ if (mandate.temporal !== void 0) {
254
+ const temporalConstraint = {
255
+ ...mandate.temporal
256
+ };
257
+ const result = enforceTemporalConstraint(temporalConstraint, currentTime);
258
+ results.push(result);
259
+ }
260
+ if (mandate.usage !== void 0) {
261
+ const usageConstraint = {
262
+ ...mandate.usage
263
+ };
264
+ const result = enforceUsageConstraint(usageConstraint, state);
265
+ results.push(result);
266
+ }
267
+ if (mandate.budget !== void 0) {
268
+ const budgetConstraint = {
269
+ ...mandate.budget
270
+ };
271
+ const result = enforceBudgetConstraint(budgetConstraint, state, requestedAmount);
272
+ results.push(result);
273
+ }
274
+ const failedResult = results.find((r) => !r.allowed);
275
+ if (failedResult) {
276
+ return failedResult;
277
+ }
278
+ const remaining = {};
279
+ for (const result of results) {
280
+ if (result.remaining) {
281
+ Object.assign(remaining, result.remaining);
282
+ }
283
+ }
284
+ return {
285
+ allowed: true,
286
+ remaining: Object.keys(remaining).length > 0 ? remaining : void 0
287
+ };
288
+ }
289
+ function enforceConstraint(mandate, state, requestedAmount, currentTime) {
290
+ switch (mandate.type) {
291
+ case "temporal":
292
+ return enforceTemporalConstraint(mandate, currentTime);
293
+ case "usage":
294
+ return enforceUsageConstraint(mandate, state);
295
+ case "budget":
296
+ return enforceBudgetConstraint(mandate, state, requestedAmount);
297
+ case "combined":
298
+ return enforceCombinedConstraint(mandate, state, requestedAmount, currentTime);
299
+ default: {
300
+ const _exhaustive = mandate;
301
+ return {
302
+ allowed: false,
303
+ reason: `Unknown mandate type: ${_exhaustive.type}`
304
+ };
305
+ }
306
+ }
307
+ }
308
+ function enforceControlBlock(constraint, state, requestedAmount, currentTime) {
309
+ return enforceConstraint(constraint, state, requestedAmount, currentTime);
310
+ }
311
+
312
+ // src/state.ts
313
+ function createControlState(receiptId, constraint) {
314
+ return {
315
+ receipt_id: receiptId,
316
+ constraint,
317
+ usage_count: 0,
318
+ spent_amount: 0,
319
+ metadata: {}
320
+ };
321
+ }
322
+ function updateStateAfterUse(state, amount) {
323
+ const currentTime = Math.floor(Date.now() / 1e3);
324
+ const usageCount = (state.usage_count ?? 0) + 1;
325
+ const spentAmount = (state.spent_amount ?? 0) + (amount ?? 0);
326
+ return {
327
+ ...state,
328
+ usage_count: usageCount,
329
+ spent_amount: spentAmount,
330
+ first_use: state.first_use ?? currentTime,
331
+ last_use: currentTime
332
+ };
333
+ }
334
+ function isStateExpired(state) {
335
+ const { constraint: mandate } = state;
336
+ const currentTime = Math.floor(Date.now() / 1e3);
337
+ if (mandate.type === "temporal") {
338
+ if (mandate.valid_until !== void 0 && currentTime > mandate.valid_until) {
339
+ return true;
340
+ }
341
+ if (mandate.duration !== void 0 && state.first_use !== void 0) {
342
+ const expiresAt = state.first_use + mandate.duration;
343
+ if (currentTime > expiresAt) {
344
+ return true;
345
+ }
346
+ }
347
+ }
348
+ if (mandate.type === "combined" && mandate.temporal) {
349
+ if (mandate.temporal.valid_until !== void 0 && currentTime > mandate.temporal.valid_until) {
350
+ return true;
351
+ }
352
+ if (mandate.temporal.duration !== void 0 && state.first_use !== void 0) {
353
+ const expiresAt = state.first_use + mandate.temporal.duration;
354
+ if (currentTime > expiresAt) {
355
+ return true;
356
+ }
357
+ }
358
+ }
359
+ if (mandate.type === "usage" && mandate.window !== void 0 && state.first_use !== void 0) {
360
+ const windowExpiry = state.first_use + mandate.window;
361
+ if (currentTime > windowExpiry) {
362
+ return true;
363
+ }
364
+ }
365
+ if (mandate.type === "budget" && mandate.window !== void 0 && state.first_use !== void 0) {
366
+ const windowExpiry = state.first_use + mandate.window;
367
+ if (currentTime > windowExpiry) {
368
+ return true;
369
+ }
370
+ }
371
+ if (mandate.type === "combined") {
372
+ if (mandate.usage?.window !== void 0 && state.first_use !== void 0) {
373
+ const windowExpiry = state.first_use + mandate.usage.window;
374
+ if (currentTime > windowExpiry) {
375
+ return true;
376
+ }
377
+ }
378
+ if (mandate.budget?.window !== void 0 && state.first_use !== void 0) {
379
+ const windowExpiry = state.first_use + mandate.budget.window;
380
+ if (currentTime > windowExpiry) {
381
+ return true;
382
+ }
383
+ }
384
+ }
385
+ return false;
386
+ }
387
+ function resetState(state) {
388
+ return {
389
+ ...state,
390
+ usage_count: 0,
391
+ spent_amount: 0,
392
+ first_use: void 0,
393
+ last_use: void 0
394
+ };
395
+ }
396
+ function getStateSummary(state) {
397
+ const parts = [];
398
+ if (state.usage_count !== void 0 && state.usage_count > 0) {
399
+ parts.push(`uses: ${state.usage_count}`);
400
+ }
401
+ if (state.spent_amount !== void 0 && state.spent_amount > 0) {
402
+ const currency = state.constraint.type === "budget" ? state.constraint.currency : state.constraint.type === "combined" && state.constraint.budget ? state.constraint.budget.currency : "units";
403
+ parts.push(`spent: ${state.spent_amount} ${currency}`);
404
+ }
405
+ if (state.first_use !== void 0) {
406
+ const date = new Date(state.first_use * 1e3).toISOString();
407
+ parts.push(`first: ${date}`);
408
+ }
409
+ if (state.last_use !== void 0) {
410
+ const date = new Date(state.last_use * 1e3).toISOString();
411
+ parts.push(`last: ${date}`);
412
+ }
413
+ return parts.join(", ");
414
+ }
415
+
416
+ Object.defineProperty(exports, "ChainControlBlockSchema", {
417
+ enumerable: true,
418
+ get: function () { return schema.ControlBlockSchema; }
419
+ });
420
+ Object.defineProperty(exports, "ControlDecisionSchema", {
421
+ enumerable: true,
422
+ get: function () { return schema.ControlDecisionSchema; }
423
+ });
424
+ Object.defineProperty(exports, "ControlLicensingModeSchema", {
425
+ enumerable: true,
426
+ get: function () { return schema.ControlLicensingModeSchema; }
427
+ });
428
+ Object.defineProperty(exports, "ControlPurposeSchema", {
429
+ enumerable: true,
430
+ get: function () { return schema.ControlPurposeSchema; }
431
+ });
432
+ Object.defineProperty(exports, "ControlStepSchema", {
433
+ enumerable: true,
434
+ get: function () { return schema.ControlStepSchema; }
435
+ });
436
+ exports.BudgetConstraintSchema = BudgetConstraintSchema;
437
+ exports.BudgetMandateSchema = BudgetConstraintSchema;
438
+ exports.CombinedConstraintSchema = CombinedConstraintSchema;
439
+ exports.CombinedMandateSchema = CombinedConstraintSchema;
440
+ exports.ConstraintSchema = ConstraintSchema;
441
+ exports.ControlBlockSchema = ControlBlockSchema2;
442
+ exports.ControlEngineRegistry = ControlEngineRegistry;
443
+ exports.ControlStateSchema = ControlStateSchema;
444
+ exports.MandateSchema = ConstraintSchema;
445
+ exports.TemporalConstraintSchema = TemporalConstraintSchema;
446
+ exports.TemporalMandateSchema = TemporalConstraintSchema;
447
+ exports.UsageConstraintSchema = UsageConstraintSchema;
448
+ exports.UsageMandateSchema = UsageConstraintSchema;
449
+ exports.createControlState = createControlState;
450
+ exports.enforceBudgetConstraint = enforceBudgetConstraint;
451
+ exports.enforceBudgetMandate = enforceBudgetConstraint;
452
+ exports.enforceCombinedConstraint = enforceCombinedConstraint;
453
+ exports.enforceCombinedMandate = enforceCombinedConstraint;
454
+ exports.enforceConstraint = enforceConstraint;
455
+ exports.enforceControlBlock = enforceControlBlock;
456
+ exports.enforceMandate = enforceConstraint;
457
+ exports.enforceTemporalConstraint = enforceTemporalConstraint;
458
+ exports.enforceTemporalMandate = enforceTemporalConstraint;
459
+ exports.enforceUsageConstraint = enforceUsageConstraint;
460
+ exports.enforceUsageMandate = enforceUsageConstraint;
461
+ exports.getStateSummary = getStateSummary;
462
+ exports.isStateExpired = isStateExpired;
463
+ exports.resetState = resetState;
464
+ exports.updateStateAfterUse = updateStateAfterUse;
465
+ //# sourceMappingURL=index.cjs.map
466
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts","../src/validators.ts","../src/enforcement.ts","../src/state.ts"],"names":["z","ControlBlockSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * PEAC Control Engine Adapter Interface\n *\n * Minimal, vendor-neutral interface for control engine implementations.\n * Control engines evaluate authorization policies and return allow/deny decisions.\n *\n * @packageDocumentation\n */\n\nimport type { ControlStep } from '@peac/schema';\n\n/**\n * Context provided to control engine for evaluation\n *\n * This is the minimal context needed for most control engines.\n * Engines may require additional context via the `policy` field.\n */\nexport interface ControlEvaluationContext {\n /** Resource being accessed (e.g., \"https://api.example.com/v1/chat\") */\n resource: string;\n\n /** HTTP method or operation (e.g., \"POST\", \"read\", \"write\") */\n method: string;\n\n /** Requested payment amount (smallest currency unit), if applicable */\n amount?: number;\n\n /** Currency (ISO 4217), if applicable */\n currency?: string;\n\n /** Subject identifier (e.g., agent ID, user ID) */\n subject?: string;\n\n /** Policy document fetched from policy_uri (engine-specific structure) */\n policy: unknown;\n\n /** Current timestamp (Unix seconds) for temporal checks */\n timestamp?: number;\n\n /** Additional context (engine-specific) */\n [key: string]: unknown;\n}\n\n/**\n * Control Engine Adapter\n *\n * Minimal interface that all control engines must implement.\n *\n * **Design principles**:\n * - Vendor-neutral: No hardcoded engine names or vendor-specific types\n * - Stateless: Engine is responsible for fetching its own state if needed\n * - Async: Allows engines to make network calls (fetch policies, check quotas)\n * - Opaque: Policy structure is engine-specific (unknown type)\n *\n * **Examples of engines**:\n * - Spend control: Per-transaction, daily, monthly limits\n * - Risk scoring: Fraud detection, anomaly detection\n * - Mandate enforcement: Enterprise approval chains\n * - Rate limiting: Request quotas, throttling\n *\n * **Usage**:\n * ```typescript\n * const engine: ControlEngineAdapter = new MyControlEngine();\n * const step = await engine.evaluate({\n * resource: \"https://api.example.com/v1/chat\",\n * method: \"POST\",\n * amount: 250,\n * currency: \"USD\",\n * policy: { ... } // Fetched from policy_uri\n * });\n * ```\n */\nexport interface ControlEngineAdapter {\n /**\n * Engine identifier (vendor-neutral)\n *\n * Examples:\n * - \"spend-control-service\"\n * - \"risk-engine\"\n * - \"mandate-service\"\n *\n * See docs/specs/registries.json for common identifiers.\n */\n readonly engineId: string;\n\n /**\n * Engine version (optional, for tracking)\n *\n * Format: Semantic versioning (e.g., \"1.2.3\")\n */\n readonly version?: string;\n\n /**\n * Evaluate authorization policy and return control decision\n *\n * @param context - Evaluation context (resource, method, amount, policy, etc.)\n * @returns Control step with decision (allow/deny) and optional limits_snapshot\n * @throws Error if evaluation fails (network error, invalid policy, etc.)\n *\n * **Requirements**:\n * - MUST return a valid ControlStep with result: \"allow\" | \"deny\" | \"review\"\n * - SHOULD populate reason if result is \"deny\" or \"review\"\n * - MAY populate limits_snapshot with engine-specific state\n * - MAY populate evidence_ref with URL to detailed evidence\n * - MUST NOT throw on normal deny decisions (only throw on errors)\n */\n evaluate(context: ControlEvaluationContext): Promise<ControlStep>;\n}\n\n/**\n * Control Engine Registry\n *\n * Optional helper for managing multiple control engines.\n *\n * **Usage**:\n * ```typescript\n * const registry = new ControlEngineRegistry();\n * registry.register(new SpendControlEngine());\n * registry.register(new RiskEngine());\n *\n * const engine = registry.get(\"spend-control-service\");\n * const step = await engine.evaluate(context);\n * ```\n */\nexport class ControlEngineRegistry {\n private engines = new Map<string, ControlEngineAdapter>();\n\n /**\n * Register a control engine\n *\n * @param engine - Control engine adapter\n * @throws Error if engine with same ID already registered\n */\n register(engine: ControlEngineAdapter): void {\n if (this.engines.has(engine.engineId)) {\n throw new Error(`Control engine already registered: ${engine.engineId}`);\n }\n this.engines.set(engine.engineId, engine);\n }\n\n /**\n * Get control engine by ID\n *\n * @param engineId - Engine identifier\n * @returns Control engine adapter\n * @throws Error if engine not found\n */\n get(engineId: string): ControlEngineAdapter {\n const engine = this.engines.get(engineId);\n if (!engine) {\n throw new Error(`Control engine not found: ${engineId}`);\n }\n return engine;\n }\n\n /**\n * Check if engine is registered\n *\n * @param engineId - Engine identifier\n * @returns True if engine is registered\n */\n has(engineId: string): boolean {\n return this.engines.has(engineId);\n }\n\n /**\n * Get all registered engine IDs\n *\n * @returns Array of engine IDs\n */\n list(): string[] {\n return Array.from(this.engines.keys());\n }\n}\n","/**\n * PEAC Control Abstraction Layer (CAL) Validators\n *\n * Validation logic for control blocks and mandates.\n */\n\nimport { z } from 'zod';\n\n/**\n * Base temporal mandate schema (without refinements)\n */\nconst TemporalConstraintBaseSchema = z.object({\n type: z.literal('temporal'),\n valid_from: z.number().int().positive().optional(),\n valid_until: z.number().int().positive().optional(),\n duration: z.number().int().positive().optional(),\n});\n\n/**\n * Base usage mandate schema (without refinements)\n */\nconst UsageConstraintBaseSchema = z.object({\n type: z.literal('usage'),\n max_uses: z.number().int().positive(),\n current_uses: z.number().int().nonnegative().optional(),\n window: z.number().int().positive().optional(),\n});\n\n/**\n * Base budget mandate schema (without refinements)\n */\nconst BudgetConstraintBaseSchema = z.object({\n type: z.literal('budget'),\n max_amount: z.number().int().positive(),\n current_amount: z.number().int().nonnegative().optional(),\n window: z.number().int().positive().optional(),\n currency: z.string().length(3).toUpperCase(),\n});\n\n/**\n * Base combined mandate schema (without refinements)\n */\nconst CombinedConstraintBaseSchema = z.object({\n type: z.literal('combined'),\n temporal: z\n .object({\n valid_from: z.number().int().positive().optional(),\n valid_until: z.number().int().positive().optional(),\n duration: z.number().int().positive().optional(),\n })\n .optional(),\n usage: z\n .object({\n max_uses: z.number().int().positive(),\n current_uses: z.number().int().nonnegative().optional(),\n window: z.number().int().positive().optional(),\n })\n .optional(),\n budget: z\n .object({\n max_amount: z.number().int().positive(),\n current_amount: z.number().int().nonnegative().optional(),\n window: z.number().int().positive().optional(),\n currency: z.string().length(3).toUpperCase(),\n })\n .optional(),\n});\n\n/**\n * Temporal mandate schema (with validation)\n */\nexport const TemporalConstraintSchema = TemporalConstraintBaseSchema.refine(\n (data) => {\n // At least one temporal constraint must be specified\n return (\n data.valid_from !== undefined || data.valid_until !== undefined || data.duration !== undefined\n );\n },\n {\n message:\n 'At least one temporal constraint (valid_from, valid_until, duration) must be specified',\n }\n).refine(\n (data) => {\n // If both valid_from and valid_until are specified, valid_until must be after valid_from\n if (data.valid_from !== undefined && data.valid_until !== undefined) {\n return data.valid_until > data.valid_from;\n }\n return true;\n },\n {\n message: 'valid_until must be after valid_from',\n }\n);\n\n/**\n * Usage mandate schema (with validation)\n */\nexport const UsageConstraintSchema = UsageConstraintBaseSchema.refine(\n (data) => {\n // current_uses cannot exceed max_uses\n if (data.current_uses !== undefined) {\n return data.current_uses <= data.max_uses;\n }\n return true;\n },\n {\n message: 'current_uses cannot exceed max_uses',\n }\n);\n\n/**\n * Budget mandate schema (with validation)\n */\nexport const BudgetConstraintSchema = BudgetConstraintBaseSchema.refine(\n (data) => {\n // current_amount cannot exceed max_amount\n if (data.current_amount !== undefined) {\n return data.current_amount <= data.max_amount;\n }\n return true;\n },\n {\n message: 'current_amount cannot exceed max_amount',\n }\n);\n\n/**\n * Combined mandate schema (with validation)\n */\nexport const CombinedConstraintSchema = CombinedConstraintBaseSchema.refine(\n (data) => {\n // At least one mandate type must be specified\n return data.temporal !== undefined || data.usage !== undefined || data.budget !== undefined;\n },\n {\n message: 'At least one mandate (temporal, usage, budget) must be specified in combined type',\n }\n);\n\n/**\n * Constraint schema (discriminated union using base schemas)\n */\nexport const ConstraintSchema = z.discriminatedUnion('type', [\n TemporalConstraintBaseSchema,\n UsageConstraintBaseSchema,\n BudgetConstraintBaseSchema,\n CombinedConstraintBaseSchema,\n]);\n\n/**\n * Control block schema\n */\nexport const ControlBlockSchema = z.object({\n mandate: ConstraintSchema,\n scope: z.string().url().optional(),\n metadata: z.record(z.unknown()).optional(),\n});\n\n/**\n * Control state schema\n */\nexport const ControlStateSchema = z.object({\n receipt_id: z.string().uuid(),\n constraint: ConstraintSchema,\n usage_count: z.number().int().nonnegative().optional(),\n spent_amount: z.number().int().nonnegative().optional(),\n first_use: z.number().int().positive().optional(),\n last_use: z.number().int().positive().optional(),\n metadata: z.record(z.unknown()).optional(),\n});\n\n// -----------------------------------------------------------------------------\n// CAL Semantic Validators (v0.9.16+)\n// Re-exported from @peac/schema for convenience\n// -----------------------------------------------------------------------------\n\nexport {\n ControlPurposeSchema,\n ControlLicensingModeSchema,\n ControlDecisionSchema,\n ControlStepSchema,\n // Note: ControlBlockSchema from @peac/schema validates chain-based governance blocks\n // (chain/decision/combinator), while the ControlBlockSchema above validates\n // constraint-based blocks (mandate/scope/metadata). We export the chain-based\n // one with a distinct name to avoid confusion.\n ControlBlockSchema as ChainControlBlockSchema,\n} from '@peac/schema';\n","/**\n * PEAC Control Abstraction Layer (CAL) Enforcement\n *\n * Enforcement logic for mandates and control blocks.\n */\n\nimport type {\n Constraint,\n ControlState,\n ConstraintEnforcementResult,\n TemporalConstraint,\n UsageConstraint,\n BudgetConstraint,\n CombinedConstraint,\n} from './types';\n\ntype EnforcementResult = ConstraintEnforcementResult;\n\n/**\n * Enforce temporal mandate\n */\nexport function enforceTemporalConstraint(\n mandate: TemporalConstraint,\n currentTime: number = Math.floor(Date.now() / 1000)\n): EnforcementResult {\n // Check valid_from\n if (mandate.valid_from !== undefined && currentTime < mandate.valid_from) {\n const remaining = mandate.valid_from - currentTime;\n return {\n allowed: false,\n reason: `Access not yet valid (starts in ${remaining}s)`,\n remaining: { seconds: remaining },\n };\n }\n\n // Check valid_until\n if (mandate.valid_until !== undefined && currentTime > mandate.valid_until) {\n return {\n allowed: false,\n reason: 'Access has expired',\n remaining: { seconds: 0 },\n };\n }\n\n // Calculate remaining time\n let remainingSeconds: number | undefined;\n if (mandate.valid_until !== undefined) {\n remainingSeconds = mandate.valid_until - currentTime;\n } else if (mandate.duration !== undefined && mandate.valid_from !== undefined) {\n const expiresAt = mandate.valid_from + mandate.duration;\n remainingSeconds = expiresAt - currentTime;\n }\n\n return {\n allowed: true,\n remaining: remainingSeconds !== undefined ? { seconds: remainingSeconds } : undefined,\n };\n}\n\n/**\n * Enforce usage mandate\n */\nexport function enforceUsageConstraint(\n mandate: UsageConstraint,\n state?: ControlState\n): EnforcementResult {\n const currentUses = state?.usage_count ?? mandate.current_uses ?? 0;\n\n // Check if max uses exceeded\n if (currentUses >= mandate.max_uses) {\n return {\n allowed: false,\n reason: `Usage limit exceeded (${currentUses}/${mandate.max_uses})`,\n remaining: { uses: 0 },\n };\n }\n\n // Check usage window if specified\n if (mandate.window !== undefined && state?.first_use !== undefined) {\n const currentTime = Math.floor(Date.now() / 1000);\n const windowExpiry = state.first_use + mandate.window;\n\n if (currentTime > windowExpiry) {\n return {\n allowed: false,\n reason: 'Usage window expired',\n remaining: { uses: 0 },\n };\n }\n }\n\n const remainingUses = mandate.max_uses - currentUses;\n\n return {\n allowed: true,\n remaining: { uses: remainingUses },\n };\n}\n\n/**\n * Enforce budget mandate\n */\nexport function enforceBudgetConstraint(\n mandate: BudgetConstraint,\n state?: ControlState,\n requestedAmount?: number\n): EnforcementResult {\n const currentAmount = state?.spent_amount ?? mandate.current_amount ?? 0;\n\n // Check if budget exceeded\n if (currentAmount >= mandate.max_amount) {\n return {\n allowed: false,\n reason: `Budget limit exceeded (${currentAmount}/${mandate.max_amount} ${mandate.currency})`,\n remaining: { amount: 0 },\n };\n }\n\n // Check if requested amount would exceed budget\n if (requestedAmount !== undefined) {\n if (currentAmount + requestedAmount > mandate.max_amount) {\n const remaining = mandate.max_amount - currentAmount;\n return {\n allowed: false,\n reason: `Requested amount would exceed budget (${requestedAmount} > ${remaining} ${mandate.currency} remaining)`,\n remaining: { amount: remaining },\n };\n }\n }\n\n // Check budget window if specified\n if (mandate.window !== undefined && state?.first_use !== undefined) {\n const currentTime = Math.floor(Date.now() / 1000);\n const windowExpiry = state.first_use + mandate.window;\n\n if (currentTime > windowExpiry) {\n return {\n allowed: false,\n reason: 'Budget window expired',\n remaining: { amount: 0 },\n };\n }\n }\n\n const remainingAmount = mandate.max_amount - currentAmount;\n\n return {\n allowed: true,\n remaining: { amount: remainingAmount },\n };\n}\n\n/**\n * Enforce combined mandate\n */\nexport function enforceCombinedConstraint(\n mandate: CombinedConstraint,\n state?: ControlState,\n requestedAmount?: number,\n currentTime?: number\n): EnforcementResult {\n const results: EnforcementResult[] = [];\n\n // Check temporal constraints\n if (mandate.temporal !== undefined) {\n const temporalConstraint: TemporalConstraint = {\n type: 'temporal',\n ...mandate.temporal,\n };\n const result = enforceTemporalConstraint(temporalConstraint, currentTime);\n results.push(result);\n }\n\n // Check usage constraints\n if (mandate.usage !== undefined) {\n const usageConstraint: UsageConstraint = {\n type: 'usage',\n ...mandate.usage,\n };\n const result = enforceUsageConstraint(usageConstraint, state);\n results.push(result);\n }\n\n // Check budget constraints\n if (mandate.budget !== undefined) {\n const budgetConstraint: BudgetConstraint = {\n type: 'budget',\n ...mandate.budget,\n };\n const result = enforceBudgetConstraint(budgetConstraint, state, requestedAmount);\n results.push(result);\n }\n\n // All constraints must be satisfied\n const failedResult = results.find((r) => !r.allowed);\n if (failedResult) {\n return failedResult;\n }\n\n // Merge remaining information\n const remaining: EnforcementResult['remaining'] = {};\n for (const result of results) {\n if (result.remaining) {\n Object.assign(remaining, result.remaining);\n }\n }\n\n return {\n allowed: true,\n remaining: Object.keys(remaining).length > 0 ? remaining : undefined,\n };\n}\n\n/**\n * Enforce mandate (dispatcher)\n */\nexport function enforceConstraint(\n mandate: Constraint,\n state?: ControlState,\n requestedAmount?: number,\n currentTime?: number\n): EnforcementResult {\n switch (mandate.type) {\n case 'temporal':\n return enforceTemporalConstraint(mandate, currentTime);\n\n case 'usage':\n return enforceUsageConstraint(mandate, state);\n\n case 'budget':\n return enforceBudgetConstraint(mandate, state, requestedAmount);\n\n case 'combined':\n return enforceCombinedConstraint(mandate, state, requestedAmount, currentTime);\n\n default: {\n // TypeScript exhaustiveness check\n const _exhaustive: never = mandate;\n return {\n allowed: false,\n reason: `Unknown mandate type: ${(_exhaustive as any).type}`,\n };\n }\n }\n}\n\n/**\n * Enforce control block\n *\n * @deprecated Use enforceConstraint directly. This function is maintained for backward compatibility.\n */\nexport function enforceControlBlock(\n constraint: Constraint,\n state?: ControlState,\n requestedAmount?: number,\n currentTime?: number\n): EnforcementResult {\n return enforceConstraint(constraint, state, requestedAmount, currentTime);\n}\n","/**\n * PEAC Control Abstraction Layer (CAL) State Management\n *\n * State tracking and updates for control blocks.\n */\n\nimport type { ControlState, Constraint } from './types';\n\n/**\n * Create initial control state\n */\nexport function createControlState(receiptId: string, constraint: Constraint): ControlState {\n return {\n receipt_id: receiptId,\n constraint,\n usage_count: 0,\n spent_amount: 0,\n metadata: {},\n };\n}\n\n/**\n * Update state after usage\n */\nexport function updateStateAfterUse(state: ControlState, amount?: number): ControlState {\n const currentTime = Math.floor(Date.now() / 1000);\n const usageCount = (state.usage_count ?? 0) + 1;\n const spentAmount = (state.spent_amount ?? 0) + (amount ?? 0);\n\n return {\n ...state,\n usage_count: usageCount,\n spent_amount: spentAmount,\n first_use: state.first_use ?? currentTime,\n last_use: currentTime,\n };\n}\n\n/**\n * Check if state is expired\n */\nexport function isStateExpired(state: ControlState): boolean {\n const { constraint: mandate } = state;\n const currentTime = Math.floor(Date.now() / 1000);\n\n // Check temporal expiry\n if (mandate.type === 'temporal') {\n if (mandate.valid_until !== undefined && currentTime > mandate.valid_until) {\n return true;\n }\n if (mandate.duration !== undefined && state.first_use !== undefined) {\n const expiresAt = state.first_use + mandate.duration;\n if (currentTime > expiresAt) {\n return true;\n }\n }\n }\n\n // Check combined mandate temporal expiry\n if (mandate.type === 'combined' && mandate.temporal) {\n if (mandate.temporal.valid_until !== undefined && currentTime > mandate.temporal.valid_until) {\n return true;\n }\n if (mandate.temporal.duration !== undefined && state.first_use !== undefined) {\n const expiresAt = state.first_use + mandate.temporal.duration;\n if (currentTime > expiresAt) {\n return true;\n }\n }\n }\n\n // Check window expiry for usage mandates\n if (mandate.type === 'usage' && mandate.window !== undefined && state.first_use !== undefined) {\n const windowExpiry = state.first_use + mandate.window;\n if (currentTime > windowExpiry) {\n return true;\n }\n }\n\n // Check window expiry for budget mandates\n if (mandate.type === 'budget' && mandate.window !== undefined && state.first_use !== undefined) {\n const windowExpiry = state.first_use + mandate.window;\n if (currentTime > windowExpiry) {\n return true;\n }\n }\n\n // Check window expiry for combined mandates\n if (mandate.type === 'combined') {\n if (mandate.usage?.window !== undefined && state.first_use !== undefined) {\n const windowExpiry = state.first_use + mandate.usage.window;\n if (currentTime > windowExpiry) {\n return true;\n }\n }\n if (mandate.budget?.window !== undefined && state.first_use !== undefined) {\n const windowExpiry = state.first_use + mandate.budget.window;\n if (currentTime > windowExpiry) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Reset state (for windowed mandates)\n */\nexport function resetState(state: ControlState): ControlState {\n return {\n ...state,\n usage_count: 0,\n spent_amount: 0,\n first_use: undefined,\n last_use: undefined,\n };\n}\n\n/**\n * Get state summary for debugging\n */\nexport function getStateSummary(state: ControlState): string {\n const parts: string[] = [];\n\n if (state.usage_count !== undefined && state.usage_count > 0) {\n parts.push(`uses: ${state.usage_count}`);\n }\n\n if (state.spent_amount !== undefined && state.spent_amount > 0) {\n const currency =\n state.constraint.type === 'budget'\n ? state.constraint.currency\n : state.constraint.type === 'combined' && state.constraint.budget\n ? state.constraint.budget.currency\n : 'units';\n parts.push(`spent: ${state.spent_amount} ${currency}`);\n }\n\n if (state.first_use !== undefined) {\n const date = new Date(state.first_use * 1000).toISOString();\n parts.push(`first: ${date}`);\n }\n\n if (state.last_use !== undefined) {\n const date = new Date(state.last_use * 1000).toISOString();\n parts.push(`last: ${date}`);\n }\n\n return parts.join(', ');\n}\n"]}