@pygmalionjs/pygmalion 0.2.7 → 0.2.8

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/node/vite.mjs CHANGED
@@ -25,6 +25,32 @@ import {
25
25
  prepareSourceOperations,
26
26
  writeSourceOperations,
27
27
  } from './source-operations.mjs';
28
+ import {
29
+ PYGMALION_STORYBOARD_ENVIRONMENT_CONTROL,
30
+ PYGMALION_STORYBOARD_ENVIRONMENT_QUERY,
31
+ pygmalionStoryboardPlugin,
32
+ pygmalionStoryboardRuntimePlugin,
33
+ scanStoryboardEnvironment,
34
+ storyboardEnvironmentBootstrapSource,
35
+ } from './storyboard-environment.mjs';
36
+ import {
37
+ canonicalizeStoryboardExecutions,
38
+ executeStoryboardCandidates,
39
+ fingerprintStoryboardSnapshot,
40
+ normalizeStoryboardSnapshot,
41
+ PYGMALION_STORYBOARD_CANONICAL_CONTROL,
42
+ recommendedStoryboardExecutionConcurrency,
43
+ } from './storyboard-canonical.mjs';
44
+ import {
45
+ convertRoutePreviewArtifactV1ToV2,
46
+ convertRoutePreviewArtifactV2ToV1,
47
+ createRoutePreviewArtifactV2,
48
+ isSafeFrozenRoutePreviewSnapshot,
49
+ reconstructRoutePreviewArtifactSnapshot,
50
+ reconstructRoutePreviewArtifactSnapshots,
51
+ ROUTE_PREVIEW_ARTIFACT_V2_LIMITS,
52
+ validateRoutePreviewArtifactV2,
53
+ } from './route-preview-artifact-v2.mjs';
28
54
 
29
55
  function requiredPath(value, name, base) {
30
56
  if (typeof value !== 'string' || value.trim() === '') {
@@ -117,10 +143,17 @@ export function resolvePygmalionProject(config) {
117
143
  }
118
144
 
119
145
  export function createPygmalionVitePlugins(config) {
120
- if (process.env.PYGMALION_PREVIEW_MODE === '1') return [];
146
+ if (process.env.PYGMALION_PREVIEW_MODE === '1') {
147
+ return [pygmalionStoryboardRuntimePlugin()];
148
+ }
121
149
 
122
150
  const project = resolvePygmalionProject(config);
123
- const plugins = [];
151
+ const plugins = [
152
+ pygmalionStoryboardPlugin({
153
+ root: project.appRoot,
154
+ sourceDirectory: project.sourceDirectory,
155
+ }),
156
+ ];
124
157
 
125
158
  if (project.inspect !== false) {
126
159
  plugins.push(
@@ -210,9 +243,21 @@ export {
210
243
  PYGMALION_INSPECT_CONTROL,
211
244
  PYGMALION_SESSION_CONTROL,
212
245
  PYGMALION_SESSION_PREFIX,
246
+ PYGMALION_STORYBOARD_ENVIRONMENT_CONTROL,
247
+ PYGMALION_STORYBOARD_ENVIRONMENT_QUERY,
248
+ PYGMALION_STORYBOARD_CANONICAL_CONTROL,
249
+ canonicalizeStoryboardExecutions,
250
+ executeStoryboardCandidates,
251
+ fingerprintStoryboardSnapshot,
252
+ normalizeStoryboardSnapshot,
253
+ recommendedStoryboardExecutionConcurrency,
213
254
  pygmalionDesignSessionPlugin,
214
255
  pygmalionDevMirrorPlugin,
215
256
  pygmalionInspectPlugin,
257
+ pygmalionStoryboardPlugin,
258
+ pygmalionStoryboardRuntimePlugin,
259
+ scanStoryboardEnvironment,
260
+ storyboardEnvironmentBootstrapSource,
216
261
  buildSourceGraph,
217
262
  collectAffectedSourceFiles,
218
263
  findAffectedSourceFiles,
@@ -221,4 +266,12 @@ export {
221
266
  writeSourceOperations,
222
267
  writeStyleEdit,
223
268
  writeTextEdit,
269
+ convertRoutePreviewArtifactV1ToV2,
270
+ convertRoutePreviewArtifactV2ToV1,
271
+ createRoutePreviewArtifactV2,
272
+ isSafeFrozenRoutePreviewSnapshot,
273
+ reconstructRoutePreviewArtifactSnapshot,
274
+ reconstructRoutePreviewArtifactSnapshots,
275
+ ROUTE_PREVIEW_ARTIFACT_V2_LIMITS,
276
+ validateRoutePreviewArtifactV2,
224
277
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pygmalionjs/pygmalion",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Code-backed DOM design sandbox and visual QA editor",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -32,9 +32,12 @@
32
32
  "node/dev-mirror.mjs",
33
33
  "node/dev-view.vite.mjs",
34
34
  "node/inspect-plugin.mjs",
35
+ "node/route-preview-artifact-v2.mjs",
35
36
  "node/source-diff.mjs",
36
37
  "node/source-graph.mjs",
37
38
  "node/source-operations.mjs",
39
+ "node/storyboard-canonical.mjs",
40
+ "node/storyboard-environment.mjs",
38
41
  "node/vite.mjs",
39
42
  "types.d.ts",
40
43
  "testing.d.ts",
package/types.d.ts CHANGED
@@ -86,6 +86,30 @@ export type DesignSerializable =
86
86
  | { readonly [key: string]: DesignSerializable };
87
87
 
88
88
  export type DesignScreenPreset = Readonly<Record<string, DesignSerializable>>;
89
+ export type StoryboardPermissionState = 'granted' | 'denied' | 'prompt';
90
+ export type StoryboardMediaFailure =
91
+ | 'not-allowed'
92
+ | 'not-found'
93
+ | 'not-readable'
94
+ | 'overconstrained';
95
+
96
+ export interface StoryboardMediaDevice {
97
+ kind: 'audioinput' | 'audiooutput' | 'videoinput';
98
+ deviceId: string;
99
+ groupId?: string;
100
+ label?: string;
101
+ }
102
+
103
+ export interface StoryboardEnvironment {
104
+ localStorage?: Readonly<Record<string, string | null>>;
105
+ sessionStorage?: Readonly<Record<string, string | null>>;
106
+ permissions?: Readonly<Record<string, StoryboardPermissionState>>;
107
+ mediaDevices?: {
108
+ devices?: readonly StoryboardMediaDevice[];
109
+ getUserMedia?: 'passthrough' | StoryboardMediaFailure;
110
+ };
111
+ }
112
+
89
113
  export type DesignScreenAssertionVisibility = 'visible' | 'hidden';
90
114
 
91
115
  export interface DesignScreenAttributeAssertion {
@@ -124,6 +148,7 @@ export interface DesignImportPage {
124
148
  state?: string;
125
149
  scenarioId?: string;
126
150
  interactions?: readonly DesignScreenInteraction[];
151
+ environment?: StoryboardEnvironment;
127
152
  preset?: DesignScreenPreset;
128
153
  assertions?: readonly DesignScreenAssertion[];
129
154
  }
@@ -353,6 +378,7 @@ export interface DesignImportInitialPage extends InitialPageDef {
353
378
  state?: string;
354
379
  scenarioId?: string;
355
380
  interactions?: DesignScreenInteraction[];
381
+ environment?: StoryboardEnvironment;
356
382
  preset?: DesignScreenPreset;
357
383
  assertions?: DesignScreenAssertion[];
358
384
  }
@@ -412,10 +438,34 @@ export declare function setPygmalionAppOrigin(origin: string): void;
412
438
  export declare function setPygmalionPreviewRevision(revision: string): void;
413
439
  /** Sets the number of actual app iframes to run simultaneously in the entire editor. */
414
440
  export declare function setPygmalionPreviewConcurrency(value: number): void;
441
+ /** Returns the adaptive live-preview lane count for the current browser. */
442
+ export declare function getRecommendedPygmalionPreviewConcurrency(
443
+ capabilities?: {
444
+ hardwareConcurrency?: number;
445
+ deviceMemory?: number;
446
+ },
447
+ ): number;
415
448
  /** Removes all route screens fixed in memory and IndexedDB. If a namespace is given, only the corresponding cache is deleted. */
416
449
  export declare function clearPygmalionPreviewCache(namespace?: string): void;
417
-
418
- export interface RoutePreviewArtifactBundle {
450
+ export declare const STORYBOARD_ENVIRONMENT_QUERY: string;
451
+ export declare const STORYBOARD_ENVIRONMENT_CONTROL: string;
452
+ export declare function createStoryboardRouteUrl(
453
+ appOrigin: string,
454
+ route: string,
455
+ environment?: StoryboardEnvironment,
456
+ ): string;
457
+ export declare function setStoryboardBaselineEnvironment(
458
+ environment?: StoryboardEnvironment,
459
+ ): void;
460
+ export declare function getStoryboardBaselineEnvironment():
461
+ | StoryboardEnvironment
462
+ | undefined;
463
+ export declare function mergeStoryboardEnvironment(
464
+ base?: StoryboardEnvironment,
465
+ override?: StoryboardEnvironment,
466
+ ): StoryboardEnvironment | undefined;
467
+
468
+ export interface RoutePreviewArtifactBundleV1 {
419
469
  version: 1;
420
470
  namespace: string;
421
471
  /** Source SHA at the time of creation. It must match the value before the first ':' of runtime previewRevision. */
@@ -423,6 +473,36 @@ export interface RoutePreviewArtifactBundle {
423
473
  snapshots: Record<string, string>;
424
474
  }
425
475
 
476
+ export interface RoutePreviewArtifactBundleV2 {
477
+ version: 2;
478
+ namespace: string;
479
+ sourceRevision?: string;
480
+ assets: {
481
+ head: Record<string, string>;
482
+ stylesheets: Record<string, string>;
483
+ };
484
+ frames: Record<
485
+ string,
486
+ {
487
+ document: {
488
+ doctype: string;
489
+ htmlAttributes: string;
490
+ headAttributes: string;
491
+ bodyAttributes: string;
492
+ };
493
+ head: {
494
+ kind: 'head' | 'stylesheet';
495
+ hash: string;
496
+ }[];
497
+ body: string;
498
+ }
499
+ >;
500
+ }
501
+
502
+ export type RoutePreviewArtifactBundle =
503
+ | RoutePreviewArtifactBundleV1
504
+ | RoutePreviewArtifactBundleV2;
505
+
426
506
  export interface InitialPageDef {
427
507
  name: string;
428
508
  /** Owning canvas, such as 'Design System' or 'Screens'. Defaults to 'default'. */
@@ -453,6 +533,7 @@ export interface InitialPageDef {
453
533
  state?: string;
454
534
  scenarioId?: string;
455
535
  interactions?: DesignScreenInteraction[];
536
+ environment?: StoryboardEnvironment;
456
537
  preset?: DesignScreenPreset;
457
538
  assertions?: DesignScreenAssertion[];
458
539
  }
@@ -821,7 +902,7 @@ export declare function PygmalionEditor(props: {
821
902
  previewCacheNamespace?: string;
822
903
  /** A canonical screen snapshot created during build. When the namespace matches, it is injected into the cache before the first render. */
823
904
  previewArtifacts?: RoutePreviewArtifactBundle;
824
- /** Number of actual app previews to run simultaneously. Default is 12, safe upper limit is 32. */
905
+ /** Number of actual app previews to run simultaneously. Defaults to an adaptive 12–32 lanes. */
825
906
  previewConcurrency?: number;
826
907
  /** Controlled by external status such as host route ▶ Whether the preview is opened or not. */
827
908
  previewOpen?: boolean;
@@ -839,6 +920,10 @@ export declare function PygmalionEditor(props: {
839
920
  onInspectPreview?: (payload: InspectApplyPayload) => Promise<InspectPreviewResult>;
840
921
  /** Check the reverse dependency closure of the changed source file. */
841
922
  onInspectImpact?: (componentFiles: string[]) => Promise<InspectImpactResult>;
923
+ /** Detect portable browser branches from source before route frames boot. Default true. */
924
+ storyboardDiscovery?: boolean;
925
+ /** Vite endpoint that returns the generated generic storyboard environment manifest. */
926
+ storyboardDiscoveryEndpoint?: string;
842
927
  }): ReactElement;
843
928
 
844
929
  /** Edit token values ​​in code (live override + onTokensChange notification). */
package/vite.d.ts CHANGED
@@ -180,6 +180,268 @@ export interface PygmalionSourceGraphOptions {
180
180
  sourceDirectory?: string;
181
181
  }
182
182
 
183
+ export type PygmalionStoryboardEnvironmentKind =
184
+ | 'permission'
185
+ | 'media-devices'
186
+ | 'storage';
187
+
188
+ export interface PygmalionStoryboardEnvironmentEvidence {
189
+ id: string;
190
+ kind: string;
191
+ capability: string;
192
+ sourcePath: string;
193
+ line: number;
194
+ column: number;
195
+ operation?: string;
196
+ }
197
+
198
+ export interface PygmalionStoryboardEnvironmentDimension {
199
+ id: string;
200
+ kind: PygmalionStoryboardEnvironmentKind;
201
+ name: string;
202
+ values: string[];
203
+ evidenceIds: string[];
204
+ }
205
+
206
+ export interface PygmalionStoryboardEnvironmentScenario {
207
+ id: string;
208
+ label: string;
209
+ environment: import('./types').StoryboardEnvironment;
210
+ evidenceIds: string[];
211
+ }
212
+
213
+ export interface PygmalionStoryboardEnvironmentUnresolved {
214
+ id: string;
215
+ kind: string;
216
+ reason: string;
217
+ sourcePath: string;
218
+ line: number;
219
+ column: number;
220
+ }
221
+
222
+ export interface PygmalionStoryboardEnvironmentManifest {
223
+ version: 1;
224
+ sourceRoot: string;
225
+ dimensions: PygmalionStoryboardEnvironmentDimension[];
226
+ scenarios: PygmalionStoryboardEnvironmentScenario[];
227
+ evidence: PygmalionStoryboardEnvironmentEvidence[];
228
+ routes: {
229
+ id: string;
230
+ path: string;
231
+ sourcePaths: string[];
232
+ rootSpecifiers: string[];
233
+ resolvedRoots: string[];
234
+ hasExplicitRoot: boolean;
235
+ declarations: {
236
+ sourcePath: string;
237
+ line: number;
238
+ column: number;
239
+ }[];
240
+ evidenceIds: string[];
241
+ scenarioIds: string[];
242
+ }[];
243
+ candidates: {
244
+ id: string;
245
+ route: string;
246
+ scenarioId: string;
247
+ environment: import('./types').StoryboardEnvironment;
248
+ evidenceIds: string[];
249
+ }[];
250
+ edges: {
251
+ id: string;
252
+ from: string;
253
+ to: string;
254
+ kind: string;
255
+ evidence: {
256
+ sourcePath: string;
257
+ line: number;
258
+ column: number;
259
+ };
260
+ unresolvedTarget: boolean;
261
+ }[];
262
+ coverage: {
263
+ routes: number;
264
+ candidates: number;
265
+ environmentDimensions: number;
266
+ unresolved: number;
267
+ unresolvedTargets: number;
268
+ };
269
+ unresolved: PygmalionStoryboardEnvironmentUnresolved[];
270
+ }
271
+
272
+ export interface PygmalionStoryboardEnvironmentScanOptions {
273
+ sourceDirectory?: string;
274
+ maxFiles?: number;
275
+ }
276
+
277
+ export interface PygmalionStoryboardCandidateExecution {
278
+ candidateId: string;
279
+ status: 'captured' | 'failed';
280
+ snapshot?: string;
281
+ error?: string;
282
+ }
283
+
284
+ export interface PygmalionStoryboardCandidateExecutionContext {
285
+ signal: AbortSignal;
286
+ index: number;
287
+ total: number;
288
+ }
289
+
290
+ export type PygmalionStoryboardCanonicalWarningCode =
291
+ | 'branch-not-observed'
292
+ | 'capture-failed'
293
+ | 'duplicate-execution'
294
+ | 'invalid-snapshot'
295
+ | 'missing-execution'
296
+ | 'unknown-candidate';
297
+
298
+ export interface PygmalionStoryboardCanonicalWarning {
299
+ code: PygmalionStoryboardCanonicalWarningCode;
300
+ severity: 'warning' | 'error';
301
+ candidateId: string;
302
+ route: string;
303
+ scenarioId: string;
304
+ evidenceIds: string[];
305
+ message: string;
306
+ }
307
+
308
+ export interface PygmalionStoryboardCanonicalFrame {
309
+ id: string;
310
+ fingerprint: string;
311
+ snapshot: string;
312
+ candidateIds: string[];
313
+ routes: string[];
314
+ scenarioIds: string[];
315
+ evidenceIds: string[];
316
+ }
317
+
318
+ export interface PygmalionStoryboardCanonicalManifest {
319
+ version: 1;
320
+ frames: PygmalionStoryboardCanonicalFrame[];
321
+ aliases: Record<string, string>;
322
+ warnings: PygmalionStoryboardCanonicalWarning[];
323
+ coverage: {
324
+ expected: number;
325
+ executed: number;
326
+ captured: number;
327
+ canonical: number;
328
+ duplicates: number;
329
+ failed: number;
330
+ missing: number;
331
+ unreproduced: number;
332
+ complete: boolean;
333
+ };
334
+ }
335
+
336
+ export declare function normalizeStoryboardSnapshot(snapshot: string): string | null;
337
+ export declare function fingerprintStoryboardSnapshot(snapshot: string): string | null;
338
+ export declare function canonicalizeStoryboardExecutions(
339
+ candidates: PygmalionStoryboardEnvironmentManifest['candidates'],
340
+ executions: PygmalionStoryboardCandidateExecution[],
341
+ ): PygmalionStoryboardCanonicalManifest;
342
+ export declare function executeStoryboardCandidates(
343
+ candidates: PygmalionStoryboardEnvironmentManifest['candidates'],
344
+ capture: (
345
+ candidate: PygmalionStoryboardEnvironmentManifest['candidates'][number],
346
+ context: PygmalionStoryboardCandidateExecutionContext,
347
+ ) => string | Promise<string>,
348
+ options?: {
349
+ concurrency?: number;
350
+ timeoutMs?: number;
351
+ },
352
+ ): Promise<PygmalionStoryboardCandidateExecution[]>;
353
+ export declare function recommendedStoryboardExecutionConcurrency(
354
+ capabilities?: {
355
+ parallelism?: number;
356
+ totalMemoryBytes?: number;
357
+ },
358
+ ): number;
359
+
360
+ export interface PygmalionRoutePreviewArtifactV1 {
361
+ version: 1;
362
+ namespace: string;
363
+ sourceRevision?: string;
364
+ snapshots: Record<string, string>;
365
+ }
366
+
367
+ export interface PygmalionRoutePreviewArtifactV2 {
368
+ version: 2;
369
+ namespace: string;
370
+ sourceRevision?: string;
371
+ assets: {
372
+ head: Record<string, string>;
373
+ stylesheets: Record<string, string>;
374
+ };
375
+ frames: Record<
376
+ string,
377
+ {
378
+ document: {
379
+ doctype: string;
380
+ htmlAttributes: string;
381
+ headAttributes: string;
382
+ bodyAttributes: string;
383
+ };
384
+ head: {
385
+ kind: 'head' | 'stylesheet';
386
+ hash: string;
387
+ }[];
388
+ body: string;
389
+ }
390
+ >;
391
+ }
392
+
393
+ export interface PygmalionRoutePreviewArtifactV2Validation {
394
+ valid: boolean;
395
+ errors: string[];
396
+ bytes: number;
397
+ }
398
+
399
+ export declare const ROUTE_PREVIEW_ARTIFACT_V2_LIMITS: Readonly<
400
+ Record<string, number>
401
+ >;
402
+ export declare function isSafeFrozenRoutePreviewSnapshot(
403
+ snapshot: unknown,
404
+ ): snapshot is string;
405
+ export declare function createRoutePreviewArtifactV2(input: {
406
+ namespace: string;
407
+ sourceRevision?: string;
408
+ snapshots: Record<string, string>;
409
+ } | PygmalionRoutePreviewArtifactV1): PygmalionRoutePreviewArtifactV2;
410
+ export declare function convertRoutePreviewArtifactV1ToV2(
411
+ bundle: PygmalionRoutePreviewArtifactV1,
412
+ ): PygmalionRoutePreviewArtifactV2;
413
+ export declare function convertRoutePreviewArtifactV2ToV1(
414
+ bundle: PygmalionRoutePreviewArtifactV2,
415
+ ): PygmalionRoutePreviewArtifactV1;
416
+ export declare function validateRoutePreviewArtifactV2(
417
+ bundle: unknown,
418
+ ): PygmalionRoutePreviewArtifactV2Validation;
419
+ export declare function reconstructRoutePreviewArtifactSnapshot(
420
+ bundle: PygmalionRoutePreviewArtifactV2,
421
+ frameId: string,
422
+ ): string | null;
423
+ export declare function reconstructRoutePreviewArtifactSnapshots(
424
+ bundle: PygmalionRoutePreviewArtifactV2,
425
+ ): Record<string, string>;
426
+
427
+ export declare function scanStoryboardEnvironment(
428
+ root: string,
429
+ options?: PygmalionStoryboardEnvironmentScanOptions,
430
+ ): Promise<PygmalionStoryboardEnvironmentManifest>;
431
+
432
+ export declare function storyboardEnvironmentBootstrapSource(): string;
433
+ export declare function pygmalionStoryboardRuntimePlugin(): PluginOption;
434
+ export declare function pygmalionStoryboardPlugin(options: {
435
+ root: string;
436
+ sourceDirectory?: string;
437
+ endpoint?: string;
438
+ canonicalEndpoint?: string;
439
+ }): PluginOption;
440
+
441
+ export declare const PYGMALION_STORYBOARD_CANONICAL_CONTROL: string;
442
+ export declare const PYGMALION_STORYBOARD_ENVIRONMENT_CONTROL: string;
443
+ export declare const PYGMALION_STORYBOARD_ENVIRONMENT_QUERY: string;
444
+
183
445
  export interface PygmalionSourceGraph {
184
446
  sourceDirectory: string;
185
447
  files: string[];