@dudousxd/nestjs-durable-dashboard 0.54.0 → 0.55.0

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