@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,510 @@
1
+ ---
2
+ description: Adding PublishEvent to Adobe I/O Runtime actions using @adobe-commerce/aio-toolkit
3
+ globs: '**/{actions,lib}/**/*.{ts,js}'
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Using PublishEvent
8
+
9
+ ## Trigger Conditions
10
+
11
+ This rule applies when the user requests to publish events to Adobe I/O Events from within an action using any of these phrases:
12
+
13
+ - "Publish event to I/O Events"
14
+ - "Emit a CloudEvent"
15
+ - "Send event to Adobe I/O"
16
+ - "Fan-out events"
17
+ - "Trigger downstream events with PublishEvent"
18
+ - "Use PublishEvent in [action-name]"
19
+ - "Add event publishing to [action-name]"
20
+ - "Publish [event-type] event"
21
+ - "Integrate PublishEvent"
22
+ - "Notify via I/O Events"
23
+
24
+ **Important**: This rule does NOT create new actions. It integrates `PublishEvent` into existing actions only.
25
+
26
+ **Integration with Other Action Creation Rules:**
27
+
28
+ When using action creation rules (RuntimeAction, WebhookAction, EventConsumerAction, OpenwhiskAction) and the developer mentions publishing events in the business logic:
29
+
30
+ - **Automatically trigger this rule** after the action is created
31
+ - Examples: "publish an event after processing", "emit a CloudEvent", "fan-out to other consumers", "notify via I/O Events"
32
+ - This rule handles all PublishEvent setup, credential wiring, config changes, and code integration
33
+
34
+ **If you need to create a new action first:**
35
+
36
+ - Use the appropriate action creation command first
37
+ - Then this rule will add PublishEvent integration to that action
38
+
39
+ ---
40
+
41
+ ## Step 1: Verify Prerequisites
42
+
43
+ Before proceeding, verify:
44
+
45
+ 1. **Toolkit installed**: Check `@adobe-commerce/aio-toolkit` in `package.json` dependencies
46
+ - If NOT installed: `npm install @adobe-commerce/aio-toolkit`
47
+
48
+ 2. **AIO SDK installed**: Check `@adobe/aio-sdk` in `package.json` dependencies
49
+ - Required for `Core.AuthClient.generateAccessToken(params)` to obtain an IMS access token
50
+ - If NOT installed: `npm install @adobe/aio-sdk`
51
+ - Note: App Builder projects typically include this — run `npm list @adobe/aio-sdk` to confirm
52
+
53
+ 3. **Detect Language (TypeScript vs JavaScript)**:
54
+
55
+ **Check for TypeScript indicators (check ALL of these)**:
56
+ 1. **Package Dependencies**: Look for `typescript` in `package.json` dependencies or devDependencies
57
+ 2. **Config File**: Check if `tsconfig.json` exists in project root
58
+ 3. **TypeScript Loaders**: Look for `ts-loader`, `ts-node`, or `@types/*` packages in `package.json`
59
+ 4. **Existing Files**: Check for `.ts` or `.tsx` files in key directories (`actions/`, `src/`, `lib/`)
60
+
61
+ **Detection Logic**:
62
+ - **If ANY of the following are true → TypeScript project**:
63
+ - `typescript` package installed AND `tsconfig.json` exists
64
+ - Multiple TypeScript indicators (2 or more from above list)
65
+ - Existing `.ts` files found in `actions/` or `lib/` directories
66
+ - **Otherwise → JavaScript project**
67
+
68
+ 4. **Detect Project Structure**:
69
+ - Check `app.config.yaml` for `application:` section (root actions)
70
+ - Check `app.config.yaml` for `extensions:` section (extension point actions)
71
+ - If extensions exist, parse the `$include` path for the extension directory
72
+
73
+ 5. **Check Existing Actions**: List all existing actions and their file paths
74
+ - From root `actions/` directory
75
+ - From `[extension-path]/actions/` directory
76
+ - If NO actions exist: Stop and recommend creating an action first
77
+
78
+ 6. Only proceed to Step 2 after confirming all prerequisites
79
+
80
+ ---
81
+
82
+ ## Step 2: Ask Required Questions
83
+
84
+ Before generating any code, ask the user the following questions:
85
+
86
+ **Important**: Do not make assumptions — keep asking until all details are clear.
87
+
88
+ 1. **Target Action**: Which existing action do you want to add PublishEvent to?
89
+ - List all discovered actions for the user to choose from
90
+
91
+ 2. **Provider ID**: What is the Adobe I/O Events provider ID?
92
+ - Source: Adobe Developer Console → Your project → I/O Events → Provider ID
93
+ - Will be stored as `PROVIDER_ID` env var (recommended) or hardcoded (not recommended)
94
+
95
+ 3. **Event Code(s)**: What event type(s) will this action publish?
96
+ - Format: reverse-DNS, e.g. `com.adobe.commerce.order.created`
97
+ - Multiple codes if the action publishes different event types based on conditions
98
+ - Each code becomes the CloudEvent `type` field
99
+
100
+ 4. **Payload**: What data should the event carry?
101
+ - Describe the structure: e.g. `{ orderId, customerId, amount }`
102
+ - This becomes the CloudEvent `data` field
103
+
104
+ 5. **Subject** (optional): Should events include a `subject` field?
105
+ - Used for routing and filtering in downstream consumers
106
+ - Example: `orders/${orderId}`, `products/${sku}`
107
+ - If not needed, subject is omitted entirely
108
+
109
+ 6. **Event ID**: How should the event ID be assigned?
110
+ - **Auto-generate** (default): UUID v4 generated automatically per event
111
+ - **Custom**: Provide a specific ID (e.g. from a correlation ID in `params`)
112
+
113
+ 7. **Fan-out Pattern**: Does this action publish multiple events per invocation?
114
+ - **Single event**: One `publisher.execute()` call
115
+ - **Multiple events**: `Promise.all()` fan-out pattern (e.g. notify multiple downstream systems)
116
+ - If yes, ask: what are all the event codes and their payloads?
117
+
118
+ ---
119
+
120
+ ## Step 3: Confirm Implementation Details
121
+
122
+ After receiving answers to ALL questions, present a comprehensive summary and **wait for user confirmation** before proceeding to Step 4:
123
+
124
+ ---
125
+
126
+ ### 📋 PublishEvent Integration Summary
127
+
128
+ **Target Action:** `[action-name]`
129
+ **Action Path:** `[path to action file]`
130
+ **Language:** [TypeScript/JavaScript] (auto-detected)
131
+
132
+ **Event Publishing Configuration:**
133
+
134
+ - **Provider ID:** `$PROVIDER_ID` (from env var) or `[hardcoded-value]`
135
+ - **Pattern:** [Single event / Fan-out with Promise.all()]
136
+
137
+ **Event(s) to Publish:**
138
+
139
+ [For single event:]
140
+ - **Event Code:** `[event-code]`
141
+ - **Payload:** `{ [payload fields] }`
142
+ - **Subject:** `[subject pattern]` / Not included
143
+ - **Event ID:** Auto-generated UUID / `[source field]`
144
+
145
+ [For fan-out:]
146
+ | Event Code | Payload | Subject |
147
+ |---|---|---|
148
+ | `[code-1]` | `{ [fields] }` | `[subject]` or — |
149
+ | `[code-2]` | `{ [fields] }` | `[subject]` or — |
150
+
151
+ **Environment Variables:**
152
+
153
+ ```bash
154
+ # Adobe I/O Events — PublishEvent credentials
155
+ IMS_ORG_ID=
156
+ API_KEY=
157
+ PROVIDER_ID=
158
+ ```
159
+
160
+ 📍 **Source:** Adobe Developer Console → Your project → Credentials + I/O Events
161
+
162
+ ---
163
+
164
+ ### ✅ What Will Be Changed
165
+
166
+ **1. Action Implementation**
167
+ - ✏️ `[action-path]/index.[js/ts]`
168
+ - Import `PublishEvent` from `@adobe-commerce/aio-toolkit`
169
+ - Import `Core` from `@adobe/aio-sdk`
170
+ - Generate IMS access token via `Core.AuthClient.generateAccessToken(params)`
171
+ - Construct `new PublishEvent(params.IMS_ORG_ID, params.API_KEY, accessToken, logger)`
172
+ - Call `publisher.execute(...)` [with `Promise.all()` if fan-out]
173
+ - Handle `result.status === 'failed'` responses
174
+
175
+ **2. Action Configuration**
176
+ - ✏️ `app.config.yaml` or `ext.config.yaml` (or `actions.config.yaml` if packaged)
177
+ - Add `include-ims-credentials: true` annotation (required for token generation)
178
+ - Add `IMS_ORG_ID: $IMS_ORG_ID`, `API_KEY: $API_KEY`, `PROVIDER_ID: $PROVIDER_ID` inputs
179
+
180
+ **3. Environment Variables**
181
+ - 📄/✏️ `.env` (project root) — add placeholder variables if not already present
182
+
183
+ ---
184
+
185
+ **Should I proceed with this implementation?**
186
+
187
+ ---
188
+
189
+ ## Step 4: Generate Implementation
190
+
191
+ ### Step 4.1: Update the Action Code
192
+
193
+ Add `PublishEvent` integration to the selected action.
194
+
195
+ #### Single Event — JavaScript
196
+
197
+ ```javascript
198
+ const { PublishEvent } = require('@adobe-commerce/aio-toolkit');
199
+ const { Core } = require('@adobe/aio-sdk');
200
+
201
+ // Inside your action handler (params, ctx):
202
+ const { logger } = ctx;
203
+
204
+ // Step 1: Generate IMS access token
205
+ // Requires include-ims-credentials: true in app.config.yaml
206
+ const tokenResponse = await Core.AuthClient.generateAccessToken(params);
207
+ const accessToken = tokenResponse && tokenResponse.access_token;
208
+
209
+ // Step 2: Construct publisher — throws if credentials are blank
210
+ const publisher = new PublishEvent(
211
+ params.IMS_ORG_ID,
212
+ params.API_KEY,
213
+ accessToken,
214
+ logger // optional: enables debug/info/error logs from the publisher
215
+ );
216
+
217
+ // Step 3: Publish the event
218
+ const result = await publisher.execute(
219
+ params.PROVIDER_ID, // required: target event provider
220
+ '[event-code]', // required: CloudEvent type field
221
+ { /* payload fields */ }, // required: CloudEvent data field
222
+ undefined, // optional: omit for auto-generated UUID
223
+ undefined // optional: subject for routing/filtering
224
+ );
225
+
226
+ // Step 4: Handle result — execute() NEVER throws, always check status
227
+ if (result.status === 'failed') {
228
+ logger.error({ message: '[action-name]-publish-failed', error: result.error });
229
+ // Decide whether to return an error or continue depending on business requirements
230
+ }
231
+
232
+ logger.info({ message: '[action-name]-published', eventId: result.eventId });
233
+ ```
234
+
235
+ **TypeScript:** Same with `import` syntax and optional type imports:
236
+ ```typescript
237
+ import { PublishEvent } from '@adobe-commerce/aio-toolkit';
238
+ import type { PublishEventResult } from '@adobe-commerce/aio-toolkit';
239
+ import { Core } from '@adobe/aio-sdk';
240
+ ```
241
+
242
+ #### Fan-out Pattern — JavaScript
243
+
244
+ ```javascript
245
+ const { PublishEvent } = require('@adobe-commerce/aio-toolkit');
246
+ const { Core } = require('@adobe/aio-sdk');
247
+
248
+ // Inside your action handler (params, ctx):
249
+ const { logger } = ctx;
250
+
251
+ const tokenResponse = await Core.AuthClient.generateAccessToken(params);
252
+ const accessToken = tokenResponse && tokenResponse.access_token;
253
+
254
+ const publisher = new PublishEvent(
255
+ params.IMS_ORG_ID,
256
+ params.API_KEY,
257
+ accessToken,
258
+ logger
259
+ );
260
+
261
+ // Publish multiple events in parallel
262
+ const events = [
263
+ { code: '[event-code-1]', data: { /* payload */ }, subject: undefined },
264
+ { code: '[event-code-2]', data: { /* payload */ }, subject: undefined },
265
+ ];
266
+
267
+ const results = await Promise.all(
268
+ events.map(({ code, data, subject }) =>
269
+ publisher.execute(params.PROVIDER_ID, code, data, undefined, subject)
270
+ )
271
+ );
272
+
273
+ // Collect failures — execute() never throws, so all results are always returned
274
+ const failed = results.filter(r => r.status === 'failed');
275
+ const published = results.filter(r => r.status === 'published');
276
+
277
+ if (failed.length > 0) {
278
+ logger.error({
279
+ message: '[action-name]-publish-partial-failure',
280
+ failures: failed.map(r => r.error),
281
+ });
282
+ }
283
+
284
+ logger.info({
285
+ message: '[action-name]-published',
286
+ publishedCount: published.length,
287
+ failedCount: failed.length,
288
+ });
289
+ ```
290
+
291
+ #### With Custom Event ID and Subject
292
+
293
+ ```javascript
294
+ const result = await publisher.execute(
295
+ params.PROVIDER_ID,
296
+ '[event-code]',
297
+ { /* payload */ },
298
+ params.correlationId, // use existing correlation ID as event ID
299
+ `[resource-type]/${params.id}` // subject for routing — e.g. 'orders/123'
300
+ );
301
+ ```
302
+
303
+ ### Step 4.2: Update Action Configuration
304
+
305
+ Add `include-ims-credentials: true` and required inputs to the action's configuration.
306
+
307
+ **In `app.config.yaml`, `ext.config.yaml`, or `actions.config.yaml`:**
308
+
309
+ ```yaml
310
+ [action-name]:
311
+ function: [action-path]/index.[js/ts]
312
+ web: 'yes' # or 'no' for event consumers
313
+ runtime: nodejs:22
314
+ annotations:
315
+ require-adobe-auth: [true/false]
316
+ final: true
317
+ include-ims-credentials: true # REQUIRED: injects IMS credentials for token generation
318
+ inputs:
319
+ LOG_LEVEL: debug
320
+ # Adobe I/O Events — PublishEvent credentials
321
+ IMS_ORG_ID: $IMS_ORG_ID
322
+ API_KEY: $API_KEY
323
+ PROVIDER_ID: $PROVIDER_ID
324
+ ```
325
+
326
+ > **Why `include-ims-credentials: true`?** This annotation tells Adobe App Builder to inject the IMS credential set into `params` at runtime. `Core.AuthClient.generateAccessToken(params)` reads from these injected fields to obtain a fresh access token per activation. Without this annotation, `generateAccessToken` will fail.
327
+
328
+ ### Step 4.3: Add Environment Variables
329
+
330
+ Update the project root `.env` file with credential placeholders:
331
+
332
+ 1. **Check for `.env`**: Look in the project root directory
333
+ 2. **Create if missing**: Create `.env` in project root if it doesn't exist
334
+ 3. **Add only missing variables**: Do not overwrite values already present
335
+
336
+ ```bash
337
+ # Adobe I/O Events — PublishEvent credentials
338
+ IMS_ORG_ID=your-org@AdobeOrg
339
+ API_KEY=
340
+ PROVIDER_ID=
341
+ ```
342
+
343
+ **How to get credentials:**
344
+ 1. Log in to [Adobe Developer Console](https://developer.adobe.com/console)
345
+ 2. Select your App Builder project
346
+ 3. **`IMS_ORG_ID`**: Organization → click your org name, copy the Org ID
347
+ 4. **`API_KEY`**: Credentials section → copy the Client ID
348
+ 5. **`PROVIDER_ID`**: I/O Events section → Event Providers → copy the provider ID
349
+
350
+ **Security Notes:**
351
+ - Never commit `.env` to version control — confirm `.env` is in `.gitignore`
352
+ - `IMS_ORG_ID` and `API_KEY` are not secrets themselves but `API_KEY` combined with an access token grants API access — treat them accordingly
353
+ - Access tokens are generated fresh per activation — no token storage required
354
+
355
+ ---
356
+
357
+ ## Step 5: Recommendations
358
+
359
+ ### A. Error Handling Strategy
360
+
361
+ `execute()` **never throws** — it always returns a `PublishEventResult`. Choose your error handling based on business requirements:
362
+
363
+ ```javascript
364
+ // Option 1: Hard fail — event publishing is critical
365
+ if (result.status === 'failed') {
366
+ return RuntimeActionResponse.error(HttpStatus.INTERNAL_ERROR, `Event publish failed: ${result.error}`);
367
+ }
368
+
369
+ // Option 2: Soft fail — log and continue, event publishing is best-effort
370
+ if (result.status === 'failed') {
371
+ logger.warn({ message: 'publish-skipped', error: result.error });
372
+ // continue processing
373
+ }
374
+
375
+ // Option 3: Fan-out partial failure — succeed if at least some events published
376
+ const failed = results.filter(r => r.status === 'failed');
377
+ if (failed.length === results.length) {
378
+ return RuntimeActionResponse.error(HttpStatus.INTERNAL_ERROR, 'All event publishes failed');
379
+ }
380
+ ```
381
+
382
+ ### B. Constructor Throws vs execute() Does Not
383
+
384
+ | Operation | Throws? | Action |
385
+ |---|---|---|
386
+ | `new PublishEvent(...)` | **Yes** — if any credential is blank | Wrap in try/catch, or ensure env vars are set |
387
+ | `publisher.execute(...)` | **Never** — always returns `PublishEventResult` | Always check `result.status` |
388
+
389
+ Since credentials come from `params` (action inputs), a blank credential will cause the constructor to throw inside your handler. `RuntimeAction`/`EventConsumerAction` catch all unhandled throws and return `500 'server error'` — but a more informative pattern is to check credentials before constructing:
390
+
391
+ ```javascript
392
+ if (!params.IMS_ORG_ID || !params.API_KEY || !accessToken) {
393
+ logger.error({ message: '[action-name]-missing-credentials' });
394
+ return RuntimeActionResponse.error(HttpStatus.INTERNAL_ERROR, 'Missing event publishing credentials');
395
+ }
396
+ const publisher = new PublishEvent(params.IMS_ORG_ID, params.API_KEY, accessToken, logger);
397
+ ```
398
+
399
+ ### C. Testing & Verification
400
+
401
+ 1. **Unit tests**: Mock `Core.AuthClient.generateAccessToken` and `PublishEvent` — verify result handling
402
+ 2. **Integration tests**: Use a real I/O Events provider in a dev environment — confirm events appear in your consumer
403
+ 3. **Local**: `aio app dev` + `aio app logs` — check for `publish-failed` log entries
404
+ 4. **Adobe Developer Console**: I/O Events Debug Tracing shows published events in real time
405
+
406
+ ---
407
+
408
+ ## Key Components from @adobe-commerce/aio-toolkit
409
+
410
+ ### PublishEvent Constructor
411
+
412
+ ```typescript
413
+ new PublishEvent(
414
+ imsOrgId: string, // Adobe IMS Org ID — throws if blank
415
+ apiKey: string, // Adobe API Key (Client ID) — throws if blank
416
+ accessToken: string, // IMS access token — throws if blank
417
+ logger?: any // optional: enables publisher-level logging
418
+ )
419
+ ```
420
+
421
+ **Source for credentials:** `params.IMS_ORG_ID`, `params.API_KEY`, and a fresh token from `Core.AuthClient.generateAccessToken(params)`.
422
+
423
+ ### publishEvent.execute()
424
+
425
+ ```typescript
426
+ async execute(
427
+ providerId: string, // required: target I/O Events provider
428
+ eventCode: string, // required: CloudEvent type (e.g. 'com.myapp.order.created')
429
+ payload: any, // required: event data — cannot be null/undefined
430
+ eventId?: string, // optional: custom ID, auto-generates UUID v4 if omitted
431
+ subject?: string // optional: routing/filtering hint — omitted if falsy
432
+ ): Promise<PublishEventResult>
433
+ ```
434
+
435
+ **Always resolves — never rejects.** All internal errors (blank providerId/eventCode, null payload, SDK init failure, publish failure) are caught and returned as `{ status: 'failed', error: '...' }`.
436
+
437
+ ### PublishEventResult
438
+
439
+ ```typescript
440
+ interface PublishEventResult {
441
+ eventId: string; // event ID assigned on success; new UUID on failure
442
+ status: 'published' | 'failed'; // always check this field
443
+ publishedAt: string; // ISO 8601 UTC timestamp
444
+ error?: string; // present only when status === 'failed'
445
+ }
446
+ ```
447
+
448
+ ### CloudEvent Structure (built automatically)
449
+
450
+ | Field | Value |
451
+ |---|---|
452
+ | `id` | `eventId` or auto-generated UUID v4 |
453
+ | `source` | `` `urn:uuid:${providerId}` `` |
454
+ | `type` | `eventCode` |
455
+ | `datacontenttype` | `'application/json'` (fixed) |
456
+ | `data` | `payload` |
457
+ | `subject` | `subject` argument — omitted if falsy |
458
+
459
+ ---
460
+
461
+ ## Important Notes
462
+
463
+ 1. **Constructor throws, execute() does not**: Validate credentials before constructing, handle `result.status` after executing
464
+ 2. **`include-ims-credentials: true` is mandatory when using `Core.AuthClient`**: Without it, `Core.AuthClient.generateAccessToken(params)` returns nothing and `accessToken` will be blank, causing the constructor to throw
465
+ 3. **Alternative: `AdobeAuth.getToken()` for explicit S2S credentials**: If the action uses a dedicated Events technical account with explicit credentials (rather than the App Builder runtime's own injected credentials), use `AdobeAuth.getToken(params.IMS_CLIENT_ID, ..., ['AdobeID', 'openid', 'adobeio_api', 'event_receiver_api'])` instead of `Core.AuthClient`. No `include-ims-credentials: true` needed in this case — add IMS credential inputs to YAML instead. See "Using AdobeAuth" rule for details.
466
+ 4. **Token is generated fresh per activation**: No caching needed — each action invocation generates its own access token
467
+ 4. **Fan-out with `Promise.all()`**: Multiple `execute()` calls are independent — one failure does not cancel others
468
+ 5. **Subject is optional but useful**: Include it for downstream consumers that filter or route by subject
469
+ 6. **No custom event ID needed in most cases**: Auto-generated UUID v4 is fine unless you need correlation with an existing ID
470
+ 7. **Works with any action type**: RuntimeAction, WebhookAction, EventConsumerAction, GraphQlAction, OpenwhiskAction
471
+ 8. **Credentials from `params`**: Always inject `IMS_ORG_ID`, `API_KEY`, `PROVIDER_ID` as action inputs in the YAML config — they are not auto-injected
472
+ 9. **`.env` security**: Never commit credentials; ensure `.env` is in `.gitignore`
473
+ 10. **Peer dependency**: `@adobe/aio-sdk` must be installed in your project — it provides `Core.AuthClient`
474
+
475
+ ## Integration with Action Creation Rules
476
+
477
+ **This rule should be referenced in other action creation rules when event publishing is mentioned:**
478
+
479
+ ### Trigger Patterns in Other Rules
480
+
481
+ When developers mention these phrases during action creation in the "Business Logic" question:
482
+
483
+ - "Publish an event after processing"
484
+ - "Emit a CloudEvent"
485
+ - "Notify via I/O Events"
486
+ - "Fan-out to other consumers"
487
+ - "Send event to Adobe I/O"
488
+ - "Trigger downstream processing via events"
489
+ - Any phrase containing "PublishEvent" or "I/O Events" + "publish"/"emit"/"send"
490
+
491
+ **Action to take:**
492
+
493
+ 1. Complete the action creation first
494
+ 2. Then inform the user: "I see you need to publish events to Adobe I/O Events. Let me help you integrate PublishEvent."
495
+ 3. Trigger/reference the "Using PublishEvent" rule
496
+ 4. This rule handles credentials, config changes, and code integration
497
+
498
+ **Example Flow:**
499
+
500
+ ```
501
+ User: "Create a runtime action that processes orders and publishes an order.created event"
502
+ AI: ✓ Detected TypeScript project
503
+ AI: Creating runtime action... [generates .ts file]
504
+ AI: I see you need to publish events to Adobe I/O Events. Let me integrate PublishEvent.
505
+ AI: [Integrates PublishEvent into the action with token generation, config update, and env vars]
506
+ ```
507
+
508
+ ## Related Rules
509
+
510
+ - **"Using AdobeAuth"** (`aio-toolkit-use-adobe-auth.mdc`) — use when `PublishEvent` needs a token from explicit S2S credentials instead of runtime-injected credentials (`Core.AuthClient`)