@maravilla-labs/types 0.8.0 → 0.8.3

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 (3) hide show
  1. package/index.d.ts +205 -0
  2. package/index.ts +230 -0
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -294,6 +294,207 @@ export interface Storage {
294
294
  */
295
295
  getMetadata(key: string): Promise<StorageMetadata>;
296
296
  }
297
+ /** Output image format for browser screenshots. */
298
+ export type ScreenshotFormat = 'png' | 'jpeg' | 'webp';
299
+ /** Page-size preset for browser PDF renders. */
300
+ export type PdfPageFormat = 'A4' | 'A3' | 'Letter' | 'Legal' | 'Tabloid';
301
+ /** Video codec for deterministic frame renders. */
302
+ export type FramesCodec = 'h264' | 'vp9';
303
+ /** Lifecycle state of a browser / frames job. Mirrors transforms `JobStatus`. */
304
+ export type BrowserJobStatus = 'pending' | 'running' | 'complete' | 'failed';
305
+ /** Viewport (CSS pixels) the headless browser launches with. */
306
+ export interface BrowserViewport {
307
+ width: number;
308
+ height: number;
309
+ }
310
+ /**
311
+ * "Wait until" predicate before the screenshot / PDF capture fires.
312
+ * Set at most one of `selector`, `network_idle`, or `ms`; the worker
313
+ * picks the first non-null in that order.
314
+ */
315
+ export interface BrowserWaitFor {
316
+ /** CSS selector that must resolve before the capture fires. */
317
+ selector?: string;
318
+ /** Wait for the network to go idle (~500ms with no in-flight requests). */
319
+ network_idle?: boolean;
320
+ /** Sleep for this many milliseconds then capture. Capped at ~30s by the worker. */
321
+ ms?: number;
322
+ }
323
+ /** Cookie pre-installed on the browser context before navigation. */
324
+ export interface BrowserCookie {
325
+ name: string;
326
+ value: string;
327
+ domain?: string;
328
+ }
329
+ /**
330
+ * Request shape for `platform.env.BROWSER.screenshot(...)`.
331
+ *
332
+ * Exactly one of `url` (public URL — SSRF-gated by the worker) or `path`
333
+ * (relative path resolved against the tenant's deployment via loopback
334
+ * to Delivery) must be set.
335
+ */
336
+ export interface ScreenshotRequest {
337
+ /** Public URL. Worker blocks loopback / RFC1918 / link-local after DNS. */
338
+ url?: string;
339
+ /** Path on the tenant's own deployment, e.g. `/dashboard`. */
340
+ path?: string;
341
+ viewport?: BrowserViewport;
342
+ wait_for?: BrowserWaitFor;
343
+ /** Capture the full scrollable page rather than the viewport. */
344
+ full_page?: boolean;
345
+ /** Defaults to `"png"` server-side when omitted. */
346
+ format?: ScreenshotFormat;
347
+ /** JPEG / WebP quality 1–100. Ignored for PNG. */
348
+ quality?: number;
349
+ cookies?: BrowserCookie[];
350
+ /** Extra HTTP headers applied to every navigation request. */
351
+ headers?: Record<string, string>;
352
+ /** Storage key where the PNG / JPEG / WebP is written. Required. */
353
+ target: string;
354
+ }
355
+ /**
356
+ * Request shape for `platform.env.BROWSER.pdf(...)`. Same `url`/`path`
357
+ * discipline as {@link ScreenshotRequest}.
358
+ */
359
+ export interface PdfRequest {
360
+ url?: string;
361
+ path?: string;
362
+ /** Defaults to `"A4"` server-side when omitted. */
363
+ format?: PdfPageFormat;
364
+ landscape?: boolean;
365
+ /** Render CSS background colour / images. Defaults `true` server-side. */
366
+ print_background?: boolean;
367
+ cookies?: BrowserCookie[];
368
+ headers?: Record<string, string>;
369
+ target: string;
370
+ }
371
+ /**
372
+ * Request shape for `platform.env.FRAMES.render(...)`.
373
+ *
374
+ * Path-only on purpose: the renderer drives one of the tenant's own
375
+ * deployment routes (which is expected to import `@maravilla/frames`
376
+ * and call `defineTimeline({...})`) frame-by-frame via CDP
377
+ * `HeadlessExperimental.beginFrame`.
378
+ */
379
+ export interface FramesRenderRequest {
380
+ /** Path on the tenant's deployment, e.g. `/render/intro-card?title=Hi`. */
381
+ path: string;
382
+ /** Frames per second. Must be ≥ 1; worker caps the upper bound. */
383
+ fps: number;
384
+ /** Total clip duration in milliseconds. */
385
+ duration_ms: number;
386
+ /** Output width (CSS pixels). Doubles as the browser viewport width. */
387
+ width: number;
388
+ /** Output height. */
389
+ height: number;
390
+ /** Storage key of an optional audio track ffmpeg mixes in. */
391
+ audio?: string;
392
+ /** Defaults to `"h264"` server-side when omitted. */
393
+ codec?: FramesCodec;
394
+ /** Constant Rate Factor for the encoder. Worker picks a default when unset. */
395
+ crf?: number;
396
+ /** Storage key the MP4 / WebM is written to. Required — no auto-generation. */
397
+ target: string;
398
+ }
399
+ /**
400
+ * Handle returned by every BROWSER / FRAMES method. `output_key` is the
401
+ * caller-supplied `target` and is known up front; status updates as the
402
+ * worker progresses through the shared transforms job ledger.
403
+ */
404
+ export interface BrowserJobHandle {
405
+ id: string;
406
+ src_key: string;
407
+ output_key: string;
408
+ status: BrowserJobStatus;
409
+ }
410
+ /**
411
+ * Headless-browser surface exposed as `platform.env.BROWSER`.
412
+ */
413
+ export interface BrowserClient {
414
+ /**
415
+ * Capture a screenshot of a public URL or one of the tenant's own
416
+ * routes. Returns a {@link BrowserJobHandle} whose `output_key` equals
417
+ * the caller-supplied `request.target` and is known up front — poll
418
+ * `platform.media.transforms.job(handle.id)` for status, then fetch
419
+ * the bytes from `platform.env.STORAGE` once the job completes.
420
+ *
421
+ * Exactly one of `request.url` or `request.path` must be set.
422
+ * `url` mode is gated by an SSRF block-list applied after DNS
423
+ * resolution; `path` mode loopback-routes to the tenant's own
424
+ * deployment.
425
+ *
426
+ * @param request `url` (public, SSRF-gated) or `path` (own deployment),
427
+ * plus optional `viewport`, `wait_for`, `format`, `cookies`,
428
+ * `headers`, and the required `target` storage key.
429
+ * @returns A handle to poll. `output_key` is `request.target`.
430
+ *
431
+ * @example
432
+ * ```ts
433
+ * const handle = await platform.env.BROWSER.screenshot({
434
+ * url: 'https://example.com',
435
+ * viewport: { width: 1280, height: 720 },
436
+ * target: 'shots/example.png',
437
+ * });
438
+ * ```
439
+ */
440
+ screenshot(request: ScreenshotRequest): Promise<BrowserJobHandle>;
441
+ /**
442
+ * Render the target page to a PDF. Same `url` xor `path` discipline
443
+ * as {@link BrowserClient.screenshot}.
444
+ *
445
+ * @param request `url` or `path`, plus optional `format` (page-size
446
+ * preset), `landscape`, `print_background`, `cookies`, `headers`,
447
+ * and the required `target` storage key.
448
+ * @returns A handle to poll. `output_key` is `request.target`.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * const handle = await platform.env.BROWSER.pdf({
453
+ * path: '/invoices/INV-1042',
454
+ * format: 'A4',
455
+ * print_background: true,
456
+ * target: 'invoices/INV-1042.pdf',
457
+ * });
458
+ * ```
459
+ */
460
+ pdf(request: PdfRequest): Promise<BrowserJobHandle>;
461
+ }
462
+ /**
463
+ * Deterministic-video surface exposed as `platform.env.FRAMES`.
464
+ */
465
+ export interface FramesClient {
466
+ /**
467
+ * Render one of the tenant's own deployment routes to MP4 / WebM,
468
+ * frame-accurately. The route is expected to import
469
+ * `@maravilla-labs/frames` and call `defineTimeline({...})` at load
470
+ * time — the worker drives `window.__mvFrames.applyState(t)` once
471
+ * per frame and captures via CDP `HeadlessExperimental.beginFrame`,
472
+ * piping PNG frames into ffmpeg.
473
+ *
474
+ * Same render against the same route is deterministic — two
475
+ * back-to-back renders produce byte-identical output (modulo
476
+ * already-stripped muxer metadata).
477
+ *
478
+ * @param request `path` on the tenant's deployment, `fps`,
479
+ * `duration_ms`, `width`, `height`, optional `audio` storage key,
480
+ * `codec` (`h264` default, `vp9` for WebM), optional `crf`, and
481
+ * the required `target` storage key.
482
+ * @returns A handle to poll. `output_key` is `request.target`.
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * const handle = await platform.env.FRAMES.render({
487
+ * path: '/render/hello',
488
+ * fps: 30,
489
+ * duration_ms: 2000,
490
+ * width: 1280,
491
+ * height: 720,
492
+ * target: 'renders/hello.mp4',
493
+ * });
494
+ * ```
495
+ */
496
+ render(request: FramesRenderRequest): Promise<BrowserJobHandle>;
497
+ }
297
498
  /**
298
499
  * Authenticated user record from the platform auth service.
299
500
  */
@@ -969,6 +1170,10 @@ export interface Platform {
969
1170
  KV: KvStore;
970
1171
  DB: Database;
971
1172
  STORAGE: Storage;
1173
+ /** Headless-browser screenshot / PDF — Phase 1 stub, real impl in Task #2. */
1174
+ BROWSER: BrowserClient;
1175
+ /** Deterministic HTML → MP4 / WebM render — Phase 1 stub, real impl in Task #3. */
1176
+ FRAMES: FramesClient;
972
1177
  };
973
1178
  }
974
1179
  /**
package/index.ts CHANGED
@@ -338,6 +338,232 @@ export interface Storage {
338
338
  getMetadata(key: string): Promise<StorageMetadata>;
339
339
  }
340
340
 
341
+ // ════════════════════════════════════════════════════════════════════
342
+ // Headless browser + deterministic-video render
343
+ // ════════════════════════════════════════════════════════════════════
344
+ //
345
+ // Same JobHandle / polling model as the existing media-transforms surface
346
+ // (`@maravilla-labs/platform`'s `transforms.ts`): every mutating method
347
+ // returns a {@link BrowserJobHandle} the caller polls until the status is
348
+ // terminal. Phase 1 wires the contract surface end-to-end — the underlying
349
+ // worker returns `failed("not implemented")` until Task #2 and Task #3
350
+ // implement the Chromium + ffmpeg pipelines.
351
+
352
+ /** Output image format for browser screenshots. */
353
+ export type ScreenshotFormat = 'png' | 'jpeg' | 'webp';
354
+
355
+ /** Page-size preset for browser PDF renders. */
356
+ export type PdfPageFormat = 'A4' | 'A3' | 'Letter' | 'Legal' | 'Tabloid';
357
+
358
+ /** Video codec for deterministic frame renders. */
359
+ export type FramesCodec = 'h264' | 'vp9';
360
+
361
+ /** Lifecycle state of a browser / frames job. Mirrors transforms `JobStatus`. */
362
+ export type BrowserJobStatus = 'pending' | 'running' | 'complete' | 'failed';
363
+
364
+ /** Viewport (CSS pixels) the headless browser launches with. */
365
+ export interface BrowserViewport {
366
+ width: number;
367
+ height: number;
368
+ }
369
+
370
+ /**
371
+ * "Wait until" predicate before the screenshot / PDF capture fires.
372
+ * Set at most one of `selector`, `network_idle`, or `ms`; the worker
373
+ * picks the first non-null in that order.
374
+ */
375
+ export interface BrowserWaitFor {
376
+ /** CSS selector that must resolve before the capture fires. */
377
+ selector?: string;
378
+ /** Wait for the network to go idle (~500ms with no in-flight requests). */
379
+ network_idle?: boolean;
380
+ /** Sleep for this many milliseconds then capture. Capped at ~30s by the worker. */
381
+ ms?: number;
382
+ }
383
+
384
+ /** Cookie pre-installed on the browser context before navigation. */
385
+ export interface BrowserCookie {
386
+ name: string;
387
+ value: string;
388
+ domain?: string;
389
+ }
390
+
391
+ /**
392
+ * Request shape for `platform.env.BROWSER.screenshot(...)`.
393
+ *
394
+ * Exactly one of `url` (public URL — SSRF-gated by the worker) or `path`
395
+ * (relative path resolved against the tenant's deployment via loopback
396
+ * to Delivery) must be set.
397
+ */
398
+ export interface ScreenshotRequest {
399
+ /** Public URL. Worker blocks loopback / RFC1918 / link-local after DNS. */
400
+ url?: string;
401
+ /** Path on the tenant's own deployment, e.g. `/dashboard`. */
402
+ path?: string;
403
+ viewport?: BrowserViewport;
404
+ wait_for?: BrowserWaitFor;
405
+ /** Capture the full scrollable page rather than the viewport. */
406
+ full_page?: boolean;
407
+ /** Defaults to `"png"` server-side when omitted. */
408
+ format?: ScreenshotFormat;
409
+ /** JPEG / WebP quality 1–100. Ignored for PNG. */
410
+ quality?: number;
411
+ cookies?: BrowserCookie[];
412
+ /** Extra HTTP headers applied to every navigation request. */
413
+ headers?: Record<string, string>;
414
+ /** Storage key where the PNG / JPEG / WebP is written. Required. */
415
+ target: string;
416
+ }
417
+
418
+ /**
419
+ * Request shape for `platform.env.BROWSER.pdf(...)`. Same `url`/`path`
420
+ * discipline as {@link ScreenshotRequest}.
421
+ */
422
+ export interface PdfRequest {
423
+ url?: string;
424
+ path?: string;
425
+ /** Defaults to `"A4"` server-side when omitted. */
426
+ format?: PdfPageFormat;
427
+ landscape?: boolean;
428
+ /** Render CSS background colour / images. Defaults `true` server-side. */
429
+ print_background?: boolean;
430
+ cookies?: BrowserCookie[];
431
+ headers?: Record<string, string>;
432
+ target: string;
433
+ }
434
+
435
+ /**
436
+ * Request shape for `platform.env.FRAMES.render(...)`.
437
+ *
438
+ * Path-only on purpose: the renderer drives one of the tenant's own
439
+ * deployment routes (which is expected to import `@maravilla/frames`
440
+ * and call `defineTimeline({...})`) frame-by-frame via CDP
441
+ * `HeadlessExperimental.beginFrame`.
442
+ */
443
+ export interface FramesRenderRequest {
444
+ /** Path on the tenant's deployment, e.g. `/render/intro-card?title=Hi`. */
445
+ path: string;
446
+ /** Frames per second. Must be ≥ 1; worker caps the upper bound. */
447
+ fps: number;
448
+ /** Total clip duration in milliseconds. */
449
+ duration_ms: number;
450
+ /** Output width (CSS pixels). Doubles as the browser viewport width. */
451
+ width: number;
452
+ /** Output height. */
453
+ height: number;
454
+ /** Storage key of an optional audio track ffmpeg mixes in. */
455
+ audio?: string;
456
+ /** Defaults to `"h264"` server-side when omitted. */
457
+ codec?: FramesCodec;
458
+ /** Constant Rate Factor for the encoder. Worker picks a default when unset. */
459
+ crf?: number;
460
+ /** Storage key the MP4 / WebM is written to. Required — no auto-generation. */
461
+ target: string;
462
+ }
463
+
464
+ /**
465
+ * Handle returned by every BROWSER / FRAMES method. `output_key` is the
466
+ * caller-supplied `target` and is known up front; status updates as the
467
+ * worker progresses through the shared transforms job ledger.
468
+ */
469
+ export interface BrowserJobHandle {
470
+ id: string;
471
+ src_key: string;
472
+ output_key: string;
473
+ status: BrowserJobStatus;
474
+ }
475
+
476
+ /**
477
+ * Headless-browser surface exposed as `platform.env.BROWSER`.
478
+ */
479
+ export interface BrowserClient {
480
+ /**
481
+ * Capture a screenshot of a public URL or one of the tenant's own
482
+ * routes. Returns a {@link BrowserJobHandle} whose `output_key` equals
483
+ * the caller-supplied `request.target` and is known up front — poll
484
+ * `platform.media.transforms.job(handle.id)` for status, then fetch
485
+ * the bytes from `platform.env.STORAGE` once the job completes.
486
+ *
487
+ * Exactly one of `request.url` or `request.path` must be set.
488
+ * `url` mode is gated by an SSRF block-list applied after DNS
489
+ * resolution; `path` mode loopback-routes to the tenant's own
490
+ * deployment.
491
+ *
492
+ * @param request `url` (public, SSRF-gated) or `path` (own deployment),
493
+ * plus optional `viewport`, `wait_for`, `format`, `cookies`,
494
+ * `headers`, and the required `target` storage key.
495
+ * @returns A handle to poll. `output_key` is `request.target`.
496
+ *
497
+ * @example
498
+ * ```ts
499
+ * const handle = await platform.env.BROWSER.screenshot({
500
+ * url: 'https://example.com',
501
+ * viewport: { width: 1280, height: 720 },
502
+ * target: 'shots/example.png',
503
+ * });
504
+ * // poll handle.id via platform.media.transforms.job(...)
505
+ * ```
506
+ */
507
+ screenshot(request: ScreenshotRequest): Promise<BrowserJobHandle>;
508
+ /**
509
+ * Render the target page to a PDF. Same `url` xor `path` discipline
510
+ * as {@link BrowserClient.screenshot}.
511
+ *
512
+ * @param request `url` or `path`, plus optional `format` (page-size
513
+ * preset), `landscape`, `print_background`, `cookies`, `headers`,
514
+ * and the required `target` storage key.
515
+ * @returns A handle to poll. `output_key` is `request.target`.
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * const handle = await platform.env.BROWSER.pdf({
520
+ * path: '/invoices/INV-1042',
521
+ * format: 'A4',
522
+ * print_background: true,
523
+ * target: 'invoices/INV-1042.pdf',
524
+ * });
525
+ * ```
526
+ */
527
+ pdf(request: PdfRequest): Promise<BrowserJobHandle>;
528
+ }
529
+
530
+ /**
531
+ * Deterministic-video surface exposed as `platform.env.FRAMES`.
532
+ */
533
+ export interface FramesClient {
534
+ /**
535
+ * Render one of the tenant's own deployment routes to MP4 / WebM,
536
+ * frame-accurately. The route is expected to import
537
+ * `@maravilla-labs/frames` and call `defineTimeline({...})` at load
538
+ * time — the worker drives `window.__mvFrames.applyState(t)` once
539
+ * per frame and captures via CDP `HeadlessExperimental.beginFrame`,
540
+ * piping PNG frames into ffmpeg.
541
+ *
542
+ * Same render against the same route is deterministic — two
543
+ * back-to-back renders produce byte-identical output (modulo
544
+ * already-stripped muxer metadata).
545
+ *
546
+ * @param request `path` on the tenant's deployment, `fps`,
547
+ * `duration_ms`, `width`, `height`, optional `audio` storage key,
548
+ * `codec` (`h264` default, `vp9` for WebM), optional `crf`, and
549
+ * the required `target` storage key.
550
+ * @returns A handle to poll. `output_key` is `request.target`.
551
+ *
552
+ * @example
553
+ * ```ts
554
+ * const handle = await platform.env.FRAMES.render({
555
+ * path: '/render/hello',
556
+ * fps: 30,
557
+ * duration_ms: 2000,
558
+ * width: 1280,
559
+ * height: 720,
560
+ * target: 'renders/hello.mp4',
561
+ * });
562
+ * ```
563
+ */
564
+ render(request: FramesRenderRequest): Promise<BrowserJobHandle>;
565
+ }
566
+
341
567
  // ════════════════════════════════════════════════════════════════════
342
568
  // Auth, Stewardship, Resources, Circles, Groups, Relations
343
569
  // ════════════════════════════════════════════════════════════════════
@@ -1136,6 +1362,10 @@ export interface Platform {
1136
1362
  KV: KvStore;
1137
1363
  DB: Database;
1138
1364
  STORAGE: Storage;
1365
+ /** Headless-browser screenshot / PDF — Phase 1 stub, real impl in Task #2. */
1366
+ BROWSER: BrowserClient;
1367
+ /** Deterministic HTML → MP4 / WebM render — Phase 1 stub, real impl in Task #3. */
1368
+ FRAMES: FramesClient;
1139
1369
  };
1140
1370
  }
1141
1371
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maravilla-labs/types",
3
- "version": "0.8.0",
3
+ "version": "0.8.3",
4
4
  "description": "TypeScript definitions for Maravilla Runtime platform APIs",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",