@open-mercato/cli 0.6.8-develop.7099.1.7ba2771d06 → 0.7.0
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/.turbo/turbo-build.log +1 -7
- package/dist/agentic/guides/module-facts.json +598 -5508
- package/dist/agentic/guides/module-facts.v2.json +598 -5594
- package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/exact-override-targets.md +0 -1
- package/dist/agentic/guides/modules/api_keys/index.md +2 -4
- package/dist/agentic/guides/modules/attachments/di-registrations-rich.md +5 -6
- package/dist/agentic/guides/modules/attachments/di-service-tokens.md +4 -5
- package/dist/agentic/guides/modules/attachments/exact-override-targets.md +5 -6
- package/dist/agentic/guides/modules/attachments/index.md +2 -2
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/di-registrations-rich.md +2 -3
- package/dist/agentic/guides/modules/auth/di-service-tokens.md +2 -3
- package/dist/agentic/guides/modules/auth/exact-override-targets.md +2 -3
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/incoming-installed-contributions.md +0 -3
- package/dist/agentic/guides/modules/catalog/index.md +2 -2
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
- package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
- package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/di-registrations-rich.md +8 -9
- package/dist/agentic/guides/modules/communication_channels/exact-override-targets.md +8 -9
- package/dist/agentic/guides/modules/communication_channels/incoming-installed-contributions.md +0 -2
- package/dist/agentic/guides/modules/communication_channels/index.md +3 -3
- package/dist/agentic/guides/modules/configs/index.md +1 -1
- package/dist/agentic/guides/modules/content/index.md +1 -1
- package/dist/agentic/guides/modules/currencies/index.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
- package/dist/agentic/guides/modules/customers/active-extension-bindings.md +3 -6
- package/dist/agentic/guides/modules/customers/contribution-resolutions.md +0 -1
- package/dist/agentic/guides/modules/customers/events.md +1 -2
- package/dist/agentic/guides/modules/customers/incoming-installed-contributions.md +0 -7
- package/dist/agentic/guides/modules/customers/index.md +4 -4
- package/dist/agentic/guides/modules/customers/umes-contributions.md +0 -1
- package/dist/agentic/guides/modules/customers/umes-hosts.md +0 -1
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/exact-override-targets.md +2 -2
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/workers.md +2 -2
- package/dist/agentic/guides/modules/design_system/index.md +1 -1
- package/dist/agentic/guides/modules/devices/index.md +1 -1
- package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
- package/dist/agentic/guides/modules/directory/exact-override-targets.md +0 -2
- package/dist/agentic/guides/modules/directory/index.md +3 -5
- package/dist/agentic/guides/modules/entities/index.md +1 -1
- package/dist/agentic/guides/modules/eudr/index.md +1 -1
- package/dist/agentic/guides/modules/events/index.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/exact-override-targets.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/workers.md +1 -1
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/index.md +1 -1
- package/dist/agentic/guides/modules/messages/index.md +1 -1
- package/dist/agentic/guides/modules/notifications/index.md +1 -1
- package/dist/agentic/guides/modules/onboarding/index.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
- package/dist/agentic/guides/modules/perspectives/index.md +1 -1
- package/dist/agentic/guides/modules/planner/index.md +1 -1
- package/dist/agentic/guides/modules/portal/index.md +1 -1
- package/dist/agentic/guides/modules/progress/index.md +1 -1
- package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
- package/dist/agentic/guides/modules/query_index/index.md +1 -1
- package/dist/agentic/guides/modules/record_locks/index.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/active-extension-bindings.md +0 -1
- package/dist/agentic/guides/modules/sales/contribution-resolutions.md +0 -1
- package/dist/agentic/guides/modules/sales/exact-override-targets.md +4 -5
- package/dist/agentic/guides/modules/sales/host-extension-points.md +1 -1
- package/dist/agentic/guides/modules/sales/incoming-installed-contributions.md +0 -2
- package/dist/agentic/guides/modules/sales/index.md +3 -3
- package/dist/agentic/guides/modules/sales/setup.md +1 -1
- package/dist/agentic/guides/modules/sales/umes-contributions.md +0 -1
- package/dist/agentic/guides/modules/sales/umes-diagnostics.md +0 -1
- package/dist/agentic/guides/modules/sales/umes-hosts.md +0 -9
- package/dist/agentic/guides/modules/scheduler/cli-commands.md +0 -1
- package/dist/agentic/guides/modules/scheduler/exact-override-targets.md +1 -3
- package/dist/agentic/guides/modules/scheduler/index.md +2 -2
- package/dist/agentic/guides/modules/scheduler/workers.md +1 -2
- package/dist/agentic/guides/modules/search/index.md +1 -1
- package/dist/agentic/guides/modules/security/index.md +1 -1
- package/dist/agentic/guides/modules/security/owned-contract-module-metadata.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
- package/dist/agentic/guides/modules/sso/index.md +1 -1
- package/dist/agentic/guides/modules/staff/index.md +1 -1
- package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
- package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/translations/index.md +1 -1
- package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
- package/dist/agentic/guides/modules/webhooks/index.md +1 -1
- package/dist/agentic/guides/modules/wms/index.md +1 -1
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +2 -2
- package/dist/agentic/guides/reference-modules/example/index.md +1 -1
- package/dist/agentic/guides/upstream/manifest.json +1 -1
- package/dist/agentic/shared/AGENTS.md.template +3 -3
- package/dist/agentic/shared/ai/harness/README.md +2 -2
- package/dist/agentic/shared/ai/harness/RELEASE.md +6 -8
- package/dist/agentic/shared/ai/harness/cases.json +0 -83
- package/dist/agentic/shared/ai/harness/cases.schema.json +4 -4
- package/dist/agentic/shared/ai/harness/validators.json +1 -1
- package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.7-to-0.7.0/SKILL.md +12 -3
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +11 -37
- package/dist/lib/generators/ast/index.js +1 -4
- package/dist/lib/generators/ast/index.js.map +2 -2
- package/dist/lib/generators/ast/source-file.js +1 -8
- package/dist/lib/generators/ast/source-file.js.map +2 -2
- package/dist/lib/generators/ast/writers.js +1 -9
- package/dist/lib/generators/ast/writers.js.map +2 -2
- package/dist/lib/generators/module-registry.js +189 -424
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/route-manifest-shards.js +1 -4
- package/dist/lib/generators/route-manifest-shards.js.map +2 -2
- package/dist/lib/spawn.js +2 -3
- package/dist/lib/spawn.js.map +2 -2
- package/dist/lib/testing/integration.js +24 -162
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +0 -14
- package/dist/mercato.js.map +2 -2
- package/package.json +7 -8
- package/src/lib/__tests__/spawn.test.ts +0 -23
- package/src/lib/generators/__tests__/metadata-extraction.test.ts +0 -44
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +8 -32
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +1 -4
- package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +1 -1
- package/src/lib/generators/__tests__/module-subset.test.ts +72 -96
- package/src/lib/generators/__tests__/output-snapshots.test.ts +1 -1
- package/src/lib/generators/__tests__/route-manifest-shards.test.ts +0 -15
- package/src/lib/generators/__tests__/structural-contracts.test.ts +3 -7
- package/src/lib/generators/ast/index.ts +1 -2
- package/src/lib/generators/ast/source-file.ts +0 -13
- package/src/lib/generators/ast/writers.ts +1 -26
- package/src/lib/generators/module-registry.ts +227 -534
- package/src/lib/generators/route-manifest-shards.ts +1 -8
- package/src/lib/spawn.ts +4 -5
- package/src/lib/testing/__tests__/integration.test.ts +0 -435
- package/src/lib/testing/integration.ts +32 -254
- package/src/mercato.ts +0 -27
- package/dist/agentic/guides/modules/api_keys/di-registrations-rich.md +0 -11
- package/dist/agentic/guides/modules/api_keys/di-service-tokens.md +0 -11
- package/dist/agentic/guides/modules/channel_discord/acl-features.md +0 -13
- package/dist/agentic/guides/modules/channel_discord/ai-agents.md +0 -11
- package/dist/agentic/guides/modules/channel_discord/backend-pages.md +0 -11
- package/dist/agentic/guides/modules/channel_discord/cli-commands.md +0 -13
- package/dist/agentic/guides/modules/channel_discord/contribution-resolutions.md +0 -14
- package/dist/agentic/guides/modules/channel_discord/di-registrations-rich.md +0 -12
- package/dist/agentic/guides/modules/channel_discord/exact-override-targets.md +0 -26
- package/dist/agentic/guides/modules/channel_discord/index.md +0 -22
- package/dist/agentic/guides/modules/channel_discord/owned-contract-module-metadata.md +0 -11
- package/dist/agentic/guides/modules/channel_discord/setup.md +0 -11
- package/dist/agentic/guides/modules/channel_discord/umes-contributions.md +0 -14
- package/dist/agentic/guides/modules/channel_discord/workers.md +0 -12
- package/dist/agentic/guides/modules/directory/di-registrations-rich.md +0 -12
- package/dist/agentic/guides/modules/directory/di-service-tokens.md +0 -12
- package/dist/agentic/guides/modules/documents/acl-features.md +0 -17
- package/dist/agentic/guides/modules/documents/backend-pages.md +0 -13
- package/dist/agentic/guides/modules/documents/contribution-resolutions.md +0 -27
- package/dist/agentic/guides/modules/documents/di-registrations-rich.md +0 -21
- package/dist/agentic/guides/modules/documents/domain-commands.md +0 -37
- package/dist/agentic/guides/modules/documents/encryption.md +0 -11
- package/dist/agentic/guides/modules/documents/entities.md +0 -21
- package/dist/agentic/guides/modules/documents/events.md +0 -25
- package/dist/agentic/guides/modules/documents/exact-override-targets.md +0 -39
- package/dist/agentic/guides/modules/documents/index.md +0 -25
- package/dist/agentic/guides/modules/documents/notifications.md +0 -13
- package/dist/agentic/guides/modules/documents/owned-contract-module-metadata.md +0 -11
- package/dist/agentic/guides/modules/documents/setup.md +0 -11
- package/dist/agentic/guides/modules/documents/umes-contributions.md +0 -27
- package/dist/agentic/guides/modules/documents/umes-hosts.md +0 -36
- package/src/__tests__/resolve-queue-abandon-hook.test.ts +0 -39
- package/src/lib/generators/__tests__/__snapshots__/bootstrap-registrations.test.ts.snap +0 -14
- package/src/lib/generators/__tests__/__snapshots__/command-loaders.test.ts.snap +0 -23
- package/src/lib/generators/__tests__/ast-writers-escaping.test.ts +0 -64
- package/src/lib/generators/__tests__/bootstrap-registrations.test.ts +0 -176
- package/src/lib/generators/__tests__/command-loaders.test.ts +0 -239
- package/src/lib/generators/__tests__/generated-registry-imports.test.ts +0 -128
- package/src/lib/generators/__tests__/registry-variant-parity.test.ts +0 -258
|
@@ -15,13 +15,10 @@ function getRouteManifestShardKey(kind, pathname) {
|
|
|
15
15
|
}
|
|
16
16
|
return firstSegment.toLowerCase();
|
|
17
17
|
}
|
|
18
|
-
function indentDeclaration(declaration) {
|
|
19
|
-
return declaration.split("\n").map((line) => line.length > 0 ? ` ${line}` : line).join("\n");
|
|
20
|
-
}
|
|
21
18
|
function renderArray(entries) {
|
|
22
19
|
if (entries.length === 0) return "[]";
|
|
23
20
|
return `[
|
|
24
|
-
${entries.map((entry) =>
|
|
21
|
+
${entries.map((entry) => ` ${entry.declaration}`).join(",\n")}
|
|
25
22
|
]`;
|
|
26
23
|
}
|
|
27
24
|
function uniqueImports(entries) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/generators/route-manifest-shards.ts"],
|
|
4
|
-
"sourcesContent": ["export type RouteManifestShardKind = 'api' | 'backend'\n\nexport type RouteManifestShardEntry = {\n path: string\n declaration: string\n imports?: string[]\n}\n\nexport type RouteManifestShardOutput = {\n fileName: string\n content: string\n}\n\ntype IndexedRouteManifestShardEntry = RouteManifestShardEntry & {\n order: number\n}\n\nconst DYNAMIC_SHARD_KEY = '__dynamic'\nconst ROOT_SHARD_KEY = '__root'\n\nfunction normalizeRoutePath(kind: RouteManifestShardKind, pathname: string): string[] {\n const segments = pathname.split('?')[0].split('/').filter(Boolean)\n if (kind === 'backend' && segments[0]?.toLowerCase() === 'backend') {\n segments.shift()\n }\n return segments\n}\n\nexport function getRouteManifestShardKey(kind: RouteManifestShardKind, pathname: string): string {\n const firstSegment = normalizeRoutePath(kind, pathname)[0]\n if (!firstSegment) return ROOT_SHARD_KEY\n if (\n firstSegment.startsWith('[')\n || firstSegment.startsWith(':')\n || firstSegment === '*'\n ) {\n return DYNAMIC_SHARD_KEY\n }\n return firstSegment.toLowerCase()\n}\n\nfunction
|
|
5
|
-
"mappings": "AAiBA,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAEvB,SAAS,mBAAmB,MAA8B,UAA4B;AACpF,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AACjE,MAAI,SAAS,aAAa,SAAS,CAAC,GAAG,YAAY,MAAM,WAAW;AAClE,aAAS,MAAM;AAAA,EACjB;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,MAA8B,UAA0B;AAC/F,QAAM,eAAe,mBAAmB,MAAM,QAAQ,EAAE,CAAC;AACzD,MAAI,CAAC,aAAc,QAAO;AAC1B,MACE,aAAa,WAAW,GAAG,KACxB,aAAa,WAAW,GAAG,KAC3B,iBAAiB,KACpB;AACA,WAAO;AAAA,EACT;AACA,SAAO,aAAa,YAAY;AAClC;AAEA,SAAS,
|
|
4
|
+
"sourcesContent": ["export type RouteManifestShardKind = 'api' | 'backend'\n\nexport type RouteManifestShardEntry = {\n path: string\n declaration: string\n imports?: string[]\n}\n\nexport type RouteManifestShardOutput = {\n fileName: string\n content: string\n}\n\ntype IndexedRouteManifestShardEntry = RouteManifestShardEntry & {\n order: number\n}\n\nconst DYNAMIC_SHARD_KEY = '__dynamic'\nconst ROOT_SHARD_KEY = '__root'\n\nfunction normalizeRoutePath(kind: RouteManifestShardKind, pathname: string): string[] {\n const segments = pathname.split('?')[0].split('/').filter(Boolean)\n if (kind === 'backend' && segments[0]?.toLowerCase() === 'backend') {\n segments.shift()\n }\n return segments\n}\n\nexport function getRouteManifestShardKey(kind: RouteManifestShardKind, pathname: string): string {\n const firstSegment = normalizeRoutePath(kind, pathname)[0]\n if (!firstSegment) return ROOT_SHARD_KEY\n if (\n firstSegment.startsWith('[')\n || firstSegment.startsWith(':')\n || firstSegment === '*'\n ) {\n return DYNAMIC_SHARD_KEY\n }\n return firstSegment.toLowerCase()\n}\n\nfunction renderArray(entries: RouteManifestShardEntry[]): string {\n if (entries.length === 0) return '[]'\n return `[\\n${entries.map((entry) => ` ${entry.declaration}`).join(',\\n')}\\n]`\n}\n\nfunction uniqueImports(entries: RouteManifestShardEntry[]): string[] {\n return Array.from(new Set(entries.flatMap((entry) => entry.imports ?? [])))\n}\n\nfunction shardStem(kind: RouteManifestShardKind, index: number, key: string): string {\n const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, '_')\n return `${kind}-route-shard.${String(index).padStart(3, '0')}.${safeKey}.generated`\n}\n\nfunction renderShardFile(kind: RouteManifestShardKind, entries: IndexedRouteManifestShardEntry[]): string {\n const typeName = kind === 'api' ? 'ApiRouteManifestEntry' : 'BackendRouteManifestEntry'\n const helperImport = kind === 'backend' ? 'resolvePageRouteMetadata, ' : ''\n const imports = uniqueImports(entries)\n return `// AUTO-GENERATED by mercato generate registry (request-scoped route shard)\\nimport { ${helperImport}type ${typeName} } from '@open-mercato/shared/modules/registry'\\n${imports.length ? `${imports.join('\\n')}\\n` : ''}\\nexport const routes: ${typeName}[] = ${renderArray(entries)}\\nexport const routeOrders = [${entries.map((entry) => entry.order).join(', ')}]\\n\\nexport default routes\\n`\n}\n\nfunction renderLoaderFile(\n kind: RouteManifestShardKind,\n shards: Array<{ key: string; stem: string; orders: number[] }>,\n): string {\n const isApi = kind === 'api'\n const typeName = kind === 'api' ? 'ApiRouteManifestEntry' : 'BackendRouteManifestEntry'\n const functionName = kind === 'api' ? 'loadApiRouteManifestShard' : 'loadBackendRouteManifestShard'\n const ordinalFunctionName = isApi ? 'loadApiRouteManifestByOrdinal' : 'loadBackendRouteManifestByOrdinal'\n const facadeExportName = isApi ? 'apiRouteFacades' : 'backendRouteFacades'\n const metadataExportName = isApi ? 'apiRouteMetadata' : 'backendRouteMetadata'\n const metadataFileName = isApi ? 'api-route-metadata.generated' : 'backend-route-metadata.generated'\n const shardCases = shards\n .map(({ key, stem }) => ` case ${JSON.stringify(key)}:\\n return import('./${stem}').then((entry) => ({ routes: entry.routes, routeOrders: entry.routeOrders }))`)\n .join('\\n')\n const hasDynamicShard = shards.some(({ key }) => key === DYNAMIC_SHARD_KEY)\n const routeShardKeys: string[] = []\n for (const shard of shards) {\n for (const order of shard.orders) routeShardKeys[order] = shard.key\n }\n const prefixNormalization = kind === 'backend'\n ? ` if (segments[0]?.toLowerCase() === 'backend') segments.shift()\\n`\n : ''\n const loadDynamic = hasDynamicShard\n ? ` const dynamicShard = await loadShard(${JSON.stringify(DYNAMIC_SHARD_KEY)})\\n`\n : ` const dynamicShard: LoadedRouteShard = EMPTY_SHARD\\n`\n\n return `// AUTO-GENERATED by mercato generate registry (request-scoped route loader)\\nimport type { ${typeName} } from '@open-mercato/shared/modules/registry'\\nimport { ${metadataExportName} } from './${metadataFileName}'\\n\\ntype LoadedRouteShard = { routes: ${typeName}[]; routeOrders: number[] }\\nconst EMPTY_SHARD: LoadedRouteShard = { routes: [], routeOrders: [] }\\nconst ROUTE_SHARD_KEYS = ${JSON.stringify(routeShardKeys)}\\n\\nfunction resolveShardKey(pathname: string): string {\\n const segments = pathname.split('?')[0].split('/').filter(Boolean)\\n${prefixNormalization} return segments[0]?.toLowerCase() ?? ${JSON.stringify(ROOT_SHARD_KEY)}\\n}\\n\\nasync function loadShard(key: string): Promise<LoadedRouteShard> {\\n switch (key) {\\n${shardCases ? `${shardCases}\\n` : ''} default:\\n return EMPTY_SHARD\\n }\\n}\\n\\nexport async function ${ordinalFunctionName}(ordinal: number): Promise<${typeName}> {\\n const shardKey = ROUTE_SHARD_KEYS[ordinal]\\n if (shardKey === undefined) throw new Error('Unknown generated route manifest ordinal: ' + ordinal)\\n const shard = await loadShard(shardKey)\\n const index = shard.routeOrders.indexOf(ordinal)\\n if (index < 0 || !shard.routes[index]) throw new Error('Generated route manifest ordinal is missing from its shard: ' + ordinal)\\n return shard.routes[index]\\n}\\n\\nexport const ${facadeExportName}: ${typeName}[] = ${metadataExportName}.map((metadata, ordinal) => ({\\n ...metadata,\\n load: async () => {\\n const route = await ${ordinalFunctionName}(ordinal)\\n return route.load()\\n },\\n}))\\n\\nexport async function ${functionName}(pathname: string): Promise<${typeName}[]> {\\n const exactShard = await loadShard(resolveShardKey(pathname))\\n${loadDynamic} return [\\n ...exactShard.routes.map((route, index) => ({ route, order: exactShard.routeOrders[index] })),\\n ...dynamicShard.routes.map((route, index) => ({ route, order: dynamicShard.routeOrders[index] })),\\n ].sort((a, b) => a.order - b.order).map(({ route }) => route)\\n}\\n`\n}\n\nexport function renderRouteManifestShardOutputs(\n kind: RouteManifestShardKind,\n entries: RouteManifestShardEntry[],\n): RouteManifestShardOutput[] {\n const grouped = new Map<string, IndexedRouteManifestShardEntry[]>()\n for (const [order, entry] of entries.entries()) {\n const key = getRouteManifestShardKey(kind, entry.path)\n const existing = grouped.get(key)\n const indexedEntry = { ...entry, order }\n if (existing) existing.push(indexedEntry)\n else grouped.set(key, [indexedEntry])\n }\n\n const sortedGroups = Array.from(grouped.entries()).sort(([a], [b]) => a.localeCompare(b))\n const shards = sortedGroups.map(([key, shardEntries], index) => {\n const stem = shardStem(kind, index, key)\n return {\n key,\n stem,\n orders: shardEntries.map((entry) => entry.order),\n output: {\n fileName: `${stem}.ts`,\n content: renderShardFile(kind, shardEntries),\n },\n }\n })\n const loaderFileName = kind === 'api'\n ? 'api-route-shards.generated.ts'\n : 'backend-route-shards.generated.ts'\n\n return [\n ...shards.map(({ output }) => output),\n {\n fileName: loaderFileName,\n content: renderLoaderFile(kind, shards),\n },\n ]\n}\n\nexport function renderRouteMetadataOutput(\n kind: RouteManifestShardKind,\n entries: RouteManifestShardEntry[],\n): RouteManifestShardOutput {\n const isApi = kind === 'api'\n const manifestType = isApi ? 'ApiRouteManifestEntry' : 'BackendRouteManifestEntry'\n const metadataType = isApi ? 'ApiRouteMetadataEntry' : 'BackendRouteMetadataEntry'\n const exportName = isApi ? 'apiRouteMetadata' : 'backendRouteMetadata'\n const fileName = isApi ? 'api-route-metadata.generated.ts' : 'backend-route-metadata.generated.ts'\n const helperImport = isApi ? '' : 'resolvePageRouteMetadata, '\n const imports = uniqueImports(entries)\n const content = `// AUTO-GENERATED by mercato generate registry (route metadata without component loaders)\\nimport { ${helperImport}type ${manifestType} } from '@open-mercato/shared/modules/registry'\\n${imports.length ? `${imports.join('\\n')}\\n` : ''}\\nexport type ${metadataType} = Omit<${manifestType}, 'load'>\\n\\nexport const ${exportName}: ${metadataType}[] = ${renderArray(entries)}\\n\\nexport default ${exportName}\\n`\n return { fileName, content }\n}\n\nexport const routeManifestShardFilePattern = /^(?:api|backend)-route-shard\\..+\\.generated\\.(?:ts|checksum)$/\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/lib/spawn.js
CHANGED
|
@@ -21,12 +21,11 @@ function resolveSpawnCommand(command, commandArgs = [], options = {}) {
|
|
|
21
21
|
const platform = options.platform ?? process.platform;
|
|
22
22
|
const safeCommand = assertProcessSafeValue(command, "Process command");
|
|
23
23
|
const safeArgs = commandArgs.map((arg, index) => assertProcessSafeValue(arg, `Process argument #${index + 1}`));
|
|
24
|
-
const detachedSpawnOptions = options.detached ? { detached: true } : {};
|
|
25
24
|
if (!isWindowsCmdScript(safeCommand, platform)) {
|
|
26
25
|
return {
|
|
27
26
|
command: safeCommand,
|
|
28
27
|
args: safeArgs,
|
|
29
|
-
spawnOptions: {
|
|
28
|
+
spawnOptions: {}
|
|
30
29
|
};
|
|
31
30
|
}
|
|
32
31
|
return {
|
|
@@ -34,7 +33,7 @@ function resolveSpawnCommand(command, commandArgs = [], options = {}) {
|
|
|
34
33
|
args: safeArgs.map(
|
|
35
34
|
(arg, index) => assertWindowsCmdSafeValue(arg, `Windows command argument #${index + 1}`)
|
|
36
35
|
),
|
|
37
|
-
spawnOptions: {
|
|
36
|
+
spawnOptions: {}
|
|
38
37
|
};
|
|
39
38
|
}
|
|
40
39
|
export {
|
package/dist/lib/spawn.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/spawn.ts"],
|
|
4
|
-
"sourcesContent": ["export function isWindowsCmdScript(command: string, platform = process.platform): boolean {\n return platform === 'win32' && /\\.(cmd|bat)$/i.test(String(command))\n}\n\nconst PROCESS_VALUE_UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f]/\nconst WINDOWS_CMD_UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f%!]/\n\nfunction assertProcessSafeValue(value: string, label: string): string {\n const stringValue = String(value)\n\n if (PROCESS_VALUE_UNSAFE_CHAR_PATTERN.test(stringValue)) {\n throw new Error(`${label} contains unsupported control characters.`)\n }\n\n return stringValue\n}\n\nfunction assertWindowsCmdSafeValue(value: string, label: string): string {\n const stringValue = assertProcessSafeValue(value, label)\n\n if (WINDOWS_CMD_UNSAFE_CHAR_PATTERN.test(stringValue)) {\n throw new Error(`${label} contains unsupported characters for Windows command execution.`)\n }\n\n return stringValue\n}\n\nexport function resolveSpawnCommand(\n command: string,\n commandArgs: string[] = [],\n options: { platform?: NodeJS.Platform
|
|
5
|
-
"mappings": "AAAO,SAAS,mBAAmB,SAAiB,WAAW,QAAQ,UAAmB;AACxF,SAAO,aAAa,WAAW,gBAAgB,KAAK,OAAO,OAAO,CAAC;AACrE;AAEA,MAAM,oCAAoC;AAC1C,MAAM,kCAAkC;AAExC,SAAS,uBAAuB,OAAe,OAAuB;AACpE,QAAM,cAAc,OAAO,KAAK;AAEhC,MAAI,kCAAkC,KAAK,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,GAAG,KAAK,2CAA2C;AAAA,EACrE;AAEA,SAAO;AACT;AAEA,SAAS,0BAA0B,OAAe,OAAuB;AACvE,QAAM,cAAc,uBAAuB,OAAO,KAAK;AAEvD,MAAI,gCAAgC,KAAK,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,GAAG,KAAK,iEAAiE;AAAA,EAC3F;AAEA,SAAO;AACT;AAEO,SAAS,oBACd,SACA,cAAwB,CAAC,GACzB,
|
|
4
|
+
"sourcesContent": ["export function isWindowsCmdScript(command: string, platform = process.platform): boolean {\n return platform === 'win32' && /\\.(cmd|bat)$/i.test(String(command))\n}\n\nconst PROCESS_VALUE_UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f]/\nconst WINDOWS_CMD_UNSAFE_CHAR_PATTERN = /[\\u0000-\\u001f\\u007f%!]/\n\nfunction assertProcessSafeValue(value: string, label: string): string {\n const stringValue = String(value)\n\n if (PROCESS_VALUE_UNSAFE_CHAR_PATTERN.test(stringValue)) {\n throw new Error(`${label} contains unsupported control characters.`)\n }\n\n return stringValue\n}\n\nfunction assertWindowsCmdSafeValue(value: string, label: string): string {\n const stringValue = assertProcessSafeValue(value, label)\n\n if (WINDOWS_CMD_UNSAFE_CHAR_PATTERN.test(stringValue)) {\n throw new Error(`${label} contains unsupported characters for Windows command execution.`)\n }\n\n return stringValue\n}\n\nexport function resolveSpawnCommand(\n command: string,\n commandArgs: string[] = [],\n options: { platform?: NodeJS.Platform } = {},\n): {\n command: string\n args: string[]\n spawnOptions: { shell?: boolean; windowsVerbatimArguments?: boolean }\n} {\n const platform = options.platform ?? process.platform\n const safeCommand = assertProcessSafeValue(command, 'Process command')\n const safeArgs = commandArgs.map((arg, index) => assertProcessSafeValue(arg, `Process argument #${index + 1}`))\n\n if (!isWindowsCmdScript(safeCommand, platform)) {\n return {\n command: safeCommand,\n args: safeArgs,\n spawnOptions: {},\n }\n }\n\n return {\n command: assertWindowsCmdSafeValue(safeCommand, 'Windows command path'),\n args: safeArgs.map((arg, index) =>\n assertWindowsCmdSafeValue(arg, `Windows command argument #${index + 1}`),\n ),\n spawnOptions: {},\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAO,SAAS,mBAAmB,SAAiB,WAAW,QAAQ,UAAmB;AACxF,SAAO,aAAa,WAAW,gBAAgB,KAAK,OAAO,OAAO,CAAC;AACrE;AAEA,MAAM,oCAAoC;AAC1C,MAAM,kCAAkC;AAExC,SAAS,uBAAuB,OAAe,OAAuB;AACpE,QAAM,cAAc,OAAO,KAAK;AAEhC,MAAI,kCAAkC,KAAK,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,GAAG,KAAK,2CAA2C;AAAA,EACrE;AAEA,SAAO;AACT;AAEA,SAAS,0BAA0B,OAAe,OAAuB;AACvE,QAAM,cAAc,uBAAuB,OAAO,KAAK;AAEvD,MAAI,gCAAgC,KAAK,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,GAAG,KAAK,iEAAiE;AAAA,EAC3F;AAEA,SAAO;AACT;AAEO,SAAS,oBACd,SACA,cAAwB,CAAC,GACzB,UAA0C,CAAC,GAK3C;AACA,QAAM,WAAW,QAAQ,YAAY,QAAQ;AAC7C,QAAM,cAAc,uBAAuB,SAAS,iBAAiB;AACrE,QAAM,WAAW,YAAY,IAAI,CAAC,KAAK,UAAU,uBAAuB,KAAK,qBAAqB,QAAQ,CAAC,EAAE,CAAC;AAE9G,MAAI,CAAC,mBAAmB,aAAa,QAAQ,GAAG;AAC9C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,MACN,cAAc,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,0BAA0B,aAAa,sBAAsB;AAAA,IACtE,MAAM,SAAS;AAAA,MAAI,CAAC,KAAK,UACvB,0BAA0B,KAAK,6BAA6B,QAAQ,CAAC,EAAE;AAAA,IACzE;AAAA,IACA,cAAc,CAAC;AAAA,EACjB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
1
|
import { createServer } from "node:net";
|
|
3
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
3
|
import { mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -453,31 +452,9 @@ function runNpxCommand(args, environment) {
|
|
|
453
452
|
});
|
|
454
453
|
});
|
|
455
454
|
}
|
|
456
|
-
const CAPTURED_OUTPUT_MAX_LENGTH = 64 * 1024;
|
|
457
|
-
function createBoundedOutputBuffer() {
|
|
458
|
-
let buffered = "";
|
|
459
|
-
return {
|
|
460
|
-
append: (chunk) => {
|
|
461
|
-
buffered += chunk.toString();
|
|
462
|
-
if (buffered.length > CAPTURED_OUTPUT_MAX_LENGTH) {
|
|
463
|
-
buffered = `\u2026(truncated)\u2026${buffered.slice(-CAPTURED_OUTPUT_MAX_LENGTH)}`;
|
|
464
|
-
}
|
|
465
|
-
},
|
|
466
|
-
read: () => buffered
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
function formatCapturedOutput(stderrText, stdoutText) {
|
|
470
|
-
if (stderrText && stdoutText) {
|
|
471
|
-
return `--- stderr ---
|
|
472
|
-
${stderrText}
|
|
473
|
-
--- stdout ---
|
|
474
|
-
${stdoutText}`;
|
|
475
|
-
}
|
|
476
|
-
return stderrText || stdoutText;
|
|
477
|
-
}
|
|
478
455
|
function startYarnRawCommand(commandArgs, environment, opts = {}, cwd = projectRootDirectory) {
|
|
479
456
|
const outputMode = opts.silent ? ["ignore", "pipe", "pipe"] : "inherit";
|
|
480
|
-
const resolvedSpawn = resolveSpawnCommand(resolveYarnBinary(), commandArgs
|
|
457
|
+
const resolvedSpawn = resolveSpawnCommand(resolveYarnBinary(), commandArgs);
|
|
481
458
|
const processHandle = spawn(resolvedSpawn.command, resolvedSpawn.args, {
|
|
482
459
|
cwd,
|
|
483
460
|
env: environment,
|
|
@@ -485,11 +462,10 @@ function startYarnRawCommand(commandArgs, environment, opts = {}, cwd = projectR
|
|
|
485
462
|
...resolvedSpawn.spawnOptions
|
|
486
463
|
});
|
|
487
464
|
if (opts.silent) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
processHandle.
|
|
491
|
-
|
|
492
|
-
processHandle.readCapturedOutput = () => formatCapturedOutput(stderrBuffer.read().trim(), stdoutBuffer.read().trim());
|
|
465
|
+
processHandle.stdout?.on("data", () => {
|
|
466
|
+
});
|
|
467
|
+
processHandle.stderr?.on("data", () => {
|
|
468
|
+
});
|
|
493
469
|
}
|
|
494
470
|
return processHandle;
|
|
495
471
|
}
|
|
@@ -1329,97 +1305,6 @@ function isProcessRunning(processId) {
|
|
|
1329
1305
|
return error.code !== "ESRCH";
|
|
1330
1306
|
}
|
|
1331
1307
|
}
|
|
1332
|
-
function defaultKillPosixProcessGroup(pid, signal) {
|
|
1333
|
-
process.kill(-pid, signal);
|
|
1334
|
-
}
|
|
1335
|
-
function defaultKillWindowsProcessTree(pid, options) {
|
|
1336
|
-
spawnSync("taskkill", ["/pid", String(pid), "/t", ...options.forced ? ["/f"] : []]);
|
|
1337
|
-
}
|
|
1338
|
-
function killProcessTree(pid, signal, dependencies = {}) {
|
|
1339
|
-
const platform = dependencies.platform ?? process.platform;
|
|
1340
|
-
if (platform === "win32") {
|
|
1341
|
-
const killWindowsProcessTree = dependencies.killWindowsProcessTree ?? defaultKillWindowsProcessTree;
|
|
1342
|
-
killWindowsProcessTree(pid, { forced: signal === "SIGKILL" });
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
const killPosixProcessGroup = dependencies.killPosixProcessGroup ?? defaultKillPosixProcessGroup;
|
|
1346
|
-
killPosixProcessGroup(pid, signal);
|
|
1347
|
-
}
|
|
1348
|
-
const PROCESS_TREE_KILL_GRACE_PERIOD_MS = 3e3;
|
|
1349
|
-
function killProcessTreeIfRunning(pid, signal, dependencies) {
|
|
1350
|
-
try {
|
|
1351
|
-
killProcessTree(pid, signal, dependencies);
|
|
1352
|
-
} catch (error) {
|
|
1353
|
-
if (error.code !== "ESRCH") {
|
|
1354
|
-
throw error;
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
function waitForProcessExitWithin(childProcess, timeoutMs) {
|
|
1359
|
-
return new Promise((resolve) => {
|
|
1360
|
-
const settle = (exited) => {
|
|
1361
|
-
clearTimeout(gracePeriodTimer);
|
|
1362
|
-
childProcess.off("exit", onExit);
|
|
1363
|
-
childProcess.off("error", onError);
|
|
1364
|
-
resolve(exited);
|
|
1365
|
-
};
|
|
1366
|
-
const onExit = () => settle(true);
|
|
1367
|
-
const onError = () => settle(false);
|
|
1368
|
-
const gracePeriodTimer = setTimeout(() => settle(false), timeoutMs);
|
|
1369
|
-
childProcess.on("exit", onExit);
|
|
1370
|
-
childProcess.on("error", onError);
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
function hasProcessAlreadyExited(childProcess) {
|
|
1374
|
-
return (childProcess.exitCode ?? null) !== null || (childProcess.signalCode ?? null) !== null;
|
|
1375
|
-
}
|
|
1376
|
-
async function terminateProcessTree(childProcess, dependencies = {}) {
|
|
1377
|
-
const pid = childProcess.pid;
|
|
1378
|
-
if (!pid) return;
|
|
1379
|
-
if (hasProcessAlreadyExited(childProcess)) {
|
|
1380
|
-
killProcessTreeIfRunning(pid, "SIGKILL", dependencies);
|
|
1381
|
-
return;
|
|
1382
|
-
}
|
|
1383
|
-
killProcessTreeIfRunning(pid, "SIGTERM", dependencies);
|
|
1384
|
-
const gracePeriodMs = dependencies.gracePeriodMs ?? PROCESS_TREE_KILL_GRACE_PERIOD_MS;
|
|
1385
|
-
const exitedBeforeGracePeriod = await waitForProcessExitWithin(childProcess, gracePeriodMs);
|
|
1386
|
-
if (!exitedBeforeGracePeriod && isProcessRunning(pid)) {
|
|
1387
|
-
killProcessTreeIfRunning(pid, "SIGKILL", dependencies);
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
const EPHEMERAL_SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
1391
|
-
function registerEphemeralShutdownHandlers(options) {
|
|
1392
|
-
const processRef = options.processRef ?? process;
|
|
1393
|
-
const onProcessExit = () => options.killApplicationTree();
|
|
1394
|
-
const signalHandlers = /* @__PURE__ */ new Map();
|
|
1395
|
-
const dispose = () => {
|
|
1396
|
-
processRef.off("exit", onProcessExit);
|
|
1397
|
-
for (const [signal, handler] of signalHandlers) {
|
|
1398
|
-
processRef.off(signal, handler);
|
|
1399
|
-
}
|
|
1400
|
-
signalHandlers.clear();
|
|
1401
|
-
};
|
|
1402
|
-
for (const signal of EPHEMERAL_SHUTDOWN_SIGNALS) {
|
|
1403
|
-
const handler = () => {
|
|
1404
|
-
void (async () => {
|
|
1405
|
-
options.onSignal?.(signal);
|
|
1406
|
-
try {
|
|
1407
|
-
await options.stop();
|
|
1408
|
-
} catch (error) {
|
|
1409
|
-
console.error(`Failed to stop the ephemeral environment on ${signal}:`, error);
|
|
1410
|
-
} finally {
|
|
1411
|
-
dispose();
|
|
1412
|
-
processRef.removeAllListeners(signal);
|
|
1413
|
-
processRef.kill(processRef.pid, signal);
|
|
1414
|
-
}
|
|
1415
|
-
})();
|
|
1416
|
-
};
|
|
1417
|
-
signalHandlers.set(signal, handler);
|
|
1418
|
-
processRef.once(signal, handler);
|
|
1419
|
-
}
|
|
1420
|
-
processRef.once("exit", onProcessExit);
|
|
1421
|
-
return { dispose };
|
|
1422
|
-
}
|
|
1423
1308
|
async function getPathAgeMilliseconds(targetPath) {
|
|
1424
1309
|
try {
|
|
1425
1310
|
const stats = await stat(targetPath);
|
|
@@ -1710,15 +1595,7 @@ async function waitForApplicationReadiness(baseUrl, appProcess, options) {
|
|
|
1710
1595
|
return { exited: true };
|
|
1711
1596
|
}
|
|
1712
1597
|
);
|
|
1713
|
-
const exitError = () => {
|
|
1714
|
-
const capturedOutput = appProcess.readCapturedOutput?.().trim();
|
|
1715
|
-
const capturedOutputTail = capturedOutput ? `
|
|
1716
|
-
Captured output:
|
|
1717
|
-
${capturedOutput.split("\n").slice(-20).join("\n")}` : "";
|
|
1718
|
-
return new Error(
|
|
1719
|
-
`Application process exited before readiness check (exit ${exitCode ?? "unknown"})${capturedOutputTail}`
|
|
1720
|
-
);
|
|
1721
|
-
};
|
|
1598
|
+
const exitError = () => new Error(`Application process exited before readiness check (exit ${exitCode ?? "unknown"})`);
|
|
1722
1599
|
while (Date.now() - startTimestamp < options.timeoutMs) {
|
|
1723
1600
|
const cycle = await Promise.race([
|
|
1724
1601
|
probeApplicationReadiness(baseUrl).then((probe) => ({ probe })),
|
|
@@ -2859,40 +2736,19 @@ async function startEphemeralEnvironment(options) {
|
|
|
2859
2736
|
const runtimeLock = await acquireEphemeralRuntimeLock(options.logPrefix);
|
|
2860
2737
|
let applicationProcess = null;
|
|
2861
2738
|
let isStopped = false;
|
|
2862
|
-
let shutdownHandlers = null;
|
|
2863
2739
|
const stop = async () => {
|
|
2864
2740
|
if (isStopped) return;
|
|
2865
2741
|
isStopped = true;
|
|
2866
2742
|
try {
|
|
2867
2743
|
if (applicationProcess && !applicationProcess.killed) {
|
|
2868
|
-
|
|
2869
|
-
await terminateProcessTree(applicationProcess);
|
|
2870
|
-
} catch (error) {
|
|
2871
|
-
console.error(`[${options.logPrefix}] Failed to terminate the application process tree:`, error);
|
|
2872
|
-
}
|
|
2744
|
+
applicationProcess.kill("SIGTERM");
|
|
2873
2745
|
}
|
|
2874
2746
|
await databaseContainer.stop();
|
|
2875
2747
|
await clearEphemeralEnvironmentState();
|
|
2876
2748
|
} finally {
|
|
2877
2749
|
await runtimeLock.release();
|
|
2878
|
-
shutdownHandlers?.dispose();
|
|
2879
2750
|
}
|
|
2880
2751
|
};
|
|
2881
|
-
shutdownHandlers = registerEphemeralShutdownHandlers({
|
|
2882
|
-
stop,
|
|
2883
|
-
onSignal: (signal) => console.log(`[${options.logPrefix}] Received ${signal}, stopping ephemeral environment...`),
|
|
2884
|
-
// Deliberately not guarded on `isStopped`: `startEphemeralEnvironment`'s own catch already ran
|
|
2885
|
-
// `stop()` before rethrowing, so the guard made the sweep dead on exactly the paths that need
|
|
2886
|
-
// it. After a successful `stop()` the extra group kill is a harmless `ESRCH` this swallows.
|
|
2887
|
-
killApplicationTree: () => {
|
|
2888
|
-
const pid = applicationProcess?.pid;
|
|
2889
|
-
if (!pid) return;
|
|
2890
|
-
try {
|
|
2891
|
-
killProcessTree(pid, "SIGKILL");
|
|
2892
|
-
} catch {
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
});
|
|
2896
2752
|
try {
|
|
2897
2753
|
const appReadyTimeoutMs = resolveAppReadyTimeoutMs(options.logPrefix);
|
|
2898
2754
|
const buildCacheTtlSeconds = resolveBuildCacheTtlSeconds(options.logPrefix);
|
|
@@ -2962,8 +2818,7 @@ async function startEphemeralEnvironment(options) {
|
|
|
2962
2818
|
}
|
|
2963
2819
|
console.log(`[${options.logPrefix}] Starting application on ${applicationBaseUrl}...`);
|
|
2964
2820
|
const startedAppProcess = startYarnCommand(["start"], commandEnvironment, {
|
|
2965
|
-
silent: !options.verbose
|
|
2966
|
-
detached: true
|
|
2821
|
+
silent: !options.verbose
|
|
2967
2822
|
}, appDirectory);
|
|
2968
2823
|
applicationProcess = startedAppProcess;
|
|
2969
2824
|
await runTimedStep(
|
|
@@ -2999,7 +2854,14 @@ async function startEphemeralEnvironment(options) {
|
|
|
2999
2854
|
await setupLock.release();
|
|
3000
2855
|
}
|
|
3001
2856
|
}
|
|
3002
|
-
async function keepEnvironmentRunningForever() {
|
|
2857
|
+
async function keepEnvironmentRunningForever(options) {
|
|
2858
|
+
const onSignal = async (signal) => {
|
|
2859
|
+
console.log(`[${options.logPrefix}] Received ${signal}, stopping ephemeral environment...`);
|
|
2860
|
+
await options.stop();
|
|
2861
|
+
process.exit(0);
|
|
2862
|
+
};
|
|
2863
|
+
process.once("SIGINT", () => void onSignal("SIGINT"));
|
|
2864
|
+
process.once("SIGTERM", () => void onSignal("SIGTERM"));
|
|
3003
2865
|
await new Promise(() => {
|
|
3004
2866
|
});
|
|
3005
2867
|
}
|
|
@@ -3045,7 +2907,10 @@ async function runIntegrationTestsInEphemeralEnvironment(rawArgs) {
|
|
|
3045
2907
|
}
|
|
3046
2908
|
if (options.keep) {
|
|
3047
2909
|
console.log("[integration] --keep enabled: leaving app and database running. Press Ctrl+C to stop.");
|
|
3048
|
-
await keepEnvironmentRunningForever(
|
|
2910
|
+
await keepEnvironmentRunningForever({
|
|
2911
|
+
logPrefix: "integration",
|
|
2912
|
+
stop: environment.stop
|
|
2913
|
+
});
|
|
3049
2914
|
}
|
|
3050
2915
|
} finally {
|
|
3051
2916
|
if (!options.keep) {
|
|
@@ -3070,7 +2935,10 @@ async function runEphemeralAppForQa(rawArgs) {
|
|
|
3070
2935
|
} else {
|
|
3071
2936
|
console.log("[ephemeral] Reused existing environment. Press Ctrl+C to exit without stopping the shared runtime.");
|
|
3072
2937
|
}
|
|
3073
|
-
await keepEnvironmentRunningForever(
|
|
2938
|
+
await keepEnvironmentRunningForever({
|
|
2939
|
+
logPrefix: "ephemeral",
|
|
2940
|
+
stop: environment.stop
|
|
2941
|
+
});
|
|
3074
2942
|
}
|
|
3075
2943
|
async function runInteractiveIntegrationInEphemeralEnvironment(rawArgs) {
|
|
3076
2944
|
const options = parseInteractiveIntegrationOptions(rawArgs);
|
|
@@ -3217,19 +3085,14 @@ async function runInteractiveIntegrationInEphemeralEnvironment(rawArgs) {
|
|
|
3217
3085
|
}
|
|
3218
3086
|
}
|
|
3219
3087
|
export {
|
|
3220
|
-
CAPTURED_OUTPUT_MAX_LENGTH,
|
|
3221
3088
|
acquireEphemeralRuntimeLock,
|
|
3222
3089
|
clearEphemeralEnvironmentState,
|
|
3223
|
-
createBoundedOutputBuffer,
|
|
3224
3090
|
ephemeralPostgresInitSql,
|
|
3225
|
-
formatCapturedOutput,
|
|
3226
|
-
killProcessTree,
|
|
3227
3091
|
parseEphemeralAppOptions,
|
|
3228
3092
|
parseIntegrationCoverageOptions,
|
|
3229
3093
|
parseInteractiveIntegrationOptions,
|
|
3230
3094
|
parseOptions,
|
|
3231
3095
|
readEphemeralEnvironmentState,
|
|
3232
|
-
registerEphemeralShutdownHandlers,
|
|
3233
3096
|
resolveAppReadyTimeoutMs,
|
|
3234
3097
|
resolveBuildCacheTtlSeconds,
|
|
3235
3098
|
resolveEphemeralPostgresImage,
|
|
@@ -3242,7 +3105,6 @@ export {
|
|
|
3242
3105
|
shouldReuseBuildArtifacts,
|
|
3243
3106
|
shouldUseIsolatedPortForFreshEnvironment,
|
|
3244
3107
|
startEphemeralEnvironment,
|
|
3245
|
-
terminateProcessTree,
|
|
3246
3108
|
tryReuseExistingEnvironment,
|
|
3247
3109
|
waitForApplicationReadiness,
|
|
3248
3110
|
writeEphemeralEnvironmentState
|