@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
package/dist/apns.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as RelayClock } from "./interface-
|
|
2
|
-
import { n as OwnerPhonePushProjection } from "./projection-
|
|
1
|
+
import { b as RelayClock } from "./interface-BVKJY6sm.js";
|
|
2
|
+
import { n as OwnerPhonePushProjection } from "./projection-CrtZYvxz.js";
|
|
3
3
|
//#region src/apns/sender.d.ts
|
|
4
4
|
/** Apple's hard limit for an alert notification payload. */
|
|
5
5
|
declare const APNS_PAYLOAD_MAX_BYTES = 4096;
|
package/dist/apns.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as relayFailure, c as canonicalIdentifier, m as timestamp, s as boundedText } from "./records-
|
|
2
|
-
import { a as relayNow, n as randomIdentifier } from "./challenge-
|
|
1
|
+
import { b as relayFailure, c as canonicalIdentifier, m as timestamp, s as boundedText } from "./records-Bh8rOpBa.js";
|
|
2
|
+
import { a as relayNow, n as randomIdentifier } from "./challenge-WmeNbyox.js";
|
|
3
3
|
import { exactRecord } from "@oaath/protocol";
|
|
4
4
|
import { createPrivateKey, sign } from "node:crypto";
|
|
5
5
|
//#region src/apns/sender.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as relayFailure, m as timestamp } from "./records-
|
|
1
|
+
import { b as relayFailure, m as timestamp } from "./records-Bh8rOpBa.js";
|
|
2
2
|
//#region src/clock.ts
|
|
3
3
|
/**
|
|
4
4
|
* Injected clock. Expiry is never read from `Date.now()` directly, so tests and
|
|
@@ -68,4 +68,4 @@ function isCodeChallengeS256(value) {
|
|
|
68
68
|
//#endregion
|
|
69
69
|
export { relayNow as a, verifyPkceS256 as i, randomIdentifier as n, sha256Base64Url as r, isCodeChallengeS256 as t };
|
|
70
70
|
|
|
71
|
-
//# sourceMappingURL=challenge-
|
|
71
|
+
//# sourceMappingURL=challenge-WmeNbyox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"challenge-
|
|
1
|
+
{"version":3,"file":"challenge-WmeNbyox.js","names":[],"sources":["../src/clock.ts","../src/authorization/challenge.ts"],"sourcesContent":["/**\n * Injected clock. Expiry is never read from `Date.now()` directly, so tests and\n * deployments own time.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { relayFailure } from \"./relay/errors.js\";\nimport { timestamp } from \"./store/records.js\";\n\nexport interface RelayClock {\n /** Milliseconds since the Unix epoch as a non-negative safe integer. */\n now(): number;\n}\n\nexport function relayNow(clock: RelayClock): number {\n let value: unknown;\n try {\n value = clock.now();\n } catch {\n return relayFailure(\"relay_internal\", \"injected clock failed\");\n }\n return timestamp(value, \"clock time\", \"relay_internal\");\n}\n","/**\n * PKCE S256 challenge verification and the relay's random/digest primitives.\n *\n * Only WebCrypto and base64url are used, so this file stays platform-neutral.\n * The verifier is never stored: the store holds the S256 challenge, and consume\n * recomputes it.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { relayFailure } from \"../relay/errors.js\";\n\n/** RFC 7636 code verifier: 43-128 unreserved characters. */\nconst CODE_VERIFIER = /^[A-Za-z0-9._~-]{43,128}$/u;\n\nconst IDENTIFIER_BYTES = 32;\n\nfunction base64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replaceAll(\"=\", \"\");\n}\n\n/** 256 bits of CSPRNG output, base64url encoded. */\nexport function randomIdentifier(): string {\n return base64Url(crypto.getRandomValues(new Uint8Array(IDENTIFIER_BYTES)));\n}\n\nexport async function sha256Base64Url(value: string): Promise<string> {\n let digest: ArrayBuffer;\n try {\n digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(value));\n } catch {\n return relayFailure(\"relay_internal\", \"WebCrypto SHA-256 is unavailable\");\n }\n return base64Url(new Uint8Array(digest));\n}\n\nfunction timingSafeEqualText(left: string, right: string): boolean {\n // Both operands are base64url digests, so length is not itself a secret.\n if (left.length !== right.length) return false;\n let difference = 0;\n for (let index = 0; index < left.length; index += 1) {\n difference |= left.charCodeAt(index) ^ right.charCodeAt(index);\n }\n return difference === 0;\n}\n\n/**\n * True only when `codeVerifier` is a well-formed RFC 7636 verifier whose S256\n * digest equals the stored challenge. Any malformed input is a mismatch.\n */\nexport async function verifyPkceS256(\n codeVerifier: string,\n storedCodeChallenge: string,\n): Promise<boolean> {\n if (!CODE_VERIFIER.test(codeVerifier)) return false;\n return timingSafeEqualText(await sha256Base64Url(codeVerifier), storedCodeChallenge);\n}\n\n/** True when the value can be a stored S256 challenge (43 base64url characters). */\nexport function isCodeChallengeS256(value: string): boolean {\n return /^[A-Za-z0-9_-]{43}$/u.test(value);\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,SAAS,OAA2B;CAClD,IAAI;CACJ,IAAI;EACF,QAAQ,MAAM,IAAI;CACpB,QAAQ;EACN,OAAO,aAAa,kBAAkB,uBAAuB;CAC/D;CACA,OAAO,UAAU,OAAO,cAAc,gBAAgB;AACxD;;;;;;;;;;;;;ACVA,MAAM,gBAAgB;AAEtB,MAAM,mBAAmB;AAEzB,SAAS,UAAU,OAA2B;CAC5C,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,OAAO,UAAU,OAAO,aAAa,IAAI;CAC5D,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,WAAW,KAAK,EAAE;AAClF;;AAGA,SAAgB,mBAA2B;CACzC,OAAO,UAAU,OAAO,gBAAgB,IAAI,WAAW,gBAAgB,CAAC,CAAC;AAC3E;AAEA,eAAsB,gBAAgB,OAAgC;CACpE,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAAC;CAChF,QAAQ;EACN,OAAO,aAAa,kBAAkB,kCAAkC;CAC1E;CACA,OAAO,UAAU,IAAI,WAAW,MAAM,CAAC;AACzC;AAEA,SAAS,oBAAoB,MAAc,OAAwB;CAEjE,IAAI,KAAK,WAAW,MAAM,QAAQ,OAAO;CACzC,IAAI,aAAa;CACjB,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAChD,cAAc,KAAK,WAAW,KAAK,IAAI,MAAM,WAAW,KAAK;CAE/D,OAAO,eAAe;AACxB;;;;;AAMA,eAAsB,eACpB,cACA,qBACkB;CAClB,IAAI,CAAC,cAAc,KAAK,YAAY,GAAG,OAAO;CAC9C,OAAO,oBAAoB,MAAM,gBAAgB,YAAY,GAAG,mBAAmB;AACrF;;AAGA,SAAgB,oBAAoB,OAAwB;CAC1D,OAAO,uBAAuB,KAAK,KAAK;AAC1C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { b as relayFailure, h as OaathRelayError, n as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION } from "./records-
|
|
2
|
-
import { a as relayNow, n as randomIdentifier, r as sha256Base64Url } from "./challenge-
|
|
3
|
-
import { S as withRelayTransaction, _ as verifyKernelV4ReplayableInstallOwnerSigningArtifact, d as classifyStoredAuthorizationScope, g as ownerPhoneDisplayPayload, p as fetchAuthorizationRequest, u as prepareOwnerPhonePermissionApproval, v as parseApprovedPermission, x as sealArtifact } from "./service-
|
|
1
|
+
import { b as relayFailure, h as OaathRelayError, n as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION } from "./records-Bh8rOpBa.js";
|
|
2
|
+
import { a as relayNow, n as randomIdentifier, r as sha256Base64Url } from "./challenge-WmeNbyox.js";
|
|
3
|
+
import { S as withRelayTransaction, _ as verifyKernelV4ReplayableInstallOwnerSigningArtifact, d as classifyStoredAuthorizationScope, g as ownerPhoneDisplayPayload, p as fetchAuthorizationRequest, u as prepareOwnerPhonePermissionApproval, v as parseApprovedPermission, x as sealArtifact } from "./service-DT0vkKop.js";
|
|
4
4
|
import { parseOwnerSigningArtifact } from "@oaath/protocol";
|
|
5
5
|
//#region src/authorization/decision.ts
|
|
6
6
|
/**
|
|
@@ -246,4 +246,4 @@ async function listOwnerPhoneRequests(input) {
|
|
|
246
246
|
//#endregion
|
|
247
247
|
export { submitAuthorizationDecision as i, listOwnerPhoneRequests as n, submitOwnerPhoneDecision as r, OAATH_NATIVE_INBOX_VERSION as t };
|
|
248
248
|
|
|
249
|
-
//# sourceMappingURL=inbox-
|
|
249
|
+
//# sourceMappingURL=inbox-BKXNtsX3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbox-B80EUVht.js","names":[],"sources":["../src/authorization/decision.ts","../src/native/decision.ts","../src/native/inbox.ts"],"sourcesContent":["/**\n * Authoritative approve/reject transition.\n *\n * ```text\n * state and owner the decision record owns \"decided\"; the request record\n * never mutates\n * persisted evidence the immutable requestedScope is reclassified from the\n * durable request before every approval attempt; the\n * artifact must carry its valid bound approval\n * resource occupied? a refused approval occupies nothing and performs no KMS\n * sealing; a rejection occupies only its decision row\n * retry positively safe? refused approval is read-only; a terminal outcome is\n * replayed by the native saga and rejected by this owner\n * transitions permission or verified Kernel owner signing:\n * undecided -> approved | rejected;\n * every reject-only scope: undecided -> rejected once\n * terminal both outcomes; a second decide fails relay_already_decided\n * crash/reload the decision, the code, and the sealed artifact commit in\n * one transaction on the row-locked request, so a crash\n * leaves the request undecided and nothing released\n * cleanup owner the relay transaction; refused approvals allocate nothing\n * ```\n *\n * Owner binding: the approving subject is recovered from the stored\n * authorization request by `requestId` and compared against the authenticated\n * owner. No wire field names the subject. A decision envelope that carries a\n * subject identifier is rejected as an unknown field by exact capture, because a\n * field that only *names* a subject is not cryptographically bound to it and can\n * never decide authority.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { sealArtifact } from \"../artifact/encrypt.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport { withRelayTransaction } from \"../store/interface.js\";\nimport {\n OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n} from \"../store/records.js\";\nimport { parseApprovedPermission } from \"./approved-permission.js\";\nimport { randomIdentifier, sha256Base64Url } from \"./challenge.js\";\nimport { verifyKernelV4ReplayableInstallOwnerSigningArtifact } from \"./owner-signing.js\";\nimport { fetchAuthorizationRequest } from \"./request.js\";\nimport { classifyStoredAuthorizationScope } from \"./scope.js\";\n\nexport type AuthorizationDecisionCommand =\n /** The owner supplies a request-bound approval artifact; the client claims it once. */\n Readonly<{ outcome: \"approved\"; artifact: string }> | Readonly<{ outcome: \"rejected\" }>;\n\nexport interface SubmitAuthorizationDecisionInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n /** Authenticated `owner` caller; only the bound subject may decide. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n readonly command: AuthorizationDecisionCommand;\n readonly codeTtlMs: number;\n}\n\nexport type SubmittedAuthorizationDecision =\n | Readonly<{\n outcome: \"approved\";\n decidedAt: number;\n /** Released exactly once, here. Only its SHA-256 is stored. */\n code: string;\n artifactId: string;\n redirectUri: string;\n codeExpiresAt: number;\n }>\n | Readonly<{ outcome: \"rejected\"; decidedAt: number }>;\n\nexport async function submitAuthorizationDecision(\n input: SubmitAuthorizationDecisionInput,\n): Promise<SubmittedAuthorizationDecision> {\n const decidedAt = relayNow(input.clock);\n let approvedArtifact: string | undefined;\n\n // Approval is the artifact-creating transition, so the shared decision owner\n // admits it only for an exact scope this server currently permits to release.\n // Refusal happens before KMS sealing or any durable decision/code/artifact.\n if (input.command.outcome === \"approved\") {\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.requestId,\n });\n // Preserve the transaction owner's existing precedence: the native saga\n // must recover an earlier terminal outcome without reclassifying its scope.\n if (state.decision !== null) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (state.expired) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n const scope = classifyStoredAuthorizationScope(state.requestedScope, state.requestId);\n if (scope.kind === \"permission-request\") {\n try {\n approvedArtifact = parseApprovedPermission(\n input.command.artifact,\n scope.request,\n decidedAt,\n ).plaintext;\n } catch {\n return relayFailure(\"relay_request_invalid\", \"permission approval artifact is invalid\");\n }\n } else if (scope.kind === \"kernel-owner-signing-request\") {\n approvedArtifact = verifyKernelV4ReplayableInstallOwnerSigningArtifact(\n scope.request,\n input.command.artifact,\n );\n } else {\n return relayFailure(\"relay_request_invalid\", \"the authorization scope is reject-only\");\n }\n }\n\n // Seal before the transaction: the store only ever receives references, and\n // an uncommitted decision leaves nothing but unreferenced ciphertexts. The\n // code is sealed too so the authenticated client can pick it up later; PKCE\n // still guards its consumption.\n let approved:\n | Readonly<{ code: string; artifactId: string; ciphertextRef: string; codeRef: string }>\n | undefined;\n if (input.command.outcome === \"approved\") {\n if (approvedArtifact === undefined) {\n return relayFailure(\"relay_internal\", \"approved artifact was not authorized\");\n }\n const code = randomIdentifier();\n approved = Object.freeze({\n code,\n artifactId: randomIdentifier(),\n ciphertextRef: await sealArtifact(input.kms, approvedArtifact),\n codeRef: await sealArtifact(input.kms, code),\n });\n }\n const codeHash = approved ? await sha256Base64Url(approved.code) : undefined;\n const decision = Object.freeze({\n version: OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n requestId: input.requestId,\n outcome: input.command.outcome,\n decidedAt,\n codeRef: approved?.codeRef ?? null,\n codeExpiresAt: approved ? decidedAt + input.codeTtlMs : null,\n } as const);\n\n const redirectUri = await withRelayTransaction(input.store, async (transaction) => {\n const request = await transaction.lockAuthorizationRequest(input.requestId);\n // The request snapshots its approving subject independently of its requester.\n if (!request || request.ownerSubject !== input.caller.subject) {\n return relayFailure(\"relay_not_found\", \"authorization request does not exist\");\n }\n if (await transaction.lockAuthorizationDecision(input.requestId)) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (decidedAt >= request.expiresAt) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n if (!(await transaction.insertAuthorizationDecision(decision))) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (approved && codeHash !== undefined) {\n const inserted =\n (await transaction.insertAuthorizationCode(\n Object.freeze({\n version: OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n codeHash,\n requestId: request.requestId,\n clientId: request.clientId,\n redirectUri: request.redirectUri,\n codeChallenge: request.codeChallenge,\n artifactId: approved.artifactId,\n createdAt: decidedAt,\n expiresAt: decidedAt + input.codeTtlMs,\n consumedAt: null,\n }),\n )) &&\n (await transaction.insertEncryptedArtifact(\n Object.freeze({\n version: OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n artifactId: approved.artifactId,\n requestId: request.requestId,\n clientId: request.clientId,\n ciphertextRef: approved.ciphertextRef,\n createdAt: decidedAt,\n claimedAt: null,\n }),\n ));\n if (!inserted) {\n return relayFailure(\"relay_internal\", \"released identifier is not unique\");\n }\n }\n return request.redirectUri;\n });\n\n if (approved && codeHash !== undefined) {\n return Object.freeze({\n outcome: \"approved\",\n decidedAt,\n code: approved.code,\n artifactId: approved.artifactId,\n redirectUri,\n codeExpiresAt: decidedAt + input.codeTtlMs,\n });\n }\n return Object.freeze({ outcome: \"rejected\", decidedAt });\n}\n","/**\n * EXPERIMENTAL PREVIEW — approve/reject saga keyed by the stable operation id.\n *\n * ```text\n * state and owner the relay's authorization decision record. This saga\n * owns no decision state of its own and keeps nothing in\n * memory; it routes to `submitAuthorizationDecision`.\n * persisted evidence one terminal decision row per request\n * resource occupied? yes: the decision occupies its request, and the\n * one-time code and artifact are released exactly once\n * retry positively safe? yes for the saga call, because a repeated call never\n * decides again: it answers the stored outcome\n * transitions undecided -> approved | rejected once, then replay-only\n * crash/reload the outcome is durable before the caller sees it, so a\n * phone that never saw its response retries and is\n * answered from the store, on any process\n * cleanup owner the relay transaction; nothing extra is allocated here\n * ```\n *\n * A second decide answers the *stored* outcome, not the resubmitted command: if\n * a rejected request is retried as approved, the answer is `rejected`. Compare\n * `outcome` against what you sent when that matters.\n *\n * The one-time code and encrypted artifact are released to the deciding call\n * only. A replay reports the outcome and no release material, because releasing\n * it twice is exactly what one-shot semantics forbid.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { type OwnerSigningArtifact, parseOwnerSigningArtifact } from \"@oaath/protocol\";\nimport type {\n AuthorizationDecisionCommand,\n SubmittedAuthorizationDecision,\n} from \"../authorization/decision.js\";\nimport { submitAuthorizationDecision } from \"../authorization/decision.js\";\nimport { fetchAuthorizationRequest } from \"../authorization/request.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { OaathRelayError, relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport type { AuthorizationDecisionOutcome } from \"../store/records.js\";\nimport {\n type OwnerPhonePermissionApprovals,\n prepareOwnerPhonePermissionApproval,\n} from \"./permission-approval.js\";\n\nexport interface SubmitOwnerPhoneDecisionInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n /** Authenticated `owner` caller; only the bound subject may decide. */\n readonly caller: RelayCaller;\n /** `operationId` from `projectOwnerPhoneRequest`. */\n readonly operationId: string;\n readonly command: AuthorizationDecisionCommand;\n readonly codeTtlMs: number;\n readonly permissionApprovals?: OwnerPhonePermissionApprovals;\n}\n\nexport interface OwnerPhoneDecision {\n readonly operationId: string;\n /** The stored outcome, which on a replay may differ from the command sent. */\n readonly outcome: AuthorizationDecisionOutcome;\n readonly decidedAt: number;\n /** `decided` performed the transition; `replayed` answered the stored one. */\n readonly settlement: \"decided\" | \"replayed\";\n /** One-time release material, on the deciding call only. */\n readonly release: SubmittedAuthorizationDecision | null;\n}\n\nexport async function submitOwnerPhoneDecision(\n input: SubmitOwnerPhoneDecisionInput,\n): Promise<OwnerPhoneDecision> {\n if (input.caller.role !== \"owner\") {\n return relayFailure(\"relay_forbidden\", \"caller may not act in the required role\");\n }\n const pending = await fetchAuthorizationRequest({ ...input, requestId: input.operationId });\n // A committed outcome wins before preparation, even if the provider is now unavailable.\n if (pending.decision !== null)\n return Object.freeze({\n operationId: input.operationId,\n outcome: pending.decision.outcome,\n decidedAt: pending.decision.decidedAt,\n settlement: \"replayed\",\n release: null,\n });\n let command = input.command;\n if (command.outcome === \"approved\" && !pending.expired) {\n const scope = classifyStoredAuthorizationScope(pending.requestedScope, pending.requestId);\n if (scope.kind === \"permission-request\") {\n const prepared = await prepareOwnerPhonePermissionApproval(\n input.permissionApprovals,\n scope.request,\n );\n let artifact: Readonly<OwnerSigningArtifact>;\n try {\n artifact = parseOwnerSigningArtifact(JSON.parse(command.artifact));\n } catch {\n return relayFailure(\"relay_request_invalid\", \"phone signing artifact is invalid\");\n }\n command = {\n outcome: \"approved\",\n artifact: await prepared.complete(artifact, Math.floor(relayNow(input.clock) / 1000)),\n };\n }\n }\n try {\n const release = await submitAuthorizationDecision({\n store: input.store,\n clock: input.clock,\n kms: input.kms,\n caller: input.caller,\n requestId: input.operationId,\n command,\n codeTtlMs: input.codeTtlMs,\n });\n return Object.freeze({\n operationId: input.operationId,\n outcome: release.outcome,\n decidedAt: release.decidedAt,\n settlement: \"decided\",\n release,\n });\n } catch (error) {\n // Only \"already decided\" is idempotent. Ambiguous, expired, unauthorized,\n // and unreadable stay failures: an unproven commit never becomes an answer.\n if (!(error instanceof OaathRelayError) || error.code !== \"relay_already_decided\") throw error;\n }\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.operationId,\n });\n if (state.decision === null) {\n return relayFailure(\"relay_internal\", \"decided request has no decision record\");\n }\n return Object.freeze({\n operationId: input.operationId,\n outcome: state.decision.outcome,\n decidedAt: state.decision.decidedAt,\n settlement: \"replayed\",\n release: null,\n });\n}\n","/**\n * Read-only owner inbox derived from retained relay requests and decisions.\n * No delivery state, lease or second queue is persisted. Recreating the service\n * reads the same pending requests; deciding or expiring one removes it from the\n * next listing. A summary is discovery only: consent/decision checks current state.\n */\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport { type RelayStore, withRelayTransaction } from \"../store/interface.js\";\nimport { ownerPhoneDisplayPayload } from \"./display.js\";\nimport type { OwnerPhonePushProjection } from \"./projection.js\";\n\nexport const OAATH_NATIVE_INBOX_VERSION = \"oaath.native-inbox/v1\" as const;\nconst INBOX_LIMIT = 20;\n\nexport interface OwnerPhoneInbox {\n readonly version: typeof OAATH_NATIVE_INBOX_VERSION;\n readonly requests: readonly Readonly<OwnerPhonePushProjection>[];\n}\n\n/** The store owns transaction resources; this read prepares, signs and submits nothing. */\nexport async function listOwnerPhoneRequests(input: {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly caller: RelayCaller;\n}): Promise<Readonly<OwnerPhoneInbox>> {\n if (input.caller.role !== \"owner\")\n return relayFailure(\"relay_forbidden\", \"only an owner may read the inbox\");\n const now = relayNow(input.clock);\n const requests = await withRelayTransaction(input.store, (transaction) =>\n transaction.listPendingOwnerRequests(input.caller.subject, now, INBOX_LIMIT),\n );\n if (requests.length > INBOX_LIMIT)\n return relayFailure(\"relay_record_unreadable\", \"owner inbox is unbounded\");\n return Object.freeze({\n version: OAATH_NATIVE_INBOX_VERSION,\n requests: Object.freeze(\n await Promise.all(\n requests.map(async (request) => {\n if (request.ownerSubject !== input.caller.subject || request.expiresAt <= now) {\n return relayFailure(\n \"relay_record_unreadable\",\n \"pending request does not match this owner inbox\",\n );\n }\n return Object.freeze({\n operationId: request.operationId,\n expiresAt: request.expiresAt,\n displayPayload: await ownerPhoneDisplayPayload(\n request.ownerSubject,\n request.operationId,\n ),\n });\n }),\n ),\n ),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inbox-BKXNtsX3.js","names":[],"sources":["../src/authorization/decision.ts","../src/native/decision.ts","../src/native/inbox.ts"],"sourcesContent":["/**\n * Authoritative approve/reject transition.\n *\n * ```text\n * state and owner the decision record owns \"decided\"; the request record\n * never mutates\n * persisted evidence the immutable requestedScope is reclassified from the\n * durable request before every approval attempt; the\n * artifact must carry its valid bound approval\n * resource occupied? a refused approval occupies nothing and performs no KMS\n * sealing; a rejection occupies only its decision row\n * retry positively safe? refused approval is read-only; a terminal outcome is\n * replayed by the native saga and rejected by this owner\n * transitions permission or verified Kernel owner signing:\n * undecided -> approved | rejected;\n * every reject-only scope: undecided -> rejected once\n * terminal both outcomes; a second decide fails relay_already_decided\n * crash/reload the decision, the code, and the sealed artifact commit in\n * one transaction on the row-locked request, so a crash\n * leaves the request undecided and nothing released\n * cleanup owner the relay transaction; refused approvals allocate nothing\n * ```\n *\n * Owner binding: the approving subject is recovered from the stored\n * authorization request by `requestId` and compared against the authenticated\n * owner. No wire field names the subject. A decision envelope that carries a\n * subject identifier is rejected as an unknown field by exact capture, because a\n * field that only *names* a subject is not cryptographically bound to it and can\n * never decide authority.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { sealArtifact } from \"../artifact/encrypt.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport { withRelayTransaction } from \"../store/interface.js\";\nimport {\n OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n} from \"../store/records.js\";\nimport { parseApprovedPermission } from \"./approved-permission.js\";\nimport { randomIdentifier, sha256Base64Url } from \"./challenge.js\";\nimport { verifyKernelV4ReplayableInstallOwnerSigningArtifact } from \"./owner-signing.js\";\nimport { fetchAuthorizationRequest } from \"./request.js\";\nimport { classifyStoredAuthorizationScope } from \"./scope.js\";\n\nexport type AuthorizationDecisionCommand =\n /** The owner supplies a request-bound approval artifact; the client claims it once. */\n Readonly<{ outcome: \"approved\"; artifact: string }> | Readonly<{ outcome: \"rejected\" }>;\n\nexport interface SubmitAuthorizationDecisionInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n /** Authenticated `owner` caller; only the bound subject may decide. */\n readonly caller: RelayCaller;\n readonly requestId: string;\n readonly command: AuthorizationDecisionCommand;\n readonly codeTtlMs: number;\n}\n\nexport type SubmittedAuthorizationDecision =\n | Readonly<{\n outcome: \"approved\";\n decidedAt: number;\n /** Released exactly once, here. Only its SHA-256 is stored. */\n code: string;\n artifactId: string;\n redirectUri: string;\n codeExpiresAt: number;\n }>\n | Readonly<{ outcome: \"rejected\"; decidedAt: number }>;\n\nexport async function submitAuthorizationDecision(\n input: SubmitAuthorizationDecisionInput,\n): Promise<SubmittedAuthorizationDecision> {\n const decidedAt = relayNow(input.clock);\n let approvedArtifact: string | undefined;\n\n // Approval is the artifact-creating transition, so the shared decision owner\n // admits it only for an exact scope this server currently permits to release.\n // Refusal happens before KMS sealing or any durable decision/code/artifact.\n if (input.command.outcome === \"approved\") {\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.requestId,\n });\n // Preserve the transaction owner's existing precedence: the native saga\n // must recover an earlier terminal outcome without reclassifying its scope.\n if (state.decision !== null) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (state.expired) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n const scope = classifyStoredAuthorizationScope(state.requestedScope, state.requestId);\n if (scope.kind === \"permission-request\") {\n try {\n approvedArtifact = parseApprovedPermission(\n input.command.artifact,\n scope.request,\n decidedAt,\n ).plaintext;\n } catch {\n return relayFailure(\"relay_request_invalid\", \"permission approval artifact is invalid\");\n }\n } else if (scope.kind === \"kernel-owner-signing-request\") {\n approvedArtifact = verifyKernelV4ReplayableInstallOwnerSigningArtifact(\n scope.request,\n input.command.artifact,\n );\n } else {\n return relayFailure(\"relay_request_invalid\", \"the authorization scope is reject-only\");\n }\n }\n\n // Seal before the transaction: the store only ever receives references, and\n // an uncommitted decision leaves nothing but unreferenced ciphertexts. The\n // code is sealed too so the authenticated client can pick it up later; PKCE\n // still guards its consumption.\n let approved:\n | Readonly<{ code: string; artifactId: string; ciphertextRef: string; codeRef: string }>\n | undefined;\n if (input.command.outcome === \"approved\") {\n if (approvedArtifact === undefined) {\n return relayFailure(\"relay_internal\", \"approved artifact was not authorized\");\n }\n const code = randomIdentifier();\n approved = Object.freeze({\n code,\n artifactId: randomIdentifier(),\n ciphertextRef: await sealArtifact(input.kms, approvedArtifact),\n codeRef: await sealArtifact(input.kms, code),\n });\n }\n const codeHash = approved ? await sha256Base64Url(approved.code) : undefined;\n const decision = Object.freeze({\n version: OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n requestId: input.requestId,\n outcome: input.command.outcome,\n decidedAt,\n codeRef: approved?.codeRef ?? null,\n codeExpiresAt: approved ? decidedAt + input.codeTtlMs : null,\n } as const);\n\n const redirectUri = await withRelayTransaction(input.store, async (transaction) => {\n const request = await transaction.lockAuthorizationRequest(input.requestId);\n // The request snapshots its approving subject independently of its requester.\n if (!request || request.ownerSubject !== input.caller.subject) {\n return relayFailure(\"relay_not_found\", \"authorization request does not exist\");\n }\n if (await transaction.lockAuthorizationDecision(input.requestId)) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (decidedAt >= request.expiresAt) {\n return relayFailure(\"relay_expired\", \"authorization request expired\");\n }\n if (!(await transaction.insertAuthorizationDecision(decision))) {\n return relayFailure(\"relay_already_decided\", \"authorization request is already decided\");\n }\n if (approved && codeHash !== undefined) {\n const inserted =\n (await transaction.insertAuthorizationCode(\n Object.freeze({\n version: OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n codeHash,\n requestId: request.requestId,\n clientId: request.clientId,\n redirectUri: request.redirectUri,\n codeChallenge: request.codeChallenge,\n artifactId: approved.artifactId,\n createdAt: decidedAt,\n expiresAt: decidedAt + input.codeTtlMs,\n consumedAt: null,\n }),\n )) &&\n (await transaction.insertEncryptedArtifact(\n Object.freeze({\n version: OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n artifactId: approved.artifactId,\n requestId: request.requestId,\n clientId: request.clientId,\n ciphertextRef: approved.ciphertextRef,\n createdAt: decidedAt,\n claimedAt: null,\n }),\n ));\n if (!inserted) {\n return relayFailure(\"relay_internal\", \"released identifier is not unique\");\n }\n }\n return request.redirectUri;\n });\n\n if (approved && codeHash !== undefined) {\n return Object.freeze({\n outcome: \"approved\",\n decidedAt,\n code: approved.code,\n artifactId: approved.artifactId,\n redirectUri,\n codeExpiresAt: decidedAt + input.codeTtlMs,\n });\n }\n return Object.freeze({ outcome: \"rejected\", decidedAt });\n}\n","/**\n * EXPERIMENTAL PREVIEW — approve/reject saga keyed by the stable operation id.\n *\n * ```text\n * state and owner the relay's authorization decision record. This saga\n * owns no decision state of its own and keeps nothing in\n * memory; it routes to `submitAuthorizationDecision`.\n * persisted evidence one terminal decision row per request\n * resource occupied? yes: the decision occupies its request, and the\n * one-time code and artifact are released exactly once\n * retry positively safe? yes for the saga call, because a repeated call never\n * decides again: it answers the stored outcome\n * transitions undecided -> approved | rejected once, then replay-only\n * crash/reload the outcome is durable before the caller sees it, so a\n * phone that never saw its response retries and is\n * answered from the store, on any process\n * cleanup owner the relay transaction; nothing extra is allocated here\n * ```\n *\n * A second decide answers the *stored* outcome, not the resubmitted command: if\n * a rejected request is retried as approved, the answer is `rejected`. Compare\n * `outcome` against what you sent when that matters.\n *\n * The one-time code and encrypted artifact are released to the deciding call\n * only. A replay reports the outcome and no release material, because releasing\n * it twice is exactly what one-shot semantics forbid.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { type OwnerSigningArtifact, parseOwnerSigningArtifact } from \"@oaath/protocol\";\nimport type {\n AuthorizationDecisionCommand,\n SubmittedAuthorizationDecision,\n} from \"../authorization/decision.js\";\nimport { submitAuthorizationDecision } from \"../authorization/decision.js\";\nimport { fetchAuthorizationRequest } from \"../authorization/request.js\";\nimport { classifyStoredAuthorizationScope } from \"../authorization/scope.js\";\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { OaathRelayError, relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport type { RelayKms } from \"../security/kms.js\";\nimport type { RelayStore } from \"../store/interface.js\";\nimport type { AuthorizationDecisionOutcome } from \"../store/records.js\";\nimport {\n type OwnerPhonePermissionApprovals,\n prepareOwnerPhonePermissionApproval,\n} from \"./permission-approval.js\";\n\nexport interface SubmitOwnerPhoneDecisionInput {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly kms: RelayKms;\n /** Authenticated `owner` caller; only the bound subject may decide. */\n readonly caller: RelayCaller;\n /** `operationId` from `projectOwnerPhoneRequest`. */\n readonly operationId: string;\n readonly command: AuthorizationDecisionCommand;\n readonly codeTtlMs: number;\n readonly permissionApprovals?: OwnerPhonePermissionApprovals;\n}\n\nexport interface OwnerPhoneDecision {\n readonly operationId: string;\n /** The stored outcome, which on a replay may differ from the command sent. */\n readonly outcome: AuthorizationDecisionOutcome;\n readonly decidedAt: number;\n /** `decided` performed the transition; `replayed` answered the stored one. */\n readonly settlement: \"decided\" | \"replayed\";\n /** One-time release material, on the deciding call only. */\n readonly release: SubmittedAuthorizationDecision | null;\n}\n\nexport async function submitOwnerPhoneDecision(\n input: SubmitOwnerPhoneDecisionInput,\n): Promise<OwnerPhoneDecision> {\n if (input.caller.role !== \"owner\") {\n return relayFailure(\"relay_forbidden\", \"caller may not act in the required role\");\n }\n const pending = await fetchAuthorizationRequest({ ...input, requestId: input.operationId });\n // A committed outcome wins before preparation, even if the provider is now unavailable.\n if (pending.decision !== null)\n return Object.freeze({\n operationId: input.operationId,\n outcome: pending.decision.outcome,\n decidedAt: pending.decision.decidedAt,\n settlement: \"replayed\",\n release: null,\n });\n let command = input.command;\n if (command.outcome === \"approved\" && !pending.expired) {\n const scope = classifyStoredAuthorizationScope(pending.requestedScope, pending.requestId);\n if (scope.kind === \"permission-request\") {\n const prepared = await prepareOwnerPhonePermissionApproval(\n input.permissionApprovals,\n scope.request,\n );\n let artifact: Readonly<OwnerSigningArtifact>;\n try {\n artifact = parseOwnerSigningArtifact(JSON.parse(command.artifact));\n } catch {\n return relayFailure(\"relay_request_invalid\", \"phone signing artifact is invalid\");\n }\n command = {\n outcome: \"approved\",\n artifact: await prepared.complete(artifact, Math.floor(relayNow(input.clock) / 1000)),\n };\n }\n }\n try {\n const release = await submitAuthorizationDecision({\n store: input.store,\n clock: input.clock,\n kms: input.kms,\n caller: input.caller,\n requestId: input.operationId,\n command,\n codeTtlMs: input.codeTtlMs,\n });\n return Object.freeze({\n operationId: input.operationId,\n outcome: release.outcome,\n decidedAt: release.decidedAt,\n settlement: \"decided\",\n release,\n });\n } catch (error) {\n // Only \"already decided\" is idempotent. Ambiguous, expired, unauthorized,\n // and unreadable stay failures: an unproven commit never becomes an answer.\n if (!(error instanceof OaathRelayError) || error.code !== \"relay_already_decided\") throw error;\n }\n const state = await fetchAuthorizationRequest({\n store: input.store,\n clock: input.clock,\n caller: input.caller,\n requestId: input.operationId,\n });\n if (state.decision === null) {\n return relayFailure(\"relay_internal\", \"decided request has no decision record\");\n }\n return Object.freeze({\n operationId: input.operationId,\n outcome: state.decision.outcome,\n decidedAt: state.decision.decidedAt,\n settlement: \"replayed\",\n release: null,\n });\n}\n","/**\n * Read-only owner inbox derived from retained relay requests and decisions.\n * No delivery state, lease or second queue is persisted. Recreating the service\n * reads the same pending requests; deciding or expiring one removes it from the\n * next listing. A summary is discovery only: consent/decision checks current state.\n */\nimport { type RelayClock, relayNow } from \"../clock.js\";\nimport { relayFailure } from \"../relay/errors.js\";\nimport type { RelayCaller } from \"../security/authentication.js\";\nimport { type RelayStore, withRelayTransaction } from \"../store/interface.js\";\nimport { ownerPhoneDisplayPayload } from \"./display.js\";\nimport type { OwnerPhonePushProjection } from \"./projection.js\";\n\nexport const OAATH_NATIVE_INBOX_VERSION = \"oaath.native-inbox/v1\" as const;\nconst INBOX_LIMIT = 20;\n\nexport interface OwnerPhoneInbox {\n readonly version: typeof OAATH_NATIVE_INBOX_VERSION;\n readonly requests: readonly Readonly<OwnerPhonePushProjection>[];\n}\n\n/** The store owns transaction resources; this read prepares, signs and submits nothing. */\nexport async function listOwnerPhoneRequests(input: {\n readonly store: RelayStore;\n readonly clock: RelayClock;\n readonly caller: RelayCaller;\n}): Promise<Readonly<OwnerPhoneInbox>> {\n if (input.caller.role !== \"owner\")\n return relayFailure(\"relay_forbidden\", \"only an owner may read the inbox\");\n const now = relayNow(input.clock);\n const requests = await withRelayTransaction(input.store, (transaction) =>\n transaction.listPendingOwnerRequests(input.caller.subject, now, INBOX_LIMIT),\n );\n if (requests.length > INBOX_LIMIT)\n return relayFailure(\"relay_record_unreadable\", \"owner inbox is unbounded\");\n return Object.freeze({\n version: OAATH_NATIVE_INBOX_VERSION,\n requests: Object.freeze(\n await Promise.all(\n requests.map(async (request) => {\n if (request.ownerSubject !== input.caller.subject || request.expiresAt <= now) {\n return relayFailure(\n \"relay_record_unreadable\",\n \"pending request does not match this owner inbox\",\n );\n }\n return Object.freeze({\n operationId: request.operationId,\n expiresAt: request.expiresAt,\n displayPayload: await ownerPhoneDisplayPayload(\n request.ownerSubject,\n request.operationId,\n ),\n });\n }),\n ),\n ),\n });\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as OAATH_REVOCATION_REQUEST_RECORD_VERSION, a as AuthorizationDecisionRecord, b as RelayClock, c as EncryptedArtifactRecord, d as OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION, f as OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION, g as OAATH_REVOCATION_DECISION_RECORD_VERSION, h as RelayErrorCode, i as AuthorizationDecisionOutcome, l as OAATH_AUTHORIZATION_CODE_RECORD_VERSION, m as RELAY_ERROR_STATUS, n as RelayTransaction, o as AuthorizationOwnerRoute, p as OaathRelayError, r as AuthorizationCodeRecord, s as AuthorizationRequestRecord, t as RelayStore, u as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION, v as RevocationDecisionRecord, y as RevocationRequestRecord } from "./interface-
|
|
2
|
-
import { h as RelayCallerRole, m as RelayCaller, p as RelayAuthentication } from "./projection-
|
|
1
|
+
import { _ as OAATH_REVOCATION_REQUEST_RECORD_VERSION, a as AuthorizationDecisionRecord, b as RelayClock, c as EncryptedArtifactRecord, d as OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION, f as OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION, g as OAATH_REVOCATION_DECISION_RECORD_VERSION, h as RelayErrorCode, i as AuthorizationDecisionOutcome, l as OAATH_AUTHORIZATION_CODE_RECORD_VERSION, m as RELAY_ERROR_STATUS, n as RelayTransaction, o as AuthorizationOwnerRoute, p as OaathRelayError, r as AuthorizationCodeRecord, s as AuthorizationRequestRecord, t as RelayStore, u as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION, v as RevocationDecisionRecord, y as RevocationRequestRecord } from "./interface-BVKJY6sm.js";
|
|
2
|
+
import { h as RelayCallerRole, m as RelayCaller, p as RelayAuthentication } from "./projection-CrtZYvxz.js";
|
|
3
3
|
import { t as RelayKms } from "./kms-BWkywdJM.js";
|
|
4
|
-
import { $ as FetchAuthorizationRequestInput, G as DirectoryOwnerDevice, H as DirectoryAccount, J as OAATH_SERVICE_DIRECTORY_VERSION, K as DirectorySelection, Q as CreatedAuthorizationRequest, U as DirectoryApplication, W as DirectoryMembership, X as AuthorizationState, Y as ServiceDirectoryDocument, Z as CreateAuthorizationRequestInput, _ as SessionSignerIdentity, a as createMemoryServiceDirectoryStore, at as SubmittedAuthorizationDecision, b as RelayRateLimitInput, c as RelayBootstrapSelection, d as RelayPaymasterServiceConfiguration, et as RelayOwnerRouting, f as RelayPaymasterServiceProvider, g as RelaySessionSignerProvider, h as createRelayHandler, i as ServiceDirectoryStore, it as SubmitAuthorizationDecisionInput, l as RelayHandler, m as RelaySessionSignerConfiguration, n as ServiceDirectory, nt as fetchAuthorizationRequest, o as createServiceDirectory, ot as submitAuthorizationDecision, p as RelayPaymasterServiceRequest, q as DirectoryWorkspace, r as ServiceDirectorySnapshot, rt as AuthorizationDecisionCommand, s as RelayBootstrapConfiguration, t as EnrollOwnerDeviceInput, tt as createAuthorizationRequest, u as RelayHandlerOptions, v as SessionSignerSignRequest, x as RelayRateLimiter, y as createKmsSessionSignerProvider } from "./service-
|
|
4
|
+
import { $ as FetchAuthorizationRequestInput, G as DirectoryOwnerDevice, H as DirectoryAccount, J as OAATH_SERVICE_DIRECTORY_VERSION, K as DirectorySelection, Q as CreatedAuthorizationRequest, U as DirectoryApplication, W as DirectoryMembership, X as AuthorizationState, Y as ServiceDirectoryDocument, Z as CreateAuthorizationRequestInput, _ as SessionSignerIdentity, a as createMemoryServiceDirectoryStore, at as SubmittedAuthorizationDecision, b as RelayRateLimitInput, c as RelayBootstrapSelection, d as RelayPaymasterServiceConfiguration, et as RelayOwnerRouting, f as RelayPaymasterServiceProvider, g as RelaySessionSignerProvider, h as createRelayHandler, i as ServiceDirectoryStore, it as SubmitAuthorizationDecisionInput, l as RelayHandler, m as RelaySessionSignerConfiguration, n as ServiceDirectory, nt as fetchAuthorizationRequest, o as createServiceDirectory, ot as submitAuthorizationDecision, p as RelayPaymasterServiceRequest, q as DirectoryWorkspace, r as ServiceDirectorySnapshot, rt as AuthorizationDecisionCommand, s as RelayBootstrapConfiguration, t as EnrollOwnerDeviceInput, tt as createAuthorizationRequest, u as RelayHandlerOptions, v as SessionSignerSignRequest, x as RelayRateLimiter, y as createKmsSessionSignerProvider } from "./service-Dv3zIiNr.js";
|
|
5
5
|
//#region src/artifact/claim.d.ts
|
|
6
6
|
interface ClaimEncryptedArtifactInput {
|
|
7
7
|
readonly store: RelayStore;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { _ as jsonResponse, a as OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION, b as relayFailure, c as canonicalIdentifier, d as parseAuthorizationRequestRecord, f as parseCapabilityInvalidationRecord, g as RELAY_ERROR_STATUS, h as OaathRelayError, i as OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION, l as parseAuthorizationCodeRecord, m as timestamp, n as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION, o as RELAY_LIMITS, p as parseEncryptedArtifactRecord, r as OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION, s as boundedText, t as OAATH_AUTHORIZATION_CODE_RECORD_VERSION, u as parseAuthorizationDecisionRecord, v as relayErrorCode, y as relayErrorResponse } from "./records-
|
|
2
|
-
import { a as relayNow, i as verifyPkceS256, r as sha256Base64Url, t as isCodeChallengeS256 } from "./challenge-
|
|
3
|
-
import { S as withRelayTransaction, a as submitOwnerPhoneRevocationDecision, b as openArtifact, c as projectOwnerPhonePermissionSigning, d as classifyStoredAuthorizationScope, f as createAuthorizationRequest, i as requestOwnerPhoneRevocation, l as projectOwnerPhoneRequest, m as readAuthorizationState, n as fetchOwnerPhoneRevocation, p as fetchAuthorizationRequest, t as fetchClientPhoneRevocation, x as sealArtifact, y as readApprovedPermission } from "./service-
|
|
4
|
-
import { i as submitAuthorizationDecision, n as listOwnerPhoneRequests, r as submitOwnerPhoneDecision } from "./inbox-
|
|
5
|
-
import { a as parseRevocationRequestRecord, i as parseRevocationDecisionRecord, n as OAATH_REVOCATION_REQUEST_RECORD_VERSION, t as OAATH_REVOCATION_DECISION_RECORD_VERSION } from "./records-
|
|
1
|
+
import { _ as jsonResponse, a as OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION, b as relayFailure, c as canonicalIdentifier, d as parseAuthorizationRequestRecord, f as parseCapabilityInvalidationRecord, g as RELAY_ERROR_STATUS, h as OaathRelayError, i as OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION, l as parseAuthorizationCodeRecord, m as timestamp, n as OAATH_AUTHORIZATION_DECISION_RECORD_VERSION, o as RELAY_LIMITS, p as parseEncryptedArtifactRecord, r as OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION, s as boundedText, t as OAATH_AUTHORIZATION_CODE_RECORD_VERSION, u as parseAuthorizationDecisionRecord, v as relayErrorCode, y as relayErrorResponse } from "./records-Bh8rOpBa.js";
|
|
2
|
+
import { a as relayNow, i as verifyPkceS256, r as sha256Base64Url, t as isCodeChallengeS256 } from "./challenge-WmeNbyox.js";
|
|
3
|
+
import { S as withRelayTransaction, a as submitOwnerPhoneRevocationDecision, b as openArtifact, c as projectOwnerPhonePermissionSigning, d as classifyStoredAuthorizationScope, f as createAuthorizationRequest, i as requestOwnerPhoneRevocation, l as projectOwnerPhoneRequest, m as readAuthorizationState, n as fetchOwnerPhoneRevocation, p as fetchAuthorizationRequest, t as fetchClientPhoneRevocation, x as sealArtifact, y as readApprovedPermission } from "./service-DT0vkKop.js";
|
|
4
|
+
import { i as submitAuthorizationDecision, n as listOwnerPhoneRequests, r as submitOwnerPhoneDecision } from "./inbox-BKXNtsX3.js";
|
|
5
|
+
import { a as parseRevocationRequestRecord, i as parseRevocationDecisionRecord, n as OAATH_REVOCATION_REQUEST_RECORD_VERSION, t as OAATH_REVOCATION_DECISION_RECORD_VERSION } from "./records-lPGo4RxO.js";
|
|
6
6
|
import { OAATH_GRANT_REFERENCE_APPROVED_REVISION, OAATH_GRANT_REFERENCE_VERSION, OAATH_OPERATOR_CREDENTIAL_PROFILE_VERSION, OAATH_SERVICE_BOOTSTRAP_VERSION, OAATH_WORKSPACE_ACCOUNT_CONTEXT_VERSION, captureDenseArray, captureRecord, captureServiceAccount, exactCapturedRecord, hashGrantPolicy, hashGrantPolicyCalls, isKernelExistingAccountProfile, parseAccountId, parseClientId, parseServiceBootstrap, parseVerifyGrantRevisionInput, readRpcBundlerRejection, readValidationGasDiagnostic } from "@oaath/protocol";
|
|
7
7
|
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
8
8
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
@@ -1198,7 +1198,7 @@ function createRelayHandler(options) {
|
|
|
1198
1198
|
try {
|
|
1199
1199
|
result = await capability(body.request);
|
|
1200
1200
|
} catch (error) {
|
|
1201
|
-
return relayFailure("relay_chain_unavailable", "chain port did not answer", readValidationGasDiagnostic(error), name === "submission" ? readRpcBundlerRejection(error) : null);
|
|
1201
|
+
return relayFailure("relay_chain_unavailable", "chain port did not answer", readValidationGasDiagnostic(error), name === "submission" ? readRpcBundlerRejection(error) : null, { cause: error });
|
|
1202
1202
|
}
|
|
1203
1203
|
return jsonResponse(200, result === void 0 ? {
|
|
1204
1204
|
present: false,
|
|
@@ -1315,7 +1315,7 @@ function createRelayHandler(options) {
|
|
|
1315
1315
|
try {
|
|
1316
1316
|
return await route(request);
|
|
1317
1317
|
} catch (error) {
|
|
1318
|
-
return relayErrorResponse(relayErrorCode(error), readValidationGasDiagnostic(error), error instanceof OaathRelayError ? error.bundlerRejection : null);
|
|
1318
|
+
return relayErrorResponse(relayErrorCode(error), readValidationGasDiagnostic(error), error instanceof OaathRelayError ? error.bundlerRejection : null, error);
|
|
1319
1319
|
}
|
|
1320
1320
|
};
|
|
1321
1321
|
}
|