@elaraai/e3-ui-cli 1.0.28
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/CLA.md +26 -0
- package/CONTRIBUTING.md +28 -0
- package/LICENSE.md +31 -0
- package/README.md +158 -0
- package/bin/e3-ui.mjs +13 -0
- package/dist/app/assets/dm-sans-latin-ext-wght-normal-BOFOeGcA.woff2 +0 -0
- package/dist/app/assets/dm-sans-latin-wght-normal-Xz1IZZA0.woff2 +0 -0
- package/dist/app/assets/engine-Daqj4eDD-BQb68g_1.js +4 -0
- package/dist/app/assets/index-30g1JIHt.js +2255 -0
- package/dist/app/assets/index-CYR-0Grb.css +1 -0
- package/dist/app/assets/inter-tight-cyrillic-ext-wght-normal-okcGN4Nq.woff2 +0 -0
- package/dist/app/assets/inter-tight-cyrillic-wght-normal-BS41q_Tv.woff2 +0 -0
- package/dist/app/assets/inter-tight-greek-ext-wght-normal-DQgQPNk4.woff2 +0 -0
- package/dist/app/assets/inter-tight-greek-wght-normal-sS1B39LI.woff2 +0 -0
- package/dist/app/assets/inter-tight-latin-ext-wght-normal-B4u9PlvR.woff2 +0 -0
- package/dist/app/assets/inter-tight-latin-wght-normal-DX-nOvPD.woff2 +0 -0
- package/dist/app/assets/inter-tight-vietnamese-wght-normal-TKKdAiBA.woff2 +0 -0
- package/dist/app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/app/index.html +13 -0
- package/dist/browser.d.ts +88 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +249 -0
- package/dist/browser.js.map +1 -0
- package/dist/capture.d.ts +80 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +275 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/shot.d.ts +42 -0
- package/dist/commands/shot.d.ts.map +1 -0
- package/dist/commands/shot.js +134 -0
- package/dist/commands/shot.js.map +1 -0
- package/dist/e3-server.d.ts +21 -0
- package/dist/e3-server.d.ts.map +1 -0
- package/dist/e3-server.js +34 -0
- package/dist/e3-server.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/load-source.d.ts +21 -0
- package/dist/load-source.d.ts.map +1 -0
- package/dist/load-source.js +163 -0
- package/dist/load-source.js.map +1 -0
- package/dist/payload.d.ts +26 -0
- package/dist/payload.d.ts.map +1 -0
- package/dist/payload.js +87 -0
- package/dist/payload.js.map +1 -0
- package/dist/render.d.ts +80 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +79 -0
- package/dist/render.js.map +1 -0
- package/dist/shot-payload.d.ts +31 -0
- package/dist/shot-payload.d.ts.map +1 -0
- package/dist/shot-payload.js +6 -0
- package/dist/shot-payload.js.map +1 -0
- package/package.json +82 -0
package/dist/capture.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Headless capture: serve the prebuilt browser app, inject the component
|
|
7
|
+
* payload, wait for fonts + render to settle, and screenshot to PNG.
|
|
8
|
+
*
|
|
9
|
+
* The app is served over a throwaway `node:http` server (NOT `file://` —
|
|
10
|
+
* Chromium blocks ES-module scripts loaded from `file://` on CORS grounds).
|
|
11
|
+
* The wait/settle/screenshot loop mirrors the in-repo snapshot pipeline
|
|
12
|
+
* (`libs/east-ui/scripts/snapshot-capture.mts`).
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
import { createServer } from 'node:http';
|
|
17
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { once } from 'node:events';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { launchBrowser } from './browser.js';
|
|
22
|
+
/** Default capture parameters — single source of truth (CLI help text in
|
|
23
|
+
* `cli.ts` documents these values; keep them in sync). */
|
|
24
|
+
export const CAPTURE_DEFAULTS = {
|
|
25
|
+
viewport: { width: 1280, height: 900 },
|
|
26
|
+
deviceScaleFactor: 2,
|
|
27
|
+
settleMs: 300,
|
|
28
|
+
timeoutMs: 30_000,
|
|
29
|
+
storageKey: 'shot',
|
|
30
|
+
statusPollMs: 100,
|
|
31
|
+
skeletonPollMs: 200,
|
|
32
|
+
errorTextLimit: 600,
|
|
33
|
+
};
|
|
34
|
+
const MIME = {
|
|
35
|
+
'.html': 'text/html; charset=utf-8',
|
|
36
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
37
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
38
|
+
'.css': 'text/css; charset=utf-8',
|
|
39
|
+
'.json': 'application/json; charset=utf-8',
|
|
40
|
+
'.map': 'application/json; charset=utf-8',
|
|
41
|
+
'.woff2': 'font/woff2',
|
|
42
|
+
'.woff': 'font/woff',
|
|
43
|
+
'.svg': 'image/svg+xml',
|
|
44
|
+
'.png': 'image/png',
|
|
45
|
+
'.ico': 'image/x-icon',
|
|
46
|
+
};
|
|
47
|
+
/** Serve the prebuilt app directory over a random localhost port. */
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a URL pathname to a file within `root`, or `null` if it would escape
|
|
50
|
+
* (path traversal). Uses a separator-boundary check so a sibling dir sharing the
|
|
51
|
+
* root's prefix cannot pass. Exported for unit tests.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveWithinRoot(root, urlPathname) {
|
|
54
|
+
const resolvedRoot = path.resolve(root);
|
|
55
|
+
const rel = urlPathname === '/' ? 'index.html' : urlPathname.replace(/^\/+/, '');
|
|
56
|
+
const filePath = path.join(resolvedRoot, rel);
|
|
57
|
+
if (filePath !== resolvedRoot && !filePath.startsWith(resolvedRoot + path.sep))
|
|
58
|
+
return null;
|
|
59
|
+
return filePath;
|
|
60
|
+
}
|
|
61
|
+
function serveApp(appDir) {
|
|
62
|
+
const root = path.resolve(appDir);
|
|
63
|
+
const server = createServer((req, res) => {
|
|
64
|
+
void (async () => {
|
|
65
|
+
try {
|
|
66
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
67
|
+
const filePath = resolveWithinRoot(root, url.pathname);
|
|
68
|
+
if (!filePath) {
|
|
69
|
+
res.statusCode = 403;
|
|
70
|
+
res.end('forbidden');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const body = await readFile(filePath);
|
|
74
|
+
res.statusCode = 200;
|
|
75
|
+
res.setHeader('content-type', MIME[path.extname(filePath).toLowerCase()] ?? 'application/octet-stream');
|
|
76
|
+
res.end(body);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
res.statusCode = 404;
|
|
80
|
+
res.end('not found');
|
|
81
|
+
}
|
|
82
|
+
})();
|
|
83
|
+
});
|
|
84
|
+
return once(server.listen(0, '127.0.0.1'), 'listening').then(() => {
|
|
85
|
+
const port = server.address().port;
|
|
86
|
+
return { server, baseUrl: `http://127.0.0.1:${port}` };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Escape text for safe inclusion in HTML. Exported for unit tests. */
|
|
90
|
+
export function escapeHtml(s) {
|
|
91
|
+
return s.replace(/[&<>"']/g, c => ({
|
|
92
|
+
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
93
|
+
}[c]));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Inline `url(...woff2)` font references in CSS as base64 data URIs (read from
|
|
97
|
+
* the app's built `assets/`), so the standalone HTML renders with the brand
|
|
98
|
+
* fonts over `file://` with no server. A font that cannot be read is left as its
|
|
99
|
+
* original (server-relative) URL and a warning is emitted — a silently broken
|
|
100
|
+
* `--html` is worse than a visible warning. Exported for unit tests.
|
|
101
|
+
*/
|
|
102
|
+
export async function inlineFonts(css, appDir) {
|
|
103
|
+
const assetsDir = path.join(appDir, 'assets');
|
|
104
|
+
const re = /url\((['"]?)[^)'"]*?([^/)'"]+\.woff2)\1\)/g;
|
|
105
|
+
const cache = new Map();
|
|
106
|
+
for (const m of css.matchAll(re)) {
|
|
107
|
+
const name = m[2];
|
|
108
|
+
if (cache.has(name))
|
|
109
|
+
continue;
|
|
110
|
+
try {
|
|
111
|
+
const buf = await readFile(path.join(assetsDir, name));
|
|
112
|
+
cache.set(name, `data:font/woff2;base64,${buf.toString('base64')}`);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
cache.set(name, '');
|
|
116
|
+
console.warn(`[e3-ui shot] could not inline font "${name}" into --html — it will be a relative URL that won't resolve standalone.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return css.replace(re, (full, _q, name) => {
|
|
120
|
+
const uri = cache.get(name);
|
|
121
|
+
return uri ? `url(${uri})` : full;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Build a self-contained HTML snapshot: the rendered body + every stylesheet
|
|
126
|
+
* rule serialized into one `<style>` block (Emotion injects rules via
|
|
127
|
+
* `insertRule`, so they are NOT in the serialized DOM and must be read from
|
|
128
|
+
* `document.styleSheets`), with fonts inlined and no scripts.
|
|
129
|
+
*/
|
|
130
|
+
async function selfContainedHtml(page, appDir) {
|
|
131
|
+
const { bodyHtml, cssText, title } = await page.evaluate(() => {
|
|
132
|
+
// `document.styleSheets` (Emotion's injected <style>s) PLUS
|
|
133
|
+
// `adoptedStyleSheets` (constructable sheets — where Vite injects the
|
|
134
|
+
// @fontsource @font-face rules, which the styleSheets list misses).
|
|
135
|
+
const sheets = [
|
|
136
|
+
...Array.from(document.styleSheets),
|
|
137
|
+
...(document.adoptedStyleSheets ?? []),
|
|
138
|
+
];
|
|
139
|
+
const css = sheets
|
|
140
|
+
.map(sheet => {
|
|
141
|
+
try {
|
|
142
|
+
return Array.from(sheet.cssRules).map(r => r.cssText).join('\n');
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return '';
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
.filter(Boolean)
|
|
149
|
+
.join('\n\n');
|
|
150
|
+
return { bodyHtml: document.body.innerHTML, cssText: css, title: document.title || 'e3-ui shot' };
|
|
151
|
+
});
|
|
152
|
+
const inlined = await inlineFonts(cssText, appDir);
|
|
153
|
+
return `<!DOCTYPE html>
|
|
154
|
+
<html lang="en">
|
|
155
|
+
<head>
|
|
156
|
+
<meta charset="UTF-8" />
|
|
157
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
158
|
+
<title>${escapeHtml(title)}</title>
|
|
159
|
+
<style>
|
|
160
|
+
${inlined}
|
|
161
|
+
</style>
|
|
162
|
+
</head>
|
|
163
|
+
<body>
|
|
164
|
+
${bodyHtml}
|
|
165
|
+
</body>
|
|
166
|
+
</html>
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Render a component payload to a PNG (and optionally a standalone HTML).
|
|
171
|
+
*
|
|
172
|
+
* @param opts - Capture options
|
|
173
|
+
* @throws If the app reports a compile/render error, or capture times out
|
|
174
|
+
*/
|
|
175
|
+
export async function capture(opts) {
|
|
176
|
+
const viewport = opts.viewport ?? CAPTURE_DEFAULTS.viewport;
|
|
177
|
+
const deviceScaleFactor = opts.deviceScaleFactor ?? CAPTURE_DEFAULTS.deviceScaleFactor;
|
|
178
|
+
const mode = opts.mode ?? { kind: 'frame' };
|
|
179
|
+
const settleMs = opts.settleMs ?? CAPTURE_DEFAULTS.settleMs;
|
|
180
|
+
const timeout = opts.timeoutMs ?? CAPTURE_DEFAULTS.timeoutMs;
|
|
181
|
+
const storageKey = opts.storageKey ?? CAPTURE_DEFAULTS.storageKey;
|
|
182
|
+
// Pre-flight: fail clearly if the prebuilt app is missing, instead of
|
|
183
|
+
// letting a 404 page turn into an opaque navigation timeout.
|
|
184
|
+
if (!existsSync(path.join(opts.appDir, 'index.html'))) {
|
|
185
|
+
throw new Error(`Prebuilt app not found at ${opts.appDir} — run \`make build\` (or \`npm run build\`) first.`);
|
|
186
|
+
}
|
|
187
|
+
const { server, baseUrl } = await serveApp(opts.appDir);
|
|
188
|
+
let browser;
|
|
189
|
+
try {
|
|
190
|
+
({ browser } = await launchBrowser());
|
|
191
|
+
const context = await browser.newContext({ viewport, deviceScaleFactor });
|
|
192
|
+
const page = await context.newPage();
|
|
193
|
+
const consoleErrors = [];
|
|
194
|
+
page.on('pageerror', err => consoleErrors.push(err.message));
|
|
195
|
+
page.on('console', msg => { if (msg.type() === 'error')
|
|
196
|
+
consoleErrors.push(msg.text()); });
|
|
197
|
+
// Inject the payload BEFORE any page script runs. The task-mode hard-stop
|
|
198
|
+
// deadline is derived from the capture timeout (minus a buffer) so the app
|
|
199
|
+
// always reports before the driver's navigation timeout fires.
|
|
200
|
+
const taskDeadlineMs = Math.max(5_000, timeout - 5_000);
|
|
201
|
+
await page.addInitScript(([p, key, deadline]) => {
|
|
202
|
+
window.__E3_UI_SHOT__ = p;
|
|
203
|
+
window.__E3_UI_SHOT_KEY__ = key;
|
|
204
|
+
window.__E3_UI_SHOT_DEADLINE__ = deadline;
|
|
205
|
+
}, [opts.payload, storageKey, taskDeadlineMs]);
|
|
206
|
+
// Component mode has no e3 polling, so wait for `networkidle` (catches
|
|
207
|
+
// lazy chunks / Map tiles / chart sizing). Task mode polls the e3 server
|
|
208
|
+
// so the network never idles — use `load` and rely on the readiness marker.
|
|
209
|
+
await page.goto(`${baseUrl}/`, {
|
|
210
|
+
waitUntil: opts.payload.kind === 'task' ? 'load' : 'networkidle',
|
|
211
|
+
timeout,
|
|
212
|
+
});
|
|
213
|
+
await page.evaluate(() => document.fonts.ready);
|
|
214
|
+
// Both modes signal terminal state on #shot-root[data-shot-status]:
|
|
215
|
+
// 'ready' once content has rendered (component: next frame; task: once
|
|
216
|
+
// e3 fetches settle), or 'error' on an East compile/render failure.
|
|
217
|
+
try {
|
|
218
|
+
await page.waitForFunction(() => {
|
|
219
|
+
const s = document.querySelector('#shot-root')?.getAttribute('data-shot-status');
|
|
220
|
+
return s === 'ready' || s === 'error';
|
|
221
|
+
}, { timeout, polling: CAPTURE_DEFAULTS.statusPollMs });
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
const detail = consoleErrors.length ? `\nBrowser errors:\n ${consoleErrors.join('\n ')}` : '';
|
|
225
|
+
throw new Error(`Timed out after ${timeout}ms waiting for the render to complete.${detail}\n` +
|
|
226
|
+
`(For a slow live task raise --timeout; otherwise the component may have failed to load.)`);
|
|
227
|
+
}
|
|
228
|
+
// Surface render/compile failures via stable hooks (NOT title-text
|
|
229
|
+
// scraping): data-shot-status='error', [data-east-error] from
|
|
230
|
+
// EastErrorDisplay (component mode), and [data-status="error"] from
|
|
231
|
+
// e3-ui's StatusDisplay / ErrorBoundary (task fetch/decode/render errors).
|
|
232
|
+
const renderError = await page.evaluate((limit) => {
|
|
233
|
+
const root = document.querySelector('#shot-root');
|
|
234
|
+
if (root?.getAttribute('data-shot-status') === 'error') {
|
|
235
|
+
return root.getAttribute('data-shot-error') ?? 'unknown render error';
|
|
236
|
+
}
|
|
237
|
+
const card = document.querySelector('[data-east-error], [data-status="error"]');
|
|
238
|
+
return card ? card.innerText.slice(0, limit) : null;
|
|
239
|
+
}, CAPTURE_DEFAULTS.errorTextLimit);
|
|
240
|
+
if (renderError) {
|
|
241
|
+
throw new Error(`Render failed:\n${renderError}`);
|
|
242
|
+
}
|
|
243
|
+
// A live task that hit its hard-stop without settling marks itself partial.
|
|
244
|
+
const partial = await page.evaluate(() => document.querySelector('#shot-root')?.getAttribute('data-shot-partial') === 'true');
|
|
245
|
+
if (partial) {
|
|
246
|
+
console.warn('[e3-ui shot] the live task did not finish loading before capture — the image may be incomplete (raise --timeout).');
|
|
247
|
+
}
|
|
248
|
+
// Let in-component skeletons clear, then settle. A component may keep a
|
|
249
|
+
// skeleton legitimately (slow async chart/map) — warn rather than fail,
|
|
250
|
+
// mirroring the in-repo snapshot pipeline.
|
|
251
|
+
await page
|
|
252
|
+
.waitForFunction(() => document.querySelectorAll('.elara-skeleton').length === 0, { timeout, polling: CAPTURE_DEFAULTS.skeletonPollMs })
|
|
253
|
+
.catch(() => console.warn('[e3-ui shot] skeletons still present at capture — the image may be premature (raise --wait).'));
|
|
254
|
+
await page.waitForTimeout(settleMs);
|
|
255
|
+
if (mode.kind === 'full-page') {
|
|
256
|
+
await page.screenshot({ path: opts.outPng, fullPage: true });
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
const selector = mode.kind === 'element' ? mode.selector : '#shot-frame';
|
|
260
|
+
const locator = page.locator(selector);
|
|
261
|
+
if (await locator.count() === 0) {
|
|
262
|
+
throw new Error(`No element matches selector "${selector}" to screenshot.`);
|
|
263
|
+
}
|
|
264
|
+
await locator.first().screenshot({ path: opts.outPng });
|
|
265
|
+
}
|
|
266
|
+
if (opts.outHtml) {
|
|
267
|
+
await writeFile(opts.outHtml, await selfContainedHtml(page, opts.appDir), 'utf8');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
finally {
|
|
271
|
+
await browser?.close();
|
|
272
|
+
server.close();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* e3-ui CLI — render east-ui / e3-ui components to PNG.
|
|
7
|
+
*
|
|
8
|
+
* One screenshot verb, three `--from-*` sources (mirroring e3-cli's
|
|
9
|
+
* `--from-zip` / `--from-source`):
|
|
10
|
+
* e3-ui shot --from-source <file.tsx> a TS/TSX component
|
|
11
|
+
* e3-ui shot --from-ir <file.beast2|.json> serialized component IR
|
|
12
|
+
* e3-ui shot --from-task <ws.task> --repo <r> a live e3 task's output (dataflow must have run)
|
|
13
|
+
*
|
|
14
|
+
* Plus the browser lifecycle for headless servers:
|
|
15
|
+
* e3-ui install-browser [--with-deps] download the managed headless Chromium
|
|
16
|
+
* e3-ui doctor diagnose the browser setup
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
import { createRequire } from 'node:module';
|
|
21
|
+
import { Command } from 'commander';
|
|
22
|
+
import { shotCommand } from './commands/shot.js';
|
|
23
|
+
import { installBrowser, doctor } from './browser.js';
|
|
24
|
+
import { CAPTURE_DEFAULTS as D } from './capture.js';
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const packageJson = require('../package.json');
|
|
27
|
+
const program = new Command();
|
|
28
|
+
program
|
|
29
|
+
.name('e3-ui')
|
|
30
|
+
.description('Render east-ui / e3-ui components to PNG')
|
|
31
|
+
.version(packageJson.version);
|
|
32
|
+
program
|
|
33
|
+
.command('shot')
|
|
34
|
+
.description('Render an east-ui / e3-ui component to a PNG — from a source file, serialized IR, or a live e3 task')
|
|
35
|
+
// Exactly one source (mutually exclusive).
|
|
36
|
+
.option('--from-source <file>', 'Render a TS/TSX component source file (.ts/.tsx)')
|
|
37
|
+
.option('--from-ir <file>', 'Render serialized component IR (.beast2/.json); "-" reads from stdin')
|
|
38
|
+
.option('--from-task <ws.task>', 'Render a live e3 task\'s output (requires --repo; the workspace dataflow must have already run)')
|
|
39
|
+
.option('--repo <path>', 'Local e3 repository path for --from-task')
|
|
40
|
+
// --from-source only.
|
|
41
|
+
.option('-e, --export <name>', 'Which exported component to render (default: the default / sole export)')
|
|
42
|
+
// Shared.
|
|
43
|
+
.option('-o, --output <path>', 'Output PNG path (default: derived from the source / task name)')
|
|
44
|
+
.option('--html', 'Also write a self-contained HTML next to the PNG')
|
|
45
|
+
.option('--viewport <WxH>', `Chromium viewport (default ${D.viewport.width}x${D.viewport.height})`)
|
|
46
|
+
.option('--dpr <n>', `Device scale factor / pixel ratio (default ${D.deviceScaleFactor})`)
|
|
47
|
+
.option('--full-page', 'Capture the full page instead of the component frame')
|
|
48
|
+
.option('--element <selector>', 'Capture a specific CSS selector instead of the component frame')
|
|
49
|
+
.option('--wait <ms>', `Extra settle time after fonts/skeletons clear (default ${D.settleMs})`)
|
|
50
|
+
.option('--timeout <ms>', `Max time to wait for the render to complete (default ${D.timeoutMs}); raise for slow live tasks`)
|
|
51
|
+
.option('--storage-key <key>', 'Storage key prefix for persisted component state')
|
|
52
|
+
.action(shotCommand);
|
|
53
|
+
program
|
|
54
|
+
.command('install-browser')
|
|
55
|
+
.description('Download the version-matched headless Chromium into the playwright-managed cache (honors PLAYWRIGHT_BROWSERS_PATH)')
|
|
56
|
+
.option('--with-deps', 'Also install required system libraries (Linux only)')
|
|
57
|
+
.action(async (options) => {
|
|
58
|
+
process.exit(await installBrowser(options));
|
|
59
|
+
});
|
|
60
|
+
program
|
|
61
|
+
.command('doctor')
|
|
62
|
+
.description('Diagnose the browser setup: env overrides, launch cascade, and remediation')
|
|
63
|
+
.action(async () => {
|
|
64
|
+
process.exit(await doctor());
|
|
65
|
+
});
|
|
66
|
+
program.parseAsync().catch((err) => {
|
|
67
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,IAAI,CAAC,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACF,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAElC,OAAO;KACF,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,qGAAqG,CAAC;IACnH,2CAA2C;KAC1C,MAAM,CAAC,sBAAsB,EAAE,kDAAkD,CAAC;KAClF,MAAM,CAAC,kBAAkB,EAAE,sEAAsE,CAAC;KAClG,MAAM,CAAC,uBAAuB,EAAE,iGAAiG,CAAC;KAClI,MAAM,CAAC,eAAe,EAAE,0CAA0C,CAAC;IACpE,sBAAsB;KACrB,MAAM,CAAC,qBAAqB,EAAE,yEAAyE,CAAC;IACzG,UAAU;KACT,MAAM,CAAC,qBAAqB,EAAE,gEAAgE,CAAC;KAC/F,MAAM,CAAC,QAAQ,EAAE,kDAAkD,CAAC;KACpE,MAAM,CAAC,kBAAkB,EAAE,8BAA8B,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;KAClG,MAAM,CAAC,WAAW,EAAE,8CAA8C,CAAC,CAAC,iBAAiB,GAAG,CAAC;KACzF,MAAM,CAAC,aAAa,EAAE,sDAAsD,CAAC;KAC7E,MAAM,CAAC,sBAAsB,EAAE,gEAAgE,CAAC;KAChG,MAAM,CAAC,aAAa,EAAE,0DAA0D,CAAC,CAAC,QAAQ,GAAG,CAAC;KAC9F,MAAM,CAAC,gBAAgB,EAAE,wDAAwD,CAAC,CAAC,SAAS,8BAA8B,CAAC;KAC3H,MAAM,CAAC,qBAAqB,EAAE,kDAAkD,CAAC;KACjF,MAAM,CAAC,WAAW,CAAC,CAAC;AAEzB,OAAO;KACF,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,oHAAoH,CAAC;KACjI,MAAM,CAAC,aAAa,EAAE,qDAAqD,CAAC;KAC5E,MAAM,CAAC,KAAK,EAAE,OAA+B,EAAE,EAAE;IAC9C,OAAO,CAAC,IAAI,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEP,OAAO;KACF,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4EAA4E,CAAC;KACzF,MAAM,CAAC,KAAK,IAAI,EAAE;IACf,OAAO,CAAC,IAAI,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEP,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { type InputFormat } from '../payload.js';
|
|
6
|
+
/** Options accepted by the `shot` command (commander camel-cases flags). */
|
|
7
|
+
export interface ShotCommandOptions {
|
|
8
|
+
fromSource?: string;
|
|
9
|
+
fromIr?: string;
|
|
10
|
+
fromTask?: string;
|
|
11
|
+
repo?: string;
|
|
12
|
+
export?: string;
|
|
13
|
+
output?: string;
|
|
14
|
+
html?: boolean;
|
|
15
|
+
viewport?: string;
|
|
16
|
+
dpr?: string;
|
|
17
|
+
fullPage?: boolean;
|
|
18
|
+
element?: string;
|
|
19
|
+
wait?: string;
|
|
20
|
+
timeout?: string;
|
|
21
|
+
storageKey?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Parse `--dpr`, bounded to a sane range (mirrors the viewport bound). */
|
|
24
|
+
export declare function parseDpr(value: string): number;
|
|
25
|
+
/** Parse `WIDTHxHEIGHT`, bounded to a sane positive range. */
|
|
26
|
+
export declare function parseViewport(spec: string): {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function parsePositive(value: string, flag: string): number;
|
|
31
|
+
/** Split a `<workspace>.<task>` specifier on its first dot. */
|
|
32
|
+
export declare function parseTaskPath(spec: string): {
|
|
33
|
+
workspace: string;
|
|
34
|
+
task: string;
|
|
35
|
+
};
|
|
36
|
+
/** Detect the IR format of a `--from-ir` file (rejecting `.ts`/`.tsx`). */
|
|
37
|
+
export declare function detectIrFormat(filePath: string): InputFormat;
|
|
38
|
+
/** Default PNG base name: `<file-without-ext>` / `<ws>.<task>` / `shot`. */
|
|
39
|
+
export declare function stripExt(filePath: string): string;
|
|
40
|
+
/** Commander action for `e3-ui shot`. */
|
|
41
|
+
export declare function shotCommand(options: ShotCommandOptions): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=shot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shot.d.ts","sourceRoot":"","sources":["../../src/commands/shot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAG/D,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAS7E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAM/E;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAM5D;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAsBD,yCAAyC;AACzC,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD5E"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* `e3-ui shot` — render an east-ui / e3-ui component to a PNG. Exactly one
|
|
7
|
+
* source: `--from-source` (a TS/TSX file), `--from-ir` (serialized IR), or
|
|
8
|
+
* `--from-task` (a live e3 task). Static and `State`-only components render with
|
|
9
|
+
* no backend; `--from-task` fetches a task's already-computed output.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import { basename } from 'node:path';
|
|
14
|
+
import { renderToPng, renderTaskToPng } from '../render.js';
|
|
15
|
+
import { detectFormat } from '../payload.js';
|
|
16
|
+
/** Max Chromium viewport dimension (px). */
|
|
17
|
+
const MAX_VIEWPORT = 16384;
|
|
18
|
+
/** Max device scale factor — `viewport × dpr` is the raster size, so an
|
|
19
|
+
* unbounded dpr can OOM Chromium. */
|
|
20
|
+
const MAX_DPR = 8;
|
|
21
|
+
/** Parse `--dpr`, bounded to a sane range (mirrors the viewport bound). */
|
|
22
|
+
export function parseDpr(value) {
|
|
23
|
+
const n = parsePositive(value, '--dpr');
|
|
24
|
+
if (n > MAX_DPR)
|
|
25
|
+
throw new Error(`Invalid --dpr "${value}" (must be 1..${MAX_DPR})`);
|
|
26
|
+
return n;
|
|
27
|
+
}
|
|
28
|
+
/** Parse `WIDTHxHEIGHT`, bounded to a sane positive range. */
|
|
29
|
+
export function parseViewport(spec) {
|
|
30
|
+
const m = /^(\d+)x(\d+)$/i.exec(spec.trim());
|
|
31
|
+
if (!m)
|
|
32
|
+
throw new Error(`Invalid --viewport "${spec}" (expected WIDTHxHEIGHT, e.g. 1280x900)`);
|
|
33
|
+
const width = Number(m[1]);
|
|
34
|
+
const height = Number(m[2]);
|
|
35
|
+
if (width < 1 || height < 1 || width > MAX_VIEWPORT || height > MAX_VIEWPORT) {
|
|
36
|
+
throw new Error(`Invalid --viewport "${spec}" (each dimension must be 1..${MAX_VIEWPORT})`);
|
|
37
|
+
}
|
|
38
|
+
return { width, height };
|
|
39
|
+
}
|
|
40
|
+
export function parsePositive(value, flag) {
|
|
41
|
+
const n = Number(value);
|
|
42
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
43
|
+
throw new Error(`Invalid ${flag} "${value}" (expected a positive number)`);
|
|
44
|
+
return n;
|
|
45
|
+
}
|
|
46
|
+
/** Split a `<workspace>.<task>` specifier on its first dot. */
|
|
47
|
+
export function parseTaskPath(spec) {
|
|
48
|
+
const dot = spec.indexOf('.');
|
|
49
|
+
if (dot <= 0 || dot === spec.length - 1) {
|
|
50
|
+
throw new Error(`Invalid --from-task "${spec}" (expected <workspace>.<task>)`);
|
|
51
|
+
}
|
|
52
|
+
return { workspace: spec.slice(0, dot), task: spec.slice(dot + 1) };
|
|
53
|
+
}
|
|
54
|
+
/** Detect the IR format of a `--from-ir` file (rejecting `.ts`/`.tsx`). */
|
|
55
|
+
export function detectIrFormat(filePath) {
|
|
56
|
+
const format = detectFormat(filePath);
|
|
57
|
+
if (format === 'ts') {
|
|
58
|
+
throw new Error(`"${filePath}" is a TypeScript source — use --from-source, not --from-ir.`);
|
|
59
|
+
}
|
|
60
|
+
return format;
|
|
61
|
+
}
|
|
62
|
+
/** Default PNG base name: `<file-without-ext>` / `<ws>.<task>` / `shot`. */
|
|
63
|
+
export function stripExt(filePath) {
|
|
64
|
+
return basename(filePath).replace(/\.(tsx?|beast2|json)$/i, '');
|
|
65
|
+
}
|
|
66
|
+
/** Shared capture options parsed from the CLI flags. */
|
|
67
|
+
function captureOptionsFrom(options) {
|
|
68
|
+
let mode = { kind: 'frame' };
|
|
69
|
+
if (options.element)
|
|
70
|
+
mode = { kind: 'element', selector: options.element };
|
|
71
|
+
else if (options.fullPage)
|
|
72
|
+
mode = { kind: 'full-page' };
|
|
73
|
+
return {
|
|
74
|
+
mode,
|
|
75
|
+
...(options.viewport ? { viewport: parseViewport(options.viewport) } : {}),
|
|
76
|
+
...(options.dpr ? { deviceScaleFactor: parseDpr(options.dpr) } : {}),
|
|
77
|
+
...(options.wait ? { settleMs: parsePositive(options.wait, '--wait') } : {}),
|
|
78
|
+
...(options.timeout ? { timeoutMs: parsePositive(options.timeout, '--timeout') } : {}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Commander action for `e3-ui shot`. */
|
|
82
|
+
export async function shotCommand(options) {
|
|
83
|
+
try {
|
|
84
|
+
const sources = [
|
|
85
|
+
options.fromSource !== undefined ? 'source' : null,
|
|
86
|
+
options.fromIr !== undefined ? 'ir' : null,
|
|
87
|
+
options.fromTask !== undefined ? 'task' : null,
|
|
88
|
+
].filter((s) => s !== null);
|
|
89
|
+
if (sources.length !== 1) {
|
|
90
|
+
throw new Error('Provide exactly one of --from-source, --from-ir, or --from-task.');
|
|
91
|
+
}
|
|
92
|
+
// --from-task: a live e3 task.
|
|
93
|
+
if (options.fromTask !== undefined) {
|
|
94
|
+
if (!options.repo)
|
|
95
|
+
throw new Error('--from-task requires --repo (a local e3 repository path).');
|
|
96
|
+
const { workspace, task } = parseTaskPath(options.fromTask);
|
|
97
|
+
const output = options.output ?? `${workspace}.${task}.png`.replace(/[^\w.-]+/g, '_');
|
|
98
|
+
const html = options.html ? output.replace(/\.png$/i, '') + '.html' : undefined;
|
|
99
|
+
await renderTaskToPng({ repo: options.repo, workspace, task, output, html, ...captureOptionsFrom(options) });
|
|
100
|
+
console.log(`Wrote ${output}${html ? ` and ${html}` : ''}`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// --from-source (.ts/.tsx) or --from-ir (.beast2/.json | stdin).
|
|
104
|
+
let inputPath;
|
|
105
|
+
let from;
|
|
106
|
+
let outBase;
|
|
107
|
+
if (options.fromSource !== undefined) {
|
|
108
|
+
inputPath = options.fromSource;
|
|
109
|
+
from = 'ts';
|
|
110
|
+
outBase = stripExt(options.fromSource);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const ir = options.fromIr;
|
|
114
|
+
inputPath = ir === '-' ? null : ir;
|
|
115
|
+
from = inputPath ? detectIrFormat(inputPath) : 'beast2';
|
|
116
|
+
outBase = inputPath ? stripExt(inputPath) : 'shot';
|
|
117
|
+
}
|
|
118
|
+
const output = options.output ?? `${outBase}.png`;
|
|
119
|
+
const html = options.html ? output.replace(/\.png$/i, '') + '.html' : undefined;
|
|
120
|
+
await renderToPng({
|
|
121
|
+
input: { path: inputPath, from, exportName: options.export },
|
|
122
|
+
output,
|
|
123
|
+
html,
|
|
124
|
+
...captureOptionsFrom(options),
|
|
125
|
+
...(options.storageKey ? { storageKey: options.storageKey } : {}),
|
|
126
|
+
});
|
|
127
|
+
console.log(`Wrote ${output}${html ? ` and ${html}` : ''}`);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=shot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shot.js","sourceRoot":"","sources":["../../src/commands/shot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/** A running single-repo e3 server. */
|
|
6
|
+
export interface RepoServerHandle {
|
|
7
|
+
/** Base API URL (`http://127.0.0.1:<port>`). */
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
/** Repo id — always `default` in single-repo mode. */
|
|
10
|
+
repo: string;
|
|
11
|
+
/** Stop the server. */
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Start a single-repo e3 API server (CORS enabled) over a local repo path.
|
|
16
|
+
*
|
|
17
|
+
* @param repoPath - Local e3 repository directory
|
|
18
|
+
* @returns A handle with the API URL, repo id, and a `stop()`
|
|
19
|
+
*/
|
|
20
|
+
export declare function startRepoServer(repoPath: string): Promise<RepoServerHandle>;
|
|
21
|
+
//# sourceMappingURL=e3-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e3-server.d.ts","sourceRoot":"","sources":["../src/e3-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC7B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAajF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Start a local e3 API server over a repository so the browser app can fetch a
|
|
7
|
+
* live task's output + bound datasets — the same `@elaraai/e3-api-server`
|
|
8
|
+
* single-repo bootstrap the VS Code extension uses (`startE3Server`).
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { createServer } from '@elaraai/e3-api-server';
|
|
14
|
+
/**
|
|
15
|
+
* Start a single-repo e3 API server (CORS enabled) over a local repo path.
|
|
16
|
+
*
|
|
17
|
+
* @param repoPath - Local e3 repository directory
|
|
18
|
+
* @returns A handle with the API URL, repo id, and a `stop()`
|
|
19
|
+
*/
|
|
20
|
+
export async function startRepoServer(repoPath) {
|
|
21
|
+
const server = await createServer({
|
|
22
|
+
singleRepoPath: path.resolve(repoPath),
|
|
23
|
+
port: 0,
|
|
24
|
+
host: '127.0.0.1',
|
|
25
|
+
cors: true,
|
|
26
|
+
});
|
|
27
|
+
await server.start();
|
|
28
|
+
return {
|
|
29
|
+
apiUrl: `http://127.0.0.1:${server.port}`,
|
|
30
|
+
repo: 'default',
|
|
31
|
+
async stop() { await server.stop(); },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=e3-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e3-server.js","sourceRoot":"","sources":["../src/e3-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,YAAY,EAAe,MAAM,wBAAwB,CAAC;AAYnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB;IAClD,MAAM,MAAM,GAAW,MAAM,YAAY,CAAC;QACtC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACtC,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;KACb,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO;QACH,MAAM,EAAE,oBAAoB,MAAM,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,SAAS;QACf,KAAK,CAAC,IAAI,KAAK,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;KACxC,CAAC;AACN,CAAC"}
|