@nxgt/janus 0.19.0 → 0.21.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 (52) hide show
  1. package/README.md +164 -10
  2. package/dist/auth/email-flows/reset-password.d.ts.map +1 -1
  3. package/dist/auth/events.d.ts +3 -3
  4. package/dist/auth/index.d.ts +1 -1
  5. package/dist/auth/index.d.ts.map +1 -1
  6. package/dist/auth/magic-link.d.ts +3 -0
  7. package/dist/auth/magic-link.d.ts.map +1 -1
  8. package/dist/auth/one-time/issue.d.ts +6 -0
  9. package/dist/auth/one-time/issue.d.ts.map +1 -1
  10. package/dist/auth/prepared.d.ts +21 -0
  11. package/dist/auth/prepared.d.ts.map +1 -0
  12. package/dist/auth/proven-sign-in.d.ts +22 -0
  13. package/dist/auth/proven-sign-in.d.ts.map +1 -0
  14. package/dist/auth/sign-in-code.d.ts +4 -0
  15. package/dist/auth/sign-in-code.d.ts.map +1 -1
  16. package/dist/auth/types/email-flows.d.ts +18 -0
  17. package/dist/auth/types/email-flows.d.ts.map +1 -1
  18. package/dist/auth/types/find-by-email.d.ts +31 -0
  19. package/dist/auth/types/find-by-email.d.ts.map +1 -0
  20. package/dist/auth/types/index.d.ts +3 -0
  21. package/dist/auth/types/index.d.ts.map +1 -1
  22. package/dist/auth/types/janus.d.ts +8 -5
  23. package/dist/auth/types/janus.d.ts.map +1 -1
  24. package/dist/auth/types/magic-link.d.ts +11 -0
  25. package/dist/auth/types/magic-link.d.ts.map +1 -1
  26. package/dist/auth/types/prepared.d.ts +41 -0
  27. package/dist/auth/types/prepared.d.ts.map +1 -0
  28. package/dist/auth/types/proven-sign-in.d.ts +43 -0
  29. package/dist/auth/types/proven-sign-in.d.ts.map +1 -0
  30. package/dist/auth/types/sign-in.d.ts +2 -2
  31. package/dist/auth/users/any-type-api.d.ts +2 -2
  32. package/dist/auth/users/any-type-api.d.ts.map +1 -1
  33. package/dist/auth/users/find-by-email.d.ts +11 -0
  34. package/dist/auth/users/find-by-email.d.ts.map +1 -0
  35. package/dist/auth/users/type-api.d.ts +2 -2
  36. package/dist/auth/users/type-api.d.ts.map +1 -1
  37. package/dist/index.js +105 -17
  38. package/dist/index.js.map +12 -9
  39. package/docs/README.md +2 -2
  40. package/docs/guide/devices.md +4 -0
  41. package/docs/guide/email-flows.md +105 -0
  42. package/docs/guide/errors.md +2 -2
  43. package/docs/guide/events.md +2 -2
  44. package/docs/guide/magic-link.md +49 -2
  45. package/docs/guide/passwords.md +5 -2
  46. package/docs/guide/second-factor.md +1 -1
  47. package/docs/guide/sessions.md +105 -1
  48. package/docs/guide/sign-in-code.md +54 -2
  49. package/docs/guide/users.md +70 -0
  50. package/docs/roadmap.md +24 -33
  51. package/docs/troubleshooting.md +100 -6
  52. package/package.json +1 -1
package/README.md CHANGED
@@ -327,6 +327,9 @@ await auth.signInCode.request(email); // { code, challenge, email,
327
327
  await auth.signInCode.confirm(challenge, code); // { status: 'signedIn', user, session, token }
328
328
  await auth.magicLink.request(email); // { token, email, expiresAt, user } | null
329
329
  await auth.magicLink.confirm(token); // { status: 'signedIn', user, session, token }
330
+ await auth.magicLink.prepare(email); // counted, nobody looked up: { send() } — and signInCode, resetPassword
331
+ await auth.findByEmail(email); // User | null — server-side only, counts nothing; every type with an e-mail
332
+ await auth.signInProven(user.id); // privileged: after a proof YOUR server verified — { status: 'signedIn', … }
330
333
  await auth.stepUp.request(user); // { via: 'email', code, challenge, email, expiresAt, user }
331
334
  await auth.stepUp.confirm(request, challenge, code); // the request's session, authenticatedAt: now
332
335
 
@@ -374,14 +377,15 @@ else reaches the store and is asynchronous.
374
377
  compile error on `login`, and the message lists the fields you could have
375
378
  meant. It is normalised with `'lowercaseTrim'` unless you say otherwise.
376
379
  - **`email`** defaults to the field named `email`. A type without one has no
377
- `verifyEmail`, no `resetPassword`, no `signInCode` and no `magicLink` — they
378
- are absent from its type, not failing at run time. Changing the e-mail sets `emailVerified`
379
- back to `false`.
380
+ `findByEmail`, no `verifyEmail`, no `resetPassword`, no `signInCode` and
381
+ no `magicLink` — they are absent from its type, not failing at run time.
382
+ Changing the e-mail sets `emailVerified` back to `false`.
380
383
  - **Per type**: `create`, `find` (or `null`), `findMany`, `get` (or
381
384
  `NOT_FOUND`), `list`, `update(user, patch)` — merged over the stored fields,
382
- then validated whole — `setActive` and `delete`; with a password, `signUp`,
383
- `signIn`, `findByLogin`, `setPassword` and `changePassword`. Every write but
384
- `delete` takes an optional `ifVersion`.
385
+ then validated whole — `setActive`, `delete` and `signInProven` (below);
386
+ with an e-mail, `findByEmail` (below), password or not; with a password,
387
+ `signUp`, `signIn`, `findByLogin`, `setPassword` and `changePassword`.
388
+ Every write but `delete` takes an optional `ifVersion`.
385
389
  - **`findMany(ids)`** answers the type's users **in the order the ids were
386
390
  given**, each once — a repeated id at its first place. An id `find` answers
387
391
  `null` for — malformed, unknown, another type's — is **left out**, so match
@@ -422,6 +426,8 @@ else reaches the store and is asynchronous.
422
426
  `magicLink.request`, `signInCode.request` and `resetPassword.request` — an
423
427
  address nobody holds is counted and refused alike — and per user for
424
428
  `verifyEmail.send` and for `stepUp.request` when it e-mails a code.
429
+ `prepare` counts as `request` does, in the same window
430
+ ([requests in two steps](#requests-in-two-steps--prepare)).
425
431
  `mail: { throttle: { attempts, window } }` changes it, `mail: { throttle:
426
432
  false }` turns it off; a store that cannot count throws `STORE_FAILED` and
427
433
  nothing is issued
@@ -724,6 +730,123 @@ to type.
724
730
  confirms from a `POST` so mail scanners spend nothing, every error, routes
725
731
  and a test.
726
732
 
733
+ ### Requests in two steps — `prepare`
734
+
735
+ ```ts
736
+ // In the visitor's request: counted, nobody looked up — the same time for any address.
737
+ // Past the limit it throws MailThrottledError: answer 429 with retryAfter, which
738
+ // @nxgt/janus-hono's janusErrors() and @nxgt/janus-graphql do for you.
739
+ const pending = await auth.magicLink.prepare(email); // { send() }
740
+
741
+ // Off the visitor's request: looked up, issued, mailed — or nothing, for nobody.
742
+ void (async () => {
743
+ const issued = await pending.send(); // what request answers: { token, email, expiresAt, user } | null
744
+ if (issued !== null) {
745
+ await sendMail(issued.email, `Sign in: https://app.example/sign-in/link?token=${issued.token}`);
746
+ }
747
+ })().catch(reportError); // a STORE_FAILED here reaches nobody: log it
748
+
749
+ // the same page for everybody, whoever holds the address
750
+ ```
751
+
752
+ `magicLink.prepare(email)`, `signInCode.prepare(email)` and
753
+ `resetPassword.prepare(email)` are `request(email)` cut in two at the mail
754
+ throttle's count, so `MAIL_THROTTLED` reaches the visitor while the e-mail
755
+ still goes out off their request.
756
+
757
+ - **`prepare(email)` validates, counts the address, and looks nobody up**:
758
+ the same store calls whoever holds the address, none with
759
+ `mail: { throttle: false }`. Past the limit it is `MailThrottledError`
760
+ with `retryAfter`, and nothing is issued. It shares its count with
761
+ `request`: one window per flow and address.
762
+ - **`send()` does the rest of `request`, once** — looks the address up,
763
+ issues, spends the earlier tokens — and answers what `request` answers,
764
+ `null` for nobody. It counts nothing: the count was `prepare`'s. A second
765
+ call is a `TypeError`, and so is a call after one that failed: prepare
766
+ again, which counts again.
767
+ - **`signInCode.prepare` also answers the `challenge`**, minted before the
768
+ lookup, so the visitor's cookie is set now, whoever holds the address —
769
+ it replaces the decoy an unknown address needed; for nobody it confirms as
770
+ `TOKEN_UNKNOWN`. `send()` answers the code issued under it.
771
+ - Typed per flow: `PreparedRequest<IssuedToken & { user }>` for a link and
772
+ a reset, `PreparedCode<User>` for a code. `verifyEmail.send` and
773
+ `stepUp.request` have no `prepare`: they take a user the application
774
+ already holds, so their time tells nothing about who has an account.
775
+
776
+ [The e-mail flows guide](docs/guide/email-flows.md#requests-in-two-steps)
777
+ has a route for each flow, with Hono.
778
+
779
+ ### Signing in on your own proof — `signInProven`
780
+
781
+ ```ts
782
+ // Accepting an invitation: the proof is the invitation token YOUR server issued and verified.
783
+ const invitation = await invitations.redeem(body.invitationToken); // yours: one use, expiring, hashed at rest
784
+ if (invitation === null) return new Response(null, { status: 404 });
785
+
786
+ const result = await auth.signInProven(invitation.userId, { device: deviceCookie ?? null });
787
+ if (result.status === 'secondFactor') return askForCode(result.challenge); // switch on status, as after signIn
788
+ // result: { status: 'signedIn', user, session, token, newDevice, deviceToken }
789
+ ```
790
+
791
+ Signs in a user **the application proved by its own means** — an invitation
792
+ token it issued and the person followed, a channel of its own it verified —
793
+ with no password, code or link. Every user type has it.
794
+
795
+ - **Privileged: janus checks no credential, your server carries the
796
+ proof.** Call it only after that proof was verified, and **never with an
797
+ id a request supplied**: whoever chooses the id signs in as anybody. No
798
+ route of `@nxgt/janus-hono` or `@nxgt/janus-graphql` exposes it.
799
+ - **It finishes as every sign-in does**: an active second factor answers a
800
+ challenge for `secondFactor.confirm` (`SignInResult`, the same union as
801
+ `signIn`'s); `device` answers `newDevice` and `deviceToken` and sends
802
+ `user.newDeviceSignedIn` for a new one; an inactive user is
803
+ `USER_INACTIVE`.
804
+ - **Takes the user, or their id** (`UserRef`). A malformed id, an unknown
805
+ one, a deleted user or one of another type is `NOT_FOUND`, as for `get`:
806
+ a sign-in that found nobody throws rather than answer something to read
807
+ past.
808
+ - **Sends nothing, counts nothing, spends nothing**: no e-mail, no token,
809
+ no mail-throttle or sign-in-throttle count — so a loop of anonymous
810
+ `magicLink.request` on the invitee's address cannot make it answer 429 —
811
+ and links or codes already in the person's inbox still work. It proves
812
+ no e-mail either: `emailVerified` stays as it was, and nothing is dropped
813
+ as on a first proof by link.
814
+
815
+ [Sessions](docs/guide/sessions.md#signing-in-on-your-own-proof--signinproven)
816
+ has the invitation route in full, and what to verify before the call.
817
+
818
+ ### Finding a user by e-mail — `findByEmail`
819
+
820
+ ```ts
821
+ // Accepting an invitation sent to an address: the account may already exist, on a type with no password.
822
+ const invitation = await invitations.redeem(body.invitationToken); // yours: verified first
823
+ if (invitation === null) return new Response(null, { status: 404 });
824
+
825
+ const member =
826
+ (await auth.member.findByEmail(invitation.email)) ?? // User | null — counts nothing, sends nothing
827
+ (await auth.member.create({ email: invitation.email, name: '' }));
828
+ const result = await auth.member.signInProven(member, { device: deviceCookie ?? null });
829
+ ```
830
+
831
+ The user of this type holding the address, or `null` — on **every type with
832
+ an e-mail, password or not**. A type with no password has no `findByLogin`,
833
+ and needs no password login to be found: declaring one would open the
834
+ password and reset flows on it.
835
+
836
+ - **Normalised as the e-mail flows normalise**: trimmed and lowercased,
837
+ whatever the type's login. A type that signs in with a username is still
838
+ found by its e-mail, and a username that only looks like an address is
839
+ nobody's — the same holder `magicLink.request` and `resetPassword.request`
840
+ would find.
841
+ - **Read-only**: counts nothing in the mail or the sign-in throttle,
842
+ issues nothing, writes nothing. An inactive user is answered, as by
843
+ `find` — `signInProven` then refuses them with `USER_INACTIVE`.
844
+ - **A value that is no address is nobody's**: not a string, empty once
845
+ trimmed, or holding a NUL or a lone surrogate answers `null` without
846
+ asking the store, as `find` answers a malformed id. An outage is
847
+ `STORE_FAILED`, never `null`.
848
+ - **Server-side only**: it tells whether an account exists. See *Traps*.
849
+
727
850
  ### Step-up — `stepUp` and `assertFresh`
728
851
 
729
852
  ```ts
@@ -1086,7 +1209,7 @@ runner-less layer.
1086
1209
  ## Traps
1087
1210
 
1088
1211
  **Once `secondFactor` is configured, switch on `signIn`'s `status`** — and
1089
- on `signInCode.confirm`'s and `magicLink.confirm`'s. A user whose factor is active gets
1212
+ on `signInCode.confirm`'s, `magicLink.confirm`'s and `signInProven`'s. A user whose factor is active gets
1090
1213
  `{ status: 'secondFactor', challenge, expiresAt, userId }`, with no `token`
1091
1214
  and no `session`: an e-mailed code or link proves the e-mail, not the factor.
1092
1215
  `userId` is for your logs and rate limits — answer the visitor the
@@ -1126,6 +1249,26 @@ user — a new `request` spends the one before — so the throttle bounds how
1126
1249
  often anyone who knows an address can fill its inbox or cancel its owner's
1127
1250
  code; it does not stop it.
1128
1251
 
1252
+ **`signInProven` trusts the id you give it — give it only one your server
1253
+ proved.** It checks no credential: an id read off a request body, a query
1254
+ string or a cookie the client wrote signs in whoever sent it, as that user.
1255
+ Call it right after verifying a proof you issued — an invitation token
1256
+ (single use, expiring, stored hashed), a channel of your own — and take the
1257
+ id from that proof's record. For an invitation, it replaces
1258
+ `magicLink.request` + `confirm`, which counts against the mail throttle:
1259
+ five anonymous requests for the invitee's address would make the
1260
+ acceptance answer 429.
1261
+
1262
+ **`findByEmail` is an account-existence oracle — never expose it to an
1263
+ anonymous client.** It answers whether somebody of the type holds an
1264
+ address, at once, with no throttle: a route that calls it on an address a
1265
+ visitor typed tells anybody who has an account. Call it on the server, after
1266
+ a proof of your own — an invitation token your server issued and just
1267
+ verified — with the address read from that proof's record, never from the
1268
+ request. A visitor who types an address goes through `magicLink.request` or
1269
+ `signInCode.request` instead: throttled per address, and answered with the
1270
+ same page whether they issued or not.
1271
+
1129
1272
  **Confirm a sign-in link from a `POST`, never from its `GET`.** Mail
1130
1273
  scanners open every link in an e-mail before the user does: a route that
1131
1274
  calls `magicLink.confirm` on the link's `GET` spends it for the scanner, and
@@ -1263,6 +1406,17 @@ dummy hash when nobody holds the login, so the hashing time does not tell.
1263
1406
  denied. `resetPassword.request` answers `null` for an unknown e-mail for the
1264
1407
  same reason: answer the visitor the same page either way.
1265
1408
 
1409
+ **`request` sent off the visitor's request swallows `MAIL_THROTTLED`.** A
1410
+ `request` for an address with an account looks it up and writes tokens; one
1411
+ for an address nobody holds stops at the lookup — so an application that
1412
+ must not tell the two apart by time runs `request` in the background, where
1413
+ its refusal reaches nobody. Call `prepare(email)` in the visitor's request
1414
+ instead — counted, nobody looked up, the same time for any address — and
1415
+ answer its `MAIL_THROTTLED`; run `send()` in the background. **Never await
1416
+ `send()` in the visitor's request**: its time is `request`'s. And it runs
1417
+ once — a second `send()`, or one after a failed one, is a `TypeError`:
1418
+ `prepare` again.
1419
+
1266
1420
  **`resetPassword.confirm` signs the user out everywhere, and opens no session.**
1267
1421
  Whoever had the old password loses their sessions, and a sign-in they left
1268
1422
  waiting on its second factor is spent with them — as it is by `setPassword`
@@ -1407,7 +1561,7 @@ that sends one, since it is awaited: queue the event and return.
1407
1561
 
1408
1562
  ## Type safety, counted
1409
1563
 
1410
- **One hundred and fifty-five plausible mistakes, one hundred and fifty-five refused at compile time — and
1564
+ **One hundred and sixty-six plausible mistakes, one hundred and sixty-six refused at compile time — and
1411
1565
  two gaps, named.**
1412
1566
 
1413
1567
  The lists are typechecked and never run, with one `@ts-expect-error` per
@@ -1415,10 +1569,10 @@ mistake beside the shapes that must keep compiling. One is a single file:
1415
1569
  `test/types/refusals.ts` (fifteen, on the shared vocabulary). The other three
1416
1570
  are folders with one file per behaviour: `test/types/port/` (twenty-five, on
1417
1571
  the identity stores' port, from the point of view of the person implementing
1418
- it), `test/types/auth/` (sixty-seven, on `janus()`, from the point of view of
1572
+ it), `test/types/auth/` (seventy-eight, on `janus()`, from the point of view of
1419
1573
  the application — twelve of them on the second factor, three on sign-in codes,
1420
1574
  five on user events, four on step-ups, six on the sign-in throttle, five on the mail throttle, four on
1421
- sign-in links, six on devices, two on `findMany`) and `test/types/permissions/` (forty-eight, on the
1575
+ sign-in links, six on devices, two on `findMany`, five on requests in two steps, three on signing in on the application's proof, three on finding a user by e-mail) and `test/types/permissions/` (forty-eight, on the
1422
1576
  permission model and the questions asked of it). The rule comes from
1423
1577
  `nxgt-data`, and so does the reason to distrust the claim without the files:
1424
1578
  when it was last measured on `@nxgt/mongo`, *seven of twelve plausible
@@ -1 +1 @@
1
- {"version":3,"file":"reset-password.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/reset-password.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAOZ,MAAM,YAAY,CAAC;AAMpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGjD,KAAK,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,aAAa,CA8Cf"}
1
+ {"version":3,"file":"reset-password.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/reset-password.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAOZ,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EAAgC,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAG/E,KAAK,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC;AAGhE;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,aAAa,CAsBf"}
@@ -30,9 +30,9 @@ import type { Context } from './context';
30
30
  * spent: a sign-in without the user's phone;
31
31
  * - `user.newDeviceSignedIn` — by a sign-in that opened a session from a
32
32
  * device the user had not signed in from: `signIn`, `secondFactor.confirm`,
33
- * `secondFactor.recover`, `signInCode.confirm` and `magicLink.confirm`, when
34
- * given a `device` its token did not prove. Never by `signUp`, nor without
35
- * a `device`. Carries `sessionId`;
33
+ * `secondFactor.recover`, `signInCode.confirm`, `magicLink.confirm` and
34
+ * `signInProven`, when given a `device` its token did not prove. Never by
35
+ * `signUp`, nor without a `device`. Carries `sessionId`;
36
36
  * - `user.deleted` — by `delete`, once; a replay that finds nobody is none.
37
37
  */
38
38
  export type UserEventType = 'user.created' | 'user.emailVerified' | 'user.passwordReset' | 'user.passwordChanged' | 'user.emailChanged' | 'user.secondFactorEnabled' | 'user.secondFactorDisabled' | 'user.recoveryCodesRegenerated' | 'user.recoveryCodeUsed' | 'user.newDeviceSignedIn' | 'user.deleted';
@@ -8,5 +8,5 @@ export type { JanusStores, Json, JsonObject, PasswordRecord, SecondFactorRecord,
8
8
  export type { SealingKey } from './sealing';
9
9
  export { assertFresh } from './sessions/fresh';
10
10
  export type { StandardSchemaV1 } from './standard-schema';
11
- export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, MagicLinkApi, PasswordApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInOptions, SignInResult, StepUpApi, StepUpByApp, StepUpByEmail, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
11
+ export type { Authenticated, Checked, EmailOf, FindByEmailApi, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, MagicLinkApi, PasswordApi, PreparedCode, PreparedRequest, ProvenSignInApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInOptions, SignInResult, StepUpApi, StepUpByApp, StepUpByEmail, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
@@ -17,6 +17,9 @@ import type { MagicLinkApi, SignInResult } from './types';
17
17
  * Whoever opens the link signs in, in the browser that opened it: the
18
18
  * application confirms it from a `POST`, never from the `GET` of the link,
19
19
  * which a mail scanner follows too.
20
+ *
21
+ * `request` is `prepare`, then `send`: counted, then looked up and issued
22
+ * (`prepared.ts`).
20
23
  */
21
24
  export declare function magicLinkFlows(context: Context, type: ResolvedType, at: At, finish: Finish): MagicLinkApi<AnyUser, SignInResult<AnyUser>>['magicLink'];
22
25
  //# sourceMappingURL=magic-link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../src/auth/magic-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAG/D,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAe,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAY3D"}
1
+ {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../src/auth/magic-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAG/D,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAEX,YAAY,EAEZ,YAAY,EACZ,MAAM,SAAS,CAAC;AAIjB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAkB3D"}
@@ -9,6 +9,12 @@ interface OneTimeRequest {
9
9
  readonly userId: string;
10
10
  readonly address: string;
11
11
  readonly ttlMs: number;
12
+ /**
13
+ * The secret to issue under, minted beforehand — a sign-in code's
14
+ * challenge, handed to the visitor by `prepare` before the lookup. A
15
+ * fresh one by default.
16
+ */
17
+ readonly secret?: string;
12
18
  }
13
19
  /**
14
20
  * Issues a one-time token: 32 random bytes, given back once, and only their
@@ -1 +1 @@
1
- {"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../src/auth/one-time/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,UAAU,cAAc;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,cAAc,GACnB,OAAO,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC,CAEhE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,cAAc,GACnB,OAAO,CAAC;IACV,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB,CAAC,CAGD"}
1
+ {"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../src/auth/one-time/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,UAAU,cAAc;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,cAAc,GACnB,OAAO,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC,CAEhE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,cAAc,GACnB,OAAO,CAAC;IACV,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB,CAAC,CAGD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A request for an e-mail made in two steps — `prepare` counts it, `send`
3
+ * issues — so the mail throttle answers in the visitor's own request, while
4
+ * the lookup and the writes, whose time depends on whether the address has
5
+ * an account, run off it.
6
+ *
7
+ * `prepare` looks nobody up: it validates, counts the address
8
+ * (`mail-requests.ts`) and refuses past the limit, the same store calls for
9
+ * any address. `send` is what `request` does after the count, **once**: the
10
+ * count `prepare` made pays for one issue, so a second call is a `TypeError`
11
+ * — a bug of the caller's, never a value from a request — and nothing a
12
+ * caller can pass skips the count.
13
+ */
14
+ /**
15
+ * `send` for a prepared request: `issue` on the first call, a `TypeError`
16
+ * on every other — marked spent before `issue` starts, so two calls at once
17
+ * cannot both issue, and spent even when `issue` fails: prepare again then,
18
+ * which counts again.
19
+ */
20
+ export declare function sendOnce<T>(where: string, issue: () => Promise<T>): () => Promise<T>;
21
+ //# sourceMappingURL=prepared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepared.d.ts","sourceRoot":"","sources":["../../src/auth/prepared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,MAAM,OAAO,CAAC,CAAC,CAAC,CAWlB"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Signing in a user the application proved by its own means — an
3
+ * invitation token it issued, a channel of its own: no credential checked
4
+ * here, so nothing to count, nothing to send and nothing to spend.
5
+ */
6
+ import type { At } from './at';
7
+ import type { ResolvedType } from './config';
8
+ import { type AnyUser, type Context } from './context';
9
+ import type { Finish } from './email-sign-in';
10
+ import type { ProvenSignInApi, SignInResult } from './types';
11
+ /**
12
+ * `signInProven` for one user type: the user read by id — `NOT_FOUND` for
13
+ * nobody, as `get` — refused when inactive, then finished as every sign-in
14
+ * is, by `secondFactor.finish`: a session, or a challenge for an active
15
+ * factor.
16
+ *
17
+ * No throttle is counted and no count restarted, no token issued or spent,
18
+ * no e-mail proved: the proof is the application's, and links and codes
19
+ * already sent keep working.
20
+ */
21
+ export declare function provenSignInFlows(context: Context, type: ResolvedType, at: At, finish: Finish): ProvenSignInApi<AnyUser, SignInResult<AnyUser>>;
22
+ //# sourceMappingURL=proven-sign-in.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proven-sign-in.d.ts","sourceRoot":"","sources":["../../src/auth/proven-sign-in.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAa,MAAM,WAAW,CAAC;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAW,MAAM,SAAS,CAAC;AAEtE;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAiBjD"}
@@ -17,6 +17,10 @@ import type { SignInCodeApi, SignInResult } from './types';
17
17
  * address (`mail-requests.ts`), and the application rate-limits it per
18
18
  * client. The code's hash is keyed by the challenge, so the
19
19
  * tokens alone do not reveal it.
20
+ *
21
+ * `request` is `prepare`, then `send` (`prepared.ts`): counted, the
22
+ * challenge minted — before anybody is looked up, so the visitor gets one
23
+ * whoever holds the address — then looked up and issued under it.
20
24
  */
21
25
  export declare function signInCodeFlows(context: Context, type: ResolvedType, at: At, finish: Finish): SignInCodeApi<AnyUser, SignInResult<AnyUser>>['signInCode'];
22
26
  //# sourceMappingURL=sign-in-code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign-in-code.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE3E,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,EAEX,aAAa,EAEb,YAAY,EACZ,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAqB7D"}
1
+ {"version":3,"file":"sign-in-code.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE3E,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAczB,OAAO,KAAK,EAGX,aAAa,EAEb,YAAY,EACZ,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAsB7D"}
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Part of what `janus()` hands back; `./index` gathers it.
6
6
  */
7
+ import type { PreparedCode, PreparedRequest } from './prepared';
7
8
  import type { SignedIn, SignInOptions } from './sign-in';
8
9
  import type { UserRef } from './user';
9
10
  /** A one-time token, given to the application once, to send by e-mail. */
@@ -51,6 +52,14 @@ export interface SignInCodeApi<U, Answer = SignedIn<U>> {
51
52
  * `retryAfter`, and no code. Rate-limit it per client too.
52
53
  */
53
54
  request(email: string): Promise<IssuedCode<U> | null>;
55
+ /**
56
+ * `request` in two steps, for an application that sends the code off
57
+ * the visitor's request: counts the address — `MAIL_THROTTLED` with
58
+ * `retryAfter` past the limit — looks nobody up, and mints the
59
+ * `challenge` to give the visitor now, whoever holds the address.
60
+ * `send()` on the answer does the rest, once.
61
+ */
62
+ prepare(email: string): Promise<PreparedCode<U>>;
54
63
  /**
55
64
  * Checks the code against its challenge, marks the e-mail verified —
56
65
  * the code reached the inbox — and signs the user in. **An e-mail
@@ -99,6 +108,15 @@ export interface ResetPasswordApi<U> {
99
108
  request(email: string): Promise<(IssuedToken & {
100
109
  readonly user: U;
101
110
  }) | null>;
111
+ /**
112
+ * `request` in two steps, for an application that sends the link off
113
+ * the visitor's request: counts the address — `MAIL_THROTTLED` with
114
+ * `retryAfter` past the limit — and looks nobody up. `send()` on the
115
+ * answer does the rest, once.
116
+ */
117
+ prepare(email: string): Promise<PreparedRequest<IssuedToken & {
118
+ readonly user: U;
119
+ }>>;
102
120
  /**
103
121
  * Redeems the token, sets the password, marks the e-mail verified — the
104
122
  * link proved it — and **signs the user out everywhere**. Every other
@@ -1 +1 @@
1
- {"version":3,"file":"email-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/types/email-flows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE;QACpB;;;;;;;;;;;;WAYG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtD;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAAC;KACnB,CAAC;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;WAKG;QACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C;;;WAGG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE;QACvB;;;;;;;;WAQG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;WAMG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC;CACF"}
1
+ {"version":3,"file":"email-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/types/email-flows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE;QACpB;;;;;;;;;;;;WAYG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtD;;;;;;WAMG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAAC;KACnB,CAAC;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;WAKG;QACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C;;;WAGG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE;QACvB;;;;;;;;WAQG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;WAKG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,CAAC,CAAC;QAChE;;;;;;WAMG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * What a user type with an e-mail answers besides: finding its user by the
3
+ * address, whether the type signs in with a password or not.
4
+ *
5
+ * Part of what `janus()` hands back; `./index` gathers it.
6
+ */
7
+ /**
8
+ * Finding a user by their e-mail — the lookup an invitation needs before
9
+ * `signInProven`, on a type with no password and so no `findByLogin`.
10
+ */
11
+ export interface FindByEmailApi<U> {
12
+ /**
13
+ * The user of this type holding this e-mail, or `null`. The address is
14
+ * normalised as the e-mail flows normalise it — trimmed and lowercased —
15
+ * whatever the type's login, so a type signing in with a username is
16
+ * still found by its e-mail, and a username that only looks like an
17
+ * address is nobody's. An inactive user is answered too, as by `find`.
18
+ *
19
+ * **An account-existence oracle: never expose it to an anonymous
20
+ * client.** It is a server-side read, to call after a proof of your own —
21
+ * an invitation token your server issued. It counts nothing in the mail
22
+ * or the sign-in throttle, issues nothing and writes nothing.
23
+ *
24
+ * A value that is no address — not a string, empty once trimmed, or
25
+ * holding a NUL or a lone surrogate — is nobody's: `null`, without
26
+ * asking the store, as `find` answers a malformed id. Rejects with
27
+ * `STORE_FAILED` only.
28
+ */
29
+ findByEmail(email: string): Promise<U | null>;
30
+ }
31
+ //# sourceMappingURL=find-by-email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-by-email.d.ts","sourceRoot":"","sources":["../../../src/auth/types/find-by-email.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CAC9C"}
@@ -9,10 +9,13 @@
9
9
  */
10
10
  export type { Checked } from './checks';
11
11
  export type { IssuedCode, IssuedToken, ResetPasswordApi, SignInCodeApi, VerifyEmailApi, } from './email-flows';
12
+ export type { FindByEmailApi } from './find-by-email';
12
13
  export type { EmailOf, LoginOf, RequiredStringKeys, TypesOf, UserOf, } from './inference';
13
14
  export type { Janus, SharedApi, TypeApi } from './janus';
14
15
  export type { MagicLinkApi } from './magic-link';
15
16
  export type { PasswordApi } from './password';
17
+ export type { PreparedCode, PreparedRequest } from './prepared';
18
+ export type { ProvenSignInApi } from './proven-sign-in';
16
19
  export type { RecoveredSignIn, RecoveryCodesIssued, SecondFactorApi, SecondFactorEnrolment, } from './second-factor';
17
20
  export type { Authenticated, HeaderRecord, RequestLike, Session, } from './session';
18
21
  export type { SecondFactorRequired, SignedIn, SignInOptions, SignInResult, } from './sign-in';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACX,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,oBAAoB,EACpB,QAAQ,EACR,aAAa,EACb,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACX,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EACX,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,oBAAoB,EACpB,QAAQ,EACR,aAAa,EACb,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -6,9 +6,11 @@
6
6
  */
7
7
  import type { JanusConfig, MultiTypeConfig, SingleTypeConfig } from '../config';
8
8
  import type { ResetPasswordApi, SignInCodeApi, VerifyEmailApi } from './email-flows';
9
+ import type { FindByEmailApi } from './find-by-email';
9
10
  import type { EmailOf, FieldsInput, LoginOf, SingleAsType, UserOf, UserOfType } from './inference';
10
11
  import type { MagicLinkApi } from './magic-link';
11
12
  import type { PasswordApi } from './password';
13
+ import type { ProvenSignInApi } from './proven-sign-in';
12
14
  import type { SecondFactorApi } from './second-factor';
13
15
  import type { Authenticated, RequestLike, Session } from './session';
14
16
  import type { SignedIn, SignInResult } from './sign-in';
@@ -16,16 +18,17 @@ import type { StepUpApi, StepUpByApp, StepUpByEmail } from './step-up';
16
18
  import type { UserRef } from './user';
17
19
  import type { UserTypeApi } from './user-type';
18
20
  /**
19
- * What a sign-in by e-mail — a code or a link — answers: a session, or a
20
- * challenge when the type has a password in an instance given a
21
- * `secondFactor`, since the e-mail proves the address and not the factor.
21
+ * What a sign-in other than the password's answers — a code, a link, or
22
+ * the application's own proof: a session, or a challenge when the type has
23
+ * a password in an instance given a `secondFactor`, since none of them
24
+ * proves the factor.
22
25
  */
23
- type EmailSignInAnswer<Name extends string, Def, TwoFactor extends boolean> = TwoFactor extends true ? [LoginOf<Def>] extends [never] ? SignedIn<UserOfType<Name, Def>> : SignInResult<UserOfType<Name, Def>> : SignedIn<UserOfType<Name, Def>>;
26
+ type SignInAnswer<Name extends string, Def, TwoFactor extends boolean> = TwoFactor extends true ? [LoginOf<Def>] extends [never] ? SignedIn<UserOfType<Name, Def>> : SignInResult<UserOfType<Name, Def>> : SignedIn<UserOfType<Name, Def>>;
24
27
  /**
25
28
  * The whole surface of one user type, with only the flows its configuration
26
29
  * allows. `TwoFactor` is whether `janus()` was given a `secondFactor`.
27
30
  */
28
- export type TypeApi<Name extends string, Def, TwoFactor extends boolean = false> = UserTypeApi<UserOfType<Name, Def>, FieldsInput<Def>> & ([LoginOf<Def>] extends [never] ? unknown : TwoFactor extends true ? PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>, SignInResult<UserOfType<Name, Def>>> & SecondFactorApi<UserOfType<Name, Def>> : PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>>) & ([EmailOf<Def>] extends [never] ? unknown : VerifyEmailApi<UserOfType<Name, Def>> & SignInCodeApi<UserOfType<Name, Def>, EmailSignInAnswer<Name, Def, TwoFactor>> & MagicLinkApi<UserOfType<Name, Def>, EmailSignInAnswer<Name, Def, TwoFactor>> & StepUpApi<UserOfType<Name, Def>, TwoFactor extends true ? [LoginOf<Def>] extends [never] ? StepUpByEmail<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>> | StepUpByApp<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>>>) & ([LoginOf<Def>] extends [never] ? unknown : [EmailOf<Def>] extends [never] ? unknown : ResetPasswordApi<UserOfType<Name, Def>>);
31
+ export type TypeApi<Name extends string, Def, TwoFactor extends boolean = false> = UserTypeApi<UserOfType<Name, Def>, FieldsInput<Def>> & ProvenSignInApi<UserOfType<Name, Def>, SignInAnswer<Name, Def, TwoFactor>> & ([LoginOf<Def>] extends [never] ? unknown : TwoFactor extends true ? PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>, SignInResult<UserOfType<Name, Def>>> & SecondFactorApi<UserOfType<Name, Def>> : PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>>) & ([EmailOf<Def>] extends [never] ? unknown : FindByEmailApi<UserOfType<Name, Def>> & VerifyEmailApi<UserOfType<Name, Def>> & SignInCodeApi<UserOfType<Name, Def>, SignInAnswer<Name, Def, TwoFactor>> & MagicLinkApi<UserOfType<Name, Def>, SignInAnswer<Name, Def, TwoFactor>> & StepUpApi<UserOfType<Name, Def>, TwoFactor extends true ? [LoginOf<Def>] extends [never] ? StepUpByEmail<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>> | StepUpByApp<UserOfType<Name, Def>> : StepUpByEmail<UserOfType<Name, Def>>>) & ([LoginOf<Def>] extends [never] ? unknown : [EmailOf<Def>] extends [never] ? unknown : ResetPasswordApi<UserOfType<Name, Def>>);
29
32
  /** What every configuration answers, whatever its user types. */
30
33
  export interface SharedApi<U extends {
31
34
  readonly type: string;
@@ -1 +1 @@
1
- {"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../../src/auth/types/janus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,KAAK,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACX,OAAO,EACP,WAAW,EACX,OAAO,EACP,YAAY,EACZ,MAAM,EACN,UAAU,EACV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,KAAK,iBAAiB,CACrB,IAAI,SAAS,MAAM,EACnB,GAAG,EACH,SAAS,SAAS,OAAO,IACtB,SAAS,SAAS,IAAI,GACvB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAC/B,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GACpC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,OAAO,CAClB,IAAI,SAAS,MAAM,EACnB,GAAG,EACH,SAAS,SAAS,OAAO,GAAG,KAAK,IAC9B,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,GACvD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,OAAO,GACP,SAAS,SAAS,IAAI,GACrB,WAAW,CACX,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EACrB,WAAW,CAAC,GAAG,CAAC,EAChB,OAAO,CAAC,GAAG,CAAC,EACZ,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CACnC,GACA,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GACtC,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GACvE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,OAAO,GACP,cAAc,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GACrC,aAAa,CACZ,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EACrB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,CACvC,GACD,YAAY,CACX,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EACrB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,CACvC,GACD,SAAS,CACR,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,EACrB,SAAS,SAAS,IAAI,GACnB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,aAAa,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAElC,aAAa,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GACpC,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GACrC,aAAa,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CACvC,CAAC,GACL,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,OAAO,GACP,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7B,OAAO,GACP,gBAAgB,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAE9C,iEAAiE;AACjE,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;IAC7D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAC3C,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAAE,GAC7B,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEnE,gGAAgG;IAChG,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhD,uEAAuE;IACvE,iBAAiB,CAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACpC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAExC,kEAAkE;IAClE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEhC,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE;QAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;QACnD,KAAK,IAAI,MAAM,CAAC;KAChB,CAAC;IAEF;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,KAAK,WAAW,CAAC,CAAC,IAAI,cAAc,SAAS,MAAM,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;AAEpE,oCAAoC;AACpC,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,WAAW,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAC9D,CAAC,CAAC,SAAS,eAAe,GACvB;IACA,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,OAAO,CACjD,CAAC,EACD,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EACb,WAAW,CAAC,CAAC,CAAC,CACd;CACD,GACA,CAAC,SAAS,gBAAgB,GACzB,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,GAChD,KAAK,CAAC,CAAC"}
1
+ {"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../../src/auth/types/janus.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@
5
5
  * Part of what `janus()` hands back; `./index` gathers it.
6
6
  */
7
7
  import type { IssuedToken } from './email-flows';
8
+ import type { PreparedRequest } from './prepared';
8
9
  import type { SignedIn, SignInOptions } from './sign-in';
9
10
  /**
10
11
  * Signing in with a link sent to the user's e-mail, no password needed —
@@ -31,6 +32,16 @@ export interface MagicLinkApi<U, Answer = SignedIn<U>> {
31
32
  request(email: string): Promise<(IssuedToken & {
32
33
  readonly user: U;
33
34
  }) | null>;
35
+ /**
36
+ * `request` in two steps, for an application that sends the link off
37
+ * the visitor's request: counts the address — `MAIL_THROTTLED` with
38
+ * `retryAfter` past the limit, to show the visitor now — and looks
39
+ * nobody up, so it takes the same time for any address. `send()` on
40
+ * the answer does the rest, once, and answers what `request` does.
41
+ */
42
+ prepare(email: string): Promise<PreparedRequest<IssuedToken & {
43
+ readonly user: U;
44
+ }>>;
34
45
  /**
35
46
  * Spends the link's token, marks the e-mail verified — the link reached
36
47
  * the inbox — and signs the user in. **An e-mail proved for the first
@@ -1 +1 @@
1
- {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../../src/auth/types/magic-link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,SAAS,EAAE;QACnB;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;;;;;;;;;WAcG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACjE,CAAC;CACF"}
1
+ {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../../src/auth/types/magic-link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,SAAS,EAAE;QACnB;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;WAMG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,CAAC,CAAC;QAChE;;;;;;;;;;;;;;WAcG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACjE,CAAC;CACF"}