@adobe-commerce/aio-toolkit 1.2.4 → 1.2.6

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 (31) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +169 -0
  3. package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
  4. package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
  5. package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
  6. package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
  7. package/dist/index.d.mts +51 -6
  8. package/dist/index.d.ts +51 -6
  9. package/dist/index.js +209 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +213 -0
  12. package/dist/index.mjs.map +1 -1
  13. package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
  14. package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
  15. package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
  16. package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
  17. package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
  18. package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
  19. package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
  20. package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
  21. package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
  22. package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
  23. package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
  24. package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
  25. package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
  26. package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
  27. package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
  28. package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
  29. package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
  30. package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
  31. package/package.json +4 -2
@@ -0,0 +1,326 @@
1
+ # AIO Toolkit: Create OpenWhisk Action
2
+
3
+ **Command Name:** `aio-toolkit-create-openwhisk-action`
4
+
5
+ **Description:** Creates an OpenWhisk action using @adobe-commerce/aio-toolkit — for action-to-action invocation, orchestration, and sub-action patterns
6
+
7
+ ## Workflow
8
+
9
+ This command creates actions that are invoked by other actions (not directly by HTTP), and optionally use the `Openwhisk` client to invoke downstream actions.
10
+
11
+ ### Step 1: Verify Prerequisites
12
+
13
+ 1. Check if `@adobe-commerce/aio-toolkit` is installed in `package.json`
14
+ - If NOT installed, ask user if they want to install it: `npm install @adobe-commerce/aio-toolkit`
15
+ 2. Detect project language (TypeScript or JavaScript)
16
+ - Check for `typescript` in dependencies + `tsconfig.json`
17
+ - Check for `.ts` files in `actions/` or `lib/`
18
+ - Default to JavaScript if ambiguous
19
+ 3. Detect project structure
20
+ - Check for `application:` in `app.config.yaml` (root actions)
21
+ - Check for `extensions:` in `app.config.yaml` (extension point actions)
22
+
23
+ ### Step 2: Collect Action Configuration
24
+
25
+ Ask the user:
26
+
27
+ 1. **Action Name** (required)
28
+ - Example: `process-order`, `validate-product`, `sync-customer`
29
+
30
+ 2. **Action Role**
31
+ - **Sub-action target** — invoked by a consumer/orchestrator; does focused processing, no further action invocation
32
+ - **Orchestrator** — invokes one or more downstream actions using the `Openwhisk` client
33
+
34
+ 3. **Action Location** (auto-detect or ask)
35
+ - Root application (`actions/`)
36
+ - Extension point (`[extension-path]/actions/`)
37
+
38
+ 4. **Package Structure**
39
+ - Simple: `actions/[action-name]/index.[js/ts]`
40
+ - Packaged: `actions/[package]/[action-name]/index.[js/ts]`
41
+ - If packaged, ask for package name
42
+
43
+ 5. **If Orchestrator: Downstream Actions to Invoke**
44
+ - Action names to invoke (e.g., `my-package/validate-order`, `my-package/send-notification`)
45
+ - Invocation mode for each: **Blocking** (wait for result, default) or **Non-blocking** (fire and forget)
46
+
47
+ 6. **Business Logic Description**
48
+ - What should this action do?
49
+
50
+ ### Step 3: Confirm Configuration
51
+
52
+ Display summary:
53
+
54
+ ```
55
+ 📋 OpenWhisk Action Configuration
56
+
57
+ Action Name: [name]
58
+ Language: [JavaScript/TypeScript] (auto-detected)
59
+ Role: [Sub-action target / Orchestrator]
60
+ Location: [Root/Extension]
61
+ Package: [package-name or simple]
62
+ [If Orchestrator]
63
+ Downstream Actions:
64
+ - [action-name] ([blocking/non-blocking])
65
+
66
+ Business Logic: [description]
67
+
68
+ ✅ Files to Create:
69
+ - actions/[path]/index.[js/ts]
70
+ - Update app.config.yaml or ext.config.yaml
71
+ [- actions/[package]/actions.config.yaml if packaged]
72
+
73
+ Should I proceed?
74
+ ```
75
+
76
+ ### Step 4: Generate OpenWhisk Action
77
+
78
+ #### Sub-action Template
79
+
80
+ **JavaScript:**
81
+
82
+ ```javascript
83
+ const {
84
+ OpenwhiskAction,
85
+ RuntimeActionResponse,
86
+ HttpStatus,
87
+ } = require('@adobe-commerce/aio-toolkit');
88
+ const name = '[action-name]';
89
+
90
+ exports.main = OpenwhiskAction.execute(name, async (params, ctx) => {
91
+ const { logger } = ctx;
92
+ logger.info({ message: `${name}-processing`, params: JSON.stringify(params) });
93
+
94
+ try {
95
+ // TODO: Implement business logic
96
+ // params contains everything passed by the calling consumer/orchestrator
97
+
98
+ logger.info({ message: `${name}-success` });
99
+ return RuntimeActionResponse.success({
100
+ success: true,
101
+ message: 'Processed successfully',
102
+ });
103
+ } catch (error) {
104
+ logger.error({ message: `${name}-error`, error: error.message, stack: error.stack });
105
+ return RuntimeActionResponse.error(
106
+ HttpStatus.INTERNAL_ERROR,
107
+ `Failed to process: ${error.message}`
108
+ );
109
+ }
110
+ });
111
+ ```
112
+
113
+ #### Orchestrator Template (blocking invocations)
114
+
115
+ **JavaScript:**
116
+
117
+ ```javascript
118
+ const {
119
+ OpenwhiskAction,
120
+ Openwhisk,
121
+ RuntimeActionResponse,
122
+ HttpStatus,
123
+ } = require('@adobe-commerce/aio-toolkit');
124
+ const name = '[action-name]';
125
+
126
+ exports.main = OpenwhiskAction.execute(name, async (params, ctx) => {
127
+ const { logger } = ctx;
128
+
129
+ // API_HOST and API_AUTH must be provided as action inputs
130
+ const openwhisk = new Openwhisk(params.API_HOST, params.API_AUTH);
131
+
132
+ logger.info({ message: `${name}-start` });
133
+
134
+ try {
135
+ // Blocking invocation — waits for the downstream action to complete
136
+ const result = await openwhisk.execute(
137
+ '[package]/[downstream-action]',
138
+ { /* params to pass */ }
139
+ );
140
+
141
+ const body = result?.response?.result?.body;
142
+ const statusCode = result?.response?.result?.statusCode;
143
+
144
+ if (statusCode >= 400) {
145
+ return RuntimeActionResponse.error(statusCode, body?.error || 'Downstream action failed');
146
+ }
147
+
148
+ logger.info({ message: `${name}-success` });
149
+ return RuntimeActionResponse.success(body);
150
+ } catch (error) {
151
+ logger.error({ message: `${name}-error`, error: error.message, stack: error.stack });
152
+ return RuntimeActionResponse.error(
153
+ HttpStatus.INTERNAL_ERROR,
154
+ `Failed to invoke downstream action: ${error.message}`
155
+ );
156
+ }
157
+ });
158
+ ```
159
+
160
+ #### Orchestrator Template (mixed blocking / non-blocking)
161
+
162
+ ```javascript
163
+ const {
164
+ OpenwhiskAction,
165
+ Openwhisk,
166
+ RuntimeActionResponse,
167
+ } = require('@adobe-commerce/aio-toolkit');
168
+ const name = '[action-name]';
169
+
170
+ exports.main = OpenwhiskAction.execute(name, async (params, ctx) => {
171
+ const { logger } = ctx;
172
+ const openwhisk = new Openwhisk(params.API_HOST, params.API_AUTH);
173
+
174
+ // Step 1: blocking — must succeed before continuing
175
+ const validation = await openwhisk.execute('[package]/validate', { id: params.id });
176
+
177
+ if (!validation.response?.result?.body?.valid) {
178
+ return RuntimeActionResponse.error(400, 'Validation failed');
179
+ }
180
+
181
+ // Step 2: non-blocking — fire and forget (parallel)
182
+ const [act1, act2] = await Promise.all([
183
+ openwhisk.execute('[package]/notify', { id: params.id }, { blocking: false }),
184
+ openwhisk.execute('[package]/log-event', { id: params.id }, { blocking: false }),
185
+ ]);
186
+
187
+ logger.info({
188
+ message: `${name}-dispatched`,
189
+ notifyActivationId: act1.activationId,
190
+ logActivationId: act2.activationId,
191
+ });
192
+
193
+ return RuntimeActionResponse.success({ dispatched: true });
194
+ });
195
+ ```
196
+
197
+ **TypeScript:** Same with type annotations and `import` syntax
198
+
199
+ ### Step 5: Update Configuration Files
200
+
201
+ Add action to `app.config.yaml` or `ext.config.yaml`:
202
+
203
+ **Sub-action (no Openwhisk client):**
204
+
205
+ ```yaml
206
+ [action-name]:
207
+ function: actions/[action-name]/index.[js/ts]
208
+ web: 'no'
209
+ runtime: nodejs:22
210
+ inputs:
211
+ LOG_LEVEL: debug
212
+ annotations:
213
+ final: true
214
+ ```
215
+
216
+ **Orchestrator (uses Openwhisk client — requires API_HOST and API_AUTH):**
217
+
218
+ ```yaml
219
+ [action-name]:
220
+ function: actions/[action-name]/index.[js/ts]
221
+ web: 'no'
222
+ runtime: nodejs:22
223
+ inputs:
224
+ LOG_LEVEL: debug
225
+ API_HOST: $API_HOST
226
+ API_AUTH: $API_AUTH
227
+ annotations:
228
+ final: true
229
+ ```
230
+
231
+ > `API_HOST` and `API_AUTH` are NOT injected automatically — they must be declared as action inputs so OpenWhisk passes them to `params`.
232
+
233
+ **Packaged structure:**
234
+
235
+ Create `actions/[package]/actions.config.yaml` and reference in main config.
236
+
237
+ ### Step 6: Completion
238
+
239
+ Display:
240
+
241
+ ```
242
+ ✅ OpenWhisk Action Created Successfully!
243
+
244
+ 📁 Files Created:
245
+ - actions/[path]/index.[js/ts]
246
+
247
+ 📝 Configuration Updated:
248
+ - app.config.yaml or ext.config.yaml
249
+ [- actions/[package]/actions.config.yaml if packaged]
250
+
251
+ 🚀 Next Steps:
252
+ 1. Implement business logic in the action
253
+ 2. [If sub-action] Reference action name in the consuming consumer/orchestrator
254
+ 3. Test locally: aio app dev
255
+ 4. Deploy: aio app deploy
256
+
257
+ 📖 Documentation:
258
+ - OpenwhiskAction / Openwhisk: @adobe-commerce/aio-toolkit
259
+ ```
260
+
261
+ ### Key Features
262
+
263
+ - **No HTTP concerns**: No method validation, no required params/headers — the action receives whatever the caller passes
264
+ - **Lightweight**: Provides logging, telemetry, and error handling only
265
+ - **Two roles**: Sub-action target (process and return) or Orchestrator (invoke and coordinate)
266
+ - **Openwhisk client**: `new Openwhisk(params.API_HOST, params.API_AUTH)` — must be in action inputs
267
+ - **Blocking vs non-blocking**: `blocking: true` (default) waits for result; `blocking: false` returns activation ID immediately
268
+ - **Parallel dispatch**: Use `Promise.all()` with `blocking: false` to fire multiple actions concurrently
269
+ - **Best Practices**: Structured logging, error handling, telemetry-ready
270
+
271
+ ### Action Classes
272
+
273
+ **OpenwhiskAction.execute(name, actionFn)**
274
+ - No HTTP method or parameter validation
275
+ - Same `ctx` shape as all other action types: `{ logger, headers, telemetry }`
276
+ - `action_type` is always `'openwhisk-action'`
277
+ - Span prefix: `openwhisk.action.*`
278
+ - Unhandled throws → `RuntimeActionResponse.error(500, 'server error')`
279
+
280
+ **Openwhisk Class** (for orchestrators only)
281
+ - Constructor: `new Openwhisk(params.API_HOST, params.API_AUTH)`
282
+ - Method: `execute(actionName, params, config?)`
283
+ - `actionName`: fully qualified (e.g., `'my-package/my-action'`) or bare name
284
+ - `params`: object passed to the invoked action
285
+ - `config.blocking`: `true` (default) — wait for result; `false` — return activation ID immediately
286
+ - Returns: full activation result when blocking; partial activation with only ID when non-blocking
287
+ - Errors are **not caught internally** — wrap in try/catch in your calling code
288
+
289
+ ### Difference from RuntimeAction
290
+
291
+ | Aspect | `OpenwhiskAction` | `RuntimeAction` |
292
+ |---|---|---|
293
+ | HTTP method validation | None | Configurable |
294
+ | Required params/headers | None | Configurable |
295
+ | `action_type` | `'openwhisk-action'` | `'runtime-action'` |
296
+ | Span prefix | `openwhisk.action.*` | `runtime.action.*` |
297
+ | Intended trigger | Action-to-action | HTTP requests |
298
+ | `web:` in config | Usually `'no'` | Usually `'yes'` |
299
+
300
+ ### Openwhisk Client vs RuntimeApiGatewayService
301
+
302
+ Both let one action call another — choose based on the target:
303
+
304
+ | | `Openwhisk` client | `RuntimeApiGatewayService` |
305
+ |---|---|---|
306
+ | Protocol | OpenWhisk API (internal) | HTTP via API Gateway |
307
+ | Target must be `web: 'yes'` | No | Yes |
308
+ | Auth | `API_HOST` + `API_AUTH` (action inputs) | IMS Bearer token (via `AdobeAuth`) |
309
+ | Returns | Full activation result | Raw `node-fetch` Response |
310
+ | Blocking / non-blocking | Configurable | Always async HTTP |
311
+ | Token management | None needed | Must generate + optionally cache |
312
+ | Best for | `web: 'no'` sub-actions, fan-out | `web: 'yes'` actions, HTTP-level control |
313
+
314
+ **Use `Openwhisk` client** (this command) when the target is `web: 'no'` or you need blocking/non-blocking control.
315
+ **Use `RuntimeApiGatewayService`** (see Related Rules) when the target is `web: 'yes'` and you need HTTP response-level control.
316
+
317
+ ### Related Rules
318
+
319
+ - **Setting up New Relic Telemetry**: Add observability to your OpenWhisk action
320
+ - **Using PublishEvent**: Publish CloudEvents to Adobe I/O Events from your OpenWhisk action
321
+ - **Using RuntimeApiGatewayService**: Call a `web: 'yes'` action via API Gateway (alternative to the Openwhisk client for web-exposed targets)
322
+ - **Using FileRepository**: Persist and retrieve records using Adobe I/O Files storage from your OpenWhisk action
323
+ - **Using AbdbCollection**: Add MongoDB-backed App Builder Data storage with schema validation to your OpenWhisk action
324
+ - **Using AbdbRepository**: Add full CRUD operations (insert, find, update, delete, pagination) on top of an AbdbCollection in your OpenWhisk action
325
+ - **Using Amazon SQS — Publish**: Publish messages to an Amazon SQS queue from your OpenWhisk action
326
+ - **Create Amazon SQS Consumer**: The SQS worker is an OpenwhiskAction — use this command to create the full scheduler + worker consumer pattern
@@ -37,7 +37,7 @@ Ask the user:
37
37
  - If packaged, ask for package name
38
38
 
39
39
  4. **HTTP Methods** (comma-separated or empty for all)
40
- - Options: GET, POST, PUT, DELETE, PATCH
40
+ - Options: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
41
41
  - Example: `POST, GET`
42
42
 
43
43
  5. **Required Parameters** (comma-separated or empty)
@@ -194,12 +194,13 @@ Display:
194
194
 
195
195
  Runtime actions return responses using these methods:
196
196
 
197
- #### **success(result)** - Return Successful Response
197
+ #### **success(result, headers?)** - Return Successful Response
198
198
 
199
199
  Returns a successful response with the provided result data and 200 status code.
200
200
 
201
201
  **Parameters:**
202
202
  - `result` (required): The data to return in the response body
203
+ - `headers` (optional): Custom HTTP response headers to include (`Record<string, string>`, default `{}`)
203
204
 
204
205
  ```javascript
205
206
  // Return success with data
@@ -215,8 +216,11 @@ return RuntimeActionResponse.success([
215
216
  { id: 2, name: 'Product B' }
216
217
  ]);
217
218
 
218
- // Return success with simple value
219
- return RuntimeActionResponse.success({ message: 'Success' });
219
+ // Return success with custom response headers
220
+ return RuntimeActionResponse.success(
221
+ { message: 'Success' },
222
+ { 'Cache-Control': 'max-age=300', 'X-Custom-Header': 'value' }
223
+ );
220
224
  ```
221
225
 
222
226
  Returns:
@@ -242,7 +246,6 @@ Returns an error response with the specified HTTP status code and error message.
242
246
  **Available HttpStatus codes:**
243
247
  - `HttpStatus.BAD_REQUEST` (400) - Invalid request
244
248
  - `HttpStatus.UNAUTHORIZED` (401) - Authentication required
245
- - `HttpStatus.FORBIDDEN` (403) - Access denied
246
249
  - `HttpStatus.NOT_FOUND` (404) - Resource not found
247
250
  - `HttpStatus.METHOD_NOT_ALLOWED` (405) - HTTP method not allowed
248
251
  - `HttpStatus.INTERNAL_ERROR` (500) - Internal server error
@@ -290,4 +293,11 @@ Returns:
290
293
  ### Related Rules
291
294
 
292
295
  - **Setting up New Relic Telemetry**: Add observability to your runtime action
296
+ - **Using PublishEvent**: Publish CloudEvents to Adobe I/O Events from your runtime action
297
+ - **Using RuntimeApiGatewayService**: Call another web-exposed Runtime action via API Gateway from your action
298
+ - **Using FileRepository**: Persist and retrieve records using Adobe I/O Files storage from your runtime action
299
+ - **Using AbdbCollection**: Add MongoDB-backed App Builder Data storage with schema validation to your runtime action
300
+ - **Using AbdbRepository**: Add full CRUD operations (insert, find, update, delete, pagination) on top of an AbdbCollection in your runtime action
301
+ - **Using Amazon SQS — Publish**: Publish messages to an Amazon SQS queue from your runtime action
302
+ - **Create Amazon SQS Consumer**: Create the scheduler + worker pair to consume messages from an Amazon SQS queue
293
303