@secondlayer/subgraphs 4.1.1 → 4.1.3

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.
@@ -2075,6 +2075,8 @@ function indexEventTypesForFilterTypes(filterTypes) {
2075
2075
  return [...types];
2076
2076
  }
2077
2077
  function referencedIndexEventTypes(subgraph) {
2078
+ if (!subgraph.sources)
2079
+ return [];
2078
2080
  return indexEventTypesForFilterTypes(sourceFilters(subgraph).map((f) => f.type));
2079
2081
  }
2080
2082
  function isStreamsIndexEligible(subgraph) {
@@ -3192,6 +3194,66 @@ function startCatchUpLeader(opts = {}) {
3192
3194
  });
3193
3195
  }
3194
3196
 
3197
+ // src/runtime/decoder-bound.ts
3198
+ import { decodeStreamsCursor, isEmptyRangeCursor } from "@secondlayer/shared";
3199
+ import { getSourceDb as getSourceDb3 } from "@secondlayer/shared/db";
3200
+ function decoderNameForEventType(indexEventType) {
3201
+ return `decode.${indexEventType}.v1`;
3202
+ }
3203
+ function decoderNamesForIndexEventTypes(eventTypes) {
3204
+ return eventTypes.map(decoderNameForEventType);
3205
+ }
3206
+ function decoderNamesForSubgraph(subgraph) {
3207
+ return decoderNamesForIndexEventTypes(referencedIndexEventTypes(subgraph));
3208
+ }
3209
+ function usesDecodedIndexPlane(subgraph) {
3210
+ return process.env.SUBGRAPH_SOURCE === "streams-index" && isStreamsIndexEligible(subgraph);
3211
+ }
3212
+ function committedHeight(cursor) {
3213
+ if (!cursor)
3214
+ return null;
3215
+ try {
3216
+ const decoded = decodeStreamsCursor(cursor);
3217
+ if (isEmptyRangeCursor(decoded))
3218
+ return decoded.block_height;
3219
+ return Math.max(0, decoded.block_height - 1);
3220
+ } catch {
3221
+ return null;
3222
+ }
3223
+ }
3224
+ async function decoderBoundTip(decoderNames, opts) {
3225
+ if (decoderNames.length === 0)
3226
+ return { kind: "unbounded" };
3227
+ const sourceDb = opts?.sourceDb ?? getSourceDb3();
3228
+ const rows = await sourceDb.selectFrom("decoder_checkpoints").select(["decoder_name", "last_cursor"]).where("decoder_name", "in", decoderNames).execute();
3229
+ const byName = new Map(rows.map((r) => [r.decoder_name, r.last_cursor]));
3230
+ const missing = [];
3231
+ const heights = [];
3232
+ for (const name of decoderNames) {
3233
+ const height = committedHeight(byName.get(name));
3234
+ if (height === null)
3235
+ missing.push(name);
3236
+ else
3237
+ heights.push(height);
3238
+ }
3239
+ if (missing.length > 0)
3240
+ return { kind: "stall", missing };
3241
+ return { kind: "height", height: Math.min(...heights) };
3242
+ }
3243
+ async function boundSourceTip(rawTip, decoderNames, opts) {
3244
+ const bound = await decoderBoundTip(decoderNames, opts);
3245
+ if (bound.kind === "stall")
3246
+ return { ok: false, missing: bound.missing };
3247
+ if (bound.kind === "unbounded") {
3248
+ return { ok: true, tip: rawTip, floor: null };
3249
+ }
3250
+ return {
3251
+ ok: true,
3252
+ tip: Math.min(rawTip, bound.height),
3253
+ floor: bound.height
3254
+ };
3255
+ }
3256
+
3195
3257
  // src/runtime/catchup.ts
3196
3258
  var LOG_INTERVAL = 1000;
3197
3259
  var STANDARD_CATCHUP_BATCH_CONFIG = {
@@ -3302,7 +3364,31 @@ async function catchUpSubgraph(subgraph, subgraphName) {
3302
3364
  if (!subgraphRow)
3303
3365
  return 0;
3304
3366
  const lastProcessedBlock = Number(subgraphRow.last_processed_block);
3305
- const chainTip = await source.getTip();
3367
+ const rawTip = await source.getTip();
3368
+ if (rawTip <= 0)
3369
+ return 0;
3370
+ let chainTip = rawTip;
3371
+ if (usesDecodedIndexPlane(subgraph)) {
3372
+ const bound = await boundSourceTip(rawTip, decoderNamesForSubgraph(subgraph));
3373
+ if (!bound.ok) {
3374
+ logger8.warn("Subgraph catch-up stalled: missing decoder checkpoint", {
3375
+ event: "subgraph_catchup_decoder_stall",
3376
+ subgraph: subgraphName,
3377
+ missing: bound.missing
3378
+ });
3379
+ return 0;
3380
+ }
3381
+ if (bound.floor !== null && bound.floor < rawTip) {
3382
+ logger8.debug("Subgraph catch-up tip bounded by decoder progress", {
3383
+ event: "subgraph_catchup_decoder_floor",
3384
+ subgraph: subgraphName,
3385
+ rawTip,
3386
+ floor: bound.floor,
3387
+ tip: bound.tip
3388
+ });
3389
+ }
3390
+ chainTip = bound.tip;
3391
+ }
3306
3392
  if (chainTip <= 0 || lastProcessedBlock >= chainTip)
3307
3393
  return 0;
3308
3394
  const subgraphStart = Number(subgraphRow.start_block) || 1;
@@ -3765,7 +3851,29 @@ async function processBlockRange(def, opts) {
3765
3851
  async function resolveBlockRange(source, def, opts) {
3766
3852
  const definitionStart = def.startBlock ?? 1;
3767
3853
  const fromBlock = opts?.startBlockFloor != null ? Math.max(definitionStart, opts.startBlockFloor) : definitionStart;
3768
- return { fromBlock, toBlock: await source.getTip() };
3854
+ const rawTip = await source.getTip();
3855
+ if (!usesDecodedIndexPlane(def)) {
3856
+ return { fromBlock, toBlock: rawTip };
3857
+ }
3858
+ const bound = await boundSourceTip(rawTip, decoderNamesForSubgraph(def));
3859
+ if (!bound.ok) {
3860
+ logger10.warn("Reindex stalled: missing decoder checkpoint", {
3861
+ event: "subgraph_reindex_decoder_stall",
3862
+ subgraph: def.name,
3863
+ missing: bound.missing
3864
+ });
3865
+ throw new Error(`Reindex stalled: missing decoder checkpoint (${bound.missing.join(", ")})`);
3866
+ }
3867
+ if (bound.floor !== null && bound.floor < rawTip) {
3868
+ logger10.debug("Reindex tip bounded by decoder progress", {
3869
+ event: "subgraph_reindex_decoder_floor",
3870
+ subgraph: def.name,
3871
+ rawTip,
3872
+ floor: bound.floor,
3873
+ tip: bound.tip
3874
+ });
3875
+ }
3876
+ return { fromBlock, toBlock: bound.tip };
3769
3877
  }
3770
3878
  async function clearReindexMetadata(db, subgraphName) {
3771
3879
  await db.updateTable("subgraphs").set({ reindex_from_block: null, reindex_to_block: null }).where("name", "=", subgraphName).execute();
@@ -4555,5 +4663,5 @@ export {
4555
4663
  startSubgraphOperationRunner
4556
4664
  };
4557
4665
 
4558
- //# debugId=DC53F813C2D7B5F564756E2164756E21
4666
+ //# debugId=0FA31971C86CC61564756E2164756E21
4559
4667
  //# sourceMappingURL=processor.js.map