@tangle-network/agent-app 0.60.213 → 0.60.215

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/platform/sso-identity-store.ts","../../src/platform/hub-connect-callback.ts","../../src/platform/hub-settings.ts","../../src/platform/billing.ts","../../src/platform/agent-spend.ts","../../src/platform/billing-consent.ts","../../src/platform/delegated-keys.ts"],"sourcesContent":["/**\n * Better Auth `account`-table store for first-party Tangle identity sign-in\n * (`protocol: 'identity'`) on D1 / SQLite.\n *\n * The platform link is Better Auth's own external-identity row:\n * `account(providerId = 'tangle', accountId = <platform user id>, userId)`.\n * Run {@link TANGLE_IDENTITY_ACCOUNT_INDEXES_SQL} in a product migration; its\n * two partial unique indexes make the link one-per-user and\n * one-per-platform-user, which the write path relies on.\n *\n * Schema expectations are Better Auth's default SQLite model with camelCase\n * columns: `user(id, name, email, emailVerified, createdAt, updatedAt)`,\n * `session(id, userId, token, expiresAt, ipAddress, userAgent, createdAt,\n * updatedAt)` and `account(id, userId, accountId, providerId, createdAt,\n * updatedAt)`, with unix-second integer timestamps (Drizzle `mode:\n * 'timestamp'`). D1 is structural: Cloudflare `D1Database` satisfies\n * {@link TangleIdentityD1Like}.\n */\n\nimport {\n normalizeTangleSsoEmail,\n resolveTangleSsoAccount,\n TangleSsoAccountConflictError,\n TangleSsoUserCreateError,\n type TangleIdentitySsoAccountStore,\n type TangleSsoAccountResolution,\n type TangleSsoLocalAccount,\n} from './sso'\n\n/** Better Auth `account.providerId` for the Tangle platform link. */\nexport const TANGLE_IDENTITY_PROVIDER_ID = 'tangle'\n\n/** Partial unique indexes the store requires on Better Auth's `account` table. */\nexport const TANGLE_IDENTITY_ACCOUNT_INDEXES_SQL = [\n `CREATE UNIQUE INDEX IF NOT EXISTS account_tangle_platform_user ON account(accountId) WHERE providerId = '${TANGLE_IDENTITY_PROVIDER_ID}'`,\n `CREATE UNIQUE INDEX IF NOT EXISTS account_tangle_user ON account(userId) WHERE providerId = '${TANGLE_IDENTITY_PROVIDER_ID}'`,\n] as const\n\n/** A prepared D1 statement; Cloudflare `D1PreparedStatement` satisfies it. */\nexport interface TangleIdentityD1Statement {\n bind(...values: unknown[]): TangleIdentityD1Statement\n first<T = Record<string, unknown>>(): Promise<T | null>\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>\n run(): Promise<unknown>\n}\n\n/** The D1 surface the store needs. `batch` must be atomic, as D1's is. */\nexport interface TangleIdentityD1Like {\n prepare(query: string): TangleIdentityD1Statement\n batch(statements: TangleIdentityD1Statement[]): Promise<Array<{ meta?: { changes?: number } }>>\n}\n\n/**\n * A link table the product used before this store. During migration the store\n * reads it after `account` and mirrors new links into it, so a link that\n * exists in either place still signs in and a rollback still finds new links.\n * Remove the option once a reconcile query proves every legacy row has an\n * equal `account` row.\n */\nexport interface TangleIdentityLegacyLinkTable {\n table: string\n /** Column holding the local `user.id`; must be unique. */\n userIdColumn: string\n /** Column holding the platform user id; must be unique. */\n platformUserIdColumn: string\n}\n\nexport interface D1TangleIdentityStoreOptions {\n db: TangleIdentityD1Like\n /**\n * The signed-in local user for an explicit \"connect Tangle\" flow. A live\n * local session plus a verified platform exchange jointly authorize linking\n * that user, even when its local email is unverified or differs. The host\n * must prove the session started this flow (for example with a signed,\n * session-bound cookie).\n */\n linkingUserId?: string\n legacyLinkTable?: TangleIdentityLegacyLinkTable\n}\n\nconst SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction identifier(value: string, field: string): string {\n if (!SQL_IDENTIFIER.test(value)) throw new Error(`createD1TangleIdentityStore: invalid ${field}`)\n return value\n}\n\ninterface CandidateRow {\n userId: string\n email: string\n emailVerified: number | boolean | null\n accountPlatformUserId: string | null\n legacyPlatformUserId: string | null\n}\n\ninterface Candidate extends TangleSsoLocalAccount {\n /** The account row and the legacy row name different platform users. */\n divergent: boolean\n}\n\nfunction randomToken(): string {\n return Array.from(crypto.getRandomValues(new Uint8Array(32)), byte => byte.toString(16).padStart(2, '0')).join('')\n}\n\n/** Create the identity-protocol account store for one request. */\nexport function createD1TangleIdentityStore(options: D1TangleIdentityStoreOptions): TangleIdentitySsoAccountStore {\n const { db, linkingUserId } = options\n const provider = TANGLE_IDENTITY_PROVIDER_ID\n const legacy = options.legacyLinkTable && {\n table: identifier(options.legacyLinkTable.table, 'legacyLinkTable.table'),\n userId: identifier(options.legacyLinkTable.userIdColumn, 'legacyLinkTable.userIdColumn'),\n platformUserId: identifier(options.legacyLinkTable.platformUserIdColumn, 'legacyLinkTable.platformUserIdColumn'),\n }\n\n const selectAccount = `SELECT u.id AS userId, u.email AS email, u.emailVerified AS emailVerified,\n a.accountId AS accountPlatformUserId,\n ${legacy ? `l.${legacy.platformUserId}` : 'NULL'} AS legacyPlatformUserId\n FROM user u\n LEFT JOIN account a ON a.userId = u.id AND a.providerId = '${provider}'\n ${legacy ? `LEFT JOIN ${legacy.table} l ON l.${legacy.userId} = u.id` : ''}`\n\n function toCandidate(row: CandidateRow): Candidate {\n const fromAccount = row.accountPlatformUserId?.trim() || null\n const fromLegacy = row.legacyPlatformUserId?.trim() || null\n return {\n userId: row.userId,\n email: row.email,\n emailVerified: row.emailVerified === 1 || row.emailVerified === true,\n platformUserId: fromAccount ?? fromLegacy,\n divergent: Boolean(fromAccount && fromLegacy && fromAccount !== fromLegacy),\n }\n }\n\n async function candidates(email: string, platformUserId: string) {\n const where = legacy\n ? `WHERE lower(trim(u.email)) = ? OR a.accountId = ? OR l.${legacy.platformUserId} = ?`\n : 'WHERE lower(trim(u.email)) = ? OR a.accountId = ?'\n const values = legacy ? [email, platformUserId, platformUserId] : [email, platformUserId]\n const { results } = await db.prepare(`${selectAccount} ${where}`).bind(...values).all<CandidateRow>()\n const rows = results.map(toCandidate)\n return {\n divergent: rows.some(row => row.divergent),\n platformMatches: rows.filter(row => row.platformUserId === platformUserId),\n emailMatches: rows.filter(row => normalizeTangleSsoEmail(row.email) === email),\n }\n }\n\n const store: TangleIdentitySsoAccountStore = {\n async resolveAccount({ email, platformUserId }): Promise<TangleSsoAccountResolution> {\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const stableId = platformUserId.trim()\n const found = await candidates(normalizedEmail, stableId)\n if (found.divergent) return { kind: 'reject', reason: 'platform-id-email-conflict' }\n if (!linkingUserId) {\n return resolveTangleSsoAccount({\n email: normalizedEmail,\n platformUserId: stableId,\n platformMatches: found.platformMatches,\n emailMatches: found.emailMatches,\n })\n }\n\n const ownRow = await db.prepare(`${selectAccount} WHERE u.id = ?`).bind(linkingUserId).first<CandidateRow>()\n if (!ownRow) return { kind: 'reject', reason: 'email-match-mismatch' }\n const own = toCandidate(ownRow)\n if (own.divergent) return { kind: 'reject', reason: 'platform-id-email-conflict' }\n if (own.platformUserId && own.platformUserId !== stableId) {\n return { kind: 'reject', reason: 'email-platform-id-conflict' }\n }\n if (found.platformMatches.some(row => row.userId !== linkingUserId)\n || found.emailMatches.some(row => row.userId !== linkingUserId)) {\n return { kind: 'reject', reason: 'platform-id-email-conflict' }\n }\n return { kind: 'existing', userId: linkingUserId, matchedBy: 'platform-id' }\n },\n\n async upsertUserByEmail({ email, name, tangleUserId, resolution }) {\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const platformUserId = tangleUserId.trim()\n const current = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (current.kind === 'reject') throw new TangleSsoAccountConflictError(current.reason)\n if (current.kind === 'existing') {\n if (resolution.kind === 'existing' && resolution.userId !== current.userId) {\n throw new TangleSsoAccountConflictError('platform-id-email-conflict')\n }\n return { userId: current.userId }\n }\n\n if (resolution.kind !== 'create') throw new TangleSsoUserCreateError('The selected account changed')\n const userId = crypto.randomUUID()\n try {\n await db.prepare(`INSERT INTO user (id, name, email, emailVerified, createdAt, updatedAt)\n VALUES (?, ?, ?, 1, unixepoch(), unixepoch())`)\n .bind(userId, name || normalizedEmail, normalizedEmail).run()\n } catch {\n // A concurrent callback may have won the email UNIQUE race. Re-apply the\n // policy; never adopt that row by email alone.\n const after = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (after.kind === 'reject') throw new TangleSsoAccountConflictError(after.reason)\n if (after.kind === 'existing') return { userId: after.userId }\n throw new TangleSsoUserCreateError()\n }\n return { userId }\n },\n\n async createSession({ userId, expiresAt, ipAddress, userAgent }) {\n const token = randomToken()\n await db.prepare(`INSERT INTO session (id, userId, token, expiresAt, ipAddress, userAgent, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, unixepoch(), unixepoch())`)\n .bind(crypto.randomUUID(), userId, token, Math.floor(expiresAt.getTime() / 1000), ipAddress, userAgent)\n .run()\n return { token }\n },\n\n async saveTangleLink({ userId, sessionToken, tangleUserId, email }) {\n const platformUserId = tangleUserId.trim()\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const session = await db.prepare('SELECT userId FROM session WHERE token = ? AND expiresAt > unixepoch()')\n .bind(sessionToken).first<{ userId: string }>()\n if (session?.userId !== userId) throw new TangleSsoAccountConflictError('email-platform-id-conflict')\n const current = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (current.kind === 'reject') throw new TangleSsoAccountConflictError(current.reason)\n if (current.kind !== 'existing' || current.userId !== userId) {\n throw new TangleSsoAccountConflictError('platform-id-email-conflict')\n }\n\n // One atomic batch: every statement re-checks the live session and the\n // email owner, and the final verified-email update runs only when this\n // exact link exists, so a lost race commits nothing and rejects.\n const liveSession = 'EXISTS (SELECT 1 FROM session WHERE token = ? AND userId = ? AND expiresAt > unixepoch())'\n const emailFree = 'NOT EXISTS (SELECT 1 FROM user WHERE lower(trim(email)) = ? AND id <> ?)'\n const linked = `EXISTS (SELECT 1 FROM account WHERE providerId = '${provider}' AND userId = ? AND accountId = ?)`\n const statements = [\n db.prepare(`INSERT INTO account (id, userId, accountId, providerId, createdAt, updatedAt)\n SELECT ?, ?, ?, '${provider}', unixepoch(), unixepoch()\n WHERE EXISTS (SELECT 1 FROM user WHERE id = ?) AND ${liveSession} AND ${emailFree}\n ON CONFLICT DO NOTHING`)\n .bind(crypto.randomUUID(), userId, platformUserId, userId, sessionToken, userId, normalizedEmail, userId),\n ]\n if (legacy) {\n statements.push(db.prepare(`INSERT INTO ${legacy.table} (${legacy.userId}, ${legacy.platformUserId})\n SELECT ?, ? WHERE ${linked}\n ON CONFLICT DO NOTHING`)\n .bind(userId, platformUserId, userId, platformUserId))\n }\n statements.push(db.prepare(`UPDATE user SET emailVerified = CASE WHEN lower(trim(email)) = ? THEN 1 ELSE emailVerified END,\n updatedAt = unixepoch()\n WHERE id = ? AND ${liveSession} AND ${linked} AND ${emailFree}`)\n .bind(normalizedEmail, userId, sessionToken, userId, userId, platformUserId, normalizedEmail, userId))\n const results = await db.batch(statements)\n if (results[results.length - 1]?.meta?.changes !== 1) {\n throw new TangleSsoAccountConflictError('email-platform-id-conflict')\n }\n },\n\n // `saveTangleLink` is one atomic batch, so a rejected call wrote nothing;\n // removing the unpublished session is the whole cleanup.\n async deleteSession({ sessionToken }) {\n await db.prepare('DELETE FROM session WHERE token = ?').bind(sessionToken).run()\n },\n }\n return store\n}\n","/**\n * The OAuth return contract shared by the browser popup and the settings\n * server. The popup appends exactly these parameters to the host's callback\n * path; the server accepts a return URL only in that shape.\n */\nconst HUB_CONNECT_CALLBACK_PARAMS = ['provider', 'nonce', 'context'] as const\n\n/** True when `returnUrl` is the host's callback for `provider`, as the popup builds it. */\nexport function isHubConnectCallbackUrl(returnUrl: URL, callbackPath: string, provider: string): boolean {\n if (returnUrl.pathname !== callbackPath || returnUrl.hash) return false\n const keys = [...returnUrl.searchParams.keys()]\n if (keys.length !== HUB_CONNECT_CALLBACK_PARAMS.length) return false\n if (!HUB_CONNECT_CALLBACK_PARAMS.every((key) => returnUrl.searchParams.getAll(key).length === 1)) return false\n const opaque = (value: string | null) => !!value && value.length <= 128 && /^[A-Za-z0-9_-]+$/.test(value)\n return returnUrl.searchParams.get('provider') === provider\n && opaque(returnUrl.searchParams.get('nonce'))\n && opaque(returnUrl.searchParams.get('context'))\n}\n","/** Finite, application-authorized account settings over the existing Hub SDK. */\nimport { parseJsonObjectBody } from '../web/core'\nimport { isHubConnectCallbackUrl } from './hub-connect-callback'\n\n/** Non-secret API-key setup shapes supported by the Hub SDK. */\nexport type HubSettingsApiKeyMetadata =\n | { propertyId: string; currency?: string }\n | { listings: Array<{ id: string; pms: string }> }\n\n/** Browser OAuth setup, excluding CLI mode and identity/credential overrides. */\nexport interface HubSettingsOAuthInput {\n returnUrl: string\n connectionParameters?: Record<string, string>\n}\n\ntype PolicyDecision = 'allow' | 'ask' | 'deny'\n\n/**\n * Structural subset of the existing SDK, with no execution methods. Keeping\n * this structural avoids imposing a Hub SDK peer on existing platform imports.\n */\nexport interface HubSettingsClient {\n connections: {\n providers(): Promise<unknown>\n list(): Promise<unknown>\n start(provider: string, input: HubSettingsOAuthInput): Promise<unknown>\n connectApiKey(provider: string, apiKey: string, metadata?: HubSettingsApiKeyMetadata): Promise<unknown>\n revoke(connectionId: string): Promise<unknown>\n health(connectionId: string): Promise<unknown>\n }\n tools: {\n search(query: string, options: { provider: string; limit: number }): Promise<unknown>\n }\n permissions: {\n list(connectionId: string): Promise<unknown>\n set(input: { connectionId: string; actionPath: string; decision: PolicyDecision }): Promise<unknown>\n delete(input: { connectionId: string; actionPath: string }): Promise<unknown>\n }\n}\n\n/** Validated, exact intent. The provider API key is deliberately not copied here. */\nexport type HubSettingsOperation =\n | { readonly operation: 'providers.list' | 'connections.list'; readonly target: 'caller-account' }\n | { readonly operation: 'oauth.start'; readonly provider: string; readonly input: Readonly<HubSettingsOAuthInput> }\n | { readonly operation: 'api-key.connect'; readonly provider: string; readonly metadata?: HubSettingsApiKeyMetadata }\n | { readonly operation: 'connection.revoke' | 'connection.health' | 'policies.list'; readonly connectionId: string }\n | { readonly operation: 'provider.actions'; readonly provider: string; readonly query: string; readonly limit: number }\n | { readonly operation: 'policy.set'; readonly connectionId: string; readonly actionPath: string; readonly decision: PolicyDecision }\n | { readonly operation: 'policy.reset'; readonly connectionId: string; readonly actionPath: string }\n\n/** Server-derived application identity, not fields read from browser input. */\nexport interface HubSettingsPrincipal {\n readonly userId: string\n readonly sessionId: string\n readonly workspaceId: string\n}\n\nexport interface HubSettingsGrant {\n readonly authorized: true\n readonly principal: HubSettingsPrincipal\n}\n\nexport interface HubSettingsClientBinding {\n readonly client: HubSettingsClient\n /** Reassert the identity against which the credential was actually resolved. */\n readonly principal: HubSettingsPrincipal\n /** Never env/admin credentials, another owner's key, or a brokered execution token. */\n readonly credentialSource: 'caller-account'\n}\n\nexport interface HubSettingsContext {\n /** Application-owned mount path, without a trailing slash. Default /api/hub/settings. */\n basePath?: string\n /**\n * Local path of the page that renders `HubConnectCallbackPage`. When set, an\n * OAuth start must return to exactly this path with the provider, nonce and\n * context that the integrations panel adds, and nothing else.\n */\n oauthCallbackPath?: string\n /**\n * Required on EVERY valid operation, including reads. Validate the current\n * session, CSRF protection, workspace role and exact target/decision here.\n * Return a denial Response or throw the app's auth Response to reject.\n * The body has been consumed; use the validated intent, not request.json().\n * OAuth success, connection ownership/policy, app consent and workspace\n * binding are separate facts. An execution grant is not a settings grant.\n */\n authorize(request: Request, operation: HubSettingsOperation): Promise<HubSettingsGrant | Response>\n /** Called only after authorization. Resolve the caller's linked account SDK client server-side. */\n resolveClient(principal: HubSettingsPrincipal): Promise<HubSettingsClientBinding>\n}\n\nexport interface HubSettingsRoutes {\n /** Exact method/path allowlist under basePath; never forwards request headers or arbitrary paths. */\n handle(request: Request): Promise<Response>\n}\n\nfunction json(value: unknown, status = 200, headers: Record<string, string> = {}): Response {\n return Response.json(value, { status, headers: { 'Cache-Control': 'no-store', ...headers } })\n}\n\nfunction invalid(): never {\n // Do not reflect request values: API keys and OAuth parameters can be sensitive.\n throw json({ error: 'Invalid Hub settings request', code: 'HUB_INVALID_INPUT' }, 400)\n}\n\nfunction record(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) invalid()\n return value as Record<string, unknown>\n}\n\nfunction onlyKeys(value: Record<string, unknown>, allowed: readonly string[]): void {\n if (Object.keys(value).some((key) => !allowed.includes(key))) invalid()\n}\n\nfunction text(value: unknown, max = 256): string {\n if (typeof value !== 'string' || !value.trim() || value.length > max || /[\\u0000-\\u001f\\u007f]/.test(value)) invalid()\n return value\n}\n\nfunction identifier(value: unknown): string {\n const id = text(value, 128)\n if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(id)) invalid()\n return id\n}\n\nfunction action(value: unknown): string {\n const path = text(value)\n // An exact dotted action, never a provider wildcard, path, glob or pattern.\n if (!/^[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+)+$/.test(path)) invalid()\n return path\n}\n\nfunction metadata(value: unknown): HubSettingsApiKeyMetadata {\n const input = record(value)\n if ('propertyId' in input) {\n onlyKeys(input, ['propertyId', 'currency'])\n return { propertyId: text(input.propertyId), ...(input.currency === undefined ? {} : { currency: text(input.currency) }) }\n }\n onlyKeys(input, ['listings'])\n if (!Array.isArray(input.listings) || input.listings.length === 0 || input.listings.length > 200) invalid()\n return { listings: input.listings.map((item) => {\n const listing = record(item)\n onlyKeys(listing, ['id', 'pms'])\n return { id: text(listing.id), pms: text(listing.pms) }\n }) }\n}\n\nfunction oauthInput(body: Record<string, unknown>, url: URL, provider: string, callbackPath: string | undefined): HubSettingsOAuthInput {\n onlyKeys(body, ['returnUrl', 'connectionParameters'])\n const returnUrl = text(body.returnUrl, 2048)\n let destination: URL\n try { destination = new URL(returnUrl) } catch { invalid() }\n if (!['https:', 'http:'].includes(destination.protocol) || destination.origin !== url.origin || destination.username || destination.password) invalid()\n if (callbackPath !== undefined && !isHubConnectCallbackUrl(destination, callbackPath, provider)) invalid()\n const input: HubSettingsOAuthInput = { returnUrl }\n if (body.connectionParameters !== undefined) {\n const parameters = record(body.connectionParameters)\n if (Object.keys(parameters).length > 20) invalid()\n input.connectionParameters = Object.fromEntries(Object.entries(parameters).map(([key, value]) => {\n identifier(key)\n // These are non-secret provider setup values, never Hub auth or identity overrides.\n if (/^(?:user|userid|owner|ownerid|workspace|workspaceid|team|teamid|principal|principalid|session|sessionid|authorization|headers|cookie|apikey|token|accesstoken|refreshtoken|clientsecret|secret|credentials?|appid|clientid)$/.test(key.replace(/[_-]/g, '').toLowerCase())) invalid()\n return [key, text(value, 1024)]\n }))\n }\n return input\n}\n\nfunction query(url: URL, allowed: readonly string[]): void {\n for (const key of url.searchParams.keys()) {\n if (!allowed.includes(key) || url.searchParams.getAll(key).length !== 1) invalid()\n }\n}\n\nasync function body(request: Request): Promise<Record<string, unknown>> {\n if ((request.headers.get('content-type')?.split(';')[0] ?? '').trim().toLowerCase() !== 'application/json') {\n throw json({ error: 'Expected application/json', code: 'HUB_INVALID_INPUT' }, 415)\n }\n const [value, error] = await parseJsonObjectBody(request, { maxBytes: 64 * 1024 })\n if (error) { error.headers.set('Cache-Control', 'no-store'); throw error }\n return value\n}\n\n/** Snapshot nested intent before application callbacks can observe it. */\nfunction freeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const child of Object.values(value)) freeze(child)\n Object.freeze(value)\n }\n return value\n}\n\nfunction isPrincipal(value: unknown): value is HubSettingsPrincipal {\n if (value === null || typeof value !== 'object') return false\n const principal = value as Partial<HubSettingsPrincipal>\n return [principal.userId, principal.sessionId, principal.workspaceId].every((part) => typeof part === 'string' && part.trim().length > 0)\n}\n\ninterface Prepared {\n intent: HubSettingsOperation\n call(client: HubSettingsClient): Promise<unknown>\n}\n\nconst ROUTES = [\n { kind: 'providers', path: /^\\/providers$/, methods: ['GET'] },\n { kind: 'connections', path: /^\\/connections$/, methods: ['GET'] },\n { kind: 'oauth', path: /^\\/connections\\/([^/]+)\\/start$/, methods: ['POST'] },\n { kind: 'api-key', path: /^\\/connections\\/([^/]+)\\/connect-key$/, methods: ['POST'] },\n { kind: 'revoke', path: /^\\/connections\\/([^/]+)$/, methods: ['DELETE'] },\n { kind: 'health', path: /^\\/connections\\/([^/]+)\\/health$/, methods: ['POST'] },\n { kind: 'actions', path: /^\\/providers\\/([^/]+)\\/actions$/, methods: ['GET'] },\n { kind: 'policies', path: /^\\/policies$/, methods: ['GET', 'PUT', 'DELETE'] },\n] as const\n\nasync function prepare(request: Request, basePath: string, callbackPath: string | undefined): Promise<Prepared | Response> {\n const url = new URL(request.url)\n if (!url.pathname.startsWith(`${basePath}/`)) return json({ error: 'Not found' }, 404)\n const path = url.pathname.slice(basePath.length)\n const route = ROUTES.find((candidate) => candidate.path.test(path))\n if (!route) return json({ error: 'Not found' }, 404)\n if (!(route.methods as readonly string[]).includes(request.method)) {\n return json({ error: 'Method not allowed' }, 405, { Allow: route.methods.join(', ') })\n }\n const target = route.path.exec(path)?.[1]\n const isPolicyRead = route.kind === 'policies' && request.method === 'GET'\n const isActions = route.kind === 'actions'\n query(url, isPolicyRead ? ['connectionId'] : isActions ? ['query', 'limit'] : [])\n const hasJson = route.kind === 'oauth' || route.kind === 'api-key' || (route.kind === 'policies' && !isPolicyRead)\n if (!hasJson && request.body !== null) {\n // Workers may expose an empty body stream for a bodyless POST.\n const reader = request.body.getReader()\n let emptyChunks = 0\n try {\n for (;;) {\n const chunk = await reader.read()\n if (chunk.done) break\n if (chunk.value.byteLength > 0) invalid()\n // Limit empty chunks before authorization; bodyless requests reach EOF.\n if (++emptyChunks > 16) invalid()\n }\n } finally {\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n\n if (route.kind === 'providers') return { intent: { operation: 'providers.list', target: 'caller-account' }, call: (hub) => hub.connections.providers() }\n if (route.kind === 'connections') return { intent: { operation: 'connections.list', target: 'caller-account' }, call: (hub) => hub.connections.list() }\n if (isPolicyRead) {\n const connectionId = identifier(url.searchParams.get('connectionId'))\n return { intent: { operation: 'policies.list', connectionId }, call: (hub) => hub.permissions.list(connectionId) }\n }\n if (route.kind === 'policies') {\n const input = await body(request)\n onlyKeys(input, request.method === 'PUT' ? ['connectionId', 'actionPath', 'decision'] : ['connectionId', 'actionPath'])\n const connectionId = identifier(input.connectionId)\n const actionPath = action(input.actionPath)\n if (request.method === 'DELETE') return { intent: { operation: 'policy.reset', connectionId, actionPath }, call: (hub) => hub.permissions.delete({ connectionId, actionPath }) }\n const decision = input.decision\n if (decision !== 'allow' && decision !== 'ask' && decision !== 'deny') invalid()\n return { intent: { operation: 'policy.set', connectionId, actionPath, decision }, call: (hub) => hub.permissions.set({ connectionId, actionPath, decision }) }\n }\n const id = identifier(target)\n if (isActions) {\n const search = url.searchParams.get('query') ?? ''\n if (search.length > 512 || /[\\u0000-\\u001f\\u007f]/.test(search)) invalid()\n const rawLimit = url.searchParams.get('limit') ?? '200'\n if (!/^[1-9][0-9]*$/.test(rawLimit)) invalid()\n const limit = Number(rawLimit)\n if (limit > 200) invalid()\n return { intent: { operation: 'provider.actions', provider: id, query: search, limit }, call: (hub) => hub.tools.search(search, { provider: id, limit }) }\n }\n if (route.kind === 'oauth') {\n const input = freeze(oauthInput(await body(request), url, id, callbackPath))\n return { intent: { operation: 'oauth.start', provider: id, input }, call: (hub) => hub.connections.start(id, input) }\n }\n if (route.kind === 'api-key') {\n const input = await body(request)\n onlyKeys(input, ['apiKey', 'metadata'])\n const apiKey = text(input.apiKey, 16 * 1024)\n const setup = input.metadata === undefined ? undefined : freeze(metadata(input.metadata))\n return { intent: { operation: 'api-key.connect', provider: id, ...(setup === undefined ? {} : { metadata: setup }) }, call: (hub) => hub.connections.connectApiKey(id, apiKey, setup) }\n }\n if (route.kind === 'health') return { intent: { operation: 'connection.health', connectionId: id }, call: (hub) => hub.connections.health(id) }\n if (route.kind === 'revoke') return { intent: { operation: 'connection.revoke', connectionId: id }, call: (hub) => hub.connections.revoke(id) }\n return invalid()\n}\n\n/** Build the finite, application-authorized Hub settings server boundary. */\nexport function createHubSettingsRoutes(ctx: HubSettingsContext): HubSettingsRoutes {\n if (typeof ctx.authorize !== 'function' || typeof ctx.resolveClient !== 'function') {\n throw new TypeError('Hub settings requires authorize and resolveClient callbacks')\n }\n const basePath = ctx.basePath ?? '/api/hub/settings'\n if (!/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(basePath)) throw new TypeError('Invalid Hub settings basePath')\n const callbackPath = ctx.oauthCallbackPath\n if (callbackPath !== undefined && !/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(callbackPath)) throw new TypeError('Invalid Hub OAuth callback path')\n\n return { async handle(request) {\n let prepared: Prepared | Response\n try { prepared = await prepare(request, basePath, callbackPath) } catch (error) {\n if (error instanceof Response) return error\n throw error\n }\n if (prepared instanceof Response) return prepared\n // Auth throws intentionally propagate. No SDK/client lookup has occurred.\n const grant = await ctx.authorize(request, freeze(prepared.intent))\n if (grant instanceof Response) return grant\n if (grant?.authorized !== true || !isPrincipal(grant.principal)) {\n return json({ error: 'Hub settings authorization required', code: 'HUB_FORBIDDEN' }, 403)\n }\n const principal = Object.freeze({ userId: grant.principal.userId, sessionId: grant.principal.sessionId, workspaceId: grant.principal.workspaceId })\n try {\n const bound = await ctx.resolveClient(principal)\n if (bound?.credentialSource !== 'caller-account' || !isPrincipal(bound.principal) ||\n bound.principal.userId !== principal.userId || bound.principal.sessionId !== principal.sessionId || bound.principal.workspaceId !== principal.workspaceId) {\n return json({ error: 'Hub settings caller binding mismatch', code: 'HUB_FORBIDDEN' }, 403)\n }\n // Client resolution can outlive a session or role grant. Recheck before the Hub effect.\n const renewed = await ctx.authorize(request, prepared.intent)\n if (renewed instanceof Response) return renewed\n if (renewed?.authorized !== true || !isPrincipal(renewed.principal) ||\n renewed.principal.userId !== principal.userId || renewed.principal.sessionId !== principal.sessionId || renewed.principal.workspaceId !== principal.workspaceId) {\n return json({ error: 'Hub settings authorization required', code: 'HUB_FORBIDDEN' }, 403)\n }\n return json(await prepared.call(bound.client))\n } catch (error) {\n // Structural detection survives SDK copies without a runtime peer import.\n if (error instanceof Error && error.name === 'HubSdkError' && typeof (error as { code?: unknown }).code === 'string') {\n const { code, status } = error as Error & { code: string; status?: number }\n const fallback = code === 'HUB_INVALID_INPUT' ? 400 : code === 'HUB_UNAUTHENTICATED' ? 401 : code === 'HUB_FORBIDDEN' ? 403 : 502\n const httpStatus = typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? status : fallback\n // Never echo upstream details/message: they can contain submitted credentials.\n return json({ error: 'Hub settings request failed', code }, httpStatus)\n }\n throw error\n }\n } }\n}\n","/**\n * Platform billing HTTP transport + tier state for apps on the shared\n * Tangle balance model (id.tangle.tools). Reads authenticate as the user via\n * their per-user platform key (the platform resolves the caller from the\n * key; service or impersonation headers on read routes are rejected). The\n * deduct write authenticates as the product service (`Bearer <serviceToken>`\n * + `X-Service-Name`) and names the target user in the body. Also provides a\n * fetch-backed implementation of the `/billing` module's\n * `PlatformBillingClient` seam (type-only import — no runtime coupling).\n */\n\nimport type { PlatformBillingClient, PlatformIdentity } from '../billing/index'\nimport { resolveTangleExecutionEnvironment } from '../runtime/model'\n\n/** Define available subscription tiers for the TanglePlan service */\nexport type TanglePlanTier = 'free' | 'pro' | 'enterprise'\n\n/** 'pro' | 'enterprise' pass through; anything else (null, unknown) → 'free'. */\nexport function normalizeTanglePlanTier(plan: string | null | undefined): TanglePlanTier {\n return plan === 'pro' || plan === 'enterprise' ? plan : 'free'\n}\n\n/** Represent platform billing HTTP errors with status code and detailed message */\nexport class PlatformBillingHttpError extends Error {\n constructor(\n readonly status: number,\n detail: string,\n ) {\n super(`Platform request failed (${status}): ${detail}`)\n this.name = 'PlatformBillingHttpError'\n }\n}\n\n/** Structural guard (name + numeric status) — robust across module instances. */\nexport function isPlatformBillingHttpError(error: unknown): error is PlatformBillingHttpError {\n return (\n error instanceof Error &&\n error.name === 'PlatformBillingHttpError' &&\n typeof (error as { status?: unknown }).status === 'number'\n )\n}\n\n/** Define HTTP options for platform billing including base URL, service token, product slug, fetch implementation, and timeout */\nexport interface PlatformBillingHttpOptions {\n /** Platform root, e.g. https://id.tangle.tools (trailing slashes stripped). */\n baseUrl: string\n /** Used only by `deduct()`; resolved lazily so reads never require it.\n * Throws at call time when empty. */\n serviceToken: string | (() => string)\n /** Product slug — the `X-Service-Name` header and the deduct `product` field. */\n productSlug: string\n fetchImpl?: typeof fetch\n /** Default 10 000. */\n timeoutMs?: number\n}\n\n/** Describe subscription tier and status information for a platform user */\nexport interface PlatformSubscriptionInfo {\n tier: TanglePlanTier\n status: string | null\n}\n\n/** Describe the platform balance and lifetime spending with an optional update timestamp */\nexport interface PlatformBalanceSnapshot {\n balance: number\n lifetimeSpent: number\n updatedAt?: string\n}\n\n/** Describe a product's usage and spending metrics on the platform */\nexport interface PlatformUsageProductRow {\n product: string | null\n totalSpent: number\n count: number\n}\n\n/** Lifecycle of a per-product seat subscription, mirroring the Stripe states\n * the platform persists. 'none' = the user has never held this seat. */\nexport type SeatStatus = 'none' | 'active' | 'trialing' | 'past_due' | 'canceled'\n\n/** Price and included shared-wallet credit for one seat billing period. */\nexport interface ProductSeatOfferPeriod {\n priceCents: number\n includedCreditsCents: number\n}\n\n/** Commercial terms returned by the platform's product catalog. Products use\n * this exact object for display instead of duplicating prices in UI copy. */\nexport interface ProductSeatOffer {\n currency: 'usd'\n interval: 'month'\n recurring: ProductSeatOfferPeriod\n introductory: ProductSeatOfferPeriod | null\n}\n\n/**\n * Per-product entitlement snapshot from the platform — the single read that\n * tells a product whether to show its workspace or the seat paywall. Shape\n * matches `GET /v1/billing/product-entitlement?product=<id>`.\n *\n * `hasSeat` is computed platform-side from the raw seat row.\n * It is true for an active or trialing seat whose period has not lapsed.\n * `onFreeTier` remains in the wire shape for compatibility, but this client\n * always returns false and never uses it for access.\n */\nexport interface ProductEntitlement {\n seatStatus: SeatStatus\n /** ISO timestamp the active seat's paid period runs until; null when none. */\n currentPeriodEnd: string | null\n /** Cumulative inference spend across the whole suite, in dollars. */\n lifetimeSpentUsd: number\n hasSeat: boolean\n /** Platform access decision, including funded balance and identity policy. */\n paidAccess?: boolean\n onFreeTier: boolean\n /** Present when the platform exposes catalog-backed commercial terms. */\n offer?: ProductSeatOffer\n}\n\nfunction productSeatOffer(value: unknown): ProductSeatOffer | undefined {\n if (!value || typeof value !== 'object') return undefined\n const candidate = value as Record<string, unknown>\n if (candidate.currency !== 'usd' || candidate.interval !== 'month') return undefined\n\n const period = (input: unknown, allowZeroPrice: boolean): ProductSeatOfferPeriod | undefined => {\n if (!input || typeof input !== 'object') return undefined\n const data = input as Record<string, unknown>\n const priceCents = data.priceCents\n const includedCreditsCents = data.includedCreditsCents\n if (\n typeof priceCents !== 'number' ||\n !Number.isSafeInteger(priceCents) ||\n (allowZeroPrice ? priceCents < 0 : priceCents <= 0) ||\n typeof includedCreditsCents !== 'number' ||\n !Number.isSafeInteger(includedCreditsCents) ||\n includedCreditsCents < 0\n ) {\n return undefined\n }\n return { priceCents, includedCreditsCents }\n }\n\n const recurring = period(candidate.recurring, false)\n const introductory =\n candidate.introductory === null\n ? null\n : period(candidate.introductory, true)\n if (!recurring || introductory === undefined) return undefined\n return {\n currency: 'usd',\n interval: 'month',\n recurring,\n introductory,\n }\n}\n\n/** Define methods to interact with platform billing endpoints using user or service authentication */\nexport interface PlatformBillingHttp {\n /** GET /v1/plans/current (user bearer). */\n getSubscription(userApiKey: string): Promise<PlatformSubscriptionInfo>\n /** GET /v1/billing/balance (user bearer). */\n getBalance(userApiKey: string): Promise<PlatformBalanceSnapshot>\n /** GET /v1/billing/usage (user bearer). */\n getUsageByProduct(userApiKey: string): Promise<PlatformUsageProductRow[]>\n /** GET /v1/billing/product-entitlement?product=<id> (user bearer). */\n getProductEntitlement(userApiKey: string, productId: string): Promise<ProductEntitlement>\n /** POST /v1/billing/deduct (service token). */\n deduct(input: {\n platformUserId: string\n amountUsd: number\n type: string\n description: string\n referenceId: string\n }): Promise<void>\n /** Absolute URL of the platform's billing-management surface. */\n billingUrl(): string\n /** Absolute URL of the catalog-backed seat checkout for `productId`. */\n seatCheckoutUrl(productId: string): string\n}\n\n/** Create a PlatformBillingHttp instance configured with given options and default behaviors */\nexport function createPlatformBillingHttp(opts: PlatformBillingHttpOptions): PlatformBillingHttp {\n const baseUrl = opts.baseUrl.replace(/\\/+$/, '')\n if (!baseUrl) throw new Error('PlatformBillingHttpOptions.baseUrl is required')\n if (!opts.productSlug) throw new Error('PlatformBillingHttpOptions.productSlug is required')\n const fetchImpl = opts.fetchImpl ?? fetch\n const timeoutMs = opts.timeoutMs ?? 10_000\n\n function resolveServiceToken(): string {\n const token = typeof opts.serviceToken === 'function' ? opts.serviceToken() : opts.serviceToken\n if (!token) throw new Error('A platform service token is required for deduct')\n return token\n }\n\n async function request<T>(path: string, init: RequestInit, headers: Headers): Promise<T> {\n const res = await fetchImpl(`${baseUrl}${path}`, {\n ...init,\n headers,\n signal: AbortSignal.timeout(timeoutMs),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { error?: { message?: string } } | null\n throw new PlatformBillingHttpError(res.status, body?.error?.message ?? res.statusText)\n }\n return res.json() as Promise<T>\n }\n\n function userRead<T>(userApiKey: string, path: string): Promise<T> {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${userApiKey}`)\n return request<T>(path, {}, headers)\n }\n\n return {\n async getSubscription(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: { subscription?: { plan?: string | null; status?: string | null } | null }\n }>(userApiKey, '/v1/plans/current')\n const sub = body.data?.subscription ?? null\n return { tier: normalizeTanglePlanTier(sub?.plan), status: sub?.status ?? null }\n },\n\n async getBalance(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: { balance?: number; lifetimeSpent?: number; updatedAt?: string }\n }>(userApiKey, '/v1/billing/balance')\n return {\n balance: body.data?.balance ?? 0,\n lifetimeSpent: body.data?.lifetimeSpent ?? 0,\n updatedAt: body.data?.updatedAt,\n }\n },\n\n async getUsageByProduct(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: Array<{ product?: string | null; totalSpent?: number; count?: number }>\n }>(userApiKey, '/v1/billing/usage')\n return (body.data ?? []).map((row) => ({\n product: row.product ?? null,\n totalSpent: row.totalSpent ?? 0,\n count: row.count ?? 0,\n }))\n },\n\n async getProductEntitlement(userApiKey, productId) {\n const slug = encodeURIComponent(productId)\n const body = await userRead<{\n success: boolean\n data?: {\n seatStatus?: SeatStatus | null\n currentPeriodEnd?: string | null\n lifetimeSpentUsd?: number | null\n hasSeat?: boolean | null\n paidAccess?: unknown\n onFreeTier?: boolean | null\n offer?: unknown\n }\n }>(userApiKey, `/v1/billing/product-entitlement?product=${slug}`)\n const data = body.data ?? {}\n const hasSeat = data.hasSeat === true\n const offer = productSeatOffer(data.offer)\n return {\n seatStatus: data.seatStatus ?? 'none',\n currentPeriodEnd: data.currentPeriodEnd ?? null,\n lifetimeSpentUsd: data.lifetimeSpentUsd ?? 0,\n hasSeat,\n ...('paidAccess' in data ? { paidAccess: data.paidAccess === true } : {}),\n // Product-funded free access is retired. Ignore stale server signals.\n onFreeTier: false,\n ...(offer ? { offer } : {}),\n }\n },\n\n async deduct(input) {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${resolveServiceToken()}`)\n headers.set('X-Service-Name', opts.productSlug)\n headers.set('Content-Type', 'application/json')\n await request('/v1/billing/deduct', {\n method: 'POST',\n body: JSON.stringify({\n userId: input.platformUserId,\n amount: input.amountUsd,\n type: input.type,\n product: opts.productSlug,\n description: input.description,\n referenceId: input.referenceId,\n }),\n }, headers)\n },\n\n billingUrl() {\n return `${baseUrl}/app/billing`\n },\n\n seatCheckoutUrl(productId) {\n return seatCheckoutUrl(baseUrl, productId)\n },\n }\n}\n\n/**\n * Platform Stripe checkout URL for a product's catalog-backed seat. The\n * platform resolves the product-specific price and introductory offer from the\n * `product` query param. Mirrors the `billingUrl()` shape — a deterministic\n * platform-rooted URL with no client-side pricing decisions.\n */\nexport function seatCheckoutUrl(baseUrl: string, productId: string): string {\n const root = baseUrl.replace(/\\/+$/, '')\n return `${root}/app/billing/seat/checkout?product=${encodeURIComponent(productId)}`\n}\n\n// ── Tier policy + composed state ────────────────────────────────────────────\n\n/** Define policy settings for concurrency and overage allowance in a tangle tier */\nexport interface TangleTierPolicy {\n concurrency: number\n overageAllowed: boolean\n}\n\n/** Define default concurrency and overage policies for each TanglePlanTier level */\nexport const DEFAULT_TANGLE_TIER_POLICY: Record<TanglePlanTier, TangleTierPolicy> = {\n free: { concurrency: 1, overageAllowed: false },\n pro: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true },\n enterprise: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true },\n}\n\n/** Describe the state of a Tangle plan tier including subscription, balance, spending, and concurrency details */\nexport interface TangleTierState {\n tier: TanglePlanTier\n subscriptionStatus: string | null\n remainingBalanceUsd: number\n lifetimeSpentUsd: number\n concurrency: number\n overageAllowed: boolean\n}\n\n/**\n * Read subscription + balance and project them onto the tier policy. A\n * null/absent key fails CLOSED (free tier, zero balance) — a billable run is\n * never started against an unknown balance. Platform errors throw; callers\n * on the billable path choose their posture explicitly.\n */\nexport async function readTangleTierState(\n http: PlatformBillingHttp,\n userApiKey: string | null | undefined,\n policy: Record<TanglePlanTier, TangleTierPolicy> = DEFAULT_TANGLE_TIER_POLICY,\n): Promise<TangleTierState> {\n if (!userApiKey) {\n return {\n tier: 'free',\n subscriptionStatus: null,\n remainingBalanceUsd: 0,\n lifetimeSpentUsd: 0,\n ...policy.free,\n }\n }\n const [subscription, balance] = await Promise.all([\n http.getSubscription(userApiKey),\n http.getBalance(userApiKey),\n ])\n return {\n tier: subscription.tier,\n subscriptionStatus: subscription.status,\n remainingBalanceUsd: balance.balance,\n lifetimeSpentUsd: balance.lifetimeSpent,\n ...policy[subscription.tier],\n }\n}\n\n// ── Per-product seat entitlement ────────────────────────────────────────────\n\n/** Product-funded free inference spend is disabled. */\nexport const FREE_TIER_SPEND_CAP_USD = 0\n\n/**\n * Default name of the per-app feature flag that controls seat billing.\n * Explicit values override the environment default.\n */\nexport const DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR = 'SEAT_BILLING_ENABLED'\n\n/** Define options to configure seat billing flag environment variables and override flag name */\nexport interface SeatBillingFlagOptions {\n env?: Record<string, string | undefined>\n /** Override the flag name; default {@link DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR}. */\n flagEnvVar?: string\n}\n\n/**\n * An explicit flag controls seat billing in every environment.\n * Without a flag, known development and test environments default to OFF.\n * Deployed and unknown environments default to ON.\n */\nexport function isSeatBillingEnabled(opts: SeatBillingFlagOptions = {}): boolean {\n const env =\n opts.env ??\n (typeof process !== 'undefined' ? (process.env as Record<string, string | undefined>) : undefined)\n if (!env) return true\n const flag = env[opts.flagEnvVar ?? DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR]?.trim().toLowerCase()\n if (flag) return !['false', '0', 'off', 'disabled', 'no'].includes(flag)\n const environment = resolveTangleExecutionEnvironment(env)\n return environment !== 'development' && environment !== 'test'\n}\n\n/**\n * Read a user's entitlement for one product.\n * An absent key or disabled flag returns no access.\n * Transport failures propagate so the product can return a retryable error.\n *\n * @param flag — pass {@link isSeatBillingEnabled} (or your own boolean) so the\n * product owns when the gate engages. When false, no network call is made.\n */\nexport async function getProductEntitlement(\n http: Pick<PlatformBillingHttp, 'getProductEntitlement'>,\n userApiKey: string | null | undefined,\n productId: string,\n flag = true,\n): Promise<ProductEntitlement> {\n if (!flag) return unavailableEntitlement()\n if (!userApiKey) return unavailableEntitlement()\n return http.getProductEntitlement(userApiKey, productId)\n}\n\nfunction unavailableEntitlement(): ProductEntitlement {\n return {\n seatStatus: 'none',\n currentPeriodEnd: null,\n lifetimeSpentUsd: 0,\n hasSeat: false,\n onFreeTier: false,\n }\n}\n\n/** Honor platform access policy; older endpoints provide only seat authority. */\nexport function isProductEntitled(ent: ProductEntitlement): boolean {\n return ent.paidAccess === undefined ? ent.hasSeat === true : ent.paidAccess === true\n}\n\n// ── Bridge onto the /billing seam ───────────────────────────────────────────\n\n/** Define a contract for resolving platform identities based on user identifiers */\nexport interface PlatformIdentityStore {\n resolveIdentity(userId: string): Promise<PlatformIdentity | null>\n}\n\n/** Concrete fetch-backed `PlatformBillingClient<TanglePlanTier>` for\n * `createPlatformBalanceManager` (from `/billing`). */\nexport function createTanglePlatformBillingClient(\n http: PlatformBillingHttp,\n identity: PlatformIdentityStore,\n): PlatformBillingClient<TanglePlanTier> {\n return {\n resolveIdentity: (userId) => identity.resolveIdentity(userId),\n getPlan: async (apiKey) => (await http.getSubscription(apiKey)).tier,\n getBalance: async (apiKey) => {\n const snapshot = await http.getBalance(apiKey)\n return { balance: snapshot.balance, lifetimeSpent: snapshot.lifetimeSpent }\n },\n getUsageByProduct: (apiKey) => http.getUsageByProduct(apiKey),\n deduct: (input) => http.deduct(input),\n }\n}\n","/**\n * Bill work an agent app runs for a Platform agent key to that key's one cap.\n *\n * An owner approves an agent key with one lifetime cap shared across every\n * product. Work the app runs for the key must spend that cap, even when the\n * owner already has their own credential in the app:\n *\n * - Model calls: `modelKey` delegates a Router key from the agent key that\n * spends its cap directly (\"spend-through\"). Router refuses every call once\n * the cap is spent, so a turn cannot run past it.\n * - Work the app cannot route through the key, such as compute in a sandbox\n * the owner's own credential pays for: `hold` reserves the work's maximum\n * against the cap before it starts, and `consume` spends what it measured,\n * up to the hold, without charging the owner's wallet again.\n *\n * A spent or insufficient cap answers 402 `agent_key.budget_exhausted`, so an\n * app refuses the work before it starts. Web-standard fetch only.\n */\n\nexport interface AgentSpendRefusal {\n status: 402 | 403 | 503\n code: string\n message: string\n}\n\nexport type AgentSpendOutcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: AgentSpendRefusal }\n\nexport interface PlatformAgentSpendOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name. */\n serviceName: string\n serviceToken: string | (() => string)\n /** The Platform product this app bills, e.g. `gtm-agent`. */\n product: string\n fetch?: typeof fetch\n}\n\nexport interface PlatformAgentSpend {\n /**\n * A Router key whose charges spend the agent key's cap. `name` must start\n * `auto:`; give each piece of work its own.\n */\n modelKey(input: { agentKey: string; name: string; expiresAt: Date }): Promise<AgentSpendOutcome<{ key: string; keyId: string | null }>>\n /** Reserve up to `amountUsd` of the agent key's cap for work billed elsewhere. */\n hold(input: { keyId: string; amountUsd: number; referenceId: string; expiresAt: Date }): Promise<AgentSpendOutcome<{ authorizationId: string }>>\n /** Spend what the work measured, at most the hold. A retry repeats the amount. */\n consume(input: { authorizationId: string; amountUsd: number }): Promise<AgentSpendOutcome<{ consumedUsd: number }>>\n /** Return a hold whose work never ran. */\n release(authorizationId: string): Promise<AgentSpendOutcome<null>>\n}\n\nconst REQUEST_TIMEOUT_MS = 10_000\n\nconst budgetExhausted: AgentSpendRefusal = {\n status: 402,\n code: 'agent_key.budget_exhausted',\n message: 'The key has spent, or cannot cover, the cap its owner approved.',\n}\n\nfunction refusal(status: number, code: unknown): AgentSpendRefusal {\n if (code === 'KEY_BUDGET_EXHAUSTED' || code === 'KEY_BUDGET_EXCEEDED' || code === 'PRODUCT_BUDGET_EXCEEDED') return budgetExhausted\n if (code === 'INSUFFICIENT_BALANCE') {\n return { status: 402, code: 'agent_key.payment_required', message: \"The key owner's Tangle account has no credit.\" }\n }\n if (code === 'EMAIL_VERIFICATION_REQUIRED') {\n return { status: 403, code: 'agent_key.owner_unverified', message: 'The key owner must verify their Tangle email.' }\n }\n if (status >= 500 || status === 429 || code === 'PLATFORM_BUSY') {\n return { status: 503, code: 'agent_key.spend_unavailable', message: 'Platform could not record the spend; retry.' }\n }\n return { status: 403, code: 'agent_key.spend_refused', message: 'Platform refused to bill this work to the key.' }\n}\n\ninterface PlatformBody {\n success?: unknown\n data?: { key?: unknown; id?: unknown; consumedAmount?: unknown }\n error?: { code?: unknown }\n}\n\nexport function createPlatformAgentSpend(options: PlatformAgentSpendOptions): PlatformAgentSpend {\n const fetchImpl = options.fetch ?? fetch\n const base = options.platformUrl.replace(/\\/+$/, '')\n\n async function call(path: string, body: unknown): Promise<{ status: number; body: PlatformBody } | null> {\n const token = typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n try {\n const response = await fetchImpl(`${base}${path}`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'x-service-name': options.serviceName,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: (await response.json().catch(() => ({}))) as PlatformBody }\n } catch {\n return null\n }\n }\n\n const unavailable = (): { succeeded: false; error: AgentSpendRefusal } => ({ succeeded: false, error: refusal(503, null) })\n\n return {\n async modelKey({ agentKey, name, expiresAt }) {\n const result = await call('/v1/keys/delegate', {\n sourceKey: agentKey, name, product: 'router', spendThrough: true, expiresAt: expiresAt.toISOString(),\n })\n if (!result) return unavailable()\n const key = result.body.data?.key\n if (result.status !== 201 || typeof key !== 'string') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n const keyId = result.body.data?.id\n return { succeeded: true, value: { key, keyId: typeof keyId === 'string' ? keyId : null } }\n },\n async hold({ keyId, amountUsd, referenceId, expiresAt }) {\n const result = await call('/v1/billing/authorizations', {\n keyId, amount: amountUsd, type: 'key_cap', product: options.product, referenceId, expiresAt: expiresAt.toISOString(),\n })\n if (!result) return unavailable()\n const id = result.body.data?.id\n if (result.status !== 201 || typeof id !== 'string') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n return { succeeded: true, value: { authorizationId: id } }\n },\n async consume({ authorizationId, amountUsd }) {\n const result = await call(`/v1/billing/authorizations/${encodeURIComponent(authorizationId)}/consume`, { amount: amountUsd })\n if (!result) return unavailable()\n const consumed = result.body.data?.consumedAmount\n if (result.status !== 200 || typeof consumed !== 'number') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n return { succeeded: true, value: { consumedUsd: consumed } }\n },\n async release(authorizationId) {\n const result = await call(`/v1/billing/authorizations/${encodeURIComponent(authorizationId)}/release`, {})\n if (!result) return unavailable()\n if (result.status !== 200) return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n return { succeeded: true, value: null }\n },\n }\n}\n","/**\n * Record a person's consent that this app's Sandbox service key may bill them.\n *\n * An app that creates sandboxes under its own service key and names the\n * signed-in person as `billingOwnerId` needs that person's billing delegation\n * grant, or the Sandbox API refuses the create with\n * `BILLING_DELEGATION_GRANT_REQUIRED`. Platform records the grant from the key\n * the person gave the app at sign-in (`POST /v1/keys/billing-delegation-grants`),\n * so the app records it before its first delegated create. The call is\n * idempotent on Platform.\n *\n * A refusal answers a typed code and a message written for the person, so an\n * app can show it as is. Web-standard fetch only.\n */\n\nexport interface BillingConsentRefusal {\n status: 402 | 403 | 503\n code: 'billing_consent.payer_not_chargeable' | 'billing_consent.refused' | 'billing_consent.unavailable'\n /** Written for the person whose account would pay. */\n message: string\n /** Platform's own code, for logs. */\n platformCode: string | null\n}\n\nexport type BillingConsentOutcome =\n | { succeeded: true; value: { created: boolean } }\n | { succeeded: false; error: BillingConsentRefusal }\n\nexport interface PlatformBillingConsentOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name. */\n serviceName: string\n serviceToken: string | (() => string)\n fetch?: typeof fetch\n}\n\nexport interface PlatformBillingConsent {\n /**\n * Record that the owner of `payerKey` consents to `serviceKey` billing them\n * for sandboxes. `payerKey` is the key the person gave this app at sign-in;\n * `serviceKey` is the listed key the app creates sandboxes under.\n */\n consent(input: { payerKey: string; serviceKey: string }): Promise<BillingConsentOutcome>\n}\n\nconst REQUEST_TIMEOUT_MS = 10_000\n\nconst notChargeable: BillingConsentRefusal = {\n status: 402,\n code: 'billing_consent.payer_not_chargeable',\n message: 'Your Tangle account has no credit for sandbox use yet. Add credit in your Tangle account, then open the terminal again.',\n platformCode: 'PAYER_NOT_CHARGEABLE',\n}\n\nfunction refusal(status: number | null, platformCode: string | null): BillingConsentRefusal {\n if (platformCode === 'PAYER_NOT_CHARGEABLE') return notChargeable\n if (status === null || status >= 500 || status === 429) {\n return {\n status: 503,\n code: 'billing_consent.unavailable',\n message: 'Tangle could not record your sandbox billing consent right now. Try again in a moment.',\n platformCode,\n }\n }\n return {\n status: 403,\n code: 'billing_consent.refused',\n message: 'Tangle did not accept your sign-in for sandbox billing. Sign out and sign in again.',\n platformCode,\n }\n}\n\ninterface PlatformBody {\n data?: { id?: unknown; created?: unknown }\n error?: { code?: unknown }\n}\n\nexport function createPlatformBillingConsent(options: PlatformBillingConsentOptions): PlatformBillingConsent {\n const fetchImpl = options.fetch ?? fetch\n const base = options.platformUrl.replace(/\\/+$/, '')\n // Resolved values only: a cancelled request never settles, so a shared\n // in-flight promise would hang every later caller.\n let delegate: { serviceKey: string; keyId: string } | null = null\n\n async function request(path: string, init: RequestInit): Promise<{ status: number; body: PlatformBody } | null> {\n try {\n const response = await fetchImpl(`${base}${path}`, {\n ...init,\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: (await response.json().catch(() => ({}))) as PlatformBody }\n } catch {\n return null\n }\n }\n\n const codeOf = (body: PlatformBody): string | null => (typeof body.error?.code === 'string' ? body.error.code : null)\n\n return {\n async consent({ payerKey, serviceKey }) {\n if (delegate?.serviceKey !== serviceKey) {\n const self = await request('/v1/keys/self', { headers: { authorization: `Bearer ${serviceKey}` } })\n const keyId = self?.body.data?.id\n if (!self || self.status !== 200 || typeof keyId !== 'string' || !keyId) {\n return { succeeded: false, error: refusal(self ? Math.max(self.status, 500) : null, self ? codeOf(self.body) : null) }\n }\n delegate = { serviceKey, keyId }\n }\n const token = typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n const result = await request('/v1/keys/billing-delegation-grants', {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'x-service-name': options.serviceName,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ sourceKey: payerKey, delegateKeyId: delegate.keyId }),\n })\n if (!result) return { succeeded: false, error: refusal(null, null) }\n if (result.status === 200 || result.status === 201) {\n return { succeeded: true, value: { created: result.status === 201 } }\n }\n const platformCode = codeOf(result.body)\n // The service key's own account pays for itself and needs no grant.\n if (platformCode === 'PAYER_IS_DELEGATE_OWNER') return { succeeded: true, value: { created: false } }\n return { succeeded: false, error: refusal(result.status, platformCode) }\n },\n }\n}\n","/**\n * Delegated product keys: a child key minted from the paying user's linked\n * Tangle key, scoped to one product, its models and its budget, so an app\n * never sends the user's own key to Router or Sandbox.\n *\n * WHY ONE. Seven apps minted these by hand (Tax, Legal, GTM, Creative,\n * Builder, Hardware, workcomp; survey 2026-10-12) with different scope,\n * expiry and revocation rules, and four never noticed a key Platform had\n * revoked, superseded or expired.\n *\n * TWO WAYS TO HOLD ONE.\n * - Per turn: `client.delegate` before the turn, `client.revoke` after it.\n * Nothing is cached, so nothing stale can be handed out.\n * - Per workspace: `createDelegatedKeyProvisioner` plugs this client into\n * `createIdentityBoundWorkspaceKeyManager` (`./billing`), which owns the\n * durable, lease-fenced slot. Its `getKey` asks Platform's\n * `verify-by-id`, which also refuses superseded generations, and reports\n * any key that is not valid as missing, so the manager marks it revoked\n * and mints a fresh one on the next use.\n *\n * THE MINT CONTRACT (`POST /v1/keys/delegate`, service-authenticated; the\n * response is the key row plus `attribution`, and the granted expiry is\n * `attribution.expiresAt`). The child is checked field by field: an\n * `sk-tan-` key that is not the source, the canonical name, this service as\n * provisioner and attribution origin, the requested product, resource, model\n * set and payer, a budget no larger than requested, and an expiry in the\n * future and no later than requested. A child that fails is revoked and\n * refused; if that revoke fails too, the refusal carries the child's id (never\n * its key) so the app can retire it.\n *\n * Errors carry a code and status, never a response body, a source key or a\n * child key.\n */\n\nconst REQUEST_TIMEOUT_MS = 10_000\nconst KEY_PREFIX = 'sk-tan-'\nconst AUTO_PREFIX = 'auto:'\n/** Products whose key names Platform qualifies as `auto:<service>:<product>:...` (key-provenance.ts). */\nconst PRODUCT_QUALIFIED = new Set(['router', 'sandbox'])\n\nexport type DelegatedKeyCode =\n | 'delegated_key.payment_required'\n | 'delegated_key.budget_exhausted'\n | 'delegated_key.owner_unverified'\n | 'delegated_key.unavailable'\n | 'delegated_key.refused'\n | 'delegated_key.response_invalid'\n | 'delegated_key.invalid_request'\n\nexport interface DelegatedKeyRefusal {\n status: number\n code: DelegatedKeyCode\n message: string\n /** Set when an untrusted child could not be revoked: the id (never the key) the app must retire. */\n unrevokedKeyId?: string\n}\n\nexport type DelegatedKeyOutcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: DelegatedKeyRefusal }\n\n/** How the child is paid for: its own budget, or spending the source's budget directly. */\nexport type DelegatedKeyBudget =\n | { usd: number; monthlyUsd?: number }\n | { spendThrough: true; monthlyUsd?: number }\n\nexport interface DelegatedKeyRequest {\n /** The payer's linked `sk-tan-` key. Never a shared app key. */\n sourceKey: string\n /** The logical slot, e.g. `turn:<id>`. Sent as Platform's canonical name; see {@link canonicalDelegatedKeyName}. */\n name: string\n product: 'router' | 'sandbox' | (string & {})\n resource?: { type: string; id: string }\n /** The only models the child may call. */\n allowedModels?: readonly string[]\n budget?: DelegatedKeyBudget\n rpmLimit?: number\n expiresAt: Date\n /** Checked against the child's attribution when given: the payer's Platform user id, the source key's id, and\n * the origin app Platform carries over from the source (an app's SSO key; a personal key has none). */\n expect?: { payerId?: string; sourceKeyId?: string; originAppId?: string | null }\n}\n\nexport interface DelegatedKey {\n key: string\n id: string\n /** The canonical name Platform stored. */\n name: string\n product: string\n /** The expiry Platform granted (`attribution.expiresAt`), never later than requested. */\n expiresAt: Date\n allowedModels: readonly string[] | null\n budgetUsd: number | null\n}\n\nexport interface PlatformDelegatedKeyClientOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name; Platform admits delegation per named service. */\n serviceName: string\n serviceToken: string | (() => string)\n fetch?: typeof fetch\n now?: () => number\n}\n\n/** Platform's `verify-by-id` verdict on one key, secret-free. */\nexport interface DelegatedKeyVerdict {\n valid: boolean\n /** Platform's reason when not valid, e.g. `key_revoked`, `budget_exhausted`. */\n invalidReason?: string\n budgetUsd?: number\n budgetRemaining?: number\n expiresAt?: string\n}\n\n/**\n * Identifies a key's slot for Platform's service-authenticated `revoke-slot`. Without `name` and `product`,\n * the client reads them from the key itself (`GET /v1/keys/:id`, which an SSO source may call), so a\n * provisioner restarted since the mint can still retire the key. Tax and Legal need `sourceKeyId`; GTM\n * and Builder admit `revoke-slot` only for their protected and preview keys, so their other keys keep\n * the refused DELETE as a typed error.\n */\nexport interface DelegatedKeySlotRef {\n userId: string\n name?: string\n product?: string\n sourceKeyId?: string\n}\n\nexport interface PlatformDelegatedKeyClient {\n delegate(request: DelegatedKeyRequest): Promise<DelegatedKeyOutcome<DelegatedKey>>\n /** Platform's authoritative verdict (`verify-by-id`), including revoked, expired and spent keys. */\n verify(input: { keyId: string; product: string }): Promise<DelegatedKeyOutcome<DelegatedKeyVerdict>>\n /**\n * `DELETE /v1/keys/:id` with the source key; a key already gone counts as revoked. Platform refuses key\n * mutations from a service-provisioned source (an app's SSO key) with 403; given `slot`, the client then\n * retires the slot through `revoke-slot` with the service token.\n */\n revoke(input: { sourceKey: string; keyId: string; slot?: DelegatedKeySlotRef }): Promise<DelegatedKeyOutcome<null>>\n /** Children of the source key in one slot, from `GET /v1/keys` with the source key. */\n listChildren(input: { sourceKey: string; name: string; product: string }): Promise<DelegatedKeyOutcome<Array<{ id: string }>>>\n}\n\n/**\n * The name Platform stores for a slot: `auto:<service>:<product>:<logical>` for\n * Router and Sandbox keys (Platform's `canonicalProvisionedKeyName`), so the\n * echo can be checked exactly. A name already qualified is kept.\n */\nexport function canonicalDelegatedKeyName(input: { serviceName: string; product: string; name: string }): string {\n const logical = input.name.startsWith(AUTO_PREFIX) ? input.name.slice(AUTO_PREFIX.length) : input.name\n if (!PRODUCT_QUALIFIED.has(input.product)) return `${AUTO_PREFIX}${logical}`\n if (logical.startsWith(`${input.serviceName}:${input.product}:`)) return `${AUTO_PREFIX}${logical}`\n const withoutService = logical.startsWith(`${input.serviceName}:`) ? logical.slice(input.serviceName.length + 1) : logical\n return `${AUTO_PREFIX}${input.serviceName}:${input.product}:${withoutService}`\n}\n\nfunction refusal(status: number, code: unknown): DelegatedKeyRefusal {\n if (code === 'INSUFFICIENT_BALANCE') {\n return { status: 402, code: 'delegated_key.payment_required', message: \"The payer's Tangle account has no credit.\" }\n }\n if (code === 'KEY_BUDGET_EXHAUSTED' || code === 'KEY_BUDGET_EXCEEDED' || code === 'PRODUCT_BUDGET_EXCEEDED') {\n return { status: 402, code: 'delegated_key.budget_exhausted', message: \"The payer's key has spent the budget it allows.\" }\n }\n if (code === 'EMAIL_VERIFICATION_REQUIRED') {\n return { status: 403, code: 'delegated_key.owner_unverified', message: 'The payer must verify their Tangle email.' }\n }\n if (status >= 500 || status === 429 || code === 'PLATFORM_BUSY') {\n return { status: 503, code: 'delegated_key.unavailable', message: 'Platform could not answer; retry.' }\n }\n return { status: 403, code: 'delegated_key.refused', message: 'Platform refused to delegate this key.' }\n}\n\nconst failure = <T,>(status: number, code: DelegatedKeyCode, message: string, extra: Partial<DelegatedKeyRefusal> = {}): DelegatedKeyOutcome<T> =>\n ({ succeeded: false, error: { status, code, message, ...extra } })\n\nconst record = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null\n\nfunction sameSet(granted: unknown, requested: readonly string[]): boolean {\n if (!Array.isArray(granted) || granted.some(model => typeof model !== 'string')) return false\n const a = [...new Set(granted as string[])].sort()\n const b = [...new Set(requested)].sort()\n return granted.length === a.length && a.length === b.length && a.every((model, index) => model === b[index])\n}\n\n/** Why the minted child cannot be trusted, or null. Each check names its field, never its value. */\nfunction childProblem(data: Record<string, unknown>, request: DelegatedKeyRequest, name: string, serviceName: string, nowMs: number): string | null {\n const key = data.key\n const id = data.id\n if (typeof id !== 'string' || !id) return 'no key id'\n if (typeof key !== 'string' || !key.startsWith(KEY_PREFIX) || key.length <= KEY_PREFIX.length) return 'not an sk-tan child key'\n if (key === request.sourceKey) return 'the source key itself'\n if (typeof data.prefix === 'string' && !key.startsWith(data.prefix)) return 'a key that does not match its prefix'\n if (data.name !== name) return 'a different name'\n if (data.product !== request.product) return 'a different product'\n if (data.provisionedByService !== serviceName) return 'a different provisioner'\n if (data.scopes !== null && !(Array.isArray(data.scopes) && data.scopes.length === 0)) return 'control-plane scopes'\n // Omitted, the child inherits the source's model restriction, which only narrows it.\n if (request.allowedModels && !sameSet(data.allowedModels, request.allowedModels)) return 'a different model set'\n const budget = request.budget\n if (budget && 'usd' in budget && !(typeof data.budgetUsd === 'number' && data.budgetUsd <= budget.usd)) return 'a budget larger than requested'\n if (budget?.monthlyUsd !== undefined && !(typeof data.monthlyBudgetUsd === 'number' && data.monthlyBudgetUsd <= budget.monthlyUsd)) {\n return 'a monthly budget larger than requested'\n }\n\n const attribution = record(data.attribution)\n if (!attribution) return 'no attribution'\n if (attribution.version !== 1 || attribution.targetService !== request.product) return 'attribution for another target'\n if (request.expect?.originAppId !== undefined && (attribution.originAppId ?? null) !== request.expect.originAppId) {\n return 'attribution from another app'\n }\n const parent = attribution.delegatedFromKeyId\n if (typeof parent !== 'string' || !parent || parent === id) return 'attribution without its parent key'\n if (request.expect?.sourceKeyId !== undefined && parent !== request.expect.sourceKeyId) return 'attribution for another source key'\n if (attribution.payerType !== 'user') return 'attribution to a non-user payer'\n if (request.expect?.payerId !== undefined && attribution.payerId !== request.expect.payerId) return 'attribution to another payer'\n if ((attribution.resourceType ?? null) !== (request.resource?.type ?? null) || (attribution.resourceId ?? null) !== (request.resource?.id ?? null)) {\n return 'attribution for another resource'\n }\n const expiresAt = typeof attribution.expiresAt === 'string' ? Date.parse(attribution.expiresAt) : NaN\n if (!Number.isFinite(expiresAt) || expiresAt <= nowMs || expiresAt > request.expiresAt.getTime()) return 'an expiry in the past or past the request'\n return null\n}\n\nexport function createPlatformDelegatedKeyClient(options: PlatformDelegatedKeyClientOptions): PlatformDelegatedKeyClient {\n const fetchImpl = options.fetch ?? fetch\n const now = options.now ?? Date.now\n const base = options.platformUrl.replace(/\\/+$/, '')\n const serviceToken = () => typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n\n async function call(path: string, init: { method: string; bearer: string; service: boolean; body?: unknown }) {\n try {\n const response = await fetchImpl(`${base}${path}`, {\n method: init.method,\n headers: {\n authorization: `Bearer ${init.bearer}`,\n ...(init.service ? { 'x-service-name': options.serviceName } : {}),\n ...(init.body === undefined ? {} : { 'content-type': 'application/json' }),\n },\n ...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: record(await response.json().catch(() => null)) }\n } catch {\n return null\n }\n }\n\n const client: PlatformDelegatedKeyClient = {\n async delegate(request) {\n if (!request.sourceKey.startsWith(KEY_PREFIX)) return failure(400, 'delegated_key.invalid_request', 'The source must be a linked sk-tan- key.')\n if (request.expiresAt.getTime() <= now()) return failure(400, 'delegated_key.invalid_request', 'The expiry must be in the future.')\n const name = canonicalDelegatedKeyName({ serviceName: options.serviceName, product: request.product, name: request.name })\n const budget = request.budget\n const result = await call('/v1/keys/delegate', {\n method: 'POST', bearer: serviceToken(), service: true, body: {\n sourceKey: request.sourceKey,\n name,\n product: request.product,\n ...(request.resource ? { resourceType: request.resource.type, resourceId: request.resource.id } : {}),\n ...(budget && 'usd' in budget ? { budgetUsd: budget.usd } : {}),\n ...(budget && 'spendThrough' in budget ? { spendThrough: true } : {}),\n ...(budget?.monthlyUsd !== undefined ? { monthlyBudgetUsd: budget.monthlyUsd } : {}),\n ...(request.allowedModels ? { allowedModels: [...new Set(request.allowedModels)] } : {}),\n ...(request.rpmLimit !== undefined ? { rpmLimit: request.rpmLimit } : {}),\n // Omitted, Platform copies the source's scopes onto the child; a product key carries none.\n scopes: [],\n expiresAt: request.expiresAt.toISOString(),\n },\n })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n const data = record(result.body?.data)\n if (result.status !== 201 || result.body?.success !== true || !data) {\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n }\n const problem = childProblem(data, request, name, options.serviceName, now())\n if (problem) {\n // A child Platform minted but this app cannot trust is retired, never returned.\n const id = typeof data.id === 'string' && data.id ? data.id : null\n const owner = request.expect?.payerId\n ? { userId: request.expect.payerId, name, product: request.product,\n ...(request.expect.sourceKeyId ? { sourceKeyId: request.expect.sourceKeyId } : {}) }\n : undefined\n const revoked = id ? await client.revoke({ sourceKey: request.sourceKey, keyId: id, ...(owner ? { slot: owner } : {}) }) : null\n return failure(502, 'delegated_key.response_invalid', `Platform returned ${problem}.`,\n id && !revoked?.succeeded ? { unrevokedKeyId: id } : {})\n }\n const attribution = record(data.attribution)!\n return { succeeded: true, value: {\n key: data.key as string, id: data.id as string, name, product: request.product,\n expiresAt: new Date(attribution.expiresAt as string),\n allowedModels: request.allowedModels ? [...new Set(request.allowedModels)] : null,\n budgetUsd: typeof data.budgetUsd === 'number' ? data.budgetUsd : null,\n } }\n },\n\n async verify({ keyId, product }) {\n const result = await call('/v1/keys/verify-by-id', {\n method: 'POST', bearer: serviceToken(), service: true, body: { keyId, expectedProduct: product },\n })\n // Fail closed: anything but a well-formed verdict for this key is not evidence about it.\n if (!result || result.status >= 500 || result.status === 429) return { succeeded: false, error: refusal(503, null) }\n const body = result.body\n if (result.status !== 200 || typeof body?.valid !== 'boolean' || (body.valid && body.keyId !== keyId)) {\n return failure(502, 'delegated_key.response_invalid', 'Platform returned no verification verdict for this key.')\n }\n const number = (value: unknown) => typeof value === 'number' && Number.isFinite(value) ? value : undefined\n return { succeeded: true, value: {\n valid: body.valid,\n ...(typeof body.invalidReason === 'string' ? { invalidReason: body.invalidReason } : {}),\n ...(number(body.budgetUsd) !== undefined ? { budgetUsd: number(body.budgetUsd) } : {}),\n ...(number(body.budgetRemaining) !== undefined ? { budgetRemaining: number(body.budgetRemaining) } : {}),\n ...(typeof body.expiresAt === 'string' ? { expiresAt: body.expiresAt } : {}),\n } }\n },\n\n async revoke({ sourceKey, keyId, slot }) {\n const result = await call(`/v1/keys/${encodeURIComponent(keyId)}`, { method: 'DELETE', bearer: sourceKey, service: false })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n if (result.status === 404 || (result.status >= 200 && result.status < 300 && result.body?.success === true)) {\n return { succeeded: true, value: null }\n }\n if (result.status === 403 && slot) {\n let name = slot.name\n let product = slot.product\n if (!name || !product) {\n const row = await call(`/v1/keys/${encodeURIComponent(keyId)}`, { method: 'GET', bearer: sourceKey, service: false })\n const data = record(row?.body?.data)\n if (row?.status === 404) return { succeeded: true, value: null }\n if (!row || row.status !== 200 || typeof data?.name !== 'string' || typeof data.product !== 'string') {\n return { succeeded: false, error: refusal(row?.status ?? 503, null) }\n }\n if (data.revokedAt) return { succeeded: true, value: null }\n name = data.name\n product = data.product\n }\n const retired = await call('/v1/keys/auto-provisioned/revoke-slot', {\n method: 'POST', bearer: serviceToken(), service: true, body: {\n userId: slot.userId, name, product, childKeyId: keyId,\n ...(slot.sourceKeyId ? { sourceKeyId: slot.sourceKeyId } : {}),\n },\n })\n if (!retired) return { succeeded: false, error: refusal(503, null) }\n if (retired.status >= 200 && retired.status < 300 && retired.body?.success === true) return { succeeded: true, value: null }\n return { succeeded: false, error: refusal(retired.status, record(retired.body?.error)?.code) }\n }\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n },\n\n async listChildren({ sourceKey, name, product }) {\n const canonical = canonicalDelegatedKeyName({ serviceName: options.serviceName, product, name })\n const result = await call('/v1/keys', { method: 'GET', bearer: sourceKey, service: false })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n const rows = result.body?.data\n if (result.status !== 200 || result.body?.success !== true || !Array.isArray(rows)) {\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n }\n return { succeeded: true, value: rows.flatMap((row) => {\n const value = record(row)\n return value && typeof value.id === 'string' && value.name === canonical && value.product === product && !value.revokedAt\n ? [{ id: value.id }] : []\n }) }\n },\n }\n return client\n}\n\n/** The `DurableWorkspaceKeyProvisioner` shape (`./billing`), kept structural so this module stays standalone. */\nexport interface DelegatedKeyProvisioner {\n createKey(input: { name: string; product: string; budgetUsd: number; expiresAt: string; idempotencyKey: string }): Promise<{\n id: string; key: string; budgetUsd?: number | null; expiresAt?: string | null\n }>\n getKey(id: string): Promise<{ budgetUsd?: number | null; expiresAt?: string | null }>\n revokeKey(id: string): Promise<unknown>\n findCreatedKeys(input: { name: string; product: string; sourceKeyId?: string | null }): Promise<Array<{ id: string }>>\n}\n\n/** A remote key the durable manager must treat as gone (it marks the row revoked and mints again). */\nexport class DelegatedKeyMissingError extends Error {\n readonly status = 404\n readonly code = 'not_found'\n constructor(keyId: string) {\n super(`Platform no longer accepts key ${keyId}`)\n this.name = 'DelegatedKeyMissingError'\n }\n}\n\n/** A Platform refusal surfaced to the durable manager. Carries the typed refusal, never a key. */\nexport class DelegatedKeyRefusalError extends Error {\n constructor(readonly refusal: DelegatedKeyRefusal) {\n super(refusal.message)\n this.name = 'DelegatedKeyRefusalError'\n }\n}\n\n/** Platform reasons that mean the key will never work again: the manager revokes the row and mints a fresh key. */\nconst GONE_REASONS = new Set([\n 'key_not_found', 'key_revoked', 'key_expired', 'key_lineage_revoked',\n 'parent_key_not_found', 'parent_key_revoked', 'parent_key_expired', 'parent_key_lineage_revoked',\n 'ancestor_key_not_found', 'ancestor_key_revoked', 'ancestor_key_expired', 'ancestor_key_lineage_revoked',\n])\nconst SPENT_REASONS = new Set(['budget_exhausted', 'monthly_budget_exhausted'])\n\n/**\n * Plug the client into `createIdentityBoundWorkspaceKeyManager` for a\n * workspace-held key. Pass the manager `nameForIdentity` returning a logical\n * slot name (the client sends Platform's canonical `auto:` form).\n *\n * `getKey` reads Platform's verdict: a key gone for good is reported missing\n * (the manager marks it revoked and mints again); a spent key is reported\n * exhausted (the manager revokes it remotely and mints again); a funding or\n * eligibility refusal is a typed error, so a lapse never retires a key that\n * still works.\n */\nexport function createDelegatedKeyProvisioner(input: {\n client: PlatformDelegatedKeyClient\n sourceKey: string\n product: string\n resource?: { type: string; id: string }\n allowedModels?: readonly string[]\n monthlyBudgetUsd?: number\n rpmLimit?: number\n expect?: { payerId?: string; sourceKeyId?: string; originAppId?: string | null }\n /** Enables the `revoke-slot` fallback when the source is an app's SSO key (Platform refuses its key mutations). */\n payerId?: string\n}): DelegatedKeyProvisioner {\n const product = input.product\n // The revoke-slot fallback needs the payer; the client reads each key's slot name itself.\n const slotOwner: DelegatedKeySlotRef | undefined = input.payerId\n ? { userId: input.payerId, ...(input.expect?.sourceKeyId ? { sourceKeyId: input.expect.sourceKeyId } : {}) }\n : undefined\n return {\n async createKey(create) {\n const minted = await input.client.delegate({\n sourceKey: input.sourceKey, name: create.name, product,\n ...(input.resource ? { resource: input.resource } : {}),\n ...(input.allowedModels ? { allowedModels: input.allowedModels } : {}),\n budget: { usd: create.budgetUsd, ...(input.monthlyBudgetUsd !== undefined ? { monthlyUsd: input.monthlyBudgetUsd } : {}) },\n ...(input.rpmLimit !== undefined ? { rpmLimit: input.rpmLimit } : {}),\n expiresAt: new Date(create.expiresAt),\n ...(input.expect ? { expect: input.expect } : {}),\n })\n if (!minted.succeeded) throw new DelegatedKeyRefusalError(minted.error)\n return { id: minted.value.id, key: minted.value.key, budgetUsd: minted.value.budgetUsd, expiresAt: minted.value.expiresAt.toISOString() }\n },\n async getKey(id) {\n const verdict = await input.client.verify({ keyId: id, product })\n if (!verdict.succeeded) throw new DelegatedKeyRefusalError(verdict.error)\n const v = verdict.value\n if (v.valid) {\n return {\n ...(v.budgetUsd !== undefined ? { budgetUsd: v.budgetUsd } : {}),\n ...(v.budgetUsd !== undefined && v.budgetRemaining !== undefined ? { budgetSpent: Math.max(0, v.budgetUsd - v.budgetRemaining) } : {}),\n ...(v.expiresAt ? { expiresAt: v.expiresAt } : {}),\n }\n }\n if (v.invalidReason && GONE_REASONS.has(v.invalidReason)) throw new DelegatedKeyMissingError(id)\n if (v.invalidReason && SPENT_REASONS.has(v.invalidReason)) {\n // Spent: the manager sees no budget left and revokes the child before minting again.\n return { budgetUsd: v.budgetUsd ?? 0, budgetSpent: v.budgetUsd ?? 0, ...(v.expiresAt ? { expiresAt: v.expiresAt } : {}) }\n }\n throw new DelegatedKeyRefusalError({ status: 403, code: 'delegated_key.refused',\n message: `Platform refused the key for now (${v.invalidReason ?? 'no reason'}).` })\n },\n async revokeKey(id) {\n const revoked = await input.client.revoke({ sourceKey: input.sourceKey, keyId: id, ...(slotOwner ? { slot: slotOwner } : {}) })\n if (!revoked.succeeded) throw new DelegatedKeyRefusalError(revoked.error)\n return null\n },\n async findCreatedKeys(find) {\n const listed = await input.client.listChildren({ sourceKey: input.sourceKey, name: find.name, product: find.product })\n if (!listed.succeeded) throw new DelegatedKeyRefusalError(listed.error)\n return listed.value\n },\n }\n}\n"],"mappings":"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","names":["identifier","body","body","body","REQUEST_TIMEOUT_MS","refusal","body","REQUEST_TIMEOUT_MS","refusal","record","body"]}
1
+ {"version":3,"sources":["../../src/platform/sso-identity-store.ts","../../src/platform/hub-connect-callback.ts","../../src/platform/hub-settings.ts","../../src/platform/billing.ts","../../src/platform/agent-spend.ts","../../src/platform/billing-consent.ts","../../src/platform/delegated-keys.ts"],"sourcesContent":["/**\n * Better Auth `account`-table store for first-party Tangle identity sign-in\n * (`protocol: 'identity'`) on D1 / SQLite.\n *\n * The platform link is Better Auth's own external-identity row:\n * `account(providerId = 'tangle', accountId = <platform user id>, userId)`.\n * Run {@link TANGLE_IDENTITY_ACCOUNT_INDEXES_SQL} in a product migration; its\n * two partial unique indexes make the link one-per-user and\n * one-per-platform-user, which the write path relies on.\n *\n * Schema expectations are Better Auth's default SQLite model with camelCase\n * columns: `user(id, name, email, emailVerified, createdAt, updatedAt)`,\n * `session(id, userId, token, expiresAt, ipAddress, userAgent, createdAt,\n * updatedAt)` and `account(id, userId, accountId, providerId, createdAt,\n * updatedAt)`, with unix-second integer timestamps (Drizzle `mode:\n * 'timestamp'`). D1 is structural: Cloudflare `D1Database` satisfies\n * {@link TangleIdentityD1Like}.\n */\n\nimport {\n normalizeTangleSsoEmail,\n resolveTangleSsoAccount,\n TangleSsoAccountConflictError,\n TangleSsoUserCreateError,\n type TangleIdentitySsoAccountStore,\n type TangleSsoAccountResolution,\n type TangleSsoLocalAccount,\n} from './sso'\n\n/** Better Auth `account.providerId` for the Tangle platform link. */\nexport const TANGLE_IDENTITY_PROVIDER_ID = 'tangle'\n\n/** Partial unique indexes the store requires on Better Auth's `account` table. */\nexport const TANGLE_IDENTITY_ACCOUNT_INDEXES_SQL = [\n `CREATE UNIQUE INDEX IF NOT EXISTS account_tangle_platform_user ON account(accountId) WHERE providerId = '${TANGLE_IDENTITY_PROVIDER_ID}'`,\n `CREATE UNIQUE INDEX IF NOT EXISTS account_tangle_user ON account(userId) WHERE providerId = '${TANGLE_IDENTITY_PROVIDER_ID}'`,\n] as const\n\n/** A prepared D1 statement; Cloudflare `D1PreparedStatement` satisfies it. */\nexport interface TangleIdentityD1Statement {\n bind(...values: unknown[]): TangleIdentityD1Statement\n first<T = Record<string, unknown>>(): Promise<T | null>\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>\n run(): Promise<unknown>\n}\n\n/** The D1 surface the store needs. `batch` must be atomic, as D1's is. */\nexport interface TangleIdentityD1Like {\n prepare(query: string): TangleIdentityD1Statement\n batch(statements: TangleIdentityD1Statement[]): Promise<Array<{ meta?: { changes?: number } }>>\n}\n\n/**\n * A link table the product used before this store. During migration the store\n * reads it after `account` and mirrors new links into it, so a link that\n * exists in either place still signs in and a rollback still finds new links.\n * Remove the option once a reconcile query proves every legacy row has an\n * equal `account` row.\n */\nexport interface TangleIdentityLegacyLinkTable {\n table: string\n /** Column holding the local `user.id`; must be unique. */\n userIdColumn: string\n /** Column holding the platform user id; must be unique. */\n platformUserIdColumn: string\n}\n\nexport interface D1TangleIdentityStoreOptions {\n db: TangleIdentityD1Like\n /**\n * The signed-in local user for an explicit \"connect Tangle\" flow. A live\n * local session plus a verified platform exchange jointly authorize linking\n * that user, even when its local email is unverified or differs. The host\n * must prove the session started this flow (for example with a signed,\n * session-bound cookie).\n */\n linkingUserId?: string\n legacyLinkTable?: TangleIdentityLegacyLinkTable\n}\n\nconst SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction identifier(value: string, field: string): string {\n if (!SQL_IDENTIFIER.test(value)) throw new Error(`createD1TangleIdentityStore: invalid ${field}`)\n return value\n}\n\ninterface CandidateRow {\n userId: string\n email: string\n emailVerified: number | boolean | null\n accountPlatformUserId: string | null\n legacyPlatformUserId: string | null\n}\n\ninterface Candidate extends TangleSsoLocalAccount {\n /** The account row and the legacy row name different platform users. */\n divergent: boolean\n}\n\nfunction randomToken(): string {\n return Array.from(crypto.getRandomValues(new Uint8Array(32)), byte => byte.toString(16).padStart(2, '0')).join('')\n}\n\n/** Create the identity-protocol account store for one request. */\nexport function createD1TangleIdentityStore(options: D1TangleIdentityStoreOptions): TangleIdentitySsoAccountStore {\n const { db, linkingUserId } = options\n const provider = TANGLE_IDENTITY_PROVIDER_ID\n const legacy = options.legacyLinkTable && {\n table: identifier(options.legacyLinkTable.table, 'legacyLinkTable.table'),\n userId: identifier(options.legacyLinkTable.userIdColumn, 'legacyLinkTable.userIdColumn'),\n platformUserId: identifier(options.legacyLinkTable.platformUserIdColumn, 'legacyLinkTable.platformUserIdColumn'),\n }\n\n const selectAccount = `SELECT u.id AS userId, u.email AS email, u.emailVerified AS emailVerified,\n a.accountId AS accountPlatformUserId,\n ${legacy ? `l.${legacy.platformUserId}` : 'NULL'} AS legacyPlatformUserId\n FROM user u\n LEFT JOIN account a ON a.userId = u.id AND a.providerId = '${provider}'\n ${legacy ? `LEFT JOIN ${legacy.table} l ON l.${legacy.userId} = u.id` : ''}`\n\n function toCandidate(row: CandidateRow): Candidate {\n const fromAccount = row.accountPlatformUserId?.trim() || null\n const fromLegacy = row.legacyPlatformUserId?.trim() || null\n return {\n userId: row.userId,\n email: row.email,\n emailVerified: row.emailVerified === 1 || row.emailVerified === true,\n platformUserId: fromAccount ?? fromLegacy,\n divergent: Boolean(fromAccount && fromLegacy && fromAccount !== fromLegacy),\n }\n }\n\n async function candidates(email: string, platformUserId: string) {\n const where = legacy\n ? `WHERE lower(trim(u.email)) = ? OR a.accountId = ? OR l.${legacy.platformUserId} = ?`\n : 'WHERE lower(trim(u.email)) = ? OR a.accountId = ?'\n const values = legacy ? [email, platformUserId, platformUserId] : [email, platformUserId]\n const { results } = await db.prepare(`${selectAccount} ${where}`).bind(...values).all<CandidateRow>()\n const rows = results.map(toCandidate)\n return {\n divergent: rows.some(row => row.divergent),\n platformMatches: rows.filter(row => row.platformUserId === platformUserId),\n emailMatches: rows.filter(row => normalizeTangleSsoEmail(row.email) === email),\n }\n }\n\n const store: TangleIdentitySsoAccountStore = {\n async resolveAccount({ email, platformUserId }): Promise<TangleSsoAccountResolution> {\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const stableId = platformUserId.trim()\n const found = await candidates(normalizedEmail, stableId)\n if (found.divergent) return { kind: 'reject', reason: 'platform-id-email-conflict' }\n if (!linkingUserId) {\n return resolveTangleSsoAccount({\n email: normalizedEmail,\n platformUserId: stableId,\n platformMatches: found.platformMatches,\n emailMatches: found.emailMatches,\n })\n }\n\n const ownRow = await db.prepare(`${selectAccount} WHERE u.id = ?`).bind(linkingUserId).first<CandidateRow>()\n if (!ownRow) return { kind: 'reject', reason: 'email-match-mismatch' }\n const own = toCandidate(ownRow)\n if (own.divergent) return { kind: 'reject', reason: 'platform-id-email-conflict' }\n if (own.platformUserId && own.platformUserId !== stableId) {\n return { kind: 'reject', reason: 'email-platform-id-conflict' }\n }\n if (found.platformMatches.some(row => row.userId !== linkingUserId)\n || found.emailMatches.some(row => row.userId !== linkingUserId)) {\n return { kind: 'reject', reason: 'platform-id-email-conflict' }\n }\n return { kind: 'existing', userId: linkingUserId, matchedBy: 'platform-id' }\n },\n\n async upsertUserByEmail({ email, name, tangleUserId, resolution }) {\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const platformUserId = tangleUserId.trim()\n const current = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (current.kind === 'reject') throw new TangleSsoAccountConflictError(current.reason)\n if (current.kind === 'existing') {\n if (resolution.kind === 'existing' && resolution.userId !== current.userId) {\n throw new TangleSsoAccountConflictError('platform-id-email-conflict')\n }\n return { userId: current.userId }\n }\n\n if (resolution.kind !== 'create') throw new TangleSsoUserCreateError('The selected account changed')\n const userId = crypto.randomUUID()\n try {\n await db.prepare(`INSERT INTO user (id, name, email, emailVerified, createdAt, updatedAt)\n VALUES (?, ?, ?, 1, unixepoch(), unixepoch())`)\n .bind(userId, name || normalizedEmail, normalizedEmail).run()\n } catch {\n // A concurrent callback may have won the email UNIQUE race. Re-apply the\n // policy; never adopt that row by email alone.\n const after = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (after.kind === 'reject') throw new TangleSsoAccountConflictError(after.reason)\n if (after.kind === 'existing') return { userId: after.userId }\n throw new TangleSsoUserCreateError()\n }\n return { userId }\n },\n\n async createSession({ userId, expiresAt, ipAddress, userAgent }) {\n const token = randomToken()\n await db.prepare(`INSERT INTO session (id, userId, token, expiresAt, ipAddress, userAgent, createdAt, updatedAt)\n VALUES (?, ?, ?, ?, ?, ?, unixepoch(), unixepoch())`)\n .bind(crypto.randomUUID(), userId, token, Math.floor(expiresAt.getTime() / 1000), ipAddress, userAgent)\n .run()\n return { token }\n },\n\n async saveTangleLink({ userId, sessionToken, tangleUserId, email }) {\n const platformUserId = tangleUserId.trim()\n const normalizedEmail = normalizeTangleSsoEmail(email)\n const session = await db.prepare('SELECT userId FROM session WHERE token = ? AND expiresAt > unixepoch()')\n .bind(sessionToken).first<{ userId: string }>()\n if (session?.userId !== userId) throw new TangleSsoAccountConflictError('email-platform-id-conflict')\n const current = await store.resolveAccount({ email: normalizedEmail, platformUserId })\n if (current.kind === 'reject') throw new TangleSsoAccountConflictError(current.reason)\n if (current.kind !== 'existing' || current.userId !== userId) {\n throw new TangleSsoAccountConflictError('platform-id-email-conflict')\n }\n\n // One atomic batch: every statement re-checks the live session and the\n // email owner, and the final verified-email update runs only when this\n // exact link exists, so a lost race commits nothing and rejects.\n const liveSession = 'EXISTS (SELECT 1 FROM session WHERE token = ? AND userId = ? AND expiresAt > unixepoch())'\n const emailFree = 'NOT EXISTS (SELECT 1 FROM user WHERE lower(trim(email)) = ? AND id <> ?)'\n const linked = `EXISTS (SELECT 1 FROM account WHERE providerId = '${provider}' AND userId = ? AND accountId = ?)`\n const statements = [\n db.prepare(`INSERT INTO account (id, userId, accountId, providerId, createdAt, updatedAt)\n SELECT ?, ?, ?, '${provider}', unixepoch(), unixepoch()\n WHERE EXISTS (SELECT 1 FROM user WHERE id = ?) AND ${liveSession} AND ${emailFree}\n ON CONFLICT DO NOTHING`)\n .bind(crypto.randomUUID(), userId, platformUserId, userId, sessionToken, userId, normalizedEmail, userId),\n ]\n if (legacy) {\n statements.push(db.prepare(`INSERT INTO ${legacy.table} (${legacy.userId}, ${legacy.platformUserId})\n SELECT ?, ? WHERE ${linked}\n ON CONFLICT DO NOTHING`)\n .bind(userId, platformUserId, userId, platformUserId))\n }\n statements.push(db.prepare(`UPDATE user SET emailVerified = CASE WHEN lower(trim(email)) = ? THEN 1 ELSE emailVerified END,\n updatedAt = unixepoch()\n WHERE id = ? AND ${liveSession} AND ${linked} AND ${emailFree}`)\n .bind(normalizedEmail, userId, sessionToken, userId, userId, platformUserId, normalizedEmail, userId))\n const results = await db.batch(statements)\n if (results[results.length - 1]?.meta?.changes !== 1) {\n throw new TangleSsoAccountConflictError('email-platform-id-conflict')\n }\n },\n\n // `saveTangleLink` is one atomic batch, so a rejected call wrote nothing;\n // removing the unpublished session is the whole cleanup.\n async deleteSession({ sessionToken }) {\n await db.prepare('DELETE FROM session WHERE token = ?').bind(sessionToken).run()\n },\n }\n return store\n}\n","/**\n * The OAuth return contract shared by the browser popup and the settings\n * server. The popup appends exactly these parameters to the host's callback\n * path; the server accepts a return URL only in that shape.\n */\nconst HUB_CONNECT_CALLBACK_PARAMS = ['provider', 'nonce', 'context'] as const\n\n/** True when `returnUrl` is the host's callback for `provider`, as the popup builds it. */\nexport function isHubConnectCallbackUrl(returnUrl: URL, callbackPath: string, provider: string): boolean {\n if (returnUrl.pathname !== callbackPath || returnUrl.hash) return false\n const keys = [...returnUrl.searchParams.keys()]\n if (keys.length !== HUB_CONNECT_CALLBACK_PARAMS.length) return false\n if (!HUB_CONNECT_CALLBACK_PARAMS.every((key) => returnUrl.searchParams.getAll(key).length === 1)) return false\n const opaque = (value: string | null) => !!value && value.length <= 128 && /^[A-Za-z0-9_-]+$/.test(value)\n return returnUrl.searchParams.get('provider') === provider\n && opaque(returnUrl.searchParams.get('nonce'))\n && opaque(returnUrl.searchParams.get('context'))\n}\n","/** Finite, application-authorized account settings over the existing Hub SDK. */\nimport { parseJsonObjectBody } from '../web/core'\nimport { isHubConnectCallbackUrl } from './hub-connect-callback'\n\n/** Non-secret API-key setup shapes supported by the Hub SDK. */\nexport type HubSettingsApiKeyMetadata =\n | { propertyId: string; currency?: string }\n | { listings: Array<{ id: string; pms: string }> }\n\n/** Browser OAuth setup, excluding CLI mode and identity/credential overrides. */\nexport interface HubSettingsOAuthInput {\n returnUrl: string\n connectionParameters?: Record<string, string>\n}\n\ntype PolicyDecision = 'allow' | 'ask' | 'deny'\n\n/**\n * Structural subset of the existing SDK, with no execution methods. Keeping\n * this structural avoids imposing a Hub SDK peer on existing platform imports.\n */\nexport interface HubSettingsClient {\n connections: {\n providers(): Promise<unknown>\n list(): Promise<unknown>\n start(provider: string, input: HubSettingsOAuthInput): Promise<unknown>\n connectApiKey(provider: string, apiKey: string, metadata?: HubSettingsApiKeyMetadata): Promise<unknown>\n revoke(connectionId: string): Promise<unknown>\n health(connectionId: string): Promise<unknown>\n }\n tools: {\n search(query: string, options: { provider: string; limit: number }): Promise<unknown>\n }\n permissions: {\n list(connectionId: string): Promise<unknown>\n set(input: { connectionId: string; actionPath: string; decision: PolicyDecision }): Promise<unknown>\n delete(input: { connectionId: string; actionPath: string }): Promise<unknown>\n }\n}\n\n/** Validated, exact intent. The provider API key is deliberately not copied here. */\nexport type HubSettingsOperation =\n | { readonly operation: 'providers.list' | 'connections.list'; readonly target: 'caller-account' }\n | { readonly operation: 'oauth.start'; readonly provider: string; readonly input: Readonly<HubSettingsOAuthInput> }\n | { readonly operation: 'api-key.connect'; readonly provider: string; readonly metadata?: HubSettingsApiKeyMetadata }\n | { readonly operation: 'connection.revoke' | 'connection.health' | 'policies.list'; readonly connectionId: string }\n | { readonly operation: 'provider.actions'; readonly provider: string; readonly query: string; readonly limit: number }\n | { readonly operation: 'policy.set'; readonly connectionId: string; readonly actionPath: string; readonly decision: PolicyDecision }\n | { readonly operation: 'policy.reset'; readonly connectionId: string; readonly actionPath: string }\n\n/** Server-derived application identity, not fields read from browser input. */\nexport interface HubSettingsPrincipal {\n readonly userId: string\n readonly sessionId: string\n readonly workspaceId: string\n}\n\nexport interface HubSettingsGrant {\n readonly authorized: true\n readonly principal: HubSettingsPrincipal\n}\n\nexport interface HubSettingsClientBinding {\n readonly client: HubSettingsClient\n /** Reassert the identity against which the credential was actually resolved. */\n readonly principal: HubSettingsPrincipal\n /** Never env/admin credentials, another owner's key, or a brokered execution token. */\n readonly credentialSource: 'caller-account'\n}\n\nexport interface HubSettingsContext {\n /** Application-owned mount path, without a trailing slash. Default /api/hub/settings. */\n basePath?: string\n /**\n * Local path of the page that renders `HubConnectCallbackPage`. When set, an\n * OAuth start must return to exactly this path with the provider, nonce and\n * context that the integrations panel adds, and nothing else.\n */\n oauthCallbackPath?: string\n /**\n * Required on EVERY valid operation, including reads. Validate the current\n * session, CSRF protection, workspace role and exact target/decision here.\n * Return a denial Response or throw the app's auth Response to reject.\n * The body has been consumed; use the validated intent, not request.json().\n * OAuth success, connection ownership/policy, app consent and workspace\n * binding are separate facts. An execution grant is not a settings grant.\n */\n authorize(request: Request, operation: HubSettingsOperation): Promise<HubSettingsGrant | Response>\n /** Called only after authorization. Resolve the caller's linked account SDK client server-side. */\n resolveClient(principal: HubSettingsPrincipal): Promise<HubSettingsClientBinding>\n}\n\nexport interface HubSettingsRoutes {\n /** Exact method/path allowlist under basePath; never forwards request headers or arbitrary paths. */\n handle(request: Request): Promise<Response>\n}\n\nfunction json(value: unknown, status = 200, headers: Record<string, string> = {}): Response {\n return Response.json(value, { status, headers: { 'Cache-Control': 'no-store', ...headers } })\n}\n\nfunction invalid(): never {\n // Do not reflect request values: API keys and OAuth parameters can be sensitive.\n throw json({ error: 'Invalid Hub settings request', code: 'HUB_INVALID_INPUT' }, 400)\n}\n\nfunction record(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) invalid()\n return value as Record<string, unknown>\n}\n\nfunction onlyKeys(value: Record<string, unknown>, allowed: readonly string[]): void {\n if (Object.keys(value).some((key) => !allowed.includes(key))) invalid()\n}\n\nfunction text(value: unknown, max = 256): string {\n if (typeof value !== 'string' || !value.trim() || value.length > max || /[\\u0000-\\u001f\\u007f]/.test(value)) invalid()\n return value\n}\n\nfunction identifier(value: unknown): string {\n const id = text(value, 128)\n if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(id)) invalid()\n return id\n}\n\nfunction action(value: unknown): string {\n const path = text(value)\n // An exact dotted action, never a provider wildcard, path, glob or pattern.\n if (!/^[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+)+$/.test(path)) invalid()\n return path\n}\n\nfunction metadata(value: unknown): HubSettingsApiKeyMetadata {\n const input = record(value)\n if ('propertyId' in input) {\n onlyKeys(input, ['propertyId', 'currency'])\n return { propertyId: text(input.propertyId), ...(input.currency === undefined ? {} : { currency: text(input.currency) }) }\n }\n onlyKeys(input, ['listings'])\n if (!Array.isArray(input.listings) || input.listings.length === 0 || input.listings.length > 200) invalid()\n return { listings: input.listings.map((item) => {\n const listing = record(item)\n onlyKeys(listing, ['id', 'pms'])\n return { id: text(listing.id), pms: text(listing.pms) }\n }) }\n}\n\nfunction oauthInput(body: Record<string, unknown>, url: URL, provider: string, callbackPath: string | undefined): HubSettingsOAuthInput {\n onlyKeys(body, ['returnUrl', 'connectionParameters'])\n const returnUrl = text(body.returnUrl, 2048)\n let destination: URL\n try { destination = new URL(returnUrl) } catch { invalid() }\n if (!['https:', 'http:'].includes(destination.protocol) || destination.origin !== url.origin || destination.username || destination.password) invalid()\n if (callbackPath !== undefined && !isHubConnectCallbackUrl(destination, callbackPath, provider)) invalid()\n const input: HubSettingsOAuthInput = { returnUrl }\n if (body.connectionParameters !== undefined) {\n const parameters = record(body.connectionParameters)\n if (Object.keys(parameters).length > 20) invalid()\n input.connectionParameters = Object.fromEntries(Object.entries(parameters).map(([key, value]) => {\n identifier(key)\n // These are non-secret provider setup values, never Hub auth or identity overrides.\n if (/^(?:user|userid|owner|ownerid|workspace|workspaceid|team|teamid|principal|principalid|session|sessionid|authorization|headers|cookie|apikey|token|accesstoken|refreshtoken|clientsecret|secret|credentials?|appid|clientid)$/.test(key.replace(/[_-]/g, '').toLowerCase())) invalid()\n return [key, text(value, 1024)]\n }))\n }\n return input\n}\n\nfunction query(url: URL, allowed: readonly string[]): void {\n for (const key of url.searchParams.keys()) {\n if (!allowed.includes(key) || url.searchParams.getAll(key).length !== 1) invalid()\n }\n}\n\nasync function body(request: Request): Promise<Record<string, unknown>> {\n if ((request.headers.get('content-type')?.split(';')[0] ?? '').trim().toLowerCase() !== 'application/json') {\n throw json({ error: 'Expected application/json', code: 'HUB_INVALID_INPUT' }, 415)\n }\n const [value, error] = await parseJsonObjectBody(request, { maxBytes: 64 * 1024 })\n if (error) { error.headers.set('Cache-Control', 'no-store'); throw error }\n return value\n}\n\n/** Snapshot nested intent before application callbacks can observe it. */\nfunction freeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const child of Object.values(value)) freeze(child)\n Object.freeze(value)\n }\n return value\n}\n\nfunction isPrincipal(value: unknown): value is HubSettingsPrincipal {\n if (value === null || typeof value !== 'object') return false\n const principal = value as Partial<HubSettingsPrincipal>\n return [principal.userId, principal.sessionId, principal.workspaceId].every((part) => typeof part === 'string' && part.trim().length > 0)\n}\n\ninterface Prepared {\n intent: HubSettingsOperation\n call(client: HubSettingsClient): Promise<unknown>\n}\n\nconst ROUTES = [\n { kind: 'providers', path: /^\\/providers$/, methods: ['GET'] },\n { kind: 'connections', path: /^\\/connections$/, methods: ['GET'] },\n { kind: 'oauth', path: /^\\/connections\\/([^/]+)\\/start$/, methods: ['POST'] },\n { kind: 'api-key', path: /^\\/connections\\/([^/]+)\\/connect-key$/, methods: ['POST'] },\n { kind: 'revoke', path: /^\\/connections\\/([^/]+)$/, methods: ['DELETE'] },\n { kind: 'health', path: /^\\/connections\\/([^/]+)\\/health$/, methods: ['POST'] },\n { kind: 'actions', path: /^\\/providers\\/([^/]+)\\/actions$/, methods: ['GET'] },\n { kind: 'policies', path: /^\\/policies$/, methods: ['GET', 'PUT', 'DELETE'] },\n] as const\n\nasync function prepare(request: Request, basePath: string, callbackPath: string | undefined): Promise<Prepared | Response> {\n const url = new URL(request.url)\n if (!url.pathname.startsWith(`${basePath}/`)) return json({ error: 'Not found' }, 404)\n const path = url.pathname.slice(basePath.length)\n const route = ROUTES.find((candidate) => candidate.path.test(path))\n if (!route) return json({ error: 'Not found' }, 404)\n if (!(route.methods as readonly string[]).includes(request.method)) {\n return json({ error: 'Method not allowed' }, 405, { Allow: route.methods.join(', ') })\n }\n const target = route.path.exec(path)?.[1]\n const isPolicyRead = route.kind === 'policies' && request.method === 'GET'\n const isActions = route.kind === 'actions'\n query(url, isPolicyRead ? ['connectionId'] : isActions ? ['query', 'limit'] : [])\n const hasJson = route.kind === 'oauth' || route.kind === 'api-key' || (route.kind === 'policies' && !isPolicyRead)\n if (!hasJson && request.body !== null) {\n // Workers may expose an empty body stream for a bodyless POST.\n const reader = request.body.getReader()\n let emptyChunks = 0\n try {\n for (;;) {\n const chunk = await reader.read()\n if (chunk.done) break\n if (chunk.value.byteLength > 0) invalid()\n // Limit empty chunks before authorization; bodyless requests reach EOF.\n if (++emptyChunks > 16) invalid()\n }\n } finally {\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n\n if (route.kind === 'providers') return { intent: { operation: 'providers.list', target: 'caller-account' }, call: (hub) => hub.connections.providers() }\n if (route.kind === 'connections') return { intent: { operation: 'connections.list', target: 'caller-account' }, call: (hub) => hub.connections.list() }\n if (isPolicyRead) {\n const connectionId = identifier(url.searchParams.get('connectionId'))\n return { intent: { operation: 'policies.list', connectionId }, call: (hub) => hub.permissions.list(connectionId) }\n }\n if (route.kind === 'policies') {\n const input = await body(request)\n onlyKeys(input, request.method === 'PUT' ? ['connectionId', 'actionPath', 'decision'] : ['connectionId', 'actionPath'])\n const connectionId = identifier(input.connectionId)\n const actionPath = action(input.actionPath)\n if (request.method === 'DELETE') return { intent: { operation: 'policy.reset', connectionId, actionPath }, call: (hub) => hub.permissions.delete({ connectionId, actionPath }) }\n const decision = input.decision\n if (decision !== 'allow' && decision !== 'ask' && decision !== 'deny') invalid()\n return { intent: { operation: 'policy.set', connectionId, actionPath, decision }, call: (hub) => hub.permissions.set({ connectionId, actionPath, decision }) }\n }\n const id = identifier(target)\n if (isActions) {\n const search = url.searchParams.get('query') ?? ''\n if (search.length > 512 || /[\\u0000-\\u001f\\u007f]/.test(search)) invalid()\n const rawLimit = url.searchParams.get('limit') ?? '200'\n if (!/^[1-9][0-9]*$/.test(rawLimit)) invalid()\n const limit = Number(rawLimit)\n if (limit > 200) invalid()\n return { intent: { operation: 'provider.actions', provider: id, query: search, limit }, call: (hub) => hub.tools.search(search, { provider: id, limit }) }\n }\n if (route.kind === 'oauth') {\n const input = freeze(oauthInput(await body(request), url, id, callbackPath))\n return { intent: { operation: 'oauth.start', provider: id, input }, call: (hub) => hub.connections.start(id, input) }\n }\n if (route.kind === 'api-key') {\n const input = await body(request)\n onlyKeys(input, ['apiKey', 'metadata'])\n const apiKey = text(input.apiKey, 16 * 1024)\n const setup = input.metadata === undefined ? undefined : freeze(metadata(input.metadata))\n return { intent: { operation: 'api-key.connect', provider: id, ...(setup === undefined ? {} : { metadata: setup }) }, call: (hub) => hub.connections.connectApiKey(id, apiKey, setup) }\n }\n if (route.kind === 'health') return { intent: { operation: 'connection.health', connectionId: id }, call: (hub) => hub.connections.health(id) }\n if (route.kind === 'revoke') return { intent: { operation: 'connection.revoke', connectionId: id }, call: (hub) => hub.connections.revoke(id) }\n return invalid()\n}\n\n/** Build the finite, application-authorized Hub settings server boundary. */\nexport function createHubSettingsRoutes(ctx: HubSettingsContext): HubSettingsRoutes {\n if (typeof ctx.authorize !== 'function' || typeof ctx.resolveClient !== 'function') {\n throw new TypeError('Hub settings requires authorize and resolveClient callbacks')\n }\n const basePath = ctx.basePath ?? '/api/hub/settings'\n if (!/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(basePath)) throw new TypeError('Invalid Hub settings basePath')\n const callbackPath = ctx.oauthCallbackPath\n if (callbackPath !== undefined && !/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(callbackPath)) throw new TypeError('Invalid Hub OAuth callback path')\n\n return { async handle(request) {\n let prepared: Prepared | Response\n try { prepared = await prepare(request, basePath, callbackPath) } catch (error) {\n if (error instanceof Response) return error\n throw error\n }\n if (prepared instanceof Response) return prepared\n // Auth throws intentionally propagate. No SDK/client lookup has occurred.\n const grant = await ctx.authorize(request, freeze(prepared.intent))\n if (grant instanceof Response) return grant\n if (grant?.authorized !== true || !isPrincipal(grant.principal)) {\n return json({ error: 'Hub settings authorization required', code: 'HUB_FORBIDDEN' }, 403)\n }\n const principal = Object.freeze({ userId: grant.principal.userId, sessionId: grant.principal.sessionId, workspaceId: grant.principal.workspaceId })\n try {\n const bound = await ctx.resolveClient(principal)\n if (bound?.credentialSource !== 'caller-account' || !isPrincipal(bound.principal) ||\n bound.principal.userId !== principal.userId || bound.principal.sessionId !== principal.sessionId || bound.principal.workspaceId !== principal.workspaceId) {\n return json({ error: 'Hub settings caller binding mismatch', code: 'HUB_FORBIDDEN' }, 403)\n }\n // Client resolution can outlive a session or role grant. Recheck before the Hub effect.\n const renewed = await ctx.authorize(request, prepared.intent)\n if (renewed instanceof Response) return renewed\n if (renewed?.authorized !== true || !isPrincipal(renewed.principal) ||\n renewed.principal.userId !== principal.userId || renewed.principal.sessionId !== principal.sessionId || renewed.principal.workspaceId !== principal.workspaceId) {\n return json({ error: 'Hub settings authorization required', code: 'HUB_FORBIDDEN' }, 403)\n }\n return json(await prepared.call(bound.client))\n } catch (error) {\n // Structural detection survives SDK copies without a runtime peer import.\n if (error instanceof Error && error.name === 'HubSdkError' && typeof (error as { code?: unknown }).code === 'string') {\n const { code, status } = error as Error & { code: string; status?: number }\n const fallback = code === 'HUB_INVALID_INPUT' ? 400 : code === 'HUB_UNAUTHENTICATED' ? 401 : code === 'HUB_FORBIDDEN' ? 403 : 502\n const httpStatus = typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? status : fallback\n // Never echo upstream details/message: they can contain submitted credentials.\n return json({ error: 'Hub settings request failed', code }, httpStatus)\n }\n throw error\n }\n } }\n}\n","/**\n * Platform billing HTTP transport + tier state for apps on the shared\n * Tangle balance model (id.tangle.tools). Reads authenticate as the user via\n * their per-user platform key (the platform resolves the caller from the\n * key; service or impersonation headers on read routes are rejected). The\n * deduct write authenticates as the product service (`Bearer <serviceToken>`\n * + `X-Service-Name`) and names the target user in the body. Also provides a\n * fetch-backed implementation of the `/billing` module's\n * `PlatformBillingClient` seam (type-only import — no runtime coupling).\n */\n\nimport type { PlatformBillingClient, PlatformIdentity } from '../billing/index'\nimport { resolveTangleExecutionEnvironment } from '../runtime/model'\n\n/** Define available subscription tiers for the TanglePlan service */\nexport type TanglePlanTier = 'free' | 'pro' | 'enterprise'\n\n/** 'pro' | 'enterprise' pass through; anything else (null, unknown) → 'free'. */\nexport function normalizeTanglePlanTier(plan: string | null | undefined): TanglePlanTier {\n return plan === 'pro' || plan === 'enterprise' ? plan : 'free'\n}\n\n/** Represent platform billing HTTP errors with status code and detailed message */\nexport class PlatformBillingHttpError extends Error {\n constructor(\n readonly status: number,\n detail: string,\n ) {\n super(`Platform request failed (${status}): ${detail}`)\n this.name = 'PlatformBillingHttpError'\n }\n}\n\n/** Structural guard (name + numeric status) — robust across module instances. */\nexport function isPlatformBillingHttpError(error: unknown): error is PlatformBillingHttpError {\n return (\n error instanceof Error &&\n error.name === 'PlatformBillingHttpError' &&\n typeof (error as { status?: unknown }).status === 'number'\n )\n}\n\n/** Define HTTP options for platform billing including base URL, service token, product slug, fetch implementation, and timeout */\nexport interface PlatformBillingHttpOptions {\n /** Platform root, e.g. https://id.tangle.tools (trailing slashes stripped). */\n baseUrl: string\n /** Used only by `deduct()`; resolved lazily so reads never require it.\n * Throws at call time when empty. */\n serviceToken: string | (() => string)\n /** Product slug — the `X-Service-Name` header and the deduct `product` field. */\n productSlug: string\n fetchImpl?: typeof fetch\n /** Default 10 000. */\n timeoutMs?: number\n}\n\n/** Describe subscription tier and status information for a platform user */\nexport interface PlatformSubscriptionInfo {\n tier: TanglePlanTier\n status: string | null\n}\n\n/** Describe the platform balance and lifetime spending with an optional update timestamp */\nexport interface PlatformBalanceSnapshot {\n balance: number\n lifetimeSpent: number\n updatedAt?: string\n}\n\n/** Describe a product's usage and spending metrics on the platform */\nexport interface PlatformUsageProductRow {\n product: string | null\n totalSpent: number\n count: number\n}\n\n/** Lifecycle of a per-product seat subscription, mirroring the Stripe states\n * the platform persists. 'none' = the user has never held this seat. */\nexport type SeatStatus = 'none' | 'active' | 'trialing' | 'past_due' | 'canceled'\n\n/** Price and included shared-wallet credit for one seat billing period. */\nexport interface ProductSeatOfferPeriod {\n priceCents: number\n includedCreditsCents: number\n}\n\n/** Commercial terms returned by the platform's product catalog. Products use\n * this exact object for display instead of duplicating prices in UI copy. */\nexport interface ProductSeatOffer {\n currency: 'usd'\n interval: 'month'\n recurring: ProductSeatOfferPeriod\n introductory: ProductSeatOfferPeriod | null\n}\n\n/**\n * Per-product entitlement snapshot from the platform — the single read that\n * tells a product whether to show its workspace or the seat paywall. Shape\n * matches `GET /v1/billing/product-entitlement?product=<id>`.\n *\n * `hasSeat` is computed platform-side from the raw seat row.\n * It is true for an active or trialing seat whose period has not lapsed.\n * `onFreeTier` remains in the wire shape for compatibility, but this client\n * always returns false and never uses it for access.\n */\nexport interface ProductEntitlement {\n seatStatus: SeatStatus\n /** ISO timestamp the active seat's paid period runs until; null when none. */\n currentPeriodEnd: string | null\n /** Cumulative inference spend across the whole suite, in dollars. */\n lifetimeSpentUsd: number\n hasSeat: boolean\n /** Platform access decision, including funded balance and identity policy. */\n paidAccess?: boolean\n onFreeTier: boolean\n /** Present when the platform exposes catalog-backed commercial terms. */\n offer?: ProductSeatOffer\n}\n\nfunction productSeatOffer(value: unknown): ProductSeatOffer | undefined {\n if (!value || typeof value !== 'object') return undefined\n const candidate = value as Record<string, unknown>\n if (candidate.currency !== 'usd' || candidate.interval !== 'month') return undefined\n\n const period = (input: unknown, allowZeroPrice: boolean): ProductSeatOfferPeriod | undefined => {\n if (!input || typeof input !== 'object') return undefined\n const data = input as Record<string, unknown>\n const priceCents = data.priceCents\n const includedCreditsCents = data.includedCreditsCents\n if (\n typeof priceCents !== 'number' ||\n !Number.isSafeInteger(priceCents) ||\n (allowZeroPrice ? priceCents < 0 : priceCents <= 0) ||\n typeof includedCreditsCents !== 'number' ||\n !Number.isSafeInteger(includedCreditsCents) ||\n includedCreditsCents < 0\n ) {\n return undefined\n }\n return { priceCents, includedCreditsCents }\n }\n\n const recurring = period(candidate.recurring, false)\n const introductory =\n candidate.introductory === null\n ? null\n : period(candidate.introductory, true)\n if (!recurring || introductory === undefined) return undefined\n return {\n currency: 'usd',\n interval: 'month',\n recurring,\n introductory,\n }\n}\n\n/** Define methods to interact with platform billing endpoints using user or service authentication */\nexport interface PlatformBillingHttp {\n /** GET /v1/plans/current (user bearer). */\n getSubscription(userApiKey: string): Promise<PlatformSubscriptionInfo>\n /** GET /v1/billing/balance (user bearer). */\n getBalance(userApiKey: string): Promise<PlatformBalanceSnapshot>\n /** GET /v1/billing/usage (user bearer). */\n getUsageByProduct(userApiKey: string): Promise<PlatformUsageProductRow[]>\n /** GET /v1/billing/product-entitlement?product=<id> (user bearer). */\n getProductEntitlement(userApiKey: string, productId: string): Promise<ProductEntitlement>\n /** POST /v1/billing/deduct (service token). */\n deduct(input: {\n platformUserId: string\n amountUsd: number\n type: string\n description: string\n referenceId: string\n }): Promise<void>\n /** Absolute URL of the platform's billing-management surface. */\n billingUrl(): string\n /** Absolute URL of the catalog-backed seat checkout for `productId`. */\n seatCheckoutUrl(productId: string): string\n}\n\n/** Create a PlatformBillingHttp instance configured with given options and default behaviors */\nexport function createPlatformBillingHttp(opts: PlatformBillingHttpOptions): PlatformBillingHttp {\n const baseUrl = opts.baseUrl.replace(/\\/+$/, '')\n if (!baseUrl) throw new Error('PlatformBillingHttpOptions.baseUrl is required')\n if (!opts.productSlug) throw new Error('PlatformBillingHttpOptions.productSlug is required')\n const fetchImpl = opts.fetchImpl ?? fetch\n const timeoutMs = opts.timeoutMs ?? 10_000\n\n function resolveServiceToken(): string {\n const token = typeof opts.serviceToken === 'function' ? opts.serviceToken() : opts.serviceToken\n if (!token) throw new Error('A platform service token is required for deduct')\n return token\n }\n\n async function request<T>(path: string, init: RequestInit, headers: Headers): Promise<T> {\n const res = await fetchImpl(`${baseUrl}${path}`, {\n ...init,\n headers,\n signal: AbortSignal.timeout(timeoutMs),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { error?: { message?: string } } | null\n throw new PlatformBillingHttpError(res.status, body?.error?.message ?? res.statusText)\n }\n return res.json() as Promise<T>\n }\n\n function userRead<T>(userApiKey: string, path: string): Promise<T> {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${userApiKey}`)\n return request<T>(path, {}, headers)\n }\n\n return {\n async getSubscription(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: { subscription?: { plan?: string | null; status?: string | null } | null }\n }>(userApiKey, '/v1/plans/current')\n const sub = body.data?.subscription ?? null\n return { tier: normalizeTanglePlanTier(sub?.plan), status: sub?.status ?? null }\n },\n\n async getBalance(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: { balance?: number; lifetimeSpent?: number; updatedAt?: string }\n }>(userApiKey, '/v1/billing/balance')\n return {\n balance: body.data?.balance ?? 0,\n lifetimeSpent: body.data?.lifetimeSpent ?? 0,\n updatedAt: body.data?.updatedAt,\n }\n },\n\n async getUsageByProduct(userApiKey) {\n const body = await userRead<{\n success: boolean\n data?: Array<{ product?: string | null; totalSpent?: number; count?: number }>\n }>(userApiKey, '/v1/billing/usage')\n return (body.data ?? []).map((row) => ({\n product: row.product ?? null,\n totalSpent: row.totalSpent ?? 0,\n count: row.count ?? 0,\n }))\n },\n\n async getProductEntitlement(userApiKey, productId) {\n const slug = encodeURIComponent(productId)\n const body = await userRead<{\n success: boolean\n data?: {\n seatStatus?: SeatStatus | null\n currentPeriodEnd?: string | null\n lifetimeSpentUsd?: number | null\n hasSeat?: boolean | null\n paidAccess?: unknown\n onFreeTier?: boolean | null\n offer?: unknown\n }\n }>(userApiKey, `/v1/billing/product-entitlement?product=${slug}`)\n const data = body.data ?? {}\n const hasSeat = data.hasSeat === true\n const offer = productSeatOffer(data.offer)\n return {\n seatStatus: data.seatStatus ?? 'none',\n currentPeriodEnd: data.currentPeriodEnd ?? null,\n lifetimeSpentUsd: data.lifetimeSpentUsd ?? 0,\n hasSeat,\n ...('paidAccess' in data ? { paidAccess: data.paidAccess === true } : {}),\n // Product-funded free access is retired. Ignore stale server signals.\n onFreeTier: false,\n ...(offer ? { offer } : {}),\n }\n },\n\n async deduct(input) {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${resolveServiceToken()}`)\n headers.set('X-Service-Name', opts.productSlug)\n headers.set('Content-Type', 'application/json')\n await request('/v1/billing/deduct', {\n method: 'POST',\n body: JSON.stringify({\n userId: input.platformUserId,\n amount: input.amountUsd,\n type: input.type,\n product: opts.productSlug,\n description: input.description,\n referenceId: input.referenceId,\n }),\n }, headers)\n },\n\n billingUrl() {\n return `${baseUrl}/app/billing`\n },\n\n seatCheckoutUrl(productId) {\n return seatCheckoutUrl(baseUrl, productId)\n },\n }\n}\n\n/**\n * Platform Stripe checkout URL for a product's catalog-backed seat. The\n * platform resolves the product-specific price and introductory offer from the\n * `product` query param. Mirrors the `billingUrl()` shape — a deterministic\n * platform-rooted URL with no client-side pricing decisions.\n */\nexport function seatCheckoutUrl(baseUrl: string, productId: string): string {\n const root = baseUrl.replace(/\\/+$/, '')\n return `${root}/app/billing/seat/checkout?product=${encodeURIComponent(productId)}`\n}\n\n// ── Tier policy + composed state ────────────────────────────────────────────\n\n/** Define policy settings for concurrency and overage allowance in a tangle tier */\nexport interface TangleTierPolicy {\n concurrency: number\n overageAllowed: boolean\n}\n\n/** Define default concurrency and overage policies for each TanglePlanTier level */\nexport const DEFAULT_TANGLE_TIER_POLICY: Record<TanglePlanTier, TangleTierPolicy> = {\n free: { concurrency: 1, overageAllowed: false },\n pro: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true },\n enterprise: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true },\n}\n\n/** Describe the state of a Tangle plan tier including subscription, balance, spending, and concurrency details */\nexport interface TangleTierState {\n tier: TanglePlanTier\n subscriptionStatus: string | null\n remainingBalanceUsd: number\n lifetimeSpentUsd: number\n concurrency: number\n overageAllowed: boolean\n}\n\n/**\n * Read subscription + balance and project them onto the tier policy. A\n * null/absent key fails CLOSED (free tier, zero balance) — a billable run is\n * never started against an unknown balance. Platform errors throw; callers\n * on the billable path choose their posture explicitly.\n */\nexport async function readTangleTierState(\n http: PlatformBillingHttp,\n userApiKey: string | null | undefined,\n policy: Record<TanglePlanTier, TangleTierPolicy> = DEFAULT_TANGLE_TIER_POLICY,\n): Promise<TangleTierState> {\n if (!userApiKey) {\n return {\n tier: 'free',\n subscriptionStatus: null,\n remainingBalanceUsd: 0,\n lifetimeSpentUsd: 0,\n ...policy.free,\n }\n }\n const [subscription, balance] = await Promise.all([\n http.getSubscription(userApiKey),\n http.getBalance(userApiKey),\n ])\n return {\n tier: subscription.tier,\n subscriptionStatus: subscription.status,\n remainingBalanceUsd: balance.balance,\n lifetimeSpentUsd: balance.lifetimeSpent,\n ...policy[subscription.tier],\n }\n}\n\n// ── Per-product seat entitlement ────────────────────────────────────────────\n\n/** Product-funded free inference spend is disabled. */\nexport const FREE_TIER_SPEND_CAP_USD = 0\n\n/**\n * Default name of the per-app feature flag that controls seat billing.\n * Explicit values override the environment default.\n */\nexport const DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR = 'SEAT_BILLING_ENABLED'\n\n/** Define options to configure seat billing flag environment variables and override flag name */\nexport interface SeatBillingFlagOptions {\n env?: Record<string, string | undefined>\n /** Override the flag name; default {@link DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR}. */\n flagEnvVar?: string\n}\n\n/**\n * An explicit flag controls seat billing in every environment.\n * Without a flag, known development and test environments default to OFF.\n * Deployed and unknown environments default to ON.\n */\nexport function isSeatBillingEnabled(opts: SeatBillingFlagOptions = {}): boolean {\n const env =\n opts.env ??\n (typeof process !== 'undefined' ? (process.env as Record<string, string | undefined>) : undefined)\n if (!env) return true\n const flag = env[opts.flagEnvVar ?? DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR]?.trim().toLowerCase()\n if (flag) return !['false', '0', 'off', 'disabled', 'no'].includes(flag)\n const environment = resolveTangleExecutionEnvironment(env)\n return environment !== 'development' && environment !== 'test'\n}\n\n/**\n * Read a user's entitlement for one product.\n * An absent key or disabled flag returns no access.\n * Transport failures propagate so the product can return a retryable error.\n *\n * @param flag — pass {@link isSeatBillingEnabled} (or your own boolean) so the\n * product owns when the gate engages. When false, no network call is made.\n */\nexport async function getProductEntitlement(\n http: Pick<PlatformBillingHttp, 'getProductEntitlement'>,\n userApiKey: string | null | undefined,\n productId: string,\n flag = true,\n): Promise<ProductEntitlement> {\n if (!flag) return unavailableEntitlement()\n if (!userApiKey) return unavailableEntitlement()\n return http.getProductEntitlement(userApiKey, productId)\n}\n\nfunction unavailableEntitlement(): ProductEntitlement {\n return {\n seatStatus: 'none',\n currentPeriodEnd: null,\n lifetimeSpentUsd: 0,\n hasSeat: false,\n onFreeTier: false,\n }\n}\n\n/** Honor platform access policy; older endpoints provide only seat authority. */\nexport function isProductEntitled(ent: ProductEntitlement): boolean {\n return ent.paidAccess === undefined ? ent.hasSeat === true : ent.paidAccess === true\n}\n\n// ── Bridge onto the /billing seam ───────────────────────────────────────────\n\n/** Define a contract for resolving platform identities based on user identifiers */\nexport interface PlatformIdentityStore {\n resolveIdentity(userId: string): Promise<PlatformIdentity | null>\n}\n\n/** Concrete fetch-backed `PlatformBillingClient<TanglePlanTier>` for\n * `createPlatformBalanceManager` (from `/billing`). */\nexport function createTanglePlatformBillingClient(\n http: PlatformBillingHttp,\n identity: PlatformIdentityStore,\n): PlatformBillingClient<TanglePlanTier> {\n return {\n resolveIdentity: (userId) => identity.resolveIdentity(userId),\n getPlan: async (apiKey) => (await http.getSubscription(apiKey)).tier,\n getBalance: async (apiKey) => {\n const snapshot = await http.getBalance(apiKey)\n return { balance: snapshot.balance, lifetimeSpent: snapshot.lifetimeSpent }\n },\n getUsageByProduct: (apiKey) => http.getUsageByProduct(apiKey),\n deduct: (input) => http.deduct(input),\n }\n}\n","/**\n * Bill work an agent app runs for a Platform agent key to that key's one cap.\n *\n * An owner approves an agent key with one lifetime cap shared across every\n * product. Work the app runs for the key must spend that cap, even when the\n * owner already has their own credential in the app:\n *\n * - Model calls: `modelKey` delegates a Router key from the agent key that\n * spends its cap directly (\"spend-through\"). Router refuses every call once\n * the cap is spent, so a turn cannot run past it.\n * - Work the app cannot route through the key, such as compute in a sandbox\n * the owner's own credential pays for: `hold` reserves the work's maximum\n * against the cap before it starts, and `consume` spends what it measured,\n * up to the hold, without charging the owner's wallet again.\n *\n * A spent or insufficient cap answers 402 `agent_key.budget_exhausted`, so an\n * app refuses the work before it starts. Web-standard fetch only.\n */\n\nexport interface AgentSpendRefusal {\n status: 402 | 403 | 503\n code: string\n message: string\n}\n\nexport type AgentSpendOutcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: AgentSpendRefusal }\n\nexport interface PlatformAgentSpendOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name. */\n serviceName: string\n serviceToken: string | (() => string)\n /** The Platform product this app bills, e.g. `gtm-agent`. */\n product: string\n fetch?: typeof fetch\n}\n\nexport interface PlatformAgentSpend {\n /**\n * A Router key whose charges spend the agent key's cap. `name` must start\n * `auto:`; give each piece of work its own.\n */\n modelKey(input: { agentKey: string; name: string; expiresAt: Date }): Promise<AgentSpendOutcome<{ key: string; keyId: string | null }>>\n /** Reserve up to `amountUsd` of the agent key's cap for work billed elsewhere. */\n hold(input: { keyId: string; amountUsd: number; referenceId: string; expiresAt: Date }): Promise<AgentSpendOutcome<{ authorizationId: string }>>\n /** Spend what the work measured, at most the hold. A retry repeats the amount. */\n consume(input: { authorizationId: string; amountUsd: number }): Promise<AgentSpendOutcome<{ consumedUsd: number }>>\n /** Return a hold whose work never ran. */\n release(authorizationId: string): Promise<AgentSpendOutcome<null>>\n}\n\nconst REQUEST_TIMEOUT_MS = 10_000\n\nconst budgetExhausted: AgentSpendRefusal = {\n status: 402,\n code: 'agent_key.budget_exhausted',\n message: 'The key has spent, or cannot cover, the cap its owner approved.',\n}\n\nfunction refusal(status: number, code: unknown): AgentSpendRefusal {\n if (code === 'KEY_BUDGET_EXHAUSTED' || code === 'KEY_BUDGET_EXCEEDED' || code === 'PRODUCT_BUDGET_EXCEEDED') return budgetExhausted\n if (code === 'INSUFFICIENT_BALANCE') {\n return { status: 402, code: 'agent_key.payment_required', message: \"The key owner's Tangle account has no credit.\" }\n }\n if (code === 'EMAIL_VERIFICATION_REQUIRED') {\n return { status: 403, code: 'agent_key.owner_unverified', message: 'The key owner must verify their Tangle email.' }\n }\n if (status >= 500 || status === 429 || code === 'PLATFORM_BUSY') {\n return { status: 503, code: 'agent_key.spend_unavailable', message: 'Platform could not record the spend; retry.' }\n }\n return { status: 403, code: 'agent_key.spend_refused', message: 'Platform refused to bill this work to the key.' }\n}\n\ninterface PlatformBody {\n success?: unknown\n data?: { key?: unknown; id?: unknown; consumedAmount?: unknown }\n error?: { code?: unknown }\n}\n\nexport function createPlatformAgentSpend(options: PlatformAgentSpendOptions): PlatformAgentSpend {\n const fetchImpl = options.fetch ?? fetch\n const base = options.platformUrl.replace(/\\/+$/, '')\n\n async function call(path: string, body: unknown): Promise<{ status: number; body: PlatformBody } | null> {\n const token = typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n try {\n const response = await fetchImpl(`${base}${path}`, {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'x-service-name': options.serviceName,\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: (await response.json().catch(() => ({}))) as PlatformBody }\n } catch {\n return null\n }\n }\n\n const unavailable = (): { succeeded: false; error: AgentSpendRefusal } => ({ succeeded: false, error: refusal(503, null) })\n\n return {\n async modelKey({ agentKey, name, expiresAt }) {\n const result = await call('/v1/keys/delegate', {\n sourceKey: agentKey, name, product: 'router', spendThrough: true, expiresAt: expiresAt.toISOString(),\n })\n if (!result) return unavailable()\n const key = result.body.data?.key\n if (result.status !== 201 || typeof key !== 'string') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n const keyId = result.body.data?.id\n return { succeeded: true, value: { key, keyId: typeof keyId === 'string' ? keyId : null } }\n },\n async hold({ keyId, amountUsd, referenceId, expiresAt }) {\n const result = await call('/v1/billing/authorizations', {\n keyId, amount: amountUsd, type: 'key_cap', product: options.product, referenceId, expiresAt: expiresAt.toISOString(),\n })\n if (!result) return unavailable()\n const id = result.body.data?.id\n if (result.status !== 201 || typeof id !== 'string') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n return { succeeded: true, value: { authorizationId: id } }\n },\n async consume({ authorizationId, amountUsd }) {\n const result = await call(`/v1/billing/authorizations/${encodeURIComponent(authorizationId)}/consume`, { amount: amountUsd })\n if (!result) return unavailable()\n const consumed = result.body.data?.consumedAmount\n if (result.status !== 200 || typeof consumed !== 'number') {\n return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n }\n return { succeeded: true, value: { consumedUsd: consumed } }\n },\n async release(authorizationId) {\n const result = await call(`/v1/billing/authorizations/${encodeURIComponent(authorizationId)}/release`, {})\n if (!result) return unavailable()\n if (result.status !== 200) return { succeeded: false, error: refusal(result.status, result.body.error?.code) }\n return { succeeded: true, value: null }\n },\n }\n}\n","/**\n * Record a person's consent that this app's Sandbox service key may bill them.\n *\n * An app that creates sandboxes under its own service key and names the\n * signed-in person as `billingOwnerId` needs that person's billing delegation\n * grant, or the Sandbox API refuses the create with\n * `BILLING_DELEGATION_GRANT_REQUIRED`. Platform records the grant from the key\n * the person gave the app at sign-in (`POST /v1/keys/billing-delegation-grants`),\n * so the app records it before its first delegated create. The call is\n * idempotent on Platform.\n *\n * A refusal answers a typed code and a message written for the person, so an\n * app can show it as is. Web-standard fetch only.\n */\n\nexport interface BillingConsentRefusal {\n status: 402 | 403 | 503\n code: 'billing_consent.payer_not_chargeable' | 'billing_consent.refused' | 'billing_consent.unavailable'\n /** Written for the person whose account would pay. */\n message: string\n /** Platform's own code, for logs. */\n platformCode: string | null\n}\n\nexport type BillingConsentOutcome =\n | { succeeded: true; value: { created: boolean } }\n | { succeeded: false; error: BillingConsentRefusal }\n\nexport interface PlatformBillingConsentOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name. */\n serviceName: string\n serviceToken: string | (() => string)\n fetch?: typeof fetch\n}\n\nexport interface PlatformBillingConsent {\n /**\n * Record that the owner of `payerKey` consents to `serviceKey` billing them\n * for sandboxes. `payerKey` is the key the person gave this app at sign-in;\n * `serviceKey` is the listed key the app creates sandboxes under.\n */\n consent(input: { payerKey: string; serviceKey: string }): Promise<BillingConsentOutcome>\n}\n\nconst REQUEST_TIMEOUT_MS = 10_000\n\nconst notChargeable: BillingConsentRefusal = {\n status: 402,\n code: 'billing_consent.payer_not_chargeable',\n message: 'Your Tangle account has no credit for sandbox use yet. Add credit in your Tangle account, then open the terminal again.',\n platformCode: 'PAYER_NOT_CHARGEABLE',\n}\n\nfunction refusal(status: number | null, platformCode: string | null): BillingConsentRefusal {\n if (platformCode === 'PAYER_NOT_CHARGEABLE') return notChargeable\n if (status === null || status >= 500 || status === 429) {\n return {\n status: 503,\n code: 'billing_consent.unavailable',\n message: 'Tangle could not record your sandbox billing consent right now. Try again in a moment.',\n platformCode,\n }\n }\n return {\n status: 403,\n code: 'billing_consent.refused',\n message: 'Tangle did not accept your sign-in for sandbox billing. Sign out and sign in again.',\n platformCode,\n }\n}\n\ninterface PlatformBody {\n data?: { id?: unknown; created?: unknown }\n error?: { code?: unknown }\n}\n\nexport function createPlatformBillingConsent(options: PlatformBillingConsentOptions): PlatformBillingConsent {\n const fetchImpl = options.fetch ?? fetch\n const base = options.platformUrl.replace(/\\/+$/, '')\n // Resolved values only: a cancelled request never settles, so a shared\n // in-flight promise would hang every later caller.\n let delegate: { serviceKey: string; keyId: string } | null = null\n\n async function request(path: string, init: RequestInit): Promise<{ status: number; body: PlatformBody } | null> {\n try {\n const response = await fetchImpl(`${base}${path}`, {\n ...init,\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: (await response.json().catch(() => ({}))) as PlatformBody }\n } catch {\n return null\n }\n }\n\n const codeOf = (body: PlatformBody): string | null => (typeof body.error?.code === 'string' ? body.error.code : null)\n\n return {\n async consent({ payerKey, serviceKey }) {\n if (delegate?.serviceKey !== serviceKey) {\n const self = await request('/v1/keys/self', { headers: { authorization: `Bearer ${serviceKey}` } })\n const keyId = self?.body.data?.id\n if (!self || self.status !== 200 || typeof keyId !== 'string' || !keyId) {\n return { succeeded: false, error: refusal(self ? Math.max(self.status, 500) : null, self ? codeOf(self.body) : null) }\n }\n delegate = { serviceKey, keyId }\n }\n const token = typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n const result = await request('/v1/keys/billing-delegation-grants', {\n method: 'POST',\n headers: {\n authorization: `Bearer ${token}`,\n 'x-service-name': options.serviceName,\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ sourceKey: payerKey, delegateKeyId: delegate.keyId }),\n })\n if (!result) return { succeeded: false, error: refusal(null, null) }\n if (result.status === 200 || result.status === 201) {\n return { succeeded: true, value: { created: result.status === 201 } }\n }\n const platformCode = codeOf(result.body)\n // The service key's own account pays for itself and needs no grant.\n if (platformCode === 'PAYER_IS_DELEGATE_OWNER') return { succeeded: true, value: { created: false } }\n return { succeeded: false, error: refusal(result.status, platformCode) }\n },\n }\n}\n","/**\n * Delegated product keys: a child key minted from the paying user's linked\n * Tangle key, scoped to one product, its models and its budget, so an app\n * never sends the user's own key to Router or Sandbox.\n *\n * WHY ONE. Seven apps minted these by hand (Tax, Legal, GTM, Creative,\n * Builder, Hardware, workcomp; survey 2026-10-12) with different scope,\n * expiry and revocation rules, and four never noticed a key Platform had\n * revoked, superseded or expired.\n *\n * TWO WAYS TO HOLD ONE.\n * - Per turn: `client.delegate` before the turn, `client.revoke` after it.\n * Nothing is cached, so nothing stale can be handed out.\n * - Per workspace: `createDelegatedKeyProvisioner` plugs this client into\n * `createIdentityBoundWorkspaceKeyManager` (`./billing`), which owns the\n * durable, lease-fenced slot. Its `getKey` asks Platform's\n * `verify-by-id`, which also refuses superseded generations, and reports\n * any key that is not valid as missing, so the manager marks it revoked\n * and mints a fresh one on the next use.\n *\n * THE MINT CONTRACT (`POST /v1/keys/delegate`, service-authenticated; the\n * response is the key row plus `attribution`, and the granted expiry is\n * `attribution.expiresAt`). The child is checked field by field: an\n * `sk-tan-` key that is not the source, the canonical name, this service as\n * provisioner and attribution origin, the requested product, resource, model\n * set and payer, a budget no larger than requested, and an expiry in the\n * future and no later than requested. A child that fails is revoked and\n * refused; if that revoke fails too, the refusal carries the child's id (never\n * its key) so the app can retire it.\n *\n * Errors carry a code and status, never a response body, a source key or a\n * child key.\n */\n\nconst REQUEST_TIMEOUT_MS = 10_000\nconst KEY_PREFIX = 'sk-tan-'\nconst AUTO_PREFIX = 'auto:'\n/** Products whose key names Platform qualifies as `auto:<service>:<product>:...` (key-provenance.ts). */\nconst PRODUCT_QUALIFIED = new Set(['router', 'sandbox'])\n\nexport type DelegatedKeyCode =\n | 'delegated_key.payment_required'\n | 'delegated_key.budget_exhausted'\n | 'delegated_key.owner_unverified'\n | 'delegated_key.unavailable'\n | 'delegated_key.refused'\n | 'delegated_key.failed'\n | 'delegated_key.response_invalid'\n | 'delegated_key.invalid_request'\n\nexport interface DelegatedKeyRefusal {\n status: number\n code: DelegatedKeyCode\n message: string\n /** Set when an untrusted child could not be revoked: the id (never the key) the app must retire. */\n unrevokedKeyId?: string\n /** Platform's own error code (never its message) for a decision this client does not type, for logs. */\n platformCode?: string\n}\n\nexport type DelegatedKeyOutcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: DelegatedKeyRefusal }\n\n/** How the child is paid for: its own budget, or spending the source's budget directly. */\nexport type DelegatedKeyBudget =\n | { usd: number; monthlyUsd?: number }\n | { spendThrough: true; monthlyUsd?: number }\n\nexport interface DelegatedKeyRequest {\n /** The payer's linked `sk-tan-` key. Never a shared app key. */\n sourceKey: string\n /** The logical slot, e.g. `turn:<id>`. Sent as Platform's canonical name; see {@link canonicalDelegatedKeyName}. */\n name: string\n product: 'router' | 'sandbox' | (string & {})\n resource?: { type: string; id: string }\n /** The only models the child may call. */\n allowedModels?: readonly string[]\n budget?: DelegatedKeyBudget\n rpmLimit?: number\n expiresAt: Date\n /** Checked against the child's attribution when given: the payer's Platform user id, the source key's id, and\n * the origin app Platform carries over from the source (an app's SSO key; a personal key has none). */\n expect?: { payerId?: string; sourceKeyId?: string; originAppId?: string | null }\n}\n\nexport interface DelegatedKey {\n key: string\n id: string\n /** The canonical name Platform stored. */\n name: string\n product: string\n /** The expiry Platform granted (`attribution.expiresAt`), never later than requested. */\n expiresAt: Date\n allowedModels: readonly string[] | null\n budgetUsd: number | null\n}\n\nexport interface PlatformDelegatedKeyClientOptions {\n /** Platform origin, e.g. `https://id.tangle.tools`. */\n platformUrl: string\n /** This app's Platform service name; Platform admits delegation per named service. */\n serviceName: string\n serviceToken: string | (() => string)\n fetch?: typeof fetch\n now?: () => number\n}\n\n/** Platform's `verify-by-id` verdict on one key, secret-free. */\nexport interface DelegatedKeyVerdict {\n valid: boolean\n /** Platform's reason when not valid, e.g. `key_revoked`, `budget_exhausted`. */\n invalidReason?: string\n budgetUsd?: number\n budgetRemaining?: number\n expiresAt?: string\n}\n\n/**\n * Identifies a key's slot for Platform's service-authenticated `revoke-slot`. Without `name` and `product`,\n * the client reads them from the key itself (`GET /v1/keys/:id`, which an SSO source may call), so a\n * provisioner restarted since the mint can still retire the key. Tax and Legal need `sourceKeyId`; GTM\n * and Builder admit `revoke-slot` only for their protected and preview keys, so their other keys keep\n * the refused DELETE as a typed error.\n */\nexport interface DelegatedKeySlotRef {\n userId: string\n name?: string\n product?: string\n sourceKeyId?: string\n}\n\nexport interface PlatformDelegatedKeyClient {\n delegate(request: DelegatedKeyRequest): Promise<DelegatedKeyOutcome<DelegatedKey>>\n /** Platform's authoritative verdict (`verify-by-id`), including revoked, expired and spent keys. */\n verify(input: { keyId: string; product: string }): Promise<DelegatedKeyOutcome<DelegatedKeyVerdict>>\n /**\n * `DELETE /v1/keys/:id` with the source key; a key already gone counts as revoked. Platform refuses key\n * mutations from a service-provisioned source (an app's SSO key) with 403; given `slot`, the client then\n * retires the slot through `revoke-slot` with the service token.\n */\n revoke(input: { sourceKey: string; keyId: string; slot?: DelegatedKeySlotRef }): Promise<DelegatedKeyOutcome<null>>\n /** Children of the source key in one slot, from `GET /v1/keys` with the source key. */\n listChildren(input: { sourceKey: string; name: string; product: string }): Promise<DelegatedKeyOutcome<Array<{ id: string }>>>\n}\n\n/**\n * The name Platform stores for a slot: `auto:<service>:<product>:<logical>` for\n * Router and Sandbox keys (Platform's `canonicalProvisionedKeyName`), so the\n * echo can be checked exactly. A name already qualified is kept.\n */\nexport function canonicalDelegatedKeyName(input: { serviceName: string; product: string; name: string }): string {\n const logical = input.name.startsWith(AUTO_PREFIX) ? input.name.slice(AUTO_PREFIX.length) : input.name\n if (!PRODUCT_QUALIFIED.has(input.product)) return `${AUTO_PREFIX}${logical}`\n if (logical.startsWith(`${input.serviceName}:${input.product}:`)) return `${AUTO_PREFIX}${logical}`\n const withoutService = logical.startsWith(`${input.serviceName}:`) ? logical.slice(input.serviceName.length + 1) : logical\n return `${AUTO_PREFIX}${input.serviceName}:${input.product}:${withoutService}`\n}\n\nfunction refusal(status: number, code: unknown): DelegatedKeyRefusal {\n if (code === 'INSUFFICIENT_BALANCE') {\n return { status: 402, code: 'delegated_key.payment_required', message: \"The payer's Tangle account has no credit.\" }\n }\n if (code === 'KEY_BUDGET_EXHAUSTED' || code === 'KEY_BUDGET_EXCEEDED' || code === 'PRODUCT_BUDGET_EXCEEDED') {\n return { status: 402, code: 'delegated_key.budget_exhausted', message: \"The payer's key has spent the budget it allows.\" }\n }\n if (code === 'EMAIL_VERIFICATION_REQUIRED') {\n return { status: 403, code: 'delegated_key.owner_unverified', message: 'The payer must verify their Tangle email.' }\n }\n if (status >= 500 || status === 429 || code === 'PLATFORM_BUSY') {\n return { status: 503, code: 'delegated_key.unavailable', message: 'Platform could not answer; retry.' }\n }\n // Only an authorization answer is a refusal. Any other 4xx is a decision about this request (Platform's\n // 400 DELEGATION_FAILED, say), kept as its own status with Platform's code so it is not mistaken for\n // a credential problem. The message stays out: it can name Platform internals.\n const platformCode = typeof code === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/.test(code) ? code : undefined\n if (status === 401 || status === 403 || status < 400) {\n return { status: 403, code: 'delegated_key.refused', message: 'Platform refused to delegate this key.', ...(platformCode ? { platformCode } : {}) }\n }\n return {\n status,\n code: 'delegated_key.failed',\n message: `Platform declined this delegation${platformCode ? ` (${platformCode})` : ''}.`,\n ...(platformCode ? { platformCode } : {}),\n }\n}\n\nconst failure = <T,>(status: number, code: DelegatedKeyCode, message: string, extra: Partial<DelegatedKeyRefusal> = {}): DelegatedKeyOutcome<T> =>\n ({ succeeded: false, error: { status, code, message, ...extra } })\n\nconst record = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null\n\nfunction sameSet(granted: unknown, requested: readonly string[]): boolean {\n if (!Array.isArray(granted) || granted.some(model => typeof model !== 'string')) return false\n const a = [...new Set(granted as string[])].sort()\n const b = [...new Set(requested)].sort()\n return granted.length === a.length && a.length === b.length && a.every((model, index) => model === b[index])\n}\n\n/** Why the minted child cannot be trusted, or null. Each check names its field, never its value. */\nfunction childProblem(data: Record<string, unknown>, request: DelegatedKeyRequest, name: string, serviceName: string, nowMs: number): string | null {\n const key = data.key\n const id = data.id\n if (typeof id !== 'string' || !id) return 'no key id'\n if (typeof key !== 'string' || !key.startsWith(KEY_PREFIX) || key.length <= KEY_PREFIX.length) return 'not an sk-tan child key'\n if (key === request.sourceKey) return 'the source key itself'\n if (typeof data.prefix === 'string' && !key.startsWith(data.prefix)) return 'a key that does not match its prefix'\n if (data.name !== name) return 'a different name'\n if (data.product !== request.product) return 'a different product'\n if (data.provisionedByService !== serviceName) return 'a different provisioner'\n if (data.scopes !== null && !(Array.isArray(data.scopes) && data.scopes.length === 0)) return 'control-plane scopes'\n // Omitted, the child inherits the source's model restriction, which only narrows it.\n if (request.allowedModels && !sameSet(data.allowedModels, request.allowedModels)) return 'a different model set'\n const budget = request.budget\n if (budget && 'usd' in budget && !(typeof data.budgetUsd === 'number' && data.budgetUsd <= budget.usd)) return 'a budget larger than requested'\n if (budget?.monthlyUsd !== undefined && !(typeof data.monthlyBudgetUsd === 'number' && data.monthlyBudgetUsd <= budget.monthlyUsd)) {\n return 'a monthly budget larger than requested'\n }\n\n const attribution = record(data.attribution)\n if (!attribution) return 'no attribution'\n if (attribution.version !== 1 || attribution.targetService !== request.product) return 'attribution for another target'\n if (request.expect?.originAppId !== undefined && (attribution.originAppId ?? null) !== request.expect.originAppId) {\n return 'attribution from another app'\n }\n const parent = attribution.delegatedFromKeyId\n if (typeof parent !== 'string' || !parent || parent === id) return 'attribution without its parent key'\n if (request.expect?.sourceKeyId !== undefined && parent !== request.expect.sourceKeyId) return 'attribution for another source key'\n if (attribution.payerType !== 'user') return 'attribution to a non-user payer'\n if (request.expect?.payerId !== undefined && attribution.payerId !== request.expect.payerId) return 'attribution to another payer'\n if ((attribution.resourceType ?? null) !== (request.resource?.type ?? null) || (attribution.resourceId ?? null) !== (request.resource?.id ?? null)) {\n return 'attribution for another resource'\n }\n const expiresAt = typeof attribution.expiresAt === 'string' ? Date.parse(attribution.expiresAt) : NaN\n if (!Number.isFinite(expiresAt) || expiresAt <= nowMs || expiresAt > request.expiresAt.getTime()) return 'an expiry in the past or past the request'\n return null\n}\n\nexport function createPlatformDelegatedKeyClient(options: PlatformDelegatedKeyClientOptions): PlatformDelegatedKeyClient {\n const fetchImpl = options.fetch ?? fetch\n const now = options.now ?? Date.now\n const base = options.platformUrl.replace(/\\/+$/, '')\n const serviceToken = () => typeof options.serviceToken === 'function' ? options.serviceToken() : options.serviceToken\n\n async function call(path: string, init: { method: string; bearer: string; service: boolean; body?: unknown }) {\n try {\n const response = await fetchImpl(`${base}${path}`, {\n method: init.method,\n headers: {\n authorization: `Bearer ${init.bearer}`,\n ...(init.service ? { 'x-service-name': options.serviceName } : {}),\n ...(init.body === undefined ? {} : { 'content-type': 'application/json' }),\n },\n ...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n redirect: 'manual',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n })\n return { status: response.status, body: record(await response.json().catch(() => null)) }\n } catch {\n return null\n }\n }\n\n const client: PlatformDelegatedKeyClient = {\n async delegate(request) {\n if (!request.sourceKey.startsWith(KEY_PREFIX)) return failure(400, 'delegated_key.invalid_request', 'The source must be a linked sk-tan- key.')\n if (request.expiresAt.getTime() <= now()) return failure(400, 'delegated_key.invalid_request', 'The expiry must be in the future.')\n const name = canonicalDelegatedKeyName({ serviceName: options.serviceName, product: request.product, name: request.name })\n const budget = request.budget\n const result = await call('/v1/keys/delegate', {\n method: 'POST', bearer: serviceToken(), service: true, body: {\n sourceKey: request.sourceKey,\n name,\n product: request.product,\n ...(request.resource ? { resourceType: request.resource.type, resourceId: request.resource.id } : {}),\n ...(budget && 'usd' in budget ? { budgetUsd: budget.usd } : {}),\n ...(budget && 'spendThrough' in budget ? { spendThrough: true } : {}),\n ...(budget?.monthlyUsd !== undefined ? { monthlyBudgetUsd: budget.monthlyUsd } : {}),\n ...(request.allowedModels ? { allowedModels: [...new Set(request.allowedModels)] } : {}),\n ...(request.rpmLimit !== undefined ? { rpmLimit: request.rpmLimit } : {}),\n // Omitted, Platform copies the source's scopes onto the child; a product key carries none.\n scopes: [],\n expiresAt: request.expiresAt.toISOString(),\n },\n })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n const data = record(result.body?.data)\n if (result.status !== 201 || result.body?.success !== true || !data) {\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n }\n const problem = childProblem(data, request, name, options.serviceName, now())\n if (problem) {\n // A child Platform minted but this app cannot trust is retired, never returned.\n const id = typeof data.id === 'string' && data.id ? data.id : null\n const owner = request.expect?.payerId\n ? { userId: request.expect.payerId, name, product: request.product,\n ...(request.expect.sourceKeyId ? { sourceKeyId: request.expect.sourceKeyId } : {}) }\n : undefined\n const revoked = id ? await client.revoke({ sourceKey: request.sourceKey, keyId: id, ...(owner ? { slot: owner } : {}) }) : null\n return failure(502, 'delegated_key.response_invalid', `Platform returned ${problem}.`,\n id && !revoked?.succeeded ? { unrevokedKeyId: id } : {})\n }\n const attribution = record(data.attribution)!\n return { succeeded: true, value: {\n key: data.key as string, id: data.id as string, name, product: request.product,\n expiresAt: new Date(attribution.expiresAt as string),\n allowedModels: request.allowedModels ? [...new Set(request.allowedModels)] : null,\n budgetUsd: typeof data.budgetUsd === 'number' ? data.budgetUsd : null,\n } }\n },\n\n async verify({ keyId, product }) {\n const result = await call('/v1/keys/verify-by-id', {\n method: 'POST', bearer: serviceToken(), service: true, body: { keyId, expectedProduct: product },\n })\n // Fail closed: anything but a well-formed verdict for this key is not evidence about it.\n if (!result || result.status >= 500 || result.status === 429) return { succeeded: false, error: refusal(503, null) }\n const body = result.body\n if (result.status !== 200 || typeof body?.valid !== 'boolean' || (body.valid && body.keyId !== keyId)) {\n return failure(502, 'delegated_key.response_invalid', 'Platform returned no verification verdict for this key.')\n }\n const number = (value: unknown) => typeof value === 'number' && Number.isFinite(value) ? value : undefined\n return { succeeded: true, value: {\n valid: body.valid,\n ...(typeof body.invalidReason === 'string' ? { invalidReason: body.invalidReason } : {}),\n ...(number(body.budgetUsd) !== undefined ? { budgetUsd: number(body.budgetUsd) } : {}),\n ...(number(body.budgetRemaining) !== undefined ? { budgetRemaining: number(body.budgetRemaining) } : {}),\n ...(typeof body.expiresAt === 'string' ? { expiresAt: body.expiresAt } : {}),\n } }\n },\n\n async revoke({ sourceKey, keyId, slot }) {\n const result = await call(`/v1/keys/${encodeURIComponent(keyId)}`, { method: 'DELETE', bearer: sourceKey, service: false })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n if (result.status === 404 || (result.status >= 200 && result.status < 300 && result.body?.success === true)) {\n return { succeeded: true, value: null }\n }\n if (result.status === 403 && slot) {\n let name = slot.name\n let product = slot.product\n if (!name || !product) {\n const row = await call(`/v1/keys/${encodeURIComponent(keyId)}`, { method: 'GET', bearer: sourceKey, service: false })\n const data = record(row?.body?.data)\n if (row?.status === 404) return { succeeded: true, value: null }\n if (!row || row.status !== 200 || typeof data?.name !== 'string' || typeof data.product !== 'string') {\n return { succeeded: false, error: refusal(row?.status ?? 503, null) }\n }\n if (data.revokedAt) return { succeeded: true, value: null }\n name = data.name\n product = data.product\n }\n const retired = await call('/v1/keys/auto-provisioned/revoke-slot', {\n method: 'POST', bearer: serviceToken(), service: true, body: {\n userId: slot.userId, name, product, childKeyId: keyId,\n ...(slot.sourceKeyId ? { sourceKeyId: slot.sourceKeyId } : {}),\n },\n })\n if (!retired) return { succeeded: false, error: refusal(503, null) }\n if (retired.status >= 200 && retired.status < 300 && retired.body?.success === true) return { succeeded: true, value: null }\n return { succeeded: false, error: refusal(retired.status, record(retired.body?.error)?.code) }\n }\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n },\n\n async listChildren({ sourceKey, name, product }) {\n const canonical = canonicalDelegatedKeyName({ serviceName: options.serviceName, product, name })\n const result = await call('/v1/keys', { method: 'GET', bearer: sourceKey, service: false })\n if (!result) return { succeeded: false, error: refusal(503, null) }\n const rows = result.body?.data\n if (result.status !== 200 || result.body?.success !== true || !Array.isArray(rows)) {\n return { succeeded: false, error: refusal(result.status, record(result.body?.error)?.code) }\n }\n return { succeeded: true, value: rows.flatMap((row) => {\n const value = record(row)\n return value && typeof value.id === 'string' && value.name === canonical && value.product === product && !value.revokedAt\n ? [{ id: value.id }] : []\n }) }\n },\n }\n return client\n}\n\n/** The `DurableWorkspaceKeyProvisioner` shape (`./billing`), kept structural so this module stays standalone. */\nexport interface DelegatedKeyProvisioner {\n createKey(input: { name: string; product: string; budgetUsd: number; expiresAt: string; idempotencyKey: string }): Promise<{\n id: string; key: string; budgetUsd?: number | null; expiresAt?: string | null\n }>\n getKey(id: string): Promise<{ budgetUsd?: number | null; expiresAt?: string | null }>\n revokeKey(id: string): Promise<unknown>\n findCreatedKeys(input: { name: string; product: string; sourceKeyId?: string | null }): Promise<Array<{ id: string }>>\n}\n\n/** A remote key the durable manager must treat as gone (it marks the row revoked and mints again). */\nexport class DelegatedKeyMissingError extends Error {\n readonly status = 404\n readonly code = 'not_found'\n constructor(keyId: string) {\n super(`Platform no longer accepts key ${keyId}`)\n this.name = 'DelegatedKeyMissingError'\n }\n}\n\n/** A Platform refusal surfaced to the durable manager. Carries the typed refusal, never a key. */\nexport class DelegatedKeyRefusalError extends Error {\n constructor(readonly refusal: DelegatedKeyRefusal) {\n super(refusal.message)\n this.name = 'DelegatedKeyRefusalError'\n }\n}\n\n/** Platform reasons that mean the key will never work again: the manager revokes the row and mints a fresh key. */\nconst GONE_REASONS = new Set([\n 'key_not_found', 'key_revoked', 'key_expired', 'key_lineage_revoked',\n 'parent_key_not_found', 'parent_key_revoked', 'parent_key_expired', 'parent_key_lineage_revoked',\n 'ancestor_key_not_found', 'ancestor_key_revoked', 'ancestor_key_expired', 'ancestor_key_lineage_revoked',\n])\nconst SPENT_REASONS = new Set(['budget_exhausted', 'monthly_budget_exhausted'])\n\n/**\n * Plug the client into `createIdentityBoundWorkspaceKeyManager` for a\n * workspace-held key. Pass the manager `nameForIdentity` returning a logical\n * slot name (the client sends Platform's canonical `auto:` form).\n *\n * `getKey` reads Platform's verdict: a key gone for good is reported missing\n * (the manager marks it revoked and mints again); a spent key is reported\n * exhausted (the manager revokes it remotely and mints again); a funding or\n * eligibility refusal is a typed error, so a lapse never retires a key that\n * still works.\n */\nexport function createDelegatedKeyProvisioner(input: {\n client: PlatformDelegatedKeyClient\n sourceKey: string\n product: string\n resource?: { type: string; id: string }\n allowedModels?: readonly string[]\n monthlyBudgetUsd?: number\n rpmLimit?: number\n expect?: { payerId?: string; sourceKeyId?: string; originAppId?: string | null }\n /** Enables the `revoke-slot` fallback when the source is an app's SSO key (Platform refuses its key mutations). */\n payerId?: string\n}): DelegatedKeyProvisioner {\n const product = input.product\n // The revoke-slot fallback needs the payer; the client reads each key's slot name itself.\n const slotOwner: DelegatedKeySlotRef | undefined = input.payerId\n ? { userId: input.payerId, ...(input.expect?.sourceKeyId ? { sourceKeyId: input.expect.sourceKeyId } : {}) }\n : undefined\n return {\n async createKey(create) {\n const minted = await input.client.delegate({\n sourceKey: input.sourceKey, name: create.name, product,\n ...(input.resource ? { resource: input.resource } : {}),\n ...(input.allowedModels ? { allowedModels: input.allowedModels } : {}),\n budget: { usd: create.budgetUsd, ...(input.monthlyBudgetUsd !== undefined ? { monthlyUsd: input.monthlyBudgetUsd } : {}) },\n ...(input.rpmLimit !== undefined ? { rpmLimit: input.rpmLimit } : {}),\n expiresAt: new Date(create.expiresAt),\n ...(input.expect ? { expect: input.expect } : {}),\n })\n if (!minted.succeeded) throw new DelegatedKeyRefusalError(minted.error)\n return { id: minted.value.id, key: minted.value.key, budgetUsd: minted.value.budgetUsd, expiresAt: minted.value.expiresAt.toISOString() }\n },\n async getKey(id) {\n const verdict = await input.client.verify({ keyId: id, product })\n if (!verdict.succeeded) throw new DelegatedKeyRefusalError(verdict.error)\n const v = verdict.value\n if (v.valid) {\n return {\n ...(v.budgetUsd !== undefined ? { budgetUsd: v.budgetUsd } : {}),\n ...(v.budgetUsd !== undefined && v.budgetRemaining !== undefined ? { budgetSpent: Math.max(0, v.budgetUsd - v.budgetRemaining) } : {}),\n ...(v.expiresAt ? { expiresAt: v.expiresAt } : {}),\n }\n }\n if (v.invalidReason && GONE_REASONS.has(v.invalidReason)) throw new DelegatedKeyMissingError(id)\n if (v.invalidReason && SPENT_REASONS.has(v.invalidReason)) {\n // Spent: the manager sees no budget left and revokes the child before minting again.\n return { budgetUsd: v.budgetUsd ?? 0, budgetSpent: v.budgetUsd ?? 0, ...(v.expiresAt ? { expiresAt: v.expiresAt } : {}) }\n }\n throw new DelegatedKeyRefusalError({ status: 403, code: 'delegated_key.refused',\n message: `Platform refused the key for now (${v.invalidReason ?? 'no reason'}).` })\n },\n async revokeKey(id) {\n const revoked = await input.client.revoke({ sourceKey: input.sourceKey, keyId: id, ...(slotOwner ? { slot: slotOwner } : {}) })\n if (!revoked.succeeded) throw new DelegatedKeyRefusalError(revoked.error)\n return null\n },\n async findCreatedKeys(find) {\n const listed = await input.client.listChildren({ sourceKey: input.sourceKey, name: find.name, product: find.product })\n if (!listed.succeeded) throw new DelegatedKeyRefusalError(listed.error)\n return listed.value\n },\n }\n}\n"],"mappings":"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","names":["identifier","body","body","body","REQUEST_TIMEOUT_MS","refusal","body","REQUEST_TIMEOUT_MS","refusal","record","body"]}