@kottera/tera-web 0.1.0-rc.3 → 0.1.0-rc.5

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.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * A person's step-up, from the page's side (ADR-173 D11 step 3).
3
+ *
4
+ * An act the plugin requires the person's confirmation for is refused
5
+ * `step_up_required`: by the plugin's own route, in the kit's envelope with
6
+ * `error.step_up`, or by a Work Order verb, relayed by the invoke route with
7
+ * the challenge in the refusal's `data.step_up`. Either names the step-up's
8
+ * id and the page on tera's origin the person confirms it on. The client then:
9
+ *
10
+ * 1. opens that page in a new window, and when the browser will not open one,
11
+ * navigates to it instead with a `return_to` naming this page, which tera
12
+ * accepts only on the plugin's own origin;
13
+ * 2. polls `GET /tera/v1/step-ups/{id}` until the step-up is satisfied,
14
+ * declined or expired, and closes the window it opened;
15
+ * 3. sends the identical request again with `Tera-Step-Up: <id>` — or, for a
16
+ * Work Order verb, with `step_up` in its params.
17
+ *
18
+ * A step-up confirms one act once: nothing here holds an id past the retry it
19
+ * was confirmed for, except across the navigation fallback, where the id rides
20
+ * back on the `return_to` as {@link STEP_UP_RESUME_PARAM} and is spent by the
21
+ * first request that needs a step-up after the page loads again.
22
+ */
23
+ import type { KitError } from "./generated/kit.ts";
24
+ /** The request header that carries a confirmed step-up's id to the plugin's route. */
25
+ export declare const STEP_UP_HEADER = "Tera-Step-Up";
26
+ /** The code of a refusal that needs the person's confirmation. */
27
+ export declare const STEP_UP_REQUIRED = "step_up_required";
28
+ /**
29
+ * The query parameter the navigation fallback adds to its `return_to`, naming
30
+ * the step-up the person went to confirm, so the page that loads again
31
+ * resumes it rather than beginning another.
32
+ */
33
+ export declare const STEP_UP_RESUME_PARAM = "tera_step_up";
34
+ /** How often the step-up's state is read while the person confirms it, by default. */
35
+ export declare const STEP_UP_POLL_MS = 1000;
36
+ /** What a refusal names of the step-up it needs: the kit envelope's `error.step_up`. */
37
+ export type StepUpChallenge = NonNullable<KitError["error"]["step_up"]>;
38
+ /** The part of a `Window` the client uses: whether the person closed it, and closing it. */
39
+ export interface StepUpWindow {
40
+ readonly closed: boolean;
41
+ close(): void;
42
+ }
43
+ export interface StepUpOptions {
44
+ /** Opens the step-up's page in a new window; `window.open(url, "_blank")` when absent. Answers null when the browser would not open one. */
45
+ openWindow?: (url: string) => StepUpWindow | null;
46
+ /** The page's own URL, which the navigation fallback returns to; `location.href` when absent. */
47
+ pageURL?: () => string;
48
+ /** Waits between reads of the step-up's state; a timer when absent. */
49
+ sleep?: (ms: number) => Promise<void>;
50
+ /** How long to wait between reads; {@link STEP_UP_POLL_MS} when absent. */
51
+ pollIntervalMs?: number;
52
+ }
53
+ /**
54
+ * How a step-up ended without being confirmed:
55
+ * - `declined` — the person said they did not ask for it;
56
+ * - `expired` — nobody confirmed it in time;
57
+ * - `spent` — it confirmed another request already;
58
+ * - `abandoned` — the person closed its window and it is still waiting;
59
+ * - `navigated` — the browser would not open a window, so the page was sent to
60
+ * tera's; it returns here, and the next request that needs a step-up resumes
61
+ * this one.
62
+ */
63
+ export type StepUpEnd = "declined" | "expired" | "spent" | "abandoned" | "navigated";
64
+ /** A step-up the person did not confirm: the request it was for was not sent again. */
65
+ export declare class StepUpError extends Error {
66
+ /** The step-up's id. */
67
+ readonly stepUpId: string;
68
+ /** How it ended. */
69
+ readonly end: StepUpEnd;
70
+ constructor(stepUpId: string, end: StepUpEnd, message: string);
71
+ }
72
+ /**
73
+ * The step-up a refusal needs confirmed, when it is one this client can have
74
+ * confirmed: code `step_up_required` with a page to open. A refusal naming an
75
+ * ended step-up carries no page, and is not one.
76
+ */
77
+ export declare function stepUpChallengeOf(code: string, stepUp: unknown): StepUpChallenge | null;
78
+ /**
79
+ * The step-up page's URL with `return_to` set to `returnTo`, itself carrying
80
+ * {@link STEP_UP_RESUME_PARAM}. tera follows it back only when it is on the
81
+ * plugin's own origin.
82
+ */
83
+ export declare function stepUpPageURL(pageURL: string, stepUpId: string, returnTo: string): string;
84
+ /** The step-up id a page loaded through the navigation fallback carries back, or null. */
85
+ export declare function resumedStepUp(pageURL: string): string | null;
86
+ export declare function defaultOpenWindow(url: string): StepUpWindow | null;
87
+ export declare function defaultSleep(ms: number): Promise<void>;
package/dist/stepup.js ADDED
@@ -0,0 +1,66 @@
1
+ /** The request header that carries a confirmed step-up's id to the plugin's route. */
2
+ export const STEP_UP_HEADER = "Tera-Step-Up";
3
+ /** The code of a refusal that needs the person's confirmation. */
4
+ export const STEP_UP_REQUIRED = "step_up_required";
5
+ /**
6
+ * The query parameter the navigation fallback adds to its `return_to`, naming
7
+ * the step-up the person went to confirm, so the page that loads again
8
+ * resumes it rather than beginning another.
9
+ */
10
+ export const STEP_UP_RESUME_PARAM = "tera_step_up";
11
+ /** How often the step-up's state is read while the person confirms it, by default. */
12
+ export const STEP_UP_POLL_MS = 1000;
13
+ /** A step-up the person did not confirm: the request it was for was not sent again. */
14
+ export class StepUpError extends Error {
15
+ /** The step-up's id. */
16
+ stepUpId;
17
+ /** How it ended. */
18
+ end;
19
+ constructor(stepUpId, end, message) {
20
+ super(message);
21
+ this.name = "StepUpError";
22
+ this.stepUpId = stepUpId;
23
+ this.end = end;
24
+ }
25
+ }
26
+ /**
27
+ * The step-up a refusal needs confirmed, when it is one this client can have
28
+ * confirmed: code `step_up_required` with a page to open. A refusal naming an
29
+ * ended step-up carries no page, and is not one.
30
+ */
31
+ export function stepUpChallengeOf(code, stepUp) {
32
+ if (code !== STEP_UP_REQUIRED || typeof stepUp !== "object" || stepUp === null)
33
+ return null;
34
+ const c = stepUp;
35
+ if (typeof c.id !== "string" || c.id === "" || typeof c.url !== "string" || c.url === "")
36
+ return null;
37
+ return c;
38
+ }
39
+ /**
40
+ * The step-up page's URL with `return_to` set to `returnTo`, itself carrying
41
+ * {@link STEP_UP_RESUME_PARAM}. tera follows it back only when it is on the
42
+ * plugin's own origin.
43
+ */
44
+ export function stepUpPageURL(pageURL, stepUpId, returnTo) {
45
+ const back = new URL(returnTo);
46
+ back.searchParams.set(STEP_UP_RESUME_PARAM, stepUpId);
47
+ const page = new URL(pageURL);
48
+ page.searchParams.set("return_to", back.toString());
49
+ return page.toString();
50
+ }
51
+ /** The step-up id a page loaded through the navigation fallback carries back, or null. */
52
+ export function resumedStepUp(pageURL) {
53
+ try {
54
+ const id = new URL(pageURL).searchParams.get(STEP_UP_RESUME_PARAM);
55
+ return id === null || id === "" ? null : id;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ export function defaultOpenWindow(url) {
62
+ return globalThis.open?.(url, "_blank") ?? null;
63
+ }
64
+ export function defaultSleep(ms) {
65
+ return new Promise((resolve) => setTimeout(resolve, ms));
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kottera/tera-web",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.1.0-rc.5",
4
4
  "description": "The browser half of a UI over tera: a framework-free client for the /tera/v1/ routes a plugin's webui kit serves (ADR-162 D4).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {