@dudousxd/nestjs-durable-dashboard 0.56.0 → 0.58.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/server/index.cjs +1203 -98
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +229 -9
- package/dist/server/index.d.ts +229 -9
- package/dist/server/index.js +1193 -103
- package/dist/server/index.js.map +1 -1
- package/dist/spa/assets/{bench-BXhQP2W7.js → bench--sTow8cG.js} +1 -1
- package/dist/spa/assets/index-BA5RJf7A.css +1 -0
- package/dist/spa/assets/{index-C6Ih-K3x.js → index-DG9crD2T.js} +1 -1
- package/dist/spa/assets/index-L85j6H4X.js +66 -0
- package/dist/spa/assets/{preview-ekPMzj7t.js → preview-b6LbKDyY.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 +2 -2
- package/dist/spa/assets/index-D_rIGnea.css +0 -1
- package/dist/spa/assets/index-DwGUovEa.js +0 -66
package/dist/server/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
7
7
|
import { Catch, HttpException, Inject, Injectable, Logger, UseFilters, UseGuards, applyDecorators } from "@nestjs/common";
|
|
8
|
-
import { HttpAdapterHost } from "@nestjs/core";
|
|
8
|
+
import { HttpAdapterHost, ModuleRef } from "@nestjs/core";
|
|
9
9
|
function _ts_decorate(decorators, target, key, desc) {
|
|
10
10
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
11
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -36,9 +36,12 @@ var CONSOLE_GATE = Symbol.for("@dudousxd/aviary:console-gate");
|
|
|
36
36
|
var PACKAGE = "@dudousxd/nestjs-durable-dashboard";
|
|
37
37
|
var MODULE = "DurableDashboardModule";
|
|
38
38
|
var CONSOLE_AUTHORIZE_MISSING_WARNING = `[${PACKAGE}] console has no \`authorize\` configured: it is open outside production and denies every request in production. Set \`authorize\` in ${MODULE}.forRoot().`;
|
|
39
|
-
var allow = /* @__PURE__ */ __name(() =>
|
|
39
|
+
var allow = /* @__PURE__ */ __name((caller) => caller !== void 0 && caller !== "" ? {
|
|
40
|
+
allowed: true,
|
|
41
|
+
caller
|
|
42
|
+
} : {
|
|
40
43
|
allowed: true
|
|
41
|
-
}
|
|
44
|
+
}, "allow");
|
|
42
45
|
var forbidden = /* @__PURE__ */ __name(() => ({
|
|
43
46
|
allowed: false,
|
|
44
47
|
reason: "forbidden"
|
|
@@ -78,7 +81,9 @@ function normalizeConsoleResult(result) {
|
|
|
78
81
|
redirectTo: shape.redirectTo
|
|
79
82
|
};
|
|
80
83
|
}
|
|
81
|
-
if (shape.allowed === true)
|
|
84
|
+
if (shape.allowed === true) {
|
|
85
|
+
return allow(typeof shape.caller === "string" ? shape.caller : void 0);
|
|
86
|
+
}
|
|
82
87
|
return shape.reason === "unauthenticated" ? unauthenticated() : forbidden();
|
|
83
88
|
}
|
|
84
89
|
__name(normalizeConsoleResult, "normalizeConsoleResult");
|
|
@@ -161,11 +166,11 @@ function classDecider(moduleRef) {
|
|
|
161
166
|
}
|
|
162
167
|
__name(classDecider, "classDecider");
|
|
163
168
|
async function resolveConsoleAuthorize(authorize, moduleRef, options = {}) {
|
|
164
|
-
const
|
|
169
|
+
const logger3 = options.logger ?? new Logger(MODULE);
|
|
165
170
|
if (authorize === void 0) {
|
|
166
|
-
if (options.warnIfMissing !== false)
|
|
171
|
+
if (options.warnIfMissing !== false) logger3.warn(CONSOLE_AUTHORIZE_MISSING_WARNING);
|
|
167
172
|
const production = isProduction();
|
|
168
|
-
return async () => production ? forbidden() : allow();
|
|
173
|
+
return async () => production ? forbidden() : allow("dev-open");
|
|
169
174
|
}
|
|
170
175
|
let decide;
|
|
171
176
|
if (typeof authorize === "string") {
|
|
@@ -192,7 +197,7 @@ async function resolveConsoleAuthorize(authorize, moduleRef, options = {}) {
|
|
|
192
197
|
try {
|
|
193
198
|
return await decide(context);
|
|
194
199
|
} catch (error) {
|
|
195
|
-
|
|
200
|
+
logger3.warn(`console \`authorize\` threw, denying the request: ${error instanceof Error ? error.message : String(error)}`);
|
|
196
201
|
return forbidden();
|
|
197
202
|
}
|
|
198
203
|
};
|
|
@@ -205,10 +210,16 @@ function authorizeByToken(options) {
|
|
|
205
210
|
throw new Error("authorizeByToken: `token` is empty; set it (e.g. from an env var).");
|
|
206
211
|
}
|
|
207
212
|
const expected = sha256(token);
|
|
213
|
+
const caller = `token:${expected.toString("hex").slice(0, 12)}`;
|
|
208
214
|
return (context) => {
|
|
209
215
|
const header = context.switchToHttp().getRequest()?.headers?.authorization;
|
|
210
216
|
const match = typeof header === "string" ? /^Bearer\s+(.+)$/i.exec(header.trim()) : null;
|
|
211
|
-
if (match?.[1] && timingSafeEqual(sha256(match[1]), expected))
|
|
217
|
+
if (match?.[1] && timingSafeEqual(sha256(match[1]), expected)) {
|
|
218
|
+
return {
|
|
219
|
+
allowed: true,
|
|
220
|
+
caller
|
|
221
|
+
};
|
|
222
|
+
}
|
|
212
223
|
return {
|
|
213
224
|
allowed: false,
|
|
214
225
|
reason: "unauthenticated"
|
|
@@ -216,6 +227,48 @@ function authorizeByToken(options) {
|
|
|
216
227
|
};
|
|
217
228
|
}
|
|
218
229
|
__name(authorizeByToken, "authorizeByToken");
|
|
230
|
+
function anyAuthorize(...forms) {
|
|
231
|
+
if (forms.length === 0) throw new Error("anyAuthorize: pass at least one authorize form.");
|
|
232
|
+
let AnyConsoleAuthorizer = class AnyConsoleAuthorizer {
|
|
233
|
+
static {
|
|
234
|
+
__name(this, "AnyConsoleAuthorizer");
|
|
235
|
+
}
|
|
236
|
+
moduleRef;
|
|
237
|
+
#decides;
|
|
238
|
+
constructor(moduleRef) {
|
|
239
|
+
this.moduleRef = moduleRef;
|
|
240
|
+
}
|
|
241
|
+
async authorize(context) {
|
|
242
|
+
this.#decides ??= Promise.all(forms.map((form) => resolveConsoleAuthorize(form, this.moduleRef, {
|
|
243
|
+
warnIfMissing: false
|
|
244
|
+
})));
|
|
245
|
+
this.#decides.catch(() => {
|
|
246
|
+
this.#decides = void 0;
|
|
247
|
+
});
|
|
248
|
+
let unauthenticated2;
|
|
249
|
+
for (const decide of await this.#decides) {
|
|
250
|
+
const decision = await decide(context);
|
|
251
|
+
if (decision.allowed) return decision;
|
|
252
|
+
if (decision.reason === "unauthenticated") unauthenticated2 ??= decision;
|
|
253
|
+
}
|
|
254
|
+
if (unauthenticated2 === void 0) return {
|
|
255
|
+
allowed: false,
|
|
256
|
+
reason: "forbidden"
|
|
257
|
+
};
|
|
258
|
+
return "redirectTo" in unauthenticated2 && unauthenticated2.redirectTo !== void 0 ? {
|
|
259
|
+
redirectTo: unauthenticated2.redirectTo
|
|
260
|
+
} : {
|
|
261
|
+
allowed: false,
|
|
262
|
+
reason: "unauthenticated"
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
Reflect.defineMetadata("design:paramtypes", [
|
|
267
|
+
ModuleRef
|
|
268
|
+
], AnyConsoleAuthorizer);
|
|
269
|
+
return AnyConsoleAuthorizer;
|
|
270
|
+
}
|
|
271
|
+
__name(anyAuthorize, "anyAuthorize");
|
|
219
272
|
var CONSOLE_AUTHORIZE_DECIDE = Symbol(`${PACKAGE}:console-authorize`);
|
|
220
273
|
var CONSOLE_PAGE_METADATA = `${PACKAGE}:console-page`;
|
|
221
274
|
var ConsolePage = /* @__PURE__ */ __name(() => (target) => {
|
|
@@ -227,7 +280,7 @@ var ConsoleAccessDenied = class extends HttpException {
|
|
|
227
280
|
}
|
|
228
281
|
decision;
|
|
229
282
|
page;
|
|
230
|
-
constructor(decision,
|
|
283
|
+
constructor(decision, page2) {
|
|
231
284
|
const unauthenticated2 = decision.reason === "unauthenticated";
|
|
232
285
|
super(unauthenticated2 ? {
|
|
233
286
|
error: "unauthenticated",
|
|
@@ -236,9 +289,13 @@ var ConsoleAccessDenied = class extends HttpException {
|
|
|
236
289
|
} : {}
|
|
237
290
|
} : {
|
|
238
291
|
error: "forbidden"
|
|
239
|
-
}, unauthenticated2 ? 401 : 403), this.decision = decision, this.page =
|
|
292
|
+
}, unauthenticated2 ? 401 : 403), this.decision = decision, this.page = page2;
|
|
240
293
|
}
|
|
241
294
|
};
|
|
295
|
+
var CONSOLE_PUBLIC_METADATA = `${PACKAGE}:console-public`;
|
|
296
|
+
var ConsolePublic = /* @__PURE__ */ __name(() => (_target, _key, descriptor) => {
|
|
297
|
+
Reflect.defineMetadata(CONSOLE_PUBLIC_METADATA, true, descriptor.value);
|
|
298
|
+
}, "ConsolePublic");
|
|
242
299
|
var ConsoleAuthorizeGuard = class {
|
|
243
300
|
static {
|
|
244
301
|
__name(this, "ConsoleAuthorizeGuard");
|
|
@@ -248,6 +305,7 @@ var ConsoleAuthorizeGuard = class {
|
|
|
248
305
|
this.decide = decide;
|
|
249
306
|
}
|
|
250
307
|
async canActivate(context) {
|
|
308
|
+
if (Reflect.getMetadata(CONSOLE_PUBLIC_METADATA, context.getHandler()) === true) return true;
|
|
251
309
|
const decision = await this.decide(context);
|
|
252
310
|
if (decision.allowed) return true;
|
|
253
311
|
throw new ConsoleAccessDenied(decision, isPageNavigation(context));
|
|
@@ -283,12 +341,12 @@ var ConsoleAuthorizeFilter = class {
|
|
|
283
341
|
catch(exception, host) {
|
|
284
342
|
const adapter = this.adapterHost.httpAdapter;
|
|
285
343
|
const response = host.switchToHttp().getResponse();
|
|
286
|
-
const { decision, page } = exception;
|
|
287
|
-
if (
|
|
344
|
+
const { decision, page: page2 } = exception;
|
|
345
|
+
if (page2 && decision.redirectTo) {
|
|
288
346
|
adapter.redirect(response, 302, decision.redirectTo);
|
|
289
347
|
return;
|
|
290
348
|
}
|
|
291
|
-
if (
|
|
349
|
+
if (page2) {
|
|
292
350
|
const forbiddenPage = decision.reason === "forbidden";
|
|
293
351
|
adapter.setHeader(response, "Content-Type", "text/html; charset=utf-8");
|
|
294
352
|
adapter.reply(response, forbiddenPage ? DENIED_PAGE : SIGN_IN_PAGE, forbiddenPage ? 403 : 401);
|
|
@@ -308,7 +366,7 @@ var UseConsoleAuthorize = /* @__PURE__ */ __name(() => applyDecorators(UseGuards
|
|
|
308
366
|
|
|
309
367
|
// src/server/dashboard.service.ts
|
|
310
368
|
import { RunGateway, STATE_STORE_CANONICAL, TERMINAL_RUN_STATUSES, WorkflowEngine, collectMetrics, parseWebhookToken } from "@dudousxd/nestjs-durable-core";
|
|
311
|
-
import { Inject as Inject2, Injectable as Injectable2, Optional } from "@nestjs/common";
|
|
369
|
+
import { Inject as Inject2, Injectable as Injectable2, NotImplementedException, Optional } from "@nestjs/common";
|
|
312
370
|
import { Observable } from "rxjs";
|
|
313
371
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
314
372
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -360,7 +418,7 @@ var DashboardService = class {
|
|
|
360
418
|
*/
|
|
361
419
|
controlPlane() {
|
|
362
420
|
if (!this.store || !this.engine) {
|
|
363
|
-
throw new
|
|
421
|
+
throw new NotImplementedException("This durable dashboard operation requires the control plane (not available on a tenant deployment).");
|
|
364
422
|
}
|
|
365
423
|
return {
|
|
366
424
|
store: this.store,
|
|
@@ -460,31 +518,31 @@ var DashboardService = class {
|
|
|
460
518
|
async workerHealth() {
|
|
461
519
|
return this.gateway.workerHealth();
|
|
462
520
|
}
|
|
463
|
-
getRunDetail(
|
|
464
|
-
return this.gateway.getRunDetail(
|
|
521
|
+
getRunDetail(runId2, options) {
|
|
522
|
+
return this.gateway.getRunDetail(runId2, options);
|
|
465
523
|
}
|
|
466
524
|
/** A page of one fan's members, or null when the run is unknown or the gateway can't page fans. */
|
|
467
|
-
async getFanMembers(
|
|
468
|
-
return await this.gateway.getFanMembers?.(
|
|
525
|
+
async getFanMembers(runId2, group, query) {
|
|
526
|
+
return await this.gateway.getFanMembers?.(runId2, group, query) ?? null;
|
|
469
527
|
}
|
|
470
528
|
/** Fix-and-replay a dead/failed run with a corrected input — a fresh linked run. Returns its id. */
|
|
471
|
-
retryWithInput(
|
|
472
|
-
return this.gateway.retryWithInput(
|
|
529
|
+
retryWithInput(runId2, input) {
|
|
530
|
+
return this.gateway.retryWithInput(runId2, input);
|
|
473
531
|
}
|
|
474
532
|
/** Re-run a failed/incomplete run; completed steps replay from their checkpoints. */
|
|
475
|
-
retry(
|
|
476
|
-
return this.gateway.retry(
|
|
533
|
+
retry(runId2) {
|
|
534
|
+
return this.gateway.retry(runId2);
|
|
477
535
|
}
|
|
478
|
-
cancel(
|
|
479
|
-
return this.gateway.cancel(
|
|
536
|
+
cancel(runId2, opts) {
|
|
537
|
+
return this.gateway.cancel(runId2, opts);
|
|
480
538
|
}
|
|
481
539
|
/**
|
|
482
540
|
* Publish a settled run's lifecycle event again, to its subscribers that have not started (or to
|
|
483
541
|
* `subscriber` alone). Undefined when the gateway cannot republish (a tenant proxy).
|
|
484
542
|
*/
|
|
485
|
-
async republishLifecycle(
|
|
543
|
+
async republishLifecycle(runId2, subscriber) {
|
|
486
544
|
return this.gateway.republishLifecycle?.({
|
|
487
|
-
runId,
|
|
545
|
+
runId: runId2,
|
|
488
546
|
...subscriber !== void 0 ? {
|
|
489
547
|
subscriber
|
|
490
548
|
} : {}
|
|
@@ -552,12 +610,12 @@ var DashboardService = class {
|
|
|
552
610
|
};
|
|
553
611
|
}
|
|
554
612
|
/** Resume a run paused at a `ctx.breakpoint` (the "continue" button). */
|
|
555
|
-
continue(
|
|
556
|
-
return this.gateway.continue(
|
|
613
|
+
continue(runId2) {
|
|
614
|
+
return this.gateway.continue(runId2);
|
|
557
615
|
}
|
|
558
616
|
/** Re-dispatch a run's stuck `pending` remote steps — recovery for a lost step dispatch. */
|
|
559
|
-
redispatch(
|
|
560
|
-
return this.gateway.redispatchPending(
|
|
617
|
+
redispatch(runId2) {
|
|
618
|
+
return this.gateway.redispatchPending(runId2);
|
|
561
619
|
}
|
|
562
620
|
/**
|
|
563
621
|
* Deliver a `ctx.webhook()` callback: turn an inbound POST (token + body) into the signal the
|
|
@@ -586,13 +644,39 @@ var DashboardService = class {
|
|
|
586
644
|
status: fresh?.status ?? run.status
|
|
587
645
|
};
|
|
588
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* What this deployment can serve: `controlPlane` (signals, run events, updates, metrics) and
|
|
649
|
+
* `schedules` (persisted schedules). Both are false on a store-less tenant.
|
|
650
|
+
*/
|
|
651
|
+
capabilities() {
|
|
652
|
+
const controlPlane = this.store !== void 0 && this.engine !== void 0;
|
|
653
|
+
return {
|
|
654
|
+
controlPlane,
|
|
655
|
+
schedules: controlPlane && this.engine?.schedules?.supported === true
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
/** Whether `runId` names a run the caller may see (tenancy applies). */
|
|
659
|
+
async runExists(runId2) {
|
|
660
|
+
if (this.gateway.getRun) return await this.gateway.getRun(runId2) !== null;
|
|
661
|
+
return await this.gateway.getRunDetail(runId2, {
|
|
662
|
+
summarizeFansOver: 0
|
|
663
|
+
}) !== null;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Deliver `payload` to the run waiting on `token` (`engine.signal`). Null when no run the caller
|
|
667
|
+
* may see waits on it yet: the engine then buffers the payload for the run that waits next.
|
|
668
|
+
* Control-plane-only.
|
|
669
|
+
*/
|
|
670
|
+
signal(token, payload) {
|
|
671
|
+
return this.controlPlane().engine.signal(token, payload);
|
|
672
|
+
}
|
|
589
673
|
/** Side-effect-free read of a value a run published via `ctx.setEvent` (a live query). Control-plane-only. */
|
|
590
|
-
async getEvent(
|
|
591
|
-
return this.controlPlane().engine.getEvent(
|
|
674
|
+
async getEvent(runId2, key) {
|
|
675
|
+
return this.controlPlane().engine.getEvent(runId2, key);
|
|
592
676
|
}
|
|
593
677
|
/** Deliver a validated `ctx.onUpdate` to a run; the validator may reject it (see UpdateResult). Control-plane-only. */
|
|
594
|
-
async update(
|
|
595
|
-
return this.controlPlane().engine.update(
|
|
678
|
+
async update(runId2, name, arg) {
|
|
679
|
+
return this.controlPlane().engine.update(runId2, name, arg);
|
|
596
680
|
}
|
|
597
681
|
/**
|
|
598
682
|
* Live stream of a run's lifecycle events for SSE. Backed by `gateway.subscribe`, which — on the
|
|
@@ -600,9 +684,9 @@ var DashboardService = class {
|
|
|
600
684
|
* executing on a worker pod), and on a tenant round-trips over the transport. Either way the
|
|
601
685
|
* gateway already filters to `runId`; the dashboard just wires the events through.
|
|
602
686
|
*/
|
|
603
|
-
streamRun(
|
|
687
|
+
streamRun(runId2) {
|
|
604
688
|
return new Observable((subscriber) => {
|
|
605
|
-
const off = this.gateway.subscribe(
|
|
689
|
+
const off = this.gateway.subscribe(runId2, (event) => subscriber.next({
|
|
606
690
|
data: event
|
|
607
691
|
}));
|
|
608
692
|
return () => off();
|
|
@@ -624,7 +708,7 @@ DashboardService = _ts_decorate2([
|
|
|
624
708
|
|
|
625
709
|
// src/server/durable-api.controller.ts
|
|
626
710
|
import { ApplyFilter, ApplyFilterInterceptor, FilterRunner } from "@dudousxd/nestjs-filter";
|
|
627
|
-
import { BadRequestException as BadRequestException2, Body, Controller, Get, Header, Headers, NotFoundException, NotImplementedException, Param, Post, Query, Res, Sse, UseFilters as UseFilters2, UseInterceptors } from "@nestjs/common";
|
|
711
|
+
import { BadRequestException as BadRequestException2, Body, Controller, Get, Header, Headers, NotFoundException, NotImplementedException as NotImplementedException2, Param, Post, Query, Res, Sse, UseFilters as UseFilters2, UseInterceptors } from "@nestjs/common";
|
|
628
712
|
|
|
629
713
|
// src/server/durable-run.ts
|
|
630
714
|
var DurableRun = class {
|
|
@@ -850,7 +934,7 @@ var RunQueryDraft2 = class {
|
|
|
850
934
|
/** The predicates minus the page window and the axes a facet count reports on — what
|
|
851
935
|
* `runFacets`/`runValueFacets` are taken over. */
|
|
852
936
|
facetQuery() {
|
|
853
|
-
const { status, statuses, origin, origins, limit, offset, ...facetQuery } = this.query;
|
|
937
|
+
const { status, statuses, origin, origins, limit: limit2, offset, ...facetQuery } = this.query;
|
|
854
938
|
return facetQuery;
|
|
855
939
|
}
|
|
856
940
|
};
|
|
@@ -1055,10 +1139,10 @@ var RunQueryAdapter = class {
|
|
|
1055
1139
|
}
|
|
1056
1140
|
unsupported(clause, "equals, notEquals, gt, gte, lt, lte, in");
|
|
1057
1141
|
}
|
|
1058
|
-
applyOffsetPagination(qb,
|
|
1142
|
+
applyOffsetPagination(qb, page2, size) {
|
|
1059
1143
|
this.draft(qb).narrow({
|
|
1060
1144
|
limit: size,
|
|
1061
|
-
offset: (
|
|
1145
|
+
offset: (page2 - 1) * size
|
|
1062
1146
|
});
|
|
1063
1147
|
}
|
|
1064
1148
|
/**
|
|
@@ -1285,9 +1369,9 @@ var RunFilter = class extends BaseFilter {
|
|
|
1285
1369
|
}
|
|
1286
1370
|
}
|
|
1287
1371
|
applyLimit(value) {
|
|
1288
|
-
const
|
|
1289
|
-
if (
|
|
1290
|
-
limit
|
|
1372
|
+
const limit2 = bound(value);
|
|
1373
|
+
if (limit2 !== void 0) this.$query.narrow({
|
|
1374
|
+
limit: limit2
|
|
1291
1375
|
});
|
|
1292
1376
|
}
|
|
1293
1377
|
applyOffset(value) {
|
|
@@ -1469,7 +1553,7 @@ var DurableApiControllerBase = class {
|
|
|
1469
1553
|
* The persisted schedules (`engine.schedules`), soonest-due first, optionally narrowed by
|
|
1470
1554
|
* `namespace`/`workflow`/`tag`/`paused`. Empty on a tenant or a store without schedules.
|
|
1471
1555
|
*/
|
|
1472
|
-
schedules(namespace, workflow, tag, paused,
|
|
1556
|
+
schedules(namespace, workflow, tag, paused, limit2) {
|
|
1473
1557
|
return this.dashboard.listSchedules({
|
|
1474
1558
|
...namespace ? {
|
|
1475
1559
|
namespace
|
|
@@ -1483,7 +1567,7 @@ var DurableApiControllerBase = class {
|
|
|
1483
1567
|
...paused === "true" || paused === "false" ? {
|
|
1484
1568
|
paused: paused === "true"
|
|
1485
1569
|
} : {},
|
|
1486
|
-
limit: Math.min(Number(
|
|
1570
|
+
limit: Math.min(Number(limit2) || 200, 1e3)
|
|
1487
1571
|
});
|
|
1488
1572
|
}
|
|
1489
1573
|
pauseSchedule(id) {
|
|
@@ -1502,7 +1586,7 @@ var DurableApiControllerBase = class {
|
|
|
1502
1586
|
*/
|
|
1503
1587
|
async workflowLifecycle(name) {
|
|
1504
1588
|
const links = await this.dashboard.workflowLifecycle(name).catch(notSupportedByServer);
|
|
1505
|
-
if (!links) throw new
|
|
1589
|
+
if (!links) throw new NotImplementedException2("workflow lifecycle links need the control plane");
|
|
1506
1590
|
return links;
|
|
1507
1591
|
}
|
|
1508
1592
|
/** This deployment's durable role (control plane vs tenant) + tenant name — for the header badge. */
|
|
@@ -1533,17 +1617,17 @@ var DurableApiControllerBase = class {
|
|
|
1533
1617
|
return body;
|
|
1534
1618
|
}
|
|
1535
1619
|
/** One page of a summarized fan's members, in seq order. Versioned like {@link run}. */
|
|
1536
|
-
async fanMembers(id, group, offset,
|
|
1537
|
-
const
|
|
1620
|
+
async fanMembers(id, group, offset, limit2, failed, ifNoneMatch, response) {
|
|
1621
|
+
const page2 = await this.dashboard.getFanMembers(id, group, {
|
|
1538
1622
|
offset: offset === void 0 ? void 0 : Number(offset),
|
|
1539
|
-
limit:
|
|
1623
|
+
limit: limit2 === void 0 ? void 0 : Number(limit2),
|
|
1540
1624
|
failedOnly: failed === "true",
|
|
1541
1625
|
...ifNoneMatch && {
|
|
1542
1626
|
ifNoneMatch
|
|
1543
1627
|
}
|
|
1544
1628
|
});
|
|
1545
|
-
if (!
|
|
1546
|
-
const { etag, notModified, ...body } =
|
|
1629
|
+
if (!page2) throw new NotFoundException(`fan ${group} of run ${id} not found`);
|
|
1630
|
+
const { etag, notModified, ...body } = page2;
|
|
1547
1631
|
if (etag) {
|
|
1548
1632
|
if (notModified) throw new NotModifiedException(etag);
|
|
1549
1633
|
setEtag(response, etag);
|
|
@@ -1568,7 +1652,7 @@ var DurableApiControllerBase = class {
|
|
|
1568
1652
|
* exactly the set the operator was looking at rather than a wider one.
|
|
1569
1653
|
*/
|
|
1570
1654
|
bulk(action, draft, compensate) {
|
|
1571
|
-
const { limit, offset, ...filter } = draft.query;
|
|
1655
|
+
const { limit: limit2, offset, ...filter } = draft.query;
|
|
1572
1656
|
return this.dashboard.bulk(action === "cancel" ? "cancel" : "retry", filter, {
|
|
1573
1657
|
compensate: compensate === "true"
|
|
1574
1658
|
});
|
|
@@ -1598,7 +1682,7 @@ var DurableApiControllerBase = class {
|
|
|
1598
1682
|
return notSupportedByServer(error);
|
|
1599
1683
|
}
|
|
1600
1684
|
if (!result) {
|
|
1601
|
-
throw new
|
|
1685
|
+
throw new NotImplementedException2("republishing lifecycle events needs the control plane");
|
|
1602
1686
|
}
|
|
1603
1687
|
return result;
|
|
1604
1688
|
}
|
|
@@ -1615,9 +1699,9 @@ var DurableApiControllerBase = class {
|
|
|
1615
1699
|
}
|
|
1616
1700
|
/**
|
|
1617
1701
|
* Public callback endpoint for `ctx.webhook()`: a third party POSTs here (the url handed to it),
|
|
1618
|
-
* and the body resumes the waiting run.
|
|
1619
|
-
*
|
|
1620
|
-
* verification in your own middleware.
|
|
1702
|
+
* and the body resumes the waiting run. Not a console route: the console's `authorize` does not
|
|
1703
|
+
* apply, the token is the secret. The app's `decorators` still do. Treat the token as a secret
|
|
1704
|
+
* and/or front it with signature verification in your own middleware.
|
|
1621
1705
|
*/
|
|
1622
1706
|
async webhook(token, body) {
|
|
1623
1707
|
const result = await this.dashboard.deliverWebhook(token, body);
|
|
@@ -1855,6 +1939,7 @@ _ts_decorate6([
|
|
|
1855
1939
|
_ts_metadata5("design:returntype", Promise)
|
|
1856
1940
|
], DurableApiControllerBase.prototype, "redispatch", null);
|
|
1857
1941
|
_ts_decorate6([
|
|
1942
|
+
ConsolePublic(),
|
|
1858
1943
|
Post("webhooks/:token"),
|
|
1859
1944
|
_ts_param3(0, Param("token")),
|
|
1860
1945
|
_ts_param3(1, Body()),
|
|
@@ -1908,7 +1993,7 @@ function notFound(error) {
|
|
|
1908
1993
|
__name(notFound, "notFound");
|
|
1909
1994
|
function notSupportedByServer(error) {
|
|
1910
1995
|
if (error?.code === "unsupported-request") {
|
|
1911
|
-
throw new
|
|
1996
|
+
throw new NotImplementedException2(error instanceof Error ? error.message : String(error));
|
|
1912
1997
|
}
|
|
1913
1998
|
throw error;
|
|
1914
1999
|
}
|
|
@@ -1926,7 +2011,194 @@ DurableApiController = _ts_decorate6([
|
|
|
1926
2011
|
import "reflect-metadata";
|
|
1927
2012
|
import { ApplyFilterInterceptor as ApplyFilterInterceptor2, FilterRunner as FilterRunner2 } from "@dudousxd/nestjs-filter";
|
|
1928
2013
|
import { Module } from "@nestjs/common";
|
|
1929
|
-
import { ModuleRef, RouterModule } from "@nestjs/core";
|
|
2014
|
+
import { ModuleRef as ModuleRef2, RouterModule } from "@nestjs/core";
|
|
2015
|
+
|
|
2016
|
+
// src/server/console-switcher.ts
|
|
2017
|
+
import { Controller as Controller2, Get as Get2, Header as Header2, Inject as Inject3, Injectable as Injectable5, Logger as Logger2, createParamDecorator } from "@nestjs/common";
|
|
2018
|
+
|
|
2019
|
+
// src/server/tokens.ts
|
|
2020
|
+
import { RunGateway as RunGateway3 } from "@dudousxd/nestjs-durable-core";
|
|
2021
|
+
var DASHBOARD_DEV_TOOLS = Symbol("DASHBOARD_DEV_TOOLS");
|
|
2022
|
+
var DASHBOARD_BASE_PATH = Symbol("DASHBOARD_BASE_PATH");
|
|
2023
|
+
var DASHBOARD_API_PATH = Symbol("DASHBOARD_API_PATH");
|
|
2024
|
+
|
|
2025
|
+
// src/server/console-switcher.ts
|
|
2026
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
2027
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2028
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
2029
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
2030
|
+
} else {
|
|
2031
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
2032
|
+
if (d = decorators[i]) {
|
|
2033
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2038
|
+
}
|
|
2039
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
2040
|
+
function _ts_metadata6(metadataKey, metadataValue) {
|
|
2041
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
2042
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
2046
|
+
function _ts_param4(paramIndex, decorator) {
|
|
2047
|
+
return function(target, key) {
|
|
2048
|
+
decorator(target, key, paramIndex);
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
__name(_ts_param4, "_ts_param");
|
|
2052
|
+
var AVIARY_CONSOLES_SLOT = Symbol.for("@dudousxd/aviary:consoles");
|
|
2053
|
+
var ID = /^[a-z][a-z0-9-]*$/;
|
|
2054
|
+
var ICONS = /* @__PURE__ */ new Set([
|
|
2055
|
+
"workflow",
|
|
2056
|
+
"telescope",
|
|
2057
|
+
"media",
|
|
2058
|
+
"payments",
|
|
2059
|
+
"agent",
|
|
2060
|
+
"identity",
|
|
2061
|
+
"generic"
|
|
2062
|
+
]);
|
|
2063
|
+
var CONSOLE_PROBE_TIMEOUT_MS = 300;
|
|
2064
|
+
function isSameOriginPath(path) {
|
|
2065
|
+
return typeof path === "string" && path.startsWith("/") && !path.startsWith("//");
|
|
2066
|
+
}
|
|
2067
|
+
__name(isSameOriginPath, "isSameOriginPath");
|
|
2068
|
+
function readAviaryConsoles() {
|
|
2069
|
+
const value = globalThis[AVIARY_CONSOLES_SLOT];
|
|
2070
|
+
if (value?.version !== 1 || !Array.isArray(value.entries)) return void 0;
|
|
2071
|
+
return value;
|
|
2072
|
+
}
|
|
2073
|
+
__name(readAviaryConsoles, "readAviaryConsoles");
|
|
2074
|
+
function registerAviaryConsole(entry, logger3) {
|
|
2075
|
+
if (!ID.test(entry.id)) throw new Error(`console id ${JSON.stringify(entry.id)} is invalid`);
|
|
2076
|
+
if (!isSameOriginPath(entry.path)) {
|
|
2077
|
+
throw new Error(`console path ${JSON.stringify(entry.path)} must start with a single "/"`);
|
|
2078
|
+
}
|
|
2079
|
+
const holder = globalThis;
|
|
2080
|
+
if (holder[AVIARY_CONSOLES_SLOT] === void 0) {
|
|
2081
|
+
const fresh = {
|
|
2082
|
+
version: 1,
|
|
2083
|
+
entries: []
|
|
2084
|
+
};
|
|
2085
|
+
holder[AVIARY_CONSOLES_SLOT] = fresh;
|
|
2086
|
+
}
|
|
2087
|
+
const registry = readAviaryConsoles();
|
|
2088
|
+
if (registry === void 0) return void 0;
|
|
2089
|
+
if (registry.entries.some((existing) => existing.id === entry.id)) {
|
|
2090
|
+
logger3?.warn(`console id "${entry.id}" is already registered`);
|
|
2091
|
+
return void 0;
|
|
2092
|
+
}
|
|
2093
|
+
registry.entries.push(entry);
|
|
2094
|
+
return () => {
|
|
2095
|
+
const index = registry.entries.indexOf(entry);
|
|
2096
|
+
if (index !== -1) registry.entries.splice(index, 1);
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
__name(registerAviaryConsole, "registerAviaryConsole");
|
|
2100
|
+
function consoleSwitcherConfig(selfId, endpoint) {
|
|
2101
|
+
const registry = readAviaryConsoles();
|
|
2102
|
+
if (!registry?.entries.some((entry) => entry.id === selfId)) return void 0;
|
|
2103
|
+
const others = registry.entries.filter((entry) => entry.id !== selfId).length;
|
|
2104
|
+
return others > 0 ? {
|
|
2105
|
+
endpoint,
|
|
2106
|
+
others
|
|
2107
|
+
} : void 0;
|
|
2108
|
+
}
|
|
2109
|
+
__name(consoleSwitcherConfig, "consoleSwitcherConfig");
|
|
2110
|
+
async function allows(entry, context, ms) {
|
|
2111
|
+
let timer;
|
|
2112
|
+
const timeout = new Promise((resolve2) => {
|
|
2113
|
+
timer = setTimeout(() => resolve2(false), ms);
|
|
2114
|
+
});
|
|
2115
|
+
try {
|
|
2116
|
+
return await Promise.race([
|
|
2117
|
+
Promise.resolve().then(() => entry.authorize(context)).then((decision) => decision?.allowed === true, () => false),
|
|
2118
|
+
timeout
|
|
2119
|
+
]);
|
|
2120
|
+
} finally {
|
|
2121
|
+
clearTimeout(timer);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
__name(allows, "allows");
|
|
2125
|
+
async function listVisibleConsoles(registry, selfId, context, timeoutMs = CONSOLE_PROBE_TIMEOUT_MS) {
|
|
2126
|
+
const others = (registry?.entries ?? []).filter((entry) => entry.id !== selfId && isSameOriginPath(entry.path)).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
|
|
2127
|
+
const verdicts = await Promise.all(others.map((entry) => allows(entry, context, timeoutMs)));
|
|
2128
|
+
return {
|
|
2129
|
+
version: 1,
|
|
2130
|
+
current: selfId,
|
|
2131
|
+
consoles: others.filter((_, index) => verdicts[index]).map((entry) => ({
|
|
2132
|
+
id: entry.id,
|
|
2133
|
+
title: entry.title,
|
|
2134
|
+
icon: ICONS.has(entry.icon) ? entry.icon : "generic",
|
|
2135
|
+
href: entry.path
|
|
2136
|
+
}))
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
__name(listVisibleConsoles, "listVisibleConsoles");
|
|
2140
|
+
var DURABLE_CONSOLE_ID = "durable";
|
|
2141
|
+
var logger = new Logger2("DurableDashboardModule");
|
|
2142
|
+
var DurableConsoleRegistration = class {
|
|
2143
|
+
static {
|
|
2144
|
+
__name(this, "DurableConsoleRegistration");
|
|
2145
|
+
}
|
|
2146
|
+
basePath;
|
|
2147
|
+
decide;
|
|
2148
|
+
#unregister;
|
|
2149
|
+
constructor(basePath, decide) {
|
|
2150
|
+
this.basePath = basePath;
|
|
2151
|
+
this.decide = decide;
|
|
2152
|
+
}
|
|
2153
|
+
onModuleInit() {
|
|
2154
|
+
this.#unregister = registerAviaryConsole({
|
|
2155
|
+
id: DURABLE_CONSOLE_ID,
|
|
2156
|
+
title: "Workflows",
|
|
2157
|
+
icon: "workflow",
|
|
2158
|
+
order: 10,
|
|
2159
|
+
path: this.basePath,
|
|
2160
|
+
authorize: /* @__PURE__ */ __name((context) => this.decide(context), "authorize")
|
|
2161
|
+
}, logger);
|
|
2162
|
+
}
|
|
2163
|
+
onModuleDestroy() {
|
|
2164
|
+
this.#unregister?.();
|
|
2165
|
+
this.#unregister = void 0;
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
DurableConsoleRegistration = _ts_decorate7([
|
|
2169
|
+
Injectable5(),
|
|
2170
|
+
_ts_param4(0, Inject3(DASHBOARD_BASE_PATH)),
|
|
2171
|
+
_ts_param4(1, Inject3(CONSOLE_AUTHORIZE_DECIDE)),
|
|
2172
|
+
_ts_metadata6("design:type", Function),
|
|
2173
|
+
_ts_metadata6("design:paramtypes", [
|
|
2174
|
+
String,
|
|
2175
|
+
typeof ConsoleDecide === "undefined" ? Object : ConsoleDecide
|
|
2176
|
+
])
|
|
2177
|
+
], DurableConsoleRegistration);
|
|
2178
|
+
var CurrentExecutionContext = createParamDecorator((_data, context) => ({
|
|
2179
|
+
context
|
|
2180
|
+
}));
|
|
2181
|
+
var DurableConsolesController = class {
|
|
2182
|
+
static {
|
|
2183
|
+
__name(this, "DurableConsolesController");
|
|
2184
|
+
}
|
|
2185
|
+
consoles(current) {
|
|
2186
|
+
return listVisibleConsoles(readAviaryConsoles(), DURABLE_CONSOLE_ID, current.context);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
_ts_decorate7([
|
|
2190
|
+
Get2("consoles"),
|
|
2191
|
+
Header2("Cache-Control", "private, no-store"),
|
|
2192
|
+
_ts_param4(0, CurrentExecutionContext()),
|
|
2193
|
+
_ts_metadata6("design:type", Function),
|
|
2194
|
+
_ts_metadata6("design:paramtypes", [
|
|
2195
|
+
typeof CurrentContext === "undefined" ? Object : CurrentContext
|
|
2196
|
+
]),
|
|
2197
|
+
_ts_metadata6("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
2198
|
+
], DurableConsolesController.prototype, "consoles", null);
|
|
2199
|
+
DurableConsolesController = _ts_decorate7([
|
|
2200
|
+
Controller2()
|
|
2201
|
+
], DurableConsolesController);
|
|
1930
2202
|
|
|
1931
2203
|
// src/server/controller-decorators.ts
|
|
1932
2204
|
import "reflect-metadata";
|
|
@@ -1954,12 +2226,785 @@ function controllerFor(base, decorators) {
|
|
|
1954
2226
|
}
|
|
1955
2227
|
__name(controllerFor, "controllerFor");
|
|
1956
2228
|
|
|
2229
|
+
// src/server/dev-tools.ts
|
|
2230
|
+
import { HttpException as HttpException3, Inject as Inject4, Injectable as Injectable6, Logger as Logger3, NotFoundException as NotFoundException2 } from "@nestjs/common";
|
|
2231
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
2232
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2233
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
2234
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
2235
|
+
} else {
|
|
2236
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
2237
|
+
if (d = decorators[i]) {
|
|
2238
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2243
|
+
}
|
|
2244
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
2245
|
+
function _ts_metadata7(metadataKey, metadataValue) {
|
|
2246
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
2247
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
__name(_ts_metadata7, "_ts_metadata");
|
|
2251
|
+
function _ts_param5(paramIndex, decorator) {
|
|
2252
|
+
return function(target, key) {
|
|
2253
|
+
decorator(target, key, paramIndex);
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
__name(_ts_param5, "_ts_param");
|
|
2257
|
+
var DEV_TOOLS_SLOT = Symbol.for("@dudousxd/aviary:dev-tools");
|
|
2258
|
+
function devToolsSlot() {
|
|
2259
|
+
const holder = globalThis;
|
|
2260
|
+
const existing = holder[DEV_TOOLS_SLOT];
|
|
2261
|
+
if (existing !== void 0) return existing;
|
|
2262
|
+
const libs = [];
|
|
2263
|
+
const slot = {
|
|
2264
|
+
version: 1,
|
|
2265
|
+
libs,
|
|
2266
|
+
register(lib) {
|
|
2267
|
+
if (libs.some((entry) => entry.lib === lib.lib)) {
|
|
2268
|
+
throw new Error(`dev tools: the lib "${lib.lib}" is already registered`);
|
|
2269
|
+
}
|
|
2270
|
+
libs.push(lib);
|
|
2271
|
+
return () => {
|
|
2272
|
+
const index = libs.indexOf(lib);
|
|
2273
|
+
if (index !== -1) libs.splice(index, 1);
|
|
2274
|
+
};
|
|
2275
|
+
}
|
|
2276
|
+
};
|
|
2277
|
+
holder[DEV_TOOLS_SLOT] = slot;
|
|
2278
|
+
return slot;
|
|
2279
|
+
}
|
|
2280
|
+
__name(devToolsSlot, "devToolsSlot");
|
|
2281
|
+
var DEFAULT_LIMIT = 20;
|
|
2282
|
+
var MAX_LIMIT = 100;
|
|
2283
|
+
var MAX_RUN_IDS = 100;
|
|
2284
|
+
var ERROR_SUMMARY_CHARS = 300;
|
|
2285
|
+
var RUN_STATUSES = [
|
|
2286
|
+
"pending",
|
|
2287
|
+
"running",
|
|
2288
|
+
"suspended",
|
|
2289
|
+
"completed",
|
|
2290
|
+
"failed",
|
|
2291
|
+
"cancelling",
|
|
2292
|
+
"cancelled",
|
|
2293
|
+
"dead",
|
|
2294
|
+
"blocked"
|
|
2295
|
+
];
|
|
2296
|
+
var COUNT_FIELDS = [
|
|
2297
|
+
"status",
|
|
2298
|
+
"workflow",
|
|
2299
|
+
"origin",
|
|
2300
|
+
"namespace",
|
|
2301
|
+
"tag",
|
|
2302
|
+
"attributeKey",
|
|
2303
|
+
"attributeValue"
|
|
2304
|
+
];
|
|
2305
|
+
var limit = {
|
|
2306
|
+
type: "integer",
|
|
2307
|
+
description: `Rows per page (default ${DEFAULT_LIMIT}, max ${MAX_LIMIT}).`,
|
|
2308
|
+
minimum: 1,
|
|
2309
|
+
maximum: MAX_LIMIT
|
|
2310
|
+
};
|
|
2311
|
+
var cursor = {
|
|
2312
|
+
type: "string",
|
|
2313
|
+
description: "Pass the `next` of the previous page."
|
|
2314
|
+
};
|
|
2315
|
+
var runId = {
|
|
2316
|
+
type: "string",
|
|
2317
|
+
description: "Run id."
|
|
2318
|
+
};
|
|
2319
|
+
var runIds = {
|
|
2320
|
+
type: "array",
|
|
2321
|
+
items: {
|
|
2322
|
+
type: "string"
|
|
2323
|
+
},
|
|
2324
|
+
description: `Several run ids (1 to ${MAX_RUN_IDS}), instead of \`id\`.`
|
|
2325
|
+
};
|
|
2326
|
+
var scheduleKey = {
|
|
2327
|
+
type: "string",
|
|
2328
|
+
description: "Schedule id."
|
|
2329
|
+
};
|
|
2330
|
+
var runFilters = {
|
|
2331
|
+
workflow: {
|
|
2332
|
+
type: "string",
|
|
2333
|
+
description: "Workflow name."
|
|
2334
|
+
},
|
|
2335
|
+
tag: {
|
|
2336
|
+
type: "string",
|
|
2337
|
+
description: "A tag the run carries."
|
|
2338
|
+
},
|
|
2339
|
+
namespace: {
|
|
2340
|
+
type: "string",
|
|
2341
|
+
description: "Worker pool (namespace)."
|
|
2342
|
+
},
|
|
2343
|
+
attr: {
|
|
2344
|
+
type: "array",
|
|
2345
|
+
items: {
|
|
2346
|
+
type: "string"
|
|
2347
|
+
},
|
|
2348
|
+
description: "Search-attribute predicates `key:op:value` (ops: eq, ne, gt, gte, lt, lte, in with `|`), ANDed."
|
|
2349
|
+
}
|
|
2350
|
+
};
|
|
2351
|
+
var str = /* @__PURE__ */ __name((value) => typeof value === "string" && value !== "" ? value : void 0, "str");
|
|
2352
|
+
function limitOf(input) {
|
|
2353
|
+
const value = input.limit;
|
|
2354
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? Math.min(value, MAX_LIMIT) : DEFAULT_LIMIT;
|
|
2355
|
+
}
|
|
2356
|
+
__name(limitOf, "limitOf");
|
|
2357
|
+
function offsetOf(input) {
|
|
2358
|
+
const value = str(input.cursor);
|
|
2359
|
+
if (value === void 0) return 0;
|
|
2360
|
+
if (!/^\d+$/.test(value)) {
|
|
2361
|
+
throw new Error(`"cursor" must be the \`next\` of a previous page, got "${value}"`);
|
|
2362
|
+
}
|
|
2363
|
+
return Number(value);
|
|
2364
|
+
}
|
|
2365
|
+
__name(offsetOf, "offsetOf");
|
|
2366
|
+
function required(input, key) {
|
|
2367
|
+
const value = str(input[key]);
|
|
2368
|
+
if (value === void 0) throw new Error(`"${key}" is required`);
|
|
2369
|
+
return value;
|
|
2370
|
+
}
|
|
2371
|
+
__name(required, "required");
|
|
2372
|
+
function page(rows, offset, size) {
|
|
2373
|
+
return {
|
|
2374
|
+
items: rows.slice(0, size),
|
|
2375
|
+
next: rows.length > size ? String(offset + size) : null
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
__name(page, "page");
|
|
2379
|
+
function runPredicates(input) {
|
|
2380
|
+
const query = {};
|
|
2381
|
+
const workflow = str(input.workflow);
|
|
2382
|
+
if (workflow !== void 0) query.workflow = workflow;
|
|
2383
|
+
const tag = str(input.tag);
|
|
2384
|
+
if (tag !== void 0) query.tag = tag;
|
|
2385
|
+
const namespace = str(input.namespace);
|
|
2386
|
+
if (namespace !== void 0) query.namespace = namespace;
|
|
2387
|
+
const attr = Array.isArray(input.attr) ? input.attr.filter((entry) => typeof entry === "string" && entry !== "") : [];
|
|
2388
|
+
if (attr.length > 0) {
|
|
2389
|
+
const attributes = parseAttrFilters(attr);
|
|
2390
|
+
if (attributes === void 0 || attributes.length !== attr.length) {
|
|
2391
|
+
throw new Error(`"attr" entries must read \`key:op:value\`, got ${JSON.stringify(attr)}`);
|
|
2392
|
+
}
|
|
2393
|
+
query.attributes = attributes;
|
|
2394
|
+
}
|
|
2395
|
+
return query;
|
|
2396
|
+
}
|
|
2397
|
+
__name(runPredicates, "runPredicates");
|
|
2398
|
+
function statusOf(input) {
|
|
2399
|
+
const status = str(input.status);
|
|
2400
|
+
if (status === void 0) return void 0;
|
|
2401
|
+
if (!RUN_STATUSES.includes(status)) {
|
|
2402
|
+
throw new Error(`"status" must be one of ${RUN_STATUSES.join(", ")}, got "${status}"`);
|
|
2403
|
+
}
|
|
2404
|
+
return status;
|
|
2405
|
+
}
|
|
2406
|
+
__name(statusOf, "statusOf");
|
|
2407
|
+
function listRow(run) {
|
|
2408
|
+
const row = {
|
|
2409
|
+
...toRunListRow(run)
|
|
2410
|
+
};
|
|
2411
|
+
const message = run.error?.message;
|
|
2412
|
+
if (typeof message === "string" && message !== "") {
|
|
2413
|
+
const line = message.split("\n", 1)[0] ?? "";
|
|
2414
|
+
row.error = line.length > ERROR_SUMMARY_CHARS ? `${line.slice(0, ERROR_SUMMARY_CHARS)}\u2026` : line;
|
|
2415
|
+
}
|
|
2416
|
+
return row;
|
|
2417
|
+
}
|
|
2418
|
+
__name(listRow, "listRow");
|
|
2419
|
+
async function call(what, run) {
|
|
2420
|
+
try {
|
|
2421
|
+
return await run();
|
|
2422
|
+
} catch (error) {
|
|
2423
|
+
if (error instanceof NotFoundException2 || error instanceof Error && error.name === "ScheduleNotFoundError") {
|
|
2424
|
+
throw new Error(`${what()} not found`);
|
|
2425
|
+
}
|
|
2426
|
+
if (error instanceof HttpException3) throw new Error(error.message);
|
|
2427
|
+
throw error;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
__name(call, "call");
|
|
2431
|
+
function found(value, what) {
|
|
2432
|
+
if (value === null || value === void 0) throw new Error(`${what} not found`);
|
|
2433
|
+
return value;
|
|
2434
|
+
}
|
|
2435
|
+
__name(found, "found");
|
|
2436
|
+
function idsOf(input) {
|
|
2437
|
+
const one = str(input.id);
|
|
2438
|
+
const many = Array.isArray(input.ids) ? input.ids.filter((id) => typeof id === "string" && id !== "") : void 0;
|
|
2439
|
+
if (one !== void 0 && many !== void 0) throw new Error('pass "id" or "ids", not both');
|
|
2440
|
+
if (one !== void 0) return {
|
|
2441
|
+
ids: [
|
|
2442
|
+
one
|
|
2443
|
+
],
|
|
2444
|
+
many: false
|
|
2445
|
+
};
|
|
2446
|
+
if (many === void 0 || many.length === 0) throw new Error('"id" or "ids" is required');
|
|
2447
|
+
if (many.length > MAX_RUN_IDS) {
|
|
2448
|
+
throw new Error(`"ids" lists ${many.length} runs; at most ${MAX_RUN_IDS} per call`);
|
|
2449
|
+
}
|
|
2450
|
+
return {
|
|
2451
|
+
ids: many,
|
|
2452
|
+
many: true
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
__name(idsOf, "idsOf");
|
|
2456
|
+
async function each(input, act) {
|
|
2457
|
+
const { ids, many } = idsOf(input);
|
|
2458
|
+
if (!many) return act(ids[0]);
|
|
2459
|
+
const applied = [];
|
|
2460
|
+
for (const [index, id] of ids.entries()) {
|
|
2461
|
+
try {
|
|
2462
|
+
applied.push(await act(id));
|
|
2463
|
+
} catch (error) {
|
|
2464
|
+
return {
|
|
2465
|
+
applied,
|
|
2466
|
+
failed: {
|
|
2467
|
+
id,
|
|
2468
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2469
|
+
},
|
|
2470
|
+
skipped: ids.slice(index + 1)
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
return {
|
|
2475
|
+
applied
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
__name(each, "each");
|
|
2479
|
+
function starvedGroups(groups) {
|
|
2480
|
+
return groups.filter((group) => group.depth > 0 && group.liveWorkers.length === 0).sort((a, b) => b.depth - a.depth).map(({ group, depth, kind }) => ({
|
|
2481
|
+
group,
|
|
2482
|
+
depth,
|
|
2483
|
+
...kind ? {
|
|
2484
|
+
kind
|
|
2485
|
+
} : {}
|
|
2486
|
+
}));
|
|
2487
|
+
}
|
|
2488
|
+
__name(starvedGroups, "starvedGroups");
|
|
2489
|
+
function durableDevTools(service) {
|
|
2490
|
+
const controlPlane = /* @__PURE__ */ __name(() => service.capabilities().controlPlane, "controlPlane");
|
|
2491
|
+
const schedules = /* @__PURE__ */ __name(() => service.capabilities().schedules, "schedules");
|
|
2492
|
+
return [
|
|
2493
|
+
{
|
|
2494
|
+
name: "durable_list_runs",
|
|
2495
|
+
kind: "read",
|
|
2496
|
+
description: "Workflow runs, newest first: id, workflow, status, what a suspended run waits on, times, tags and a one-line error summary (no input or output). Filters: status, workflow, tag, namespace, origin, attr. Returns { items, next }; pass next as cursor.",
|
|
2497
|
+
input: {
|
|
2498
|
+
type: "object",
|
|
2499
|
+
properties: {
|
|
2500
|
+
status: {
|
|
2501
|
+
type: "string",
|
|
2502
|
+
enum: RUN_STATUSES,
|
|
2503
|
+
description: "Run status."
|
|
2504
|
+
},
|
|
2505
|
+
...runFilters,
|
|
2506
|
+
origin: {
|
|
2507
|
+
type: "string",
|
|
2508
|
+
description: "The package the run came from."
|
|
2509
|
+
},
|
|
2510
|
+
cursor,
|
|
2511
|
+
limit
|
|
2512
|
+
}
|
|
2513
|
+
},
|
|
2514
|
+
async run(input) {
|
|
2515
|
+
const size = limitOf(input);
|
|
2516
|
+
const offset = offsetOf(input);
|
|
2517
|
+
const status = statusOf(input);
|
|
2518
|
+
const origin = str(input.origin);
|
|
2519
|
+
const query = {
|
|
2520
|
+
...runPredicates(input),
|
|
2521
|
+
...status !== void 0 ? {
|
|
2522
|
+
status
|
|
2523
|
+
} : {},
|
|
2524
|
+
...origin !== void 0 ? {
|
|
2525
|
+
origin
|
|
2526
|
+
} : {},
|
|
2527
|
+
offset,
|
|
2528
|
+
limit: size + 1
|
|
2529
|
+
};
|
|
2530
|
+
const runs = await call(() => "runs", () => service.listRuns(query));
|
|
2531
|
+
return page(runs.map(listRow), offset, size);
|
|
2532
|
+
}
|
|
2533
|
+
},
|
|
2534
|
+
{
|
|
2535
|
+
name: "durable_get_run",
|
|
2536
|
+
kind: "read",
|
|
2537
|
+
description: 'One run: its input, output, error, step timeline, children, fans (summarized over 50 members unless full) and lifecycle links. `field` returns that one field only (e.g. "steps"). An error when no run has that id.',
|
|
2538
|
+
input: {
|
|
2539
|
+
type: "object",
|
|
2540
|
+
properties: {
|
|
2541
|
+
id: runId,
|
|
2542
|
+
full: {
|
|
2543
|
+
type: "boolean",
|
|
2544
|
+
description: "Every fan member inline (default false)."
|
|
2545
|
+
},
|
|
2546
|
+
field: {
|
|
2547
|
+
type: "string",
|
|
2548
|
+
description: "Return only this top-level field."
|
|
2549
|
+
}
|
|
2550
|
+
},
|
|
2551
|
+
required: [
|
|
2552
|
+
"id"
|
|
2553
|
+
]
|
|
2554
|
+
},
|
|
2555
|
+
async run(input) {
|
|
2556
|
+
const id = required(input, "id");
|
|
2557
|
+
const detail = found(await call(() => `run ${id}`, () => service.getRunDetail(id, input.full === true ? void 0 : {
|
|
2558
|
+
summarizeFansOver: 50
|
|
2559
|
+
})), `run ${id}`);
|
|
2560
|
+
const { etag: _etag, notModified: _notModified, ...body } = detail;
|
|
2561
|
+
const field = str(input.field);
|
|
2562
|
+
if (field === void 0) return body;
|
|
2563
|
+
if (!Object.hasOwn(body, field)) {
|
|
2564
|
+
throw new Error(`run ${id} has no field "${field}"; fields: ${Object.keys(body).join(", ")}`);
|
|
2565
|
+
}
|
|
2566
|
+
return {
|
|
2567
|
+
id,
|
|
2568
|
+
[field]: body[field]
|
|
2569
|
+
};
|
|
2570
|
+
}
|
|
2571
|
+
},
|
|
2572
|
+
{
|
|
2573
|
+
name: "durable_list_fan_members",
|
|
2574
|
+
kind: "read",
|
|
2575
|
+
description: "One fan's members (the steps or children of a fan-out group), in order. Filters: failed (only failed members). Returns { items, total, next }; pass next as cursor. An error when the run or the fan does not exist.",
|
|
2576
|
+
input: {
|
|
2577
|
+
type: "object",
|
|
2578
|
+
properties: {
|
|
2579
|
+
id: runId,
|
|
2580
|
+
group: {
|
|
2581
|
+
type: "string",
|
|
2582
|
+
description: "The fan group, as the run detail names it."
|
|
2583
|
+
},
|
|
2584
|
+
failed: {
|
|
2585
|
+
type: "boolean",
|
|
2586
|
+
description: "Only failed members."
|
|
2587
|
+
},
|
|
2588
|
+
cursor,
|
|
2589
|
+
limit
|
|
2590
|
+
},
|
|
2591
|
+
required: [
|
|
2592
|
+
"id",
|
|
2593
|
+
"group"
|
|
2594
|
+
]
|
|
2595
|
+
},
|
|
2596
|
+
async run(input) {
|
|
2597
|
+
const id = required(input, "id");
|
|
2598
|
+
const group = required(input, "group");
|
|
2599
|
+
const size = limitOf(input);
|
|
2600
|
+
const offset = offsetOf(input);
|
|
2601
|
+
const fan = found(await call(() => `fan ${group} of run ${id}`, () => service.getFanMembers(id, group, {
|
|
2602
|
+
offset,
|
|
2603
|
+
limit: size,
|
|
2604
|
+
failedOnly: input.failed === true
|
|
2605
|
+
})), `fan ${group} of run ${id}`);
|
|
2606
|
+
const end = offset + fan.items.length;
|
|
2607
|
+
return {
|
|
2608
|
+
items: fan.items,
|
|
2609
|
+
total: fan.total,
|
|
2610
|
+
next: fan.items.length > 0 && end < fan.total ? String(end) : null
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2613
|
+
},
|
|
2614
|
+
{
|
|
2615
|
+
name: "durable_count_runs_by",
|
|
2616
|
+
kind: "read",
|
|
2617
|
+
description: "How many runs have each value of one field (status, workflow, origin, namespace, tag, attributeKey, or attributeValue with key), most frequent first. Filters: workflow, tag, namespace, attr. Returns { items: [{ value, count }], next }; pass next as cursor. Empty when the store cannot count that field.",
|
|
2618
|
+
input: {
|
|
2619
|
+
type: "object",
|
|
2620
|
+
properties: {
|
|
2621
|
+
field: {
|
|
2622
|
+
type: "string",
|
|
2623
|
+
enum: COUNT_FIELDS,
|
|
2624
|
+
description: "The field to count by."
|
|
2625
|
+
},
|
|
2626
|
+
key: {
|
|
2627
|
+
type: "string",
|
|
2628
|
+
description: "The search attribute, for attributeValue."
|
|
2629
|
+
},
|
|
2630
|
+
...runFilters,
|
|
2631
|
+
cursor,
|
|
2632
|
+
limit
|
|
2633
|
+
},
|
|
2634
|
+
required: [
|
|
2635
|
+
"field"
|
|
2636
|
+
]
|
|
2637
|
+
},
|
|
2638
|
+
async run(input) {
|
|
2639
|
+
const field = required(input, "field");
|
|
2640
|
+
if (!COUNT_FIELDS.includes(field)) {
|
|
2641
|
+
throw new Error(`"field" must be one of ${COUNT_FIELDS.join(", ")}, got "${field}"`);
|
|
2642
|
+
}
|
|
2643
|
+
const size = limitOf(input);
|
|
2644
|
+
const offset = offsetOf(input);
|
|
2645
|
+
const predicates = runPredicates(input);
|
|
2646
|
+
if (field === "status" || field === "origin") {
|
|
2647
|
+
const rows2 = await call(() => "runs", () => service.runFacets(predicates));
|
|
2648
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2649
|
+
for (const row of rows2) {
|
|
2650
|
+
const value = field === "status" ? row.status : row.origin;
|
|
2651
|
+
counts.set(value, (counts.get(value) ?? 0) + row.count);
|
|
2652
|
+
}
|
|
2653
|
+
const items = [
|
|
2654
|
+
...counts
|
|
2655
|
+
].map(([value, count]) => ({
|
|
2656
|
+
value,
|
|
2657
|
+
count
|
|
2658
|
+
})).sort((a, b) => b.count - a.count || String(a.value).localeCompare(String(b.value)));
|
|
2659
|
+
return page(items.slice(offset), offset, size);
|
|
2660
|
+
}
|
|
2661
|
+
const axis = field === "attributeValue" ? {
|
|
2662
|
+
field,
|
|
2663
|
+
key: required(input, "key")
|
|
2664
|
+
} : {
|
|
2665
|
+
field
|
|
2666
|
+
};
|
|
2667
|
+
const rows = await call(() => "runs", () => service.runValueFacets(axis, predicates, {
|
|
2668
|
+
offset,
|
|
2669
|
+
limit: size + 1
|
|
2670
|
+
}));
|
|
2671
|
+
return page(rows, offset, size);
|
|
2672
|
+
}
|
|
2673
|
+
},
|
|
2674
|
+
{
|
|
2675
|
+
name: "durable_get_health",
|
|
2676
|
+
kind: "read",
|
|
2677
|
+
description: "The fleet at a glance: run counts by status (pending backlog, dead, blocked: a run no compatible worker can take), queues with backlog and no live worker (starved), live worker count, and this deployment's role (control plane or tenant).",
|
|
2678
|
+
input: {
|
|
2679
|
+
type: "object",
|
|
2680
|
+
properties: {}
|
|
2681
|
+
},
|
|
2682
|
+
async run() {
|
|
2683
|
+
const [facets, groups] = await Promise.all([
|
|
2684
|
+
call(() => "runs", () => service.runFacets({})),
|
|
2685
|
+
call(() => "workers", () => service.workerHealth())
|
|
2686
|
+
]);
|
|
2687
|
+
const runs = {};
|
|
2688
|
+
for (const row of facets) runs[row.status] = (runs[row.status] ?? 0) + row.count;
|
|
2689
|
+
const workers = /* @__PURE__ */ new Set();
|
|
2690
|
+
for (const group of groups) {
|
|
2691
|
+
for (const worker of group.liveWorkers) workers.add(worker.instanceId);
|
|
2692
|
+
}
|
|
2693
|
+
const starved = starvedGroups(groups);
|
|
2694
|
+
return {
|
|
2695
|
+
topology: service.topology(),
|
|
2696
|
+
runs,
|
|
2697
|
+
backlog: runs.pending ?? 0,
|
|
2698
|
+
dead: runs.dead ?? 0,
|
|
2699
|
+
blocked: runs.blocked ?? 0,
|
|
2700
|
+
queues: groups.length,
|
|
2701
|
+
liveWorkers: workers.size,
|
|
2702
|
+
starved,
|
|
2703
|
+
healthy: starved.length === 0 && (runs.blocked ?? 0) === 0
|
|
2704
|
+
};
|
|
2705
|
+
}
|
|
2706
|
+
},
|
|
2707
|
+
{
|
|
2708
|
+
name: "durable_list_workers",
|
|
2709
|
+
kind: "read",
|
|
2710
|
+
description: "Worker groups (queues): group, kind (workflow or step), queue depth and the live workers with their heartbeats. A group with depth > 0 and no live worker is starved. Returns { items, next: null }.",
|
|
2711
|
+
input: {
|
|
2712
|
+
type: "object",
|
|
2713
|
+
properties: {}
|
|
2714
|
+
},
|
|
2715
|
+
async run() {
|
|
2716
|
+
const groups = await call(() => "workers", () => service.workerHealth());
|
|
2717
|
+
return {
|
|
2718
|
+
items: groups,
|
|
2719
|
+
next: null
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
},
|
|
2723
|
+
{
|
|
2724
|
+
name: "durable_list_schedules",
|
|
2725
|
+
kind: "read",
|
|
2726
|
+
description: "Persisted schedules, soonest due first: id, workflow, cadence (cron, every or rrule), paused, nextFireAt, lastFireAt, lastRunId, fires, lastError. Filters: workflow, tag, namespace, paused. Returns { items, next }; pass next as cursor.",
|
|
2727
|
+
input: {
|
|
2728
|
+
type: "object",
|
|
2729
|
+
properties: {
|
|
2730
|
+
workflow: {
|
|
2731
|
+
type: "string",
|
|
2732
|
+
description: "Workflow name."
|
|
2733
|
+
},
|
|
2734
|
+
tag: {
|
|
2735
|
+
type: "string",
|
|
2736
|
+
description: "A tag the schedule carries."
|
|
2737
|
+
},
|
|
2738
|
+
namespace: {
|
|
2739
|
+
type: "string",
|
|
2740
|
+
description: "Worker pool (namespace)."
|
|
2741
|
+
},
|
|
2742
|
+
paused: {
|
|
2743
|
+
type: "boolean",
|
|
2744
|
+
description: "Only paused (true) or active (false)."
|
|
2745
|
+
},
|
|
2746
|
+
cursor,
|
|
2747
|
+
limit
|
|
2748
|
+
}
|
|
2749
|
+
},
|
|
2750
|
+
available: schedules,
|
|
2751
|
+
async run(input) {
|
|
2752
|
+
const size = limitOf(input);
|
|
2753
|
+
const offset = offsetOf(input);
|
|
2754
|
+
const workflow = str(input.workflow);
|
|
2755
|
+
const tag = str(input.tag);
|
|
2756
|
+
const namespace = str(input.namespace);
|
|
2757
|
+
const rows = await call(() => "schedules", () => service.listSchedules({
|
|
2758
|
+
...workflow !== void 0 ? {
|
|
2759
|
+
workflow
|
|
2760
|
+
} : {},
|
|
2761
|
+
...tag !== void 0 ? {
|
|
2762
|
+
tag
|
|
2763
|
+
} : {},
|
|
2764
|
+
...namespace !== void 0 ? {
|
|
2765
|
+
namespace
|
|
2766
|
+
} : {},
|
|
2767
|
+
...typeof input.paused === "boolean" ? {
|
|
2768
|
+
paused: input.paused
|
|
2769
|
+
} : {},
|
|
2770
|
+
offset,
|
|
2771
|
+
limit: size + 1
|
|
2772
|
+
}));
|
|
2773
|
+
return page(rows, offset, size);
|
|
2774
|
+
}
|
|
2775
|
+
},
|
|
2776
|
+
{
|
|
2777
|
+
name: "durable_get_run_event",
|
|
2778
|
+
kind: "read",
|
|
2779
|
+
description: "The latest value a run published for `key` with ctx.setEvent (a live query, no side effect). Returns { id, key, value }; value is null when the run never published that key. An error when no run has that id.",
|
|
2780
|
+
input: {
|
|
2781
|
+
type: "object",
|
|
2782
|
+
properties: {
|
|
2783
|
+
id: runId,
|
|
2784
|
+
key: {
|
|
2785
|
+
type: "string",
|
|
2786
|
+
description: "Event key."
|
|
2787
|
+
}
|
|
2788
|
+
},
|
|
2789
|
+
required: [
|
|
2790
|
+
"id",
|
|
2791
|
+
"key"
|
|
2792
|
+
]
|
|
2793
|
+
},
|
|
2794
|
+
available: controlPlane,
|
|
2795
|
+
async run(input) {
|
|
2796
|
+
const id = required(input, "id");
|
|
2797
|
+
const key = required(input, "key");
|
|
2798
|
+
if (!await call(() => `run ${id}`, () => service.runExists(id))) {
|
|
2799
|
+
throw new Error(`run ${id} not found`);
|
|
2800
|
+
}
|
|
2801
|
+
const value = await call(() => `run ${id}`, () => service.getEvent(id, key));
|
|
2802
|
+
return {
|
|
2803
|
+
id,
|
|
2804
|
+
key,
|
|
2805
|
+
value: value ?? null
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
},
|
|
2809
|
+
{
|
|
2810
|
+
name: "durable_retry_run",
|
|
2811
|
+
kind: "action",
|
|
2812
|
+
description: `Re-runs a failed, dead or cancelled run; completed steps replay from their checkpoints. Returns { runId, status }. With ids (at most ${MAX_RUN_IDS}), runs them in order and stops at the first that fails: { applied, failed: { id, error }, skipped }. An error when no run has that id.`,
|
|
2813
|
+
input: {
|
|
2814
|
+
type: "object",
|
|
2815
|
+
properties: {
|
|
2816
|
+
id: runId,
|
|
2817
|
+
ids: runIds
|
|
2818
|
+
}
|
|
2819
|
+
},
|
|
2820
|
+
async run(input) {
|
|
2821
|
+
return each(input, async (id) => found(await call(() => `run ${id}`, () => service.retry(id)), `run ${id}`));
|
|
2822
|
+
}
|
|
2823
|
+
},
|
|
2824
|
+
{
|
|
2825
|
+
name: "durable_cancel_run",
|
|
2826
|
+
kind: "action",
|
|
2827
|
+
destructive: true,
|
|
2828
|
+
description: `Cancels a run that has not finished (with compensate: true, its completed steps' compensations run first). Returns { runId, status }. With ids (at most ${MAX_RUN_IDS}), cancels them in order and stops at the first that fails: { applied, failed: { id, error }, skipped }. An error when no run has that id.`,
|
|
2829
|
+
input: {
|
|
2830
|
+
type: "object",
|
|
2831
|
+
properties: {
|
|
2832
|
+
id: runId,
|
|
2833
|
+
ids: runIds,
|
|
2834
|
+
compensate: {
|
|
2835
|
+
type: "boolean",
|
|
2836
|
+
description: "Run compensations (default false)."
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
},
|
|
2840
|
+
async run(input) {
|
|
2841
|
+
const compensate = input.compensate === true;
|
|
2842
|
+
return each(input, async (id) => found(await call(() => `run ${id}`, () => service.cancel(id, {
|
|
2843
|
+
compensate
|
|
2844
|
+
})), `run ${id}`));
|
|
2845
|
+
}
|
|
2846
|
+
},
|
|
2847
|
+
{
|
|
2848
|
+
name: "durable_continue_run",
|
|
2849
|
+
kind: "action",
|
|
2850
|
+
description: "Resumes a run paused at a ctx.breakpoint. Returns { runId, status }. An error when no run has that id, or when it is not paused at a breakpoint.",
|
|
2851
|
+
input: {
|
|
2852
|
+
type: "object",
|
|
2853
|
+
properties: {
|
|
2854
|
+
id: runId
|
|
2855
|
+
},
|
|
2856
|
+
required: [
|
|
2857
|
+
"id"
|
|
2858
|
+
]
|
|
2859
|
+
},
|
|
2860
|
+
async run(input) {
|
|
2861
|
+
const id = required(input, "id");
|
|
2862
|
+
const what = /* @__PURE__ */ __name(() => `run ${id}`, "what");
|
|
2863
|
+
const result = await call(what, () => service.continue(id));
|
|
2864
|
+
if (result) return result;
|
|
2865
|
+
if (!await call(what, () => service.runExists(id))) throw new Error(`run ${id} not found`);
|
|
2866
|
+
throw new Error(`run ${id} is not paused at a breakpoint`);
|
|
2867
|
+
}
|
|
2868
|
+
},
|
|
2869
|
+
{
|
|
2870
|
+
name: "durable_signal_run",
|
|
2871
|
+
kind: "action",
|
|
2872
|
+
description: "Sends a signal: delivers payload (JSON text; omitted is null) to the run waiting on token (ctx.waitForSignal or a ctx.webhook token). Returns { delivered: true, runId, status }, or { delivered: false } when no run you can see waits on the token yet: the engine then buffers the payload for the next run that waits on it.",
|
|
2873
|
+
input: {
|
|
2874
|
+
type: "object",
|
|
2875
|
+
properties: {
|
|
2876
|
+
token: {
|
|
2877
|
+
type: "string",
|
|
2878
|
+
description: "The signal token the run waits on."
|
|
2879
|
+
},
|
|
2880
|
+
payload: {
|
|
2881
|
+
type: "string",
|
|
2882
|
+
description: "The payload, as JSON text."
|
|
2883
|
+
}
|
|
2884
|
+
},
|
|
2885
|
+
required: [
|
|
2886
|
+
"token"
|
|
2887
|
+
]
|
|
2888
|
+
},
|
|
2889
|
+
available: controlPlane,
|
|
2890
|
+
async run(input) {
|
|
2891
|
+
const token = required(input, "token");
|
|
2892
|
+
let payload = null;
|
|
2893
|
+
if (typeof input.payload === "string" && input.payload.trim() !== "") {
|
|
2894
|
+
try {
|
|
2895
|
+
payload = JSON.parse(input.payload);
|
|
2896
|
+
} catch {
|
|
2897
|
+
throw new Error('"payload" must be JSON text (quote a plain string: "\\"ok\\"")');
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
const result = await call(() => `token ${token}`, () => service.signal(token, payload));
|
|
2901
|
+
return result ? {
|
|
2902
|
+
delivered: true,
|
|
2903
|
+
runId: result.runId,
|
|
2904
|
+
status: result.status
|
|
2905
|
+
} : {
|
|
2906
|
+
delivered: false
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
},
|
|
2910
|
+
{
|
|
2911
|
+
name: "durable_trigger_schedule",
|
|
2912
|
+
kind: "action",
|
|
2913
|
+
description: "Starts one run of a schedule now, outside its cadence (it does not count as a fire). Returns { runId, status }. An error when no schedule has that id.",
|
|
2914
|
+
input: {
|
|
2915
|
+
type: "object",
|
|
2916
|
+
properties: {
|
|
2917
|
+
key: scheduleKey
|
|
2918
|
+
},
|
|
2919
|
+
required: [
|
|
2920
|
+
"key"
|
|
2921
|
+
]
|
|
2922
|
+
},
|
|
2923
|
+
available: schedules,
|
|
2924
|
+
async run(input) {
|
|
2925
|
+
const key = required(input, "key");
|
|
2926
|
+
return call(() => `schedule ${key}`, () => service.triggerSchedule(key));
|
|
2927
|
+
}
|
|
2928
|
+
},
|
|
2929
|
+
{
|
|
2930
|
+
name: "durable_pause_schedule",
|
|
2931
|
+
kind: "action",
|
|
2932
|
+
description: "Pauses a schedule (paused: true, the default) or resumes it from its next window (paused: false). Returns the schedule. An error when no schedule has that id.",
|
|
2933
|
+
input: {
|
|
2934
|
+
type: "object",
|
|
2935
|
+
properties: {
|
|
2936
|
+
key: scheduleKey,
|
|
2937
|
+
paused: {
|
|
2938
|
+
type: "boolean",
|
|
2939
|
+
description: "false resumes it (default true)."
|
|
2940
|
+
}
|
|
2941
|
+
},
|
|
2942
|
+
required: [
|
|
2943
|
+
"key"
|
|
2944
|
+
]
|
|
2945
|
+
},
|
|
2946
|
+
available: schedules,
|
|
2947
|
+
async run(input) {
|
|
2948
|
+
const key = required(input, "key");
|
|
2949
|
+
return call(() => `schedule ${key}`, () => input.paused === false ? service.resumeSchedule(key) : service.pauseSchedule(key));
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
];
|
|
2953
|
+
}
|
|
2954
|
+
__name(durableDevTools, "durableDevTools");
|
|
2955
|
+
var logger2 = new Logger3("DurableDashboardModule");
|
|
2956
|
+
var DurableDevToolsRegistration = class {
|
|
2957
|
+
static {
|
|
2958
|
+
__name(this, "DurableDevToolsRegistration");
|
|
2959
|
+
}
|
|
2960
|
+
enabled;
|
|
2961
|
+
service;
|
|
2962
|
+
decide;
|
|
2963
|
+
#unregister;
|
|
2964
|
+
constructor(enabled, service, decide) {
|
|
2965
|
+
this.enabled = enabled;
|
|
2966
|
+
this.service = service;
|
|
2967
|
+
this.decide = decide;
|
|
2968
|
+
}
|
|
2969
|
+
onModuleInit() {
|
|
2970
|
+
if (!this.enabled) return;
|
|
2971
|
+
const slot = devToolsSlot();
|
|
2972
|
+
if (slot.version !== 1 || typeof slot.register !== "function") return;
|
|
2973
|
+
try {
|
|
2974
|
+
this.#unregister = slot.register({
|
|
2975
|
+
lib: "durable",
|
|
2976
|
+
title: "Durable workflows",
|
|
2977
|
+
authorize: /* @__PURE__ */ __name((context) => this.decide(context), "authorize"),
|
|
2978
|
+
tools: durableDevTools(this.service)
|
|
2979
|
+
});
|
|
2980
|
+
} catch (error) {
|
|
2981
|
+
logger2.warn(`durable dev tools not registered: ${error instanceof Error ? error.message : String(error)}`);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
onModuleDestroy() {
|
|
2985
|
+
this.#unregister?.();
|
|
2986
|
+
this.#unregister = void 0;
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
DurableDevToolsRegistration = _ts_decorate8([
|
|
2990
|
+
Injectable6(),
|
|
2991
|
+
_ts_param5(0, Inject4(DASHBOARD_DEV_TOOLS)),
|
|
2992
|
+
_ts_param5(1, Inject4(DashboardService)),
|
|
2993
|
+
_ts_param5(2, Inject4(CONSOLE_AUTHORIZE_DECIDE)),
|
|
2994
|
+
_ts_metadata7("design:type", Function),
|
|
2995
|
+
_ts_metadata7("design:paramtypes", [
|
|
2996
|
+
Boolean,
|
|
2997
|
+
typeof DashboardService === "undefined" ? Object : DashboardService,
|
|
2998
|
+
typeof ConsoleDecide === "undefined" ? Object : ConsoleDecide
|
|
2999
|
+
])
|
|
3000
|
+
], DurableDevToolsRegistration);
|
|
3001
|
+
|
|
1957
3002
|
// src/server/durable-ui.controller.ts
|
|
1958
3003
|
import { existsSync, readFileSync } from "node:fs";
|
|
1959
3004
|
import { basename, extname, join, resolve, sep } from "node:path";
|
|
1960
3005
|
import { fileURLToPath } from "node:url";
|
|
1961
|
-
import { Controller as
|
|
1962
|
-
function
|
|
3006
|
+
import { Controller as Controller3, Get as Get3, Header as Header3, Inject as Inject5, NotFoundException as NotFoundException3, Param as Param2, StreamableFile } from "@nestjs/common";
|
|
3007
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
1963
3008
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1964
3009
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1965
3010
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1972,21 +3017,20 @@ function _ts_decorate7(decorators, target, key, desc) {
|
|
|
1972
3017
|
}
|
|
1973
3018
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1974
3019
|
}
|
|
1975
|
-
__name(
|
|
1976
|
-
function
|
|
3020
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
3021
|
+
function _ts_metadata8(metadataKey, metadataValue) {
|
|
1977
3022
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1978
3023
|
return Reflect.metadata(metadataKey, metadataValue);
|
|
1979
3024
|
}
|
|
1980
3025
|
}
|
|
1981
|
-
__name(
|
|
1982
|
-
function
|
|
3026
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
3027
|
+
function _ts_param6(paramIndex, decorator) {
|
|
1983
3028
|
return function(target, key) {
|
|
1984
3029
|
decorator(target, key, paramIndex);
|
|
1985
3030
|
};
|
|
1986
3031
|
}
|
|
1987
|
-
__name(
|
|
1988
|
-
var
|
|
1989
|
-
var DASHBOARD_API_PATH = Symbol("DASHBOARD_API_PATH");
|
|
3032
|
+
__name(_ts_param6, "_ts_param");
|
|
3033
|
+
var DURABLE_DASHBOARD_CONFIG_ID = "durable-dashboard-config";
|
|
1990
3034
|
var BUILD_BASE = "/durable";
|
|
1991
3035
|
function spaDir() {
|
|
1992
3036
|
return fileURLToPath(new URL("../spa", import.meta.url));
|
|
@@ -2017,19 +3061,33 @@ var DurableUiControllerBase = class {
|
|
|
2017
3061
|
index() {
|
|
2018
3062
|
const indexPath = join(this.dir, "index.html");
|
|
2019
3063
|
if (!existsSync(indexPath)) {
|
|
2020
|
-
throw new
|
|
3064
|
+
throw new NotFoundException3("Dashboard is not built. Run the package build.");
|
|
2021
3065
|
}
|
|
2022
3066
|
const html = readFileSync(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
|
|
2023
|
-
const inject = `<script>window.__DURABLE_BASE__='${this.basePath}';window.__DURABLE_API__='${this.apiBasePath}';</script
|
|
3067
|
+
const inject = `<script>window.__DURABLE_BASE__='${this.basePath}';window.__DURABLE_API__='${this.apiBasePath}';</script>${this.configBlock()}`;
|
|
2024
3068
|
return html.includes("</head>") ? html.replace("</head>", `${inject}</head>`) : inject + html;
|
|
2025
3069
|
}
|
|
3070
|
+
/**
|
|
3071
|
+
* The page's JSON config block (`durable-dashboard-config`, CSP-safe: data, not script). It
|
|
3072
|
+
* carries `switcher` only when another Aviary console is registered.
|
|
3073
|
+
*/
|
|
3074
|
+
configBlock() {
|
|
3075
|
+
const switcher = consoleSwitcherConfig(DURABLE_CONSOLE_ID, `${this.apiBasePath}/consoles`);
|
|
3076
|
+
const json = JSON.stringify({
|
|
3077
|
+
apiBase: this.apiBasePath,
|
|
3078
|
+
...switcher !== void 0 ? {
|
|
3079
|
+
switcher
|
|
3080
|
+
} : {}
|
|
3081
|
+
}).replaceAll("<", "\\u003c");
|
|
3082
|
+
return `<script type="application/json" id="${DURABLE_DASHBOARD_CONFIG_ID}">${json}</script>`;
|
|
3083
|
+
}
|
|
2026
3084
|
asset(file) {
|
|
2027
3085
|
const safe = basename(file);
|
|
2028
|
-
if (safe !== file) throw new
|
|
3086
|
+
if (safe !== file) throw new NotFoundException3();
|
|
2029
3087
|
const root = resolve(this.dir, "assets");
|
|
2030
3088
|
const assetPath = resolve(root, safe);
|
|
2031
3089
|
if (!assetPath.startsWith(root + sep) || !existsSync(assetPath)) {
|
|
2032
|
-
throw new
|
|
3090
|
+
throw new NotFoundException3();
|
|
2033
3091
|
}
|
|
2034
3092
|
const type = CONTENT_TYPES[extname(safe)] ?? "application/octet-stream";
|
|
2035
3093
|
return new StreamableFile(readFileSync(assetPath), {
|
|
@@ -2037,31 +3095,31 @@ var DurableUiControllerBase = class {
|
|
|
2037
3095
|
});
|
|
2038
3096
|
}
|
|
2039
3097
|
};
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
3098
|
+
_ts_decorate9([
|
|
3099
|
+
Get3(),
|
|
3100
|
+
Header3("Content-Type", "text/html; charset=utf-8"),
|
|
3101
|
+
Header3("Cache-Control", "no-store, must-revalidate"),
|
|
3102
|
+
_ts_metadata8("design:type", Function),
|
|
3103
|
+
_ts_metadata8("design:paramtypes", []),
|
|
3104
|
+
_ts_metadata8("design:returntype", String)
|
|
2047
3105
|
], DurableUiControllerBase.prototype, "index", null);
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
3106
|
+
_ts_decorate9([
|
|
3107
|
+
Get3("assets/:file"),
|
|
3108
|
+
Header3("Cache-Control", "public, max-age=31536000, immutable"),
|
|
3109
|
+
_ts_param6(0, Param2("file")),
|
|
3110
|
+
_ts_metadata8("design:type", Function),
|
|
3111
|
+
_ts_metadata8("design:paramtypes", [
|
|
2054
3112
|
String
|
|
2055
3113
|
]),
|
|
2056
|
-
|
|
3114
|
+
_ts_metadata8("design:returntype", typeof StreamableFile === "undefined" ? Object : StreamableFile)
|
|
2057
3115
|
], DurableUiControllerBase.prototype, "asset", null);
|
|
2058
|
-
DurableUiControllerBase =
|
|
2059
|
-
|
|
3116
|
+
DurableUiControllerBase = _ts_decorate9([
|
|
3117
|
+
Controller3(),
|
|
2060
3118
|
ConsolePage(),
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
3119
|
+
_ts_param6(0, Inject5(DASHBOARD_BASE_PATH)),
|
|
3120
|
+
_ts_param6(1, Inject5(DASHBOARD_API_PATH)),
|
|
3121
|
+
_ts_metadata8("design:type", Function),
|
|
3122
|
+
_ts_metadata8("design:paramtypes", [
|
|
2065
3123
|
String,
|
|
2066
3124
|
String
|
|
2067
3125
|
])
|
|
@@ -2071,12 +3129,12 @@ var DurableUiController = class extends DurableUiControllerBase {
|
|
|
2071
3129
|
__name(this, "DurableUiController");
|
|
2072
3130
|
}
|
|
2073
3131
|
};
|
|
2074
|
-
DurableUiController =
|
|
2075
|
-
|
|
3132
|
+
DurableUiController = _ts_decorate9([
|
|
3133
|
+
Controller3()
|
|
2076
3134
|
], DurableUiController);
|
|
2077
3135
|
|
|
2078
3136
|
// src/server/durable-dashboard.module.ts
|
|
2079
|
-
function
|
|
3137
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
2080
3138
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2081
3139
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
2082
3140
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -2089,9 +3147,10 @@ function _ts_decorate8(decorators, target, key, desc) {
|
|
|
2089
3147
|
}
|
|
2090
3148
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2091
3149
|
}
|
|
2092
|
-
__name(
|
|
3150
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
2093
3151
|
markOpenToAuthorization(DurableApiController);
|
|
2094
3152
|
markOpenToAuthorization(DurableUiController);
|
|
3153
|
+
markOpenToAuthorization(DurableConsolesController);
|
|
2095
3154
|
function assertNothingToDecorate(options) {
|
|
2096
3155
|
if (options.decorators === void 0) return;
|
|
2097
3156
|
throw new Error([
|
|
@@ -2125,10 +3184,16 @@ var DurableApiModule = class _DurableApiModule {
|
|
|
2125
3184
|
...options.imports ?? []
|
|
2126
3185
|
],
|
|
2127
3186
|
controllers: routes ? [
|
|
2128
|
-
consoleController(DurableApiController, options.decorators)
|
|
3187
|
+
consoleController(DurableApiController, options.decorators),
|
|
3188
|
+
consoleController(DurableConsolesController, options.decorators)
|
|
2129
3189
|
] : [],
|
|
2130
3190
|
providers: [
|
|
2131
3191
|
DashboardService,
|
|
3192
|
+
{
|
|
3193
|
+
provide: DASHBOARD_DEV_TOOLS,
|
|
3194
|
+
useValue: options.devTools ?? routes
|
|
3195
|
+
},
|
|
3196
|
+
DurableDevToolsRegistration,
|
|
2132
3197
|
// Resolved at boot: a gate name without nestjs-authz, or a policy without
|
|
2133
3198
|
// @nestjs/authorization, fails here rather than on the first request.
|
|
2134
3199
|
{
|
|
@@ -2136,7 +3201,7 @@ var DurableApiModule = class _DurableApiModule {
|
|
|
2136
3201
|
// Also with `routes: false`: `@UseConsoleAuthorize()` still applies the production 403.
|
|
2137
3202
|
useFactory: /* @__PURE__ */ __name((moduleRef) => resolveConsoleAuthorize(options.authorize, moduleRef), "useFactory"),
|
|
2138
3203
|
inject: [
|
|
2139
|
-
|
|
3204
|
+
ModuleRef2
|
|
2140
3205
|
]
|
|
2141
3206
|
},
|
|
2142
3207
|
// `@dudousxd/nestjs-filter` is wired PRIVATELY here rather than through
|
|
@@ -2160,7 +3225,7 @@ var DurableApiModule = class _DurableApiModule {
|
|
|
2160
3225
|
validation: "off"
|
|
2161
3226
|
}, null), "useFactory"),
|
|
2162
3227
|
inject: [
|
|
2163
|
-
|
|
3228
|
+
ModuleRef2
|
|
2164
3229
|
]
|
|
2165
3230
|
},
|
|
2166
3231
|
ApplyFilterInterceptor2,
|
|
@@ -2186,7 +3251,7 @@ var DurableApiModule = class _DurableApiModule {
|
|
|
2186
3251
|
};
|
|
2187
3252
|
}
|
|
2188
3253
|
};
|
|
2189
|
-
DurableApiModule =
|
|
3254
|
+
DurableApiModule = _ts_decorate10([
|
|
2190
3255
|
Module({})
|
|
2191
3256
|
], DurableApiModule);
|
|
2192
3257
|
var DurableDashboardModule = class _DurableDashboardModule {
|
|
@@ -2215,6 +3280,9 @@ var DurableDashboardModule = class _DurableDashboardModule {
|
|
|
2215
3280
|
...options.authorize !== void 0 ? {
|
|
2216
3281
|
authorize: options.authorize
|
|
2217
3282
|
} : {},
|
|
3283
|
+
...options.devTools !== void 0 ? {
|
|
3284
|
+
devTools: options.devTools
|
|
3285
|
+
} : {},
|
|
2218
3286
|
routes: false
|
|
2219
3287
|
});
|
|
2220
3288
|
return {
|
|
@@ -2251,6 +3319,9 @@ var DurableDashboardModule = class _DurableDashboardModule {
|
|
|
2251
3319
|
} : {},
|
|
2252
3320
|
...options.authorize !== void 0 ? {
|
|
2253
3321
|
authorize: options.authorize
|
|
3322
|
+
} : {},
|
|
3323
|
+
...options.devTools !== void 0 ? {
|
|
3324
|
+
devTools: options.devTools
|
|
2254
3325
|
} : {}
|
|
2255
3326
|
}),
|
|
2256
3327
|
RouterModule.register([
|
|
@@ -2267,7 +3338,11 @@ var DurableDashboardModule = class _DurableDashboardModule {
|
|
|
2267
3338
|
controllers: [
|
|
2268
3339
|
consoleController(DurableUiController, options.decorators)
|
|
2269
3340
|
],
|
|
2270
|
-
|
|
3341
|
+
// The console switcher lists this console only where it serves its own page.
|
|
3342
|
+
providers: [
|
|
3343
|
+
...pathProviders,
|
|
3344
|
+
DurableConsoleRegistration
|
|
3345
|
+
],
|
|
2271
3346
|
// Re-export the API module so its DashboardService reaches importers (e.g. flip's own controllers).
|
|
2272
3347
|
exports: [
|
|
2273
3348
|
DurableApiModule
|
|
@@ -2275,30 +3350,45 @@ var DurableDashboardModule = class _DurableDashboardModule {
|
|
|
2275
3350
|
};
|
|
2276
3351
|
}
|
|
2277
3352
|
};
|
|
2278
|
-
DurableDashboardModule =
|
|
3353
|
+
DurableDashboardModule = _ts_decorate10([
|
|
2279
3354
|
Module({})
|
|
2280
3355
|
], DurableDashboardModule);
|
|
2281
3356
|
export {
|
|
3357
|
+
AVIARY_CONSOLES_SLOT,
|
|
2282
3358
|
CONSOLE_AUTHORIZE_DECIDE,
|
|
2283
3359
|
CONSOLE_AUTHORIZE_MISSING_WARNING,
|
|
2284
3360
|
CONSOLE_GATE,
|
|
2285
3361
|
CONSOLE_PAGE_METADATA,
|
|
3362
|
+
CONSOLE_PROBE_TIMEOUT_MS,
|
|
3363
|
+
CONSOLE_PUBLIC_METADATA,
|
|
2286
3364
|
ConsoleAccessDenied,
|
|
2287
3365
|
ConsoleAuthorizeFilter,
|
|
2288
3366
|
ConsoleAuthorizeGuard,
|
|
2289
3367
|
ConsolePage,
|
|
3368
|
+
ConsolePublic,
|
|
2290
3369
|
DASHBOARD_API_PATH,
|
|
2291
3370
|
DASHBOARD_BASE_PATH,
|
|
3371
|
+
DEV_TOOLS_SLOT,
|
|
3372
|
+
DURABLE_CONSOLE_ID,
|
|
3373
|
+
DURABLE_DASHBOARD_CONFIG_ID,
|
|
2292
3374
|
DashboardService,
|
|
2293
3375
|
DurableApiController,
|
|
2294
3376
|
DurableApiControllerBase,
|
|
2295
3377
|
DurableApiModule,
|
|
3378
|
+
DurableConsoleRegistration,
|
|
3379
|
+
DurableConsolesController,
|
|
2296
3380
|
DurableDashboardModule,
|
|
3381
|
+
DurableDevToolsRegistration,
|
|
2297
3382
|
DurableUiController,
|
|
2298
3383
|
DurableUiControllerBase,
|
|
3384
|
+
MAX_RUN_IDS,
|
|
2299
3385
|
UseConsoleAuthorize,
|
|
3386
|
+
anyAuthorize,
|
|
2300
3387
|
authorizeByToken,
|
|
3388
|
+
durableDevTools,
|
|
3389
|
+
listVisibleConsoles,
|
|
2301
3390
|
normalizeConsoleResult,
|
|
3391
|
+
registerAviaryConsole,
|
|
2302
3392
|
resolveConsoleAuthorize
|
|
2303
3393
|
};
|
|
2304
3394
|
//# sourceMappingURL=index.js.map
|