@agent-native/core 0.195.0 → 0.195.1-nightly-20260927210321
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/corpus/README.md +1 -1
- package/corpus/templates/design/actions/generate-home-suggestions.ts +55 -7
- package/corpus/templates/design/app/components/design/design-canvas/LocalNetworkAccessPrompt.tsx +82 -18
- package/corpus/templates/design/app/i18n/en-US.ts +6 -1
- package/corpus/templates/design/changelog/2026-09-27-local-access-setup-shows-chrome-permission-screenshots-and-c.md +6 -0
- package/corpus/templates/design/changelog/2026-09-27-personalized-home-suggestions-work-when-responses-include-ex.md +6 -0
- package/corpus/templates/mail/app/components/email/EmailList.tsx +10 -0
- package/corpus/templates/mail/app/components/email/EmailListItem.tsx +78 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +9 -9
- package/corpus/templates/mail/app/components/layout/SearchBar.tsx +192 -175
- package/corpus/templates/mail/app/components/onboarding/AiInboxSetup.tsx +4 -0
- package/corpus/templates/mail/app/global.css +14 -0
- package/corpus/templates/mail/changelog/2026-09-27-inbox-priority-shows-each-email-s-score-with-quick-feedback-.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-27-mail-setup-waits-for-first-run-onboarding-and-empty-importan.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-27-mobile-inbox-toolbar-scrolls-together.md +6 -0
- package/corpus/templates/slides/actions/generate-home-suggestions.ts +55 -11
- package/corpus/templates/slides/changelog/2026-09-27-personalized-presentation-suggestions-work-when-responses-in.md +6 -0
- package/dist/client/onboarding/first-run-startup-gate.js +3 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/auth-policy.js +0 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/auth-plugin.js +2 -1
- package/dist/server/auth.js +22 -43
- package/dist/triggers/actions/manage-automation.d.ts +2 -2
- package/dist/vite/agent-native-config-loader.js +4 -2
- package/package.json +3 -3
- package/dist/server/session-email-cache.d.ts +0 -14
- package/dist/server/session-email-cache.js +0 -53
|
@@ -311,6 +311,7 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
+
message?: undefined;
|
|
314
315
|
id?: undefined;
|
|
315
316
|
deleted?: undefined;
|
|
316
317
|
provider?: undefined;
|
|
@@ -327,8 +328,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
327
328
|
found?: undefined;
|
|
328
329
|
registered?: undefined;
|
|
329
330
|
label?: undefined;
|
|
330
|
-
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
+
message?: undefined;
|
|
332
333
|
id?: undefined;
|
|
333
334
|
deleted?: undefined;
|
|
334
335
|
count?: undefined;
|
|
@@ -337,8 +338,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
337
338
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
338
339
|
registered?: undefined;
|
|
339
340
|
label?: undefined;
|
|
340
|
-
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
+
message?: undefined;
|
|
342
343
|
deleted?: undefined;
|
|
343
344
|
provider?: undefined;
|
|
344
345
|
count?: undefined;
|
|
@@ -347,8 +348,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
347
348
|
id: string;
|
|
348
349
|
registered?: undefined;
|
|
349
350
|
label?: undefined;
|
|
350
|
-
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
+
message?: undefined;
|
|
352
353
|
provider?: undefined;
|
|
353
354
|
count?: undefined;
|
|
354
355
|
providers?: undefined;
|
|
@@ -357,7 +358,6 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
357
358
|
id: string;
|
|
358
359
|
registered?: undefined;
|
|
359
360
|
label?: undefined;
|
|
360
|
-
message?: undefined;
|
|
361
361
|
} | {
|
|
362
362
|
deleted?: undefined;
|
|
363
363
|
provider?: undefined;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -35,30 +35,30 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
35
35
|
ok?: undefined;
|
|
36
36
|
status?: undefined;
|
|
37
37
|
} | {
|
|
38
|
-
error?: undefined;
|
|
39
38
|
ok: boolean;
|
|
40
39
|
status: string;
|
|
40
|
+
error?: undefined;
|
|
41
41
|
} | {
|
|
42
42
|
ok?: undefined;
|
|
43
43
|
error: string;
|
|
44
44
|
removed?: undefined;
|
|
45
45
|
} | {
|
|
46
|
-
error?: undefined;
|
|
47
46
|
ok: boolean;
|
|
48
47
|
removed: boolean;
|
|
48
|
+
error?: undefined;
|
|
49
49
|
}>>;
|
|
50
50
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
51
51
|
ok?: undefined;
|
|
52
52
|
error: string;
|
|
53
53
|
note?: undefined;
|
|
54
54
|
} | {
|
|
55
|
-
error?: undefined;
|
|
56
55
|
ok: boolean;
|
|
57
56
|
note?: undefined;
|
|
58
|
-
} | {
|
|
59
57
|
error?: undefined;
|
|
58
|
+
} | {
|
|
60
59
|
ok: boolean;
|
|
61
60
|
note: string;
|
|
61
|
+
error?: undefined;
|
|
62
62
|
} | {
|
|
63
63
|
note?: undefined;
|
|
64
64
|
ok: boolean;
|
|
@@ -78,11 +78,11 @@ export interface AdHocSecretPayload {
|
|
|
78
78
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
79
79
|
error: string;
|
|
80
80
|
} | {
|
|
81
|
-
error?: undefined;
|
|
82
81
|
ok: boolean;
|
|
83
82
|
key: string;
|
|
84
|
-
} | {
|
|
85
83
|
error?: undefined;
|
|
84
|
+
} | {
|
|
86
85
|
ok: boolean;
|
|
87
86
|
removed: boolean;
|
|
87
|
+
error?: undefined;
|
|
88
88
|
}>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getMethod, setResponseStatus } from "h3";
|
|
1
|
+
import { getMethod, setResponseHeader, setResponseStatus } from "h3";
|
|
2
2
|
import { autoMountAuth } from "./auth.js";
|
|
3
3
|
import { getSession } from "./auth.js";
|
|
4
4
|
import { runBetterAuthMigrations } from "./better-auth-migrations.js";
|
|
@@ -12,6 +12,7 @@ export function createAuthPlugin(options) {
|
|
|
12
12
|
if (!isByoa) {
|
|
13
13
|
markFrameworkRoutesReadyBeforeBootstrap(nitroApp, [sessionPath]);
|
|
14
14
|
app.use(sessionPath, async (event) => {
|
|
15
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
15
16
|
const method = getMethod(event);
|
|
16
17
|
if (method !== "GET" && method !== "HEAD") {
|
|
17
18
|
setResponseStatus(event, 405);
|
package/dist/server/auth.js
CHANGED
|
@@ -80,7 +80,6 @@ import { safeOAuthReturnUrl } from "./oauth-return-url.js";
|
|
|
80
80
|
import { getOnboardingHtml, getResetPasswordHtml, } from "./onboarding-html.js";
|
|
81
81
|
import { getRequestContext, markRequestIdentityAuthenticatedAtMs, hasContinuationLocalRequestContext, hasExplicitPersonalOrgScope, markExplicitPersonalOrgScope, runWithRequestContext, } from "./request-context.js";
|
|
82
82
|
import { captureAuthError } from "./sentry.js";
|
|
83
|
-
import { forgetCachedSessionEmail, getCachedSessionEmail, getSessionEmailCacheGeneration, invalidateSessionEmailCache, setCachedSessionEmail, } from "./session-email-cache.js";
|
|
84
83
|
import { isWorkspaceOAuthCallbackRelayEnabled } from "./workspace-oauth.js";
|
|
85
84
|
function stripAppBasePath(pathname) {
|
|
86
85
|
return stripConfiguredAppBasePath(pathname, getAppBasePath());
|
|
@@ -1325,7 +1324,6 @@ export async function addSession(token, email) {
|
|
|
1325
1324
|
sql: `INSERT INTO sessions (token, email, created_at) VALUES (?, ?, ?) ON CONFLICT (token) DO UPDATE SET email=EXCLUDED.email, created_at=EXCLUDED.created_at`,
|
|
1326
1325
|
args: [token, email ?? null, Date.now()],
|
|
1327
1326
|
}));
|
|
1328
|
-
invalidateSessionEmailCache();
|
|
1329
1327
|
}
|
|
1330
1328
|
async function replaceSession(oldToken, newToken, email) {
|
|
1331
1329
|
await ensureSessionTable();
|
|
@@ -1343,7 +1341,6 @@ async function replaceSession(oldToken, newToken, email) {
|
|
|
1343
1341
|
args: [oldToken],
|
|
1344
1342
|
});
|
|
1345
1343
|
}));
|
|
1346
|
-
invalidateSessionEmailCache();
|
|
1347
1344
|
}
|
|
1348
1345
|
export async function hasLegacySessionForEmail(email) {
|
|
1349
1346
|
await ensureSessionTable();
|
|
@@ -1361,7 +1358,6 @@ export async function removeSession(token) {
|
|
|
1361
1358
|
sql: `DELETE FROM sessions WHERE token = ?`,
|
|
1362
1359
|
args: [token],
|
|
1363
1360
|
}));
|
|
1364
|
-
invalidateSessionEmailCache();
|
|
1365
1361
|
}
|
|
1366
1362
|
/**
|
|
1367
1363
|
* The one logout implementation, shared by every auth mode's route.
|
|
@@ -1402,7 +1398,6 @@ async function performLogout(event, getAuth) {
|
|
|
1402
1398
|
}
|
|
1403
1399
|
try {
|
|
1404
1400
|
const identities = await getPresentedSessionIdentities(event, candidates, Boolean(auth || revocationFailed));
|
|
1405
|
-
invalidateSessionEmailCache();
|
|
1406
1401
|
await ensureSessionTable();
|
|
1407
1402
|
await revokeEmbedSessionsForOwners([...identities], async (tx) => {
|
|
1408
1403
|
const canRevokeBetterAuth = auth
|
|
@@ -1423,14 +1418,10 @@ async function performLogout(event, getAuth) {
|
|
|
1423
1418
|
});
|
|
1424
1419
|
}
|
|
1425
1420
|
catch (error) {
|
|
1426
|
-
invalidateSessionEmailCache();
|
|
1427
1421
|
captureAuthError(error, { route: "logout" });
|
|
1428
1422
|
setResponseStatus(event, 503);
|
|
1429
1423
|
return { error: "Unable to revoke session" };
|
|
1430
1424
|
}
|
|
1431
|
-
finally {
|
|
1432
|
-
invalidateSessionEmailCache();
|
|
1433
|
-
}
|
|
1434
1425
|
if (!revocationFailed) {
|
|
1435
1426
|
clearFrameworkSessionCookies(event);
|
|
1436
1427
|
clearIdentityGoogleAuthCookie(event);
|
|
@@ -1466,10 +1457,6 @@ export async function logout(event) {
|
|
|
1466
1457
|
return performLogout(event, () => getBetterAuth());
|
|
1467
1458
|
}
|
|
1468
1459
|
export async function getSessionEmail(token) {
|
|
1469
|
-
const cached = getCachedSessionEmail(token);
|
|
1470
|
-
if (cached !== undefined)
|
|
1471
|
-
return cached;
|
|
1472
|
-
const cacheGeneration = getSessionEmailCacheGeneration();
|
|
1473
1460
|
await ensureSessionTable();
|
|
1474
1461
|
const client = getDbExec();
|
|
1475
1462
|
const { rows } = await retryIfSessionsMissing(() => client.execute({
|
|
@@ -1484,12 +1471,9 @@ export async function getSessionEmail(token) {
|
|
|
1484
1471
|
sql: `DELETE FROM sessions WHERE token = ?`,
|
|
1485
1472
|
args: [token],
|
|
1486
1473
|
});
|
|
1487
|
-
forgetCachedSessionEmail(token);
|
|
1488
1474
|
return null;
|
|
1489
1475
|
}
|
|
1490
1476
|
const email = rows[0].email ?? null;
|
|
1491
|
-
if (email)
|
|
1492
|
-
setCachedSessionEmail(token, email, cacheGeneration);
|
|
1493
1477
|
return email;
|
|
1494
1478
|
}
|
|
1495
1479
|
async function resolveLegacySessionEmailVerification(email) {
|
|
@@ -1976,7 +1960,6 @@ async function consumeDesktopExchangeFromDB(flowId) {
|
|
|
1976
1960
|
});
|
|
1977
1961
|
if (deleted.rows.length === 0)
|
|
1978
1962
|
return { status: "missing" };
|
|
1979
|
-
forgetCachedSessionEmail(`dex:${flowId}`);
|
|
1980
1963
|
return { status: "entry", entry };
|
|
1981
1964
|
}
|
|
1982
1965
|
catch {
|
|
@@ -4700,7 +4683,6 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
4700
4683
|
args: [userEmail],
|
|
4701
4684
|
});
|
|
4702
4685
|
}
|
|
4703
|
-
invalidateSessionEmailCache();
|
|
4704
4686
|
}
|
|
4705
4687
|
}
|
|
4706
4688
|
catch {
|
|
@@ -4952,35 +4934,29 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
4952
4934
|
const sessionEmail = normalizeAuthEmail(session.email);
|
|
4953
4935
|
if (sessionEmail)
|
|
4954
4936
|
identities.add(sessionEmail);
|
|
4955
|
-
invalidateSessionEmailCache();
|
|
4956
4937
|
await ensureSessionTable();
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
sql: 'SELECT id FROM "user" WHERE email = ?',
|
|
4964
|
-
args: [email],
|
|
4965
|
-
});
|
|
4966
|
-
const userId = (rows[0]?.id ?? rows[0]?.[0]);
|
|
4967
|
-
if (userId) {
|
|
4968
|
-
await tx.execute({
|
|
4969
|
-
sql: 'DELETE FROM "session" WHERE user_id = ?',
|
|
4970
|
-
args: [userId],
|
|
4971
|
-
});
|
|
4972
|
-
}
|
|
4973
|
-
}
|
|
4974
|
-
await tx.execute({
|
|
4975
|
-
sql: "DELETE FROM sessions WHERE email = ?",
|
|
4938
|
+
await revokeEmbedSessionsForOwners([...identities], async (tx) => {
|
|
4939
|
+
const canRevokeBetterAuth = await betterAuthTablesAvailable(tx);
|
|
4940
|
+
for (const email of identities) {
|
|
4941
|
+
if (canRevokeBetterAuth) {
|
|
4942
|
+
const { rows } = await tx.execute({
|
|
4943
|
+
sql: 'SELECT id FROM "user" WHERE email = ?',
|
|
4976
4944
|
args: [email],
|
|
4977
4945
|
});
|
|
4946
|
+
const userId = (rows[0]?.id ?? rows[0]?.[0]);
|
|
4947
|
+
if (userId) {
|
|
4948
|
+
await tx.execute({
|
|
4949
|
+
sql: 'DELETE FROM "session" WHERE user_id = ?',
|
|
4950
|
+
args: [userId],
|
|
4951
|
+
});
|
|
4952
|
+
}
|
|
4978
4953
|
}
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4954
|
+
await tx.execute({
|
|
4955
|
+
sql: "DELETE FROM sessions WHERE email = ?",
|
|
4956
|
+
args: [email],
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4959
|
+
});
|
|
4984
4960
|
clearFrameworkSessionCookies(event);
|
|
4985
4961
|
clearFirstRunOnboardingCookie(event);
|
|
4986
4962
|
optOutOfAuthDisabledSession(event);
|
|
@@ -5004,6 +4980,7 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
5004
4980
|
}
|
|
5005
4981
|
}));
|
|
5006
4982
|
app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
|
|
4983
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
5007
4984
|
if (!isReadMethod(event)) {
|
|
5008
4985
|
setResponseStatus(event, 405);
|
|
5009
4986
|
return { error: "Method not allowed" };
|
|
@@ -5159,6 +5136,7 @@ function mountAuthFallbackRoutes(app) {
|
|
|
5159
5136
|
return performLogout(event, () => getBetterAuth());
|
|
5160
5137
|
}));
|
|
5161
5138
|
app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
|
|
5139
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
5162
5140
|
if (!isReadMethod(event)) {
|
|
5163
5141
|
setResponseStatus(event, 405);
|
|
5164
5142
|
return { error: "Method not allowed" };
|
|
@@ -5252,6 +5230,7 @@ export async function autoMountAuth(app, options = {}) {
|
|
|
5252
5230
|
}
|
|
5253
5231
|
if (customGetSession) {
|
|
5254
5232
|
app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
|
|
5233
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
5255
5234
|
if (!isReadMethod(event)) {
|
|
5256
5235
|
setResponseStatus(event, 405);
|
|
5257
5236
|
return { error: "Method not allowed" };
|
|
@@ -13,6 +13,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
13
13
|
executionEngine?: string;
|
|
14
14
|
executionCwd?: string;
|
|
15
15
|
}, {
|
|
16
|
+
deleted?: undefined;
|
|
16
17
|
created: boolean;
|
|
17
18
|
name: string;
|
|
18
19
|
scope: "organization" | "personal";
|
|
@@ -23,7 +24,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
23
24
|
reasoningEffort: "auto" | "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh";
|
|
24
25
|
webhookPath: string;
|
|
25
26
|
nextRun: string;
|
|
26
|
-
deleted?: undefined;
|
|
27
27
|
enabled?: undefined;
|
|
28
28
|
executionHostId?: undefined;
|
|
29
29
|
executionEngine?: undefined;
|
|
@@ -45,11 +45,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
45
45
|
nextRun?: undefined;
|
|
46
46
|
webhookPath?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
deleted?: undefined;
|
|
48
49
|
created?: undefined;
|
|
49
50
|
scope?: undefined;
|
|
50
51
|
triggerType?: undefined;
|
|
51
52
|
event?: undefined;
|
|
52
|
-
deleted?: undefined;
|
|
53
53
|
name: string;
|
|
54
54
|
enabled: boolean;
|
|
55
55
|
schedule: string;
|
|
@@ -36,7 +36,8 @@ export async function loadAgentNativeConfigFile(cwd) {
|
|
|
36
36
|
if (!configPath)
|
|
37
37
|
return undefined;
|
|
38
38
|
try {
|
|
39
|
-
const module = (await import(
|
|
39
|
+
const module = (await import(
|
|
40
|
+
/* @vite-ignore */ pathToFileURL(configPath).href));
|
|
40
41
|
const config = module.default ?? module.agentNativeConfig;
|
|
41
42
|
if (typeof config !== "object" && typeof config !== "function") {
|
|
42
43
|
throw new Error("the default export must be an object or function");
|
|
@@ -55,7 +56,8 @@ export async function loadWorkspaceAgentNativeConfigFile(cwd) {
|
|
|
55
56
|
if (!configPath)
|
|
56
57
|
return undefined;
|
|
57
58
|
try {
|
|
58
|
-
const module = (await import(
|
|
59
|
+
const module = (await import(
|
|
60
|
+
/* @vite-ignore */ pathToFileURL(configPath).href));
|
|
59
61
|
const config = module.default ?? module.agentNativeConfig;
|
|
60
62
|
if (typeof config !== "object" && typeof config !== "function") {
|
|
61
63
|
throw new Error("the default export must be an object or function");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.195.
|
|
3
|
+
"version": "0.195.1-nightly-20260927210321",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -517,9 +517,9 @@
|
|
|
517
517
|
"yaml": "^2.9.0",
|
|
518
518
|
"yjs": "^13.6.32",
|
|
519
519
|
"zod": "^4.3.6",
|
|
520
|
-
"@agent-native/recap-cli": "0.5.47",
|
|
521
520
|
"@agent-native/agentkit": "^0.4.1",
|
|
522
|
-
"@agent-native/toolkit": "^0.22.3"
|
|
521
|
+
"@agent-native/toolkit": "^0.22.3",
|
|
522
|
+
"@agent-native/recap-cli": "0.5.47"
|
|
523
523
|
},
|
|
524
524
|
"devDependencies": {
|
|
525
525
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare function getCachedSessionEmail(token: string): string | undefined;
|
|
2
|
-
export declare function getSessionEmailCacheGeneration(): number;
|
|
3
|
-
export declare function setCachedSessionEmail(token: string, email: string, generation: number): void;
|
|
4
|
-
export declare function forgetCachedSessionEmail(token: string): void;
|
|
5
|
-
/**
|
|
6
|
-
* Drop cached session resolutions. Call after ANY write to `sessions`.
|
|
7
|
-
*
|
|
8
|
-
* Clears every token rather than one: the bulk sign-out paths delete by email
|
|
9
|
-
* (`DELETE FROM sessions WHERE email = ?`) and do not know which tokens they
|
|
10
|
-
* removed, so a per-token eviction there would leave a signed-out session
|
|
11
|
-
* resolving for the rest of the TTL.
|
|
12
|
-
*/
|
|
13
|
-
export declare function invalidateSessionEmailCache(): void;
|
|
14
|
-
export declare function __resetSessionEmailCacheForTests(): void;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { createTtlCache } from "../shared/ttl-cache.js";
|
|
2
|
-
/**
|
|
3
|
-
* Cross-request cache for resolved legacy session tokens.
|
|
4
|
-
*
|
|
5
|
-
* A session token is immutable for its (30-day) lifetime, yet every
|
|
6
|
-
* authenticated request re-read it: production showed 494,848 of these for 3
|
|
7
|
-
* users, 1:1 with the request count. The TTL is far shorter than the session
|
|
8
|
-
* lifetime, so expiry is enforced at most `SESSION_EMAIL_TTL_MS` late — a 30-day
|
|
9
|
-
* boundary observed up to 15s late changes nothing.
|
|
10
|
-
*
|
|
11
|
-
* ONLY successful resolutions belong in here. A `null` — no such token, expired,
|
|
12
|
-
* revoked — must stay uncached so a sign-out or a token that has just been
|
|
13
|
-
* written is never answered from a stale negative, and so an auth failure can
|
|
14
|
-
* never be made sticky by a cache.
|
|
15
|
-
*
|
|
16
|
-
* Lives in its own module rather than in `auth.ts` because `auth.ts` imports
|
|
17
|
-
* `org/auth-policy.ts`, which also revokes sessions and so needs to invalidate
|
|
18
|
-
* this. Importing back into `auth.ts` from there would be a cycle.
|
|
19
|
-
*/
|
|
20
|
-
const SESSION_EMAIL_TTL_MS = 15_000;
|
|
21
|
-
const sessionEmailCache = createTtlCache({
|
|
22
|
-
ttlMs: SESSION_EMAIL_TTL_MS,
|
|
23
|
-
maxEntries: 4_096,
|
|
24
|
-
});
|
|
25
|
-
let cacheGeneration = 0;
|
|
26
|
-
export function getCachedSessionEmail(token) {
|
|
27
|
-
return sessionEmailCache.get(token);
|
|
28
|
-
}
|
|
29
|
-
export function getSessionEmailCacheGeneration() {
|
|
30
|
-
return cacheGeneration;
|
|
31
|
-
}
|
|
32
|
-
export function setCachedSessionEmail(token, email, generation) {
|
|
33
|
-
if (generation === cacheGeneration)
|
|
34
|
-
sessionEmailCache.set(token, email);
|
|
35
|
-
}
|
|
36
|
-
export function forgetCachedSessionEmail(token) {
|
|
37
|
-
sessionEmailCache.delete(token);
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Drop cached session resolutions. Call after ANY write to `sessions`.
|
|
41
|
-
*
|
|
42
|
-
* Clears every token rather than one: the bulk sign-out paths delete by email
|
|
43
|
-
* (`DELETE FROM sessions WHERE email = ?`) and do not know which tokens they
|
|
44
|
-
* removed, so a per-token eviction there would leave a signed-out session
|
|
45
|
-
* resolving for the rest of the TTL.
|
|
46
|
-
*/
|
|
47
|
-
export function invalidateSessionEmailCache() {
|
|
48
|
-
cacheGeneration++;
|
|
49
|
-
sessionEmailCache.clear();
|
|
50
|
-
}
|
|
51
|
-
export function __resetSessionEmailCacheForTests() {
|
|
52
|
-
sessionEmailCache.clear();
|
|
53
|
-
}
|