@nxgt/janus-mail 0.9.0 → 0.9.2
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 +4 -3
- package/dist/index.js +35 -20
- package/dist/index.js.map +7 -6
- package/dist/new-sign-in-mail.d.ts +2 -4
- package/dist/new-sign-in-mail.d.ts.map +1 -1
- package/dist/no-location.d.ts +23 -0
- package/dist/no-location.d.ts.map +1 -0
- package/dist/template-types.d.ts +4 -2
- package/dist/template-types.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/docs/guide/locales.md +4 -0
- package/docs/guide/sending.md +13 -7
- package/docs/guide/templates.md +6 -3
- package/docs/roadmap.md +8 -0
- package/docs/troubleshooting.md +3 -2
- package/mails/en/new-sign-in.txt +3 -8
- package/mails/fr/new-sign-in.txt +3 -8
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -94,7 +94,7 @@ class. To retry a `MailFailure` or trace each send, wrap the mailer you pass:
|
|
|
94
94
|
| `twoFactorEnabled(to)` | A notice: two-factor authentication was turned on, with `links.secureAccount()` | `to.email` |
|
|
95
95
|
| `twoFactorDisabled(to)` | A notice: two-factor authentication was turned off, with `links.secureAccount()` | `to.email` |
|
|
96
96
|
| `recoveryCodeUsed(to, { when, recoveryCodesLeft })` | A notice: a recovery code was used, `when`, and how many are left — "You have 9 recovery codes left." — with `links.recoveryCodes()`, else `links.secureAccount()` | `to.email` |
|
|
97
|
-
| `newSignIn(to, { device, time, location? })` | A notice: the account was signed in from a new device — which device, `time`, and `location`,
|
|
97
|
+
| `newSignIn(to, { device, time, location? })` | A notice: the account was signed in from a new device — which device, `time`, and `location`, "Unknown" ("Inconnu") when left out — with `links.secureAccount()` | `to.email` |
|
|
98
98
|
| `welcome(to)` | A welcome to a new user — "Welcome, Ada" — with `links.getStarted()` | `to.email` |
|
|
99
99
|
|
|
100
100
|
The five e-mails of a link or a code say how long it lasts — "This link
|
|
@@ -328,7 +328,8 @@ const auth = janus({
|
|
|
328
328
|
Every value is your text, in the recipient's locale: `device` described
|
|
329
329
|
from the request's `User-Agent`, `time` formatted in their time zone.
|
|
330
330
|
**`@nxgt/janus` sees no IP**, so `location` is yours to work out — from a
|
|
331
|
-
geo-IP of your own — and an e-mail without one
|
|
331
|
+
geo-IP of your own — and an e-mail without one says "Unknown" in its
|
|
332
|
+
place: `Location Unknown`, `Lieu Inconnu` in French. The
|
|
332
333
|
button links to `links.secureAccount()`.
|
|
333
334
|
|
|
334
335
|
### Replacing a template
|
|
@@ -423,7 +424,7 @@ can carry the token.
|
|
|
423
424
|
nothing answers `null`, which is a compile error here and, in JavaScript,
|
|
424
425
|
`janusMail.newSignIn: location must be a string`: spread it in only when it
|
|
425
426
|
is a string — `...(city === null ? {} : { location: city })` — and the
|
|
426
|
-
e-mail
|
|
427
|
+
e-mail says "Unknown" in the recipient's locale.
|
|
427
428
|
|
|
428
429
|
**Check `via` before `stepUp`.** `auth.stepUp.request(user)` answers
|
|
429
430
|
`via: 'secondFactor'` — no code, no address — for a user whose second
|
package/dist/index.js
CHANGED
|
@@ -117,27 +117,42 @@ function expiringMails(options) {
|
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// src/no-location.ts
|
|
121
|
+
var NO_LOCATION = Object.freeze({
|
|
122
|
+
en: "Unknown",
|
|
123
|
+
fr: "Inconnu"
|
|
124
|
+
});
|
|
125
|
+
function isBuilt(locale) {
|
|
126
|
+
return Object.hasOwn(NO_LOCATION, locale);
|
|
127
|
+
}
|
|
128
|
+
function noLocationText(locale) {
|
|
129
|
+
if (isBuilt(locale))
|
|
130
|
+
return NO_LOCATION[locale];
|
|
131
|
+
const { language } = new Intl.Locale(locale);
|
|
132
|
+
return isBuilt(language) ? NO_LOCATION[language] : NO_LOCATION.en;
|
|
133
|
+
}
|
|
134
|
+
|
|
120
135
|
// src/new-sign-in-mail.ts
|
|
121
136
|
var METHOD = "newSignIn";
|
|
122
|
-
|
|
123
|
-
function locationOf(signIn) {
|
|
137
|
+
function locationOf(signIn, locale) {
|
|
124
138
|
const given = typeof signIn === "object" && signIn !== null ? signIn.location : undefined;
|
|
125
139
|
if (given === undefined)
|
|
126
|
-
return
|
|
140
|
+
return noLocationText(locale);
|
|
127
141
|
return field(METHOD, signIn, "location");
|
|
128
142
|
}
|
|
129
143
|
function newSignInMail(options) {
|
|
130
144
|
const { brand, links } = options;
|
|
131
145
|
return {
|
|
132
146
|
async newSignIn(to, signIn) {
|
|
147
|
+
const locale = localeFor(options, to);
|
|
133
148
|
return send(options, METHOD, field(METHOD, to, "email"), {
|
|
134
149
|
brand,
|
|
135
150
|
name: field(METHOD, to, "name"),
|
|
136
151
|
device: field(METHOD, signIn, "device"),
|
|
137
|
-
location: locationOf(signIn),
|
|
152
|
+
location: locationOf(signIn, locale),
|
|
138
153
|
time: field(METHOD, signIn, "time"),
|
|
139
154
|
link: link(METHOD, links.secureAccount(), "secureAccount()"),
|
|
140
|
-
locale
|
|
155
|
+
locale
|
|
141
156
|
});
|
|
142
157
|
}
|
|
143
158
|
};
|
|
@@ -280,11 +295,11 @@ function isObject(value) {
|
|
|
280
295
|
function isAddress(value) {
|
|
281
296
|
if (typeof value === "string")
|
|
282
297
|
return value.trim() !== "";
|
|
283
|
-
return isObject(value) && typeof value
|
|
298
|
+
return isObject(value) && typeof value["name"] === "string" && typeof value["address"] === "string" && value["address"].trim() !== "";
|
|
284
299
|
}
|
|
285
300
|
function checkSending(options) {
|
|
286
301
|
const { mailer, from, replyTo, brand, links } = options;
|
|
287
|
-
if (!isObject(mailer) || typeof mailer
|
|
302
|
+
if (!isObject(mailer) || typeof mailer["send"] !== "function") {
|
|
288
303
|
refuse("mailer must be a Mailer — an object with a send function");
|
|
289
304
|
}
|
|
290
305
|
if (!isAddress(from)) {
|
|
@@ -301,10 +316,10 @@ function checkSending(options) {
|
|
|
301
316
|
function resolveClock(clock) {
|
|
302
317
|
if (clock === undefined)
|
|
303
318
|
return SYSTEM_CLOCK;
|
|
304
|
-
if (!isObject(clock) || typeof clock
|
|
319
|
+
if (!isObject(clock) || typeof clock["now"] !== "function") {
|
|
305
320
|
refuse("clock must be a Clock — an object with a now function");
|
|
306
321
|
}
|
|
307
|
-
return Object.freeze({ now: clock
|
|
322
|
+
return Object.freeze({ now: clock["now"].bind(clock) });
|
|
308
323
|
}
|
|
309
324
|
function isLanguageTag(locale) {
|
|
310
325
|
try {
|
|
@@ -315,7 +330,7 @@ function isLanguageTag(locale) {
|
|
|
315
330
|
}
|
|
316
331
|
}
|
|
317
332
|
function resolveLocales(options) {
|
|
318
|
-
const wanted = options
|
|
333
|
+
const wanted = options["locales"] ?? LOCALES;
|
|
319
334
|
if (!Array.isArray(wanted) || wanted.length === 0 || !wanted.every((locale) => typeof locale === "string" && locale !== "")) {
|
|
320
335
|
refuse("locales must list at least one locale, as ['en', 'fr']");
|
|
321
336
|
}
|
|
@@ -326,14 +341,14 @@ function resolveLocales(options) {
|
|
|
326
341
|
if (new Set(locales).size !== locales.length) {
|
|
327
342
|
refuse("locales holds the same locale twice");
|
|
328
343
|
}
|
|
329
|
-
const fallbackLocale = options
|
|
344
|
+
const fallbackLocale = options["fallbackLocale"] ?? (locales.includes("en") ? "en" : locales[0]);
|
|
330
345
|
if (typeof fallbackLocale !== "string" || !locales.includes(fallbackLocale)) {
|
|
331
346
|
refuse("fallbackLocale must be one of locales");
|
|
332
347
|
}
|
|
333
348
|
return { locales, fallbackLocale };
|
|
334
349
|
}
|
|
335
350
|
function resolveTemplates(options, locales) {
|
|
336
|
-
const given = options
|
|
351
|
+
const given = options["templates"] ?? {};
|
|
337
352
|
if (!isObject(given)) {
|
|
338
353
|
refuse("templates must be an object of functions, as { verifyEmail: (variables) => rendered }");
|
|
339
354
|
}
|
|
@@ -369,15 +384,15 @@ function resolveOptions(options) {
|
|
|
369
384
|
checkSending(options);
|
|
370
385
|
const { locales, fallbackLocale } = resolveLocales(options);
|
|
371
386
|
return Object.freeze({
|
|
372
|
-
mailer: options
|
|
373
|
-
from: frozenAddress(options
|
|
374
|
-
replyTo: options
|
|
375
|
-
brand: options
|
|
376
|
-
links: frozenLinks(options
|
|
387
|
+
mailer: options["mailer"],
|
|
388
|
+
from: frozenAddress(options["from"]),
|
|
389
|
+
replyTo: options["replyTo"] === undefined ? undefined : frozenAddress(options["replyTo"]),
|
|
390
|
+
brand: options["brand"],
|
|
391
|
+
links: frozenLinks(options["links"]),
|
|
377
392
|
locales,
|
|
378
393
|
fallbackLocale,
|
|
379
394
|
templates: resolveTemplates(options, locales),
|
|
380
|
-
clock: resolveClock(options
|
|
395
|
+
clock: resolveClock(options["clock"])
|
|
381
396
|
});
|
|
382
397
|
}
|
|
383
398
|
|
|
@@ -420,7 +435,7 @@ function codesLeftText(locale, count) {
|
|
|
420
435
|
if (!Object.hasOwn(CODES_LEFT, locale))
|
|
421
436
|
return;
|
|
422
437
|
const branches = CODES_LEFT[locale];
|
|
423
|
-
const branch = branches[`=${count}`] ?? branches[new Intl.PluralRules(locale).select(count)] ?? branches
|
|
438
|
+
const branch = branches[`=${count}`] ?? branches[new Intl.PluralRules(locale).select(count)] ?? branches["other"];
|
|
424
439
|
const digits = new Intl.NumberFormat(locale).format(count);
|
|
425
440
|
return (branch ?? []).map((part) => part ?? digits).join("");
|
|
426
441
|
}
|
|
@@ -503,5 +518,5 @@ export {
|
|
|
503
518
|
janusTemplates
|
|
504
519
|
};
|
|
505
520
|
|
|
506
|
-
//# debugId=
|
|
521
|
+
//# debugId=1AB9B2239C4A4C2464756E2164756E21
|
|
507
522
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/expiry.ts", "../src/send.ts", "../src/expiring-mails.ts", "../src/new-sign-in-mail.ts", "../src/notice-mails.ts", "../src/generated/locales.ts", "../src/refuse.ts", "../src/links.ts", "../src/mails.ts", "../src/templates.ts", "../src/options.ts", "../src/generated/codes-left.ts", "../src/codes-left.ts", "../src/recovery-mail.ts", "../src/step-up-mail.ts", "../src/janus-mail.ts"],
|
|
3
|
+
"sources": ["../src/expiry.ts", "../src/send.ts", "../src/expiring-mails.ts", "../src/no-location.ts", "../src/new-sign-in-mail.ts", "../src/notice-mails.ts", "../src/generated/locales.ts", "../src/refuse.ts", "../src/links.ts", "../src/mails.ts", "../src/templates.ts", "../src/options.ts", "../src/generated/codes-left.ts", "../src/codes-left.ts", "../src/recovery-mail.ts", "../src/step-up-mail.ts", "../src/janus-mail.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * `expiresIn`: how long the link or the code of an e-mail stays valid, as\n * the text the e-mail shows — \"1 hour\", \"1 heure\". Derived from the\n * `expiresAt` the flow answered and the locale the recipient gets, unless the\n * send passes its own.\n */\nimport type { Clock } from '@nxgt/janus';\n\nconst MINUTE_MS = 60_000;\nconst MINUTES_IN_HOUR = 60;\nconst MINUTES_IN_DAY = 24 * MINUTES_IN_HOUR;\n\n/**\n * A duration in the locale, in the largest unit it holds at least once:\n * rounded to the minute first — the flow set `expiresAt` a moment before the\n * send, so an hour is 59 minutes and 59 seconds by then — and then down to a\n * whole unit: 90 minutes is \"1 hour\", 36 hours \"1 day\". At 30 seconds or\n * more, the e-mail never promises more than half a minute beyond what is\n * left; under that, it says \"1 minute\".\n *\n * ```ts\n * formatExpiry(3_600_000, 'fr'); // '1 heure'\n * ```\n */\nexport function formatExpiry(ms: number, locale: string): string {\n\tconst minutes = Math.max(1, Math.round(ms / MINUTE_MS));\n\tconst [value, unit] =\n\t\tminutes >= MINUTES_IN_DAY\n\t\t\t? [Math.floor(minutes / MINUTES_IN_DAY), 'day']\n\t\t\t: minutes >= MINUTES_IN_HOUR\n\t\t\t\t? [Math.floor(minutes / MINUTES_IN_HOUR), 'hour']\n\t\t\t\t: [minutes, 'minute'];\n\treturn new Intl.NumberFormat(locale, {\n\t\tstyle: 'unit',\n\t\tunit,\n\t\tunitDisplay: 'long',\n\t}).format(value);\n}\n\n/** The per-send `expiresIn`, when one was passed, or `undefined`; a `TypeError` when it is not a string. */\nfunction passedExpiresIn(method: string, options: unknown): string | undefined {\n\tconst read =\n\t\ttypeof options === 'object' && options !== null\n\t\t\t? (options as { expiresIn?: unknown }).expiresIn\n\t\t\t: undefined;\n\tif (read !== undefined && typeof read !== 'string') {\n\t\tthrow new TypeError(`janusMail.${method}: expiresIn must be a string`);\n\t}\n\treturn read;\n}\n\n/**\n * The `expiresIn` of one send: the one passed, as is, or the time left\n * until the flow's `expiresAt` by `clock` — the one given to `janus()`, when\n * it was given to `janusMail()` too — in `locale`. A `TypeError` naming the method\n * when `expiresAt` is not a valid `Date` — a flow's answer that went through\n * JSON holds a string there — or is already past.\n */\nexport function expiresInFor(\n\tmethod: string,\n\tissued: unknown,\n\tlocale: string,\n\toptions: unknown,\n\tclock: Clock,\n): string {\n\tconst passed = passedExpiresIn(method, options);\n\tif (passed !== undefined) return passed;\n\tconst expiresAt =\n\t\ttypeof issued === 'object' && issued !== null\n\t\t\t? (issued as { expiresAt?: unknown }).expiresAt\n\t\t\t: undefined;\n\tif (!(expiresAt instanceof Date) || Number.isNaN(expiresAt.getTime())) {\n\t\tthrow new TypeError(`janusMail.${method}: expiresAt must be a Date`);\n\t}\n\tconst now = clock.now();\n\tif (!(now instanceof Date) || Number.isNaN(now.getTime())) {\n\t\tthrow new TypeError(`janusMail.${method}: clock.now() must answer a Date`);\n\t}\n\tconst left = expiresAt.getTime() - now.getTime();\n\tif (left <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`janusMail.${method}: expiresAt is past — the link or code would not work`,\n\t\t);\n\t}\n\treturn formatExpiry(left, locale);\n}\n",
|
|
6
6
|
"/**\n * What every method shares: reading an argument's fields, a link, the\n * recipient's locale, and the send itself. A wrong argument is a `TypeError`\n * naming the method and the field — never its value.\n */\nimport type { Address, Rendered, SentMail, WantedLocales } from '@nxgt/mail';\nimport { pickLocale } from '@nxgt/mail';\nimport type { ResolvedOptions } from './options';\nimport type { JanusMailTemplateName, JanusMailVariables } from './types';\n\n/** A string field of an argument, or a `TypeError` naming the method and the field. */\nexport function field(method: string, value: unknown, key: string): string {\n\tconst read =\n\t\ttypeof value === 'object' && value !== null\n\t\t\t? (value as Record<string, unknown>)[key]\n\t\t\t: undefined;\n\tif (typeof read !== 'string') {\n\t\tthrow new TypeError(`janusMail.${method}: ${key} must be a string`);\n\t}\n\treturn read;\n}\n\n/**\n * What a `links` function answered, or a `TypeError` naming the method and\n * the call. Its scheme is the renderer's to check: `http(s)` and `mailto:`\n * pass, anything else is its `MailRefused`.\n */\nexport function link(method: string, value: unknown, call: string): string {\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(\n\t\t\t`janusMail.${method}: links.${call} must answer a string`,\n\t\t);\n\t}\n\treturn value;\n}\n\n/** The locale the recipient gets: the first they want that is sent in, else the fallback. */\nexport function localeFor(options: ResolvedOptions, to: unknown): string {\n\tconst wanted =\n\t\ttypeof to === 'object' && to !== null\n\t\t\t? (to as { locale?: WantedLocales }).locale\n\t\t\t: undefined;\n\treturn pickLocale(wanted, options.locales, options.fallbackLocale);\n}\n\n/**\n * Renders one e-mail and hands it to the mailer. Only `subject`, `html` and\n * `text` are read from what the template answered: a template cannot add a\n * recipient or a header.\n */\nexport async function send<K extends JanusMailTemplateName>(\n\toptions: ResolvedOptions,\n\tname: K,\n\taddress: string,\n\tvariables: JanusMailVariables[K] & { readonly locale: string },\n): Promise<SentMail> {\n\tconst template = options.templates[name] as (\n\t\tvariables: JanusMailVariables[K] & { readonly locale: string },\n\t) => Rendered | PromiseLike<Rendered>;\n\tconst { subject, html, text }: Rendered = await template(variables);\n\tconst replyTo: { replyTo?: Address } =\n\t\toptions.replyTo === undefined ? {} : { replyTo: options.replyTo };\n\treturn options.mailer.send({\n\t\tto: address,\n\t\tfrom: options.from,\n\t\t...replyTo,\n\t\tsubject,\n\t\thtml,\n\t\ttext,\n\t});\n}\n",
|
|
7
7
|
"/**\n * The four e-mails that carry what a flow issued — a one-time link or a\n * sign-in code — and say how long it lasts: `verifyEmail`, `resetPassword`,\n * `signInCode` and `magicLink`.\n */\nimport { expiresInFor } from './expiry';\nimport type { ResolvedOptions } from './options';\nimport { field, link, localeFor, send } from './send';\nimport type { JanusMail } from './types';\n\ntype ExpiringMails = Pick<\n\tJanusMail<string>,\n\t'verifyEmail' | 'resetPassword' | 'signInCode' | 'magicLink'\n>;\n\n/** The two e-mails of a one-time token, which link to your page with it. */\ntype LinkMailName = 'verifyEmail' | 'resetPassword';\n\n/** One e-mail of a one-time token: to `issued.email`, its link built from `issued.token`. */\nfunction linkMail(options: ResolvedOptions, name: LinkMailName) {\n\treturn async (issued: unknown, to: unknown, sendOptions?: unknown) => {\n\t\tconst token = field(name, issued, 'token');\n\t\tconst locale = localeFor(options, to);\n\t\treturn send(options, name, field(name, issued, 'email'), {\n\t\t\tbrand: options.brand,\n\t\t\tname: field(name, to, 'name'),\n\t\t\tlink: link(name, options.links[name](token), `${name}(token)`),\n\t\t\texpiresIn: expiresInFor(name, issued, locale, sendOptions, options.clock),\n\t\t\tlocale,\n\t\t});\n\t};\n}\n\n/**\n * The sign-in link's e-mail: to `issued.email`, greeting nobody, its link\n * built from `issued.token` by the optional `links.magicLink` — checked\n * before anything else is read, so a missing link is refused whatever the\n * arguments.\n */\nfunction magicLinkMail(options: ResolvedOptions) {\n\treturn async (issued: unknown, to: unknown, sendOptions?: unknown) => {\n\t\tconst build = options.links.magicLink;\n\t\tif (build === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'janusMail.magicLink: links.magicLink is missing — pass it to janusMail({ links }) to send sign-in links',\n\t\t\t);\n\t\t}\n\t\tconst token = field('magicLink', issued, 'token');\n\t\tconst locale = localeFor(options, to);\n\t\treturn send(options, 'magicLink', field('magicLink', issued, 'email'), {\n\t\t\tbrand: options.brand,\n\t\t\tlink: link('magicLink', build(token), 'magicLink(token)'),\n\t\t\texpiresIn: expiresInFor(\n\t\t\t\t'magicLink',\n\t\t\t\tissued,\n\t\t\t\tlocale,\n\t\t\t\tsendOptions,\n\t\t\t\toptions.clock,\n\t\t\t),\n\t\t\tlocale,\n\t\t});\n\t};\n}\n\n/** `verifyEmail`, `resetPassword`, `signInCode` and `magicLink`, over the resolved options. */\nexport function expiringMails(options: ResolvedOptions): ExpiringMails {\n\treturn {\n\t\tverifyEmail: linkMail(options, 'verifyEmail'),\n\t\tresetPassword: linkMail(options, 'resetPassword'),\n\t\tasync signInCode(issued, to, sendOptions) {\n\t\t\t// `code`, `email` and `expiresAt` only: the challenge is the visitor's secret.\n\t\t\tconst locale = localeFor(options, to);\n\t\t\treturn send(options, 'signInCode', field('signInCode', issued, 'email'), {\n\t\t\t\tbrand: options.brand,\n\t\t\t\tcode: field('signInCode', issued, 'code'),\n\t\t\t\texpiresIn: expiresInFor(\n\t\t\t\t\t'signInCode',\n\t\t\t\t\tissued,\n\t\t\t\t\tlocale,\n\t\t\t\t\tsendOptions,\n\t\t\t\t\toptions.clock,\n\t\t\t\t),\n\t\t\t\tlocale,\n\t\t\t});\n\t\t},\n\t\tmagicLink: magicLinkMail(options),\n\t};\n}\n",
|
|
8
|
-
"/**\n * `newSignIn
|
|
8
|
+
"/**\n * What `newSignIn` shows where the sender knew no location — \"Unknown\",\n * \"Inconnu\" — in the recipient's locale: the value after the row's label,\n * so \"Location Unknown\", \"Lieu Inconnu\".\n *\n * A map written here, not a message in `mail/locales/*.json`: those\n * catalogues are read by the Maizzle build alone, and hold only the\n * presets' own keys, which the build checks against `@nxgt/mail-presets`'\n * `en`. This string is a send's — whether a location was given is known\n * only then — so it is chosen at send time, as the codes left are\n * (`./codes-left`). Keyed by `JanusMailLocale`, so a locale added to the\n * build without its text here is a compile error.\n */\nimport type { JanusMailLocale } from './generated/locales';\n\n/** The text of a missing location, by built locale. */\nexport const NO_LOCATION: Readonly<Record<JanusMailLocale, string>> =\n\tObject.freeze({\n\t\ten: 'Unknown',\n\t\tfr: 'Inconnu',\n\t});\n\nfunction isBuilt(locale: string): locale is JanusMailLocale {\n\treturn Object.hasOwn(NO_LOCATION, locale);\n}\n\n/**\n * The text of a missing location in `locale` — the one `localeFor` picked —\n * else in its language (`fr` for `fr-CA`), else in `en`: a locale beyond\n * the built ones is sent only through templates of the consumer's own.\n */\nexport function noLocationText(locale: string): string {\n\tif (isBuilt(locale)) return NO_LOCATION[locale];\n\t// A language tag: `resolveOptions` refused anything else in `locales`.\n\tconst { language } = new Intl.Locale(locale);\n\treturn isBuilt(language) ? NO_LOCATION[language] : NO_LOCATION.en;\n}\n",
|
|
9
|
+
"/**\n * `newSignIn`: the notice of a sign-in from a device the user had not signed\n * in from — which device, when, and where when the sender knows — linking to\n * where the account is secured.\n *\n * Apart from the other notices because of its optional `location`: Janus\n * sees no IP, so the sender may know none, and the e-mail then says so in\n * the send's locale — \"Location Unknown\", \"Lieu Inconnu\" (`./no-location`).\n */\n\nimport { noLocationText } from './no-location';\nimport type { ResolvedOptions } from './options';\nimport { field, link, localeFor, send } from './send';\nimport type { JanusMail } from './types';\n\nconst METHOD = 'newSignIn';\n\n/**\n * The sender's location, the text of a missing one in `locale` without one,\n * or a `TypeError` for anything else.\n */\nfunction locationOf(signIn: unknown, locale: string): string {\n\tconst given =\n\t\ttypeof signIn === 'object' && signIn !== null\n\t\t\t? (signIn as { location?: unknown }).location\n\t\t\t: undefined;\n\tif (given === undefined) return noLocationText(locale);\n\treturn field(METHOD, signIn, 'location');\n}\n\n/** The new sign-in notice, over the resolved options. */\nexport function newSignInMail(\n\toptions: ResolvedOptions,\n): Pick<JanusMail<string>, 'newSignIn'> {\n\tconst { brand, links } = options;\n\treturn {\n\t\t// Async, so a wrong argument rejects as the other methods' do.\n\t\tasync newSignIn(to, signIn) {\n\t\t\tconst locale = localeFor(options, to);\n\t\t\treturn send(options, METHOD, field(METHOD, to, 'email'), {\n\t\t\t\tbrand,\n\t\t\t\tname: field(METHOD, to, 'name'),\n\t\t\t\tdevice: field(METHOD, signIn, 'device'),\n\t\t\t\tlocation: locationOf(signIn, locale),\n\t\t\t\ttime: field(METHOD, signIn, 'time'),\n\t\t\t\tlink: link(METHOD, links.secureAccount(), 'secureAccount()'),\n\t\t\t\tlocale,\n\t\t\t});\n\t\t},\n\t};\n}\n",
|
|
9
10
|
"/**\n * The e-mails about the account itself, sent on what happened to it rather\n * than on a flow's answer: the notices of a change the user made — or someone\n * else did — `passwordChanged`, `emailChanged`, `twoFactorEnabled` and\n * `twoFactorDisabled`, each linking to where the account is secured; and\n * `welcome`, once it was created, linking to where a new user starts.\n */\nimport type { ResolvedOptions } from './options';\nimport { field, link, localeFor, send } from './send';\nimport type { JanusMail } from './types';\n\ntype NoticeMails = Pick<\n\tJanusMail<string>,\n\t| 'passwordChanged'\n\t| 'emailChanged'\n\t| 'twoFactorEnabled'\n\t| 'twoFactorDisabled'\n\t| 'welcome'\n>;\n\n/** The e-mails that greet `to.name` at `to.email`, and link to one of `links`. */\ntype PlainNotice =\n\t| 'passwordChanged'\n\t| 'twoFactorEnabled'\n\t| 'twoFactorDisabled'\n\t| 'welcome';\n\n/** The links a plain notice may take: those called with nothing. */\ntype PlainLink = 'secureAccount' | 'getStarted';\n\n/** The notices and the welcome, over the resolved options. */\nexport function noticeMails(options: ResolvedOptions): NoticeMails {\n\tconst { brand, links } = options;\n\tconst plain =\n\t\t(method: PlainNotice, target: PlainLink) =>\n\t\t// Async, so a wrong argument rejects as the other methods' do.\n\t\tasync (to: unknown): ReturnType<NoticeMails[PlainNotice]> =>\n\t\t\tsend(options, method, field(method, to, 'email'), {\n\t\t\t\tbrand,\n\t\t\t\tname: field(method, to, 'name'),\n\t\t\t\tlink: link(method, links[target](), `${target}()`),\n\t\t\t\tlocale: localeFor(options, to),\n\t\t\t});\n\treturn {\n\t\tpasswordChanged: plain('passwordChanged', 'secureAccount'),\n\t\ttwoFactorEnabled: plain('twoFactorEnabled', 'secureAccount'),\n\t\ttwoFactorDisabled: plain('twoFactorDisabled', 'secureAccount'),\n\t\twelcome: plain('welcome', 'getStarted'),\n\t\tasync emailChanged(to) {\n\t\t\t// To the former address: the one a hijacker just took the account from.\n\t\t\treturn send(\n\t\t\t\toptions,\n\t\t\t\t'emailChanged',\n\t\t\t\tfield('emailChanged', to, 'formerEmail'),\n\t\t\t\t{\n\t\t\t\t\tbrand,\n\t\t\t\t\tname: field('emailChanged', to, 'name'),\n\t\t\t\t\tlink: link('emailChanged', links.secureAccount(), 'secureAccount()'),\n\t\t\t\t\tnewEmail: field('emailChanged', to, 'newEmail'),\n\t\t\t\t\tlocale: localeFor(options, to),\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t};\n}\n",
|
|
10
11
|
"// Generated by scripts/build-mail.ts from mails/mail-manifest.json, after\n// each build of the default e-mails. Never edited; committed.\n\n/** The locales the default e-mails are built in, the fallback locale first. */\nexport const LOCALES = ['en', 'fr'] as const;\n\n/** A locale the default e-mails are built in. */\nexport type JanusMailLocale = (typeof LOCALES)[number];\n",
|
|
11
12
|
"/** A wiring refusal of `janusMail()`: a `TypeError` naming the option. */\nexport function refuse(message: string): never {\n\tthrow new TypeError(`janusMail: ${message}`);\n}\n",
|
|
12
13
|
"/**\n * `janusMail()`'s `links`, checked once when it is called and copied, so\n * the guarantee made there holds at every send. A mistake is a wiring\n * mistake: a bare `TypeError` naming the link, never its value.\n */\nimport { refuse } from './refuse';\nimport type { JanusMailLinks } from './types';\n\n/** The links every `janusMail()` needs: checked, then copied, by these names. */\nconst REQUIRED_LINKS = [\n\t'verifyEmail',\n\t'resetPassword',\n\t'secureAccount',\n\t'getStarted',\n] as const;\n\n/**\n * The links a `janusMail()` may leave out: `recoveryCodes` falls back to\n * `secureAccount`; `magicLink` has none, and its send is refused without it.\n */\nconst OPTIONAL_LINKS = ['recoveryCodes', 'magicLink'] as const;\n\n/** `links`: an object of functions, every required one there. */\nexport function checkLinks(\n\tlinks: unknown,\n): asserts links is Record<string, unknown> {\n\tif (typeof links !== 'object' || links === null || Array.isArray(links)) {\n\t\trefuse(\n\t\t\t'links must be an object, as { verifyEmail, resetPassword, secureAccount, getStarted }',\n\t\t);\n\t}\n\tconst given = links as Record<string, unknown>;\n\tfor (const name of REQUIRED_LINKS) {\n\t\tif (typeof given[name] !== 'function') {\n\t\t\trefuse(`links.${name} must be a function`);\n\t\t}\n\t}\n\tfor (const name of OPTIONAL_LINKS) {\n\t\tif (given[name] !== undefined && typeof given[name] !== 'function') {\n\t\t\trefuse(`links.${name} must be a function, or left out`);\n\t\t}\n\t}\n}\n\n/**\n * A frozen copy of the checked links, each bound to the caller's object — a\n * class instance's methods keep their `this` — so replacing a link after\n * `janusMail()` cannot undo the check. An optional link left out stays out.\n */\nexport function frozenLinks(links: JanusMailLinks): JanusMailLinks {\n\tconst given = links as unknown as Record<\n\t\tstring,\n\t\t((...args: never[]) => unknown) | undefined\n\t>;\n\tconst names = [\n\t\t...REQUIRED_LINKS,\n\t\t...OPTIONAL_LINKS.filter((name) => given[name] !== undefined),\n\t];\n\t// Every name kept was checked a function by checkLinks.\n\treturn Object.freeze(\n\t\tObject.fromEntries(\n\t\t\tnames.map((name) => [\n\t\t\t\tname,\n\t\t\t\t(given[name] as (...args: never[]) => unknown).bind(links),\n\t\t\t]),\n\t\t),\n\t) as unknown as JanusMailLinks;\n}\n",
|
|
13
14
|
"/**\n * Where the default e-mails are, and the one renderer that reads them.\n *\n * The package ships the built e-mails in `mails/`, beside `dist/` — not in\n * it, because the root `build.ts` removes from `dist/` every file it did not\n * write itself.\n */\nimport { fileURLToPath } from 'node:url';\nimport { createMailRenderer, type MailRenderer } from '@nxgt/mail/renderer';\nimport type { MailEmails } from './generated/mail';\n\n/**\n * The folder of the built e-mails, resolved from this module rather than from\n * the working directory, which is the consumer's.\n *\n * **This file must stay directly under `src/`.** `../mails/` is right from\n * `src/mails.ts` in the specs, and from `dist/index.js` in the tarball,\n * because the build bundles this module into the single entry\n * `dist/index.js`, one level under the package as `src/` is. Moved into a\n * subfolder, or bundled into `dist/chunks/` by a second entry point, it would\n * resolve a folder that does not exist — which the artifact spec, rendering\n * from `../dist`, would catch.\n */\nexport const MAILS_DIR = fileURLToPath(new URL('../mails/', import.meta.url));\n\nlet renderer: MailRenderer<MailEmails> | undefined;\n\n/**\n * The renderer of the default e-mails, created on first use and shared by\n * every `janusMail()` and `janusTemplates()` after it.\n *\n * Lazy, so importing the package reads nothing: an application that\n * overrides every template never opens `mails/`. The first default template\n * rendered reads the whole build once — a missing `mails/` throws there, with\n * `createMailRenderer`'s own message.\n */\nexport function defaultRenderer(): MailRenderer<MailEmails> {\n\trenderer ??= createMailRenderer<MailEmails>({ dir: MAILS_DIR });\n\treturn renderer;\n}\n",
|
|
14
15
|
"/**\n * The default templates: the prebuilt e-mails, filled by `@nxgt/mail`'s\n * renderer. Each picks from its variables exactly what its e-mail takes — the\n * renderer refuses a variable too many — so the `locale` beside them goes to\n * the renderer's options, and nowhere else.\n */\nimport type { Rendered } from '@nxgt/mail';\nimport { defaultRenderer } from './mails';\nimport type { JanusMailTemplates } from './types';\n\n/** The two whose variables fill a summary, apart to keep the list short. */\nconst recoveryCodeUsed: JanusMailTemplates['recoveryCodeUsed'] = ({\n\tbrand,\n\tname,\n\twhen,\n\trecoveryCodesLeft,\n\tlink,\n\tlocale,\n}): Rendered =>\n\tdefaultRenderer().render(\n\t\t'recovery-code-used',\n\t\t{ brand, name, when, recoveryCodesLeft, link },\n\t\t{ locale },\n\t);\n\nconst newSignIn: JanusMailTemplates['newSignIn'] = ({\n\tbrand,\n\tname,\n\tdevice,\n\tlocation,\n\ttime,\n\tlink,\n\tlocale,\n}): Rendered =>\n\tdefaultRenderer().render(\n\t\t'new-sign-in',\n\t\t{ brand, name, device, location, time, link },\n\t\t{ locale },\n\t);\n\n/**\n * The twelve default templates, in the locales they are built in. The\n * renderer behind them is created on the first render, not here.\n *\n * ```ts\n * const defaults = janusTemplates();\n * const { subject } = await defaults.verifyEmail({ brand: 'Acme', name: 'Ada', link, locale: 'fr' });\n * ```\n *\n * A URL that is not `http:`, `https:` or `mailto:` throws `MailRefused`; a\n * missing `mails/` folder throws when the first one renders.\n */\nexport function janusTemplates(): JanusMailTemplates {\n\treturn Object.freeze({\n\t\tverifyEmail: ({ brand, name, link, expiresIn, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'verify-email',\n\t\t\t\t{ brand, name, link, expiresIn },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\tresetPassword: ({ brand, name, link, expiresIn, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'reset-password',\n\t\t\t\t{ brand, name, link, expiresIn },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\tsignInCode: ({ brand, code, expiresIn, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'sign-in-code',\n\t\t\t\t{ brand, code, expiresIn },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\tmagicLink: ({ brand, link, expiresIn, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'magic-link',\n\t\t\t\t{ brand, link, expiresIn },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\tstepUp: ({ brand, name, code, expiresIn, link, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'confirm-action',\n\t\t\t\t{ brand, name, code, expiresIn, link },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\tpasswordChanged: ({ brand, name, link, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'password-changed',\n\t\t\t\t{ brand, name, link },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\temailChanged: ({ brand, name, link, newEmail, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'email-changed',\n\t\t\t\t{ brand, name, link, newEmail },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\ttwoFactorEnabled: ({ brand, name, link, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'two-factor-enabled',\n\t\t\t\t{ brand, name, link },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\ttwoFactorDisabled: ({ brand, name, link, locale }): Rendered =>\n\t\t\tdefaultRenderer().render(\n\t\t\t\t'two-factor-disabled',\n\t\t\t\t{ brand, name, link },\n\t\t\t\t{ locale },\n\t\t\t),\n\t\trecoveryCodeUsed,\n\t\tnewSignIn,\n\t\twelcome: ({ brand, name, link, locale }): Rendered =>\n\t\t\tdefaultRenderer().render('welcome', { brand, name, link }, { locale }),\n\t});\n}\n",
|
|
15
|
-
"/**\n * `janusMail()`'s options, checked once when it is called. A mistake is a\n * wiring mistake, so a bare `TypeError` naming the option — never its value —\n * thrown before anything is sent.\n */\nimport type { Clock } from '@nxgt/janus';\nimport type { Address, Mailer } from '@nxgt/mail';\nimport { LOCALES } from './generated/locales';\nimport { checkLinks, frozenLinks } from './links';\nimport { refuse } from './refuse';\nimport { janusTemplates } from './templates';\nimport type {\n\tJanusMailLinks,\n\tJanusMailTemplateName,\n\tJanusMailTemplates,\n} from './types';\n\n/** The templates in the order the documentation lists them. */\nexport const TEMPLATE_NAMES: readonly JanusMailTemplateName[] = [\n\t'verifyEmail',\n\t'resetPassword',\n\t'signInCode',\n\t'magicLink',\n\t'stepUp',\n\t'passwordChanged',\n\t'emailChanged',\n\t'twoFactorEnabled',\n\t'twoFactorDisabled',\n\t'recoveryCodeUsed',\n\t'newSignIn',\n\t'welcome',\n];\n\n/** The options once checked, with `string` for the locales: the degenericised mirror. */\nexport interface ResolvedOptions {\n\treadonly mailer: Mailer;\n\treadonly from: Address;\n\treadonly replyTo: Address | undefined;\n\treadonly brand: string;\n\treadonly links: JanusMailLinks;\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly templates: JanusMailTemplates<string>;\n\treadonly clock: Clock;\n}\n\n/** The system clock, written here: `@nxgt/janus` is a peer for its types only. */\nconst SYSTEM_CLOCK: Clock = Object.freeze({ now: () => new Date() });\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isAddress(value: unknown): value is Address {\n\tif (typeof value === 'string') return value.trim() !== '';\n\treturn (\n\t\tisObject(value) &&\n\t\ttypeof value
|
|
16
|
+
"/**\n * `janusMail()`'s options, checked once when it is called. A mistake is a\n * wiring mistake, so a bare `TypeError` naming the option — never its value —\n * thrown before anything is sent.\n */\nimport type { Clock } from '@nxgt/janus';\nimport type { Address, Mailer } from '@nxgt/mail';\nimport { LOCALES } from './generated/locales';\nimport { checkLinks, frozenLinks } from './links';\nimport { refuse } from './refuse';\nimport { janusTemplates } from './templates';\nimport type {\n\tJanusMailLinks,\n\tJanusMailTemplateName,\n\tJanusMailTemplates,\n} from './types';\n\n/** The templates in the order the documentation lists them. */\nexport const TEMPLATE_NAMES: readonly JanusMailTemplateName[] = [\n\t'verifyEmail',\n\t'resetPassword',\n\t'signInCode',\n\t'magicLink',\n\t'stepUp',\n\t'passwordChanged',\n\t'emailChanged',\n\t'twoFactorEnabled',\n\t'twoFactorDisabled',\n\t'recoveryCodeUsed',\n\t'newSignIn',\n\t'welcome',\n];\n\n/** The options once checked, with `string` for the locales: the degenericised mirror. */\nexport interface ResolvedOptions {\n\treadonly mailer: Mailer;\n\treadonly from: Address;\n\treadonly replyTo: Address | undefined;\n\treadonly brand: string;\n\treadonly links: JanusMailLinks;\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly templates: JanusMailTemplates<string>;\n\treadonly clock: Clock;\n}\n\n/** The system clock, written here: `@nxgt/janus` is a peer for its types only. */\nconst SYSTEM_CLOCK: Clock = Object.freeze({ now: () => new Date() });\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isAddress(value: unknown): value is Address {\n\tif (typeof value === 'string') return value.trim() !== '';\n\treturn (\n\t\tisObject(value) &&\n\t\ttypeof value['name'] === 'string' &&\n\t\ttypeof value['address'] === 'string' &&\n\t\tvalue['address'].trim() !== ''\n\t);\n}\n\n/** `mailer`, `from`, `replyTo`, `brand` and `links` (`./links`). */\nfunction checkSending(options: Record<string, unknown>): void {\n\tconst { mailer, from, replyTo, brand, links } = options;\n\tif (!isObject(mailer) || typeof mailer['send'] !== 'function') {\n\t\trefuse('mailer must be a Mailer — an object with a send function');\n\t}\n\tif (!isAddress(from)) {\n\t\trefuse(\n\t\t\t\"from must be an address, as 'noreply@example.com' or { name, address }\",\n\t\t);\n\t}\n\tif (replyTo !== undefined && !isAddress(replyTo)) {\n\t\trefuse(\n\t\t\t\"replyTo must be an address, as 'support@example.com' or { name, address }\",\n\t\t);\n\t}\n\tif (typeof brand !== 'string' || brand.trim() === '') {\n\t\trefuse(\"brand must be the name the e-mails show, as 'Acme'\");\n\t}\n\tcheckLinks(links);\n}\n\n/** `clock`, bound to the caller's object, or the system clock. */\nfunction resolveClock(clock: unknown): Clock {\n\tif (clock === undefined) return SYSTEM_CLOCK;\n\tif (!isObject(clock) || typeof clock['now'] !== 'function') {\n\t\trefuse('clock must be a Clock — an object with a now function');\n\t}\n\treturn Object.freeze({ now: (clock['now'] as () => Date).bind(clock) });\n}\n\n/** Whether `Intl` takes the locale — the expiry is formatted in it — as `fr-CA`, not `fr_CA`. */\nfunction isLanguageTag(locale: string): boolean {\n\ttry {\n\t\tIntl.getCanonicalLocales(locale);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/** `locales` and `fallbackLocale`, with their defaults. */\nfunction resolveLocales(options: Record<string, unknown>): {\n\tlocales: readonly string[];\n\tfallbackLocale: string;\n} {\n\tconst wanted = options['locales'] ?? LOCALES;\n\tif (\n\t\t!Array.isArray(wanted) ||\n\t\twanted.length === 0 ||\n\t\t!wanted.every((locale) => typeof locale === 'string' && locale !== '')\n\t) {\n\t\trefuse(\"locales must list at least one locale, as ['en', 'fr']\");\n\t}\n\tconst locales: readonly string[] = Object.freeze([...wanted]);\n\tif (!locales.every(isLanguageTag)) {\n\t\trefuse(\"locales must be BCP 47 language tags, as 'fr-CA'\");\n\t}\n\tif (new Set(locales).size !== locales.length) {\n\t\trefuse('locales holds the same locale twice');\n\t}\n\tconst fallbackLocale =\n\t\toptions['fallbackLocale'] ??\n\t\t(locales.includes('en') ? 'en' : (locales[0] as string));\n\tif (typeof fallbackLocale !== 'string' || !locales.includes(fallbackLocale)) {\n\t\trefuse('fallbackLocale must be one of locales');\n\t}\n\treturn { locales, fallbackLocale };\n}\n\n/** `templates` over the defaults — the defaults only while every locale is built. */\nfunction resolveTemplates(\n\toptions: Record<string, unknown>,\n\tlocales: readonly string[],\n): JanusMailTemplates<string> {\n\tconst given = options['templates'] ?? {};\n\tif (!isObject(given)) {\n\t\trefuse(\n\t\t\t'templates must be an object of functions, as { verifyEmail: (variables) => rendered }',\n\t\t);\n\t}\n\tfor (const [name, template] of Object.entries(given)) {\n\t\tif (!(TEMPLATE_NAMES as readonly string[]).includes(name)) {\n\t\t\trefuse(\n\t\t\t\t`templates has no template ${name} — name one of ${TEMPLATE_NAMES.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (typeof template !== 'function') {\n\t\t\trefuse(`templates.${name} must be a function`);\n\t\t}\n\t}\n\t// Own enumerable keys, the ones the spread below copies. A template on a\n\t// prototype — a class instance's method — or an own property that is not\n\t// enumerable would be dropped without a word, the default sent in its\n\t// place: `in` sees it and `passed` does not, so it is refused instead.\n\tconst passed = Object.keys(given);\n\tfor (const name of TEMPLATE_NAMES) {\n\t\tif (name in given && !passed.includes(name)) {\n\t\t\trefuse(\n\t\t\t\t`templates.${name} is not an own enumerable property — pass a plain object, as { ${name}: (variables) => rendered }`,\n\t\t\t);\n\t\t}\n\t}\n\tconst built = locales.every((locale) =>\n\t\t(LOCALES as readonly string[]).includes(locale),\n\t);\n\tconst missing = TEMPLATE_NAMES.filter((name) => !passed.includes(name));\n\tif (!built && missing.length > 0) {\n\t\trefuse(\n\t\t\t`the default templates are built in ${LOCALES.join(' and ')} only — with another ` +\n\t\t\t\t`locale in locales, pass every template in templates; ${missing.join(', ')} missing`,\n\t\t);\n\t}\n\t// The one cast: a default template takes a built locale only, and the check\n\t// above proves every locale is one whenever a default is kept.\n\tconst defaults = janusTemplates() as unknown as JanusMailTemplates<string>;\n\treturn Object.freeze({ ...defaults, ...given }) as JanusMailTemplates<string>;\n}\n\n/** A frozen copy of a checked address: a later change to the caller's object is not seen. */\nfunction frozenAddress(address: Address): Address {\n\treturn typeof address === 'string'\n\t\t? address\n\t\t: Object.freeze({ name: address.name, address: address.address });\n}\n\n/**\n * Checks `janusMail()`'s options and answers them resolved, or throws a\n * `TypeError`. What was checked is copied and frozen, so the guarantee made\n * here holds at every send.\n */\nexport function resolveOptions(options: unknown): ResolvedOptions {\n\tif (!isObject(options)) {\n\t\trefuse('options must be an object, as { mailer, from, brand, links }');\n\t}\n\tcheckSending(options);\n\tconst { locales, fallbackLocale } = resolveLocales(options);\n\treturn Object.freeze({\n\t\tmailer: options['mailer'] as Mailer,\n\t\tfrom: frozenAddress(options['from'] as Address),\n\t\treplyTo:\n\t\t\toptions['replyTo'] === undefined\n\t\t\t\t? undefined\n\t\t\t\t: frozenAddress(options['replyTo'] as Address),\n\t\tbrand: options['brand'] as string,\n\t\tlinks: frozenLinks(options['links'] as unknown as JanusMailLinks),\n\t\tlocales,\n\t\tfallbackLocale,\n\t\ttemplates: resolveTemplates(options, locales),\n\t\tclock: resolveClock(options['clock']),\n\t});\n}\n",
|
|
16
17
|
"// Generated by scripts/build-mail.ts from recovery-code-used.codes-left, after\n// each build of the default e-mails. Never edited; committed.\n\n/** Each locale's plural for the recovery codes left: branches by selector, `null` where the count goes. */\nexport const CODES_LEFT: Readonly<Record<string, Readonly<Record<string, readonly (string | null)[]>>>> = {\n\t\"en\": {\n\t\t\"=0\": [\n\t\t\t\"You have no recovery codes left.\"\n\t\t],\n\t\t\"one\": [\n\t\t\t\"You have \",\n\t\t\tnull,\n\t\t\t\" recovery code left.\"\n\t\t],\n\t\t\"other\": [\n\t\t\t\"You have \",\n\t\t\tnull,\n\t\t\t\" recovery codes left.\"\n\t\t]\n\t},\n\t\"fr\": {\n\t\t\"=0\": [\n\t\t\t\"Il ne vous reste aucun code de récupération.\"\n\t\t],\n\t\t\"one\": [\n\t\t\t\"Il vous reste \",\n\t\t\tnull,\n\t\t\t\" code de récupération.\"\n\t\t],\n\t\t\"other\": [\n\t\t\t\"Il vous reste \",\n\t\t\tnull,\n\t\t\t\" codes de récupération.\"\n\t\t]\n\t}\n};\n",
|
|
17
|
-
"/**\n * The sentence of the recovery codes left, in the recipient's locale:\n * \"You have 1 recovery code left.\" — the `recovery-code-used` e-mail's\n * `recoveryCodesLeft`, which the build could not write since the count is a\n * send's.\n *\n * Formatted from `src/generated/codes-left.ts`, the preset's ICU plural\n * parsed at our build, as `@nxgt/mail-i18n`'s `createTranslator` formats\n * it: an exact branch (`=0`) first, then the locale's plural category, then\n * `other`, with `#` as the count in the locale's digits. No Maizzle and no\n * ICU parser at send time.\n */\nimport { CODES_LEFT } from './generated/codes-left';\n\n/**\n * The sentence for `count` codes left in `locale`, or `undefined` for a\n * locale the default e-mails are not built in.\n */\nexport function codesLeftText(\n\tlocale: string,\n\tcount: number,\n): string | undefined {\n\tif (!Object.hasOwn(CODES_LEFT, locale)) return undefined;\n\tconst branches = CODES_LEFT[locale] as (typeof CODES_LEFT)[string];\n\tconst branch =\n\t\tbranches[`=${count}`] ??\n\t\tbranches[new Intl.PluralRules(locale).select(count)] ??\n\t\tbranches
|
|
18
|
+
"/**\n * The sentence of the recovery codes left, in the recipient's locale:\n * \"You have 1 recovery code left.\" — the `recovery-code-used` e-mail's\n * `recoveryCodesLeft`, which the build could not write since the count is a\n * send's.\n *\n * Formatted from `src/generated/codes-left.ts`, the preset's ICU plural\n * parsed at our build, as `@nxgt/mail-i18n`'s `createTranslator` formats\n * it: an exact branch (`=0`) first, then the locale's plural category, then\n * `other`, with `#` as the count in the locale's digits. No Maizzle and no\n * ICU parser at send time.\n */\nimport { CODES_LEFT } from './generated/codes-left';\n\n/**\n * The sentence for `count` codes left in `locale`, or `undefined` for a\n * locale the default e-mails are not built in.\n */\nexport function codesLeftText(\n\tlocale: string,\n\tcount: number,\n): string | undefined {\n\tif (!Object.hasOwn(CODES_LEFT, locale)) return undefined;\n\tconst branches = CODES_LEFT[locale] as (typeof CODES_LEFT)[string];\n\tconst branch =\n\t\tbranches[`=${count}`] ??\n\t\tbranches[new Intl.PluralRules(locale).select(count)] ??\n\t\tbranches['other'];\n\tconst digits = new Intl.NumberFormat(locale).format(count);\n\treturn (branch ?? []).map((part) => part ?? digits).join('');\n}\n",
|
|
18
19
|
"/**\n * `recoveryCodeUsed`: the notice of a recovery code spent — a sign-in\n * without the user's phone — saying when, and how many codes are left.\n *\n * Apart from the other notices because of its count: the build could not\n * choose the plural, so the send does, in the recipient's locale\n * (`./codes-left`).\n */\nimport { codesLeftText } from './codes-left';\nimport type { ResolvedOptions } from './options';\nimport { field, link, localeFor, send } from './send';\nimport type { JanusMail } from './types';\n\nconst METHOD = 'recoveryCodeUsed';\n\n/** A count of codes: a whole number, 0 or more. */\nconst isCount = (value: unknown): value is number =>\n\ttypeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n\n/**\n * The sentence of the codes left: the count formatted in `locale`, or the\n * sender's own text. A `TypeError` for anything else, or for a count in a\n * locale the default e-mails hold no sentence for.\n */\nfunction codesLeft(used: unknown, locale: string): string {\n\tconst given =\n\t\ttypeof used === 'object' && used !== null\n\t\t\t? (used as { recoveryCodesLeft?: unknown }).recoveryCodesLeft\n\t\t\t: undefined;\n\tif (typeof given === 'string') return given;\n\tif (!isCount(given)) {\n\t\tthrow new TypeError(\n\t\t\t`janusMail.${METHOD}: recoveryCodesLeft must be a count — a whole number, 0 or more — or the sentence to show`,\n\t\t);\n\t}\n\tconst text = codesLeftText(locale, given);\n\tif (text === undefined) {\n\t\tthrow new TypeError(\n\t\t\t`janusMail.${METHOD}: recoveryCodesLeft must be the sentence to show in a locale the default e-mails are not built in`,\n\t\t);\n\t}\n\treturn text;\n}\n\n/** The recovery code notice, over the resolved options. */\nexport function recoveryMail(\n\toptions: ResolvedOptions,\n): Pick<JanusMail<string>, 'recoveryCodeUsed'> {\n\tconst { brand, links } = options;\n\treturn {\n\t\t// Async, so a wrong argument rejects as the other methods' do.\n\t\tasync recoveryCodeUsed(to, used) {\n\t\t\tconst locale = localeFor(options, to);\n\t\t\treturn send(options, METHOD, field(METHOD, to, 'email'), {\n\t\t\t\tbrand,\n\t\t\t\tname: field(METHOD, to, 'name'),\n\t\t\t\twhen: field(METHOD, used, 'when'),\n\t\t\t\trecoveryCodesLeft: codesLeft(used, locale),\n\t\t\t\tlink:\n\t\t\t\t\tlinks.recoveryCodes === undefined\n\t\t\t\t\t\t? link(METHOD, links.secureAccount(), 'secureAccount()')\n\t\t\t\t\t\t: link(METHOD, links.recoveryCodes(), 'recoveryCodes()'),\n\t\t\t\tlocale,\n\t\t\t});\n\t\t},\n\t};\n}\n",
|
|
19
20
|
"/**\n * `stepUp`: the code of a step-up — a signed-in user proving again who they\n * are before a sensitive action — to the address `auth.stepUp.request(user)`\n * answered, greeting them, saying how long the code lasts, and linking to\n * where the account is secured, for a user who asked for nothing.\n *\n * Apart from the sign-in code's e-mail because of `via`: a step-up confirmed\n * with the user's app sends nothing, and is refused here rather than mailed\n * as an empty code.\n */\nimport { expiresInFor } from './expiry';\nimport type { ResolvedOptions } from './options';\nimport { field, link, localeFor, send } from './send';\nimport type { JanusMail } from './types';\n\nconst METHOD = 'stepUp';\n\n/** `issued.via`, which must be `'email'`: a `TypeError` otherwise, before anything else is read. */\nfunction checkVia(issued: unknown): void {\n\tconst via =\n\t\ttypeof issued === 'object' && issued !== null\n\t\t\t? (issued as { via?: unknown }).via\n\t\t\t: undefined;\n\tif (via !== 'email') {\n\t\tthrow new TypeError(\n\t\t\t`janusMail.${METHOD}: via must be 'email' — a step-up confirmed with the user's app sends no e-mail`,\n\t\t);\n\t}\n}\n\n/** The step-up's e-mail, over the resolved options. */\nexport function stepUpMail(\n\toptions: ResolvedOptions,\n): Pick<JanusMail<string>, 'stepUp'> {\n\tconst { brand, links } = options;\n\treturn {\n\t\t// `via`, `code`, `email` and `expiresAt` only: the challenge is the user's secret.\n\t\tasync stepUp(issued, to, sendOptions) {\n\t\t\tcheckVia(issued);\n\t\t\tconst locale = localeFor(options, to);\n\t\t\treturn send(options, METHOD, field(METHOD, issued, 'email'), {\n\t\t\t\tbrand,\n\t\t\t\tname: field(METHOD, to, 'name'),\n\t\t\t\tcode: field(METHOD, issued, 'code'),\n\t\t\t\texpiresIn: expiresInFor(\n\t\t\t\t\tMETHOD,\n\t\t\t\t\tissued,\n\t\t\t\t\tlocale,\n\t\t\t\t\tsendOptions,\n\t\t\t\t\toptions.clock,\n\t\t\t\t),\n\t\t\t\tlink: link(METHOD, links.secureAccount(), 'secureAccount()'),\n\t\t\t\tlocale,\n\t\t\t});\n\t\t},\n\t};\n}\n",
|
|
20
21
|
"/**\n * `janusMail()`: the e-mails of Janus's flows, rendered by the templates and\n * handed to the mailer. It sends what a flow answered, to the address the\n * flow answered, and nothing else: no retry, no queue, no error of its own —\n * the mailer's `MailFailure` and `MailRefused` reach the caller untouched.\n */\n\nimport { expiringMails } from './expiring-mails';\nimport { newSignInMail } from './new-sign-in-mail';\nimport { noticeMails } from './notice-mails';\nimport { resolveOptions } from './options';\nimport { recoveryMail } from './recovery-mail';\nimport { stepUpMail } from './step-up-mail';\nimport type { JanusMail, JanusMailLocale, JanusMailOptions } from './types';\n\n/**\n * The e-mails of Janus's flows, over your mailer:\n *\n * ```ts\n * const mail = janusMail({\n * \tmailer,\n * \tfrom: 'noreply@acme.example',\n * \tbrand: 'Acme',\n * \tlinks: {\n * \t\tverifyEmail: (token) => `https://acme.example/verify?token=${token}`,\n * \t\tresetPassword: (token) => `https://acme.example/reset?token=${token}`,\n * \t\tsecureAccount: () => 'https://acme.example/account/security',\n * \t\tgetStarted: () => 'https://acme.example/',\n * \t\trecoveryCodes: () => 'https://acme.example/account/recovery-codes', // optional\n * \t},\n * });\n *\n * await mail.verifyEmail(await auth.verifyEmail.send(user), { name: user.name, locale: user.locale });\n * ```\n *\n * Reads nothing when called: the default e-mails are read on the first one\n * sent. A wrong option is a bare `TypeError`, thrown here.\n */\nexport function janusMail<const L extends string = JanusMailLocale>(\n\toptions: JanusMailOptions<L>,\n): JanusMail<L> {\n\tconst resolved = resolveOptions(options);\n\tconst mail: JanusMail<string> = Object.freeze({\n\t\t...expiringMails(resolved),\n\t\t...noticeMails(resolved),\n\t\t...recoveryMail(resolved),\n\t\t...newSignInMail(resolved),\n\t\t...stepUpMail(resolved),\n\t\ttemplates: resolved.templates,\n\t\tlocales: resolved.locales,\n\t});\n\t// The one cast at the boundary: the mirror above works on `string` locales.\n\treturn mail as unknown as JanusMail<L>;\n}\n"
|
|
21
22
|
],
|
|
22
|
-
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
23
|
+
"mappings": "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",
|
|
24
|
+
"debugId": "1AB9B2239C4A4C2464756E2164756E21",
|
|
24
25
|
"names": []
|
|
25
26
|
}
|
|
@@ -4,13 +4,11 @@
|
|
|
4
4
|
* where the account is secured.
|
|
5
5
|
*
|
|
6
6
|
* Apart from the other notices because of its optional `location`: Janus
|
|
7
|
-
* sees no IP, so the sender may know none, and the e-mail then
|
|
8
|
-
*
|
|
7
|
+
* sees no IP, so the sender may know none, and the e-mail then says so in
|
|
8
|
+
* the send's locale — "Location Unknown", "Lieu Inconnu" (`./no-location`).
|
|
9
9
|
*/
|
|
10
10
|
import type { ResolvedOptions } from './options';
|
|
11
11
|
import type { JanusMail } from './types';
|
|
12
|
-
/** What the e-mail shows where the sender knew no location. */
|
|
13
|
-
export declare const NO_LOCATION = "\u2014";
|
|
14
12
|
/** The new sign-in notice, over the resolved options. */
|
|
15
13
|
export declare function newSignInMail(options: ResolvedOptions): Pick<JanusMail<string>, 'newSignIn'>;
|
|
16
14
|
//# sourceMappingURL=new-sign-in-mail.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new-sign-in-mail.d.ts","sourceRoot":"","sources":["../src/new-sign-in-mail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"new-sign-in-mail.d.ts","sourceRoot":"","sources":["../src/new-sign-in-mail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAiBzC,yDAAyD;AACzD,wBAAgB,aAAa,CAC5B,OAAO,EAAE,eAAe,GACtB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAiBtC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `newSignIn` shows where the sender knew no location — "Unknown",
|
|
3
|
+
* "Inconnu" — in the recipient's locale: the value after the row's label,
|
|
4
|
+
* so "Location Unknown", "Lieu Inconnu".
|
|
5
|
+
*
|
|
6
|
+
* A map written here, not a message in `mail/locales/*.json`: those
|
|
7
|
+
* catalogues are read by the Maizzle build alone, and hold only the
|
|
8
|
+
* presets' own keys, which the build checks against `@nxgt/mail-presets`'
|
|
9
|
+
* `en`. This string is a send's — whether a location was given is known
|
|
10
|
+
* only then — so it is chosen at send time, as the codes left are
|
|
11
|
+
* (`./codes-left`). Keyed by `JanusMailLocale`, so a locale added to the
|
|
12
|
+
* build without its text here is a compile error.
|
|
13
|
+
*/
|
|
14
|
+
import type { JanusMailLocale } from './generated/locales';
|
|
15
|
+
/** The text of a missing location, by built locale. */
|
|
16
|
+
export declare const NO_LOCATION: Readonly<Record<JanusMailLocale, string>>;
|
|
17
|
+
/**
|
|
18
|
+
* The text of a missing location in `locale` — the one `localeFor` picked —
|
|
19
|
+
* else in its language (`fr` for `fr-CA`), else in `en`: a locale beyond
|
|
20
|
+
* the built ones is sent only through templates of the consumer's own.
|
|
21
|
+
*/
|
|
22
|
+
export declare function noLocationText(locale: string): string;
|
|
23
|
+
//# sourceMappingURL=no-location.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-location.d.ts","sourceRoot":"","sources":["../src/no-location.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAI/D,CAAC;AAMJ;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD"}
|
package/dist/template-types.d.ts
CHANGED
|
@@ -86,8 +86,10 @@ export interface JanusMailVariables {
|
|
|
86
86
|
};
|
|
87
87
|
/**
|
|
88
88
|
* `device`, `time` and `location` are the sender's text, already in the
|
|
89
|
-
* recipient's locale
|
|
90
|
-
*
|
|
89
|
+
* recipient's locale. Without a `location` from the sender, it is
|
|
90
|
+
* "Unknown" in the send's locale — "Inconnu" in `fr` — the
|
|
91
|
+
* language's text for a regional `en` or `fr` tag, `en`'s for any other.
|
|
92
|
+
* `link` is where the account is secured.
|
|
91
93
|
*/
|
|
92
94
|
readonly newSignIn: {
|
|
93
95
|
readonly brand: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-types.d.ts","sourceRoot":"","sources":["../src/template-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,WAAW,EAAE;QACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,qFAAqF;IACrF,QAAQ,CAAC,UAAU,EAAE;QACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE;QACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE;QAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,eAAe,EAAE;QACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,YAAY,EAAE;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,QAAQ,CAAC,gBAAgB,EAAE;QAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,iBAAiB,EAAE;QAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACtB,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,EAAE;QAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;QACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACtB,CAAC;IACF
|
|
1
|
+
{"version":3,"file":"template-types.d.ts","sourceRoot":"","sources":["../src/template-types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -165,7 +165,7 @@ export interface JanusMail<L extends string = JanusMailLocale> {
|
|
|
165
165
|
* Every value is your text, in the recipient's locale: `device` described
|
|
166
166
|
* from the request (`'Firefox on macOS'`), `time` formatted in their time
|
|
167
167
|
* zone. **Janus sees no IP**: `location` is yours to work out, and an
|
|
168
|
-
* e-mail without one
|
|
168
|
+
* e-mail without one says "Unknown" in its place — "Inconnu" in French.
|
|
169
169
|
*/
|
|
170
170
|
newSignIn(to: Recipient & {
|
|
171
171
|
readonly email: string;
|
package/docs/guide/locales.md
CHANGED
|
@@ -104,6 +104,10 @@ mail.locales; // readonly ('en' | 'fr' | 'de')[]
|
|
|
104
104
|
plural of the codes left in `en` and `fr` only, so a German recipient's
|
|
105
105
|
`mail.recoveryCodeUsed` takes the sentence as text — "Sie haben noch 3
|
|
106
106
|
Wiederherstellungscodes." — and a count is a `TypeError` there.
|
|
107
|
+
`location`, left out of a `newSignIn`, is "Unknown" for `de`:
|
|
108
|
+
the text of a missing location is held in `en` and `fr` only, so pass
|
|
109
|
+
`location` yourself — "Unbekannt", so the row reads `Ort Unbekannt` —
|
|
110
|
+
where it matters.
|
|
107
111
|
`recoveryCodeUsed` is the ninth template, since 0.5.0, `magicLink` the
|
|
108
112
|
tenth, since 0.7.0, `stepUp` the eleventh, since 0.8.0, and `newSignIn` the
|
|
109
113
|
twelfth, since 0.9.0: a `templates`
|
package/docs/guide/sending.md
CHANGED
|
@@ -180,8 +180,10 @@ no action: it says "something sensitive", whatever the route guards.
|
|
|
180
180
|
template.
|
|
181
181
|
- **The link has no fallback, and needs none.** `links.secureAccount` is
|
|
182
182
|
required by `janusMail()`: the notices link to it too.
|
|
183
|
-
-
|
|
184
|
-
|
|
183
|
+
- **`@nxgt/janus` throttles `stepUp.request` per user** (five in 10 minutes by
|
|
184
|
+
default): past that it throws `MAIL_THROTTLED` and there is nothing to send;
|
|
185
|
+
the code last sent still works.
|
|
186
|
+
Limiting per client stays the application's.
|
|
185
187
|
|
|
186
188
|
### `passwordChanged(to)`
|
|
187
189
|
|
|
@@ -386,14 +388,18 @@ it carries no request to describe the device from.
|
|
|
386
388
|
happened.
|
|
387
389
|
- **`location` is optional, and yours.** `@nxgt/janus` sees no IP: a
|
|
388
390
|
location comes from a geo-IP of your own, if you have one. Left out, the
|
|
389
|
-
e-mail
|
|
390
|
-
|
|
391
|
+
e-mail says so in the locale it is sent in — `Location Unknown`, `Lieu
|
|
392
|
+
Inconnu` — since every line of the summary is always there. A locale
|
|
393
|
+
beyond `en` and `fr`, sent through templates of your own, gets its
|
|
394
|
+
language's text when it is `en` or `fr` (`fr-CA` gets "Inconnu"),
|
|
395
|
+
and "Unknown" otherwise: pass `location` yourself there. `null` is a
|
|
391
396
|
compile error, and in JavaScript `janusMail.newSignIn: location must be a
|
|
392
397
|
string`: spread it in only when you have one,
|
|
393
398
|
`...(city === null ? {} : { location: city })`.
|
|
394
|
-
- **The text part** gives each line of the summary
|
|
395
|
-
|
|
396
|
-
|
|
399
|
+
- **The text part** gives each line of the summary on one line, its label
|
|
400
|
+
then its value — `Device Firefox on macOS`, `Location Unknown`,
|
|
401
|
+
`Time September 29, 2026 at 9:12 AM` — one row per line, with no blank line
|
|
402
|
+
between rows.
|
|
397
403
|
|
|
398
404
|
## The expiry
|
|
399
405
|
|
package/docs/guide/templates.md
CHANGED
|
@@ -78,7 +78,9 @@ Every one also gets `locale`, one of `locales`. Every value is a string:
|
|
|
78
78
|
for `stepUp`, `links.recoveryCodes()` (else
|
|
79
79
|
`links.secureAccount()`) for `recoveryCodeUsed`, `links.getStarted()` for
|
|
80
80
|
`welcome` — `code`, `newEmail`, `when`, `device` and `time` from the
|
|
81
|
-
call, `location` from the call or
|
|
81
|
+
call, `location` from the call or, without one, "Unknown" in the
|
|
82
|
+
send's locale — "Inconnu" in `fr`; for another locale, its
|
|
83
|
+
language's text when it is `en` or `fr` (`fr-CA`), else `en`'s — and `expiresIn` derived from the flow's `expiresAt` in the locale, or
|
|
82
84
|
the send's own `expiresIn` ([Sending](sending.md#the-expiry)).
|
|
83
85
|
|
|
84
86
|
`recoveryCodesLeft` is a **sentence**, not the count: "You have 9 recovery
|
|
@@ -181,7 +183,7 @@ them renders: that is when the package's `mails/` folder is read, once.
|
|
|
181
183
|
## What the defaults say
|
|
182
184
|
|
|
183
185
|
The defaults are [`@nxgt/mail-presets`](https://www.npmjs.com/package/@nxgt/mail-presets)
|
|
184
|
-
1.1.
|
|
186
|
+
1.1.1, built with a neutral grey theme and no logo:
|
|
185
187
|
|
|
186
188
|
| Template | Built from | Subject (`en`) | Subject (`fr`) |
|
|
187
189
|
| --- | --- | --- | --- |
|
|
@@ -212,7 +214,8 @@ device we had not seen*, then a summary of three lines — **Device**,
|
|
|
212
214
|
**Location** and **Time**, *Appareil*, *Lieu* and *Heure* in French — then
|
|
213
215
|
*if this was you, there is nothing to do; if this was not you, secure your
|
|
214
216
|
account now*, its button saying **Secure my account**; in the text part each
|
|
215
|
-
line of the summary is its label
|
|
217
|
+
line of the summary is one line, its label then its value — `Device Firefox
|
|
218
|
+
on macOS` — with no blank line between rows. `welcome` has the brand in
|
|
216
219
|
its heading — "Welcome to Acme" — and the recipient's name in its subject,
|
|
217
220
|
filled at send time like the body; its button says **Get started**.
|
|
218
221
|
|
package/docs/roadmap.md
CHANGED
|
@@ -46,6 +46,14 @@ Nothing between releases.
|
|
|
46
46
|
|
|
47
47
|
Newest first; from the first release on, the package's CHANGELOG holds every one.
|
|
48
48
|
|
|
49
|
+
- **A readable summary and a location in words, v0.9.1.** Built with
|
|
50
|
+
`@nxgt/mail-config` 1.0.2 and `@nxgt/mail-presets` 1.1.1, the text part of
|
|
51
|
+
`newSignIn` gives each row of its summary on one line — `Device Firefox on
|
|
52
|
+
macOS` — with no blank line between rows, where it split each into a label
|
|
53
|
+
line and a value line. A new sign-in sent without `location` says
|
|
54
|
+
"Unknown" — `Location Unknown`, `Lieu Inconnu` in French — in the
|
|
55
|
+
recipient's locale, where it showed `—`.
|
|
56
|
+
|
|
49
57
|
- **The new sign-in notice, v0.9.0.** `newSignIn(to, { device, time,
|
|
50
58
|
location? })`, built from `@nxgt/mail-presets` 1.1.0's `new-sign-in` in
|
|
51
59
|
English and French — "New sign-in to your account", which device, where
|
package/docs/troubleshooting.md
CHANGED
|
@@ -346,7 +346,8 @@ if (event.type === 'user.emailChanged' && event.formerEmail != null) {
|
|
|
346
346
|
time must be a string` are the second argument missing, or its `time` given
|
|
347
347
|
as the session's `Date`: pass the device as you describe it and the time as
|
|
348
348
|
text. `janusMail.newSignIn: location must be a string` is a location lookup's
|
|
349
|
-
`null`: leave `location` out, and the e-mail
|
|
349
|
+
`null`: leave `location` out, and the e-mail says "Unknown" in
|
|
350
|
+
the recipient's locale. `janusMail.newSignIn:
|
|
350
351
|
email must be a string` is the `user.newDeviceSignedIn` event itself given
|
|
351
352
|
as the recipient — read the user first.
|
|
352
353
|
|
|
@@ -769,7 +770,7 @@ Also, without `exactOptionalPropertyTypes` in your tsconfig:
|
|
|
769
770
|
|
|
770
771
|
On `newSignIn`'s `location`: a geo-IP lookup's answer, `null` when it found
|
|
771
772
|
nothing, passed as it is. `location` is optional: leave it out, and the
|
|
772
|
-
e-mail
|
|
773
|
+
e-mail says "Unknown" — "Inconnu" in French:
|
|
773
774
|
|
|
774
775
|
```ts
|
|
775
776
|
await mail.newSignIn(to, { device, time, ...(city === null ? {} : { location: city }) });
|
package/mails/en/new-sign-in.txt
CHANGED
|
@@ -8,14 +8,9 @@ Hello {{ name }},
|
|
|
8
8
|
|
|
9
9
|
Your account was signed in from a device we had not seen.
|
|
10
10
|
|
|
11
|
-
Device
|
|
12
|
-
{{
|
|
13
|
-
|
|
14
|
-
Location
|
|
15
|
-
{{ location }}
|
|
16
|
-
|
|
17
|
-
Time
|
|
18
|
-
{{ time }}
|
|
11
|
+
Device {{ device }}
|
|
12
|
+
Location {{ location }}
|
|
13
|
+
Time {{ time }}
|
|
19
14
|
|
|
20
15
|
If this was you, there is nothing to do. If this was not you, secure your account now.
|
|
21
16
|
|
package/mails/fr/new-sign-in.txt
CHANGED
|
@@ -8,14 +8,9 @@ Bonjour {{ name }},
|
|
|
8
8
|
|
|
9
9
|
Votre compte a été utilisé depuis un appareil que nous ne connaissions pas.
|
|
10
10
|
|
|
11
|
-
Appareil
|
|
12
|
-
{{
|
|
13
|
-
|
|
14
|
-
Lieu
|
|
15
|
-
{{ location }}
|
|
16
|
-
|
|
17
|
-
Heure
|
|
18
|
-
{{ time }}
|
|
11
|
+
Appareil {{ device }}
|
|
12
|
+
Lieu {{ location }}
|
|
13
|
+
Heure {{ time }}
|
|
19
14
|
|
|
20
15
|
Si c'était vous, vous n'avez rien à faire. Si ce n'était pas vous, sécurisez votre compte dès maintenant.
|
|
21
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/janus-mail",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "The e-mails of @nxgt/janus's flows — e-mail verification, password reset, sign-in code, sign-in link, step-up code, password changed, e-mail changed, two-factor enabled and disabled, recovery code used, new sign-in, welcome — rendered in English and French from a prebuilt Maizzle build, with your brand, sent through any @nxgt/mail transport",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"@maizzle/framework": "6.1.7",
|
|
55
55
|
"@maizzle/tailwindcss": "1.5.6",
|
|
56
56
|
"@formatjs/icu-messageformat-parser": "3.5.20",
|
|
57
|
-
"@nxgt/janus": "^0.
|
|
57
|
+
"@nxgt/janus": "^0.18.0",
|
|
58
58
|
"@nxgt/mail": "1.0.1",
|
|
59
|
-
"@nxgt/mail-config": "1.0.
|
|
59
|
+
"@nxgt/mail-config": "1.0.2",
|
|
60
60
|
"@nxgt/mail-i18n": "1.0.1",
|
|
61
|
-
"@nxgt/mail-presets": "1.1.
|
|
61
|
+
"@nxgt/mail-presets": "1.1.1",
|
|
62
62
|
"@nxgt/mail-ui": "1.0.1",
|
|
63
63
|
"@types/bun": "^1.4.2",
|
|
64
64
|
"vue": "3.5.43",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"zod": "^4.6.5"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@nxgt/janus": "^0.
|
|
69
|
+
"@nxgt/janus": "^0.18.0",
|
|
70
70
|
"@nxgt/mail": ">=0.1.0 <2",
|
|
71
71
|
"typescript": "^6.0.3"
|
|
72
72
|
}
|