@alxia/react-router 0.28.2 → 0.29.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.
package/README.md CHANGED
@@ -1268,8 +1268,8 @@ From `@alxia/react-router/session` (`react-router` and `/errors`' files are its
1268
1268
  | `serializeCookie(name, value, { maxAge, path?, secure })`, `readCookie(request, name)`, `secondsUntil(expiresAt, now?)`, `SerializeOptions` | the bytes `sessionCookies` writes, for the cookies of your own; a name that is not an RFC 6265 token throws a `TypeError` |
1269
1269
  | `signInFlow({ cookies, errors, json, revoke, attemptsLeft?, paths?, clear?, unavailable?, codes?, endedParam? })`, `SignInFlow`, `SignInFlowOptions`, `SignInFlowWithoutSecondFactorOptions`, `SignInFlowBase`, `SecondFactorSteps` | the server side of the sign-in pages; `attemptsLeft` and cookies with a `challenge` go together (giving only one is a compile error, and a `TypeError` at runtime), and without them the flow is `SignInFlow<L, C, false>`, with no `readCodeInput`, `codeStep`, `codeRefusal` or `attemptsLeft`. It also exposes what it was built with (`cookies`, `errors`, `json`, `attemptsLeft`, `unavailable(language)`, `clear()`) and `guard(request)`, the check an app's own POST step runs first: `nextParam`, `signInRedirect`, `landing`, `landReplacing` (revokes the session the browser held), `signInStep` (a same-site JSON post only; an API refusal as the form's message and status, an unreachable API as a 503), `readCodeInput`, `codeStep`, `codeRefusal` (with the tries left) (these four and `attemptsLeft`: with a second factor), `revokeSession`, `signOut` (JSON and same-origin only; it clears the challenge cookie too), `viewer` (`null` for a 401, `undefined` when unknown) and `requireViewer` (throws the sign-in redirect); `revoke(token, request, context)` gets the caller context (`C`, inferred from the annotation of `revoke`'s third parameter) that `signOut`, `revokeSession`, `landReplacing` and `signInStep` take as `context` |
1270
1270
  | `SignInAnswer`, `SignInFormError`, `SignInStayed`, `SignInCodes` | what a step answers (`signedIn`, `secondFactor` or `other`), a form step's answer when it stays on the page, and the `codes` option (`invalidCode`, `challengeOver`) |
1271
- | `stepUpSteps({ signIn, spent, locked?, wording?, codes? })`, `StepUpSteps`, `StepUpStepsOptions`, `StepUpCall` | a step-up for a route's action, reading the flow's `errors`, `json` and `attemptsLeft`, each step taking `{ request, language }` and refusing a post that is not a same-site JSON one: `request(run, { request, language })` answers the challenge and how it is confirmed (a throttled mail or any 429 is `error: 'throttled'` with `retryAfter`), `confirm(run, { request, language, via? })` answers `error: 'invalid'` with the tries left (and `locked: true` for an app or recovery code with none left), `expired` or `failed`; `request` and `confirm` answer `throttled` with `retryAfter` on any 429 (on `confirm` the challenge and its tries stay, `locked: false`); and `isStepUpRequired(error)`; and `route(run, { request, language })`, the whole action of one resource route that any page posts `request-step-up` and `confirm-step-up` to (`run.request()`, `run.confirm({ challenge, code })`; `StepUpRun`) |
1272
- | `StepUpCodes`, `StepUpStayed`, `INVALID_CODE`, `CHALLENGE_OVER`, `MAIL_THROTTLED`, `STEP_UP_REQUIRED`, `STEP_UP_OVER` | the `codes` option (`invalidCode`, `challengeOver`, `stepUpRequired`, `mailThrottled`), a step's answer that stays on the page, and janus's default codes, which an app can extend |
1271
+ | `stepUpSteps({ signIn, spent, locked?, wording?, codes?, onSignedOut? })`, `StepUpSteps`, `StepUpStepsOptions`, `StepUpCall` | a step-up for a route's action, reading the flow's `errors`, `json` and `attemptsLeft`, each step taking `{ request, language }` and refusing a post that is not a same-site JSON one: `request(run, { request, language })` answers the challenge and how it is confirmed (a throttled mail or any 429 is `error: 'throttled'` with `retryAfter`), `confirm(run, { request, language, via? })` answers `error: 'invalid'` with the tries left (and `locked: true` for an app or recovery code with none left), `expired` or `failed`; `request` and `confirm` answer `throttled` with `retryAfter` on any 429 (on `confirm` the challenge and its tries stay, `locked: false`); and `isStepUpRequired(error)`; and `route(run, { request, language })`, the whole action of one resource route that any page posts `request-step-up` and `confirm-step-up` to (`run.request()`, `run.confirm({ challenge, code })`; `StepUpRun`); with `onSignedOut: 'sign-in'` it throws the sign-in redirect for a signed-out user (an `ApiError` with `codes.unauthenticated`, default `'UNAUTHENTICATED'`; from `request` also a bare 401 response, from `confirm` never), `next` being a same-site `Referer`'s page, else the route's own path, while a wrong code stays a refusal |
1272
+ | `StepUpCodes`, `StepUpStayed`, `INVALID_CODE`, `CHALLENGE_OVER`, `MAIL_THROTTLED`, `UNAUTHENTICATED`, `STEP_UP_REQUIRED`, `STEP_UP_OVER` | the `codes` option (`invalidCode`, `challengeOver`, `stepUpRequired`, `mailThrottled`, `unauthenticated`), a step's answer that stays on the page, and janus's default codes, which an app can extend |
1273
1273
  | `authLinks({ signIn, codes?, wording?, start?, resetDone?, invalidState? })`, `AuthLinks`, `AuthLinksOptions`, `AuthLinksCodes` | the pages a mail's link opens, over the flow's cookies, errors and json: `linkArgs`, `spendToken(run, { request, language, path, states, fields? })`, `answerOf`, `landByLink` (`context?`), `afterReset(request, { context? })` (clears the session, the challenge and the flow's cookies), `requestLink(run, { request, language })` (a wait, whose `codes.mailThrottled` is one code or a list of them, answers `throttled: true` and `retryAfter` when the API gives the seconds; `wording` words every refusal that is not a field's), `statePath` and `ended` |
1274
1274
  | `Spent`, `SpendOptions`, `LinkStayed`, `RequestLinkAnswer` | their types |
1275
1275
  | `TOKEN_PAGE_HEADERS` | `Referrer-Policy: no-referrer` and `X-Robots-Tag: noindex, nofollow`, for a page whose URL carries a token |
@@ -4,4 +4,6 @@ export declare const INVALID_CODE = "CODE_INVALID";
4
4
  export declare const CHALLENGE_OVER: readonly ["TOKEN_UNKNOWN", "TOKEN_SPENT", "TOKEN_EXPIRED"];
5
5
  /** `@nxgt/janus`'s code for a mail the API holds back: a link or a code asked for too often. */
6
6
  export declare const MAIL_THROTTLED = "MAIL_THROTTLED";
7
+ /** The code of an API answer for no session, or a dead one. */
8
+ export declare const UNAUTHENTICATED = "UNAUTHENTICATED";
7
9
  //# sourceMappingURL=codes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../../src/session/codes.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,qFAAqF;AACrF,eAAO,MAAM,cAAc,4DAIjB,CAAC;AAEX,gGAAgG;AAChG,eAAO,MAAM,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../../src/session/codes.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,qFAAqF;AACrF,eAAO,MAAM,cAAc,4DAIjB,CAAC;AAEX,gGAAgG;AAChG,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,+DAA+D;AAC/D,eAAO,MAAM,eAAe,oBAAoB,CAAC"}
@@ -4,7 +4,7 @@
4
4
  * cookie. The subpath may import `react-router` and `/errors`' files,
5
5
  * nothing else.
6
6
  */
7
- export { CHALLENGE_OVER, INVALID_CODE, MAIL_THROTTLED } from './codes';
7
+ export { CHALLENGE_OVER, INVALID_CODE, MAIL_THROTTLED, UNAUTHENTICATED, } from './codes';
8
8
  export { type ChallengeCookies, type CookieSession, type NoChallengeCookies, type SessionCookies, type SessionCookiesBase, type SessionCookiesOptions, type SessionCookiesWithoutChallengeOptions, sessionCookies, } from './cookies';
9
9
  export type { SecondFactorSteps, SignInAnswer, SignInCodes, SignInFlow, SignInFlowBase, SignInFlowOptions, SignInFlowWithoutSecondFactorOptions, SignInFormError, SignInStayed, } from './flow-types';
10
10
  export { TOKEN_PAGE_HEADERS } from './link-token';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qCAAqC,EAC1C,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,oCAAoC,EACpC,eAAe,EACf,YAAY,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EACX,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,KAAK,GACL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EACN,UAAU,EACV,KAAK,gBAAgB,EACrB,YAAY,EACZ,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,kBAAkB,GAClB,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,cAAc,EACd,YAAY,EACZ,cAAc,EACd,eAAe,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qCAAqC,EAC1C,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,oCAAoC,EACpC,eAAe,EACf,YAAY,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EACX,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,KAAK,GACL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EACN,UAAU,EACV,KAAK,gBAAgB,EACrB,YAAY,EACZ,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,kBAAkB,GAClB,MAAM,iBAAiB,CAAC"}
@@ -24,6 +24,7 @@ var CHALLENGE_OVER = [
24
24
  "TOKEN_EXPIRED"
25
25
  ];
26
26
  var MAIL_THROTTLED = "MAIL_THROTTLED";
27
+ var UNAUTHENTICATED = "UNAUTHENTICATED";
27
28
  // src/session/serialize.ts
28
29
  var TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
29
30
  var PATH = /^\/[^;\x00-\x1f\x7f]*$/;
@@ -566,6 +567,61 @@ var STEP_UP_OVER = [
566
567
  "SECOND_FACTOR_NOT_ENROLLED"
567
568
  ];
568
569
 
570
+ // src/session/step-up-signed-out.ts
571
+ function isSignedOut(error, unauthenticated, from) {
572
+ if (error instanceof Response)
573
+ return from === "request" && error.status === 401;
574
+ return isApiErrorLike2(error) && error.code === unauthenticated;
575
+ }
576
+ function cameFrom(request) {
577
+ const referer = request.headers.get("referer");
578
+ if (referer) {
579
+ try {
580
+ const from = new URL(referer);
581
+ if (from.origin === new URL(request.url).origin) {
582
+ return new Request(from, { headers: request.headers });
583
+ }
584
+ } catch {}
585
+ }
586
+ return request;
587
+ }
588
+ async function signingOut({
589
+ signIn,
590
+ unauthenticated,
591
+ run,
592
+ request
593
+ }, route) {
594
+ let signedOut = false;
595
+ const watched = {
596
+ request: async () => {
597
+ try {
598
+ return await run.request();
599
+ } catch (error) {
600
+ signedOut ||= isSignedOut(error, unauthenticated, "request");
601
+ throw error;
602
+ }
603
+ },
604
+ confirm: async (input) => {
605
+ try {
606
+ return await run.confirm(input);
607
+ } catch (error) {
608
+ signedOut ||= isSignedOut(error, unauthenticated, "confirm");
609
+ throw error;
610
+ }
611
+ }
612
+ };
613
+ const redirect = () => signIn.signInRedirect(cameFrom(request));
614
+ let answer;
615
+ try {
616
+ answer = await route(watched);
617
+ } catch (error) {
618
+ throw signedOut ? redirect() : error;
619
+ }
620
+ if (signedOut)
621
+ throw redirect();
622
+ return answer;
623
+ }
624
+
569
625
  // src/session/step-up.ts
570
626
  function resolve2(steps) {
571
627
  const invalidCode = steps.codes?.invalidCode ?? INVALID_CODE;
@@ -579,7 +635,8 @@ function resolve2(steps) {
579
635
  invalidCode,
580
636
  challengeOver,
581
637
  stepUpRequired: steps.codes?.stepUpRequired ?? STEP_UP_REQUIRED,
582
- mailThrottled: steps.codes?.mailThrottled ?? MAIL_THROTTLED
638
+ mailThrottled: steps.codes?.mailThrottled ?? MAIL_THROTTLED,
639
+ unauthenticated: steps.codes?.unauthenticated ?? UNAUTHENTICATED
583
640
  };
584
641
  }
585
642
  function worded2({ steps }, error, language) {
@@ -670,6 +727,17 @@ async function confirmStep(context, run, { request, language, via }) {
670
727
  async function routeStep(context, run, call) {
671
728
  const { json } = context.steps.signIn;
672
729
  samesitePost(json, call.request);
730
+ if (context.steps.onSignedOut !== "sign-in")
731
+ return routeIntent(context, run, call);
732
+ return signingOut({
733
+ signIn: context.steps.signIn,
734
+ unauthenticated: context.unauthenticated,
735
+ run,
736
+ request: call.request
737
+ }, (watched) => routeIntent(context, watched, call));
738
+ }
739
+ async function routeIntent(context, run, call) {
740
+ const { json } = context.steps.signIn;
673
741
  const body = await json.readJson(call.request);
674
742
  if (body?.intent === "request-step-up") {
675
743
  return requestStep(context, () => run.request(), call);
@@ -700,6 +768,7 @@ export {
700
768
  STEP_UP_OVER,
701
769
  STEP_UP_REQUIRED,
702
770
  TOKEN_PAGE_HEADERS,
771
+ UNAUTHENTICATED,
703
772
  authLinks,
704
773
  readCookie,
705
774
  secondsUntil,
@@ -709,5 +778,5 @@ export {
709
778
  stepUpSteps
710
779
  };
711
780
 
712
- //# debugId=8A737E1A0227A8CE64756E2164756E21
781
+ //# debugId=E4F6B37F2041D5B464756E2164756E21
713
782
  //# sourceMappingURL=index.js.map
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/session/codes.ts", "../src/session/serialize.ts", "../src/session/cookies.ts", "../src/session/link-token.ts", "../src/session/guard.ts", "../src/session/links.ts", "../src/session/link-land.ts", "../src/session/land.ts", "../src/session/second-factor.ts", "../src/session/step.ts", "../src/session/viewer.ts", "../src/session/sign-in.ts", "../src/session/step-up.ts", "../src/session/step-up-codes.ts"],
3
+ "sources": ["../src/session/codes.ts", "../src/session/serialize.ts", "../src/session/cookies.ts", "../src/session/link-token.ts", "../src/session/guard.ts", "../src/session/links.ts", "../src/session/link-land.ts", "../src/session/land.ts", "../src/session/second-factor.ts", "../src/session/step.ts", "../src/session/viewer.ts", "../src/session/sign-in.ts", "../src/session/step-up.ts", "../src/session/step-up-codes.ts", "../src/session/step-up-signed-out.ts"],
4
4
  "sourcesContent": [
5
- "/** `@nxgt/janus`'s code for a wrong second-factor or step-up code. */\nexport const INVALID_CODE = 'CODE_INVALID';\n\n/** `@nxgt/janus`'s codes for a challenge that is gone: unknown, spent or expired. */\nexport const CHALLENGE_OVER = [\n\t'TOKEN_UNKNOWN',\n\t'TOKEN_SPENT',\n\t'TOKEN_EXPIRED',\n] as const;\n\n/** `@nxgt/janus`'s code for a mail the API holds back: a link or a code asked for too often. */\nexport const MAIL_THROTTLED = 'MAIL_THROTTLED';\n",
5
+ "/** `@nxgt/janus`'s code for a wrong second-factor or step-up code. */\nexport const INVALID_CODE = 'CODE_INVALID';\n\n/** `@nxgt/janus`'s codes for a challenge that is gone: unknown, spent or expired. */\nexport const CHALLENGE_OVER = [\n\t'TOKEN_UNKNOWN',\n\t'TOKEN_SPENT',\n\t'TOKEN_EXPIRED',\n] as const;\n\n/** `@nxgt/janus`'s code for a mail the API holds back: a link or a code asked for too often. */\nexport const MAIL_THROTTLED = 'MAIL_THROTTLED';\n\n/** The code of an API answer for no session, or a dead one. */\nexport const UNAUTHENTICATED = 'UNAUTHENTICATED';\n",
6
6
  "/**\n * The bytes of a cookie, and the reading of one: `Name=v; Max-Age=n; Path=/;\n * HttpOnly[; Secure]; SameSite=Lax`, in this order, so a session set by an\n * app before it adopted this package is still read after, and the other way\n * round.\n */\n\nexport interface SerializeOptions {\n\t/** Seconds; floored, and never below 0 (0 removes the cookie, and so does a value that is not finite). */\n\treadonly maxAge: number;\n\t/** `/` by default. */\n\treadonly path?: string | undefined;\n\t/** Adds `Secure`. Required: it is never read from the environment. */\n\treadonly secure: boolean;\n}\n\n// RFC 6265 `token`: what a cookie name may be made of.\nconst TOKEN = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n// A path of the site: no `;` to open another attribute, no control character.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: that is the point\nconst PATH = /^\\/[^;\\x00-\\x1f\\x7f]*$/;\n\n/** Whether `name` can name a cookie (an RFC 6265 token). */\nexport const isCookieName = (name: string): boolean => TOKEN.test(name);\n/** Whether `path` can be a cookie's `Path`: absolute, no `;`, no control character. */\nexport const isCookiePath = (path: string): boolean => PATH.test(path);\n\n/**\n * A `Set-Cookie` value: always `HttpOnly` and `SameSite=Lax`, `Secure` when\n * asked. A name or a path that could open another attribute throws a\n * `TypeError`; a `maxAge` that is not finite is 0.\n */\nexport function serializeCookie(\n\tname: string,\n\tvalue: string,\n\t{ maxAge, path = '/', secure }: SerializeOptions,\n): string {\n\tif (!isCookieName(name)) {\n\t\tthrow new TypeError(\n\t\t\t`serializeCookie(): the name ${JSON.stringify(name)} is not a cookie name (an RFC 6265 token).`,\n\t\t);\n\t}\n\tif (!isCookiePath(path)) {\n\t\tthrow new TypeError(\n\t\t\t`serializeCookie(): the path ${JSON.stringify(path)} is not a cookie path: it must start with \"/\" and hold no \";\" or control character.`,\n\t\t);\n\t}\n\treturn [\n\t\t`${name}=${encodeURIComponent(value)}`,\n\t\t`Max-Age=${Number.isFinite(maxAge) ? Math.max(0, Math.floor(maxAge)) : 0}`,\n\t\t`Path=${path}`,\n\t\t'HttpOnly',\n\t\t...(secure ? ['Secure'] : []),\n\t\t'SameSite=Lax',\n\t].join('; ');\n}\n\n/**\n * A cookie of the request: the first one of that name that is not empty,\n * decoded; `null` when there is none, or when it is not valid percent-encoding.\n */\nexport function readCookie(request: Request, name: string): string | null {\n\tfor (const pair of request.headers.get('cookie')?.split(';') ?? []) {\n\t\tconst index = pair.indexOf('=');\n\t\tif (index < 0 || pair.slice(0, index).trim() !== name) continue;\n\t\tconst raw = pair.slice(index + 1).trim();\n\t\tif (!raw) continue;\n\t\ttry {\n\t\t\treturn decodeURIComponent(raw);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** An instant as milliseconds; 0 when it is not a date. */\nexport function millisOf(at: string | Date): number {\n\tconst time = typeof at === 'string' ? Date.parse(at) : at.getTime();\n\treturn Number.isNaN(time) ? 0 : time;\n}\n\n/** Seconds from `now` until `expiresAt`: 0 when past or unreadable. */\nexport function secondsUntil(\n\texpiresAt: string | Date,\n\tnow: number = Date.now(),\n): number {\n\tconst end = millisOf(expiresAt);\n\treturn end === 0 ? 0 : Math.max(0, (end - now) / 1000);\n}\n",
7
7
  "import {\n\tisCookieName,\n\tisCookiePath,\n\tmillisOf,\n\treadCookie,\n\tsecondsUntil,\n\tserializeCookie,\n} from './serialize';\n\n/** What every `sessionCookies` call takes, with or without a second factor. */\nexport interface SessionCookiesBaseOptions {\n\t/**\n\t * The base name of the session cookie, e.g. `'my-app_session'`. With\n\t * `secure`, the cookie is named `__Host-my-app_session`.\n\t */\n\treadonly session: string;\n\t/**\n\t * The app is served over HTTPS. Required, and never read from the\n\t * environment: pass `!import.meta.env.DEV`. `false` drops `Secure` and the\n\t * prefixes (Safari drops a `Secure` cookie over `http://localhost`).\n\t */\n\treadonly secure: boolean;\n}\n\n/** The options of an app with no second factor: no challenge cookie. */\nexport interface SessionCookiesWithoutChallengeOptions\n\textends SessionCookiesBaseOptions {\n\treadonly challenge?: undefined;\n\treadonly challengePath?: undefined;\n\treadonly challengeSeconds?: undefined;\n}\n\n/** The options of an app with a second factor: the challenge cookie's name is given. */\nexport interface SessionCookiesOptions extends SessionCookiesBaseOptions {\n\t/**\n\t * The base name of the second-factor challenge's cookie. With `secure`, it\n\t * is named `__Secure-<name>`.\n\t */\n\treadonly challenge: string;\n\t/** Where the browser sends the challenge. `'/sign-in'` by default. */\n\treadonly challengePath?: string | undefined;\n\t/** The most the challenge lives. 300, `@nxgt/janus`'s lifetime, by default. */\n\treadonly challengeSeconds?: number | undefined;\n}\n\n/** What the session cookie holds: the token, and the expiry (ms) it was last set to. */\nexport interface CookieSession {\n\treadonly token: string;\n\treadonly expiresAt: number;\n}\n\n/** The cookies every BFF has: the session's. */\nexport interface SessionCookiesBase {\n\t/** The names as sent, prefixes included. */\n\treadonly names: { readonly session: string };\n\t/** The session cookie of the request; `null` when absent or not `<ms>.<token>`. */\n\tread(request: Request): CookieSession | null;\n\t/** The session token of the request, or `null`. */\n\ttoken(request: Request): string | null;\n\t/** A `Set-Cookie` value keeping `token` until `expiresAt`. */\n\tcommit(token: string, expiresAt: string | Date, now?: number): string;\n\t/** A `Set-Cookie` value removing the session cookie. */\n\tdestroy(): string;\n\t/** The `Set-Cookie` header that keeps the cookie as long as the session lives; empty when the expiry did not move, or is absent or not a date. */\n\trefreshed(\n\t\tsession: CookieSession,\n\t\texpiresAt: string | Date | null,\n\t): HeadersInit;\n\t/**\n\t * What a signed-out visit of the sign-in page sets: a dead session's\n\t * cookie when `deadSession` (and, with a second factor, the challenge\n\t * cleared blind: a client navigation fetches `/sign-in.data`, which the\n\t * cookie's path does not match, so the request never shows it).\n\t */\n\tsignInPageHeaders(deadSession: boolean): Headers;\n}\n\n/** The challenge cookie's helpers, present when `challenge` was given. */\nexport interface ChallengeCookies {\n\treadonly names: { readonly challenge: string };\n\t/** The challenge cookie of the request, or `null`. */\n\tchallengeOf(request: Request): string | null;\n\t/** A `Set-Cookie` value keeping the challenge for the code page. */\n\tcommitChallenge(\n\t\tchallenge: string,\n\t\texpiresAt?: string | Date | null,\n\t\tnow?: number,\n\t): string;\n\t/** A `Set-Cookie` value removing the challenge. */\n\tdestroyChallenge(): string;\n}\n\n/**\n * The cookies `sessionCookies` returns: with the challenge helpers (the\n * default) when `challenge` was given, `SessionCookies<false>` without.\n */\nexport type SessionCookies<WithChallenge extends boolean = true> =\n\tWithChallenge extends true\n\t\t? SessionCookiesBase & ChallengeCookies\n\t\t: SessionCookiesBase & NoChallengeCookies;\n\n/**\n * What `SessionCookies<false>` says of the challenge helpers: they are\n * absent. Declared as `undefined` so that a set with a challenge is not\n * assignable to it (a flow with no second factor refuses one at compile time).\n */\nexport interface NoChallengeCookies {\n\treadonly challengeOf?: undefined;\n\treadonly commitChallenge?: undefined;\n\treadonly destroyChallenge?: undefined;\n}\n\nconst PREFIX = /^__(?:Host|Secure)-/;\n\nfunction checkName(label: string, name: string): void {\n\tif (!isCookieName(name)) {\n\t\tthrow new TypeError(\n\t\t\t`sessionCookies(): the ${label} name ${JSON.stringify(name)} is not a cookie name (an RFC 6265 token: letters, digits and ! # $ % & ' * + - . ^ _ \\` | ~). Pass a name such as \"my-app_${label}\".`,\n\t\t);\n\t}\n\tif (PREFIX.test(name)) {\n\t\tthrow new TypeError(\n\t\t\t`sessionCookies(): the ${label} name ${JSON.stringify(name)} already carries a prefix. Pass the base name: the package adds __Host- (session) or __Secure- (challenge) when secure is true.`,\n\t\t);\n\t}\n}\n\n/**\n * The cookies of a BFF's session and, when `challenge` is given, of its\n * second-factor challenge. Without `challenge`, the result has no challenge\n * helpers and the type says so.\n *\n * @example\n * const cookies = sessionCookies({ session: 'my-app_session', secure: true });\n */\nexport function sessionCookies(\n\toptions: SessionCookiesOptions,\n): SessionCookies<true>;\nexport function sessionCookies(\n\toptions: SessionCookiesWithoutChallengeOptions,\n): SessionCookies<false>;\nexport function sessionCookies(\n\toptions: SessionCookiesBaseOptions & {\n\t\treadonly challenge?: string | undefined;\n\t\treadonly challengePath?: string | undefined;\n\t\treadonly challengeSeconds?: number | undefined;\n\t},\n): SessionCookies<boolean>;\nexport function sessionCookies(\n\toptions: SessionCookiesBaseOptions & {\n\t\treadonly challenge?: string | undefined;\n\t\treadonly challengePath?: string | undefined;\n\t\treadonly challengeSeconds?: number | undefined;\n\t},\n): SessionCookies<boolean> {\n\tconst {\n\t\tsecure,\n\t\tchallengePath = '/sign-in',\n\t\tchallengeSeconds = 5 * 60,\n\t} = options;\n\tcheckName('session', options.session);\n\tif (options.challenge !== undefined)\n\t\tcheckName('challenge', options.challenge);\n\tif (!Number.isInteger(challengeSeconds) || challengeSeconds <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`sessionCookies(): challengeSeconds must be a positive integer; got ${String(challengeSeconds)}.`,\n\t\t);\n\t}\n\tif (!isCookiePath(challengePath)) {\n\t\tthrow new TypeError(\n\t\t\t`sessionCookies(): challengePath must start with \"/\" and hold no \";\" or control character; got ${JSON.stringify(challengePath)}.`,\n\t\t);\n\t}\n\t// `__Host-` holds only with `Path=/` and no `Domain`: the session cookie\n\t// sets neither option.\n\tconst session = secure ? `__Host-${options.session}` : options.session;\n\tconst challengeName =\n\t\toptions.challenge === undefined\n\t\t\t? undefined\n\t\t\t: secure\n\t\t\t\t? `__Secure-${options.challenge}`\n\t\t\t\t: options.challenge;\n\tconst clear = (name: string, path?: string) =>\n\t\tserializeCookie(name, '', { maxAge: 0, secure, ...(path && { path }) });\n\n\tconst read = (request: Request): CookieSession | null => {\n\t\tconst value = readCookie(request, session);\n\t\tconst dot = value?.indexOf('.') ?? -1;\n\t\tif (!value || dot < 1) return null;\n\t\tconst digits = value.slice(0, dot);\n\t\tconst expiresAt = Number(digits);\n\t\tconst token = value.slice(dot + 1);\n\t\treturn token && /^\\d+$/.test(digits) && Number.isSafeInteger(expiresAt)\n\t\t\t? { token, expiresAt }\n\t\t\t: null;\n\t};\n\t// The value is `<expiry ms>.<token>`: the expiry only tells a later request\n\t// whether the API moved it, so the cookie is set again then. It is never\n\t// trusted: the API alone decides whether a session is valid.\n\tconst commit = (token: string, expiresAt: string | Date, now?: number) =>\n\t\tserializeCookie(session, `${millisOf(expiresAt)}.${token}`, {\n\t\t\tmaxAge: secondsUntil(expiresAt, now),\n\t\t\tsecure,\n\t\t});\n\n\tconst base: SessionCookiesBase = {\n\t\tnames: { session },\n\t\tread,\n\t\ttoken: (request) => read(request)?.token ?? null,\n\t\tcommit,\n\t\tdestroy: () => clear(session),\n\t\trefreshed(current, expiresAt) {\n\t\t\t// An expiry that is not a date is garbage, not an end: keep the cookie.\n\t\t\tconst end = expiresAt ? millisOf(expiresAt) : 0;\n\t\t\tif (!expiresAt || end === 0 || end === current.expiresAt) return {};\n\t\t\treturn { 'Set-Cookie': commit(current.token, expiresAt) };\n\t\t},\n\t\tsignInPageHeaders(deadSession) {\n\t\t\tconst headers = new Headers();\n\t\t\tif (challengeName) {\n\t\t\t\theaders.append('Set-Cookie', clear(challengeName, challengePath));\n\t\t\t}\n\t\t\tif (deadSession) headers.append('Set-Cookie', clear(session));\n\t\t\treturn headers;\n\t\t},\n\t};\n\tif (challengeName === undefined) return base;\n\tconst challengeCookies: ChallengeCookies = {\n\t\tnames: { challenge: challengeName },\n\t\tchallengeOf: (request) => readCookie(request, challengeName),\n\t\tcommitChallenge: (value, expiresAt, now) =>\n\t\t\tserializeCookie(challengeName, value, {\n\t\t\t\tmaxAge: Math.min(\n\t\t\t\t\tchallengeSeconds,\n\t\t\t\t\texpiresAt ? secondsUntil(expiresAt, now) : challengeSeconds,\n\t\t\t\t),\n\t\t\t\tpath: challengePath,\n\t\t\t\tsecure,\n\t\t\t}),\n\t\tdestroyChallenge: () => clear(challengeName, challengePath),\n\t};\n\treturn {\n\t\t...base,\n\t\t...challengeCookies,\n\t\tnames: { session, challenge: challengeName },\n\t};\n}\n\n/** The `Set-Cookie` values that clear the challenge: none without a second factor. */\nexport function challengeCleared(cookies: SessionCookies<boolean>): string[] {\n\treturn cookies.destroyChallenge ? [cookies.destroyChallenge()] : [];\n}\n",
8
8
  "import { data, replace } from 'react-router';\nimport { isApiErrorLike } from '../errors/api-error';\nimport type { FormErrors } from '../errors/form-errors';\nimport type { InferOutput, StandardSchemaV1 } from '../errors/standard-schema';\nimport { samesitePost } from './guard';\nimport type {\n\tLinkStayed,\n\tLinksContext,\n\tSpendOptions,\n\tSpent,\n} from './link-types';\nimport { sitePath } from './model/site-path';\n\n/**\n * The response headers of a page a mail's link opens, whose URL carries a\n * token: no `Referer` sends it to another site (its fonts included), and\n * no search engine keeps it.\n */\nexport const TOKEN_PAGE_HEADERS = {\n\t'Referrer-Policy': 'no-referrer',\n\t'X-Robots-Tag': 'noindex, nofollow',\n} as const;\n\n/** A token page's path with no query or fragment, or a `TypeError` naming `call`. */\nconst pathOf = (path: string, call: string): string =>\n\tsitePath(path, { label: `${call}: a token page's path` });\n\nexport const statePath = (path: string, state: string): string =>\n\t`${pathOf(path, 'statePath()')}?${new URLSearchParams({ state })}`;\n\n/** `headers`, with the token page's own on top. */\nexport function withTokenHeaders(headers?: HeadersInit): Headers {\n\tconst merged = new Headers(headers);\n\tfor (const [name, value] of Object.entries(TOKEN_PAGE_HEADERS)) {\n\t\tmerged.set(name, value);\n\t}\n\treturn merged;\n}\n\n/** A redirect replacing the current history entry: the token's, so Back never opens it again. */\nexport const stateRedirect = (\n\tpath: string,\n\tstate: string,\n\theaders?: HeadersInit,\n): Response =>\n\treplace(statePath(path, state), { headers: withTokenHeaders(headers) });\n\nconst isTokenIssue = (issue: {\n\treadonly path?:\n\t\t| readonly (PropertyKey | { readonly key: PropertyKey })[]\n\t\t| undefined;\n}) => {\n\tconst first = issue.path?.[0];\n\treturn (typeof first === 'object' ? first.key : first) === 'token';\n};\n\nexport async function linkArgs<S extends StandardSchemaV1>(\n\t{ json }: Pick<LinksContext<string>, 'json'>,\n\tinvalidState: string,\n\tschema: S,\n\trequest: Request,\n\tpath: string,\n): Promise<InferOutput<S>> {\n\tsamesitePost(json, request);\n\tpathOf(path, 'linkArgs()');\n\tconst body = await json.readJson(request);\n\tconst result = await schema['~standard'].validate(body);\n\tif (!result.issues) return result.value as InferOutput<S>;\n\t// A token the API would refuse anyway (a link cut or padded on its way)\n\t// ends as an unknown one does; anything else is a bad request.\n\tif (result.issues.some(isTokenIssue)) {\n\t\tthrow stateRedirect(path, invalidState);\n\t}\n\tthrow data('Bad link request', { status: 400 });\n}\n\nexport async function spendToken<L extends string, C, T>(\n\toptions: LinksContext<L, C>,\n\trun: () => Promise<T>,\n\t{ request, language, path, states, fields: shown = [] }: SpendOptions<L>,\n): Promise<Spent<T>> {\n\tconst { errors } = options;\n\tsamesitePost(options.json, request);\n\tpathOf(path, 'spendToken()');\n\ttry {\n\t\treturn { ok: true, value: await run() };\n\t} catch (error) {\n\t\tconst refusal = errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst { message, status } = refusal;\n\t\tif (isApiErrorLike(error)) {\n\t\t\tconst state = error.code ? states[error.code] : undefined;\n\t\t\tif (state) return { ok: false, response: stateRedirect(path, state) };\n\t\t\tconst fields = errors.fieldErrors(error, language);\n\t\t\tconst named = Object.keys(fields);\n\t\t\t// A refusal under a field the page does not show would say nothing.\n\t\t\tif (named.length && named.every((field) => shown.includes(field))) {\n\t\t\t\treturn { ok: false, refusal: { fieldErrors: fields }, status };\n\t\t\t}\n\t\t}\n\t\treturn { ok: false, refusal: { formError: message }, status };\n\t}\n}\n\nexport const answerOf = (\n\tspent: Exclude<Spent<unknown>, { ok: true }>,\n): Response | LinkStayed =>\n\t'response' in spent\n\t\t? spent.response\n\t\t: data<FormErrors>(spent.refusal, { status: spent.status });\n",
@@ -14,10 +14,11 @@
14
14
  "import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n} from '../errors/api-error';\nimport type {\n\tCodeWording,\n\tFlowContext,\n\tSignInAnswer,\n\tSignInFlow,\n\tSignInFlowOptions,\n\tSignInFormError,\n\tSignInStayed,\n} from './flow-types';\nimport { samesitePost } from './guard';\nimport { landReplacing } from './land';\n\n/**\n * A refused code's message, with the tries left when the API counts them;\n * `undefined` when the challenge is over (gone, or no try left and no\n * `whenNone` to say instead) and the user must sign in again.\n */\nexport function codeRefusal<L extends string>(\n\t{ options, invalidCode, challengeOver }: CodeWording<L>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n\twhenNone?: string,\n): string | undefined {\n\tif (error.code !== invalidCode) {\n\t\treturn error.code && challengeOver.includes(error.code)\n\t\t\t? undefined\n\t\t\t: options.errors.apiErrorMessage(error, language);\n\t}\n\tconst message = options.errors.apiErrorMessage(error, language);\n\tconst count = attemptsLeftOf(error);\n\tif (count === undefined) return message;\n\tif (count === 0) {\n\t\treturn whenNone === undefined ? undefined : `${message} ${whenNone}`;\n\t}\n\treturn `${message} ${options.attemptsLeft(count, language)}`;\n}\n\n/** What a sign-in says when the API cannot be reached. */\nexport const unavailableMessage = <L extends string>(\n\t{ unavailable, errors }: Pick<SignInFlowOptions<L>, 'unavailable' | 'errors'>,\n\tlanguage: L,\n): string => unavailable?.(language) ?? errors.unavailableMessage(language);\n\n/**\n * Runs a sign-in step and redirects where its answer leads, a new session\n * replacing the browser's (`landReplacing`). A refusal is the form's\n * message (a wrong password, a lock with its delay); an unreachable API\n * says `unavailable`, with a 503.\n */\nexport async function signInStep<L extends string, C, T extends object>(\n\tflow: FlowContext<L, C>,\n\trun: () => Promise<SignInAnswer>,\n\t{\n\t\trequest,\n\t\tlanguage,\n\t\tnext,\n\t\textra,\n\t\trefused,\n\t\tcontext,\n\t}: Parameters<SignInFlow<L, C>['signInStep']>[1] & { extra: T },\n): Promise<Response | SignInStayed<T>> {\n\tconst { errors, json } = flow.options;\n\t// A cross-site post must never sign in or revoke (headers only).\n\tsamesitePost(json, request);\n\tconst stay = (formError: string, status: number) =>\n\t\tdata<SignInFormError<T>>({ ...extra, formError }, { status });\n\tconst unreachable = () =>\n\t\tstay(unavailableMessage(flow.options, language), 503);\n\tlet answer: SignInAnswer;\n\ttry {\n\t\tanswer = await run();\n\t} catch (error) {\n\t\tconst refusal = errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\t// An API it cannot reach: sign-in's own words.\n\t\tif (!isApiErrorLike(error)) return unreachable();\n\t\tconst own = refused?.(error);\n\t\tif (own instanceof Response) return own;\n\t\treturn stay(own ?? refusal.message, refusal.status);\n\t}\n\treturn (\n\t\t(await landReplacing(flow, answer, next, { request, context })) ??\n\t\tunreachable()\n\t);\n}\n",
15
15
  "import { redirect } from 'react-router';\nimport { isApiErrorLike } from '../errors/api-error';\nimport { nextOf } from '../errors/page-path';\nimport { routeError } from '../errors/route-error';\nimport { challengeCleared } from './cookies';\nimport type { FlowContext } from './flow-types';\nimport { revokeSession } from './land';\nimport { safeNext, signInPath } from './model';\n\n/** The `next` a sign-in page was opened with, safe to redirect to. */\nexport const nextParam = (request: Request): string =>\n\tsafeNext(new URL(request.url).searchParams.get('next'));\n\n/**\n * The sign-in page, coming back to this request's page afterwards, with the\n * session cookie cleared: what a page answers without a (live) session. A\n * request that carried a session cookie says it ended when `endedParam` is\n * set.\n */\nexport function signInRedirect<L extends string, C>(\n\t{ options, paths }: FlowContext<L, C>,\n\trequest: Request,\n): Response {\n\tconst { endedParam, cookies } = options;\n\tconst query =\n\t\tendedParam && cookies.read(request) ? { [endedParam]: '1' } : undefined;\n\treturn redirect(\n\t\tsignInPath(nextOf(request.url), {\n\t\t\tpath: paths.signIn,\n\t\t\t...(query && { query }),\n\t\t}),\n\t\t{ headers: { 'Set-Cookie': cookies.destroy() } },\n\t);\n}\n\n/**\n * For the sign-in pages: the viewer when the cookie holds a live session,\n * `null` when the API refuses it (a 401), `undefined` without a cookie or\n * when the API cannot tell.\n */\nexport async function viewer<L extends string, C, V>(\n\t{ options }: FlowContext<L, C>,\n\trequest: Request,\n\tread: (token: string) => Promise<V | null>,\n\ttoken: string | null | undefined = options.cookies.token(request),\n): Promise<V | null | undefined> {\n\tif (!token) return undefined;\n\ttry {\n\t\treturn await read(token);\n\t} catch (error) {\n\t\treturn isApiErrorLike(error) && error.status === 401 ? null : undefined;\n\t}\n}\n\n/**\n * The signed-in viewer, else the sign-in redirect. Its `headers` move the\n * cookie's expiry to the session's when the API moved it.\n */\nexport async function requireViewer<L extends string, C, V>(\n\tcontext: FlowContext<L, C>,\n\trequest: Request,\n\tread: (token: string) => Promise<V | null>,\n\texpiresAt: (viewer: V) => string | null,\n): Promise<{ viewer: V; headers: HeadersInit }> {\n\tconst session = context.options.cookies.read(request);\n\tif (!session) throw signInRedirect(context, request);\n\tlet found: V | null;\n\ttry {\n\t\tfound = await read(session.token);\n\t} catch (error) {\n\t\tif (isApiErrorLike(error) && error.status === 401) {\n\t\t\tthrow signInRedirect(context, request);\n\t\t}\n\t\tthrow routeError(error);\n\t}\n\tif (!found) throw signInRedirect(context, request);\n\treturn {\n\t\tviewer: found,\n\t\theaders: context.options.cookies.refreshed(session, expiresAt(found)),\n\t};\n}\n\n/**\n * Ends the session and goes to the sign-in page (`?signed-out=1`), or to\n * `to`. The body is read as JSON first: JSON and same-origin only, so\n * another site cannot sign the user out.\n */\nexport async function signOut<L extends string, C>(\n\tflow: FlowContext<L, C>,\n\trequest: Request,\n\t{\n\t\tto,\n\t\tcontext,\n\t}: {\n\t\treadonly to?: string | undefined;\n\t\treadonly context?: C | undefined;\n\t} = {},\n): Promise<Response> {\n\tconst { options, paths } = flow;\n\tawait options.json.readJson(request);\n\tawait revokeSession(flow, request, { context });\n\tconst headers = new Headers();\n\theaders.append('Set-Cookie', options.cookies.destroy());\n\tfor (const cookie of challengeCleared(options.cookies)) {\n\t\theaders.append('Set-Cookie', cookie);\n\t}\n\tfor (const cookie of options.clear?.() ?? []) {\n\t\theaders.append('Set-Cookie', cookie);\n\t}\n\treturn redirect(\n\t\tto === undefined ? `${paths.signIn}?signed-out=1` : safeNext(to),\n\t\t{ headers },\n\t);\n}\n",
16
16
  "import { hasSiteCheck } from '../errors/same-site';\nimport { CHALLENGE_OVER, INVALID_CODE } from './codes';\nimport type {\n\tFlowContext,\n\tSignInFlow,\n\tSignInFlowBase,\n\tSignInFlowOptions,\n\tSignInFlowWithoutSecondFactorOptions,\n} from './flow-types';\nimport { samesitePost } from './guard';\nimport { landing, landReplacing, revokeSession } from './land';\nimport { SIGN_IN_PATHS, type SignInPaths } from './model';\nimport { sitePath } from './model/site-path';\nimport { codeStep, readCodeInput } from './second-factor';\nimport { codeRefusal, signInStep, unavailableMessage } from './step';\nimport {\n\tnextParam,\n\trequireViewer,\n\tsignInRedirect,\n\tsignOut,\n\tviewer,\n} from './viewer';\n\nfunction resolve<L extends string, C>(\n\toptions: SignInFlowOptions<L, C> | SignInFlowWithoutSecondFactorOptions<L, C>,\n): FlowContext<L, C> {\n\tif (\n\t\t(options.attemptsLeft === undefined) !==\n\t\t!options.cookies.commitChallenge\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'signInFlow(): a second factor needs both the challenge cookie (sessionCookies({ challenge })) and attemptsLeft; without one, give neither.',\n\t\t);\n\t}\n\tconst paths: SignInPaths = { ...SIGN_IN_PATHS, ...options.paths };\n\tfor (const key of ['signIn', 'secondFactor'] as const) {\n\t\tsitePath(paths[key], { label: `signInFlow(): paths.${key}` });\n\t}\n\tif (!hasSiteCheck(options.json)) {\n\t\tthrow new TypeError(\n\t\t\t\"signInFlow(): json must come from jsonActions(), which carries the site check every step runs; this object has none (a hand-made double?). Pass the app's jsonActions({ origin }) instance, or a spread copy of it.\",\n\t\t);\n\t}\n\tconst invalidCode = options.codes?.invalidCode ?? INVALID_CODE;\n\tconst challengeOver = options.codes?.challengeOver ?? CHALLENGE_OVER;\n\tif (challengeOver.includes(invalidCode)) {\n\t\tthrow new TypeError(\n\t\t\t`signInFlow(): the code ${JSON.stringify(invalidCode)} is both the wrong-code code (codes.invalidCode) and in codes.challengeOver. A wrong code that leaves tries cannot end the challenge.`,\n\t\t);\n\t}\n\treturn { options, paths, invalidCode, challengeOver };\n}\n\n/**\n * The server side of a BFF's sign-in, over the cookies, the app's\n * `createApiErrors` and its `jsonActions`: where an answer lands, the form\n * steps with their refusals, the second factor, the viewer and sign-out.\n * Built once, beside the app's cookies; it speaks `@nxgt/janus`'s words\n * (`signedIn`, `secondFactor`, `CODE_INVALID`) and the app maps its API's.\n *\n * @example\n * export const signIn = signInFlow({\n * \tcookies, errors, json,\n * \trevoke: (token, request, caller?: Caller) =>\n * \t\texecute(SignOutMutation, {}, { token, ...caller }),\n * \tattemptsLeft: (count, language) => t('auth.attempts-left', { count }, language),\n * });\n */\nexport function signInFlow<L extends string, C = undefined>(\n\toptions: SignInFlowOptions<L, C>,\n): SignInFlow<L, C, true>;\nexport function signInFlow<L extends string, C = undefined>(\n\toptions: SignInFlowWithoutSecondFactorOptions<L, C>,\n): SignInFlow<L, C, false>;\nexport function signInFlow<L extends string, C = undefined>(\n\toptions: SignInFlowOptions<L, C> | SignInFlowWithoutSecondFactorOptions<L, C>,\n): SignInFlow<L, C, boolean> {\n\tconst context = resolve(options);\n\tconst { options: o } = context;\n\tconst base: SignInFlowBase<L, C, boolean> = {\n\t\tcookies: o.cookies,\n\t\terrors: o.errors,\n\t\tjson: o.json,\n\t\tunavailable: (language) => unavailableMessage(o, language),\n\t\tclear: () => o.clear?.() ?? [],\n\t\tguard: (request) => samesitePost(o.json, request),\n\t\tnextParam,\n\t\tsignInRedirect: (request) => signInRedirect(context, request),\n\t\tlanding: (answer, next) => landing(context, answer, next),\n\t\tlandReplacing: (answer, next, o) => landReplacing(context, answer, next, o),\n\t\tsignInStep: (run, o) => signInStep(context, run, o),\n\t\trevokeSession: (request, o) => revokeSession(context, request, o),\n\t\tsignOut: (request, o) => signOut(context, request, o),\n\t\tviewer: (request, read, token) => viewer(context, request, read, token),\n\t\trequireViewer: (request, read, expiresAt) =>\n\t\t\trequireViewer(context, request, read, expiresAt),\n\t};\n\tif (!o.attemptsLeft) return base as SignInFlow<L, C, false>;\n\tconst wording = { ...context, options: o };\n\treturn {\n\t\t...base,\n\t\tattemptsLeft: o.attemptsLeft,\n\t\tcodeRefusal: (error, language, whenNone) =>\n\t\t\tcodeRefusal(wording, error, language, whenNone),\n\t\treadCodeInput: (request) => readCodeInput(context, request),\n\t\tcodeStep,\n\t} as SignInFlow<L, C, true>;\n}\n",
17
- "import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n\tretryAfterOf,\n} from '../errors/api-error';\nimport { INVALID_CODE, MAIL_THROTTLED } from './codes';\nimport type { CodeWording } from './flow-types';\nimport { samesitePost } from './guard';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n\tStepUpVia,\n} from './model';\nimport { codeRefusal } from './step';\nimport { STEP_UP_OVER, STEP_UP_REQUIRED } from './step-up-codes';\nimport type {\n\tStepUpRun,\n\tStepUpStayed,\n\tStepUpSteps,\n\tStepUpStepsOptions,\n} from './step-up-types';\n\ntype Refused = Extract<StepUpConfirmAnswer, { ok: false }>;\n\ninterface StepUpContext<L extends string, C> extends CodeWording<L> {\n\treadonly steps: StepUpStepsOptions<L, C>;\n\treadonly stepUpRequired: string;\n\treadonly mailThrottled: string;\n}\n\nfunction resolve<L extends string, C>(\n\tsteps: StepUpStepsOptions<L, C>,\n): StepUpContext<L, C> {\n\tconst invalidCode = steps.codes?.invalidCode ?? INVALID_CODE;\n\tconst challengeOver = steps.codes?.challengeOver ?? STEP_UP_OVER;\n\tif (challengeOver.includes(invalidCode)) {\n\t\tthrow new TypeError(\n\t\t\t`stepUpSteps(): the code ${JSON.stringify(invalidCode)} is both the wrong-code code (codes.invalidCode) and in codes.challengeOver. A wrong code that leaves tries cannot end the challenge.`,\n\t\t);\n\t}\n\treturn {\n\t\toptions: steps.signIn,\n\t\tsteps,\n\t\tinvalidCode,\n\t\tchallengeOver,\n\t\tstepUpRequired: steps.codes?.stepUpRequired ?? STEP_UP_REQUIRED,\n\t\tmailThrottled: steps.codes?.mailThrottled ?? MAIL_THROTTLED,\n\t};\n}\n\n/** The refusal's message: the app's own wording, else `errors`'. */\nfunction worded<L extends string, C>(\n\t{ steps }: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n): string {\n\treturn (\n\t\tsteps.wording?.(error, language) ??\n\t\tsteps.signIn.errors.apiErrorMessage(error, language)\n\t);\n}\n\n/** A code the API refused. With none left, a mailed one is over and an app's is locked. */\nfunction refusedCode<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tvia: StepUpVia | undefined,\n\tlanguage: L,\n): Omit<Refused, 'ok' | 'intent'> {\n\tconst { steps } = context;\n\tconst attemptsLeft = attemptsLeftOf(error);\n\tif (attemptsLeft === 0 && via !== 'secondFactor') {\n\t\treturn {\n\t\t\terror: 'expired',\n\t\t\tattemptsLeft,\n\t\t\tlocked: false,\n\t\t\tmessage: steps.spent(language),\n\t\t};\n\t}\n\tconst locked = attemptsLeft === 0;\n\tconst message =\n\t\tcodeRefusal(\n\t\t\tcontext,\n\t\t\terror,\n\t\t\tlanguage,\n\t\t\tlocked ? steps.locked?.(language) : undefined,\n\t\t) ?? steps.signIn.errors.apiErrorMessage(error, language);\n\treturn {\n\t\terror: 'invalid',\n\t\t...(attemptsLeft === undefined ? {} : { attemptsLeft }),\n\t\tlocked,\n\t\tmessage,\n\t};\n}\n\n/** The mail throttle's code, or any 429: a rate limit asks to wait, whatever its code. */\nfunction isThrottle<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n): boolean {\n\treturn error.status === 429 || error.code === context.mailThrottled;\n}\n\nasync function requestStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: Parameters<StepUpSteps<L>['request']>[0],\n\t{ request, language }: Parameters<StepUpSteps<L>['request']>[1],\n): Promise<StepUpRequestAnswer | StepUpStayed<StepUpRequestAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'request-step-up';\n\ttry {\n\t\tconst { challenge, via } = await run();\n\t\treturn { ok: true, intent, challenge, via };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst api = isApiErrorLike(error);\n\t\tconst message = api ? worded(context, error, language) : refusal.message;\n\t\tconst throttled = api && isThrottle(context, error);\n\t\tconst retryAfter = throttled ? retryAfterOf(error) : undefined;\n\t\treturn data<StepUpRequestAnswer>(\n\t\t\t{\n\t\t\t\tok: false,\n\t\t\t\tintent,\n\t\t\t\terror: throttled ? 'throttled' : 'failed',\n\t\t\t\tmessage,\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t},\n\t\t\t{ status: refusal.status },\n\t\t);\n\t}\n}\n\nasync function confirmStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: () => Promise<unknown>,\n\t{ request, language, via }: Parameters<StepUpSteps<L>['confirm']>[1],\n): Promise<StepUpConfirmAnswer | StepUpStayed<StepUpConfirmAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'confirm-step-up';\n\ttry {\n\t\tawait run();\n\t\treturn { ok: true, intent };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst stay = (\n\t\t\tfailure: Omit<Refused, 'ok' | 'intent'>,\n\t\t): StepUpStayed<StepUpConfirmAnswer> =>\n\t\t\tdata<StepUpConfirmAnswer>(\n\t\t\t\t{ ok: false, intent, ...failure },\n\t\t\t\t{ status: refusal.status },\n\t\t\t);\n\t\tconst failed = (message: string) =>\n\t\t\tstay({ error: 'failed' satisfies StepUpError, locked: false, message });\n\t\tif (!isApiErrorLike(error)) return failed(refusal.message);\n\t\tif (error.status === 429) {\n\t\t\tconst retryAfter = retryAfterOf(error);\n\t\t\treturn stay({\n\t\t\t\terror: 'throttled',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage: worded(context, error, language),\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t});\n\t\t}\n\t\tif (error.code === context.invalidCode) {\n\t\t\treturn stay(refusedCode(context, error, via, language));\n\t\t}\n\t\tif (error.code && context.challengeOver.includes(error.code)) {\n\t\t\treturn stay({\n\t\t\t\terror: 'expired',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage: context.steps.spent(language),\n\t\t\t});\n\t\t}\n\t\treturn failed(worded(context, error, language));\n\t}\n}\n\nasync function routeStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: StepUpRun,\n\tcall: Parameters<StepUpSteps<L>['request']>[1],\n) {\n\tconst { json } = context.steps.signIn;\n\tsamesitePost(json, call.request);\n\tconst body = (await json.readJson(call.request)) as {\n\t\tintent?: unknown;\n\t\tchallenge?: unknown;\n\t\tcode?: unknown;\n\t\tvia?: unknown;\n\t} | null;\n\tif (body?.intent === 'request-step-up') {\n\t\treturn requestStep(context, () => run.request(), call);\n\t}\n\tif (\n\t\tbody?.intent === 'confirm-step-up' &&\n\t\ttypeof body.challenge === 'string' &&\n\t\ttypeof body.code === 'string'\n\t) {\n\t\tconst { challenge, code } = body;\n\t\tconst via =\n\t\t\tbody.via === 'email' || body.via === 'secondFactor'\n\t\t\t\t? body.via\n\t\t\t\t: undefined;\n\t\treturn confirmStep(context, () => run.confirm({ challenge, code }), {\n\t\t\t...call,\n\t\t\tvia,\n\t\t});\n\t}\n\tthrow data('Not a step-up intent', { status: 400 });\n}\n\n/**\n * The server side of a BFF's step-up: `request` and `confirm` answer the\n * page's fetcher with `StepUpRequestAnswer` and `StepUpConfirmAnswer`, which\n * `stepUpReducer` takes as they are. It speaks `@nxgt/janus`'s words\n * (`CODE_INVALID`, `TOKEN_*`, `STEP_UP_REQUIRED`); the app maps the rest.\n *\n * @example\n * const stepUp = stepUpSteps({\n * \terrors,\n * \tattemptsLeft: (count, language) => t('code.attempts-left', { count }, language),\n * \tspent: (language) => t('step-up.spent', {}, language),\n * \tlocked: (language) => t('step-up.locked', {}, language),\n * });\n */\nexport function stepUpSteps<L extends string, C = undefined>(\n\toptions: StepUpStepsOptions<L, C>,\n): StepUpSteps<L> {\n\tconst context = resolve(options);\n\treturn {\n\t\trequest: (run, o) => requestStep(context, run, o),\n\t\tconfirm: (run, o) => confirmStep(context, run, o),\n\t\troute: (run, o) => routeStep(context, run, o),\n\t\tisStepUpRequired: (error) =>\n\t\t\tisApiErrorLike(error) && error.code === context.stepUpRequired,\n\t};\n}\n",
18
- "import { CHALLENGE_OVER } from './codes';\n\n/** `@nxgt/janus`'s code for a mutation that needs a recent step-up. */\nexport const STEP_UP_REQUIRED = 'STEP_UP_REQUIRED';\n\n/**\n * The codes that end a step-up's challenge: unknown, spent, expired or stale,\n * and a second factor that changed since the request (`SECOND_FACTOR_ACTIVE`,\n * `SECOND_FACTOR_NOT_ENROLLED`). The user asks again.\n */\nexport const STEP_UP_OVER = [\n\t...CHALLENGE_OVER,\n\t'TOKEN_STALE',\n\t'SECOND_FACTOR_ACTIVE',\n\t'SECOND_FACTOR_NOT_ENROLLED',\n] as const;\n"
17
+ "import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n\tretryAfterOf,\n} from '../errors/api-error';\nimport { INVALID_CODE, MAIL_THROTTLED, UNAUTHENTICATED } from './codes';\nimport type { CodeWording } from './flow-types';\nimport { samesitePost } from './guard';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n\tStepUpVia,\n} from './model';\nimport { codeRefusal } from './step';\nimport { STEP_UP_OVER, STEP_UP_REQUIRED } from './step-up-codes';\nimport { signingOut } from './step-up-signed-out';\nimport type {\n\tStepUpRun,\n\tStepUpStayed,\n\tStepUpSteps,\n\tStepUpStepsOptions,\n} from './step-up-types';\n\ntype Refused = Extract<StepUpConfirmAnswer, { ok: false }>;\n\ninterface StepUpContext<L extends string, C> extends CodeWording<L> {\n\treadonly steps: StepUpStepsOptions<L, C>;\n\treadonly stepUpRequired: string;\n\treadonly mailThrottled: string;\n\treadonly unauthenticated: string;\n}\n\nfunction resolve<L extends string, C>(\n\tsteps: StepUpStepsOptions<L, C>,\n): StepUpContext<L, C> {\n\tconst invalidCode = steps.codes?.invalidCode ?? INVALID_CODE;\n\tconst challengeOver = steps.codes?.challengeOver ?? STEP_UP_OVER;\n\tif (challengeOver.includes(invalidCode)) {\n\t\tthrow new TypeError(\n\t\t\t`stepUpSteps(): the code ${JSON.stringify(invalidCode)} is both the wrong-code code (codes.invalidCode) and in codes.challengeOver. A wrong code that leaves tries cannot end the challenge.`,\n\t\t);\n\t}\n\treturn {\n\t\toptions: steps.signIn,\n\t\tsteps,\n\t\tinvalidCode,\n\t\tchallengeOver,\n\t\tstepUpRequired: steps.codes?.stepUpRequired ?? STEP_UP_REQUIRED,\n\t\tmailThrottled: steps.codes?.mailThrottled ?? MAIL_THROTTLED,\n\t\tunauthenticated: steps.codes?.unauthenticated ?? UNAUTHENTICATED,\n\t};\n}\n\n/** The refusal's message: the app's own wording, else `errors`'. */\nfunction worded<L extends string, C>(\n\t{ steps }: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n): string {\n\treturn (\n\t\tsteps.wording?.(error, language) ??\n\t\tsteps.signIn.errors.apiErrorMessage(error, language)\n\t);\n}\n\n/** A code the API refused. With none left, a mailed one is over and an app's is locked. */\nfunction refusedCode<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n\tvia: StepUpVia | undefined,\n\tlanguage: L,\n): Omit<Refused, 'ok' | 'intent'> {\n\tconst { steps } = context;\n\tconst attemptsLeft = attemptsLeftOf(error);\n\tif (attemptsLeft === 0 && via !== 'secondFactor') {\n\t\treturn {\n\t\t\terror: 'expired',\n\t\t\tattemptsLeft,\n\t\t\tlocked: false,\n\t\t\tmessage: steps.spent(language),\n\t\t};\n\t}\n\tconst locked = attemptsLeft === 0;\n\tconst message =\n\t\tcodeRefusal(\n\t\t\tcontext,\n\t\t\terror,\n\t\t\tlanguage,\n\t\t\tlocked ? steps.locked?.(language) : undefined,\n\t\t) ?? steps.signIn.errors.apiErrorMessage(error, language);\n\treturn {\n\t\terror: 'invalid',\n\t\t...(attemptsLeft === undefined ? {} : { attemptsLeft }),\n\t\tlocked,\n\t\tmessage,\n\t};\n}\n\n/** The mail throttle's code, or any 429: a rate limit asks to wait, whatever its code. */\nfunction isThrottle<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\terror: ApiErrorLike,\n): boolean {\n\treturn error.status === 429 || error.code === context.mailThrottled;\n}\n\nasync function requestStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: Parameters<StepUpSteps<L>['request']>[0],\n\t{ request, language }: Parameters<StepUpSteps<L>['request']>[1],\n): Promise<StepUpRequestAnswer | StepUpStayed<StepUpRequestAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'request-step-up';\n\ttry {\n\t\tconst { challenge, via } = await run();\n\t\treturn { ok: true, intent, challenge, via };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst api = isApiErrorLike(error);\n\t\tconst message = api ? worded(context, error, language) : refusal.message;\n\t\tconst throttled = api && isThrottle(context, error);\n\t\tconst retryAfter = throttled ? retryAfterOf(error) : undefined;\n\t\treturn data<StepUpRequestAnswer>(\n\t\t\t{\n\t\t\t\tok: false,\n\t\t\t\tintent,\n\t\t\t\terror: throttled ? 'throttled' : 'failed',\n\t\t\t\tmessage,\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t},\n\t\t\t{ status: refusal.status },\n\t\t);\n\t}\n}\n\nasync function confirmStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: () => Promise<unknown>,\n\t{ request, language, via }: Parameters<StepUpSteps<L>['confirm']>[1],\n): Promise<StepUpConfirmAnswer | StepUpStayed<StepUpConfirmAnswer>> {\n\tsamesitePost(context.steps.signIn.json, request);\n\tconst intent = 'confirm-step-up';\n\ttry {\n\t\tawait run();\n\t\treturn { ok: true, intent };\n\t} catch (error) {\n\t\tconst refusal = context.steps.signIn.errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\tconst stay = (\n\t\t\tfailure: Omit<Refused, 'ok' | 'intent'>,\n\t\t): StepUpStayed<StepUpConfirmAnswer> =>\n\t\t\tdata<StepUpConfirmAnswer>(\n\t\t\t\t{ ok: false, intent, ...failure },\n\t\t\t\t{ status: refusal.status },\n\t\t\t);\n\t\tconst failed = (message: string) =>\n\t\t\tstay({ error: 'failed' satisfies StepUpError, locked: false, message });\n\t\tif (!isApiErrorLike(error)) return failed(refusal.message);\n\t\tif (error.status === 429) {\n\t\t\tconst retryAfter = retryAfterOf(error);\n\t\t\treturn stay({\n\t\t\t\terror: 'throttled',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage: worded(context, error, language),\n\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t});\n\t\t}\n\t\tif (error.code === context.invalidCode) {\n\t\t\treturn stay(refusedCode(context, error, via, language));\n\t\t}\n\t\tif (error.code && context.challengeOver.includes(error.code)) {\n\t\t\treturn stay({\n\t\t\t\terror: 'expired',\n\t\t\t\tlocked: false,\n\t\t\t\tmessage: context.steps.spent(language),\n\t\t\t});\n\t\t}\n\t\treturn failed(worded(context, error, language));\n\t}\n}\n\nasync function routeStep<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: StepUpRun,\n\tcall: Parameters<StepUpSteps<L>['request']>[1],\n) {\n\tconst { json } = context.steps.signIn;\n\tsamesitePost(json, call.request);\n\tif (context.steps.onSignedOut !== 'sign-in')\n\t\treturn routeIntent(context, run, call);\n\treturn signingOut(\n\t\t{\n\t\t\tsignIn: context.steps.signIn,\n\t\t\tunauthenticated: context.unauthenticated,\n\t\t\trun,\n\t\t\trequest: call.request,\n\t\t},\n\t\t(watched) => routeIntent(context, watched, call),\n\t);\n}\n\nasync function routeIntent<L extends string, C>(\n\tcontext: StepUpContext<L, C>,\n\trun: StepUpRun,\n\tcall: Parameters<StepUpSteps<L>['request']>[1],\n) {\n\tconst { json } = context.steps.signIn;\n\tconst body = (await json.readJson(call.request)) as {\n\t\tintent?: unknown;\n\t\tchallenge?: unknown;\n\t\tcode?: unknown;\n\t\tvia?: unknown;\n\t} | null;\n\tif (body?.intent === 'request-step-up') {\n\t\treturn requestStep(context, () => run.request(), call);\n\t}\n\tif (\n\t\tbody?.intent === 'confirm-step-up' &&\n\t\ttypeof body.challenge === 'string' &&\n\t\ttypeof body.code === 'string'\n\t) {\n\t\tconst { challenge, code } = body;\n\t\tconst via =\n\t\t\tbody.via === 'email' || body.via === 'secondFactor'\n\t\t\t\t? body.via\n\t\t\t\t: undefined;\n\t\treturn confirmStep(context, () => run.confirm({ challenge, code }), {\n\t\t\t...call,\n\t\t\tvia,\n\t\t});\n\t}\n\tthrow data('Not a step-up intent', { status: 400 });\n}\n\n/**\n * The server side of a BFF's step-up: `request` and `confirm` answer the\n * page's fetcher with `StepUpRequestAnswer` and `StepUpConfirmAnswer`, which\n * `stepUpReducer` takes as they are. It speaks `@nxgt/janus`'s words\n * (`CODE_INVALID`, `TOKEN_*`, `STEP_UP_REQUIRED`); the app maps the rest.\n *\n * @example\n * const stepUp = stepUpSteps({\n * \terrors,\n * \tattemptsLeft: (count, language) => t('code.attempts-left', { count }, language),\n * \tspent: (language) => t('step-up.spent', {}, language),\n * \tlocked: (language) => t('step-up.locked', {}, language),\n * });\n */\nexport function stepUpSteps<L extends string, C = undefined>(\n\toptions: StepUpStepsOptions<L, C>,\n): StepUpSteps<L> {\n\tconst context = resolve(options);\n\treturn {\n\t\trequest: (run, o) => requestStep(context, run, o),\n\t\tconfirm: (run, o) => confirmStep(context, run, o),\n\t\troute: (run, o) => routeStep(context, run, o),\n\t\tisStepUpRequired: (error) =>\n\t\t\tisApiErrorLike(error) && error.code === context.stepUpRequired,\n\t};\n}\n",
18
+ "import { CHALLENGE_OVER } from './codes';\n\n/** `@nxgt/janus`'s code for a mutation that needs a recent step-up. */\nexport const STEP_UP_REQUIRED = 'STEP_UP_REQUIRED';\n\n/**\n * The codes that end a step-up's challenge: unknown, spent, expired or stale,\n * and a second factor that changed since the request (`SECOND_FACTOR_ACTIVE`,\n * `SECOND_FACTOR_NOT_ENROLLED`). The user asks again.\n */\nexport const STEP_UP_OVER = [\n\t...CHALLENGE_OVER,\n\t'TOKEN_STALE',\n\t'SECOND_FACTOR_ACTIVE',\n\t'SECOND_FACTOR_NOT_ENROLLED',\n] as const;\n",
19
+ "import { isApiErrorLike } from '../errors/api-error';\nimport type { SignInFlow } from './flow-types';\nimport type { StepUpRun } from './step-up-types';\n\n/**\n * A signed-out user's failure. From `request`, the API's no-session code or a\n * bare 401 response; from `confirm`, the code only: a 401 there is also what a\n * wrong code answers, so a bare one stays a refusal.\n */\nfunction isSignedOut(\n\terror: unknown,\n\tunauthenticated: string,\n\tfrom: 'request' | 'confirm',\n): boolean {\n\tif (error instanceof Response)\n\t\treturn from === 'request' && error.status === 401;\n\treturn isApiErrorLike(error) && error.code === unauthenticated;\n}\n\n/**\n * The request the sign-in redirect comes back to: the same-site `Referer`'s\n * page (the step-up route has none of its own), else the request's own URL.\n * A `Referer` of another origin (port and protocol count), or one that is not\n * a URL, is ignored. Behind a TLS-terminating proxy an `http` `request.url`\n * never matches an `https` `Referer`, so `next` is the route's own path.\n */\nexport function cameFrom(request: Request): Request {\n\tconst referer = request.headers.get('referer');\n\tif (referer) {\n\t\ttry {\n\t\t\tconst from = new URL(referer);\n\t\t\tif (from.origin === new URL(request.url).origin) {\n\t\t\t\treturn new Request(from, { headers: request.headers });\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not a URL: the request's own path.\n\t\t}\n\t}\n\treturn request;\n}\n\n/**\n * Runs `route` over a `run` that notes a signed-out failure, then throws the\n * flow's sign-in redirect in place of whatever the step answered or threw.\n */\nexport async function signingOut<A>(\n\t{\n\t\tsignIn,\n\t\tunauthenticated,\n\t\trun,\n\t\trequest,\n\t}: {\n\t\treadonly signIn: Pick<SignInFlow<string, never>, 'signInRedirect'>;\n\t\treadonly unauthenticated: string;\n\t\treadonly run: StepUpRun;\n\t\treadonly request: Request;\n\t},\n\troute: (watched: StepUpRun) => Promise<A>,\n): Promise<A> {\n\tlet signedOut = false;\n\tconst watched: StepUpRun = {\n\t\trequest: async () => {\n\t\t\ttry {\n\t\t\t\treturn await run.request();\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'request');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tconfirm: async (input) => {\n\t\t\ttry {\n\t\t\t\treturn await run.confirm(input);\n\t\t\t} catch (error) {\n\t\t\t\tsignedOut ||= isSignedOut(error, unauthenticated, 'confirm');\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n\tconst redirect = () => signIn.signInRedirect(cameFrom(request));\n\tlet answer: A;\n\ttry {\n\t\tanswer = await route(watched);\n\t} catch (error) {\n\t\tthrow signedOut ? redirect() : error;\n\t}\n\tif (signedOut) throw redirect();\n\treturn answer;\n}\n"
19
20
  ],
20
- "mappings": "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",
21
- "debugId": "8A737E1A0227A8CE64756E2164756E21",
21
+ "mappings": "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",
22
+ "debugId": "E4F6B37F2041D5B464756E2164756E21",
22
23
  "names": []
23
24
  }
@@ -0,0 +1,21 @@
1
+ import type { SignInFlow } from './flow-types';
2
+ import type { StepUpRun } from './step-up-types';
3
+ /**
4
+ * The request the sign-in redirect comes back to: the same-site `Referer`'s
5
+ * page (the step-up route has none of its own), else the request's own URL.
6
+ * A `Referer` of another origin (port and protocol count), or one that is not
7
+ * a URL, is ignored. Behind a TLS-terminating proxy an `http` `request.url`
8
+ * never matches an `https` `Referer`, so `next` is the route's own path.
9
+ */
10
+ export declare function cameFrom(request: Request): Request;
11
+ /**
12
+ * Runs `route` over a `run` that notes a signed-out failure, then throws the
13
+ * flow's sign-in redirect in place of whatever the step answered or threw.
14
+ */
15
+ export declare function signingOut<A>({ signIn, unauthenticated, run, request, }: {
16
+ readonly signIn: Pick<SignInFlow<string, never>, 'signInRedirect'>;
17
+ readonly unauthenticated: string;
18
+ readonly run: StepUpRun;
19
+ readonly request: Request;
20
+ }, route: (watched: StepUpRun) => Promise<A>): Promise<A>;
21
+ //# sourceMappingURL=step-up-signed-out.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-up-signed-out.d.ts","sourceRoot":"","sources":["../../src/session/step-up-signed-out.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAiBjD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAalD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EACjC,EACC,MAAM,EACN,eAAe,EACf,GAAG,EACH,OAAO,GACP,EAAE;IACF,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACnE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B,EACD,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GACvC,OAAO,CAAC,CAAC,CAAC,CA6BZ"}
@@ -8,6 +8,8 @@ export interface StepUpCodes extends SignInCodes {
8
8
  readonly stepUpRequired?: string | undefined;
9
9
  /** The code of a mail the API holds back (`'MAIL_THROTTLED'`): `request` answers `error: 'throttled'`. Any 429 is throttled too, whatever its code. */
10
10
  readonly mailThrottled?: string | undefined;
11
+ /** The code of an API answer for no session or a dead one (`'UNAUTHENTICATED'`): what `onSignedOut` redirects on. */
12
+ readonly unauthenticated?: string | undefined;
11
13
  }
12
14
  export interface StepUpStepsOptions<L extends string, C = undefined> {
13
15
  /**
@@ -31,6 +33,17 @@ export interface StepUpStepsOptions<L extends string, C = undefined> {
31
33
  */
32
34
  readonly wording?: ((error: ApiErrorLike, language: L) => string | undefined) | undefined;
33
35
  readonly codes?: StepUpCodes | undefined;
36
+ /**
37
+ * What `route` does when the user is signed out. `'sign-in'` redirects to
38
+ * the flow's sign-in page (clearing the session cookie) when `run` fails
39
+ * with `codes.unauthenticated` (`UNAUTHENTICATED`) as an `ApiError`, or, from `request` only, a bare 401 response (from `confirm` a bare 401 stays a refusal, since a wrong code is a 401 too: `run.confirm` must throw an `ApiError` for the API's code refusals);
40
+ * `next` is the page the request came from (a same-site `Referer`, else the
41
+ * route's own path). A wrong or expired code (also a 401 from the API)
42
+ * stays a refusal for the dialog, and a second-factor-required answer is a
43
+ * refusal too, never a redirect of the fetcher. Unset keeps `route` as it
44
+ * was: `run`'s failures are the app's to read.
45
+ */
46
+ readonly onSignedOut?: 'sign-in' | undefined;
34
47
  }
35
48
  /** An answer that stays on the page: the answer, with the API's status. */
36
49
  export type StepUpStayed<T> = ReturnType<typeof data<T>>;
@@ -88,7 +101,8 @@ export interface StepUpSteps<L extends string> {
88
101
  * `{ intent: 'request-step-up' }` and `confirm` for
89
102
  * `{ intent: 'confirm-step-up', challenge, code, via? }`, and answers what
90
103
  * those steps answer. Any other intent, or a confirm with no challenge or
91
- * code, is a 400.
104
+ * code, is a 400. With `onSignedOut: 'sign-in'` a signed-out user is
105
+ * redirected to sign-in (thrown) instead of answered.
92
106
  */
93
107
  route(run: StepUpRun, options: StepUpCall<L>): Promise<StepUpRequestAnswer | StepUpConfirmAnswer | StepUpStayed<StepUpRequestAnswer> | StepUpStayed<StepUpConfirmAnswer>>;
94
108
  /** Whether `error` is the API asking for a step-up first. */
@@ -1 +1 @@
1
- {"version":3,"file":"step-up-types.d.ts","sourceRoot":"","sources":["../../src/session/step-up-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"step-up-types.d.ts","sourceRoot":"","sources":["../../src/session/step-up-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../src/session/step-up.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAGX,WAAW,EACX,kBAAkB,EAClB,MAAM,iBAAiB,CAAC;AAiMzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,EAC1D,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC/B,WAAW,CAAC,CAAC,CAAC,CAShB"}
1
+ {"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../src/session/step-up.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAGX,WAAW,EACX,kBAAkB,EAClB,MAAM,iBAAiB,CAAC;AAsNzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,EAC1D,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC/B,WAAW,CAAC,CAAC,CAAC,CAShB"}
package/docs/README.md CHANGED
@@ -19,7 +19,7 @@ installable and usable offline, wording an API's refusals, the BFF session, a Gr
19
19
  | [Deploying](guide/deploying.md) | running the build with `bun build/server/index.js`, and the Docker image |
20
20
  | [Installable and offline](guide/pwa.md) | making the app installable and usable offline: the subpaths of `@alxia/react-router/pwa`, the service worker (`startWorker`, `/pwa/worker`), its build by `alxia()` or `buildWorker` (`/pwa/build`), its contract and cache names, which requests the worker caches and which responses it stores, the precache list read from a build, or clearing the caches at sign-out |
21
21
  | [An API's refusals](guide/errors.md) | wording a GraphQL API's refusals for the pages: recognising an `ApiError`, the request id, the page a request is for, the catalogue store, the form checks in the API's words, the provider, and the loaders, the error page and the actions that answer with it, the JSON actions with their CSRF check and fetcher hook, calling the API from a loader (`apiCallFailure`), and keeping the catalogue fresh (`@alxia/react-router/errors`) |
22
- | [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
22
+ | [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), the step-up route's signed-out handling (`onSignedOut`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
23
23
  | [Links through React Router](guide/link.md) | `RouterLink`, React Router's `Link` as the link component of a UI library that hands `href` and spreads anchor props; `@alxia/react-router/link` |
24
24
  | [Lists whose state is the URL](guide/lists.md) | a search and filters in the address bar that drop the cursor (`useSearchChange`), a skeleton while the same page reloads (`useSameRouteLoading`), and a load-more button that appends pages by cursor and keeps the rows when one fails (`usePagedRows`); `@alxia/react-router/lists` |
25
25
  | [Subscriptions for a BFF](guide/subscriptions.md) | showing a GraphQL subscription in the browser without giving it the API's token or a way to write a document: a resource route with a map of operation names to the server's documents, the same-site check, the bearer from the session, extra upstream headers, a heartbeat, abort propagation, size limits and a 429 passed through with `retryAfter` (`@alxia/react-router/subscription`) |
@@ -689,6 +689,32 @@ export async function action({ context, request }: Route.ActionArgs) {
689
689
  }
690
690
  ```
691
691
 
692
+ A signed-out user has no page to come back to on that route. Set
693
+ `onSignedOut: 'sign-in'` on `stepUpSteps` and `route` throws the flow's
694
+ sign-in redirect (clearing the session cookie) when `run` fails with an
695
+ `ApiError` whose code is `UNAUTHENTICATED` (`codes.unauthenticated` renames
696
+ it). From `run.request` a bare 401 `Response` counts too; from `run.confirm`
697
+ it does not, since a wrong code is a 401 as well: `run.confirm` must throw an
698
+ `ApiError` for the API's code refusals. `next` is the page of a same-site
699
+ `Referer`; a `Referer` of another origin (port and protocol count) or one
700
+ that is not a URL is ignored and `next` is the route's own path. Behind a
701
+ TLS-terminating proxy an `http` `request.url` never matches an `https`
702
+ `Referer`, so `next` falls back to the route's own path there. A wrong or
703
+ expired code stays a refusal for the dialog, and a second-factor-required
704
+ answer is a refusal, never a redirect of the fetcher. Your caller must
705
+ therefore not redirect on 401 or second-factor-required itself.
706
+
707
+ This replaces the `stepUpSteps({ signIn, spent, locked })` definition above
708
+ and applies to the `stepUp.route(...)` call of the resource route:
709
+
710
+ ```ts
711
+ export const stepUp = stepUpSteps({ signIn, spent, locked, onSignedOut: 'sign-in' });
712
+
713
+ // app/routes/step-up.tsx: a signed-out user is redirected, never answered
714
+ export const action = ({ request }: Route.ActionArgs) =>
715
+ stepUp.route({ request: runRequest, confirm: runConfirm }, { request, language: 'en' });
716
+ ```
717
+
692
718
  `request(run, { request, language })` answers `{ ok: true,
693
719
  intent: 'request-step-up', challenge, via }`. `confirm(run, { request,
694
720
  language, via? })` answers `{ ok: true, intent: 'confirm-step-up' }`. Both
@@ -788,7 +814,9 @@ own can spread either. `invalidCode` in `challengeOver` is a
788
814
  caller that treats every 401 as "the session is dead" and redirects to the
789
815
  sign-in page would sign the user out on the first typo. Make the caller of the
790
816
  step-up's two operations leave a 401 alone, or have it redirect only when the
791
- error's code is `UNAUTHENTICATED`.
817
+ error's code is `UNAUTHENTICATED`. This applies when `onSignedOut` is unset;
818
+ with `onSignedOut: 'sign-in'`, `route()` does it
819
+ ([a signed-out user](#step-up)).
792
820
 
793
821
  ### The state on the page
794
822
 
@@ -2710,7 +2710,7 @@ The user types a wrong code in the step-up dialog and lands on the sign-in page,
2710
2710
 
2711
2711
  **Why:** `@nxgt/janus-graphql` answers `CODE_INVALID` with HTTP 401. A caller that redirects to the sign-in page on any 401 takes the wrong code for a dead session, before `stepUp.confirm` sees the error.
2712
2712
 
2713
- **Fix:** in the app's caller, redirect to sign-in only for a session 401 (`UNAUTHENTICATED`), never for a step-up's `CODE_INVALID`. [Step-up](guide/session.md#call-the-step-up-with-a-caller-that-does-not-sign-out-on-a-401) has the full section.
2713
+ **Fix:** in the app's caller, redirect to sign-in only for a session 401 (`UNAUTHENTICATED`), never for a step-up's `CODE_INVALID`. Or set `onSignedOut: 'sign-in'` on `stepUpSteps`: `route()` then redirects only a signed-out user. [Step-up](guide/session.md#call-the-step-up-with-a-caller-that-does-not-sign-out-on-a-401) has the full section.
2714
2714
 
2715
2715
 
2716
2716
  ### `TypeError: statePath(): a token page's path must be a path of this site with no query or fragment, starting with a single "/"; got ….`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alxia/react-router",
3
- "version": "0.28.2",
3
+ "version": "0.29.0",
4
4
  "description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), a GraphQL subscription relayed to the browser over SSE (`/subscription`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
5
5
  "license": "MIT",
6
6
  "type": "module",