@orkestrel/scaffold 0.0.16 → 0.0.18
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/README.md +13 -3
- package/dist/bin/scaffold.js +67 -31
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/claude/agents/orkestrel.md +14 -14
- package/dist/host/guides/src/scaffold.md +55 -18
- package/dist/host/tests/setupPolicy.ts +4 -3
- package/dist/src/core/index.cjs +196 -62
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +3 -3
- package/dist/src/core/index.d.ts +3 -3
- package/dist/src/core/index.js +196 -62
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +51 -33
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +10 -6
- package/dist/src/server/index.d.ts +10 -6
- package/dist/src/server/index.js +49 -31
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -4
package/dist/src/core/index.cjs
CHANGED
|
@@ -227,7 +227,7 @@ var DEFAULT_VERSION = "0.0.1";
|
|
|
227
227
|
/** The `engines.node` range the `blueprint` builder fills. */
|
|
228
228
|
var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
|
|
229
229
|
/** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
|
|
230
|
-
var SCAFFOLD_RANGE = "^0.0.
|
|
230
|
+
var SCAFFOLD_RANGE = "^0.0.18";
|
|
231
231
|
/** Tooling versions shared by scaffold and every generated workspace. */
|
|
232
232
|
var BASE_DEV_DEPENDENCIES = Object.freeze({
|
|
233
233
|
"@microsoft/api-extractor": "^7.58.12",
|
|
@@ -4467,9 +4467,7 @@ describe('createApplication', () => {
|
|
|
4467
4467
|
'x'.repeat(204),
|
|
4468
4468
|
\`\${' '.repeat(MAX_APPLICATION_NAME_INPUT_LENGTH)}x\`,
|
|
4469
4469
|
]) {
|
|
4470
|
-
expect(() => Reflect.apply(createApplication, undefined, [value])).
|
|
4471
|
-
ApplicationError,
|
|
4472
|
-
)
|
|
4470
|
+
expect(() => Reflect.apply(createApplication, undefined, [value])).toThrow(ApplicationError)
|
|
4473
4471
|
}
|
|
4474
4472
|
const error = new ApplicationError('CONFIG', 'invalid')
|
|
4475
4473
|
expect(isApplicationError(error)).toBe(true)
|
|
@@ -4544,7 +4542,7 @@ describe('createBrowserApplication', () => {
|
|
|
4544
4542
|
{ name: 'x'.repeat(204) },
|
|
4545
4543
|
{ name: \`\${' '.repeat(MAX_BROWSER_APPLICATION_NAME_INPUT_LENGTH)}x\` },
|
|
4546
4544
|
]) {
|
|
4547
|
-
expect(() => Reflect.apply(createBrowserApplication, undefined, [value])).
|
|
4545
|
+
expect(() => Reflect.apply(createBrowserApplication, undefined, [value])).toThrow(
|
|
4548
4546
|
BrowserApplicationError,
|
|
4549
4547
|
)
|
|
4550
4548
|
}
|
|
@@ -4569,14 +4567,14 @@ describe('createBrowserApplication', () => {
|
|
|
4569
4567
|
const revocable = Proxy.revocable({}, {})
|
|
4570
4568
|
revocable.revoke()
|
|
4571
4569
|
|
|
4572
|
-
expect(() => parseBrowserApplicationOptions(accessor)).
|
|
4570
|
+
expect(() => parseBrowserApplicationOptions(accessor)).toThrow(BrowserApplicationError)
|
|
4573
4571
|
expect(reads).toBe(0)
|
|
4574
|
-
expect(() => Reflect.apply(createBrowserApplication, undefined, [hostile])).
|
|
4572
|
+
expect(() => Reflect.apply(createBrowserApplication, undefined, [hostile])).toThrow(
|
|
4573
|
+
BrowserApplicationError,
|
|
4574
|
+
)
|
|
4575
|
+
expect(() => Reflect.apply(createBrowserApplication, undefined, [revocable.proxy])).toThrow(
|
|
4575
4576
|
BrowserApplicationError,
|
|
4576
4577
|
)
|
|
4577
|
-
expect(() =>
|
|
4578
|
-
Reflect.apply(createBrowserApplication, undefined, [revocable.proxy]),
|
|
4579
|
-
).toThrowError(BrowserApplicationError)
|
|
4580
4578
|
expect(isBrowserApplicationError(new BrowserApplicationError('CONFIG', 'invalid'))).toBe(true)
|
|
4581
4579
|
expect(isBrowserApplicationError(new Error('plain'))).toBe(false)
|
|
4582
4580
|
expect(isBrowserApplicationError(revocable.proxy)).toBe(false)
|
|
@@ -4679,20 +4677,20 @@ describe('ApplicationServer', () => {
|
|
|
4679
4677
|
})
|
|
4680
4678
|
|
|
4681
4679
|
it('validates direct options before allocating a listener', () => {
|
|
4682
|
-
expect(() => createApplicationServer({ host: ' ' })).
|
|
4680
|
+
expect(() => createApplicationServer({ host: ' ' })).toThrow(
|
|
4683
4681
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
4684
4682
|
)
|
|
4685
|
-
expect(() => createApplicationServer({ port: Number.NaN })).
|
|
4683
|
+
expect(() => createApplicationServer({ port: Number.NaN })).toThrow(
|
|
4686
4684
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
4687
4685
|
)
|
|
4688
|
-
expect(() => createApplicationServer({ port: -1 })).
|
|
4686
|
+
expect(() => createApplicationServer({ port: -1 })).toThrow(
|
|
4689
4687
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
4690
4688
|
)
|
|
4691
|
-
expect(() => createApplicationServer({ timeout: 0 })).
|
|
4689
|
+
expect(() => createApplicationServer({ timeout: 0 })).toThrow(
|
|
4692
4690
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
4693
4691
|
)
|
|
4694
4692
|
for (const value of [null, 42, [], { host: 42 }, { port: [42] }]) {
|
|
4695
|
-
expect(() => Reflect.apply(createApplicationServer, undefined, [value])).
|
|
4693
|
+
expect(() => Reflect.apply(createApplicationServer, undefined, [value])).toThrow(
|
|
4696
4694
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
4697
4695
|
)
|
|
4698
4696
|
}
|
|
@@ -4712,14 +4710,10 @@ describe('ApplicationServer', () => {
|
|
|
4712
4710
|
expect(server.port).toBe(0)
|
|
4713
4711
|
|
|
4714
4712
|
process.env.APP_PORT = '1e3'
|
|
4715
|
-
expect(() => createApplicationServer()).
|
|
4716
|
-
expect.objectContaining({ code: 'CONFIG' }),
|
|
4717
|
-
)
|
|
4713
|
+
expect(() => createApplicationServer()).toThrow(expect.objectContaining({ code: 'CONFIG' }))
|
|
4718
4714
|
process.env.APP_PORT = '0'
|
|
4719
4715
|
process.env.APP_START_TIMEOUT = '0'
|
|
4720
|
-
expect(() => createApplicationServer()).
|
|
4721
|
-
expect.objectContaining({ code: 'CONFIG' }),
|
|
4722
|
-
)
|
|
4716
|
+
expect(() => createApplicationServer()).toThrow(expect.objectContaining({ code: 'CONFIG' }))
|
|
4723
4717
|
} finally {
|
|
4724
4718
|
if (previousHost === undefined) delete process.env.APP_HOST
|
|
4725
4719
|
else process.env.APP_HOST = previousHost
|
|
@@ -5088,15 +5082,13 @@ describe('application environment parsers', () => {
|
|
|
5088
5082
|
'999.999.999.999',
|
|
5089
5083
|
\`\${'a'.repeat(64)}.example\`,
|
|
5090
5084
|
])('rejects hostile APP_HOST value %s before listener allocation', (value) => {
|
|
5091
|
-
expect(() => parseApplicationHost(value)).
|
|
5092
|
-
expect.objectContaining({ code: 'CONFIG' }),
|
|
5093
|
-
)
|
|
5085
|
+
expect(() => parseApplicationHost(value)).toThrow(expect.objectContaining({ code: 'CONFIG' }))
|
|
5094
5086
|
})
|
|
5095
5087
|
|
|
5096
5088
|
it.each([null, 42, [], { port: [42] }, { timeout: 0 }])(
|
|
5097
5089
|
'rejects hostile option container or leaf value %#',
|
|
5098
5090
|
(value) => {
|
|
5099
|
-
expect(() => parseApplicationServerOptions(value)).
|
|
5091
|
+
expect(() => parseApplicationServerOptions(value)).toThrow(
|
|
5100
5092
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
5101
5093
|
)
|
|
5102
5094
|
},
|
|
@@ -5119,7 +5111,7 @@ describe('application environment parsers', () => {
|
|
|
5119
5111
|
])(
|
|
5120
5112
|
'rejects inherited, unknown, symbolic, accessor, instance, and hostile proxy options %#',
|
|
5121
5113
|
(value) => {
|
|
5122
|
-
expect(() => parseApplicationServerOptions(value)).
|
|
5114
|
+
expect(() => parseApplicationServerOptions(value)).toThrow(
|
|
5123
5115
|
expect.objectContaining({ code: 'CONFIG' }),
|
|
5124
5116
|
)
|
|
5125
5117
|
},
|
|
@@ -5630,7 +5622,7 @@ function packageManifest(spec) {
|
|
|
5630
5622
|
}
|
|
5631
5623
|
if (spec.bin) scripts["test:src:bin"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin";
|
|
5632
5624
|
if (spec.integration) scripts["test:integration"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project integration";
|
|
5633
|
-
if (spec.bin && spec.integration) scripts["test:equivalence"] = "node -e \"const c=require('node:child_process'),
|
|
5625
|
+
if (spec.bin && spec.integration) scripts["test:equivalence"] = "node -e \"const c=require('node:child_process'),p=process.env.npm_execpath;if(p===undefined)process.exit(1);const r=c.spawnSync(process.execPath,[p,'run','test:integration'],{stdio:'inherit',env:{...process.env,SCAFFOLD_BOUNDARY_EQUIVALENCE:'1'}});process.exit(r.status??1)\"";
|
|
5634
5626
|
if (spec.service) scripts["test:service"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project service";
|
|
5635
5627
|
if (spec.app.length > 0) {
|
|
5636
5628
|
scripts["test:app"] = "vitest run --config vite.config.ts --no-cache --reporter=dot " + spec.app.map((environment) => `--project ${APP_MATRIX[environment].project}`).join(" ");
|
|
@@ -5724,6 +5716,7 @@ function rootTsconfig(src, app = []) {
|
|
|
5724
5716
|
target: "ESNext",
|
|
5725
5717
|
module: "ESNext",
|
|
5726
5718
|
moduleResolution: "bundler",
|
|
5719
|
+
allowImportingTsExtensions: true,
|
|
5727
5720
|
lib: [
|
|
5728
5721
|
"ESNext",
|
|
5729
5722
|
"DOM",
|
|
@@ -5873,7 +5866,7 @@ ${renderedProjects}
|
|
|
5873
5866
|
${fitsPrintWidth(inlineRegistrations) ? inlineRegistrations : ` [
|
|
5874
5867
|
${renderedRegistrations.map((registration) => ` ${registration},`).join("\n")}
|
|
5875
5868
|
],`}
|
|
5876
|
-
|
|
5869
|
+
browserOptions !== undefined,
|
|
5877
5870
|
process.argv,
|
|
5878
5871
|
),`;
|
|
5879
5872
|
}
|
|
@@ -5897,6 +5890,8 @@ ${renderedRegistrations.map((registration) => ` ${registration},`).join("\n")}
|
|
|
5897
5890
|
*/
|
|
5898
5891
|
function viteHeader(machinery) {
|
|
5899
5892
|
const { browser: needsBrowser, vue: needsVue, output: needsOutput } = machinery;
|
|
5893
|
+
const playwrightTypeImports = needsBrowser ? `import type { PlaywrightProviderOptions } from '@vitest/browser-playwright'
|
|
5894
|
+
` : "";
|
|
5900
5895
|
const playwrightImports = needsBrowser ? `import { playwright } from '@vitest/browser-playwright'
|
|
5901
5896
|
import { chromium } from 'playwright'
|
|
5902
5897
|
` : "";
|
|
@@ -6207,7 +6202,9 @@ import { parse as parseVue } from 'vue/compiler-sfc'
|
|
|
6207
6202
|
? undefined
|
|
6208
6203
|
: packageRootOf(packageName, physicalSource)
|
|
6209
6204
|
if (packageRoot === undefined || !containedPath(packageRoot, physicalSource)) {
|
|
6210
|
-
this.error(
|
|
6205
|
+
return this.error(
|
|
6206
|
+
'Resolved dependencies must remain inside their physical package root',
|
|
6207
|
+
)
|
|
6211
6208
|
}
|
|
6212
6209
|
trustedPackageRoots.add(packageRoot)
|
|
6213
6210
|
}
|
|
@@ -6215,7 +6212,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
|
|
|
6215
6212
|
}
|
|
6216
6213
|
const resolvedSource = workspacePath(physicalSource)
|
|
6217
6214
|
if (resolvedSource === undefined) {
|
|
6218
|
-
this.error('Environment modules cannot import files outside the workspace')
|
|
6215
|
+
return this.error('Environment modules cannot import files outside the workspace')
|
|
6219
6216
|
}
|
|
6220
6217
|
const assetError = environmentPathError(owner, resolvedSource)
|
|
6221
6218
|
if (assetError !== undefined) this.error(assetError)
|
|
@@ -7244,7 +7241,7 @@ ${needsVue ? ` configureServer(server) {
|
|
|
7244
7241
|
}
|
|
7245
7242
|
}
|
|
7246
7243
|
`;
|
|
7247
|
-
return `${viteTypeImports}
|
|
7244
|
+
return `${playwrightTypeImports}${viteTypeImports}
|
|
7248
7245
|
${needsBrowser ? `import { isCSSRequest, parseSync, preprocessCSS, transformWithOxc, Visitor } from 'vite'
|
|
7249
7246
|
` : `import { parseSync, transformWithOxc, Visitor } from 'vite'
|
|
7250
7247
|
`}import { defineConfig, mergeConfig } from 'vitest/config'
|
|
@@ -7252,7 +7249,7 @@ import tsconfig from './tsconfig.json' with { type: 'json' }
|
|
|
7252
7249
|
import { fileURLToPath, URL } from 'node:url'
|
|
7253
7250
|
import { isBuiltin } from 'node:module'
|
|
7254
7251
|
import {
|
|
7255
|
-
closeSync,
|
|
7252
|
+
${needsBrowser ? " accessSync,\n" : ""} closeSync,
|
|
7256
7253
|
constants as FS_CONSTANTS,
|
|
7257
7254
|
existsSync,
|
|
7258
7255
|
fstatSync,
|
|
@@ -7261,7 +7258,15 @@ import {
|
|
|
7261
7258
|
${needsBrowser ? " readdirSync,\n" : ""} readSync,
|
|
7262
7259
|
realpathSync,
|
|
7263
7260
|
${needsBrowser ? " statSync,\n" : ""}} from 'node:fs'
|
|
7264
|
-
|
|
7261
|
+
${needsBrowser ? `import {
|
|
7262
|
+
basename,
|
|
7263
|
+
join,
|
|
7264
|
+
dirname,
|
|
7265
|
+
isAbsolute,
|
|
7266
|
+
relative,
|
|
7267
|
+
resolve as resolvePath,
|
|
7268
|
+
sep,
|
|
7269
|
+
} from 'node:path'` : `import { dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path'`}
|
|
7265
7270
|
${playwrightImports}${vueImports}${needsBrowser ? `\n/** Chromium executable layouts inside a \`chromium-<revision>\` browsers-directory entry, per platform. */
|
|
7266
7271
|
${EXPORT_KEYWORD} ${CONST_KEYWORD} CHROMIUM_LAYOUTS = Object.freeze([
|
|
7267
7272
|
'chrome-linux/chrome',
|
|
@@ -7272,15 +7277,64 @@ ${EXPORT_KEYWORD} ${CONST_KEYWORD} CHROMIUM_LAYOUTS = Object.freeze([
|
|
|
7272
7277
|
'chrome-mac-arm64/Chromium.app/Contents/MacOS/Chromium',
|
|
7273
7278
|
])
|
|
7274
7279
|
|
|
7280
|
+
/** Stable Playwright Chromium channels and their standard executable layouts. */
|
|
7281
|
+
${EXPORT_KEYWORD} ${CONST_KEYWORD} SYSTEM_BROWSER_CHANNELS = Object.freeze([
|
|
7282
|
+
Object.freeze({
|
|
7283
|
+
channel: 'chrome',
|
|
7284
|
+
layouts: Object.freeze({
|
|
7285
|
+
linux: '/opt/google/chrome/chrome',
|
|
7286
|
+
darwin: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
7287
|
+
win32: Object.freeze(['Google', 'Chrome', 'Application', 'chrome.exe']),
|
|
7288
|
+
}),
|
|
7289
|
+
}),
|
|
7290
|
+
Object.freeze({
|
|
7291
|
+
channel: 'msedge',
|
|
7292
|
+
layouts: Object.freeze({
|
|
7293
|
+
linux: '/opt/microsoft/msedge/msedge',
|
|
7294
|
+
darwin: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
7295
|
+
win32: Object.freeze(['Microsoft', 'Edge', 'Application', 'msedge.exe']),
|
|
7296
|
+
}),
|
|
7297
|
+
}),
|
|
7298
|
+
])
|
|
7299
|
+
|
|
7300
|
+
/**
|
|
7301
|
+
* Determine whether a path identifies an executable regular file.
|
|
7302
|
+
*
|
|
7303
|
+
* @param path - The filesystem path to inspect.
|
|
7304
|
+
* @returns Whether the path is a regular file with execute access.
|
|
7305
|
+
*
|
|
7306
|
+
* @example
|
|
7307
|
+
* \`\`\`ts
|
|
7308
|
+
* isBrowserExecutable('/opt/google/chrome/chrome')
|
|
7309
|
+
* \`\`\`
|
|
7310
|
+
*/
|
|
7311
|
+
${EXPORT_KEYWORD} function isBrowserExecutable(path: string): boolean {
|
|
7312
|
+
try {
|
|
7313
|
+
if (!statSync(path).isFile()) return false
|
|
7314
|
+
accessSync(path, FS_CONSTANTS.X_OK)
|
|
7315
|
+
return true
|
|
7316
|
+
} catch {
|
|
7317
|
+
return false
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
|
|
7275
7321
|
/**
|
|
7276
|
-
* Resolve a launchable Chromium executable: the pinned revision when installed,
|
|
7322
|
+
* Resolve a launchable Playwright-managed Chromium executable: the pinned revision when installed,
|
|
7277
7323
|
* otherwise a \`chromium\` / \`chromium.exe\` alias or any other \`chromium-*\`
|
|
7278
7324
|
* revision under the same Playwright browsers directory. A pinned-revision miss
|
|
7279
7325
|
* is not Chromium absence — managed containers ship one usable build (often
|
|
7280
7326
|
* behind a revision-agnostic alias) for many Playwright versions.
|
|
7327
|
+
*
|
|
7328
|
+
* @param pinned - The executable path for Playwright's pinned Chromium revision.
|
|
7329
|
+
* @returns The managed executable path, or \`undefined\` when none is executable.
|
|
7330
|
+
*
|
|
7331
|
+
* @example
|
|
7332
|
+
* \`\`\`ts
|
|
7333
|
+
* resolveManagedBrowser(chromium.executablePath())
|
|
7334
|
+
* \`\`\`
|
|
7281
7335
|
*/
|
|
7282
|
-
${EXPORT_KEYWORD} function
|
|
7283
|
-
if (
|
|
7336
|
+
${EXPORT_KEYWORD} function resolveManagedBrowser(pinned: string): string | undefined {
|
|
7337
|
+
if (isBrowserExecutable(pinned)) return pinned
|
|
7284
7338
|
let revisionRoot = dirname(pinned)
|
|
7285
7339
|
for (;;) {
|
|
7286
7340
|
if (/^chromium-\\d+$/.test(basename(revisionRoot))) break
|
|
@@ -7291,7 +7345,7 @@ ${EXPORT_KEYWORD} function resolveChromium(pinned: string): string | undefined {
|
|
|
7291
7345
|
const browsersRoot = dirname(revisionRoot)
|
|
7292
7346
|
for (const alias of ['chromium', 'chromium.exe']) {
|
|
7293
7347
|
const candidate = resolvePath(browsersRoot, alias)
|
|
7294
|
-
if (
|
|
7348
|
+
if (isBrowserExecutable(candidate)) return candidate
|
|
7295
7349
|
}
|
|
7296
7350
|
let entries: readonly string[]
|
|
7297
7351
|
try {
|
|
@@ -7305,18 +7359,89 @@ ${EXPORT_KEYWORD} function resolveChromium(pinned: string): string | undefined {
|
|
|
7305
7359
|
for (const revision of revisions) {
|
|
7306
7360
|
for (const layout of CHROMIUM_LAYOUTS) {
|
|
7307
7361
|
const candidate = resolvePath(browsersRoot, revision, layout)
|
|
7308
|
-
if (
|
|
7362
|
+
if (isBrowserExecutable(candidate)) return candidate
|
|
7309
7363
|
}
|
|
7310
7364
|
}
|
|
7311
7365
|
return undefined
|
|
7312
7366
|
}
|
|
7313
7367
|
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7368
|
+
/**
|
|
7369
|
+
* Resolve the first installed stable system Chromium channel.
|
|
7370
|
+
*
|
|
7371
|
+
* @param platform - The Node platform whose standard layouts should be probed.
|
|
7372
|
+
* @param environment - The process environment supplying Windows installation roots.
|
|
7373
|
+
* @returns \`chrome\`, then \`msedge\`, or \`undefined\` when neither is executable.
|
|
7374
|
+
*
|
|
7375
|
+
* @example
|
|
7376
|
+
* \`\`\`ts
|
|
7377
|
+
* resolveSystemBrowser(process.platform, process.env)
|
|
7378
|
+
* \`\`\`
|
|
7379
|
+
*/
|
|
7380
|
+
${EXPORT_KEYWORD} function resolveSystemBrowser(
|
|
7381
|
+
platform: NodeJS.Platform,
|
|
7382
|
+
environment: NodeJS.ProcessEnv,
|
|
7383
|
+
): string | undefined {
|
|
7384
|
+
if (platform !== 'linux' && platform !== 'darwin' && platform !== 'win32') return undefined
|
|
7385
|
+
const roots = new Set<string>()
|
|
7386
|
+
if (platform === 'win32') {
|
|
7387
|
+
for (const root of [
|
|
7388
|
+
environment.LOCALAPPDATA,
|
|
7389
|
+
environment.PROGRAMFILES,
|
|
7390
|
+
environment['PROGRAMFILES(X86)'],
|
|
7391
|
+
]) {
|
|
7392
|
+
if (root !== undefined && root.length > 0) roots.add(root)
|
|
7393
|
+
}
|
|
7394
|
+
const homeDrive = environment.HOMEDRIVE
|
|
7395
|
+
if (homeDrive !== undefined && homeDrive.length > 0) {
|
|
7396
|
+
roots.add(join(homeDrive, 'Program Files'))
|
|
7397
|
+
roots.add(join(homeDrive, 'Program Files (x86)'))
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
for (const browser of SYSTEM_BROWSER_CHANNELS) {
|
|
7401
|
+
if (platform === 'win32') {
|
|
7402
|
+
for (const root of roots) {
|
|
7403
|
+
if (isBrowserExecutable(join(root, ...browser.layouts.win32))) return browser.channel
|
|
7404
|
+
}
|
|
7405
|
+
continue
|
|
7406
|
+
}
|
|
7407
|
+
if (isBrowserExecutable(browser.layouts[platform])) return browser.channel
|
|
7408
|
+
}
|
|
7409
|
+
return undefined
|
|
7410
|
+
}
|
|
7411
|
+
|
|
7412
|
+
/**
|
|
7413
|
+
* Resolve launch options for a managed Chromium or stable system browser.
|
|
7414
|
+
*
|
|
7415
|
+
* @param pinned - The executable path for Playwright's pinned Chromium revision.
|
|
7416
|
+
* @param platform - The Node platform whose standard system layouts should be probed.
|
|
7417
|
+
* @param environment - The process environment supplying Windows installation roots.
|
|
7418
|
+
* @returns Provider options for managed Chromium, Chrome, or Edge, or \`undefined\`.
|
|
7419
|
+
*
|
|
7420
|
+
* @remarks
|
|
7421
|
+
* An installed pinned revision returns an empty object so Playwright retains
|
|
7422
|
+
* its default launch semantics. A different managed executable is selected by
|
|
7423
|
+
* path; a system browser is selected by its stable Playwright channel.
|
|
7424
|
+
*
|
|
7425
|
+
* @example
|
|
7426
|
+
* \`\`\`ts
|
|
7427
|
+
* resolveBrowser(chromium.executablePath(), process.platform, process.env)
|
|
7428
|
+
* \`\`\`
|
|
7429
|
+
*/
|
|
7430
|
+
${EXPORT_KEYWORD} function resolveBrowser(
|
|
7431
|
+
pinned: string,
|
|
7432
|
+
platform: NodeJS.Platform,
|
|
7433
|
+
environment: NodeJS.ProcessEnv,
|
|
7434
|
+
): PlaywrightProviderOptions | undefined {
|
|
7435
|
+
const managed = resolveManagedBrowser(pinned)
|
|
7436
|
+
if (managed !== undefined) {
|
|
7437
|
+
return managed === pinned ? {} : { launchOptions: { executablePath: managed } }
|
|
7438
|
+
}
|
|
7439
|
+
const channel = resolveSystemBrowser(platform, environment)
|
|
7440
|
+
return channel === undefined ? undefined : { launchOptions: { channel } }
|
|
7441
|
+
}
|
|
7442
|
+
|
|
7443
|
+
${CONST_KEYWORD} browserPinned = chromium.executablePath()
|
|
7444
|
+
${CONST_KEYWORD} browserOptions = resolveBrowser(browserPinned, process.platform, process.env)
|
|
7320
7445
|
` : ""}
|
|
7321
7446
|
${EXPORT_KEYWORD} function resolveWorkspacePath(relativePath: string): string {
|
|
7322
7447
|
return fileURLToPath(new URL(relativePath, import.meta.url))
|
|
@@ -7365,7 +7490,9 @@ ${needsBrowser ? `${EXPORT_KEYWORD} function gateBrowserProjects(
|
|
|
7365
7490
|
projects.push(registration.project())
|
|
7366
7491
|
}
|
|
7367
7492
|
if (gated.length === 0) return { projects }
|
|
7368
|
-
console.warn(
|
|
7493
|
+
console.warn(
|
|
7494
|
+
\`browser projects skipped: no Playwright Chromium, Chrome, or Edge found (\${gated.join(', ')})\`,
|
|
7495
|
+
)
|
|
7369
7496
|
const filters: string[] = []
|
|
7370
7497
|
let readable = true
|
|
7371
7498
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -7656,7 +7783,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
|
|
|
7656
7783
|
}),
|
|
7657
7784
|
browser: {
|
|
7658
7785
|
enabled: true,
|
|
7659
|
-
provider: playwright(
|
|
7786
|
+
provider: playwright(browserOptions),
|
|
7660
7787
|
instances: [{ browser: 'chromium', headless: true }],
|
|
7661
7788
|
},
|
|
7662
7789
|
fileParallelism: false,
|
|
@@ -7690,6 +7817,7 @@ ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
|
|
|
7690
7817
|
outDir: 'dist/src/server',
|
|
7691
7818
|
target: 'node22',
|
|
7692
7819
|
rolldownOptions: {
|
|
7820
|
+
platform: 'node',
|
|
7693
7821
|
external: (id: string) => id.startsWith('node:') || id.startsWith('@orkestrel/'),
|
|
7694
7822
|
},
|
|
7695
7823
|
},
|
|
@@ -7788,7 +7916,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
|
|
|
7788
7916
|
}),
|
|
7789
7917
|
browser: {
|
|
7790
7918
|
enabled: true,
|
|
7791
|
-
provider: playwright(
|
|
7919
|
+
provider: playwright(browserOptions),
|
|
7792
7920
|
instances: [{ browser: 'chromium', headless: true }],
|
|
7793
7921
|
},
|
|
7794
7922
|
fileParallelism: false,
|
|
@@ -7813,6 +7941,7 @@ ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
|
|
|
7813
7941
|
outDir: 'dist/src/server',
|
|
7814
7942
|
target: 'node22',
|
|
7815
7943
|
rolldownOptions: {
|
|
7944
|
+
platform: 'node',
|
|
7816
7945
|
external: (id: string) =>
|
|
7817
7946
|
id === '@src/core' || id.startsWith('node:') || id.startsWith('@orkestrel/'),
|
|
7818
7947
|
output: [
|
|
@@ -7953,7 +8082,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
|
|
|
7953
8082
|
}),
|
|
7954
8083
|
browser: {
|
|
7955
8084
|
enabled: true,
|
|
7956
|
-
provider: playwright(
|
|
8085
|
+
provider: playwright(browserOptions),
|
|
7957
8086
|
instances: [{ browser: 'chromium', headless: true }],
|
|
7958
8087
|
},
|
|
7959
8088
|
fileParallelism: false,
|
|
@@ -7997,6 +8126,7 @@ ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
|
|
|
7997
8126
|
outDir: 'dist/src/server',
|
|
7998
8127
|
target: 'node22',
|
|
7999
8128
|
rolldownOptions: {
|
|
8129
|
+
platform: 'node',
|
|
8000
8130
|
external: (id: string) =>
|
|
8001
8131
|
${coreExternal}id.startsWith('node:') || id.startsWith('@orkestrel/'),${coreOutput}
|
|
8002
8132
|
},
|
|
@@ -8082,7 +8212,7 @@ ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
|
|
|
8082
8212
|
},
|
|
8083
8213
|
browser: {
|
|
8084
8214
|
enabled: true,
|
|
8085
|
-
provider: playwright(
|
|
8215
|
+
provider: playwright(browserOptions),
|
|
8086
8216
|
instances: [{ browser: 'chromium', headless: true }],
|
|
8087
8217
|
},
|
|
8088
8218
|
fileParallelism: false,
|
|
@@ -8175,7 +8305,7 @@ import {
|
|
|
8175
8305
|
outputBoundary,
|
|
8176
8306
|
srcCore,
|
|
8177
8307
|
resolveWorkspacePath,
|
|
8178
|
-
} from '../../vite.config'
|
|
8308
|
+
} from '../../vite.config.ts'
|
|
8179
8309
|
|
|
8180
8310
|
export default defineConfig(
|
|
8181
8311
|
srcCore({
|
|
@@ -8260,7 +8390,7 @@ function srcViteConfig(environment) {
|
|
|
8260
8390
|
const anchor = environment === "browser" ? "srcBrowser" : "srcServer";
|
|
8261
8391
|
return `import { defineConfig } from 'vite'
|
|
8262
8392
|
import dts from 'vite-plugin-dts'
|
|
8263
|
-
import { ${anchor}, resolveWorkspacePath } from '../../vite.config'
|
|
8393
|
+
import { ${anchor}, resolveWorkspacePath } from '../../vite.config.ts'
|
|
8264
8394
|
|
|
8265
8395
|
// Types are bundled inline by vite-plugin-dts (see configs/src/vite.core.config.ts
|
|
8266
8396
|
// for the same pattern).
|
|
@@ -8313,7 +8443,7 @@ function binTsconfig() {
|
|
|
8313
8443
|
*/
|
|
8314
8444
|
function binViteConfig() {
|
|
8315
8445
|
return `import { defineConfig } from 'vite'
|
|
8316
|
-
import { srcBin } from '../../vite.config'
|
|
8446
|
+
import { srcBin } from '../../vite.config.ts'
|
|
8317
8447
|
|
|
8318
8448
|
// The \`scaffold\` executable build — a single ESM lib file, no declarations (an
|
|
8319
8449
|
// executable ships no types), with the \`#!/usr/bin/env node\` shebang re-emitted via
|
|
@@ -8380,7 +8510,7 @@ function appTsconfig(environment, hasCore) {
|
|
|
8380
8510
|
function appViteConfig(environment) {
|
|
8381
8511
|
const anchor = environment === "browser" ? "appBrowser" : "appServer";
|
|
8382
8512
|
return `import { defineConfig } from 'vite'
|
|
8383
|
-
import { ${anchor} } from '../../vite.config'
|
|
8513
|
+
import { ${anchor} } from '../../vite.config.ts'
|
|
8384
8514
|
|
|
8385
8515
|
export default defineConfig(${anchor}())
|
|
8386
8516
|
`;
|
|
@@ -8649,8 +8779,7 @@ function paritySpecifiers(spec) {
|
|
|
8649
8779
|
function testArtifacts(spec, pascal) {
|
|
8650
8780
|
const hasBrowser = spec.src.includes("browser") || spec.app.includes("browser");
|
|
8651
8781
|
const hasVue = spec.app.includes("browser");
|
|
8652
|
-
const
|
|
8653
|
-
const browserPolicyImport = hasBrowser ? "\nimport { chromium } from 'playwright'\nimport { resolveChromium } from '../vite.config.js'" : "";
|
|
8782
|
+
const browserPolicyImport = hasBrowser ? "\nimport { chromium } from 'playwright'\nimport { isBrowserExecutable, resolveBrowser, SYSTEM_BROWSER_CHANNELS } from '../vite.config.js'" : "";
|
|
8654
8783
|
const vuePolicyImport = hasVue ? "\nimport { parse as parseVue } from 'vue/compiler-sfc'" : "";
|
|
8655
8784
|
const workspacePolicyAssertion = hasVue ? `expect(
|
|
8656
8785
|
inspectCodingWorkspace(process.cwd(), (path, content) => {
|
|
@@ -8663,15 +8792,20 @@ function testArtifacts(spec, pascal) {
|
|
|
8663
8792
|
).toEqual([])` : "expect(inspectCodingWorkspace(process.cwd())).toEqual([])";
|
|
8664
8793
|
const browserPolicyTest = hasBrowser ? `
|
|
8665
8794
|
|
|
8666
|
-
it('resolves
|
|
8667
|
-
const
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8795
|
+
it('resolves only a real managed executable or stable system browser channel', () => {
|
|
8796
|
+
const options = resolveBrowser(chromium.executablePath(), process.platform, process.env)
|
|
8797
|
+
let valid = options === undefined
|
|
8798
|
+
if (options !== undefined) {
|
|
8799
|
+
const channel = options.launchOptions?.channel
|
|
8800
|
+
valid =
|
|
8801
|
+
channel === undefined
|
|
8802
|
+
? isBrowserExecutable(options.launchOptions?.executablePath ?? chromium.executablePath())
|
|
8803
|
+
: SYSTEM_BROWSER_CHANNELS.some((browser) => browser.channel === channel)
|
|
8804
|
+
}
|
|
8805
|
+
expect(valid).toBe(true)
|
|
8672
8806
|
})` : "";
|
|
8673
8807
|
const artifacts = [fillArtifact("tests/setup.ts", "tests", "setup", {}), fillArtifact("tests/policy.test.ts", "tests", "policyTest", {
|
|
8674
|
-
browserPolicySpecifier,
|
|
8808
|
+
browserPolicySpecifier: "",
|
|
8675
8809
|
browserPolicyImport,
|
|
8676
8810
|
browserPolicyTest,
|
|
8677
8811
|
vuePolicyImport,
|