@alxia/react-router 0.24.0 → 0.25.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 +2 -2
- package/dist/errors/code-resolver.d.ts +1 -1
- package/dist/errors/code-resolver.d.ts.map +1 -1
- package/dist/errors/index.js +2 -2
- package/dist/errors/index.js.map +2 -2
- package/dist/session/cookies.d.ts +63 -17
- package/dist/session/cookies.d.ts.map +1 -1
- package/dist/session/flow-types.d.ts +54 -28
- package/dist/session/flow-types.d.ts.map +1 -1
- package/dist/session/index.d.ts +2 -2
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +53 -22
- package/dist/session/index.js.map +7 -7
- package/dist/session/land.d.ts.map +1 -1
- package/dist/session/link-land.d.ts.map +1 -1
- package/dist/session/link-types.d.ts +2 -2
- package/dist/session/link-types.d.ts.map +1 -1
- package/dist/session/sign-in.d.ts +3 -2
- package/dist/session/sign-in.d.ts.map +1 -1
- package/dist/session/viewer.d.ts.map +1 -1
- package/docs/guide/errors.md +7 -4
- package/docs/guide/session.md +26 -1
- package/docs/roadmap.md +2 -2
- package/docs/troubleshooting.md +31 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1238,9 +1238,9 @@ From `@alxia/react-router/session` (`react-router` and `/errors`' files are its
|
|
|
1238
1238
|
|
|
1239
1239
|
| export | |
|
|
1240
1240
|
| --- | --- |
|
|
1241
|
-
| `sessionCookies({ session, challenge
|
|
1241
|
+
| `sessionCookies({ session, challenge?, secure, challengePath?, challengeSeconds? })`, `SessionCookies`, `SessionCookiesOptions`, `SessionCookiesWithoutChallengeOptions`, `SessionCookiesBase`, `ChallengeCookies`, `NoChallengeCookies`, `CookieSession` | the session and, when `challenge` is given, second-factor challenge cookies (without it the result is `SessionCookies<false>`, with no challenge helper on the type), `HttpOnly; SameSite=Lax`, `__Host-` and `__Secure-` when `secure` (required, never read from the environment): `commit(token, expiresAt)`, `read(request)`, `token(request)`, `destroy()`, `refreshed(session, expiresAt)` (a `Set-Cookie` only when the expiry moved), `commitChallenge`, `challengeOf`, `destroyChallenge` (these three: with a second factor), `signInPageHeaders(deadSession)` and `names` (the cookie names as sent, prefixes included); a cookie written by an app's own code in `<expiry ms>.<token>` is read as it is |
|
|
1242
1242
|
| `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` |
|
|
1243
|
-
| `signInFlow({ cookies, errors, json, revoke, attemptsLeft
|
|
1243
|
+
| `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` |
|
|
1244
1244
|
| `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`) |
|
|
1245
1245
|
| `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)` |
|
|
1246
1246
|
| `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 |
|
|
@@ -11,7 +11,7 @@ export type CodeIssueLike = {
|
|
|
11
11
|
readonly expected?: unknown;
|
|
12
12
|
readonly message?: string | undefined;
|
|
13
13
|
};
|
|
14
|
-
/** An API error code (`<module>.errors.<slug
|
|
14
|
+
/** An API error code (`<module>.errors.<slug>`, the module in kebab-case or camelCase), as opposed to a GraphQL one (`BAD_USER_INPUT`). */
|
|
15
15
|
export declare const API_CODE: RegExp;
|
|
16
16
|
export interface ApiCodeResolverOptions<L extends string> {
|
|
17
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-resolver.d.ts","sourceRoot":"","sources":["../../src/errors/code-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"code-resolver.d.ts","sourceRoot":"","sources":["../../src/errors/code-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,CAAC;AAEF,2IAA2I;AAC3I,eAAO,MAAM,QAAQ,QAA6C,CAAC;AAEnE,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,MAAM;IACvD;;;OAGG;IACH,SAAS,CACR,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GACtB,MAAM,CAAC;IACV,mDAAmD;IACnD,QAAQ,IAAI,CAAC,CAAC;IACd,yEAAyE;IACzE,MAAM,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;IAClD,yEAAyE;IACzE,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM;IAChD,SAAS,EAAE,CACV,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KACpB,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;CACrD;AAOD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAC/C,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAChC,eAAe,CAAC,CAAC,CAAC,CAiBpB"}
|
package/dist/errors/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
rememberSiteCheck
|
|
16
16
|
} from "../chunks/index-rgy503w9.js";
|
|
17
17
|
// src/errors/code-resolver.ts
|
|
18
|
-
var API_CODE = /^[a-z-]
|
|
18
|
+
var API_CODE = /^[a-z][a-zA-Z0-9-]*\.errors\.[a-z0-9-]+$/;
|
|
19
19
|
function paramsCode(issue) {
|
|
20
20
|
const code = issue.params?.code;
|
|
21
21
|
return typeof code === "string" ? code : undefined;
|
|
@@ -538,5 +538,5 @@ export {
|
|
|
538
538
|
waitMinutes2 as waitMinutes
|
|
539
539
|
};
|
|
540
540
|
|
|
541
|
-
//# debugId=
|
|
541
|
+
//# debugId=C040A51D1737CFBA64756E2164756E21
|
|
542
542
|
//# sourceMappingURL=index.js.map
|
package/dist/errors/index.js.map
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/errors/code-resolver.ts", "../src/errors/describe-refusal.ts", "../src/errors/fetcher-result.ts", "../src/errors/submit-form.ts", "../src/errors/describe.ts", "../src/errors/api-errors.ts", "../src/errors/log.ts", "../src/errors/call-failure.ts", "../src/errors/catalogue-check.ts", "../src/errors/catalogue-read.ts", "../src/errors/catalogue.ts", "../src/errors/json-actions.ts", "../src/errors/message-values.ts", "../src/errors/messages.ts", "../src/errors/provider.ts", "../src/errors/use-json-fetcher.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { ApiMessages } from './messages';\n\n/** The part of a zod issue a code reads, by shape (`@nxgt/material-core`'s `CodeIssue`). */\nexport type CodeIssueLike = {\n\treadonly code: string;\n\t/** A custom issue's params: `.refine(…, { params: { code } })`. */\n\treadonly params?: Record<string, unknown> | undefined;\n\treadonly input?: unknown;\n\treadonly origin?: string | undefined;\n\treadonly minimum?: unknown;\n\treadonly maximum?: unknown;\n\treadonly expected?: unknown;\n\treadonly message?: string | undefined;\n};\n\n/** An API error code (`<module>.errors.<slug
|
|
5
|
+
"import type { ApiMessages } from './messages';\n\n/** The part of a zod issue a code reads, by shape (`@nxgt/material-core`'s `CodeIssue`). */\nexport type CodeIssueLike = {\n\treadonly code: string;\n\t/** A custom issue's params: `.refine(…, { params: { code } })`. */\n\treadonly params?: Record<string, unknown> | undefined;\n\treadonly input?: unknown;\n\treadonly origin?: string | undefined;\n\treadonly minimum?: unknown;\n\treadonly maximum?: unknown;\n\treadonly expected?: unknown;\n\treadonly message?: string | undefined;\n};\n\n/** An API error code (`<module>.errors.<slug>`, the module in kebab-case or camelCase), as opposed to a GraphQL one (`BAD_USER_INPUT`). */\nexport const API_CODE = /^[a-z][a-zA-Z0-9-]*\\.errors\\.[a-z0-9-]+$/;\n\nexport interface ApiCodeResolverOptions<L extends string> {\n\t/**\n\t * The app's translator, for every key that is not an API code. Method\n\t * syntax: the app's own `Translate<LocaleKey>` is accepted.\n\t */\n\ttranslate(\n\t\tkey: string,\n\t\tcontext?: Readonly<Record<string, unknown>>,\n\t\tlanguage?: L | (() => L),\n\t): string;\n\t/** The page's language, when a call names none. */\n\tlanguage(): L;\n\t/** Which code an issue carries; the issue's `params.code` by default. */\n\tcodeOf?(issue: CodeIssueLike): string | undefined;\n\t/** Whether a key is an API code; `<module>.errors.<slug>` by default. */\n\tisApiCode?(key: string): boolean;\n}\n\n/** What `@nxgt/material`'s `useCodeResolver(schema, resolver)` takes. */\nexport interface ApiCodeResolver<L extends string> {\n\ttranslate: (\n\t\tkey: string,\n\t\tcontext?: Readonly<Record<string, unknown>>,\n\t\tlanguage?: L | (() => L),\n\t) => string;\n\tcodeOf: (issue: CodeIssueLike) => string | undefined;\n}\n\nfunction paramsCode(issue: CodeIssueLike) {\n\tconst code = (issue.params as { code?: unknown } | undefined)?.code;\n\treturn typeof code === 'string' ? code : undefined;\n}\n\n/**\n * The words of what a form's checks ask for: a refinement carrying an API\n * code in `params.code` reads exactly as the API words it (from the\n * catalogue `messages` holds), any other key takes the app's translator, and\n * a code the catalogue lacks comes back as it is, so the form library words\n * the issue with its own locale instead. Both functions are stable: a\n * resolver is made once per schema and language, so build this once, at\n * module scope.\n */\nexport function apiCodeResolver<L extends string>(\n\tmessages: ApiMessages<L>,\n\toptions: ApiCodeResolverOptions<L>,\n): ApiCodeResolver<L> {\n\tconst isApiCode = (key: string) =>\n\t\toptions.isApiCode ? options.isApiCode(key) : API_CODE.test(key);\n\treturn {\n\t\ttranslate(key, context, provideLanguage) {\n\t\t\tif (!isApiCode(key))\n\t\t\t\treturn options.translate(key, context, provideLanguage);\n\t\t\tconst language =\n\t\t\t\ttypeof provideLanguage === 'function'\n\t\t\t\t\t? provideLanguage()\n\t\t\t\t\t: (provideLanguage ?? options.language());\n\t\t\treturn messages.apiMessage(key, context, language) ?? key;\n\t\t},\n\t\tcodeOf(issue) {\n\t\t\treturn options.codeOf ? options.codeOf(issue) : paramsCode(issue);\n\t\t},\n\t};\n}\n",
|
|
6
6
|
"import { isApiErrorLike } from './api-error';\nimport type { ApiErrors } from './api-errors';\n\n/** The API's refusal of `error`, or `undefined` when it is not one. */\nexport function refusalOf<L extends string>(\n\terrors: Pick<ApiErrors<L>, 'apiErrorMessage' | 'unavailableMessage'>,\n\terror: unknown,\n\tlanguage: L,\n): ReturnType<ApiErrors<L>['apiRefusal']> {\n\tif (isApiErrorLike(error)) {\n\t\treturn {\n\t\t\tmessage: errors.apiErrorMessage(error, language),\n\t\t\tstatus: error.status,\n\t\t};\n\t}\n\tif (error instanceof Response && error.status === 503) {\n\t\treturn { message: errors.unavailableMessage(language), status: 503 };\n\t}\n\treturn undefined;\n}\n\n/** The worded message of each field an API error names, by field path. */\nexport function fieldErrorsOf<L extends string>(\n\terrors: Pick<ApiErrors<L>, 'apiErrorMessage' | 'translateCode'>,\n\terror: Parameters<ApiErrors<L>['fieldErrors']>[0],\n\tlanguage: L,\n): ReturnType<ApiErrors<L>['fieldErrors']> {\n\tconst extensions = error.errors[0]?.extensions;\n\tconst fields = Array.isArray(extensions?.fields) ? extensions.fields : [];\n\tif (!fields.length && extensions?.field) {\n\t\treturn { [extensions.field]: errors.apiErrorMessage(error, language) };\n\t}\n\treturn Object.fromEntries(\n\t\tfields.map(({ path, code, message, params }) => [\n\t\t\tpath,\n\t\t\terrors.translateCode(code, message, language, params),\n\t\t]),\n\t);\n}\n",
|
|
7
7
|
"import { data } from 'react-router';\nimport { isApiErrorLike } from './api-error';\nimport type { ApiErrors, ApiRefusal } from './api-errors';\nimport { type RouteErrorOptions, routeError } from './route-error';\n\n/**\n * A fetcher's refusal: the API's (`apiRefusal`), an unreachable API's too,\n * so the page stays where it was. A 401 (the session caller redirects\n * first) or any other failure is thrown, for the error page.\n */\nexport function fetcherRefusal<L extends string>(\n\terrors: Pick<ApiErrors<L>, 'apiRefusal'>,\n\terror: unknown,\n\tlanguage: L,\n\troute?: RouteErrorOptions,\n): ApiRefusal {\n\tconst refusal =\n\t\tisApiErrorLike(error) && error.status === 401\n\t\t\t? undefined\n\t\t\t: errors.apiRefusal(error, language);\n\tif (!refusal) throw routeError(error, route);\n\treturn refusal;\n}\n\n/**\n * Runs the mutation of an action a fetcher posted to: `{ ok: true }` with\n * `about` and the mutation's value, or the refusal (`fetcherRefusal`) as a\n * worded `error`, with its HTTP status, for a toast or a form message.\n */\nexport async function fetcherResult<\n\tL extends string,\n\tAbout extends object,\n\tValue extends object = Record<never, never>,\n>(\n\terrors: Pick<ApiErrors<L>, 'apiRefusal'>,\n\tlanguage: L,\n\tabout: About,\n\trun: () => Promise<Value>,\n\troute?: RouteErrorOptions,\n) {\n\ttry {\n\t\treturn { ok: true as const, ...about, ...(await run()) };\n\t} catch (error) {\n\t\tconst { message, status } = fetcherRefusal(errors, error, language, route);\n\t\treturn data({ ok: false as const, ...about, error: message }, { status });\n\t}\n}\n",
|
|
8
8
|
"import { data } from 'react-router';\nimport { isApiErrorLike } from './api-error';\nimport type { ApiErrors } from './api-errors';\nimport type { FormErrors } from './form-errors';\nimport { type RouteErrorOptions, routeError } from './route-error';\n\n/**\n * Runs a form's mutation. An `ApiError` becomes the form's errors: each\n * refused field (`extensions.fields`, or the one `extensions.field` names)\n * under the form field `fieldOf` names (else on the form), and any other\n * code as the form's message. A 404 about none of the form's fields (the\n * record itself is gone), a 401 and other failures go to the error page.\n */\nexport async function submitForm<L extends string, T>(\n\terrors: Pick<ApiErrors<L>, 'apiErrorMessage' | 'fieldErrors'>,\n\tlanguage: L,\n\trun: () => Promise<T>,\n\tfieldOf: (path: string) => string | undefined,\n\troute?: RouteErrorOptions,\n): Promise<{ ok: true; value: T } | ReturnType<typeof data<FormErrors>>> {\n\ttry {\n\t\treturn { ok: true, value: await run() };\n\t} catch (error) {\n\t\tif (!isApiErrorLike(error) || error.status === 401) {\n\t\t\tthrow routeError(error, route);\n\t\t}\n\t\tconst field = error.errors[0]?.extensions?.field;\n\t\tif (error.status === 404 && !(field && fieldOf(field))) {\n\t\t\tthrow routeError(error, route);\n\t\t}\n\t\tconst byField: Record<string, string> = {};\n\t\tconst unplaced: string[] = [];\n\t\tfor (const [path, message] of Object.entries(\n\t\t\terrors.fieldErrors(error, language),\n\t\t)) {\n\t\t\tconst field = fieldOf(path);\n\t\t\tif (field) byField[field] = message;\n\t\t\telse unplaced.push(message);\n\t\t}\n\t\tconst formError =\n\t\t\tObject.keys(byField).length && !unplaced.length\n\t\t\t\t? undefined\n\t\t\t\t: [errors.apiErrorMessage(error, language), ...unplaced].join(' ');\n\t\treturn data({ fieldErrors: byField, formError }, { status: error.status });\n\t}\n}\n",
|
|
@@ -20,6 +20,6 @@
|
|
|
20
20
|
"import { type FetcherWithComponents, useFetcher } from 'react-router';\n\n/** What a fetcher can post as JSON. */\nexport type JsonBody = Parameters<FetcherWithComponents<unknown>['submit']>[0];\n\n/**\n * A fetcher posting JSON to its page's action (which reads it with\n * `readJson`, and answers `fetcherResult` or the like): `post` sends a\n * body, `busy` while it is in flight. `key` shares the fetcher between the\n * form that posts and the component that reads the answer; `action` posts to\n * another route's action instead (a resource route's, such as a\n * `notifications/poll`). `post` takes the target of one call as its second\n * argument (a list's rows each post to their own record's action).\n */\nexport function useJsonFetcher<Action, Body extends JsonBody = JsonBody>(\n\tkey?: string,\n\taction?: string,\n): {\n\tfetcher: ReturnType<typeof useFetcher<Action>>;\n\tpost(body: Body, to?: string): Promise<void>;\n\tbusy: boolean;\n} {\n\tconst fetcher = useFetcher<Action>(key ? { key } : undefined);\n\tconst post = (body: Body, to = action) =>\n\t\tfetcher.submit(body, {\n\t\t\tmethod: 'post',\n\t\t\tencType: 'application/json',\n\t\t\t...(to ? { action: to } : {}),\n\t\t});\n\treturn { fetcher, post, busy: fetcher.state !== 'idle' };\n}\n"
|
|
21
21
|
],
|
|
22
22
|
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
23
|
+
"debugId": "C040A51D1737CFBA64756E2164756E21",
|
|
24
24
|
"names": []
|
|
25
25
|
}
|
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
/** What every `sessionCookies` call takes, with or without a second factor. */
|
|
2
|
+
export interface SessionCookiesBaseOptions {
|
|
2
3
|
/**
|
|
3
4
|
* The base name of the session cookie, e.g. `'my-app_session'`. With
|
|
4
5
|
* `secure`, the cookie is named `__Host-my-app_session`.
|
|
5
6
|
*/
|
|
6
7
|
readonly session: string;
|
|
7
|
-
/**
|
|
8
|
-
* The base name of the second-factor challenge's cookie. With `secure`, it
|
|
9
|
-
* is named `__Secure-<name>`.
|
|
10
|
-
*/
|
|
11
|
-
readonly challenge: string;
|
|
12
8
|
/**
|
|
13
9
|
* The app is served over HTTPS. Required, and never read from the
|
|
14
10
|
* environment: pass `!import.meta.env.DEV`. `false` drops `Secure` and the
|
|
15
11
|
* prefixes (Safari drops a `Secure` cookie over `http://localhost`).
|
|
16
12
|
*/
|
|
17
13
|
readonly secure: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** The options of an app with no second factor: no challenge cookie. */
|
|
16
|
+
export interface SessionCookiesWithoutChallengeOptions extends SessionCookiesBaseOptions {
|
|
17
|
+
readonly challenge?: undefined;
|
|
18
|
+
readonly challengePath?: undefined;
|
|
19
|
+
readonly challengeSeconds?: undefined;
|
|
20
|
+
}
|
|
21
|
+
/** The options of an app with a second factor: the challenge cookie's name is given. */
|
|
22
|
+
export interface SessionCookiesOptions extends SessionCookiesBaseOptions {
|
|
23
|
+
/**
|
|
24
|
+
* The base name of the second-factor challenge's cookie. With `secure`, it
|
|
25
|
+
* is named `__Secure-<name>`.
|
|
26
|
+
*/
|
|
27
|
+
readonly challenge: string;
|
|
18
28
|
/** Where the browser sends the challenge. `'/sign-in'` by default. */
|
|
19
29
|
readonly challengePath?: string | undefined;
|
|
20
30
|
/** The most the challenge lives. 300, `@nxgt/janus`'s lifetime, by default. */
|
|
@@ -25,11 +35,11 @@ export interface CookieSession {
|
|
|
25
35
|
readonly token: string;
|
|
26
36
|
readonly expiresAt: number;
|
|
27
37
|
}
|
|
28
|
-
|
|
38
|
+
/** The cookies every BFF has: the session's. */
|
|
39
|
+
export interface SessionCookiesBase {
|
|
29
40
|
/** The names as sent, prefixes included. */
|
|
30
41
|
readonly names: {
|
|
31
42
|
readonly session: string;
|
|
32
|
-
readonly challenge: string;
|
|
33
43
|
};
|
|
34
44
|
/** The session cookie of the request; `null` when absent or not `<ms>.<token>`. */
|
|
35
45
|
read(request: Request): CookieSession | null;
|
|
@@ -41,20 +51,56 @@ export interface SessionCookies {
|
|
|
41
51
|
destroy(): string;
|
|
42
52
|
/** 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. */
|
|
43
53
|
refreshed(session: CookieSession, expiresAt: string | Date | null): HeadersInit;
|
|
54
|
+
/**
|
|
55
|
+
* What a signed-out visit of the sign-in page sets: a dead session's
|
|
56
|
+
* cookie when `deadSession` (and, with a second factor, the challenge
|
|
57
|
+
* cleared blind: a client navigation fetches `/sign-in.data`, which the
|
|
58
|
+
* cookie's path does not match, so the request never shows it).
|
|
59
|
+
*/
|
|
60
|
+
signInPageHeaders(deadSession: boolean): Headers;
|
|
61
|
+
}
|
|
62
|
+
/** The challenge cookie's helpers, present when `challenge` was given. */
|
|
63
|
+
export interface ChallengeCookies {
|
|
64
|
+
readonly names: {
|
|
65
|
+
readonly challenge: string;
|
|
66
|
+
};
|
|
44
67
|
/** The challenge cookie of the request, or `null`. */
|
|
45
68
|
challengeOf(request: Request): string | null;
|
|
46
69
|
/** A `Set-Cookie` value keeping the challenge for the code page. */
|
|
47
70
|
commitChallenge(challenge: string, expiresAt?: string | Date | null, now?: number): string;
|
|
48
71
|
/** A `Set-Cookie` value removing the challenge. */
|
|
49
72
|
destroyChallenge(): string;
|
|
50
|
-
/**
|
|
51
|
-
* What a signed-out visit of the sign-in page sets: the challenge cleared
|
|
52
|
-
* blind (a client navigation fetches `/sign-in.data`, which the cookie's
|
|
53
|
-
* path does not match, so the request never shows it), and a dead
|
|
54
|
-
* session's cookie when `deadSession`.
|
|
55
|
-
*/
|
|
56
|
-
signInPageHeaders(deadSession: boolean): Headers;
|
|
57
73
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
74
|
+
/**
|
|
75
|
+
* The cookies `sessionCookies` returns: with the challenge helpers (the
|
|
76
|
+
* default) when `challenge` was given, `SessionCookies<false>` without.
|
|
77
|
+
*/
|
|
78
|
+
export type SessionCookies<WithChallenge extends boolean = true> = WithChallenge extends true ? SessionCookiesBase & ChallengeCookies : SessionCookiesBase & NoChallengeCookies;
|
|
79
|
+
/**
|
|
80
|
+
* What `SessionCookies<false>` says of the challenge helpers: they are
|
|
81
|
+
* absent. Declared as `undefined` so that a set with a challenge is not
|
|
82
|
+
* assignable to it (a flow with no second factor refuses one at compile time).
|
|
83
|
+
*/
|
|
84
|
+
export interface NoChallengeCookies {
|
|
85
|
+
readonly challengeOf?: undefined;
|
|
86
|
+
readonly commitChallenge?: undefined;
|
|
87
|
+
readonly destroyChallenge?: undefined;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The cookies of a BFF's session and, when `challenge` is given, of its
|
|
91
|
+
* second-factor challenge. Without `challenge`, the result has no challenge
|
|
92
|
+
* helpers and the type says so.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const cookies = sessionCookies({ session: 'my-app_session', secure: true });
|
|
96
|
+
*/
|
|
97
|
+
export declare function sessionCookies(options: SessionCookiesOptions): SessionCookies<true>;
|
|
98
|
+
export declare function sessionCookies(options: SessionCookiesWithoutChallengeOptions): SessionCookies<false>;
|
|
99
|
+
export declare function sessionCookies(options: SessionCookiesBaseOptions & {
|
|
100
|
+
readonly challenge?: string | undefined;
|
|
101
|
+
readonly challengePath?: string | undefined;
|
|
102
|
+
readonly challengeSeconds?: number | undefined;
|
|
103
|
+
}): SessionCookies<boolean>;
|
|
104
|
+
/** The `Set-Cookie` values that clear the challenge: none without a second factor. */
|
|
105
|
+
export declare function challengeCleared(cookies: SessionCookies<boolean>): string[];
|
|
60
106
|
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/session/cookies.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/session/cookies.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,8 +32,7 @@ export interface SignInCodes {
|
|
|
32
32
|
/** The codes that end the challenge (`TOKEN_UNKNOWN`, `TOKEN_SPENT`, `TOKEN_EXPIRED`). */
|
|
33
33
|
readonly challengeOver?: readonly string[] | undefined;
|
|
34
34
|
}
|
|
35
|
-
export interface
|
|
36
|
-
readonly cookies: SessionCookies;
|
|
35
|
+
export interface SignInFlowBaseOptions<L extends string, C = undefined> {
|
|
37
36
|
/** The app's `createApiErrors` instance. */
|
|
38
37
|
readonly errors: ApiErrors<L>;
|
|
39
38
|
/** The app's `jsonActions({ origin })`, so a body is read with the same CSRF check. */
|
|
@@ -45,8 +44,6 @@ export interface SignInFlowOptions<L extends string, C = undefined> {
|
|
|
45
44
|
* cannot carry. `undefined` when the step got none.
|
|
46
45
|
*/
|
|
47
46
|
revoke(token: string, request: Request, context: C | undefined): Promise<unknown>;
|
|
48
|
-
/** A refused code's tries left, worded ("3 tries left"). */
|
|
49
|
-
attemptsLeft(count: number, language: L): string;
|
|
50
47
|
/** The sign-in pages' paths; `SIGN_IN_PATHS` by default. */
|
|
51
48
|
readonly paths?: Partial<SignInPaths> | undefined;
|
|
52
49
|
/**
|
|
@@ -63,17 +60,65 @@ export interface SignInFlowOptions<L extends string, C = undefined> {
|
|
|
63
60
|
*/
|
|
64
61
|
readonly endedParam?: string | undefined;
|
|
65
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* The options of a flow with a second factor: the cookies carry the
|
|
65
|
+
* challenge (`sessionCookies({ challenge })`) and `attemptsLeft` words the
|
|
66
|
+
* tries left.
|
|
67
|
+
*/
|
|
68
|
+
export interface SignInFlowOptions<L extends string, C = undefined> extends SignInFlowBaseOptions<L, C> {
|
|
69
|
+
readonly cookies: SessionCookies<true>;
|
|
70
|
+
/** A refused code's tries left, worded ("3 tries left"). */
|
|
71
|
+
attemptsLeft(count: number, language: L): string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The options of a flow with no second factor: cookies built without
|
|
75
|
+
* `challenge` and no `attemptsLeft`. The flow then offers no second-factor
|
|
76
|
+
* step.
|
|
77
|
+
*/
|
|
78
|
+
export interface SignInFlowWithoutSecondFactorOptions<L extends string, C = undefined> extends SignInFlowBaseOptions<L, C> {
|
|
79
|
+
readonly cookies: SessionCookies<false>;
|
|
80
|
+
readonly attemptsLeft?: undefined;
|
|
81
|
+
}
|
|
66
82
|
/** A form step's answer when it stays on the page: the form's message, with a status. */
|
|
67
83
|
export type SignInStayed<T extends object> = ReturnType<typeof data<SignInFormError<T>>>;
|
|
68
|
-
|
|
84
|
+
/** The members of a flow built with a second factor, on top of the common ones. */
|
|
85
|
+
export interface SecondFactorSteps<L extends string> {
|
|
86
|
+
/** A refused code's tries left, worded (the `attemptsLeft` option). */
|
|
87
|
+
attemptsLeft(count: number, language: L): string;
|
|
88
|
+
/**
|
|
89
|
+
* A refused code's message with the tries left; `undefined` when the
|
|
90
|
+
* challenge is over (sign in again). With no try left, `whenNone` is
|
|
91
|
+
* added to the message instead, when given.
|
|
92
|
+
*/
|
|
93
|
+
codeRefusal(error: ApiErrorLike, language: L, whenNone?: string): string | undefined;
|
|
94
|
+
/** The code a second-factor page posted, with how it is given; a 400 otherwise. */
|
|
95
|
+
readCodeInput(request: Request): Promise<{
|
|
96
|
+
kind: SecondFactorKind;
|
|
97
|
+
code: string;
|
|
98
|
+
}>;
|
|
99
|
+
/** The code against the challenge: `confirm` for an issued code, `recover` for a recovery code. */
|
|
100
|
+
codeStep(input: {
|
|
101
|
+
readonly kind: SecondFactorKind;
|
|
102
|
+
readonly code: string;
|
|
103
|
+
}, challenge: string, steps: {
|
|
104
|
+
confirm(challenge: string, code: string): Promise<SignInAnswer>;
|
|
105
|
+
recover(challenge: string, code: string): Promise<SignInAnswer>;
|
|
106
|
+
}): Promise<SignInAnswer>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The flow `signInFlow` returns. `SignInFlow<L, C>` has a second factor (the
|
|
110
|
+
* default, as before); `SignInFlow<L, C, false>` has none, and no
|
|
111
|
+
* second-factor member (`attemptsLeft`, `codeRefusal`, `readCodeInput`,
|
|
112
|
+
* `codeStep`) is on its type.
|
|
113
|
+
*/
|
|
114
|
+
export type SignInFlow<L extends string, C = undefined, WithSecondFactor extends boolean = true> = SignInFlowBase<L, C, WithSecondFactor> & (WithSecondFactor extends true ? SecondFactorSteps<L> : unknown);
|
|
115
|
+
export interface SignInFlowBase<L extends string, C = undefined, WithSecondFactor extends boolean = true> {
|
|
69
116
|
/** The cookies the flow was built with. */
|
|
70
|
-
readonly cookies: SessionCookies
|
|
117
|
+
readonly cookies: SessionCookies<WithSecondFactor>;
|
|
71
118
|
/** The `createApiErrors` instance the flow was built with. */
|
|
72
119
|
readonly errors: ApiErrors<L>;
|
|
73
120
|
/** The `jsonActions` instance the flow was built with. */
|
|
74
121
|
readonly json: JsonActions;
|
|
75
|
-
/** A refused code's tries left, worded (the `attemptsLeft` option). */
|
|
76
|
-
attemptsLeft(count: number, language: L): string;
|
|
77
122
|
/**
|
|
78
123
|
* The guard every step of the flow that signs in, out, spends or mails
|
|
79
124
|
* runs first, for an app's own step (a passkey's): a native form post is
|
|
@@ -123,25 +168,6 @@ export interface SignInFlow<L extends string, C = undefined> {
|
|
|
123
168
|
/** The caller context handed to `revoke` when the answer replaces a session. */
|
|
124
169
|
readonly context?: C | undefined;
|
|
125
170
|
}): Promise<Response | SignInStayed<T>>;
|
|
126
|
-
/**
|
|
127
|
-
* A refused code's message with the tries left; `undefined` when the
|
|
128
|
-
* challenge is over (sign in again). With no try left, `whenNone` is
|
|
129
|
-
* added to the message instead, when given.
|
|
130
|
-
*/
|
|
131
|
-
codeRefusal(error: ApiErrorLike, language: L, whenNone?: string): string | undefined;
|
|
132
|
-
/** The code a second-factor page posted, with how it is given; a 400 otherwise. */
|
|
133
|
-
readCodeInput(request: Request): Promise<{
|
|
134
|
-
kind: SecondFactorKind;
|
|
135
|
-
code: string;
|
|
136
|
-
}>;
|
|
137
|
-
/** The code against the challenge: `confirm` for an issued code, `recover` for a recovery code. */
|
|
138
|
-
codeStep(input: {
|
|
139
|
-
readonly kind: SecondFactorKind;
|
|
140
|
-
readonly code: string;
|
|
141
|
-
}, challenge: string, steps: {
|
|
142
|
-
confirm(challenge: string, code: string): Promise<SignInAnswer>;
|
|
143
|
-
recover(challenge: string, code: string): Promise<SignInAnswer>;
|
|
144
|
-
}): Promise<SignInAnswer>;
|
|
145
171
|
/**
|
|
146
172
|
* Ends the request's session at the API; true when it carried one.
|
|
147
173
|
* `context` is handed to `revoke`.
|
|
@@ -177,7 +203,7 @@ export interface SignInFlow<L extends string, C = undefined> {
|
|
|
177
203
|
}
|
|
178
204
|
/** The options once resolved, as the flow's functions take them. */
|
|
179
205
|
export interface FlowContext<L extends string, C = undefined> {
|
|
180
|
-
readonly options: SignInFlowOptions<L, C>;
|
|
206
|
+
readonly options: SignInFlowOptions<L, C> | SignInFlowWithoutSecondFactorOptions<L, C>;
|
|
181
207
|
readonly paths: SignInPaths;
|
|
182
208
|
readonly invalidCode: string;
|
|
183
209
|
readonly challengeOver: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-types.d.ts","sourceRoot":"","sources":["../../src/session/flow-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE3E;;;;GAIG;AACH,MAAM,MAAM,YAAY,GACrB;IACA,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,GACD;IACA,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;CACrD,GACD;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhC,sEAAsE;AACtE,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,0FAA0F;IAC1F,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"flow-types.d.ts","sourceRoot":"","sources":["../../src/session/flow-types.ts"],"names":[],"mappings":"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"}
|
package/dist/session/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* nothing else.
|
|
6
6
|
*/
|
|
7
7
|
export { CHALLENGE_OVER, INVALID_CODE, MAIL_THROTTLED } from './codes';
|
|
8
|
-
export { type CookieSession, type SessionCookies, type SessionCookiesOptions, sessionCookies, } from './cookies';
|
|
9
|
-
export type { SignInAnswer, SignInCodes, SignInFlow, SignInFlowOptions, SignInFormError, SignInStayed, } from './flow-types';
|
|
8
|
+
export { type ChallengeCookies, type CookieSession, type NoChallengeCookies, type SessionCookies, type SessionCookiesBase, type SessionCookiesOptions, type SessionCookiesWithoutChallengeOptions, sessionCookies, } from './cookies';
|
|
9
|
+
export type { SecondFactorSteps, SignInAnswer, SignInCodes, SignInFlow, SignInFlowBase, SignInFlowOptions, SignInFlowWithoutSecondFactorOptions, SignInFormError, SignInStayed, } from './flow-types';
|
|
10
10
|
export { TOKEN_PAGE_HEADERS } from './link-token';
|
|
11
11
|
export type { AuthLinks, AuthLinksCodes, AuthLinksOptions, LinkStayed, RequestLinkAnswer, SpendOptions, Spent, } from './link-types';
|
|
12
12
|
export { authLinks } from './links';
|
|
@@ -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,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,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,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,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,YAAY,EACZ,WAAW,EACX,kBAAkB,GAClB,MAAM,iBAAiB,CAAC"}
|
package/dist/session/index.js
CHANGED
|
@@ -87,7 +87,8 @@ function sessionCookies(options) {
|
|
|
87
87
|
challengeSeconds = 5 * 60
|
|
88
88
|
} = options;
|
|
89
89
|
checkName("session", options.session);
|
|
90
|
-
|
|
90
|
+
if (options.challenge !== undefined)
|
|
91
|
+
checkName("challenge", options.challenge);
|
|
91
92
|
if (!Number.isInteger(challengeSeconds) || challengeSeconds <= 0) {
|
|
92
93
|
throw new TypeError(`sessionCookies(): challengeSeconds must be a positive integer; got ${String(challengeSeconds)}.`);
|
|
93
94
|
}
|
|
@@ -95,7 +96,7 @@ function sessionCookies(options) {
|
|
|
95
96
|
throw new TypeError(`sessionCookies(): challengePath must start with "/" and hold no ";" or control character; got ${JSON.stringify(challengePath)}.`);
|
|
96
97
|
}
|
|
97
98
|
const session = secure ? `__Host-${options.session}` : options.session;
|
|
98
|
-
const
|
|
99
|
+
const challengeName = options.challenge === undefined ? undefined : secure ? `__Secure-${options.challenge}` : options.challenge;
|
|
99
100
|
const clear = (name, path) => serializeCookie(name, "", { maxAge: 0, secure, ...path && { path } });
|
|
100
101
|
const read = (request) => {
|
|
101
102
|
const value = readCookie(request, session);
|
|
@@ -111,8 +112,8 @@ function sessionCookies(options) {
|
|
|
111
112
|
maxAge: secondsUntil(expiresAt, now),
|
|
112
113
|
secure
|
|
113
114
|
});
|
|
114
|
-
|
|
115
|
-
names: { session
|
|
115
|
+
const base = {
|
|
116
|
+
names: { session },
|
|
116
117
|
read,
|
|
117
118
|
token: (request) => read(request)?.token ?? null,
|
|
118
119
|
commit,
|
|
@@ -123,21 +124,36 @@ function sessionCookies(options) {
|
|
|
123
124
|
return {};
|
|
124
125
|
return { "Set-Cookie": commit(current.token, expiresAt) };
|
|
125
126
|
},
|
|
126
|
-
challengeOf: (request) => readCookie(request, challenge),
|
|
127
|
-
commitChallenge: (value, expiresAt, now) => serializeCookie(challenge, value, {
|
|
128
|
-
maxAge: Math.min(challengeSeconds, expiresAt ? secondsUntil(expiresAt, now) : challengeSeconds),
|
|
129
|
-
path: challengePath,
|
|
130
|
-
secure
|
|
131
|
-
}),
|
|
132
|
-
destroyChallenge: () => clear(challenge, challengePath),
|
|
133
127
|
signInPageHeaders(deadSession) {
|
|
134
128
|
const headers = new Headers;
|
|
135
|
-
|
|
129
|
+
if (challengeName) {
|
|
130
|
+
headers.append("Set-Cookie", clear(challengeName, challengePath));
|
|
131
|
+
}
|
|
136
132
|
if (deadSession)
|
|
137
133
|
headers.append("Set-Cookie", clear(session));
|
|
138
134
|
return headers;
|
|
139
135
|
}
|
|
140
136
|
};
|
|
137
|
+
if (challengeName === undefined)
|
|
138
|
+
return base;
|
|
139
|
+
const challengeCookies = {
|
|
140
|
+
names: { challenge: challengeName },
|
|
141
|
+
challengeOf: (request) => readCookie(request, challengeName),
|
|
142
|
+
commitChallenge: (value, expiresAt, now) => serializeCookie(challengeName, value, {
|
|
143
|
+
maxAge: Math.min(challengeSeconds, expiresAt ? secondsUntil(expiresAt, now) : challengeSeconds),
|
|
144
|
+
path: challengePath,
|
|
145
|
+
secure
|
|
146
|
+
}),
|
|
147
|
+
destroyChallenge: () => clear(challengeName, challengePath)
|
|
148
|
+
};
|
|
149
|
+
return {
|
|
150
|
+
...base,
|
|
151
|
+
...challengeCookies,
|
|
152
|
+
names: { session, challenge: challengeName }
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function challengeCleared(cookies) {
|
|
156
|
+
return cookies.destroyChallenge ? [cookies.destroyChallenge()] : [];
|
|
141
157
|
}
|
|
142
158
|
// src/session/link-token.ts
|
|
143
159
|
import { data, replace } from "react-router";
|
|
@@ -228,13 +244,15 @@ function landing({ options, paths }, answer, next) {
|
|
|
228
244
|
if (isLive(answer)) {
|
|
229
245
|
const headers = new Headers;
|
|
230
246
|
headers.append("Set-Cookie", cookies.commit(answer.token, answer.expiresAt));
|
|
231
|
-
|
|
247
|
+
for (const cookie of challengeCleared(cookies)) {
|
|
248
|
+
headers.append("Set-Cookie", cookie);
|
|
249
|
+
}
|
|
232
250
|
for (const cookie of options.clear?.() ?? []) {
|
|
233
251
|
headers.append("Set-Cookie", cookie);
|
|
234
252
|
}
|
|
235
253
|
return redirect(safeNext2(next), { headers });
|
|
236
254
|
}
|
|
237
|
-
if (answer.status === "secondFactor" && answer.challenge) {
|
|
255
|
+
if (answer.status === "secondFactor" && answer.challenge && cookies.commitChallenge) {
|
|
238
256
|
return redirect(secondFactorPath2(next, paths.secondFactor), {
|
|
239
257
|
headers: {
|
|
240
258
|
"Set-Cookie": cookies.commitChallenge(answer.challenge, answer.expiresAt)
|
|
@@ -298,7 +316,9 @@ async function afterReset(options, resetDone, request, { context } = {}) {
|
|
|
298
316
|
await options.signIn.revokeSession(request, { context });
|
|
299
317
|
const headers = withTokenHeaders();
|
|
300
318
|
headers.append("Set-Cookie", options.cookies.destroy());
|
|
301
|
-
|
|
319
|
+
for (const cookie of challengeCleared(options.cookies)) {
|
|
320
|
+
headers.append("Set-Cookie", cookie);
|
|
321
|
+
}
|
|
302
322
|
for (const cookie of options.signIn.clear()) {
|
|
303
323
|
headers.append("Set-Cookie", cookie);
|
|
304
324
|
}
|
|
@@ -475,7 +495,9 @@ async function signOut(flow, request, {
|
|
|
475
495
|
await revokeSession(flow, request, { context });
|
|
476
496
|
const headers = new Headers;
|
|
477
497
|
headers.append("Set-Cookie", options.cookies.destroy());
|
|
478
|
-
|
|
498
|
+
for (const cookie of challengeCleared(options.cookies)) {
|
|
499
|
+
headers.append("Set-Cookie", cookie);
|
|
500
|
+
}
|
|
479
501
|
for (const cookie of options.clear?.() ?? []) {
|
|
480
502
|
headers.append("Set-Cookie", cookie);
|
|
481
503
|
}
|
|
@@ -484,6 +506,9 @@ async function signOut(flow, request, {
|
|
|
484
506
|
|
|
485
507
|
// src/session/sign-in.ts
|
|
486
508
|
function resolve(options) {
|
|
509
|
+
if (options.attemptsLeft === undefined !== !options.cookies.commitChallenge) {
|
|
510
|
+
throw new TypeError("signInFlow(): a second factor needs both the challenge cookie (sessionCookies({ challenge })) and attemptsLeft; without one, give neither.");
|
|
511
|
+
}
|
|
487
512
|
const paths = { ...SIGN_IN_PATHS2, ...options.paths };
|
|
488
513
|
for (const key of ["signIn", "secondFactor"]) {
|
|
489
514
|
sitePath(paths[key], { label: `signInFlow(): paths.${key}` });
|
|
@@ -501,27 +526,33 @@ function resolve(options) {
|
|
|
501
526
|
function signInFlow(options) {
|
|
502
527
|
const context = resolve(options);
|
|
503
528
|
const { options: o } = context;
|
|
504
|
-
|
|
529
|
+
const base = {
|
|
505
530
|
cookies: o.cookies,
|
|
506
531
|
errors: o.errors,
|
|
507
532
|
json: o.json,
|
|
508
533
|
unavailable: (language) => unavailableMessage(o, language),
|
|
509
534
|
clear: () => o.clear?.() ?? [],
|
|
510
|
-
attemptsLeft: o.attemptsLeft,
|
|
511
535
|
guard: (request) => samesitePost(o.json, request),
|
|
512
536
|
nextParam,
|
|
513
537
|
signInRedirect: (request) => signInRedirect(context, request),
|
|
514
538
|
landing: (answer, next) => landing(context, answer, next),
|
|
515
539
|
landReplacing: (answer, next, o) => landReplacing(context, answer, next, o),
|
|
516
540
|
signInStep: (run, o) => signInStep(context, run, o),
|
|
517
|
-
codeRefusal: (error, language, whenNone) => codeRefusal(context, error, language, whenNone),
|
|
518
|
-
readCodeInput: (request) => readCodeInput(context, request),
|
|
519
|
-
codeStep,
|
|
520
541
|
revokeSession: (request, o) => revokeSession(context, request, o),
|
|
521
542
|
signOut: (request, o) => signOut(context, request, o),
|
|
522
543
|
viewer: (request, read, token) => viewer(context, request, read, token),
|
|
523
544
|
requireViewer: (request, read, expiresAt) => requireViewer(context, request, read, expiresAt)
|
|
524
545
|
};
|
|
546
|
+
if (!o.attemptsLeft)
|
|
547
|
+
return base;
|
|
548
|
+
const wording = { ...context, options: o };
|
|
549
|
+
return {
|
|
550
|
+
...base,
|
|
551
|
+
attemptsLeft: o.attemptsLeft,
|
|
552
|
+
codeRefusal: (error, language, whenNone) => codeRefusal(wording, error, language, whenNone),
|
|
553
|
+
readCodeInput: (request) => readCodeInput(context, request),
|
|
554
|
+
codeStep
|
|
555
|
+
};
|
|
525
556
|
}
|
|
526
557
|
// src/session/step-up.ts
|
|
527
558
|
import { data as data6 } from "react-router";
|
|
@@ -660,5 +691,5 @@ export {
|
|
|
660
691
|
stepUpSteps
|
|
661
692
|
};
|
|
662
693
|
|
|
663
|
-
//# debugId=
|
|
694
|
+
//# debugId=DC4CDFEB0777ED0864756E2164756E21
|
|
664
695
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
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",
|
|
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
|
-
"import {\n\tisCookieName,\n\tisCookiePath,\n\tmillisOf,\n\treadCookie,\n\tsecondsUntil,\n\tserializeCookie,\n} from './serialize';\n\nexport interface
|
|
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",
|
|
9
9
|
"import type { JsonActions } from '../errors/json-actions';\nimport { refuseCrossSite } from '../errors/same-site';\n\n/**\n * What every step that signs in, out, spends or mails runs first: a native\n * form post (before hydration) goes back to its page, which then posts JSON\n * (`json.requireJsonPost`), and a request from another site is a 403 even\n * when it is JSON (the `Origin` and `Sec-Fetch-Site` rule of `readJson`). It\n * reads headers only, never the body.\n */\nexport function samesitePost(json: JsonActions, request: Request): void {\n\tjson.requireJsonPost(request);\n\trefuseCrossSite(json, request);\n}\n",
|
|
10
10
|
"import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tisApiErrorLike,\n\tretryAfterOf,\n} from '../errors/api-error';\nimport { MAIL_THROTTLED } from './codes';\nimport { samesitePost } from './guard';\nimport { afterReset, landByLink } from './link-land';\nimport {\n\tanswerOf,\n\tlinkArgs,\n\tspendToken,\n\tstatePath,\n\tstateRedirect,\n} from './link-token';\nimport type {\n\tAuthLinks,\n\tAuthLinksCodes,\n\tAuthLinksOptions,\n\tLinksContext,\n\tRequestLinkAnswer,\n} from './link-types';\nimport { sitePath } from './model/site-path';\n\nconst RESET_DONE = '/sign-in?password-reset=1';\n\n/**\n * Requests a mail's link with `run`. The API answers true whether or not\n * the e-mail holds an account, and so does the page: the same \"sent\" for\n * everyone. A wait or an unreachable API is the form's message; a malformed\n * address is the `email` field's.\n */\n/** The refusal's message: the app's own wording, else `errors`'. */\nconst worded = <L extends string, C>(\n\t{ wording, errors }: LinksContext<L, C>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n): string =>\n\twording?.(error, language) ?? errors.apiErrorMessage(error, language);\n\n/** The codes that are a wait: the configured one or list, else janus's. */\nconst throttleCodes = (\n\tcodes: AuthLinksCodes | undefined,\n): readonly string[] => {\n\tconst configured = codes?.mailThrottled ?? MAIL_THROTTLED;\n\treturn typeof configured === 'string' ? [configured] : configured;\n};\n\nasync function requestLink<L extends string, C>(\n\toptions: LinksContext<L, C>,\n\trun: () => Promise<unknown>,\n\t{ request, language }: Parameters<AuthLinks<L, C>['requestLink']>[1],\n) {\n\tconst { errors } = options;\n\tsamesitePost(options.json, request);\n\ttry {\n\t\tawait run();\n\t\treturn data<RequestLinkAnswer>({ sent: true });\n\t} catch (error) {\n\t\tconst api = isApiErrorLike(error);\n\t\tif (api && throttleCodes(options.codes).includes(error.code ?? '')) {\n\t\t\tconst retryAfter = retryAfterOf(error);\n\t\t\treturn data<RequestLinkAnswer>(\n\t\t\t\t{\n\t\t\t\t\tformError: worded(options, error, language),\n\t\t\t\t\tthrottled: true,\n\t\t\t\t\t...(retryAfter === undefined ? {} : { retryAfter }),\n\t\t\t\t},\n\t\t\t\t{ status: 429 },\n\t\t\t);\n\t\t}\n\t\tif (api) {\n\t\t\tconst email = errors.fieldErrors(error, language)['email'];\n\t\t\tif (email) {\n\t\t\t\treturn data<RequestLinkAnswer>(\n\t\t\t\t\t{ fieldErrors: { email } },\n\t\t\t\t\t{ status: error.status },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst refusal = errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\treturn data<RequestLinkAnswer>(\n\t\t\t{ formError: api ? worded(options, error, language) : refusal.message },\n\t\t\t{ status: refusal.status },\n\t\t);\n\t}\n}\n\n/**\n * The pages a mail's link opens (a magic link, a password reset, an\n * invitation): the token page's end states, the arguments it posts, the\n * token spent against the API, the sign-in it leads to (replacing the\n * token's history entry), and the request for a link. Built once, beside the\n * app's `signInFlow`.\n *\n * @example\n * export const links = authLinks({ signIn });\n * // loader: return data({ ... }, { headers: TOKEN_PAGE_HEADERS });\n */\nexport function authLinks<L extends string, C = undefined>(\n\tlinks: AuthLinksOptions<L, C>,\n): AuthLinks<L, C> {\n\tconst { signIn } = links;\n\tconst options: LinksContext<L, C> = {\n\t\t...links,\n\t\tcookies: signIn.cookies,\n\t\terrors: signIn.errors,\n\t\tjson: signIn.json,\n\t};\n\tconst resetDone = options.resetDone ?? RESET_DONE;\n\tsitePath(resetDone, { label: 'authLinks(): resetDone', query: true });\n\tconst invalid = options.invalidState ?? 'invalid';\n\treturn {\n\t\tstatePath,\n\t\tended: stateRedirect,\n\t\tlinkArgs: (schema, request, path) =>\n\t\t\tlinkArgs(options, invalid, schema, request, path),\n\t\tspendToken: (run, o) => spendToken(options, run, o),\n\t\tanswerOf,\n\t\tlandByLink: (answer, o) => landByLink(options, answer, o),\n\t\tafterReset: (request, o) => afterReset(options, resetDone, request, o),\n\t\trequestLink: (run, o) => requestLink(options, run, o),\n\t};\n}\n",
|
|
11
|
-
"import { data, replace } from 'react-router';\nimport type { FormErrors } from '../errors/form-errors';\nimport type { SignInAnswer } from './flow-types';\nimport { samesitePost } from './guard';\nimport { isLive } from './land';\nimport { stateRedirect, withTokenHeaders } from './link-token';\nimport type { AuthLinks, LinkStayed, LinksContext } from './link-types';\nimport { HOME, safeNext } from './model';\n\n/** Where a new session starts: the app's start page, else `/`; never an unsafe path. */\nasync function startOf<L extends string, C>(\n\t{ start }: LinksContext<L, C>,\n\trequest: Request,\n\ttoken: string,\n): Promise<string> {\n\tif (!start) return HOME;\n\ttry {\n\t\treturn safeNext(await start(token, request));\n\t} catch {\n\t\t// The token is spent: a failed lookup must not fail the sign-in.\n\t\treturn HOME;\n\t}\n}\n\n/**\n * Where a link's sign-in leads, replacing the token's history entry. Signed\n * in: the start page, with the new session's cookie; a second factor: its\n * page. Either way the session the browser held, whoever's, is revoked\n * first: one browser holds one session. Only a JSON post goes on, before\n * anything is revoked or landed.\n */\nexport async function landByLink<L extends string, C>(\n\toptions: LinksContext<L, C>,\n\tanswer: SignInAnswer,\n\t{\n\t\trequest,\n\t\tlanguage,\n\t\tother,\n\t\tcontext,\n\t}: Parameters<AuthLinks<L, C>['landByLink']>[1],\n): Promise<Response | LinkStayed> {\n\tsamesitePost(options.json, request);\n\tif (answer.status === 'other' && other) {\n\t\treturn stateRedirect(other.path, other.state);\n\t}\n\t// A dead session would be looked up with a token the API refuses.\n\tconst next = isLive(answer)\n\t\t? await startOf(options, request, answer.token)\n\t\t: HOME;\n\tconst landed = await options.signIn.landReplacing(answer, next, {\n\t\trequest,\n\t\trevokeOn: ['signedIn', 'secondFactor'],\n\t\tcontext,\n\t});\n\tif (!landed) {\n\t\treturn data<FormErrors>(\n\t\t\t{ formError: options.signIn.unavailable(language) },\n\t\t\t{ status: 503 },\n\t\t);\n\t}\n\tconst location = landed.headers.get('Location') ?? HOME;\n\treturn replace(location, { headers: withTokenHeaders(landed.headers) });\n}\n\n/**\n * After a password reset, which signs the account out everywhere: the\n * browser's session is revoked (it may be another account's) and its cookies\n * cleared (the session's, the challenge's, the flow's `clear()`), then the sign-in page says the password changed. Only a JSON post\n * goes on.\n */\nexport async function afterReset<L extends string, C>(\n\toptions: LinksContext<L, C>,\n\tresetDone: string,\n\trequest: Request,\n\t{ context }: { readonly context?: C | undefined } = {},\n): Promise<Response> {\n\tsamesitePost(options.json, request);\n\tawait options.signIn.revokeSession(request, { context });\n\tconst headers = withTokenHeaders();\n\theaders.append('Set-Cookie', options.cookies.destroy());\n\theaders.append('Set-Cookie',
|
|
12
|
-
"import { redirect } from 'react-router';\nimport type { FlowContext, SignInAnswer, SignInFlow } from './flow-types';\nimport { samesitePost } from './guard';\nimport { safeNext, secondFactorPath } from './model';\nimport { millisOf } from './serialize';\n\n/**\n * Ends the request's session at the API, when it carries one; a failure is\n * ignored, the caller clears the cookie anyway. True when there was one.\n */\nexport async function revokeSession<L extends string, C>(\n\t{ options }: FlowContext<L, C>,\n\trequest: Request,\n\t{ context }: { readonly context?: C | undefined } = {},\n): Promise<boolean> {\n\tsamesitePost(options.json, request);\n\tconst token = options.cookies.token(request);\n\tif (!token) return false;\n\ttry {\n\t\tawait options.revoke(token, request, context);\n\t} catch {\n\t\t// The old session ends when it expires.\n\t}\n\treturn true;\n}\n\n/** The condition a session opens on: a signed-in answer with a token and an end still to come. */\nexport const isLive = (\n\tanswer: SignInAnswer,\n): answer is Extract<SignInAnswer, { status: 'signedIn' }> =>\n\tanswer.status === 'signedIn' &&\n\tBoolean(answer.token) &&\n\tBoolean(answer.expiresAt) &&\n\tmillisOf(answer.expiresAt) > Date.now();\n\n/**\n * Where a sign-in's answer leads: signed in, to `next` with the session\n * cookie (and the challenge cleared); a second factor, to its page with the\n * challenge in its own cookie, never in the URL. Any other answer, or a\n * signed-in one with no token or an end that is missing, unreadable or past,\n * opens no session: `null`, the caller shows its own state.\n */\nexport function landing<L extends string, C>(\n\t{ options, paths }: FlowContext<L, C>,\n\tanswer: SignInAnswer,\n\tnext: string,\n): Response | null {\n\tconst { cookies } = options;\n\t// A session with no readable or past end would be set and dead at once.\n\tif (isLive(answer)) {\n\t\tconst headers = new Headers();\n\t\theaders.append(\n\t\t\t'Set-Cookie',\n\t\t\tcookies.commit(answer.token, answer.expiresAt),\n\t\t);\n\t\theaders.append('Set-Cookie',
|
|
11
|
+
"import { data, replace } from 'react-router';\nimport type { FormErrors } from '../errors/form-errors';\nimport { challengeCleared } from './cookies';\nimport type { SignInAnswer } from './flow-types';\nimport { samesitePost } from './guard';\nimport { isLive } from './land';\nimport { stateRedirect, withTokenHeaders } from './link-token';\nimport type { AuthLinks, LinkStayed, LinksContext } from './link-types';\nimport { HOME, safeNext } from './model';\n\n/** Where a new session starts: the app's start page, else `/`; never an unsafe path. */\nasync function startOf<L extends string, C>(\n\t{ start }: LinksContext<L, C>,\n\trequest: Request,\n\ttoken: string,\n): Promise<string> {\n\tif (!start) return HOME;\n\ttry {\n\t\treturn safeNext(await start(token, request));\n\t} catch {\n\t\t// The token is spent: a failed lookup must not fail the sign-in.\n\t\treturn HOME;\n\t}\n}\n\n/**\n * Where a link's sign-in leads, replacing the token's history entry. Signed\n * in: the start page, with the new session's cookie; a second factor: its\n * page. Either way the session the browser held, whoever's, is revoked\n * first: one browser holds one session. Only a JSON post goes on, before\n * anything is revoked or landed.\n */\nexport async function landByLink<L extends string, C>(\n\toptions: LinksContext<L, C>,\n\tanswer: SignInAnswer,\n\t{\n\t\trequest,\n\t\tlanguage,\n\t\tother,\n\t\tcontext,\n\t}: Parameters<AuthLinks<L, C>['landByLink']>[1],\n): Promise<Response | LinkStayed> {\n\tsamesitePost(options.json, request);\n\tif (answer.status === 'other' && other) {\n\t\treturn stateRedirect(other.path, other.state);\n\t}\n\t// A dead session would be looked up with a token the API refuses.\n\tconst next = isLive(answer)\n\t\t? await startOf(options, request, answer.token)\n\t\t: HOME;\n\tconst landed = await options.signIn.landReplacing(answer, next, {\n\t\trequest,\n\t\trevokeOn: ['signedIn', 'secondFactor'],\n\t\tcontext,\n\t});\n\tif (!landed) {\n\t\treturn data<FormErrors>(\n\t\t\t{ formError: options.signIn.unavailable(language) },\n\t\t\t{ status: 503 },\n\t\t);\n\t}\n\tconst location = landed.headers.get('Location') ?? HOME;\n\treturn replace(location, { headers: withTokenHeaders(landed.headers) });\n}\n\n/**\n * After a password reset, which signs the account out everywhere: the\n * browser's session is revoked (it may be another account's) and its cookies\n * cleared (the session's, the challenge's, the flow's `clear()`), then the sign-in page says the password changed. Only a JSON post\n * goes on.\n */\nexport async function afterReset<L extends string, C>(\n\toptions: LinksContext<L, C>,\n\tresetDone: string,\n\trequest: Request,\n\t{ context }: { readonly context?: C | undefined } = {},\n): Promise<Response> {\n\tsamesitePost(options.json, request);\n\tawait options.signIn.revokeSession(request, { context });\n\tconst headers = withTokenHeaders();\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.signIn.clear()) {\n\t\theaders.append('Set-Cookie', cookie);\n\t}\n\treturn replace(resetDone, { headers });\n}\n",
|
|
12
|
+
"import { redirect } from 'react-router';\nimport { challengeCleared } from './cookies';\nimport type { FlowContext, SignInAnswer, SignInFlow } from './flow-types';\nimport { samesitePost } from './guard';\nimport { safeNext, secondFactorPath } from './model';\nimport { millisOf } from './serialize';\n\n/**\n * Ends the request's session at the API, when it carries one; a failure is\n * ignored, the caller clears the cookie anyway. True when there was one.\n */\nexport async function revokeSession<L extends string, C>(\n\t{ options }: FlowContext<L, C>,\n\trequest: Request,\n\t{ context }: { readonly context?: C | undefined } = {},\n): Promise<boolean> {\n\tsamesitePost(options.json, request);\n\tconst token = options.cookies.token(request);\n\tif (!token) return false;\n\ttry {\n\t\tawait options.revoke(token, request, context);\n\t} catch {\n\t\t// The old session ends when it expires.\n\t}\n\treturn true;\n}\n\n/** The condition a session opens on: a signed-in answer with a token and an end still to come. */\nexport const isLive = (\n\tanswer: SignInAnswer,\n): answer is Extract<SignInAnswer, { status: 'signedIn' }> =>\n\tanswer.status === 'signedIn' &&\n\tBoolean(answer.token) &&\n\tBoolean(answer.expiresAt) &&\n\tmillisOf(answer.expiresAt) > Date.now();\n\n/**\n * Where a sign-in's answer leads: signed in, to `next` with the session\n * cookie (and the challenge cleared); a second factor, to its page with the\n * challenge in its own cookie, never in the URL. Any other answer, or a\n * signed-in one with no token or an end that is missing, unreadable or past,\n * opens no session: `null`, the caller shows its own state.\n */\nexport function landing<L extends string, C>(\n\t{ options, paths }: FlowContext<L, C>,\n\tanswer: SignInAnswer,\n\tnext: string,\n): Response | null {\n\tconst { cookies } = options;\n\t// A session with no readable or past end would be set and dead at once.\n\tif (isLive(answer)) {\n\t\tconst headers = new Headers();\n\t\theaders.append(\n\t\t\t'Set-Cookie',\n\t\t\tcookies.commit(answer.token, answer.expiresAt),\n\t\t);\n\t\tfor (const cookie of challengeCleared(cookies)) {\n\t\t\theaders.append('Set-Cookie', cookie);\n\t\t}\n\t\tfor (const cookie of options.clear?.() ?? []) {\n\t\t\theaders.append('Set-Cookie', cookie);\n\t\t}\n\t\treturn redirect(safeNext(next), { headers });\n\t}\n\t// An app with no second factor has no challenge cookie: nothing to land on.\n\tif (\n\t\tanswer.status === 'secondFactor' &&\n\t\tanswer.challenge &&\n\t\tcookies.commitChallenge\n\t) {\n\t\treturn redirect(secondFactorPath(next, paths.secondFactor), {\n\t\t\theaders: {\n\t\t\t\t'Set-Cookie': cookies.commitChallenge(\n\t\t\t\t\tanswer.challenge,\n\t\t\t\t\tanswer.expiresAt,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t}\n\treturn null;\n}\n\n/**\n * `landing`, ending the session the browser held first: one browser holds\n * one session, so the one its cookie names, whoever's, is revoked when an\n * answer in `revokeOn` lands. A signed-in answer's own cookie replaces the\n * old one; any other answer clears it. A failed revoke is ignored.\n */\nexport async function landReplacing<L extends string, C>(\n\tflow: FlowContext<L, C>,\n\tanswer: SignInAnswer,\n\tnext: string,\n\t{\n\t\trequest,\n\t\trevokeOn = ['signedIn'],\n\t\tcontext,\n\t}: Parameters<SignInFlow<L, C>['landReplacing']>[2],\n): Promise<Response | null> {\n\tsamesitePost(flow.options.json, request);\n\tconst landed = landing(flow, answer, next);\n\tif (!landed || answer.status === 'other') return landed;\n\tif (!revokeOn.includes(answer.status)) return landed;\n\tconst hadSession = await revokeSession(flow, request, { context });\n\tif (hadSession && answer.status !== 'signedIn') {\n\t\tlanded.headers.append('Set-Cookie', flow.options.cookies.destroy());\n\t}\n\treturn landed;\n}\n",
|
|
13
13
|
"import { data } from 'react-router';\nimport type { FlowContext, SignInAnswer, SignInFlow } from './flow-types';\nimport { samesitePost } from './guard';\nimport type { SecondFactorKind } from './model';\n\nconst MAX_CODE = 40;\n\nfunction isMethod(value: unknown): value is SecondFactorKind {\n\treturn value === 'code' || value === 'recovery';\n}\n\n/**\n * The code a second-factor page posted, with how it is given\n * (`{ kind: 'code' | 'recovery', code }`, the code at most 40 characters). A\n * native form post goes back to its page, which then posts JSON; a\n * cross-site post is a 403; a body of another shape is a 400.\n */\nexport async function readCodeInput<L extends string, C>(\n\t{ options }: FlowContext<L, C>,\n\trequest: Request,\n): Promise<{ kind: SecondFactorKind; code: string }> {\n\tsamesitePost(options.json, request);\n\tconst body = (await options.json.readJson(request)) as {\n\t\tkind?: unknown;\n\t\tcode?: unknown;\n\t} | null;\n\tconst { kind, code } = body ?? {};\n\tif (!isMethod(kind) || typeof code !== 'string' || code.length > MAX_CODE) {\n\t\tthrow data('Bad code request', { status: 400 });\n\t}\n\treturn { kind, code };\n}\n\n/**\n * The code against the sign-in's challenge: an issued code (an app's, or\n * the one mailed) is confirmed, a recovery code is recovered. Either\n * answers like a sign-in.\n */\nexport function codeStep(\n\tinput: { readonly kind: SecondFactorKind; readonly code: string },\n\tchallenge: string,\n\tsteps: Parameters<SignInFlow<string>['codeStep']>[2],\n): Promise<SignInAnswer> {\n\treturn input.kind === 'code'\n\t\t? steps.confirm(challenge, input.code)\n\t\t: steps.recover(challenge, input.code);\n}\n",
|
|
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
|
-
"import { redirect } from 'react-router';\nimport { isApiErrorLike } from '../errors/api-error';\nimport { nextOf } from '../errors/page-path';\nimport { routeError } from '../errors/route-error';\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\theaders.append('Set-Cookie',
|
|
16
|
-
"import { hasSiteCheck } from '../errors/same-site';\nimport { CHALLENGE_OVER, INVALID_CODE } from './codes';\nimport type {
|
|
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
|
+
"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
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\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\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\tisStepUpRequired: (error) =>\n\t\t\tisApiErrorLike(error) && error.code === context.stepUpRequired,\n\t};\n}\n",
|
|
18
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
19
|
],
|
|
20
|
-
"mappings": "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",
|
|
21
|
-
"debugId": "
|
|
20
|
+
"mappings": "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",
|
|
21
|
+
"debugId": "DC4CDFEB0777ED0864756E2164756E21",
|
|
22
22
|
"names": []
|
|
23
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"land.d.ts","sourceRoot":"","sources":["../../src/session/land.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"land.d.ts","sourceRoot":"","sources":["../../src/session/land.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1E;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EACtD,EAAE,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAC9B,OAAO,EAAE,OAAO,EAChB,EAAE,OAAO,EAAE,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAA;CAAO,GACpD,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED,kGAAkG;AAClG,eAAO,MAAM,MAAM,GAClB,QAAQ,YAAY,KAClB,MAAM,IAAI,OAAO,CAAC,YAAY,EAAE;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAIjB,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAC1C,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EACrC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,GACV,QAAQ,GAAG,IAAI,CAiCjB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EACtD,IAAI,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EACvB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,EACC,OAAO,EACP,QAAuB,EACvB,OAAO,GACP,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GACjD,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAU1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-land.d.ts","sourceRoot":"","sources":["../../src/session/link-land.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"link-land.d.ts","sourceRoot":"","sources":["../../src/session/link-land.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkBxE;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EACnD,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3B,MAAM,EAAE,YAAY,EACpB,EACC,OAAO,EACP,QAAQ,EACR,KAAK,EACL,OAAO,GACP,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,QAAQ,GAAG,UAAU,CAAC,CAsBhC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EACnD,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,EAAE,OAAO,EAAE,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAA;CAAO,GACpD,OAAO,CAAC,QAAQ,CAAC,CAYnB"}
|
|
@@ -17,7 +17,7 @@ export interface AuthLinksOptions<L extends string, C = undefined> {
|
|
|
17
17
|
* The app's sign-in flow: it lands the sessions a link opens, and its
|
|
18
18
|
* `cookies`, `errors` and `json` are the ones the links use.
|
|
19
19
|
*/
|
|
20
|
-
readonly signIn: SignInFlow<L, C>;
|
|
20
|
+
readonly signIn: SignInFlow<L, C, boolean>;
|
|
21
21
|
/** The codes the links tell apart; `@nxgt/janus`'s by default. */
|
|
22
22
|
readonly codes?: AuthLinksCodes | undefined;
|
|
23
23
|
/**
|
|
@@ -39,7 +39,7 @@ export interface AuthLinksOptions<L extends string, C = undefined> {
|
|
|
39
39
|
readonly invalidState?: string | undefined;
|
|
40
40
|
}
|
|
41
41
|
/** The options with what they read of the flow: the functions take this. */
|
|
42
|
-
export type LinksContext<L extends string, C = undefined> = AuthLinksOptions<L, C> & Pick<SignInFlow<L, C>, 'cookies' | 'errors' | 'json'>;
|
|
42
|
+
export type LinksContext<L extends string, C = undefined> = AuthLinksOptions<L, C> & Pick<SignInFlow<L, C, boolean>, 'cookies' | 'errors' | 'json'>;
|
|
43
43
|
/** What a token page answers when it stays on the page. */
|
|
44
44
|
export type LinkStayed = ReturnType<typeof data<FormErrors>>;
|
|
45
45
|
/** A link request's answer: always "sent", whoever the e-mail is. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-types.d.ts","sourceRoot":"","sources":["../../src/session/link-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE7D,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAChE;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS;IAChE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"link-types.d.ts","sourceRoot":"","sources":["../../src/session/link-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SignInFlow, SignInFlowOptions } from './flow-types';
|
|
1
|
+
import type { SignInFlow, SignInFlowOptions, SignInFlowWithoutSecondFactorOptions } from './flow-types';
|
|
2
2
|
/**
|
|
3
3
|
* The server side of a BFF's sign-in, over the cookies, the app's
|
|
4
4
|
* `createApiErrors` and its `jsonActions`: where an answer lands, the form
|
|
@@ -14,5 +14,6 @@ import type { SignInFlow, SignInFlowOptions } from './flow-types';
|
|
|
14
14
|
* attemptsLeft: (count, language) => t('auth.attempts-left', { count }, language),
|
|
15
15
|
* });
|
|
16
16
|
*/
|
|
17
|
-
export declare function signInFlow<L extends string, C = undefined>(options: SignInFlowOptions<L, C>): SignInFlow<L, C>;
|
|
17
|
+
export declare function signInFlow<L extends string, C = undefined>(options: SignInFlowOptions<L, C>): SignInFlow<L, C, true>;
|
|
18
|
+
export declare function signInFlow<L extends string, C = undefined>(options: SignInFlowWithoutSecondFactorOptions<L, C>): SignInFlow<L, C, false>;
|
|
18
19
|
//# sourceMappingURL=sign-in.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-in.d.ts","sourceRoot":"","sources":["../../src/session/sign-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sign-in.d.ts","sourceRoot":"","sources":["../../src/session/sign-in.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEX,UAAU,EAEV,iBAAiB,EACjB,oCAAoC,EACpC,MAAM,cAAc,CAAC;AA6CtB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,EACzD,OAAO,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC9B,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AAC1B,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,EACzD,OAAO,EAAE,oCAAoC,CAAC,CAAC,EAAE,CAAC,CAAC,GACjD,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/session/viewer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/session/viewer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD,sEAAsE;AACtE,eAAO,MAAM,SAAS,GAAI,SAAS,OAAO,KAAG,MACW,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EACjD,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,GACd,QAAQ,CAWV;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,EAClD,EAAE,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1C,KAAK,GAAE,MAAM,GAAG,IAAI,GAAG,SAA0C,GAC/D,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAO/B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,EACzD,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1C,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GACrC,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC,CAiB9C;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAChD,IAAI,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EACvB,OAAO,EAAE,OAAO,EAChB,EACC,EAAE,EACF,OAAO,GACP,GAAE;IACF,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CAC5B,GACJ,OAAO,CAAC,QAAQ,CAAC,CAgBnB"}
|
package/docs/guide/errors.md
CHANGED
|
@@ -62,7 +62,8 @@ export function codeOf(error: unknown) {
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
An `ApiError` is assignable to `ApiErrorLike` as it is. The shape's code is
|
|
65
|
-
the API's own `<module>.errors.<slug>`, such as `todos.errors.title-taken
|
|
65
|
+
the API's own `<module>.errors.<slug>`, such as `todos.errors.title-taken`
|
|
66
|
+
or `userProfiles.errors.slug-taken` (the module is kebab-case or camelCase).
|
|
66
67
|
|
|
67
68
|
`waitMinutes` reads a throttle's wait the way the API words it: the
|
|
68
69
|
`minutes` of `extensions.params` or beside it, at least one, else the
|
|
@@ -261,7 +262,8 @@ it once, at module scope: a new function re-creates the resolver.
|
|
|
261
262
|
Two options adapt it. `codeOf(issue)` says which code an issue carries (the
|
|
262
263
|
refinement's `params.code` by default); an app that also words an empty field
|
|
263
264
|
as the API's `validation.errors.required` passes its own. `isApiCode(key)`
|
|
264
|
-
says which keys are API codes (`<module>.errors.<slug>` by default
|
|
265
|
+
says which keys are API codes (`<module>.errors.<slug>` by default, the
|
|
266
|
+
module in kebab-case or camelCase).
|
|
265
267
|
|
|
266
268
|
```ts
|
|
267
269
|
import { apiCodeResolver } from '@alxia/react-router/errors';
|
|
@@ -397,8 +399,9 @@ code), `translateCode`'s, nor the entries of `extensions.fields`, which go
|
|
|
397
399
|
straight to the catalogue.
|
|
398
400
|
|
|
399
401
|
`isApiCode` changes what counts as an API code (`<module>.errors.<slug>` by
|
|
400
|
-
default). Here only the codes of the
|
|
401
|
-
other code, even one shaped like a
|
|
402
|
+
default, the module in kebab-case or camelCase). Here only the codes of the
|
|
403
|
+
`todos` module are the catalogue's; any other code, even one shaped like a
|
|
404
|
+
catalogue code, says `refused`:
|
|
402
405
|
|
|
403
406
|
```ts
|
|
404
407
|
export const apiErrors = createApiErrors<'en' | 'fr'>({
|
package/docs/guide/session.md
CHANGED
|
@@ -342,7 +342,8 @@ decides when a session is over.
|
|
|
342
342
|
`commit` takes the expiry as an ISO string or a `Date`, and sets `Max-Age`
|
|
343
343
|
to the seconds left: floored, and 0 for a past or unreadable date.
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
With no `challenge` option the cookies have no challenge helpers, and `names`
|
|
346
|
+
holds the session alone (`SessionCookies<false>`). The challenge has its own three: `commitChallenge(challenge, expiresAt?)`,
|
|
346
347
|
`challengeOf(request)`, `destroyChallenge()`.
|
|
347
348
|
|
|
348
349
|
`cookies.names` holds the names as sent, prefixes included
|
|
@@ -543,6 +544,30 @@ without a cookie or when the API cannot tell.
|
|
|
543
544
|
|
|
544
545
|
## The second factor
|
|
545
546
|
|
|
547
|
+
A second factor is optional. An API with none builds the cookies without
|
|
548
|
+
`challenge` and the flow without `attemptsLeft`. Neither carries a
|
|
549
|
+
second-factor member on its type, a `secondFactor` answer lands nowhere
|
|
550
|
+
(`landing` returns `null`), and no challenge cookie is set or cleared:
|
|
551
|
+
|
|
552
|
+
```ts
|
|
553
|
+
export const cookies = sessionCookies({ session: 'my-app_session', secure: true });
|
|
554
|
+
export const signIn = signInFlow({ cookies, errors, json, revoke });
|
|
555
|
+
// signIn.codeStep, signIn.readCodeInput and cookies.challengeOf do not exist.
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Give both or neither: `signInFlow` refuses cookies with a challenge and no
|
|
559
|
+
`attemptsLeft` at compile time, and throws a TypeError at runtime when only
|
|
560
|
+
one is given ([troubleshooting](../troubleshooting.md)). To type a helper
|
|
561
|
+
that takes the flow or the cookies, use `SignInFlow<L, C, false>` and
|
|
562
|
+
`SessionCookies<false>` (no second factor), `SignInFlow<L, C>` and
|
|
563
|
+
`SessionCookies` (one), or `SignInFlow<L, C, boolean>` and
|
|
564
|
+
`SessionCookies<boolean>` for either. `signInFlow` itself takes
|
|
565
|
+
`SessionCookies<true>` or `SessionCookies<false>`, not the union: when
|
|
566
|
+
`challenge` may be `undefined`, `sessionCookies` returns
|
|
567
|
+
`SessionCookies<boolean>`, so branch on `challenge` and call `sessionCookies`
|
|
568
|
+
in each branch. `stepUpSteps` takes a flow with a second factor; `authLinks`
|
|
569
|
+
takes either. The rest of this section is for an app that has one.
|
|
570
|
+
|
|
546
571
|
The sign-in page's answer `secondFactor` leads to the second-factor page,
|
|
547
572
|
whose loader needs the challenge cookie (`cookies.challengeOf(request)`; back
|
|
548
573
|
to the sign-in page without one) and whose action posts the code.
|
package/docs/roadmap.md
CHANGED
|
@@ -85,8 +85,8 @@ Nothing planned.
|
|
|
85
85
|
- **`@alxia/react-router/session` and `/session/model`: a BFF session for a
|
|
86
86
|
janus API.** An app that is the backend of its own pages and calls a GraphQL
|
|
87
87
|
API that signs users in with `@nxgt/janus` gets its session from one place:
|
|
88
|
-
`sessionCookies` (the session and the
|
|
89
|
-
HttpOnly cookie), `signInFlow` (where a sign-in lands, the second factor,
|
|
88
|
+
`sessionCookies` (the session and, when the API has one, the second-factor
|
|
89
|
+
challenge, in an HttpOnly cookie), `signInFlow` (where a sign-in lands, the second factor,
|
|
90
90
|
the viewer, sign-out), `stepUpSteps` (the code asked before a sensitive
|
|
91
91
|
action), `authLinks` and `TOKEN_PAGE_HEADERS` (the pages a mail's link
|
|
92
92
|
opens). `/session/model` imports nothing and is safe in a component: `safeNext`
|
package/docs/troubleshooting.md
CHANGED
|
@@ -32,6 +32,7 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
32
32
|
- [`useNonce()` is undefined on the server](#usenonce-is-undefined-on-the-server)
|
|
33
33
|
- [`TypeError: InlineScript(): the code contains "</script" or "<!--", which ends or confuses the script element; escape it, such as "<\/script" inside a string`](#typeerror-inlinescript-the-code-contains-script-or----which-ends-or-confuses-the-script-element-escape-it-such-as-script-inside-a-string)
|
|
34
34
|
- [`TypeError: createPageLanguage(): the fallback … is not one of the languages; got ….`](#typeerror-createpagelanguage-the-fallback--is-not-one-of-the-languages-got-)
|
|
35
|
+
- [`TypeError: signInFlow(): a second factor needs both the challenge cookie (sessionCookies({ challenge })) and attemptsLeft; without one, give neither.`](#typeerror-signinflow-a-second-factor-needs-both-the-challenge-cookie-sessioncookies-challenge--and-attemptsleft-without-one-give-neither)
|
|
35
36
|
- [The error page shows in the fallback language](#the-error-page-shows-in-the-fallback-language)
|
|
36
37
|
- [`Error: You must render this element inside a <HydratedRouter> element`](#error-you-must-render-this-element-inside-a-hydratedrouter-element)
|
|
37
38
|
- [`alxia-react-router: … already exists, and reveal leaves it as it is. Run alxia-react-router reveal --force to overwrite it.`](#alxia-react-router--already-exists-and-reveal-leaves-it-as-it-is-run-alxia-react-router-reveal---force-to-overwrite-it)
|
|
@@ -764,6 +765,33 @@ source than the fallback.
|
|
|
764
765
|
createPageLanguage({ languages: ['en', 'fr'], fallback: 'en' });
|
|
765
766
|
```
|
|
766
767
|
|
|
768
|
+
### `TypeError: signInFlow(): a second factor needs both the challenge cookie (sessionCookies({ challenge })) and attemptsLeft; without one, give neither.`
|
|
769
|
+
|
|
770
|
+
```text
|
|
771
|
+
TypeError: signInFlow(): a second factor needs both the challenge cookie (sessionCookies({ challenge })) and attemptsLeft; without one, give neither.
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
**When:** the module that calls `signInFlow` loads.
|
|
775
|
+
|
|
776
|
+
**Why:** a second factor is the challenge cookie (`sessionCookies({ challenge })`)
|
|
777
|
+
and the `attemptsLeft` wording together. The flow got only one: cookies with
|
|
778
|
+
a challenge and no `attemptsLeft`, or an `attemptsLeft` and cookies built
|
|
779
|
+
without `challenge`. TypeScript refuses the first when the cookies are typed
|
|
780
|
+
`SessionCookies<true>`; a set typed `SessionCookies<boolean>` (a `challenge`
|
|
781
|
+
that may be `undefined`) or a call from JavaScript reaches this check.
|
|
782
|
+
|
|
783
|
+
**Fix:** give both, or neither:
|
|
784
|
+
|
|
785
|
+
```ts
|
|
786
|
+
// with a second factor
|
|
787
|
+
const cookies = sessionCookies({ session: 'my-app_session', challenge: 'my-app_challenge', secure });
|
|
788
|
+
signInFlow({ cookies, errors, json, revoke, attemptsLeft });
|
|
789
|
+
|
|
790
|
+
// without one
|
|
791
|
+
const plain = sessionCookies({ session: 'my-app_session', secure });
|
|
792
|
+
signInFlow({ cookies: plain, errors, json, revoke });
|
|
793
|
+
```
|
|
794
|
+
|
|
767
795
|
### The error page shows in the fallback language
|
|
768
796
|
|
|
769
797
|
**When:** on an error document, the root's `<html lang>` or text shows the
|
|
@@ -2428,6 +2456,9 @@ failed before the API's validation layer), or a code that `isApiCode`
|
|
|
2428
2456
|
rejects. Without `refused`, `createApiErrors` says the API's own message for
|
|
2429
2457
|
such an error.
|
|
2430
2458
|
|
|
2459
|
+
Versions before the camelCase patch also rejected a camelCase module
|
|
2460
|
+
(`userProfiles.errors.slug-taken`): upgrade, or pass `isApiCode`.
|
|
2461
|
+
|
|
2431
2462
|
**Fix:** pass `refused`, the app's generic refusal; it replaces the raw
|
|
2432
2463
|
message for every error that is not an API code
|
|
2433
2464
|
([wording a refusal](guide/errors.md#wording-a-refusal)):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.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",
|