@dudousxd/nestjs-durable-dashboard 0.41.0 → 0.42.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.
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_durable_core from '@dudousxd/nestjs-durable-core';
2
- import { RunGateway, StateStore, WorkflowEngine, RunQuery, RunListItem, DurableTopology, GroupHealth, RunDetail, RunResult, UpdateResult, EngineEvent, RunStatus } from '@dudousxd/nestjs-durable-core';
2
+ import { RunGateway, StateStore, WorkflowEngine, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, DurableTopology, GroupHealth, RunDetail, RunResult, UpdateResult, EngineEvent, RunStatus } from '@dudousxd/nestjs-durable-core';
3
3
  export { RunDetail } from '@dudousxd/nestjs-durable-core';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Observable } from 'rxjs';
@@ -134,6 +134,9 @@ declare class DashboardService {
134
134
  */
135
135
  metrics(): Promise<string>;
136
136
  listRuns(query: RunQuery): Promise<RunListItem[]>;
137
+ /** `(status, origin)` counts over the same predicates {@link listRuns} pages — what keeps the
138
+ * console's chips exact while its list is bounded to a page. */
139
+ runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
137
140
  /** This deployment's durable role (control plane vs tenant) + tenant name — for the dashboard header
138
141
  * badge. Routes through the gateway, which knows its own topology (store-backed = operator, proxy =
139
142
  * tenant). Works on both topologies (no store/engine needed). */
@@ -195,6 +198,18 @@ declare class DashboardService {
195
198
  }>;
196
199
  }
197
200
 
201
+ /**
202
+ * A run as the CONSOLE'S LIST needs it: every field a row or its derived state reads, and none of the
203
+ * payloads only the detail view opens.
204
+ *
205
+ * `input`, `output` and `error` are dropped. On a real control plane they dominate the response —
206
+ * measured against a 9.5k-run deployment, `error` alone (stack traces on every failed run) was 63% of
207
+ * a 12 MB listing — while no list row, and no `deriveRunState` input, ever reads them. The detail
208
+ * endpoint (`GET runs/:id`) still returns the whole run, which is where those three are actually
209
+ * rendered.
210
+ */
211
+ type RunListRow = Omit<RunListItem, 'input' | 'output' | 'error'>;
212
+
198
213
  /** JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule). */
199
214
  declare class DurableApiController {
200
215
  private readonly dashboard;
@@ -207,7 +222,16 @@ declare class DurableApiController {
207
222
  * A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
208
223
  * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console.
209
224
  */
210
- runs(status?: RunStatus, workflow?: string, tag?: string, attr?: string | string[], namespace?: string, origin?: string): Promise<_dudousxd_nestjs_durable_core.RunListItem[]>;
225
+ runs(status?: RunStatus | RunStatus[], workflow?: string, tag?: string, attr?: string | string[], namespace?: string, origin?: string, unattributed?: string, limit?: string, offset?: string): Promise<RunListRow[]>;
226
+ /**
227
+ * `(status, origin)` counts for the runs matching the same tag/tenant/attribute predicates as
228
+ * `GET runs`. This is what lets that listing be PAGED at all: the page bounds what the console
229
+ * renders, this bounds nothing and keeps its status and origin chips exact.
230
+ *
231
+ * `status`, `origin` and the page bounds are deliberately NOT accepted — they are the axes being
232
+ * counted, so narrowing by them would report the answer back to itself.
233
+ */
234
+ facets(workflow?: string, tag?: string, attr?: string | string[], namespace?: string): Promise<_dudousxd_nestjs_durable_core.RunFacetRow[]>;
211
235
  /** Prometheus-text metrics (runs/steps by outcome, per-workflow counts) for a scrape. */
212
236
  metrics(): Promise<string>;
213
237
  /** Per-group worker health (queue backlog + live worker heartbeats) for the Workers panel. */
@@ -232,7 +256,7 @@ declare class DurableApiController {
232
256
  * The filter takes the SAME params as `GET runs` and is parsed identically, so "retry all" acts on
233
257
  * exactly the set the operator was looking at rather than a wider one.
234
258
  */
235
- bulk(action: 'retry' | 'cancel', status?: RunStatus, tag?: string, workflow?: string, attr?: string | string[], compensate?: string, namespace?: string, origin?: string): Promise<{
259
+ bulk(action: 'retry' | 'cancel', status?: RunStatus, tag?: string, workflow?: string, attr?: string | string[], compensate?: string, namespace?: string, origin?: string, unattributed?: string): Promise<{
236
260
  matched: number;
237
261
  applied: number;
238
262
  }>;
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_durable_core from '@dudousxd/nestjs-durable-core';
2
- import { RunGateway, StateStore, WorkflowEngine, RunQuery, RunListItem, DurableTopology, GroupHealth, RunDetail, RunResult, UpdateResult, EngineEvent, RunStatus } from '@dudousxd/nestjs-durable-core';
2
+ import { RunGateway, StateStore, WorkflowEngine, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, DurableTopology, GroupHealth, RunDetail, RunResult, UpdateResult, EngineEvent, RunStatus } from '@dudousxd/nestjs-durable-core';
3
3
  export { RunDetail } from '@dudousxd/nestjs-durable-core';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Observable } from 'rxjs';
@@ -134,6 +134,9 @@ declare class DashboardService {
134
134
  */
135
135
  metrics(): Promise<string>;
136
136
  listRuns(query: RunQuery): Promise<RunListItem[]>;
137
+ /** `(status, origin)` counts over the same predicates {@link listRuns} pages — what keeps the
138
+ * console's chips exact while its list is bounded to a page. */
139
+ runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
137
140
  /** This deployment's durable role (control plane vs tenant) + tenant name — for the dashboard header
138
141
  * badge. Routes through the gateway, which knows its own topology (store-backed = operator, proxy =
139
142
  * tenant). Works on both topologies (no store/engine needed). */
@@ -195,6 +198,18 @@ declare class DashboardService {
195
198
  }>;
196
199
  }
197
200
 
201
+ /**
202
+ * A run as the CONSOLE'S LIST needs it: every field a row or its derived state reads, and none of the
203
+ * payloads only the detail view opens.
204
+ *
205
+ * `input`, `output` and `error` are dropped. On a real control plane they dominate the response —
206
+ * measured against a 9.5k-run deployment, `error` alone (stack traces on every failed run) was 63% of
207
+ * a 12 MB listing — while no list row, and no `deriveRunState` input, ever reads them. The detail
208
+ * endpoint (`GET runs/:id`) still returns the whole run, which is where those three are actually
209
+ * rendered.
210
+ */
211
+ type RunListRow = Omit<RunListItem, 'input' | 'output' | 'error'>;
212
+
198
213
  /** JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule). */
199
214
  declare class DurableApiController {
200
215
  private readonly dashboard;
@@ -207,7 +222,16 @@ declare class DurableApiController {
207
222
  * A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
208
223
  * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console.
209
224
  */
210
- runs(status?: RunStatus, workflow?: string, tag?: string, attr?: string | string[], namespace?: string, origin?: string): Promise<_dudousxd_nestjs_durable_core.RunListItem[]>;
225
+ runs(status?: RunStatus | RunStatus[], workflow?: string, tag?: string, attr?: string | string[], namespace?: string, origin?: string, unattributed?: string, limit?: string, offset?: string): Promise<RunListRow[]>;
226
+ /**
227
+ * `(status, origin)` counts for the runs matching the same tag/tenant/attribute predicates as
228
+ * `GET runs`. This is what lets that listing be PAGED at all: the page bounds what the console
229
+ * renders, this bounds nothing and keeps its status and origin chips exact.
230
+ *
231
+ * `status`, `origin` and the page bounds are deliberately NOT accepted — they are the axes being
232
+ * counted, so narrowing by them would report the answer back to itself.
233
+ */
234
+ facets(workflow?: string, tag?: string, attr?: string | string[], namespace?: string): Promise<_dudousxd_nestjs_durable_core.RunFacetRow[]>;
211
235
  /** Prometheus-text metrics (runs/steps by outcome, per-workflow counts) for a scrape. */
212
236
  metrics(): Promise<string>;
213
237
  /** Per-group worker health (queue backlog + live worker heartbeats) for the Workers panel. */
@@ -232,7 +256,7 @@ declare class DurableApiController {
232
256
  * The filter takes the SAME params as `GET runs` and is parsed identically, so "retry all" acts on
233
257
  * exactly the set the operator was looking at rather than a wider one.
234
258
  */
235
- bulk(action: 'retry' | 'cancel', status?: RunStatus, tag?: string, workflow?: string, attr?: string | string[], compensate?: string, namespace?: string, origin?: string): Promise<{
259
+ bulk(action: 'retry' | 'cancel', status?: RunStatus, tag?: string, workflow?: string, attr?: string | string[], compensate?: string, namespace?: string, origin?: string, unattributed?: string): Promise<{
236
260
  matched: number;
237
261
  applied: number;
238
262
  }>;
@@ -101,6 +101,11 @@ var DashboardService = class {
101
101
  listRuns(query) {
102
102
  return this.gateway.listRuns(query);
103
103
  }
104
+ /** `(status, origin)` counts over the same predicates {@link listRuns} pages — what keeps the
105
+ * console's chips exact while its list is bounded to a page. */
106
+ runFacets(query) {
107
+ return this.gateway.runFacets(query);
108
+ }
104
109
  /** This deployment's durable role (control plane vs tenant) + tenant name — for the dashboard header
105
110
  * badge. Routes through the gateway, which knows its own topology (store-backed = operator, proxy =
106
111
  * tenant). Works on both topologies (no store/engine needed). */
@@ -246,6 +251,13 @@ function parseAttrFilters(attr) {
246
251
  }
247
252
  __name(parseAttrFilters, "parseAttrFilters");
248
253
 
254
+ // src/server/run-list-row.ts
255
+ function toRunListRow(run) {
256
+ const { input: _input, output: _output, error: _error, ...row } = run;
257
+ return row;
258
+ }
259
+ __name(toRunListRow, "toRunListRow");
260
+
249
261
  // src/server/durable-api.controller.ts
250
262
  function _ts_decorate2(decorators, target, key, desc) {
251
263
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -264,6 +276,41 @@ function _ts_param2(paramIndex, decorator) {
264
276
  };
265
277
  }
266
278
  __name(_ts_param2, "_ts_param");
279
+ function pageBounds(limit, offset) {
280
+ const bound = /* @__PURE__ */ __name((raw) => {
281
+ const n = Number(raw);
282
+ return raw !== void 0 && raw !== "" && Number.isInteger(n) && n >= 0 ? n : void 0;
283
+ }, "bound");
284
+ const l = bound(limit);
285
+ const o = bound(offset);
286
+ return {
287
+ ...l !== void 0 ? {
288
+ limit: l
289
+ } : {},
290
+ ...o !== void 0 ? {
291
+ offset: o
292
+ } : {}
293
+ };
294
+ }
295
+ __name(pageBounds, "pageBounds");
296
+ function statusPredicate(status) {
297
+ if (Array.isArray(status)) return status.length ? {
298
+ statuses: status
299
+ } : {};
300
+ return status ? {
301
+ status
302
+ } : {};
303
+ }
304
+ __name(statusPredicate, "statusPredicate");
305
+ function originPredicate(origin, unattributed) {
306
+ if (unattributed === "true" || unattributed === "1") return {
307
+ origin: null
308
+ };
309
+ return origin ? {
310
+ origin
311
+ } : {};
312
+ }
313
+ __name(originPredicate, "originPredicate");
267
314
  var DurableApiController = class {
268
315
  static {
269
316
  __name(this, "DurableApiController");
@@ -280,14 +327,32 @@ var DurableApiController = class {
280
327
  * A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
281
328
  * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console.
282
329
  */
283
- runs(status, workflow, tag, attr, namespace, origin) {
284
- return this.dashboard.listRuns({
285
- status,
330
+ async runs(status, workflow, tag, attr, namespace, origin, unattributed, limit, offset) {
331
+ const runs = await this.dashboard.listRuns({
332
+ ...statusPredicate(status),
286
333
  workflow,
287
334
  tag,
288
335
  attributes: parseAttrFilters(attr),
289
336
  namespace: namespace || void 0,
290
- origin: origin || void 0
337
+ ...originPredicate(origin, unattributed),
338
+ ...pageBounds(limit, offset)
339
+ });
340
+ return runs.map(toRunListRow);
341
+ }
342
+ /**
343
+ * `(status, origin)` counts for the runs matching the same tag/tenant/attribute predicates as
344
+ * `GET runs`. This is what lets that listing be PAGED at all: the page bounds what the console
345
+ * renders, this bounds nothing and keeps its status and origin chips exact.
346
+ *
347
+ * `status`, `origin` and the page bounds are deliberately NOT accepted — they are the axes being
348
+ * counted, so narrowing by them would report the answer back to itself.
349
+ */
350
+ facets(workflow, tag, attr, namespace) {
351
+ return this.dashboard.runFacets({
352
+ workflow,
353
+ tag,
354
+ attributes: parseAttrFilters(attr),
355
+ namespace: namespace || void 0
291
356
  });
292
357
  }
293
358
  /** Prometheus-text metrics (runs/steps by outcome, per-workflow counts) for a scrape. */
@@ -324,14 +389,17 @@ var DurableApiController = class {
324
389
  * The filter takes the SAME params as `GET runs` and is parsed identically, so "retry all" acts on
325
390
  * exactly the set the operator was looking at rather than a wider one.
326
391
  */
327
- bulk(action, status, tag, workflow, attr, compensate, namespace, origin) {
392
+ bulk(action, status, tag, workflow, attr, compensate, namespace, origin, unattributed) {
328
393
  return this.dashboard.bulk(action === "cancel" ? "cancel" : "retry", {
329
394
  status,
330
395
  tag,
331
396
  workflow,
332
397
  attributes: parseAttrFilters(attr),
333
398
  namespace: namespace || void 0,
334
- origin: origin || void 0
399
+ // The unattributed bucket is a scope a console can actually SELECT, so a bulk action launched
400
+ // under it must be narrowed to it. Dropping the param would widen a retry/cancel to every
401
+ // origin — acting on runs the operator was not looking at.
402
+ ...originPredicate(origin, unattributed)
335
403
  }, {
336
404
  compensate: compensate === "true"
337
405
  });
@@ -382,17 +450,38 @@ _ts_decorate2([
382
450
  _ts_param2(3, Query("attr")),
383
451
  _ts_param2(4, Query("namespace")),
384
452
  _ts_param2(5, Query("origin")),
453
+ _ts_param2(6, Query("unattributed")),
454
+ _ts_param2(7, Query("limit")),
455
+ _ts_param2(8, Query("offset")),
385
456
  _ts_metadata2("design:type", Function),
386
457
  _ts_metadata2("design:paramtypes", [
387
- typeof RunStatus === "undefined" ? Object : RunStatus,
458
+ Object,
388
459
  String,
389
460
  String,
390
461
  Object,
391
462
  String,
463
+ String,
464
+ String,
465
+ String,
392
466
  String
393
467
  ]),
394
- _ts_metadata2("design:returntype", void 0)
468
+ _ts_metadata2("design:returntype", Promise)
395
469
  ], DurableApiController.prototype, "runs", null);
470
+ _ts_decorate2([
471
+ Get("runs/facets"),
472
+ _ts_param2(0, Query("workflow")),
473
+ _ts_param2(1, Query("tag")),
474
+ _ts_param2(2, Query("attr")),
475
+ _ts_param2(3, Query("namespace")),
476
+ _ts_metadata2("design:type", Function),
477
+ _ts_metadata2("design:paramtypes", [
478
+ String,
479
+ String,
480
+ Object,
481
+ String
482
+ ]),
483
+ _ts_metadata2("design:returntype", void 0)
484
+ ], DurableApiController.prototype, "facets", null);
396
485
  _ts_decorate2([
397
486
  Get("metrics"),
398
487
  Header("Content-Type", "text/plain; version=0.0.4"),
@@ -460,6 +549,7 @@ _ts_decorate2([
460
549
  _ts_param2(5, Query("compensate")),
461
550
  _ts_param2(6, Query("namespace")),
462
551
  _ts_param2(7, Query("origin")),
552
+ _ts_param2(8, Query("unattributed")),
463
553
  _ts_metadata2("design:type", Function),
464
554
  _ts_metadata2("design:paramtypes", [
465
555
  String,
@@ -469,6 +559,7 @@ _ts_decorate2([
469
559
  Object,
470
560
  String,
471
561
  String,
562
+ String,
472
563
  String
473
564
  ]),
474
565
  _ts_metadata2("design:returntype", void 0)