@openelement/ssg 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.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/package.json +30 -0
- package/src/build-postprocess.d.ts +24 -0
- package/src/build-postprocess.js +74 -0
- package/src/cem-compat.js +226 -0
- package/src/entry-generators.d.ts +3 -0
- package/src/entry-generators.js +126 -0
- package/src/entry-render-helpers.js +307 -0
- package/src/entry-render-runtime.js +94 -0
- package/src/entry-render-ssg.js +169 -0
- package/src/entry-renderer.d.ts +87 -0
- package/src/entry-renderer.js +555 -0
- package/src/external-resolver.d.ts +62 -0
- package/src/external-resolver.js +285 -0
- package/src/index.d.ts +31 -0
- package/src/index.js +28 -0
- package/src/island-manifest.d.ts +27 -0
- package/src/island-manifest.js +78 -0
- package/src/postprocess.d.ts +73 -0
- package/src/postprocess.js +376 -0
- package/src/route-scanner-fs.js +29 -0
- package/src/route-scanner.d.ts +132 -0
- package/src/route-scanner.js +497 -0
- package/src/route-type-generator.d.ts +29 -0
- package/src/route-type-generator.js +99 -0
- package/src/ssg-dynamic.js +66 -0
- package/src/ssg-helpers.d.ts +8 -0
- package/src/ssg-helpers.js +96 -0
- package/src/ssg-i18n.js +78 -0
- package/src/ssg-render.d.ts +3 -0
- package/src/ssg-render.js +162 -0
- package/src/ssg-report.js +172 -0
- package/src/ssr-polyfills.d.ts +15 -0
- package/src/ssr-polyfills.js +26 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapter-vite internal SSG - Deno External Dependency Pre-Resolution (ADR-0047).
|
|
3
|
+
*
|
|
4
|
+
* Eliminates ESM subpath leaks into Rolldown by having Deno resolve all
|
|
5
|
+
* external package transitive dependencies before the bundler sees them.
|
|
6
|
+
* Produces a complete specifier list so ssr.external needs no regex.
|
|
7
|
+
*
|
|
8
|
+
* ADR-0054: AST-based specifier resolution replaces manual regex patterns.
|
|
9
|
+
* For each external package, we parse its package.json exports field to
|
|
10
|
+
* auto-discover ALL subpath exports. No more regex maintenance.
|
|
11
|
+
*/ import type { ExternalManifest } from '@openelement/protocol/ssg';
|
|
12
|
+
interface DenoInfoModule {
|
|
13
|
+
specifier: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
interface DenoInfoOutput {
|
|
17
|
+
modules: DenoInfoModule[];
|
|
18
|
+
roots: string[];
|
|
19
|
+
redirects?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* ADR-0054: Recursively walk a package.json exports field to extract all
|
|
23
|
+
* export subpaths as bare specifier strings.
|
|
24
|
+
*
|
|
25
|
+
* Handles:
|
|
26
|
+
* "." → "package-name"
|
|
27
|
+
* "./sub" → "package-name/sub"
|
|
28
|
+
* "./sub/*" → "package-name/sub/*" (wildcard, matches all sub-subpaths)
|
|
29
|
+
* "./*" → "package-name/*"
|
|
30
|
+
* Conditional → recurses into sub-conditions (import/require/default)
|
|
31
|
+
*
|
|
32
|
+
* Skips condition keys: import, require, node, default, types, browser,
|
|
33
|
+
* deno, worker, development, production, module.
|
|
34
|
+
*/ export declare function walkExports(exports: unknown, packageName: string, prefix?: string): string[];
|
|
35
|
+
/**
|
|
36
|
+
* ADR-0054: Resolve a package's exports to a complete list of bare specifiers
|
|
37
|
+
* by reading its package.json from node_modules.
|
|
38
|
+
*/ export declare function resolvePackageExports(packageName: string, projectRoot: string): string[];
|
|
39
|
+
/**
|
|
40
|
+
* ADR-0054: Complete external specifier list by resolving each package's
|
|
41
|
+
* exports via AST (package.json exports walk).
|
|
42
|
+
*/ export declare function completeExternalSpecifiers(baseSpecifiers: string[], externalPackages: string[], projectRoot: string): string[];
|
|
43
|
+
/**
|
|
44
|
+
* ADR-0047: Parse `deno info --json` output to extract all specifiers belonging
|
|
45
|
+
* to external packages. This eliminates the need for regex-based external matching
|
|
46
|
+
* that leaks ESM subpaths into Rolldown.
|
|
47
|
+
*/ export declare function extractExternalSpecifiers(denoInfo: DenoInfoOutput, externalPackages: string[]): string[];
|
|
48
|
+
/**
|
|
49
|
+
* Build a fallback manifest.
|
|
50
|
+
* Used when Deno is unavailable or skipResolution is true.
|
|
51
|
+
*
|
|
52
|
+
* ADR-0054: Uses AST-based exports resolution instead of regex patterns.
|
|
53
|
+
*/ export declare function buildFallbackManifest(externalPackages: string[], projectRoot: string): ExternalManifest;
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the complete external dependency manifest using Deno module graph.
|
|
56
|
+
*
|
|
57
|
+
* Flow:
|
|
58
|
+
* 1. Check cache (.openElement/external-manifest.json by deno.lock hash)
|
|
59
|
+
* 2. If cache miss: write temp probe module, run `deno info --json`, parse
|
|
60
|
+
* 3. Supplement with AST-based exports resolution (ADR-0054)
|
|
61
|
+
* 4. Fallback to AST-only if Deno is unavailable
|
|
62
|
+
*/ export declare function resolveExternalManifest(externalPackages: string[], projectRoot: string, skipResolution?: boolean): Promise<ExternalManifest>;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapter-vite internal SSG - Deno External Dependency Pre-Resolution (ADR-0047).
|
|
3
|
+
*
|
|
4
|
+
* Eliminates ESM subpath leaks into Rolldown by having Deno resolve all
|
|
5
|
+
* external package transitive dependencies before the bundler sees them.
|
|
6
|
+
* Produces a complete specifier list so ssr.external needs no regex.
|
|
7
|
+
*
|
|
8
|
+
* ADR-0054: AST-based specifier resolution replaces manual regex patterns.
|
|
9
|
+
* For each external package, we parse its package.json exports field to
|
|
10
|
+
* auto-discover ALL subpath exports. No more regex maintenance.
|
|
11
|
+
*/ import { join } from 'node:path';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { writeJson } from '@openelement/content/write-json';
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
15
|
+
/** Conditional keys to skip when walking exports (not subpaths). */ const CONDITION_KEYS = new Set([
|
|
16
|
+
'import',
|
|
17
|
+
'require',
|
|
18
|
+
'node',
|
|
19
|
+
'default',
|
|
20
|
+
'types',
|
|
21
|
+
'browser',
|
|
22
|
+
'deno',
|
|
23
|
+
'worker',
|
|
24
|
+
'development',
|
|
25
|
+
'production',
|
|
26
|
+
'module'
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* ADR-0054: Recursively walk a package.json exports field to extract all
|
|
30
|
+
* export subpaths as bare specifier strings.
|
|
31
|
+
*
|
|
32
|
+
* Handles:
|
|
33
|
+
* "." → "package-name"
|
|
34
|
+
* "./sub" → "package-name/sub"
|
|
35
|
+
* "./sub/*" → "package-name/sub/*" (wildcard, matches all sub-subpaths)
|
|
36
|
+
* "./*" → "package-name/*"
|
|
37
|
+
* Conditional → recurses into sub-conditions (import/require/default)
|
|
38
|
+
*
|
|
39
|
+
* Skips condition keys: import, require, node, default, types, browser,
|
|
40
|
+
* deno, worker, development, production, module.
|
|
41
|
+
*/ export function walkExports(exports, packageName, prefix = '') {
|
|
42
|
+
const results = [];
|
|
43
|
+
if (typeof exports === 'string') {
|
|
44
|
+
// Leaf: e.g. ".": "./index.js" → package-name
|
|
45
|
+
// Strip "./" prefix to get subpath: "./sub" → "sub", "./*" → "*", "." → ""
|
|
46
|
+
const subpath = prefix.replace(/^\.\/?/, '');
|
|
47
|
+
results.push(subpath ? `${packageName}/${subpath}` : packageName);
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
if (exports === null || exports === undefined) {
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(exports)) {
|
|
54
|
+
// Array fallback — take first valid
|
|
55
|
+
for (const item of exports){
|
|
56
|
+
const sub = walkExports(item, packageName, prefix);
|
|
57
|
+
if (sub.length > 0) {
|
|
58
|
+
results.push(...sub);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return results;
|
|
63
|
+
}
|
|
64
|
+
if (typeof exports === 'object') {
|
|
65
|
+
const obj = exports;
|
|
66
|
+
const hasSubpathKeys = Object.keys(obj).some((k)=>!CONDITION_KEYS.has(k));
|
|
67
|
+
const hasConditionKeys = Object.keys(obj).some((k)=>CONDITION_KEYS.has(k));
|
|
68
|
+
if (hasConditionKeys && !hasSubpathKeys) {
|
|
69
|
+
// Pure condition block: recurse into each condition
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
for (const key of Object.keys(obj)){
|
|
72
|
+
if (CONDITION_KEYS.has(key)) {
|
|
73
|
+
const sub = walkExports(obj[key], packageName, prefix);
|
|
74
|
+
for (const s of sub){
|
|
75
|
+
if (!seen.has(s)) {
|
|
76
|
+
seen.add(s);
|
|
77
|
+
results.push(s);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} else if (hasSubpathKeys) {
|
|
83
|
+
// Subpath mapping: each key is a subpath
|
|
84
|
+
for (const key of Object.keys(obj)){
|
|
85
|
+
if (CONDITION_KEYS.has(key)) continue;
|
|
86
|
+
const newPrefix = key; // e.g. ".", "./secure-headers", "./*"
|
|
87
|
+
const sub = walkExports(obj[key], packageName, newPrefix);
|
|
88
|
+
results.push(...sub);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* ADR-0054: Resolve a package's exports to a complete list of bare specifiers
|
|
96
|
+
* by reading its package.json from node_modules.
|
|
97
|
+
*/ export function resolvePackageExports(packageName, projectRoot) {
|
|
98
|
+
// Try standard node_modules resolution first
|
|
99
|
+
const candidates = [
|
|
100
|
+
join(projectRoot, 'node_modules', packageName, 'package.json'),
|
|
101
|
+
join(projectRoot, 'node_modules', '.deno', `${packageName}.node_modules`, packageName, 'package.json')
|
|
102
|
+
];
|
|
103
|
+
for (const pkgPath of candidates){
|
|
104
|
+
if (existsSync(pkgPath)) {
|
|
105
|
+
try {
|
|
106
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
107
|
+
if (pkg.exports) {
|
|
108
|
+
return walkExports(pkg.exports, packageName);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
} catch {
|
|
112
|
+
// corrupt package.json — skip
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Fallback: return just the main package name
|
|
117
|
+
return [
|
|
118
|
+
packageName
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* ADR-0054: Complete external specifier list by resolving each package's
|
|
123
|
+
* exports via AST (package.json exports walk).
|
|
124
|
+
*/ export function completeExternalSpecifiers(baseSpecifiers, externalPackages, projectRoot) {
|
|
125
|
+
const seen = new Set(baseSpecifiers);
|
|
126
|
+
const result = [
|
|
127
|
+
...baseSpecifiers
|
|
128
|
+
];
|
|
129
|
+
for (const pkg of externalPackages){
|
|
130
|
+
try {
|
|
131
|
+
const subpaths = resolvePackageExports(pkg, projectRoot);
|
|
132
|
+
for (const sp of subpaths){
|
|
133
|
+
if (!seen.has(sp)) {
|
|
134
|
+
seen.add(sp);
|
|
135
|
+
result.push(sp);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
// Package not found or has no exports — keep base specifiers
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return result.sort();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Compute a stable hash of deno.lock for cache invalidation.
|
|
146
|
+
* Returns 'no-lock' if deno.lock doesn't exist.
|
|
147
|
+
*/ function computeLockHash(projectRoot) {
|
|
148
|
+
const lockPath = join(projectRoot, 'deno.lock');
|
|
149
|
+
if (!existsSync(lockPath)) return 'no-lock';
|
|
150
|
+
const content = readFileSync(lockPath, 'utf-8');
|
|
151
|
+
return createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Read a cached manifest from .openElement/external-manifest.json.
|
|
155
|
+
* Returns null if the cache is stale (lock hash mismatch) or missing.
|
|
156
|
+
*/ function readCachedManifest(projectRoot, lockHash) {
|
|
157
|
+
const cachePath = join(projectRoot, '.openElement', 'external-manifest.json');
|
|
158
|
+
if (!existsSync(cachePath)) return null;
|
|
159
|
+
try {
|
|
160
|
+
const cached = JSON.parse(readFileSync(cachePath, 'utf-8'));
|
|
161
|
+
if (cached.lockHash === lockHash && cached.specifiers?.length > 0) {
|
|
162
|
+
return cached; // Cache hit — lock unchanged, deps stable
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
/* stale/corrupt cache — treat as miss */ }
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Write the manifest cache to .openElement/external-manifest.json.
|
|
170
|
+
*/ function writeCachedManifest(projectRoot, manifest) {
|
|
171
|
+
const dir = join(projectRoot, '.openElement');
|
|
172
|
+
if (!existsSync(dir)) mkdirSync(dir, {
|
|
173
|
+
recursive: true
|
|
174
|
+
});
|
|
175
|
+
writeFileSync(join(dir, 'external-manifest.json'), writeJson(manifest), 'utf-8');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* ADR-0047: Parse `deno info --json` output to extract all specifiers belonging
|
|
179
|
+
* to external packages. This eliminates the need for regex-based external matching
|
|
180
|
+
* that leaks ESM subpaths into Rolldown.
|
|
181
|
+
*/ export function extractExternalSpecifiers(denoInfo, externalPackages) {
|
|
182
|
+
const specifiers = new Set();
|
|
183
|
+
for (const mod of denoInfo.modules){
|
|
184
|
+
if (mod.error) continue;
|
|
185
|
+
const spec = mod.specifier;
|
|
186
|
+
// Only process npm: specifiers — these are the ones Rolldown chokes on.
|
|
187
|
+
if (!spec.startsWith('npm:')) continue;
|
|
188
|
+
for (const pkg of externalPackages){
|
|
189
|
+
// Match: npm:pkg@..., npm:pkg@.../sub/path, npm:pkg/sub/path
|
|
190
|
+
if (spec === `npm:${pkg}` || spec.startsWith(`npm:${pkg}@`) || spec.startsWith(`npm:${pkg}/`)) {
|
|
191
|
+
// Strip npm: prefix to get the bare specifier Rolldown expects.
|
|
192
|
+
const bare = spec.replace(/^npm:/, '');
|
|
193
|
+
// Strip version tag to get clean bare specifier:
|
|
194
|
+
// entities@^4/lib/escape.js → entities/lib/escape.js
|
|
195
|
+
const clean = bare.replace(/@[^/]+/, '');
|
|
196
|
+
specifiers.add(clean);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return [
|
|
201
|
+
...specifiers
|
|
202
|
+
].sort();
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Build a fallback manifest.
|
|
206
|
+
* Used when Deno is unavailable or skipResolution is true.
|
|
207
|
+
*
|
|
208
|
+
* ADR-0054: Uses AST-based exports resolution instead of regex patterns.
|
|
209
|
+
*/ export function buildFallbackManifest(externalPackages, projectRoot) {
|
|
210
|
+
const specifiers = completeExternalSpecifiers([], externalPackages, projectRoot);
|
|
211
|
+
return {
|
|
212
|
+
specifiers,
|
|
213
|
+
importMap: {},
|
|
214
|
+
generatedAt: new Date().toISOString(),
|
|
215
|
+
lockHash: 'fallback'
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Build importmap entries from Deno redirects.
|
|
220
|
+
* Only includes redirects that point to npm: URLs.
|
|
221
|
+
*/ function buildImportMapFromRedirects(output, _externalPackages) {
|
|
222
|
+
const importMap = {};
|
|
223
|
+
if (output.redirects) {
|
|
224
|
+
for (const [key, value] of Object.entries(output.redirects)){
|
|
225
|
+
// Only include redirects that start with npm:
|
|
226
|
+
if (value.startsWith('npm:')) {
|
|
227
|
+
importMap[key] = value;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return importMap;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Resolve the complete external dependency manifest using Deno module graph.
|
|
235
|
+
*
|
|
236
|
+
* Flow:
|
|
237
|
+
* 1. Check cache (.openElement/external-manifest.json by deno.lock hash)
|
|
238
|
+
* 2. If cache miss: write temp probe module, run `deno info --json`, parse
|
|
239
|
+
* 3. Supplement with AST-based exports resolution (ADR-0054)
|
|
240
|
+
* 4. Fallback to AST-only if Deno is unavailable
|
|
241
|
+
*/ export async function resolveExternalManifest(externalPackages, projectRoot, skipResolution = false) {
|
|
242
|
+
const lockHash = computeLockHash(projectRoot);
|
|
243
|
+
// Cache hit?
|
|
244
|
+
if (!skipResolution) {
|
|
245
|
+
const cached = readCachedManifest(projectRoot, lockHash);
|
|
246
|
+
if (cached) return cached;
|
|
247
|
+
}
|
|
248
|
+
if (skipResolution) {
|
|
249
|
+
return buildFallbackManifest(externalPackages, projectRoot);
|
|
250
|
+
}
|
|
251
|
+
// Try Deno pre-resolution
|
|
252
|
+
try {
|
|
253
|
+
const probeCode = externalPackages.map((pkg)=>`import '${pkg}';`).join('\n');
|
|
254
|
+
const probePath = join(projectRoot, '.openElement', '.external-probe.ts');
|
|
255
|
+
mkdirSync(join(projectRoot, '.openElement'), {
|
|
256
|
+
recursive: true
|
|
257
|
+
});
|
|
258
|
+
writeFileSync(probePath, probeCode, 'utf-8');
|
|
259
|
+
const { execSync } = await import('node:child_process');
|
|
260
|
+
const deno = execSync(`deno info --json "${probePath}"`, {
|
|
261
|
+
cwd: projectRoot,
|
|
262
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
263
|
+
timeout: 15000
|
|
264
|
+
});
|
|
265
|
+
unlinkSync(probePath);
|
|
266
|
+
const output = JSON.parse(deno.toString());
|
|
267
|
+
const baseSpecifiers = extractExternalSpecifiers(output, externalPackages);
|
|
268
|
+
// ADR-0054: Supplement with AST-based exports resolution
|
|
269
|
+
const specifiers = completeExternalSpecifiers(baseSpecifiers, externalPackages, projectRoot);
|
|
270
|
+
const importMap = buildImportMapFromRedirects(output, externalPackages);
|
|
271
|
+
const manifest = {
|
|
272
|
+
specifiers,
|
|
273
|
+
importMap,
|
|
274
|
+
generatedAt: new Date().toISOString(),
|
|
275
|
+
lockHash
|
|
276
|
+
};
|
|
277
|
+
writeCachedManifest(projectRoot, manifest);
|
|
278
|
+
return manifest;
|
|
279
|
+
} catch (_err) {
|
|
280
|
+
// Deno not available or failed — fallback to AST-based resolution
|
|
281
|
+
const fallback = buildFallbackManifest(externalPackages, projectRoot);
|
|
282
|
+
return fallback;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2V4dGVybmFsLXJlc29sdmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYWRhcHRlci12aXRlIGludGVybmFsIFNTRyAtIERlbm8gRXh0ZXJuYWwgRGVwZW5kZW5jeSBQcmUtUmVzb2x1dGlvbiAoQURSLTAwNDcpLlxuICpcbiAqIEVsaW1pbmF0ZXMgRVNNIHN1YnBhdGggbGVha3MgaW50byBSb2xsZG93biBieSBoYXZpbmcgRGVubyByZXNvbHZlIGFsbFxuICogZXh0ZXJuYWwgcGFja2FnZSB0cmFuc2l0aXZlIGRlcGVuZGVuY2llcyBiZWZvcmUgdGhlIGJ1bmRsZXIgc2VlcyB0aGVtLlxuICogUHJvZHVjZXMgYSBjb21wbGV0ZSBzcGVjaWZpZXIgbGlzdCBzbyBzc3IuZXh0ZXJuYWwgbmVlZHMgbm8gcmVnZXguXG4gKlxuICogQURSLTAwNTQ6IEFTVC1iYXNlZCBzcGVjaWZpZXIgcmVzb2x1dGlvbiByZXBsYWNlcyBtYW51YWwgcmVnZXggcGF0dGVybnMuXG4gKiBGb3IgZWFjaCBleHRlcm5hbCBwYWNrYWdlLCB3ZSBwYXJzZSBpdHMgcGFja2FnZS5qc29uIGV4cG9ydHMgZmllbGQgdG9cbiAqIGF1dG8tZGlzY292ZXIgQUxMIHN1YnBhdGggZXhwb3J0cy4gTm8gbW9yZSByZWdleCBtYWludGVuYW5jZS5cbiAqL1xuaW1wb3J0IHR5cGUgeyBFeHRlcm5hbE1hbmlmZXN0IH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL3NzZyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgeyB3cml0ZUpzb24gfSBmcm9tICdAb3BlbmVsZW1lbnQvY29udGVudC93cml0ZS1qc29uJztcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB1bmxpbmtTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnbm9kZTpmcyc7XG5cbmludGVyZmFjZSBEZW5vSW5mb01vZHVsZSB7XG4gIHNwZWNpZmllcjogc3RyaW5nO1xuICBlcnJvcj86IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIERlbm9JbmZvT3V0cHV0IHtcbiAgbW9kdWxlczogRGVub0luZm9Nb2R1bGVbXTtcbiAgcm9vdHM6IHN0cmluZ1tdO1xuICByZWRpcmVjdHM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufVxuXG4vKiogUGFja2FnZS5qc29uIG1pbmltYWwgc2hhcGUgZm9yIGV4cG9ydHMgcGFyc2luZy4gKi9cbmludGVyZmFjZSBQa2dKc29uIHtcbiAgZXhwb3J0cz86IHVua25vd247XG4gIG1haW4/OiBzdHJpbmc7XG59XG5cbi8qKiBDb25kaXRpb25hbCBrZXlzIHRvIHNraXAgd2hlbiB3YWxraW5nIGV4cG9ydHMgKG5vdCBzdWJwYXRocykuICovXG5jb25zdCBDT05ESVRJT05fS0VZUyA9IG5ldyBTZXQoW1xuICAnaW1wb3J0JyxcbiAgJ3JlcXVpcmUnLFxuICAnbm9kZScsXG4gICdkZWZhdWx0JyxcbiAgJ3R5cGVzJyxcbiAgJ2Jyb3dzZXInLFxuICAnZGVubycsXG4gICd3b3JrZXInLFxuICAnZGV2ZWxvcG1lbnQnLFxuICAncHJvZHVjdGlvbicsXG4gICdtb2R1bGUnLFxuXSk7XG5cbi8qKlxuICogQURSLTAwNTQ6IFJlY3Vyc2l2ZWx5IHdhbGsgYSBwYWNrYWdlLmpzb24gZXhwb3J0cyBmaWVsZCB0byBleHRyYWN0IGFsbFxuICogZXhwb3J0IHN1YnBhdGhzIGFzIGJhcmUgc3BlY2lmaWVyIHN0cmluZ3MuXG4gKlxuICogSGFuZGxlczpcbiAqICAgXCIuXCIgICAgICAgICAg4oaSIFwicGFja2FnZS1uYW1lXCJcbiAqICAgXCIuL3N1YlwiICAgICAg4oaSIFwicGFja2FnZS1uYW1lL3N1YlwiXG4gKiAgIFwiLi9zdWIvKlwiICAgIOKGkiBcInBhY2thZ2UtbmFtZS9zdWIvKlwiICh3aWxkY2FyZCwgbWF0Y2hlcyBhbGwgc3ViLXN1YnBhdGhzKVxuICogICBcIi4vKlwiICAgICAgICDihpIgXCJwYWNrYWdlLW5hbWUvKlwiXG4gKiAgIENvbmRpdGlvbmFsICDihpIgcmVjdXJzZXMgaW50byBzdWItY29uZGl0aW9ucyAoaW1wb3J0L3JlcXVpcmUvZGVmYXVsdClcbiAqXG4gKiBTa2lwcyBjb25kaXRpb24ga2V5czogaW1wb3J0LCByZXF1aXJlLCBub2RlLCBkZWZhdWx0LCB0eXBlcywgYnJvd3NlcixcbiAqIGRlbm8sIHdvcmtlciwgZGV2ZWxvcG1lbnQsIHByb2R1Y3Rpb24sIG1vZHVsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdhbGtFeHBvcnRzKFxuICBleHBvcnRzOiB1bmtub3duLFxuICBwYWNrYWdlTmFtZTogc3RyaW5nLFxuICBwcmVmaXggPSAnJyxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgcmVzdWx0czogc3RyaW5nW10gPSBbXTtcblxuICBpZiAodHlwZW9mIGV4cG9ydHMgPT09ICdzdHJpbmcnKSB7XG4gICAgLy8gTGVhZjogZS5nLiBcIi5cIjogXCIuL2luZGV4LmpzXCIg4oaSIHBhY2thZ2UtbmFtZVxuICAgIC8vIFN0cmlwIFwiLi9cIiBwcmVmaXggdG8gZ2V0IHN1YnBhdGg6IFwiLi9zdWJcIiDihpIgXCJzdWJcIiwgXCIuLypcIiDihpIgXCIqXCIsIFwiLlwiIOKGkiBcIlwiXG4gICAgY29uc3Qgc3VicGF0aCA9IHByZWZpeC5yZXBsYWNlKC9eXFwuXFwvPy8sICcnKTtcbiAgICByZXN1bHRzLnB1c2goc3VicGF0aCA/IGAke3BhY2thZ2VOYW1lfS8ke3N1YnBhdGh9YCA6IHBhY2thZ2VOYW1lKTtcbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIGlmIChleHBvcnRzID09PSBudWxsIHx8IGV4cG9ydHMgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoZXhwb3J0cykpIHtcbiAgICAvLyBBcnJheSBmYWxsYmFjayDigJQgdGFrZSBmaXJzdCB2YWxpZFxuICAgIGZvciAoY29uc3QgaXRlbSBvZiBleHBvcnRzKSB7XG4gICAgICBjb25zdCBzdWIgPSB3YWxrRXhwb3J0cyhpdGVtLCBwYWNrYWdlTmFtZSwgcHJlZml4KTtcbiAgICAgIGlmIChzdWIubGVuZ3RoID4gMCkge1xuICAgICAgICByZXN1bHRzLnB1c2goLi4uc3ViKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0Jykge1xuICAgIGNvbnN0IG9iaiA9IGV4cG9ydHMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG5cbiAgICBjb25zdCBoYXNTdWJwYXRoS2V5cyA9IE9iamVjdC5rZXlzKG9iaikuc29tZSgoaykgPT4gIUNPTkRJVElPTl9LRVlTLmhhcyhrKSk7XG4gICAgY29uc3QgaGFzQ29uZGl0aW9uS2V5cyA9IE9iamVjdC5rZXlzKG9iaikuc29tZSgoaykgPT4gQ09ORElUSU9OX0tFWVMuaGFzKGspKTtcblxuICAgIGlmIChoYXNDb25kaXRpb25LZXlzICYmICFoYXNTdWJwYXRoS2V5cykge1xuICAgICAgLy8gUHVyZSBjb25kaXRpb24gYmxvY2s6IHJlY3Vyc2UgaW50byBlYWNoIGNvbmRpdGlvblxuICAgICAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMob2JqKSkge1xuICAgICAgICBpZiAoQ09ORElUSU9OX0tFWVMuaGFzKGtleSkpIHtcbiAgICAgICAgICBjb25zdCBzdWIgPSB3YWxrRXhwb3J0cyhvYmpba2V5XSwgcGFja2FnZU5hbWUsIHByZWZpeCk7XG4gICAgICAgICAgZm9yIChjb25zdCBzIG9mIHN1Yikge1xuICAgICAgICAgICAgaWYgKCFzZWVuLmhhcyhzKSkge1xuICAgICAgICAgICAgICBzZWVuLmFkZChzKTtcbiAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaGFzU3VicGF0aEtleXMpIHtcbiAgICAgIC8vIFN1YnBhdGggbWFwcGluZzogZWFjaCBrZXkgaXMgYSBzdWJwYXRoXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhvYmopKSB7XG4gICAgICAgIGlmIChDT05ESVRJT05fS0VZUy5oYXMoa2V5KSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IG5ld1ByZWZpeCA9IGtleTsgLy8gZS5nLiBcIi5cIiwgXCIuL3NlY3VyZS1oZWFkZXJzXCIsIFwiLi8qXCJcbiAgICAgICAgY29uc3Qgc3ViID0gd2Fsa0V4cG9ydHMob2JqW2tleV0sIHBhY2thZ2VOYW1lLCBuZXdQcmVmaXgpO1xuICAgICAgICByZXN1bHRzLnB1c2goLi4uc3ViKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzdWx0cztcbn1cblxuLyoqXG4gKiBBRFItMDA1NDogUmVzb2x2ZSBhIHBhY2thZ2UncyBleHBvcnRzIHRvIGEgY29tcGxldGUgbGlzdCBvZiBiYXJlIHNwZWNpZmllcnNcbiAqIGJ5IHJlYWRpbmcgaXRzIHBhY2thZ2UuanNvbiBmcm9tIG5vZGVfbW9kdWxlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVQYWNrYWdlRXhwb3J0cyhwYWNrYWdlTmFtZTogc3RyaW5nLCBwcm9qZWN0Um9vdDogc3RyaW5nKTogc3RyaW5nW10ge1xuICAvLyBUcnkgc3RhbmRhcmQgbm9kZV9tb2R1bGVzIHJlc29sdXRpb24gZmlyc3RcbiAgY29uc3QgY2FuZGlkYXRlcyA9IFtcbiAgICBqb2luKHByb2plY3RSb290LCAnbm9kZV9tb2R1bGVzJywgcGFja2FnZU5hbWUsICdwYWNrYWdlLmpzb24nKSxcbiAgICBqb2luKFxuICAgICAgcHJvamVjdFJvb3QsXG4gICAgICAnbm9kZV9tb2R1bGVzJyxcbiAgICAgICcuZGVubycsXG4gICAgICBgJHtwYWNrYWdlTmFtZX0ubm9kZV9tb2R1bGVzYCxcbiAgICAgIHBhY2thZ2VOYW1lLFxuICAgICAgJ3BhY2thZ2UuanNvbicsXG4gICAgKSxcbiAgXTtcblxuICBmb3IgKGNvbnN0IHBrZ1BhdGggb2YgY2FuZGlkYXRlcykge1xuICAgIGlmIChleGlzdHNTeW5jKHBrZ1BhdGgpKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBwa2c6IFBrZ0pzb24gPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwa2dQYXRoLCAndXRmLTgnKSk7XG4gICAgICAgIGlmIChwa2cuZXhwb3J0cykge1xuICAgICAgICAgIHJldHVybiB3YWxrRXhwb3J0cyhwa2cuZXhwb3J0cywgcGFja2FnZU5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIC8vIE5vIGV4cG9ydHMgZmllbGQg4oCUIHVzZSBtYWluIG9yIGRlZmF1bHQgdG8gcGFja2FnZSBuYW1lXG4gICAgICAgIGJyZWFrO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIGNvcnJ1cHQgcGFja2FnZS5qc29uIOKAlCBza2lwXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gRmFsbGJhY2s6IHJldHVybiBqdXN0IHRoZSBtYWluIHBhY2thZ2UgbmFtZVxuICByZXR1cm4gW3BhY2thZ2VOYW1lXTtcbn1cblxuLyoqXG4gKiBBRFItMDA1NDogQ29tcGxldGUgZXh0ZXJuYWwgc3BlY2lmaWVyIGxpc3QgYnkgcmVzb2x2aW5nIGVhY2ggcGFja2FnZSdzXG4gKiBleHBvcnRzIHZpYSBBU1QgKHBhY2thZ2UuanNvbiBleHBvcnRzIHdhbGspLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGxldGVFeHRlcm5hbFNwZWNpZmllcnMoXG4gIGJhc2VTcGVjaWZpZXJzOiBzdHJpbmdbXSxcbiAgZXh0ZXJuYWxQYWNrYWdlczogc3RyaW5nW10sXG4gIHByb2plY3RSb290OiBzdHJpbmcsXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0KGJhc2VTcGVjaWZpZXJzKTtcbiAgY29uc3QgcmVzdWx0ID0gWy4uLmJhc2VTcGVjaWZpZXJzXTtcblxuICBmb3IgKGNvbnN0IHBrZyBvZiBleHRlcm5hbFBhY2thZ2VzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN1YnBhdGhzID0gcmVzb2x2ZVBhY2thZ2VFeHBvcnRzKHBrZywgcHJvamVjdFJvb3QpO1xuICAgICAgZm9yIChjb25zdCBzcCBvZiBzdWJwYXRocykge1xuICAgICAgICBpZiAoIXNlZW4uaGFzKHNwKSkge1xuICAgICAgICAgIHNlZW4uYWRkKHNwKTtcbiAgICAgICAgICByZXN1bHQucHVzaChzcCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFBhY2thZ2Ugbm90IGZvdW5kIG9yIGhhcyBubyBleHBvcnRzIOKAlCBrZWVwIGJhc2Ugc3BlY2lmaWVyc1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHQuc29ydCgpO1xufVxuXG4vKipcbiAqIENvbXB1dGUgYSBzdGFibGUgaGFzaCBvZiBkZW5vLmxvY2sgZm9yIGNhY2hlIGludmFsaWRhdGlvbi5cbiAqIFJldHVybnMgJ25vLWxvY2snIGlmIGRlbm8ubG9jayBkb2Vzbid0IGV4aXN0LlxuICovXG5mdW5jdGlvbiBjb21wdXRlTG9ja0hhc2gocHJvamVjdFJvb3Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGxvY2tQYXRoID0gam9pbihwcm9qZWN0Um9vdCwgJ2Rlbm8ubG9jaycpO1xuICBpZiAoIWV4aXN0c1N5bmMobG9ja1BhdGgpKSByZXR1cm4gJ25vLWxvY2snO1xuICBjb25zdCBjb250ZW50ID0gcmVhZEZpbGVTeW5jKGxvY2tQYXRoLCAndXRmLTgnKTtcbiAgcmV0dXJuIGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShjb250ZW50KS5kaWdlc3QoJ2hleCcpLnN1YnN0cmluZygwLCAxNik7XG59XG5cbi8qKlxuICogUmVhZCBhIGNhY2hlZCBtYW5pZmVzdCBmcm9tIC5vcGVuRWxlbWVudC9leHRlcm5hbC1tYW5pZmVzdC5qc29uLlxuICogUmV0dXJucyBudWxsIGlmIHRoZSBjYWNoZSBpcyBzdGFsZSAobG9jayBoYXNoIG1pc21hdGNoKSBvciBtaXNzaW5nLlxuICovXG5mdW5jdGlvbiByZWFkQ2FjaGVkTWFuaWZlc3QocHJvamVjdFJvb3Q6IHN0cmluZywgbG9ja0hhc2g6IHN0cmluZyk6IEV4dGVybmFsTWFuaWZlc3QgfCBudWxsIHtcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihwcm9qZWN0Um9vdCwgJy5vcGVuRWxlbWVudCcsICdleHRlcm5hbC1tYW5pZmVzdC5qc29uJyk7XG4gIGlmICghZXhpc3RzU3luYyhjYWNoZVBhdGgpKSByZXR1cm4gbnVsbDtcbiAgdHJ5IHtcbiAgICBjb25zdCBjYWNoZWQgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjYWNoZVBhdGgsICd1dGYtOCcpKSBhcyBFeHRlcm5hbE1hbmlmZXN0O1xuICAgIGlmIChjYWNoZWQubG9ja0hhc2ggPT09IGxvY2tIYXNoICYmIGNhY2hlZC5zcGVjaWZpZXJzPy5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gY2FjaGVkOyAvLyBDYWNoZSBoaXQg4oCUIGxvY2sgdW5jaGFuZ2VkLCBkZXBzIHN0YWJsZVxuICAgIH1cbiAgfSBjYXRjaCB7XG4gICAgLyogc3RhbGUvY29ycnVwdCBjYWNoZSDigJQgdHJlYXQgYXMgbWlzcyAqL1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFdyaXRlIHRoZSBtYW5pZmVzdCBjYWNoZSB0byAub3BlbkVsZW1lbnQvZXh0ZXJuYWwtbWFuaWZlc3QuanNvbi5cbiAqL1xuZnVuY3Rpb24gd3JpdGVDYWNoZWRNYW5pZmVzdChwcm9qZWN0Um9vdDogc3RyaW5nLCBtYW5pZmVzdDogRXh0ZXJuYWxNYW5pZmVzdCk6IHZvaWQge1xuICBjb25zdCBkaXIgPSBqb2luKHByb2plY3RSb290LCAnLm9wZW5FbGVtZW50Jyk7XG4gIGlmICghZXhpc3RzU3luYyhkaXIpKSBta2RpclN5bmMoZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgd3JpdGVGaWxlU3luYyhqb2luKGRpciwgJ2V4dGVybmFsLW1hbmlmZXN0Lmpzb24nKSwgd3JpdGVKc29uKG1hbmlmZXN0KSwgJ3V0Zi04Jyk7XG59XG5cbi8qKlxuICogQURSLTAwNDc6IFBhcnNlIGBkZW5vIGluZm8gLS1qc29uYCBvdXRwdXQgdG8gZXh0cmFjdCBhbGwgc3BlY2lmaWVycyBiZWxvbmdpbmdcbiAqIHRvIGV4dGVybmFsIHBhY2thZ2VzLiBUaGlzIGVsaW1pbmF0ZXMgdGhlIG5lZWQgZm9yIHJlZ2V4LWJhc2VkIGV4dGVybmFsIG1hdGNoaW5nXG4gKiB0aGF0IGxlYWtzIEVTTSBzdWJwYXRocyBpbnRvIFJvbGxkb3duLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdEV4dGVybmFsU3BlY2lmaWVycyhcbiAgZGVub0luZm86IERlbm9JbmZvT3V0cHV0LFxuICBleHRlcm5hbFBhY2thZ2VzOiBzdHJpbmdbXSxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3Qgc3BlY2lmaWVycyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGZvciAoY29uc3QgbW9kIG9mIGRlbm9JbmZvLm1vZHVsZXMpIHtcbiAgICBpZiAobW9kLmVycm9yKSBjb250aW51ZTtcbiAgICBjb25zdCBzcGVjID0gbW9kLnNwZWNpZmllcjtcbiAgICAvLyBPbmx5IHByb2Nlc3MgbnBtOiBzcGVjaWZpZXJzIOKAlCB0aGVzZSBhcmUgdGhlIG9uZXMgUm9sbGRvd24gY2hva2VzIG9uLlxuICAgIGlmICghc3BlYy5zdGFydHNXaXRoKCducG06JykpIGNvbnRpbnVlO1xuXG4gICAgZm9yIChjb25zdCBwa2cgb2YgZXh0ZXJuYWxQYWNrYWdlcykge1xuICAgICAgLy8gTWF0Y2g6IG5wbTpwa2dALi4uLCBucG06cGtnQC4uLi9zdWIvcGF0aCwgbnBtOnBrZy9zdWIvcGF0aFxuICAgICAgaWYgKFxuICAgICAgICBzcGVjID09PSBgbnBtOiR7cGtnfWAgfHxcbiAgICAgICAgc3BlYy5zdGFydHNXaXRoKGBucG06JHtwa2d9QGApIHx8XG4gICAgICAgIHNwZWMuc3RhcnRzV2l0aChgbnBtOiR7cGtnfS9gKVxuICAgICAgKSB7XG4gICAgICAgIC8vIFN0cmlwIG5wbTogcHJlZml4IHRvIGdldCB0aGUgYmFyZSBzcGVjaWZpZXIgUm9sbGRvd24gZXhwZWN0cy5cbiAgICAgICAgY29uc3QgYmFyZSA9IHNwZWMucmVwbGFjZSgvXm5wbTovLCAnJyk7XG4gICAgICAgIC8vIFN0cmlwIHZlcnNpb24gdGFnIHRvIGdldCBjbGVhbiBiYXJlIHNwZWNpZmllcjpcbiAgICAgICAgLy8gICBlbnRpdGllc0BeNC9saWIvZXNjYXBlLmpzIOKGkiBlbnRpdGllcy9saWIvZXNjYXBlLmpzXG4gICAgICAgIGNvbnN0IGNsZWFuID0gYmFyZS5yZXBsYWNlKC9AW14vXSsvLCAnJyk7XG4gICAgICAgIHNwZWNpZmllcnMuYWRkKGNsZWFuKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gWy4uLnNwZWNpZmllcnNdLnNvcnQoKTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhIGZhbGxiYWNrIG1hbmlmZXN0LlxuICogVXNlZCB3aGVuIERlbm8gaXMgdW5hdmFpbGFibGUgb3Igc2tpcFJlc29sdXRpb24gaXMgdHJ1ZS5cbiAqXG4gKiBBRFItMDA1NDogVXNlcyBBU1QtYmFzZWQgZXhwb3J0cyByZXNvbHV0aW9uIGluc3RlYWQgb2YgcmVnZXggcGF0dGVybnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEZhbGxiYWNrTWFuaWZlc3QoXG4gIGV4dGVybmFsUGFja2FnZXM6IHN0cmluZ1tdLFxuICBwcm9qZWN0Um9vdDogc3RyaW5nLFxuKTogRXh0ZXJuYWxNYW5pZmVzdCB7XG4gIGNvbnN0IHNwZWNpZmllcnMgPSBjb21wbGV0ZUV4dGVybmFsU3BlY2lmaWVycyhbXSwgZXh0ZXJuYWxQYWNrYWdlcywgcHJvamVjdFJvb3QpO1xuXG4gIHJldHVybiB7XG4gICAgc3BlY2lmaWVycyxcbiAgICBpbXBvcnRNYXA6IHt9LCAvLyBGYWxsYmFjayBza2lwcyBpbXBvcnRtYXAgZ2VuZXJhdGlvblxuICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgbG9ja0hhc2g6ICdmYWxsYmFjaycsXG4gIH07XG59XG5cbi8qKlxuICogQnVpbGQgaW1wb3J0bWFwIGVudHJpZXMgZnJvbSBEZW5vIHJlZGlyZWN0cy5cbiAqIE9ubHkgaW5jbHVkZXMgcmVkaXJlY3RzIHRoYXQgcG9pbnQgdG8gbnBtOiBVUkxzLlxuICovXG5mdW5jdGlvbiBidWlsZEltcG9ydE1hcEZyb21SZWRpcmVjdHMoXG4gIG91dHB1dDogRGVub0luZm9PdXRwdXQsXG4gIF9leHRlcm5hbFBhY2thZ2VzOiBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBpbXBvcnRNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICBpZiAob3V0cHV0LnJlZGlyZWN0cykge1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG91dHB1dC5yZWRpcmVjdHMpKSB7XG4gICAgICAvLyBPbmx5IGluY2x1ZGUgcmVkaXJlY3RzIHRoYXQgc3RhcnQgd2l0aCBucG06XG4gICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnbnBtOicpKSB7XG4gICAgICAgIGltcG9ydE1hcFtrZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGltcG9ydE1hcDtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBjb21wbGV0ZSBleHRlcm5hbCBkZXBlbmRlbmN5IG1hbmlmZXN0IHVzaW5nIERlbm8gbW9kdWxlIGdyYXBoLlxuICpcbiAqIEZsb3c6XG4gKiAxLiBDaGVjayBjYWNoZSAoLm9wZW5FbGVtZW50L2V4dGVybmFsLW1hbmlmZXN0Lmpzb24gYnkgZGVuby5sb2NrIGhhc2gpXG4gKiAyLiBJZiBjYWNoZSBtaXNzOiB3cml0ZSB0ZW1wIHByb2JlIG1vZHVsZSwgcnVuIGBkZW5vIGluZm8gLS1qc29uYCwgcGFyc2VcbiAqIDMuIFN1cHBsZW1lbnQgd2l0aCBBU1QtYmFzZWQgZXhwb3J0cyByZXNvbHV0aW9uIChBRFItMDA1NClcbiAqIDQuIEZhbGxiYWNrIHRvIEFTVC1vbmx5IGlmIERlbm8gaXMgdW5hdmFpbGFibGVcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVFeHRlcm5hbE1hbmlmZXN0KFxuICBleHRlcm5hbFBhY2thZ2VzOiBzdHJpbmdbXSxcbiAgcHJvamVjdFJvb3Q6IHN0cmluZyxcbiAgc2tpcFJlc29sdXRpb24gPSBmYWxzZSxcbik6IFByb21pc2U8RXh0ZXJuYWxNYW5pZmVzdD4ge1xuICBjb25zdCBsb2NrSGFzaCA9IGNvbXB1dGVMb2NrSGFzaChwcm9qZWN0Um9vdCk7XG5cbiAgLy8gQ2FjaGUgaGl0P1xuICBpZiAoIXNraXBSZXNvbHV0aW9uKSB7XG4gICAgY29uc3QgY2FjaGVkID0gcmVhZENhY2hlZE1hbmlmZXN0KHByb2plY3RSb290LCBsb2NrSGFzaCk7XG4gICAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcbiAgfVxuXG4gIGlmIChza2lwUmVzb2x1dGlvbikge1xuICAgIHJldHVybiBidWlsZEZhbGxiYWNrTWFuaWZlc3QoZXh0ZXJuYWxQYWNrYWdlcywgcHJvamVjdFJvb3QpO1xuICB9XG5cbiAgLy8gVHJ5IERlbm8gcHJlLXJlc29sdXRpb25cbiAgdHJ5IHtcbiAgICBjb25zdCBwcm9iZUNvZGUgPSBleHRlcm5hbFBhY2thZ2VzXG4gICAgICAubWFwKChwa2cpID0+IGBpbXBvcnQgJyR7cGtnfSc7YClcbiAgICAgIC5qb2luKCdcXG4nKTtcbiAgICBjb25zdCBwcm9iZVBhdGggPSBqb2luKHByb2plY3RSb290LCAnLm9wZW5FbGVtZW50JywgJy5leHRlcm5hbC1wcm9iZS50cycpO1xuXG4gICAgbWtkaXJTeW5jKGpvaW4ocHJvamVjdFJvb3QsICcub3BlbkVsZW1lbnQnKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgd3JpdGVGaWxlU3luYyhwcm9iZVBhdGgsIHByb2JlQ29kZSwgJ3V0Zi04Jyk7XG5cbiAgICBjb25zdCB7IGV4ZWNTeW5jIH0gPSBhd2FpdCBpbXBvcnQoJ25vZGU6Y2hpbGRfcHJvY2VzcycpO1xuICAgIGNvbnN0IGRlbm8gPSBleGVjU3luYyhcbiAgICAgIGBkZW5vIGluZm8gLS1qc29uIFwiJHtwcm9iZVBhdGh9XCJgLFxuICAgICAgeyBjd2Q6IHByb2plY3RSb290LCBtYXhCdWZmZXI6IDEwICogMTAyNCAqIDEwMjQsIHRpbWVvdXQ6IDE1MDAwIH0sXG4gICAgKTtcblxuICAgIHVubGlua1N5bmMocHJvYmVQYXRoKTtcbiAgICBjb25zdCBvdXRwdXQ6IERlbm9JbmZvT3V0cHV0ID0gSlNPTi5wYXJzZShkZW5vLnRvU3RyaW5nKCkpO1xuXG4gICAgY29uc3QgYmFzZVNwZWNpZmllcnMgPSBleHRyYWN0RXh0ZXJuYWxTcGVjaWZpZXJzKG91dHB1dCwgZXh0ZXJuYWxQYWNrYWdlcyk7XG4gICAgLy8gQURSLTAwNTQ6IFN1cHBsZW1lbnQgd2l0aCBBU1QtYmFzZWQgZXhwb3J0cyByZXNvbHV0aW9uXG4gICAgY29uc3Qgc3BlY2lmaWVycyA9IGNvbXBsZXRlRXh0ZXJuYWxTcGVjaWZpZXJzKFxuICAgICAgYmFzZVNwZWNpZmllcnMsXG4gICAgICBleHRlcm5hbFBhY2thZ2VzLFxuICAgICAgcHJvamVjdFJvb3QsXG4gICAgKTtcbiAgICBjb25zdCBpbXBvcnRNYXAgPSBidWlsZEltcG9ydE1hcEZyb21SZWRpcmVjdHMob3V0cHV0LCBleHRlcm5hbFBhY2thZ2VzKTtcblxuICAgIGNvbnN0IG1hbmlmZXN0OiBFeHRlcm5hbE1hbmlmZXN0ID0ge1xuICAgICAgc3BlY2lmaWVycyxcbiAgICAgIGltcG9ydE1hcCxcbiAgICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBsb2NrSGFzaCxcbiAgICB9O1xuXG4gICAgd3JpdGVDYWNoZWRNYW5pZmVzdChwcm9qZWN0Um9vdCwgbWFuaWZlc3QpO1xuICAgIHJldHVybiBtYW5pZmVzdDtcbiAgfSBjYXRjaCAoX2Vycikge1xuICAgIC8vIERlbm8gbm90IGF2YWlsYWJsZSBvciBmYWlsZWQg4oCUIGZhbGxiYWNrIHRvIEFTVC1iYXNlZCByZXNvbHV0aW9uXG4gICAgY29uc3QgZmFsbGJhY2sgPSBidWlsZEZhbGxiYWNrTWFuaWZlc3QoZXh0ZXJuYWxQYWNrYWdlcywgcHJvamVjdFJvb3QpO1xuICAgIHJldHVybiBmYWxsYmFjaztcbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0NBVUMsR0FFRCxTQUFTLElBQUksUUFBUSxZQUFZO0FBQ2pDLFNBQVMsVUFBVSxRQUFRLGNBQWM7QUFDekMsU0FBUyxTQUFTLFFBQVEsa0NBQWtDO0FBQzVELFNBQVMsVUFBVSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLGFBQWEsUUFBUSxVQUFVO0FBbUJ6RixrRUFBa0UsR0FDbEUsTUFBTSxpQkFBaUIsSUFBSSxJQUFJO0VBQzdCO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7Q0FDRDtBQUVEOzs7Ozs7Ozs7Ozs7O0NBYUMsR0FDRCxPQUFPLFNBQVMsWUFDZCxPQUFnQixFQUNoQixXQUFtQixFQUNuQixTQUFTLEVBQUU7RUFFWCxNQUFNLFVBQW9CLEVBQUU7RUFFNUIsSUFBSSxPQUFPLFlBQVksVUFBVTtJQUMvQiw4Q0FBOEM7SUFDOUMsMkVBQTJFO0lBQzNFLE1BQU0sVUFBVSxPQUFPLE9BQU8sQ0FBQyxVQUFVO0lBQ3pDLFFBQVEsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZLENBQUMsRUFBRSxTQUFTLEdBQUc7SUFDckQsT0FBTztFQUNUO0VBRUEsSUFBSSxZQUFZLFFB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
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/ssg - Adapter-agnostic SSG engine.
|
|
3
|
+
*
|
|
4
|
+
* Provides parallel SSG rendering, entry code generation, route scanning,
|
|
5
|
+
* island manifest generation, and HTML post-processing.
|
|
6
|
+
*
|
|
7
|
+
* This engine depends on protocol, core, router, and content — never on
|
|
8
|
+
* Vite or adapter-vite. Build adapters (e.g. adapter-vite) delegate SSG
|
|
9
|
+
* orchestration to this package.
|
|
10
|
+
*
|
|
11
|
+
* Architecture:
|
|
12
|
+
* - Sequential rendering (baseline): render pages one at a time
|
|
13
|
+
* - Parallel rendering (pool-based): render pages with concurrency limit
|
|
14
|
+
*
|
|
15
|
+
* @module @openelement/ssg
|
|
16
|
+
*/ export type { ApiRouteDecl, AppShellDecl, AppShellPlan, ClientIslandEntry, CorsOriginConfig, CspConfig, DocumentConfig, EntryDescriptor, ExternalManifest, ImportDecl, IslandDecl, MiddlewareDecl, MiddlewareScopeDecl, PageRouteDecl, ParallelRenderOptions, ParallelRenderPageOutput, ParallelRenderResult, RendererDecl, ResolvedAppShell, RouteDecl, SpeculationRulesOptions, SsgIslandDeclForReport, SsgPageInput, SsgPageOutput, SsgRenderEvidence, SsgRenderOptions, SsrAdmissionPlan, SsrBundle } from '@openelement/protocol/ssg';
|
|
17
|
+
export { resolveDynamicRoutePath, ssgRender } from "./ssg-render.js";
|
|
18
|
+
export { buildIslandChunkMap, buildSpeculationRulesJson, injectClientScript, injectCspMeta, injectDsdPolyfill, injectSpeculationRules, injectViewTransitionMeta, insertAfterHead } from "./postprocess.js";
|
|
19
|
+
export { cleanSsrArtifacts, postProcessClientIslandBuild } from "./build-postprocess.js";
|
|
20
|
+
export type { BuildContextView } from "./build-postprocess.js";
|
|
21
|
+
export { generateSsrPolyfillBanner } from "./ssr-polyfills.js";
|
|
22
|
+
export { buildFallbackManifest, completeExternalSpecifiers, extractExternalSpecifiers, resolveExternalManifest, resolvePackageExports, walkExports } from "./external-resolver.js";
|
|
23
|
+
export { detectAndClassifyCemPackages, fileToTagName, scanCemManifests, scanIslandMeta, scanIslands, scanPackageManifests, scanRoutes } from "./route-scanner.js";
|
|
24
|
+
export { generateRouteTypes } from "./route-type-generator.js";
|
|
25
|
+
export { buildEntryDescriptor, buildSsrAdmissionPlan } from "./entry-renderer.js";
|
|
26
|
+
export { generateHonoEntryCode, renderEntry } from "./entry-renderer.js";
|
|
27
|
+
export type { HonoEntryOptions } from "./entry-renderer.js";
|
|
28
|
+
export { extractCustomElementTags, generateIslandManifests, writeIslandManifests } from "./island-manifest.js";
|
|
29
|
+
export { stableHash } from "./ssg-helpers.js";
|
|
30
|
+
export type { IslandLayerMap, IslandManifestEntry, IslandStrategyMap, PageIslandManifest } from "./island-manifest.js";
|
|
31
|
+
export { generateClientEntry, validateClientIslandEntry } from "./entry-generators.js";
|
package/src/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/ssg - Adapter-agnostic SSG engine.
|
|
3
|
+
*
|
|
4
|
+
* Provides parallel SSG rendering, entry code generation, route scanning,
|
|
5
|
+
* island manifest generation, and HTML post-processing.
|
|
6
|
+
*
|
|
7
|
+
* This engine depends on protocol, core, router, and content — never on
|
|
8
|
+
* Vite or adapter-vite. Build adapters (e.g. adapter-vite) delegate SSG
|
|
9
|
+
* orchestration to this package.
|
|
10
|
+
*
|
|
11
|
+
* Architecture:
|
|
12
|
+
* - Sequential rendering (baseline): render pages one at a time
|
|
13
|
+
* - Parallel rendering (pool-based): render pages with concurrency limit
|
|
14
|
+
*
|
|
15
|
+
* @module @openelement/ssg
|
|
16
|
+
*/ export { resolveDynamicRoutePath, ssgRender } from './ssg-render.js';
|
|
17
|
+
export { buildIslandChunkMap, buildSpeculationRulesJson, injectClientScript, injectCspMeta, injectDsdPolyfill, injectSpeculationRules, injectViewTransitionMeta, insertAfterHead } from './postprocess.js';
|
|
18
|
+
export { cleanSsrArtifacts, postProcessClientIslandBuild } from './build-postprocess.js';
|
|
19
|
+
export { generateSsrPolyfillBanner } from './ssr-polyfills.js';
|
|
20
|
+
export { buildFallbackManifest, completeExternalSpecifiers, extractExternalSpecifiers, resolveExternalManifest, resolvePackageExports, walkExports } from './external-resolver.js';
|
|
21
|
+
export { detectAndClassifyCemPackages, fileToTagName, scanCemManifests, scanIslandMeta, scanIslands, scanPackageManifests, scanRoutes } from './route-scanner.js';
|
|
22
|
+
export { generateRouteTypes } from './route-type-generator.js';
|
|
23
|
+
export { buildEntryDescriptor, buildSsrAdmissionPlan } from './entry-renderer.js';
|
|
24
|
+
export { generateHonoEntryCode, renderEntry } from './entry-renderer.js';
|
|
25
|
+
export { extractCustomElementTags, generateIslandManifests, writeIslandManifests } from './island-manifest.js';
|
|
26
|
+
export { stableHash } from './ssg-helpers.js';
|
|
27
|
+
export { generateClientEntry, validateClientIslandEntry } from './entry-generators.js';
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L3NzZyAtIEFkYXB0ZXItYWdub3N0aWMgU1NHIGVuZ2luZS5cbiAqXG4gKiBQcm92aWRlcyBwYXJhbGxlbCBTU0cgcmVuZGVyaW5nLCBlbnRyeSBjb2RlIGdlbmVyYXRpb24sIHJvdXRlIHNjYW5uaW5nLFxuICogaXNsYW5kIG1hbmlmZXN0IGdlbmVyYXRpb24sIGFuZCBIVE1MIHBvc3QtcHJvY2Vzc2luZy5cbiAqXG4gKiBUaGlzIGVuZ2luZSBkZXBlbmRzIG9uIHByb3RvY29sLCBjb3JlLCByb3V0ZXIsIGFuZCBjb250ZW50IOKAlCBuZXZlciBvblxuICogVml0ZSBvciBhZGFwdGVyLXZpdGUuIEJ1aWxkIGFkYXB0ZXJzIChlLmcuIGFkYXB0ZXItdml0ZSkgZGVsZWdhdGUgU1NHXG4gKiBvcmNoZXN0cmF0aW9uIHRvIHRoaXMgcGFja2FnZS5cbiAqXG4gKiBBcmNoaXRlY3R1cmU6XG4gKiAgIC0gU2VxdWVudGlhbCByZW5kZXJpbmcgKGJhc2VsaW5lKTogcmVuZGVyIHBhZ2VzIG9uZSBhdCBhIHRpbWVcbiAqICAgLSBQYXJhbGxlbCByZW5kZXJpbmcgKHBvb2wtYmFzZWQpOiByZW5kZXIgcGFnZXMgd2l0aCBjb25jdXJyZW5jeSBsaW1pdFxuICpcbiAqIEBtb2R1bGUgQG9wZW5lbGVtZW50L3NzZ1xuICovXG5cbmV4cG9ydCB0eXBlIHtcbiAgQXBpUm91dGVEZWNsLFxuICBBcHBTaGVsbERlY2wsXG4gIEFwcFNoZWxsUGxhbixcbiAgQ2xpZW50SXNsYW5kRW50cnksXG4gIENvcnNPcmlnaW5Db25maWcsXG4gIENzcENvbmZpZyxcbiAgRG9jdW1lbnRDb25maWcsXG4gIEVudHJ5RGVzY3JpcHRvcixcbiAgRXh0ZXJuYWxNYW5pZmVzdCxcbiAgSW1wb3J0RGVjbCxcbiAgSXNsYW5kRGVjbCxcbiAgTWlkZGxld2FyZURlY2wsXG4gIE1pZGRsZXdhcmVTY29wZURlY2wsXG4gIFBhZ2VSb3V0ZURlY2wsXG4gIFBhcmFsbGVsUmVuZGVyT3B0aW9ucyxcbiAgUGFyYWxsZWxSZW5kZXJQYWdlT3V0cHV0LFxuICBQYXJhbGxlbFJlbmRlclJlc3VsdCxcbiAgUmVuZGVyZXJEZWNsLFxuICBSZXNvbHZlZEFwcFNoZWxsLFxuICBSb3V0ZURlY2wsXG4gIFNwZWN1bGF0aW9uUnVsZXNPcHRpb25zLFxuICBTc2dJc2xhbmREZWNsRm9yUmVwb3J0LFxuICBTc2dQYWdlSW5wdXQsXG4gIFNzZ1BhZ2VPdXRwdXQsXG4gIFNzZ1JlbmRlckV2aWRlbmNlLFxuICBTc2dSZW5kZXJPcHRpb25zLFxuICBTc3JBZG1pc3Npb25QbGFuLFxuICBTc3JCdW5kbGUsXG59IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9zc2cnO1xuZXhwb3J0IHsgcmVzb2x2ZUR5bmFtaWNSb3V0ZVBhdGgsIHNzZ1JlbmRlciB9IGZyb20gJy4vc3NnLXJlbmRlci5qcyc7XG5cbmV4cG9ydCB7XG4gIGJ1aWxkSXNsYW5kQ2h1bmtNYXAsXG4gIGJ1aWxkU3BlY3VsYXRpb25SdWxlc0pzb24sXG4gIGluamVjdENsaWVudFNjcmlwdCxcbiAgaW5qZWN0Q3NwTWV0YSxcbiAgaW5qZWN0RHNkUG9seWZpbGwsXG4gIGluamVjdFNwZWN1bGF0aW9uUnVsZXMsXG4gIGluamVjdFZpZXdUcmFuc2l0aW9uTWV0YSxcbiAgaW5zZXJ0QWZ0ZXJIZWFkLFxufSBmcm9tICcuL3Bvc3Rwcm9jZXNzLmpzJztcblxuZXhwb3J0IHsgY2xlYW5Tc3JBcnRpZmFjdHMsIHBvc3RQcm9jZXNzQ2xpZW50SXNsYW5kQnVpbGQgfSBmcm9tICcuL2J1aWxkLXBvc3Rwcm9jZXNzLmpzJztcbmV4cG9ydCB0eXBlIHsgQnVpbGRDb250ZXh0VmlldyB9IGZyb20gJy4vYnVpbGQtcG9zdHByb2Nlc3MuanMnO1xuXG5leHBvcnQgeyBnZW5lcmF0ZVNzclBvbHlmaWxsQmFubmVyIH0gZnJvbSAnLi9zc3ItcG9seWZpbGxzLmpzJztcbmV4cG9ydCB7XG4gIGJ1aWxkRmFsbGJhY2tNYW5pZmVzdCxcbiAgY29tcGxldGVFeHRlcm5hbFNwZWNpZmllcnMsXG4gIGV4dHJhY3RFeHRlcm5hbFNwZWNpZmllcnMsXG4gIHJlc29sdmVFeHRlcm5hbE1hbmlmZXN0LFxuICByZXNvbHZlUGFja2FnZUV4cG9ydHMsXG4gIHdhbGtFeHBvcnRzLFxufSBmcm9tICcuL2V4dGVybmFsLXJlc29sdmVyLmpzJztcblxuZXhwb3J0IHtcbiAgZGV0ZWN0QW5kQ2xhc3NpZnlDZW1QYWNrYWdlcyxcbiAgZmlsZVRvVGFnTmFtZSxcbiAgc2NhbkNlbU1hbmlmZXN0cyxcbiAgc2NhbklzbGFuZE1ldGEsXG4gIHNjYW5Jc2xhbmRzLFxuICBzY2FuUGFja2FnZU1hbmlmZXN0cyxcbiAgc2NhblJvdXRlcyxcbn0gZnJvbSAnLi9yb3V0ZS1zY2FubmVyLmpzJztcblxuZXhwb3J0IHsgZ2VuZXJhdGVSb3V0ZVR5cGVzIH0gZnJvbSAnLi9yb3V0ZS10eXBlLWdlbmVyYXRvci5qcyc7XG5cbmV4cG9ydCB7IGJ1aWxkRW50cnlEZXNjcmlwdG9yLCBidWlsZFNzckFkbWlzc2lvblBsYW4gfSBmcm9tICcuL2VudHJ5LXJlbmRlcmVyLmpzJztcblxuZXhwb3J0IHsgZ2VuZXJhdGVIb25vRW50cnlDb2RlLCByZW5kZXJFbnRyeSB9IGZyb20gJy4vZW50cnktcmVuZGVyZXIuanMnO1xuZXhwb3J0IHR5cGUgeyBIb25vRW50cnlPcHRpb25zIH0gZnJvbSAnLi9lbnRyeS1yZW5kZXJlci5qcyc7XG5cbmV4cG9ydCB7XG4gIGV4dHJhY3RDdXN0b21FbGVtZW50VGFncyxcbiAgZ2VuZXJhdGVJc2xhbmRNYW5pZmVzdHMsXG4gIHdyaXRlSXNsYW5kTWFuaWZlc3RzLFxufSBmcm9tICcuL2lzbGFuZC1tYW5pZmVzdC5qcyc7XG5cbmV4cG9ydCB7IHN0YWJsZUhhc2ggfSBmcm9tICcuL3NzZy1oZWxwZXJzLmpzJztcbmV4cG9ydCB0eXBlIHtcbiAgSXNsYW5kTGF5ZXJNYXAsXG4gIElzbGFuZE1hbmlmZXN0RW50cnksXG4gIElzbGFuZFN0cmF0ZWd5TWFwLFxuICBQYWdlSXNsYW5kTWFuaWZlc3QsXG59IGZyb20gJy4vaXNsYW5kLW1hbmlmZXN0LmpzJztcblxuZXhwb3J0IHsgZ2VuZXJhdGVDbGllbnRFbnRyeSwgdmFsaWRhdGVDbGllbnRJc2xhbmRFbnRyeSB9IGZyb20gJy4vZW50cnktZ2VuZXJhdG9ycy5qcyc7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztDQWVDLEdBZ0NELFNBQVMsdUJBQXVCLEVBQUUsU0FBUyxRQUFRLGtCQUFrQjtBQUVyRSxTQUNFLG1CQUFtQixFQUNuQix5QkFBeUIsRUFDekIsa0JBQWtCLEVBQ2xCLGFBQWEsRUFDYixpQkFBaUIsRUFDakIsc0JBQXNCLEVBQ3RCLHdCQUF3QixFQUN4QixlQUFlLFFBQ1YsbUJBQW1CO0FBRTFCLFNBQVMsaUJBQWlCLEVBQUUsNEJBQTRCLFFBQVEseUJBQXlCO0FBR3pGLFNBQVMseUJBQXlCLFFBQVEscUJBQXFCO0FBQy9ELFNBQ0UscUJBQXFCLEVBQ3JCLDBCQUEwQixFQUMxQix5QkFBeUIsRUFDekIsdUJBQXVCLEVBQ3ZCLHFCQUFxQixFQUNyQixXQUFXLFFBQ04seUJBQXlCO0FBRWhDLFNBQ0UsNEJBQTRCLEVBQzVCLGFBQWEsRUFDYixnQkFBZ0IsRUFDaEIsY0FBYyxFQUNkLFdBQVcsRUFDWCxvQkFBb0IsRUFDcEIsVUFBVSxRQUNMLHFCQUFxQjtBQUU1QixTQUFTLGtCQUFrQixRQUFRLDRCQUE0QjtBQUUvRCxTQUFTLG9CQUFvQixFQUFFLHFCQUFxQixRQUFRLHNCQUFzQjtBQUVsRixTQUFTLHFCQUFxQixFQUFFLFdBQVcsUUFBUSxzQkFBc0I7QUFHekUsU0FDRSx3QkFBd0IsRUFDeEIsdUJBQXVCLEVBQ3ZCLG9CQUFvQixRQUNmLHVCQUF1QjtBQUU5QixTQUFTLFVBQVUsUUFBUSxtQkFBbUI7QUFROUMsU0FBUyxtQkFBbUIsRUFBRSx5QkFBeUIsUUFBUSx3QkFBd0IifQ==
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ComponentLayer, HydrationStrategy } from '@openelement/protocol/framework';
|
|
2
|
+
/** Island manifest entry for a single custom element */ export interface IslandManifestEntry {
|
|
3
|
+
/** Custom element tag name (e.g. 'open-theme-toggle') */ tagName: string;
|
|
4
|
+
/** Client chunk URL relative to site root */ chunkUrl: string;
|
|
5
|
+
/** Upgrade strategy */ strategy: HydrationStrategy;
|
|
6
|
+
/** Component layer */ layer: ComponentLayer;
|
|
7
|
+
}
|
|
8
|
+
/** Per-page island manifest */ export interface PageIslandManifest {
|
|
9
|
+
/** Page route (e.g. '/guide/getting-started') */ route: string;
|
|
10
|
+
/** Islands found on this page */ islands: IslandManifestEntry[];
|
|
11
|
+
/** Build timestamp (ISO 8601) */ builtAt: string;
|
|
12
|
+
}
|
|
13
|
+
/** Strategy map type: tagName -> strategy */ export type IslandStrategyMap = Record<string, HydrationStrategy>;
|
|
14
|
+
/** Layer map type: tagName -> layer */ export type IslandLayerMap = Record<string, ComponentLayer>;
|
|
15
|
+
/**
|
|
16
|
+
* Extract custom element tag names from HTML content.
|
|
17
|
+
* Matches <xxx-yyy> or <xxx-yyy ...> patterns (custom elements must contain a hyphen).
|
|
18
|
+
* v0.14.6: Strips HTML comments, script blocks, and style blocks before matching
|
|
19
|
+
* to avoid false positives (e.g., CE tags inside comments or script content).
|
|
20
|
+
*/ export declare function extractCustomElementTags(html: string): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Generate island manifests for all HTML files in the output directory.
|
|
23
|
+
*/ export declare function generateIslandManifests(htmlDir: string, islandChunkMap: Record<string, string>, strategyMap?: IslandStrategyMap, layerMap?: IslandLayerMap): PageIslandManifest[];
|
|
24
|
+
/**
|
|
25
|
+
* Write island manifest files to disk.
|
|
26
|
+
* Each page gets its own JSON file at {outDir}/island-manifests/{route-hash}.json
|
|
27
|
+
*/ export declare function writeIslandManifests(outputDir: string, manifests: PageIslandManifest[]): Promise<void>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core - Island Upgrade Manifest
|
|
3
|
+
*
|
|
4
|
+
* Generates per-page island manifest JSON files during SSG post-processing.
|
|
5
|
+
* Each manifest lists the islands found on a page with their chunk URLs and strategies.
|
|
6
|
+
*/ import { join } from 'node:path';
|
|
7
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { writeJson } from '@openelement/content/write-json';
|
|
9
|
+
import { stableHash } from './ssg-helpers.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extract custom element tag names from HTML content.
|
|
12
|
+
* Matches <xxx-yyy> or <xxx-yyy ...> patterns (custom elements must contain a hyphen).
|
|
13
|
+
* v0.14.6: Strips HTML comments, script blocks, and style blocks before matching
|
|
14
|
+
* to avoid false positives (e.g., CE tags inside comments or script content).
|
|
15
|
+
*/ export function extractCustomElementTags(html) {
|
|
16
|
+
// Strip HTML comments, script blocks, and style blocks first
|
|
17
|
+
const cleaned = html.replace(/<!--[\s\S]*?-->/g, '') // Remove HTML comments
|
|
18
|
+
.replace(/<script[\s>][\s\S]*?<\/script>/gi, '') // Remove script blocks
|
|
19
|
+
.replace(/<style[\s>][\s\S]*?<\/style>/gi, ''); // Remove style blocks
|
|
20
|
+
const tagPattern = /<([a-z][a-z0-9]*-[a-z0-9-]+)[\s>\/]/gi;
|
|
21
|
+
const tags = new Set();
|
|
22
|
+
let match;
|
|
23
|
+
while((match = tagPattern.exec(cleaned)) !== null){
|
|
24
|
+
tags.add(match[1].toLowerCase());
|
|
25
|
+
}
|
|
26
|
+
return [
|
|
27
|
+
...tags
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generate island manifests for all HTML files in the output directory.
|
|
32
|
+
*/ export function generateIslandManifests(htmlDir, islandChunkMap, strategyMap = {}, layerMap = {}) {
|
|
33
|
+
const manifests = [];
|
|
34
|
+
if (!existsSync(htmlDir)) return manifests;
|
|
35
|
+
const entries = readdirSync(htmlDir, {
|
|
36
|
+
withFileTypes: true
|
|
37
|
+
});
|
|
38
|
+
for (const entry of entries){
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
const subManifests = generateIslandManifests(join(htmlDir, entry.name), islandChunkMap, strategyMap, layerMap);
|
|
41
|
+
for (const m of subManifests){
|
|
42
|
+
m.route = `/${entry.name}${m.route}`;
|
|
43
|
+
}
|
|
44
|
+
manifests.push(...subManifests);
|
|
45
|
+
} else if (entry.name.endsWith('.html')) {
|
|
46
|
+
const html = readFileSync(join(htmlDir, entry.name), 'utf-8');
|
|
47
|
+
const tags = extractCustomElementTags(html);
|
|
48
|
+
const islands = tags.filter((tag)=>tag in islandChunkMap).map((tag)=>({
|
|
49
|
+
tagName: tag,
|
|
50
|
+
chunkUrl: islandChunkMap[tag],
|
|
51
|
+
strategy: strategyMap[tag] || 'idle',
|
|
52
|
+
layer: layerMap[tag] || 'dsd-static'
|
|
53
|
+
}));
|
|
54
|
+
const route = entry.name === 'index.html' ? '/' : `/${entry.name.replace(/\.html$/, '')}`;
|
|
55
|
+
manifests.push({
|
|
56
|
+
route,
|
|
57
|
+
islands,
|
|
58
|
+
builtAt: new Date().toISOString()
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return manifests;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Write island manifest files to disk.
|
|
66
|
+
* Each page gets its own JSON file at {outDir}/island-manifests/{route-hash}.json
|
|
67
|
+
*/ export async function writeIslandManifests(outputDir, manifests) {
|
|
68
|
+
const manifestDir = join(outputDir, 'island-manifests');
|
|
69
|
+
mkdirSync(manifestDir, {
|
|
70
|
+
recursive: true
|
|
71
|
+
});
|
|
72
|
+
for (const manifest of manifests){
|
|
73
|
+
const hash = await stableHash(manifest.route);
|
|
74
|
+
const filename = `page-${hash}.json`;
|
|
75
|
+
writeFileSync(join(manifestDir, filename), writeJson(manifest), 'utf-8');
|
|
76
|
+
}
|
|
77
|
+
} // stableHash moved to ssg-helpers.ts — imported above
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2lzbGFuZC1tYW5pZmVzdC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBvcGVuZWxlbWVudC9jb3JlIC0gSXNsYW5kIFVwZ3JhZGUgTWFuaWZlc3RcbiAqXG4gKiBHZW5lcmF0ZXMgcGVyLXBhZ2UgaXNsYW5kIG1hbmlmZXN0IEpTT04gZmlsZXMgZHVyaW5nIFNTRyBwb3N0LXByb2Nlc3NpbmcuXG4gKiBFYWNoIG1hbmlmZXN0IGxpc3RzIHRoZSBpc2xhbmRzIGZvdW5kIG9uIGEgcGFnZSB3aXRoIHRoZWlyIGNodW5rIFVSTHMgYW5kIHN0cmF0ZWdpZXMuXG4gKi9cblxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB0eXBlIHsgQ29tcG9uZW50TGF5ZXIsIEh5ZHJhdGlvblN0cmF0ZWd5IH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL2ZyYW1ld29yayc7XG5pbXBvcnQgeyB3cml0ZUpzb24gfSBmcm9tICdAb3BlbmVsZW1lbnQvY29udGVudC93cml0ZS1qc29uJztcbmltcG9ydCB7IHN0YWJsZUhhc2ggfSBmcm9tICcuL3NzZy1oZWxwZXJzLmpzJztcblxuLyoqIElzbGFuZCBtYW5pZmVzdCBlbnRyeSBmb3IgYSBzaW5nbGUgY3VzdG9tIGVsZW1lbnQgKi9cbmV4cG9ydCBpbnRlcmZhY2UgSXNsYW5kTWFuaWZlc3RFbnRyeSB7XG4gIC8qKiBDdXN0b20gZWxlbWVudCB0YWcgbmFtZSAoZS5nLiAnb3Blbi10aGVtZS10b2dnbGUnKSAqL1xuICB0YWdOYW1lOiBzdHJpbmc7XG4gIC8qKiBDbGllbnQgY2h1bmsgVVJMIHJlbGF0aXZlIHRvIHNpdGUgcm9vdCAqL1xuICBjaHVua1VybDogc3RyaW5nO1xuICAvKiogVXBncmFkZSBzdHJhdGVneSAqL1xuICBzdHJhdGVneTogSHlkcmF0aW9uU3RyYXRlZ3k7XG4gIC8qKiBDb21wb25lbnQgbGF5ZXIgKi9cbiAgbGF5ZXI6IENvbXBvbmVudExheWVyO1xufVxuXG4vKiogUGVyLXBhZ2UgaXNsYW5kIG1hbmlmZXN0ICovXG5leHBvcnQgaW50ZXJmYWNlIFBhZ2VJc2xhbmRNYW5pZmVzdCB7XG4gIC8qKiBQYWdlIHJvdXRlIChlLmcuICcvZ3VpZGUvZ2V0dGluZy1zdGFydGVkJykgKi9cbiAgcm91dGU6IHN0cmluZztcbiAgLyoqIElzbGFuZHMgZm91bmQgb24gdGhpcyBwYWdlICovXG4gIGlzbGFuZHM6IElzbGFuZE1hbmlmZXN0RW50cnlbXTtcbiAgLyoqIEJ1aWxkIHRpbWVzdGFtcCAoSVNPIDg2MDEpICovXG4gIGJ1aWx0QXQ6IHN0cmluZztcbn1cblxuLyoqIFN0cmF0ZWd5IG1hcCB0eXBlOiB0YWdOYW1lIC0+IHN0cmF0ZWd5ICovXG5leHBvcnQgdHlwZSBJc2xhbmRTdHJhdGVneU1hcCA9IFJlY29yZDxzdHJpbmcsIEh5ZHJhdGlvblN0cmF0ZWd5PjtcblxuLyoqIExheWVyIG1hcCB0eXBlOiB0YWdOYW1lIC0+IGxheWVyICovXG5leHBvcnQgdHlwZSBJc2xhbmRMYXllck1hcCA9IFJlY29yZDxzdHJpbmcsIENvbXBvbmVudExheWVyPjtcblxuLyoqXG4gKiBFeHRyYWN0IGN1c3RvbSBlbGVtZW50IHRhZyBuYW1lcyBmcm9tIEhUTUwgY29udGVudC5cbiAqIE1hdGNoZXMgPHh4eC15eXk+IG9yIDx4eHgteXl5IC4uLj4gcGF0dGVybnMgKGN1c3RvbSBlbGVtZW50cyBtdXN0IGNvbnRhaW4gYSBoeXBoZW4pLlxuICogdjAuMTQuNjogU3RyaXBzIEhUTUwgY29tbWVudHMsIHNjcmlwdCBibG9ja3MsIGFuZCBzdHlsZSBibG9ja3MgYmVmb3JlIG1hdGNoaW5nXG4gKiB0byBhdm9pZCBmYWxzZSBwb3NpdGl2ZXMgKGUuZy4sIENFIHRhZ3MgaW5zaWRlIGNvbW1lbnRzIG9yIHNjcmlwdCBjb250ZW50KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RDdXN0b21FbGVtZW50VGFncyhodG1sOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIC8vIFN0cmlwIEhUTUwgY29tbWVudHMsIHNjcmlwdCBibG9ja3MsIGFuZCBzdHlsZSBibG9ja3MgZmlyc3RcbiAgY29uc3QgY2xlYW5lZCA9IGh0bWxcbiAgICAucmVwbGFjZSgvPCEtLVtcXHNcXFNdKj8tLT4vZywgJycpIC8vIFJlbW92ZSBIVE1MIGNvbW1lbnRzXG4gICAgLnJlcGxhY2UoLzxzY3JpcHRbXFxzPl1bXFxzXFxTXSo/PFxcL3NjcmlwdD4vZ2ksICcnKSAvLyBSZW1vdmUgc2NyaXB0IGJsb2Nrc1xuICAgIC5yZXBsYWNlKC88c3R5bGVbXFxzPl1bXFxzXFxTXSo/PFxcL3N0eWxlPi9naSwgJycpOyAvLyBSZW1vdmUgc3R5bGUgYmxvY2tzXG4gIGNvbnN0IHRhZ1BhdHRlcm4gPSAvPChbYS16XVthLXowLTldKi1bYS16MC05LV0rKVtcXHM+XFwvXS9naTtcbiAgY29uc3QgdGFncyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBsZXQgbWF0Y2g6IFJlZ0V4cEV4ZWNBcnJheSB8IG51bGw7XG4gIHdoaWxlICgobWF0Y2ggPSB0YWdQYXR0ZXJuLmV4ZWMoY2xlYW5lZCkpICE9PSBudWxsKSB7XG4gICAgdGFncy5hZGQobWF0Y2hbMV0udG9Mb3dlckNhc2UoKSk7XG4gIH1cbiAgcmV0dXJuIFsuLi50YWdzXTtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZSBpc2xhbmQgbWFuaWZlc3RzIGZvciBhbGwgSFRNTCBmaWxlcyBpbiB0aGUgb3V0cHV0IGRpcmVjdG9yeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlSXNsYW5kTWFuaWZlc3RzKFxuICBodG1sRGlyOiBzdHJpbmcsXG4gIGlzbGFuZENodW5rTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICBzdHJhdGVneU1hcDogSXNsYW5kU3RyYXRlZ3lNYXAgPSB7fSxcbiAgbGF5ZXJNYXA6IElzbGFuZExheWVyTWFwID0ge30sXG4pOiBQYWdlSXNsYW5kTWFuaWZlc3RbXSB7XG4gIGNvbnN0IG1hbmlmZXN0czogUGFnZUlzbGFuZE1hbmlmZXN0W10gPSBbXTtcblxuICBpZiAoIWV4aXN0c1N5bmMoaHRtbERpcikpIHJldHVybiBtYW5pZmVzdHM7XG5cbiAgY29uc3QgZW50cmllcyA9IHJlYWRkaXJTeW5jKGh0bWxEaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgY29uc3Qgc3ViTWFuaWZlc3RzID0gZ2VuZXJhdGVJc2xhbmRNYW5pZmVzdHMoXG4gICAgICAgIGpvaW4oaHRtbERpciwgZW50cnkubmFtZSksXG4gICAgICAgIGlzbGFuZENodW5rTWFwLFxuICAgICAgICBzdHJhdGVneU1hcCxcbiAgICAgICAgbGF5ZXJNYXAsXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCBtIG9mIHN1Yk1hbmlmZXN0cykge1xuICAgICAgICBtLnJvdXRlID0gYC8ke2VudHJ5Lm5hbWV9JHttLnJvdXRlfWA7XG4gICAgICB9XG4gICAgICBtYW5pZmVzdHMucHVzaCguLi5zdWJNYW5pZmVzdHMpO1xuICAgIH0gZWxzZSBpZiAoZW50cnkubmFtZS5lbmRzV2l0aCgnLmh0bWwnKSkge1xuICAgICAgY29uc3QgaHRtbCA9IHJlYWRGaWxlU3luYyhqb2luKGh0bWxEaXIsIGVudHJ5Lm5hbWUpLCAndXRmLTgnKTtcbiAgICAgIGNvbnN0IHRhZ3MgPSBleHRyYWN0Q3VzdG9tRWxlbWVudFRhZ3MoaHRtbCk7XG5cbiAgICAgIGNvbnN0IGlzbGFuZHM6IElzbGFuZE1hbmlmZXN0RW50cnlbXSA9IHRhZ3NcbiAgICAgICAgLmZpbHRlcigodGFnKSA9PiB0YWcgaW4gaXNsYW5kQ2h1bmtNYXApXG4gICAgICAgIC5tYXAoKHRhZykgPT4gKHtcbiAgICAgICAgICB0YWdOYW1lOiB0YWcsXG4gICAgICAgICAgY2h1bmtVcmw6IGlzbGFuZENodW5rTWFwW3RhZ10sXG4gICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5TWFwW3RhZ10gfHwgJ2lkbGUnLFxuICAgICAgICAgIGxheWVyOiBsYXllck1hcFt0YWddIHx8ICdkc2Qtc3RhdGljJyxcbiAgICAgICAgfSkpO1xuXG4gICAgICBjb25zdCByb3V0ZSA9IGVudHJ5Lm5hbWUgPT09ICdpbmRleC5odG1sJyA/ICcvJyA6IGAvJHtlbnRyeS5uYW1lLnJlcGxhY2UoL1xcLmh0bWwkLywgJycpfWA7XG5cbiAgICAgIG1hbmlmZXN0cy5wdXNoKHtcbiAgICAgICAgcm91dGUsXG4gICAgICAgIGlzbGFuZHMsXG4gICAgICAgIGJ1aWx0QXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBtYW5pZmVzdHM7XG59XG5cbi8qKlxuICogV3JpdGUgaXNsYW5kIG1hbmlmZXN0IGZpbGVzIHRvIGRpc2suXG4gKiBFYWNoIHBhZ2UgZ2V0cyBpdHMgb3duIEpTT04gZmlsZSBhdCB7b3V0RGlyfS9pc2xhbmQtbWFuaWZlc3RzL3tyb3V0ZS1oYXNofS5qc29uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZUlzbGFuZE1hbmlmZXN0cyhcbiAgb3V0cHV0RGlyOiBzdHJpbmcsXG4gIG1hbmlmZXN0czogUGFnZUlzbGFuZE1hbmlmZXN0W10sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgbWFuaWZlc3REaXIgPSBqb2luKG91dHB1dERpciwgJ2lzbGFuZC1tYW5pZmVzdHMnKTtcbiAgbWtkaXJTeW5jKG1hbmlmZXN0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICBmb3IgKGNvbnN0IG1hbmlmZXN0IG9mIG1hbmlmZXN0cykge1xuICAgIGNvbnN0IGhhc2ggPSBhd2FpdCBzdGFibGVIYXNoKG1hbmlmZXN0LnJvdXRlKTtcbiAgICBjb25zdCBmaWxlbmFtZSA9IGBwYWdlLSR7aGFzaH0uanNvbmA7XG4gICAgd3JpdGVGaWxlU3luYyhqb2luKG1hbmlmZXN0RGlyLCBmaWxlbmFtZSksIHdyaXRlSnNvbihtYW5pZmVzdCksICd1dGYtOCcpO1xuICB9XG59XG5cbi8vIHN0YWJsZUhhc2ggbW92ZWQgdG8gc3NnLWhlbHBlcnMudHMg4oCUIGltcG9ydGVkIGFib3ZlXG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0NBS0MsR0FFRCxTQUFTLElBQUksUUFBUSxZQUFZO0FBQ2pDLFNBQVMsVUFBVSxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGFBQWEsUUFBUSxVQUFVO0FBRTFGLFNBQVMsU0FBUyxRQUFRLGtDQUFrQztBQUM1RCxTQUFTLFVBQVUsUUFBUSxtQkFBbUI7QUE4QjlDOzs7OztDQUtDLEdBQ0QsT0FBTyxTQUFTLHlCQUF5QixJQUFZO0VBQ25ELDZEQUE2RDtFQUM3RCxNQUFNLFVBQVUsS0FDYixPQUFPLENBQUMsb0JBQW9CLElBQUksdUJBQXVCO0dBQ3ZELE9BQU8sQ0FBQyxvQ0FBb0MsSUFBSSx1QkFBdUI7R0FDdkUsT0FBTyxDQUFDLGtDQUFrQyxLQUFLLHNCQUFzQjtFQUN4RSxNQUFNLGFBQWE7RUFDbkIsTUFBTSxPQUFPLElBQUk7RUFDakIsSUFBSTtFQUNKLE1BQU8sQ0FBQyxRQUFRLFdBQVcsSUFBSSxDQUFDLFFBQVEsTUFBTSxLQUFNO0lBQ2xELEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsV0FBVztFQUMvQjtFQUNBLE9BQU87T0FBSTtHQUFLO0FBQ2xCO0FBRUE7O0NBRUMsR0FDRCxPQUFPLFNBQVMsd0JBQ2QsT0FBZSxFQUNmLGNBQXNDLEVBQ3RDLGNBQWlDLENBQUMsQ0FBQyxFQUNuQyxXQUEyQixDQUFDLENBQUM7RUFFN0IsTUFBTSxZQUFrQyxFQUFFO0VBRTFDLElBQUksQ0FBQyxXQUFXLFVBQVUsT0FBTztFQUVqQyxNQUFNLFVBQVUsWUFBWSxTQUFTO0lBQUUsZUFBZTtFQUFLO0VBRTNELEtBQUssTUFBTSxTQUFTLFFBQVM7SUFDM0IsSUFBSSxNQUFNLFdBQVcsSUFBSTtNQUN2QixNQUFNLGVBQWUsd0JBQ25CLEtBQUssU0FBUyxNQUFNLElBQUksR0FDeEIsZ0JBQ0EsYUFDQTtNQUVGLEtBQUssTUFBTSxLQUFLLGFBQWM7UUFDNUIsRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJLEdBQUcsRUFBRSxLQUFLLEVBQUU7TUFDdEM7TUFDQSxVQUFVLElBQUksSUFBSTtJQUNwQixPQUFPLElBQUksTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVU7TUFDdkMsTUFBTSxPQUFPLGFBQWEsS0FBSyxTQUFTLE1BQU0sSUFBSSxHQUFHO01BQ3JELE1BQU0sT0FBTyx5QkFBeUI7TUFFdEMsTUFBTSxVQUFpQyxLQUNwQyxNQUFNLENBQUMsQ0FBQyxNQUFRLE9BQU8sZ0JBQ3ZCLEdBQUcsQ0FBQyxDQUFDLE1BQVEsQ0FBQztVQUNiLFNBQVM7VUFDVCxVQUFVLGNBQWMsQ0FBQyxJQUFJO1VBQzdCLFVBQVUsV0FBVyxDQUFDLElBQUksSUFBSTtVQUM5QixPQUFPLFFBQVEsQ0FBQyxJQUFJLElBQUk7UUFDMUIsQ0FBQztNQUVILE1BQU0sUUFBUSxNQUFNLElBQUksS0FBSyxlQUFlLE1BQU0sQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsS0FBSztNQUV6RixVQUFVLElBQUksQ0FBQztRQUNiO1FBQ0E7UUFDQSxTQUFTLElBQUksT0FBTyxXQUFXO01BQ2pDO0lBQ0Y7RUFDRjtFQUVBLE9BQU87QUFDVDtBQUVBOzs7Q0FHQyxHQUNELE9BQU8sZUFBZSxxQkFDcEIsU0FBaUIsRUFDakIsU0FBK0I7RUFFL0IsTUFBTSxjQUFjLEtBQUssV0FBVztFQUNwQyxVQUFVLGFBQWE7SUFBRSxXQUFXO0VBQUs7RUFFekMsS0FBSyxNQUFNLFlBQVksVUFBVztJQUNoQyxNQUFNLE9BQU8sTUFBTSxXQUFXLFNBQVMsS0FBSztJQUM1QyxNQUFNLFdBQVcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxLQUFLLENBQUM7SUFDcEMsY0FBYyxLQUFLLGFBQWEsV0FBVyxVQUFVLFdBQVc7RUFDbEU7QUFDRixFQUVBLHNEQUFzRCJ9
|