@adobe-commerce/aio-toolkit 1.0.14 → 1.0.15
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 +37 -0
- package/README.md +94 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js +1089 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -0
- package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +562 -0
- package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +531 -0
- package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +293 -0
- package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +439 -0
- package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +1321 -0
- package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +331 -0
- package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +354 -0
- package/package.json +6 -1
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# AIO Toolkit: Create Webhook Action
|
|
2
|
+
|
|
3
|
+
**Command Name:** `aio-toolkit-create-webhook-action`
|
|
4
|
+
|
|
5
|
+
**Description:** Creates a webhook action using @adobe-commerce/aio-toolkit with signature verification and API Gateway support
|
|
6
|
+
|
|
7
|
+
## Workflow
|
|
8
|
+
|
|
9
|
+
This command creates a new webhook action with optional signature verification and API Gateway endpoint.
|
|
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: `customer-validation`, `order-webhook`, `product-sync-webhook`
|
|
29
|
+
|
|
30
|
+
2. **Action Location** (auto-detect or ask)
|
|
31
|
+
- Root application (`actions/`)
|
|
32
|
+
- Extension point (`[extension-path]/actions/`)
|
|
33
|
+
|
|
34
|
+
3. **Package Structure**
|
|
35
|
+
- Simple: `actions/[action-name]/index.[js/ts]`
|
|
36
|
+
- Packaged: `actions/[package]/[action-name]/index.[js/ts]`
|
|
37
|
+
- If packaged, ask for package name (e.g., `webhooks`, `customers`, `orders`)
|
|
38
|
+
|
|
39
|
+
4. **Signature Verification** (security feature)
|
|
40
|
+
- **Disabled** - No signature verification (SignatureVerification.DISABLED)
|
|
41
|
+
- **Enabled with PUBLIC_KEY** - Requires PUBLIC_KEY in `.env`
|
|
42
|
+
- **Enabled with PUBLIC_KEY_BASE64** - Requires base64 encoded key in `.env`
|
|
43
|
+
- Note: Signature verification validates webhook requests from Adobe Commerce using HMAC SHA256
|
|
44
|
+
- Reference: [Adobe Commerce Signature Verification](https://developer.adobe.com/commerce/extensibility/webhooks/signature-verification/)
|
|
45
|
+
|
|
46
|
+
5. **Required Parameters** (comma-separated or empty)
|
|
47
|
+
- Example: `orderId, customerId, webhookData`
|
|
48
|
+
|
|
49
|
+
6. **Required Headers** (comma-separated or empty)
|
|
50
|
+
- Example: `Authorization, x-webhook-signature`
|
|
51
|
+
- Note: If `Authorization` included, sets `require-adobe-auth: true`
|
|
52
|
+
|
|
53
|
+
7. **Error Handling**
|
|
54
|
+
- Specific error scenarios to handle
|
|
55
|
+
- Example: Invalid signature, missing data, processing errors
|
|
56
|
+
- Note: WebhookActionResponse.exception() accepts optional message and exception class
|
|
57
|
+
- Default exception class (if not provided): `\\Magento\\Framework\\Exception\\LocalizedException`
|
|
58
|
+
|
|
59
|
+
8. **Business Logic Description**
|
|
60
|
+
- Brief description of what the webhook should do
|
|
61
|
+
|
|
62
|
+
9. **Response Type**
|
|
63
|
+
- **success**: Continue process without changes (most common)
|
|
64
|
+
- **exception**: Terminate process with optional error message and exception class
|
|
65
|
+
- **add**: Add data to event arguments at path (with optional DataObject instance class)
|
|
66
|
+
- **replace**: Replace values in event arguments at path (with optional DataObject instance class)
|
|
67
|
+
- **remove**: Remove data from event arguments at path
|
|
68
|
+
- Note: Response is a 200 OK with JSON object containing the operation details
|
|
69
|
+
|
|
70
|
+
10. **API Gateway Configuration** (optional, recommended)
|
|
71
|
+
- Do you want to create an API Gateway endpoint?
|
|
72
|
+
- If Yes, ask:
|
|
73
|
+
- **Base Path**: Default `v1` (e.g., `v1`, `v2`, `api`)
|
|
74
|
+
- **Relative Path**: e.g., `customers/validation`, `webhooks/order`
|
|
75
|
+
- **HTTP Method**: Default `post` (options: `get`, `post`, `put`, `delete`, `patch`)
|
|
76
|
+
- **Response Type**: Default `http` (options: `http`, `json`, `text`, `html`)
|
|
77
|
+
|
|
78
|
+
### Step 3: Confirm Configuration
|
|
79
|
+
|
|
80
|
+
Display summary:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
📋 Webhook Action Configuration
|
|
84
|
+
|
|
85
|
+
Action Name: [name]
|
|
86
|
+
Language: [JavaScript/TypeScript] (auto-detected)
|
|
87
|
+
Location: [Root/Extension]
|
|
88
|
+
Package: [package-name or simple]
|
|
89
|
+
Signature Verification: [Disabled/Enabled]
|
|
90
|
+
Required Parameters: [params or none]
|
|
91
|
+
Required Headers: [headers or none]
|
|
92
|
+
Authentication: [Yes/No]
|
|
93
|
+
Business Logic: [description]
|
|
94
|
+
Response Operation: [success/exception/add/replace/remove]
|
|
95
|
+
- success: Continue process without changes
|
|
96
|
+
- exception: Terminate process with error
|
|
97
|
+
- add: Add data to event arguments
|
|
98
|
+
- replace: Replace values in event arguments
|
|
99
|
+
- remove: Remove data from event arguments
|
|
100
|
+
|
|
101
|
+
API Gateway: [Yes/No]
|
|
102
|
+
[If Yes]
|
|
103
|
+
Endpoint: [method] /apis/[namespace]/[base-path]/[relative-path]
|
|
104
|
+
Response Type: [http/json/text/html]
|
|
105
|
+
|
|
106
|
+
✅ Files to Create:
|
|
107
|
+
- actions/[path]/index.[js/ts]
|
|
108
|
+
- Update app.config.yaml or ext.config.yaml
|
|
109
|
+
[- actions/[package]/actions.config.yaml if packaged]
|
|
110
|
+
[- actions/[package]/apis.config.yaml if API Gateway]
|
|
111
|
+
[- .env with PUBLIC_KEY if signature verification enabled]
|
|
112
|
+
|
|
113
|
+
Should I proceed?
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Step 4: Generate Webhook Action
|
|
117
|
+
|
|
118
|
+
Create action file with this template:
|
|
119
|
+
|
|
120
|
+
**JavaScript:**
|
|
121
|
+
```javascript
|
|
122
|
+
const {
|
|
123
|
+
WebhookAction,
|
|
124
|
+
WebhookActionResponse,
|
|
125
|
+
SignatureVerification,
|
|
126
|
+
} = require('@adobe-commerce/aio-toolkit');
|
|
127
|
+
const name = '[action-name]';
|
|
128
|
+
|
|
129
|
+
exports.main = WebhookAction.execute(
|
|
130
|
+
name,
|
|
131
|
+
[/* 'param1', 'param2' */],
|
|
132
|
+
[/* 'Authorization', 'x-webhook-signature' */],
|
|
133
|
+
SignatureVerification.DISABLED, // or ENABLED
|
|
134
|
+
async (params, ctx) => {
|
|
135
|
+
const { logger } = ctx;
|
|
136
|
+
logger.info({ message: `${name}-received`, params: JSON.stringify(params) });
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// TODO: Implement webhook business logic
|
|
140
|
+
logger.info({ message: `${name}-processed` });
|
|
141
|
+
return WebhookActionResponse.success();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
logger.error({ message: `${name}-error`, error: error.message, stack: error.stack });
|
|
144
|
+
// Optional parameters: message and exceptionClass
|
|
145
|
+
return WebhookActionResponse.exception(
|
|
146
|
+
`Failed: ${error.message}`,
|
|
147
|
+
'\\Magento\\Framework\\Exception\\LocalizedException'
|
|
148
|
+
);
|
|
149
|
+
// Or simply: WebhookActionResponse.exception('Failed');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**TypeScript:** Same with type annotations and `import` syntax
|
|
156
|
+
|
|
157
|
+
**Notes:**
|
|
158
|
+
- If Authorization header NOT in requiredHeaders, set `require-adobe-auth: false`
|
|
159
|
+
- If signature verification enabled, ensure PUBLIC_KEY in `.env`
|
|
160
|
+
- Enable in Commerce Admin: Stores > Configuration > Adobe Services > Webhooks
|
|
161
|
+
|
|
162
|
+
### Step 5: Update Configuration Files
|
|
163
|
+
|
|
164
|
+
Add action to `app.config.yaml` or `ext.config.yaml`:
|
|
165
|
+
|
|
166
|
+
**Simple structure:**
|
|
167
|
+
```yaml
|
|
168
|
+
application:
|
|
169
|
+
runtimeManifest:
|
|
170
|
+
packages:
|
|
171
|
+
[package-name]:
|
|
172
|
+
license: Apache-2.0
|
|
173
|
+
actions:
|
|
174
|
+
[action-name]:
|
|
175
|
+
function: actions/[action-name]/index.[js/ts]
|
|
176
|
+
web: 'yes'
|
|
177
|
+
runtime: nodejs:22
|
|
178
|
+
inputs:
|
|
179
|
+
LOG_LEVEL: debug
|
|
180
|
+
# If signature verification enabled:
|
|
181
|
+
PUBLIC_KEY: $PUBLIC_KEY
|
|
182
|
+
# OR: PUBLIC_KEY_BASE64: $PUBLIC_KEY_BASE64
|
|
183
|
+
annotations:
|
|
184
|
+
require-adobe-auth: [true/false]
|
|
185
|
+
final: true
|
|
186
|
+
# If API Gateway requested:
|
|
187
|
+
apis:
|
|
188
|
+
[action-name]:
|
|
189
|
+
[base-path]:
|
|
190
|
+
[relative-path]:
|
|
191
|
+
[action-name]:
|
|
192
|
+
method: post
|
|
193
|
+
response: http
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Packaged structure:**
|
|
197
|
+
- Create `actions/[package]/actions.config.yaml` with action config
|
|
198
|
+
- If API Gateway: Create `actions/[package]/apis.config.yaml`
|
|
199
|
+
- Reference both in main config
|
|
200
|
+
|
|
201
|
+
### Step 6: Setup Signature Verification (if enabled)
|
|
202
|
+
|
|
203
|
+
If signature verification enabled:
|
|
204
|
+
|
|
205
|
+
1. **Get Public Key from Commerce Admin:**
|
|
206
|
+
- Navigate to: Stores → Configuration → Adobe Services → Webhooks
|
|
207
|
+
- Set Signature Verification: Yes
|
|
208
|
+
- Click "Regenerate key pair"
|
|
209
|
+
- Copy the Public Key
|
|
210
|
+
|
|
211
|
+
2. **Add to `.env` file (project root):**
|
|
212
|
+
```bash
|
|
213
|
+
# Option 1: Standard format (recommended)
|
|
214
|
+
PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
|
|
215
|
+
[your public key here]
|
|
216
|
+
-----END PUBLIC KEY-----"
|
|
217
|
+
|
|
218
|
+
# Option 2: Base64 encoded
|
|
219
|
+
PUBLIC_KEY_BASE64="[your base64 encoded key]"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
3. **Security Notes:**
|
|
223
|
+
- Never commit `.env` to version control
|
|
224
|
+
- Add `.env` to `.gitignore`
|
|
225
|
+
- Regenerate keys regularly
|
|
226
|
+
- Update `.env` when keys are regenerated
|
|
227
|
+
|
|
228
|
+
### Step 7: Completion
|
|
229
|
+
|
|
230
|
+
Display:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
✅ Webhook Action Created Successfully!
|
|
234
|
+
|
|
235
|
+
📁 Files Created:
|
|
236
|
+
- actions/[path]/index.[js/ts]
|
|
237
|
+
[- .env with PUBLIC_KEY placeholder if signature verification enabled]
|
|
238
|
+
|
|
239
|
+
📝 Configuration Updated:
|
|
240
|
+
- app.config.yaml or ext.config.yaml
|
|
241
|
+
[- actions/[package]/actions.config.yaml if packaged]
|
|
242
|
+
[- actions/[package]/apis.config.yaml if API Gateway]
|
|
243
|
+
|
|
244
|
+
🚀 Next Steps:
|
|
245
|
+
1. Implement webhook business logic
|
|
246
|
+
[2. Add PUBLIC_KEY to .env if signature verification enabled]
|
|
247
|
+
[3. Wait 5-10 mins for API Gateway provisioning if configured]
|
|
248
|
+
4. Test locally: aio app dev
|
|
249
|
+
5. Deploy: aio app deploy
|
|
250
|
+
6. Test webhook endpoint
|
|
251
|
+
[7. Configure webhook in Adobe Commerce Admin if needed]
|
|
252
|
+
|
|
253
|
+
📖 Documentation:
|
|
254
|
+
- WebhookAction: @adobe-commerce/aio-toolkit
|
|
255
|
+
- Signature Verification: https://developer.adobe.com/commerce/extensibility/webhooks/signature-verification/
|
|
256
|
+
- Webhook Responses: https://developer.adobe.com/commerce/extensibility/webhooks/responses/
|
|
257
|
+
|
|
258
|
+
🔐 Signature Verification:
|
|
259
|
+
[If enabled]
|
|
260
|
+
- Protects against unauthorized webhook requests
|
|
261
|
+
- Uses HMAC SHA256 validation
|
|
262
|
+
- Commerce sends x-adobe-commerce-webhook-signature header
|
|
263
|
+
- Toolkit validates automatically using PUBLIC_KEY from .env
|
|
264
|
+
|
|
265
|
+
📤 Webhook Responses:
|
|
266
|
+
- All responses return 200 OK with JSON operation object
|
|
267
|
+
- Operations: success, exception, add, replace, remove
|
|
268
|
+
- Commerce processes the operation and modifies event arguments accordingly
|
|
269
|
+
- See WebhookActionResponse Operations section for detailed examples
|
|
270
|
+
|
|
271
|
+
🌐 API Gateway:
|
|
272
|
+
[If configured]
|
|
273
|
+
- Endpoint: https://adobeioruntime.net/apis/[namespace]/[base-path]/[relative-path]
|
|
274
|
+
- Provisioning: 5-10 minutes (may see 404 errors during)
|
|
275
|
+
- Response Type: [http/json/text/html]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Key Features
|
|
279
|
+
|
|
280
|
+
- **Auto-detection**: Language (TS/JS) and project structure
|
|
281
|
+
- **Flexible**: Simple or packaged actions
|
|
282
|
+
- **Signature Verification**: HMAC SHA256 webhook validation for Adobe Commerce
|
|
283
|
+
- **API Gateway**: Optional standardized API endpoints (5-10 min provisioning)
|
|
284
|
+
- **Response Operations**: Full Adobe Commerce webhook spec support
|
|
285
|
+
- `success`: Continue without changes
|
|
286
|
+
- `exception`: Terminate with error
|
|
287
|
+
- `add`: Add data to event arguments (with optional DataObject instance)
|
|
288
|
+
- `replace`: Replace values in event arguments (with optional DataObject instance)
|
|
289
|
+
- `remove`: Remove data from event arguments
|
|
290
|
+
- **Best Practices**: Structured logging, error handling, telemetry-ready
|
|
291
|
+
- **Configuration Management**: Automatic config file updates
|
|
292
|
+
|
|
293
|
+
### WebhookActionResponse Operations
|
|
294
|
+
|
|
295
|
+
Adobe Commerce webhooks expect a 200 response with a JSON object indicating the operation result. The toolkit provides these methods:
|
|
296
|
+
|
|
297
|
+
#### **success()** - Continue Process Without Changes
|
|
298
|
+
|
|
299
|
+
The process that triggered the original event continues without any changes.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
return WebhookActionResponse.success();
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
```json
|
|
307
|
+
{ "op": "success" }
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### **exception(message?, exceptionClass?)** - Terminate Process
|
|
311
|
+
|
|
312
|
+
Causes Commerce to terminate the process that triggered the original event. The exception is logged in Commerce's system.log.
|
|
313
|
+
|
|
314
|
+
**Parameters:**
|
|
315
|
+
- `message` (optional): Exception message. If not set, uses fallbackErrorMessage from config or system default
|
|
316
|
+
- `exceptionClass` (optional): Exception class path. Default: `\\Magento\\Framework\\Exception\\LocalizedException`
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
// With custom message and class
|
|
320
|
+
return WebhookActionResponse.exception(
|
|
321
|
+
'The product cannot be added to the cart because it is out of stock',
|
|
322
|
+
'Path\\To\\Exception\\Class'
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// With just message
|
|
326
|
+
return WebhookActionResponse.exception('Processing failed');
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"op": "exception",
|
|
333
|
+
"class": "Path\\To\\Exception\\Class",
|
|
334
|
+
"message": "The product cannot be added to the cart because it is out of stock"
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### **add(path, value, instance?)** - Add Data to Event Arguments
|
|
339
|
+
|
|
340
|
+
Updates the arguments in the original event by adding data at the specified path.
|
|
341
|
+
|
|
342
|
+
**Parameters:**
|
|
343
|
+
- `path` (required): Path where value should be added to triggered event arguments
|
|
344
|
+
- `value` (required): Value to add (single value or object)
|
|
345
|
+
- `instance` (optional): DataObject class name to create from the value
|
|
346
|
+
|
|
347
|
+
```javascript
|
|
348
|
+
// Add a new shipping method
|
|
349
|
+
return WebhookActionResponse.add(
|
|
350
|
+
'result',
|
|
351
|
+
{
|
|
352
|
+
data: {
|
|
353
|
+
amount: '5',
|
|
354
|
+
base_amount: '5',
|
|
355
|
+
carrier_code: 'newshipmethod',
|
|
356
|
+
carrier_title: 'Webhook new shipping method'
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
'Magento\\Quote\\Api\\Data\\ShippingMethodInterface'
|
|
360
|
+
);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"op": "add",
|
|
367
|
+
"path": "result",
|
|
368
|
+
"value": {
|
|
369
|
+
"data": {
|
|
370
|
+
"amount": "5",
|
|
371
|
+
"base_amount": "5",
|
|
372
|
+
"carrier_code": "newshipmethod",
|
|
373
|
+
"carrier_title": "Webhook new shipping method"
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"instance": "Magento\\Quote\\Api\\Data\\ShippingMethodInterface"
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### **replace(path, value, instance?)** - Replace Values in Event Arguments
|
|
381
|
+
|
|
382
|
+
Replaces argument values in the original event at the specified path.
|
|
383
|
+
|
|
384
|
+
**Parameters:**
|
|
385
|
+
- `path` (required): Path where value should be replaced (use `/` for nested paths)
|
|
386
|
+
- `value` (required): Replacement value (single value or object)
|
|
387
|
+
- `instance` (optional): DataObject class name to create from the value
|
|
388
|
+
|
|
389
|
+
```javascript
|
|
390
|
+
// Replace nested shipping method amount
|
|
391
|
+
return WebhookActionResponse.replace(
|
|
392
|
+
'result/shipping_methods/shipping_method_one/amount',
|
|
393
|
+
6
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
// Replace customer email
|
|
397
|
+
return WebhookActionResponse.replace(
|
|
398
|
+
'customer/email',
|
|
399
|
+
'newemail@example.com'
|
|
400
|
+
);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"op": "replace",
|
|
407
|
+
"path": "result/shipping_methods/shipping_method_one/amount",
|
|
408
|
+
"value": 6
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
#### **remove(path)** - Remove Data from Event Arguments
|
|
413
|
+
|
|
414
|
+
Removes values or nodes from the arguments in the original event by the provided path.
|
|
415
|
+
|
|
416
|
+
**Parameters:**
|
|
417
|
+
- `path` (required): Path of value to remove (use `/` for nested paths)
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
// Remove a specific key
|
|
421
|
+
return WebhookActionResponse.remove('result/key2');
|
|
422
|
+
|
|
423
|
+
// Remove internal notes from order
|
|
424
|
+
return WebhookActionResponse.remove('order/internal_notes');
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
```json
|
|
429
|
+
{
|
|
430
|
+
"op": "remove",
|
|
431
|
+
"path": "result/key2"
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
### Related Rules
|
|
437
|
+
|
|
438
|
+
- **Setting up New Relic Telemetry**: Add observability to your webhook action
|
|
439
|
+
|