quidproquo-cli 0.1.19 → 0.1.21

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.
Files changed (130) hide show
  1. package/README.md +1 -0
  2. package/lib/commonjs/cli/commandRegistry.js +6 -0
  3. package/lib/commonjs/cli/commandRegistry.js.map +1 -1
  4. package/lib/commonjs/commands/goDevApi.js +18 -5
  5. package/lib/commonjs/commands/goDevApi.js.map +1 -1
  6. package/lib/commonjs/commands/goDevWeb.js +10 -2
  7. package/lib/commonjs/commands/goDevWeb.js.map +1 -1
  8. package/lib/commonjs/commands/setup.d.ts +1 -0
  9. package/lib/commonjs/commands/setup.js +102 -0
  10. package/lib/commonjs/commands/setup.js.map +1 -0
  11. package/lib/commonjs/lib/args.d.ts +1 -0
  12. package/lib/commonjs/lib/args.js +11 -1
  13. package/lib/commonjs/lib/args.js.map +1 -1
  14. package/lib/commonjs/lib/keepOtherDevServersFlag.d.ts +1 -0
  15. package/lib/commonjs/lib/keepOtherDevServersFlag.js +11 -0
  16. package/lib/commonjs/lib/keepOtherDevServersFlag.js.map +1 -0
  17. package/lib/commonjs/lib/killStaleListeners.d.ts +14 -0
  18. package/lib/commonjs/lib/killStaleListeners.js +47 -20
  19. package/lib/commonjs/lib/killStaleListeners.js.map +1 -1
  20. package/lib/commonjs/lib/prompts.d.ts +2 -0
  21. package/lib/commonjs/lib/prompts.js +1 -1
  22. package/lib/commonjs/lib/prompts.js.map +1 -1
  23. package/lib/commonjs/lib/setupStep.d.ts +16 -0
  24. package/lib/commonjs/lib/setupStep.js +3 -0
  25. package/lib/commonjs/lib/setupStep.js.map +1 -0
  26. package/lib/commonjs/platforms/aws/index.js +2 -0
  27. package/lib/commonjs/platforms/aws/index.js.map +1 -1
  28. package/lib/commonjs/platforms/aws/setup/awsSetupContext.d.ts +12 -0
  29. package/lib/commonjs/platforms/aws/setup/awsSetupContext.js +23 -0
  30. package/lib/commonjs/platforms/aws/setup/awsSetupContext.js.map +1 -0
  31. package/lib/commonjs/platforms/aws/setup/awsSetupSteps.d.ts +8 -0
  32. package/lib/commonjs/platforms/aws/setup/awsSetupSteps.js +44 -0
  33. package/lib/commonjs/platforms/aws/setup/awsSetupSteps.js.map +1 -0
  34. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.d.ts +4 -0
  35. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js +77 -0
  36. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js.map +1 -0
  37. package/lib/commonjs/platforms/aws/setup/buildCdkBootstrapSteps.d.ts +5 -0
  38. package/lib/commonjs/platforms/aws/setup/buildCdkBootstrapSteps.js +38 -0
  39. package/lib/commonjs/platforms/aws/setup/buildCdkBootstrapSteps.js.map +1 -0
  40. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.d.ts +4 -0
  41. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js +55 -0
  42. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -0
  43. package/lib/commonjs/platforms/aws/setup/buildGithubOidcProviderStep.d.ts +4 -0
  44. package/lib/commonjs/platforms/aws/setup/buildGithubOidcProviderStep.js +54 -0
  45. package/lib/commonjs/platforms/aws/setup/buildGithubOidcProviderStep.js.map +1 -0
  46. package/lib/commonjs/platforms/aws/setup/buildHostedZonesStep.d.ts +4 -0
  47. package/lib/commonjs/platforms/aws/setup/buildHostedZonesStep.js +63 -0
  48. package/lib/commonjs/platforms/aws/setup/buildHostedZonesStep.js.map +1 -0
  49. package/lib/commonjs/platforms/aws/setup/buildIamCapabilityStep.d.ts +4 -0
  50. package/lib/commonjs/platforms/aws/setup/buildIamCapabilityStep.js +48 -0
  51. package/lib/commonjs/platforms/aws/setup/buildIamCapabilityStep.js.map +1 -0
  52. package/lib/commonjs/platforms/aws/setup/buildIdentityStep.d.ts +4 -0
  53. package/lib/commonjs/platforms/aws/setup/buildIdentityStep.js +39 -0
  54. package/lib/commonjs/platforms/aws/setup/buildIdentityStep.js.map +1 -0
  55. package/lib/commonjs/platforms/aws/setup/buildStackSteps.d.ts +5 -0
  56. package/lib/commonjs/platforms/aws/setup/buildStackSteps.js +32 -0
  57. package/lib/commonjs/platforms/aws/setup/buildStackSteps.js.map +1 -0
  58. package/lib/commonjs/platforms/aws/setup/describeStackStatus.d.ts +4 -0
  59. package/lib/commonjs/platforms/aws/setup/describeStackStatus.js +32 -0
  60. package/lib/commonjs/platforms/aws/setup/describeStackStatus.js.map +1 -0
  61. package/lib/commonjs/platforms/aws/setup/index.d.ts +1 -0
  62. package/lib/commonjs/platforms/aws/setup/index.js +18 -0
  63. package/lib/commonjs/platforms/aws/setup/index.js.map +1 -0
  64. package/lib/commonjs/platforms/types.d.ts +2 -0
  65. package/lib/commonjs/platforms/types.js.map +1 -1
  66. package/lib/esm/cli/commandRegistry.js +6 -0
  67. package/lib/esm/cli/commandRegistry.js.map +1 -1
  68. package/lib/esm/commands/goDevApi.js +19 -6
  69. package/lib/esm/commands/goDevApi.js.map +1 -1
  70. package/lib/esm/commands/goDevWeb.js +10 -2
  71. package/lib/esm/commands/goDevWeb.js.map +1 -1
  72. package/lib/esm/commands/setup.d.ts +1 -0
  73. package/lib/esm/commands/setup.js +88 -0
  74. package/lib/esm/commands/setup.js.map +1 -0
  75. package/lib/esm/lib/args.d.ts +1 -0
  76. package/lib/esm/lib/args.js +9 -0
  77. package/lib/esm/lib/args.js.map +1 -1
  78. package/lib/esm/lib/keepOtherDevServersFlag.d.ts +1 -0
  79. package/lib/esm/lib/keepOtherDevServersFlag.js +8 -0
  80. package/lib/esm/lib/keepOtherDevServersFlag.js.map +1 -0
  81. package/lib/esm/lib/killStaleListeners.d.ts +14 -0
  82. package/lib/esm/lib/killStaleListeners.js +45 -19
  83. package/lib/esm/lib/killStaleListeners.js.map +1 -1
  84. package/lib/esm/lib/prompts.d.ts +2 -0
  85. package/lib/esm/lib/prompts.js +1 -1
  86. package/lib/esm/lib/prompts.js.map +1 -1
  87. package/lib/esm/lib/setupStep.d.ts +16 -0
  88. package/lib/esm/lib/setupStep.js +2 -0
  89. package/lib/esm/lib/setupStep.js.map +1 -0
  90. package/lib/esm/platforms/aws/index.js +2 -0
  91. package/lib/esm/platforms/aws/index.js.map +1 -1
  92. package/lib/esm/platforms/aws/setup/awsSetupContext.d.ts +12 -0
  93. package/lib/esm/platforms/aws/setup/awsSetupContext.js +18 -0
  94. package/lib/esm/platforms/aws/setup/awsSetupContext.js.map +1 -0
  95. package/lib/esm/platforms/aws/setup/awsSetupSteps.d.ts +8 -0
  96. package/lib/esm/platforms/aws/setup/awsSetupSteps.js +31 -0
  97. package/lib/esm/platforms/aws/setup/awsSetupSteps.js.map +1 -0
  98. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.d.ts +4 -0
  99. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js +62 -0
  100. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js.map +1 -0
  101. package/lib/esm/platforms/aws/setup/buildCdkBootstrapSteps.d.ts +5 -0
  102. package/lib/esm/platforms/aws/setup/buildCdkBootstrapSteps.js +24 -0
  103. package/lib/esm/platforms/aws/setup/buildCdkBootstrapSteps.js.map +1 -0
  104. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.d.ts +4 -0
  105. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js +40 -0
  106. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -0
  107. package/lib/esm/platforms/aws/setup/buildGithubOidcProviderStep.d.ts +4 -0
  108. package/lib/esm/platforms/aws/setup/buildGithubOidcProviderStep.js +40 -0
  109. package/lib/esm/platforms/aws/setup/buildGithubOidcProviderStep.js.map +1 -0
  110. package/lib/esm/platforms/aws/setup/buildHostedZonesStep.d.ts +4 -0
  111. package/lib/esm/platforms/aws/setup/buildHostedZonesStep.js +49 -0
  112. package/lib/esm/platforms/aws/setup/buildHostedZonesStep.js.map +1 -0
  113. package/lib/esm/platforms/aws/setup/buildIamCapabilityStep.d.ts +4 -0
  114. package/lib/esm/platforms/aws/setup/buildIamCapabilityStep.js +34 -0
  115. package/lib/esm/platforms/aws/setup/buildIamCapabilityStep.js.map +1 -0
  116. package/lib/esm/platforms/aws/setup/buildIdentityStep.d.ts +4 -0
  117. package/lib/esm/platforms/aws/setup/buildIdentityStep.js +26 -0
  118. package/lib/esm/platforms/aws/setup/buildIdentityStep.js.map +1 -0
  119. package/lib/esm/platforms/aws/setup/buildStackSteps.d.ts +5 -0
  120. package/lib/esm/platforms/aws/setup/buildStackSteps.js +17 -0
  121. package/lib/esm/platforms/aws/setup/buildStackSteps.js.map +1 -0
  122. package/lib/esm/platforms/aws/setup/describeStackStatus.d.ts +4 -0
  123. package/lib/esm/platforms/aws/setup/describeStackStatus.js +17 -0
  124. package/lib/esm/platforms/aws/setup/describeStackStatus.js.map +1 -0
  125. package/lib/esm/platforms/aws/setup/index.d.ts +1 -0
  126. package/lib/esm/platforms/aws/setup/index.js +2 -0
  127. package/lib/esm/platforms/aws/setup/index.js.map +1 -0
  128. package/lib/esm/platforms/types.d.ts +2 -0
  129. package/lib/esm/platforms/types.js.map +1 -1
  130. package/package.json +13 -10
@@ -0,0 +1,24 @@
1
+ import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
2
+ import { getRoot } from '../../../lib/discovery';
3
+ import { runCommand } from '../../../lib/runCommand';
4
+ import { describeStackStatus, isStackHealthy } from './describeStackStatus';
5
+ /** Every region the app deploys into: the deploy region plus each certificate region (us-east-1 for CloudFront). */
6
+ export const getSetupRegions = (ctx) => [
7
+ ...new Set([ctx.region, ...qpqConfigAwsUtils.getDomainCertificateConfigs(ctx.bootstrapQpqConfig).map((cert) => cert.region)]),
8
+ ];
9
+ const buildCdkBootstrapStep = (ctx, region) => ({
10
+ id: `cdk-bootstrap-${region}`,
11
+ name: `CDK bootstrap ${region}`,
12
+ check: async () => {
13
+ const status = await describeStackStatus('CDKToolkit', region);
14
+ if (status === null) {
15
+ return { done: false, detail: 'no CDKToolkit stack' };
16
+ }
17
+ return isStackHealthy(status)
18
+ ? { done: true, detail: `CDKToolkit ${status}` }
19
+ : { done: false, detail: `CDKToolkit is ${status}; delete the stack in ${region} before retrying` };
20
+ },
21
+ run: () => runCommand('npx', ['cdk', 'bootstrap', `aws://${ctx.accountId}/${region}`], { cwd: getRoot() }),
22
+ });
23
+ export const buildCdkBootstrapSteps = (ctx) => getSetupRegions(ctx).map((region) => buildCdkBootstrapStep(ctx, region));
24
+ //# sourceMappingURL=buildCdkBootstrapSteps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildCdkBootstrapSteps.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildCdkBootstrapSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5E,oHAAoH;AACpH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAoB,EAAY,EAAE,CAAC;IACjE,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,iBAAiB,CAAC,2BAA2B,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;CAC9H,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,GAAoB,EAAE,MAAc,EAAa,EAAE,CAAC,CAAC;IAClF,EAAE,EAAE,iBAAiB,MAAM,EAAE;IAC7B,IAAI,EAAE,iBAAiB,MAAM,EAAE;IAC/B,KAAK,EAAE,KAAK,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC/D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QACxD,CAAC;QACD,OAAO,cAAc,CAAC,MAAM,CAAC;YAC3B,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,MAAM,EAAE,EAAE;YAChD,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,MAAM,yBAAyB,MAAM,kBAAkB,EAAE,CAAC;IACxG,CAAC;IACD,GAAG,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC;CAC3G,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAoB,EAAe,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC","sourcesContent":["import { qpqConfigAwsUtils } from 'quidproquo-config-aws';\n\nimport { getRoot } from '../../../lib/discovery';\nimport { runCommand } from '../../../lib/runCommand';\nimport { SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\nimport { describeStackStatus, isStackHealthy } from './describeStackStatus';\n\n/** Every region the app deploys into: the deploy region plus each certificate region (us-east-1 for CloudFront). */\nexport const getSetupRegions = (ctx: AwsSetupContext): string[] => [\n ...new Set([ctx.region, ...qpqConfigAwsUtils.getDomainCertificateConfigs(ctx.bootstrapQpqConfig).map((cert) => cert.region)]),\n];\n\nconst buildCdkBootstrapStep = (ctx: AwsSetupContext, region: string): SetupStep => ({\n id: `cdk-bootstrap-${region}`,\n name: `CDK bootstrap ${region}`,\n check: async () => {\n const status = await describeStackStatus('CDKToolkit', region);\n if (status === null) {\n return { done: false, detail: 'no CDKToolkit stack' };\n }\n return isStackHealthy(status)\n ? { done: true, detail: `CDKToolkit ${status}` }\n : { done: false, detail: `CDKToolkit is ${status}; delete the stack in ${region} before retrying` };\n },\n run: () => runCommand('npx', ['cdk', 'bootstrap', `aws://${ctx.accountId}/${region}`], { cwd: getRoot() }),\n});\n\nexport const buildCdkBootstrapSteps = (ctx: AwsSetupContext): SetupStep[] => getSetupRegions(ctx).map((region) => buildCdkBootstrapStep(ctx, region));\n"]}
@@ -0,0 +1,4 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ /** Check-only: the GitHub Actions deploy role is declared and deployed, with the values the GitHub Environment needs. */
4
+ export declare const buildGithubDeployRoleStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,40 @@
1
+ import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';
2
+ import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
3
+ import { GetRoleCommand, IAMClient } from '@aws-sdk/client-iam';
4
+ // The role itself is deployed by the bootstrap stack; this step tells you whether the config
5
+ // declares it, whether it exists yet, and what to put in the GitHub Environment once it does.
6
+ const checkDeployRole = async (ctx) => {
7
+ const config = qpqConfigAwsUtils.getAwsGithubDeployRoleConfig(ctx.bootstrapQpqConfig);
8
+ if (!config) {
9
+ return { done: false, detail: 'not declared: add defineAwsGithubDeployRole("owner/repo", { ownerId, repositoryId }) to bootstrap.qpq.ts' };
10
+ }
11
+ const roleName = awsNamingUtils.getGithubDeployRoleNameFromConfig(ctx.bootstrapQpqConfig);
12
+ const githubEnvironment = config.githubEnvironment ?? ctx.environment;
13
+ try {
14
+ const { Role } = await new IAMClient({ region: ctx.region }).send(new GetRoleCommand({ RoleName: roleName }));
15
+ return {
16
+ done: true,
17
+ detail: `${Role?.Arn}; GitHub Environment '${githubEnvironment}' needs DEPLOY_ROLE_ARN=<that arn> and AWS_REGION=${ctx.region}`,
18
+ };
19
+ }
20
+ catch (error) {
21
+ if (error instanceof Error && error.name === 'NoSuchEntityException') {
22
+ return { done: false, detail: `${roleName} not deployed yet (the bootstrap stack creates it)` };
23
+ }
24
+ throw error;
25
+ }
26
+ };
27
+ /** Check-only: the GitHub Actions deploy role is declared and deployed, with the values the GitHub Environment needs. */
28
+ export const buildGithubDeployRoleStep = (ctx) => ({
29
+ id: 'github-deploy-role',
30
+ name: 'GitHub Actions deploy role',
31
+ check: () => checkDeployRole(ctx),
32
+ run: async () => {
33
+ const result = await checkDeployRole(ctx);
34
+ if (!result.done) {
35
+ throw new Error(result.detail ?? 'deploy role missing');
36
+ }
37
+ console.log(result.detail);
38
+ },
39
+ });
40
+ //# sourceMappingURL=buildGithubDeployRoleStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildGithubDeployRoleStep.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildGithubDeployRoleStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKhE,6FAA6F;AAC7F,8FAA8F;AAC9F,MAAM,eAAe,GAAG,KAAK,EAAE,GAAoB,EAA6B,EAAE;IAChF,MAAM,MAAM,GAAG,iBAAiB,CAAC,4BAA4B,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,0GAA0G,EAAE,CAAC;IAC7I,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,iCAAiC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC1F,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,IAAI,GAAG,CAAC,WAAW,CAAC;IACtE,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC9G,OAAO;YACL,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,yBAAyB,iBAAiB,qDAAqD,GAAG,CAAC,MAAM,EAAE;SAChI,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,oDAAoD,EAAE,CAAC;QAClG,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,yHAAyH;AACzH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAoB,EAAa,EAAE,CAAC,CAAC;IAC7E,EAAE,EAAE,oBAAoB;IACxB,IAAI,EAAE,4BAA4B;IAClC,KAAK,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC;IACjC,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,qBAAqB,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { qpqConfigAwsUtils } from 'quidproquo-config-aws';\n\nimport { GetRoleCommand, IAMClient } from '@aws-sdk/client-iam';\n\nimport { SetupCheckResult, SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\n\n// The role itself is deployed by the bootstrap stack; this step tells you whether the config\n// declares it, whether it exists yet, and what to put in the GitHub Environment once it does.\nconst checkDeployRole = async (ctx: AwsSetupContext): Promise<SetupCheckResult> => {\n const config = qpqConfigAwsUtils.getAwsGithubDeployRoleConfig(ctx.bootstrapQpqConfig);\n if (!config) {\n return { done: false, detail: 'not declared: add defineAwsGithubDeployRole(\"owner/repo\", { ownerId, repositoryId }) to bootstrap.qpq.ts' };\n }\n\n const roleName = awsNamingUtils.getGithubDeployRoleNameFromConfig(ctx.bootstrapQpqConfig);\n const githubEnvironment = config.githubEnvironment ?? ctx.environment;\n try {\n const { Role } = await new IAMClient({ region: ctx.region }).send(new GetRoleCommand({ RoleName: roleName }));\n return {\n done: true,\n detail: `${Role?.Arn}; GitHub Environment '${githubEnvironment}' needs DEPLOY_ROLE_ARN=<that arn> and AWS_REGION=${ctx.region}`,\n };\n } catch (error) {\n if (error instanceof Error && error.name === 'NoSuchEntityException') {\n return { done: false, detail: `${roleName} not deployed yet (the bootstrap stack creates it)` };\n }\n throw error;\n }\n};\n\n/** Check-only: the GitHub Actions deploy role is declared and deployed, with the values the GitHub Environment needs. */\nexport const buildGithubDeployRoleStep = (ctx: AwsSetupContext): SetupStep => ({\n id: 'github-deploy-role',\n name: 'GitHub Actions deploy role',\n check: () => checkDeployRole(ctx),\n run: async () => {\n const result = await checkDeployRole(ctx);\n if (!result.done) {\n throw new Error(result.detail ?? 'deploy role missing');\n }\n console.log(result.detail);\n },\n});\n"]}
@@ -0,0 +1,4 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ /** Check-only: the account's GitHub Actions OIDC provider is declared in account.qpq.ts and deployed. */
4
+ export declare const buildGithubOidcProviderStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,40 @@
1
+ import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
2
+ import { GetOpenIDConnectProviderCommand, IAMClient } from '@aws-sdk/client-iam';
3
+ // The provider is created by the account stack (defineAccountGithubOidcProvider in
4
+ // account.qpq.ts), so this only reports: declared or not, present or not.
5
+ const checkProvider = async (ctx) => {
6
+ const declared = qpqConfigAwsUtils.isAccountGithubOidcProviderDeclared(ctx.accountQpqConfig);
7
+ const arn = qpqConfigAwsUtils.getGithubOidcProviderArn(ctx.accountId);
8
+ let exists = false;
9
+ try {
10
+ await new IAMClient({ region: ctx.region }).send(new GetOpenIDConnectProviderCommand({ OpenIDConnectProviderArn: arn }));
11
+ exists = true;
12
+ }
13
+ catch (error) {
14
+ if (!(error instanceof Error && error.name === 'NoSuchEntityException')) {
15
+ throw error;
16
+ }
17
+ }
18
+ if (!declared) {
19
+ return {
20
+ done: false,
21
+ detail: exists
22
+ ? `${arn} exists but account.qpq.ts does not declare it: add defineAccountGithubOidcProvider() and delete the hand-made provider before deploying the account stack`
23
+ : 'not declared: add defineAccountGithubOidcProvider() to account.qpq.ts (the account stack creates it)',
24
+ };
25
+ }
26
+ return exists ? { done: true, detail: arn } : { done: false, detail: 'declared, not deployed yet (the account stack creates it)' };
27
+ };
28
+ /** Check-only: the account's GitHub Actions OIDC provider is declared in account.qpq.ts and deployed. */
29
+ export const buildGithubOidcProviderStep = (ctx) => ({
30
+ id: 'github-oidc-provider',
31
+ name: 'GitHub Actions OIDC provider',
32
+ check: () => checkProvider(ctx),
33
+ run: async () => {
34
+ const result = await checkProvider(ctx);
35
+ if (!result.done) {
36
+ throw new Error(result.detail ?? 'provider missing');
37
+ }
38
+ },
39
+ });
40
+ //# sourceMappingURL=buildGithubOidcProviderStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildGithubOidcProviderStep.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildGithubOidcProviderStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,+BAA+B,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKjF,mFAAmF;AACnF,0EAA0E;AAC1E,MAAM,aAAa,GAAG,KAAK,EAAE,GAAoB,EAA6B,EAAE;IAC9E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,mCAAmC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7F,MAAM,GAAG,GAAG,iBAAiB,CAAC,wBAAwB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEtE,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,+BAA+B,CAAC,EAAE,wBAAwB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACzH,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,CAAC,EAAE,CAAC;YACxE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,MAAM;gBACZ,CAAC,CAAC,GAAG,GAAG,4JAA4J;gBACpK,CAAC,CAAC,sGAAsG;SAC3G,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,2DAA2D,EAAE,CAAC;AACrI,CAAC,CAAC;AAEF,yGAAyG;AACzG,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAoB,EAAa,EAAE,CAAC,CAAC;IAC/E,EAAE,EAAE,sBAAsB;IAC1B,IAAI,EAAE,8BAA8B;IACpC,KAAK,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC;IAC/B,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,kBAAkB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { qpqConfigAwsUtils } from 'quidproquo-config-aws';\n\nimport { GetOpenIDConnectProviderCommand, IAMClient } from '@aws-sdk/client-iam';\n\nimport { SetupCheckResult, SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\n\n// The provider is created by the account stack (defineAccountGithubOidcProvider in\n// account.qpq.ts), so this only reports: declared or not, present or not.\nconst checkProvider = async (ctx: AwsSetupContext): Promise<SetupCheckResult> => {\n const declared = qpqConfigAwsUtils.isAccountGithubOidcProviderDeclared(ctx.accountQpqConfig);\n const arn = qpqConfigAwsUtils.getGithubOidcProviderArn(ctx.accountId);\n\n let exists = false;\n try {\n await new IAMClient({ region: ctx.region }).send(new GetOpenIDConnectProviderCommand({ OpenIDConnectProviderArn: arn }));\n exists = true;\n } catch (error) {\n if (!(error instanceof Error && error.name === 'NoSuchEntityException')) {\n throw error;\n }\n }\n\n if (!declared) {\n return {\n done: false,\n detail: exists\n ? `${arn} exists but account.qpq.ts does not declare it: add defineAccountGithubOidcProvider() and delete the hand-made provider before deploying the account stack`\n : 'not declared: add defineAccountGithubOidcProvider() to account.qpq.ts (the account stack creates it)',\n };\n }\n\n return exists ? { done: true, detail: arn } : { done: false, detail: 'declared, not deployed yet (the account stack creates it)' };\n};\n\n/** Check-only: the account's GitHub Actions OIDC provider is declared in account.qpq.ts and deployed. */\nexport const buildGithubOidcProviderStep = (ctx: AwsSetupContext): SetupStep => ({\n id: 'github-oidc-provider',\n name: 'GitHub Actions OIDC provider',\n check: () => checkProvider(ctx),\n run: async () => {\n const result = await checkProvider(ctx);\n if (!result.done) {\n throw new Error(result.detail ?? 'provider missing');\n }\n },\n});\n"]}
@@ -0,0 +1,4 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ /** Check-only: the Route53 zones the deploy will write records into exist in this account. */
4
+ export declare const buildHostedZonesStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,49 @@
1
+ import { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';
2
+ import { qpqWebServerUtils } from 'quidproquo-webserver';
3
+ import { ListHostedZonesByNameCommand, Route53Client } from '@aws-sdk/client-route-53';
4
+ // The zones the environment writes records into: one per root, chosen the way the
5
+ // CDK chooses them (each root's site root under the app's resolver, or the root).
6
+ const getRequiredZones = (ctx) => {
7
+ const config = ctx.bootstrapQpqConfig;
8
+ return [
9
+ ...new Set(qpqWebServerUtils
10
+ .getRootDomains(config)
11
+ .map((rootDomain) => qpqDeployAwsCdkUtils.resolveHostedZoneForHost(config, qpqDeployAwsCdkUtils.resolveDeployHostForRoot(config, rootDomain, {})))),
12
+ ];
13
+ };
14
+ const zoneExists = async (client, zoneName) => {
15
+ const { HostedZones } = await client.send(new ListHostedZonesByNameCommand({ DNSName: zoneName, MaxItems: 1 }));
16
+ return (HostedZones ?? []).some((zone) => zone.Name === `${zoneName}.` && !zone.Config?.PrivateZone);
17
+ };
18
+ const checkHostedZones = async (ctx) => {
19
+ const required = getRequiredZones(ctx);
20
+ if (required.length === 0) {
21
+ return { done: true, detail: 'no domains declared' };
22
+ }
23
+ const client = new Route53Client({ region: ctx.region });
24
+ const missing = [];
25
+ for (const zoneName of required) {
26
+ if (!(await zoneExists(client, zoneName))) {
27
+ missing.push(zoneName);
28
+ }
29
+ }
30
+ return missing.length === 0
31
+ ? { done: true, detail: required.join(', ') }
32
+ : {
33
+ done: false,
34
+ detail: `missing ${missing.join(', ')}: create each as a public hosted zone here and delegate it (NS record) from its parent zone`,
35
+ };
36
+ };
37
+ /** Check-only: the Route53 zones the deploy will write records into exist in this account. */
38
+ export const buildHostedZonesStep = (ctx) => ({
39
+ id: 'hosted-zones',
40
+ name: 'Route53 hosted zones',
41
+ check: () => checkHostedZones(ctx),
42
+ run: async () => {
43
+ const result = await checkHostedZones(ctx);
44
+ if (!result.done) {
45
+ throw new Error(result.detail ?? 'hosted zones missing');
46
+ }
47
+ },
48
+ });
49
+ //# sourceMappingURL=buildHostedZonesStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildHostedZonesStep.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildHostedZonesStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,4BAA4B,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAKvF,kFAAkF;AAClF,kFAAkF;AAClF,MAAM,gBAAgB,GAAG,CAAC,GAAoB,EAAY,EAAE;IAC1D,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACtC,OAAO;QACL,GAAG,IAAI,GAAG,CACR,iBAAiB;aACd,cAAc,CAAC,MAAM,CAAC;aACtB,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAClB,oBAAoB,CAAC,wBAAwB,CAAC,MAAM,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAC7H,CACJ;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,KAAK,EAAE,MAAqB,EAAE,QAAgB,EAAoB,EAAE;IACrF,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,4BAA4B,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChH,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AACvG,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,KAAK,EAAE,GAAoB,EAA6B,EAAE;IACjF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC;QACzB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC7C,CAAC,CAAC;YACE,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,WAAW,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,6FAA6F;SACnI,CAAC;AACR,CAAC,CAAC;AAEF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAoB,EAAa,EAAE,CAAC,CAAC;IACxE,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC;IAClC,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,sBAAsB,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';\nimport { qpqWebServerUtils } from 'quidproquo-webserver';\n\nimport { ListHostedZonesByNameCommand, Route53Client } from '@aws-sdk/client-route-53';\n\nimport { SetupCheckResult, SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\n\n// The zones the environment writes records into: one per root, chosen the way the\n// CDK chooses them (each root's site root under the app's resolver, or the root).\nconst getRequiredZones = (ctx: AwsSetupContext): string[] => {\n const config = ctx.bootstrapQpqConfig;\n return [\n ...new Set(\n qpqWebServerUtils\n .getRootDomains(config)\n .map((rootDomain) =>\n qpqDeployAwsCdkUtils.resolveHostedZoneForHost(config, qpqDeployAwsCdkUtils.resolveDeployHostForRoot(config, rootDomain, {})),\n ),\n ),\n ];\n};\n\nconst zoneExists = async (client: Route53Client, zoneName: string): Promise<boolean> => {\n const { HostedZones } = await client.send(new ListHostedZonesByNameCommand({ DNSName: zoneName, MaxItems: 1 }));\n return (HostedZones ?? []).some((zone) => zone.Name === `${zoneName}.` && !zone.Config?.PrivateZone);\n};\n\nconst checkHostedZones = async (ctx: AwsSetupContext): Promise<SetupCheckResult> => {\n const required = getRequiredZones(ctx);\n if (required.length === 0) {\n return { done: true, detail: 'no domains declared' };\n }\n\n const client = new Route53Client({ region: ctx.region });\n const missing: string[] = [];\n for (const zoneName of required) {\n if (!(await zoneExists(client, zoneName))) {\n missing.push(zoneName);\n }\n }\n\n return missing.length === 0\n ? { done: true, detail: required.join(', ') }\n : {\n done: false,\n detail: `missing ${missing.join(', ')}: create each as a public hosted zone here and delegate it (NS record) from its parent zone`,\n };\n};\n\n/** Check-only: the Route53 zones the deploy will write records into exist in this account. */\nexport const buildHostedZonesStep = (ctx: AwsSetupContext): SetupStep => ({\n id: 'hosted-zones',\n name: 'Route53 hosted zones',\n check: () => checkHostedZones(ctx),\n run: async () => {\n const result = await checkHostedZones(ctx);\n if (!result.done) {\n throw new Error(result.detail ?? 'hosted zones missing');\n }\n },\n});\n"]}
@@ -0,0 +1,4 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ /** Check-only: the credentials can manage IAM, which every CDK deploy needs. */
4
+ export declare const buildIamCapabilityStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,34 @@
1
+ import { GetRoleCommand, IAMClient } from '@aws-sdk/client-iam';
2
+ // CDK bootstrap and every deploy create IAM roles. PowerUserAccess fails on the
3
+ // first iam:GetRole for a cdk-* role, so probe exactly that: a NoSuchEntity
4
+ // answer means the permission is there, AccessDenied means it is not.
5
+ const checkIamCapability = async (ctx) => {
6
+ const roleName = `cdk-hnb659fds-cfn-exec-role-${ctx.accountId}-${ctx.region}`;
7
+ try {
8
+ await new IAMClient({ region: ctx.region }).send(new GetRoleCommand({ RoleName: roleName }));
9
+ return { done: true, detail: 'iam:GetRole allowed' };
10
+ }
11
+ catch (error) {
12
+ const name = error instanceof Error ? error.name : '';
13
+ if (name === 'NoSuchEntityException') {
14
+ return { done: true, detail: 'iam:GetRole allowed' };
15
+ }
16
+ return {
17
+ done: false,
18
+ detail: `iam:GetRole denied (${name}); the permission set needs IAM rights (AdministratorAccess or a custom set adding iam:*)`,
19
+ };
20
+ }
21
+ };
22
+ /** Check-only: the credentials can manage IAM, which every CDK deploy needs. */
23
+ export const buildIamCapabilityStep = (ctx) => ({
24
+ id: 'iam',
25
+ name: 'IAM rights on the credentials',
26
+ check: () => checkIamCapability(ctx),
27
+ run: async () => {
28
+ const result = await checkIamCapability(ctx);
29
+ if (!result.done) {
30
+ throw new Error(result.detail ?? 'IAM rights missing');
31
+ }
32
+ },
33
+ });
34
+ //# sourceMappingURL=buildIamCapabilityStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildIamCapabilityStep.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildIamCapabilityStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAKhE,gFAAgF;AAChF,4EAA4E;AAC5E,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,KAAK,EAAE,GAAoB,EAA6B,EAAE;IACnF,MAAM,QAAQ,GAAG,+BAA+B,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;IAC9E,IAAI,CAAC;QACH,MAAM,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC7F,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,IAAI,IAAI,KAAK,uBAAuB,EAAE,CAAC;YACrC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QACvD,CAAC;QACD,OAAO;YACL,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,uBAAuB,IAAI,2FAA2F;SAC/H,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAoB,EAAa,EAAE,CAAC,CAAC;IAC1E,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,+BAA+B;IACrC,KAAK,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC;IACpC,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,oBAAoB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { GetRoleCommand, IAMClient } from '@aws-sdk/client-iam';\n\nimport { SetupCheckResult, SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\n\n// CDK bootstrap and every deploy create IAM roles. PowerUserAccess fails on the\n// first iam:GetRole for a cdk-* role, so probe exactly that: a NoSuchEntity\n// answer means the permission is there, AccessDenied means it is not.\nconst checkIamCapability = async (ctx: AwsSetupContext): Promise<SetupCheckResult> => {\n const roleName = `cdk-hnb659fds-cfn-exec-role-${ctx.accountId}-${ctx.region}`;\n try {\n await new IAMClient({ region: ctx.region }).send(new GetRoleCommand({ RoleName: roleName }));\n return { done: true, detail: 'iam:GetRole allowed' };\n } catch (error) {\n const name = error instanceof Error ? error.name : '';\n if (name === 'NoSuchEntityException') {\n return { done: true, detail: 'iam:GetRole allowed' };\n }\n return {\n done: false,\n detail: `iam:GetRole denied (${name}); the permission set needs IAM rights (AdministratorAccess or a custom set adding iam:*)`,\n };\n }\n};\n\n/** Check-only: the credentials can manage IAM, which every CDK deploy needs. */\nexport const buildIamCapabilityStep = (ctx: AwsSetupContext): SetupStep => ({\n id: 'iam',\n name: 'IAM rights on the credentials',\n check: () => checkIamCapability(ctx),\n run: async () => {\n const result = await checkIamCapability(ctx);\n if (!result.done) {\n throw new Error(result.detail ?? 'IAM rights missing');\n }\n },\n});\n"]}
@@ -0,0 +1,4 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ /** Check-only: the active credentials belong to the environment's account. Catches a stale .env or SSO profile. */
4
+ export declare const buildIdentityStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,26 @@
1
+ import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts';
2
+ const checkIdentity = async (ctx) => {
3
+ try {
4
+ const { Account, Arn } = await new STSClient({ region: ctx.region }).send(new GetCallerIdentityCommand({}));
5
+ if (Account !== ctx.accountId) {
6
+ return { done: false, detail: `credentials are for account ${Account}, environment '${ctx.environment}' deploys to ${ctx.accountId}` };
7
+ }
8
+ return { done: true, detail: `${Arn}` };
9
+ }
10
+ catch (error) {
11
+ return { done: false, detail: `no valid credentials: ${error instanceof Error ? error.message : String(error)}` };
12
+ }
13
+ };
14
+ /** Check-only: the active credentials belong to the environment's account. Catches a stale .env or SSO profile. */
15
+ export const buildIdentityStep = (ctx) => ({
16
+ id: 'identity',
17
+ name: `Credentials for account ${ctx.accountId}`,
18
+ check: () => checkIdentity(ctx),
19
+ run: async () => {
20
+ const result = await checkIdentity(ctx);
21
+ if (!result.done) {
22
+ throw new Error(`${result.detail}. Log in to the right account (or fix AWS_DEFAULT_ACCOUNT / deploy.config.json) and rerun.`);
23
+ }
24
+ },
25
+ });
26
+ //# sourceMappingURL=buildIdentityStep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildIdentityStep.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildIdentityStep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAK1E,MAAM,aAAa,GAAG,KAAK,EAAE,GAAoB,EAA6B,EAAE;IAC9E,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5G,IAAI,OAAO,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,+BAA+B,OAAO,kBAAkB,GAAG,CAAC,WAAW,gBAAgB,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC;QACzI,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IACpH,CAAC;AACH,CAAC,CAAC;AAEF,mHAAmH;AACnH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAoB,EAAa,EAAE,CAAC,CAAC;IACrE,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,2BAA2B,GAAG,CAAC,SAAS,EAAE;IAChD,KAAK,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC;IAC/B,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,4FAA4F,CAAC,CAAC;QAChI,CAAC;IACH,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts';\n\nimport { SetupCheckResult, SetupStep } from '../../../lib/setupStep';\nimport { AwsSetupContext } from './awsSetupContext';\n\nconst checkIdentity = async (ctx: AwsSetupContext): Promise<SetupCheckResult> => {\n try {\n const { Account, Arn } = await new STSClient({ region: ctx.region }).send(new GetCallerIdentityCommand({}));\n if (Account !== ctx.accountId) {\n return { done: false, detail: `credentials are for account ${Account}, environment '${ctx.environment}' deploys to ${ctx.accountId}` };\n }\n return { done: true, detail: `${Arn}` };\n } catch (error) {\n return { done: false, detail: `no valid credentials: ${error instanceof Error ? error.message : String(error)}` };\n }\n};\n\n/** Check-only: the active credentials belong to the environment's account. Catches a stale .env or SSO profile. */\nexport const buildIdentityStep = (ctx: AwsSetupContext): SetupStep => ({\n id: 'identity',\n name: `Credentials for account ${ctx.accountId}`,\n check: () => checkIdentity(ctx),\n run: async () => {\n const result = await checkIdentity(ctx);\n if (!result.done) {\n throw new Error(`${result.detail}. Log in to the right account (or fix AWS_DEFAULT_ACCOUNT / deploy.config.json) and rerun.`);\n }\n },\n});\n"]}
@@ -0,0 +1,5 @@
1
+ import { SetupStep } from '../../../lib/setupStep';
2
+ import { AwsSetupContext } from './awsSetupContext';
3
+ export declare const buildAccountStackStep: (ctx: AwsSetupContext) => SetupStep;
4
+ export declare const buildDomainStackStep: (ctx: AwsSetupContext) => SetupStep;
5
+ export declare const buildBootstrapStackStep: (ctx: AwsSetupContext) => SetupStep;
@@ -0,0 +1,17 @@
1
+ import { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';
2
+ import { deployAccountStack, deployBootstrapStack, deployDomainStack } from '../stacks';
3
+ import { describeStackStatus, isStackHealthy } from './describeStackStatus';
4
+ const buildStackStep = (id, name, stackName, region, run) => ({
5
+ id,
6
+ name: `${name} (${stackName})`,
7
+ check: async () => {
8
+ const status = await describeStackStatus(stackName, region);
9
+ return status === null ? { done: false, detail: 'not deployed' } : { done: isStackHealthy(status), detail: status };
10
+ },
11
+ run,
12
+ });
13
+ export const buildAccountStackStep = (ctx) => buildStackStep('account-stack', 'Account guardrails stack', qpqDeployAwsCdkUtils.getAccountStackName(), ctx.region, () => deployAccountStack(ctx.appName));
14
+ // The domain stack deploys its cert stacks as dependencies, so one step covers certificates too.
15
+ export const buildDomainStackStep = (ctx) => buildStackStep('domain-stack', 'Domain stack: certificates + api domains', qpqDeployAwsCdkUtils.getDomainStackName(ctx.bootstrapQpqConfig), ctx.region, () => deployDomainStack(ctx.appName));
16
+ export const buildBootstrapStackStep = (ctx) => buildStackStep('bootstrap-stack', 'Bootstrap stack: WAF and app-wide resources', qpqDeployAwsCdkUtils.getBootstrapStackName(ctx.bootstrapQpqConfig), ctx.region, () => deployBootstrapStack(ctx.appName));
17
+ //# sourceMappingURL=buildStackSteps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildStackSteps.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/buildStackSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGhE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAExF,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5E,MAAM,cAAc,GAAG,CAAC,EAAU,EAAE,IAAY,EAAE,SAAiB,EAAE,MAAc,EAAE,GAAwB,EAAa,EAAE,CAAC,CAAC;IAC5H,EAAE;IACF,IAAI,EAAE,GAAG,IAAI,KAAK,SAAS,GAAG;IAC9B,KAAK,EAAE,KAAK,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC5D,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACtH,CAAC;IACD,GAAG;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,GAAoB,EAAa,EAAE,CACvE,cAAc,CAAC,eAAe,EAAE,0BAA0B,EAAE,oBAAoB,CAAC,mBAAmB,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CACvH,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAChC,CAAC;AAEJ,iGAAiG;AACjG,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAoB,EAAa,EAAE,CACtE,cAAc,CACZ,cAAc,EACd,0CAA0C,EAC1C,oBAAoB,CAAC,kBAAkB,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAC/D,GAAG,CAAC,MAAM,EACV,GAAG,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CACrC,CAAC;AAEJ,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAoB,EAAa,EAAE,CACzE,cAAc,CACZ,iBAAiB,EACjB,6CAA6C,EAC7C,oBAAoB,CAAC,qBAAqB,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAClE,GAAG,CAAC,MAAM,EACV,GAAG,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CACxC,CAAC","sourcesContent":["import { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';\n\nimport { SetupStep } from '../../../lib/setupStep';\nimport { deployAccountStack, deployBootstrapStack, deployDomainStack } from '../stacks';\nimport { AwsSetupContext } from './awsSetupContext';\nimport { describeStackStatus, isStackHealthy } from './describeStackStatus';\n\nconst buildStackStep = (id: string, name: string, stackName: string, region: string, run: () => Promise<void>): SetupStep => ({\n id,\n name: `${name} (${stackName})`,\n check: async () => {\n const status = await describeStackStatus(stackName, region);\n return status === null ? { done: false, detail: 'not deployed' } : { done: isStackHealthy(status), detail: status };\n },\n run,\n});\n\nexport const buildAccountStackStep = (ctx: AwsSetupContext): SetupStep =>\n buildStackStep('account-stack', 'Account guardrails stack', qpqDeployAwsCdkUtils.getAccountStackName(), ctx.region, () =>\n deployAccountStack(ctx.appName),\n );\n\n// The domain stack deploys its cert stacks as dependencies, so one step covers certificates too.\nexport const buildDomainStackStep = (ctx: AwsSetupContext): SetupStep =>\n buildStackStep(\n 'domain-stack',\n 'Domain stack: certificates + api domains',\n qpqDeployAwsCdkUtils.getDomainStackName(ctx.bootstrapQpqConfig),\n ctx.region,\n () => deployDomainStack(ctx.appName),\n );\n\nexport const buildBootstrapStackStep = (ctx: AwsSetupContext): SetupStep =>\n buildStackStep(\n 'bootstrap-stack',\n 'Bootstrap stack: WAF and app-wide resources',\n qpqDeployAwsCdkUtils.getBootstrapStackName(ctx.bootstrapQpqConfig),\n ctx.region,\n () => deployBootstrapStack(ctx.appName),\n );\n"]}
@@ -0,0 +1,4 @@
1
+ import { Nullable } from 'quidproquo-core';
2
+ /** A stack's status, or null when it does not exist. */
3
+ export declare const describeStackStatus: (stackName: string, region: string) => Promise<Nullable<string>>;
4
+ export declare const isStackHealthy: (status: Nullable<string>) => boolean;
@@ -0,0 +1,17 @@
1
+ import { CloudFormationClient, DescribeStacksCommand } from '@aws-sdk/client-cloudformation';
2
+ /** A stack's status, or null when it does not exist. */
3
+ export const describeStackStatus = async (stackName, region) => {
4
+ try {
5
+ const { Stacks } = await new CloudFormationClient({ region }).send(new DescribeStacksCommand({ StackName: stackName }));
6
+ return Stacks?.[0]?.StackStatus ?? null;
7
+ }
8
+ catch (error) {
9
+ if (error instanceof Error && /does not exist/.test(error.message)) {
10
+ return null;
11
+ }
12
+ throw error;
13
+ }
14
+ };
15
+ const healthyStatuses = ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'IMPORT_COMPLETE'];
16
+ export const isStackHealthy = (status) => status !== null && healthyStatuses.includes(status);
17
+ //# sourceMappingURL=describeStackStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describeStackStatus.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/describeStackStatus.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE7F,wDAAwD;AACxD,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EAAE,SAAiB,EAAE,MAAc,EAA6B,EAAE;IACxG,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,qBAAqB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QACxH,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,IAAI,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YACnE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAwB,EAAW,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC","sourcesContent":["import { Nullable } from 'quidproquo-core';\n\nimport { CloudFormationClient, DescribeStacksCommand } from '@aws-sdk/client-cloudformation';\n\n/** A stack's status, or null when it does not exist. */\nexport const describeStackStatus = async (stackName: string, region: string): Promise<Nullable<string>> => {\n try {\n const { Stacks } = await new CloudFormationClient({ region }).send(new DescribeStacksCommand({ StackName: stackName }));\n return Stacks?.[0]?.StackStatus ?? null;\n } catch (error) {\n if (error instanceof Error && /does not exist/.test(error.message)) {\n return null;\n }\n throw error;\n }\n};\n\nconst healthyStatuses = ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'IMPORT_COMPLETE'];\n\nexport const isStackHealthy = (status: Nullable<string>): boolean => status !== null && healthyStatuses.includes(status);\n"]}
@@ -0,0 +1 @@
1
+ export * from './awsSetupSteps';
@@ -0,0 +1,2 @@
1
+ export * from './awsSetupSteps';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/platforms/aws/setup/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC","sourcesContent":["export * from './awsSetupSteps';\n"]}
@@ -1,6 +1,7 @@
1
1
  import { QpqAppDeployEnvironment } from 'quidproquo-deploy-awscdk';
2
2
  import { ClearResourcesPlan } from '../lib/clearResourcesPlan';
3
3
  import { DeployPlan, TeardownPlan } from '../lib/deployPrompts';
4
+ import { SetupStep } from '../lib/setupStep';
4
5
  export declare enum QpqDeployPlatform {
5
6
  aws = "aws",
6
7
  docker = "docker"
@@ -11,6 +12,7 @@ export interface QpqPlatformDriver {
11
12
  goDocker?: (appName: string, plan: DeployPlan) => Promise<void>;
12
13
  teardown?: (appName: string, plan: TeardownPlan) => Promise<void>;
13
14
  clearResources?: (appName: string, plan: ClearResourcesPlan) => Promise<void>;
15
+ setupSteps?: (appName: string, environment: string) => Promise<SetupStep[]>;
14
16
  publish: (appName: string, serviceNames: string[]) => Promise<void>;
15
17
  publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;
16
18
  publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/platforms/types.ts"],"names":[],"mappings":"AAKA,MAAM,CAAN,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,gCAAW,CAAA;IACX,sCAAiB,CAAA;AACnB,CAAC,EAHW,iBAAiB,KAAjB,iBAAiB,QAG5B","sourcesContent":["import { QpqAppDeployEnvironment } from 'quidproquo-deploy-awscdk';\n\nimport { ClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { DeployPlan, TeardownPlan } from '../lib/deployPrompts';\n\nexport enum QpqDeployPlatform {\n aws = 'aws',\n docker = 'docker',\n}\n\n// A deploy platform driver — everything that happens after \"what to deploy\"\n// has been decided. `qpq go` resolves the app + environment, prompts the plan,\n// then hands off here; the platform comes from the environment's entry in\n// apps/<app>/deploy.config.json (default aws), so an app can move platforms\n// with a config change instead of a different command.\nexport interface QpqPlatformDriver {\n // Prime process.env with this platform's deploy identity from the resolved\n // environment target (already-set env vars win). Service configs read these\n // vars at load time, so this runs before any infrastructure.ts is required.\n // Returns human-readable descriptions of anything still missing — deploys\n // treat that as fatal, local dev commands ignore it.\n primeDeployIdentity: (target: QpqAppDeployEnvironment | undefined) => string[];\n\n // Sequential deploy (`qpq go`).\n go: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Parallel containerized deploy (`qpq go:docker`) — optional; drivers that\n // have no docker strategy simply omit it.\n goDocker?: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Destroy the web/api/inf stacks for selected services (`qpq teardown`) —\n // optional; drivers with no teardown strategy simply omit it.\n teardown?: (appName: string, plan: TeardownPlan) => Promise<void>;\n\n // Empty the stored data of selected resources without touching the stacks\n // (`qpq clear-resources`) — optional; drivers with no strategy omit it.\n clearResources?: (appName: string, plan: ClearResourcesPlan) => Promise<void>;\n\n // Federated remote publishing (`qpq publish[:build|:upload|:deploy]`).\n publish: (appName: string, serviceNames: string[]) => Promise<void>;\n publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;\n publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;\n publishDeploy: (appName: string, serviceNames: string[]) => Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/platforms/types.ts"],"names":[],"mappings":"AAMA,MAAM,CAAN,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,gCAAW,CAAA;IACX,sCAAiB,CAAA;AACnB,CAAC,EAHW,iBAAiB,KAAjB,iBAAiB,QAG5B","sourcesContent":["import { QpqAppDeployEnvironment } from 'quidproquo-deploy-awscdk';\n\nimport { ClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { DeployPlan, TeardownPlan } from '../lib/deployPrompts';\nimport { SetupStep } from '../lib/setupStep';\n\nexport enum QpqDeployPlatform {\n aws = 'aws',\n docker = 'docker',\n}\n\n// A deploy platform driver — everything that happens after \"what to deploy\"\n// has been decided. `qpq go` resolves the app + environment, prompts the plan,\n// then hands off here; the platform comes from the environment's entry in\n// apps/<app>/deploy.config.json (default aws), so an app can move platforms\n// with a config change instead of a different command.\nexport interface QpqPlatformDriver {\n // Prime process.env with this platform's deploy identity from the resolved\n // environment target (already-set env vars win). Service configs read these\n // vars at load time, so this runs before any infrastructure.ts is required.\n // Returns human-readable descriptions of anything still missing — deploys\n // treat that as fatal, local dev commands ignore it.\n primeDeployIdentity: (target: QpqAppDeployEnvironment | undefined) => string[];\n\n // Sequential deploy (`qpq go`).\n go: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Parallel containerized deploy (`qpq go:docker`) — optional; drivers that\n // have no docker strategy simply omit it.\n goDocker?: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Destroy the web/api/inf stacks for selected services (`qpq teardown`) —\n // optional; drivers with no teardown strategy simply omit it.\n teardown?: (appName: string, plan: TeardownPlan) => Promise<void>;\n\n // Empty the stored data of selected resources without touching the stacks\n // (`qpq clear-resources`) — optional; drivers with no strategy omit it.\n clearResources?: (appName: string, plan: ClearResourcesPlan) => Promise<void>;\n\n // The ordered checklist that takes an empty cloud environment to a deployed\n // one (`qpq setup`) — optional; drivers with nothing to set up omit it.\n setupSteps?: (appName: string, environment: string) => Promise<SetupStep[]>;\n\n // Federated remote publishing (`qpq publish[:build|:upload|:deploy]`).\n publish: (appName: string, serviceNames: string[]) => Promise<void>;\n publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;\n publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;\n publishDeploy: (appName: string, serviceNames: string[]) => Promise<void>;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quidproquo-cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "The qpq CLI — build, dev and deploy orchestration for QPQ apps",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -37,28 +37,31 @@
37
37
  },
38
38
  "homepage": "https://github.com/qpqjs/quidproquo#readme",
39
39
  "dependencies": {
40
+ "@aws-sdk/client-cloudformation": "^3.1093.0",
40
41
  "@aws-sdk/client-dynamodb": "^3.1093.0",
42
+ "@aws-sdk/client-iam": "^3.1093.0",
43
+ "@aws-sdk/client-route-53": "^3.1093.0",
41
44
  "@aws-sdk/client-s3": "^3.1093.0",
42
45
  "@aws-sdk/client-sts": "^3.1093.0",
43
46
  "@inquirer/prompts": "^8.5.2",
44
47
  "@rspack/dev-server": "^2.1.0",
45
48
  "aws-cdk": "^2.1132.1",
46
49
  "madge": "^8.0.0",
47
- "quidproquo": "0.1.19",
48
- "quidproquo-actionprocessor-awslambda": "0.1.19",
49
- "quidproquo-config-aws": "0.1.19",
50
- "quidproquo-core": "0.1.19",
51
- "quidproquo-deploy-awscdk": "0.1.19",
52
- "quidproquo-deploy-rspack": "0.1.19",
53
- "quidproquo-dev-server": "0.1.19",
54
- "quidproquo-webserver": "0.1.19",
50
+ "quidproquo": "0.1.21",
51
+ "quidproquo-actionprocessor-awslambda": "0.1.21",
52
+ "quidproquo-config-aws": "0.1.21",
53
+ "quidproquo-core": "0.1.21",
54
+ "quidproquo-deploy-awscdk": "0.1.21",
55
+ "quidproquo-deploy-rspack": "0.1.21",
56
+ "quidproquo-dev-server": "0.1.21",
57
+ "quidproquo-webserver": "0.1.21",
55
58
  "ts-node": "^10.9.1",
56
59
  "typescript": "^5.8.2"
57
60
  },
58
61
  "devDependencies": {
59
62
  "@rspack/core": "^2.1.2",
60
63
  "@types/node": "^22.13.13",
61
- "quidproquo-tsconfig": "0.1.19"
64
+ "quidproquo-tsconfig": "0.1.21"
62
65
  },
63
66
  "bin": {
64
67
  "qpq": "./lib/commonjs/bin/qpq.js"