@@ -309,6 +309,18 @@ const defaultFetchSideshiftOrders: FetchSideshiftOrders = async (
309309 return asSideshiftResult ( jsonObj )
310310}
311311
312+ // Reads only the timestamp from a raw order. Used to advance an account's
313+ // cursor past an order that processOrder rejects (e.g. an unmapped coin or
314+ // network), so a page of only unprocessable orders can never stall the query
315+ // window. Returns undefined when the raw order has no usable createdAt.
316+ const asRawOrderDate = asMaybe ( asObject ( { createdAt : asString } ) )
317+
318+ const rawOrderIsoDate = ( rawTx : unknown ) : string | undefined => {
319+ const parsed = asRawOrderDate ( rawTx )
320+ if ( parsed == null ) return undefined
321+ return smartIsoDateFromTimestamp ( parsed . createdAt ) . isoDate
322+ }
323+
312324// Queries the completed orders for a single affiliate account, advancing its
313325// own cursor. Mirrors the original per-account query/signature/retry/time-block
314326// behavior exactly; only the fetch + per-order processing are abstracted so the
@@ -347,18 +359,28 @@ async function querySideshiftAccount(
347359 // the plugin maps) must not stall the account. Without skipping, the
348360 // throw aborts the page, the cursor never advances past it, and the
349361 // account retries-then-gives-up every cycle forever. Log the gap so
350- // it can be mapped, then move on.
362+ // it can be mapped, then advance the cursor past this order's own
363+ // timestamp so the window still moves forward even when an entire
364+ // page is unprocessable.
351365 log . warn (
352366 `${ account . affiliateId } skipping unprocessable order: ${ String ( e ) } `
353367 )
368+ const skippedIsoDate = rawOrderIsoDate ( rawTx )
369+ if ( skippedIsoDate != null && skippedIsoDate > latestIsoDate ) {
370+ latestIsoDate = skippedIsoDate
371+ }
354372 continue
355373 }
356374 standardTxs . push ( standardTx )
357375 if ( standardTx . isoDate > latestIsoDate ) {
358376 latestIsoDate = standardTx . isoDate
359377 }
360378 }
361- startTime = new Date ( latestIsoDate ) . getTime ( )
379+ const advancedTime = new Date ( latestIsoDate ) . getTime ( )
380+ // Guarantee forward progress even if every order in this block was skipped
381+ // without a usable timestamp, so the window can never spin on the same
382+ // startTime until the engine timeout.
383+ startTime = advancedTime > startTime ? advancedTime : endTime
362384 log ( `${ account . affiliateId } latestIsoDate ${ latestIsoDate } ` )
363385 if ( endTime > now ) {
364386 break
0 commit comments