veryfront 0.1.746 → 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/api.d.ts.map +1 -1
- package/esm/src/cache/backends/api.js +9 -5
- 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/middleware/builtin/security/redis-rate-limit.d.ts +2 -0
- package/esm/src/middleware/builtin/security/redis-rate-limit.d.ts.map +1 -1
- package/esm/src/middleware/builtin/security/redis-rate-limit.js +46 -13
- 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/auto-instrument/http-instrumentation.d.ts.map +1 -1
- package/esm/src/observability/auto-instrument/http-instrumentation.js +10 -6
- 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 +10 -0
- package/esm/src/utils/logger/redact.d.ts.map +1 -1
- package/esm/src/utils/logger/redact.js +60 -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,5 +1,5 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import { isNotFoundError, mkdir, readDir, readTextFile, writeTextFile, } from "../platform/compat/fs.js";
|
|
2
|
+
import { isNotFoundError, mkdir, readDir, readTextFile, stat, writeTextFile, } from "../platform/compat/fs.js";
|
|
3
3
|
import { dirname, extname, join } from "../platform/compat/path/basic-operations.js";
|
|
4
4
|
import { serverLogger } from "../utils/index.js";
|
|
5
5
|
import { isVeryfrontCloudEnabled } from "../platform/cloud/resolver.js";
|
|
@@ -12,6 +12,77 @@ import { cosineSimilarity } from "../runtime/runtime-bridge.js";
|
|
|
12
12
|
import { INVALID_ARGUMENT } from "../errors/index.js";
|
|
13
13
|
/** Default number of top results returned by similarity search. */
|
|
14
14
|
const DEFAULT_TOP_K = 5;
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function isFiniteNumber(value) {
|
|
19
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
20
|
+
}
|
|
21
|
+
function isNumberArray(value) {
|
|
22
|
+
return Array.isArray(value) && value.every(isFiniteNumber);
|
|
23
|
+
}
|
|
24
|
+
function isNonNegativeInteger(value) {
|
|
25
|
+
return Number.isInteger(value) && Number(value) >= 0;
|
|
26
|
+
}
|
|
27
|
+
function isRagDocumentMeta(value) {
|
|
28
|
+
if (!isRecord(value))
|
|
29
|
+
return false;
|
|
30
|
+
return typeof value.id === "string" &&
|
|
31
|
+
typeof value.title === "string" &&
|
|
32
|
+
typeof value.source === "string" &&
|
|
33
|
+
typeof value.type === "string" &&
|
|
34
|
+
isFiniteNumber(value.createdAt) &&
|
|
35
|
+
(value.url === undefined || typeof value.url === "string");
|
|
36
|
+
}
|
|
37
|
+
function isRagChunk(value) {
|
|
38
|
+
if (!isRecord(value))
|
|
39
|
+
return false;
|
|
40
|
+
return typeof value.id === "string" &&
|
|
41
|
+
typeof value.documentId === "string" &&
|
|
42
|
+
typeof value.text === "string" &&
|
|
43
|
+
isNumberArray(value.embedding) &&
|
|
44
|
+
isNonNegativeInteger(value.index);
|
|
45
|
+
}
|
|
46
|
+
function isRagStoreData(value) {
|
|
47
|
+
if (!isRecord(value))
|
|
48
|
+
return false;
|
|
49
|
+
return Array.isArray(value.documents) &&
|
|
50
|
+
value.documents.every(isRagDocumentMeta) &&
|
|
51
|
+
Array.isArray(value.chunks) &&
|
|
52
|
+
value.chunks.every(isRagChunk);
|
|
53
|
+
}
|
|
54
|
+
function cloneRagStoreData(data) {
|
|
55
|
+
return {
|
|
56
|
+
documents: data.documents.map((document) => ({ ...document })),
|
|
57
|
+
chunks: data.chunks.map((chunk) => ({
|
|
58
|
+
...chunk,
|
|
59
|
+
embedding: [...chunk.embedding],
|
|
60
|
+
})),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function hashStoreText(text) {
|
|
64
|
+
let hash = 0x811c9dc5;
|
|
65
|
+
for (let i = 0; i < text.length; i++) {
|
|
66
|
+
hash ^= text.charCodeAt(i);
|
|
67
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
68
|
+
}
|
|
69
|
+
return hash.toString(16).padStart(8, "0");
|
|
70
|
+
}
|
|
71
|
+
function sameStoreFileSignature(left, right) {
|
|
72
|
+
return left.contentHash === right.contentHash &&
|
|
73
|
+
left.changeTimeMs === right.changeTimeMs &&
|
|
74
|
+
left.mtimeMs === right.mtimeMs &&
|
|
75
|
+
left.size === right.size;
|
|
76
|
+
}
|
|
77
|
+
function isLegacyStoredChunk(value) {
|
|
78
|
+
if (!isRecord(value))
|
|
79
|
+
return false;
|
|
80
|
+
return typeof value.id === "string" &&
|
|
81
|
+
typeof value.uploadId === "string" &&
|
|
82
|
+
typeof value.text === "string" &&
|
|
83
|
+
isNumberArray(value.embedding) &&
|
|
84
|
+
isNonNegativeInteger(value.index);
|
|
85
|
+
}
|
|
15
86
|
/**
|
|
16
87
|
* Creates a persistent RAG store with lazy embedding and similarity search.
|
|
17
88
|
*
|
|
@@ -109,6 +180,7 @@ function createLocalJsonRagStore(config) {
|
|
|
109
180
|
const contentDir = config.contentDir;
|
|
110
181
|
const contentExtensions = new Set(config.contentExtensions ?? [".md", ".mdx", ".txt"]);
|
|
111
182
|
const chunkOptions = config.chunkOptions;
|
|
183
|
+
let storeDataCache = null;
|
|
112
184
|
const MAX_TEXT_LENGTH = 5 * 1024 * 1024; // 5 MB text limit per document
|
|
113
185
|
// Serialize all load→modify→save operations to prevent concurrent overwrites.
|
|
114
186
|
// NOTE: This is a single-process, single-instance mutex. In multi-instance
|
|
@@ -133,7 +205,10 @@ function createLocalJsonRagStore(config) {
|
|
|
133
205
|
if (!value || typeof value !== "object")
|
|
134
206
|
return false;
|
|
135
207
|
const data = value;
|
|
136
|
-
return Array.isArray(data.uploads) &&
|
|
208
|
+
return Array.isArray(data.uploads) &&
|
|
209
|
+
data.uploads.every(isRagDocumentMeta) &&
|
|
210
|
+
Array.isArray(data.chunks) &&
|
|
211
|
+
data.chunks.every(isLegacyStoredChunk);
|
|
137
212
|
}
|
|
138
213
|
function migrateLegacyUploadStoreData(data) {
|
|
139
214
|
return {
|
|
@@ -147,25 +222,98 @@ function createLocalJsonRagStore(config) {
|
|
|
147
222
|
})),
|
|
148
223
|
};
|
|
149
224
|
}
|
|
225
|
+
async function getStoreFileMetadata() {
|
|
226
|
+
try {
|
|
227
|
+
if (typeof dntShim.Deno !== "undefined") {
|
|
228
|
+
const info = await dntShim.Deno.stat(storagePath);
|
|
229
|
+
const changeTime = info.ctime;
|
|
230
|
+
return {
|
|
231
|
+
changeTimeMs: changeTime?.getTime() ?? null,
|
|
232
|
+
mtimeMs: info.mtime?.getTime() ?? null,
|
|
233
|
+
size: info.size,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const info = await stat(storagePath);
|
|
237
|
+
let changeTimeMs = null;
|
|
238
|
+
try {
|
|
239
|
+
const nodeFs = await import("node:fs/promises");
|
|
240
|
+
const nodeInfo = await nodeFs.stat(storagePath);
|
|
241
|
+
changeTimeMs = nodeInfo.ctime.getTime();
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// expected: not every runtime exposes a file change time
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
changeTimeMs,
|
|
248
|
+
mtimeMs: info.mtime?.getTime() ?? null,
|
|
249
|
+
size: info.size,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
if (isNotFoundError(err))
|
|
254
|
+
return null;
|
|
255
|
+
throw err;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function readStoreFileSnapshot() {
|
|
259
|
+
const metadata = await getStoreFileMetadata();
|
|
260
|
+
if (metadata === null)
|
|
261
|
+
return null;
|
|
262
|
+
const text = await readTextFile(storagePath);
|
|
263
|
+
return {
|
|
264
|
+
signature: {
|
|
265
|
+
...metadata,
|
|
266
|
+
contentHash: hashStoreText(text),
|
|
267
|
+
},
|
|
268
|
+
text,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async function updateStoreDataCache(data, payload) {
|
|
272
|
+
const metadata = await getStoreFileMetadata();
|
|
273
|
+
storeDataCache = metadata === null ? null : {
|
|
274
|
+
signature: {
|
|
275
|
+
...metadata,
|
|
276
|
+
contentHash: hashStoreText(payload),
|
|
277
|
+
},
|
|
278
|
+
data: cloneRagStoreData(data),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
150
281
|
async function load() {
|
|
151
282
|
try {
|
|
152
|
-
const
|
|
153
|
-
|
|
283
|
+
const snapshot = await readStoreFileSnapshot();
|
|
284
|
+
if (snapshot === null) {
|
|
285
|
+
storeDataCache = null;
|
|
286
|
+
return { documents: [], chunks: [] };
|
|
287
|
+
}
|
|
288
|
+
if (storeDataCache !== null &&
|
|
289
|
+
sameStoreFileSignature(storeDataCache.signature, snapshot.signature)) {
|
|
290
|
+
return cloneRagStoreData(storeDataCache.data);
|
|
291
|
+
}
|
|
292
|
+
const parsed = JSON.parse(snapshot.text);
|
|
154
293
|
if (isLegacyUploadStoreData(parsed)) {
|
|
155
|
-
|
|
294
|
+
const migrated = migrateLegacyUploadStoreData(parsed);
|
|
295
|
+
storeDataCache = {
|
|
296
|
+
signature: snapshot.signature,
|
|
297
|
+
data: cloneRagStoreData(migrated),
|
|
298
|
+
};
|
|
299
|
+
return cloneRagStoreData(migrated);
|
|
156
300
|
}
|
|
157
|
-
if (!
|
|
301
|
+
if (!isRagStoreData(parsed)) {
|
|
158
302
|
serverLogger.warn("[rag-store] Corrupted store file, resetting", { storagePath });
|
|
303
|
+
storeDataCache = null;
|
|
159
304
|
return { documents: [], chunks: [] };
|
|
160
305
|
}
|
|
161
|
-
|
|
306
|
+
storeDataCache = { signature: snapshot.signature, data: cloneRagStoreData(parsed) };
|
|
307
|
+
return cloneRagStoreData(parsed);
|
|
162
308
|
}
|
|
163
309
|
catch (err) {
|
|
164
310
|
// File not found is expected on first run; anything else is worth logging
|
|
165
311
|
if (isNotFoundError(err)) {
|
|
312
|
+
storeDataCache = null;
|
|
166
313
|
return { documents: [], chunks: [] };
|
|
167
314
|
}
|
|
168
315
|
serverLogger.warn("[rag-store] Failed to load store, resetting", err);
|
|
316
|
+
storeDataCache = null;
|
|
169
317
|
return { documents: [], chunks: [] };
|
|
170
318
|
}
|
|
171
319
|
}
|
|
@@ -174,7 +322,7 @@ function createLocalJsonRagStore(config) {
|
|
|
174
322
|
if (dir && dir !== ".") {
|
|
175
323
|
await mkdir(dir, { recursive: true });
|
|
176
324
|
}
|
|
177
|
-
const payload = JSON.stringify(data
|
|
325
|
+
const payload = JSON.stringify(data);
|
|
178
326
|
// Atomic write: write to temp file then rename to prevent corruption on crash
|
|
179
327
|
const tmpPath = storagePath + ".tmp";
|
|
180
328
|
await writeTextFile(tmpPath, payload);
|
|
@@ -191,6 +339,7 @@ function createLocalJsonRagStore(config) {
|
|
|
191
339
|
// expected: rename not available in all environments, fall back to direct write
|
|
192
340
|
await writeTextFile(storagePath, payload);
|
|
193
341
|
}
|
|
342
|
+
await updateStoreDataCache(data, payload);
|
|
194
343
|
}
|
|
195
344
|
async function ensureEmbeddings(data) {
|
|
196
345
|
const unembedded = data.chunks.filter((c) => c.embedding.length === 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-uploads.d.ts","sourceRoot":"","sources":["../../../../src/src/embedding/react/use-uploads.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qCAAqC;IACrC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,6BAA6B;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAmEvE"}
|
|
1
|
+
{"version":3,"file":"use-uploads.d.ts","sourceRoot":"","sources":["../../../../src/src/embedding/react/use-uploads.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qCAAqC;IACrC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,6BAA6B;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAmEvE"}
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { useCallback, useEffect, useRef, useState } from "../../../react/react.js";
|
|
8
8
|
import { API_ERROR } from "../../errors/index.js";
|
|
9
|
+
export function buildUploadResourceUrl(api, id) {
|
|
10
|
+
return `${api}/${encodeURIComponent(id)}`;
|
|
11
|
+
}
|
|
9
12
|
/**
|
|
10
13
|
* useUploads hook for managing RAG upload lifecycle.
|
|
11
14
|
*/
|
|
@@ -61,7 +64,7 @@ export function useUploads(options) {
|
|
|
61
64
|
const remove = useCallback(async (id) => {
|
|
62
65
|
setError(null);
|
|
63
66
|
try {
|
|
64
|
-
await fetch(
|
|
67
|
+
await fetch(buildUploadResourceUrl(options.api, id), { method: "DELETE" });
|
|
65
68
|
await refresh();
|
|
66
69
|
}
|
|
67
70
|
catch (error) {
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import type { RagStore } from "./types.js";
|
|
2
|
-
|
|
2
|
+
export type UploadAuthorizationResult = boolean | Response | void | undefined;
|
|
3
|
+
export type UploadAuthorize = (request: Request) => UploadAuthorizationResult | Promise<UploadAuthorizationResult>;
|
|
4
|
+
export type UploadHandlerAuthConfig = {
|
|
5
|
+
type: "none";
|
|
6
|
+
allowUnauthenticated: true;
|
|
7
|
+
} | {
|
|
8
|
+
authorize: UploadAuthorize;
|
|
9
|
+
};
|
|
10
|
+
export interface UploadHandlerConfig {
|
|
3
11
|
maxFileSize?: number;
|
|
12
|
+
auth?: UploadHandlerAuthConfig;
|
|
4
13
|
}
|
|
5
14
|
/**
|
|
6
15
|
* Creates HTTP route handlers for upload, listing, and deletion.
|
|
7
16
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
17
|
+
* Pass `auth: { authorize }` to protect these handlers before they read
|
|
18
|
+
* request bodies or access the RAG store. For local development, pass
|
|
19
|
+
* `auth: { type: "none", allowUnauthenticated: true }` to explicitly allow
|
|
20
|
+
* unauthenticated upload routes. Omitting `auth` still allows the route for
|
|
21
|
+
* compatibility and logs a warning.
|
|
10
22
|
*
|
|
11
23
|
* Returns `{ POST, GET, DELETE }` handlers compatible with file-based routing.
|
|
12
24
|
* POST accepts multipart form data with a `file` field, extracts text via
|
|
@@ -21,7 +33,15 @@ interface UploadHandlerConfig {
|
|
|
21
33
|
* import { createUploadHandler } from "veryfront/embedding";
|
|
22
34
|
* import { store } from "lib/store.ts";
|
|
23
35
|
*
|
|
24
|
-
* export const { POST, GET } = createUploadHandler(store
|
|
36
|
+
* export const { POST, GET } = createUploadHandler(store, {
|
|
37
|
+
* auth: {
|
|
38
|
+
* authorize: (request) => {
|
|
39
|
+
* const token = Deno.env.get("UPLOAD_TOKEN");
|
|
40
|
+
* return token !== undefined &&
|
|
41
|
+
* request.headers.get("authorization") === `Bearer ${token}`;
|
|
42
|
+
* },
|
|
43
|
+
* },
|
|
44
|
+
* });
|
|
25
45
|
* ```
|
|
26
46
|
*
|
|
27
47
|
* @example
|
|
@@ -30,15 +50,16 @@ interface UploadHandlerConfig {
|
|
|
30
50
|
* import { createUploadHandler } from "veryfront/embedding";
|
|
31
51
|
* import { store } from "lib/store.ts";
|
|
32
52
|
*
|
|
33
|
-
* export const { DELETE } = createUploadHandler(store
|
|
53
|
+
* export const { DELETE } = createUploadHandler(store, {
|
|
54
|
+
* auth: { type: "none", allowUnauthenticated: true },
|
|
55
|
+
* });
|
|
34
56
|
* ```
|
|
35
57
|
*/
|
|
36
58
|
export declare function createUploadHandler(store: RagStore, config?: UploadHandlerConfig): {
|
|
37
59
|
POST: (request: Request) => Promise<Response>;
|
|
38
|
-
GET: () => Promise<Response>;
|
|
39
|
-
DELETE: (
|
|
60
|
+
GET: (request?: Request) => Promise<Response>;
|
|
61
|
+
DELETE: (request: Request, context: {
|
|
40
62
|
params: Record<string, string>;
|
|
41
63
|
}) => Promise<Response>;
|
|
42
64
|
};
|
|
43
|
-
export {};
|
|
44
65
|
//# sourceMappingURL=upload-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqF3C,
|
|
1
|
+
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqF3C,MAAM,MAAM,yBAAyB,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG,CAC5B,OAAO,EAAE,OAAO,KACb,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;AAEpE,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,IAAI,CAAA;CAAE,GAC5C;IAAE,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC;AAEnC,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,uBAAuB,CAAC;CAChC;AA6FD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EACf,MAAM,CAAC,EAAE,mBAAmB;oBAKC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;oBAiF3B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;sBAc7C,OAAO,WACP;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAC1C,OAAO,CAAC,QAAQ,CAAC;EA6BrB"}
|
|
@@ -75,6 +75,43 @@ function sanitizeFileName(raw) {
|
|
|
75
75
|
return sanitized || "untitled";
|
|
76
76
|
}
|
|
77
77
|
const MAX_CONCURRENT_URL_LOOKUPS = 5;
|
|
78
|
+
let missingAuthWarningEmitted = false;
|
|
79
|
+
function warnMissingAuthConfig() {
|
|
80
|
+
if (missingAuthWarningEmitted)
|
|
81
|
+
return;
|
|
82
|
+
missingAuthWarningEmitted = true;
|
|
83
|
+
serverLogger.warn("createUploadHandler registered without auth. Pass auth: { authorize } for protected routes, " +
|
|
84
|
+
"or auth: { type: 'none', allowUnauthenticated: true } to explicitly allow unauthenticated uploads.");
|
|
85
|
+
}
|
|
86
|
+
function resolveUploadAuthorize(auth) {
|
|
87
|
+
if (auth === undefined) {
|
|
88
|
+
warnMissingAuthConfig();
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if ("type" in auth) {
|
|
92
|
+
if (auth.type === "none" && auth.allowUnauthenticated === true)
|
|
93
|
+
return null;
|
|
94
|
+
throw new Error("createUploadHandler auth type 'none' requires allowUnauthenticated: true.");
|
|
95
|
+
}
|
|
96
|
+
if (typeof auth.authorize === "function")
|
|
97
|
+
return auth.authorize;
|
|
98
|
+
throw new Error("createUploadHandler auth must be { authorize } or " +
|
|
99
|
+
"{ type: 'none', allowUnauthenticated: true }.");
|
|
100
|
+
}
|
|
101
|
+
async function authorizeUploadRequest(request, authorize) {
|
|
102
|
+
if (!authorize)
|
|
103
|
+
return null;
|
|
104
|
+
if (!request) {
|
|
105
|
+
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
|
106
|
+
}
|
|
107
|
+
const result = await authorize(request);
|
|
108
|
+
if (result instanceof Response)
|
|
109
|
+
return result;
|
|
110
|
+
if (result === false) {
|
|
111
|
+
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
78
115
|
async function enrichUploadsWithSourceUrls(uploads) {
|
|
79
116
|
const sourceBlobStorage = getSourceBlobStorage();
|
|
80
117
|
if (!sourceBlobStorage)
|
|
@@ -111,8 +148,11 @@ function getSourceBlobStorage() {
|
|
|
111
148
|
/**
|
|
112
149
|
* Creates HTTP route handlers for upload, listing, and deletion.
|
|
113
150
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
151
|
+
* Pass `auth: { authorize }` to protect these handlers before they read
|
|
152
|
+
* request bodies or access the RAG store. For local development, pass
|
|
153
|
+
* `auth: { type: "none", allowUnauthenticated: true }` to explicitly allow
|
|
154
|
+
* unauthenticated upload routes. Omitting `auth` still allows the route for
|
|
155
|
+
* compatibility and logs a warning.
|
|
116
156
|
*
|
|
117
157
|
* Returns `{ POST, GET, DELETE }` handlers compatible with file-based routing.
|
|
118
158
|
* POST accepts multipart form data with a `file` field, extracts text via
|
|
@@ -127,7 +167,15 @@ function getSourceBlobStorage() {
|
|
|
127
167
|
* import { createUploadHandler } from "veryfront/embedding";
|
|
128
168
|
* import { store } from "lib/store.ts";
|
|
129
169
|
*
|
|
130
|
-
* export const { POST, GET } = createUploadHandler(store
|
|
170
|
+
* export const { POST, GET } = createUploadHandler(store, {
|
|
171
|
+
* auth: {
|
|
172
|
+
* authorize: (request) => {
|
|
173
|
+
* const token = Deno.env.get("UPLOAD_TOKEN");
|
|
174
|
+
* return token !== undefined &&
|
|
175
|
+
* request.headers.get("authorization") === `Bearer ${token}`;
|
|
176
|
+
* },
|
|
177
|
+
* },
|
|
178
|
+
* });
|
|
131
179
|
* ```
|
|
132
180
|
*
|
|
133
181
|
* @example
|
|
@@ -136,13 +184,19 @@ function getSourceBlobStorage() {
|
|
|
136
184
|
* import { createUploadHandler } from "veryfront/embedding";
|
|
137
185
|
* import { store } from "lib/store.ts";
|
|
138
186
|
*
|
|
139
|
-
* export const { DELETE } = createUploadHandler(store
|
|
187
|
+
* export const { DELETE } = createUploadHandler(store, {
|
|
188
|
+
* auth: { type: "none", allowUnauthenticated: true },
|
|
189
|
+
* });
|
|
140
190
|
* ```
|
|
141
191
|
*/
|
|
142
192
|
export function createUploadHandler(store, config) {
|
|
143
193
|
const maxSize = config?.maxFileSize ?? MAX_FILE_SIZE;
|
|
194
|
+
const authorize = resolveUploadAuthorize(config?.auth);
|
|
144
195
|
async function POST(request) {
|
|
145
196
|
try {
|
|
197
|
+
const unauthorized = await authorizeUploadRequest(request, authorize);
|
|
198
|
+
if (unauthorized)
|
|
199
|
+
return unauthorized;
|
|
146
200
|
const formData = await request.formData();
|
|
147
201
|
const file = formData.get("file");
|
|
148
202
|
if (!file || !(file instanceof FileCtor)) {
|
|
@@ -201,8 +255,11 @@ export function createUploadHandler(store, config) {
|
|
|
201
255
|
return Response.json({ error: message }, { status: 500 });
|
|
202
256
|
}
|
|
203
257
|
}
|
|
204
|
-
async function GET() {
|
|
258
|
+
async function GET(request) {
|
|
205
259
|
try {
|
|
260
|
+
const unauthorized = await authorizeUploadRequest(request, authorize);
|
|
261
|
+
if (unauthorized)
|
|
262
|
+
return unauthorized;
|
|
206
263
|
const uploads = await enrichUploadsWithSourceUrls(await store.listDocuments());
|
|
207
264
|
return Response.json({ uploads });
|
|
208
265
|
}
|
|
@@ -211,8 +268,11 @@ export function createUploadHandler(store, config) {
|
|
|
211
268
|
return Response.json({ error: "Failed to list uploads" }, { status: 500 });
|
|
212
269
|
}
|
|
213
270
|
}
|
|
214
|
-
async function DELETE(
|
|
271
|
+
async function DELETE(request, context) {
|
|
215
272
|
try {
|
|
273
|
+
const unauthorized = await authorizeUploadRequest(request, authorize);
|
|
274
|
+
if (unauthorized)
|
|
275
|
+
return unauthorized;
|
|
216
276
|
const id = context.params.id;
|
|
217
277
|
if (!id) {
|
|
218
278
|
return Response.json({ error: "Missing upload ID" }, { status: 400 });
|
|
@@ -10,7 +10,7 @@ import { generateHydrationData, getDevScripts, getProdScripts, PROD_HYDRATION_MO
|
|
|
10
10
|
import { getPreviewStylesheetLink, getStudioScripts } from "./dev-scripts.js";
|
|
11
11
|
import { processMetadata } from "./metadata-builder.js";
|
|
12
12
|
import { extractCandidates, getDevStyles as getErrorOverlayStyles, getProjectCSS, } from "./styles-builder/index.js";
|
|
13
|
-
import {
|
|
13
|
+
import { buildImportMap, buildRootAttributes, shouldDisableLayout } from "./utils.js";
|
|
14
14
|
function pathToModuleUrl(path, studioEmbed) {
|
|
15
15
|
if (!path)
|
|
16
16
|
return "";
|
|
@@ -114,7 +114,7 @@ async function generateHTMLShellPartsImpl(meta, options, params, props, contentF
|
|
|
114
114
|
// Enable dev scripts for local dev OR preview mode (for HMR support in Studio),
|
|
115
115
|
// unless a caller explicitly forces production client scripts for fair benchmarking.
|
|
116
116
|
const useDevScripts = !options.forceProductionScripts && (isLocalProject || isPreviewMode);
|
|
117
|
-
const
|
|
117
|
+
const importMapPromise = buildImportMap({
|
|
118
118
|
projectDir: options.projectDir,
|
|
119
119
|
config: options.config,
|
|
120
120
|
customImports: options.importMap,
|
|
@@ -130,11 +130,11 @@ async function generateHTMLShellPartsImpl(meta, options, params, props, contentF
|
|
|
130
130
|
: getProdScripts(meta.slug || "", params, props, nonce);
|
|
131
131
|
const modeStyles = useDevScripts ? getErrorOverlayStyles(nonce) : "";
|
|
132
132
|
const modulePreloadHints = generateModulePreloadHints(options);
|
|
133
|
-
const
|
|
133
|
+
const importMap = await profilePhase("html.import_map", () => importMapPromise);
|
|
134
|
+
const importMapJson = importMap.json;
|
|
134
135
|
// Preload critical React dependencies to avoid waterfall delays.
|
|
135
136
|
// jsx-runtime is discovered late (only when modules execute), adding ~500ms latency.
|
|
136
|
-
const
|
|
137
|
-
const jsxRuntimeUrl = importMapData.imports?.["react/jsx-runtime"];
|
|
137
|
+
const jsxRuntimeUrl = importMap.imports["react/jsx-runtime"];
|
|
138
138
|
const criticalDepsPreload = jsxRuntimeUrl
|
|
139
139
|
? `<link rel="modulepreload" href="${jsxRuntimeUrl}">`
|
|
140
140
|
: "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nonce-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/nonce-injection.ts"],"names":[],"mappings":"AA8HA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA6DvE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,KAAK,CAAC,EAAE,MAAM,GACb,cAAc,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"nonce-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/nonce-injection.ts"],"names":[],"mappings":"AA8HA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA6DvE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,KAAK,CAAC,EAAE,MAAM,GACb,cAAc,CAAC,UAAU,CAAC,CA8I5B"}
|
|
@@ -160,11 +160,11 @@ export function addNonceToHtmlStream(stream, nonce) {
|
|
|
160
160
|
const decoder = new TextDecoder();
|
|
161
161
|
const encoder = new TextEncoder();
|
|
162
162
|
let buffer = "";
|
|
163
|
+
let lowerBuffer = "";
|
|
163
164
|
let rawTextTag = null;
|
|
164
165
|
function transformBuffer(flush) {
|
|
165
166
|
let result = "";
|
|
166
167
|
let index = 0;
|
|
167
|
-
const lowerBuffer = buffer.toLowerCase();
|
|
168
168
|
while (index < buffer.length) {
|
|
169
169
|
if (rawTextTag) {
|
|
170
170
|
const closingIndex = findRawTextClosingTagStart(lowerBuffer, rawTextTag, index);
|
|
@@ -227,7 +227,10 @@ export function addNonceToHtmlStream(stream, nonce) {
|
|
|
227
227
|
rawTextTag = tagName;
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
-
|
|
230
|
+
if (index > 0) {
|
|
231
|
+
buffer = buffer.slice(index);
|
|
232
|
+
lowerBuffer = buffer.toLowerCase();
|
|
233
|
+
}
|
|
231
234
|
return result;
|
|
232
235
|
}
|
|
233
236
|
const reader = stream.getReader();
|
|
@@ -244,7 +247,9 @@ export function addNonceToHtmlStream(stream, nonce) {
|
|
|
244
247
|
while (true) {
|
|
245
248
|
const { done, value } = await reader.read();
|
|
246
249
|
if (done) {
|
|
247
|
-
|
|
250
|
+
const decoded = decoder.decode();
|
|
251
|
+
buffer += decoded;
|
|
252
|
+
lowerBuffer += decoded.toLowerCase();
|
|
248
253
|
const transformed = transformBuffer(true);
|
|
249
254
|
if (transformed)
|
|
250
255
|
controller.enqueue(encoder.encode(transformed));
|
|
@@ -252,7 +257,9 @@ export function addNonceToHtmlStream(stream, nonce) {
|
|
|
252
257
|
releaseReaderLock();
|
|
253
258
|
return;
|
|
254
259
|
}
|
|
255
|
-
|
|
260
|
+
const decoded = decoder.decode(value, { stream: true });
|
|
261
|
+
buffer += decoded;
|
|
262
|
+
lowerBuffer += decoded.toLowerCase();
|
|
256
263
|
const transformed = transformBuffer(false);
|
|
257
264
|
if (transformed) {
|
|
258
265
|
controller.enqueue(encoder.encode(transformed));
|
package/esm/src/html/utils.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { VeryfrontConfig } from "../config/index.js";
|
|
2
2
|
export declare function buildRootAttributes(slug: string, mode: string, noLayout: boolean, ssrHash?: string): string;
|
|
3
|
+
export interface BuiltImportMap {
|
|
4
|
+
imports: Record<string, string>;
|
|
5
|
+
json: string;
|
|
6
|
+
}
|
|
3
7
|
interface BuildImportMapOptions {
|
|
4
8
|
projectDir?: string;
|
|
5
9
|
config?: VeryfrontConfig;
|
|
6
10
|
customImports?: Record<string, string>;
|
|
7
11
|
pretty?: boolean;
|
|
8
12
|
}
|
|
13
|
+
export declare function buildImportMap(options?: BuildImportMapOptions | Record<string, string>): Promise<BuiltImportMap>;
|
|
9
14
|
export declare function buildImportMapJson(options?: BuildImportMapOptions | Record<string, string>): Promise<string>;
|
|
10
15
|
export declare function clearImportMapCache(): void;
|
|
11
16
|
export declare function shouldDisableLayout(frontmatter?: Record<string, unknown>): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/src/html/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAc1D,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAQR;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/src/html/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAc1D,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAQR;AAaD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AA4ND,UAAU,qBAAqB;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAqBD,wBAAsB,cAAc,CAClC,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvD,OAAO,CAAC,cAAc,CAAC,CA2DzB;AAED,wBAAsB,kBAAkB,CACtC,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvD,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAElF"}
|
package/esm/src/html/utils.js
CHANGED
|
@@ -178,19 +178,25 @@ async function resolveVersions(projectDir, config) {
|
|
|
178
178
|
}
|
|
179
179
|
return { react: await reactVersion, veryfront: veryfrontVersion };
|
|
180
180
|
}
|
|
181
|
+
function stringifyImportMap(imports, pretty = true) {
|
|
182
|
+
return JSON.stringify({ imports }, null, pretty ? 2 : undefined);
|
|
183
|
+
}
|
|
184
|
+
function stableMapKey(imports) {
|
|
185
|
+
return imports
|
|
186
|
+
? JSON.stringify(Object.entries(imports).sort(([a], [b]) => a.localeCompare(b)))
|
|
187
|
+
: "";
|
|
188
|
+
}
|
|
181
189
|
function isImportMapOnlyOptions(options) {
|
|
182
190
|
return !("projectDir" in options) &&
|
|
183
191
|
!("config" in options) &&
|
|
184
192
|
!("customImports" in options) &&
|
|
185
193
|
!("pretty" in options);
|
|
186
194
|
}
|
|
187
|
-
export async function
|
|
188
|
-
const stringifyImportMap = (imports, pretty = true) => JSON.stringify({ imports }, null, pretty ? 2 : undefined);
|
|
189
|
-
const stableMapKey = (imports) => imports ? JSON.stringify(Object.entries(imports).sort(([a], [b]) => a.localeCompare(b))) : "";
|
|
195
|
+
export async function buildImportMap(options) {
|
|
190
196
|
if (options && isImportMapOnlyOptions(options)) {
|
|
191
|
-
const imports = options;
|
|
197
|
+
const imports = { ...options };
|
|
192
198
|
if (Object.keys(imports).length > 0) {
|
|
193
|
-
return stringifyImportMap(imports);
|
|
199
|
+
return { imports, json: stringifyImportMap(imports) };
|
|
194
200
|
}
|
|
195
201
|
}
|
|
196
202
|
const { projectDir, config, customImports, pretty = true } = (options ?? {});
|
|
@@ -206,7 +212,7 @@ export async function buildImportMapJson(options) {
|
|
|
206
212
|
"react/jsx-dev-runtime": reactTemplates.jsxDevRuntime(versions.react),
|
|
207
213
|
...customImports,
|
|
208
214
|
};
|
|
209
|
-
return stringifyImportMap(imports, pretty);
|
|
215
|
+
return { imports, json: stringifyImportMap(imports, pretty) };
|
|
210
216
|
}
|
|
211
217
|
let imports;
|
|
212
218
|
if (mode === "self-hosted") {
|
|
@@ -230,10 +236,14 @@ export async function buildImportMapJson(options) {
|
|
|
230
236
|
});
|
|
231
237
|
const cached = importMapJsonCache.get(cacheKey);
|
|
232
238
|
if (cached)
|
|
233
|
-
return cached
|
|
239
|
+
return cached;
|
|
234
240
|
const json = stringifyImportMap(imports, pretty);
|
|
235
|
-
|
|
236
|
-
|
|
241
|
+
const built = { cacheKey, imports, json };
|
|
242
|
+
importMapJsonCache.set(cacheKey, built);
|
|
243
|
+
return built;
|
|
244
|
+
}
|
|
245
|
+
export async function buildImportMapJson(options) {
|
|
246
|
+
return (await buildImportMap(options)).json;
|
|
237
247
|
}
|
|
238
248
|
export function clearImportMapCache() {
|
|
239
249
|
importMapJsonCache.clear();
|
|
@@ -12,6 +12,8 @@ export declare class RedisRateLimitStore implements RateLimitStore {
|
|
|
12
12
|
private readonly keyPrefix;
|
|
13
13
|
constructor(options?: RedisRateLimitOptions);
|
|
14
14
|
private ensureClient;
|
|
15
|
+
private clearCachedClient;
|
|
16
|
+
private attachClientLifecycleHandlers;
|
|
15
17
|
private connectClient;
|
|
16
18
|
private storageKey;
|
|
17
19
|
increment(key: string, windowMs: number): Promise<RateLimitEntry>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-rate-limit.d.ts","sourceRoot":"","sources":["../../../../../src/src/middleware/builtin/security/redis-rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"redis-rate-limit.d.ts","sourceRoot":"","sources":["../../../../../src/src/middleware/builtin/security/redis-rate-limit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA4BjE,4CAA4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wCAAwC;AACxC,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,GAAE,qBAA0B;IAK/C,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,6BAA6B;YAWvB,aAAa;IAiC3B,OAAO,CAAC,UAAU;IAIZ,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcjE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B"}
|