@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,445 @@
1
+ # AIO Toolkit: Create Amazon SQS Consumer
2
+
3
+ **Command Name:** `aio-toolkit-create-amazon-sqs-consumer`
4
+
5
+ **Description:** Creates a complete Amazon SQS fan-out consumer pattern using @adobe-commerce/aio-toolkit — a scheduler action (cron trigger) and a worker action (pulls and processes messages), wired together via Openwhisk.
6
+
7
+ ## Workflow
8
+
9
+ This command creates two dedicated action files that work together to process messages from an Amazon SQS queue at scale within App Builder's 60-second action time limit:
10
+
11
+ - **Scheduler** (`RuntimeAction`, `web: 'no'`) — triggered on a cron schedule; spawns N worker activations in parallel via `Openwhisk.execute()` (non-blocking) and returns immediately
12
+ - **Worker** (`OpenwhiskAction`, `web: 'no'`) — spawned by the scheduler; pulls up to `batchSize` messages from SQS, processes each one, and deletes successfully handled messages
13
+
14
+ ### Step 1: Verify Prerequisites
15
+
16
+ 1. Check if `@adobe-commerce/aio-toolkit` is installed in `package.json`
17
+ - If NOT installed: `npm install @adobe-commerce/aio-toolkit`
18
+ 2. Check if `@aws-sdk/client-sqs` is installed (peer dependency — required)
19
+ - If NOT installed: `npm install @aws-sdk/client-sqs`
20
+ 3. Detect project language (TypeScript or JavaScript)
21
+ - Check for `typescript` in dependencies + `tsconfig.json`
22
+ - Check for `.ts` files in `actions/` or `lib/`
23
+ - Default to JavaScript if ambiguous
24
+ 4. Detect project structure
25
+ - Check for `application:` in `app.config.yaml` (root actions)
26
+ - Check for `extensions:` in `app.config.yaml` (extension point actions)
27
+
28
+ ### Step 2: Collect Consumer Configuration
29
+
30
+ Ask the user:
31
+
32
+ 1. **Scheduler Action Name** (default: `amazon-sqs-scheduler`)
33
+ - Example: `order-queue-scheduler`, `product-sync-scheduler`
34
+
35
+ 2. **Worker Action Name** (default: `amazon-sqs-worker`)
36
+ - Example: `order-queue-worker`, `product-sync-worker`
37
+
38
+ 3. **Action Location**
39
+ - Root application (`actions/`)
40
+ - Extension point (`[extension-path]/actions/`)
41
+
42
+ 4. **Package Structure**
43
+ - Simple: `actions/[action-name]/index.[js/ts]`
44
+ - Packaged: `actions/[package]/[action-name]/index.[js/ts]`
45
+ - If packaged, ask for package name (e.g., `crons`, `queues`, `workers`)
46
+
47
+ 5. **Worker Thread Count** (default: `5`)
48
+ - Number of worker activations spawned in parallel per scheduler run
49
+ - Each worker processes `batchSize` messages independently
50
+
51
+ 6. **Batch Size per Worker** (default: `100`)
52
+ - Maximum number of SQS messages each worker pulls per invocation
53
+ - Rule of thumb: `total expected queue depth ÷ worker thread count`
54
+
55
+ 7. **Visibility Timeout** (default: `60` seconds)
56
+ - How long a pulled message is hidden from other consumers while being processed
57
+ - Set this to comfortably exceed your expected per-message processing time
58
+ - If a worker times out before finishing, messages become visible again and are retried
59
+
60
+ 8. **Message Payload Structure** — what does each message body contain?
61
+ - Example: `{ type: 'order.created', data: { orderId, ... } }`
62
+ - Used to generate the `JSON.parse(body)` destructuring in the worker handler
63
+
64
+ 9. **What does the worker do with each message?**
65
+ - Brief description, e.g.: "persist to ABDB", "call Commerce API", "forward to another action"
66
+ - Used to scaffold the handler body with a TODO comment
67
+
68
+ 10. **Does the worker need IMS credentials?** (e.g., to call Core.AuthClient.generateAccessToken or ABDB)
69
+ - If yes: add `include-ims-credentials: true` to worker config
70
+
71
+ 11. **FIFO queue?** — does the queue URL end in `.fifo`?
72
+ - If yes: ask for a `messageGroupId` (default `'default'`) — only relevant if this project also publishes
73
+
74
+ ### Step 3: Confirm Configuration
75
+
76
+ Display summary:
77
+
78
+ ```
79
+ 📋 Amazon SQS Consumer Configuration
80
+
81
+ Scheduler Action: [scheduler-name]
82
+ Worker Action: [worker-name]
83
+ Language: [JavaScript/TypeScript] (auto-detected)
84
+ Location: [Root/Extension]
85
+ Package: [package-name or simple]
86
+
87
+ Worker Threads: [N] (spawned in parallel per scheduler run)
88
+ Batch Size per Worker: [N] messages per worker activation
89
+ Visibility Timeout: [N]s
90
+
91
+ Message Payload: [structure description]
92
+ Worker Logic: [description]
93
+ IMS Credentials: [Yes/No]
94
+
95
+ ✅ Files to Create:
96
+ - actions/[scheduler-path]/index.[js/ts]
97
+ - actions/[worker-path]/index.[js/ts]
98
+ - Update app.config.yaml or ext.config.yaml
99
+
100
+ Should I proceed?
101
+ ```
102
+
103
+ ### Step 4: Generate Scheduler Action
104
+
105
+ Create `actions/[scheduler-name]/index.[js|ts]`.
106
+
107
+ The scheduler fires all workers in parallel (non-blocking) and returns immediately with the activation IDs. It does not process any messages itself.
108
+
109
+ **JavaScript:**
110
+ ```javascript
111
+ /*
112
+ * <license header>
113
+ */
114
+
115
+ const {
116
+ RuntimeAction,
117
+ RuntimeActionResponse,
118
+ HttpStatus,
119
+ Openwhisk,
120
+ } = require('@adobe-commerce/aio-toolkit');
121
+
122
+ const DEFAULT_WORKER_THREADS = [worker-thread-count];
123
+ const name = '[scheduler-name]';
124
+
125
+ exports.main = RuntimeAction.execute(
126
+ name,
127
+ [],
128
+ ['LOG_LEVEL'],
129
+ [],
130
+ async (params, ctx) => {
131
+ const { logger } = ctx;
132
+
133
+ const rawThreads = Number(params.AWS_SQS_WORKER_THREADS);
134
+ const threads =
135
+ Number.isFinite(rawThreads) && rawThreads > 0
136
+ ? Math.floor(rawThreads)
137
+ : DEFAULT_WORKER_THREADS;
138
+
139
+ logger.info({ message: `${name}-start`, threads });
140
+
141
+ const openwhisk = new Openwhisk(params.API_HOST, params.API_AUTH);
142
+
143
+ // Fire all workers in parallel — non-blocking (blocking: false)
144
+ const activations = await Promise.all(
145
+ Array.from({ length: threads }, (_, workerIndex) =>
146
+ openwhisk.execute(
147
+ '[package/][worker-name]', // full action path: package/action-name or just action-name
148
+ { workerIndex },
149
+ { blocking: false }
150
+ )
151
+ )
152
+ );
153
+
154
+ const activationIds = activations.map((a) => a.activationId);
155
+
156
+ logger.info({ message: `${name}-dispatched`, threads, activation_ids: activationIds });
157
+
158
+ return RuntimeActionResponse.success({
159
+ success: true,
160
+ message: `Spawned ${threads} workers`,
161
+ threads,
162
+ activation_ids: activationIds,
163
+ });
164
+ }
165
+ );
166
+ ```
167
+
168
+ **TypeScript:** Same structure with `import` syntax and type annotations.
169
+
170
+ ### Step 5: Generate Worker Action
171
+
172
+ Create `actions/[worker-name]/index.[js|ts]`.
173
+
174
+ The worker pulls `batchSize` messages from SQS, processes each one concurrently via the handler, and deletes successfully handled messages. Failed messages remain in the queue until `visibilityTimeout` expires.
175
+
176
+ **JavaScript:**
177
+ ```javascript
178
+ /*
179
+ * <license header>
180
+ */
181
+
182
+ const {
183
+ AmazonSQSClient,
184
+ OpenwhiskAction,
185
+ RuntimeActionResponse,
186
+ HttpStatus,
187
+ } = require('@adobe-commerce/aio-toolkit');
188
+
189
+ const DEFAULT_BATCH_SIZE = [batch-size];
190
+ const name = '[worker-name]';
191
+
192
+ exports.main = OpenwhiskAction.execute(
193
+ name,
194
+ async (params, ctx) => {
195
+ const { logger } = ctx;
196
+
197
+ const workerIndex = params.workerIndex ?? 0;
198
+
199
+ if (!params.AWS_SQS_URL) {
200
+ logger.error({ message: `${name}-missing-queue-url`, workerIndex });
201
+ return RuntimeActionResponse.error(HttpStatus.BAD_REQUEST, 'AWS_SQS_URL is required');
202
+ }
203
+
204
+ const batchSize = Number(params.AWS_SQS_BATCH_SIZE) > 0
205
+ ? Math.floor(Number(params.AWS_SQS_BATCH_SIZE))
206
+ : DEFAULT_BATCH_SIZE;
207
+
208
+ logger.info({ message: `${name}-start`, workerIndex, batchSize, queueUrl: params.AWS_SQS_URL });
209
+
210
+ const sqs = new AmazonSQSClient({
211
+ region: params.AWS_REGION,
212
+ accessKeyId: params.AWS_ACCESS_KEY_ID,
213
+ secretAccessKey: params.AWS_SECRET_ACCESS_KEY,
214
+ queueUrl: params.AWS_SQS_URL,
215
+ visibilityTimeout: Number(params.AWS_SQS_VISIBILITY_TIMEOUT) || [visibility-timeout],
216
+ });
217
+
218
+ const consumeStart = Date.now();
219
+
220
+ // Handler: called concurrently for each received message
221
+ // Throw to signal failure — message stays in queue until visibilityTimeout
222
+ const stats = await sqs.consume(batchSize, async (messageId, body) => {
223
+ const payload = JSON.parse(body);
224
+
225
+ // TODO: implement message processing logic
226
+ // payload contains: [describe expected fields]
227
+ logger.info({ message: `${name}-processing`, workerIndex, messageId, type: payload.type });
228
+
229
+ // Example: persist, call an API, forward to another action
230
+ // throw new Error('processing failed') ← leaves message in queue for retry
231
+ });
232
+
233
+ const consumeDurationSec = +((Date.now() - consumeStart) / 1000).toFixed(2);
234
+
235
+ // Log handler-level failures (message stays in queue — will be retried)
236
+ for (const { messageId, error } of stats.errors) {
237
+ logger.error({
238
+ message: `${name}-handler-error`,
239
+ workerIndex,
240
+ messageId,
241
+ error: error instanceof Error ? error.message : String(error),
242
+ });
243
+ }
244
+
245
+ logger.info({
246
+ message: `${name}-complete`,
247
+ workerIndex,
248
+ consumeDurationSec,
249
+ received: stats.received,
250
+ processed: stats.processed,
251
+ deleted: stats.deleted,
252
+ failed: stats.failed,
253
+ });
254
+
255
+ return RuntimeActionResponse.success({
256
+ success: true,
257
+ workerIndex,
258
+ stats: {
259
+ consumeDurationSec,
260
+ received: stats.received,
261
+ processed: stats.processed,
262
+ deleted: stats.deleted,
263
+ failed: stats.failed,
264
+ },
265
+ });
266
+ }
267
+ );
268
+ ```
269
+
270
+ **TypeScript:** Same structure with `import` syntax, typed payload interface, and `AmazonSQSConsumeStats` type.
271
+
272
+ ### Step 6: Update Configuration Files
273
+
274
+ Add both actions to `app.config.yaml` or `ext.config.yaml`.
275
+
276
+ ```yaml
277
+ # Scheduler — cron trigger, spawns workers
278
+ [scheduler-name]:
279
+ function: actions/[scheduler-path]/index.[js/ts]
280
+ web: 'no'
281
+ runtime: nodejs:22
282
+ inputs:
283
+ LOG_LEVEL: debug
284
+ API_HOST: $API_HOST
285
+ API_AUTH: $API_AUTH
286
+ AWS_SQS_WORKER_THREADS: [worker-thread-count]
287
+ annotations:
288
+ final: true
289
+
290
+ # Worker — spawned by scheduler, not directly web-invokable
291
+ [worker-name]:
292
+ function: actions/[worker-path]/index.[js/ts]
293
+ web: 'no'
294
+ runtime: nodejs:22
295
+ inputs:
296
+ LOG_LEVEL: debug
297
+ AWS_REGION: $AWS_REGION
298
+ AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
299
+ AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
300
+ AWS_SQS_URL: $AWS_SQS_URL
301
+ AWS_SQS_BATCH_SIZE: [batch-size]
302
+ AWS_SQS_VISIBILITY_TIMEOUT: [visibility-timeout]
303
+ annotations:
304
+ final: true
305
+ # include-ims-credentials: true # uncomment if worker needs Core.AuthClient.generateAccessToken
306
+ ```
307
+
308
+ > **Note on `API_HOST` and `API_AUTH`**: The scheduler uses `Openwhisk.execute()` to spawn workers. These are auto-injected by the App Builder runtime — add `API_HOST: $API_HOST` and `API_AUTH: $API_AUTH` to the scheduler's `inputs` to make them available as `params`.
309
+
310
+ > **Note on cron trigger**: App Builder cron triggers are configured separately in `app.config.yaml` under `triggers` / `rules`. Example:
311
+ > ```yaml
312
+ > triggers:
313
+ > every-5-min:
314
+ > feed: /whisk.system/alarms/alarm
315
+ > trigger:
316
+ > cron: '*/5 * * * *'
317
+ > rules:
318
+ > sqs-scheduler-rule:
319
+ > trigger: every-5-min
320
+ > action: [scheduler-name]
321
+ > ```
322
+
323
+ ### Step 7: Add Environment Variables
324
+
325
+ ```bash
326
+ # Amazon SQS — shared by scheduler (thread count) and worker (credentials + queue)
327
+ AWS_REGION=us-east-1
328
+ AWS_ACCESS_KEY_ID=your-access-key-id
329
+ AWS_SECRET_ACCESS_KEY=your-secret-access-key
330
+ AWS_SQS_URL=https://sqs.us-east-1.amazonaws.com/123456789012/your-queue-name
331
+ # For FIFO: https://sqs.us-east-1.amazonaws.com/123456789012/your-queue.fifo
332
+ ```
333
+
334
+ **IAM permissions required on the worker's IAM user:**
335
+ - `sqs:ReceiveMessage`
336
+ - `sqs:DeleteMessage`
337
+ - `sqs:DeleteMessageBatch`
338
+
339
+ ### Step 8: Completion
340
+
341
+ Display:
342
+
343
+ ```
344
+ ✅ Amazon SQS Consumer Created Successfully!
345
+
346
+ 📁 Files Created:
347
+ - actions/[scheduler-path]/index.[js/ts] ← scheduler (cron trigger, spawns workers)
348
+ - actions/[worker-path]/index.[js/ts] ← worker (pulls + processes messages)
349
+
350
+ 📝 Configuration Updated:
351
+ - app.config.yaml or ext.config.yaml
352
+
353
+ 🚀 Next Steps:
354
+ 1. Implement the message processing logic in the worker's handler (marked with TODO)
355
+ 2. Add a cron trigger rule in app.config.yaml to schedule the scheduler action
356
+ 3. Ensure the SQS queue exists in AWS (queue URL: [queue-url])
357
+ 4. Verify IAM user has sqs:ReceiveMessage, sqs:DeleteMessage, sqs:DeleteMessageBatch
358
+ 5. Test locally: aio app dev
359
+ 6. Deploy: aio app deploy
360
+
361
+ ⚙️ Tuning:
362
+ - Worker threads: [N] × Batch size: [N] = [N×N] messages per scheduler run
363
+ - Increase AWS_SQS_WORKER_THREADS (scheduler input) to drain the queue faster
364
+ - Increase AWS_SQS_BATCH_SIZE (worker input) to process more per activation
365
+ - Set AWS_SQS_VISIBILITY_TIMEOUT > expected worker processing time to prevent re-delivery
366
+
367
+ 📖 Documentation:
368
+ - AmazonSQSClient: @adobe-commerce/aio-toolkit
369
+ - Openwhisk.execute(): @adobe-commerce/aio-toolkit
370
+
371
+ 💡 To also PUBLISH messages to this queue, use the "Using Amazon SQS — Publish" rule
372
+ to integrate AmazonSQSClient.publish() into any of your existing actions.
373
+ ```
374
+
375
+ ---
376
+
377
+ ### Key Features
378
+
379
+ - **Auto-detection**: Language (TS/JS) and project structure
380
+ - **Fan-out pattern**: Scheduler spawns N workers in parallel (non-blocking) — stays well within the 60-second action time limit
381
+ - **Concurrent message processing**: Worker processes all received messages via `Promise.all()` inside `consume()`
382
+ - **Automatic delete**: Successfully handled messages deleted; failed messages stay in queue for retry via `visibilityTimeout`
383
+ - **Configurable threads**: `AWS_SQS_WORKER_THREADS` in scheduler inputs — no redeploy needed to scale
384
+ - **Configurable batch size**: `AWS_SQS_BATCH_SIZE` in worker inputs — no redeploy needed to tune
385
+ - **FIFO support**: Automatic — just use a `.fifo` queue URL
386
+
387
+ ---
388
+
389
+ ### AmazonSQSClient Key Components
390
+
391
+ ```javascript
392
+ // Constructor
393
+ new AmazonSQSClient({
394
+ region, // AWS region — e.g. 'us-east-1'
395
+ accessKeyId, // IAM access key ID
396
+ secretAccessKey, // IAM secret access key
397
+ queueUrl, // full SQS queue URL
398
+ visibilityTimeout, // seconds message stays hidden while processing (default: 30)
399
+ waitTimeSeconds, // long polling on first receive call (default: 0 — use 0 for cron workers)
400
+ messageGroupId, // FIFO MessageGroupId (default: 'default')
401
+ })
402
+
403
+ // Consume
404
+ async consume(batchSize, handler): Promise<ConsumeStats>
405
+ // batchSize: max messages to pull per invocation
406
+ // handler: async (messageId, body) => void
407
+ // resolve → message deleted | throw → message stays in queue
408
+
409
+ // ConsumeStats shape:
410
+ {
411
+ received: number, // messages pulled from SQS
412
+ processed: number, // messages passed to handler
413
+ deleted: number, // handlers that resolved (deleted)
414
+ failed: number, // handlers that threw (left in queue)
415
+ errors: [{ messageId: string, error: Error }, ...]
416
+ }
417
+ ```
418
+
419
+ > **`consume()` throws on SQS transport errors** (ReceiveMessage or DeleteMessageBatch failures). Wrap in try/catch if you want to handle these in the worker rather than letting the activation fail.
420
+
421
+ ```javascript
422
+ // Openwhisk — for spawning workers from the scheduler
423
+ new Openwhisk(params.API_HOST, params.API_AUTH)
424
+ openwhisk.execute(actionName, params, { blocking: false })
425
+ // blocking: false → fire-and-forget, returns { activationId } immediately
426
+ ```
427
+
428
+ ---
429
+
430
+ ### Tuning Guidance
431
+
432
+ | Parameter | Config key | Guidance |
433
+ |---|---|---|
434
+ | `visibilityTimeout` | `AWS_SQS_VISIBILITY_TIMEOUT` | Must exceed expected per-message processing time + overhead. If a worker times out or crashes, unfinished messages re-appear after this interval |
435
+ | `batchSize` | `AWS_SQS_BATCH_SIZE` | `total queue depth ÷ worker thread count`. Keep low enough that a single worker finishes within the action time limit |
436
+ | Worker threads | `AWS_SQS_WORKER_THREADS` | Each thread is a separate OpenWhisk activation — scale up without redeployment by changing this input |
437
+ | `waitTimeSeconds` | Constructor | Leave at `0` for cron-based workers. Use `1–20` only when workers are triggered by queue events rather than a fixed schedule |
438
+
439
+ ---
440
+
441
+ ### Related Rules
442
+
443
+ - **"Using Amazon SQS — Publish"** (`aio-toolkit-use-amazon-sqs-publish.mdc`) — integrate `AmazonSQSClient.publish()` into any action to write messages to the queue this consumer reads from
444
+ - **"Creating Openwhisk Action"** (`aio-toolkit-create-openwhisk-action.md`) — the worker is an `OpenwhiskAction`; see that command for the full OpenwhiskAction reference
445
+ - **"Setting up New Relic Telemetry"** (`aio-toolkit-setup-new-relic-telemetry.mdc`) — add observability to the scheduler and worker actions
@@ -559,4 +559,10 @@ Display:
559
559
  ### Related Rules
560
560
 
561
561
  - **Setting up New Relic Telemetry**: Add observability to your event consumer
562
+ - **Using PublishEvent**: Publish CloudEvents to Adobe I/O Events from your consumer (fan-out pattern)
563
+ - **Using RuntimeApiGatewayService**: Call a web-exposed Runtime action via API Gateway from your consumer
564
+ - **Using FileRepository**: Persist and retrieve records using Adobe I/O Files storage from your consumer action
565
+ - **Using AbdbCollection**: Add MongoDB-backed App Builder Data storage with schema validation to your consumer action
566
+ - **Using AbdbRepository**: Add full CRUD operations (insert, find, update, delete, pagination) on top of an AbdbCollection in your consumer action
567
+ - **Using Amazon SQS — Publish**: Publish messages to an Amazon SQS queue from your consumer action (fan-out to SQS after processing an I/O Event)
562
568
 
@@ -502,16 +502,22 @@ Resolvers follow this class-based pattern:
502
502
  ```javascript
503
503
  class ResolverName {
504
504
  constructor(ctx) {
505
- this.ctx = ctx; // Context with logger, headers, params
505
+ this.ctx = ctx;
506
506
  }
507
507
 
508
508
  async execute() {
509
509
  return async (args) => {
510
- // args = GraphQL operation arguments
511
- const { logger } = this.ctx;
510
+ // args = GraphQL operation arguments (field arguments from the query)
511
+ const { logger, headers, telemetry, params } = this.ctx;
512
512
 
513
- // Business logic here
514
- // Can access: logger, this.ctx.headers, this.ctx.params
513
+ // logger - structured logger with auto-correlation
514
+ // headers - incoming HTTP request headers
515
+ // telemetry - OpenTelemetry helper for custom spans
516
+ // params - full OpenWhisk params including:
517
+ // params.query (GraphQL query string)
518
+ // params.variables (GraphQL variables, already parsed)
519
+ // params.operationName (named operation, if provided)
520
+ // params.LOG_LEVEL, params.ENABLE_TELEMETRY, etc. (action inputs)
515
521
 
516
522
  return result; // Return data matching GraphQL return type
517
523
  };
@@ -521,11 +527,19 @@ class ResolverName {
521
527
 
522
528
  **Key Points:**
523
529
  - Constructor receives context from GraphQlAction
524
- - execute() returns async function that receives GraphQL arguments
525
- - Throw errors for GraphQL error handling
530
+ - `execute()` returns an async function that receives GraphQL field arguments (`args`)
531
+ - `args` contains the field-level arguments (e.g. `id` from `getUser(id: ID!)`)
532
+ - `ctx.params` contains the full OpenWhisk params — use it to access action inputs or raw query details
533
+ - Throw errors inside the resolver for GraphQL field-level error handling (returned as `errors[]` in the response with HTTP 200)
526
534
  - Use structured logging
527
535
 
528
536
  ### Related Rules
529
537
 
530
538
  - **Setting up New Relic Telemetry**: Add observability to your GraphQL action
539
+ - **Using PublishEvent**: Publish CloudEvents to Adobe I/O Events from your GraphQL resolver
540
+ - **Using RuntimeApiGatewayService**: Call a web-exposed Runtime action via API Gateway from your resolver
541
+ - **Using FileRepository**: Persist and retrieve records using Adobe I/O Files storage from your GraphQL resolver
542
+ - **Using AbdbCollection**: Add MongoDB-backed App Builder Data storage with schema validation to your GraphQL resolver
543
+ - **Using AbdbRepository**: Add full CRUD operations (insert, find, update, delete, pagination) on top of an AbdbCollection in your GraphQL resolver
544
+ - **Using Amazon SQS — Publish**: Publish messages to an Amazon SQS queue from a GraphQL resolver
531
545