@aws/nx-plugin 1.0.0-rc.56 → 1.0.0-rc.58

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 (179) hide show
  1. package/LICENSE-THIRD-PARTY +2917 -1295
  2. package/migrations.json +34 -24
  3. package/package.json +13 -13
  4. package/src/agentcore-gateway/generator.d.ts +16 -1
  5. package/src/agentcore-gateway/generator.js +3 -2
  6. package/src/agentcore-gateway/generator.js.map +1 -1
  7. package/src/agentcore-gateway/schema.json +1 -0
  8. package/src/connection/scaffold-catalog.d.ts +160 -0
  9. package/src/connection/scaffold-catalog.js +207 -0
  10. package/src/connection/scaffold-catalog.js.map +1 -0
  11. package/src/connection/schema-resolver.d.ts +5 -0
  12. package/src/connection/schema-resolver.js +27 -0
  13. package/src/connection/schema-resolver.js.map +1 -0
  14. package/src/infra/app/__snapshots__/generator.spec.ts.snap +7 -7
  15. package/src/migrations/latest/smithy-ssdk-bundle-pins/migration.js +78 -0
  16. package/src/migrations/latest/smithy-ssdk-bundle-pins/migration.js.map +1 -0
  17. package/src/migrations/v1.0.0-rc.50/modernize-function-props-cast/migration.js.map +1 -0
  18. package/src/migrations/v1.0.0-rc.50/restrict-cors-to-custom-domains/migration.js.map +1 -0
  19. package/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/migration.d.ts +6 -0
  20. package/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/migration.js.map +1 -0
  21. package/src/migrations/v1.0.0-rc.52/user-identity-waf-allow-localhost-callback/migration.js.map +1 -0
  22. package/src/migrations/v1.0.0-rc.54/order-access-log-delivery-after-bucket-policy/migration.js.map +1 -0
  23. package/src/migrations/v1.0.0-rc.55/backfill-generator-metadata/migration.js.map +1 -0
  24. package/src/migrations/v1.0.0-rc.56/dynamodb-local-remove-optimize-flag/migration.js.map +1 -0
  25. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.d.ts +6 -0
  26. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.js +449 -0
  27. package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/migration.js.map +1 -0
  28. package/src/preset/__snapshots__/generator.spec.ts.snap +5 -5
  29. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +11 -9
  30. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +20 -20
  31. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +3 -3
  32. package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
  33. package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client_strands.py.template +2 -1
  34. package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +2 -1
  35. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  36. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  37. package/src/py/agent/generator.js +4 -0
  38. package/src/py/agent/generator.js.map +1 -1
  39. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
  40. package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client_strands.py.template +2 -1
  41. package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +2 -1
  42. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  43. package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +6 -0
  44. package/src/py/agent/schema.d.js.map +1 -1
  45. package/src/py/agent/schema.d.ts +3 -0
  46. package/src/py/agent/schema.json +9 -0
  47. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
  48. package/src/py/dynamodb/schema.json +1 -0
  49. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
  50. package/src/py/fast-api/generator.d.ts +5 -0
  51. package/src/py/fast-api/generator.js +3 -2
  52. package/src/py/fast-api/generator.js.map +1 -1
  53. package/src/py/fast-api/schema.json +1 -0
  54. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  55. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +9 -7
  56. package/src/py/mcp-server/schema.json +1 -0
  57. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +2 -2
  58. package/src/py/rdb/schema.json +1 -0
  59. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +4 -4
  60. package/src/smithy/project/files/service/build.Dockerfile.template +2 -2
  61. package/src/smithy/project/generator.d.ts +25 -0
  62. package/src/smithy/project/generator.js +24 -3
  63. package/src/smithy/project/generator.js.map +1 -1
  64. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +7 -7
  65. package/src/smithy/ts/api/generator.d.ts +6 -1
  66. package/src/smithy/ts/api/generator.js +3 -2
  67. package/src/smithy/ts/api/generator.js.map +1 -1
  68. package/src/smithy/ts/api/schema.json +1 -0
  69. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +12 -12
  70. package/src/trpc/backend/generator.d.ts +6 -1
  71. package/src/trpc/backend/generator.js +3 -2
  72. package/src/trpc/backend/generator.js.map +1 -1
  73. package/src/trpc/backend/schema.json +1 -0
  74. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +668 -24
  75. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
  76. package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client-strands.ts.template +1 -1
  77. package/src/ts/agent/files/ag-ui/index.ts.template +10 -1
  78. package/src/ts/agent/files/common/agent.ts.template +11 -3
  79. package/src/ts/agent/files/common/session.ts.template +43 -0
  80. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +1 -0
  81. package/src/ts/agent/generator.d.ts +36 -1
  82. package/src/ts/agent/generator.js +28 -4
  83. package/src/ts/agent/generator.js.map +1 -1
  84. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
  85. package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client-strands.ts.template +2 -1
  86. package/src/ts/agent/react-connection/__snapshots__/generator.spec.ts.snap +8 -4
  87. package/src/ts/agent/react-connection/files/src/components/__agentNameClassName__AgentClientProvider.tsx.template +2 -1
  88. package/src/ts/agent/schema.d.js.map +1 -1
  89. package/src/ts/agent/schema.d.ts +3 -0
  90. package/src/ts/agent/schema.json +9 -0
  91. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +1 -1
  92. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
  93. package/src/ts/dynamodb/schema.json +1 -0
  94. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  95. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +6 -4
  96. package/src/ts/mcp-server/generator.d.ts +32 -1
  97. package/src/ts/mcp-server/generator.js +7 -4
  98. package/src/ts/mcp-server/generator.js.map +1 -1
  99. package/src/ts/mcp-server/schema.json +1 -0
  100. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +6 -6
  101. package/src/ts/rdb/generator.d.ts +8 -0
  102. package/src/ts/rdb/generator.js +3 -2
  103. package/src/ts/rdb/generator.js.map +1 -1
  104. package/src/ts/rdb/schema.json +1 -0
  105. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +61 -45
  106. package/src/ts/react-website/app/generator.d.ts +6 -1
  107. package/src/ts/react-website/app/generator.js +3 -2
  108. package/src/ts/react-website/app/generator.js.map +1 -1
  109. package/src/ts/react-website/app/schema.json +1 -0
  110. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
  111. package/src/ts/react-website/cognito-auth/generator.d.ts +6 -1
  112. package/src/ts/react-website/cognito-auth/generator.js +3 -2
  113. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  114. package/src/utils/agent-chat/files/common/agentcore.ts.template +2 -2
  115. package/src/utils/agent-connection/agent-connection.js +4 -0
  116. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  117. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +11 -1
  118. package/src/utils/agent-connection/files/core-strands/base/model-errors-strands.ts.template +26 -15
  119. package/src/utils/agent-connection/files/core-strands/base/tool-errors-strands.ts.template +23 -16
  120. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +4 -3
  121. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +22 -0
  122. package/src/utils/agent-core-constructs/agent-core-constructs.js +29 -2
  123. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  124. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +131 -3
  125. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +180 -1
  126. package/src/utils/api-constructs/api-constructs.d.ts +9 -0
  127. package/src/utils/api-constructs/api-constructs.js +11 -1
  128. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  129. package/src/utils/ast.d.ts +5 -0
  130. package/src/utils/ast.js +25 -0
  131. package/src/utils/ast.js.map +1 -1
  132. package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +2 -0
  133. package/src/utils/docker.d.ts +27 -2
  134. package/src/utils/docker.js +31 -2
  135. package/src/utils/docker.js.map +1 -1
  136. package/src/utils/identity-constructs/identity-constructs.d.ts +10 -0
  137. package/src/utils/identity-constructs/identity-constructs.js +11 -1
  138. package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
  139. package/src/utils/shared-constructs-constants.d.ts +6 -0
  140. package/src/utils/shared-constructs-constants.js +5 -0
  141. package/src/utils/shared-constructs-constants.js.map +1 -1
  142. package/src/utils/version-upgrade-migration/owned-dependencies.d.ts +26 -0
  143. package/src/utils/version-upgrade-migration/owned-dependencies.js +52 -4
  144. package/src/utils/version-upgrade-migration/owned-dependencies.js.map +1 -1
  145. package/src/utils/version-upgrade-migration/register.d.ts +5 -1
  146. package/src/utils/version-upgrade-migration/register.js +6 -2
  147. package/src/utils/version-upgrade-migration/register.js.map +1 -1
  148. package/src/utils/version-upgrade-migration/sync-embedded-versions.d.ts +26 -0
  149. package/src/utils/version-upgrade-migration/sync-embedded-versions.js +304 -0
  150. package/src/utils/version-upgrade-migration/sync-embedded-versions.js.map +1 -0
  151. package/src/utils/version-upgrade-migration/sync-vended-versions.js +14 -0
  152. package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -1
  153. package/src/utils/versions.d.ts +90 -77
  154. package/src/utils/versions.js +86 -75
  155. package/src/utils/versions.js.map +1 -1
  156. package/src/utils/website-constructs/website-constructs.d.ts +11 -0
  157. package/src/utils/website-constructs/website-constructs.js +12 -1
  158. package/src/utils/website-constructs/website-constructs.js.map +1 -1
  159. package/src/migrations/latest/backfill-generator-metadata/migration.js.map +0 -1
  160. package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js.map +0 -1
  161. package/src/migrations/latest/modernize-function-props-cast/migration.js.map +0 -1
  162. package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js.map +0 -1
  163. package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js.map +0 -1
  164. package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js.map +0 -1
  165. package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js.map +0 -1
  166. /package/src/migrations/latest/{modernize-function-props-cast → smithy-ssdk-bundle-pins}/migration.d.ts +0 -0
  167. /package/src/migrations/{latest/restrict-cors-to-custom-domains → v1.0.0-rc.50/modernize-function-props-cast}/migration.d.ts +0 -0
  168. /package/src/migrations/{latest → v1.0.0-rc.50}/modernize-function-props-cast/migration.js +0 -0
  169. /package/src/migrations/{latest/terraform-bootstrap-adopt-existing-bucket → v1.0.0-rc.50/restrict-cors-to-custom-domains}/migration.d.ts +0 -0
  170. /package/src/migrations/{latest → v1.0.0-rc.50}/restrict-cors-to-custom-domains/migration.js +0 -0
  171. /package/src/migrations/{latest → v1.0.0-rc.50}/terraform-bootstrap-adopt-existing-bucket/migration.js +0 -0
  172. /package/src/migrations/{latest/dynamodb-local-remove-optimize-flag → v1.0.0-rc.52/user-identity-waf-allow-localhost-callback}/migration.d.ts +0 -0
  173. /package/src/migrations/{latest → v1.0.0-rc.52}/user-identity-waf-allow-localhost-callback/migration.js +0 -0
  174. /package/src/migrations/{latest → v1.0.0-rc.54}/order-access-log-delivery-after-bucket-policy/migration.d.ts +0 -0
  175. /package/src/migrations/{latest → v1.0.0-rc.54}/order-access-log-delivery-after-bucket-policy/migration.js +0 -0
  176. /package/src/migrations/{latest → v1.0.0-rc.55}/backfill-generator-metadata/migration.d.ts +0 -0
  177. /package/src/migrations/{latest → v1.0.0-rc.55}/backfill-generator-metadata/migration.js +0 -0
  178. /package/src/migrations/{latest/user-identity-waf-allow-localhost-callback → v1.0.0-rc.56/dynamodb-local-remove-optimize-flag}/migration.d.ts +0 -0
  179. /package/src/migrations/{latest → v1.0.0-rc.56}/dynamodb-local-remove-optimize-flag/migration.js +0 -0
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import GeneratorsJson from "../../generators.json" with {
5
+ type: 'json'
6
+ };
7
+ import { SUPPORTED_CONNECTIONS } from "./supported-connections.js";
8
+ const GENERATORS = GeneratorsJson.generators;
9
+ /** The path `generators.json` records for a generator, relative to the plugin root. */ export const schemaPathOf = (generatorId)=>{
10
+ const entry = GENERATORS[generatorId];
11
+ if (!entry) {
12
+ throw new Error(`Scaffold catalog: '${generatorId}' is not in generators.json`);
13
+ }
14
+ return entry.schema;
15
+ };
16
+ /** The language prefix of a generator id: `ts` for `ts#agent`, `` for `license`. */ const languageOf = (id)=>id.includes('#') ? id.slice(0, id.indexOf('#')) : '';
17
+ /** Compare ids ignoring the separators that differ between wrapper and variant. */ const alike = (a, b)=>a.replace(/[^a-z0-9]/gi, '').toLowerCase() === b.replace(/[^a-z0-9]/gi, '').toLowerCase();
18
+ /**
19
+ * The public generator and option value that select a hidden endpoint type.
20
+ *
21
+ * A wrapper like `ts#api` produces several endpoint types, choosing between them
22
+ * with an enum option: `--framework=trpc` yields `ts#trpc-api`. The pairing is
23
+ * found by looking for a same-language public generator with an enum value that
24
+ * reconstructs the endpoint's own name.
25
+ */ const findWrapper = (endpointType, schemaOf)=>{
26
+ const language = languageOf(endpointType);
27
+ const name = endpointType.slice(endpointType.indexOf('#') + 1);
28
+ for (const [generatorId, entry] of Object.entries(GENERATORS)){
29
+ if (entry.hidden) continue;
30
+ if (languageOf(generatorId) !== language) continue;
31
+ const wrapperName = generatorId.slice(generatorId.indexOf('#') + 1);
32
+ for (const [option, property] of Object.entries(schemaOf(generatorId).properties ?? {})){
33
+ for (const value of property.enum ?? []){
34
+ // Either the value names the variant outright (`react` for
35
+ // `react-website`), or it qualifies the wrapper's own name
36
+ // (`trpc` + `api` for `trpc-api`).
37
+ if (alike(value, name) || alike(`${value}${wrapperName}`, name)) {
38
+ return {
39
+ generator: generatorId,
40
+ options: {
41
+ [option]: value
42
+ }
43
+ };
44
+ }
45
+ }
46
+ }
47
+ }
48
+ return undefined;
49
+ };
50
+ /**
51
+ * Derive the recipe for one endpoint type. Exported so a test can assert the
52
+ * derivation against every type the plugin supports.
53
+ */ export const deriveScaffoldRecipe = (endpointType, schemaOf)=>{
54
+ const own = GENERATORS[endpointType];
55
+ if (!own) {
56
+ throw new Error(`Scaffold catalog: connection endpoint '${endpointType}' is not a generator id`);
57
+ }
58
+ // A hidden generator is an implementation detail reached through its public
59
+ // wrapper, which is what a user would actually run.
60
+ const wrapper = own.hidden ? findWrapper(endpointType, schemaOf) : undefined;
61
+ if (own.hidden && !wrapper) {
62
+ throw new Error(`Scaffold catalog: '${endpointType}' is hidden and no public generator selects it`);
63
+ }
64
+ // A generator requiring a `project` adds a component to one; anything else
65
+ // creates its own project.
66
+ const kind = (schemaOf(endpointType).required ?? []).includes('project') ? 'component' : 'project';
67
+ const language = languageOf(endpointType);
68
+ const hostGenerator = `${language}#project`;
69
+ if (kind === 'component' && !GENERATORS[hostGenerator]) {
70
+ throw new Error(`Scaffold catalog: '${endpointType}' is a component but '${hostGenerator}' does not exist to host it`);
71
+ }
72
+ return {
73
+ // `x-label` is the short noun a palette entry needs; `title` and
74
+ // `description` are prose aimed at CLI prompts ("Create a relational database
75
+ // project"). A generator without one falls back to its id, so a new endpoint
76
+ // type still appears rather than being dropped.
77
+ label: schemaOf(endpointType)['x-label'] ?? endpointType,
78
+ generator: wrapper?.generator ?? endpointType,
79
+ ...wrapper ? {
80
+ options: wrapper.options
81
+ } : {},
82
+ kind,
83
+ ...kind === 'component' ? {
84
+ host: {
85
+ generator: hostGenerator,
86
+ // Only options the host's schema actually requires, so a base
87
+ // project generator gaining a required option is handled here.
88
+ options: Object.fromEntries((schemaOf(hostGenerator).required ?? []).filter((option)=>option !== 'name').map((option)=>{
89
+ const property = schemaOf(hostGenerator).properties?.[option];
90
+ const value = property?.default ?? property?.enum?.[0];
91
+ if (value === undefined) {
92
+ throw new Error(`Scaffold catalog: '${hostGenerator}' requires '${option}' but its schema offers no value to use`);
93
+ }
94
+ return [
95
+ option,
96
+ String(value)
97
+ ];
98
+ })),
99
+ // Python project names are snake_cased when Nx qualifies them.
100
+ snakeCaseName: language === 'py'
101
+ }
102
+ } : {}
103
+ };
104
+ };
105
+ /** Every endpoint type appearing at either end of a supported connection. */ export const CONNECTION_ENDPOINT_TYPES = [
106
+ ...new Set(SUPPORTED_CONNECTIONS.flatMap(({ source, target })=>[
107
+ source,
108
+ target
109
+ ]))
110
+ ].sort();
111
+ /**
112
+ * How to scaffold each connection endpoint type, derived from the generator
113
+ * metadata. A connection added to `SUPPORTED_CONNECTIONS` appears here with no
114
+ * edit to this file.
115
+ */ export const buildScaffoldRecipes = (schemaOf)=>Object.fromEntries(CONNECTION_ENDPOINT_TYPES.map((type)=>[
116
+ type,
117
+ deriveScaffoldRecipe(type, schemaOf)
118
+ ]));
119
+ /** Reusable constraint shapes, so the map below states each rule once. */ const AGENT_TO_AGENT = [
120
+ {
121
+ side: 'target',
122
+ option: 'protocol',
123
+ equals: 'a2a',
124
+ reason: 'Only an A2A agent can be connected to another agent as a tool.'
125
+ },
126
+ {
127
+ side: 'target',
128
+ option: 'auth',
129
+ equals: 'iam',
130
+ reason: 'A2A agent connections authenticate with IAM.'
131
+ }
132
+ ];
133
+ const WEBSITE_TO_AGENT = [
134
+ {
135
+ side: 'target',
136
+ option: 'protocol',
137
+ notEquals: 'a2a',
138
+ reason: 'A2A agents are reached by other agents, not by a website. Use the http or ag-ui protocol.'
139
+ }
140
+ ];
141
+ const AGENT_TO_MCP = [
142
+ {
143
+ side: 'target',
144
+ option: 'auth',
145
+ equals: 'iam',
146
+ reason: 'An agent reaches an MCP server with IAM authentication.'
147
+ }
148
+ ];
149
+ const AGENT_TO_GATEWAY = [
150
+ {
151
+ side: 'source',
152
+ option: 'auth',
153
+ equals: 'iam',
154
+ reason: 'Only an IAM-authenticated agent can reach an IAM gateway.'
155
+ },
156
+ {
157
+ side: 'target',
158
+ option: 'auth',
159
+ equals: 'iam',
160
+ reason: 'Agent connections require the gateway to authenticate with IAM.'
161
+ }
162
+ ];
163
+ const GATEWAY_TO_MCP = [
164
+ {
165
+ side: 'target',
166
+ option: 'auth',
167
+ equals: 'iam',
168
+ reason: 'A gateway reaches an MCP server target with IAM authentication.'
169
+ }
170
+ ];
171
+ /**
172
+ * The option-level requirements each connection places on its endpoints.
173
+ *
174
+ * Only connections carrying a requirement appear. Keyed by `ConnectionKey`, so a
175
+ * key that no longer names a supported connection is a compile error.
176
+ */ export const CONNECTION_CONSTRAINTS = {
177
+ 'ts#react-website -> ts#agent': WEBSITE_TO_AGENT,
178
+ 'ts#react-website -> py#agent': WEBSITE_TO_AGENT,
179
+ 'ts#agent -> ts#agent': AGENT_TO_AGENT,
180
+ 'ts#agent -> py#agent': AGENT_TO_AGENT,
181
+ 'py#agent -> ts#agent': AGENT_TO_AGENT,
182
+ 'py#agent -> py#agent': AGENT_TO_AGENT,
183
+ 'ts#agent -> ts#mcp-server': AGENT_TO_MCP,
184
+ 'ts#agent -> py#mcp-server': AGENT_TO_MCP,
185
+ 'py#agent -> ts#mcp-server': AGENT_TO_MCP,
186
+ 'py#agent -> py#mcp-server': AGENT_TO_MCP,
187
+ 'ts#agent -> agentcore-gateway': AGENT_TO_GATEWAY,
188
+ 'py#agent -> agentcore-gateway': AGENT_TO_GATEWAY,
189
+ 'agentcore-gateway -> ts#mcp-server': GATEWAY_TO_MCP,
190
+ 'agentcore-gateway -> py#mcp-server': GATEWAY_TO_MCP,
191
+ 'agentcore-gateway -> agentcore-gateway': [
192
+ {
193
+ side: 'target',
194
+ option: 'auth',
195
+ equals: 'iam',
196
+ reason: 'The source gateway signs its request with IAM, so the target gateway must accept IAM.'
197
+ }
198
+ ]
199
+ };
200
+ /**
201
+ * Connections whose source and target must be distinct projects, because the
202
+ * connection generator refuses to wire a project to itself.
203
+ */ export const SELF_CONNECTION_DISALLOWED = [
204
+ 'agentcore-gateway -> agentcore-gateway'
205
+ ];
206
+
207
+ //# sourceMappingURL=scaffold-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/connection/scaffold-catalog.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport {\n type ConnectionKey,\n SUPPORTED_CONNECTIONS,\n type SUPPORTED_PROJECT_TYPES,\n} from './supported-connections';\n\n/**\n * How to scaffold each end of a connection, derived from the plugin's own\n * metadata rather than hand-listed.\n *\n * Every connection endpoint type is also a generator id, which is what makes the\n * derivation possible:\n *\n * - **kind** — a generator whose schema `required`s a `project` adds a component\n * to an existing project; anything else creates a project of its own.\n * - **host** — a component lands in a project made by its language's base\n * generator (`ts#project` / `py#project`).\n * - **generator + options** — a type whose own generator is `hidden` is reached\n * through the public wrapper that selects it, found by matching the wrapper's\n * enum values against the type's name (`ts#trpc-api` ← `ts#api\n * --framework=trpc`). A visible generator is run directly.\n *\n * - **label** — the generator schema's own `x-label`.\n *\n * The result is that adding a generator and a connection for it needs no edit\n * here at all. The one thing still declared below is the option constraints,\n * which live as imperative guards inside each connection generator and so cannot\n * be read from metadata.\n */\n\n/**\n * Every type that can sit at either end of a connection: the project-level\n * types resolved by introspection, plus the component generator ids recorded in\n * component metadata.\n */\nexport type ConnectionEndpointType =\n | (typeof SUPPORTED_PROJECT_TYPES)[number]\n | (typeof SUPPORTED_CONNECTIONS)[number]['source']\n | (typeof SUPPORTED_CONNECTIONS)[number]['target'];\n\n/**\n * Whether scaffolding an endpoint creates a project of its own, or adds a\n * component to a project that must already exist.\n */\nexport type ScaffoldKind = 'project' | 'component';\n\n/** How to scaffold one end of a connection from the CLI. */\nexport interface ScaffoldRecipe {\n /** Human-readable name for this endpoint type. */\n readonly label: string;\n /** The generator id in `generators.json` that produces this endpoint. */\n readonly generator: string;\n /**\n * Options that select this endpoint type from its generator, for generators\n * producing more than one type (e.g. `framework`).\n */\n readonly options?: Readonly<Record<string, string>>;\n /** Whether the generator creates a project or adds a component to one. */\n readonly kind: ScaffoldKind;\n /**\n * The generator producing a project able to host this component, for\n * `component` recipes. Components are added to an existing project, so one\n * must be scaffolded first.\n */\n readonly host?: {\n readonly generator: string;\n readonly options?: Readonly<Record<string, string>>;\n /**\n * Whether the host project's name is referenced in snake_case. Python\n * project names are snake_cased when qualified, TypeScript ones are not.\n */\n readonly snakeCaseName?: boolean;\n };\n}\n\ntype GeneratorEntry = { schema: string; hidden?: boolean };\n/** The subset of JSON Schema the catalogue and the docs builder read. */\nexport type GeneratorSchema = {\n /**\n * Short display name for the thing this generator produces, used by the docs\n * graph builder's palette. Set it on any generator that can take part in a\n * connection.\n */\n 'x-label'?: string;\n properties?: Record<\n string,\n {\n type?: string;\n description?: string;\n enum?: string[];\n default?: unknown;\n 'x-priority'?: string;\n }\n >;\n required?: string[];\n};\n\ntype Schema = GeneratorSchema;\n\nconst GENERATORS = GeneratorsJson.generators as Record<string, GeneratorEntry>;\n\n/**\n * Resolves a generator's JSON schema by generator id.\n *\n * Injected rather than fixed because the two callers load files differently: the\n * plugin reads from disk (see `./schema-resolver`), while the docs site bundles\n * the schemas for the browser, where `node:fs` does not exist. Keeping this\n * module free of `node:fs` is what lets the browser import it at all.\n */\nexport type SchemaResolver = (generatorId: string) => Schema;\n\n/** The path `generators.json` records for a generator, relative to the plugin root. */\nexport const schemaPathOf = (generatorId: string): string => {\n const entry = GENERATORS[generatorId];\n if (!entry) {\n throw new Error(\n `Scaffold catalog: '${generatorId}' is not in generators.json`,\n );\n }\n return entry.schema;\n};\n\n/** The language prefix of a generator id: `ts` for `ts#agent`, `` for `license`. */\nconst languageOf = (id: string): string =>\n id.includes('#') ? id.slice(0, id.indexOf('#')) : '';\n\n/** Compare ids ignoring the separators that differ between wrapper and variant. */\nconst alike = (a: string, b: string): boolean =>\n a.replace(/[^a-z0-9]/gi, '').toLowerCase() ===\n b.replace(/[^a-z0-9]/gi, '').toLowerCase();\n\n/**\n * The public generator and option value that select a hidden endpoint type.\n *\n * A wrapper like `ts#api` produces several endpoint types, choosing between them\n * with an enum option: `--framework=trpc` yields `ts#trpc-api`. The pairing is\n * found by looking for a same-language public generator with an enum value that\n * reconstructs the endpoint's own name.\n */\nconst findWrapper = (\n endpointType: string,\n schemaOf: SchemaResolver,\n): { generator: string; options: Record<string, string> } | undefined => {\n const language = languageOf(endpointType);\n const name = endpointType.slice(endpointType.indexOf('#') + 1);\n\n for (const [generatorId, entry] of Object.entries(GENERATORS)) {\n if (entry.hidden) continue;\n if (languageOf(generatorId) !== language) continue;\n const wrapperName = generatorId.slice(generatorId.indexOf('#') + 1);\n\n for (const [option, property] of Object.entries(\n schemaOf(generatorId).properties ?? {},\n )) {\n for (const value of property.enum ?? []) {\n // Either the value names the variant outright (`react` for\n // `react-website`), or it qualifies the wrapper's own name\n // (`trpc` + `api` for `trpc-api`).\n if (alike(value, name) || alike(`${value}${wrapperName}`, name)) {\n return { generator: generatorId, options: { [option]: value } };\n }\n }\n }\n }\n return undefined;\n};\n\n/**\n * Derive the recipe for one endpoint type. Exported so a test can assert the\n * derivation against every type the plugin supports.\n */\nexport const deriveScaffoldRecipe = (\n endpointType: string,\n schemaOf: SchemaResolver,\n): ScaffoldRecipe => {\n const own = GENERATORS[endpointType];\n if (!own) {\n throw new Error(\n `Scaffold catalog: connection endpoint '${endpointType}' is not a generator id`,\n );\n }\n\n // A hidden generator is an implementation detail reached through its public\n // wrapper, which is what a user would actually run.\n const wrapper = own.hidden ? findWrapper(endpointType, schemaOf) : undefined;\n if (own.hidden && !wrapper) {\n throw new Error(\n `Scaffold catalog: '${endpointType}' is hidden and no public generator selects it`,\n );\n }\n\n // A generator requiring a `project` adds a component to one; anything else\n // creates its own project.\n const kind: ScaffoldKind = (schemaOf(endpointType).required ?? []).includes(\n 'project',\n )\n ? 'component'\n : 'project';\n\n const language = languageOf(endpointType);\n const hostGenerator = `${language}#project`;\n if (kind === 'component' && !GENERATORS[hostGenerator]) {\n throw new Error(\n `Scaffold catalog: '${endpointType}' is a component but '${hostGenerator}' does not exist to host it`,\n );\n }\n\n return {\n // `x-label` is the short noun a palette entry needs; `title` and\n // `description` are prose aimed at CLI prompts (\"Create a relational database\n // project\"). A generator without one falls back to its id, so a new endpoint\n // type still appears rather than being dropped.\n label: schemaOf(endpointType)['x-label'] ?? endpointType,\n generator: wrapper?.generator ?? endpointType,\n ...(wrapper ? { options: wrapper.options } : {}),\n kind,\n ...(kind === 'component'\n ? {\n host: {\n generator: hostGenerator,\n // Only options the host's schema actually requires, so a base\n // project generator gaining a required option is handled here.\n options: Object.fromEntries(\n (schemaOf(hostGenerator).required ?? [])\n .filter((option) => option !== 'name')\n .map((option) => {\n const property = schemaOf(hostGenerator).properties?.[option];\n const value = property?.default ?? property?.enum?.[0];\n if (value === undefined) {\n throw new Error(\n `Scaffold catalog: '${hostGenerator}' requires '${option}' but its schema offers no value to use`,\n );\n }\n return [option, String(value)];\n }),\n ),\n // Python project names are snake_cased when Nx qualifies them.\n snakeCaseName: language === 'py',\n },\n }\n : {}),\n };\n};\n\n/** Every endpoint type appearing at either end of a supported connection. */\nexport const CONNECTION_ENDPOINT_TYPES: readonly string[] = [\n ...new Set(\n SUPPORTED_CONNECTIONS.flatMap(({ source, target }) => [source, target]),\n ),\n].sort();\n\n/**\n * How to scaffold each connection endpoint type, derived from the generator\n * metadata. A connection added to `SUPPORTED_CONNECTIONS` appears here with no\n * edit to this file.\n */\nexport const buildScaffoldRecipes = (\n schemaOf: SchemaResolver,\n): Readonly<Record<string, ScaffoldRecipe>> =>\n Object.fromEntries(\n CONNECTION_ENDPOINT_TYPES.map((type) => [\n type,\n deriveScaffoldRecipe(type, schemaOf),\n ]),\n );\n\n/**\n * A requirement one end of a connection places on the other's options, mirroring\n * the guard the corresponding connection generator enforces.\n *\n * Declared rather than derived: each guard is an imperative `throw` inside its\n * connection generator, reachable only by running it. Recording them here lets a\n * caller choosing options up front check them first, and the paired test asserts\n * every entry names a real option with a value its enum allows.\n */\nexport interface ConnectionConstraint {\n /** Which end of the connection the constrained option belongs to. */\n readonly side: 'source' | 'target';\n /** The generator option carrying the constrained value. */\n readonly option: string;\n /** The only value accepted, if the option is pinned to one. */\n readonly equals?: string;\n /** A value rejected, for options accepting all but one. */\n readonly notEquals?: string;\n /** Why the constraint exists, phrased for the user choosing the option. */\n readonly reason: string;\n}\n\n/** Reusable constraint shapes, so the map below states each rule once. */\nconst AGENT_TO_AGENT: readonly ConnectionConstraint[] = [\n {\n side: 'target',\n option: 'protocol',\n equals: 'a2a',\n reason: 'Only an A2A agent can be connected to another agent as a tool.',\n },\n {\n side: 'target',\n option: 'auth',\n equals: 'iam',\n reason: 'A2A agent connections authenticate with IAM.',\n },\n];\n\nconst WEBSITE_TO_AGENT: readonly ConnectionConstraint[] = [\n {\n side: 'target',\n option: 'protocol',\n notEquals: 'a2a',\n reason:\n 'A2A agents are reached by other agents, not by a website. Use the http or ag-ui protocol.',\n },\n];\n\nconst AGENT_TO_MCP: readonly ConnectionConstraint[] = [\n {\n side: 'target',\n option: 'auth',\n equals: 'iam',\n reason: 'An agent reaches an MCP server with IAM authentication.',\n },\n];\n\nconst AGENT_TO_GATEWAY: readonly ConnectionConstraint[] = [\n {\n side: 'source',\n option: 'auth',\n equals: 'iam',\n reason: 'Only an IAM-authenticated agent can reach an IAM gateway.',\n },\n {\n side: 'target',\n option: 'auth',\n equals: 'iam',\n reason: 'Agent connections require the gateway to authenticate with IAM.',\n },\n];\n\nconst GATEWAY_TO_MCP: readonly ConnectionConstraint[] = [\n {\n side: 'target',\n option: 'auth',\n equals: 'iam',\n reason: 'A gateway reaches an MCP server target with IAM authentication.',\n },\n];\n\n/**\n * The option-level requirements each connection places on its endpoints.\n *\n * Only connections carrying a requirement appear. Keyed by `ConnectionKey`, so a\n * key that no longer names a supported connection is a compile error.\n */\nexport const CONNECTION_CONSTRAINTS = {\n 'ts#react-website -> ts#agent': WEBSITE_TO_AGENT,\n 'ts#react-website -> py#agent': WEBSITE_TO_AGENT,\n 'ts#agent -> ts#agent': AGENT_TO_AGENT,\n 'ts#agent -> py#agent': AGENT_TO_AGENT,\n 'py#agent -> ts#agent': AGENT_TO_AGENT,\n 'py#agent -> py#agent': AGENT_TO_AGENT,\n 'ts#agent -> ts#mcp-server': AGENT_TO_MCP,\n 'ts#agent -> py#mcp-server': AGENT_TO_MCP,\n 'py#agent -> ts#mcp-server': AGENT_TO_MCP,\n 'py#agent -> py#mcp-server': AGENT_TO_MCP,\n 'ts#agent -> agentcore-gateway': AGENT_TO_GATEWAY,\n 'py#agent -> agentcore-gateway': AGENT_TO_GATEWAY,\n 'agentcore-gateway -> ts#mcp-server': GATEWAY_TO_MCP,\n 'agentcore-gateway -> py#mcp-server': GATEWAY_TO_MCP,\n 'agentcore-gateway -> agentcore-gateway': [\n {\n side: 'target',\n option: 'auth',\n equals: 'iam',\n reason:\n 'The source gateway signs its request with IAM, so the target gateway must accept IAM.',\n },\n ],\n} as const satisfies Partial<\n Record<ConnectionKey, readonly ConnectionConstraint[]>\n>;\n\n/**\n * Connections whose source and target must be distinct projects, because the\n * connection generator refuses to wire a project to itself.\n */\nexport const SELF_CONNECTION_DISALLOWED = [\n 'agentcore-gateway -> agentcore-gateway',\n] as const satisfies readonly ConnectionKey[];\n"],"names":["GeneratorsJson","type","SUPPORTED_CONNECTIONS","GENERATORS","generators","schemaPathOf","generatorId","entry","Error","schema","languageOf","id","includes","slice","indexOf","alike","a","b","replace","toLowerCase","findWrapper","endpointType","schemaOf","language","name","Object","entries","hidden","wrapperName","option","property","properties","value","enum","generator","options","undefined","deriveScaffoldRecipe","own","wrapper","kind","required","hostGenerator","label","host","fromEntries","filter","map","default","String","snakeCaseName","CONNECTION_ENDPOINT_TYPES","Set","flatMap","source","target","sort","buildScaffoldRecipes","AGENT_TO_AGENT","side","equals","reason","WEBSITE_TO_AGENT","notEquals","AGENT_TO_MCP","AGENT_TO_GATEWAY","GATEWAY_TO_MCP","CONNECTION_CONSTRAINTS","SELF_CONNECTION_DISALLOWED"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type ScaffoldRecipe, type SchemaResolver } from './scaffold-catalog';
2
+ /** Reads schemas from disk, for the plugin and its tests. */
3
+ export declare const nodeSchemaResolver: SchemaResolver;
4
+ /** The scaffold recipes, resolved from the schemas on disk. */
5
+ export declare const SCAFFOLD_RECIPES: Readonly<Record<string, ScaffoldRecipe>>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { readFileSync } from "node:fs";
5
+ import * as path from "node:path";
6
+ import { buildScaffoldRecipes, schemaPathOf } from "./scaffold-catalog.js";
7
+ /** Reads schemas from disk, for the plugin and its tests. */ export const nodeSchemaResolver = (()=>{
8
+ const cache = new Map();
9
+ return (generatorId)=>{
10
+ const cached = cache.get(generatorId);
11
+ if (cached) return cached;
12
+ // This module lives at src/connection/, and the recorded path is relative to
13
+ // the plugin root, so resolve from two levels up.
14
+ const schemaPath = path.resolve(import.meta.dirname, '..', '..', schemaPathOf(generatorId));
15
+ let schema;
16
+ try {
17
+ schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));
18
+ } catch (error) {
19
+ throw new Error(`Scaffold catalog: could not read the schema for '${generatorId}' at ${schemaPath}: ${error}`);
20
+ }
21
+ cache.set(generatorId, schema);
22
+ return schema;
23
+ };
24
+ })();
25
+ /** The scaffold recipes, resolved from the schemas on disk. */ export const SCAFFOLD_RECIPES = buildScaffoldRecipes(nodeSchemaResolver);
26
+
27
+ //# sourceMappingURL=schema-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/connection/schema-resolver.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport {\n buildScaffoldRecipes,\n type GeneratorSchema,\n type ScaffoldRecipe,\n type SchemaResolver,\n schemaPathOf,\n} from './scaffold-catalog';\n\n/** Reads schemas from disk, for the plugin and its tests. */\nexport const nodeSchemaResolver: SchemaResolver = (() => {\n const cache = new Map<string, GeneratorSchema>();\n return (generatorId: string): GeneratorSchema => {\n const cached = cache.get(generatorId);\n if (cached) return cached;\n // This module lives at src/connection/, and the recorded path is relative to\n // the plugin root, so resolve from two levels up.\n const schemaPath = path.resolve(\n import.meta.dirname,\n '..',\n '..',\n schemaPathOf(generatorId),\n );\n let schema: GeneratorSchema;\n try {\n schema = JSON.parse(readFileSync(schemaPath, 'utf-8'));\n } catch (error) {\n throw new Error(\n `Scaffold catalog: could not read the schema for '${generatorId}' at ${schemaPath}: ${error}`,\n );\n }\n cache.set(generatorId, schema);\n return schema;\n };\n})();\n\n/** The scaffold recipes, resolved from the schemas on disk. */\nexport const SCAFFOLD_RECIPES: Readonly<Record<string, ScaffoldRecipe>> =\n buildScaffoldRecipes(nodeSchemaResolver);\n"],"names":["readFileSync","path","buildScaffoldRecipes","schemaPathOf","nodeSchemaResolver","cache","Map","generatorId","cached","get","schemaPath","resolve","dirname","schema","JSON","parse","error","Error","set","SCAFFOLD_RECIPES"],"mappings":"AAAA;;;CAGC,GACD,SAASA,YAAY,QAAQ,UAAU;AACvC,YAAYC,UAAU,YAAY;AAClC,SACEC,oBAAoB,EAIpBC,YAAY,QACP,wBAAqB;AAE5B,2DAA2D,GAC3D,OAAO,MAAMC,qBAAqC,AAAC,CAAA;IACjD,MAAMC,QAAQ,IAAIC;IAClB,OAAO,CAACC;QACN,MAAMC,SAASH,MAAMI,GAAG,CAACF;QACzB,IAAIC,QAAQ,OAAOA;QACnB,6EAA6E;QAC7E,kDAAkD;QAClD,MAAME,aAAaT,KAAKU,OAAO,CAC7B,YAAYC,OAAO,EACnB,MACA,MACAT,aAAaI;QAEf,IAAIM;QACJ,IAAI;YACFA,SAASC,KAAKC,KAAK,CAACf,aAAaU,YAAY;QAC/C,EAAE,OAAOM,OAAO;YACd,MAAM,IAAIC,MACR,CAAC,iDAAiD,EAAEV,YAAY,KAAK,EAAEG,WAAW,EAAE,EAAEM,OAAO;QAEjG;QACAX,MAAMa,GAAG,CAACX,aAAaM;QACvB,OAAOA;IACT;AACF,CAAA,IAAK;AAEL,6DAA6D,GAC7D,OAAO,MAAMM,mBACXjB,qBAAqBE,oBAAoB"}
@@ -4,8 +4,8 @@ exports[`infra generator > should add required dependencies to package.json > de
4
4
 
5
5
  exports[`infra generator > should add required dependencies to package.json > dev-dependencies 1`] = `
6
6
  {
7
- "@nx/js": "23.1.0",
8
- "@nx/vitest": "23.1.0",
7
+ "@nx/js": "23.1.1",
8
+ "@nx/vitest": "23.1.1",
9
9
  "@swc/helpers": "~0.5.18",
10
10
  "@types/node": "catalog:",
11
11
  "@vitest/coverage-v8": "catalog:",
@@ -23,8 +23,8 @@ exports[`infra generator > should add required dependencies to package.json > pa
23
23
  {
24
24
  "dependencies": {},
25
25
  "devDependencies": {
26
- "@nx/js": "23.1.0",
27
- "@nx/vitest": "23.1.0",
26
+ "@nx/js": "23.1.1",
27
+ "@nx/vitest": "23.1.1",
28
28
  "@swc/helpers": "~0.5.18",
29
29
  "@types/node": "catalog:",
30
30
  "@vitest/coverage-v8": "catalog:",
@@ -56,7 +56,7 @@ exports[`infra generator > should configure Checkov target correctly > checkov-t
56
56
  "{workspaceRoot}/dist/{projectRoot}/cdk.out",
57
57
  ],
58
58
  "options": {
59
- "command": "uvx --from checkov==3.3.8 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
59
+ "command": "uvx --from checkov==3.3.9 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
60
60
  },
61
61
  "outputs": [
62
62
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -150,7 +150,7 @@ exports[`infra generator > should configure project.json with correct targets >
150
150
  "{workspaceRoot}/dist/{projectRoot}/cdk.out",
151
151
  ],
152
152
  "options": {
153
- "command": "uvx --from checkov==3.3.8 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
153
+ "command": "uvx --from checkov==3.3.9 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
154
154
  },
155
155
  "outputs": [
156
156
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -728,7 +728,7 @@ exports[`infra generator > should handle custom project names correctly > custom
728
728
  "{workspaceRoot}/dist/{projectRoot}/cdk.out",
729
729
  ],
730
730
  "options": {
731
- "command": "uvx --from checkov==3.3.8 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
731
+ "command": "uvx --from checkov==3.3.9 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
732
732
  },
733
733
  "outputs": [
734
734
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { getProjects, joinPathFragments } from "@nx/devkit";
5
+ import { SMITHY_PROJECT_GENERATOR_INFO } from "../../../smithy/project/generator.js";
6
+ import { applyGritQL } from "../../../utils/ast.js";
7
+ import { formatFilesInSubtree } from "../../../utils/format.js";
8
+ import { isVendedUpgrade } from "../../../utils/version-upgrade-migration/vended-upgrade.js";
9
+ /**
10
+ * Hardcoded rather than read from `TS_VERSIONS`: this runs once, for the release
11
+ * that fixed the declaration naming, so it must keep applying that exact change
12
+ * however far the vended versions move afterwards. A workspace on a later release
13
+ * gets the newer pins from the version sync instead.
14
+ */ const PINS = [
15
+ {
16
+ name: 'rolldown',
17
+ target: '1.2.0'
18
+ },
19
+ {
20
+ name: 'rolldown-plugin-dts',
21
+ target: '0.28.0'
22
+ },
23
+ {
24
+ name: '@rollup/plugin-esm-shim',
25
+ target: '0.1.8'
26
+ }
27
+ ];
28
+ /** A version ends at whitespace, a line break or the end of the command. */ const VERSION = String.raw`[^\s\\]+`;
29
+ const escapeRegExp = (value)=>value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
30
+ /**
31
+ * Rewrite every occurrence of one pin to its target version.
32
+ *
33
+ * The pin is matched by name, so a `rolldown-plugin-dts@x` in the same command as
34
+ * `rolldown@y` keeps its own version — the `@` before the version terminates the
35
+ * match, so the shorter name does not match the longer one.
36
+ */ const rewritePin = ({ name, target })=>`r"[\\s\\S]*${escapeRegExp(name)}@(${VERSION})[\\s\\S]*"($version) where { $version => \`${target}\` }`;
37
+ /** Whether the file pins this package behind the target version. */ const isBehindTarget = (contents, { name, target })=>{
38
+ const matches = contents.matchAll(new RegExp(`${escapeRegExp(name)}@(${VERSION})`, 'g'));
39
+ const declared = [
40
+ ...matches
41
+ ].flatMap((match)=>match[1] ? [
42
+ match[1]
43
+ ] : []);
44
+ // A rewrite replaces every occurrence at once, so this has to hold for all of
45
+ // them. Compared rather than tested for inequality, so a workspace a later
46
+ // release has already moved past the target keeps its newer pin.
47
+ return declared.length > 0 && declared.every((version)=>isVendedUpgrade(target, version));
48
+ };
49
+ const divergedNextStep = (path)=>`${path}: the Smithy build image's bundle pins have diverged from the generated shape - left untouched. Update \`rolldown\` to 1.2.0 and \`rolldown-plugin-dts\` to 0.28.0.`;
50
+ export default async function migration(tree) {
51
+ const nextSteps = [];
52
+ // Only a Smithy service project bundles the SSDK; the shapes type builds the
53
+ // model alone and pins none of this.
54
+ const buildDockerfiles = [
55
+ ...getProjects(tree).values()
56
+ ].filter((project)=>{
57
+ const metadata = project.metadata;
58
+ return metadata?.generator === SMITHY_PROJECT_GENERATOR_INFO.id && metadata.smithyType === 'service';
59
+ }).map((project)=>joinPathFragments(project.root, 'build.Dockerfile')).filter((filePath)=>tree.exists(filePath));
60
+ for (const path of buildDockerfiles){
61
+ const contents = tree.read(path, 'utf-8') ?? '';
62
+ for (const pin of PINS){
63
+ if (!isBehindTarget(contents, pin)) {
64
+ continue;
65
+ }
66
+ if (!await applyGritQL(tree, path, rewritePin(pin))) {
67
+ nextSteps.push(divergedNextStep(path));
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ await formatFilesInSubtree(tree);
73
+ return {
74
+ nextSteps
75
+ };
76
+ }
77
+
78
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/smithy-ssdk-bundle-pins/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { SMITHY_PROJECT_GENERATOR_INFO } from '../../../smithy/project/generator';\nimport { applyGritQL } from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport { isVendedUpgrade } from '../../../utils/version-upgrade-migration/vended-upgrade';\n\n/**\n * Move a Smithy `build.Dockerfile` onto the SSDK bundle pins this release fixes.\n *\n * `rolldown-plugin-dts` named the bundled declaration after its content hash\n * before 0.20.0, so the generated handler's `./generated/ssdk/index.js` import\n * found no `index.d.ts` beside it and `compile` failed with TS7016. The two pins\n * move together: the plugin release that fixed the naming needs a rolldown past\n * the pin this shipped with.\n *\n * There is no Dockerfile grammar, so each pin is matched as an anchored rewrite\n * over the whole file with the version captured — `${...}` in these patterns is\n * GritQL metavariable syntax, not interpolation.\n */\n\n/** A pin in the file body, and the version this migration moves it to. */\ninterface Pin {\n /** The package as the install command names it. */\n readonly name: string;\n readonly target: string;\n}\n\n/**\n * Hardcoded rather than read from `TS_VERSIONS`: this runs once, for the release\n * that fixed the declaration naming, so it must keep applying that exact change\n * however far the vended versions move afterwards. A workspace on a later release\n * gets the newer pins from the version sync instead.\n */\nconst PINS: readonly Pin[] = [\n { name: 'rolldown', target: '1.2.0' },\n { name: 'rolldown-plugin-dts', target: '0.28.0' },\n { name: '@rollup/plugin-esm-shim', target: '0.1.8' },\n];\n\n/** A version ends at whitespace, a line break or the end of the command. */\nconst VERSION = String.raw`[^\\s\\\\]+`;\n\nconst escapeRegExp = (value: string): string =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Rewrite every occurrence of one pin to its target version.\n *\n * The pin is matched by name, so a `rolldown-plugin-dts@x` in the same command as\n * `rolldown@y` keeps its own version — the `@` before the version terminates the\n * match, so the shorter name does not match the longer one.\n */\nconst rewritePin = ({ name, target }: Pin): string =>\n `r\"[\\\\s\\\\S]*${escapeRegExp(name)}@(${VERSION})[\\\\s\\\\S]*\"($version) where { $version => \\`${target}\\` }`;\n\n/** Whether the file pins this package behind the target version. */\nconst isBehindTarget = (contents: string, { name, target }: Pin): boolean => {\n const matches = contents.matchAll(\n new RegExp(`${escapeRegExp(name)}@(${VERSION})`, 'g'),\n );\n const declared = [...matches].flatMap((match) =>\n match[1] ? [match[1]] : [],\n );\n // A rewrite replaces every occurrence at once, so this has to hold for all of\n // them. Compared rather than tested for inequality, so a workspace a later\n // release has already moved past the target keeps its newer pin.\n return (\n declared.length > 0 &&\n declared.every((version) => isVendedUpgrade(target, version))\n );\n};\n\nconst divergedNextStep = (path: string): string =>\n `${path}: the Smithy build image's bundle pins have diverged from the generated shape - left untouched. Update \\`rolldown\\` to 1.2.0 and \\`rolldown-plugin-dts\\` to 0.28.0.`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n // Only a Smithy service project bundles the SSDK; the shapes type builds the\n // model alone and pins none of this.\n const buildDockerfiles = [...getProjects(tree).values()]\n .filter((project) => {\n const metadata = project.metadata as\n | { generator?: string; smithyType?: string }\n | undefined;\n return (\n metadata?.generator === SMITHY_PROJECT_GENERATOR_INFO.id &&\n metadata.smithyType === 'service'\n );\n })\n .map((project) => joinPathFragments(project.root, 'build.Dockerfile'))\n .filter((filePath) => tree.exists(filePath));\n\n for (const path of buildDockerfiles) {\n const contents = tree.read(path, 'utf-8') ?? '';\n\n for (const pin of PINS) {\n if (!isBehindTarget(contents, pin)) {\n continue;\n }\n if (!(await applyGritQL(tree, path, rewritePin(pin)))) {\n nextSteps.push(divergedNextStep(path));\n break;\n }\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","SMITHY_PROJECT_GENERATOR_INFO","applyGritQL","formatFilesInSubtree","isVendedUpgrade","PINS","name","target","VERSION","String","raw","escapeRegExp","value","replace","rewritePin","isBehindTarget","contents","matches","matchAll","RegExp","declared","flatMap","match","length","every","version","divergedNextStep","path","migration","tree","nextSteps","buildDockerfiles","values","filter","project","metadata","generator","id","smithyType","map","root","filePath","exists","read","pin","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,6BAA6B,QAAQ,uCAAoC;AAClF,SAASC,WAAW,QAAQ,wBAAqB;AACjD,SAASC,oBAAoB,QAAQ,2BAAwB;AAC7D,SAASC,eAAe,QAAQ,6DAA0D;AAuB1F;;;;;CAKC,GACD,MAAMC,OAAuB;IAC3B;QAAEC,MAAM;QAAYC,QAAQ;IAAQ;IACpC;QAAED,MAAM;QAAuBC,QAAQ;IAAS;IAChD;QAAED,MAAM;QAA2BC,QAAQ;IAAQ;CACpD;AAED,0EAA0E,GAC1E,MAAMC,UAAUC,OAAOC,GAAG,CAAC,QAAQ,CAAC;AAEpC,MAAMC,eAAe,CAACC,QACpBA,MAAMC,OAAO,CAAC,uBAAuB;AAEvC;;;;;;CAMC,GACD,MAAMC,aAAa,CAAC,EAAER,IAAI,EAAEC,MAAM,EAAO,GACvC,CAAC,WAAW,EAAEI,aAAaL,MAAM,EAAE,EAAEE,QAAQ,4CAA4C,EAAED,OAAO,IAAI,CAAC;AAEzG,kEAAkE,GAClE,MAAMQ,iBAAiB,CAACC,UAAkB,EAAEV,IAAI,EAAEC,MAAM,EAAO;IAC7D,MAAMU,UAAUD,SAASE,QAAQ,CAC/B,IAAIC,OAAO,GAAGR,aAAaL,MAAM,EAAE,EAAEE,QAAQ,CAAC,CAAC,EAAE;IAEnD,MAAMY,WAAW;WAAIH;KAAQ,CAACI,OAAO,CAAC,CAACC,QACrCA,KAAK,CAAC,EAAE,GAAG;YAACA,KAAK,CAAC,EAAE;SAAC,GAAG,EAAE;IAE5B,8EAA8E;IAC9E,2EAA2E;IAC3E,iEAAiE;IACjE,OACEF,SAASG,MAAM,GAAG,KAClBH,SAASI,KAAK,CAAC,CAACC,UAAYrB,gBAAgBG,QAAQkB;AAExD;AAEA,MAAMC,mBAAmB,CAACC,OACxB,GAAGA,KAAK,mKAAmK,CAAC;AAE9K,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,6EAA6E;IAC7E,qCAAqC;IACrC,MAAMC,mBAAmB;WAAIhC,YAAY8B,MAAMG,MAAM;KAAG,CACrDC,MAAM,CAAC,CAACC;QACP,MAAMC,WAAWD,QAAQC,QAAQ;QAGjC,OACEA,UAAUC,cAAcnC,8BAA8BoC,EAAE,IACxDF,SAASG,UAAU,KAAK;IAE5B,GACCC,GAAG,CAAC,CAACL,UAAYlC,kBAAkBkC,QAAQM,IAAI,EAAE,qBACjDP,MAAM,CAAC,CAACQ,WAAaZ,KAAKa,MAAM,CAACD;IAEpC,KAAK,MAAMd,QAAQI,iBAAkB;QACnC,MAAMf,WAAWa,KAAKc,IAAI,CAAChB,MAAM,YAAY;QAE7C,KAAK,MAAMiB,OAAOvC,KAAM;YACtB,IAAI,CAACU,eAAeC,UAAU4B,MAAM;gBAClC;YACF;YACA,IAAI,CAAE,MAAM1C,YAAY2B,MAAMF,MAAMb,WAAW8B,OAAQ;gBACrDd,UAAUe,IAAI,CAACnB,iBAAiBC;gBAChC;YACF;QACF;IACF;IAEA,MAAMxB,qBAAqB0B;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.50/modernize-function-props-cast/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type MigrationReturnObject,\n type Tree,\n visitNotIgnoredFiles,\n} from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants';\n\n/**\n * Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs\n *\n * The legacy `<FunctionProps>{ ... }` cast form is not supported by GritQL's\n * TypeScript parser, which silently breaks parsing (and therefore matching)\n * for the entire containing file. Since several other migrations rely on\n * GritQL to update these API construct files, this cast is replaced here with\n * the equivalent, GritQL-compatible `{ ... } as FunctionProps` form. This is\n * matched as an exact literal (rather than via GritQL) since GritQL cannot\n * parse the file while the legacy cast is still present.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, or consider a\n * hybrid migration, rather than clobbering the user's changes.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files your\n * migration wrote are formatted correctly.\n */\n\nconst APIS_APP_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/apis`;\n\nconst OLD_CAST_OPEN = 'defaultIntegrationOptions: <FunctionProps>{';\nconst NEW_CAST_OPEN = 'defaultIntegrationOptions: {';\nconst OLD_CAST_CLOSE = '\\n },\\n buildDefaultIntegration:';\nconst NEW_CAST_CLOSE =\n '\\n } as FunctionProps,\\n buildDefaultIntegration:';\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(APIS_APP_DIR)) {\n return { nextSteps };\n }\n\n const apiAppFiles: string[] = [];\n visitNotIgnoredFiles(tree, APIS_APP_DIR, (filePath) => {\n apiAppFiles.push(filePath);\n });\n\n for (const filePath of apiAppFiles) {\n if (!filePath.endsWith('.ts') || filePath.endsWith('/index.ts')) {\n continue;\n }\n const contents = tree.read(filePath, 'utf-8') ?? '';\n if (!contents.includes(OLD_CAST_OPEN)) {\n // Already migrated, or doesn't use this shape.\n continue;\n }\n if (!contents.includes(OLD_CAST_CLOSE)) {\n nextSteps.push(\n `${filePath}: the defaultIntegrationOptions cast has diverged from the generated shape - left untouched. Manually replace \\`<FunctionProps>{ ... }\\` with \\`{ ... } as FunctionProps\\`.`,\n );\n continue;\n }\n tree.write(\n filePath,\n contents\n .replace(OLD_CAST_OPEN, NEW_CAST_OPEN)\n .replace(OLD_CAST_CLOSE, NEW_CAST_CLOSE),\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["visitNotIgnoredFiles","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","APIS_APP_DIR","OLD_CAST_OPEN","NEW_CAST_OPEN","OLD_CAST_CLOSE","NEW_CAST_CLOSE","migration","tree","nextSteps","exists","apiAppFiles","filePath","push","endsWith","contents","read","includes","write","replace"],"mappings":"AAAA;;;CAGC,GACD,SAGEA,oBAAoB,QACf,aAAa;AACpB,SAASC,oBAAoB,QAAQ,2BAAwB;AAC7D,SACEC,YAAY,EACZC,qBAAqB,QAChB,gDAA6C;AAEpD;;;;;;;;;;;;;;;;;;;;;;CAsBC,GAED,MAAMC,eAAe,GAAGF,aAAa,CAAC,EAAEC,sBAAsB,aAAa,CAAC;AAE5E,MAAME,gBAAgB;AACtB,MAAMC,gBAAgB;AACtB,MAAMC,iBAAiB;AACvB,MAAMC,iBACJ;AAEF,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,IAAI,CAACD,KAAKE,MAAM,CAACR,eAAe;QAC9B,OAAO;YAAEO;QAAU;IACrB;IAEA,MAAME,cAAwB,EAAE;IAChCb,qBAAqBU,MAAMN,cAAc,CAACU;QACxCD,YAAYE,IAAI,CAACD;IACnB;IAEA,KAAK,MAAMA,YAAYD,YAAa;QAClC,IAAI,CAACC,SAASE,QAAQ,CAAC,UAAUF,SAASE,QAAQ,CAAC,cAAc;YAC/D;QACF;QACA,MAAMC,WAAWP,KAAKQ,IAAI,CAACJ,UAAU,YAAY;QACjD,IAAI,CAACG,SAASE,QAAQ,CAACd,gBAAgB;YAErC;QACF;QACA,IAAI,CAACY,SAASE,QAAQ,CAACZ,iBAAiB;YACtCI,UAAUI,IAAI,CACZ,GAAGD,SAAS,2KAA2K,CAAC;YAE1L;QACF;QACAJ,KAAKU,KAAK,CACRN,UACAG,SACGI,OAAO,CAAChB,eAAeC,eACvBe,OAAO,CAACd,gBAAgBC;IAE/B;IAEA,MAAMP,qBAAqBS;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.50/restrict-cors-to-custom-domains/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type MigrationReturnObject,\n type Tree,\n visitNotIgnoredFiles,\n} from '@nx/devkit';\nimport {\n addDestructuredImport,\n addStarExport,\n applyGritQL,\n} from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport { isEsmWorkspace } from '../../../utils/module-format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants';\n\n/**\n * Include CloudFront custom domain aliases in restrictCorsTo and UserIdentity callback URLs\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, rather than\n * clobbering the user's changes.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files your\n * migration wrote are formatted correctly.\n */\n\nconst CORE_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/core`;\nconst APIS_APP_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/apis`;\nconst CLOUDFRONT_CORE_FILE = `${CORE_DIR}/cloudfront.ts`;\nconst CORE_INDEX_FILE = `${CORE_DIR}/index.ts`;\nconst USER_IDENTITY_FILE = `${CORE_DIR}/user-identity.ts`;\n\nconst CLOUDFRONT_HELPER_CONTENT = `import { CfnDistribution, Distribution } from 'aws-cdk-lib/aws-cloudfront';\n\n/**\n * Finds the domain names associated with a CloudFront distribution.\n *\n * Includes the distribution's default \\`*.cloudfront.net\\` domain name plus any custom\n * domain names (aliases) configured on it.\n */\nexport const findCloudFrontDomainNames = (\n distribution: Distribution,\n): string[] => {\n const cfnDistribution = distribution.node.defaultChild as CfnDistribution;\n const distributionConfig =\n cfnDistribution.distributionConfig as CfnDistribution.DistributionConfigProperty;\n return [distribution.domainName, ...(distributionConfig.aliases ?? [])];\n};\n`;\n\n// Rewrites the `restrictCorsTo` body as produced by generators prior to this fix.\nconst RESTRICT_CORS_TO_GRITQL_PATTERN =\n \"`origins.map(($o) => typeof $o === 'string' ? $o : 'cloudFrontDistribution' in $o ? $branch1 : $branch2)` where { $branch1 <: contains `distributionDomainName`, $branch2 <: contains `distributionDomainName` } => raw`origins.flatMap(($o) => typeof $o === 'string' ? [$o] : findCloudFrontDomainNames('cloudFrontDistribution' in $o ? $o.cloudFrontDistribution : $o).map((domain) => \\\\`https://${domain}\\\\`))`\";\n\n// Rewrites UserIdentity's callback/logout URL logic as produced by generators\n// prior to this fix.\nconst USER_IDENTITY_CALLBACK_URLS_GRITQL_PATTERN =\n '`this.findCloudFrontDomainNames()` => `Stack.of(this).node.findAll().filter((child): child is Distribution => child instanceof Distribution).flatMap(findCloudFrontDomainNames)`';\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(CORE_INDEX_FILE)) {\n // No common/constructs shared library in this workspace - nothing to migrate.\n return { nextSteps };\n }\n\n const esm = isEsmWorkspace(tree);\n const apiCloudFrontImportSpecifier = esm\n ? '../../core/cloudfront.js'\n : '../../core/cloudfront';\n const coreCloudFrontImportSpecifier = esm\n ? './cloudfront.js'\n : './cloudfront';\n\n if (!tree.exists(CLOUDFRONT_CORE_FILE)) {\n tree.write(CLOUDFRONT_CORE_FILE, CLOUDFRONT_HELPER_CONTENT);\n }\n await addStarExport(tree, CORE_INDEX_FILE, './cloudfront.js');\n\n const apiAppFiles: string[] = [];\n visitNotIgnoredFiles(tree, APIS_APP_DIR, (filePath) => {\n apiAppFiles.push(filePath);\n });\n\n for (const filePath of apiAppFiles) {\n if (!filePath.endsWith('.ts') || filePath.endsWith('/index.ts')) {\n continue;\n }\n const rewrote = await applyGritQL(\n tree,\n filePath,\n RESTRICT_CORS_TO_GRITQL_PATTERN,\n );\n if (rewrote) {\n await addDestructuredImport(\n tree,\n filePath,\n ['findCloudFrontDomainNames'],\n apiCloudFrontImportSpecifier,\n );\n continue;\n }\n const contents = tree.read(filePath, 'utf-8') ?? '';\n if (!contents.includes('findCloudFrontDomainNames(')) {\n nextSteps.push(\n `${filePath}: restrictCorsTo has diverged from the generated shape - left untouched. Manually apply the CloudFront custom domain fix (see findCloudFrontDomainNames in common/constructs/src/core/cloudfront.ts).`,\n );\n }\n // Otherwise already migrated - silent skip.\n }\n\n if (tree.exists(USER_IDENTITY_FILE)) {\n const rewrote = await applyGritQL(\n tree,\n USER_IDENTITY_FILE,\n USER_IDENTITY_CALLBACK_URLS_GRITQL_PATTERN,\n );\n if (rewrote) {\n await applyGritQL(\n tree,\n USER_IDENTITY_FILE,\n \"`import { CfnDistribution, Distribution } from 'aws-cdk-lib/aws-cloudfront'` => `import { Distribution } from 'aws-cdk-lib/aws-cloudfront';`\",\n );\n await applyGritQL(\n tree,\n USER_IDENTITY_FILE,\n \"or { `// Includes each distribution's default domain name plus any custom domain names (aliases) configured on it.` => ., `private findCloudFrontDomainNames = (): string[] => $body` => . }\",\n );\n await addDestructuredImport(\n tree,\n USER_IDENTITY_FILE,\n ['findCloudFrontDomainNames'],\n coreCloudFrontImportSpecifier,\n );\n } else {\n const contents = tree.read(USER_IDENTITY_FILE, 'utf-8') ?? '';\n if (!contents.includes('.flatMap(findCloudFrontDomainNames)')) {\n nextSteps.push(\n `${USER_IDENTITY_FILE}: the callback URL logic has diverged from the generated shape - left untouched. Manually apply the shared findCloudFrontDomainNames helper (see common/constructs/src/core/cloudfront.ts).`,\n );\n }\n // Otherwise already migrated - silent skip.\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["visitNotIgnoredFiles","addDestructuredImport","addStarExport","applyGritQL","formatFilesInSubtree","isEsmWorkspace","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","CORE_DIR","APIS_APP_DIR","CLOUDFRONT_CORE_FILE","CORE_INDEX_FILE","USER_IDENTITY_FILE","CLOUDFRONT_HELPER_CONTENT","RESTRICT_CORS_TO_GRITQL_PATTERN","USER_IDENTITY_CALLBACK_URLS_GRITQL_PATTERN","migration","tree","nextSteps","exists","esm","apiCloudFrontImportSpecifier","coreCloudFrontImportSpecifier","write","apiAppFiles","filePath","push","endsWith","rewrote","contents","read","includes"],"mappings":"AAAA;;;CAGC,GACD,SAGEA,oBAAoB,QACf,aAAa;AACpB,SACEC,qBAAqB,EACrBC,aAAa,EACbC,WAAW,QACN,wBAAqB;AAC5B,SAASC,oBAAoB,QAAQ,2BAAwB;AAC7D,SAASC,cAAc,QAAQ,kCAA+B;AAC9D,SACEC,YAAY,EACZC,qBAAqB,QAChB,gDAA6C;AAEpD;;;;;;;;;;;;;;CAcC,GAED,MAAMC,WAAW,GAAGF,aAAa,CAAC,EAAEC,sBAAsB,SAAS,CAAC;AACpE,MAAME,eAAe,GAAGH,aAAa,CAAC,EAAEC,sBAAsB,aAAa,CAAC;AAC5E,MAAMG,uBAAuB,GAAGF,SAAS,cAAc,CAAC;AACxD,MAAMG,kBAAkB,GAAGH,SAAS,SAAS,CAAC;AAC9C,MAAMI,qBAAqB,GAAGJ,SAAS,iBAAiB,CAAC;AAEzD,MAAMK,4BAA4B,CAAC;;;;;;;;;;;;;;;;AAgBnC,CAAC;AAED,kFAAkF;AAClF,MAAMC,kCACJ;AAEF,8EAA8E;AAC9E,qBAAqB;AACrB,MAAMC,6CACJ;AAEF,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,IAAI,CAACD,KAAKE,MAAM,CAACR,kBAAkB;QACjC,8EAA8E;QAC9E,OAAO;YAAEO;QAAU;IACrB;IAEA,MAAME,MAAMf,eAAeY;IAC3B,MAAMI,+BAA+BD,MACjC,6BACA;IACJ,MAAME,gCAAgCF,MAClC,oBACA;IAEJ,IAAI,CAACH,KAAKE,MAAM,CAACT,uBAAuB;QACtCO,KAAKM,KAAK,CAACb,sBAAsBG;IACnC;IACA,MAAMX,cAAce,MAAMN,iBAAiB;IAE3C,MAAMa,cAAwB,EAAE;IAChCxB,qBAAqBiB,MAAMR,cAAc,CAACgB;QACxCD,YAAYE,IAAI,CAACD;IACnB;IAEA,KAAK,MAAMA,YAAYD,YAAa;QAClC,IAAI,CAACC,SAASE,QAAQ,CAAC,UAAUF,SAASE,QAAQ,CAAC,cAAc;YAC/D;QACF;QACA,MAAMC,UAAU,MAAMzB,YACpBc,MACAQ,UACAX;QAEF,IAAIc,SAAS;YACX,MAAM3B,sBACJgB,MACAQ,UACA;gBAAC;aAA4B,EAC7BJ;YAEF;QACF;QACA,MAAMQ,WAAWZ,KAAKa,IAAI,CAACL,UAAU,YAAY;QACjD,IAAI,CAACI,SAASE,QAAQ,CAAC,+BAA+B;YACpDb,UAAUQ,IAAI,CACZ,GAAGD,SAAS,qMAAqM,CAAC;QAEtN;IACA,4CAA4C;IAC9C;IAEA,IAAIR,KAAKE,MAAM,CAACP,qBAAqB;QACnC,MAAMgB,UAAU,MAAMzB,YACpBc,MACAL,oBACAG;QAEF,IAAIa,SAAS;YACX,MAAMzB,YACJc,MACAL,oBACA;YAEF,MAAMT,YACJc,MACAL,oBACA;YAEF,MAAMX,sBACJgB,MACAL,oBACA;gBAAC;aAA4B,EAC7BU;QAEJ,OAAO;YACL,MAAMO,WAAWZ,KAAKa,IAAI,CAAClB,oBAAoB,YAAY;YAC3D,IAAI,CAACiB,SAASE,QAAQ,CAAC,wCAAwC;gBAC7Db,UAAUQ,IAAI,CACZ,GAAGd,mBAAmB,2LAA2L,CAAC;YAEtN;QACA,4CAA4C;QAC9C;IACF;IAEA,MAAMR,qBAAqBa;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
6
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { TERRAFORM_PROJECT_GENERATOR_INFO } from '../../../terraform/project/generator';\nimport {\n applyGritQL,\n GRIT_INSERT_PLACEHOLDER,\n insertViaGritQL,\n matchGritQL,\n} from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\n\n/**\n * Adopt an existing Terraform state bucket in the vended bootstrap script when its state object is missing\n *\n * The state bucket stores its own tfstate inside itself, so if that object is\n * deleted while the bucket survives, `bootstrap` reads the 404 as a first run\n * and asks terraform to create a bucket that already exists — failing with\n * `BucketAlreadyOwnedByYou` on every subsequent run, with no retry that clears\n * it. The vended script now imports the existing bucket instead.\n *\n * Every edit is expressed as a GritQL rewrite so the script is matched on its\n * AST rather than its formatting.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, or consider a\n * hybrid migration, rather than clobbering the user's changes.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files your\n * migration wrote are formatted correctly.\n */\n\n// Guards the whole migration: present only once the import step exists.\nconst MIGRATED_PATTERN = '`bucketExists($_, $_)`';\n\n// Every edit site, matched structurally so formatting and argument layout\n// don't affect whether the script is recognised.\nconst STATE_FETCH_TRY_PATTERN =\n 'try_statement() as $try where { $try <: contains `GetObjectCommand` }';\nconst STATE_FLAG_SET_PATTERN = '`if (out.Body) { $body }`';\nconst HELPER_PATTERN = '`const main = async () => { $body }`';\nconst INIT_PATTERN = \"`execFileSync('terraform', ['init'], $opts)`\";\nconst S3_IMPORT_PATTERN =\n \"`import { $before, GetObjectCommand, $after } from '@aws-sdk/client-s3'`\";\nconst HEADER_COMMENT_PATTERN =\n 'comment() as $c where { $c <: includes \"state back to S3.\" }';\n\n// GritQL snippets are parsed as backtick-quoted patterns, so any backtick in\n// the inserted source has to survive that layer escaped.\nconst BUCKET_EXISTS_HELPER = `// S3 answers 404 only when the name is genuinely free; 403 means it exists\n// but is not readable with these credentials.\nconst bucketExists = async (s3: S3Client, bucket: string) => {\n try {\n await s3.send(new HeadBucketCommand({ Bucket: bucket }));\n return true;\n } catch (err: any) {\n const status = err?.$metadata?.httpStatusCode;\n if (status === 404) return false;\n if (status === 403) return true;\n throw err;\n }\n};`;\n\nconst IMPORT_STEP = `// The bucket holds its own state, so losing the state object while the\n // bucket survives would otherwise wedge bootstrap on a permanent\n // \\`BucketAlreadyOwnedByYou\\`. Adopt the existing bucket instead.\n if (!haveState && (await bucketExists(s3, bucket))) {\n console.log(\n \\`State bucket \\${bucket} already exists but its bootstrap state is missing — importing it.\\`,\n );\n execFileSync(\n 'terraform',\n [\n 'import',\n \\`-state=\\${tfStatePath}\\`,\n \\`-var=aws_region=\\${region}\\`,\n 'aws_s3_bucket.terraform_state',\n bucket,\n ],\n { cwd: bootstrapDir, stdio: 'inherit' },\n );\n }`;\n\n// Rewritten wholesale rather than appended to, since the summary sentence\n// changes rather than gaining a clause.\nconst NEW_HEADER_COMMENT = `/**\n * Bootstraps the remote Terraform state bucket.\n *\n * Equivalent to \\\\\\`cdk bootstrap\\\\\\` — resolves account + region from the AWS\n * SDK credential chain, pulls any existing bootstrap tfstate from S3,\n * runs \\\\\\`terraform apply\\\\\\` in the \\\\\\`bootstrap\\\\\\` dir, then pushes the new\n * state back to S3. Adopts an already-existing state bucket when its\n * state object is missing.\n */`;\n\nconst DIVERGED_NEXT_STEP = (filePath: string) =>\n `${filePath}: the bootstrap script has diverged from the generated shape - left untouched. Manually \\`terraform import aws_s3_bucket.terraform_state <bucket>\\` before \\`terraform apply\\` when the state bucket exists but its \\`bootstrap.tfstate\\` object does not, otherwise bootstrap fails with BucketAlreadyOwnedByYou.`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n // Terraform application projects are the only ones that vend bootstrap.ts.\n const bootstrapScripts = [...getProjects(tree).values()]\n .filter(\n (project) =>\n (project.metadata as any)?.generator ===\n TERRAFORM_PROJECT_GENERATOR_INFO.id,\n )\n .map((project) => joinPathFragments(project.root, 'scripts/bootstrap.ts'))\n .filter((filePath) => tree.exists(filePath));\n\n for (const filePath of bootstrapScripts) {\n if (await matchGritQL(tree, filePath, MIGRATED_PATTERN)) {\n // Already migrated - silent skip keeps re-runs a no-op.\n continue;\n }\n\n // Confirm every edit site is present before writing any of them, so a\n // script that only partly matches is left whole rather than half-edited.\n const allSitesPresent = (\n await Promise.all(\n [\n STATE_FETCH_TRY_PATTERN,\n STATE_FLAG_SET_PATTERN,\n HELPER_PATTERN,\n INIT_PATTERN,\n S3_IMPORT_PATTERN,\n HEADER_COMMENT_PATTERN,\n ].map((pattern) => matchGritQL(tree, filePath, pattern)),\n )\n ).every(Boolean);\n\n if (!allSitesPresent) {\n nextSteps.push(DIVERGED_NEXT_STEP(filePath));\n continue;\n }\n\n // `haveState` distinguishes \"no remote state\" from \"no bucket\", so the\n // import only runs when terraform has no prior knowledge of the bucket.\n await insertViaGritQL(\n tree,\n filePath,\n `${STATE_FETCH_TRY_PATTERN} => \\`${GRIT_INSERT_PLACEHOLDER}\\n $try\\``,\n 'let haveState = false;',\n );\n await applyGritQL(\n tree,\n filePath,\n `${STATE_FLAG_SET_PATTERN} => \\`if (out.Body) {\\n $body\\n haveState = true;\\n }\\``,\n );\n await insertViaGritQL(\n tree,\n filePath,\n `${HELPER_PATTERN} => \\`${GRIT_INSERT_PLACEHOLDER}\\n\\nconst main = async () => { $body }\\``,\n BUCKET_EXISTS_HELPER,\n );\n await insertViaGritQL(\n tree,\n filePath,\n `${INIT_PATTERN} => \\`execFileSync('terraform', ['init'], $opts);\\n\\n ${GRIT_INSERT_PLACEHOLDER}\\n\\``,\n IMPORT_STEP,\n );\n\n // Placed in the generator's import position rather than appended, so a\n // migrated workspace matches a freshly generated one.\n await applyGritQL(\n tree,\n filePath,\n `${S3_IMPORT_PATTERN} => \\`import { $before, GetObjectCommand, HeadBucketCommand, $after } from '@aws-sdk/client-s3'\\``,\n );\n\n await applyGritQL(\n tree,\n filePath,\n `${HEADER_COMMENT_PATTERN} => \\`${NEW_HEADER_COMMENT}\\``,\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","TERRAFORM_PROJECT_GENERATOR_INFO","applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","MIGRATED_PATTERN","STATE_FETCH_TRY_PATTERN","STATE_FLAG_SET_PATTERN","HELPER_PATTERN","INIT_PATTERN","S3_IMPORT_PATTERN","HEADER_COMMENT_PATTERN","BUCKET_EXISTS_HELPER","IMPORT_STEP","NEW_HEADER_COMMENT","DIVERGED_NEXT_STEP","filePath","migration","tree","nextSteps","bootstrapScripts","values","filter","project","metadata","generator","id","map","root","exists","allSitesPresent","Promise","all","pattern","every","Boolean","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,gCAAgC,QAAQ,0CAAuC;AACxF,SACEC,WAAW,EACXC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAqB;AAC5B,SAASC,oBAAoB,QAAQ,2BAAwB;AAE7D;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GAED,wEAAwE;AACxE,MAAMC,mBAAmB;AAEzB,0EAA0E;AAC1E,iDAAiD;AACjD,MAAMC,0BACJ;AACF,MAAMC,yBAAyB;AAC/B,MAAMC,iBAAiB;AACvB,MAAMC,eAAe;AACrB,MAAMC,oBACJ;AACF,MAAMC,yBACJ;AAEF,6EAA6E;AAC7E,yDAAyD;AACzD,MAAMC,uBAAuB,CAAC;;;;;;;;;;;;EAY5B,CAAC;AAEH,MAAMC,cAAc,CAAC;;;;;;;;;;;;;;;;;;GAkBlB,CAAC;AAEJ,0EAA0E;AAC1E,wCAAwC;AACxC,MAAMC,qBAAqB,CAAC;;;;;;;;GAQzB,CAAC;AAEJ,MAAMC,qBAAqB,CAACC,WAC1B,GAAGA,SAAS,kTAAkT,CAAC;AAEjU,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,2EAA2E;IAC3E,MAAMC,mBAAmB;WAAIvB,YAAYqB,MAAMG,MAAM;KAAG,CACrDC,MAAM,CACL,CAACC,UACC,AAACA,QAAQC,QAAQ,EAAUC,cAC3B1B,iCAAiC2B,EAAE,EAEtCC,GAAG,CAAC,CAACJ,UAAYzB,kBAAkByB,QAAQK,IAAI,EAAE,yBACjDN,MAAM,CAAC,CAACN,WAAaE,KAAKW,MAAM,CAACb;IAEpC,KAAK,MAAMA,YAAYI,iBAAkB;QACvC,IAAI,MAAMjB,YAAYe,MAAMF,UAAUX,mBAAmB;YAEvD;QACF;QAEA,sEAAsE;QACtE,yEAAyE;QACzE,MAAMyB,kBAAkB,AACtB,CAAA,MAAMC,QAAQC,GAAG,CACf;YACE1B;YACAC;YACAC;YACAC;YACAC;YACAC;SACD,CAACgB,GAAG,CAAC,CAACM,UAAY9B,YAAYe,MAAMF,UAAUiB,UACjD,EACAC,KAAK,CAACC;QAER,IAAI,CAACL,iBAAiB;YACpBX,UAAUiB,IAAI,CAACrB,mBAAmBC;YAClC;QACF;QAEA,uEAAuE;QACvE,wEAAwE;QACxE,MAAMd,gBACJgB,MACAF,UACA,GAAGV,wBAAwB,MAAM,EAAEL,wBAAwB,UAAU,CAAC,EACtE;QAEF,MAAMD,YACJkB,MACAF,UACA,GAAGT,uBAAuB,oEAAoE,CAAC;QAEjG,MAAML,gBACJgB,MACAF,UACA,GAAGR,eAAe,MAAM,EAAEP,wBAAwB,wCAAwC,CAAC,EAC3FW;QAEF,MAAMV,gBACJgB,MACAF,UACA,GAAGP,aAAa,uDAAuD,EAAER,wBAAwB,IAAI,CAAC,EACtGY;QAGF,uEAAuE;QACvE,sDAAsD;QACtD,MAAMb,YACJkB,MACAF,UACA,GAAGN,kBAAkB,iGAAiG,CAAC;QAGzH,MAAMV,YACJkB,MACAF,UACA,GAAGL,uBAAuB,MAAM,EAAEG,mBAAmB,EAAE,CAAC;IAE5D;IAEA,MAAMV,qBAAqBc;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.52/user-identity-waf-allow-localhost-callback/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants';\n\n/**\n * Count the EC2MetaDataSSRF_QUERYARGUMENTS WAF rule on the UserIdentity Web ACL\n *\n * `AWSManagedRulesCommonRuleSet` treats the loopback `redirect_uri` the Cognito\n * Hosted UI receives during local sign-in as an SSRF attempt, so sign-in against\n * a local dev server fails with an opaque 403 before the login page renders. The\n * rule is overridden to Count while a local callback URL is allowed; every other\n * rule in the group still blocks.\n *\n * The local callback URLs are lifted into a named constant so the override can be\n * derived from them rather than restating the condition.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, rather than\n * clobbering the user's changes.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files your\n * migration wrote are formatted correctly.\n */\n\nconst CDK_USER_IDENTITY_FILE = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/core/user-identity.ts`;\nconst TERRAFORM_IDENTITY_FILE = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/core/user-identity/identity/identity.tf`;\n\nconst SSRF_RULE_NAME = 'EC2MetaDataSSRF_QUERYARGUMENTS';\n\n// Guards each file: present only once the override has been added.\nconst CDK_MIGRATED_PATTERN = `\\`ruleActionOverrides: allowsLocalCallback ? $_ : undefined\\``;\nconst TERRAFORM_MIGRATED_PATTERN = `language hcl\\n\\`name = \"${SSRF_RULE_NAME}\"\\``;\n\n// Every CDK edit site, matched structurally so formatting doesn't affect whether\n// the construct is recognised.\nconst CDK_CONSTANT_ANCHOR_PATTERN = \"`const WEB_CLIENT_ID = 'WebClient'`\";\n// Scoped to the `.concat` callsite so it can't also rewrite the array literal\n// inside the constant this migration inserts.\nconst CDK_LOCAL_URLS_PATTERN =\n \"`['http://localhost:4200', 'http://localhost:4300'].concat($rest)`\";\nconst CDK_CALL_PATTERN = '`this.createWebAcl($id, this.userPool)`';\nconst CDK_SIGNATURE_PATTERN =\n '`private createWebAcl = ($id: string, $pool: UserPool) => $body`';\nconst CDK_STATEMENT_PATTERN =\n \"`managedRuleGroupStatement: { name: 'AWSManagedRulesCommonRuleSet', vendorName: 'AWS' }`\";\n\nconst CDK_EDITS: Array<[string, string]> = [\n // Local callback URLs become a named constant the override can key off.\n [\n CDK_CONSTANT_ANCHOR_PATTERN,\n `${CDK_CONSTANT_ANCHOR_PATTERN} => \\`const WEB_CLIENT_ID = 'WebClient';\n\n/** Local dev server origins permitted to complete the sign-in redirect */\nconst LOCAL_CALLBACK_URLS = ['http://localhost:4200', 'http://localhost:4300']\\``,\n ],\n [\n CDK_LOCAL_URLS_PATTERN,\n `${CDK_LOCAL_URLS_PATTERN} => \\`LOCAL_CALLBACK_URLS.concat($rest)\\``,\n ],\n [\n CDK_CALL_PATTERN,\n `${CDK_CALL_PATTERN} => \\`this.createWebAcl($id, this.userPool, LOCAL_CALLBACK_URLS.length > 0)\\``,\n ],\n [\n CDK_SIGNATURE_PATTERN,\n `${CDK_SIGNATURE_PATTERN} => \\`private createWebAcl = (\n $id: string,\n $pool: UserPool,\n allowsLocalCallback: boolean\n ) => $body\\``,\n ],\n [\n CDK_STATEMENT_PATTERN,\n `${CDK_STATEMENT_PATTERN} => \\`managedRuleGroupStatement: {\n name: 'AWSManagedRulesCommonRuleSet',\n vendorName: 'AWS',\n // ${SSRF_RULE_NAME} treats the loopback redirect_uri the\n // Hosted UI receives during local sign-in as an SSRF attempt. Counted\n // only while a local callback URL is allowed; every other rule blocks.\n ruleActionOverrides: allowsLocalCallback\n ? [\n {\n name: '${SSRF_RULE_NAME}',\n actionToUse: { count: {} },\n },\n ]\n : undefined,\n }\\``,\n ],\n];\n\nconst TERRAFORM_DATA_SOURCES_PATTERN = [\n 'language hcl',\n '`data \"aws_region\" \"current\" {}`',\n].join('\\n');\n\nconst TERRAFORM_EDITS: Array<[string, string]> = [\n // Local callback URLs become a local the override can key off.\n [\n TERRAFORM_DATA_SOURCES_PATTERN,\n [\n 'language hcl',\n '`data \"aws_region\" \"current\" {}` => `data \"aws_region\" \"current\" {}',\n '',\n 'locals {',\n ' # Local dev server origins permitted to complete the sign-in redirect',\n ' local_callback_urls = [',\n ' \"http://localhost:4200\",',\n ' \"http://localhost:4300\"',\n ' ]',\n '}`',\n ].join('\\n'),\n ],\n [\n [\n 'language hcl',\n '`callback_urls = concat([',\n ' \"http://localhost:4200\",',\n ' \"http://localhost:4300\"',\n ' ], var.callback_urls)`',\n ].join('\\n'),\n [\n 'language hcl',\n '`callback_urls = concat([',\n ' \"http://localhost:4200\",',\n ' \"http://localhost:4300\"',\n ' ], var.callback_urls)` => `callback_urls = concat(local.local_callback_urls, var.callback_urls)`',\n ].join('\\n'),\n ],\n [\n [\n 'language hcl',\n '`logout_urls = concat([',\n ' \"http://localhost:4200\",',\n ' \"http://localhost:4300\"',\n ' ], var.logout_urls)`',\n ].join('\\n'),\n [\n 'language hcl',\n '`logout_urls = concat([',\n ' \"http://localhost:4200\",',\n ' \"http://localhost:4300\"',\n ' ], var.logout_urls)` => `logout_urls = concat(local.local_callback_urls, var.logout_urls)`',\n ].join('\\n'),\n ],\n [\n [\n 'language hcl',\n '`managed_rule_group_statement {',\n ' name = \"AWSManagedRulesCommonRuleSet\"',\n ' vendor_name = \"AWS\"',\n ' }`',\n ].join('\\n'),\n [\n 'language hcl',\n '`managed_rule_group_statement {',\n ' name = \"AWSManagedRulesCommonRuleSet\"',\n ' vendor_name = \"AWS\"',\n ' }` => `managed_rule_group_statement {',\n ' name = \"AWSManagedRulesCommonRuleSet\"',\n ' vendor_name = \"AWS\"',\n '',\n ` # ${SSRF_RULE_NAME} treats the loopback redirect_uri the`,\n ' # Hosted UI receives during local sign-in as an SSRF attempt. Counted',\n ' # only while a local callback URL is allowed; every other rule blocks.',\n ' dynamic \"rule_action_override\" {',\n ' for_each = length(local.local_callback_urls) > 0 ? [1] : []',\n '',\n ' content {',\n ` name = \"${SSRF_RULE_NAME}\"`,\n '',\n ' action_to_use {',\n ' count {}',\n ' }',\n ' }',\n ' }',\n ' }`',\n ].join('\\n'),\n ],\n];\n\nconst divergedNextStep = (filePath: string) =>\n `${filePath}: the UserIdentity Web ACL has diverged from the generated shape - left untouched. To sign in against a local dev server, override ${SSRF_RULE_NAME} in the AWSManagedRulesCommonRuleSet rule group to Count, otherwise the Cognito Hosted UI returns 403 for localhost redirect URIs.`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [filePath, migratedPattern, edits] of [\n [CDK_USER_IDENTITY_FILE, CDK_MIGRATED_PATTERN, CDK_EDITS],\n [TERRAFORM_IDENTITY_FILE, TERRAFORM_MIGRATED_PATTERN, TERRAFORM_EDITS],\n ] as const) {\n if (!tree.exists(filePath)) {\n // This workspace doesn't use this IaC provider, or has no UserIdentity.\n continue;\n }\n\n if (await matchGritQL(tree, filePath, migratedPattern)) {\n // Already migrated - silent skip keeps re-runs a no-op.\n continue;\n }\n\n // Confirm every edit site is present before writing any of them, so a file\n // that only partly matches is left whole rather than half-edited.\n const allSitesPresent = (\n await Promise.all(\n edits.map(([match]) => matchGritQL(tree, filePath, match)),\n )\n ).every(Boolean);\n\n if (!allSitesPresent) {\n nextSteps.push(divergedNextStep(filePath));\n continue;\n }\n\n for (const [, rewrite] of edits) {\n await applyGritQL(tree, filePath, rewrite);\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["applyGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","CDK_USER_IDENTITY_FILE","TERRAFORM_IDENTITY_FILE","SSRF_RULE_NAME","CDK_MIGRATED_PATTERN","TERRAFORM_MIGRATED_PATTERN","CDK_CONSTANT_ANCHOR_PATTERN","CDK_LOCAL_URLS_PATTERN","CDK_CALL_PATTERN","CDK_SIGNATURE_PATTERN","CDK_STATEMENT_PATTERN","CDK_EDITS","TERRAFORM_DATA_SOURCES_PATTERN","join","TERRAFORM_EDITS","divergedNextStep","filePath","migration","tree","nextSteps","migratedPattern","edits","exists","allSitesPresent","Promise","all","map","match","every","Boolean","push","rewrite"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.54/order-access-log-delivery-after-bucket-policy/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport {\n addDestructuredImport,\n applyGritQL,\n captureGritQL,\n matchGritQL,\n} from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants';\n\n/**\n * Order the S3 server access log delivery source after the bucket policy.\n *\n * S3 rejects concurrent configuration writes against the same bucket with a 409\n * (OperationAborted). The generated StaticWebsite construct left the delivery\n * source and the bucket policy unordered, so CloudFormation could submit both at\n * once and fail the stack.\n */\n\nconst STATIC_WEBSITE_FILE = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/core/static-website.ts`;\n\nconst BUCKET_ARN_SUFFIX = '.bucketArn';\n\n/**\n * The bucket whose policy the delivery source must be ordered after is the one\n * the delivery source itself targets, so read it off `resourceArn` rather than\n * assuming the generated parameter name. Returns undefined unless exactly one\n * simple identifier is found, so a diverged helper is left alone.\n */\nconst findDeliverySourceBucket = async (\n tree: Tree,\n filePath: string,\n): Promise<string | undefined> => {\n const captured = await captureGritQL(\n tree,\n filePath,\n '`resourceArn: $bucket.bucketArn`',\n );\n if (!captured) return undefined;\n\n const bucket = captured\n .slice(captured.indexOf(':') + 1)\n .replace(BUCKET_ARN_SUFFIX, '')\n .trim();\n\n // Only a plain identifier can be cast and dereferenced safely in the\n // statement this migration writes.\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(bucket) ? bucket : undefined;\n};\n\n/**\n * Confirm the bucket the delivery source targets is declared as a parameter of\n * the enclosing helper, so the statement this migration writes references a\n * variable that is actually in scope.\n */\nconst isBucketDeclaredParameter = async (\n tree: Tree,\n filePath: string,\n bucket: string,\n): Promise<boolean> =>\n await matchGritQL(\n tree,\n filePath,\n `\\`private deliverAccessLogsToCloudWatch($params) { $_ }\\` where {\n $params <: contains \\`${bucket}: $bucketType\\`,\n $bucketType <: or { \\`IBucket\\`, \\`Bucket\\` }\n }`,\n );\n\n// Inserts the bucket policy dependency between the delivery source and the\n// delivery destination, matching the shape generators produced prior to this\n// fix. Anchored on the destination declaration so the source's own (multi-line,\n// Lazy-valued) arguments don't need to be matched.\nconst addDependencyPattern = (bucket: string) =>\n `\\`const $dest: CfnDeliveryDestination = new CfnDeliveryDestination($destArgs)\\` as $decl where {\n $dest <: \\`destination\\`\n} => \\`const bucketPolicy = (${bucket} as Bucket).policy;\n if (bucketPolicy) {\n source.node.addDependency(bucketPolicy);\n }\n $decl\\``;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(STATIC_WEBSITE_FILE)) {\n // No vended StaticWebsite construct in this workspace - nothing to migrate.\n return { nextSteps };\n }\n\n const contents = tree.read(STATIC_WEBSITE_FILE, 'utf-8') ?? '';\n if (contents.includes('source.node.addDependency(bucketPolicy)')) {\n // Already migrated.\n return { nextSteps };\n }\n\n const divergedMessage = `${STATIC_WEBSITE_FILE}: deliverAccessLogsToCloudWatch has diverged from the generated shape - left untouched. Manually order the S3 server access log delivery source after the bucket policy of the bucket it targets (\\`source.node.addDependency(bucketPolicy)\\`), avoiding a 409 (OperationAborted) from concurrent bucket configuration writes.`;\n\n // The rewrite is anchored on the delivery destination but references the\n // `source` variable, so only apply it when the delivery source still has the\n // generated shape.\n const hasGeneratedSource = await matchGritQL(\n tree,\n STATIC_WEBSITE_FILE,\n '`const source: CfnDeliverySource = new CfnDeliverySource($_)`',\n );\n\n const bucket = hasGeneratedSource\n ? await findDeliverySourceBucket(tree, STATIC_WEBSITE_FILE)\n : undefined;\n\n if (\n !bucket ||\n !(await isBucketDeclaredParameter(tree, STATIC_WEBSITE_FILE, bucket))\n ) {\n nextSteps.push(divergedMessage);\n return { nextSteps };\n }\n\n const rewrote = await applyGritQL(\n tree,\n STATIC_WEBSITE_FILE,\n addDependencyPattern(bucket),\n );\n\n if (!rewrote) {\n nextSteps.push(divergedMessage);\n return { nextSteps };\n }\n\n // The inserted statement casts to the concrete Bucket to reach its policy,\n // which the helper's own `IBucket` parameter type does not expose.\n await addDestructuredImport(\n tree,\n STATIC_WEBSITE_FILE,\n ['Bucket'],\n 'aws-cdk-lib/aws-s3',\n );\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["addDestructuredImport","applyGritQL","captureGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","STATIC_WEBSITE_FILE","BUCKET_ARN_SUFFIX","findDeliverySourceBucket","tree","filePath","captured","undefined","bucket","slice","indexOf","replace","trim","test","isBucketDeclaredParameter","addDependencyPattern","migration","nextSteps","exists","contents","read","includes","divergedMessage","hasGeneratedSource","push","rewrote"],"mappings":"AAAA;;;CAGC,GAED,SACEA,qBAAqB,EACrBC,WAAW,EACXC,aAAa,EACbC,WAAW,QACN,wBAAqB;AAC5B,SAASC,oBAAoB,QAAQ,2BAAwB;AAC7D,SACEC,YAAY,EACZC,qBAAqB,QAChB,gDAA6C;AAEpD;;;;;;;CAOC,GAED,MAAMC,sBAAsB,GAAGF,aAAa,CAAC,EAAEC,sBAAsB,2BAA2B,CAAC;AAEjG,MAAME,oBAAoB;AAE1B;;;;;CAKC,GACD,MAAMC,2BAA2B,OAC/BC,MACAC;IAEA,MAAMC,WAAW,MAAMV,cACrBQ,MACAC,UACA;IAEF,IAAI,CAACC,UAAU,OAAOC;IAEtB,MAAMC,SAASF,SACZG,KAAK,CAACH,SAASI,OAAO,CAAC,OAAO,GAC9BC,OAAO,CAACT,mBAAmB,IAC3BU,IAAI;IAEP,qEAAqE;IACrE,mCAAmC;IACnC,OAAO,6BAA6BC,IAAI,CAACL,UAAUA,SAASD;AAC9D;AAEA;;;;CAIC,GACD,MAAMO,4BAA4B,OAChCV,MACAC,UACAG,SAEA,MAAMX,YACJO,MACAC,UACA,CAAC;4BACuB,EAAEG,OAAO;;KAEhC,CAAC;AAGN,2EAA2E;AAC3E,6EAA6E;AAC7E,gFAAgF;AAChF,mDAAmD;AACnD,MAAMO,uBAAuB,CAACP,SAC5B,CAAC;;6BAE0B,EAAEA,OAAO;;;;WAI3B,CAAC;AAEZ,eAAe,eAAeQ,UAC5BZ,IAAU;IAEV,MAAMa,YAAsB,EAAE;IAE9B,IAAI,CAACb,KAAKc,MAAM,CAACjB,sBAAsB;QACrC,4EAA4E;QAC5E,OAAO;YAAEgB;QAAU;IACrB;IAEA,MAAME,WAAWf,KAAKgB,IAAI,CAACnB,qBAAqB,YAAY;IAC5D,IAAIkB,SAASE,QAAQ,CAAC,4CAA4C;QAChE,oBAAoB;QACpB,OAAO;YAAEJ;QAAU;IACrB;IAEA,MAAMK,kBAAkB,GAAGrB,oBAAoB,8TAA8T,CAAC;IAE9W,yEAAyE;IACzE,6EAA6E;IAC7E,mBAAmB;IACnB,MAAMsB,qBAAqB,MAAM1B,YAC/BO,MACAH,qBACA;IAGF,MAAMO,SAASe,qBACX,MAAMpB,yBAAyBC,MAAMH,uBACrCM;IAEJ,IACE,CAACC,UACD,CAAE,MAAMM,0BAA0BV,MAAMH,qBAAqBO,SAC7D;QACAS,UAAUO,IAAI,CAACF;QACf,OAAO;YAAEL;QAAU;IACrB;IAEA,MAAMQ,UAAU,MAAM9B,YACpBS,MACAH,qBACAc,qBAAqBP;IAGvB,IAAI,CAACiB,SAAS;QACZR,UAAUO,IAAI,CAACF;QACf,OAAO;YAAEL;QAAU;IACrB;IAEA,2EAA2E;IAC3E,mEAAmE;IACnE,MAAMvB,sBACJU,MACAH,qBACA;QAAC;KAAS,EACV;IAGF,MAAMH,qBAAqBM;IAE3B,OAAO;QAAEa;IAAU;AACrB"}