@openelement/adapter-vite 0.41.0-alpha.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.
@@ -0,0 +1,198 @@
1
+ /**
2
+ * @openelement/adapter-vite - Build Manifest / Observability
3
+ *
4
+ * Scans build output directories after each phase and prints a structured
5
+ * summary table. This gives developers visibility into:
6
+ * - Per-island chunk sizes (Phase 2)
7
+ * - Total JS/CSS bundle budgets (Phase 3)
8
+ * - HTML page counts and compression potential
9
+ * - headExtras injection size
10
+ *
11
+ * Output format: Fixed-width table via console.info (no external dependency).
12
+ *
13
+ * Called by:
14
+ * - cli/build-client.ts (after Phase 2: client chunks ready)
15
+ * - cli/build-ssg.ts (after Phase 3: HTML + post-process complete)
16
+ */ import { join, resolve } from 'node:path';
17
+ import { existsSync, readdirSync, statSync } from 'node:fs';
18
+ import { createLogger } from '@openelement/core/logger';
19
+ const log = createLogger('ssg');
20
+ /**
21
+ * Format bytes to human-readable string.
22
+ */ function formatSize(bytes) {
23
+ if (bytes < 1024) return `${bytes} B`;
24
+ if (bytes < 1024 * 10) return `${(bytes / 1024).toFixed(1)} KB`;
25
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
26
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
27
+ }
28
+ /**
29
+ * Recursively collect all matching files with their sizes.
30
+ */ function collectFiles(dir, extension, basePath = '') {
31
+ const results = [];
32
+ if (!existsSync(dir)) return results;
33
+ const entries = readdirSync(dir, {
34
+ withFileTypes: true
35
+ });
36
+ for (const entry of entries){
37
+ const fullPath = join(dir, entry.name);
38
+ const relPath = basePath ? `${basePath}/${entry.name}` : entry.name;
39
+ if (entry.isDirectory()) {
40
+ results.push(...collectFiles(fullPath, extension, relPath));
41
+ } else if (entry.name.endsWith(extension)) {
42
+ try {
43
+ const stat = statSync(fullPath);
44
+ results.push({
45
+ name: entry.name,
46
+ path: relPath,
47
+ sizeBytes: stat.size,
48
+ sizeKB: formatSize(stat.size)
49
+ });
50
+ } catch (e) {
51
+ log.warn(`Cannot stat ${relPath}: ${e.message}`);
52
+ }
53
+ }
54
+ }
55
+ return results;
56
+ }
57
+ /**
58
+ * Scan client build output (dist/client/) for island chunks.
59
+ */ export function scanClientBuild(root, outDir = 'dist') {
60
+ const clientDir = resolve(root, outDir, 'client');
61
+ const islands = [];
62
+ let clientEntry = null;
63
+ let totalJsBytes = 0;
64
+ // Scan islands/ subdirectory (single pass - avoid redundant directory scans)
65
+ const islandsDir = join(clientDir, 'islands');
66
+ if (existsSync(islandsDir)) {
67
+ const files = readdirSync(islandsDir);
68
+ for (const file of files){
69
+ if (!file.endsWith('.js')) continue;
70
+ const fullPath = join(islandsDir, file);
71
+ try {
72
+ const fileStat = statSync(fullPath);
73
+ if (file === 'client.js') {
74
+ // Client entry (shared island upgrade runtime)
75
+ clientEntry = {
76
+ name: 'client.js',
77
+ path: 'islands/client.js',
78
+ sizeBytes: fileStat.size,
79
+ sizeKB: formatSize(fileStat.size)
80
+ };
81
+ } else {
82
+ // Island chunk or shared chunk
83
+ const _isIslandChunk = /^island-(.+?)-[A-Za-z0-9]+\.js$/.test(file);
84
+ islands.push({
85
+ name: file,
86
+ path: `islands/${file}`,
87
+ sizeBytes: fileStat.size,
88
+ sizeKB: formatSize(fileStat.size)
89
+ });
90
+ }
91
+ totalJsBytes += fileStat.size;
92
+ } catch (e) {
93
+ log.warn(`Cannot stat ${file}: ${e.message}`);
94
+ }
95
+ }
96
+ }
97
+ return {
98
+ islands,
99
+ clientEntry,
100
+ totalJsBytes
101
+ };
102
+ }
103
+ /**
104
+ * Scan SSG output (dist/*.html) for page information.
105
+ */ export function scanSSGOutput(root, outDir = 'dist') {
106
+ const distDir = resolve(root, outDir);
107
+ return collectFiles(distDir, '.html');
108
+ }
109
+ /**
110
+ * Print a formatted build manifest table to console.
111
+ *
112
+ * This is called at the end of each build phase to provide observability
113
+ * into what was produced and how large everything is.
114
+ */ export function printBuildManifest(options) {
115
+ const { root, outDir = 'dist', phase, headExtras = '' } = options;
116
+ const timestamp = new Date().toISOString();
117
+ // Gather data
118
+ const clientData = scanClientBuild(root, outDir);
119
+ const htmlPages = phase === 3 ? scanSSGOutput(root, outDir) : [];
120
+ const headExtrasSize = new TextEncoder().encode(headExtras).length;
121
+ // Budget thresholds
122
+ const ISLAND_BUDGET_KB = 50; // Warn if single island > 50KB
123
+ const TOTAL_JS_BUDGET_KB = 200; // Warn if total JS > 200KB
124
+ const PAGE_BUDGET_KB = 200; // Advisory only: single uncompressed HTML page budget.
125
+ const warnings = [];
126
+ // Check island budgets
127
+ for (const island of clientData.islands){
128
+ if (island.sizeBytes > ISLAND_BUDGET_KB * 1024) {
129
+ warnings.push(`Warning: ${island.name} (${island.sizeKB}) exceeds ${ISLAND_BUDGET_KB} KB budget`);
130
+ }
131
+ }
132
+ // Check total JS budget
133
+ if (clientData.totalJsBytes > TOTAL_JS_BUDGET_KB * 1024) {
134
+ warnings.push(`Warning: Total JS (${formatSize(clientData.totalJsBytes)}) exceeds ${TOTAL_JS_BUDGET_KB} KB budget`);
135
+ }
136
+ // Check page sizes
137
+ for (const page of htmlPages){
138
+ if (page.sizeBytes > PAGE_BUDGET_KB * 1024) {
139
+ warnings.push(`Warning: ${page.path} (${page.sizeKB}) exceeds advisory ${PAGE_BUDGET_KB} KB HTML budget - consider compression`);
140
+ }
141
+ }
142
+ const manifest = {
143
+ phase,
144
+ timestamp,
145
+ islands: clientData.islands,
146
+ clientEntry: clientData.clientEntry,
147
+ htmlPages,
148
+ totalJsBytes: clientData.totalJsBytes,
149
+ totalHtmlBytes: htmlPages.reduce((sum, p)=>sum + p.sizeBytes, 0),
150
+ headExtrasSize,
151
+ warnings
152
+ };
153
+ // Print table using ASCII-only output so build logs remain portable.
154
+ console.info('');
155
+ console.info(`== openElement Build Manifest - Phase ${phase} @ ${timestamp.slice(11, 19)} ==`);
156
+ if (manifest.islands.length > 0 || manifest.clientEntry) {
157
+ console.info('\n Client Islands:');
158
+ console.info(' File Size');
159
+ console.info(' -------------------------- --------');
160
+ for (const island of manifest.islands){
161
+ const displayName = island.name.length > 30 ? island.name.slice(0, 27) + '...' : island.name;
162
+ console.info(` ${displayName.padEnd(26)} ${island.sizeKB.padEnd(8)}`);
163
+ }
164
+ if (manifest.clientEntry) {
165
+ console.info(` ${'client.js (entry)'.padEnd(26)} ${manifest.clientEntry.sizeKB.padEnd(8)}`);
166
+ }
167
+ console.info(' -------------------------- --------');
168
+ console.info(` ${'TOTAL JS'.padEnd(26)} ${formatSize(manifest.totalJsBytes).padEnd(8)}`);
169
+ } else {
170
+ console.info('\n Client Islands: none - zero client JS');
171
+ }
172
+ if (phase === 3 && manifest.htmlPages.length > 0) {
173
+ console.info(`\n HTML Pages (${manifest.htmlPages.length} files, ${formatSize(manifest.totalHtmlBytes)} total):`);
174
+ const maxShow = 15;
175
+ const shown = manifest.htmlPages.slice(0, maxShow);
176
+ for (const page of shown){
177
+ const displayName = page.path.length > 40 ? page.path.slice(0, 37) + '...' : page.path;
178
+ console.info(` - ${displayName} (${page.sizeKB})`);
179
+ }
180
+ if (manifest.htmlPages.length > maxShow) {
181
+ console.info(` ... +${manifest.htmlPages.length - maxShow} more pages`);
182
+ }
183
+ }
184
+ if (manifest.headExtrasSize > 0) {
185
+ console.info(`\n headExtras: ${formatSize(manifest.headExtrasSize)} (${manifest.headExtrasSize} bytes injected)`);
186
+ }
187
+ if (warnings.length > 0) {
188
+ console.info('\n Budget Warnings:');
189
+ for (const w of warnings){
190
+ console.info(` ${w}`);
191
+ }
192
+ } else {
193
+ console.info('\n All artifacts within budget limits');
194
+ }
195
+ console.info('');
196
+ return manifest;
197
+ }
198
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9hZGFwdGVyLXZpdGUvc3JjL2J1aWxkLW1hbmlmZXN0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZSAtIEJ1aWxkIE1hbmlmZXN0IC8gT2JzZXJ2YWJpbGl0eVxuICpcbiAqIFNjYW5zIGJ1aWxkIG91dHB1dCBkaXJlY3RvcmllcyBhZnRlciBlYWNoIHBoYXNlIGFuZCBwcmludHMgYSBzdHJ1Y3R1cmVkXG4gKiBzdW1tYXJ5IHRhYmxlLiBUaGlzIGdpdmVzIGRldmVsb3BlcnMgdmlzaWJpbGl0eSBpbnRvOlxuICogICAtIFBlci1pc2xhbmQgY2h1bmsgc2l6ZXMgKFBoYXNlIDIpXG4gKiAgIC0gVG90YWwgSlMvQ1NTIGJ1bmRsZSBidWRnZXRzIChQaGFzZSAzKVxuICogICAtIEhUTUwgcGFnZSBjb3VudHMgYW5kIGNvbXByZXNzaW9uIHBvdGVudGlhbFxuICogICAtIGhlYWRFeHRyYXMgaW5qZWN0aW9uIHNpemVcbiAqXG4gKiBPdXRwdXQgZm9ybWF0OiBGaXhlZC13aWR0aCB0YWJsZSB2aWEgY29uc29sZS5pbmZvIChubyBleHRlcm5hbCBkZXBlbmRlbmN5KS5cbiAqXG4gKiBDYWxsZWQgYnk6XG4gKiAgIC0gY2xpL2J1aWxkLWNsaWVudC50cyAoYWZ0ZXIgUGhhc2UgMjogY2xpZW50IGNodW5rcyByZWFkeSlcbiAqICAgLSBjbGkvYnVpbGQtc3NnLnRzICAgIChhZnRlciBQaGFzZSAzOiBIVE1MICsgcG9zdC1wcm9jZXNzIGNvbXBsZXRlKVxuICovXG5cbmltcG9ydCB7IGpvaW4sIHJlc29sdmUgfSBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZGRpclN5bmMsIHN0YXRTeW5jIH0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9sb2dnZXInO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ3NzZycpO1xuXG4vKiogRmlsZSBzaXplIGluZm8gZm9yIGEgc2luZ2xlIGFydGlmYWN0ICovXG5leHBvcnQgaW50ZXJmYWNlIEFydGlmYWN0SW5mbyB7XG4gIG5hbWU6IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICBzaXplQnl0ZXM6IG51bWJlcjtcbiAgc2l6ZUtCOiBzdHJpbmc7XG59XG5cbi8qKiBGdWxsIGJ1aWxkIG1hbmlmZXN0IHN1bW1hcnkgKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnVpbGRNYW5pZmVzdCB7XG4gIHBoYXNlOiAxIHwgMiB8IDM7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuICBpc2xhbmRzOiBBcnRpZmFjdEluZm9bXTtcbiAgY2xpZW50RW50cnk6IEFydGlmYWN0SW5mbyB8IG51bGw7XG4gIGh0bWxQYWdlczogQXJ0aWZhY3RJbmZvW107XG4gIHRvdGFsSnNCeXRlczogbnVtYmVyO1xuICB0b3RhbEh0bWxCeXRlczogbnVtYmVyO1xuICBoZWFkRXh0cmFzU2l6ZTogbnVtYmVyO1xuICAvKiogQnVkZ2V0IHdhcm5pbmdzIChmaWxlcyA+IHRocmVzaG9sZCkgKi9cbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEZvcm1hdCBieXRlcyB0byBodW1hbi1yZWFkYWJsZSBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFNpemUoYnl0ZXM6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmIChieXRlcyA8IDEwMjQpIHJldHVybiBgJHtieXRlc30gQmA7XG4gIGlmIChieXRlcyA8IDEwMjQgKiAxMCkgcmV0dXJuIGAkeyhieXRlcyAvIDEwMjQpLnRvRml4ZWQoMSl9IEtCYDtcbiAgaWYgKGJ5dGVzIDwgMTAyNCAqIDEwMjQpIHJldHVybiBgJHtNYXRoLnJvdW5kKGJ5dGVzIC8gMTAyNCl9IEtCYDtcbiAgcmV0dXJuIGAkeyhieXRlcyAvICgxMDI0ICogMTAyNCkpLnRvRml4ZWQoMSl9IE1CYDtcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSBjb2xsZWN0IGFsbCBtYXRjaGluZyBmaWxlcyB3aXRoIHRoZWlyIHNpemVzLlxuICovXG5mdW5jdGlvbiBjb2xsZWN0RmlsZXMoXG4gIGRpcjogc3RyaW5nLFxuICBleHRlbnNpb246IHN0cmluZyxcbiAgYmFzZVBhdGggPSAnJyxcbik6IEFydGlmYWN0SW5mb1tdIHtcbiAgY29uc3QgcmVzdWx0czogQXJ0aWZhY3RJbmZvW10gPSBbXTtcbiAgaWYgKCFleGlzdHNTeW5jKGRpcikpIHJldHVybiByZXN1bHRzO1xuXG4gIGNvbnN0IGVudHJpZXMgPSByZWFkZGlyU3luYyhkaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGRpciwgZW50cnkubmFtZSk7XG4gICAgY29uc3QgcmVsUGF0aCA9IGJhc2VQYXRoID8gYCR7YmFzZVBhdGh9LyR7ZW50cnkubmFtZX1gIDogZW50cnkubmFtZTtcbiAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgcmVzdWx0cy5wdXNoKC4uLmNvbGxlY3RGaWxlcyhmdWxsUGF0aCwgZXh0ZW5zaW9uLCByZWxQYXRoKSk7XG4gICAgfSBlbHNlIGlmIChlbnRyeS5uYW1lLmVuZHNXaXRoKGV4dGVuc2lvbikpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0YXQgPSBzdGF0U3luYyhmdWxsUGF0aCk7XG4gICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICBwYXRoOiByZWxQYXRoLFxuICAgICAgICAgIHNpemVCeXRlczogc3RhdC5zaXplLFxuICAgICAgICAgIHNpemVLQjogZm9ybWF0U2l6ZShzdGF0LnNpemUpLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgbG9nLndhcm4oYENhbm5vdCBzdGF0ICR7cmVsUGF0aH06ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzO1xufVxuXG4vKipcbiAqIFNjYW4gY2xpZW50IGJ1aWxkIG91dHB1dCAoZGlzdC9jbGllbnQvKSBmb3IgaXNsYW5kIGNodW5rcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5DbGllbnRCdWlsZChcbiAgcm9vdDogc3RyaW5nLFxuICBvdXREaXI6IHN0cmluZyA9ICdkaXN0Jyxcbik6IHsgaXNsYW5kczogQXJ0aWZhY3RJbmZvW107IGNsaWVudEVudHJ5OiBBcnRpZmFjdEluZm8gfCBudWxsOyB0b3RhbEpzQnl0ZXM6IG51bWJlciB9IHtcbiAgY29uc3QgY2xpZW50RGlyID0gcmVzb2x2ZShyb290LCBvdXREaXIsICdjbGllbnQnKTtcbiAgY29uc3QgaXNsYW5kczogQXJ0aWZhY3RJbmZvW10gPSBbXTtcbiAgbGV0IGNsaWVudEVudHJ5OiBBcnRpZmFjdEluZm8gfCBudWxsID0gbnVsbDtcbiAgbGV0IHRvdGFsSnNCeXRlcyA9IDA7XG5cbiAgLy8gU2NhbiBpc2xhbmRzLyBzdWJkaXJlY3RvcnkgKHNpbmdsZSBwYXNzIC0gYXZvaWQgcmVkdW5kYW50IGRpcmVjdG9yeSBzY2FucylcbiAgY29uc3QgaXNsYW5kc0RpciA9IGpvaW4oY2xpZW50RGlyLCAnaXNsYW5kcycpO1xuICBpZiAoZXhpc3RzU3luYyhpc2xhbmRzRGlyKSkge1xuICAgIGNvbnN0IGZpbGVzID0gcmVhZGRpclN5bmMoaXNsYW5kc0Rpcik7XG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBpZiAoIWZpbGUuZW5kc1dpdGgoJy5qcycpKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gam9pbihpc2xhbmRzRGlyLCBmaWxlKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZpbGVTdGF0ID0gc3RhdFN5bmMoZnVsbFBhdGgpO1xuICAgICAgICBpZiAoZmlsZSA9PT0gJ2NsaWVudC5qcycpIHtcbiAgICAgICAgICAvLyBDbGllbnQgZW50cnkgKHNoYXJlZCBpc2xhbmQgdXBncmFkZSBydW50aW1lKVxuICAgICAgICAgIGNsaWVudEVudHJ5ID0ge1xuICAgICAgICAgICAgbmFtZTogJ2NsaWVudC5qcycsXG4gICAgICAgICAgICBwYXRoOiAnaXNsYW5kcy9jbGllbnQuanMnLFxuICAgICAgICAgICAgc2l6ZUJ5dGVzOiBmaWxlU3RhdC5zaXplLFxuICAgICAgICAgICAgc2l6ZUtCOiBmb3JtYXRTaXplKGZpbGVTdGF0LnNpemUpLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gSXNsYW5kIGNodW5rIG9yIHNoYXJlZCBjaHVua1xuICAgICAgICAgIGNvbnN0IF9pc0lzbGFuZENodW5rID0gL15pc2xhbmQtKC4rPyktW0EtWmEtejAtOV0rXFwuanMkLy50ZXN0KGZpbGUpO1xuICAgICAgICAgIGlzbGFuZHMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiBmaWxlLFxuICAgICAgICAgICAgcGF0aDogYGlzbGFuZHMvJHtmaWxlfWAsXG4gICAgICAgICAgICBzaXplQnl0ZXM6IGZpbGVTdGF0LnNpemUsXG4gICAgICAgICAgICBzaXplS0I6IGZvcm1hdFNpemUoZmlsZVN0YXQuc2l6ZSksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdG90YWxKc0J5dGVzICs9IGZpbGVTdGF0LnNpemU7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZy53YXJuKGBDYW5ub3Qgc3RhdCAke2ZpbGV9OiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGlzbGFuZHMsIGNsaWVudEVudHJ5LCB0b3RhbEpzQnl0ZXMgfTtcbn1cblxuLyoqXG4gKiBTY2FuIFNTRyBvdXRwdXQgKGRpc3QvKi5odG1sKSBmb3IgcGFnZSBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5TU0dPdXRwdXQoXG4gIHJvb3Q6IHN0cmluZyxcbiAgb3V0RGlyOiBzdHJpbmcgPSAnZGlzdCcsXG4pOiBBcnRpZmFjdEluZm9bXSB7XG4gIGNvbnN0IGRpc3REaXIgPSByZXNvbHZlKHJvb3QsIG91dERpcik7XG4gIHJldHVybiBjb2xsZWN0RmlsZXMoZGlzdERpciwgJy5odG1sJyk7XG59XG5cbi8qKlxuICogUHJpbnQgYSBmb3JtYXR0ZWQgYnVpbGQgbWFuaWZlc3QgdGFibGUgdG8gY29uc29sZS5cbiAqXG4gKiBUaGlzIGlzIGNhbGxlZCBhdCB0aGUgZW5kIG9mIGVhY2ggYnVpbGQgcGhhc2UgdG8gcHJvdmlkZSBvYnNlcnZhYmlsaXR5XG4gKiBpbnRvIHdoYXQgd2FzIHByb2R1Y2VkIGFuZCBob3cgbGFyZ2UgZXZlcnl0aGluZyBpcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByaW50QnVpbGRNYW5pZmVzdChvcHRpb25zOiB7XG4gIHJvb3Q6IHN0cmluZztcbiAgb3V0RGlyPzogc3RyaW5nO1xuICBwaGFzZTogMiB8IDM7XG4gIGhlYWRFeHRyYXM/OiBzdHJpbmc7XG59KTogQnVpbGRNYW5pZmVzdCB7XG4gIGNvbnN0IHsgcm9vdCwgb3V0RGlyID0gJ2Rpc3QnLCBwaGFzZSwgaGVhZEV4dHJhcyA9ICcnIH0gPSBvcHRpb25zO1xuICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cbiAgLy8gR2F0aGVyIGRhdGFcbiAgY29uc3QgY2xpZW50RGF0YSA9IHNjYW5DbGllbnRCdWlsZChyb290LCBvdXREaXIpO1xuICBjb25zdCBodG1sUGFnZXMgPSBwaGFzZSA9PT0gMyA/IHNjYW5TU0dPdXRwdXQocm9vdCwgb3V0RGlyKSA6IFtdO1xuICBjb25zdCBoZWFkRXh0cmFzU2l6ZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShoZWFkRXh0cmFzKS5sZW5ndGg7XG5cbiAgLy8gQnVkZ2V0IHRocmVzaG9sZHNcbiAgY29uc3QgSVNMQU5EX0JVREdFVF9LQiA9IDUwOyAvLyBXYXJuIGlmIHNpbmdsZSBpc2xhbmQgPiA1MEtCXG4gIGNvbnN0IFRPVEFMX0pTX0JVREdFVF9LQiA9IDIwMDsgLy8gV2FybiBpZiB0b3RhbCBKUyA+IDIwMEtCXG4gIGNvbnN0IFBBR0VfQlVER0VUX0tCID0gMjAwOyAvLyBBZHZpc29yeSBvbmx5OiBzaW5nbGUgdW5jb21wcmVzc2VkIEhUTUwgcGFnZSBidWRnZXQuXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gQ2hlY2sgaXNsYW5kIGJ1ZGdldHNcbiAgZm9yIChjb25zdCBpc2xhbmQgb2YgY2xpZW50RGF0YS5pc2xhbmRzKSB7XG4gICAgaWYgKGlzbGFuZC5zaXplQnl0ZXMgPiBJU0xBTkRfQlVER0VUX0tCICogMTAyNCkge1xuICAgICAgd2FybmluZ3MucHVzaChcbiAgICAgICAgYFdhcm5pbmc6ICR7aXNsYW5kLm5hbWV9ICgke2lzbGFuZC5zaXplS0J9KSBleGNlZWRzICR7SVNMQU5EX0JVREdFVF9LQn0gS0IgYnVkZ2V0YCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgdG90YWwgSlMgYnVkZ2V0XG4gIGlmIChjbGllbnREYXRhLnRvdGFsSnNCeXRlcyA+IFRPVEFMX0pTX0JVREdFVF9LQiAqIDEwMjQpIHtcbiAgICB3YXJuaW5ncy5wdXNoKFxuICAgICAgYFdhcm5pbmc6IFRvdGFsIEpTICgke1xuICAgICAgICBmb3JtYXRTaXplKGNsaWVudERhdGEudG90YWxKc0J5dGVzKVxuICAgICAgfSkgZXhjZWVkcyAke1RPVEFMX0pTX0JVREdFVF9LQn0gS0IgYnVkZ2V0YCxcbiAgICApO1xuICB9XG5cbiAgLy8gQ2hlY2sgcGFnZSBzaXplc1xuICBmb3IgKGNvbnN0IHBhZ2Ugb2YgaHRtbFBhZ2VzKSB7XG4gICAgaWYgKHBhZ2Uuc2l6ZUJ5dGVzID4gUEFHRV9CVURHRVRfS0IgKiAxMDI0KSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKFxuICAgICAgICBgV2FybmluZzogJHtwYWdlLnBhdGh9ICgke3BhZ2Uuc2l6ZUtCfSkgZXhjZWVkcyBhZHZpc29yeSAke1BBR0VfQlVER0VUX0tCfSBLQiBIVE1MIGJ1ZGdldCAtIGNvbnNpZGVyIGNvbXByZXNzaW9uYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbWFuaWZlc3Q6IEJ1aWxkTWFuaWZlc3QgPSB7XG4gICAgcGhhc2UsXG4gICAgdGltZXN0YW1wLFxuICAgIGlzbGFuZHM6IGNsaWVudERhdGEuaXNsYW5kcyxcbiAgICBjbGllbnRFbnRyeTogY2xpZW50RGF0YS5jbGllbnRFbnRyeSxcbiAgICBodG1sUGFnZXMsXG4gICAgdG90YWxKc0J5dGVzOiBjbGllbnREYXRhLnRvdGFsSnNCeXRlcyxcbiAgICB0b3RhbEh0bWxCeXRlczogaHRtbFBhZ2VzLnJlZHVjZSgoc3VtLCBwKSA9PiBzdW0gKyBwLnNpemVCeXRlcywgMCksXG4gICAgaGVhZEV4dHJhc1NpemUsXG4gICAgd2FybmluZ3MsXG4gIH07XG5cbiAgLy8gUHJpbnQgdGFibGUgdXNpbmcgQVNDSUktb25seSBvdXRwdXQgc28gYnVpbGQgbG9ncyByZW1haW4gcG9ydGFibGUuXG4gIGNvbnNvbGUuaW5mbygnJyk7XG4gIGNvbnNvbGUuaW5mbyhgPT0gb3BlbkVsZW1lbnQgQnVpbGQgTWFuaWZlc3QgLSBQaGFzZSAke3BoYXNlfSBAICR7dGltZXN0YW1wLnNsaWNlKDExLCAxOSl9ID09YCk7XG5cbiAgaWYgKG1hbmlmZXN0LmlzbGFuZHMubGVuZ3RoID4gMCB8fCBtYW5pZmVzdC5jbGllbnRFbnRyeSkge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBDbGllbnQgSXNsYW5kczonKTtcbiAgICBjb25zb2xlLmluZm8oJyAgRmlsZSAgICAgICAgICAgICAgICAgICAgICAgICBTaXplJyk7XG4gICAgY29uc29sZS5pbmZvKCcgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICAgLS0tLS0tLS0nKTtcblxuICAgIGZvciAoY29uc3QgaXNsYW5kIG9mIG1hbmlmZXN0LmlzbGFuZHMpIHtcbiAgICAgIGNvbnN0IGRpc3BsYXlOYW1lID0gaXNsYW5kLm5hbWUubGVuZ3RoID4gMzAgPyBpc2xhbmQubmFtZS5zbGljZSgwLCAyNykgKyAnLi4uJyA6IGlzbGFuZC5uYW1lO1xuICAgICAgY29uc29sZS5pbmZvKGAgICR7ZGlzcGxheU5hbWUucGFkRW5kKDI2KX0gICAke2lzbGFuZC5zaXplS0IucGFkRW5kKDgpfWApO1xuICAgIH1cblxuICAgIGlmIChtYW5pZmVzdC5jbGllbnRFbnRyeSkge1xuICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICBgICAkeydjbGllbnQuanMgKGVudHJ5KScucGFkRW5kKDI2KX0gICAke21hbmlmZXN0LmNsaWVudEVudHJ5LnNpemVLQi5wYWRFbmQoOCl9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc29sZS5pbmZvKCcgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICAgLS0tLS0tLS0nKTtcbiAgICBjb25zb2xlLmluZm8oYCAgJHsnVE9UQUwgSlMnLnBhZEVuZCgyNil9ICAgJHtmb3JtYXRTaXplKG1hbmlmZXN0LnRvdGFsSnNCeXRlcykucGFkRW5kKDgpfWApO1xuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBDbGllbnQgSXNsYW5kczogbm9uZSAtIHplcm8gY2xpZW50IEpTJyk7XG4gIH1cblxuICBpZiAocGhhc2UgPT09IDMgJiYgbWFuaWZlc3QuaHRtbFBhZ2VzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zb2xlLmluZm8oXG4gICAgICBgXFxuICBIVE1MIFBhZ2VzICgke21hbmlmZXN0Lmh0bWxQYWdlcy5sZW5ndGh9IGZpbGVzLCAke1xuICAgICAgICBmb3JtYXRTaXplKG1hbmlmZXN0LnRvdGFsSHRtbEJ5dGVzKVxuICAgICAgfSB0b3RhbCk6YCxcbiAgICApO1xuXG4gICAgY29uc3QgbWF4U2hvdyA9IDE1O1xuICAgIGNvbnN0IHNob3duID0gbWFuaWZlc3QuaHRtbFBhZ2VzLnNsaWNlKDAsIG1heFNob3cpO1xuICAgIGZvciAoY29uc3QgcGFnZSBvZiBzaG93bikge1xuICAgICAgY29uc3QgZGlzcGxheU5hbWUgPSBwYWdlLnBhdGgubGVuZ3RoID4gNDAgPyBwYWdlLnBhdGguc2xpY2UoMCwgMzcpICsgJy4uLicgOiBwYWdlLnBhdGg7XG4gICAgICBjb25zb2xlLmluZm8oYCAgICAtICR7ZGlzcGxheU5hbWV9ICgke3BhZ2Uuc2l6ZUtCfSlgKTtcbiAgICB9XG4gICAgaWYgKG1hbmlmZXN0Lmh0bWxQYWdlcy5sZW5ndGggPiBtYXhTaG93KSB7XG4gICAgICBjb25zb2xlLmluZm8oYCAgICAuLi4gKyR7bWFuaWZlc3QuaHRtbFBhZ2VzLmxlbmd0aCAtIG1heFNob3d9IG1vcmUgcGFnZXNgKTtcbiAgICB9XG4gIH1cblxuICBpZiAobWFuaWZlc3QuaGVhZEV4dHJhc1NpemUgPiAwKSB7XG4gICAgY29uc29sZS5pbmZvKFxuICAgICAgYFxcbiAgaGVhZEV4dHJhczogJHtcbiAgICAgICAgZm9ybWF0U2l6ZShtYW5pZmVzdC5oZWFkRXh0cmFzU2l6ZSlcbiAgICAgIH0gKCR7bWFuaWZlc3QuaGVhZEV4dHJhc1NpemV9IGJ5dGVzIGluamVjdGVkKWAsXG4gICAgKTtcbiAgfVxuXG4gIGlmICh3YXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5pbmZvKCdcXG4gIEJ1ZGdldCBXYXJuaW5nczonKTtcbiAgICBmb3IgKGNvbnN0IHcgb2Ygd2FybmluZ3MpIHtcbiAgICAgIGNvbnNvbGUuaW5mbyhgICAgICAke3d9YCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBBbGwgYXJ0aWZhY3RzIHdpdGhpbiBidWRnZXQgbGltaXRzJyk7XG4gIH1cblxuICBjb25zb2xlLmluZm8oJycpO1xuXG4gIHJldHVybiBtYW5pZmVzdDtcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0NBZUMs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
package/src/build.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @openelement/adapter-vite - Build plugin
3
+ * openElement Architecture (K·I·S·S): Knowledge · Isolated · Semantic · Static
4
+ * Build produces only static files (K+S), Islands are the only JS (I).
5
+ * API Routes (S - Serverless extension) deploy separately.
6
+ *
7
+ * ADR 0011: closeBundle writes metadata to ctx, then triggers Phase 2/3.
8
+ * No globalThis bridge - ctx stays in createOpenPlugin() closure scope throughout.
9
+ */ import { join } from 'node:path';
10
+ import process from 'node:process';
11
+ import { createLogger } from '@openelement/core/logger';
12
+ import { cleanSsrArtifacts, postProcessClientIslandBuild } from '@openelement/ssg';
13
+ const log = createLogger('core');
14
+ /** Vite plugin: writes build metadata to ctx, then runs Phase 2 + Phase 3 */ export function buildPlugin(options = {}, ctx) {
15
+ let config;
16
+ return {
17
+ name: 'open:build',
18
+ configResolved (resolvedConfig) {
19
+ config = resolvedConfig;
20
+ },
21
+ async closeBundle () {
22
+ // Only run in build mode (not dev)
23
+ if (config.command !== 'build') return;
24
+ if (!ctx) {
25
+ log.warn('open:build skipped Phase 2/3 because no OpenElementBuildContext was provided.');
26
+ return;
27
+ }
28
+ // Serialize SSR noExternal patterns (RegExp -> marker objects)
29
+ const ssrNoExternal = (options.ssr?.noExternal || config.ssr?.noExternal || []).map((item)=>{
30
+ if (item instanceof RegExp) {
31
+ return {
32
+ __type: 'RegExp',
33
+ source: item.source,
34
+ flags: item.flags
35
+ };
36
+ }
37
+ return item;
38
+ });
39
+ // --- Write to OpenElementBuildContext ----------
40
+ ctx.populatePhase3(options, config, ssrNoExternal);
41
+ const totalIslands = (ctx.phase1.islandTagNames?.length || 0) + (ctx.phase1.packageIslandDecls?.length || 0);
42
+ log.info('Phase 1/3 complete - SSR bundle + metadata written to ctx');
43
+ // ADR 0023: Phase 3 (SSG) runs before Phase 2 (client bundle).
44
+ // SSG only needs Phase 1 - it renders HTML from the SSR bundle.
45
+ // Phase 2 runs last because client chunks have content hashes that
46
+ // don't affect HTML content, and injection is a post-processing step.
47
+ ctx.completePhase1();
48
+ await ctx.runPhase3(async ()=>{
49
+ const { buildSSG } = await import('./cli/build-ssg.js');
50
+ await buildSSG({}, ctx);
51
+ });
52
+ // Phase 2: Client island bundle (only if islands exist)
53
+ if (totalIslands > 0) {
54
+ await ctx.runPhase2(async ()=>{
55
+ const { buildClient } = await import('./cli/build-client.js');
56
+ await buildClient(ctx);
57
+ });
58
+ }
59
+ // -- Inject client script (only runs if Phase 2 completed) --
60
+ // Phase 2's manifest.json tells us the client chunk URLs to inject
61
+ // into the already-rendered HTML pages.
62
+ if (ctx.isPhaseComplete(2)) {
63
+ try {
64
+ const outDir = ctx.phase3.outDir || 'dist';
65
+ const root = ctx.phase3.root || process.cwd();
66
+ const clientManifestPath = join(root, outDir, 'client', '.vite', 'manifest.json');
67
+ const { existsSync, readFileSync } = await import('node:fs');
68
+ if (existsSync(clientManifestPath)) {
69
+ const manifestRaw = readFileSync(clientManifestPath, 'utf-8');
70
+ const manifest = JSON.parse(manifestRaw);
71
+ for (const [src, entry] of Object.entries(manifest)){
72
+ if ((src.includes('open-client-entry') || src.includes('virtual:open-client')) && entry.file) {
73
+ const base = ctx.phase3.base || '/';
74
+ const scriptSrc = `${base}client/${entry.file}`;
75
+ await postProcessClientIslandBuild(ctx, scriptSrc);
76
+ log.info(`Client script injected: ${scriptSrc}`);
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ } catch (error) {
82
+ log.warn(`Failed to inject client script: ${error}`);
83
+ }
84
+ } else {
85
+ log.info('No Phase 2 - client script injection skipped');
86
+ }
87
+ // -- Clean Phase 1 SSR artifacts from public dist (v0.14.10) --
88
+ try {
89
+ await cleanSsrArtifacts(ctx);
90
+ } catch (error) {
91
+ log.warn(`Failed to clean SSR artifacts: ${error}`);
92
+ }
93
+ log.info('Build complete.');
94
+ }
95
+ };
96
+ }
97
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9hZGFwdGVyLXZpdGUvc3JjL2J1aWxkLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZSAtIEJ1aWxkIHBsdWdpblxuICogb3BlbkVsZW1lbnQgQXJjaGl0ZWN0dXJlIChLwrdJwrdTwrdTKTogS25vd2xlZGdlIMK3IElzb2xhdGVkIMK3IFNlbWFudGljIMK3IFN0YXRpY1xuICogQnVpbGQgcHJvZHVjZXMgb25seSBzdGF0aWMgZmlsZXMgKEsrUyksIElzbGFuZHMgYXJlIHRoZSBvbmx5IEpTIChJKS5cbiAqIEFQSSBSb3V0ZXMgKFMgLSBTZXJ2ZXJsZXNzIGV4dGVuc2lvbikgZGVwbG95IHNlcGFyYXRlbHkuXG4gKlxuICogQURSIDAwMTE6IGNsb3NlQnVuZGxlIHdyaXRlcyBtZXRhZGF0YSB0byBjdHgsIHRoZW4gdHJpZ2dlcnMgUGhhc2UgMi8zLlxuICogTm8gZ2xvYmFsVGhpcyBicmlkZ2UgLSBjdHggc3RheXMgaW4gY3JlYXRlT3BlblBsdWdpbigpIGNsb3N1cmUgc2NvcGUgdGhyb3VnaG91dC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFBsdWdpbiwgUmVzb2x2ZWRDb25maWcgfSBmcm9tICd2aXRlJztcbmltcG9ydCB0eXBlIHsgRnJhbWV3b3JrT3B0aW9ucyB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9mcmFtZXdvcmsnO1xuaW1wb3J0IHR5cGUgeyBPcGVuRWxlbWVudEJ1aWxkQ29udGV4dCB9IGZyb20gJy4vYnVpbGQtY29udGV4dC5qcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9sb2dnZXInO1xuaW1wb3J0IHsgY2xlYW5Tc3JBcnRpZmFjdHMsIHBvc3RQcm9jZXNzQ2xpZW50SXNsYW5kQnVpbGQgfSBmcm9tICdAb3BlbmVsZW1lbnQvc3NnJztcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKCdjb3JlJyk7XG5cbi8qKiBWaXRlIHBsdWdpbjogd3JpdGVzIGJ1aWxkIG1ldGFkYXRhIHRvIGN0eCwgdGhlbiBydW5zIFBoYXNlIDIgKyBQaGFzZSAzICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRQbHVnaW4oXG4gIG9wdGlvbnM6IEZyYW1ld29ya09wdGlvbnMgJiB7IGFsbG93SGVhZEV4dHJhc1NjcmlwdHM/OiBib29sZWFuIH0gPSB7fSxcbiAgY3R4PzogT3BlbkVsZW1lbnRCdWlsZENvbnRleHQsXG4pOiBQbHVnaW4ge1xuICBsZXQgY29uZmlnOiBSZXNvbHZlZENvbmZpZztcblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICdvcGVuOmJ1aWxkJyxcblxuICAgIGNvbmZpZ1Jlc29sdmVkKHJlc29sdmVkQ29uZmlnKSB7XG4gICAgICBjb25maWcgPSByZXNvbHZlZENvbmZpZztcbiAgICB9LFxuXG4gICAgYXN5bmMgY2xvc2VCdW5kbGUoKSB7XG4gICAgICAvLyBPbmx5IHJ1biBpbiBidWlsZCBtb2RlIChub3QgZGV2KVxuICAgICAgaWYgKGNvbmZpZy5jb21tYW5kICE9PSAnYnVpbGQnKSByZXR1cm47XG5cbiAgICAgIGlmICghY3R4KSB7XG4gICAgICAgIGxvZy53YXJuKCdvcGVuOmJ1aWxkIHNraXBwZWQgUGhhc2UgMi8zIGJlY2F1c2Ugbm8gT3BlbkVsZW1lbnRCdWlsZENvbnRleHQgd2FzIHByb3ZpZGVkLicpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIFNlcmlhbGl6ZSBTU1Igbm9FeHRlcm5hbCBwYXR0ZXJucyAoUmVnRXhwIC0+IG1hcmtlciBvYmplY3RzKVxuICAgICAgY29uc3Qgc3NyTm9FeHRlcm5hbCA9ICgob3B0aW9ucy5zc3I/Lm5vRXh0ZXJuYWwgfHxcbiAgICAgICAgKGNvbmZpZy5zc3IgYXMgeyBub0V4dGVybmFsPzogKHN0cmluZyB8IFJlZ0V4cClbXSB9IHwgdW5kZWZpbmVkKT8ubm9FeHRlcm5hbCkgfHwgW10pXG4gICAgICAgIC5tYXAoKGl0ZW0pID0+IHtcbiAgICAgICAgICBpZiAoaXRlbSBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgX190eXBlOiAnUmVnRXhwJywgc291cmNlOiBpdGVtLnNvdXJjZSwgZmxhZ3M6IGl0ZW0uZmxhZ3MgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgIH0pO1xuXG4gICAgICAvLyAtLS0gV3JpdGUgdG8gT3BlbkVsZW1lbnRCdWlsZENvbnRleHQgLS0tLS0tLS0tLVxuICAgICAgY3R4LnBvcHVsYXRlUGhhc2UzKFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICBjb25maWcsXG4gICAgICAgIHNzck5vRXh0ZXJuYWwgYXMgKHN0cmluZyB8IHsgX190eXBlOiAnUmVnRXhwJzsgc291cmNlOiBzdHJpbmc7IGZsYWdzOiBzdHJpbmcgfSlbXSxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHRvdGFsSXNsYW5kcyA9IChjdHgucGhhc2UxLmlzbGFuZFRhZ05hbWVzPy5sZW5ndGggfHwgMCkgK1xuICAgICAgICAoY3R4LnBoYXNlMS5wYWNrYWdlSXNsYW5kRGVjbHM/Lmxlbmd0aCB8fCAwKTtcblxuICAgICAgbG9nLmluZm8oJ1BoYXNlIDEvMyBjb21wbGV0ZSAtIFNTUiBidW5kbGUgKyBtZXRhZGF0YSB3cml0dGVuIHRvIGN0eCcpO1xuXG4gICAgICAvLyBBRFIgMDAyMzogUGhhc2UgMyAoU1NHKSBydW5zIGJlZm9yZSBQaGFzZSAyIChjbGllbnQgYnVuZGxlKS5cbiAgICAgIC8vIFNTRyBvbmx5IG5lZWRzIFBoYXNlIDEgLSBpdCByZW5kZXJzIEhUTUwgZnJvbSB0aGUgU1NSIGJ1bmRsZS5cbiAgICAgIC8vIFBoYXNlIDIgcnVucyBsYXN0IGJlY2F1c2UgY2xpZW50IGNodW5rcyBoYXZlIGNvbnRlbnQgaGFzaGVzIHRoYXRcbiAgICAgIC8vIGRvbid0IGFmZmVjdCBIVE1MIGNvbnRlbnQsIGFuZCBpbmplY3Rpb24gaXMgYSBwb3N0LXByb2Nlc3Npbmcgc3RlcC5cbiAgICAgIGN0eC5jb21wbGV0ZVBoYXNlMSgpO1xuXG4gICAgICBhd2FpdCBjdHgucnVuUGhhc2UzKGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgeyBidWlsZFNTRyB9ID0gYXdhaXQgaW1wb3J0KCcuL2NsaS9idWlsZC1zc2cuanMnKTtcbiAgICAgICAgYXdhaXQgYnVpbGRTU0coe30sIGN0eCk7XG4gICAgICB9KTtcblxuICAgICAgLy8gUGhhc2UgMjogQ2xpZW50IGlzbGFuZCBidW5kbGUgKG9ubHkgaWYgaXNsYW5kcyBleGlzdClcbiAgICAgIGlmICh0b3RhbElzbGFuZHMgPiAwKSB7XG4gICAgICAgIGF3YWl0IGN0eC5ydW5QaGFzZTIoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgYnVpbGRDbGllbnQgfSA9IGF3YWl0IGltcG9ydCgnLi9jbGkvYnVpbGQtY2xpZW50LmpzJyk7XG4gICAgICAgICAgYXdhaXQgYnVpbGRDbGllbnQoY3R4KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIC0tIEluamVjdCBjbGllbnQgc2NyaXB0IChvbmx5IHJ1bnMgaWYgUGhhc2UgMiBjb21wbGV0ZWQpIC0tXG4gICAgICAvLyBQaGFzZSAyJ3MgbWFuaWZlc3QuanNvbiB0ZWxscyB1cyB0aGUgY2xpZW50IGNodW5rIFVSTHMgdG8gaW5qZWN0XG4gICAgICAvLyBpbnRvIHRoZSBhbHJlYWR5LXJlbmRlcmVkIEhUTUwgcGFnZXMuXG4gICAgICBpZiAoY3R4LmlzUGhhc2VDb21wbGV0ZSgyKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IG91dERpciA9IGN0eC5waGFzZTMub3V0RGlyIHx8ICdkaXN0JztcbiAgICAgICAgICBjb25zdCByb290ID0gY3R4LnBoYXNlMy5yb290IHx8IHByb2Nlc3MuY3dkKCk7XG4gICAgICAgICAgY29uc3QgY2xpZW50TWFuaWZlc3RQYXRoID0gam9pbihyb290LCBvdXREaXIsICdjbGllbnQnLCAnLnZpdGUnLCAnbWFuaWZlc3QuanNvbicpO1xuICAgICAgICAgIGNvbnN0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jIH0gPSBhd2FpdCBpbXBvcnQoJ25vZGU6ZnMnKTtcbiAgICAgICAgICBpZiAoZXhpc3RzU3luYyhjbGllbnRNYW5pZmVzdFBhdGgpKSB7XG4gICAgICAgICAgICBjb25zdCBtYW5pZmVzdFJhdyA9IHJlYWRGaWxlU3luYyhjbGllbnRNYW5pZmVzdFBhdGgsICd1dGYtOCcpO1xuICAgICAgICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKG1hbmlmZXN0UmF3KTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW3NyYywgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKG1hbmlmZXN0KSBhcyBbc3RyaW5nLCB7IGZpbGU/OiBzdHJpbmcgfV1bXSkge1xuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgKHNyYy5pbmNsdWRlcygnb3Blbi1jbGllbnQtZW50cnknKSB8fCBzcmMuaW5jbHVkZXMoJ3ZpcnR1YWw6b3Blbi1jbGllbnQnKSkgJiZcbiAgICAgICAgICAgICAgICBlbnRyeS5maWxlXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJhc2UgPSBjdHgucGhhc2UzLmJhc2UgfHwgJy8nO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNjcmlwdFNyYyA9IGAke2Jhc2V9Y2xpZW50LyR7ZW50cnkuZmlsZX1gO1xuICAgICAgICAgICAgICAgIGF3YWl0IHBvc3RQcm9jZXNzQ2xpZW50SXNsYW5kQnVpbGQoY3R4LCBzY3JpcHRTcmMpO1xuICAgICAgICAgICAgICAgIGxvZy5pbmZvKGBDbGllbnQgc2NyaXB0IGluamVjdGVkOiAke3NjcmlwdFNyY31gKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2cud2FybihgRmFpbGVkIHRvIGluamVjdCBjbGllbnQgc2NyaXB0OiAke2Vycm9yfWApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2cuaW5mbygnTm8gUGhhc2UgMiAtIGNsaWVudCBzY3JpcHQgaW5qZWN0aW9uIHNraXBwZWQnKTtcbiAgICAgIH1cblxuICAgICAgLy8gLS0gQ2xlYW4gUGhhc2UgMSBTU1IgYXJ0aWZhY3RzIGZyb20gcHVibGljIGRpc3QgKHYwLjE0LjEwKSAtLVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgY2xlYW5Tc3JBcnRpZmFjdHMoY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZy53YXJuKGBGYWlsZWQgdG8gY2xlYW4gU1NSIGFydGlmYWN0czogJHtlcnJvcn1gKTtcbiAgICAgIH1cblxuICAgICAgbG9nLmluZm8oJ0J1aWxkIGNvbXBsZXRlLicpO1xuICAgIH0sXG4gIH07XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0NBUUMsR0FLRCxTQUFTLElBQUksUUFBUSxZQUFZO0FBQ2pDLE9BQU8sYUFBYSxlQUFlO0FBQ25DLFNBQVMsWUFBWSxRQUFRLDJCQUEyQjtBQUN4RCxTQUFTLGlCQUFpQixFQUFFLDRCQUE0QixRQUFRLG1CQUFtQjtBQUVuRixNQUFNLE1BQU0sYUFBYTtBQUV6QiwyRUFBMkUsR0FDM0UsT0FBTyxTQUFTLFlBQ2QsVUFBbUUsQ0FBQyxDQUFDLEVBQ3JFLEdBQTZCO0VBRTdCLElBQUk7RUFFSixPQUFPO0lBQ0wsTUFBTTtJQUVOLGdCQUFlLGNBQWM7TUFDM0IsU0FBUztJQUNYO0lBRUEsTUFBTTtNQUNKLG1DQUFtQztNQUNuQyxJQUFJLE9BQU8sT0FBTyxLQUFLLFNBQVM7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
@@ -0,0 +1,3 @@
1
+ import type { OpenElementBuildContext } from "../build-context.js";
2
+ declare function buildClient(ctx: OpenElementBuildContext): Promise<void>;
3
+ export { buildClient };