@aws/nx-plugin 1.0.0-rc.86 → 1.0.0-rc.87

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 (70) hide show
  1. package/migrations.json +11 -1
  2. package/package.json +1 -1
  3. package/src/infra/app/__snapshots__/generator.spec.ts.snap +34 -8
  4. package/src/infra/app/files/app/README.md.template +14 -0
  5. package/src/infra/app/generator.js +15 -2
  6. package/src/infra/app/generator.js.map +1 -1
  7. package/src/mcp-server/tools/general-guidance.js +1 -1
  8. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  9. package/src/migrations/latest/add-destroy-sandbox-target/metadata.json +3 -0
  10. package/src/migrations/latest/add-destroy-sandbox-target/migration.d.ts +6 -0
  11. package/src/migrations/latest/add-destroy-sandbox-target/migration.js +150 -0
  12. package/src/migrations/latest/add-destroy-sandbox-target/migration.js.map +1 -0
  13. package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/__snapshots__/migration.spec.ts.snap +23 -0
  14. package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/metadata.json +3 -0
  15. package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.d.ts +6 -0
  16. package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js +88 -0
  17. package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js.map +1 -0
  18. package/src/open-api/ts-client/generator.js.map +1 -1
  19. package/src/open-api/ts-hooks/generator.spec.tsx +1 -1
  20. package/src/py/project/generator.js +5 -5
  21. package/src/py/project/generator.js.map +1 -1
  22. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
  23. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +16 -16
  24. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +3 -3
  25. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +3 -3
  26. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +4 -11
  27. package/src/ts/react-website/cognito-auth/generator.js +1 -1
  28. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  29. package/src/ts/react-website/runtime-config/generator.js +1 -1
  30. package/src/ts/react-website/runtime-config/generator.js.map +1 -1
  31. package/src/utils/agent-core-constructs/agent-core-constructs.js +3 -2
  32. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  33. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +1 -1
  34. package/src/utils/api-constructs/api-constructs.js +7 -4
  35. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  36. package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +4 -4
  37. package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +4 -4
  38. package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account.ts.template +1 -1
  39. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +4 -4
  40. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +4 -4
  41. package/src/utils/ast.d.ts +13 -0
  42. package/src/utils/ast.js +36 -0
  43. package/src/utils/ast.js.map +1 -1
  44. package/src/utils/bundle/bundle.js +5 -2
  45. package/src/utils/bundle/bundle.js.map +1 -1
  46. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +5 -3
  47. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -1
  48. package/src/utils/dcr-proxy-constructs/files/cdk/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.ts.template +1 -1
  49. package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +2 -2
  50. package/src/utils/files/common/scripts/src/infra/stage-credentials/cdk-command.ts.template +7 -3
  51. package/src/utils/function-constructs/function-constructs.js +3 -3
  52. package/src/utils/function-constructs/function-constructs.js.map +1 -1
  53. package/src/utils/lambda-runtime-resolution.d.ts +74 -0
  54. package/src/utils/lambda-runtime-resolution.js +97 -0
  55. package/src/utils/lambda-runtime-resolution.js.map +1 -0
  56. package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +3 -3
  57. package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +4 -21
  58. package/src/utils/rdb-constructs/rdb-constructs.js +5 -3
  59. package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
  60. package/src/utils/version-upgrade-migration/sync-lambda-runtimes.d.ts +28 -0
  61. package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js +148 -0
  62. package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js.map +1 -0
  63. package/src/utils/version-upgrade-migration/sync-python-language-version.d.ts +31 -0
  64. package/src/utils/version-upgrade-migration/sync-python-language-version.js +110 -0
  65. package/src/utils/version-upgrade-migration/sync-python-language-version.js.map +1 -0
  66. package/src/utils/version-upgrade-migration/sync-vended-versions.js +36 -7
  67. package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -1
  68. package/src/utils/versions.d.ts +60 -0
  69. package/src/utils/versions.js +51 -0
  70. package/src/utils/versions.js.map +1 -1
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { joinPathFragments } from "@nx/devkit";
5
+ import { applyGritQL, matchGritQL } from "../../../utils/ast.js";
6
+ import { formatFilesInSubtree } from "../../../utils/format.js";
7
+ import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
8
+ /**
9
+ * Give the RDS Proxy role in every vended Terraform Aurora app module the
10
+ * `rds-db:connect` grant for the application database user.
11
+ *
12
+ * The proxy is created with `default_auth_scheme = "IAM_AUTH"` and no secrets
13
+ * registered, so `rds-db:connect` on the application user is the only
14
+ * permission it needs to reach the cluster. MySQL modules instead granted the
15
+ * role `secretsmanager:GetSecretValue` on the admin credentials secret plus
16
+ * `kms:Decrypt` — credentials the proxy never uses, and a far wider grant than
17
+ * connecting as the application user.
18
+ *
19
+ * These files are generated with `KeepExisting`, so an upgraded MySQL workspace
20
+ * keeps the admin secret grant until this runs. Diverged files are left
21
+ * untouched and reported via `nextSteps`.
22
+ */ const TERRAFORM_DBS_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dbs`;
23
+ const hcl = (pattern)=>`language hcl\n${pattern}`;
24
+ const CONNECT_STATEMENT_TEXT = [
25
+ '{',
26
+ ' Effect = "Allow"',
27
+ ' Action = ["rds-db:connect"]',
28
+ ' Resource = [',
29
+ ' "arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.aurora.cluster_resource_id}/${local.database_runtime_user}"',
30
+ ' ]',
31
+ ' }'
32
+ ].join('\n');
33
+ const divergedMessage = (filePath)=>`${filePath}: the aws_iam_role_policy.proxy_db_user_connect policy has diverged from the generated shape - left untouched. The RDS Proxy authenticates to the cluster with IAM, so replace any secretsmanager:GetSecretValue / kms:Decrypt statements on the proxy role with a single rds-db:connect statement for local.database_runtime_user (see the ts#rdb generator's database app template).`;
34
+ const proxyPolicyBlock = (body)=>hcl(`\`resource "aws_iam_role_policy" "proxy_db_user_connect" { ${body} }\``);
35
+ const migrateModule = async (tree, filePath, nextSteps)=>{
36
+ if (!await matchGritQL(tree, filePath, proxyPolicyBlock('$_'))) {
37
+ return; // No proxy policy in this module - nothing this migration owns.
38
+ }
39
+ if (await matchGritQL(tree, filePath, proxyPolicyBlock('$props') + ' where { $props <: contains `"rds-db:connect"` }')) {
40
+ return; // Already granted.
41
+ }
42
+ // The whole statement list is replaced, so the policy must still hold exactly
43
+ // the two statements the generator vended and nothing the user has added.
44
+ const secretStatements = hcl([
45
+ '`Statement = [',
46
+ ' {',
47
+ ' Effect = "Allow"',
48
+ ' Action = [',
49
+ ' "secretsmanager:GetSecretValue"',
50
+ ' ]',
51
+ ' Resource = [module.aurora.secret_arn]',
52
+ ' },',
53
+ ' {',
54
+ ' Effect = "Allow"',
55
+ ' Action = [',
56
+ ' "kms:Decrypt"',
57
+ ' ]',
58
+ ' Resource = [module.aurora.kms_key_arn]',
59
+ ' }',
60
+ ' ]`'
61
+ ].join('\n'));
62
+ if (!await matchGritQL(tree, filePath, secretStatements)) {
63
+ nextSteps.push(divergedMessage(filePath));
64
+ return;
65
+ }
66
+ await applyGritQL(tree, filePath, `${secretStatements} => \`Statement = [\n ${CONNECT_STATEMENT_TEXT}\n ]\``);
67
+ };
68
+ export default async function migration(tree) {
69
+ const nextSteps = [];
70
+ if (!tree.exists(TERRAFORM_DBS_DIR)) {
71
+ return {
72
+ nextSteps
73
+ }; // This workspace has no Terraform database modules.
74
+ }
75
+ for (const dirName of tree.children(TERRAFORM_DBS_DIR)){
76
+ const filePath = joinPathFragments(TERRAFORM_DBS_DIR, dirName, `${dirName}.tf`);
77
+ if (!tree.exists(filePath)) {
78
+ continue; // Not a database app module directory.
79
+ }
80
+ await migrateModule(tree, filePath, nextSteps);
81
+ }
82
+ await formatFilesInSubtree(tree);
83
+ return {
84
+ nextSteps
85
+ };
86
+ }
87
+
88
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Give the RDS Proxy role in every vended Terraform Aurora app module the\n * `rds-db:connect` grant for the application database user.\n *\n * The proxy is created with `default_auth_scheme = \"IAM_AUTH\"` and no secrets\n * registered, so `rds-db:connect` on the application user is the only\n * permission it needs to reach the cluster. MySQL modules instead granted the\n * role `secretsmanager:GetSecretValue` on the admin credentials secret plus\n * `kms:Decrypt` — credentials the proxy never uses, and a far wider grant than\n * connecting as the application user.\n *\n * These files are generated with `KeepExisting`, so an upgraded MySQL workspace\n * keeps the admin secret grant until this runs. Diverged files are left\n * untouched and reported via `nextSteps`.\n */\n\nconst TERRAFORM_DBS_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dbs`;\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\nconst CONNECT_STATEMENT_TEXT = [\n '{',\n ' Effect = \"Allow\"',\n ' Action = [\"rds-db:connect\"]',\n ' Resource = [',\n ' \"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.aurora.cluster_resource_id}/${local.database_runtime_user}\"',\n ' ]',\n ' }',\n].join('\\n');\n\nconst divergedMessage = (filePath: string) =>\n `${filePath}: the aws_iam_role_policy.proxy_db_user_connect policy has diverged from the generated shape - left untouched. The RDS Proxy authenticates to the cluster with IAM, so replace any secretsmanager:GetSecretValue / kms:Decrypt statements on the proxy role with a single rds-db:connect statement for local.database_runtime_user (see the ts#rdb generator's database app template).`;\n\nconst proxyPolicyBlock = (body: string) =>\n hcl(`\\`resource \"aws_iam_role_policy\" \"proxy_db_user_connect\" { ${body} }\\``);\n\nconst migrateModule = async (\n tree: Tree,\n filePath: string,\n nextSteps: string[],\n): Promise<void> => {\n if (!(await matchGritQL(tree, filePath, proxyPolicyBlock('$_')))) {\n return; // No proxy policy in this module - nothing this migration owns.\n }\n\n if (\n await matchGritQL(\n tree,\n filePath,\n proxyPolicyBlock('$props') +\n ' where { $props <: contains `\"rds-db:connect\"` }',\n )\n ) {\n return; // Already granted.\n }\n\n // The whole statement list is replaced, so the policy must still hold exactly\n // the two statements the generator vended and nothing the user has added.\n const secretStatements = hcl(\n [\n '`Statement = [',\n ' {',\n ' Effect = \"Allow\"',\n ' Action = [',\n ' \"secretsmanager:GetSecretValue\"',\n ' ]',\n ' Resource = [module.aurora.secret_arn]',\n ' },',\n ' {',\n ' Effect = \"Allow\"',\n ' Action = [',\n ' \"kms:Decrypt\"',\n ' ]',\n ' Resource = [module.aurora.kms_key_arn]',\n ' }',\n ' ]`',\n ].join('\\n'),\n );\n\n if (!(await matchGritQL(tree, filePath, secretStatements))) {\n nextSteps.push(divergedMessage(filePath));\n return;\n }\n\n await applyGritQL(\n tree,\n filePath,\n `${secretStatements} => \\`Statement = [\\n ${CONNECT_STATEMENT_TEXT}\\n ]\\``,\n );\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(TERRAFORM_DBS_DIR)) {\n return { nextSteps }; // This workspace has no Terraform database modules.\n }\n\n for (const dirName of tree.children(TERRAFORM_DBS_DIR)) {\n const filePath = joinPathFragments(\n TERRAFORM_DBS_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a database app module directory.\n }\n\n await migrateModule(tree, filePath, nextSteps);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","applyGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_DBS_DIR","hcl","pattern","CONNECT_STATEMENT_TEXT","join","divergedMessage","filePath","proxyPolicyBlock","body","migrateModule","tree","nextSteps","secretStatements","push","migration","exists","dirName","children"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,WAAW,EAAEC,WAAW,QAAQ,wBAAwB;AACjE,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;;;;CAcC,GAED,MAAMC,oBAAoB,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,YAAY,CAAC;AAE/E,MAAME,MAAM,CAACC,UAAoB,CAAC,cAAc,EAAEA,SAAS;AAE3D,MAAMC,yBAAyB;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAACC,IAAI,CAAC;AAEP,MAAMC,kBAAkB,CAACC,WACvB,GAAGA,SAAS,sXAAsX,CAAC;AAErY,MAAMC,mBAAmB,CAACC,OACxBP,IAAI,CAAC,2DAA2D,EAAEO,KAAK,IAAI,CAAC;AAE9E,MAAMC,gBAAgB,OACpBC,MACAJ,UACAK;IAEA,IAAI,CAAE,MAAMf,YAAYc,MAAMJ,UAAUC,iBAAiB,QAAS;QAChE,QAAQ,gEAAgE;IAC1E;IAEA,IACE,MAAMX,YACJc,MACAJ,UACAC,iBAAiB,YACf,qDAEJ;QACA,QAAQ,mBAAmB;IAC7B;IAEA,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAMK,mBAAmBX,IACvB;QACE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACD,CAACG,IAAI,CAAC;IAGT,IAAI,CAAE,MAAMR,YAAYc,MAAMJ,UAAUM,mBAAoB;QAC1DD,UAAUE,IAAI,CAACR,gBAAgBC;QAC/B;IACF;IAEA,MAAMX,YACJe,MACAJ,UACA,GAAGM,iBAAiB,2BAA2B,EAAET,uBAAuB,SAAS,CAAC;AAEtF;AAEA,eAAe,eAAeW,UAC5BJ,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,IAAI,CAACD,KAAKK,MAAM,CAACf,oBAAoB;QACnC,OAAO;YAAEW;QAAU,GAAG,oDAAoD;IAC5E;IAEA,KAAK,MAAMK,WAAWN,KAAKO,QAAQ,CAACjB,mBAAoB;QACtD,MAAMM,WAAWZ,kBACfM,mBACAgB,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACN,KAAKK,MAAM,CAACT,WAAW;YAC1B,UAAU,uCAAuC;QACnD;QAEA,MAAMG,cAAcC,MAAMJ,UAAUK;IACtC;IAEA,MAAMd,qBAAqBa;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/open-api/ts-client/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { generateFiles, logger, type Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { esmVars } from '../../utils/module-format.js';\nimport { buildOpenApiCodeGenData } from '../utils/codegen-data.js';\nimport type { CodeGenData } from '../utils/codegen-data/types.js';\nimport { parseOpenApiSpec } from '../utils/parse.js';\nimport type { Spec } from '../utils/types.js';\nimport type { OpenApiTsClientGeneratorSchema } from './schema';\n\n/**\n * Generates typescript client from an openapi spec\n */\nexport const openApiTsClientGenerator = async (\n tree: Tree,\n options: OpenApiTsClientGeneratorSchema,\n) => {\n const data = await buildOpenApiCodeGenerationData(\n tree,\n options.openApiSpecPath,\n );\n\n generateOpenApiTsClient(tree, data, options.outputPath);\n\n await formatFilesInSubtree(tree);\n};\n\n/**\n * Build a data structure which can be used to generate code from OpenAPI\n */\nexport const buildOpenApiCodeGenerationData = async (\n tree: Tree,\n specPath: string,\n) => {\n const spec = await parseOpenApiSpec(tree, specPath);\n warnForUnsupportedFeatures(spec);\n return buildOpenApiCodeGenData(spec);\n};\n\n/**\n * Warn for spec features the generated client does not implement, so their\n * omission is never silent.\n */\nconst warnForUnsupportedFeatures = (spec: Spec) => {\n if (Object.keys((spec as { webhooks?: object }).webhooks ?? {}).length > 0) {\n logger.warn(\n 'OpenAPI webhooks are not supported and no client code is generated for them',\n );\n }\n for (const [p, pathItem] of Object.entries(spec.paths ?? {})) {\n for (const [method, op] of Object.entries(pathItem ?? {})) {\n if (typeof op !== 'object' || op === null) continue;\n const operation = op as {\n callbacks?: object;\n servers?: unknown[];\n };\n if (Object.keys(operation.callbacks ?? {}).length > 0) {\n logger.warn(\n `Operation ${method.toUpperCase()} ${p} declares callbacks, which are not supported and are ignored`,\n );\n }\n if ((operation.servers ?? []).length > 0) {\n logger.warn(\n `Operation ${method.toUpperCase()} ${p} declares operation-level servers, which are ignored — the client always uses its configured url`,\n );\n }\n }\n }\n};\n\n/**\n * Generate an OpenAPI typescript client in the target directory\n */\nexport const generateOpenApiTsClient = (\n tree: Tree,\n data: CodeGenData,\n outputPath: string,\n) => {\n generateFiles(tree, path.join(import.meta.dirname, 'files'), outputPath, {\n ...data,\n ...esmVars(tree),\n });\n};\n\nexport default openApiTsClientGenerator;\n"],"names":["generateFiles","logger","path","formatFilesInSubtree","esmVars","buildOpenApiCodeGenData","parseOpenApiSpec","openApiTsClientGenerator","tree","options","data","buildOpenApiCodeGenerationData","openApiSpecPath","generateOpenApiTsClient","outputPath","specPath","spec","warnForUnsupportedFeatures","Object","keys","webhooks","length","warn","p","pathItem","entries","paths","method","op","operation","callbacks","toUpperCase","servers","join","dirname"],"mappings":"AAAA;;;CAGC,GACD,SAASA,aAAa,EAAEC,MAAM,QAAmB,aAAa;AAC9D,YAAYC,UAAU,OAAO;AAC7B,SAASC,oBAAoB,QAAQ,wBAAwB;AAC7D,SAASC,OAAO,QAAQ,+BAA+B;AACvD,SAASC,uBAAuB,QAAQ,2BAA2B;AAEnE,SAASC,gBAAgB,QAAQ,oBAAoB;AAIrD;;CAEC,GACD,OAAO,MAAMC,2BAA2B,OACtCC,MACAC;IAEA,MAAMC,OAAO,MAAMC,+BACjBH,MACAC,QAAQG,eAAe;IAGzBC,wBAAwBL,MAAME,MAAMD,QAAQK,UAAU;IAEtD,MAAMX,qBAAqBK;AAC7B,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMG,iCAAiC,OAC5CH,MACAO;IAEA,MAAMC,OAAO,MAAMV,iBAAiBE,MAAMO;IAC1CE,2BAA2BD;IAC3B,OAAOX,wBAAwBW;AACjC,EAAE;AAEF;;;CAGC,GACD,MAAMC,6BAA6B,CAACD;IAClC,IAAIE,OAAOC,IAAI,CAAC,AAACH,KAA+BI,QAAQ,IAAI,CAAC,GAAGC,MAAM,GAAG,GAAG;QAC1EpB,OAAOqB,IAAI,CACT;IAEJ;IACA,KAAK,MAAM,CAACC,GAAGC,SAAS,IAAIN,OAAOO,OAAO,CAACT,KAAKU,KAAK,IAAI,CAAC,GAAI;QAC5D,KAAK,MAAM,CAACC,QAAQC,GAAG,IAAIV,OAAOO,OAAO,CAACD,YAAY,CAAC,GAAI;YACzD,IAAI,OAAOI,OAAO,YAAYA,OAAO,MAAM;YAC3C,MAAMC,YAAYD;YAIlB,IAAIV,OAAOC,IAAI,CAACU,UAAUC,SAAS,IAAI,CAAC,GAAGT,MAAM,GAAG,GAAG;gBACrDpB,OAAOqB,IAAI,CACT,CAAC,UAAU,EAAEK,OAAOI,WAAW,GAAG,CAAC,EAAER,EAAE,4DAA4D,CAAC;YAExG;YACA,IAAI,AAACM,CAAAA,UAAUG,OAAO,IAAI,EAAE,AAAD,EAAGX,MAAM,GAAG,GAAG;gBACxCpB,OAAOqB,IAAI,CACT,CAAC,UAAU,EAAEK,OAAOI,WAAW,GAAG,CAAC,EAAER,EAAE,gGAAgG,CAAC;YAE5I;QACF;IACF;AACF;AAEA;;CAEC,GACD,OAAO,MAAMV,0BAA0B,CACrCL,MACAE,MACAI;IAEAd,cAAcQ,MAAMN,KAAK+B,IAAI,CAAC,YAAYC,OAAO,EAAE,UAAUpB,YAAY;QACvE,GAAGJ,IAAI;QACP,GAAGN,QAAQI,KAAK;IAClB;AACF,EAAE;AAEF,eAAeD,yBAAyB"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/open-api/ts-client/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { generateFiles, logger, type Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { esmVars } from '../../utils/module-format.js';\nimport type { CodeGenData } from '../utils/codegen-data/types.js';\nimport { buildOpenApiCodeGenData } from '../utils/codegen-data.js';\nimport { parseOpenApiSpec } from '../utils/parse.js';\nimport type { Spec } from '../utils/types.js';\nimport type { OpenApiTsClientGeneratorSchema } from './schema';\n\n/**\n * Generates typescript client from an openapi spec\n */\nexport const openApiTsClientGenerator = async (\n tree: Tree,\n options: OpenApiTsClientGeneratorSchema,\n) => {\n const data = await buildOpenApiCodeGenerationData(\n tree,\n options.openApiSpecPath,\n );\n\n generateOpenApiTsClient(tree, data, options.outputPath);\n\n await formatFilesInSubtree(tree);\n};\n\n/**\n * Build a data structure which can be used to generate code from OpenAPI\n */\nexport const buildOpenApiCodeGenerationData = async (\n tree: Tree,\n specPath: string,\n) => {\n const spec = await parseOpenApiSpec(tree, specPath);\n warnForUnsupportedFeatures(spec);\n return buildOpenApiCodeGenData(spec);\n};\n\n/**\n * Warn for spec features the generated client does not implement, so their\n * omission is never silent.\n */\nconst warnForUnsupportedFeatures = (spec: Spec) => {\n if (Object.keys((spec as { webhooks?: object }).webhooks ?? {}).length > 0) {\n logger.warn(\n 'OpenAPI webhooks are not supported and no client code is generated for them',\n );\n }\n for (const [p, pathItem] of Object.entries(spec.paths ?? {})) {\n for (const [method, op] of Object.entries(pathItem ?? {})) {\n if (typeof op !== 'object' || op === null) continue;\n const operation = op as {\n callbacks?: object;\n servers?: unknown[];\n };\n if (Object.keys(operation.callbacks ?? {}).length > 0) {\n logger.warn(\n `Operation ${method.toUpperCase()} ${p} declares callbacks, which are not supported and are ignored`,\n );\n }\n if ((operation.servers ?? []).length > 0) {\n logger.warn(\n `Operation ${method.toUpperCase()} ${p} declares operation-level servers, which are ignored — the client always uses its configured url`,\n );\n }\n }\n }\n};\n\n/**\n * Generate an OpenAPI typescript client in the target directory\n */\nexport const generateOpenApiTsClient = (\n tree: Tree,\n data: CodeGenData,\n outputPath: string,\n) => {\n generateFiles(tree, path.join(import.meta.dirname, 'files'), outputPath, {\n ...data,\n ...esmVars(tree),\n });\n};\n\nexport default openApiTsClientGenerator;\n"],"names":["generateFiles","logger","path","formatFilesInSubtree","esmVars","buildOpenApiCodeGenData","parseOpenApiSpec","openApiTsClientGenerator","tree","options","data","buildOpenApiCodeGenerationData","openApiSpecPath","generateOpenApiTsClient","outputPath","specPath","spec","warnForUnsupportedFeatures","Object","keys","webhooks","length","warn","p","pathItem","entries","paths","method","op","operation","callbacks","toUpperCase","servers","join","dirname"],"mappings":"AAAA;;;CAGC,GACD,SAASA,aAAa,EAAEC,MAAM,QAAmB,aAAa;AAC9D,YAAYC,UAAU,OAAO;AAC7B,SAASC,oBAAoB,QAAQ,wBAAwB;AAC7D,SAASC,OAAO,QAAQ,+BAA+B;AAEvD,SAASC,uBAAuB,QAAQ,2BAA2B;AACnE,SAASC,gBAAgB,QAAQ,oBAAoB;AAIrD;;CAEC,GACD,OAAO,MAAMC,2BAA2B,OACtCC,MACAC;IAEA,MAAMC,OAAO,MAAMC,+BACjBH,MACAC,QAAQG,eAAe;IAGzBC,wBAAwBL,MAAME,MAAMD,QAAQK,UAAU;IAEtD,MAAMX,qBAAqBK;AAC7B,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMG,iCAAiC,OAC5CH,MACAO;IAEA,MAAMC,OAAO,MAAMV,iBAAiBE,MAAMO;IAC1CE,2BAA2BD;IAC3B,OAAOX,wBAAwBW;AACjC,EAAE;AAEF;;;CAGC,GACD,MAAMC,6BAA6B,CAACD;IAClC,IAAIE,OAAOC,IAAI,CAAC,AAACH,KAA+BI,QAAQ,IAAI,CAAC,GAAGC,MAAM,GAAG,GAAG;QAC1EpB,OAAOqB,IAAI,CACT;IAEJ;IACA,KAAK,MAAM,CAACC,GAAGC,SAAS,IAAIN,OAAOO,OAAO,CAACT,KAAKU,KAAK,IAAI,CAAC,GAAI;QAC5D,KAAK,MAAM,CAACC,QAAQC,GAAG,IAAIV,OAAOO,OAAO,CAACD,YAAY,CAAC,GAAI;YACzD,IAAI,OAAOI,OAAO,YAAYA,OAAO,MAAM;YAC3C,MAAMC,YAAYD;YAIlB,IAAIV,OAAOC,IAAI,CAACU,UAAUC,SAAS,IAAI,CAAC,GAAGT,MAAM,GAAG,GAAG;gBACrDpB,OAAOqB,IAAI,CACT,CAAC,UAAU,EAAEK,OAAOI,WAAW,GAAG,CAAC,EAAER,EAAE,4DAA4D,CAAC;YAExG;YACA,IAAI,AAACM,CAAAA,UAAUG,OAAO,IAAI,EAAE,AAAD,EAAGX,MAAM,GAAG,GAAG;gBACxCpB,OAAOqB,IAAI,CACT,CAAC,UAAU,EAAEK,OAAOI,WAAW,GAAG,CAAC,EAAER,EAAE,gGAAgG,CAAC;YAE5I;QACF;IACF;AACF;AAEA;;CAEC,GACD,OAAO,MAAMV,0BAA0B,CACrCL,MACAE,MACAI;IAEAd,cAAcQ,MAAMN,KAAK+B,IAAI,CAAC,YAAYC,OAAO,EAAE,UAAUpB,YAAY;QACvE,GAAGJ,IAAI;QACP,GAAGN,QAAQI,KAAK;IAClB;AACF,EAAE;AAEF,eAAeD,yBAAyB"}
@@ -17,8 +17,8 @@ import { fireEvent, render, waitFor } from '@testing-library/react';
17
17
  import type React from 'react';
18
18
  import type { Mock } from 'vitest';
19
19
  import { importTypeScriptModule } from '../../utils/js.js';
20
- import { createTreeUsingTsSolutionSetup } from '../../utils/test.js';
21
20
  import { TypeScriptVerifier } from '../../utils/test/ts.spec.js';
21
+ import { createTreeUsingTsSolutionSetup } from '../../utils/test.js';
22
22
  import { PET_STORE_SPEC } from '../ts-client/generator.petstore.spec.js';
23
23
  import type { Spec } from '../utils/types.js';
24
24
  import { openApiTsHooksGenerator } from './generator.js';
@@ -14,7 +14,7 @@ import { addDependencyToTargetIfNotPresent, addGeneratorMetadata, getGeneratorIn
14
14
  import { migrateToSharedVenvGenerator, uvProjectGenerator } from "../../utils/nxlv-python.js";
15
15
  import { sortObjectKeys } from "../../utils/object.js";
16
16
  import { updateToml } from "../../utils/toml.js";
17
- import { withVersions } from "../../utils/versions.js";
17
+ import { pyenvPythonVersion, pyprojectPythonDependency, withVersions } from "../../utils/versions.js";
18
18
  export const DEPENDENCIES = declareDependencies()({
19
19
  ts: [
20
20
  {
@@ -106,8 +106,8 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
106
106
  autoActivate: true,
107
107
  packageManager: 'uv',
108
108
  moveDevDependencies: false,
109
- pyenvPythonVersion: '3.14.0',
110
- pyprojectPythonDependency: '>=3.14'
109
+ pyenvPythonVersion: pyenvPythonVersion(),
110
+ pyprojectPythonDependency: pyprojectPythonDependency()
111
111
  });
112
112
  }
113
113
  await uvProjectGenerator(tree, {
@@ -124,8 +124,8 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
124
124
  buildBundleLocalDependencies: true,
125
125
  linter: 'ruff',
126
126
  rootPyprojectDependencyGroup: 'main',
127
- pyenvPythonVersion: '3.14.0',
128
- pyprojectPythonDependency: '>=3.14',
127
+ pyenvPythonVersion: pyenvPythonVersion(),
128
+ pyprojectPythonDependency: pyprojectPythonDependency(),
129
129
  projectType: schema.type,
130
130
  projectNameAndRootFormat: 'as-provided',
131
131
  moduleName: normalizedModuleName,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { declareDependencies } from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python.js';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { updateToml } from '../../utils/toml.js';\nimport { withVersions } from '../../utils/versions.js';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const DEPENDENCIES = declareDependencies()({\n ts: [{ name: '@nxlv/python', dev: true, root: true }],\n py: [\n // The linting and type checking tools live in the workspace root pyproject.\n // Pinned to the version generation-time formatting uses, so generated files\n // stay `ruff format --check`-clean across ruff releases.\n { name: 'ruff', group: 'dev', root: true },\n { name: 'ty', group: 'dev', root: true },\n ],\n});\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n const pythonPlugin = withVersions(DEPENDENCIES, ['@nxlv/python']);\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: '3.14.0',\n pyprojectPythonDependency: '>=3.14',\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n inputs: ['default', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n addPyDependencies(tree, DEPENDENCIES);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","addPyDependencies","addTsDependencies","declareDependencies","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","updateToml","withVersions","DEPENDENCIES","ts","name","dev","root","py","group","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","getPyProjectDetails","tree","schema","scope","normalizedName","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","nxJson","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","pyenvPythonVersion","pyprojectPythonDependency","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","filter","preferInstallDependencies","languages"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { declareDependencies } from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python.js';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { updateToml } from '../../utils/toml.js';\nimport {\n pyenvPythonVersion,\n pyprojectPythonDependency,\n withVersions,\n} from '../../utils/versions.js';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const DEPENDENCIES = declareDependencies()({\n ts: [{ name: '@nxlv/python', dev: true, root: true }],\n py: [\n // The linting and type checking tools live in the workspace root pyproject.\n // Pinned to the version generation-time formatting uses, so generated files\n // stay `ruff format --check`-clean across ruff releases.\n { name: 'ruff', group: 'dev', root: true },\n { name: 'ty', group: 'dev', root: true },\n ],\n});\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n const pythonPlugin = withVersions(DEPENDENCIES, ['@nxlv/python']);\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n inputs: ['default', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n addPyDependencies(tree, DEPENDENCIES);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","addPyDependencies","addTsDependencies","declareDependencies","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","updateToml","pyenvPythonVersion","pyprojectPythonDependency","withVersions","DEPENDENCIES","ts","name","dev","root","py","group","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","getPyProjectDetails","tree","schema","scope","normalizedName","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","nxJson","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","filter","preferInstallDependencies","languages"],"mappings":"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"}
@@ -88,7 +88,7 @@ export class TestApi<
88
88
  pattern: 'isolated',
89
89
  operations: OPERATION_DETAILS,
90
90
  defaultIntegrationOptions: {
91
- runtime: Runtime.NODEJS_LATEST,
91
+ runtime: Runtime.NODEJS_24_X,
92
92
  handler: 'index.handler',
93
93
  code: Code.fromAsset(
94
94
  url.fileURLToPath(
@@ -276,7 +276,7 @@ export class TestApi<
276
276
  pattern: 'isolated',
277
277
  operations: OPERATION_DETAILS,
278
278
  defaultIntegrationOptions: {
279
- runtime: Runtime.NODEJS_LATEST,
279
+ runtime: Runtime.NODEJS_24_X,
280
280
  handler: 'index.handler',
281
281
  code: Code.fromAsset(
282
282
  url.fileURLToPath(
@@ -1158,7 +1158,7 @@ resource "aws_lambda_function" "api_lambda" {
1158
1158
  function_name = local.function_name[each.key]
1159
1159
  role = aws_iam_role.lambda_execution_role[each.key].arn
1160
1160
  handler = "index.handler"
1161
- runtime = "nodejs22.x"
1161
+ runtime = "nodejs24.x"
1162
1162
  timeout = 30
1163
1163
  memory_size = 128
1164
1164
 
@@ -1297,7 +1297,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
1297
1297
  function_name = "TestApiAuthorizer-\${random_string.suffix.result}"
1298
1298
  role = aws_iam_role.authorizer_execution_role.arn
1299
1299
  handler = "index.handler"
1300
- runtime = "nodejs22.x"
1300
+ runtime = "nodejs24.x"
1301
1301
  timeout = 10
1302
1302
  memory_size = 128
1303
1303
 
@@ -2994,7 +2994,7 @@ resource "aws_lambda_function" "api_lambda" {
2994
2994
  function_name = local.function_name[each.key]
2995
2995
  role = aws_iam_role.lambda_execution_role[each.key].arn
2996
2996
  handler = "index.handler"
2997
- runtime = "nodejs22.x"
2997
+ runtime = "nodejs24.x"
2998
2998
  timeout = 30
2999
2999
  memory_size = 128
3000
3000
 
@@ -4297,7 +4297,7 @@ resource "aws_lambda_function" "api_lambda" {
4297
4297
  function_name = local.function_name[each.key]
4298
4298
  role = aws_iam_role.lambda_execution_role[each.key].arn
4299
4299
  handler = "index.handler"
4300
- runtime = "nodejs22.x"
4300
+ runtime = "nodejs24.x"
4301
4301
  timeout = 30
4302
4302
  memory_size = 128
4303
4303
 
@@ -5286,7 +5286,7 @@ resource "aws_lambda_function" "api_lambda" {
5286
5286
  function_name = local.function_name[each.key]
5287
5287
  role = aws_iam_role.lambda_execution_role[each.key].arn
5288
5288
  handler = "index.handler"
5289
- runtime = "nodejs22.x"
5289
+ runtime = "nodejs24.x"
5290
5290
  timeout = 30
5291
5291
  memory_size = 128
5292
5292
 
@@ -5425,7 +5425,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
5425
5425
  function_name = "CustomApiAuthorizer-\${random_string.suffix.result}"
5426
5426
  role = aws_iam_role.authorizer_execution_role.arn
5427
5427
  handler = "index.handler"
5428
- runtime = "nodejs22.x"
5428
+ runtime = "nodejs24.x"
5429
5429
  timeout = 10
5430
5430
  memory_size = 128
5431
5431
 
@@ -437,7 +437,7 @@ export class TestApi<
437
437
  pattern: 'isolated',
438
438
  operations: routerToOperations(appRouter),
439
439
  defaultIntegrationOptions: {
440
- runtime: Runtime.NODEJS_LATEST,
440
+ runtime: Runtime.NODEJS_24_X,
441
441
  handler: 'index.handler',
442
442
  code: Code.fromAsset(
443
443
  url.fileURLToPath(
@@ -647,7 +647,7 @@ export class TestApi<
647
647
  pattern: 'isolated',
648
648
  operations: routerToOperations(appRouter),
649
649
  defaultIntegrationOptions: {
650
- runtime: Runtime.NODEJS_LATEST,
650
+ runtime: Runtime.NODEJS_24_X,
651
651
  handler: 'index.handler',
652
652
  code: Code.fromAsset(
653
653
  url.fileURLToPath(
@@ -865,7 +865,7 @@ export class TestApi<
865
865
  pattern: 'isolated',
866
866
  operations: routerToOperations(appRouter),
867
867
  defaultIntegrationOptions: {
868
- runtime: Runtime.NODEJS_LATEST,
868
+ runtime: Runtime.NODEJS_24_X,
869
869
  handler: 'index.handler',
870
870
  code: Code.fromAsset(
871
871
  url.fileURLToPath(
@@ -904,7 +904,7 @@ export class TestApi<
904
904
  scope,
905
905
  'TestApiAuthorizerFunction',
906
906
  {
907
- runtime: Runtime.NODEJS_LATEST,
907
+ runtime: Runtime.NODEJS_24_X,
908
908
  handler: 'index.handler',
909
909
  code: Code.fromAsset(
910
910
  url.fileURLToPath(
@@ -1082,7 +1082,7 @@ export class TestApi<
1082
1082
  pattern: 'isolated',
1083
1083
  operations: routerToOperations(appRouter),
1084
1084
  defaultIntegrationOptions: {
1085
- runtime: Runtime.NODEJS_LATEST,
1085
+ runtime: Runtime.NODEJS_24_X,
1086
1086
  handler: 'index.handler',
1087
1087
  code: Code.fromAsset(
1088
1088
  url.fileURLToPath(
@@ -1122,7 +1122,7 @@ export class TestApi<
1122
1122
  scope,
1123
1123
  'TestApiAuthorizerFunction',
1124
1124
  {
1125
- runtime: Runtime.NODEJS_LATEST,
1125
+ runtime: Runtime.NODEJS_24_X,
1126
1126
  handler: 'index.handler',
1127
1127
  code: Code.fromAsset(
1128
1128
  url.fileURLToPath(
@@ -1454,7 +1454,7 @@ export class TestApi<
1454
1454
  pattern: 'isolated',
1455
1455
  operations: routerToOperations(appRouter),
1456
1456
  defaultIntegrationOptions: {
1457
- runtime: Runtime.NODEJS_LATEST,
1457
+ runtime: Runtime.NODEJS_24_X,
1458
1458
  handler: 'index.handler',
1459
1459
  code: Code.fromAsset(
1460
1460
  url.fileURLToPath(
@@ -2500,7 +2500,7 @@ export class TestApi<
2500
2500
  pattern: 'isolated',
2501
2501
  operations: routerToOperations(appRouter),
2502
2502
  defaultIntegrationOptions: {
2503
- runtime: Runtime.NODEJS_LATEST,
2503
+ runtime: Runtime.NODEJS_24_X,
2504
2504
  handler: 'index.handler',
2505
2505
  code: Code.fromAsset(
2506
2506
  url.fileURLToPath(
@@ -3669,7 +3669,7 @@ resource "aws_lambda_function" "api_lambda" {
3669
3669
  function_name = local.function_name[each.key]
3670
3670
  role = aws_iam_role.lambda_execution_role[each.key].arn
3671
3671
  handler = "index.handler"
3672
- runtime = "nodejs22.x"
3672
+ runtime = "nodejs24.x"
3673
3673
  timeout = 30
3674
3674
  memory_size = 128
3675
3675
 
@@ -4474,7 +4474,7 @@ resource "aws_lambda_function" "api_lambda" {
4474
4474
  function_name = local.function_name[each.key]
4475
4475
  role = aws_iam_role.lambda_execution_role[each.key].arn
4476
4476
  handler = "index.handler"
4477
- runtime = "nodejs22.x"
4477
+ runtime = "nodejs24.x"
4478
4478
  timeout = 30
4479
4479
  memory_size = 128
4480
4480
 
@@ -4613,7 +4613,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
4613
4613
  function_name = "TestApiAuthorizer-\${random_string.suffix.result}"
4614
4614
  role = aws_iam_role.authorizer_execution_role.arn
4615
4615
  handler = "index.handler"
4616
- runtime = "nodejs22.x"
4616
+ runtime = "nodejs24.x"
4617
4617
  timeout = 10
4618
4618
  memory_size = 128
4619
4619
 
@@ -5362,7 +5362,7 @@ resource "aws_lambda_function" "api_lambda" {
5362
5362
  function_name = local.function_name[each.key]
5363
5363
  role = aws_iam_role.lambda_execution_role[each.key].arn
5364
5364
  handler = "index.handler"
5365
- runtime = "nodejs22.x"
5365
+ runtime = "nodejs24.x"
5366
5366
  timeout = 30
5367
5367
  memory_size = 128
5368
5368
 
@@ -6422,7 +6422,7 @@ resource "aws_lambda_function" "api_lambda" {
6422
6422
  function_name = local.function_name[each.key]
6423
6423
  role = aws_iam_role.lambda_execution_role[each.key].arn
6424
6424
  handler = "index.handler"
6425
- runtime = "nodejs22.x"
6425
+ runtime = "nodejs24.x"
6426
6426
  timeout = 30
6427
6427
  memory_size = 128
6428
6428
 
@@ -7726,7 +7726,7 @@ resource "aws_lambda_function" "api_lambda" {
7726
7726
  function_name = local.function_name[each.key]
7727
7727
  role = aws_iam_role.lambda_execution_role[each.key].arn
7728
7728
  handler = "index.handler"
7729
- runtime = "nodejs22.x"
7729
+ runtime = "nodejs24.x"
7730
7730
  timeout = 30
7731
7731
  memory_size = 128
7732
7732
 
@@ -9029,7 +9029,7 @@ resource "aws_lambda_function" "api_lambda" {
9029
9029
  function_name = local.function_name[each.key]
9030
9030
  role = aws_iam_role.lambda_execution_role[each.key].arn
9031
9031
  handler = "index.handler"
9032
- runtime = "nodejs22.x"
9032
+ runtime = "nodejs24.x"
9033
9033
  timeout = 30
9034
9034
  memory_size = 128
9035
9035
 
@@ -9168,7 +9168,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
9168
9168
  function_name = "TestApiAuthorizer-\${random_string.suffix.result}"
9169
9169
  role = aws_iam_role.authorizer_execution_role.arn
9170
9170
  handler = "index.handler"
9171
- runtime = "nodejs22.x"
9171
+ runtime = "nodejs24.x"
9172
9172
  timeout = 10
9173
9173
  memory_size = 128
9174
9174
 
@@ -214,7 +214,7 @@ export class SnapshotProxy extends Construct {
214
214
  new lambda.Function(this, id_, {
215
215
  code: asset(bundlePathFromRoot),
216
216
  handler: 'index.handler',
217
- runtime: lambda.Runtime.NODEJS_22_X,
217
+ runtime: lambda.Runtime.NODEJS_24_X,
218
218
  architecture: lambda.Architecture.ARM_64,
219
219
  timeout: Duration.seconds(10),
220
220
  memorySize: 256,
@@ -810,7 +810,7 @@ resource "aws_lambda_function" "standard" {
810
810
  function_name = "snapshot-proxy-\${each.key}-\${random_string.suffix.result}"
811
811
  role = each.key == "token" ? aws_iam_role.token.arn : aws_iam_role.proxy.arn
812
812
  handler = "index.handler"
813
- runtime = "nodejs22.x"
813
+ runtime = "nodejs24.x"
814
814
  architectures = ["arm64"]
815
815
  source_code_hash = data.archive_file.handler_zip[each.key].output_base64sha256
816
816
  timeout = 10
@@ -839,7 +839,7 @@ resource "aws_lambda_function" "mcp_proxy" {
839
839
  function_name = "snapshot-proxy-mcp-proxy-\${random_string.suffix.result}"
840
840
  role = aws_iam_role.proxy.arn
841
841
  handler = "index.handler"
842
- runtime = "nodejs22.x"
842
+ runtime = "nodejs24.x"
843
843
  architectures = ["arm64"]
844
844
  source_code_hash = data.archive_file.handler_zip["mcp-proxy"].output_base64sha256
845
845
  timeout = var.mcp_proxy_timeout
@@ -10,7 +10,7 @@ export class TestProjectTestFunction extends Function {
10
10
  constructor(scope: Construct, id: string) {
11
11
  super(scope, id, {
12
12
  timeout: Duration.seconds(30),
13
- runtime: Runtime.NODEJS_LATEST,
13
+ runtime: Runtime.NODEJS_24_X,
14
14
  handler: 'index.handler',
15
15
  code: Code.fromAsset(
16
16
  url.fileURLToPath(
@@ -282,7 +282,7 @@ resource "aws_lambda_function" "lambda_function" {
282
282
  role = aws_iam_role.lambda_role.arn
283
283
  handler = "index.handler"
284
284
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
285
- runtime = "nodejs22.x"
285
+ runtime = "nodejs24.x"
286
286
  timeout = 30
287
287
 
288
288
  tracing_config {
@@ -467,7 +467,7 @@ resource "aws_lambda_function" "lambda_function" {
467
467
  role = aws_iam_role.lambda_role.arn
468
468
  handler = "index.handler"
469
469
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
470
- runtime = "nodejs22.x"
470
+ runtime = "nodejs24.x"
471
471
  timeout = 30
472
472
 
473
473
  tracing_config {
@@ -3113,17 +3113,10 @@ resource "aws_iam_role_policy" "proxy_db_user_connect" {
3113
3113
  Statement = [
3114
3114
  {
3115
3115
  Effect = "Allow"
3116
- Action = [
3117
- "secretsmanager:GetSecretValue"
3118
- ]
3119
- Resource = [module.aurora.secret_arn]
3120
- },
3121
- {
3122
- Effect = "Allow"
3123
- Action = [
3124
- "kms:Decrypt"
3116
+ Action = ["rds-db:connect"]
3117
+ Resource = [
3118
+ "arn:aws:rds-db:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:dbuser:\${module.aurora.cluster_resource_id}/\${local.database_runtime_user}"
3125
3119
  ]
3126
- Resource = [module.aurora.kms_key_arn]
3127
3120
  }
3128
3121
  ]
3129
3122
  })
@@ -4570,7 +4563,7 @@ export class Db extends AuroraDatabase {
4570
4563
  ...baseProps,
4571
4564
  code: Code.fromAsset(createDbUserBundleDir),
4572
4565
  handler: 'index.handler',
4573
- runtime: Runtime.NODEJS_LATEST,
4566
+ runtime: Runtime.NODEJS_24_X,
4574
4567
  environment: {
4575
4568
  NODE_EXTRA_CA_CERTS: '/var/runtime/ca-cert.pem',
4576
4569
  },
@@ -5,8 +5,8 @@
5
5
  import { readFileSync } from "fs";
6
6
  import { join } from "path";
7
7
  import { addTsDependencies } from "../../../utils/add-dependencies.js";
8
- import { addDestructuredImport, addSingleImport, applyGritQL } from "../../../utils/ast.js";
9
8
  import { addHookResultToRouterProviderContext } from "../../../utils/ast/website.js";
9
+ import { addDestructuredImport, addSingleImport, applyGritQL } from "../../../utils/ast.js";
10
10
  import { declareDependencies, ownedElsewhere } from "../../../utils/declared-dependencies.js";
11
11
  import { formatFilesInSubtree } from "../../../utils/format.js";
12
12
  import { resolveIac } from "../../../utils/iac.js";