@pygmalionjs/pygmalion 0.5.4 → 0.5.6

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.
@@ -1,4 +1,4 @@
1
- import { F as s, N as a, e as r, s as i, a as t } from "./FrozenRoutePreview-gn0xHRPG.js";
1
+ import { F as s, N as a, e as r, s as i, a as t } from "./FrozenRoutePreview-ZQp4jiaX.js";
2
2
  export {
3
3
  s as FrozenRoutePreviewView,
4
4
  a as NodeModel,
@@ -1384,6 +1384,140 @@ export function storyboardEnvironmentBootstrapSource() {
1384
1384
  });
1385
1385
  }
1386
1386
 
1387
+ // Request outcomes and request recording share one interception point: the
1388
+ // frame's own traffic is both what the editor asks about and what a condition
1389
+ // acts on, so recording is the enumeration and conditions are the answer.
1390
+ const network = plainRecord(environment.network);
1391
+ if (network) {
1392
+ const conditions = Array.isArray(network.conditions)
1393
+ ? network.conditions.filter((condition) => {
1394
+ const record = plainRecord(condition);
1395
+ return (
1396
+ record &&
1397
+ typeof record.match === 'string' &&
1398
+ record.match.length > 0 &&
1399
+ plainRecord(record.outcome) &&
1400
+ ['fail', 'empty', 'slow'].includes(record.outcome.kind)
1401
+ );
1402
+ })
1403
+ : [];
1404
+ const recorded = network.record === true ? [] : null;
1405
+ if (recorded) {
1406
+ Object.defineProperty(globalThis, '__PYGMALION_REQUESTS__', {
1407
+ configurable: true,
1408
+ value: recorded,
1409
+ });
1410
+ }
1411
+ const methodOf = (init, fallback) =>
1412
+ String(init?.method ?? fallback ?? 'GET').toUpperCase();
1413
+ const matchFor = (url, method) =>
1414
+ conditions.find(
1415
+ (condition) =>
1416
+ url.includes(condition.match) &&
1417
+ (condition.method == null ||
1418
+ String(condition.method).toUpperCase() === method),
1419
+ ) ?? null;
1420
+ const wait = (ms) =>
1421
+ new Promise((resolve) => setTimeout(resolve, Math.max(0, Number(ms) || 0)));
1422
+
1423
+ if (typeof globalThis.fetch === 'function') {
1424
+ const originalFetch = globalThis.fetch.bind(globalThis);
1425
+ Object.defineProperty(globalThis, 'fetch', {
1426
+ configurable: true,
1427
+ writable: true,
1428
+ async value(input, init) {
1429
+ const url = String(
1430
+ typeof input === 'string' ? input : (input?.url ?? input),
1431
+ );
1432
+ const method = methodOf(init, input?.method);
1433
+ if (recorded) recorded.push({ url, method });
1434
+ const condition = matchFor(url, method);
1435
+ if (!condition) return originalFetch(input, init);
1436
+ const outcome = condition.outcome;
1437
+ if (outcome.kind === 'slow') {
1438
+ await wait(outcome.delayMs);
1439
+ return originalFetch(input, init);
1440
+ }
1441
+ if (outcome.kind === 'empty') {
1442
+ // A well-formed response with nothing in it — the empty state is a
1443
+ // success path, so failing here would exercise the wrong branch.
1444
+ return new Response(String(outcome.body ?? ''), {
1445
+ status: Number(outcome.status ?? 200),
1446
+ headers: { 'content-type': 'application/json' },
1447
+ });
1448
+ }
1449
+ const status = Number(outcome.status ?? 0);
1450
+ if (status > 0) {
1451
+ return new Response(null, {
1452
+ status,
1453
+ statusText: String(outcome.message ?? 'Pygmalion request condition'),
1454
+ });
1455
+ }
1456
+ throw new TypeError(
1457
+ String(outcome.message ?? 'Pygmalion request condition: failed'),
1458
+ );
1459
+ },
1460
+ });
1461
+ }
1462
+
1463
+ const XHR = globalThis.XMLHttpRequest;
1464
+ if (typeof XHR === 'function' && XHR.prototype) {
1465
+ const originalOpen = XHR.prototype.open;
1466
+ const originalSend = XHR.prototype.send;
1467
+ const state = new WeakMap();
1468
+ Object.defineProperty(XHR.prototype, 'open', {
1469
+ configurable: true,
1470
+ value(method, url, ...rest) {
1471
+ state.set(this, {
1472
+ url: String(url),
1473
+ method: String(method ?? 'GET').toUpperCase(),
1474
+ });
1475
+ return originalOpen.call(this, method, url, ...rest);
1476
+ },
1477
+ });
1478
+ Object.defineProperty(XHR.prototype, 'send', {
1479
+ configurable: true,
1480
+ value(body) {
1481
+ const opened = state.get(this);
1482
+ if (!opened) return originalSend.call(this, body);
1483
+ if (recorded) recorded.push({ ...opened });
1484
+ const condition = matchFor(opened.url, opened.method);
1485
+ if (!condition) return originalSend.call(this, body);
1486
+ const outcome = condition.outcome;
1487
+ if (outcome.kind === 'slow') {
1488
+ wait(outcome.delayMs).then(() => originalSend.call(this, body));
1489
+ return undefined;
1490
+ }
1491
+ // The event order matters to callers: readyState settles, then the
1492
+ // terminal event fires, the same way the real object behaves.
1493
+ const fail = () => {
1494
+ Object.defineProperty(this, 'readyState', {
1495
+ configurable: true,
1496
+ value: 4,
1497
+ });
1498
+ if (outcome.kind === 'empty') {
1499
+ Object.defineProperties(this, {
1500
+ status: { configurable: true, value: Number(outcome.status ?? 200) },
1501
+ responseText: { configurable: true, value: String(outcome.body ?? '') },
1502
+ response: { configurable: true, value: String(outcome.body ?? '') },
1503
+ });
1504
+ this.dispatchEvent(new Event('load'));
1505
+ } else {
1506
+ Object.defineProperty(this, 'status', {
1507
+ configurable: true,
1508
+ value: Number(outcome.status ?? 0),
1509
+ });
1510
+ this.dispatchEvent(new Event('error'));
1511
+ }
1512
+ this.dispatchEvent(new Event('loadend'));
1513
+ };
1514
+ setTimeout(fail, 0);
1515
+ return undefined;
1516
+ },
1517
+ });
1518
+ }
1519
+ }
1520
+
1387
1521
  const permissions = plainRecord(environment.permissions);
1388
1522
  if (permissions && navigator.permissions?.query) {
1389
1523
  const originalQuery = navigator.permissions.query.bind(navigator.permissions);
@@ -50,3 +50,11 @@ export {
50
50
  validateRoutePreviewArtifactBundle,
51
51
  validateRoutePreviewArtifactV3,
52
52
  } from './route-preview-artifact-v3.mjs';
53
+
54
+ // The source scan, so a consumer's own gate can ask the route question outside
55
+ // a running Vite server: the scan lists the routes the codebase can render and
56
+ // `enumerateRouteCandidates` turns the ones with no screen case into demands.
57
+ export {
58
+ PYGMALION_STORYBOARD_ENVIRONMENT_QUERY,
59
+ scanStoryboardEnvironment,
60
+ } from './storyboard-environment.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pygmalionjs/pygmalion",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Code-backed DOM design sandbox and visual QA editor",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {