@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,442 @@
1
+ ---
2
+ description: Using AdobeAuth to generate IMS bearer tokens in Adobe I/O Runtime actions using @adobe-commerce/aio-toolkit
3
+ globs: '**/{actions,lib}/**/*.{ts,js}'
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Using AdobeAuth
8
+
9
+ ## Trigger Conditions
10
+
11
+ This rule applies when the user needs to generate an IMS bearer token using explicit OAuth Server-to-Server credentials with any of these phrases:
12
+
13
+ - "Get IMS token"
14
+ - "Generate IMS bearer token"
15
+ - "Use AdobeAuth"
16
+ - "OAuth S2S authentication"
17
+ - "S2S token for [service]"
18
+ - "Technical account credentials"
19
+ - "Service account token"
20
+ - "IMS credentials for [action-name]"
21
+ - "Authenticate with Adobe IMS"
22
+ - "Generate access token for Commerce / PublishEvent / API Gateway"
23
+ - "AdobeAuth.getToken"
24
+
25
+ **Important**: This rule integrates `AdobeAuth` into an existing action. It does NOT create new actions.
26
+
27
+ **When to use `AdobeAuth` vs `Core.AuthClient`**:
28
+
29
+ | Scenario | Use |
30
+ |---|---|
31
+ | Action already has `include-ims-credentials: true` and only needs its own App Builder token | `Core.AuthClient.generateAccessToken(params)` — simpler, no extra env vars |
32
+ | Action needs a token from **separate, explicitly stored** S2S credentials (dedicated technical account per integration) | `AdobeAuth.getToken()` — reads credentials from `params` env vars |
33
+ | Multiple actions share a single dedicated technical account | `AdobeAuth.getToken()` — credentials stored once in `.env`, injected via `inputs` |
34
+ | Calling `ImsConnection` for `AdobeCommerceClient` with a dedicated Commerce technical account | `AdobeAuth.getToken()` |
35
+ | Calling `PublishEvent` with a dedicated Events technical account | `AdobeAuth.getToken()` |
36
+ | Calling `RuntimeApiGatewayService` with a shared org-level account | `AdobeAuth.getToken()` |
37
+
38
+ **Integration with Other Rules:**
39
+
40
+ When using action creation rules (RuntimeAction, WebhookAction, EventConsumerAction, GraphQlAction, OpenwhiskAction) and the developer mentions needing S2S authentication or explicit IMS credentials:
41
+
42
+ - **Automatically trigger this rule** after the action is created
43
+ - This rule handles credential injection, scope selection, error handling, and caching guidance
44
+
45
+ ---
46
+
47
+ ## Step 1: Confirm Prerequisites
48
+
49
+ Before generating code, confirm:
50
+
51
+ 1. **`@adobe-commerce/aio-toolkit` installed**: Check `package.json` — `AdobeAuth` is exported from it
52
+ - If NOT installed: `npm install @adobe-commerce/aio-toolkit`
53
+
54
+ 2. **Credentials available**: The user must have an **OAuth Server-to-Server** credential in Adobe Developer Console with the required scopes already granted
55
+ - Scopes are configured when the credential is created — `AdobeAuth.getToken()` cannot request scopes that were not granted
56
+
57
+ ---
58
+
59
+ ## Step 2: Ask Clarifying Questions
60
+
61
+ Ask the following before generating any code:
62
+
63
+ 1. **What consumes the token?**
64
+ - [ ] `ImsConnection` for `AdobeCommerceClient`
65
+ - [ ] `PublishEvent` for Adobe I/O Events
66
+ - [ ] `RuntimeApiGatewayService` for web action calls
67
+ - [ ] A custom Adobe API call (specify which)
68
+
69
+ 2. **Do you already have separate IMS credentials (Client ID, Client Secret, Technical Account ID/Email, IMS Org ID)?**
70
+ - If NO: suggest using `Core.AuthClient.generateAccessToken(params)` with `include-ims-credentials: true` instead (no extra credentials needed)
71
+ - If YES: proceed with `AdobeAuth.getToken()`
72
+
73
+ 3. **Which OAuth scopes are needed?** (see scope reference below — suggest based on the consumer)
74
+ - `ImsConnection` / Commerce → `['AdobeID', 'openid', 'adobeio_api']`
75
+ - `PublishEvent` → `['AdobeID', 'openid', 'adobeio_api', 'event_receiver_api']`
76
+ - `RuntimeApiGatewayService` → `['openid', 'AdobeID', 'adobeio_api']`
77
+
78
+ 4. **High-frequency action?** If the action is invoked frequently (>10x/min), recommend caching the token using AIO State — `AdobeAuth.getToken()` makes a live IMS network call every invocation.
79
+
80
+ 5. **Which action file(s) should `AdobeAuth` be added to?** (if not already clear from context)
81
+
82
+ ---
83
+
84
+ ## Step 3: Confirm Plan
85
+
86
+ Before writing code, confirm the implementation plan:
87
+
88
+ ```
89
+ I'll make the following changes:
90
+
91
+ 1. Action file ([path/to/action/index.ts|js]):
92
+ - Import AdobeAuth from @adobe-commerce/aio-toolkit
93
+ - Add AdobeAuth.getToken() call [with try/catch for error handling]
94
+ - [Pass token to: ImsConnection / PublishEvent / RuntimeApiGatewayService / custom]
95
+ [If caching: Import BearerToken and add TTL-based cache check]
96
+
97
+ 2. app.config.yaml (or ext.config.yaml / actions.config.yaml):
98
+ - Add IMS credential inputs: IMS_CLIENT_ID, IMS_CLIENT_SECRET,
99
+ IMS_TECHNICAL_ACCOUNT_ID, IMS_TECHNICAL_ACCOUNT_EMAIL, IMS_ORG_ID
100
+
101
+ 3. .env:
102
+ - Add IMS_CLIENT_ID, IMS_CLIENT_SECRET, IMS_TECHNICAL_ACCOUNT_ID,
103
+ IMS_TECHNICAL_ACCOUNT_EMAIL, IMS_ORG_ID
104
+
105
+ Scopes to request: [list based on consumer]
106
+
107
+ Shall I proceed?
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Step 4: Generate Code
113
+
114
+ ### Step 4.1: Action Code
115
+
116
+ Detect language (TypeScript or JavaScript) by checking the action file extension or `tsconfig.json`. Generate in the detected language.
117
+
118
+ #### A. Basic usage — with error handling (recommended)
119
+
120
+ ```javascript
121
+ const {
122
+ AdobeAuth,
123
+ // ... other imports
124
+ } = require('@adobe-commerce/aio-toolkit');
125
+
126
+ // Inside your action handler (params, ctx):
127
+ const { logger, telemetry } = ctx;
128
+
129
+ let imsToken;
130
+
131
+ try {
132
+ imsToken = await AdobeAuth.getToken(
133
+ params.IMS_CLIENT_ID,
134
+ params.IMS_CLIENT_SECRET,
135
+ params.IMS_TECHNICAL_ACCOUNT_ID,
136
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
137
+ params.IMS_ORG_ID,
138
+ ['AdobeID', 'openid', 'adobeio_api'] // adjust scopes to your integration
139
+ );
140
+ } catch (error) {
141
+ logger.error({
142
+ message: '[action-name]-ims-token-failed',
143
+ ...telemetry.formatError(error),
144
+ });
145
+ return RuntimeActionResponse.error(401, 'Failed to generate IMS token');
146
+ }
147
+
148
+ // Pass imsToken to your consumer:
149
+ // const connection = new ImsConnection(imsToken, logger);
150
+ // const publisher = new PublishEvent(params.IMS_ORG_ID, params.API_KEY, imsToken, logger);
151
+ // const service = new RuntimeApiGatewayService(params.NAMESPACE, params.IMS_ORG_ID, imsToken, logger);
152
+ ```
153
+
154
+ **TypeScript imports:**
155
+
156
+ ```typescript
157
+ import { AdobeAuth } from '@adobe-commerce/aio-toolkit';
158
+ ```
159
+
160
+ #### B. With ImsConnection for AdobeCommerceClient
161
+
162
+ ```javascript
163
+ const {
164
+ AdobeAuth,
165
+ AdobeCommerceClient,
166
+ ImsConnection,
167
+ } = require('@adobe-commerce/aio-toolkit');
168
+
169
+ let imsToken;
170
+
171
+ try {
172
+ imsToken = await AdobeAuth.getToken(
173
+ params.IMS_CLIENT_ID,
174
+ params.IMS_CLIENT_SECRET,
175
+ params.IMS_TECHNICAL_ACCOUNT_ID,
176
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
177
+ params.IMS_ORG_ID,
178
+ ['AdobeID', 'openid', 'adobeio_api']
179
+ );
180
+ } catch (error) {
181
+ logger.error({ message: '[action-name]-ims-token-failed', ...telemetry.formatError(error) });
182
+ return RuntimeActionResponse.error(401, 'Failed to generate IMS token');
183
+ }
184
+
185
+ const client = new AdobeCommerceClient(
186
+ params.COMMERCE_BASE_URL,
187
+ new ImsConnection(imsToken, logger),
188
+ logger
189
+ );
190
+ ```
191
+
192
+ #### C. With PublishEvent for Adobe I/O Events
193
+
194
+ ```javascript
195
+ const {
196
+ AdobeAuth,
197
+ PublishEvent,
198
+ } = require('@adobe-commerce/aio-toolkit');
199
+
200
+ let imsToken;
201
+
202
+ try {
203
+ imsToken = await AdobeAuth.getToken(
204
+ params.IMS_CLIENT_ID,
205
+ params.IMS_CLIENT_SECRET,
206
+ params.IMS_TECHNICAL_ACCOUNT_ID,
207
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
208
+ params.IMS_ORG_ID,
209
+ ['AdobeID', 'openid', 'adobeio_api', 'event_receiver_api']
210
+ );
211
+ } catch (error) {
212
+ logger.error({ message: '[action-name]-ims-token-failed', ...telemetry.formatError(error) });
213
+ return RuntimeActionResponse.error(401, 'Failed to generate IMS token');
214
+ }
215
+
216
+ const publisher = new PublishEvent(
217
+ params.IMS_ORG_ID,
218
+ params.API_KEY,
219
+ imsToken,
220
+ logger
221
+ );
222
+ ```
223
+
224
+ #### D. With token caching (high-frequency actions)
225
+
226
+ Use this pattern when the action is invoked frequently and you want to avoid a live IMS call every invocation. Cache the token in Adobe I/O State with a TTL matching the token's expiry.
227
+
228
+ ```javascript
229
+ const {
230
+ AdobeAuth,
231
+ BearerToken,
232
+ } = require('@adobe-commerce/aio-toolkit');
233
+ const { Files, State } = require('@adobe/aio-sdk');
234
+
235
+ // Module-level cache (valid for container lifetime only — not reliable across invocations)
236
+ let cachedToken = null;
237
+
238
+ // Inside your action handler:
239
+ let imsToken;
240
+
241
+ // Check in-memory cache first (fast path for warm containers)
242
+ if (cachedToken && BearerToken.info(cachedToken).isValid) {
243
+ imsToken = cachedToken;
244
+ } else {
245
+ // Fall back to AIO State for cross-invocation persistence
246
+ const state = await State.init();
247
+ const cached = await state.get('ims-token');
248
+
249
+ if (cached && BearerToken.info(cached.value).isValid) {
250
+ imsToken = cached.value;
251
+ cachedToken = imsToken;
252
+ } else {
253
+ try {
254
+ imsToken = await AdobeAuth.getToken(
255
+ params.IMS_CLIENT_ID,
256
+ params.IMS_CLIENT_SECRET,
257
+ params.IMS_TECHNICAL_ACCOUNT_ID,
258
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
259
+ params.IMS_ORG_ID,
260
+ ['AdobeID', 'openid', 'adobeio_api']
261
+ );
262
+ } catch (error) {
263
+ logger.error({ message: '[action-name]-ims-token-failed', ...telemetry.formatError(error) });
264
+ return RuntimeActionResponse.error(401, 'Failed to generate IMS token');
265
+ }
266
+
267
+ const { timeUntilExpiry } = BearerToken.info(imsToken);
268
+ const ttl = timeUntilExpiry ? Math.floor(timeUntilExpiry / 1000) - 60 : 3000; // 60s safety margin
269
+
270
+ await state.put('ims-token', imsToken, { ttl });
271
+ cachedToken = imsToken;
272
+ }
273
+ }
274
+ ```
275
+
276
+ > **Caching note:** `AdobeAuth.getToken()` makes a **live IMS network call every invocation** — it has no built-in caching. If your action is called frequently, use the pattern above or implement your own TTL-based cache using Adobe I/O State.
277
+
278
+ ---
279
+
280
+ ### Step 4.2: Update Action Configuration
281
+
282
+ Add IMS credential inputs to the action's YAML configuration:
283
+
284
+ **In `app.config.yaml`, `ext.config.yaml`, or `actions.config.yaml`:**
285
+
286
+ ```yaml
287
+ [action-name]:
288
+ function: actions/[action-name]/index.js
289
+ web: 'yes'
290
+ runtime: nodejs:22
291
+ inputs:
292
+ LOG_LEVEL: debug
293
+ # IMS S2S credentials
294
+ IMS_CLIENT_ID: $IMS_CLIENT_ID
295
+ IMS_CLIENT_SECRET: $IMS_CLIENT_SECRET
296
+ IMS_TECHNICAL_ACCOUNT_ID: $IMS_TECHNICAL_ACCOUNT_ID
297
+ IMS_TECHNICAL_ACCOUNT_EMAIL: $IMS_TECHNICAL_ACCOUNT_EMAIL
298
+ IMS_ORG_ID: $IMS_ORG_ID
299
+ annotations:
300
+ require-adobe-auth: true
301
+ final: true
302
+ ```
303
+
304
+ > **Note:** `include-ims-credentials: true` is **NOT required** when using `AdobeAuth.getToken()`. That annotation is only needed for `Core.AuthClient.generateAccessToken(params)`. `AdobeAuth` reads credentials from the standard `inputs` you define above.
305
+
306
+ ---
307
+
308
+ ### Step 4.3: Add Environment Variables
309
+
310
+ Add to the project's `.env` file:
311
+
312
+ ```bash
313
+ # IMS OAuth S2S credentials — from Adobe Developer Console → OAuth Server-to-Server
314
+ IMS_CLIENT_ID=your-client-id
315
+ IMS_CLIENT_SECRET=your-client-secret
316
+ IMS_TECHNICAL_ACCOUNT_ID=XXXXXXXXXXXXXXXX@techacct.adobe.com
317
+ IMS_TECHNICAL_ACCOUNT_EMAIL=techacct@your-org.adobe.com
318
+ IMS_ORG_ID=XXXXXXXXXXXXXXXX@AdobeOrg
319
+ ```
320
+
321
+ **Where to find credentials:**
322
+ 1. Open [Adobe Developer Console](https://developer.adobe.com/console)
323
+ 2. Select your **Project** → **Workspace** (e.g. Production, Stage)
324
+ 3. Go to **OAuth Server-to-Server** under the credentials section
325
+ 4. Copy: **Client ID**, **Client Secret**, **Technical Account ID**, **Technical Account Email**, **IMS Org ID**
326
+ 5. Verify the listed **Scopes** include everything you intend to request
327
+
328
+ ---
329
+
330
+ ## OAuth Scopes Reference
331
+
332
+ Request only the scopes your integration actually needs. Scopes must be a subset of those granted to the credential in Adobe Developer Console.
333
+
334
+ | Scope | Purpose |
335
+ |---|---|
336
+ | `AdobeID` | Basic Adobe identity — required for most integrations |
337
+ | `openid` | OpenID Connect identity token |
338
+ | `adobeio_api` | Access to Adobe I/O APIs |
339
+ | `event_receiver_api` | Publish and consume Adobe I/O Events (required for `PublishEvent`) |
340
+ | `adobeio.appregistry.read` | Read App Registry entries |
341
+ | `read_organizations` | Read IMS organization details |
342
+ | `additional_info.projectedProductContext` | Access product context in the token |
343
+
344
+ **Recommended scopes by consumer:**
345
+
346
+ | Consumer | Minimum recommended scopes |
347
+ |---|---|
348
+ | `ImsConnection` (AdobeCommerceClient) | `['AdobeID', 'openid', 'adobeio_api']` |
349
+ | `PublishEvent` | `['AdobeID', 'openid', 'adobeio_api', 'event_receiver_api']` |
350
+ | `RuntimeApiGatewayService` | `['openid', 'AdobeID', 'adobeio_api']` |
351
+ | Custom Adobe I/O API | `['AdobeID', 'openid', 'adobeio_api']` + any API-specific scope |
352
+
353
+ ---
354
+
355
+ ## Key Components
356
+
357
+ ### `AdobeAuth.getToken()` — generate IMS token
358
+
359
+ ```typescript
360
+ static async getToken(
361
+ clientId: string, // OAuth S2S Client ID
362
+ clientSecret: string, // OAuth S2S Client Secret
363
+ technicalAccountId: string, // Technical Account ID (XXXXXXXX@techacct.adobe.com)
364
+ technicalAccountEmail: string, // Technical Account Email
365
+ imsOrgId: string, // IMS Org ID (XXXXXXXX@AdobeOrg)
366
+ scopes: string[], // OAuth scopes — must be granted to the credential
367
+ currentContext?: string // optional, default: 'onboarding-config'
368
+ ): Promise<string> // returns raw IMS access token string
369
+ ```
370
+
371
+ - **Throws** on invalid credentials, network failure, or unauthorized scopes — always wrap in `try/catch`
372
+ - **No caching** — makes a live IMS network call every invocation
373
+ - `currentContext` only needs to be overridden when managing multiple concurrent IMS contexts in the same process
374
+
375
+ ### `BearerToken.info()` — inspect token validity (for caching)
376
+
377
+ ```typescript
378
+ const { isValid, timeUntilExpiry } = BearerToken.info(token);
379
+ // isValid: boolean — false if expired or invalid
380
+ // timeUntilExpiry: number (ms) — time until expiry; 0 or undefined if expired
381
+ ```
382
+
383
+ ### Exports
384
+
385
+ ```javascript
386
+ const { AdobeAuth, BearerToken } = require('@adobe-commerce/aio-toolkit');
387
+
388
+ // TypeScript only
389
+ import type { AdobeIMSConfig } from '@adobe-commerce/aio-toolkit';
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Important Notes
395
+
396
+ 1. **`AdobeAuth.getToken()` throws — always use try/catch**: Invalid credentials, network failures, and unauthorized scopes all propagate directly. Return a clean error response rather than letting the action crash.
397
+ 2. **No built-in caching**: Every call makes a live round-trip to Adobe IMS. For high-frequency actions, implement TTL-based caching using AIO State + `BearerToken.info()`.
398
+ 3. **`include-ims-credentials: true` is NOT needed**: That annotation is for `Core.AuthClient.generateAccessToken(params)` only. `AdobeAuth` reads from standard `inputs` you define in YAML.
399
+ 4. **Scopes must be pre-granted**: You cannot request scopes at runtime that were not granted when the OAuth S2S credential was created in Adobe Developer Console.
400
+ 5. **`currentContext` param**: Only override the default `'onboarding-config'` context if you need to manage multiple concurrent IMS contexts in the same process (rare).
401
+ 6. **One token per consumer**: If an action uses both `ImsConnection` and `PublishEvent`, you may use the same token if the scopes cover both — or generate separate tokens if the credentials differ.
402
+ 7. **Credential security**: Never commit `.env` to version control — confirm `.env` is in `.gitignore`. `IMS_CLIENT_SECRET` is a secret and must be treated accordingly.
403
+ 8. **Works with any action type**: RuntimeAction, WebhookAction, EventConsumerAction, GraphQlAction, OpenwhiskAction.
404
+
405
+ ---
406
+
407
+ ## Related Rules
408
+
409
+ - **"Creating Adobe Commerce Client Operations"** (`aio-toolkit-create-adobe-commerce-client.mdc`) — uses `AdobeAuth.getToken()` to obtain a token for `ImsConnection`
410
+ - **"Using PublishEvent"** (`aio-toolkit-use-publish-event.mdc`) — uses `Core.AuthClient` by default; use `AdobeAuth.getToken()` instead when publishing with explicit S2S credentials
411
+ - **"Using RuntimeApiGatewayService"** (`aio-toolkit-use-runtime-api-gateway-service.mdc`) — uses `AdobeAuth.getToken()` as the primary token source for API Gateway calls
412
+
413
+ ## Integration with Action Creation Rules
414
+
415
+ **This rule should be triggered when developers mention needing IMS token generation with explicit S2S credentials:**
416
+
417
+ ### Trigger Patterns in Other Rules
418
+
419
+ When developers mention these phrases during action creation:
420
+
421
+ - "Generate an IMS token"
422
+ - "Authenticate with Adobe IMS"
423
+ - "Need an IMS bearer token for [service]"
424
+ - "Use my technical account credentials"
425
+ - "OAuth S2S token"
426
+ - Any phrase containing "AdobeAuth" or "IMS token" + "S2S"/"technical account"/"credentials"
427
+
428
+ **Action to take:**
429
+
430
+ 1. Determine if `Core.AuthClient.generateAccessToken(params)` covers the use case first
431
+ 2. If the user has explicit S2S credentials or needs a dedicated technical account: apply this rule
432
+ 3. This rule handles credential injection, scope selection, error handling, caching, and config wiring
433
+
434
+ **Example Flow:**
435
+
436
+ ```
437
+ User: "Create a runtime action that fetches products from Commerce using our technical account"
438
+ AI: ✓ Detected TypeScript project
439
+ AI: Creating runtime action... [generates .ts file]
440
+ AI: I see you need IMS token generation with explicit S2S credentials. Let me integrate AdobeAuth.
441
+ AI: [Adds AdobeAuth.getToken(), ImsConnection, config inputs, and .env entries]
442
+ ```