@hozu/cli 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,466 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, extname, join, relative, resolve } from 'node:path';
5
+ import { findBrowser, launch } from '../cdp.js';
6
+ import { HozuCliError } from '../errors.js';
7
+ import { appParts } from './request.js';
8
+ const ORIGIN = 'http://localhost';
9
+ const LIMIT = 1500;
10
+ const QUIET_MS = 300;
11
+ const SETTLE_MS = 500;
12
+ const CAP_MS = 8000;
13
+ const MIME = {
14
+ '.png': 'image/png',
15
+ '.jpg': 'image/jpeg',
16
+ '.jpeg': 'image/jpeg',
17
+ '.svg': 'image/svg+xml',
18
+ '.ico': 'image/x-icon',
19
+ '.webp': 'image/webp',
20
+ '.json': 'application/json',
21
+ '.txt': 'text/plain',
22
+ '.css': 'text/css',
23
+ '.js': 'text/javascript',
24
+ '.woff2': 'font/woff2',
25
+ };
26
+ const KEYS = {
27
+ Enter: { code: 'Enter', keyCode: 13, text: '\r' },
28
+ Escape: { code: 'Escape', keyCode: 27 },
29
+ Tab: { code: 'Tab', keyCode: 9 },
30
+ Backspace: { code: 'Backspace', keyCode: 8 },
31
+ Space: { code: 'Space', keyCode: 32, text: ' ' },
32
+ ArrowUp: { code: 'ArrowUp', keyCode: 38 },
33
+ ArrowDown: { code: 'ArrowDown', keyCode: 40 },
34
+ ArrowLeft: { code: 'ArrowLeft', keyCode: 37 },
35
+ ArrowRight: { code: 'ArrowRight', keyCode: 39 },
36
+ };
37
+ const PAGE = String.raw `(() => {
38
+ const norm = (s) => (s ?? '').replace(/\s+/g, ' ').trim().toLowerCase()
39
+ const shown = (el) => { const r = el.getBoundingClientRect(); return r.width > 0 || r.height > 0 }
40
+ const nameOf = (el) => {
41
+ const aria = el.getAttribute('aria-label')
42
+ if (aria) return aria
43
+ const by = el.getAttribute('aria-labelledby')
44
+ if (by) return by.split(/\s+/).map((id) => document.getElementById(id)?.textContent ?? '').join(' ')
45
+ if (el.labels && el.labels.length) return [...el.labels].map((l) => l.textContent).join(' ')
46
+ if (el.tagName === 'INPUT' && ['submit', 'button'].includes(el.type)) return el.value
47
+ if (el.placeholder) return el.placeholder
48
+ if (el.getAttribute('title') && !el.textContent.trim()) return el.getAttribute('title')
49
+ return el.textContent
50
+ }
51
+ const KINDS = {
52
+ fill: 'input:not([type=hidden]):not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]), textarea, [contenteditable=true]',
53
+ select: 'select',
54
+ check: 'input[type=checkbox], input[type=radio]',
55
+ click: 'button, a[href], [role=button], [role=link], [role=tab], [role=option], [role=menuitem], [role=checkbox], [role=switch], input[type=submit], input[type=button], summary, [title], label',
56
+ }
57
+ const find = (kind, name) => {
58
+ const all = [...document.querySelectorAll(KINDS[kind])].filter(shown)
59
+ const want = norm(name)
60
+ let hits = all.filter((el) => norm(nameOf(el)) === want || norm(el.getAttribute('title')) === want)
61
+ if (!hits.length && kind === 'click')
62
+ hits = [...document.body.querySelectorAll('*')].filter(
63
+ (el) => shown(el) && norm(el.textContent) === want && ![...el.children].some((c) => norm(c.textContent) === want),
64
+ )
65
+ if (!hits.length) {
66
+ const names = [...new Set(all.map((el) => (nameOf(el) ?? '').replace(/\s+/g, ' ').trim()).filter(Boolean))]
67
+ return { error: 'No ' + kind + ' target named "' + name + '"' + (names.length ? '. On the page: ' + names.slice(0, 20).map((n) => JSON.stringify(n.slice(0, 40))).join(', ') : '') }
68
+ }
69
+ return { el: hits[0], count: hits.length }
70
+ }
71
+ const setValue = (el, value) => {
72
+ const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : el instanceof HTMLSelectElement ? HTMLSelectElement.prototype : HTMLInputElement.prototype
73
+ el.focus()
74
+ if (el.isContentEditable) el.textContent = value
75
+ else Object.getOwnPropertyDescriptor(proto, 'value').set.call(el, value)
76
+ el.dispatchEvent(new Event('input', { bubbles: true }))
77
+ el.dispatchEvent(new Event('change', { bubbles: true }))
78
+ }
79
+ const note = (count) => (count > 1 ? count + ' matched; used the first' : null)
80
+ return {
81
+ point(kind, name) {
82
+ const f = find(kind, name)
83
+ if (f.error) return f
84
+ f.el.scrollIntoView({ block: 'center', inline: 'center' })
85
+ const r = f.el.getBoundingClientRect()
86
+ return { x: r.left + r.width / 2, y: r.top + r.height / 2, note: note(f.count) }
87
+ },
88
+ fill(name, value) {
89
+ const f = find('fill', name)
90
+ if (f.error) return f
91
+ setValue(f.el, value)
92
+ return { note: note(f.count) }
93
+ },
94
+ select(name, option) {
95
+ const f = find('select', name)
96
+ if (f.error) return f
97
+ const o = [...f.el.options].find((o) => norm(o.textContent) === norm(option) || o.value === option)
98
+ if (!o) return { error: 'Select "' + name + '" has no option "' + option + '". Options: ' + [...f.el.options].map((o) => JSON.stringify(o.textContent.trim())).join(', ') }
99
+ setValue(f.el, o.value)
100
+ return { note: note(f.count) }
101
+ },
102
+ report(selectors, expected) {
103
+ const widgets = []
104
+ const hydrated = document.documentElement.hasAttribute('data-hozu-ready')
105
+ for (const el of document.querySelectorAll('[data-hozu-widget]')) {
106
+ const name = el.getAttribute('data-hozu-widget')
107
+ const state = el.getAttribute('data-hozu-widget-state')
108
+ const load = expected.find(([n]) => n === name)?.[1]
109
+ const r = el.getBoundingClientRect()
110
+ const empty = !el.children.length && !el.textContent.trim()
111
+ widgets.push({
112
+ name,
113
+ state: state === 'loading' ? 'not mounted' : state,
114
+ width: Math.round(r.width),
115
+ height: Math.round(r.height),
116
+ canvases: el.querySelectorAll('canvas').length,
117
+ elements: el.querySelectorAll('*').length,
118
+ hint:
119
+ state === 'failed'
120
+ ? 'its setup threw; see errors'
121
+ : state === 'loading'
122
+ ? load === 'visible' && (r.bottom < 0 || r.top > innerHeight)
123
+ ? "load: 'visible' mounts it when it scrolls into view"
124
+ : load === 'idle'
125
+ ? "load: 'idle' mounts it when the browser is idle"
126
+ : 'its module has not loaded; see errors'
127
+ : r.height === 0
128
+ ? 'it has no height, so a map or canvas inside shows nothing: give it a height class such as h-64'
129
+ : empty
130
+ ? 'it mounted but rendered nothing'
131
+ : null,
132
+ })
133
+ }
134
+ if (!hydrated)
135
+ for (const [name] of expected)
136
+ widgets.push({
137
+ name, state: 'not mounted', width: null, height: null, canvases: 0, elements: 0,
138
+ hint: 'the page did not hydrate; see errors',
139
+ })
140
+ const elements = []
141
+ for (const sel of selectors)
142
+ for (const el of document.querySelectorAll(sel)) {
143
+ const attrs = {}
144
+ for (const a of el.attributes) attrs[a.name] = a.value
145
+ const text = (el.innerText ?? el.textContent ?? '').replace(/\s+/g, ' ').trim()
146
+ elements.push({ selector: sel, tag: el.tagName.toLowerCase(), attrs, text: text.length > 120 ? text.slice(0, 120) + '…' : text })
147
+ }
148
+ return {
149
+ title: document.title,
150
+ url: location.pathname + location.search,
151
+ hydrated,
152
+ text: (document.body?.innerText ?? '').replace(/[ \t]+/g, ' ').replace(/\n\s*\n+/g, '\n').trim(),
153
+ widgets,
154
+ elements,
155
+ }
156
+ },
157
+ }
158
+ })()`;
159
+ async function bodyOf(request) {
160
+ if (request.postDataEntries?.length)
161
+ return Buffer.concat(request.postDataEntries.map((e) => Buffer.from(e.bytes ?? '', 'base64')));
162
+ return request.postData === undefined ? undefined : Buffer.from(request.postData);
163
+ }
164
+ export async function runBrowse(loaded, options) {
165
+ const path = options.path ?? '/';
166
+ if (!path.startsWith('/'))
167
+ throw new HozuCliError('usage', 'hozu browse needs a path', ['hozu browse /']);
168
+ const browser = findBrowser();
169
+ if (!browser)
170
+ throw new HozuCliError('config', 'hozu browse needs Chrome, Chromium or Edge, and none was found', [
171
+ 'Install Google Chrome, or set HOZU_CHROME=/path/to/chrome',
172
+ ]);
173
+ const parts = await appParts(loaded, 'browse', options.session);
174
+ const root = dirname(loaded.path);
175
+ const build = loaded.build(false);
176
+ const server = await parts.importFrom('@hozu/runtime-server', ['npm install @hozu/runtime-server']);
177
+ const styles = await (await parts.importFrom('@hozu/css', ['npm install @hozu/css'])).compileStyles(build, { base: root });
178
+ const used = server.usedWidgets(build.ir);
179
+ const widgets = used.length
180
+ ? await (await parts.importFrom('@hozu/bundle', ['npm install @hozu/bundle'])).bundleWidgets(build)
181
+ : null;
182
+ const handler = server.createHandler({
183
+ build,
184
+ styles,
185
+ widgets,
186
+ resolvers: parts.resolvers,
187
+ session: parts.session,
188
+ env: process.env,
189
+ });
190
+ const publicDir = join(root, 'public');
191
+ const respond = async (request) => {
192
+ const response = await handler.fetch(request);
193
+ const file = join(publicDir, decodeURIComponent(new URL(request.url).pathname));
194
+ if (response.status !== 404 || !file.startsWith(publicDir) || !existsSync(file))
195
+ return response;
196
+ return new Response(await readFile(file).catch(() => null), {
197
+ headers: { 'content-type': MIME[extname(file)] ?? 'application/octet-stream' },
198
+ });
199
+ };
200
+ const profile = await mkdtemp(join(tmpdir(), 'hozu-browse-'));
201
+ const cdp = launch(browser, profile);
202
+ const errors = [];
203
+ const steps = [];
204
+ let status = 0;
205
+ let inflight = 0;
206
+ let lastActivity = Date.now();
207
+ let loaded_ = false;
208
+ try {
209
+ const { targetId } = await cdp.send('Target.createTarget', { url: 'about:blank' });
210
+ const { sessionId } = await cdp.send('Target.attachToTarget', { targetId, flatten: true });
211
+ const send = (method, params = {}) => cdp.send(method, params, sessionId);
212
+ const documentUrls = new Set();
213
+ cdp.on((method, params, from) => {
214
+ if (from !== sessionId)
215
+ return;
216
+ if (method === 'Fetch.requestPaused') {
217
+ const r = params.request;
218
+ void (async () => {
219
+ try {
220
+ const response = await respond(new Request(r.url, {
221
+ method: r.method,
222
+ headers: r.headers,
223
+ ...(r.method === 'GET' || r.method === 'HEAD' ? {} : { body: (await bodyOf(r)) ?? null }),
224
+ }));
225
+ const headers = [...response.headers]
226
+ .filter(([k]) => k !== 'set-cookie')
227
+ .map(([name, value]) => ({ name, value }));
228
+ for (const c of response.headers.getSetCookie())
229
+ headers.push({ name: 'set-cookie', value: c });
230
+ const body = Buffer.from(await response.arrayBuffer()).toString('base64');
231
+ await send('Fetch.fulfillRequest', {
232
+ requestId: params.requestId,
233
+ responseCode: response.status,
234
+ responseHeaders: headers,
235
+ body,
236
+ });
237
+ }
238
+ catch (error) {
239
+ errors.push({ kind: 'request', text: `the app threw: ${String(error)}`, at: r.url });
240
+ await send('Fetch.failRequest', { requestId: params.requestId, errorReason: 'Failed' }).catch(() => { });
241
+ }
242
+ })();
243
+ }
244
+ if (method.startsWith('Network.'))
245
+ lastActivity = Date.now();
246
+ if (method === 'Network.requestWillBeSent') {
247
+ inflight++;
248
+ if (params.type === 'Document')
249
+ documentUrls.add(params.requestId);
250
+ }
251
+ if (method === 'Network.loadingFinished')
252
+ inflight--;
253
+ if (method === 'Network.loadingFailed') {
254
+ inflight--;
255
+ if (!params.canceled && params.blockedReason !== 'inspector')
256
+ errors.push({ kind: 'request', text: params.errorText, at: null });
257
+ }
258
+ if (method === 'Network.responseReceived') {
259
+ const url = params.response.url.startsWith(ORIGIN)
260
+ ? params.response.url.slice(ORIGIN.length)
261
+ : params.response.url;
262
+ if (documentUrls.has(params.requestId))
263
+ status = params.response.status;
264
+ if (params.response.status >= 400)
265
+ errors.push({ kind: 'request', text: `${params.response.status} ${url}`, at: url });
266
+ }
267
+ if (method === 'Runtime.exceptionThrown') {
268
+ const d = params.exceptionDetails;
269
+ const frame = d.stackTrace?.callFrames?.[0];
270
+ errors.push({
271
+ kind: 'exception',
272
+ text: d.exception?.description?.split('\n')[0] ?? d.text,
273
+ at: frame ? `${frame.url.replace(ORIGIN, '')}:${frame.lineNumber + 1}` : (d.url ?? null),
274
+ });
275
+ }
276
+ if (method === 'Runtime.consoleAPICalled' && params.type === 'error') {
277
+ const frame = params.stackTrace?.callFrames?.[0];
278
+ errors.push({
279
+ kind: 'console',
280
+ text: params.args
281
+ .map((a) => a.value !== undefined ? String(a.value) : String(a.description ?? a.type).split('\n')[0])
282
+ .join(' '),
283
+ at: frame ? `${frame.url.replace(ORIGIN, '')}:${frame.lineNumber + 1}` : null,
284
+ });
285
+ }
286
+ if (method === 'Page.frameStartedLoading' && params.frameId === targetId)
287
+ loaded_ = false;
288
+ if (method === 'Page.loadEventFired')
289
+ loaded_ = true;
290
+ });
291
+ await send('Fetch.enable', { patterns: [{ urlPattern: `${ORIGIN}/*` }] });
292
+ await send('Network.enable');
293
+ await send('Runtime.enable');
294
+ await send('Page.enable');
295
+ await send('Emulation.setDeviceMetricsOverride', {
296
+ width: 1280,
297
+ height: 800,
298
+ deviceScaleFactor: 1,
299
+ mobile: false,
300
+ });
301
+ if (options.reducedMotion)
302
+ await send('Emulation.setEmulatedMedia', {
303
+ features: [{ name: 'prefers-reduced-motion', value: 'reduce' }],
304
+ });
305
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
306
+ const evaluate = async (expression) => {
307
+ const r = await send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true });
308
+ if (r.exceptionDetails)
309
+ throw new Error(r.exceptionDetails.exception?.description ?? r.exceptionDetails.text);
310
+ return r.result.value;
311
+ };
312
+ const settle = async () => {
313
+ const start = Date.now();
314
+ await sleep(SETTLE_MS);
315
+ while (Date.now() - start < CAP_MS) {
316
+ if (inflight <= 0 && Date.now() - lastActivity >= QUIET_MS) {
317
+ const ready = await evaluate("!document.getElementById('hozu-payload') || document.documentElement.hasAttribute('data-hozu-ready')").catch(() => false);
318
+ if (ready && loaded_)
319
+ return;
320
+ }
321
+ await sleep(50);
322
+ }
323
+ };
324
+ const open = async (to) => {
325
+ loaded_ = false;
326
+ lastActivity = Date.now();
327
+ await send('Page.navigate', { url: ORIGIN + to });
328
+ await settle();
329
+ };
330
+ const mouse = async (x, y) => {
331
+ for (const type of ['mouseMoved', 'mousePressed', 'mouseReleased'])
332
+ await send('Input.dispatchMouseEvent', { type, x, y, button: 'left', clickCount: 1 });
333
+ };
334
+ await open(path);
335
+ const firstStatus = status;
336
+ for (const raw of options.steps) {
337
+ const text = raw.trim();
338
+ const space = text.indexOf(' ');
339
+ const verb = space < 0 ? text : text.slice(0, space);
340
+ const rest = space < 0 ? '' : text.slice(space + 1).trim();
341
+ const pair = () => {
342
+ const eq = rest.indexOf('=');
343
+ if (eq <= 0)
344
+ throw new Error(`"${text}" needs <label>=<value>`);
345
+ return [rest.slice(0, eq).trim(), rest.slice(eq + 1)];
346
+ };
347
+ let result = {};
348
+ try {
349
+ if (verb === 'fill') {
350
+ const [label, value] = pair();
351
+ result = await evaluate(`${PAGE}.fill(${JSON.stringify(label)}, ${JSON.stringify(value)})`);
352
+ }
353
+ else if (verb === 'select') {
354
+ const [label, value] = pair();
355
+ result = await evaluate(`${PAGE}.select(${JSON.stringify(label)}, ${JSON.stringify(value)})`);
356
+ }
357
+ else if (verb === 'click' || verb === 'check') {
358
+ const at = await evaluate(`${PAGE}.point(${JSON.stringify(verb === 'click' ? 'click' : 'check')}, ${JSON.stringify(rest)})`);
359
+ if (at.error)
360
+ result = at;
361
+ else {
362
+ await mouse(at.x, at.y);
363
+ result = { note: at.note };
364
+ }
365
+ }
366
+ else if (verb === 'press') {
367
+ const key = KEYS[rest] ?? {
368
+ code: `Key${rest.toUpperCase()}`,
369
+ keyCode: rest.toUpperCase().charCodeAt(0),
370
+ text: rest,
371
+ };
372
+ await send('Input.dispatchKeyEvent', {
373
+ type: 'keyDown',
374
+ key: rest,
375
+ code: key.code,
376
+ windowsVirtualKeyCode: key.keyCode,
377
+ ...(key.text ? { text: key.text } : {}),
378
+ });
379
+ await send('Input.dispatchKeyEvent', {
380
+ type: 'keyUp',
381
+ key: rest,
382
+ code: key.code,
383
+ windowsVirtualKeyCode: key.keyCode,
384
+ });
385
+ }
386
+ else if (verb === 'wait') {
387
+ const ms = Number(rest);
388
+ if (!Number.isFinite(ms) || ms < 0 || ms > 30000)
389
+ throw new Error('wait takes milliseconds (0–30000)');
390
+ await sleep(ms);
391
+ }
392
+ else if (verb === 'goto') {
393
+ if (!rest.startsWith('/'))
394
+ throw new Error('goto takes a path such as /items/1');
395
+ await open(rest);
396
+ }
397
+ else
398
+ throw new Error(`Unknown step "${verb}": use fill <label>=<value>, select <label>=<option>, check <label>, click <name>, press <key>, wait <ms>, goto <path>`);
399
+ }
400
+ catch (error) {
401
+ result = { error: error instanceof Error ? error.message : String(error) };
402
+ }
403
+ steps.push({ step: text, ok: !result.error, note: result.error ?? result.note ?? null });
404
+ if (result.error)
405
+ break;
406
+ if (verb !== 'wait' && verb !== 'goto')
407
+ await settle();
408
+ }
409
+ for (const skipped of options.steps.slice(steps.length))
410
+ steps.push({ step: skipped.trim(), ok: false, note: 'skipped after a failed step' });
411
+ const expected = Object.entries((await evaluate("(() => { try { return JSON.parse(document.getElementById('hozu-payload')?.textContent ?? '{}').widgets ?? {} } catch { return {} } })()"))).map(([name, w]) => [name, w.load]);
412
+ const report = await evaluate(`${PAGE}.report(${JSON.stringify(options.select)}, ${JSON.stringify(expected)})`);
413
+ let screenshot = null;
414
+ if (options.screenshot) {
415
+ const shot = await send('Page.captureScreenshot', { format: 'png' });
416
+ const file = resolve(options.screenshot);
417
+ await writeFile(file, Buffer.from(shot.data, 'base64'));
418
+ const near = relative(process.cwd(), file);
419
+ screenshot = near && !near.startsWith('..') ? near : file;
420
+ }
421
+ const full = report.text;
422
+ return {
423
+ path,
424
+ url: report.url,
425
+ status: firstStatus,
426
+ title: report.title,
427
+ hydrated: report.hydrated,
428
+ steps,
429
+ errors,
430
+ widgets: report.widgets,
431
+ text: full.length > LIMIT && !options.full ? `${full.slice(0, LIMIT)}…` : full,
432
+ truncated: full.length > LIMIT && !options.full,
433
+ elements: report.elements,
434
+ screenshot,
435
+ };
436
+ }
437
+ finally {
438
+ await cdp.close().catch(() => { });
439
+ await rm(profile, { recursive: true, force: true }).catch(() => { });
440
+ }
441
+ }
442
+ export const browseFailed = (out) => out.errors.length > 0 || out.steps.some((s) => !s.ok) || out.widgets.some((w) => w.state === 'failed');
443
+ export function describeBrowse(out) {
444
+ const lines = [
445
+ `BROWSE ${out.path} → ${out.status}${out.url !== out.path ? ` (now ${out.url})` : ''} · ${out.hydrated ? 'hydrated' : 'not hydrated'}`,
446
+ ` title: ${out.title}`,
447
+ ];
448
+ for (const s of out.steps)
449
+ lines.push(` ${s.ok ? 'step' : 'FAILED'}: ${s.step}${s.note ? ` — ${s.note}` : ''}`);
450
+ if (!out.errors.length)
451
+ lines.push(' errors: none');
452
+ for (const e of out.errors)
453
+ lines.push(` error (${e.kind}): ${e.text}${e.at ? ` at ${e.at}` : ''}`);
454
+ for (const w of out.widgets)
455
+ lines.push(` widget ${w.name}: ${w.state}${w.width === null ? '' : ` ${w.width}×${w.height}`}${w.state === 'mounted' ? `, ${w.canvases} canvas, ${w.elements} elements` : ''}${w.hint ? ` — ${w.hint}` : ''}`);
456
+ lines.push(` text: ${out.text.replace(/\n/g, ' · ')}${out.truncated ? ' (truncated; --full shows all)' : ''}`);
457
+ for (const e of out.elements)
458
+ lines.push(` ${e.selector}: <${e.tag}${Object.entries(e.attrs)
459
+ .filter(([k]) => k !== 'class' && k !== 'style')
460
+ .map(([k, v]) => (v === '' ? ` ${k}` : ` ${k}="${v}"`))
461
+ .join('')}>${e.text ? ` ${e.text}` : ''}`);
462
+ if (out.screenshot)
463
+ lines.push(` screenshot: ${out.screenshot}`);
464
+ return `${lines.join('\n')}\n`;
465
+ }
466
+ //# sourceMappingURL=browse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browse.js","sourceRoot":"","sources":["../../src/commands/browse.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,11 @@ export interface RequestOptions {
18
18
  session: string | undefined;
19
19
  full: boolean;
20
20
  }
21
+ export declare function appParts(loaded: Loaded, command: string, sessionJson: string | undefined): Promise<{
22
+ importFrom: <T>(id: string, hint: string[]) => Promise<T>;
23
+ resolvers: unknown;
24
+ session: unknown;
25
+ }>;
21
26
  export declare function runRequest(loaded: Loaded, options: RequestOptions): Promise<RequestOutput>;
22
27
  export declare function describeRequest(out: RequestOutput): string;
23
28
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/commands/request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAA;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAqCxC,UAAU,IAAI;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,CAqCxD;AAiCD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAoC3E;AAYD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;CACd;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAiKhG;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA0B1D"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/commands/request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAA;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAqCxC,UAAU,IAAI;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,CAqCxD;AAiCD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAoC3E;AAYD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;CACd;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS;iBAEnE,CAAC,MAAM,MAAM,QAAQ,MAAM,EAAE,KAAG,OAAO,CAAC,CAAC,CAAC;eA6BR,OAAO;;GACpE;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAoIhG;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA0B1D"}
@@ -146,17 +146,16 @@ const titleOf = (html) => {
146
146
  const alertsOf = (html) => [...html.matchAll(/<(\w+)\b[^>]*role="alert"[^>]*>([\s\S]*?)<\/\1>/g)]
147
147
  .map((m) => plain(m[2]))
148
148
  .filter((t) => t !== '');
149
- export async function runRequest(loaded, options) {
149
+ export async function appParts(loaded, command, sessionJson) {
150
150
  const require = createRequire(loaded.path);
151
151
  const importFrom = async (id, hint) => {
152
152
  try {
153
153
  return (await import(__rewriteRelativeImportExtension(pathToFileURL(require.resolve(id)).href)));
154
154
  }
155
155
  catch {
156
- throw new HozuCliError('config', `hozu ${options.method.toLowerCase()} needs ${id} in the app`, hint);
156
+ throw new HozuCliError('config', `hozu ${command} needs ${id} in the app`, hint);
157
157
  }
158
158
  };
159
- const { testApp } = await importFrom('@hozu/testing', ['npm install -D @hozu/testing']);
160
159
  const serverPath = join(dirname(loaded.path), 'server.ts');
161
160
  const server = await import(__rewriteRelativeImportExtension(pathToFileURL(serverPath).href)).catch(() => null);
162
161
  if (typeof server?.createResolvers !== 'function')
@@ -164,21 +163,26 @@ export async function runRequest(loaded, options) {
164
163
  'export function createResolvers() { return resolvers(project, (implement) => [...]) }',
165
164
  ]);
166
165
  let session = null;
167
- if (options.session !== undefined)
166
+ if (sessionJson !== undefined)
168
167
  try {
169
- session = JSON.parse(options.session);
168
+ session = JSON.parse(sessionJson);
170
169
  }
171
170
  catch {
172
171
  throw new HozuCliError('usage', '--session must be JSON', [`--session '{"userId":"ada"}'`]);
173
172
  }
174
- const store = options.session === undefined
173
+ const store = sessionJson === undefined
175
174
  ? (await importFrom('@hozu/runtime-server', ['npm install @hozu/runtime-server'])).sessionCookie({ name: 'sid', secret: randomBytes(24).toString('hex'), secure: false })
176
175
  : () => session;
176
+ return { importFrom, resolvers: server.createResolvers(), session: store };
177
+ }
178
+ export async function runRequest(loaded, options) {
179
+ const parts = await appParts(loaded, options.method.toLowerCase(), options.session);
180
+ const { testApp } = await parts.importFrom('@hozu/testing', ['npm install -D @hozu/testing']);
177
181
  const app = testApp({
178
182
  build: loaded.build(),
179
- resolvers: server.createResolvers(),
183
+ resolvers: parts.resolvers,
180
184
  env: process.env,
181
- session: store,
185
+ session: parts.session,
182
186
  });
183
187
  const cookies = new Map();
184
188
  const init = () => ({