vitecache 0.0.0-stage → 0.1.1

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/dist/key.js ADDED
@@ -0,0 +1,10 @@
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
@@ -0,0 +1 @@
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/node.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { Entry } from './entry.js';
2
+ import type { CacheEntryOptions } from './types.js';
3
+ export type { CacheEntryOptions, Dependencies, Dependency, JsonValue } from './types.js';
4
+ /** A persistent binary computation result with content-based dependency validation. */
5
+ export declare class CacheEntry extends Entry {
6
+ constructor(options: CacheEntryOptions);
7
+ }
package/dist/node.js ADDED
@@ -0,0 +1,9 @@
1
+ import { Entry } from './entry.js';
2
+ import { createStorage } from './storage.js';
3
+ /** A persistent binary computation result with content-based dependency validation. */
4
+ export class CacheEntry extends Entry {
5
+ constructor(options) {
6
+ super(options, createStorage(options));
7
+ }
8
+ }
9
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,uFAAuF;AACvF,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAA0B;QACpC,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { Entry } from './entry.js';\nimport { createStorage } from './storage.js';\nimport type { CacheEntryOptions } from './types.js';\nexport type { CacheEntryOptions, Dependencies, Dependency, JsonValue } from './types.js';\n\n/** A persistent binary computation result with content-based dependency validation. */\nexport class CacheEntry extends Entry {\n constructor(options: CacheEntryOptions) {\n super(options, createStorage(options));\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function packageVersion(root: string, name: string): Promise<string | undefined>;
@@ -0,0 +1,27 @@
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
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,5 @@
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'>): Backend;
@@ -0,0 +1,97 @@
1
+ import { realpath } from 'node:fs/promises';
2
+ import { isAbsolute, join, relative, resolve, sep } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import * as disk from './disk.js';
5
+ import { equalHashes, hashes, resolvedDependencies } from './dependencies.js';
6
+ import { packageVersion } from './packages.js';
7
+ import { digest } from './key.js';
8
+ export class ChangedDependenciesError extends Error {
9
+ constructor() {
10
+ super('vitecache dependencies changed during computation.');
11
+ }
12
+ }
13
+ function metadata(bytes) {
14
+ const value = JSON.parse(new TextDecoder().decode(bytes));
15
+ if (typeof value !== 'object' || value === null || !('contentHash' in value) || !('dependencies' in value)) {
16
+ throw new Error('Invalid vitecache metadata.');
17
+ }
18
+ const { contentHash, dependencies } = value;
19
+ if (typeof contentHash !== 'string' || !/^[a-f0-9]{64}$/.test(contentHash)) {
20
+ throw new Error('Invalid vitecache metadata.');
21
+ }
22
+ return { contentHash, dependencies: hashes(dependencies) };
23
+ }
24
+ function matches(current, expected) {
25
+ return current !== null && equalHashes(current, expected);
26
+ }
27
+ export function createStorage(options) {
28
+ const { root, directory } = disk.location(options);
29
+ async function snapshot(dependencies) {
30
+ const entries = await Promise.all(Object.entries(dependencies).filter(([, dependency]) => !('value' in dependency)).map(async ([name, dependency]) => {
31
+ try {
32
+ if (dependency.package !== undefined) {
33
+ const version = await packageVersion(root, dependency.package);
34
+ return version === undefined ? null : [name, digest(new TextEncoder().encode(version))];
35
+ }
36
+ if (dependency.path === undefined)
37
+ throw new TypeError('Expected a resolved dependency.');
38
+ const bytes = await disk.load(resolve(root, dependency.path));
39
+ return bytes === undefined ? null : [name, digest(bytes)];
40
+ }
41
+ catch (error) {
42
+ if (!disk.missingDependency(error))
43
+ throw error;
44
+ return null;
45
+ }
46
+ }));
47
+ const present = [];
48
+ for (const entry of entries) {
49
+ if (entry === null)
50
+ return null;
51
+ present.push(entry);
52
+ }
53
+ return Object.fromEntries(present);
54
+ }
55
+ return {
56
+ async canSave() { return true; },
57
+ async resolve(files) {
58
+ return resolvedDependencies(Object.fromEntries(await Promise.all(Object.entries(files).map(async ([name, dependency]) => {
59
+ if (dependency.url === undefined)
60
+ return [name, dependency];
61
+ const url = new URL(dependency.url);
62
+ if (url.protocol !== 'file:') {
63
+ throw new Error('Node file dependency URLs must use file:. Use a project-root-relative path for Vite-served files.');
64
+ }
65
+ const file = fileURLToPath(url);
66
+ let path = relative(root, file);
67
+ if (path === '..' || path.startsWith(`..${sep}`) || isAbsolute(path)) {
68
+ path = relative(await realpath(root), await realpath(file));
69
+ }
70
+ return [name, { path: path.split(sep).join('/') }];
71
+ }))));
72
+ },
73
+ snapshot,
74
+ async load(key) {
75
+ const record = await disk.load(join(directory, `${key}.json`));
76
+ if (record === undefined)
77
+ return undefined;
78
+ const { contentHash, dependencies } = metadata(record);
79
+ const bytes = await disk.load(join(directory, `${key}.bin`));
80
+ if (bytes === undefined || digest(bytes) !== contentHash)
81
+ return undefined;
82
+ return { bytes, hashes: dependencies };
83
+ },
84
+ async save(key, value, files, expected) {
85
+ if (!matches(await snapshot(files), expected))
86
+ throw new ChangedDependenciesError();
87
+ await disk.ignore(root, directory);
88
+ await disk.save(join(directory, `${key}.bin`), value, async () => {
89
+ if (!matches(await snapshot(files), expected))
90
+ throw new ChangedDependenciesError();
91
+ });
92
+ const record = { contentHash: digest(value), dependencies: expected };
93
+ await disk.save(join(directory, `${key}.json`), new TextEncoder().encode(JSON.stringify(record)));
94
+ },
95
+ };
96
+ }
97
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpath } 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, resolvedDependencies } from './dependencies.js';\nimport { packageVersion } from './packages.js';\nimport { digest } from './key.js';\nimport type { Backend, CacheEntryOptions, Dependencies, Hashes, ResolvedDependencies } from './types.js';\n\ninterface Metadata {\n contentHash: string;\n dependencies: Hashes;\n}\n\nexport class ChangedDependenciesError extends Error {\n constructor() {\n super('vitecache dependencies changed during computation.');\n }\n}\n\nfunction metadata(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('Invalid vitecache metadata.');\n }\n const { contentHash, dependencies } = value;\n if (typeof contentHash !== 'string' || !/^[a-f0-9]{64}$/.test(contentHash)) {\n throw new Error('Invalid vitecache metadata.');\n }\n return { contentHash, dependencies: hashes(dependencies) };\n}\n\nfunction matches(current: Hashes | null, expected: Hashes): boolean {\n return current !== null && equalHashes(current, expected);\n}\n\nexport function createStorage(options: Pick<CacheEntryOptions, 'root' | 'basePath'>): Backend {\n const { root, directory } = disk.location(options);\n\n async function snapshot(dependencies: ResolvedDependencies): Promise<Hashes | null> {\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 bytes = await disk.load(resolve(root, dependency.path));\n return bytes === undefined ? null : [name, digest(bytes)] 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 null;\n present.push(entry);\n }\n return Object.fromEntries(present);\n }\n\n return {\n async canSave() { return true; },\n async resolve(files: Dependencies) {\n return resolvedDependencies(Object.fromEntries(await Promise.all(Object.entries(files).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 record = await disk.load(join(directory, `${key}.json`));\n if (record === undefined) return undefined;\n const { contentHash, dependencies } = metadata(record);\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, files, expected) {\n if (!matches(await snapshot(files), expected)) throw new ChangedDependenciesError();\n await disk.ignore(root, directory);\n await disk.save(join(directory, `${key}.bin`), value, async () => {\n if (!matches(await snapshot(files), expected)) throw new ChangedDependenciesError();\n });\n const record: Metadata = { contentHash: digest(value), dependencies: expected };\n await disk.save(join(directory, `${key}.json`), new TextEncoder().encode(JSON.stringify(record)));\n },\n };\n}\n"]}
@@ -0,0 +1,54 @@
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
+ export type ResolvedDependencies = Readonly<Record<string, ResolvedDependency>>;
31
+ export type Paths = Readonly<Record<string, string>>;
32
+ export type Hashes = Readonly<Record<string, string>>;
33
+ export interface CacheEntryOptions {
34
+ /** Identifies the computation and its implementation version, for example "simplify@2". */
35
+ version: string;
36
+ /** 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. */
37
+ dependencies?: Dependencies;
38
+ /** Disk directory in Node (default public/_vitecache); URL prefix in browsers (default /_vitecache/). Excluded from the key. */
39
+ basePath?: string;
40
+ /** Node project root, default process.cwd(). Browser dependencies resolve against the Vite root. Excluded from the key. */
41
+ root?: string;
42
+ }
43
+ export interface Stored {
44
+ bytes: Uint8Array;
45
+ hashes?: Hashes;
46
+ }
47
+ export interface Backend {
48
+ canSave(): Promise<boolean>;
49
+ resolve(dependencies: Dependencies): Promise<ResolvedDependencies>;
50
+ /** null means a missing dependency; undefined means validation is unavailable. Values need no fingerprint. */
51
+ snapshot(dependencies: ResolvedDependencies): Promise<Hashes | null | undefined>;
52
+ load(key: string, validate: boolean): Promise<Stored | undefined>;
53
+ save(key: string, value: Uint8Array, dependencies: ResolvedDependencies, expected: Hashes): Promise<void>;
54
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
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 }>;\nexport type ResolvedDependencies = Readonly<Record<string, ResolvedDependency>>;\nexport type Paths = Readonly<Record<string, string>>;\nexport type Hashes = Readonly<Record<string, string>>;\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 Stored {\n bytes: Uint8Array;\n hashes?: Hashes;\n}\n\nexport interface Backend {\n canSave(): Promise<boolean>;\n resolve(dependencies: Dependencies): Promise<ResolvedDependencies>;\n /** null means a missing dependency; undefined means validation is unavailable. Values need no fingerprint. */\n snapshot(dependencies: ResolvedDependencies): Promise<Hashes | null | undefined>;\n load(key: string, validate: boolean): Promise<Stored | undefined>;\n save(key: string, value: Uint8Array, dependencies: ResolvedDependencies, expected: Hashes): Promise<void>;\n}\n"]}
@@ -0,0 +1,8 @@
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;
@@ -0,0 +1,210 @@
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, resolvedDependencies } 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 OutsideRootError)
20
+ return 403;
21
+ if (error instanceof TypeError || error instanceof URIError)
22
+ return 400;
23
+ return 500;
24
+ }
25
+ function allowed(request) {
26
+ if (request.headers['sec-fetch-site'] === 'cross-site')
27
+ return false;
28
+ const origin = request.headers.origin;
29
+ if (!origin)
30
+ return true;
31
+ try {
32
+ const url = new URL(origin);
33
+ return (url.protocol === 'http:' || url.protocol === 'https:') && url.host === request.headers.host;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ async function body(request) {
40
+ const chunks = [];
41
+ for await (const value of request) {
42
+ const chunk = value;
43
+ if (!Buffer.isBuffer(chunk))
44
+ throw new RequestError(400, 'Expected a binary request body');
45
+ chunks.push(chunk);
46
+ }
47
+ return Buffer.concat(chunks);
48
+ }
49
+ function parse(value) {
50
+ try {
51
+ return JSON.parse(value);
52
+ }
53
+ catch {
54
+ throw new RequestError(400, 'Expected valid JSON');
55
+ }
56
+ }
57
+ function validate(value, parser) {
58
+ try {
59
+ return parser(value);
60
+ }
61
+ catch (error) {
62
+ if (!(error instanceof TypeError))
63
+ throw error;
64
+ throw new RequestError(400, error.message);
65
+ }
66
+ }
67
+ function header(request, name) {
68
+ const value = request.headers[name];
69
+ if (typeof value !== 'string')
70
+ throw new RequestError(400, `Missing ${name} header`);
71
+ try {
72
+ return parse(decodeURIComponent(value));
73
+ }
74
+ catch (error) {
75
+ if (!(error instanceof URIError))
76
+ throw error;
77
+ throw new RequestError(400, 'Invalid encoded request header');
78
+ }
79
+ }
80
+ function json(response, value) {
81
+ response.setHeader('Content-Type', 'application/json');
82
+ response.end(JSON.stringify(value));
83
+ }
84
+ async function respond(request, response, name, storage, server) {
85
+ const root = server.config.root;
86
+ response.setHeader('Cache-Control', 'no-store');
87
+ if (name === '__vitecache' && request.method === 'GET') {
88
+ json(response, { vitecache: 1 });
89
+ return;
90
+ }
91
+ if ((name === '__vitecache/snapshot' || name === '__vitecache/resolve') && request.method === 'POST') {
92
+ if (!allowed(request))
93
+ throw new RequestError(403, 'Cross-origin requests are forbidden');
94
+ const value = parse(new TextDecoder().decode(await body(request)));
95
+ if (typeof value !== 'object' || value === null || !('dependencies' in value)) {
96
+ throw new RequestError(400, 'Expected dependencies');
97
+ }
98
+ if (name === '__vitecache/resolve') {
99
+ const deps = validate(value.dependencies, dependencies);
100
+ const origin = `${server.config.server.https ? 'https' : 'http'}://${request.headers.host}`;
101
+ json(response, { dependencies: await resolveDependencies(server, deps, origin) });
102
+ return;
103
+ }
104
+ const deps = validate(value.dependencies, resolvedDependencies);
105
+ await confine(root, deps);
106
+ json(response, { hashes: await storage.snapshot(deps) });
107
+ return;
108
+ }
109
+ if (!/^[a-f0-9]{64}\.bin$/.test(name)) {
110
+ response.statusCode = 404;
111
+ response.end();
112
+ return;
113
+ }
114
+ const key = name.slice(0, -4);
115
+ if (request.method === 'PUT') {
116
+ if (!allowed(request))
117
+ throw new RequestError(403, 'Cross-origin requests are forbidden');
118
+ const deps = validate(header(request, 'x-vitecache-dependencies'), resolvedDependencies);
119
+ const expected = validate(header(request, 'x-vitecache-hashes'), hashes);
120
+ await confine(root, deps);
121
+ await storage.save(key, await body(request), deps, expected);
122
+ response.statusCode = 204;
123
+ response.end();
124
+ return;
125
+ }
126
+ if (request.method !== 'GET' && request.method !== 'HEAD') {
127
+ response.statusCode = 405;
128
+ response.setHeader('Allow', 'GET, HEAD, PUT');
129
+ response.end();
130
+ return;
131
+ }
132
+ const stored = await storage.load(key, true);
133
+ if (stored === undefined) {
134
+ response.statusCode = 404;
135
+ response.end();
136
+ return;
137
+ }
138
+ response.setHeader('Content-Type', 'application/octet-stream');
139
+ response.setHeader('Content-Length', stored.bytes.byteLength);
140
+ response.setHeader('X-Vitecache-Dependencies', encodeURIComponent(JSON.stringify(stored.hashes)));
141
+ response.end(request.method === 'HEAD' ? undefined : stored.bytes);
142
+ }
143
+ /** Persist and validate entries in development; preserve asset URL mappings in production builds. */
144
+ export function vitecache(options = {}) {
145
+ let resolved;
146
+ return {
147
+ name: 'vitecache',
148
+ enforce: 'post',
149
+ async configResolved(config) {
150
+ if (!config.publicDir)
151
+ throw new Error('vitecache requires Vite publicDir');
152
+ const { root, directory } = disk.location({ root: config.root, ...options });
153
+ const path = relative(config.publicDir, directory);
154
+ if (!path || !inside(config.publicDir, directory)) {
155
+ throw new Error('vitecache basePath must be a directory inside Vite publicDir');
156
+ }
157
+ const base = new URL(config.base, 'http://vitecache').pathname.replace(/\/$/, '');
158
+ resolved = {
159
+ backend: createStorage({ root, ...options }),
160
+ root,
161
+ directory,
162
+ config,
163
+ cachePath: path.split(sep).join('/'),
164
+ prefix: `${base}/${path.split(sep).map(encodeURIComponent).join('/')}/`,
165
+ };
166
+ await disk.ignore(root, directory);
167
+ },
168
+ async generateBundle(_options, bundle) {
169
+ const storage = resolved;
170
+ if (!storage)
171
+ throw new Error('vitecache configuration was not resolved');
172
+ const paths = new Map(Object.entries(await publicPaths(storage.config, storage.directory)));
173
+ for (const asset of Object.values(bundle)) {
174
+ if (asset.type !== 'asset')
175
+ continue;
176
+ const originals = [...new Set(asset.originalFileNames)];
177
+ if (originals.length !== 1)
178
+ continue;
179
+ const original = originals[0];
180
+ if (!original)
181
+ continue;
182
+ const file = relative(storage.root, resolve(storage.root, original));
183
+ if (!inside(storage.root, resolve(storage.root, original)))
184
+ continue;
185
+ paths.set(assetUrl(asset.fileName), file.split(sep).join('/'));
186
+ }
187
+ const manifest = { paths: Object.fromEntries(paths), root: '../'.repeat(storage.cachePath.split('/').length + 1) };
188
+ this.emitFile({ type: 'asset', fileName: `${storage.cachePath}/__vitecache/paths.json`, source: JSON.stringify(manifest) });
189
+ },
190
+ configureServer(server) {
191
+ const storage = resolved;
192
+ if (!storage)
193
+ throw new Error('vitecache configuration was not resolved');
194
+ server.middlewares.use((request, response, next) => {
195
+ const path = new URL(request.url ?? '/', 'http://vitecache').pathname;
196
+ if (!path.startsWith(storage.prefix)) {
197
+ next();
198
+ return;
199
+ }
200
+ void respond(request, response, path.slice(storage.prefix.length), storage.backend, server).catch((error) => {
201
+ response.statusCode = status(error);
202
+ response.setHeader('Content-Type', 'text/plain');
203
+ response.end(error instanceof Error ? error.message : 'vitecache request failed');
204
+ });
205
+ });
206
+ },
207
+ };
208
+ }
209
+ export default vitecache;
210
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { relative, resolve, sep } from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\nimport * as disk from '../disk.js';\nimport { ChangedDependenciesError, createStorage } from '../storage.js';\nimport type { Backend } from '../types.js';\nimport { dependencies, hashes, resolvedDependencies } from '../dependencies.js';\nimport { confine, inside, OutsideRootError, resolveDependencies } from './resolve.js';\nimport { assetUrl, publicPaths } from './manifest.js';\n\nexport interface VitecacheOptions {\n /** Cache directory relative to the Vite project root; must be inside publicDir. */\n basePath?: string;\n}\n\nclass RequestError extends Error {\n constructor(readonly status: number, message: string) {\n super(message);\n }\n}\n\nfunction status(error: unknown): number {\n if (error instanceof RequestError) return error.status;\n if (error instanceof ChangedDependenciesError) return 409;\n if (error instanceof OutsideRootError) return 403;\n if (error instanceof TypeError || error instanceof URIError) return 400;\n return 500;\n}\n\nfunction allowed(request: IncomingMessage): boolean {\n if (request.headers['sec-fetch-site'] === 'cross-site') return false;\n const origin = request.headers.origin;\n if (!origin) return true;\n try {\n const url = new URL(origin);\n return (url.protocol === 'http:' || url.protocol === 'https:') && url.host === request.headers.host;\n } catch {\n return false;\n }\n}\n\nasync function body(request: IncomingMessage): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n for await (const value of request) {\n const chunk: unknown = value;\n if (!Buffer.isBuffer(chunk)) throw new RequestError(400, 'Expected a binary request body');\n chunks.push(chunk);\n }\n return Buffer.concat(chunks);\n}\n\nfunction parse(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n throw new RequestError(400, 'Expected valid JSON');\n }\n}\n\nfunction validate<T>(value: unknown, parser: (value: unknown) => T): T {\n try {\n return parser(value);\n } catch (error) {\n if (!(error instanceof TypeError)) throw error;\n throw new RequestError(400, error.message);\n }\n}\n\nfunction header(request: IncomingMessage, name: string): unknown {\n const value = request.headers[name];\n if (typeof value !== 'string') throw new RequestError(400, `Missing ${name} header`);\n try {\n return parse(decodeURIComponent(value));\n } catch (error) {\n if (!(error instanceof URIError)) throw error;\n throw new RequestError(400, 'Invalid encoded request header');\n }\n}\n\nfunction json(response: ServerResponse, value: unknown): void {\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(value));\n}\n\nasync function respond(\n request: IncomingMessage,\n response: ServerResponse,\n name: string,\n storage: Backend,\n server: ViteDevServer,\n): Promise<void> {\n const root = server.config.root;\n response.setHeader('Cache-Control', 'no-store');\n if (name === '__vitecache' && request.method === 'GET') {\n json(response, { vitecache: 1 });\n return;\n }\n if ((name === '__vitecache/snapshot' || name === '__vitecache/resolve') && request.method === 'POST') {\n if (!allowed(request)) throw new RequestError(403, 'Cross-origin requests are forbidden');\n const value = parse(new TextDecoder().decode(await body(request)));\n if (typeof value !== 'object' || value === null || !('dependencies' in value)) {\n throw new RequestError(400, 'Expected dependencies');\n }\n if (name === '__vitecache/resolve') {\n const deps = validate(value.dependencies, dependencies);\n const origin = `${server.config.server.https ? 'https' : 'http'}://${request.headers.host}`;\n json(response, { dependencies: await resolveDependencies(server, deps, origin) });\n return;\n }\n const deps = validate(value.dependencies, resolvedDependencies);\n await confine(root, deps);\n json(response, { hashes: await storage.snapshot(deps) });\n return;\n }\n if (!/^[a-f0-9]{64}\\.bin$/.test(name)) {\n response.statusCode = 404;\n response.end();\n return;\n }\n const key = name.slice(0, -4);\n if (request.method === 'PUT') {\n if (!allowed(request)) throw new RequestError(403, 'Cross-origin requests are forbidden');\n const deps = validate(header(request, 'x-vitecache-dependencies'), resolvedDependencies);\n const expected = validate(header(request, 'x-vitecache-hashes'), hashes);\n await confine(root, deps);\n await storage.save(key, await body(request), deps, expected);\n response.statusCode = 204;\n response.end();\n return;\n }\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n response.statusCode = 405;\n response.setHeader('Allow', 'GET, HEAD, PUT');\n response.end();\n return;\n }\n const stored = await storage.load(key, true);\n if (stored === undefined) {\n response.statusCode = 404;\n response.end();\n return;\n }\n response.setHeader('Content-Type', 'application/octet-stream');\n response.setHeader('Content-Length', stored.bytes.byteLength);\n response.setHeader('X-Vitecache-Dependencies', encodeURIComponent(JSON.stringify(stored.hashes)));\n response.end(request.method === 'HEAD' ? undefined : stored.bytes);\n}\n\n/** Persist and validate entries in development; preserve asset URL mappings in production builds. */\nexport function vitecache(options: VitecacheOptions = {}): Plugin {\n let resolved: { backend: Backend; root: string; prefix: string; directory: string; config: ResolvedConfig; cachePath: string } | undefined;\n return {\n name: 'vitecache',\n enforce: 'post',\n async configResolved(config) {\n if (!config.publicDir) throw new Error('vitecache requires Vite publicDir');\n const { root, directory } = disk.location({ root: config.root, ...options });\n const path = relative(config.publicDir, directory);\n if (!path || !inside(config.publicDir, directory)) {\n throw new Error('vitecache basePath must be a directory inside Vite publicDir');\n }\n const base = new URL(config.base, 'http://vitecache').pathname.replace(/\\/$/, '');\n resolved = {\n backend: createStorage({ root, ...options }),\n root,\n directory,\n config,\n cachePath: path.split(sep).join('/'),\n prefix: `${base}/${path.split(sep).map(encodeURIComponent).join('/')}/`,\n };\n await disk.ignore(root, directory);\n },\n async generateBundle(_options, bundle) {\n const storage = resolved;\n if (!storage) throw new Error('vitecache configuration was not resolved');\n const paths = new Map(Object.entries(await publicPaths(storage.config, storage.directory)));\n for (const asset of Object.values(bundle)) {\n if (asset.type !== 'asset') continue;\n const originals = [...new Set(asset.originalFileNames)];\n if (originals.length !== 1) continue;\n const original = originals[0];\n if (!original) continue;\n const file = relative(storage.root, resolve(storage.root, original));\n if (!inside(storage.root, resolve(storage.root, original))) continue;\n paths.set(assetUrl(asset.fileName), file.split(sep).join('/'));\n }\n const manifest = { paths: Object.fromEntries(paths), root: '../'.repeat(storage.cachePath.split('/').length + 1) };\n this.emitFile({ type: 'asset', fileName: `${storage.cachePath}/__vitecache/paths.json`, source: JSON.stringify(manifest) });\n },\n configureServer(server) {\n const storage = resolved;\n if (!storage) throw new Error('vitecache configuration was not resolved');\n server.middlewares.use((request, response, next) => {\n const path = new URL(request.url ?? '/', 'http://vitecache').pathname;\n if (!path.startsWith(storage.prefix)) {\n next();\n return;\n }\n void respond(request, response, path.slice(storage.prefix.length), storage.backend, server).catch((error: unknown) => {\n response.statusCode = status(error);\n response.setHeader('Content-Type', 'text/plain');\n response.end(error instanceof Error ? error.message : 'vitecache request failed');\n });\n });\n },\n };\n}\n\nexport default vitecache;\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ResolvedConfig } from 'vite';
2
+ export declare function assetUrl(file: string): string;
3
+ export declare function publicPaths(config: ResolvedConfig, cacheDirectory: string): Promise<Record<string, string>>;
@@ -0,0 +1,34 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import { relative, resolve, sep } from 'node:path';
3
+ import { inside } from './resolve.js';
4
+ export function assetUrl(file) {
5
+ return file.split('/').map(encodeURIComponent).join('/');
6
+ }
7
+ export async function publicPaths(config, cacheDirectory) {
8
+ const paths = [];
9
+ async function visit(directory) {
10
+ let entries;
11
+ try {
12
+ entries = await readdir(directory, { withFileTypes: true });
13
+ }
14
+ catch (error) {
15
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
16
+ return;
17
+ throw error;
18
+ }
19
+ for (const entry of entries) {
20
+ const file = resolve(directory, entry.name);
21
+ if (inside(cacheDirectory, file))
22
+ continue;
23
+ if (entry.isDirectory())
24
+ await visit(file);
25
+ else if (entry.isFile()) {
26
+ const publicPath = relative(config.publicDir, file).split(sep).join('/');
27
+ paths.push([assetUrl(publicPath), relative(config.root, file).split(sep).join('/')]);
28
+ }
29
+ }
30
+ }
31
+ await visit(config.publicDir);
32
+ return Object.fromEntries(paths);
33
+ }
34
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/vite/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAsB,EAAE,cAAsB;IAC9E,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,UAAU,KAAK,CAAC,SAAiB;QACpC,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO;YACjF,MAAM,KAAK,CAAC;QACd,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC;gBAAE,SAAS;YAC3C,IAAI,KAAK,CAAC,WAAW,EAAE;gBAAE,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;iBACtC,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBACxB,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACzE,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { readdir } from 'node:fs/promises';\nimport { relative, resolve, sep } from 'node:path';\nimport type { ResolvedConfig } from 'vite';\nimport { inside } from './resolve.js';\n\nexport function assetUrl(file: string): string {\n return file.split('/').map(encodeURIComponent).join('/');\n}\n\nexport async function publicPaths(config: ResolvedConfig, cacheDirectory: string): Promise<Record<string, string>> {\n const paths: [string, string][] = [];\n async function visit(directory: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(directory, { withFileTypes: true });\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return;\n throw error;\n }\n for (const entry of entries) {\n const file = resolve(directory, entry.name);\n if (inside(cacheDirectory, file)) continue;\n if (entry.isDirectory()) await visit(file);\n else if (entry.isFile()) {\n const publicPath = relative(config.publicDir, file).split(sep).join('/');\n paths.push([assetUrl(publicPath), relative(config.root, file).split(sep).join('/')]);\n }\n }\n }\n await visit(config.publicDir);\n return Object.fromEntries(paths);\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ViteDevServer } from 'vite';
2
+ import type { Dependencies, ResolvedDependencies } from '../types.js';
3
+ export declare class OutsideRootError extends Error {
4
+ constructor();
5
+ }
6
+ export declare function inside(root: string, path: string): boolean;
7
+ export declare function confine(root: string, dependencies: ResolvedDependencies): Promise<void>;
8
+ export declare function resolveDependencies(server: ViteDevServer, dependencies: Dependencies, origin: string): Promise<ResolvedDependencies>;