@dudousxd/nestjs-agent-dashboard 0.9.1 → 0.10.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/README.md +41 -5
- package/dist/server/index.cjs +193 -78
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +96 -37
- package/dist/server/index.d.ts +96 -37
- package/dist/server/index.js +194 -79
- package/dist/server/index.js.map +1 -1
- package/package.json +2 -2
package/dist/server/index.js
CHANGED
|
@@ -261,6 +261,56 @@ function clearSessionCookie(context) {
|
|
|
261
261
|
appendSetCookie(context.response, cookie);
|
|
262
262
|
}
|
|
263
263
|
__name(clearSessionCookie, "clearSessionCookie");
|
|
264
|
+
var inFlightRevalidations = /* @__PURE__ */ new Map();
|
|
265
|
+
function revalidationKey(session) {
|
|
266
|
+
return `${session.sub}:${session.iat}`;
|
|
267
|
+
}
|
|
268
|
+
__name(revalidationKey, "revalidationKey");
|
|
269
|
+
function getOrStartRevalidation(auth, session, user) {
|
|
270
|
+
const hook = auth.revalidate;
|
|
271
|
+
if (!hook) return Promise.resolve(true);
|
|
272
|
+
const key = revalidationKey(session);
|
|
273
|
+
const inFlight = inFlightRevalidations.get(key);
|
|
274
|
+
if (inFlight) return inFlight;
|
|
275
|
+
const outcome = (async () => {
|
|
276
|
+
try {
|
|
277
|
+
return await hook(user);
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
})().finally(() => {
|
|
282
|
+
inFlightRevalidations.delete(key);
|
|
283
|
+
});
|
|
284
|
+
inFlightRevalidations.set(key, outcome);
|
|
285
|
+
return outcome;
|
|
286
|
+
}
|
|
287
|
+
__name(getOrStartRevalidation, "getOrStartRevalidation");
|
|
288
|
+
async function maybeRenewSession(auth, session, request, response, now = Date.now()) {
|
|
289
|
+
if (now - session.iat <= auth.ttlMs / 2) return true;
|
|
290
|
+
const user = {
|
|
291
|
+
id: session.sub,
|
|
292
|
+
...session.name !== void 0 ? {
|
|
293
|
+
name: session.name
|
|
294
|
+
} : {},
|
|
295
|
+
roles: session.roles
|
|
296
|
+
};
|
|
297
|
+
const allowed = await getOrStartRevalidation(auth, session, user);
|
|
298
|
+
if (!allowed) {
|
|
299
|
+
clearSessionCookie({
|
|
300
|
+
request,
|
|
301
|
+
response
|
|
302
|
+
});
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
issueSessionCookie(user, {
|
|
306
|
+
auth,
|
|
307
|
+
request,
|
|
308
|
+
response,
|
|
309
|
+
now
|
|
310
|
+
});
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
__name(maybeRenewSession, "maybeRenewSession");
|
|
264
314
|
|
|
265
315
|
// src/server/auth/dashboard-auth.guard.ts
|
|
266
316
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -288,14 +338,16 @@ var DashboardAuthGuard = class {
|
|
|
288
338
|
constructor(auth) {
|
|
289
339
|
this.auth = auth;
|
|
290
340
|
}
|
|
291
|
-
canActivate(context) {
|
|
341
|
+
async canActivate(context) {
|
|
292
342
|
if (!this.auth) return true;
|
|
293
343
|
const http = context.switchToHttp();
|
|
294
344
|
const request = http.getRequest();
|
|
295
345
|
const session = this.verifyRequestSession(request);
|
|
296
346
|
if (!session) throw new UnauthorizedException();
|
|
297
347
|
attachSession(request, session);
|
|
298
|
-
this.
|
|
348
|
+
if (!await maybeRenewSession(this.auth, session, request, http.getResponse())) {
|
|
349
|
+
throw new UnauthorizedException();
|
|
350
|
+
}
|
|
299
351
|
return true;
|
|
300
352
|
}
|
|
301
353
|
verifyRequestSession(request) {
|
|
@@ -307,28 +359,6 @@ var DashboardAuthGuard = class {
|
|
|
307
359
|
secret: auth.secret
|
|
308
360
|
});
|
|
309
361
|
}
|
|
310
|
-
/**
|
|
311
|
-
* Sliding renewal: a valid cookie past 50% of its TTL is transparently re-issued on the
|
|
312
|
-
* response, so an active user never gets logged out mid-session.
|
|
313
|
-
*/
|
|
314
|
-
maybeRenew(response, request, session) {
|
|
315
|
-
const auth = this.auth;
|
|
316
|
-
if (!auth) return;
|
|
317
|
-
const now = Date.now();
|
|
318
|
-
if (now - session.iat <= auth.ttlMs / 2) return;
|
|
319
|
-
issueSessionCookie({
|
|
320
|
-
id: session.sub,
|
|
321
|
-
...session.name !== void 0 ? {
|
|
322
|
-
name: session.name
|
|
323
|
-
} : {},
|
|
324
|
-
roles: session.roles
|
|
325
|
-
}, {
|
|
326
|
-
auth,
|
|
327
|
-
request,
|
|
328
|
-
response,
|
|
329
|
-
now
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
362
|
};
|
|
333
363
|
DashboardAuthGuard = _ts_decorate([
|
|
334
364
|
Injectable(),
|
|
@@ -1117,24 +1147,21 @@ AgentApiController = _ts_decorate3([
|
|
|
1117
1147
|
], AgentApiController);
|
|
1118
1148
|
|
|
1119
1149
|
// src/server/agent-dashboard-auth.controller.ts
|
|
1120
|
-
import { Body as Body2, Controller as Controller2, Get as Get2, Header, Inject as Inject4, Logger, NotFoundException, Optional as Optional4, Post as Post2, Query as Query2, Req as Req2, Res } from "@nestjs/common";
|
|
1150
|
+
import { Body as Body2, Controller as Controller2, Get as Get2, Header, HttpCode as HttpCode2, Inject as Inject4, Logger, NotFoundException, Optional as Optional4, Post as Post2, Query as Query2, Req as Req2, Res, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
|
|
1121
1151
|
|
|
1122
1152
|
// src/server/auth/login-page.ts
|
|
1123
1153
|
function escapeHtml(value) {
|
|
1124
1154
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1125
1155
|
}
|
|
1126
1156
|
__name(escapeHtml, "escapeHtml");
|
|
1127
|
-
function
|
|
1128
|
-
const action = escapeHtml(options.actionUrl);
|
|
1129
|
-
const returnTo = escapeHtml(options.returnTo);
|
|
1130
|
-
const errorBanner = options.error === true ? '<p role="alert" class="error">Invalid username or password.</p>' : "";
|
|
1157
|
+
function pageShell(content, title) {
|
|
1131
1158
|
return `<!doctype html>
|
|
1132
1159
|
<html lang="en">
|
|
1133
1160
|
<head>
|
|
1134
1161
|
<meta charset="utf-8" />
|
|
1135
1162
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1136
1163
|
<meta name="robots" content="noindex, nofollow" />
|
|
1137
|
-
<title
|
|
1164
|
+
<title>${title}</title>
|
|
1138
1165
|
<style>
|
|
1139
1166
|
:root { color-scheme: dark; }
|
|
1140
1167
|
* { box-sizing: border-box; }
|
|
@@ -1165,6 +1192,13 @@ function renderLoginPage(options) {
|
|
|
1165
1192
|
font-weight: 600;
|
|
1166
1193
|
color: #34d399;
|
|
1167
1194
|
}
|
|
1195
|
+
h1 {
|
|
1196
|
+
margin: 0 0 12px;
|
|
1197
|
+
font-size: 16px;
|
|
1198
|
+
font-weight: 600;
|
|
1199
|
+
color: #f4f4f5;
|
|
1200
|
+
}
|
|
1201
|
+
p { margin: 0 0 16px; color: #a1a1aa; }
|
|
1168
1202
|
form { display: flex; flex-direction: column; gap: 16px; }
|
|
1169
1203
|
label { display: flex; flex-direction: column; gap: 6px; }
|
|
1170
1204
|
.field-label {
|
|
@@ -1203,7 +1237,17 @@ function renderLoginPage(options) {
|
|
|
1203
1237
|
</head>
|
|
1204
1238
|
<body>
|
|
1205
1239
|
<div class="card">
|
|
1206
|
-
|
|
1240
|
+
${content}
|
|
1241
|
+
</div>
|
|
1242
|
+
</body>
|
|
1243
|
+
</html>`;
|
|
1244
|
+
}
|
|
1245
|
+
__name(pageShell, "pageShell");
|
|
1246
|
+
function renderLoginPage(options) {
|
|
1247
|
+
const action = escapeHtml(options.actionUrl);
|
|
1248
|
+
const returnTo = escapeHtml(options.returnTo);
|
|
1249
|
+
const errorBanner = options.error === true ? '<p role="alert" class="error">Invalid username or password.</p>' : "";
|
|
1250
|
+
return pageShell(`<p class="brand">AI Gateway</p>
|
|
1207
1251
|
<form method="post" action="${action}">
|
|
1208
1252
|
<input type="hidden" name="returnTo" value="${returnTo}" />
|
|
1209
1253
|
<label>
|
|
@@ -1216,12 +1260,15 @@ function renderLoginPage(options) {
|
|
|
1216
1260
|
</label>
|
|
1217
1261
|
${errorBanner}
|
|
1218
1262
|
<button type="submit">Sign in</button>
|
|
1219
|
-
</form
|
|
1220
|
-
</div>
|
|
1221
|
-
</body>
|
|
1222
|
-
</html>`;
|
|
1263
|
+
</form>`, "Sign in \u2014 AI Gateway");
|
|
1223
1264
|
}
|
|
1224
1265
|
__name(renderLoginPage, "renderLoginPage");
|
|
1266
|
+
function renderSessionRequiredPage() {
|
|
1267
|
+
return pageShell(`<p class="brand">AI Gateway</p>
|
|
1268
|
+
<h1>Open this console from your application</h1>
|
|
1269
|
+
<p>Your session is minted by the host app. Use its console launcher to sign in, then reload.</p>`, "Sign in \u2014 AI Gateway");
|
|
1270
|
+
}
|
|
1271
|
+
__name(renderSessionRequiredPage, "renderSessionRequiredPage");
|
|
1225
1272
|
|
|
1226
1273
|
// src/server/auth/sanitize-return-to.ts
|
|
1227
1274
|
function sanitizeReturnTo(basePath, returnTo) {
|
|
@@ -1267,14 +1314,15 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1267
1314
|
auth;
|
|
1268
1315
|
basePath;
|
|
1269
1316
|
logger = new Logger(_AgentDashboardAuthController.name);
|
|
1270
|
-
/** Warn once (not per request) so a broken hook can't be used to flood the logs. */
|
|
1271
|
-
|
|
1317
|
+
/** Warn once PER HOOK KIND (not per request) so a broken hook can't be used to flood the logs. */
|
|
1318
|
+
warnedHooks = /* @__PURE__ */ new Set();
|
|
1272
1319
|
constructor(auth, basePath) {
|
|
1273
1320
|
this.auth = auth;
|
|
1274
1321
|
this.basePath = basePath;
|
|
1275
1322
|
}
|
|
1276
1323
|
loginPage(req, res, returnToQuery, error) {
|
|
1277
|
-
this.requireAuth();
|
|
1324
|
+
const auth = this.requireAuth();
|
|
1325
|
+
if (!auth.modes.includes("login")) throw new NotFoundException();
|
|
1278
1326
|
const returnTo = sanitizeReturnTo(this.basePath, returnToQuery);
|
|
1279
1327
|
if (this.currentSession(req)) {
|
|
1280
1328
|
res.status(302);
|
|
@@ -1289,6 +1337,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1289
1337
|
}
|
|
1290
1338
|
async login(body, req, res) {
|
|
1291
1339
|
const auth = this.requireAuth();
|
|
1340
|
+
if (!auth.modes.includes("login")) throw new NotFoundException();
|
|
1292
1341
|
const returnTo = sanitizeReturnTo(this.basePath, body?.returnTo);
|
|
1293
1342
|
const username = body?.username;
|
|
1294
1343
|
const password = body?.password;
|
|
@@ -1296,7 +1345,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1296
1345
|
this.redirectToLoginError(res, returnTo);
|
|
1297
1346
|
return "";
|
|
1298
1347
|
}
|
|
1299
|
-
const user = await this.
|
|
1348
|
+
const user = await this.runHook("login", () => auth.login?.(username.trim(), isString(password) ? password : "") ?? null);
|
|
1300
1349
|
if (!user) {
|
|
1301
1350
|
this.redirectToLoginError(res, returnTo);
|
|
1302
1351
|
return "";
|
|
@@ -1316,9 +1365,30 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1316
1365
|
response: res
|
|
1317
1366
|
});
|
|
1318
1367
|
res.status(302);
|
|
1319
|
-
res.setHeader("Location", `${this.basePath}/auth/login`);
|
|
1368
|
+
res.setHeader("Location", this.auth && !this.auth.modes.includes("login") ? `${this.basePath}/auth/session-required` : `${this.basePath}/auth/login`);
|
|
1320
1369
|
return "";
|
|
1321
1370
|
}
|
|
1371
|
+
// Mode A: the host frontend (carrying its own auth) POSTs here; the host hook validates the raw
|
|
1372
|
+
// request and returns the session user, or `null` to deny. No credential reaches this library.
|
|
1373
|
+
async session(request, response) {
|
|
1374
|
+
const auth = this.requireAuth();
|
|
1375
|
+
if (!auth.modes.includes("session")) throw new NotFoundException();
|
|
1376
|
+
const user = await this.runHook("session", () => auth.session?.(request) ?? null);
|
|
1377
|
+
if (!user) throw new UnauthorizedException2();
|
|
1378
|
+
issueSessionCookie(user, {
|
|
1379
|
+
auth,
|
|
1380
|
+
request,
|
|
1381
|
+
response
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
// Mode-A-only landing: the host mints the session, so there is nothing to submit here. Serves
|
|
1385
|
+
// as the redirect target `DashboardAuthPageGuard` bounces to instead of `/auth/login`, which
|
|
1386
|
+
// 404s under Mode A (see `loginPage` above).
|
|
1387
|
+
sessionRequiredPage() {
|
|
1388
|
+
const auth = this.requireAuth();
|
|
1389
|
+
if (auth.modes.includes("login")) throw new NotFoundException();
|
|
1390
|
+
return renderSessionRequiredPage();
|
|
1391
|
+
}
|
|
1322
1392
|
/** Uniform failure: same redirect (generic error flag) whether the user is unknown or the password is wrong. */
|
|
1323
1393
|
redirectToLoginError(res, returnTo) {
|
|
1324
1394
|
res.status(303);
|
|
@@ -1334,17 +1404,17 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
|
|
|
1334
1404
|
}) !== null;
|
|
1335
1405
|
}
|
|
1336
1406
|
/**
|
|
1337
|
-
* Run
|
|
1338
|
-
* (`null`) and warn-logged ONCE, so a buggy/unreachable hook never 500s the
|
|
1339
|
-
* stack-trace leak nor floods the logs.
|
|
1407
|
+
* Run a host hook (`login` or `session`) defensively: a throw (sync or async) is treated as a
|
|
1408
|
+
* denial (`null`) and warn-logged ONCE PER KIND, so a buggy/unreachable hook never 500s the
|
|
1409
|
+
* endpoint into a stack-trace leak nor floods the logs on repeated bad attempts.
|
|
1340
1410
|
*/
|
|
1341
|
-
async
|
|
1411
|
+
async runHook(kind, run) {
|
|
1342
1412
|
try {
|
|
1343
|
-
return await
|
|
1413
|
+
return await run() ?? null;
|
|
1344
1414
|
} catch (error) {
|
|
1345
|
-
if (!this.
|
|
1346
|
-
this.
|
|
1347
|
-
this.logger.warn(`AgentDashboardModule dashboardAuth
|
|
1415
|
+
if (!this.warnedHooks.has(kind)) {
|
|
1416
|
+
this.warnedHooks.add(kind);
|
|
1417
|
+
this.logger.warn(`AgentDashboardModule dashboardAuth ${kind} hook threw; treating as denial. ${error instanceof Error ? error.message : String(error)}`);
|
|
1348
1418
|
}
|
|
1349
1419
|
return null;
|
|
1350
1420
|
}
|
|
@@ -1401,6 +1471,28 @@ _ts_decorate4([
|
|
|
1401
1471
|
]),
|
|
1402
1472
|
_ts_metadata4("design:returntype", String)
|
|
1403
1473
|
], AgentDashboardAuthController.prototype, "logout", null);
|
|
1474
|
+
_ts_decorate4([
|
|
1475
|
+
Post2("session"),
|
|
1476
|
+
HttpCode2(204),
|
|
1477
|
+
_ts_param4(0, Req2()),
|
|
1478
|
+
_ts_param4(1, Res({
|
|
1479
|
+
passthrough: true
|
|
1480
|
+
})),
|
|
1481
|
+
_ts_metadata4("design:type", Function),
|
|
1482
|
+
_ts_metadata4("design:paramtypes", [
|
|
1483
|
+
Object,
|
|
1484
|
+
Object
|
|
1485
|
+
]),
|
|
1486
|
+
_ts_metadata4("design:returntype", Promise)
|
|
1487
|
+
], AgentDashboardAuthController.prototype, "session", null);
|
|
1488
|
+
_ts_decorate4([
|
|
1489
|
+
Get2("session-required"),
|
|
1490
|
+
Header("Content-Type", "text/html; charset=utf-8"),
|
|
1491
|
+
Header("Cache-Control", "no-store, must-revalidate"),
|
|
1492
|
+
_ts_metadata4("design:type", Function),
|
|
1493
|
+
_ts_metadata4("design:paramtypes", []),
|
|
1494
|
+
_ts_metadata4("design:returntype", String)
|
|
1495
|
+
], AgentDashboardAuthController.prototype, "sessionRequiredPage", null);
|
|
1404
1496
|
AgentDashboardAuthController = _ts_decorate4([
|
|
1405
1497
|
Controller2("auth"),
|
|
1406
1498
|
_ts_param4(0, Optional4()),
|
|
@@ -1513,19 +1605,39 @@ var DashboardAuthPageGuard = class {
|
|
|
1513
1605
|
this.auth = auth;
|
|
1514
1606
|
this.basePath = basePath;
|
|
1515
1607
|
}
|
|
1516
|
-
canActivate(context) {
|
|
1608
|
+
async canActivate(context) {
|
|
1517
1609
|
if (!this.auth) return true;
|
|
1610
|
+
const auth = this.auth;
|
|
1518
1611
|
const http = context.switchToHttp();
|
|
1519
1612
|
const request = http.getRequest();
|
|
1520
1613
|
const session = this.verifyRequestSession(request);
|
|
1521
|
-
if (!session)
|
|
1522
|
-
const returnTo = readOriginalUrl(request);
|
|
1523
|
-
throw new DashboardAuthRedirect(`${this.basePath}/auth/login?returnTo=${encodeURIComponent(returnTo)}`);
|
|
1524
|
-
}
|
|
1614
|
+
if (!session) this.deny(auth, request);
|
|
1525
1615
|
attachSession(request, session);
|
|
1526
|
-
|
|
1616
|
+
if (!await maybeRenewSession(auth, session, request, http.getResponse())) {
|
|
1617
|
+
this.deny(auth, request);
|
|
1618
|
+
}
|
|
1527
1619
|
return true;
|
|
1528
1620
|
}
|
|
1621
|
+
/**
|
|
1622
|
+
* No valid session: bounce the browser navigation onward. Under Mode B (`login` configured)
|
|
1623
|
+
* that's the built-in login screen, carrying `returnTo` back to the page that was requested.
|
|
1624
|
+
* Under Mode-A-only there is no login screen to redirect to — the host mints the session
|
|
1625
|
+
* itself — so this instead serves the instruction page rather than redirecting into a 404.
|
|
1626
|
+
* Pulled out of `canActivate` so both the "no session at all" and the "revalidate revoked a
|
|
1627
|
+
* renewable session" paths reuse the exact same mode-aware deny logic.
|
|
1628
|
+
*
|
|
1629
|
+
* Takes `auth` explicitly rather than reading `this.auth`: `canActivate`'s `!this.auth` early
|
|
1630
|
+
* return narrows the field within that method only — TS doesn't carry it across a method call —
|
|
1631
|
+
* so the caller passes the already-narrowed value instead of this method re-deriving (or
|
|
1632
|
+
* asserting away) the nullability.
|
|
1633
|
+
*/
|
|
1634
|
+
deny(auth, request) {
|
|
1635
|
+
if (!auth.modes.includes("login")) {
|
|
1636
|
+
throw new DashboardAuthRedirect(`${this.basePath}/auth/session-required`);
|
|
1637
|
+
}
|
|
1638
|
+
const returnTo = readOriginalUrl(request);
|
|
1639
|
+
throw new DashboardAuthRedirect(`${this.basePath}/auth/login?returnTo=${encodeURIComponent(returnTo)}`);
|
|
1640
|
+
}
|
|
1529
1641
|
verifyRequestSession(request) {
|
|
1530
1642
|
const auth = this.auth;
|
|
1531
1643
|
if (!auth) return null;
|
|
@@ -1535,28 +1647,6 @@ var DashboardAuthPageGuard = class {
|
|
|
1535
1647
|
secret: auth.secret
|
|
1536
1648
|
});
|
|
1537
1649
|
}
|
|
1538
|
-
/**
|
|
1539
|
-
* Sliding renewal: a valid cookie past 50% of its TTL is transparently re-issued on the
|
|
1540
|
-
* response, so an active user never gets logged out mid-session.
|
|
1541
|
-
*/
|
|
1542
|
-
maybeRenew(response, request, session) {
|
|
1543
|
-
const auth = this.auth;
|
|
1544
|
-
if (!auth) return;
|
|
1545
|
-
const now = Date.now();
|
|
1546
|
-
if (now - session.iat <= auth.ttlMs / 2) return;
|
|
1547
|
-
issueSessionCookie({
|
|
1548
|
-
id: session.sub,
|
|
1549
|
-
...session.name !== void 0 ? {
|
|
1550
|
-
name: session.name
|
|
1551
|
-
} : {},
|
|
1552
|
-
roles: session.roles
|
|
1553
|
-
}, {
|
|
1554
|
-
auth,
|
|
1555
|
-
request,
|
|
1556
|
-
response,
|
|
1557
|
-
now
|
|
1558
|
-
});
|
|
1559
|
-
}
|
|
1560
1650
|
};
|
|
1561
1651
|
DashboardAuthPageGuard = _ts_decorate6([
|
|
1562
1652
|
Injectable4(),
|
|
@@ -1715,13 +1805,38 @@ function resolveDashboardAuth(options) {
|
|
|
1715
1805
|
if (typeof options.secret !== "string" || options.secret === "") {
|
|
1716
1806
|
throw new Error("AgentDashboardModule dashboardAuth: `secret` is required and must be a non-empty string (HMAC-SHA256 signing key, 32+ bytes recommended). Failing closed.");
|
|
1717
1807
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1808
|
+
const modes = [];
|
|
1809
|
+
if (options.session !== void 0) {
|
|
1810
|
+
if (typeof options.session !== "function") {
|
|
1811
|
+
throw new Error("AgentDashboardModule dashboardAuth: `session` must be a function.");
|
|
1812
|
+
}
|
|
1813
|
+
modes.push("session");
|
|
1814
|
+
}
|
|
1815
|
+
if (options.login !== void 0) {
|
|
1816
|
+
if (typeof options.login !== "function") {
|
|
1817
|
+
throw new Error("AgentDashboardModule dashboardAuth: `login` must be a function.");
|
|
1818
|
+
}
|
|
1819
|
+
modes.push("login");
|
|
1820
|
+
}
|
|
1821
|
+
if (options.revalidate !== void 0 && typeof options.revalidate !== "function") {
|
|
1822
|
+
throw new Error("AgentDashboardModule dashboardAuth: `revalidate` must be a function.");
|
|
1823
|
+
}
|
|
1824
|
+
if (modes.length === 0) {
|
|
1825
|
+
throw new Error("AgentDashboardModule dashboardAuth: at least one of `session` (the host mints the session from its own auth) or `login` (the built-in login screen) is required \u2014 otherwise the cookie can never be minted. Failing closed.");
|
|
1720
1826
|
}
|
|
1721
1827
|
return {
|
|
1722
1828
|
secret: options.secret,
|
|
1723
1829
|
ttlMs: durationToMs(options.ttl ?? DEFAULT_TTL),
|
|
1724
|
-
|
|
1830
|
+
modes,
|
|
1831
|
+
...options.session !== void 0 ? {
|
|
1832
|
+
session: options.session
|
|
1833
|
+
} : {},
|
|
1834
|
+
...options.login !== void 0 ? {
|
|
1835
|
+
login: options.login
|
|
1836
|
+
} : {},
|
|
1837
|
+
...options.revalidate !== void 0 ? {
|
|
1838
|
+
revalidate: options.revalidate
|
|
1839
|
+
} : {}
|
|
1725
1840
|
};
|
|
1726
1841
|
}
|
|
1727
1842
|
__name(resolveDashboardAuth, "resolveDashboardAuth");
|