veryfront 0.1.748 → 0.1.749
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/esm/cli/templates/manifest.js +2 -2
- package/esm/deno.js +1 -1
- package/esm/src/build/production-build/static-generation.d.ts.map +1 -1
- package/esm/src/build/production-build/static-generation.js +2 -0
- package/esm/src/cache/backends/disk.d.ts +1 -1
- package/esm/src/cache/backends/disk.d.ts.map +1 -1
- package/esm/src/cache/backends/disk.js +41 -13
- package/esm/src/cache/backends/glob.d.ts +6 -0
- package/esm/src/cache/backends/glob.d.ts.map +1 -0
- package/esm/src/cache/backends/glob.js +41 -0
- package/esm/src/cache/backends/memory.d.ts +1 -1
- package/esm/src/cache/backends/memory.d.ts.map +1 -1
- package/esm/src/cache/backends/memory.js +14 -12
- package/esm/src/cache/backends/redis.d.ts.map +1 -1
- package/esm/src/cache/backends/redis.js +33 -7
- package/esm/src/cache/dependency-graph.d.ts +1 -0
- package/esm/src/cache/dependency-graph.d.ts.map +1 -1
- package/esm/src/cache/dependency-graph.js +15 -1
- package/esm/src/cache/paths.d.ts.map +1 -1
- package/esm/src/cache/paths.js +5 -0
- package/esm/src/embedding/index.d.ts +4 -1
- package/esm/src/embedding/index.d.ts.map +1 -1
- package/esm/src/embedding/index.js +3 -1
- package/esm/src/embedding/rag-store.d.ts.map +1 -1
- package/esm/src/embedding/rag-store.js +157 -8
- package/esm/src/embedding/react/use-uploads.d.ts +1 -0
- package/esm/src/embedding/react/use-uploads.d.ts.map +1 -1
- package/esm/src/embedding/react/use-uploads.js +4 -1
- package/esm/src/embedding/upload-handler.d.ts +29 -8
- package/esm/src/embedding/upload-handler.d.ts.map +1 -1
- package/esm/src/embedding/upload-handler.js +66 -6
- package/esm/src/html/html-shell-generator.js +5 -5
- package/esm/src/html/nonce-injection.d.ts.map +1 -1
- package/esm/src/html/nonce-injection.js +11 -4
- package/esm/src/html/utils.d.ts +5 -0
- package/esm/src/html/utils.d.ts.map +1 -1
- package/esm/src/html/utils.js +19 -9
- package/esm/src/modules/react-loader/ssr-module-loader/import-rewriter.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/import-rewriter.js +12 -5
- package/esm/src/modules/server/module-batch-handler.d.ts +1 -0
- package/esm/src/modules/server/module-batch-handler.d.ts.map +1 -1
- package/esm/src/modules/server/module-batch-handler.js +52 -26
- package/esm/src/modules/server/module-server.d.ts.map +1 -1
- package/esm/src/modules/server/module-server.js +87 -69
- package/esm/src/modules/server/module-source-resolution-cache.d.ts +16 -0
- package/esm/src/modules/server/module-source-resolution-cache.d.ts.map +1 -0
- package/esm/src/modules/server/module-source-resolution-cache.js +43 -0
- package/esm/src/oauth/providers/base.d.ts +0 -2
- package/esm/src/oauth/providers/base.d.ts.map +1 -1
- package/esm/src/oauth/providers/base.js +35 -10
- package/esm/src/oauth/token-store/memory.d.ts +7 -0
- package/esm/src/oauth/token-store/memory.d.ts.map +1 -1
- package/esm/src/oauth/token-store/memory.js +14 -1
- package/esm/src/observability/file-log-subscriber.d.ts +1 -0
- package/esm/src/observability/file-log-subscriber.d.ts.map +1 -1
- package/esm/src/observability/file-log-subscriber.js +2 -1
- package/esm/src/observability/tracing/api-shim.d.ts +1 -0
- package/esm/src/observability/tracing/api-shim.d.ts.map +1 -1
- package/esm/src/observability/tracing/api-shim.js +7 -0
- package/esm/src/observability/tracing/otlp-setup.d.ts.map +1 -1
- package/esm/src/observability/tracing/otlp-setup.js +17 -7
- package/esm/src/proxy/handler.d.ts +5 -2
- package/esm/src/proxy/handler.d.ts.map +1 -1
- package/esm/src/proxy/handler.js +26 -25
- package/esm/src/proxy/main.js +8 -11
- package/esm/src/rendering/renderer.d.ts.map +1 -1
- package/esm/src/rendering/renderer.js +32 -12
- package/esm/src/server/context/cache-invalidation.d.ts.map +1 -1
- package/esm/src/server/context/cache-invalidation.js +2 -0
- package/esm/src/server/handlers/dev/scripts/error-overlay.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/scripts/error-overlay.js +32 -18
- package/esm/src/server/handlers/monitoring/client-log.handler.d.ts +1 -0
- package/esm/src/server/handlers/monitoring/client-log.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/monitoring/client-log.handler.js +39 -5
- package/esm/src/server/handlers/request/module/batch-module-handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/module/batch-module-handler.js +2 -1
- package/esm/src/utils/logger/redact.d.ts.map +1 -1
- package/esm/src/utils/logger/redact.js +13 -1
- package/esm/src/utils/redis-client.d.ts +1 -0
- package/esm/src/utils/redis-client.d.ts.map +1 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"module-batch-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-batch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAiGtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6K/F;AA0PD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAc1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKrE"}
|
|
@@ -27,6 +27,7 @@ import { getFrameworkRootFromMeta } from "../../platform/compat/vfs-paths.js";
|
|
|
27
27
|
import { LRUCache } from "../../utils/lru-wrapper.js";
|
|
28
28
|
import { registerLRUCache } from "../../cache/index.js";
|
|
29
29
|
import { sha256Short } from "../../cache/hash.js";
|
|
30
|
+
import { buildSourceMissCacheKey, clearSourceMissCache, hasSourceMiss, rememberSourceMiss, } from "./module-source-resolution-cache.js";
|
|
30
31
|
const logger = serverLogger.component("module-batch");
|
|
31
32
|
/** Slow request threshold in milliseconds */
|
|
32
33
|
const SLOW_REQUEST_THRESHOLD_MS = 500;
|
|
@@ -57,6 +58,30 @@ const FRAMEWORK_EXTENSIONS = [
|
|
|
57
58
|
".jsx",
|
|
58
59
|
".js", // Regular sources for dev mode
|
|
59
60
|
];
|
|
61
|
+
async function findFirstSecureFile(secureFs, paths) {
|
|
62
|
+
const results = await Promise.all(paths.map(async (path) => {
|
|
63
|
+
try {
|
|
64
|
+
const stat = await secureFs.stat(path);
|
|
65
|
+
return stat.isFile ? path : null;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
return results.find((path) => path !== null) ?? null;
|
|
72
|
+
}
|
|
73
|
+
async function findFirstPlatformFile(platformFs, paths) {
|
|
74
|
+
const results = await Promise.all(paths.map(async (path) => {
|
|
75
|
+
try {
|
|
76
|
+
const stat = await platformFs.stat(path);
|
|
77
|
+
return stat.isFile ? path : null;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
return results.find((path) => path !== null) ?? null;
|
|
84
|
+
}
|
|
60
85
|
/**
|
|
61
86
|
* Handle a batch module request
|
|
62
87
|
*/
|
|
@@ -87,7 +112,7 @@ export function handleModuleBatch(req, options) {
|
|
|
87
112
|
headers: { "Content-Type": "text/plain" },
|
|
88
113
|
});
|
|
89
114
|
}
|
|
90
|
-
const { projectDir, adapter, projectSlug, projectId, branch, dev = false, allowedImportDirs, reactVersion, } = options;
|
|
115
|
+
const { projectDir, adapter, projectSlug, projectId, branch, releaseId, dev = false, allowedImportDirs, reactVersion, } = options;
|
|
91
116
|
const projectKey = projectId || projectSlug || "default";
|
|
92
117
|
const userAgent = req.headers.get("user-agent") ?? "";
|
|
93
118
|
const isSSR = url.searchParams.get("ssr") === "true" || userAgent.startsWith("Deno/");
|
|
@@ -124,6 +149,7 @@ export function handleModuleBatch(req, options) {
|
|
|
124
149
|
projectSlug,
|
|
125
150
|
branch,
|
|
126
151
|
projectId,
|
|
152
|
+
releaseId,
|
|
127
153
|
reactVersion,
|
|
128
154
|
});
|
|
129
155
|
const transformDurationMs = performance.now() - moduleStart;
|
|
@@ -196,21 +222,27 @@ export function handleModuleBatch(req, options) {
|
|
|
196
222
|
*/
|
|
197
223
|
async function loadAndTransformModule(modulePath, projectDir, adapter, secureFs, options) {
|
|
198
224
|
const basePath = modulePath.replace(/\.js$/, "");
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
const missCacheKey = buildSourceMissCacheKey({
|
|
226
|
+
resolver: "module-batch",
|
|
227
|
+
projectDir,
|
|
228
|
+
projectId: options.projectId,
|
|
229
|
+
projectSlug: options.projectSlug,
|
|
230
|
+
branch: options.branch,
|
|
231
|
+
releaseId: options.releaseId,
|
|
232
|
+
basePath,
|
|
233
|
+
reactVersion: options.reactVersion,
|
|
234
|
+
});
|
|
235
|
+
if (hasSourceMiss(missCacheKey))
|
|
236
|
+
return null;
|
|
237
|
+
const sourcePath = await findFirstSecureFile(secureFs, EXTENSIONS.map((ext) => join(projectDir, basePath + ext)));
|
|
238
|
+
if (sourcePath) {
|
|
239
|
+
const source = await secureFs.readFile(sourcePath);
|
|
240
|
+
return transformModule(source, sourcePath, modulePath, projectDir, adapter, secureFs, options);
|
|
211
241
|
}
|
|
212
|
-
if (!basePath.startsWith("lib/"))
|
|
242
|
+
if (!basePath.startsWith("lib/")) {
|
|
243
|
+
rememberSourceMiss(missCacheKey);
|
|
213
244
|
return null;
|
|
245
|
+
}
|
|
214
246
|
// Framework lookup directories in priority order
|
|
215
247
|
const frameworkLookupDirs = [
|
|
216
248
|
EMBEDDED_SRC_DIR, // Embedded sources for compiled binaries (.src files)
|
|
@@ -218,20 +250,13 @@ async function loadAndTransformModule(modulePath, projectDir, adapter, secureFs,
|
|
|
218
250
|
];
|
|
219
251
|
const platformFs = createFileSystem();
|
|
220
252
|
for (const lookupDir of frameworkLookupDirs) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (!stat.isFile)
|
|
226
|
-
continue;
|
|
227
|
-
const source = await platformFs.readTextFile(frameworkPath);
|
|
228
|
-
return transformModule(source, frameworkPath, modulePath, projectDir, adapter, secureFs, options);
|
|
229
|
-
}
|
|
230
|
-
catch (_) {
|
|
231
|
-
/* expected: framework file may not exist at this extension */
|
|
232
|
-
}
|
|
253
|
+
const frameworkPath = await findFirstPlatformFile(platformFs, FRAMEWORK_EXTENSIONS.map((ext) => join(lookupDir, basePath + ext)));
|
|
254
|
+
if (frameworkPath) {
|
|
255
|
+
const source = await platformFs.readTextFile(frameworkPath);
|
|
256
|
+
return transformModule(source, frameworkPath, modulePath, projectDir, adapter, secureFs, options);
|
|
233
257
|
}
|
|
234
258
|
}
|
|
259
|
+
rememberSourceMiss(missCacheKey);
|
|
235
260
|
return null;
|
|
236
261
|
}
|
|
237
262
|
async function transformModule(source, sourceFile, modulePath, projectDir, adapter, secureFs, options) {
|
|
@@ -369,6 +394,7 @@ function transformExportsForBundle(code) {
|
|
|
369
394
|
* Clear the transform cache (on deployment or memory pressure)
|
|
370
395
|
*/
|
|
371
396
|
export function clearBatchCache(projectSlug) {
|
|
397
|
+
clearSourceMissCache("module-batch");
|
|
372
398
|
if (!projectSlug) {
|
|
373
399
|
transformCache.clear();
|
|
374
400
|
logger.debug("Cleared all cache");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAkCtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AAiBF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkWzF;AAiVD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGrD"}
|
|
@@ -17,6 +17,7 @@ import { FRAMEWORK_ROOT, resolveFrameworkSourcePath, } from "../../platform/comp
|
|
|
17
17
|
import { getReactUrls, REACT_DEFAULT_VERSION } from "../../utils/constants/cdn.js";
|
|
18
18
|
import { readLimitedCrossProjectSource } from "./cross-project-source-limit.js";
|
|
19
19
|
import { sha256Short } from "../../cache/hash.js";
|
|
20
|
+
import { buildSourceMissCacheKey, hasSourceMiss, rememberSourceMiss, } from "./module-source-resolution-cache.js";
|
|
20
21
|
const logger = serverLogger.component("module-server");
|
|
21
22
|
/**
|
|
22
23
|
* Embedded polyfills for compiled Deno binaries.
|
|
@@ -161,6 +162,10 @@ export function serveModule(req, options) {
|
|
|
161
162
|
secureFs,
|
|
162
163
|
projectDir,
|
|
163
164
|
currentModulePath: `_snippets/${hash}.js`,
|
|
165
|
+
projectId: effectiveProjectId,
|
|
166
|
+
projectSlug: snippetProjectSlug,
|
|
167
|
+
branch: snippetBranch,
|
|
168
|
+
releaseId: options.releaseId,
|
|
164
169
|
reactVersion,
|
|
165
170
|
}),
|
|
166
171
|
});
|
|
@@ -229,6 +234,8 @@ export function serveModule(req, options) {
|
|
|
229
234
|
projectDir,
|
|
230
235
|
currentModulePath: crossPath,
|
|
231
236
|
crossProjectRef: projectRef,
|
|
237
|
+
projectId: effectiveProjectId,
|
|
238
|
+
releaseId: options.releaseId,
|
|
232
239
|
reactVersion,
|
|
233
240
|
}),
|
|
234
241
|
});
|
|
@@ -262,7 +269,13 @@ export function serveModule(req, options) {
|
|
|
262
269
|
branch ??= parsedHost.branch;
|
|
263
270
|
}
|
|
264
271
|
try {
|
|
265
|
-
const findResult = await findSourceFile(secureFs, projectDir, filePathWithoutExt,
|
|
272
|
+
const findResult = await findSourceFile(secureFs, projectDir, filePathWithoutExt, {
|
|
273
|
+
projectId: effectiveProjectId,
|
|
274
|
+
projectSlug,
|
|
275
|
+
branch,
|
|
276
|
+
releaseId: options.releaseId,
|
|
277
|
+
reactVersion,
|
|
278
|
+
});
|
|
266
279
|
if (!findResult) {
|
|
267
280
|
logger.warn("Module not found", {
|
|
268
281
|
modulePath,
|
|
@@ -326,6 +339,10 @@ export function serveModule(req, options) {
|
|
|
326
339
|
secureFs,
|
|
327
340
|
projectDir,
|
|
328
341
|
currentModulePath: modulePath,
|
|
342
|
+
projectId: effectiveProjectId,
|
|
343
|
+
projectSlug,
|
|
344
|
+
branch,
|
|
345
|
+
releaseId: options.releaseId,
|
|
329
346
|
reactVersion,
|
|
330
347
|
}),
|
|
331
348
|
});
|
|
@@ -375,7 +392,13 @@ function createSSRTargetCacheBusterResolver(options) {
|
|
|
375
392
|
const source = await fetchCrossProjectSource(options.crossProjectRef, targetPath);
|
|
376
393
|
return source === null ? undefined : await sha256Short(`${targetPath}\0${source}`);
|
|
377
394
|
}
|
|
378
|
-
const findResult = await findSourceFile(options.secureFs, options.projectDir, stripSSRModuleJsExtension(targetPath),
|
|
395
|
+
const findResult = await findSourceFile(options.secureFs, options.projectDir, stripSSRModuleJsExtension(targetPath), {
|
|
396
|
+
projectId: options.projectId,
|
|
397
|
+
projectSlug: options.projectSlug,
|
|
398
|
+
branch: options.branch,
|
|
399
|
+
releaseId: options.releaseId,
|
|
400
|
+
reactVersion: options.reactVersion,
|
|
401
|
+
});
|
|
379
402
|
if (!findResult)
|
|
380
403
|
return undefined;
|
|
381
404
|
const source = await readSourceFileForVersion(options.secureFs, findResult);
|
|
@@ -415,20 +438,34 @@ function createBrowserReactPackageShim(basePathWithoutExt, reactVersion = REACT_
|
|
|
415
438
|
async function findFrameworkPackageAssetFile(fs, basePathWithoutExt, extensions) {
|
|
416
439
|
if (hasUnsafePackageAssetPath(basePathWithoutExt))
|
|
417
440
|
return null;
|
|
418
|
-
|
|
419
|
-
|
|
441
|
+
return await findFirstPlatformFile(fs, extensions.map((ext) => join(FRAMEWORK_ROOT, basePathWithoutExt + ext)));
|
|
442
|
+
}
|
|
443
|
+
async function findFirstPlatformFile(fs, paths) {
|
|
444
|
+
const results = await Promise.all(paths.map(async (path) => {
|
|
420
445
|
try {
|
|
421
|
-
const stat = await fs.stat(
|
|
422
|
-
|
|
423
|
-
return candidatePath;
|
|
446
|
+
const stat = await fs.stat(path);
|
|
447
|
+
return stat.isFile ? path : null;
|
|
424
448
|
}
|
|
425
449
|
catch {
|
|
426
|
-
|
|
450
|
+
return null;
|
|
427
451
|
}
|
|
428
|
-
}
|
|
429
|
-
return null;
|
|
452
|
+
}));
|
|
453
|
+
return results.find((path) => path !== null) ?? null;
|
|
430
454
|
}
|
|
431
|
-
async function
|
|
455
|
+
async function findFirstSecureFile(secureFs, paths) {
|
|
456
|
+
const results = await Promise.all(paths.map(async (path) => {
|
|
457
|
+
try {
|
|
458
|
+
const stat = await secureFs.stat(path);
|
|
459
|
+
return stat.isFile ? path : null;
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
}));
|
|
465
|
+
return results.find((path) => path !== null) ?? null;
|
|
466
|
+
}
|
|
467
|
+
async function findSourceFile(secureFs, projectDir, basePath, context) {
|
|
468
|
+
const { reactVersion } = context;
|
|
432
469
|
// Extensions including .src for compiled binary embedded sources
|
|
433
470
|
const extensions = [
|
|
434
471
|
".json",
|
|
@@ -457,6 +494,16 @@ async function findSourceFile(secureFs, projectDir, basePath, reactVersion) {
|
|
|
457
494
|
const isFrameworkPath = basePathWithoutExt.startsWith("_veryfront/");
|
|
458
495
|
const isFrameworkPackageAssetPath = basePathWithoutExt.startsWith("react/") ||
|
|
459
496
|
basePathWithoutExt.startsWith("deps/");
|
|
497
|
+
const missCacheKey = buildSourceMissCacheKey({
|
|
498
|
+
resolver: "module-server",
|
|
499
|
+
projectDir,
|
|
500
|
+
projectId: context.projectId,
|
|
501
|
+
projectSlug: context.projectSlug,
|
|
502
|
+
branch: context.branch,
|
|
503
|
+
releaseId: context.releaseId,
|
|
504
|
+
basePath: basePathWithoutExt,
|
|
505
|
+
reactVersion,
|
|
506
|
+
});
|
|
460
507
|
// Check embedded polyfills first (no filesystem access needed).
|
|
461
508
|
// These cover both compiled-binary polyfills (node:async_hooks etc.)
|
|
462
509
|
// and dnt build artifacts (_dnt.shims, _dnt.polyfills) that don't
|
|
@@ -475,6 +522,8 @@ async function findSourceFile(secureFs, projectDir, basePath, reactVersion) {
|
|
|
475
522
|
embeddedContent,
|
|
476
523
|
};
|
|
477
524
|
}
|
|
525
|
+
if (hasSourceMiss(missCacheKey))
|
|
526
|
+
return null;
|
|
478
527
|
if (isFrameworkPackageAssetPath) {
|
|
479
528
|
const browserReactShim = createBrowserReactPackageShim(basePathWithoutExt, reactVersion);
|
|
480
529
|
if (browserReactShim) {
|
|
@@ -525,78 +574,47 @@ async function findSourceFile(secureFs, projectDir, basePath, reactVersion) {
|
|
|
525
574
|
}
|
|
526
575
|
}
|
|
527
576
|
// Project file lookups (using secureFs which may go through FSAdapter in proxy mode)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (stat.isFile) {
|
|
533
|
-
logger.debug("Found file", { basePath, resolvedPath: fullPath });
|
|
534
|
-
return { path: fullPath, isFrameworkFile: false };
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
catch (_) {
|
|
538
|
-
/* expected: file may not exist at this extension */
|
|
539
|
-
}
|
|
577
|
+
const projectFilePath = await findFirstSecureFile(secureFs, extensions.map((ext) => join(projectDir, basePathWithoutExt + ext)));
|
|
578
|
+
if (projectFilePath) {
|
|
579
|
+
logger.debug("Found file", { basePath, resolvedPath: projectFilePath });
|
|
580
|
+
return { path: projectFilePath, isFrameworkFile: false };
|
|
540
581
|
}
|
|
541
582
|
const prefixesToStrip = ["components/", "pages/", "lib/", "app/", "src/"];
|
|
542
583
|
for (const prefix of prefixesToStrip) {
|
|
543
584
|
if (!basePathWithoutExt.startsWith(prefix))
|
|
544
585
|
continue;
|
|
545
586
|
const strippedPath = basePathWithoutExt.slice(prefix.length);
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
resolvedPath: fullPath,
|
|
555
|
-
});
|
|
556
|
-
return { path: fullPath, isFrameworkFile: false };
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
catch (_) {
|
|
560
|
-
/* expected: file may not exist after stripping prefix */
|
|
561
|
-
}
|
|
587
|
+
const strippedFilePath = await findFirstSecureFile(secureFs, extensions.map((ext) => join(projectDir, strippedPath + ext)));
|
|
588
|
+
if (strippedFilePath) {
|
|
589
|
+
logger.debug("Found file after stripping prefix", {
|
|
590
|
+
originalPath: basePathWithoutExt,
|
|
591
|
+
strippedPath,
|
|
592
|
+
resolvedPath: strippedFilePath,
|
|
593
|
+
});
|
|
594
|
+
return { path: strippedFilePath, isFrameworkFile: false };
|
|
562
595
|
}
|
|
563
596
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
resolvedPath: fullPath,
|
|
572
|
-
});
|
|
573
|
-
return { path: fullPath, isFrameworkFile: false };
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
catch (_) {
|
|
577
|
-
/* expected: index file may not exist at this extension */
|
|
578
|
-
}
|
|
597
|
+
const indexFilePath = await findFirstSecureFile(secureFs, extensions.map((ext) => join(projectDir, basePathWithoutExt, `index${ext}`)));
|
|
598
|
+
if (indexFilePath) {
|
|
599
|
+
logger.debug("Found index file", {
|
|
600
|
+
basePath: basePathWithoutExt,
|
|
601
|
+
resolvedPath: indexFilePath,
|
|
602
|
+
});
|
|
603
|
+
return { path: indexFilePath, isFrameworkFile: false };
|
|
579
604
|
}
|
|
580
605
|
// Try looking in common project directories
|
|
581
606
|
const commonDirs = ["components", "app", "pages", "lib", "src"];
|
|
582
607
|
for (const dir of commonDirs) {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
resolvedPath: fullPath,
|
|
591
|
-
});
|
|
592
|
-
return { path: fullPath, isFrameworkFile: false };
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
catch (_) {
|
|
596
|
-
/* expected: file may not exist in common directory */
|
|
597
|
-
}
|
|
608
|
+
const commonDirFilePath = await findFirstSecureFile(secureFs, extensions.map((ext) => join(projectDir, dir, basePathWithoutExt + ext)));
|
|
609
|
+
if (commonDirFilePath) {
|
|
610
|
+
logger.debug("Found file in common directory", {
|
|
611
|
+
basePath,
|
|
612
|
+
resolvedPath: commonDirFilePath,
|
|
613
|
+
});
|
|
614
|
+
return { path: commonDirFilePath, isFrameworkFile: false };
|
|
598
615
|
}
|
|
599
616
|
}
|
|
617
|
+
rememberSourceMiss(missCacheKey);
|
|
600
618
|
return null;
|
|
601
619
|
}
|
|
602
620
|
/**
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ModuleSourceResolver = "module-server" | "module-batch";
|
|
2
|
+
export declare function buildSourceMissCacheKey(options: {
|
|
3
|
+
resolver: ModuleSourceResolver;
|
|
4
|
+
projectDir: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
projectSlug?: string | null;
|
|
7
|
+
branch?: string | null;
|
|
8
|
+
releaseId?: string | null;
|
|
9
|
+
basePath: string;
|
|
10
|
+
reactVersion?: string;
|
|
11
|
+
}): string;
|
|
12
|
+
export declare function hasSourceMiss(cacheKey: string): boolean;
|
|
13
|
+
export declare function rememberSourceMiss(cacheKey: string): void;
|
|
14
|
+
export declare function clearSourceMissCache(resolver?: ModuleSourceResolver): void;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=module-source-resolution-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-source-resolution-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-source-resolution-cache.ts"],"names":[],"mappings":"AAGA,KAAK,oBAAoB,GAAG,eAAe,GAAG,cAAc,CAAC;AAgB7D,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAWT;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAO1E"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { registerLRUCache } from "../../cache/index.js";
|
|
2
|
+
import { LRUCache } from "../../utils/lru-wrapper.js";
|
|
3
|
+
const SOURCE_MISS_CACHE_MAX_ENTRIES = 5_000;
|
|
4
|
+
const sourceMissCaches = {
|
|
5
|
+
"module-server": new LRUCache({
|
|
6
|
+
maxEntries: SOURCE_MISS_CACHE_MAX_ENTRIES,
|
|
7
|
+
}),
|
|
8
|
+
"module-batch": new LRUCache({
|
|
9
|
+
maxEntries: SOURCE_MISS_CACHE_MAX_ENTRIES,
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
registerLRUCache("module-server-source-miss-cache", sourceMissCaches["module-server"]);
|
|
13
|
+
registerLRUCache("module-batch-source-miss-cache", sourceMissCaches["module-batch"]);
|
|
14
|
+
export function buildSourceMissCacheKey(options) {
|
|
15
|
+
return [
|
|
16
|
+
options.resolver,
|
|
17
|
+
options.projectDir,
|
|
18
|
+
options.projectId ?? "",
|
|
19
|
+
options.projectSlug ?? "",
|
|
20
|
+
options.branch ?? "",
|
|
21
|
+
options.releaseId ?? "",
|
|
22
|
+
options.reactVersion ?? "",
|
|
23
|
+
options.basePath,
|
|
24
|
+
].join("\0");
|
|
25
|
+
}
|
|
26
|
+
export function hasSourceMiss(cacheKey) {
|
|
27
|
+
return sourceMissCaches[getResolverFromCacheKey(cacheKey)].has(cacheKey);
|
|
28
|
+
}
|
|
29
|
+
export function rememberSourceMiss(cacheKey) {
|
|
30
|
+
sourceMissCaches[getResolverFromCacheKey(cacheKey)].set(cacheKey, true);
|
|
31
|
+
}
|
|
32
|
+
export function clearSourceMissCache(resolver) {
|
|
33
|
+
if (resolver) {
|
|
34
|
+
sourceMissCaches[resolver].clear();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const cache of Object.values(sourceMissCaches))
|
|
38
|
+
cache.clear();
|
|
39
|
+
}
|
|
40
|
+
function getResolverFromCacheKey(cacheKey) {
|
|
41
|
+
const resolver = cacheKey.split("\0", 1)[0];
|
|
42
|
+
return resolver === "module-batch" ? "module-batch" : "module-server";
|
|
43
|
+
}
|
|
@@ -36,11 +36,9 @@ export declare class OAuthProvider {
|
|
|
36
36
|
export declare class OAuthService extends OAuthProvider {
|
|
37
37
|
protected serviceConfig: OAuthServiceConfig;
|
|
38
38
|
protected tokenStore?: TokenStore;
|
|
39
|
-
private refreshPromises;
|
|
40
39
|
constructor(config: OAuthServiceConfig, tokenStore?: TokenStore, envReader?: EnvReader);
|
|
41
40
|
get serviceId(): string;
|
|
42
41
|
get apiBaseUrl(): string;
|
|
43
|
-
private refreshKey;
|
|
44
42
|
createAuthorizationUrl(options?: AuthorizationUrlOptions): Promise<{
|
|
45
43
|
url: string;
|
|
46
44
|
state: OAuthState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/providers/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAarB,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAuB5D,gCAAgC;AAChC,qBAAa,aAAa;IACxB,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACtC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;gBAEnB,MAAM,EAAE,mBAAmB,EAAE,SAAS,GAAE,SAAkB;IAKtE,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,OAAO;IAIjB,sBAAsB,CAC1B,OAAO,GAAE,uBAAuB,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACnE,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IA0C9C,OAAO,CAAC,iBAAiB;IAazB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;YA0CZ,gBAAgB;IAe9B,OAAO,CAAC,4BAA4B;YAQtB,aAAa;IAyCrB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgCzE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBjE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBnD;
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/providers/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAarB,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAuB5D,gCAAgC;AAChC,qBAAa,aAAa;IACxB,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACtC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC;gBAEnB,MAAM,EAAE,mBAAmB,EAAE,SAAS,GAAE,SAAkB;IAKtE,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,YAAY,IAAI,OAAO;IAIjB,sBAAsB,CAC1B,OAAO,GAAE,uBAAuB,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACnE,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IA0C9C,OAAO,CAAC,iBAAiB;IAazB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;YA0CZ,gBAAgB;IAe9B,OAAO,CAAC,4BAA4B;YAQtB,aAAa;IAyCrB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgCzE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBjE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBnD;AA2CD,+BAA+B;AAC/B,qBAAa,YAAa,SAAQ,aAAa;IAC7C,SAAS,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC5C,SAAS,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;gBAEtB,MAAM,EAAE,kBAAkB,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,SAAS;IAMtF,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEQ,sBAAsB,CAC7B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAO9C;;;;;;OAMG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YA4B9C,0BAA0B;IAcxC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAuBpB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;CA+BxF"}
|
|
@@ -229,11 +229,37 @@ export class OAuthProvider {
|
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Module-level singleflight for token refreshes, scoped by TokenStore instance
|
|
234
|
+
* and then `(serviceId, userId)`. This dedupes separate OAuthService instances
|
|
235
|
+
* that share the same scoped store without making different project stores
|
|
236
|
+
* share refresh promises.
|
|
237
|
+
*/
|
|
238
|
+
const refreshInFlightByStore = new WeakMap();
|
|
239
|
+
function getRefreshInFlight(tokenStore, key) {
|
|
240
|
+
return refreshInFlightByStore.get(tokenStore)?.get(key);
|
|
241
|
+
}
|
|
242
|
+
function setRefreshInFlight(tokenStore, key, promise) {
|
|
243
|
+
let storeInflight = refreshInFlightByStore.get(tokenStore);
|
|
244
|
+
if (!storeInflight) {
|
|
245
|
+
storeInflight = new Map();
|
|
246
|
+
refreshInFlightByStore.set(tokenStore, storeInflight);
|
|
247
|
+
}
|
|
248
|
+
storeInflight.set(key, promise);
|
|
249
|
+
}
|
|
250
|
+
function clearRefreshInFlight(tokenStore, key, promise) {
|
|
251
|
+
const storeInflight = refreshInFlightByStore.get(tokenStore);
|
|
252
|
+
if (!storeInflight || storeInflight.get(key) !== promise)
|
|
253
|
+
return;
|
|
254
|
+
storeInflight.delete(key);
|
|
255
|
+
if (storeInflight.size === 0) {
|
|
256
|
+
refreshInFlightByStore.delete(tokenStore);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
232
259
|
/** Implement oauth service. */
|
|
233
260
|
export class OAuthService extends OAuthProvider {
|
|
234
261
|
serviceConfig;
|
|
235
262
|
tokenStore;
|
|
236
|
-
refreshPromises = new Map();
|
|
237
263
|
constructor(config, tokenStore, envReader) {
|
|
238
264
|
super(config, envReader);
|
|
239
265
|
this.serviceConfig = config;
|
|
@@ -245,9 +271,6 @@ export class OAuthService extends OAuthProvider {
|
|
|
245
271
|
get apiBaseUrl() {
|
|
246
272
|
return this.serviceConfig.apiBaseUrl;
|
|
247
273
|
}
|
|
248
|
-
refreshKey(userId) {
|
|
249
|
-
return JSON.stringify([this.serviceId, userId]);
|
|
250
|
-
}
|
|
251
274
|
createAuthorizationUrl(options = {}) {
|
|
252
275
|
return super.createAuthorizationUrl({
|
|
253
276
|
...options,
|
|
@@ -270,19 +293,21 @@ export class OAuthService extends OAuthProvider {
|
|
|
270
293
|
return tokens.accessToken;
|
|
271
294
|
if (!tokens.refreshToken)
|
|
272
295
|
return null;
|
|
273
|
-
|
|
274
|
-
|
|
296
|
+
if (!this.tokenStore) {
|
|
297
|
+
throw new Error("TokenStore not configured");
|
|
298
|
+
}
|
|
299
|
+
const key = JSON.stringify([this.serviceId, userId]);
|
|
300
|
+
const existingRefresh = getRefreshInFlight(this.tokenStore, key);
|
|
275
301
|
if (existingRefresh)
|
|
276
302
|
return existingRefresh;
|
|
303
|
+
const tokenStore = this.tokenStore;
|
|
277
304
|
const refreshPromise = this.refreshAndStoreAccessToken(userId, tokens.refreshToken);
|
|
278
|
-
|
|
305
|
+
setRefreshInFlight(tokenStore, key, refreshPromise);
|
|
279
306
|
try {
|
|
280
307
|
return await refreshPromise;
|
|
281
308
|
}
|
|
282
309
|
finally {
|
|
283
|
-
|
|
284
|
-
this.refreshPromises.delete(key);
|
|
285
|
-
}
|
|
310
|
+
clearRefreshInFlight(tokenStore, key, refreshPromise);
|
|
286
311
|
}
|
|
287
312
|
}
|
|
288
313
|
async refreshAndStoreAccessToken(userId, refreshToken) {
|
|
@@ -7,6 +7,11 @@ export interface MemoryTokenStoreOptions {
|
|
|
7
7
|
* {@link DEFAULT_MAX_TOKEN_ENTRIES}.
|
|
8
8
|
*/
|
|
9
9
|
maxEntries?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Maximum number of in-flight OAuth state entries to retain before oldest
|
|
12
|
+
* entries are evicted. Defaults to {@link DEFAULT_MAX_STATE_ENTRIES}.
|
|
13
|
+
*/
|
|
14
|
+
maxStateEntries?: number;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
17
|
* In-memory TokenStore keyed by `(serviceId, userId)`.
|
|
@@ -24,6 +29,7 @@ export interface MemoryTokenStoreOptions {
|
|
|
24
29
|
export declare class MemoryTokenStore implements TokenStore {
|
|
25
30
|
private tokens;
|
|
26
31
|
private states;
|
|
32
|
+
private maxStateEntries;
|
|
27
33
|
private projectId;
|
|
28
34
|
private warnedProductionUse;
|
|
29
35
|
constructor(projectId?: string, options?: MemoryTokenStoreOptions);
|
|
@@ -44,6 +50,7 @@ export declare class MemoryTokenStore implements TokenStore {
|
|
|
44
50
|
*/
|
|
45
51
|
consumeState(state: string): Promise<StoredOAuthState | null>;
|
|
46
52
|
private cleanupExpiredStates;
|
|
53
|
+
private evictOldestStates;
|
|
47
54
|
/** List connected slots as `${serviceId}:${userId}` strings (test/debug aid). */
|
|
48
55
|
getConnectedServices(): string[];
|
|
49
56
|
/** Whether a given user has usable tokens for a service. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAmB7E,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,mBAAmB,CAAS;gBAExB,SAAS,SAAY,EAAE,OAAO,GAAE,uBAA4B;IAQxE,OAAO,CAAC,SAAS;IAIjB;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAW3B,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAMzE,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhF,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAU7D,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,iBAAiB;IAQzB,iFAAiF;IACjF,oBAAoB,IAAI,MAAM,EAAE;IAOhC,4DAA4D;IAC5D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAQvD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,EAAE,UAAmC,CAAC"}
|
|
@@ -12,6 +12,8 @@ const STATE_EXPIRY_MS = 10 * 60 * 1_000;
|
|
|
12
12
|
* eviction is by capacity/recency only.
|
|
13
13
|
*/
|
|
14
14
|
const DEFAULT_MAX_TOKEN_ENTRIES = 10_000;
|
|
15
|
+
/** Default cap on in-flight OAuth state values. */
|
|
16
|
+
const DEFAULT_MAX_STATE_ENTRIES = 10_000;
|
|
15
17
|
/**
|
|
16
18
|
* In-memory TokenStore keyed by `(serviceId, userId)`.
|
|
17
19
|
*
|
|
@@ -28,10 +30,12 @@ const DEFAULT_MAX_TOKEN_ENTRIES = 10_000;
|
|
|
28
30
|
export class MemoryTokenStore {
|
|
29
31
|
tokens;
|
|
30
32
|
states = new Map();
|
|
33
|
+
maxStateEntries;
|
|
31
34
|
projectId;
|
|
32
35
|
warnedProductionUse = false;
|
|
33
36
|
constructor(projectId = "default", options = {}) {
|
|
34
37
|
this.projectId = projectId;
|
|
38
|
+
this.maxStateEntries = Math.max(1, options.maxStateEntries ?? DEFAULT_MAX_STATE_ENTRIES);
|
|
35
39
|
this.tokens = new LRUCacheAdapter({
|
|
36
40
|
maxEntries: options.maxEntries ?? DEFAULT_MAX_TOKEN_ENTRIES,
|
|
37
41
|
});
|
|
@@ -66,8 +70,9 @@ export class MemoryTokenStore {
|
|
|
66
70
|
return Promise.resolve();
|
|
67
71
|
}
|
|
68
72
|
setState(state, meta) {
|
|
69
|
-
this.states.set(state, meta);
|
|
70
73
|
this.cleanupExpiredStates();
|
|
74
|
+
this.states.set(state, meta);
|
|
75
|
+
this.evictOldestStates();
|
|
71
76
|
return Promise.resolve();
|
|
72
77
|
}
|
|
73
78
|
/**
|
|
@@ -92,6 +97,14 @@ export class MemoryTokenStore {
|
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
99
|
}
|
|
100
|
+
evictOldestStates() {
|
|
101
|
+
while (this.states.size > this.maxStateEntries) {
|
|
102
|
+
const oldestState = this.states.keys().next().value;
|
|
103
|
+
if (oldestState === undefined)
|
|
104
|
+
return;
|
|
105
|
+
this.states.delete(oldestState);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
95
108
|
/** List connected slots as `${serviceId}:${userId}` strings (test/debug aid). */
|
|
96
109
|
getConnectedServices() {
|
|
97
110
|
const prefix = `${this.projectId}:`;
|