@orkestrel/scaffold 0.0.73 → 0.0.74

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.
@@ -4,7 +4,7 @@ let _orkestrel_template = require("@orkestrel/template");
4
4
  let _orkestrel_emitter = require("@orkestrel/emitter");
5
5
  var package_default = {
6
6
  name: "@orkestrel/scaffold",
7
- version: "0.0.73",
7
+ version: "0.0.74",
8
8
  description: "Scaffold workspaces with commands: new, audit, repair, catalog, and overwrite.",
9
9
  keywords: [
10
10
  "audit",
@@ -102,7 +102,7 @@ var package_default = {
102
102
  "@orkestrel/guide": "^0.0.20",
103
103
  "@orkestrel/html": "^0.0.10",
104
104
  "@orkestrel/probe": "^0.0.16",
105
- "@orkestrel/test": "^0.0.16",
105
+ "@orkestrel/test": "^0.0.17",
106
106
  "@types/node": "^26.5.1",
107
107
  "@vitest/browser-playwright": "^4.1.11",
108
108
  "oxfmt": "^0.68.0",
@@ -435,6 +435,8 @@ var SERVICE_SETUP_PATH = "tests/setupService.ts";
435
435
  var SERVICE_TEST_INCLUDE = "tests/service/**/*.test.ts";
436
436
  /** Names the Vite wrapper whose presence makes a workspace `showcase`. */
437
437
  var SHOWCASE_CONFIG_PATH = "configs/app/vite.showcase.config.ts";
438
+ /** Names the Vite wrapper whose presence makes a workspace `journey`. */
439
+ var JOURNEY_CONFIG_PATH = "configs/app/vite.journey.config.ts";
438
440
  /** Matches the bare workspace name syntax: lowercase alphanumeric with hyphens, letter first. */
439
441
  var NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
440
442
  /**
@@ -671,7 +673,7 @@ var CONFIG_TEMPLATES = Object.freeze({
671
673
  "exclude": ["node_modules", "dist", "tmp"]
672
674
  }
673
675
  `,
674
- vite: `import type { PluginOption, UserConfig } from 'vite'
676
+ vite: `{{journey}}import type { PluginOption, UserConfig } from 'vite'
675
677
  import { mergeConfig } from 'vite'
676
678
  {{imports}}import { defineConfig } from 'vitest/config'
677
679
  import manifest from './package.json' with { type: 'json' }
@@ -945,7 +947,7 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
945
947
  root: resolveWorkspacePath('.'),
946
948
  dir: resolveWorkspacePath('.'),
947
949
  include: ['tests/app/browser/**/*.test.ts'],
948
- setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
950
+ {{journeyExclude}} setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
949
951
  browser: {
950
952
  enabled: true,
951
953
  provider: playwright(browserOptions),
@@ -956,7 +958,29 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
956
958
  }
957
959
  return mergeOverride(project, override)
958
960
  }
959
- {{showcaseFactory}}`,
961
+ {{showcaseFactory}}{{journeyFactory}}`,
962
+ journey: `
963
+ // Replace the journey fields directly: merging would concatenate the ordinary include
964
+ // and retain the exclusion of the journey suite.
965
+ export function appJourney(variant: JourneyVariant, variants: readonly JourneyVariant[]): UserConfig {
966
+ const browser = appBrowser()
967
+ return {
968
+ ...browser,
969
+ test: {
970
+ ...browser.test,
971
+ name: { label: \`journey:\${variant.name}\`, color: 'green' },
972
+ include: ['tests/app/browser/integration.test.ts'],
973
+ exclude: [],
974
+ provide: { variant: variant.name, variants, capture },
975
+ browser: {
976
+ ...browser.test?.browser,
977
+ enabled: true,
978
+ viewport: { width: variant.width, height: variant.height },
979
+ },
980
+ },
981
+ }
982
+ }
983
+ `,
960
984
  showcase: `
961
985
  export function appShowcase(override?: UserConfig): UserConfig {
962
986
  const output = 'dist/showcase'
@@ -1068,6 +1092,7 @@ export function appShowcase(override?: UserConfig): UserConfig {
1068
1092
  test: {
1069
1093
  name: { label: 'setup', color: 'white' },
1070
1094
  include: ['tests/setup*.test.ts'],
1095
+ exclude: ['tests/setupBrowser.test.ts'],
1071
1096
  setupFiles: ['./tests/setup.ts'],
1072
1097
  environment: 'node',
1073
1098
  browser: { enabled: false },
@@ -1075,6 +1100,23 @@ export function appShowcase(override?: UserConfig): UserConfig {
1075
1100
  }
1076
1101
  return mergeOverride(project, override)
1077
1102
  }
1103
+ `,
1104
+ browser: `export function setupBrowser(override?: UserConfig): UserConfig {
1105
+ const project: UserConfig = {
1106
+ resolve,
1107
+ test: {
1108
+ name: { label: 'setup:browser', color: 'blue' },
1109
+ include: ['tests/setupBrowser.test.ts'],
1110
+ setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
1111
+ browser: {
1112
+ enabled: true,
1113
+ provider: playwright(browserOptions),
1114
+ instances: [{ browser: 'chromium', headless: true }],
1115
+ },
1116
+ },
1117
+ }
1118
+ return mergeOverride(project, override)
1119
+ }
1078
1120
  `,
1079
1121
  guides: `export function guides(override?: UserConfig): UserConfig {
1080
1122
  const project: UserConfig = {
@@ -1407,6 +1449,22 @@ export default defineConfig(appServer())
1407
1449
  import { appShowcase } from '../../vite.config.ts'
1408
1450
 
1409
1451
  export default defineConfig(appShowcase())
1452
+ `,
1453
+ journey: `import type { JourneyVariant } from '@orkestrel/test'
1454
+ import { defineConfig } from 'vitest/config'
1455
+ import { appJourney } from '../../vite.config.ts'
1456
+
1457
+ // Rename and extend these viewports for the application. Apply themes through its interface.
1458
+ const VARIANTS: readonly JourneyVariant[] = Object.freeze([
1459
+ { name: 'desktop', width: 1280, height: 800 },
1460
+ { name: 'compact', width: 390, height: 844 },
1461
+ ])
1462
+
1463
+ export default defineConfig({
1464
+ test: {
1465
+ projects: VARIANTS.map((variant) => () => appJourney(variant, VARIANTS)),
1466
+ },
1467
+ })
1410
1468
  `
1411
1469
  })
1412
1470
  }),
@@ -1669,7 +1727,7 @@ export function resolveSystemBrowser(
1669
1727
  }
1670
1728
 
1671
1729
  /**
1672
- * Resolves Playwright provider options for whatever browser this host can actually launch.
1730
+ * Resolves Playwright provider options for Chromium on this host.
1673
1731
  *
1674
1732
  * @param pinned - The executable path for Playwright's pinned Chromium revision, when it has one.
1675
1733
  * @param platform - The Node platform whose standard layouts this call probes.
@@ -1689,6 +1747,10 @@ export function resolveSystemBrowser(
1689
1747
  * as well and exists only as a last resort: Windows takes \`msedge\`, which ships with the OS and
1690
1748
  * never collides with a foreground Chrome.
1691
1749
  *
1750
+ * The resolver and the gate cover Chromium alone. Reopen engine selection when another
1751
+ * Playwright engine is installed and launches on the host with a \`captureFrame\` reading
1752
+ * back at its declared size, or when a journey or style divergence is recorded.
1753
+ *
1692
1754
  * @example
1693
1755
  * \`\`\`ts
1694
1756
  * resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)
@@ -3247,14 +3309,15 @@ var isBlueprint = (0, _orkestrel_contract.recordOf)({
3247
3309
  engines: _orkestrel_contract.isString,
3248
3310
  overrides: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(isOverride)),
3249
3311
  bin: _orkestrel_contract.isBoolean,
3250
- setup: _orkestrel_contract.isBoolean,
3312
+ setup: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)((0, _orkestrel_contract.literalOf)("node", "browser"))),
3251
3313
  guides: _orkestrel_contract.isBoolean,
3252
3314
  integration: _orkestrel_contract.isBoolean,
3253
3315
  conformance: _orkestrel_contract.isBoolean,
3254
3316
  service: _orkestrel_contract.isBoolean,
3255
3317
  vendors: (0, _orkestrel_contract.andOf)(isCollection, (0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isString)),
3256
3318
  global: _orkestrel_contract.isBoolean,
3257
- showcase: _orkestrel_contract.isBoolean
3319
+ showcase: _orkestrel_contract.isBoolean,
3320
+ journey: _orkestrel_contract.isBoolean
3258
3321
  }, ["description"]);
3259
3322
  /**
3260
3323
  * Narrows a value to an {@link Artifact}.
@@ -4730,7 +4793,7 @@ function blueprintToDevDependencies(blueprint) {
4730
4793
  const merged = {
4731
4794
  ...BASE_DEV_DEPENDENCIES,
4732
4795
  ...blueprint.src.length > 0 || blueprint.bin ? DECLARATION_DEV_DEPENDENCIES : {},
4733
- ...blueprint.src.includes("browser") ? SOURCE_BROWSER_DEV_DEPENDENCIES : {},
4796
+ ...blueprint.src.includes("browser") || blueprint.setup.includes("browser") ? SOURCE_BROWSER_DEV_DEPENDENCIES : {},
4734
4797
  ...blueprint.app.length > 0 ? APP_DEV_DEPENDENCIES : {},
4735
4798
  ...blueprint.app.includes("browser") ? APP_BROWSER_DEV_DEPENDENCIES : {},
4736
4799
  ...blueprint.showcase && blueprint.app.includes("browser") ? SHOWCASE_DEV_DEPENDENCIES : {},
@@ -4809,9 +4872,11 @@ function blueprintToScripts(blueprint) {
4809
4872
  scripts.test = [
4810
4873
  ...compiles ? ["npm run test:src"] : [],
4811
4874
  ...blueprint.app.length > 0 ? ["npm run test:app"] : [],
4875
+ ...blueprint.journey && blueprint.app.includes("browser") ? ["npm run test:journey"] : [],
4812
4876
  "npm run test:policy",
4813
4877
  "npm run test:config",
4814
- ...blueprint.setup ? ["npm run test:setup"] : [],
4878
+ ...blueprint.setup.includes("node") ? ["npm run test:setup"] : [],
4879
+ ...blueprint.setup.includes("browser") ? ["npm run test:setup:browser"] : [],
4815
4880
  ...blueprint.guides ? ["npm run test:guides"] : [],
4816
4881
  ...blueprint.conformance ? ["npm run test:conformance"] : [],
4817
4882
  ...integrates ? ["npm run test:integration"] : [],
@@ -4832,7 +4897,9 @@ function blueprintToScripts(blueprint) {
4832
4897
  }
4833
4898
  scripts["test:policy"] = `${vitest} --project policy`;
4834
4899
  scripts["test:config"] = `${vitest} --project config`;
4835
- if (blueprint.setup) scripts["test:setup"] = `${vitest} --project setup`;
4900
+ if (blueprint.setup.includes("node")) scripts["test:setup"] = `${vitest} --project setup`;
4901
+ if (blueprint.setup.includes("browser")) scripts["test:setup:browser"] = `${vitest} --project setup:browser`;
4902
+ if (blueprint.journey && blueprint.app.includes("browser")) scripts["test:journey"] = `vitest run --config ${JOURNEY_CONFIG_PATH} --no-cache --reporter=dot`;
4836
4903
  if (blueprint.guides) scripts["test:guides"] = `node --experimental-strip-types ${GUIDES_TEST_PATH}`;
4837
4904
  if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
4838
4905
  scripts["test:probe"] = "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe";
@@ -5056,7 +5123,7 @@ function blueprintToManifest(blueprint) {
5056
5123
  function blueprintToMachinery(blueprint) {
5057
5124
  const hosted = blueprint.app.some((environment) => environment !== "core");
5058
5125
  return {
5059
- browser: blueprint.src.includes("browser") || blueprint.app.includes("browser"),
5126
+ browser: blueprint.src.includes("browser") || blueprint.app.includes("browser") || blueprint.setup.includes("browser"),
5060
5127
  vue: blueprint.app.includes("browser"),
5061
5128
  output: blueprint.src.length > 0 || blueprint.bin || hosted,
5062
5129
  showcase: blueprint.showcase && blueprint.app.includes("browser")
@@ -5196,7 +5263,11 @@ function blueprintToRootVite(blueprint) {
5196
5263
  }
5197
5264
  if (blueprint.app.includes("browser")) {
5198
5265
  const showcaseFactory = machinery.showcase ? CONFIG_TEMPLATES.factories.app.showcase : "";
5199
- factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.app.browser, { showcaseFactory }));
5266
+ factories.push((0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.factories.app.browser, {
5267
+ showcaseFactory,
5268
+ journeyFactory: blueprint.journey ? CONFIG_TEMPLATES.factories.app.journey : "",
5269
+ journeyExclude: blueprint.journey ? " exclude: ['tests/app/browser/integration.test.ts'],\n" : ""
5270
+ }));
5200
5271
  projects.push("appBrowser");
5201
5272
  }
5202
5273
  if (blueprint.app.includes("server")) {
@@ -5207,10 +5278,14 @@ function blueprintToRootVite(blueprint) {
5207
5278
  projects.push("policy");
5208
5279
  factories.push(CONFIG_TEMPLATES.factories.config);
5209
5280
  projects.push("config");
5210
- if (blueprint.setup) {
5281
+ if (blueprint.setup.includes("node")) {
5211
5282
  factories.push(CONFIG_TEMPLATES.factories.setup);
5212
5283
  projects.push("setup");
5213
5284
  }
5285
+ if (blueprint.setup.includes("browser")) {
5286
+ factories.push(CONFIG_TEMPLATES.factories.browser);
5287
+ projects.push("setupBrowser");
5288
+ }
5214
5289
  if (blueprint.guides) {
5215
5290
  factories.push(CONFIG_TEMPLATES.factories.guides);
5216
5291
  projects.push("guides");
@@ -5244,10 +5319,11 @@ ${projects.map((project) => `\t\t\t${project},`).join("\n")}
5244
5319
  "outputBoundary"
5245
5320
  ].filter((helper) => body.includes(helper));
5246
5321
  return (0, _orkestrel_template.fillTemplate)(CONFIG_TEMPLATES.root.vite, {
5322
+ journey: blueprint.journey && machinery.vue ? "import type { JourneyVariant } from '@orkestrel/test'\n" : "",
5247
5323
  imports: imports.length === 0 ? "" : `${imports.join("\n")}\n`,
5248
5324
  helpers: helpers.length === 0 ? "" : `import { ${helpers.join(", ")} } from './configs/helpers.js'\n`,
5249
5325
  browsers: machinery.browser ? "import { resolveBrowser, resolvePinnedBrowser } from './configs/browsers.js'\n" : "",
5250
- options: machinery.browser ? "const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)\n\n" : "",
5326
+ options: (machinery.browser ? "const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)\n\n" : "") + (blueprint.journey && machinery.vue ? "const capture = process.env.CAPTURE === '1'\n\n" : ""),
5251
5327
  factories: body,
5252
5328
  projects: projectRows
5253
5329
  });
@@ -5360,6 +5436,14 @@ ${paths.join("\n")}
5360
5436
  environment: "browser",
5361
5437
  content: CONFIG_TEMPLATES.vites.app.showcase
5362
5438
  });
5439
+ if (blueprint.journey && blueprint.app.includes("browser")) artifacts.push({
5440
+ path: JOURNEY_CONFIG_PATH,
5441
+ group: "configs",
5442
+ ownership: "birth",
5443
+ origin: "template",
5444
+ environment: "browser",
5445
+ content: CONFIG_TEMPLATES.vites.app.journey
5446
+ });
5363
5447
  return artifacts;
5364
5448
  }
5365
5449
  /**
@@ -5480,7 +5564,7 @@ function blueprintToTestArtifacts(blueprint) {
5480
5564
  origin: "template",
5481
5565
  content: ARTIFACT_TEMPLATES.tests.setup
5482
5566
  }];
5483
- if (blueprint.src.includes("browser") || blueprint.app.includes("browser")) artifacts.push({
5567
+ if (blueprintToMachinery(blueprint).browser) artifacts.push({
5484
5568
  path: "tests/setupBrowser.ts",
5485
5569
  group: "tests",
5486
5570
  ownership: "birth",
@@ -6529,6 +6613,11 @@ function blueprintToQuestions(blueprint) {
6529
6613
  message: "showcase projects a browser app, and this workspace declares none, so it emits nothing.",
6530
6614
  blocking: false
6531
6615
  });
6616
+ if (blueprint.journey && !blueprint.app.includes("browser")) questions.push({
6617
+ field: "journey",
6618
+ message: "journey projects a browser app, and this workspace declares none, so it emits nothing.",
6619
+ blocking: false
6620
+ });
6532
6621
  questions.push(...dependenciesToQuestions(blueprint.dependencies, "dependencies", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers.filter((peer) => peer.name.startsWith("@orkestrel/")), "peers", DEPENDENCY_NAME_PATTERN, ORKESTREL_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.peers.filter((peer) => !peer.name.startsWith("@orkestrel/")), "peers", FOREIGN_NAME_PATTERN, FLOOR_RANGE_PATTERN), ...dependenciesToQuestions(blueprint.extras, "extras", FOREIGN_NAME_PATTERN, EXTRA_RANGE_PATTERN));
6533
6622
  const lists = [
6534
6623
  ["dependencies", blueprint.dependencies],
@@ -6736,14 +6825,15 @@ function createBlueprint(name, input) {
6736
6825
  engines: input?.engines ?? DEFAULT_ENGINES,
6737
6826
  overrides: input?.overrides ?? [],
6738
6827
  bin: input?.bin ?? false,
6739
- setup: input?.setup ?? false,
6828
+ setup: input?.setup ?? [],
6740
6829
  guides: input?.guides ?? false,
6741
6830
  integration: input?.integration ?? false,
6742
6831
  conformance: input?.conformance ?? false,
6743
6832
  service: input?.service ?? false,
6744
6833
  vendors: input?.vendors ?? [],
6745
6834
  global: input?.global ?? false,
6746
- showcase: input?.showcase ?? false
6835
+ showcase: input?.showcase ?? false,
6836
+ journey: input?.journey ?? false
6747
6837
  }));
6748
6838
  if (blueprint === void 0) throw new ScaffoldError("INVALID", "The filled record is not a blueprint.", { name });
6749
6839
  return blueprint;
@@ -7087,6 +7177,7 @@ exports.HOST_INVENTORY_PATH = HOST_INVENTORY_PATH;
7087
7177
  exports.HOST_PATHS = HOST_PATHS;
7088
7178
  exports.INTEGRATION_TEST_PATH = INTEGRATION_TEST_PATH;
7089
7179
  exports.INVALID_PATH_CHARACTER_PATTERN = INVALID_PATH_CHARACTER_PATTERN;
7180
+ exports.JOURNEY_CONFIG_PATH = JOURNEY_CONFIG_PATH;
7090
7181
  exports.MANIFEST_PATH = MANIFEST_PATH;
7091
7182
  exports.MAX_ARTIFACT_BYTES = MAX_ARTIFACT_BYTES;
7092
7183
  exports.MAX_ARTIFACT_HEX_LENGTH = MAX_ARTIFACT_HEX_LENGTH;