@dudousxd/nestjs-durable-dashboard 0.53.0 → 0.55.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/dist/client/durable-client.d.ts +67 -3
- package/dist/client/durable-client.d.ts.map +1 -1
- package/dist/client/durable-client.js +26 -46
- package/dist/client/durable-client.js.map +1 -1
- package/dist/client/event-tail.d.ts +25 -0
- package/dist/client/event-tail.d.ts.map +1 -0
- package/dist/client/event-tail.js +30 -0
- package/dist/client/event-tail.js.map +1 -0
- package/dist/server/index.cjs +322 -1337
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +149 -389
- package/dist/server/index.d.ts +149 -389
- package/dist/server/index.js +308 -1317
- package/dist/server/index.js.map +1 -1
- package/dist/spa/assets/{bench-Db-gqOEF.js → bench-DCclNvcZ.js} +1 -1
- package/dist/spa/assets/index-B-wtX4GV.js +66 -0
- package/dist/spa/assets/index-CJdk28vt.css +1 -0
- package/dist/spa/assets/{index-4tEXGRlA.js → index-ChjKRQZx.js} +1 -1
- package/dist/spa/assets/{preview-BvCp1zR5.js → preview-CdsjvOrK.js} +1 -1
- package/dist/spa/bench.html +3 -3
- package/dist/spa/index.html +3 -3
- package/dist/spa/preview.html +3 -3
- package/package.json +5 -18
- package/dist/client/console-session.d.ts +0 -63
- package/dist/client/console-session.d.ts.map +0 -1
- package/dist/client/console-session.js +0 -107
- package/dist/client/console-session.js.map +0 -1
- package/dist/react/index.d.ts +0 -4
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/index.js +0 -14
- package/dist/react/index.js.map +0 -1
- package/dist/react/open-console-button.d.ts +0 -26
- package/dist/react/open-console-button.d.ts.map +0 -1
- package/dist/react/open-console-button.js +0 -26
- package/dist/react/open-console-button.js.map +0 -1
- package/dist/react/use-open-console.d.ts +0 -40
- package/dist/react/use-open-console.d.ts.map +0 -1
- package/dist/react/use-open-console.js +0 -77
- package/dist/react/use-open-console.js.map +0 -1
- package/dist/spa/assets/index-BbR4CZ1K.css +0 -1
- package/dist/spa/assets/index-CEV7yPmk.js +0 -66
package/dist/server/index.d.ts
CHANGED
|
@@ -1,108 +1,11 @@
|
|
|
1
1
|
import * as _dudousxd_nestjs_durable_core from '@dudousxd/nestjs-durable-core';
|
|
2
|
-
import { RunGateway, StateStore, WorkflowEngine, ScheduleListQuery, ScheduleDescription, RunResult, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, DurableTopology, GroupHealth, RunDetailOptions, RunDetail, FanPageQuery, FanPage, UpdateResult, EngineEvent, AttributeFilter } from '@dudousxd/nestjs-durable-core';
|
|
2
|
+
import { RunGateway, StateStore, WorkflowEngine, ScheduleListQuery, ScheduleDescription, RunResult, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, DurableTopology, GroupHealth, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RepublishLifecycleResult, WorkflowLifecycleLinks, UpdateResult, EngineEvent, AttributeFilter } from '@dudousxd/nestjs-durable-core';
|
|
3
3
|
export { RunDetail } from '@dudousxd/nestjs-durable-core';
|
|
4
4
|
import * as rxjs from 'rxjs';
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
import * as _dudousxd_nestjs_filter from '@dudousxd/nestjs-filter';
|
|
7
7
|
import { FilterRunner } from '@dudousxd/nestjs-filter';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
/** The session user the host `login` hook returns to mint a cookie. */
|
|
11
|
-
interface DashboardSessionUser {
|
|
12
|
-
id: string;
|
|
13
|
-
name?: string;
|
|
14
|
-
roles?: string[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Host hook for Mode A — validates the host's own auth on the raw request. */
|
|
18
|
-
type SessionHook = (request: unknown) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
19
|
-
/** Host hook for Mode B — validates submitted credentials from the built-in login page. */
|
|
20
|
-
type LoginHook = (username: string, password: string) => Promise<DashboardSessionUser | null> | DashboardSessionUser | null;
|
|
21
|
-
/**
|
|
22
|
-
* Re-checks a LIVE session when the cookie is slid forward. Runs at most once per `ttl/2` per
|
|
23
|
-
* session, so a DB round-trip here is cheap — this holds even under concurrent traffic: N parallel
|
|
24
|
-
* requests carrying the same past-half-life cookie share ONE call (see `revalidateOnce` in
|
|
25
|
-
* `session-cookie-io.ts`), not N. Return `false` to revoke (the cookie is cleared and the request
|
|
26
|
-
* denied). Distinct from `session`: that hook reads the host's auth off a fresh request, which a
|
|
27
|
-
* console XHR does not carry — this one receives the already-minted session.
|
|
28
|
-
*/
|
|
29
|
-
type RevalidateHook = (session: DashboardSessionUser) => Promise<boolean> | boolean;
|
|
30
|
-
/** What `unauthenticatedPage` receives. An object (not positional args) so fields can be added later. */
|
|
31
|
-
interface UnauthenticatedPageContext {
|
|
32
|
-
/**
|
|
33
|
-
* The platform-native request — Express' `Request`, Fastify's `FastifyRequest`. Typed `unknown`
|
|
34
|
-
* for the same reason `SessionHook`'s is: this package refuses to depend on either platform.
|
|
35
|
-
* Cast it to whatever your app actually runs on.
|
|
36
|
-
*/
|
|
37
|
-
request: unknown;
|
|
38
|
-
/**
|
|
39
|
-
* The platform-native response. The hook OWNS it: it must write AND end it (`res.render(...)`,
|
|
40
|
-
* `res.status(401).send(...)`, an Inertia render, ...). If the hook returns without writing, the
|
|
41
|
-
* library falls back to its own built-in page rather than leaving the request hanging.
|
|
42
|
-
*/
|
|
43
|
-
response: unknown;
|
|
44
|
-
/** Where this console is mounted (e.g. `/durable`) — useful for a "back to the console" link. */
|
|
45
|
-
basePath: string;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Host-owned page for an unauthenticated full-page navigation to the console.
|
|
49
|
-
*
|
|
50
|
-
* The built-in page cannot know who hosts the console, so it can only say "open this console from
|
|
51
|
-
* your application" in the abstract — it can't name the launcher, link to it, or look like the rest
|
|
52
|
-
* of the host's product. This hook hands the whole response to the host instead: render through
|
|
53
|
-
* your own template engine, your own Inertia page, whatever. The page is served AT the console's
|
|
54
|
-
* own URL, so `/durable` stays `/durable`.
|
|
55
|
-
*
|
|
56
|
-
* Deliberately NOT a replacement for Mode B's built-in login form. A host that wants its own login
|
|
57
|
-
* UI uses Mode A plus this hook, and posts to `<basePath>/session` from its own page — the mint
|
|
58
|
-
* endpoint is the supported primitive for that.
|
|
59
|
-
*
|
|
60
|
-
* Fail-closed by construction: it only ever runs on a request that has ALREADY been denied. A hook
|
|
61
|
-
* that throws, or that returns without writing, falls back to the built-in page — it cannot let
|
|
62
|
-
* anyone in.
|
|
63
|
-
*/
|
|
64
|
-
type UnauthenticatedPageHook = (context: UnauthenticatedPageContext) => void | Promise<void>;
|
|
65
|
-
type AuthMode = 'session' | 'login';
|
|
66
|
-
/**
|
|
67
|
-
* Author-facing `dashboardAuth` option on `DurableDashboardModule.forRoot`/`forRootAsync`. Gates
|
|
68
|
-
* BOTH the SPA (a full-page navigation redirected to a server-rendered login page) and the JSON
|
|
69
|
-
* API (a plain `401`) behind a signed session cookie, mirroring `@dudousxd/nestjs-telescope`'s
|
|
70
|
-
* `dashboardAuth` mechanism (same HMAC-SHA256 cookie, same fail-closed validation). Two ways to
|
|
71
|
-
* mint that cookie: Mode A (`session`) — the host frontend, already carrying its own auth, POSTs
|
|
72
|
-
* to `<basePath>/session` and the host hook decides; or Mode B (`login`) — the built-in,
|
|
73
|
-
* dependency-free server-rendered login page (`GET <basePath>/login`). At least one of the two is
|
|
74
|
-
* required so an un-mintable gate is a boot error, not a silently-open (or silently-stuck) console.
|
|
75
|
-
*/
|
|
76
|
-
interface DashboardAuthOptions {
|
|
77
|
-
/** REQUIRED HMAC-SHA256 signing key. Missing/empty => boot error (fail closed). */
|
|
78
|
-
secret: string;
|
|
79
|
-
/** Cookie TTL as a duration string (`'8h'`, `'30m'`, `'7d'`). Default `'8h'`. */
|
|
80
|
-
ttl?: string;
|
|
81
|
-
/** Mode A: validates the host's own auth on the raw request POSTed to `<basePath>/session`;
|
|
82
|
-
* return the session user, or `null` to deny. Thrown errors are treated as a denial (logged
|
|
83
|
-
* once, never surfaced to the client). */
|
|
84
|
-
session?: SessionHook;
|
|
85
|
-
/** Mode B: validates submitted username/password from the built-in login page; return the
|
|
86
|
-
* session user, or `null` to deny. Thrown errors are treated as a denial (logged once, never
|
|
87
|
-
* surfaced to the client). */
|
|
88
|
-
login?: LoginHook;
|
|
89
|
-
/** Re-checks a live session on sliding renewal; see `RevalidateHook`. Not a mode — it cannot
|
|
90
|
-
* mint a session, only revoke one already minted by `session`/`login`. */
|
|
91
|
-
revalidate?: RevalidateHook;
|
|
92
|
-
/** Renders the host's own page for an unauthenticated navigation, in place of the built-in
|
|
93
|
-
* "open this console from your application" card; see `UnauthenticatedPageHook`. */
|
|
94
|
-
unauthenticatedPage?: UnauthenticatedPageHook;
|
|
95
|
-
}
|
|
96
|
-
/** Resolved, validated `dashboardAuth` config shared by the guards, auth controller, and login page. */
|
|
97
|
-
interface ResolvedDashboardAuth {
|
|
98
|
-
secret: string;
|
|
99
|
-
ttlMs: number;
|
|
100
|
-
modes: AuthMode[];
|
|
101
|
-
session?: SessionHook;
|
|
102
|
-
login?: LoginHook;
|
|
103
|
-
revalidate?: RevalidateHook;
|
|
104
|
-
unauthenticatedPage?: UnauthenticatedPageHook;
|
|
105
|
-
}
|
|
8
|
+
import { DynamicModule, StreamableFile } from '@nestjs/common';
|
|
106
9
|
|
|
107
10
|
/**
|
|
108
11
|
* Read-model and actions backing the control-plane UI. Run-facing ops (list/detail/retry/cancel/
|
|
@@ -113,6 +16,17 @@ interface ResolvedDashboardAuth {
|
|
|
113
16
|
* Operator-only ops (metrics/deliverWebhook/getEvent/update) still need direct `store`/`engine`
|
|
114
17
|
* access; they stay `@Optional()` and throw a clear error when absent.
|
|
115
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* A workflow's lifecycle links as `GET workflows/:name/lifecycle` answers them, plus `triggerCounts`:
|
|
21
|
+
* per subscriber of `startsOnSettle`, how many runs it was started for (`triggered`) and how many
|
|
22
|
+
* times starting it failed (`failed`), counted by this process's metrics since it started.
|
|
23
|
+
*/
|
|
24
|
+
interface WorkflowLifecyclePage extends WorkflowLifecycleLinks {
|
|
25
|
+
triggerCounts?: Record<string, {
|
|
26
|
+
triggered: number;
|
|
27
|
+
failed: number;
|
|
28
|
+
}> | undefined;
|
|
29
|
+
}
|
|
116
30
|
declare class DashboardService {
|
|
117
31
|
private readonly gateway;
|
|
118
32
|
private readonly store?;
|
|
@@ -176,6 +90,23 @@ declare class DashboardService {
|
|
|
176
90
|
cancel(runId: string, opts?: {
|
|
177
91
|
compensate?: boolean;
|
|
178
92
|
}): Promise<RunResult | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Publish a settled run's lifecycle event again, to its subscribers that have not started (or to
|
|
95
|
+
* `subscriber` alone). Undefined when the gateway cannot republish (a tenant proxy).
|
|
96
|
+
*/
|
|
97
|
+
republishLifecycle(runId: string, subscriber?: string): Promise<RepublishLifecycleResult | undefined>;
|
|
98
|
+
/**
|
|
99
|
+
* Who starts whom through lifecycle events, for `workflow`, plus `triggerCounts` when this process
|
|
100
|
+
* counts the engine's events (the control plane) and the workflow has subscribers. Undefined when
|
|
101
|
+
* the gateway cannot answer.
|
|
102
|
+
*/
|
|
103
|
+
workflowLifecycle(workflow: string): Promise<WorkflowLifecyclePage | undefined>;
|
|
104
|
+
/**
|
|
105
|
+
* How many runs each subscriber of `links.workflow` was started for and how many times starting it
|
|
106
|
+
* failed, counted by this process's metrics since it started. Undefined without metrics (a tenant)
|
|
107
|
+
* or without subscribers.
|
|
108
|
+
*/
|
|
109
|
+
private triggerCountsOf;
|
|
179
110
|
/**
|
|
180
111
|
* Apply `retry` or `cancel` to every run matching a filter (status / tag / workflow / namespace /
|
|
181
112
|
* origin) — e.g. "retry every `dead` run tagged `type:mel`". The filter is the same one the run
|
|
@@ -258,14 +189,20 @@ declare class RunQueryDraft {
|
|
|
258
189
|
}
|
|
259
190
|
|
|
260
191
|
/**
|
|
261
|
-
* JSON API consumed by the control-plane SPA.
|
|
192
|
+
* JSON API consumed by the control-plane SPA. The mounted {@link DurableApiController} sits at
|
|
193
|
+
* `apiBasePath` (set by RouterModule).
|
|
194
|
+
*
|
|
195
|
+
* This base is what a host EXTENDS to serve the API from a controller of its own (with
|
|
196
|
+
* `forRoot({ routes: false, apiBasePath })`): `@Controller('<apiBasePath>') class MyConsoleApi
|
|
197
|
+
* extends DurableApiControllerBase {}`. It carries no guards and no `@nestjs/authorization` mark,
|
|
198
|
+
* so a subclass is protected only by what the host puts on it.
|
|
262
199
|
*
|
|
263
200
|
* The filter interceptor (what resolves `@ApplyFilter` into a query) is bound HERE rather than as
|
|
264
201
|
* the app-wide `APP_INTERCEPTOR` that `FilterModule.forRoot()` registers: a library must not add a
|
|
265
202
|
* global interceptor to its host, and on an app that already has one this would be the second copy,
|
|
266
203
|
* running every filter in the app twice.
|
|
267
204
|
*/
|
|
268
|
-
declare class
|
|
205
|
+
declare class DurableApiControllerBase {
|
|
269
206
|
private readonly dashboard;
|
|
270
207
|
private readonly runner;
|
|
271
208
|
constructor(dashboard: DashboardService, runner: FilterRunner);
|
|
@@ -318,6 +255,11 @@ declare class DurableApiController {
|
|
|
318
255
|
resumeSchedule(id: string): Promise<_dudousxd_nestjs_durable_core.ScheduleDescription>;
|
|
319
256
|
/** Start one run of the schedule now, outside its cadence. */
|
|
320
257
|
triggerSchedule(id: string): Promise<_dudousxd_nestjs_durable_core.RunResult>;
|
|
258
|
+
/**
|
|
259
|
+
* Who starts whom through lifecycle events, for one workflow: the workflows that start when it
|
|
260
|
+
* settles, and the ones whose settling starts it. What the console's workflow page lists.
|
|
261
|
+
*/
|
|
262
|
+
workflowLifecycle(name: string): Promise<WorkflowLifecyclePage>;
|
|
321
263
|
/** This deployment's durable role (control plane vs tenant) + tenant name — for the header badge. */
|
|
322
264
|
topology(): _dudousxd_nestjs_durable_core.DurableTopology;
|
|
323
265
|
/**
|
|
@@ -334,6 +276,13 @@ declare class DurableApiController {
|
|
|
334
276
|
children: string[];
|
|
335
277
|
fans?: _dudousxd_nestjs_durable_core.FanSummary[] | undefined;
|
|
336
278
|
childCount?: number | undefined;
|
|
279
|
+
triggered?: string[] | undefined;
|
|
280
|
+
triggeredBy?: _dudousxd_nestjs_durable_core.LifecycleSource | undefined;
|
|
281
|
+
lifecycleSubscribers?: string[] | undefined;
|
|
282
|
+
workflowLifecycle?: _dudousxd_nestjs_durable_core.WorkflowLifecycleLinks | undefined;
|
|
283
|
+
lifecycleDeliveries?: _dudousxd_nestjs_durable_core.LifecycleDelivery[] | undefined;
|
|
284
|
+
waitsFor?: _dudousxd_nestjs_durable_core.RunWaitLink[] | undefined;
|
|
285
|
+
awaitedBy?: _dudousxd_nestjs_durable_core.RunWaitLink[] | undefined;
|
|
337
286
|
}>;
|
|
338
287
|
/** One page of a summarized fan's members, in seq order. Versioned like {@link run}. */
|
|
339
288
|
fanMembers(id: string, group: string, offset?: string, limit?: string, failed?: string, ifNoneMatch?: string, response?: unknown): Promise<{
|
|
@@ -362,6 +311,13 @@ declare class DurableApiController {
|
|
|
362
311
|
applied: number;
|
|
363
312
|
}>;
|
|
364
313
|
cancel(id: string, compensate?: string): Promise<_dudousxd_nestjs_durable_core.RunResult>;
|
|
314
|
+
/**
|
|
315
|
+
* Publish a settled run's lifecycle event again, to the subscribers that have not started from it
|
|
316
|
+
* (or only `subscriber`). Same gate as retry/cancel.
|
|
317
|
+
*/
|
|
318
|
+
republishLifecycle(id: string, body?: {
|
|
319
|
+
subscriber?: string;
|
|
320
|
+
}): Promise<_dudousxd_nestjs_durable_core.RepublishLifecycleResult>;
|
|
365
321
|
continue(id: string): Promise<_dudousxd_nestjs_durable_core.RunResult>;
|
|
366
322
|
/** Re-dispatch a run's stuck `pending` remote steps — recovery for a lost step dispatch. */
|
|
367
323
|
redispatch(id: string): Promise<_dudousxd_nestjs_durable_core.RunResult & {
|
|
@@ -379,103 +335,13 @@ declare class DurableApiController {
|
|
|
379
335
|
/** Deliver a validated `ctx.onUpdate` to a run; the body is the update argument. */
|
|
380
336
|
update(id: string, name: string, body: unknown): Promise<_dudousxd_nestjs_durable_core.UpdateResult>;
|
|
381
337
|
}
|
|
382
|
-
|
|
383
|
-
interface LoginBody {
|
|
384
|
-
username?: unknown;
|
|
385
|
-
password?: unknown;
|
|
386
|
-
returnTo?: unknown;
|
|
387
|
-
}
|
|
388
338
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
* only registered when `dashboardAuth` might be configured (a static `forRoot({ dashboardAuth })`
|
|
394
|
-
* or any `forRootAsync`), but the resolved value can still be `null` at runtime for the async case
|
|
395
|
-
* — every handler below re-checks it and 404s rather than assuming it is set.
|
|
339
|
+
* The JSON API controller `DurableDashboardModule.forRoot(...)` mounts at `apiBasePath`. The module
|
|
340
|
+
* puts the `@nestjs/authorization` open mark on THIS class (and `decorators` on a per-registration
|
|
341
|
+
* subclass of it), never on {@link DurableApiControllerBase}, so a host's own subclass of the base
|
|
342
|
+
* inherits none of them.
|
|
396
343
|
*/
|
|
397
|
-
declare class
|
|
398
|
-
private readonly auth;
|
|
399
|
-
private readonly basePath;
|
|
400
|
-
private readonly logger;
|
|
401
|
-
/** Warn once per hook kind so a throwing hook doesn't spam logs on every failed attempt. */
|
|
402
|
-
private readonly warnedHooks;
|
|
403
|
-
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
404
|
-
loginPage(): string;
|
|
405
|
-
login(body: LoginBody, request: unknown, response: unknown): Promise<{
|
|
406
|
-
redirectTo: string;
|
|
407
|
-
}>;
|
|
408
|
-
session(request: unknown, response: unknown): Promise<void>;
|
|
409
|
-
logout(request: unknown, response: unknown): void;
|
|
410
|
-
private requireAuth;
|
|
411
|
-
/**
|
|
412
|
-
* Run a host hook (`login` or `session`) defensively: a throw is treated as a denial (uniform
|
|
413
|
-
* failure) and warn-logged once PER KIND, so a buggy hook never 500s the endpoint into a
|
|
414
|
-
* stack-trace leak nor floods the logs on repeated bad attempts.
|
|
415
|
-
*/
|
|
416
|
-
private runHook;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/** The env var the token gate reads when no `token` option is given. */
|
|
420
|
-
declare const DURABLE_DASHBOARD_TOKEN_ENV = "DURABLE_DASHBOARD_TOKEN";
|
|
421
|
-
/** DI token carrying the resolved {@link DashboardGate} (one per dashboard mount). */
|
|
422
|
-
declare const DASHBOARD_GATE: unique symbol;
|
|
423
|
-
/**
|
|
424
|
-
* What the module knows about how the console is protected, captured at `forRoot`/`forRootAsync`
|
|
425
|
-
* time. Everything that can change between module definition and boot (env vars, the async
|
|
426
|
-
* `dashboardAuth` factory) is read later, in {@link resolveDashboardGate}.
|
|
427
|
-
*/
|
|
428
|
-
interface DashboardGateOptions {
|
|
429
|
-
/** Host `guards` were passed (non-empty). */
|
|
430
|
-
hasGuards: boolean;
|
|
431
|
-
/** `allowUnauthenticated` as passed. */
|
|
432
|
-
allowUnauthenticated?: boolean;
|
|
433
|
-
/** `token` as passed (else `DURABLE_DASHBOARD_TOKEN` is read at boot). */
|
|
434
|
-
token?: string;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* How the gate treats every console request:
|
|
438
|
-
*
|
|
439
|
-
* - `delegated`: `guards` or `dashboardAuth` protect the console; the gate passes everything.
|
|
440
|
-
* - `open`: `allowUnauthenticated: true`; the gate passes everything (warned at boot).
|
|
441
|
-
* - `token`: a request must carry the token (`Authorization: Bearer`, `x-durable-token`, or
|
|
442
|
-
* `?token=` on GET/HEAD).
|
|
443
|
-
* - `unconfigured`: nothing was configured outside production; the gate passes everything
|
|
444
|
-
* (warned at boot, because production will deny).
|
|
445
|
-
* - `deny`: nothing was configured and `NODE_ENV=production`; every request is refused.
|
|
446
|
-
*/
|
|
447
|
-
type DashboardGateMode = 'delegated' | 'open' | 'token' | 'unconfigured' | 'deny';
|
|
448
|
-
interface DashboardGate {
|
|
449
|
-
mode: DashboardGateMode;
|
|
450
|
-
/** Set only when `mode === 'token'`. */
|
|
451
|
-
token?: string;
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
* Decide the gate mode. Precedence: `guards`/`dashboardAuth` (they are the gate) > a token > the
|
|
455
|
-
* `allowUnauthenticated` opt-out > the environment default. A token beats `allowUnauthenticated`
|
|
456
|
-
* because a configured secret is never silently ignored.
|
|
457
|
-
*/
|
|
458
|
-
declare function resolveDashboardGate(options: DashboardGateOptions, auth: ResolvedDashboardAuth | null): DashboardGate;
|
|
459
|
-
/** Log the one boot line the resolved gate calls for (nothing for a properly configured console). */
|
|
460
|
-
declare function reportDashboardGate(gate: DashboardGate, options: DashboardGateOptions, logger?: Pick<Logger, 'warn' | 'error'>): void;
|
|
461
|
-
/** The `DASHBOARD_GATE` provider: resolves once, after `DASHBOARD_AUTH`, and logs once. */
|
|
462
|
-
declare function dashboardGateProvider(options: DashboardGateOptions): Provider;
|
|
463
|
-
/**
|
|
464
|
-
* Read the token from `Authorization: Bearer <token>`, `x-durable-token`, or (GET/HEAD only) a
|
|
465
|
-
* `token` query param. The query channel is read-only on purpose: a `?token=` URL ends up in access
|
|
466
|
-
* logs, `Referer` headers and browser history, and must never authorize a mutation.
|
|
467
|
-
*/
|
|
468
|
-
declare function readDashboardToken(request: unknown): string | undefined;
|
|
469
|
-
/**
|
|
470
|
-
* The fail-closed default gate, stamped on `DurableUiController` and `DurableApiController` (after
|
|
471
|
-
* the built-in session guard, before host `guards`) whenever the module can't prove at definition
|
|
472
|
-
* time that something else protects the console. It never gates `DurableAuthController`, so the
|
|
473
|
-
* login/session/logout routes stay reachable. See {@link DashboardGateMode} for what each mode does.
|
|
474
|
-
*/
|
|
475
|
-
declare class DurableDashboardGateGuard implements CanActivate {
|
|
476
|
-
private readonly gate;
|
|
477
|
-
constructor(gate: DashboardGate);
|
|
478
|
-
canActivate(context: ExecutionContext): boolean;
|
|
344
|
+
declare class DurableApiController extends DurableApiControllerBase {
|
|
479
345
|
}
|
|
480
346
|
|
|
481
347
|
interface DurableDashboardOptions {
|
|
@@ -491,150 +357,76 @@ interface DurableDashboardOptions {
|
|
|
491
357
|
*/
|
|
492
358
|
apiBasePath?: string;
|
|
493
359
|
/**
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
* call stamped, same as re-applying `@UseGuards` by hand. A non-empty `guards` counts as the
|
|
498
|
-
* console's authentication, so the fail-closed default gate steps aside (see
|
|
499
|
-
* {@link allowUnauthenticated}). If the host fronts the routes another way (a global guard,
|
|
500
|
-
* reverse-proxy auth), say so with `allowUnauthenticated: true` instead.
|
|
501
|
-
*
|
|
502
|
-
* A guard's own DEPENDENCIES resolve from this module's `imports` (see {@link imports}) — the
|
|
503
|
-
* dashboard module has no application context of its own to pull them from otherwise.
|
|
504
|
-
*
|
|
505
|
-
* Auth reality for the two mount points: `apiBasePath` is fetched by the SPA's own JS (an XHR/fetch
|
|
506
|
-
* from the same origin), so a guard reading a bearer/`Authorization` header there works exactly like
|
|
507
|
-
* any other API route. `basePath` (the UI shell, `DurableUiController.index()`) is a full-page
|
|
508
|
-
* navigation — the BROWSER issues that GET directly (typing the URL, a bookmark, a link click), so
|
|
509
|
-
* there is no custom header to read: only whatever ambient credential the browser sends by default
|
|
510
|
-
* (a cookie, or nothing) reaches the guard there. A guard that only checks an `Authorization` header
|
|
511
|
-
* will 403 the page shell while the API calls it makes right after would have passed — put session
|
|
512
|
-
* auth behind a cookie (or front the UI mount with your reverse proxy / SSO instead) if you need the
|
|
513
|
-
* shell itself gated.
|
|
514
|
-
*/
|
|
515
|
-
guards?: Type<CanActivate>[];
|
|
516
|
-
/**
|
|
517
|
-
* Extra `imports` merged into the dashboard's dynamic module — the DI resolution path for a class
|
|
518
|
-
* passed to {@link guards} (or any other provider the controllers need reachable). Typically the
|
|
519
|
-
* host's own auth module, e.g. `imports: [AuthModule]` alongside `guards: [JwtAuthGuard]`.
|
|
360
|
+
* Extra `imports` merged into the dashboard's dynamic module: the DI resolution path for a guard
|
|
361
|
+
* passed through {@link decorators} (`UseGuards(...)`), whose dependencies resolve from the module
|
|
362
|
+
* that hosts the controller. Typically the host's own auth module, unless it is global.
|
|
520
363
|
*/
|
|
521
364
|
imports?: DynamicModule['imports'];
|
|
522
365
|
/**
|
|
523
|
-
*
|
|
524
|
-
*
|
|
366
|
+
* Class decorators applied to BOTH controllers this module mounts (the SPA and its JSON API), the
|
|
367
|
+
* way `@nestjs/mcp`'s own `decorators` option works. Use it to hand the console to the official NestJS tooling, e.g.
|
|
368
|
+
* `[UseGuards(AuthenticationGuard), Can(ConsolePolicy, 'view')]` with `@nestjs/authentication`
|
|
369
|
+
* and `@nestjs/authorization`.
|
|
525
370
|
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
* its cookie from that. No credential this library understands ever exists; you keep your own
|
|
530
|
-
* identity provider as the source of truth. A page-level request with no valid session (and only
|
|
531
|
-
* Mode A configured) gets a small server-rendered instruction page telling the visitor to sign in
|
|
532
|
-
* through your host app, since there is no login page to redirect to.
|
|
533
|
-
* - **Mode B (`login`, standalone fallback)**: no host frontend/IdP to lean on — the durable
|
|
534
|
-
* dashboard serves its own small, dependency-free, server-rendered login page (`GET
|
|
535
|
-
* <basePath>/login`, handled by `DurableAuthController`) and your `login` hook validates
|
|
536
|
-
* submitted username/password. A missing/invalid/expired session redirects a page-level request
|
|
537
|
-
* to that login page with `?returnTo=<original url>`.
|
|
371
|
+
* Each registration gets fresh subclasses of the controllers, so decorators never leak into
|
|
372
|
+
* another registration or onto the exported classes. A guard named in `UseGuards(...)` resolves
|
|
373
|
+
* its dependencies from {@link imports} (or a global module).
|
|
538
374
|
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
* session, regardless of mode — the caller reads the status code, not HTML.
|
|
375
|
+
* A non-empty `decorators` is how a mounted console states its protection. With
|
|
376
|
+
* `NODE_ENV=production`, a mounted console with no (or an empty) `decorators` fails the boot; see
|
|
377
|
+
* {@link DurableDashboardModule}. The module cannot tell a `Can(...)` from a decorator that
|
|
378
|
+
* protects nothing, so passing one is your statement that the console is protected.
|
|
544
379
|
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
* operator loses access instead of riding a self-renewing cookie indefinitely. It only runs on
|
|
549
|
-
* that renewal path, not on every request, so revocation has **latency, not immediacy**: an
|
|
550
|
-
* operator revoked right after a renewal keeps their existing cookie — and therefore console
|
|
551
|
-
* access — for up to `ttl/2` (4 hours at the default 8h TTL) before the next renewal check catches
|
|
552
|
-
* it. Do not rely on `revalidate` for a same-second cutoff; front the mount with your own guard
|
|
553
|
-
* (see {@link guards}) if you need that.
|
|
554
|
-
*
|
|
555
|
-
* Auth here is mount-level and role-agnostic: this option (and the guards/controller it wires up)
|
|
556
|
-
* has no notion of control-plane vs tenant role (see the durable dashboard's topology note in
|
|
557
|
-
* `dashboard.service.ts`) — nothing role-specific changes based on who logs in.
|
|
558
|
-
*
|
|
559
|
-
* Composes with {@link guards}: when both are set, a request must pass the built-in session check
|
|
560
|
-
* AND every guard in `guards` — the SAME logical-AND semantics `@UseGuards` already gives multiple
|
|
561
|
-
* guards, since the built-in guard is simply prepended to whatever `guards` you pass. Setting it
|
|
562
|
-
* counts as the console's authentication (the fail-closed default gate steps aside). Omit it and
|
|
563
|
-
* configure `guards`, a {@link token}, or {@link allowUnauthenticated} instead.
|
|
564
|
-
*
|
|
565
|
-
* See {@link DashboardAuthOptions} for the `secret`/`ttl`/`session`/`login`/`revalidate` shape,
|
|
566
|
-
* and `forRootAsync` / {@link DurableDashboardAsyncOptions.useDashboardAuth} when a hook needs DI
|
|
567
|
-
* (e.g. an `EntityManager` to look up an admin user).
|
|
380
|
+
* Default: none. Outside production the console is then served open, and the controllers are
|
|
381
|
+
* marked `Can.Anyone()` for `@nestjs/authorization`, whose global guard otherwise refuses every
|
|
382
|
+
* route that declares no `@Can()`. A `@Can()` passed here is still enforced.
|
|
568
383
|
*/
|
|
569
|
-
|
|
384
|
+
decorators?: ClassDecorator[];
|
|
570
385
|
/**
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
386
|
+
* `false` mounts NO controllers: the SPA and its JSON API are not registered,
|
|
387
|
+
* while every provider still is (the run read/action service, the run filter, the SPA's base
|
|
388
|
+
* paths). Serve the console from controllers of your own instead, protected with ordinary Nest
|
|
389
|
+
* decorators, by extending {@link DurableUiControllerBase} and {@link DurableApiControllerBase}:
|
|
574
390
|
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
391
|
+
* ```ts
|
|
392
|
+
* @Controller('ops/durable') @UseGuards(AuthenticationGuard) @Can(ConsolePolicy, 'view')
|
|
393
|
+
* class ConsoleUi extends DurableUiControllerBase {}
|
|
394
|
+
* @Controller('ops/durable/api') @UseGuards(AuthenticationGuard) @Can(ConsolePolicy, 'view')
|
|
395
|
+
* class ConsoleApi extends DurableApiControllerBase {}
|
|
396
|
+
* // in the module that declares them:
|
|
397
|
+
* imports: [DurableDashboardModule.forRoot({ routes: false, basePath: '/ops/durable', apiBasePath: '/ops/durable/api' })]
|
|
398
|
+
* ```
|
|
399
|
+
*
|
|
400
|
+
* `basePath`/`apiBasePath` still matter here: they are where you mounted the two controllers, and
|
|
401
|
+
* the SPA is told to load its assets from `basePath` and fetch from `apiBasePath`.
|
|
586
402
|
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
403
|
+
* The production rule does not apply: this module mounts nothing, and the routes are yours,
|
|
404
|
+
* protected by what you put on them like any other route you write. The `*Base` classes carry no
|
|
405
|
+
* guards and no `Can.Anyone()` mark, so under `@nestjs/authorization`'s global guard a subclass
|
|
406
|
+
* without a `@Can()` is denied. `decorators` throws when combined with `routes: false` rather than
|
|
407
|
+
* being silently ignored.
|
|
408
|
+
*
|
|
409
|
+
* Default `true`. Named `routes` rather than `path: false` because `basePath`/`apiBasePath` are
|
|
410
|
+
* strings that keep their meaning (where the console lives) whether or not this module mounts it.
|
|
589
411
|
*/
|
|
590
|
-
|
|
412
|
+
routes?: boolean;
|
|
591
413
|
}
|
|
414
|
+
/** DI token of the boot-time check that refuses an unprotected console in production. */
|
|
415
|
+
declare const DASHBOARD_PROTECTION_CHECK: unique symbol;
|
|
416
|
+
/** The boot error for a mounted console with no `decorators` under `NODE_ENV=production`. */
|
|
417
|
+
declare const UNPROTECTED_CONSOLE_IN_PRODUCTION: string;
|
|
592
418
|
/**
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
* can reach your DB/services — e.g. Mode A's `session` hook calling out to the same auth service
|
|
597
|
-
* your host app already uses to validate the raw request. Returning `undefined` from
|
|
598
|
-
* `useDashboardAuth` is exactly like omitting `dashboardAuth` from `forRoot`: the console then
|
|
599
|
-
* falls back to `guards` / the token / `allowUnauthenticated`, and is DENIED in production when
|
|
600
|
-
* none of those is configured.
|
|
601
|
-
*/
|
|
602
|
-
interface DurableDashboardAsyncOptions {
|
|
603
|
-
basePath?: string;
|
|
604
|
-
apiBasePath?: string;
|
|
605
|
-
guards?: Type<CanActivate>[];
|
|
606
|
-
imports?: DynamicModule['imports'];
|
|
607
|
-
/** Providers injected into `useDashboardAuth`, in order. Shared with a `guards` class's own deps. */
|
|
608
|
-
inject?: Array<InjectionToken | OptionalFactoryDependency>;
|
|
609
|
-
/** Build the `dashboardAuth` config from injected deps (or `undefined` for no session auth). */
|
|
610
|
-
useDashboardAuth: (...deps: any[]) => DashboardAuthOptions | undefined | Promise<DashboardAuthOptions | undefined>;
|
|
611
|
-
/** See {@link DurableDashboardOptions.allowUnauthenticated}. */
|
|
612
|
-
allowUnauthenticated?: boolean;
|
|
613
|
-
/** See {@link DurableDashboardOptions.token}. */
|
|
614
|
-
token?: string;
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Holds the JSON API controller + its read service, mounted on its own path by `forRoot`. Dynamic:
|
|
618
|
-
* guards are DI-instantiated by the CONTROLLER's host module, so this module — not the outer wrapper
|
|
619
|
-
* — must carry the guard classes as providers plus the host's `imports` that resolve their
|
|
620
|
-
* dependencies. A static module here made `guards: [SomeGuardWithDeps]` fail at boot with "Nest can't
|
|
621
|
-
* resolve dependencies ... in the DurableApiModule context" even when the host passed the right
|
|
622
|
-
* `imports` to `forRoot` (mirrors `@dudousxd/nestjs-agent-dashboard`'s `AgentApiModule`).
|
|
419
|
+
* Holds the JSON API controller + its read service, mounted on its own path by `forRoot`. Its own
|
|
420
|
+
* dynamic module because enhancers (a guard from `decorators`) DI-instantiate from their
|
|
421
|
+
* controller's host module, so this module, not the outer wrapper, must carry the host's `imports`.
|
|
623
422
|
*/
|
|
624
423
|
declare class DurableApiModule {
|
|
625
424
|
static register(options: {
|
|
626
425
|
imports?: DynamicModule['imports'];
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
* (true whenever `dashboardAuth` was set, or unconditionally for `forRootAsync`, where it's
|
|
632
|
-
* resolved at runtime and is a no-op if it ends up unconfigured). */
|
|
633
|
-
authMayBeConfigured: boolean;
|
|
634
|
-
/** What the fail-closed gate needs; resolved into `DASHBOARD_GATE` at boot (logged once). */
|
|
635
|
-
gate: DashboardGateOptions;
|
|
636
|
-
/** Whether `DurableDashboardGateGuard` is stamped (false when guards/dashboardAuth are static). */
|
|
637
|
-
stampGate: boolean;
|
|
426
|
+
/** `false`: register the providers only, no controller (see `routes`). */
|
|
427
|
+
routes?: boolean;
|
|
428
|
+
/** See {@link DurableDashboardOptions.decorators}. */
|
|
429
|
+
decorators?: ClassDecorator[];
|
|
638
430
|
}): DynamicModule;
|
|
639
431
|
}
|
|
640
432
|
/**
|
|
@@ -644,66 +436,28 @@ declare class DurableApiModule {
|
|
|
644
436
|
* so it resolves the engine and store. Front the routes with the first-class `guards` option
|
|
645
437
|
* (plus `imports` for the guards' own dependencies) — see {@link DurableDashboardOptions.guards} —
|
|
646
438
|
* or with the built-in `dashboardAuth` cookie login, or both.
|
|
647
|
-
* With none of those (and no `token` / `allowUnauthenticated`), the console fails
|
|
648
|
-
* `NODE_ENV=production` — see {@link DurableDashboardOptions.allowUnauthenticated}.
|
|
439
|
+
* With none of those (and no `decorators` / `token` / `allowUnauthenticated`), the console fails
|
|
440
|
+
* closed when `NODE_ENV=production` — see {@link DurableDashboardOptions.allowUnauthenticated}.
|
|
441
|
+
* `routes: false` mounts nothing and leaves serving the console to the host's own controllers — see
|
|
442
|
+
* {@link DurableDashboardOptions.routes}.
|
|
649
443
|
*/
|
|
650
|
-
declare class DurableDashboardModule {
|
|
651
|
-
static forRoot(options?: DurableDashboardOptions): DynamicModule;
|
|
652
|
-
static forRootAsync(options: DurableDashboardAsyncOptions): DynamicModule;
|
|
653
|
-
/** Shared wiring: static routing + the API module, with `dashboardAuth` supplied by `authProvider`. */
|
|
654
|
-
private static build;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
444
|
/**
|
|
658
|
-
*
|
|
659
|
-
* `
|
|
660
|
-
*
|
|
661
|
-
* when Mode B (`login`) is configured, gets a `302` to the built-in login page carrying
|
|
662
|
-
* `?returnTo=<original url>`, via `DashboardLoginRedirectException` (see that file for why a guard
|
|
663
|
-
* can't just call `response.redirect()` and return `false`). When only Mode A (`session`) is
|
|
664
|
-
* configured there is no login page to redirect to — the host mints the session itself — so it
|
|
665
|
-
* instead throws `DashboardSessionRequiredException`, rendering a small instruction page.
|
|
445
|
+
* Mounts the control plane: the bundled React SPA at `basePath` and its JSON API at `apiBasePath`
|
|
446
|
+
* (default `<basePath>/api`). Import via `DurableDashboardModule.forRoot(...)` alongside
|
|
447
|
+
* `DurableModule` (global), so it resolves the engine and store.
|
|
666
448
|
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
* "is there a valid dashboard session", nothing role-specific changes here.
|
|
670
|
-
*/
|
|
671
|
-
declare class DurableUiSessionGuard implements CanActivate {
|
|
672
|
-
private readonly auth;
|
|
673
|
-
private readonly basePath;
|
|
674
|
-
constructor(auth: ResolvedDashboardAuth | null, basePath: string);
|
|
675
|
-
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
676
|
-
/**
|
|
677
|
-
* A revoked session (the host's `revalidate` hook says no) is denied exactly like an absent
|
|
678
|
-
* one — by design, there is nothing left to distinguish "never had a session" from "had one,
|
|
679
|
-
* then lost it" once the cookie is cleared, so both get the same Mode-aware treatment.
|
|
680
|
-
*
|
|
681
|
-
* Takes `auth` explicitly rather than reading `this.auth`: `canActivate`'s `!this.auth` early
|
|
682
|
-
* return narrows the field within that method only — TS doesn't carry it across a method call
|
|
683
|
-
* — so callers pass the already-narrowed value instead of this method re-deriving (or
|
|
684
|
-
* asserting away) the nullability.
|
|
685
|
-
*/
|
|
686
|
-
private denyUnauthenticated;
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Gates `DurableApiController` (the JSON API the SPA fetches) on a valid `dashboardAuth` session
|
|
690
|
-
* cookie. A no-op (always `true`) when `dashboardAuth` was not configured. Missing/invalid/expired
|
|
691
|
-
* session => a plain `401` (the API is called via `fetch`, never a browser navigation, so a
|
|
692
|
-
* redirect would just fail the request anyway — the caller reads the status code, not HTML).
|
|
449
|
+
* Protect the console with the first-party NestJS tools (`@nestjs/authentication`,
|
|
450
|
+
* `@nestjs/authorization`), one of two ways:
|
|
693
451
|
*
|
|
694
|
-
*
|
|
452
|
+
* 1. `decorators` on the mounted controllers (see {@link DurableDashboardOptions.decorators});
|
|
453
|
+
* 2. `routes: false`, and mount it yourself by extending `DurableUiControllerBase` /
|
|
454
|
+
* `DurableApiControllerBase` (see {@link DurableDashboardOptions.routes}).
|
|
455
|
+
*
|
|
456
|
+
* With `NODE_ENV=production`, a mounted console with no `decorators` fails the boot with
|
|
457
|
+
* {@link UNPROTECTED_CONSOLE_IN_PRODUCTION}. Outside production it is served open, with a warning.
|
|
695
458
|
*/
|
|
696
|
-
declare class
|
|
697
|
-
|
|
698
|
-
constructor(auth: ResolvedDashboardAuth | null);
|
|
699
|
-
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
700
|
-
/**
|
|
701
|
-
* A bare 401 body carrying `{ auth: { modes } }` — mirrors `@dudousxd/nestjs-telescope`'s
|
|
702
|
-
* dashboardAuth 401. The API is fetched (never navigated), so this is the ONLY way the console
|
|
703
|
-
* SPA (`durable-client.ts`) learns which auth surface to send the operator to on a mid-session
|
|
704
|
-
* 401; `DurableUiSessionGuard`'s redirect/session-required exceptions above don't reach it.
|
|
705
|
-
*/
|
|
706
|
-
private unauthorized;
|
|
459
|
+
declare class DurableDashboardModule {
|
|
460
|
+
static forRoot(options?: DurableDashboardOptions): DynamicModule;
|
|
707
461
|
}
|
|
708
462
|
|
|
709
463
|
/** DI token carrying the UI mount base (e.g. `/durable`). */
|
|
@@ -712,18 +466,16 @@ declare const DASHBOARD_BASE_PATH: unique symbol;
|
|
|
712
466
|
declare const DASHBOARD_API_PATH: unique symbol;
|
|
713
467
|
/**
|
|
714
468
|
* Serves the bundled control-plane SPA at the configured base (+ hashed assets at `<base>/assets`).
|
|
715
|
-
* The
|
|
716
|
-
*
|
|
469
|
+
* The controller routes are relative: the mounted {@link DurableUiController} gets its path from
|
|
470
|
+
* `RouterModule` (set by `DurableDashboardModule.forRoot({ basePath })`).
|
|
717
471
|
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
* based on which mode is configured (Mode B => redirect to the login page; Mode A only => render
|
|
724
|
-
* the session-required instruction page in place, since there is no login page to redirect to).
|
|
472
|
+
* This base is what a host EXTENDS to serve the console from a controller of its own (with
|
|
473
|
+
* `forRoot({ routes: false, basePath })`): `@Controller('<basePath>') class MyConsole extends
|
|
474
|
+
* DurableUiControllerBase {}`, protected with the host's own decorators. It carries no guards and
|
|
475
|
+
* no `@nestjs/authorization` mark, so a subclass is protected only by what the host puts on it (and,
|
|
476
|
+
* under `AuthorizationModule`'s global guard, is denied until it declares a `@Can()`).
|
|
725
477
|
*/
|
|
726
|
-
declare class
|
|
478
|
+
declare class DurableUiControllerBase {
|
|
727
479
|
private readonly basePath;
|
|
728
480
|
private readonly apiBasePath;
|
|
729
481
|
private readonly dir;
|
|
@@ -731,5 +483,13 @@ declare class DurableUiController {
|
|
|
731
483
|
index(): string;
|
|
732
484
|
asset(file: string): StreamableFile;
|
|
733
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* The SPA controller `DurableDashboardModule.forRoot(...)` mounts at `basePath`. The module puts
|
|
488
|
+
* the `@nestjs/authorization` open mark on THIS class (and `decorators` on a per-registration
|
|
489
|
+
* subclass of it), never on {@link DurableUiControllerBase}, so a host's own subclass of the base
|
|
490
|
+
* inherits none of them.
|
|
491
|
+
*/
|
|
492
|
+
declare class DurableUiController extends DurableUiControllerBase {
|
|
493
|
+
}
|
|
734
494
|
|
|
735
|
-
export { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH,
|
|
495
|
+
export { DASHBOARD_API_PATH, DASHBOARD_BASE_PATH, DASHBOARD_PROTECTION_CHECK, DashboardService, DurableApiController, DurableApiControllerBase, DurableApiModule, DurableDashboardModule, type DurableDashboardOptions, DurableUiController, DurableUiControllerBase, UNPROTECTED_CONSOLE_IN_PRODUCTION, type WorkflowLifecyclePage };
|