@datacules/agent-identity 0.2.1

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 (81) hide show
  1. package/dist/cjs/approval.js +157 -0
  2. package/dist/cjs/approval.js.map +1 -0
  3. package/dist/cjs/attestation.js +89 -0
  4. package/dist/cjs/attestation.js.map +1 -0
  5. package/dist/cjs/budget.js +110 -0
  6. package/dist/cjs/budget.js.map +1 -0
  7. package/dist/cjs/credentials.js +14 -0
  8. package/dist/cjs/credentials.js.map +1 -0
  9. package/dist/cjs/decision.js +30 -0
  10. package/dist/cjs/decision.js.map +1 -0
  11. package/dist/cjs/federation.js +55 -0
  12. package/dist/cjs/federation.js.map +1 -0
  13. package/dist/cjs/index.js +42 -0
  14. package/dist/cjs/index.js.map +1 -0
  15. package/dist/cjs/providers.js +97 -0
  16. package/dist/cjs/providers.js.map +1 -0
  17. package/dist/cjs/rotation.js +127 -0
  18. package/dist/cjs/rotation.js.map +1 -0
  19. package/dist/cjs/router.js +216 -0
  20. package/dist/cjs/router.js.map +1 -0
  21. package/dist/cjs/schemas.js +127 -0
  22. package/dist/cjs/schemas.js.map +1 -0
  23. package/dist/cjs/types.js +4 -0
  24. package/dist/cjs/types.js.map +1 -0
  25. package/dist/esm/approval.js +150 -0
  26. package/dist/esm/approval.js.map +1 -0
  27. package/dist/esm/attestation.js +83 -0
  28. package/dist/esm/attestation.js.map +1 -0
  29. package/dist/esm/budget.js +105 -0
  30. package/dist/esm/budget.js.map +1 -0
  31. package/dist/esm/credentials.js +11 -0
  32. package/dist/esm/credentials.js.map +1 -0
  33. package/dist/esm/decision.js +27 -0
  34. package/dist/esm/decision.js.map +1 -0
  35. package/dist/esm/federation.js +50 -0
  36. package/dist/esm/federation.js.map +1 -0
  37. package/dist/esm/index.js +26 -0
  38. package/dist/esm/index.js.map +1 -0
  39. package/dist/esm/providers.js +92 -0
  40. package/dist/esm/providers.js.map +1 -0
  41. package/dist/esm/react/index.js +2 -0
  42. package/dist/esm/react/index.js.map +1 -0
  43. package/dist/esm/react/useAgentIdentity.js +100 -0
  44. package/dist/esm/react/useAgentIdentity.js.map +1 -0
  45. package/dist/esm/rotation.js +123 -0
  46. package/dist/esm/rotation.js.map +1 -0
  47. package/dist/esm/router.js +208 -0
  48. package/dist/esm/router.js.map +1 -0
  49. package/dist/esm/schemas.js +124 -0
  50. package/dist/esm/schemas.js.map +1 -0
  51. package/dist/esm/types.js +3 -0
  52. package/dist/esm/types.js.map +1 -0
  53. package/dist/types/approval.d.ts +48 -0
  54. package/dist/types/approval.d.ts.map +1 -0
  55. package/dist/types/attestation.d.ts +36 -0
  56. package/dist/types/attestation.d.ts.map +1 -0
  57. package/dist/types/budget.d.ts +38 -0
  58. package/dist/types/budget.d.ts.map +1 -0
  59. package/dist/types/credentials.d.ts +4 -0
  60. package/dist/types/credentials.d.ts.map +1 -0
  61. package/dist/types/decision.d.ts +3 -0
  62. package/dist/types/decision.d.ts.map +1 -0
  63. package/dist/types/federation.d.ts +23 -0
  64. package/dist/types/federation.d.ts.map +1 -0
  65. package/dist/types/index.d.ts +26 -0
  66. package/dist/types/index.d.ts.map +1 -0
  67. package/dist/types/providers.d.ts +13 -0
  68. package/dist/types/providers.d.ts.map +1 -0
  69. package/dist/types/react/index.d.ts +3 -0
  70. package/dist/types/react/index.d.ts.map +1 -0
  71. package/dist/types/react/useAgentIdentity.d.ts +58 -0
  72. package/dist/types/react/useAgentIdentity.d.ts.map +1 -0
  73. package/dist/types/rotation.d.ts +51 -0
  74. package/dist/types/rotation.d.ts.map +1 -0
  75. package/dist/types/router.d.ts +48 -0
  76. package/dist/types/router.d.ts.map +1 -0
  77. package/dist/types/schemas.d.ts +434 -0
  78. package/dist/types/schemas.d.ts.map +1 -0
  79. package/dist/types/types.d.ts +263 -0
  80. package/dist/types/types.d.ts.map +1 -0
  81. package/package.json +59 -0
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApprovalManager = exports.SlackApprovalNotifier = exports.WebhookApprovalNotifier = exports.MemoryApprovalStore = void 0;
4
+ // ─── MemoryApprovalStore ──────────────────────────────────────────────────────
5
+ class MemoryApprovalStore {
6
+ constructor() {
7
+ this.store = new Map();
8
+ }
9
+ async create(request) {
10
+ this.store.set(request.requestId, { ...request });
11
+ }
12
+ async get(requestId) {
13
+ return this.store.get(requestId) ?? null;
14
+ }
15
+ async update(requestId, status, resolvedBy, justification) {
16
+ const existing = this.store.get(requestId);
17
+ if (!existing)
18
+ return;
19
+ this.store.set(requestId, {
20
+ ...existing,
21
+ status,
22
+ resolvedAt: new Date().toISOString(),
23
+ resolvedBy,
24
+ justification,
25
+ });
26
+ }
27
+ async listPending() {
28
+ return Array.from(this.store.values()).filter((r) => r.status === 'pending');
29
+ }
30
+ }
31
+ exports.MemoryApprovalStore = MemoryApprovalStore;
32
+ // ─── WebhookApprovalNotifier ──────────────────────────────────────────────────
33
+ class WebhookApprovalNotifier {
34
+ constructor(webhookUrl, secret) {
35
+ this.webhookUrl = webhookUrl;
36
+ this.secret = secret;
37
+ }
38
+ async notify(request, _policy) {
39
+ const body = JSON.stringify(request);
40
+ const headers = { 'Content-Type': 'application/json' };
41
+ if (this.secret) {
42
+ headers['X-Agent-Identity-Signature'] = this.secret;
43
+ }
44
+ try {
45
+ await fetch(this.webhookUrl, { method: 'POST', headers, body });
46
+ }
47
+ catch {
48
+ // Notification failure is non-fatal — approval still waits
49
+ }
50
+ }
51
+ }
52
+ exports.WebhookApprovalNotifier = WebhookApprovalNotifier;
53
+ // ─── SlackApprovalNotifier ────────────────────────────────────────────────────
54
+ class SlackApprovalNotifier {
55
+ constructor(webhookUrl) {
56
+ this.webhookUrl = webhookUrl;
57
+ }
58
+ async notify(request, _policy) {
59
+ const text = [
60
+ `*Approval required* — request \`${request.requestId}\``,
61
+ `User: ${request.context.userId}`,
62
+ `Action: ${request.context.action} on ${request.context.resourceId}`,
63
+ `Credential: ${request.credentialId}`,
64
+ `Expires: ${request.expiresAt}`,
65
+ ].join('\n');
66
+ try {
67
+ await fetch(this.webhookUrl, {
68
+ method: 'POST',
69
+ headers: { 'Content-Type': 'application/json' },
70
+ body: JSON.stringify({ text }),
71
+ });
72
+ }
73
+ catch {
74
+ // Notification failure is non-fatal
75
+ }
76
+ }
77
+ }
78
+ exports.SlackApprovalNotifier = SlackApprovalNotifier;
79
+ // ─── ApprovalManager ─────────────────────────────────────────────────────────
80
+ class ApprovalManager {
81
+ constructor(store, notifiers = [], auditLogger) {
82
+ this.store = store;
83
+ this.notifiers = notifiers;
84
+ this.auditLogger = auditLogger;
85
+ }
86
+ /**
87
+ * Gate a resolve() call behind an approval policy.
88
+ * Returns 'approved' / 'break_glass' if the request was already
89
+ * approved, otherwise creates a new approval request, notifies approvers,
90
+ * and returns 'pending' (the router returns null — caller should retry).
91
+ */
92
+ async request(ctx, policy, credentialId, ruleId) {
93
+ // Generate deterministic request ID for idempotency within the same trace
94
+ const requestId = `approval-${ctx.traceId}-${ruleId}`;
95
+ const existing = await this.store.get(requestId);
96
+ if (existing) {
97
+ if (existing.status === 'approved' || existing.status === 'break_glass') {
98
+ return existing.status;
99
+ }
100
+ if (existing.status === 'rejected')
101
+ return 'rejected';
102
+ // Check timeout
103
+ if (new Date(existing.expiresAt) < new Date()) {
104
+ await this.store.update(requestId, 'timeout');
105
+ if (this.auditLogger) {
106
+ await this.auditLogger.log({
107
+ timestamp: new Date().toISOString(),
108
+ traceId: ctx.traceId,
109
+ userId: ctx.userId,
110
+ action: 'credential.approval_timeout',
111
+ resourceId: ctx.resourceId,
112
+ resourceKind: ctx.resourceKind,
113
+ provider: ctx.provider,
114
+ model: ctx.model,
115
+ credentialId,
116
+ credentialKind: 'fixed',
117
+ resolvedFor: ctx.userId,
118
+ });
119
+ }
120
+ return 'timeout';
121
+ }
122
+ return 'pending';
123
+ }
124
+ // Create new request
125
+ const timeoutSeconds = policy.timeoutSeconds ?? 300;
126
+ const newRequest = {
127
+ requestId,
128
+ credentialId,
129
+ ruleId,
130
+ context: ctx,
131
+ status: 'pending',
132
+ requestedAt: new Date().toISOString(),
133
+ expiresAt: new Date(Date.now() + timeoutSeconds * 1000).toISOString(),
134
+ };
135
+ await this.store.create(newRequest);
136
+ // Notify all approvers
137
+ await Promise.allSettled(this.notifiers.map((n) => n.notify(newRequest, policy)));
138
+ if (this.auditLogger) {
139
+ await this.auditLogger.log({
140
+ timestamp: new Date().toISOString(),
141
+ traceId: ctx.traceId,
142
+ userId: ctx.userId,
143
+ action: 'credential.approval_requested',
144
+ resourceId: ctx.resourceId,
145
+ resourceKind: ctx.resourceKind,
146
+ provider: ctx.provider,
147
+ model: ctx.model,
148
+ credentialId,
149
+ credentialKind: 'fixed',
150
+ resolvedFor: ctx.userId,
151
+ });
152
+ }
153
+ return 'pending';
154
+ }
155
+ }
156
+ exports.ApprovalManager = ApprovalManager;
157
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/approval.ts"],"names":[],"mappings":";;;AAqBA,iFAAiF;AAEjF,MAAa,mBAAmB;IAAhC;QACmB,UAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IA8B9D,CAAC;IA5BC,KAAK,CAAC,MAAM,CAAC,OAAwB;QACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,MAAM,CACV,SAAiB,EACjB,MAAsB,EACtB,UAAmB,EACnB,aAAsB;QAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACxB,GAAG,QAAQ;YACX,MAAM;YACN,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,UAAU;YACV,aAAa;SACd,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IAC/E,CAAC;CACF;AA/BD,kDA+BC;AAED,iFAAiF;AAEjF,MAAa,uBAAuB;IAClC,YAA6B,UAAkB,EAAmB,MAAe;QAApD,eAAU,GAAV,UAAU,CAAQ;QAAmB,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAErF,KAAK,CAAC,MAAM,CAAC,OAAwB,EAAE,OAAuB;QAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;QAC/E,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,CAAC,4BAA4B,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;CACF;AAfD,0DAeC;AAED,iFAAiF;AAEjF,MAAa,qBAAqB;IAChC,YAA6B,UAAkB;QAAlB,eAAU,GAAV,UAAU,CAAQ;IAAG,CAAC;IAEnD,KAAK,CAAC,MAAM,CAAC,OAAwB,EAAE,OAAuB;QAC5D,MAAM,IAAI,GAAG;YACX,mCAAmC,OAAO,CAAC,SAAS,IAAI;YACxD,SAAS,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE;YACjC,WAAW,OAAO,CAAC,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE;YACpE,eAAe,OAAO,CAAC,YAAY,EAAE;YACrC,YAAY,OAAO,CAAC,SAAS,EAAE;SAChC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE;gBAC3B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,oCAAoC;QACtC,CAAC;IACH,CAAC;CACF;AArBD,sDAqBC;AAED,gFAAgF;AAEhF,MAAa,eAAe;IAC1B,YACmB,KAAoB,EACpB,YAAgC,EAAE,EAClC,WAAyB;QAFzB,UAAK,GAAL,KAAK,CAAe;QACpB,cAAS,GAAT,SAAS,CAAyB;QAClC,gBAAW,GAAX,WAAW,CAAc;IACzC,CAAC;IAEJ;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CACX,GAAwB,EACxB,MAAsB,EACtB,YAAoB,EACpB,MAAc;QAEd,0EAA0E;QAC1E,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC,OAAO,IAAI,MAAM,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,IAAI,QAAQ,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;gBACxE,OAAO,QAAQ,CAAC,MAAM,CAAC;YACzB,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;gBAAE,OAAO,UAAU,CAAC;YACtD,gBAAgB;YAChB,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;gBAC9C,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBAC9C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;wBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,OAAO,EAAE,GAAG,CAAC,OAAO;wBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,MAAM,EAAE,6BAA6B;wBACrC,UAAU,EAAE,GAAG,CAAC,UAAU;wBAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;wBAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;wBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,YAAY;wBACZ,cAAc,EAAE,OAAO;wBACvB,WAAW,EAAE,GAAG,CAAC,MAAM;qBACxB,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,qBAAqB;QACrB,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,GAAG,CAAC;QACpD,MAAM,UAAU,GAAoB;YAClC,SAAS;YACT,YAAY;YACZ,MAAM;YACN,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;SACtE,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEpC,uBAAuB;QACvB,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QAElF,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;gBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,+BAA+B;gBACvC,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,YAAY;gBACZ,cAAc,EAAE,OAAO;gBACvB,WAAW,EAAE,GAAG,CAAC,MAAM;aACxB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AApFD,0CAoFC"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HmacAttestationSigner = void 0;
4
+ exports.buildAttestation = buildAttestation;
5
+ exports.verifyAttestation = verifyAttestation;
6
+ // ─── HMAC Signer (built-in, zero deps) ──────────────────────────────────────
7
+ class HmacAttestationSigner {
8
+ constructor(options) {
9
+ this.secret = options.secret;
10
+ this.issuer = options.issuer ?? 'agent-identity';
11
+ this.ttlSeconds = options.ttlSeconds ?? 300;
12
+ }
13
+ base64url(input) {
14
+ // Works in both browser and Node 18+ (Buffer is global in Node)
15
+ if (typeof Buffer !== 'undefined') {
16
+ return Buffer.from(input).toString('base64url');
17
+ }
18
+ // Browser fallback via btoa
19
+ return btoa(input).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
20
+ }
21
+ bufToBase64url(buf) {
22
+ if (typeof Buffer !== 'undefined') {
23
+ return Buffer.from(buf).toString('base64url');
24
+ }
25
+ const bytes = new Uint8Array(buf);
26
+ let binary = '';
27
+ for (let i = 0; i < bytes.byteLength; i++)
28
+ binary += String.fromCharCode(bytes[i]);
29
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
30
+ }
31
+ async hmacSign(data) {
32
+ const enc = new TextEncoder();
33
+ const key = await crypto.subtle.importKey('raw', enc.encode(this.secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
34
+ const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data));
35
+ return this.bufToBase64url(sig);
36
+ }
37
+ async sign(payload) {
38
+ const header = this.base64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
39
+ const body = this.base64url(JSON.stringify(payload));
40
+ const sig = await this.hmacSign(`${header}.${body}`);
41
+ return `${header}.${body}.${sig}`;
42
+ }
43
+ async verify(token) {
44
+ try {
45
+ const [header, body, sig] = token.split('.');
46
+ if (!header || !body || !sig)
47
+ return null;
48
+ const expected = await this.hmacSign(`${header}.${body}`);
49
+ if (expected !== sig)
50
+ return null;
51
+ // Decode body: Node uses Buffer, browsers use atob
52
+ const decoded = typeof Buffer !== 'undefined'
53
+ ? Buffer.from(body, 'base64url').toString('utf8')
54
+ : atob(body.replace(/-/g, '+').replace(/_/g, '/'));
55
+ return JSON.parse(decoded);
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ }
62
+ exports.HmacAttestationSigner = HmacAttestationSigner;
63
+ async function buildAttestation(ctx, resolved, options) {
64
+ const now = Math.floor(Date.now() / 1000);
65
+ const payload = {
66
+ iss: options.issuer ?? 'agent-identity',
67
+ sub: ctx.userId,
68
+ credentialId: resolved.credentialId,
69
+ resolvedFor: resolved.resolvedFor,
70
+ action: ctx.action,
71
+ resourceId: ctx.resourceId,
72
+ traceId: ctx.traceId,
73
+ ruleId: options.ruleId,
74
+ iat: now,
75
+ exp: now + (options.ttlSeconds ?? 300),
76
+ };
77
+ return options.signer.sign(payload);
78
+ }
79
+ // ─── Standalone verifyAttestation helper ────────────────────────────────────
80
+ async function verifyAttestation(token, signer) {
81
+ const raw = await signer.verify(token);
82
+ if (!raw)
83
+ return null;
84
+ const now = Math.floor(Date.now() / 1000);
85
+ if (typeof raw.exp === 'number' && raw.exp < now)
86
+ return null;
87
+ return raw;
88
+ }
89
+ //# sourceMappingURL=attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.js","sourceRoot":"","sources":["../../src/attestation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BudgetEnforcer = exports.MemoryBudgetStore = void 0;
4
+ // ─── MemoryBudgetStore ────────────────────────────────────────────────────────
5
+ class MemoryBudgetStore {
6
+ constructor() {
7
+ this.hourlyCounts = new Map();
8
+ this.dailySpend = new Map();
9
+ }
10
+ async getHourlyCount(credentialId) {
11
+ const entry = this.hourlyCounts.get(credentialId);
12
+ if (!entry)
13
+ return 0;
14
+ const hourMs = 3600000;
15
+ if (Date.now() - entry.windowStart > hourMs) {
16
+ this.hourlyCounts.delete(credentialId);
17
+ return 0;
18
+ }
19
+ return entry.count;
20
+ }
21
+ async incrementHourlyCount(credentialId) {
22
+ const existing = this.hourlyCounts.get(credentialId);
23
+ const hourMs = 3600000;
24
+ if (!existing || Date.now() - existing.windowStart > hourMs) {
25
+ this.hourlyCounts.set(credentialId, { count: 1, windowStart: Date.now() });
26
+ }
27
+ else {
28
+ existing.count++;
29
+ }
30
+ }
31
+ async getConcurrentSessions(_credentialId) {
32
+ // Placeholder — real impl tracks open sessions with TTL
33
+ return 0;
34
+ }
35
+ async getDailySpend(credentialId) {
36
+ return this.dailySpend.get(credentialId) ?? 0;
37
+ }
38
+ async resetHourly(credentialId) {
39
+ this.hourlyCounts.delete(credentialId);
40
+ }
41
+ async resetDaily(credentialId) {
42
+ this.dailySpend.delete(credentialId);
43
+ }
44
+ }
45
+ exports.MemoryBudgetStore = MemoryBudgetStore;
46
+ // ─── BudgetEnforcer ──────────────────────────────────────────────────────────
47
+ class BudgetEnforcer {
48
+ constructor(store, auditLogger) {
49
+ this.store = store;
50
+ this.auditLogger = auditLogger;
51
+ }
52
+ async check(credential) {
53
+ const policy = credential.budget;
54
+ if (!policy)
55
+ return { allowed: true };
56
+ // Hourly resolution limit
57
+ if (policy.maxResolutionsPerHour !== undefined) {
58
+ const count = await this.store.getHourlyCount(credential.id);
59
+ const soft = policy.softThresholdPercent ?? 80;
60
+ const softLimit = Math.floor((policy.maxResolutionsPerHour * soft) / 100);
61
+ if (count >= policy.maxResolutionsPerHour) {
62
+ const retryAfter = new Date(Date.now() + 3600000).toISOString();
63
+ if (this.auditLogger) {
64
+ // Fire-and-forget — budget exceeded audit event
65
+ void this.auditLogger.log({
66
+ timestamp: new Date().toISOString(),
67
+ traceId: 'budget-enforcer',
68
+ userId: 'system',
69
+ action: 'credential.budget_exceeded',
70
+ resourceId: credential.id,
71
+ resourceKind: 'shared',
72
+ provider: 'local',
73
+ model: 'system',
74
+ credentialId: credential.id,
75
+ credentialKind: credential.kind,
76
+ resolvedFor: 'system',
77
+ });
78
+ }
79
+ return { allowed: false, reason: 'hourly_limit', retryAfter };
80
+ }
81
+ if (count >= softLimit && this.auditLogger) {
82
+ void this.auditLogger.log({
83
+ timestamp: new Date().toISOString(),
84
+ traceId: 'budget-enforcer',
85
+ userId: 'system',
86
+ action: 'credential.budget_warning',
87
+ resourceId: credential.id,
88
+ resourceKind: 'shared',
89
+ provider: 'local',
90
+ model: 'system',
91
+ credentialId: credential.id,
92
+ credentialKind: credential.kind,
93
+ resolvedFor: 'system',
94
+ });
95
+ }
96
+ }
97
+ // Concurrent sessions limit
98
+ if (policy.maxConcurrentSessions !== undefined) {
99
+ const sessions = await this.store.getConcurrentSessions(credential.id);
100
+ if (sessions >= policy.maxConcurrentSessions) {
101
+ return { allowed: false, reason: 'session_limit' };
102
+ }
103
+ }
104
+ // Record the resolution
105
+ await this.store.incrementHourlyCount(credential.id);
106
+ return { allowed: true };
107
+ }
108
+ }
109
+ exports.BudgetEnforcer = BudgetEnforcer;
110
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/budget.ts"],"names":[],"mappings":";;;AA0BA,iFAAiF;AAEjF,MAAa,iBAAiB;IAA9B;QACmB,iBAAY,GAAG,IAAI,GAAG,EAAkD,CAAC;QACzE,eAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAuC1D,CAAC;IArCC,KAAK,CAAC,cAAc,CAAC,YAAoB;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC;QACrB,MAAM,MAAM,GAAG,OAAQ,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW,GAAG,MAAM,EAAE,CAAC;YAC5C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACvC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,YAAoB;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,OAAQ,CAAC;QACxB,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,WAAW,GAAG,MAAM,EAAE,CAAC;YAC5D,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7E,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,aAAqB;QAC/C,wDAAwD;QACxD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,YAAoB;QACtC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,YAAoB;QACpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,YAAoB;QACnC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;CACF;AAzCD,8CAyCC;AAED,gFAAgF;AAEhF,MAAa,cAAc;IACzB,YACmB,KAAkB,EAClB,WAAyB;QADzB,UAAK,GAAL,KAAK,CAAa;QAClB,gBAAW,GAAX,WAAW,CAAc;IACzC,CAAC;IAEJ,KAAK,CAAC,KAAK,CAAC,UAAsB;QAChC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAEtC,0BAA0B;QAC1B,IAAI,MAAM,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,qBAAqB,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;YAE1E,IAAI,KAAK,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;gBAC1C,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;gBACjE,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,gDAAgD;oBAChD,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;wBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,OAAO,EAAE,iBAAiB;wBAC1B,MAAM,EAAE,QAAQ;wBAChB,MAAM,EAAE,4BAA4B;wBACpC,UAAU,EAAE,UAAU,CAAC,EAAE;wBACzB,YAAY,EAAE,QAAQ;wBACtB,QAAQ,EAAE,OAAO;wBACjB,KAAK,EAAE,QAAQ;wBACf,YAAY,EAAE,UAAU,CAAC,EAAE;wBAC3B,cAAc,EAAE,UAAU,CAAC,IAAI;wBAC/B,WAAW,EAAE,QAAQ;qBACtB,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC;YAChE,CAAC;YAED,IAAI,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC3C,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;oBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,OAAO,EAAE,iBAAiB;oBAC1B,MAAM,EAAE,QAAQ;oBAChB,MAAM,EAAE,2BAA2B;oBACnC,UAAU,EAAE,UAAU,CAAC,EAAE;oBACzB,YAAY,EAAE,QAAQ;oBACtB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,QAAQ;oBACf,YAAY,EAAE,UAAU,CAAC,EAAE;oBAC3B,cAAc,EAAE,UAAU,CAAC,IAAI;oBAC/B,WAAW,EAAE,QAAQ;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,MAAM,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACvE,IAAI,QAAQ,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC;gBAC7C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;YACrD,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF;AAlED,wCAkEC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_ROUTING_RULES = exports.DEFAULT_CREDENTIALS = void 0;
4
+ exports.DEFAULT_CREDENTIALS = [
5
+ { id: 'cred-linear', kind: 'fixed', name: 'Linear service account', scope: 'All projects - read/write', status: 'active', provider: 'Linear', ref: 'linear-service-account-slot', rotationIntervalDays: 90 },
6
+ { id: 'cred-analytics-db', kind: 'fixed', name: 'Shared analytics DB', scope: 'Read-only replica', status: 'active', provider: 'PostgreSQL', ref: 'analytics-db-readonly-slot', rotationIntervalDays: 180 },
7
+ { id: 'cred-knowledge-base', kind: 'user-delegated', name: 'Company knowledge base', scope: 'Variable - resolved per user at call time', status: 'active', provider: 'Notion', ref: 'knowledge-base-user-slot', rotationIntervalDays: 0 },
8
+ { id: 'cred-gmail', kind: 'user-delegated', name: 'Gmail / inbox access', scope: "User's mailbox - OAuth 2.0", status: 'active', provider: 'Google', ref: 'gmail-oauth-user-slot', rotationIntervalDays: 0 },
9
+ ];
10
+ exports.DEFAULT_ROUTING_RULES = [
11
+ { id: 'rule-shared-tools', description: 'Shared tools → fixed service account', matchResourceKind: 'shared', credentialKind: 'fixed', credentialRef: 'linear-service-account-slot', priority: 10 },
12
+ { id: 'rule-personal-resources', description: 'Personal resources → user-delegated token', matchResourceKind: 'personal', credentialKind: 'user-delegated', credentialRef: 'knowledge-base-user-slot', priority: 10 },
13
+ ];
14
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/credentials.ts"],"names":[],"mappings":";;;AAEa,QAAA,mBAAmB,GAAiB;IAC/C,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,EAAE,EAAE;IAC5M,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,GAAG,EAAE;IAC3M,EAAE,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,2CAA2C,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,CAAC,EAAE;IACzO,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,4BAA4B,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,CAAC,EAAE;CAC7M,CAAC;AAEW,QAAA,qBAAqB,GAAkB;IAClD,EAAE,EAAE,EAAE,mBAAmB,EAAE,WAAW,EAAE,sCAAsC,EAAE,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,6BAA6B,EAAE,QAAQ,EAAE,EAAE,EAAE;IAClM,EAAE,EAAE,EAAE,yBAAyB,EAAE,WAAW,EAAE,2CAA2C,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,0BAA0B,EAAE,QAAQ,EAAE,EAAE,EAAE;CACtN,CAAC"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeDecision = computeDecision;
4
+ function computeDecision(answers) {
5
+ const { variableAccess, mixedResources, auditRequired, longTermTokenStorage } = answers;
6
+ if (variableAccess === null || mixedResources === null || auditRequired === null)
7
+ return null;
8
+ if (variableAccess && longTermTokenStorage === null)
9
+ return null;
10
+ if (variableAccess && mixedResources) {
11
+ return { pattern: 'context-switched', label: 'Hybrid (context-switched)', explanation: 'Your agent needs both fixed credentials for shared resources and user-delegated tokens for personal data. Set explicit routing rules so the agent always knows which to use.' };
12
+ }
13
+ if (variableAccess && !mixedResources) {
14
+ if (!longTermTokenStorage) {
15
+ return { pattern: 'token-exchange', label: 'Token exchange / impersonation', explanation: 'You need per-user access but cannot store tokens long-term. Use OAuth token exchange or STS assume-role to get scoped user tokens at request time, without persisting them.' };
16
+ }
17
+ return { pattern: 'individual-user-auth', label: 'Individual user auth', explanation: "Users have different access levels, so each request must carry that user's own token. The agent passes it through; the downstream resource enforces the ACL." };
18
+ }
19
+ if (!variableAccess && mixedResources) {
20
+ return { pattern: 'fixed-credential', label: 'Fixed credential with resource-type awareness', explanation: 'All users are equal but the agent accesses different resource types. A single fixed credential works — ensure its scope covers both resource types your agent needs.' };
21
+ }
22
+ if (!variableAccess && !auditRequired) {
23
+ return { pattern: 'fixed-credential', label: 'Fixed credential', explanation: "All users are equal and audit trail isn't critical. A single service account keeps setup simple. Store the key encrypted; never pass it to the model layer." };
24
+ }
25
+ if (!variableAccess && auditRequired) {
26
+ return { pattern: 'fixed-credential', label: 'Fixed credential + request tagging', explanation: "Use a shared service account, but tag each request with the calling user's ID in your own logs. Gives you the simplicity of a fixed credential with an audit trail layer above it." };
27
+ }
28
+ return null;
29
+ }
30
+ //# sourceMappingURL=decision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.js","sourceRoot":"","sources":["../../src/decision.ts"],"names":[],"mappings":";;AAEA,0CAyBC;AAzBD,SAAgB,eAAe,CAAC,OAAwB;IACtD,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC;IAExF,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9F,IAAI,cAAc,IAAI,oBAAoB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjE,IAAI,cAAc,IAAI,cAAc,EAAE,CAAC;QACrC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,2BAA2B,EAAE,WAAW,EAAE,8KAA8K,EAAE,CAAC;IAC1Q,CAAC;IACD,IAAI,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;QACtC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,gCAAgC,EAAE,WAAW,EAAE,6KAA6K,EAAE,CAAC;QAC5Q,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,8JAA8J,EAAE,CAAC;IACzP,CAAC;IACD,IAAI,CAAC,cAAc,IAAI,cAAc,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,+CAA+C,EAAE,WAAW,EAAE,sKAAsK,EAAE,CAAC;IACtR,CAAC;IACD,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,6JAA6J,EAAE,CAAC;IAChP,CAAC;IACD,IAAI,CAAC,cAAc,IAAI,aAAa,EAAE,CAAC;QACrC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,oCAAoC,EAAE,WAAW,EAAE,oLAAoL,EAAE,CAAC;IACzR,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FederationIssuer = exports.FederationVerifier = void 0;
4
+ // ─── FederationVerifier ──────────────────────────────────────────────────────
5
+ class FederationVerifier {
6
+ constructor(config) {
7
+ this.config = config;
8
+ }
9
+ verify(chain) {
10
+ if (!chain || chain.length === 0)
11
+ return false;
12
+ for (const entry of chain) {
13
+ const trustedKey = this.config.trustedDomains[entry.org];
14
+ if (!trustedKey)
15
+ return false;
16
+ if (!entry.signature || entry.signature.length === 0)
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ }
22
+ exports.FederationVerifier = FederationVerifier;
23
+ // ─── FederationIssuer ────────────────────────────────────────────────────────
24
+ class FederationIssuer {
25
+ constructor(trustDomain, agentId) {
26
+ this.trustDomain = trustDomain;
27
+ this.agentId = agentId;
28
+ }
29
+ issueEntry(ctx) {
30
+ const payload = JSON.stringify({
31
+ org: this.trustDomain,
32
+ userId: ctx.userId,
33
+ agentId: this.agentId,
34
+ });
35
+ // Placeholder signature — replace with Ed25519 in production
36
+ const signature = typeof Buffer !== 'undefined'
37
+ ? Buffer.from(payload).toString('base64')
38
+ : btoa(payload);
39
+ return {
40
+ org: this.trustDomain,
41
+ userId: ctx.userId,
42
+ agentId: this.agentId,
43
+ issuedAt: new Date().toISOString(),
44
+ signature,
45
+ };
46
+ }
47
+ issueChain(ctx) {
48
+ return [this.issueEntry(ctx)];
49
+ }
50
+ extendChain(chain, ctx) {
51
+ return [...chain, this.issueEntry(ctx)];
52
+ }
53
+ }
54
+ exports.FederationIssuer = FederationIssuer;
55
+ //# sourceMappingURL=federation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation.js","sourceRoot":"","sources":["../../src/federation.ts"],"names":[],"mappings":";;;AAUA,gFAAgF;AAEhF,MAAa,kBAAkB;IAC7B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEzD,MAAM,CAAC,KAA2B;QAChC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/C,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACzD,IAAI,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;QACrE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAZD,gDAYC;AAED,gFAAgF;AAEhF,MAAa,gBAAgB;IAC3B,YACmB,WAAmB,EACnB,OAAe;QADf,gBAAW,GAAX,WAAW,CAAQ;QACnB,YAAO,GAAP,OAAO,CAAQ;IAC/B,CAAC;IAEJ,UAAU,CAAC,GAAwB;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,GAAG,EAAE,IAAI,CAAC,WAAW;YACrB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QACH,6DAA6D;QAC7D,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,WAAW;YAC7C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAElB,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,WAAW;YACrB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAClC,SAAS;SACV,CAAC;IACJ,CAAC;IAED,UAAU,CAAC,GAAwB;QACjC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,WAAW,CAAC,KAA2B,EAAE,GAAwB;QAC/D,OAAO,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;CACF;AAjCD,4CAiCC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * @datacules/agent-identity — public API
4
+ *
5
+ * Provider-agnostic credential routing and identity management for AI agents.
6
+ * The model/LLM layer never receives raw credentials.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { createRouter } from '@datacules/agent-identity';
11
+ * import type { AgentRequestContext } from '@datacules/agent-identity';
12
+ *
13
+ * const router = createRouter(credentials, rules, logger);
14
+ * const resolved = await router.resolveAsync(ctx);
15
+ * ```
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
29
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ // ─── Runtime modules (classes, functions, const) ─────────────────────────────
33
+ __exportStar(require("./router"), exports);
34
+ __exportStar(require("./providers"), exports);
35
+ __exportStar(require("./credentials"), exports);
36
+ __exportStar(require("./decision"), exports);
37
+ __exportStar(require("./rotation"), exports);
38
+ __exportStar(require("./attestation"), exports);
39
+ __exportStar(require("./approval"), exports);
40
+ __exportStar(require("./budget"), exports);
41
+ __exportStar(require("./federation"), exports);
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;AAOH,gFAAgF;AAChF,2CAAyB;AACzB,8CAA4B;AAC5B,gDAA8B;AAC9B,6CAA2B;AAC3B,6CAA2B;AAC3B,gDAA8B;AAC9B,6CAA2B;AAC3B,2CAAyB;AACzB,+CAA6B"}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROVIDER_ADAPTERS = void 0;
4
+ exports.getAdapter = getAdapter;
5
+ exports.registerProvider = registerProvider;
6
+ function assertMigrationScope(credential, phase, adapterId) {
7
+ const writePhases = ['load', 'rollback'];
8
+ const readOnlyRef = credential.ref.includes('readonly') || credential.ref.endsWith('-ro');
9
+ if (writePhases.includes(phase) && readOnlyRef) {
10
+ throw new Error(`[${adapterId}] Migration phase "${phase}" requires a write-scoped credential, but ref "${credential.ref}" appears read-only.`);
11
+ }
12
+ if (phase === 'dry-run' && !readOnlyRef) {
13
+ console.warn(`[${adapterId}] dry-run received potentially write-capable ref "${credential.ref}". Ensure dryRun:true is enforced.`);
14
+ }
15
+ }
16
+ const openaiAdapter = {
17
+ id: 'openai',
18
+ label: 'OpenAI',
19
+ injectCredential(request, credential) {
20
+ return { ...request, user: credential.resolvedFor, _agentIdentityMeta: { credentialRef: credential.ref, resolvedFor: credential.resolvedFor, injectionPoint: 'Authorization: Bearer header (server-side)' } };
21
+ },
22
+ validate(request) {
23
+ if (!request.model)
24
+ throw new Error('[openai] request.model is required');
25
+ },
26
+ validateForMigration(credential, phase) { assertMigrationScope(credential, phase, 'openai'); },
27
+ };
28
+ const anthropicAdapter = {
29
+ id: 'anthropic',
30
+ label: 'Anthropic',
31
+ injectCredential(request, credential) {
32
+ return { ...request, metadata: { ...request.metadata, user_id: credential.resolvedFor, _agentIdentityMeta: { credentialRef: credential.ref, injectionPoint: 'x-api-key header (server-side)' } } };
33
+ },
34
+ validate(request) {
35
+ if (!request.model)
36
+ throw new Error('[anthropic] request.model is required');
37
+ if (!request.messages)
38
+ throw new Error('[anthropic] request.messages is required');
39
+ },
40
+ validateForMigration(credential, phase) { assertMigrationScope(credential, phase, 'anthropic'); },
41
+ };
42
+ const geminiAdapter = {
43
+ id: 'gemini',
44
+ label: 'Gemini',
45
+ injectCredential(request, credential) {
46
+ return { ...request, labels: { ...request.labels, user_id: credential.resolvedFor }, _agentIdentityMeta: { credentialRef: credential.ref, resolvedFor: credential.resolvedFor, injectionPoint: 'x-goog-api-key header (server-side)' } };
47
+ },
48
+ validate(request) {
49
+ if (!request.contents)
50
+ throw new Error('[gemini] request.contents is required');
51
+ },
52
+ validateForMigration(credential, phase) { assertMigrationScope(credential, phase, 'gemini'); },
53
+ };
54
+ const mistralAdapter = {
55
+ id: 'mistral',
56
+ label: 'Mistral',
57
+ injectCredential(request, credential) {
58
+ return { ...request, _agentIdentityMeta: { credentialRef: credential.ref, resolvedFor: credential.resolvedFor, injectionPoint: 'Authorization: Bearer header (server-side)' } };
59
+ },
60
+ validate(request) {
61
+ if (!request.model)
62
+ throw new Error('[mistral] request.model is required');
63
+ if (!request.messages)
64
+ throw new Error('[mistral] request.messages is required');
65
+ },
66
+ validateForMigration(credential, phase) { assertMigrationScope(credential, phase, 'mistral'); },
67
+ };
68
+ const localAdapter = {
69
+ id: 'local',
70
+ label: 'Local / self-hosted',
71
+ injectCredential(request, credential) {
72
+ return { ...request, _agentIdentityMeta: { credentialRef: credential.ref, resolvedFor: credential.resolvedFor, injectionPoint: 'varies by runtime' } };
73
+ },
74
+ validateForMigration(credential, phase) { assertMigrationScope(credential, phase, 'local'); },
75
+ };
76
+ exports.PROVIDER_ADAPTERS = {
77
+ openai: openaiAdapter,
78
+ anthropic: anthropicAdapter,
79
+ gemini: geminiAdapter,
80
+ mistral: mistralAdapter,
81
+ local: localAdapter,
82
+ };
83
+ function getAdapter(provider) {
84
+ return exports.PROVIDER_ADAPTERS[provider];
85
+ }
86
+ /**
87
+ * Registry pattern — register a custom provider adapter without forking core.
88
+ * Registered adapters are available via getAdapter() immediately.
89
+ *
90
+ * Example:
91
+ * import { registerProvider } from '@datacules/agent-identity';
92
+ * registerProvider({ id: 'cohere' as SupportedProvider, label: 'Cohere', injectCredential: ... });
93
+ */
94
+ function registerProvider(adapter) {
95
+ exports.PROVIDER_ADAPTERS[adapter.id] = adapter;
96
+ }
97
+ //# sourceMappingURL=providers.js.map