@oxy.so/contracts 2.0.0 → 2.2.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 (53) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/accountEmail.js +83 -0
  3. package/dist/cjs/federationInstanceFetch.js +44 -0
  4. package/dist/cjs/identityLink.js +89 -0
  5. package/dist/cjs/identityProof.js +6 -29
  6. package/dist/cjs/index.js +36 -49
  7. package/dist/cjs/linkedAccounts.js +34 -1
  8. package/dist/cjs/notifications.js +20 -1
  9. package/dist/cjs/webauthn.js +50 -21
  10. package/dist/esm/.tsbuildinfo +1 -1
  11. package/dist/esm/accountEmail.js +80 -0
  12. package/dist/esm/federationInstanceFetch.js +41 -0
  13. package/dist/esm/identityLink.js +84 -0
  14. package/dist/esm/identityProof.js +6 -29
  15. package/dist/esm/index.js +8 -10
  16. package/dist/esm/linkedAccounts.js +33 -0
  17. package/dist/esm/notifications.js +19 -0
  18. package/dist/esm/webauthn.js +49 -20
  19. package/dist/types/.tsbuildinfo +1 -1
  20. package/dist/types/accountEmail.d.ts +98 -0
  21. package/dist/types/accountGraph.d.ts +4 -4
  22. package/dist/types/agency.d.ts +2 -2
  23. package/dist/types/deviceSession.d.ts +4 -4
  24. package/dist/types/externalIdentity.d.ts +8 -8
  25. package/dist/types/federationInstanceFetch.d.ts +63 -0
  26. package/dist/types/identityLink.d.ts +210 -0
  27. package/dist/types/identityProof.d.ts +15 -42
  28. package/dist/types/index.d.ts +7 -8
  29. package/dist/types/inference/accountBilling.d.ts +2 -2
  30. package/dist/types/inference/aliaModelRelease.d.ts +8 -8
  31. package/dist/types/inference/embeddings.d.ts +16 -16
  32. package/dist/types/inference/errors.d.ts +8 -8
  33. package/dist/types/inference/inbox.d.ts +8 -8
  34. package/dist/types/inference/modelDocumentation.d.ts +8 -8
  35. package/dist/types/inference/providerConnection.d.ts +20 -20
  36. package/dist/types/inference/request.d.ts +16 -16
  37. package/dist/types/inference/streamEvents.d.ts +20 -20
  38. package/dist/types/keyRecovery.d.ts +4 -4
  39. package/dist/types/linkedAccounts.d.ts +33 -0
  40. package/dist/types/notifications.d.ts +26 -0
  41. package/dist/types/sessionStatus.d.ts +2 -2
  42. package/dist/types/userResponse.d.ts +4 -4
  43. package/dist/types/webauthn.d.ts +102 -214
  44. package/package.json +1 -1
  45. package/dist/cjs/identityMove.js +0 -156
  46. package/dist/cjs/identityRecovery.js +0 -51
  47. package/dist/cjs/webIdentityCarrier.js +0 -181
  48. package/dist/esm/identityMove.js +0 -148
  49. package/dist/esm/identityRecovery.js +0 -48
  50. package/dist/esm/webIdentityCarrier.js +0 -178
  51. package/dist/types/identityMove.d.ts +0 -185
  52. package/dist/types/identityRecovery.d.ts +0 -246
  53. package/dist/types/webIdentityCarrier.d.ts +0 -1130
@@ -11,18 +11,99 @@
11
11
  * create a second, drift-prone definition of a shape we do not own.
12
12
  */
13
13
  import { z } from 'zod';
14
+ /** A WebAuthn credential id, base64url as the browser reports it. */
15
+ export declare const webauthnCredentialIdSchema: z.ZodString;
14
16
  /**
15
- * `POST /webauthn/register/options` — request registration options. With a bearer
16
- * token the caller links a passkey to their signed-in account and `username` is
17
- * ignored; without one it is a prospective signup and `username` is the desired
18
- * (not-yet-created) handle.
17
+ * A WebAuthn assertion by one of the account's EXISTING passkeys over a server
18
+ * challenge — the fresh use of the factor the account already has (linking
19
+ * Commons to a passkey account, deleting a passkey account). The API verifies
20
+ * it with `@simplewebauthn/server`; this only bounds its shape.
21
+ */
22
+ export declare const webauthnAssertionResponseSchema: z.ZodObject<{
23
+ id: z.ZodString;
24
+ rawId: z.ZodString;
25
+ type: z.ZodLiteral<"public-key">;
26
+ response: z.ZodObject<{
27
+ clientDataJSON: z.ZodString;
28
+ authenticatorData: z.ZodString;
29
+ signature: z.ZodString;
30
+ userHandle: z.ZodOptional<z.ZodString>;
31
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
32
+ clientDataJSON: z.ZodString;
33
+ authenticatorData: z.ZodString;
34
+ signature: z.ZodString;
35
+ userHandle: z.ZodOptional<z.ZodString>;
36
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
37
+ clientDataJSON: z.ZodString;
38
+ authenticatorData: z.ZodString;
39
+ signature: z.ZodString;
40
+ userHandle: z.ZodOptional<z.ZodString>;
41
+ }, z.ZodTypeAny, "passthrough">>;
42
+ clientExtensionResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
+ authenticatorAttachment: z.ZodOptional<z.ZodString>;
44
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
45
+ id: z.ZodString;
46
+ rawId: z.ZodString;
47
+ type: z.ZodLiteral<"public-key">;
48
+ response: z.ZodObject<{
49
+ clientDataJSON: z.ZodString;
50
+ authenticatorData: z.ZodString;
51
+ signature: z.ZodString;
52
+ userHandle: z.ZodOptional<z.ZodString>;
53
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
54
+ clientDataJSON: z.ZodString;
55
+ authenticatorData: z.ZodString;
56
+ signature: z.ZodString;
57
+ userHandle: z.ZodOptional<z.ZodString>;
58
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
59
+ clientDataJSON: z.ZodString;
60
+ authenticatorData: z.ZodString;
61
+ signature: z.ZodString;
62
+ userHandle: z.ZodOptional<z.ZodString>;
63
+ }, z.ZodTypeAny, "passthrough">>;
64
+ clientExtensionResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
65
+ authenticatorAttachment: z.ZodOptional<z.ZodString>;
66
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
67
+ id: z.ZodString;
68
+ rawId: z.ZodString;
69
+ type: z.ZodLiteral<"public-key">;
70
+ response: z.ZodObject<{
71
+ clientDataJSON: z.ZodString;
72
+ authenticatorData: z.ZodString;
73
+ signature: z.ZodString;
74
+ userHandle: z.ZodOptional<z.ZodString>;
75
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
76
+ clientDataJSON: z.ZodString;
77
+ authenticatorData: z.ZodString;
78
+ signature: z.ZodString;
79
+ userHandle: z.ZodOptional<z.ZodString>;
80
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
81
+ clientDataJSON: z.ZodString;
82
+ authenticatorData: z.ZodString;
83
+ signature: z.ZodString;
84
+ userHandle: z.ZodOptional<z.ZodString>;
85
+ }, z.ZodTypeAny, "passthrough">>;
86
+ clientExtensionResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
87
+ authenticatorAttachment: z.ZodOptional<z.ZodString>;
88
+ }, z.ZodTypeAny, "passthrough">>;
89
+ export type WebauthnAssertionResponse = z.infer<typeof webauthnAssertionResponseSchema>;
90
+ /**
91
+ * `POST /webauthn/register/options` — request registration options. Three flows:
92
+ *
93
+ * - a bearer: the caller adds a passkey to their signed-in account;
94
+ * - `recoveryTicket` (no bearer): a new passkey for the account a recovery code
95
+ * was confirmed for (`POST /auth/email/verify/confirm`, purpose `recovery`);
96
+ * - `username` (no bearer): a prospective sign-up; the handle is not created yet.
19
97
  */
20
98
  export declare const webauthnRegisterOptionsRequestSchema: z.ZodObject<{
21
99
  username: z.ZodOptional<z.ZodString>;
100
+ recoveryTicket: z.ZodOptional<z.ZodString>;
22
101
  }, "strip", z.ZodTypeAny, {
23
102
  username?: string | undefined;
103
+ recoveryTicket?: string | undefined;
24
104
  }, {
25
105
  username?: string | undefined;
106
+ recoveryTicket?: string | undefined;
26
107
  }>;
27
108
  export type WebauthnRegisterOptionsRequest = z.infer<typeof webauthnRegisterOptionsRequestSchema>;
28
109
  /**
@@ -42,227 +123,34 @@ export type WebauthnLoginOptionsRequest = z.infer<typeof webauthnLoginOptionsReq
42
123
  /**
43
124
  * `POST /webauthn/register/verify` — the outer envelope. The browser
44
125
  * `RegistrationResponseJSON` travels alongside these fields under `response` and
45
- * is validated by `@simplewebauthn/server`, not here. `username` is required only
46
- * for the prospective-signup branch (no bearer); the linking branch ignores it.
126
+ * is validated by `@simplewebauthn/server`, not here.
127
+ *
128
+ * - Sign-up (no bearer, ADR 0029 D3): `username`, the recovery `email` and the
129
+ * `emailTicket` its code was confirmed with. The account is created with the
130
+ * passkey and that verified email, and no key.
131
+ * - Recovery (no bearer): `recoveryTicket`; the passkey is added to its account
132
+ * and a session minted.
133
+ * - A bearer: the passkey is added to the signed-in account.
47
134
  */
48
135
  export declare const webauthnRegisterVerifyRequestSchema: z.ZodObject<{
49
136
  deviceName: z.ZodOptional<z.ZodString>;
50
137
  deviceFingerprint: z.ZodOptional<z.ZodString>;
51
138
  username: z.ZodOptional<z.ZodString>;
52
- /**
53
- * Sign-up only (ADR 0024 D4): the account's root, created on the holder BEFORE
54
- * this request — sealed under the passkey being registered — and a root proof
55
- * (`enroll_identity`) whose challenge is the registration challenge. The
56
- * account, passkey, root and envelope are then created in one transaction.
57
- */
58
- identity: z.ZodOptional<z.ZodObject<{
59
- envelope: z.ZodEffects<z.ZodObject<{
60
- version: z.ZodLiteral<2>;
61
- algorithm: z.ZodLiteral<"xchacha20poly1305">;
62
- publicKey: z.ZodString;
63
- secretKind: z.ZodEnum<["mnemonic-entropy", "raw-private-key"]>;
64
- secretNonce: z.ZodString;
65
- sealedSecret: z.ZodString;
66
- wraps: z.ZodArray<z.ZodObject<{
67
- credentialId: z.ZodString;
68
- nonce: z.ZodString;
69
- wrappedKey: z.ZodString;
70
- createdAt: z.ZodString;
71
- rpId: z.ZodString;
72
- verifiedAt: z.ZodOptional<z.ZodString>;
73
- }, "strip", z.ZodTypeAny, {
74
- credentialId: string;
75
- createdAt: string;
76
- nonce: string;
77
- wrappedKey: string;
78
- rpId: string;
79
- verifiedAt?: string | undefined;
80
- }, {
81
- credentialId: string;
82
- createdAt: string;
83
- nonce: string;
84
- wrappedKey: string;
85
- rpId: string;
86
- verifiedAt?: string | undefined;
87
- }>, "many">;
88
- }, "strip", z.ZodTypeAny, {
89
- version: 2;
90
- publicKey: string;
91
- algorithm: "xchacha20poly1305";
92
- secretKind: "mnemonic-entropy" | "raw-private-key";
93
- secretNonce: string;
94
- sealedSecret: string;
95
- wraps: {
96
- credentialId: string;
97
- createdAt: string;
98
- nonce: string;
99
- wrappedKey: string;
100
- rpId: string;
101
- verifiedAt?: string | undefined;
102
- }[];
103
- }, {
104
- version: 2;
105
- publicKey: string;
106
- algorithm: "xchacha20poly1305";
107
- secretKind: "mnemonic-entropy" | "raw-private-key";
108
- secretNonce: string;
109
- sealedSecret: string;
110
- wraps: {
111
- credentialId: string;
112
- createdAt: string;
113
- nonce: string;
114
- wrappedKey: string;
115
- rpId: string;
116
- verifiedAt?: string | undefined;
117
- }[];
118
- }>, {
119
- version: 2;
120
- publicKey: string;
121
- algorithm: "xchacha20poly1305";
122
- secretKind: "mnemonic-entropy" | "raw-private-key";
123
- secretNonce: string;
124
- sealedSecret: string;
125
- wraps: {
126
- credentialId: string;
127
- createdAt: string;
128
- nonce: string;
129
- wrappedKey: string;
130
- rpId: string;
131
- verifiedAt?: string | undefined;
132
- }[];
133
- }, {
134
- version: 2;
135
- publicKey: string;
136
- algorithm: "xchacha20poly1305";
137
- secretKind: "mnemonic-entropy" | "raw-private-key";
138
- secretNonce: string;
139
- sealedSecret: string;
140
- wraps: {
141
- credentialId: string;
142
- createdAt: string;
143
- nonce: string;
144
- wrappedKey: string;
145
- rpId: string;
146
- verifiedAt?: string | undefined;
147
- }[];
148
- }>;
149
- proof: z.ZodObject<{
150
- v: z.ZodLiteral<2>;
151
- challenge: z.ZodString;
152
- expiresAt: z.ZodNumber;
153
- signature: z.ZodString;
154
- }, "strip", z.ZodTypeAny, {
155
- expiresAt: number;
156
- signature: string;
157
- v: 2;
158
- challenge: string;
159
- }, {
160
- expiresAt: number;
161
- signature: string;
162
- v: 2;
163
- challenge: string;
164
- }>;
165
- }, "strip", z.ZodTypeAny, {
166
- proof: {
167
- expiresAt: number;
168
- signature: string;
169
- v: 2;
170
- challenge: string;
171
- };
172
- envelope: {
173
- version: 2;
174
- publicKey: string;
175
- algorithm: "xchacha20poly1305";
176
- secretKind: "mnemonic-entropy" | "raw-private-key";
177
- secretNonce: string;
178
- sealedSecret: string;
179
- wraps: {
180
- credentialId: string;
181
- createdAt: string;
182
- nonce: string;
183
- wrappedKey: string;
184
- rpId: string;
185
- verifiedAt?: string | undefined;
186
- }[];
187
- };
188
- }, {
189
- proof: {
190
- expiresAt: number;
191
- signature: string;
192
- v: 2;
193
- challenge: string;
194
- };
195
- envelope: {
196
- version: 2;
197
- publicKey: string;
198
- algorithm: "xchacha20poly1305";
199
- secretKind: "mnemonic-entropy" | "raw-private-key";
200
- secretNonce: string;
201
- sealedSecret: string;
202
- wraps: {
203
- credentialId: string;
204
- createdAt: string;
205
- nonce: string;
206
- wrappedKey: string;
207
- rpId: string;
208
- verifiedAt?: string | undefined;
209
- }[];
210
- };
211
- }>>;
139
+ email: z.ZodOptional<z.ZodString>;
140
+ emailTicket: z.ZodOptional<z.ZodString>;
141
+ recoveryTicket: z.ZodOptional<z.ZodString>;
212
142
  }, "strip", z.ZodTypeAny, {
143
+ email?: string | undefined;
213
144
  username?: string | undefined;
214
- identity?: {
215
- proof: {
216
- expiresAt: number;
217
- signature: string;
218
- v: 2;
219
- challenge: string;
220
- };
221
- envelope: {
222
- version: 2;
223
- publicKey: string;
224
- algorithm: "xchacha20poly1305";
225
- secretKind: "mnemonic-entropy" | "raw-private-key";
226
- secretNonce: string;
227
- sealedSecret: string;
228
- wraps: {
229
- credentialId: string;
230
- createdAt: string;
231
- nonce: string;
232
- wrappedKey: string;
233
- rpId: string;
234
- verifiedAt?: string | undefined;
235
- }[];
236
- };
237
- } | undefined;
145
+ recoveryTicket?: string | undefined;
146
+ emailTicket?: string | undefined;
238
147
  deviceName?: string | undefined;
239
148
  deviceFingerprint?: string | undefined;
240
149
  }, {
150
+ email?: string | undefined;
241
151
  username?: string | undefined;
242
- identity?: {
243
- proof: {
244
- expiresAt: number;
245
- signature: string;
246
- v: 2;
247
- challenge: string;
248
- };
249
- envelope: {
250
- version: 2;
251
- publicKey: string;
252
- algorithm: "xchacha20poly1305";
253
- secretKind: "mnemonic-entropy" | "raw-private-key";
254
- secretNonce: string;
255
- sealedSecret: string;
256
- wraps: {
257
- credentialId: string;
258
- createdAt: string;
259
- nonce: string;
260
- wrappedKey: string;
261
- rpId: string;
262
- verifiedAt?: string | undefined;
263
- }[];
264
- };
265
- } | undefined;
152
+ recoveryTicket?: string | undefined;
153
+ emailTicket?: string | undefined;
266
154
  deviceName?: string | undefined;
267
155
  deviceFingerprint?: string | undefined;
268
156
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxy.so/contracts",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "OxyHQ API contracts — single source of truth for request/response Zod schemas and inferred types, shared by the backend and the client SDKs",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -1,156 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.identityMoveStateSchema = exports.identityMoveReceiptRequestSchema = exports.identityMoveSealRequestSchema = exports.identityMoveRevealRequestSchema = exports.identityMoveJoinRequestSchema = exports.identityMoveCreateResponseSchema = exports.identityMoveCreateRequestSchema = exports.IDENTITY_MOVE_QR_PREFIX = exports.IDENTITY_MOVE_STATUSES = exports.identityMoveEphemeralKeySchema = exports.identityMoveIdSchema = exports.IDENTITY_MOVE_TTL_MS = void 0;
4
- exports.buildMoveCommitmentInput = buildMoveCommitmentInput;
5
- exports.buildMoveSasInput = buildMoveSasInput;
6
- exports.buildMoveCiphertextDigestInput = buildMoveCiphertextDigestInput;
7
- exports.buildMoveSealPayload = buildMoveSealPayload;
8
- exports.buildMoveReceiptMessage = buildMoveReceiptMessage;
9
- /**
10
- * Identity move contract — give a web root to Commons (add it, or keep it only in
11
- * Commons; ADR 0024 D6).
12
- *
13
- * The web (holding the root) shows a QR carrying only a move id; Commons scans.
14
- * The relay in between must not be able to take the root, so:
15
- *
16
- * 1. `POST /identity/move { initiatorCommitment }` — the web publishes only
17
- * `H(initiatorKey, nonce)`, never the key.
18
- * 2. `POST /identity/move/:moveId/join { responderEphemeralPublicKey }` —
19
- * Commons, having read the commitment first, joins with its own key.
20
- * 3. `POST /identity/move/:moveId/reveal` — only then does the web reveal its
21
- * key and nonce; Commons checks them against the commitment it read.
22
- * 4. Both screens show a 6-digit code over `(moveId, both keys, commitment)`;
23
- * the person confirms on the web that they match.
24
- * 5. `POST /identity/move/:moveId/seal` — the web seals the phrase entropy under
25
- * `HKDF(ECDH(both keys), moveId)`, authorized by a one-use root proof over the
26
- * exact sealed bytes.
27
- * 6. `POST /identity/move/:moveId/receipt` — Commons stores the root, reads it
28
- * back from its keychain, and signs a receipt over the move, the root, both
29
- * keys and the digest of the ciphertext it opened. The server verifies it; the
30
- * web verifies it again from what IT sealed before removing anything.
31
- *
32
- * Why the commitment: without it the relay sees both keys before committing to
33
- * anything and can grind a substituted key until the two codes agree (~10⁶
34
- * tries, seconds). With it, the relay must fix the key it shows Commons before
35
- * learning Commons' key, and the key it shows the web before the web reveals.
36
- *
37
- * The server holds a commitment, two ephemeral public keys, an opaque ciphertext
38
- * and a receipt — nothing that decrypts the ciphertext.
39
- *
40
- * Platform-agnostic — zod only, ESM-safe (no `require()`).
41
- */
42
- const zod_1 = require("zod");
43
- const identityProof_1 = require("./identityProof");
44
- /** A move lives this long: one interactive handoff. */
45
- exports.IDENTITY_MOVE_TTL_MS = 5 * 60 * 1000;
46
- /** 128-bit move id, lowercase hex. */
47
- exports.identityMoveIdSchema = zod_1.z
48
- .string()
49
- .trim()
50
- .regex(/^[0-9a-f]{32}$/, 'moveId must be 32 lowercase hex characters');
51
- /** An ephemeral secp256k1 public key, uncompressed lowercase hex. */
52
- exports.identityMoveEphemeralKeySchema = zod_1.z
53
- .string()
54
- .trim()
55
- .regex(/^04[0-9a-f]{128}$/, 'ephemeral public key must be uncompressed, lowercase hex');
56
- exports.IDENTITY_MOVE_STATUSES = ['pending', 'joined', 'sealed', 'completed', 'cancelled', 'expired'];
57
- /** The QR payload Commons scans. Carries the move id only. */
58
- exports.IDENTITY_MOVE_QR_PREFIX = 'oxycommons://move?id=';
59
- const hex64 = (label) => zod_1.z.string().trim().regex(/^[0-9a-f]{64}$/, `${label} must be 64 lowercase hex characters`);
60
- exports.identityMoveCreateRequestSchema = zod_1.z
61
- .object({
62
- /** `H(initiator ephemeral key, nonce)` — the key itself is revealed only after Commons joins. */
63
- initiatorCommitment: hex64('initiatorCommitment'),
64
- })
65
- .strict();
66
- exports.identityMoveCreateResponseSchema = zod_1.z.object({
67
- moveId: exports.identityMoveIdSchema,
68
- expiresAt: zod_1.z.string().datetime(),
69
- });
70
- exports.identityMoveJoinRequestSchema = zod_1.z.object({
71
- responderEphemeralPublicKey: exports.identityMoveEphemeralKeySchema,
72
- });
73
- /** After Commons joined: the committed key and its nonce. */
74
- exports.identityMoveRevealRequestSchema = zod_1.z
75
- .object({
76
- initiatorEphemeralPublicKey: exports.identityMoveEphemeralKeySchema,
77
- commitmentNonce: hex64('commitmentNonce'),
78
- })
79
- .strict();
80
- exports.identityMoveSealRequestSchema = zod_1.z
81
- .object({
82
- /** 24-byte XChaCha20-Poly1305 nonce, hex. */
83
- nonce: zod_1.z.string().trim().regex(/^[0-9a-f]{48}$/, 'nonce must be 48 lowercase hex characters'),
84
- /** The 16–32-byte phrase entropy (12–24 words), tag appended, hex. */
85
- ciphertext: zod_1.z
86
- .string()
87
- .trim()
88
- .regex(/^(?:[0-9a-f]{64}|[0-9a-f]{72}|[0-9a-f]{80}|[0-9a-f]{88}|[0-9a-f]{96})$/, 'ciphertext has an unsupported length'),
89
- /**
90
- * Root proof (`identity_move_seal`), payload `{ moveId, nonce, ciphertext }`,
91
- * over a one-use challenge from `POST /identity/proof-challenge`.
92
- */
93
- proof: identityProof_1.identityProofSchema,
94
- })
95
- .strict();
96
- exports.identityMoveReceiptRequestSchema = zod_1.z
97
- .object({
98
- /** Root signature over `buildMoveReceiptMessage(...)`. */
99
- signature: zod_1.z.string().trim().min(1).max(512),
100
- })
101
- .strict();
102
- exports.identityMoveStateSchema = zod_1.z.object({
103
- moveId: exports.identityMoveIdSchema,
104
- status: zod_1.z.enum(exports.IDENTITY_MOVE_STATUSES),
105
- initiatorCommitment: zod_1.z.string(),
106
- initiatorCommitmentNonce: zod_1.z.string().nullable(),
107
- publicKey: zod_1.z.string().regex(/^04[0-9a-f]{128}$/),
108
- initiatorEphemeralPublicKey: exports.identityMoveEphemeralKeySchema.nullable(),
109
- responderEphemeralPublicKey: exports.identityMoveEphemeralKeySchema.nullable(),
110
- nonce: zod_1.z.string().nullable(),
111
- ciphertext: zod_1.z.string().nullable(),
112
- receiptSignature: zod_1.z.string().nullable(),
113
- expiresAt: zod_1.z.string().datetime(),
114
- });
115
- /**
116
- * The initiator's commitment input, `canonicalJson({ v, purpose, key, nonce })`,
117
- * which the caller hashes with SHA-256.
118
- */
119
- function buildMoveCommitmentInput(initiatorEphemeralPublicKey, nonce) {
120
- return (0, identityProof_1.canonicalJson)({
121
- v: 2,
122
- purpose: 'oxy-identity-move-initiator-commitment',
123
- initiatorEphemeralPublicKey: initiatorEphemeralPublicKey.toLowerCase(),
124
- nonce: nonce.toLowerCase(),
125
- });
126
- }
127
- /** The bytes both sides hash for the 6-digit code. */
128
- function buildMoveSasInput(input) {
129
- return (0, identityProof_1.canonicalJson)({
130
- v: 'oxy-identity-transfer-sas-v2',
131
- moveId: input.moveId.toLowerCase(),
132
- initiator: input.initiatorEphemeralPublicKey.toLowerCase(),
133
- responder: input.responderEphemeralPublicKey.toLowerCase(),
134
- commitment: input.initiatorCommitment.toLowerCase(),
135
- });
136
- }
137
- /** The ciphertext digest input the receipt binds: `canonicalJson({ nonce, ciphertext })`. */
138
- function buildMoveCiphertextDigestInput(sealed) {
139
- return (0, identityProof_1.canonicalJson)({ nonce: sealed.nonce.toLowerCase(), ciphertext: sealed.ciphertext.toLowerCase() });
140
- }
141
- /** The payload a seal proof digests. */
142
- function buildMoveSealPayload(moveId, sealed) {
143
- return { moveId: moveId.toLowerCase(), nonce: sealed.nonce.toLowerCase(), ciphertext: sealed.ciphertext.toLowerCase() };
144
- }
145
- /** The exact bytes a receipt signs. */
146
- function buildMoveReceiptMessage(input) {
147
- return (0, identityProof_1.canonicalJson)({
148
- v: 2,
149
- domain: 'oxy-identity-move-receipt',
150
- moveId: input.moveId.toLowerCase(),
151
- rootPublicKey: input.rootPublicKey.toLowerCase(),
152
- initiator: input.initiatorEphemeralPublicKey.toLowerCase(),
153
- responder: input.responderEphemeralPublicKey.toLowerCase(),
154
- ciphertextDigest: input.ciphertextDigest.toLowerCase(),
155
- });
156
- }
@@ -1,51 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.identityRecoveryCompleteRequestSchema = exports.identityRecoveryStartRequestSchema = exports.identityRecoveryChallengeResponseSchema = exports.IDENTITY_RECOVERY_TTL_MS = void 0;
4
- /**
5
- * Signed-out recovery contract (ADR 0024 D5) — get an EXISTING account back from
6
- * its root alone, with no passkey, session or email.
7
- *
8
- * 1. `POST /identity/recovery/challenge` → a one-use challenge. It says nothing
9
- * about any account.
10
- * 2. The holder derives the root locally from recovery material (12/24 words or a
11
- * raw key) and signs `recover_account_start` over that challenge:
12
- * `POST /identity/recovery/start { publicKey, proof }`. Only a valid proof
13
- * learns which account the root belongs to; the response carries passkey
14
- * registration options for THAT account and a short-lived ticket.
15
- * 3. The holder creates the passkey, seals the root under it (PRF), and signs
16
- * `recover_account_complete` over the registration challenge and the envelope
17
- * digest: `POST /identity/recovery/complete`. The passkey, the envelope and a
18
- * session are created in one transaction.
19
- *
20
- * The recovery material and the root never leave the holder. Platform-agnostic —
21
- * zod only, ESM-safe.
22
- */
23
- const zod_1 = require("zod");
24
- const identityProof_1 = require("./identityProof");
25
- const webIdentityCarrier_1 = require("./webIdentityCarrier");
26
- /** A recovery attempt lives this long between steps. */
27
- exports.IDENTITY_RECOVERY_TTL_MS = 5 * 60 * 1000;
28
- exports.identityRecoveryChallengeResponseSchema = zod_1.z.object({
29
- challenge: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
30
- expiresAt: zod_1.z.number().int().positive(),
31
- });
32
- exports.identityRecoveryStartRequestSchema = zod_1.z
33
- .object({
34
- publicKey: webIdentityCarrier_1.webIdentityPublicKeySchema,
35
- /** `recover_account_start`, subject `root:<publicKey>`, actor `anonymous`. */
36
- proof: identityProof_1.identityProofSchema,
37
- })
38
- .strict();
39
- exports.identityRecoveryCompleteRequestSchema = zod_1.z
40
- .object({
41
- ticket: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
42
- /** The browser `RegistrationResponseJSON`, verified by the API's WebAuthn library. */
43
- response: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
44
- /** The root sealed under the new passkey — exactly one wrap, for that credential. */
45
- envelope: webIdentityCarrier_1.webIdentityEnvelopeSchema,
46
- /** `recover_account_complete`, subject = account id, actor `credential:<id>`, challenge = registration challenge (hex). */
47
- proof: identityProof_1.identityProofSchema,
48
- deviceName: zod_1.z.string().trim().max(100).optional(),
49
- deviceFingerprint: zod_1.z.string().trim().max(512).optional(),
50
- })
51
- .strict();