@tangle-network/hub-sdk 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isRecord","#apiKey","isRecord","isRecord"],"sources":["../src/json-init.ts","../src/allowances.ts","../src/apps.ts","../src/knowledge-management.ts","../src/knowledge.ts","../src/lines.ts","../src/managed-numbers.ts","../src/redaction.ts","../src/transport.ts","../src/environment.ts","../src/authorization.ts","../src/tools.ts","../src/inbound-webhooks.ts","../src/connections.ts","../src/channels.ts","../src/github-app.ts","../src/audit.ts","../src/workflow-run-events.ts","../src/workflows-kv.ts","../src/workflows.ts","../src/client.ts","../src/broker.ts","../src/event-delivery.ts","../src/knowledge-approval.ts","../src/line-grants.ts","../src/workflow-definition-types.ts"],"sourcesContent":["/** The init of a request whose body is JSON. Every client builds its bodies\n * here, so the content type cannot drift from the encoding. */\nexport function jsonInit<Body>(\n method: \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n body: Body,\n): RequestInit {\n return {\n method,\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n };\n}\n","import { jsonInit } from \"./json-init.js\";\n\n/**\n * Allowances: a developer's per-member daily allowance on a meter, and the\n * paywall decision past it. The platform counts every admitted turn and reads\n * each payer's dollars from the ledger; the app keeps only its checkout and\n * records a paying member with {@link HubAllowancesClient.grant}.\n *\n * Only the meter's owner may call these, signed in or with a root API key of\n * their own. A delegated or resource-bound key, such as the key a hosted end\n * user's sandbox runs on, is refused.\n */\n\nexport type HubAllowanceTier = \"free\" | \"paid\" | \"owner\";\nexport type HubAllowanceRole = \"owner\" | \"member\";\n\nexport interface HubAllowancePlanInput {\n free: { turnsPerDay: number; usdPerDay: number | null };\n /** Null turns billing off: past the free allowance nothing lifts the limit. */\n paid: {\n turnsPerDay: number;\n usdPerDay: number | null;\n priceUsdMonthly: number;\n } | null;\n owner?: { turnsPerDay: number };\n /** Key resource type whose ledger spend counts against a payer's dollars. */\n spendResourceType: string | null;\n}\n\nexport interface HubAllowancePlan extends HubAllowancePlanInput {\n meter: string;\n owner: { turnsPerDay: number };\n /** False while the meter runs on the default plan. */\n configured: boolean;\n updatedAt: string | null;\n}\n\nexport interface HubAllowanceSubject {\n member: string;\n role?: HubAllowanceRole;\n /** The member whose keys pay for the turn, when that is someone else. */\n payer?: string;\n payerRole?: HubAllowanceRole;\n}\n\nexport interface HubAllowanceDecision {\n /** `paywall`: paying lifts the limit. `allowance_reached`: nothing does today. */\n decision: \"admit\" | \"paywall\" | \"allowance_reached\";\n tier: HubAllowanceTier;\n paywall: boolean;\n turns: { used: number; limit: number };\n usd: { spent: number; limit: number; remaining: number } | null;\n day: string;\n resetsAt: string;\n /**\n * A paying payer's spend in the current paid period against what funds it:\n * the plan price less Tangle's 10% fee, plus the free daily allowance for\n * the period. A paid turn is refused once `remaining` is gone.\n */\n period?: {\n spent: number;\n funded: number;\n remaining: number;\n startsAt: string;\n endsAt: string;\n };\n replay?: boolean;\n}\n\nexport interface HubAllowanceUsage {\n day: string;\n turns: number;\n members: Array<{\n member: string;\n turns: number;\n tier: HubAllowanceTier;\n usdSpent: number | null;\n }>;\n lines: Array<{ line: string; turns: number }>;\n}\n\nexport interface HubAllowanceSyncInput {\n source: string;\n revision: number;\n expiresAt: string | null;\n reference: string | null;\n}\nexport interface HubAllowanceSyncReceipt extends HubAllowanceSyncInput {\n member: string;\n}\n\nexport interface HubAllowanceGrant {\n member: string;\n tier: \"paid\";\n expiresAt: string;\n reference: string | null;\n}\n\n/** Every body this client sends. */\ntype HubAllowanceRequestBody =\n | HubAllowanceSyncInput\n | HubAllowancePlanInput\n | (HubAllowanceSubject & { turnId: string; line?: string; channel?: string })\n | { tier: \"paid\"; expiresAt: string; reference?: string | null };\n\nexport class HubAllowancesClient {\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {}\n\n async plan(meter: string): Promise<HubAllowancePlan> {\n return (\n await this.request<{ plan: HubAllowancePlan }>(this.path(meter), {\n method: \"GET\",\n })\n ).plan;\n }\n\n async setPlan(\n meter: string,\n plan: HubAllowancePlanInput,\n ): Promise<HubAllowancePlan> {\n return (\n await this.request<{ plan: HubAllowancePlan }>(\n this.path(meter),\n this.body(\"PUT\", plan),\n )\n ).plan;\n }\n\n /** Admit one turn or refuse it. Retrying the same `turnId` never counts twice. */\n async admit(\n meter: string,\n input: HubAllowanceSubject & {\n turnId: string;\n line?: string;\n channel?: string;\n },\n ): Promise<HubAllowanceDecision> {\n return (\n await this.request<{ allowance: HubAllowanceDecision }>(\n `${this.path(meter)}/turns`,\n this.body(\"POST\", input),\n )\n ).allowance;\n }\n\n /** What the member's next turn would get, without counting anything. */\n async status(\n meter: string,\n subject: HubAllowanceSubject,\n ): Promise<HubAllowanceDecision> {\n const query = new URLSearchParams();\n if (subject.role) query.set(\"role\", subject.role);\n if (subject.payer) query.set(\"payer\", subject.payer);\n if (subject.payerRole) query.set(\"payerRole\", subject.payerRole);\n const suffix = query.size ? `?${query}` : \"\";\n return (\n await this.request<{ allowance: HubAllowanceDecision }>(\n `${this.memberPath(meter, subject.member)}${suffix}`,\n { method: \"GET\" },\n )\n ).allowance;\n }\n\n /** Move a member to the paid allowance until `expiresAt` (the paid period's end). */\n async grant(\n meter: string,\n member: string,\n input: { expiresAt: string; reference?: string | null },\n ): Promise<HubAllowanceGrant> {\n return (\n await this.request<{ grant: HubAllowanceGrant }>(\n `${this.memberPath(meter, member)}/grant`,\n this.body(\"PUT\", { tier: \"paid\", ...input }),\n )\n ).grant;\n }\n\n /** Synchronize a paid grant by durable product revision. Null expiry writes\n * a retained revocation. A delayed older update is refused, never reactivated.\n * There is no fallback to the unversioned grant endpoint on older servers. */\n async syncGrant(\n meter: string,\n member: string,\n input: HubAllowanceSyncInput,\n ): Promise<HubAllowanceSyncReceipt> {\n const { grant } = await this.request<{ grant: HubAllowanceSyncReceipt }>(\n `${this.memberPath(meter, member)}/grant/sync`,\n this.body(\"PUT\", input),\n );\n if (\n grant.member !== member ||\n grant.source !== input.source ||\n grant.revision !== input.revision ||\n grant.reference !== input.reference ||\n grant.expiresAt !==\n (input.expiresAt === null\n ? null\n : new Date(input.expiresAt).toISOString())\n ) {\n throw new Error(\n \"The Hub returned a mismatched grant synchronization receipt\",\n );\n }\n return grant;\n }\n\n async revoke(meter: string, member: string): Promise<void> {\n await this.request(`${this.memberPath(meter, member)}/grant`, {\n method: \"DELETE\",\n });\n }\n\n /** Turns per member and per line on one UTC day (default today). */\n async usage(meter: string, day?: string): Promise<HubAllowanceUsage> {\n const suffix = day ? `?day=${encodeURIComponent(day)}` : \"\";\n return (\n await this.request<{ usage: HubAllowanceUsage }>(\n `${this.path(meter)}/usage${suffix}`,\n { method: \"GET\" },\n )\n ).usage;\n }\n\n private path(meter: string) {\n return `/v1/hub/allowances/${encodeURIComponent(meter)}`;\n }\n private memberPath(meter: string, member: string) {\n return `${this.path(meter)}/members/${encodeURIComponent(member)}`;\n }\n private body(\n method: \"POST\" | \"PUT\",\n body: HubAllowanceRequestBody,\n ): RequestInit {\n return jsonInit(method, body);\n }\n}\n","import { jsonInit } from \"./json-init.js\";\n\n/** The compliance claim an owner latches through a BAA acceptance. Positive\n * claims only: `{ hipaa: true }` or absent — `hipaa: false` is unspellable. */\nexport interface HubAppComplianceClaim {\n hipaa: true;\n}\n/** Owner-facing compliance state: the latched claim and the acceptance behind it. */\nexport interface HubAppComplianceState {\n compliance: HubAppComplianceClaim | null;\n agreement: { version: string; url: string } | null;\n acceptance: {\n agreementVersion: string;\n agreementUrl: string;\n acceptedByUserId: string;\n acceptedAt: string;\n } | null;\n}\n\n/** App identity and customer permissions over the existing Platform transport.\n * These operations do not authorize spending or expose upstream credentials. */\nexport interface HubApp {\n id: string;\n clientId: string;\n oauthClientId: string | null;\n name: string;\n redirectUris: string[];\n allowedScopes: string[];\n homepageUrl: string | null;\n accessPayer?: \"user\" | \"app-owner\";\n /** Latched HIPAA declaration; absent or null means \"no claim\". */\n compliance?: HubAppComplianceClaim | null;\n status: \"active\" | \"revoked\";\n createdAt: string;\n updatedAt: string;\n}\nexport interface HubAppCreateInput {\n name: string;\n redirectUris: string[];\n allowedScopes: string[];\n homepageUrl?: string;\n /** The registered app owner funds eligibility; customer permissions remain separate. */\n accessPayer?: \"user\" | \"app-owner\";\n /** Associate an existing owned login client in the same transaction as creation. */\n oauthClientId?: string;\n}\nexport interface HubAppGrant {\n id: string;\n appId: string;\n userId: string;\n connectionId: string;\n scopes: string[];\n status: \"active\" | \"revoked\";\n createdAt: string;\n updatedAt: string;\n revokedAt: string | null;\n /** Display metadata is additive; older deployments may omit it. */\n appName?: string | null;\n oauthClientId?: string | null;\n providerId?: string | null;\n accountDisplay?: string | null;\n connectionDisplayName?: string | null;\n}\nexport interface HubAppGrantRevoked {\n grantId: string;\n status: \"revoked\";\n revokedAt: string | null;\n tokensRevoked: number;\n}\nfunction encodedId(id: string): string {\n if (\n typeof id !== \"string\" ||\n !id ||\n id.length > 256 ||\n id === \".\" ||\n id === \"..\"\n )\n throw new Error(\"A bounded app or grant id is required\");\n return encodeURIComponent(id);\n}\nexport class HubAppsClient {\n readonly grants: {\n list: () => Promise<HubAppGrant[]>;\n revoke: (grantId: string) => Promise<HubAppGrantRevoked>;\n };\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {\n this.grants = {\n list: () => this.request(\"/v1/me/app-grants\", { method: \"GET\" }),\n revoke: async (grantId) =>\n this.request(`/v1/me/app-grants/${encodedId(grantId)}/revoke`, {\n method: \"POST\",\n }),\n };\n }\n list(): Promise<HubApp[]> {\n return this.request(\"/v1/apps\", { method: \"GET\" });\n }\n /** The secret is returned only by creation; keep it in your server vault. */\n create(\n input: HubAppCreateInput,\n ): Promise<{ app: HubApp; clientSecret: string }> {\n return this.request(\"/v1/apps\", jsonInit(\"POST\", input));\n }\n /** Immutable association of two existing records with the same owner. */\n async linkOAuthClient(\n appId: string,\n clientId: string,\n ): Promise<{ appId: string; oauthClientId: string }> {\n return this.request(\n `/v1/apps/${encodedId(appId)}/oidc-client`,\n jsonInit(\"POST\", { clientId }),\n );\n }\n async revoke(\n appId: string,\n ): Promise<{ appId: string; grantsRevoked: number; tokensRevoked: number }> {\n return this.request(`/v1/apps/${encodedId(appId)}/revoke`, {\n method: \"POST\",\n });\n }\n /** Current latched compliance state and the BAA acceptance behind it. */\n async getCompliance(appId: string): Promise<HubAppComplianceState> {\n return this.request(`/v1/apps/${encodedId(appId)}/compliance`, {\n method: \"GET\",\n });\n }\n /**\n * Latch HIPAA compliance for this app. The request MUST carry the exact\n * `agreementVersion` the deployment currently offers — the acceptance is\n * recorded before the claim exists, and the claim can never be cleared:\n * `hipaa: false` on a latched app is a 409, on an unlatched app a no-op.\n */\n async setCompliance(\n appId: string,\n input: { hipaa: boolean; agreementVersion?: string },\n ): Promise<HubAppComplianceState> {\n return this.request(\n `/v1/apps/${encodedId(appId)}/compliance`,\n jsonInit(\"PUT\", input),\n );\n }\n}\n","export interface KnowledgeReference {\n sourceId: string;\n generation: string;\n}\n\nimport { jsonInit } from \"./json-init.js\";\n\n/** Connection references only. Provider credentials never enter this contract. */\nexport interface KnowledgeEmbeddingSpace {\n connectionId: string;\n model: string;\n dimensions: number;\n}\nexport type KnowledgeSourceInput =\n | { kind: \"file\"; name: string; base64: string; mediaType: string }\n | {\n kind: \"git\";\n connectionId: string;\n owner: string;\n repo: string;\n ref: string;\n pathPrefix?: string;\n }\n | { kind: \"url\"; url: string }\n | { kind: \"s3\"; connectionId: string; bucket: string; prefix: string }\n | {\n kind: \"vector\";\n connectionId: string;\n provider: \"pinecone\" | \"qdrant\" | \"weaviate\";\n indexName: string;\n namespace?: string;\n embedding: KnowledgeEmbeddingSpace;\n textField: string;\n sourceUriField: string;\n };\nexport interface KnowledgeCapability {\n supported: boolean;\n reason?: string;\n}\nexport interface KnowledgeCapabilities {\n delegation?: KnowledgeCapability & { resource?: string; scopes?: string[] };\n sources: Record<KnowledgeSourceInput[\"kind\"], KnowledgeCapability>;\n vectorProviders: Record<\n \"pinecone\" | \"qdrant\" | \"weaviate\",\n KnowledgeCapability\n >;\n managedVector: KnowledgeCapability;\n file: { mediaTypes: string[]; maxBytes: number; maxObjects: number };\n}\nexport interface KnowledgeSourceSummary {\n /** Required query authorization, not proof that an owner policy currently permits it. */\n retrieval?:\n | { kind: \"lexical\" }\n | {\n kind: \"vector\";\n embeddingPolicy: {\n connectionId: string;\n actionPath: \"openai.embeddings.create\";\n scope: \"owner-connection-action\";\n };\n };\n id: string;\n name: string;\n kind: KnowledgeSourceInput[\"kind\"];\n status: \"ready\" | \"refreshing\" | \"failed\" | \"awaiting-approval\";\n approval?: {\n id: string;\n path: string;\n preview: {\n provider: string;\n connectionId: string;\n collection: string;\n sourceId: string;\n requestId: string;\n embedding: KnowledgeEmbeddingSpace;\n chunkCount: number;\n sourceCount: number;\n dataSharing: string;\n };\n };\n refreshRequestId?: string;\n generation: string | null;\n lastError: { code: string; message: string } | null;\n updatedAt: string;\n}\nexport type KnowledgeAttachmentAuthorization =\n | { status: \"active\" }\n | {\n status: \"unavailable\";\n code:\n | \"APP_CONSENT_REVOKED\"\n | \"KEY_REVOKED\"\n | \"CONNECTION_UNAVAILABLE\"\n | \"ATTACHMENT_REVOKED\"\n | \"GENERATION_UNAVAILABLE\"\n | \"RUNTIME_AUTHORITY_REVOKED\";\n };\nexport interface KnowledgeAttachment {\n /** Snapshot of live grant/key/connection authority, separate from durable pin state. */\n authorization?: KnowledgeAttachmentAuthorization;\n id: string;\n sourceId: string;\n sandboxId: string;\n generation: string;\n status: \"active\" | \"detached\";\n}\nexport interface KnowledgeSourceCreate {\n requestId: string;\n name: string;\n source: KnowledgeSourceInput;\n target?:\n | { kind: \"lexical\" }\n | {\n kind: \"managed-vector\";\n provider: \"qdrant\";\n connectionId: string;\n embedding: KnowledgeEmbeddingSpace;\n };\n}\n\n/** Owner-only management. Runtime tools use HubKnowledgeClient.query instead. */\nexport interface KnowledgeAuthorization {\n userId: string;\n clientId: string;\n resource: string;\n scopes: Array<\"knowledge:read\" | \"knowledge:write\">;\n}\n\nexport class HubKnowledgeManagementClient {\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {}\n materialize(input: {\n sandboxId: string;\n references: KnowledgeReference[];\n }): Promise<KnowledgeAttachment[]> {\n return this.request(\n \"/v1/knowledge/attachments/materialize\",\n jsonInit(\"POST\", input),\n );\n }\n authorization(): Promise<KnowledgeAuthorization> {\n return this.request(\"/v1/knowledge/authorization\", { method: \"GET\" });\n }\n disconnectAuthorization(): Promise<{ revoked: true }> {\n return this.request(\"/v1/knowledge/authorization\", { method: \"DELETE\" });\n }\n capabilities(): Promise<KnowledgeCapabilities> {\n return this.request(\"/v1/knowledge/capabilities\", { method: \"GET\" });\n }\n list(): Promise<KnowledgeSourceSummary[]> {\n return this.request(\"/v1/knowledge/sources\", { method: \"GET\" });\n }\n get(sourceId: string): Promise<KnowledgeSourceSummary> {\n return this.request(\n `/v1/knowledge/sources/${encodeURIComponent(sourceId)}`,\n { method: \"GET\" },\n );\n }\n create(input: KnowledgeSourceCreate): Promise<KnowledgeSourceSummary> {\n return this.request(\"/v1/knowledge/sources\", jsonInit(\"POST\", input));\n }\n refresh(\n sourceId: string,\n input: { requestId: string; approvalToken?: string },\n ): Promise<KnowledgeSourceSummary> {\n return this.request(\n `/v1/knowledge/sources/${encodeURIComponent(sourceId)}/refresh`,\n jsonInit(\"POST\", input),\n );\n }\n attach(\n sourceId: string,\n input: {\n sandboxId: string;\n generation: string;\n expectedGeneration?: string;\n },\n ): Promise<KnowledgeAttachment> {\n return this.request(\n `/v1/knowledge/sources/${encodeURIComponent(sourceId)}/attachments`,\n jsonInit(\"POST\", input),\n );\n }\n attachments(sandboxId?: string): Promise<KnowledgeAttachment[]> {\n return this.request(\n `/v1/knowledge/attachments${sandboxId ? `?sandboxId=${encodeURIComponent(sandboxId)}` : \"\"}`,\n { method: \"GET\" },\n );\n }\n detach(attachmentId: string): Promise<KnowledgeAttachment> {\n return this.request(\n `/v1/knowledge/attachments/${encodeURIComponent(attachmentId)}`,\n { method: \"DELETE\" },\n );\n }\n}\n","import {\n HubKnowledgeManagementClient,\n type KnowledgeReference,\n} from \"./knowledge-management.js\";\n\nexport * from \"./knowledge-management.js\";\n\nimport { jsonInit } from \"./json-init.js\";\n\nexport interface HubKnowledgeRetrievalResult {\n attachmentId: string;\n generation: string;\n provenance: \"ingested\" | \"record-supplied\";\n hits: Array<{\n id: string;\n title: string;\n snippet: string;\n score?: number;\n citations?: Array<{\n sourceId: string;\n sourceUri: string;\n revision?: string;\n }>;\n }>;\n elapsedMs?: number;\n}\n\nexport interface HubKnowledgeQueryResult {\n results: HubKnowledgeRetrievalResult[];\n /** Individual unavailable sources do not hide evidence from healthy sources. */\n failures: Array<{ attachmentId: string; code: string; message: string }>;\n partial: boolean;\n}\n\n/** Runtime-only retrieval. The authenticated sandbox credential determines the\n * scope on the server; neither a caller nor an agent can supply another scope. */\nexport class HubKnowledgeClient {\n readonly management: HubKnowledgeManagementClient;\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {\n this.management = new HubKnowledgeManagementClient(request);\n }\n\n bindings(): Promise<{ references: KnowledgeReference[] }> {\n return this.request(\"/v1/knowledge/runtime/bindings\", { method: \"GET\" });\n }\n query(\n input: {\n query: string;\n limit?: number;\n expectedReferences?: KnowledgeReference[];\n },\n options?: { signal?: AbortSignal },\n ): Promise<HubKnowledgeQueryResult> {\n return this.request(\"/v1/knowledge/runtime/query\", {\n ...jsonInit(\"POST\", {\n query: input.query,\n ...(input.expectedReferences !== undefined\n ? { expectedReferences: input.expectedReferences }\n : {}),\n ...(input.limit !== undefined ? { limit: input.limit } : {}),\n }),\n signal: options?.signal,\n });\n }\n}\n","import { jsonInit } from \"./json-init.js\";\nimport type { HubWorkflow } from \"./types.js\";\n\nexport interface HubLineMember {\n id: string;\n label: string | null;\n role: string;\n self?: boolean;\n consent?: \"enabled\" | \"required\";\n}\n\nexport interface HubLineContext {\n self: { id: string; label: string | null; role: string };\n line: { id: string; label: string | null; transport: string };\n members: HubLineMember[];\n capabilities: Record<string, { allowed: boolean; reason?: string }>;\n pendingReminders: Array<{\n messageId: string;\n wakeAt?: string;\n prompt: string | null;\n }>;\n quotas: {\n selfMessagesToday: number;\n selfMessagesPerDay: number;\n selfMessagesPending: number;\n selfMessagesPendingLimit: number;\n };\n}\n\nexport interface HubLineSendInput {\n toMember: string;\n text: string;\n notBefore?: string;\n onBehalfOf?: string;\n idempotencyKey?: string;\n}\n\n/** An asset URL safe to share with the recipient and provider. Hub never fetches it.\n * Meta WhatsApp API-key lines send it with `text` as the caption. Other transports refuse it.\n * Use public HTTPS without a query, fragment or credentials. */\nexport interface HubLineImage {\n url: string;\n}\n\nexport interface HubLineOwnerSendInput {\n memberId: string;\n text: string;\n image?: HubLineImage;\n notBefore?: string;\n idempotencyKey: string;\n /** Ask a coded question; the member's reply that starts with `code` returns here. */\n reply?: HubLineReplyCodeInput;\n}\n\nexport interface HubLineReplyCodeInput {\n /** A letter, then up to seven letters or digits, with at least one digit (`F7`). Hub compares it case-insensitively. */\n code: string;\n /** 60 to 604800; the window opens when the send first becomes eligible. */\n ttlSeconds: number;\n /**\n * 1 to 20 distinct texted choices, each 1-32 of `a-z 0-9 _ -` after lower-casing.\n * An answer must then be `<code> <option>[ <note>]`; any other coded text keeps the question open.\n */\n options?: string[];\n}\n\n/** The coded question's state on an owner send receipt. */\nexport interface HubLineReplyCode {\n /** Upper case. */\n code: string;\n expiresAt: string;\n /** Authoritative closure fence; absent on older Hub, never infer it from local time. */\n closed?: boolean;\n /** The first coded answer; `text` is null after content retention ends. */\n answer: {\n messageId: string;\n text: string | null;\n receivedAt: string;\n /** The named option, lower case; null when the send listed no options. */\n option: string | null;\n /** Words after the option; null when there were none or retention ended. */\n note: string | null;\n } | null;\n}\n\nexport interface HubLineReminderInput {\n text: string;\n notBefore: string;\n idempotencyKey: string;\n}\n\nexport interface HubLineApplicationDispatchCurrentInput {\n attachmentId: string;\n memberId: string;\n memberRevision: string;\n senderAddress: string;\n textSha256: string;\n binding: string;\n dispatchFence: string;\n dispatchDeadline: string;\n}\n\nexport interface HubLineMemberApplication {\n id: string;\n lineId: string;\n attachmentId: string;\n memberId: string;\n subjectId: string;\n status: \"active\" | \"revoked\";\n application: { url: string; binding: string };\n /** Hub's name for the app at this callback; present on reads. */\n app?: { name: string };\n createdAt: string;\n revokedAt: string | null;\n}\n\nexport interface HubLineMemberApplicationInput {\n expectedSelectionId: string | null;\n expectedMemberRevision: string;\n subjectId: string;\n application: { url: string; binding: string; secret: string };\n}\n\nexport interface HubLineProviderDelivery {\n provider: \"meta_whatsapp\";\n messageId: string;\n acceptedAt: string;\n sentAt: string | null;\n deliveredAt: string | null;\n readAt: string | null;\n failedAt: string | null;\n failureCode: number | null;\n}\n\nexport interface HubLineSendReceipt {\n /** Absent on older Hub. Replied/accepted never implies delivered. */\n delivery?: HubLineProviderDelivery | null;\n message: {\n id: string;\n status: string;\n text: string | null;\n image?: HubLineImage;\n };\n eligibleAt: string | null;\n expiresAt: string;\n /** Null when the send asked no coded question; absent from Hub before reply codes. */\n reply?: HubLineReplyCode | null;\n}\n\nexport interface HubLineReminderReceipt {\n state: \"queued\" | \"skipped\";\n lineId: string;\n messageId?: string;\n sessionId?: string;\n completion?: string;\n reason?: string;\n}\n\nexport interface HubLineScheduledSendOptions {\n lineId: string;\n memberId: string;\n text: string;\n timezone: string;\n name?: string;\n notBefore?: string;\n /**\n * RFC 3339 instant the schedule stops at. Required when the calling key\n * expires, and no later than that expiry: a schedule never outlives the\n * key that wrote it.\n */\n until?: string;\n}\n\nexport interface HubLineCheckinOptions {\n lineId: string;\n member: string;\n timezone: string;\n prompt: string;\n name?: string;\n /** RFC 3339 instant the schedule stops at; see {@link HubLineScheduledSendOptions.until}. */\n until?: string;\n}\n\n/** The `on.schedule` mapping a Line schedule helper writes. */\nfunction scheduleYaml(cron: string, timezone: string, until?: string): string {\n const fields = [\n `cron: ${JSON.stringify(cron)}`,\n `timezone: ${JSON.stringify(timezone)}`,\n ...(until ? [`until: ${JSON.stringify(until)}`] : []),\n ];\n return ` schedule: { ${fields.join(\", \")} }`;\n}\n\n/** Line calls share HubClient authentication and envelope handling. */\nexport class HubLinesClient {\n readonly members: { list: (lineId: string) => Promise<HubLineMember[]> };\n readonly memberApplications: {\n get: (\n lineId: string,\n memberId: string,\n ) => Promise<{\n memberRevision: string;\n selection: HubLineMemberApplication | null;\n }>;\n select: (\n lineId: string,\n memberId: string,\n input: HubLineMemberApplicationInput,\n ) => Promise<HubLineMemberApplication>;\n clear: (\n lineId: string,\n memberId: string,\n input: {\n expectedSelectionId: string;\n expectedMemberRevision: string;\n },\n ) => Promise<void>;\n };\n readonly checkins: {\n schedule: (\n cron: string,\n options: HubLineCheckinOptions,\n ) => Promise<HubWorkflow>;\n };\n\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n private readonly createWorkflow: (yaml: string) => Promise<HubWorkflow>,\n private readonly requestApplicationDispatchCurrent?: (\n path: string,\n init: RequestInit,\n callbackBearer: string,\n ) => Promise<{ current: boolean }>,\n ) {\n this.members = {\n list: async (lineId) =>\n (\n await this.request<{ members: HubLineMember[] }>(\n `/v1/hub/lines/${encodeURIComponent(lineId)}/members`,\n { method: \"GET\" },\n )\n ).members,\n };\n const applicationPath = (lineId: string, memberId: string) =>\n `/v1/hub/lines/${encodeURIComponent(lineId)}/members/${encodeURIComponent(memberId)}/application`;\n this.memberApplications = {\n get: async (lineId, memberId) =>\n await this.request<{\n memberRevision: string;\n selection: HubLineMemberApplication | null;\n }>(applicationPath(lineId, memberId), { method: \"GET\" }),\n select: async (lineId, memberId, input) =>\n (\n await this.request<{ selection: HubLineMemberApplication }>(\n applicationPath(lineId, memberId),\n jsonInit(\"PUT\", input),\n )\n ).selection,\n clear: async (lineId, memberId, input) => {\n await this.request(\n applicationPath(lineId, memberId),\n jsonInit(\"DELETE\", input),\n );\n },\n };\n this.checkins = {\n schedule: (cron, options) => {\n const name =\n options.name ?? `line-checkin-${crypto.randomUUID().slice(0, 8)}`;\n const yaml = [\n `name: ${JSON.stringify(name)}`,\n \"on:\",\n scheduleYaml(cron, options.timezone, options.until),\n \"do:\",\n \" - agent.run:\",\n \" line:\",\n ` id: ${JSON.stringify(options.lineId)}`,\n ` member: ${JSON.stringify(options.member)}`,\n ` prompt: ${JSON.stringify(options.prompt)}`,\n ].join(\"\\n\");\n return this.createWorkflow(yaml);\n },\n };\n }\n\n async scheduleSend(\n cron: string,\n options: HubLineScheduledSendOptions,\n ): Promise<HubWorkflow> {\n const name = options.name ?? `line-send-${crypto.randomUUID().slice(0, 8)}`;\n const yaml = [\n `name: ${JSON.stringify(name)}`,\n \"on:\",\n scheduleYaml(cron, options.timezone, options.until),\n \"do:\",\n \" - line.send:\",\n ` lineId: ${JSON.stringify(options.lineId)}`,\n ` memberId: ${JSON.stringify(options.memberId)}`,\n ` text: ${JSON.stringify(options.text)}`,\n ...(options.notBefore\n ? [` notBefore: ${JSON.stringify(options.notBefore)}`]\n : []),\n ].join(\"\\n\");\n return this.createWorkflow(yaml);\n }\n\n async context(): Promise<HubLineContext> {\n return this.request<HubLineContext>(\"/v1/hub/lines/context\", {\n method: \"GET\",\n });\n }\n\n async send(\n lineId: string,\n input: HubLineSendInput | HubLineOwnerSendInput,\n ): Promise<HubLineSendReceipt> {\n return this.request<HubLineSendReceipt>(\n `/v1/hub/lines/${encodeURIComponent(lineId)}/send`,\n jsonInit(\"POST\", input),\n );\n }\n\n /** Read an owner send's receipt, including its coded answer. Queued is not delivered. */\n async sentMessage(\n lineId: string,\n messageId: string,\n ): Promise<HubLineSendReceipt> {\n return this.request<HubLineSendReceipt>(\n `/v1/hub/lines/${encodeURIComponent(lineId)}/outbox/${encodeURIComponent(messageId)}`,\n { method: \"GET\" },\n );\n }\n\n async remind(\n lineId: string,\n input: HubLineReminderInput,\n ): Promise<HubLineReminderReceipt> {\n return this.request<HubLineReminderReceipt>(\n `/v1/hub/lines/${encodeURIComponent(lineId)}/remind`,\n jsonInit(\"POST\", input),\n );\n }\n\n async applicationDispatchCurrent(\n lineId: string,\n messageId: string,\n input: HubLineApplicationDispatchCurrentInput,\n callbackBearer: string,\n ): Promise<boolean> {\n if (!this.requestApplicationDispatchCurrent) {\n throw new Error(\"Use HubClient to check application dispatch authority\");\n }\n const result = await this.requestApplicationDispatchCurrent(\n `/v1/hub/lines/${encodeURIComponent(lineId)}/messages/${encodeURIComponent(messageId)}/application-dispatch/current`,\n jsonInit(\"POST\", input),\n callbackBearer,\n );\n return result.current;\n }\n}\n","import { jsonInit } from \"./json-init.js\";\n\nexport interface HubNumberReadiness {\n configured: boolean;\n provider: \"inkbox\";\n transports: Array<\"sms\" | \"imessage\">;\n billing: \"prepaid_activation\";\n automaticRentalBilling: false;\n deliveryVerified: false;\n}\nexport interface HubNumberQuote {\n transport: \"sms\" | \"imessage\";\n activationCents: number;\n currency: \"usd\";\n termsVersion: string;\n terms: string;\n expiresAt: number;\n /** The binding the quote was issued for. Absent from older servers. */\n clientReference?: string;\n /** Opaque. Pass it back to `create`; never decode it. */\n token: string;\n}\n/** One page of the owner's orders, newest first. */\nexport interface HubNumberOrderPage {\n orders: HubNumberOrder[];\n /** Present while more orders exist. Older servers omit it and return one\n * bounded page, so an absent cursor never proves an order does not exist. */\n nextCursor?: string | null;\n}\nexport interface HubNumberListQuery {\n /** Only orders requested for this binding, including closed ones. */\n clientReference?: string;\n cursor?: string;\n /** 1 to 100; the server default is 100. */\n limit?: number;\n}\n/** An operator's terminal decision on an order stuck in `needs_review`.\n * Read-only for a creator: the resolution is made through the platform's\n * admin surface, never through this client. */\nexport interface HubNumberResolution {\n action: \"release\" | \"settle\" | \"abandon\";\n operator: string;\n reason: string;\n at: number;\n /** Present while the operator's action is still running. The decision is\n * not final and the order can still return to review. */\n pending?: true;\n /** Present when a `settle` handed a live, unfinished order back to\n * provisioning, so the order is working again rather than closed. */\n requeued?: true;\n}\nexport interface HubNumberOrder {\n id: string;\n clientReference: string;\n transport: \"sms\" | \"imessage\";\n status:\n | \"pending\"\n | \"provider_pending\"\n | \"needs_review\"\n | \"ready_for_setup\"\n | \"cancelled\";\n phase: \"identity\" | \"number\" | \"credential\" | \"connection\" | \"complete\";\n address: string | null;\n connectionId: string | null;\n identityId: string | null;\n providerNumberId: string | null;\n billingStatus: \"unreserved\" | \"reserved\" | \"settled\" | \"released\";\n cancellation:\n | \"none\"\n | \"requested\"\n | \"needs_review\"\n | \"released\"\n | \"abandoned\";\n errorCode: string | null;\n nextAttemptAt: number | null;\n resolution: HubNumberResolution | null;\n deliveryVerified: false;\n activationCents: number;\n currency: \"usd\";\n terms: string;\n}\n/** Every body this client may send. The server owns price, owner and funding; none of them appear here. */\ntype HubNumberRequestBody =\n | Record<string, never>\n | { transport: \"sms\" | \"imessage\"; clientReference: string }\n | { clientReferences: string[] }\n | {\n quoteToken: string;\n consent: true;\n state?: string;\n clientReference?: string;\n transport?: \"sms\" | \"imessage\";\n };\n\n/** Administrative number operations through Hub's authenticated transport.\n * A mutation is one attempt; an uncertain create reuses its quote and reference. */\nexport class HubManagedNumbersClient {\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {}\n readiness(): Promise<HubNumberReadiness> {\n return this.request(\"/v1/hub/numbers/readiness\", { method: \"GET\" });\n }\n /** One page of orders. Scope by `clientReference` to ask about one binding,\n * and follow `nextCursor` for the rest; a page is never ownership evidence. */\n list(query: HubNumberListQuery = {}): Promise<HubNumberOrderPage> {\n const params = new URLSearchParams();\n if (query.clientReference !== undefined)\n params.set(\"clientReference\", query.clientReference);\n if (query.cursor !== undefined) params.set(\"cursor\", query.cursor);\n if (query.limit !== undefined) params.set(\"limit\", String(query.limit));\n const search = params.toString();\n return this.request(`/v1/hub/numbers${search ? `?${search}` : \"\"}`, {\n method: \"GET\",\n });\n }\n get(id: string): Promise<{ order: HubNumberOrder }> {\n return this.request(this.path(id), { method: \"GET\" });\n }\n quote(input: {\n transport: \"sms\" | \"imessage\";\n clientReference: string;\n }): Promise<{ quote: HubNumberQuote }> {\n return this.request(\"/v1/hub/numbers/quote\", this.post(input));\n }\n /** `clientReference` and `transport`, when given, must match the signed\n * quote or Hub refuses the purchase with a conflict. */\n create(input: {\n quoteToken: string;\n consent: true;\n state?: string;\n clientReference?: string;\n transport?: \"sms\" | \"imessage\";\n }): Promise<{ order: HubNumberOrder }> {\n return this.request(\"/v1/hub/numbers\", this.post(input));\n }\n /** Fences references so no order can take them again. Call it as the last\n * step before retiring the resource they name: a purchase that races the\n * retirement is then refused (`409 number_reference_fenced`) instead of\n * binding a line to a resource that is gone. Refused with\n * `409 number_reference_held` while a live order holds one of them; cancel\n * it first. A cancelled order no longer holds its reference, so the fence\n * succeeds as soon as `cancel` returns, whether or not its release is still\n * pending. Repeating a fence is harmless. */\n fence(input: {\n clientReferences: string[];\n }): Promise<{ clientReferences: string[] }> {\n return this.request(\"/v1/hub/numbers/fences\", this.post(input));\n }\n advance(id: string): Promise<{ order: HubNumberOrder }> {\n return this.request(`${this.path(id)}/advance`, this.post({}));\n }\n cancel(id: string): Promise<{ order: HubNumberOrder }> {\n return this.request(`${this.path(id)}/cancel`, this.post({}));\n }\n private path(id: string) {\n if (!/^num_[a-f0-9]{36}$/.test(id))\n throw new Error(\"Invalid managed number order id\");\n return `/v1/hub/numbers/${encodeURIComponent(id)}`;\n }\n private post(body: HubNumberRequestBody): RequestInit {\n return jsonInit(\"POST\", body);\n }\n}\n","const SECRET_KEY_PATTERN =\n /(api[_-]?key|authorization|capability[_-]?token|token|secret)/i;\nconst SECRET_VALUE_PATTERN =\n /\\b(?:sk-tan[-_]|hubcap_|hct_|lrc_|gh[pousr]_)[A-Za-z0-9_.=-]+\\b/g;\n\n// oxlint-disable-next-line anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Error details are untrusted JSON and retain their shape after redaction.\nexport function redactHubValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return value.replace(SECRET_VALUE_PATTERN, \"[REDACTED]\");\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => redactHubValue(item));\n }\n\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n SECRET_KEY_PATTERN.test(key)\n ? \"[REDACTED]\"\n : redactHubValue(entryValue),\n ]),\n );\n }\n\n return value;\n}\n","import { redactHubValue } from \"./redaction.js\";\nimport type {\n HubErrorBody,\n HubErrorEnvelope,\n HubSuccessEnvelope,\n HubWorkflowArtifactDownload,\n} from \"./types.js\";\n\nexport type HubAuthHeaders = () => HeadersInit | Promise<HeadersInit>;\n\nexport interface HubClientOptions {\n baseUrl: string;\n apiKey?: string;\n authHeaders?: HubAuthHeaders;\n fetch?: typeof fetch;\n}\n\nexport class HubSdkError extends Error {\n readonly code: HubErrorBody[\"code\"];\n readonly details?: unknown;\n readonly status?: number;\n\n constructor(error: HubErrorBody, options: { status?: number } = {}) {\n super(String(redactHubValue(error.message)));\n this.name = \"HubSdkError\";\n this.code = error.code;\n this.details = redactHubValue(error.details);\n this.status = options.status;\n }\n}\n\n// Cap a response body at a readable length for inclusion in an error's\n// `details.bodySnippet`. The HubSdkError constructor runs the result through\n// `redactHubValue`, so token-shaped substrings in an upstream error page are\n// scrubbed before they reach the snippet.\nfunction bodySnippet(body: string, max = 200): string {\n const trimmed = body.trim();\n return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;\n}\n\n// Transport-level failure: the response was not a hub envelope. Carries the\n// numeric HTTP status on both `code` (HUB_HTTP_<status>) and `status`, plus a\n// body snippet, so callers see the real status instead of a JSON parse error.\nexport function httpError(\n path: string,\n status: number,\n statusText: string,\n body: string,\n contentType: string,\n omitResponseDetails = false,\n): HubSdkError {\n const suffix = !omitResponseDetails && statusText ? ` ${statusText}` : \"\";\n return new HubSdkError(\n {\n code: `HUB_HTTP_${status}`,\n message: `Hub request ${path} failed: HTTP ${status}${suffix}`,\n details: {\n status,\n path,\n ...(omitResponseDetails\n ? {}\n : {\n contentType: contentType || null,\n bodySnippet: bodySnippet(body),\n }),\n },\n },\n { status },\n );\n}\n\nfunction isHubErrorEnvelope(value: unknown): value is HubErrorEnvelope {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { success?: unknown; error?: unknown };\n if (candidate.success !== false) return false;\n const error = candidate.error as { code?: unknown } | undefined;\n return (\n typeof error === \"object\" &&\n error !== null &&\n typeof error.code === \"string\"\n );\n}\n\nfunction isHubSuccessEnvelope<TData>(\n value: unknown,\n): value is HubSuccessEnvelope<TData> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { success?: unknown }).success === true\n );\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport class HubTransport {\n readonly baseUrl: string;\n readonly fetch: typeof fetch;\n readonly authHeaders?: HubAuthHeaders;\n // An ES private field: a public or TypeScript-private property prints\n // with the client, its sub-clients and anything holding them.\n readonly #apiKey?: string;\n\n constructor(options: HubClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.#apiKey = options.apiKey;\n this.authHeaders = options.authHeaders;\n // Cloudflare Workers' global fetch needs the global receiver.\n this.fetch = options.fetch ?? fetch.bind(globalThis);\n }\n\n /** The API key this client authenticates with, when it has one. */\n get apiKey(): string | undefined {\n return this.#apiKey;\n }\n\n protected async request<TData>(\n path: string,\n init: RequestInit,\n options: {\n auth?: \"client\" | \"caller\";\n validateData?: (data: unknown) => data is TData;\n } = {},\n ): Promise<TData> {\n const callerAuth = options.auth === \"caller\";\n const response = await this.fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: await this.buildHeaders(init.headers, callerAuth),\n });\n\n const status = response.status;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const bodyText = await response.text();\n\n // The hub envelope is always JSON. A non-JSON body (gateway/HTML error\n // page, redirect, plaintext, wrong host) is not an envelope — surface the\n // HTTP status + a body snippet rather than letting JSON parsing throw an\n // opaque SyntaxError that hides the real status.\n if (!contentType.includes(\"application/json\")) {\n throw httpError(\n path,\n status,\n response.statusText,\n bodyText,\n contentType,\n callerAuth,\n );\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyText);\n } catch {\n // JSON content-type but an unparseable body — still a transport-level\n // failure, not a hub envelope.\n throw httpError(\n path,\n status,\n response.statusText,\n bodyText,\n contentType,\n callerAuth,\n );\n }\n\n // A typed error envelope (success: false) keeps the server's code/status,\n // including on non-2xx responses (e.g. HUB_NOT_FOUND on 404).\n if (isHubErrorEnvelope(parsed)) {\n if (callerAuth) {\n throw new HubSdkError(\n {\n code: parsed.error.code,\n message: `Hub request ${path} failed: HTTP ${status}`,\n },\n { status },\n );\n }\n throw new HubSdkError(parsed.error, { status });\n }\n if (isHubSuccessEnvelope<TData>(parsed)) {\n if (callerAuth && !response.ok) {\n throw httpError(\n path,\n status,\n response.statusText,\n bodyText,\n contentType,\n callerAuth,\n );\n }\n if (options.validateData && !options.validateData(parsed.data)) {\n throw new HubSdkError(\n {\n code: `HUB_HTTP_${status}`,\n message: `Hub request ${path} returned invalid data`,\n details: { status, path },\n },\n { status },\n );\n }\n return parsed.data;\n }\n\n // Valid JSON, but not a hub envelope (e.g. a proxy's own error shape).\n throw httpError(\n path,\n status,\n response.statusText,\n bodyText,\n contentType,\n callerAuth,\n );\n }\n\n protected async buildHeaders(\n headers: HeadersInit | undefined,\n callerAuth = false,\n ) {\n const mergedHeaders = new Headers({ Accept: \"application/json\" });\n\n if (!callerAuth && this.apiKey) {\n mergedHeaders.set(\"Authorization\", `Bearer ${this.apiKey}`);\n }\n\n if (!callerAuth && this.authHeaders) {\n for (const [key, value] of new Headers(await this.authHeaders())) {\n mergedHeaders.set(key, value);\n }\n }\n\n // Caller headers take precedence, including a streaming Accept value.\n for (const [key, value] of new Headers(headers)) {\n mergedHeaders.set(key, value);\n }\n\n return mergedHeaders;\n }\n}\n/** Domain clients receive the existing envelope transport as one request function. */\nexport type HubRequest = <TData>(\n path: string,\n init: RequestInit,\n) => Promise<TData>;\nexport type HubStreamRequest = (\n path: string,\n init: RequestInit,\n) => Promise<ReadableStream<Uint8Array>>;\nexport type HubArtifactRequest = (\n path: string,\n init: RequestInit,\n) => Promise<HubWorkflowArtifactDownload>;\n\n/** Decode a failed non-envelope response using the same redacted SDK errors. */\nexport async function throwHubResponseError(\n path: string,\n response: Response,\n status: number,\n contentType: string,\n): Promise<never> {\n const bodyText = await response.text().catch(() => \"\");\n if (contentType.includes(\"application/json\")) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyText);\n } catch {\n parsed = undefined;\n }\n if (isHubErrorEnvelope(parsed)) {\n throw new HubSdkError(parsed.error, { status });\n }\n }\n throw httpError(path, status, response.statusText, bodyText, contentType);\n}\n","import { type HubAuthHeaders, HubSdkError } from \"./transport.js\";\n\n// Wire-contract env var names. Sandboxes and the CLI set these exact names,\n// so any drift here is a contract break.\nexport const HUB_URL_ENV_VAR = \"TANGLE_HUB_URL\" as const;\n\nexport const HUB_API_KEY_ENV_VAR = \"TANGLE_API_KEY\" as const;\n\nexport const HUB_CAPABILITY_TOKEN_ENV_VAR =\n \"TANGLE_HUB_CAPABILITY_TOKEN\" as const;\n\nexport type HubEnv = Record<string, string | undefined>;\n\nexport interface HubClientFromEnvOptions {\n env?: HubEnv;\n apiKey?: string;\n authHeaders?: HubAuthHeaders;\n fetch?: typeof fetch;\n}\n\n// Read TANGLE_HUB_URL from env. Strips trailing slashes and the optional\n// `/v1/hub` suffix so the result is the platform root the SDK appends\n// `/v1/hub/...` to. No default — throws HubSdkError on undefined / empty /\n// non-URL. SaaS vs on-prem flips via env only.\nexport function resolveHubBaseUrl(env: HubEnv = readProcessEnv()): string {\n const raw = env[HUB_URL_ENV_VAR];\n if (raw === undefined || raw.trim() === \"\") {\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: `${HUB_URL_ENV_VAR} is required`,\n details: { envVar: HUB_URL_ENV_VAR },\n });\n }\n\n const trimmed = raw.trim();\n try {\n new URL(trimmed);\n } catch {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message: `${HUB_URL_ENV_VAR} is not a valid URL`,\n details: { envVar: HUB_URL_ENV_VAR },\n });\n }\n\n return trimmed.replace(/\\/+$/, \"\").replace(/\\/v1\\/hub$/, \"\");\n}\n\n// Read exactly one Hub auth credential: an API key or a capability token,\n// never both. No default; throws on none-or-both.\nexport function resolveHubAuth(env: HubEnv = readProcessEnv()): string {\n const apiKey = nonEmpty(env[HUB_API_KEY_ENV_VAR]);\n const capabilityToken = nonEmpty(env[HUB_CAPABILITY_TOKEN_ENV_VAR]);\n const present = [apiKey, capabilityToken].filter(\n (value): value is string => value !== undefined,\n );\n\n if (present.length === 0) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: `One of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR} is required`,\n details: {\n envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR],\n },\n });\n }\n if (present.length > 1) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message: `Set exactly one of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR}, not both`,\n details: {\n envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR],\n },\n });\n }\n\n return present[0];\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const trimmed = value.trim();\n return trimmed.length === 0 ? undefined : trimmed;\n}\n\nexport function readProcessEnv(): HubEnv {\n // Browsers / Workers may not expose `process`. Callers there must pass `env`.\n const proc = (globalThis as { process?: { env?: HubEnv } }).process;\n return proc?.env ?? {};\n}\n","import { jsonInit } from \"./json-init.js\";\nimport type { HubRequest } from \"./transport.js\";\nimport type {\n HubAllowWritesResponse,\n HubApprovalDecisionResponse,\n HubApprovalListResponse,\n HubPolicyDeleteRequest,\n HubPolicyDeleteResponse,\n HubPolicyListResponse,\n HubPolicyResponse,\n HubPolicyUpdateRequest,\n HubRevertWritesResponse,\n HubTokenMintResponse,\n HubTokenRevokeResponse,\n HubTokensListResponse,\n} from \"./types.js\";\n\nexport interface HubTokenListOptions {\n includeExpired?: boolean;\n}\n\nexport class HubTokensClient {\n constructor(private readonly request: HubRequest) {}\n\n async mint(options: {\n actionPath: string;\n connectionId?: string;\n provider?: string;\n ttlSeconds?: number;\n }): Promise<HubTokenMintResponse> {\n return this.request<HubTokenMintResponse>(\n \"/v1/hub/tokens\",\n jsonInit(\"POST\", options),\n );\n }\n\n async list(\n options: HubTokenListOptions = {},\n ): Promise<HubTokensListResponse> {\n const searchParams = new URLSearchParams();\n if (options.includeExpired) searchParams.set(\"includeExpired\", \"true\");\n const query = searchParams.toString();\n const response = await this.request<HubTokensListResponse>(\n `/v1/hub/tokens${query ? `?${query}` : \"\"}`,\n { method: \"GET\" },\n );\n return {\n tokens: response.tokens.map((token) => ({\n id: token.id,\n providerId: token.providerId,\n connectionId: token.connectionId,\n connectionDisplay: token.connectionDisplay,\n actionPath: token.actionPath,\n expiresAt: token.expiresAt,\n status: token.status,\n principalKind: token.principalKind,\n createdAt: token.createdAt,\n })),\n };\n }\n\n async revoke(tokenId: string): Promise<HubTokenRevokeResponse> {\n const response = await this.request<HubTokenRevokeResponse>(\n `/v1/hub/tokens/${encodeURIComponent(tokenId)}`,\n { method: \"DELETE\" },\n );\n return {\n tokenId: response.tokenId,\n status: response.status,\n };\n }\n}\n\nexport class HubPermissionsClient {\n constructor(private readonly request: HubRequest) {}\n\n async list(connectionId: string): Promise<HubPolicyListResponse> {\n return this.request<HubPolicyListResponse>(\n `/v1/hub/policies?connectionId=${encodeURIComponent(connectionId)}`,\n { method: \"GET\" },\n );\n }\n\n async set(input: HubPolicyUpdateRequest): Promise<HubPolicyResponse> {\n return this.request<HubPolicyResponse>(\n \"/v1/hub/policies\",\n jsonInit(\"PUT\", input),\n );\n }\n\n /** Reset an action to its default by deleting any stored override. */\n async delete(\n input: HubPolicyDeleteRequest,\n ): Promise<HubPolicyDeleteResponse> {\n return this.request<HubPolicyDeleteResponse>(\n \"/v1/hub/policies\",\n jsonInit(\"DELETE\", input),\n );\n }\n\n /** Bulk-allow every write action of a connection's provider. Reads are\n * already allowed for sandbox agents; destructive actions stay `ask`.\n * Idempotent: actions with an existing policy are left untouched. */\n async allowWrites(connectionId: string): Promise<HubAllowWritesResponse> {\n return this.request<HubAllowWritesResponse>(\n \"/v1/hub/policies/allow-writes\",\n jsonInit(\"POST\", { connectionId }),\n );\n }\n\n /** Inverse of `allowWrites`: delete only the rows it created for this\n * connection. Manual per-action decisions are left intact. */\n async revertWrites(connectionId: string): Promise<HubRevertWritesResponse> {\n return this.request<HubRevertWritesResponse>(\n \"/v1/hub/policies/revert-writes\",\n jsonInit(\"POST\", { connectionId }),\n );\n }\n}\n\nexport class HubApprovalsClient {\n constructor(private readonly request: HubRequest) {}\n\n async list(): Promise<HubApprovalListResponse> {\n return this.request<HubApprovalListResponse>(\"/v1/hub/approvals\", {\n method: \"GET\",\n });\n }\n\n async approve(approvalId: string): Promise<HubApprovalDecisionResponse> {\n return this.request<HubApprovalDecisionResponse>(\n `/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`,\n { method: \"POST\" },\n );\n }\n\n async deny(approvalId: string): Promise<HubApprovalDecisionResponse> {\n return this.request<HubApprovalDecisionResponse>(\n `/v1/hub/approvals/${encodeURIComponent(approvalId)}/deny`,\n { method: \"POST\" },\n );\n }\n}\n","import { jsonInit } from \"./json-init.js\";\nimport { type HubRequest, HubSdkError } from \"./transport.js\";\nimport type {\n HubApprovalDecisionResponse,\n HubExecResponse,\n HubTokenMintResponse,\n HubToolSourcesResponse,\n HubToolsDescribeResponse,\n HubToolsSearchResponse,\n} from \"./types.js\";\n\nexport interface HubToolSearchOptions {\n provider?: string;\n /** Max tools to return. The server defaults to a relevance-ranked shortlist\n * (20); pass a higher value (bounded server-side) to enumerate a provider's\n * full action list, e.g. for a catalog/browse UI. The cap bounds the MERGED\n * response across sources — with no `provider` set, a low limit can exclude\n * some providers' tools, so scope by `provider` when you need one connector's\n * complete list. */\n limit?: number;\n}\n\nexport interface HubToolInvokeOptions {\n connectionId?: string;\n approve?: boolean;\n /** Caller-minted key for this invoke. On the direct exec arm the platform\n * ledger replays the first call's result for a retry that carries the same\n * key, and refuses a key bound to a different request. The approval and\n * capability-token retries re-send the key, and the connector receives it\n * for provider-native dedupe. Capability-token execution stays at-most-once\n * per token: it refuses a replay instead of replaying a stored result. */\n idempotencyKey?: string;\n}\n\nexport class HubToolsClient {\n constructor(private readonly request: HubRequest) {}\n\n async search(\n query: string,\n options: HubToolSearchOptions = {},\n ): Promise<HubToolsSearchResponse> {\n return this.request<HubToolsSearchResponse>(\n \"/v1/hub/tools/search\",\n jsonInit(\"POST\", {\n query,\n provider: options.provider,\n limit: options.limit,\n }),\n );\n }\n\n async sources(): Promise<HubToolSourcesResponse> {\n return this.request<HubToolSourcesResponse>(\"/v1/hub/tools/sources\", {\n method: \"GET\",\n });\n }\n\n async describe(path: string): Promise<HubToolsDescribeResponse> {\n return this.request<HubToolsDescribeResponse>(\n \"/v1/hub/tools/describe\",\n jsonInit(\"POST\", { path }),\n );\n }\n\n /**\n * Run one hub tool. `raw` is the tool input: the SDK forwards it verbatim as\n * the request body's `input`, and the server validates it against the tool's\n * own schema, so the client never gives it a shape.\n */\n async invoke<TResult = unknown>(\n path: string,\n raw: unknown,\n options: HubToolInvokeOptions = {},\n ): Promise<HubExecResponse<TResult>> {\n const execInit = this.buildExecInit(path, raw, options);\n try {\n return await this.request<HubExecResponse<TResult>>(\n \"/v1/hub/exec\",\n execInit,\n );\n } catch (error) {\n if (!(error instanceof HubSdkError) || !requiresCapabilityToken(error)) {\n throw error;\n }\n const approvalId = getApprovalId(error);\n // Keep the action-bound approval instead of creating a second token approval.\n if (approvalId && options.approve !== true) throw error;\n if (options.approve) {\n if (!approvalId) throw error;\n const approved = await this.request<HubApprovalDecisionResponse>(\n `/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`,\n { method: \"POST\" },\n );\n validateApprovedExecution(approved, path, options.connectionId);\n if (!approved.capabilityToken?.token) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Hub approval did not return a capability token\",\n details: { approvalId },\n });\n }\n return this.request<HubExecResponse<TResult>>(\"/v1/hub/exec\", {\n ...execInit,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${approved.capabilityToken.token}`,\n },\n });\n }\n }\n\n const minted = await this.request<HubTokenMintResponse>(\n \"/v1/hub/tokens\",\n jsonInit(\"POST\", {\n actionPath: path,\n connectionId: options.connectionId,\n provider: options.connectionId ? undefined : path.split(\".\")[0],\n }),\n );\n\n return this.request<HubExecResponse<TResult>>(\"/v1/hub/exec\", {\n ...execInit,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${minted.token}`,\n },\n });\n }\n\n private buildExecInit(\n path: string,\n raw: unknown,\n options: HubToolInvokeOptions,\n ): RequestInit {\n return jsonInit(\"POST\", {\n path,\n input: raw,\n connectionId: options.connectionId,\n idempotencyKey: options.idempotencyKey,\n });\n }\n}\n\nfunction requiresCapabilityToken(error: HubSdkError): boolean {\n return error.code === \"HUB_APPROVAL_REQUIRED\";\n}\n\nfunction getApprovalId(error: HubSdkError): string | undefined {\n const id = (error.details as { approval?: { id?: unknown } } | undefined)\n ?.approval?.id;\n return typeof id === \"string\" ? id : undefined;\n}\n\nfunction validateApprovedExecution(\n approved: HubApprovalDecisionResponse,\n path: string,\n connectionId: string | undefined,\n): void {\n if (approved.approval.actionPath !== path) {\n throw new HubSdkError({\n code: \"HUB_POLICY_DENIED\",\n message: \"Hub approval action does not match requested execution\",\n details: {\n approvalId: approved.approval.id,\n expectedActionPath: path,\n approvalActionPath: approved.approval.actionPath,\n },\n });\n }\n if (\n connectionId !== undefined &&\n approved.approval.connectionId !== connectionId\n ) {\n throw new HubSdkError({\n code: \"HUB_POLICY_DENIED\",\n message: \"Hub approval connection does not match requested execution\",\n details: {\n approvalId: approved.approval.id,\n expectedConnectionId: connectionId,\n approvalConnectionId: approved.approval.connectionId,\n },\n });\n }\n}\n","import { jsonInit } from \"./json-init.js\";\n\n/** Provider setup uses the existing authenticated Hub transport and vault. */\nexport interface HubInboundWebhookCreateOptions {\n /** Inkbox identity that owns all selected channels. */\n identityId?: string;\n mailboxId?: string;\n phoneNumberId?: string;\n imessage?: boolean;\n /** Linq: explicit owned lines; omitted does not mean every account line. */\n phoneNumbers?: string[];\n /** Linq WhatsApp: explicit opaque IDs from numbers.list, not E.164 phone strings. */\n phoneNumberIds?: string[];\n /** Contiguity Console secret, or an existing Inkbox identity signing key. */\n signingSecret?: string;\n}\n\nexport interface HubInboundWebhookCreateResponse {\n url: string;\n /** True only when the provider subscription was created by the server. */\n provisioned?: boolean;\n /** Self-configured legacy providers can return a newly minted secret once. */\n secret?: string;\n inboundAddress?: string;\n requiresProviderSetup?: boolean;\n}\n\nexport interface HubInboundWebhookStatus {\n configured: boolean;\n url?: string;\n /** Configuration is not evidence of a real delivered message. */\n deliveryVerified: false;\n requiresProviderSetup?: boolean;\n}\n\n/** Live provider readback for one explicitly selected Linq WhatsApp number. */\nexport interface HubInboundPhoneNumberScope {\n configured: true;\n provisioned: true;\n subscribed: true;\n phoneNumberIds: string[];\n}\n\nexport class HubInboundWebhooksClient {\n constructor(\n private readonly request: <T>(\n path: string,\n init: RequestInit,\n ) => Promise<T>,\n ) {}\n\n async create(\n connectionId: string,\n options: HubInboundWebhookCreateOptions = {},\n ): Promise<HubInboundWebhookCreateResponse> {\n return this.request(this.path(connectionId), jsonInit(\"POST\", options));\n }\n\n async get(connectionId: string): Promise<HubInboundWebhookStatus> {\n return this.request(this.path(connectionId), { method: \"GET\" });\n }\n\n /** Add one owned Linq WhatsApp number without rotating the webhook secret. */\n async ensurePhoneNumber(\n connectionId: string,\n phoneNumberId: string,\n ): Promise<HubInboundPhoneNumberScope> {\n if (\n !phoneNumberId ||\n phoneNumberId.length > 128 ||\n !/^[\\x21-\\x7e]+$/.test(phoneNumberId)\n ) {\n throw new Error(\"A bounded phone-number id is required\");\n }\n return this.request(\n `${this.path(connectionId)}/phone-numbers/ensure`,\n jsonInit(\"POST\", { phoneNumberId }),\n );\n }\n\n /** Remove event subscriptions first. This does not silently rotate a live URL. */\n async delete(connectionId: string): Promise<{ removed: boolean }> {\n return this.request(this.path(connectionId), { method: \"DELETE\" });\n }\n\n private path(connectionId: string): string {\n if (!connectionId || connectionId.length > 256)\n throw new Error(\"A bounded connection id is required\");\n return `/v1/hub/connections/${encodeURIComponent(connectionId)}/inbound-webhook`;\n }\n}\n","import { HubInboundWebhooksClient } from \"./inbound-webhooks.js\";\nimport { jsonInit } from \"./json-init.js\";\nimport { type HubRequest, HubSdkError } from \"./transport.js\";\nimport type {\n HubApiKeyConnectRequest,\n HubApiKeyConnectResponse,\n HubConnectionDeleteResponse,\n HubConnectionHealthResponse,\n HubConnectionsResponse,\n HubOAuthStartResponse,\n HubProvidersResponse,\n HubWhatsappEmbeddedSignupCompleteRequest,\n HubWhatsappEmbeddedSignupCompleteResponse,\n HubWhatsappEmbeddedSignupStartRequest,\n HubWhatsappEmbeddedSignupStartResponse,\n} from \"./types.js\";\n\nconst GITHUB_EXACT_CONNECT_SCOPES = [\"read:user\", \"repo\", \"read:org\"] as const;\n\nfunction sameOAuthScopeSet(\n left: readonly string[] | undefined,\n right: readonly string[],\n): boolean {\n if (!Array.isArray(left)) return false;\n const leftSet = new Set(left);\n const rightSet = new Set(right);\n return (\n leftSet.size === left.length &&\n rightSet.size === right.length &&\n leftSet.size === rightSet.size &&\n [...leftSet].every((scope) => rightSet.has(scope))\n );\n}\n\nexport interface HubConnectionStartOptions {\n returnUrl?: string;\n cli?: boolean;\n connectionParameters?: Record<string, string>;\n /** GitHub accepts the exact read:user, repo, read:org set. */\n requestedScopes?: readonly string[];\n}\n\nexport class HubConnectionsClient {\n readonly inboundWebhook: HubInboundWebhooksClient;\n\n constructor(private readonly request: HubRequest) {\n this.inboundWebhook = new HubInboundWebhooksClient(request);\n }\n\n async list(): Promise<HubConnectionsResponse> {\n return this.request<HubConnectionsResponse>(\"/v1/hub/connections\", {\n method: \"GET\",\n });\n }\n\n /** Connector catalog: every provider the hub can expose, each flagged with\n * `configured` (whether its OAuth app credentials are wired). Callers render\n * this alongside `list()` to offer Connect for not-yet-connected providers. */\n async providers(): Promise<HubProvidersResponse> {\n return this.request<HubProvidersResponse>(\"/v1/hub/providers\", {\n method: \"GET\",\n });\n }\n\n async start(\n provider: string,\n options: HubConnectionStartOptions = {},\n ): Promise<HubOAuthStartResponse> {\n if (\n options.requestedScopes !== undefined &&\n (provider !== \"github\" ||\n !sameOAuthScopeSet(\n options.requestedScopes,\n GITHUB_EXACT_CONNECT_SCOPES,\n ))\n ) {\n throw new HubSdkError({\n code: \"HUB_INVALID_INPUT\",\n message: \"GitHub requestedScopes must be read:user, repo, and read:org\",\n });\n }\n const started = await this.request<HubOAuthStartResponse>(\n `/v1/hub/connections/${encodeURIComponent(provider)}/start`,\n jsonInit(\"POST\", {\n returnUrl: options.returnUrl,\n cli: options.cli,\n connectionParameters: options.connectionParameters,\n requestedScopes: options.requestedScopes,\n }),\n );\n if (\n options.requestedScopes !== undefined &&\n (started.provider !== provider ||\n !sameOAuthScopeSet(started.scopes, options.requestedScopes))\n ) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Hub did not preserve the requested OAuth scopes\",\n });\n }\n return started;\n }\n\n async startWhatsappEmbeddedSignup(\n options: HubWhatsappEmbeddedSignupStartRequest = {},\n ): Promise<HubWhatsappEmbeddedSignupStartResponse> {\n return this.request<HubWhatsappEmbeddedSignupStartResponse>(\n \"/v1/hub/connections/whatsapp-business/embedded-signup/start\",\n jsonInit(\"POST\", { returnUrl: options.returnUrl }),\n );\n }\n\n async completeWhatsappEmbeddedSignup(\n input: HubWhatsappEmbeddedSignupCompleteRequest,\n ): Promise<HubWhatsappEmbeddedSignupCompleteResponse> {\n return this.request<HubWhatsappEmbeddedSignupCompleteResponse>(\n \"/v1/hub/connections/whatsapp-business/embedded-signup/complete\",\n jsonInit(\"POST\", input),\n );\n }\n\n /** Connect a non-OAuth (api-key) connector by submitting the user's key.\n * The server validates the key with a live probe before persisting and\n * returns the created (or reconnected) connection — there is no redirect,\n * unlike `start`. Cloudbeds requires propertyId metadata and PriceLabs\n * requires listing ID/PMS pairs; other providers have no metadata. */\n async connectApiKey(\n provider: string,\n apiKey: string,\n metadata?: HubApiKeyConnectRequest[\"metadata\"],\n ): Promise<HubApiKeyConnectResponse> {\n return this.request<HubApiKeyConnectResponse>(\n `/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`,\n jsonInit(\"POST\", {\n apiKey,\n ...(metadata === undefined ? {} : { metadata }),\n }),\n );\n }\n\n async revoke(connectionId: string): Promise<HubConnectionDeleteResponse> {\n return this.request<HubConnectionDeleteResponse>(\n `/v1/hub/connections/${encodeURIComponent(connectionId)}`,\n { method: \"DELETE\" },\n );\n }\n\n async health(connectionId: string): Promise<HubConnectionHealthResponse> {\n return this.request<HubConnectionHealthResponse>(\n `/v1/hub/connections/${encodeURIComponent(connectionId)}/health`,\n { method: \"POST\" },\n );\n }\n}\n","import { jsonInit } from \"./json-init.js\";\nimport type { HubRequest } from \"./transport.js\";\nimport type {\n HubChannelCreateResponse,\n HubChannelDeleteResponse,\n HubChannelsResponse,\n HubEmailChannelCreateRequest,\n HubEventSubscriptionCreateRequest,\n HubEventSubscriptionCreateResponse,\n HubEventSubscriptionDeleteResponse,\n HubEventSubscriptionsResponse,\n} from \"./types.js\";\n\nexport class HubChannelsClient {\n constructor(private readonly request: HubRequest) {}\n\n async list(): Promise<HubChannelsResponse> {\n return this.request<HubChannelsResponse>(\"/v1/hub/channels\", {\n method: \"GET\",\n });\n }\n\n async createEmail(\n input: HubEmailChannelCreateRequest = {},\n ): Promise<HubChannelCreateResponse> {\n return this.request<HubChannelCreateResponse>(\n \"/v1/hub/channels/email\",\n jsonInit(\"POST\", input),\n );\n }\n\n async delete(channelId: string): Promise<HubChannelDeleteResponse> {\n return this.request<HubChannelDeleteResponse>(\n `/v1/hub/channels/${encodeURIComponent(channelId)}`,\n { method: \"DELETE\" },\n );\n }\n}\n\nexport class HubEventSubscriptionsClient {\n constructor(private readonly request: HubRequest) {}\n\n async list(): Promise<HubEventSubscriptionsResponse> {\n return this.request<HubEventSubscriptionsResponse>(\n \"/v1/hub/event-subscriptions\",\n { method: \"GET\" },\n );\n }\n\n async create(\n input: HubEventSubscriptionCreateRequest,\n ): Promise<HubEventSubscriptionCreateResponse> {\n return this.request<HubEventSubscriptionCreateResponse>(\n \"/v1/hub/event-subscriptions\",\n jsonInit(\"POST\", input),\n );\n }\n\n async delete(\n subscriptionId: string,\n ): Promise<HubEventSubscriptionDeleteResponse> {\n return this.request<HubEventSubscriptionDeleteResponse>(\n `/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`,\n { method: \"DELETE\" },\n );\n }\n}\n","import { jsonInit } from \"./json-init.js\";\nimport type { HubRequest } from \"./transport.js\";\nimport type {\n HubGithubAppDisconnectResponse,\n HubGithubAppInstallationResponse,\n HubGithubAppIsRepoInstalledResponse,\n HubGithubAppListInstallationsResponse,\n HubGithubAppListReposResponse,\n HubGithubAppMintInstallationTokenRequest,\n HubGithubAppMintInstallationTokenResponse,\n HubGithubAppSyncResponse,\n} from \"./types.js\";\n\n// GitHub App primitive. The hub holds the App PEM + the per-tenant\n// installation grants; consumers (intelligence autonomous-improvement loop,\n// future code reviewers) ask the hub to mint a short-lived repo-scoped\n// installation token. The mint call MUST be principal-authed; the hub refuses\n// without a matching grant for the calling principal.\nexport class HubGithubAppClient {\n constructor(private readonly request: HubRequest) {}\n\n async mintInstallationToken(\n input: HubGithubAppMintInstallationTokenRequest,\n ): Promise<HubGithubAppMintInstallationTokenResponse> {\n return this.request<HubGithubAppMintInstallationTokenResponse>(\n \"/v1/hub/github-app/mint-installation-token\",\n jsonInit(\"POST\", input),\n );\n }\n\n /** Every installation the caller may act through — their own and any org's\n * they were verified against. The management surface's read. */\n async listInstallations(): Promise<HubGithubAppListInstallationsResponse> {\n return this.request<HubGithubAppListInstallationsResponse>(\n \"/v1/hub/github-app/installations\",\n { method: \"GET\" },\n );\n }\n\n /**\n * Find installations `listInstallations` cannot show: the hub only registers\n * what the setup redirect witnessed, so an org install approved out of band —\n * or created by another member — is invisible until this asks GitHub for it.\n * Links whatever the caller can prove access to; never uninstalls anything.\n */\n async syncInstallations(): Promise<HubGithubAppSyncResponse> {\n return this.request<HubGithubAppSyncResponse>(\n \"/v1/hub/github-app/installations/sync\",\n { method: \"POST\" },\n );\n }\n\n /** Give up THIS caller's access. Not an uninstall — the installation is\n * account-level and other members may still be using it. */\n async disconnectInstallation(\n installationId: number,\n ): Promise<HubGithubAppDisconnectResponse> {\n return this.request<HubGithubAppDisconnectResponse>(\n `/v1/hub/github-app/installations/${encodeURIComponent(String(installationId))}/access`,\n { method: \"DELETE\" },\n );\n }\n\n async getInstallation(\n installationId: number,\n ): Promise<HubGithubAppInstallationResponse> {\n return this.request<HubGithubAppInstallationResponse>(\n `/v1/hub/github-app/installations/${encodeURIComponent(String(installationId))}`,\n { method: \"GET\" },\n );\n }\n\n async listRepos(\n installationId: number,\n ): Promise<HubGithubAppListReposResponse> {\n return this.request<HubGithubAppListReposResponse>(\n `/v1/hub/github-app/installations/${encodeURIComponent(String(installationId))}/repos`,\n { method: \"GET\" },\n );\n }\n\n async isRepoInstalled(input: {\n owner: string;\n repo: string;\n }): Promise<HubGithubAppIsRepoInstalledResponse> {\n const params = new URLSearchParams({\n owner: input.owner,\n repo: input.repo,\n });\n return this.request<HubGithubAppIsRepoInstalledResponse>(\n `/v1/hub/github-app/is-repo-installed?${params.toString()}`,\n { method: \"GET\" },\n );\n }\n}\n","import type { HubRequest } from \"./transport.js\";\nimport type { HubAuditListRequest, HubAuditResponse } from \"./types.js\";\n\nexport class HubAuditClient {\n constructor(private readonly request: HubRequest) {}\n\n async list(options: HubAuditListRequest = {}): Promise<HubAuditResponse> {\n const searchParams = new URLSearchParams();\n if (options.provider !== undefined)\n searchParams.set(\"provider\", options.provider);\n if (options.action !== undefined)\n searchParams.set(\"action\", options.action);\n if (options.status !== undefined)\n searchParams.set(\"status\", options.status);\n if (options.since !== undefined) searchParams.set(\"since\", options.since);\n if (options.until !== undefined) searchParams.set(\"until\", options.until);\n if (options.cursor !== undefined)\n searchParams.set(\"cursor\", options.cursor);\n if (options.limit !== undefined)\n searchParams.set(\"limit\", String(options.limit));\n const query = searchParams.toString();\n return this.request<HubAuditResponse>(\n `/v1/hub/audit${query ? `?${query}` : \"\"}`,\n { method: \"GET\" },\n );\n }\n}\n","import { isRecord } from \"./transport.js\";\nimport type {\n HubWorkflowRunDetail,\n HubWorkflowRunStreamEvent,\n} from \"./types.js\";\n\n/** Read a wire field as a string, or \"\" when the server sent anything else.\n * `raw` is that field straight off the parsed payload, before any check. */\nfunction optString(raw: unknown): string {\n return typeof raw === \"string\" ? raw : \"\";\n}\n\n/** An agent iteration's terminal status (`iteration.ended`) — only ever\n * succeeded/failed; an iteration is never guard-skipped. */\nfunction isIterationStatus(value: unknown): value is \"succeeded\" | \"failed\" {\n return value === \"succeeded\" || value === \"failed\";\n}\n\n/** An action's terminal status on `action.finished`. Beyond succeeded/failed a\n * guarded action can end `skipped` (its `if` resolved false, so it never ran) —\n * accepted here so a skipped event is surfaced, not dropped as malformed. */\nfunction isActionFinishedStatus(\n value: unknown,\n): value is \"succeeded\" | \"failed\" | \"skipped\" {\n return value === \"succeeded\" || value === \"failed\" || value === \"skipped\";\n}\n\n/** Terminal status of a whole run's `run.done` event. A run can end `cancelled`\n * (a user cancel) — a value neither the action nor iteration status checkers\n * accept — so `run.done` uses this rather than them, which would drop a\n * cancelled terminal event and hang the stream. */\nfunction isRunDoneStatus(\n value: unknown,\n): value is \"succeeded\" | \"failed\" | \"cancelled\" {\n return value === \"succeeded\" || value === \"failed\" || value === \"cancelled\";\n}\n\n/**\n * Map one raw SSE event (its `event:` name + parsed JSON `data:`) to a typed\n * run-stream event, validating the fields each variant declares rather than\n * blindly casting the wire payload. A frame that doesn't match its event's\n * shape (or an unknown event name) returns null so the consumer skips it — a\n * malformed `token` can never reach a consumer as `{ delta: undefined }`, and\n * new server event kinds don't break older clients.\n */\nexport function toRunStreamEvent(\n eventType: string | undefined,\n raw: unknown,\n): HubWorkflowRunStreamEvent | null {\n if (eventType === \"ping\") return { type: \"ping\" };\n if (!isRecord(raw)) return null;\n switch (eventType) {\n case \"snapshot\":\n // The snapshot payload is the full run detail. HubWorkflowRunDetail narrows\n // status/actionResults from optional to REQUIRED, so validate those anchors\n // (not just id/workflowId) before the cast — otherwise a contract-breaking\n // server response would hand consumers `undefined` where the type promises a\n // value. `status` is checked as a present string rather than against the\n // enum so a new server-side status doesn't drop an otherwise-valid snapshot.\n return typeof raw.id === \"string\" &&\n typeof raw.workflowId === \"string\" &&\n typeof raw.status === \"string\" &&\n Array.isArray(raw.actionResults)\n ? { type: \"snapshot\", run: raw as unknown as HubWorkflowRunDetail }\n : null;\n case \"token\":\n // `delta` is the one field a consumer writes to stdout unchanged, so a\n // non-string drops the frame instead of crashing downstream.\n return typeof raw.delta === \"string\" &&\n typeof raw.actionIndex === \"number\"\n ? {\n type: \"token\",\n actionIndex: raw.actionIndex,\n delta: raw.delta,\n at: optString(raw.at),\n }\n : null;\n case \"run.done\":\n // The terminal signal — a bad status must not masquerade as completion,\n // but `cancelled` is a valid terminal outcome (a user-cancelled run) and\n // must be surfaced, not dropped, so the stream ends instead of hanging.\n return isRunDoneStatus(raw.status)\n ? {\n type: \"run.done\",\n status: raw.status,\n error: typeof raw.error === \"string\" ? raw.error : null,\n ...(typeof raw.at === \"string\" ? { at: raw.at } : {}),\n }\n : null;\n case \"run.waiting\":\n // The run PARKED on a human `decision` step — non-terminal, but it ENDS the\n // live stream (no further ticks until it resumes, a fresh execution). Surface\n // it with the pending decision id so a consumer stops watching and prompts\n // for a resolution instead of hanging or reading it as completion. Require a\n // NON-EMPTY decisionId: a blank one is unactionable (the consumer couldn't\n // resolve it), so drop the frame rather than end the stream on a dead id.\n return typeof raw.decisionId === \"string\" && raw.decisionId.length > 0\n ? {\n type: \"run.waiting\",\n decisionId: raw.decisionId,\n ...(typeof raw.at === \"string\" ? { at: raw.at } : {}),\n }\n : null;\n // Lifecycle events: construct the result from the SSE frame's `eventType`\n // with the required fields validated, so the yielded `.type` always matches\n // the frame (never the payload's own `type`, which may drift or be absent)\n // and only validated optional fields are copied.\n case \"action.started\":\n return typeof raw.index === \"number\" &&\n typeof raw.kind === \"string\" &&\n typeof raw.at === \"string\"\n ? {\n type: \"action.started\",\n index: raw.index,\n kind: raw.kind,\n at: raw.at,\n }\n : null;\n case \"action.finished\":\n return typeof raw.index === \"number\" &&\n typeof raw.kind === \"string\" &&\n isActionFinishedStatus(raw.status) &&\n typeof raw.at === \"string\"\n ? {\n type: \"action.finished\",\n index: raw.index,\n kind: raw.kind,\n status: raw.status,\n at: raw.at,\n ...(typeof raw.costUsd === \"number\"\n ? { costUsd: raw.costUsd }\n : {}),\n ...(typeof raw.error === \"string\" ? { error: raw.error } : {}),\n }\n : null;\n case \"iteration.started\":\n return typeof raw.actionIndex === \"number\" &&\n typeof raw.iterationIndex === \"number\" &&\n typeof raw.at === \"string\"\n ? {\n type: \"iteration.started\",\n actionIndex: raw.actionIndex,\n iterationIndex: raw.iterationIndex,\n at: raw.at,\n ...(typeof raw.model === \"string\" ? { model: raw.model } : {}),\n }\n : null;\n case \"iteration.ended\":\n return typeof raw.actionIndex === \"number\" &&\n typeof raw.iterationIndex === \"number\" &&\n isIterationStatus(raw.status) &&\n typeof raw.at === \"string\"\n ? {\n type: \"iteration.ended\",\n actionIndex: raw.actionIndex,\n iterationIndex: raw.iterationIndex,\n status: raw.status,\n at: raw.at,\n ...(typeof raw.outputPreview === \"string\"\n ? { outputPreview: raw.outputPreview }\n : {}),\n ...(typeof raw.inputTokens === \"number\"\n ? { inputTokens: raw.inputTokens }\n : {}),\n ...(typeof raw.outputTokens === \"number\"\n ? { outputTokens: raw.outputTokens }\n : {}),\n ...(typeof raw.costUsd === \"number\"\n ? { costUsd: raw.costUsd }\n : {}),\n }\n : null;\n default:\n return null;\n }\n}\n","import { jsonInit } from \"./json-init.js\";\nimport type { HubRequest } from \"./transport.js\";\nimport type {\n HubWorkflowKvDeleteResponse,\n HubWorkflowKvEntry,\n HubWorkflowKvListResponse,\n} from \"./types.js\";\n\n/** The workflow's durable keyspace, shared by all its runs. */\nexport class WorkflowKvResource {\n constructor(protected readonly request: HubRequest) {}\n\n // ----- Workflow KV (cross-run state) -----\n\n /**\n * The workflow's whole keyspace as metadata (key, version, updatedAt — never\n * values), key-ordered. Bounded by the server's per-workflow key cap.\n */\n async listKv(id: string): Promise<HubWorkflowKvListResponse> {\n return this.request<HubWorkflowKvListResponse>(\n `/v1/workflows/${encodeURIComponent(id)}/kv`,\n { method: \"GET\" },\n );\n }\n\n /** One KV entry (value + version); `HubSdkError(NOT_FOUND)` when absent. */\n async getKv(id: string, key: string): Promise<HubWorkflowKvEntry> {\n return this.request<HubWorkflowKvEntry>(\n `/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`,\n { method: \"GET\" },\n );\n }\n\n /**\n * Upsert a key; returns the entry with its NEW version (increments on every\n * write). Throws `HubSdkError(KV_VALUE_TOO_LARGE)` past the 64KiB value cap\n * or `KV_KEY_LIMIT` past the per-workflow key cap. `raw` is the caller's\n * value, stored and read back verbatim, so the client never gives it a shape.\n */\n async putKv(\n id: string,\n key: string,\n raw: unknown,\n ): Promise<HubWorkflowKvEntry> {\n return this.request<HubWorkflowKvEntry>(\n `/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`,\n jsonInit(\"PUT\", { value: raw }),\n );\n }\n\n /**\n * Compare-and-swap: the write lands only when the stored version still\n * equals `expectedVersion`; otherwise `HubSdkError(KV_VERSION_CONFLICT)`\n * (409) — re-read and retry. Creation is {@link putKv}'s job. `raw` is the\n * caller's value, stored and read back verbatim, so the client never gives it\n * a shape.\n */\n async casKv(\n id: string,\n key: string,\n expectedVersion: number,\n raw: unknown,\n ): Promise<HubWorkflowKvEntry> {\n return this.request<HubWorkflowKvEntry>(\n `/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`,\n jsonInit(\"POST\", { expectedVersion, value: raw }),\n );\n }\n\n /** Delete a key; idempotent — `deleted` reports whether a row was removed. */\n async deleteKv(\n id: string,\n key: string,\n ): Promise<HubWorkflowKvDeleteResponse> {\n return this.request<HubWorkflowKvDeleteResponse>(\n `/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`,\n { method: \"DELETE\" },\n );\n }\n}\n","import { SSEChunkParser } from \"@tangle-network/agent-core/sse\";\n\nimport { jsonInit } from \"./json-init.js\";\nimport {\n type HubArtifactRequest,\n type HubRequest,\n HubSdkError,\n type HubStreamRequest,\n} from \"./transport.js\";\nimport type {\n HubWorkflow,\n HubWorkflowArtifactDownload,\n HubWorkflowArtifactRef,\n HubWorkflowArtifactsResponse,\n HubWorkflowDecision,\n HubWorkflowDecisionResolveResult,\n HubWorkflowFleetInsights,\n HubWorkflowFleetWindow,\n HubWorkflowHealth,\n HubWorkflowPendingDecisionsResponse,\n HubWorkflowRevision,\n HubWorkflowRevisionMeta,\n HubWorkflowRunCancelResult,\n HubWorkflowRunDetail,\n HubWorkflowRunEnqueued,\n HubWorkflowRunInputs,\n HubWorkflowRunRetried,\n HubWorkflowRunStatus,\n HubWorkflowRunStepsPage,\n HubWorkflowRunStreamEvent,\n HubWorkflowRunsPage,\n HubWorkflowSchemaResponse,\n HubWorkflowTemplate,\n HubWorkflowTemplateInstantiateResult,\n HubWorkflowValidateResponse,\n} from \"./types.js\";\nimport { toRunStreamEvent } from \"./workflow-run-events.js\";\nimport { WorkflowKvResource } from \"./workflows-kv.js\";\n\n/** True for an aborted/timed-out fetch (or any abort). fetch rejects with the\n * signal's reason — a DOMException named `AbortError` (caller) or `TimeoutError`\n * (AbortSignal.timeout). */\nfunction isAbortError(cause: unknown): boolean {\n return (\n cause instanceof Error &&\n (cause.name === \"AbortError\" || cause.name === \"TimeoutError\")\n );\n}\n\n/** A signal that aborts when the caller's signal aborts OR `timeoutMs` elapses.\n * Returns undefined when neither bound applies (no per-request abort needed). */\nfunction combineAbortSignals(\n caller: AbortSignal | undefined,\n timeoutMs: number | null,\n): AbortSignal | undefined {\n const signals: AbortSignal[] = [];\n if (caller) signals.push(caller);\n if (timeoutMs !== null) signals.push(AbortSignal.timeout(timeoutMs));\n if (signals.length === 0) return undefined;\n return signals.length === 1 ? signals[0] : AbortSignal.any(signals);\n}\n\n/** Resolve after `ms`, or reject if `signal` aborts first. Clears its timer on\n * abort so a cancelled wait leaves nothing pending. */\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new Error(\"The operation was aborted\"));\n return;\n }\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason ?? new Error(\"The operation was aborted\"));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n// Workflow resource. Unlike the rest of the hub surface these endpoints live\n// at `/v1/workflows` (the platform root, not `/v1/hub`), but they share the\n// same auth + envelope, so they ride the same client. YAML is the durable\n// representation — create/update take a raw YAML string and the platform\n// compiles it to the engine's run model.\n/** Wait before reopening a run event stream that a restart ended. */\nconst STREAM_REOPEN_DELAY_MS = 1_000;\n/** Reopens in a row that deliver nothing before watchRun gives up. */\nconst MAX_IDLE_STREAM_REOPENS = 30;\n\nfunction abortableDelay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport class HubWorkflowsClient extends WorkflowKvResource {\n // `stream`/`download` are optional so the exported constructor stays\n // source-compatible with the pre-streaming `new HubWorkflowsClient(request)`\n // shape. `HubClient` always supplies them; only `watchRun` needs `stream` and\n // only `downloadArtifact` needs `download`, and both fail loudly when a\n // client was built without the one they need.\n constructor(\n request: HubRequest,\n private readonly stream?: HubStreamRequest,\n private readonly download?: HubArtifactRequest,\n ) {\n super(request);\n }\n\n async list(): Promise<HubWorkflow[]> {\n return this.request<HubWorkflow[]>(\"/v1/workflows\", { method: \"GET\" });\n }\n\n /**\n * Owner-wide fleet overview: one row per workflow with its run tallies over\n * a trailing window (default 7d), sorted failing-first. Answers \"how are ALL\n * my workflows doing\" in one call — the per-workflow insights endpoint is\n * the drill-down, not a way to build this row set client-side.\n */\n async fleetInsights(\n opts: { window?: HubWorkflowFleetWindow } = {},\n ): Promise<HubWorkflowFleetInsights> {\n const query = opts.window\n ? `?window=${encodeURIComponent(opts.window)}`\n : \"\";\n return this.request<HubWorkflowFleetInsights>(\n `/v1/workflows/insights/fleet${query}`,\n { method: \"GET\" },\n );\n }\n\n async get(id: string): Promise<HubWorkflow> {\n return this.request<HubWorkflow>(\n `/v1/workflows/${encodeURIComponent(id)}`,\n { method: \"GET\" },\n );\n }\n\n async create(yaml: string): Promise<HubWorkflow> {\n return this.request<HubWorkflow>(\n \"/v1/workflows\",\n jsonInit(\"POST\", { yaml }),\n );\n }\n\n /**\n * Replace the workflow's definition from YAML (recompiled server-side,\n * triggers reconciled). Every landed update appends a revision;\n * `opts.note` rides onto that revision row (e.g. \"why this change\"), visible\n * in {@link listRevisions}. Throws `HubSdkError`: `WORKFLOW_INVALID` when the\n * YAML doesn't compile or its connections aren't met, `CONFLICT` on a\n * concurrent modification, `NOT_FOUND` for an unknown/foreign id.\n */\n async update(\n id: string,\n yaml: string,\n opts: { note?: string } = {},\n ): Promise<HubWorkflow> {\n return this.request<HubWorkflow>(\n `/v1/workflows/${encodeURIComponent(id)}`,\n jsonInit(\"PUT\", {\n yaml,\n ...(opts.note !== undefined ? { note: opts.note } : {}),\n }),\n );\n }\n\n async delete(id: string): Promise<void> {\n await this.request<undefined>(`/v1/workflows/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n }\n\n /**\n * Enable or disable a workflow without editing its YAML. Works even when the\n * workflow's connection was revoked (a disabled workflow can't be recompiled\n * via `update`, but it can still be paused/resumed here).\n */\n async setEnabled(id: string, enabled: boolean): Promise<HubWorkflow> {\n return this.request<HubWorkflow>(\n `/v1/workflows/${encodeURIComponent(id)}`,\n jsonInit(\"PATCH\", { enabled }),\n );\n }\n\n /**\n * One page of run history, newest first. Pass the previous page's\n * `nextCursor` to fetch the next; a null `nextCursor` means the last page.\n */\n async listRuns(\n id: string,\n opts: { limit?: number; cursor?: string } = {},\n ): Promise<HubWorkflowRunsPage> {\n const params = new URLSearchParams();\n if (opts.limit !== undefined) params.set(\"limit\", String(opts.limit));\n if (opts.cursor !== undefined) params.set(\"cursor\", opts.cursor);\n const query = params.toString();\n return this.request<HubWorkflowRunsPage>(\n `/v1/workflows/${encodeURIComponent(id)}/runs${query ? `?${query}` : \"\"}`,\n { method: \"GET\" },\n );\n }\n\n /**\n * Enqueue an immediate (\"Run now\") run and return its `runId`. The run goes\n * through the identical execution path a trigger delivery uses.\n *\n * `inputs` supplies the trigger fields the workflow reads (its\n * {@link HubWorkflow.manualRunInputs}), as a flat `{ path: value }` map — e.g.\n * `{ \"pull_request.number\": \"123\" }`. Omit it for a one-click run of a\n * workflow that reads no trigger fields. Throws `HubSdkError`:\n * `MISSING_RUN_INPUTS` when a required field is absent (`details.missing`\n * names them), `NOT_FOUND` for an unknown/foreign id. A paused workflow\n * still runs once; pausing only stops its triggers. Pass `opts.signal` to\n * abort a slow request.\n */\n async run(\n id: string,\n inputs?: HubWorkflowRunInputs,\n opts: { signal?: AbortSignal } = {},\n ): Promise<HubWorkflowRunEnqueued> {\n const hasInputs = inputs !== undefined && Object.keys(inputs).length > 0;\n return this.request<HubWorkflowRunEnqueued>(\n `/v1/workflows/${encodeURIComponent(id)}/run`,\n {\n ...jsonInit(\"POST\", hasInputs ? { inputs } : {}),\n ...(opts.signal ? { signal: opts.signal } : {}),\n },\n );\n }\n\n /**\n * A single run's full detail: per-action `output` + `agentRun` execution\n * detail (size-capped server-side) and the trigger context — the deep \"why\n * did this run do what it did\" view. `NOT_FOUND` when the run is unknown or\n * does not belong to both the caller and this workflow.\n */\n async getRun(\n id: string,\n runId: string,\n opts: { signal?: AbortSignal } = {},\n ): Promise<HubWorkflowRunDetail> {\n return this.request<HubWorkflowRunDetail>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}`,\n { method: \"GET\", ...(opts.signal ? { signal: opts.signal } : {}) },\n );\n }\n\n /**\n * Stop a queued or in-flight run. A `queued` run is cancelled synchronously\n * and comes back `{ status: \"cancelled\" }` (already terminal); a `running` run\n * is signalled to abort and comes back `{ status: \"cancelling\", signalled }` —\n * it settles `cancelled` a moment later as its current action tears down, which\n * a {@link watchRun}/{@link getRun} observes. Throws `HubSdkError`:\n * `RUN_NOT_CANCELLABLE` when the run already finished, `NOT_FOUND` for an\n * unknown/foreign run id. Pass `opts.signal` to abort a slow request.\n */\n async cancel(\n id: string,\n runId: string,\n opts: { signal?: AbortSignal } = {},\n ): Promise<HubWorkflowRunCancelResult> {\n return this.request<HubWorkflowRunCancelResult>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/cancel`,\n { method: \"POST\", ...(opts.signal ? { signal: opts.signal } : {}) },\n );\n }\n\n /**\n * Re-run a terminal failed/cancelled run: enqueues a FRESH run of the same\n * workflow with the SAME trigger context the original ran against, linked\n * back to it via `retriedFromRunId`. The original row is never mutated —\n * execution is at-most-once, so a retry is always a new run, never a\n * requeue. The response carries the NEW run id (and the run it retried);\n * follow it with {@link getRun}/{@link watchRun}/{@link waitForRun} like any\n * other run. Throws `HubSdkError`: `RUN_NOT_RETRYABLE` when the run is not\n * terminal-failed/cancelled (queued/running/waiting, or succeeded),\n * `NOT_FOUND` for an unknown/foreign run id; a workflow paused since the\n * failure still retries. Pass `opts.signal` to abort a slow request.\n */\n async retryRun(\n id: string,\n runId: string,\n opts: { signal?: AbortSignal } = {},\n ): Promise<HubWorkflowRunRetried> {\n return this.request<HubWorkflowRunRetried>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/retry`,\n { method: \"POST\", ...(opts.signal ? { signal: opts.signal } : {}) },\n );\n }\n\n /**\n * Stream a run's live progress as an async iterable of typed events. The\n * first event is always a `snapshot` of the current persisted state; then\n * `action.*` / `iteration.*` / `token` ticks arrive as the run executes;\n * `ping` is a keepalive; a terminal `run.done` ends the iteration. If the run\n * is already finished when the stream opens, it yields the snapshot then\n * `run.done` and completes.\n *\n * Live ticks require the worker executing the run to share the API process;\n * across instances only `snapshot` + `run.done` (from the server's terminal\n * poll) arrive — the persisted record, read via {@link getRun}, stays the\n * source of truth. Pass `signal` to cancel; iterating to `run.done` (or\n * breaking early) releases the connection.\n *\n * A stream that ends before `run.done` or `run.waiting` (the Platform is\n * restarting or handing over) is reopened after a second, as is one refused\n * with `SERVICE_DRAINING`; the reopened stream starts with a fresh\n * `snapshot`. After 30 reopens in a row that deliver nothing it throws\n * `HubSdkError(WORKFLOW_STREAM_INTERRUPTED)`.\n */\n async *watchRun(\n id: string,\n runId: string,\n opts: { signal?: AbortSignal } = {},\n ): AsyncGenerator<HubWorkflowRunStreamEvent> {\n const openStream = this.stream;\n if (!openStream) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message:\n \"watchRun needs a streaming transport; use HubClient (which wires it up) rather than constructing HubWorkflowsClient directly\",\n });\n }\n const path = `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/events`;\n // A Platform process that is stopping or handing over ends this stream\n // before the run does, and refuses a new one with 503 SERVICE_DRAINING\n // for the moment it takes. The next stream starts with a full snapshot,\n // so reopening loses nothing; ending the iteration would tell the caller\n // the run had finished.\n let idleReopens = 0;\n for (;;) {\n let delivered = false;\n const connection = this.watchRunOnce(openStream, path, opts);\n try {\n for (;;) {\n const next = await connection.next();\n if (next.done) {\n if (next.value === \"ended\") return;\n break;\n }\n delivered = true;\n yield next.value;\n }\n } catch (error) {\n if (\n !(error instanceof HubSdkError) ||\n error.code !== \"SERVICE_DRAINING\" ||\n opts.signal?.aborted\n )\n throw error;\n } finally {\n // A caller that stops iterating closes this connection too.\n await connection.return(\"interrupted\");\n }\n idleReopens = delivered ? 0 : idleReopens + 1;\n if (idleReopens > MAX_IDLE_STREAM_REOPENS)\n throw new HubSdkError({\n code: \"WORKFLOW_STREAM_INTERRUPTED\",\n message: `the run event stream ended ${MAX_IDLE_STREAM_REOPENS} times without delivering an event`,\n });\n await abortableDelay(STREAM_REOPEN_DELAY_MS, opts.signal);\n }\n }\n\n /** One connection's events, then how it ended. */\n private async *watchRunOnce(\n openStream: HubStreamRequest,\n path: string,\n opts: { signal?: AbortSignal },\n ): AsyncGenerator<HubWorkflowRunStreamEvent, \"ended\" | \"interrupted\"> {\n const body = await openStream(path, {\n method: \"GET\",\n headers: { Accept: \"text/event-stream\" },\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n // Frame + parse with the shared SSE primitive (`SSEChunkParser` from\n // agent-core/sse). A malformed `data:` payload becomes null and is skipped\n // rather than throwing mid-stream.\n const reader = body.getReader();\n const decoder = new TextDecoder();\n const parser = new SSEChunkParser<unknown>({\n transform: (raw) => {\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n },\n });\n try {\n for (;;) {\n const { done, value } = await reader.read();\n const text = done\n ? decoder.decode()\n : decoder.decode(value, { stream: true });\n const parsedEvents = done\n ? [...parser.push(text), ...parser.flush()]\n : parser.push(text);\n for (const parsed of parsedEvents) {\n const event = toRunStreamEvent(parsed.eventType, parsed.data);\n if (!event) continue;\n yield event;\n // Both terminal completion and a decision park end the stream.\n if (event.type === \"run.done\" || event.type === \"run.waiting\")\n return \"ended\";\n }\n if (done) return \"interrupted\";\n }\n } finally {\n // Cancel through the reader on every exit (early break, run.done, throw)\n // to tear down the HTTP/SSE connection; it's a safe no-op once the stream\n // has closed on its own. NOT releaseLock() — cancelling via the reader\n // already tears down the source, and releaseLock() after cancel risks a\n // TypeError if a read is still settling. (body.cancel() can't be used here\n // — getReader() locks the body.)\n await reader.cancel().catch(() => {});\n }\n }\n\n /**\n * Poll {@link getRun} until the run reaches a terminal state (`succeeded` or\n * `failed`) and return its detail. The scripting primitive behind \"run and\n * print the result\": pairs with {@link run} for a one-call trigger-and-wait.\n *\n * Returns as soon as the run leaves the active set (`queued` / `running`) —\n * i.e. on `succeeded`, `failed`, or any future non-active status — so a new\n * terminal state can never hang the wait. Polls every `pollIntervalMs`\n * (default 2000). With `timeoutMs` set, throws\n * `HubSdkError(WORKFLOW_RUN_TIMEOUT)` — carrying the last observed status on\n * `details.status` — only once the deadline has actually passed; the last\n * wait is clamped to the remaining time so a `timeoutMs` shorter than the\n * poll interval still waits the full requested window rather than giving up a\n * poll early. Pass `signal` to cancel the wait between polls.\n */\n async waitForRun(\n id: string,\n runId: string,\n opts: {\n pollIntervalMs?: number;\n timeoutMs?: number;\n signal?: AbortSignal;\n } = {},\n ): Promise<HubWorkflowRunDetail> {\n const pollIntervalMs = opts.pollIntervalMs ?? 2000;\n // Guard against a bad poll cadence turning the loop into a getRun hot-loop\n // (e.g. 0 / NaN → zero-delay timers).\n if (!Number.isFinite(pollIntervalMs) || pollIntervalMs <= 0) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message: `waitForRun pollIntervalMs must be a positive number (got ${opts.pollIntervalMs})`,\n });\n }\n if (\n opts.timeoutMs !== undefined &&\n (!Number.isFinite(opts.timeoutMs) || opts.timeoutMs <= 0)\n ) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message: `waitForRun timeoutMs must be a positive number (got ${opts.timeoutMs})`,\n });\n }\n const deadline =\n opts.timeoutMs !== undefined ? Date.now() + opts.timeoutMs : null;\n const timeoutError = (status: HubWorkflowRunStatus | undefined) =>\n new HubSdkError({\n code: \"WORKFLOW_RUN_TIMEOUT\",\n message: `Workflow run ${runId} did not reach a terminal state within ${opts.timeoutMs}ms${status ? ` (last status: ${status})` : \"\"}`,\n details: { runId, status, timeoutMs: opts.timeoutMs },\n });\n let lastStatus: HubWorkflowRunStatus | undefined;\n for (;;) {\n if (opts.signal?.aborted) {\n throw opts.signal.reason ?? new Error(\"The operation was aborted\");\n }\n const remainingMs = deadline !== null ? deadline - Date.now() : null;\n if (remainingMs !== null && remainingMs <= 0)\n throw timeoutError(lastStatus);\n\n // Abort the in-flight poll if the caller aborts OR the deadline elapses\n // mid-request, so a hung getRun can't outlive `timeoutMs` / ignore `signal`.\n const pollSignal = combineAbortSignals(opts.signal, remainingMs);\n let run: HubWorkflowRunDetail;\n try {\n run = await this.getRun(\n id,\n runId,\n pollSignal ? { signal: pollSignal } : {},\n );\n } catch (err) {\n // Caller cancellation propagates as-is; a deadline-driven abort becomes\n // the typed timeout.\n if (opts.signal?.aborted) throw err;\n if (deadline !== null && isAbortError(err))\n throw timeoutError(lastStatus);\n throw err;\n }\n lastStatus = run.status;\n // Terminal = anything not still in flight. Waiting for a fixed\n // {succeeded,failed} allow-list would hang forever if the run reached a\n // status added later (e.g. a future `cancelled`).\n if (run.status !== \"queued\" && run.status !== \"running\") return run;\n // Recompute the remaining budget AFTER the poll — `getRun` may have\n // consumed most of it — so the wait is clamped to what's actually left\n // and can never overshoot `timeoutMs`.\n const delayRemainingMs = deadline !== null ? deadline - Date.now() : null;\n if (delayRemainingMs !== null && delayRemainingMs <= 0) {\n throw timeoutError(lastStatus);\n }\n await delay(\n delayRemainingMs !== null\n ? Math.min(pollIntervalMs, delayRemainingMs)\n : pollIntervalMs,\n opts.signal,\n );\n }\n }\n\n // ----- Definition revisions -----\n\n /**\n * The workflow's definition history, newest rev first — metadata only (rev,\n * attribution, note); fetch the YAML per-rev with {@link getRevision}. Empty\n * for a pre-versioning workflow until its next update.\n */\n async listRevisions(id: string): Promise<HubWorkflowRevisionMeta[]> {\n return this.request<HubWorkflowRevisionMeta[]>(\n `/v1/workflows/${encodeURIComponent(id)}/revisions`,\n { method: \"GET\" },\n );\n }\n\n /**\n * One revision WITH its YAML (and the actions compiled alongside it), for\n * diff/inspect views. Throws `HubSdkError(REVISION_NOT_FOUND)` for an\n * unknown rev, `NOT_FOUND` for an unknown/foreign workflow.\n */\n async getRevision(id: string, rev: number): Promise<HubWorkflowRevision> {\n return this.request<HubWorkflowRevision>(\n `/v1/workflows/${encodeURIComponent(id)}/revisions/${encodeURIComponent(String(rev))}`,\n { method: \"GET\" },\n );\n }\n\n /**\n * Restore a prior rev's YAML as a NEW head revision (history is append-only)\n * through the same compile path as {@link update}, so the restored definition\n * is re-validated against today's connections/models. Throws `HubSdkError`:\n * `REVISION_NOT_FOUND` for an unknown rev, `WORKFLOW_INVALID` when the old\n * YAML no longer compiles, `CONFLICT` on a concurrent modification.\n */\n async rollback(id: string, rev: number): Promise<HubWorkflow> {\n return this.request<HubWorkflow>(\n `/v1/workflows/${encodeURIComponent(id)}/rollback`,\n jsonInit(\"POST\", { rev }),\n );\n }\n\n // ----- Health analytics -----\n\n /**\n * Deterministic health stats over the workflow's last N terminal runs\n * (default 20, max 100): per-node visits/failures/cost/duration, failure\n * clusters by normalized error signature, and distillation CANDIDATES\n * (agent.run nodes with near-static outputs — labeled with their\n * measurements, never as verdicts). No model in this path.\n */\n async health(\n id: string,\n opts: { runs?: number } = {},\n ): Promise<HubWorkflowHealth> {\n const query = opts.runs !== undefined ? `?runs=${opts.runs}` : \"\";\n return this.request<HubWorkflowHealth>(\n `/v1/workflows/${encodeURIComponent(id)}/health${query}`,\n { method: \"GET\" },\n );\n }\n\n // ----- Run step archive -----\n\n /**\n * One agent round's execution timeline, paged. `action` is the action's\n * `${steps[N]}` position and `iteration` the round's position in that\n * action's `iterations` — both exactly as the run detail serializes them.\n * Pass the previous page's `nextCursor` as `after` for the next page; a null\n * `nextCursor` means the round is fully read.\n */\n async listRunSteps(\n id: string,\n runId: string,\n input: {\n action: number;\n iteration: number;\n after?: number;\n limit?: number;\n },\n ): Promise<HubWorkflowRunStepsPage> {\n const params = new URLSearchParams({\n action: String(input.action),\n iteration: String(input.iteration),\n });\n if (input.after !== undefined) params.set(\"after\", String(input.after));\n if (input.limit !== undefined) params.set(\"limit\", String(input.limit));\n return this.request<HubWorkflowRunStepsPage>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/steps?${params.toString()}`,\n { method: \"GET\" },\n );\n }\n\n // ----- Run artifacts -----\n\n /**\n * Store one artifact for a run (raw bytes) and return the opaque ref — the\n * value a script.run node returns as its step output. `contentType` defaults\n * to `application/octet-stream`; `nodeId` attributes the write to a graph\n * node (owner credential only — a run-scoped token binds its own node).\n * Throws `HubSdkError(ARTIFACT_TOO_LARGE)` past the server cap.\n */\n async uploadArtifact(\n id: string,\n runId: string,\n input: {\n name: string;\n bytes: Uint8Array;\n contentType?: string;\n nodeId?: string;\n },\n ): Promise<HubWorkflowArtifactRef> {\n const headers: Record<string, string> = {\n \"Content-Type\": input.contentType ?? \"application/octet-stream\",\n \"x-wf-artifact-name\": input.name,\n };\n if (input.nodeId !== undefined)\n headers[\"x-wf-artifact-node\"] = input.nodeId;\n return this.request<HubWorkflowArtifactRef>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/artifacts`,\n {\n method: \"POST\",\n // Uint8Array is a valid fetch body — pass it through rather than\n // copying what can be a large artifact. The cast is only TS 5.7's\n // generic Uint8Array<ArrayBufferLike> vs BodyInit's ArrayBuffer-backed\n // view; the runtime accepts either.\n body: input.bytes as BodyInit,\n headers,\n },\n );\n }\n\n /** Metadata for every artifact of the run (never the bytes), oldest first. */\n async listArtifacts(\n id: string,\n runId: string,\n ): Promise<HubWorkflowArtifactsResponse> {\n return this.request<HubWorkflowArtifactsResponse>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/artifacts`,\n { method: \"GET\" },\n );\n }\n\n /**\n * The artifact's raw bytes with their stored content type — the route every\n * `downloadUrl` attached to an `$artifact` ref in a run detail points at.\n */\n async downloadArtifact(\n id: string,\n runId: string,\n artifactId: string,\n ): Promise<HubWorkflowArtifactDownload> {\n const downloadBytes = this.download;\n if (!downloadBytes) {\n throw new HubSdkError({\n code: \"HUB_CONFIG_INVALID\",\n message:\n \"downloadArtifact needs a byte transport; use HubClient (which wires it up) rather than constructing HubWorkflowsClient directly\",\n });\n }\n return downloadBytes(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}`,\n { method: \"GET\" },\n );\n }\n\n // ----- Templates -----\n\n /** The curated starter gallery runnable on THIS deployment: metadata,\n * parameters, referenced providers, and a concrete `previewYaml` per card. */\n async listTemplates(): Promise<HubWorkflowTemplate[]> {\n return this.request<HubWorkflowTemplate[]>(\"/v1/workflows/templates\", {\n method: \"GET\",\n });\n }\n\n /**\n * One-click create from a gallery template: substitutes `parameters` into\n * the template server-side, then runs the SAME create path as\n * {@link create}. A `{ created: false }` result is NOT an error — an\n * actionable continuation listing the connections to satisfy before\n * retrying. Invalid parameters or a compile failure throw `HubSdkError`\n * (400); an unknown template id throws `NOT_FOUND`.\n */\n async instantiateTemplate(\n templateId: string,\n parameters?: Record<string, string>,\n ): Promise<HubWorkflowTemplateInstantiateResult> {\n return this.request<HubWorkflowTemplateInstantiateResult>(\n `/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`,\n jsonInit(\"POST\", parameters ? { parameters } : {}),\n );\n }\n\n // ----- Decisions (human-in-the-loop) -----\n\n /**\n * The caller's open decisions across all workflows — the always-available\n * \"pending approvals\" surface. Each entry carries its workflow's name (null\n * when the workflow was deleted while the run was parked).\n */\n async listPendingDecisions(): Promise<HubWorkflowPendingDecisionsResponse> {\n return this.request<HubWorkflowPendingDecisionsResponse>(\n \"/v1/workflows/decisions/pending\",\n { method: \"GET\" },\n );\n }\n\n /**\n * The pending decision a run is parked on. Throws `HubSdkError(NOT_FOUND)`\n * when the run is unknown/foreign or holds no pending decision.\n */\n async getRunDecision(\n id: string,\n runId: string,\n ): Promise<HubWorkflowDecision> {\n return this.request<HubWorkflowDecision>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision`,\n { method: \"GET\" },\n );\n }\n\n /**\n * Answer the decision a run is parked on and resume it from the next action.\n * `decisionId` is REQUIRED: a run can resolve one decision and re-park on the\n * next, so an answer addressed only by run could silently land on a question\n * the caller never saw — a mismatch throws `HubSdkError(DECISION_SUPERSEDED)`.\n * Other typed failures: `INVALID_CHOICE` (400), `DECISION_ALREADY_RESOLVED` /\n * `DECISION_EXPIRED` (409), `DECISION_NOT_FOUND` (404), `RUN_NOT_WAITING`\n * (409 — answered, timed out, or cancelled first).\n */\n async resolveRunDecision(\n id: string,\n runId: string,\n input: { decisionId: string; choice: string; note?: string },\n ): Promise<HubWorkflowDecisionResolveResult> {\n return this.request<HubWorkflowDecisionResolveResult>(\n `/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`,\n jsonInit(\"POST\", input),\n );\n }\n\n /**\n * Dry-run a YAML definition against the platform compiler without saving it.\n *\n * `opts.structural` selects the CI mode: the platform skips its owner-scoped\n * connection/skill/profile resolution, so the verdict depends only on the\n * definition and the deployment's capabilities — identical no matter which\n * providers the calling account has connected. Use it in pipelines that\n * assert \"this YAML is well-formed\"; leave it off in an editor, where naming\n * the unconnected providers is the point.\n */\n async validate(\n yaml: string,\n opts: { structural?: boolean } = {},\n ): Promise<HubWorkflowValidateResponse> {\n return this.request<HubWorkflowValidateResponse>(\n \"/v1/workflows/validate\",\n jsonInit(\"POST\", {\n yaml,\n ...(opts.structural ? { structural: true } : {}),\n }),\n );\n }\n\n async schema(): Promise<HubWorkflowSchemaResponse> {\n return this.request<HubWorkflowSchemaResponse>(\"/v1/workflows/schema\", {\n method: \"GET\",\n });\n }\n}\n","import { HubAllowancesClient } from \"./allowances.js\";\nimport { HubAppsClient } from \"./apps.js\";\nimport { HubKnowledgeClient } from \"./knowledge.js\";\nimport { HubLinesClient } from \"./lines.js\";\nimport { HubManagedNumbersClient } from \"./managed-numbers.js\";\nimport {\n type HubClientOptions,\n HubSdkError,\n HubTransport,\n httpError,\n} from \"./transport.js\";\nimport type {\n HubStatusResponse,\n HubWorkflowArtifactDownload,\n} from \"./types.js\";\n\nexport {\n type HubAuthHeaders,\n type HubClientOptions,\n HubSdkError,\n HubTransport,\n} from \"./transport.js\";\n\nimport {\n type HubClientFromEnvOptions,\n resolveHubAuth,\n resolveHubBaseUrl,\n} from \"./environment.js\";\n\nexport {\n HUB_API_KEY_ENV_VAR,\n HUB_CAPABILITY_TOKEN_ENV_VAR,\n HUB_URL_ENV_VAR,\n type HubClientFromEnvOptions,\n type HubEnv,\n resolveHubAuth,\n resolveHubBaseUrl,\n} from \"./environment.js\";\n\nimport {\n HubApprovalsClient,\n HubPermissionsClient,\n HubTokensClient,\n} from \"./authorization.js\";\n\nexport {\n HubApprovalsClient,\n HubPermissionsClient,\n type HubTokenListOptions,\n HubTokensClient,\n} from \"./authorization.js\";\n\nimport { HubToolsClient } from \"./tools.js\";\n\nexport {\n type HubToolInvokeOptions,\n type HubToolSearchOptions,\n HubToolsClient,\n} from \"./tools.js\";\n\nimport { HubConnectionsClient } from \"./connections.js\";\n\nexport {\n type HubConnectionStartOptions,\n HubConnectionsClient,\n} from \"./connections.js\";\n\nimport { HubChannelsClient, HubEventSubscriptionsClient } from \"./channels.js\";\n\nexport { HubChannelsClient, HubEventSubscriptionsClient } from \"./channels.js\";\n\nimport { HubGithubAppClient } from \"./github-app.js\";\n\nexport { HubGithubAppClient } from \"./github-app.js\";\n\nimport { HubAuditClient } from \"./audit.js\";\n\nexport { HubAuditClient } from \"./audit.js\";\n\nimport { HubWorkflowsClient } from \"./workflows.js\";\n\nexport { HubWorkflowsClient } from \"./workflows.js\";\n\nimport { readProcessEnv } from \"./environment.js\";\nimport { isRecord, throwHubResponseError } from \"./transport.js\";\n\nfunction isDispatchCurrentData(value: unknown): value is { current: boolean } {\n return isRecord(value) && typeof value.current === \"boolean\";\n}\n\nexport class HubClient extends HubTransport {\n readonly knowledge: HubKnowledgeClient;\n readonly allowances: HubAllowancesClient;\n readonly apps: HubAppsClient;\n readonly connections: HubConnectionsClient;\n readonly channels: HubChannelsClient;\n readonly numbers: HubManagedNumbersClient;\n readonly eventSubscriptions: HubEventSubscriptionsClient;\n readonly permissions: HubPermissionsClient;\n readonly tokens: HubTokensClient;\n readonly tools: HubToolsClient;\n readonly approvals: HubApprovalsClient;\n readonly audit: HubAuditClient;\n readonly githubApp: HubGithubAppClient;\n readonly workflows: HubWorkflowsClient;\n readonly lines: HubLinesClient;\n\n constructor(options: HubClientOptions) {\n super(options);\n this.knowledge = new HubKnowledgeClient((path, init) =>\n this.request(path, init),\n );\n this.allowances = new HubAllowancesClient((path, init) =>\n this.request(path, init),\n );\n this.apps = new HubAppsClient((path, init) => this.request(path, init));\n this.numbers = new HubManagedNumbersClient((path, init) =>\n this.request(path, init),\n );\n this.connections = new HubConnectionsClient((path, init) =>\n this.request(path, init),\n );\n this.channels = new HubChannelsClient((path, init) =>\n this.request(path, init),\n );\n this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) =>\n this.request(path, init),\n );\n this.permissions = new HubPermissionsClient((path, init) =>\n this.request(path, init),\n );\n this.tokens = new HubTokensClient((path, init) => this.request(path, init));\n this.tools = new HubToolsClient((path, init) => this.request(path, init));\n this.approvals = new HubApprovalsClient((path, init) =>\n this.request(path, init),\n );\n this.audit = new HubAuditClient((path, init) => this.request(path, init));\n this.githubApp = new HubGithubAppClient((path, init) =>\n this.request(path, init),\n );\n this.workflows = new HubWorkflowsClient(\n (path, init) => this.request(path, init),\n (path, init) => this.stream(path, init),\n (path, init) => this.requestBytes(path, init),\n );\n this.lines = new HubLinesClient(\n (path, init) => this.request(path, init),\n (yaml) => this.workflows.create(yaml),\n (path, init, callbackBearer) => {\n if (\n typeof callbackBearer !== \"string\" ||\n !/^[\\x21-\\x7e]{16,512}$/.test(callbackBearer)\n ) {\n throw new HubSdkError({\n code: \"HUB_INVALID_INPUT\",\n message: \"Application callback bearer is invalid\",\n });\n }\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `Bearer ${callbackBearer}`);\n // Worker transports support manual redirects; the strict HTTP check\n // rejects the response without forwarding the callback bearer.\n return this.request<{ current: boolean }>(\n path,\n { ...init, headers, credentials: \"omit\", redirect: \"manual\" },\n { auth: \"caller\", validateData: isDispatchCurrentData },\n );\n },\n );\n }\n\n // Static factory: construct a HubClient from environment variables.\n // Required: TANGLE_HUB_URL. Auth: exactly one of TANGLE_API_KEY or\n // TANGLE_HUB_CAPABILITY_TOKEN (skip the env auth resolve by passing\n // `apiKey` / `authHeaders` explicitly). No fallback — throws HubSdkError\n // with HUB_CONFIG_MISSING / HUB_CONFIG_INVALID when env is incomplete.\n // SaaS vs on-prem flips via env only.\n static fromEnv(options: HubClientFromEnvOptions = {}): HubClient {\n const env = options.env ?? readProcessEnv();\n const baseUrl = resolveHubBaseUrl(env);\n const apiKey =\n options.apiKey ?? (options.authHeaders ? undefined : resolveHubAuth(env));\n return new HubClient({\n baseUrl,\n apiKey,\n authHeaders: options.authHeaders,\n fetch: options.fetch,\n });\n }\n\n async status(): Promise<HubStatusResponse> {\n return this.request<HubStatusResponse>(\"/v1/hub/status\", { method: \"GET\" });\n }\n\n /**\n * Open a streaming (Server-Sent Events) response and return its raw body.\n * Shares auth-header building + `fetch` with {@link request}, but does NOT\n * buffer or JSON-parse the body — the caller consumes the stream.\n *\n * A successful stream comes back as `text/event-stream`. Anything else is an\n * error envelope (404/429/401 JSON) or a transport failure (gateway/HTML\n * page); it is surfaced the same way {@link request} surfaces errors — a\n * typed `HubSdkError` from a `{success:false}` envelope, otherwise an\n * `HUB_HTTP_<status>` transport error — rather than handed back as bogus SSE.\n */\n private async stream(\n path: string,\n init: RequestInit,\n ): Promise<ReadableStream<Uint8Array>> {\n const response = await this.fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: await this.buildHeaders(init.headers),\n });\n\n const status = response.status;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n // A non-2xx response is an error even when it carries a text/event-stream\n // content-type (a misconfigured upstream / proxy error page) — route it into\n // the error path below instead of handing it to the consumer as a live\n // stream, which would hang waiting for events that never come.\n if (!response.ok || !contentType.includes(\"text/event-stream\")) {\n await throwHubResponseError(path, response, status, contentType);\n }\n\n if (!response.body) {\n throw httpError(\n path,\n status,\n response.statusText,\n \"event-stream response had no body\",\n contentType,\n );\n }\n return response.body;\n }\n\n /**\n * Fetch raw (non-envelope) bytes — the artifact download route, whose 200 is\n * the artifact's own content type, not JSON. Error responses on such routes\n * are still the standard envelope, so a failure surfaces exactly like\n * {@link request}: a typed `HubSdkError` from a `{success:false}` body,\n * otherwise an `HUB_HTTP_<status>` transport error.\n */\n private async requestBytes(\n path: string,\n init: RequestInit,\n ): Promise<HubWorkflowArtifactDownload> {\n const response = await this.fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: await this.buildHeaders(init.headers),\n });\n\n const status = response.status;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!response.ok) {\n await throwHubResponseError(path, response, status, contentType);\n }\n return {\n bytes: new Uint8Array(await response.arrayBuffer()),\n contentType,\n };\n }\n}\n","import { HubClient, HubSdkError } from \"./client.js\";\n\nexport interface HubAppBrokerOptions {\n baseUrl: string;\n clientId: string;\n clientSecret: string;\n fetch?: typeof fetch;\n}\nexport interface HubAppBrokerToken {\n accessToken: string;\n expiresIn: number;\n scopes: string[];\n}\nexport interface HubAppBrokerExchange extends HubAppBrokerToken {\n grantId: string;\n connectionId: string;\n}\n/** Server-only client. App secrets never become a user's general API key.\n * Every invocation mints and consumes one short-lived, exact-grant token. */\nexport class HubAppBrokerClient {\n private readonly baseUrl: string;\n private readonly fetcher: typeof fetch;\n constructor(private readonly options: HubAppBrokerOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.fetcher = options.fetch ?? fetch.bind(globalThis);\n }\n private async token(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const response = await this.fetcher(`${this.baseUrl}${path}`, {\n method: \"POST\",\n // Workers support manual redirects; the non-ok check below rejects every 3xx.\n redirect: \"manual\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...body,\n client_id: this.options.clientId,\n client_secret: this.options.clientSecret,\n }),\n });\n const result: unknown = await response.json().catch(() => null);\n if (\n !response.ok ||\n !result ||\n typeof result !== \"object\" ||\n Array.isArray(result)\n ) {\n throw new HubSdkError(\n {\n code: \"HUB_CONFIG_MISSING\",\n message: \"Application authorization is unavailable\",\n },\n { status: response.status },\n );\n }\n return result as Record<string, unknown>;\n }\n private readToken(body: Record<string, unknown>): HubAppBrokerToken {\n if (\n typeof body.access_token !== \"string\" ||\n !body.access_token.startsWith(\"sk-tan-broker-\") ||\n body.token_type !== \"Bearer\" ||\n typeof body.expires_in !== \"number\" ||\n !Number.isSafeInteger(body.expires_in) ||\n body.expires_in <= 0 ||\n typeof body.scope !== \"string\"\n )\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Invalid application authorization response\",\n });\n return {\n accessToken: body.access_token,\n expiresIn: body.expires_in,\n scopes: body.scope.split(\" \").filter(Boolean),\n };\n }\n async exchange(input: {\n code: string;\n redirectUri: string;\n connectionId?: string;\n }): Promise<HubAppBrokerExchange> {\n const body = await this.token(\"/v1/apps/oauth/token\", {\n grant_type: \"authorization_code\",\n code: input.code,\n redirect_uri: input.redirectUri,\n ...(input.connectionId === undefined\n ? {}\n : { connection_id: input.connectionId }),\n ttl_seconds: 60,\n });\n const token = this.readToken(body);\n if (\n typeof body.grant_id !== \"string\" ||\n !body.grant_id ||\n typeof body.connection_id !== \"string\" ||\n !body.connection_id.trim() ||\n (input.connectionId !== undefined &&\n body.connection_id !== input.connectionId)\n )\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Application connection did not match consent\",\n });\n return {\n ...token,\n grantId: body.grant_id,\n connectionId: body.connection_id,\n };\n }\n async mint(grantId: string): Promise<HubAppBrokerToken> {\n if (!/^[A-Za-z0-9_-]{1,256}$/.test(grantId))\n throw new Error(\"Invalid application grant\");\n return this.readToken(\n await this.token(\n `/v1/apps/grants/${encodeURIComponent(grantId)}/mint-broker-token`,\n { grant_id: grantId, ttl_seconds: 60 },\n ),\n );\n }\n async invoke<T = unknown>(\n grantId: string,\n connectionId: string,\n actionPath: string,\n input: Record<string, unknown>,\n ) {\n const token = await this.mint(grantId);\n if (!token.scopes.includes(actionPath))\n throw new HubSdkError({\n code: \"HUB_POLICY_DENIED\",\n message: \"This action was not granted to the application\",\n });\n return new HubClient({\n baseUrl: this.baseUrl,\n apiKey: token.accessToken,\n fetch: this.fetcher,\n }).tools.invoke<T>(actionPath, input, { connectionId });\n }\n}\n","import type { HubEventDelivery } from \"./types.js\";\n\nconst DEFAULT_TOLERANCE_SECONDS = 300;\nconst MAX_TOLERANCE_SECONDS = 3_600;\nconst MAX_SIGNATURE_HEADER_LENGTH = 1_024;\nconst MAX_SIGNATURES = 5;\nconst SHA256_HEX_LENGTH = 64;\nconst MIN_CALLBACK_SECRET_BYTES = 32;\nconst MAX_SECRET_SCOPE_COMPONENT_BYTES = 512;\nconst DEFAULT_MAX_CALLBACK_BODY_BYTES = 5 * 1024 * 1024 + 64 * 1024;\nconst MAX_CALLBACK_BODY_BYTES = 10 * 1024 * 1024;\n\nexport type HubEventSignatureFailure =\n | \"missing\"\n | \"malformed\"\n | \"stale\"\n | \"mismatch\";\n\nexport type HubEventSignatureResult =\n | { valid: true; timestamp: number }\n | { valid: false; reason: HubEventSignatureFailure };\n\nexport interface VerifyHubEventSignatureInput {\n body: string;\n signature: string | null | undefined;\n secret: string;\n toleranceSeconds?: number;\n now?: number | Date;\n}\n\nexport interface DeriveHubEventCallbackSecretInput {\n /** App-level secret stored only in the product's server environment. */\n rootSecret: string;\n /** Stable product slug, such as `relationships`. */\n productId: string;\n /** Stable Tangle owner id; user and team ids are both valid. */\n ownerId: string;\n /** Stable product-local binding id used in the callback route. */\n bindingId: string;\n}\n\nexport type HubEventRequestFailureCode =\n | \"METHOD_NOT_ALLOWED\"\n | \"UNEXPECTED_EVENT\"\n | \"UNSUPPORTED_MEDIA_TYPE\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_DELIVERY\"\n | \"DELIVERY_ID_MISMATCH\";\n\nexport type HubEventRequestResult =\n | { ok: true; delivery: HubEventDelivery }\n | {\n ok: false;\n code: HubEventRequestFailureCode;\n response: Response;\n };\n\nexport interface AuthenticateHubEventRequestInput {\n request: Request;\n /** The per-binding secret supplied when the subscription was created. */\n secret: string;\n /** Defaults to 5 MiB plus envelope overhead; hard-capped at 10 MiB. */\n maxBodyBytes?: number;\n toleranceSeconds?: number;\n now?: number | Date;\n}\n\nexport class HubEventDeliveryError extends Error {\n readonly code:\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\"\n | \"CRYPTO_UNAVAILABLE\"\n | \"INVALID_TOLERANCE\"\n | \"INVALID_CALLBACK_SECRET\"\n | \"INVALID_SECRET_SCOPE\"\n | \"INVALID_BODY_LIMIT\";\n\n constructor(code: HubEventDeliveryError[\"code\"], message: string) {\n super(message);\n this.name = \"HubEventDeliveryError\";\n this.code = code;\n }\n}\n\n/**\n * Derive one callback secret per product binding from a single server-held root\n * secret. Products persist only the binding id; the derived secret can be\n * reproduced for callback authentication without another secret table.\n */\nexport async function deriveHubEventCallbackSecret(\n input: DeriveHubEventCallbackSecretInput,\n): Promise<string> {\n const encoder = new TextEncoder();\n if (encoder.encode(input.rootSecret).byteLength < MIN_CALLBACK_SECRET_BYTES) {\n throw new HubEventDeliveryError(\n \"INVALID_CALLBACK_SECRET\",\n `Hub event root secret must contain at least ${MIN_CALLBACK_SECRET_BYTES} UTF-8 bytes`,\n );\n }\n for (const [name, value] of [\n [\"productId\", input.productId],\n [\"ownerId\", input.ownerId],\n [\"bindingId\", input.bindingId],\n ] as const) {\n const bytes = encoder.encode(value).byteLength;\n if (bytes === 0 || bytes > MAX_SECRET_SCOPE_COMPONENT_BYTES) {\n throw new HubEventDeliveryError(\n \"INVALID_SECRET_SCOPE\",\n `${name} must contain 1-${MAX_SECRET_SCOPE_COMPONENT_BYTES} UTF-8 bytes`,\n );\n }\n }\n const subtle = requireSubtleCrypto();\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(input.rootSecret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const scope = JSON.stringify([\n \"tangle-hub-event-callback\",\n 1,\n input.productId,\n input.ownerId,\n input.bindingId,\n ]);\n const signature = new Uint8Array(\n await subtle.sign(\"HMAC\", key, encoder.encode(scope)),\n );\n return bytesToBase64Url(signature);\n}\n\n/**\n * Authenticate and parse the platform's callback as one operation. The exact\n * raw body is read once with a size limit before its signature is checked.\n *\n * A successful callback can be retried. Use `delivery.runId` as the durable\n * idempotency key before starting product work.\n */\nexport async function authenticateHubEventRequest(\n input: AuthenticateHubEventRequestInput,\n): Promise<HubEventRequestResult> {\n if (input.request.method !== \"POST\") {\n return requestFailure(\"METHOD_NOT_ALLOWED\", 405, \"method_not_allowed\", {\n Allow: \"POST\",\n });\n }\n if (input.request.headers.get(\"x-tangle-event\") !== \"hub.event\") {\n return requestFailure(\"UNEXPECTED_EVENT\", 400, \"invalid_hub_event\");\n }\n const contentType = input.request.headers.get(\"content-type\") ?? \"\";\n if (!/^application\\/json(?:\\s*;|$)/i.test(contentType)) {\n return requestFailure(\n \"UNSUPPORTED_MEDIA_TYPE\",\n 415,\n \"unsupported_media_type\",\n );\n }\n const maxBodyBytes = input.maxBodyBytes ?? DEFAULT_MAX_CALLBACK_BODY_BYTES;\n if (\n !Number.isSafeInteger(maxBodyBytes) ||\n maxBodyBytes < 1 ||\n maxBodyBytes > MAX_CALLBACK_BODY_BYTES\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_BODY_LIMIT\",\n `Hub event body limit must be an integer from 1 to ${MAX_CALLBACK_BODY_BYTES} bytes`,\n );\n }\n if (\n new TextEncoder().encode(input.secret).byteLength <\n MIN_CALLBACK_SECRET_BYTES\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_CALLBACK_SECRET\",\n `Hub event callback secret must contain at least ${MIN_CALLBACK_SECRET_BYTES} UTF-8 bytes`,\n );\n }\n const declaredLength = input.request.headers.get(\"content-length\");\n if (\n declaredLength !== null &&\n /^\\d+$/.test(declaredLength) &&\n Number(declaredLength) > maxBodyBytes\n ) {\n return requestFailure(\"PAYLOAD_TOO_LARGE\", 413, \"payload_too_large\");\n }\n const body = await readRequestBody(input.request, maxBodyBytes);\n if (body === null) {\n return requestFailure(\"PAYLOAD_TOO_LARGE\", 413, \"payload_too_large\");\n }\n const signature = await verifyHubEventSignature({\n body,\n signature: input.request.headers.get(\"x-tangle-signature\"),\n secret: input.secret,\n ...(input.toleranceSeconds !== undefined\n ? { toleranceSeconds: input.toleranceSeconds }\n : {}),\n ...(input.now !== undefined ? { now: input.now } : {}),\n });\n if (!signature.valid) {\n return requestFailure(\"INVALID_SIGNATURE\", 401, \"invalid_signature\");\n }\n let delivery: HubEventDelivery;\n try {\n delivery = parseHubEventDelivery(body);\n } catch (error) {\n if (error instanceof HubEventDeliveryError) {\n return requestFailure(\"INVALID_DELIVERY\", 400, \"invalid_delivery\");\n }\n throw error;\n }\n if (input.request.headers.get(\"x-tangle-delivery-id\") !== delivery.runId) {\n return requestFailure(\"DELIVERY_ID_MISMATCH\", 400, \"invalid_delivery\");\n }\n return { ok: true, delivery };\n}\n\n/**\n * Authenticate a Hub event callback against its exact raw request body.\n * The timestamp window rejects captured-request replay, and byte-wise\n * comparison avoids secret-dependent string comparison behavior.\n */\nexport async function verifyHubEventSignature(\n input: VerifyHubEventSignatureInput,\n): Promise<HubEventSignatureResult> {\n if (!input.signature) return { valid: false, reason: \"missing\" };\n if (input.signature.length > MAX_SIGNATURE_HEADER_LENGTH) {\n return { valid: false, reason: \"malformed\" };\n }\n const parsed = parseSignatureHeader(input.signature);\n if (!parsed) return { valid: false, reason: \"malformed\" };\n\n const tolerance = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (\n !Number.isFinite(tolerance) ||\n !Number.isInteger(tolerance) ||\n tolerance < 0 ||\n tolerance > MAX_TOLERANCE_SECONDS\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_TOLERANCE\",\n `Signature tolerance must be an integer from 0 to ${MAX_TOLERANCE_SECONDS} seconds`,\n );\n }\n const nowMs =\n input.now instanceof Date\n ? input.now.getTime()\n : typeof input.now === \"number\"\n ? input.now\n : Date.now();\n if (\n !Number.isFinite(nowMs) ||\n Math.abs(Math.floor(nowMs / 1_000) - parsed.timestamp) > tolerance\n ) {\n return { valid: false, reason: \"stale\" };\n }\n\n const subtle = requireSubtleCrypto();\n const encoder = new TextEncoder();\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(input.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const expected = new Uint8Array(\n await subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(`${parsed.timestamp}.${input.body}`),\n ),\n );\n let matched = 0;\n for (const signature of parsed.signatures) {\n matched |= constantTimeEqual(expected, signature);\n }\n return matched === 1\n ? { valid: true, timestamp: parsed.timestamp }\n : { valid: false, reason: \"mismatch\" };\n}\n\nexport function parseHubEventDelivery(\n input: string | unknown,\n): HubEventDelivery {\n let value: unknown = input;\n if (typeof input === \"string\") {\n try {\n value = JSON.parse(input);\n } catch {\n throw new HubEventDeliveryError(\n \"INVALID_JSON\",\n \"Hub event callback body is not valid JSON\",\n );\n }\n }\n if (!isRecord(value)) return invalidDelivery();\n const source = value.source;\n const providerEvent = value.providerEvent;\n if (\n !nonEmptyString(value.subscriptionId) ||\n !nonEmptyString(value.workflowId) ||\n !nonEmptyString(value.runId) ||\n !isRecord(source) ||\n (source.kind !== \"channel\" && source.kind !== \"connection\") ||\n !nonEmptyString(source.id) ||\n !nonEmptyString(source.provider) ||\n !nonEmptyString(source.event) ||\n !isRecord(providerEvent) ||\n !nonEmptyString(providerEvent.provider) ||\n !nonEmptyString(providerEvent.connectionId) ||\n !nonEmptyString(providerEvent.type) ||\n providerEvent.provider !== source.provider ||\n providerEvent.type !== source.event ||\n !Object.hasOwn(providerEvent, \"payload\") ||\n !optionalString(providerEvent.action) ||\n !optionalString(providerEvent.repo) ||\n !optionalString(providerEvent.deliveryId) ||\n !nonEmptyString(value.firedAt) ||\n !Number.isFinite(Date.parse(value.firedAt))\n ) {\n return invalidDelivery();\n }\n return {\n subscriptionId: value.subscriptionId,\n workflowId: value.workflowId,\n runId: value.runId,\n source: {\n kind: source.kind,\n id: source.id,\n provider: source.provider,\n event: source.event,\n },\n providerEvent: {\n provider: providerEvent.provider,\n connectionId: providerEvent.connectionId,\n type: providerEvent.type,\n ...(typeof providerEvent.action === \"string\"\n ? { action: providerEvent.action }\n : {}),\n ...(typeof providerEvent.repo === \"string\"\n ? { repo: providerEvent.repo }\n : {}),\n ...(typeof providerEvent.deliveryId === \"string\"\n ? { deliveryId: providerEvent.deliveryId }\n : {}),\n payload: providerEvent.payload,\n },\n firedAt: value.firedAt,\n };\n}\n\nfunction parseSignatureHeader(\n header: string,\n): { timestamp: number; signatures: Uint8Array[] } | null {\n let timestamp: number | undefined;\n const signatures: Uint8Array[] = [];\n for (const segment of header.split(\",\")) {\n const separator = segment.indexOf(\"=\");\n if (separator <= 0) return null;\n const key = segment.slice(0, separator).trim();\n const value = segment.slice(separator + 1).trim();\n if (key === \"t\") {\n if (timestamp !== undefined || !/^\\d+$/.test(value)) return null;\n const candidate = Number(value);\n if (!Number.isSafeInteger(candidate) || candidate <= 0) return null;\n timestamp = candidate;\n } else if (key === \"v1\") {\n if (\n signatures.length >= MAX_SIGNATURES ||\n value.length !== SHA256_HEX_LENGTH ||\n !/^[0-9a-f]+$/i.test(value)\n ) {\n return null;\n }\n signatures.push(hexToBytes(value));\n }\n }\n return timestamp !== undefined && signatures.length > 0\n ? { timestamp, signatures }\n : null;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let index = 0; index < bytes.length; index += 1) {\n bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);\n }\n return bytes;\n}\n\nfunction constantTimeEqual(expected: Uint8Array, actual: Uint8Array): number {\n let difference = expected.length ^ actual.length;\n const length = Math.max(expected.length, actual.length);\n for (let index = 0; index < length; index += 1) {\n difference |=\n (expected[index % expected.length] ?? 0) ^\n (actual[index % actual.length] ?? 0);\n }\n return difference === 0 ? 1 : 0;\n}\n\nfunction nonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nfunction optionalString(value: unknown): boolean {\n return value === undefined || nonEmptyString(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction invalidDelivery(): never {\n throw new HubEventDeliveryError(\n \"INVALID_PAYLOAD\",\n \"Hub event callback body does not match the delivery contract\",\n );\n}\n\nfunction requireSubtleCrypto(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new HubEventDeliveryError(\n \"CRYPTO_UNAVAILABLE\",\n \"Web Crypto is required for Hub event callback authentication\",\n );\n }\n return subtle;\n}\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nasync function readRequestBody(\n request: Request,\n maxBytes: number,\n): Promise<string | null> {\n const reader = request.body?.getReader();\n if (!reader) return \"\";\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) break;\n total += next.value.byteLength;\n if (total > maxBytes) return null;\n chunks.push(next.value);\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nfunction requestFailure(\n code: HubEventRequestFailureCode,\n status: number,\n error: string,\n headers?: HeadersInit,\n): Extract<HubEventRequestResult, { ok: false }> {\n return {\n ok: false,\n code,\n response: Response.json(\n { error },\n {\n status,\n headers: {\n \"cache-control\": \"no-store\",\n ...(headers ? Object.fromEntries(new Headers(headers)) : {}),\n },\n },\n ),\n };\n}\n","import type {\n HubKnowledgeManagementClient,\n KnowledgeSourceSummary,\n} from \"./knowledge-management.js\";\n\n/** Called only after the owner reviews this exact pending effect and clicks\n * Approve. Re-read first: a stale tab cannot approve a substituted operation. */\nexport async function approveKnowledgeSource(input: {\n port: Pick<HubKnowledgeManagementClient, \"get\" | \"refresh\">;\n approvals: Pick<import(\"./client.js\").HubApprovalsClient, \"approve\">;\n source: KnowledgeSourceSummary;\n}): Promise<KnowledgeSourceSummary> {\n const { source, port, approvals } = input;\n if (\n source.status !== \"awaiting-approval\" ||\n !source.approval ||\n !source.refreshRequestId ||\n source.approval.preview.sourceId !== source.id ||\n source.approval.preview.requestId !== source.refreshRequestId\n ) {\n throw new Error(\n \"This source has no reviewable pending action. Reload knowledge.\",\n );\n }\n const current = await port.get(source.id);\n if (\n current.id !== source.id ||\n current.status !== \"awaiting-approval\" ||\n current.refreshRequestId !== source.refreshRequestId ||\n JSON.stringify(current.approval) !== JSON.stringify(source.approval)\n ) {\n throw new Error(\n \"The requested action changed. Reload knowledge and review it again.\",\n );\n }\n let approvalToken: string | undefined;\n try {\n const decision = await approvals.approve(source.approval.id);\n if (\n decision.approval.id !== source.approval.id ||\n decision.approval.actionPath !== source.approval.path ||\n decision.approval.connectionId !== source.approval.preview.connectionId ||\n decision.approval.providerId !== source.approval.preview.provider ||\n // Hub consumes the approval when it issues the one-time capability.\n decision.approval.status !== \"consumed\" ||\n !decision.capabilityToken?.token\n ) {\n throw new Error(\n \"The approval did not return a matching one-time capability. Reload knowledge.\",\n );\n }\n approvalToken = decision.capabilityToken.token;\n return await port.refresh(source.id, {\n requestId: source.refreshRequestId,\n approvalToken,\n });\n } finally {\n // Never put capability tokens in component state, storage, URLs, or logs.\n approvalToken = undefined;\n }\n}\n","import { HubTransport } from \"./client.js\";\nimport { jsonInit } from \"./json-init.js\";\nimport type { HubLineOwnerSendInput, HubLineSendReceipt } from \"./lines.js\";\n\nexport type HubOwnerAskSendInput = Pick<\n HubLineOwnerSendInput,\n \"text\" | \"image\" | \"reply\" | \"idempotencyKey\"\n>;\n\nexport interface HubLineGrantBinding {\n workspaceId: string;\n workspaceAgentId: string;\n}\n\nexport interface HubLineGrant {\n id: string;\n /** Canonical Hub identity that consented this grant; distinct from the app-local owner. */\n ownerUserId?: string;\n purpose?: \"agent\" | \"owner_asks\";\n lineId: string;\n connectionId: string;\n workspaceId: string;\n workspaceAgentId: string;\n agentProfileVersion: string;\n backendSha256: string;\n attachmentId: string | null;\n intakeMode: \"guests\" | \"owner_only\";\n /** \"application\" grants select the app's callback for the owner member instead of attaching. */\n execution: \"backend\" | \"application\" | \"none\";\n applicationOrigin: string | null;\n priorAttachmentId: string | null;\n priorAttachmentActive: boolean;\n monthlyBudgetUsd: number;\n monthlySpentUsd: number;\n}\n\nexport interface HubLineGrantLine {\n id: string;\n connectionId: string;\n transport: \"sms\" | \"imessage\" | \"whatsapp\";\n status: string;\n address: string | null;\n attachment: { id: string; sandboxId: string; status: string } | null;\n}\n\nexport interface HubLineGrantAttachInput {\n workspaceAgentId: string;\n agentProfileVersion: string;\n renewalCode?: string;\n respond: { kind: \"agent\"; backend: Record<string, unknown> };\n}\n\nexport interface HubLineGrantAttachment {\n id: string;\n sandboxId: string;\n status: string;\n members?: Array<{ id: string; role: string }>;\n}\n\nexport interface HubLineGrantThread {\n id: string;\n lineId: string;\n attachmentId: string;\n}\n\nexport interface HubLineGrantMessage {\n id: string;\n threadId: string;\n direction: string;\n text: string | null;\n}\n\n/** The consented owner member on the owner's current attachment. */\nexport interface HubLineGrantMemberApplication {\n lineId: string;\n attachmentId: string;\n memberId: string;\n subjectId: string;\n /** Pass back unchanged as `expectedMemberRevision`. */\n memberRevision: string;\n /** False until the owner has texted the line and Hub recorded consent. */\n eligible: boolean;\n /** Hub-derived; every callback for this grant carries it. */\n binding: string;\n selection: {\n id: string;\n /** True when this grant's callback is the selected application. */\n own: boolean;\n /**\n * Hub's name for the app that answers the owner's texts, shown to the\n * owner in every app they consented on this line: a registered app's\n * name, or \"Another app\" when Hub has none. Absent before Platform named\n * selection holders.\n */\n app?: { name: string };\n /** When the current app started answering. */\n selectedAt?: string;\n /** This app's own callback; never returned for another app. */\n url?: string;\n createdAt?: string;\n } | null;\n}\n\nexport interface HubLineGrantSelectApplicationInput {\n /** The current selection exactly as read. */\n expectedSelectionId: string | null;\n /**\n * Set only when the owner chose to move their texts here from the app shown\n * in `selection.app`: that selection's id, also passed as\n * `expectedSelectionId`. Without it Hub never replaces another app.\n */\n replaceSelectionId?: string;\n expectedMemberRevision: string;\n /** HTTPS callback on the owner-approved application origin. */\n url: string;\n /** Bearer Hub sends to the callback; 32-512 printable ASCII characters. */\n secret: string;\n}\n\nexport interface HubLineGrantApplicationSelection {\n id: string;\n lineId: string;\n attachmentId: string;\n memberId: string;\n subjectId: string;\n status: string;\n application: { url: string; binding: string };\n createdAt: string;\n revokedAt: string | null;\n}\n\nfunction path(binding: HubLineGrantBinding, suffix = \"\"): string {\n if (!binding.workspaceId || !binding.workspaceAgentId)\n throw new Error(\"A workspace and agent are required for a line grant\");\n const query = new URLSearchParams({\n workspaceId: binding.workspaceId,\n workspaceAgentId: binding.workspaceAgentId,\n });\n return `/v1/hub/line-grants/current${suffix}?${query}`;\n}\n\n/** Every call uses HubTransport's authHeaders, so one-use app broker tokens can be minted per request. */\nexport class HubLineGrantsClient extends HubTransport {\n current(binding: HubLineGrantBinding): Promise<HubLineGrant> {\n return this.request(path(binding), { method: \"GET\" });\n }\n\n async line(binding: HubLineGrantBinding): Promise<HubLineGrantLine> {\n return (\n await this.request<{ line: HubLineGrantLine }>(path(binding, \"/line\"), {\n method: \"GET\",\n })\n ).line;\n }\n\n async attach(\n binding: HubLineGrantBinding,\n input: HubLineGrantAttachInput,\n ): Promise<HubLineGrantAttachment> {\n return (\n await this.request<{ attachment: HubLineGrantAttachment }>(\n path(binding, \"/attachment\"),\n jsonInit(\"PUT\", input),\n )\n ).attachment;\n }\n\n detach(binding: HubLineGrantBinding): Promise<{ detached: boolean }> {\n return this.request(path(binding, \"/attachment\"), { method: \"DELETE\" });\n }\n\n async threads(binding: HubLineGrantBinding): Promise<HubLineGrantThread[]> {\n return (\n await this.request<{ threads: HubLineGrantThread[] }>(\n path(binding, \"/threads\"),\n { method: \"GET\" },\n )\n ).threads;\n }\n\n async messages(\n binding: HubLineGrantBinding,\n threadId: string,\n ): Promise<HubLineGrantMessage[]> {\n if (!threadId || threadId.length > 256)\n throw new Error(\"A bounded line thread id is required\");\n return (\n await this.request<{ messages: HubLineGrantMessage[] }>(\n path(binding, `/threads/${encodeURIComponent(threadId)}/messages`),\n { method: \"GET\" },\n )\n ).messages;\n }\n\n memberApplication(\n binding: HubLineGrantBinding,\n ): Promise<HubLineGrantMemberApplication> {\n return this.request(path(binding, \"/member-application\"), {\n method: \"GET\",\n });\n }\n\n /**\n * Route the owner's texts to this app's callback; the incumbent attachment\n * stays. `replaceSelectionId` moves them from another app on the owner's\n * explicit choice.\n */\n async selectApplication(\n binding: HubLineGrantBinding,\n input: HubLineGrantSelectApplicationInput,\n ): Promise<HubLineGrantApplicationSelection> {\n return (\n await this.request<{ selection: HubLineGrantApplicationSelection }>(\n path(binding, \"/member-application\"),\n jsonInit(\"PUT\", input),\n )\n ).selection;\n }\n\n /** Return the owner's texts to the incumbent attachment. */\n async clearApplication(\n binding: HubLineGrantBinding,\n input: { expectedSelectionId: string; expectedMemberRevision: string },\n ): Promise<void> {\n await this.request(\n path(binding, \"/member-application\"),\n jsonInit(\"DELETE\", input),\n );\n }\n\n /** Ask only the verified owner member named by this owner_asks grant. */\n send(\n binding: HubLineGrantBinding,\n input: HubOwnerAskSendInput,\n ): Promise<HubLineSendReceipt> {\n return this.request(path(binding, \"/send\"), jsonInit(\"POST\", input));\n }\n\n /** Only a send created by this same grant is visible. */\n outbox(\n binding: HubLineGrantBinding,\n messageId: string,\n ): Promise<HubLineSendReceipt> {\n if (!/^lmsg_[A-Za-z0-9_-]+$/.test(messageId))\n throw new Error(\"A line message id is required\");\n return this.request(\n path(binding, `/outbox/${encodeURIComponent(messageId)}`),\n { method: \"GET\" },\n );\n }\n\n revoke(\n binding: HubLineGrantBinding,\n expectedGrantId?: string,\n ): Promise<{ revoked: boolean }> {\n const target = path(binding);\n return this.request(\n expectedGrantId === undefined\n ? target\n : `${target}&expectedGrantId=${encodeURIComponent(expectedGrantId)}`,\n { method: \"DELETE\" },\n );\n }\n}\n","import type { HubWorkflowGraphSpec } from \"./workflow-graph-types.js\";\nimport type { HubWorkflowRunSummary } from \"./workflow-run-types.js\";\n\nexport type {\n HubWorkflowCondition,\n HubWorkflowConditionOp,\n HubWorkflowConditionScalar,\n HubWorkflowGraphEdge,\n HubWorkflowGraphJoinRule,\n HubWorkflowGraphNode,\n HubWorkflowGraphSpec,\n} from \"./workflow-graph-types.js\";\n\n// ---------- Workflows ----------\n//\n// The workflow resource on the platform (`/v1/workflows`). YAML is the\n// durable representation; the platform compiles it to the engine's run model.\n// Reachable from inside a sandbox via the same client (TANGLE_API_KEY auth).\n\nexport interface HubWorkflowAction {\n kind: string;\n config: Record<string, unknown>;\n}\n\n/** Inbound-event matcher for a `provider_event` trigger. */\nexport interface HubWorkflowEventFilter {\n event: string;\n action?: string;\n repo?: string;\n}\n\nexport interface HubWorkflowTrigger {\n id: string;\n kind: \"provider_event\" | \"schedule\" | \"webhook\";\n enabled: boolean;\n provider: string | null;\n connectionId: string | null;\n eventFilter: HubWorkflowEventFilter | null;\n cron: string | null;\n timezone: string | null;\n nextFireAt: string | null;\n lastFiredAt: string | null;\n /** Schedule only: the ISO-8601 instant it stops firing; null when unbounded. */\n until: string | null;\n}\n\nexport interface HubWorkflowValidationError {\n path: string;\n message: string;\n /** Machine-readable reason where one is defined, e.g. `schedule_outlives_grant`. */\n code?: string;\n}\n\nexport interface HubWorkflow {\n id: string;\n name: string;\n description: string | null;\n enabled: boolean;\n /** Compiled engine actions (connection refs resolved to ids). */\n actions: HubWorkflowAction[];\n /** The durable YAML this workflow compiled from. */\n definitionYaml: string | null;\n validationErrors: HubWorkflowValidationError[];\n /** Current head revision; null on pre-versioning rows until their next\n * update (they have no revision history to point at yet). */\n headRev?: number | null;\n /** Present on get/create/update detail responses; omitted on list. */\n triggers?: HubWorkflowTrigger[];\n /** Present on the detail response: the trigger fields a manual run must supply,\n * derived from the definition's `${trigger.*}` references (empty when none). */\n manualRunInputs?: HubManualRunInput[];\n /** Present on the get-detail response: the compiled graph topology (null\n * when the definition has no graph topology, or is chain-equivalent —\n * the legacy linear semantics). Omitted on the list projection. */\n graph?: HubWorkflowGraphSpec | null;\n /** Create response only, when the definition has a webhook trigger: the\n * hook delivery URL, plus the plaintext bearer token exactly once at mint\n * (absent when an active token already exists — rotate to re-reveal). */\n hook?: HubWorkflowHookEndpoint;\n /** Present on the list response (latest run, or null if never run); omitted on detail. */\n lastRun?: HubWorkflowRunSummary | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** A trigger field a manual \"Run now\" must supply (derived from the\n * definition's `${trigger.*}` references). `required` is false only when every\n * read is wrapped in a `default(...)`. */\nexport interface HubManualRunInput {\n path: string;\n required: boolean;\n}\n\nexport type HubWorkflowValidateResponse =\n | { valid: true; name: string; actionCount: number; triggerCount: number }\n | { valid: false; errors: HubWorkflowValidationError[] };\n\n/** JSON Schema for the YAML workflow definition. */\nexport type HubWorkflowSchemaResponse = Record<string, unknown>;\n\n// ---------- Workflow definition revisions ----------\n//\n// The append-only history of a workflow's YAML (`GET :id/revisions`,\n// `POST :id/rollback`). Every create/update/rollback appends one rev; rollback\n// restores a prior rev's YAML as a NEW head — history is never rewritten.\n// `GET :id/revisions` lists APPLIED revs only (the history); proposed and\n// rejected revs live on the proposals surface below.\n\nexport type HubWorkflowRevisionSource = \"user\" | \"copilot\" | \"intelligence\";\n\n/** Lifecycle state of a revision. The head rev only ever points at an\n * `applied` revision; `proposed` is a service-token-authored suggestion\n * awaiting an owner decision; `rejected` is a declined proposal (kept for\n * audit). */\nexport type HubWorkflowRevisionStatus = \"applied\" | \"proposed\" | \"rejected\";\n\n/** Revision list projection — attribution + note + status, WITHOUT the YAML body. */\nexport interface HubWorkflowRevisionMeta {\n rev: number;\n createdAt: string;\n createdBy: string;\n source: HubWorkflowRevisionSource;\n note: string | null;\n status: HubWorkflowRevisionStatus;\n}\n\n/** One revision WITH its YAML (and the actions compiled alongside it). */\nexport interface HubWorkflowRevision extends HubWorkflowRevisionMeta {\n yaml: string;\n actions: HubWorkflowAction[];\n}\n\n/** A proposal (proposed or rejected revision) WITH its evidence — what the\n * proposer derived the suggestion from (e.g. health stats), plus\n * `rejectionReason` once declined. */\nexport interface HubWorkflowProposal extends HubWorkflowRevisionMeta {\n evidence: unknown;\n}\n\n// ---------- Workflow templates ----------\n//\n// The curated starter gallery (`GET /v1/workflows/templates`) and one-click\n// instantiate. Static catalog data — no per-user fields.\n\nexport type HubWorkflowTemplateCategory =\n | \"Code Review\"\n | \"Triage\"\n | \"Reports\"\n | \"Multi-agent\";\n\n/** One author-time literal a gallery starter needs the user to supply. Every\n * declared parameter is required; `example` is a valid value that seeds the\n * form placeholder. */\nexport interface HubWorkflowTemplateParameter {\n key: string;\n label: string;\n type: \"string\" | \"integer\";\n help?: string;\n example: string;\n default?: string;\n defaultFrom?: \"native_evaluation\";\n required?: boolean;\n advanced?: boolean;\n}\n\nexport interface HubWorkflowTemplate {\n id: string;\n name: string;\n summary: string;\n category: HubWorkflowTemplateCategory;\n icon: string;\n requiresSandbox: boolean;\n /** Providers the template references (a \"uses GitHub\" hint), sorted. */\n providers: string[];\n parameters: HubWorkflowTemplateParameter[];\n /** The template with parameter tokens rendered to their example values. */\n previewYaml: string;\n setupNotes?: string[];\n}\n\n/** A connection a definition needs, with where to connect it. */\nexport interface HubWorkflowConnectionRequirement {\n provider: string;\n connected: boolean;\n kind: \"integration\" | \"github_app\";\n /** Where to satisfy the requirement (App install flow for `github_app`,\n * integrations page otherwise); null when no target exists. */\n connectUrl: string | null;\n /** Another requirement in the same list that must be satisfied first — a\n * `github_app` install is claimed through the `github` connection, so it is\n * refused while that connection is missing. Null when nothing blocks this\n * requirement. The list is ordered prerequisite-first. */\n prerequisite: { provider: string; kind: \"integration\" | \"github_app\" } | null;\n}\n\n/** Stable identity shared by workflow connection requirements and prerequisite references. */\nexport function workflowConnectionRequirementKey(\n ref: Readonly<Pick<HubWorkflowConnectionRequirement, \"provider\" | \"kind\">>,\n): string {\n return `${ref.kind}:${ref.provider}`;\n}\n\n/**\n * Result of instantiating a template. `created: false` is NOT an error — an\n * actionable continuation listing the connections to satisfy before retrying\n * the same call. Invalid parameters or a compile failure throw `HubSdkError`\n * (400) instead, matching the create route's contract.\n */\nexport type HubWorkflowTemplateInstantiateResult =\n | { created: true; workflow: HubWorkflow }\n | {\n created: false;\n connectionRequirements: HubWorkflowConnectionRequirement[];\n };\n\n// ---------- Webhook hook tokens ----------\n\n/** A workflow's webhook delivery endpoint. `token` is the plaintext bearer —\n * revealed only at mint/rotate time (only the hash is stored). */\nexport interface HubWorkflowHookEndpoint {\n url: string;\n token?: string;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/broker.ts","../src/event-delivery.ts","../src/knowledge-approval.ts","../src/line-grants.ts","../src/workflow-definition-types.ts"],"sourcesContent":["import { HubClient, HubSdkError } from \"./client.js\";\n\nexport interface HubAppBrokerOptions {\n baseUrl: string;\n clientId: string;\n clientSecret: string;\n fetch?: typeof fetch;\n}\nexport interface HubAppBrokerToken {\n accessToken: string;\n expiresIn: number;\n scopes: string[];\n}\nexport interface HubAppBrokerExchange extends HubAppBrokerToken {\n grantId: string;\n connectionId: string;\n}\n/** Server-only client. App secrets never become a user's general API key.\n * Every invocation mints and consumes one short-lived, exact-grant token. */\nexport class HubAppBrokerClient {\n private readonly baseUrl: string;\n private readonly fetcher: typeof fetch;\n constructor(private readonly options: HubAppBrokerOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.fetcher = options.fetch ?? fetch.bind(globalThis);\n }\n private async token(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const response = await this.fetcher(`${this.baseUrl}${path}`, {\n method: \"POST\",\n // Workers support manual redirects; the non-ok check below rejects every 3xx.\n redirect: \"manual\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...body,\n client_id: this.options.clientId,\n client_secret: this.options.clientSecret,\n }),\n });\n const result: unknown = await response.json().catch(() => null);\n if (\n !response.ok ||\n !result ||\n typeof result !== \"object\" ||\n Array.isArray(result)\n ) {\n throw new HubSdkError(\n {\n code: \"HUB_CONFIG_MISSING\",\n message: \"Application authorization is unavailable\",\n },\n { status: response.status },\n );\n }\n return result as Record<string, unknown>;\n }\n private readToken(body: Record<string, unknown>): HubAppBrokerToken {\n if (\n typeof body.access_token !== \"string\" ||\n !body.access_token.startsWith(\"sk-tan-broker-\") ||\n body.token_type !== \"Bearer\" ||\n typeof body.expires_in !== \"number\" ||\n !Number.isSafeInteger(body.expires_in) ||\n body.expires_in <= 0 ||\n typeof body.scope !== \"string\"\n )\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Invalid application authorization response\",\n });\n return {\n accessToken: body.access_token,\n expiresIn: body.expires_in,\n scopes: body.scope.split(\" \").filter(Boolean),\n };\n }\n async exchange(input: {\n code: string;\n redirectUri: string;\n connectionId?: string;\n }): Promise<HubAppBrokerExchange> {\n const body = await this.token(\"/v1/apps/oauth/token\", {\n grant_type: \"authorization_code\",\n code: input.code,\n redirect_uri: input.redirectUri,\n ...(input.connectionId === undefined\n ? {}\n : { connection_id: input.connectionId }),\n ttl_seconds: 60,\n });\n const token = this.readToken(body);\n if (\n typeof body.grant_id !== \"string\" ||\n !body.grant_id ||\n typeof body.connection_id !== \"string\" ||\n !body.connection_id.trim() ||\n (input.connectionId !== undefined &&\n body.connection_id !== input.connectionId)\n )\n throw new HubSdkError({\n code: \"HUB_CONFIG_MISSING\",\n message: \"Application connection did not match consent\",\n });\n return {\n ...token,\n grantId: body.grant_id,\n connectionId: body.connection_id,\n };\n }\n async mint(grantId: string): Promise<HubAppBrokerToken> {\n if (!/^[A-Za-z0-9_-]{1,256}$/.test(grantId))\n throw new Error(\"Invalid application grant\");\n return this.readToken(\n await this.token(\n `/v1/apps/grants/${encodeURIComponent(grantId)}/mint-broker-token`,\n { grant_id: grantId, ttl_seconds: 60 },\n ),\n );\n }\n async invoke<T = unknown>(\n grantId: string,\n connectionId: string,\n actionPath: string,\n input: Record<string, unknown>,\n ) {\n const token = await this.mint(grantId);\n if (!token.scopes.includes(actionPath))\n throw new HubSdkError({\n code: \"HUB_POLICY_DENIED\",\n message: \"This action was not granted to the application\",\n });\n return new HubClient({\n baseUrl: this.baseUrl,\n apiKey: token.accessToken,\n fetch: this.fetcher,\n }).tools.invoke<T>(actionPath, input, { connectionId });\n }\n}\n","import type { HubEventDelivery } from \"./types.js\";\n\nconst DEFAULT_TOLERANCE_SECONDS = 300;\nconst MAX_TOLERANCE_SECONDS = 3_600;\nconst MAX_SIGNATURE_HEADER_LENGTH = 1_024;\nconst MAX_SIGNATURES = 5;\nconst SHA256_HEX_LENGTH = 64;\nconst MIN_CALLBACK_SECRET_BYTES = 32;\nconst MAX_SECRET_SCOPE_COMPONENT_BYTES = 512;\nconst DEFAULT_MAX_CALLBACK_BODY_BYTES = 5 * 1024 * 1024 + 64 * 1024;\nconst MAX_CALLBACK_BODY_BYTES = 10 * 1024 * 1024;\n\nexport type HubEventSignatureFailure =\n | \"missing\"\n | \"malformed\"\n | \"stale\"\n | \"mismatch\";\n\nexport type HubEventSignatureResult =\n | { valid: true; timestamp: number }\n | { valid: false; reason: HubEventSignatureFailure };\n\nexport interface VerifyHubEventSignatureInput {\n body: string;\n signature: string | null | undefined;\n secret: string;\n toleranceSeconds?: number;\n now?: number | Date;\n}\n\nexport interface DeriveHubEventCallbackSecretInput {\n /** App-level secret stored only in the product's server environment. */\n rootSecret: string;\n /** Stable product slug, such as `relationships`. */\n productId: string;\n /** Stable Tangle owner id; user and team ids are both valid. */\n ownerId: string;\n /** Stable product-local binding id used in the callback route. */\n bindingId: string;\n}\n\nexport type HubEventRequestFailureCode =\n | \"METHOD_NOT_ALLOWED\"\n | \"UNEXPECTED_EVENT\"\n | \"UNSUPPORTED_MEDIA_TYPE\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_DELIVERY\"\n | \"DELIVERY_ID_MISMATCH\";\n\nexport type HubEventRequestResult =\n | { ok: true; delivery: HubEventDelivery }\n | {\n ok: false;\n code: HubEventRequestFailureCode;\n response: Response;\n };\n\nexport interface AuthenticateHubEventRequestInput {\n request: Request;\n /** The per-binding secret supplied when the subscription was created. */\n secret: string;\n /** Defaults to 5 MiB plus envelope overhead; hard-capped at 10 MiB. */\n maxBodyBytes?: number;\n toleranceSeconds?: number;\n now?: number | Date;\n}\n\nexport class HubEventDeliveryError extends Error {\n readonly code:\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\"\n | \"CRYPTO_UNAVAILABLE\"\n | \"INVALID_TOLERANCE\"\n | \"INVALID_CALLBACK_SECRET\"\n | \"INVALID_SECRET_SCOPE\"\n | \"INVALID_BODY_LIMIT\";\n\n constructor(code: HubEventDeliveryError[\"code\"], message: string) {\n super(message);\n this.name = \"HubEventDeliveryError\";\n this.code = code;\n }\n}\n\n/**\n * Derive one callback secret per product binding from a single server-held root\n * secret. Products persist only the binding id; the derived secret can be\n * reproduced for callback authentication without another secret table.\n */\nexport async function deriveHubEventCallbackSecret(\n input: DeriveHubEventCallbackSecretInput,\n): Promise<string> {\n const encoder = new TextEncoder();\n if (encoder.encode(input.rootSecret).byteLength < MIN_CALLBACK_SECRET_BYTES) {\n throw new HubEventDeliveryError(\n \"INVALID_CALLBACK_SECRET\",\n `Hub event root secret must contain at least ${MIN_CALLBACK_SECRET_BYTES} UTF-8 bytes`,\n );\n }\n for (const [name, value] of [\n [\"productId\", input.productId],\n [\"ownerId\", input.ownerId],\n [\"bindingId\", input.bindingId],\n ] as const) {\n const bytes = encoder.encode(value).byteLength;\n if (bytes === 0 || bytes > MAX_SECRET_SCOPE_COMPONENT_BYTES) {\n throw new HubEventDeliveryError(\n \"INVALID_SECRET_SCOPE\",\n `${name} must contain 1-${MAX_SECRET_SCOPE_COMPONENT_BYTES} UTF-8 bytes`,\n );\n }\n }\n const subtle = requireSubtleCrypto();\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(input.rootSecret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const scope = JSON.stringify([\n \"tangle-hub-event-callback\",\n 1,\n input.productId,\n input.ownerId,\n input.bindingId,\n ]);\n const signature = new Uint8Array(\n await subtle.sign(\"HMAC\", key, encoder.encode(scope)),\n );\n return bytesToBase64Url(signature);\n}\n\n/**\n * Authenticate and parse the platform's callback as one operation. The exact\n * raw body is read once with a size limit before its signature is checked.\n *\n * A successful callback can be retried. Use `delivery.runId` as the durable\n * idempotency key before starting product work.\n */\nexport async function authenticateHubEventRequest(\n input: AuthenticateHubEventRequestInput,\n): Promise<HubEventRequestResult> {\n if (input.request.method !== \"POST\") {\n return requestFailure(\"METHOD_NOT_ALLOWED\", 405, \"method_not_allowed\", {\n Allow: \"POST\",\n });\n }\n if (input.request.headers.get(\"x-tangle-event\") !== \"hub.event\") {\n return requestFailure(\"UNEXPECTED_EVENT\", 400, \"invalid_hub_event\");\n }\n const contentType = input.request.headers.get(\"content-type\") ?? \"\";\n if (!/^application\\/json(?:\\s*;|$)/i.test(contentType)) {\n return requestFailure(\n \"UNSUPPORTED_MEDIA_TYPE\",\n 415,\n \"unsupported_media_type\",\n );\n }\n const maxBodyBytes = input.maxBodyBytes ?? DEFAULT_MAX_CALLBACK_BODY_BYTES;\n if (\n !Number.isSafeInteger(maxBodyBytes) ||\n maxBodyBytes < 1 ||\n maxBodyBytes > MAX_CALLBACK_BODY_BYTES\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_BODY_LIMIT\",\n `Hub event body limit must be an integer from 1 to ${MAX_CALLBACK_BODY_BYTES} bytes`,\n );\n }\n if (\n new TextEncoder().encode(input.secret).byteLength <\n MIN_CALLBACK_SECRET_BYTES\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_CALLBACK_SECRET\",\n `Hub event callback secret must contain at least ${MIN_CALLBACK_SECRET_BYTES} UTF-8 bytes`,\n );\n }\n const declaredLength = input.request.headers.get(\"content-length\");\n if (\n declaredLength !== null &&\n /^\\d+$/.test(declaredLength) &&\n Number(declaredLength) > maxBodyBytes\n ) {\n return requestFailure(\"PAYLOAD_TOO_LARGE\", 413, \"payload_too_large\");\n }\n const body = await readRequestBody(input.request, maxBodyBytes);\n if (body === null) {\n return requestFailure(\"PAYLOAD_TOO_LARGE\", 413, \"payload_too_large\");\n }\n const signature = await verifyHubEventSignature({\n body,\n signature: input.request.headers.get(\"x-tangle-signature\"),\n secret: input.secret,\n ...(input.toleranceSeconds !== undefined\n ? { toleranceSeconds: input.toleranceSeconds }\n : {}),\n ...(input.now !== undefined ? { now: input.now } : {}),\n });\n if (!signature.valid) {\n return requestFailure(\"INVALID_SIGNATURE\", 401, \"invalid_signature\");\n }\n let delivery: HubEventDelivery;\n try {\n delivery = parseHubEventDelivery(body);\n } catch (error) {\n if (error instanceof HubEventDeliveryError) {\n return requestFailure(\"INVALID_DELIVERY\", 400, \"invalid_delivery\");\n }\n throw error;\n }\n if (input.request.headers.get(\"x-tangle-delivery-id\") !== delivery.runId) {\n return requestFailure(\"DELIVERY_ID_MISMATCH\", 400, \"invalid_delivery\");\n }\n return { ok: true, delivery };\n}\n\n/**\n * Authenticate a Hub event callback against its exact raw request body.\n * The timestamp window rejects captured-request replay, and byte-wise\n * comparison avoids secret-dependent string comparison behavior.\n */\nexport async function verifyHubEventSignature(\n input: VerifyHubEventSignatureInput,\n): Promise<HubEventSignatureResult> {\n if (!input.signature) return { valid: false, reason: \"missing\" };\n if (input.signature.length > MAX_SIGNATURE_HEADER_LENGTH) {\n return { valid: false, reason: \"malformed\" };\n }\n const parsed = parseSignatureHeader(input.signature);\n if (!parsed) return { valid: false, reason: \"malformed\" };\n\n const tolerance = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (\n !Number.isFinite(tolerance) ||\n !Number.isInteger(tolerance) ||\n tolerance < 0 ||\n tolerance > MAX_TOLERANCE_SECONDS\n ) {\n throw new HubEventDeliveryError(\n \"INVALID_TOLERANCE\",\n `Signature tolerance must be an integer from 0 to ${MAX_TOLERANCE_SECONDS} seconds`,\n );\n }\n const nowMs =\n input.now instanceof Date\n ? input.now.getTime()\n : typeof input.now === \"number\"\n ? input.now\n : Date.now();\n if (\n !Number.isFinite(nowMs) ||\n Math.abs(Math.floor(nowMs / 1_000) - parsed.timestamp) > tolerance\n ) {\n return { valid: false, reason: \"stale\" };\n }\n\n const subtle = requireSubtleCrypto();\n const encoder = new TextEncoder();\n const key = await subtle.importKey(\n \"raw\",\n encoder.encode(input.secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const expected = new Uint8Array(\n await subtle.sign(\n \"HMAC\",\n key,\n encoder.encode(`${parsed.timestamp}.${input.body}`),\n ),\n );\n let matched = 0;\n for (const signature of parsed.signatures) {\n matched |= constantTimeEqual(expected, signature);\n }\n return matched === 1\n ? { valid: true, timestamp: parsed.timestamp }\n : { valid: false, reason: \"mismatch\" };\n}\n\nexport function parseHubEventDelivery(\n input: string | unknown,\n): HubEventDelivery {\n let value: unknown = input;\n if (typeof input === \"string\") {\n try {\n value = JSON.parse(input);\n } catch {\n throw new HubEventDeliveryError(\n \"INVALID_JSON\",\n \"Hub event callback body is not valid JSON\",\n );\n }\n }\n if (!isRecord(value)) return invalidDelivery();\n const source = value.source;\n const providerEvent = value.providerEvent;\n if (\n !nonEmptyString(value.subscriptionId) ||\n !nonEmptyString(value.workflowId) ||\n !nonEmptyString(value.runId) ||\n !isRecord(source) ||\n (source.kind !== \"channel\" && source.kind !== \"connection\") ||\n !nonEmptyString(source.id) ||\n !nonEmptyString(source.provider) ||\n !nonEmptyString(source.event) ||\n !isRecord(providerEvent) ||\n !nonEmptyString(providerEvent.provider) ||\n !nonEmptyString(providerEvent.connectionId) ||\n !nonEmptyString(providerEvent.type) ||\n providerEvent.provider !== source.provider ||\n providerEvent.type !== source.event ||\n !Object.hasOwn(providerEvent, \"payload\") ||\n !optionalString(providerEvent.action) ||\n !optionalString(providerEvent.repo) ||\n !optionalString(providerEvent.deliveryId) ||\n !nonEmptyString(value.firedAt) ||\n !Number.isFinite(Date.parse(value.firedAt))\n ) {\n return invalidDelivery();\n }\n return {\n subscriptionId: value.subscriptionId,\n workflowId: value.workflowId,\n runId: value.runId,\n source: {\n kind: source.kind,\n id: source.id,\n provider: source.provider,\n event: source.event,\n },\n providerEvent: {\n provider: providerEvent.provider,\n connectionId: providerEvent.connectionId,\n type: providerEvent.type,\n ...(typeof providerEvent.action === \"string\"\n ? { action: providerEvent.action }\n : {}),\n ...(typeof providerEvent.repo === \"string\"\n ? { repo: providerEvent.repo }\n : {}),\n ...(typeof providerEvent.deliveryId === \"string\"\n ? { deliveryId: providerEvent.deliveryId }\n : {}),\n payload: providerEvent.payload,\n },\n firedAt: value.firedAt,\n };\n}\n\nfunction parseSignatureHeader(\n header: string,\n): { timestamp: number; signatures: Uint8Array[] } | null {\n let timestamp: number | undefined;\n const signatures: Uint8Array[] = [];\n for (const segment of header.split(\",\")) {\n const separator = segment.indexOf(\"=\");\n if (separator <= 0) return null;\n const key = segment.slice(0, separator).trim();\n const value = segment.slice(separator + 1).trim();\n if (key === \"t\") {\n if (timestamp !== undefined || !/^\\d+$/.test(value)) return null;\n const candidate = Number(value);\n if (!Number.isSafeInteger(candidate) || candidate <= 0) return null;\n timestamp = candidate;\n } else if (key === \"v1\") {\n if (\n signatures.length >= MAX_SIGNATURES ||\n value.length !== SHA256_HEX_LENGTH ||\n !/^[0-9a-f]+$/i.test(value)\n ) {\n return null;\n }\n signatures.push(hexToBytes(value));\n }\n }\n return timestamp !== undefined && signatures.length > 0\n ? { timestamp, signatures }\n : null;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let index = 0; index < bytes.length; index += 1) {\n bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);\n }\n return bytes;\n}\n\nfunction constantTimeEqual(expected: Uint8Array, actual: Uint8Array): number {\n let difference = expected.length ^ actual.length;\n const length = Math.max(expected.length, actual.length);\n for (let index = 0; index < length; index += 1) {\n difference |=\n (expected[index % expected.length] ?? 0) ^\n (actual[index % actual.length] ?? 0);\n }\n return difference === 0 ? 1 : 0;\n}\n\nfunction nonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nfunction optionalString(value: unknown): boolean {\n return value === undefined || nonEmptyString(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction invalidDelivery(): never {\n throw new HubEventDeliveryError(\n \"INVALID_PAYLOAD\",\n \"Hub event callback body does not match the delivery contract\",\n );\n}\n\nfunction requireSubtleCrypto(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new HubEventDeliveryError(\n \"CRYPTO_UNAVAILABLE\",\n \"Web Crypto is required for Hub event callback authentication\",\n );\n }\n return subtle;\n}\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nasync function readRequestBody(\n request: Request,\n maxBytes: number,\n): Promise<string | null> {\n const reader = request.body?.getReader();\n if (!reader) return \"\";\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) break;\n total += next.value.byteLength;\n if (total > maxBytes) return null;\n chunks.push(next.value);\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n const body = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(body);\n}\n\nfunction requestFailure(\n code: HubEventRequestFailureCode,\n status: number,\n error: string,\n headers?: HeadersInit,\n): Extract<HubEventRequestResult, { ok: false }> {\n return {\n ok: false,\n code,\n response: Response.json(\n { error },\n {\n status,\n headers: {\n \"cache-control\": \"no-store\",\n ...(headers ? Object.fromEntries(new Headers(headers)) : {}),\n },\n },\n ),\n };\n}\n","import type {\n HubKnowledgeManagementClient,\n KnowledgeSourceSummary,\n} from \"./knowledge-management.js\";\n\n/** Called only after the owner reviews this exact pending effect and clicks\n * Approve. Re-read first: a stale tab cannot approve a substituted operation. */\nexport async function approveKnowledgeSource(input: {\n port: Pick<HubKnowledgeManagementClient, \"get\" | \"refresh\">;\n approvals: Pick<import(\"./client.js\").HubApprovalsClient, \"approve\">;\n source: KnowledgeSourceSummary;\n}): Promise<KnowledgeSourceSummary> {\n const { source, port, approvals } = input;\n if (\n source.status !== \"awaiting-approval\" ||\n !source.approval ||\n !source.refreshRequestId ||\n source.approval.preview.sourceId !== source.id ||\n source.approval.preview.requestId !== source.refreshRequestId\n ) {\n throw new Error(\n \"This source has no reviewable pending action. Reload knowledge.\",\n );\n }\n const current = await port.get(source.id);\n if (\n current.id !== source.id ||\n current.status !== \"awaiting-approval\" ||\n current.refreshRequestId !== source.refreshRequestId ||\n JSON.stringify(current.approval) !== JSON.stringify(source.approval)\n ) {\n throw new Error(\n \"The requested action changed. Reload knowledge and review it again.\",\n );\n }\n let approvalToken: string | undefined;\n try {\n const decision = await approvals.approve(source.approval.id);\n if (\n decision.approval.id !== source.approval.id ||\n decision.approval.actionPath !== source.approval.path ||\n decision.approval.connectionId !== source.approval.preview.connectionId ||\n decision.approval.providerId !== source.approval.preview.provider ||\n // Hub consumes the approval when it issues the one-time capability.\n decision.approval.status !== \"consumed\" ||\n !decision.capabilityToken?.token\n ) {\n throw new Error(\n \"The approval did not return a matching one-time capability. Reload knowledge.\",\n );\n }\n approvalToken = decision.capabilityToken.token;\n return await port.refresh(source.id, {\n requestId: source.refreshRequestId,\n approvalToken,\n });\n } finally {\n // Never put capability tokens in component state, storage, URLs, or logs.\n approvalToken = undefined;\n }\n}\n","import { HubTransport } from \"./client.js\";\nimport { jsonInit } from \"./json-init.js\";\nimport type { HubLineOwnerSendInput, HubLineSendReceipt } from \"./lines.js\";\n\nexport type HubOwnerAskSendInput = Pick<\n HubLineOwnerSendInput,\n \"text\" | \"image\" | \"reply\" | \"idempotencyKey\"\n>;\n\nexport interface HubLineGrantBinding {\n workspaceId: string;\n workspaceAgentId: string;\n}\n\nexport interface HubLineGrant {\n id: string;\n /** Canonical Hub identity that consented this grant; distinct from the app-local owner. */\n ownerUserId?: string;\n purpose?: \"agent\" | \"owner_asks\";\n lineId: string;\n connectionId: string;\n workspaceId: string;\n workspaceAgentId: string;\n agentProfileVersion: string;\n backendSha256: string;\n attachmentId: string | null;\n intakeMode: \"guests\" | \"owner_only\";\n /** \"application\" grants select the app's callback for the owner member instead of attaching. */\n execution: \"backend\" | \"application\" | \"none\";\n applicationOrigin: string | null;\n priorAttachmentId: string | null;\n priorAttachmentActive: boolean;\n monthlyBudgetUsd: number;\n monthlySpentUsd: number;\n}\n\nexport interface HubLineGrantLine {\n id: string;\n connectionId: string;\n transport: \"sms\" | \"imessage\" | \"whatsapp\";\n status: string;\n address: string | null;\n attachment: { id: string; sandboxId: string; status: string } | null;\n}\n\nexport interface HubLineGrantAttachInput {\n workspaceAgentId: string;\n agentProfileVersion: string;\n renewalCode?: string;\n respond: { kind: \"agent\"; backend: Record<string, unknown> };\n}\n\nexport interface HubLineGrantAttachment {\n id: string;\n sandboxId: string;\n status: string;\n members?: Array<{ id: string; role: string }>;\n}\n\nexport interface HubLineGrantThread {\n id: string;\n lineId: string;\n attachmentId: string;\n}\n\nexport interface HubLineGrantMessage {\n id: string;\n threadId: string;\n direction: string;\n text: string | null;\n}\n\n/** The consented owner member on the owner's current attachment. */\nexport interface HubLineGrantMemberApplication {\n lineId: string;\n attachmentId: string;\n memberId: string;\n subjectId: string;\n /** Pass back unchanged as `expectedMemberRevision`. */\n memberRevision: string;\n /** False until the owner has texted the line and Hub recorded consent. */\n eligible: boolean;\n /** Hub-derived; every callback for this grant carries it. */\n binding: string;\n selection: {\n id: string;\n /** True when this grant's callback is the selected application. */\n own: boolean;\n /**\n * Hub's name for the app that answers the owner's texts, shown to the\n * owner in every app they consented on this line: a registered app's\n * name, or \"Another app\" when Hub has none. Absent before Platform named\n * selection holders.\n */\n app?: { name: string };\n /** When the current app started answering. */\n selectedAt?: string;\n /** This app's own callback; never returned for another app. */\n url?: string;\n createdAt?: string;\n } | null;\n}\n\nexport interface HubLineGrantSelectApplicationInput {\n /** The current selection exactly as read. */\n expectedSelectionId: string | null;\n /**\n * Set only when the owner chose to move their texts here from the app shown\n * in `selection.app`: that selection's id, also passed as\n * `expectedSelectionId`. Without it Hub never replaces another app.\n */\n replaceSelectionId?: string;\n expectedMemberRevision: string;\n /** HTTPS callback on the owner-approved application origin. */\n url: string;\n /** Bearer Hub sends to the callback; 32-512 printable ASCII characters. */\n secret: string;\n}\n\nexport interface HubLineGrantApplicationSelection {\n id: string;\n lineId: string;\n attachmentId: string;\n memberId: string;\n subjectId: string;\n status: string;\n application: { url: string; binding: string };\n createdAt: string;\n revokedAt: string | null;\n}\n\nfunction path(binding: HubLineGrantBinding, suffix = \"\"): string {\n if (!binding.workspaceId || !binding.workspaceAgentId)\n throw new Error(\"A workspace and agent are required for a line grant\");\n const query = new URLSearchParams({\n workspaceId: binding.workspaceId,\n workspaceAgentId: binding.workspaceAgentId,\n });\n return `/v1/hub/line-grants/current${suffix}?${query}`;\n}\n\n/** Every call uses HubTransport's authHeaders, so one-use app broker tokens can be minted per request. */\nexport class HubLineGrantsClient extends HubTransport {\n current(binding: HubLineGrantBinding): Promise<HubLineGrant> {\n return this.request(path(binding), { method: \"GET\" });\n }\n\n async line(binding: HubLineGrantBinding): Promise<HubLineGrantLine> {\n return (\n await this.request<{ line: HubLineGrantLine }>(path(binding, \"/line\"), {\n method: \"GET\",\n })\n ).line;\n }\n\n async attach(\n binding: HubLineGrantBinding,\n input: HubLineGrantAttachInput,\n ): Promise<HubLineGrantAttachment> {\n return (\n await this.request<{ attachment: HubLineGrantAttachment }>(\n path(binding, \"/attachment\"),\n jsonInit(\"PUT\", input),\n )\n ).attachment;\n }\n\n detach(binding: HubLineGrantBinding): Promise<{ detached: boolean }> {\n return this.request(path(binding, \"/attachment\"), { method: \"DELETE\" });\n }\n\n async threads(binding: HubLineGrantBinding): Promise<HubLineGrantThread[]> {\n return (\n await this.request<{ threads: HubLineGrantThread[] }>(\n path(binding, \"/threads\"),\n { method: \"GET\" },\n )\n ).threads;\n }\n\n async messages(\n binding: HubLineGrantBinding,\n threadId: string,\n ): Promise<HubLineGrantMessage[]> {\n if (!threadId || threadId.length > 256)\n throw new Error(\"A bounded line thread id is required\");\n return (\n await this.request<{ messages: HubLineGrantMessage[] }>(\n path(binding, `/threads/${encodeURIComponent(threadId)}/messages`),\n { method: \"GET\" },\n )\n ).messages;\n }\n\n memberApplication(\n binding: HubLineGrantBinding,\n ): Promise<HubLineGrantMemberApplication> {\n return this.request(path(binding, \"/member-application\"), {\n method: \"GET\",\n });\n }\n\n /**\n * Route the owner's texts to this app's callback; the incumbent attachment\n * stays. `replaceSelectionId` moves them from another app on the owner's\n * explicit choice.\n */\n async selectApplication(\n binding: HubLineGrantBinding,\n input: HubLineGrantSelectApplicationInput,\n ): Promise<HubLineGrantApplicationSelection> {\n return (\n await this.request<{ selection: HubLineGrantApplicationSelection }>(\n path(binding, \"/member-application\"),\n jsonInit(\"PUT\", input),\n )\n ).selection;\n }\n\n /** Return the owner's texts to the incumbent attachment. */\n async clearApplication(\n binding: HubLineGrantBinding,\n input: { expectedSelectionId: string; expectedMemberRevision: string },\n ): Promise<void> {\n await this.request(\n path(binding, \"/member-application\"),\n jsonInit(\"DELETE\", input),\n );\n }\n\n /** Ask only the verified owner member named by this owner_asks grant. */\n send(\n binding: HubLineGrantBinding,\n input: HubOwnerAskSendInput,\n ): Promise<HubLineSendReceipt> {\n return this.request(path(binding, \"/send\"), jsonInit(\"POST\", input));\n }\n\n /** Only a send created by this same grant is visible. */\n outbox(\n binding: HubLineGrantBinding,\n messageId: string,\n ): Promise<HubLineSendReceipt> {\n if (!/^lmsg_[A-Za-z0-9_-]+$/.test(messageId))\n throw new Error(\"A line message id is required\");\n return this.request(\n path(binding, `/outbox/${encodeURIComponent(messageId)}`),\n { method: \"GET\" },\n );\n }\n\n revoke(\n binding: HubLineGrantBinding,\n expectedGrantId?: string,\n ): Promise<{ revoked: boolean }> {\n const target = path(binding);\n return this.request(\n expectedGrantId === undefined\n ? target\n : `${target}&expectedGrantId=${encodeURIComponent(expectedGrantId)}`,\n { method: \"DELETE\" },\n );\n }\n}\n","import type { HubWorkflowGraphSpec } from \"./workflow-graph-types.js\";\nimport type { HubWorkflowRunSummary } from \"./workflow-run-types.js\";\n\nexport type {\n HubWorkflowCondition,\n HubWorkflowConditionOp,\n HubWorkflowConditionScalar,\n HubWorkflowGraphEdge,\n HubWorkflowGraphJoinRule,\n HubWorkflowGraphNode,\n HubWorkflowGraphSpec,\n} from \"./workflow-graph-types.js\";\n\n// ---------- Workflows ----------\n//\n// The workflow resource on the platform (`/v1/workflows`). YAML is the\n// durable representation; the platform compiles it to the engine's run model.\n// Reachable from inside a sandbox via the same client (TANGLE_API_KEY auth).\n\nexport interface HubWorkflowAction {\n kind: string;\n config: Record<string, unknown>;\n}\n\n/** Inbound-event matcher for a `provider_event` trigger. */\nexport interface HubWorkflowEventFilter {\n event: string;\n action?: string;\n repo?: string;\n}\n\nexport interface HubWorkflowTrigger {\n id: string;\n kind: \"provider_event\" | \"schedule\" | \"webhook\";\n enabled: boolean;\n provider: string | null;\n connectionId: string | null;\n eventFilter: HubWorkflowEventFilter | null;\n cron: string | null;\n timezone: string | null;\n nextFireAt: string | null;\n lastFiredAt: string | null;\n /** Schedule only: the ISO-8601 instant it stops firing; null when unbounded. */\n until: string | null;\n}\n\nexport interface HubWorkflowValidationError {\n path: string;\n message: string;\n /** Machine-readable reason where one is defined, e.g. `schedule_outlives_grant`. */\n code?: string;\n}\n\nexport interface HubWorkflow {\n id: string;\n name: string;\n description: string | null;\n enabled: boolean;\n /** Compiled engine actions (connection refs resolved to ids). */\n actions: HubWorkflowAction[];\n /** The durable YAML this workflow compiled from. */\n definitionYaml: string | null;\n validationErrors: HubWorkflowValidationError[];\n /** Current head revision; null on pre-versioning rows until their next\n * update (they have no revision history to point at yet). */\n headRev?: number | null;\n /** Present on get/create/update detail responses; omitted on list. */\n triggers?: HubWorkflowTrigger[];\n /** Present on the detail response: the trigger fields a manual run must supply,\n * derived from the definition's `${trigger.*}` references (empty when none). */\n manualRunInputs?: HubManualRunInput[];\n /** Present on the get-detail response: the compiled graph topology (null\n * when the definition has no graph topology, or is chain-equivalent —\n * the legacy linear semantics). Omitted on the list projection. */\n graph?: HubWorkflowGraphSpec | null;\n /** Create response only, when the definition has a webhook trigger: the\n * hook delivery URL, plus the plaintext bearer token exactly once at mint\n * (absent when an active token already exists — rotate to re-reveal). */\n hook?: HubWorkflowHookEndpoint;\n /** Present on the list response (latest run, or null if never run); omitted on detail. */\n lastRun?: HubWorkflowRunSummary | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** A trigger field a manual \"Run now\" must supply (derived from the\n * definition's `${trigger.*}` references). `required` is false only when every\n * read is wrapped in a `default(...)`. */\nexport interface HubManualRunInput {\n path: string;\n required: boolean;\n}\n\nexport type HubWorkflowValidateResponse =\n | { valid: true; name: string; actionCount: number; triggerCount: number }\n | { valid: false; errors: HubWorkflowValidationError[] };\n\n/** JSON Schema for the YAML workflow definition. */\nexport type HubWorkflowSchemaResponse = Record<string, unknown>;\n\n// ---------- Workflow definition revisions ----------\n//\n// The append-only history of a workflow's YAML (`GET :id/revisions`,\n// `POST :id/rollback`). Every create/update/rollback appends one rev; rollback\n// restores a prior rev's YAML as a NEW head — history is never rewritten.\n// `GET :id/revisions` lists APPLIED revs only (the history); proposed and\n// rejected revs live on the proposals surface below.\n\nexport type HubWorkflowRevisionSource = \"user\" | \"copilot\" | \"intelligence\";\n\n/** Lifecycle state of a revision. The head rev only ever points at an\n * `applied` revision; `proposed` is a service-token-authored suggestion\n * awaiting an owner decision; `rejected` is a declined proposal (kept for\n * audit). */\nexport type HubWorkflowRevisionStatus = \"applied\" | \"proposed\" | \"rejected\";\n\n/** Revision list projection — attribution + note + status, WITHOUT the YAML body. */\nexport interface HubWorkflowRevisionMeta {\n rev: number;\n createdAt: string;\n createdBy: string;\n source: HubWorkflowRevisionSource;\n note: string | null;\n status: HubWorkflowRevisionStatus;\n}\n\n/** One revision WITH its YAML (and the actions compiled alongside it). */\nexport interface HubWorkflowRevision extends HubWorkflowRevisionMeta {\n yaml: string;\n actions: HubWorkflowAction[];\n}\n\n/** A proposal (proposed or rejected revision) WITH its evidence — what the\n * proposer derived the suggestion from (e.g. health stats), plus\n * `rejectionReason` once declined. */\nexport interface HubWorkflowProposal extends HubWorkflowRevisionMeta {\n evidence: unknown;\n}\n\n// ---------- Workflow templates ----------\n//\n// The curated starter gallery (`GET /v1/workflows/templates`) and one-click\n// instantiate. Static catalog data — no per-user fields.\n\nexport type HubWorkflowTemplateCategory =\n | \"Code Review\"\n | \"Triage\"\n | \"Reports\"\n | \"Multi-agent\";\n\n/** One author-time literal a gallery starter needs the user to supply. Every\n * declared parameter is required; `example` is a valid value that seeds the\n * form placeholder. */\nexport interface HubWorkflowTemplateParameter {\n key: string;\n label: string;\n type: \"string\" | \"integer\";\n help?: string;\n example: string;\n default?: string;\n defaultFrom?: \"native_evaluation\";\n required?: boolean;\n advanced?: boolean;\n}\n\nexport interface HubWorkflowTemplate {\n id: string;\n name: string;\n summary: string;\n category: HubWorkflowTemplateCategory;\n icon: string;\n requiresSandbox: boolean;\n /** Providers the template references (a \"uses GitHub\" hint), sorted. */\n providers: string[];\n parameters: HubWorkflowTemplateParameter[];\n /** The template with parameter tokens rendered to their example values. */\n previewYaml: string;\n setupNotes?: string[];\n}\n\n/** A connection a definition needs, with where to connect it. */\nexport interface HubWorkflowConnectionRequirement {\n provider: string;\n connected: boolean;\n kind: \"integration\" | \"github_app\";\n /** Where to satisfy the requirement (App install flow for `github_app`,\n * integrations page otherwise); null when no target exists. */\n connectUrl: string | null;\n /** Another requirement in the same list that must be satisfied first — a\n * `github_app` install is claimed through the `github` connection, so it is\n * refused while that connection is missing. Null when nothing blocks this\n * requirement. The list is ordered prerequisite-first. */\n prerequisite: { provider: string; kind: \"integration\" | \"github_app\" } | null;\n}\n\n/** Stable identity shared by workflow connection requirements and prerequisite references. */\nexport function workflowConnectionRequirementKey(\n ref: Readonly<Pick<HubWorkflowConnectionRequirement, \"provider\" | \"kind\">>,\n): string {\n return `${ref.kind}:${ref.provider}`;\n}\n\n/**\n * Result of instantiating a template. `created: false` is NOT an error — an\n * actionable continuation listing the connections to satisfy before retrying\n * the same call. Invalid parameters or a compile failure throw `HubSdkError`\n * (400) instead, matching the create route's contract.\n */\nexport type HubWorkflowTemplateInstantiateResult =\n | { created: true; workflow: HubWorkflow }\n | {\n created: false;\n connectionRequirements: HubWorkflowConnectionRequirement[];\n };\n\n// ---------- Webhook hook tokens ----------\n\n/** A workflow's webhook delivery endpoint. `token` is the plaintext bearer —\n * revealed only at mint/rotate time (only the hash is stored). */\nexport interface HubWorkflowHookEndpoint {\n url: string;\n token?: string;\n}\n"],"mappings":"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"}