vitecache 0.3.0 → 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.
Files changed (57) hide show
  1. package/README.md +17 -22
  2. package/dist/browser.d.ts +9 -6
  3. package/dist/browser.js +28 -178
  4. package/dist/browser.js.map +1 -1
  5. package/dist/discover.d.ts +15 -0
  6. package/dist/discover.js +131 -0
  7. package/dist/discover.js.map +1 -0
  8. package/dist/disk.d.ts +2 -26
  9. package/dist/disk.js +8 -107
  10. package/dist/disk.js.map +1 -1
  11. package/dist/entry.d.ts +29 -17
  12. package/dist/entry.js +11 -114
  13. package/dist/entry.js.map +1 -1
  14. package/dist/node.d.ts +9 -6
  15. package/dist/node.js +101 -6
  16. package/dist/node.js.map +1 -1
  17. package/dist/shared.d.ts +17 -0
  18. package/dist/shared.js +5 -0
  19. package/dist/shared.js.map +1 -0
  20. package/dist/vite.d.ts +12 -0
  21. package/dist/vite.js +253 -0
  22. package/dist/vite.js.map +1 -0
  23. package/package.json +17 -13
  24. package/skills/vitecache/SKILL.md +41 -46
  25. package/dist/dependencies.d.ts +0 -23
  26. package/dist/dependencies.js +0 -147
  27. package/dist/dependencies.js.map +0 -1
  28. package/dist/hash.d.ts +0 -4
  29. package/dist/hash.js +0 -41
  30. package/dist/hash.js.map +0 -1
  31. package/dist/index.d.ts +0 -1
  32. package/dist/index.js +0 -2
  33. package/dist/index.js.map +0 -1
  34. package/dist/key.d.ts +0 -3
  35. package/dist/key.js +0 -10
  36. package/dist/key.js.map +0 -1
  37. package/dist/packages.d.ts +0 -6
  38. package/dist/packages.js +0 -52
  39. package/dist/packages.js.map +0 -1
  40. package/dist/prune.d.ts +0 -11
  41. package/dist/prune.js +0 -71
  42. package/dist/prune.js.map +0 -1
  43. package/dist/storage.d.ts +0 -12
  44. package/dist/storage.js +0 -95
  45. package/dist/storage.js.map +0 -1
  46. package/dist/types.d.ts +0 -89
  47. package/dist/types.js +0 -2
  48. package/dist/types.js.map +0 -1
  49. package/dist/vite/index.d.ts +0 -8
  50. package/dist/vite/index.js +0 -220
  51. package/dist/vite/index.js.map +0 -1
  52. package/dist/vite/manifest.d.ts +0 -3
  53. package/dist/vite/manifest.js +0 -34
  54. package/dist/vite/manifest.js.map +0 -1
  55. package/dist/vite/resolve.d.ts +0 -9
  56. package/dist/vite/resolve.js +0 -90
  57. package/dist/vite/resolve.js.map +0 -1
package/README.md CHANGED
@@ -1,37 +1,32 @@
1
1
  # vitecache
2
2
 
3
- Cache expensive computation as bytes, then reuse it across browser sessions and Node runs.
3
+ Cache expensive computation as bytes: the Vite plugin computes it once in Node, then browsers and Node reuse it.
4
4
 
5
5
  ```sh
6
6
  pnpm add vitecache
7
7
  ```
8
8
 
9
+ Wrap a computation in a class named `Cached…Loader` and load with literal arguments:
10
+
9
11
  ```ts
10
12
  import { CacheEntry } from "vitecache"
11
- import modelUrl from "./models/chair.glb?url"
12
-
13
- const entry = new CacheEntry({
14
- version: "simplify@2",
15
- dependencies: {
16
- settings: { value: { ratio: 0.5, preserveUVs: true } },
17
- algorithm: { path: "src/simplify.ts" },
18
- model: { url: modelUrl },
19
- },
20
- })
21
-
22
- let bytes = await entry.load()
23
-
24
- if (bytes === undefined) {
25
- bytes = await simplify()
26
- await entry.save(bytes)
13
+
14
+ export class CachedMeshLoader {
15
+ async loadAsync(settings: { ratio: number }) {
16
+ const entry = new CacheEntry({ version: "simplify@2", dependencies: { settings: { value: settings } } })
17
+ let bytes = await entry.load()
18
+ if (bytes === undefined) {
19
+ bytes = await simplify(settings)
20
+ await entry.save(bytes)
21
+ }
22
+ return bytes
23
+ }
27
24
  }
28
25
 
29
- useMeshBytes(bytes)
26
+ const mesh = await new CachedMeshLoader().loadAsync({ ratio: 0.5 })
30
27
  ```
31
28
 
32
- Entries identify computations by version and named dependencies: JSON `{ value }`, file `{ path }` or `{ url }`, and installed library `{ package: "layout-engine" }`. Node and the Vite development plugin validate file contents and package versions without changing entry keys.
33
-
34
- Node reads and writes `<project_root>/public/_vitecache/`. Add the plugin to save browser results into the same directory during development:
29
+ Add the plugin:
35
30
 
36
31
  ```ts
37
32
  import { defineConfig } from "vite"
@@ -40,6 +35,6 @@ import { vitecache } from "vitecache/vite"
40
35
  export default defineConfig({ plugins: [vitecache()] })
41
36
  ```
42
37
 
43
- Node saves and the plugin add the cache directory to `.gitignore`. Generate caches before building and include them in your deployment; `prune` from `vitecache/prune` removes entries no load or save has used since a given time. Browsers without the plugin read public cache files, assume dependencies unchanged, and warn and skip writes when `save()` is called.
38
+ The plugin finds these loads by scanning the project's source files, computes them in Node during development and builds, and deletes entries no load uses. Browsers read the saved bytes.
44
39
 
45
40
  For usage patterns, see the [vitecache skill](skills/vitecache/SKILL.md), also shipped in this package.
package/dist/browser.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- import { Entry } from './entry.js';
2
- import type { CacheEntryOptions } from './types.js';
3
- export { ChangedDependenciesError, MissingDependencyError } from './dependencies.js';
4
- export type { CacheEntryOptions, Dependency, Dependencies, JsonValue, SavedDependencies, SavedDependency, SaveOptions } from './types.js';
5
- /** A persistent binary computation result. Pass a browser basePath matching the public cache URL, including any Vite base. */
6
- export declare class CacheEntry extends Entry {
1
+ import { type CacheEntryOptions, type SaveOptions } from './entry.js';
2
+ export type { CacheEntryOptions, Dependency, Input, JsonValue, SaveOptions } from './entry.js';
3
+ /** A cached result, read from the cache directory the app serves. Only Node writes entries. */
4
+ export declare class CacheEntry {
5
+ #private;
7
6
  constructor(options: CacheEntryOptions);
7
+ /** The saved bytes, or undefined when the app serves none. */
8
+ load(): Promise<Uint8Array | undefined>;
9
+ /** Writes nothing, since browsers only read. Warns once per version that its result was computed here. */
10
+ save(_value: Uint8Array, _options?: SaveOptions): Promise<void>;
8
11
  }
package/dist/browser.js CHANGED
@@ -1,183 +1,33 @@
1
- import { ChangedDependenciesError, hashes, MissingDependencyError, paths, resolvedDependencies } from './dependencies.js';
2
- import { Entry } from './entry.js';
3
- export { ChangedDependenciesError, MissingDependencyError } from './dependencies.js';
4
- /** Shares one request per URL across the page, and retries after a failure. */
5
- function memoize(cache, url, request) {
6
- const existing = cache.get(url.href);
7
- if (existing)
8
- return existing;
9
- const pending = request(url).catch((error) => {
10
- cache.delete(url.href);
11
- throw error;
12
- });
13
- cache.set(url.href, pending);
14
- return pending;
15
- }
16
- const discoveries = new Map();
17
- async function discover(url) {
18
- const response = await fetch(url, { cache: 'no-store' });
19
- if (response.status === 404)
20
- return false;
21
- if (!response.ok)
22
- throw new Error(`vitecache discovery failed: HTTP ${response.status}`);
23
- // Static SPA servers may return index.html for unknown paths.
24
- if (!response.headers.get('content-type')?.includes('application/json'))
25
- return false;
26
- const data = await response.json();
27
- return typeof data === 'object' && data !== null && 'vitecache' in data && data.vitecache === 1;
28
- }
29
- const mappings = new Map();
30
- /** The production build's served pathnames mapped to project-root-relative source paths. */
31
- async function mapping(url) {
32
- const response = await fetch(url, { cache: 'no-cache' });
33
- if (!response.ok || !response.headers.get('content-type')?.includes('application/json')) {
34
- throw new Error('URL dependencies require the vitecache Vite plugin during development and build. Missing production URL mapping.');
1
+ import { key } from './entry.js';
2
+ const warned = new Set();
3
+ /** A cached result, read from the cache directory the app serves. Only Node writes entries. */
4
+ export class CacheEntry {
5
+ #version;
6
+ #url;
7
+ constructor(options) {
8
+ this.#version = options.version;
9
+ const base = new URL((options.basePath ?? '/_vitecache/').replace(/\/?$/, '/'), globalThis.location.href);
10
+ this.#url = new URL(`${key(options)}.bin`, base);
35
11
  }
36
- const data = await response.json();
37
- const manifest = responseObject(data);
38
- const mapped = paths(manifest.paths);
39
- if (typeof manifest.root !== 'string' || !/^(?:\.\.\/)+$/.test(manifest.root))
40
- throw new Error('Invalid vitecache production mapping root.');
41
- const projectRoot = new URL(manifest.root, url);
42
- return Object.fromEntries(Object.entries(mapped).map(([served, path]) => [new URL(served, projectRoot).pathname, path]));
43
- }
44
- /** A JSON object that the plugin or a build answered with. */
45
- function responseObject(data) {
46
- if (typeof data !== 'object' || data === null || Array.isArray(data))
47
- throw new TypeError('Invalid vitecache response.');
48
- return Object.fromEntries(Object.entries(data));
49
- }
50
- /** The plugin answers a missing file or package dependency with `{ status: 'missing', message }` on every route. */
51
- function missingMessage(data) {
52
- if (data.status !== 'missing')
53
- return undefined;
54
- if (typeof data.message !== 'string')
55
- throw new TypeError('Invalid vitecache missing dependency response.');
56
- return data.message;
57
- }
58
- function createBackend(options) {
59
- const base = new URL(options.basePath ?? '/_vitecache/', globalThis.location.href);
60
- base.pathname = `${base.pathname.replace(/\/+$/, '')}/`;
61
- base.search = '';
62
- base.hash = '';
63
- function plugin() {
64
- return memoize(discoveries, new URL('__vitecache', base), discover);
12
+ /** The saved bytes, or undefined when the app serves none. */
13
+ async load() {
14
+ // An entry keeps its name when its bytes change, so the HTTP cache must revalidate them.
15
+ const response = await fetch(this.#url, { cache: 'no-cache' });
16
+ if (response.status === 404)
17
+ return undefined;
18
+ if (!response.ok)
19
+ throw new Error(`vitecache load failed: HTTP ${response.status}`);
20
+ // Vite's dev server and SPA hosts answer a missing file with index.html.
21
+ if (response.headers.get('content-type')?.startsWith('text/html'))
22
+ return undefined;
23
+ return new Uint8Array(await response.arrayBuffer());
65
24
  }
66
- return {
67
- canSave: plugin,
68
- async resolve(declared) {
69
- const locators = Object.entries(declared).map(([name, locator]) => {
70
- if (locator.url === undefined)
71
- return [name, locator];
72
- const url = new URL(locator.url, globalThis.location.href);
73
- if (url.origin !== new URL(globalThis.location.href).origin)
74
- throw new Error('URL dependencies must be served by the same Vite project origin.');
75
- return [name, { url: url.href }];
76
- });
77
- if (locators.every(([, locator]) => locator.url === undefined)) {
78
- return resolvedDependencies(Object.fromEntries(locators));
79
- }
80
- if (await plugin()) {
81
- const response = await fetch(new URL('__vitecache/resolve', base), {
82
- method: 'POST',
83
- headers: { 'Content-Type': 'application/json' },
84
- body: JSON.stringify({ dependencies: Object.fromEntries(locators) }),
85
- cache: 'no-store',
86
- });
87
- if (!response.ok)
88
- throw new Error(`vitecache URL resolution failed: HTTP ${response.status}: ${await response.text()}`);
89
- const data = responseObject(await response.json());
90
- const missing = missingMessage(data);
91
- if (missing !== undefined)
92
- throw new MissingDependencyError(missing);
93
- const resolved = resolvedDependencies(data.dependencies);
94
- if (Object.keys(resolved).length !== locators.length || !locators.every(([name]) => Object.hasOwn(resolved, name))) {
95
- throw new Error('Invalid vitecache resolved dependencies.');
96
- }
97
- return resolved;
98
- }
99
- const mapped = await memoize(mappings, new URL('__vitecache/paths.json', base), mapping);
100
- const resolved = locators.map(([name, locator]) => {
101
- if (locator.url === undefined)
102
- return [name, locator];
103
- const pathname = new URL(locator.url).pathname;
104
- const path = mapped[pathname];
105
- // The build maps every file it deployed, so an unmapped URL has no backing file, as the plugin reports in development.
106
- if (path === undefined)
107
- throw new MissingDependencyError(`No vitecache source file mapping for URL: ${pathname}`);
108
- return [name, { path }];
109
- });
110
- return resolvedDependencies(Object.fromEntries(resolved));
111
- },
112
- async snapshot(dependencies) {
113
- if (!await plugin())
114
- return { status: 'unchecked' };
115
- const response = await fetch(new URL('__vitecache/snapshot', base), {
116
- method: 'POST',
117
- headers: { 'Content-Type': 'application/json' },
118
- body: JSON.stringify({ dependencies }),
119
- cache: 'no-store',
120
- });
121
- if (!response.ok)
122
- throw new Error(`vitecache dependency validation failed: HTTP ${response.status}: ${await response.text()}`);
123
- const data = responseObject(await response.json());
124
- const missing = missingMessage(data);
125
- if (missing !== undefined)
126
- return { status: 'missing', message: missing };
127
- if (data.status !== 'current')
128
- throw new TypeError('Invalid vitecache dependency response.');
129
- return { status: 'current', hashes: hashes(data.hashes) };
130
- },
131
- async load(key) {
132
- // Entry names do not change with their contents, so cached bytes are revalidated before each use.
133
- const response = await fetch(new URL(`${key}.bin`, base), { cache: 'no-cache' });
134
- // The plugin answers misses with 204 so they stay out of the console; static hosts answer 404.
135
- if (response.status === 204 || response.status === 404)
136
- return undefined;
137
- if (!response.ok)
138
- throw new Error(`vitecache load failed: HTTP ${response.status}`);
139
- const contentType = response.headers.get('content-type')?.split(';')[0]?.trim();
140
- if (contentType === 'text/html')
141
- return undefined;
142
- if (contentType !== 'application/octet-stream')
143
- throw new Error(`Unexpected vitecache content type: ${contentType ?? 'missing'}`);
144
- const bytes = new Uint8Array(await response.arrayBuffer());
145
- // Only the plugin sends hashes.
146
- const header = response.headers.get('X-Vitecache-Dependencies');
147
- if (header === null)
148
- return { bytes };
149
- const value = JSON.parse(decodeURIComponent(header));
150
- return { bytes, hashes: hashes(value) };
151
- },
152
- async save(key, value, { checked, expected, saved }) {
153
- // Metadata travels in the body: headers are capped near 16 KiB, and saved dependencies can be many.
154
- const metadata = new TextEncoder().encode(JSON.stringify({ checked, expected, saved }));
155
- const body = new Uint8Array(4 + metadata.byteLength + value.byteLength);
156
- new DataView(body.buffer).setUint32(0, metadata.byteLength);
157
- body.set(metadata, 4);
158
- body.set(value, 4 + metadata.byteLength);
159
- const response = await fetch(new URL(`${key}.bin`, base), {
160
- method: 'PUT',
161
- headers: { 'Content-Type': 'application/octet-stream' },
162
- body,
163
- });
164
- if (response.status === 409)
165
- throw new ChangedDependenciesError();
166
- if (!response.ok)
167
- throw new Error(`vitecache save failed: HTTP ${response.status}: ${await response.text()}`);
168
- if (response.status === 204)
169
- return;
170
- const missing = missingMessage(responseObject(await response.json()));
171
- if (missing === undefined)
172
- throw new TypeError('Invalid vitecache save response.');
173
- throw new MissingDependencyError(missing);
174
- },
175
- };
176
- }
177
- /** A persistent binary computation result. Pass a browser basePath matching the public cache URL, including any Vite base. */
178
- export class CacheEntry extends Entry {
179
- constructor(options) {
180
- super(options, createBackend(options));
25
+ /** Writes nothing, since browsers only read. Warns once per version that its result was computed here. */
26
+ async save(_value, _options) {
27
+ if (warned.has(this.#version))
28
+ return;
29
+ warned.add(this.#version);
30
+ console.warn(`vitecache: ${this.#version} was computed in the browser, which does not save it.`);
181
31
  }
182
32
  }
183
33
  //# sourceMappingURL=browser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1H,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGrF,+EAA+E;AAC/E,SAAS,OAAO,CAAI,KAA8B,EAAE,GAAQ,EAAE,OAAiC;IAC7F,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACpD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;AAExD,KAAK,UAAU,QAAQ,CAAC,GAAQ;IAC9B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IACzD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,8DAA8D;IAC9D,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,WAAW,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC;AAClG,CAAC;AAED,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEnD,4FAA4F;AAC5F,KAAK,UAAU,OAAO,CAAC,GAAQ;IAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,kHAAkH,CAAC,CAAC;IACtI,CAAC;IACD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC7I,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3H,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAa;IACnC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,6BAA6B,CAAC,CAAC;IACzH,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,oHAAoH;AACpH,SAAS,cAAc,CAAC,IAA6B;IACnD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;IAC5G,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,OAA0B;IAC/C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnF,IAAI,CAAC,QAAQ,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC;IACxD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IAEf,SAAS,MAAM;QACb,OAAO,OAAO,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;IACtE,CAAC;IAED,OAAO;QACL,OAAO,EAAE,MAAM;QACf,KAAK,CAAC,OAAO,CAAC,QAAQ;YACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAwB,EAAE;gBACtF,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;oBAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC3D,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;gBACjJ,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,EAAE,CAAC;gBAC/D,OAAO,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,MAAM,MAAM,EAAE,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,EAAE;oBACjE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACpE,KAAK,EAAE,UAAU;iBAClB,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACxH,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;gBACnD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;gBACrC,IAAI,OAAO,KAAK,SAAS;oBAAE,MAAM,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC;gBACrE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBACzD,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;oBACnH,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;gBAC9D,CAAC;gBACD,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,wBAAwB,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YACzF,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAsB,EAAE;gBACpE,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;oBAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;gBAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC9B,uHAAuH;gBACvH,IAAI,IAAI,KAAK,SAAS;oBAAE,MAAM,IAAI,sBAAsB,CAAC,6CAA6C,QAAQ,EAAE,CAAC,CAAC;gBAClH,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,OAAO,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,YAAY;YACzB,IAAI,CAAC,MAAM,MAAM,EAAE;gBAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,EAAE;gBAClE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;gBACtC,KAAK,EAAE,UAAU;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/H,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YAC1E,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;YAC7F,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG;YACZ,kGAAkG;YAClG,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;YACjF,+FAA+F;YAC/F,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,SAAS,CAAC;YACzE,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACpF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YAChF,IAAI,WAAW,KAAK,WAAW;gBAAE,OAAO,SAAS,CAAC;YAClD,IAAI,WAAW,KAAK,0BAA0B;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,WAAW,IAAI,SAAS,EAAE,CAAC,CAAC;YAClI,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;YAC3D,gCAAgC;YAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YAChE,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtC,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;YACjD,oGAAoG;YACpG,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YACxF,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;YACxE,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE;gBACxD,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE;gBACvD,IAAI;aACL,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC;YAClE,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC9G,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO;YACpC,MAAM,OAAO,GAAG,cAAc,CAAC,cAAc,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtE,IAAI,OAAO,KAAK,SAAS;gBAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;YACnF,MAAM,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,8HAA8H;AAC9H,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAA0B;QACpC,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,CAAC;CACF","sourcesContent":["import { ChangedDependenciesError, hashes, MissingDependencyError, paths, resolvedDependencies } from './dependencies.js';\nimport { Entry } from './entry.js';\nimport type { Backend, CacheEntryOptions, Dependency, Paths, Resolved } from './types.js';\nexport { ChangedDependenciesError, MissingDependencyError } from './dependencies.js';\nexport type { CacheEntryOptions, Dependency, Dependencies, JsonValue, SavedDependencies, SavedDependency, SaveOptions } from './types.js';\n\n/** Shares one request per URL across the page, and retries after a failure. */\nfunction memoize<T>(cache: Map<string, Promise<T>>, url: URL, request: (url: URL) => Promise<T>): Promise<T> {\n const existing = cache.get(url.href);\n if (existing) return existing;\n const pending = request(url).catch((error: unknown) => {\n cache.delete(url.href);\n throw error;\n });\n cache.set(url.href, pending);\n return pending;\n}\n\nconst discoveries = new Map<string, Promise<boolean>>();\n\nasync function discover(url: URL): Promise<boolean> {\n const response = await fetch(url, { cache: 'no-store' });\n if (response.status === 404) return false;\n if (!response.ok) throw new Error(`vitecache discovery failed: HTTP ${response.status}`);\n // Static SPA servers may return index.html for unknown paths.\n if (!response.headers.get('content-type')?.includes('application/json')) return false;\n const data: unknown = await response.json();\n return typeof data === 'object' && data !== null && 'vitecache' in data && data.vitecache === 1;\n}\n\nconst mappings = new Map<string, Promise<Paths>>();\n\n/** The production build's served pathnames mapped to project-root-relative source paths. */\nasync function mapping(url: URL): Promise<Paths> {\n const response = await fetch(url, { cache: 'no-cache' });\n if (!response.ok || !response.headers.get('content-type')?.includes('application/json')) {\n throw new Error('URL dependencies require the vitecache Vite plugin during development and build. Missing production URL mapping.');\n }\n const data: unknown = await response.json();\n const manifest = responseObject(data);\n const mapped = paths(manifest.paths);\n if (typeof manifest.root !== 'string' || !/^(?:\\.\\.\\/)+$/.test(manifest.root)) throw new Error('Invalid vitecache production mapping root.');\n const projectRoot = new URL(manifest.root, url);\n return Object.fromEntries(Object.entries(mapped).map(([served, path]) => [new URL(served, projectRoot).pathname, path]));\n}\n\n/** A JSON object that the plugin or a build answered with. */\nfunction responseObject(data: unknown): Record<string, unknown> {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) throw new TypeError('Invalid vitecache response.');\n return Object.fromEntries(Object.entries(data));\n}\n\n/** The plugin answers a missing file or package dependency with `{ status: 'missing', message }` on every route. */\nfunction missingMessage(data: Record<string, unknown>): string | undefined {\n if (data.status !== 'missing') return undefined;\n if (typeof data.message !== 'string') throw new TypeError('Invalid vitecache missing dependency response.');\n return data.message;\n}\n\nfunction createBackend(options: CacheEntryOptions): Backend {\n const base = new URL(options.basePath ?? '/_vitecache/', globalThis.location.href);\n base.pathname = `${base.pathname.replace(/\\/+$/, '')}/`;\n base.search = '';\n base.hash = '';\n\n function plugin(): Promise<boolean> {\n return memoize(discoveries, new URL('__vitecache', base), discover);\n }\n\n return {\n canSave: plugin,\n async resolve(declared) {\n const locators = Object.entries(declared).map(([name, locator]): [string, Dependency] => {\n if (locator.url === undefined) return [name, locator];\n const url = new URL(locator.url, globalThis.location.href);\n if (url.origin !== new URL(globalThis.location.href).origin) throw new Error('URL dependencies must be served by the same Vite project origin.');\n return [name, { url: url.href }];\n });\n if (locators.every(([, locator]) => locator.url === undefined)) {\n return resolvedDependencies(Object.fromEntries(locators));\n }\n if (await plugin()) {\n const response = await fetch(new URL('__vitecache/resolve', base), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ dependencies: Object.fromEntries(locators) }),\n cache: 'no-store',\n });\n if (!response.ok) throw new Error(`vitecache URL resolution failed: HTTP ${response.status}: ${await response.text()}`);\n const data = responseObject(await response.json());\n const missing = missingMessage(data);\n if (missing !== undefined) throw new MissingDependencyError(missing);\n const resolved = resolvedDependencies(data.dependencies);\n if (Object.keys(resolved).length !== locators.length || !locators.every(([name]) => Object.hasOwn(resolved, name))) {\n throw new Error('Invalid vitecache resolved dependencies.');\n }\n return resolved;\n }\n const mapped = await memoize(mappings, new URL('__vitecache/paths.json', base), mapping);\n const resolved = locators.map(([name, locator]): [string, Resolved] => {\n if (locator.url === undefined) return [name, locator];\n const pathname = new URL(locator.url).pathname;\n const path = mapped[pathname];\n // The build maps every file it deployed, so an unmapped URL has no backing file, as the plugin reports in development.\n if (path === undefined) throw new MissingDependencyError(`No vitecache source file mapping for URL: ${pathname}`);\n return [name, { path }];\n });\n return resolvedDependencies(Object.fromEntries(resolved));\n },\n async snapshot(dependencies) {\n if (!await plugin()) return { status: 'unchecked' };\n const response = await fetch(new URL('__vitecache/snapshot', base), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ dependencies }),\n cache: 'no-store',\n });\n if (!response.ok) throw new Error(`vitecache dependency validation failed: HTTP ${response.status}: ${await response.text()}`);\n const data = responseObject(await response.json());\n const missing = missingMessage(data);\n if (missing !== undefined) return { status: 'missing', message: missing };\n if (data.status !== 'current') throw new TypeError('Invalid vitecache dependency response.');\n return { status: 'current', hashes: hashes(data.hashes) };\n },\n async load(key) {\n // Entry names do not change with their contents, so cached bytes are revalidated before each use.\n const response = await fetch(new URL(`${key}.bin`, base), { cache: 'no-cache' });\n // The plugin answers misses with 204 so they stay out of the console; static hosts answer 404.\n if (response.status === 204 || response.status === 404) return undefined;\n if (!response.ok) throw new Error(`vitecache load failed: HTTP ${response.status}`);\n const contentType = response.headers.get('content-type')?.split(';')[0]?.trim();\n if (contentType === 'text/html') return undefined;\n if (contentType !== 'application/octet-stream') throw new Error(`Unexpected vitecache content type: ${contentType ?? 'missing'}`);\n const bytes = new Uint8Array(await response.arrayBuffer());\n // Only the plugin sends hashes.\n const header = response.headers.get('X-Vitecache-Dependencies');\n if (header === null) return { bytes };\n const value: unknown = JSON.parse(decodeURIComponent(header));\n return { bytes, hashes: hashes(value) };\n },\n async save(key, value, { checked, expected, saved }) {\n // Metadata travels in the body: headers are capped near 16 KiB, and saved dependencies can be many.\n const metadata = new TextEncoder().encode(JSON.stringify({ checked, expected, saved }));\n const body = new Uint8Array(4 + metadata.byteLength + value.byteLength);\n new DataView(body.buffer).setUint32(0, metadata.byteLength);\n body.set(metadata, 4);\n body.set(value, 4 + metadata.byteLength);\n const response = await fetch(new URL(`${key}.bin`, base), {\n method: 'PUT',\n headers: { 'Content-Type': 'application/octet-stream' },\n body,\n });\n if (response.status === 409) throw new ChangedDependenciesError();\n if (!response.ok) throw new Error(`vitecache save failed: HTTP ${response.status}: ${await response.text()}`);\n if (response.status === 204) return;\n const missing = missingMessage(responseObject(await response.json()));\n if (missing === undefined) throw new TypeError('Invalid vitecache save response.');\n throw new MissingDependencyError(missing);\n },\n };\n}\n\n/** A persistent binary computation result. Pass a browser basePath matching the public cache URL, including any Vite base. */\nexport class CacheEntry extends Entry {\n constructor(options: CacheEntryOptions) {\n super(options, createBackend(options));\n }\n}\n"]}
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAA4C,MAAM,YAAY,CAAC;AAG3E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjC,+FAA+F;AAC/F,MAAM,OAAO,UAAU;IACZ,QAAQ,CAAS;IACjB,IAAI,CAAM;IAEnB,YAAY,OAA0B;QACpC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1G,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,8DAA8D;IAC9D,KAAK,CAAC,IAAI;QACR,yFAAyF;QACzF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAS,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACpF,yEAAyE;QACzE,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,SAAS,CAAC;QACpF,OAAO,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,0GAA0G;IAC1G,KAAK,CAAC,IAAI,CAAC,MAAkB,EAAE,QAAsB;QACnD,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO;QACtC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,QAAQ,uDAAuD,CAAC,CAAC;IACnG,CAAC;CACF","sourcesContent":["import { key, type CacheEntryOptions, type SaveOptions } from './entry.js';\nexport type { CacheEntryOptions, Dependency, Input, JsonValue, SaveOptions } from './entry.js';\n\nconst warned = new Set<string>();\n\n/** A cached result, read from the cache directory the app serves. Only Node writes entries. */\nexport class CacheEntry {\n readonly #version: string;\n readonly #url: URL;\n\n constructor(options: CacheEntryOptions) {\n this.#version = options.version;\n const base = new URL((options.basePath ?? '/_vitecache/').replace(/\\/?$/, '/'), globalThis.location.href);\n this.#url = new URL(`${key(options)}.bin`, base);\n }\n\n /** The saved bytes, or undefined when the app serves none. */\n async load(): Promise<Uint8Array | undefined> {\n // An entry keeps its name when its bytes change, so the HTTP cache must revalidate them.\n const response = await fetch(this.#url, { cache: 'no-cache' });\n if (response.status === 404) return undefined;\n if (!response.ok) throw new Error(`vitecache load failed: HTTP ${response.status}`);\n // Vite's dev server and SPA hosts answer a missing file with index.html.\n if (response.headers.get('content-type')?.startsWith('text/html')) return undefined;\n return new Uint8Array(await response.arrayBuffer());\n }\n\n /** Writes nothing, since browsers only read. Warns once per version that its result was computed here. */\n async save(_value: Uint8Array, _options?: SaveOptions): Promise<void> {\n if (warned.has(this.#version)) return;\n warned.add(this.#version);\n console.warn(`vitecache: ${this.#version} was computed in the browser, which does not save it.`);\n }\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { JsonValue } from './entry.js';
2
+ /** A `loadAsync(...args)` of a cached loader that discovery found, which warming repeats on a `new` loader in Node. */
3
+ export interface Load {
4
+ importer: string;
5
+ /** Where in the importer the load is, as `line:column`. */
6
+ position: string;
7
+ source: string;
8
+ name: string;
9
+ args: JsonValue[];
10
+ }
11
+ /**
12
+ * The cached loader loads in a module: `new Loader(...).loadAsync(...)`, or `loadAsync(...)` on a variable initialized
13
+ * with `new Loader(...)`. Any other use of a loader or such a variable fails, since warming could not repeat it.
14
+ */
15
+ export declare function discover(code: string, importer: string): Load[];
@@ -0,0 +1,131 @@
1
+ import JSON5 from 'json5';
2
+ import { parseSync, Visitor } from 'vite';
3
+ /**
4
+ * The convention that marks a class as a cached loader: its loadAsync computes a result once and saves it. Warming
5
+ * constructs it without arguments, so only loadAsync's arguments may select the result.
6
+ */
7
+ const loader = /^Cached\w*Loader$/;
8
+ /**
9
+ * The cached loader loads in a module: `new Loader(...).loadAsync(...)`, or `loadAsync(...)` on a variable initialized
10
+ * with `new Loader(...)`. Any other use of a loader or such a variable fails, since warming could not repeat it.
11
+ */
12
+ export function discover(code, importer) {
13
+ const at = (offset) => {
14
+ const lines = code.slice(0, offset).split('\n');
15
+ return `${lines.length}:${(lines.at(-1)?.length ?? 0) + 1}`;
16
+ };
17
+ const fail = (message, offset) => {
18
+ throw new Error(`${message} at ${importer}:${at(offset)}`);
19
+ };
20
+ const { program, errors } = parseSync(importer, code);
21
+ if (errors[0])
22
+ fail(errors[0].message, errors[0].labels[0]?.start ?? 0);
23
+ const imports = new Map();
24
+ const namespaces = new Map();
25
+ for (const statement of program.body) {
26
+ if (statement.type !== 'ImportDeclaration')
27
+ continue;
28
+ for (const specifier of statement.specifiers) {
29
+ if (specifier.type === 'ImportNamespaceSpecifier')
30
+ namespaces.set(specifier.local.name, statement.source.value);
31
+ if (specifier.type !== 'ImportSpecifier')
32
+ continue;
33
+ const name = specifier.imported.type === 'Literal' ? specifier.imported.value : specifier.imported.name;
34
+ if (loader.test(name))
35
+ imports.set(specifier.local.name, { source: statement.source.value, name });
36
+ }
37
+ }
38
+ /** Nodes that name a loader or loader variable without using its value. */
39
+ const allowed = new Set();
40
+ // JSON5 is the literal subset of JavaScript: unquoted keys, single quotes, signed numbers.
41
+ const literal = (node) => {
42
+ try {
43
+ return JSON5.parse(code.slice(node.start, node.end));
44
+ }
45
+ catch {
46
+ return fail('Cached loader loadAsync arguments must be literal JSON', node.start);
47
+ }
48
+ };
49
+ const target = (node) => {
50
+ if (node.type === 'Identifier')
51
+ return imports.get(node.name);
52
+ if (node.type !== 'MemberExpression' || node.computed || node.object.type !== 'Identifier')
53
+ return undefined;
54
+ const source = namespaces.get(node.object.name);
55
+ return source !== undefined && loader.test(node.property.name) ? { source, name: node.property.name } : undefined;
56
+ };
57
+ const created = (node) => {
58
+ const loaded = target(node.callee);
59
+ if (loaded)
60
+ allowed.add(node.callee);
61
+ return loaded;
62
+ };
63
+ // A first pass, since a variable can be used above its declaration, as in a function declared earlier.
64
+ const instances = new Map();
65
+ new Visitor({
66
+ VariableDeclarator(node) {
67
+ if (node.id.type !== 'Identifier' || node.init?.type !== 'NewExpression')
68
+ return;
69
+ const instance = created(node.init);
70
+ if (!instance)
71
+ return;
72
+ instances.set(node.id.name, instance);
73
+ allowed.add(node.id);
74
+ },
75
+ }).visit(program);
76
+ const member = (node) => {
77
+ if (!node.computed)
78
+ allowed.add(node.key);
79
+ };
80
+ const misused = (node) => fail('Use cached loaders only as new Loader().loadAsync(), or a variable of one', node.start);
81
+ const loads = [];
82
+ new Visitor({
83
+ ImportSpecifier: (node) => allowed.add(node.local).add(node.imported),
84
+ // Loads through an exported loader variable happen in other modules, out of discovery's reach.
85
+ ExportSpecifier(node) {
86
+ if (node.local.type === 'Identifier' && instances.has(node.local.name))
87
+ misused(node);
88
+ allowed.add(node.local).add(node.exported);
89
+ },
90
+ ExportNamedDeclaration(node) {
91
+ if (node.declaration?.type !== 'VariableDeclaration')
92
+ return;
93
+ for (const { id } of node.declaration.declarations)
94
+ if (id.type === 'Identifier' && instances.has(id.name))
95
+ misused(id);
96
+ },
97
+ Property(node) {
98
+ if (!node.shorthand)
99
+ member(node);
100
+ },
101
+ MethodDefinition: member,
102
+ PropertyDefinition: member,
103
+ CallExpression(node) {
104
+ const { callee } = node;
105
+ if (callee.type !== 'MemberExpression' || callee.computed || callee.property.name !== 'loadAsync')
106
+ return;
107
+ const { object } = callee;
108
+ const instance = object.type === 'NewExpression'
109
+ ? created(object)
110
+ : object.type === 'Identifier'
111
+ ? instances.get(object.name)
112
+ : undefined;
113
+ if (!instance)
114
+ return;
115
+ allowed.add(object);
116
+ loads.push({ importer, position: at(node.start), ...instance, args: node.arguments.map(literal) });
117
+ },
118
+ MemberExpression(node) {
119
+ if (!node.computed)
120
+ allowed.add(node.property);
121
+ if (target(node) && !allowed.has(node))
122
+ misused(node);
123
+ },
124
+ Identifier(node) {
125
+ if ((imports.has(node.name) || instances.has(node.name)) && !allowed.has(node))
126
+ misused(node);
127
+ },
128
+ }).visit(program);
129
+ return loads;
130
+ }
131
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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","sourcesContent":["import JSON5 from 'json5';\nimport { parseSync, Visitor, type ESTree } from 'vite';\nimport type { JsonValue } from './entry.js';\n\n/** A `loadAsync(...args)` of a cached loader that discovery found, which warming repeats on a `new` loader in Node. */\nexport interface Load {\n importer: string;\n /** Where in the importer the load is, as `line:column`. */\n position: string;\n source: string;\n name: string;\n args: JsonValue[];\n}\n\n/**\n * The convention that marks a class as a cached loader: its loadAsync computes a result once and saves it. Warming\n * constructs it without arguments, so only loadAsync's arguments may select the result.\n */\nconst loader = /^Cached\\w*Loader$/;\n\n/**\n * The cached loader loads in a module: `new Loader(...).loadAsync(...)`, or `loadAsync(...)` on a variable initialized\n * with `new Loader(...)`. Any other use of a loader or such a variable fails, since warming could not repeat it.\n */\nexport function discover(code: string, importer: string): Load[] {\n const at = (offset: number) => {\n const lines = code.slice(0, offset).split('\\n');\n return `${lines.length}:${(lines.at(-1)?.length ?? 0) + 1}`;\n };\n const fail = (message: string, offset: number): never => {\n throw new Error(`${message} at ${importer}:${at(offset)}`);\n };\n const { program, errors } = parseSync(importer, code);\n if (errors[0]) fail(errors[0].message, errors[0].labels[0]?.start ?? 0);\n const imports = new Map<string, { source: string; name: string }>();\n const namespaces = new Map<string, string>();\n for (const statement of program.body) {\n if (statement.type !== 'ImportDeclaration') continue;\n for (const specifier of statement.specifiers) {\n if (specifier.type === 'ImportNamespaceSpecifier') namespaces.set(specifier.local.name, statement.source.value);\n if (specifier.type !== 'ImportSpecifier') continue;\n const name = specifier.imported.type === 'Literal' ? specifier.imported.value : specifier.imported.name;\n if (loader.test(name)) imports.set(specifier.local.name, { source: statement.source.value, name });\n }\n }\n /** Nodes that name a loader or loader variable without using its value. */\n const allowed = new Set<ESTree.Node>();\n // JSON5 is the literal subset of JavaScript: unquoted keys, single quotes, signed numbers.\n const literal = (node: ESTree.Argument) => {\n try {\n return JSON5.parse<JsonValue>(code.slice(node.start, node.end));\n } catch {\n return fail('Cached loader loadAsync arguments must be literal JSON', node.start);\n }\n };\n const target = (node: ESTree.Node) => {\n if (node.type === 'Identifier') return imports.get(node.name);\n if (node.type !== 'MemberExpression' || node.computed || node.object.type !== 'Identifier') return undefined;\n const source = namespaces.get(node.object.name);\n return source !== undefined && loader.test(node.property.name) ? { source, name: node.property.name } : undefined;\n };\n const created = (node: ESTree.NewExpression) => {\n const loaded = target(node.callee);\n if (loaded) allowed.add(node.callee);\n return loaded;\n };\n // A first pass, since a variable can be used above its declaration, as in a function declared earlier.\n const instances = new Map<string, { source: string; name: string }>();\n new Visitor({\n VariableDeclarator(node) {\n if (node.id.type !== 'Identifier' || node.init?.type !== 'NewExpression') return;\n const instance = created(node.init);\n if (!instance) return;\n instances.set(node.id.name, instance);\n allowed.add(node.id);\n },\n }).visit(program);\n const member = (node: { computed: boolean; key: ESTree.Node }) => {\n if (!node.computed) allowed.add(node.key);\n };\n const misused = (node: ESTree.Node) =>\n fail('Use cached loaders only as new Loader().loadAsync(), or a variable of one', node.start);\n const loads: Load[] = [];\n new Visitor({\n ImportSpecifier: (node) => allowed.add(node.local).add(node.imported),\n // Loads through an exported loader variable happen in other modules, out of discovery's reach.\n ExportSpecifier(node) {\n if (node.local.type === 'Identifier' && instances.has(node.local.name)) misused(node);\n allowed.add(node.local).add(node.exported);\n },\n ExportNamedDeclaration(node) {\n if (node.declaration?.type !== 'VariableDeclaration') return;\n for (const { id } of node.declaration.declarations)\n if (id.type === 'Identifier' && instances.has(id.name)) misused(id);\n },\n Property(node) {\n if (!node.shorthand) member(node);\n },\n MethodDefinition: member,\n PropertyDefinition: member,\n CallExpression(node) {\n const { callee } = node;\n if (callee.type !== 'MemberExpression' || callee.computed || callee.property.name !== 'loadAsync') return;\n const { object } = callee;\n const instance =\n object.type === 'NewExpression'\n ? created(object)\n : object.type === 'Identifier'\n ? instances.get(object.name)\n : undefined;\n if (!instance) return;\n allowed.add(object);\n loads.push({ importer, position: at(node.start), ...instance, args: node.arguments.map(literal) });\n },\n MemberExpression(node) {\n if (!node.computed) allowed.add(node.property);\n if (target(node) && !allowed.has(node)) misused(node);\n },\n Identifier(node) {\n if ((imports.has(node.name) || instances.has(node.name)) && !allowed.has(node)) misused(node);\n },\n }).visit(program);\n return loads;\n}\n"]}
package/dist/disk.d.ts CHANGED
@@ -1,27 +1,3 @@
1
- import type { CacheEntryOptions } from './types.js';
2
1
  export declare function missing(error: unknown): boolean;
3
- /** A filesystem error for a path that does not exist, also below a path component that is a file. */
4
- export declare function notFound(error: unknown): boolean;
5
- /** Whether `path` is `root` or below it, compared lexically. */
6
- export declare function inside(root: string, path: string): boolean;
7
- /**
8
- * `file` relative to `root`, with `/` separators. A file that lies outside `root` only lexically, as through a symlinked
9
- * root, is related by real paths instead.
10
- */
11
- export declare function rootRelative(root: string, file: string): Promise<string>;
12
- export declare function location(options: Pick<CacheEntryOptions, 'root' | 'basePath'>): {
13
- root: string;
14
- directory: string;
15
- };
16
- export declare function ignore(root: string, directory: string): Promise<void>;
17
- /**
18
- * A file's bytes as a plain Uint8Array that owns its whole ArrayBuffer, as a browser's response gives them. A Buffer's
19
- * slice() shares its memory, so a slice whose buffer is transferred to a worker would detach the bytes it came from.
20
- */
21
- export declare function load(path: string): Promise<Uint8Array | undefined>;
22
- export declare function save(path: string, value: Uint8Array, beforeCommit?: () => Promise<void>): Promise<void>;
23
- /**
24
- * Sets a file's modification time to now; a file that no longer exists is left alone. Where this process may not change
25
- * it, as on a read-only deployment, it warns once per directory instead of failing the read that called it.
26
- */
27
- export declare function touch(path: string): Promise<void>;
2
+ /** The file's bytes, or undefined when it does not exist. */
3
+ export declare function read(path: string): Promise<Uint8Array | undefined>;