@oaath/server 0.3.1 → 0.3.3
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/apns.d.ts +2 -2
- package/dist/apns.js +2 -2
- package/dist/{challenge-DmpGSogj.js → challenge-WmeNbyox.js} +2 -2
- package/dist/{challenge-DmpGSogj.js.map → challenge-WmeNbyox.js.map} +1 -1
- package/dist/{inbox-B80EUVht.js → inbox-BKXNtsX3.js} +4 -4
- package/dist/{inbox-B80EUVht.js.map → inbox-BKXNtsX3.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/{interface-DHpwP0wr.d.ts → interface-BVKJY6sm.d.ts} +2 -2
- package/dist/interface-BVKJY6sm.d.ts.map +1 -0
- package/dist/kernel.d.ts +1 -1
- package/dist/kernel.js +3 -3
- package/dist/native.d.ts +2 -2
- package/dist/native.js +4 -4
- package/dist/postgres.d.ts +2 -2
- package/dist/postgres.js +2 -2
- package/dist/{projection-B7IB9irs.d.ts → projection-CrtZYvxz.d.ts} +2 -2
- package/dist/{projection-B7IB9irs.d.ts.map → projection-CrtZYvxz.d.ts.map} +1 -1
- package/dist/{records-BQNDxbPg.js → records-Bh8rOpBa.js} +10 -8
- package/dist/records-Bh8rOpBa.js.map +1 -0
- package/dist/{records-BUvqmp0D.js → records-lPGo4RxO.js} +2 -2
- package/dist/{records-BUvqmp0D.js.map → records-lPGo4RxO.js.map} +1 -1
- package/dist/{service-Cf4f-9KP.js → service-DT0vkKop.js} +4 -4
- package/dist/{service-Cf4f-9KP.js.map → service-DT0vkKop.js.map} +1 -1
- package/dist/{service-J51bOVe6.d.ts → service-Dv3zIiNr.d.ts} +3 -3
- package/dist/{service-J51bOVe6.d.ts.map → service-Dv3zIiNr.d.ts.map} +1 -1
- package/package.json +3 -3
- package/dist/interface-DHpwP0wr.d.ts.map +0 -1
- package/dist/records-BQNDxbPg.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-Cf4f-9KP.js","names":[],"sources":["../src/store/interface.ts","../src/artifact/encrypt.ts","../src/authorization/approved-permission.ts","../src/authorization/owner-signing.ts","../src/native/display.ts","../src/authorization/request.ts","../src/authorization/scope.ts","../src/native/permission-approval.ts","../src/native/projection.ts","../src/native/revocation.ts","../src/revocation/service.ts"],"sourcesContent":["/**\n * Durable relay transaction contract.\n *\n * State model owned by this contract:\n *\n * ```text\n * state and owner authorization request (immutable), decision (terminal),\n * code (one-shot), encrypted artifact (one-shot);\n * revocation request (immutable), phone decision (terminal)\n * persisted evidence one row per record, one current schema version\n * resource occupied? yes: a decision row occupies its request; a consumed\n * code and a claimed artifact are terminal\n * retry positively safe? recover committed evidence before any new transition\n * transitions request -> decision(approved|rejected) once;\n * code: issued -> consumed once;\n * artifact: sealed -> claimed once;\n * revocation: pending -> approved|rejected once, no code;\n * expired undecided custody may be replaced under grant lock\n * crash/reload every transition is decided inside one transaction on a\n * row locked for update; a crash leaves the prior state\n * cleanup owner the caller rolls back; the store releases its handle\n * ```\n *\n * Every `lock*` read must acquire an exclusive row lock for the life of the\n * transaction (`SELECT ... FOR UPDATE` semantics). Every one-shot writer\n * (`consumeAuthorizationCode`, `claimEncryptedArtifact`) must additionally\n * guard on the terminal column being null and report whether *this* call\n * performed the transition.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport type { RevocationDecisionRecord, RevocationRequestRecord } from \"../revocation/records.js\";\nimport type {\n AuthorizationCodeRecord,\n AuthorizationDecisionRecord,\n AuthorizationRequestRecord,\n CapabilityInvalidationRecord,\n EncryptedArtifactRecord,\n} from \"./records.js\";\n\n/** Read-only discovery metadata. The existing request/decision records own pending state. */\nexport interface PendingOwnerRequest {\n readonly operationId: string;\n readonly ownerSubject: string;\n readonly expiresAt: number;\n}\n\nexport interface RelayTransaction {\n /** Unexpired and undecided requests, ordered by expiry then ASCII operation ID. No reservation. */\n listPendingOwnerRequests(\n ownerSubject: string,\n now: number,\n limit: number,\n ): Promise<readonly PendingOwnerRequest[]>;\n /** Lock the original authorization request first to serialize grant/chain enqueue. */\n lockLatestRevocationRequest(\n grantId: string,\n chainId: number,\n ): Promise<RevocationRequestRecord | undefined>;\n /** Lock the immutable request before reading or writing its terminal decision. */\n lockRevocationRequest(operationId: string): Promise<RevocationRequestRecord | undefined>;\n insertRevocationRequest(record: RevocationRequestRecord): Promise<boolean>;\n lockRevocationDecision(operationId: string): Promise<RevocationDecisionRecord | undefined>;\n insertRevocationDecision(record: RevocationDecisionRecord): Promise<boolean>;\n\n lockAuthorizationRequest(requestId: string): Promise<AuthorizationRequestRecord | undefined>;\n /** Returns false when the identifier already exists. */\n insertAuthorizationRequest(record: AuthorizationRequestRecord): Promise<boolean>;\n\n lockAuthorizationDecision(requestId: string): Promise<AuthorizationDecisionRecord | undefined>;\n /** Returns false when the request was already decided. */\n insertAuthorizationDecision(record: AuthorizationDecisionRecord): Promise<boolean>;\n\n lockAuthorizationCode(codeHash: string): Promise<AuthorizationCodeRecord | undefined>;\n insertAuthorizationCode(record: AuthorizationCodeRecord): Promise<boolean>;\n /** Returns true only when this call set `consumed_at`. */\n consumeAuthorizationCode(codeHash: string, consumedAt: number): Promise<boolean>;\n\n lockCapabilityInvalidation(grantId: string): Promise<CapabilityInvalidationRecord | undefined>;\n /** Returns false when the Grant's capability is already invalidated. */\n insertCapabilityInvalidation(record: CapabilityInvalidationRecord): Promise<boolean>;\n\n lockEncryptedArtifact(artifactId: string): Promise<EncryptedArtifactRecord | undefined>;\n /** Internal authority lookup; returns retained evidence even after client claim. Never releases it. */\n lockEncryptedArtifactByRequestId(requestId: string): Promise<EncryptedArtifactRecord | undefined>;\n insertEncryptedArtifact(record: EncryptedArtifactRecord): Promise<boolean>;\n /** Returns true only when this call set `claimed_at`. */\n claimEncryptedArtifact(artifactId: string, claimedAt: number): Promise<boolean>;\n\n /** Throws `relay_state_ambiguous` when the outcome cannot be proven. */\n commit(): Promise<void>;\n /** Never throws; rollback failure is a suppressed diagnostic. */\n rollback(): Promise<void>;\n}\n\nexport interface RelayStore {\n begin(): Promise<RelayTransaction>;\n close(): Promise<void>;\n}\n\n/**\n * Runs one transition inside one transaction. The body commits, or the\n * transaction is rolled back and the canonical failure is preserved.\n */\nexport async function withRelayTransaction<Value>(\n store: RelayStore,\n run: (transaction: RelayTransaction) => Promise<Value>,\n): Promise<Value> {\n const transaction = await store.begin();\n let result: Value;\n try {\n result = await run(transaction);\n } catch (error) {\n await transaction.rollback();\n throw error;\n }\n await transaction.commit();\n return result;\n}\n","/**\n * KMS sealing boundary. Plaintext never reaches the store.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nconst KMS_UNAVAILABLE = \"relay_kms_unavailable\" as const;\n\n/**\n * Encrypts an approval artifact and returns the opaque reference to store.\n * A port that echoes plaintext is rejected: the store must never hold it.\n */\nexport async function sealArtifact(kms: RelayKms, plaintext: string): Promise<string> {\n let sealed: unknown;\n try {\n sealed = await kms.encrypt(plaintext);\n } catch {\n return relayFailure(KMS_UNAVAILABLE, \"KMS encrypt failed\");\n }\n const ciphertextRef = boundedText(\n sealed,\n RELAY_LIMITS.ciphertextRef,\n \"KMS ciphertext reference\",\n KMS_UNAVAILABLE,\n );\n if (ciphertextRef.includes(plaintext)) {\n return relayFailure(KMS_UNAVAILABLE, \"KMS reference contains plaintext\");\n }\n return ciphertextRef;\n}\n\n/**\n * Opens retained ciphertext for an authorized internal reader. Client release\n * calls this only after claim commits; authority verification releases no bytes.\n */\nexport async function openArtifact(kms: RelayKms, ciphertextRef: string): Promise<string> {\n let opened: unknown;\n try {\n opened = await kms.decrypt(ciphertextRef);\n } catch {\n return relayFailure(KMS_UNAVAILABLE, \"KMS decrypt failed\");\n }\n return boundedText(opened, RELAY_LIMITS.artifactPlaintext, \"KMS plaintext\", KMS_UNAVAILABLE);\n}\n","/** Retained service-approved policy, independent of OAuth claim or execution expiry. */\nimport {\n applyPermissionDecision,\n createGrantFromPermissionRequest,\n type PermissionRequest,\n parsePermissionDecision,\n} from \"@oaath/protocol\";\nimport { openArtifact } from \"../artifact/encrypt.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayTransaction } from \"../store/interface.js\";\nimport type { AuthorizationDecisionRecord, AuthorizationRequestRecord } from \"../store/records.js\";\n\n/**\n * The same protocol approval meaning at admission and after durable recovery.\n * Kernel capability verification belongs to the SDK; this owner checks the\n * decision's request binding, policy attenuation and reported decision time.\n * Evaluate at that time so a retained approval remains readable for revocation\n * after its execution or OAuth claim window has closed.\n */\nexport function parseApprovedPermission(\n plaintext: string,\n permissionRequest: Readonly<PermissionRequest>,\n relayDecidedAt: number,\n) {\n const value = JSON.parse(plaintext) as unknown;\n const decisionValue =\n value !== null && typeof value === \"object\" && \"installApproval\" in value\n ? (({ installApproval: _install, ...permission }) => permission)(value)\n : value;\n const permission = parsePermissionDecision(decisionValue);\n if (permission.kind !== \"approve\" || permission.decidedAt > Math.floor(relayDecidedAt / 1_000))\n throw new Error(\"permission artifact is not an approved decision at the relay decision time\");\n const applied = applyPermissionDecision({\n request: permissionRequest,\n grant: createGrantFromPermissionRequest(permissionRequest),\n observation: { status: \"available\", decision: permission },\n evaluatedAt: permission.decidedAt,\n });\n if (applied.status !== \"applied\" || applied.grant.state !== \"approved\")\n throw new Error(\"permission artifact does not approve this request\");\n return { permission, plaintext };\n}\n\n/** Kernel capability verification remains the SDK preparation owner's responsibility. */\nexport async function readApprovedPermission(\n transaction: RelayTransaction,\n kms: RelayKms,\n request: AuthorizationRequestRecord,\n decision: AuthorizationDecisionRecord,\n permissionRequest: Readonly<PermissionRequest>,\n) {\n try {\n const artifact = await transaction.lockEncryptedArtifactByRequestId(request.requestId);\n if (\n !artifact ||\n artifact.requestId !== request.requestId ||\n artifact.clientId !== request.clientId ||\n artifact.createdAt !== decision.decidedAt\n )\n return null;\n const plaintext = await openArtifact(kms, artifact.ciphertextRef);\n return parseApprovedPermission(plaintext, permissionRequest, decision.decidedAt);\n } catch {\n return null;\n }\n}\n","/**\n * Pure authorization of one returned Kernel owner-signing artifact.\n *\n * The protocol owns both exact wire shapes. This server owner adds only the\n * release policy: the request must use the first-runtime P-256 credential, the\n * artifact must be its one canonical JSON representation, its request hash must\n * bind the exact request, and its compact low-S signature must verify the exact\n * Kernel digest. It allocates and persists nothing.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { p256 } from \"@noble/curves/nist.js\";\nimport { hexToBytes } from \"@noble/hashes/utils.js\";\nimport {\n hashKernelRevocationSigningRequest,\n hashOwnerSigningRequest,\n type KernelRevocationSigningRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n parseOwnerSigningArtifact,\n serializeOwnerSigningArtifact,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nconst INVALID = \"relay_request_invalid\" as const;\n\n/**\n * Returns the canonical artifact plaintext only after every request, key,\n * request-hash, and signature binding agrees.\n */\nexport function verifyKernelV4ReplayableInstallOwnerSigningArtifact(\n requestValue: unknown,\n artifactPlaintext: unknown,\n): string {\n try {\n const request = parseKernelReplayableInstallOwnerSigningRequest(requestValue);\n if (request.signer.ownerCredential.kind !== \"p256\") throw new TypeError();\n\n return verifyArtifact(\n hashOwnerSigningRequest(request),\n request.expectedDigest,\n request.signer.ownerCredential.publicKey,\n artifactPlaintext,\n );\n } catch {\n return relayFailure(INVALID, \"Kernel owner signing artifact is invalid\");\n }\n}\n\n/** Stored signing request has already crossed the durable record boundary. */\nexport function verifyKernelV4RevocationOwnerSigningArtifact(\n request: Readonly<KernelRevocationSigningRequest>,\n artifactPlaintext: unknown,\n): string {\n try {\n if (request.install.signer.ownerCredential.kind !== \"p256\") throw new TypeError();\n return verifyArtifact(\n hashKernelRevocationSigningRequest(request),\n request.expectedDigest,\n request.install.signer.ownerCredential.publicKey,\n artifactPlaintext,\n );\n } catch {\n return relayFailure(INVALID, \"Kernel owner signing artifact is invalid\");\n }\n}\nfunction verifyArtifact(\n requestHash: string,\n digest: string,\n publicKey: string,\n artifactPlaintext: unknown,\n): string {\n const received = boundedText(\n artifactPlaintext,\n RELAY_LIMITS.artifactPlaintext,\n \"owner signing artifact\",\n INVALID,\n );\n const artifact = parseOwnerSigningArtifact(JSON.parse(received) as unknown);\n const canonical = serializeOwnerSigningArtifact(artifact);\n if (received !== canonical) throw new TypeError();\n if (artifact.requestHash !== requestHash) throw new TypeError();\n\n const verified = p256.verify(\n hexToBytes(artifact.signature.slice(2)),\n hexToBytes(digest.slice(2)),\n hexToBytes(publicKey.slice(2)),\n { format: \"compact\", lowS: true, prehash: false },\n );\n if (!verified) throw new TypeError();\n return canonical;\n}\n","import { sha256Base64Url } from \"../authorization/challenge.js\";\n\n/** Bounded base64url match code length. 48 bits is plenty to compare by eye. */\nexport const NATIVE_DISPLAY_PAYLOAD_LENGTH = 8;\nexport const NATIVE_DISPLAY_DOMAIN = \"oaath.native-display/v1:\";\n\n/** One non-secret comparison code for the requesting app, phone, inbox, and push. */\nexport async function ownerPhoneDisplayPayload(\n ownerSubject: string,\n operationId: string,\n): Promise<string> {\n const digest = await sha256Base64Url(`${NATIVE_DISPLAY_DOMAIN}${ownerSubject}:${operationId}`);\n return digest.slice(0, NATIVE_DISPLAY_PAYLOAD_LENGTH);\n}\n","/**\n * Create and read an authorization request.\n *\n * The request record snapshots the resolved approving device separately from\n * the requesting member. It is immutable once created; reads and decisions never\n * re-resolve the owner. A refused route creates no row. After a crash, the durable\n * route remains authoritative. Creation does not automatically retry writes.\n * Its decision is a separate terminal record, so \"was this decided?\" has one owner.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { exactRecord } from \"@oaath/protocol\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { ownerPhoneDisplayPayload } from \"../native/display.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayStore, RelayTransaction } from \"../store/interface.js\";\nimport { withRelayTransaction } from \"../store/interface.js\";\nimport {\n type AuthorizationDecisionOutcome,\n type AuthorizationOwnerRoute,\n type AuthorizationRequestRecord,\n canonicalIdentifier,\n OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n} from \"../store/records.js\";\nimport { isCodeChallengeS256, randomIdentifier } from \"./challenge.js\";\n\n/** Resolves once at creation; existing requests never follow later routing changes. */\nexport interface RelayOwnerRouting {\n resolveOwner(\n caller: Readonly<RelayCaller>,\n request: Readonly<{ requestId: string; requestedScope: string }>,\n ): Promise<Readonly<AuthorizationOwnerRoute> | null>;\n}\n\nexport interface CreateAuthorizationRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `client` caller; it owns `clientId` and `subject`. */\n readonly caller: RelayCaller;\n readonly ownerRouting: RelayOwnerRouting;\n readonly redirectUri: string;\n readonly codeChallenge: string;\n readonly requestedScope: string;\n readonly requestTtlMs: number;\n}\n\nexport interface CreatedAuthorizationRequest {\n /** Non-secret comparison code shown by the approving phone. */\n readonly matchCode: string;\n readonly requestId: string;\n readonly expiresAt: number;\n}\n\nexport interface AuthorizationState {\n readonly requestId: string;\n readonly clientId: string;\n readonly redirectUri: string;\n readonly requestedScope: string;\n readonly expiresAt: number;\n readonly expired: boolean;\n readonly decision: Readonly<{\n outcome: AuthorizationDecisionOutcome;\n decidedAt: number;\n }> | null;\n}\n\nexport async function createAuthorizationRequest(\n input: CreateAuthorizationRequestInput,\n): Promise<CreatedAuthorizationRequest> {\n if (!isCodeChallengeS256(input.codeChallenge)) {\n return relayFailure(\"relay_request_invalid\", \"codeChallenge must be an S256 challenge\");\n }\n // The deployment owns client registration, so only a redirect URI it bound to\n // this client may receive an authorization code.\n if (!input.caller.redirectUris.includes(input.redirectUri)) {\n return relayFailure(\"relay_forbidden\", \"redirectUri is not registered for this client\");\n }\n const requestId = randomIdentifier();\n const resolved = await input.ownerRouting.resolveOwner(\n input.caller,\n Object.freeze({ requestId, requestedScope: input.requestedScope }),\n );\n if (resolved === null) return relayFailure(\"relay_forbidden\", \"no approving device is assigned\");\n const owner = exactRecord(\n resolved,\n [\"ownerDeviceId\", \"ownerSubject\"],\n \"owner route\",\n new WeakSet(),\n (message) => relayFailure(\"relay_internal\", message),\n );\n const ownerDeviceId = canonicalIdentifier(owner.ownerDeviceId, \"ownerDeviceId\", \"relay_internal\");\n const ownerSubject = canonicalIdentifier(owner.ownerSubject, \"ownerSubject\", \"relay_internal\");\n const createdAt = relayNow(input.clock);\n const record: AuthorizationRequestRecord = Object.freeze({\n version: OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n requestId,\n clientId: input.caller.clientId,\n subject: input.caller.subject,\n ownerDeviceId,\n ownerSubject,\n organizationAudience: input.caller.organizationAudience,\n redirectUri: input.redirectUri,\n codeChallenge: input.codeChallenge,\n requestedScope: input.requestedScope,\n createdAt,\n expiresAt: createdAt + input.requestTtlMs,\n });\n const matchCode = await ownerPhoneDisplayPayload(ownerSubject, requestId);\n await withRelayTransaction(input.store, async (transaction) => {\n if (!(await transaction.insertAuthorizationRequest(record))) {\n // 256 bits of CSPRNG output collided, or the store contradicts itself.\n return relayFailure(\"relay_internal\", \"authorization request identifier is not unique\");\n }\n });\n return Object.freeze({ requestId: record.requestId, expiresAt: record.expiresAt, matchCode });\n}\n\n/**\n * Row-locked read of the request and its decision. Read paths take the same\n * exclusive lock as transitions.\n *\n * ponytail: one lock class for reads and writes; add a shared read mode only if\n * approval-screen traffic measurably contends.\n */\nexport async function readAuthorizationState(\n transaction: RelayTransaction,\n requestId: string,\n now: number,\n match: (request: AuthorizationRequestRecord) => boolean,\n): Promise<AuthorizationState> {\n const request = await transaction.lockAuthorizationRequest(requestId);\n // A caller that is not entitled to this request learns only that it is absent.\n if (!request || !match(request)) {\n return relayFailure(\"relay_not_found\", \"authorization request does not exist\");\n }\n const decision = await transaction.lockAuthorizationDecision(requestId);\n return Object.freeze({\n requestId: request.requestId,\n clientId: request.clientId,\n redirectUri: request.redirectUri,\n requestedScope: request.requestedScope,\n expiresAt: request.expiresAt,\n expired: now >= request.expiresAt,\n decision: decision\n ? Object.freeze({ outcome: decision.outcome, decidedAt: decision.decidedAt })\n : null,\n });\n}\n\nexport interface FetchAuthorizationRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `owner` caller; only the bound subject may read the request. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n}\n\n/** Read for the approving owner. */\nexport function fetchAuthorizationRequest(\n input: FetchAuthorizationRequestInput,\n): Promise<AuthorizationState> {\n const now = relayNow(input.clock);\n return withRelayTransaction(input.store, (transaction) =>\n readAuthorizationState(\n transaction,\n input.requestId,\n now,\n (request) => request.ownerSubject === input.caller.subject,\n ),\n );\n}\n","/**\n * Authoritative classification of one immutable stored authorization scope.\n *\n * The current server may approve an exact protocol PermissionRequest or the\n * one exact Kernel replayable-install request backed by a P-256 owner. Other\n * closed owner-signing requests are captured for projection and hashing but\n * remain reject-only. Unknown, malformed, and legacy scopes stay readable and\n * rejectable, but never authorize artifact creation.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport {\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningRequest,\n type PermissionRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n parseOwnerSigningRequest,\n parsePermissionRequest,\n} from \"@oaath/protocol\";\n\nexport type StoredAuthorizationScope =\n | Readonly<{\n kind: \"permission-request\";\n decision: \"approve-or-reject\";\n request: Readonly<PermissionRequest>;\n }>\n | Readonly<{\n kind: \"kernel-owner-signing-request\";\n decision: \"approve-or-reject\";\n request: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n }>\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"reject-only\";\n request: Readonly<OwnerSigningRequest>;\n }>\n | Readonly<{ kind: \"unverified\"; decision: \"reject-only\" }>;\n\nexport function classifyStoredAuthorizationScope(\n requestedScope: string,\n requestId: string,\n): StoredAuthorizationScope {\n try {\n const parsed: unknown = JSON.parse(requestedScope);\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return Object.freeze({ kind: \"unverified\", decision: \"reject-only\" });\n }\n try {\n return Object.freeze({\n kind: \"permission-request\",\n decision: \"approve-or-reject\",\n request: parsePermissionRequest({ ...parsed, requestId }),\n });\n } catch {\n const request = parseOwnerSigningRequest(parsed);\n try {\n const kernelRequest = parseKernelReplayableInstallOwnerSigningRequest(request);\n if (kernelRequest.signer.ownerCredential.kind === \"p256\") {\n return Object.freeze({\n kind: \"kernel-owner-signing-request\",\n decision: \"approve-or-reject\",\n request: kernelRequest,\n });\n }\n } catch {\n // The generic closed request remains readable but reject-only.\n }\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"reject-only\",\n request,\n });\n }\n } catch {\n return Object.freeze({ kind: \"unverified\", decision: \"reject-only\" });\n }\n}\n","/** Canonical permission preparation supplied by the deployment's Kernel SDK integration. */\nimport {\n captureRecord,\n hashOwnerSigningRequest,\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningArtifact,\n type PermissionRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n sameOwnerCredentialProfile,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nexport interface PreparedOwnerPhonePermissionApproval {\n readonly signingRequest: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n /** Verifies and serializes the SDK's decision plus install approval; submits nothing. */\n complete(artifact: Readonly<OwnerSigningArtifact>, decidedAt: number): Promise<string>;\n}\n\nexport interface OwnerPhonePermissionApprovals {\n /** Recreate from the stored request and the deployment-owned install nonce. */\n prepare(\n request: Readonly<PermissionRequest>,\n ): Promise<Readonly<PreparedOwnerPhonePermissionApproval>>;\n}\n\nexport async function prepareOwnerPhonePermissionApproval(\n provider: OwnerPhonePermissionApprovals | undefined,\n request: Readonly<PermissionRequest>,\n): Promise<Readonly<PreparedOwnerPhonePermissionApproval>> {\n if (!provider)\n return relayFailure(\"relay_request_invalid\", \"phone permission signing is not configured\");\n const invalid = () =>\n relayFailure(\"relay_request_invalid\", \"phone permission preparation is invalid\");\n const result = captureRecord(\n await provider.prepare(request),\n \"phone permission preparation\",\n new WeakSet(),\n invalid,\n );\n const signingRequest = parseKernelReplayableInstallOwnerSigningRequest(result.signingRequest);\n if (\n signingRequest.signer.ownerCredential.kind !== \"p256\" ||\n !sameOwnerCredentialProfile(\n signingRequest.signer.ownerCredential,\n request.logicalAccount.ownerCredential,\n ) ||\n typeof result.complete !== \"function\"\n )\n return invalid();\n const complete = result.complete as PreparedOwnerPhonePermissionApproval[\"complete\"];\n const requestHash = hashOwnerSigningRequest(signingRequest);\n return Object.freeze({\n signingRequest,\n async complete(artifact: Readonly<OwnerSigningArtifact>, decidedAt: number) {\n if (artifact.requestHash !== requestHash) return invalid();\n return boundedText(\n await complete(artifact, decidedAt),\n RELAY_LIMITS.artifactPlaintext,\n \"permission artifact\",\n \"relay_request_invalid\",\n );\n },\n });\n}\n","/**\n * EXPERIMENTAL PREVIEW — authenticated owner-phone consent projection.\n *\n * This is a preview surface reached through `@oaath/server/native` and the\n * relay's preview HTTP routes (`GET /native/projections/{operationId}`). It has\n * no stability guarantee and no production qualification: real iOS, Apple\n * provisioning, Secure Enclave, and hosted operations are later work.\n *\n * What it owns: turning one stored authorization request into the projection\n * the owner's phone renders before deciding. It owns nothing about deciding;\n * the relay's decision use case stays the only decision owner.\n *\n * Two very different surfaces share this file, and only one of them is opaque:\n *\n * - The **push** projection (`operationId`, `displayPayload`, `expiresAt`)\n * transits Apple inside an APNs payload, so it stays opaque by design: no\n * permission, scope, client, chain, or account detail may ride it. The APNs\n * sender enforces that subset exactly.\n * - The **consent** projection returned here travels only the authenticated\n * relay → owner channel, so it deliberately carries the full authorization\n * request: the requesting client identity and the requested scope. The owner\n * must see exactly the authority they grant before approving.\n *\n * `displayPayload` is not a secret and not authority: it is a deterministic\n * digest of the request and its bound subject, so the owner can check that the\n * code on the phone is the code the browser shows. Holding it authorizes\n * nothing — deciding still requires the authenticated bound owner.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport {\n hashOwnerSigningRequest,\n isKernelExistingAccountProfile,\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningRequest,\n type PermissionRequest,\n type WorkspaceAccountContext,\n} from \"@oaath/protocol\";\nimport { sha256Base64Url } from \"../authorization/challenge.js\";\nimport { type AuthorizationState, fetchAuthorizationRequest } from \"../authorization/request.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport type { RelayClock } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport {\n NATIVE_DISPLAY_DOMAIN,\n NATIVE_DISPLAY_PAYLOAD_LENGTH,\n ownerPhoneDisplayPayload,\n} from \"./display.js\";\nimport {\n type OwnerPhonePermissionApprovals,\n prepareOwnerPhonePermissionApproval,\n} from \"./permission-approval.js\";\nimport type { OwnerPhoneRevocationScopeProjection } from \"./revocation.js\";\n\n/** Versioned consent envelope; the Swift decoder pins this exact value. */\nexport const OAATH_NATIVE_PROJECTION_VERSION = \"oaath.native-projection/v7\" as const;\n\n/**\n * Whether the phone may offer approval for one projected scope. Permission\n * requests and exact Kernel replayable-install P-256 signing are approvable;\n * every other owner-signing, unknown, and malformed scope remains reject-only.\n */\nexport type OwnerPhoneDecisionCapability = \"approve-or-reject\" | \"reject-only\";\n\n/** One credential identity as the owner reviews it: public material only. */\nexport type OwnerPhoneCredentialProjection =\n | Readonly<{ kind: \"ecdsa\"; address: string }>\n | Readonly<{ kind: \"p256\"; publicKey: string }>\n | Readonly<{ kind: \"webauthn\"; publicKey: string; authenticatorIdHash: string }>;\n\n/**\n * The requested scope as the phone renders it. When the stored scope parses as\n * an `@oaath/protocol` permission request, every fact that determines who\n * receives authority, over which account, and under what limits is projected\n * structurally. A valid owner-signing request is also projected in full with\n * its protocol-owned hash; only exact Kernel replayable-install P-256 signing\n * is approvable. Anything else is returned as explicitly labeled raw text.\n */\nexport type OwnerPhonePermissionScopeProjection = Readonly<{\n kind: \"permission-request\";\n decision: \"approve-or-reject\";\n /** Explicit request context, independent of later account selection. */\n context: Readonly<WorkspaceAccountContext>;\n /** The application identity the signed request binds, verbatim. */\n application: Readonly<{\n applicationId: string;\n clientId: string;\n origin: string;\n /** Opaque device identity, fingerprinted: raw ids mean nothing to an owner. */\n deviceFingerprint: string;\n }>;\n /** The logical account this authority acts for. */\n account: Readonly<{\n accountIndex: string;\n kernelVersion: string;\n factoryRoute: string;\n entryPointVersion: string;\n ownerCredential: OwnerPhoneCredentialProjection;\n }>;\n /** The session credential that receives the scoped authority. */\n operatorCredential: OwnerPhoneCredentialProjection;\n /**\n * Where the session key lives: null for frontend custody (the page's\n * own non-extractable key), or the remote trust model the owner is\n * asked to approve — the request hash binds it, so approving this\n * display approves exactly this custody.\n */\n sessionSigner: Readonly<{\n mode: \"application_backend\" | \"oaath_hosted\";\n providerId: string;\n }> | null;\n chainScope: \"all\";\n calls: readonly Readonly<{\n target: string;\n selector: string;\n valueLimit: string;\n argumentEquals: readonly Readonly<{ index: number; value: string }>[];\n }>[];\n requestedAt: number;\n /** The permission request's own expiry, as the requesting client stated it. */\n expiresAt: number;\n /** The policy's on-chain validity window; inclusive, in Unix seconds. */\n policyValidAfter: number;\n policyValidUntil: number | null;\n perChainOperationLimit: number;\n /** Window after which the count refills, or null for a lifetime cap. */\n perChainOperationIntervalSeconds: number | null;\n}>;\n\nexport type OwnerPhoneScopeProjection =\n | OwnerPhonePermissionScopeProjection\n | OwnerPhoneRevocationScopeProjection\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"approve-or-reject\";\n /** Canonical hash binding every captured request fact. */\n requestHash: `0x${string}`;\n /** Exact Kernel request independently refined by the protocol owner. */\n request: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n }>\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"reject-only\";\n /** Canonical hash binding every captured request fact. */\n requestHash: `0x${string}`;\n /** Full immutable protocol request for independent device review. */\n request: Readonly<OwnerSigningRequest>;\n }>\n | Readonly<{ kind: \"raw\"; decision: \"reject-only\"; text: string }>;\n\nexport interface OwnerPhoneRequestProjection {\n readonly version: typeof OAATH_NATIVE_PROJECTION_VERSION;\n /**\n * Stable across every projection of the same request, and the key the\n * approve/reject saga is keyed by. It is the relay's own opaque request\n * identifier: one authoritative id, no second mapping table to lose.\n */\n readonly operationId: string;\n /** Bounded opaque match code, the only variable an APNs payload may carry. */\n readonly displayPayload: string;\n /** The stored request's expiry, in epoch milliseconds. */\n readonly expiresAt: number;\n /** The requesting client, exactly as the stored request binds it. */\n readonly client: Readonly<{ clientId: string; redirectUri: string | null }>;\n readonly scope: OwnerPhoneScopeProjection;\n}\n\n/**\n * The opaque subset of the projection that may transit Apple inside an APNs\n * payload. The sender exact-captures precisely these three fields, so consent\n * detail can never ride a notification.\n */\nexport type OwnerPhonePushProjection = Pick<\n OwnerPhoneRequestProjection,\n \"operationId\" | \"displayPayload\" | \"expiresAt\"\n>;\n\nexport interface ProjectOwnerPhoneRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `owner` caller; only the bound subject may be projected. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n}\n\n/**\n * The stored scope is the requesting client's own JSON permission scope (the\n * SDK serializes a permission request without its `requestId`; the relay's\n * request id is the binding). An unparseable scope is not a failure: the owner\n * still gets the raw text to review, never a silent omission.\n */\nfunction projectCredential(\n credential: Readonly<{\n kind: \"ecdsa\" | \"p256\" | \"webauthn\";\n address?: string;\n publicKey?: string;\n authenticatorIdHash?: string;\n }>,\n): OwnerPhoneCredentialProjection {\n if (credential.kind === \"ecdsa\") {\n return Object.freeze({ kind: \"ecdsa\", address: credential.address ?? \"\" });\n }\n if (credential.kind === \"p256\") {\n return Object.freeze({ kind: \"p256\", publicKey: credential.publicKey ?? \"\" });\n }\n return Object.freeze({\n kind: \"webauthn\",\n publicKey: credential.publicKey ?? \"\",\n authenticatorIdHash: credential.authenticatorIdHash ?? \"\",\n });\n}\n\n/** One owner for permission display facts in both grant and removal consent. */\nexport async function projectPermissionConsent(\n request: Readonly<PermissionRequest>,\n): Promise<OwnerPhonePermissionScopeProjection> {\n if (isKernelExistingAccountProfile(request.logicalAccount))\n return relayFailure(\"relay_request_invalid\", \"phone consent requires a Kernel v4 account\");\n return Object.freeze({\n kind: \"permission-request\",\n decision: \"approve-or-reject\",\n context: request.context,\n application: Object.freeze({\n applicationId: request.application.applicationId,\n clientId: request.application.clientId,\n origin: request.application.origin,\n deviceFingerprint: (\n await sha256Base64Url(`${NATIVE_DISPLAY_DOMAIN}device:${request.application.deviceId}`)\n ).slice(0, NATIVE_DISPLAY_PAYLOAD_LENGTH),\n }),\n account: Object.freeze({\n accountIndex: request.logicalAccount.accountIndex,\n kernelVersion: request.logicalAccount.kernelVersion,\n factoryRoute: request.logicalAccount.factoryRoute,\n entryPointVersion: request.logicalAccount.entryPoint.version,\n ownerCredential: projectCredential(request.logicalAccount.ownerCredential),\n }),\n operatorCredential: projectCredential(request.operatorCredential),\n sessionSigner:\n request.sessionSigner === null\n ? null\n : Object.freeze({\n mode: request.sessionSigner.mode,\n providerId: request.sessionSigner.providerId,\n }),\n chainScope: request.chainScope,\n calls: Object.freeze(\n request.policy.calls.map((call) =>\n Object.freeze({\n target: call.target,\n selector: call.selector,\n valueLimit: call.valueLimit,\n argumentEquals: Object.freeze(\n call.argumentEquals.map((rule) =>\n Object.freeze({ index: rule.index, value: rule.value }),\n ),\n ),\n }),\n ),\n ),\n requestedAt: request.requestedAt,\n expiresAt: request.expiresAt,\n policyValidAfter: request.policy.validAfter,\n policyValidUntil: request.policy.validUntil,\n perChainOperationLimit: request.policy.perChainOperationLimit.count,\n perChainOperationIntervalSeconds: request.policy.perChainOperationLimit.intervalSeconds,\n });\n}\n\nexport async function projectOwnerPhoneScope(\n requestedScope: string,\n operationId: string,\n): Promise<OwnerPhoneScopeProjection> {\n try {\n const classified = classifyStoredAuthorizationScope(requestedScope, operationId);\n if (classified.kind === \"permission-request\") {\n return projectPermissionConsent(classified.request);\n }\n if (classified.kind === \"kernel-owner-signing-request\") {\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"approve-or-reject\",\n requestHash: hashOwnerSigningRequest(classified.request),\n request: classified.request,\n });\n }\n if (classified.kind === \"owner-signing-request\") {\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"reject-only\",\n requestHash: hashOwnerSigningRequest(classified.request),\n request: classified.request,\n });\n }\n return Object.freeze({ kind: \"raw\", decision: \"reject-only\", text: requestedScope });\n } catch {\n return Object.freeze({ kind: \"raw\", decision: \"reject-only\", text: requestedScope });\n }\n}\n\n/**\n * Projects a pending request for its bound owner. An expired or already decided\n * request is not projectable: there is nothing left to approve, so nothing is\n * ever pushed or rendered for it.\n */\nasync function pendingOwnerRequest(\n input: ProjectOwnerPhoneRequestInput,\n): Promise<AuthorizationState> {\n if (input.caller.role !== \"owner\") {\n return relayFailure(\"relay_forbidden\", \"caller may not act in the required role\");\n }\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.requestId,\n });\n if (state.expired) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n if (state.decision !== null) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n return state;\n}\n\nasync function projectionFromState(\n state: AuthorizationState,\n caller: RelayCaller,\n scope: OwnerPhoneScopeProjection,\n): Promise<OwnerPhoneRequestProjection> {\n return Object.freeze({\n version: OAATH_NATIVE_PROJECTION_VERSION,\n operationId: state.requestId,\n displayPayload: await ownerPhoneDisplayPayload(caller.subject, state.requestId),\n expiresAt: state.expiresAt,\n client: Object.freeze({ clientId: state.clientId, redirectUri: state.redirectUri }),\n scope,\n });\n}\n\nexport async function projectOwnerPhoneRequest(\n input: ProjectOwnerPhoneRequestInput,\n): Promise<OwnerPhoneRequestProjection> {\n const state = await pendingOwnerRequest(input);\n return projectionFromState(\n state,\n input.caller,\n await projectOwnerPhoneScope(state.requestedScope, state.requestId),\n );\n}\n\n/** The signing packet for the same consent, using the existing projection wire shape. */\nexport async function projectOwnerPhonePermissionSigning(\n input: ProjectOwnerPhoneRequestInput & {\n readonly permissionApprovals?: OwnerPhonePermissionApprovals;\n },\n): Promise<OwnerPhoneRequestProjection> {\n const state = await pendingOwnerRequest(input);\n const scope = classifyStoredAuthorizationScope(state.requestedScope, state.requestId);\n if (scope.kind !== \"permission-request\")\n return relayFailure(\"relay_request_invalid\", \"request is not a permission\");\n const prepared = await prepareOwnerPhonePermissionApproval(\n input.permissionApprovals,\n scope.request,\n );\n return projectionFromState(\n state,\n input.caller,\n Object.freeze({\n kind: \"owner-signing-request\" as const,\n decision: \"approve-or-reject\" as const,\n requestHash: hashOwnerSigningRequest(prepared.signingRequest),\n request: prepared.signingRequest,\n }),\n );\n}\n","/** Consent projection for an immutable owner revocation request; no admission or decision state. */\nimport {\n hashKernelRevocationSigningRequest,\n hashOwnerSigningRequest,\n type KernelRevocationSigningRequest,\n parseKernelRevocationSigningRequest,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { ownerPhoneDisplayPayload } from \"./display.js\";\nimport {\n OAATH_NATIVE_PROJECTION_VERSION,\n type OwnerPhonePermissionScopeProjection,\n type OwnerPhoneRequestProjection,\n projectPermissionConsent,\n} from \"./projection.js\";\n\nexport interface OwnerPhoneRevocationScopeProjection {\n readonly kind: \"kernel-revocation\";\n readonly decision: \"approve-or-reject\";\n /** Authenticated service commitment; the phone independently derives the operation digest. */\n readonly requestHash: `0x${string}`;\n readonly permission: OwnerPhonePermissionScopeProjection;\n readonly install: Readonly<{\n kind: \"owner-signing-request\";\n decision: \"approve-or-reject\";\n requestHash: `0x${string}`;\n request: KernelRevocationSigningRequest[\"install\"];\n }>;\n readonly effect: KernelRevocationSigningRequest[\"effect\"];\n readonly chainId: number;\n readonly entryPoint: `0x${string}`;\n readonly operation: KernelRevocationSigningRequest[\"operation\"];\n readonly expectedDigest: `0x${string}`;\n}\n\n/** A terminal owner decision acknowledges custody; it releases no OAuth code or signing artifact. */\nexport interface OwnerPhoneRevocationDecision {\n readonly version: \"oaath.native-revocation-decision/v1\";\n readonly operationId: string;\n readonly outcome: \"approved\" | \"rejected\";\n readonly decidedAt: number;\n readonly settlement: \"decided\" | \"replayed\";\n}\n\n/**\n * Projects a stored request for its authenticated owner. The calling queue owns\n * admission, current ownership, expiry and terminal-decision checks; this helper\n * owns only consent bytes. It performs no signing, submission or observation.\n */\nexport async function projectOwnerPhoneRevocation(input: {\n readonly operationId: string;\n readonly ownerSubject: string;\n readonly expiresAt: number;\n readonly request: unknown;\n}): Promise<OwnerPhoneRequestProjection> {\n if (\n !/^[A-Za-z0-9._~-]{1,64}$/u.test(input.operationId) ||\n !input.ownerSubject ||\n !Number.isSafeInteger(input.expiresAt) ||\n input.expiresAt < 0\n )\n return relayFailure(\"relay_request_invalid\", \"revocation projection metadata is invalid\");\n const request = parseKernelRevocationSigningRequest(input.request);\n return Object.freeze({\n version: OAATH_NATIVE_PROJECTION_VERSION,\n operationId: input.operationId,\n displayPayload: await ownerPhoneDisplayPayload(input.ownerSubject, input.operationId),\n expiresAt: input.expiresAt,\n client: Object.freeze({\n clientId: request.permissionRequest.application.clientId,\n redirectUri: null,\n }),\n scope: Object.freeze({\n kind: \"kernel-revocation\",\n decision: \"approve-or-reject\",\n requestHash: hashKernelRevocationSigningRequest(request),\n permission: await projectPermissionConsent(request.permissionRequest),\n install: Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"approve-or-reject\",\n requestHash: hashOwnerSigningRequest(request.install),\n request: request.install,\n }),\n effect: request.effect,\n chainId: request.chainId,\n entryPoint: request.entryPoint,\n operation: request.operation,\n expectedDigest: request.expectedDigest,\n }),\n });\n}\n","/**\n * Owner revocation custody: absent -> pending -> approved | rejected once.\n * The immutable request and terminal decision are the only persisted evidence.\n * Approval occupies this operation ID; it proves custody, never submission or\n * onchain completion. No execution lane is acquired here. A decision retry reads\n * the stored outcome before expiry or artifact handling. An ambiguous enqueue\n * response is recovered by looking up the original grant/chain; it never\n * authorizes a blind insertion. Only expired undecided custody may be replaced.\n * Enqueue recovery needs only the store; signing custody needs KMS. There\n * is no in-memory preparation to recover. Transactions own rollback and release.\n */\nimport {\n hashPermissionRequest,\n type KernelRevocationSigningRequest,\n type PermissionRequest,\n parseKernelRevocationSigningRequest,\n} from \"@oaath/protocol\";\nimport { sealArtifact } from \"../artifact/encrypt.js\";\nimport { readApprovedPermission } from \"../authorization/approved-permission.js\";\nimport { randomIdentifier } from \"../authorization/challenge.js\";\nimport type { AuthorizationDecisionCommand } from \"../authorization/decision.js\";\nimport { verifyKernelV4RevocationOwnerSigningArtifact } from \"../authorization/owner-signing.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport type { ServiceDirectory } from \"../directory/service.js\";\nimport {\n type OwnerPhoneRevocationDecision,\n projectOwnerPhoneRevocation,\n} from \"../native/revocation.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport {\n type RelayStore,\n type RelayTransaction,\n withRelayTransaction,\n} from \"../store/interface.js\";\nimport { timestamp } from \"../store/records.js\";\nimport {\n OAATH_REVOCATION_DECISION_RECORD_VERSION,\n OAATH_REVOCATION_REQUEST_RECORD_VERSION,\n REVOCATION_OPERATION_PREFIX,\n type RevocationDecisionRecord,\n type RevocationRequestRecord,\n} from \"./records.js\";\n\nexport interface RequestOwnerPhoneRevocationInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n readonly directory: Pick<ServiceDirectory, \"resolveRevocationOwner\">;\n /** Deployment-authenticated original application/member. */\n readonly caller: RelayCaller;\n readonly grantId: string;\n readonly chainId: number;\n readonly requestTtlMs: number;\n /**\n * Deployment uses prepareKernelPermissionRevocation to verify the retained Kernel\n * capability, read target-chain state, and choose effect/root nonce/gas.\n * Receives the retained approval plaintext; never log or expose it to clients.\n * Preparation must not reserve a nonce or execution lane; concurrent\n * preparations may lose admission.\n * Returns the SDK signingRequest only. Must not sign or submit an operation.\n */\n readonly prepare: (\n input: Readonly<{ request: Readonly<PermissionRequest>; artifact: string; chainId: number }>,\n ) => Promise<unknown>;\n}\n\nexport interface OwnerPhoneRevocationStatus {\n readonly grantId: string;\n readonly chainId: number;\n readonly operationId: string;\n /** Relay timestamp in milliseconds. */\n readonly expiresAt: number;\n /** Custody status only, never submission or grant revocation completion. */\n readonly status: \"pending\" | \"approved\" | \"rejected\" | \"expired\";\n}\n\ntype ClientRevocationInput = Pick<\n RequestOwnerPhoneRevocationInput,\n \"store\" | \"clock\" | \"caller\" | \"grantId\" | \"chainId\"\n>;\n\nasync function readClientState(transaction: RelayTransaction, input: ClientRevocationInput) {\n if (input.caller.role !== \"client\")\n return relayFailure(\"relay_forbidden\", \"only the originating client may request revocation\");\n const source = await transaction.lockAuthorizationRequest(input.grantId);\n if (\n !source ||\n source.clientId !== input.caller.clientId ||\n source.subject !== input.caller.subject\n )\n return relayFailure(\"relay_forbidden\", \"permission is not owned by this caller\");\n const request = await transaction.lockLatestRevocationRequest(input.grantId, input.chainId);\n const current = request ? { request, decision: await readDecision(transaction, request) } : null;\n return { source, current };\n}\n\nfunction statusOf(\n state: { request: RevocationRequestRecord; decision: RevocationDecisionRecord | undefined },\n clock: RelayClock,\n): Readonly<OwnerPhoneRevocationStatus> {\n return Object.freeze({\n grantId: state.request.signingRequest.permissionRequest.requestId,\n chainId: state.request.signingRequest.chainId,\n operationId: state.request.operationId,\n expiresAt: state.request.expiresAt,\n status:\n state.decision?.outcome ??\n (relayNow(clock) > state.request.expiresAt ? \"expired\" : \"pending\"),\n });\n}\nfunction reusable(\n state: Awaited<ReturnType<typeof readClientState>>[\"current\"],\n clock: RelayClock,\n) {\n return (\n state !== null && (state.decision !== undefined || relayNow(clock) <= state.request.expiresAt)\n );\n}\n\n/** Authenticated metadata lookup. It never prepares, opens KMS custody or submits. */\nexport async function fetchClientPhoneRevocation(\n input: ClientRevocationInput,\n): Promise<Readonly<OwnerPhoneRevocationStatus>> {\n return withRelayTransaction(input.store, async (transaction) => {\n const { current } = await readClientState(transaction, input);\n if (!current) return relayFailure(\"relay_not_found\", \"revocation request is absent\");\n return statusOf(current, input.clock);\n });\n}\n\n/**\n * Returns the current grant/chain request before touching preparation or KMS.\n * Only positively expired, undecided custody may be replaced. Approved custody\n * remains immutable even after expiry: operation evidence owns any replacement.\n * Pure preparation runs outside the transaction; final admission locks the\n * original grant again so concurrent callers share the winner's exact request.\n */\nexport async function requestOwnerPhoneRevocation(\n input: RequestOwnerPhoneRevocationInput,\n): Promise<Readonly<OwnerPhoneRevocationStatus & { created: boolean }>> {\n const { store, clock, kms, directory, caller, grantId, chainId, requestTtlMs, prepare } = input;\n if (\n !Number.isSafeInteger(chainId) ||\n chainId < 1 ||\n !Number.isSafeInteger(requestTtlMs) ||\n requestTtlMs < 1\n )\n return relayFailure(\"relay_request_invalid\", \"revocation chain or TTL is invalid\");\n const source = await withRelayTransaction(store, async (transaction) => {\n const { source: request, current } = await readClientState(transaction, input);\n if (current && reusable(current, clock)) return { retained: statusOf(current, clock) } as const;\n const scope = classifyStoredAuthorizationScope(request.requestedScope, request.requestId);\n const decision = await transaction.lockAuthorizationDecision(grantId);\n if (scope.kind !== \"permission-request\" || decision?.outcome !== \"approved\")\n return relayFailure(\"relay_request_invalid\", \"permission is not approved\");\n const owner = await directory.resolveRevocationOwner(caller, {\n requestId: grantId,\n requestedScope: request.requestedScope,\n chainId,\n });\n if (!owner) return relayFailure(\"relay_forbidden\", \"account or chain is not assigned\");\n const retained = await readApprovedPermission(\n transaction,\n kms,\n request,\n decision,\n scope.request,\n );\n if (!retained)\n return relayFailure(\"relay_record_unreadable\", \"approved permission is unreadable\");\n return { request: scope.request, artifact: retained.plaintext, owner } as const;\n });\n if (\"retained\" in source) return Object.freeze({ ...source.retained, created: false });\n let signingRequest: Readonly<KernelRevocationSigningRequest>;\n try {\n signingRequest = parseKernelRevocationSigningRequest(\n await prepare(Object.freeze({ request: source.request, artifact: source.artifact, chainId })),\n );\n } catch {\n return relayFailure(\"relay_request_invalid\", \"revocation preparation failed\");\n }\n if (\n signingRequest.chainId !== chainId ||\n hashPermissionRequest(signingRequest.permissionRequest) !==\n hashPermissionRequest(source.request)\n )\n return relayFailure(\n \"relay_request_invalid\",\n \"prepared revocation changed its permission or chain\",\n );\n return withRelayTransaction(store, async (transaction) => {\n const { current } = await readClientState(transaction, input);\n if (current && reusable(current, clock))\n return Object.freeze({ ...statusOf(current, clock), created: false });\n const createdAt = relayNow(clock);\n const expiresAt = timestamp(\n createdAt + requestTtlMs,\n \"revocation expiry\",\n \"relay_request_invalid\",\n );\n const record: RevocationRequestRecord = Object.freeze({\n version: OAATH_REVOCATION_REQUEST_RECORD_VERSION,\n operationId: REVOCATION_OPERATION_PREFIX + randomIdentifier(),\n ...source.owner,\n createdAt,\n expiresAt,\n signingRequest,\n });\n if (!(await transaction.insertRevocationRequest(record)))\n return relayFailure(\"relay_state_ambiguous\", \"revocation request insertion did not settle\");\n return Object.freeze({\n ...statusOf({ request: record, decision: undefined }, clock),\n created: true,\n });\n });\n}\n\ninterface OwnerRevocationInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly caller: RelayCaller;\n readonly operationId: string;\n}\nasync function readOwnerState(transaction: RelayTransaction, input: OwnerRevocationInput) {\n if (input.caller.role !== \"owner\")\n return relayFailure(\"relay_forbidden\", \"caller may not decide\");\n const state = await readRevocationState(transaction, input.operationId);\n if (state.request.ownerSubject !== input.caller.subject)\n return relayFailure(\"relay_forbidden\", \"revocation belongs to another owner\");\n return state;\n}\n/** Shared durable request/decision binding; caller admission belongs to each use case. */\nexport async function readRevocationState(transaction: RelayTransaction, operationId: string) {\n const request = await transaction.lockRevocationRequest(operationId);\n if (!request) return relayFailure(\"relay_not_found\", \"revocation request is absent\");\n return { request, decision: await readDecision(transaction, request) };\n}\nasync function readDecision(transaction: RelayTransaction, request: RevocationRequestRecord) {\n const decision = await transaction.lockRevocationDecision(request.operationId);\n if (\n decision &&\n (decision.decidedAt < request.createdAt || decision.decidedAt > request.expiresAt)\n )\n return relayFailure(\n \"relay_record_unreadable\",\n \"revocation decision time contradicts its request\",\n );\n return decision;\n}\n\nfunction requirePending(request: RevocationRequestRecord, clock: RelayClock) {\n if (relayNow(clock) > request.expiresAt)\n return relayFailure(\"relay_expired\", \"revocation request expired\");\n}\nexport async function fetchOwnerPhoneRevocation(input: OwnerRevocationInput) {\n const { request, decision } = await withRelayTransaction(input.store, (transaction) =>\n readOwnerState(transaction, input),\n );\n if (decision) return relayFailure(\"relay_already_decided\", \"revocation is already decided\");\n requirePending(request, input.clock);\n return projectOwnerPhoneRevocation({\n operationId: request.operationId,\n ownerSubject: request.ownerSubject,\n expiresAt: request.expiresAt,\n request: request.signingRequest,\n });\n}\nfunction answer(\n decision: RevocationDecisionRecord,\n settlement: \"decided\" | \"replayed\",\n): OwnerPhoneRevocationDecision {\n return Object.freeze({\n version: \"oaath.native-revocation-decision/v1\",\n operationId: decision.operationId,\n outcome: decision.outcome,\n decidedAt: decision.decidedAt,\n settlement,\n });\n}\nexport async function submitOwnerPhoneRevocationDecision(\n input: OwnerRevocationInput & {\n readonly kms: RelayKms;\n readonly command: AuthorizationDecisionCommand;\n },\n): Promise<OwnerPhoneRevocationDecision> {\n const initial = await withRelayTransaction(input.store, (transaction) =>\n readOwnerState(transaction, input),\n );\n if (initial.decision) return answer(initial.decision, \"replayed\");\n requirePending(initial.request, input.clock);\n const artifactRef =\n input.command.outcome === \"approved\"\n ? await sealArtifact(\n input.kms,\n verifyKernelV4RevocationOwnerSigningArtifact(\n initial.request.signingRequest,\n input.command.artifact,\n ),\n )\n : null;\n return withRelayTransaction(input.store, async (transaction) => {\n const { request, decision } = await readOwnerState(transaction, input);\n if (decision) return answer(decision, \"replayed\");\n requirePending(request, input.clock);\n const decidedAt = relayNow(input.clock);\n if (decidedAt < request.createdAt || decidedAt > request.expiresAt)\n return relayFailure(\"relay_expired\", \"decision is outside the request window\");\n const record: RevocationDecisionRecord = Object.freeze({\n version: OAATH_REVOCATION_DECISION_RECORD_VERSION,\n operationId: request.operationId,\n outcome: input.command.outcome,\n decidedAt,\n artifactRef,\n });\n if (!(await transaction.insertRevocationDecision(record)))\n return relayFailure(\"relay_state_ambiguous\", \"revocation decision insertion did not settle\");\n return answer(record, \"decided\");\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service-DT0vkKop.js","names":[],"sources":["../src/store/interface.ts","../src/artifact/encrypt.ts","../src/authorization/approved-permission.ts","../src/authorization/owner-signing.ts","../src/native/display.ts","../src/authorization/request.ts","../src/authorization/scope.ts","../src/native/permission-approval.ts","../src/native/projection.ts","../src/native/revocation.ts","../src/revocation/service.ts"],"sourcesContent":["/**\n * Durable relay transaction contract.\n *\n * State model owned by this contract:\n *\n * ```text\n * state and owner authorization request (immutable), decision (terminal),\n * code (one-shot), encrypted artifact (one-shot);\n * revocation request (immutable), phone decision (terminal)\n * persisted evidence one row per record, one current schema version\n * resource occupied? yes: a decision row occupies its request; a consumed\n * code and a claimed artifact are terminal\n * retry positively safe? recover committed evidence before any new transition\n * transitions request -> decision(approved|rejected) once;\n * code: issued -> consumed once;\n * artifact: sealed -> claimed once;\n * revocation: pending -> approved|rejected once, no code;\n * expired undecided custody may be replaced under grant lock\n * crash/reload every transition is decided inside one transaction on a\n * row locked for update; a crash leaves the prior state\n * cleanup owner the caller rolls back; the store releases its handle\n * ```\n *\n * Every `lock*` read must acquire an exclusive row lock for the life of the\n * transaction (`SELECT ... FOR UPDATE` semantics). Every one-shot writer\n * (`consumeAuthorizationCode`, `claimEncryptedArtifact`) must additionally\n * guard on the terminal column being null and report whether *this* call\n * performed the transition.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport type { RevocationDecisionRecord, RevocationRequestRecord } from \"../revocation/records.js\";\nimport type {\n AuthorizationCodeRecord,\n AuthorizationDecisionRecord,\n AuthorizationRequestRecord,\n CapabilityInvalidationRecord,\n EncryptedArtifactRecord,\n} from \"./records.js\";\n\n/** Read-only discovery metadata. The existing request/decision records own pending state. */\nexport interface PendingOwnerRequest {\n readonly operationId: string;\n readonly ownerSubject: string;\n readonly expiresAt: number;\n}\n\nexport interface RelayTransaction {\n /** Unexpired and undecided requests, ordered by expiry then ASCII operation ID. No reservation. */\n listPendingOwnerRequests(\n ownerSubject: string,\n now: number,\n limit: number,\n ): Promise<readonly PendingOwnerRequest[]>;\n /** Lock the original authorization request first to serialize grant/chain enqueue. */\n lockLatestRevocationRequest(\n grantId: string,\n chainId: number,\n ): Promise<RevocationRequestRecord | undefined>;\n /** Lock the immutable request before reading or writing its terminal decision. */\n lockRevocationRequest(operationId: string): Promise<RevocationRequestRecord | undefined>;\n insertRevocationRequest(record: RevocationRequestRecord): Promise<boolean>;\n lockRevocationDecision(operationId: string): Promise<RevocationDecisionRecord | undefined>;\n insertRevocationDecision(record: RevocationDecisionRecord): Promise<boolean>;\n\n lockAuthorizationRequest(requestId: string): Promise<AuthorizationRequestRecord | undefined>;\n /** Returns false when the identifier already exists. */\n insertAuthorizationRequest(record: AuthorizationRequestRecord): Promise<boolean>;\n\n lockAuthorizationDecision(requestId: string): Promise<AuthorizationDecisionRecord | undefined>;\n /** Returns false when the request was already decided. */\n insertAuthorizationDecision(record: AuthorizationDecisionRecord): Promise<boolean>;\n\n lockAuthorizationCode(codeHash: string): Promise<AuthorizationCodeRecord | undefined>;\n insertAuthorizationCode(record: AuthorizationCodeRecord): Promise<boolean>;\n /** Returns true only when this call set `consumed_at`. */\n consumeAuthorizationCode(codeHash: string, consumedAt: number): Promise<boolean>;\n\n lockCapabilityInvalidation(grantId: string): Promise<CapabilityInvalidationRecord | undefined>;\n /** Returns false when the Grant's capability is already invalidated. */\n insertCapabilityInvalidation(record: CapabilityInvalidationRecord): Promise<boolean>;\n\n lockEncryptedArtifact(artifactId: string): Promise<EncryptedArtifactRecord | undefined>;\n /** Internal authority lookup; returns retained evidence even after client claim. Never releases it. */\n lockEncryptedArtifactByRequestId(requestId: string): Promise<EncryptedArtifactRecord | undefined>;\n insertEncryptedArtifact(record: EncryptedArtifactRecord): Promise<boolean>;\n /** Returns true only when this call set `claimed_at`. */\n claimEncryptedArtifact(artifactId: string, claimedAt: number): Promise<boolean>;\n\n /** Throws `relay_state_ambiguous` when the outcome cannot be proven. */\n commit(): Promise<void>;\n /** Never throws; rollback failure is a suppressed diagnostic. */\n rollback(): Promise<void>;\n}\n\nexport interface RelayStore {\n begin(): Promise<RelayTransaction>;\n close(): Promise<void>;\n}\n\n/**\n * Runs one transition inside one transaction. The body commits, or the\n * transaction is rolled back and the canonical failure is preserved.\n */\nexport async function withRelayTransaction<Value>(\n store: RelayStore,\n run: (transaction: RelayTransaction) => Promise<Value>,\n): Promise<Value> {\n const transaction = await store.begin();\n let result: Value;\n try {\n result = await run(transaction);\n } catch (error) {\n await transaction.rollback();\n throw error;\n }\n await transaction.commit();\n return result;\n}\n","/**\n * KMS sealing boundary. Plaintext never reaches the store.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nconst KMS_UNAVAILABLE = \"relay_kms_unavailable\" as const;\n\n/**\n * Encrypts an approval artifact and returns the opaque reference to store.\n * A port that echoes plaintext is rejected: the store must never hold it.\n */\nexport async function sealArtifact(kms: RelayKms, plaintext: string): Promise<string> {\n let sealed: unknown;\n try {\n sealed = await kms.encrypt(plaintext);\n } catch {\n return relayFailure(KMS_UNAVAILABLE, \"KMS encrypt failed\");\n }\n const ciphertextRef = boundedText(\n sealed,\n RELAY_LIMITS.ciphertextRef,\n \"KMS ciphertext reference\",\n KMS_UNAVAILABLE,\n );\n if (ciphertextRef.includes(plaintext)) {\n return relayFailure(KMS_UNAVAILABLE, \"KMS reference contains plaintext\");\n }\n return ciphertextRef;\n}\n\n/**\n * Opens retained ciphertext for an authorized internal reader. Client release\n * calls this only after claim commits; authority verification releases no bytes.\n */\nexport async function openArtifact(kms: RelayKms, ciphertextRef: string): Promise<string> {\n let opened: unknown;\n try {\n opened = await kms.decrypt(ciphertextRef);\n } catch {\n return relayFailure(KMS_UNAVAILABLE, \"KMS decrypt failed\");\n }\n return boundedText(opened, RELAY_LIMITS.artifactPlaintext, \"KMS plaintext\", KMS_UNAVAILABLE);\n}\n","/** Retained service-approved policy, independent of OAuth claim or execution expiry. */\nimport {\n applyPermissionDecision,\n createGrantFromPermissionRequest,\n type PermissionRequest,\n parsePermissionDecision,\n} from \"@oaath/protocol\";\nimport { openArtifact } from \"../artifact/encrypt.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayTransaction } from \"../store/interface.js\";\nimport type { AuthorizationDecisionRecord, AuthorizationRequestRecord } from \"../store/records.js\";\n\n/**\n * The same protocol approval meaning at admission and after durable recovery.\n * Kernel capability verification belongs to the SDK; this owner checks the\n * decision's request binding, policy attenuation and reported decision time.\n * Evaluate at that time so a retained approval remains readable for revocation\n * after its execution or OAuth claim window has closed.\n */\nexport function parseApprovedPermission(\n plaintext: string,\n permissionRequest: Readonly<PermissionRequest>,\n relayDecidedAt: number,\n) {\n const value = JSON.parse(plaintext) as unknown;\n const decisionValue =\n value !== null && typeof value === \"object\" && \"installApproval\" in value\n ? (({ installApproval: _install, ...permission }) => permission)(value)\n : value;\n const permission = parsePermissionDecision(decisionValue);\n if (permission.kind !== \"approve\" || permission.decidedAt > Math.floor(relayDecidedAt / 1_000))\n throw new Error(\"permission artifact is not an approved decision at the relay decision time\");\n const applied = applyPermissionDecision({\n request: permissionRequest,\n grant: createGrantFromPermissionRequest(permissionRequest),\n observation: { status: \"available\", decision: permission },\n evaluatedAt: permission.decidedAt,\n });\n if (applied.status !== \"applied\" || applied.grant.state !== \"approved\")\n throw new Error(\"permission artifact does not approve this request\");\n return { permission, plaintext };\n}\n\n/** Kernel capability verification remains the SDK preparation owner's responsibility. */\nexport async function readApprovedPermission(\n transaction: RelayTransaction,\n kms: RelayKms,\n request: AuthorizationRequestRecord,\n decision: AuthorizationDecisionRecord,\n permissionRequest: Readonly<PermissionRequest>,\n) {\n try {\n const artifact = await transaction.lockEncryptedArtifactByRequestId(request.requestId);\n if (\n !artifact ||\n artifact.requestId !== request.requestId ||\n artifact.clientId !== request.clientId ||\n artifact.createdAt !== decision.decidedAt\n )\n return null;\n const plaintext = await openArtifact(kms, artifact.ciphertextRef);\n return parseApprovedPermission(plaintext, permissionRequest, decision.decidedAt);\n } catch {\n return null;\n }\n}\n","/**\n * Pure authorization of one returned Kernel owner-signing artifact.\n *\n * The protocol owns both exact wire shapes. This server owner adds only the\n * release policy: the request must use the first-runtime P-256 credential, the\n * artifact must be its one canonical JSON representation, its request hash must\n * bind the exact request, and its compact low-S signature must verify the exact\n * Kernel digest. It allocates and persists nothing.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { p256 } from \"@noble/curves/nist.js\";\nimport { hexToBytes } from \"@noble/hashes/utils.js\";\nimport {\n hashKernelRevocationSigningRequest,\n hashOwnerSigningRequest,\n type KernelRevocationSigningRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n parseOwnerSigningArtifact,\n serializeOwnerSigningArtifact,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nconst INVALID = \"relay_request_invalid\" as const;\n\n/**\n * Returns the canonical artifact plaintext only after every request, key,\n * request-hash, and signature binding agrees.\n */\nexport function verifyKernelV4ReplayableInstallOwnerSigningArtifact(\n requestValue: unknown,\n artifactPlaintext: unknown,\n): string {\n try {\n const request = parseKernelReplayableInstallOwnerSigningRequest(requestValue);\n if (request.signer.ownerCredential.kind !== \"p256\") throw new TypeError();\n\n return verifyArtifact(\n hashOwnerSigningRequest(request),\n request.expectedDigest,\n request.signer.ownerCredential.publicKey,\n artifactPlaintext,\n );\n } catch {\n return relayFailure(INVALID, \"Kernel owner signing artifact is invalid\");\n }\n}\n\n/** Stored signing request has already crossed the durable record boundary. */\nexport function verifyKernelV4RevocationOwnerSigningArtifact(\n request: Readonly<KernelRevocationSigningRequest>,\n artifactPlaintext: unknown,\n): string {\n try {\n if (request.install.signer.ownerCredential.kind !== \"p256\") throw new TypeError();\n return verifyArtifact(\n hashKernelRevocationSigningRequest(request),\n request.expectedDigest,\n request.install.signer.ownerCredential.publicKey,\n artifactPlaintext,\n );\n } catch {\n return relayFailure(INVALID, \"Kernel owner signing artifact is invalid\");\n }\n}\nfunction verifyArtifact(\n requestHash: string,\n digest: string,\n publicKey: string,\n artifactPlaintext: unknown,\n): string {\n const received = boundedText(\n artifactPlaintext,\n RELAY_LIMITS.artifactPlaintext,\n \"owner signing artifact\",\n INVALID,\n );\n const artifact = parseOwnerSigningArtifact(JSON.parse(received) as unknown);\n const canonical = serializeOwnerSigningArtifact(artifact);\n if (received !== canonical) throw new TypeError();\n if (artifact.requestHash !== requestHash) throw new TypeError();\n\n const verified = p256.verify(\n hexToBytes(artifact.signature.slice(2)),\n hexToBytes(digest.slice(2)),\n hexToBytes(publicKey.slice(2)),\n { format: \"compact\", lowS: true, prehash: false },\n );\n if (!verified) throw new TypeError();\n return canonical;\n}\n","import { sha256Base64Url } from \"../authorization/challenge.js\";\n\n/** Bounded base64url match code length. 48 bits is plenty to compare by eye. */\nexport const NATIVE_DISPLAY_PAYLOAD_LENGTH = 8;\nexport const NATIVE_DISPLAY_DOMAIN = \"oaath.native-display/v1:\";\n\n/** One non-secret comparison code for the requesting app, phone, inbox, and push. */\nexport async function ownerPhoneDisplayPayload(\n ownerSubject: string,\n operationId: string,\n): Promise<string> {\n const digest = await sha256Base64Url(`${NATIVE_DISPLAY_DOMAIN}${ownerSubject}:${operationId}`);\n return digest.slice(0, NATIVE_DISPLAY_PAYLOAD_LENGTH);\n}\n","/**\n * Create and read an authorization request.\n *\n * The request record snapshots the resolved approving device separately from\n * the requesting member. It is immutable once created; reads and decisions never\n * re-resolve the owner. A refused route creates no row. After a crash, the durable\n * route remains authoritative. Creation does not automatically retry writes.\n * Its decision is a separate terminal record, so \"was this decided?\" has one owner.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { exactRecord } from \"@oaath/protocol\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { ownerPhoneDisplayPayload } from \"../native/display.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayStore, RelayTransaction } from \"../store/interface.js\";\nimport { withRelayTransaction } from \"../store/interface.js\";\nimport {\n type AuthorizationDecisionOutcome,\n type AuthorizationOwnerRoute,\n type AuthorizationRequestRecord,\n canonicalIdentifier,\n OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n} from \"../store/records.js\";\nimport { isCodeChallengeS256, randomIdentifier } from \"./challenge.js\";\n\n/** Resolves once at creation; existing requests never follow later routing changes. */\nexport interface RelayOwnerRouting {\n resolveOwner(\n caller: Readonly<RelayCaller>,\n request: Readonly<{ requestId: string; requestedScope: string }>,\n ): Promise<Readonly<AuthorizationOwnerRoute> | null>;\n}\n\nexport interface CreateAuthorizationRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `client` caller; it owns `clientId` and `subject`. */\n readonly caller: RelayCaller;\n readonly ownerRouting: RelayOwnerRouting;\n readonly redirectUri: string;\n readonly codeChallenge: string;\n readonly requestedScope: string;\n readonly requestTtlMs: number;\n}\n\nexport interface CreatedAuthorizationRequest {\n /** Non-secret comparison code shown by the approving phone. */\n readonly matchCode: string;\n readonly requestId: string;\n readonly expiresAt: number;\n}\n\nexport interface AuthorizationState {\n readonly requestId: string;\n readonly clientId: string;\n readonly redirectUri: string;\n readonly requestedScope: string;\n readonly expiresAt: number;\n readonly expired: boolean;\n readonly decision: Readonly<{\n outcome: AuthorizationDecisionOutcome;\n decidedAt: number;\n }> | null;\n}\n\nexport async function createAuthorizationRequest(\n input: CreateAuthorizationRequestInput,\n): Promise<CreatedAuthorizationRequest> {\n if (!isCodeChallengeS256(input.codeChallenge)) {\n return relayFailure(\"relay_request_invalid\", \"codeChallenge must be an S256 challenge\");\n }\n // The deployment owns client registration, so only a redirect URI it bound to\n // this client may receive an authorization code.\n if (!input.caller.redirectUris.includes(input.redirectUri)) {\n return relayFailure(\"relay_forbidden\", \"redirectUri is not registered for this client\");\n }\n const requestId = randomIdentifier();\n const resolved = await input.ownerRouting.resolveOwner(\n input.caller,\n Object.freeze({ requestId, requestedScope: input.requestedScope }),\n );\n if (resolved === null) return relayFailure(\"relay_forbidden\", \"no approving device is assigned\");\n const owner = exactRecord(\n resolved,\n [\"ownerDeviceId\", \"ownerSubject\"],\n \"owner route\",\n new WeakSet(),\n (message) => relayFailure(\"relay_internal\", message),\n );\n const ownerDeviceId = canonicalIdentifier(owner.ownerDeviceId, \"ownerDeviceId\", \"relay_internal\");\n const ownerSubject = canonicalIdentifier(owner.ownerSubject, \"ownerSubject\", \"relay_internal\");\n const createdAt = relayNow(input.clock);\n const record: AuthorizationRequestRecord = Object.freeze({\n version: OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n requestId,\n clientId: input.caller.clientId,\n subject: input.caller.subject,\n ownerDeviceId,\n ownerSubject,\n organizationAudience: input.caller.organizationAudience,\n redirectUri: input.redirectUri,\n codeChallenge: input.codeChallenge,\n requestedScope: input.requestedScope,\n createdAt,\n expiresAt: createdAt + input.requestTtlMs,\n });\n const matchCode = await ownerPhoneDisplayPayload(ownerSubject, requestId);\n await withRelayTransaction(input.store, async (transaction) => {\n if (!(await transaction.insertAuthorizationRequest(record))) {\n // 256 bits of CSPRNG output collided, or the store contradicts itself.\n return relayFailure(\"relay_internal\", \"authorization request identifier is not unique\");\n }\n });\n return Object.freeze({ requestId: record.requestId, expiresAt: record.expiresAt, matchCode });\n}\n\n/**\n * Row-locked read of the request and its decision. Read paths take the same\n * exclusive lock as transitions.\n *\n * ponytail: one lock class for reads and writes; add a shared read mode only if\n * approval-screen traffic measurably contends.\n */\nexport async function readAuthorizationState(\n transaction: RelayTransaction,\n requestId: string,\n now: number,\n match: (request: AuthorizationRequestRecord) => boolean,\n): Promise<AuthorizationState> {\n const request = await transaction.lockAuthorizationRequest(requestId);\n // A caller that is not entitled to this request learns only that it is absent.\n if (!request || !match(request)) {\n return relayFailure(\"relay_not_found\", \"authorization request does not exist\");\n }\n const decision = await transaction.lockAuthorizationDecision(requestId);\n return Object.freeze({\n requestId: request.requestId,\n clientId: request.clientId,\n redirectUri: request.redirectUri,\n requestedScope: request.requestedScope,\n expiresAt: request.expiresAt,\n expired: now >= request.expiresAt,\n decision: decision\n ? Object.freeze({ outcome: decision.outcome, decidedAt: decision.decidedAt })\n : null,\n });\n}\n\nexport interface FetchAuthorizationRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `owner` caller; only the bound subject may read the request. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n}\n\n/** Read for the approving owner. */\nexport function fetchAuthorizationRequest(\n input: FetchAuthorizationRequestInput,\n): Promise<AuthorizationState> {\n const now = relayNow(input.clock);\n return withRelayTransaction(input.store, (transaction) =>\n readAuthorizationState(\n transaction,\n input.requestId,\n now,\n (request) => request.ownerSubject === input.caller.subject,\n ),\n );\n}\n","/**\n * Authoritative classification of one immutable stored authorization scope.\n *\n * The current server may approve an exact protocol PermissionRequest or the\n * one exact Kernel replayable-install request backed by a P-256 owner. Other\n * closed owner-signing requests are captured for projection and hashing but\n * remain reject-only. Unknown, malformed, and legacy scopes stay readable and\n * rejectable, but never authorize artifact creation.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport {\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningRequest,\n type PermissionRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n parseOwnerSigningRequest,\n parsePermissionRequest,\n} from \"@oaath/protocol\";\n\nexport type StoredAuthorizationScope =\n | Readonly<{\n kind: \"permission-request\";\n decision: \"approve-or-reject\";\n request: Readonly<PermissionRequest>;\n }>\n | Readonly<{\n kind: \"kernel-owner-signing-request\";\n decision: \"approve-or-reject\";\n request: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n }>\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"reject-only\";\n request: Readonly<OwnerSigningRequest>;\n }>\n | Readonly<{ kind: \"unverified\"; decision: \"reject-only\" }>;\n\nexport function classifyStoredAuthorizationScope(\n requestedScope: string,\n requestId: string,\n): StoredAuthorizationScope {\n try {\n const parsed: unknown = JSON.parse(requestedScope);\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return Object.freeze({ kind: \"unverified\", decision: \"reject-only\" });\n }\n try {\n return Object.freeze({\n kind: \"permission-request\",\n decision: \"approve-or-reject\",\n request: parsePermissionRequest({ ...parsed, requestId }),\n });\n } catch {\n const request = parseOwnerSigningRequest(parsed);\n try {\n const kernelRequest = parseKernelReplayableInstallOwnerSigningRequest(request);\n if (kernelRequest.signer.ownerCredential.kind === \"p256\") {\n return Object.freeze({\n kind: \"kernel-owner-signing-request\",\n decision: \"approve-or-reject\",\n request: kernelRequest,\n });\n }\n } catch {\n // The generic closed request remains readable but reject-only.\n }\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"reject-only\",\n request,\n });\n }\n } catch {\n return Object.freeze({ kind: \"unverified\", decision: \"reject-only\" });\n }\n}\n","/** Canonical permission preparation supplied by the deployment's Kernel SDK integration. */\nimport {\n captureRecord,\n hashOwnerSigningRequest,\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningArtifact,\n type PermissionRequest,\n parseKernelReplayableInstallOwnerSigningRequest,\n sameOwnerCredentialProfile,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { boundedText, RELAY_LIMITS } from \"../store/records.js\";\n\nexport interface PreparedOwnerPhonePermissionApproval {\n readonly signingRequest: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n /** Verifies and serializes the SDK's decision plus install approval; submits nothing. */\n complete(artifact: Readonly<OwnerSigningArtifact>, decidedAt: number): Promise<string>;\n}\n\nexport interface OwnerPhonePermissionApprovals {\n /** Recreate from the stored request and the deployment-owned install nonce. */\n prepare(\n request: Readonly<PermissionRequest>,\n ): Promise<Readonly<PreparedOwnerPhonePermissionApproval>>;\n}\n\nexport async function prepareOwnerPhonePermissionApproval(\n provider: OwnerPhonePermissionApprovals | undefined,\n request: Readonly<PermissionRequest>,\n): Promise<Readonly<PreparedOwnerPhonePermissionApproval>> {\n if (!provider)\n return relayFailure(\"relay_request_invalid\", \"phone permission signing is not configured\");\n const invalid = () =>\n relayFailure(\"relay_request_invalid\", \"phone permission preparation is invalid\");\n const result = captureRecord(\n await provider.prepare(request),\n \"phone permission preparation\",\n new WeakSet(),\n invalid,\n );\n const signingRequest = parseKernelReplayableInstallOwnerSigningRequest(result.signingRequest);\n if (\n signingRequest.signer.ownerCredential.kind !== \"p256\" ||\n !sameOwnerCredentialProfile(\n signingRequest.signer.ownerCredential,\n request.logicalAccount.ownerCredential,\n ) ||\n typeof result.complete !== \"function\"\n )\n return invalid();\n const complete = result.complete as PreparedOwnerPhonePermissionApproval[\"complete\"];\n const requestHash = hashOwnerSigningRequest(signingRequest);\n return Object.freeze({\n signingRequest,\n async complete(artifact: Readonly<OwnerSigningArtifact>, decidedAt: number) {\n if (artifact.requestHash !== requestHash) return invalid();\n return boundedText(\n await complete(artifact, decidedAt),\n RELAY_LIMITS.artifactPlaintext,\n \"permission artifact\",\n \"relay_request_invalid\",\n );\n },\n });\n}\n","/**\n * EXPERIMENTAL PREVIEW — authenticated owner-phone consent projection.\n *\n * This is a preview surface reached through `@oaath/server/native` and the\n * relay's preview HTTP routes (`GET /native/projections/{operationId}`). It has\n * no stability guarantee and no production qualification: real iOS, Apple\n * provisioning, Secure Enclave, and hosted operations are later work.\n *\n * What it owns: turning one stored authorization request into the projection\n * the owner's phone renders before deciding. It owns nothing about deciding;\n * the relay's decision use case stays the only decision owner.\n *\n * Two very different surfaces share this file, and only one of them is opaque:\n *\n * - The **push** projection (`operationId`, `displayPayload`, `expiresAt`)\n * transits Apple inside an APNs payload, so it stays opaque by design: no\n * permission, scope, client, chain, or account detail may ride it. The APNs\n * sender enforces that subset exactly.\n * - The **consent** projection returned here travels only the authenticated\n * relay → owner channel, so it deliberately carries the full authorization\n * request: the requesting client identity and the requested scope. The owner\n * must see exactly the authority they grant before approving.\n *\n * `displayPayload` is not a secret and not authority: it is a deterministic\n * digest of the request and its bound subject, so the owner can check that the\n * code on the phone is the code the browser shows. Holding it authorizes\n * nothing — deciding still requires the authenticated bound owner.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport {\n hashOwnerSigningRequest,\n isKernelExistingAccountProfile,\n type KernelReplayableInstallOwnerSigningRequest,\n type OwnerSigningRequest,\n type PermissionRequest,\n type WorkspaceAccountContext,\n} from \"@oaath/protocol\";\nimport { sha256Base64Url } from \"../authorization/challenge.js\";\nimport { type AuthorizationState, fetchAuthorizationRequest } from \"../authorization/request.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport type { RelayClock } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport {\n NATIVE_DISPLAY_DOMAIN,\n NATIVE_DISPLAY_PAYLOAD_LENGTH,\n ownerPhoneDisplayPayload,\n} from \"./display.js\";\nimport {\n type OwnerPhonePermissionApprovals,\n prepareOwnerPhonePermissionApproval,\n} from \"./permission-approval.js\";\nimport type { OwnerPhoneRevocationScopeProjection } from \"./revocation.js\";\n\n/** Versioned consent envelope; the Swift decoder pins this exact value. */\nexport const OAATH_NATIVE_PROJECTION_VERSION = \"oaath.native-projection/v7\" as const;\n\n/**\n * Whether the phone may offer approval for one projected scope. Permission\n * requests and exact Kernel replayable-install P-256 signing are approvable;\n * every other owner-signing, unknown, and malformed scope remains reject-only.\n */\nexport type OwnerPhoneDecisionCapability = \"approve-or-reject\" | \"reject-only\";\n\n/** One credential identity as the owner reviews it: public material only. */\nexport type OwnerPhoneCredentialProjection =\n | Readonly<{ kind: \"ecdsa\"; address: string }>\n | Readonly<{ kind: \"p256\"; publicKey: string }>\n | Readonly<{ kind: \"webauthn\"; publicKey: string; authenticatorIdHash: string }>;\n\n/**\n * The requested scope as the phone renders it. When the stored scope parses as\n * an `@oaath/protocol` permission request, every fact that determines who\n * receives authority, over which account, and under what limits is projected\n * structurally. A valid owner-signing request is also projected in full with\n * its protocol-owned hash; only exact Kernel replayable-install P-256 signing\n * is approvable. Anything else is returned as explicitly labeled raw text.\n */\nexport type OwnerPhonePermissionScopeProjection = Readonly<{\n kind: \"permission-request\";\n decision: \"approve-or-reject\";\n /** Explicit request context, independent of later account selection. */\n context: Readonly<WorkspaceAccountContext>;\n /** The application identity the signed request binds, verbatim. */\n application: Readonly<{\n applicationId: string;\n clientId: string;\n origin: string;\n /** Opaque device identity, fingerprinted: raw ids mean nothing to an owner. */\n deviceFingerprint: string;\n }>;\n /** The logical account this authority acts for. */\n account: Readonly<{\n accountIndex: string;\n kernelVersion: string;\n factoryRoute: string;\n entryPointVersion: string;\n ownerCredential: OwnerPhoneCredentialProjection;\n }>;\n /** The session credential that receives the scoped authority. */\n operatorCredential: OwnerPhoneCredentialProjection;\n /**\n * Where the session key lives: null for frontend custody (the page's\n * own non-extractable key), or the remote trust model the owner is\n * asked to approve — the request hash binds it, so approving this\n * display approves exactly this custody.\n */\n sessionSigner: Readonly<{\n mode: \"application_backend\" | \"oaath_hosted\";\n providerId: string;\n }> | null;\n chainScope: \"all\";\n calls: readonly Readonly<{\n target: string;\n selector: string;\n valueLimit: string;\n argumentEquals: readonly Readonly<{ index: number; value: string }>[];\n }>[];\n requestedAt: number;\n /** The permission request's own expiry, as the requesting client stated it. */\n expiresAt: number;\n /** The policy's on-chain validity window; inclusive, in Unix seconds. */\n policyValidAfter: number;\n policyValidUntil: number | null;\n perChainOperationLimit: number;\n /** Window after which the count refills, or null for a lifetime cap. */\n perChainOperationIntervalSeconds: number | null;\n}>;\n\nexport type OwnerPhoneScopeProjection =\n | OwnerPhonePermissionScopeProjection\n | OwnerPhoneRevocationScopeProjection\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"approve-or-reject\";\n /** Canonical hash binding every captured request fact. */\n requestHash: `0x${string}`;\n /** Exact Kernel request independently refined by the protocol owner. */\n request: Readonly<KernelReplayableInstallOwnerSigningRequest>;\n }>\n | Readonly<{\n kind: \"owner-signing-request\";\n decision: \"reject-only\";\n /** Canonical hash binding every captured request fact. */\n requestHash: `0x${string}`;\n /** Full immutable protocol request for independent device review. */\n request: Readonly<OwnerSigningRequest>;\n }>\n | Readonly<{ kind: \"raw\"; decision: \"reject-only\"; text: string }>;\n\nexport interface OwnerPhoneRequestProjection {\n readonly version: typeof OAATH_NATIVE_PROJECTION_VERSION;\n /**\n * Stable across every projection of the same request, and the key the\n * approve/reject saga is keyed by. It is the relay's own opaque request\n * identifier: one authoritative id, no second mapping table to lose.\n */\n readonly operationId: string;\n /** Bounded opaque match code, the only variable an APNs payload may carry. */\n readonly displayPayload: string;\n /** The stored request's expiry, in epoch milliseconds. */\n readonly expiresAt: number;\n /** The requesting client, exactly as the stored request binds it. */\n readonly client: Readonly<{ clientId: string; redirectUri: string | null }>;\n readonly scope: OwnerPhoneScopeProjection;\n}\n\n/**\n * The opaque subset of the projection that may transit Apple inside an APNs\n * payload. The sender exact-captures precisely these three fields, so consent\n * detail can never ride a notification.\n */\nexport type OwnerPhonePushProjection = Pick<\n OwnerPhoneRequestProjection,\n \"operationId\" | \"displayPayload\" | \"expiresAt\"\n>;\n\nexport interface ProjectOwnerPhoneRequestInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n /** Authenticated `owner` caller; only the bound subject may be projected. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n}\n\n/**\n * The stored scope is the requesting client's own JSON permission scope (the\n * SDK serializes a permission request without its `requestId`; the relay's\n * request id is the binding). An unparseable scope is not a failure: the owner\n * still gets the raw text to review, never a silent omission.\n */\nfunction projectCredential(\n credential: Readonly<{\n kind: \"ecdsa\" | \"p256\" | \"webauthn\";\n address?: string;\n publicKey?: string;\n authenticatorIdHash?: string;\n }>,\n): OwnerPhoneCredentialProjection {\n if (credential.kind === \"ecdsa\") {\n return Object.freeze({ kind: \"ecdsa\", address: credential.address ?? \"\" });\n }\n if (credential.kind === \"p256\") {\n return Object.freeze({ kind: \"p256\", publicKey: credential.publicKey ?? \"\" });\n }\n return Object.freeze({\n kind: \"webauthn\",\n publicKey: credential.publicKey ?? \"\",\n authenticatorIdHash: credential.authenticatorIdHash ?? \"\",\n });\n}\n\n/** One owner for permission display facts in both grant and removal consent. */\nexport async function projectPermissionConsent(\n request: Readonly<PermissionRequest>,\n): Promise<OwnerPhonePermissionScopeProjection> {\n if (isKernelExistingAccountProfile(request.logicalAccount))\n return relayFailure(\"relay_request_invalid\", \"phone consent requires a Kernel v4 account\");\n return Object.freeze({\n kind: \"permission-request\",\n decision: \"approve-or-reject\",\n context: request.context,\n application: Object.freeze({\n applicationId: request.application.applicationId,\n clientId: request.application.clientId,\n origin: request.application.origin,\n deviceFingerprint: (\n await sha256Base64Url(`${NATIVE_DISPLAY_DOMAIN}device:${request.application.deviceId}`)\n ).slice(0, NATIVE_DISPLAY_PAYLOAD_LENGTH),\n }),\n account: Object.freeze({\n accountIndex: request.logicalAccount.accountIndex,\n kernelVersion: request.logicalAccount.kernelVersion,\n factoryRoute: request.logicalAccount.factoryRoute,\n entryPointVersion: request.logicalAccount.entryPoint.version,\n ownerCredential: projectCredential(request.logicalAccount.ownerCredential),\n }),\n operatorCredential: projectCredential(request.operatorCredential),\n sessionSigner:\n request.sessionSigner === null\n ? null\n : Object.freeze({\n mode: request.sessionSigner.mode,\n providerId: request.sessionSigner.providerId,\n }),\n chainScope: request.chainScope,\n calls: Object.freeze(\n request.policy.calls.map((call) =>\n Object.freeze({\n target: call.target,\n selector: call.selector,\n valueLimit: call.valueLimit,\n argumentEquals: Object.freeze(\n call.argumentEquals.map((rule) =>\n Object.freeze({ index: rule.index, value: rule.value }),\n ),\n ),\n }),\n ),\n ),\n requestedAt: request.requestedAt,\n expiresAt: request.expiresAt,\n policyValidAfter: request.policy.validAfter,\n policyValidUntil: request.policy.validUntil,\n perChainOperationLimit: request.policy.perChainOperationLimit.count,\n perChainOperationIntervalSeconds: request.policy.perChainOperationLimit.intervalSeconds,\n });\n}\n\nexport async function projectOwnerPhoneScope(\n requestedScope: string,\n operationId: string,\n): Promise<OwnerPhoneScopeProjection> {\n try {\n const classified = classifyStoredAuthorizationScope(requestedScope, operationId);\n if (classified.kind === \"permission-request\") {\n return projectPermissionConsent(classified.request);\n }\n if (classified.kind === \"kernel-owner-signing-request\") {\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"approve-or-reject\",\n requestHash: hashOwnerSigningRequest(classified.request),\n request: classified.request,\n });\n }\n if (classified.kind === \"owner-signing-request\") {\n return Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"reject-only\",\n requestHash: hashOwnerSigningRequest(classified.request),\n request: classified.request,\n });\n }\n return Object.freeze({ kind: \"raw\", decision: \"reject-only\", text: requestedScope });\n } catch {\n return Object.freeze({ kind: \"raw\", decision: \"reject-only\", text: requestedScope });\n }\n}\n\n/**\n * Projects a pending request for its bound owner. An expired or already decided\n * request is not projectable: there is nothing left to approve, so nothing is\n * ever pushed or rendered for it.\n */\nasync function pendingOwnerRequest(\n input: ProjectOwnerPhoneRequestInput,\n): Promise<AuthorizationState> {\n if (input.caller.role !== \"owner\") {\n return relayFailure(\"relay_forbidden\", \"caller may not act in the required role\");\n }\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.requestId,\n });\n if (state.expired) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n if (state.decision !== null) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n return state;\n}\n\nasync function projectionFromState(\n state: AuthorizationState,\n caller: RelayCaller,\n scope: OwnerPhoneScopeProjection,\n): Promise<OwnerPhoneRequestProjection> {\n return Object.freeze({\n version: OAATH_NATIVE_PROJECTION_VERSION,\n operationId: state.requestId,\n displayPayload: await ownerPhoneDisplayPayload(caller.subject, state.requestId),\n expiresAt: state.expiresAt,\n client: Object.freeze({ clientId: state.clientId, redirectUri: state.redirectUri }),\n scope,\n });\n}\n\nexport async function projectOwnerPhoneRequest(\n input: ProjectOwnerPhoneRequestInput,\n): Promise<OwnerPhoneRequestProjection> {\n const state = await pendingOwnerRequest(input);\n return projectionFromState(\n state,\n input.caller,\n await projectOwnerPhoneScope(state.requestedScope, state.requestId),\n );\n}\n\n/** The signing packet for the same consent, using the existing projection wire shape. */\nexport async function projectOwnerPhonePermissionSigning(\n input: ProjectOwnerPhoneRequestInput & {\n readonly permissionApprovals?: OwnerPhonePermissionApprovals;\n },\n): Promise<OwnerPhoneRequestProjection> {\n const state = await pendingOwnerRequest(input);\n const scope = classifyStoredAuthorizationScope(state.requestedScope, state.requestId);\n if (scope.kind !== \"permission-request\")\n return relayFailure(\"relay_request_invalid\", \"request is not a permission\");\n const prepared = await prepareOwnerPhonePermissionApproval(\n input.permissionApprovals,\n scope.request,\n );\n return projectionFromState(\n state,\n input.caller,\n Object.freeze({\n kind: \"owner-signing-request\" as const,\n decision: \"approve-or-reject\" as const,\n requestHash: hashOwnerSigningRequest(prepared.signingRequest),\n request: prepared.signingRequest,\n }),\n );\n}\n","/** Consent projection for an immutable owner revocation request; no admission or decision state. */\nimport {\n hashKernelRevocationSigningRequest,\n hashOwnerSigningRequest,\n type KernelRevocationSigningRequest,\n parseKernelRevocationSigningRequest,\n} from \"@oaath/protocol\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport { ownerPhoneDisplayPayload } from \"./display.js\";\nimport {\n OAATH_NATIVE_PROJECTION_VERSION,\n type OwnerPhonePermissionScopeProjection,\n type OwnerPhoneRequestProjection,\n projectPermissionConsent,\n} from \"./projection.js\";\n\nexport interface OwnerPhoneRevocationScopeProjection {\n readonly kind: \"kernel-revocation\";\n readonly decision: \"approve-or-reject\";\n /** Authenticated service commitment; the phone independently derives the operation digest. */\n readonly requestHash: `0x${string}`;\n readonly permission: OwnerPhonePermissionScopeProjection;\n readonly install: Readonly<{\n kind: \"owner-signing-request\";\n decision: \"approve-or-reject\";\n requestHash: `0x${string}`;\n request: KernelRevocationSigningRequest[\"install\"];\n }>;\n readonly effect: KernelRevocationSigningRequest[\"effect\"];\n readonly chainId: number;\n readonly entryPoint: `0x${string}`;\n readonly operation: KernelRevocationSigningRequest[\"operation\"];\n readonly expectedDigest: `0x${string}`;\n}\n\n/** A terminal owner decision acknowledges custody; it releases no OAuth code or signing artifact. */\nexport interface OwnerPhoneRevocationDecision {\n readonly version: \"oaath.native-revocation-decision/v1\";\n readonly operationId: string;\n readonly outcome: \"approved\" | \"rejected\";\n readonly decidedAt: number;\n readonly settlement: \"decided\" | \"replayed\";\n}\n\n/**\n * Projects a stored request for its authenticated owner. The calling queue owns\n * admission, current ownership, expiry and terminal-decision checks; this helper\n * owns only consent bytes. It performs no signing, submission or observation.\n */\nexport async function projectOwnerPhoneRevocation(input: {\n readonly operationId: string;\n readonly ownerSubject: string;\n readonly expiresAt: number;\n readonly request: unknown;\n}): Promise<OwnerPhoneRequestProjection> {\n if (\n !/^[A-Za-z0-9._~-]{1,64}$/u.test(input.operationId) ||\n !input.ownerSubject ||\n !Number.isSafeInteger(input.expiresAt) ||\n input.expiresAt < 0\n )\n return relayFailure(\"relay_request_invalid\", \"revocation projection metadata is invalid\");\n const request = parseKernelRevocationSigningRequest(input.request);\n return Object.freeze({\n version: OAATH_NATIVE_PROJECTION_VERSION,\n operationId: input.operationId,\n displayPayload: await ownerPhoneDisplayPayload(input.ownerSubject, input.operationId),\n expiresAt: input.expiresAt,\n client: Object.freeze({\n clientId: request.permissionRequest.application.clientId,\n redirectUri: null,\n }),\n scope: Object.freeze({\n kind: \"kernel-revocation\",\n decision: \"approve-or-reject\",\n requestHash: hashKernelRevocationSigningRequest(request),\n permission: await projectPermissionConsent(request.permissionRequest),\n install: Object.freeze({\n kind: \"owner-signing-request\",\n decision: \"approve-or-reject\",\n requestHash: hashOwnerSigningRequest(request.install),\n request: request.install,\n }),\n effect: request.effect,\n chainId: request.chainId,\n entryPoint: request.entryPoint,\n operation: request.operation,\n expectedDigest: request.expectedDigest,\n }),\n });\n}\n","/**\n * Owner revocation custody: absent -> pending -> approved | rejected once.\n * The immutable request and terminal decision are the only persisted evidence.\n * Approval occupies this operation ID; it proves custody, never submission or\n * onchain completion. No execution lane is acquired here. A decision retry reads\n * the stored outcome before expiry or artifact handling. An ambiguous enqueue\n * response is recovered by looking up the original grant/chain; it never\n * authorizes a blind insertion. Only expired undecided custody may be replaced.\n * Enqueue recovery needs only the store; signing custody needs KMS. There\n * is no in-memory preparation to recover. Transactions own rollback and release.\n */\nimport {\n hashPermissionRequest,\n type KernelRevocationSigningRequest,\n type PermissionRequest,\n parseKernelRevocationSigningRequest,\n} from \"@oaath/protocol\";\nimport { sealArtifact } from \"../artifact/encrypt.js\";\nimport { readApprovedPermission } from \"../authorization/approved-permission.js\";\nimport { randomIdentifier } from \"../authorization/challenge.js\";\nimport type { AuthorizationDecisionCommand } from \"../authorization/decision.js\";\nimport { verifyKernelV4RevocationOwnerSigningArtifact } from \"../authorization/owner-signing.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport type { ServiceDirectory } from \"../directory/service.js\";\nimport {\n type OwnerPhoneRevocationDecision,\n projectOwnerPhoneRevocation,\n} from \"../native/revocation.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport {\n type RelayStore,\n type RelayTransaction,\n withRelayTransaction,\n} from \"../store/interface.js\";\nimport { timestamp } from \"../store/records.js\";\nimport {\n OAATH_REVOCATION_DECISION_RECORD_VERSION,\n OAATH_REVOCATION_REQUEST_RECORD_VERSION,\n REVOCATION_OPERATION_PREFIX,\n type RevocationDecisionRecord,\n type RevocationRequestRecord,\n} from \"./records.js\";\n\nexport interface RequestOwnerPhoneRevocationInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n readonly directory: Pick<ServiceDirectory, \"resolveRevocationOwner\">;\n /** Deployment-authenticated original application/member. */\n readonly caller: RelayCaller;\n readonly grantId: string;\n readonly chainId: number;\n readonly requestTtlMs: number;\n /**\n * Deployment uses prepareKernelPermissionRevocation to verify the retained Kernel\n * capability, read target-chain state, and choose effect/root nonce/gas.\n * Receives the retained approval plaintext; never log or expose it to clients.\n * Preparation must not reserve a nonce or execution lane; concurrent\n * preparations may lose admission.\n * Returns the SDK signingRequest only. Must not sign or submit an operation.\n */\n readonly prepare: (\n input: Readonly<{ request: Readonly<PermissionRequest>; artifact: string; chainId: number }>,\n ) => Promise<unknown>;\n}\n\nexport interface OwnerPhoneRevocationStatus {\n readonly grantId: string;\n readonly chainId: number;\n readonly operationId: string;\n /** Relay timestamp in milliseconds. */\n readonly expiresAt: number;\n /** Custody status only, never submission or grant revocation completion. */\n readonly status: \"pending\" | \"approved\" | \"rejected\" | \"expired\";\n}\n\ntype ClientRevocationInput = Pick<\n RequestOwnerPhoneRevocationInput,\n \"store\" | \"clock\" | \"caller\" | \"grantId\" | \"chainId\"\n>;\n\nasync function readClientState(transaction: RelayTransaction, input: ClientRevocationInput) {\n if (input.caller.role !== \"client\")\n return relayFailure(\"relay_forbidden\", \"only the originating client may request revocation\");\n const source = await transaction.lockAuthorizationRequest(input.grantId);\n if (\n !source ||\n source.clientId !== input.caller.clientId ||\n source.subject !== input.caller.subject\n )\n return relayFailure(\"relay_forbidden\", \"permission is not owned by this caller\");\n const request = await transaction.lockLatestRevocationRequest(input.grantId, input.chainId);\n const current = request ? { request, decision: await readDecision(transaction, request) } : null;\n return { source, current };\n}\n\nfunction statusOf(\n state: { request: RevocationRequestRecord; decision: RevocationDecisionRecord | undefined },\n clock: RelayClock,\n): Readonly<OwnerPhoneRevocationStatus> {\n return Object.freeze({\n grantId: state.request.signingRequest.permissionRequest.requestId,\n chainId: state.request.signingRequest.chainId,\n operationId: state.request.operationId,\n expiresAt: state.request.expiresAt,\n status:\n state.decision?.outcome ??\n (relayNow(clock) > state.request.expiresAt ? \"expired\" : \"pending\"),\n });\n}\nfunction reusable(\n state: Awaited<ReturnType<typeof readClientState>>[\"current\"],\n clock: RelayClock,\n) {\n return (\n state !== null && (state.decision !== undefined || relayNow(clock) <= state.request.expiresAt)\n );\n}\n\n/** Authenticated metadata lookup. It never prepares, opens KMS custody or submits. */\nexport async function fetchClientPhoneRevocation(\n input: ClientRevocationInput,\n): Promise<Readonly<OwnerPhoneRevocationStatus>> {\n return withRelayTransaction(input.store, async (transaction) => {\n const { current } = await readClientState(transaction, input);\n if (!current) return relayFailure(\"relay_not_found\", \"revocation request is absent\");\n return statusOf(current, input.clock);\n });\n}\n\n/**\n * Returns the current grant/chain request before touching preparation or KMS.\n * Only positively expired, undecided custody may be replaced. Approved custody\n * remains immutable even after expiry: operation evidence owns any replacement.\n * Pure preparation runs outside the transaction; final admission locks the\n * original grant again so concurrent callers share the winner's exact request.\n */\nexport async function requestOwnerPhoneRevocation(\n input: RequestOwnerPhoneRevocationInput,\n): Promise<Readonly<OwnerPhoneRevocationStatus & { created: boolean }>> {\n const { store, clock, kms, directory, caller, grantId, chainId, requestTtlMs, prepare } = input;\n if (\n !Number.isSafeInteger(chainId) ||\n chainId < 1 ||\n !Number.isSafeInteger(requestTtlMs) ||\n requestTtlMs < 1\n )\n return relayFailure(\"relay_request_invalid\", \"revocation chain or TTL is invalid\");\n const source = await withRelayTransaction(store, async (transaction) => {\n const { source: request, current } = await readClientState(transaction, input);\n if (current && reusable(current, clock)) return { retained: statusOf(current, clock) } as const;\n const scope = classifyStoredAuthorizationScope(request.requestedScope, request.requestId);\n const decision = await transaction.lockAuthorizationDecision(grantId);\n if (scope.kind !== \"permission-request\" || decision?.outcome !== \"approved\")\n return relayFailure(\"relay_request_invalid\", \"permission is not approved\");\n const owner = await directory.resolveRevocationOwner(caller, {\n requestId: grantId,\n requestedScope: request.requestedScope,\n chainId,\n });\n if (!owner) return relayFailure(\"relay_forbidden\", \"account or chain is not assigned\");\n const retained = await readApprovedPermission(\n transaction,\n kms,\n request,\n decision,\n scope.request,\n );\n if (!retained)\n return relayFailure(\"relay_record_unreadable\", \"approved permission is unreadable\");\n return { request: scope.request, artifact: retained.plaintext, owner } as const;\n });\n if (\"retained\" in source) return Object.freeze({ ...source.retained, created: false });\n let signingRequest: Readonly<KernelRevocationSigningRequest>;\n try {\n signingRequest = parseKernelRevocationSigningRequest(\n await prepare(Object.freeze({ request: source.request, artifact: source.artifact, chainId })),\n );\n } catch {\n return relayFailure(\"relay_request_invalid\", \"revocation preparation failed\");\n }\n if (\n signingRequest.chainId !== chainId ||\n hashPermissionRequest(signingRequest.permissionRequest) !==\n hashPermissionRequest(source.request)\n )\n return relayFailure(\n \"relay_request_invalid\",\n \"prepared revocation changed its permission or chain\",\n );\n return withRelayTransaction(store, async (transaction) => {\n const { current } = await readClientState(transaction, input);\n if (current && reusable(current, clock))\n return Object.freeze({ ...statusOf(current, clock), created: false });\n const createdAt = relayNow(clock);\n const expiresAt = timestamp(\n createdAt + requestTtlMs,\n \"revocation expiry\",\n \"relay_request_invalid\",\n );\n const record: RevocationRequestRecord = Object.freeze({\n version: OAATH_REVOCATION_REQUEST_RECORD_VERSION,\n operationId: REVOCATION_OPERATION_PREFIX + randomIdentifier(),\n ...source.owner,\n createdAt,\n expiresAt,\n signingRequest,\n });\n if (!(await transaction.insertRevocationRequest(record)))\n return relayFailure(\"relay_state_ambiguous\", \"revocation request insertion did not settle\");\n return Object.freeze({\n ...statusOf({ request: record, decision: undefined }, clock),\n created: true,\n });\n });\n}\n\ninterface OwnerRevocationInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly caller: RelayCaller;\n readonly operationId: string;\n}\nasync function readOwnerState(transaction: RelayTransaction, input: OwnerRevocationInput) {\n if (input.caller.role !== \"owner\")\n return relayFailure(\"relay_forbidden\", \"caller may not decide\");\n const state = await readRevocationState(transaction, input.operationId);\n if (state.request.ownerSubject !== input.caller.subject)\n return relayFailure(\"relay_forbidden\", \"revocation belongs to another owner\");\n return state;\n}\n/** Shared durable request/decision binding; caller admission belongs to each use case. */\nexport async function readRevocationState(transaction: RelayTransaction, operationId: string) {\n const request = await transaction.lockRevocationRequest(operationId);\n if (!request) return relayFailure(\"relay_not_found\", \"revocation request is absent\");\n return { request, decision: await readDecision(transaction, request) };\n}\nasync function readDecision(transaction: RelayTransaction, request: RevocationRequestRecord) {\n const decision = await transaction.lockRevocationDecision(request.operationId);\n if (\n decision &&\n (decision.decidedAt < request.createdAt || decision.decidedAt > request.expiresAt)\n )\n return relayFailure(\n \"relay_record_unreadable\",\n \"revocation decision time contradicts its request\",\n );\n return decision;\n}\n\nfunction requirePending(request: RevocationRequestRecord, clock: RelayClock) {\n if (relayNow(clock) > request.expiresAt)\n return relayFailure(\"relay_expired\", \"revocation request expired\");\n}\nexport async function fetchOwnerPhoneRevocation(input: OwnerRevocationInput) {\n const { request, decision } = await withRelayTransaction(input.store, (transaction) =>\n readOwnerState(transaction, input),\n );\n if (decision) return relayFailure(\"relay_already_decided\", \"revocation is already decided\");\n requirePending(request, input.clock);\n return projectOwnerPhoneRevocation({\n operationId: request.operationId,\n ownerSubject: request.ownerSubject,\n expiresAt: request.expiresAt,\n request: request.signingRequest,\n });\n}\nfunction answer(\n decision: RevocationDecisionRecord,\n settlement: \"decided\" | \"replayed\",\n): OwnerPhoneRevocationDecision {\n return Object.freeze({\n version: \"oaath.native-revocation-decision/v1\",\n operationId: decision.operationId,\n outcome: decision.outcome,\n decidedAt: decision.decidedAt,\n settlement,\n });\n}\nexport async function submitOwnerPhoneRevocationDecision(\n input: OwnerRevocationInput & {\n readonly kms: RelayKms;\n readonly command: AuthorizationDecisionCommand;\n },\n): Promise<OwnerPhoneRevocationDecision> {\n const initial = await withRelayTransaction(input.store, (transaction) =>\n readOwnerState(transaction, input),\n );\n if (initial.decision) return answer(initial.decision, \"replayed\");\n requirePending(initial.request, input.clock);\n const artifactRef =\n input.command.outcome === \"approved\"\n ? await sealArtifact(\n input.kms,\n verifyKernelV4RevocationOwnerSigningArtifact(\n initial.request.signingRequest,\n input.command.artifact,\n ),\n )\n : null;\n return withRelayTransaction(input.store, async (transaction) => {\n const { request, decision } = await readOwnerState(transaction, input);\n if (decision) return answer(decision, \"replayed\");\n requirePending(request, input.clock);\n const decidedAt = relayNow(input.clock);\n if (decidedAt < request.createdAt || decidedAt > request.expiresAt)\n return relayFailure(\"relay_expired\", \"decision is outside the request window\");\n const record: RevocationDecisionRecord = Object.freeze({\n version: OAATH_REVOCATION_DECISION_RECORD_VERSION,\n operationId: request.operationId,\n outcome: input.command.outcome,\n decidedAt,\n artifactRef,\n });\n if (!(await transaction.insertRevocationDecision(record)))\n return relayFailure(\"relay_state_ambiguous\", \"revocation decision insertion did not settle\");\n return answer(record, \"decided\");\n });\n}\n"],"mappings":";;;;;;;;;;;AAyGA,eAAsB,qBACpB,OACA,KACgB;CAChB,MAAM,cAAc,MAAM,MAAM,MAAM;CACtC,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,IAAI,WAAW;CAChC,SAAS,OAAO;EACd,MAAM,YAAY,SAAS;EAC3B,MAAM;CACR;CACA,MAAM,YAAY,OAAO;CACzB,OAAO;AACT;;;;;;;;AC7GA,MAAM,kBAAkB;;;;;AAMxB,eAAsB,aAAa,KAAe,WAAoC;CACpF,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,IAAI,QAAQ,SAAS;CACtC,QAAQ;EACN,OAAO,aAAa,iBAAiB,oBAAoB;CAC3D;CACA,MAAM,gBAAgB,YACpB,QACA,aAAa,eACb,4BACA,eACF;CACA,IAAI,cAAc,SAAS,SAAS,GAClC,OAAO,aAAa,iBAAiB,kCAAkC;CAEzE,OAAO;AACT;;;;;AAMA,eAAsB,aAAa,KAAe,eAAwC;CACxF,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,IAAI,QAAQ,aAAa;CAC1C,QAAQ;EACN,OAAO,aAAa,iBAAiB,oBAAoB;CAC3D;CACA,OAAO,YAAY,QAAQ,aAAa,mBAAmB,iBAAiB,eAAe;AAC7F;;;;;;;;;;;AC5BA,SAAgB,wBACd,WACA,mBACA,gBACA;CACA,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,gBACJ,UAAU,QAAQ,OAAO,UAAU,YAAY,qBAAqB,UAC9D,EAAE,iBAAiB,UAAU,GAAG,iBAAiB,WAAA,CAAY,KAAK,IACpE;CACN,MAAM,aAAa,wBAAwB,aAAa;CACxD,IAAI,WAAW,SAAS,aAAa,WAAW,YAAY,KAAK,MAAM,iBAAiB,GAAK,GAC3F,MAAM,IAAI,MAAM,4EAA4E;CAC9F,MAAM,UAAU,wBAAwB;EACtC,SAAS;EACT,OAAO,iCAAiC,iBAAiB;EACzD,aAAa;GAAE,QAAQ;GAAa,UAAU;EAAW;EACzD,aAAa,WAAW;CAC1B,CAAC;CACD,IAAI,QAAQ,WAAW,aAAa,QAAQ,MAAM,UAAU,YAC1D,MAAM,IAAI,MAAM,mDAAmD;CACrE,OAAO;EAAE;EAAY;CAAU;AACjC;;AAGA,eAAsB,uBACpB,aACA,KACA,SACA,UACA,mBACA;CACA,IAAI;EACF,MAAM,WAAW,MAAM,YAAY,iCAAiC,QAAQ,SAAS;EACrF,IACE,CAAC,YACD,SAAS,cAAc,QAAQ,aAC/B,SAAS,aAAa,QAAQ,YAC9B,SAAS,cAAc,SAAS,WAEhC,OAAO;EAET,OAAO,wBAAwB,MADP,aAAa,KAAK,SAAS,aAAa,GACtB,mBAAmB,SAAS,SAAS;CACjF,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;ACxCA,MAAM,UAAU;;;;;AAMhB,SAAgB,oDACd,cACA,mBACQ;CACR,IAAI;EACF,MAAM,UAAU,gDAAgD,YAAY;EAC5E,IAAI,QAAQ,OAAO,gBAAgB,SAAS,QAAQ,MAAM,IAAI,UAAU;EAExE,OAAO,eACL,wBAAwB,OAAO,GAC/B,QAAQ,gBACR,QAAQ,OAAO,gBAAgB,WAC/B,iBACF;CACF,QAAQ;EACN,OAAO,aAAa,SAAS,0CAA0C;CACzE;AACF;;AAGA,SAAgB,6CACd,SACA,mBACQ;CACR,IAAI;EACF,IAAI,QAAQ,QAAQ,OAAO,gBAAgB,SAAS,QAAQ,MAAM,IAAI,UAAU;EAChF,OAAO,eACL,mCAAmC,OAAO,GAC1C,QAAQ,gBACR,QAAQ,QAAQ,OAAO,gBAAgB,WACvC,iBACF;CACF,QAAQ;EACN,OAAO,aAAa,SAAS,0CAA0C;CACzE;AACF;AACA,SAAS,eACP,aACA,QACA,WACA,mBACQ;CACR,MAAM,WAAW,YACf,mBACA,aAAa,mBACb,0BACA,OACF;CACA,MAAM,WAAW,0BAA0B,KAAK,MAAM,QAAQ,CAAY;CAC1E,MAAM,YAAY,8BAA8B,QAAQ;CACxD,IAAI,aAAa,WAAW,MAAM,IAAI,UAAU;CAChD,IAAI,SAAS,gBAAgB,aAAa,MAAM,IAAI,UAAU;CAQ9D,IAAI,CANa,KAAK,OACpB,WAAW,SAAS,UAAU,MAAM,CAAC,CAAC,GACtC,WAAW,OAAO,MAAM,CAAC,CAAC,GAC1B,WAAW,UAAU,MAAM,CAAC,CAAC,GAC7B;EAAE,QAAQ;EAAW,MAAM;EAAM,SAAS;CAAM,CAEtC,GAAG,MAAM,IAAI,UAAU;CACnC,OAAO;AACT;;;;ACzFA,MAAa,gCAAgC;AAC7C,MAAa,wBAAwB;;AAGrC,eAAsB,yBACpB,cACA,aACiB;CAEjB,QAAO,MADc,gBAAgB,GAAG,wBAAwB,aAAa,GAAG,aAAa,EAAA,CAC/E,MAAM,GAAA,CAAgC;AACtD;;;;;;;;;;;;;;ACuDA,eAAsB,2BACpB,OACsC;CACtC,IAAI,CAAC,oBAAoB,MAAM,aAAa,GAC1C,OAAO,aAAa,yBAAyB,yCAAyC;CAIxF,IAAI,CAAC,MAAM,OAAO,aAAa,SAAS,MAAM,WAAW,GACvD,OAAO,aAAa,mBAAmB,+CAA+C;CAExF,MAAM,YAAY,iBAAiB;CACnC,MAAM,WAAW,MAAM,MAAM,aAAa,aACxC,MAAM,QACN,OAAO,OAAO;EAAE;EAAW,gBAAgB,MAAM;CAAe,CAAC,CACnE;CACA,IAAI,aAAa,MAAM,OAAO,aAAa,mBAAmB,iCAAiC;CAC/F,MAAM,QAAQ,YACZ,UACA,CAAC,iBAAiB,cAAc,GAChC,+BACA,IAAI,QAAQ,IACX,YAAY,aAAa,kBAAkB,OAAO,CACrD;CACA,MAAM,gBAAgB,oBAAoB,MAAM,eAAe,iBAAiB,gBAAgB;CAChG,MAAM,eAAe,oBAAoB,MAAM,cAAc,gBAAgB,gBAAgB;CAC7F,MAAM,YAAY,SAAS,MAAM,KAAK;CACtC,MAAM,SAAqC,OAAO,OAAO;EACvD,SAAS;EACT;EACA,UAAU,MAAM,OAAO;EACvB,SAAS,MAAM,OAAO;EACtB;EACA;EACA,sBAAsB,MAAM,OAAO;EACnC,aAAa,MAAM;EACnB,eAAe,MAAM;EACrB,gBAAgB,MAAM;EACtB;EACA,WAAW,YAAY,MAAM;CAC/B,CAAC;CACD,MAAM,YAAY,MAAM,yBAAyB,cAAc,SAAS;CACxE,MAAM,qBAAqB,MAAM,OAAO,OAAO,gBAAgB;EAC7D,IAAI,CAAE,MAAM,YAAY,2BAA2B,MAAM,GAEvD,OAAO,aAAa,kBAAkB,gDAAgD;CAE1F,CAAC;CACD,OAAO,OAAO,OAAO;EAAE,WAAW,OAAO;EAAW,WAAW,OAAO;EAAW;CAAU,CAAC;AAC9F;;;;;;;;AASA,eAAsB,uBACpB,aACA,WACA,KACA,OAC6B;CAC7B,MAAM,UAAU,MAAM,YAAY,yBAAyB,SAAS;CAEpE,IAAI,CAAC,WAAW,CAAC,MAAM,OAAO,GAC5B,OAAO,aAAa,mBAAmB,sCAAsC;CAE/E,MAAM,WAAW,MAAM,YAAY,0BAA0B,SAAS;CACtE,OAAO,OAAO,OAAO;EACnB,WAAW,QAAQ;EACnB,UAAU,QAAQ;EAClB,aAAa,QAAQ;EACrB,gBAAgB,QAAQ;EACxB,WAAW,QAAQ;EACnB,SAAS,OAAO,QAAQ;EACxB,UAAU,WACN,OAAO,OAAO;GAAE,SAAS,SAAS;GAAS,WAAW,SAAS;EAAU,CAAC,IAC1E;CACN,CAAC;AACH;;AAWA,SAAgB,0BACd,OAC6B;CAC7B,MAAM,MAAM,SAAS,MAAM,KAAK;CAChC,OAAO,qBAAqB,MAAM,QAAQ,gBACxC,uBACE,aACA,MAAM,WACN,MACC,YAAY,QAAQ,iBAAiB,MAAM,OAAO,OACrD,CACF;AACF;;;;;;;;;;;;;;ACrIA,SAAgB,iCACd,gBACA,WAC0B;CAC1B,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,cAAc;EACjD,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GACvE,OAAO,OAAO,OAAO;GAAE,MAAM;GAAc,UAAU;EAAc,CAAC;EAEtE,IAAI;GACF,OAAO,OAAO,OAAO;IACnB,MAAM;IACN,UAAU;IACV,SAAS,uBAAuB;KAAE,GAAG;KAAQ;IAAU,CAAC;GAC1D,CAAC;EACH,QAAQ;GACN,MAAM,UAAU,yBAAyB,MAAM;GAC/C,IAAI;IACF,MAAM,gBAAgB,gDAAgD,OAAO;IAC7E,IAAI,cAAc,OAAO,gBAAgB,SAAS,QAChD,OAAO,OAAO,OAAO;KACnB,MAAM;KACN,UAAU;KACV,SAAS;IACX,CAAC;GAEL,QAAQ,CAER;GACA,OAAO,OAAO,OAAO;IACnB,MAAM;IACN,UAAU;IACV;GACF,CAAC;EACH;CACF,QAAQ;EACN,OAAO,OAAO,OAAO;GAAE,MAAM;GAAc,UAAU;EAAc,CAAC;CACtE;AACF;;;;ACnDA,eAAsB,oCACpB,UACA,SACyD;CACzD,IAAI,CAAC,UACH,OAAO,aAAa,yBAAyB,4CAA4C;CAC3F,MAAM,gBACJ,aAAa,yBAAyB,yCAAyC;CACjF,MAAM,SAAS,cACb,MAAM,SAAS,QAAQ,OAAO,GAC9B,gDACA,IAAI,QAAQ,GACZ,OACF;CACA,MAAM,iBAAiB,gDAAgD,OAAO,cAAc;CAC5F,IACE,eAAe,OAAO,gBAAgB,SAAS,UAC/C,CAAC,2BACC,eAAe,OAAO,iBACtB,QAAQ,eAAe,eACzB,KACA,OAAO,OAAO,aAAa,YAE3B,OAAO,QAAQ;CACjB,MAAM,WAAW,OAAO;CACxB,MAAM,cAAc,wBAAwB,cAAc;CAC1D,OAAO,OAAO,OAAO;EACnB;EACA,MAAM,SAAS,UAA0C,WAAmB;GAC1E,IAAI,SAAS,gBAAgB,aAAa,OAAO,QAAQ;GACzD,OAAO,YACL,MAAM,SAAS,UAAU,SAAS,GAClC,aAAa,mBACb,uBACA,uBACF;EACF;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA,MAAa,kCAAkC;;;;;;;AAwI/C,SAAS,kBACP,YAMgC;CAChC,IAAI,WAAW,SAAS,SACtB,OAAO,OAAO,OAAO;EAAE,MAAM;EAAS,SAAS,WAAW,WAAW;CAAG,CAAC;CAE3E,IAAI,WAAW,SAAS,QACtB,OAAO,OAAO,OAAO;EAAE,MAAM;EAAQ,WAAW,WAAW,aAAa;CAAG,CAAC;CAE9E,OAAO,OAAO,OAAO;EACnB,MAAM;EACN,WAAW,WAAW,aAAa;EACnC,qBAAqB,WAAW,uBAAuB;CACzD,CAAC;AACH;;AAGA,eAAsB,yBACpB,SAC8C;CAC9C,IAAI,+BAA+B,QAAQ,cAAc,GACvD,OAAO,aAAa,yBAAyB,4CAA4C;CAC3F,OAAO,OAAO,OAAO;EACnB,MAAM;EACN,UAAU;EACV,SAAS,QAAQ;EACjB,aAAa,OAAO,OAAO;GACzB,eAAe,QAAQ,YAAY;GACnC,UAAU,QAAQ,YAAY;GAC9B,QAAQ,QAAQ,YAAY;GAC5B,oBACE,MAAM,gBAAgB,GAAG,sBAAsB,SAAS,QAAQ,YAAY,UAAU,EAAA,CACtF,MAAM,GAAA,CAAgC;EAC1C,CAAC;EACD,SAAS,OAAO,OAAO;GACrB,cAAc,QAAQ,eAAe;GACrC,eAAe,QAAQ,eAAe;GACtC,cAAc,QAAQ,eAAe;GACrC,mBAAmB,QAAQ,eAAe,WAAW;GACrD,iBAAiB,kBAAkB,QAAQ,eAAe,eAAe;EAC3E,CAAC;EACD,oBAAoB,kBAAkB,QAAQ,kBAAkB;EAChE,eACE,QAAQ,kBAAkB,OACtB,OACA,OAAO,OAAO;GACZ,MAAM,QAAQ,cAAc;GAC5B,YAAY,QAAQ,cAAc;EACpC,CAAC;EACP,YAAY,QAAQ;EACpB,OAAO,OAAO,OACZ,QAAQ,OAAO,MAAM,KAAK,SACxB,OAAO,OAAO;GACZ,QAAQ,KAAK;GACb,UAAU,KAAK;GACf,YAAY,KAAK;GACjB,gBAAgB,OAAO,OACrB,KAAK,eAAe,KAAK,SACvB,OAAO,OAAO;IAAE,OAAO,KAAK;IAAO,OAAO,KAAK;GAAM,CAAC,CACxD,CACF;EACF,CAAC,CACH,CACF;EACA,aAAa,QAAQ;EACrB,WAAW,QAAQ;EACnB,kBAAkB,QAAQ,OAAO;EACjC,kBAAkB,QAAQ,OAAO;EACjC,wBAAwB,QAAQ,OAAO,uBAAuB;EAC9D,kCAAkC,QAAQ,OAAO,uBAAuB;CAC1E,CAAC;AACH;AAEA,eAAsB,uBACpB,gBACA,aACoC;CACpC,IAAI;EACF,MAAM,aAAa,iCAAiC,gBAAgB,WAAW;EAC/E,IAAI,WAAW,SAAS,sBACtB,OAAO,yBAAyB,WAAW,OAAO;EAEpD,IAAI,WAAW,SAAS,gCACtB,OAAO,OAAO,OAAO;GACnB,MAAM;GACN,UAAU;GACV,aAAa,wBAAwB,WAAW,OAAO;GACvD,SAAS,WAAW;EACtB,CAAC;EAEH,IAAI,WAAW,SAAS,yBACtB,OAAO,OAAO,OAAO;GACnB,MAAM;GACN,UAAU;GACV,aAAa,wBAAwB,WAAW,OAAO;GACvD,SAAS,WAAW;EACtB,CAAC;EAEH,OAAO,OAAO,OAAO;GAAE,MAAM;GAAO,UAAU;GAAe,MAAM;EAAe,CAAC;CACrF,QAAQ;EACN,OAAO,OAAO,OAAO;GAAE,MAAM;GAAO,UAAU;GAAe,MAAM;EAAe,CAAC;CACrF;AACF;;;;;;AAOA,eAAe,oBACb,OAC6B;CAC7B,IAAI,MAAM,OAAO,SAAS,SACxB,OAAO,aAAa,mBAAmB,yCAAyC;CAElF,MAAM,QAAQ,MAAM,0BAA0B;EAC5C,OAAO,MAAM;EACb,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,WAAW,MAAM;CACnB,CAAC;CACD,IAAI,MAAM,SACR,OAAO,aAAa,iBAAiB,+BAA+B;CAEtE,IAAI,MAAM,aAAa,MACrB,OAAO,aAAa,yBAAyB,0CAA0C;CAEzF,OAAO;AACT;AAEA,eAAe,oBACb,OACA,QACA,OACsC;CACtC,OAAO,OAAO,OAAO;EACnB,SAAS;EACT,aAAa,MAAM;EACnB,gBAAgB,MAAM,yBAAyB,OAAO,SAAS,MAAM,SAAS;EAC9E,WAAW,MAAM;EACjB,QAAQ,OAAO,OAAO;GAAE,UAAU,MAAM;GAAU,aAAa,MAAM;EAAY,CAAC;EAClF;CACF,CAAC;AACH;AAEA,eAAsB,yBACpB,OACsC;CACtC,MAAM,QAAQ,MAAM,oBAAoB,KAAK;CAC7C,OAAO,oBACL,OACA,MAAM,QACN,MAAM,uBAAuB,MAAM,gBAAgB,MAAM,SAAS,CACpE;AACF;;AAGA,eAAsB,mCACpB,OAGsC;CACtC,MAAM,QAAQ,MAAM,oBAAoB,KAAK;CAC7C,MAAM,QAAQ,iCAAiC,MAAM,gBAAgB,MAAM,SAAS;CACpF,IAAI,MAAM,SAAS,sBACjB,OAAO,aAAa,yBAAyB,6BAA6B;CAC5E,MAAM,WAAW,MAAM,oCACrB,MAAM,qBACN,MAAM,OACR;CACA,OAAO,oBACL,OACA,MAAM,QACN,OAAO,OAAO;EACZ,MAAM;EACN,UAAU;EACV,aAAa,wBAAwB,SAAS,cAAc;EAC5D,SAAS,SAAS;CACpB,CAAC,CACH;AACF;;;;;;;;;AC1UA,eAAsB,4BAA4B,OAKT;CACvC,IACE,CAAC,2BAA2B,KAAK,MAAM,WAAW,KAClD,CAAC,MAAM,gBACP,CAAC,OAAO,cAAc,MAAM,SAAS,KACrC,MAAM,YAAY,GAElB,OAAO,aAAa,yBAAyB,2CAA2C;CAC1F,MAAM,UAAU,oCAAoC,MAAM,OAAO;CACjE,OAAO,OAAO,OAAO;EACnB,SAAS;EACT,aAAa,MAAM;EACnB,gBAAgB,MAAM,yBAAyB,MAAM,cAAc,MAAM,WAAW;EACpF,WAAW,MAAM;EACjB,QAAQ,OAAO,OAAO;GACpB,UAAU,QAAQ,kBAAkB,YAAY;GAChD,aAAa;EACf,CAAC;EACD,OAAO,OAAO,OAAO;GACnB,MAAM;GACN,UAAU;GACV,aAAa,mCAAmC,OAAO;GACvD,YAAY,MAAM,yBAAyB,QAAQ,iBAAiB;GACpE,SAAS,OAAO,OAAO;IACrB,MAAM;IACN,UAAU;IACV,aAAa,wBAAwB,QAAQ,OAAO;IACpD,SAAS,QAAQ;GACnB,CAAC;GACD,QAAQ,QAAQ;GAChB,SAAS,QAAQ;GACjB,YAAY,QAAQ;GACpB,WAAW,QAAQ;GACnB,gBAAgB,QAAQ;EAC1B,CAAC;CACH,CAAC;AACH;;;;;;;;;;;;;;ACNA,eAAe,gBAAgB,aAA+B,OAA8B;CAC1F,IAAI,MAAM,OAAO,SAAS,UACxB,OAAO,aAAa,mBAAmB,oDAAoD;CAC7F,MAAM,SAAS,MAAM,YAAY,yBAAyB,MAAM,OAAO;CACvE,IACE,CAAC,UACD,OAAO,aAAa,MAAM,OAAO,YACjC,OAAO,YAAY,MAAM,OAAO,SAEhC,OAAO,aAAa,mBAAmB,wCAAwC;CACjF,MAAM,UAAU,MAAM,YAAY,4BAA4B,MAAM,SAAS,MAAM,OAAO;CAE1F,OAAO;EAAE;EAAQ,SADD,UAAU;GAAE;GAAS,UAAU,MAAM,aAAa,aAAa,OAAO;EAAE,IAAI;CACnE;AAC3B;AAEA,SAAS,SACP,OACA,OACsC;CACtC,OAAO,OAAO,OAAO;EACnB,SAAS,MAAM,QAAQ,eAAe,kBAAkB;EACxD,SAAS,MAAM,QAAQ,eAAe;EACtC,aAAa,MAAM,QAAQ;EAC3B,WAAW,MAAM,QAAQ;EACzB,QACE,MAAM,UAAU,YACf,SAAS,KAAK,IAAI,MAAM,QAAQ,YAAY,YAAY;CAC7D,CAAC;AACH;AACA,SAAS,SACP,OACA,OACA;CACA,OACE,UAAU,SAAS,MAAM,aAAa,KAAA,KAAa,SAAS,KAAK,KAAK,MAAM,QAAQ;AAExF;;AAGA,eAAsB,2BACpB,OAC+C;CAC/C,OAAO,qBAAqB,MAAM,OAAO,OAAO,gBAAgB;EAC9D,MAAM,EAAE,YAAY,MAAM,gBAAgB,aAAa,KAAK;EAC5D,IAAI,CAAC,SAAS,OAAO,aAAa,mBAAmB,8BAA8B;EACnF,OAAO,SAAS,SAAS,MAAM,KAAK;CACtC,CAAC;AACH;;;;;;;;AASA,eAAsB,4BACpB,OACsE;CACtE,MAAM,EAAE,OAAO,OAAO,KAAK,WAAW,QAAQ,SAAS,SAAS,cAAc,YAAY;CAC1F,IACE,CAAC,OAAO,cAAc,OAAO,KAC7B,UAAU,KACV,CAAC,OAAO,cAAc,YAAY,KAClC,eAAe,GAEf,OAAO,aAAa,yBAAyB,oCAAoC;CACnF,MAAM,SAAS,MAAM,qBAAqB,OAAO,OAAO,gBAAgB;EACtE,MAAM,EAAE,QAAQ,SAAS,YAAY,MAAM,gBAAgB,aAAa,KAAK;EAC7E,IAAI,WAAW,SAAS,SAAS,KAAK,GAAG,OAAO,EAAE,UAAU,SAAS,SAAS,KAAK,EAAE;EACrF,MAAM,QAAQ,iCAAiC,QAAQ,gBAAgB,QAAQ,SAAS;EACxF,MAAM,WAAW,MAAM,YAAY,0BAA0B,OAAO;EACpE,IAAI,MAAM,SAAS,wBAAwB,UAAU,YAAY,YAC/D,OAAO,aAAa,yBAAyB,4BAA4B;EAC3E,MAAM,QAAQ,MAAM,UAAU,uBAAuB,QAAQ;GAC3D,WAAW;GACX,gBAAgB,QAAQ;GACxB;EACF,CAAC;EACD,IAAI,CAAC,OAAO,OAAO,aAAa,mBAAmB,kCAAkC;EACrF,MAAM,WAAW,MAAM,uBACrB,aACA,KACA,SACA,UACA,MAAM,OACR;EACA,IAAI,CAAC,UACH,OAAO,aAAa,2BAA2B,mCAAmC;EACpF,OAAO;GAAE,SAAS,MAAM;GAAS,UAAU,SAAS;GAAW;EAAM;CACvE,CAAC;CACD,IAAI,cAAc,QAAQ,OAAO,OAAO,OAAO;EAAE,GAAG,OAAO;EAAU,SAAS;CAAM,CAAC;CACrF,IAAI;CACJ,IAAI;EACF,iBAAiB,oCACf,MAAM,QAAQ,OAAO,OAAO;GAAE,SAAS,OAAO;GAAS,UAAU,OAAO;GAAU;EAAQ,CAAC,CAAC,CAC9F;CACF,QAAQ;EACN,OAAO,aAAa,yBAAyB,+BAA+B;CAC9E;CACA,IACE,eAAe,YAAY,WAC3B,sBAAsB,eAAe,iBAAiB,MACpD,sBAAsB,OAAO,OAAO,GAEtC,OAAO,aACL,yBACA,qDACF;CACF,OAAO,qBAAqB,OAAO,OAAO,gBAAgB;EACxD,MAAM,EAAE,YAAY,MAAM,gBAAgB,aAAa,KAAK;EAC5D,IAAI,WAAW,SAAS,SAAS,KAAK,GACpC,OAAO,OAAO,OAAO;GAAE,GAAG,SAAS,SAAS,KAAK;GAAG,SAAS;EAAM,CAAC;EACtE,MAAM,YAAY,SAAS,KAAK;EAChC,MAAM,YAAY,UAChB,YAAY,cACZ,qBACA,uBACF;EACA,MAAM,SAAkC,OAAO,OAAO;GACpD,SAAS;GACT,aAAa,8BAA8B,iBAAiB;GAC5D,GAAG,OAAO;GACV;GACA;GACA;EACF,CAAC;EACD,IAAI,CAAE,MAAM,YAAY,wBAAwB,MAAM,GACpD,OAAO,aAAa,yBAAyB,6CAA6C;EAC5F,OAAO,OAAO,OAAO;GACnB,GAAG,SAAS;IAAE,SAAS;IAAQ,UAAU,KAAA;GAAU,GAAG,KAAK;GAC3D,SAAS;EACX,CAAC;CACH,CAAC;AACH;AAQA,eAAe,eAAe,aAA+B,OAA6B;CACxF,IAAI,MAAM,OAAO,SAAS,SACxB,OAAO,aAAa,mBAAmB,uBAAuB;CAChE,MAAM,QAAQ,MAAM,oBAAoB,aAAa,MAAM,WAAW;CACtE,IAAI,MAAM,QAAQ,iBAAiB,MAAM,OAAO,SAC9C,OAAO,aAAa,mBAAmB,qCAAqC;CAC9E,OAAO;AACT;;AAEA,eAAsB,oBAAoB,aAA+B,aAAqB;CAC5F,MAAM,UAAU,MAAM,YAAY,sBAAsB,WAAW;CACnE,IAAI,CAAC,SAAS,OAAO,aAAa,mBAAmB,8BAA8B;CACnF,OAAO;EAAE;EAAS,UAAU,MAAM,aAAa,aAAa,OAAO;CAAE;AACvE;AACA,eAAe,aAAa,aAA+B,SAAkC;CAC3F,MAAM,WAAW,MAAM,YAAY,uBAAuB,QAAQ,WAAW;CAC7E,IACE,aACC,SAAS,YAAY,QAAQ,aAAa,SAAS,YAAY,QAAQ,YAExE,OAAO,aACL,2BACA,kDACF;CACF,OAAO;AACT;AAEA,SAAS,eAAe,SAAkC,OAAmB;CAC3E,IAAI,SAAS,KAAK,IAAI,QAAQ,WAC5B,OAAO,aAAa,iBAAiB,4BAA4B;AACrE;AACA,eAAsB,0BAA0B,OAA6B;CAC3E,MAAM,EAAE,SAAS,aAAa,MAAM,qBAAqB,MAAM,QAAQ,gBACrE,eAAe,aAAa,KAAK,CACnC;CACA,IAAI,UAAU,OAAO,aAAa,yBAAyB,+BAA+B;CAC1F,eAAe,SAAS,MAAM,KAAK;CACnC,OAAO,4BAA4B;EACjC,aAAa,QAAQ;EACrB,cAAc,QAAQ;EACtB,WAAW,QAAQ;EACnB,SAAS,QAAQ;CACnB,CAAC;AACH;AACA,SAAS,OACP,UACA,YAC8B;CAC9B,OAAO,OAAO,OAAO;EACnB,SAAS;EACT,aAAa,SAAS;EACtB,SAAS,SAAS;EAClB,WAAW,SAAS;EACpB;CACF,CAAC;AACH;AACA,eAAsB,mCACpB,OAIuC;CACvC,MAAM,UAAU,MAAM,qBAAqB,MAAM,QAAQ,gBACvD,eAAe,aAAa,KAAK,CACnC;CACA,IAAI,QAAQ,UAAU,OAAO,OAAO,QAAQ,UAAU,UAAU;CAChE,eAAe,QAAQ,SAAS,MAAM,KAAK;CAC3C,MAAM,cACJ,MAAM,QAAQ,YAAY,aACtB,MAAM,aACJ,MAAM,KACN,6CACE,QAAQ,QAAQ,gBAChB,MAAM,QAAQ,QAChB,CACF,IACA;CACN,OAAO,qBAAqB,MAAM,OAAO,OAAO,gBAAgB;EAC9D,MAAM,EAAE,SAAS,aAAa,MAAM,eAAe,aAAa,KAAK;EACrE,IAAI,UAAU,OAAO,OAAO,UAAU,UAAU;EAChD,eAAe,SAAS,MAAM,KAAK;EACnC,MAAM,YAAY,SAAS,MAAM,KAAK;EACtC,IAAI,YAAY,QAAQ,aAAa,YAAY,QAAQ,WACvD,OAAO,aAAa,iBAAiB,wCAAwC;EAC/E,MAAM,SAAmC,OAAO,OAAO;GACrD,SAAS;GACT,aAAa,QAAQ;GACrB,SAAS,MAAM,QAAQ;GACvB;GACA;EACF,CAAC;EACD,IAAI,CAAE,MAAM,YAAY,yBAAyB,MAAM,GACrD,OAAO,aAAa,yBAAyB,8CAA8C;EAC7F,OAAO,OAAO,QAAQ,SAAS;CACjC,CAAC;AACH"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as RelayClock, i as AuthorizationDecisionOutcome, o as AuthorizationOwnerRoute, t as RelayStore } from "./interface-
|
|
2
|
-
import { c as OwnerPhoneRevocationDecision, d as OwnerPhonePermissionApprovals, m as RelayCaller, n as OwnerPhonePushProjection, p as RelayAuthentication, r as OwnerPhoneRequestProjection } from "./projection-
|
|
1
|
+
import { b as RelayClock, i as AuthorizationDecisionOutcome, o as AuthorizationOwnerRoute, t as RelayStore } from "./interface-BVKJY6sm.js";
|
|
2
|
+
import { c as OwnerPhoneRevocationDecision, d as OwnerPhonePermissionApprovals, m as RelayCaller, n as OwnerPhonePushProjection, p as RelayAuthentication, r as OwnerPhoneRequestProjection } from "./projection-CrtZYvxz.js";
|
|
3
3
|
import { t as RelayKms } from "./kms-BWkywdJM.js";
|
|
4
4
|
import { PermissionRequest, ServiceAccount, ServiceBootstrap } from "@oaath/protocol";
|
|
5
5
|
//#region src/authorization/decision.d.ts
|
|
@@ -480,4 +480,4 @@ declare function createServiceDirectory(store: ServiceDirectoryStore): Readonly<
|
|
|
480
480
|
declare function createMemoryServiceDirectoryStore(): ServiceDirectoryStore;
|
|
481
481
|
//#endregion
|
|
482
482
|
export { FetchAuthorizationRequestInput as $, listOwnerPhoneRequests as A, createMemoryOwnerDeviceCredentialStore as B, RequestOwnerPhoneRevocationInput as C, submitOwnerPhoneRevocationDecision as D, requestOwnerPhoneRevocation as E, OAATH_OWNER_DEVICE_CREDENTIAL_VERSION as F, DirectoryOwnerDevice as G, DirectoryAccount as H, OwnerDeviceAuthentication as I, OAATH_SERVICE_DIRECTORY_VERSION as J, DirectorySelection as K, OwnerDeviceCredentialRecord as L, OwnerPhoneDecision as M, SubmitOwnerPhoneDecisionInput as N, OAATH_NATIVE_INBOX_VERSION as O, submitOwnerPhoneDecision as P, CreatedAuthorizationRequest as Q, OwnerDeviceCredentialStore as R, OwnerPhoneRevocationStatus as S, fetchOwnerPhoneRevocation as T, DirectoryApplication as U, createOwnerDeviceAuthentication as V, DirectoryMembership as W, AuthorizationState as X, ServiceDirectoryDocument as Y, CreateAuthorizationRequestInput as Z, SessionSignerIdentity as _, createMemoryServiceDirectoryStore as a, SubmittedAuthorizationDecision as at, RelayRateLimitInput as b, RelayBootstrapSelection as c, RelayPaymasterServiceConfiguration as d, RelayOwnerRouting as et, RelayPaymasterServiceProvider as f, RelaySessionSignerProvider as g, createRelayHandler as h, ServiceDirectoryStore as i, SubmitAuthorizationDecisionInput as it, NATIVE_DISPLAY_PAYLOAD_LENGTH as j, OwnerPhoneInbox as k, RelayHandler as l, RelaySessionSignerConfiguration as m, ServiceDirectory as n, fetchAuthorizationRequest as nt, createServiceDirectory as o, submitAuthorizationDecision as ot, RelayPaymasterServiceRequest as p, DirectoryWorkspace as q, ServiceDirectorySnapshot as r, AuthorizationDecisionCommand as rt, RelayBootstrapConfiguration as s, EnrollOwnerDeviceInput as t, createAuthorizationRequest as tt, RelayHandlerOptions as u, SessionSignerSignRequest as v, fetchClientPhoneRevocation as w, RelayRateLimiter as x, createKmsSessionSignerProvider as y, OwnerDeviceReference as z };
|
|
483
|
-
//# sourceMappingURL=service-
|
|
483
|
+
//# sourceMappingURL=service-Dv3zIiNr.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-
|
|
1
|
+
{"version":3,"file":"service-Dv3zIiNr.d.ts","names":[],"sources":["../src/authorization/decision.ts","../src/authorization/request.ts","../src/directory/records.ts","../src/native/authentication.ts","../src/native/decision.ts","../src/native/display.ts","../src/native/inbox.ts","../src/revocation/service.ts","../src/security/rate-limit.ts","../src/session-signer/kms-provider.ts","../src/relay/handler.ts","../src/directory/service.ts"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oaath/server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "OAAth deployable relay and PostgreSQL boundary.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -79,9 +79,9 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@noble/curves": "1.9.1",
|
|
81
81
|
"@noble/hashes": "2.2.0",
|
|
82
|
-
"@oaath/protocol": "0.3.
|
|
82
|
+
"@oaath/protocol": "0.3.3",
|
|
83
83
|
"pg": "8.22.0",
|
|
84
|
-
"@oaath/sdk": "0.3.
|
|
84
|
+
"@oaath/sdk": "0.3.3"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@types/node": "22.13.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interface-DHpwP0wr.d.ts","names":[],"sources":["../src/clock.ts","../src/revocation/records.ts","../src/relay/errors.ts","../src/store/records.ts","../src/store/interface.ts"],"mappings":";;;;;;;;UAUiB;;EAEf;;;;cCHW;cAEA;UAKI;WACN,gBAAgB;WAChB;WACA;WACA;WACA;WACA;WACA,gBAAgB,SAAS;;UAEnB;WACN,gBAAgB;WAChB;WACA;WACA;;WAEA;;;;KCfC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6DC,oBAAoB,SAAS,OAAO;cAyBpC,wBAAwB;WAC1B,kBAAkB,SAAS;WAC3B,MAAM;WACN,YAAY,SAAS;EAE9B,YACE,MAAM,gBACN,iBACA,aAAY,SAAS,iCACrB,mBAAkB,SAAS;;;;cC3FlB;cAEA;cAEA;cAEA;cAEA;;UAiBI;WACN;WACA;;UAGM,mCAAmC;WACzC,gBAAgB;WAChB;;WAEA;;WAEA;;;;;;WAMA;WACA;;WAEA;;WAEA;WACA;WACA;;KAGC;;;;;UAMK;WACN,gBAAgB;WAChB;WACA,SAAS;WACT;;;;;;;WAOA;WACA;;UAGM;WACN,gBAAgB;;WAEhB;WACA;;WAEA;WACA;WACA;WACA;WACA;WACA;;WAEA;;UAGM;WACN,gBAAgB;WAChB;WACA;WACA;;WAEA;WACA;;WAEA;;;;;;;;;;UAWM;WACN,gBAAgB;WAChB;;WAEA;WACA;WACA;;;;;UC7FM;WACN;WACA;WACA;;UAGM;;EAEf,yBACE,sBACA,aACA,gBACC,iBAAiB;;EAEpB,4BACE,iBACA,kBACC,QAAQ;;EAEX,sBAAsB,sBAAsB,QAAQ;EACpD,wBAAwB,QAAQ,0BAA0B;EAC1D,uBAAuB,sBAAsB,QAAQ;EACrD,yBAAyB,QAAQ,2BAA2B;EAE5D,yBAAyB,oBAAoB,QAAQ;;EAErD,2BAA2B,QAAQ,6BAA6B;EAEhE,0BAA0B,oBAAoB,QAAQ;;EAEtD,4BAA4B,QAAQ,8BAA8B;EAElE,sBAAsB,mBAAmB,QAAQ;EACjD,wBAAwB,QAAQ,0BAA0B;;EAE1D,yBAAyB,kBAAkB,qBAAqB;EAEhE,2BAA2B,kBAAkB,QAAQ;;EAErD,6BAA6B,QAAQ,+BAA+B;EAEpE,sBAAsB,qBAAqB,QAAQ;;EAEnD,iCAAiC,oBAAoB,QAAQ;EAC7D,wBAAwB,QAAQ,0BAA0B;;EAE1D,uBAAuB,oBAAoB,oBAAoB;;EAG/D,UAAU;;EAEV,YAAY;;UAGG;EACf,SAAS,QAAQ;EACjB,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"records-BQNDxbPg.js","names":[],"sources":["../src/relay/errors.ts","../src/store/records.ts"],"sourcesContent":["/**\n * Closed relay failure codes and their stable HTTP projection.\n *\n * Machine decisions and wire responses use these codes only. `Error.message`\n * exists for local diagnostics and never reaches a response body.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport {\n type BundlerRejection,\n captureBundlerRejection,\n captureValidationGasDiagnostic,\n type ValidationGasDiagnostic,\n} from \"@oaath/protocol\";\n\nexport type RelayErrorCode =\n /** Wire input is missing, malformed, oversized, or contains unknown fields. */\n | \"relay_request_invalid\"\n /** The deployment authentication port did not authenticate the caller. */\n | \"relay_unauthenticated\"\n /** Authenticated caller may not act in the required role. */\n | \"relay_forbidden\"\n /** Route, or a record the caller is entitled to see, does not exist. */\n | \"relay_not_found\"\n /** Route exists with a different method. */\n | \"relay_method_not_allowed\"\n /** The authorization request or code is past its injected-clock expiry. */\n | \"relay_expired\"\n /** The authorization request already reached a terminal decision. */\n | \"relay_already_decided\"\n /** The one-time authorization code was already consumed. */\n | \"relay_code_already_consumed\"\n /** The one-time encrypted artifact was already claimed. */\n | \"relay_artifact_already_claimed\"\n /**\n * Authorization code redemption failed. One code for every reason it can\n * fail — unknown code, another client's code, wrong redirect URI, wrong PKCE\n * verifier — so the endpoint never confirms that a guessed code was correct.\n * A code that existed is burned.\n */\n | \"relay_code_invalid\"\n /** The optional deployment limiter rejected the call. */\n | \"relay_rate_limited\"\n /** A durable record could not be read as the current schema version. */\n | \"relay_record_unreadable\"\n /** The KMS port was unavailable or returned an unusable result. */\n | \"relay_kms_unavailable\"\n /** The store failed before any state change could have been committed. */\n | \"relay_store_unavailable\"\n /**\n * The store could not prove whether a transition committed. The caller must\n * treat the transition as neither applied nor retryable: an ambiguous commit\n * never authorizes resubmission.\n */\n | \"relay_state_ambiguous\"\n /**\n * EXPERIMENTAL PREVIEW (`@oaath/server/apns`): the constructed APNs payload\n * exceeded Apple's 4096-byte limit, so nothing was sent.\n */\n | \"relay_apns_payload_too_large\"\n /**\n * EXPERIMENTAL PREVIEW (`@oaath/server/apns`): the injected Apple credential\n * capability is not a usable P-256 signing key, key id, team id, or topic.\n */\n | \"relay_apns_credentials_invalid\"\n /** A deployment-injected chain execution port failed or answered unusably. */\n | \"relay_chain_unavailable\"\n /** The Grant's capability is durably invalidated; nothing more executes here. */\n | \"relay_capability_invalidated\"\n /** An invariant the relay owns was violated. */\n | \"relay_internal\";\n\n/**\n * Status projection. `relay_state_ambiguous` is deliberately 500 and not 503,\n * because 503 invites the retry that an ambiguous commit forbids.\n */\nexport const RELAY_ERROR_STATUS: Readonly<Record<RelayErrorCode, number>> = Object.freeze({\n relay_request_invalid: 400,\n relay_unauthenticated: 401,\n relay_forbidden: 403,\n relay_not_found: 404,\n relay_method_not_allowed: 405,\n relay_expired: 410,\n relay_already_decided: 409,\n relay_code_already_consumed: 409,\n relay_artifact_already_claimed: 409,\n relay_code_invalid: 400,\n relay_rate_limited: 429,\n relay_record_unreadable: 500,\n relay_kms_unavailable: 503,\n relay_store_unavailable: 503,\n relay_state_ambiguous: 500,\n // The preview codes have no route. They are projected only so the union stays\n // closed and one owner keeps every code's status.\n relay_apns_payload_too_large: 500,\n relay_apns_credentials_invalid: 500,\n relay_chain_unavailable: 503,\n relay_capability_invalidated: 409,\n relay_internal: 500,\n});\n\nexport class OaathRelayError extends Error {\n readonly bundlerRejection: Readonly<BundlerRejection> | null;\n readonly code: RelayErrorCode;\n readonly diagnostic: Readonly<ValidationGasDiagnostic> | null;\n\n constructor(\n code: RelayErrorCode,\n message: string,\n diagnostic: Readonly<ValidationGasDiagnostic> | null = null,\n bundlerRejection: Readonly<BundlerRejection> | null = null,\n ) {\n super(message);\n this.name = \"OaathRelayError\";\n this.code = code;\n this.diagnostic = captureValidationGasDiagnostic(diagnostic);\n this.bundlerRejection =\n code === \"relay_chain_unavailable\" ? captureBundlerRejection(bundlerRejection) : null;\n }\n}\n\nexport function relayFailure(\n code: RelayErrorCode,\n message: string,\n diagnostic: Readonly<ValidationGasDiagnostic> | null = null,\n bundlerRejection: Readonly<BundlerRejection> | null = null,\n): never {\n throw new OaathRelayError(code, message, diagnostic, bundlerRejection);\n}\n\n/** Any non-relay throw is an unreadable internal failure, never caller-visible detail. */\nexport function relayErrorCode(error: unknown): RelayErrorCode {\n return error instanceof OaathRelayError ? error.code : \"relay_internal\";\n}\n\nconst RESPONSE_HEADERS: Readonly<Record<string, string>> = Object.freeze({\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n});\n\nexport function relayErrorResponse(\n code: RelayErrorCode,\n diagnostic: Readonly<ValidationGasDiagnostic> | null = null,\n bundlerRejection: Readonly<BundlerRejection> | null = null,\n): Response {\n const captured =\n code === \"relay_chain_unavailable\" ? captureValidationGasDiagnostic(diagnostic) : null;\n const rejection =\n code === \"relay_chain_unavailable\" ? captureBundlerRejection(bundlerRejection) : null;\n return jsonResponse(RELAY_ERROR_STATUS[code], {\n error: {\n code,\n ...(captured === null ? {} : { diagnostic: captured }),\n ...(rejection === null ? {} : { bundlerRejection: rejection }),\n },\n });\n}\n\nexport function jsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), { status, headers: RESPONSE_HEADERS });\n}\n","/**\n * Exact current-version durable relay records.\n *\n * Durable storage is a trust boundary: every read is captured into an exact,\n * owned, immutable record before typed code consumes it. There is exactly one\n * current version per record and no reader for any older version.\n *\n * These shapes are relay-owned for now. `@oaath/protocol` owns the wire\n * `AuthorizationRequest`, `AuthorizationDecision`, and `AuthorizationCode`\n * contracts; adopting them here is a follow-up because the units differ (this\n * store keeps epoch milliseconds, the protocol speaks whole seconds) and the\n * code digest differs (base64url WebCrypto here, `0x` hex there). Once adopted,\n * this file should keep only the store envelope around those records.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { type CaptureContext, exactRecord } from \"@oaath/protocol\";\nimport { type RelayErrorCode, relayFailure } from \"../relay/errors.js\";\n\nexport const OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION =\n \"oaath.authorization-request-record/v2\" as const;\nexport const OAATH_AUTHORIZATION_DECISION_RECORD_VERSION =\n \"oaath.authorization-decision-record/v1\" as const;\nexport const OAATH_AUTHORIZATION_CODE_RECORD_VERSION =\n \"oaath.authorization-code-record/v1\" as const;\nexport const OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION =\n \"oaath.encrypted-artifact-record/v1\" as const;\nexport const OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION =\n \"oaath.capability-invalidation-record/v1\" as const;\n\n/** Bounded field limits owned here and shared with wire capture. */\nexport const RELAY_LIMITS = Object.freeze({\n identifier: 256,\n redirectUri: 2048,\n codeChallenge: 128,\n codeVerifier: 128,\n requestedScope: 8192,\n artifactPlaintext: 32_768,\n ciphertextRef: 65_536,\n});\n\nconst MAX_TIMESTAMP = Number.MAX_SAFE_INTEGER;\n\n/** Deployment-selected device reference and its authenticated approving subject. */\nexport interface AuthorizationOwnerRoute {\n readonly ownerDeviceId: string;\n readonly ownerSubject: string;\n}\n\nexport interface AuthorizationRequestRecord extends AuthorizationOwnerRoute {\n readonly version: typeof OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION;\n readonly requestId: string;\n /** Client bound by the deployment authentication port, never by wire input. */\n readonly clientId: string;\n /** Requesting member's subject, independent of the approving device. */\n readonly subject: string;\n /**\n * Organization/audience bound by the authentication port at creation time,\n * or null when the deployment declares none. Grant reference verification\n * compares assertions against this captured value.\n */\n readonly organizationAudience: string | null;\n readonly redirectUri: string;\n /** PKCE S256 challenge; the verifier never reaches the store. */\n readonly codeChallenge: string;\n /** Opaque owner-reviewed scope payload. Migrates to @oaath/protocol. */\n readonly requestedScope: string;\n readonly createdAt: number;\n readonly expiresAt: number;\n}\n\nexport type AuthorizationDecisionOutcome = \"approved\" | \"rejected\";\n\n/**\n * Terminal decision. Its existence is the single authoritative fact that an\n * authorization request was decided; the request record never mutates.\n */\nexport interface AuthorizationDecisionRecord {\n readonly version: typeof OAATH_AUTHORIZATION_DECISION_RECORD_VERSION;\n readonly requestId: string;\n readonly outcome: AuthorizationDecisionOutcome;\n readonly decidedAt: number;\n /**\n * KMS-sealed copy of the released code for authenticated client pickup, and\n * its expiry. The relay mints the code itself, so holding a sealed copy adds\n * no new trust; PKCE still guards consumption. Both are null exactly when\n * the outcome is a rejection.\n */\n readonly codeRef: string | null;\n readonly codeExpiresAt: number | null;\n}\n\nexport interface AuthorizationCodeRecord {\n readonly version: typeof OAATH_AUTHORIZATION_CODE_RECORD_VERSION;\n /** SHA-256 (base64url) of the released code. The code itself is never stored. */\n readonly codeHash: string;\n readonly requestId: string;\n /** Binding snapshot taken at issue time so consume needs exactly one row lock. */\n readonly clientId: string;\n readonly redirectUri: string;\n readonly codeChallenge: string;\n readonly artifactId: string;\n readonly createdAt: number;\n readonly expiresAt: number;\n /** Set exactly once. A non-null value is terminal. */\n readonly consumedAt: number | null;\n}\n\nexport interface EncryptedArtifactRecord {\n readonly version: typeof OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION;\n readonly artifactId: string;\n readonly requestId: string;\n readonly clientId: string;\n /** Opaque KMS reference. Plaintext never reaches the store. */\n readonly ciphertextRef: string;\n readonly createdAt: number;\n /** Set exactly once. A non-null value is terminal. */\n readonly claimedAt: number | null;\n}\n\n/**\n * One durable capability invalidation: from the moment this record commits,\n * the relay's chain execution routes refuse every submission and usage read\n * for the Grant, so the recorded evidence states an enforced fact — \"this\n * service will no longer act for this capability\" — not a bare digest.\n * Consuming the on-chain install nonce is the chain-local revocation\n * operation's job and stays separate evidence.\n */\nexport interface CapabilityInvalidationRecord {\n readonly version: typeof OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION;\n readonly grantId: string;\n /** The authenticated client that recorded the invalidation. */\n readonly clientId: string;\n readonly capabilityHash: string;\n readonly invalidatedAt: number;\n}\n\nexport function boundedText(\n value: unknown,\n maximum: number,\n label: string,\n code: RelayErrorCode,\n): string {\n if (typeof value !== \"string\" || value.length < 1 || value.length > maximum) {\n return relayFailure(code, `${label} must be a bounded non-empty string`);\n }\n // Control characters would corrupt logs and downstream headers.\n for (let index = 0; index < value.length; index += 1) {\n const unit = value.charCodeAt(index);\n if (unit < 0x20 || unit === 0x7f) {\n return relayFailure(code, `${label} must not contain control characters`);\n }\n }\n return value;\n}\n\nexport function canonicalIdentifier(value: unknown, label: string, code: RelayErrorCode): string {\n const text = boundedText(value, RELAY_LIMITS.identifier, label, code);\n if (!/^[A-Za-z0-9._~-]+$/u.test(text)) {\n return relayFailure(code, `${label} must be URL-safe`);\n }\n return text;\n}\n\nexport function timestamp(value: unknown, label: string, code: RelayErrorCode): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n Object.is(value, -0) ||\n value < 0 ||\n value > MAX_TIMESTAMP\n ) {\n return relayFailure(code, `${label} must be a non-negative safe integer`);\n }\n return value;\n}\n\nfunction nullableTimestamp(value: unknown, label: string, code: RelayErrorCode): number | null {\n return value === null ? null : timestamp(value, label, code);\n}\n\nconst UNREADABLE: RelayErrorCode = \"relay_record_unreadable\";\n\nfunction captured(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {\n const context: CaptureContext = new WeakSet();\n return exactRecord(value, keys, label, context, (message) => relayFailure(UNREADABLE, message));\n}\n\nfunction version<Value extends string>(value: unknown, expected: Value, label: string): Value {\n if (value !== expected) {\n return relayFailure(UNREADABLE, `${label} version is unsupported`);\n }\n return expected;\n}\n\nexport function parseCapabilityInvalidationRecord(value: unknown): CapabilityInvalidationRecord {\n const record = captured(\n value,\n [\"version\", \"grantId\", \"clientId\", \"capabilityHash\", \"invalidatedAt\"],\n \"capability invalidation record\",\n );\n const capabilityHash = boundedText(record.capabilityHash, 66, \"capabilityHash\", UNREADABLE);\n if (!/^0x[0-9a-f]{64}$/u.test(capabilityHash)) {\n return relayFailure(UNREADABLE, \"capabilityHash must be a lowercase 32-byte hash\");\n }\n return Object.freeze({\n version: version(\n record.version,\n OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION,\n \"capability invalidation record\",\n ),\n grantId: canonicalIdentifier(record.grantId, \"grantId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n capabilityHash,\n invalidatedAt: timestamp(record.invalidatedAt, \"invalidatedAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationRequestRecord(value: unknown): AuthorizationRequestRecord {\n const record = captured(\n value,\n [\n \"version\",\n \"requestId\",\n \"clientId\",\n \"subject\",\n \"ownerDeviceId\",\n \"ownerSubject\",\n \"organizationAudience\",\n \"redirectUri\",\n \"codeChallenge\",\n \"requestedScope\",\n \"createdAt\",\n \"expiresAt\",\n ],\n \"authorization request record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n \"authorization request record\",\n ),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n subject: canonicalIdentifier(record.subject, \"subject\", UNREADABLE),\n ownerDeviceId: canonicalIdentifier(record.ownerDeviceId, \"ownerDeviceId\", UNREADABLE),\n ownerSubject: canonicalIdentifier(record.ownerSubject, \"ownerSubject\", UNREADABLE),\n organizationAudience:\n record.organizationAudience === null\n ? null\n : canonicalIdentifier(record.organizationAudience, \"organizationAudience\", UNREADABLE),\n redirectUri: boundedText(\n record.redirectUri,\n RELAY_LIMITS.redirectUri,\n \"redirectUri\",\n UNREADABLE,\n ),\n codeChallenge: canonicalIdentifier(record.codeChallenge, \"codeChallenge\", UNREADABLE),\n requestedScope: boundedText(\n record.requestedScope,\n RELAY_LIMITS.requestedScope,\n \"requestedScope\",\n UNREADABLE,\n ),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n expiresAt: timestamp(record.expiresAt, \"expiresAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationDecisionRecord(value: unknown): AuthorizationDecisionRecord {\n const record = captured(\n value,\n [\"version\", \"requestId\", \"outcome\", \"decidedAt\", \"codeRef\", \"codeExpiresAt\"],\n \"authorization decision record\",\n );\n if (record.outcome !== \"approved\" && record.outcome !== \"rejected\") {\n return relayFailure(UNREADABLE, \"decision outcome is unsupported\");\n }\n // The sealed code exists exactly when a code was released: an approval with\n // no pickup copy or a rejection carrying one is an unreadable record.\n if ((record.outcome === \"approved\") !== (record.codeRef !== null)) {\n return relayFailure(UNREADABLE, \"decision code reference does not match the outcome\");\n }\n if ((record.codeRef === null) !== (record.codeExpiresAt === null)) {\n return relayFailure(UNREADABLE, \"decision code expiry does not match its reference\");\n }\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n \"authorization decision record\",\n ),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n outcome: record.outcome,\n decidedAt: timestamp(record.decidedAt, \"decidedAt\", UNREADABLE),\n codeRef:\n record.codeRef === null\n ? null\n : boundedText(record.codeRef, RELAY_LIMITS.ciphertextRef, \"codeRef\", UNREADABLE),\n codeExpiresAt:\n record.codeExpiresAt === null\n ? null\n : timestamp(record.codeExpiresAt, \"codeExpiresAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationCodeRecord(value: unknown): AuthorizationCodeRecord {\n const record = captured(\n value,\n [\n \"version\",\n \"codeHash\",\n \"requestId\",\n \"clientId\",\n \"redirectUri\",\n \"codeChallenge\",\n \"artifactId\",\n \"createdAt\",\n \"expiresAt\",\n \"consumedAt\",\n ],\n \"authorization code record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n \"authorization code record\",\n ),\n codeHash: canonicalIdentifier(record.codeHash, \"codeHash\", UNREADABLE),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n redirectUri: boundedText(\n record.redirectUri,\n RELAY_LIMITS.redirectUri,\n \"redirectUri\",\n UNREADABLE,\n ),\n codeChallenge: canonicalIdentifier(record.codeChallenge, \"codeChallenge\", UNREADABLE),\n artifactId: canonicalIdentifier(record.artifactId, \"artifactId\", UNREADABLE),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n expiresAt: timestamp(record.expiresAt, \"expiresAt\", UNREADABLE),\n consumedAt: nullableTimestamp(record.consumedAt, \"consumedAt\", UNREADABLE),\n });\n}\n\nexport function parseEncryptedArtifactRecord(value: unknown): EncryptedArtifactRecord {\n const record = captured(\n value,\n [\"version\", \"artifactId\", \"requestId\", \"clientId\", \"ciphertextRef\", \"createdAt\", \"claimedAt\"],\n \"encrypted artifact record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n \"encrypted artifact record\",\n ),\n artifactId: canonicalIdentifier(record.artifactId, \"artifactId\", UNREADABLE),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n ciphertextRef: boundedText(\n record.ciphertextRef,\n RELAY_LIMITS.ciphertextRef,\n \"ciphertextRef\",\n UNREADABLE,\n ),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n claimedAt: nullableTimestamp(record.claimedAt, \"claimedAt\", UNREADABLE),\n });\n}\n"],"mappings":"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"}
|