@absolutejs/secrets 0.6.1 → 0.7.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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +43 -1
- package/dist/index.js.map +6 -5
- package/dist/postgres.d.ts +13 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { type TracerProvider } from '@absolutejs/telemetry';
|
|
27
27
|
export { createCredentialOperationBroker, createMemoryCredentialGrantStore, type CredentialGrant, type CredentialGrantStore, type CredentialOperationBroker, type CredentialOperationBrokerOptions, type CredentialOperationContext, type CredentialOperationEvent, type CredentialOperationInput, type CredentialOperationResult, type CredentialProvider, type PendingCredentialOperation } from './operations';
|
|
28
|
+
export { createPostgresCredentialGrantStore, credentialGrantsPostgresSchemaSql, type SecretsSqlClient, type SecretsSqlResult } from './postgres';
|
|
28
29
|
export type SecretValue = {
|
|
29
30
|
/** The plaintext secret. Treat as poison: never log, never serialize. */
|
|
30
31
|
value: string;
|
package/dist/index.js
CHANGED
|
@@ -254,6 +254,46 @@ var createCredentialOperationBroker = ({
|
|
|
254
254
|
};
|
|
255
255
|
return { request, resume, revoke: store.revoke };
|
|
256
256
|
};
|
|
257
|
+
// src/postgres.ts
|
|
258
|
+
var namespaceOf = (namespace) => {
|
|
259
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(namespace))
|
|
260
|
+
throw new Error("Secrets PostgreSQL namespace must be a simple identifier");
|
|
261
|
+
return namespace;
|
|
262
|
+
};
|
|
263
|
+
var credentialGrantsPostgresSchemaSql = (namespace = "secrets") => {
|
|
264
|
+
const ns = namespaceOf(namespace);
|
|
265
|
+
return `CREATE SCHEMA IF NOT EXISTS ${ns};
|
|
266
|
+
CREATE TABLE IF NOT EXISTS ${ns}.credential_grants (
|
|
267
|
+
grant_id text PRIMARY KEY, agent_id text NOT NULL, user_id text NOT NULL,
|
|
268
|
+
provider text NOT NULL, expires_at bigint NOT NULL, maximum_uses integer NOT NULL CHECK (maximum_uses > 0),
|
|
269
|
+
used integer NOT NULL DEFAULT 0 CHECK (used >= 0 AND used <= maximum_uses), data jsonb NOT NULL
|
|
270
|
+
);
|
|
271
|
+
CREATE INDEX IF NOT EXISTS credential_grants_agent_idx ON ${ns}.credential_grants (agent_id, expires_at);
|
|
272
|
+
CREATE TABLE IF NOT EXISTS ${ns}.pending_operations (
|
|
273
|
+
action_id text PRIMARY KEY, grant_id text NOT NULL REFERENCES ${ns}.credential_grants(grant_id) ON DELETE CASCADE,
|
|
274
|
+
created_at timestamptz NOT NULL DEFAULT now(), data jsonb NOT NULL
|
|
275
|
+
);`;
|
|
276
|
+
};
|
|
277
|
+
var createPostgresCredentialGrantStore = ({ client, namespace = "secrets" }) => {
|
|
278
|
+
const ns = namespaceOf(namespace);
|
|
279
|
+
return {
|
|
280
|
+
consume: async (grantId, now) => {
|
|
281
|
+
const result = await client.query(`UPDATE ${ns}.credential_grants SET used = used + 1, data = jsonb_set(data, '{used}', to_jsonb(used + 1), true) WHERE grant_id = $1 AND expires_at > $2 AND used < maximum_uses RETURNING data`, [grantId, now]);
|
|
282
|
+
return result.rows[0]?.data;
|
|
283
|
+
},
|
|
284
|
+
get: async (grantId) => (await client.query(`SELECT data FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rows[0]?.data,
|
|
285
|
+
getPending: async (actionId) => (await client.query(`SELECT data FROM ${ns}.pending_operations WHERE action_id = $1`, [actionId])).rows[0]?.data,
|
|
286
|
+
put: async (grant) => {
|
|
287
|
+
if (grant.maximumUses < 1 || grant.used < 0 || grant.used > grant.maximumUses)
|
|
288
|
+
throw new Error("Invalid credential grant usage");
|
|
289
|
+
await client.query(`INSERT INTO ${ns}.credential_grants (grant_id, agent_id, user_id, provider, expires_at, maximum_uses, used, data) VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb) ON CONFLICT (grant_id) DO UPDATE SET expires_at=EXCLUDED.expires_at, maximum_uses=EXCLUDED.maximum_uses, used=EXCLUDED.used, data=EXCLUDED.data`, [grant.grantId, grant.agentId, grant.userId, grant.provider, grant.expiresAt, grant.maximumUses, grant.used, JSON.stringify(grant)]);
|
|
290
|
+
},
|
|
291
|
+
putPending: async (pending) => {
|
|
292
|
+
await client.query(`INSERT INTO ${ns}.pending_operations (action_id, grant_id, data) VALUES ($1,$2,$3::jsonb) ON CONFLICT (action_id) DO UPDATE SET data=EXCLUDED.data`, [pending.actionId, pending.input.grantId, JSON.stringify(pending)]);
|
|
293
|
+
},
|
|
294
|
+
revoke: async (grantId) => (await client.query(`DELETE FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rowCount === 1
|
|
295
|
+
};
|
|
296
|
+
};
|
|
257
297
|
|
|
258
298
|
// src/index.ts
|
|
259
299
|
class BrokerDrainedError extends Error {
|
|
@@ -988,12 +1028,14 @@ export {
|
|
|
988
1028
|
inMemoryAdapter,
|
|
989
1029
|
envAdapter,
|
|
990
1030
|
encryptedFileAdapter,
|
|
1031
|
+
credentialGrantsPostgresSchemaSql,
|
|
991
1032
|
createSecretBroker,
|
|
1033
|
+
createPostgresCredentialGrantStore,
|
|
992
1034
|
createMemoryCredentialGrantStore,
|
|
993
1035
|
createCredentialOperationBroker,
|
|
994
1036
|
compositeAdapter,
|
|
995
1037
|
BrokerDrainedError
|
|
996
1038
|
};
|
|
997
1039
|
|
|
998
|
-
//# debugId=
|
|
1040
|
+
//# debugId=0694F56E375AD55B64756E2164756E21
|
|
999
1041
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../node_modules/@absolutejs/telemetry/dist/index.js", "../node_modules/@absolutejs/agency/dist/index.js", "../src/operations.ts", "../src/index.ts"],
|
|
3
|
+
"sources": ["../node_modules/@absolutejs/telemetry/dist/index.js", "../node_modules/@absolutejs/agency/dist/index.js", "../src/operations.ts", "../src/postgres.ts", "../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"// @bun\n// src/index.ts\nvar SpanKind = {\n INTERNAL: 0,\n SERVER: 1,\n CLIENT: 2,\n PRODUCER: 3,\n CONSUMER: 4\n};\nvar SpanStatusCode = {\n UNSET: 0,\n OK: 1,\n ERROR: 2\n};\nvar NOOP_SPAN_CONTEXT = {\n spanId: \"0000000000000000\",\n traceFlags: 0,\n traceId: \"00000000000000000000000000000000\"\n};\nvar noopSpan = {\n addEvent: () => noopSpan,\n end: () => {},\n isRecording: () => false,\n recordException: () => {},\n setAttribute: () => noopSpan,\n setAttributes: () => noopSpan,\n setStatus: () => noopSpan,\n spanContext: () => NOOP_SPAN_CONTEXT,\n updateName: () => noopSpan\n};\nvar createNoopSpan = () => noopSpan;\nvar startActiveSpanNoop = (_name, optionsOrFn, maybeFn) => {\n const fn = typeof optionsOrFn === \"function\" ? optionsOrFn : maybeFn;\n return fn(noopSpan);\n};\nvar noopTracer = {\n startActiveSpan: startActiveSpanNoop,\n startSpan: () => noopSpan\n};\nvar createNoopTracer = () => noopTracer;\nvar createNoopTracerProvider = () => ({\n getTracer: () => noopTracer\n});\nvar tracerOrNoop = (provider, name, version) => provider !== undefined ? provider.getTracer(name, version) : noopTracer;\nvar ABS_ATTRS = {\n tenant: \"abs.tenant\",\n shardId: \"abs.shard.id\",\n engineId: \"abs.engine.id\",\n collection: \"abs.collection\",\n mutation: \"abs.mutation\",\n mutationAttempt: \"abs.mutation.attempt\",\n subscriptionId: \"abs.subscription.id\",\n batchSize: \"abs.batch.size\",\n clusterMessageOrigin: \"abs.cluster.origin\",\n jobId: \"abs.job.id\",\n jobKind: \"abs.job.kind\",\n jobAttempt: \"abs.job.attempt\",\n jobMaxAttempts: \"abs.job.max_attempts\",\n workerId: \"abs.worker.id\",\n runtimeKey: \"abs.runtime.key\",\n runtimePid: \"abs.runtime.pid\",\n runtimePort: \"abs.runtime.port\",\n runtimeExitReason: \"abs.runtime.exit_reason\",\n runtimeReadinessMs: \"abs.runtime.readiness_ms\",\n routeShard: \"abs.route.shard\",\n routeDecision: \"abs.route.decision\",\n secretName: \"abs.secret.name\",\n secretFingerprint: \"abs.secret.fingerprint\",\n auditKind: \"abs.audit.kind\"\n};\nvar withSpan = async (tracer, name, options, fn) => tracer.startActiveSpan(name, options, async (span) => {\n try {\n const result = await fn(span);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error)\n });\n span.recordException(error);\n throw error;\n } finally {\n span.end();\n }\n});\nvar withSpanSync = (tracer, name, options, fn) => tracer.startActiveSpan(name, options, (span) => {\n try {\n const result = fn(span);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error)\n });\n span.recordException(error);\n throw error;\n } finally {\n span.end();\n }\n});\nvar readActiveTraceId = async () => {\n try {\n const specifier = [\"@opentelemetry\", \"api\"].join(\"/\");\n const otel = await import(specifier).catch(() => null);\n if (otel === null)\n return;\n const span = otel.trace.getActiveSpan?.();\n if (!span)\n return;\n const ctx = span.spanContext?.();\n return ctx?.traceId;\n } catch {\n return;\n }\n};\nexport {\n withSpanSync,\n withSpan,\n tracerOrNoop,\n readActiveTraceId,\n createNoopTracerProvider,\n createNoopTracer,\n createNoopSpan,\n SpanStatusCode,\n SpanKind,\n ABS_ATTRS\n};\n\n//# debugId=7A9259DC2D84DCF764756E2164756E21\n//# sourceMappingURL=index.js.map\n",
|
|
6
|
-
"// @bun\nvar __defProp = Object.defineProperty;\nvar __returnValue = (v) => v;\nfunction __exportSetter(name, newValue) {\n this[name] = __returnValue.bind(null, newValue);\n}\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, {\n get: all[name],\n enumerable: true,\n configurable: true,\n set: __exportSetter.bind(all, name)\n });\n};\n\n// src/canonical.ts\nvar normalize = (value) => {\n if (Array.isArray(value))\n return value.map(normalize);\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalize(entry)]));\n }\n return value;\n};\nvar canonicalJson = (value) => JSON.stringify(normalize(value));\nvar digest = async (value) => {\n const encoded = new TextEncoder().encode(canonicalJson(value));\n const result = await crypto.subtle.digest(\"SHA-256\", encoded);\n return [...new Uint8Array(result)].map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n};\nvar actionBinding = (action) => digest({\n action: action.action,\n actionId: action.actionId,\n actor: action.actor,\n effects: action.effects,\n expiresAt: action.expiresAt,\n inputDigest: action.inputDigest,\n resource: action.resource,\n spend: action.spend\n});\n// src/engine.ts\nvar DEFAULT_LEASE_TTL_MS = 60000;\nvar required = (value, message) => {\n if (value === undefined)\n throw new Error(message);\n return value;\n};\nvar createAgency = ({\n control,\n defaultLeaseTtlMs = DEFAULT_LEASE_TTL_MS,\n emit,\n now = Date.now,\n policy,\n store\n}) => {\n const decide = async (action, approval) => {\n const decision = await policy.evaluate({ action, approval, now: now() });\n await emit?.({\n actionId: action.actionId,\n decision,\n type: \"action.decided\"\n });\n return decision;\n };\n const request = async (input) => {\n await control?.assertActive(input.actor.agentId);\n const createdAt = now();\n const action = {\n ...input,\n actionId: `act_${crypto.randomUUID()}`,\n createdAt,\n inputDigest: await digest(input.input ?? null)\n };\n await store.saveAction(action);\n await emit?.({ action, type: \"action.requested\" });\n return { action, decision: await decide(action) };\n };\n const approve = async ({\n actionId,\n approvedBy,\n approvedUntil,\n conditions,\n state\n }) => {\n const action = required(await store.getAction(actionId), \"Unknown action\");\n const approvedAt = now();\n if (approvedUntil <= approvedAt)\n throw new Error(\"Approval must expire in the future\");\n const approval = {\n actionId,\n approvalId: `apr_${crypto.randomUUID()}`,\n approvedAt,\n approvedBy,\n approvedUntil,\n bindingDigest: await actionBinding(action),\n conditions,\n state\n };\n await store.saveApproval(approval);\n await emit?.({ actionId, approval, type: \"action.approved\" });\n return approval;\n };\n const issueLease = async (actionId) => {\n const action = required(await store.getAction(actionId), \"Unknown action\");\n await control?.assertActive(action.actor.agentId);\n const approval = await store.getApproval(actionId);\n const currentTime = now();\n if (action.expiresAt !== undefined && action.expiresAt <= currentTime) {\n throw new Error(\"Action request has expired\");\n }\n if (approval !== undefined) {\n if (approval.approvedUntil <= currentTime)\n throw new Error(\"Approval has expired\");\n if (approval.bindingDigest !== await actionBinding(action)) {\n throw new Error(\"Approval is not bound to the current action\");\n }\n }\n const decision = await decide(action, approval);\n if (decision.kind !== \"allow\")\n throw new Error(`Action denied: ${decision.reason}`);\n const issuedAt = now();\n const lease = {\n actionId,\n bindingDigest: await actionBinding(action),\n expiresAt: Math.min(issuedAt + defaultLeaseTtlMs, action.expiresAt ?? Number.POSITIVE_INFINITY, approval?.approvedUntil ?? Number.POSITIVE_INFINITY, decision.expiresAt ?? Number.POSITIVE_INFINITY),\n issuedAt,\n leaseId: `lease_${crypto.randomUUID()}`,\n maximumUses: 1\n };\n await store.saveLease(lease);\n await emit?.({ actionId, lease, type: \"action.lease-issued\" });\n return lease;\n };\n const execute = async ({\n costs,\n executor,\n leaseId,\n run\n }) => {\n const lease = required(await store.getLease(leaseId), \"Unknown execution lease\");\n const action = required(await store.getAction(lease.actionId), \"Unknown action\");\n await control?.assertActive(action.actor.agentId);\n const startedAt = now();\n if (lease.expiresAt <= startedAt)\n throw new Error(\"Execution lease has expired\");\n if (lease.bindingDigest !== await actionBinding(action)) {\n throw new Error(\"Execution lease is not bound to the current action\");\n }\n if (!await store.consumeLease(leaseId, startedAt)) {\n throw new Error(\"Execution lease has already been consumed\");\n }\n let result;\n let receipt;\n try {\n result = await run();\n receipt = {\n actionId: action.actionId,\n completedAt: now(),\n costs,\n executor,\n leaseId,\n receiptId: `rcpt_${crypto.randomUUID()}`,\n resultDigest: await digest(result),\n startedAt,\n status: \"succeeded\"\n };\n } catch (error) {\n receipt = {\n actionId: action.actionId,\n completedAt: now(),\n costs,\n error: error instanceof Error ? error.message : \"Action failed\",\n executor,\n leaseId,\n receiptId: `rcpt_${crypto.randomUUID()}`,\n startedAt,\n status: \"failed\"\n };\n await store.saveReceipt(receipt);\n await emit?.({\n actionId: action.actionId,\n receipt,\n type: \"action.completed\"\n });\n throw error;\n }\n await store.saveReceipt(receipt);\n await emit?.({\n actionId: action.actionId,\n receipt,\n type: \"action.completed\"\n });\n return { receipt, result };\n };\n const inspect = async (actorId) => ({\n actions: await store.listActions(actorId),\n approvals: await store.listApprovals(actorId),\n leases: await store.listLeases(actorId),\n receipts: await store.listReceipts(actorId)\n });\n return { approve, execute, inspect, issueLease, request };\n};\n// src/memory.ts\nvar clone = (value) => structuredClone(value);\nvar createMemoryAgencyStore = () => {\n const actions = new Map;\n const approvals = new Map;\n const leases = new Map;\n const receipts = new Map;\n const actorForAction = (actionId) => actions.get(actionId)?.actor.agentId;\n return {\n consumeLease: async (leaseId, consumedAt) => {\n const lease = leases.get(leaseId);\n if (lease === undefined || lease.consumedAt !== undefined)\n return false;\n leases.set(leaseId, { ...lease, consumedAt });\n return true;\n },\n getAction: async (actionId) => {\n const action = actions.get(actionId);\n return action === undefined ? undefined : clone(action);\n },\n getApproval: async (actionId) => {\n const approval = approvals.get(actionId);\n return approval === undefined ? undefined : clone(approval);\n },\n getLease: async (leaseId) => {\n const lease = leases.get(leaseId);\n return lease === undefined ? undefined : clone(lease);\n },\n listActions: async (actorId) => [...actions.values()].filter((action) => actorId === undefined || action.actor.agentId === actorId).map(clone),\n listApprovals: async (actorId) => [...approvals.values()].filter((approval) => actorId === undefined || actorForAction(approval.actionId) === actorId).map(clone),\n listLeases: async (actorId) => [...leases.values()].filter((lease) => actorId === undefined || actorForAction(lease.actionId) === actorId).map(clone),\n listReceipts: async (actorId) => [...receipts.values()].filter((receipt) => actorId === undefined || actorForAction(receipt.actionId) === actorId).map(clone),\n saveAction: async (action) => {\n actions.set(action.actionId, clone(action));\n },\n saveApproval: async (approval) => {\n approvals.set(approval.actionId, clone(approval));\n },\n saveLease: async (lease) => {\n leases.set(lease.leaseId, clone(lease));\n },\n saveReceipt: async (receipt) => {\n receipts.set(receipt.receiptId, clone(receipt));\n }\n };\n};\n// src/policies.ts\nvar allowAllPolicy = () => ({\n evaluate: ({ now }) => ({\n decisionId: `decision_${crypto.randomUUID()}`,\n evaluatedAt: now,\n kind: \"allow\"\n })\n});\nvar denyAllPolicy = (reason = \"default_deny\") => ({\n evaluate: ({ now }) => ({\n decisionId: `decision_${crypto.randomUUID()}`,\n evaluatedAt: now,\n kind: \"deny\",\n reason,\n requestable: false\n })\n});\n// src/control.ts\nvar createMemoryAgentControlStore = () => {\n const switches = new Map;\n return {\n clearKillSwitch: async (agentId) => {\n switches.delete(agentId);\n },\n getKillSwitch: async (agentId) => switches.get(agentId),\n setKillSwitch: async (killSwitch) => {\n switches.set(killSwitch.agentId, structuredClone(killSwitch));\n }\n };\n};\nvar createAgentControlPlane = ({\n now = Date.now,\n sources,\n store\n}) => {\n const status = async (agentId) => store.getKillSwitch(agentId);\n const assertActive = async (agentId) => {\n const killSwitch = await status(agentId);\n if (killSwitch !== undefined)\n throw new Error(`Agent is disabled: ${killSwitch.reason}`);\n };\n const inventory = async (agentId) => {\n const settled = await Promise.allSettled(sources.map(async (source) => ({\n items: await source.inventory(agentId),\n source: source.name\n })));\n return {\n agentId,\n items: settled.flatMap((result) => result.status === \"fulfilled\" ? result.value.items : []),\n killSwitch: await status(agentId),\n sourceErrors: settled.flatMap((result, index) => result.status === \"rejected\" ? [\n {\n error: result.reason instanceof Error ? result.reason.message : \"Control source failed\",\n source: sources[index]?.name ?? \"unknown\"\n }\n ] : [])\n };\n };\n const revoke = async ({\n activatedBy,\n agentId,\n reason\n }) => {\n const killSwitch = {\n activatedAt: now(),\n activatedBy,\n agentId,\n reason\n };\n await store.setKillSwitch(killSwitch);\n const settled = await Promise.allSettled(sources.map(async (source) => ({\n revoked: await source.revoke(agentId, reason),\n source: source.name\n })));\n return {\n killSwitch,\n results: settled.map((result, index) => result.status === \"fulfilled\" ? { ...result.value, status: \"fulfilled\" } : {\n error: result.reason instanceof Error ? result.reason.message : \"Control source failed\",\n source: sources[index]?.name ?? \"unknown\",\n status: \"rejected\"\n })\n };\n };\n return {\n assertActive,\n inventory,\n restore: store.clearKillSwitch,\n revoke,\n status\n };\n};\n// src/handoff.ts\nvar encode = (value) => btoa(String.fromCharCode(...new Uint8Array(value))).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\nvar keyBytes = (key) => typeof key === \"string\" ? new TextEncoder().encode(key) : key;\nvar constantTimeEqual = (left, right) => {\n if (left.length !== right.length)\n return false;\n let difference = 0;\n for (let index = 0;index < left.length; index += 1)\n difference |= (left[index] ?? 0) ^ (right[index] ?? 0);\n return difference === 0;\n};\nvar sign = async (claims, keyId, key) => {\n const rawKey = Uint8Array.from(keyBytes(key));\n const cryptoKey = await crypto.subtle.importKey(\"raw\", rawKey.buffer, { hash: \"SHA-256\", name: \"HMAC\" }, false, [\"sign\"]);\n return encode(await crypto.subtle.sign(\"HMAC\", cryptoKey, new TextEncoder().encode(canonicalJson({ claims, keyId }))));\n};\nvar signAgentHandoff = async ({\n claims,\n key,\n keyId\n}) => {\n const versioned = {\n ...claims,\n version: \"absolute.agent-handoff/1\"\n };\n return {\n algorithm: \"HS256\",\n claims: versioned,\n keyId,\n signature: await sign(versioned, keyId, key)\n };\n};\nvar verifyAgentHandoff = async ({\n expectedAudience,\n handoff,\n key,\n now = Date.now,\n replayStore\n}) => {\n if (handoff.algorithm !== \"HS256\")\n throw new Error(\"Unsupported handoff algorithm\");\n if (handoff.claims.version !== \"absolute.agent-handoff/1\")\n throw new Error(\"Unsupported handoff version\");\n if (handoff.claims.audience !== expectedAudience)\n throw new Error(\"Agent handoff audience mismatch\");\n if (handoff.claims.expiresAt <= now())\n throw new Error(\"Agent handoff has expired\");\n const expected = await sign(handoff.claims, handoff.keyId, key);\n const actualBytes = new TextEncoder().encode(handoff.signature);\n const expectedBytes = new TextEncoder().encode(expected);\n if (!constantTimeEqual(actualBytes, expectedBytes))\n throw new Error(\"Invalid agent handoff signature\");\n if (!await replayStore.consume(handoff.claims.nonce, handoff.claims.expiresAt))\n throw new Error(\"Agent handoff has already been consumed\");\n return structuredClone(handoff.claims);\n};\nvar createMemoryHandoffReplayStore = (now = Date.now) => {\n const nonces = new Map;\n return {\n consume: async (nonce, expiresAt) => {\n for (const [storedNonce, expiry] of nonces)\n if (expiry <= now())\n nonces.delete(storedNonce);\n if (nonces.has(nonce))\n return false;\n nonces.set(nonce, expiresAt);\n return true;\n }\n };\n};\nvar attenuateAgentHandoff = (parent, child) => {\n if (child.userId !== parent.userId)\n throw new Error(\"Agent handoff cannot change users\");\n if (child.expiresAt > parent.expiresAt)\n throw new Error(\"Agent handoff cannot extend expiry\");\n if (child.scopes.some((scope) => !parent.scopes.includes(scope)))\n throw new Error(\"Agent handoff cannot escalate scopes\");\n if (parent.spendLimit !== undefined) {\n if (child.spendLimit === undefined || child.spendLimit.currency !== parent.spendLimit.currency || child.spendLimit.amountMinor > parent.spendLimit.amountMinor)\n throw new Error(\"Agent handoff cannot escalate spend\");\n }\n return child;\n};\n// src/simulation.ts\nvar simulateAction = async ({\n approval,\n input,\n now = Date.now,\n policy\n}) => {\n const evaluatedAt = now();\n const action = {\n ...input,\n actionId: `sim_${await digest(input)}`,\n createdAt: evaluatedAt,\n inputDigest: await digest(input.input ?? null)\n };\n const decision = await policy.evaluate({\n action,\n approval,\n now: evaluatedAt\n });\n return {\n action,\n bindingDigest: await actionBinding(action),\n decision,\n dryRun: true,\n wouldExecute: decision.kind === \"allow\"\n };\n};\n// src/telemetry.ts\nvar agencyEventToTelemetry = (event, timestamp = Date.now()) => {\n const actionId = \"action\" in event ? event.action.actionId : event.actionId;\n const attributes = {\n \"agent.action.id\": actionId,\n \"agent.event.type\": event.type\n };\n if (event.type === \"action.requested\") {\n attributes[\"agent.id\"] = event.action.actor.agentId;\n attributes[\"agent.action.name\"] = event.action.action;\n attributes[\"agent.action.effects\"] = event.action.effects.join(\",\");\n attributes[\"agent.user.id\"] = event.action.actor.userId;\n } else if (event.type === \"action.decided\") {\n attributes[\"agent.decision.kind\"] = event.decision.kind;\n attributes[\"agent.decision.requestable\"] = event.decision.kind === \"deny\" && event.decision.requestable;\n } else if (event.type === \"action.lease-issued\") {\n attributes[\"agent.lease.id\"] = event.lease.leaseId;\n attributes[\"agent.lease.expires_at\"] = event.lease.expiresAt;\n } else if (event.type === \"action.completed\") {\n attributes[\"agent.receipt.id\"] = event.receipt.receiptId;\n attributes[\"agent.execution.status\"] = event.receipt.status;\n } else {\n attributes[\"agent.approval.id\"] = event.approval.approvalId;\n attributes[\"agent.approval.by\"] = event.approval.approvedBy;\n }\n return { attributes, name: `agent.${event.type}`, timestamp };\n};\nvar createAgencyTelemetryEmitter = (emit, now = Date.now) => (event) => emit(agencyEventToTelemetry(event, now()));\nexport {\n verifyAgentHandoff,\n simulateAction,\n signAgentHandoff,\n digest,\n denyAllPolicy,\n createMemoryHandoffReplayStore,\n createMemoryAgentControlStore,\n createMemoryAgencyStore,\n createAgentControlPlane,\n createAgencyTelemetryEmitter,\n createAgency,\n canonicalJson,\n attenuateAgentHandoff,\n allowAllPolicy,\n agencyEventToTelemetry,\n actionBinding\n};\n\n//# debugId=52D29C222039C20364756E2164756E21\n//# sourceMappingURL=index.js.map\n",
|
|
6
|
+
"// @bun\nvar __defProp = Object.defineProperty;\nvar __returnValue = (v) => v;\nfunction __exportSetter(name, newValue) {\n this[name] = __returnValue.bind(null, newValue);\n}\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, {\n get: all[name],\n enumerable: true,\n configurable: true,\n set: __exportSetter.bind(all, name)\n });\n};\n\n// src/canonical.ts\nvar normalize = (value) => {\n if (Array.isArray(value))\n return value.map(normalize);\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalize(entry)]));\n }\n return value;\n};\nvar canonicalJson = (value) => JSON.stringify(normalize(value));\nvar digest = async (value) => {\n const encoded = new TextEncoder().encode(canonicalJson(value));\n const result = await crypto.subtle.digest(\"SHA-256\", encoded);\n return [...new Uint8Array(result)].map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n};\nvar actionBinding = (action) => digest({\n action: action.action,\n actionId: action.actionId,\n actor: action.actor,\n effects: action.effects,\n expiresAt: action.expiresAt,\n inputDigest: action.inputDigest,\n resource: action.resource,\n spend: action.spend\n});\n// src/engine.ts\nvar DEFAULT_LEASE_TTL_MS = 60000;\nvar required = (value, message) => {\n if (value === undefined)\n throw new Error(message);\n return value;\n};\nvar createAgency = ({\n control,\n defaultLeaseTtlMs = DEFAULT_LEASE_TTL_MS,\n emit,\n now = Date.now,\n policy,\n store\n}) => {\n const decide = async (action, approval) => {\n const decision = await policy.evaluate({ action, approval, now: now() });\n await emit?.({\n actionId: action.actionId,\n decision,\n type: \"action.decided\"\n });\n return decision;\n };\n const request = async (input) => {\n await control?.assertActive(input.actor.agentId);\n const createdAt = now();\n const action = {\n ...input,\n actionId: `act_${crypto.randomUUID()}`,\n createdAt,\n inputDigest: await digest(input.input ?? null)\n };\n await store.saveAction(action);\n await emit?.({ action, type: \"action.requested\" });\n return { action, decision: await decide(action) };\n };\n const approve = async ({\n actionId,\n approvedBy,\n approvedUntil,\n conditions,\n state\n }) => {\n const action = required(await store.getAction(actionId), \"Unknown action\");\n const approvedAt = now();\n if (approvedUntil <= approvedAt)\n throw new Error(\"Approval must expire in the future\");\n const approval = {\n actionId,\n approvalId: `apr_${crypto.randomUUID()}`,\n approvedAt,\n approvedBy,\n approvedUntil,\n bindingDigest: await actionBinding(action),\n conditions,\n state\n };\n await store.saveApproval(approval);\n await emit?.({ actionId, approval, type: \"action.approved\" });\n return approval;\n };\n const issueLease = async (actionId) => {\n const action = required(await store.getAction(actionId), \"Unknown action\");\n await control?.assertActive(action.actor.agentId);\n const approval = await store.getApproval(actionId);\n const currentTime = now();\n if (action.expiresAt !== undefined && action.expiresAt <= currentTime) {\n throw new Error(\"Action request has expired\");\n }\n if (approval !== undefined) {\n if (approval.approvedUntil <= currentTime)\n throw new Error(\"Approval has expired\");\n if (approval.bindingDigest !== await actionBinding(action)) {\n throw new Error(\"Approval is not bound to the current action\");\n }\n }\n const decision = await decide(action, approval);\n if (decision.kind !== \"allow\")\n throw new Error(`Action denied: ${decision.reason}`);\n const issuedAt = now();\n const lease = {\n actionId,\n bindingDigest: await actionBinding(action),\n expiresAt: Math.min(issuedAt + defaultLeaseTtlMs, action.expiresAt ?? Number.POSITIVE_INFINITY, approval?.approvedUntil ?? Number.POSITIVE_INFINITY, decision.expiresAt ?? Number.POSITIVE_INFINITY),\n issuedAt,\n leaseId: `lease_${crypto.randomUUID()}`,\n maximumUses: 1\n };\n await store.saveLease(lease);\n await emit?.({ actionId, lease, type: \"action.lease-issued\" });\n return lease;\n };\n const execute = async ({\n costs,\n executor,\n leaseId,\n run\n }) => {\n const lease = required(await store.getLease(leaseId), \"Unknown execution lease\");\n const action = required(await store.getAction(lease.actionId), \"Unknown action\");\n await control?.assertActive(action.actor.agentId);\n const startedAt = now();\n if (lease.expiresAt <= startedAt)\n throw new Error(\"Execution lease has expired\");\n if (lease.bindingDigest !== await actionBinding(action)) {\n throw new Error(\"Execution lease is not bound to the current action\");\n }\n if (!await store.consumeLease(leaseId, startedAt)) {\n throw new Error(\"Execution lease has already been consumed\");\n }\n let result;\n let receipt;\n try {\n result = await run();\n receipt = {\n actionId: action.actionId,\n completedAt: now(),\n costs,\n executor,\n leaseId,\n receiptId: `rcpt_${crypto.randomUUID()}`,\n resultDigest: await digest(result),\n startedAt,\n status: \"succeeded\"\n };\n } catch (error) {\n receipt = {\n actionId: action.actionId,\n completedAt: now(),\n costs,\n error: error instanceof Error ? error.message : \"Action failed\",\n executor,\n leaseId,\n receiptId: `rcpt_${crypto.randomUUID()}`,\n startedAt,\n status: \"failed\"\n };\n await store.saveReceipt(receipt);\n await emit?.({\n actionId: action.actionId,\n receipt,\n type: \"action.completed\"\n });\n throw error;\n }\n await store.saveReceipt(receipt);\n await emit?.({\n actionId: action.actionId,\n receipt,\n type: \"action.completed\"\n });\n return { receipt, result };\n };\n const inspect = async (actorId) => ({\n actions: await store.listActions(actorId),\n approvals: await store.listApprovals(actorId),\n leases: await store.listLeases(actorId),\n receipts: await store.listReceipts(actorId)\n });\n return { approve, execute, inspect, issueLease, request };\n};\n// src/memory.ts\nvar clone = (value) => structuredClone(value);\nvar createMemoryAgencyStore = () => {\n const actions = new Map;\n const approvals = new Map;\n const leases = new Map;\n const receipts = new Map;\n const actorForAction = (actionId) => actions.get(actionId)?.actor.agentId;\n return {\n consumeLease: async (leaseId, consumedAt) => {\n const lease = leases.get(leaseId);\n if (lease === undefined || lease.consumedAt !== undefined)\n return false;\n leases.set(leaseId, { ...lease, consumedAt });\n return true;\n },\n getAction: async (actionId) => {\n const action = actions.get(actionId);\n return action === undefined ? undefined : clone(action);\n },\n getApproval: async (actionId) => {\n const approval = approvals.get(actionId);\n return approval === undefined ? undefined : clone(approval);\n },\n getLease: async (leaseId) => {\n const lease = leases.get(leaseId);\n return lease === undefined ? undefined : clone(lease);\n },\n listActions: async (actorId) => [...actions.values()].filter((action) => actorId === undefined || action.actor.agentId === actorId).map(clone),\n listApprovals: async (actorId) => [...approvals.values()].filter((approval) => actorId === undefined || actorForAction(approval.actionId) === actorId).map(clone),\n listLeases: async (actorId) => [...leases.values()].filter((lease) => actorId === undefined || actorForAction(lease.actionId) === actorId).map(clone),\n listReceipts: async (actorId) => [...receipts.values()].filter((receipt) => actorId === undefined || actorForAction(receipt.actionId) === actorId).map(clone),\n saveAction: async (action) => {\n actions.set(action.actionId, clone(action));\n },\n saveApproval: async (approval) => {\n approvals.set(approval.actionId, clone(approval));\n },\n saveLease: async (lease) => {\n leases.set(lease.leaseId, clone(lease));\n },\n saveReceipt: async (receipt) => {\n receipts.set(receipt.receiptId, clone(receipt));\n }\n };\n};\n// src/policies.ts\nvar allowAllPolicy = () => ({\n evaluate: ({ now }) => ({\n decisionId: `decision_${crypto.randomUUID()}`,\n evaluatedAt: now,\n kind: \"allow\"\n })\n});\nvar denyAllPolicy = (reason = \"default_deny\") => ({\n evaluate: ({ now }) => ({\n decisionId: `decision_${crypto.randomUUID()}`,\n evaluatedAt: now,\n kind: \"deny\",\n reason,\n requestable: false\n })\n});\n// src/control.ts\nvar createMemoryAgentControlStore = () => {\n const switches = new Map;\n return {\n clearKillSwitch: async (agentId) => {\n switches.delete(agentId);\n },\n getKillSwitch: async (agentId) => switches.get(agentId),\n setKillSwitch: async (killSwitch) => {\n switches.set(killSwitch.agentId, structuredClone(killSwitch));\n }\n };\n};\nvar createAgentControlPlane = ({\n now = Date.now,\n sources,\n store\n}) => {\n const status = async (agentId) => store.getKillSwitch(agentId);\n const assertActive = async (agentId) => {\n const killSwitch = await status(agentId);\n if (killSwitch !== undefined)\n throw new Error(`Agent is disabled: ${killSwitch.reason}`);\n };\n const inventory = async (agentId) => {\n const settled = await Promise.allSettled(sources.map(async (source) => ({\n items: await source.inventory(agentId),\n source: source.name\n })));\n return {\n agentId,\n items: settled.flatMap((result) => result.status === \"fulfilled\" ? result.value.items : []),\n killSwitch: await status(agentId),\n sourceErrors: settled.flatMap((result, index) => result.status === \"rejected\" ? [\n {\n error: result.reason instanceof Error ? result.reason.message : \"Control source failed\",\n source: sources[index]?.name ?? \"unknown\"\n }\n ] : [])\n };\n };\n const revoke = async ({\n activatedBy,\n agentId,\n reason\n }) => {\n const killSwitch = {\n activatedAt: now(),\n activatedBy,\n agentId,\n reason\n };\n await store.setKillSwitch(killSwitch);\n const settled = await Promise.allSettled(sources.map(async (source) => ({\n revoked: await source.revoke(agentId, reason),\n source: source.name\n })));\n return {\n killSwitch,\n results: settled.map((result, index) => result.status === \"fulfilled\" ? { ...result.value, status: \"fulfilled\" } : {\n error: result.reason instanceof Error ? result.reason.message : \"Control source failed\",\n source: sources[index]?.name ?? \"unknown\",\n status: \"rejected\"\n })\n };\n };\n return {\n assertActive,\n inventory,\n restore: store.clearKillSwitch,\n revoke,\n status\n };\n};\n// src/handoff.ts\nvar encode = (value) => btoa(String.fromCharCode(...new Uint8Array(value))).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\nvar keyBytes = (key) => typeof key === \"string\" ? new TextEncoder().encode(key) : key;\nvar constantTimeEqual = (left, right) => {\n if (left.length !== right.length)\n return false;\n let difference = 0;\n for (let index = 0;index < left.length; index += 1)\n difference |= (left[index] ?? 0) ^ (right[index] ?? 0);\n return difference === 0;\n};\nvar sign = async (claims, keyId, key) => {\n const rawKey = Uint8Array.from(keyBytes(key));\n const cryptoKey = await crypto.subtle.importKey(\"raw\", rawKey.buffer, { hash: \"SHA-256\", name: \"HMAC\" }, false, [\"sign\"]);\n return encode(await crypto.subtle.sign(\"HMAC\", cryptoKey, new TextEncoder().encode(canonicalJson({ claims, keyId }))));\n};\nvar signAgentHandoff = async ({\n claims,\n key,\n keyId\n}) => {\n const versioned = {\n ...claims,\n version: \"absolute.agent-handoff/1\"\n };\n return {\n algorithm: \"HS256\",\n claims: versioned,\n keyId,\n signature: await sign(versioned, keyId, key)\n };\n};\nvar verifyAgentHandoff = async ({\n expectedAudience,\n handoff,\n key,\n now = Date.now,\n replayStore\n}) => {\n if (handoff.algorithm !== \"HS256\")\n throw new Error(\"Unsupported handoff algorithm\");\n if (handoff.claims.version !== \"absolute.agent-handoff/1\")\n throw new Error(\"Unsupported handoff version\");\n if (handoff.claims.audience !== expectedAudience)\n throw new Error(\"Agent handoff audience mismatch\");\n if (handoff.claims.expiresAt <= now())\n throw new Error(\"Agent handoff has expired\");\n const expected = await sign(handoff.claims, handoff.keyId, key);\n const actualBytes = new TextEncoder().encode(handoff.signature);\n const expectedBytes = new TextEncoder().encode(expected);\n if (!constantTimeEqual(actualBytes, expectedBytes))\n throw new Error(\"Invalid agent handoff signature\");\n if (!await replayStore.consume(handoff.claims.nonce, handoff.claims.expiresAt))\n throw new Error(\"Agent handoff has already been consumed\");\n return structuredClone(handoff.claims);\n};\nvar createMemoryHandoffReplayStore = (now = Date.now) => {\n const nonces = new Map;\n return {\n consume: async (nonce, expiresAt) => {\n for (const [storedNonce, expiry] of nonces)\n if (expiry <= now())\n nonces.delete(storedNonce);\n if (nonces.has(nonce))\n return false;\n nonces.set(nonce, expiresAt);\n return true;\n }\n };\n};\nvar attenuateAgentHandoff = (parent, child) => {\n if (child.userId !== parent.userId)\n throw new Error(\"Agent handoff cannot change users\");\n if (child.expiresAt > parent.expiresAt)\n throw new Error(\"Agent handoff cannot extend expiry\");\n if (child.scopes.some((scope) => !parent.scopes.includes(scope)))\n throw new Error(\"Agent handoff cannot escalate scopes\");\n if (parent.spendLimit !== undefined) {\n if (child.spendLimit === undefined || child.spendLimit.currency !== parent.spendLimit.currency || child.spendLimit.amountMinor > parent.spendLimit.amountMinor)\n throw new Error(\"Agent handoff cannot escalate spend\");\n }\n return child;\n};\n// src/simulation.ts\nvar simulateAction = async ({\n approval,\n input,\n now = Date.now,\n policy\n}) => {\n const evaluatedAt = now();\n const action = {\n ...input,\n actionId: `sim_${await digest(input)}`,\n createdAt: evaluatedAt,\n inputDigest: await digest(input.input ?? null)\n };\n const decision = await policy.evaluate({\n action,\n approval,\n now: evaluatedAt\n });\n return {\n action,\n bindingDigest: await actionBinding(action),\n decision,\n dryRun: true,\n wouldExecute: decision.kind === \"allow\"\n };\n};\n// src/postgres.ts\nvar namespaceOf = (namespace) => {\n if (!/^[a-z_][a-z0-9_]*$/.test(namespace))\n throw new Error(\"Agency PostgreSQL namespace must be a simple identifier\");\n return namespace;\n};\nvar agencyPostgresSchemaSql = (namespace = \"agency\") => {\n const ns = namespaceOf(namespace);\n return `CREATE SCHEMA IF NOT EXISTS ${ns};\nCREATE TABLE IF NOT EXISTS ${ns}.actions (\n action_id text PRIMARY KEY,\n actor_id text NOT NULL,\n created_at bigint NOT NULL,\n data jsonb NOT NULL\n);\nCREATE INDEX IF NOT EXISTS actions_actor_created_idx ON ${ns}.actions (actor_id, created_at DESC);\nCREATE TABLE IF NOT EXISTS ${ns}.approvals (\n action_id text PRIMARY KEY REFERENCES ${ns}.actions(action_id) ON DELETE CASCADE,\n actor_id text NOT NULL,\n approved_at bigint NOT NULL,\n data jsonb NOT NULL\n);\nCREATE TABLE IF NOT EXISTS ${ns}.leases (\n lease_id text PRIMARY KEY,\n action_id text NOT NULL REFERENCES ${ns}.actions(action_id) ON DELETE CASCADE,\n actor_id text NOT NULL,\n issued_at bigint NOT NULL,\n consumed_at bigint,\n data jsonb NOT NULL\n);\nCREATE TABLE IF NOT EXISTS ${ns}.receipts (\n receipt_id text PRIMARY KEY,\n action_id text NOT NULL REFERENCES ${ns}.actions(action_id) ON DELETE CASCADE,\n actor_id text NOT NULL,\n completed_at bigint NOT NULL,\n data jsonb NOT NULL\n);\nCREATE TABLE IF NOT EXISTS ${ns}.kill_switches (\n agent_id text PRIMARY KEY,\n activated_at bigint NOT NULL,\n data jsonb NOT NULL\n);\nCREATE TABLE IF NOT EXISTS ${ns}.handoff_nonces (\n nonce_hash text PRIMARY KEY,\n expires_at bigint NOT NULL\n);\nCREATE INDEX IF NOT EXISTS handoff_nonces_expiry_idx ON ${ns}.handoff_nonces (expires_at);`;\n};\nvar createPostgresAgencyStore = ({\n client,\n namespace = \"agency\"\n}) => {\n const ns = namespaceOf(namespace);\n const one = async (sql, parameters) => (await client.query(sql, parameters)).rows[0]?.data;\n const many = async (sql, parameters) => (await client.query(sql, parameters)).rows.map(({ data }) => data);\n const actorFor = async (actionId) => {\n const row = await client.query(`SELECT actor_id FROM ${ns}.actions WHERE action_id = $1`, [actionId]);\n if (row.rows[0] === undefined)\n throw new Error(\"Unknown action\");\n return row.rows[0].actor_id;\n };\n return {\n consumeLease: async (leaseId, consumedAt) => (await client.query(`UPDATE ${ns}.leases SET consumed_at = $2, data = jsonb_set(data, '{consumedAt}', to_jsonb($2::bigint), true) WHERE lease_id = $1 AND consumed_at IS NULL`, [leaseId, consumedAt])).rowCount === 1,\n getAction: (id) => one(`SELECT data FROM ${ns}.actions WHERE action_id = $1`, [id]),\n getApproval: (id) => one(`SELECT data FROM ${ns}.approvals WHERE action_id = $1`, [id]),\n getLease: (id) => one(`SELECT data FROM ${ns}.leases WHERE lease_id = $1`, [id]),\n listActions: (actorId) => many(`SELECT data FROM ${ns}.actions WHERE ($1::text IS NULL OR actor_id = $1) ORDER BY created_at DESC`, [actorId ?? null]),\n listApprovals: (actorId) => many(`SELECT data FROM ${ns}.approvals WHERE ($1::text IS NULL OR actor_id = $1) ORDER BY approved_at DESC`, [actorId ?? null]),\n listLeases: (actorId) => many(`SELECT data FROM ${ns}.leases WHERE ($1::text IS NULL OR actor_id = $1) ORDER BY issued_at DESC`, [actorId ?? null]),\n listReceipts: (actorId) => many(`SELECT data FROM ${ns}.receipts WHERE ($1::text IS NULL OR actor_id = $1) ORDER BY completed_at DESC`, [actorId ?? null]),\n saveAction: async (action) => {\n await client.query(`INSERT INTO ${ns}.actions (action_id, actor_id, created_at, data) VALUES ($1, $2, $3, $4::jsonb) ON CONFLICT (action_id) DO UPDATE SET data = EXCLUDED.data`, [action.actionId, action.actor.agentId, action.createdAt, JSON.stringify(action)]);\n },\n saveApproval: async (approval) => {\n await client.query(`INSERT INTO ${ns}.approvals (action_id, actor_id, approved_at, data) VALUES ($1, $2, $3, $4::jsonb) ON CONFLICT (action_id) DO UPDATE SET approved_at = EXCLUDED.approved_at, data = EXCLUDED.data`, [approval.actionId, await actorFor(approval.actionId), approval.approvedAt, JSON.stringify(approval)]);\n },\n saveLease: async (lease) => {\n await client.query(`INSERT INTO ${ns}.leases (lease_id, action_id, actor_id, issued_at, consumed_at, data) VALUES ($1, $2, $3, $4, $5, $6::jsonb) ON CONFLICT (lease_id) DO NOTHING`, [lease.leaseId, lease.actionId, await actorFor(lease.actionId), lease.issuedAt, lease.consumedAt ?? null, JSON.stringify(lease)]);\n },\n saveReceipt: async (receipt) => {\n await client.query(`INSERT INTO ${ns}.receipts (receipt_id, action_id, actor_id, completed_at, data) VALUES ($1, $2, $3, $4, $5::jsonb) ON CONFLICT (receipt_id) DO NOTHING`, [receipt.receiptId, receipt.actionId, await actorFor(receipt.actionId), receipt.completedAt, JSON.stringify(receipt)]);\n }\n };\n};\nvar createPostgresAgentControlStore = ({\n client,\n namespace = \"agency\"\n}) => {\n const ns = namespaceOf(namespace);\n return {\n clearKillSwitch: async (agentId) => {\n await client.query(`DELETE FROM ${ns}.kill_switches WHERE agent_id = $1`, [agentId]);\n },\n getKillSwitch: async (agentId) => (await client.query(`SELECT data FROM ${ns}.kill_switches WHERE agent_id = $1`, [agentId])).rows[0]?.data,\n setKillSwitch: async (killSwitch) => {\n await client.query(`INSERT INTO ${ns}.kill_switches (agent_id, activated_at, data) VALUES ($1, $2, $3::jsonb) ON CONFLICT (agent_id) DO UPDATE SET activated_at = EXCLUDED.activated_at, data = EXCLUDED.data`, [killSwitch.agentId, killSwitch.activatedAt, JSON.stringify(killSwitch)]);\n }\n };\n};\nvar createPostgresHandoffReplayStore = ({\n client,\n namespace = \"agency\",\n now = Date.now\n}) => {\n const ns = namespaceOf(namespace);\n return {\n consume: async (nonce, expiresAt) => {\n if (expiresAt <= now())\n return false;\n const nonceHash = await digest(nonce);\n const result = await client.query(`INSERT INTO ${ns}.handoff_nonces (nonce_hash, expires_at) VALUES ($1, $2) ON CONFLICT (nonce_hash) DO NOTHING`, [nonceHash, expiresAt]);\n return result.rowCount === 1;\n }\n };\n};\n// src/telemetry.ts\nvar agencyEventToTelemetry = (event, timestamp = Date.now()) => {\n const actionId = \"action\" in event ? event.action.actionId : event.actionId;\n const attributes = {\n \"agent.action.id\": actionId,\n \"agent.event.type\": event.type\n };\n if (event.type === \"action.requested\") {\n attributes[\"agent.id\"] = event.action.actor.agentId;\n attributes[\"agent.action.name\"] = event.action.action;\n attributes[\"agent.action.effects\"] = event.action.effects.join(\",\");\n attributes[\"agent.user.id\"] = event.action.actor.userId;\n } else if (event.type === \"action.decided\") {\n attributes[\"agent.decision.kind\"] = event.decision.kind;\n attributes[\"agent.decision.requestable\"] = event.decision.kind === \"deny\" && event.decision.requestable;\n } else if (event.type === \"action.lease-issued\") {\n attributes[\"agent.lease.id\"] = event.lease.leaseId;\n attributes[\"agent.lease.expires_at\"] = event.lease.expiresAt;\n } else if (event.type === \"action.completed\") {\n attributes[\"agent.receipt.id\"] = event.receipt.receiptId;\n attributes[\"agent.execution.status\"] = event.receipt.status;\n } else {\n attributes[\"agent.approval.id\"] = event.approval.approvalId;\n attributes[\"agent.approval.by\"] = event.approval.approvedBy;\n }\n return { attributes, name: `agent.${event.type}`, timestamp };\n};\nvar createAgencyTelemetryEmitter = (emit, now = Date.now) => (event) => emit(agencyEventToTelemetry(event, now()));\nexport {\n verifyAgentHandoff,\n simulateAction,\n signAgentHandoff,\n digest,\n denyAllPolicy,\n createPostgresHandoffReplayStore,\n createPostgresAgentControlStore,\n createPostgresAgencyStore,\n createMemoryHandoffReplayStore,\n createMemoryAgentControlStore,\n createMemoryAgencyStore,\n createAgentControlPlane,\n createAgencyTelemetryEmitter,\n createAgency,\n canonicalJson,\n attenuateAgentHandoff,\n allowAllPolicy,\n agencyPostgresSchemaSql,\n agencyEventToTelemetry,\n actionBinding\n};\n\n//# debugId=9228E134AB6761D064756E2164756E21\n//# sourceMappingURL=index.js.map\n",
|
|
7
7
|
"import {\n type ActionDecision,\n type Agency,\n type AgentActor,\n digest,\n} from \"@absolutejs/agency\";\nimport type { SecretBroker } from \"./index\";\n\nexport type CredentialGrant = {\n agentId: string;\n allowedOrigins: ReadonlyArray<string>;\n createdAt: number;\n expiresAt: number;\n grantId: string;\n maximumUses: number;\n provider: string;\n scopes: ReadonlyArray<string>;\n secretName: string;\n used: number;\n userId: string;\n};\n\nexport type CredentialOperationInput = {\n actor: AgentActor;\n destination: string;\n grantId: string;\n idempotencyKey?: string;\n input?: unknown;\n operation: string;\n};\n\nexport type CredentialOperationContext = {\n credential: string;\n destination: URL;\n input: unknown;\n signal?: AbortSignal;\n};\n\nexport type CredentialProvider = {\n operations: Record<\n string,\n (context: CredentialOperationContext) => Promise<unknown> | unknown\n >;\n provider: string;\n};\n\nexport type PendingCredentialOperation = {\n actionId: string;\n input: CredentialOperationInput;\n};\n\nexport type CredentialGrantStore = {\n consume: (\n grantId: string,\n now: number,\n ) => Promise<CredentialGrant | undefined>;\n get: (grantId: string) => Promise<CredentialGrant | undefined>;\n getPending: (\n actionId: string,\n ) => Promise<PendingCredentialOperation | undefined>;\n put: (grant: CredentialGrant) => Promise<void>;\n putPending: (pending: PendingCredentialOperation) => Promise<void>;\n revoke: (grantId: string) => Promise<boolean>;\n};\n\nexport type CredentialOperationEvent =\n | {\n actionId?: string;\n destinationOrigin: string;\n grantId: string;\n operation: string;\n provider: string;\n type: \"credential.operation.requested\";\n }\n | {\n actionId?: string;\n destinationOrigin: string;\n grantId: string;\n operation: string;\n provider: string;\n resultDigest?: string;\n status: \"failed\" | \"succeeded\";\n type: \"credential.operation.completed\";\n };\n\nexport type CredentialOperationResult =\n | {\n actionId: string;\n decision: ActionDecision;\n kind: \"pending\";\n }\n | {\n actionId?: string;\n kind: \"completed\";\n result: unknown;\n resultDigest: string;\n };\n\nexport type CredentialOperationBrokerOptions = {\n agency?: Agency;\n emit?: (event: CredentialOperationEvent) => Promise<void> | void;\n now?: () => number;\n providers: ReadonlyArray<CredentialProvider>;\n secrets: SecretBroker;\n store: CredentialGrantStore;\n};\n\nconst normalizeOrigin = (destination: string) => new URL(destination).origin;\n\nconst validateGrant = (\n grant: CredentialGrant,\n input: CredentialOperationInput,\n now: number,\n) => {\n if (\n grant.agentId !== input.actor.agentId ||\n grant.userId !== input.actor.userId\n )\n throw new Error(\"Credential grant actor mismatch\");\n if (grant.expiresAt <= now) throw new Error(\"Credential grant has expired\");\n if (!grant.scopes.includes(input.operation))\n throw new Error(\"Credential operation is outside grant scope\");\n const origin = normalizeOrigin(input.destination);\n if (!grant.allowedOrigins.map(normalizeOrigin).includes(origin))\n throw new Error(\"Credential destination is outside grant scope\");\n if (grant.used >= grant.maximumUses)\n throw new Error(\"Credential grant has been exhausted\");\n\n return origin;\n};\n\nexport const createMemoryCredentialGrantStore = (): CredentialGrantStore => {\n const grants = new Map<string, CredentialGrant>();\n const pending = new Map<string, PendingCredentialOperation>();\n let lock = Promise.resolve();\n\n const exclusive = async <Result>(run: () => Result | Promise<Result>) => {\n const previous = lock;\n let release = () => {};\n lock = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n try {\n return await run();\n } finally {\n release();\n }\n };\n\n return {\n consume: (grantId, now) =>\n exclusive(() => {\n const grant = grants.get(grantId);\n if (\n grant === undefined ||\n grant.expiresAt <= now ||\n grant.used >= grant.maximumUses\n )\n return undefined;\n const consumed = { ...grant, used: grant.used + 1 };\n grants.set(grantId, consumed);\n return { ...consumed };\n }),\n get: async (grantId) => {\n const grant = grants.get(grantId);\n return grant === undefined ? undefined : { ...grant };\n },\n getPending: async (actionId) => pending.get(actionId),\n put: async (grant) => {\n if (grant.maximumUses < 1)\n throw new Error(\"maximumUses must be positive\");\n if (grant.used < 0 || grant.used > grant.maximumUses)\n throw new Error(\"Invalid credential grant usage\");\n grants.set(grant.grantId, { ...grant });\n },\n putPending: async (operation) => {\n pending.set(operation.actionId, operation);\n },\n revoke: async (grantId) => grants.delete(grantId),\n };\n};\n\nexport const createCredentialOperationBroker = ({\n agency,\n emit,\n now = Date.now,\n providers,\n secrets,\n store,\n}: CredentialOperationBrokerOptions) => {\n const providerMap = new Map(\n providers.map((provider) => [provider.provider, provider]),\n );\n\n const perform = async (\n input: CredentialOperationInput,\n actionId?: string,\n signal?: AbortSignal,\n ): Promise<CredentialOperationResult> => {\n const preview = await store.get(input.grantId);\n if (preview === undefined) throw new Error(\"Unknown credential grant\");\n const origin = validateGrant(preview, input, now());\n const provider = providerMap.get(preview.provider);\n const operation = provider?.operations[input.operation];\n if (provider === undefined || operation === undefined)\n throw new Error(\"Credential provider operation is not registered\");\n await emit?.({\n actionId,\n destinationOrigin: origin,\n grantId: preview.grantId,\n operation: input.operation,\n provider: preview.provider,\n type: \"credential.operation.requested\",\n });\n const consumed = await store.consume(input.grantId, now());\n if (consumed === undefined)\n throw new Error(\"Credential grant has been exhausted\");\n validateGrant({ ...consumed, used: consumed.used - 1 }, input, now());\n const secret = await secrets.resolve(consumed.secretName);\n if (secret === null) throw new Error(\"Credential is not configured\");\n try {\n const result = await operation({\n credential: secret.value,\n destination: new URL(input.destination),\n input: input.input,\n signal,\n });\n const resultDigest = await digest(result);\n await emit?.({\n actionId,\n destinationOrigin: origin,\n grantId: consumed.grantId,\n operation: input.operation,\n provider: consumed.provider,\n resultDigest,\n status: \"succeeded\",\n type: \"credential.operation.completed\",\n });\n return { actionId, kind: \"completed\", result, resultDigest };\n } catch (error) {\n await emit?.({\n actionId,\n destinationOrigin: origin,\n grantId: consumed.grantId,\n operation: input.operation,\n provider: consumed.provider,\n status: \"failed\",\n type: \"credential.operation.completed\",\n });\n throw error;\n }\n };\n\n const request = async (\n input: CredentialOperationInput,\n signal?: AbortSignal,\n ): Promise<CredentialOperationResult> => {\n const grant = await store.get(input.grantId);\n if (grant === undefined) throw new Error(\"Unknown credential grant\");\n const origin = validateGrant(grant, input, now());\n if (agency === undefined) return perform(input, undefined, signal);\n const { action, decision } = await agency.request({\n action: `credential.${grant.provider}.${input.operation}`,\n actor: input.actor,\n context: { destinationOrigin: origin, grantId: grant.grantId },\n effects: [\"external-network\"],\n expiresAt: grant.expiresAt,\n idempotencyKey: input.idempotencyKey,\n input: { destination: input.destination, input: input.input },\n resource: { id: grant.grantId, type: \"credential-grant\" },\n });\n if (decision.kind !== \"allow\") {\n await store.putPending({ actionId: action.actionId, input });\n return { actionId: action.actionId, decision, kind: \"pending\" };\n }\n const lease = await agency.issueLease(action.actionId);\n const execution = await agency.execute({\n executor: `credential-provider:${grant.provider}`,\n leaseId: lease.leaseId,\n run: () => perform(input, action.actionId, signal),\n });\n return execution.result;\n };\n\n const resume = async (actionId: string, signal?: AbortSignal) => {\n if (agency === undefined) throw new Error(\"Agency is not configured\");\n const pending = await store.getPending(actionId);\n if (pending === undefined)\n throw new Error(\"Unknown pending credential operation\");\n const lease = await agency.issueLease(actionId);\n const execution = await agency.execute({\n executor: \"credential-provider\",\n leaseId: lease.leaseId,\n run: () => perform(pending.input, actionId, signal),\n });\n return execution.result;\n };\n\n return { request, resume, revoke: store.revoke };\n};\n\nexport type CredentialOperationBroker = ReturnType<\n typeof createCredentialOperationBroker\n>;\n",
|
|
8
|
-
"/**\n * @absolutejs/secrets — host-side secret broker for multi-tenant Bun\n * runtimes.\n *\n * Three responsibilities, kept narrow on purpose:\n *\n * 1. **Resolve.** A pluggable adapter fetches a secret by name. The broker\n * caches the answer, hands the caller back a `{ value, fingerprint }`\n * pair (fingerprint is a sha256 prefix safe to put in logs), and fires\n * an audit event for every lookup.\n * 2. **Redact.** Walks every known cached secret out of an arbitrary string\n * before it leaves the host (e.g. an error message that contains the\n * leaked API key the host call just made). The replacement is\n * `[REDACTED:name]`; matches shorter than `redactionMinLength` are\n * skipped to avoid blanking coincidental short tokens.\n * 3. **Rotate.** Delegates to `adapter.rotate?(name)` if the adapter\n * supports it, invalidates the cache entry. Caller is expected to\n * re-distribute to dependent surfaces.\n *\n * v0.0.1 ships three adapters: `inMemoryAdapter`, `envAdapter`,\n * `compositeAdapter`. AWS Secrets Manager / Vault / Doppler / Infisical\n * adapters ship later as siblings.\n *\n * The broker is bun/elysia-agnostic — same posture as router + meter.\n */\n\nimport {\n\tABS_ATTRS,\n\ttracerOrNoop,\n\ttype TracerProvider\n} from '@absolutejs/telemetry';\n\nexport {\n\tcreateCredentialOperationBroker,\n\tcreateMemoryCredentialGrantStore,\n\ttype CredentialGrant,\n\ttype CredentialGrantStore,\n\ttype CredentialOperationBroker,\n\ttype CredentialOperationBrokerOptions,\n\ttype CredentialOperationContext,\n\ttype CredentialOperationEvent,\n\ttype CredentialOperationInput,\n\ttype CredentialOperationResult,\n\ttype CredentialProvider,\n\ttype PendingCredentialOperation\n} from './operations';\n\nexport type SecretValue = {\n\t/** The plaintext secret. Treat as poison: never log, never serialize. */\n\tvalue: string;\n\t/**\n\t * Short sha256-derived id (first 8 hex chars). Stable across calls for\n\t * the same value; safe to print in logs and traces. Useful for \"which\n\t * version of the key did this request use?\" diagnostics without leaking.\n\t */\n\tfingerprint: string;\n};\n\nexport type SecretAdapter = {\n\t/** Return the plaintext value for a name, or `null` if not stored here. */\n\tfetch: (name: string) => Promise<string | null>;\n\t/** Write a value. Optional — adapters may be read-only. */\n\tput?: (name: string, value: string) => Promise<void>;\n\t/** Delete a value. Optional. */\n\tremove?: (name: string) => Promise<void>;\n\t/** Rotate a value; return the NEW plaintext. Optional. */\n\trotate?: (name: string) => Promise<string>;\n\t/** Enumerate names. Optional; default omitted to avoid leaking the index. */\n\tlist?: () => Promise<string[]>;\n};\n\nexport type AuditEvent =\n\t| { event: 'resolve.hit'; name: string; fingerprint: string; at: number }\n\t| { event: 'resolve.miss'; name: string; fingerprint?: string; at: number }\n\t| { event: 'resolve.error'; name: string; error: string; at: number }\n\t| { event: 'rotate'; name: string; fingerprint: string; at: number }\n\t| { event: 'invalidate'; name: string | null; at: number };\n\nexport type AuditHook = (event: AuditEvent) => void | Promise<void>;\n\nexport type RedactionEncoding = 'plain' | 'base64';\n\nexport type SecretBrokerOptions = {\n\t/** The adapter the broker delegates fetch / rotate / put to. */\n\tadapter: SecretAdapter;\n\t/** Audit hook fired on every resolve / rotate / invalidate. */\n\taudit?: AuditHook;\n\t/**\n\t * How long a cached secret stays fresh, in ms. After this, the next\n\t * resolve re-hits the adapter. Default 60_000 (1 minute). Set to\n\t * `Infinity` to disable TTL — only `rotate` / `invalidate` evict.\n\t */\n\tcacheTtlMs?: number;\n\t/**\n\t * Per-name TTL overrides. The override wins over `cacheTtlMs`. Use\n\t * a short TTL for high-blast-radius secrets (admin tokens, signing\n\t * keys) so a compromised value's lifetime is bounded by the override,\n\t * not the global default.\n\t */\n\tcacheTtlOverrides?: Record<string, number>;\n\t/**\n\t * Minimum length a cached value must have before `redact` will rewrite\n\t * occurrences of it in arbitrary text. Default 8 — short values risk\n\t * blanking out coincidental matches (e.g. a short password \"abc1\"\n\t * appearing as a substring of unrelated text).\n\t */\n\tredactionMinLength?: number;\n\t/**\n\t * Encodings to redact alongside the plaintext value. Default `['plain']`.\n\t * Add `'base64'` to also catch base64-encoded forms — useful when\n\t * secrets end up inside JWTs, cookies, or any payload that base64-wraps\n\t * a credential.\n\t */\n\tredactionEncodings?: RedactionEncoding[];\n\t/** Override `Date.now` for tests. */\n\tclock?: () => number;\n\t/**\n\t * Optional OpenTelemetry tracer provider. When set, `broker.resolve`\n\t * and `broker.rotate` are wrapped in `secrets.resolve` /\n\t * `secrets.rotate` spans with `abs.secret.name` +\n\t * `abs.secret.fingerprint` attributes. `broker.redact` is NOT\n\t * traced — it's called per log line, which would explode span\n\t * volume. When omitted, all tracing is a zero-allocation noop.\n\t * Added in 0.3.0.\n\t */\n\ttracerProvider?: TracerProvider;\n};\n\n/** Listener registered via {@link SecretBroker.onRotate}. */\nexport type RotationListener = (event: {\n\tname: string;\n\tvalue: string;\n\tfingerprint: string;\n\tat: number;\n}) => void | Promise<void>;\n\nexport type SecretBroker = {\n\t/**\n\t * Resolve a secret by name. Returns `null` if the adapter reports\n\t * no value. Caches the answer for `cacheTtlMs`.\n\t */\n\tresolve: (name: string) => Promise<SecretValue | null>;\n\t/**\n\t * Returns the fingerprint of a value WITHOUT touching the adapter.\n\t * Useful for hashing a value the caller already has — e.g. a webhook\n\t * payload — to compare against an audit log.\n\t */\n\tfingerprint: (value: string) => string;\n\t/**\n\t * Replace every cached secret value found in `text` with\n\t * `[REDACTED:name]`. Returns the rewritten text. Subjects shorter than\n\t * `redactionMinLength` are skipped.\n\t */\n\tredact: (text: string) => string;\n\t/**\n\t * Streaming variant of {@link redact}. Returns a `TransformStream`\n\t * that catches secrets even when they're split across chunks (a chunk\n\t * boundary in the middle of `sk_live_abc...` would otherwise miss). The\n\t * stream keeps a lookback buffer the size of the longest cached secret;\n\t * once the buffer outgrows that, the safe-region prefix is emitted.\n\t *\n\t * Use this on `process.stdout` / `process.stderr` / a tenant log forwarder\n\t * so plaintext secrets never reach the sink.\n\t */\n\tredactStream: () => TransformStream<string, string>;\n\t/**\n\t * Rotate a secret. Calls `adapter.rotate(name)`, invalidates the cache,\n\t * returns the new `{ value, fingerprint }`. Throws if the adapter does\n\t * not support rotation. Fires every `onRotate` listener registered for\n\t * this name.\n\t */\n\trotate: (name: string) => Promise<SecretValue>;\n\t/**\n\t * Subscribe to rotation events for a specific name. Listener fires\n\t * AFTER the new value is in the cache. Returns an unsubscribe handle.\n\t * Use this for long-lived connections (DB clients, AI provider SDKs)\n\t * that need to swap credentials in-place when rotation lands.\n\t */\n\tonRotate: (name: string, listener: RotationListener) => () => void;\n\t/**\n\t * Invalidate one cache entry, or the whole cache when `name` is omitted.\n\t */\n\tinvalidate: (name?: string) => void;\n\t/** Tear down the broker — clears the cache; further resolves still hit the adapter. */\n\tdispose: () => void;\n\t/**\n\t * Operator-shaped cumulative counters since `createSecretBroker()`.\n\t * Scrape on a 30s interval for tier monitoring + rotation cadence.\n\t * Added in 0.2.0.\n\t */\n\tmetrics: () => SecretBrokerMetrics;\n\t/**\n\t * Refuse new `resolve()` / `rotate()` calls (they reject with\n\t * `BrokerDrainedError`); in-flight adapter calls keep running. Use\n\t * during graceful shutdown so a tenant whose process is about to\n\t * stop doesn't issue a fresh fetch against the secret store mid-\n\t * teardown. Symmetric with `runtime.drain()` / `queue.drain()`.\n\t * Added in 0.2.0.\n\t */\n\tdrain: () => void;\n};\n\n/**\n * Returned by {@link SecretBroker.metrics}. All counters cumulative\n * since `createSecretBroker()`; cleared by neither `dispose()` nor\n * `drain()` (so the operator can see what happened pre-shutdown).\n * Added in 0.2.0.\n */\nexport type SecretBrokerMetrics = {\n\t/** `resolve()` calls — including cached hits, misses, and errors. */\n\tresolves: number;\n\t/** `resolve()` calls served from cache (no adapter hit). */\n\tresolveHits: number;\n\t/** `resolve()` calls that hit the adapter (cache miss OR expired). */\n\tresolveMisses: number;\n\t/** `resolve()` calls where the adapter threw. */\n\tresolveErrors: number;\n\t/** Successful `rotate()` calls. */\n\trotates: number;\n\t/** `rotate()` calls where the adapter threw. */\n\trotateErrors: number;\n\t/** `invalidate()` calls (per call, regardless of cache size). */\n\tinvalidations: number;\n\t/** `redact()` calls (whether anything was rewritten or not). */\n\tredactCalls: number;\n\t/**\n\t * Distinct (secret, encoding) pairs that triggered a replacement —\n\t * NOT total occurrences. A `redact()` call that rewrites the same\n\t * key three times in one string bumps this by 1. Useful for\n\t * \"is anything ever actually getting redacted, or are we configured\n\t * for nothing.\"\n\t */\n\tredactionsApplied: number;\n\t/** Subset of `redactionsApplied` for base64 encoding. */\n\tredactionsBase64: number;\n};\n\n/**\n * Thrown by `resolve()` / `rotate()` after `drain()` has been called.\n * Added in 0.2.0.\n */\nexport class BrokerDrainedError extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'[secrets] Broker is draining — resolve/rotate refused. ' +\n\t\t\t\t'Use the broker before the shutdown handler fires.'\n\t\t);\n\t\tthis.name = 'BrokerDrainedError';\n\t}\n}\n\n// -----------------------------------------------------------------------------\n// Fingerprint\n// -----------------------------------------------------------------------------\n\nconst HEX = '0123456789abcdef';\n\nconst sha256Hex = (input: string): string => {\n\t// 2026-era Bun: `crypto.subtle.digest` is the portable path. Synchronous\n\t// path via `Bun.CryptoHasher` is faster but requires Bun globals; we use\n\t// subtle to keep the broker runtime-agnostic at the cost of being async.\n\t// For the `fingerprint(value)` *public* method we want a synchronous\n\t// answer — so we use a tiny in-house sha256. It's slower than the native\n\t// digest but only runs on the secret value (small, ~ < 1KB), once per\n\t// distinct value over the broker's lifetime (memoized in the cache entry).\n\treturn sha256(input);\n};\n\n// Pure JS sha256, NIST FIPS 180-4. Small + dependency-free. Returns lowercase hex.\nconst ROUND_CONSTANTS = new Uint32Array([\n\t0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,\n\t0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n\t0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,\n\t0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n\t0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,\n\t0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n\t0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,\n\t0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n\t0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,\n\t0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n\t0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\nconst sha256 = (input: string): string => {\n\tconst bytes = new TextEncoder().encode(input);\n\tconst bitLength = bytes.length * 8;\n\tconst padLength = ((bytes.length + 9 + 63) & ~63) - bytes.length;\n\tconst padded = new Uint8Array(bytes.length + padLength);\n\tpadded.set(bytes);\n\tpadded[bytes.length] = 0x80;\n\tconst view = new DataView(padded.buffer);\n\tview.setUint32(padded.length - 4, bitLength >>> 0);\n\tview.setUint32(padded.length - 8, Math.floor(bitLength / 0x1_0000_0000));\n\n\tlet h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;\n\tlet h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;\n\tconst w = new Uint32Array(64);\n\tfor (let i = 0; i < padded.length; i += 64) {\n\t\tfor (let t = 0; t < 16; t++) {\n\t\t\tw[t] = view.getUint32(i + t * 4);\n\t\t}\n\t\tfor (let t = 16; t < 64; t++) {\n\t\t\tconst w15 = w[t - 15]!;\n\t\t\tconst w2 = w[t - 2]!;\n\t\t\tconst s0 = ((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3);\n\t\t\tconst s1 = ((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10);\n\t\t\tw[t] = (w[t - 16]! + s0 + w[t - 7]! + s1) >>> 0;\n\t\t}\n\t\tlet a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;\n\t\tfor (let t = 0; t < 64; t++) {\n\t\t\tconst S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n\t\t\tconst ch = (e & f) ^ (~e & g);\n\t\t\tconst T1 = (h + S1 + ch + ROUND_CONSTANTS[t]! + w[t]!) >>> 0;\n\t\t\tconst S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n\t\t\tconst maj = (a & b) ^ (a & c) ^ (b & c);\n\t\t\tconst T2 = (S0 + maj) >>> 0;\n\t\t\th = g;\n\t\t\tg = f;\n\t\t\tf = e;\n\t\t\te = (d + T1) >>> 0;\n\t\t\td = c;\n\t\t\tc = b;\n\t\t\tb = a;\n\t\t\ta = (T1 + T2) >>> 0;\n\t\t}\n\t\th0 = (h0 + a) >>> 0;\n\t\th1 = (h1 + b) >>> 0;\n\t\th2 = (h2 + c) >>> 0;\n\t\th3 = (h3 + d) >>> 0;\n\t\th4 = (h4 + e) >>> 0;\n\t\th5 = (h5 + f) >>> 0;\n\t\th6 = (h6 + g) >>> 0;\n\t\th7 = (h7 + h) >>> 0;\n\t}\n\tconst toHex = (n: number): string => {\n\t\tlet result = '';\n\t\tfor (let i = 7; i >= 0; i--) {\n\t\t\tresult += HEX[(n >>> (i * 4)) & 0xf];\n\t\t}\n\t\treturn result;\n\t};\n\treturn toHex(h0) + toHex(h1) + toHex(h2) + toHex(h3) + toHex(h4) + toHex(h5) + toHex(h6) + toHex(h7);\n};\n\nconst fingerprintOf = (value: string): string => sha256Hex(value).slice(0, 8);\n\n// -----------------------------------------------------------------------------\n// Bundled adapters\n// -----------------------------------------------------------------------------\n\nexport type InMemoryAdapterOptions = {\n\tinitial?: Record<string, string>;\n\t/** Override the rotation strategy. Default = random 32-char base36 string. */\n\trotate?: (name: string, previous: string | null) => string;\n};\n\nconst randomBase36 = (length: number): string => {\n\tlet out = '';\n\twhile (out.length < length) {\n\t\tout += Math.random().toString(36).slice(2);\n\t}\n\treturn out.slice(0, length);\n};\n\nexport const inMemoryAdapter = (\n\toptions: InMemoryAdapterOptions = {},\n): SecretAdapter => {\n\tconst store = new Map<string, string>();\n\tfor (const [k, v] of Object.entries(options.initial ?? {})) store.set(k, v);\n\tconst rotate = options.rotate ?? (() => randomBase36(32));\n\treturn {\n\t\tfetch: async (name) => store.get(name) ?? null,\n\t\tlist: async () => Array.from(store.keys()),\n\t\tput: async (name, value) => { store.set(name, value); },\n\t\tremove: async (name) => { store.delete(name); },\n\t\trotate: async (name) => {\n\t\t\tconst next = rotate(name, store.get(name) ?? null);\n\t\t\tstore.set(name, next);\n\t\t\treturn next;\n\t\t},\n\t};\n};\n\nexport type EnvAdapterOptions = {\n\t/**\n\t * If set, lookups are prefixed before reading from env. e.g.\n\t * `prefix: 'ABS_SECRET_'` and `resolve('STRIPE_KEY')` reads `ABS_SECRET_STRIPE_KEY`.\n\t * Default `''` (no prefix).\n\t */\n\tprefix?: string;\n\t/** The env object to read from. Default `process.env`. */\n\tenv?: Record<string, string | undefined>;\n};\n\nexport const envAdapter = (options: EnvAdapterOptions = {}): SecretAdapter => {\n\tconst prefix = options.prefix ?? '';\n\tconst env = options.env ?? (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {};\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tconst key = `${prefix}${name}`;\n\t\t\tconst value = env[key];\n\t\t\treturn value === undefined ? null : value;\n\t\t},\n\t\tlist: async () => {\n\t\t\tif (!prefix) return Object.keys(env);\n\t\t\tconst matches: string[] = [];\n\t\t\tfor (const key of Object.keys(env)) {\n\t\t\t\tif (key.startsWith(prefix)) matches.push(key.slice(prefix.length));\n\t\t\t}\n\t\t\treturn matches;\n\t\t},\n\t};\n};\n\n/**\n * Compose adapters: `fetch` falls through to the first non-null result;\n * `put` / `rotate` / `remove` go to the first adapter that implements them.\n */\nexport const compositeAdapter = (adapters: SecretAdapter[]): SecretAdapter => {\n\tconst firstWith = <K extends keyof SecretAdapter>(method: K) =>\n\t\tadapters.find((adapter) => adapter[method] !== undefined);\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tfor (const adapter of adapters) {\n\t\t\t\tconst value = await adapter.fetch(name);\n\t\t\t\tif (value !== null) return value;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tlist: async () => {\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const adapter of adapters) {\n\t\t\t\tif (!adapter.list) continue;\n\t\t\t\tfor (const name of await adapter.list()) seen.add(name);\n\t\t\t}\n\t\t\treturn Array.from(seen);\n\t\t},\n\t\tput: async (name, value) => {\n\t\t\tconst target = firstWith('put');\n\t\t\tif (!target?.put) throw new Error('No adapter in the composite supports put()');\n\t\t\tawait target.put(name, value);\n\t\t},\n\t\tremove: async (name) => {\n\t\t\tconst target = firstWith('remove');\n\t\t\tif (!target?.remove) throw new Error('No adapter in the composite supports remove()');\n\t\t\tawait target.remove(name);\n\t\t},\n\t\trotate: async (name) => {\n\t\t\tconst target = firstWith('rotate');\n\t\t\tif (!target?.rotate) throw new Error('No adapter in the composite supports rotate()');\n\t\t\treturn target.rotate(name);\n\t\t},\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// encryptedFileAdapter — durable, AES-256-GCM, committable to private repo\n// -----------------------------------------------------------------------------\n\nconst DEFAULT_PBKDF2_ITERATIONS = 600_000;\nconst ENC_FILE_VERSION = 1;\nconst SALT_BYTES = 16;\nconst IV_BYTES = 12;\nconst KEY_BYTES = 32;\n\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n\tlet bin = '';\n\tfor (const byte of bytes) bin += String.fromCharCode(byte);\n\treturn btoa(bin);\n};\n\nconst base64ToBytes = (b64: string): Uint8Array => {\n\tconst bin = atob(b64);\n\tconst out = new Uint8Array(bin.length);\n\tfor (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);\n\treturn out;\n};\n\ntype EncryptedEntry = {\n\t/** Base64 12-byte IV. */\n\tiv: string;\n\t/** Base64 AES-GCM ciphertext (includes 16-byte tag at end). */\n\tct: string;\n};\n\ntype EncryptedFile = {\n\tversion: 1;\n\t/** Salt is omitted when the master key is supplied as raw bytes. */\n\tkdf?: {\n\t\ttype: 'pbkdf2-sha256';\n\t\titerations: number;\n\t\tsalt: string;\n\t};\n\tvalues: Record<string, EncryptedEntry>;\n};\n\n/** Override for tests; defaults touch disk via `node:fs/promises`. */\nexport type EncryptedFileIO = {\n\treadFile: (path: string) => Promise<string | undefined>;\n\twriteFileAtomic: (path: string, contents: string) => Promise<void>;\n};\n\nexport type EncryptedFileAdapterMasterKey =\n\t| { type: 'passphrase'; passphrase: string }\n\t| { type: 'raw'; bytes: Uint8Array };\n\nexport type EncryptedFileAdapterOptions = {\n\t/** Absolute or relative path to the encrypted JSON file. */\n\tpath: string;\n\t/**\n\t * Master key. Either a `passphrase` (KDF'd via PBKDF2-SHA256 with the\n\t * salt stored in the file) or `raw` 32 bytes (no KDF — pass the key\n\t * directly, useful when sourced from a vendor secret manager).\n\t */\n\tkey: EncryptedFileAdapterMasterKey;\n\t/**\n\t * PBKDF2 iterations when `key.type === 'passphrase'`. Default 600_000\n\t * (OWASP 2025 recommendation for SHA-256). The chosen value is stored\n\t * in the file so future opens use it.\n\t */\n\tpbkdf2Iterations?: number;\n\t/** Override the rotation strategy (matches `inMemoryAdapter`). */\n\trotate?: (name: string, previous: string | null) => string;\n\t/** Override file IO (tests). */\n\tio?: EncryptedFileIO;\n};\n\nconst defaultIo = (): EncryptedFileIO => ({\n\treadFile: async (path) => {\n\t\ttry {\n\t\t\tconst text = await (await import('node:fs/promises')).readFile(\n\t\t\t\tpath,\n\t\t\t\t'utf8'\n\t\t\t);\n\t\t\treturn text;\n\t\t} catch (error) {\n\t\t\tif ((error as { code?: string }).code === 'ENOENT') return undefined;\n\t\t\tthrow error;\n\t\t}\n\t},\n\twriteFileAtomic: async (path, contents) => {\n\t\tconst fs = await import('node:fs/promises');\n\t\tconst tempPath = `${path}.tmp.${process.pid}`;\n\t\tawait fs.writeFile(tempPath, contents, { mode: 0o600 });\n\t\tawait fs.rename(tempPath, path);\n\t}\n});\n\nconst deriveKeyFromPassphrase = async (\n\tpassphrase: string,\n\tsalt: Uint8Array,\n\titerations: number\n): Promise<CryptoKey> => {\n\tconst base = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tnew TextEncoder().encode(passphrase) as BufferSource,\n\t\t'PBKDF2',\n\t\tfalse,\n\t\t['deriveKey']\n\t);\n\treturn crypto.subtle.deriveKey(\n\t\t{\n\t\t\thash: 'SHA-256',\n\t\t\titerations,\n\t\t\tname: 'PBKDF2',\n\t\t\tsalt: salt as BufferSource\n\t\t},\n\t\tbase,\n\t\t{ length: 256, name: 'AES-GCM' },\n\t\tfalse,\n\t\t['encrypt', 'decrypt']\n\t);\n};\n\nconst importRawKey = async (bytes: Uint8Array): Promise<CryptoKey> => {\n\tif (bytes.length !== KEY_BYTES) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] raw key must be ${KEY_BYTES} bytes (got ${bytes.length})`\n\t\t);\n\t}\n\treturn crypto.subtle.importKey(\n\t\t'raw',\n\t\tbytes as BufferSource,\n\t\t{ name: 'AES-GCM' },\n\t\tfalse,\n\t\t['encrypt', 'decrypt']\n\t);\n};\n\n/**\n * Durable secret adapter that stores `name → value` in an encrypted\n * JSON file (AES-256-GCM, per-value random IV). File is safe to commit\n * to a private repo as long as the master key is kept separately\n * (1Password, env var, hardware key, etc.).\n *\n * Two master-key shapes:\n *\n * - `{ type: 'passphrase', passphrase }` — PBKDF2-SHA256 from the\n * passphrase, salt stored in the file. OWASP 2025 default (600k\n * iterations); add a stronger one via `pbkdf2Iterations`.\n * - `{ type: 'raw', bytes }` — 32 raw bytes. No KDF. Useful when the\n * key comes from a vendor secret manager that already gave you\n * random bytes.\n *\n * Caches decrypted values in memory after first read (consistent with\n * the broker's caching layer above it).\n */\nexport const encryptedFileAdapter = (\n\toptions: EncryptedFileAdapterOptions\n): SecretAdapter => {\n\tconst io = options.io ?? defaultIo();\n\tconst iterations = options.pbkdf2Iterations ?? DEFAULT_PBKDF2_ITERATIONS;\n\tconst rotate = options.rotate ?? (() => randomBase36(32));\n\n\tlet cache: Map<string, string> | undefined;\n\tlet derivedKey: CryptoKey | undefined;\n\tlet mutationQueue = Promise.resolve();\n\tlet salt: Uint8Array | undefined;\n\n\tconst mutate = <Result>(operation: () => Promise<Result>) => {\n\t\tconst result = mutationQueue.then(operation, operation);\n\t\tmutationQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t};\n\n\tconst ensureKey = async (): Promise<CryptoKey> => {\n\t\tif (derivedKey !== undefined) return derivedKey;\n\t\tif (options.key.type === 'raw') {\n\t\t\tderivedKey = await importRawKey(options.key.bytes);\n\t\t\treturn derivedKey;\n\t\t}\n\t\tif (salt === undefined) {\n\t\t\tsalt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));\n\t\t}\n\t\tderivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.key.passphrase,\n\t\t\tsalt,\n\t\t\titerations\n\t\t);\n\t\treturn derivedKey;\n\t};\n\n\tconst load = async (): Promise<Map<string, string>> => {\n\t\tif (cache !== undefined) return cache;\n\t\tconst fileText = await io.readFile(options.path);\n\t\tif (fileText === undefined) {\n\t\t\tcache = new Map();\n\t\t\treturn cache;\n\t\t}\n\t\tlet parsed: EncryptedFile;\n\t\ttry {\n\t\t\tparsed = JSON.parse(fileText) as EncryptedFile;\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] could not parse ${options.path}: ${\n\t\t\t\t\t(error as Error).message\n\t\t\t\t}`\n\t\t\t);\n\t\t}\n\t\tif (parsed.version !== ENC_FILE_VERSION) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] unsupported file version ${parsed.version} in ${options.path}`\n\t\t\t);\n\t\t}\n\t\tif (parsed.kdf !== undefined) {\n\t\t\tif (options.key.type !== 'passphrase') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[secrets/encrypted-file] file was written with a passphrase but raw key was supplied`\n\t\t\t\t);\n\t\t\t}\n\t\t\tsalt = base64ToBytes(parsed.kdf.salt);\n\t\t} else if (options.key.type === 'passphrase') {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a raw key but passphrase was supplied`\n\t\t\t);\n\t\t}\n\t\tconst key = await ensureKey();\n\t\tconst decoded = new Map<string, string>();\n\t\tfor (const [name, entry] of Object.entries(parsed.values)) {\n\t\t\ttry {\n\t\t\t\tconst iv = base64ToBytes(entry.iv) as BufferSource;\n\t\t\t\tconst ct = base64ToBytes(entry.ct) as BufferSource;\n\t\t\t\tconst pt = await crypto.subtle.decrypt(\n\t\t\t\t\t{ iv, name: 'AES-GCM' },\n\t\t\t\t\tkey,\n\t\t\t\t\tct\n\t\t\t\t);\n\t\t\t\tdecoded.set(name, new TextDecoder().decode(pt));\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[secrets/encrypted-file] failed to decrypt \"${name}\" in ${options.path} — wrong master key or corrupted file`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcache = decoded;\n\t\treturn cache;\n\t};\n\n\tconst save = async (): Promise<void> => {\n\t\tconst data = cache ?? new Map<string, string>();\n\t\tconst key = await ensureKey();\n\t\tconst values: Record<string, EncryptedEntry> = {};\n\t\tfor (const [name, value] of data) {\n\t\t\tconst iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));\n\t\t\tconst ct = await crypto.subtle.encrypt(\n\t\t\t\t{ iv: iv as BufferSource, name: 'AES-GCM' },\n\t\t\t\tkey,\n\t\t\t\tnew TextEncoder().encode(value) as BufferSource\n\t\t\t);\n\t\t\tvalues[name] = {\n\t\t\t\tct: bytesToBase64(new Uint8Array(ct)),\n\t\t\t\tiv: bytesToBase64(iv)\n\t\t\t};\n\t\t}\n\t\tconst file: EncryptedFile = {\n\t\t\tvalues,\n\t\t\tversion: ENC_FILE_VERSION,\n\t\t\t...(options.key.type === 'passphrase' && salt !== undefined\n\t\t\t\t? {\n\t\t\t\t\t\tkdf: {\n\t\t\t\t\t\t\titerations,\n\t\t\t\t\t\t\tsalt: bytesToBase64(salt),\n\t\t\t\t\t\t\ttype: 'pbkdf2-sha256'\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: {})\n\t\t};\n\t\tawait io.writeFileAtomic(options.path, JSON.stringify(file, null, 2));\n\t};\n\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tconst data = await load();\n\t\t\treturn data.get(name) ?? null;\n\t\t},\n\t\tlist: async () => {\n\t\t\tconst data = await load();\n\t\t\treturn Array.from(data.keys());\n\t\t},\n\t\tput: (name, value) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tdata.set(name, value);\n\t\t\tawait save();\n\t\t}),\n\t\tremove: (name) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tdata.delete(name);\n\t\t\tawait save();\n\t\t}),\n\t\trotate: (name) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tconst previous = data.get(name) ?? null;\n\t\t\tconst next = rotate(name, previous);\n\t\t\tdata.set(name, next);\n\t\t\tawait save();\n\t\t\treturn next;\n\t\t})\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// rotateMasterKey — re-encrypt the file under a new master key\n// -----------------------------------------------------------------------------\n\nexport type RotateMasterKeyOptions = {\n\t/** Path to the encrypted JSON file (must exist). */\n\tpath: string;\n\t/** Master key the file was written with. */\n\toldKey: EncryptedFileAdapterMasterKey;\n\t/** Master key to re-encrypt under. */\n\tnewKey: EncryptedFileAdapterMasterKey;\n\t/**\n\t * PBKDF2 iterations for the new passphrase (when `newKey.type ===\n\t * 'passphrase'`). Default 600_000. Stored in the rewritten file.\n\t */\n\tnewPbkdf2Iterations?: number;\n\t/** Override file IO (tests). */\n\tio?: EncryptedFileIO;\n};\n\n/**\n * Re-encrypt the entire secrets file under a new master key. Reads\n * every value with `oldKey`, writes them back encrypted under\n * `newKey`. Atomic at the file layer (temp + rename); the old file\n * remains intact if any step fails before the final write.\n *\n * Use cases:\n * - master passphrase leak: rotate to a new passphrase\n * - moving from passphrase to raw-bytes (or vice versa) — e.g.\n * graduating from \"operator-typed passphrase\" to \"key sourced\n * from a vendor secret manager\"\n * - periodic master-key rotation as a compliance hygiene measure\n *\n * After this returns, any process still holding the old key\n * will fail to decrypt on next access. Rotate the consumers'\n * master-key references at the same time you call this.\n */\nexport const rotateMasterKey = async (\n\toptions: RotateMasterKeyOptions\n): Promise<void> => {\n\tconst io = options.io ?? defaultIo();\n\tconst newIterations =\n\t\toptions.newPbkdf2Iterations ?? DEFAULT_PBKDF2_ITERATIONS;\n\n\tconst fileText = await io.readFile(options.path);\n\tif (fileText === undefined) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] file ${options.path} does not exist`\n\t\t);\n\t}\n\n\tlet parsed: EncryptedFile;\n\ttry {\n\t\tparsed = JSON.parse(fileText) as EncryptedFile;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] could not parse ${options.path}: ${(error as Error).message}`\n\t\t);\n\t}\n\tif (parsed.version !== ENC_FILE_VERSION) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] unsupported file version ${parsed.version} in ${options.path}`\n\t\t);\n\t}\n\n\tlet oldDerivedKey: CryptoKey;\n\tif (options.oldKey.type === 'raw') {\n\t\tif (parsed.kdf !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a passphrase but old key was supplied as raw`\n\t\t\t);\n\t\t}\n\t\toldDerivedKey = await importRawKey(options.oldKey.bytes);\n\t} else {\n\t\tif (parsed.kdf === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a raw key but old key was supplied as passphrase`\n\t\t\t);\n\t\t}\n\t\tconst oldSalt = base64ToBytes(parsed.kdf.salt);\n\t\toldDerivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.oldKey.passphrase,\n\t\t\toldSalt,\n\t\t\tparsed.kdf.iterations\n\t\t);\n\t}\n\n\tconst decrypted = new Map<string, string>();\n\tfor (const [name, entry] of Object.entries(parsed.values)) {\n\t\ttry {\n\t\t\tconst iv = base64ToBytes(entry.iv) as BufferSource;\n\t\t\tconst ct = base64ToBytes(entry.ct) as BufferSource;\n\t\t\tconst pt = await crypto.subtle.decrypt(\n\t\t\t\t{ iv, name: 'AES-GCM' },\n\t\t\t\toldDerivedKey,\n\t\t\t\tct\n\t\t\t);\n\t\t\tdecrypted.set(name, new TextDecoder().decode(pt));\n\t\t} catch {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] failed to decrypt \"${name}\" with old master key — wrong key or corrupted file`\n\t\t\t);\n\t\t}\n\t}\n\n\tlet newDerivedKey: CryptoKey;\n\tlet newSalt: Uint8Array | undefined;\n\tif (options.newKey.type === 'raw') {\n\t\tnewDerivedKey = await importRawKey(options.newKey.bytes);\n\t} else {\n\t\tnewSalt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));\n\t\tnewDerivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.newKey.passphrase,\n\t\t\tnewSalt,\n\t\t\tnewIterations\n\t\t);\n\t}\n\n\tconst newValues: Record<string, EncryptedEntry> = {};\n\tfor (const [name, value] of decrypted) {\n\t\tconst iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));\n\t\tconst ct = await crypto.subtle.encrypt(\n\t\t\t{ iv: iv as BufferSource, name: 'AES-GCM' },\n\t\t\tnewDerivedKey,\n\t\t\tnew TextEncoder().encode(value) as BufferSource\n\t\t);\n\t\tnewValues[name] = {\n\t\t\tct: bytesToBase64(new Uint8Array(ct)),\n\t\t\tiv: bytesToBase64(iv)\n\t\t};\n\t}\n\n\tconst newFile: EncryptedFile = {\n\t\tvalues: newValues,\n\t\tversion: ENC_FILE_VERSION,\n\t\t...(options.newKey.type === 'passphrase' && newSalt !== undefined\n\t\t\t? {\n\t\t\t\t\tkdf: {\n\t\t\t\t\t\titerations: newIterations,\n\t\t\t\t\t\tsalt: bytesToBase64(newSalt),\n\t\t\t\t\t\ttype: 'pbkdf2-sha256'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t: {})\n\t};\n\n\tawait io.writeFileAtomic(options.path, JSON.stringify(newFile, null, 2));\n};\n\n// -----------------------------------------------------------------------------\n// Broker\n// -----------------------------------------------------------------------------\n\ntype CacheEntry = {\n\tvalue: string;\n\tfingerprint: string;\n\tstoredAt: number;\n};\n\nexport const createSecretBroker = (options: SecretBrokerOptions): SecretBroker => {\n\tconst clock = options.clock ?? Date.now;\n\tconst defaultTtl = options.cacheTtlMs ?? 60_000;\n\tconst ttlOverrides = options.cacheTtlOverrides ?? {};\n\tconst minLen = options.redactionMinLength ?? 8;\n\tconst encodings = options.redactionEncodings ?? ['plain'];\n\tconst audit = options.audit;\n\tconst cache = new Map<string, CacheEntry>();\n\tconst rotationListeners = new Map<string, Set<RotationListener>>();\n\tlet disposed = false;\n\tlet draining = false;\n\t// 0.3.0: OTel tracer (noop when options.tracerProvider unset).\n\tconst tracer = tracerOrNoop(options.tracerProvider, '@absolutejs/secrets');\n\t// 0.2.0: cumulative operator counters. Survive `drain()` and\n\t// `dispose()` so the operator can read final state post-shutdown.\n\tconst counters: SecretBrokerMetrics = {\n\t\tinvalidations: 0,\n\t\tredactCalls: 0,\n\t\tredactionsApplied: 0,\n\t\tredactionsBase64: 0,\n\t\tresolveErrors: 0,\n\t\tresolveHits: 0,\n\t\tresolveMisses: 0,\n\t\tresolves: 0,\n\t\trotateErrors: 0,\n\t\trotates: 0\n\t};\n\n\tconst ttlFor = (name: string): number => ttlOverrides[name] ?? defaultTtl;\n\n\tconst fireRotation = (name: string, value: string, fingerprint: string, at: number) => {\n\t\tconst set = rotationListeners.get(name);\n\t\tif (!set || set.size === 0) return;\n\t\tfor (const listener of set) {\n\t\t\ttry {\n\t\t\t\tconst ret = listener({ at, fingerprint, name, value });\n\t\t\t\tif (ret && typeof (ret as Promise<void>).then === 'function') {\n\t\t\t\t\t(ret as Promise<void>).catch((error) => {\n\t\t\t\t\t\tconsole.error('[secrets] rotation listener rejected:', error);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[secrets] rotation listener threw:', error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst fireAudit = (event: AuditEvent) => {\n\t\tif (!audit) return;\n\t\ttry {\n\t\t\tconst result = audit(event);\n\t\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\t\t(result as Promise<void>).catch((error) => {\n\t\t\t\t\tconsole.error('[secrets] audit hook rejected:', error);\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('[secrets] audit hook threw:', error);\n\t\t}\n\t};\n\n\tconst cacheEntry = (name: string, value: string, now: number): CacheEntry => {\n\t\tconst entry: CacheEntry = {\n\t\t\tfingerprint: fingerprintOf(value),\n\t\t\tstoredAt: now,\n\t\t\tvalue,\n\t\t};\n\t\tcache.set(name, entry);\n\t\treturn entry;\n\t};\n\n\tconst resolve: SecretBroker['resolve'] = async (name) => {\n\t\tif (disposed) return null;\n\t\tif (draining) throw new BrokerDrainedError();\n\t\t// 0.3.0: span the resolve. Attribute carries the secret NAME\n\t\t// (safe) and on cache hit also the FINGERPRINT (also safe —\n\t\t// it's sha256-derived, never the value).\n\t\tconst span = tracer.startSpan('secrets.resolve', {\n\t\t\tattributes: { [ABS_ATTRS.secretName]: name }\n\t\t});\n\t\tcounters.resolves += 1;\n\t\tconst now = clock();\n\t\ttry {\n\t\t\tconst cached = cache.get(name);\n\t\t\tif (cached && now - cached.storedAt < ttlFor(name)) {\n\t\t\t\tcounters.resolveHits += 1;\n\t\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, cached.fingerprint);\n\t\t\t\tspan.setAttribute('secrets.cache', 'hit');\n\t\t\t\tfireAudit({ at: now, event: 'resolve.hit', fingerprint: cached.fingerprint, name });\n\t\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\t\treturn { fingerprint: cached.fingerprint, value: cached.value };\n\t\t\t}\n\t\t\tcounters.resolveMisses += 1;\n\t\t\tspan.setAttribute('secrets.cache', 'miss');\n\t\t\tconst value = await options.adapter.fetch(name);\n\t\t\tif (value === null) {\n\t\t\t\tfireAudit({ at: now, event: 'resolve.miss', name });\n\t\t\t\tcache.delete(name);\n\t\t\t\tspan.setAttribute('secrets.found', false);\n\t\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst entry = cacheEntry(name, value, now);\n\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);\n\t\t\tfireAudit({ at: now, event: 'resolve.miss', fingerprint: entry.fingerprint, name });\n\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\treturn { fingerprint: entry.fingerprint, value: entry.value };\n\t\t} catch (error) {\n\t\t\tcounters.resolveErrors += 1;\n\t\t\tfireAudit({\n\t\t\t\tat: now,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\tevent: 'resolve.error',\n\t\t\t\tname,\n\t\t\t});\n\t\t\tspan.recordException(error);\n\t\t\tspan.setStatus({\n\t\t\t\tcode: 2 /* ERROR */,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tspan.end();\n\t\t}\n\t};\n\n\tconst rotate: SecretBroker['rotate'] = async (name) => {\n\t\tif (disposed) throw new Error('Broker is disposed');\n\t\tif (draining) throw new BrokerDrainedError();\n\t\tif (!options.adapter.rotate) {\n\t\t\tthrow new Error('Adapter does not support rotate()');\n\t\t}\n\t\t// 0.3.0: span the rotation. The pre-rotation fingerprint isn't\n\t\t// known until after the cache lookup is done; attach the new\n\t\t// fingerprint on success.\n\t\tconst span = tracer.startSpan('secrets.rotate', {\n\t\t\tattributes: { [ABS_ATTRS.secretName]: name }\n\t\t});\n\t\ttry {\n\t\t\tconst next = await options.adapter.rotate(name);\n\t\t\tconst now = clock();\n\t\t\tconst entry = cacheEntry(name, next, now);\n\t\t\tcounters.rotates += 1;\n\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);\n\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\tfireAudit({ at: now, event: 'rotate', fingerprint: entry.fingerprint, name });\n\t\t\tfireRotation(name, entry.value, entry.fingerprint, now);\n\t\t\treturn { fingerprint: entry.fingerprint, value: entry.value };\n\t\t} catch (error) {\n\t\t\tcounters.rotateErrors += 1;\n\t\t\tspan.recordException(error);\n\t\t\tspan.setStatus({\n\t\t\t\tcode: 2 /* ERROR */,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tspan.end();\n\t\t}\n\t};\n\n\tconst invalidate: SecretBroker['invalidate'] = (name) => {\n\t\tif (name === undefined) {\n\t\t\tcache.clear();\n\t\t} else {\n\t\t\tcache.delete(name);\n\t\t}\n\t\tcounters.invalidations += 1;\n\t\tfireAudit({ at: clock(), event: 'invalidate', name: name ?? null });\n\t};\n\n\t// Returns every (representation, replacementLabel) pair currently in\n\t// the cache that's worth searching for. Longest-first so a longer\n\t// secret blanks BEFORE one of its substrings would.\n\tconst redactionPairs = (): Array<[string, string]> => {\n\t\tconst pairs: Array<[string, string]> = [];\n\t\tfor (const [name, entry] of cache) {\n\t\t\tif (entry.value.length < minLen) continue;\n\t\t\tfor (const enc of encodings) {\n\t\t\t\tif (enc === 'plain') {\n\t\t\t\t\tpairs.push([entry.value, `[REDACTED:${name}]`]);\n\t\t\t\t} else if (enc === 'base64') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst encoded = btoa(entry.value);\n\t\t\t\t\t\t// Skip if encoding produces a too-short token to be safe.\n\t\t\t\t\t\tif (encoded.length >= minLen) {\n\t\t\t\t\t\t\tpairs.push([encoded, `[REDACTED:${name}:b64]`]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// btoa rejects non-Latin-1; skip silently.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpairs.sort((a, b) => b[0].length - a[0].length);\n\t\treturn pairs;\n\t};\n\n\tconst redact: SecretBroker['redact'] = (text) => {\n\t\tcounters.redactCalls += 1;\n\t\tif (text.length === 0 || cache.size === 0) return text;\n\t\tlet out = text;\n\t\tfor (const [needle, replacement] of redactionPairs()) {\n\t\t\tif (!out.includes(needle)) continue;\n\t\t\tout = out.split(needle).join(replacement);\n\t\t\tcounters.redactionsApplied += 1;\n\t\t\tif (replacement.endsWith(':b64]')) counters.redactionsBase64 += 1;\n\t\t}\n\t\treturn out;\n\t};\n\n\tconst redactStream: SecretBroker['redactStream'] = () => {\n\t\t// Per-chunk algorithm:\n\t\t// 1. Append chunk to buffer.\n\t\t// 2. Redact the WHOLE buffer (complete secrets → labels).\n\t\t// 3. Hold back the last `lookback` chars — they might contain a\n\t\t// partial secret that completes on the next chunk. The next\n\t\t// chunk's redact() will catch it once the full secret arrives.\n\t\t// 4. Emit the safe prefix.\n\t\t// Without step 2 happening BEFORE the split, a secret straddling the\n\t\t// boundary would have its prefix emitted un-redacted before the suffix\n\t\t// even shows up.\n\t\tlet buffer = '';\n\t\tconst maxLen = () =>\n\t\t\tredactionPairs().reduce((max, [needle]) => Math.max(max, needle.length), 0);\n\t\treturn new TransformStream<string, string>({\n\t\t\ttransform: (chunk, controller) => {\n\t\t\t\tbuffer += chunk;\n\t\t\t\tconst lookback = maxLen();\n\t\t\t\tconst reduced = redact(buffer);\n\t\t\t\tif (reduced.length <= lookback) {\n\t\t\t\t\tbuffer = reduced;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst safe = reduced.slice(0, reduced.length - lookback);\n\t\t\t\tbuffer = reduced.slice(reduced.length - lookback);\n\t\t\t\tif (safe.length > 0) controller.enqueue(safe);\n\t\t\t},\n\t\t\tflush: (controller) => {\n\t\t\t\tif (buffer.length === 0) return;\n\t\t\t\tcontroller.enqueue(redact(buffer));\n\t\t\t\tbuffer = '';\n\t\t\t},\n\t\t});\n\t};\n\n\tconst onRotate: SecretBroker['onRotate'] = (name, listener) => {\n\t\tlet set = rotationListeners.get(name);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\trotationListeners.set(name, set);\n\t\t}\n\t\tset.add(listener);\n\t\treturn () => {\n\t\t\tconst current = rotationListeners.get(name);\n\t\t\tif (!current) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) rotationListeners.delete(name);\n\t\t};\n\t};\n\n\treturn {\n\t\tdispose: () => {\n\t\t\tdisposed = true;\n\t\t\tcache.clear();\n\t\t\trotationListeners.clear();\n\t\t},\n\t\tdrain: () => {\n\t\t\tdraining = true;\n\t\t},\n\t\tfingerprint: fingerprintOf,\n\t\tinvalidate,\n\t\tmetrics: () => ({ ...counters }),\n\t\tonRotate,\n\t\tredact,\n\t\tredactStream,\n\t\tresolve,\n\t\trotate,\n\t};\n};\n"
|
|
8
|
+
"import type { CredentialGrant, CredentialGrantStore, PendingCredentialOperation } from \"./operations\";\n\nexport type SecretsSqlResult<Row> = { rowCount: number; rows: ReadonlyArray<Row> };\nexport type SecretsSqlClient = {\n query: <Row = Record<string, unknown>>(sql: string, parameters?: ReadonlyArray<unknown>) => Promise<SecretsSqlResult<Row>>;\n};\n\nconst namespaceOf = (namespace: string) => {\n if (!/^[a-z_][a-z0-9_]*$/.test(namespace))\n throw new Error(\"Secrets PostgreSQL namespace must be a simple identifier\");\n return namespace;\n};\n\nexport const credentialGrantsPostgresSchemaSql = (namespace = \"secrets\") => {\n const ns = namespaceOf(namespace);\n return `CREATE SCHEMA IF NOT EXISTS ${ns};\nCREATE TABLE IF NOT EXISTS ${ns}.credential_grants (\n grant_id text PRIMARY KEY, agent_id text NOT NULL, user_id text NOT NULL,\n provider text NOT NULL, expires_at bigint NOT NULL, maximum_uses integer NOT NULL CHECK (maximum_uses > 0),\n used integer NOT NULL DEFAULT 0 CHECK (used >= 0 AND used <= maximum_uses), data jsonb NOT NULL\n);\nCREATE INDEX IF NOT EXISTS credential_grants_agent_idx ON ${ns}.credential_grants (agent_id, expires_at);\nCREATE TABLE IF NOT EXISTS ${ns}.pending_operations (\n action_id text PRIMARY KEY, grant_id text NOT NULL REFERENCES ${ns}.credential_grants(grant_id) ON DELETE CASCADE,\n created_at timestamptz NOT NULL DEFAULT now(), data jsonb NOT NULL\n);`;\n};\n\ntype DataRow<Value> = { data: Value };\n\nexport const createPostgresCredentialGrantStore = ({ client, namespace = \"secrets\" }: { client: SecretsSqlClient; namespace?: string }): CredentialGrantStore => {\n const ns = namespaceOf(namespace);\n return {\n consume: async (grantId, now) => {\n const result = await client.query<DataRow<CredentialGrant>>(\n `UPDATE ${ns}.credential_grants SET used = used + 1, data = jsonb_set(data, '{used}', to_jsonb(used + 1), true) WHERE grant_id = $1 AND expires_at > $2 AND used < maximum_uses RETURNING data`,\n [grantId, now],\n );\n return result.rows[0]?.data;\n },\n get: async (grantId) =>\n (await client.query<DataRow<CredentialGrant>>(`SELECT data FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rows[0]?.data,\n getPending: async (actionId) =>\n (await client.query<DataRow<PendingCredentialOperation>>(`SELECT data FROM ${ns}.pending_operations WHERE action_id = $1`, [actionId])).rows[0]?.data,\n put: async (grant) => {\n if (grant.maximumUses < 1 || grant.used < 0 || grant.used > grant.maximumUses)\n throw new Error(\"Invalid credential grant usage\");\n await client.query(\n `INSERT INTO ${ns}.credential_grants (grant_id, agent_id, user_id, provider, expires_at, maximum_uses, used, data) VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb) ON CONFLICT (grant_id) DO UPDATE SET expires_at=EXCLUDED.expires_at, maximum_uses=EXCLUDED.maximum_uses, used=EXCLUDED.used, data=EXCLUDED.data`,\n [grant.grantId, grant.agentId, grant.userId, grant.provider, grant.expiresAt, grant.maximumUses, grant.used, JSON.stringify(grant)],\n );\n },\n putPending: async (pending) => {\n await client.query(\n `INSERT INTO ${ns}.pending_operations (action_id, grant_id, data) VALUES ($1,$2,$3::jsonb) ON CONFLICT (action_id) DO UPDATE SET data=EXCLUDED.data`,\n [pending.actionId, pending.input.grantId, JSON.stringify(pending)],\n );\n },\n revoke: async (grantId) =>\n (await client.query(`DELETE FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rowCount === 1,\n };\n};\n",
|
|
9
|
+
"/**\n * @absolutejs/secrets — host-side secret broker for multi-tenant Bun\n * runtimes.\n *\n * Three responsibilities, kept narrow on purpose:\n *\n * 1. **Resolve.** A pluggable adapter fetches a secret by name. The broker\n * caches the answer, hands the caller back a `{ value, fingerprint }`\n * pair (fingerprint is a sha256 prefix safe to put in logs), and fires\n * an audit event for every lookup.\n * 2. **Redact.** Walks every known cached secret out of an arbitrary string\n * before it leaves the host (e.g. an error message that contains the\n * leaked API key the host call just made). The replacement is\n * `[REDACTED:name]`; matches shorter than `redactionMinLength` are\n * skipped to avoid blanking coincidental short tokens.\n * 3. **Rotate.** Delegates to `adapter.rotate?(name)` if the adapter\n * supports it, invalidates the cache entry. Caller is expected to\n * re-distribute to dependent surfaces.\n *\n * v0.0.1 ships three adapters: `inMemoryAdapter`, `envAdapter`,\n * `compositeAdapter`. AWS Secrets Manager / Vault / Doppler / Infisical\n * adapters ship later as siblings.\n *\n * The broker is bun/elysia-agnostic — same posture as router + meter.\n */\n\nimport {\n\tABS_ATTRS,\n\ttracerOrNoop,\n\ttype TracerProvider\n} from '@absolutejs/telemetry';\n\nexport {\n\tcreateCredentialOperationBroker,\n\tcreateMemoryCredentialGrantStore,\n\ttype CredentialGrant,\n\ttype CredentialGrantStore,\n\ttype CredentialOperationBroker,\n\ttype CredentialOperationBrokerOptions,\n\ttype CredentialOperationContext,\n\ttype CredentialOperationEvent,\n\ttype CredentialOperationInput,\n\ttype CredentialOperationResult,\n\ttype CredentialProvider,\n\ttype PendingCredentialOperation\n} from './operations';\nexport {\n\tcreatePostgresCredentialGrantStore,\n\tcredentialGrantsPostgresSchemaSql,\n\ttype SecretsSqlClient,\n\ttype SecretsSqlResult\n} from './postgres';\n\nexport type SecretValue = {\n\t/** The plaintext secret. Treat as poison: never log, never serialize. */\n\tvalue: string;\n\t/**\n\t * Short sha256-derived id (first 8 hex chars). Stable across calls for\n\t * the same value; safe to print in logs and traces. Useful for \"which\n\t * version of the key did this request use?\" diagnostics without leaking.\n\t */\n\tfingerprint: string;\n};\n\nexport type SecretAdapter = {\n\t/** Return the plaintext value for a name, or `null` if not stored here. */\n\tfetch: (name: string) => Promise<string | null>;\n\t/** Write a value. Optional — adapters may be read-only. */\n\tput?: (name: string, value: string) => Promise<void>;\n\t/** Delete a value. Optional. */\n\tremove?: (name: string) => Promise<void>;\n\t/** Rotate a value; return the NEW plaintext. Optional. */\n\trotate?: (name: string) => Promise<string>;\n\t/** Enumerate names. Optional; default omitted to avoid leaking the index. */\n\tlist?: () => Promise<string[]>;\n};\n\nexport type AuditEvent =\n\t| { event: 'resolve.hit'; name: string; fingerprint: string; at: number }\n\t| { event: 'resolve.miss'; name: string; fingerprint?: string; at: number }\n\t| { event: 'resolve.error'; name: string; error: string; at: number }\n\t| { event: 'rotate'; name: string; fingerprint: string; at: number }\n\t| { event: 'invalidate'; name: string | null; at: number };\n\nexport type AuditHook = (event: AuditEvent) => void | Promise<void>;\n\nexport type RedactionEncoding = 'plain' | 'base64';\n\nexport type SecretBrokerOptions = {\n\t/** The adapter the broker delegates fetch / rotate / put to. */\n\tadapter: SecretAdapter;\n\t/** Audit hook fired on every resolve / rotate / invalidate. */\n\taudit?: AuditHook;\n\t/**\n\t * How long a cached secret stays fresh, in ms. After this, the next\n\t * resolve re-hits the adapter. Default 60_000 (1 minute). Set to\n\t * `Infinity` to disable TTL — only `rotate` / `invalidate` evict.\n\t */\n\tcacheTtlMs?: number;\n\t/**\n\t * Per-name TTL overrides. The override wins over `cacheTtlMs`. Use\n\t * a short TTL for high-blast-radius secrets (admin tokens, signing\n\t * keys) so a compromised value's lifetime is bounded by the override,\n\t * not the global default.\n\t */\n\tcacheTtlOverrides?: Record<string, number>;\n\t/**\n\t * Minimum length a cached value must have before `redact` will rewrite\n\t * occurrences of it in arbitrary text. Default 8 — short values risk\n\t * blanking out coincidental matches (e.g. a short password \"abc1\"\n\t * appearing as a substring of unrelated text).\n\t */\n\tredactionMinLength?: number;\n\t/**\n\t * Encodings to redact alongside the plaintext value. Default `['plain']`.\n\t * Add `'base64'` to also catch base64-encoded forms — useful when\n\t * secrets end up inside JWTs, cookies, or any payload that base64-wraps\n\t * a credential.\n\t */\n\tredactionEncodings?: RedactionEncoding[];\n\t/** Override `Date.now` for tests. */\n\tclock?: () => number;\n\t/**\n\t * Optional OpenTelemetry tracer provider. When set, `broker.resolve`\n\t * and `broker.rotate` are wrapped in `secrets.resolve` /\n\t * `secrets.rotate` spans with `abs.secret.name` +\n\t * `abs.secret.fingerprint` attributes. `broker.redact` is NOT\n\t * traced — it's called per log line, which would explode span\n\t * volume. When omitted, all tracing is a zero-allocation noop.\n\t * Added in 0.3.0.\n\t */\n\ttracerProvider?: TracerProvider;\n};\n\n/** Listener registered via {@link SecretBroker.onRotate}. */\nexport type RotationListener = (event: {\n\tname: string;\n\tvalue: string;\n\tfingerprint: string;\n\tat: number;\n}) => void | Promise<void>;\n\nexport type SecretBroker = {\n\t/**\n\t * Resolve a secret by name. Returns `null` if the adapter reports\n\t * no value. Caches the answer for `cacheTtlMs`.\n\t */\n\tresolve: (name: string) => Promise<SecretValue | null>;\n\t/**\n\t * Returns the fingerprint of a value WITHOUT touching the adapter.\n\t * Useful for hashing a value the caller already has — e.g. a webhook\n\t * payload — to compare against an audit log.\n\t */\n\tfingerprint: (value: string) => string;\n\t/**\n\t * Replace every cached secret value found in `text` with\n\t * `[REDACTED:name]`. Returns the rewritten text. Subjects shorter than\n\t * `redactionMinLength` are skipped.\n\t */\n\tredact: (text: string) => string;\n\t/**\n\t * Streaming variant of {@link redact}. Returns a `TransformStream`\n\t * that catches secrets even when they're split across chunks (a chunk\n\t * boundary in the middle of `sk_live_abc...` would otherwise miss). The\n\t * stream keeps a lookback buffer the size of the longest cached secret;\n\t * once the buffer outgrows that, the safe-region prefix is emitted.\n\t *\n\t * Use this on `process.stdout` / `process.stderr` / a tenant log forwarder\n\t * so plaintext secrets never reach the sink.\n\t */\n\tredactStream: () => TransformStream<string, string>;\n\t/**\n\t * Rotate a secret. Calls `adapter.rotate(name)`, invalidates the cache,\n\t * returns the new `{ value, fingerprint }`. Throws if the adapter does\n\t * not support rotation. Fires every `onRotate` listener registered for\n\t * this name.\n\t */\n\trotate: (name: string) => Promise<SecretValue>;\n\t/**\n\t * Subscribe to rotation events for a specific name. Listener fires\n\t * AFTER the new value is in the cache. Returns an unsubscribe handle.\n\t * Use this for long-lived connections (DB clients, AI provider SDKs)\n\t * that need to swap credentials in-place when rotation lands.\n\t */\n\tonRotate: (name: string, listener: RotationListener) => () => void;\n\t/**\n\t * Invalidate one cache entry, or the whole cache when `name` is omitted.\n\t */\n\tinvalidate: (name?: string) => void;\n\t/** Tear down the broker — clears the cache; further resolves still hit the adapter. */\n\tdispose: () => void;\n\t/**\n\t * Operator-shaped cumulative counters since `createSecretBroker()`.\n\t * Scrape on a 30s interval for tier monitoring + rotation cadence.\n\t * Added in 0.2.0.\n\t */\n\tmetrics: () => SecretBrokerMetrics;\n\t/**\n\t * Refuse new `resolve()` / `rotate()` calls (they reject with\n\t * `BrokerDrainedError`); in-flight adapter calls keep running. Use\n\t * during graceful shutdown so a tenant whose process is about to\n\t * stop doesn't issue a fresh fetch against the secret store mid-\n\t * teardown. Symmetric with `runtime.drain()` / `queue.drain()`.\n\t * Added in 0.2.0.\n\t */\n\tdrain: () => void;\n};\n\n/**\n * Returned by {@link SecretBroker.metrics}. All counters cumulative\n * since `createSecretBroker()`; cleared by neither `dispose()` nor\n * `drain()` (so the operator can see what happened pre-shutdown).\n * Added in 0.2.0.\n */\nexport type SecretBrokerMetrics = {\n\t/** `resolve()` calls — including cached hits, misses, and errors. */\n\tresolves: number;\n\t/** `resolve()` calls served from cache (no adapter hit). */\n\tresolveHits: number;\n\t/** `resolve()` calls that hit the adapter (cache miss OR expired). */\n\tresolveMisses: number;\n\t/** `resolve()` calls where the adapter threw. */\n\tresolveErrors: number;\n\t/** Successful `rotate()` calls. */\n\trotates: number;\n\t/** `rotate()` calls where the adapter threw. */\n\trotateErrors: number;\n\t/** `invalidate()` calls (per call, regardless of cache size). */\n\tinvalidations: number;\n\t/** `redact()` calls (whether anything was rewritten or not). */\n\tredactCalls: number;\n\t/**\n\t * Distinct (secret, encoding) pairs that triggered a replacement —\n\t * NOT total occurrences. A `redact()` call that rewrites the same\n\t * key three times in one string bumps this by 1. Useful for\n\t * \"is anything ever actually getting redacted, or are we configured\n\t * for nothing.\"\n\t */\n\tredactionsApplied: number;\n\t/** Subset of `redactionsApplied` for base64 encoding. */\n\tredactionsBase64: number;\n};\n\n/**\n * Thrown by `resolve()` / `rotate()` after `drain()` has been called.\n * Added in 0.2.0.\n */\nexport class BrokerDrainedError extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'[secrets] Broker is draining — resolve/rotate refused. ' +\n\t\t\t\t'Use the broker before the shutdown handler fires.'\n\t\t);\n\t\tthis.name = 'BrokerDrainedError';\n\t}\n}\n\n// -----------------------------------------------------------------------------\n// Fingerprint\n// -----------------------------------------------------------------------------\n\nconst HEX = '0123456789abcdef';\n\nconst sha256Hex = (input: string): string => {\n\t// 2026-era Bun: `crypto.subtle.digest` is the portable path. Synchronous\n\t// path via `Bun.CryptoHasher` is faster but requires Bun globals; we use\n\t// subtle to keep the broker runtime-agnostic at the cost of being async.\n\t// For the `fingerprint(value)` *public* method we want a synchronous\n\t// answer — so we use a tiny in-house sha256. It's slower than the native\n\t// digest but only runs on the secret value (small, ~ < 1KB), once per\n\t// distinct value over the broker's lifetime (memoized in the cache entry).\n\treturn sha256(input);\n};\n\n// Pure JS sha256, NIST FIPS 180-4. Small + dependency-free. Returns lowercase hex.\nconst ROUND_CONSTANTS = new Uint32Array([\n\t0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,\n\t0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n\t0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,\n\t0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n\t0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,\n\t0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n\t0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,\n\t0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n\t0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,\n\t0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n\t0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\nconst sha256 = (input: string): string => {\n\tconst bytes = new TextEncoder().encode(input);\n\tconst bitLength = bytes.length * 8;\n\tconst padLength = ((bytes.length + 9 + 63) & ~63) - bytes.length;\n\tconst padded = new Uint8Array(bytes.length + padLength);\n\tpadded.set(bytes);\n\tpadded[bytes.length] = 0x80;\n\tconst view = new DataView(padded.buffer);\n\tview.setUint32(padded.length - 4, bitLength >>> 0);\n\tview.setUint32(padded.length - 8, Math.floor(bitLength / 0x1_0000_0000));\n\n\tlet h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;\n\tlet h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;\n\tconst w = new Uint32Array(64);\n\tfor (let i = 0; i < padded.length; i += 64) {\n\t\tfor (let t = 0; t < 16; t++) {\n\t\t\tw[t] = view.getUint32(i + t * 4);\n\t\t}\n\t\tfor (let t = 16; t < 64; t++) {\n\t\t\tconst w15 = w[t - 15]!;\n\t\t\tconst w2 = w[t - 2]!;\n\t\t\tconst s0 = ((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3);\n\t\t\tconst s1 = ((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10);\n\t\t\tw[t] = (w[t - 16]! + s0 + w[t - 7]! + s1) >>> 0;\n\t\t}\n\t\tlet a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;\n\t\tfor (let t = 0; t < 64; t++) {\n\t\t\tconst S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n\t\t\tconst ch = (e & f) ^ (~e & g);\n\t\t\tconst T1 = (h + S1 + ch + ROUND_CONSTANTS[t]! + w[t]!) >>> 0;\n\t\t\tconst S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n\t\t\tconst maj = (a & b) ^ (a & c) ^ (b & c);\n\t\t\tconst T2 = (S0 + maj) >>> 0;\n\t\t\th = g;\n\t\t\tg = f;\n\t\t\tf = e;\n\t\t\te = (d + T1) >>> 0;\n\t\t\td = c;\n\t\t\tc = b;\n\t\t\tb = a;\n\t\t\ta = (T1 + T2) >>> 0;\n\t\t}\n\t\th0 = (h0 + a) >>> 0;\n\t\th1 = (h1 + b) >>> 0;\n\t\th2 = (h2 + c) >>> 0;\n\t\th3 = (h3 + d) >>> 0;\n\t\th4 = (h4 + e) >>> 0;\n\t\th5 = (h5 + f) >>> 0;\n\t\th6 = (h6 + g) >>> 0;\n\t\th7 = (h7 + h) >>> 0;\n\t}\n\tconst toHex = (n: number): string => {\n\t\tlet result = '';\n\t\tfor (let i = 7; i >= 0; i--) {\n\t\t\tresult += HEX[(n >>> (i * 4)) & 0xf];\n\t\t}\n\t\treturn result;\n\t};\n\treturn toHex(h0) + toHex(h1) + toHex(h2) + toHex(h3) + toHex(h4) + toHex(h5) + toHex(h6) + toHex(h7);\n};\n\nconst fingerprintOf = (value: string): string => sha256Hex(value).slice(0, 8);\n\n// -----------------------------------------------------------------------------\n// Bundled adapters\n// -----------------------------------------------------------------------------\n\nexport type InMemoryAdapterOptions = {\n\tinitial?: Record<string, string>;\n\t/** Override the rotation strategy. Default = random 32-char base36 string. */\n\trotate?: (name: string, previous: string | null) => string;\n};\n\nconst randomBase36 = (length: number): string => {\n\tlet out = '';\n\twhile (out.length < length) {\n\t\tout += Math.random().toString(36).slice(2);\n\t}\n\treturn out.slice(0, length);\n};\n\nexport const inMemoryAdapter = (\n\toptions: InMemoryAdapterOptions = {},\n): SecretAdapter => {\n\tconst store = new Map<string, string>();\n\tfor (const [k, v] of Object.entries(options.initial ?? {})) store.set(k, v);\n\tconst rotate = options.rotate ?? (() => randomBase36(32));\n\treturn {\n\t\tfetch: async (name) => store.get(name) ?? null,\n\t\tlist: async () => Array.from(store.keys()),\n\t\tput: async (name, value) => { store.set(name, value); },\n\t\tremove: async (name) => { store.delete(name); },\n\t\trotate: async (name) => {\n\t\t\tconst next = rotate(name, store.get(name) ?? null);\n\t\t\tstore.set(name, next);\n\t\t\treturn next;\n\t\t},\n\t};\n};\n\nexport type EnvAdapterOptions = {\n\t/**\n\t * If set, lookups are prefixed before reading from env. e.g.\n\t * `prefix: 'ABS_SECRET_'` and `resolve('STRIPE_KEY')` reads `ABS_SECRET_STRIPE_KEY`.\n\t * Default `''` (no prefix).\n\t */\n\tprefix?: string;\n\t/** The env object to read from. Default `process.env`. */\n\tenv?: Record<string, string | undefined>;\n};\n\nexport const envAdapter = (options: EnvAdapterOptions = {}): SecretAdapter => {\n\tconst prefix = options.prefix ?? '';\n\tconst env = options.env ?? (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {};\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tconst key = `${prefix}${name}`;\n\t\t\tconst value = env[key];\n\t\t\treturn value === undefined ? null : value;\n\t\t},\n\t\tlist: async () => {\n\t\t\tif (!prefix) return Object.keys(env);\n\t\t\tconst matches: string[] = [];\n\t\t\tfor (const key of Object.keys(env)) {\n\t\t\t\tif (key.startsWith(prefix)) matches.push(key.slice(prefix.length));\n\t\t\t}\n\t\t\treturn matches;\n\t\t},\n\t};\n};\n\n/**\n * Compose adapters: `fetch` falls through to the first non-null result;\n * `put` / `rotate` / `remove` go to the first adapter that implements them.\n */\nexport const compositeAdapter = (adapters: SecretAdapter[]): SecretAdapter => {\n\tconst firstWith = <K extends keyof SecretAdapter>(method: K) =>\n\t\tadapters.find((adapter) => adapter[method] !== undefined);\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tfor (const adapter of adapters) {\n\t\t\t\tconst value = await adapter.fetch(name);\n\t\t\t\tif (value !== null) return value;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tlist: async () => {\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const adapter of adapters) {\n\t\t\t\tif (!adapter.list) continue;\n\t\t\t\tfor (const name of await adapter.list()) seen.add(name);\n\t\t\t}\n\t\t\treturn Array.from(seen);\n\t\t},\n\t\tput: async (name, value) => {\n\t\t\tconst target = firstWith('put');\n\t\t\tif (!target?.put) throw new Error('No adapter in the composite supports put()');\n\t\t\tawait target.put(name, value);\n\t\t},\n\t\tremove: async (name) => {\n\t\t\tconst target = firstWith('remove');\n\t\t\tif (!target?.remove) throw new Error('No adapter in the composite supports remove()');\n\t\t\tawait target.remove(name);\n\t\t},\n\t\trotate: async (name) => {\n\t\t\tconst target = firstWith('rotate');\n\t\t\tif (!target?.rotate) throw new Error('No adapter in the composite supports rotate()');\n\t\t\treturn target.rotate(name);\n\t\t},\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// encryptedFileAdapter — durable, AES-256-GCM, committable to private repo\n// -----------------------------------------------------------------------------\n\nconst DEFAULT_PBKDF2_ITERATIONS = 600_000;\nconst ENC_FILE_VERSION = 1;\nconst SALT_BYTES = 16;\nconst IV_BYTES = 12;\nconst KEY_BYTES = 32;\n\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n\tlet bin = '';\n\tfor (const byte of bytes) bin += String.fromCharCode(byte);\n\treturn btoa(bin);\n};\n\nconst base64ToBytes = (b64: string): Uint8Array => {\n\tconst bin = atob(b64);\n\tconst out = new Uint8Array(bin.length);\n\tfor (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);\n\treturn out;\n};\n\ntype EncryptedEntry = {\n\t/** Base64 12-byte IV. */\n\tiv: string;\n\t/** Base64 AES-GCM ciphertext (includes 16-byte tag at end). */\n\tct: string;\n};\n\ntype EncryptedFile = {\n\tversion: 1;\n\t/** Salt is omitted when the master key is supplied as raw bytes. */\n\tkdf?: {\n\t\ttype: 'pbkdf2-sha256';\n\t\titerations: number;\n\t\tsalt: string;\n\t};\n\tvalues: Record<string, EncryptedEntry>;\n};\n\n/** Override for tests; defaults touch disk via `node:fs/promises`. */\nexport type EncryptedFileIO = {\n\treadFile: (path: string) => Promise<string | undefined>;\n\twriteFileAtomic: (path: string, contents: string) => Promise<void>;\n};\n\nexport type EncryptedFileAdapterMasterKey =\n\t| { type: 'passphrase'; passphrase: string }\n\t| { type: 'raw'; bytes: Uint8Array };\n\nexport type EncryptedFileAdapterOptions = {\n\t/** Absolute or relative path to the encrypted JSON file. */\n\tpath: string;\n\t/**\n\t * Master key. Either a `passphrase` (KDF'd via PBKDF2-SHA256 with the\n\t * salt stored in the file) or `raw` 32 bytes (no KDF — pass the key\n\t * directly, useful when sourced from a vendor secret manager).\n\t */\n\tkey: EncryptedFileAdapterMasterKey;\n\t/**\n\t * PBKDF2 iterations when `key.type === 'passphrase'`. Default 600_000\n\t * (OWASP 2025 recommendation for SHA-256). The chosen value is stored\n\t * in the file so future opens use it.\n\t */\n\tpbkdf2Iterations?: number;\n\t/** Override the rotation strategy (matches `inMemoryAdapter`). */\n\trotate?: (name: string, previous: string | null) => string;\n\t/** Override file IO (tests). */\n\tio?: EncryptedFileIO;\n};\n\nconst defaultIo = (): EncryptedFileIO => ({\n\treadFile: async (path) => {\n\t\ttry {\n\t\t\tconst text = await (await import('node:fs/promises')).readFile(\n\t\t\t\tpath,\n\t\t\t\t'utf8'\n\t\t\t);\n\t\t\treturn text;\n\t\t} catch (error) {\n\t\t\tif ((error as { code?: string }).code === 'ENOENT') return undefined;\n\t\t\tthrow error;\n\t\t}\n\t},\n\twriteFileAtomic: async (path, contents) => {\n\t\tconst fs = await import('node:fs/promises');\n\t\tconst tempPath = `${path}.tmp.${process.pid}`;\n\t\tawait fs.writeFile(tempPath, contents, { mode: 0o600 });\n\t\tawait fs.rename(tempPath, path);\n\t}\n});\n\nconst deriveKeyFromPassphrase = async (\n\tpassphrase: string,\n\tsalt: Uint8Array,\n\titerations: number\n): Promise<CryptoKey> => {\n\tconst base = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tnew TextEncoder().encode(passphrase) as BufferSource,\n\t\t'PBKDF2',\n\t\tfalse,\n\t\t['deriveKey']\n\t);\n\treturn crypto.subtle.deriveKey(\n\t\t{\n\t\t\thash: 'SHA-256',\n\t\t\titerations,\n\t\t\tname: 'PBKDF2',\n\t\t\tsalt: salt as BufferSource\n\t\t},\n\t\tbase,\n\t\t{ length: 256, name: 'AES-GCM' },\n\t\tfalse,\n\t\t['encrypt', 'decrypt']\n\t);\n};\n\nconst importRawKey = async (bytes: Uint8Array): Promise<CryptoKey> => {\n\tif (bytes.length !== KEY_BYTES) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] raw key must be ${KEY_BYTES} bytes (got ${bytes.length})`\n\t\t);\n\t}\n\treturn crypto.subtle.importKey(\n\t\t'raw',\n\t\tbytes as BufferSource,\n\t\t{ name: 'AES-GCM' },\n\t\tfalse,\n\t\t['encrypt', 'decrypt']\n\t);\n};\n\n/**\n * Durable secret adapter that stores `name → value` in an encrypted\n * JSON file (AES-256-GCM, per-value random IV). File is safe to commit\n * to a private repo as long as the master key is kept separately\n * (1Password, env var, hardware key, etc.).\n *\n * Two master-key shapes:\n *\n * - `{ type: 'passphrase', passphrase }` — PBKDF2-SHA256 from the\n * passphrase, salt stored in the file. OWASP 2025 default (600k\n * iterations); add a stronger one via `pbkdf2Iterations`.\n * - `{ type: 'raw', bytes }` — 32 raw bytes. No KDF. Useful when the\n * key comes from a vendor secret manager that already gave you\n * random bytes.\n *\n * Caches decrypted values in memory after first read (consistent with\n * the broker's caching layer above it).\n */\nexport const encryptedFileAdapter = (\n\toptions: EncryptedFileAdapterOptions\n): SecretAdapter => {\n\tconst io = options.io ?? defaultIo();\n\tconst iterations = options.pbkdf2Iterations ?? DEFAULT_PBKDF2_ITERATIONS;\n\tconst rotate = options.rotate ?? (() => randomBase36(32));\n\n\tlet cache: Map<string, string> | undefined;\n\tlet derivedKey: CryptoKey | undefined;\n\tlet mutationQueue = Promise.resolve();\n\tlet salt: Uint8Array | undefined;\n\n\tconst mutate = <Result>(operation: () => Promise<Result>) => {\n\t\tconst result = mutationQueue.then(operation, operation);\n\t\tmutationQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t};\n\n\tconst ensureKey = async (): Promise<CryptoKey> => {\n\t\tif (derivedKey !== undefined) return derivedKey;\n\t\tif (options.key.type === 'raw') {\n\t\t\tderivedKey = await importRawKey(options.key.bytes);\n\t\t\treturn derivedKey;\n\t\t}\n\t\tif (salt === undefined) {\n\t\t\tsalt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));\n\t\t}\n\t\tderivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.key.passphrase,\n\t\t\tsalt,\n\t\t\titerations\n\t\t);\n\t\treturn derivedKey;\n\t};\n\n\tconst load = async (): Promise<Map<string, string>> => {\n\t\tif (cache !== undefined) return cache;\n\t\tconst fileText = await io.readFile(options.path);\n\t\tif (fileText === undefined) {\n\t\t\tcache = new Map();\n\t\t\treturn cache;\n\t\t}\n\t\tlet parsed: EncryptedFile;\n\t\ttry {\n\t\t\tparsed = JSON.parse(fileText) as EncryptedFile;\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] could not parse ${options.path}: ${\n\t\t\t\t\t(error as Error).message\n\t\t\t\t}`\n\t\t\t);\n\t\t}\n\t\tif (parsed.version !== ENC_FILE_VERSION) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] unsupported file version ${parsed.version} in ${options.path}`\n\t\t\t);\n\t\t}\n\t\tif (parsed.kdf !== undefined) {\n\t\t\tif (options.key.type !== 'passphrase') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[secrets/encrypted-file] file was written with a passphrase but raw key was supplied`\n\t\t\t\t);\n\t\t\t}\n\t\t\tsalt = base64ToBytes(parsed.kdf.salt);\n\t\t} else if (options.key.type === 'passphrase') {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a raw key but passphrase was supplied`\n\t\t\t);\n\t\t}\n\t\tconst key = await ensureKey();\n\t\tconst decoded = new Map<string, string>();\n\t\tfor (const [name, entry] of Object.entries(parsed.values)) {\n\t\t\ttry {\n\t\t\t\tconst iv = base64ToBytes(entry.iv) as BufferSource;\n\t\t\t\tconst ct = base64ToBytes(entry.ct) as BufferSource;\n\t\t\t\tconst pt = await crypto.subtle.decrypt(\n\t\t\t\t\t{ iv, name: 'AES-GCM' },\n\t\t\t\t\tkey,\n\t\t\t\t\tct\n\t\t\t\t);\n\t\t\t\tdecoded.set(name, new TextDecoder().decode(pt));\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[secrets/encrypted-file] failed to decrypt \"${name}\" in ${options.path} — wrong master key or corrupted file`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcache = decoded;\n\t\treturn cache;\n\t};\n\n\tconst save = async (): Promise<void> => {\n\t\tconst data = cache ?? new Map<string, string>();\n\t\tconst key = await ensureKey();\n\t\tconst values: Record<string, EncryptedEntry> = {};\n\t\tfor (const [name, value] of data) {\n\t\t\tconst iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));\n\t\t\tconst ct = await crypto.subtle.encrypt(\n\t\t\t\t{ iv: iv as BufferSource, name: 'AES-GCM' },\n\t\t\t\tkey,\n\t\t\t\tnew TextEncoder().encode(value) as BufferSource\n\t\t\t);\n\t\t\tvalues[name] = {\n\t\t\t\tct: bytesToBase64(new Uint8Array(ct)),\n\t\t\t\tiv: bytesToBase64(iv)\n\t\t\t};\n\t\t}\n\t\tconst file: EncryptedFile = {\n\t\t\tvalues,\n\t\t\tversion: ENC_FILE_VERSION,\n\t\t\t...(options.key.type === 'passphrase' && salt !== undefined\n\t\t\t\t? {\n\t\t\t\t\t\tkdf: {\n\t\t\t\t\t\t\titerations,\n\t\t\t\t\t\t\tsalt: bytesToBase64(salt),\n\t\t\t\t\t\t\ttype: 'pbkdf2-sha256'\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: {})\n\t\t};\n\t\tawait io.writeFileAtomic(options.path, JSON.stringify(file, null, 2));\n\t};\n\n\treturn {\n\t\tfetch: async (name) => {\n\t\t\tconst data = await load();\n\t\t\treturn data.get(name) ?? null;\n\t\t},\n\t\tlist: async () => {\n\t\t\tconst data = await load();\n\t\t\treturn Array.from(data.keys());\n\t\t},\n\t\tput: (name, value) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tdata.set(name, value);\n\t\t\tawait save();\n\t\t}),\n\t\tremove: (name) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tdata.delete(name);\n\t\t\tawait save();\n\t\t}),\n\t\trotate: (name) => mutate(async () => {\n\t\t\tconst data = await load();\n\t\t\tconst previous = data.get(name) ?? null;\n\t\t\tconst next = rotate(name, previous);\n\t\t\tdata.set(name, next);\n\t\t\tawait save();\n\t\t\treturn next;\n\t\t})\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// rotateMasterKey — re-encrypt the file under a new master key\n// -----------------------------------------------------------------------------\n\nexport type RotateMasterKeyOptions = {\n\t/** Path to the encrypted JSON file (must exist). */\n\tpath: string;\n\t/** Master key the file was written with. */\n\toldKey: EncryptedFileAdapterMasterKey;\n\t/** Master key to re-encrypt under. */\n\tnewKey: EncryptedFileAdapterMasterKey;\n\t/**\n\t * PBKDF2 iterations for the new passphrase (when `newKey.type ===\n\t * 'passphrase'`). Default 600_000. Stored in the rewritten file.\n\t */\n\tnewPbkdf2Iterations?: number;\n\t/** Override file IO (tests). */\n\tio?: EncryptedFileIO;\n};\n\n/**\n * Re-encrypt the entire secrets file under a new master key. Reads\n * every value with `oldKey`, writes them back encrypted under\n * `newKey`. Atomic at the file layer (temp + rename); the old file\n * remains intact if any step fails before the final write.\n *\n * Use cases:\n * - master passphrase leak: rotate to a new passphrase\n * - moving from passphrase to raw-bytes (or vice versa) — e.g.\n * graduating from \"operator-typed passphrase\" to \"key sourced\n * from a vendor secret manager\"\n * - periodic master-key rotation as a compliance hygiene measure\n *\n * After this returns, any process still holding the old key\n * will fail to decrypt on next access. Rotate the consumers'\n * master-key references at the same time you call this.\n */\nexport const rotateMasterKey = async (\n\toptions: RotateMasterKeyOptions\n): Promise<void> => {\n\tconst io = options.io ?? defaultIo();\n\tconst newIterations =\n\t\toptions.newPbkdf2Iterations ?? DEFAULT_PBKDF2_ITERATIONS;\n\n\tconst fileText = await io.readFile(options.path);\n\tif (fileText === undefined) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] file ${options.path} does not exist`\n\t\t);\n\t}\n\n\tlet parsed: EncryptedFile;\n\ttry {\n\t\tparsed = JSON.parse(fileText) as EncryptedFile;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] could not parse ${options.path}: ${(error as Error).message}`\n\t\t);\n\t}\n\tif (parsed.version !== ENC_FILE_VERSION) {\n\t\tthrow new Error(\n\t\t\t`[secrets/encrypted-file] unsupported file version ${parsed.version} in ${options.path}`\n\t\t);\n\t}\n\n\tlet oldDerivedKey: CryptoKey;\n\tif (options.oldKey.type === 'raw') {\n\t\tif (parsed.kdf !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a passphrase but old key was supplied as raw`\n\t\t\t);\n\t\t}\n\t\toldDerivedKey = await importRawKey(options.oldKey.bytes);\n\t} else {\n\t\tif (parsed.kdf === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] file was written with a raw key but old key was supplied as passphrase`\n\t\t\t);\n\t\t}\n\t\tconst oldSalt = base64ToBytes(parsed.kdf.salt);\n\t\toldDerivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.oldKey.passphrase,\n\t\t\toldSalt,\n\t\t\tparsed.kdf.iterations\n\t\t);\n\t}\n\n\tconst decrypted = new Map<string, string>();\n\tfor (const [name, entry] of Object.entries(parsed.values)) {\n\t\ttry {\n\t\t\tconst iv = base64ToBytes(entry.iv) as BufferSource;\n\t\t\tconst ct = base64ToBytes(entry.ct) as BufferSource;\n\t\t\tconst pt = await crypto.subtle.decrypt(\n\t\t\t\t{ iv, name: 'AES-GCM' },\n\t\t\t\toldDerivedKey,\n\t\t\t\tct\n\t\t\t);\n\t\t\tdecrypted.set(name, new TextDecoder().decode(pt));\n\t\t} catch {\n\t\t\tthrow new Error(\n\t\t\t\t`[secrets/encrypted-file] failed to decrypt \"${name}\" with old master key — wrong key or corrupted file`\n\t\t\t);\n\t\t}\n\t}\n\n\tlet newDerivedKey: CryptoKey;\n\tlet newSalt: Uint8Array | undefined;\n\tif (options.newKey.type === 'raw') {\n\t\tnewDerivedKey = await importRawKey(options.newKey.bytes);\n\t} else {\n\t\tnewSalt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));\n\t\tnewDerivedKey = await deriveKeyFromPassphrase(\n\t\t\toptions.newKey.passphrase,\n\t\t\tnewSalt,\n\t\t\tnewIterations\n\t\t);\n\t}\n\n\tconst newValues: Record<string, EncryptedEntry> = {};\n\tfor (const [name, value] of decrypted) {\n\t\tconst iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));\n\t\tconst ct = await crypto.subtle.encrypt(\n\t\t\t{ iv: iv as BufferSource, name: 'AES-GCM' },\n\t\t\tnewDerivedKey,\n\t\t\tnew TextEncoder().encode(value) as BufferSource\n\t\t);\n\t\tnewValues[name] = {\n\t\t\tct: bytesToBase64(new Uint8Array(ct)),\n\t\t\tiv: bytesToBase64(iv)\n\t\t};\n\t}\n\n\tconst newFile: EncryptedFile = {\n\t\tvalues: newValues,\n\t\tversion: ENC_FILE_VERSION,\n\t\t...(options.newKey.type === 'passphrase' && newSalt !== undefined\n\t\t\t? {\n\t\t\t\t\tkdf: {\n\t\t\t\t\t\titerations: newIterations,\n\t\t\t\t\t\tsalt: bytesToBase64(newSalt),\n\t\t\t\t\t\ttype: 'pbkdf2-sha256'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t: {})\n\t};\n\n\tawait io.writeFileAtomic(options.path, JSON.stringify(newFile, null, 2));\n};\n\n// -----------------------------------------------------------------------------\n// Broker\n// -----------------------------------------------------------------------------\n\ntype CacheEntry = {\n\tvalue: string;\n\tfingerprint: string;\n\tstoredAt: number;\n};\n\nexport const createSecretBroker = (options: SecretBrokerOptions): SecretBroker => {\n\tconst clock = options.clock ?? Date.now;\n\tconst defaultTtl = options.cacheTtlMs ?? 60_000;\n\tconst ttlOverrides = options.cacheTtlOverrides ?? {};\n\tconst minLen = options.redactionMinLength ?? 8;\n\tconst encodings = options.redactionEncodings ?? ['plain'];\n\tconst audit = options.audit;\n\tconst cache = new Map<string, CacheEntry>();\n\tconst rotationListeners = new Map<string, Set<RotationListener>>();\n\tlet disposed = false;\n\tlet draining = false;\n\t// 0.3.0: OTel tracer (noop when options.tracerProvider unset).\n\tconst tracer = tracerOrNoop(options.tracerProvider, '@absolutejs/secrets');\n\t// 0.2.0: cumulative operator counters. Survive `drain()` and\n\t// `dispose()` so the operator can read final state post-shutdown.\n\tconst counters: SecretBrokerMetrics = {\n\t\tinvalidations: 0,\n\t\tredactCalls: 0,\n\t\tredactionsApplied: 0,\n\t\tredactionsBase64: 0,\n\t\tresolveErrors: 0,\n\t\tresolveHits: 0,\n\t\tresolveMisses: 0,\n\t\tresolves: 0,\n\t\trotateErrors: 0,\n\t\trotates: 0\n\t};\n\n\tconst ttlFor = (name: string): number => ttlOverrides[name] ?? defaultTtl;\n\n\tconst fireRotation = (name: string, value: string, fingerprint: string, at: number) => {\n\t\tconst set = rotationListeners.get(name);\n\t\tif (!set || set.size === 0) return;\n\t\tfor (const listener of set) {\n\t\t\ttry {\n\t\t\t\tconst ret = listener({ at, fingerprint, name, value });\n\t\t\t\tif (ret && typeof (ret as Promise<void>).then === 'function') {\n\t\t\t\t\t(ret as Promise<void>).catch((error) => {\n\t\t\t\t\t\tconsole.error('[secrets] rotation listener rejected:', error);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[secrets] rotation listener threw:', error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst fireAudit = (event: AuditEvent) => {\n\t\tif (!audit) return;\n\t\ttry {\n\t\t\tconst result = audit(event);\n\t\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\t\t(result as Promise<void>).catch((error) => {\n\t\t\t\t\tconsole.error('[secrets] audit hook rejected:', error);\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('[secrets] audit hook threw:', error);\n\t\t}\n\t};\n\n\tconst cacheEntry = (name: string, value: string, now: number): CacheEntry => {\n\t\tconst entry: CacheEntry = {\n\t\t\tfingerprint: fingerprintOf(value),\n\t\t\tstoredAt: now,\n\t\t\tvalue,\n\t\t};\n\t\tcache.set(name, entry);\n\t\treturn entry;\n\t};\n\n\tconst resolve: SecretBroker['resolve'] = async (name) => {\n\t\tif (disposed) return null;\n\t\tif (draining) throw new BrokerDrainedError();\n\t\t// 0.3.0: span the resolve. Attribute carries the secret NAME\n\t\t// (safe) and on cache hit also the FINGERPRINT (also safe —\n\t\t// it's sha256-derived, never the value).\n\t\tconst span = tracer.startSpan('secrets.resolve', {\n\t\t\tattributes: { [ABS_ATTRS.secretName]: name }\n\t\t});\n\t\tcounters.resolves += 1;\n\t\tconst now = clock();\n\t\ttry {\n\t\t\tconst cached = cache.get(name);\n\t\t\tif (cached && now - cached.storedAt < ttlFor(name)) {\n\t\t\t\tcounters.resolveHits += 1;\n\t\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, cached.fingerprint);\n\t\t\t\tspan.setAttribute('secrets.cache', 'hit');\n\t\t\t\tfireAudit({ at: now, event: 'resolve.hit', fingerprint: cached.fingerprint, name });\n\t\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\t\treturn { fingerprint: cached.fingerprint, value: cached.value };\n\t\t\t}\n\t\t\tcounters.resolveMisses += 1;\n\t\t\tspan.setAttribute('secrets.cache', 'miss');\n\t\t\tconst value = await options.adapter.fetch(name);\n\t\t\tif (value === null) {\n\t\t\t\tfireAudit({ at: now, event: 'resolve.miss', name });\n\t\t\t\tcache.delete(name);\n\t\t\t\tspan.setAttribute('secrets.found', false);\n\t\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst entry = cacheEntry(name, value, now);\n\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);\n\t\t\tfireAudit({ at: now, event: 'resolve.miss', fingerprint: entry.fingerprint, name });\n\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\treturn { fingerprint: entry.fingerprint, value: entry.value };\n\t\t} catch (error) {\n\t\t\tcounters.resolveErrors += 1;\n\t\t\tfireAudit({\n\t\t\t\tat: now,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\tevent: 'resolve.error',\n\t\t\t\tname,\n\t\t\t});\n\t\t\tspan.recordException(error);\n\t\t\tspan.setStatus({\n\t\t\t\tcode: 2 /* ERROR */,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tspan.end();\n\t\t}\n\t};\n\n\tconst rotate: SecretBroker['rotate'] = async (name) => {\n\t\tif (disposed) throw new Error('Broker is disposed');\n\t\tif (draining) throw new BrokerDrainedError();\n\t\tif (!options.adapter.rotate) {\n\t\t\tthrow new Error('Adapter does not support rotate()');\n\t\t}\n\t\t// 0.3.0: span the rotation. The pre-rotation fingerprint isn't\n\t\t// known until after the cache lookup is done; attach the new\n\t\t// fingerprint on success.\n\t\tconst span = tracer.startSpan('secrets.rotate', {\n\t\t\tattributes: { [ABS_ATTRS.secretName]: name }\n\t\t});\n\t\ttry {\n\t\t\tconst next = await options.adapter.rotate(name);\n\t\t\tconst now = clock();\n\t\t\tconst entry = cacheEntry(name, next, now);\n\t\t\tcounters.rotates += 1;\n\t\t\tspan.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);\n\t\t\tspan.setStatus({ code: 1 /* OK */ });\n\t\t\tfireAudit({ at: now, event: 'rotate', fingerprint: entry.fingerprint, name });\n\t\t\tfireRotation(name, entry.value, entry.fingerprint, now);\n\t\t\treturn { fingerprint: entry.fingerprint, value: entry.value };\n\t\t} catch (error) {\n\t\t\tcounters.rotateErrors += 1;\n\t\t\tspan.recordException(error);\n\t\t\tspan.setStatus({\n\t\t\t\tcode: 2 /* ERROR */,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tspan.end();\n\t\t}\n\t};\n\n\tconst invalidate: SecretBroker['invalidate'] = (name) => {\n\t\tif (name === undefined) {\n\t\t\tcache.clear();\n\t\t} else {\n\t\t\tcache.delete(name);\n\t\t}\n\t\tcounters.invalidations += 1;\n\t\tfireAudit({ at: clock(), event: 'invalidate', name: name ?? null });\n\t};\n\n\t// Returns every (representation, replacementLabel) pair currently in\n\t// the cache that's worth searching for. Longest-first so a longer\n\t// secret blanks BEFORE one of its substrings would.\n\tconst redactionPairs = (): Array<[string, string]> => {\n\t\tconst pairs: Array<[string, string]> = [];\n\t\tfor (const [name, entry] of cache) {\n\t\t\tif (entry.value.length < minLen) continue;\n\t\t\tfor (const enc of encodings) {\n\t\t\t\tif (enc === 'plain') {\n\t\t\t\t\tpairs.push([entry.value, `[REDACTED:${name}]`]);\n\t\t\t\t} else if (enc === 'base64') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst encoded = btoa(entry.value);\n\t\t\t\t\t\t// Skip if encoding produces a too-short token to be safe.\n\t\t\t\t\t\tif (encoded.length >= minLen) {\n\t\t\t\t\t\t\tpairs.push([encoded, `[REDACTED:${name}:b64]`]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// btoa rejects non-Latin-1; skip silently.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpairs.sort((a, b) => b[0].length - a[0].length);\n\t\treturn pairs;\n\t};\n\n\tconst redact: SecretBroker['redact'] = (text) => {\n\t\tcounters.redactCalls += 1;\n\t\tif (text.length === 0 || cache.size === 0) return text;\n\t\tlet out = text;\n\t\tfor (const [needle, replacement] of redactionPairs()) {\n\t\t\tif (!out.includes(needle)) continue;\n\t\t\tout = out.split(needle).join(replacement);\n\t\t\tcounters.redactionsApplied += 1;\n\t\t\tif (replacement.endsWith(':b64]')) counters.redactionsBase64 += 1;\n\t\t}\n\t\treturn out;\n\t};\n\n\tconst redactStream: SecretBroker['redactStream'] = () => {\n\t\t// Per-chunk algorithm:\n\t\t// 1. Append chunk to buffer.\n\t\t// 2. Redact the WHOLE buffer (complete secrets → labels).\n\t\t// 3. Hold back the last `lookback` chars — they might contain a\n\t\t// partial secret that completes on the next chunk. The next\n\t\t// chunk's redact() will catch it once the full secret arrives.\n\t\t// 4. Emit the safe prefix.\n\t\t// Without step 2 happening BEFORE the split, a secret straddling the\n\t\t// boundary would have its prefix emitted un-redacted before the suffix\n\t\t// even shows up.\n\t\tlet buffer = '';\n\t\tconst maxLen = () =>\n\t\t\tredactionPairs().reduce((max, [needle]) => Math.max(max, needle.length), 0);\n\t\treturn new TransformStream<string, string>({\n\t\t\ttransform: (chunk, controller) => {\n\t\t\t\tbuffer += chunk;\n\t\t\t\tconst lookback = maxLen();\n\t\t\t\tconst reduced = redact(buffer);\n\t\t\t\tif (reduced.length <= lookback) {\n\t\t\t\t\tbuffer = reduced;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst safe = reduced.slice(0, reduced.length - lookback);\n\t\t\t\tbuffer = reduced.slice(reduced.length - lookback);\n\t\t\t\tif (safe.length > 0) controller.enqueue(safe);\n\t\t\t},\n\t\t\tflush: (controller) => {\n\t\t\t\tif (buffer.length === 0) return;\n\t\t\t\tcontroller.enqueue(redact(buffer));\n\t\t\t\tbuffer = '';\n\t\t\t},\n\t\t});\n\t};\n\n\tconst onRotate: SecretBroker['onRotate'] = (name, listener) => {\n\t\tlet set = rotationListeners.get(name);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\trotationListeners.set(name, set);\n\t\t}\n\t\tset.add(listener);\n\t\treturn () => {\n\t\t\tconst current = rotationListeners.get(name);\n\t\t\tif (!current) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) rotationListeners.delete(name);\n\t\t};\n\t};\n\n\treturn {\n\t\tdispose: () => {\n\t\t\tdisposed = true;\n\t\t\tcache.clear();\n\t\t\trotationListeners.clear();\n\t\t},\n\t\tdrain: () => {\n\t\t\tdraining = true;\n\t\t},\n\t\tfingerprint: fingerprintOf,\n\t\tinvalidate,\n\t\tmetrics: () => ({ ...counters }),\n\t\tonRotate,\n\t\tredact,\n\t\tredactStream,\n\t\tresolve,\n\t\trotate,\n\t};\n};\n"
|
|
9
10
|
],
|
|
10
|
-
"mappings": "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",
|
|
11
|
-
"debugId": "
|
|
11
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "0694F56E375AD55B64756E2164756E21",
|
|
12
13
|
"names": []
|
|
13
14
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CredentialGrantStore } from "./operations";
|
|
2
|
+
export type SecretsSqlResult<Row> = {
|
|
3
|
+
rowCount: number;
|
|
4
|
+
rows: ReadonlyArray<Row>;
|
|
5
|
+
};
|
|
6
|
+
export type SecretsSqlClient = {
|
|
7
|
+
query: <Row = Record<string, unknown>>(sql: string, parameters?: ReadonlyArray<unknown>) => Promise<SecretsSqlResult<Row>>;
|
|
8
|
+
};
|
|
9
|
+
export declare const credentialGrantsPostgresSchemaSql: (namespace?: string) => string;
|
|
10
|
+
export declare const createPostgresCredentialGrantStore: ({ client, namespace }: {
|
|
11
|
+
client: SecretsSqlClient;
|
|
12
|
+
namespace?: string;
|
|
13
|
+
}) => CredentialGrantStore;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@absolutejs/secrets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Host-side secret broker for multi-tenant Bun runtimes. Pluggable adapters (env-var, in-memory, composite, encrypted-file); audit hook per resolve; safe fingerprints for logs; redact() walks known secrets out of arbitrary text before it lands in a log sink.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"release": "bun run format && bun run check:package && bun publish"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@absolutejs/agency": "^0.
|
|
44
|
+
"@absolutejs/agency": "^0.3.0",
|
|
45
45
|
"@absolutejs/manifest": "^0.2.0",
|
|
46
46
|
"@absolutejs/telemetry": "^0.1.1",
|
|
47
47
|
"@sinclair/typebox": "^0.34.0"
|