@alxia/react-router 0.15.1 → 0.17.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 +22 -4
- package/dist/chunks/{index-0tyw54ad.js → index-3jfeew2y.js} +13 -2
- package/dist/chunks/{index-0tyw54ad.js.map → index-3jfeew2y.js.map} +3 -3
- package/dist/session/index.js +15 -3
- package/dist/session/index.js.map +3 -3
- package/dist/session/model/index.js +1 -1
- package/dist/session/model/step-up-answers.d.ts +6 -3
- package/dist/session/model/step-up-answers.d.ts.map +1 -1
- package/dist/session/model/step-up.d.ts.map +1 -1
- package/dist/session/react/index.d.ts +10 -0
- package/dist/session/react/index.d.ts.map +1 -0
- package/dist/session/react/index.js +94 -0
- package/dist/session/react/index.js.map +12 -0
- package/dist/session/react/use-code-field.d.ts +37 -0
- package/dist/session/react/use-code-field.d.ts.map +1 -0
- package/dist/session/react/use-link-param.d.ts +16 -0
- package/dist/session/react/use-link-param.d.ts.map +1 -0
- package/dist/session/react/use-sign-out.d.ts +26 -0
- package/dist/session/react/use-sign-out.d.ts.map +1 -0
- package/dist/session/step-up-types.d.ts +10 -7
- package/dist/session/step-up-types.d.ts.map +1 -1
- package/dist/session/step-up.d.ts +1 -1
- package/dist/session/step-up.d.ts.map +1 -1
- package/docs/README.md +1 -1
- package/docs/guide/session.md +149 -6
- package/docs/roadmap.md +6 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -937,8 +937,9 @@ has the rest.
|
|
|
937
937
|
An app that renders its pages and calls a GraphQL API that signs users in
|
|
938
938
|
with `@nxgt/janus` keeps the API's token in its own HttpOnly cookie.
|
|
939
939
|
`@alxia/react-router/session` holds that session's server side, built on
|
|
940
|
-
`/errors`; `/session/
|
|
941
|
-
|
|
940
|
+
`/errors`; `/session/react` holds the page's hooks around it (`useSignOut`, `useLinkParam`,
|
|
941
|
+
`useCodeField`); `/session/model` imports nothing and is safe in a component.
|
|
942
|
+
`/session` and `/session/model` add no peer; `/session/react` needs `react`, an optional peer.
|
|
942
943
|
|
|
943
944
|
```ts
|
|
944
945
|
// app/session.server.ts
|
|
@@ -1131,12 +1132,29 @@ From `@alxia/react-router/session` (`react-router` and `/errors`' files are its
|
|
|
1131
1132
|
| `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` |
|
|
1132
1133
|
| `signInFlow({ cookies, errors, json, revoke, attemptsLeft, paths?, clear?, unavailable?, codes?, endedParam? })`, `SignInFlow`, `SignInFlowOptions` | the server side of the sign-in pages, which 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), `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` |
|
|
1133
1134
|
| `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`) |
|
|
1134
|
-
| `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 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`
|
|
1135
|
+
| `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)` |
|
|
1135
1136
|
| `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 |
|
|
1136
1137
|
| `authLinks({ signIn, codes?, wording?, start?, resetDone?, invalidState? })`, `AuthLinks`, `AuthLinksOptions`, `AuthLinksCodes` | the pages a mail's link opens, over the flow's cookies, errors and json: `linkArgs`, `spendToken(run, { request, language, path, states, fields? })`, `answerOf`, `landByLink` (`context?`), `afterReset(request, { context? })` (clears the session, the challenge and the flow's cookies), `requestLink(run, { request, language })` (a wait answers `throttled: true` and `retryAfter` when the API gives the seconds; `wording` words every refusal that is not a field's), `statePath` and `ended` |
|
|
1137
1138
|
| `Spent`, `SpendOptions`, `LinkStayed`, `RequestLinkAnswer` | their types |
|
|
1138
1139
|
| `TOKEN_PAGE_HEADERS` | `Referrer-Policy: no-referrer` and `X-Robots-Tag: noindex, nofollow`, for a page whose URL carries a token |
|
|
1139
1140
|
|
|
1141
|
+
From `@alxia/react-router/session/react` (`react` and `react-router` are its only imports; every hook renders on the server):
|
|
1142
|
+
|
|
1143
|
+
| export | |
|
|
1144
|
+
| --- | --- |
|
|
1145
|
+
| `useSignOut({ action?, before? })` | `{ signOut, busy }`: posts `{}` as JSON to `action` (default `/sign-out`) after `before()`, whose failure never keeps the user signed in; `busy` until the navigation ends |
|
|
1146
|
+
| `SIGN_OUT_PATH`, `SignOutOptions`, `signOutAfter(before, submit)` | `/sign-out`, the options, and the step `useSignOut` is built on |
|
|
1147
|
+
| `useLinkParam(name, { drop? }?)`, `LinkParamOptions` | a mail link's query parameter, read once (`null` when absent or empty); `drop: true` removes it from the address bar with `history.replaceState` |
|
|
1148
|
+
| `useCodeField(schema, refusal)`, `CodeField`, `CodeSchema` | a one-code field with no form library: `{ code, setCode, ref, error, check() }` over a synchronous Standard Schema; each new `refusal` object clears the refused code and focuses the input |
|
|
1149
|
+
| `useOnRefusal(refusal, handler)` | the core under it, for any form library: `handler` runs once per new refusal, not for one present at mount |
|
|
1150
|
+
|
|
1151
|
+
```tsx
|
|
1152
|
+
import { useLinkParam, useSignOut } from '@alxia/react-router/session/react';
|
|
1153
|
+
|
|
1154
|
+
const token = useLinkParam('token', { drop: true });
|
|
1155
|
+
const { signOut, busy } = useSignOut();
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1140
1158
|
From `@alxia/react-router/session/model` (no import at all):
|
|
1141
1159
|
|
|
1142
1160
|
| export | |
|
|
@@ -1147,7 +1165,7 @@ From `@alxia/react-router/session/model` (no import at all):
|
|
|
1147
1165
|
| `SecondFactorKind`, `SignInStatus`, `StepUpVia` | `'code' \| 'recovery'`, `'signedIn' \| 'secondFactor'` and `'email' \| 'secondFactor'` |
|
|
1148
1166
|
| `stepUpReducer`, `INITIAL_STEP_UP`, `StepUpState`, `StepUpAction`, `StepUpPhase` | the step-up's state on the page, with no React: `phase`, `via`, `challenge`, `attemptsLeft`, `locked`, `error`, `message` (the last refusal worded), `retryAfter`, `pending`, `resent` |
|
|
1149
1167
|
| `stepUpProps(state)`, `StepUpProps` | what a code form shows (`via`, `attemptsLeft`, `locked`, `error`, `retryAfter`, `pending`, `resent`; never the challenge or the message), for a step-up dialog's props |
|
|
1150
|
-
| `StepUpRequestAnswer`, `StepUpConfirmAnswer`, `StepUpError` | what `stepUpSteps` answers, which the reducer takes as it is; `StepUpError` is `'invalid' \| 'expired' \| 'failed' \| 'throttled'` |
|
|
1168
|
+
| `StepUpRequestAnswer`, `StepUpConfirmAnswer`, `StepUpError` | what `stepUpSteps` answers, which the reducer takes as it is (a throttle carries `retryAfter`); `StepUpError` is `'invalid' \| 'expired' \| 'failed' \| 'throttled'` |
|
|
1151
1169
|
|
|
1152
1170
|
From `@alxia/react-router/document`:
|
|
1153
1171
|
|
|
@@ -95,6 +95,17 @@ function refused(state, answer) {
|
|
|
95
95
|
resent: false
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
+
if (answer.error === "throttled") {
|
|
99
|
+
return {
|
|
100
|
+
...state,
|
|
101
|
+
phase: "code",
|
|
102
|
+
error: "throttled",
|
|
103
|
+
message: answer.message,
|
|
104
|
+
retryAfter: answer.retryAfter,
|
|
105
|
+
pending: false,
|
|
106
|
+
resent: false
|
|
107
|
+
};
|
|
108
|
+
}
|
|
98
109
|
return {
|
|
99
110
|
...state,
|
|
100
111
|
phase: "code",
|
|
@@ -156,5 +167,5 @@ function stepUpProps2(state) {
|
|
|
156
167
|
}
|
|
157
168
|
export { HOME2, safeNext2, sitePath, SIGN_IN_PATHS2, signInPath2, secondFactorPath2, TOTP_CODE2, INITIAL_STEP_UP2, stepUpReducer2, stepUpProps2 };
|
|
158
169
|
|
|
159
|
-
//# debugId=
|
|
160
|
-
//# sourceMappingURL=index-
|
|
170
|
+
//# debugId=E77CC5BBAAF44F7C64756E2164756E21
|
|
171
|
+
//# sourceMappingURL=index-3jfeew2y.js.map
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
"import { safeNext } from './safe-next';\n\n/**\n * A path of this site, or a `TypeError` naming `label`. With no `query`, the\n * path holds no `?` or `#` either, and the message prints it only up to\n * there, since what follows may be a token.\n */\nexport function sitePath(\n\tpath: string,\n\t{\n\t\tlabel,\n\t\tquery = false,\n\t}: { readonly label: string; readonly query?: boolean | undefined },\n): string {\n\tif (safeNext(path) !== path || (!query && /[?#]/.test(path))) {\n\t\tconst shown = query ? path : path.replace(/[?#].*$/s, '?…');\n\t\tthrow new TypeError(\n\t\t\t`${label} must be a path of this site${query ? '' : ' with no query or fragment'}, starting with a single \"/\"; got ${JSON.stringify(shown)}.`,\n\t\t);\n\t}\n\treturn path;\n}\n",
|
|
7
7
|
"import { HOME, safeNext } from './safe-next';\nimport { sitePath } from './site-path';\n\n/** The two pages of a sign-in. */\nexport interface SignInPaths {\n\treadonly signIn: string;\n\treadonly secondFactor: string;\n}\n\n/** The defaults: `/sign-in` and `/sign-in/second-factor`. */\nexport const SIGN_IN_PATHS: SignInPaths = {\n\tsignIn: '/sign-in',\n\tsecondFactor: '/sign-in/second-factor',\n};\n\nfunction withNext(\n\tpath: string,\n\tnext: string,\n\tquery?: Record<string, string>,\n): string {\n\tconst params = new URLSearchParams(query);\n\tconst target = safeNext(next);\n\tif (target !== HOME) params.set('next', target);\n\tconst search = params.toString();\n\treturn search ? `${path}?${search}` : path;\n}\n\n/**\n * The sign-in page's URL, coming back to `next` (none for the home page, and\n * `next` goes through `safeNext`). `query` adds parameters, such as\n * `{ expired: '1' }`; `path` replaces `/sign-in` and must be a path of this\n * site with no query or fragment (a `TypeError` otherwise).\n *\n * @example\n * signInPath('/orders'); // '/sign-in?next=%2Forders'\n * signInPath('/', { query: { expired: '1' } }); // '/sign-in?expired=1'\n */\nexport function signInPath(\n\tnext: string,\n\toptions: {\n\t\treadonly query?: Record<string, string> | undefined;\n\t\treadonly path?: string | undefined;\n\t} = {},\n): string {\n\tconst path =\n\t\toptions.path === undefined\n\t\t\t? SIGN_IN_PATHS.signIn\n\t\t\t: sitePath(options.path, { label: 'signInPath(): options.path' });\n\treturn withNext(path, next, options.query);\n}\n\n/** The second-factor page's URL, coming back to `next` as `signInPath` does. */\nexport function secondFactorPath(\n\tnext: string,\n\tpath: string = SIGN_IN_PATHS.secondFactor,\n): string {\n\treturn withNext(path, next);\n}\n",
|
|
8
8
|
"/** A code of an authenticator app: six digits. */\nexport const TOTP_CODE: RegExp = /^\\d{6}$/;\n\n/**\n * What a second-factor form sends: `code` is the issued code (an app's, or\n * the one mailed), `recovery` a recovery code. Janus has no name for it, only\n * `confirm` and `recover`.\n */\nexport type SecondFactorKind = 'code' | 'recovery';\n\n/** How a sign-in ended, in `@nxgt/janus`'s words (`SignInResult['status']`). */\nexport type SignInStatus = 'signedIn' | 'secondFactor';\n\n/**\n * How a step-up is confirmed, in `@nxgt/janus`'s words: a code mailed to the\n * current address, or the account's second factor.\n */\nexport type StepUpVia = 'email' | 'secondFactor';\n",
|
|
9
|
-
"import type { StepUpVia } from './second-factor';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n} from './step-up-answers';\n\n/** Where a step-up is. */\nexport type StepUpPhase =\n\t| 'idle'\n\t| 'requesting'\n\t| 'code'\n\t| 'confirming'\n\t| 'done';\n\nexport interface StepUpState {\n\treadonly phase: StepUpPhase;\n\t/** How the challenge held (or the last one) is confirmed. */\n\treadonly via?: StepUpVia | undefined;\n\t/** The challenge held. A secret: never in a URL, a log or loader data. */\n\treadonly challenge?: string | undefined;\n\t/** The tries the last refused code left. */\n\treadonly attemptsLeft?: number | undefined;\n\t/** No try left on an app or recovery code: wait, asking again would fail too. */\n\treadonly locked: boolean;\n\treadonly error?: StepUpError | undefined;\n\t/** The last refusal worded for the page, until the next step or the release. */\n\treadonly message?: string | undefined;\n\t/** The seconds a throttled request asks to wait before asking again. */\n\treadonly retryAfter?: number | undefined;\n\t/** A request or a code is in flight. */\n\treadonly pending: boolean;\n\t/** The last request replaced a challenge that was held. */\n\treadonly resent: boolean;\n}\n\nexport type StepUpAction =\n\t| { readonly type: 'start' }\n\t| { readonly type: 'requested'; readonly answer: StepUpRequestAnswer }\n\t| { readonly type: 'submit' }\n\t| { readonly type: 'confirmed'; readonly answer: StepUpConfirmAnswer }\n\t| { readonly type: 'release' };\n\nexport const INITIAL_STEP_UP: StepUpState = {\n\tphase: 'idle',\n\tlocked: false,\n\tpending: false,\n\tresent: false,\n};\n\nfunction requested(\n\tstate: StepUpState,\n\tanswer: StepUpRequestAnswer,\n): StepUpState {\n\tif (!answer.ok) {\n\t\t// A resend refused leaves the code form up, and says why in it.\n\t\treturn {\n\t\t\t...state,\n\t\t\tphase: state.challenge ? 'code' : 'idle',\n\t\t\terror: answer.error,\n\t\t\tmessage: answer.message,\n\t\t\tretryAfter: answer.retryAfter,\n\t\t\tpending: false,\n\t\t\tresent: false,\n\t\t};\n\t}\n\treturn {\n\t\tphase: 'code',\n\t\tvia: answer.via,\n\t\tchallenge: answer.challenge,\n\t\tlocked: false,\n\t\tpending: false,\n\t\tresent: state.challenge !== undefined,\n\t};\n}\n\n/** A refused code. At 0 tries left a mailed code is over (ask again), an app or recovery code is locked (wait). */\nfunction refused(\n\tstate: StepUpState,\n\tanswer: Extract<StepUpConfirmAnswer, { ok: false }>,\n): StepUpState {\n\tconst none = answer.attemptsLeft === 0;\n\tconst over = answer.error === 'expired' || (none && state.via === 'email');\n\tif (over) {\n\t\treturn {\n\t\t\tphase: 'idle',\n\t\t\t...(state.via ? { via: state.via } : {}),\n\t\t\tlocked: false,\n\t\t\terror: 'expired',\n\t\t\tmessage: answer.message,\n\t\t\tpending: false,\n\t\t\tresent: false,\n\t\t};\n\t}\n\treturn {\n\t\t...state,\n\t\tphase: 'code',\n\t\terror: answer.error,\n\t\tmessage: answer.message,\n\t\tretryAfter: undefined,\n\t\tattemptsLeft: answer.attemptsLeft,\n\t\tlocked: answer.locked || none,\n\t\tpending: false,\n\t\tresent: false,\n\t};\n}\n\n/**\n * The step-up's transitions, pure. `start` (a request in flight) forgets the\n * last error but keeps a challenge held, so a refused \"Resend code\" leaves\n * the code form up; a refusal keeps its `message` (and a throttle its\n * `retryAfter`) until the next step; a granted request replaces the challenge; a code accepted\n * spends it; an expired or spent one leaves \"ask again\"; at 0 tries left a\n * mailed code is `expired` and an app or recovery code is `locked`.\n */\nexport function stepUpReducer(\n\tstate: StepUpState,\n\taction: StepUpAction,\n): StepUpState {\n\tswitch (action.type) {\n\t\tcase 'start':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tphase: state.challenge ? 'code' : 'requesting',\n\t\t\t\terror: undefined,\n\t\t\t\tmessage: undefined,\n\t\t\t\tretryAfter: undefined,\n\t\t\t\tpending: true,\n\t\t\t\tresent: false,\n\t\t\t};\n\t\tcase 'requested':\n\t\t\treturn requested(state, action.answer);\n\t\tcase 'submit':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tphase: 'confirming',\n\t\t\t\terror: undefined,\n\t\t\t\tmessage: undefined,\n\t\t\t\tretryAfter: undefined,\n\t\t\t\tpending: true,\n\t\t\t};\n\t\tcase 'confirmed':\n\t\t\treturn action.answer.ok\n\t\t\t\t? {\n\t\t\t\t\t\tphase: 'done',\n\t\t\t\t\t\t...(state.via ? { via: state.via } : {}),\n\t\t\t\t\t\tlocked: false,\n\t\t\t\t\t\tpending: false,\n\t\t\t\t\t\tresent: false,\n\t\t\t\t\t}\n\t\t\t\t: refused(state, action.answer);\n\t\tcase 'release':\n\t\t\treturn INITIAL_STEP_UP;\n\t}\n}\n",
|
|
9
|
+
"import type { StepUpVia } from './second-factor';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n} from './step-up-answers';\n\n/** Where a step-up is. */\nexport type StepUpPhase =\n\t| 'idle'\n\t| 'requesting'\n\t| 'code'\n\t| 'confirming'\n\t| 'done';\n\nexport interface StepUpState {\n\treadonly phase: StepUpPhase;\n\t/** How the challenge held (or the last one) is confirmed. */\n\treadonly via?: StepUpVia | undefined;\n\t/** The challenge held. A secret: never in a URL, a log or loader data. */\n\treadonly challenge?: string | undefined;\n\t/** The tries the last refused code left. */\n\treadonly attemptsLeft?: number | undefined;\n\t/** No try left on an app or recovery code: wait, asking again would fail too. */\n\treadonly locked: boolean;\n\treadonly error?: StepUpError | undefined;\n\t/** The last refusal worded for the page, until the next step or the release. */\n\treadonly message?: string | undefined;\n\t/** The seconds a throttled request asks to wait before asking again. */\n\treadonly retryAfter?: number | undefined;\n\t/** A request or a code is in flight. */\n\treadonly pending: boolean;\n\t/** The last request replaced a challenge that was held. */\n\treadonly resent: boolean;\n}\n\nexport type StepUpAction =\n\t| { readonly type: 'start' }\n\t| { readonly type: 'requested'; readonly answer: StepUpRequestAnswer }\n\t| { readonly type: 'submit' }\n\t| { readonly type: 'confirmed'; readonly answer: StepUpConfirmAnswer }\n\t| { readonly type: 'release' };\n\nexport const INITIAL_STEP_UP: StepUpState = {\n\tphase: 'idle',\n\tlocked: false,\n\tpending: false,\n\tresent: false,\n};\n\nfunction requested(\n\tstate: StepUpState,\n\tanswer: StepUpRequestAnswer,\n): StepUpState {\n\tif (!answer.ok) {\n\t\t// A resend refused leaves the code form up, and says why in it.\n\t\treturn {\n\t\t\t...state,\n\t\t\tphase: state.challenge ? 'code' : 'idle',\n\t\t\terror: answer.error,\n\t\t\tmessage: answer.message,\n\t\t\tretryAfter: answer.retryAfter,\n\t\t\tpending: false,\n\t\t\tresent: false,\n\t\t};\n\t}\n\treturn {\n\t\tphase: 'code',\n\t\tvia: answer.via,\n\t\tchallenge: answer.challenge,\n\t\tlocked: false,\n\t\tpending: false,\n\t\tresent: state.challenge !== undefined,\n\t};\n}\n\n/** A refused code. At 0 tries left a mailed code is over (ask again), an app or recovery code is locked (wait). */\nfunction refused(\n\tstate: StepUpState,\n\tanswer: Extract<StepUpConfirmAnswer, { ok: false }>,\n): StepUpState {\n\tconst none = answer.attemptsLeft === 0;\n\tconst over = answer.error === 'expired' || (none && state.via === 'email');\n\tif (over) {\n\t\treturn {\n\t\t\tphase: 'idle',\n\t\t\t...(state.via ? { via: state.via } : {}),\n\t\t\tlocked: false,\n\t\t\terror: 'expired',\n\t\t\tmessage: answer.message,\n\t\t\tpending: false,\n\t\t\tresent: false,\n\t\t};\n\t}\n\tif (answer.error === 'throttled') {\n\t\t// Asking too often spends nothing: the challenge and its tries stay.\n\t\treturn {\n\t\t\t...state,\n\t\t\tphase: 'code',\n\t\t\terror: 'throttled',\n\t\t\tmessage: answer.message,\n\t\t\tretryAfter: answer.retryAfter,\n\t\t\tpending: false,\n\t\t\tresent: false,\n\t\t};\n\t}\n\treturn {\n\t\t...state,\n\t\tphase: 'code',\n\t\terror: answer.error,\n\t\tmessage: answer.message,\n\t\tretryAfter: undefined,\n\t\tattemptsLeft: answer.attemptsLeft,\n\t\tlocked: answer.locked || none,\n\t\tpending: false,\n\t\tresent: false,\n\t};\n}\n\n/**\n * The step-up's transitions, pure. `start` (a request in flight) forgets the\n * last error but keeps a challenge held, so a refused \"Resend code\" leaves\n * the code form up; a refusal keeps its `message` (and a throttle its\n * `retryAfter`) until the next step; a granted request replaces the challenge; a code accepted\n * spends it; an expired or spent one leaves \"ask again\"; at 0 tries left a\n * mailed code is `expired` and an app or recovery code is `locked`.\n */\nexport function stepUpReducer(\n\tstate: StepUpState,\n\taction: StepUpAction,\n): StepUpState {\n\tswitch (action.type) {\n\t\tcase 'start':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tphase: state.challenge ? 'code' : 'requesting',\n\t\t\t\terror: undefined,\n\t\t\t\tmessage: undefined,\n\t\t\t\tretryAfter: undefined,\n\t\t\t\tpending: true,\n\t\t\t\tresent: false,\n\t\t\t};\n\t\tcase 'requested':\n\t\t\treturn requested(state, action.answer);\n\t\tcase 'submit':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tphase: 'confirming',\n\t\t\t\terror: undefined,\n\t\t\t\tmessage: undefined,\n\t\t\t\tretryAfter: undefined,\n\t\t\t\tpending: true,\n\t\t\t};\n\t\tcase 'confirmed':\n\t\t\treturn action.answer.ok\n\t\t\t\t? {\n\t\t\t\t\t\tphase: 'done',\n\t\t\t\t\t\t...(state.via ? { via: state.via } : {}),\n\t\t\t\t\t\tlocked: false,\n\t\t\t\t\t\tpending: false,\n\t\t\t\t\t\tresent: false,\n\t\t\t\t\t}\n\t\t\t\t: refused(state, action.answer);\n\t\tcase 'release':\n\t\t\treturn INITIAL_STEP_UP;\n\t}\n}\n",
|
|
10
10
|
"import type { StepUpVia } from './second-factor';\nimport type { StepUpState } from './step-up';\nimport type { StepUpError } from './step-up-answers';\n\n/**\n * The props of `@nxgt/material`'s `VerificationCode` and `StepUpDialog` that\n * the state decides. The state's `message` is not one: the dialog words its\n * own texts from `error`, `attemptsLeft`, `locked` and `retryAfter`. The callbacks (`onSubmit`, `onResend`) are the app's.\n */\nexport interface StepUpProps {\n\treadonly via?: StepUpVia;\n\treadonly attemptsLeft?: number;\n\treadonly locked: boolean;\n\treadonly error?: StepUpError;\n\t/** The seconds to wait when `error` is `throttled` and the API said how long. */\n\treadonly retryAfter?: number;\n\treadonly pending: boolean;\n\treadonly resent: boolean;\n}\n\n/** The state as the dialog's props: `{ ...stepUpProps(state), onSubmit, onResend }`. */\nexport function stepUpProps(state: StepUpState): StepUpProps {\n\treturn {\n\t\t...(state.via ? { via: state.via } : {}),\n\t\t...(state.attemptsLeft === undefined\n\t\t\t? {}\n\t\t\t: { attemptsLeft: state.attemptsLeft }),\n\t\tlocked: state.locked,\n\t\t...(state.error ? { error: state.error } : {}),\n\t\t...(state.retryAfter === undefined ? {} : { retryAfter: state.retryAfter }),\n\t\tpending: state.pending,\n\t\tresent: state.resent,\n\t};\n}\n"
|
|
11
11
|
],
|
|
12
|
-
"mappings": "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
|
|
13
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "E77CC5BBAAF44F7C64756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
package/dist/session/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
SIGN_IN_PATHS2,
|
|
15
15
|
signInPath2,
|
|
16
16
|
secondFactorPath2
|
|
17
|
-
} from "../chunks/index-
|
|
17
|
+
} from "../chunks/index-3jfeew2y.js";
|
|
18
18
|
|
|
19
19
|
// src/session/codes.ts
|
|
20
20
|
var INVALID_CODE = "CODE_INVALID";
|
|
@@ -570,6 +570,9 @@ function refusedCode(context, error, via, language) {
|
|
|
570
570
|
message
|
|
571
571
|
};
|
|
572
572
|
}
|
|
573
|
+
function isThrottle(context, error) {
|
|
574
|
+
return error.status === 429 || error.code === context.mailThrottled;
|
|
575
|
+
}
|
|
573
576
|
async function requestStep(context, run, { request, language }) {
|
|
574
577
|
samesitePost(context.steps.signIn.json, request);
|
|
575
578
|
const intent = "request-step-up";
|
|
@@ -582,7 +585,7 @@ async function requestStep(context, run, { request, language }) {
|
|
|
582
585
|
throw error;
|
|
583
586
|
const api = isApiErrorLike2(error);
|
|
584
587
|
const message = api ? worded2(context, error, language) : refusal.message;
|
|
585
|
-
const throttled = api && error
|
|
588
|
+
const throttled = api && isThrottle(context, error);
|
|
586
589
|
const retryAfter = throttled ? retryAfterOf(error) : undefined;
|
|
587
590
|
return data6({
|
|
588
591
|
ok: false,
|
|
@@ -607,6 +610,15 @@ async function confirmStep(context, run, { request, language, via }) {
|
|
|
607
610
|
const failed = (message) => stay({ error: "failed", locked: false, message });
|
|
608
611
|
if (!isApiErrorLike2(error))
|
|
609
612
|
return failed(refusal.message);
|
|
613
|
+
if (error.status === 429) {
|
|
614
|
+
const retryAfter = retryAfterOf(error);
|
|
615
|
+
return stay({
|
|
616
|
+
error: "throttled",
|
|
617
|
+
locked: false,
|
|
618
|
+
message: worded2(context, error, language),
|
|
619
|
+
...retryAfter === undefined ? {} : { retryAfter }
|
|
620
|
+
});
|
|
621
|
+
}
|
|
610
622
|
if (error.code === context.invalidCode) {
|
|
611
623
|
return stay(refusedCode(context, error, via, language));
|
|
612
624
|
}
|
|
@@ -644,5 +656,5 @@ export {
|
|
|
644
656
|
stepUpSteps
|
|
645
657
|
};
|
|
646
658
|
|
|
647
|
-
//# debugId=
|
|
659
|
+
//# debugId=C18C44A4DCC5656A64756E2164756E21
|
|
648
660
|
//# sourceMappingURL=index.js.map
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n} from '../errors/api-error';\nimport type {\n\tCodeWording,\n\tFlowContext,\n\tSignInAnswer,\n\tSignInFlow,\n\tSignInFlowOptions,\n\tSignInFormError,\n\tSignInStayed,\n} from './flow-types';\nimport { samesitePost } from './guard';\nimport { landReplacing } from './land';\n\n/**\n * A refused code's message, with the tries left when the API counts them;\n * `undefined` when the challenge is over (gone, or no try left and no\n * `whenNone` to say instead) and the user must sign in again.\n */\nexport function codeRefusal<L extends string>(\n\t{ options, invalidCode, challengeOver }: CodeWording<L>,\n\terror: ApiErrorLike,\n\tlanguage: L,\n\twhenNone?: string,\n): string | undefined {\n\tif (error.code !== invalidCode) {\n\t\treturn error.code && challengeOver.includes(error.code)\n\t\t\t? undefined\n\t\t\t: options.errors.apiErrorMessage(error, language);\n\t}\n\tconst message = options.errors.apiErrorMessage(error, language);\n\tconst count = attemptsLeftOf(error);\n\tif (count === undefined) return message;\n\tif (count === 0) {\n\t\treturn whenNone === undefined ? undefined : `${message} ${whenNone}`;\n\t}\n\treturn `${message} ${options.attemptsLeft(count, language)}`;\n}\n\n/** What a sign-in says when the API cannot be reached. */\nexport const unavailableMessage = <L extends string>(\n\t{ unavailable, errors }: Pick<SignInFlowOptions<L>, 'unavailable' | 'errors'>,\n\tlanguage: L,\n): string => unavailable?.(language) ?? errors.unavailableMessage(language);\n\n/**\n * Runs a sign-in step and redirects where its answer leads, a new session\n * replacing the browser's (`landReplacing`). A refusal is the form's\n * message (a wrong password, a lock with its delay); an unreachable API\n * says `unavailable`, with a 503.\n */\nexport async function signInStep<L extends string, C, T extends object>(\n\tflow: FlowContext<L, C>,\n\trun: () => Promise<SignInAnswer>,\n\t{\n\t\trequest,\n\t\tlanguage,\n\t\tnext,\n\t\textra,\n\t\trefused,\n\t\tcontext,\n\t}: Parameters<SignInFlow<L, C>['signInStep']>[1] & { extra: T },\n): Promise<Response | SignInStayed<T>> {\n\tconst { errors, json } = flow.options;\n\t// A cross-site post must never sign in or revoke (headers only).\n\tsamesitePost(json, request);\n\tconst stay = (formError: string, status: number) =>\n\t\tdata<SignInFormError<T>>({ ...extra, formError }, { status });\n\tconst unreachable = () =>\n\t\tstay(unavailableMessage(flow.options, language), 503);\n\tlet answer: SignInAnswer;\n\ttry {\n\t\tanswer = await run();\n\t} catch (error) {\n\t\tconst refusal = errors.apiRefusal(error, language);\n\t\tif (!refusal) throw error;\n\t\t// An API it cannot reach: sign-in's own words.\n\t\tif (!isApiErrorLike(error)) return unreachable();\n\t\tconst own = refused?.(error);\n\t\tif (own instanceof Response) return own;\n\t\treturn stay(own ?? refusal.message, refusal.status);\n\t}\n\treturn (\n\t\t(await landReplacing(flow, answer, next, { request, context })) ??\n\t\tunreachable()\n\t);\n}\n",
|
|
15
15
|
"import { redirect } from 'react-router';\nimport { isApiErrorLike } from '../errors/api-error';\nimport { nextOf } from '../errors/page-path';\nimport { routeError } from '../errors/route-error';\nimport 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', options.cookies.destroyChallenge());\n\tfor (const cookie of options.clear?.() ?? []) {\n\t\theaders.append('Set-Cookie', cookie);\n\t}\n\treturn redirect(\n\t\tto === undefined ? `${paths.signIn}?signed-out=1` : safeNext(to),\n\t\t{ headers },\n\t);\n}\n",
|
|
16
16
|
"import { hasSiteCheck } from '../errors/same-site';\nimport { CHALLENGE_OVER, INVALID_CODE } from './codes';\nimport type { FlowContext, SignInFlow, SignInFlowOptions } 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>,\n): FlowContext<L, C> {\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> {\n\tconst context = resolve(options);\n\tconst { options: o } = context;\n\treturn {\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\tattemptsLeft: o.attemptsLeft,\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\tcodeRefusal: (error, language, whenNone) =>\n\t\t\tcodeRefusal(context, error, language, whenNone),\n\t\treadCodeInput: (request) => readCodeInput(context, request),\n\t\tcodeStep,\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}\n",
|
|
17
|
-
"import { data } from 'react-router';\nimport {\n\ttype ApiErrorLike,\n\tattemptsLeftOf,\n\tisApiErrorLike,\n\tretryAfterOf,\n} from '../errors/api-error';\nimport { INVALID_CODE, MAIL_THROTTLED } from './codes';\nimport type { CodeWording } from './flow-types';\nimport { samesitePost } from './guard';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpError,\n\tStepUpRequestAnswer,\n\tStepUpVia,\n} from './model';\nimport { codeRefusal } from './step';\nimport { STEP_UP_OVER, STEP_UP_REQUIRED } from './step-up-codes';\nimport type {\n\tStepUpStayed,\n\tStepUpSteps,\n\tStepUpStepsOptions,\n} from './step-up-types';\n\ntype Refused = Extract<StepUpConfirmAnswer, { ok: false }>;\n\ninterface StepUpContext<L extends string> extends CodeWording<L> {\n\treadonly steps: StepUpStepsOptions<L>;\n\treadonly stepUpRequired: string;\n\treadonly mailThrottled: string;\n}\n\nfunction resolve<L extends string>(\n\tsteps: StepUpStepsOptions<L>,\n): StepUpContext<L> {\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>(\n\t{ steps }: StepUpContext<L>,\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>(\n\tcontext: StepUpContext<L>,\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\nasync function requestStep<L extends string>(\n\tcontext: StepUpContext<L>,\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 && error
|
|
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": "C18C44A4DCC5656A64756E2164756E21",
|
|
22
22
|
"names": []
|
|
23
23
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { StepUpVia } from './second-factor';
|
|
2
2
|
/**
|
|
3
|
-
* Why a step-up step failed: a wrong code, a challenge gone, a
|
|
4
|
-
* for asking too often (`throttled
|
|
5
|
-
* long), or anything
|
|
3
|
+
* Why a step-up step failed: a wrong code, a challenge gone, a request held
|
|
4
|
+
* back for asking too often (`throttled`: a mail the API holds back or a rate
|
|
5
|
+
* limit, a 429, with `retryAfter` when the API says how long), or anything
|
|
6
|
+
* else.
|
|
6
7
|
*/
|
|
7
8
|
export type StepUpError = 'invalid' | 'expired' | 'failed' | 'throttled';
|
|
8
9
|
/** What the server answers to a request for a challenge. */
|
|
@@ -36,5 +37,7 @@ export type StepUpConfirmAnswer = {
|
|
|
36
37
|
readonly locked: boolean;
|
|
37
38
|
/** The refusal worded for the page, in its language. */
|
|
38
39
|
readonly message?: string | undefined;
|
|
40
|
+
/** The seconds to wait before trying again (a whole number from 0), when `error` is `throttled` and the API says. */
|
|
41
|
+
readonly retryAfter?: number | undefined;
|
|
39
42
|
};
|
|
40
43
|
//# sourceMappingURL=step-up-answers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-up-answers.d.ts","sourceRoot":"","sources":["../../../src/session/model/step-up-answers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD
|
|
1
|
+
{"version":3,"file":"step-up-answers.d.ts","sourceRoot":"","sources":["../../../src/session/model/step-up-answers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEzE,4DAA4D;AAC5D,MAAM,MAAM,mBAAmB,GAC5B;IACA,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;CACvB,GACD;IACA,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,qHAAqH;IACrH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,CAAC;AAEL;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAC5B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GACzD;IACA,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,qHAAqH;IACrH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../../src/session/model/step-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,MAAM,mBAAmB,CAAC;AAE3B,0BAA0B;AAC1B,MAAM,MAAM,WAAW,GACpB,MAAM,GACN,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,MAAM,CAAC;AAEV,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,4CAA4C;IAC5C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhC,eAAO,MAAM,eAAe,EAAE,WAK7B,CAAC;
|
|
1
|
+
{"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../../src/session/model/step-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,MAAM,mBAAmB,CAAC;AAE3B,0BAA0B;AAC1B,MAAM,MAAM,WAAW,GACpB,MAAM,GACN,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,MAAM,CAAC;AAEV,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,4CAA4C;IAC5C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhC,eAAO,MAAM,eAAe,EAAE,WAK7B,CAAC;AAuEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,YAAY,GAClB,WAAW,CAoCb"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@alxia/react-router/session/react`: the hooks of a page around the
|
|
3
|
+
* session flows `/session` serves: signing out, a mail link's parameter and
|
|
4
|
+
* a one-code field. `react` and `react-router` are its only imports; it
|
|
5
|
+
* shares nothing with the server side of `/session`.
|
|
6
|
+
*/
|
|
7
|
+
export { type CodeField, type CodeSchema, useCodeField, useOnRefusal, } from './use-code-field';
|
|
8
|
+
export { type LinkParamOptions, useLinkParam } from './use-link-param';
|
|
9
|
+
export { SIGN_OUT_PATH, type SignOutOptions, signOutAfter, useSignOut, } from './use-sign-out';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/session/react/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,KAAK,SAAS,EACd,KAAK,UAAU,EACf,YAAY,EACZ,YAAY,GACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,gBAAgB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EACN,aAAa,EACb,KAAK,cAAc,EACnB,YAAY,EACZ,UAAU,GACV,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/session/react/use-code-field.ts
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState
|
|
7
|
+
} from "react";
|
|
8
|
+
function useOnRefusal(refusal, handler) {
|
|
9
|
+
const handled = useRef(refusal);
|
|
10
|
+
const latest = useRef(handler);
|
|
11
|
+
latest.current = handler;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!refusal || handled.current === refusal)
|
|
14
|
+
return;
|
|
15
|
+
handled.current = refusal;
|
|
16
|
+
latest.current();
|
|
17
|
+
}, [refusal]);
|
|
18
|
+
}
|
|
19
|
+
function useCodeField(schema, refusal) {
|
|
20
|
+
const [code, setCodeState] = useState("");
|
|
21
|
+
const [error, setError] = useState();
|
|
22
|
+
const ref = useRef(null);
|
|
23
|
+
const setCode = useCallback((next) => {
|
|
24
|
+
setCodeState(next);
|
|
25
|
+
setError(undefined);
|
|
26
|
+
}, []);
|
|
27
|
+
useOnRefusal(refusal, () => {
|
|
28
|
+
setCode("");
|
|
29
|
+
ref.current?.focus();
|
|
30
|
+
});
|
|
31
|
+
const check = () => {
|
|
32
|
+
const result = schema["~standard"].validate(code);
|
|
33
|
+
if (result instanceof Promise) {
|
|
34
|
+
throw new TypeError("useCodeField takes a synchronous schema");
|
|
35
|
+
}
|
|
36
|
+
const { issues, value } = result;
|
|
37
|
+
if (issues?.length) {
|
|
38
|
+
setError(issues[0]?.message);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setError(undefined);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
return { code, setCode, ref, error, check };
|
|
45
|
+
}
|
|
46
|
+
// src/session/react/use-link-param.ts
|
|
47
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
48
|
+
import { useSearchParams } from "react-router";
|
|
49
|
+
function useLinkParam(name, { drop = false } = {}) {
|
|
50
|
+
const [params] = useSearchParams();
|
|
51
|
+
const [value] = useState2(() => params.get(name) || null);
|
|
52
|
+
useEffect2(() => {
|
|
53
|
+
if (!drop)
|
|
54
|
+
return;
|
|
55
|
+
const url = new URL(window.location.href);
|
|
56
|
+
if (!url.searchParams.has(name))
|
|
57
|
+
return;
|
|
58
|
+
url.searchParams.delete(name);
|
|
59
|
+
window.history.replaceState(window.history.state, "", `${url.pathname}${url.search}${url.hash}`);
|
|
60
|
+
}, [drop, name]);
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
// src/session/react/use-sign-out.ts
|
|
64
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
65
|
+
import { useNavigation, useSubmit } from "react-router";
|
|
66
|
+
var SIGN_OUT_PATH = "/sign-out";
|
|
67
|
+
async function signOutAfter(before, submit) {
|
|
68
|
+
try {
|
|
69
|
+
await before?.();
|
|
70
|
+
} catch {}
|
|
71
|
+
await submit();
|
|
72
|
+
}
|
|
73
|
+
function useSignOut(options = {}) {
|
|
74
|
+
const { action = SIGN_OUT_PATH, before } = options;
|
|
75
|
+
const submit = useSubmit();
|
|
76
|
+
const [preparing, setPreparing] = useState3(false);
|
|
77
|
+
const submitting = useNavigation().formAction === action;
|
|
78
|
+
const signOut = useCallback2(() => {
|
|
79
|
+
setPreparing(true);
|
|
80
|
+
signOutAfter(before, () => submit({}, { method: "post", action, encType: "application/json" })).finally(() => setPreparing(false));
|
|
81
|
+
}, [submit, action, before]);
|
|
82
|
+
return { signOut, busy: preparing || submitting };
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
SIGN_OUT_PATH,
|
|
86
|
+
signOutAfter,
|
|
87
|
+
useCodeField,
|
|
88
|
+
useLinkParam,
|
|
89
|
+
useOnRefusal,
|
|
90
|
+
useSignOut
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
//# debugId=26E2FEF9A38E677964756E2164756E21
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/session/react/use-code-field.ts", "../src/session/react/use-link-param.ts", "../src/session/react/use-sign-out.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from 'react';\n\n/** The part of a Standard Schema (`~standard`) this hook reads; Zod, Valibot and ArkType satisfy it. */\nexport interface CodeSchema {\n\treadonly '~standard': {\n\t\tvalidate(value: unknown): unknown;\n\t};\n}\n\n/**\n * Calls `handler` once for each new `refusal` (a new object each time,\n * `undefined` when there is none). A refusal already there when the\n * component mounted is not new: it is the page's own, seen again.\n * Library-agnostic: pair it with any form library's `reset` and `focus`.\n */\nexport function useOnRefusal(\n\trefusal: object | undefined,\n\thandler: () => void,\n): void {\n\tconst handled = useRef(refusal);\n\tconst latest = useRef(handler);\n\tlatest.current = handler;\n\tuseEffect(() => {\n\t\tif (!refusal || handled.current === refusal) return;\n\t\thandled.current = refusal;\n\t\tlatest.current();\n\t}, [refusal]);\n}\n\nexport interface CodeField {\n\t/** The code typed so far. */\n\treadonly code: string;\n\treadonly setCode: (code: string) => void;\n\t/** On the input, so a refusal can focus it. */\n\treadonly ref: RefObject<HTMLInputElement | null>;\n\t/** The first issue's message of the last `check`, cleared by typing. */\n\treadonly error: string | undefined;\n\t/**\n\t * Validates the code against the schema: the parsed value, or\n\t * `undefined` and `error` set. Synchronous schemas only.\n\t */\n\treadonly check: () => unknown;\n}\n\n/**\n * A one-code field (an authenticator app's code, a recovery code) with no\n * form library: it holds the code, checks it against `schema`, and on each\n * new `refusal` clears the refused code and focuses the input for the next\n * try. With react-hook-form, use `useOnRefusal` and its `setValue` and\n * `setFocus` instead.\n */\nexport function useCodeField(\n\tschema: CodeSchema,\n\trefusal: object | undefined,\n): CodeField {\n\tconst [code, setCodeState] = useState('');\n\tconst [error, setError] = useState<string | undefined>();\n\tconst ref = useRef<HTMLInputElement | null>(null);\n\tconst setCode = useCallback((next: string) => {\n\t\tsetCodeState(next);\n\t\tsetError(undefined);\n\t}, []);\n\tuseOnRefusal(refusal, () => {\n\t\tsetCode('');\n\t\tref.current?.focus();\n\t});\n\tconst check = () => {\n\t\tconst result = schema['~standard'].validate(code);\n\t\tif (result instanceof Promise) {\n\t\t\tthrow new TypeError('useCodeField takes a synchronous schema');\n\t\t}\n\t\tconst { issues, value } = result as {\n\t\t\tissues?: ReadonlyArray<{ message: string }>;\n\t\t\tvalue?: unknown;\n\t\t};\n\t\tif (issues?.length) {\n\t\t\tsetError(issues[0]?.message);\n\t\t\treturn undefined;\n\t\t}\n\t\tsetError(undefined);\n\t\treturn value;\n\t};\n\treturn { code, setCode, ref, error, check };\n}\n",
|
|
6
|
+
"import { useEffect, useState } from 'react';\nimport { useSearchParams } from 'react-router';\n\nexport interface LinkParamOptions {\n\t/**\n\t * Remove the parameter from the address bar once read\n\t * (`history.replaceState`), so a token is not left in the history, a\n\t * bookmark or a shared screen. Default `false`.\n\t */\n\treadonly drop?: boolean;\n}\n\n/**\n * The query parameter a mail's link carries (`token`, `code`, `state`),\n * read once: the value of the first render is kept for the page's life, so\n * dropping it from the address bar never loses it. `null` when absent or\n * empty. Safe to render on the server, where nothing is dropped.\n */\nexport function useLinkParam(\n\tname: string,\n\t{ drop = false }: LinkParamOptions = {},\n): string | null {\n\tconst [params] = useSearchParams();\n\tconst [value] = useState(() => params.get(name) || null);\n\tuseEffect(() => {\n\t\tif (!drop) return;\n\t\tconst url = new URL(window.location.href);\n\t\tif (!url.searchParams.has(name)) return;\n\t\turl.searchParams.delete(name);\n\t\twindow.history.replaceState(\n\t\t\twindow.history.state,\n\t\t\t'',\n\t\t\t`${url.pathname}${url.search}${url.hash}`,\n\t\t);\n\t}, [drop, name]);\n\treturn value;\n}\n",
|
|
7
|
+
"import { useCallback, useState } from 'react';\nimport { useNavigation, useSubmit } from 'react-router';\n\n/** Where `signInFlow`'s sign-out action is mounted unless the app says otherwise. */\nexport const SIGN_OUT_PATH = '/sign-out';\n\nexport interface SignOutOptions {\n\t/** The sign-out route (default `/sign-out`). */\n\treadonly action?: string;\n\t/**\n\t * Runs before the post: clear the worker's caches, a local store. A\n\t * rejection never keeps the user signed in: the sign-out goes on.\n\t */\n\treadonly before?: () => Promise<unknown> | unknown;\n}\n\n/**\n * Runs `before`, then `submit`. A `before` that throws or rejects is\n * ignored, so a failed cleanup cannot keep a session alive.\n */\nexport async function signOutAfter(\n\tbefore: (() => Promise<unknown> | unknown) | undefined,\n\tsubmit: () => Promise<void> | void,\n): Promise<void> {\n\ttry {\n\t\tawait before?.();\n\t} catch {\n\t\t// Signing out matters more than the cleanup.\n\t}\n\tawait submit();\n}\n\n/**\n * The one way a page signs out, wherever the control is: posts `{}` as JSON\n * to the sign-out route (same-origin and JSON only, as `signInFlow`'s action\n * requires). `busy` from the call until the navigation it starts has ended.\n */\nexport function useSignOut(options: SignOutOptions = {}): {\n\tsignOut: () => void;\n\tbusy: boolean;\n} {\n\tconst { action = SIGN_OUT_PATH, before } = options;\n\tconst submit = useSubmit();\n\tconst [preparing, setPreparing] = useState(false);\n\tconst submitting = useNavigation().formAction === action;\n\tconst signOut = useCallback(() => {\n\t\tsetPreparing(true);\n\t\tvoid signOutAfter(before, () =>\n\t\t\tsubmit({}, { method: 'post', action, encType: 'application/json' }),\n\t\t).finally(() => setPreparing(false));\n\t}, [submit, action, before]);\n\treturn { signOut, busy: preparing || submitting };\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": ";AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,SAAS,YAAY,CAC3B,SACA,SACO;AAAA,EACP,MAAM,UAAU,OAAO,OAAO;AAAA,EAC9B,MAAM,SAAS,OAAO,OAAO;AAAA,EAC7B,OAAO,UAAU;AAAA,EACjB,UAAU,MAAM;AAAA,IACf,IAAI,CAAC,WAAW,QAAQ,YAAY;AAAA,MAAS;AAAA,IAC7C,QAAQ,UAAU;AAAA,IAClB,OAAO,QAAQ;AAAA,KACb,CAAC,OAAO,CAAC;AAAA;AAyBN,SAAS,YAAY,CAC3B,QACA,SACY;AAAA,EACZ,OAAO,MAAM,gBAAgB,SAAS,EAAE;AAAA,EACxC,OAAO,OAAO,YAAY,SAA6B;AAAA,EACvD,MAAM,MAAM,OAAgC,IAAI;AAAA,EAChD,MAAM,UAAU,YAAY,CAAC,SAAiB;AAAA,IAC7C,aAAa,IAAI;AAAA,IACjB,SAAS,SAAS;AAAA,KAChB,CAAC,CAAC;AAAA,EACL,aAAa,SAAS,MAAM;AAAA,IAC3B,QAAQ,EAAE;AAAA,IACV,IAAI,SAAS,MAAM;AAAA,GACnB;AAAA,EACD,MAAM,QAAQ,MAAM;AAAA,IACnB,MAAM,SAAS,OAAO,aAAa,SAAS,IAAI;AAAA,IAChD,IAAI,kBAAkB,SAAS;AAAA,MAC9B,MAAM,IAAI,UAAU,yCAAyC;AAAA,IAC9D;AAAA,IACA,QAAQ,QAAQ,UAAU;AAAA,IAI1B,IAAI,QAAQ,QAAQ;AAAA,MACnB,SAAS,OAAO,IAAI,OAAO;AAAA,MAC3B;AAAA,IACD;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,OAAO;AAAA;AAAA,EAER,OAAO,EAAE,MAAM,SAAS,KAAK,OAAO,MAAM;AAAA;;ACxF3C,sBAAS,wBAAW;AACpB;AAiBO,SAAS,YAAY,CAC3B,QACE,OAAO,UAA4B,CAAC,GACtB;AAAA,EAChB,OAAO,UAAU,gBAAgB;AAAA,EACjC,OAAO,SAAS,UAAS,MAAM,OAAO,IAAI,IAAI,KAAK,IAAI;AAAA,EACvD,WAAU,MAAM;AAAA,IACf,IAAI,CAAC;AAAA,MAAM;AAAA,IACX,MAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AAAA,IACxC,IAAI,CAAC,IAAI,aAAa,IAAI,IAAI;AAAA,MAAG;AAAA,IACjC,IAAI,aAAa,OAAO,IAAI;AAAA,IAC5B,OAAO,QAAQ,aACd,OAAO,QAAQ,OACf,IACA,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI,MACpC;AAAA,KACE,CAAC,MAAM,IAAI,CAAC;AAAA,EACf,OAAO;AAAA;;ACnCR,wBAAS,0BAAa;AACtB;AAGO,IAAM,gBAAgB;AAgB7B,eAAsB,YAAY,CACjC,QACA,QACgB;AAAA,EAChB,IAAI;AAAA,IACH,MAAM,SAAS;AAAA,IACd,MAAM;AAAA,EAGR,MAAM,OAAO;AAAA;AAQP,SAAS,UAAU,CAAC,UAA0B,CAAC,GAGpD;AAAA,EACD,QAAQ,SAAS,eAAe,WAAW;AAAA,EAC3C,MAAM,SAAS,UAAU;AAAA,EACzB,OAAO,WAAW,gBAAgB,UAAS,KAAK;AAAA,EAChD,MAAM,aAAa,cAAc,EAAE,eAAe;AAAA,EAClD,MAAM,UAAU,aAAY,MAAM;AAAA,IACjC,aAAa,IAAI;AAAA,IACZ,aAAa,QAAQ,MACzB,OAAO,CAAC,GAAG,EAAE,QAAQ,QAAQ,QAAQ,SAAS,mBAAmB,CAAC,CACnE,EAAE,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,KACjC,CAAC,QAAQ,QAAQ,MAAM,CAAC;AAAA,EAC3B,OAAO,EAAE,SAAS,MAAM,aAAa,WAAW;AAAA;",
|
|
10
|
+
"debugId": "26E2FEF9A38E677964756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
/** The part of a Standard Schema (`~standard`) this hook reads; Zod, Valibot and ArkType satisfy it. */
|
|
3
|
+
export interface CodeSchema {
|
|
4
|
+
readonly '~standard': {
|
|
5
|
+
validate(value: unknown): unknown;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Calls `handler` once for each new `refusal` (a new object each time,
|
|
10
|
+
* `undefined` when there is none). A refusal already there when the
|
|
11
|
+
* component mounted is not new: it is the page's own, seen again.
|
|
12
|
+
* Library-agnostic: pair it with any form library's `reset` and `focus`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useOnRefusal(refusal: object | undefined, handler: () => void): void;
|
|
15
|
+
export interface CodeField {
|
|
16
|
+
/** The code typed so far. */
|
|
17
|
+
readonly code: string;
|
|
18
|
+
readonly setCode: (code: string) => void;
|
|
19
|
+
/** On the input, so a refusal can focus it. */
|
|
20
|
+
readonly ref: RefObject<HTMLInputElement | null>;
|
|
21
|
+
/** The first issue's message of the last `check`, cleared by typing. */
|
|
22
|
+
readonly error: string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Validates the code against the schema: the parsed value, or
|
|
25
|
+
* `undefined` and `error` set. Synchronous schemas only.
|
|
26
|
+
*/
|
|
27
|
+
readonly check: () => unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A one-code field (an authenticator app's code, a recovery code) with no
|
|
31
|
+
* form library: it holds the code, checks it against `schema`, and on each
|
|
32
|
+
* new `refusal` clears the refused code and focuses the input for the next
|
|
33
|
+
* try. With react-hook-form, use `useOnRefusal` and its `setValue` and
|
|
34
|
+
* `setFocus` instead.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useCodeField(schema: CodeSchema, refusal: object | undefined): CodeField;
|
|
37
|
+
//# sourceMappingURL=use-code-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-code-field.d.ts","sourceRoot":"","sources":["../../../src/session/react/use-code-field.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EAKd,MAAM,OAAO,CAAC;AAEf,wGAAwG;AACxG,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,WAAW,EAAE;QACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;KAClC,CAAC;CACF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,IAAI,GACjB,IAAI,CASN;AAED,MAAM,WAAW,SAAS;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACjD,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,MAAM,GAAG,SAAS,GACzB,SAAS,CA6BX"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface LinkParamOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Remove the parameter from the address bar once read
|
|
4
|
+
* (`history.replaceState`), so a token is not left in the history, a
|
|
5
|
+
* bookmark or a shared screen. Default `false`.
|
|
6
|
+
*/
|
|
7
|
+
readonly drop?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The query parameter a mail's link carries (`token`, `code`, `state`),
|
|
11
|
+
* read once: the value of the first render is kept for the page's life, so
|
|
12
|
+
* dropping it from the address bar never loses it. `null` when absent or
|
|
13
|
+
* empty. Safe to render on the server, where nothing is dropped.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useLinkParam(name: string, { drop }?: LinkParamOptions): string | null;
|
|
16
|
+
//# sourceMappingURL=use-link-param.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-link-param.d.ts","sourceRoot":"","sources":["../../../src/session/react/use-link-param.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,MAAM,EACZ,EAAE,IAAY,EAAE,GAAE,gBAAqB,GACrC,MAAM,GAAG,IAAI,CAef"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Where `signInFlow`'s sign-out action is mounted unless the app says otherwise. */
|
|
2
|
+
export declare const SIGN_OUT_PATH = "/sign-out";
|
|
3
|
+
export interface SignOutOptions {
|
|
4
|
+
/** The sign-out route (default `/sign-out`). */
|
|
5
|
+
readonly action?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Runs before the post: clear the worker's caches, a local store. A
|
|
8
|
+
* rejection never keeps the user signed in: the sign-out goes on.
|
|
9
|
+
*/
|
|
10
|
+
readonly before?: () => Promise<unknown> | unknown;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Runs `before`, then `submit`. A `before` that throws or rejects is
|
|
14
|
+
* ignored, so a failed cleanup cannot keep a session alive.
|
|
15
|
+
*/
|
|
16
|
+
export declare function signOutAfter(before: (() => Promise<unknown> | unknown) | undefined, submit: () => Promise<void> | void): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* The one way a page signs out, wherever the control is: posts `{}` as JSON
|
|
19
|
+
* to the sign-out route (same-origin and JSON only, as `signInFlow`'s action
|
|
20
|
+
* requires). `busy` from the call until the navigation it starts has ended.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useSignOut(options?: SignOutOptions): {
|
|
23
|
+
signOut: () => void;
|
|
24
|
+
busy: boolean;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=use-sign-out.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-sign-out.d.ts","sourceRoot":"","sources":["../../../src/session/react/use-sign-out.ts"],"names":[],"mappings":"AAGA,qFAAqF;AACrF,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,MAAM,EAAE,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,SAAS,EACtD,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG;IACzD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACd,CAYA"}
|
|
@@ -6,15 +6,17 @@ import type { StepUpConfirmAnswer, StepUpRequestAnswer, StepUpVia } from './mode
|
|
|
6
6
|
export interface StepUpCodes extends SignInCodes {
|
|
7
7
|
/** The code of a mutation that needs a step-up first (`'STEP_UP_REQUIRED'`). */
|
|
8
8
|
readonly stepUpRequired?: string | undefined;
|
|
9
|
-
/** The code of a mail the API holds back (`'MAIL_THROTTLED'`): `request` answers `error: 'throttled'`. */
|
|
9
|
+
/** The code of a mail the API holds back (`'MAIL_THROTTLED'`): `request` answers `error: 'throttled'`. Any 429 is throttled too, whatever its code. */
|
|
10
10
|
readonly mailThrottled?: string | undefined;
|
|
11
11
|
}
|
|
12
|
-
export interface StepUpStepsOptions<L extends string> {
|
|
12
|
+
export interface StepUpStepsOptions<L extends string, C = undefined> {
|
|
13
13
|
/**
|
|
14
14
|
* The app's sign-in flow: the step-up reads its `errors`, its `json` (a
|
|
15
|
-
* step runs only for a same-site JSON post) and its `attemptsLeft`.
|
|
15
|
+
* step runs only for a same-site JSON post) and its `attemptsLeft`. A flow
|
|
16
|
+
* typed with a caller context (`C`) is as good: the step-up never revokes,
|
|
17
|
+
* so it never reads one.
|
|
16
18
|
*/
|
|
17
|
-
readonly signIn: SignInFlow<L>;
|
|
19
|
+
readonly signIn: SignInFlow<L, C>;
|
|
18
20
|
/** A challenge that is over, worded ("ask for a new code"). */
|
|
19
21
|
spent(language: L): string;
|
|
20
22
|
/**
|
|
@@ -46,8 +48,8 @@ export interface StepUpSteps<L extends string> {
|
|
|
46
48
|
* Starts a step-up (`requestStepUp`): the challenge and how it is
|
|
47
49
|
* confirmed. The challenge goes to the page's fetcher and nowhere else.
|
|
48
50
|
* A refusal is `error: 'failed'` with the
|
|
49
|
-
* message and the API's status, and a throttled mail
|
|
50
|
-
* with `retryAfter` when the API says how long; an API it cannot reach is a 503. Anything
|
|
51
|
+
* message and the API's status, and a throttled mail or any 429 (a rate
|
|
52
|
+
* limit) `error: 'throttled'`, with `retryAfter` when the API says how long; an API it cannot reach is a 503. Anything
|
|
51
53
|
* that is not an API failure is thrown. Only a same-site JSON post goes on.
|
|
52
54
|
*/
|
|
53
55
|
request(run: () => Promise<{
|
|
@@ -56,7 +58,8 @@ export interface StepUpSteps<L extends string> {
|
|
|
56
58
|
}>, options: StepUpCall<L>): Promise<StepUpRequestAnswer | StepUpStayed<StepUpRequestAnswer>>;
|
|
57
59
|
/**
|
|
58
60
|
* Confirms the step-up with the code (`confirmStepUp`). A refusal says
|
|
59
|
-
* why: `invalid` with the tries left, `expired` (ask again),
|
|
61
|
+
* why: `invalid` with the tries left, `expired` (ask again), `throttled`
|
|
62
|
+
* (a 429: wait `retryAfter`, the challenge and its tries stay), or `failed`;
|
|
60
63
|
* with no try left, a mailed code (`via: 'email'`, or not given) is
|
|
61
64
|
* `expired` and an app or recovery code is `locked`.
|
|
62
65
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-up-types.d.ts","sourceRoot":"","sources":["../../src/session/step-up-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,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EACX,mBAAmB,EACnB,mBAAmB,EACnB,SAAS,EACT,MAAM,SAAS,CAAC;AAEjB,qEAAqE;AACrE,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,gFAAgF;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,
|
|
1
|
+
{"version":3,"file":"step-up-types.d.ts","sourceRoot":"","sources":["../../src/session/step-up-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,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EACX,mBAAmB,EACnB,mBAAmB,EACnB,SAAS,EACT,MAAM,SAAS,CAAC;AAEjB,qEAAqE;AACrE,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,gFAAgF;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,uJAAuJ;IACvJ,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS;IAClE;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,+DAA+D;IAC/D,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;IACxD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EACd,CAAC,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC,GAC1D,SAAS,CAAC;IACb,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACzC;AAED,2EAA2E;AAC3E,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,MAAM;IAC5C;;;;;;;OAOG;IACH,OAAO,CACN,GAAG,EAAE,MAAM,OAAO,CAAC;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,EAC3E,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,OAAO,CACN,GAAG,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC3B,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;KAAE,GAC/D,OAAO,CAAC,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACpE,6DAA6D;IAC7D,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CAC1C"}
|
|
@@ -13,5 +13,5 @@ import type { StepUpSteps, StepUpStepsOptions } from './step-up-types';
|
|
|
13
13
|
* locked: (language) => t('step-up.locked', {}, language),
|
|
14
14
|
* });
|
|
15
15
|
*/
|
|
16
|
-
export declare function stepUpSteps<L extends string>(options: StepUpStepsOptions<L>): StepUpSteps<L>;
|
|
16
|
+
export declare function stepUpSteps<L extends string, C = undefined>(options: StepUpStepsOptions<L, C>): StepUpSteps<L>;
|
|
17
17
|
//# sourceMappingURL=step-up.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../src/session/step-up.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEX,WAAW,EACX,kBAAkB,EAClB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../src/session/step-up.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEX,WAAW,EACX,kBAAkB,EAClB,MAAM,iBAAiB,CAAC;AA+JzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,EAC1D,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC/B,WAAW,CAAC,CAAC,CAAC,CAQhB"}
|
package/docs/README.md
CHANGED
|
@@ -19,7 +19,7 @@ installable and usable offline, wording an API's refusals, and what to do with e
|
|
|
19
19
|
| [Deploying](guide/deploying.md) | running the build with `bun build/server/index.js`, and the Docker image |
|
|
20
20
|
| [Installable and offline](guide/pwa.md) | making the app installable and usable offline: the subpaths of `@alxia/react-router/pwa`, the service worker (`startWorker`, `/pwa/worker`), its build by `alxia()` or `buildWorker` (`/pwa/build`), its contract and cache names, which requests the worker caches and which responses it stores, the precache list read from a build, or clearing the caches at sign-out |
|
|
21
21
|
| [An API's refusals](guide/errors.md) | wording a GraphQL API's refusals for the pages: recognising an `ApiError`, the request id, the page a request is for, the catalogue store, the form checks in the API's words, the provider, and the loaders, the error page and the actions that answer with it, the JSON actions with their CSRF check and fetcher hook, calling the API from a loader (`apiCallFailure`), and keeping the catalogue fresh (`@alxia/react-router/errors`) |
|
|
22
|
-
| [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
|
|
22
|
+
| [A BFF session](guide/session.md) | redirecting after sign-in to a page of the site and nowhere else, the sign-in pages' paths, the session's cookies, the sign-in flow (where an answer lands, a refused code, the viewer, sign-out; `@alxia/react-router/session`), the pages a mail's link opens (a magic link, a password reset: `authLinks`), the page's hooks (sign-out, a mail link's parameter, a one-code field; `@alxia/react-router/session/react`), and the step-up's state and the props it gives the UI (`@alxia/react-router/session/model`) |
|
|
23
23
|
| [Troubleshooting](troubleshooting.md) | something went wrong and you have the message, or a page streams, hydrates or reads its context unlike you expected |
|
|
24
24
|
| [Roadmap](roadmap.md) | wondering what is coming, and what is not planned |
|
|
25
25
|
|
package/docs/guide/session.md
CHANGED
|
@@ -6,12 +6,15 @@ holds the API's session token in an HttpOnly cookie of its own. The browser
|
|
|
6
6
|
never sees the token; the app sends it to the API as a bearer, on the user's
|
|
7
7
|
behalf.
|
|
8
8
|
|
|
9
|
-
It covers
|
|
9
|
+
It covers three subpaths:
|
|
10
10
|
|
|
11
11
|
- `@alxia/react-router/session`, the server side: the cookies, the sign-in
|
|
12
12
|
flow, the step-up and the pages a mail's link opens. It imports
|
|
13
13
|
`react-router` and `/errors`' files, nothing else, knows no API client and
|
|
14
14
|
adds no peer.
|
|
15
|
+
- `@alxia/react-router/session/react`, the page's hooks around those flows:
|
|
16
|
+
signing out, a mail link's parameter and a one-code field. They import
|
|
17
|
+
`react` and `react-router`, both already peers.
|
|
15
18
|
- `@alxia/react-router/session/model`, the part that imports nothing and is
|
|
16
19
|
safe in a component as well as in a loader: redirects that stay on the
|
|
17
20
|
site, the sign-in pages' paths, and the step-up's state.
|
|
@@ -31,6 +34,7 @@ instead.
|
|
|
31
34
|
- [Signing out](#signing-out)
|
|
32
35
|
- [Step-up](#step-up)
|
|
33
36
|
- [Pages a mail's link opens](#pages-a-mails-link-opens)
|
|
37
|
+
- [The page's hooks](#the-pages-hooks)
|
|
34
38
|
- [The types and the rest of `/session/model`](#the-types-and-the-rest-of-sessionmodel)
|
|
35
39
|
|
|
36
40
|
## A complete sign-in
|
|
@@ -478,6 +482,17 @@ export async function action({ context, request }: Route.ActionArgs) {
|
|
|
478
482
|
}
|
|
479
483
|
```
|
|
480
484
|
|
|
485
|
+
`stepUpSteps` and `authLinks` take such a flow as it is, with no cast. The
|
|
486
|
+
step-up never calls `revoke`, so it needs no `context` of its own: its
|
|
487
|
+
`request` and `confirm` take none.
|
|
488
|
+
|
|
489
|
+
```ts
|
|
490
|
+
export const stepUp = stepUpSteps({
|
|
491
|
+
signIn, // the flow above, typed with `Caller`
|
|
492
|
+
spent: (language) => t('step-up.spent', {}, language),
|
|
493
|
+
});
|
|
494
|
+
```
|
|
495
|
+
|
|
481
496
|
The same `context` is taken by `revokeSession(request, { context })`,
|
|
482
497
|
`landReplacing(answer, next, { request, context })`,
|
|
483
498
|
`signInStep(run, { ..., context })`, and, on `authLinks`, by
|
|
@@ -638,7 +653,7 @@ type StepUpError = 'invalid' | 'expired' | 'failed' | 'throttled';
|
|
|
638
653
|
// request, refused
|
|
639
654
|
{ ok: false, intent: 'request-step-up', error: StepUpError, message, retryAfter? }
|
|
640
655
|
// confirm, refused
|
|
641
|
-
{ ok: false, intent: 'confirm-step-up', error: StepUpError, attemptsLeft?, locked, message }
|
|
656
|
+
{ ok: false, intent: 'confirm-step-up', error: StepUpError, attemptsLeft?, locked, message, retryAfter? }
|
|
642
657
|
```
|
|
643
658
|
|
|
644
659
|
The answer must not be cached: `Cache-Control: private, no-store`, which
|
|
@@ -674,10 +689,12 @@ This is the table of `@nxgt/janus-graphql`'s `confirmStepUp`, with what
|
|
|
674
689
|
| `SECOND_FACTOR_ACTIVE`, `SECOND_FACTOR_NOT_ENROLLED` | 409 | `error: 'expired'`: start over, the way to confirm changed |
|
|
675
690
|
| `USER_INACTIVE`, anything else | 403 or other | `error: 'failed'`, in `wording`'s words or `errors`' |
|
|
676
691
|
| an API it cannot reach | 503 | `error: 'failed'` |
|
|
677
|
-
| `request` refused with `MAIL_THROTTLED
|
|
692
|
+
| `request` refused with `MAIL_THROTTLED`, or any 429 (a rate limit) | 429 | `error: 'throttled'`, `retryAfter` in seconds when the API sent them, `message` in `wording`'s words or `errors`' |
|
|
693
|
+
| `confirm` refused with a 429 (a rate limit), whatever the code | 429 | `error: 'throttled'`, `locked: false`, `retryAfter` when sent: the challenge and its tries stay, wait and send the code again |
|
|
678
694
|
|
|
679
695
|
A request that the API refuses is `error: 'failed'`. A mail throttled
|
|
680
|
-
(`MAIL_THROTTLED
|
|
696
|
+
(`MAIL_THROTTLED`) or any refusal with the status 429 (a rate limit, under
|
|
697
|
+
whatever code, on `request` or on `confirm`) is `error: 'throttled'` instead, with `retryAfter`, the
|
|
681
698
|
whole seconds to wait, read from `extensions.params.retryAfter` or
|
|
682
699
|
`extensions.retryAfter` (a number or a numeric string, rounded up; with none
|
|
683
700
|
usable the answer is still `throttled`, without `retryAfter`). Its `message`
|
|
@@ -730,7 +747,7 @@ its state on the page, with no React: `phase` (`idle`, `requesting`, `code`,
|
|
|
730
747
|
`confirming`, `done`), the `via` that confirms it (`email` or
|
|
731
748
|
`secondFactor`), the `challenge` held, `attemptsLeft`, `locked`, `error`
|
|
732
749
|
(`invalid`, `expired`, `failed` or `throttled`), `message` (the last refusal
|
|
733
|
-
worded for the page), `retryAfter` (a throttle's seconds), `pending` and
|
|
750
|
+
worded for the page), `retryAfter` (a throttle's seconds, from a request or a code), `pending` and
|
|
734
751
|
`resent`. `start`, `submit`, an accepted answer and `release` clear `message`
|
|
735
752
|
and `retryAfter`.
|
|
736
753
|
|
|
@@ -768,7 +785,8 @@ state = stepUpReducer(state, {
|
|
|
768
785
|
|
|
769
786
|
stepUpProps(state);
|
|
770
787
|
// { via: 'secondFactor', attemptsLeft: 0, locked: true, error: 'invalid', pending: false, resent: false }
|
|
771
|
-
// A throttled request adds `retryAfter` (seconds) when the API said how long
|
|
788
|
+
// A throttled request or code (a 429) adds `error: 'throttled'` and `retryAfter` (seconds) when the API said how long:
|
|
789
|
+
// the challenge and its tries stay, and `VerificationCode` makes Resend wait without locking.
|
|
772
790
|
```
|
|
773
791
|
|
|
774
792
|
With no try left, a mailed code is over (`error: 'expired'`: ask for a new
|
|
@@ -935,6 +953,131 @@ site, as a GET that spends nothing; the token is no further from the user than
|
|
|
935
953
|
it was in the address bar, and the page's `TOKEN_PAGE_HEADERS` still keep it
|
|
936
954
|
out of any `Referer`.
|
|
937
955
|
|
|
956
|
+
## The page's hooks
|
|
957
|
+
|
|
958
|
+
`@alxia/react-router/session/react` holds the three client pieces every app
|
|
959
|
+
writes around the flows above. It imports `react` and `react-router` (peers
|
|
960
|
+
the package already has) and nothing else; every hook renders on the server.
|
|
961
|
+
|
|
962
|
+
### `useSignOut`
|
|
963
|
+
|
|
964
|
+
Posts `{}` as JSON to the sign-out route (the one `signIn.signOut` serves; JSON
|
|
965
|
+
and same-origin only), wherever the control is. `busy` is true from the call
|
|
966
|
+
until the navigation it starts has ended, so the button can show it.
|
|
967
|
+
|
|
968
|
+
```tsx
|
|
969
|
+
import { useSignOut } from '@alxia/react-router/session/react';
|
|
970
|
+
|
|
971
|
+
export function SignOutButton() {
|
|
972
|
+
const { signOut, busy } = useSignOut();
|
|
973
|
+
return (
|
|
974
|
+
<button type="button" onClick={signOut} disabled={busy}>
|
|
975
|
+
{busy ? 'Signing out…' : 'Sign out'}
|
|
976
|
+
</button>
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
Options: `action` (the route, default `/sign-out`) and `before`, run before the
|
|
982
|
+
post, for what must be gone from a shared device first. A `before` that throws
|
|
983
|
+
or rejects never keeps the user signed in: the sign-out goes on.
|
|
984
|
+
|
|
985
|
+
```tsx
|
|
986
|
+
const { signOut } = useSignOut({
|
|
987
|
+
action: '/account/sign-out',
|
|
988
|
+
before: () => caches.keys().then((keys) => Promise.all(keys.map((k) => caches.delete(k)))),
|
|
989
|
+
});
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
### `useLinkParam`
|
|
993
|
+
|
|
994
|
+
Reads the query parameter a mail's link carries, once: the first render's value
|
|
995
|
+
is kept for the page's life. With `drop: true` the parameter is then removed
|
|
996
|
+
from the address bar (`history.replaceState`, keeping the history state and the
|
|
997
|
+
hash), so a token is not left in the history, a bookmark or a screenshot. It is
|
|
998
|
+
`null` when the parameter is absent or empty.
|
|
999
|
+
|
|
1000
|
+
```tsx
|
|
1001
|
+
import { useLinkParam } from '@alxia/react-router/session/react';
|
|
1002
|
+
|
|
1003
|
+
export default function ResetPassword() {
|
|
1004
|
+
const token = useLinkParam('token', { drop: true });
|
|
1005
|
+
if (!token) return <p>This link is not valid. Ask for a new one.</p>;
|
|
1006
|
+
return (
|
|
1007
|
+
<form method="post">
|
|
1008
|
+
<input type="hidden" name="token" value={token} />
|
|
1009
|
+
<input type="password" name="password" autoComplete="new-password" />
|
|
1010
|
+
<button type="submit">Choose a new password</button>
|
|
1011
|
+
</form>
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
The router's own location is not updated by `replaceState`: a loader or
|
|
1017
|
+
`useSearchParams` elsewhere still sees the token until the next navigation.
|
|
1018
|
+
Read it with the hook once, and pass it down.
|
|
1019
|
+
|
|
1020
|
+
### `useCodeField` and `useOnRefusal`
|
|
1021
|
+
|
|
1022
|
+
A form that asks for one code (an authenticator app's, a recovery code) and
|
|
1023
|
+
whose action answers a refusal object when the code is wrong: on each new
|
|
1024
|
+
refusal the refused code goes and the field takes focus, for the next try. A
|
|
1025
|
+
refusal already there when the component mounted is the page's own and is
|
|
1026
|
+
ignored.
|
|
1027
|
+
|
|
1028
|
+
`useCodeField(schema, refusal)` needs no form library. `schema` is any
|
|
1029
|
+
[Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType; a
|
|
1030
|
+
synchronous one). It returns `code`, `setCode`, `ref` (put it on the input),
|
|
1031
|
+
`error` (the first message of the last `check()`, cleared by typing) and
|
|
1032
|
+
`check()` (the parsed value, or `undefined` with `error` set).
|
|
1033
|
+
|
|
1034
|
+
```tsx
|
|
1035
|
+
import { useCodeField } from '@alxia/react-router/session/react';
|
|
1036
|
+
import { TOTP_CODE } from '@alxia/react-router/session/model';
|
|
1037
|
+
import { Form, useActionData } from 'react-router';
|
|
1038
|
+
import { z } from 'zod';
|
|
1039
|
+
|
|
1040
|
+
const schema = z.string().regex(TOTP_CODE, 'Six digits');
|
|
1041
|
+
|
|
1042
|
+
export function CodeForm() {
|
|
1043
|
+
const refusal = useActionData<object>(); // a new object on each refusal
|
|
1044
|
+
const field = useCodeField(schema, refusal);
|
|
1045
|
+
return (
|
|
1046
|
+
<Form method="post" onSubmit={(event) => { if (field.check() === undefined) event.preventDefault(); }}>
|
|
1047
|
+
<input
|
|
1048
|
+
ref={field.ref}
|
|
1049
|
+
name="code"
|
|
1050
|
+
inputMode="numeric"
|
|
1051
|
+
autoComplete="one-time-code"
|
|
1052
|
+
value={field.code}
|
|
1053
|
+
onChange={(event) => field.setCode(event.target.value)}
|
|
1054
|
+
/>
|
|
1055
|
+
{field.error ? <p role="alert">{field.error}</p> : null}
|
|
1056
|
+
<button type="submit">Confirm</button>
|
|
1057
|
+
</Form>
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
An app on react-hook-form keeps its form and its resolver and uses the part
|
|
1063
|
+
underneath, `useOnRefusal(refusal, handler)`, which calls `handler` once per
|
|
1064
|
+
new refusal:
|
|
1065
|
+
|
|
1066
|
+
```tsx
|
|
1067
|
+
import { useOnRefusal } from '@alxia/react-router/session/react';
|
|
1068
|
+
import { useForm } from 'react-hook-form';
|
|
1069
|
+
|
|
1070
|
+
const form = useForm({ defaultValues: { code: '' } /* , resolver */ });
|
|
1071
|
+
useOnRefusal(refusal, () => {
|
|
1072
|
+
form.setValue('code', '');
|
|
1073
|
+
form.setFocus('code');
|
|
1074
|
+
});
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
The package takes no form library as a peer: react-hook-form would also need
|
|
1078
|
+
its resolver for the schema, and a library-agnostic core serves every form
|
|
1079
|
+
library at the price of three lines.
|
|
1080
|
+
|
|
938
1081
|
## The types and the rest of `/session/model`
|
|
939
1082
|
|
|
940
1083
|
The rest of `@alxia/react-router/session/model`, beside `safeNext`,
|
package/docs/roadmap.md
CHANGED
|
@@ -7,7 +7,12 @@ number on it. Every release, with each change it made, is in
|
|
|
7
7
|
|
|
8
8
|
## Now
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
- **`@alxia/react-router/session/react`: the page's hooks around the session
|
|
11
|
+
flows.** `useSignOut`, `useLinkParam` (a mail link's parameter, read once and
|
|
12
|
+
optionally dropped from the address bar) and `useCodeField` /
|
|
13
|
+
`useOnRefusal` (a one-code field that clears and refocuses on each refusal),
|
|
14
|
+
so an app stops carrying its own copies. See the
|
|
15
|
+
[session guide](guide/session.md#the-pages-hooks).
|
|
11
16
|
|
|
12
17
|
## Next
|
|
13
18
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
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`) and what it shares with the page (`/session/model`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
|
|
3
|
+
"version": "0.17.0",
|
|
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`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -72,6 +72,11 @@
|
|
|
72
72
|
"import": "./dist/pwa/worker/index.js",
|
|
73
73
|
"default": "./dist/pwa/worker/index.js"
|
|
74
74
|
},
|
|
75
|
+
"./session/react": {
|
|
76
|
+
"types": "./dist/session/react/index.d.ts",
|
|
77
|
+
"import": "./dist/session/react/index.js",
|
|
78
|
+
"default": "./dist/session/react/index.js"
|
|
79
|
+
},
|
|
75
80
|
"./session/model": {
|
|
76
81
|
"types": "./dist/session/model/index.d.ts",
|
|
77
82
|
"import": "./dist/session/model/index.js",
|
|
@@ -103,6 +108,7 @@
|
|
|
103
108
|
"src/errors/index.ts",
|
|
104
109
|
"src/session/model/index.ts",
|
|
105
110
|
"src/session/index.ts",
|
|
111
|
+
"src/session/react/index.ts",
|
|
106
112
|
"src/document/index.ts",
|
|
107
113
|
"src/entry/index.ts",
|
|
108
114
|
"src/pwa/worker/index.ts",
|
|
@@ -121,6 +127,7 @@
|
|
|
121
127
|
"@types/react": "^19.3.0",
|
|
122
128
|
"@types/react-dom": "^19.3.0",
|
|
123
129
|
"graphql": "^17.0.2",
|
|
130
|
+
"happy-dom": "^20",
|
|
124
131
|
"intl-messageformat": "^12.1.4",
|
|
125
132
|
"isbot": "^5.2.2",
|
|
126
133
|
"react": "^19.3.1",
|