@remix-run/assets 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +185 -104
- package/dist/assets.d.ts +4 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/lib/access.d.ts +29 -2
- package/dist/lib/access.d.ts.map +1 -1
- package/dist/lib/access.js +52 -26
- package/dist/lib/asset-server.d.ts +61 -25
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +127 -55
- package/dist/lib/compilation-error.d.ts +1 -1
- package/dist/lib/compilation-error.d.ts.map +1 -1
- package/dist/lib/files/compiler.d.ts +1 -1
- package/dist/lib/files/compiler.d.ts.map +1 -1
- package/dist/lib/files/compiler.js +28 -31
- package/dist/lib/files/config.d.ts +6 -0
- package/dist/lib/files/config.d.ts.map +1 -1
- package/dist/lib/files/config.js +9 -0
- package/dist/lib/fingerprint.d.ts +0 -4
- package/dist/lib/fingerprint.d.ts.map +1 -1
- package/dist/lib/fingerprint.js +0 -4
- package/dist/lib/hmr.d.ts +7 -0
- package/dist/lib/hmr.d.ts.map +1 -1
- package/dist/lib/hmr.js +198 -25
- package/dist/lib/injected-packages.d.ts +3 -2
- package/dist/lib/injected-packages.d.ts.map +1 -1
- package/dist/lib/injected-packages.js +11 -8
- package/dist/lib/inspection.d.ts +39 -0
- package/dist/lib/inspection.d.ts.map +1 -0
- package/dist/lib/inspection.js +160 -0
- package/dist/lib/routes.d.ts +12 -3
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +124 -80
- package/dist/lib/scripts/compiler.d.ts +8 -2
- package/dist/lib/scripts/compiler.d.ts.map +1 -1
- package/dist/lib/scripts/compiler.js +188 -38
- package/dist/lib/scripts/emit.d.ts +2 -1
- package/dist/lib/scripts/emit.d.ts.map +1 -1
- package/dist/lib/scripts/emit.js +25 -16
- package/dist/lib/scripts/resolve.d.ts +7 -1
- package/dist/lib/scripts/resolve.d.ts.map +1 -1
- package/dist/lib/scripts/resolve.js +119 -12
- package/dist/lib/scripts/specifiers.d.ts +2 -0
- package/dist/lib/scripts/specifiers.d.ts.map +1 -0
- package/dist/lib/scripts/specifiers.js +9 -0
- package/dist/lib/scripts/transform.d.ts +2 -3
- package/dist/lib/scripts/transform.d.ts.map +1 -1
- package/dist/lib/scripts/transform.js +4 -18
- package/dist/lib/styles/compiler.d.ts +0 -1
- package/dist/lib/styles/compiler.d.ts.map +1 -1
- package/dist/lib/styles/compiler.js +105 -25
- package/dist/lib/styles/emit.d.ts +2 -1
- package/dist/lib/styles/emit.d.ts.map +1 -1
- package/dist/lib/styles/emit.js +12 -10
- package/dist/lib/styles/resolve.d.ts +0 -1
- package/dist/lib/styles/resolve.d.ts.map +1 -1
- package/dist/lib/styles/resolve.js +8 -9
- package/dist/lib/styles/transform.d.ts +0 -2
- package/dist/lib/styles/transform.d.ts.map +1 -1
- package/dist/lib/styles/transform.js +2 -9
- package/dist/lib/virtual-store.d.ts +8 -0
- package/dist/lib/virtual-store.d.ts.map +1 -0
- package/dist/lib/virtual-store.js +100 -0
- package/package.json +6 -6
- package/src/assets.ts +9 -1
- package/src/lib/access.ts +83 -30
- package/src/lib/asset-server.ts +224 -94
- package/src/lib/compilation-error.ts +4 -3
- package/src/lib/files/compiler.ts +32 -42
- package/src/lib/files/config.ts +17 -0
- package/src/lib/fingerprint.ts +0 -9
- package/src/lib/hmr.ts +210 -26
- package/src/lib/injected-packages.ts +16 -10
- package/src/lib/inspection.ts +229 -0
- package/src/lib/routes.ts +158 -126
- package/src/lib/scripts/compiler.ts +240 -54
- package/src/lib/scripts/emit.ts +34 -19
- package/src/lib/scripts/resolve.ts +175 -13
- package/src/lib/scripts/specifiers.ts +11 -0
- package/src/lib/scripts/transform.ts +6 -25
- package/src/lib/styles/compiler.ts +137 -39
- package/src/lib/styles/emit.ts +18 -13
- package/src/lib/styles/resolve.ts +8 -10
- package/src/lib/styles/transform.ts +2 -12
- package/src/lib/virtual-store.ts +124 -0
package/dist/lib/asset-server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createFileCompiler, createResponseForFile } from './files/compiler.js';
|
|
|
6
6
|
import { normalizeFilesOptions, serializeAssetTransformInvocations } from './files/config.js';
|
|
7
7
|
import { getFingerprintRequestCacheControl, parseFingerprintSuffix } from './fingerprint.js';
|
|
8
8
|
import { createHmrClientSource } from './hmr.js';
|
|
9
|
-
import {
|
|
9
|
+
import { getInjectedPackageMountConfigs } from './injected-packages.js';
|
|
10
10
|
import { normalizeFilePath, normalizePathname } from './paths.js';
|
|
11
11
|
import { compileRoutes } from './routes.js';
|
|
12
12
|
import { createResponseForScript, createScriptCompiler } from './scripts/compiler.js';
|
|
@@ -14,7 +14,13 @@ import { supportedScriptExtensions } from './scripts/resolve.js';
|
|
|
14
14
|
import { createResponseForStyle, createStyleCompiler, isStyleFilePath } from './styles/compiler.js';
|
|
15
15
|
import { resolveScriptTarget, resolveStyleTarget } from './target.js';
|
|
16
16
|
import { createAssetServerWatcher } from './watch.js';
|
|
17
|
+
import { createAssetInspector } from './inspection.js';
|
|
18
|
+
import { getVirtualStoreMountConfigs } from './virtual-store.js';
|
|
17
19
|
const scriptExtensionSet = new Set(supportedScriptExtensions);
|
|
20
|
+
const defaultMounts = {
|
|
21
|
+
app: 'app',
|
|
22
|
+
npm: 'node_modules',
|
|
23
|
+
};
|
|
18
24
|
const chokidarWatcherByAssetServer = new WeakMap();
|
|
19
25
|
const watcherByAssetServer = new WeakMap();
|
|
20
26
|
export function getInternalChokidarWatcher(assetServer) {
|
|
@@ -27,7 +33,7 @@ export function getInternalWatchTargets(assetServer) {
|
|
|
27
33
|
* Create an asset server instance
|
|
28
34
|
*
|
|
29
35
|
* Compiles TypeScript/JavaScript scripts and CSS styles on demand with optional
|
|
30
|
-
*
|
|
36
|
+
* content-based URL fingerprinting, caching, and configurable directory mounts.
|
|
31
37
|
*
|
|
32
38
|
* @param options Server configuration
|
|
33
39
|
* @returns A {@link AssetServer} with `fetch()`, `getHref()`, and `getPreloads()` methods
|
|
@@ -36,9 +42,6 @@ export function getInternalWatchTargets(assetServer) {
|
|
|
36
42
|
* ```ts
|
|
37
43
|
* let assetServer = createAssetServer({
|
|
38
44
|
* basePath: '/assets',
|
|
39
|
-
* fileMap: {
|
|
40
|
-
* '/app/*path': 'app/*path',
|
|
41
|
-
* },
|
|
42
45
|
* allowFiles: ['app/routes.ts', 'app/**\/public/**'],
|
|
43
46
|
* allowPackages: ['remix'],
|
|
44
47
|
* denyFiles: ['app/**\/*.test.*'],
|
|
@@ -54,10 +57,17 @@ export function createAssetServer(options) {
|
|
|
54
57
|
allowPackages: resolvedOptions.allowPackages,
|
|
55
58
|
denyFiles: resolvedOptions.denyFiles,
|
|
56
59
|
packageSearchRoots: hasPackages(resolvedOptions.allowPackages)
|
|
57
|
-
? getPackageSearchRoots(
|
|
60
|
+
? getPackageSearchRoots(resolvedOptions.mounts, resolvedOptions.rootDir)
|
|
58
61
|
: undefined,
|
|
59
62
|
rootDir: resolvedOptions.rootDir,
|
|
60
63
|
});
|
|
64
|
+
let assetInspector = createAssetInspector({
|
|
65
|
+
accessPolicy,
|
|
66
|
+
allowFiles: resolvedOptions.allowFiles,
|
|
67
|
+
fileExtensions: resolvedOptions.files.extensions,
|
|
68
|
+
rootDir: resolvedOptions.rootDir,
|
|
69
|
+
routes: resolvedOptions.routes,
|
|
70
|
+
});
|
|
61
71
|
let watcher = null;
|
|
62
72
|
let chokidarWatcher = null;
|
|
63
73
|
let fileCompiler = null;
|
|
@@ -73,8 +83,8 @@ export function createAssetServer(options) {
|
|
|
73
83
|
});
|
|
74
84
|
let sendHmrPayload = resolvedOptions.hmr ? createHmrPayloadSender() : null;
|
|
75
85
|
let hmrPathnames = getHmrPathnames(resolvedOptions.basePath);
|
|
86
|
+
let hmrDataKey = `remix/assets@1:${resolvedOptions.basePath}`;
|
|
76
87
|
let scriptCompiler = createScriptCompiler({
|
|
77
|
-
buildId: resolvedOptions.buildId,
|
|
78
88
|
define: resolvedOptions.define,
|
|
79
89
|
external: resolvedOptions.external,
|
|
80
90
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
@@ -108,7 +118,6 @@ export function createAssetServer(options) {
|
|
|
108
118
|
watchMode: resolvedOptions.watchOptions !== null,
|
|
109
119
|
});
|
|
110
120
|
let styleCompiler = createStyleCompiler({
|
|
111
|
-
buildId: resolvedOptions.buildId,
|
|
112
121
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
113
122
|
getServedFileUrl: (identityPath, options) => {
|
|
114
123
|
if (!fileCompiler) {
|
|
@@ -159,8 +168,8 @@ export function createAssetServer(options) {
|
|
|
159
168
|
});
|
|
160
169
|
if (resolvedOptions.files.extensions.length > 0) {
|
|
161
170
|
fileCompiler = createFileCompiler({
|
|
162
|
-
buildId: resolvedOptions.buildId,
|
|
163
171
|
cache: resolvedOptions.files.cache,
|
|
172
|
+
cacheKey: resolvedOptions.files.cacheKey,
|
|
164
173
|
extensions: resolvedOptions.files.extensions,
|
|
165
174
|
fingerprintAssets: resolvedOptions.fingerprintAssets,
|
|
166
175
|
globalTransforms: resolvedOptions.files.globalTransforms,
|
|
@@ -208,9 +217,9 @@ export function createAssetServer(options) {
|
|
|
208
217
|
for (let event of events) {
|
|
209
218
|
let normalizedFilePath = normalizeFilePath(event.filePath);
|
|
210
219
|
let scriptUpdates = await scriptCompiler.classifyHmrFileEvent(normalizedFilePath, event.event);
|
|
211
|
-
let scriptPayload =
|
|
220
|
+
let scriptPayload = await createScriptHmrPayloadWithImportMaps(scriptUpdates);
|
|
212
221
|
if (scriptPayload) {
|
|
213
|
-
browserHmrEvents.push(createBrowserHmrEvent(scriptPayload, getScriptHmrUpdateFiles(scriptUpdates)));
|
|
222
|
+
browserHmrEvents.push(createBrowserHmrEvent(scriptPayload, getScriptHmrUpdateFiles(scriptUpdates), hmrDataKey));
|
|
214
223
|
}
|
|
215
224
|
let styleUpdates = await styleCompiler.classifyHmrFileEvent(normalizedFilePath, event.event);
|
|
216
225
|
for (let styleUpdate of styleUpdates) {
|
|
@@ -223,11 +232,34 @@ export function createAssetServer(options) {
|
|
|
223
232
|
type: 'css',
|
|
224
233
|
},
|
|
225
234
|
],
|
|
226
|
-
}, [styleUpdate.filePath]));
|
|
235
|
+
}, [styleUpdate.filePath], hmrDataKey));
|
|
227
236
|
}
|
|
228
237
|
await fileCompiler?.handleFileEvent(normalizedFilePath, event.event);
|
|
229
238
|
}
|
|
230
239
|
return browserHmrEvents;
|
|
240
|
+
async function createScriptHmrPayloadWithImportMaps(updates) {
|
|
241
|
+
let payload = createScriptHmrPayload(updates);
|
|
242
|
+
if (!payload || payload.type === 'browser:reload')
|
|
243
|
+
return payload;
|
|
244
|
+
let acceptedUpdates = updates.filter((update) => update.accepted);
|
|
245
|
+
let importMaps = await Promise.all(acceptedUpdates.map(async (update) => {
|
|
246
|
+
try {
|
|
247
|
+
return await scriptCompiler.getImportMap(update.acceptedFilePath);
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
if (!isAssetServerCompilationError(error))
|
|
251
|
+
throw error;
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
}));
|
|
255
|
+
return {
|
|
256
|
+
...payload,
|
|
257
|
+
updates: payload.updates.map((update, index) => ({
|
|
258
|
+
...update,
|
|
259
|
+
...(importMaps[index] ? { importMap: importMaps[index] } : null),
|
|
260
|
+
})),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
231
263
|
}
|
|
232
264
|
function updateBrowserHmrWatchedFiles(delta) {
|
|
233
265
|
browserHmrChannelPromise
|
|
@@ -239,6 +271,12 @@ export function createAssetServer(options) {
|
|
|
239
271
|
});
|
|
240
272
|
}
|
|
241
273
|
let assetServer = {
|
|
274
|
+
getAssetDetails(input) {
|
|
275
|
+
return assetInspector.getAssetDetails(input);
|
|
276
|
+
},
|
|
277
|
+
getAssets() {
|
|
278
|
+
return assetInspector.getAssets();
|
|
279
|
+
},
|
|
242
280
|
async fetch(request) {
|
|
243
281
|
if (request.method !== 'GET' && request.method !== 'HEAD')
|
|
244
282
|
return null;
|
|
@@ -247,7 +285,7 @@ export function createAssetServer(options) {
|
|
|
247
285
|
if (requestPathname === hmrPathnames.client) {
|
|
248
286
|
let browserHmrChannel = await browserHmrChannelPromise;
|
|
249
287
|
assertBrowserEventUrl(browserHmrChannel?.url);
|
|
250
|
-
return createHmrClientResponse(browserHmrChannel.url, request.method);
|
|
288
|
+
return await createHmrClientResponse(browserHmrChannel.url, hmrDataKey, resolvedOptions.hmrModuleImporter, request.method, scriptCompiler);
|
|
251
289
|
}
|
|
252
290
|
}
|
|
253
291
|
let requestUrl = new URL(request.url);
|
|
@@ -277,7 +315,10 @@ export function createAssetServer(options) {
|
|
|
277
315
|
}
|
|
278
316
|
let compiledStyle = styleResult.style;
|
|
279
317
|
if (parsedRequestPathname.requestedFingerprint !== null) {
|
|
280
|
-
|
|
318
|
+
let fingerprint = parsedRequestPathname.isSourceMapRequest
|
|
319
|
+
? compiledStyle.sourceMap?.fingerprint
|
|
320
|
+
: compiledStyle.fingerprint;
|
|
321
|
+
if (fingerprint !== parsedRequestPathname.requestedFingerprint)
|
|
281
322
|
return null;
|
|
282
323
|
}
|
|
283
324
|
return createResponseForStyle(compiledStyle, {
|
|
@@ -332,7 +373,10 @@ export function createAssetServer(options) {
|
|
|
332
373
|
}
|
|
333
374
|
let compiledScript = scriptResult.script;
|
|
334
375
|
if (parsedRequestPathname.requestedFingerprint !== null) {
|
|
335
|
-
|
|
376
|
+
let fingerprint = parsedRequestPathname.isSourceMapRequest
|
|
377
|
+
? compiledScript.sourceMap?.fingerprint
|
|
378
|
+
: compiledScript.fingerprint;
|
|
379
|
+
if (fingerprint !== parsedRequestPathname.requestedFingerprint)
|
|
336
380
|
return null;
|
|
337
381
|
}
|
|
338
382
|
return createResponseForScript(compiledScript, {
|
|
@@ -383,6 +427,14 @@ export function createAssetServer(options) {
|
|
|
383
427
|
}
|
|
384
428
|
return scriptCompiler.getHref(filePath);
|
|
385
429
|
},
|
|
430
|
+
async getScriptEntry(filePath) {
|
|
431
|
+
let [href, preloads, importMap] = await Promise.all([
|
|
432
|
+
assetServer.getHref(filePath),
|
|
433
|
+
assetServer.getPreloads(filePath),
|
|
434
|
+
assetServer.getImportMap(filePath),
|
|
435
|
+
]);
|
|
436
|
+
return { href, preloads, importMap };
|
|
437
|
+
},
|
|
386
438
|
async getPreloads(filePath) {
|
|
387
439
|
let filePaths = Array.isArray(filePath) ? filePath : [filePath];
|
|
388
440
|
let fileAssetFiles = [];
|
|
@@ -437,6 +489,16 @@ export function createAssetServer(options) {
|
|
|
437
489
|
});
|
|
438
490
|
return mergePreloadLayers(await Promise.all(preloadLayerGroupPromises));
|
|
439
491
|
},
|
|
492
|
+
async getImportMap(filePath) {
|
|
493
|
+
let filePaths = Array.isArray(filePath) ? filePath : [filePath];
|
|
494
|
+
for (let nextFilePath of filePaths) {
|
|
495
|
+
let typeCheckFilePath = stripFilePathUrlSuffix(nextFilePath);
|
|
496
|
+
if (!isScriptFilePath(typeCheckFilePath)) {
|
|
497
|
+
throw new TypeError(`assetServer.getImportMap() only supports script files: ${nextFilePath}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return scriptCompiler.getImportMap(filePath);
|
|
501
|
+
},
|
|
440
502
|
async close() {
|
|
441
503
|
if (closed)
|
|
442
504
|
return;
|
|
@@ -493,8 +555,13 @@ function getHmrPathnames(basePath) {
|
|
|
493
555
|
events: `${hmrBase}/events`,
|
|
494
556
|
};
|
|
495
557
|
}
|
|
496
|
-
function createHmrClientResponse(eventPathname, method) {
|
|
497
|
-
|
|
558
|
+
async function createHmrClientResponse(eventPathname, dataKey, moduleImporter, method, scriptCompiler) {
|
|
559
|
+
let moduleImporterHref = moduleImporter
|
|
560
|
+
? await scriptCompiler.resolveSpecifierFromRoot(moduleImporter)
|
|
561
|
+
: null;
|
|
562
|
+
return new Response(method === 'HEAD'
|
|
563
|
+
? null
|
|
564
|
+
: createHmrClientSource({ dataKey, eventPathname, moduleImporter: moduleImporterHref }), {
|
|
498
565
|
headers: {
|
|
499
566
|
'Cache-Control': 'no-cache',
|
|
500
567
|
'Content-Type': 'application/javascript; charset=utf-8',
|
|
@@ -509,7 +576,7 @@ function assertBrowserEventUrl(url) {
|
|
|
509
576
|
function createHmrPayloadSender() {
|
|
510
577
|
return () => { };
|
|
511
578
|
}
|
|
512
|
-
function createBrowserHmrEvent(payload, files) {
|
|
579
|
+
function createBrowserHmrEvent(payload, files, dataKey) {
|
|
513
580
|
if (payload.type === 'browser:reload') {
|
|
514
581
|
return {
|
|
515
582
|
...(files.length === 0 ? {} : { files: [...files] }),
|
|
@@ -517,10 +584,14 @@ function createBrowserHmrEvent(payload, files) {
|
|
|
517
584
|
};
|
|
518
585
|
}
|
|
519
586
|
return {
|
|
587
|
+
data: {
|
|
588
|
+
[dataKey]: {
|
|
589
|
+
timestamp: payload.timestamp,
|
|
590
|
+
updates: payload.updates,
|
|
591
|
+
},
|
|
592
|
+
},
|
|
520
593
|
...(files.length === 0 ? {} : { files: [...files] }),
|
|
521
|
-
timestamp: payload.timestamp,
|
|
522
594
|
type: 'update',
|
|
523
|
-
updates: payload.updates,
|
|
524
595
|
};
|
|
525
596
|
}
|
|
526
597
|
function getScriptHmrUpdateFiles(updates) {
|
|
@@ -541,7 +612,9 @@ export function createScriptHmrPayload(updates) {
|
|
|
541
612
|
timestamp,
|
|
542
613
|
type: 'browser:update',
|
|
543
614
|
updates: acceptedUpdates.map((update) => ({
|
|
544
|
-
...(update.
|
|
615
|
+
...(update.acceptedUrlPathname === update.path
|
|
616
|
+
? {}
|
|
617
|
+
: { acceptedPath: update.acceptedUrlPathname }),
|
|
545
618
|
path: update.path,
|
|
546
619
|
type: 'js',
|
|
547
620
|
})),
|
|
@@ -588,36 +661,42 @@ function resolveAssetServerOptions(options) {
|
|
|
588
661
|
let rootDir = normalizeFilePath(fs.realpathSync(path.resolve(options.rootDir ?? process.cwd())));
|
|
589
662
|
let basePath = normalizeBasePath(options.basePath);
|
|
590
663
|
let scriptOptions = options.scripts ?? {};
|
|
591
|
-
let
|
|
664
|
+
let fingerprintAssets = normalizeFingerprintOptions({
|
|
592
665
|
fingerprint: options.fingerprint,
|
|
593
666
|
watch: options.watch,
|
|
594
667
|
});
|
|
595
668
|
let watchOptions = normalizeWatchOptions(options.watch);
|
|
596
|
-
let
|
|
597
|
-
|
|
669
|
+
let hmr = normalizeHmrOptions(options.hmr);
|
|
670
|
+
let mounts = options.mounts ?? defaultMounts;
|
|
671
|
+
if (hmr.channel && watchOptions === null) {
|
|
598
672
|
throw new TypeError('hmr requires watch mode');
|
|
599
673
|
}
|
|
674
|
+
if (Object.keys(mounts).length === 0) {
|
|
675
|
+
throw new TypeError('mounts must include at least one entry');
|
|
676
|
+
}
|
|
600
677
|
return {
|
|
601
678
|
allowFiles: options.allowFiles,
|
|
602
679
|
allowPackages: options.allowPackages,
|
|
603
680
|
basePath,
|
|
604
|
-
buildId: fingerprintOptions.buildId,
|
|
605
681
|
define: scriptOptions.define,
|
|
606
682
|
denyFiles: options.denyFiles,
|
|
607
683
|
external: scriptOptions.external ?? [],
|
|
608
684
|
files: normalizeFilesOptions(options.files),
|
|
609
|
-
fingerprintAssets
|
|
610
|
-
hmr:
|
|
685
|
+
fingerprintAssets,
|
|
686
|
+
hmr: hmr.channel,
|
|
687
|
+
hmrModuleImporter: hmr.moduleImporter,
|
|
611
688
|
minify: options.minify ?? false,
|
|
689
|
+
mounts,
|
|
612
690
|
loaders: scriptOptions.loaders ?? [],
|
|
613
691
|
onError: options.onError ?? defaultErrorHandler,
|
|
614
692
|
rootDir,
|
|
615
693
|
routes: compileRoutes(basePath, [
|
|
616
694
|
{
|
|
617
|
-
|
|
695
|
+
mounts,
|
|
618
696
|
rootDir,
|
|
619
697
|
},
|
|
620
|
-
...
|
|
698
|
+
...getInjectedPackageMountConfigs(),
|
|
699
|
+
...getVirtualStoreMountConfigs({ mounts, rootDir }),
|
|
621
700
|
]),
|
|
622
701
|
sourceMapSourcePaths: options.sourceMapSourcePaths ?? 'url',
|
|
623
702
|
sourceMaps: options.sourceMaps,
|
|
@@ -626,13 +705,19 @@ function resolveAssetServerOptions(options) {
|
|
|
626
705
|
watchOptions,
|
|
627
706
|
};
|
|
628
707
|
}
|
|
629
|
-
function
|
|
630
|
-
if (
|
|
631
|
-
return null;
|
|
632
|
-
if (typeof
|
|
633
|
-
|
|
708
|
+
function normalizeHmrOptions(options) {
|
|
709
|
+
if (options === undefined)
|
|
710
|
+
return { channel: null, moduleImporter: null };
|
|
711
|
+
if (typeof options === 'function')
|
|
712
|
+
return { channel: options, moduleImporter: null };
|
|
713
|
+
if (!options || typeof options !== 'object' || typeof options.channel !== 'function') {
|
|
714
|
+
throw new TypeError('hmr must be a function or an object with a channel function');
|
|
715
|
+
}
|
|
716
|
+
if (options.moduleImporter !== undefined &&
|
|
717
|
+
(typeof options.moduleImporter !== 'string' || options.moduleImporter.trim().length === 0)) {
|
|
718
|
+
throw new TypeError('hmr.moduleImporter must be a non-empty string');
|
|
634
719
|
}
|
|
635
|
-
return
|
|
720
|
+
return { channel: options.channel, moduleImporter: options.moduleImporter ?? null };
|
|
636
721
|
}
|
|
637
722
|
function createBrowserHmrChannel(createChannel, handleFileEvents, isClosed, setUnsubscribe) {
|
|
638
723
|
if (!createChannel)
|
|
@@ -680,24 +765,16 @@ function normalizeBasePath(basePath) {
|
|
|
680
765
|
return normalizePathname(basePath || '/').replace(/\/+$/, '') || '/';
|
|
681
766
|
}
|
|
682
767
|
function normalizeFingerprintOptions(options) {
|
|
683
|
-
if (
|
|
684
|
-
|
|
685
|
-
enabled: false,
|
|
686
|
-
};
|
|
768
|
+
if (options.fingerprint !== undefined && typeof options.fingerprint !== 'boolean') {
|
|
769
|
+
throw new TypeError('fingerprint must be a boolean');
|
|
687
770
|
}
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
}
|
|
691
|
-
if (options.fingerprint.buildId.length === 0) {
|
|
692
|
-
throw new TypeError('fingerprint.buildId must be a non-empty string');
|
|
771
|
+
if (!options.fingerprint) {
|
|
772
|
+
return false;
|
|
693
773
|
}
|
|
694
774
|
if (options.watch !== false) {
|
|
695
775
|
throw new TypeError('fingerprint cannot be used with watch mode');
|
|
696
776
|
}
|
|
697
|
-
return
|
|
698
|
-
enabled: true,
|
|
699
|
-
buildId: options.fingerprint.buildId,
|
|
700
|
-
};
|
|
777
|
+
return true;
|
|
701
778
|
}
|
|
702
779
|
function normalizeWatchOptions(options) {
|
|
703
780
|
if (options === false)
|
|
@@ -709,13 +786,8 @@ function normalizeWatchOptions(options) {
|
|
|
709
786
|
function hasPackages(packages) {
|
|
710
787
|
return packages !== undefined && packages.length > 0;
|
|
711
788
|
}
|
|
712
|
-
function getPackageSearchRoots(
|
|
713
|
-
return Object.values(
|
|
714
|
-
}
|
|
715
|
-
function getStaticFilePatternPrefix(filePattern) {
|
|
716
|
-
let firstDynamicIndex = filePattern.search(/[*:]/);
|
|
717
|
-
let staticPrefix = firstDynamicIndex === -1 ? filePattern : filePattern.slice(0, firstDynamicIndex);
|
|
718
|
-
return staticPrefix.replace(/[/\\]*$/, '');
|
|
789
|
+
function getPackageSearchRoots(mounts, rootDir) {
|
|
790
|
+
return Object.values(mounts).map((fileRoot) => path.resolve(rootDir, fileRoot));
|
|
719
791
|
}
|
|
720
792
|
function parseAssetRequestPathname(pathname, options) {
|
|
721
793
|
let isSourceMapRequest = pathname.endsWith('.map');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type AssetServerCompilationErrorCode = 'FILE_NOT_FOUND' | 'FILE_NOT_ALLOWED' | 'FILE_NOT_SUPPORTED' | '
|
|
1
|
+
type AssetServerCompilationErrorCode = 'FILE_NOT_FOUND' | 'FILE_NOT_ALLOWED' | 'FILE_NOT_SUPPORTED' | 'FILE_OUTSIDE_MOUNTS' | 'FILE_TRANSFORM_QUERY_INVALID' | 'FILE_TRANSFORM_NOT_SUPPORTED' | 'FILE_TRANSFORM_RESULT_INVALID' | 'FILE_TRANSFORM_FAILED' | 'COMMONJS_NOT_SUPPORTED' | 'TRANSFORM_FAILED' | 'LOADER_FAILED' | 'EMIT_FAILED' | 'IMPORT_RESOLUTION_FAILED' | 'IMPORT_NOT_SUPPORTED' | 'IMPORT_NOT_ALLOWED' | 'IMPORT_OUTSIDE_MOUNTS' | 'IMPORT_RESOLUTION_NOT_DIRECTORY_UNIFORM' | 'URL_RESOLUTION_FAILED' | 'URL_NOT_SUPPORTED' | 'URL_NOT_ALLOWED' | 'URL_OUTSIDE_MOUNTS';
|
|
2
2
|
/**
|
|
3
3
|
* Internal error used by the request-time asset compilation pipeline.
|
|
4
4
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compilation-error.d.ts","sourceRoot":"","sources":["../../src/lib/compilation-error.ts"],"names":[],"mappings":"AAAA,KAAK,+BAA+B,GAChC,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,
|
|
1
|
+
{"version":3,"file":"compilation-error.d.ts","sourceRoot":"","sources":["../../src/lib/compilation-error.ts"],"names":[],"mappings":"AAAA,KAAK,+BAA+B,GAChC,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,qBAAqB,GACrB,8BAA8B,GAC9B,8BAA8B,GAC9B,+BAA+B,GAC/B,uBAAuB,GACvB,wBAAwB,GACxB,kBAAkB,GAClB,eAAe,GACf,aAAa,GACb,0BAA0B,GAC1B,sBAAsB,GACtB,oBAAoB,GACpB,uBAAuB,GACvB,yCAAyC,GACzC,uBAAuB,GACvB,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,CAAA;AAExB;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,IAAI,EAAE,+BAA+B,CAAA;IAErC,YACE,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QACP,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,IAAI,EAAE,+BAA+B,CAAA;KACtC,EAKF;CACF;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,2BAA2B,CAEtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,+BAA+B,CAAA;CACtC,GACA,2BAA2B,CAE7B"}
|
|
@@ -25,8 +25,8 @@ type FileGetHrefOptions = {
|
|
|
25
25
|
transform: readonly string[] | null;
|
|
26
26
|
};
|
|
27
27
|
type FileCompilerOptions = {
|
|
28
|
-
buildId?: string;
|
|
29
28
|
cache?: FileStorage;
|
|
29
|
+
cacheKey?: string;
|
|
30
30
|
extensions: readonly string[];
|
|
31
31
|
fingerprintAssets: boolean;
|
|
32
32
|
globalTransforms: readonly {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/files/compiler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAU1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,wBAAwB,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAA;AAU7F,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B,CAAA;AAID,KAAK,iBAAiB,GAAG,WAAW,CAAA;AAEpC,KAAK,aAAa,GACd;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,cAAc,CAAA;CACrB,GACD;IACE,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAEL,KAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,KAAK,mBAAmB,GAAG;IACzB,
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../src/lib/files/compiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { IfNoneMatch } from '@remix-run/headers/if-none-match';
|
|
6
6
|
import { detectContentType } from '@remix-run/mime';
|
|
7
7
|
import { createAssetServerCompilationError, isAssetServerCompilationError, } from '../compilation-error.js';
|
|
8
|
-
import { formatFingerprintedPathname,
|
|
8
|
+
import { formatFingerprintedPathname, hashContent } from '../fingerprint.js';
|
|
9
9
|
import { normalizeFilePath, resolveFilePath } from '../paths.js';
|
|
10
10
|
import { parseAssetTransformInvocations } from './config.js';
|
|
11
11
|
import { createSourceFileStore } from './store.js';
|
|
@@ -19,7 +19,7 @@ export function createFileCompiler(options) {
|
|
|
19
19
|
let transformedAssetMetadataByCacheKey = new Map();
|
|
20
20
|
let transformedCacheKeysByIdentityPath = new Map();
|
|
21
21
|
let transformedEmitInFlightByCacheKey = new Map();
|
|
22
|
-
let
|
|
22
|
+
let cacheKey = resolvedOptions.cacheKey ?? crypto.randomUUID();
|
|
23
23
|
let resolveArgs = {
|
|
24
24
|
extensions: resolvedOptions.extensionSet,
|
|
25
25
|
isAllowed: resolvedOptions.isAllowed,
|
|
@@ -30,8 +30,8 @@ export function createFileCompiler(options) {
|
|
|
30
30
|
let resolvedFile = resolveServedFileOrThrow(resolveInputFilePath(filePath), resolveArgs);
|
|
31
31
|
let record = getFreshSourceFileRecord(resolvedFile.identityPath);
|
|
32
32
|
if (shouldUseTransformPipeline(getOptions.transform)) {
|
|
33
|
-
let
|
|
34
|
-
let notModified = getNotModifiedFile(transformedAssetMetadataByCacheKey.get(
|
|
33
|
+
let transformedCacheKey = getTransformedRecordCacheKey(cacheKey, record, getOptions.transform);
|
|
34
|
+
let notModified = getNotModifiedFile(transformedAssetMetadataByCacheKey.get(transformedCacheKey), getOptions);
|
|
35
35
|
if (notModified)
|
|
36
36
|
return notModified;
|
|
37
37
|
let transformedFile = await getOrCreateTransformedFile(record, getOptions.transform);
|
|
@@ -62,9 +62,13 @@ export function createFileCompiler(options) {
|
|
|
62
62
|
async getHref(filePath, hrefOptions) {
|
|
63
63
|
let resolvedFile = resolveServedFileOrThrow(resolveInputFilePath(filePath), resolveArgs);
|
|
64
64
|
let record = getFreshSourceFileRecord(resolvedFile.identityPath);
|
|
65
|
-
let href =
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
let href = resolvedFile.stableUrlPathname;
|
|
66
|
+
if (resolvedOptions.fingerprintAssets) {
|
|
67
|
+
let emittedFile = shouldUseTransformPipeline(hrefOptions.transform)
|
|
68
|
+
? await getOrCreateTransformedFile(record, hrefOptions.transform)
|
|
69
|
+
: await getOrCreateSourceFile(record);
|
|
70
|
+
href = formatFingerprintedPathname(href, emittedFile.fingerprint);
|
|
71
|
+
}
|
|
68
72
|
if (shouldUseTransformPipeline(hrefOptions.transform)) {
|
|
69
73
|
return appendTransformQuery(href, hrefOptions.transform);
|
|
70
74
|
}
|
|
@@ -138,15 +142,15 @@ export function createFileCompiler(options) {
|
|
|
138
142
|
}
|
|
139
143
|
async function getOrCreateTransformedFile(record, transformQuery) {
|
|
140
144
|
let parsedTransforms = parseRequestTransforms(transformQuery, resolvedOptions.transforms, resolvedOptions.maxRequestTransforms);
|
|
141
|
-
let
|
|
142
|
-
let existing = transformedEmitInFlightByCacheKey.get(
|
|
145
|
+
let transformedCacheKey = getTransformedRecordCacheKey(cacheKey, record, transformQuery);
|
|
146
|
+
let existing = transformedEmitInFlightByCacheKey.get(transformedCacheKey);
|
|
143
147
|
if (existing)
|
|
144
148
|
return existing;
|
|
145
149
|
let promise = (async () => {
|
|
146
|
-
let
|
|
147
|
-
let cachedFile = await getCachedTransformedFile(cacheKey, record.identityPath, sourceFile.fingerprint);
|
|
150
|
+
let cachedFile = await getCachedTransformedFile(transformedCacheKey, record.identityPath);
|
|
148
151
|
if (cachedFile)
|
|
149
152
|
return cachedFile;
|
|
153
|
+
let sourceFile = await getOrCreateSourceFile(record);
|
|
150
154
|
let transformedFile = await applyTransforms(record.identityPath, sourceFile, parsedTransforms);
|
|
151
155
|
if (transformedFile === null) {
|
|
152
156
|
return sourceFile;
|
|
@@ -154,19 +158,18 @@ export function createFileCompiler(options) {
|
|
|
154
158
|
let emittedFile = await createEmittedFile(transformedFile.body, {
|
|
155
159
|
extension: transformedFile.extension,
|
|
156
160
|
filePath: record.identityPath,
|
|
157
|
-
fingerprint: sourceFile.fingerprint,
|
|
158
161
|
});
|
|
159
|
-
rememberTransformedAssetMetadata(
|
|
160
|
-
await setCachedTransformedFile(
|
|
162
|
+
rememberTransformedAssetMetadata(transformedCacheKey, record.identityPath, toEmittedFileMetadata(emittedFile));
|
|
163
|
+
await setCachedTransformedFile(transformedCacheKey, record.identityPath, emittedFile);
|
|
161
164
|
return emittedFile;
|
|
162
165
|
})();
|
|
163
|
-
transformedEmitInFlightByCacheKey.set(
|
|
166
|
+
transformedEmitInFlightByCacheKey.set(transformedCacheKey, promise);
|
|
164
167
|
try {
|
|
165
168
|
return await promise;
|
|
166
169
|
}
|
|
167
170
|
finally {
|
|
168
|
-
if (transformedEmitInFlightByCacheKey.get(
|
|
169
|
-
transformedEmitInFlightByCacheKey.delete(
|
|
171
|
+
if (transformedEmitInFlightByCacheKey.get(transformedCacheKey) === promise) {
|
|
172
|
+
transformedEmitInFlightByCacheKey.delete(transformedCacheKey);
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
}
|
|
@@ -174,12 +177,6 @@ export function createFileCompiler(options) {
|
|
|
174
177
|
return createEmittedFile(body, {
|
|
175
178
|
extension: path.extname(identityPath).toLowerCase(),
|
|
176
179
|
filePath: identityPath,
|
|
177
|
-
fingerprint: resolvedOptions.fingerprintAssets && resolvedOptions.buildId
|
|
178
|
-
? await generateFingerprint({
|
|
179
|
-
buildId: resolvedOptions.buildId,
|
|
180
|
-
content: body,
|
|
181
|
-
})
|
|
182
|
-
: null,
|
|
183
180
|
});
|
|
184
181
|
}
|
|
185
182
|
function createEmittedFileFromMetadata(body, metadata) {
|
|
@@ -253,7 +250,7 @@ export function createFileCompiler(options) {
|
|
|
253
250
|
return null;
|
|
254
251
|
return { body: currentBody, extension: currentExtension };
|
|
255
252
|
}
|
|
256
|
-
async function getCachedTransformedFile(cacheKey, identityPath
|
|
253
|
+
async function getCachedTransformedFile(cacheKey, identityPath) {
|
|
257
254
|
if (!resolvedOptions.cache)
|
|
258
255
|
return null;
|
|
259
256
|
let file = await resolvedOptions.cache.get(cacheKey);
|
|
@@ -264,7 +261,6 @@ export function createFileCompiler(options) {
|
|
|
264
261
|
(await createEmittedFileMetadata(body, {
|
|
265
262
|
extension: path.extname(file.name).toLowerCase(),
|
|
266
263
|
filePath: identityPath,
|
|
267
|
-
fingerprint,
|
|
268
264
|
}));
|
|
269
265
|
rememberTransformedAssetMetadata(cacheKey, identityPath, metadata);
|
|
270
266
|
return {
|
|
@@ -303,14 +299,15 @@ export function createFileCompiler(options) {
|
|
|
303
299
|
transformedCacheKeysByIdentityPath.set(identityPath, cacheKeys);
|
|
304
300
|
}
|
|
305
301
|
async function createEmittedFileMetadata(body, options) {
|
|
302
|
+
let contentHash = await hashContent(body);
|
|
306
303
|
let contentType = detectContentType(`file${options.extension}`) ??
|
|
307
304
|
detectContentType(options.filePath) ??
|
|
308
305
|
'application/octet-stream';
|
|
309
306
|
return {
|
|
310
307
|
contentType,
|
|
311
|
-
etag: `W/"${
|
|
308
|
+
etag: `W/"${contentHash}"`,
|
|
312
309
|
extension: options.extension,
|
|
313
|
-
fingerprint:
|
|
310
|
+
fingerprint: resolvedOptions.fingerprintAssets ? contentHash : null,
|
|
314
311
|
};
|
|
315
312
|
}
|
|
316
313
|
}
|
|
@@ -334,8 +331,8 @@ export function resolveServedFileOrThrow(filePath, args) {
|
|
|
334
331
|
}
|
|
335
332
|
let stableUrlPathname = args.routes.toUrlPathname(identityPath);
|
|
336
333
|
if (!stableUrlPathname) {
|
|
337
|
-
throw createAssetServerCompilationError(`File ${identityPath} is outside all configured
|
|
338
|
-
code: '
|
|
334
|
+
throw createAssetServerCompilationError(`File ${identityPath} is outside all configured mounts.`, {
|
|
335
|
+
code: 'FILE_OUTSIDE_MOUNTS',
|
|
339
336
|
});
|
|
340
337
|
}
|
|
341
338
|
return {
|
|
@@ -361,9 +358,9 @@ export function isServedFilePath(filePath, extensions) {
|
|
|
361
358
|
function getRecordCacheKey(record) {
|
|
362
359
|
return `${record.identityPath}\0${record.invalidationVersion}`;
|
|
363
360
|
}
|
|
364
|
-
function getTransformedRecordCacheKey(
|
|
361
|
+
function getTransformedRecordCacheKey(cacheKey, record, transformQuery) {
|
|
365
362
|
return [
|
|
366
|
-
encodeCacheKeyPart(
|
|
363
|
+
encodeCacheKeyPart(cacheKey),
|
|
367
364
|
encodeCacheKeyPart(record.identityPath),
|
|
368
365
|
String(record.invalidationVersion),
|
|
369
366
|
encodeCacheKeyPart(JSON.stringify(transformQuery ?? [])),
|
|
@@ -73,9 +73,15 @@ export interface AssetServerFilesOptions<transforms extends AssetRequestTransfor
|
|
|
73
73
|
* Optional backing store for cached transformed file outputs.
|
|
74
74
|
*/
|
|
75
75
|
cache?: FileStorage;
|
|
76
|
+
/**
|
|
77
|
+
* Optional namespace for cached transformed file outputs. Use a stable value such as a
|
|
78
|
+
* commit SHA to reuse transformed files across server restarts for the same deployment.
|
|
79
|
+
*/
|
|
80
|
+
cacheKey?: string;
|
|
76
81
|
}
|
|
77
82
|
export interface ResolvedAssetServerFilesOptions {
|
|
78
83
|
cache?: FileStorage;
|
|
84
|
+
cacheKey?: string;
|
|
79
85
|
extensions: readonly string[];
|
|
80
86
|
globalTransforms: readonly ResolvedAssetGlobalTransform[];
|
|
81
87
|
hasTransforms: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/lib/files/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/lib/files/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/files/config.js
CHANGED
|
@@ -96,8 +96,17 @@ export function normalizeFilesOptions(files) {
|
|
|
96
96
|
throw new TypeError('files.cache must implement the FileStorage interface');
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
if (files.cacheKey !== undefined) {
|
|
100
|
+
if (typeof files.cacheKey !== 'string') {
|
|
101
|
+
throw new TypeError('files.cacheKey must be a string');
|
|
102
|
+
}
|
|
103
|
+
if (files.cacheKey.length === 0) {
|
|
104
|
+
throw new TypeError('files.cacheKey must be a non-empty string');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
99
107
|
return {
|
|
100
108
|
cache: files.cache,
|
|
109
|
+
cacheKey: files.cacheKey,
|
|
101
110
|
extensions: normalizedExtensions,
|
|
102
111
|
globalTransforms: normalizedGlobalTransforms,
|
|
103
112
|
hasTransforms: normalizedTransforms.size > 0 || normalizedGlobalTransforms.length > 0,
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export declare function hashContent(content: string | Uint8Array<ArrayBufferLike>): Promise<string>;
|
|
2
|
-
export declare function generateFingerprint(args: {
|
|
3
|
-
buildId: string;
|
|
4
|
-
content: string | Uint8Array<ArrayBufferLike>;
|
|
5
|
-
}): Promise<string>;
|
|
6
2
|
export declare function parseFingerprintSuffix(pathname: string): {
|
|
7
3
|
pathname: string;
|
|
8
4
|
requestedFingerprint: string | null;
|