@adobe-commerce/aio-toolkit 1.2.5 → 1.2.7
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.
- package/CHANGELOG.md +250 -0
- package/README.md +450 -1
- package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
- package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
- package/dist/index.d.mts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +600 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +610 -38
- package/dist/index.mjs.map +1 -1
- package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
- package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
- package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
- package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
- package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
- package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
- package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
- package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
- package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
- package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
- package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
- package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
- package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
- package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
- package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
- package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
- package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
- package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
- package/package.json +4 -2
|
@@ -70,7 +70,7 @@ class OrderProcessor {
|
|
|
70
70
|
**Keep implementation details private:**
|
|
71
71
|
|
|
72
72
|
```javascript
|
|
73
|
-
// JavaScript
|
|
73
|
+
// JavaScript
|
|
74
74
|
class UserManager {
|
|
75
75
|
#apiKey; // Private field
|
|
76
76
|
|
|
@@ -197,7 +197,13 @@ class GetUserResolver {
|
|
|
197
197
|
|
|
198
198
|
async execute() {
|
|
199
199
|
return async (args) => {
|
|
200
|
-
|
|
200
|
+
// args = GraphQL field arguments (e.g. { id } from getUser(id: ID!))
|
|
201
|
+
const { logger, headers, telemetry, params } = this.ctx;
|
|
202
|
+
// logger - structured logger with auto-correlation
|
|
203
|
+
// headers - incoming HTTP request headers
|
|
204
|
+
// telemetry - OpenTelemetry helper for custom spans
|
|
205
|
+
// params - full OpenWhisk params (query, variables, operationName, action inputs)
|
|
206
|
+
|
|
201
207
|
logger.info({ message: 'getUser-execution', args });
|
|
202
208
|
|
|
203
209
|
try {
|
|
@@ -205,7 +211,7 @@ class GetUserResolver {
|
|
|
205
211
|
return result;
|
|
206
212
|
} catch (error) {
|
|
207
213
|
logger.error({ message: 'getUser-error', error: error.message });
|
|
208
|
-
throw error;
|
|
214
|
+
throw error; // GraphQL returns this as a field error (HTTP 200 with errors[])
|
|
209
215
|
}
|
|
210
216
|
};
|
|
211
217
|
}
|
|
@@ -308,7 +314,7 @@ class HelloWorld {
|
|
|
308
314
|
|
|
309
315
|
async execute() {
|
|
310
316
|
return async (args) => {
|
|
311
|
-
const { logger } = this.ctx;
|
|
317
|
+
const { logger, headers, telemetry, params } = this.ctx;
|
|
312
318
|
// Implementation
|
|
313
319
|
};
|
|
314
320
|
}
|
|
@@ -8,7 +8,7 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
## Trigger Conditions
|
|
10
10
|
|
|
11
|
-
This rule applies when the user requests to add New Relic telemetry to their actions using any of these phrases:
|
|
11
|
+
This rule applies when the user requests to add New Relic telemetry, use structured logging, or add custom spans to their actions using any of these phrases:
|
|
12
12
|
|
|
13
13
|
- "Add New Relic telemetry"
|
|
14
14
|
- "Enable New Relic monitoring"
|
|
@@ -18,6 +18,16 @@ This rule applies when the user requests to add New Relic telemetry to their act
|
|
|
18
18
|
- "Enable observability with New Relic"
|
|
19
19
|
- "Setup New Relic OTLP"
|
|
20
20
|
- "Add telemetry monitoring"
|
|
21
|
+
- "How to use ctx.logger"
|
|
22
|
+
- "Structured logging in my action"
|
|
23
|
+
- "Log object fields as separate attributes"
|
|
24
|
+
- "Add custom spans"
|
|
25
|
+
- "Instrument a function with telemetry"
|
|
26
|
+
- "Use ctx.telemetry"
|
|
27
|
+
- "Add spans to my action"
|
|
28
|
+
- "How to use formatError"
|
|
29
|
+
- "Structured error logging"
|
|
30
|
+
- "How does ctx.logger work"
|
|
21
31
|
|
|
22
32
|
### Supported Action Types
|
|
23
33
|
|
|
@@ -42,7 +52,150 @@ The `@adobe-commerce/aio-toolkit` library includes built-in New Relic telemetry
|
|
|
42
52
|
5. **Tags data** - Adds environment, service name, and custom resource attributes
|
|
43
53
|
6. **Detects success/failure** - Automatically detects action outcomes
|
|
44
54
|
|
|
45
|
-
**No code changes required** - Telemetry is configured entirely through action inputs and environment variables.
|
|
55
|
+
**No code changes required for New Relic setup** - Telemetry is configured entirely through action inputs and environment variables. However, `ctx.logger` and `ctx.telemetry` are available in every action handler and benefit from intentional usage patterns described below.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Using `ctx.logger`
|
|
60
|
+
|
|
61
|
+
`ctx.logger` is injected automatically into every action handler. It is available in all action types regardless of whether New Relic telemetry is enabled. All log methods accept a plain string or **an object with a `message` key**:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const { logger } = ctx;
|
|
65
|
+
|
|
66
|
+
logger.debug({ message: 'debug-message', key: 'value' });
|
|
67
|
+
logger.info({ message: 'info-message', key: 'value' });
|
|
68
|
+
logger.warn({ message: 'warn-message', key: 'value' });
|
|
69
|
+
logger.error({ message: 'error-message', key: 'value' });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Always log objects, not plain strings
|
|
73
|
+
|
|
74
|
+
When telemetry is enabled, the toolkit's `JsonMessageProcessor` automatically **promotes each key in a logged object to a separate, queryable attribute in New Relic**. Plain string logs are stored as a single `message` attribute only:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
// Preferred — each field becomes a queryable attribute in New Relic
|
|
78
|
+
logger.info({
|
|
79
|
+
message: 'order-created',
|
|
80
|
+
order_id: 'ORD-123',
|
|
81
|
+
customer_id: 'CUST-456',
|
|
82
|
+
total: 99.99,
|
|
83
|
+
});
|
|
84
|
+
// New Relic receives: message, order_id, customer_id, total as separate attributes
|
|
85
|
+
|
|
86
|
+
// Avoid — entire message is a single string, not queryable by field
|
|
87
|
+
logger.info('order created for CUST-456');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Nested objects are flattened to dot-notation
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
logger.debug({
|
|
94
|
+
message: 'ACTION_HEADERS',
|
|
95
|
+
headers: {
|
|
96
|
+
accept: 'application/json',
|
|
97
|
+
authorization: 'Bearer token',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
// New Relic attributes: headers.accept, headers.authorization
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Automatic metadata injection
|
|
104
|
+
|
|
105
|
+
The logger automatically merges contextual metadata into every object log call — you do not need to add these fields yourself:
|
|
106
|
+
|
|
107
|
+
| Metadata key | Source | Description |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `x-adobe-commerce-request-id` | `__ow_headers['x-adobe-commerce-request-id']` | Adobe Commerce request correlation ID |
|
|
110
|
+
| `action.type` | `params.action_type` | Action category set by the framework (e.g. `runtime`, `webhook`, `event-consumer`) |
|
|
111
|
+
|
|
112
|
+
When `ENABLE_TELEMETRY: true` and New Relic is configured, the `ENVIRONMENT` param is attached as a **resource attribute** on every log, trace, and metric automatically.
|
|
113
|
+
|
|
114
|
+
### Log level
|
|
115
|
+
|
|
116
|
+
Controlled by the `LOG_LEVEL` action input. Valid values: `trace`, `debug`, `info`, `warn`, `error`. Defaults to `info` if not set.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Using `ctx.telemetry`
|
|
121
|
+
|
|
122
|
+
`ctx.telemetry` is injected alongside `ctx.logger`. Its span methods are only functional when `ENABLE_TELEMETRY: true`; when disabled, `getCurrentSpan()` always returns `null`. It exposes three methods relevant to action developers.
|
|
123
|
+
|
|
124
|
+
### `instrument(spanName, fn)` — create child spans
|
|
125
|
+
|
|
126
|
+
Wraps any function (sync or async) to produce a **child span** within the current trace context. The instrumented function has the same signature as the original — it must be called to execute:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const { logger, telemetry } = ctx;
|
|
130
|
+
|
|
131
|
+
const fetchOrders = telemetry.instrument(
|
|
132
|
+
'runtime.action.my-action.fetchOrders', // span name as it appears in New Relic
|
|
133
|
+
async (customerId) => {
|
|
134
|
+
const span = telemetry.getCurrentSpan();
|
|
135
|
+
if (span) {
|
|
136
|
+
span.setAttribute('customer.id', customerId);
|
|
137
|
+
span.addEvent('fetch-started');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const orders = await orderService.findByCustomer(customerId);
|
|
141
|
+
|
|
142
|
+
if (span) {
|
|
143
|
+
span.setAttribute('orders.count', orders.length);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return orders;
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// instrument() wraps the function — call it to execute and produce the span
|
|
151
|
+
const orders = await fetchOrders(params.customer_id);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> `instrument()` must be called **inside** an active trace context — i.e., inside the action handler. Calling it outside will produce no span.
|
|
155
|
+
|
|
156
|
+
**Span naming convention**: use `[action-type].action.[action-name].[operation]` — e.g. `runtime.action.order-create.validatePayload`.
|
|
157
|
+
|
|
158
|
+
### `getCurrentSpan()` — attach attributes and events
|
|
159
|
+
|
|
160
|
+
Returns the currently active OpenTelemetry span, or `null` when telemetry is disabled or called outside an active context. **Always guard with `if (span)`**:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
const span = telemetry.getCurrentSpan();
|
|
164
|
+
|
|
165
|
+
if (span) {
|
|
166
|
+
span.setAttribute('order.id', orderId);
|
|
167
|
+
span.setAttribute('order.status', 'processing');
|
|
168
|
+
span.addEvent('validation-passed');
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### `formatError(error)` — structured error logging
|
|
173
|
+
|
|
174
|
+
Converts an `Error` object (or any thrown value) into a structured object safe for logging. Use it inside `catch` blocks to promote error fields to individual New Relic attributes:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
try {
|
|
178
|
+
await processOrder(orderId);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logger.error({
|
|
181
|
+
message: 'order-processing-failed',
|
|
182
|
+
order_id: orderId,
|
|
183
|
+
...telemetry.formatError(error), // spreads error_name, error_message, error_stack
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Returns:**
|
|
189
|
+
|
|
190
|
+
| Key | Value |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `error_name` | `error.name` |
|
|
193
|
+
| `error_message` | `error.message` |
|
|
194
|
+
| `error_stack` | `error.stack` |
|
|
195
|
+
|
|
196
|
+
If the thrown value is not an `Error`, returns `{ error: String(error) }`.
|
|
197
|
+
|
|
198
|
+
---
|
|
46
199
|
|
|
47
200
|
## Step 1: Verify Prerequisites and Existing Configuration
|
|
48
201
|
|
|
@@ -208,6 +361,8 @@ Locate the action under `application.runtimeManifest.packages.[package-name].act
|
|
|
208
361
|
final: true
|
|
209
362
|
```
|
|
210
363
|
|
|
364
|
+
> **Misconfiguration is fatal.** If `NEW_RELIC_TELEMETRY: true` is set but `NEW_RELIC_SERVICE_NAME` or `NEW_RELIC_LICENSE_KEY` is missing or blank, the action returns **HTTP 500 immediately** with a `Telemetry configuration error: ...` message. This is intentional — it prevents silently running without telemetry when you expect it to be active. Always ensure both variables are set in `.env` before deploying with `NEW_RELIC_TELEMETRY: true`.
|
|
365
|
+
|
|
211
366
|
#### Packaged Actions (in `actions/[package]/actions.config.yaml`)
|
|
212
367
|
|
|
213
368
|
For actions defined in separate config files:
|
|
@@ -296,6 +451,16 @@ NEW_RELIC_URL=[custom-endpoint] # Optional: EU only
|
|
|
296
451
|
|
|
297
452
|
**Alerting**: Set up alerts for high error rates, slow execution, failed invocations, or missing telemetry data.
|
|
298
453
|
|
|
454
|
+
**PublishEvent Logger Integration**: When an action uses `PublishEvent` to publish CloudEvents, pass the action's `ctx.logger` to the constructor so publisher-level logs appear in the same New Relic trace:
|
|
455
|
+
```javascript
|
|
456
|
+
const publisher = new PublishEvent(
|
|
457
|
+
params.IMS_ORG_ID,
|
|
458
|
+
params.API_KEY,
|
|
459
|
+
accessToken,
|
|
460
|
+
logger // ← pass ctx.logger here for correlated logs in New Relic
|
|
461
|
+
);
|
|
462
|
+
```
|
|
463
|
+
|
|
299
464
|
**Multiple Environments**: Use different `ENVIRONMENT` values (dev/staging/prod) in separate `.env.{env}` files in project root. Filter New Relic data by environment tag.
|
|
300
465
|
|
|
301
466
|
**CI/CD Integration**: Store `NEW_RELIC_LICENSE_KEY` in CI/CD secrets (GitHub Actions, etc.), set environment-specific values in deployment workflows.
|