@alxia/react-router 0.28.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1286,7 +1286,7 @@ From `@alxia/react-router/session/react` (`react` and `react-router` are its onl
|
|
|
1286
1286
|
| `useStepUp({ request, confirm, onConfirmed })`, `StepUpOptions`, `StepUpChannel` | the step-up under it: `{ phase, via, props, message, busy, start(), submit(code), release() }` |
|
|
1287
1287
|
| `asksStepUp(answer)`, `stepUpDialogPhase(state)`, `StepUpDialogPhase` | whether an answer asks for a step-up, and the dialog's phase (`'asking' \| 'failed' \| 'code' \| 'expired' \| 'confirmed'`) |
|
|
1288
1288
|
| `requestAnswerOf(data)`, `confirmAnswerOf(data)` | narrow the data of `route()`'s union to one intent's answer, to type each channel |
|
|
1289
|
-
| `dialogPropsOf(stepUp, open, cancel)`, `StepUpDialogProps` | the props a step-up dialog is given: `open`, `phase`, `via
|
|
1289
|
+
| `dialogPropsOf(stepUp, open, cancel)`, `StepUpDialogProps` | the props a step-up dialog is given: `open`, `phase`, `via` (kept in every phase once a challenge was granted), `props`, `message`, `busy`, `confirming` and the handlers |
|
|
1290
1290
|
| `useOnRefusal(refusal, handler)` | the core under it, for any form library: `handler` runs once per new refusal, not for one present at mount |
|
|
1291
1291
|
|
|
1292
1292
|
```tsx
|
|
@@ -17,7 +17,7 @@ function dialogPropsOf(stepUp, open, cancel) {
|
|
|
17
17
|
return {
|
|
18
18
|
open,
|
|
19
19
|
phase: stepUp.phase,
|
|
20
|
-
via: stepUp.
|
|
20
|
+
via: stepUp.via,
|
|
21
21
|
props: stepUp.props,
|
|
22
22
|
message: stepUp.message,
|
|
23
23
|
busy: stepUp.busy,
|
|
@@ -283,5 +283,5 @@ export {
|
|
|
283
283
|
useStepUpReplay
|
|
284
284
|
};
|
|
285
285
|
|
|
286
|
-
//# debugId=
|
|
286
|
+
//# debugId=E34A285DD08642E264756E2164756E21
|
|
287
287
|
//# sourceMappingURL=index.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"sources": ["../src/session/react/step-up/answers.ts", "../src/session/react/step-up/dialog-props.ts", "../src/session/react/step-up/phase.ts", "../src/session/react/step-up/use-step-up.ts", "../src/session/react/step-up/use-step-up-replay.ts", "../src/session/react/use-code-field.ts", "../src/session/react/use-link-param.ts", "../src/session/react/use-sign-out.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import type {\n\tStepUpConfirmAnswer,\n\tStepUpRequestAnswer,\n} from '../../model/step-up-answers';\n\nconst intentOf = (data: unknown) =>\n\ttypeof data === 'object' && data !== null\n\t\t? (data as { intent?: unknown }).intent\n\t\t: undefined;\n\n/**\n * The step-up route answers both intents from one action, so a fetcher's data\n * is their union: this is the request's answer, or `undefined` for any other.\n */\nexport function requestAnswerOf(\n\tdata: unknown,\n): StepUpRequestAnswer | undefined {\n\treturn intentOf(data) === 'request-step-up'\n\t\t? (data as StepUpRequestAnswer)\n\t\t: undefined;\n}\n\n/** The confirm's answer out of the route's union, or `undefined` for any other. */\nexport function confirmAnswerOf(\n\tdata: unknown,\n): StepUpConfirmAnswer | undefined {\n\treturn intentOf(data) === 'confirm-step-up'\n\t\t? (data as StepUpConfirmAnswer)\n\t\t: undefined;\n}\n",
|
|
6
|
-
"import type { StepUpVia } from '../../model/second-factor';\nimport type { StepUpProps } from '../../model/step-up-props';\nimport type { StepUpDialogPhase } from './phase';\nimport type { useStepUp } from './use-step-up';\n\n/** What a step-up dialog is given: the phase to show and the handlers. */\nexport interface StepUpDialogProps {\n\topen: boolean;\n\tphase: StepUpDialogPhase;\n\t/** How the code is confirmed,
|
|
6
|
+
"import type { StepUpVia } from '../../model/second-factor';\nimport type { StepUpProps } from '../../model/step-up-props';\nimport type { StepUpDialogPhase } from './phase';\nimport type { useStepUp } from './use-step-up';\n\n/** What a step-up dialog is given: the phase to show and the handlers. */\nexport interface StepUpDialogProps {\n\topen: boolean;\n\tphase: StepUpDialogPhase;\n\t/** How the code is confirmed, in every phase once a challenge was granted (`undefined` before). */\n\tvia: StepUpVia | undefined;\n\t/** The words of the code form (`stepUpProps`). */\n\tprops: StepUpProps;\n\t/** The last refusal worded by the server. */\n\tmessage: string | undefined;\n\tbusy: boolean;\n\t/** The code was accepted and the action is being sent again. */\n\tconfirming: boolean;\n\tonCancel(): void;\n\t/** \"Retry\" after a refused request or an over challenge. */\n\tonRetry(): void;\n\tonSubmit(code: string): void;\n\t/** \"Resend code\", for a mailed code only. */\n\tonResend: (() => void) | undefined;\n}\n\n/** The dialog's props out of a step-up: plain, so any host can build them. */\nexport function dialogPropsOf(\n\tstepUp: ReturnType<typeof useStepUp>,\n\topen: boolean,\n\tcancel: () => void,\n): StepUpDialogProps {\n\treturn {\n\t\topen,\n\t\tphase: stepUp.phase,\n\t\tvia: stepUp.via,\n\t\tprops: stepUp.props,\n\t\tmessage: stepUp.message,\n\t\tbusy: stepUp.busy,\n\t\tconfirming: stepUp.phase === 'confirmed',\n\t\tonCancel: cancel,\n\t\tonRetry: () => stepUp.start(),\n\t\tonSubmit: (code) => stepUp.submit(code),\n\t\tonResend: stepUp.via === 'email' ? () => stepUp.start() : undefined,\n\t};\n}\n",
|
|
7
7
|
"import type { StepUpState } from '../../model/step-up';\n\n/** Where a step-up is, as a dialog shows it. */\nexport type StepUpDialogPhase =\n\t| 'asking'\n\t| 'failed'\n\t| 'code'\n\t| 'expired'\n\t| 'confirmed';\n\n/** The phase a reducer state is in: what the dialog shows. */\nexport function stepUpDialogPhase(state: StepUpState): StepUpDialogPhase {\n\tif (state.phase === 'done') return 'confirmed';\n\tif (state.challenge) return 'code';\n\tif (state.error === 'expired') return 'expired';\n\treturn state.error ? 'failed' : 'asking';\n}\n\n/** Whether an answer is a refusal asking for a step-up (`stepUp` set, not ok). */\nexport function asksStepUp(answer: unknown): boolean {\n\tif (typeof answer !== 'object' || answer === null) return false;\n\tconst a = answer as { ok?: unknown; stepUp?: unknown };\n\treturn !a.ok && Boolean(a.stepUp);\n}\n",
|
|
8
8
|
"import { useEffect, useReducer, useRef } from 'react';\nimport type { StepUpVia } from '../../model/second-factor';\nimport { INITIAL_STEP_UP, stepUpReducer } from '../../model/step-up';\nimport type {\n\tStepUpConfirmAnswer,\n\tStepUpRequestAnswer,\n} from '../../model/step-up-answers';\nimport { stepUpProps } from '../../model/step-up-props';\nimport { stepUpDialogPhase } from './phase';\n\n/**\n * One step-up intent as the host posts it: its own `post` (so the fields stay\n * typed by the host's action), the settled answer it got since it mounted\n * (`undefined` before), and whether it is in flight. `reset` forgets the\n * answer (a fetcher's `reset`).\n */\nexport interface StepUpChannel<Fields, Answer> {\n\tpost(fields: Fields): void;\n\treadonly answer: Answer | undefined;\n\treadonly busy: boolean;\n\treset?(): void;\n}\n\nexport interface StepUpOptions {\n\t/** Posts `{ intent: 'request-step-up' }`, to the route that serves `stepUpSteps().route`. */\n\trequest: StepUpChannel<Record<string, never>, StepUpRequestAnswer>;\n\t/** Posts `{ intent: 'confirm-step-up', challenge, code, via }`. */\n\tconfirm: StepUpChannel<\n\t\t{ challenge: string; code: string; via: StepUpVia | undefined },\n\t\tStepUpConfirmAnswer\n\t>;\n\t/** Runs once the API accepted the code. */\n\tonConfirmed(): void;\n}\n\n/**\n * The step-up as the page lives it, on `stepUpReducer`: `start` asks for a\n * challenge, `submit` posts the code, and once it is accepted `onConfirmed`\n * runs. The challenge lives in the reducer's state and the channels' answers\n * only; `release` forgets everything, and an answer that lands after it (a\n * request or a code in flight when the host closed) is ignored.\n */\nexport function useStepUp({ request, confirm, onConfirmed }: StepUpOptions) {\n\tconst [state, dispatch] = useReducer(stepUpReducer, INITIAL_STEP_UP);\n\tconst confirmedRun = useRef(onConfirmed);\n\tconfirmedRun.current = onConfirmed;\n\t// True from `start` to `release`: only then are answers this step-up's.\n\tconst live = useRef(false);\n\n\t// Each settled answer once, even one worded as the last (a new object).\n\tconst handledRequest = useRef(request.answer);\n\tconst handledConfirm = useRef(confirm.answer);\n\tuseEffect(() => {\n\t\tconst answer = request.answer;\n\t\tif (!answer || handledRequest.current === answer) return;\n\t\thandledRequest.current = answer;\n\t\tif (!live.current) return;\n\t\tdispatch({ type: 'requested', answer });\n\t}, [request.answer]);\n\tuseEffect(() => {\n\t\tconst answer = confirm.answer;\n\t\tif (!answer || handledConfirm.current === answer) return;\n\t\thandledConfirm.current = answer;\n\t\tif (!live.current) return;\n\t\tdispatch({ type: 'confirmed', answer });\n\t\tif (answer.ok) confirmedRun.current();\n\t}, [confirm.answer]);\n\n\treturn {\n\t\tphase: stepUpDialogPhase(state),\n\t\t/** How the challenge held (or the last one) is confirmed. */\n\t\tvia: state.via,\n\t\t/** What a dialog words its texts from (`stepUpProps`). */\n\t\tprops: stepUpProps(state),\n\t\t/** The last refusal worded by the server: the fallback of the dialog's own words. */\n\t\tmessage: state.message,\n\t\t/** A request or a code is in flight. */\n\t\tbusy: request.busy || confirm.busy,\n\t\t/** Asks for a challenge: the first, or \"Resend code\" / \"New code\". */\n\t\tstart() {\n\t\t\tlive.current = true;\n\t\t\tdispatch({ type: 'start' });\n\t\t\trequest.post({});\n\t\t},\n\t\t/** Posts the code for the challenge held. */\n\t\tsubmit(code: string) {\n\t\t\tif (!state.challenge) return;\n\t\t\tdispatch({ type: 'submit' });\n\t\t\tconfirm.post({ challenge: state.challenge, code, via: state.via });\n\t\t},\n\t\t/** Forgets the challenge, the answers and the errors. */\n\t\trelease() {\n\t\t\tlive.current = false;\n\t\t\trequest.reset?.();\n\t\t\tconfirm.reset?.();\n\t\t\thandledRequest.current = request.answer;\n\t\t\thandledConfirm.current = confirm.answer;\n\t\t\tdispatch({ type: 'release' });\n\t\t},\n\t};\n}\n",
|
|
9
9
|
"import { useEffect, useRef, useState } from 'react';\nimport { dialogPropsOf } from './dialog-props';\nimport { asksStepUp } from './phase';\nimport { type StepUpOptions, useStepUp } from './use-step-up';\n\nexport interface StepUpReplayOptions<Action>\n\textends Pick<StepUpOptions, 'request' | 'confirm'> {\n\t/**\n\t * The settled answer of the sensitive action. A refusal carrying `stepUp`\n\t * opens the step-up; the first answer after the replay closes it.\n\t */\n\tanswer: unknown;\n\t/** Sends the refused action again, once the session is confirmed. */\n\treplay(): void;\n\t/** The action that was refused, for `spendsCode`. */\n\taction?: Action | undefined;\n\t/**\n\t * Whether the action carries a one-time code that a step-up by the\n\t * second factor just spent. Such an action is not replayed: the dialog\n\t * closes and `confirmedNotice` is true (\"confirmed, type a new code\").\n\t */\n\tspendsCode?(action: Action): boolean;\n}\n\n/**\n * The step-up a sensitive action asks for: an answer carrying `stepUp` opens\n * it; once the session is confirmed the same action is sent again by itself\n * (`replay`), except an action that `spendsCode` after a step-up by the\n * second factor, whose code was just spent: the user types the next one\n * (`confirmedNotice`). The dialog stays, saying so, until the replayed\n * action is answered; if that is refused for a step-up again, it asks again.\n * Generic over the host's `post`s, so each intent keeps its typed fields.\n *\n * @example\n * const { open, dialogProps, cancel, confirmedNotice } = useStepUpReplay({\n * \tanswer: fetcher.data,\n * \treplay: () => post(lastAction.current),\n * \trequest: { post: () => stepUpPost({ intent: 'request-step-up' }), answer, busy },\n * \tconfirm: { post: (f) => stepUpPost({ intent: 'confirm-step-up', ...f }), answer, busy },\n * });\n */\nexport function useStepUpReplay<Action = never>({\n\tanswer,\n\treplay,\n\taction,\n\tspendsCode,\n\trequest,\n\tconfirm,\n}: StepUpReplayOptions<Action>) {\n\tconst [open, setOpen] = useState(false);\n\tconst [confirmedNotice, setConfirmedNotice] = useState(false);\n\tconst isOpen = useRef(false);\n\tconst replaying = useRef(false);\n\tconst latest = useRef({ replay, action, spendsCode });\n\tlatest.current = { replay, action, spendsCode };\n\n\tfunction show(value: boolean) {\n\t\tisOpen.current = value;\n\t\tsetOpen(value);\n\t}\n\n\tconst stepUp = useStepUp({\n\t\trequest,\n\t\tconfirm,\n\t\tonConfirmed() {\n\t\t\t// A code accepted after the host cancelled replays nothing.\n\t\t\tif (!isOpen.current) return;\n\t\t\tconst { replay, action, spendsCode } = latest.current;\n\t\t\tconst spent =\n\t\t\t\tstepUpRef.current.via === 'secondFactor' &&\n\t\t\t\taction !== undefined &&\n\t\t\t\tspendsCode?.(action) === true;\n\t\t\tif (spent) {\n\t\t\t\tstepUpRef.current.release();\n\t\t\t\tshow(false);\n\t\t\t\tsetConfirmedNotice(true);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// The dialog stays, saying so, until the action is answered.\n\t\t\treplaying.current = true;\n\t\t\treplay();\n\t\t},\n\t});\n\tconst stepUpRef = useRef(stepUp);\n\tstepUpRef.current = stepUp;\n\n\t// Each answer once: a refusal asking for a step-up opens it; the answer\n\t// of the replayed action closes it (a new step-up opens it again).\n\tconst handled = useRef(answer);\n\tuseEffect(() => {\n\t\tif (!answer || handled.current === answer) return;\n\t\thandled.current = answer;\n\t\tif (asksStepUp(answer)) {\n\t\t\treplaying.current = false;\n\t\t\tsetConfirmedNotice(false);\n\t\t\tshow(true);\n\t\t\tstepUpRef.current.start();\n\t\t\treturn;\n\t\t}\n\t\tsetConfirmedNotice(false);\n\t\tif (replaying.current) {\n\t\t\treplaying.current = false;\n\t\t\tshow(false);\n\t\t\tstepUpRef.current.release();\n\t\t}\n\t}, [answer]);\n\n\tfunction cancel() {\n\t\treplaying.current = false;\n\t\tstepUp.release();\n\t\tshow(false);\n\t\tsetConfirmedNotice(false);\n\t}\n\n\treturn {\n\t\topen,\n\t\t/** True after a step-up by the second factor spent the action's own code. */\n\t\tconfirmedNotice,\n\t\tdialogProps: dialogPropsOf(stepUp, open, cancel),\n\t\t/** Closes the dialog without sending the action again. */\n\t\tcancel,\n\t\tstepUp,\n\t};\n}\n",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"import { useEffect, useState } from 'react';\nimport { useLocation, 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\t/**\n\t * Follow the URL instead of reading it once. A parameter that a redirect\n\t * or a link adds to the SAME mounted route (`?state=linked`) is seen, and\n\t * each new location is read again. Without `drop` the value is the\n\t * parameter of the current location. With `drop` the value is kept after\n\t * the address bar loses the parameter, until a location carries a new\n\t * one: a navigation that has none does not clear it. Default `false`.\n\t */\n\treadonly live?: 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. With `live: true` it\n * follows the URL instead (see `LinkParamOptions`). `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, live = false }: LinkParamOptions = {},\n): string | null {\n\tconst [params] = useSearchParams();\n\tconst { key } = useLocation();\n\tconst followed = live ? key : null;\n\tconst current = params.get(name) || null;\n\tconst [kept, setKept] = useState(current);\n\tconst [seen, setSeen] = useState(current);\n\tif (live && current !== seen) {\n\t\tsetSeen(current);\n\t\tif (!drop || current !== null) setKept(current);\n\t}\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, followed]);\n\tif (live && !drop) return current;\n\treturn kept;\n}\n",
|
|
12
12
|
"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"
|
|
13
13
|
],
|
|
14
|
-
"mappings": ";;;;;;;AAKA,IAAM,WAAW,CAAC,SACjB,OAAO,SAAS,YAAY,SAAS,OACjC,KAA8B,SAC/B;AAMG,SAAS,eAAe,CAC9B,MACkC;AAAA,EAClC,OAAO,SAAS,IAAI,MAAM,oBACtB,OACD;AAAA;AAIG,SAAS,eAAe,CAC9B,MACkC;AAAA,EAClC,OAAO,SAAS,IAAI,MAAM,oBACtB,OACD;AAAA;;ACDG,SAAS,aAAa,CAC5B,QACA,MACA,QACoB;AAAA,EACpB,OAAO;AAAA,IACN;AAAA,IACA,OAAO,OAAO;AAAA,IACd,KAAK,OAAO
|
|
15
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "E34A285DD08642E264756E2164756E21",
|
|
16
16
|
"names": []
|
|
17
17
|
}
|
|
@@ -6,7 +6,7 @@ import type { useStepUp } from './use-step-up';
|
|
|
6
6
|
export interface StepUpDialogProps {
|
|
7
7
|
open: boolean;
|
|
8
8
|
phase: StepUpDialogPhase;
|
|
9
|
-
/** How the code is confirmed,
|
|
9
|
+
/** How the code is confirmed, in every phase once a challenge was granted (`undefined` before). */
|
|
10
10
|
via: StepUpVia | undefined;
|
|
11
11
|
/** The words of the code form (`stepUpProps`). */
|
|
12
12
|
props: StepUpProps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-props.d.ts","sourceRoot":"","sources":["../../../../src/session/react/step-up/dialog-props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,iBAAiB,CAAC;IACzB,
|
|
1
|
+
{"version":3,"file":"dialog-props.d.ts","sourceRoot":"","sources":["../../../../src/session/react/step-up/dialog-props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,iBAAiB,CAAC;IACzB,mGAAmG;IACnG,GAAG,EAAE,SAAS,GAAG,SAAS,CAAC;IAC3B,kDAAkD;IAClD,KAAK,EAAE,WAAW,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,IAAI,IAAI,CAAC;IACjB,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6CAA6C;IAC7C,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACnC;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,EACpC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,IAAI,GAChB,iBAAiB,CAcnB"}
|
package/docs/guide/session.md
CHANGED
|
@@ -1237,6 +1237,10 @@ export function useDeleteItem() {
|
|
|
1237
1237
|
`dialogProps` is `dialogPropsOf(stepUp, open, cancel)`, which is plain and
|
|
1238
1238
|
exported, for a host that builds them itself.
|
|
1239
1239
|
|
|
1240
|
+
`via` is kept in every phase once a challenge was granted (`code`, `expired`,
|
|
1241
|
+
`failed`, `confirmed`) and is `undefined` before, so a dialog can tell a mailed
|
|
1242
|
+
code from an authenticator-app code.
|
|
1243
|
+
|
|
1240
1244
|
### `useStepUp`, `asksStepUp` and `stepUpDialogPhase`
|
|
1241
1245
|
|
|
1242
1246
|
`useStepUp({ request, confirm, onConfirmed })` is the part under it, for a host
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served; the code with no UI an installable app shares (`/pwa`), its hooks (`/pwa/react`), `noCache` for the worker's script (`/pwa/server`), the service worker on Workbox (`/pwa/worker`) and its build (`/pwa/build`), an API's refusals worded for the page (`/errors`), the BFF session: cookies, sign-in, step-up and mail links (`/session`), its page hooks (`/session/react`) and what it shares with the page (`/session/model`), a GraphQL subscription relayed to the browser over SSE (`/subscription`), the page's CSP nonce and inline boot scripts (`/document`) and a streaming `entry.server` (`/entry`)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|