@@ -5,7 +5,7 @@ import { EpcisQueryService } from "./services/EPCISQueryService";
55import { formatSourceKAs } from "./utils/sourceKA" ;
66import 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)
99const PUBLISHER_POST_TIMEOUT_MS = 10000 ;
1010const 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 = / ^ d i r e c t - [ 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