@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.
- package/dist/client/durable-client.d.ts +6 -1
- package/dist/client/durable-client.d.ts.map +1 -1
- package/dist/client/durable-client.js +9 -46
- package/dist/client/durable-client.js.map +1 -1
- package/dist/server/index.cjs +223 -1341
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +101 -388
- package/dist/server/index.d.ts +101 -388
- package/dist/server/index.js +208 -1320
- package/dist/server/index.js.map +1 -1
- package/dist/spa/assets/{bench-Dee6-QN_.js → bench-DCclNvcZ.js} +1 -1
- package/dist/spa/assets/index-B-wtX4GV.js +66 -0
- package/dist/spa/assets/{index-RjxbO7dU.js → index-ChjKRQZx.js} +1 -1
- package/dist/spa/assets/{preview-BscU9n0o.js → preview-CdsjvOrK.js} +1 -1
- package/dist/spa/bench.html +2 -2
- package/dist/spa/index.html +2 -2
- package/dist/spa/preview.html +2 -2
- package/package.json +6 -19
- package/dist/client/console-session.d.ts +0 -63
- package/dist/client/console-session.d.ts.map +0 -1
- package/dist/client/console-session.js +0 -107
- package/dist/client/console-session.js.map +0 -1
- package/dist/react/index.d.ts +0 -4
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/index.js +0 -14
- package/dist/react/index.js.map +0 -1
- package/dist/react/open-console-button.d.ts +0 -26
- package/dist/react/open-console-button.d.ts.map +0 -1
- package/dist/react/open-console-button.js +0 -26
- package/dist/react/open-console-button.js.map +0 -1
- package/dist/react/use-open-console.d.ts +0 -40
- package/dist/react/use-open-console.d.ts.map +0 -1
- package/dist/react/use-open-console.js +0 -77
- package/dist/react/use-open-console.js.map +0 -1
- package/dist/spa/assets/index-VXNPW483.js +0 -66
package/dist/server/index.js
CHANGED
|
@@ -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,
|
|
753
|
+
applyOffsetPagination(qb, page, size) {
|
|
810
754
|
this.draft(qb).narrow({
|
|
811
755
|
limit: size,
|
|
812
|
-
offset: (
|
|
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
|
|
1100
|
+
var DurableApiControllerBase = class {
|
|
1157
1101
|
static {
|
|
1158
|
-
__name(this, "
|
|
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
|
|
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 (!
|
|
1297
|
-
const { etag, notModified, ...body } =
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
1643
|
-
|
|
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
|
-
],
|
|
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
|
-
|
|
1669
|
-
|
|
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
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
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/
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
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
|
-
|
|
2034
|
-
|
|
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
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
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
|
-
|
|
2142
|
-
auth,
|
|
2143
|
-
request,
|
|
2144
|
-
response,
|
|
2145
|
-
now
|
|
2146
|
-
});
|
|
2147
|
-
return true;
|
|
1648
|
+
return decorated;
|
|
2148
1649
|
}
|
|
2149
|
-
__name(
|
|
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
|
|
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
|
|
1699
|
+
var DurableUiControllerBase = class {
|
|
2327
1700
|
static {
|
|
2328
|
-
__name(this, "
|
|
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
|
-
|
|
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
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
],
|
|
2370
|
-
|
|
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
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
1746
|
+
_ts_param3(0, Param2("file")),
|
|
1747
|
+
_ts_metadata5("design:type", Function),
|
|
1748
|
+
_ts_metadata5("design:paramtypes", [
|
|
2376
1749
|
String
|
|
2377
1750
|
]),
|
|
2378
|
-
|
|
2379
|
-
],
|
|
2380
|
-
|
|
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
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
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
|
-
],
|
|
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, "
|
|
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
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
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
|
|
2576
|
-
|
|
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(
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
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
|
|
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
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
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(
|
|
2678
|
-
function
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1881
|
+
FilterRunner2
|
|
2971
1882
|
]
|
|
2972
1883
|
};
|
|
2973
1884
|
}
|
|
2974
1885
|
};
|
|
2975
|
-
DurableApiModule =
|
|
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
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
}
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
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
|
-
//
|
|
3022
|
-
//
|
|
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.
|
|
3029
|
-
|
|
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
|
-
|
|
3059
|
-
|
|
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 =
|
|
1974
|
+
DurableDashboardModule = _ts_decorate7([
|
|
3081
1975
|
Module({})
|
|
3082
1976
|
], DurableDashboardModule);
|
|
3083
1977
|
export {
|
|
3084
1978
|
DASHBOARD_API_PATH,
|
|
3085
1979
|
DASHBOARD_BASE_PATH,
|
|
3086
|
-
|
|
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
|
-
|
|
3097
|
-
|
|
3098
|
-
readDashboardToken,
|
|
3099
|
-
reportDashboardGate,
|
|
3100
|
-
resolveDashboardGate
|
|
1987
|
+
DurableUiControllerBase,
|
|
1988
|
+
UNPROTECTED_CONSOLE_IN_PRODUCTION
|
|
3101
1989
|
};
|
|
3102
1990
|
//# sourceMappingURL=index.js.map
|