@dudousxd/nestjs-durable-dashboard 0.43.2 → 0.45.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.
@@ -140,6 +140,12 @@ var DashboardService = class {
140
140
  runFacets(query) {
141
141
  return this.gateway.runFacets(query);
142
142
  }
143
+ /** The distinct values of one filter axis over the same predicates — what fills the console's
144
+ * tenant/tag/attribute pickers, so an operator picks a value that exists instead of typing one
145
+ * blind. `[]` when the store cannot enumerate them; the pickers then fall back to free text. */
146
+ runValueFacets(axis, query, opts) {
147
+ return this.gateway.runValueFacets(axis, query, opts);
148
+ }
143
149
  /** This deployment's durable role (control plane vs tenant) + tenant name — for the dashboard header
144
150
  * badge. Routes through the gateway, which knows its own topology (store-backed = operator, proxy =
145
151
  * tenant). Works on both topologies (no store/engine needed). */
@@ -248,10 +254,95 @@ DashboardService = _ts_decorate([
248
254
  ], DashboardService);
249
255
 
250
256
  // src/server/durable-api.controller.ts
251
- var import_common2 = require("@nestjs/common");
257
+ var import_nestjs_filter2 = require("@dudousxd/nestjs-filter");
258
+ var import_common4 = require("@nestjs/common");
259
+
260
+ // src/server/durable-run.ts
261
+ var DurableRun = class {
262
+ static {
263
+ __name(this, "DurableRun");
264
+ }
265
+ workflow;
266
+ status;
267
+ /** `null` for a run no package claims — see `WorkflowRun.origin`. */
268
+ origin;
269
+ /** Tenant / worker-pool partition. */
270
+ namespace;
271
+ /**
272
+ * ONE of the run's tags. Singular deliberately: a run carries a SET of tags, so a predicate here
273
+ * asks about membership (`tag in [etl, nightly]` = runs carrying either), never equality with the
274
+ * whole set.
275
+ */
276
+ tag;
277
+ /** Typed search attributes, addressed per key as `attr.<key>` — a JSON sub-path, not a column. */
278
+ attr;
279
+ };
280
+ var ATTRIBUTE_FIELD = "attr";
281
+ var DURABLE_RUN_FIELDS = [
282
+ {
283
+ name: "workflow",
284
+ columnName: "workflow",
285
+ type: "string"
286
+ },
287
+ {
288
+ name: "status",
289
+ columnName: "status",
290
+ type: "string"
291
+ },
292
+ {
293
+ name: "origin",
294
+ columnName: "origin",
295
+ type: "string"
296
+ },
297
+ {
298
+ name: "namespace",
299
+ columnName: "namespace",
300
+ type: "string"
301
+ },
302
+ {
303
+ name: "tag",
304
+ columnName: "tags",
305
+ type: "string"
306
+ },
307
+ {
308
+ name: ATTRIBUTE_FIELD,
309
+ columnName: "search_attributes",
310
+ type: "json"
311
+ }
312
+ ];
313
+ function runValueAxisFor(field) {
314
+ if (field === ATTRIBUTE_FIELD) return {
315
+ field: "attributeKey"
316
+ };
317
+ if (field.startsWith(`${ATTRIBUTE_FIELD}.`)) {
318
+ const key = field.slice(ATTRIBUTE_FIELD.length + 1);
319
+ return key ? {
320
+ field: "attributeValue",
321
+ key
322
+ } : null;
323
+ }
324
+ if (field === "workflow" || field === "status" || field === "origin" || field === "namespace" || field === "tag") {
325
+ return {
326
+ field
327
+ };
328
+ }
329
+ return null;
330
+ }
331
+ __name(runValueAxisFor, "runValueAxisFor");
332
+
333
+ // src/server/run-list-row.ts
334
+ function toRunListRow(run) {
335
+ const { input: _input, output: _output, error: _error, ...row } = run;
336
+ return row;
337
+ }
338
+ __name(toRunListRow, "toRunListRow");
339
+
340
+ // src/server/run.filter.ts
341
+ var import_nestjs_filter = require("@dudousxd/nestjs-filter");
342
+ var import_common3 = require("@nestjs/common");
252
343
 
253
344
  // src/server/attr-filter.ts
254
- var ATTR_OPS = /* @__PURE__ */ new Set([
345
+ var SCALAR_OPS = /* @__PURE__ */ new Set([
255
346
  "eq",
256
347
  "ne",
257
348
  "gt",
@@ -259,6 +350,7 @@ var ATTR_OPS = /* @__PURE__ */ new Set([
259
350
  "lt",
260
351
  "lte"
261
352
  ]);
353
+ var IN_SEPARATOR = "|";
262
354
  function coerce(v) {
263
355
  if (v === "true") return true;
264
356
  if (v === "false") return false;
@@ -274,25 +366,60 @@ function parseAttrFilters(attr) {
274
366
  const filters = [];
275
367
  for (const entry of raw) {
276
368
  const [key, op, ...rest] = entry.split(":");
277
- if (!key || !ATTR_OPS.has(op) || rest.length === 0) continue;
369
+ if (!key || rest.length === 0) continue;
370
+ const operand = rest.join(":");
371
+ if (op === "in") {
372
+ const values = operand.split(IN_SEPARATOR).filter(Boolean).map(coerce);
373
+ if (values.length) filters.push({
374
+ key,
375
+ op: "in",
376
+ values
377
+ });
378
+ continue;
379
+ }
380
+ if (!SCALAR_OPS.has(op)) continue;
278
381
  filters.push({
279
382
  key,
280
383
  op,
281
- value: coerce(rest.join(":"))
384
+ value: coerce(operand)
282
385
  });
283
386
  }
284
387
  return filters.length ? filters : void 0;
285
388
  }
286
389
  __name(parseAttrFilters, "parseAttrFilters");
287
390
 
288
- // src/server/run-list-row.ts
289
- function toRunListRow(run) {
290
- const { input: _input, output: _output, error: _error, ...row } = run;
291
- return row;
292
- }
293
- __name(toRunListRow, "toRunListRow");
391
+ // src/server/run-query.adapter.ts
392
+ var import_nestjs_durable_core2 = require("@dudousxd/nestjs-durable-core");
393
+ var import_common2 = require("@nestjs/common");
294
394
 
295
- // src/server/durable-api.controller.ts
395
+ // src/server/run-query-draft.ts
396
+ var RunQueryDraft2 = class {
397
+ static {
398
+ __name(this, "RunQueryDraft");
399
+ }
400
+ query = {};
401
+ /** Narrow by one or more predicates. Later calls overwrite the same field — the runner applies one
402
+ * clause per field, so the last one wins, exactly as a repeated `where` on a builder would. */
403
+ narrow(patch) {
404
+ Object.assign(this.query, patch);
405
+ }
406
+ /** Add one search-attribute predicate. These ACCUMULATE (unlike {@link narrow}) because
407
+ * `RunQuery.attributes` is an ANDed list — two predicates on different keys are both meant. */
408
+ attribute(filter) {
409
+ this.query.attributes = [
410
+ ...this.query.attributes ?? [],
411
+ filter
412
+ ];
413
+ }
414
+ /** The predicates minus the page window and the axes a facet count reports on — what
415
+ * `runFacets`/`runValueFacets` are taken over. */
416
+ facetQuery() {
417
+ const { status, statuses, origin, origins, limit, offset, ...facetQuery } = this.query;
418
+ return facetQuery;
419
+ }
420
+ };
421
+
422
+ // src/server/run-query.adapter.ts
296
423
  function _ts_decorate2(decorators, target, key, desc) {
297
424
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
298
425
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -304,73 +431,527 @@ function _ts_metadata2(k, v) {
304
431
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
305
432
  }
306
433
  __name(_ts_metadata2, "_ts_metadata");
434
+ var RUN_QUERY_ADAPTER = Symbol("DURABLE_RUN_QUERY_ADAPTER");
435
+ var FIXED_ORDER = {
436
+ field: "createdAt",
437
+ direction: "desc"
438
+ };
439
+ function coerce2(value) {
440
+ if (typeof value === "number" || typeof value === "boolean") return value;
441
+ const raw = String(value);
442
+ if (raw === "true") return true;
443
+ if (raw === "false") return false;
444
+ if (raw !== "" && !Number.isNaN(Number(raw))) return Number(raw);
445
+ return raw;
446
+ }
447
+ __name(coerce2, "coerce");
448
+ function operands(clause) {
449
+ return Array.isArray(clause.value) ? clause.value : [
450
+ clause.value
451
+ ];
452
+ }
453
+ __name(operands, "operands");
454
+ function unsupported(clause, supported) {
455
+ throw new import_common2.BadRequestException(`The durable run list cannot filter \`${clause.field}\` with \`${clause.operator}\`. Supported here: ${supported}.`);
456
+ }
457
+ __name(unsupported, "unsupported");
458
+ var RunQueryAdapter = class {
459
+ static {
460
+ __name(this, "RunQueryAdapter");
461
+ }
462
+ gateway;
463
+ constructor(gateway) {
464
+ this.gateway = gateway;
465
+ }
466
+ createQueryBuilder(entity) {
467
+ this.assertDurableRun(entity);
468
+ return new RunQueryDraft2();
469
+ }
470
+ getEntityFields(entity) {
471
+ return entity === DurableRun ? DURABLE_RUN_FIELDS : null;
472
+ }
473
+ /** No relations: a run is a flat row here, and the one nested-looking address (`attr.<key>`) is a
474
+ * JSON path. Returning `[]` (not null) tells the runner the answer is "none", not "can't say". */
475
+ getEntityRelations() {
476
+ return [];
477
+ }
478
+ /**
479
+ * Which addresses resolve, and as what. `attr` and `attr.<key>` are JSON paths — that classification
480
+ * is what routes a flat `?attr.tier=pro` through the same translation as a structured
481
+ * `where[attr.tier]`, instead of it being dropped as an unknown key.
482
+ */
483
+ resolveFieldPath(entity, path) {
484
+ if (entity !== DurableRun) return null;
485
+ if (path === ATTRIBUTE_FIELD || path.startsWith(`${ATTRIBUTE_FIELD}.`)) return "json";
486
+ return DURABLE_RUN_FIELDS.some((f) => f.name === path) ? "field" : null;
487
+ }
488
+ applyColumnFilters(qb, filters, entity) {
489
+ if (entity) this.assertDurableRun(entity);
490
+ const draft = this.draft(qb);
491
+ for (const clause of filters) {
492
+ if (clause.AND || clause.OR) {
493
+ throw new import_common2.BadRequestException("The durable run list cannot filter with nested AND/OR groups: its predicates are a flat conjunction.");
494
+ }
495
+ this.applyClause(draft, clause);
496
+ }
497
+ }
498
+ applyClause(draft, clause) {
499
+ const { field, operator } = clause;
500
+ if (field === ATTRIBUTE_FIELD || field.startsWith(`${ATTRIBUTE_FIELD}.`)) {
501
+ this.applyAttributeClause(draft, clause);
502
+ return;
503
+ }
504
+ const anyOf = operator === "in" || operator === "isAnyOf";
505
+ switch (field) {
506
+ case "status":
507
+ if (operator === "equals") {
508
+ draft.narrow({
509
+ status: String(clause.value)
510
+ });
511
+ } else if (anyOf) {
512
+ draft.narrow({
513
+ statuses: operands(clause).map((v) => String(v))
514
+ });
515
+ } else {
516
+ unsupported(clause, "equals, in");
517
+ }
518
+ return;
519
+ case "workflow":
520
+ if (operator === "equals") {
521
+ draft.narrow({
522
+ workflow: String(clause.value)
523
+ });
524
+ } else if (anyOf) {
525
+ draft.narrow({
526
+ workflows: operands(clause).map(String)
527
+ });
528
+ } else {
529
+ unsupported(clause, "equals, in");
530
+ }
531
+ return;
532
+ case "namespace":
533
+ if (operator === "equals") {
534
+ draft.narrow({
535
+ namespace: String(clause.value)
536
+ });
537
+ } else if (anyOf) {
538
+ draft.narrow({
539
+ namespaces: operands(clause).map(String)
540
+ });
541
+ } else {
542
+ unsupported(clause, "equals, in");
543
+ }
544
+ return;
545
+ case "tag":
546
+ if (operator === "equals") {
547
+ draft.narrow({
548
+ tag: String(clause.value)
549
+ });
550
+ } else if (anyOf) {
551
+ draft.narrow({
552
+ tags: operands(clause).map(String)
553
+ });
554
+ } else {
555
+ unsupported(clause, "equals, in");
556
+ }
557
+ return;
558
+ case "origin":
559
+ if (operator === "isNull") {
560
+ draft.narrow({
561
+ origin: null
562
+ });
563
+ } else if (operator === "equals") {
564
+ draft.narrow({
565
+ origin: clause.value === null ? null : String(clause.value)
566
+ });
567
+ } else if (anyOf) {
568
+ draft.narrow({
569
+ origins: operands(clause).map((v) => v === null ? null : String(v))
570
+ });
571
+ } else {
572
+ unsupported(clause, "equals, in, isNull");
573
+ }
574
+ return;
575
+ default:
576
+ unsupported(clause, `one of ${DURABLE_RUN_FIELDS.map((f) => f.name).join(", ")}`);
577
+ }
578
+ }
579
+ /** `attr.<key>` → one {@link AttributeFilter}. The operator set is the store's, so the mapping is
580
+ * 1:1 and anything outside it is rejected rather than approximated. */
581
+ applyAttributeClause(draft, clause) {
582
+ const key = clause.field.slice(ATTRIBUTE_FIELD.length + 1);
583
+ if (!key) {
584
+ throw new import_common2.BadRequestException("Filtering search attributes needs a key: `attr.<key>`, e.g. `attr.tier`.");
585
+ }
586
+ const scalarOps = {
587
+ equals: "eq",
588
+ notEquals: "ne",
589
+ gt: "gt",
590
+ gte: "gte",
591
+ lt: "lt",
592
+ lte: "lte"
593
+ };
594
+ const scalar = scalarOps[clause.operator];
595
+ if (scalar) {
596
+ draft.attribute({
597
+ key,
598
+ op: scalar,
599
+ value: coerce2(clause.value)
600
+ });
601
+ return;
602
+ }
603
+ if (clause.operator === "in" || clause.operator === "isAnyOf") {
604
+ draft.attribute({
605
+ key,
606
+ op: "in",
607
+ values: operands(clause).map(coerce2)
608
+ });
609
+ return;
610
+ }
611
+ unsupported(clause, "equals, notEquals, gt, gte, lt, lte, in");
612
+ }
613
+ applyOffsetPagination(qb, page2, size) {
614
+ this.draft(qb).narrow({
615
+ limit: size,
616
+ offset: (page2 - 1) * size
617
+ });
618
+ }
619
+ /**
620
+ * A run listing has ONE order — newest first — because that is what every store adapter's
621
+ * `listRuns` emits and what the console's paging depends on. A request for any other sort is
622
+ * refused rather than accepted and ignored: silently returning a differently-ordered page is how a
623
+ * paginated list starts duplicating and skipping rows.
624
+ */
625
+ applySort(_qb, sorts) {
626
+ for (const sort of sorts) {
627
+ if (sort.field !== FIXED_ORDER.field || sort.direction !== FIXED_ORDER.direction) {
628
+ throw new import_common2.BadRequestException(`The durable run list is always ordered \`${FIXED_ORDER.field} ${FIXED_ORDER.direction}\` and cannot be sorted by \`${sort.field} ${sort.direction}\`.`);
629
+ }
630
+ }
631
+ }
632
+ getResult(qb) {
633
+ return this.gateway.listRuns(this.draft(qb).query);
634
+ }
635
+ /**
636
+ * A page plus the size of the whole matching set. The total comes from the facet aggregate rather
637
+ * than from a second listing — that is the entire reason durable exposes one, and it keeps the
638
+ * count exact while the page stays bounded.
639
+ */
640
+ async getResultAndCount(qb) {
641
+ const draft = this.draft(qb);
642
+ const [rows, facets] = await Promise.all([
643
+ this.gateway.listRuns(draft.query),
644
+ this.gateway.runFacets(draft.facetQuery())
645
+ ]);
646
+ const { status, statuses, origin, origins } = draft.query;
647
+ const total = facets.filter((cell) => {
648
+ if (status && cell.status !== status) return false;
649
+ if (statuses && !statuses.includes(cell.status)) return false;
650
+ if (origin !== void 0 && cell.origin !== origin) return false;
651
+ if (origins && !origins.includes(cell.origin)) return false;
652
+ return true;
653
+ }).reduce((sum, cell) => sum + cell.count, 0);
654
+ return {
655
+ rows,
656
+ total
657
+ };
658
+ }
659
+ /**
660
+ * The distinct values of one field over the runs the active predicates select — the console's
661
+ * pickers. `limit` is honoured because it has to be: tag and search-attribute cardinality grows
662
+ * with the data, so the unbounded answer is a listing rather than an aggregate.
663
+ */
664
+ async groupByCount(qb, field, entity, opts) {
665
+ this.assertDurableRun(entity);
666
+ if (typeof field !== "string") {
667
+ throw new import_common2.BadRequestException("The durable run list has no computed fields to group by \u2014 group by one of its own fields.");
668
+ }
669
+ if (opts?.bucket !== void 0) {
670
+ throw new import_common2.BadRequestException("The durable run list cannot bucket a group-by-count: none of its filterable fields is numeric.");
671
+ }
672
+ const axis = runValueAxisFor(field);
673
+ if (!axis) {
674
+ throw new import_common2.BadRequestException(`The durable run list cannot enumerate values of \`${field}\`.`);
675
+ }
676
+ const rows = await this.gateway.runValueFacets(axis, this.draft(qb).facetQuery(), {
677
+ limit: opts?.limit ?? import_nestjs_durable_core2.RUN_VALUE_FACET_LIMIT
678
+ });
679
+ return rows.map((row) => ({
680
+ value: row.value,
681
+ count: row.count
682
+ }));
683
+ }
684
+ getPrimaryKey() {
685
+ return "id";
686
+ }
687
+ draft(qb) {
688
+ if (!(qb instanceof RunQueryDraft2)) {
689
+ throw new Error("The durable run adapter was handed a query builder it did not create. A filter using it must declare `@Filterable({ entity: DurableRun, adapter: RUN_QUERY_ADAPTER })`.");
690
+ }
691
+ return qb;
692
+ }
693
+ assertDurableRun(entity) {
694
+ if (entity !== DurableRun) {
695
+ throw new Error(`The durable run adapter only answers for DurableRun, not ${entity?.name ?? String(entity)}.`);
696
+ }
697
+ }
698
+ };
699
+ RunQueryAdapter = _ts_decorate2([
700
+ (0, import_common2.Injectable)(),
701
+ _ts_metadata2("design:type", Function),
702
+ _ts_metadata2("design:paramtypes", [
703
+ typeof import_nestjs_durable_core2.RunGateway === "undefined" ? Object : import_nestjs_durable_core2.RunGateway
704
+ ])
705
+ ], RunQueryAdapter);
706
+
707
+ // src/server/run.filter.ts
708
+ function _ts_decorate3(decorators, target, key, desc) {
709
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
710
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
711
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
712
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
713
+ }
714
+ __name(_ts_decorate3, "_ts_decorate");
715
+ function _ts_metadata3(k, v) {
716
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
717
+ }
718
+ __name(_ts_metadata3, "_ts_metadata");
719
+ function list(value) {
720
+ return (Array.isArray(value) ? value : [
721
+ value
722
+ ]).filter((v) => v !== void 0 && v !== null && v !== "").map(String);
723
+ }
724
+ __name(list, "list");
725
+ function bound(value) {
726
+ const n = Number(value);
727
+ return value !== void 0 && value !== "" && Number.isInteger(n) && n >= 0 ? n : void 0;
728
+ }
729
+ __name(bound, "bound");
730
+ var RunFilter = class extends import_nestjs_filter.BaseFilter {
731
+ static {
732
+ __name(this, "RunFilter");
733
+ }
734
+ /** One status narrows; several match ANY of them — how a caller asks for a SET (the console's
735
+ * in-flight sibling query, for one). */
736
+ applyStatus(value) {
737
+ const values = list(value);
738
+ if (values.length === 0) return;
739
+ this.$query.narrow(values.length === 1 ? {
740
+ status: values[0]
741
+ } : {
742
+ statuses: values
743
+ });
744
+ }
745
+ applyWorkflow(value) {
746
+ const values = list(value);
747
+ if (values.length === 0) return;
748
+ this.$query.narrow(values.length === 1 ? {
749
+ workflow: values[0]
750
+ } : {
751
+ workflows: values
752
+ });
753
+ }
754
+ /** A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
755
+ * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console. */
756
+ applyNamespace(value) {
757
+ const values = list(value);
758
+ if (values.length === 0) return;
759
+ this.$query.narrow(values.length === 1 ? {
760
+ namespace: values[0]
761
+ } : {
762
+ namespaces: values
763
+ });
764
+ }
765
+ applyTag(value) {
766
+ const values = list(value);
767
+ if (values.length === 0) return;
768
+ this.$query.narrow(values.length === 1 ? {
769
+ tag: values[0]
770
+ } : {
771
+ tags: values
772
+ });
773
+ }
774
+ /**
775
+ * Origin has THREE states rather than two — a named package, the unattributed bucket, or no
776
+ * restriction — and the bucket rides on its own `unattributed` param rather than on a reserved
777
+ * `origin` value, because any reserved string is a package name someone can legitimately have and a
778
+ * console that quietly reinterpreted it would show the wrong runs.
779
+ *
780
+ * Both keys resolve through one function, called from either, reading the RAW input each time:
781
+ * the answer depends on both params, and `@FilterFor` dispatch follows the order the client's keys
782
+ * happen to arrive in. Recomputing from the input makes the result the same either way, where
783
+ * accumulating onto the draft would make `?origin=x&unattributed=true` mean different things
784
+ * depending on key order.
785
+ *
786
+ * Sent together they are a UNION, not a contradiction: `origins` carries the absent bucket
787
+ * alongside named packages, which is the "this package plus the runs nothing claims" view that a
788
+ * single `origin` value cannot express at all.
789
+ */
790
+ applyOrigin() {
791
+ this.resolveOrigin();
792
+ }
793
+ applyUnattributed() {
794
+ this.resolveOrigin();
795
+ }
796
+ resolveOrigin() {
797
+ const named = list(this.$input.origin);
798
+ const raw = this.$input.unattributed;
799
+ const wantsUnattributed = raw === "true" || raw === "1" || raw === true;
800
+ const values = [
801
+ ...named,
802
+ ...wantsUnattributed ? [
803
+ null
804
+ ] : []
805
+ ];
806
+ if (values.length === 0) return;
807
+ if (values.length === 1) {
808
+ const only = values[0];
809
+ this.$query.narrow({
810
+ origin: only
811
+ });
812
+ return;
813
+ }
814
+ this.$query.narrow({
815
+ origins: values
816
+ });
817
+ }
818
+ /** Comma/repeat-separated `key:op:value` predicates (e.g. `amount:gte:200`), ANDed. The structured
819
+ * spelling of the same thing is `filter[where][attr.amount][gte]=200`. */
820
+ applyAttributes(value) {
821
+ for (const filter of parseAttrFilters(value) ?? []) {
822
+ this.$query.attribute(filter);
823
+ }
824
+ }
825
+ applyLimit(value) {
826
+ const limit = bound(value);
827
+ if (limit !== void 0) this.$query.narrow({
828
+ limit
829
+ });
830
+ }
831
+ applyOffset(value) {
832
+ const offset = bound(value);
833
+ if (offset !== void 0) this.$query.narrow({
834
+ offset
835
+ });
836
+ }
837
+ };
838
+ _ts_decorate3([
839
+ (0, import_nestjs_filter.FilterFor)("status"),
840
+ _ts_metadata3("design:type", Function),
841
+ _ts_metadata3("design:paramtypes", [
842
+ Object
843
+ ]),
844
+ _ts_metadata3("design:returntype", void 0)
845
+ ], RunFilter.prototype, "applyStatus", null);
846
+ _ts_decorate3([
847
+ (0, import_nestjs_filter.FilterFor)("workflow"),
848
+ _ts_metadata3("design:type", Function),
849
+ _ts_metadata3("design:paramtypes", [
850
+ Object
851
+ ]),
852
+ _ts_metadata3("design:returntype", void 0)
853
+ ], RunFilter.prototype, "applyWorkflow", null);
854
+ _ts_decorate3([
855
+ (0, import_nestjs_filter.FilterFor)("namespace"),
856
+ _ts_metadata3("design:type", Function),
857
+ _ts_metadata3("design:paramtypes", [
858
+ Object
859
+ ]),
860
+ _ts_metadata3("design:returntype", void 0)
861
+ ], RunFilter.prototype, "applyNamespace", null);
862
+ _ts_decorate3([
863
+ (0, import_nestjs_filter.FilterFor)("tag"),
864
+ _ts_metadata3("design:type", Function),
865
+ _ts_metadata3("design:paramtypes", [
866
+ Object
867
+ ]),
868
+ _ts_metadata3("design:returntype", void 0)
869
+ ], RunFilter.prototype, "applyTag", null);
870
+ _ts_decorate3([
871
+ (0, import_nestjs_filter.FilterFor)("origin"),
872
+ _ts_metadata3("design:type", Function),
873
+ _ts_metadata3("design:paramtypes", []),
874
+ _ts_metadata3("design:returntype", void 0)
875
+ ], RunFilter.prototype, "applyOrigin", null);
876
+ _ts_decorate3([
877
+ (0, import_nestjs_filter.FilterFor)("unattributed"),
878
+ _ts_metadata3("design:type", Function),
879
+ _ts_metadata3("design:paramtypes", []),
880
+ _ts_metadata3("design:returntype", void 0)
881
+ ], RunFilter.prototype, "applyUnattributed", null);
882
+ _ts_decorate3([
883
+ (0, import_nestjs_filter.FilterFor)("attr"),
884
+ _ts_metadata3("design:type", Function),
885
+ _ts_metadata3("design:paramtypes", [
886
+ Object
887
+ ]),
888
+ _ts_metadata3("design:returntype", void 0)
889
+ ], RunFilter.prototype, "applyAttributes", null);
890
+ _ts_decorate3([
891
+ (0, import_nestjs_filter.FilterFor)("limit"),
892
+ _ts_metadata3("design:type", Function),
893
+ _ts_metadata3("design:paramtypes", [
894
+ Object
895
+ ]),
896
+ _ts_metadata3("design:returntype", void 0)
897
+ ], RunFilter.prototype, "applyLimit", null);
898
+ _ts_decorate3([
899
+ (0, import_nestjs_filter.FilterFor)("offset"),
900
+ _ts_metadata3("design:type", Function),
901
+ _ts_metadata3("design:paramtypes", [
902
+ Object
903
+ ]),
904
+ _ts_metadata3("design:returntype", void 0)
905
+ ], RunFilter.prototype, "applyOffset", null);
906
+ RunFilter = _ts_decorate3([
907
+ (0, import_common3.Injectable)(),
908
+ (0, import_nestjs_filter.Filterable)({
909
+ entity: DurableRun,
910
+ adapter: RUN_QUERY_ADAPTER,
911
+ autoFields: false
912
+ })
913
+ ], RunFilter);
914
+
915
+ // src/server/durable-api.controller.ts
916
+ function _ts_decorate4(decorators, target, key, desc) {
917
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
918
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
919
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
920
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
921
+ }
922
+ __name(_ts_decorate4, "_ts_decorate");
923
+ function _ts_metadata4(k, v) {
924
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
925
+ }
926
+ __name(_ts_metadata4, "_ts_metadata");
307
927
  function _ts_param2(paramIndex, decorator) {
308
928
  return function(target, key) {
309
929
  decorator(target, key, paramIndex);
310
930
  };
311
931
  }
312
932
  __name(_ts_param2, "_ts_param");
313
- function pageBounds(limit, offset) {
314
- const bound = /* @__PURE__ */ __name((raw) => {
315
- const n = Number(raw);
316
- return raw !== void 0 && raw !== "" && Number.isInteger(n) && n >= 0 ? n : void 0;
317
- }, "bound");
318
- const l = bound(limit);
319
- const o = bound(offset);
320
- return {
321
- ...l !== void 0 ? {
322
- limit: l
323
- } : {},
324
- ...o !== void 0 ? {
325
- offset: o
326
- } : {}
327
- };
328
- }
329
- __name(pageBounds, "pageBounds");
330
- function statusPredicate(status) {
331
- if (Array.isArray(status)) return status.length ? {
332
- statuses: status
333
- } : {};
334
- return status ? {
335
- status
336
- } : {};
337
- }
338
- __name(statusPredicate, "statusPredicate");
339
- function originPredicate(origin, unattributed) {
340
- if (unattributed === "true" || unattributed === "1") return {
341
- origin: null
342
- };
343
- return origin ? {
344
- origin
345
- } : {};
346
- }
347
- __name(originPredicate, "originPredicate");
348
933
  var DurableApiController = class {
349
934
  static {
350
935
  __name(this, "DurableApiController");
351
936
  }
352
937
  dashboard;
353
- constructor(dashboard) {
938
+ runner;
939
+ constructor(dashboard, runner) {
354
940
  this.dashboard = dashboard;
941
+ this.runner = runner;
355
942
  }
356
943
  /**
357
- * The run list, filtered by whatever the operator asked for. Every predicate is OPTIONAL and an
358
- * omitted one means "don't narrow on this axis" — in particular `namespace`, whose absence keeps
359
- * the historical, deliberate behaviour that read paths are NOT namespace-scoped (core,
360
- * `WorkflowRun.namespace`): the console shows every tenant's runs until an operator chooses one.
361
- * A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
362
- * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console.
944
+ * The run list, filtered by whatever the operator asked for.
945
+ *
946
+ * The predicates are parsed, validated and translated by `@dudousxd/nestjs-filter` (see
947
+ * `RunFilter` for the two spellings it accepts, and `RunQueryAdapter` for how they become a
948
+ * `RunQuery`). Every predicate is OPTIONAL and an omitted one means "don't narrow on this axis" —
949
+ * in particular `namespace`, whose absence keeps the historical, deliberate behaviour that read
950
+ * paths are NOT namespace-scoped (core, `WorkflowRun.namespace`): the console shows every tenant's
951
+ * runs until an operator chooses one.
363
952
  */
364
- async runs(status, workflow, tag, attr, namespace, origin, unattributed, limit, offset) {
365
- const runs = await this.dashboard.listRuns({
366
- ...statusPredicate(status),
367
- workflow,
368
- tag,
369
- attributes: parseAttrFilters(attr),
370
- namespace: namespace || void 0,
371
- ...originPredicate(origin, unattributed),
372
- ...pageBounds(limit, offset)
373
- });
953
+ async runs(draft) {
954
+ const runs = await this.dashboard.listRuns(draft.query);
374
955
  return runs.map(toRunListRow);
375
956
  }
376
957
  /**
@@ -378,15 +959,28 @@ var DurableApiController = class {
378
959
  * `GET runs`. This is what lets that listing be PAGED at all: the page bounds what the console
379
960
  * renders, this bounds nothing and keeps its status and origin chips exact.
380
961
  *
381
- * `status`, `origin` and the page bounds are deliberately NOT accepted — they are the axes being
382
- * counted, so narrowing by them would report the answer back to itself.
962
+ * `status`, `origin` and the page bounds are accepted (the route takes the same filter) but
963
+ * deliberately DROPPED before counting — they are the axes being counted, so narrowing by them
964
+ * would report the answer back to itself.
965
+ */
966
+ facets(draft) {
967
+ return this.dashboard.runFacets(draft.facetQuery());
968
+ }
969
+ /**
970
+ * The distinct values one filter field takes across the runs matching every OTHER active
971
+ * predicate, with counts — what the console's tenant/tag/attribute pickers list.
972
+ *
973
+ * `?groupByCount[field]=tag&groupByCount[limit]=20`, with the filters in the structured
974
+ * `filter[where][...]` form (what `filterQuery()` builds). Scoping the values to the active
975
+ * filters is the point: picking a tenant leaves the tag picker offering only that tenant's tags,
976
+ * so a picker never offers a value whose result set is empty.
977
+ *
978
+ * `limit` matters rather than being a nicety — tag and attribute cardinality grows with the data
979
+ * (a `singleton:<key>` tag is minted per key), so the unbounded answer is a listing.
383
980
  */
384
- facets(workflow, tag, attr, namespace) {
385
- return this.dashboard.runFacets({
386
- workflow,
387
- tag,
388
- attributes: parseAttrFilters(attr),
389
- namespace: namespace || void 0
981
+ values(query) {
982
+ return this.runner.groupByCount(DurableRun, query, {
983
+ filterClass: RunFilter
390
984
  });
391
985
  }
392
986
  /** Prometheus-text metrics (runs/steps by outcome, per-workflow counts) for a scrape. */
@@ -403,7 +997,7 @@ var DurableApiController = class {
403
997
  }
404
998
  async run(id) {
405
999
  const detail = await this.dashboard.getRunDetail(id);
406
- if (!detail) throw new import_common2.NotFoundException(`run ${id} not found`);
1000
+ if (!detail) throw new import_common4.NotFoundException(`run ${id} not found`);
407
1001
  return detail;
408
1002
  }
409
1003
  /** Server-Sent Events stream of a run's live lifecycle events — the dashboard tails it instead
@@ -423,18 +1017,9 @@ var DurableApiController = class {
423
1017
  * The filter takes the SAME params as `GET runs` and is parsed identically, so "retry all" acts on
424
1018
  * exactly the set the operator was looking at rather than a wider one.
425
1019
  */
426
- bulk(action, status, tag, workflow, attr, compensate, namespace, origin, unattributed) {
427
- return this.dashboard.bulk(action === "cancel" ? "cancel" : "retry", {
428
- status,
429
- tag,
430
- workflow,
431
- attributes: parseAttrFilters(attr),
432
- namespace: namespace || void 0,
433
- // The unattributed bucket is a scope a console can actually SELECT, so a bulk action launched
434
- // under it must be narrowed to it. Dropping the param would widen a retry/cancel to every
435
- // origin — acting on runs the operator was not looking at.
436
- ...originPredicate(origin, unattributed)
437
- }, {
1020
+ bulk(action, draft, compensate) {
1021
+ const { limit, offset, ...filter } = draft.query;
1022
+ return this.dashboard.bulk(action === "cancel" ? "cancel" : "retry", filter, {
438
1023
  compensate: compensate === "true"
439
1024
  });
440
1025
  }
@@ -442,18 +1027,18 @@ var DurableApiController = class {
442
1027
  const result = await this.dashboard.cancel(id, {
443
1028
  compensate: compensate === "true"
444
1029
  });
445
- if (!result) throw new import_common2.NotFoundException(`run ${id} not found`);
1030
+ if (!result) throw new import_common4.NotFoundException(`run ${id} not found`);
446
1031
  return result;
447
1032
  }
448
1033
  async continue(id) {
449
1034
  const result = await this.dashboard.continue(id);
450
- if (!result) throw new import_common2.NotFoundException(`run ${id} is not paused at a breakpoint`);
1035
+ if (!result) throw new import_common4.NotFoundException(`run ${id} is not paused at a breakpoint`);
451
1036
  return result;
452
1037
  }
453
1038
  /** Re-dispatch a run's stuck `pending` remote steps — recovery for a lost step dispatch. */
454
1039
  async redispatch(id) {
455
1040
  const result = await this.dashboard.redispatch(id);
456
- if (!result) throw new import_common2.NotFoundException(`run ${id} not found`);
1041
+ if (!result) throw new import_common4.NotFoundException(`run ${id} not found`);
457
1042
  return result;
458
1043
  }
459
1044
  /**
@@ -464,7 +1049,7 @@ var DurableApiController = class {
464
1049
  */
465
1050
  async webhook(token, body) {
466
1051
  const result = await this.dashboard.deliverWebhook(token, body);
467
- if (!result) throw new import_common2.NotFoundException(`no run is waiting on webhook ${token}`);
1052
+ if (!result) throw new import_common4.NotFoundException(`no run is waiting on webhook ${token}`);
468
1053
  return result;
469
1054
  }
470
1055
  /** Live query: the latest value a run published for `key` via `ctx.setEvent` (no side effect). */
@@ -476,202 +1061,179 @@ var DurableApiController = class {
476
1061
  return this.dashboard.update(id, name, body);
477
1062
  }
478
1063
  };
479
- _ts_decorate2([
480
- (0, import_common2.Get)("runs"),
481
- _ts_param2(0, (0, import_common2.Query)("status")),
482
- _ts_param2(1, (0, import_common2.Query)("workflow")),
483
- _ts_param2(2, (0, import_common2.Query)("tag")),
484
- _ts_param2(3, (0, import_common2.Query)("attr")),
485
- _ts_param2(4, (0, import_common2.Query)("namespace")),
486
- _ts_param2(5, (0, import_common2.Query)("origin")),
487
- _ts_param2(6, (0, import_common2.Query)("unattributed")),
488
- _ts_param2(7, (0, import_common2.Query)("limit")),
489
- _ts_param2(8, (0, import_common2.Query)("offset")),
490
- _ts_metadata2("design:type", Function),
491
- _ts_metadata2("design:paramtypes", [
492
- Object,
493
- String,
494
- String,
495
- Object,
496
- String,
497
- String,
498
- String,
499
- String,
500
- String
1064
+ _ts_decorate4([
1065
+ (0, import_common4.Get)("runs"),
1066
+ _ts_param2(0, (0, import_nestjs_filter2.ApplyFilter)(RunFilter)),
1067
+ _ts_metadata4("design:type", Function),
1068
+ _ts_metadata4("design:paramtypes", [
1069
+ typeof RunQueryDraft === "undefined" ? Object : RunQueryDraft
501
1070
  ]),
502
- _ts_metadata2("design:returntype", Promise)
1071
+ _ts_metadata4("design:returntype", Promise)
503
1072
  ], DurableApiController.prototype, "runs", null);
504
- _ts_decorate2([
505
- (0, import_common2.Get)("runs/facets"),
506
- _ts_param2(0, (0, import_common2.Query)("workflow")),
507
- _ts_param2(1, (0, import_common2.Query)("tag")),
508
- _ts_param2(2, (0, import_common2.Query)("attr")),
509
- _ts_param2(3, (0, import_common2.Query)("namespace")),
510
- _ts_metadata2("design:type", Function),
511
- _ts_metadata2("design:paramtypes", [
512
- String,
513
- String,
514
- Object,
515
- String
1073
+ _ts_decorate4([
1074
+ (0, import_common4.Get)("runs/facets"),
1075
+ _ts_param2(0, (0, import_nestjs_filter2.ApplyFilter)(RunFilter)),
1076
+ _ts_metadata4("design:type", Function),
1077
+ _ts_metadata4("design:paramtypes", [
1078
+ typeof RunQueryDraft === "undefined" ? Object : RunQueryDraft
516
1079
  ]),
517
- _ts_metadata2("design:returntype", void 0)
1080
+ _ts_metadata4("design:returntype", void 0)
518
1081
  ], DurableApiController.prototype, "facets", null);
519
- _ts_decorate2([
520
- (0, import_common2.Get)("metrics"),
521
- (0, import_common2.Header)("Content-Type", "text/plain; version=0.0.4"),
522
- _ts_metadata2("design:type", Function),
523
- _ts_metadata2("design:paramtypes", []),
524
- _ts_metadata2("design:returntype", void 0)
1082
+ _ts_decorate4([
1083
+ (0, import_common4.Get)("runs/values"),
1084
+ _ts_param2(0, (0, import_common4.Query)()),
1085
+ _ts_metadata4("design:type", Function),
1086
+ _ts_metadata4("design:paramtypes", [
1087
+ typeof Record === "undefined" ? Object : Record
1088
+ ]),
1089
+ _ts_metadata4("design:returntype", void 0)
1090
+ ], DurableApiController.prototype, "values", null);
1091
+ _ts_decorate4([
1092
+ (0, import_common4.Get)("metrics"),
1093
+ (0, import_common4.Header)("Content-Type", "text/plain; version=0.0.4"),
1094
+ _ts_metadata4("design:type", Function),
1095
+ _ts_metadata4("design:paramtypes", []),
1096
+ _ts_metadata4("design:returntype", void 0)
525
1097
  ], DurableApiController.prototype, "metrics", null);
526
- _ts_decorate2([
527
- (0, import_common2.Get)("workers"),
528
- _ts_metadata2("design:type", Function),
529
- _ts_metadata2("design:paramtypes", []),
530
- _ts_metadata2("design:returntype", void 0)
1098
+ _ts_decorate4([
1099
+ (0, import_common4.Get)("workers"),
1100
+ _ts_metadata4("design:type", Function),
1101
+ _ts_metadata4("design:paramtypes", []),
1102
+ _ts_metadata4("design:returntype", void 0)
531
1103
  ], DurableApiController.prototype, "workers", null);
532
- _ts_decorate2([
533
- (0, import_common2.Get)("topology"),
534
- _ts_metadata2("design:type", Function),
535
- _ts_metadata2("design:paramtypes", []),
536
- _ts_metadata2("design:returntype", void 0)
1104
+ _ts_decorate4([
1105
+ (0, import_common4.Get)("topology"),
1106
+ _ts_metadata4("design:type", Function),
1107
+ _ts_metadata4("design:paramtypes", []),
1108
+ _ts_metadata4("design:returntype", void 0)
537
1109
  ], DurableApiController.prototype, "topology", null);
538
- _ts_decorate2([
539
- (0, import_common2.Get)("runs/:id"),
540
- _ts_param2(0, (0, import_common2.Param)("id")),
541
- _ts_metadata2("design:type", Function),
542
- _ts_metadata2("design:paramtypes", [
1110
+ _ts_decorate4([
1111
+ (0, import_common4.Get)("runs/:id"),
1112
+ _ts_param2(0, (0, import_common4.Param)("id")),
1113
+ _ts_metadata4("design:type", Function),
1114
+ _ts_metadata4("design:paramtypes", [
543
1115
  String
544
1116
  ]),
545
- _ts_metadata2("design:returntype", Promise)
1117
+ _ts_metadata4("design:returntype", Promise)
546
1118
  ], DurableApiController.prototype, "run", null);
547
- _ts_decorate2([
548
- (0, import_common2.Sse)("runs/:id/stream"),
549
- _ts_param2(0, (0, import_common2.Param)("id")),
550
- _ts_metadata2("design:type", Function),
551
- _ts_metadata2("design:paramtypes", [
1119
+ _ts_decorate4([
1120
+ (0, import_common4.Sse)("runs/:id/stream"),
1121
+ _ts_param2(0, (0, import_common4.Param)("id")),
1122
+ _ts_metadata4("design:type", Function),
1123
+ _ts_metadata4("design:paramtypes", [
552
1124
  String
553
1125
  ]),
554
- _ts_metadata2("design:returntype", void 0)
1126
+ _ts_metadata4("design:returntype", void 0)
555
1127
  ], DurableApiController.prototype, "stream", null);
556
- _ts_decorate2([
557
- (0, import_common2.Post)("runs/:id/retry"),
558
- _ts_param2(0, (0, import_common2.Param)("id")),
559
- _ts_metadata2("design:type", Function),
560
- _ts_metadata2("design:paramtypes", [
1128
+ _ts_decorate4([
1129
+ (0, import_common4.Post)("runs/:id/retry"),
1130
+ _ts_param2(0, (0, import_common4.Param)("id")),
1131
+ _ts_metadata4("design:type", Function),
1132
+ _ts_metadata4("design:paramtypes", [
561
1133
  String
562
1134
  ]),
563
- _ts_metadata2("design:returntype", void 0)
1135
+ _ts_metadata4("design:returntype", void 0)
564
1136
  ], DurableApiController.prototype, "retry", null);
565
- _ts_decorate2([
566
- (0, import_common2.Post)("runs/:id/retry-with-input"),
567
- _ts_param2(0, (0, import_common2.Param)("id")),
568
- _ts_param2(1, (0, import_common2.Body)()),
569
- _ts_metadata2("design:type", Function),
570
- _ts_metadata2("design:paramtypes", [
1137
+ _ts_decorate4([
1138
+ (0, import_common4.Post)("runs/:id/retry-with-input"),
1139
+ _ts_param2(0, (0, import_common4.Param)("id")),
1140
+ _ts_param2(1, (0, import_common4.Body)()),
1141
+ _ts_metadata4("design:type", Function),
1142
+ _ts_metadata4("design:paramtypes", [
571
1143
  String,
572
1144
  Object
573
1145
  ]),
574
- _ts_metadata2("design:returntype", void 0)
1146
+ _ts_metadata4("design:returntype", void 0)
575
1147
  ], DurableApiController.prototype, "retryWithInput", null);
576
- _ts_decorate2([
577
- (0, import_common2.Post)("bulk/:action"),
578
- _ts_param2(0, (0, import_common2.Param)("action")),
579
- _ts_param2(1, (0, import_common2.Query)("status")),
580
- _ts_param2(2, (0, import_common2.Query)("tag")),
581
- _ts_param2(3, (0, import_common2.Query)("workflow")),
582
- _ts_param2(4, (0, import_common2.Query)("attr")),
583
- _ts_param2(5, (0, import_common2.Query)("compensate")),
584
- _ts_param2(6, (0, import_common2.Query)("namespace")),
585
- _ts_param2(7, (0, import_common2.Query)("origin")),
586
- _ts_param2(8, (0, import_common2.Query)("unattributed")),
587
- _ts_metadata2("design:type", Function),
588
- _ts_metadata2("design:paramtypes", [
589
- String,
590
- typeof RunStatus === "undefined" ? Object : RunStatus,
591
- String,
592
- String,
593
- Object,
594
- String,
595
- String,
1148
+ _ts_decorate4([
1149
+ (0, import_common4.Post)("bulk/:action"),
1150
+ _ts_param2(0, (0, import_common4.Param)("action")),
1151
+ _ts_param2(1, (0, import_nestjs_filter2.ApplyFilter)(RunFilter)),
1152
+ _ts_param2(2, (0, import_common4.Query)("compensate")),
1153
+ _ts_metadata4("design:type", Function),
1154
+ _ts_metadata4("design:paramtypes", [
596
1155
  String,
1156
+ typeof RunQueryDraft === "undefined" ? Object : RunQueryDraft,
597
1157
  String
598
1158
  ]),
599
- _ts_metadata2("design:returntype", void 0)
1159
+ _ts_metadata4("design:returntype", void 0)
600
1160
  ], DurableApiController.prototype, "bulk", null);
601
- _ts_decorate2([
602
- (0, import_common2.Post)("runs/:id/cancel"),
603
- _ts_param2(0, (0, import_common2.Param)("id")),
604
- _ts_param2(1, (0, import_common2.Query)("compensate")),
605
- _ts_metadata2("design:type", Function),
606
- _ts_metadata2("design:paramtypes", [
1161
+ _ts_decorate4([
1162
+ (0, import_common4.Post)("runs/:id/cancel"),
1163
+ _ts_param2(0, (0, import_common4.Param)("id")),
1164
+ _ts_param2(1, (0, import_common4.Query)("compensate")),
1165
+ _ts_metadata4("design:type", Function),
1166
+ _ts_metadata4("design:paramtypes", [
607
1167
  String,
608
1168
  String
609
1169
  ]),
610
- _ts_metadata2("design:returntype", Promise)
1170
+ _ts_metadata4("design:returntype", Promise)
611
1171
  ], DurableApiController.prototype, "cancel", null);
612
- _ts_decorate2([
613
- (0, import_common2.Post)("runs/:id/continue"),
614
- _ts_param2(0, (0, import_common2.Param)("id")),
615
- _ts_metadata2("design:type", Function),
616
- _ts_metadata2("design:paramtypes", [
1172
+ _ts_decorate4([
1173
+ (0, import_common4.Post)("runs/:id/continue"),
1174
+ _ts_param2(0, (0, import_common4.Param)("id")),
1175
+ _ts_metadata4("design:type", Function),
1176
+ _ts_metadata4("design:paramtypes", [
617
1177
  String
618
1178
  ]),
619
- _ts_metadata2("design:returntype", Promise)
1179
+ _ts_metadata4("design:returntype", Promise)
620
1180
  ], DurableApiController.prototype, "continue", null);
621
- _ts_decorate2([
622
- (0, import_common2.Post)("runs/:id/redispatch"),
623
- _ts_param2(0, (0, import_common2.Param)("id")),
624
- _ts_metadata2("design:type", Function),
625
- _ts_metadata2("design:paramtypes", [
1181
+ _ts_decorate4([
1182
+ (0, import_common4.Post)("runs/:id/redispatch"),
1183
+ _ts_param2(0, (0, import_common4.Param)("id")),
1184
+ _ts_metadata4("design:type", Function),
1185
+ _ts_metadata4("design:paramtypes", [
626
1186
  String
627
1187
  ]),
628
- _ts_metadata2("design:returntype", Promise)
1188
+ _ts_metadata4("design:returntype", Promise)
629
1189
  ], DurableApiController.prototype, "redispatch", null);
630
- _ts_decorate2([
631
- (0, import_common2.Post)("webhooks/:token"),
632
- _ts_param2(0, (0, import_common2.Param)("token")),
633
- _ts_param2(1, (0, import_common2.Body)()),
634
- _ts_metadata2("design:type", Function),
635
- _ts_metadata2("design:paramtypes", [
1190
+ _ts_decorate4([
1191
+ (0, import_common4.Post)("webhooks/:token"),
1192
+ _ts_param2(0, (0, import_common4.Param)("token")),
1193
+ _ts_param2(1, (0, import_common4.Body)()),
1194
+ _ts_metadata4("design:type", Function),
1195
+ _ts_metadata4("design:paramtypes", [
636
1196
  String,
637
1197
  Object
638
1198
  ]),
639
- _ts_metadata2("design:returntype", Promise)
1199
+ _ts_metadata4("design:returntype", Promise)
640
1200
  ], DurableApiController.prototype, "webhook", null);
641
- _ts_decorate2([
642
- (0, import_common2.Get)("runs/:id/events/:key"),
643
- _ts_param2(0, (0, import_common2.Param)("id")),
644
- _ts_param2(1, (0, import_common2.Param)("key")),
645
- _ts_metadata2("design:type", Function),
646
- _ts_metadata2("design:paramtypes", [
1201
+ _ts_decorate4([
1202
+ (0, import_common4.Get)("runs/:id/events/:key"),
1203
+ _ts_param2(0, (0, import_common4.Param)("id")),
1204
+ _ts_param2(1, (0, import_common4.Param)("key")),
1205
+ _ts_metadata4("design:type", Function),
1206
+ _ts_metadata4("design:paramtypes", [
647
1207
  String,
648
1208
  String
649
1209
  ]),
650
- _ts_metadata2("design:returntype", void 0)
1210
+ _ts_metadata4("design:returntype", void 0)
651
1211
  ], DurableApiController.prototype, "event", null);
652
- _ts_decorate2([
653
- (0, import_common2.Post)("runs/:id/updates/:name"),
654
- _ts_param2(0, (0, import_common2.Param)("id")),
655
- _ts_param2(1, (0, import_common2.Param)("name")),
656
- _ts_param2(2, (0, import_common2.Body)()),
657
- _ts_metadata2("design:type", Function),
658
- _ts_metadata2("design:paramtypes", [
1212
+ _ts_decorate4([
1213
+ (0, import_common4.Post)("runs/:id/updates/:name"),
1214
+ _ts_param2(0, (0, import_common4.Param)("id")),
1215
+ _ts_param2(1, (0, import_common4.Param)("name")),
1216
+ _ts_param2(2, (0, import_common4.Body)()),
1217
+ _ts_metadata4("design:type", Function),
1218
+ _ts_metadata4("design:paramtypes", [
659
1219
  String,
660
1220
  String,
661
1221
  Object
662
1222
  ]),
663
- _ts_metadata2("design:returntype", void 0)
1223
+ _ts_metadata4("design:returntype", void 0)
664
1224
  ], DurableApiController.prototype, "update", null);
665
- DurableApiController = _ts_decorate2([
666
- (0, import_common2.Controller)(),
667
- _ts_metadata2("design:type", Function),
668
- _ts_metadata2("design:paramtypes", [
669
- typeof DashboardService === "undefined" ? Object : DashboardService
1225
+ DurableApiController = _ts_decorate4([
1226
+ (0, import_common4.Controller)(),
1227
+ (0, import_common4.UseInterceptors)(import_nestjs_filter2.ApplyFilterInterceptor),
1228
+ _ts_metadata4("design:type", Function),
1229
+ _ts_metadata4("design:paramtypes", [
1230
+ typeof DashboardService === "undefined" ? Object : DashboardService,
1231
+ typeof import_nestjs_filter2.FilterRunner === "undefined" ? Object : import_nestjs_filter2.FilterRunner
670
1232
  ])
671
1233
  ], DurableApiController);
672
1234
 
673
1235
  // src/server/durable-auth.controller.ts
674
- var import_common6 = require("@nestjs/common");
1236
+ var import_common8 = require("@nestjs/common");
675
1237
 
676
1238
  // src/server/auth/dashboard-auth-config.ts
677
1239
  var DASHBOARD_AUTH = Symbol("DASHBOARD_AUTH");
@@ -1223,18 +1785,18 @@ __name(maybeRenewSession, "maybeRenewSession");
1223
1785
  var import_node_fs = require("fs");
1224
1786
  var import_node_path = require("path");
1225
1787
  var import_node_url = require("url");
1226
- var import_common5 = require("@nestjs/common");
1788
+ var import_common7 = require("@nestjs/common");
1227
1789
 
1228
1790
  // src/server/auth/login-redirect.exception.ts
1229
- var import_common3 = require("@nestjs/common");
1230
- function _ts_decorate3(decorators, target, key, desc) {
1791
+ var import_common5 = require("@nestjs/common");
1792
+ function _ts_decorate5(decorators, target, key, desc) {
1231
1793
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1232
1794
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1233
1795
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1234
1796
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1235
1797
  }
1236
- __name(_ts_decorate3, "_ts_decorate");
1237
- var DashboardLoginRedirectException = class extends import_common3.HttpException {
1798
+ __name(_ts_decorate5, "_ts_decorate");
1799
+ var DashboardLoginRedirectException = class extends import_common5.HttpException {
1238
1800
  static {
1239
1801
  __name(this, "DashboardLoginRedirectException");
1240
1802
  }
@@ -1242,7 +1804,7 @@ var DashboardLoginRedirectException = class extends import_common3.HttpException
1242
1804
  constructor(location) {
1243
1805
  super({
1244
1806
  location
1245
- }, import_common3.HttpStatus.FOUND), this.location = location;
1807
+ }, import_common5.HttpStatus.FOUND), this.location = location;
1246
1808
  }
1247
1809
  };
1248
1810
  var DashboardLoginRedirectFilter = class {
@@ -1254,30 +1816,30 @@ var DashboardLoginRedirectFilter = class {
1254
1816
  redirectRaw(response, exception.location);
1255
1817
  }
1256
1818
  };
1257
- DashboardLoginRedirectFilter = _ts_decorate3([
1258
- (0, import_common3.Catch)(DashboardLoginRedirectException)
1819
+ DashboardLoginRedirectFilter = _ts_decorate5([
1820
+ (0, import_common5.Catch)(DashboardLoginRedirectException)
1259
1821
  ], DashboardLoginRedirectFilter);
1260
1822
 
1261
1823
  // src/server/auth/session-required.exception.ts
1262
- var import_common4 = require("@nestjs/common");
1263
- function _ts_decorate4(decorators, target, key, desc) {
1824
+ var import_common6 = require("@nestjs/common");
1825
+ function _ts_decorate6(decorators, target, key, desc) {
1264
1826
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1265
1827
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1266
1828
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1267
1829
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1268
1830
  }
1269
- __name(_ts_decorate4, "_ts_decorate");
1270
- function _ts_metadata3(k, v) {
1831
+ __name(_ts_decorate6, "_ts_decorate");
1832
+ function _ts_metadata5(k, v) {
1271
1833
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1272
1834
  }
1273
- __name(_ts_metadata3, "_ts_metadata");
1835
+ __name(_ts_metadata5, "_ts_metadata");
1274
1836
  function _ts_param3(paramIndex, decorator) {
1275
1837
  return function(target, key) {
1276
1838
  decorator(target, key, paramIndex);
1277
1839
  };
1278
1840
  }
1279
1841
  __name(_ts_param3, "_ts_param");
1280
- var DashboardSessionRequiredException = class extends import_common4.HttpException {
1842
+ var DashboardSessionRequiredException = class extends import_common6.HttpException {
1281
1843
  static {
1282
1844
  __name(this, "DashboardSessionRequiredException");
1283
1845
  }
@@ -1285,7 +1847,7 @@ var DashboardSessionRequiredException = class extends import_common4.HttpExcepti
1285
1847
  constructor(basePath) {
1286
1848
  super({
1287
1849
  basePath
1288
- }, import_common4.HttpStatus.UNAUTHORIZED), this.basePath = basePath;
1850
+ }, import_common6.HttpStatus.UNAUTHORIZED), this.basePath = basePath;
1289
1851
  }
1290
1852
  };
1291
1853
  var DashboardSessionRequiredFilter = class _DashboardSessionRequiredFilter {
@@ -1293,7 +1855,7 @@ var DashboardSessionRequiredFilter = class _DashboardSessionRequiredFilter {
1293
1855
  __name(this, "DashboardSessionRequiredFilter");
1294
1856
  }
1295
1857
  auth;
1296
- logger = new import_common4.Logger(_DashboardSessionRequiredFilter.name);
1858
+ logger = new import_common6.Logger(_DashboardSessionRequiredFilter.name);
1297
1859
  warned = false;
1298
1860
  constructor(auth = null) {
1299
1861
  this.auth = auth;
@@ -1316,7 +1878,7 @@ var DashboardSessionRequiredFilter = class _DashboardSessionRequiredFilter {
1316
1878
  if (responseAlreadyWritten(response)) return;
1317
1879
  }
1318
1880
  }
1319
- writeHtmlRaw(response, renderSessionRequiredPage(exception.basePath), import_common4.HttpStatus.UNAUTHORIZED);
1881
+ writeHtmlRaw(response, renderSessionRequiredPage(exception.basePath), import_common6.HttpStatus.UNAUTHORIZED);
1320
1882
  }
1321
1883
  /** Once per process, not once per request: a broken hook fires on every denied navigation. */
1322
1884
  warnOnce(message) {
@@ -1325,28 +1887,28 @@ var DashboardSessionRequiredFilter = class _DashboardSessionRequiredFilter {
1325
1887
  this.logger.warn(message);
1326
1888
  }
1327
1889
  };
1328
- DashboardSessionRequiredFilter = _ts_decorate4([
1329
- (0, import_common4.Catch)(DashboardSessionRequiredException),
1330
- _ts_param3(0, (0, import_common4.Optional)()),
1331
- _ts_param3(0, (0, import_common4.Inject)(DASHBOARD_AUTH)),
1332
- _ts_metadata3("design:type", Function),
1333
- _ts_metadata3("design:paramtypes", [
1890
+ DashboardSessionRequiredFilter = _ts_decorate6([
1891
+ (0, import_common6.Catch)(DashboardSessionRequiredException),
1892
+ _ts_param3(0, (0, import_common6.Optional)()),
1893
+ _ts_param3(0, (0, import_common6.Inject)(DASHBOARD_AUTH)),
1894
+ _ts_metadata5("design:type", Function),
1895
+ _ts_metadata5("design:paramtypes", [
1334
1896
  Object
1335
1897
  ])
1336
1898
  ], DashboardSessionRequiredFilter);
1337
1899
 
1338
1900
  // src/server/durable-ui.controller.ts
1339
- function _ts_decorate5(decorators, target, key, desc) {
1901
+ function _ts_decorate7(decorators, target, key, desc) {
1340
1902
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1341
1903
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1342
1904
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1343
1905
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1344
1906
  }
1345
- __name(_ts_decorate5, "_ts_decorate");
1346
- function _ts_metadata4(k, v) {
1907
+ __name(_ts_decorate7, "_ts_decorate");
1908
+ function _ts_metadata6(k, v) {
1347
1909
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1348
1910
  }
1349
- __name(_ts_metadata4, "_ts_metadata");
1911
+ __name(_ts_metadata6, "_ts_metadata");
1350
1912
  function _ts_param4(paramIndex, decorator) {
1351
1913
  return function(target, key) {
1352
1914
  decorator(target, key, paramIndex);
@@ -1385,7 +1947,7 @@ var DurableUiController = class {
1385
1947
  index() {
1386
1948
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
1387
1949
  if (!(0, import_node_fs.existsSync)(indexPath)) {
1388
- throw new import_common5.NotFoundException("Dashboard is not built. Run the package build.");
1950
+ throw new import_common7.NotFoundException("Dashboard is not built. Run the package build.");
1389
1951
  }
1390
1952
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
1391
1953
  const inject = `<script>window.__DURABLE_BASE__='${this.basePath}';window.__DURABLE_API__='${this.apiBasePath}';</script>`;
@@ -1393,60 +1955,60 @@ var DurableUiController = class {
1393
1955
  }
1394
1956
  asset(file) {
1395
1957
  const safe = (0, import_node_path.basename)(file);
1396
- if (safe !== file) throw new import_common5.NotFoundException();
1958
+ if (safe !== file) throw new import_common7.NotFoundException();
1397
1959
  const root = (0, import_node_path.resolve)(this.dir, "assets");
1398
1960
  const assetPath = (0, import_node_path.resolve)(root, safe);
1399
1961
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
1400
- throw new import_common5.NotFoundException();
1962
+ throw new import_common7.NotFoundException();
1401
1963
  }
1402
1964
  const type = CONTENT_TYPES[(0, import_node_path.extname)(safe)] ?? "application/octet-stream";
1403
- return new import_common5.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1965
+ return new import_common7.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1404
1966
  type
1405
1967
  });
1406
1968
  }
1407
1969
  };
1408
- _ts_decorate5([
1409
- (0, import_common5.Get)(),
1410
- (0, import_common5.Header)("Content-Type", "text/html; charset=utf-8"),
1411
- (0, import_common5.Header)("Cache-Control", "no-store, must-revalidate"),
1412
- _ts_metadata4("design:type", Function),
1413
- _ts_metadata4("design:paramtypes", []),
1414
- _ts_metadata4("design:returntype", String)
1970
+ _ts_decorate7([
1971
+ (0, import_common7.Get)(),
1972
+ (0, import_common7.Header)("Content-Type", "text/html; charset=utf-8"),
1973
+ (0, import_common7.Header)("Cache-Control", "no-store, must-revalidate"),
1974
+ _ts_metadata6("design:type", Function),
1975
+ _ts_metadata6("design:paramtypes", []),
1976
+ _ts_metadata6("design:returntype", String)
1415
1977
  ], DurableUiController.prototype, "index", null);
1416
- _ts_decorate5([
1417
- (0, import_common5.Get)("assets/:file"),
1418
- (0, import_common5.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1419
- _ts_param4(0, (0, import_common5.Param)("file")),
1420
- _ts_metadata4("design:type", Function),
1421
- _ts_metadata4("design:paramtypes", [
1978
+ _ts_decorate7([
1979
+ (0, import_common7.Get)("assets/:file"),
1980
+ (0, import_common7.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1981
+ _ts_param4(0, (0, import_common7.Param)("file")),
1982
+ _ts_metadata6("design:type", Function),
1983
+ _ts_metadata6("design:paramtypes", [
1422
1984
  String
1423
1985
  ]),
1424
- _ts_metadata4("design:returntype", typeof import_common5.StreamableFile === "undefined" ? Object : import_common5.StreamableFile)
1986
+ _ts_metadata6("design:returntype", typeof import_common7.StreamableFile === "undefined" ? Object : import_common7.StreamableFile)
1425
1987
  ], DurableUiController.prototype, "asset", null);
1426
- DurableUiController = _ts_decorate5([
1427
- (0, import_common5.UseFilters)(DashboardLoginRedirectFilter, DashboardSessionRequiredFilter),
1428
- (0, import_common5.Controller)(),
1429
- _ts_param4(0, (0, import_common5.Inject)(DASHBOARD_BASE_PATH)),
1430
- _ts_param4(1, (0, import_common5.Inject)(DASHBOARD_API_PATH)),
1431
- _ts_metadata4("design:type", Function),
1432
- _ts_metadata4("design:paramtypes", [
1988
+ DurableUiController = _ts_decorate7([
1989
+ (0, import_common7.UseFilters)(DashboardLoginRedirectFilter, DashboardSessionRequiredFilter),
1990
+ (0, import_common7.Controller)(),
1991
+ _ts_param4(0, (0, import_common7.Inject)(DASHBOARD_BASE_PATH)),
1992
+ _ts_param4(1, (0, import_common7.Inject)(DASHBOARD_API_PATH)),
1993
+ _ts_metadata6("design:type", Function),
1994
+ _ts_metadata6("design:paramtypes", [
1433
1995
  String,
1434
1996
  String
1435
1997
  ])
1436
1998
  ], DurableUiController);
1437
1999
 
1438
2000
  // src/server/durable-auth.controller.ts
1439
- function _ts_decorate6(decorators, target, key, desc) {
2001
+ function _ts_decorate8(decorators, target, key, desc) {
1440
2002
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1441
2003
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1442
2004
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1443
2005
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1444
2006
  }
1445
- __name(_ts_decorate6, "_ts_decorate");
1446
- function _ts_metadata5(k, v) {
2007
+ __name(_ts_decorate8, "_ts_decorate");
2008
+ function _ts_metadata7(k, v) {
1447
2009
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1448
2010
  }
1449
- __name(_ts_metadata5, "_ts_metadata");
2011
+ __name(_ts_metadata7, "_ts_metadata");
1450
2012
  function _ts_param5(paramIndex, decorator) {
1451
2013
  return function(target, key) {
1452
2014
  decorator(target, key, paramIndex);
@@ -1463,7 +2025,7 @@ var DurableAuthController = class _DurableAuthController {
1463
2025
  }
1464
2026
  auth;
1465
2027
  basePath;
1466
- logger = new import_common6.Logger(_DurableAuthController.name);
2028
+ logger = new import_common8.Logger(_DurableAuthController.name);
1467
2029
  /** Warn once per hook kind so a throwing hook doesn't spam logs on every failed attempt. */
1468
2030
  warnedHooks = /* @__PURE__ */ new Set();
1469
2031
  constructor(auth, basePath) {
@@ -1475,7 +2037,7 @@ var DurableAuthController = class _DurableAuthController {
1475
2037
  // the developer-controlled `basePath`.
1476
2038
  loginPage() {
1477
2039
  const auth = this.requireAuth();
1478
- if (!auth.modes.includes("login")) throw new import_common6.NotFoundException();
2040
+ if (!auth.modes.includes("login")) throw new import_common8.NotFoundException();
1479
2041
  return renderLoginPage(this.basePath);
1480
2042
  }
1481
2043
  // Called by the login page's own fetch (JSON, not a classic form POST — see `login-page.ts` for
@@ -1484,13 +2046,13 @@ var DurableAuthController = class _DurableAuthController {
1484
2046
  // (unknown user, wrong password, throwing hook) — no user-enumeration.
1485
2047
  async login(body, request, response) {
1486
2048
  const auth = this.requireAuth();
1487
- if (!auth.modes.includes("login")) throw new import_common6.NotFoundException();
2049
+ if (!auth.modes.includes("login")) throw new import_common8.NotFoundException();
1488
2050
  if (!isString(body?.username) || !isString(body?.password)) {
1489
- throw new import_common6.BadRequestException("Body must include string `username` and `password`.");
2051
+ throw new import_common8.BadRequestException("Body must include string `username` and `password`.");
1490
2052
  }
1491
2053
  const { username, password } = body;
1492
2054
  const user = await this.runHook("login", () => auth.login?.(username, password) ?? null);
1493
- if (!user) throw new import_common6.UnauthorizedException({
2055
+ if (!user) throw new import_common8.UnauthorizedException({
1494
2056
  message: "Invalid username or password."
1495
2057
  });
1496
2058
  issueSessionCookie(user, {
@@ -1507,9 +2069,9 @@ var DurableAuthController = class _DurableAuthController {
1507
2069
  // guard decides, and no credential ever reaches this library.
1508
2070
  async session(request, response) {
1509
2071
  const auth = this.requireAuth();
1510
- if (!auth.modes.includes("session")) throw new import_common6.NotFoundException();
2072
+ if (!auth.modes.includes("session")) throw new import_common8.NotFoundException();
1511
2073
  const user = await this.runHook("session", () => auth.session?.(request) ?? null);
1512
- if (!user) throw new import_common6.UnauthorizedException();
2074
+ if (!user) throw new import_common8.UnauthorizedException();
1513
2075
  issueSessionCookie(user, {
1514
2076
  auth,
1515
2077
  request,
@@ -1528,7 +2090,7 @@ var DurableAuthController = class _DurableAuthController {
1528
2090
  redirectRaw(response, this.auth?.modes.includes("login") ? `${this.basePath}/login` : this.basePath);
1529
2091
  }
1530
2092
  requireAuth() {
1531
- if (!this.auth) throw new import_common6.NotFoundException();
2093
+ if (!this.auth) throw new import_common8.NotFoundException();
1532
2094
  return this.auth;
1533
2095
  }
1534
2096
  /**
@@ -1548,62 +2110,62 @@ var DurableAuthController = class _DurableAuthController {
1548
2110
  }
1549
2111
  }
1550
2112
  };
1551
- _ts_decorate6([
1552
- (0, import_common6.Get)("login"),
1553
- (0, import_common6.Header)("Content-Type", "text/html; charset=utf-8"),
1554
- (0, import_common6.Header)("Cache-Control", "no-store, must-revalidate"),
1555
- _ts_metadata5("design:type", Function),
1556
- _ts_metadata5("design:paramtypes", []),
1557
- _ts_metadata5("design:returntype", String)
2113
+ _ts_decorate8([
2114
+ (0, import_common8.Get)("login"),
2115
+ (0, import_common8.Header)("Content-Type", "text/html; charset=utf-8"),
2116
+ (0, import_common8.Header)("Cache-Control", "no-store, must-revalidate"),
2117
+ _ts_metadata7("design:type", Function),
2118
+ _ts_metadata7("design:paramtypes", []),
2119
+ _ts_metadata7("design:returntype", String)
1558
2120
  ], DurableAuthController.prototype, "loginPage", null);
1559
- _ts_decorate6([
1560
- (0, import_common6.Post)("login"),
1561
- (0, import_common6.HttpCode)(200),
1562
- _ts_param5(0, (0, import_common6.Body)()),
1563
- _ts_param5(1, (0, import_common6.Req)()),
1564
- _ts_param5(2, (0, import_common6.Res)({
2121
+ _ts_decorate8([
2122
+ (0, import_common8.Post)("login"),
2123
+ (0, import_common8.HttpCode)(200),
2124
+ _ts_param5(0, (0, import_common8.Body)()),
2125
+ _ts_param5(1, (0, import_common8.Req)()),
2126
+ _ts_param5(2, (0, import_common8.Res)({
1565
2127
  passthrough: true
1566
2128
  })),
1567
- _ts_metadata5("design:type", Function),
1568
- _ts_metadata5("design:paramtypes", [
2129
+ _ts_metadata7("design:type", Function),
2130
+ _ts_metadata7("design:paramtypes", [
1569
2131
  typeof LoginBody === "undefined" ? Object : LoginBody,
1570
2132
  Object,
1571
2133
  Object
1572
2134
  ]),
1573
- _ts_metadata5("design:returntype", Promise)
2135
+ _ts_metadata7("design:returntype", Promise)
1574
2136
  ], DurableAuthController.prototype, "login", null);
1575
- _ts_decorate6([
1576
- (0, import_common6.Post)("session"),
1577
- (0, import_common6.HttpCode)(204),
1578
- _ts_param5(0, (0, import_common6.Req)()),
1579
- _ts_param5(1, (0, import_common6.Res)({
2137
+ _ts_decorate8([
2138
+ (0, import_common8.Post)("session"),
2139
+ (0, import_common8.HttpCode)(204),
2140
+ _ts_param5(0, (0, import_common8.Req)()),
2141
+ _ts_param5(1, (0, import_common8.Res)({
1580
2142
  passthrough: true
1581
2143
  })),
1582
- _ts_metadata5("design:type", Function),
1583
- _ts_metadata5("design:paramtypes", [
2144
+ _ts_metadata7("design:type", Function),
2145
+ _ts_metadata7("design:paramtypes", [
1584
2146
  Object,
1585
2147
  Object
1586
2148
  ]),
1587
- _ts_metadata5("design:returntype", Promise)
2149
+ _ts_metadata7("design:returntype", Promise)
1588
2150
  ], DurableAuthController.prototype, "session", null);
1589
- _ts_decorate6([
1590
- (0, import_common6.Get)("logout"),
1591
- _ts_param5(0, (0, import_common6.Req)()),
1592
- _ts_param5(1, (0, import_common6.Res)()),
1593
- _ts_metadata5("design:type", Function),
1594
- _ts_metadata5("design:paramtypes", [
2151
+ _ts_decorate8([
2152
+ (0, import_common8.Get)("logout"),
2153
+ _ts_param5(0, (0, import_common8.Req)()),
2154
+ _ts_param5(1, (0, import_common8.Res)()),
2155
+ _ts_metadata7("design:type", Function),
2156
+ _ts_metadata7("design:paramtypes", [
1595
2157
  Object,
1596
2158
  Object
1597
2159
  ]),
1598
- _ts_metadata5("design:returntype", void 0)
2160
+ _ts_metadata7("design:returntype", void 0)
1599
2161
  ], DurableAuthController.prototype, "logout", null);
1600
- DurableAuthController = _ts_decorate6([
1601
- (0, import_common6.Controller)(),
1602
- _ts_param5(0, (0, import_common6.Optional)()),
1603
- _ts_param5(0, (0, import_common6.Inject)(DASHBOARD_AUTH)),
1604
- _ts_param5(1, (0, import_common6.Inject)(DASHBOARD_BASE_PATH)),
1605
- _ts_metadata5("design:type", Function),
1606
- _ts_metadata5("design:paramtypes", [
2162
+ DurableAuthController = _ts_decorate8([
2163
+ (0, import_common8.Controller)(),
2164
+ _ts_param5(0, (0, import_common8.Optional)()),
2165
+ _ts_param5(0, (0, import_common8.Inject)(DASHBOARD_AUTH)),
2166
+ _ts_param5(1, (0, import_common8.Inject)(DASHBOARD_BASE_PATH)),
2167
+ _ts_metadata7("design:type", Function),
2168
+ _ts_metadata7("design:paramtypes", [
1607
2169
  Object,
1608
2170
  String
1609
2171
  ])
@@ -1611,22 +2173,23 @@ DurableAuthController = _ts_decorate6([
1611
2173
 
1612
2174
  // src/server/durable-dashboard.module.ts
1613
2175
  var import_reflect_metadata = require("reflect-metadata");
1614
- var import_common8 = require("@nestjs/common");
2176
+ var import_nestjs_filter3 = require("@dudousxd/nestjs-filter");
2177
+ var import_common10 = require("@nestjs/common");
1615
2178
  var import_core = require("@nestjs/core");
1616
2179
 
1617
2180
  // src/server/durable-session.guard.ts
1618
- var import_common7 = require("@nestjs/common");
1619
- function _ts_decorate7(decorators, target, key, desc) {
2181
+ var import_common9 = require("@nestjs/common");
2182
+ function _ts_decorate9(decorators, target, key, desc) {
1620
2183
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1621
2184
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1622
2185
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1623
2186
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1624
2187
  }
1625
- __name(_ts_decorate7, "_ts_decorate");
1626
- function _ts_metadata6(k, v) {
2188
+ __name(_ts_decorate9, "_ts_decorate");
2189
+ function _ts_metadata8(k, v) {
1627
2190
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1628
2191
  }
1629
- __name(_ts_metadata6, "_ts_metadata");
2192
+ __name(_ts_metadata8, "_ts_metadata");
1630
2193
  function _ts_param6(paramIndex, decorator) {
1631
2194
  return function(target, key) {
1632
2195
  decorator(target, key, paramIndex);
@@ -1673,12 +2236,12 @@ var DurableUiSessionGuard = class {
1673
2236
  throw new DashboardLoginRedirectException(`${this.basePath}/login?returnTo=${returnTo}`);
1674
2237
  }
1675
2238
  };
1676
- DurableUiSessionGuard = _ts_decorate7([
1677
- (0, import_common7.Injectable)(),
1678
- _ts_param6(0, (0, import_common7.Inject)(DASHBOARD_AUTH)),
1679
- _ts_param6(1, (0, import_common7.Inject)(DASHBOARD_BASE_PATH)),
1680
- _ts_metadata6("design:type", Function),
1681
- _ts_metadata6("design:paramtypes", [
2239
+ DurableUiSessionGuard = _ts_decorate9([
2240
+ (0, import_common9.Injectable)(),
2241
+ _ts_param6(0, (0, import_common9.Inject)(DASHBOARD_AUTH)),
2242
+ _ts_param6(1, (0, import_common9.Inject)(DASHBOARD_BASE_PATH)),
2243
+ _ts_metadata8("design:type", Function),
2244
+ _ts_metadata8("design:paramtypes", [
1682
2245
  Object,
1683
2246
  String
1684
2247
  ])
@@ -1710,30 +2273,30 @@ var DurableApiSessionGuard = class {
1710
2273
  * 401; `DurableUiSessionGuard`'s redirect/session-required exceptions above don't reach it.
1711
2274
  */
1712
2275
  unauthorized(auth) {
1713
- return new import_common7.UnauthorizedException({
2276
+ return new import_common9.UnauthorizedException({
1714
2277
  auth: {
1715
2278
  modes: auth.modes
1716
2279
  }
1717
2280
  });
1718
2281
  }
1719
2282
  };
1720
- DurableApiSessionGuard = _ts_decorate7([
1721
- (0, import_common7.Injectable)(),
1722
- _ts_param6(0, (0, import_common7.Inject)(DASHBOARD_AUTH)),
1723
- _ts_metadata6("design:type", Function),
1724
- _ts_metadata6("design:paramtypes", [
2283
+ DurableApiSessionGuard = _ts_decorate9([
2284
+ (0, import_common9.Injectable)(),
2285
+ _ts_param6(0, (0, import_common9.Inject)(DASHBOARD_AUTH)),
2286
+ _ts_metadata8("design:type", Function),
2287
+ _ts_metadata8("design:paramtypes", [
1725
2288
  Object
1726
2289
  ])
1727
2290
  ], DurableApiSessionGuard);
1728
2291
 
1729
2292
  // src/server/durable-dashboard.module.ts
1730
- function _ts_decorate8(decorators, target, key, desc) {
2293
+ function _ts_decorate10(decorators, target, key, desc) {
1731
2294
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1732
2295
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1733
2296
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1734
2297
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1735
2298
  }
1736
- __name(_ts_decorate8, "_ts_decorate");
2299
+ __name(_ts_decorate10, "_ts_decorate");
1737
2300
  var GUARDS_METADATA = "__guards__";
1738
2301
  function normalize(path) {
1739
2302
  return `/${path.replace(/^\/+|\/+$/g, "")}`;
@@ -1765,6 +2328,37 @@ var DurableApiModule = class _DurableApiModule {
1765
2328
  ],
1766
2329
  providers: [
1767
2330
  DashboardService,
2331
+ // `@dudousxd/nestjs-filter` is wired PRIVATELY here rather than through
2332
+ // `FilterModule.forRoot()`, which is a global registration. A library calling that would
2333
+ // fight the host app over one set of module options and register a second app-wide
2334
+ // interceptor — and it cannot tell at module-definition time whether the host already
2335
+ // called it. Everything below is scoped to this module, so the console composes with an app
2336
+ // that uses the filter library, and with one that has never heard of it, identically.
2337
+ //
2338
+ // `validation: 'off'`: the run filter's inputs are validated by their own translation —
2339
+ // every field/operator pair either maps onto a `RunQuery` predicate or is rejected by
2340
+ // name — so there is nothing left for class-validator to check, and requiring it would put
2341
+ // a peer dependency on every consumer of this dashboard for no gain.
2342
+ //
2343
+ // The `null` adapter is the GLOBAL one, deliberately absent: `RunFilter` names its own via
2344
+ // `@Filterable({ adapter })`, so the console runs on the durable run gateway while the host
2345
+ // app's filters keep running on whatever adapter it registered.
2346
+ {
2347
+ provide: import_nestjs_filter3.FilterRunner,
2348
+ useFactory: /* @__PURE__ */ __name((moduleRef) => new import_nestjs_filter3.FilterRunner(moduleRef, {
2349
+ validation: "off"
2350
+ }, null), "useFactory"),
2351
+ inject: [
2352
+ import_core.ModuleRef
2353
+ ]
2354
+ },
2355
+ import_nestjs_filter3.ApplyFilterInterceptor,
2356
+ RunQueryAdapter,
2357
+ {
2358
+ provide: RUN_QUERY_ADAPTER,
2359
+ useExisting: RunQueryAdapter
2360
+ },
2361
+ RunFilter,
1768
2362
  options.authProvider,
1769
2363
  DurableApiSessionGuard,
1770
2364
  ...options.guards ?? []
@@ -1775,8 +2369,8 @@ var DurableApiModule = class _DurableApiModule {
1775
2369
  };
1776
2370
  }
1777
2371
  };
1778
- DurableApiModule = _ts_decorate8([
1779
- (0, import_common8.Module)({})
2372
+ DurableApiModule = _ts_decorate10([
2373
+ (0, import_common10.Module)({})
1780
2374
  ], DurableApiModule);
1781
2375
  var DurableDashboardModule = class _DurableDashboardModule {
1782
2376
  static {
@@ -1861,8 +2455,8 @@ var DurableDashboardModule = class _DurableDashboardModule {
1861
2455
  };
1862
2456
  }
1863
2457
  };
1864
- DurableDashboardModule = _ts_decorate8([
1865
- (0, import_common8.Module)({})
2458
+ DurableDashboardModule = _ts_decorate10([
2459
+ (0, import_common10.Module)({})
1866
2460
  ], DurableDashboardModule);
1867
2461
  // Annotate the CommonJS export names for ESM import in node:
1868
2462
  0 && (module.exports = {