@nxgt/janus 0.23.0 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -761,11 +761,12 @@ password and the second factor go with it, so whoever holds the new inbox
761
761
  and follows the link signs in with them. The mail to the new address should
762
762
  say so, and say "ignore it if it was not you".
763
763
 
764
- **For now, send the link to the new address with your own mailer**:
765
- `@nxgt/janus-mail` has no template for it yet (it sends the notice to the
766
- former address, `emailChanged`). `mail.verifyEmail(issued)` is not the
767
- change-of-e-mail mail: it would tell the new address to verify, not that the
768
- account moves there.
764
+ **Send the link to the new address with `@nxgt/janus-mail` 0.10.0 or later**:
765
+ `mail.changeEmail(issued, { name })` (its `links.changeEmail` is the page
766
+ above), and it sends the notice to the former address, `emailChanged`, once
767
+ the link is redeemed. `mail.verifyEmail(issued)` is not the change-of-e-mail
768
+ mail: it would tell the new address to verify, not that the account moves
769
+ there. Without janus-mail, send it with your own mailer.
769
770
 
770
771
  - **On every user type with an e-mail**, with a password or without one. The
771
772
  address is validated by the type's schema as `update` would: a malformed
@@ -37,15 +37,17 @@ writes it: it takes what `send` and `request` answer, as they answer it, and
37
37
  sends the verification, reset, sign-in code and sign-in link e-mails — with the notices
38
38
  of a password, an e-mail or a second factor changed, and a welcome on
39
39
  `user.created` — in English and French, over any `@nxgt/mail` transport.
40
- Every link is required but two: `getStarted`, since janus-mail 0.4.0, is
41
- where the welcome's **Get started** button leads; `recoveryCodes` and
40
+ Every link is required but three: `getStarted`, since janus-mail 0.4.0, is
41
+ where the welcome's **Get started** button leads; `recoveryCodes`,
42
42
  `magicLink` — the page a [sign-in link](magic-link.md) opens, since
43
- janus-mail 0.7.0 — are optional. **`changeEmail.send` is not among them
44
- yet**: janus-mail has no template for the link to a new address. Send that
45
- link with your own mailer; janus-mail sends the notice to the former address
46
- (`emailChanged`). `mail.verifyEmail(issued)` is not the change-of-e-mail
47
- mail: it would ask the new address to verify, not say the account moves
48
- there.
43
+ janus-mail 0.7.0 — and `changeEmail`, the page that confirms a new address,
44
+ since janus-mail 0.10.0, are optional. **`changeEmail.send`'s link has its
45
+ own e-mail**: `mail.changeEmail(issued, { name })` sends it to
46
+ `issued.email`, the new address, and janus-mail sends the notice to the
47
+ former address (`emailChanged`) once the link is redeemed. It needs
48
+ `@nxgt/janus-mail` 0.10.0 or later; `mail.verifyEmail(issued)` is not the
49
+ change-of-e-mail mail: it would ask the new address to verify, not say the
50
+ account moves there.
49
51
 
50
52
  ```ts
51
53
  import { janusMail } from '@nxgt/janus-mail';
@@ -59,11 +61,15 @@ const mail = janusMail({
59
61
  resetPassword: (token) => `https://app.example/reset?token=${token}`,
60
62
  secureAccount: () => 'https://app.example/account/security',
61
63
  getStarted: () => 'https://app.example/',
64
+ changeEmail: (token) => `https://app.example/email/confirm?token=${token}`, // optional
62
65
  },
63
66
  });
64
67
 
65
68
  await mail.verifyEmail(await auth.verifyEmail.send(user), { name: user.name });
66
69
 
70
+ // to the NEW address; the account moves when changeEmail.confirm(token) redeems the link
71
+ await mail.changeEmail(await auth.changeEmail.send(user, newEmail), { name: user.name });
72
+
67
73
  const issued = await auth.resetPassword.request(email);
68
74
  if (issued !== null) await mail.resetPassword(issued, { name: issued.user.name });
69
75
  ```
@@ -59,7 +59,7 @@ either finds this row.
59
59
  | **device**, **device token** | A device is a browser or an app a user signs in from, as the client's long-lived cookie — or a bearer client's storage — tells it. A **device token** is what janus signs for it with `devices.keys`, answers as `deviceToken`, and takes back as `device`: `d1.<key id>.<device id>.<mac>`, bound to one user, stored nowhere. A sign-in from a **new device** — one whose token did not prove this user signed in there — answers `newDevice: true` and sends `user.newDeviceSignedIn`. See [devices](devices.md) | "fingerprint", "trusted device", "remembered browser"; "token" alone |
60
60
  | **token** | Never alone in prose: a *session token*, a *one-time token* or a *device token*. The `tokens` store and the `TOKEN_*` codes are one-time tokens only | |
61
61
  | **e-mail flow** | `verifyEmail`, `resetPassword` or `changeEmail`: send a one-time token, then confirm it. `magicLink` sends one too, to sign in; `signInCode` sends a one-time code instead | |
62
- | **issued** | What a flow answers for the application to send: an `IssuedToken` from `verifyEmail.send`, `changeEmail.send`, `resetPassword.request` or `magicLink.request`, an `IssuedCode` from `signInCode.request` — the address with it. `@nxgt/janus-mail` takes it as it is, except `changeEmail.send`'s: it has no template for that link yet, so send it with your own mailer | "result", "payload" |
62
+ | **issued** | What a flow answers for the application to send: an `IssuedToken` from `verifyEmail.send`, `changeEmail.send`, `resetPassword.request` or `magicLink.request`, an `IssuedCode` from `signInCode.request` — the address with it. `@nxgt/janus-mail` takes it as it is — `mail.changeEmail(issued, to)` for `changeEmail.send`'s, sent to the new address (janus-mail 0.10.0 or later) | "result", "payload" |
63
63
  | **notice** | An e-mail that tells a user of a change and asks for nothing: *password changed*, *e-mail changed* — the latter sent to the former address — *two-factor enabled*, *two-factor disabled*, *recovery code used* and *new sign-in*. `@nxgt/janus-mail` sends all six | "alert", "notification" |
64
64
  | **user event** | What happened to a user, once it is written: `user.created`, `user.emailVerified`, `user.passwordReset`, `user.passwordChanged`, `user.emailChanged`, `user.secondFactorEnabled`, `user.secondFactorDisabled`, `user.recoveryCodesRegenerated`, `user.recoveryCodeUsed`, `user.newDeviceSignedIn`, `user.deleted` — a `UserEvent`, naming the user by id alone — `user.emailChanged` adds `formerEmail`, `user.newDeviceSignedIn` adds `sessionId` — with an `id` of its own. See [user events](events.md) | "webhook" — a webhook is one way to deliver it; "event" alone where it could be read as `@nxgt/janus-telemetry`'s audit log record — on a page about user events, "the event" is fine |
65
65
  | **step-up**, **fresh** | A step-up is a signed-in user proving again who they are before a sensitive action — `stepUp.request`, then `stepUp.confirm`, with an e-mailed code or, when their second factor is active, their app's — which moves the session's `authenticatedAt` to now and opens no session. A session is **fresh** for `maxAge` after it proved who it is, at the sign-in or by a step-up; `assertFresh` refuses an older one with `STEP_UP_REQUIRED`. See [step-up](step-up.md) | "re-authentication", "sudo mode", "elevated session"; "recent sign-in" once a step-up counts too |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/janus",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "description": "Embeddable, type-safe identities and permissions: bring your own database",
5
5
  "license": "MIT",
6
6
  "type": "module",