@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.
Files changed (64) hide show
  1. package/CLA.md +26 -0
  2. package/CONTRIBUTING.md +28 -0
  3. package/LICENSE.md +31 -0
  4. package/README.md +158 -0
  5. package/bin/e3-ui.mjs +13 -0
  6. package/dist/app/assets/dm-sans-latin-ext-wght-normal-BOFOeGcA.woff2 +0 -0
  7. package/dist/app/assets/dm-sans-latin-wght-normal-Xz1IZZA0.woff2 +0 -0
  8. package/dist/app/assets/engine-Daqj4eDD-BQb68g_1.js +4 -0
  9. package/dist/app/assets/index-30g1JIHt.js +2255 -0
  10. package/dist/app/assets/index-CYR-0Grb.css +1 -0
  11. package/dist/app/assets/inter-tight-cyrillic-ext-wght-normal-okcGN4Nq.woff2 +0 -0
  12. package/dist/app/assets/inter-tight-cyrillic-wght-normal-BS41q_Tv.woff2 +0 -0
  13. package/dist/app/assets/inter-tight-greek-ext-wght-normal-DQgQPNk4.woff2 +0 -0
  14. package/dist/app/assets/inter-tight-greek-wght-normal-sS1B39LI.woff2 +0 -0
  15. package/dist/app/assets/inter-tight-latin-ext-wght-normal-B4u9PlvR.woff2 +0 -0
  16. package/dist/app/assets/inter-tight-latin-wght-normal-DX-nOvPD.woff2 +0 -0
  17. package/dist/app/assets/inter-tight-vietnamese-wght-normal-TKKdAiBA.woff2 +0 -0
  18. package/dist/app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  19. package/dist/app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  20. package/dist/app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  21. package/dist/app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  22. package/dist/app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  23. package/dist/app/index.html +13 -0
  24. package/dist/browser.d.ts +88 -0
  25. package/dist/browser.d.ts.map +1 -0
  26. package/dist/browser.js +249 -0
  27. package/dist/browser.js.map +1 -0
  28. package/dist/capture.d.ts +80 -0
  29. package/dist/capture.d.ts.map +1 -0
  30. package/dist/capture.js +275 -0
  31. package/dist/capture.js.map +1 -0
  32. package/dist/cli.d.ts +6 -0
  33. package/dist/cli.d.ts.map +1 -0
  34. package/dist/cli.js +70 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/commands/shot.d.ts +42 -0
  37. package/dist/commands/shot.d.ts.map +1 -0
  38. package/dist/commands/shot.js +134 -0
  39. package/dist/commands/shot.js.map +1 -0
  40. package/dist/e3-server.d.ts +21 -0
  41. package/dist/e3-server.d.ts.map +1 -0
  42. package/dist/e3-server.js +34 -0
  43. package/dist/e3-server.js.map +1 -0
  44. package/dist/index.d.ts +17 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +17 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/load-source.d.ts +21 -0
  49. package/dist/load-source.d.ts.map +1 -0
  50. package/dist/load-source.js +163 -0
  51. package/dist/load-source.js.map +1 -0
  52. package/dist/payload.d.ts +26 -0
  53. package/dist/payload.d.ts.map +1 -0
  54. package/dist/payload.js +87 -0
  55. package/dist/payload.js.map +1 -0
  56. package/dist/render.d.ts +80 -0
  57. package/dist/render.d.ts.map +1 -0
  58. package/dist/render.js +79 -0
  59. package/dist/render.js.map +1 -0
  60. package/dist/shot-payload.d.ts +31 -0
  61. package/dist/shot-payload.d.ts.map +1 -0
  62. package/dist/shot-payload.js +6 -0
  63. package/dist/shot-payload.js.map +1 -0
  64. package/package.json +82 -0
@@ -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
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
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":"AAAA;;;GAGG;AAEH;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C;2DAC2D;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC5B,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACtC,iBAAiB,EAAE,CAAC;IACpB,QAAQ,EAAE,GAAG;IACb,SAAS,EAAE,MAAM;IACjB,UAAU,EAAE,MAAM;IAClB,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,GAAG;IACnB,cAAc,EAAE,GAAG;CACb,CAAC;AAgCX,MAAM,IAAI,GAA2B;IACjC,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,gCAAgC;IACxC,MAAM,EAAE,yBAAyB;IACjC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,iCAAiC;IACzC,QAAQ,EAAE,YAAY;IACtB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,cAAc;CACzB,CAAC;AAEF,qEAAqE;AACrE;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,WAAmB;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,WAAW,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAK,YAAY,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5F,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACrC,KAAK,CAAC,KAAK,IAAI,EAAE;YACb,IAAI,CAAC;gBACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;gBACxD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACZ,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;oBACrB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBACrB,OAAO;gBACX,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACtC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B,CAAC,CAAC;gBACxG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACL,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzB,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QAC9D,MAAM,IAAI,GAAI,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,CAAC;QACpD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,IAAI,EAAE,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;AACP,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/B,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO;KACtE,CAAC,CAAC,CAAY,CAAA,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,MAAc;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,EAAE,GAAG,4CAA4C,CAAC;IACxD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9B,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACvD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,0BAA0B,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YACL,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,uCAAuC,IAAI,0EAA0E,CAAC,CAAC;QACxI,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAU,EAAE,IAAY,EAAE,EAAE;QACtD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,iBAAiB,CAAC,IAAU,EAAE,MAAc;IACvD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;QAC1D,4DAA4D;QAC5D,sEAAsE;QACtE,oEAAoE;QACpE,MAAM,MAAM,GAAoB;YAC5B,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YACnC,GAAG,CAAC,QAAQ,CAAC,kBAAkB,IAAI,EAAE,CAAC;SACzC,CAAC;QACF,MAAM,GAAG,GAAG,MAAM;aACb,GAAG,CAAC,KAAK,CAAC,EAAE;YACT,IAAI,CAAC;gBAAC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YACzE,MAAM,CAAC;gBAAC,OAAO,EAAE,CAAC;YAAC,CAAC;QACxB,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,YAAY,EAAE,CAAC;IACtG,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACnD,OAAO;;;;;SAKF,UAAU,CAAC,KAAK,CAAC;;EAExB,OAAO;;;;EAIP,QAAQ;;;CAGT,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAoB;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAC,QAAQ,CAAC;IAC5D,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,iBAAiB,CAAC;IACvF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAC,QAAQ,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAElE,sEAAsE;IACtE,6DAA6D;IAC7D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,MAAM,qDAAqD,CAAC,CAAC;IACnH,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,OAA4B,CAAC;IACjC,IAAI,CAAC;QACD,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAErC,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,OAAO;YAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3F,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC;QACxD,MAAM,IAAI,CAAC,aAAa,CACpB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE;YAClB,MAAiD,CAAC,cAAc,GAAG,CAAC,CAAC;YACrE,MAAqD,CAAC,kBAAkB,GAAG,GAAG,CAAC;YAC/E,MAA0D,CAAC,uBAAuB,GAAG,QAAQ,CAAC;QACnG,CAAC,EACD,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAU,CACtD,CAAC;QAEF,uEAAuE;QACvE,yEAAyE;QACzE,4EAA4E;QAC5E,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,GAAG,EAAE;YAC3B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa;YAChE,OAAO;SACV,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAEhD,oEAAoE;QACpE,uEAAuE;QACvE,oEAAoE;QACpE,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,eAAe,CACtB,GAAG,EAAE;gBACD,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAC;gBACjF,OAAO,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,OAAO,CAAC;YAC1C,CAAC,EACD,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,YAAY,EAAE,CACtD,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,wBAAwB,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChG,MAAM,IAAI,KAAK,CACX,mBAAmB,OAAO,yCAAyC,MAAM,IAAI;gBAC7E,0FAA0F,CAC7F,CAAC;QACN,CAAC;QAED,mEAAmE;QACnE,8DAA8D;QAC9D,oEAAoE;QACpE,2EAA2E;QAC3E,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;YAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;YAClD,IAAI,IAAI,EAAE,YAAY,CAAC,kBAAkB,CAAC,KAAK,OAAO,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,sBAAsB,CAAC;YAC1E,CAAC;YACD,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,0CAA0C,CAAC,CAAC;YAChF,OAAO,IAAI,CAAC,CAAC,CAAE,IAAoB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzE,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;QACpC,IAAI,WAAW,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,4EAA4E;QAC5E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAC/B,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,mBAAmB,CAAC,KAAK,MAAM,CAC3F,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,mHAAmH,CAAC,CAAC;QACtI,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,2CAA2C;QAC3C,MAAM,IAAI;aACL,eAAe,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,MAAM,KAAK,CAAC,EAC5E,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,cAAc,EAAE,CAAC;aACzD,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC,CAAC;QAC/H,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAEpC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC;YACzE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,MAAM,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,kBAAkB,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QACtF,CAAC;IACL,CAAC;YAAS,CAAC;QACP,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;AACL,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
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
+ export {};
6
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -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"}