@dudousxd/nestjs-durable-dashboard 0.54.0 → 0.55.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/client/durable-client.d.ts +6 -1
  2. package/dist/client/durable-client.d.ts.map +1 -1
  3. package/dist/client/durable-client.js +9 -46
  4. package/dist/client/durable-client.js.map +1 -1
  5. package/dist/server/index.cjs +223 -1341
  6. package/dist/server/index.cjs.map +1 -1
  7. package/dist/server/index.d.cts +101 -388
  8. package/dist/server/index.d.ts +101 -388
  9. package/dist/server/index.js +208 -1320
  10. package/dist/server/index.js.map +1 -1
  11. package/dist/spa/assets/{bench-Dee6-QN_.js → bench-DCclNvcZ.js} +1 -1
  12. package/dist/spa/assets/index-B-wtX4GV.js +66 -0
  13. package/dist/spa/assets/{index-RjxbO7dU.js → index-ChjKRQZx.js} +1 -1
  14. package/dist/spa/assets/{preview-BscU9n0o.js → preview-CdsjvOrK.js} +1 -1
  15. package/dist/spa/bench.html +2 -2
  16. package/dist/spa/index.html +2 -2
  17. package/dist/spa/preview.html +2 -2
  18. package/package.json +6 -19
  19. package/dist/client/console-session.d.ts +0 -63
  20. package/dist/client/console-session.d.ts.map +0 -1
  21. package/dist/client/console-session.js +0 -107
  22. package/dist/client/console-session.js.map +0 -1
  23. package/dist/react/index.d.ts +0 -4
  24. package/dist/react/index.d.ts.map +0 -1
  25. package/dist/react/index.js +0 -14
  26. package/dist/react/index.js.map +0 -1
  27. package/dist/react/open-console-button.d.ts +0 -26
  28. package/dist/react/open-console-button.d.ts.map +0 -1
  29. package/dist/react/open-console-button.js +0 -26
  30. package/dist/react/open-console-button.js.map +0 -1
  31. package/dist/react/use-open-console.d.ts +0 -40
  32. package/dist/react/use-open-console.d.ts.map +0 -1
  33. package/dist/react/use-open-console.js +0 -77
  34. package/dist/react/use-open-console.js.map +0 -1
  35. package/dist/spa/assets/index-VXNPW483.js +0 -66
@@ -24,21 +24,15 @@ var index_exports = {};
24
24
  __export(index_exports, {
25
25
  DASHBOARD_API_PATH: () => DASHBOARD_API_PATH,
26
26
  DASHBOARD_BASE_PATH: () => DASHBOARD_BASE_PATH,
27
- DASHBOARD_GATE: () => DASHBOARD_GATE,
28
- DURABLE_DASHBOARD_TOKEN_ENV: () => DURABLE_DASHBOARD_TOKEN_ENV,
27
+ DASHBOARD_PROTECTION_CHECK: () => DASHBOARD_PROTECTION_CHECK,
29
28
  DashboardService: () => DashboardService,
30
29
  DurableApiController: () => DurableApiController,
30
+ DurableApiControllerBase: () => DurableApiControllerBase,
31
31
  DurableApiModule: () => DurableApiModule,
32
- DurableApiSessionGuard: () => DurableApiSessionGuard,
33
- DurableAuthController: () => DurableAuthController,
34
- DurableDashboardGateGuard: () => DurableDashboardGateGuard,
35
32
  DurableDashboardModule: () => DurableDashboardModule,
36
33
  DurableUiController: () => DurableUiController,
37
- DurableUiSessionGuard: () => DurableUiSessionGuard,
38
- dashboardGateProvider: () => dashboardGateProvider,
39
- readDashboardToken: () => readDashboardToken,
40
- reportDashboardGate: () => reportDashboardGate,
41
- resolveDashboardGate: () => resolveDashboardGate
34
+ DurableUiControllerBase: () => DurableUiControllerBase,
35
+ UNPROTECTED_CONSOLE_IN_PRODUCTION: () => UNPROTECTED_CONSOLE_IN_PRODUCTION
42
36
  });
43
37
  module.exports = __toCommonJS(index_exports);
44
38
 
@@ -437,87 +431,6 @@ __name(runValueAxisFor, "runValueAxisFor");
437
431
 
438
432
  // src/server/not-modified.ts
439
433
  var import_common2 = require("@nestjs/common");
440
-
441
- // src/server/auth/response.ts
442
- function isRecord(value) {
443
- return typeof value === "object" && value !== null;
444
- }
445
- __name(isRecord, "isRecord");
446
- function isRawCookieResponse(value) {
447
- return isRecord(value) && typeof value.getHeader === "function" && typeof value.setHeader === "function";
448
- }
449
- __name(isRawCookieResponse, "isRawCookieResponse");
450
- function resolveCookieResponse(response) {
451
- if (isRawCookieResponse(response)) return response;
452
- if (isRecord(response) && isRawCookieResponse(response.raw)) return response.raw;
453
- return null;
454
- }
455
- __name(resolveCookieResponse, "resolveCookieResponse");
456
- function existingSetCookies(response) {
457
- const current = response.getHeader("set-cookie");
458
- if (Array.isArray(current)) return current;
459
- if (typeof current === "string") return [
460
- current
461
- ];
462
- return [];
463
- }
464
- __name(existingSetCookies, "existingSetCookies");
465
- function appendSetCookie(response, cookie) {
466
- const raw = resolveCookieResponse(response);
467
- if (!raw) return;
468
- raw.setHeader("set-cookie", [
469
- ...existingSetCookies(raw),
470
- cookie
471
- ]);
472
- }
473
- __name(appendSetCookie, "appendSetCookie");
474
- function isRawRedirectResponse(value) {
475
- return isRecord(value) && typeof value.getHeader === "function" && typeof value.setHeader === "function" && typeof value.end === "function";
476
- }
477
- __name(isRawRedirectResponse, "isRawRedirectResponse");
478
- function resolveRedirectResponse(response) {
479
- if (isRawRedirectResponse(response)) return response;
480
- if (isRecord(response) && isRawRedirectResponse(response.raw)) return response.raw;
481
- return null;
482
- }
483
- __name(resolveRedirectResponse, "resolveRedirectResponse");
484
- function redirectRaw(response, location, status = 302) {
485
- const raw = resolveRedirectResponse(response);
486
- if (!raw) return;
487
- raw.statusCode = status;
488
- raw.setHeader("location", location);
489
- raw.end();
490
- }
491
- __name(redirectRaw, "redirectRaw");
492
- function responseAlreadyWritten(response) {
493
- const raw = resolveRedirectResponse(response);
494
- return raw?.headersSent === true;
495
- }
496
- __name(responseAlreadyWritten, "responseAlreadyWritten");
497
- function writeHtmlRaw(response, html, status = 200) {
498
- const raw = resolveRedirectResponse(response);
499
- if (!raw) return;
500
- raw.statusCode = status;
501
- raw.setHeader("content-type", "text/html; charset=utf-8");
502
- raw.setHeader("cache-control", "no-store, must-revalidate");
503
- raw.end(html);
504
- }
505
- __name(writeHtmlRaw, "writeHtmlRaw");
506
- function setRawHeader(response, name, value) {
507
- resolveCookieResponse(response)?.setHeader(name, value);
508
- }
509
- __name(setRawHeader, "setRawHeader");
510
- function writeNotModifiedRaw(response, etag) {
511
- const raw = resolveRedirectResponse(response);
512
- if (!raw) return;
513
- raw.statusCode = 304;
514
- raw.setHeader("etag", etag);
515
- raw.setHeader("cache-control", "private, no-cache");
516
- raw.end();
517
- }
518
- __name(writeNotModifiedRaw, "writeNotModifiedRaw");
519
-
520
- // src/server/not-modified.ts
521
434
  function _ts_decorate2(decorators, target, key, desc) {
522
435
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
523
436
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -532,6 +445,31 @@ function _ts_decorate2(decorators, target, key, desc) {
532
445
  return c > 3 && r && Object.defineProperty(target, key, r), r;
533
446
  }
534
447
  __name(_ts_decorate2, "_ts_decorate");
448
+ function isRawResponse(value) {
449
+ if (typeof value !== "object" || value === null) return false;
450
+ const candidate = value;
451
+ return typeof candidate.setHeader === "function" && typeof candidate.end === "function";
452
+ }
453
+ __name(isRawResponse, "isRawResponse");
454
+ function rawResponse(response) {
455
+ if (isRawResponse(response)) return response;
456
+ const raw = response?.raw;
457
+ return isRawResponse(raw) ? raw : null;
458
+ }
459
+ __name(rawResponse, "rawResponse");
460
+ function setRawHeader(response, name, value) {
461
+ rawResponse(response)?.setHeader(name, value);
462
+ }
463
+ __name(setRawHeader, "setRawHeader");
464
+ function writeNotModifiedRaw(response, etag) {
465
+ const raw = rawResponse(response);
466
+ if (!raw) return;
467
+ raw.statusCode = 304;
468
+ raw.setHeader("etag", etag);
469
+ raw.setHeader("cache-control", "private, no-cache");
470
+ raw.end();
471
+ }
472
+ __name(writeNotModifiedRaw, "writeNotModifiedRaw");
535
473
  var NotModifiedException = class extends import_common2.HttpException {
536
474
  static {
537
475
  __name(this, "NotModifiedException");
@@ -847,10 +785,10 @@ var RunQueryAdapter = class {
847
785
  }
848
786
  unsupported(clause, "equals, notEquals, gt, gte, lt, lte, in");
849
787
  }
850
- applyOffsetPagination(qb, page2, size) {
788
+ applyOffsetPagination(qb, page, size) {
851
789
  this.draft(qb).narrow({
852
790
  limit: size,
853
- offset: (page2 - 1) * size
791
+ offset: (page - 1) * size
854
792
  });
855
793
  }
856
794
  /**
@@ -1194,9 +1132,9 @@ function _ts_param2(paramIndex, decorator) {
1194
1132
  }
1195
1133
  __name(_ts_param2, "_ts_param");
1196
1134
  var FAN_INLINE_MAX = 50;
1197
- var DurableApiController = class {
1135
+ var DurableApiControllerBase = class {
1198
1136
  static {
1199
- __name(this, "DurableApiController");
1137
+ __name(this, "DurableApiControllerBase");
1200
1138
  }
1201
1139
  dashboard;
1202
1140
  runner;
@@ -1326,7 +1264,7 @@ var DurableApiController = class {
1326
1264
  }
1327
1265
  /** One page of a summarized fan's members, in seq order. Versioned like {@link run}. */
1328
1266
  async fanMembers(id, group, offset, limit, failed, ifNoneMatch, response) {
1329
- const page2 = await this.dashboard.getFanMembers(id, group, {
1267
+ const page = await this.dashboard.getFanMembers(id, group, {
1330
1268
  offset: offset === void 0 ? void 0 : Number(offset),
1331
1269
  limit: limit === void 0 ? void 0 : Number(limit),
1332
1270
  failedOnly: failed === "true",
@@ -1334,8 +1272,8 @@ var DurableApiController = class {
1334
1272
  ifNoneMatch
1335
1273
  }
1336
1274
  });
1337
- if (!page2) throw new import_common5.NotFoundException(`fan ${group} of run ${id} not found`);
1338
- const { etag, notModified, ...body } = page2;
1275
+ if (!page) throw new import_common5.NotFoundException(`fan ${group} of run ${id} not found`);
1276
+ const { etag, notModified, ...body } = page;
1339
1277
  if (etag) {
1340
1278
  if (notModified) throw new NotModifiedException(etag);
1341
1279
  setEtag(response, etag);
@@ -1433,7 +1371,7 @@ _ts_decorate5([
1433
1371
  typeof RunQueryDraft === "undefined" ? Object : RunQueryDraft
1434
1372
  ]),
1435
1373
  _ts_metadata4("design:returntype", Promise)
1436
- ], DurableApiController.prototype, "runs", null);
1374
+ ], DurableApiControllerBase.prototype, "runs", null);
1437
1375
  _ts_decorate5([
1438
1376
  (0, import_common5.Get)("runs/facets"),
1439
1377
  _ts_param2(0, (0, import_nestjs_filter2.ApplyFilter)(RunFilter)),
@@ -1442,7 +1380,7 @@ _ts_decorate5([
1442
1380
  typeof RunQueryDraft === "undefined" ? Object : RunQueryDraft
1443
1381
  ]),
1444
1382
  _ts_metadata4("design:returntype", void 0)
1445
- ], DurableApiController.prototype, "facets", null);
1383
+ ], DurableApiControllerBase.prototype, "facets", null);
1446
1384
  _ts_decorate5([
1447
1385
  (0, import_common5.Get)("runs/values"),
1448
1386
  _ts_param2(0, (0, import_common5.Query)()),
@@ -1451,20 +1389,20 @@ _ts_decorate5([
1451
1389
  typeof Record === "undefined" ? Object : Record
1452
1390
  ]),
1453
1391
  _ts_metadata4("design:returntype", void 0)
1454
- ], DurableApiController.prototype, "values", null);
1392
+ ], DurableApiControllerBase.prototype, "values", null);
1455
1393
  _ts_decorate5([
1456
1394
  (0, import_common5.Get)("metrics"),
1457
1395
  (0, import_common5.Header)("Content-Type", "text/plain; version=0.0.4"),
1458
1396
  _ts_metadata4("design:type", Function),
1459
1397
  _ts_metadata4("design:paramtypes", []),
1460
1398
  _ts_metadata4("design:returntype", void 0)
1461
- ], DurableApiController.prototype, "metrics", null);
1399
+ ], DurableApiControllerBase.prototype, "metrics", null);
1462
1400
  _ts_decorate5([
1463
1401
  (0, import_common5.Get)("workers"),
1464
1402
  _ts_metadata4("design:type", Function),
1465
1403
  _ts_metadata4("design:paramtypes", []),
1466
1404
  _ts_metadata4("design:returntype", void 0)
1467
- ], DurableApiController.prototype, "workers", null);
1405
+ ], DurableApiControllerBase.prototype, "workers", null);
1468
1406
  _ts_decorate5([
1469
1407
  (0, import_common5.Get)("schedules"),
1470
1408
  _ts_param2(0, (0, import_common5.Query)("namespace")),
@@ -1481,7 +1419,7 @@ _ts_decorate5([
1481
1419
  String
1482
1420
  ]),
1483
1421
  _ts_metadata4("design:returntype", void 0)
1484
- ], DurableApiController.prototype, "schedules", null);
1422
+ ], DurableApiControllerBase.prototype, "schedules", null);
1485
1423
  _ts_decorate5([
1486
1424
  (0, import_common5.Post)("schedules/:id/pause"),
1487
1425
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1490,7 +1428,7 @@ _ts_decorate5([
1490
1428
  String
1491
1429
  ]),
1492
1430
  _ts_metadata4("design:returntype", void 0)
1493
- ], DurableApiController.prototype, "pauseSchedule", null);
1431
+ ], DurableApiControllerBase.prototype, "pauseSchedule", null);
1494
1432
  _ts_decorate5([
1495
1433
  (0, import_common5.Post)("schedules/:id/resume"),
1496
1434
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1499,7 +1437,7 @@ _ts_decorate5([
1499
1437
  String
1500
1438
  ]),
1501
1439
  _ts_metadata4("design:returntype", void 0)
1502
- ], DurableApiController.prototype, "resumeSchedule", null);
1440
+ ], DurableApiControllerBase.prototype, "resumeSchedule", null);
1503
1441
  _ts_decorate5([
1504
1442
  (0, import_common5.Post)("schedules/:id/trigger"),
1505
1443
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1508,7 +1446,7 @@ _ts_decorate5([
1508
1446
  String
1509
1447
  ]),
1510
1448
  _ts_metadata4("design:returntype", void 0)
1511
- ], DurableApiController.prototype, "triggerSchedule", null);
1449
+ ], DurableApiControllerBase.prototype, "triggerSchedule", null);
1512
1450
  _ts_decorate5([
1513
1451
  (0, import_common5.Get)("workflows/:name/lifecycle"),
1514
1452
  _ts_param2(0, (0, import_common5.Param)("name")),
@@ -1517,13 +1455,13 @@ _ts_decorate5([
1517
1455
  String
1518
1456
  ]),
1519
1457
  _ts_metadata4("design:returntype", Promise)
1520
- ], DurableApiController.prototype, "workflowLifecycle", null);
1458
+ ], DurableApiControllerBase.prototype, "workflowLifecycle", null);
1521
1459
  _ts_decorate5([
1522
1460
  (0, import_common5.Get)("topology"),
1523
1461
  _ts_metadata4("design:type", Function),
1524
1462
  _ts_metadata4("design:paramtypes", []),
1525
1463
  _ts_metadata4("design:returntype", void 0)
1526
- ], DurableApiController.prototype, "topology", null);
1464
+ ], DurableApiControllerBase.prototype, "topology", null);
1527
1465
  _ts_decorate5([
1528
1466
  (0, import_common5.Get)("runs/:id"),
1529
1467
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1540,7 +1478,7 @@ _ts_decorate5([
1540
1478
  Object
1541
1479
  ]),
1542
1480
  _ts_metadata4("design:returntype", Promise)
1543
- ], DurableApiController.prototype, "run", null);
1481
+ ], DurableApiControllerBase.prototype, "run", null);
1544
1482
  _ts_decorate5([
1545
1483
  (0, import_common5.Get)("runs/:id/fans/:group"),
1546
1484
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1563,7 +1501,7 @@ _ts_decorate5([
1563
1501
  Object
1564
1502
  ]),
1565
1503
  _ts_metadata4("design:returntype", Promise)
1566
- ], DurableApiController.prototype, "fanMembers", null);
1504
+ ], DurableApiControllerBase.prototype, "fanMembers", null);
1567
1505
  _ts_decorate5([
1568
1506
  (0, import_common5.Sse)("runs/:id/stream"),
1569
1507
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1572,7 +1510,7 @@ _ts_decorate5([
1572
1510
  String
1573
1511
  ]),
1574
1512
  _ts_metadata4("design:returntype", void 0)
1575
- ], DurableApiController.prototype, "stream", null);
1513
+ ], DurableApiControllerBase.prototype, "stream", null);
1576
1514
  _ts_decorate5([
1577
1515
  (0, import_common5.Post)("runs/:id/retry"),
1578
1516
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1581,7 +1519,7 @@ _ts_decorate5([
1581
1519
  String
1582
1520
  ]),
1583
1521
  _ts_metadata4("design:returntype", void 0)
1584
- ], DurableApiController.prototype, "retry", null);
1522
+ ], DurableApiControllerBase.prototype, "retry", null);
1585
1523
  _ts_decorate5([
1586
1524
  (0, import_common5.Post)("runs/:id/retry-with-input"),
1587
1525
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1592,7 +1530,7 @@ _ts_decorate5([
1592
1530
  Object
1593
1531
  ]),
1594
1532
  _ts_metadata4("design:returntype", void 0)
1595
- ], DurableApiController.prototype, "retryWithInput", null);
1533
+ ], DurableApiControllerBase.prototype, "retryWithInput", null);
1596
1534
  _ts_decorate5([
1597
1535
  (0, import_common5.Post)("bulk/:action"),
1598
1536
  _ts_param2(0, (0, import_common5.Param)("action")),
@@ -1605,7 +1543,7 @@ _ts_decorate5([
1605
1543
  String
1606
1544
  ]),
1607
1545
  _ts_metadata4("design:returntype", void 0)
1608
- ], DurableApiController.prototype, "bulk", null);
1546
+ ], DurableApiControllerBase.prototype, "bulk", null);
1609
1547
  _ts_decorate5([
1610
1548
  (0, import_common5.Post)("runs/:id/cancel"),
1611
1549
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1616,7 +1554,7 @@ _ts_decorate5([
1616
1554
  String
1617
1555
  ]),
1618
1556
  _ts_metadata4("design:returntype", Promise)
1619
- ], DurableApiController.prototype, "cancel", null);
1557
+ ], DurableApiControllerBase.prototype, "cancel", null);
1620
1558
  _ts_decorate5([
1621
1559
  (0, import_common5.Post)("runs/:id/republish-lifecycle"),
1622
1560
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1627,7 +1565,7 @@ _ts_decorate5([
1627
1565
  Object
1628
1566
  ]),
1629
1567
  _ts_metadata4("design:returntype", Promise)
1630
- ], DurableApiController.prototype, "republishLifecycle", null);
1568
+ ], DurableApiControllerBase.prototype, "republishLifecycle", null);
1631
1569
  _ts_decorate5([
1632
1570
  (0, import_common5.Post)("runs/:id/continue"),
1633
1571
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1636,7 +1574,7 @@ _ts_decorate5([
1636
1574
  String
1637
1575
  ]),
1638
1576
  _ts_metadata4("design:returntype", Promise)
1639
- ], DurableApiController.prototype, "continue", null);
1577
+ ], DurableApiControllerBase.prototype, "continue", null);
1640
1578
  _ts_decorate5([
1641
1579
  (0, import_common5.Post)("runs/:id/redispatch"),
1642
1580
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1645,7 +1583,7 @@ _ts_decorate5([
1645
1583
  String
1646
1584
  ]),
1647
1585
  _ts_metadata4("design:returntype", Promise)
1648
- ], DurableApiController.prototype, "redispatch", null);
1586
+ ], DurableApiControllerBase.prototype, "redispatch", null);
1649
1587
  _ts_decorate5([
1650
1588
  (0, import_common5.Post)("webhooks/:token"),
1651
1589
  _ts_param2(0, (0, import_common5.Param)("token")),
@@ -1656,7 +1594,7 @@ _ts_decorate5([
1656
1594
  Object
1657
1595
  ]),
1658
1596
  _ts_metadata4("design:returntype", Promise)
1659
- ], DurableApiController.prototype, "webhook", null);
1597
+ ], DurableApiControllerBase.prototype, "webhook", null);
1660
1598
  _ts_decorate5([
1661
1599
  (0, import_common5.Get)("runs/:id/events/:key"),
1662
1600
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1667,7 +1605,7 @@ _ts_decorate5([
1667
1605
  String
1668
1606
  ]),
1669
1607
  _ts_metadata4("design:returntype", void 0)
1670
- ], DurableApiController.prototype, "event", null);
1608
+ ], DurableApiControllerBase.prototype, "event", null);
1671
1609
  _ts_decorate5([
1672
1610
  (0, import_common5.Post)("runs/:id/updates/:name"),
1673
1611
  _ts_param2(0, (0, import_common5.Param)("id")),
@@ -1680,8 +1618,8 @@ _ts_decorate5([
1680
1618
  Object
1681
1619
  ]),
1682
1620
  _ts_metadata4("design:returntype", void 0)
1683
- ], DurableApiController.prototype, "update", null);
1684
- DurableApiController = _ts_decorate5([
1621
+ ], DurableApiControllerBase.prototype, "update", null);
1622
+ DurableApiControllerBase = _ts_decorate5([
1685
1623
  (0, import_common5.Controller)(),
1686
1624
  (0, import_common5.UseInterceptors)(import_nestjs_filter2.ApplyFilterInterceptor),
1687
1625
  (0, import_common5.UseFilters)(NotModifiedFilter),
@@ -1690,7 +1628,7 @@ DurableApiController = _ts_decorate5([
1690
1628
  typeof DashboardService === "undefined" ? Object : DashboardService,
1691
1629
  typeof import_nestjs_filter2.FilterRunner === "undefined" ? Object : import_nestjs_filter2.FilterRunner
1692
1630
  ])
1693
- ], DurableApiController);
1631
+ ], DurableApiControllerBase);
1694
1632
  function notFound(error) {
1695
1633
  if (error instanceof Error && error.name === "ScheduleNotFoundError") {
1696
1634
  throw new import_common5.NotFoundException(error.message);
@@ -1705,497 +1643,51 @@ function notSupportedByServer(error) {
1705
1643
  throw error;
1706
1644
  }
1707
1645
  __name(notSupportedByServer, "notSupportedByServer");
1708
-
1709
- // src/server/durable-auth.controller.ts
1710
- var import_common9 = require("@nestjs/common");
1711
-
1712
- // src/server/auth/dashboard-auth-config.ts
1713
- var DASHBOARD_AUTH = Symbol("DASHBOARD_AUTH");
1714
- var DEFAULT_TTL = "8h";
1715
- var DEFAULT_TTL_MS = 8 * 60 * 60 * 1e3;
1716
- var DURATION_UNITS = {
1717
- s: 1e3,
1718
- m: 60 * 1e3,
1719
- h: 60 * 60 * 1e3,
1720
- d: 24 * 60 * 60 * 1e3
1721
- };
1722
- function durationToMs(ttl) {
1723
- const match = /^(\d+)([smhd])$/.exec(ttl.trim());
1724
- if (!match) return DEFAULT_TTL_MS;
1725
- const unit = DURATION_UNITS[match[2] ?? ""];
1726
- if (unit === void 0) return DEFAULT_TTL_MS;
1727
- return Number(match[1]) * unit;
1728
- }
1729
- __name(durationToMs, "durationToMs");
1730
- function resolveDashboardAuth(options) {
1731
- if (options === void 0) return null;
1732
- if (typeof options.secret !== "string" || options.secret === "") {
1733
- throw new Error("DurableDashboardModule: dashboardAuth.secret is required and must be a non-empty string (HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.");
1734
- }
1735
- const modes = [];
1736
- if (options.session !== void 0) {
1737
- if (typeof options.session !== "function") {
1738
- throw new Error("DurableDashboardModule: dashboardAuth.session must be a function.");
1739
- }
1740
- modes.push("session");
1741
- }
1742
- if (options.login !== void 0) {
1743
- if (typeof options.login !== "function") {
1744
- throw new Error("DurableDashboardModule: dashboardAuth.login must be a function.");
1745
- }
1746
- modes.push("login");
1747
- }
1748
- if (options.revalidate !== void 0 && typeof options.revalidate !== "function") {
1749
- throw new Error("DurableDashboardModule: dashboardAuth.revalidate must be a function.");
1750
- }
1751
- if (options.unauthenticatedPage !== void 0 && typeof options.unauthenticatedPage !== "function") {
1752
- throw new Error("DurableDashboardModule: dashboardAuth.unauthenticatedPage must be a function.");
1753
- }
1754
- if (modes.length === 0) {
1755
- throw new Error("DurableDashboardModule: dashboardAuth needs at least one of `session` or `login` (otherwise the cookie can never be minted). Failing closed.");
1756
- }
1757
- return {
1758
- secret: options.secret,
1759
- ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
1760
- modes,
1761
- ...options.session !== void 0 ? {
1762
- session: options.session
1763
- } : {},
1764
- ...options.login !== void 0 ? {
1765
- login: options.login
1766
- } : {},
1767
- ...options.revalidate !== void 0 ? {
1768
- revalidate: options.revalidate
1769
- } : {},
1770
- ...options.unauthenticatedPage !== void 0 ? {
1771
- unauthenticatedPage: options.unauthenticatedPage
1772
- } : {}
1773
- };
1774
- }
1775
- __name(resolveDashboardAuth, "resolveDashboardAuth");
1776
-
1777
- // src/server/auth/login-page.ts
1778
- function page(content, title = "Durable") {
1779
- return `<!doctype html>
1780
- <html lang="en">
1781
- <head>
1782
- <meta charset="utf-8" />
1783
- <meta name="viewport" content="width=device-width, initial-scale=1" />
1784
- <meta name="robots" content="noindex, nofollow" />
1785
- <title>${title}</title>
1786
- <style>
1787
- :root { color-scheme: dark; }
1788
- * { box-sizing: border-box; }
1789
- body {
1790
- margin: 0;
1791
- min-height: 100vh;
1792
- display: flex;
1793
- align-items: center;
1794
- justify-content: center;
1795
- background: #09090b;
1796
- color: #e4e4e7;
1797
- font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1798
- padding: 16px;
1799
- }
1800
- .card {
1801
- width: 100%;
1802
- max-width: 384px;
1803
- border: 1px solid #27272a;
1804
- background: #18181b;
1805
- border-radius: 8px;
1806
- padding: 32px;
1807
- box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5);
1808
- }
1809
- .brand {
1810
- margin: 0 0 24px;
1811
- text-align: center;
1812
- font-size: 18px;
1813
- font-weight: 600;
1814
- color: #34d399;
1815
- }
1816
- h1 {
1817
- margin: 0 0 12px;
1818
- font-size: 16px;
1819
- font-weight: 600;
1820
- color: #f4f4f5;
1821
- }
1822
- p { margin: 0 0 16px; color: #a1a1aa; }
1823
- form { display: flex; flex-direction: column; gap: 16px; }
1824
- label { display: flex; flex-direction: column; gap: 6px; }
1825
- .field-label {
1826
- font-size: 11px;
1827
- text-transform: uppercase;
1828
- letter-spacing: 0.05em;
1829
- color: #71717a;
1830
- }
1831
- input {
1832
- border-radius: 4px;
1833
- border: 1px solid #3f3f46;
1834
- background: #09090b;
1835
- color: #f4f4f5;
1836
- padding: 8px 12px;
1837
- font: inherit;
1838
- outline: none;
1839
- }
1840
- input:focus { border-color: rgb(52 211 153 / 0.6); }
1841
- #error {
1842
- display: none;
1843
- margin: 0;
1844
- font-size: 12px;
1845
- color: #fb7185;
1846
- }
1847
- button, .button {
1848
- margin-top: 8px;
1849
- border-radius: 4px;
1850
- border: 1px solid rgb(52 211 153 / 0.4);
1851
- background: rgb(52 211 153 / 0.1);
1852
- color: #6ee7b7;
1853
- padding: 8px 12px;
1854
- font: inherit;
1855
- font-size: 12px;
1856
- font-weight: 500;
1857
- text-transform: uppercase;
1858
- letter-spacing: 0.05em;
1859
- cursor: pointer;
1860
- display: inline-block;
1861
- text-align: center;
1862
- text-decoration: none;
1863
- box-sizing: border-box;
1864
- }
1865
- button:hover:not(:disabled), .button:hover { background: rgb(52 211 153 / 0.2); }
1866
- button:disabled { opacity: 0.6; cursor: default; }
1867
- </style>
1868
- </head>
1869
- <body>
1870
- <div class="card">
1871
- ${content}
1872
- </div>
1873
- </body>
1874
- </html>`;
1875
- }
1876
- __name(page, "page");
1877
- function renderLoginPage(basePath) {
1878
- const loginAction = `${basePath}/login`;
1879
- const defaultReturnTo = basePath;
1880
- return page(`<p class="brand">Durable</p>
1881
- <form id="login-form" autocomplete="on">
1882
- <label>
1883
- <span class="field-label">Username</span>
1884
- <input id="username" name="username" type="text" autocomplete="username" required autofocus />
1885
- </label>
1886
- <label>
1887
- <span class="field-label">Password</span>
1888
- <input id="password" name="password" type="password" autocomplete="current-password" />
1889
- </label>
1890
- <p id="error" role="alert">Invalid username or password.</p>
1891
- <button id="submit" type="submit">Sign in</button>
1892
- </form>
1893
- <script>
1894
- (function () {
1895
- var LOGIN_ACTION = ${JSON.stringify(loginAction)};
1896
- var DEFAULT_RETURN_TO = ${JSON.stringify(defaultReturnTo)};
1897
- var params = new URLSearchParams(window.location.search);
1898
- var errorBox = document.getElementById('error');
1899
- if (params.get('error')) errorBox.style.display = 'block';
1900
-
1901
- function sameOriginReturnTo(value) {
1902
- if (typeof value !== 'string' || value === '') return DEFAULT_RETURN_TO;
1903
- if (value.charAt(0) !== '/' || value.charAt(1) === '/' || value.indexOf('://') !== -1) {
1904
- return DEFAULT_RETURN_TO;
1905
- }
1906
- return value;
1646
+ var DurableApiController = class extends DurableApiControllerBase {
1647
+ static {
1648
+ __name(this, "DurableApiController");
1907
1649
  }
1650
+ };
1651
+ DurableApiController = _ts_decorate5([
1652
+ (0, import_common5.Controller)()
1653
+ ], DurableApiController);
1908
1654
 
1909
- var form = document.getElementById('login-form');
1910
- var submitButton = document.getElementById('submit');
1911
- form.addEventListener('submit', function (event) {
1912
- event.preventDefault();
1913
- submitButton.disabled = true;
1914
- errorBox.style.display = 'none';
1915
- var returnTo = sameOriginReturnTo(params.get('returnTo'));
1916
- fetch(LOGIN_ACTION, {
1917
- method: 'POST',
1918
- headers: { 'content-type': 'application/json' },
1919
- credentials: 'same-origin',
1920
- body: JSON.stringify({
1921
- username: document.getElementById('username').value,
1922
- password: document.getElementById('password').value,
1923
- returnTo: returnTo,
1924
- }),
1925
- })
1926
- .then(function (response) {
1927
- if (!response.ok) throw new Error('unauthorized');
1928
- return response.json();
1929
- })
1930
- .then(function (data) {
1931
- window.location.href = data.redirectTo || DEFAULT_RETURN_TO;
1932
- })
1933
- .catch(function () {
1934
- errorBox.style.display = 'block';
1935
- submitButton.disabled = false;
1936
- });
1937
- });
1938
- })();
1939
- </script>`, "Sign in \u2014 Durable");
1940
- }
1941
- __name(renderLoginPage, "renderLoginPage");
1942
- function renderSessionRequiredPage(basePath) {
1943
- return page(`<h1>Open this console from your application</h1>
1944
- <p>Your session is minted by the host app. Use its console launcher to sign in, then reload.</p>
1945
- <a class="button" href="${basePath}">Retry</a>`);
1946
- }
1947
- __name(renderSessionRequiredPage, "renderSessionRequiredPage");
1948
-
1949
- // src/server/auth/request.ts
1950
- function isRecord2(value) {
1951
- return typeof value === "object" && value !== null;
1952
- }
1953
- __name(isRecord2, "isRecord");
1954
- function readHeaders(request) {
1955
- if (!isRecord2(request)) return {};
1956
- const headers = request.headers;
1957
- return isRecord2(headers) ? headers : {};
1958
- }
1959
- __name(readHeaders, "readHeaders");
1960
- function headerToString(value) {
1961
- if (typeof value === "string") return value;
1962
- if (Array.isArray(value) && value.every((part) => typeof part === "string")) {
1963
- return value.join(",");
1964
- }
1965
- return void 0;
1966
- }
1967
- __name(headerToString, "headerToString");
1968
- function readCookieHeader(request) {
1969
- return headerToString(readHeaders(request).cookie);
1970
- }
1971
- __name(readCookieHeader, "readCookieHeader");
1972
- function isHttpsRequest(request) {
1973
- if (isRecord2(request) && request.protocol === "https") return true;
1974
- const forwarded = headerToString(readHeaders(request)["x-forwarded-proto"]);
1975
- if (forwarded === void 0) return false;
1976
- return forwarded.split(",").map((proto) => proto.trim().toLowerCase()).includes("https");
1977
- }
1978
- __name(isHttpsRequest, "isHttpsRequest");
1979
- function originalRequestUrl(request) {
1980
- if (!isRecord2(request)) return "/";
1981
- if (typeof request.originalUrl === "string" && request.originalUrl !== "") {
1982
- return request.originalUrl;
1983
- }
1984
- if (typeof request.url === "string" && request.url !== "") return request.url;
1985
- return "/";
1986
- }
1987
- __name(originalRequestUrl, "originalRequestUrl");
1988
- function sanitizeReturnTo(candidate, fallback) {
1989
- if (typeof candidate !== "string") return fallback;
1990
- if (!candidate.startsWith("/")) return fallback;
1991
- if (candidate.startsWith("//")) return fallback;
1992
- if (candidate.includes("://")) return fallback;
1993
- return candidate;
1994
- }
1995
- __name(sanitizeReturnTo, "sanitizeReturnTo");
1655
+ // src/server/durable-dashboard.module.ts
1656
+ var import_reflect_metadata2 = require("reflect-metadata");
1657
+ var import_nestjs_filter3 = require("@dudousxd/nestjs-filter");
1658
+ var import_common7 = require("@nestjs/common");
1659
+ var import_core = require("@nestjs/core");
1996
1660
 
1997
- // src/server/auth/cookie-header.ts
1998
- function parseCookieHeader(header) {
1999
- const cookies = {};
2000
- if (typeof header !== "string" || header === "") return cookies;
2001
- for (const segment of header.split(";")) {
2002
- const eq = segment.indexOf("=");
2003
- if (eq <= 0) continue;
2004
- const name = segment.slice(0, eq).trim();
2005
- if (name === "") continue;
2006
- let rawValue = segment.slice(eq + 1).trim();
2007
- if (rawValue.length >= 2 && rawValue.startsWith('"') && rawValue.endsWith('"')) {
2008
- rawValue = rawValue.slice(1, -1);
2009
- }
2010
- if (name in cookies) continue;
2011
- try {
2012
- cookies[name] = decodeURIComponent(rawValue);
2013
- } catch {
2014
- cookies[name] = rawValue;
1661
+ // src/server/controller-decorators.ts
1662
+ var import_reflect_metadata = require("reflect-metadata");
1663
+ var CAN_ANYONE_METADATA = "authorization:can-anyone";
1664
+ function markOpenToAuthorization(controller) {
1665
+ Reflect.defineMetadata(CAN_ANYONE_METADATA, true, controller);
1666
+ }
1667
+ __name(markOpenToAuthorization, "markOpenToAuthorization");
1668
+ function controllerFor(base, decorators) {
1669
+ if (decorators === void 0 || decorators.length === 0) return base;
1670
+ const derived = class extends base {
1671
+ static {
1672
+ __name(this, "derived");
2015
1673
  }
2016
- }
2017
- return cookies;
2018
- }
2019
- __name(parseCookieHeader, "parseCookieHeader");
2020
- function serializeSetCookie(name, value, options) {
2021
- const parts = [
2022
- `${name}=${options.clear ? "" : encodeURIComponent(value)}`
2023
- ];
2024
- parts.push(`Path=${options.path}`);
2025
- parts.push("HttpOnly");
2026
- parts.push("SameSite=Lax");
2027
- if (options.secure) parts.push("Secure");
2028
- if (options.clear) {
2029
- parts.push("Max-Age=0");
2030
- parts.push("Expires=Thu, 01 Jan 1970 00:00:00 GMT");
2031
- } else {
2032
- parts.push(`Max-Age=${options.maxAgeSeconds}`);
2033
- }
2034
- return parts.join("; ");
2035
- }
2036
- __name(serializeSetCookie, "serializeSetCookie");
2037
-
2038
- // src/server/auth/session-cookie.ts
2039
- var import_node_crypto = require("crypto");
2040
- var EXP_GRACE_MS = 3e4;
2041
- function base64urlEncode(value) {
2042
- return Buffer.from(value, "utf8").toString("base64url");
2043
- }
2044
- __name(base64urlEncode, "base64urlEncode");
2045
- function base64urlDecode(value) {
2046
- return Buffer.from(value, "base64url").toString("utf8");
2047
- }
2048
- __name(base64urlDecode, "base64urlDecode");
2049
- function hmac(secret, payload) {
2050
- return (0, import_node_crypto.createHmac)("sha256", secret).update(payload).digest("base64url");
2051
- }
2052
- __name(hmac, "hmac");
2053
- function signSessionCookie(user, options) {
2054
- const issuedAt = options.now ?? Date.now();
2055
- const session = {
2056
- sub: user.id,
2057
- ...user.name !== void 0 ? {
2058
- name: user.name
2059
- } : {},
2060
- roles: user.roles ?? [],
2061
- iat: issuedAt,
2062
- exp: issuedAt + options.ttlMs
2063
- };
2064
- const encodedPayload = base64urlEncode(JSON.stringify(session));
2065
- const signature = hmac(options.secret, encodedPayload);
2066
- return `${encodedPayload}.${signature}`;
2067
- }
2068
- __name(signSessionCookie, "signSessionCookie");
2069
- function isSessionPayload(value) {
2070
- if (typeof value !== "object" || value === null) return false;
2071
- const record = {
2072
- ...value
2073
1674
  };
2074
- if (typeof record.sub !== "string") return false;
2075
- if (record.name !== void 0 && typeof record.name !== "string") return false;
2076
- if (!Array.isArray(record.roles)) return false;
2077
- if (!record.roles.every((role) => typeof role === "string")) return false;
2078
- if (typeof record.iat !== "number" || !Number.isFinite(record.iat)) return false;
2079
- if (typeof record.exp !== "number" || !Number.isFinite(record.exp)) return false;
2080
- return true;
2081
- }
2082
- __name(isSessionPayload, "isSessionPayload");
2083
- function verifySessionCookie(value, options) {
2084
- try {
2085
- const dot = value.indexOf(".");
2086
- if (dot <= 0 || dot === value.length - 1) return null;
2087
- const encodedPayload = value.slice(0, dot);
2088
- const providedSignature = value.slice(dot + 1);
2089
- const expectedSignature = hmac(options.secret, encodedPayload);
2090
- const provided = Buffer.from(providedSignature, "base64url");
2091
- const expected = Buffer.from(expectedSignature, "base64url");
2092
- if (provided.length !== expected.length) return null;
2093
- if (!(0, import_node_crypto.timingSafeEqual)(provided, expected)) return null;
2094
- const decoded = JSON.parse(base64urlDecode(encodedPayload));
2095
- if (!isSessionPayload(decoded)) return null;
2096
- const now = options.now ?? Date.now();
2097
- if (now > decoded.exp + EXP_GRACE_MS) return null;
2098
- const session = {
2099
- sub: decoded.sub,
2100
- ...decoded.name !== void 0 ? {
2101
- name: decoded.name
2102
- } : {},
2103
- roles: decoded.roles,
2104
- iat: decoded.iat,
2105
- exp: decoded.exp
2106
- };
2107
- return session;
2108
- } catch {
2109
- return null;
2110
- }
2111
- }
2112
- __name(verifySessionCookie, "verifySessionCookie");
2113
-
2114
- // src/server/auth/session-cookie-io.ts
2115
- var SESSION_COOKIE_NAME = "durable_dashboard_session";
2116
- var COOKIE_PATH = "/";
2117
- function issueSessionCookie(user, context) {
2118
- const value = signSessionCookie(user, {
2119
- secret: context.auth.secret,
2120
- ttlMs: context.auth.ttlMs,
2121
- ...context.now !== void 0 ? {
2122
- now: context.now
2123
- } : {}
1675
+ Object.defineProperty(derived, "name", {
1676
+ value: base.name
2124
1677
  });
2125
- const cookie = serializeSetCookie(SESSION_COOKIE_NAME, value, {
2126
- path: COOKIE_PATH,
2127
- maxAgeSeconds: Math.floor(context.auth.ttlMs / 1e3),
2128
- secure: isHttpsRequest(context.request)
2129
- });
2130
- appendSetCookie(context.response, cookie);
2131
- }
2132
- __name(issueSessionCookie, "issueSessionCookie");
2133
- function clearSessionCookie(context) {
2134
- const cookie = serializeSetCookie(SESSION_COOKIE_NAME, "", {
2135
- path: COOKIE_PATH,
2136
- maxAgeSeconds: 0,
2137
- secure: isHttpsRequest(context.request),
2138
- clear: true
2139
- });
2140
- appendSetCookie(context.response, cookie);
2141
- }
2142
- __name(clearSessionCookie, "clearSessionCookie");
2143
- function readSessionFromRequest(auth, request) {
2144
- const cookieValue = parseCookieHeader(readCookieHeader(request))[SESSION_COOKIE_NAME];
2145
- if (cookieValue === void 0) return null;
2146
- return verifySessionCookie(cookieValue, {
2147
- secret: auth.secret
2148
- });
2149
- }
2150
- __name(readSessionFromRequest, "readSessionFromRequest");
2151
- var inFlightRevalidations = /* @__PURE__ */ new Map();
2152
- function revalidateOnce(auth, user) {
2153
- const revalidate = auth.revalidate;
2154
- if (!revalidate) return Promise.resolve(true);
2155
- const key = `${auth.secret}:${user.id}`;
2156
- const inFlight = inFlightRevalidations.get(key);
2157
- if (inFlight) return inFlight;
2158
- const call = Promise.resolve().then(() => revalidate(user)).catch(() => false).finally(() => {
2159
- inFlightRevalidations.delete(key);
2160
- });
2161
- inFlightRevalidations.set(key, call);
2162
- return call;
2163
- }
2164
- __name(revalidateOnce, "revalidateOnce");
2165
- async function maybeRenewSession(auth, session, request, response, now = Date.now()) {
2166
- if (now - session.iat <= auth.ttlMs / 2) return true;
2167
- const user = {
2168
- id: session.sub,
2169
- ...session.name !== void 0 ? {
2170
- name: session.name
2171
- } : {},
2172
- roles: session.roles
2173
- };
2174
- const allowed = await revalidateOnce(auth, user);
2175
- if (!allowed) {
2176
- clearSessionCookie({
2177
- request,
2178
- response
2179
- });
2180
- return false;
1678
+ markOpenToAuthorization(derived);
1679
+ let decorated = derived;
1680
+ for (const decorator of decorators) {
1681
+ decorated = decorator(decorated) ?? decorated;
2181
1682
  }
2182
- issueSessionCookie(user, {
2183
- auth,
2184
- request,
2185
- response,
2186
- now
2187
- });
2188
- return true;
1683
+ return decorated;
2189
1684
  }
2190
- __name(maybeRenewSession, "maybeRenewSession");
1685
+ __name(controllerFor, "controllerFor");
2191
1686
 
2192
1687
  // src/server/durable-ui.controller.ts
2193
1688
  var import_node_fs = require("fs");
2194
1689
  var import_node_path = require("path");
2195
1690
  var import_node_url = require("url");
2196
- var import_common8 = require("@nestjs/common");
2197
-
2198
- // src/server/auth/login-redirect.exception.ts
2199
1691
  var import_common6 = require("@nestjs/common");
2200
1692
  function _ts_decorate6(decorators, target, key, desc) {
2201
1693
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2211,46 +1703,6 @@ function _ts_decorate6(decorators, target, key, desc) {
2211
1703
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2212
1704
  }
2213
1705
  __name(_ts_decorate6, "_ts_decorate");
2214
- var DashboardLoginRedirectException = class extends import_common6.HttpException {
2215
- static {
2216
- __name(this, "DashboardLoginRedirectException");
2217
- }
2218
- location;
2219
- constructor(location) {
2220
- super({
2221
- location
2222
- }, import_common6.HttpStatus.FOUND), this.location = location;
2223
- }
2224
- };
2225
- var DashboardLoginRedirectFilter = class {
2226
- static {
2227
- __name(this, "DashboardLoginRedirectFilter");
2228
- }
2229
- catch(exception, host) {
2230
- const response = host.switchToHttp().getResponse();
2231
- redirectRaw(response, exception.location);
2232
- }
2233
- };
2234
- DashboardLoginRedirectFilter = _ts_decorate6([
2235
- (0, import_common6.Catch)(DashboardLoginRedirectException)
2236
- ], DashboardLoginRedirectFilter);
2237
-
2238
- // src/server/auth/session-required.exception.ts
2239
- var import_common7 = require("@nestjs/common");
2240
- function _ts_decorate7(decorators, target, key, desc) {
2241
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2242
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2243
- r = Reflect.decorate(decorators, target, key, desc);
2244
- } else {
2245
- for (var i = decorators.length - 1; i >= 0; i--) {
2246
- if (d = decorators[i]) {
2247
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2248
- }
2249
- }
2250
- }
2251
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2252
- }
2253
- __name(_ts_decorate7, "_ts_decorate");
2254
1706
  function _ts_metadata5(metadataKey, metadataValue) {
2255
1707
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2256
1708
  return Reflect.metadata(metadataKey, metadataValue);
@@ -2263,91 +1715,6 @@ function _ts_param3(paramIndex, decorator) {
2263
1715
  };
2264
1716
  }
2265
1717
  __name(_ts_param3, "_ts_param");
2266
- var DashboardSessionRequiredException = class extends import_common7.HttpException {
2267
- static {
2268
- __name(this, "DashboardSessionRequiredException");
2269
- }
2270
- basePath;
2271
- constructor(basePath) {
2272
- super({
2273
- basePath
2274
- }, import_common7.HttpStatus.UNAUTHORIZED), this.basePath = basePath;
2275
- }
2276
- };
2277
- var DashboardSessionRequiredFilter = class _DashboardSessionRequiredFilter {
2278
- static {
2279
- __name(this, "DashboardSessionRequiredFilter");
2280
- }
2281
- auth;
2282
- logger = new import_common7.Logger(_DashboardSessionRequiredFilter.name);
2283
- warned = false;
2284
- constructor(auth = null) {
2285
- this.auth = auth;
2286
- }
2287
- async catch(exception, host) {
2288
- const http = host.switchToHttp();
2289
- const response = http.getResponse();
2290
- const hook = this.auth?.unauthenticatedPage;
2291
- if (hook) {
2292
- try {
2293
- await hook({
2294
- request: http.getRequest(),
2295
- response,
2296
- basePath: exception.basePath
2297
- });
2298
- if (responseAlreadyWritten(response)) return;
2299
- this.warnOnce("dashboardAuth.unauthenticatedPage returned without writing a response; falling back to the built-in page. The hook must write AND end the response it is given.");
2300
- } catch (error) {
2301
- this.warnOnce(`dashboardAuth.unauthenticatedPage threw; falling back to the built-in page. ${String(error)}`);
2302
- if (responseAlreadyWritten(response)) return;
2303
- }
2304
- }
2305
- writeHtmlRaw(response, renderSessionRequiredPage(exception.basePath), import_common7.HttpStatus.UNAUTHORIZED);
2306
- }
2307
- /** Once per process, not once per request: a broken hook fires on every denied navigation. */
2308
- warnOnce(message) {
2309
- if (this.warned) return;
2310
- this.warned = true;
2311
- this.logger.warn(message);
2312
- }
2313
- };
2314
- DashboardSessionRequiredFilter = _ts_decorate7([
2315
- (0, import_common7.Catch)(DashboardSessionRequiredException),
2316
- _ts_param3(0, (0, import_common7.Optional)()),
2317
- _ts_param3(0, (0, import_common7.Inject)(DASHBOARD_AUTH)),
2318
- _ts_metadata5("design:type", Function),
2319
- _ts_metadata5("design:paramtypes", [
2320
- Object
2321
- ])
2322
- ], DashboardSessionRequiredFilter);
2323
-
2324
- // src/server/durable-ui.controller.ts
2325
- function _ts_decorate8(decorators, target, key, desc) {
2326
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2327
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2328
- r = Reflect.decorate(decorators, target, key, desc);
2329
- } else {
2330
- for (var i = decorators.length - 1; i >= 0; i--) {
2331
- if (d = decorators[i]) {
2332
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2333
- }
2334
- }
2335
- }
2336
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2337
- }
2338
- __name(_ts_decorate8, "_ts_decorate");
2339
- function _ts_metadata6(metadataKey, metadataValue) {
2340
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2341
- return Reflect.metadata(metadataKey, metadataValue);
2342
- }
2343
- }
2344
- __name(_ts_metadata6, "_ts_metadata");
2345
- function _ts_param4(paramIndex, decorator) {
2346
- return function(target, key) {
2347
- decorator(target, key, paramIndex);
2348
- };
2349
- }
2350
- __name(_ts_param4, "_ts_param");
2351
1718
  var DASHBOARD_BASE_PATH = Symbol("DASHBOARD_BASE_PATH");
2352
1719
  var DASHBOARD_API_PATH = Symbol("DASHBOARD_API_PATH");
2353
1720
  var BUILD_BASE = "/durable";
@@ -2364,9 +1731,9 @@ var CONTENT_TYPES = {
2364
1731
  ".woff2": "font/woff2",
2365
1732
  ".ico": "image/x-icon"
2366
1733
  };
2367
- var DurableUiController = class {
1734
+ var DurableUiControllerBase = class {
2368
1735
  static {
2369
- __name(this, "DurableUiController");
1736
+ __name(this, "DurableUiControllerBase");
2370
1737
  }
2371
1738
  basePath;
2372
1739
  apiBasePath;
@@ -2380,7 +1747,7 @@ var DurableUiController = class {
2380
1747
  index() {
2381
1748
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
2382
1749
  if (!(0, import_node_fs.existsSync)(indexPath)) {
2383
- throw new import_common8.NotFoundException("Dashboard is not built. Run the package build.");
1750
+ throw new import_common6.NotFoundException("Dashboard is not built. Run the package build.");
2384
1751
  }
2385
1752
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
2386
1753
  const inject = `<script>window.__DURABLE_BASE__='${this.basePath}';window.__DURABLE_API__='${this.apiBasePath}';</script>`;
@@ -2388,235 +1755,57 @@ var DurableUiController = class {
2388
1755
  }
2389
1756
  asset(file) {
2390
1757
  const safe = (0, import_node_path.basename)(file);
2391
- if (safe !== file) throw new import_common8.NotFoundException();
1758
+ if (safe !== file) throw new import_common6.NotFoundException();
2392
1759
  const root = (0, import_node_path.resolve)(this.dir, "assets");
2393
1760
  const assetPath = (0, import_node_path.resolve)(root, safe);
2394
1761
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
2395
- throw new import_common8.NotFoundException();
1762
+ throw new import_common6.NotFoundException();
2396
1763
  }
2397
1764
  const type = CONTENT_TYPES[(0, import_node_path.extname)(safe)] ?? "application/octet-stream";
2398
- return new import_common8.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1765
+ return new import_common6.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
2399
1766
  type
2400
1767
  });
2401
1768
  }
2402
1769
  };
2403
- _ts_decorate8([
2404
- (0, import_common8.Get)(),
2405
- (0, import_common8.Header)("Content-Type", "text/html; charset=utf-8"),
2406
- (0, import_common8.Header)("Cache-Control", "no-store, must-revalidate"),
2407
- _ts_metadata6("design:type", Function),
2408
- _ts_metadata6("design:paramtypes", []),
2409
- _ts_metadata6("design:returntype", String)
2410
- ], DurableUiController.prototype, "index", null);
2411
- _ts_decorate8([
2412
- (0, import_common8.Get)("assets/:file"),
2413
- (0, import_common8.Header)("Cache-Control", "public, max-age=31536000, immutable"),
2414
- _ts_param4(0, (0, import_common8.Param)("file")),
2415
- _ts_metadata6("design:type", Function),
2416
- _ts_metadata6("design:paramtypes", [
1770
+ _ts_decorate6([
1771
+ (0, import_common6.Get)(),
1772
+ (0, import_common6.Header)("Content-Type", "text/html; charset=utf-8"),
1773
+ (0, import_common6.Header)("Cache-Control", "no-store, must-revalidate"),
1774
+ _ts_metadata5("design:type", Function),
1775
+ _ts_metadata5("design:paramtypes", []),
1776
+ _ts_metadata5("design:returntype", String)
1777
+ ], DurableUiControllerBase.prototype, "index", null);
1778
+ _ts_decorate6([
1779
+ (0, import_common6.Get)("assets/:file"),
1780
+ (0, import_common6.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1781
+ _ts_param3(0, (0, import_common6.Param)("file")),
1782
+ _ts_metadata5("design:type", Function),
1783
+ _ts_metadata5("design:paramtypes", [
2417
1784
  String
2418
1785
  ]),
2419
- _ts_metadata6("design:returntype", typeof import_common8.StreamableFile === "undefined" ? Object : import_common8.StreamableFile)
2420
- ], DurableUiController.prototype, "asset", null);
2421
- DurableUiController = _ts_decorate8([
2422
- (0, import_common8.UseFilters)(DashboardLoginRedirectFilter, DashboardSessionRequiredFilter),
2423
- (0, import_common8.Controller)(),
2424
- _ts_param4(0, (0, import_common8.Inject)(DASHBOARD_BASE_PATH)),
2425
- _ts_param4(1, (0, import_common8.Inject)(DASHBOARD_API_PATH)),
2426
- _ts_metadata6("design:type", Function),
2427
- _ts_metadata6("design:paramtypes", [
1786
+ _ts_metadata5("design:returntype", typeof import_common6.StreamableFile === "undefined" ? Object : import_common6.StreamableFile)
1787
+ ], DurableUiControllerBase.prototype, "asset", null);
1788
+ DurableUiControllerBase = _ts_decorate6([
1789
+ (0, import_common6.Controller)(),
1790
+ _ts_param3(0, (0, import_common6.Inject)(DASHBOARD_BASE_PATH)),
1791
+ _ts_param3(1, (0, import_common6.Inject)(DASHBOARD_API_PATH)),
1792
+ _ts_metadata5("design:type", Function),
1793
+ _ts_metadata5("design:paramtypes", [
2428
1794
  String,
2429
1795
  String
2430
1796
  ])
2431
- ], DurableUiController);
2432
-
2433
- // src/server/durable-auth.controller.ts
2434
- function _ts_decorate9(decorators, target, key, desc) {
2435
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2436
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2437
- r = Reflect.decorate(decorators, target, key, desc);
2438
- } else {
2439
- for (var i = decorators.length - 1; i >= 0; i--) {
2440
- if (d = decorators[i]) {
2441
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2442
- }
2443
- }
2444
- }
2445
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2446
- }
2447
- __name(_ts_decorate9, "_ts_decorate");
2448
- function _ts_metadata7(metadataKey, metadataValue) {
2449
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2450
- return Reflect.metadata(metadataKey, metadataValue);
2451
- }
2452
- }
2453
- __name(_ts_metadata7, "_ts_metadata");
2454
- function _ts_param5(paramIndex, decorator) {
2455
- return function(target, key) {
2456
- decorator(target, key, paramIndex);
2457
- };
2458
- }
2459
- __name(_ts_param5, "_ts_param");
2460
- function isString(value) {
2461
- return typeof value === "string";
2462
- }
2463
- __name(isString, "isString");
2464
- var DurableAuthController = class _DurableAuthController {
1797
+ ], DurableUiControllerBase);
1798
+ var DurableUiController = class extends DurableUiControllerBase {
2465
1799
  static {
2466
- __name(this, "DurableAuthController");
2467
- }
2468
- auth;
2469
- basePath;
2470
- logger = new import_common9.Logger(_DurableAuthController.name);
2471
- /** Warn once per hook kind so a throwing hook doesn't spam logs on every failed attempt. */
2472
- warnedHooks = /* @__PURE__ */ new Set();
2473
- constructor(auth, basePath) {
2474
- this.auth = auth;
2475
- this.basePath = basePath;
2476
- }
2477
- // The login page reads `returnTo`/`error` from `location.search` client-side (see
2478
- // `login-page.ts`), so this response never varies per request and needs no templating beyond
2479
- // the developer-controlled `basePath`.
2480
- loginPage() {
2481
- const auth = this.requireAuth();
2482
- if (!auth.modes.includes("login")) throw new import_common9.NotFoundException();
2483
- return renderLoginPage(this.basePath);
2484
- }
2485
- // Called by the login page's own fetch (JSON, not a classic form POST — see `login-page.ts` for
2486
- // why: it keeps the login page working with no host-configured body parser beyond the
2487
- // JSON one Nest wires in by default on both Express and Fastify). Uniform `401` on any failure
2488
- // (unknown user, wrong password, throwing hook) — no user-enumeration.
2489
- async login(body, request, response) {
2490
- const auth = this.requireAuth();
2491
- if (!auth.modes.includes("login")) throw new import_common9.NotFoundException();
2492
- if (!isString(body?.username) || !isString(body?.password)) {
2493
- throw new import_common9.BadRequestException("Body must include string `username` and `password`.");
2494
- }
2495
- const { username, password } = body;
2496
- const user = await this.runHook("login", () => auth.login?.(username, password) ?? null);
2497
- if (!user) throw new import_common9.UnauthorizedException({
2498
- message: "Invalid username or password."
2499
- });
2500
- issueSessionCookie(user, {
2501
- auth,
2502
- request,
2503
- response
2504
- });
2505
- return {
2506
- redirectTo: sanitizeReturnTo(body.returnTo, this.basePath)
2507
- };
2508
- }
2509
- // Mode A: the host frontend (carrying its own auth) POSTs here; the host hook validates the raw
2510
- // request and returns the session user, or `null` to deny. This is the SSO path — the host's own
2511
- // guard decides, and no credential ever reaches this library.
2512
- async session(request, response) {
2513
- const auth = this.requireAuth();
2514
- if (!auth.modes.includes("session")) throw new import_common9.NotFoundException();
2515
- const user = await this.runHook("session", () => auth.session?.(request) ?? null);
2516
- if (!user) throw new import_common9.UnauthorizedException();
2517
- issueSessionCookie(user, {
2518
- auth,
2519
- request,
2520
- response
2521
- });
2522
- }
2523
- // Plain `GET` (not `POST`): logging out only ever destroys the CALLER's own session, so it's
2524
- // safe/idempotent from the caller's perspective — a simple `<a href>` (no JS, no CSRF token)
2525
- // works. Non-passthrough `@Res()`: this handler owns the response outright (clears the cookie,
2526
- // then redirects), so Nest must not also try to send a return value afterwards.
2527
- logout(request, response) {
2528
- clearSessionCookie({
2529
- request,
2530
- response
2531
- });
2532
- redirectRaw(response, this.auth?.modes.includes("login") ? `${this.basePath}/login` : this.basePath);
2533
- }
2534
- requireAuth() {
2535
- if (!this.auth) throw new import_common9.NotFoundException();
2536
- return this.auth;
2537
- }
2538
- /**
2539
- * Run a host hook (`login` or `session`) defensively: a throw is treated as a denial (uniform
2540
- * failure) and warn-logged once PER KIND, so a buggy hook never 500s the endpoint into a
2541
- * stack-trace leak nor floods the logs on repeated bad attempts.
2542
- */
2543
- async runHook(kind, run) {
2544
- try {
2545
- return await run() ?? null;
2546
- } catch (error) {
2547
- if (!this.warnedHooks.has(kind)) {
2548
- this.warnedHooks.add(kind);
2549
- this.logger.warn(`dashboardAuth ${kind} hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
2550
- }
2551
- return null;
2552
- }
1800
+ __name(this, "DurableUiController");
2553
1801
  }
2554
1802
  };
2555
- _ts_decorate9([
2556
- (0, import_common9.Get)("login"),
2557
- (0, import_common9.Header)("Content-Type", "text/html; charset=utf-8"),
2558
- (0, import_common9.Header)("Cache-Control", "no-store, must-revalidate"),
2559
- _ts_metadata7("design:type", Function),
2560
- _ts_metadata7("design:paramtypes", []),
2561
- _ts_metadata7("design:returntype", String)
2562
- ], DurableAuthController.prototype, "loginPage", null);
2563
- _ts_decorate9([
2564
- (0, import_common9.Post)("login"),
2565
- (0, import_common9.HttpCode)(200),
2566
- _ts_param5(0, (0, import_common9.Body)()),
2567
- _ts_param5(1, (0, import_common9.Req)()),
2568
- _ts_param5(2, (0, import_common9.Res)({
2569
- passthrough: true
2570
- })),
2571
- _ts_metadata7("design:type", Function),
2572
- _ts_metadata7("design:paramtypes", [
2573
- typeof LoginBody === "undefined" ? Object : LoginBody,
2574
- Object,
2575
- Object
2576
- ]),
2577
- _ts_metadata7("design:returntype", Promise)
2578
- ], DurableAuthController.prototype, "login", null);
2579
- _ts_decorate9([
2580
- (0, import_common9.Post)("session"),
2581
- (0, import_common9.HttpCode)(204),
2582
- _ts_param5(0, (0, import_common9.Req)()),
2583
- _ts_param5(1, (0, import_common9.Res)({
2584
- passthrough: true
2585
- })),
2586
- _ts_metadata7("design:type", Function),
2587
- _ts_metadata7("design:paramtypes", [
2588
- Object,
2589
- Object
2590
- ]),
2591
- _ts_metadata7("design:returntype", Promise)
2592
- ], DurableAuthController.prototype, "session", null);
2593
- _ts_decorate9([
2594
- (0, import_common9.Get)("logout"),
2595
- _ts_param5(0, (0, import_common9.Req)()),
2596
- _ts_param5(1, (0, import_common9.Res)()),
2597
- _ts_metadata7("design:type", Function),
2598
- _ts_metadata7("design:paramtypes", [
2599
- Object,
2600
- Object
2601
- ]),
2602
- _ts_metadata7("design:returntype", void 0)
2603
- ], DurableAuthController.prototype, "logout", null);
2604
- DurableAuthController = _ts_decorate9([
2605
- (0, import_common9.Controller)(),
2606
- _ts_param5(0, (0, import_common9.Optional)()),
2607
- _ts_param5(0, (0, import_common9.Inject)(DASHBOARD_AUTH)),
2608
- _ts_param5(1, (0, import_common9.Inject)(DASHBOARD_BASE_PATH)),
2609
- _ts_metadata7("design:type", Function),
2610
- _ts_metadata7("design:paramtypes", [
2611
- Object,
2612
- String
2613
- ])
2614
- ], DurableAuthController);
1803
+ DurableUiController = _ts_decorate6([
1804
+ (0, import_common6.Controller)()
1805
+ ], DurableUiController);
2615
1806
 
2616
- // src/server/durable-dashboard-gate.guard.ts
2617
- var import_node_crypto2 = require("crypto");
2618
- var import_common10 = require("@nestjs/common");
2619
- function _ts_decorate10(decorators, target, key, desc) {
1807
+ // src/server/durable-dashboard.module.ts
1808
+ function _ts_decorate7(decorators, target, key, desc) {
2620
1809
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2621
1810
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2622
1811
  r = Reflect.decorate(decorators, target, key, desc);
@@ -2629,342 +1818,59 @@ function _ts_decorate10(decorators, target, key, desc) {
2629
1818
  }
2630
1819
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2631
1820
  }
2632
- __name(_ts_decorate10, "_ts_decorate");
2633
- function _ts_metadata8(metadataKey, metadataValue) {
2634
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2635
- return Reflect.metadata(metadataKey, metadataValue);
2636
- }
2637
- }
2638
- __name(_ts_metadata8, "_ts_metadata");
2639
- function _ts_param6(paramIndex, decorator) {
2640
- return function(target, key) {
2641
- decorator(target, key, paramIndex);
2642
- };
2643
- }
2644
- __name(_ts_param6, "_ts_param");
2645
- var DURABLE_DASHBOARD_TOKEN_ENV = "DURABLE_DASHBOARD_TOKEN";
2646
- var DASHBOARD_GATE = Symbol("DASHBOARD_GATE");
2647
- var LOG_CONTEXT = "DurableDashboard";
2648
- var HOW_TO_CONFIGURE = [
2649
- "Configure one of: `guards: [YourAuthGuard]`, `dashboardAuth: { secret, session | login }`",
2650
- "(or `useDashboardAuth` in forRootAsync), a bearer token via the `token` option or the",
2651
- `${DURABLE_DASHBOARD_TOKEN_ENV} env var, or \`allowUnauthenticated: true\` when the console is`,
2652
- "already protected outside this module (a global guard, a reverse proxy, a private network)."
1821
+ __name(_ts_decorate7, "_ts_decorate");
1822
+ markOpenToAuthorization(DurableApiController);
1823
+ markOpenToAuthorization(DurableUiController);
1824
+ var DASHBOARD_PROTECTION_CHECK = Symbol("DASHBOARD_PROTECTION_CHECK");
1825
+ var UNPROTECTED_CONSOLE_IN_PRODUCTION = [
1826
+ "DurableDashboardModule: NODE_ENV=production and the durable console is mounted with no",
1827
+ "protection, so the app refuses to boot. Protect it one of two ways:",
1828
+ "(1) decorators on the mounted console: DurableDashboardModule.forRoot({ decorators: [UseGuards(AuthenticationGuard), Can(ConsolePolicy, 'view')] });",
1829
+ "(2) mount it yourself: DurableDashboardModule.forRoot({ routes: false }) plus @Controller('durable') @UseGuards(AuthenticationGuard) @Can(ConsolePolicy, 'view') class ConsoleUi extends DurableUiControllerBase {} (and the same over DurableApiControllerBase at 'durable/api')."
2653
1830
  ].join(" ");
2654
1831
  function isProduction() {
2655
1832
  return (process.env.NODE_ENV ?? "").trim().toLowerCase() === "production";
2656
1833
  }
2657
1834
  __name(isProduction, "isProduction");
2658
- function resolveDashboardGate(options, auth) {
2659
- if (options.hasGuards || auth !== null) return {
2660
- mode: "delegated"
2661
- };
2662
- const token = options.token ?? process.env[DURABLE_DASHBOARD_TOKEN_ENV];
2663
- if (typeof token === "string" && token !== "") return {
2664
- mode: "token",
2665
- token
2666
- };
2667
- if (options.allowUnauthenticated === true) return {
2668
- mode: "open"
2669
- };
1835
+ function protectionCheckProvider() {
2670
1836
  return {
2671
- mode: isProduction() ? "deny" : "unconfigured"
2672
- };
2673
- }
2674
- __name(resolveDashboardGate, "resolveDashboardGate");
2675
- function reportDashboardGate(gate, options, logger = new import_common10.Logger(LOG_CONTEXT)) {
2676
- switch (gate.mode) {
2677
- case "open":
2678
- logger.warn("allowUnauthenticated: true. The durable console (including retry/cancel and other mutating endpoints) is served with NO authentication from this module. Only do this when a global guard or reverse proxy already protects it.");
2679
- return;
2680
- case "token":
2681
- if (options.allowUnauthenticated === true) {
2682
- logger.warn("allowUnauthenticated: true is ignored because a dashboard token is configured; requests must carry the token.");
2683
- }
2684
- return;
2685
- case "unconfigured":
2686
- logger.warn([
2687
- "The durable console is UNAUTHENTICATED: no guards, dashboardAuth, token or",
2688
- "allowUnauthenticated were configured. It is served open because NODE_ENV is not",
2689
- '"production", but it WILL deny every request when NODE_ENV=production.',
2690
- HOW_TO_CONFIGURE
2691
- ].join(" "));
2692
- return;
2693
- case "deny":
2694
- logger.error([
2695
- "The durable console has no authentication configured and NODE_ENV=production, so it",
2696
- "is failing closed: every console request (UI and API) is denied.",
2697
- HOW_TO_CONFIGURE
2698
- ].join(" "));
2699
- return;
2700
- case "delegated":
2701
- return;
2702
- }
2703
- }
2704
- __name(reportDashboardGate, "reportDashboardGate");
2705
- function dashboardGateProvider(options) {
2706
- return {
2707
- provide: DASHBOARD_GATE,
2708
- inject: [
2709
- DASHBOARD_AUTH
2710
- ],
2711
- useFactory: /* @__PURE__ */ __name((auth) => {
2712
- const gate = resolveDashboardGate(options, auth);
2713
- reportDashboardGate(gate, options);
2714
- return gate;
1837
+ provide: DASHBOARD_PROTECTION_CHECK,
1838
+ useFactory: /* @__PURE__ */ __name(() => {
1839
+ if (isProduction()) throw new Error(UNPROTECTED_CONSOLE_IN_PRODUCTION);
1840
+ new import_common7.Logger("DurableDashboard").warn("The durable console is mounted with no `decorators`, so it is served OPEN (retry/cancel included). That is refused when NODE_ENV=production: pass `decorators` (e.g. [UseGuards(AuthenticationGuard), Can(ConsolePolicy, 'view')]) or mount it yourself with `routes: false`.");
1841
+ return true;
2715
1842
  }, "useFactory")
2716
1843
  };
2717
1844
  }
2718
- __name(dashboardGateProvider, "dashboardGateProvider");
2719
- function isRecord3(value) {
2720
- return typeof value === "object" && value !== null;
2721
- }
2722
- __name(isRecord3, "isRecord");
2723
- function headerValue(request, name) {
2724
- const headers = request.headers;
2725
- if (!isRecord3(headers)) return void 0;
2726
- const value = headers[name];
2727
- if (typeof value === "string") return value;
2728
- if (Array.isArray(value) && typeof value[0] === "string") return value[0];
2729
- return void 0;
2730
- }
2731
- __name(headerValue, "headerValue");
2732
- function readDashboardToken(request) {
2733
- if (!isRecord3(request)) return void 0;
2734
- const authorization = headerValue(request, "authorization");
2735
- if (authorization) {
2736
- const match = /^Bearer\s+(.+)$/i.exec(authorization);
2737
- if (match?.[1]) return match[1].trim();
2738
- }
2739
- const header = headerValue(request, "x-durable-token");
2740
- if (header) return header.trim();
2741
- const method = typeof request.method === "string" ? request.method.toUpperCase() : "";
2742
- if (method === "GET" || method === "HEAD") {
2743
- const query = request.query;
2744
- if (isRecord3(query)) {
2745
- const value = query.token;
2746
- if (typeof value === "string" && value !== "") return value;
2747
- }
2748
- }
2749
- return void 0;
2750
- }
2751
- __name(readDashboardToken, "readDashboardToken");
2752
- function secretsMatch(provided, expected) {
2753
- const a = Buffer.from(provided);
2754
- const b = Buffer.from(expected);
2755
- if (a.length !== b.length) return false;
2756
- return (0, import_node_crypto2.timingSafeEqual)(a, b);
2757
- }
2758
- __name(secretsMatch, "secretsMatch");
2759
- var DurableDashboardGateGuard = class {
2760
- static {
2761
- __name(this, "DurableDashboardGateGuard");
2762
- }
2763
- gate;
2764
- constructor(gate) {
2765
- this.gate = gate;
2766
- }
2767
- canActivate(context) {
2768
- switch (this.gate.mode) {
2769
- case "delegated":
2770
- case "open":
2771
- case "unconfigured":
2772
- return true;
2773
- case "deny":
2774
- throw new import_common10.ForbiddenException([
2775
- "Durable dashboard authentication is not configured, and NODE_ENV=production denies",
2776
- "an unauthenticated console.",
2777
- HOW_TO_CONFIGURE
2778
- ].join(" "));
2779
- case "token": {
2780
- const provided = readDashboardToken(context.switchToHttp().getRequest());
2781
- if (provided !== void 0 && secretsMatch(provided, this.gate.token ?? "")) return true;
2782
- throw new import_common10.UnauthorizedException("A valid durable dashboard token is required (Authorization: Bearer <token>, x-durable-token, or ?token= on GET).");
2783
- }
2784
- }
2785
- }
2786
- };
2787
- DurableDashboardGateGuard = _ts_decorate10([
2788
- (0, import_common10.Injectable)(),
2789
- _ts_param6(0, (0, import_common10.Inject)(DASHBOARD_GATE)),
2790
- _ts_metadata8("design:type", Function),
2791
- _ts_metadata8("design:paramtypes", [
2792
- typeof DashboardGate === "undefined" ? Object : DashboardGate
2793
- ])
2794
- ], DurableDashboardGateGuard);
2795
-
2796
- // src/server/durable-dashboard.module.ts
2797
- var import_reflect_metadata = require("reflect-metadata");
2798
- var import_nestjs_filter3 = require("@dudousxd/nestjs-filter");
2799
- var import_common12 = require("@nestjs/common");
2800
- var import_core = require("@nestjs/core");
2801
-
2802
- // src/server/durable-session.guard.ts
2803
- var import_common11 = require("@nestjs/common");
2804
- function _ts_decorate11(decorators, target, key, desc) {
2805
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2806
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2807
- r = Reflect.decorate(decorators, target, key, desc);
2808
- } else {
2809
- for (var i = decorators.length - 1; i >= 0; i--) {
2810
- if (d = decorators[i]) {
2811
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2812
- }
2813
- }
2814
- }
2815
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2816
- }
2817
- __name(_ts_decorate11, "_ts_decorate");
2818
- function _ts_metadata9(metadataKey, metadataValue) {
2819
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2820
- return Reflect.metadata(metadataKey, metadataValue);
2821
- }
2822
- }
2823
- __name(_ts_metadata9, "_ts_metadata");
2824
- function _ts_param7(paramIndex, decorator) {
2825
- return function(target, key) {
2826
- decorator(target, key, paramIndex);
2827
- };
2828
- }
2829
- __name(_ts_param7, "_ts_param");
2830
- var DurableUiSessionGuard = class {
2831
- static {
2832
- __name(this, "DurableUiSessionGuard");
2833
- }
2834
- auth;
2835
- basePath;
2836
- constructor(auth, basePath) {
2837
- this.auth = auth;
2838
- this.basePath = basePath;
2839
- }
2840
- async canActivate(context) {
2841
- if (!this.auth) return true;
2842
- const auth = this.auth;
2843
- const http = context.switchToHttp();
2844
- const request = http.getRequest();
2845
- const session = readSessionFromRequest(auth, request);
2846
- if (!session) {
2847
- this.denyUnauthenticated(auth, request);
2848
- }
2849
- if (!await maybeRenewSession(auth, session, request, http.getResponse())) {
2850
- this.denyUnauthenticated(auth, request);
2851
- }
2852
- return true;
2853
- }
2854
- /**
2855
- * A revoked session (the host's `revalidate` hook says no) is denied exactly like an absent
2856
- * one — by design, there is nothing left to distinguish "never had a session" from "had one,
2857
- * then lost it" once the cookie is cleared, so both get the same Mode-aware treatment.
2858
- *
2859
- * Takes `auth` explicitly rather than reading `this.auth`: `canActivate`'s `!this.auth` early
2860
- * return narrows the field within that method only — TS doesn't carry it across a method call
2861
- * — so callers pass the already-narrowed value instead of this method re-deriving (or
2862
- * asserting away) the nullability.
2863
- */
2864
- denyUnauthenticated(auth, request) {
2865
- if (!auth.modes.includes("login")) throw new DashboardSessionRequiredException(this.basePath);
2866
- const returnTo = encodeURIComponent(originalRequestUrl(request));
2867
- throw new DashboardLoginRedirectException(`${this.basePath}/login?returnTo=${returnTo}`);
2868
- }
2869
- };
2870
- DurableUiSessionGuard = _ts_decorate11([
2871
- (0, import_common11.Injectable)(),
2872
- _ts_param7(0, (0, import_common11.Inject)(DASHBOARD_AUTH)),
2873
- _ts_param7(1, (0, import_common11.Inject)(DASHBOARD_BASE_PATH)),
2874
- _ts_metadata9("design:type", Function),
2875
- _ts_metadata9("design:paramtypes", [
2876
- Object,
2877
- String
2878
- ])
2879
- ], DurableUiSessionGuard);
2880
- var DurableApiSessionGuard = class {
2881
- static {
2882
- __name(this, "DurableApiSessionGuard");
2883
- }
2884
- auth;
2885
- constructor(auth) {
2886
- this.auth = auth;
2887
- }
2888
- async canActivate(context) {
2889
- if (!this.auth) return true;
2890
- const auth = this.auth;
2891
- const http = context.switchToHttp();
2892
- const request = http.getRequest();
2893
- const session = readSessionFromRequest(auth, request);
2894
- if (!session) throw this.unauthorized(auth);
2895
- if (!await maybeRenewSession(auth, session, request, http.getResponse())) {
2896
- throw this.unauthorized(auth);
2897
- }
2898
- return true;
2899
- }
2900
- /**
2901
- * A bare 401 body carrying `{ auth: { modes } }` — mirrors `@dudousxd/nestjs-telescope`'s
2902
- * dashboardAuth 401. The API is fetched (never navigated), so this is the ONLY way the console
2903
- * SPA (`durable-client.ts`) learns which auth surface to send the operator to on a mid-session
2904
- * 401; `DurableUiSessionGuard`'s redirect/session-required exceptions above don't reach it.
2905
- */
2906
- unauthorized(auth) {
2907
- return new import_common11.UnauthorizedException({
2908
- auth: {
2909
- modes: auth.modes
2910
- }
2911
- });
2912
- }
2913
- };
2914
- DurableApiSessionGuard = _ts_decorate11([
2915
- (0, import_common11.Injectable)(),
2916
- _ts_param7(0, (0, import_common11.Inject)(DASHBOARD_AUTH)),
2917
- _ts_metadata9("design:type", Function),
2918
- _ts_metadata9("design:paramtypes", [
2919
- Object
2920
- ])
2921
- ], DurableApiSessionGuard);
2922
-
2923
- // src/server/durable-dashboard.module.ts
2924
- function _ts_decorate12(decorators, target, key, desc) {
2925
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2926
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2927
- r = Reflect.decorate(decorators, target, key, desc);
2928
- } else {
2929
- for (var i = decorators.length - 1; i >= 0; i--) {
2930
- if (d = decorators[i]) {
2931
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2932
- }
2933
- }
2934
- }
2935
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2936
- }
2937
- __name(_ts_decorate12, "_ts_decorate");
2938
- var GUARDS_METADATA = "__guards__";
1845
+ __name(protectionCheckProvider, "protectionCheckProvider");
1846
+ function assertNothingToDecorate(options) {
1847
+ if (options.decorators === void 0) return;
1848
+ throw new Error([
1849
+ "DurableDashboardModule.forRoot({ routes: false }) mounts no controllers, so `decorators`",
1850
+ "would protect nothing. Put your protection on the controllers you mount (extend",
1851
+ "DurableUiControllerBase / DurableApiControllerBase and decorate them with @UseGuards /",
1852
+ "@Can), and drop `decorators`."
1853
+ ].join(" "));
1854
+ }
1855
+ __name(assertNothingToDecorate, "assertNothingToDecorate");
2939
1856
  function normalize(path) {
2940
1857
  return `/${path.replace(/^\/+|\/+$/g, "")}`;
2941
1858
  }
2942
1859
  __name(normalize, "normalize");
2943
- function stampGuards(hostGuards, builtIn, controller) {
2944
- const merged = [
2945
- ...builtIn.filter((guard) => guard !== void 0),
2946
- ...hostGuards ?? []
2947
- ];
2948
- Reflect.defineMetadata(GUARDS_METADATA, merged, controller);
2949
- }
2950
- __name(stampGuards, "stampGuards");
2951
1860
  var DurableApiModule = class _DurableApiModule {
2952
1861
  static {
2953
1862
  __name(this, "DurableApiModule");
2954
1863
  }
2955
1864
  static register(options) {
2956
- stampGuards(options.guards, [
2957
- options.authMayBeConfigured ? DurableApiSessionGuard : void 0,
2958
- options.stampGate ? DurableDashboardGateGuard : void 0
2959
- ], DurableApiController);
1865
+ const routes = options.routes !== false;
2960
1866
  return {
2961
1867
  module: _DurableApiModule,
2962
1868
  imports: [
2963
1869
  ...options.imports ?? []
2964
1870
  ],
2965
- controllers: [
2966
- DurableApiController
2967
- ],
1871
+ controllers: routes ? [
1872
+ controllerFor(DurableApiController, options.decorators)
1873
+ ] : [],
2968
1874
  providers: [
2969
1875
  DashboardService,
2970
1876
  // `@dudousxd/nestjs-filter` is wired PRIVATELY here rather than through
@@ -2997,82 +1903,81 @@ var DurableApiModule = class _DurableApiModule {
2997
1903
  provide: RUN_QUERY_ADAPTER,
2998
1904
  useExisting: RunQueryAdapter
2999
1905
  },
3000
- RunFilter,
3001
- options.authProvider,
3002
- DurableApiSessionGuard,
3003
- // Resolved ONCE here (this module is imported by the UI module, which reuses it via the
3004
- // export below), so the boot report is logged once per mount.
3005
- dashboardGateProvider(options.gate),
3006
- DurableDashboardGateGuard,
3007
- ...options.guards ?? []
1906
+ RunFilter
3008
1907
  ],
3009
- exports: [
1908
+ // Self-mounted (`routes: false`): the host's own subclass of `DurableApiControllerBase` is
1909
+ // hosted in the HOST's module, so what its constructor injects must be exported. `FilterRunner`
1910
+ // is only exported then: exporting it from a mounted console would shadow a host's own
1911
+ // `FilterModule` runner in whatever module imports the dashboard.
1912
+ exports: routes ? [
1913
+ DashboardService
1914
+ ] : [
3010
1915
  DashboardService,
3011
- DASHBOARD_GATE
1916
+ import_nestjs_filter3.FilterRunner
3012
1917
  ]
3013
1918
  };
3014
1919
  }
3015
1920
  };
3016
- DurableApiModule = _ts_decorate12([
3017
- (0, import_common12.Module)({})
1921
+ DurableApiModule = _ts_decorate7([
1922
+ (0, import_common7.Module)({})
3018
1923
  ], DurableApiModule);
3019
1924
  var DurableDashboardModule = class _DurableDashboardModule {
3020
1925
  static {
3021
1926
  __name(this, "DurableDashboardModule");
3022
1927
  }
3023
1928
  static forRoot(options = {}) {
3024
- const authProvider = {
3025
- provide: DASHBOARD_AUTH,
3026
- useValue: resolveDashboardAuth(options.dashboardAuth)
3027
- };
3028
- const authConfigured = options.dashboardAuth !== void 0;
3029
- return _DurableDashboardModule.build(options, authProvider, authConfigured, authConfigured);
3030
- }
3031
- static forRootAsync(options) {
3032
- const authProvider = {
3033
- provide: DASHBOARD_AUTH,
3034
- inject: options.inject ?? [],
3035
- useFactory: /* @__PURE__ */ __name(async (...deps) => resolveDashboardAuth(await options.useDashboardAuth(...deps)), "useFactory")
3036
- };
3037
- return _DurableDashboardModule.build(options, authProvider, true, false);
3038
- }
3039
- /** Shared wiring: static routing + the API module, with `dashboardAuth` supplied by `authProvider`. */
3040
- static build(options, authProvider, authMayBeConfigured, authStaticallyConfigured) {
3041
1929
  const basePath = normalize(options.basePath ?? "/durable");
3042
1930
  const apiBasePath = normalize(options.apiBasePath ?? `${basePath}/api`);
3043
- const hasGuards = (options.guards?.length ?? 0) > 0;
3044
- const gate = {
3045
- hasGuards,
3046
- ...options.allowUnauthenticated !== void 0 ? {
3047
- allowUnauthenticated: options.allowUnauthenticated
3048
- } : {},
3049
- ...options.token !== void 0 ? {
3050
- token: options.token
3051
- } : {}
3052
- };
3053
- const stampGate = !hasGuards && !authStaticallyConfigured;
3054
- stampGuards(options.guards, [
3055
- authMayBeConfigured ? DurableUiSessionGuard : void 0,
3056
- stampGate ? DurableDashboardGateGuard : void 0
3057
- ], DurableUiController);
1931
+ const pathProviders = [
1932
+ {
1933
+ provide: DASHBOARD_BASE_PATH,
1934
+ useValue: basePath
1935
+ },
1936
+ {
1937
+ provide: DASHBOARD_API_PATH,
1938
+ useValue: apiBasePath
1939
+ }
1940
+ ];
1941
+ if (options.routes === false) {
1942
+ assertNothingToDecorate(options);
1943
+ const api = DurableApiModule.register({
1944
+ ...options.imports ? {
1945
+ imports: options.imports
1946
+ } : {},
1947
+ routes: false
1948
+ });
1949
+ return {
1950
+ module: _DurableDashboardModule,
1951
+ imports: [
1952
+ ...options.imports ?? [],
1953
+ api
1954
+ ],
1955
+ controllers: [],
1956
+ providers: pathProviders,
1957
+ // What a host's subclasses of `DurableUiControllerBase` / `DurableApiControllerBase` inject:
1958
+ // the SPA's paths, and the read/action service and the filter runner via the API module.
1959
+ exports: [
1960
+ DurableApiModule,
1961
+ DASHBOARD_BASE_PATH,
1962
+ DASHBOARD_API_PATH
1963
+ ]
1964
+ };
1965
+ }
1966
+ const decorated = (options.decorators?.length ?? 0) > 0;
3058
1967
  return {
3059
1968
  module: _DurableDashboardModule,
3060
1969
  imports: [
3061
1970
  ...options.imports ?? [],
3062
- // Guards + host imports must reach the API controller's HOST module — enhancers resolve
3063
- // from their controller's own module, never from a parent (see DurableApiModule.register).
1971
+ // Host imports must reach the API controller's HOST module: enhancers resolve from their
1972
+ // controller's own module, never from a parent (see DurableApiModule.register).
3064
1973
  // Spread-only-when-set: exactOptionalPropertyTypes rejects an explicit `undefined`.
3065
1974
  DurableApiModule.register({
3066
1975
  ...options.imports ? {
3067
1976
  imports: options.imports
3068
1977
  } : {},
3069
- ...options.guards ? {
3070
- guards: options.guards
3071
- } : {},
3072
- authProvider,
3073
- authMayBeConfigured,
3074
- gate,
3075
- stampGate
1978
+ ...options.decorators ? {
1979
+ decorators: options.decorators
1980
+ } : {}
3076
1981
  }),
3077
1982
  import_core.RouterModule.register([
3078
1983
  {
@@ -3086,30 +1991,13 @@ var DurableDashboardModule = class _DurableDashboardModule {
3086
1991
  ])
3087
1992
  ],
3088
1993
  controllers: [
3089
- DurableUiController,
3090
- // The auth controller (login page + logout) only exists when dashboardAuth might be
3091
- // configured — mounting it unconditionally would add a new `/login` route even for hosts
3092
- // that never set `dashboardAuth`, breaking "absent -> today's behavior byte-for-byte".
3093
- ...authMayBeConfigured ? [
3094
- DurableAuthController
3095
- ] : []
1994
+ controllerFor(DurableUiController, options.decorators)
3096
1995
  ],
3097
1996
  providers: [
3098
- {
3099
- provide: DASHBOARD_BASE_PATH,
3100
- useValue: basePath
3101
- },
3102
- {
3103
- provide: DASHBOARD_API_PATH,
3104
- useValue: apiBasePath
3105
- },
3106
- authProvider,
3107
- DurableUiSessionGuard,
3108
- // `DASHBOARD_GATE` itself comes from the imported DurableApiModule (resolved once there).
3109
- DurableDashboardGateGuard,
3110
- // DurableUiController (and DurableAuthController, when present) are hosted HERE, so their
3111
- // guards DI-instantiate from this module.
3112
- ...options.guards ?? []
1997
+ ...pathProviders,
1998
+ ...decorated ? [] : [
1999
+ protectionCheckProvider()
2000
+ ]
3113
2001
  ],
3114
2002
  // Re-export the API module so its DashboardService reaches importers (e.g. flip's own controllers).
3115
2003
  exports: [
@@ -3118,27 +2006,21 @@ var DurableDashboardModule = class _DurableDashboardModule {
3118
2006
  };
3119
2007
  }
3120
2008
  };
3121
- DurableDashboardModule = _ts_decorate12([
3122
- (0, import_common12.Module)({})
2009
+ DurableDashboardModule = _ts_decorate7([
2010
+ (0, import_common7.Module)({})
3123
2011
  ], DurableDashboardModule);
3124
2012
  // Annotate the CommonJS export names for ESM import in node:
3125
2013
  0 && (module.exports = {
3126
2014
  DASHBOARD_API_PATH,
3127
2015
  DASHBOARD_BASE_PATH,
3128
- DASHBOARD_GATE,
3129
- DURABLE_DASHBOARD_TOKEN_ENV,
2016
+ DASHBOARD_PROTECTION_CHECK,
3130
2017
  DashboardService,
3131
2018
  DurableApiController,
2019
+ DurableApiControllerBase,
3132
2020
  DurableApiModule,
3133
- DurableApiSessionGuard,
3134
- DurableAuthController,
3135
- DurableDashboardGateGuard,
3136
2021
  DurableDashboardModule,
3137
2022
  DurableUiController,
3138
- DurableUiSessionGuard,
3139
- dashboardGateProvider,
3140
- readDashboardToken,
3141
- reportDashboardGate,
3142
- resolveDashboardGate
2023
+ DurableUiControllerBase,
2024
+ UNPROTECTED_CONSOLE_IN_PRODUCTION
3143
2025
  });
3144
2026
  //# sourceMappingURL=index.cjs.map