@aws/nx-plugin 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +31 -29
  2. package/generators.json +16 -0
  3. package/migrations.json +6 -1
  4. package/package.json +1 -1
  5. package/src/agentcore-harness/generator.d.ts +1 -1
  6. package/src/greengrass/component/common.d.ts +60 -0
  7. package/src/greengrass/component/common.js +191 -0
  8. package/src/greengrass/component/common.js.map +1 -0
  9. package/src/greengrass/component/dependencies.d.ts +101 -0
  10. package/src/greengrass/component/dependencies.js +37 -0
  11. package/src/greengrass/component/dependencies.js.map +1 -0
  12. package/src/greengrass/component/generator.d.ts +174 -0
  13. package/src/greengrass/component/generator.js +32 -0
  14. package/src/greengrass/component/generator.js.map +1 -0
  15. package/src/greengrass/component/metadata.d.ts +2 -0
  16. package/src/greengrass/component/metadata.js +14 -0
  17. package/src/greengrass/component/metadata.js.map +1 -0
  18. package/src/greengrass/component/python/__snapshots__/generator.spec.ts.snap +450 -0
  19. package/src/greengrass/component/python/files/component/main.py.template +60 -0
  20. package/src/greengrass/component/python/files/component/recipe.yaml.template +30 -0
  21. package/src/greengrass/component/python/files/gdk/gdk-config.json.template +13 -0
  22. package/src/greengrass/component/python/files/tests/test___componentSnakeCase__.py.template +37 -0
  23. package/src/greengrass/component/python/generator.d.ts +15 -0
  24. package/src/greengrass/component/python/generator.js +192 -0
  25. package/src/greengrass/component/python/generator.js.map +1 -0
  26. package/src/greengrass/component/schema.d.js +6 -0
  27. package/src/greengrass/component/schema.d.js.map +1 -0
  28. package/src/greengrass/component/schema.d.ts +18 -0
  29. package/src/greengrass/component/schema.json +82 -0
  30. package/src/greengrass/component/typescript/__snapshots__/generator.spec.ts.snap +275 -0
  31. package/src/greengrass/component/typescript/files/component/recipe.yaml.template +41 -0
  32. package/src/greengrass/component/typescript/files/entrypoint/main.ts.template +58 -0
  33. package/src/greengrass/component/typescript/files/gdk/gdk-config.json.template +13 -0
  34. package/src/greengrass/component/typescript/files/scripts/vendor-crt-addon.ts.template +115 -0
  35. package/src/greengrass/component/typescript/generator.d.ts +16 -0
  36. package/src/greengrass/component/typescript/generator.js +194 -0
  37. package/src/greengrass/component/typescript/generator.js.map +1 -0
  38. package/src/infra/app/generator.d.ts +1 -1
  39. package/src/init/generator.d.ts +1 -1
  40. package/src/internal/test-matrix/generator.js +48 -1
  41. package/src/internal/test-matrix/generator.js.map +1 -1
  42. package/src/license/dependency-check/pre-approved.js +2 -1
  43. package/src/license/dependency-check/pre-approved.js.map +1 -1
  44. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/metadata.json +3 -0
  45. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.d.ts +6 -0
  46. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.js +118 -0
  47. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.js.map +1 -0
  48. package/src/open-api/py-client/generator.d.ts +1 -1
  49. package/src/preset/__snapshots__/generator.spec.ts.snap +4 -0
  50. package/src/preset/generator.d.ts +1 -1
  51. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  52. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  53. package/src/py/agent/guardrails/__snapshots__/generator.spec.ts.snap +3813 -0
  54. package/src/py/agent/guardrails/files/langchain/guardrail.py.template +135 -0
  55. package/src/py/agent/guardrails/files/strands/guardrail.py.template +93 -0
  56. package/src/py/agent/guardrails/generator.d.ts +10 -0
  57. package/src/py/agent/guardrails/generator.js +175 -0
  58. package/src/py/agent/guardrails/generator.js.map +1 -0
  59. package/src/py/agent/guardrails/runtime-check/run_checks.py +250 -0
  60. package/src/py/agent/guardrails/schema.d.js +6 -0
  61. package/src/py/agent/guardrails/schema.d.js.map +1 -0
  62. package/src/py/agent/guardrails/schema.d.ts +9 -0
  63. package/src/py/agent/guardrails/schema.json +25 -0
  64. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  65. package/src/py/agent/react-connection/generator.d.ts +1 -1
  66. package/src/py/fast-api/react/generator.d.ts +1 -1
  67. package/src/py/project/generator.js +2 -0
  68. package/src/py/project/generator.js.map +1 -1
  69. package/src/sdk/greengrass.d.ts +6 -0
  70. package/src/sdk/greengrass.js +6 -0
  71. package/src/sdk/greengrass.js.map +1 -0
  72. package/src/sdk/py.d.ts +2 -0
  73. package/src/sdk/py.js +1 -0
  74. package/src/sdk/py.js.map +1 -1
  75. package/src/smithy/project/generator.d.ts +1 -1
  76. package/src/smithy/react-connection/generator.d.ts +1 -1
  77. package/src/terraform/project/generator.d.ts +1 -1
  78. package/src/trpc/react/generator.d.ts +1 -1
  79. package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
  80. package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
  81. package/src/ts/agent/guardrails/__snapshots__/generator.spec.ts.snap +54 -3
  82. package/src/ts/agent/guardrails/generator.js +2 -1
  83. package/src/ts/agent/guardrails/generator.js.map +1 -1
  84. package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
  85. package/src/ts/agent/react-connection/generator.d.ts +1 -1
  86. package/src/ts/astro-docs/generator.d.ts +1 -1
  87. package/src/ts/dcr-proxy/generator.d.ts +1 -1
  88. package/src/ts/dynamodb/generator.d.ts +1 -1
  89. package/src/ts/lambda-function/generator.d.ts +1 -1
  90. package/src/ts/lib/generator.d.ts +1 -1
  91. package/src/ts/nx-generator/generator.d.ts +1 -1
  92. package/src/ts/nx-migration/generator.d.ts +1 -1
  93. package/src/ts/nx-plugin/generator.d.ts +1 -1
  94. package/src/ts/rdb/generator.d.ts +1 -1
  95. package/src/ts/react-website/agui/generator.d.ts +1 -1
  96. package/src/utils/__snapshots__/shared-greengrass-scripts.spec.ts.snap +1279 -0
  97. package/src/utils/files/common/scripts/src/greengrass/build-artifact.ts.template +236 -0
  98. package/src/utils/files/common/scripts/src/greengrass/component-logs.ts.template +48 -0
  99. package/src/utils/files/common/scripts/src/greengrass/deploy-local.ts.template +497 -0
  100. package/src/utils/files/common/scripts/src/greengrass/recipe-utils.ts.template +356 -0
  101. package/src/utils/files/common/scripts/src/greengrass/zip-writer.ts.template +121 -0
  102. package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +3 -3
  103. package/src/utils/files/terraform/src/metrics/metrics.tf.template +1 -1
  104. package/src/utils/greengrass/constants.d.ts +58 -0
  105. package/src/utils/greengrass/constants.js +63 -0
  106. package/src/utils/greengrass/constants.js.map +1 -0
  107. package/src/utils/greengrass/naming.d.ts +46 -0
  108. package/src/utils/greengrass/naming.js +67 -0
  109. package/src/utils/greengrass/naming.js.map +1 -0
  110. package/src/utils/greengrass/recipe.d.ts +143 -0
  111. package/src/utils/greengrass/recipe.js +119 -0
  112. package/src/utils/greengrass/recipe.js.map +1 -0
  113. package/src/utils/greengrass-constructs/files/cdk/app/greengrass-component/__componentDirName__.ts.template +42 -0
  114. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/artifact-bucket.ts.template +82 -0
  115. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/component-version.ts.template +370 -0
  116. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/deployment.ts.template +276 -0
  117. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/index.ts.template +5 -0
  118. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/next-version.ts.template +119 -0
  119. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/recipe.ts.template +90 -0
  120. package/src/utils/greengrass-constructs/files/next-version/__nextVersionFileName__.template +195 -0
  121. package/src/utils/greengrass-constructs/files/terraform/app/greengrass-component/__componentDirName__/__componentDirName__.tf.template +26 -0
  122. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/artifact-bucket/main.tf.template +204 -0
  123. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/component-version/main.tf.template +156 -0
  124. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/deployment/main.tf.template +186 -0
  125. package/src/utils/greengrass-constructs/greengrass-constructs.d.ts +57 -0
  126. package/src/utils/greengrass-constructs/greengrass-constructs.js +154 -0
  127. package/src/utils/greengrass-constructs/greengrass-constructs.js.map +1 -0
  128. package/src/utils/guardrail-constructs/files/terraform/app/guardrails/__nameKebabCase__/__nameKebabCase__-guardrail.tf.template +18 -1
  129. package/src/utils/guardrail-constructs/guardrail-constructs.d.ts +5 -0
  130. package/src/utils/guardrail-constructs/guardrail-constructs.js +8 -0
  131. package/src/utils/guardrail-constructs/guardrail-constructs.js.map +1 -1
  132. package/src/utils/guardrail-constructs/guardrail-wiring.d.ts +7 -0
  133. package/src/utils/guardrail-constructs/guardrail-wiring.js +6 -5
  134. package/src/utils/guardrail-constructs/guardrail-wiring.js.map +1 -1
  135. package/src/utils/nx.d.ts +15 -0
  136. package/src/utils/nx.js +32 -0
  137. package/src/utils/nx.js.map +1 -1
  138. package/src/utils/shared-greengrass-scripts.d.ts +21 -0
  139. package/src/utils/shared-greengrass-scripts.js +43 -0
  140. package/src/utils/shared-greengrass-scripts.js.map +1 -0
  141. package/src/utils/test/fake-aws/fake_aws.py +205 -0
  142. package/src/utils/test/python-dependencies.d.ts +6 -0
  143. package/src/utils/test/python-dependencies.js +19 -0
  144. package/src/utils/test/python-dependencies.js.map +1 -1
  145. package/src/utils/test/warm-python-cache.js +5 -1
  146. package/src/utils/test/warm-python-cache.js.map +1 -1
  147. package/src/utils/versions.d.ts +7 -0
  148. package/src/utils/versions.js +7 -0
  149. package/src/utils/versions.js.map +1 -1
  150. /package/src/{ts/agent/guardrails/files/agent → utils/guardrail-constructs/files/policy}/guardrail.json.template +0 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { generateFiles, joinPathFragments, logger, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
5
+ import { FsCommands } from "../../../utils/fs.js";
6
+ import { GREENGRASS_PLATFORM_MAPPINGS, RECIPE_FORMAT_VERSION } from "../../../utils/greengrass/constants.js";
7
+ import { toSnakeCase } from "../../../utils/names.js";
8
+ import { addArtifactDependencyToTargets, normalizeTargetKeyOrder } from "../../../utils/nx.js";
9
+ import { sortObjectKeys } from "../../../utils/object.js";
10
+ import { toProjectRelativePath } from "../../../utils/paths.js";
11
+ import { sharedGreengrassScriptsGenerator } from "../../../utils/shared-greengrass-scripts.js";
12
+ import { tryReadToml } from "../../../utils/toml.js";
13
+ import { LAMBDA_RUNTIME_VERSIONS } from "../../../utils/versions.js";
14
+ import { assertUnchangedPlatform, finalizeComponent, GREENGRASS_SCRIPTS_DIR, sharedComponentTargets } from "../common.js";
15
+ import { PY_DEPENDENCIES as DEPENDENCIES } from "../dependencies.js";
16
+ /**
17
+ * The lowest Python `major.minor` declared by `[project].requires-python`
18
+ * (eg "3.14" from ">=3.14"), so vendoring targets the device's own floor
19
+ * rather than the Lambda runtime `addPythonBundleTarget` pins. Falls back to
20
+ * the plugin's Lambda Python floor only when the project declares none.
21
+ */ const pythonVersionFloor = (requiresPython)=>{
22
+ if (typeof requiresPython === 'string') {
23
+ let min;
24
+ for (const match of requiresPython.matchAll(/(\d+)\.(\d+)/g)){
25
+ const major = Number(match[1]);
26
+ const minor = Number(match[2]);
27
+ if (!min || major < min.major || major === min.major && minor < min.minor) {
28
+ min = {
29
+ major,
30
+ minor
31
+ };
32
+ }
33
+ }
34
+ if (min) {
35
+ return `${min.major}.${min.minor}`;
36
+ }
37
+ }
38
+ return LAMBDA_RUNTIME_VERSIONS.python;
39
+ };
40
+ /**
41
+ * Generates an AWS IoT Greengrass v2 component on an existing Python project:
42
+ * packaging and local-deployment targets (`<c>-vendor`, `<c>-artifact`,
43
+ * `<c>-deploy-local`, `<c>-logs`), plus, unless `--infra none`, a
44
+ * `GreengrassComponentVersion` CDK construct (or Terraform module, via the
45
+ * `hashicorp/awscc` provider) that publishes the built artifact.
46
+ */ export const pythonGreengrassComponentGenerator = async (tree, component)=>{
47
+ const { project: projectConfig, options } = component;
48
+ const componentDirName = component.componentDirName;
49
+ const componentSnakeCase = toSnakeCase(options.name);
50
+ const componentName = component.componentName;
51
+ const componentVersion = component.componentVersion;
52
+ const publisher = component.publisher;
53
+ const ipc = component.ipc;
54
+ const gdkConfig = component.gdkConfig;
55
+ const platforms = component.platforms;
56
+ const isMultiPlatform = platforms.length > 1;
57
+ const distDir = `dist/{projectRoot}/greengrass/${componentDirName}`;
58
+ const distDirVendor = `${distDir}/vendor`;
59
+ // One entry per recipe manifest. Every per-architecture name - the vendor
60
+ // subdirectory, the zip base name and the manifest `architecture` value -
61
+ // is derived from the SAME mapping entry, so they cannot drift apart.
62
+ const manifests = platforms.map((p)=>{
63
+ const { uvPlatform, manifestPlatform } = GREENGRASS_PLATFORM_MAPPINGS[p];
64
+ return {
65
+ uvPlatform,
66
+ os: manifestPlatform.os,
67
+ architecture: manifestPlatform.architecture,
68
+ // Single-platform names stay flat: `<c>.zip` and `vendor/`.
69
+ artifactBaseName: isMultiPlatform ? `${componentDirName}-${manifestPlatform.architecture}` : componentDirName,
70
+ vendorDir: isMultiPlatform ? `${distDirVendor}/${manifestPlatform.architecture}` : distDirVendor
71
+ };
72
+ });
73
+ const pyProjectPath = joinPathFragments(projectConfig.root, 'pyproject.toml');
74
+ const pyproject = tryReadToml(tree, pyProjectPath);
75
+ const pythonFloor = pythonVersionFloor(pyproject?.project?.['requires-python']);
76
+ const componentDir = joinPathFragments(projectConfig.root, 'greengrass', componentDirName);
77
+ const mainPath = joinPathFragments(componentDir, 'main.py');
78
+ const gdkConfigPath = joinPathFragments(componentDir, 'gdk-config.json');
79
+ // Flat under tests/greengrass/, one file per component: pytest imports a test
80
+ // module by basename, so two components sharing a `test_main.py` basename in
81
+ // sibling directories would collide.
82
+ const testDir = joinPathFragments(projectConfig.root, 'tests', 'greengrass');
83
+ const manifestPreview = manifests.map((m)=>` - Platform:\n os: ${m.os}\n architecture: ${m.architecture}\n Artifacts:\n - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/${m.artifactBaseName}.zip\n Unarchive: ZIP\n Lifecycle:\n Run: python${pythonFloor} {artifacts:decompressedPath}/${m.artifactBaseName}/main.py`).join('\n');
84
+ assertUnchangedPlatform(component, manifestPreview);
85
+ const templateOptions = {
86
+ componentName,
87
+ // Named `version` / `recipeFormat`, not `componentVersion` /
88
+ // `recipeFormatVersion`: a `*Version` template variable is how a template
89
+ // names a vended dependency pin (see `VENDED_TEMPLATE_VARS` in
90
+ // `version-upgrade-migration/real-templates.spec.ts`), which neither a
91
+ // user-owned option nor a fixed protocol constant is.
92
+ version: componentVersion,
93
+ recipeFormat: RECIPE_FORMAT_VERSION,
94
+ componentDescription: `${componentName} Greengrass component using Python ${pythonFloor}, generated by greengrass#component.`,
95
+ publisher,
96
+ ipc,
97
+ manifests,
98
+ // The recipe Run command pins the same interpreter the wheels were
99
+ // vendored for; a bare `python3` can resolve to an older device default
100
+ // whose ABI the vendored native wheels do not support.
101
+ pythonFloor,
102
+ componentDirName,
103
+ componentSnakeCase,
104
+ project: projectConfig.name
105
+ };
106
+ // recipe.yaml and main.py are user-owned from first generation onward.
107
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'component'), componentDir, templateOptions, {
108
+ overwriteStrategy: OverwriteStrategy.KeepExisting
109
+ });
110
+ if (gdkConfig) {
111
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'gdk'), componentDir, templateOptions, {
112
+ overwriteStrategy: OverwriteStrategy.Overwrite
113
+ });
114
+ } else if (tree.exists(gdkConfigPath)) {
115
+ tree.delete(gdkConfigPath);
116
+ logger.info(`Removed ${gdkConfigPath}; pass --gdkConfig to keep it.`);
117
+ }
118
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'tests'), testDir, templateOptions, {
119
+ overwriteStrategy: OverwriteStrategy.KeepExisting
120
+ });
121
+ await sharedGreengrassScriptsGenerator(tree, DEPENDENCIES);
122
+ const vendorTarget = `${componentDirName}-vendor`;
123
+ const artifactTarget = `${componentDirName}-artifact`;
124
+ projectConfig.targets ??= {};
125
+ const fs = new FsCommands(tree, DEPENDENCIES);
126
+ projectConfig.targets[vendorTarget] = normalizeTargetKeyOrder({
127
+ cache: true,
128
+ // The vendor dir holds only exported dependencies, never test files.
129
+ inputs: [
130
+ 'production',
131
+ '^production'
132
+ ],
133
+ outputs: [
134
+ `{workspaceRoot}/${distDirVendor}`
135
+ ],
136
+ executor: 'nx:run-commands',
137
+ dependsOn: [
138
+ 'compile'
139
+ ],
140
+ options: {
141
+ commands: [
142
+ // `uv pip install --target` adds to whatever is already there and
143
+ // never prunes, so without this a dropped dependency - or the other
144
+ // platform's `vendor/<architecture>` directory after a deliberate
145
+ // platform change - would still be packaged into the next artifact.
146
+ // Artifact bytes must depend only on the current source.
147
+ fs.rm(distDirVendor),
148
+ fs.mkdir(distDirVendor),
149
+ `uv export --frozen --no-dev --no-editable --no-emit-project --project {projectRoot} --package ${projectConfig.name} -o ${distDirVendor}/requirements.txt`,
150
+ // `--only-binary :all:` is required: without it an sdist can build a
151
+ // host-architecture binary into a cross-architecture artifact.
152
+ ...manifests.map((m)=>`uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --only-binary :all: --python-platform ${m.uvPlatform} --python-version ${pythonFloor} --target ${m.vendorDir} -r ${distDirVendor}/requirements.txt`)
153
+ ],
154
+ parallel: false
155
+ }
156
+ });
157
+ projectConfig.targets[artifactTarget] = normalizeTargetKeyOrder({
158
+ cache: true,
159
+ // The vended scripts live outside this project, so the cache key must
160
+ // name them explicitly or a refreshed script serves a stale artifact.
161
+ inputs: [
162
+ 'production',
163
+ '^production',
164
+ `{workspaceRoot}/${GREENGRASS_SCRIPTS_DIR}/**/*`
165
+ ],
166
+ outputs: [
167
+ `{workspaceRoot}/${distDir}/greengrass-build`
168
+ ],
169
+ executor: 'nx:run-commands',
170
+ dependsOn: [
171
+ vendorTarget
172
+ ],
173
+ options: {
174
+ command: `tsx ${GREENGRASS_SCRIPTS_DIR}/build-artifact.ts {projectRoot} ${componentDirName} ${distDir}${isMultiPlatform ? ` --platforms=${manifests.map((m)=>m.architecture).join(',')}` : ''}`
175
+ }
176
+ });
177
+ addArtifactDependencyToTargets(projectConfig, artifactTarget);
178
+ Object.assign(projectConfig.targets, sharedComponentTargets({
179
+ artifactTarget,
180
+ componentDirName,
181
+ componentName,
182
+ distDir
183
+ }));
184
+ // py#project and ts#project sort targets on every run, including re-runs,
185
+ // so append in the same order or a later project re-run reorders the file.
186
+ projectConfig.targets = sortObjectKeys(projectConfig.targets);
187
+ updateProjectConfiguration(tree, projectConfig.name, projectConfig);
188
+ return finalizeComponent(tree, component, joinPathFragments(toProjectRelativePath(projectConfig, mainPath)), DEPENDENCIES);
189
+ };
190
+ export default pythonGreengrassComponentGenerator;
191
+
192
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/greengrass/component/python/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { FsCommands } from '../../../utils/fs.js';\nimport {\n GREENGRASS_PLATFORM_MAPPINGS,\n RECIPE_FORMAT_VERSION,\n} from '../../../utils/greengrass/constants.js';\nimport { toSnakeCase } from '../../../utils/names.js';\nimport {\n addArtifactDependencyToTargets,\n normalizeTargetKeyOrder,\n} from '../../../utils/nx.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\nimport { toProjectRelativePath } from '../../../utils/paths.js';\nimport { sharedGreengrassScriptsGenerator } from '../../../utils/shared-greengrass-scripts.js';\nimport { tryReadToml } from '../../../utils/toml.js';\nimport { LAMBDA_RUNTIME_VERSIONS } from '../../../utils/versions.js';\nimport type { NormalizedComponent } from '../common.js';\nimport {\n assertUnchangedPlatform,\n finalizeComponent,\n GREENGRASS_SCRIPTS_DIR,\n sharedComponentTargets,\n} from '../common.js';\nimport { PY_DEPENDENCIES as DEPENDENCIES } from '../dependencies.js';\n\n/**\n * The lowest Python `major.minor` declared by `[project].requires-python`\n * (eg \"3.14\" from \">=3.14\"), so vendoring targets the device's own floor\n * rather than the Lambda runtime `addPythonBundleTarget` pins. Falls back to\n * the plugin's Lambda Python floor only when the project declares none.\n */\nconst pythonVersionFloor = (requiresPython: unknown): string => {\n if (typeof requiresPython === 'string') {\n let min: { major: number; minor: number } | undefined;\n for (const match of requiresPython.matchAll(/(\\d+)\\.(\\d+)/g)) {\n const major = Number(match[1]);\n const minor = Number(match[2]);\n if (\n !min ||\n major < min.major ||\n (major === min.major && minor < min.minor)\n ) {\n min = { major, minor };\n }\n }\n if (min) {\n return `${min.major}.${min.minor}`;\n }\n }\n return LAMBDA_RUNTIME_VERSIONS.python;\n};\n\n/**\n * Generates an AWS IoT Greengrass v2 component on an existing Python project:\n * packaging and local-deployment targets (`<c>-vendor`, `<c>-artifact`,\n * `<c>-deploy-local`, `<c>-logs`), plus, unless `--infra none`, a\n * `GreengrassComponentVersion` CDK construct (or Terraform module, via the\n * `hashicorp/awscc` provider) that publishes the built artifact.\n */\nexport const pythonGreengrassComponentGenerator = async (\n tree: Tree,\n component: NormalizedComponent,\n): Promise<GeneratorCallback> => {\n const { project: projectConfig, options } = component;\n\n const componentDirName = component.componentDirName;\n const componentSnakeCase = toSnakeCase(options.name);\n const componentName = component.componentName;\n const componentVersion = component.componentVersion;\n const publisher = component.publisher;\n const ipc = component.ipc;\n const gdkConfig = component.gdkConfig;\n const platforms = component.platforms;\n const isMultiPlatform = platforms.length > 1;\n const distDir = `dist/{projectRoot}/greengrass/${componentDirName}`;\n const distDirVendor = `${distDir}/vendor`;\n // One entry per recipe manifest. Every per-architecture name - the vendor\n // subdirectory, the zip base name and the manifest `architecture` value -\n // is derived from the SAME mapping entry, so they cannot drift apart.\n const manifests = platforms.map((p) => {\n const { uvPlatform, manifestPlatform } = GREENGRASS_PLATFORM_MAPPINGS[p];\n return {\n uvPlatform,\n os: manifestPlatform.os,\n architecture: manifestPlatform.architecture,\n // Single-platform names stay flat: `<c>.zip` and `vendor/`.\n artifactBaseName: isMultiPlatform\n ? `${componentDirName}-${manifestPlatform.architecture}`\n : componentDirName,\n vendorDir: isMultiPlatform\n ? `${distDirVendor}/${manifestPlatform.architecture}`\n : distDirVendor,\n };\n });\n\n const pyProjectPath = joinPathFragments(projectConfig.root, 'pyproject.toml');\n const pyproject = tryReadToml(tree, pyProjectPath) as unknown as\n | { project?: { 'requires-python'?: unknown } }\n | undefined;\n const pythonFloor = pythonVersionFloor(\n pyproject?.project?.['requires-python'],\n );\n\n const componentDir = joinPathFragments(\n projectConfig.root,\n 'greengrass',\n componentDirName,\n );\n const mainPath = joinPathFragments(componentDir, 'main.py');\n const gdkConfigPath = joinPathFragments(componentDir, 'gdk-config.json');\n // Flat under tests/greengrass/, one file per component: pytest imports a test\n // module by basename, so two components sharing a `test_main.py` basename in\n // sibling directories would collide.\n const testDir = joinPathFragments(projectConfig.root, 'tests', 'greengrass');\n\n const manifestPreview = manifests\n .map(\n (m) =>\n ` - Platform:\\n os: ${m.os}\\n architecture: ${m.architecture}\\n Artifacts:\\n - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/${m.artifactBaseName}.zip\\n Unarchive: ZIP\\n Lifecycle:\\n Run: python${pythonFloor} {artifacts:decompressedPath}/${m.artifactBaseName}/main.py`,\n )\n .join('\\n');\n assertUnchangedPlatform(component, manifestPreview);\n\n const templateOptions = {\n componentName,\n // Named `version` / `recipeFormat`, not `componentVersion` /\n // `recipeFormatVersion`: a `*Version` template variable is how a template\n // names a vended dependency pin (see `VENDED_TEMPLATE_VARS` in\n // `version-upgrade-migration/real-templates.spec.ts`), which neither a\n // user-owned option nor a fixed protocol constant is.\n version: componentVersion,\n recipeFormat: RECIPE_FORMAT_VERSION,\n componentDescription: `${componentName} Greengrass component using Python ${pythonFloor}, generated by greengrass#component.`,\n publisher,\n ipc,\n manifests,\n // The recipe Run command pins the same interpreter the wheels were\n // vendored for; a bare `python3` can resolve to an older device default\n // whose ABI the vendored native wheels do not support.\n pythonFloor,\n componentDirName,\n componentSnakeCase,\n project: projectConfig.name,\n };\n\n // recipe.yaml and main.py are user-owned from first generation onward.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'component'),\n componentDir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (gdkConfig) {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'gdk'),\n componentDir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.Overwrite },\n );\n } else if (tree.exists(gdkConfigPath)) {\n tree.delete(gdkConfigPath);\n logger.info(`Removed ${gdkConfigPath}; pass --gdkConfig to keep it.`);\n }\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'tests'),\n testDir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await sharedGreengrassScriptsGenerator(tree, DEPENDENCIES);\n\n const vendorTarget = `${componentDirName}-vendor`;\n const artifactTarget = `${componentDirName}-artifact`;\n\n projectConfig.targets ??= {};\n\n const fs = new FsCommands(tree, DEPENDENCIES);\n\n projectConfig.targets[vendorTarget] = normalizeTargetKeyOrder({\n cache: true,\n // The vendor dir holds only exported dependencies, never test files.\n inputs: ['production', '^production'],\n outputs: [`{workspaceRoot}/${distDirVendor}`],\n executor: 'nx:run-commands',\n dependsOn: ['compile'],\n options: {\n commands: [\n // `uv pip install --target` adds to whatever is already there and\n // never prunes, so without this a dropped dependency - or the other\n // platform's `vendor/<architecture>` directory after a deliberate\n // platform change - would still be packaged into the next artifact.\n // Artifact bytes must depend only on the current source.\n fs.rm(distDirVendor),\n fs.mkdir(distDirVendor),\n `uv export --frozen --no-dev --no-editable --no-emit-project --project {projectRoot} --package ${projectConfig.name} -o ${distDirVendor}/requirements.txt`,\n // `--only-binary :all:` is required: without it an sdist can build a\n // host-architecture binary into a cross-architecture artifact.\n ...manifests.map(\n (m) =>\n `uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --only-binary :all: --python-platform ${m.uvPlatform} --python-version ${pythonFloor} --target ${m.vendorDir} -r ${distDirVendor}/requirements.txt`,\n ),\n ],\n parallel: false,\n },\n });\n\n projectConfig.targets[artifactTarget] = normalizeTargetKeyOrder({\n cache: true,\n // The vended scripts live outside this project, so the cache key must\n // name them explicitly or a refreshed script serves a stale artifact.\n inputs: [\n 'production',\n '^production',\n `{workspaceRoot}/${GREENGRASS_SCRIPTS_DIR}/**/*`,\n ],\n outputs: [`{workspaceRoot}/${distDir}/greengrass-build`],\n executor: 'nx:run-commands',\n dependsOn: [vendorTarget],\n options: {\n command: `tsx ${GREENGRASS_SCRIPTS_DIR}/build-artifact.ts {projectRoot} ${componentDirName} ${distDir}${\n isMultiPlatform\n ? ` --platforms=${manifests.map((m) => m.architecture).join(',')}`\n : ''\n }`,\n },\n });\n addArtifactDependencyToTargets(projectConfig, artifactTarget);\n\n Object.assign(\n projectConfig.targets,\n sharedComponentTargets({\n artifactTarget,\n componentDirName,\n componentName,\n distDir,\n }),\n );\n\n // py#project and ts#project sort targets on every run, including re-runs,\n // so append in the same order or a later project re-run reorders the file.\n projectConfig.targets = sortObjectKeys(projectConfig.targets);\n updateProjectConfiguration(tree, projectConfig.name, projectConfig);\n\n return finalizeComponent(\n tree,\n component,\n joinPathFragments(toProjectRelativePath(projectConfig, mainPath)),\n DEPENDENCIES,\n );\n};\n\nexport default pythonGreengrassComponentGenerator;\n"],"names":["generateFiles","joinPathFragments","logger","OverwriteStrategy","updateProjectConfiguration","FsCommands","GREENGRASS_PLATFORM_MAPPINGS","RECIPE_FORMAT_VERSION","toSnakeCase","addArtifactDependencyToTargets","normalizeTargetKeyOrder","sortObjectKeys","toProjectRelativePath","sharedGreengrassScriptsGenerator","tryReadToml","LAMBDA_RUNTIME_VERSIONS","assertUnchangedPlatform","finalizeComponent","GREENGRASS_SCRIPTS_DIR","sharedComponentTargets","PY_DEPENDENCIES","DEPENDENCIES","pythonVersionFloor","requiresPython","min","match","matchAll","major","Number","minor","python","pythonGreengrassComponentGenerator","tree","component","project","projectConfig","options","componentDirName","componentSnakeCase","name","componentName","componentVersion","publisher","ipc","gdkConfig","platforms","isMultiPlatform","length","distDir","distDirVendor","manifests","map","p","uvPlatform","manifestPlatform","os","architecture","artifactBaseName","vendorDir","pyProjectPath","root","pyproject","pythonFloor","componentDir","mainPath","gdkConfigPath","testDir","manifestPreview","m","join","templateOptions","version","recipeFormat","componentDescription","dirname","overwriteStrategy","KeepExisting","Overwrite","exists","delete","info","vendorTarget","artifactTarget","targets","fs","cache","inputs","outputs","executor","dependsOn","commands","rm","mkdir","parallel","command","Object","assign"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ export { };
5
+
6
+ //# sourceMappingURL=schema.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/greengrass/component/schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nexport interface GreengrassComponentGeneratorSchema {\n project: string;\n name: string;\n language?: 'typescript' | 'python';\n componentName?: string;\n componentVersion?: string;\n publisher?: string;\n ipc?: boolean;\n gdkConfig?: boolean;\n platform?: 'linux-amd64' | 'linux-arm64' | 'linux-amd64-arm64';\n infra?: 'component-version' | 'none';\n iac?: 'inherit' | 'cdk' | 'terraform';\n preferInstallDependencies?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GACD,WAaC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ export interface GreengrassComponentGeneratorSchema {
6
+ project: string;
7
+ name: string;
8
+ language?: 'typescript' | 'python';
9
+ componentName?: string;
10
+ componentVersion?: string;
11
+ publisher?: string;
12
+ ipc?: boolean;
13
+ gdkConfig?: boolean;
14
+ platform?: 'linux-amd64' | 'linux-arm64' | 'linux-amd64-arm64';
15
+ infra?: 'component-version' | 'none';
16
+ iac?: 'inherit' | 'cdk' | 'terraform';
17
+ preferInstallDependencies?: boolean;
18
+ }
@@ -0,0 +1,82 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "greengrass#component",
4
+ "title": "greengrass#component",
5
+ "x-label": "Greengrass Component",
6
+ "description": "Add an AWS IoT Greengrass component to an existing Python or TypeScript project. Language is inferred from the selected project's marker when unambiguous.",
7
+ "type": "object",
8
+ "properties": {
9
+ "project": {
10
+ "type": "string",
11
+ "description": "The existing Python or TypeScript host project",
12
+ "x-prompt": "Select the project to add the Greengrass component to",
13
+ "x-dropdown": "projects"
14
+ },
15
+ "name": {
16
+ "type": "string",
17
+ "description": "The component name",
18
+ "x-priority": "important",
19
+ "$default": { "$source": "argv", "index": 0 },
20
+ "x-prompt": "What name would you like for the Greengrass component?"
21
+ },
22
+ "language": {
23
+ "type": "string",
24
+ "enum": ["typescript", "python"],
25
+ "description": "The component language. Omit it only when the host has exactly one supported language marker."
26
+ },
27
+ "componentName": {
28
+ "type": "string",
29
+ "description": "The recipe ComponentName. Defaults to a reversed-domain name derived from the workspace npm scope and component name."
30
+ },
31
+ "componentVersion": {
32
+ "type": "string",
33
+ "default": "1.0.0",
34
+ "description": "The recipe ComponentVersion. CDK resolves NEXT_* at deploy time; Terraform requires an explicit semantic version. With infra=none, NEXT_* is written unchanged."
35
+ },
36
+ "publisher": {
37
+ "type": "string",
38
+ "description": "The recipe ComponentPublisher. Defaults to the workspace npm scope."
39
+ },
40
+ "ipc": {
41
+ "type": "boolean",
42
+ "default": false,
43
+ "description": "Whether to wire the Greengrass IPC client. Defaults to false for both languages."
44
+ },
45
+ "gdkConfig": {
46
+ "type": "boolean",
47
+ "default": false,
48
+ "description": "Vend gdk-config.json for using the GDK CLI by hand. GDK supports NEXT_PATCH, not NEXT_MINOR or NEXT_MAJOR.",
49
+ "x-priority": "low"
50
+ },
51
+ "platform": {
52
+ "type": "string",
53
+ "enum": ["linux-amd64", "linux-arm64", "linux-amd64-arm64"],
54
+ "default": "linux-arm64",
55
+ "description": "The core device platform or platforms.",
56
+ "x-priority": "important",
57
+ "x-prompt": "Which core device platform(s) would you like to target?"
58
+ },
59
+ "infra": {
60
+ "type": "string",
61
+ "enum": ["component-version", "none"],
62
+ "default": "component-version",
63
+ "description": "component-version vends reusable Greengrass component infrastructure; none supports local development only.",
64
+ "x-priority": "important",
65
+ "x-prompt": "Which infrastructure would you like to provision?"
66
+ },
67
+ "iac": {
68
+ "type": "string",
69
+ "enum": ["inherit", "cdk", "terraform"],
70
+ "default": "inherit",
71
+ "description": "The IaC provider, resolved only when infrastructure is requested.",
72
+ "x-priority": "important",
73
+ "x-prompt": "Which provider would you like to manage your infrastructure? (default: Inherit)"
74
+ },
75
+ "preferInstallDependencies": {
76
+ "type": "boolean",
77
+ "default": true,
78
+ "description": "Whether to prefer installing dependencies after the generator runs."
79
+ }
80
+ },
81
+ "required": ["project", "name"]
82
+ }
@@ -0,0 +1,275 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`greengrass#component generator (typescript) > multi-architecture (platform: linux-amd64-arm64) > should match snapshot for a multi-architecture component > multi-arch-snapshot 1`] = `
4
+ {
5
+ "packages/test-project/greengrass/my-component/recipe.yaml": "RecipeFormatVersion: '2020-01-25'
6
+ ComponentName: com.proj.MyComponent
7
+ ComponentVersion: 1.0.0
8
+ ComponentDescription: com.proj.MyComponent Greengrass component, generated by greengrass#component.
9
+ ComponentPublisher: proj
10
+ Manifests:
11
+ - Platform:
12
+ os: linux
13
+ architecture: amd64
14
+ Artifacts:
15
+ # Placeholders are substituted at publish time. The basename must stay
16
+ # my-component.zip, which is what the Run script below unarchives to.
17
+ - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component.zip
18
+ Unarchive: ZIP
19
+ Lifecycle:
20
+ # Requires a node binary on the device's PATH. The generated bundle was
21
+ # tested with Node.js 22; Greengrass uses the installed runtime.
22
+ Run: node {artifacts:decompressedPath}/my-component/index.js
23
+ - Platform:
24
+ os: linux
25
+ architecture: aarch64
26
+ Artifacts:
27
+ # Placeholders are substituted at publish time. The basename must stay
28
+ # my-component.zip, which is what the Run script below unarchives to.
29
+ - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component.zip
30
+ Unarchive: ZIP
31
+ Lifecycle:
32
+ # Requires a node binary on the device's PATH. The generated bundle was
33
+ # tested with Node.js 22; Greengrass uses the installed runtime.
34
+ Run: node {artifacts:decompressedPath}/my-component/index.js
35
+ ",
36
+ "packages/test-project/project.json": "{
37
+ "name": "test-project",
38
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
39
+ "sourceRoot": "packages/test-project/src",
40
+ "metadata": {
41
+ "components": [
42
+ {
43
+ "generator": "greengrass#component",
44
+ "path": "src/greengrass/my-component/main.ts",
45
+ "name": "my-component",
46
+ "language": "typescript",
47
+ "componentName": "com.proj.MyComponent",
48
+ "componentVersion": "1.0.0",
49
+ "platform": "linux-amd64-arm64",
50
+ "ipc": false,
51
+ "gdkConfig": false
52
+ }
53
+ ]
54
+ },
55
+ "targets": {
56
+ "assemble": {
57
+ "dependsOn": ["bundle", "my-component-artifact"]
58
+ },
59
+ "build": {
60
+ "dependsOn": ["bundle", "my-component-artifact"]
61
+ },
62
+ "bundle": {
63
+ "executor": "nx:run-commands",
64
+ "dependsOn": ["compile"],
65
+ "cache": true,
66
+ "inputs": ["default"],
67
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle"],
68
+ "options": {
69
+ "command": "rolldown -c rolldown.config.ts",
70
+ "cwd": "{projectRoot}"
71
+ }
72
+ },
73
+ "compile": {
74
+ "executor": "@nx/js:tsc"
75
+ },
76
+ "my-component-artifact": {
77
+ "executor": "nx:run-commands",
78
+ "dependsOn": ["bundle"],
79
+ "cache": true,
80
+ "inputs": [
81
+ "production",
82
+ "^production",
83
+ "{workspaceRoot}/packages/common/scripts/src/greengrass/**/*"
84
+ ],
85
+ "outputs": [
86
+ "{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/greengrass-build"
87
+ ],
88
+ "options": {
89
+ "command": "tsx packages/common/scripts/src/greengrass/build-artifact.ts {projectRoot} my-component dist/{projectRoot}/greengrass/my-component dist/{projectRoot}/bundle/greengrass/my-component"
90
+ }
91
+ },
92
+ "my-component-deploy-local": {
93
+ "executor": "nx:run-commands",
94
+ "dependsOn": ["my-component-artifact"],
95
+ "options": {
96
+ "command": "tsx packages/common/scripts/src/greengrass/deploy-local.ts dist/{projectRoot}/greengrass/my-component"
97
+ }
98
+ },
99
+ "my-component-logs": {
100
+ "executor": "nx:run-commands",
101
+ "continuous": true,
102
+ "options": {
103
+ "command": "tsx packages/common/scripts/src/greengrass/component-logs.ts com.proj.MyComponent"
104
+ }
105
+ }
106
+ }
107
+ }
108
+ ",
109
+ "packages/test-project/rolldown.config.ts": "import { defineConfig } from 'rolldown';
110
+
111
+ export default defineConfig([
112
+ {
113
+ tsconfig: 'tsconfig.lib.json',
114
+ input: 'src/greengrass/my-component/main.ts',
115
+ output: {
116
+ file: '../../dist/packages/test-project/bundle/greengrass/my-component/index.js',
117
+ format: 'cjs',
118
+ codeSplitting: false,
119
+ },
120
+ platform: 'node',
121
+ },
122
+ ]);
123
+ ",
124
+ "packages/test-project/src/greengrass/my-component/main.ts": "const RUN_INTERVAL_MS = 30_000;
125
+
126
+ export function runOnce(sequence: number): void {
127
+ console.log(
128
+ \`[com.proj.MyComponent] heartbeat \${sequence} at \${new Date().toISOString()}\`,
129
+ );
130
+ }
131
+
132
+ async function main(): Promise<void> {
133
+ let sequence = 0;
134
+ for (;;) {
135
+ runOnce(sequence);
136
+ sequence += 1;
137
+ await new Promise((resolve) => setTimeout(resolve, RUN_INTERVAL_MS));
138
+ }
139
+ }
140
+
141
+ main();
142
+ ",
143
+ }
144
+ `;
145
+
146
+ exports[`greengrass#component generator (typescript) > should match snapshot > main-snapshot 1`] = `
147
+ {
148
+ "packages/test-project/greengrass/my-component/recipe.yaml": "RecipeFormatVersion: '2020-01-25'
149
+ ComponentName: com.proj.MyComponent
150
+ ComponentVersion: 1.0.0
151
+ ComponentDescription: com.proj.MyComponent Greengrass component, generated by greengrass#component.
152
+ ComponentPublisher: proj
153
+ Manifests:
154
+ - Platform:
155
+ os: linux
156
+ architecture: aarch64
157
+ Artifacts:
158
+ # Placeholders are substituted at publish time. The basename must stay
159
+ # my-component.zip, which is what the Run script below unarchives to.
160
+ - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component.zip
161
+ Unarchive: ZIP
162
+ Lifecycle:
163
+ # Requires a node binary on the device's PATH. The generated bundle was
164
+ # tested with Node.js 22; Greengrass uses the installed runtime.
165
+ Run: node {artifacts:decompressedPath}/my-component/index.js
166
+ ",
167
+ "packages/test-project/project.json": "{
168
+ "name": "test-project",
169
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
170
+ "sourceRoot": "packages/test-project/src",
171
+ "metadata": {
172
+ "components": [
173
+ {
174
+ "generator": "greengrass#component",
175
+ "path": "src/greengrass/my-component/main.ts",
176
+ "name": "my-component",
177
+ "language": "typescript",
178
+ "componentName": "com.proj.MyComponent",
179
+ "componentVersion": "1.0.0",
180
+ "platform": "linux-arm64",
181
+ "ipc": false,
182
+ "gdkConfig": false
183
+ }
184
+ ]
185
+ },
186
+ "targets": {
187
+ "assemble": {
188
+ "dependsOn": ["bundle", "my-component-artifact"]
189
+ },
190
+ "build": {
191
+ "dependsOn": ["bundle", "my-component-artifact"]
192
+ },
193
+ "bundle": {
194
+ "executor": "nx:run-commands",
195
+ "dependsOn": ["compile"],
196
+ "cache": true,
197
+ "inputs": ["default"],
198
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle"],
199
+ "options": {
200
+ "command": "rolldown -c rolldown.config.ts",
201
+ "cwd": "{projectRoot}"
202
+ }
203
+ },
204
+ "compile": {
205
+ "executor": "@nx/js:tsc"
206
+ },
207
+ "my-component-artifact": {
208
+ "executor": "nx:run-commands",
209
+ "dependsOn": ["bundle"],
210
+ "cache": true,
211
+ "inputs": [
212
+ "production",
213
+ "^production",
214
+ "{workspaceRoot}/packages/common/scripts/src/greengrass/**/*"
215
+ ],
216
+ "outputs": [
217
+ "{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/greengrass-build"
218
+ ],
219
+ "options": {
220
+ "command": "tsx packages/common/scripts/src/greengrass/build-artifact.ts {projectRoot} my-component dist/{projectRoot}/greengrass/my-component dist/{projectRoot}/bundle/greengrass/my-component"
221
+ }
222
+ },
223
+ "my-component-deploy-local": {
224
+ "executor": "nx:run-commands",
225
+ "dependsOn": ["my-component-artifact"],
226
+ "options": {
227
+ "command": "tsx packages/common/scripts/src/greengrass/deploy-local.ts dist/{projectRoot}/greengrass/my-component"
228
+ }
229
+ },
230
+ "my-component-logs": {
231
+ "executor": "nx:run-commands",
232
+ "continuous": true,
233
+ "options": {
234
+ "command": "tsx packages/common/scripts/src/greengrass/component-logs.ts com.proj.MyComponent"
235
+ }
236
+ }
237
+ }
238
+ }
239
+ ",
240
+ "packages/test-project/rolldown.config.ts": "import { defineConfig } from 'rolldown';
241
+
242
+ export default defineConfig([
243
+ {
244
+ tsconfig: 'tsconfig.lib.json',
245
+ input: 'src/greengrass/my-component/main.ts',
246
+ output: {
247
+ file: '../../dist/packages/test-project/bundle/greengrass/my-component/index.js',
248
+ format: 'cjs',
249
+ codeSplitting: false,
250
+ },
251
+ platform: 'node',
252
+ },
253
+ ]);
254
+ ",
255
+ "packages/test-project/src/greengrass/my-component/main.ts": "const RUN_INTERVAL_MS = 30_000;
256
+
257
+ export function runOnce(sequence: number): void {
258
+ console.log(
259
+ \`[com.proj.MyComponent] heartbeat \${sequence} at \${new Date().toISOString()}\`,
260
+ );
261
+ }
262
+
263
+ async function main(): Promise<void> {
264
+ let sequence = 0;
265
+ for (;;) {
266
+ runOnce(sequence);
267
+ sequence += 1;
268
+ await new Promise((resolve) => setTimeout(resolve, RUN_INTERVAL_MS));
269
+ }
270
+ }
271
+
272
+ main();
273
+ ",
274
+ }
275
+ `;
@@ -0,0 +1,41 @@
1
+ RecipeFormatVersion: '<%- recipeFormat %>'
2
+ ComponentName: <%- componentName %>
3
+ ComponentVersion: <%- version %>
4
+ ComponentDescription: <%- componentDescription %>
5
+ ComponentPublisher: <%- publisher %>
6
+ <%_ if (ipc) { _%>
7
+ ComponentConfiguration:
8
+ DefaultConfiguration:
9
+ accessControl:
10
+ aws.greengrass.ipc.pubsub:
11
+ <%- componentName %>:pubsub:1:
12
+ policyDescription: Allow publishing heartbeat messages to this component's own topic.
13
+ operations:
14
+ - aws.greengrass#PublishToTopic
15
+ resources:
16
+ - <%- componentName %>/heartbeat
17
+ <%_ } _%>
18
+ Manifests:
19
+ <%_ manifests.forEach((m) => { _%>
20
+ - Platform:
21
+ os: <%- m.os %>
22
+ architecture: <%- m.architecture %>
23
+ Artifacts:
24
+ # Placeholders are substituted at publish time. The basename must stay
25
+ # <%- m.artifactBaseName %>.zip, which is what the Run script below unarchives to.
26
+ - Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/<%- m.artifactBaseName %>.zip
27
+ Unarchive: ZIP
28
+ Lifecycle:
29
+ <%_ if (ipc) { _%>
30
+ # aws-crt ships its native addon prebuilt for every platform it supports,
31
+ # so this component's build copies this architecture's copy into the
32
+ # artifact and aws-crt's own loader reads it from this path, resolved
33
+ # relative to index.js. There is no Install step: the decompressed
34
+ # artifact folder is read-only by contract, and nothing here writes to it.
35
+ Setenv:
36
+ AWS_CRT_NODEJS_BINARY_RELATIVE_PATH: native/aws-crt/<%- m.nodeCrtAddonDir %>/aws-crt-nodejs.node
37
+ <%_ } _%>
38
+ # Requires a node binary on the device's PATH. The generated bundle was
39
+ # tested with Node.js 22; Greengrass uses the installed runtime.
40
+ Run: node {artifacts:decompressedPath}/<%- m.artifactBaseName %>/index.js
41
+ <%_ }); _%>