@tangle-network/agent-app 0.1.2 → 0.1.4
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/billing/index.d.ts +94 -1
- package/dist/billing/index.js +3 -1
- package/dist/chunk-5RV6CAHZ.js +137 -0
- package/dist/chunk-5RV6CAHZ.js.map +1 -0
- package/dist/{chunk-7P6VIHI4.js → chunk-AQ2BOPOQ.js} +8 -2
- package/dist/{chunk-7P6VIHI4.js.map → chunk-AQ2BOPOQ.js.map} +1 -1
- package/dist/{chunk-45MYQ3GD.js → chunk-EAJSWUU5.js} +56 -1
- package/dist/chunk-EAJSWUU5.js.map +1 -0
- package/dist/chunk-EEPJGZJW.js +102 -0
- package/dist/chunk-EEPJGZJW.js.map +1 -0
- package/dist/chunk-EZXN67KE.js +318 -0
- package/dist/chunk-EZXN67KE.js.map +1 -0
- package/dist/{chunk-SIDR6BH3.js → chunk-ZJGY7OMZ.js} +47 -2
- package/dist/chunk-ZJGY7OMZ.js.map +1 -0
- package/dist/chunk-ZXNXAQAH.js +69 -0
- package/dist/chunk-ZXNXAQAH.js.map +1 -0
- package/dist/config/index.d.ts +367 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/crypto/index.d.ts +36 -1
- package/dist/crypto/index.js +13 -3
- package/dist/delegation/index.d.ts +16 -1
- package/dist/delegation/index.js +5 -3
- package/dist/index.d.ts +10 -4
- package/dist/index.js +61 -9
- package/dist/knowledge/index.d.ts +90 -0
- package/dist/knowledge/index.js +9 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge-loop/index.d.ts +208 -0
- package/dist/knowledge-loop/index.js +11 -0
- package/dist/knowledge-loop/index.js.map +1 -0
- package/dist/model-BOP69mVu.d.ts +35 -0
- package/dist/preset-cloudflare/index.d.ts +244 -0
- package/dist/preset-cloudflare/index.js +23 -0
- package/dist/preset-cloudflare/index.js.map +1 -0
- package/dist/runtime/index.d.ts +2 -35
- package/package.json +36 -5
- package/dist/chunk-45MYQ3GD.js.map +0 -1
- package/dist/chunk-SIDR6BH3.js.map +0 -1
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,39 +1,6 @@
|
|
|
1
|
+
export { D as DEFAULT_TANGLE_ROUTER_BASE_URL, R as ResolveModelOptions, T as TangleModelConfig, r as resolveTangleModelConfig } from '../model-BOP69mVu.js';
|
|
1
2
|
import { d as AppToolOutcome } from '../types-CeWor4bQ.js';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the model config a Tangle agent's sandbox/runtime runs on.
|
|
5
|
-
*
|
|
6
|
-
* Every Tangle agent product resolves the SAME thing from env: the Tangle Router
|
|
7
|
-
* (OpenAI-compatible, metered at the platform markup against a single
|
|
8
|
-
* `TANGLE_API_KEY`) by default, with a direct-Anthropic BYOK escape hatch. The
|
|
9
|
-
* shape feeds the sandbox SDK's `backend.model`. Lifted here so no product
|
|
10
|
-
* hand-rolls the env parsing + the router default.
|
|
11
|
-
*/
|
|
12
|
-
interface TangleModelConfig {
|
|
13
|
-
/** The Tangle Router is OpenAI-compatible → driven via `openai-compat`.
|
|
14
|
-
* `anthropic` is the BYOK escape hatch. */
|
|
15
|
-
provider: 'openai-compat' | 'anthropic';
|
|
16
|
-
model: string;
|
|
17
|
-
apiKey: string;
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
}
|
|
20
|
-
interface ResolveModelOptions {
|
|
21
|
-
/** Env to read (defaults to process.env). */
|
|
22
|
-
env?: Record<string, string | undefined>;
|
|
23
|
-
/** Router base URL default when `TANGLE_ROUTER_BASE_URL` is unset. */
|
|
24
|
-
defaultRouterBaseUrl?: string;
|
|
25
|
-
}
|
|
26
|
-
declare const DEFAULT_TANGLE_ROUTER_BASE_URL = "https://router.tangle.tools/v1";
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the model config from env. DEFAULT path (`MODEL_PROVIDER` unset or
|
|
29
|
-
* `openai-compat`/`tangle-router`/`tcloud`): the Tangle Router, authenticated
|
|
30
|
-
* with `TANGLE_API_KEY`, model from `MODEL_NAME`. BYOK path
|
|
31
|
-
* (`MODEL_PROVIDER=anthropic`): direct Anthropic with `ANTHROPIC_API_KEY` +
|
|
32
|
-
* `ANTHROPIC_BASE_URL`. Throws (fail-loud) on a missing required var so a
|
|
33
|
-
* misconfigured deploy fails at boot, not mid-turn.
|
|
34
|
-
*/
|
|
35
|
-
declare function resolveTangleModelConfig(opts?: ResolveModelOptions): TangleModelConfig;
|
|
36
|
-
|
|
37
4
|
/**
|
|
38
5
|
* OpenAI-compatible stream → `LoopEvent` adapter, for NON-sandbox copilots.
|
|
39
6
|
*
|
|
@@ -216,4 +183,4 @@ interface StreamAppToolLoopOptions<Raw> {
|
|
|
216
183
|
*/
|
|
217
184
|
declare function streamAppToolLoop<Raw>(opts: StreamAppToolLoopOptions<Raw>): AsyncGenerator<StreamLoopYield<Raw>, void, unknown>;
|
|
218
185
|
|
|
219
|
-
export { type AppToolLoopOptions,
|
|
186
|
+
export { type AppToolLoopOptions, type LoopEvent, type LoopToolCall, type OpenAICompatStreamTurnOptions, type OpenAIStreamChunk, type StreamAppToolLoopOptions, type StreamLoopYield, type ToolLoopResult, createOpenAICompatStreamTurn, runAppToolLoop, streamAppToolLoop, toLoopEvents };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -61,6 +61,26 @@
|
|
|
61
61
|
"import": "./dist/eval/index.js",
|
|
62
62
|
"default": "./dist/eval/index.js"
|
|
63
63
|
},
|
|
64
|
+
"./knowledge": {
|
|
65
|
+
"types": "./dist/knowledge/index.d.ts",
|
|
66
|
+
"import": "./dist/knowledge/index.js",
|
|
67
|
+
"default": "./dist/knowledge/index.js"
|
|
68
|
+
},
|
|
69
|
+
"./config": {
|
|
70
|
+
"types": "./dist/config/index.d.ts",
|
|
71
|
+
"import": "./dist/config/index.js",
|
|
72
|
+
"default": "./dist/config/index.js"
|
|
73
|
+
},
|
|
74
|
+
"./knowledge-loop": {
|
|
75
|
+
"types": "./dist/knowledge-loop/index.d.ts",
|
|
76
|
+
"import": "./dist/knowledge-loop/index.js",
|
|
77
|
+
"default": "./dist/knowledge-loop/index.js"
|
|
78
|
+
},
|
|
79
|
+
"./preset-cloudflare": {
|
|
80
|
+
"types": "./dist/preset-cloudflare/index.d.ts",
|
|
81
|
+
"import": "./dist/preset-cloudflare/index.js",
|
|
82
|
+
"default": "./dist/preset-cloudflare/index.js"
|
|
83
|
+
},
|
|
64
84
|
"./billing": {
|
|
65
85
|
"types": "./dist/billing/index.d.ts",
|
|
66
86
|
"import": "./dist/billing/index.js",
|
|
@@ -101,15 +121,26 @@
|
|
|
101
121
|
"typecheck": "tsc --noEmit"
|
|
102
122
|
},
|
|
103
123
|
"devDependencies": {
|
|
124
|
+
"@tangle-network/agent-eval": "^0.70.0",
|
|
125
|
+
"@tangle-network/agent-integrations": "^0.32.0",
|
|
126
|
+
"@tangle-network/agent-knowledge": "^1.5.2",
|
|
104
127
|
"@types/node": "^25.6.0",
|
|
105
128
|
"tsup": "^8.0.0",
|
|
106
129
|
"typescript": "^5.7.0",
|
|
107
|
-
"vitest": "^3.0.0"
|
|
108
|
-
"@tangle-network/agent-integrations": "^0.32.0",
|
|
109
|
-
"@tangle-network/agent-eval": "^0.70.0"
|
|
130
|
+
"vitest": "^3.0.0"
|
|
110
131
|
},
|
|
111
132
|
"peerDependencies": {
|
|
133
|
+
"@tangle-network/agent-eval": ">=0.50.0",
|
|
112
134
|
"@tangle-network/agent-integrations": ">=0.32.0",
|
|
113
|
-
"@tangle-network/agent-
|
|
135
|
+
"@tangle-network/agent-knowledge": ">=1.5.0",
|
|
136
|
+
"@tangle-network/agent-runtime": ">=0.21.0"
|
|
137
|
+
},
|
|
138
|
+
"peerDependenciesMeta": {
|
|
139
|
+
"@tangle-network/agent-knowledge": {
|
|
140
|
+
"optional": true
|
|
141
|
+
},
|
|
142
|
+
"@tangle-network/agent-runtime": {
|
|
143
|
+
"optional": true
|
|
144
|
+
}
|
|
114
145
|
}
|
|
115
146
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/billing/index.ts"],"sourcesContent":["/**\n * Per-workspace budget-capped model keys — app-owned billing, metered on Tangle.\n *\n * Each workspace (the paying entity) runs the agent on its OWN child API key\n * minted from the platform parent key. The child carries a hard USD budget the\n * Tangle Router enforces AT THE KEY — model spend can't exceed the allowance,\n * zero app-side accounting. The app charges its own subscription (e.g. 5× the\n * allowance) and re-provisions each period. Child budgets are IMMUTABLE on the\n * platform, so a new budget = a fresh key + revoke the prior (rotate).\n *\n * The mint / rotate / rollover / usage LOGIC is generic and lives here.\n * Persistence (which D1 table), secret encryption, and key provisioning are\n * SEAMS each product supplies — so this module imports no DB and no key-mgmt\n * SDK (structural contracts only, like `../tangle`). The `@tangle-network/tcloud`\n * SDK is the provisioner a product passes in; it is not a dependency here.\n */\n\n/** The key-provisioning operations this needs — the `@tangle-network/tcloud`\n * SDK's `TCloudClient` satisfies it structurally; pass it in. */\nexport interface KeyProvisioner {\n createKey(input: { name: string; product: string; budgetUsd: number; expiresAt: string }): Promise<{ id?: string; key?: string }>\n revokeKey(keyId: string): Promise<unknown>\n getKey(keyId: string): Promise<{ budgetUsd?: number; budgetSpent?: number; expiresAt?: string | null }>\n}\n\n/** A stored child-key record (the app's row, shape-normalized). */\nexport interface WorkspaceKeyRecord {\n /** App row id (opaque). */\n id: string\n keyId: string\n /** The encrypted secret — decrypted via {@link KeyCrypto.decrypt}. */\n keyEncrypted: string\n budgetUsd: number\n expiresAt: Date | null\n}\n\n/** Persistence seam — the product implements this against its own D1 table. */\nexport interface WorkspaceKeyStore {\n /** Most-recent active key for the workspace, or null. */\n getActive(workspaceId: string): Promise<WorkspaceKeyRecord | null>\n /** All active keys (to revoke priors on rotate). */\n listActive(workspaceId: string): Promise<Array<{ id: string; keyId: string }>>\n /** Persist a freshly minted active key. */\n insert(record: { workspaceId: string; keyId: string; keyEncrypted: string; budgetUsd: number; expiresAt: Date }): Promise<void>\n /** Mark a prior row revoked. */\n markRevoked(id: string, now: Date): Promise<void>\n}\n\n/** Secret encryption seam (the app's at-rest crypto). */\nexport interface KeyCrypto {\n encrypt(secret: string): Promise<string>\n decrypt(encrypted: string): Promise<string>\n}\n\nexport interface WorkspaceKeyManagerOptions {\n provisioner: KeyProvisioner\n store: WorkspaceKeyStore\n crypto: KeyCrypto\n /** Default monthly allowance (USD) when a call doesn't specify one. */\n defaultBudgetUsd: number\n /** Injectable clock. Default `() => new Date()`. */\n now?: () => Date\n /** tcloud product the key is scoped to. Default `'router'`. */\n product?: string\n}\n\nexport interface WorkspaceModelKeyUsage {\n keyId: string\n budgetUsd: number\n budgetSpent: number\n budgetRemaining: number\n expiresAt: string | null\n exhausted: boolean\n}\n\nexport interface WorkspaceKeyManager {\n /** The workspace's active child-key secret, provisioning one if absent/expired. */\n ensureKey(workspaceId: string, opts?: { budgetUsd?: number }): Promise<string>\n /** Mint a fresh key + revoke priors (period renewal / top-up). `rollover`\n * carries the prior key's unused budget into the new one, bounded by\n * `rolloverCapUsd`. Returns the new secret. */\n rotateKey(workspaceId: string, opts?: { budgetUsd?: number; rollover?: boolean; rolloverCapUsd?: number }): Promise<string>\n /** Live budget usage for the active key (drives the \"$X of $Y used\" panel). */\n getUsage(workspaceId: string): Promise<WorkspaceModelKeyUsage | null>\n}\n\n/** Period end = first day of next month, midnight UTC. Keys expire at the period\n * boundary so a forgotten rotation fails closed rather than running free. */\nfunction nextPeriodEnd(now: Date): Date {\n return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0))\n}\n\nexport function createWorkspaceKeyManager(opts: WorkspaceKeyManagerOptions): WorkspaceKeyManager {\n const clock = opts.now ?? (() => new Date())\n const product = opts.product ?? 'router'\n\n const getUsage: WorkspaceKeyManager['getUsage'] = async (workspaceId) => {\n const active = await opts.store.getActive(workspaceId)\n if (!active) return null\n const info = await opts.provisioner.getKey(active.keyId)\n const budgetUsd = info.budgetUsd ?? active.budgetUsd\n const budgetSpent = info.budgetSpent ?? 0\n const budgetRemaining = Math.max(0, budgetUsd - budgetSpent)\n return {\n keyId: active.keyId,\n budgetUsd,\n budgetSpent,\n budgetRemaining,\n expiresAt: info.expiresAt ?? (active.expiresAt ? active.expiresAt.toISOString() : null),\n exhausted: budgetRemaining <= 0,\n }\n }\n\n const rotateKey: WorkspaceKeyManager['rotateKey'] = async (workspaceId, ropts) => {\n const now = clock()\n const allowance = ropts?.budgetUsd ?? opts.defaultBudgetUsd\n\n let budgetUsd = allowance\n if (ropts?.rollover) {\n const prior = await getUsage(workspaceId).catch(() => null)\n budgetUsd = allowance + (prior?.budgetRemaining ?? 0)\n if (ropts.rolloverCapUsd != null) budgetUsd = Math.min(budgetUsd, ropts.rolloverCapUsd)\n }\n\n const expiresAt = nextPeriodEnd(now)\n const created = await opts.provisioner.createKey({ name: `ws:${workspaceId}`, product, budgetUsd, expiresAt: expiresAt.toISOString() })\n if (!created.key || !created.id) throw new Error('tcloud createKey returned no key')\n const keyEncrypted = await opts.crypto.encrypt(created.key)\n\n const priors = await opts.store.listActive(workspaceId)\n await opts.store.insert({ workspaceId, keyId: created.id, keyEncrypted, budgetUsd, expiresAt })\n for (const p of priors) {\n await opts.store.markRevoked(p.id, now)\n // Best-effort upstream revoke — the row is already revoked and an expired\n // key fails closed regardless, so a transient error is non-fatal.\n try {\n await opts.provisioner.revokeKey(p.keyId)\n } catch {\n /* non-fatal */\n }\n }\n return created.key\n }\n\n const ensureKey: WorkspaceKeyManager['ensureKey'] = async (workspaceId, eopts) => {\n const now = clock()\n const active = await opts.store.getActive(workspaceId)\n if (active && (!active.expiresAt || active.expiresAt.getTime() > now.getTime())) {\n return opts.crypto.decrypt(active.keyEncrypted)\n }\n return rotateKey(workspaceId, { budgetUsd: eopts?.budgetUsd })\n }\n\n return { ensureKey, rotateKey, getUsage }\n}\n"],"mappings":";AAwFA,SAAS,cAAc,KAAiB;AACtC,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AACtF;AAEO,SAAS,0BAA0B,MAAuD;AAC/F,QAAM,QAAQ,KAAK,QAAQ,MAAM,oBAAI,KAAK;AAC1C,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,WAA4C,OAAO,gBAAgB;AACvE,UAAM,SAAS,MAAM,KAAK,MAAM,UAAU,WAAW;AACrD,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAAO,MAAM,KAAK,YAAY,OAAO,OAAO,KAAK;AACvD,UAAM,YAAY,KAAK,aAAa,OAAO;AAC3C,UAAM,cAAc,KAAK,eAAe;AACxC,UAAM,kBAAkB,KAAK,IAAI,GAAG,YAAY,WAAW;AAC3D,WAAO;AAAA,MACL,OAAO,OAAO;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,cAAc,OAAO,YAAY,OAAO,UAAU,YAAY,IAAI;AAAA,MAClF,WAAW,mBAAmB;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,YAA8C,OAAO,aAAa,UAAU;AAChF,UAAM,MAAM,MAAM;AAClB,UAAM,YAAY,OAAO,aAAa,KAAK;AAE3C,QAAI,YAAY;AAChB,QAAI,OAAO,UAAU;AACnB,YAAM,QAAQ,MAAM,SAAS,WAAW,EAAE,MAAM,MAAM,IAAI;AAC1D,kBAAY,aAAa,OAAO,mBAAmB;AACnD,UAAI,MAAM,kBAAkB,KAAM,aAAY,KAAK,IAAI,WAAW,MAAM,cAAc;AAAA,IACxF;AAEA,UAAM,YAAY,cAAc,GAAG;AACnC,UAAM,UAAU,MAAM,KAAK,YAAY,UAAU,EAAE,MAAM,MAAM,WAAW,IAAI,SAAS,WAAW,WAAW,UAAU,YAAY,EAAE,CAAC;AACtI,QAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,GAAI,OAAM,IAAI,MAAM,kCAAkC;AACnF,UAAM,eAAe,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AAE1D,UAAM,SAAS,MAAM,KAAK,MAAM,WAAW,WAAW;AACtD,UAAM,KAAK,MAAM,OAAO,EAAE,aAAa,OAAO,QAAQ,IAAI,cAAc,WAAW,UAAU,CAAC;AAC9F,eAAW,KAAK,QAAQ;AACtB,YAAM,KAAK,MAAM,YAAY,EAAE,IAAI,GAAG;AAGtC,UAAI;AACF,cAAM,KAAK,YAAY,UAAU,EAAE,KAAK;AAAA,MAC1C,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO,QAAQ;AAAA,EACjB;AAEA,QAAM,YAA8C,OAAO,aAAa,UAAU;AAChF,UAAM,MAAM,MAAM;AAClB,UAAM,SAAS,MAAM,KAAK,MAAM,UAAU,WAAW;AACrD,QAAI,WAAW,CAAC,OAAO,aAAa,OAAO,UAAU,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAC/E,aAAO,KAAK,OAAO,QAAQ,OAAO,YAAY;AAAA,IAChD;AACA,WAAO,UAAU,aAAa,EAAE,WAAW,OAAO,UAAU,CAAC;AAAA,EAC/D;AAEA,SAAO,EAAE,WAAW,WAAW,SAAS;AAC1C;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/crypto/index.ts"],"sourcesContent":["/**\n * AES-256-GCM field encryption (for PII at rest — SSN/EIN/ID numbers, secrets).\n * WebCrypto only — runs on Cloudflare Workers, Node, and the browser with no\n * Node `crypto` dependency. The 32-byte key is a PARAMETER (64-char hex); the\n * framework never reads env — the product binds its own `ENCRYPTION_KEY` (this\n * is the concrete impl behind the `KeyCrypto` seam in `../billing`).\n *\n * Wire format: base64(iv ‖ ciphertext ‖ tag) — the 12-byte IV is prepended; the\n * GCM auth tag is appended by WebCrypto inside the ciphertext.\n */\n\nconst IV_LENGTH = 12\nconst TAG_LENGTH = 16\nconst ALGORITHM = 'AES-GCM'\n\n/** Validate + decode a 64-char hex key to 32 bytes. Throws on the wrong shape so\n * a misconfigured key fails loud, never silently weakens encryption. */\nexport function decodeHexKey(keyHex: string): Uint8Array {\n if (keyHex.length !== 64) throw new Error('encryption key must be a 64-char hex string (32 bytes)')\n const bytes = new Uint8Array(32)\n for (let i = 0; i < 64; i += 2) bytes[i / 2] = parseInt(keyHex.substring(i, i + 2), 16)\n return bytes\n}\n\nasync function importKey(keyHex: string): Promise<CryptoKey> {\n const raw = decodeHexKey(keyHex)\n return crypto.subtle.importKey('raw', raw.buffer as ArrayBuffer, { name: ALGORITHM } as Algorithm, false, ['encrypt', 'decrypt'])\n}\n\nfunction toBase64(data: Uint8Array): string {\n let binary = ''\n for (let i = 0; i < data.length; i++) binary += String.fromCharCode(data[i]!)\n return btoa(binary)\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n const binary = atob(b64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n return bytes\n}\n\n/** Encrypt `plaintext` with AES-256-GCM under `keyHex`. Returns\n * base64(iv ‖ ciphertext ‖ tag). A fresh random IV per call. */\nexport async function encryptAesGcm(plaintext: string, keyHex: string): Promise<string> {\n const key = await importKey(keyHex)\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH))\n const ciphertext = await crypto.subtle.encrypt({ name: ALGORITHM, iv, tagLength: TAG_LENGTH * 8 }, key, new TextEncoder().encode(plaintext))\n const result = new Uint8Array(IV_LENGTH + ciphertext.byteLength)\n result.set(iv, 0)\n result.set(new Uint8Array(ciphertext), IV_LENGTH)\n return toBase64(result)\n}\n\n/** Decrypt a base64(iv ‖ ciphertext ‖ tag) string under `keyHex`. Throws if the\n * tag fails (tamper/wrong key). */\nexport async function decryptAesGcm(encrypted: string, keyHex: string): Promise<string> {\n const key = await importKey(keyHex)\n const data = fromBase64(encrypted)\n const iv = data.slice(0, IV_LENGTH)\n const ciphertext = data.slice(IV_LENGTH)\n const plain = await crypto.subtle.decrypt({ name: ALGORITHM, iv, tagLength: TAG_LENGTH * 8 }, key, ciphertext)\n return new TextDecoder().decode(plain)\n}\n\n/** Build a {@link import('../billing').KeyCrypto}-compatible pair bound to a key\n * (or a key-resolver, for env-backed keys resolved per call). */\nexport function createFieldCrypto(key: string | (() => string)): { encrypt(s: string): Promise<string>; decrypt(s: string): Promise<string> } {\n const resolve = typeof key === 'function' ? key : () => key\n return {\n encrypt: (s) => encryptAesGcm(s, resolve()),\n decrypt: (s) => decryptAesGcm(s, resolve()),\n }\n}\n"],"mappings":";AAWA,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,YAAY;AAIX,SAAS,aAAa,QAA4B;AACvD,MAAI,OAAO,WAAW,GAAI,OAAM,IAAI,MAAM,wDAAwD;AAClG,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,EAAG,OAAM,IAAI,CAAC,IAAI,SAAS,OAAO,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AACtF,SAAO;AACT;AAEA,eAAe,UAAU,QAAoC;AAC3D,QAAM,MAAM,aAAa,MAAM;AAC/B,SAAO,OAAO,OAAO,UAAU,OAAO,IAAI,QAAuB,EAAE,MAAM,UAAU,GAAgB,OAAO,CAAC,WAAW,SAAS,CAAC;AAClI;AAEA,SAAS,SAAS,MAA0B;AAC1C,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK,WAAU,OAAO,aAAa,KAAK,CAAC,CAAE;AAC5E,SAAO,KAAK,MAAM;AACpB;AAEA,SAAS,WAAW,KAAyB;AAC3C,QAAM,SAAS,KAAK,GAAG;AACvB,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,OAAM,CAAC,IAAI,OAAO,WAAW,CAAC;AACtE,SAAO;AACT;AAIA,eAAsB,cAAc,WAAmB,QAAiC;AACtF,QAAM,MAAM,MAAM,UAAU,MAAM;AAClC,QAAM,KAAK,OAAO,gBAAgB,IAAI,WAAW,SAAS,CAAC;AAC3D,QAAM,aAAa,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,IAAI,WAAW,aAAa,EAAE,GAAG,KAAK,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAC3I,QAAM,SAAS,IAAI,WAAW,YAAY,WAAW,UAAU;AAC/D,SAAO,IAAI,IAAI,CAAC;AAChB,SAAO,IAAI,IAAI,WAAW,UAAU,GAAG,SAAS;AAChD,SAAO,SAAS,MAAM;AACxB;AAIA,eAAsB,cAAc,WAAmB,QAAiC;AACtF,QAAM,MAAM,MAAM,UAAU,MAAM;AAClC,QAAM,OAAO,WAAW,SAAS;AACjC,QAAM,KAAK,KAAK,MAAM,GAAG,SAAS;AAClC,QAAM,aAAa,KAAK,MAAM,SAAS;AACvC,QAAM,QAAQ,MAAM,OAAO,OAAO,QAAQ,EAAE,MAAM,WAAW,IAAI,WAAW,aAAa,EAAE,GAAG,KAAK,UAAU;AAC7G,SAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AACvC;AAIO,SAAS,kBAAkB,KAA4G;AAC5I,QAAM,UAAU,OAAO,QAAQ,aAAa,MAAM,MAAM;AACxD,SAAO;AAAA,IACL,SAAS,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AAAA,IAC1C,SAAS,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AAAA,EAC5C;AACF;","names":[]}
|