@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.
- package/README.md +239 -5
- package/dist/apns.d.ts +2 -2
- package/dist/apns.js +2 -2
- package/dist/{challenge-AGTmUfj2.js → challenge-DmpGSogj.js} +2 -2
- package/dist/{challenge-AGTmUfj2.js.map → challenge-DmpGSogj.js.map} +1 -1
- package/dist/inbox-B80EUVht.js +249 -0
- package/dist/inbox-B80EUVht.js.map +1 -0
- package/dist/index.d.ts +9 -255
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +631 -48
- package/dist/index.js.map +1 -1
- package/dist/interface-DHpwP0wr.d.ts +245 -0
- package/dist/interface-DHpwP0wr.d.ts.map +1 -0
- package/dist/kernel.d.ts +42 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +80 -0
- package/dist/kernel.js.map +1 -0
- package/dist/kms-BWkywdJM.d.ts +18 -0
- package/dist/kms-BWkywdJM.d.ts.map +1 -0
- package/dist/native.d.ts +3 -30
- package/dist/native.js +115 -2
- package/dist/native.js.map +1 -0
- package/dist/postgres.d.ts +38 -3
- package/dist/postgres.d.ts.map +1 -1
- package/dist/postgres.js +301 -14
- package/dist/postgres.js.map +1 -1
- package/dist/projection-B7IB9irs.d.ts +228 -0
- package/dist/projection-B7IB9irs.d.ts.map +1 -0
- package/dist/{records-Bgr-9PUh.js → records-BQNDxbPg.js} +32 -8
- package/dist/records-BQNDxbPg.js.map +1 -0
- package/dist/records-BUvqmp0D.js +70 -0
- package/dist/records-BUvqmp0D.js.map +1 -0
- package/dist/service-Cf4f-9KP.js +706 -0
- package/dist/service-Cf4f-9KP.js.map +1 -0
- package/dist/service-J51bOVe6.d.ts +483 -0
- package/dist/service-J51bOVe6.d.ts.map +1 -0
- package/package.json +39 -8
- package/LICENSE +0 -201
- package/dist/authentication-HUYWk5Y2.d.ts +0 -46
- package/dist/authentication-HUYWk5Y2.d.ts.map +0 -1
- package/dist/decision-dEe9n108.d.ts +0 -53
- package/dist/decision-dEe9n108.d.ts.map +0 -1
- package/dist/interface-WwvwWs8e.d.ts +0 -114
- package/dist/interface-WwvwWs8e.d.ts.map +0 -1
- package/dist/native.d.ts.map +0 -1
- package/dist/projection-dGIkE0rI.js +0 -516
- package/dist/projection-dGIkE0rI.js.map +0 -1
- package/dist/projection-g6k_CCUK.d.ts +0 -136
- package/dist/projection-g6k_CCUK.d.ts.map +0 -1
- package/dist/records-Bgr-9PUh.js.map +0 -1
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { i as RelayClock, n as RelayCaller } from "./authentication-HUYWk5Y2.js";
|
|
2
|
-
import { t as RelayStore } from "./interface-WwvwWs8e.js";
|
|
3
|
-
import { KernelV4ReplayableInstallOwnerSigningRequest, OwnerSigningRequest } from "@oaath/protocol";
|
|
4
|
-
//#region src/native/projection.d.ts
|
|
5
|
-
/** Bounded base64url match code length. 48 bits is plenty to compare by eye. */
|
|
6
|
-
declare const NATIVE_DISPLAY_PAYLOAD_LENGTH = 8;
|
|
7
|
-
/** Versioned consent envelope; the Swift decoder pins this exact value. */
|
|
8
|
-
declare const OAATH_NATIVE_PROJECTION_VERSION: "oaath.native-projection/v4";
|
|
9
|
-
/** One credential identity as the owner reviews it: public material only. */
|
|
10
|
-
type OwnerPhoneCredentialProjection = Readonly<{
|
|
11
|
-
kind: "ecdsa";
|
|
12
|
-
address: string;
|
|
13
|
-
}> | Readonly<{
|
|
14
|
-
kind: "p256";
|
|
15
|
-
publicKey: string;
|
|
16
|
-
}> | Readonly<{
|
|
17
|
-
kind: "webauthn";
|
|
18
|
-
publicKey: string;
|
|
19
|
-
authenticatorIdHash: string;
|
|
20
|
-
}>;
|
|
21
|
-
/**
|
|
22
|
-
* The requested scope as the phone renders it. When the stored scope parses as
|
|
23
|
-
* an `@oaath/protocol` permission request, every fact that determines who
|
|
24
|
-
* receives authority, over which account, and under what limits is projected
|
|
25
|
-
* structurally. A valid owner-signing request is also projected in full with
|
|
26
|
-
* its protocol-owned hash; only exact Kernel replayable-install P-256 signing
|
|
27
|
-
* is approvable. Anything else is returned as explicitly labeled raw text.
|
|
28
|
-
*/
|
|
29
|
-
type OwnerPhoneScopeProjection = Readonly<{
|
|
30
|
-
kind: "permission-request";
|
|
31
|
-
decision: "approve-or-reject";
|
|
32
|
-
/** The application identity the signed request binds, verbatim. */
|
|
33
|
-
application: Readonly<{
|
|
34
|
-
applicationId: string;
|
|
35
|
-
clientId: string;
|
|
36
|
-
origin: string;
|
|
37
|
-
/** Opaque device identity, fingerprinted: raw ids mean nothing to an owner. */
|
|
38
|
-
deviceFingerprint: string;
|
|
39
|
-
}>;
|
|
40
|
-
/** The logical account this authority acts for. */
|
|
41
|
-
account: Readonly<{
|
|
42
|
-
accountIndex: string;
|
|
43
|
-
kernelVersion: string;
|
|
44
|
-
factoryRoute: string;
|
|
45
|
-
entryPointVersion: string;
|
|
46
|
-
ownerCredential: OwnerPhoneCredentialProjection;
|
|
47
|
-
}>;
|
|
48
|
-
/** The session credential that receives the scoped authority. */
|
|
49
|
-
operatorCredential: OwnerPhoneCredentialProjection;
|
|
50
|
-
/**
|
|
51
|
-
* Where the session key lives: null for frontend custody (the page's
|
|
52
|
-
* own non-extractable key), or the remote trust model the owner is
|
|
53
|
-
* asked to approve — the request hash binds it, so approving this
|
|
54
|
-
* display approves exactly this custody.
|
|
55
|
-
*/
|
|
56
|
-
sessionSigner: Readonly<{
|
|
57
|
-
mode: "application_backend" | "oaath_hosted";
|
|
58
|
-
providerId: string;
|
|
59
|
-
}> | null;
|
|
60
|
-
chainScope: "all";
|
|
61
|
-
calls: readonly Readonly<{
|
|
62
|
-
target: string;
|
|
63
|
-
selector: string;
|
|
64
|
-
valueLimit: string;
|
|
65
|
-
argumentEquals: readonly Readonly<{
|
|
66
|
-
index: number;
|
|
67
|
-
value: string;
|
|
68
|
-
}>[];
|
|
69
|
-
}>[];
|
|
70
|
-
requestedAt: number;
|
|
71
|
-
/** The permission request's own expiry, as the requesting client stated it. */
|
|
72
|
-
expiresAt: number;
|
|
73
|
-
/** The policy's on-chain validity window; inclusive, in Unix seconds. */
|
|
74
|
-
policyValidAfter: number;
|
|
75
|
-
policyValidUntil: number | null;
|
|
76
|
-
perChainOperationLimit: number;
|
|
77
|
-
}> | Readonly<{
|
|
78
|
-
kind: "owner-signing-request";
|
|
79
|
-
decision: "approve-or-reject";
|
|
80
|
-
/** Canonical hash binding every captured request fact. */
|
|
81
|
-
requestHash: `0x${string}`;
|
|
82
|
-
/** Exact Kernel request independently refined by the protocol owner. */
|
|
83
|
-
request: Readonly<KernelV4ReplayableInstallOwnerSigningRequest>;
|
|
84
|
-
}> | Readonly<{
|
|
85
|
-
kind: "owner-signing-request";
|
|
86
|
-
decision: "reject-only";
|
|
87
|
-
/** Canonical hash binding every captured request fact. */
|
|
88
|
-
requestHash: `0x${string}`;
|
|
89
|
-
/** Full immutable protocol request for independent device review. */
|
|
90
|
-
request: Readonly<OwnerSigningRequest>;
|
|
91
|
-
}> | Readonly<{
|
|
92
|
-
kind: "raw";
|
|
93
|
-
decision: "reject-only";
|
|
94
|
-
text: string;
|
|
95
|
-
}>;
|
|
96
|
-
interface OwnerPhoneRequestProjection {
|
|
97
|
-
readonly version: typeof OAATH_NATIVE_PROJECTION_VERSION;
|
|
98
|
-
/**
|
|
99
|
-
* Stable across every projection of the same request, and the key the
|
|
100
|
-
* approve/reject saga is keyed by. It is the relay's own opaque request
|
|
101
|
-
* identifier: one authoritative id, no second mapping table to lose.
|
|
102
|
-
*/
|
|
103
|
-
readonly operationId: string;
|
|
104
|
-
/** Bounded opaque match code, the only variable an APNs payload may carry. */
|
|
105
|
-
readonly displayPayload: string;
|
|
106
|
-
/** The stored request's expiry, in epoch milliseconds. */
|
|
107
|
-
readonly expiresAt: number;
|
|
108
|
-
/** The requesting client, exactly as the stored request binds it. */
|
|
109
|
-
readonly client: Readonly<{
|
|
110
|
-
clientId: string;
|
|
111
|
-
redirectUri: string;
|
|
112
|
-
}>;
|
|
113
|
-
readonly scope: OwnerPhoneScopeProjection;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* The opaque subset of the projection that may transit Apple inside an APNs
|
|
117
|
-
* payload. The sender exact-captures precisely these three fields, so consent
|
|
118
|
-
* detail can never ride a notification.
|
|
119
|
-
*/
|
|
120
|
-
type OwnerPhonePushProjection = Pick<OwnerPhoneRequestProjection, "operationId" | "displayPayload" | "expiresAt">;
|
|
121
|
-
interface ProjectOwnerPhoneRequestInput {
|
|
122
|
-
readonly store: RelayStore;
|
|
123
|
-
readonly clock: RelayClock;
|
|
124
|
-
/** Authenticated `owner` caller; only the bound subject may be projected. */
|
|
125
|
-
readonly caller: RelayCaller;
|
|
126
|
-
readonly requestId: string;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Projects a pending request for its bound owner. An expired or already decided
|
|
130
|
-
* request is not projectable: there is nothing left to approve, so nothing is
|
|
131
|
-
* ever pushed or rendered for it.
|
|
132
|
-
*/
|
|
133
|
-
declare function projectOwnerPhoneRequest(input: ProjectOwnerPhoneRequestInput): Promise<OwnerPhoneRequestProjection>;
|
|
134
|
-
//#endregion
|
|
135
|
-
export { OwnerPhoneScopeProjection as a, OwnerPhoneRequestProjection as i, OAATH_NATIVE_PROJECTION_VERSION as n, ProjectOwnerPhoneRequestInput as o, OwnerPhonePushProjection as r, projectOwnerPhoneRequest as s, NATIVE_DISPLAY_PAYLOAD_LENGTH as t };
|
|
136
|
-
//# sourceMappingURL=projection-g6k_CCUK.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"projection-g6k_CCUK.d.ts","names":[],"sources":["../src/native/projection.ts"],"mappings":";;;;;cA6Ca;;cAGA;;KAYD,iCACR;EAAW;EAAe;KAC1B;EAAW;EAAc;KACzB;EAAW;EAAkB;EAAmB;;;;;;;;;;KAUxC,4BACR;EACE;EACA;;EAEA,aAAa;IACX;IACA;IACA;;IAEA;;;EAGF,SAAS;IACP;IACA;IACA;IACA;IACA,iBAAiB;;;EAGnB,oBAAoB;;;;;;;EAOpB,eAAe;IACb;IACA;;EAEF;EACA,gBAAgB;IACd;IACA;IACA;IACA,yBAAyB;MAAW;MAAe;;;EAErD;;EAEA;;EAEA;EACA;EACA;KAEF;EACE;EACA;;EAEA;;EAEA,SAAS,SAAS;KAEpB;EACE;EACA;;EAEA;;EAEA,SAAS,SAAS;KAEpB;EAAW;EAAa;EAAyB;;UAEpC;WACN,gBAAgB;;;;;;WAMhB;;WAEA;;WAEA;;WAEA,QAAQ;IAAW;IAAkB;;WACrC,OAAO;;;;;;;KAQN,2BAA2B,KACrC;UAIe;WACN,OAAO;WACP,OAAO;;WAEP,QAAQ;WACR;;;;;;;iBAiHW,yBACpB,OAAO,gCACN,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"records-Bgr-9PUh.js","names":[],"sources":["../src/relay/errors.ts","../src/store/records.ts"],"sourcesContent":["/**\n * Closed relay failure codes and their stable HTTP projection.\n *\n * Machine decisions and wire responses use these codes only. `Error.message`\n * exists for local diagnostics and never reaches a response body.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nexport type RelayErrorCode =\n /** Wire input is missing, malformed, oversized, or contains unknown fields. */\n | \"relay_request_invalid\"\n /** The deployment authentication port did not authenticate the caller. */\n | \"relay_unauthenticated\"\n /** Authenticated caller may not act in the required role. */\n | \"relay_forbidden\"\n /** Route, or a record the caller is entitled to see, does not exist. */\n | \"relay_not_found\"\n /** Route exists with a different method. */\n | \"relay_method_not_allowed\"\n /** The authorization request or code is past its injected-clock expiry. */\n | \"relay_expired\"\n /** The authorization request already reached a terminal decision. */\n | \"relay_already_decided\"\n /** The one-time authorization code was already consumed. */\n | \"relay_code_already_consumed\"\n /** The one-time encrypted artifact was already claimed. */\n | \"relay_artifact_already_claimed\"\n /**\n * Authorization code redemption failed. One code for every reason it can\n * fail — unknown code, another client's code, wrong redirect URI, wrong PKCE\n * verifier — so the endpoint never confirms that a guessed code was correct.\n * A code that existed is burned.\n */\n | \"relay_code_invalid\"\n /** The optional deployment limiter rejected the call. */\n | \"relay_rate_limited\"\n /** A durable record could not be read as the current schema version. */\n | \"relay_record_unreadable\"\n /** The KMS port was unavailable or returned an unusable result. */\n | \"relay_kms_unavailable\"\n /** The store failed before any state change could have been committed. */\n | \"relay_store_unavailable\"\n /**\n * The store could not prove whether a transition committed. The caller must\n * treat the transition as neither applied nor retryable: an ambiguous commit\n * never authorizes resubmission.\n */\n | \"relay_state_ambiguous\"\n /**\n * EXPERIMENTAL PREVIEW (`@oaath/server/apns`): the constructed APNs payload\n * exceeded Apple's 4096-byte limit, so nothing was sent.\n */\n | \"relay_apns_payload_too_large\"\n /**\n * EXPERIMENTAL PREVIEW (`@oaath/server/apns`): the injected Apple credential\n * capability is not a usable P-256 signing key, key id, team id, or topic.\n */\n | \"relay_apns_credentials_invalid\"\n /** A deployment-injected chain execution port failed or answered unusably. */\n | \"relay_chain_unavailable\"\n /** The Grant's capability is durably invalidated; nothing more executes here. */\n | \"relay_capability_invalidated\"\n /** An invariant the relay owns was violated. */\n | \"relay_internal\";\n\n/**\n * Status projection. `relay_state_ambiguous` is deliberately 500 and not 503,\n * because 503 invites the retry that an ambiguous commit forbids.\n */\nexport const RELAY_ERROR_STATUS: Readonly<Record<RelayErrorCode, number>> = Object.freeze({\n relay_request_invalid: 400,\n relay_unauthenticated: 401,\n relay_forbidden: 403,\n relay_not_found: 404,\n relay_method_not_allowed: 405,\n relay_expired: 410,\n relay_already_decided: 409,\n relay_code_already_consumed: 409,\n relay_artifact_already_claimed: 409,\n relay_code_invalid: 400,\n relay_rate_limited: 429,\n relay_record_unreadable: 500,\n relay_kms_unavailable: 503,\n relay_store_unavailable: 503,\n relay_state_ambiguous: 500,\n // The preview codes have no route. They are projected only so the union stays\n // closed and one owner keeps every code's status.\n relay_apns_payload_too_large: 500,\n relay_apns_credentials_invalid: 500,\n relay_chain_unavailable: 503,\n relay_capability_invalidated: 409,\n relay_internal: 500,\n});\n\nexport class OaathRelayError extends Error {\n readonly code: RelayErrorCode;\n\n constructor(code: RelayErrorCode, message: string) {\n super(message);\n this.name = \"OaathRelayError\";\n this.code = code;\n }\n}\n\nexport function relayFailure(code: RelayErrorCode, message: string): never {\n throw new OaathRelayError(code, message);\n}\n\n/** Any non-relay throw is an unreadable internal failure, never caller-visible detail. */\nexport function relayErrorCode(error: unknown): RelayErrorCode {\n return error instanceof OaathRelayError ? error.code : \"relay_internal\";\n}\n\nconst RESPONSE_HEADERS: Readonly<Record<string, string>> = Object.freeze({\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n});\n\nexport function relayErrorResponse(code: RelayErrorCode): Response {\n return jsonResponse(RELAY_ERROR_STATUS[code], { error: { code } });\n}\n\nexport function jsonResponse(status: number, body: unknown): Response {\n return new Response(JSON.stringify(body), { status, headers: RESPONSE_HEADERS });\n}\n","/**\n * Exact current-version durable relay records.\n *\n * Durable storage is a trust boundary: every read is captured into an exact,\n * owned, immutable record before typed code consumes it. There is exactly one\n * current version per record and no reader for any older version.\n *\n * These shapes are relay-owned for now. `@oaath/protocol` owns the wire\n * `AuthorizationRequest`, `AuthorizationDecision`, and `AuthorizationCode`\n * contracts; adopting them here is a follow-up because the units differ (this\n * store keeps epoch milliseconds, the protocol speaks whole seconds) and the\n * code digest differs (base64url WebCrypto here, `0x` hex there). Once adopted,\n * this file should keep only the store envelope around those records.\n *\n * @author taek <leekt216@gmail.com>\n */\n\nimport { type CaptureContext, exactRecord } from \"@oaath/protocol\";\nimport { type RelayErrorCode, relayFailure } from \"../relay/errors.js\";\n\nexport const OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION =\n \"oaath.authorization-request-record/v1\" as const;\nexport const OAATH_AUTHORIZATION_DECISION_RECORD_VERSION =\n \"oaath.authorization-decision-record/v1\" as const;\nexport const OAATH_AUTHORIZATION_CODE_RECORD_VERSION =\n \"oaath.authorization-code-record/v1\" as const;\nexport const OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION =\n \"oaath.encrypted-artifact-record/v1\" as const;\nexport const OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION =\n \"oaath.capability-invalidation-record/v1\" as const;\n\n/** Bounded field limits owned here and shared with wire capture. */\nexport const RELAY_LIMITS = Object.freeze({\n identifier: 256,\n redirectUri: 2048,\n codeChallenge: 128,\n codeVerifier: 128,\n requestedScope: 8192,\n artifactPlaintext: 32_768,\n ciphertextRef: 65_536,\n});\n\nconst MAX_TIMESTAMP = Number.MAX_SAFE_INTEGER;\n\nexport interface AuthorizationRequestRecord {\n readonly version: typeof OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION;\n readonly requestId: string;\n /** Client bound by the deployment authentication port, never by wire input. */\n readonly clientId: string;\n /** Pairwise user/device subject bound by the authentication port. */\n readonly subject: string;\n readonly redirectUri: string;\n /** PKCE S256 challenge; the verifier never reaches the store. */\n readonly codeChallenge: string;\n /** Opaque owner-reviewed scope payload. Migrates to @oaath/protocol. */\n readonly requestedScope: string;\n readonly createdAt: number;\n readonly expiresAt: number;\n}\n\nexport type AuthorizationDecisionOutcome = \"approved\" | \"rejected\";\n\n/**\n * Terminal decision. Its existence is the single authoritative fact that an\n * authorization request was decided; the request record never mutates.\n */\nexport interface AuthorizationDecisionRecord {\n readonly version: typeof OAATH_AUTHORIZATION_DECISION_RECORD_VERSION;\n readonly requestId: string;\n readonly outcome: AuthorizationDecisionOutcome;\n readonly decidedAt: number;\n /**\n * KMS-sealed copy of the released code for authenticated client pickup, and\n * its expiry. The relay mints the code itself, so holding a sealed copy adds\n * no new trust; PKCE still guards consumption. Both are null exactly when\n * the outcome is a rejection.\n */\n readonly codeRef: string | null;\n readonly codeExpiresAt: number | null;\n}\n\nexport interface AuthorizationCodeRecord {\n readonly version: typeof OAATH_AUTHORIZATION_CODE_RECORD_VERSION;\n /** SHA-256 (base64url) of the released code. The code itself is never stored. */\n readonly codeHash: string;\n readonly requestId: string;\n /** Binding snapshot taken at issue time so consume needs exactly one row lock. */\n readonly clientId: string;\n readonly redirectUri: string;\n readonly codeChallenge: string;\n readonly artifactId: string;\n readonly createdAt: number;\n readonly expiresAt: number;\n /** Set exactly once. A non-null value is terminal. */\n readonly consumedAt: number | null;\n}\n\nexport interface EncryptedArtifactRecord {\n readonly version: typeof OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION;\n readonly artifactId: string;\n readonly requestId: string;\n readonly clientId: string;\n /** Opaque KMS reference. Plaintext never reaches the store. */\n readonly ciphertextRef: string;\n readonly createdAt: number;\n /** Set exactly once. A non-null value is terminal. */\n readonly claimedAt: number | null;\n}\n\n/**\n * One durable capability invalidation: from the moment this record commits,\n * the relay's chain execution routes refuse every submission and usage read\n * for the Grant, so the recorded evidence states an enforced fact — \"this\n * service will no longer act for this capability\" — not a bare digest.\n * Consuming the on-chain install nonce is the chain-local revocation\n * operation's job and stays separate evidence.\n */\nexport interface CapabilityInvalidationRecord {\n readonly version: typeof OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION;\n readonly grantId: string;\n /** The authenticated client that recorded the invalidation. */\n readonly clientId: string;\n readonly capabilityHash: string;\n readonly invalidatedAt: number;\n}\n\nexport function boundedText(\n value: unknown,\n maximum: number,\n label: string,\n code: RelayErrorCode,\n): string {\n if (typeof value !== \"string\" || value.length < 1 || value.length > maximum) {\n return relayFailure(code, `${label} must be a bounded non-empty string`);\n }\n // Control characters would corrupt logs and downstream headers.\n for (let index = 0; index < value.length; index += 1) {\n const unit = value.charCodeAt(index);\n if (unit < 0x20 || unit === 0x7f) {\n return relayFailure(code, `${label} must not contain control characters`);\n }\n }\n return value;\n}\n\nexport function canonicalIdentifier(value: unknown, label: string, code: RelayErrorCode): string {\n const text = boundedText(value, RELAY_LIMITS.identifier, label, code);\n if (!/^[A-Za-z0-9._~-]+$/u.test(text)) {\n return relayFailure(code, `${label} must be URL-safe`);\n }\n return text;\n}\n\nexport function timestamp(value: unknown, label: string, code: RelayErrorCode): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n Object.is(value, -0) ||\n value < 0 ||\n value > MAX_TIMESTAMP\n ) {\n return relayFailure(code, `${label} must be a non-negative safe integer`);\n }\n return value;\n}\n\nfunction nullableTimestamp(value: unknown, label: string, code: RelayErrorCode): number | null {\n return value === null ? null : timestamp(value, label, code);\n}\n\nconst UNREADABLE: RelayErrorCode = \"relay_record_unreadable\";\n\nfunction captured(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {\n const context: CaptureContext = new WeakSet();\n return exactRecord(value, keys, label, context, (message) => relayFailure(UNREADABLE, message));\n}\n\nfunction version<Value extends string>(value: unknown, expected: Value, label: string): Value {\n if (value !== expected) {\n return relayFailure(UNREADABLE, `${label} version is unsupported`);\n }\n return expected;\n}\n\nexport function parseCapabilityInvalidationRecord(value: unknown): CapabilityInvalidationRecord {\n const record = captured(\n value,\n [\"version\", \"grantId\", \"clientId\", \"capabilityHash\", \"invalidatedAt\"],\n \"capability invalidation record\",\n );\n const capabilityHash = boundedText(record.capabilityHash, 66, \"capabilityHash\", UNREADABLE);\n if (!/^0x[0-9a-f]{64}$/u.test(capabilityHash)) {\n return relayFailure(UNREADABLE, \"capabilityHash must be a lowercase 32-byte hash\");\n }\n return Object.freeze({\n version: version(\n record.version,\n OAATH_CAPABILITY_INVALIDATION_RECORD_VERSION,\n \"capability invalidation record\",\n ),\n grantId: canonicalIdentifier(record.grantId, \"grantId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n capabilityHash,\n invalidatedAt: timestamp(record.invalidatedAt, \"invalidatedAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationRequestRecord(value: unknown): AuthorizationRequestRecord {\n const record = captured(\n value,\n [\n \"version\",\n \"requestId\",\n \"clientId\",\n \"subject\",\n \"redirectUri\",\n \"codeChallenge\",\n \"requestedScope\",\n \"createdAt\",\n \"expiresAt\",\n ],\n \"authorization request record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_REQUEST_RECORD_VERSION,\n \"authorization request record\",\n ),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n subject: canonicalIdentifier(record.subject, \"subject\", UNREADABLE),\n redirectUri: boundedText(\n record.redirectUri,\n RELAY_LIMITS.redirectUri,\n \"redirectUri\",\n UNREADABLE,\n ),\n codeChallenge: canonicalIdentifier(record.codeChallenge, \"codeChallenge\", UNREADABLE),\n requestedScope: boundedText(\n record.requestedScope,\n RELAY_LIMITS.requestedScope,\n \"requestedScope\",\n UNREADABLE,\n ),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n expiresAt: timestamp(record.expiresAt, \"expiresAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationDecisionRecord(value: unknown): AuthorizationDecisionRecord {\n const record = captured(\n value,\n [\"version\", \"requestId\", \"outcome\", \"decidedAt\", \"codeRef\", \"codeExpiresAt\"],\n \"authorization decision record\",\n );\n if (record.outcome !== \"approved\" && record.outcome !== \"rejected\") {\n return relayFailure(UNREADABLE, \"decision outcome is unsupported\");\n }\n // The sealed code exists exactly when a code was released: an approval with\n // no pickup copy or a rejection carrying one is an unreadable record.\n if ((record.outcome === \"approved\") !== (record.codeRef !== null)) {\n return relayFailure(UNREADABLE, \"decision code reference does not match the outcome\");\n }\n if ((record.codeRef === null) !== (record.codeExpiresAt === null)) {\n return relayFailure(UNREADABLE, \"decision code expiry does not match its reference\");\n }\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_DECISION_RECORD_VERSION,\n \"authorization decision record\",\n ),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n outcome: record.outcome,\n decidedAt: timestamp(record.decidedAt, \"decidedAt\", UNREADABLE),\n codeRef:\n record.codeRef === null\n ? null\n : boundedText(record.codeRef, RELAY_LIMITS.ciphertextRef, \"codeRef\", UNREADABLE),\n codeExpiresAt:\n record.codeExpiresAt === null\n ? null\n : timestamp(record.codeExpiresAt, \"codeExpiresAt\", UNREADABLE),\n });\n}\n\nexport function parseAuthorizationCodeRecord(value: unknown): AuthorizationCodeRecord {\n const record = captured(\n value,\n [\n \"version\",\n \"codeHash\",\n \"requestId\",\n \"clientId\",\n \"redirectUri\",\n \"codeChallenge\",\n \"artifactId\",\n \"createdAt\",\n \"expiresAt\",\n \"consumedAt\",\n ],\n \"authorization code record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_AUTHORIZATION_CODE_RECORD_VERSION,\n \"authorization code record\",\n ),\n codeHash: canonicalIdentifier(record.codeHash, \"codeHash\", UNREADABLE),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n redirectUri: boundedText(\n record.redirectUri,\n RELAY_LIMITS.redirectUri,\n \"redirectUri\",\n UNREADABLE,\n ),\n codeChallenge: canonicalIdentifier(record.codeChallenge, \"codeChallenge\", UNREADABLE),\n artifactId: canonicalIdentifier(record.artifactId, \"artifactId\", UNREADABLE),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n expiresAt: timestamp(record.expiresAt, \"expiresAt\", UNREADABLE),\n consumedAt: nullableTimestamp(record.consumedAt, \"consumedAt\", UNREADABLE),\n });\n}\n\nexport function parseEncryptedArtifactRecord(value: unknown): EncryptedArtifactRecord {\n const record = captured(\n value,\n [\"version\", \"artifactId\", \"requestId\", \"clientId\", \"ciphertextRef\", \"createdAt\", \"claimedAt\"],\n \"encrypted artifact record\",\n );\n return Object.freeze({\n version: version(\n record.version,\n OAATH_ENCRYPTED_ARTIFACT_RECORD_VERSION,\n \"encrypted artifact record\",\n ),\n artifactId: canonicalIdentifier(record.artifactId, \"artifactId\", UNREADABLE),\n requestId: canonicalIdentifier(record.requestId, \"requestId\", UNREADABLE),\n clientId: canonicalIdentifier(record.clientId, \"clientId\", UNREADABLE),\n ciphertextRef: boundedText(\n record.ciphertextRef,\n RELAY_LIMITS.ciphertextRef,\n \"ciphertextRef\",\n UNREADABLE,\n ),\n createdAt: timestamp(record.createdAt, \"createdAt\", UNREADABLE),\n claimedAt: nullableTimestamp(record.claimedAt, \"claimedAt\", UNREADABLE),\n });\n}\n"],"mappings":"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"}
|