@oxy.so/contracts 2.2.0 → 4.0.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 (41) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/accountEmail.js +21 -25
  3. package/dist/cjs/deviceBoot.js +2 -2
  4. package/dist/cjs/deviceSession.js +73 -16
  5. package/dist/cjs/externalIdentity.js +9 -3
  6. package/dist/cjs/identity.js +1 -3
  7. package/dist/cjs/identityLink.js +22 -19
  8. package/dist/cjs/identityProof.js +2 -2
  9. package/dist/cjs/index.js +59 -28
  10. package/dist/cjs/reputation.js +10 -55
  11. package/dist/cjs/signIn.js +304 -0
  12. package/dist/esm/.tsbuildinfo +1 -1
  13. package/dist/esm/accountEmail.js +21 -25
  14. package/dist/esm/deviceBoot.js +2 -2
  15. package/dist/esm/deviceSession.js +72 -15
  16. package/dist/esm/externalIdentity.js +8 -2
  17. package/dist/esm/identity.js +1 -3
  18. package/dist/esm/identityLink.js +21 -18
  19. package/dist/esm/identityProof.js +2 -2
  20. package/dist/esm/index.js +11 -11
  21. package/dist/esm/reputation.js +9 -54
  22. package/dist/esm/signIn.js +299 -0
  23. package/dist/types/.tsbuildinfo +1 -1
  24. package/dist/types/accountEmail.d.ts +20 -28
  25. package/dist/types/accountGraph.d.ts +4 -4
  26. package/dist/types/deviceBoot.d.ts +2 -2
  27. package/dist/types/deviceSession.d.ts +127 -15
  28. package/dist/types/externalIdentity.d.ts +53 -46
  29. package/dist/types/identity.d.ts +4 -8
  30. package/dist/types/identityLink.d.ts +54 -118
  31. package/dist/types/identityProof.d.ts +3 -3
  32. package/dist/types/index.d.ts +8 -8
  33. package/dist/types/inference/entitlement.d.ts +2 -2
  34. package/dist/types/oauth.d.ts +16 -16
  35. package/dist/types/reputation.d.ts +32 -127
  36. package/dist/types/signIn.d.ts +717 -0
  37. package/dist/types/userResponse.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/dist/cjs/webauthn.js +0 -114
  40. package/dist/esm/webauthn.js +0 -111
  41. package/dist/types/webauthn.d.ts +0 -173
@@ -1,22 +1,26 @@
1
1
  /**
2
- * Recovery email contracts (ADR 0029 D3).
2
+ * Email codes and tickets (ADR 0030).
3
3
  *
4
- * A web account is a username, a passkey and a recovery email. The email is
5
- * proven by a 6-digit code sent to it, and the proof is a short-lived one-use
6
- * ticket the next step spends:
4
+ * A web account is a username and an email; a password and an authenticator
5
+ * app are optional and added later. The email is proven by a 6-digit code sent
6
+ * to it, and the proof is a short-lived one-use ticket the next step spends:
7
7
  *
8
- * - `signup`: the ticket lets `POST /webauthn/register/verify` create the
9
- * account with that email;
10
- * - `recovery`: the person names their username or email, the code goes to the
11
- * account's recovery email, and the ticket lets them register a new passkey
12
- * for that account.
8
+ * - `signup`: the ticket lets `POST /auth/signup` create the account with that
9
+ * email. `start` answers the same whether or not the address already has an
10
+ * account, so it never tells anyone which emails have an Oxy account.
13
11
  *
14
- * `start` answers the same whether or not an account exists, so neither purpose
15
- * tells anyone which emails or usernames have an Oxy account. An account with a
16
- * Commons key has no recovery email: it recovers in Commons.
12
+ * Signing in by email (`signin`) and re-verifying before a sensitive change
13
+ * (`reauth`) use the same code, through their own routes (`signIn.ts`).
17
14
  */
18
15
  import { z } from 'zod';
19
- export declare const EMAIL_VERIFICATION_PURPOSES: readonly ["signup", "recovery"];
16
+ /**
17
+ * - `signup`: above.
18
+ * - `signin`: the code (and link) of an email sign-in (`POST /auth/signin/email/start`).
19
+ * - `reauth`: a signed-in person proving it is them before a sensitive step
20
+ * (`POST /users/me/reauth/email`): a password, an authenticator, deleting the
21
+ * account, linking Commons.
22
+ */
23
+ export declare const EMAIL_VERIFICATION_PURPOSES: readonly ["signup", "signin", "reauth"];
20
24
  export type EmailVerificationPurpose = (typeof EMAIL_VERIFICATION_PURPOSES)[number];
21
25
  /** Digits in a code. */
22
26
  export declare const EMAIL_CODE_LENGTH = 6;
@@ -31,7 +35,7 @@ export declare const emailAddressSchema: z.ZodString;
31
35
  /** An opaque one-use ticket (32 random bytes, base64url). */
32
36
  export declare const emailTicketSchema: z.ZodString;
33
37
  /** `POST /auth/email/verify/start` */
34
- export declare const emailVerificationStartRequestSchema: z.ZodDiscriminatedUnion<"purpose", [z.ZodObject<{
38
+ export declare const emailVerificationStartRequestSchema: z.ZodObject<{
35
39
  purpose: z.ZodLiteral<"signup">;
36
40
  email: z.ZodString;
37
41
  }, "strict", z.ZodTypeAny, {
@@ -40,17 +44,7 @@ export declare const emailVerificationStartRequestSchema: z.ZodDiscriminatedUnio
40
44
  }, {
41
45
  purpose: "signup";
42
46
  email: string;
43
- }>, z.ZodObject<{
44
- purpose: z.ZodLiteral<"recovery">;
45
- /** The account's username, or its recovery email. */
46
- identifier: z.ZodString;
47
- }, "strict", z.ZodTypeAny, {
48
- purpose: "recovery";
49
- identifier: string;
50
- }, {
51
- purpose: "recovery";
52
- identifier: string;
53
- }>]>;
47
+ }>;
54
48
  export type EmailVerificationStartRequest = z.infer<typeof emailVerificationStartRequestSchema>;
55
49
  export interface EmailVerificationStartResponse {
56
50
  /** Names this verification in `confirm`. Returned whether or not a code was sent. */
@@ -75,8 +69,6 @@ export interface EmailVerificationConfirmResponse {
75
69
  ticket: string;
76
70
  /** Unix milliseconds after which the ticket is refused. */
77
71
  expiresAt: number;
78
- /** Recovery only: the account the ticket recovers. `null` for sign-up. */
79
- username: string | null;
80
72
  }
81
73
  export declare const emailVerificationConfirmResponseSchema: z.ZodType<EmailVerificationConfirmResponse>;
82
74
  /**
@@ -90,7 +82,7 @@ export declare const EMAIL_VERIFICATION_ERROR_CODES: {
90
82
  readonly tooManyAttempts: "EMAIL_CODE_TOO_MANY_ATTEMPTS";
91
83
  /** The ticket is unknown, expired, spent, or for another email or purpose. */
92
84
  readonly ticketInvalid: "EMAIL_TICKET_INVALID";
93
- /** A sign-up without a confirmed recovery email. */
85
+ /** A sign-up without a confirmed email. */
94
86
  readonly ticketRequired: "EMAIL_TICKET_REQUIRED";
95
87
  /** This server cannot send mail. */
96
88
  readonly unavailable: "EMAIL_UNAVAILABLE";
@@ -315,8 +315,8 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
315
315
  */
316
316
  isPrivateAccount: z.ZodOptional<z.ZodBoolean>;
317
317
  }, "strip", z.ZodTypeAny, {
318
- username: string;
319
318
  kind: "bot" | "organization" | "project" | "channel";
319
+ username: string;
320
320
  parentAccountId?: string | undefined;
321
321
  name?: {
322
322
  first?: string | undefined;
@@ -330,8 +330,8 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
330
330
  accountCategories?: ("security" | "news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[] | undefined;
331
331
  isPrivateAccount?: boolean | undefined;
332
332
  }, {
333
- username: string;
334
333
  kind: "bot" | "organization" | "project" | "channel";
334
+ username: string;
335
335
  parentAccountId?: string | undefined;
336
336
  name?: {
337
337
  first?: string | undefined;
@@ -345,8 +345,8 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
345
345
  accountCategories?: ("security" | "news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[] | undefined;
346
346
  isPrivateAccount?: boolean | undefined;
347
347
  }>, {
348
- username: string;
349
348
  kind: "bot" | "organization" | "project" | "channel";
349
+ username: string;
350
350
  parentAccountId?: string | undefined;
351
351
  name?: {
352
352
  first?: string | undefined;
@@ -360,8 +360,8 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
360
360
  accountCategories?: ("security" | "news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[] | undefined;
361
361
  isPrivateAccount?: boolean | undefined;
362
362
  }, {
363
- username: string;
364
363
  kind: "bot" | "organization" | "project" | "channel";
364
+ username: string;
365
365
  parentAccountId?: string | undefined;
366
366
  name?: {
367
367
  first?: string | undefined;
@@ -4,8 +4,8 @@
4
4
  * SINGLE SOURCE OF TRUTH for the first-party login result (the session arm). The
5
5
  * API validates its OUTPUT against this schema; every consumer (`@oxy.so/core`'s
6
6
  * auth mixin) validates its INPUT against the same definition, so producer and
7
- * consumers cannot drift. Sign-in is passkey (WebAuthn) or Commons handoff —
8
- * password and 2FA were removed, so the only outcome is a completed session.
7
+ * consumers cannot drift. This is the session arm every sign-in
8
+ * ends in (email code or link, password, authenticator, Commons handoff).
9
9
  *
10
10
  * The device transport is `deviceId` + `deviceSecret` + `POST /session/device/token`
11
11
  * (see `deviceSession.ts`). The legacy cookie/bootstrap/refresh-family lanes were
@@ -166,9 +166,10 @@ export type DeviceSessionSync = z.infer<typeof deviceSessionSyncSchema>;
166
166
  /**
167
167
  * Request body for `POST /session/device/token` — the client presents the
168
168
  * `deviceId` it stored first-party plus the opaque `deviceSecret`. NO bearer:
169
- * possession of the secret IS the proof of device ownership. The server matches
170
- * `sha256(deviceSecret)` against the device's stored `secretHash` (constant-time)
171
- * and mints a short access token for the device's active account.
169
+ * possession of the secret IS the proof of device ownership. The server looks
170
+ * `sha256(deviceSecret)` up among the device's holder credentials (one per app
171
+ * or origin that joined the shared DeviceSession) and mints a short access
172
+ * token for the device's active account.
172
173
  *
173
174
  * `accountId` pins the mint to ONE account of that device instead of whichever
174
175
  * account is currently active. It exists for identity-bound clients (Commons),
@@ -196,8 +197,8 @@ export declare const deviceTokenMintRequestSchema: z.ZodObject<{
196
197
  * short access token for the active account, its expiry, the device secret the
197
198
  * client must persist (`nextDeviceSecret` — on mint this echoes the presented
198
199
  * secret unchanged so concurrent refreshes from multiple origins do not race),
199
- * and the projected device-session state. Sign-in rotates the secret via
200
- * `issueDeviceSecret`; mint does not.
200
+ * and the projected device-session state. Nothing rotates: each sign-in issues
201
+ * a NEW holder credential and leaves the others valid.
201
202
  */
202
203
  export declare const deviceTokenMintResponseSchema: z.ZodObject<{
203
204
  accessToken: z.ZodString;
@@ -330,12 +331,11 @@ export type SessionAccountsChangedEvent = z.infer<typeof sessionAccountsChangedE
330
331
  * derived server-side from it) and consumed afterwards only by native
331
332
  * background code, which has no JS runtime to mint a token for itself.
332
333
  *
333
- * Deliberately a SEPARATE credential from the rotating `deviceSecret`: that one
334
- * rotates on every mint, so background code presenting it would become a second
335
- * writer of a value the JS runtime depends on, and background code killed
336
- * mid-rotation would silently sign the user out on the next cold start. Against
337
- * this credential background code is the sole writer, and it can never rotate
338
- * anything JS reads.
334
+ * Deliberately a SEPARATE credential from the holder `deviceSecret`: that one
335
+ * is device-wide and mints for whichever account is active, while this one is
336
+ * bound to ONE account and expires, so a widget worker never holds a
337
+ * credential that reaches every account on the device. Background code is its
338
+ * sole writer and never touches anything JS reads.
339
339
  *
340
340
  * The raw `secret` is returned exactly once, at provision time — never stored
341
341
  * retrievably, never logged, never re-read. A caller that loses it provisions
@@ -368,10 +368,10 @@ export declare const deviceBackgroundCredentialResponseSchema: z.ZodObject<{
368
368
  * native background code with NO bearer and NO cookies: possession of the
369
369
  * background `secret` IS the proof, as it is for the device-secret mint.
370
370
  *
371
- * Unlike that mint this one NEVER rotates the presented secret (hence no
372
- * `next…` field to persist in the response), so background code interrupted
373
- * anywhere between request and response leaves the credential intact and
374
- * usable on its next run.
371
+ * Like that mint this one NEVER rotates the presented secret, and it carries
372
+ * no `next…` field at all, so background code interrupted anywhere between
373
+ * request and response leaves the credential intact and usable on its next
374
+ * run.
375
375
  */
376
376
  export declare const deviceBackgroundTokenRequestSchema: z.ZodObject<{
377
377
  deviceId: z.ZodString;
@@ -409,3 +409,115 @@ export declare const deviceBackgroundTokenResponseSchema: z.ZodObject<{
409
409
  export type DeviceBackgroundCredentialResponse = z.infer<typeof deviceBackgroundCredentialResponseSchema>;
410
410
  export type DeviceBackgroundTokenRequest = z.infer<typeof deviceBackgroundTokenRequestSchema>;
411
411
  export type DeviceBackgroundTokenResponse = z.infer<typeof deviceBackgroundTokenResponseSchema>;
412
+ /**
413
+ * Proof that the caller holds a device: the `deviceId` it stored first-party and
414
+ * one of that device's holder secrets. Sent with `POST /session/device/join-code`
415
+ * and, optionally, with a sign-in (`POST /auth/session/claim`, the email,
416
+ * password and second-factor sign-ins, `POST /auth/signup`), where
417
+ * a valid proof puts the new session on THAT device so every app holding it sees
418
+ * the account. An invalid proof on a sign-in is ignored, never an error.
419
+ */
420
+ export declare const deviceProofSchema: z.ZodObject<{
421
+ deviceId: z.ZodString;
422
+ deviceSecret: z.ZodString;
423
+ }, "strip", z.ZodTypeAny, {
424
+ deviceId: string;
425
+ deviceSecret: string;
426
+ }, {
427
+ deviceId: string;
428
+ deviceSecret: string;
429
+ }>;
430
+ /**
431
+ * `POST /session/device/register` — auth.oxy.so only. No body. A new, empty
432
+ * DeviceSession with a server-chosen `deviceId` and ONE holder credential for
433
+ * auth.oxy.so. The raw secret is returned exactly once.
434
+ */
435
+ export declare const deviceRegisterResponseSchema: z.ZodObject<{
436
+ deviceId: z.ZodString;
437
+ deviceSecret: z.ZodString;
438
+ }, "strip", z.ZodTypeAny, {
439
+ deviceId: string;
440
+ deviceSecret: string;
441
+ }, {
442
+ deviceId: string;
443
+ deviceSecret: string;
444
+ }>;
445
+ /**
446
+ * `POST /session/device/join-code` — auth.oxy.so only (the bridge window). Proves
447
+ * auth.oxy.so's device and asks for a one-use code an official app redeems to
448
+ * join it. The code is bound to the application (`clientId`), its exact
449
+ * registered `redirectUri` and the app's PKCE challenge, and lives about a
450
+ * minute.
451
+ */
452
+ export declare const deviceJoinCodeRequestSchema: z.ZodObject<{
453
+ deviceId: z.ZodString;
454
+ deviceSecret: z.ZodString;
455
+ } & {
456
+ clientId: z.ZodString;
457
+ redirectUri: z.ZodString;
458
+ codeChallenge: z.ZodString;
459
+ codeChallengeMethod: z.ZodLiteral<"S256">;
460
+ }, "strip", z.ZodTypeAny, {
461
+ deviceId: string;
462
+ deviceSecret: string;
463
+ clientId: string;
464
+ redirectUri: string;
465
+ codeChallenge: string;
466
+ codeChallengeMethod: "S256";
467
+ }, {
468
+ deviceId: string;
469
+ deviceSecret: string;
470
+ clientId: string;
471
+ redirectUri: string;
472
+ codeChallenge: string;
473
+ codeChallengeMethod: "S256";
474
+ }>;
475
+ export declare const deviceJoinCodeResponseSchema: z.ZodObject<{
476
+ code: z.ZodString;
477
+ /** Seconds until the code expires. */
478
+ expiresIn: z.ZodNumber;
479
+ }, "strip", z.ZodTypeAny, {
480
+ code: string;
481
+ expiresIn: number;
482
+ }, {
483
+ code: string;
484
+ expiresIn: number;
485
+ }>;
486
+ /**
487
+ * `POST /session/device/join` — called by the app's own origin with the code the
488
+ * bridge window posted to it and the PKCE verifier only the app holds. Returns a
489
+ * NEW holder credential for the browser's device; the app then mints through the
490
+ * ordinary `POST /session/device/token`.
491
+ */
492
+ export declare const deviceJoinRequestSchema: z.ZodObject<{
493
+ code: z.ZodString;
494
+ codeVerifier: z.ZodString;
495
+ clientId: z.ZodString;
496
+ redirectUri: z.ZodString;
497
+ }, "strip", z.ZodTypeAny, {
498
+ code: string;
499
+ clientId: string;
500
+ redirectUri: string;
501
+ codeVerifier: string;
502
+ }, {
503
+ code: string;
504
+ clientId: string;
505
+ redirectUri: string;
506
+ codeVerifier: string;
507
+ }>;
508
+ export declare const deviceJoinResponseSchema: z.ZodObject<{
509
+ deviceId: z.ZodString;
510
+ deviceSecret: z.ZodString;
511
+ }, "strip", z.ZodTypeAny, {
512
+ deviceId: string;
513
+ deviceSecret: string;
514
+ }, {
515
+ deviceId: string;
516
+ deviceSecret: string;
517
+ }>;
518
+ export type DeviceProof = z.infer<typeof deviceProofSchema>;
519
+ export type DeviceRegisterResponse = z.infer<typeof deviceRegisterResponseSchema>;
520
+ export type DeviceJoinCodeRequest = z.infer<typeof deviceJoinCodeRequestSchema>;
521
+ export type DeviceJoinCodeResponse = z.infer<typeof deviceJoinCodeResponseSchema>;
522
+ export type DeviceJoinRequest = z.infer<typeof deviceJoinRequestSchema>;
523
+ export type DeviceJoinResponse = z.infer<typeof deviceJoinResponseSchema>;