Skip to content

Commit 456c8c8

Browse files
committed
Codex fixes
1 parent d0fc1b6 commit 456c8c8

2 files changed

Lines changed: 68 additions & 15 deletions

File tree

packages/plugin-epcis/docs/EPCIS-Integration-Guide.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,12 @@ Accept an EPCIS Document and queue it for publishing to DKG.
573573
}
574574
```
575575

576-
**Response** (HTTP 202 Accepted):
576+
**Response modes:**
577+
578+
- **HTTP 202 Accepted**: Capture queued in publisher (numeric `captureID`, status is queryable)
579+
- **HTTP 201 Created**: Publisher unavailable, fallback published directly to DKG (`captureID` in `direct-*` format, includes `UAL`)
580+
581+
**Example (HTTP 202 Accepted):**
577582

578583
```json
579584
{
@@ -584,11 +589,27 @@ Accept an EPCIS Document and queue it for publishing to DKG.
584589
}
585590
```
586591

592+
**Example (HTTP 201 Created - direct fallback):**
593+
594+
```json
595+
{
596+
"status": "201",
597+
"receivedAt": "2024-03-01T08:00:01.123Z",
598+
"captureID": "direct-1709280001123",
599+
"eventCount": 1,
600+
"UAL": "did:dkg:otp/0x1234.../789"
601+
}
602+
```
603+
587604
---
588605

589606
### GET `/epcis/capture/:captureID`
590607

591-
Check the status of a previously submitted capture.
608+
Check the status of a previously submitted capture tracked by the publisher.
609+
610+
> **Note:** This endpoint accepts numeric publisher `captureID` values.
611+
> Direct fallback IDs (`direct-*`) are not tracked by publisher status API.
612+
> For fallback captures, use the returned `UAL` with `GET /epcis/asset/*ual`.
592613
593614
**Response:**
594615

@@ -623,13 +644,13 @@ Query EPCIS events from the DKG.
623644
| `to` | string (ISO 8601) | End of time range | `2024-03-31T23:59:59Z` |
624645
| `bizStep` | string | Filter by business step | `assembling` or full URI |
625646
| `bizLocation` | string | Filter by location | `urn:epc:id:sgln:4012345.00002.0` |
626-
| `fullTrace` | string | Search all EPC fields | `true` |
647+
| `fullTrace` | string enum | Must be `"true"` or `"false"` | `true` |
627648
| `parentID` | string | Filter by parent EPC (AggregationEvent) | `urn:epc:id:sscc:...` |
628649
| `childEPC` | string | Filter by child EPC (AggregationEvent) | `urn:epc:id:sgtin:...` |
629650
| `inputEPC` | string | Filter by input EPC (TransformationEvent) | `urn:epc:id:sgtin:...` |
630651
| `outputEPC` | string | Filter by output EPC (TransformationEvent) | `urn:epc:id:sgtin:...` |
631-
| `limit` | number | Results per page (default: 100, max: 1000) | `50` |
632-
| `offset` | number | Results to skip (pagination) | `0` |
652+
| `limit` | integer | Results per page (default: 100, range: 1-1000) | `50` |
653+
| `offset` | integer | Results to skip (pagination, min: 0) | `0` |
633654

634655
**Response:**
635656

packages/plugin-epcis/src/index.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { EpcisQueryService } from "./services/EPCISQueryService";
55
import { formatSourceKAs } from "./utils/sourceKA";
66
import type { CaptureResponse } from "./model/types";
77

8-
// Timeout for internal publisher requests (30s for POST, 5s for GET)
8+
// Timeout for internal publisher requests (10s for POST, 5s for GET)
99
const PUBLISHER_POST_TIMEOUT_MS = 10000;
1010
const PUBLISHER_GET_TIMEOUT_MS = 5000;
1111

@@ -368,10 +368,12 @@ export default defineDkgPlugin((ctx, mcp, api) => {
368368
{
369369
tag: "EPCIS",
370370
summary: "Get Capture Status",
371-
description: "Check the status of an EPCIS capture by captureID",
371+
description:
372+
"Check publisher-tracked status by numeric captureID. " +
373+
"Direct fallback IDs (direct-*) are published directly to DKG and are not tracked by this endpoint.",
372374
params: z.object({
373375
captureID: z.string().openapi({
374-
description: "The capture ID returned from POST /epcis/capture",
376+
description: "Numeric publisher capture ID returned from POST /epcis/capture",
375377
example: "123",
376378
}),
377379
}),
@@ -392,6 +394,16 @@ export default defineDkgPlugin((ctx, mcp, api) => {
392394
const publisherUrl = process.env.PUBLISHER_URL || "http://localhost:9200";
393395

394396
const captureIdPattern = /^[0-9]{1,20}$/;
397+
const directCaptureIdPattern = /^direct-[0-9]+$/;
398+
399+
if (directCaptureIdPattern.test(captureID)) {
400+
return res.status(400).json({
401+
error: "Direct fallback capture IDs are not tracked by publisher status API",
402+
message: "This capture was published directly to DKG. Use the returned UAL to retrieve the asset.",
403+
captureID,
404+
} as any);
405+
}
406+
395407
if (!captureIdPattern.test(captureID)) {
396408
return res.status(400).json({
397409
error: "Invalid captureID format",
@@ -474,7 +486,7 @@ export default defineDkgPlugin((ctx, mcp, api) => {
474486
description: "Filter by business location",
475487
example: "urn:epc:id:sgln:0614141.00001.0",
476488
}),
477-
fullTrace: z.string().optional().openapi({
489+
fullTrace: z.enum(["true", "false"]).optional().openapi({
478490
description: "If 'true', search all EPC fields for full supply chain traceability",
479491
example: "true",
480492
}),
@@ -531,6 +543,26 @@ export default defineDkgPlugin((ctx, mcp, api) => {
531543
}
532544
}
533545

546+
// Parse + validate pagination params
547+
const parsedLimit =
548+
typeof limit === "string" && limit.length > 0 ? Number.parseInt(limit, 10) : undefined;
549+
const parsedOffset =
550+
typeof offset === "string" && offset.length > 0 ? Number.parseInt(offset, 10) : undefined;
551+
552+
if (parsedLimit !== undefined && (!Number.isInteger(parsedLimit) || parsedLimit < 1 || parsedLimit > 1000)) {
553+
return res.status(400).json({
554+
success: false,
555+
error: "Parameter 'limit' must be an integer between 1 and 1000",
556+
} as any);
557+
}
558+
559+
if (parsedOffset !== undefined && (!Number.isInteger(parsedOffset) || parsedOffset < 0)) {
560+
return res.status(400).json({
561+
success: false,
562+
error: "Parameter 'offset' must be a non-negative integer",
563+
} as any);
564+
}
565+
534566
// Build the SPARQL query based on parameters
535567
const sparqlQuery = queryService.buildQuery({
536568
epc: epc as string,
@@ -543,8 +575,8 @@ export default defineDkgPlugin((ctx, mcp, api) => {
543575
childEPC: childEPC as string,
544576
inputEPC: inputEPC as string,
545577
outputEPC: outputEPC as string,
546-
limit: limit ? parseInt(limit as string, 10) : undefined,
547-
offset: offset ? parseInt(offset as string, 10) : undefined,
578+
limit: parsedLimit,
579+
offset: parsedOffset,
548580
});
549581

550582
console.log("[EPCIS Events] Executing SPARQL query:", sparqlQuery);
@@ -553,13 +585,13 @@ export default defineDkgPlugin((ctx, mcp, api) => {
553585
const results = await ctx.dkg.graph.query(sparqlQuery, "SELECT");
554586

555587
// Calculate pagination values
556-
const effectiveLimit = Math.min(limit ? parseInt(limit as string, 10) : 100, 1000);
557-
const effectiveOffset = offset ? parseInt(offset as string, 10) : 0;
558-
const resultCount = results?.length || 0;
588+
const effectiveLimit = parsedLimit ?? 100;
589+
const effectiveOffset = parsedOffset ?? 0;
590+
const resultCount = results?.data?.length || 0;
559591

560592
res.json({
561593
success: true,
562-
results: results || [],
594+
results: results?.data || [],
563595
count: resultCount,
564596
pagination: {
565597
limit: effectiveLimit,

0 commit comments

Comments
 (0)