@securitydept/client 0.2.0-beta.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/dist/auth-coordination/index.d.mts +198 -0
- package/dist/auth-coordination/index.mjs +107 -0
- package/dist/auth-coordination/index.mjs.map +1 -0
- package/dist/fetch-transport-CMG4tfDu.d.mts +368 -0
- package/dist/fetch-transport-DtnSRWAH.mjs +631 -0
- package/dist/fetch-transport-DtnSRWAH.mjs.map +1 -0
- package/dist/index-XkwmYaJF.d.mts +39 -0
- package/dist/index.d.mts +426 -0
- package/dist/index.mjs +661 -0
- package/dist/index.mjs.map +1 -0
- package/dist/persistence/index.d.mts +3 -0
- package/dist/persistence/index.mjs +2 -0
- package/dist/persistence/web/index.d.mts +16 -0
- package/dist/persistence/web/index.mjs +51 -0
- package/dist/persistence/web/index.mjs.map +1 -0
- package/dist/persistence-Db2CIFbx.mjs +108 -0
- package/dist/persistence-Db2CIFbx.mjs.map +1 -0
- package/dist/planner-host-CcEpcHws.mjs +195 -0
- package/dist/planner-host-CcEpcHws.mjs.map +1 -0
- package/dist/planner-host-DUZCkLj3.d.mts +190 -0
- package/dist/types-DKluXsWS.d.mts +52 -0
- package/dist/web/index.d.mts +329 -0
- package/dist/web/index.mjs +292 -0
- package/dist/web/index.mjs.map +1 -0
- package/dist/web-router/index.d.mts +259 -0
- package/dist/web-router/index.mjs +395 -0
- package/dist/web-router/index.mjs.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
//#region src/auth-coordination/planner-host.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A single requirement candidate that a guard submits to the planner-host.
|
|
4
|
+
*
|
|
5
|
+
* Each option describes:
|
|
6
|
+
* 1. What auth requirement it represents (id, kind, label)
|
|
7
|
+
* 2. How to check whether it's already satisfied
|
|
8
|
+
* 3. What to do when the planner selects it as the next pending action
|
|
9
|
+
*/
|
|
10
|
+
interface AuthGuardClientOption {
|
|
11
|
+
/** Unique identifier for this requirement candidate. */
|
|
12
|
+
requirementId: string;
|
|
13
|
+
/**
|
|
14
|
+
* The kind of auth requirement (opaque string).
|
|
15
|
+
* @example "session", "frontend_oidc", "backend_oidc"
|
|
16
|
+
*/
|
|
17
|
+
requirementKind: string;
|
|
18
|
+
/** Human-readable label (for logging / debugging / chooser UI). */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** Arbitrary metadata the adopter can attach. */
|
|
21
|
+
attributes?: Record<string, unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Check whether this requirement candidate is already authenticated.
|
|
24
|
+
* Called synchronously by the planner-host during evaluation.
|
|
25
|
+
*/
|
|
26
|
+
checkAuthenticated: () => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Action to execute when this candidate is selected as the pending
|
|
29
|
+
* requirement by the planner-host.
|
|
30
|
+
*
|
|
31
|
+
* Return value semantics:
|
|
32
|
+
* - `true` — allow navigation (requirement will be resolved externally)
|
|
33
|
+
* - `false` — block navigation
|
|
34
|
+
* - `string` — redirect to the given URL
|
|
35
|
+
* - `Promise<...>` — async version of the above
|
|
36
|
+
*/
|
|
37
|
+
onUnauthenticated: () => boolean | string | Promise<boolean | string>;
|
|
38
|
+
}
|
|
39
|
+
/** A flat collection of requirement candidates. */
|
|
40
|
+
interface RequirementsClientSet {
|
|
41
|
+
readonly options: readonly AuthGuardClientOption[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* How a child scope's requirements client set relates to its parent.
|
|
45
|
+
*
|
|
46
|
+
* - `inherit` — use the parent's set as-is (child adds nothing)
|
|
47
|
+
* - `merge` — inherit parent's options, then append/override with child's
|
|
48
|
+
* (child options with the same `requirementId` replace parent ones)
|
|
49
|
+
* - `replace` — discard parent's set entirely, use child's set only
|
|
50
|
+
*/
|
|
51
|
+
declare const RequirementsClientSetComposition: {
|
|
52
|
+
readonly Inherit: "inherit";
|
|
53
|
+
readonly Merge: "merge";
|
|
54
|
+
readonly Replace: "replace";
|
|
55
|
+
};
|
|
56
|
+
type RequirementsClientSetComposition = (typeof RequirementsClientSetComposition)[keyof typeof RequirementsClientSetComposition];
|
|
57
|
+
/** A requirements client set annotated with its composition strategy. */
|
|
58
|
+
interface ScopedRequirementsClientSet {
|
|
59
|
+
/** How this set composes with its parent scope. */
|
|
60
|
+
composition: RequirementsClientSetComposition;
|
|
61
|
+
/** The requirement candidates declared at this scope. */
|
|
62
|
+
options: readonly AuthGuardClientOption[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the effective requirements client set by composing a parent set
|
|
66
|
+
* with a child scope's declaration.
|
|
67
|
+
*
|
|
68
|
+
* @param parentOptions - The parent scope's resolved options (or empty).
|
|
69
|
+
* @param child - The child scope's scoped set (with composition strategy).
|
|
70
|
+
* @returns The effective options after composition.
|
|
71
|
+
*/
|
|
72
|
+
declare function resolveEffectiveClientSet(parentOptions: readonly AuthGuardClientOption[], child: ScopedRequirementsClientSet): AuthGuardClientOption[];
|
|
73
|
+
/** Result of a planner-host evaluation. */
|
|
74
|
+
interface PlannerHostResult {
|
|
75
|
+
/** Whether all candidates are authenticated (route can activate). */
|
|
76
|
+
allAuthenticated: boolean;
|
|
77
|
+
/** All candidates that are not yet authenticated. */
|
|
78
|
+
unauthenticatedCandidates: readonly AuthGuardClientOption[];
|
|
79
|
+
/**
|
|
80
|
+
* The candidate selected by the planner as the next one to act on.
|
|
81
|
+
* `null` when `allAuthenticated` is true.
|
|
82
|
+
*
|
|
83
|
+
* Determined by the RequirementPlanner's sequential resolution discipline:
|
|
84
|
+
* the first unresolved requirement in declaration order that is still
|
|
85
|
+
* unauthenticated, then optionally further narrowed by `selectCandidate`.
|
|
86
|
+
*/
|
|
87
|
+
pendingCandidate: AuthGuardClientOption | null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A candidate selection strategy.
|
|
91
|
+
*
|
|
92
|
+
* Receives the list of unauthenticated candidates (in RequirementPlanner
|
|
93
|
+
* declaration order) and returns the one that should be acted on next.
|
|
94
|
+
* The default strategy picks the first one (matching the planner's
|
|
95
|
+
* `nextPending` requirement).
|
|
96
|
+
*
|
|
97
|
+
* Async selectors are supported: return a `Promise<AuthGuardClientOption>`
|
|
98
|
+
* to implement interactive chooser UIs (e.g. show a dialog and await the
|
|
99
|
+
* user's pick before navigation continues).
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* // Async chooser: show a dialog and await user's selection
|
|
104
|
+
* const selectCandidate: CandidateSelector = async (candidates) => {
|
|
105
|
+
* const chosen = await showChooserDialog(candidates);
|
|
106
|
+
* return chosen;
|
|
107
|
+
* };
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
type CandidateSelector = (unauthenticated: readonly AuthGuardClientOption[]) => AuthGuardClientOption | Promise<AuthGuardClientOption>;
|
|
111
|
+
/** The planner-host coordination contract. */
|
|
112
|
+
interface PlannerHost {
|
|
113
|
+
/**
|
|
114
|
+
* Evaluate a set of requirement candidates using RequirementPlanner's
|
|
115
|
+
* sequential resolution discipline.
|
|
116
|
+
*
|
|
117
|
+
* Always returns a Promise so that custom async selectors (e.g. chooser
|
|
118
|
+
* dialog) are fully supported. Callers should always `await` the result.
|
|
119
|
+
*
|
|
120
|
+
* @param candidates - The resolved candidates from the guard's client options.
|
|
121
|
+
* @returns Promise resolving to the evaluation result.
|
|
122
|
+
*/
|
|
123
|
+
evaluate(candidates: readonly AuthGuardClientOption[]): Promise<PlannerHostResult>;
|
|
124
|
+
}
|
|
125
|
+
/** Options for {@link createPlannerHost}. */
|
|
126
|
+
interface CreatePlannerHostOptions {
|
|
127
|
+
/**
|
|
128
|
+
* Custom candidate selection strategy.
|
|
129
|
+
*
|
|
130
|
+
* The default strategy picks the candidate that corresponds to the
|
|
131
|
+
* RequirementPlanner's `nextPending` requirement (first unauthenticated
|
|
132
|
+
* in declaration order).
|
|
133
|
+
*
|
|
134
|
+
* A custom strategy can further filter or reorder the unauthenticated
|
|
135
|
+
* candidates, e.g. to implement a chooser UI that lets the user pick.
|
|
136
|
+
*
|
|
137
|
+
* @default first-unauthenticated-matching-planner-nextPending
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* // Async chooser: present all options and await user's pick
|
|
142
|
+
* createPlannerHost({
|
|
143
|
+
* selectCandidate: async (candidates) => {
|
|
144
|
+
* return await showChooserDialog(candidates);
|
|
145
|
+
* },
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
selectCandidate?: CandidateSelector;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a planner-host instance backed by {@link createRequirementPlanner}.
|
|
153
|
+
*
|
|
154
|
+
* **How it works:**
|
|
155
|
+
*
|
|
156
|
+
* 1. `evaluate()` builds an `AuthRequirement[]` from `candidates`
|
|
157
|
+
* (using each candidate's `requirementId`, `requirementKind`, `label`,
|
|
158
|
+
* and `attributes`).
|
|
159
|
+
* 2. A `RequirementPlanner` is created for this evaluation cycle.
|
|
160
|
+
* 3. Already-authenticated requirements are auto-resolved as `Fulfilled`,
|
|
161
|
+
* respecting the planner's sequential discipline.
|
|
162
|
+
* 4. The planner's `nextPending` determines the first unresolved requirement
|
|
163
|
+
* in declaration order.
|
|
164
|
+
* 5. `selectCandidate` is called with all unauthenticated candidates so
|
|
165
|
+
* adopters can implement custom chooser strategies (e.g. UI dialog).
|
|
166
|
+
* The default strategy picks the first candidate (matching nextPending).
|
|
167
|
+
*
|
|
168
|
+
* `evaluate()` always returns a `Promise` to accommodate async selectors.
|
|
169
|
+
* For synchronous selectors the Promise resolves in the same microtask tick.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* import { createPlannerHost } from "@securitydept/client/auth-coordination";
|
|
174
|
+
*
|
|
175
|
+
* // Default sequential strategy (sync selector, wrapped in Promise)
|
|
176
|
+
* const host = createPlannerHost();
|
|
177
|
+
* const result = await host.evaluate(candidates);
|
|
178
|
+
*
|
|
179
|
+
* // Async chooser strategy — show a dialog and await user's pick
|
|
180
|
+
* const hostWithChooser = createPlannerHost({
|
|
181
|
+
* selectCandidate: async (candidates) => {
|
|
182
|
+
* return await showChooserDialog(candidates);
|
|
183
|
+
* },
|
|
184
|
+
* });
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
declare function createPlannerHost(options?: CreatePlannerHostOptions): PlannerHost;
|
|
188
|
+
//#endregion
|
|
189
|
+
export { PlannerHostResult as a, ScopedRequirementsClientSet as c, PlannerHost as i, createPlannerHost as l, CandidateSelector as n, RequirementsClientSet as o, CreatePlannerHostOptions as r, RequirementsClientSetComposition as s, AuthGuardClientOption as t, resolveEffectiveClientSet as u };
|
|
190
|
+
//# sourceMappingURL=planner-host-DUZCkLj3.d.mts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/persistence/types.d.ts
|
|
2
|
+
/** Low-level key-value record store. */
|
|
3
|
+
interface RecordStore {
|
|
4
|
+
get(key: string): Promise<string | null>;
|
|
5
|
+
set(key: string, value: string): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Atomically read and remove a record within the store's consistency domain.
|
|
8
|
+
*/
|
|
9
|
+
take?(key: string): Promise<string | null>;
|
|
10
|
+
remove(key: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/** Serialization codec for typed values. */
|
|
13
|
+
interface Codec<T> {
|
|
14
|
+
encode(value: T): string;
|
|
15
|
+
decode(raw: string): T;
|
|
16
|
+
}
|
|
17
|
+
/** Semantic store for long-lived auth state. */
|
|
18
|
+
interface PersistentAuthStore<T> {
|
|
19
|
+
load(): Promise<T | null>;
|
|
20
|
+
save(value: T): Promise<void>;
|
|
21
|
+
clear(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/** Semantic store for recoverable state (survives page reload). */
|
|
24
|
+
interface RecoverableStateStore<T> {
|
|
25
|
+
load(): Promise<T | null>;
|
|
26
|
+
save(value: T): Promise<void>;
|
|
27
|
+
clear(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/** Semantic store for ephemeral flow state (one-time-use). */
|
|
30
|
+
interface EphemeralFlowStore<T> {
|
|
31
|
+
load(): Promise<T | null>;
|
|
32
|
+
save(value: T): Promise<void>;
|
|
33
|
+
consume(): Promise<T | null>;
|
|
34
|
+
clear(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/** Semantic store for keyed ephemeral flow state (one-time-use per key). */
|
|
37
|
+
interface KeyedEphemeralFlowStore<T> {
|
|
38
|
+
load(key: string): Promise<T | null>;
|
|
39
|
+
save(key: string, value: T): Promise<void>;
|
|
40
|
+
take(key: string): Promise<T | null>;
|
|
41
|
+
clear(key: string): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/** Versioned storage envelope — first-version migration support. */
|
|
44
|
+
interface StoredEnvelope<T> {
|
|
45
|
+
version: number;
|
|
46
|
+
storedAt: number;
|
|
47
|
+
expiresAt?: number;
|
|
48
|
+
value: T;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { RecordStore as a, PersistentAuthStore as i, EphemeralFlowStore as n, RecoverableStateStore as o, KeyedEphemeralFlowStore as r, StoredEnvelope as s, Codec as t };
|
|
52
|
+
//# sourceMappingURL=types-DKluXsWS.d.mts.map
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { S as ClientRuntime, d as Subscription, n as FetchTransportRedirectKind, r as createFetchTransport, t as FetchTransportOptions, z as CancellationTokenTrait } from "../fetch-transport-CMG4tfDu.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/web/cancellation.d.ts
|
|
4
|
+
interface AbortSignalBridge {
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
dispose(): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Bridge a web `AbortSignal` back into the foundation cancellation contract.
|
|
10
|
+
*
|
|
11
|
+
* This is the canonical consumer-side path for browser hosts that receive an
|
|
12
|
+
* `AbortSignal` from framework/runtime APIs (for example React Query queryFns)
|
|
13
|
+
* but need to call SDK surfaces that accept `CancellationTokenTrait`.
|
|
14
|
+
*/
|
|
15
|
+
declare function createCancellationTokenFromAbortSignal(signal?: AbortSignal): CancellationTokenTrait | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Bridge foundation cancellation to web `AbortSignal` without exposing
|
|
18
|
+
* `AbortSignal` in core contracts.
|
|
19
|
+
*/
|
|
20
|
+
declare function createAbortSignalBridge(token?: CancellationTokenTrait): AbortSignalBridge;
|
|
21
|
+
declare function normalizeAbortError(token: CancellationTokenTrait | undefined, error: unknown): unknown;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/web/cross-tab-sync.d.ts
|
|
24
|
+
/** Callback invoked when a cross-tab storage change is detected for the watched key. */
|
|
25
|
+
type CrossTabSyncCallback = (event: {
|
|
26
|
+
/** The new value written by the other tab, or null if the key was removed. */newValue: string | null; /** The old value before the other tab's write. */
|
|
27
|
+
oldValue: string | null;
|
|
28
|
+
}) => void;
|
|
29
|
+
/** Options for {@link createCrossTabSync}. */
|
|
30
|
+
interface CreateCrossTabSyncOptions {
|
|
31
|
+
/** The localStorage key to watch for cross-tab changes. */
|
|
32
|
+
key: string;
|
|
33
|
+
/** Called when another tab modifies the watched key. */
|
|
34
|
+
onSync: CrossTabSyncCallback;
|
|
35
|
+
/**
|
|
36
|
+
* Override the window target (primarily for testing).
|
|
37
|
+
* Defaults to `globalThis`.
|
|
38
|
+
*/
|
|
39
|
+
target?: {
|
|
40
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
41
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Handle returned by {@link createCrossTabSync}. */
|
|
45
|
+
interface CrossTabSync {
|
|
46
|
+
/** Stop listening for cross-tab storage events. */
|
|
47
|
+
dispose(): void;
|
|
48
|
+
/** Number of times a sync event has been received. */
|
|
49
|
+
readonly syncCount: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a cross-tab sync listener for a specific localStorage key.
|
|
53
|
+
*
|
|
54
|
+
* The browser `storage` event fires on ALL tabs EXCEPT the one that made the
|
|
55
|
+
* change. This makes it a natural primitive for cross-tab state notification.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const sync = createCrossTabSync({
|
|
60
|
+
* key: "auth:v1",
|
|
61
|
+
* onSync: ({ newValue }) => {
|
|
62
|
+
* if (newValue) {
|
|
63
|
+
* // Another tab updated auth state — reconcile
|
|
64
|
+
* controller.restoreFromPersistence();
|
|
65
|
+
* } else {
|
|
66
|
+
* // Another tab cleared auth state — log out
|
|
67
|
+
* controller.clearState({ clearPersisted: false });
|
|
68
|
+
* }
|
|
69
|
+
* },
|
|
70
|
+
* });
|
|
71
|
+
* // Later:
|
|
72
|
+
* sync.dispose();
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function createCrossTabSync(options: CreateCrossTabSyncOptions): CrossTabSync;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/web/input-sources.d.ts
|
|
78
|
+
interface AbortSignalSource {
|
|
79
|
+
aborted: boolean;
|
|
80
|
+
reason: unknown;
|
|
81
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
82
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
83
|
+
}
|
|
84
|
+
interface FromAbortSignalOptions {
|
|
85
|
+
/** AbortSignal to observe. */
|
|
86
|
+
signal?: AbortSignalSource;
|
|
87
|
+
/** Callback invoked when the signal aborts. */
|
|
88
|
+
callback: (reason: unknown) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Emit immediately when the signal is already aborted at subscribe time.
|
|
91
|
+
* Defaults to `false`.
|
|
92
|
+
*/
|
|
93
|
+
emitIfAborted?: boolean;
|
|
94
|
+
}
|
|
95
|
+
interface StorageEventTarget {
|
|
96
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
97
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
98
|
+
}
|
|
99
|
+
interface FromStorageEventOptions {
|
|
100
|
+
/**
|
|
101
|
+
* Storage-event target. Defaults to `globalThis`, which is appropriate for
|
|
102
|
+
* browser hosts and jsdom-based tests.
|
|
103
|
+
*/
|
|
104
|
+
target?: StorageEventTarget;
|
|
105
|
+
/** Callback invoked for each browser `storage` event. */
|
|
106
|
+
callback: (event: StorageEvent) => void;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Adapt a browser AbortSignal into the shared Subscription model.
|
|
110
|
+
*/
|
|
111
|
+
declare function fromAbortSignal(options: FromAbortSignalOptions): Subscription;
|
|
112
|
+
/**
|
|
113
|
+
* Adapt browser `storage` events into the shared Subscription model.
|
|
114
|
+
*/
|
|
115
|
+
declare function fromStorageEvent(options: FromStorageEventOptions): Subscription;
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/web/popup.d.ts
|
|
118
|
+
/** Stable error codes for popup-related failures. */
|
|
119
|
+
declare const PopupErrorCode: {
|
|
120
|
+
/** The browser blocked the popup window from opening. */readonly Blocked: "popup.blocked"; /** The popup was closed by the user before completing the flow. */
|
|
121
|
+
readonly Closed: "popup.closed_by_user"; /** The relay message was not received within the timeout. */
|
|
122
|
+
readonly Timeout: "popup.relay_timeout"; /** The relay message contained an error from the callback page. */
|
|
123
|
+
readonly RelayError: "popup.relay_error"; /** An unexpected error occurred during popup lifecycle. */
|
|
124
|
+
readonly Internal: "popup.internal";
|
|
125
|
+
};
|
|
126
|
+
type PopupErrorCode = (typeof PopupErrorCode)[keyof typeof PopupErrorCode];
|
|
127
|
+
/**
|
|
128
|
+
* Options for computing the popup window features string.
|
|
129
|
+
*/
|
|
130
|
+
interface PopupFeaturesOptions {
|
|
131
|
+
/** Width in pixels (default: 500). */
|
|
132
|
+
width?: number;
|
|
133
|
+
/** Height in pixels (default: 600). */
|
|
134
|
+
height?: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Compute the `features` string for `window.open()`, centered on screen.
|
|
138
|
+
*/
|
|
139
|
+
declare function computePopupFeatures(options?: PopupFeaturesOptions): string;
|
|
140
|
+
/**
|
|
141
|
+
* Result of opening a popup window.
|
|
142
|
+
*/
|
|
143
|
+
interface PopupWindowHandle {
|
|
144
|
+
/** The opened window reference. */
|
|
145
|
+
window: Window;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Open a popup window to the given URL.
|
|
149
|
+
*
|
|
150
|
+
* Throws a `ClientError` with code `popup.blocked` if the browser
|
|
151
|
+
* blocks the popup.
|
|
152
|
+
*/
|
|
153
|
+
declare function openPopupWindow(url: string, options?: PopupFeaturesOptions & {
|
|
154
|
+
target?: string;
|
|
155
|
+
}): PopupWindowHandle;
|
|
156
|
+
/**
|
|
157
|
+
* Expected shape of a relay message from the popup callback page.
|
|
158
|
+
*/
|
|
159
|
+
interface PopupRelayMessage {
|
|
160
|
+
/** Discriminator for the message type. */
|
|
161
|
+
type: "securitydept:popup_callback";
|
|
162
|
+
/** The callback URL or fragment received by the popup. */
|
|
163
|
+
payload: string;
|
|
164
|
+
/** Optional error from the callback page. */
|
|
165
|
+
error?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Options for waiting for a popup relay message.
|
|
169
|
+
*/
|
|
170
|
+
interface WaitForPopupRelayOptions {
|
|
171
|
+
/** The popup window handle to monitor. */
|
|
172
|
+
popup: PopupWindowHandle;
|
|
173
|
+
/** Maximum time to wait in milliseconds (default: 120000 = 2 minutes). */
|
|
174
|
+
timeoutMs?: number;
|
|
175
|
+
/** Expected origin for the relay message (default: current origin). */
|
|
176
|
+
expectedOrigin?: string;
|
|
177
|
+
/** Poll interval for checking if the popup is closed (default: 500ms). */
|
|
178
|
+
pollIntervalMs?: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Wait for a relay message from a popup callback page.
|
|
182
|
+
*
|
|
183
|
+
* The popup callback page should call `relayPopupCallback()` to post
|
|
184
|
+
* the callback URL back to the opener.
|
|
185
|
+
*
|
|
186
|
+
* Resolves with the callback payload (URL or fragment string).
|
|
187
|
+
* Rejects with a `ClientError` if:
|
|
188
|
+
* - the popup is closed without relaying (popup.closed_by_user)
|
|
189
|
+
* - the timeout expires (popup.relay_timeout)
|
|
190
|
+
* - the relay message contains an error (popup.relay_error)
|
|
191
|
+
*/
|
|
192
|
+
declare function waitForPopupRelay(options: WaitForPopupRelayOptions): Promise<string>;
|
|
193
|
+
/**
|
|
194
|
+
* Options for relaying the callback from the popup window back to the opener.
|
|
195
|
+
*/
|
|
196
|
+
interface RelayPopupCallbackOptions {
|
|
197
|
+
/** The callback payload (URL or fragment) to relay. */
|
|
198
|
+
payload?: string;
|
|
199
|
+
/** An error message to relay instead of a successful payload. */
|
|
200
|
+
error?: string;
|
|
201
|
+
/** Whether to close the popup after relaying (default: true). */
|
|
202
|
+
closeAfterRelay?: boolean;
|
|
203
|
+
/** Target origin for the postMessage (default: current origin). */
|
|
204
|
+
targetOrigin?: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Relay the popup callback result back to the opener window.
|
|
208
|
+
*
|
|
209
|
+
* Call this function from the popup callback page to send the callback
|
|
210
|
+
* URL/fragment back to the parent window that initiated the popup login.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```html
|
|
214
|
+
* <script type="module">
|
|
215
|
+
* import { relayPopupCallback } from "@securitydept/client/web";
|
|
216
|
+
* relayPopupCallback({ payload: window.location.href });
|
|
217
|
+
* </script>
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
declare function relayPopupCallback(options?: RelayPopupCallbackOptions): void;
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/web/runtime.d.ts
|
|
223
|
+
interface CreateWebRuntimeOptions extends Partial<Omit<ClientRuntime, "transport">> {
|
|
224
|
+
transport?: ClientRuntime["transport"];
|
|
225
|
+
fetchTransport?: FetchTransportOptions;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Create a `ClientRuntime` for browser/Web-capable environments.
|
|
229
|
+
*/
|
|
230
|
+
declare function createWebRuntime(overrides?: CreateWebRuntimeOptions): ClientRuntime;
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/web/visibility.d.ts
|
|
233
|
+
/** Visibility state snapshot passed to the callback. */
|
|
234
|
+
declare const VisibilityState: {
|
|
235
|
+
readonly Visible: "visible";
|
|
236
|
+
readonly Hidden: "hidden";
|
|
237
|
+
};
|
|
238
|
+
type VisibilityState = (typeof VisibilityState)[keyof typeof VisibilityState];
|
|
239
|
+
/** Options for {@link fromVisibilityChange}. */
|
|
240
|
+
interface FromVisibilityChangeOptions {
|
|
241
|
+
/**
|
|
242
|
+
* Callback invoked when the document visibility state changes.
|
|
243
|
+
*
|
|
244
|
+
* The callback receives the new visibility state ("visible" or "hidden").
|
|
245
|
+
*/
|
|
246
|
+
callback: (state: VisibilityState) => void;
|
|
247
|
+
/**
|
|
248
|
+
* Override the document target (primarily for testing).
|
|
249
|
+
* Defaults to `globalThis.document`.
|
|
250
|
+
*/
|
|
251
|
+
document?: Pick<Document, "addEventListener" | "removeEventListener" | "visibilityState">;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Subscribe to browser document visibility changes.
|
|
255
|
+
*
|
|
256
|
+
* Built on {@link fromEventPattern} so it follows the same Subscription
|
|
257
|
+
* contract. Returns a {@link Subscription} handle for cleanup.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* const sub = fromVisibilityChange({
|
|
262
|
+
* callback: (state) => {
|
|
263
|
+
* if (state === VisibilityState.Visible) {
|
|
264
|
+
* scheduleRefresh();
|
|
265
|
+
* }
|
|
266
|
+
* },
|
|
267
|
+
* });
|
|
268
|
+
* // Cleanup:
|
|
269
|
+
* sub.unsubscribe();
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function fromVisibilityChange(options: FromVisibilityChangeOptions): Subscription;
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/web/visibility-reconciler.d.ts
|
|
275
|
+
/** Callback invoked when the page becomes visible and reconciliation is needed. */
|
|
276
|
+
type ReconcileCallback = () => void | Promise<void>;
|
|
277
|
+
/** Options for {@link createVisibilityReconciler}. */
|
|
278
|
+
interface CreateVisibilityReconcilerOptions {
|
|
279
|
+
/**
|
|
280
|
+
* Called when the document transitions from hidden → visible.
|
|
281
|
+
* The reconciler only fires on the hidden→visible edge; repeated
|
|
282
|
+
* visible→visible events are suppressed.
|
|
283
|
+
*/
|
|
284
|
+
onReconcile: ReconcileCallback;
|
|
285
|
+
/**
|
|
286
|
+
* Minimum interval (ms) between reconciliation triggers.
|
|
287
|
+
* Prevents rapid-fire reconciliation when the user toggles tabs quickly.
|
|
288
|
+
* Defaults to 5000ms (5 seconds).
|
|
289
|
+
*/
|
|
290
|
+
throttleMs?: number;
|
|
291
|
+
/**
|
|
292
|
+
* Override the document target (primarily for testing).
|
|
293
|
+
* Defaults to `globalThis.document`.
|
|
294
|
+
*/
|
|
295
|
+
document?: FromVisibilityChangeOptions["document"];
|
|
296
|
+
/**
|
|
297
|
+
* Clock override for testing.
|
|
298
|
+
*/
|
|
299
|
+
now?: () => number;
|
|
300
|
+
}
|
|
301
|
+
/** Handle returned by {@link createVisibilityReconciler}. */
|
|
302
|
+
interface VisibilityReconciler {
|
|
303
|
+
/** Stop listening for visibility changes. */
|
|
304
|
+
dispose(): void;
|
|
305
|
+
/** Number of times reconciliation has been triggered. */
|
|
306
|
+
readonly reconcileCount: number;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Create a visibility reconciler that triggers a callback when the page
|
|
310
|
+
* transitions from hidden → visible.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* const reconciler = createVisibilityReconciler({
|
|
315
|
+
* onReconcile: () => {
|
|
316
|
+
* // Re-check token freshness or sync cross-tab state
|
|
317
|
+
* if (controller.snapshot?.tokens.accessTokenExpiresAt) {
|
|
318
|
+
* scheduleRefreshIfExpired();
|
|
319
|
+
* }
|
|
320
|
+
* },
|
|
321
|
+
* });
|
|
322
|
+
* // Later:
|
|
323
|
+
* reconciler.dispose();
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
declare function createVisibilityReconciler(options: CreateVisibilityReconcilerOptions): VisibilityReconciler;
|
|
327
|
+
//#endregion
|
|
328
|
+
export { type AbortSignalBridge, type CreateCrossTabSyncOptions, type CreateVisibilityReconcilerOptions, type CreateWebRuntimeOptions, type CrossTabSync, type CrossTabSyncCallback, type FetchTransportOptions, FetchTransportRedirectKind, type FromAbortSignalOptions, type FromStorageEventOptions, type FromVisibilityChangeOptions, PopupErrorCode, type PopupFeaturesOptions, type PopupRelayMessage, type PopupWindowHandle, type ReconcileCallback, type RelayPopupCallbackOptions, type VisibilityReconciler, VisibilityState, type WaitForPopupRelayOptions, computePopupFeatures, createAbortSignalBridge, createCancellationTokenFromAbortSignal, createCrossTabSync, createFetchTransport, createVisibilityReconciler, createWebRuntime, fromAbortSignal, fromStorageEvent, fromVisibilityChange, normalizeAbortError, openPopupWindow, relayPopupCallback, waitForPopupRelay };
|
|
329
|
+
//# sourceMappingURL=index.d.mts.map
|