@aws/nx-plugin 1.0.0-rc.85 → 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.
- package/migrations.json +11 -1
- package/package.json +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +34 -8
- package/src/infra/app/files/app/README.md.template +14 -0
- package/src/infra/app/generator.js +15 -2
- package/src/infra/app/generator.js.map +1 -1
- package/src/mcp-server/tools/general-guidance.js +1 -1
- package/src/mcp-server/tools/general-guidance.js.map +1 -1
- package/src/migrations/latest/add-destroy-sandbox-target/metadata.json +3 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.d.ts +6 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.js +150 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.js.map +1 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/__snapshots__/migration.spec.ts.snap +23 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/metadata.json +3 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js +88 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js.map +1 -0
- package/src/open-api/ts-client/generator.js.map +1 -1
- package/src/open-api/ts-hooks/generator.spec.tsx +1 -1
- package/src/py/project/generator.js +5 -5
- package/src/py/project/generator.js.map +1 -1
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +21 -9
- package/src/py/rdb/files/__name__/utils.py.template +17 -1
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +16 -16
- package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +132 -261
- package/src/ts/rdb/files/src/utils.ts.template +28 -1
- package/src/ts/react-website/cognito-auth/generator.js +1 -1
- package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
- package/src/ts/react-website/runtime-config/generator.js +1 -1
- package/src/ts/react-website/runtime-config/generator.js.map +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js +3 -2
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +1 -1
- package/src/utils/api-constructs/api-constructs.js +7 -4
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +4 -4
- package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +4 -4
- package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account.ts.template +1 -1
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +4 -4
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +4 -4
- package/src/utils/ast.d.ts +13 -0
- package/src/utils/ast.js +36 -0
- package/src/utils/ast.js.map +1 -1
- package/src/utils/bundle/bundle.js +5 -2
- package/src/utils/bundle/bundle.js.map +1 -1
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +5 -3
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -1
- package/src/utils/dcr-proxy-constructs/files/cdk/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.ts.template +1 -1
- package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +2 -2
- package/src/utils/files/common/scripts/src/infra/stage-credentials/cdk-command.ts.template +7 -3
- package/src/utils/function-constructs/function-constructs.js +3 -3
- package/src/utils/function-constructs/function-constructs.js.map +1 -1
- package/src/utils/lambda-runtime-resolution.d.ts +74 -0
- package/src/utils/lambda-runtime-resolution.js +97 -0
- package/src/utils/lambda-runtime-resolution.js.map +1 -0
- package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +3 -3
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +10 -29
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +28 -116
- package/src/utils/rdb-constructs/rdb-constructs.js +5 -3
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.d.ts +28 -0
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js +148 -0
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.d.ts +31 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.js +110 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-vended-versions.js +36 -7
- package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -1
- package/src/utils/versions.d.ts +60 -0
- package/src/utils/versions.js +51 -0
- 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 {
|
|
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:
|
|
110
|
-
pyprojectPythonDependency:
|
|
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:
|
|
128
|
-
pyprojectPythonDependency:
|
|
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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"}
|
|
@@ -294,12 +294,6 @@ variable "enable_rds_proxy" {
|
|
|
294
294
|
default = true
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
variable "enable_credential_rotation" {
|
|
298
|
-
description = "Whether to enable automatic credential rotation for the admin secret."
|
|
299
|
-
type = bool
|
|
300
|
-
default = true
|
|
301
|
-
}
|
|
302
|
-
|
|
303
297
|
variable "enable_cloudwatch_logs" {
|
|
304
298
|
description = "Whether to export Aurora engine logs to CloudWatch. PostgreSQL logs DDL statements only (log_statement=ddl); MySQL enables Advanced Auditing scoped to connections and DDL (server_audit_events=CONNECT,QUERY_DDL). Neither logs statement parameter values, to avoid leaking PII into log data."
|
|
305
299
|
type = bool
|
|
@@ -372,7 +366,6 @@ module "aurora" {
|
|
|
372
366
|
name = "db"
|
|
373
367
|
vpc_id = var.vpc_id
|
|
374
368
|
subnet_ids = var.database_subnet_ids
|
|
375
|
-
lambda_subnet_ids = var.lambda_subnet_ids
|
|
376
369
|
engine = "aurora-postgresql"
|
|
377
370
|
engine_version = var.engine_version
|
|
378
371
|
database_name = "database_name"
|
|
@@ -384,7 +377,6 @@ module "aurora" {
|
|
|
384
377
|
deletion_protection = var.deletion_protection
|
|
385
378
|
skip_final_snapshot = var.skip_final_snapshot
|
|
386
379
|
enable_rds_proxy = var.enable_rds_proxy
|
|
387
|
-
enable_credential_rotation = var.enable_credential_rotation
|
|
388
380
|
enable_cloudwatch_logs = var.enable_cloudwatch_logs
|
|
389
381
|
enable_performance_insights = var.enable_performance_insights
|
|
390
382
|
performance_insights_retention_period = var.performance_insights_retention_period
|
|
@@ -754,6 +746,9 @@ resource "aws_lambda_function" "create_db_user" {
|
|
|
754
746
|
environment {
|
|
755
747
|
variables = {
|
|
756
748
|
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
749
|
+
DATABASE_HOST = module.aurora.writer_endpoint
|
|
750
|
+
DATABASE_PORT = module.aurora.cluster_port
|
|
751
|
+
DATABASE_NAME = module.aurora.database_name
|
|
757
752
|
}
|
|
758
753
|
}
|
|
759
754
|
|
|
@@ -830,6 +825,9 @@ resource "aws_lambda_function" "migration_handler" {
|
|
|
830
825
|
environment {
|
|
831
826
|
variables = {
|
|
832
827
|
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
828
|
+
DATABASE_HOST = module.aurora.writer_endpoint
|
|
829
|
+
DATABASE_PORT = module.aurora.cluster_port
|
|
830
|
+
DATABASE_NAME = module.aurora.database_name
|
|
833
831
|
}
|
|
834
832
|
}
|
|
835
833
|
|
|
@@ -1309,12 +1307,26 @@ def get_local_dev_config() -> dict:
|
|
|
1309
1307
|
|
|
1310
1308
|
|
|
1311
1309
|
def get_database_secret() -> DatabaseSecret:
|
|
1310
|
+
"""Read the admin credentials secret.
|
|
1311
|
+
|
|
1312
|
+
RDS-managed secrets hold only \`username\` and \`password\`, so the host, port
|
|
1313
|
+
and database name are taken from the environment when the secret omits them.
|
|
1314
|
+
"""
|
|
1312
1315
|
secret_arn = os.environ.get("DATABASE_SECRET_ARN")
|
|
1313
1316
|
if not secret_arn:
|
|
1314
1317
|
raise ValueError("Missing required environment variable DATABASE_SECRET_ARN.")
|
|
1315
1318
|
client = boto3.client("secretsmanager")
|
|
1316
1319
|
response = client.get_secret_value(SecretId=secret_arn)
|
|
1317
|
-
|
|
1320
|
+
secret = json.loads(response["SecretString"])
|
|
1321
|
+
|
|
1322
|
+
for key, env_var in (("host", "DATABASE_HOST"), ("port", "DATABASE_PORT"), ("dbname", "DATABASE_NAME")):
|
|
1323
|
+
value = os.environ.get(env_var)
|
|
1324
|
+
if value:
|
|
1325
|
+
secret[key] = value
|
|
1326
|
+
if secret.get(key) is None:
|
|
1327
|
+
raise ValueError(f"Database secret is missing {key} and no override was provided in {env_var}.")
|
|
1328
|
+
|
|
1329
|
+
return secret
|
|
1318
1330
|
|
|
1319
1331
|
|
|
1320
1332
|
_database_config: dict[str, DatabaseConfig] = {}
|
|
@@ -39,12 +39,28 @@ def get_local_dev_config() -> dict:
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def get_database_secret() -> DatabaseSecret:
|
|
42
|
+
"""Read the admin credentials secret.
|
|
43
|
+
|
|
44
|
+
RDS-managed secrets hold only `username` and `password`, so the host, port
|
|
45
|
+
and database name are taken from the environment when the secret omits them.
|
|
46
|
+
"""
|
|
42
47
|
secret_arn = os.environ.get('DATABASE_SECRET_ARN')
|
|
43
48
|
if not secret_arn:
|
|
44
49
|
raise ValueError('Missing required environment variable DATABASE_SECRET_ARN.')
|
|
45
50
|
client = boto3.client('secretsmanager')
|
|
46
51
|
response = client.get_secret_value(SecretId=secret_arn)
|
|
47
|
-
|
|
52
|
+
secret = json.loads(response['SecretString'])
|
|
53
|
+
|
|
54
|
+
for key, env_var in (('host', 'DATABASE_HOST'), ('port', 'DATABASE_PORT'), ('dbname', 'DATABASE_NAME')):
|
|
55
|
+
value = os.environ.get(env_var)
|
|
56
|
+
if value:
|
|
57
|
+
secret[key] = value
|
|
58
|
+
if secret.get(key) is None:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
f'Database secret is missing {key} and no override was provided in {env_var}.'
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return secret
|
|
48
64
|
|
|
49
65
|
|
|
50
66
|
_database_config: dict[str, DatabaseConfig] = {}
|
|
@@ -88,7 +88,7 @@ export class TestApi<
|
|
|
88
88
|
pattern: 'isolated',
|
|
89
89
|
operations: OPERATION_DETAILS,
|
|
90
90
|
defaultIntegrationOptions: {
|
|
91
|
-
runtime: Runtime.
|
|
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.
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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.
|
|
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 = "
|
|
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 = "
|
|
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
|