quidproquo-cli 0.1.5
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 +3 -0
- package/docker/cdk-deployer/Dockerfile +13 -0
- package/docker/dev-server/Dockerfile +48 -0
- package/lib/commonjs/bin/qpq.d.ts +2 -0
- package/lib/commonjs/bin/qpq.js +6 -0
- package/lib/commonjs/bin/qpq.js.map +1 -0
- package/lib/commonjs/bin/qpqCdkApp.d.ts +1 -0
- package/lib/commonjs/bin/qpqCdkApp.js +8 -0
- package/lib/commonjs/bin/qpqCdkApp.js.map +1 -0
- package/lib/commonjs/cli/index.d.ts +1 -0
- package/lib/commonjs/cli/index.js +18 -0
- package/lib/commonjs/cli/index.js.map +1 -0
- package/lib/commonjs/cli/runCli.d.ts +1 -0
- package/lib/commonjs/cli/runCli.js +80 -0
- package/lib/commonjs/cli/runCli.js.map +1 -0
- package/lib/commonjs/commands/go.d.ts +1 -0
- package/lib/commonjs/commands/go.js +28 -0
- package/lib/commonjs/commands/go.js.map +1 -0
- package/lib/commonjs/commands/goDev.d.ts +1 -0
- package/lib/commonjs/commands/goDev.js +143 -0
- package/lib/commonjs/commands/goDev.js.map +1 -0
- package/lib/commonjs/commands/goDevWeb.d.ts +1 -0
- package/lib/commonjs/commands/goDevWeb.js +122 -0
- package/lib/commonjs/commands/goDevWeb.js.map +1 -0
- package/lib/commonjs/commands/goDocker.d.ts +1 -0
- package/lib/commonjs/commands/goDocker.js +32 -0
- package/lib/commonjs/commands/goDocker.js.map +1 -0
- package/lib/commonjs/commands/hooks.d.ts +1 -0
- package/lib/commonjs/commands/hooks.js +26 -0
- package/lib/commonjs/commands/hooks.js.map +1 -0
- package/lib/commonjs/commands/prep.d.ts +1 -0
- package/lib/commonjs/commands/prep.js +28 -0
- package/lib/commonjs/commands/prep.js.map +1 -0
- package/lib/commonjs/commands/publish.d.ts +4 -0
- package/lib/commonjs/commands/publish.js +54 -0
- package/lib/commonjs/commands/publish.js.map +1 -0
- package/lib/commonjs/commands/synth.d.ts +1 -0
- package/lib/commonjs/commands/synth.js +79 -0
- package/lib/commonjs/commands/synth.js.map +1 -0
- package/lib/commonjs/commands/teardown.d.ts +1 -0
- package/lib/commonjs/commands/teardown.js +33 -0
- package/lib/commonjs/commands/teardown.js.map +1 -0
- package/lib/commonjs/index.d.ts +1 -0
- package/lib/commonjs/index.js +18 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/lib/args.d.ts +2 -0
- package/lib/commonjs/lib/args.js +21 -0
- package/lib/commonjs/lib/args.js.map +1 -0
- package/lib/commonjs/lib/deployEnv.d.ts +6 -0
- package/lib/commonjs/lib/deployEnv.js +76 -0
- package/lib/commonjs/lib/deployEnv.js.map +1 -0
- package/lib/commonjs/lib/deployPrompts.d.ts +25 -0
- package/lib/commonjs/lib/deployPrompts.js +83 -0
- package/lib/commonjs/lib/deployPrompts.js.map +1 -0
- package/lib/commonjs/lib/devServerEntry.d.ts +1 -0
- package/lib/commonjs/lib/devServerEntry.js +53 -0
- package/lib/commonjs/lib/devServerEntry.js.map +1 -0
- package/lib/commonjs/lib/discovery.d.ts +10 -0
- package/lib/commonjs/lib/discovery.js +56 -0
- package/lib/commonjs/lib/discovery.js.map +1 -0
- package/lib/commonjs/lib/hooks.d.ts +2 -0
- package/lib/commonjs/lib/hooks.js +45 -0
- package/lib/commonjs/lib/hooks.js.map +1 -0
- package/lib/commonjs/lib/packageRoot.d.ts +1 -0
- package/lib/commonjs/lib/packageRoot.js +21 -0
- package/lib/commonjs/lib/packageRoot.js.map +1 -0
- package/lib/commonjs/lib/prompts.d.ts +3 -0
- package/lib/commonjs/lib/prompts.js +64 -0
- package/lib/commonjs/lib/prompts.js.map +1 -0
- package/lib/commonjs/lib/qpqConfigs.d.ts +3 -0
- package/lib/commonjs/lib/qpqConfigs.js +19 -0
- package/lib/commonjs/lib/qpqConfigs.js.map +1 -0
- package/lib/commonjs/lib/resolveAppSelection.d.ts +6 -0
- package/lib/commonjs/lib/resolveAppSelection.js +58 -0
- package/lib/commonjs/lib/resolveAppSelection.js.map +1 -0
- package/lib/commonjs/lib/rspackRun.d.ts +2 -0
- package/lib/commonjs/lib/rspackRun.js +23 -0
- package/lib/commonjs/lib/rspackRun.js.map +1 -0
- package/lib/commonjs/lib/runCommand.d.ts +13 -0
- package/lib/commonjs/lib/runCommand.js +78 -0
- package/lib/commonjs/lib/runCommand.js.map +1 -0
- package/lib/commonjs/lib/runTasks.d.ts +10 -0
- package/lib/commonjs/lib/runTasks.js +42 -0
- package/lib/commonjs/lib/runTasks.js.map +1 -0
- package/lib/commonjs/lib/timing.d.ts +2 -0
- package/lib/commonjs/lib/timing.js +11 -0
- package/lib/commonjs/lib/timing.js.map +1 -0
- package/lib/commonjs/lib/views.d.ts +2 -0
- package/lib/commonjs/lib/views.js +32 -0
- package/lib/commonjs/lib/views.js.map +1 -0
- package/lib/commonjs/platforms/aws/awsCredentials.d.ts +1 -0
- package/lib/commonjs/platforms/aws/awsCredentials.js +28 -0
- package/lib/commonjs/platforms/aws/awsCredentials.js.map +1 -0
- package/lib/commonjs/platforms/aws/cdkApp.d.ts +2 -0
- package/lib/commonjs/platforms/aws/cdkApp.js +19 -0
- package/lib/commonjs/platforms/aws/cdkApp.js.map +1 -0
- package/lib/commonjs/platforms/aws/go.d.ts +2 -0
- package/lib/commonjs/platforms/aws/go.js +116 -0
- package/lib/commonjs/platforms/aws/go.js.map +1 -0
- package/lib/commonjs/platforms/aws/goDocker.d.ts +2 -0
- package/lib/commonjs/platforms/aws/goDocker.js +287 -0
- package/lib/commonjs/platforms/aws/goDocker.js.map +1 -0
- package/lib/commonjs/platforms/aws/identity.d.ts +2 -0
- package/lib/commonjs/platforms/aws/identity.js +26 -0
- package/lib/commonjs/platforms/aws/identity.js.map +1 -0
- package/lib/commonjs/platforms/aws/index.d.ts +2 -0
- package/lib/commonjs/platforms/aws/index.js +19 -0
- package/lib/commonjs/platforms/aws/index.js.map +1 -0
- package/lib/commonjs/platforms/aws/publish.d.ts +4 -0
- package/lib/commonjs/platforms/aws/publish.js +66 -0
- package/lib/commonjs/platforms/aws/publish.js.map +1 -0
- package/lib/commonjs/platforms/aws/remote.d.ts +11 -0
- package/lib/commonjs/platforms/aws/remote.js +106 -0
- package/lib/commonjs/platforms/aws/remote.js.map +1 -0
- package/lib/commonjs/platforms/aws/stacks.d.ts +7 -0
- package/lib/commonjs/platforms/aws/stacks.js +91 -0
- package/lib/commonjs/platforms/aws/stacks.js.map +1 -0
- package/lib/commonjs/platforms/aws/teardown.d.ts +2 -0
- package/lib/commonjs/platforms/aws/teardown.js +59 -0
- package/lib/commonjs/platforms/aws/teardown.js.map +1 -0
- package/lib/commonjs/platforms/aws/viewsSync.d.ts +2 -0
- package/lib/commonjs/platforms/aws/viewsSync.js +39 -0
- package/lib/commonjs/platforms/aws/viewsSync.js.map +1 -0
- package/lib/commonjs/platforms/docker/go.d.ts +2 -0
- package/lib/commonjs/platforms/docker/go.js +160 -0
- package/lib/commonjs/platforms/docker/go.js.map +1 -0
- package/lib/commonjs/platforms/docker/index.d.ts +2 -0
- package/lib/commonjs/platforms/docker/index.js +27 -0
- package/lib/commonjs/platforms/docker/index.js.map +1 -0
- package/lib/commonjs/platforms/index.d.ts +4 -0
- package/lib/commonjs/platforms/index.js +39 -0
- package/lib/commonjs/platforms/index.js.map +1 -0
- package/lib/commonjs/platforms/types.d.ts +16 -0
- package/lib/commonjs/platforms/types.js +9 -0
- package/lib/commonjs/platforms/types.js.map +1 -0
- package/lib/esm/bin/qpq.d.ts +2 -0
- package/lib/esm/bin/qpq.js +4 -0
- package/lib/esm/bin/qpq.js.map +1 -0
- package/lib/esm/bin/qpqCdkApp.d.ts +1 -0
- package/lib/esm/bin/qpqCdkApp.js +6 -0
- package/lib/esm/bin/qpqCdkApp.js.map +1 -0
- package/lib/esm/cli/index.d.ts +1 -0
- package/lib/esm/cli/index.js +2 -0
- package/lib/esm/cli/index.js.map +1 -0
- package/lib/esm/cli/runCli.d.ts +1 -0
- package/lib/esm/cli/runCli.js +67 -0
- package/lib/esm/cli/runCli.js.map +1 -0
- package/lib/esm/commands/go.d.ts +1 -0
- package/lib/esm/commands/go.js +15 -0
- package/lib/esm/commands/go.js.map +1 -0
- package/lib/esm/commands/goDev.d.ts +1 -0
- package/lib/esm/commands/goDev.js +127 -0
- package/lib/esm/commands/goDev.js.map +1 -0
- package/lib/esm/commands/goDevWeb.d.ts +1 -0
- package/lib/esm/commands/goDevWeb.js +107 -0
- package/lib/esm/commands/goDevWeb.js.map +1 -0
- package/lib/esm/commands/goDocker.d.ts +1 -0
- package/lib/esm/commands/goDocker.js +19 -0
- package/lib/esm/commands/goDocker.js.map +1 -0
- package/lib/esm/commands/hooks.d.ts +1 -0
- package/lib/esm/commands/hooks.js +13 -0
- package/lib/esm/commands/hooks.js.map +1 -0
- package/lib/esm/commands/prep.d.ts +1 -0
- package/lib/esm/commands/prep.js +15 -0
- package/lib/esm/commands/prep.js.map +1 -0
- package/lib/esm/commands/publish.d.ts +4 -0
- package/lib/esm/commands/publish.js +38 -0
- package/lib/esm/commands/publish.js.map +1 -0
- package/lib/esm/commands/synth.d.ts +1 -0
- package/lib/esm/commands/synth.js +63 -0
- package/lib/esm/commands/synth.js.map +1 -0
- package/lib/esm/commands/teardown.d.ts +1 -0
- package/lib/esm/commands/teardown.js +20 -0
- package/lib/esm/commands/teardown.js.map +1 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/lib/args.d.ts +2 -0
- package/lib/esm/lib/args.js +16 -0
- package/lib/esm/lib/args.js.map +1 -0
- package/lib/esm/lib/deployEnv.d.ts +6 -0
- package/lib/esm/lib/deployEnv.js +60 -0
- package/lib/esm/lib/deployEnv.js.map +1 -0
- package/lib/esm/lib/deployPrompts.d.ts +25 -0
- package/lib/esm/lib/deployPrompts.js +69 -0
- package/lib/esm/lib/deployPrompts.js.map +1 -0
- package/lib/esm/lib/devServerEntry.d.ts +1 -0
- package/lib/esm/lib/devServerEntry.js +46 -0
- package/lib/esm/lib/devServerEntry.js.map +1 -0
- package/lib/esm/lib/discovery.d.ts +10 -0
- package/lib/esm/lib/discovery.js +40 -0
- package/lib/esm/lib/discovery.js.map +1 -0
- package/lib/esm/lib/hooks.d.ts +2 -0
- package/lib/esm/lib/hooks.js +27 -0
- package/lib/esm/lib/hooks.js.map +1 -0
- package/lib/esm/lib/packageRoot.d.ts +1 -0
- package/lib/esm/lib/packageRoot.js +14 -0
- package/lib/esm/lib/packageRoot.js.map +1 -0
- package/lib/esm/lib/prompts.d.ts +3 -0
- package/lib/esm/lib/prompts.js +16 -0
- package/lib/esm/lib/prompts.js.map +1 -0
- package/lib/esm/lib/qpqConfigs.d.ts +3 -0
- package/lib/esm/lib/qpqConfigs.js +14 -0
- package/lib/esm/lib/qpqConfigs.js.map +1 -0
- package/lib/esm/lib/resolveAppSelection.d.ts +6 -0
- package/lib/esm/lib/resolveAppSelection.js +45 -0
- package/lib/esm/lib/resolveAppSelection.js.map +1 -0
- package/lib/esm/lib/rspackRun.d.ts +2 -0
- package/lib/esm/lib/rspackRun.js +19 -0
- package/lib/esm/lib/rspackRun.js.map +1 -0
- package/lib/esm/lib/runCommand.d.ts +13 -0
- package/lib/esm/lib/runCommand.js +69 -0
- package/lib/esm/lib/runCommand.js.map +1 -0
- package/lib/esm/lib/runTasks.d.ts +10 -0
- package/lib/esm/lib/runTasks.js +28 -0
- package/lib/esm/lib/runTasks.js.map +1 -0
- package/lib/esm/lib/timing.d.ts +2 -0
- package/lib/esm/lib/timing.js +6 -0
- package/lib/esm/lib/timing.js.map +1 -0
- package/lib/esm/lib/views.d.ts +2 -0
- package/lib/esm/lib/views.js +15 -0
- package/lib/esm/lib/views.js.map +1 -0
- package/lib/esm/platforms/aws/awsCredentials.d.ts +1 -0
- package/lib/esm/platforms/aws/awsCredentials.js +15 -0
- package/lib/esm/platforms/aws/awsCredentials.js.map +1 -0
- package/lib/esm/platforms/aws/cdkApp.d.ts +2 -0
- package/lib/esm/platforms/aws/cdkApp.js +11 -0
- package/lib/esm/platforms/aws/cdkApp.js.map +1 -0
- package/lib/esm/platforms/aws/go.d.ts +2 -0
- package/lib/esm/platforms/aws/go.js +100 -0
- package/lib/esm/platforms/aws/go.js.map +1 -0
- package/lib/esm/platforms/aws/goDocker.d.ts +2 -0
- package/lib/esm/platforms/aws/goDocker.js +271 -0
- package/lib/esm/platforms/aws/goDocker.js.map +1 -0
- package/lib/esm/platforms/aws/identity.d.ts +2 -0
- package/lib/esm/platforms/aws/identity.js +22 -0
- package/lib/esm/platforms/aws/identity.js.map +1 -0
- package/lib/esm/platforms/aws/index.d.ts +2 -0
- package/lib/esm/platforms/aws/index.js +16 -0
- package/lib/esm/platforms/aws/index.js.map +1 -0
- package/lib/esm/platforms/aws/publish.d.ts +4 -0
- package/lib/esm/platforms/aws/publish.js +50 -0
- package/lib/esm/platforms/aws/publish.js.map +1 -0
- package/lib/esm/platforms/aws/remote.d.ts +11 -0
- package/lib/esm/platforms/aws/remote.js +90 -0
- package/lib/esm/platforms/aws/remote.js.map +1 -0
- package/lib/esm/platforms/aws/stacks.d.ts +7 -0
- package/lib/esm/platforms/aws/stacks.js +69 -0
- package/lib/esm/platforms/aws/stacks.js.map +1 -0
- package/lib/esm/platforms/aws/teardown.d.ts +2 -0
- package/lib/esm/platforms/aws/teardown.js +46 -0
- package/lib/esm/platforms/aws/teardown.js.map +1 -0
- package/lib/esm/platforms/aws/viewsSync.d.ts +2 -0
- package/lib/esm/platforms/aws/viewsSync.js +25 -0
- package/lib/esm/platforms/aws/viewsSync.js.map +1 -0
- package/lib/esm/platforms/docker/go.d.ts +2 -0
- package/lib/esm/platforms/docker/go.js +143 -0
- package/lib/esm/platforms/docker/go.js.map +1 -0
- package/lib/esm/platforms/docker/index.d.ts +2 -0
- package/lib/esm/platforms/docker/index.js +15 -0
- package/lib/esm/platforms/docker/index.js.map +1 -0
- package/lib/esm/platforms/index.d.ts +4 -0
- package/lib/esm/platforms/index.js +20 -0
- package/lib/esm/platforms/index.js.map +1 -0
- package/lib/esm/platforms/types.d.ts +16 -0
- package/lib/esm/platforms/types.js +6 -0
- package/lib/esm/platforms/types.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// The interactive question flow shared by `qpq go` (sequential AWS deploy) and
|
|
2
|
+
// a future dockerized variant: pick an app, confirm the target, pick services
|
|
3
|
+
// (or domain/bootstrap), pick stacks.
|
|
4
|
+
import { getServiceNames } from './discovery';
|
|
5
|
+
import { promptSelect, promptText, promptYesNo } from './prompts';
|
|
6
|
+
export const promptDeployPlan = async (appName) => {
|
|
7
|
+
const deployInfo = process.env.ACTOR_NAME
|
|
8
|
+
? `${appName}-${process.env.ENVIRONMENT}-${process.env.ACTOR_NAME}`
|
|
9
|
+
: `${appName}-${process.env.ENVIRONMENT}`;
|
|
10
|
+
if (!(await promptYesNo(`Deploying to: [${deployInfo}]`))) {
|
|
11
|
+
console.log('Exiting!');
|
|
12
|
+
return { kind: 'cancelled' };
|
|
13
|
+
}
|
|
14
|
+
let services = [];
|
|
15
|
+
do {
|
|
16
|
+
const allServices = getServiceNames(appName);
|
|
17
|
+
// Bracketed so the meta options can't be mistaken for actual services.
|
|
18
|
+
const allText = '[ all ]';
|
|
19
|
+
const accountText = '[ account ]';
|
|
20
|
+
const domainEnvText = '[ domain ]';
|
|
21
|
+
const bootstrapEnvText = '[ bootstrap environment ]';
|
|
22
|
+
const service = await promptSelect('Select services to deploy', [allText, ...allServices, accountText, domainEnvText, bootstrapEnvText]);
|
|
23
|
+
if (service === allText) {
|
|
24
|
+
services = allServices;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
if (service === accountText) {
|
|
28
|
+
return { kind: 'account', appName };
|
|
29
|
+
}
|
|
30
|
+
if (service === domainEnvText) {
|
|
31
|
+
return { kind: 'bootstrap', appName, includeDomain: true };
|
|
32
|
+
}
|
|
33
|
+
if (service === bootstrapEnvText) {
|
|
34
|
+
return { kind: 'bootstrap', appName, includeDomain: false };
|
|
35
|
+
}
|
|
36
|
+
services.push(service);
|
|
37
|
+
} while (await promptYesNo('Do you want to deploy another service?'));
|
|
38
|
+
services = [...new Set(services)];
|
|
39
|
+
const stacks = (await promptSelect('Stacks to deploy', ['all', 'inf', 'api', 'web', 'views']));
|
|
40
|
+
return { kind: 'services', appName, services, stacks };
|
|
41
|
+
};
|
|
42
|
+
// The question flow for `qpq teardown`: pick services, then type the deploy
|
|
43
|
+
// target back to confirm — destroying inf stacks takes user data (key value
|
|
44
|
+
// stores, user directories) with it, so a y/n prompt isn't enough friction.
|
|
45
|
+
export const promptTeardownPlan = async (appName) => {
|
|
46
|
+
const deployInfo = process.env.ACTOR_NAME
|
|
47
|
+
? `${appName}-${process.env.ENVIRONMENT}-${process.env.ACTOR_NAME}`
|
|
48
|
+
: `${appName}-${process.env.ENVIRONMENT}`;
|
|
49
|
+
let services = [];
|
|
50
|
+
do {
|
|
51
|
+
const allServices = getServiceNames(appName);
|
|
52
|
+
const allText = '[ all ]';
|
|
53
|
+
const service = await promptSelect('Select services to tear down', [allText, ...allServices]);
|
|
54
|
+
if (service === allText) {
|
|
55
|
+
services = allServices;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
services.push(service);
|
|
59
|
+
} while (await promptYesNo('Do you want to tear down another service?'));
|
|
60
|
+
services = [...new Set(services)];
|
|
61
|
+
console.log(`\nThis will DESTROY the web, api and inf stacks (including all stored data) for: ${services.join(', ')}`);
|
|
62
|
+
const confirmation = await promptText(`Type '${deployInfo}' to confirm`);
|
|
63
|
+
if (confirmation !== deployInfo) {
|
|
64
|
+
console.log('Confirmation did not match. Exiting!');
|
|
65
|
+
return { kind: 'cancelled' };
|
|
66
|
+
}
|
|
67
|
+
return { kind: 'services', appName, services };
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=deployPrompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployPrompts.js","sourceRoot":"","sources":["../../../src/lib/deployPrompts.ts"],"names":[],"mappings":"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","sourcesContent":["// The interactive question flow shared by `qpq go` (sequential AWS deploy) and\n// a future dockerized variant: pick an app, confirm the target, pick services\n// (or domain/bootstrap), pick stacks.\nimport { getServiceNames } from './discovery';\nimport { promptSelect, promptText, promptYesNo } from './prompts';\n\nexport type StackType = 'all' | 'inf' | 'api' | 'web' | 'views';\n\nexport type DeployPlan =\n | { kind: 'cancelled' }\n // Deploy only the account-level guardrails stack (one per AWS account).\n | { kind: 'account'; appName: string }\n // Deploy the bootstrap stack (and optionally the domain stack first).\n | { kind: 'bootstrap'; appName: string; includeDomain: boolean }\n // Deploy the selected stacks for the selected services.\n | {\n kind: 'services';\n appName: string;\n services: string[];\n stacks: StackType;\n };\n\nexport const promptDeployPlan = async (appName: string): Promise<DeployPlan> => {\n const deployInfo = process.env.ACTOR_NAME\n ? `${appName}-${process.env.ENVIRONMENT}-${process.env.ACTOR_NAME}`\n : `${appName}-${process.env.ENVIRONMENT}`;\n\n if (!(await promptYesNo(`Deploying to: [${deployInfo}]`))) {\n console.log('Exiting!');\n return { kind: 'cancelled' };\n }\n\n let services: string[] = [];\n\n do {\n const allServices = getServiceNames(appName);\n\n // Bracketed so the meta options can't be mistaken for actual services.\n const allText = '[ all ]';\n const accountText = '[ account ]';\n const domainEnvText = '[ domain ]';\n const bootstrapEnvText = '[ bootstrap environment ]';\n\n const service = await promptSelect('Select services to deploy', [allText, ...allServices, accountText, domainEnvText, bootstrapEnvText]);\n\n if (service === allText) {\n services = allServices;\n break;\n }\n if (service === accountText) {\n return { kind: 'account', appName };\n }\n if (service === domainEnvText) {\n return { kind: 'bootstrap', appName, includeDomain: true };\n }\n if (service === bootstrapEnvText) {\n return { kind: 'bootstrap', appName, includeDomain: false };\n }\n\n services.push(service);\n } while (await promptYesNo('Do you want to deploy another service?'));\n\n services = [...new Set(services)];\n\n const stacks = (await promptSelect('Stacks to deploy', ['all', 'inf', 'api', 'web', 'views'])) as StackType;\n\n return { kind: 'services', appName, services, stacks };\n};\n\nexport type TeardownPlan =\n | { kind: 'cancelled' }\n // Destroy the web, api and inf stacks for the selected services.\n | { kind: 'services'; appName: string; services: string[] };\n\n// The question flow for `qpq teardown`: pick services, then type the deploy\n// target back to confirm — destroying inf stacks takes user data (key value\n// stores, user directories) with it, so a y/n prompt isn't enough friction.\nexport const promptTeardownPlan = async (appName: string): Promise<TeardownPlan> => {\n const deployInfo = process.env.ACTOR_NAME\n ? `${appName}-${process.env.ENVIRONMENT}-${process.env.ACTOR_NAME}`\n : `${appName}-${process.env.ENVIRONMENT}`;\n\n let services: string[] = [];\n\n do {\n const allServices = getServiceNames(appName);\n const allText = '[ all ]';\n\n const service = await promptSelect('Select services to tear down', [allText, ...allServices]);\n\n if (service === allText) {\n services = allServices;\n break;\n }\n\n services.push(service);\n } while (await promptYesNo('Do you want to tear down another service?'));\n\n services = [...new Set(services)];\n\n console.log(`\\nThis will DESTROY the web, api and inf stacks (including all stored data) for: ${services.join(', ')}`);\n const confirmation = await promptText(`Type '${deployInfo}' to confirm`);\n\n if (confirmation !== deployInfo) {\n console.log('Confirmation did not match. Exiting!');\n return { kind: 'cancelled' };\n }\n\n return { kind: 'services', appName, services };\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const writeDevServerEntry: (root: string, appName: string) => string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getAppDirectory } from './discovery';
|
|
4
|
+
// The dev-server bootstrap, generated per build so it can import an optional
|
|
5
|
+
// app-owned overrides file (apps/<app>/devServer.config.ts, default-exporting
|
|
6
|
+
// DevServerConfigOverrides). The `quidproquo-dynamic-loader` import is a
|
|
7
|
+
// virtual module injected by QpqPlugin at bundle time. QPQ_WEB_ROOT (set in
|
|
8
|
+
// the docker platform image) turns on static views serving.
|
|
9
|
+
export const writeDevServerEntry = (root, appName) => {
|
|
10
|
+
const entryDir = path.join(root, 'dist', 'qpq', 'dev-server');
|
|
11
|
+
const entryPath = path.join(entryDir, 'entry.ts');
|
|
12
|
+
const overridesPath = path.join(getAppDirectory(appName), 'devServer.config.ts');
|
|
13
|
+
const overridesImport = fs.existsSync(overridesPath)
|
|
14
|
+
? `import devServerConfigOverrides from ${JSON.stringify(overridesPath.replace(/\.ts$/, ''))};`
|
|
15
|
+
: 'const devServerConfigOverrides = {};';
|
|
16
|
+
fs.mkdirSync(entryDir, { recursive: true });
|
|
17
|
+
fs.writeFileSync(entryPath, `// GENERATED by qpq — do not edit.
|
|
18
|
+
import { startDevServer } from 'quidproquo-dev-server';
|
|
19
|
+
import {
|
|
20
|
+
qpqConfigs,
|
|
21
|
+
qpqDynamicModuleLoaderForService,
|
|
22
|
+
// @ts-ignore - Special build-time virtual module
|
|
23
|
+
} from 'quidproquo-dynamic-loader';
|
|
24
|
+
|
|
25
|
+
${overridesImport}
|
|
26
|
+
|
|
27
|
+
startDevServer(
|
|
28
|
+
{
|
|
29
|
+
serverDomain: 'localhost',
|
|
30
|
+
serverPort: 8080,
|
|
31
|
+
webSocketPort: 8888,
|
|
32
|
+
fileStorageConfig: {
|
|
33
|
+
secureUrlSecret: 'dev-secure-url-secret',
|
|
34
|
+
},
|
|
35
|
+
qpqConfigs,
|
|
36
|
+
dynamicModuleLoader: qpqDynamicModuleLoaderForService,
|
|
37
|
+
webRoot: process.env.QPQ_WEB_ROOT,
|
|
38
|
+
logServiceName: 'admin',
|
|
39
|
+
delay: { default: 0 },
|
|
40
|
+
},
|
|
41
|
+
devServerConfigOverrides,
|
|
42
|
+
);
|
|
43
|
+
`);
|
|
44
|
+
return entryPath;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=devServerEntry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devServerEntry.js","sourceRoot":"","sources":["../../../src/lib/devServerEntry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAE,OAAe,EAAU,EAAE;IAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAElD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC;IACjF,MAAM,eAAe,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;QAClD,CAAC,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG;QAC/F,CAAC,CAAC,sCAAsC,CAAC;IAE3C,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,EAAE,CAAC,aAAa,CACd,SAAS,EACT;;;;;;;;EAQF,eAAe;;;;;;;;;;;;;;;;;;CAkBhB,CACE,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { getAppDirectory } from './discovery';\n\n// The dev-server bootstrap, generated per build so it can import an optional\n// app-owned overrides file (apps/<app>/devServer.config.ts, default-exporting\n// DevServerConfigOverrides). The `quidproquo-dynamic-loader` import is a\n// virtual module injected by QpqPlugin at bundle time. QPQ_WEB_ROOT (set in\n// the docker platform image) turns on static views serving.\nexport const writeDevServerEntry = (root: string, appName: string): string => {\n const entryDir = path.join(root, 'dist', 'qpq', 'dev-server');\n const entryPath = path.join(entryDir, 'entry.ts');\n\n const overridesPath = path.join(getAppDirectory(appName), 'devServer.config.ts');\n const overridesImport = fs.existsSync(overridesPath)\n ? `import devServerConfigOverrides from ${JSON.stringify(overridesPath.replace(/\\.ts$/, ''))};`\n : 'const devServerConfigOverrides = {};';\n\n fs.mkdirSync(entryDir, { recursive: true });\n fs.writeFileSync(\n entryPath,\n `// GENERATED by qpq — do not edit.\nimport { startDevServer } from 'quidproquo-dev-server';\nimport {\n qpqConfigs,\n qpqDynamicModuleLoaderForService,\n // @ts-ignore - Special build-time virtual module\n} from 'quidproquo-dynamic-loader';\n\n${overridesImport}\n\nstartDevServer(\n {\n serverDomain: 'localhost',\n serverPort: 8080,\n webSocketPort: 8888,\n fileStorageConfig: {\n secureUrlSecret: 'dev-secure-url-secret',\n },\n qpqConfigs,\n dynamicModuleLoader: qpqDynamicModuleLoaderForService,\n webRoot: process.env.QPQ_WEB_ROOT,\n logServiceName: 'admin',\n delay: { default: 0 },\n },\n devServerConfigOverrides,\n);\n`,\n );\n\n return entryPath;\n};\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const getRoot: () => string;
|
|
2
|
+
export declare const getAppsDirectory: () => string;
|
|
3
|
+
export declare const getAppDirectory: (appName: string) => string;
|
|
4
|
+
export declare const getServiceDirectory: (appName: string, service: string) => string;
|
|
5
|
+
export declare const getAvailableApps: () => string[];
|
|
6
|
+
export declare const getAllServiceNames: (appName: string) => string[];
|
|
7
|
+
export declare const serviceHasSubdir: (appName: string, service: string, subdir: string) => boolean;
|
|
8
|
+
export declare const getServiceNamesWithSubdir: (appName: string, subdir: string) => string[];
|
|
9
|
+
export declare const getServiceNames: (appName: string) => string[];
|
|
10
|
+
export declare const getServiceNamesWithViews: (appName: string) => string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
// The consumer repo root — qpq always runs from the workspace root (npm
|
|
4
|
+
// scripts set cwd there).
|
|
5
|
+
export const getRoot = () => process.cwd();
|
|
6
|
+
export const getAppsDirectory = () => path.join(getRoot(), 'apps');
|
|
7
|
+
export const getAppDirectory = (appName) => path.join(getAppsDirectory(), appName);
|
|
8
|
+
export const getServiceDirectory = (appName, service) => path.join(getAppDirectory(appName), 'services', service);
|
|
9
|
+
// Apps are the directories under apps/ that contain a services/ directory.
|
|
10
|
+
export const getAvailableApps = () => {
|
|
11
|
+
const appsPath = getAppsDirectory();
|
|
12
|
+
if (!fs.existsSync(appsPath)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
return fs.readdirSync(appsPath).filter((name) => {
|
|
16
|
+
const servicesPath = path.join(getAppDirectory(name), 'services');
|
|
17
|
+
return fs.statSync(getAppDirectory(name)).isDirectory() && fs.existsSync(servicesPath) && fs.statSync(servicesPath).isDirectory();
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
// Every service directory under an app's services/ folder (no subdir filter).
|
|
21
|
+
export const getAllServiceNames = (appName) => {
|
|
22
|
+
const directoryPath = path.join(getAppDirectory(appName), 'services');
|
|
23
|
+
if (!fs.existsSync(directoryPath)) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
return fs.readdirSync(directoryPath).filter((name) => fs.statSync(getServiceDirectory(appName, name)).isDirectory());
|
|
27
|
+
};
|
|
28
|
+
// True when a service contains the given child directory (e.g. 'service' for a
|
|
29
|
+
// backend, 'views' for a frontend).
|
|
30
|
+
export const serviceHasSubdir = (appName, service, subdir) => {
|
|
31
|
+
const subdirPath = path.join(getServiceDirectory(appName, service), subdir);
|
|
32
|
+
return fs.existsSync(subdirPath) && fs.statSync(subdirPath).isDirectory();
|
|
33
|
+
};
|
|
34
|
+
// Services that contain a given child directory.
|
|
35
|
+
export const getServiceNamesWithSubdir = (appName, subdir) => getAllServiceNames(appName).filter((service) => serviceHasSubdir(appName, service, subdir));
|
|
36
|
+
// Backend services — those with a service/ subdir.
|
|
37
|
+
export const getServiceNames = (appName) => getServiceNamesWithSubdir(appName, 'service');
|
|
38
|
+
// Backend services that also ship a frontend (views/ subdir).
|
|
39
|
+
export const getServiceNamesWithViews = (appName) => getServiceNames(appName).filter((service) => serviceHasSubdir(appName, service, 'views'));
|
|
40
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/lib/discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\n// The consumer repo root — qpq always runs from the workspace root (npm\n// scripts set cwd there).\nexport const getRoot = (): string => process.cwd();\n\nexport const getAppsDirectory = (): string => path.join(getRoot(), 'apps');\nexport const getAppDirectory = (appName: string): string => path.join(getAppsDirectory(), appName);\nexport const getServiceDirectory = (appName: string, service: string): string => path.join(getAppDirectory(appName), 'services', service);\n\n// Apps are the directories under apps/ that contain a services/ directory.\nexport const getAvailableApps = (): string[] => {\n const appsPath = getAppsDirectory();\n\n if (!fs.existsSync(appsPath)) {\n return [];\n }\n\n return fs.readdirSync(appsPath).filter((name) => {\n const servicesPath = path.join(getAppDirectory(name), 'services');\n return fs.statSync(getAppDirectory(name)).isDirectory() && fs.existsSync(servicesPath) && fs.statSync(servicesPath).isDirectory();\n });\n};\n\n// Every service directory under an app's services/ folder (no subdir filter).\nexport const getAllServiceNames = (appName: string): string[] => {\n const directoryPath = path.join(getAppDirectory(appName), 'services');\n\n if (!fs.existsSync(directoryPath)) {\n return [];\n }\n\n return fs.readdirSync(directoryPath).filter((name) => fs.statSync(getServiceDirectory(appName, name)).isDirectory());\n};\n\n// True when a service contains the given child directory (e.g. 'service' for a\n// backend, 'views' for a frontend).\nexport const serviceHasSubdir = (appName: string, service: string, subdir: string): boolean => {\n const subdirPath = path.join(getServiceDirectory(appName, service), subdir);\n return fs.existsSync(subdirPath) && fs.statSync(subdirPath).isDirectory();\n};\n\n// Services that contain a given child directory.\nexport const getServiceNamesWithSubdir = (appName: string, subdir: string): string[] =>\n getAllServiceNames(appName).filter((service) => serviceHasSubdir(appName, service, subdir));\n\n// Backend services — those with a service/ subdir.\nexport const getServiceNames = (appName: string): string[] => getServiceNamesWithSubdir(appName, 'service');\n\n// Backend services that also ship a frontend (views/ subdir).\nexport const getServiceNamesWithViews = (appName: string): string[] =>\n getServiceNames(appName).filter((service) => serviceHasSubdir(appName, service, 'views'));\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getAppDirectory, getAvailableApps } from './discovery';
|
|
4
|
+
import { runCommand } from './runCommand';
|
|
5
|
+
// App lifecycle hooks: apps/<app>/package.json scripts named `qpq:<hook>`
|
|
6
|
+
// (e.g. qpq:postinstall, qpq:prebuild). The CLI invokes them when present;
|
|
7
|
+
// apps without the hook are skipped silently.
|
|
8
|
+
export const runAppHook = async (appName, hook) => {
|
|
9
|
+
const packageJsonPath = path.join(getAppDirectory(appName), 'package.json');
|
|
10
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
14
|
+
const scriptName = `qpq:${hook}`;
|
|
15
|
+
if (!packageJson.scripts?.[scriptName]) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
console.log(`Running ${scriptName} for [${appName}]`);
|
|
19
|
+
await runCommand('npm', ['run', scriptName], { cwd: getAppDirectory(appName) });
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
export const runAppHookForAllApps = async (hook) => {
|
|
23
|
+
for (const appName of getAvailableApps()) {
|
|
24
|
+
await runAppHook(appName, hook);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/lib/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,0EAA0E;AAC1E,2EAA2E;AAC3E,8CAA8C;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,OAAe,EAAE,IAAY,EAAoB,EAAE;IAClF,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC;IAC5E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,OAAO,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,SAAS,OAAO,GAAG,CAAC,CAAC;IACtD,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,IAAY,EAAiB,EAAE;IACxE,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACzC,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;AACH,CAAC,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { getAppDirectory, getAvailableApps } from './discovery';\nimport { runCommand } from './runCommand';\n\n// App lifecycle hooks: apps/<app>/package.json scripts named `qpq:<hook>`\n// (e.g. qpq:postinstall, qpq:prebuild). The CLI invokes them when present;\n// apps without the hook are skipped silently.\nexport const runAppHook = async (appName: string, hook: string): Promise<boolean> => {\n const packageJsonPath = path.join(getAppDirectory(appName), 'package.json');\n if (!fs.existsSync(packageJsonPath)) {\n return false;\n }\n\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const scriptName = `qpq:${hook}`;\n if (!packageJson.scripts?.[scriptName]) {\n return false;\n }\n\n console.log(`Running ${scriptName} for [${appName}]`);\n await runCommand('npm', ['run', scriptName], { cwd: getAppDirectory(appName) });\n return true;\n};\n\nexport const runAppHookForAllApps = async (hook: string): Promise<void> => {\n for (const appName of getAvailableApps()) {\n await runAppHook(appName, hook);\n }\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getOwnPackageRoot: () => string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
// This package's root (works from src under ts-node and from lib/commonjs).
|
|
4
|
+
export const getOwnPackageRoot = () => {
|
|
5
|
+
let dir = __dirname;
|
|
6
|
+
while (!fs.existsSync(path.join(dir, 'package.json'))) {
|
|
7
|
+
const parent = path.dirname(dir);
|
|
8
|
+
if (parent === dir)
|
|
9
|
+
throw new Error('Could not locate the quidproquo-cli package root');
|
|
10
|
+
dir = parent;
|
|
11
|
+
}
|
|
12
|
+
return dir;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=packageRoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packageRoot.js","sourceRoot":"","sources":["../../../src/lib/packageRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAW,EAAE;IAC5C,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACxF,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\n// This package's root (works from src under ts-node and from lib/commonjs).\nexport const getOwnPackageRoot = (): string => {\n let dir = __dirname;\n while (!fs.existsSync(path.join(dir, 'package.json'))) {\n const parent = path.dirname(dir);\n if (parent === dir) throw new Error('Could not locate the quidproquo-cli package root');\n dir = parent;\n }\n return dir;\n};\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Present a single-choice list prompt and return the selected value.
|
|
2
|
+
// @inquirer/prompts is imported lazily so commands only pay for it when
|
|
3
|
+
// actually prompting.
|
|
4
|
+
export const promptSelect = async (message, choices, defaultChoice) => {
|
|
5
|
+
const { select } = await import('@inquirer/prompts');
|
|
6
|
+
return select({ message, choices, default: defaultChoice });
|
|
7
|
+
};
|
|
8
|
+
// A yes/no list prompt, returning true for "Yes".
|
|
9
|
+
export const promptYesNo = async (message) => (await promptSelect(message, ['No', 'Yes'])) === 'Yes';
|
|
10
|
+
// A free-text prompt — used where a y/n is too easy to fat-finger (destructive
|
|
11
|
+
// confirmations that require typing the target name back).
|
|
12
|
+
export const promptText = async (message) => {
|
|
13
|
+
const { input } = await import('@inquirer/prompts');
|
|
14
|
+
return input({ message });
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/lib/prompts.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,wEAAwE;AACxE,sBAAsB;AACtB,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,OAAe,EAAE,OAAiB,EAAE,aAAsB,EAAmB,EAAE;IAChH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,OAAe,EAAoB,EAAE,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;AAE/H,+EAA+E;AAC/E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,OAAe,EAAmB,EAAE;IACnE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC","sourcesContent":["// Present a single-choice list prompt and return the selected value.\n// @inquirer/prompts is imported lazily so commands only pay for it when\n// actually prompting.\nexport const promptSelect = async (message: string, choices: string[], defaultChoice?: string): Promise<string> => {\n const { select } = await import('@inquirer/prompts');\n return select({ message, choices, default: defaultChoice });\n};\n\n// A yes/no list prompt, returning true for \"Yes\".\nexport const promptYesNo = async (message: string): Promise<boolean> => (await promptSelect(message, ['No', 'Yes'])) === 'Yes';\n\n// A free-text prompt — used where a y/n is too easy to fat-finger (destructive\n// confirmations that require typing the target name back).\nexport const promptText = async (message: string): Promise<string> => {\n const { input } = await import('@inquirer/prompts');\n return input({ message });\n};\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { qpqCoreUtils } from 'quidproquo-core';
|
|
2
|
+
import { getWorkspaceServiceQpqConfig } from 'quidproquo-deploy-awscdk';
|
|
3
|
+
import { getRoot, getServiceNames } from './discovery';
|
|
4
|
+
// Loads a service's live infrastructure.ts (qpq runs with ts-node hooks
|
|
5
|
+
// registered, so requiring TS works and `@scope/*` imports resolve through
|
|
6
|
+
// workspace symlinks).
|
|
7
|
+
export const loadServiceQpqConfig = (appName, service) => getWorkspaceServiceQpqConfig(getRoot(), appName, service);
|
|
8
|
+
export const getAppPrefix = (appName) => {
|
|
9
|
+
const services = getServiceNames(appName);
|
|
10
|
+
if (services.length === 0)
|
|
11
|
+
throw new Error(`No services found for app ${appName}`);
|
|
12
|
+
return qpqCoreUtils.getApplicationName(loadServiceQpqConfig(appName, services[0]));
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=qpqConfigs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qpqConfigs.js","sourceRoot":"","sources":["../../../src/lib/qpqConfigs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvD,wEAAwE;AACxE,2EAA2E;AAC3E,uBAAuB;AACvB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAe,EAAE,OAAe,EAAa,EAAE,CAAC,4BAA4B,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAE/I,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAU,EAAE;IACtD,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IACnF,OAAO,YAAY,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,CAAC","sourcesContent":["import { type QPQConfig, qpqCoreUtils } from 'quidproquo-core';\nimport { getWorkspaceServiceQpqConfig } from 'quidproquo-deploy-awscdk';\n\nimport { getRoot, getServiceNames } from './discovery';\n\n// Loads a service's live infrastructure.ts (qpq runs with ts-node hooks\n// registered, so requiring TS works and `@scope/*` imports resolve through\n// workspace symlinks).\nexport const loadServiceQpqConfig = (appName: string, service: string): QPQConfig => getWorkspaceServiceQpqConfig(getRoot(), appName, service);\n\nexport const getAppPrefix = (appName: string): string => {\n const services = getServiceNames(appName);\n if (services.length === 0) throw new Error(`No services found for app ${appName}`);\n return qpqCoreUtils.getApplicationName(loadServiceQpqConfig(appName, services[0]));\n};\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// One app-selection contract for every app-facing command (prep / synth / go /
|
|
2
|
+
// go:dev / go:dev:web / publish). Resolution order:
|
|
3
|
+
// 1. --app <name> / --app=<name> on argv
|
|
4
|
+
// 2. npm_config_app (npm run x --app foo, no --)
|
|
5
|
+
// 3. an env var the command already honours (QPQ_DEV_APP / DEPLOY_APP_NAME)
|
|
6
|
+
// 4. exactly one app under apps/ -> auto-select
|
|
7
|
+
// 5. interactive prompt (TTY only)
|
|
8
|
+
// 6. otherwise: print the valid app list and exit non-zero
|
|
9
|
+
// An unknown name (from any source) also prints the list and exits non-zero.
|
|
10
|
+
// Commands that can meaningfully run for every app may pass allowAll to accept
|
|
11
|
+
// `--app all` (returned as the literal 'all').
|
|
12
|
+
import { getArgValue } from './args';
|
|
13
|
+
import { getAvailableApps } from './discovery';
|
|
14
|
+
import { promptSelect } from './prompts';
|
|
15
|
+
const exitWithAppList = (requested, availableApps) => {
|
|
16
|
+
if (requested)
|
|
17
|
+
console.error(`Unknown app '${requested}'.`);
|
|
18
|
+
console.error(`Valid apps: ${availableApps.join(', ')}`);
|
|
19
|
+
console.error(`Pass one with --app <name> (e.g. qpq <command> --app ${availableApps[0]}).`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
};
|
|
22
|
+
export const resolveAppSelection = async (options) => {
|
|
23
|
+
const availableApps = getAvailableApps();
|
|
24
|
+
if (availableApps.length === 0) {
|
|
25
|
+
console.error('No apps found under apps/.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
const requested = getArgValue(options.argv, '--app') || process.env.npm_config_app || (options.envVar ? process.env[options.envVar] : undefined);
|
|
29
|
+
if (requested) {
|
|
30
|
+
if (options.allowAll && requested === 'all')
|
|
31
|
+
return 'all';
|
|
32
|
+
if (!availableApps.includes(requested))
|
|
33
|
+
exitWithAppList(requested, availableApps);
|
|
34
|
+
return requested;
|
|
35
|
+
}
|
|
36
|
+
if (availableApps.length === 1) {
|
|
37
|
+
console.log(`Using app: ${availableApps[0]}`);
|
|
38
|
+
return availableApps[0];
|
|
39
|
+
}
|
|
40
|
+
if (process.stdin.isTTY) {
|
|
41
|
+
return promptSelect('Select app', options.allowAll ? [...availableApps, 'all'] : availableApps);
|
|
42
|
+
}
|
|
43
|
+
return exitWithAppList(undefined, availableApps);
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=resolveAppSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveAppSelection.js","sourceRoot":"","sources":["../../../src/lib/resolveAppSelection.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,oDAAoD;AACpD,2CAA2C;AAC3C,+EAA+E;AAC/E,kFAAkF;AAClF,kDAAkD;AAClD,qCAAqC;AACrC,6DAA6D;AAC7D,6EAA6E;AAC7E,+EAA+E;AAC/E,+CAA+C;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAUzC,MAAM,eAAe,GAAG,CAAC,SAA6B,EAAE,aAAuB,EAAS,EAAE;IACxF,IAAI,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,IAAI,CAAC,CAAC;IAC5D,OAAO,CAAC,KAAK,CAAC,eAAe,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,CAAC,wDAAwD,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EAAE,OAA0B,EAAmB,EAAE;IACvF,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IACzC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GACb,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAEjI,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,OAAO,CAAC,QAAQ,IAAI,SAAS,KAAK,KAAK;YAAE,OAAO,KAAK,CAAC;QAC1D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,eAAe,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAClF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,cAAc,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9C,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,eAAe,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AACnD,CAAC,CAAC","sourcesContent":["// One app-selection contract for every app-facing command (prep / synth / go /\n// go:dev / go:dev:web / publish). Resolution order:\n// 1. --app <name> / --app=<name> on argv\n// 2. npm_config_app (npm run x --app foo, no --)\n// 3. an env var the command already honours (QPQ_DEV_APP / DEPLOY_APP_NAME)\n// 4. exactly one app under apps/ -> auto-select\n// 5. interactive prompt (TTY only)\n// 6. otherwise: print the valid app list and exit non-zero\n// An unknown name (from any source) also prints the list and exits non-zero.\n// Commands that can meaningfully run for every app may pass allowAll to accept\n// `--app all` (returned as the literal 'all').\nimport { getArgValue } from './args';\nimport { getAvailableApps } from './discovery';\nimport { promptSelect } from './prompts';\n\nexport type ResolveAppOptions = {\n argv: string[];\n // Env var this command historically honours (e.g. QPQ_DEV_APP, DEPLOY_APP_NAME).\n envVar?: string;\n // Accept `--app all` and return 'all'.\n allowAll?: boolean;\n};\n\nconst exitWithAppList = (requested: string | undefined, availableApps: string[]): never => {\n if (requested) console.error(`Unknown app '${requested}'.`);\n console.error(`Valid apps: ${availableApps.join(', ')}`);\n console.error(`Pass one with --app <name> (e.g. qpq <command> --app ${availableApps[0]}).`);\n process.exit(1);\n};\n\nexport const resolveAppSelection = async (options: ResolveAppOptions): Promise<string> => {\n const availableApps = getAvailableApps();\n if (availableApps.length === 0) {\n console.error('No apps found under apps/.');\n process.exit(1);\n }\n\n const requested =\n getArgValue(options.argv, '--app') || process.env.npm_config_app || (options.envVar ? process.env[options.envVar] : undefined);\n\n if (requested) {\n if (options.allowAll && requested === 'all') return 'all';\n if (!availableApps.includes(requested)) exitWithAppList(requested, availableApps);\n return requested;\n }\n\n if (availableApps.length === 1) {\n console.log(`Using app: ${availableApps[0]}`);\n return availableApps[0];\n }\n\n if (process.stdin.isTTY) {\n return promptSelect('Select app', options.allowAll ? [...availableApps, 'all'] : availableApps);\n }\n\n return exitWithAppList(undefined, availableApps);\n};\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { rspack } from '@rspack/core';
|
|
2
|
+
// One-shot rspack build as a promise. Rejects on compiler error or stats
|
|
3
|
+
// errors so a failed bundle stops the run.
|
|
4
|
+
export const runRspack = (config) => new Promise((resolve, reject) => {
|
|
5
|
+
rspack(config, (err, stats) => {
|
|
6
|
+
if (err)
|
|
7
|
+
return reject(err);
|
|
8
|
+
if (stats?.hasErrors())
|
|
9
|
+
return reject(new Error(stats.toString({ errors: true, colors: false })));
|
|
10
|
+
console.log(stats?.toString({
|
|
11
|
+
colors: false,
|
|
12
|
+
chunks: false,
|
|
13
|
+
modules: false,
|
|
14
|
+
assets: true,
|
|
15
|
+
}));
|
|
16
|
+
return resolve();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=rspackRun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rspackRun.js","sourceRoot":"","sources":["../../../src/lib/rspackRun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,MAAM,cAAc,CAAC;AAErD,yEAAyE;AACzE,2CAA2C;AAC3C,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAqB,EAAiB,EAAE,CAChE,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC5B,IAAI,GAAG;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,KAAK,EAAE,SAAS,EAAE;YAAE,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,GAAG,CACT,KAAK,EAAE,QAAQ,CAAC;YACd,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;QACF,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { Configuration, rspack } from '@rspack/core';\n\n// One-shot rspack build as a promise. Rejects on compiler error or stats\n// errors so a failed bundle stops the run.\nexport const runRspack = (config: Configuration): Promise<void> =>\n new Promise((resolve, reject) => {\n rspack(config, (err, stats) => {\n if (err) return reject(err);\n if (stats?.hasErrors()) return reject(new Error(stats.toString({ errors: true, colors: false })));\n console.log(\n stats?.toString({\n colors: false,\n chunks: false,\n modules: false,\n assets: true,\n }),\n );\n return resolve();\n });\n });\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type RunCommandOptions = {
|
|
2
|
+
env?: Record<string, string>;
|
|
3
|
+
cwd?: string;
|
|
4
|
+
logCommand?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const runCommand: (command: string, args: string[], options?: RunCommandOptions) => Promise<void>;
|
|
7
|
+
export type RunCommandPrefixedOptions = {
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
cwd?: string;
|
|
10
|
+
color?: number;
|
|
11
|
+
};
|
|
12
|
+
export declare const nextPrefixColor: () => number;
|
|
13
|
+
export declare const runCommandPrefixed: (label: string, command: string, args: string[], options?: RunCommandPrefixedOptions) => Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
// Spawn a command, inheriting stdio, resolving on success. A non-zero exit
|
|
3
|
+
// REJECTS so a failed build/deploy stops the run.
|
|
4
|
+
export const runCommand = (command, args, options = {}) => new Promise((resolve, reject) => {
|
|
5
|
+
const validArgs = args.filter((a) => !!a);
|
|
6
|
+
if (options.logCommand) {
|
|
7
|
+
console.log(`Running command: ${command} ${validArgs.join(' ')}`);
|
|
8
|
+
}
|
|
9
|
+
const child = spawn(command, validArgs, {
|
|
10
|
+
stdio: 'inherit',
|
|
11
|
+
shell: true,
|
|
12
|
+
cwd: options.cwd ?? process.cwd(),
|
|
13
|
+
env: { ...process.env, ...(options.env ?? {}) },
|
|
14
|
+
});
|
|
15
|
+
child.on('error', (error) => reject(error));
|
|
16
|
+
child.on('exit', (code, signal) => {
|
|
17
|
+
if (signal)
|
|
18
|
+
return reject(new Error(`${command} was killed with signal ${signal}`));
|
|
19
|
+
if (code)
|
|
20
|
+
return reject(new Error(`${command} ${validArgs.join(' ')} exited with code ${code}`));
|
|
21
|
+
return resolve();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
const PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];
|
|
25
|
+
let colorIndex = 0;
|
|
26
|
+
// Hand each concurrent task a distinct prefix color so interleaved output is
|
|
27
|
+
// scannable.
|
|
28
|
+
export const nextPrefixColor = () => {
|
|
29
|
+
const color = PREFIX_COLORS[colorIndex % PREFIX_COLORS.length];
|
|
30
|
+
colorIndex += 1;
|
|
31
|
+
return color;
|
|
32
|
+
};
|
|
33
|
+
// Like runCommand, but pipes output and prefixes every line with a colored
|
|
34
|
+
// [label] — for running many commands concurrently without unreadable
|
|
35
|
+
// interleaving. Rejects on non-zero exit.
|
|
36
|
+
export const runCommandPrefixed = (label, command, args, options = {}) => new Promise((resolve, reject) => {
|
|
37
|
+
const validArgs = args.filter((a) => !!a);
|
|
38
|
+
const prefix = `\x1b[${options.color ?? 36}m[${label}]\x1b[0m `;
|
|
39
|
+
const child = spawn(command, validArgs, {
|
|
40
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
|
+
shell: true,
|
|
42
|
+
cwd: options.cwd ?? process.cwd(),
|
|
43
|
+
env: { ...process.env, ...(options.env ?? {}) },
|
|
44
|
+
});
|
|
45
|
+
const attach = (stream, out) => {
|
|
46
|
+
let buffered = '';
|
|
47
|
+
stream.on('data', (chunk) => {
|
|
48
|
+
buffered += chunk.toString();
|
|
49
|
+
const lines = buffered.split('\n');
|
|
50
|
+
buffered = lines.pop() ?? '';
|
|
51
|
+
lines.forEach((line) => out.write(`${prefix}${line}\n`));
|
|
52
|
+
});
|
|
53
|
+
stream.on('end', () => {
|
|
54
|
+
if (buffered)
|
|
55
|
+
out.write(`${prefix}${buffered}\n`);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
attach(child.stdout, process.stdout);
|
|
59
|
+
attach(child.stderr, process.stderr);
|
|
60
|
+
child.on('error', (error) => reject(error));
|
|
61
|
+
child.on('exit', (code, signal) => {
|
|
62
|
+
if (signal)
|
|
63
|
+
return reject(new Error(`[${label}] ${command} was killed with signal ${signal}`));
|
|
64
|
+
if (code)
|
|
65
|
+
return reject(new Error(`[${label}] ${command} exited with code ${code}`));
|
|
66
|
+
return resolve();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=runCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../../src/lib/runCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'child_process';\nimport type { Readable } from 'stream';\n\nexport type RunCommandOptions = {\n // Extra environment variables merged over the parent process env.\n env?: Record<string, string>;\n // Working directory for the child (defaults to cwd).\n cwd?: string;\n // Echo the command before running it.\n logCommand?: boolean;\n};\n\n// Spawn a command, inheriting stdio, resolving on success. A non-zero exit\n// REJECTS so a failed build/deploy stops the run.\nexport const runCommand = (command: string, args: string[], options: RunCommandOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n\n if (options.logCommand) {\n console.log(`Running command: ${command} ${validArgs.join(' ')}`);\n }\n\n const child = spawn(command, validArgs, {\n stdio: 'inherit',\n shell: true,\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`${command} ${validArgs.join(' ')} exited with code ${code}`));\n return resolve();\n });\n });\n\nexport type RunCommandPrefixedOptions = {\n env?: Record<string, string>;\n cwd?: string;\n // ANSI color code for the prefix (see nextPrefixColor).\n color?: number;\n};\n\nconst PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];\nlet colorIndex = 0;\n\n// Hand each concurrent task a distinct prefix color so interleaved output is\n// scannable.\nexport const nextPrefixColor = (): number => {\n const color = PREFIX_COLORS[colorIndex % PREFIX_COLORS.length];\n colorIndex += 1;\n return color;\n};\n\n// Like runCommand, but pipes output and prefixes every line with a colored\n// [label] — for running many commands concurrently without unreadable\n// interleaving. Rejects on non-zero exit.\nexport const runCommandPrefixed = (label: string, command: string, args: string[], options: RunCommandPrefixedOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n const prefix = `\\x1b[${options.color ?? 36}m[${label}]\\x1b[0m `;\n\n const child = spawn(command, validArgs, {\n stdio: ['ignore', 'pipe', 'pipe'],\n shell: true,\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n const attach = (stream: Readable, out: NodeJS.WriteStream): void => {\n let buffered = '';\n stream.on('data', (chunk: Buffer) => {\n buffered += chunk.toString();\n const lines = buffered.split('\\n');\n buffered = lines.pop() ?? '';\n lines.forEach((line) => out.write(`${prefix}${line}\\n`));\n });\n stream.on('end', () => {\n if (buffered) out.write(`${prefix}${buffered}\\n`);\n });\n };\n\n attach(child.stdout as Readable, process.stdout);\n attach(child.stderr as Readable, process.stderr);\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`[${label}] ${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`[${label}] ${command} exited with code ${code}`));\n return resolve();\n });\n });\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Task = {
|
|
2
|
+
label: string;
|
|
3
|
+
run: () => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export type TaskFailure = {
|
|
6
|
+
label: string;
|
|
7
|
+
error: Error;
|
|
8
|
+
};
|
|
9
|
+
export declare const runTasks: (tasks: Task[], limit: number) => Promise<TaskFailure[]>;
|
|
10
|
+
export declare const assertNoFailures: (phaseName: string, failures: TaskFailure[]) => void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Run tasks with at most `limit` in flight; never rejects — failures come back
|
|
2
|
+
// labelled so a whole wave can finish before we report what broke.
|
|
3
|
+
export const runTasks = async (tasks, limit) => {
|
|
4
|
+
const failures = [];
|
|
5
|
+
let nextIndex = 0;
|
|
6
|
+
const workerCount = Math.max(1, Math.min(limit, tasks.length));
|
|
7
|
+
await Promise.all(Array.from({ length: workerCount }, async () => {
|
|
8
|
+
while (nextIndex < tasks.length) {
|
|
9
|
+
const task = tasks[nextIndex];
|
|
10
|
+
nextIndex += 1;
|
|
11
|
+
try {
|
|
12
|
+
await task.run();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
failures.push({ label: task.label, error: error });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
return failures;
|
|
20
|
+
};
|
|
21
|
+
export const assertNoFailures = (phaseName, failures) => {
|
|
22
|
+
if (failures.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
console.error(`\n${phaseName} failed for:`);
|
|
25
|
+
failures.forEach((failure) => console.error(` ${failure.label}: ${failure.error.message}`));
|
|
26
|
+
throw new Error(`${phaseName}: ${failures.length} task(s) failed`);
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=runTasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTasks.js","sourceRoot":"","sources":["../../../src/lib/runTasks.ts"],"names":[],"mappings":"AAGA,+EAA+E;AAC/E,mEAAmE;AACnE,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAa,EAAE,KAAa,EAA0B,EAAE;IACrF,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE;QAC7C,OAAO,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;YAC9B,SAAS,IAAI,CAAC,CAAC;YACf,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAc,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAiB,EAAE,QAAuB,EAAQ,EAAE;IACnF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAClC,OAAO,CAAC,KAAK,CAAC,KAAK,SAAS,cAAc,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7F,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,KAAK,QAAQ,CAAC,MAAM,iBAAiB,CAAC,CAAC;AACrE,CAAC,CAAC","sourcesContent":["export type Task = { label: string; run: () => Promise<void> };\nexport type TaskFailure = { label: string; error: Error };\n\n// Run tasks with at most `limit` in flight; never rejects — failures come back\n// labelled so a whole wave can finish before we report what broke.\nexport const runTasks = async (tasks: Task[], limit: number): Promise<TaskFailure[]> => {\n const failures: TaskFailure[] = [];\n let nextIndex = 0;\n\n const workerCount = Math.max(1, Math.min(limit, tasks.length));\n await Promise.all(\n Array.from({ length: workerCount }, async () => {\n while (nextIndex < tasks.length) {\n const task = tasks[nextIndex];\n nextIndex += 1;\n try {\n await task.run();\n } catch (error) {\n failures.push({ label: task.label, error: error as Error });\n }\n }\n }),\n );\n\n return failures;\n};\n\nexport const assertNoFailures = (phaseName: string, failures: TaskFailure[]): void => {\n if (failures.length === 0) return;\n console.error(`\\n${phaseName} failed for:`);\n failures.forEach((failure) => console.error(` ${failure.label}: ${failure.error.message}`));\n throw new Error(`${phaseName}: ${failures.length} task(s) failed`);\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../../../src/lib/timing.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAQ,EAAE;IAC/C,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC,CAAC","sourcesContent":["export const logTimeStart = (name: string): void => console.time(name);\n\nexport const logTimeEnd = (name: string): void => {\n console.log('When:', new Date().toLocaleTimeString());\n console.timeEnd(name);\n};\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Views build — programmatic (getViewsRspackConfig), platform-neutral. Where
|
|
2
|
+
// the built views get hosted is a platform driver concern (see
|
|
3
|
+
// platforms/<platform>/viewsSync).
|
|
4
|
+
import { getViewsRspackConfig } from 'quidproquo-deploy-rspack';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { getRoot, getServiceDirectory } from './discovery';
|
|
7
|
+
import { runRspack } from './rspackRun';
|
|
8
|
+
export const bundleViews = async (appName, serviceName) => {
|
|
9
|
+
const viewsDir = path.join(getServiceDirectory(appName, serviceName), 'views');
|
|
10
|
+
process.env.NODE_ENV = 'production';
|
|
11
|
+
delete process.env.LOCAL_DEV_SERVER;
|
|
12
|
+
await runRspack(getViewsRspackConfig(viewsDir));
|
|
13
|
+
};
|
|
14
|
+
export const getViewsDistDir = (appName, serviceName) => path.join(getRoot(), 'dist', 'apps', appName, 'services', serviceName, 'views');
|
|
15
|
+
//# sourceMappingURL=views.js.map
|