@fluentcommerce/fc-connect-sdk 0.1.51 → 0.1.53
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 +514 -488
- package/README.md +227 -0
- package/dist/cjs/clients/fluent-client.js +60 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/types/index.d.ts +64 -0
- package/dist/cjs/versori/fluent-versori-client.d.ts +4 -1
- package/dist/cjs/versori/fluent-versori-client.js +83 -0
- package/dist/esm/clients/fluent-client.js +60 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/types/index.d.ts +64 -0
- package/dist/esm/versori/fluent-versori-client.d.ts +4 -1
- package/dist/esm/versori/fluent-versori-client.js +83 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types/index.d.ts +64 -0
- package/dist/types/versori/fluent-versori-client.d.ts +4 -1
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +487 -18
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +83 -0
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +52 -0
- package/docs/02-CORE-GUIDES/api-reference/readme.md +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -147,6 +147,7 @@ Choose the right Fluent Commerce API for your use case:
|
|
|
147
147
|
| **Location setup** (stores, warehouses) | **Event API** | `sendEvent()` | Requires workflow orchestration |
|
|
148
148
|
| **Order creation** (one-time orders) | **GraphQL** | `client.graphql()` with `createOrder` mutation | Triggers Order CREATED event, full control |
|
|
149
149
|
| **Order updates/events** (status changes) | **Event API** | `sendEvent()` | Triggers workflows for order state changes |
|
|
150
|
+
| **Audit/search event history** (trace flows, investigate failures) | **Event API (GET)** | `getEvents()` + `getEventById()` | Read-only event/audit retrieval with filters and pagination |
|
|
150
151
|
| **Customer data** (registration, profiles) | **GraphQL** | `client.graphql()` with mutations | No Rubix workflow support for customers |
|
|
151
152
|
| **Data extraction** (export to S3/SFTP) | **GraphQL** | `client.graphql()` + `ExtractionOrchestrator` | Query with auto-pagination, extract thousands of records |
|
|
152
153
|
| **Single operations** (create one product, update one location) | **GraphQL** | `client.graphql()` | Direct control, immediate feedback |
|
|
@@ -1217,6 +1218,232 @@ console.log('✅ Event sent successfully');
|
|
|
1217
1218
|
- **Event API Templates:** `docs/01-TEMPLATES/versori/workflows/ingestion/event-api/` (8 templates for S3/SFTP with CSV, XML, JSON, Parquet)
|
|
1218
1219
|
- **Batch API Guide:** `docs/02-CORE-GUIDES/ingestion/modules/02-CORE-GUIDES-ingestion-06-batch-api.md`
|
|
1219
1220
|
|
|
1221
|
+
### Event Log API (Search + Audit)
|
|
1222
|
+
|
|
1223
|
+
Query and retrieve events/audit logs from the Fluent Commerce REST Event API. Use these **read-only** methods for troubleshooting workflows, tracing event chains, monitoring orchestration, and auditing batch processing.
|
|
1224
|
+
|
|
1225
|
+
**Methods:**
|
|
1226
|
+
- `getEvents(params)` → `GET /api/v4.1/event` - Search/filter events with flexible query parameters
|
|
1227
|
+
- `getEventById(eventId)` → `GET /api/v4.1/event/{eventId}` - Get a single event by ID
|
|
1228
|
+
|
|
1229
|
+
**Important:** These methods query the Event Log (audit trail). They do NOT trigger workflows — use `sendEvent()` for that.
|
|
1230
|
+
|
|
1231
|
+
#### Basic Usage
|
|
1232
|
+
|
|
1233
|
+
```typescript
|
|
1234
|
+
import { createClient } from '@fluentcommerce/fc-connect-sdk';
|
|
1235
|
+
|
|
1236
|
+
const client = await createClient({
|
|
1237
|
+
config: { baseUrl, clientId, clientSecret, username, password },
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
// 1) Search for failed orchestration audit events on orders
|
|
1241
|
+
const logs = await client.getEvents({
|
|
1242
|
+
'context.rootEntityType': 'ORDER',
|
|
1243
|
+
eventType: 'ORCHESTRATION_AUDIT',
|
|
1244
|
+
eventStatus: 'FAILED',
|
|
1245
|
+
count: 100,
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
console.log(`Found ${logs.results.length} events (hasMore=${logs.hasMore})`);
|
|
1249
|
+
|
|
1250
|
+
for (const event of logs.results) {
|
|
1251
|
+
console.log(` ${event.name} [${event.eventStatus}] on ${event.context?.entityType}:${event.context?.entityRef}`);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// 2) Get full details for a specific event by ID
|
|
1255
|
+
if (logs.results[0]?.id) {
|
|
1256
|
+
const event = await client.getEventById(logs.results[0].id);
|
|
1257
|
+
console.log(`Event: ${event.name} - Status: ${event.eventStatus}`);
|
|
1258
|
+
console.log(` Entity: ${event.context?.entityType}:${event.context?.entityRef}`);
|
|
1259
|
+
console.log(` Root: ${event.context?.rootEntityType}:${event.context?.rootEntityRef}`);
|
|
1260
|
+
console.log(` Generated: ${event.generatedOn} by ${event.generatedBy}`);
|
|
1261
|
+
|
|
1262
|
+
// Trace parent events (for debugging event chains)
|
|
1263
|
+
if (event.context?.sourceEvents?.length) {
|
|
1264
|
+
for (const parentId of event.context.sourceEvents) {
|
|
1265
|
+
const parent = await client.getEventById(parentId);
|
|
1266
|
+
console.log(` Parent: ${parent.name} (${parent.eventStatus})`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
#### Response Shape
|
|
1273
|
+
|
|
1274
|
+
`getEvents()` returns `FluentEventLogResponse`:
|
|
1275
|
+
|
|
1276
|
+
```typescript
|
|
1277
|
+
{
|
|
1278
|
+
start: 1, // Pagination offset
|
|
1279
|
+
count: 1000, // Results in this page
|
|
1280
|
+
hasMore: false, // More pages available?
|
|
1281
|
+
results: [ // Array of FluentEventLogItem
|
|
1282
|
+
{
|
|
1283
|
+
id: "e2cc5040-...", // UUID
|
|
1284
|
+
name: "BATCH_COMPLETE", // Event/ruleset name (can be null)
|
|
1285
|
+
type: "ORCHESTRATION_AUDIT",
|
|
1286
|
+
accountId: "MYACCOUNT",
|
|
1287
|
+
retailerId: "5", // String in response (not number)
|
|
1288
|
+
category: "BATCH",
|
|
1289
|
+
context: {
|
|
1290
|
+
sourceEvents: ["babc5f37-..."], // Parent event IDs for tracing
|
|
1291
|
+
entityType: "BATCH",
|
|
1292
|
+
entityId: "12",
|
|
1293
|
+
entityRef: "12",
|
|
1294
|
+
rootEntityType: "JOB",
|
|
1295
|
+
rootEntityId: "13",
|
|
1296
|
+
rootEntityRef: "13"
|
|
1297
|
+
},
|
|
1298
|
+
eventStatus: "COMPLETE",
|
|
1299
|
+
attributes: null, // null OR array of { name, value, type }
|
|
1300
|
+
source: null,
|
|
1301
|
+
generatedBy: "Rubix User",
|
|
1302
|
+
generatedOn: "2026-02-05T06:31:56.895+00:00"
|
|
1303
|
+
}
|
|
1304
|
+
]
|
|
1305
|
+
}
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
`getEventById(id)` returns a single `FluentEventLogItem` (same shape as each item in `results`).
|
|
1309
|
+
|
|
1310
|
+
#### Query Parameters
|
|
1311
|
+
|
|
1312
|
+
All parameters are optional. Context filters use **dot-notation keys** which require quotes in JavaScript/TypeScript:
|
|
1313
|
+
|
|
1314
|
+
```typescript
|
|
1315
|
+
// ⚠️ Dot-notation keys MUST be quoted (JavaScript syntax requirement)
|
|
1316
|
+
await client.getEvents({
|
|
1317
|
+
'context.rootEntityType': 'ORDER', // ✅ Quotes required (has dot)
|
|
1318
|
+
'context.entityRef': 'ORD-123', // ✅ Quotes required (has dot)
|
|
1319
|
+
eventType: 'ORCHESTRATION_AUDIT', // ✅ No quotes needed (simple key)
|
|
1320
|
+
count: 100, // ✅ No quotes needed (simple key)
|
|
1321
|
+
});
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
| Parameter | Type | Description | Example |
|
|
1325
|
+
|-----------|------|-------------|---------|
|
|
1326
|
+
| `context.rootEntityType` | string | Root entity type | `'ORDER'`, `'JOB'`, `'LOCATION'` |
|
|
1327
|
+
| `context.rootEntityId` | string | Root entity ID | `'12345'` |
|
|
1328
|
+
| `context.rootEntityRef` | string | Root entity reference | `'ORD-12345'` |
|
|
1329
|
+
| `context.entityType` | string | Sub-entity type | `'FULFILMENT'`, `'BATCH'`, `'ARTICLE'` |
|
|
1330
|
+
| `context.entityId` | string | Sub-entity ID | `'67890'` |
|
|
1331
|
+
| `context.entityRef` | string | Sub-entity reference | `'FUL-67890'` |
|
|
1332
|
+
| `eventType` | string | Event type filter | `'ORCHESTRATION_AUDIT'` |
|
|
1333
|
+
| `eventStatus` | string | Status filter | `'FAILED'`, `'COMPLETE'` |
|
|
1334
|
+
| `name` | string | Event/ruleset name | `'BATCH_COMPLETE'` |
|
|
1335
|
+
| `category` | string | Category filter | `'ruleSet'`, `'ACTION'` |
|
|
1336
|
+
| `from` | string | Start date (UTC ISO 8601) | `'2026-02-01T00:00:00.000Z'` |
|
|
1337
|
+
| `to` | string | End date (UTC ISO 8601) | `'2026-02-15T23:59:59.999Z'` |
|
|
1338
|
+
| `retailerId` | string/number | Retailer filter (pass explicitly; no auto-fallback) | `'5'` |
|
|
1339
|
+
| `start` | number | Pagination offset (default: `0`) | `0` |
|
|
1340
|
+
| `count` | number | Results per page (default: `100`, max: `5000`) | `1000` |
|
|
1341
|
+
|
|
1342
|
+
#### Valid Values Reference
|
|
1343
|
+
|
|
1344
|
+
| Parameter | Valid Values |
|
|
1345
|
+
|-----------|-------------|
|
|
1346
|
+
| **eventType** | `ORCHESTRATION`, `ORCHESTRATION_AUDIT`, `API`, `INTEGRATION`, `SECURITY`, `GENERAL` |
|
|
1347
|
+
| **eventStatus** | `PENDING`, `SCHEDULED`, `NO_MATCH`, `SUCCESS`, `FAILED`, `COMPLETE` |
|
|
1348
|
+
| **category** | `snapshot`, `ruleSet`, `rule`, `ACTION`, `CUSTOM`, `exception`, `ORDER_WORKFLOW`, `BATCH` |
|
|
1349
|
+
| **rootEntityType** | `ORDER`, `LOCATION`, `FULFILMENT_OPTIONS`, `PRODUCT_CATALOGUE`, `INVENTORY_CATALOGUE`, `VIRTUAL_CATALOGUE`, `CONTROL_GROUP`, `RETURN_ORDER`, `BILLING_ACCOUNT`, `JOB` |
|
|
1350
|
+
| **entityType** | `ORDER`, `FULFILMENT`, `ARTICLE`, `CONSIGNMENT`, `LOCATION`, `WAVE`, `FULFILMENT_OPTIONS`, `FULFILMENT_PLAN`, `PRODUCT_CATALOGUE`, `CATEGORY`, `PRODUCT`, `INVENTORY_CATALOGUE`, `INVENTORY_POSITION`, `INVENTORY_QUANTITY`, `VIRTUAL_CATALOGUE`, `VIRTUAL_POSITION`, `CONTROL_GROUP`, `CONTROL`, `RETURN_ORDER`, `RETURN_FULFILMENT`, `BILLING_ACCOUNT`, `CREDIT_MEMO`, `BATCH` |
|
|
1351
|
+
|
|
1352
|
+
#### Common Use Cases
|
|
1353
|
+
|
|
1354
|
+
```typescript
|
|
1355
|
+
// 1. Find failed events in the last 24 hours
|
|
1356
|
+
const failedEvents = await client.getEvents({
|
|
1357
|
+
eventStatus: 'FAILED',
|
|
1358
|
+
from: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
|
|
1359
|
+
to: new Date().toISOString(),
|
|
1360
|
+
count: 1000,
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
// 2. Track batch job processing (all events for a specific job)
|
|
1364
|
+
const batchEvents = await client.getEvents({
|
|
1365
|
+
'context.rootEntityType': 'JOB',
|
|
1366
|
+
'context.rootEntityId': '13',
|
|
1367
|
+
eventType: 'ORCHESTRATION_AUDIT',
|
|
1368
|
+
count: 500,
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
// 3. Paginate through large result sets
|
|
1372
|
+
let start = 0;
|
|
1373
|
+
const allEvents: any[] = [];
|
|
1374
|
+
let hasMore = true;
|
|
1375
|
+
|
|
1376
|
+
while (hasMore) {
|
|
1377
|
+
const page = await client.getEvents({
|
|
1378
|
+
'context.rootEntityType': 'ORDER',
|
|
1379
|
+
start,
|
|
1380
|
+
count: 1000,
|
|
1381
|
+
});
|
|
1382
|
+
allEvents.push(...page.results);
|
|
1383
|
+
hasMore = page.hasMore;
|
|
1384
|
+
start += page.count;
|
|
1385
|
+
}
|
|
1386
|
+
console.log(`Total events collected: ${allEvents.length}`);
|
|
1387
|
+
|
|
1388
|
+
// 4. Extract performance timing from event attributes
|
|
1389
|
+
const auditEvents = await client.getEvents({
|
|
1390
|
+
eventType: 'ORCHESTRATION_AUDIT',
|
|
1391
|
+
'context.rootEntityType': 'JOB',
|
|
1392
|
+
count: 100,
|
|
1393
|
+
});
|
|
1394
|
+
|
|
1395
|
+
for (const event of auditEvents.results) {
|
|
1396
|
+
if (Array.isArray(event.attributes)) {
|
|
1397
|
+
const startTimer = event.attributes.find(a => a.name === 'startTimer');
|
|
1398
|
+
const stopTimer = event.attributes.find(a => a.name === 'stopTimer');
|
|
1399
|
+
if (startTimer && stopTimer) {
|
|
1400
|
+
const duration = Number(stopTimer.value) - Number(startTimer.value);
|
|
1401
|
+
console.log(`${event.name}: ${duration}ms`);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
// 5. Find events for a specific order by reference
|
|
1407
|
+
const orderEvents = await client.getEvents({
|
|
1408
|
+
'context.rootEntityType': 'ORDER',
|
|
1409
|
+
'context.rootEntityRef': 'HD_12345',
|
|
1410
|
+
eventType: 'ORCHESTRATION_AUDIT',
|
|
1411
|
+
});
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
#### When to Use Which Method
|
|
1415
|
+
|
|
1416
|
+
| Method | Use When | Returns | Example |
|
|
1417
|
+
|--------|----------|---------|---------|
|
|
1418
|
+
| `sendEvent()` | **Trigger** a workflow or business action | Event creation response | Product upsert, order cancel, location update |
|
|
1419
|
+
| `getEvents()` | **Search/filter** historical events | `{ results[], hasMore, start, count }` | Find failed events, audit batch processing |
|
|
1420
|
+
| `getEventById()` | **Get full details** for one event by ID | Single event object | Drill into context, attributes, trace sourceEvents |
|
|
1421
|
+
|
|
1422
|
+
#### Limitations & Operational Notes
|
|
1423
|
+
|
|
1424
|
+
| Constraint | Value | Notes |
|
|
1425
|
+
|------------|-------|-------|
|
|
1426
|
+
| **Max count per request** | `5000` | Use pagination (`start`/`count`/`hasMore`) for larger result sets |
|
|
1427
|
+
| **Time range (from)** | 4 months back max | API rejects queries older than ~4 months |
|
|
1428
|
+
| **Time range (to)** | 1 month forward max | API rejects future dates beyond ~1 month |
|
|
1429
|
+
| **Default time window** | Past 30 days | Applied when `from` is omitted |
|
|
1430
|
+
| **Date format** | UTC ISO 8601 | `YYYY-MM-DDTHH:mm:ss.SSSZ` |
|
|
1431
|
+
| **retailerId** | Pass explicitly | Unlike `sendEvent()`, no auto-fallback to client config — pass in params if needed |
|
|
1432
|
+
| **attributes field** | Nullable | Can be `null` (not empty array) — always check before iterating |
|
|
1433
|
+
| **name field** | Nullable | Can be `null` for some system events |
|
|
1434
|
+
| **GraphQL** | Not available | Event queries use REST only — no GraphQL `events` root field exists |
|
|
1435
|
+
|
|
1436
|
+
**Key points:**
|
|
1437
|
+
- `getEvents()` and `getEventById()` are **read-only** — they do NOT trigger workflows
|
|
1438
|
+
- Empty `results: []` is valid (not an error) — your filter may simply match zero events
|
|
1439
|
+
- Always use bounded time ranges (`from`/`to`) for predictable performance
|
|
1440
|
+
- Use `eventType: 'ORCHESTRATION_AUDIT'` for workflow execution history
|
|
1441
|
+
- Use `context.sourceEvents` array on each event to trace parent event chains
|
|
1442
|
+
- The `attributes` field is `null` for most events; only rule/ruleset events populate it
|
|
1443
|
+
- `retailerId` in responses is a **string** (e.g., `"5"`) even though you can pass a number in params
|
|
1444
|
+
|
|
1445
|
+
**📚 Detailed Guide:** `docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md`
|
|
1446
|
+
|
|
1220
1447
|
---
|
|
1221
1448
|
|
|
1222
1449
|
### Error Classification
|
|
@@ -513,6 +513,56 @@ class FluentClient {
|
|
|
513
513
|
throw error;
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
+
async getEvents(params = {}) {
|
|
517
|
+
const queryString = this.buildEventQueryString(params);
|
|
518
|
+
const endpoint = queryString ? `/api/v4.1/event?${queryString}` : '/api/v4.1/event';
|
|
519
|
+
this.log('info', '[FluentClient:event] Searching event logs', {
|
|
520
|
+
endpoint,
|
|
521
|
+
filterCount: Object.keys(params).length,
|
|
522
|
+
hasDateRange: !!(params.from || params.to),
|
|
523
|
+
entityType: params['context.entityType'],
|
|
524
|
+
rootEntityType: params['context.rootEntityType'],
|
|
525
|
+
eventStatus: params.eventStatus,
|
|
526
|
+
});
|
|
527
|
+
try {
|
|
528
|
+
const response = await this.request(endpoint, {
|
|
529
|
+
method: 'GET',
|
|
530
|
+
});
|
|
531
|
+
this.log('info', '[FluentClient:event] Event search completed', {
|
|
532
|
+
resultCount: response.data.count,
|
|
533
|
+
hasMore: response.data.hasMore,
|
|
534
|
+
start: response.data.start,
|
|
535
|
+
});
|
|
536
|
+
return response.data;
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
this.log('error', '[FluentClient:event] Failed to search events', error);
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
async getEventById(eventId) {
|
|
544
|
+
if (!eventId) {
|
|
545
|
+
throw new types_1.FluentValidationError('eventId is required');
|
|
546
|
+
}
|
|
547
|
+
this.log('info', `[FluentClient:event] Getting event by ID: ${eventId}`, { eventId });
|
|
548
|
+
try {
|
|
549
|
+
const response = await this.request(`/api/v4.1/event/${eventId}`, {
|
|
550
|
+
method: 'GET',
|
|
551
|
+
});
|
|
552
|
+
this.log('info', `[FluentClient:event] Event retrieved: ${response.data.name}`, {
|
|
553
|
+
eventId: response.data.id,
|
|
554
|
+
name: response.data.name,
|
|
555
|
+
type: response.data.type,
|
|
556
|
+
eventStatus: response.data.eventStatus,
|
|
557
|
+
entityType: response.data.context?.entityType,
|
|
558
|
+
});
|
|
559
|
+
return response.data;
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
this.log('error', `[FluentClient:event] Failed to get event ${eventId}`, error);
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
516
566
|
async validateWebhook(payload, signature, rawPayload) {
|
|
517
567
|
this.log('info', `[FluentClient:webhook] Validating webhook for event "${payload.name || 'unknown'}"`, {
|
|
518
568
|
hasSignature: !!signature,
|
|
@@ -592,6 +642,16 @@ class FluentClient {
|
|
|
592
642
|
const result = await this.graphql(payload);
|
|
593
643
|
return result.data;
|
|
594
644
|
}
|
|
645
|
+
buildEventQueryString(params) {
|
|
646
|
+
const searchParams = new URLSearchParams();
|
|
647
|
+
for (const [key, value] of Object.entries(params)) {
|
|
648
|
+
if (value === undefined || value === null || value === '') {
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
searchParams.append(key, String(value));
|
|
652
|
+
}
|
|
653
|
+
return searchParams.toString();
|
|
654
|
+
}
|
|
595
655
|
async request(endpoint, config = {}) {
|
|
596
656
|
const isVersoriContext = this.context?.fetch && this.context?.fetch !== globalThis.fetch;
|
|
597
657
|
this.log('debug', 'Request mode detection', {
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { GraphQLTemplateGenerator } from './services/mapping/query/graphql-templ
|
|
|
34
34
|
export { MappingError, ResolverError } from './errors';
|
|
35
35
|
export type { NodeConfig, NodesConfig, FieldConfig, FieldsConfig, NodesContext, MappingContext, ResolverFunction, ResolverHelpers, ResolverContext, ResolversMap, MapResult, MapWithNodesResult, NodeValidationResult, MappingOptions, } from './services/mapping/types';
|
|
36
36
|
export { CsvDelimiter, FileEncoding, JobStrategy, FileType, BatchAction, EntityType, AwsRegion, ValidationMode, ProcessingStatus, } from './types/enums';
|
|
37
|
-
export type { FluentClientConfig, FluentBatchPayload, FluentInventoryBatchEntity, FluentInventoryBatchRequest, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobMetadata, FluentJobStatus, FluentJobResults, FluentEvent, FluentEventMode, CreateEventOptions, GraphQLPayload, GraphQLResponse, GraphQLErrorMode, GraphQLError, PaginationConfig, PageInfo, PaginatedResponse, FluentWebhookPayload, WebhookRequestContext, GraphQLValidationResult, BatchConfiguration, DataSourceConfig, FileMetadata, Logger, StructuredLogger, LogContext, LoggerConfig, PerformanceMetrics, InventoryDataRecord, ParquetDataRecord, FieldMappingConfig, FieldMappingRule, ProcessingMetadata, AttributeValue, } from './types';
|
|
37
|
+
export type { FluentClientConfig, FluentBatchPayload, FluentInventoryBatchEntity, FluentInventoryBatchRequest, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobMetadata, FluentJobStatus, FluentJobResults, FluentEvent, FluentEventMode, CreateEventOptions, FluentEventRootEntityType, FluentEventEntityType, FluentEventCategory, FluentEventType, FluentEventStatus, FluentEventQueryParamValue, FluentEventQueryParams, FluentEventLogAttribute, FluentEventLogContext, FluentEventLogItem, FluentEventLogResponse, GraphQLPayload, GraphQLResponse, GraphQLErrorMode, GraphQLError, PaginationConfig, PageInfo, PaginatedResponse, FluentWebhookPayload, WebhookRequestContext, GraphQLValidationResult, BatchConfiguration, DataSourceConfig, FileMetadata, Logger, StructuredLogger, LogContext, LoggerConfig, PerformanceMetrics, InventoryDataRecord, ParquetDataRecord, FieldMappingConfig, FieldMappingRule, ProcessingMetadata, AttributeValue, } from './types';
|
|
38
38
|
export type { VersoriContext, WebhookContext, DirectContext } from './types';
|
|
39
39
|
export { S3SDKTester, S3PresignedTester, S3ComparisonTester, FluentConnectionTester, type TestResult, type FluentTestConfig, type S3TestConfig, } from './testing/index';
|
|
40
40
|
export { S3Service, S3ServiceError, type S3ServiceConfig, type S3Config, type S3Object, type ListOptions, type PutOptions, type CopyOptions, type S3Location, } from './services/s3/index';
|
|
@@ -95,6 +95,70 @@ export interface FluentEvent {
|
|
|
95
95
|
export interface CreateEventOptions {
|
|
96
96
|
mode?: FluentEventMode;
|
|
97
97
|
}
|
|
98
|
+
export type FluentEventRootEntityType = 'ORDER' | 'LOCATION' | 'FULFILMENT_OPTIONS' | 'PRODUCT_CATALOGUE' | 'INVENTORY_CATALOGUE' | 'VIRTUAL_CATALOGUE' | 'CONTROL_GROUP' | 'RETURN_ORDER' | 'BILLING_ACCOUNT' | 'JOB';
|
|
99
|
+
export type FluentEventEntityType = 'ORDER' | 'FULFILMENT' | 'ARTICLE' | 'CONSIGNMENT' | 'LOCATION' | 'WAVE' | 'FULFILMENT_OPTIONS' | 'FULFILMENT_PLAN' | 'PRODUCT_CATALOGUE' | 'CATEGORY' | 'PRODUCT' | 'INVENTORY_CATALOGUE' | 'INVENTORY_POSITION' | 'INVENTORY_QUANTITY' | 'VIRTUAL_CATALOGUE' | 'VIRTUAL_POSITION' | 'CONTROL_GROUP' | 'CONTROL' | 'RETURN_ORDER' | 'RETURN_FULFILMENT' | 'BILLING_ACCOUNT' | 'CREDIT_MEMO' | 'BATCH';
|
|
100
|
+
export type FluentEventCategory = 'snapshot' | 'ruleSet' | 'rule' | 'ACTION' | 'CUSTOM' | 'exception' | 'ORDER_WORKFLOW';
|
|
101
|
+
export type FluentEventType = 'ORCHESTRATION' | 'ORCHESTRATION_AUDIT' | 'API' | 'INTEGRATION' | 'SECURITY' | 'GENERAL';
|
|
102
|
+
export type FluentEventStatus = 'PENDING' | 'SCHEDULED' | 'NO_MATCH' | 'SUCCESS' | 'FAILED' | 'COMPLETE';
|
|
103
|
+
export type FluentEventQueryParamValue = string | number | boolean;
|
|
104
|
+
export interface FluentEventQueryParams {
|
|
105
|
+
start?: number;
|
|
106
|
+
count?: number;
|
|
107
|
+
from?: string;
|
|
108
|
+
to?: string;
|
|
109
|
+
name?: string;
|
|
110
|
+
category?: FluentEventCategory | string;
|
|
111
|
+
retailerId?: string | number;
|
|
112
|
+
eventType?: FluentEventType | string;
|
|
113
|
+
eventStatus?: FluentEventStatus | string;
|
|
114
|
+
eventId?: string;
|
|
115
|
+
'context.rootEntityType'?: FluentEventRootEntityType | string;
|
|
116
|
+
'context.rootEntityId'?: string | number;
|
|
117
|
+
'context.rootEntityRef'?: string;
|
|
118
|
+
'context.entityType'?: FluentEventEntityType | string;
|
|
119
|
+
'context.entityId'?: string | number;
|
|
120
|
+
'context.entityRef'?: string;
|
|
121
|
+
'context.sourceEvents'?: string;
|
|
122
|
+
[key: string]: FluentEventQueryParamValue | undefined;
|
|
123
|
+
}
|
|
124
|
+
export interface FluentEventLogContext {
|
|
125
|
+
sourceEvents?: string[];
|
|
126
|
+
entityType?: FluentEventEntityType | string;
|
|
127
|
+
entityId?: string;
|
|
128
|
+
entityRef?: string;
|
|
129
|
+
rootEntityType?: FluentEventRootEntityType | string;
|
|
130
|
+
rootEntityId?: string;
|
|
131
|
+
rootEntityRef?: string;
|
|
132
|
+
[key: string]: JsonValue | undefined;
|
|
133
|
+
}
|
|
134
|
+
export interface FluentEventLogAttribute {
|
|
135
|
+
name: string;
|
|
136
|
+
value: unknown;
|
|
137
|
+
type?: string;
|
|
138
|
+
[key: string]: unknown;
|
|
139
|
+
}
|
|
140
|
+
export interface FluentEventLogItem {
|
|
141
|
+
id: string;
|
|
142
|
+
name: string;
|
|
143
|
+
type?: FluentEventType | string;
|
|
144
|
+
accountId?: string;
|
|
145
|
+
retailerId?: string;
|
|
146
|
+
category?: FluentEventCategory | string;
|
|
147
|
+
context?: FluentEventLogContext;
|
|
148
|
+
eventStatus?: FluentEventStatus | string;
|
|
149
|
+
attributes?: FluentEventLogAttribute[] | Record<string, JsonValue> | null;
|
|
150
|
+
source?: string | null;
|
|
151
|
+
generatedBy?: string;
|
|
152
|
+
generatedOn?: string;
|
|
153
|
+
[key: string]: unknown;
|
|
154
|
+
}
|
|
155
|
+
export interface FluentEventLogResponse {
|
|
156
|
+
start: number;
|
|
157
|
+
count: number;
|
|
158
|
+
hasMore: boolean;
|
|
159
|
+
results: FluentEventLogItem[];
|
|
160
|
+
[key: string]: unknown;
|
|
161
|
+
}
|
|
98
162
|
export type GraphQLErrorMode = 'throw' | 'partial';
|
|
99
163
|
export interface GraphQLPayload<T = Record<string, JsonValue>> {
|
|
100
164
|
query: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FluentEvent, GraphQLPayload, GraphQLResponse, FluentEventMode, JsonValue, FluentBatchPayload, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobStatus, FluentJobResults } from '../types';
|
|
1
|
+
import type { FluentEvent, GraphQLPayload, GraphQLResponse, FluentEventMode, FluentEventLogResponse, FluentEventLogItem, FluentEventQueryParams, JsonValue, FluentBatchPayload, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobStatus, FluentJobResults } from '../types';
|
|
2
2
|
import type { FluentWebhookPayload, EventResponse } from '../types';
|
|
3
3
|
export declare class FluentVersoriClient {
|
|
4
4
|
private ctx;
|
|
@@ -13,6 +13,8 @@ export declare class FluentVersoriClient {
|
|
|
13
13
|
private executeSinglePage;
|
|
14
14
|
private executeWithAutoPagination;
|
|
15
15
|
sendEvent(event: FluentEvent, mode?: FluentEventMode): Promise<EventResponse>;
|
|
16
|
+
getEvents(params?: FluentEventQueryParams): Promise<FluentEventLogResponse>;
|
|
17
|
+
getEventById(eventId: string): Promise<FluentEventLogItem>;
|
|
16
18
|
createJob(payload: FluentJobPayload): Promise<FluentJobResponse>;
|
|
17
19
|
sendBatch(jobId: string, payload: FluentBatchPayload): Promise<FluentBatchResponse>;
|
|
18
20
|
getJobStatus(jobId: string): Promise<FluentJobStatus>;
|
|
@@ -20,6 +22,7 @@ export declare class FluentVersoriClient {
|
|
|
20
22
|
getJobResults(jobId: string): Promise<FluentJobResults>;
|
|
21
23
|
query<T = JsonValue>(queryOrPayload: string | GraphQLPayload, variables?: Record<string, any>): Promise<T | undefined>;
|
|
22
24
|
mutate<T = JsonValue>(mutationOrPayload: string | GraphQLPayload, variables?: Record<string, any>): Promise<T | undefined>;
|
|
25
|
+
private buildEventQueryString;
|
|
23
26
|
private throwApiError;
|
|
24
27
|
private fetchWithRetry;
|
|
25
28
|
validateWebhook(payload: FluentWebhookPayload, signature?: string, rawPayload?: string, publicKey?: string): Promise<boolean>;
|
|
@@ -427,6 +427,79 @@ class FluentVersoriClient {
|
|
|
427
427
|
return { success: true, statusCode: response.status, message: text };
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
+
async getEvents(params = {}) {
|
|
431
|
+
const query = this.buildEventQueryString(params);
|
|
432
|
+
const endpoint = query ? `/api/v4.1/event?${query}` : '/api/v4.1/event';
|
|
433
|
+
this.ctx.log.info('[fc-connect-sdk:event] Searching event logs', {
|
|
434
|
+
endpoint,
|
|
435
|
+
filterCount: Object.keys(params).length,
|
|
436
|
+
hasDateRange: !!(params.from || params.to),
|
|
437
|
+
entityType: params['context.entityType'],
|
|
438
|
+
rootEntityType: params['context.rootEntityType'],
|
|
439
|
+
eventStatus: params.eventStatus,
|
|
440
|
+
});
|
|
441
|
+
const response = await this.fetchWithRetry(endpoint, {
|
|
442
|
+
method: 'GET',
|
|
443
|
+
headers: {
|
|
444
|
+
'Content-Type': 'application/json',
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
const text = response.text;
|
|
448
|
+
if (!response.ok) {
|
|
449
|
+
this.ctx.log.error('[fc-connect-sdk:event] Failed to search events', {
|
|
450
|
+
status: response.status,
|
|
451
|
+
body: text,
|
|
452
|
+
});
|
|
453
|
+
this.throwApiError('Get events failed', response.status, text);
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const result = JSON.parse(text);
|
|
457
|
+
this.ctx.log.info('[fc-connect-sdk:event] Event search completed', {
|
|
458
|
+
resultCount: result.count,
|
|
459
|
+
hasMore: result.hasMore,
|
|
460
|
+
start: result.start,
|
|
461
|
+
});
|
|
462
|
+
return result;
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
throw new types_1.FluentAPIError('Failed to parse event log response', response.status, text);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async getEventById(eventId) {
|
|
469
|
+
if (!eventId) {
|
|
470
|
+
throw new types_1.FluentValidationError('eventId is required');
|
|
471
|
+
}
|
|
472
|
+
this.ctx.log.info(`[fc-connect-sdk:event] Getting event by ID: ${eventId}`, { eventId });
|
|
473
|
+
const response = await this.fetchWithRetry(`/api/v4.1/event/${eventId}`, {
|
|
474
|
+
method: 'GET',
|
|
475
|
+
headers: {
|
|
476
|
+
'Content-Type': 'application/json',
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
const text = response.text;
|
|
480
|
+
if (!response.ok) {
|
|
481
|
+
this.ctx.log.error(`[fc-connect-sdk:event] Failed to get event ${eventId}`, {
|
|
482
|
+
eventId,
|
|
483
|
+
status: response.status,
|
|
484
|
+
body: text,
|
|
485
|
+
});
|
|
486
|
+
this.throwApiError(`Get event ${eventId} failed`, response.status, text);
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
const event = JSON.parse(text);
|
|
490
|
+
this.ctx.log.info(`[fc-connect-sdk:event] Event retrieved: ${event.name}`, {
|
|
491
|
+
eventId: event.id,
|
|
492
|
+
name: event.name,
|
|
493
|
+
type: event.type,
|
|
494
|
+
eventStatus: event.eventStatus,
|
|
495
|
+
entityType: event.context?.entityType,
|
|
496
|
+
});
|
|
497
|
+
return event;
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
throw new types_1.FluentAPIError('Failed to parse event response', response.status, text);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
430
503
|
async createJob(payload) {
|
|
431
504
|
this.ctx.log.info(`[fc-connect-sdk:job] Creating job "${payload.name}"`, {
|
|
432
505
|
name: payload.name,
|
|
@@ -574,6 +647,16 @@ class FluentVersoriClient {
|
|
|
574
647
|
const result = await this.graphql(payload);
|
|
575
648
|
return result.data;
|
|
576
649
|
}
|
|
650
|
+
buildEventQueryString(params) {
|
|
651
|
+
const searchParams = new URLSearchParams();
|
|
652
|
+
for (const [key, value] of Object.entries(params)) {
|
|
653
|
+
if (value === undefined || value === null || value === '') {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
searchParams.append(key, String(value));
|
|
657
|
+
}
|
|
658
|
+
return searchParams.toString();
|
|
659
|
+
}
|
|
577
660
|
throwApiError(message, status, responseText) {
|
|
578
661
|
if (status === 401) {
|
|
579
662
|
throw new types_1.AuthenticationError(`${message}: ${responseText}`, { response: responseText });
|
|
@@ -510,6 +510,56 @@ export class FluentClient {
|
|
|
510
510
|
throw error;
|
|
511
511
|
}
|
|
512
512
|
}
|
|
513
|
+
async getEvents(params = {}) {
|
|
514
|
+
const queryString = this.buildEventQueryString(params);
|
|
515
|
+
const endpoint = queryString ? `/api/v4.1/event?${queryString}` : '/api/v4.1/event';
|
|
516
|
+
this.log('info', '[FluentClient:event] Searching event logs', {
|
|
517
|
+
endpoint,
|
|
518
|
+
filterCount: Object.keys(params).length,
|
|
519
|
+
hasDateRange: !!(params.from || params.to),
|
|
520
|
+
entityType: params['context.entityType'],
|
|
521
|
+
rootEntityType: params['context.rootEntityType'],
|
|
522
|
+
eventStatus: params.eventStatus,
|
|
523
|
+
});
|
|
524
|
+
try {
|
|
525
|
+
const response = await this.request(endpoint, {
|
|
526
|
+
method: 'GET',
|
|
527
|
+
});
|
|
528
|
+
this.log('info', '[FluentClient:event] Event search completed', {
|
|
529
|
+
resultCount: response.data.count,
|
|
530
|
+
hasMore: response.data.hasMore,
|
|
531
|
+
start: response.data.start,
|
|
532
|
+
});
|
|
533
|
+
return response.data;
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
this.log('error', '[FluentClient:event] Failed to search events', error);
|
|
537
|
+
throw error;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
async getEventById(eventId) {
|
|
541
|
+
if (!eventId) {
|
|
542
|
+
throw new FluentValidationError('eventId is required');
|
|
543
|
+
}
|
|
544
|
+
this.log('info', `[FluentClient:event] Getting event by ID: ${eventId}`, { eventId });
|
|
545
|
+
try {
|
|
546
|
+
const response = await this.request(`/api/v4.1/event/${eventId}`, {
|
|
547
|
+
method: 'GET',
|
|
548
|
+
});
|
|
549
|
+
this.log('info', `[FluentClient:event] Event retrieved: ${response.data.name}`, {
|
|
550
|
+
eventId: response.data.id,
|
|
551
|
+
name: response.data.name,
|
|
552
|
+
type: response.data.type,
|
|
553
|
+
eventStatus: response.data.eventStatus,
|
|
554
|
+
entityType: response.data.context?.entityType,
|
|
555
|
+
});
|
|
556
|
+
return response.data;
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
this.log('error', `[FluentClient:event] Failed to get event ${eventId}`, error);
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
513
563
|
async validateWebhook(payload, signature, rawPayload) {
|
|
514
564
|
this.log('info', `[FluentClient:webhook] Validating webhook for event "${payload.name || 'unknown'}"`, {
|
|
515
565
|
hasSignature: !!signature,
|
|
@@ -589,6 +639,16 @@ export class FluentClient {
|
|
|
589
639
|
const result = await this.graphql(payload);
|
|
590
640
|
return result.data;
|
|
591
641
|
}
|
|
642
|
+
buildEventQueryString(params) {
|
|
643
|
+
const searchParams = new URLSearchParams();
|
|
644
|
+
for (const [key, value] of Object.entries(params)) {
|
|
645
|
+
if (value === undefined || value === null || value === '') {
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
searchParams.append(key, String(value));
|
|
649
|
+
}
|
|
650
|
+
return searchParams.toString();
|
|
651
|
+
}
|
|
592
652
|
async request(endpoint, config = {}) {
|
|
593
653
|
const isVersoriContext = this.context?.fetch && this.context?.fetch !== globalThis.fetch;
|
|
594
654
|
this.log('debug', 'Request mode detection', {
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { GraphQLTemplateGenerator } from './services/mapping/query/graphql-templ
|
|
|
34
34
|
export { MappingError, ResolverError } from './errors/index.js';
|
|
35
35
|
export type { NodeConfig, NodesConfig, FieldConfig, FieldsConfig, NodesContext, MappingContext, ResolverFunction, ResolverHelpers, ResolverContext, ResolversMap, MapResult, MapWithNodesResult, NodeValidationResult, MappingOptions, } from './services/mapping/types/index.js';
|
|
36
36
|
export { CsvDelimiter, FileEncoding, JobStrategy, FileType, BatchAction, EntityType, AwsRegion, ValidationMode, ProcessingStatus, } from './types/enums.js';
|
|
37
|
-
export type { FluentClientConfig, FluentBatchPayload, FluentInventoryBatchEntity, FluentInventoryBatchRequest, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobMetadata, FluentJobStatus, FluentJobResults, FluentEvent, FluentEventMode, CreateEventOptions, GraphQLPayload, GraphQLResponse, GraphQLErrorMode, GraphQLError, PaginationConfig, PageInfo, PaginatedResponse, FluentWebhookPayload, WebhookRequestContext, GraphQLValidationResult, BatchConfiguration, DataSourceConfig, FileMetadata, Logger, StructuredLogger, LogContext, LoggerConfig, PerformanceMetrics, InventoryDataRecord, ParquetDataRecord, FieldMappingConfig, FieldMappingRule, ProcessingMetadata, AttributeValue, } from './types/index.js';
|
|
37
|
+
export type { FluentClientConfig, FluentBatchPayload, FluentInventoryBatchEntity, FluentInventoryBatchRequest, FluentBatchResponse, FluentBatchStatus, FluentJobPayload, FluentJobResponse, FluentJobMetadata, FluentJobStatus, FluentJobResults, FluentEvent, FluentEventMode, CreateEventOptions, FluentEventRootEntityType, FluentEventEntityType, FluentEventCategory, FluentEventType, FluentEventStatus, FluentEventQueryParamValue, FluentEventQueryParams, FluentEventLogAttribute, FluentEventLogContext, FluentEventLogItem, FluentEventLogResponse, GraphQLPayload, GraphQLResponse, GraphQLErrorMode, GraphQLError, PaginationConfig, PageInfo, PaginatedResponse, FluentWebhookPayload, WebhookRequestContext, GraphQLValidationResult, BatchConfiguration, DataSourceConfig, FileMetadata, Logger, StructuredLogger, LogContext, LoggerConfig, PerformanceMetrics, InventoryDataRecord, ParquetDataRecord, FieldMappingConfig, FieldMappingRule, ProcessingMetadata, AttributeValue, } from './types/index.js';
|
|
38
38
|
export type { VersoriContext, WebhookContext, DirectContext } from './types/index.js';
|
|
39
39
|
export { S3SDKTester, S3PresignedTester, S3ComparisonTester, FluentConnectionTester, type TestResult, type FluentTestConfig, type S3TestConfig, } from './testing/index.js';
|
|
40
40
|
export { S3Service, S3ServiceError, type S3ServiceConfig, type S3Config, type S3Object, type ListOptions, type PutOptions, type CopyOptions, type S3Location, } from './services/s3/index.js';
|