vitecache 0.2.1 → 0.4.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 +17 -26
- package/dist/browser.d.ts +9 -6
- package/dist/browser.js +28 -159
- package/dist/browser.js.map +1 -1
- package/dist/discover.d.ts +15 -0
- package/dist/discover.js +131 -0
- package/dist/discover.js.map +1 -0
- package/dist/disk.d.ts +2 -9
- package/dist/disk.js +9 -63
- package/dist/disk.js.map +1 -1
- package/dist/entry.d.ts +31 -10
- package/dist/entry.js +11 -94
- package/dist/entry.js.map +1 -1
- package/dist/node.d.ts +9 -6
- package/dist/node.js +101 -6
- package/dist/node.js.map +1 -1
- package/dist/shared.d.ts +17 -0
- package/dist/shared.js +5 -0
- package/dist/shared.js.map +1 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.js +253 -0
- package/dist/vite.js.map +1 -0
- package/package.json +17 -9
- package/skills/vitecache/SKILL.md +46 -37
- package/dist/dependencies.d.ts +0 -15
- package/dist/dependencies.js +0 -131
- package/dist/dependencies.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/key.d.ts +0 -3
- package/dist/key.js +0 -10
- package/dist/key.js.map +0 -1
- package/dist/packages.d.ts +0 -1
- package/dist/packages.js +0 -27
- package/dist/packages.js.map +0 -1
- package/dist/storage.d.ts +0 -7
- package/dist/storage.js +0 -162
- package/dist/storage.js.map +0 -1
- package/dist/types.d.ts +0 -79
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/vite/index.d.ts +0 -8
- package/dist/vite/index.js +0 -220
- package/dist/vite/index.js.map +0 -1
- package/dist/vite/manifest.d.ts +0 -3
- package/dist/vite/manifest.js +0 -34
- package/dist/vite/manifest.js.map +0 -1
- package/dist/vite/resolve.d.ts +0 -8
- package/dist/vite/resolve.js +0 -83
- package/dist/vite/resolve.js.map +0 -1
package/dist/dependencies.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Dependencies, Dependency, Hashes, JsonValue, Paths, ResolvedDependencies, ResolvedDependency, SavedDependencies, SavedDependency } from './types.js';\n\n/** A file or package dependency has no backing file or installation, so its state cannot be checked. */\nexport class MissingDependencyError extends Error {\n override name = 'MissingDependencyError';\n}\n\nexport function record(value: unknown): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError('Expected a named dependency record.');\n }\n const prototype: unknown = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) throw new TypeError('Expected a plain dependency record.');\n if (Object.getOwnPropertySymbols(value).length) throw new TypeError('Dependency names must be strings.');\n return Object.fromEntries(Object.keys(value).sort().map((name) => {\n const property = Object.getOwnPropertyDescriptor(value, name);\n if (!property || !('value' in property)) throw new TypeError('Dependency getters are not supported.');\n const item: unknown = property.value;\n return [name, item];\n }));\n}\n\nfunction path(value: unknown): string {\n if (typeof value !== 'string' || !value || value.includes('\\0')) throw new TypeError('File dependencies require nonempty paths.');\n if (/^(?:[\\\\/]|[a-z]:|[a-z][a-z\\d+.-]*:\\/\\/)/i.test(value)) {\n throw new TypeError('File dependency paths must be relative to the project root.');\n }\n const parts: string[] = [];\n for (const part of value.replace(/\\\\/g, '/').split('/')) {\n if (!part || part === '.') continue;\n if (part !== '..') {\n parts.push(part);\n continue;\n }\n if (!parts.length) throw new TypeError('File dependency paths must stay inside the project root.');\n parts.pop();\n }\n if (!parts.length) throw new TypeError('File dependencies must identify files, not the project root.');\n return parts.join('/');\n}\n\nexport function paths(value: unknown): Paths {\n return Object.freeze(Object.fromEntries(Object.entries(record(value)).map(([name, value]) => {\n if (!name) throw new TypeError('File dependencies require nonempty names.');\n return [name, path(value)];\n })));\n}\n\n/** Validate and snapshot JSON before asynchronous dependency resolution starts. */\nexport function json(value: unknown, ancestors = new Set<object>()): JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value !== 'object') throw new TypeError('Dependency values must contain only JSON values.');\n if (ancestors.has(value)) throw new TypeError('Dependency values must not contain cycles.');\n ancestors.add(value);\n try {\n if (!Array.isArray(value)) return Object.freeze(Object.fromEntries(Object.entries(record(value)).map(([name, item]) => [name, json(item, ancestors)])));\n if (Object.getOwnPropertySymbols(value).length) throw new TypeError('Dependency values must not contain symbol properties.');\n const items: JsonValue[] = [];\n for (let index = 0; index < value.length; index++) {\n const property = Object.getOwnPropertyDescriptor(value, index);\n if (!property || !('value' in property)) throw new TypeError('Dependency values must not contain sparse arrays or getters.');\n const item: unknown = property.value;\n items.push(json(item, ancestors));\n }\n return Object.freeze(items);\n } finally {\n ancestors.delete(value);\n }\n}\n\nexport function dependencies(value: unknown): Dependencies {\n const entries = Object.entries(record(value)).map(([name, value]): [string, Dependency] => {\n if (!name) throw new TypeError('Dependencies require nonempty names.');\n const source = record(value);\n if (Object.keys(source).length !== 1) throw new TypeError('Each dependency must have exactly one value, path, url, or package.');\n if (Object.hasOwn(source, 'value')) return [name, Object.freeze({ value: json(source.value) })];\n if (Object.hasOwn(source, 'path')) return [name, Object.freeze({ path: path(source.path) })];\n if (Object.hasOwn(source, 'url') && typeof source.url === 'string' && source.url && !source.url.includes('\\0')) {\n return [name, Object.freeze({ url: source.url })];\n }\n if (Object.hasOwn(source, 'package') && typeof source.package === 'string' && /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/i.test(source.package)) {\n return [name, Object.freeze({ package: source.package })];\n }\n throw new TypeError('Each dependency must have a JSON value, root-relative path, nonempty URL, or package name without a subpath.');\n });\n return Object.freeze(Object.fromEntries(entries));\n}\n\nexport function resolvedDependencies(value: unknown): ResolvedDependencies {\n const entries = Object.entries(dependencies(value)).map(([name, dependency]): [string, ResolvedDependency] => {\n if (dependency.url !== undefined) throw new TypeError('Expected resolved dependencies, not URLs.');\n return [name, dependency];\n });\n return Object.freeze(Object.fromEntries(entries));\n}\n\n/** Saved dependencies are rechecked later, so they cannot be values: values select the result and belong to the key. */\nexport function savedDependencies(value: unknown): SavedDependencies {\n const entries = Object.entries(dependencies(value)).map(([name, dependency]): [string, SavedDependency] => {\n if (dependency.value !== undefined) throw new TypeError('Saved dependencies cannot be values: values select the result; pass them to the constructor.');\n return [name, dependency];\n });\n return Object.freeze(Object.fromEntries(entries));\n}\n\nexport function hashes(value: unknown): Hashes {\n return Object.freeze(Object.fromEntries(Object.entries(record(value)).map(([name, hash]) => {\n if (!name || typeof hash !== 'string' || !/^[a-f0-9]{64}$/.test(hash)) {\n throw new TypeError('Invalid file dependency hash.');\n }\n return [name, hash];\n })));\n}\n\nexport function equalHashes(first: Hashes, second: Hashes): boolean {\n const names = Object.keys(first);\n return names.length === Object.keys(second).length && names.every((name) => first[name] === second[name]);\n}\n"]}
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { CacheEntry, MissingDependencyError } from './browser.js';\nexport type { CacheEntryOptions, Dependency, Dependencies, JsonValue, SavedDependencies, SavedDependency, SaveOptions } from './types.js';\n"]}
|
package/dist/key.d.ts
DELETED
package/dist/key.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { sha256 } from '@noble/hashes/sha2.js';
|
|
2
|
-
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
3
|
-
import { json } from './dependencies.js';
|
|
4
|
-
export function digest(bytes) {
|
|
5
|
-
return bytesToHex(sha256(bytes));
|
|
6
|
-
}
|
|
7
|
-
export function key(version, dependencies) {
|
|
8
|
-
return digest(new TextEncoder().encode(JSON.stringify(json({ version, dependencies }))));
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=key.js.map
|
package/dist/key.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"key.js","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC,MAAM,UAAU,MAAM,CAAC,KAAiB;IACtC,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,YAAkC;IACrE,OAAO,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3F,CAAC","sourcesContent":["import { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\nimport { json } from './dependencies.js';\nimport type { ResolvedDependencies } from './types.js';\n\nexport function digest(bytes: Uint8Array): string {\n return bytesToHex(sha256(bytes));\n}\n\nexport function key(version: string, dependencies: ResolvedDependencies): string {\n return digest(new TextEncoder().encode(JSON.stringify(json({ version, dependencies }))));\n}\n"]}
|
package/dist/packages.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function packageVersion(root: string, name: string): Promise<string | undefined>;
|
package/dist/packages.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { missingDependency } from './disk.js';
|
|
5
|
-
export async function packageVersion(root, name) {
|
|
6
|
-
const directories = createRequire(join(root, 'package.json')).resolve.paths(name);
|
|
7
|
-
if (directories === null)
|
|
8
|
-
throw new TypeError(`Expected an installed package: ${name}`);
|
|
9
|
-
for (const directory of directories) {
|
|
10
|
-
let contents;
|
|
11
|
-
try {
|
|
12
|
-
contents = await readFile(join(directory, name, 'package.json'), 'utf8');
|
|
13
|
-
}
|
|
14
|
-
catch (error) {
|
|
15
|
-
if (!missingDependency(error))
|
|
16
|
-
throw error;
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
const manifest = JSON.parse(contents);
|
|
20
|
-
if (typeof manifest !== 'object' || manifest === null || !('version' in manifest) || typeof manifest.version !== 'string' || !manifest.version.trim()) {
|
|
21
|
-
throw new TypeError(`Package ${name} must declare a nonempty version in package.json.`);
|
|
22
|
-
}
|
|
23
|
-
return manifest.version;
|
|
24
|
-
}
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=packages.js.map
|
package/dist/packages.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"packages.js","sourceRoot":"","sources":["../src/packages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,IAAY;IAC7D,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClF,IAAI,WAAW,KAAK,IAAI;QAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;IACxF,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QACpC,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YAC3C,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YACtJ,MAAM,IAAI,SAAS,CAAC,WAAW,IAAI,mDAAmD,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { missingDependency } from './disk.js';\n\nexport async function packageVersion(root: string, name: string): Promise<string | undefined> {\n const directories = createRequire(join(root, 'package.json')).resolve.paths(name);\n if (directories === null) throw new TypeError(`Expected an installed package: ${name}`);\n for (const directory of directories) {\n let contents: string;\n try {\n contents = await readFile(join(directory, name, 'package.json'), 'utf8');\n } catch (error) {\n if (!missingDependency(error)) throw error;\n continue;\n }\n const manifest: unknown = JSON.parse(contents);\n if (typeof manifest !== 'object' || manifest === null || !('version' in manifest) || typeof manifest.version !== 'string' || !manifest.version.trim()) {\n throw new TypeError(`Package ${name} must declare a nonempty version in package.json.`);\n }\n return manifest.version;\n }\n return undefined;\n}\n"]}
|
package/dist/storage.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Backend, CacheEntryOptions } from './types.js';
|
|
2
|
-
export declare class ChangedDependenciesError extends Error {
|
|
3
|
-
constructor();
|
|
4
|
-
}
|
|
5
|
-
export declare function createStorage(options: Pick<CacheEntryOptions, 'root' | 'basePath'> & {
|
|
6
|
-
memoizeHashes?: boolean;
|
|
7
|
-
}): Backend;
|
package/dist/storage.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { realpath, stat } from 'node:fs/promises';
|
|
3
|
-
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import * as disk from './disk.js';
|
|
6
|
-
import { equalHashes, hashes, MissingDependencyError, resolvedDependencies, savedDependencies } from './dependencies.js';
|
|
7
|
-
import { packageVersion } from './packages.js';
|
|
8
|
-
function digest(bytes) {
|
|
9
|
-
return createHash('sha256').update(bytes).digest('hex');
|
|
10
|
-
}
|
|
11
|
-
export class ChangedDependenciesError extends Error {
|
|
12
|
-
constructor() {
|
|
13
|
-
super('vitecache dependencies changed during computation.');
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/** A metadata file vitecache wrote; any failure to read it names the file, since no request caused it. */
|
|
17
|
-
function metadata(bytes, file) {
|
|
18
|
-
try {
|
|
19
|
-
return parse(bytes);
|
|
20
|
-
}
|
|
21
|
-
catch (cause) {
|
|
22
|
-
throw new Error(`Invalid vitecache metadata: ${file}`, { cause });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function parse(bytes) {
|
|
26
|
-
const value = JSON.parse(new TextDecoder().decode(bytes));
|
|
27
|
-
if (typeof value !== 'object' || value === null || !('contentHash' in value) || !('dependencies' in value)) {
|
|
28
|
-
throw new Error('Expected contentHash and dependencies.');
|
|
29
|
-
}
|
|
30
|
-
const { contentHash, dependencies } = value;
|
|
31
|
-
if (typeof contentHash !== 'string' || !/^[a-f0-9]{64}$/.test(contentHash))
|
|
32
|
-
throw new Error('Expected a content hash.');
|
|
33
|
-
if (!('saved' in value))
|
|
34
|
-
return { contentHash, dependencies: hashes(dependencies) };
|
|
35
|
-
if (typeof value.saved !== 'object' || value.saved === null)
|
|
36
|
-
throw new Error('Expected saved dependencies.');
|
|
37
|
-
const saved = Object.entries(value.saved).map(([name, item]) => {
|
|
38
|
-
if (typeof item !== 'object' || item === null || !('dependency' in item) || !('hash' in item))
|
|
39
|
-
throw new Error('Expected a saved dependency and its hash.');
|
|
40
|
-
const dependency = resolvedDependencies(savedDependencies({ [name]: item.dependency }))[name];
|
|
41
|
-
const hash = hashes({ [name]: item.hash })[name];
|
|
42
|
-
if (dependency === undefined || hash === undefined)
|
|
43
|
-
throw new Error('Expected a saved dependency and its hash.');
|
|
44
|
-
return [name, { dependency, hash }];
|
|
45
|
-
});
|
|
46
|
-
return { contentHash, dependencies: hashes(dependencies), saved: Object.fromEntries(saved) };
|
|
47
|
-
}
|
|
48
|
-
function matches(current, expected) {
|
|
49
|
-
return current.status === 'available' && equalHashes(current.hashes, expected);
|
|
50
|
-
}
|
|
51
|
-
export function createStorage(options) {
|
|
52
|
-
const { root, directory } = disk.location(options);
|
|
53
|
-
const fileHashes = new Map();
|
|
54
|
-
async function fileHash(path) {
|
|
55
|
-
if (!options.memoizeHashes) {
|
|
56
|
-
const bytes = await disk.load(path);
|
|
57
|
-
return bytes === undefined ? undefined : digest(bytes);
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
const { size, mtimeNs: mtime, ctimeNs: ctime } = await stat(path, { bigint: true });
|
|
61
|
-
const cached = fileHashes.get(path);
|
|
62
|
-
if (cached?.size === size && cached.mtime === mtime && cached.ctime === ctime)
|
|
63
|
-
return await cached.hash;
|
|
64
|
-
const hash = disk.load(path).then((bytes) => bytes === undefined ? undefined : digest(bytes));
|
|
65
|
-
fileHashes.set(path, { size, mtime, ctime, hash });
|
|
66
|
-
const value = await hash;
|
|
67
|
-
if (value === undefined && fileHashes.get(path)?.hash === hash)
|
|
68
|
-
fileHashes.delete(path);
|
|
69
|
-
return value;
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
fileHashes.delete(path);
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async function snapshot(dependencies) {
|
|
77
|
-
const entries = await Promise.all(Object.entries(dependencies).filter(([, dependency]) => !('value' in dependency)).map(async ([name, dependency]) => {
|
|
78
|
-
try {
|
|
79
|
-
if (dependency.package !== undefined) {
|
|
80
|
-
const version = await packageVersion(root, dependency.package);
|
|
81
|
-
return version === undefined ? null : [name, digest(new TextEncoder().encode(version))];
|
|
82
|
-
}
|
|
83
|
-
if (dependency.path === undefined)
|
|
84
|
-
throw new TypeError('Expected a resolved dependency.');
|
|
85
|
-
const hash = await fileHash(resolve(root, dependency.path));
|
|
86
|
-
return hash === undefined ? null : [name, hash];
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (!disk.missingDependency(error))
|
|
90
|
-
throw error;
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
}));
|
|
94
|
-
const present = [];
|
|
95
|
-
for (const entry of entries) {
|
|
96
|
-
if (entry === null)
|
|
97
|
-
return { status: 'missing' };
|
|
98
|
-
present.push(entry);
|
|
99
|
-
}
|
|
100
|
-
return { status: 'available', hashes: Object.fromEntries(present) };
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
async canSave() { return true; },
|
|
104
|
-
async resolve(dependencies) {
|
|
105
|
-
return resolvedDependencies(Object.fromEntries(await Promise.all(Object.entries(dependencies).map(async ([name, dependency]) => {
|
|
106
|
-
if (dependency.url === undefined)
|
|
107
|
-
return [name, dependency];
|
|
108
|
-
const url = new URL(dependency.url);
|
|
109
|
-
if (url.protocol !== 'file:') {
|
|
110
|
-
throw new Error('Node file dependency URLs must use file:. Use a project-root-relative path for Vite-served files.');
|
|
111
|
-
}
|
|
112
|
-
const file = fileURLToPath(url);
|
|
113
|
-
let path = relative(root, file);
|
|
114
|
-
if (path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path)) {
|
|
115
|
-
path = relative(await realpath(root), await realpath(file));
|
|
116
|
-
}
|
|
117
|
-
return [name, { path: path.split(sep).join('/') }];
|
|
118
|
-
}))));
|
|
119
|
-
},
|
|
120
|
-
snapshot,
|
|
121
|
-
async load(key) {
|
|
122
|
-
const file = join(directory, `${key}.json`);
|
|
123
|
-
const record = await disk.load(file);
|
|
124
|
-
if (record === undefined)
|
|
125
|
-
return undefined;
|
|
126
|
-
const { contentHash, dependencies, saved } = metadata(record, file);
|
|
127
|
-
if (saved) {
|
|
128
|
-
const entries = Object.entries(saved);
|
|
129
|
-
const current = await snapshot(Object.fromEntries(entries.map(([name, { dependency }]) => [name, dependency])));
|
|
130
|
-
if (!matches(current, Object.fromEntries(entries.map(([name, { hash }]) => [name, hash]))))
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
const bytes = await disk.load(join(directory, `${key}.bin`));
|
|
134
|
-
if (bytes === undefined || digest(bytes) !== contentHash)
|
|
135
|
-
return undefined;
|
|
136
|
-
return { bytes, hashes: dependencies };
|
|
137
|
-
},
|
|
138
|
-
async save(key, value, validation, expected, saved) {
|
|
139
|
-
if (!matches(await snapshot(validation), expected))
|
|
140
|
-
throw new ChangedDependenciesError();
|
|
141
|
-
const current = await snapshot(saved);
|
|
142
|
-
if (current.status !== 'available')
|
|
143
|
-
throw new MissingDependencyError('Cannot save a cache entry with missing saved dependencies.');
|
|
144
|
-
await disk.ignore(root, directory);
|
|
145
|
-
await disk.save(join(directory, `${key}.bin`), value, async () => {
|
|
146
|
-
if (!matches(await snapshot(validation), expected))
|
|
147
|
-
throw new ChangedDependenciesError();
|
|
148
|
-
});
|
|
149
|
-
const record = { contentHash: digest(value), dependencies: expected };
|
|
150
|
-
const entries = Object.entries(saved).map(([name, dependency]) => {
|
|
151
|
-
const hash = current.hashes[name];
|
|
152
|
-
if (hash === undefined)
|
|
153
|
-
throw new Error(`vitecache did not hash saved dependency ${name}.`);
|
|
154
|
-
return [name, { dependency, hash }];
|
|
155
|
-
});
|
|
156
|
-
if (entries.length)
|
|
157
|
-
record.saved = Object.fromEntries(entries);
|
|
158
|
-
await disk.save(join(directory, `${key}.json`), new TextEncoder().encode(JSON.stringify(record)));
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=storage.js.map
|
package/dist/storage.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,SAAS,MAAM,CAAC,KAAiB;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AASD,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD;QACE,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC9D,CAAC;CACF;AAED,0GAA0G;AAC1G,SAAS,QAAQ,CAAC,KAAiB,EAAE,IAAY;IAC/C,IAAI,CAAC;QACH,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,KAAiB;IAC9B,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,cAAc,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3G,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAC5C,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACxH,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;IACpF,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC7G,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAoB,EAAE,EAAE;QAChF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC5J,MAAM,UAAU,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9F,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,UAAU,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QACjH,OAAO,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAU,CAAC;IAC/C,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED,SAAS,OAAO,CAAC,OAAiB,EAAE,QAAgB;IAClD,OAAO,OAAO,CAAC,MAAM,KAAK,WAAW,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmF;IAC/G,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6F,CAAC;IAExH,KAAK,UAAU,QAAQ,CAAC,IAAY;QAClC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACpF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,MAAM,EAAE,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK;gBAAE,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC;YACxG,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC9F,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;YACzB,IAAI,KAAK,KAAK,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,IAAI;gBAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACxF,OAAO,KAAK,CAAC;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACxB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,YAAkC;QACxD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE;YACnJ,IAAI,CAAC;gBACH,IAAI,UAAU,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;oBACrC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;oBAC/D,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAA4B,CAAC;gBACrH,CAAC;gBACD,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS;oBAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;gBAC1F,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC5D,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAA4B,CAAC;YAC7E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;oBAAE,MAAM,KAAK,CAAC;gBAChD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC,CAAC;QACJ,MAAM,OAAO,GAAuB,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,OAAO;QACL,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC;QAChC,KAAK,CAAC,OAAO,CAAC,YAA0B;YACtC,OAAO,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE;gBAC7H,IAAI,UAAU,CAAC,GAAG,KAAK,SAAS;oBAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBAC7B,MAAM,IAAI,KAAK,CAAC,mGAAmG,CAAC,CAAC;gBACvH,CAAC;gBACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAChC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrE,IAAI,GAAG,QAAQ,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC9D,CAAC;gBACD,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACR,CAAC;QACD,QAAQ;QACR,KAAK,CAAC,IAAI,CAAC,GAAG;YACZ,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC3C,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACpE,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACtC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChH,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;oBAAE,OAAO,SAAS,CAAC;YAC/G,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC;YAC7D,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,WAAW;gBAAE,OAAO,SAAS,CAAC;YAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACzC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK;YAChD,IAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;gBAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;YACzF,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW;gBAAE,MAAM,IAAI,sBAAsB,CAAC,4DAA4D,CAAC,CAAC;YACnI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACnC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;gBAC/D,IAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;oBAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;YAC3F,CAAC,CAAC,CAAC;YACH,MAAM,MAAM,GAAa,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;YAChF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE;gBAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,IAAI,KAAK,SAAS;oBAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,GAAG,CAAC,CAAC;gBAC5F,OAAO,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAU,CAAC;YAC/C,CAAC,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM;gBAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpG,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { realpath, stat } from 'node:fs/promises';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport * as disk from './disk.js';\nimport { equalHashes, hashes, MissingDependencyError, resolvedDependencies, savedDependencies } from './dependencies.js';\nimport { packageVersion } from './packages.js';\nimport type { Backend, CacheEntryOptions, Dependencies, Hashes, ResolvedDependencies, ResolvedDependency, Snapshot } from './types.js';\n\nfunction digest(bytes: Uint8Array): string {\n return createHash('sha256').update(bytes).digest('hex');\n}\n\ninterface Metadata {\n contentHash: string;\n dependencies: Hashes;\n /** Saved dependencies with their hashes at save time; absent when there were none. */\n saved?: Readonly<Record<string, { dependency: ResolvedDependency; hash: string }>>;\n}\n\nexport class ChangedDependenciesError extends Error {\n constructor() {\n super('vitecache dependencies changed during computation.');\n }\n}\n\n/** A metadata file vitecache wrote; any failure to read it names the file, since no request caused it. */\nfunction metadata(bytes: Uint8Array, file: string): Metadata {\n try {\n return parse(bytes);\n } catch (cause) {\n throw new Error(`Invalid vitecache metadata: ${file}`, { cause });\n }\n}\n\nfunction parse(bytes: Uint8Array): Metadata {\n const value: unknown = JSON.parse(new TextDecoder().decode(bytes));\n if (typeof value !== 'object' || value === null || !('contentHash' in value) || !('dependencies' in value)) {\n throw new Error('Expected contentHash and dependencies.');\n }\n const { contentHash, dependencies } = value;\n if (typeof contentHash !== 'string' || !/^[a-f0-9]{64}$/.test(contentHash)) throw new Error('Expected a content hash.');\n if (!('saved' in value)) return { contentHash, dependencies: hashes(dependencies) };\n if (typeof value.saved !== 'object' || value.saved === null) throw new Error('Expected saved dependencies.');\n const saved = Object.entries(value.saved).map(([name, item]: [string, unknown]) => {\n if (typeof item !== 'object' || item === null || !('dependency' in item) || !('hash' in item)) throw new Error('Expected a saved dependency and its hash.');\n const dependency = resolvedDependencies(savedDependencies({ [name]: item.dependency }))[name];\n const hash = hashes({ [name]: item.hash })[name];\n if (dependency === undefined || hash === undefined) throw new Error('Expected a saved dependency and its hash.');\n return [name, { dependency, hash }] as const;\n });\n return { contentHash, dependencies: hashes(dependencies), saved: Object.fromEntries(saved) };\n}\n\nfunction matches(current: Snapshot, expected: Hashes): boolean {\n return current.status === 'available' && equalHashes(current.hashes, expected);\n}\n\nexport function createStorage(options: Pick<CacheEntryOptions, 'root' | 'basePath'> & { memoizeHashes?: boolean }): Backend {\n const { root, directory } = disk.location(options);\n const fileHashes = new Map<string, { size: bigint; mtime: bigint; ctime: bigint; hash: Promise<string | undefined> }>();\n\n async function fileHash(path: string): Promise<string | undefined> {\n if (!options.memoizeHashes) {\n const bytes = await disk.load(path);\n return bytes === undefined ? undefined : digest(bytes);\n }\n try {\n const { size, mtimeNs: mtime, ctimeNs: ctime } = await stat(path, { bigint: true });\n const cached = fileHashes.get(path);\n if (cached?.size === size && cached.mtime === mtime && cached.ctime === ctime) return await cached.hash;\n const hash = disk.load(path).then((bytes) => bytes === undefined ? undefined : digest(bytes));\n fileHashes.set(path, { size, mtime, ctime, hash });\n const value = await hash;\n if (value === undefined && fileHashes.get(path)?.hash === hash) fileHashes.delete(path);\n return value;\n } catch (error) {\n fileHashes.delete(path);\n throw error;\n }\n }\n\n async function snapshot(dependencies: ResolvedDependencies): Promise<Snapshot> {\n const entries = await Promise.all(Object.entries(dependencies).filter(([, dependency]) => !('value' in dependency)).map(async ([name, dependency]) => {\n try {\n if (dependency.package !== undefined) {\n const version = await packageVersion(root, dependency.package);\n return version === undefined ? null : [name, digest(new TextEncoder().encode(version))] satisfies [string, string];\n }\n if (dependency.path === undefined) throw new TypeError('Expected a resolved dependency.');\n const hash = await fileHash(resolve(root, dependency.path));\n return hash === undefined ? null : [name, hash] satisfies [string, string];\n } catch (error) {\n if (!disk.missingDependency(error)) throw error;\n return null;\n }\n }));\n const present: [string, string][] = [];\n for (const entry of entries) {\n if (entry === null) return { status: 'missing' };\n present.push(entry);\n }\n return { status: 'available', hashes: Object.fromEntries(present) };\n }\n\n return {\n async canSave() { return true; },\n async resolve(dependencies: Dependencies) {\n return resolvedDependencies(Object.fromEntries(await Promise.all(Object.entries(dependencies).map(async ([name, dependency]) => {\n if (dependency.url === undefined) return [name, dependency];\n const url = new URL(dependency.url);\n if (url.protocol !== 'file:') {\n throw new Error('Node file dependency URLs must use file:. Use a project-root-relative path for Vite-served files.');\n }\n const file = fileURLToPath(url);\n let path = relative(root, file);\n if (path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path)) {\n path = relative(await realpath(root), await realpath(file));\n }\n return [name, { path: path.split(sep).join('/') }];\n }))));\n },\n snapshot,\n async load(key) {\n const file = join(directory, `${key}.json`);\n const record = await disk.load(file);\n if (record === undefined) return undefined;\n const { contentHash, dependencies, saved } = metadata(record, file);\n if (saved) {\n const entries = Object.entries(saved);\n const current = await snapshot(Object.fromEntries(entries.map(([name, { dependency }]) => [name, dependency])));\n if (!matches(current, Object.fromEntries(entries.map(([name, { hash }]) => [name, hash])))) return undefined;\n }\n const bytes = await disk.load(join(directory, `${key}.bin`));\n if (bytes === undefined || digest(bytes) !== contentHash) return undefined;\n return { bytes, hashes: dependencies };\n },\n async save(key, value, validation, expected, saved) {\n if (!matches(await snapshot(validation), expected)) throw new ChangedDependenciesError();\n const current = await snapshot(saved);\n if (current.status !== 'available') throw new MissingDependencyError('Cannot save a cache entry with missing saved dependencies.');\n await disk.ignore(root, directory);\n await disk.save(join(directory, `${key}.bin`), value, async () => {\n if (!matches(await snapshot(validation), expected)) throw new ChangedDependenciesError();\n });\n const record: Metadata = { contentHash: digest(value), dependencies: expected };\n const entries = Object.entries(saved).map(([name, dependency]) => {\n const hash = current.hashes[name];\n if (hash === undefined) throw new Error(`vitecache did not hash saved dependency ${name}.`);\n return [name, { dependency, hash }] as const;\n });\n if (entries.length) record.saved = Object.fromEntries(entries);\n await disk.save(join(directory, `${key}.json`), new TextEncoder().encode(JSON.stringify(record)));\n },\n };\n}\n"]}
|
package/dist/types.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
2
|
-
readonly [key: string]: JsonValue;
|
|
3
|
-
};
|
|
4
|
-
/** Exactly one source per dependency. Names and descriptors participate in cache identity. */
|
|
5
|
-
export type Dependency = {
|
|
6
|
-
readonly value: JsonValue;
|
|
7
|
-
readonly path?: never;
|
|
8
|
-
readonly url?: never;
|
|
9
|
-
readonly package?: never;
|
|
10
|
-
} | {
|
|
11
|
-
readonly path: string;
|
|
12
|
-
readonly value?: never;
|
|
13
|
-
readonly url?: never;
|
|
14
|
-
readonly package?: never;
|
|
15
|
-
} | {
|
|
16
|
-
readonly url: string;
|
|
17
|
-
readonly value?: never;
|
|
18
|
-
readonly path?: never;
|
|
19
|
-
readonly package?: never;
|
|
20
|
-
} | {
|
|
21
|
-
readonly package: string;
|
|
22
|
-
readonly value?: never;
|
|
23
|
-
readonly path?: never;
|
|
24
|
-
readonly url?: never;
|
|
25
|
-
};
|
|
26
|
-
export type Dependencies = Readonly<Record<string, Dependency>>;
|
|
27
|
-
export type ResolvedDependency = Exclude<Dependency, {
|
|
28
|
-
readonly url: string;
|
|
29
|
-
}>;
|
|
30
|
-
/** A file, URL, or package dependency: one whose current state can be checked again later. */
|
|
31
|
-
export type SavedDependency = Exclude<Dependency, {
|
|
32
|
-
readonly value: JsonValue;
|
|
33
|
-
}>;
|
|
34
|
-
export type SavedDependencies = Readonly<Record<string, SavedDependency>>;
|
|
35
|
-
export type ResolvedDependencies = Readonly<Record<string, ResolvedDependency>>;
|
|
36
|
-
export type Paths = Readonly<Record<string, string>>;
|
|
37
|
-
/** Dependency names mapped to file-content or installed-package-version hashes. */
|
|
38
|
-
export type Hashes = Readonly<Record<string, string>>;
|
|
39
|
-
/** Current dependency hashes, a missing dependency, or unavailable browser validation. */
|
|
40
|
-
export type Snapshot = {
|
|
41
|
-
readonly status: 'available';
|
|
42
|
-
readonly hashes: Hashes;
|
|
43
|
-
} | {
|
|
44
|
-
readonly status: 'missing';
|
|
45
|
-
} | {
|
|
46
|
-
readonly status: 'unavailable';
|
|
47
|
-
};
|
|
48
|
-
export interface CacheEntryOptions {
|
|
49
|
-
/** Identifies the computation and its implementation version, for example "simplify@2". */
|
|
50
|
-
version: string;
|
|
51
|
-
/** Named dependencies sorted by name. JSON values affect the key; file contents and installed package versions are validated in Node or through the Vite plugin. Paths are always project-root-relative. URLs resolve to those paths through Vite, or from local file: URLs in Node. Packages track only the declared package's installed version, without importing it. */
|
|
52
|
-
dependencies?: Dependencies;
|
|
53
|
-
/** Disk directory in Node (default public/_vitecache); URL prefix in browsers (default /_vitecache/). Excluded from the key. */
|
|
54
|
-
basePath?: string;
|
|
55
|
-
/** Node project root, default process.cwd(). Browser dependencies resolve against the Vite root. Excluded from the key. */
|
|
56
|
-
root?: string;
|
|
57
|
-
}
|
|
58
|
-
export interface SaveOptions {
|
|
59
|
-
/**
|
|
60
|
-
* What the result was built from, when known only after computing it. They do not affect the key, so a save with
|
|
61
|
-
* different saved dependencies replaces the same entry. Rechecked by every load() where file contents are validated;
|
|
62
|
-
* a changed or missing one is a miss. Hashed when save() runs, so one that changed after the computation read it goes
|
|
63
|
-
* unnoticed until it changes again. One without a backing file makes save() throw MissingDependencyError. Values select
|
|
64
|
-
* the result, so they belong in the constructor.
|
|
65
|
-
*/
|
|
66
|
-
dependencies?: SavedDependencies;
|
|
67
|
-
}
|
|
68
|
-
export interface Stored {
|
|
69
|
-
bytes: Uint8Array;
|
|
70
|
-
hashes?: Hashes;
|
|
71
|
-
}
|
|
72
|
-
export interface Backend {
|
|
73
|
-
canSave(): Promise<boolean>;
|
|
74
|
-
resolve(dependencies: Dependencies): Promise<ResolvedDependencies>;
|
|
75
|
-
snapshot(dependencies: ResolvedDependencies): Promise<Snapshot>;
|
|
76
|
-
load(key: string, validate: boolean): Promise<Stored | undefined>;
|
|
77
|
-
/** `validation` must still match `expected`; `saved` is hashed now and rechecked on load. Neither holds values. */
|
|
78
|
-
save(key: string, value: Uint8Array, validation: ResolvedDependencies, expected: Hashes, saved: ResolvedDependencies): Promise<void>;
|
|
79
|
-
}
|
package/dist/types.js
DELETED
package/dist/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type JsonValue = null | boolean | number | string | readonly JsonValue[] | { readonly [key: string]: JsonValue };\n\n/** Exactly one source per dependency. Names and descriptors participate in cache identity. */\nexport type Dependency =\n | { readonly value: JsonValue; readonly path?: never; readonly url?: never; readonly package?: never }\n | { readonly path: string; readonly value?: never; readonly url?: never; readonly package?: never }\n | { readonly url: string; readonly value?: never; readonly path?: never; readonly package?: never }\n | { readonly package: string; readonly value?: never; readonly path?: never; readonly url?: never };\nexport type Dependencies = Readonly<Record<string, Dependency>>;\nexport type ResolvedDependency = Exclude<Dependency, { readonly url: string }>;\n/** A file, URL, or package dependency: one whose current state can be checked again later. */\nexport type SavedDependency = Exclude<Dependency, { readonly value: JsonValue }>;\nexport type SavedDependencies = Readonly<Record<string, SavedDependency>>;\nexport type ResolvedDependencies = Readonly<Record<string, ResolvedDependency>>;\nexport type Paths = Readonly<Record<string, string>>;\n/** Dependency names mapped to file-content or installed-package-version hashes. */\nexport type Hashes = Readonly<Record<string, string>>;\n/** Current dependency hashes, a missing dependency, or unavailable browser validation. */\nexport type Snapshot =\n | { readonly status: 'available'; readonly hashes: Hashes }\n | { readonly status: 'missing' }\n | { readonly status: 'unavailable' };\n\nexport interface CacheEntryOptions {\n /** Identifies the computation and its implementation version, for example \"simplify@2\". */\n version: string;\n /** Named dependencies sorted by name. JSON values affect the key; file contents and installed package versions are validated in Node or through the Vite plugin. Paths are always project-root-relative. URLs resolve to those paths through Vite, or from local file: URLs in Node. Packages track only the declared package's installed version, without importing it. */\n dependencies?: Dependencies;\n /** Disk directory in Node (default public/_vitecache); URL prefix in browsers (default /_vitecache/). Excluded from the key. */\n basePath?: string;\n /** Node project root, default process.cwd(). Browser dependencies resolve against the Vite root. Excluded from the key. */\n root?: string;\n}\n\nexport interface SaveOptions {\n /**\n * What the result was built from, when known only after computing it. They do not affect the key, so a save with\n * different saved dependencies replaces the same entry. Rechecked by every load() where file contents are validated;\n * a changed or missing one is a miss. Hashed when save() runs, so one that changed after the computation read it goes\n * unnoticed until it changes again. One without a backing file makes save() throw MissingDependencyError. Values select\n * the result, so they belong in the constructor.\n */\n dependencies?: SavedDependencies;\n}\n\nexport interface Stored {\n bytes: Uint8Array;\n hashes?: Hashes;\n}\n\nexport interface Backend {\n canSave(): Promise<boolean>;\n resolve(dependencies: Dependencies): Promise<ResolvedDependencies>;\n snapshot(dependencies: ResolvedDependencies): Promise<Snapshot>;\n load(key: string, validate: boolean): Promise<Stored | undefined>;\n /** `validation` must still match `expected`; `saved` is hashed now and rechecked on load. Neither holds values. */\n save(key: string, value: Uint8Array, validation: ResolvedDependencies, expected: Hashes, saved: ResolvedDependencies): Promise<void>;\n}\n"]}
|
package/dist/vite/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from 'vite';
|
|
2
|
-
export interface VitecacheOptions {
|
|
3
|
-
/** Cache directory relative to the Vite project root; must be inside publicDir. */
|
|
4
|
-
basePath?: string;
|
|
5
|
-
}
|
|
6
|
-
/** Persist and validate entries in development; preserve asset URL mappings in production builds. */
|
|
7
|
-
export declare function vitecache(options?: VitecacheOptions): Plugin;
|
|
8
|
-
export default vitecache;
|
package/dist/vite/index.js
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { relative, resolve, sep } from 'node:path';
|
|
2
|
-
import * as disk from '../disk.js';
|
|
3
|
-
import { ChangedDependenciesError, createStorage } from '../storage.js';
|
|
4
|
-
import { dependencies, hashes, MissingDependencyError, resolvedDependencies, savedDependencies } from '../dependencies.js';
|
|
5
|
-
import { confine, inside, OutsideRootError, resolveDependencies } from './resolve.js';
|
|
6
|
-
import { assetUrl, publicPaths } from './manifest.js';
|
|
7
|
-
class RequestError extends Error {
|
|
8
|
-
status;
|
|
9
|
-
constructor(status, message) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.status = status;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function status(error) {
|
|
15
|
-
if (error instanceof RequestError)
|
|
16
|
-
return error.status;
|
|
17
|
-
if (error instanceof ChangedDependenciesError)
|
|
18
|
-
return 409;
|
|
19
|
-
if (error instanceof MissingDependencyError)
|
|
20
|
-
return 404;
|
|
21
|
-
if (error instanceof OutsideRootError)
|
|
22
|
-
return 403;
|
|
23
|
-
if (error instanceof TypeError || error instanceof URIError)
|
|
24
|
-
return 400;
|
|
25
|
-
return 500;
|
|
26
|
-
}
|
|
27
|
-
function allowed(request) {
|
|
28
|
-
if (request.headers['sec-fetch-site'] === 'cross-site')
|
|
29
|
-
return false;
|
|
30
|
-
const origin = request.headers.origin;
|
|
31
|
-
if (!origin)
|
|
32
|
-
return true;
|
|
33
|
-
try {
|
|
34
|
-
const url = new URL(origin);
|
|
35
|
-
return (url.protocol === 'http:' || url.protocol === 'https:') && url.host === request.headers.host;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async function body(request) {
|
|
42
|
-
const chunks = [];
|
|
43
|
-
for await (const value of request) {
|
|
44
|
-
const chunk = value;
|
|
45
|
-
if (!Buffer.isBuffer(chunk))
|
|
46
|
-
throw new RequestError(400, 'Expected a binary request body');
|
|
47
|
-
chunks.push(chunk);
|
|
48
|
-
}
|
|
49
|
-
return Buffer.concat(chunks);
|
|
50
|
-
}
|
|
51
|
-
function parse(value) {
|
|
52
|
-
try {
|
|
53
|
-
return JSON.parse(value);
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
throw new RequestError(400, 'Expected valid JSON');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function validate(value, parser) {
|
|
60
|
-
try {
|
|
61
|
-
return parser(value);
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
if (!(error instanceof TypeError))
|
|
65
|
-
throw error;
|
|
66
|
-
throw new RequestError(400, error.message);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/** A save body: a 4-byte big-endian metadata length, that much JSON metadata, then the cached bytes. */
|
|
70
|
-
function upload(bytes) {
|
|
71
|
-
if (bytes.byteLength < 4)
|
|
72
|
-
throw new RequestError(400, 'Expected a metadata length');
|
|
73
|
-
const end = 4 + new DataView(bytes.buffer, bytes.byteOffset, 4).getUint32(0);
|
|
74
|
-
if (end > bytes.byteLength)
|
|
75
|
-
throw new RequestError(400, 'Truncated save metadata');
|
|
76
|
-
const metadata = parse(new TextDecoder().decode(bytes.subarray(4, end)));
|
|
77
|
-
if (typeof metadata !== 'object' || metadata === null || !('dependencies' in metadata) || !('hashes' in metadata) || !('saved' in metadata)) {
|
|
78
|
-
throw new RequestError(400, 'Expected dependencies, hashes, and saved dependencies');
|
|
79
|
-
}
|
|
80
|
-
return { metadata, value: bytes.subarray(end) };
|
|
81
|
-
}
|
|
82
|
-
function json(response, value) {
|
|
83
|
-
response.setHeader('Content-Type', 'application/json');
|
|
84
|
-
response.end(JSON.stringify(value));
|
|
85
|
-
}
|
|
86
|
-
async function respond(request, response, name, storage, server) {
|
|
87
|
-
const root = server.config.root;
|
|
88
|
-
response.setHeader('Cache-Control', 'no-store');
|
|
89
|
-
if (name === '__vitecache' && request.method === 'GET') {
|
|
90
|
-
json(response, { vitecache: 1 });
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if ((name === '__vitecache/snapshot' || name === '__vitecache/resolve') && request.method === 'POST') {
|
|
94
|
-
if (!allowed(request))
|
|
95
|
-
throw new RequestError(403, 'Cross-origin requests are forbidden');
|
|
96
|
-
const value = parse(new TextDecoder().decode(await body(request)));
|
|
97
|
-
if (typeof value !== 'object' || value === null || !('dependencies' in value)) {
|
|
98
|
-
throw new RequestError(400, 'Expected dependencies');
|
|
99
|
-
}
|
|
100
|
-
if (name === '__vitecache/resolve') {
|
|
101
|
-
const deps = validate(value.dependencies, dependencies);
|
|
102
|
-
const origin = `${server.config.server.https ? 'https' : 'http'}://${request.headers.host}`;
|
|
103
|
-
json(response, { dependencies: await resolveDependencies(server, deps, origin) });
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const deps = validate(value.dependencies, resolvedDependencies);
|
|
107
|
-
await confine(root, deps);
|
|
108
|
-
json(response, await storage.snapshot(deps));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
if (!/^[a-f0-9]{64}\.bin$/.test(name)) {
|
|
112
|
-
response.statusCode = 404;
|
|
113
|
-
response.end();
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
const key = name.slice(0, -4);
|
|
117
|
-
if (request.method === 'PUT') {
|
|
118
|
-
if (!allowed(request))
|
|
119
|
-
throw new RequestError(403, 'Cross-origin requests are forbidden');
|
|
120
|
-
const { metadata, value } = upload(await body(request));
|
|
121
|
-
const validation = validate(metadata.dependencies, resolvedDependencies);
|
|
122
|
-
const expected = validate(metadata.hashes, hashes);
|
|
123
|
-
const saved = validate(metadata.saved, (input) => resolvedDependencies(savedDependencies(input)));
|
|
124
|
-
await confine(root, validation);
|
|
125
|
-
await confine(root, saved);
|
|
126
|
-
await storage.save(key, value, validation, expected, saved);
|
|
127
|
-
response.statusCode = 204;
|
|
128
|
-
response.end();
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
132
|
-
response.statusCode = 405;
|
|
133
|
-
response.setHeader('Allow', 'GET, HEAD, PUT');
|
|
134
|
-
response.end();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const stored = await storage.load(key, true);
|
|
138
|
-
if (stored === undefined) {
|
|
139
|
-
// Browsers log every 404 fetch as an error, and a miss is an expected answer.
|
|
140
|
-
response.statusCode = 204;
|
|
141
|
-
response.end();
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
response.setHeader('Content-Type', 'application/octet-stream');
|
|
145
|
-
response.setHeader('Content-Length', stored.bytes.byteLength);
|
|
146
|
-
response.setHeader('X-Vitecache-Dependencies', encodeURIComponent(JSON.stringify(stored.hashes)));
|
|
147
|
-
response.end(request.method === 'HEAD' ? undefined : stored.bytes);
|
|
148
|
-
}
|
|
149
|
-
/** Persist and validate entries in development; preserve asset URL mappings in production builds. */
|
|
150
|
-
export function vitecache(options = {}) {
|
|
151
|
-
let resolved;
|
|
152
|
-
return {
|
|
153
|
-
name: 'vitecache',
|
|
154
|
-
enforce: 'post',
|
|
155
|
-
async configResolved(config) {
|
|
156
|
-
if (!config.publicDir)
|
|
157
|
-
throw new Error('vitecache requires Vite publicDir');
|
|
158
|
-
const { root, directory } = disk.location({ root: config.root, ...options });
|
|
159
|
-
const path = relative(config.publicDir, directory);
|
|
160
|
-
if (!path || !inside(config.publicDir, directory)) {
|
|
161
|
-
throw new Error('vitecache basePath must be a directory inside Vite publicDir');
|
|
162
|
-
}
|
|
163
|
-
const base = new URL(config.base, 'http://vitecache').pathname.replace(/\/$/, '');
|
|
164
|
-
resolved = {
|
|
165
|
-
backend: createStorage({ root, ...options, memoizeHashes: config.command === 'serve' }),
|
|
166
|
-
root,
|
|
167
|
-
directory,
|
|
168
|
-
config,
|
|
169
|
-
cachePath: path.split(sep).join('/'),
|
|
170
|
-
prefix: `${base}/${path.split(sep).map(encodeURIComponent).join('/')}/`,
|
|
171
|
-
};
|
|
172
|
-
await disk.ignore(root, directory);
|
|
173
|
-
},
|
|
174
|
-
async generateBundle(_options, bundle) {
|
|
175
|
-
const storage = resolved;
|
|
176
|
-
if (!storage)
|
|
177
|
-
throw new Error('vitecache configuration was not resolved');
|
|
178
|
-
const paths = new Map(Object.entries(await publicPaths(storage.config, storage.directory)));
|
|
179
|
-
for (const asset of Object.values(bundle)) {
|
|
180
|
-
if (asset.type !== 'asset')
|
|
181
|
-
continue;
|
|
182
|
-
const originals = [...new Set(asset.originalFileNames)];
|
|
183
|
-
if (originals.length !== 1)
|
|
184
|
-
continue;
|
|
185
|
-
const original = originals[0];
|
|
186
|
-
if (!original)
|
|
187
|
-
continue;
|
|
188
|
-
const file = relative(storage.root, resolve(storage.root, original));
|
|
189
|
-
if (!inside(storage.root, resolve(storage.root, original)))
|
|
190
|
-
continue;
|
|
191
|
-
paths.set(assetUrl(asset.fileName), file.split(sep).join('/'));
|
|
192
|
-
}
|
|
193
|
-
const manifest = { paths: Object.fromEntries(paths), root: '../'.repeat(storage.cachePath.split('/').length + 1) };
|
|
194
|
-
this.emitFile({ type: 'asset', fileName: `${storage.cachePath}/__vitecache/paths.json`, source: JSON.stringify(manifest) });
|
|
195
|
-
},
|
|
196
|
-
configureServer(server) {
|
|
197
|
-
const storage = resolved;
|
|
198
|
-
if (!storage)
|
|
199
|
-
throw new Error('vitecache configuration was not resolved');
|
|
200
|
-
server.middlewares.use((request, response, next) => {
|
|
201
|
-
const path = new URL(request.url ?? '/', 'http://vitecache').pathname;
|
|
202
|
-
if (!path.startsWith(storage.prefix)) {
|
|
203
|
-
next();
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
void respond(request, response, path.slice(storage.prefix.length), storage.backend, server).catch((error) => {
|
|
207
|
-
response.statusCode = status(error);
|
|
208
|
-
if (error instanceof MissingDependencyError) {
|
|
209
|
-
json(response, { error: 'missing-dependency', message: error.message });
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
response.setHeader('Content-Type', 'text/plain');
|
|
213
|
-
response.end(error instanceof Error ? error.message : 'vitecache request failed');
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
export default vitecache;
|
|
220
|
-
//# sourceMappingURL=index.js.map
|