@oaath/server 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +239 -5
  2. package/dist/apns.d.ts +2 -2
  3. package/dist/apns.js +2 -2
  4. package/dist/{challenge-AGTmUfj2.js → challenge-DmpGSogj.js} +2 -2
  5. package/dist/{challenge-AGTmUfj2.js.map → challenge-DmpGSogj.js.map} +1 -1
  6. package/dist/inbox-B80EUVht.js +249 -0
  7. package/dist/inbox-B80EUVht.js.map +1 -0
  8. package/dist/index.d.ts +9 -255
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +631 -48
  11. package/dist/index.js.map +1 -1
  12. package/dist/interface-DHpwP0wr.d.ts +245 -0
  13. package/dist/interface-DHpwP0wr.d.ts.map +1 -0
  14. package/dist/kernel.d.ts +42 -0
  15. package/dist/kernel.d.ts.map +1 -0
  16. package/dist/kernel.js +80 -0
  17. package/dist/kernel.js.map +1 -0
  18. package/dist/kms-BWkywdJM.d.ts +18 -0
  19. package/dist/kms-BWkywdJM.d.ts.map +1 -0
  20. package/dist/native.d.ts +3 -30
  21. package/dist/native.js +115 -2
  22. package/dist/native.js.map +1 -0
  23. package/dist/postgres.d.ts +38 -3
  24. package/dist/postgres.d.ts.map +1 -1
  25. package/dist/postgres.js +301 -14
  26. package/dist/postgres.js.map +1 -1
  27. package/dist/projection-B7IB9irs.d.ts +228 -0
  28. package/dist/projection-B7IB9irs.d.ts.map +1 -0
  29. package/dist/{records-Bgr-9PUh.js → records-BQNDxbPg.js} +32 -8
  30. package/dist/records-BQNDxbPg.js.map +1 -0
  31. package/dist/records-BUvqmp0D.js +70 -0
  32. package/dist/records-BUvqmp0D.js.map +1 -0
  33. package/dist/service-Cf4f-9KP.js +706 -0
  34. package/dist/service-Cf4f-9KP.js.map +1 -0
  35. package/dist/service-J51bOVe6.d.ts +483 -0
  36. package/dist/service-J51bOVe6.d.ts.map +1 -0
  37. package/package.json +39 -8
  38. package/LICENSE +0 -201
  39. package/dist/authentication-HUYWk5Y2.d.ts +0 -46
  40. package/dist/authentication-HUYWk5Y2.d.ts.map +0 -1
  41. package/dist/decision-dEe9n108.d.ts +0 -53
  42. package/dist/decision-dEe9n108.d.ts.map +0 -1
  43. package/dist/interface-WwvwWs8e.d.ts +0 -114
  44. package/dist/interface-WwvwWs8e.d.ts.map +0 -1
  45. package/dist/native.d.ts.map +0 -1
  46. package/dist/projection-dGIkE0rI.js +0 -516
  47. package/dist/projection-dGIkE0rI.js.map +0 -1
  48. package/dist/projection-g6k_CCUK.d.ts +0 -136
  49. package/dist/projection-g6k_CCUK.d.ts.map +0 -1
  50. package/dist/records-Bgr-9PUh.js.map +0 -1
@@ -0,0 +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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"}