@tyndall/build 0.0.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/README.md +35 -0
- package/dist/build.d.ts +30 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +925 -0
- package/dist/bundler.d.ts +32 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +48 -0
- package/dist/cache-gc.d.ts +20 -0
- package/dist/cache-gc.d.ts.map +1 -0
- package/dist/cache-gc.js +153 -0
- package/dist/chunk-cache.d.ts +17 -0
- package/dist/chunk-cache.d.ts.map +1 -0
- package/dist/chunk-cache.js +119 -0
- package/dist/emit.d.ts +5 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +62 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/manifest.d.ts +12 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +58 -0
- package/dist/pipeline.d.ts +42 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +56 -0
- package/dist/renderer.d.ts +50 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +109 -0
- package/dist/ssg-cache.d.ts +48 -0
- package/dist/ssg-cache.d.ts.map +1 -0
- package/dist/ssg-cache.js +159 -0
- package/dist/ssg-data.d.ts +21 -0
- package/dist/ssg-data.d.ts.map +1 -0
- package/dist/ssg-data.js +82 -0
- package/package.json +29 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type BundleFormat = "esm" | "cjs" | "iife";
|
|
2
|
+
export interface BundleEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
input: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BundleOptions {
|
|
7
|
+
format: BundleFormat;
|
|
8
|
+
target?: string;
|
|
9
|
+
define?: Record<string, string>;
|
|
10
|
+
depsHashByEntry?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export interface BundleChunk {
|
|
13
|
+
file: string;
|
|
14
|
+
imports?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface BundleResult {
|
|
17
|
+
entryChunks: Record<string, string>;
|
|
18
|
+
chunks: Record<string, BundleChunk>;
|
|
19
|
+
optionsHash: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const getBundleOptionsHash: (options: BundleOptions) => string;
|
|
22
|
+
export declare const resolveDepsHash: (entryId: string, depsHashByEntry?: Record<string, string>) => string;
|
|
23
|
+
export declare const getChunkKey: (entry: BundleEntry, options: BundleOptions, depsHash?: string) => string;
|
|
24
|
+
export declare const getChunkFileName: (entryId: string, chunkKey: string) => string;
|
|
25
|
+
export declare const bundleEntries: (entries: BundleEntry[], options: BundleOptions) => BundleResult;
|
|
26
|
+
export interface BundleClientOptions extends Omit<BundleOptions, "format"> {
|
|
27
|
+
entries: BundleEntry[];
|
|
28
|
+
format?: BundleFormat;
|
|
29
|
+
}
|
|
30
|
+
export declare const bundleClient: (options: BundleClientOptions) => BundleResult;
|
|
31
|
+
export declare const bundleServer: (options: BundleClientOptions) => BundleResult;
|
|
32
|
+
//# sourceMappingURL=bundler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;CACrB;AAaD,eAAO,MAAM,oBAAoB,GAAI,SAAS,aAAa,WACH,CAAC;AAEzD,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,kBAAkB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,WACE,CAAC;AAE7C,eAAO,MAAM,WAAW,GACtB,OAAO,WAAW,EAClB,SAAS,aAAa,EACtB,WAAW,MAAM,WAQhB,CAAC;AAEJ,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,WAGjE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,WAAW,EAAE,EAAE,SAAS,aAAa,KAAG,YAgB9E,CAAC;AAEF,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC;IACxE,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,YAAY,GAAI,SAAS,mBAAmB,KAAG,YAMxD,CAAC;AAEL,eAAO,MAAM,YAAY,GAAI,SAAS,mBAAmB,KAAG,YAMxD,CAAC"}
|
package/dist/bundler.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { hash, stableStringify } from "@tyndall/shared";
|
|
2
|
+
const sanitizeChunkBase = (value) => {
|
|
3
|
+
const cleaned = value.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4
|
+
return cleaned.length > 0 ? cleaned : "entry";
|
|
5
|
+
};
|
|
6
|
+
const normalizeBundleOptions = (options) => ({
|
|
7
|
+
format: options.format,
|
|
8
|
+
target: options.target,
|
|
9
|
+
define: options.define,
|
|
10
|
+
});
|
|
11
|
+
export const getBundleOptionsHash = (options) => hash(stableStringify(normalizeBundleOptions(options)));
|
|
12
|
+
export const resolveDepsHash = (entryId, depsHashByEntry) => depsHashByEntry?.[entryId] ?? "missing";
|
|
13
|
+
export const getChunkKey = (entry, options, depsHash) => hash(stableStringify({
|
|
14
|
+
entry,
|
|
15
|
+
options: normalizeBundleOptions(options),
|
|
16
|
+
depsHash: depsHash ?? "missing",
|
|
17
|
+
}));
|
|
18
|
+
export const getChunkFileName = (entryId, chunkKey) => {
|
|
19
|
+
const base = sanitizeChunkBase(entryId);
|
|
20
|
+
return `${base}.${chunkKey.slice(0, 8)}.js`;
|
|
21
|
+
};
|
|
22
|
+
export const bundleEntries = (entries, options) => {
|
|
23
|
+
const entryChunks = {};
|
|
24
|
+
const chunks = {};
|
|
25
|
+
const optionsHash = getBundleOptionsHash(options);
|
|
26
|
+
const orderedEntries = [...entries].sort((a, b) => a.id.localeCompare(b.id));
|
|
27
|
+
for (const entry of orderedEntries) {
|
|
28
|
+
const depsHash = resolveDepsHash(entry.id, options.depsHashByEntry);
|
|
29
|
+
const chunkKey = getChunkKey(entry, options, depsHash);
|
|
30
|
+
// Important: file naming uses stable hashing to keep chunk keys deterministic.
|
|
31
|
+
const file = getChunkFileName(entry.id, chunkKey);
|
|
32
|
+
entryChunks[entry.id] = chunkKey;
|
|
33
|
+
chunks[chunkKey] = { file, imports: [] };
|
|
34
|
+
}
|
|
35
|
+
return { entryChunks, chunks, optionsHash };
|
|
36
|
+
};
|
|
37
|
+
export const bundleClient = (options) => bundleEntries(options.entries, {
|
|
38
|
+
format: options.format ?? "esm",
|
|
39
|
+
target: options.target,
|
|
40
|
+
define: options.define,
|
|
41
|
+
depsHashByEntry: options.depsHashByEntry,
|
|
42
|
+
});
|
|
43
|
+
export const bundleServer = (options) => bundleEntries(options.entries, {
|
|
44
|
+
format: "cjs",
|
|
45
|
+
target: options.target,
|
|
46
|
+
define: options.define,
|
|
47
|
+
depsHashByEntry: options.depsHashByEntry,
|
|
48
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type CacheIndexEntry = {
|
|
2
|
+
key: string;
|
|
3
|
+
path: string;
|
|
4
|
+
sizeBytes: number;
|
|
5
|
+
lastUsed: number;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
};
|
|
8
|
+
export type CacheIndex = {
|
|
9
|
+
version: 1;
|
|
10
|
+
updatedAt: number;
|
|
11
|
+
entries: CacheIndexEntry[];
|
|
12
|
+
};
|
|
13
|
+
export type CacheGcPolicy = {
|
|
14
|
+
maxSizeMB?: number;
|
|
15
|
+
maxAgeDays?: number;
|
|
16
|
+
};
|
|
17
|
+
export declare const readCacheIndex: (cacheDir: string) => Promise<CacheIndex>;
|
|
18
|
+
export declare const writeCacheIndex: (cacheDir: string, index: CacheIndex) => Promise<void>;
|
|
19
|
+
export declare const updateCacheIndex: (cacheDir: string, currentKey: string, currentPath: string, policy: CacheGcPolicy) => Promise<CacheIndex>;
|
|
20
|
+
//# sourceMappingURL=cache-gc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-gc.d.ts","sourceRoot":"","sources":["../src/cache-gc.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAwCF,eAAO,MAAM,cAAc,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,UAAU,CAGzE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,UAAU,MAAM,EAAE,OAAO,UAAU,KAAG,OAAO,CAAC,IAAI,CAIvF,CAAC;AA8BF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,EAChB,YAAY,MAAM,EAClB,aAAa,MAAM,EACnB,QAAQ,aAAa,KACpB,OAAO,CAAC,UAAU,CAiFpB,CAAC"}
|
package/dist/cache-gc.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { mkdir, readdir, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readFileSafe, writeFileAtomic } from "@tyndall/shared";
|
|
4
|
+
const INDEX_FILE = "index.json";
|
|
5
|
+
const resolveIndexPath = (cacheDir) => join(cacheDir, INDEX_FILE);
|
|
6
|
+
const parseIndex = (raw) => {
|
|
7
|
+
if (!raw) {
|
|
8
|
+
return { version: 1, updatedAt: Date.now(), entries: [] };
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(raw.toString());
|
|
12
|
+
if (!parsed || typeof parsed !== "object" || parsed.version !== 1) {
|
|
13
|
+
return { version: 1, updatedAt: Date.now(), entries: [] };
|
|
14
|
+
}
|
|
15
|
+
const entries = Array.isArray(parsed.entries) ? parsed.entries : [];
|
|
16
|
+
const normalized = [];
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (entry &&
|
|
19
|
+
typeof entry === "object" &&
|
|
20
|
+
typeof entry.key === "string" &&
|
|
21
|
+
typeof entry.path === "string" &&
|
|
22
|
+
typeof entry.sizeBytes === "number" &&
|
|
23
|
+
typeof entry.lastUsed === "number" &&
|
|
24
|
+
typeof entry.createdAt === "number") {
|
|
25
|
+
normalized.push(entry);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
version: 1,
|
|
30
|
+
updatedAt: typeof parsed.updatedAt === "number" ? parsed.updatedAt : Date.now(),
|
|
31
|
+
entries: normalized,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { version: 1, updatedAt: Date.now(), entries: [] };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export const readCacheIndex = async (cacheDir) => {
|
|
39
|
+
const raw = await readFileSafe(resolveIndexPath(cacheDir));
|
|
40
|
+
return parseIndex(raw);
|
|
41
|
+
};
|
|
42
|
+
export const writeCacheIndex = async (cacheDir, index) => {
|
|
43
|
+
await mkdir(cacheDir, { recursive: true });
|
|
44
|
+
const payload = JSON.stringify(index, null, 2);
|
|
45
|
+
await writeFileAtomic(resolveIndexPath(cacheDir), payload, { encoding: "utf-8" });
|
|
46
|
+
};
|
|
47
|
+
const getDirectorySize = async (dirPath) => {
|
|
48
|
+
try {
|
|
49
|
+
const stats = await stat(dirPath);
|
|
50
|
+
if (!stats.isDirectory()) {
|
|
51
|
+
return stats.size;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
let total = 0;
|
|
58
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const entryPath = join(dirPath, entry.name);
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
total += await getDirectorySize(entryPath);
|
|
63
|
+
}
|
|
64
|
+
else if (entry.isFile()) {
|
|
65
|
+
const stats = await stat(entryPath);
|
|
66
|
+
total += stats.size;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return total;
|
|
70
|
+
};
|
|
71
|
+
const removeEntry = async (entry) => {
|
|
72
|
+
await rm(entry.path, { recursive: true, force: true });
|
|
73
|
+
};
|
|
74
|
+
export const updateCacheIndex = async (cacheDir, currentKey, currentPath, policy) => {
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
const index = await readCacheIndex(cacheDir);
|
|
77
|
+
const entries = index.entries.filter((entry) => entry.key !== "");
|
|
78
|
+
// Drop entries that no longer exist on disk.
|
|
79
|
+
const existing = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
try {
|
|
82
|
+
await stat(entry.path);
|
|
83
|
+
existing.push(entry);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const currentSize = await getDirectorySize(currentPath);
|
|
90
|
+
const currentEntry = existing.find((entry) => entry.key === currentKey);
|
|
91
|
+
if (currentEntry) {
|
|
92
|
+
currentEntry.path = currentPath;
|
|
93
|
+
currentEntry.sizeBytes = currentSize;
|
|
94
|
+
currentEntry.lastUsed = now;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
existing.push({
|
|
98
|
+
key: currentKey,
|
|
99
|
+
path: currentPath,
|
|
100
|
+
sizeBytes: currentSize,
|
|
101
|
+
lastUsed: now,
|
|
102
|
+
createdAt: now,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (typeof policy.maxAgeDays === "number" && policy.maxAgeDays > 0) {
|
|
106
|
+
const maxAgeMs = policy.maxAgeDays * 24 * 60 * 60 * 1000;
|
|
107
|
+
const stillValid = [];
|
|
108
|
+
for (const entry of existing) {
|
|
109
|
+
if (entry.key === currentKey) {
|
|
110
|
+
stillValid.push(entry);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (now - entry.lastUsed > maxAgeMs) {
|
|
114
|
+
await removeEntry(entry);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
stillValid.push(entry);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
existing.splice(0, existing.length, ...stillValid);
|
|
121
|
+
}
|
|
122
|
+
if (typeof policy.maxSizeMB === "number" && policy.maxSizeMB > 0) {
|
|
123
|
+
const limitBytes = policy.maxSizeMB * 1024 * 1024;
|
|
124
|
+
for (const entry of existing) {
|
|
125
|
+
if (!Number.isFinite(entry.sizeBytes) || entry.sizeBytes < 0) {
|
|
126
|
+
entry.sizeBytes = await getDirectorySize(entry.path);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
let totalSize = existing.reduce((sum, entry) => sum + entry.sizeBytes, 0);
|
|
130
|
+
if (totalSize > limitBytes) {
|
|
131
|
+
const candidates = existing
|
|
132
|
+
.filter((entry) => entry.key !== currentKey)
|
|
133
|
+
.sort((a, b) => a.lastUsed - b.lastUsed);
|
|
134
|
+
const remaining = existing.filter((entry) => entry.key === currentKey);
|
|
135
|
+
for (const entry of candidates) {
|
|
136
|
+
if (totalSize <= limitBytes) {
|
|
137
|
+
remaining.push(entry);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
await removeEntry(entry);
|
|
141
|
+
totalSize -= entry.sizeBytes;
|
|
142
|
+
}
|
|
143
|
+
existing.splice(0, existing.length, ...remaining);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const updatedIndex = {
|
|
147
|
+
version: 1,
|
|
148
|
+
updatedAt: now,
|
|
149
|
+
entries: existing,
|
|
150
|
+
};
|
|
151
|
+
await writeCacheIndex(cacheDir, updatedIndex);
|
|
152
|
+
return updatedIndex;
|
|
153
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ModuleGraphSnapshot } from "@tyndall/shared";
|
|
2
|
+
import type { BundleEntry, BundleOptions, BundleResult } from "./bundler.js";
|
|
3
|
+
export type ChunkCacheEntry = {
|
|
4
|
+
entryId: string;
|
|
5
|
+
chunkKey: string;
|
|
6
|
+
file: string;
|
|
7
|
+
imports: string[];
|
|
8
|
+
depsHash: string;
|
|
9
|
+
optionsHash: string;
|
|
10
|
+
generatedAt: number;
|
|
11
|
+
};
|
|
12
|
+
export declare const readChunkCacheEntry: (cacheRoot: string, chunkKey: string) => Promise<ChunkCacheEntry | null>;
|
|
13
|
+
export declare const writeChunkCacheEntry: (cacheRoot: string, entry: ChunkCacheEntry) => Promise<void>;
|
|
14
|
+
export declare const readChunkCache: (cacheRoot: string, entries: BundleEntry[], options: BundleOptions, depsHashByEntry?: Record<string, string>) => Promise<BundleResult | null>;
|
|
15
|
+
export declare const writeChunkCache: (cacheRoot: string, entries: BundleEntry[], result: BundleResult, depsHashByEntry?: Record<string, string>) => Promise<void>;
|
|
16
|
+
export declare const computeDepsHashByEntry: (snapshot: ModuleGraphSnapshot) => Promise<Record<string, string>>;
|
|
17
|
+
//# sourceMappingURL=chunk-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-cache.d.ts","sourceRoot":"","sources":["../src/chunk-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAe,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG1F,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AA2CF,eAAO,MAAM,mBAAmB,GAC9B,WAAW,MAAM,EACjB,UAAU,MAAM,KACf,OAAO,CAAC,eAAe,GAAG,IAAI,CAGhC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,OAAO,eAAe,KACrB,OAAO,CAAC,IAAI,CAKd,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,WAAW,MAAM,EACjB,SAAS,WAAW,EAAE,EACtB,SAAS,aAAa,EACtB,kBAAkB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACvC,OAAO,CAAC,YAAY,GAAG,IAAI,CAyB7B,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,WAAW,MAAM,EACjB,SAAS,WAAW,EAAE,EACtB,QAAQ,YAAY,EACpB,kBAAkB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACvC,OAAO,CAAC,IAAI,CA0Bd,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,UAAU,mBAAmB,KAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0BhC,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { hash, moduleContentHash, readFileSafe, stableStringify, writeFileAtomic, } from "@tyndall/shared";
|
|
3
|
+
import { getBundleOptionsHash, getChunkKey, resolveDepsHash } from "./bundler.js";
|
|
4
|
+
const CHUNK_DIR = "chunks";
|
|
5
|
+
const META_FILE = "meta.json";
|
|
6
|
+
const resolveChunkMetaPath = (cacheRoot, chunkKey) => join(cacheRoot, CHUNK_DIR, chunkKey, META_FILE);
|
|
7
|
+
const parseChunkCacheEntry = (raw) => {
|
|
8
|
+
if (!raw) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(raw.toString());
|
|
13
|
+
if (!parsed || typeof parsed !== "object") {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (typeof parsed.entryId !== "string" ||
|
|
17
|
+
typeof parsed.chunkKey !== "string" ||
|
|
18
|
+
typeof parsed.file !== "string" ||
|
|
19
|
+
typeof parsed.depsHash !== "string" ||
|
|
20
|
+
typeof parsed.optionsHash !== "string") {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const imports = Array.isArray(parsed.imports)
|
|
24
|
+
? parsed.imports.filter((item) => typeof item === "string")
|
|
25
|
+
: [];
|
|
26
|
+
return {
|
|
27
|
+
entryId: parsed.entryId,
|
|
28
|
+
chunkKey: parsed.chunkKey,
|
|
29
|
+
file: parsed.file,
|
|
30
|
+
imports,
|
|
31
|
+
depsHash: parsed.depsHash,
|
|
32
|
+
optionsHash: parsed.optionsHash,
|
|
33
|
+
generatedAt: typeof parsed.generatedAt === "number" ? parsed.generatedAt : Date.now(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export const readChunkCacheEntry = async (cacheRoot, chunkKey) => {
|
|
41
|
+
const raw = await readFileSafe(resolveChunkMetaPath(cacheRoot, chunkKey));
|
|
42
|
+
return parseChunkCacheEntry(raw);
|
|
43
|
+
};
|
|
44
|
+
export const writeChunkCacheEntry = async (cacheRoot, entry) => {
|
|
45
|
+
const payload = JSON.stringify(entry, null, 2);
|
|
46
|
+
await writeFileAtomic(resolveChunkMetaPath(cacheRoot, entry.chunkKey), payload, {
|
|
47
|
+
encoding: "utf-8",
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
export const readChunkCache = async (cacheRoot, entries, options, depsHashByEntry) => {
|
|
51
|
+
const entryChunks = {};
|
|
52
|
+
const chunks = {};
|
|
53
|
+
const optionsHash = getBundleOptionsHash(options);
|
|
54
|
+
const orderedEntries = [...entries].sort((a, b) => a.id.localeCompare(b.id));
|
|
55
|
+
for (const entry of orderedEntries) {
|
|
56
|
+
const depsHash = resolveDepsHash(entry.id, depsHashByEntry);
|
|
57
|
+
const chunkKey = getChunkKey(entry, options, depsHash);
|
|
58
|
+
const cached = await readChunkCacheEntry(cacheRoot, chunkKey);
|
|
59
|
+
if (!cached) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (cached.entryId !== entry.id ||
|
|
63
|
+
cached.depsHash !== depsHash ||
|
|
64
|
+
cached.optionsHash !== optionsHash) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
entryChunks[entry.id] = chunkKey;
|
|
68
|
+
chunks[chunkKey] = { file: cached.file, imports: cached.imports };
|
|
69
|
+
}
|
|
70
|
+
return { entryChunks, chunks, optionsHash };
|
|
71
|
+
};
|
|
72
|
+
export const writeChunkCache = async (cacheRoot, entries, result, depsHashByEntry) => {
|
|
73
|
+
const tasks = [];
|
|
74
|
+
const orderedEntries = [...entries].sort((a, b) => a.id.localeCompare(b.id));
|
|
75
|
+
for (const entry of orderedEntries) {
|
|
76
|
+
const chunkKey = result.entryChunks[entry.id];
|
|
77
|
+
if (!chunkKey) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const chunk = result.chunks[chunkKey];
|
|
81
|
+
if (!chunk) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const depsHash = resolveDepsHash(entry.id, depsHashByEntry);
|
|
85
|
+
tasks.push(writeChunkCacheEntry(cacheRoot, {
|
|
86
|
+
entryId: entry.id,
|
|
87
|
+
chunkKey,
|
|
88
|
+
file: chunk.file,
|
|
89
|
+
imports: chunk.imports ?? [],
|
|
90
|
+
depsHash,
|
|
91
|
+
optionsHash: result.optionsHash,
|
|
92
|
+
generatedAt: Date.now(),
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
await Promise.all(tasks);
|
|
96
|
+
};
|
|
97
|
+
export const computeDepsHashByEntry = async (snapshot) => {
|
|
98
|
+
const depsHashByEntry = {};
|
|
99
|
+
const moduleHashes = new Map();
|
|
100
|
+
const routeIds = Object.keys(snapshot.routeToModules).sort((a, b) => a.localeCompare(b));
|
|
101
|
+
for (const routeId of routeIds) {
|
|
102
|
+
const modules = snapshot.routeToModules[routeId] ?? [];
|
|
103
|
+
const moduleEntries = [];
|
|
104
|
+
for (const modulePath of modules) {
|
|
105
|
+
const cached = moduleHashes.get(modulePath);
|
|
106
|
+
if (cached) {
|
|
107
|
+
moduleEntries.push([modulePath, cached]);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const content = await readFileSafe(modulePath, "utf-8");
|
|
111
|
+
const contentHash = content ? moduleContentHash(content.toString()) : "missing";
|
|
112
|
+
moduleHashes.set(modulePath, contentHash);
|
|
113
|
+
moduleEntries.push([modulePath, contentHash]);
|
|
114
|
+
}
|
|
115
|
+
// Important: include module path + content hash so order/content changes affect depsHash.
|
|
116
|
+
depsHashByEntry[routeId] = hash(stableStringify(moduleEntries));
|
|
117
|
+
}
|
|
118
|
+
return depsHashByEntry;
|
|
119
|
+
};
|
package/dist/emit.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AA+BD,eAAO,MAAM,aAAa,GAAU,WAAW,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAgC/F,CAAC"}
|
package/dist/emit.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { copyFile, mkdir, readdir, rm, stat, rename, mkdtemp } from "node:fs/promises";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
const copyDir = async (source, dest) => {
|
|
4
|
+
await mkdir(dest, { recursive: true });
|
|
5
|
+
const entries = await readdir(source, { withFileTypes: true });
|
|
6
|
+
for (const entry of entries) {
|
|
7
|
+
const srcPath = join(source, entry.name);
|
|
8
|
+
const destPath = join(dest, entry.name);
|
|
9
|
+
if (entry.isDirectory()) {
|
|
10
|
+
await copyDir(srcPath, destPath);
|
|
11
|
+
}
|
|
12
|
+
else if (entry.isFile()) {
|
|
13
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
14
|
+
await copyFile(srcPath, destPath);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const listFiles = async (root, base = root) => {
|
|
19
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
20
|
+
const files = [];
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const fullPath = join(root, entry.name);
|
|
23
|
+
if (entry.isDirectory()) {
|
|
24
|
+
files.push(...(await listFiles(fullPath, base)));
|
|
25
|
+
}
|
|
26
|
+
else if (entry.isFile()) {
|
|
27
|
+
files.push(fullPath.slice(base.length + 1));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return files;
|
|
31
|
+
};
|
|
32
|
+
export const copyPublicDir = async (publicDir, outDir) => {
|
|
33
|
+
try {
|
|
34
|
+
await stat(publicDir);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { copiedFiles: [] };
|
|
38
|
+
}
|
|
39
|
+
await mkdir(outDir, { recursive: true });
|
|
40
|
+
const tempDir = await mkdtemp(join(outDir, ".public-tmp-"));
|
|
41
|
+
await copyDir(publicDir, tempDir);
|
|
42
|
+
const files = await listFiles(tempDir);
|
|
43
|
+
const moved = [];
|
|
44
|
+
try {
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
const fromPath = join(tempDir, file);
|
|
47
|
+
const toPath = join(outDir, file);
|
|
48
|
+
await mkdir(dirname(toPath), { recursive: true });
|
|
49
|
+
await rename(fromPath, toPath);
|
|
50
|
+
moved.push(toPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
for (const file of moved.reverse()) {
|
|
55
|
+
await rm(file, { force: true });
|
|
56
|
+
}
|
|
57
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
61
|
+
return { copiedFiles: moved };
|
|
62
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { runBuildPipeline, BuildStageError, } from "./pipeline.js";
|
|
2
|
+
export { build } from "./build.js";
|
|
3
|
+
export type { BuildCacheOptions, BuildMode, BuildOptions, BuildResult, } from "./build.js";
|
|
4
|
+
export type { BuildStage, BuildStageTiming, BuildPipelineContext, BuildPipelineState, BuildPipelineHandlers, BuildPipelineOptions, BuildPipelineResult, } from "./pipeline.js";
|
|
5
|
+
export { bundleClient, bundleServer, bundleEntries } from "./bundler.js";
|
|
6
|
+
export type { BundleFormat, BundleEntry, BundleOptions, BundleChunk, BundleResult, BundleClientOptions, } from "./bundler.js";
|
|
7
|
+
export { collectStaticData, StaticDataError } from "./ssg-data.js";
|
|
8
|
+
export type { StaticDataCache, StaticDataEntry, StaticDataResult } from "./ssg-data.js";
|
|
9
|
+
export { renderHtml, defaultHtmlTemplate } from "./renderer.js";
|
|
10
|
+
export type { RenderContext, RenderResult, UIAdapterLike, TemplateAssets, TemplateContext, HtmlTemplate, RenderHtmlOutput, } from "./renderer.js";
|
|
11
|
+
export { generateManifest } from "./manifest.js";
|
|
12
|
+
export type { ManifestOptions } from "./manifest.js";
|
|
13
|
+
export { copyPublicDir } from "./emit.js";
|
|
14
|
+
export type { CopyPublicResult } from "./emit.js";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EACV,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EACV,YAAY,EACZ,WAAW,EACX,aAAa,EACb,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAChE,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { runBuildPipeline, BuildStageError, } from "./pipeline.js";
|
|
2
|
+
export { build } from "./build.js";
|
|
3
|
+
export { bundleClient, bundleServer, bundleEntries } from "./bundler.js";
|
|
4
|
+
export { collectStaticData, StaticDataError } from "./ssg-data.js";
|
|
5
|
+
export { renderHtml, defaultHtmlTemplate } from "./renderer.js";
|
|
6
|
+
export { generateManifest } from "./manifest.js";
|
|
7
|
+
export { copyPublicDir } from "./emit.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Manifest, RouteGraph } from "@tyndall/core";
|
|
2
|
+
import type { BundleResult } from "./bundler.js";
|
|
3
|
+
export interface ManifestOptions {
|
|
4
|
+
version: string;
|
|
5
|
+
basePath?: string;
|
|
6
|
+
routeGraph: RouteGraph;
|
|
7
|
+
clientBundle: BundleResult;
|
|
8
|
+
serverBundle?: BundleResult;
|
|
9
|
+
assets?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare const generateManifest: (options: ManifestOptions) => Manifest;
|
|
12
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAc,UAAU,EAAe,MAAM,eAAe,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAuBD,eAAO,MAAM,gBAAgB,GAAI,SAAS,eAAe,KAAG,QA+C3D,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const routeTypeForRecord = (route) => {
|
|
2
|
+
let hasDynamic = false;
|
|
3
|
+
for (const segment of route.segments) {
|
|
4
|
+
if (segment.type === "catchAll") {
|
|
5
|
+
return "catchAll";
|
|
6
|
+
}
|
|
7
|
+
if (segment.type === "dynamic") {
|
|
8
|
+
hasDynamic = true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return hasDynamic ? "dynamic" : "static";
|
|
12
|
+
};
|
|
13
|
+
const htmlPathForRoute = (routeId) => {
|
|
14
|
+
if (routeId === "/") {
|
|
15
|
+
return "index.html";
|
|
16
|
+
}
|
|
17
|
+
const trimmed = routeId.replace(/^\//, "");
|
|
18
|
+
return `${trimmed}/index.html`;
|
|
19
|
+
};
|
|
20
|
+
export const generateManifest = (options) => {
|
|
21
|
+
const routes = {};
|
|
22
|
+
const orderedRoutes = [...options.routeGraph.routes].sort((a, b) => a.id.localeCompare(b.id));
|
|
23
|
+
for (const route of orderedRoutes) {
|
|
24
|
+
const type = routeTypeForRecord(route);
|
|
25
|
+
const clientEntry = options.clientBundle.entryChunks[route.id];
|
|
26
|
+
if (!clientEntry) {
|
|
27
|
+
throw new Error(`Missing client bundle entry for route ${route.id}`);
|
|
28
|
+
}
|
|
29
|
+
const entry = {
|
|
30
|
+
type,
|
|
31
|
+
clientEntry,
|
|
32
|
+
};
|
|
33
|
+
if (type === "static") {
|
|
34
|
+
entry.html = htmlPathForRoute(route.id);
|
|
35
|
+
}
|
|
36
|
+
if (options.serverBundle) {
|
|
37
|
+
const serverEntry = options.serverBundle.entryChunks[route.id];
|
|
38
|
+
if (serverEntry) {
|
|
39
|
+
entry.serverEntry = serverEntry;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
routes[route.id] = entry;
|
|
43
|
+
}
|
|
44
|
+
const chunks = {
|
|
45
|
+
...options.clientBundle.chunks,
|
|
46
|
+
...(options.serverBundle?.chunks ?? {}),
|
|
47
|
+
};
|
|
48
|
+
const manifest = {
|
|
49
|
+
version: options.version,
|
|
50
|
+
basePath: options.basePath ?? "",
|
|
51
|
+
routes,
|
|
52
|
+
chunks,
|
|
53
|
+
};
|
|
54
|
+
if (options.assets) {
|
|
55
|
+
manifest.assets = options.assets;
|
|
56
|
+
}
|
|
57
|
+
return manifest;
|
|
58
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Manifest, RouteGraph } from "@tyndall/core";
|
|
2
|
+
export type BuildStage = "scanRoutes" | "analyzeGraph" | "bundleClient" | "bundleServer" | "runStaticData" | "renderHtml" | "emitManifest" | "copyPublic";
|
|
3
|
+
export interface BuildStageTiming {
|
|
4
|
+
stage: BuildStage;
|
|
5
|
+
startedAt: number;
|
|
6
|
+
durationMs: number;
|
|
7
|
+
}
|
|
8
|
+
export interface BuildPipelineContext {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface BuildPipelineState {
|
|
12
|
+
routeGraph?: RouteGraph;
|
|
13
|
+
moduleGraph?: unknown;
|
|
14
|
+
clientBundle?: unknown;
|
|
15
|
+
serverBundle?: unknown;
|
|
16
|
+
staticData?: unknown;
|
|
17
|
+
renderResult?: unknown;
|
|
18
|
+
manifest?: Manifest;
|
|
19
|
+
}
|
|
20
|
+
export interface BuildPipelineHandlers {
|
|
21
|
+
scanRoutes: (ctx: BuildPipelineContext) => Promise<RouteGraph> | RouteGraph;
|
|
22
|
+
analyzeGraph: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<unknown> | unknown;
|
|
23
|
+
bundleClient: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<unknown> | unknown;
|
|
24
|
+
bundleServer?: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<unknown> | unknown;
|
|
25
|
+
runStaticData: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<unknown> | unknown;
|
|
26
|
+
renderHtml: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<unknown> | unknown;
|
|
27
|
+
emitManifest: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<Manifest> | Manifest;
|
|
28
|
+
copyPublic: (ctx: BuildPipelineContext, state: BuildPipelineState) => Promise<void> | void;
|
|
29
|
+
}
|
|
30
|
+
export interface BuildPipelineOptions {
|
|
31
|
+
ssr?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface BuildPipelineResult {
|
|
34
|
+
state: BuildPipelineState;
|
|
35
|
+
timings: BuildStageTiming[];
|
|
36
|
+
}
|
|
37
|
+
export declare class BuildStageError extends Error {
|
|
38
|
+
readonly stage: BuildStage;
|
|
39
|
+
constructor(stage: BuildStage, error: unknown);
|
|
40
|
+
}
|
|
41
|
+
export declare const runBuildPipeline: (ctx: BuildPipelineContext, handlers: BuildPipelineHandlers, options?: BuildPipelineOptions) => Promise<BuildPipelineResult>;
|
|
42
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,cAAc,GACd,cAAc,GACd,cAAc,GACd,eAAe,GACf,YAAY,GACZ,cAAc,GACd,YAAY,CAAC;AAEjB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;IAC5E,YAAY,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACnG,YAAY,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACnG,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACpG,aAAa,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACpG,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjG,YAAY,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;IACrG,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC5F;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;gBAEf,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO;CAQ9C;AAED,eAAO,MAAM,gBAAgB,GAC3B,KAAK,oBAAoB,EACzB,UAAU,qBAAqB,EAC/B,UAAS,oBAAyB,KACjC,OAAO,CAAC,mBAAmB,CAkD7B,CAAC"}
|