@absolutejs/absolute 0.20.0-beta.155 → 0.20.0-beta.157

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.
@@ -0,0 +1,215 @@
1
+ // @bun
2
+ // src/runtime/clientAssetArchive.ts
3
+ import {
4
+ mkdir,
5
+ readdir,
6
+ readFile,
7
+ rename,
8
+ rm,
9
+ stat,
10
+ writeFile
11
+ } from "fs/promises";
12
+ import { dirname, join, resolve } from "path";
13
+ import { randomUUID } from "crypto";
14
+ var PREFIX = "/_absolute/assets/";
15
+ var GRAPH_ID = /^[a-f0-9]{64}$/;
16
+ var MAX_GRAPHS = 3;
17
+ var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
18
+ var MAX_BYTES = 512 * 1024 * 1024;
19
+ var safePath = (path) => path.length > 0 && !path.includes("\\") && !path.includes("\x00") && path.split("/").every((part) => part.length > 0 && part !== "." && part !== "..");
20
+ var sequentially = (items, action) => items.reduce((pending, value) => pending.then(() => action(value)), Promise.resolve());
21
+ var readManifest = async (directory) => {
22
+ try {
23
+ const value = JSON.parse(await readFile(join(directory, "graph.json"), "utf8"));
24
+ if (!value || typeof value !== "object")
25
+ return;
26
+ const createdAt = Reflect.get(value, "createdAt");
27
+ const bytes = Reflect.get(value, "bytes");
28
+ const paths = Reflect.get(value, "paths");
29
+ const retiredAt = Reflect.get(value, "retiredAt");
30
+ if (retiredAt !== undefined && (typeof retiredAt !== "number" || !Number.isFinite(retiredAt)))
31
+ return;
32
+ if (typeof createdAt !== "number" || !Number.isFinite(createdAt) || typeof bytes !== "number" || !Number.isSafeInteger(bytes) || bytes < 0 || !Array.isArray(paths) || !paths.every((path) => typeof path === "string" && safePath(path)))
33
+ return;
34
+ const manifest = {
35
+ bytes,
36
+ createdAt,
37
+ paths,
38
+ ...typeof retiredAt === "number" ? { retiredAt } : {}
39
+ };
40
+ return manifest;
41
+ } catch {
42
+ return;
43
+ }
44
+ };
45
+ var commitGraph = async (temporary, destination) => {
46
+ try {
47
+ await rename(temporary, destination);
48
+ } catch (error) {
49
+ if (!await readManifest(destination))
50
+ throw error;
51
+ }
52
+ };
53
+ var sourceFile = (source) => typeof source === "string" ? Bun.file(source) : source;
54
+ var graphBytes = (entries) => entries.reduce((bytes, [, source]) => bytes + sourceFile(source).size, 0);
55
+ var publishGraph = async (directory, id, entries, now) => {
56
+ const destination = join(directory, id);
57
+ if (await readManifest(destination))
58
+ return;
59
+ const bytes = graphBytes(entries);
60
+ if (bytes > MAX_BYTES)
61
+ throw new Error("Client asset graph exceeds archive byte limit");
62
+ const temporary = join(directory, `.pending-${randomUUID()}`);
63
+ const manifest = {
64
+ bytes,
65
+ createdAt: now,
66
+ paths: entries.map(([path]) => path)
67
+ };
68
+ try {
69
+ await sequentially(entries, async ([path, source]) => {
70
+ const target = join(temporary, "files", path);
71
+ await mkdir(dirname(target), { recursive: true });
72
+ await Bun.write(target, sourceFile(source));
73
+ });
74
+ await writeFile(join(temporary, "graph.json"), JSON.stringify(manifest));
75
+ await commitGraph(temporary, destination);
76
+ } finally {
77
+ await rm(temporary, { force: true, recursive: true });
78
+ }
79
+ };
80
+ var cleanAbandonedStage = async (path, now) => {
81
+ if (now - (await stat(path)).mtimeMs <= MAX_AGE_MS)
82
+ return;
83
+ await rm(path, { force: true, recursive: true });
84
+ };
85
+ var listGraphs = async (directory, now) => {
86
+ const graphs = [];
87
+ await sequentially(await readdir(directory, { withFileTypes: true }), async (entry) => {
88
+ if (!entry.isDirectory())
89
+ return;
90
+ const path = join(directory, entry.name);
91
+ if (/^\.pending-[a-f0-9-]+$/.test(entry.name)) {
92
+ await cleanAbandonedStage(path, now);
93
+ return;
94
+ }
95
+ if (!GRAPH_ID.test(entry.name))
96
+ return;
97
+ const manifest = await readManifest(path);
98
+ if (manifest)
99
+ graphs.push({ id: entry.name, manifest });
100
+ });
101
+ return graphs;
102
+ };
103
+ var atomicArchiveJson = async (directory, target, value) => {
104
+ const temporary = join(directory, `.pending-${randomUUID()}`);
105
+ await mkdir(temporary);
106
+ try {
107
+ const source = join(temporary, "data.json");
108
+ await writeFile(source, JSON.stringify(value));
109
+ await rename(source, target);
110
+ } finally {
111
+ await rm(temporary, { force: true, recursive: true });
112
+ }
113
+ };
114
+ var readActiveGraphs = async (directory) => {
115
+ try {
116
+ const value = JSON.parse(await readFile(join(directory, "active.json"), "utf8"));
117
+ return Array.isArray(value) ? value.filter((id) => typeof id === "string" && GRAPH_ID.test(id)) : [];
118
+ } catch {
119
+ return [];
120
+ }
121
+ };
122
+ var recordActivation = async (directory, current, now) => {
123
+ const previous = await readActiveGraphs(directory);
124
+ await sequentially(previous.filter((id) => !current.has(id)), async (id) => {
125
+ const path = join(directory, id);
126
+ const manifest = await readManifest(path);
127
+ if (!manifest || manifest.retiredAt !== undefined)
128
+ return;
129
+ await atomicArchiveJson(directory, join(path, "graph.json"), {
130
+ ...manifest,
131
+ retiredAt: now
132
+ });
133
+ });
134
+ await sequentially([...current], async (id) => {
135
+ const path = join(directory, id);
136
+ const manifest = await readManifest(path);
137
+ if (!manifest || manifest.retiredAt === undefined)
138
+ return;
139
+ const active = {
140
+ bytes: manifest.bytes,
141
+ createdAt: manifest.createdAt,
142
+ paths: manifest.paths
143
+ };
144
+ await atomicArchiveJson(directory, join(path, "graph.json"), active);
145
+ });
146
+ await atomicArchiveJson(directory, join(directory, "active.json"), [
147
+ ...current
148
+ ]);
149
+ };
150
+ var retentionTime = (graph) => graph.manifest.retiredAt ?? graph.manifest.createdAt;
151
+ var collectGraphs = (assets) => {
152
+ const groups = new Map;
153
+ for (const [url, file] of Object.entries(assets)) {
154
+ if (!url.startsWith(PREFIX))
155
+ continue;
156
+ const [id, ...parts] = url.slice(PREFIX.length).split("/");
157
+ const path = parts.join("/");
158
+ if (!id || !GRAPH_ID.test(id) || !safePath(path))
159
+ continue;
160
+ const group = groups.get(id) ?? [];
161
+ group.push([path, file]);
162
+ groups.set(id, group);
163
+ }
164
+ return groups;
165
+ };
166
+ var findRetainedAsset = async (directory, retained, pathname) => {
167
+ if (!pathname.startsWith(PREFIX))
168
+ return;
169
+ const [id, ...parts] = pathname.slice(PREFIX.length).split("/");
170
+ const path = parts.join("/");
171
+ if (!id || !safePath(path) || !retained.get(id)?.has(path))
172
+ return;
173
+ const file = join(directory, id, "files", path);
174
+ try {
175
+ if (!(await stat(file)).isFile())
176
+ return;
177
+ } catch {
178
+ return;
179
+ }
180
+ return Bun.file(file);
181
+ };
182
+ var createClientAssetArchive = async (assets, directory = resolve(process.env.ABSOLUTE_ASSET_ARCHIVE_DIR || ".absolutejs/client-assets"), now = Date.now()) => {
183
+ const groups = collectGraphs(assets);
184
+ const currentBytes = [...groups.values()].reduce((bytes, entries) => bytes + graphBytes(entries), 0);
185
+ if (currentBytes > MAX_BYTES || groups.size > MAX_GRAPHS)
186
+ throw new Error("Current client graphs exceed archive limits");
187
+ await mkdir(directory, { recursive: true });
188
+ await sequentially([...groups], ([id, entries]) => publishGraph(directory, id, entries, now));
189
+ await recordActivation(directory, new Set(groups.keys()), now);
190
+ const graphs = await listGraphs(directory, now);
191
+ graphs.sort((a, b) => Number(groups.has(b.id)) - Number(groups.has(a.id)) || retentionTime(b) - retentionTime(a));
192
+ let bytes = 0;
193
+ let count = 0;
194
+ const retained = new Map;
195
+ await sequentially(graphs, async (graph) => {
196
+ const expired = now - retentionTime(graph) > MAX_AGE_MS;
197
+ if (!groups.has(graph.id) && (expired || count >= MAX_GRAPHS || bytes + graph.manifest.bytes > MAX_BYTES)) {
198
+ await rm(join(directory, graph.id), {
199
+ force: true,
200
+ recursive: true
201
+ });
202
+ return;
203
+ }
204
+ count++;
205
+ bytes += graph.manifest.bytes;
206
+ retained.set(graph.id, new Set(graph.manifest.paths));
207
+ });
208
+ return (pathname) => findRetainedAsset(directory, retained, pathname);
209
+ };
210
+ export {
211
+ createClientAssetArchive
212
+ };
213
+
214
+ //# debugId=7C1C3482FC40FA1B64756E2164756E21
215
+ //# sourceMappingURL=clientAssetArchive.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/runtime/clientAssetArchive.ts"],
4
+ "sourcesContent": [
5
+ "import {\n\tmkdir,\n\treaddir,\n\treadFile,\n\trename,\n\trm,\n\tstat,\n\twriteFile\n} from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { randomUUID } from 'node:crypto';\n\nconst PREFIX = '/_absolute/assets/';\nconst GRAPH_ID = /^[a-f0-9]{64}$/;\nconst MAX_GRAPHS = 3;\nconst MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\nconst MAX_BYTES = 512 * 1024 * 1024;\n\ntype GraphManifest = {\n\tbytes: number;\n\tcreatedAt: number;\n\tpaths: string[];\n\tretiredAt?: number;\n};\ntype StoredGraph = { id: string; manifest: GraphManifest };\ntype AssetEntry = [string, string | Blob];\nconst safePath = (path: string) =>\n\tpath.length > 0 &&\n\t!path.includes('\\\\') &&\n\t!path.includes('\\0') &&\n\tpath\n\t\t.split('/')\n\t\t.every((part) => part.length > 0 && part !== '.' && part !== '..');\nconst sequentially = <Value>(\n\titems: Value[],\n\taction: (value: Value) => Promise<void>\n) =>\n\titems.reduce<Promise<void>>(\n\t\t(pending, value) => pending.then(() => action(value)),\n\t\tPromise.resolve()\n\t);\n\nconst readManifest = async (directory: string) => {\n\ttry {\n\t\tconst value: unknown = JSON.parse(\n\t\t\tawait readFile(join(directory, 'graph.json'), 'utf8')\n\t\t);\n\t\tif (!value || typeof value !== 'object') return undefined;\n\t\tconst createdAt: unknown = Reflect.get(value, 'createdAt');\n\t\tconst bytes: unknown = Reflect.get(value, 'bytes');\n\t\tconst paths: unknown = Reflect.get(value, 'paths');\n\t\tconst retiredAt: unknown = Reflect.get(value, 'retiredAt');\n\t\tif (\n\t\t\tretiredAt !== undefined &&\n\t\t\t(typeof retiredAt !== 'number' || !Number.isFinite(retiredAt))\n\t\t)\n\t\t\treturn undefined;\n\t\tif (\n\t\t\ttypeof createdAt !== 'number' ||\n\t\t\t!Number.isFinite(createdAt) ||\n\t\t\ttypeof bytes !== 'number' ||\n\t\t\t!Number.isSafeInteger(bytes) ||\n\t\t\tbytes < 0 ||\n\t\t\t!Array.isArray(paths) ||\n\t\t\t!paths.every(\n\t\t\t\t(path): path is string =>\n\t\t\t\t\ttypeof path === 'string' && safePath(path)\n\t\t\t)\n\t\t)\n\t\t\treturn undefined;\n\t\tconst manifest: GraphManifest = {\n\t\t\tbytes,\n\t\t\tcreatedAt,\n\t\t\tpaths,\n\t\t\t...(typeof retiredAt === 'number' ? { retiredAt } : {})\n\t\t};\n\n\t\treturn manifest;\n\t} catch {\n\t\treturn undefined;\n\t}\n};\n\nconst commitGraph = async (temporary: string, destination: string) => {\n\ttry {\n\t\tawait rename(temporary, destination);\n\t} catch (error) {\n\t\tif (!(await readManifest(destination))) throw error;\n\t}\n};\n\nconst sourceFile = (source: string | Blob) =>\n\ttypeof source === 'string' ? Bun.file(source) : source;\nconst graphBytes = (entries: AssetEntry[]) =>\n\tentries.reduce((bytes, [, source]) => bytes + sourceFile(source).size, 0);\nconst publishGraph = async (\n\tdirectory: string,\n\tid: string,\n\tentries: AssetEntry[],\n\tnow: number\n) => {\n\tconst destination = join(directory, id);\n\tif (await readManifest(destination)) return;\n\tconst bytes = graphBytes(entries);\n\tif (bytes > MAX_BYTES)\n\t\tthrow new Error('Client asset graph exceeds archive byte limit');\n\tconst temporary = join(directory, `.pending-${randomUUID()}`);\n\tconst manifest: GraphManifest = {\n\t\tbytes,\n\t\tcreatedAt: now,\n\t\tpaths: entries.map(([path]) => path)\n\t};\n\ttry {\n\t\tawait sequentially(entries, async ([path, source]) => {\n\t\t\tconst target = join(temporary, 'files', path);\n\t\t\tawait mkdir(dirname(target), { recursive: true });\n\t\t\tawait Bun.write(target, sourceFile(source));\n\t\t});\n\t\tawait writeFile(\n\t\t\tjoin(temporary, 'graph.json'),\n\t\t\tJSON.stringify(manifest)\n\t\t);\n\t\tawait commitGraph(temporary, destination);\n\t} finally {\n\t\tawait rm(temporary, { force: true, recursive: true });\n\t}\n};\n\nconst cleanAbandonedStage = async (path: string, now: number) => {\n\tif (now - (await stat(path)).mtimeMs <= MAX_AGE_MS) return;\n\tawait rm(path, { force: true, recursive: true });\n};\n\nconst listGraphs = async (directory: string, now: number) => {\n\tconst graphs: StoredGraph[] = [];\n\tawait sequentially(\n\t\tawait readdir(directory, { withFileTypes: true }),\n\t\tasync (entry) => {\n\t\t\tif (!entry.isDirectory()) return;\n\t\t\tconst path = join(directory, entry.name);\n\t\t\tif (/^\\.pending-[a-f0-9-]+$/.test(entry.name)) {\n\t\t\t\tawait cleanAbandonedStage(path, now);\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!GRAPH_ID.test(entry.name)) return;\n\t\t\tconst manifest = await readManifest(path);\n\t\t\tif (manifest) graphs.push({ id: entry.name, manifest });\n\t\t}\n\t);\n\n\treturn graphs;\n};\n\nconst atomicArchiveJson = async (\n\tdirectory: string,\n\ttarget: string,\n\tvalue: unknown\n) => {\n\tconst temporary = join(directory, `.pending-${randomUUID()}`);\n\tawait mkdir(temporary);\n\ttry {\n\t\tconst source = join(temporary, 'data.json');\n\t\tawait writeFile(source, JSON.stringify(value));\n\t\tawait rename(source, target);\n\t} finally {\n\t\tawait rm(temporary, { force: true, recursive: true });\n\t}\n};\n\nconst readActiveGraphs = async (directory: string) => {\n\ttry {\n\t\tconst value: unknown = JSON.parse(\n\t\t\tawait readFile(join(directory, 'active.json'), 'utf8')\n\t\t);\n\n\t\treturn Array.isArray(value)\n\t\t\t? value.filter(\n\t\t\t\t\t(id): id is string =>\n\t\t\t\t\t\ttypeof id === 'string' && GRAPH_ID.test(id)\n\t\t\t\t)\n\t\t\t: [];\n\t} catch {\n\t\treturn [];\n\t}\n};\n\nconst recordActivation = async (\n\tdirectory: string,\n\tcurrent: Set<string>,\n\tnow: number\n) => {\n\tconst previous = await readActiveGraphs(directory);\n\tawait sequentially(\n\t\tprevious.filter((id) => !current.has(id)),\n\t\tasync (id) => {\n\t\t\tconst path = join(directory, id);\n\t\t\tconst manifest = await readManifest(path);\n\t\t\tif (!manifest || manifest.retiredAt !== undefined) return;\n\t\t\tawait atomicArchiveJson(directory, join(path, 'graph.json'), {\n\t\t\t\t...manifest,\n\t\t\t\tretiredAt: now\n\t\t\t});\n\t\t}\n\t);\n\tawait sequentially([...current], async (id) => {\n\t\tconst path = join(directory, id);\n\t\tconst manifest = await readManifest(path);\n\t\tif (!manifest || manifest.retiredAt === undefined) return;\n\t\tconst active: GraphManifest = {\n\t\t\tbytes: manifest.bytes,\n\t\t\tcreatedAt: manifest.createdAt,\n\t\t\tpaths: manifest.paths\n\t\t};\n\t\tawait atomicArchiveJson(directory, join(path, 'graph.json'), active);\n\t});\n\tawait atomicArchiveJson(directory, join(directory, 'active.json'), [\n\t\t...current\n\t]);\n};\n\nconst retentionTime = (graph: StoredGraph) =>\n\tgraph.manifest.retiredAt ?? graph.manifest.createdAt;\n\nconst collectGraphs = (assets: Record<string, string | Blob>) => {\n\tconst groups = new Map<string, AssetEntry[]>();\n\tfor (const [url, file] of Object.entries(assets)) {\n\t\tif (!url.startsWith(PREFIX)) continue;\n\t\tconst [id, ...parts] = url.slice(PREFIX.length).split('/');\n\t\tconst path = parts.join('/');\n\t\tif (!id || !GRAPH_ID.test(id) || !safePath(path)) continue;\n\t\tconst group = groups.get(id) ?? [];\n\t\tgroup.push([path, file]);\n\t\tgroups.set(id, group);\n\t}\n\n\treturn groups;\n};\n\nconst findRetainedAsset = async (\n\tdirectory: string,\n\tretained: Map<string, Set<string>>,\n\tpathname: string\n) => {\n\tif (!pathname.startsWith(PREFIX)) return undefined;\n\tconst [id, ...parts] = pathname.slice(PREFIX.length).split('/');\n\tconst path = parts.join('/');\n\tif (!id || !safePath(path) || !retained.get(id)?.has(path))\n\t\treturn undefined;\n\tconst file = join(directory, id, 'files', path);\n\ttry {\n\t\tif (!(await stat(file)).isFile()) return undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\treturn Bun.file(file);\n};\n\n/** Persist only explicitly namespaced browser assets in a directory shared by\n * releases. Atomic publication preserves previous graphs on failure; sequential\n * writes bound memory. Current assets are always served from the executable.\n */\nexport const createClientAssetArchive = async (\n\tassets: Record<string, string | Blob>,\n\tdirectory = resolve(\n\t\tprocess.env.ABSOLUTE_ASSET_ARCHIVE_DIR || '.absolutejs/client-assets'\n\t),\n\tnow = Date.now()\n) => {\n\tconst groups = collectGraphs(assets);\n\tconst currentBytes = [...groups.values()].reduce(\n\t\t(bytes, entries) => bytes + graphBytes(entries),\n\t\t0\n\t);\n\tif (currentBytes > MAX_BYTES || groups.size > MAX_GRAPHS)\n\t\tthrow new Error('Current client graphs exceed archive limits');\n\tawait mkdir(directory, { recursive: true });\n\tawait sequentially([...groups], ([id, entries]) =>\n\t\tpublishGraph(directory, id, entries, now)\n\t);\n\tawait recordActivation(directory, new Set(groups.keys()), now);\n\tconst graphs = await listGraphs(directory, now);\n\tgraphs.sort(\n\t\t(a, b) =>\n\t\t\tNumber(groups.has(b.id)) - Number(groups.has(a.id)) ||\n\t\t\tretentionTime(b) - retentionTime(a)\n\t);\n\tlet bytes = 0;\n\tlet count = 0;\n\tconst retained = new Map<string, Set<string>>();\n\tawait sequentially(graphs, async (graph) => {\n\t\tconst expired = now - retentionTime(graph) > MAX_AGE_MS;\n\t\tif (\n\t\t\t!groups.has(graph.id) &&\n\t\t\t(expired ||\n\t\t\t\tcount >= MAX_GRAPHS ||\n\t\t\t\tbytes + graph.manifest.bytes > MAX_BYTES)\n\t\t) {\n\t\t\tawait rm(join(directory, graph.id), {\n\t\t\t\tforce: true,\n\t\t\t\trecursive: true\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\t\tcount++;\n\t\tbytes += graph.manifest.bytes;\n\t\tretained.set(graph.id, new Set(graph.manifest.paths));\n\t});\n\n\treturn (pathname: string) =>\n\t\tfindRetainedAsset(directory, retained, pathname);\n};\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "7C1C3482FC40FA1B64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,7 @@
1
+ export declare const CLIENT_GRAPH_PREFIX = "/_absolute/assets/";
2
+ export declare const isClientGraphAsset: (path: string) => boolean;
3
+ /** Namespace the complete browser graph, including stable vendor filenames.
4
+ * Relative imports stay within the graph. Original URLs remain current-release
5
+ * aliases; application strings, API paths and SW registration scopes stay intact.
6
+ */
7
+ export declare const prepareCompiledClientGraph: (directory: string, serverBundle: string, publicDirectory?: string) => string;
@@ -0,0 +1,5 @@
1
+ /** Persist only explicitly namespaced browser assets in a directory shared by
2
+ * releases. Atomic publication preserves previous graphs on failure; sequential
3
+ * writes bound memory. Current assets are always served from the executable.
4
+ */
5
+ export declare const createClientAssetArchive: (assets: Record<string, string | Blob>, directory?: string, now?: number) => Promise<(pathname: string) => Promise<Bun.BunFile | undefined>>;
package/package.json CHANGED
@@ -563,7 +563,7 @@
563
563
  ]
564
564
  }
565
565
  },
566
- "version": "0.20.0-beta.155",
566
+ "version": "0.20.0-beta.157",
567
567
  "workspaces": [
568
568
  "tests/fixtures/*",
569
569
  "tests/fixtures/_packages/*"
@@ -1,108 +0,0 @@
1
- // @bun
2
- import {
3
- SENTINEL,
4
- maskLiterals
5
- } from "./index-039rh39e.js";
6
-
7
- // src/build/specifierRewriter.ts
8
- var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9
- var PLACEHOLDER = `${SENTINEL}\\d+${SENTINEL}`;
10
- var GAP = `(?:\\s|${PLACEHOLDER}|/\\*${PLACEHOLDER}\\*/|//${PLACEHOLDER})*`;
11
- var QUOTE = `["']`;
12
- var ADJACENT_PREFIXES = [`from\\s*${QUOTE}`, `import\\s*${QUOTE}`];
13
- var ADJACENT_DYNAMIC_PREFIX = `import\\s*\\(\\s*${QUOTE}`;
14
- var ADJACENT_DYNAMIC_SUFFIX = `${QUOTE}\\s*\\)`;
15
- var SWEEP_PREFIXES = [
16
- `\\bfrom${GAP}${QUOTE}`,
17
- `\\bimport${GAP}${QUOTE}`,
18
- `\\b(?:import|require)${GAP}\\(${GAP}${QUOTE}`
19
- ];
20
- var rewriterCache = new Map;
21
- var cacheKey = (vendorPaths) => Object.entries(vendorPaths).sort(([left], [right]) => left.localeCompare(right)).map(([specifier, webPath]) => `${specifier}\x00${webPath}\x00`).join("");
22
- var compileRegex = (prefixes, alternation, withAdjacentDynamic) => {
23
- const plain = `(${prefixes.join("|")})(${alternation})(${QUOTE})`;
24
- if (!withAdjacentDynamic)
25
- return new RegExp(plain, "g");
26
- const dynamic = `(${ADJACENT_DYNAMIC_PREFIX})(${alternation})(${ADJACENT_DYNAMIC_SUFFIX})`;
27
- return new RegExp(`${plain}|${dynamic}`, "g");
28
- };
29
- var compileSpecifierRewriter = (vendorPaths) => {
30
- const key = cacheKey(vendorPaths);
31
- const cached = rewriterCache.get(key);
32
- if (cached)
33
- return cached;
34
- const replacements = Object.entries(vendorPaths).sort(([specA], [specB]) => specB.length - specA.length);
35
- const alternation = replacements.map(([specifier]) => escapeRegex(specifier)).join("|");
36
- const rewriter = {
37
- lookup: new Map(replacements),
38
- mainRegex: compileRegex(ADJACENT_PREFIXES, alternation, true),
39
- quotedSpecifiers: replacements.flatMap(([specifier]) => [
40
- `"${specifier}`,
41
- `'${specifier}`
42
- ]),
43
- sweepRegex: compileRegex(SWEEP_PREFIXES, alternation, false),
44
- unionRegex: compileRegex([...ADJACENT_PREFIXES, ...SWEEP_PREFIXES], alternation, true)
45
- };
46
- rewriterCache.set(key, rewriter);
47
- return rewriter;
48
- };
49
- var hasSpecifierCandidate = (content, rewriter) => rewriter.quotedSpecifiers.some((quoted) => content.includes(quoted));
50
- var asGroup = (value) => typeof value === "string" ? value : undefined;
51
- var replaceSpecifier = (lookup) => (match, ...groups) => {
52
- const [prefixA, specA, suffixA, prefixB, specB, suffixB] = groups;
53
- const prefix = asGroup(prefixA) ?? asGroup(prefixB);
54
- const specifier = asGroup(specA) ?? asGroup(specB);
55
- const suffix = asGroup(suffixA) ?? asGroup(suffixB);
56
- if (prefix === undefined || specifier === undefined || suffix === undefined)
57
- return match;
58
- const webPath = lookup.get(specifier);
59
- return webPath === undefined ? match : `${prefix}${webPath}${suffix}`;
60
- };
61
- var rewriteContentSpecifiers = (content, rewriter, options) => {
62
- if (!hasSpecifierCandidate(content, rewriter))
63
- return content;
64
- const { masked, restore } = maskLiterals(content);
65
- return restore(rewriteSpecifiers(masked, rewriter, options));
66
- };
67
- var rewriteSpecifiers = (masked, rewriter, options) => masked.replace(options.sweep ? rewriter.unionRegex : rewriter.mainRegex, replaceSpecifier(rewriter.lookup));
68
-
69
- // src/build/rewriteImportsPlugin.ts
70
- var rewriteImportsInContent = (content, vendorPaths) => {
71
- if (Object.keys(vendorPaths).length === 0)
72
- return content;
73
- return rewriteContentSpecifiers(content, compileSpecifierRewriter(vendorPaths), { sweep: false });
74
- };
75
-
76
- // src/build/rewriteImports.ts
77
- var rewriteImports = async (outputPaths, vendorPaths) => {
78
- const jsFiles = outputPaths.filter((path) => path.endsWith(".js"));
79
- if (jsFiles.length === 0)
80
- return;
81
- if (Object.keys(vendorPaths).length === 0)
82
- return;
83
- await Promise.all(jsFiles.map(async (filePath) => {
84
- let original;
85
- try {
86
- original = await Bun.file(filePath).text();
87
- } catch (err) {
88
- const code = err.code;
89
- if (code === "ENOENT")
90
- return;
91
- throw err;
92
- }
93
- const rewritten = rewriteImportsInContent(original, vendorPaths);
94
- if (rewritten === original)
95
- return;
96
- try {
97
- await Bun.write(filePath, rewritten);
98
- } catch (err) {
99
- const code = err.code;
100
- if (code === "ENOENT")
101
- return;
102
- throw err;
103
- }
104
- }));
105
- };
106
- export {
107
- rewriteImports
108
- };