@secondlayer/subgraphs 3.26.0 → 3.26.2

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/dist/src/index.js CHANGED
@@ -820,14 +820,10 @@ class SubgraphContext {
820
820
  this.ops.length = 0;
821
821
  const statements = this.buildStatements(opsToFlush);
822
822
  if ("isTransaction" in this.db) {
823
- for (const stmt of statements) {
824
- await sql.raw(stmt).execute(this.db);
825
- }
823
+ await this.execStatements(this.db, statements);
826
824
  } else {
827
825
  await this.db.transaction().execute(async (tx) => {
828
- for (const stmt of statements) {
829
- await sql.raw(stmt).execute(tx);
830
- }
826
+ await this.execStatements(tx, statements);
831
827
  });
832
828
  }
833
829
  const writes = opsToFlush.map((op, rowIndex) => {
@@ -846,6 +842,25 @@ class SubgraphContext {
846
842
  });
847
843
  return { count: opsToFlush.length, writes };
848
844
  }
845
+ async execStatements(executor, statements) {
846
+ const affected = (r) => r.numAffectedRows ?? 0n;
847
+ for (const stmt of statements) {
848
+ if (typeof stmt === "string") {
849
+ await sql.raw(stmt).execute(executor);
850
+ continue;
851
+ }
852
+ const updated = await sql.raw(stmt.update).execute(executor);
853
+ if (affected(updated) > 0n)
854
+ continue;
855
+ const inserted = await sql.raw(stmt.insert).execute(executor);
856
+ if (affected(inserted) > 0n)
857
+ continue;
858
+ const retried = await sql.raw(stmt.update).execute(executor);
859
+ if (affected(retried) === 0n) {
860
+ throw new Error(`increment could not be applied to ${this.pgSchemaName}.${stmt.table} where ${stmt.keyPred}: row neither updated nor inserted`);
861
+ }
862
+ }
863
+ }
849
864
  prepareInsert(op) {
850
865
  const upsertKeys = op.data._upsert_keys;
851
866
  const data = { ...op.data };
@@ -925,7 +940,6 @@ class SubgraphContext {
925
940
  for (const r of batch.rows.values()) {
926
941
  const keyPred = batch.keyCols.map((k) => `"${k}" = ${escapeLiteral(r.keys[k])}`).join(" AND ");
927
942
  const updSet = batch.deltaCols.map((c) => `"${c}" = COALESCE("${c}", 0) + (${String(r.deltas[c] ?? 0n)})`).join(", ");
928
- statements.push(`UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`);
929
943
  const insertVals = [
930
944
  ...batch.keyCols.map((k) => escapeLiteral(r.keys[k])),
931
945
  ...batch.deltaCols.map((c) => String(r.deltas[c] ?? 0n)),
@@ -933,7 +947,13 @@ class SubgraphContext {
933
947
  escapeLiteral(r.meta.txId),
934
948
  "NOW()"
935
949
  ];
936
- statements.push(`INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) ` + `SELECT ${insertVals.join(", ")} ` + `WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`);
950
+ statements.push({
951
+ kind: "increment",
952
+ table: batch.table,
953
+ keyPred,
954
+ update: `UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`,
955
+ insert: `INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) ` + `SELECT ${insertVals.join(", ")} ` + `WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`
956
+ });
937
957
  }
938
958
  incBatch = null;
939
959
  incBatchKey = "";
@@ -3239,9 +3259,278 @@ class StatsAccumulator {
3239
3259
  }
3240
3260
  }
3241
3261
 
3262
+ // src/runtime/catchup.ts
3263
+ import { getTargetDb as getTargetDb2, sql as sql4 } from "@secondlayer/shared/db";
3264
+ import { getSubgraph } from "@secondlayer/shared/db/queries/subgraphs";
3265
+ import { logger as logger8 } from "@secondlayer/shared/logger";
3266
+
3267
+ // src/runtime/catchup-leader.ts
3268
+ import {
3269
+ SUBGRAPH_CATCHUP_LOCK_KEY,
3270
+ createPostgresLeaderBackend,
3271
+ withLeaderLock
3272
+ } from "@secondlayer/shared/leader";
3273
+ import { targetListenerUrl } from "@secondlayer/shared/queue/listener";
3274
+ var catchUpLeader = false;
3275
+ function isCatchUpLeader() {
3276
+ return catchUpLeader;
3277
+ }
3278
+ function startCatchUpLeader(opts = {}) {
3279
+ return withLeaderLock(SUBGRAPH_CATCHUP_LOCK_KEY, async () => {
3280
+ catchUpLeader = true;
3281
+ await opts.onAcquire?.();
3282
+ return () => {
3283
+ catchUpLeader = false;
3284
+ };
3285
+ }, {
3286
+ pollMs: opts.pollMs,
3287
+ heartbeatMs: opts.heartbeatMs,
3288
+ createBackend: opts.createBackend ?? (() => createPostgresLeaderBackend(targetListenerUrl()))
3289
+ });
3290
+ }
3291
+
3292
+ // src/runtime/catchup.ts
3293
+ var LOG_INTERVAL = 1000;
3294
+ var STANDARD_CATCHUP_BATCH_CONFIG = {
3295
+ defaultBatchSize: 500,
3296
+ minBatchSize: 100,
3297
+ maxBatchSize: 1000,
3298
+ prefetch: true
3299
+ };
3300
+ var catchingUp = new Set;
3301
+ var subgraphBlockLockHeld = new Set;
3302
+ var subgraphBlockLockWaiters = new Map;
3303
+ var reorgEpoch = new Map;
3304
+ async function acquireSubgraphBlockLock(name) {
3305
+ if (!subgraphBlockLockHeld.has(name)) {
3306
+ subgraphBlockLockHeld.add(name);
3307
+ return () => releaseSubgraphBlockLock(name);
3308
+ }
3309
+ return new Promise((resolve) => {
3310
+ const waiters = subgraphBlockLockWaiters.get(name) ?? [];
3311
+ waiters.push(() => resolve(() => releaseSubgraphBlockLock(name)));
3312
+ subgraphBlockLockWaiters.set(name, waiters);
3313
+ });
3314
+ }
3315
+ function releaseSubgraphBlockLock(name) {
3316
+ const waiters = subgraphBlockLockWaiters.get(name);
3317
+ if (waiters && waiters.length > 0) {
3318
+ const next = waiters.shift();
3319
+ if (waiters.length === 0)
3320
+ subgraphBlockLockWaiters.delete(name);
3321
+ next();
3322
+ return;
3323
+ }
3324
+ subgraphBlockLockHeld.delete(name);
3325
+ }
3326
+ async function withSubgraphBlockLock(name, fn) {
3327
+ const release = await acquireSubgraphBlockLock(name);
3328
+ try {
3329
+ return await fn();
3330
+ } finally {
3331
+ release();
3332
+ }
3333
+ }
3334
+ async function withSubgraphBlockAdvisoryLock(name, fn) {
3335
+ return getTargetDb2().transaction().execute(async (lockTx) => {
3336
+ await sql4`SELECT pg_advisory_xact_lock(hashtext(${`subgraph-block:${name}`}))`.execute(lockTx);
3337
+ return fn();
3338
+ });
3339
+ }
3340
+ async function withSubgraphBlockWriteLock(name, fn) {
3341
+ return withSubgraphBlockLock(name, () => withSubgraphBlockAdvisoryLock(name, fn));
3342
+ }
3343
+ function bumpReorgEpoch(name) {
3344
+ reorgEpoch.set(name, (reorgEpoch.get(name) ?? 0) + 1);
3345
+ }
3346
+ function getReorgEpoch(name) {
3347
+ return reorgEpoch.get(name) ?? 0;
3348
+ }
3349
+
3350
+ class ReorgEpochChangedError extends Error {
3351
+ constructor(name) {
3352
+ super(`reorg epoch changed for ${name} mid catch-up`);
3353
+ this.name = "ReorgEpochChangedError";
3354
+ }
3355
+ }
3356
+ function parsePositiveInt(value) {
3357
+ if (value == null || value.trim() === "")
3358
+ return;
3359
+ const parsed = Number.parseInt(value, 10);
3360
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
3361
+ }
3362
+ function parseBoolean(value) {
3363
+ if (value == null || value.trim() === "")
3364
+ return;
3365
+ const normalized = value.trim().toLowerCase();
3366
+ if (normalized === "true")
3367
+ return true;
3368
+ if (normalized === "false")
3369
+ return false;
3370
+ return;
3371
+ }
3372
+ function resolveCatchupBatchConfig(env = process.env) {
3373
+ const base = STANDARD_CATCHUP_BATCH_CONFIG;
3374
+ const minBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_MIN_BATCH_SIZE) ?? base.minBatchSize;
3375
+ const maxBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_MAX_BATCH_SIZE) ?? base.maxBatchSize;
3376
+ const defaultBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_BATCH_SIZE) ?? base.defaultBatchSize;
3377
+ return {
3378
+ minBatchSize,
3379
+ maxBatchSize,
3380
+ defaultBatchSize: Math.min(Math.max(defaultBatchSize, minBatchSize), maxBatchSize),
3381
+ prefetch: parseBoolean(env.SUBGRAPH_CATCHUP_PREFETCH) ?? base.prefetch
3382
+ };
3383
+ }
3384
+ function adjustBatchSize(current, avgEvents, config) {
3385
+ if (avgEvents > 50)
3386
+ return Math.max(Math.round(current * 0.5), config.minBatchSize);
3387
+ if (avgEvents < 10)
3388
+ return Math.min(Math.round(current * 1.5), config.maxBatchSize);
3389
+ return current;
3390
+ }
3391
+ async function catchUpSubgraph(subgraph, subgraphName) {
3392
+ if (catchingUp.has(subgraphName))
3393
+ return 0;
3394
+ catchingUp.add(subgraphName);
3395
+ try {
3396
+ const source = resolveBlockSource(subgraph);
3397
+ const targetDb = getTargetDb2();
3398
+ const subgraphRow = await getSubgraph(targetDb, subgraphName);
3399
+ if (!subgraphRow)
3400
+ return 0;
3401
+ const lastProcessedBlock = Number(subgraphRow.last_processed_block);
3402
+ const chainTip = await source.getTip();
3403
+ if (chainTip <= 0 || lastProcessedBlock >= chainTip)
3404
+ return 0;
3405
+ const subgraphStart = Number(subgraphRow.start_block) || 1;
3406
+ const startBlock = Math.max(lastProcessedBlock + 1, subgraphStart);
3407
+ const totalBlocks = chainTip - lastProcessedBlock;
3408
+ logger8.info("Subgraph catch-up starting", {
3409
+ subgraph: subgraphName,
3410
+ from: startBlock,
3411
+ to: chainTip,
3412
+ blocks: totalBlocks
3413
+ });
3414
+ const stats = new StatsAccumulator(subgraphName, true);
3415
+ let processed = 0;
3416
+ const batchConfig = resolveCatchupBatchConfig();
3417
+ let batchSize = batchConfig.defaultBatchSize;
3418
+ let currentHeight = startBlock;
3419
+ const walkEpoch = getReorgEpoch(subgraphName);
3420
+ let prefetchedBatchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
3421
+ let nextBatchPromise = batchConfig.prefetch ? source.loadBlockRange(currentHeight, prefetchedBatchEnd) : undefined;
3422
+ while (currentHeight <= chainTip) {
3423
+ if (!isCatchUpLeader()) {
3424
+ logger8.info("Lost catch-up leadership, stopping catch-up", {
3425
+ subgraph: subgraphName,
3426
+ processed
3427
+ });
3428
+ break;
3429
+ }
3430
+ const currentRow = await getSubgraph(targetDb, subgraphName);
3431
+ if (!currentRow || currentRow.status !== "active") {
3432
+ logger8.info("Subgraph status changed, stopping catch-up", {
3433
+ subgraph: subgraphName,
3434
+ status: currentRow?.status ?? "deleted"
3435
+ });
3436
+ break;
3437
+ }
3438
+ let batchEnd;
3439
+ let batch;
3440
+ if (nextBatchPromise) {
3441
+ batch = await nextBatchPromise;
3442
+ batchEnd = prefetchedBatchEnd;
3443
+ const nextStart = batchEnd + 1;
3444
+ if (nextStart <= chainTip) {
3445
+ prefetchedBatchEnd = Math.min(nextStart + batchSize - 1, chainTip);
3446
+ nextBatchPromise = source.loadBlockRange(nextStart, prefetchedBatchEnd);
3447
+ } else {
3448
+ nextBatchPromise = undefined;
3449
+ }
3450
+ } else {
3451
+ batchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
3452
+ batch = await source.loadBlockRange(currentHeight, batchEnd);
3453
+ }
3454
+ let stopCatchup = false;
3455
+ for (let height = currentHeight;height <= batchEnd; height++) {
3456
+ let blockData = batch.get(height);
3457
+ if (!blockData) {
3458
+ blockData = (await source.loadBlockRange(height, height)).get(height);
3459
+ }
3460
+ if (!blockData) {
3461
+ logger8.warn("Block missing during catch-up, deferring to next tick", {
3462
+ subgraph: subgraphName,
3463
+ blockHeight: height
3464
+ });
3465
+ stopCatchup = true;
3466
+ break;
3467
+ }
3468
+ const preloaded = blockData;
3469
+ let result;
3470
+ try {
3471
+ result = await withSubgraphBlockWriteLock(subgraphName, async () => {
3472
+ if (getReorgEpoch(subgraphName) !== walkEpoch) {
3473
+ throw new ReorgEpochChangedError(subgraphName);
3474
+ }
3475
+ return processBlockWithRetry(subgraph, subgraphName, height, {
3476
+ preloaded
3477
+ });
3478
+ });
3479
+ } catch (err) {
3480
+ if (err instanceof ReorgEpochChangedError) {
3481
+ logger8.info("Reorg detected mid catch-up, aborting walk without writing further progress", { subgraph: subgraphName, blockHeight: height });
3482
+ stopCatchup = true;
3483
+ break;
3484
+ }
3485
+ const errorMsg = err instanceof Error ? err.message : String(err);
3486
+ logger8.error("Block processing failed persistently during catch-up", {
3487
+ subgraph: subgraphName,
3488
+ blockHeight: height,
3489
+ error: errorMsg
3490
+ });
3491
+ const { updateSubgraphStatus: updateSubgraphStatus2, recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
3492
+ await recordSubgraphProcessed2(targetDb, subgraphName, 0, 1, `catch-up halted at block ${height}: ${errorMsg}`).catch(() => {});
3493
+ await updateSubgraphStatus2(targetDb, subgraphName, "error").catch(() => {});
3494
+ stopCatchup = true;
3495
+ break;
3496
+ }
3497
+ processed++;
3498
+ if (result.timing) {
3499
+ stats.record(result.timing, result.processed);
3500
+ if (stats.shouldFlush()) {
3501
+ await stats.flush(targetDb);
3502
+ }
3503
+ }
3504
+ if (processed % LOG_INTERVAL === 0) {
3505
+ logger8.info("Subgraph catch-up progress", {
3506
+ subgraph: subgraphName,
3507
+ processed,
3508
+ total: totalBlocks,
3509
+ currentBlock: height,
3510
+ pct: Math.round(processed / totalBlocks * 100)
3511
+ });
3512
+ }
3513
+ }
3514
+ if (stopCatchup)
3515
+ break;
3516
+ const avg = avgEventsPerBlock(batch);
3517
+ batchSize = adjustBatchSize(batchSize, avg, batchConfig);
3518
+ currentHeight = batchEnd + 1;
3519
+ }
3520
+ await stats.flush(targetDb);
3521
+ logger8.info("Subgraph catch-up complete", {
3522
+ subgraph: subgraphName,
3523
+ processed
3524
+ });
3525
+ return processed;
3526
+ } finally {
3527
+ catchingUp.delete(subgraphName);
3528
+ }
3529
+ }
3530
+
3242
3531
  // src/runtime/reindex.ts
3243
3532
  import { getErrorMessage as getErrorMessage3 } from "@secondlayer/shared";
3244
- import { getRawClient, getTargetDb as getTargetDb2 } from "@secondlayer/shared/db";
3533
+ import { getRawClient, getTargetDb as getTargetDb3 } from "@secondlayer/shared/db";
3245
3534
  import {
3246
3535
  recordGapBatch,
3247
3536
  resolveGaps
@@ -3254,11 +3543,11 @@ import {
3254
3543
  recordSubgraphProcessed as recordSubgraphProcessed2,
3255
3544
  updateSubgraphStatus as updateSubgraphStatus2
3256
3545
  } from "@secondlayer/shared/db/queries/subgraphs";
3257
- import { logger as logger9 } from "@secondlayer/shared/logger";
3546
+ import { logger as logger10 } from "@secondlayer/shared/logger";
3258
3547
 
3259
3548
  // src/runtime/reindex-notify.ts
3260
3549
  import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
3261
- import { logger as logger8 } from "@secondlayer/shared/logger";
3550
+ import { logger as logger9 } from "@secondlayer/shared/logger";
3262
3551
  async function notifyReindexComplete(db, subgraphName, stats) {
3263
3552
  try {
3264
3553
  const subgraph = await db.selectFrom("subgraphs").select(["account_id"]).where("name", "=", subgraphName).executeTakeFirst();
@@ -3269,7 +3558,7 @@ async function notifyReindexComplete(db, subgraphName, stats) {
3269
3558
  return;
3270
3559
  const resendKey = process.env.RESEND_API_KEY;
3271
3560
  if (!resendKey) {
3272
- logger8.warn("RESEND_API_KEY unset — skipping reindex-complete email", {
3561
+ logger9.warn("RESEND_API_KEY unset — skipping reindex-complete email", {
3273
3562
  subgraph: subgraphName
3274
3563
  });
3275
3564
  return;
@@ -3291,14 +3580,14 @@ async function notifyReindexComplete(db, subgraphName, stats) {
3291
3580
  });
3292
3581
  if (!res.ok) {
3293
3582
  const text = await res.text().catch(() => "");
3294
- logger8.warn("reindex-complete email failed", {
3583
+ logger9.warn("reindex-complete email failed", {
3295
3584
  subgraph: subgraphName,
3296
3585
  status: res.status,
3297
3586
  body: text.slice(0, 200)
3298
3587
  });
3299
3588
  }
3300
3589
  } catch (err) {
3301
- logger8.warn("reindex-complete email threw", {
3590
+ logger9.warn("reindex-complete email threw", {
3302
3591
  subgraph: subgraphName,
3303
3592
  error: getErrorMessage2(err)
3304
3593
  });
@@ -3306,7 +3595,7 @@ async function notifyReindexComplete(db, subgraphName, stats) {
3306
3595
  }
3307
3596
 
3308
3597
  // src/runtime/reindex.ts
3309
- var LOG_INTERVAL = 1000;
3598
+ var LOG_INTERVAL2 = 1000;
3310
3599
  var HEALTH_FLUSH_INTERVAL = 1000;
3311
3600
  var PROGRESS_FLUSH_INTERVAL_MS = 5000;
3312
3601
  var EMPTY_BATCH_HALT_THRESHOLD = 3;
@@ -3326,7 +3615,7 @@ function resolveReindexResumeBlock(row) {
3326
3615
  const reindexFromBlock = Number(row.reindex_from_block);
3327
3616
  return Math.max(lastProcessedBlock + 1, reindexFromBlock);
3328
3617
  }
3329
- function parsePositiveInt(value) {
3618
+ function parsePositiveInt2(value) {
3330
3619
  if (value == null || value.trim() === "")
3331
3620
  return;
3332
3621
  const parsed = Number.parseInt(value, 10);
@@ -3334,9 +3623,9 @@ function parsePositiveInt(value) {
3334
3623
  }
3335
3624
  function resolveReindexBatchConfig(env = process.env) {
3336
3625
  const base = STANDARD_REINDEX_BATCH_CONFIG;
3337
- const minBatchSize = parsePositiveInt(env.SUBGRAPH_REINDEX_MIN_BATCH_SIZE) ?? base.minBatchSize;
3338
- const maxBatchSize = parsePositiveInt(env.SUBGRAPH_REINDEX_MAX_BATCH_SIZE) ?? base.maxBatchSize;
3339
- const defaultBatchSize = parsePositiveInt(env.SUBGRAPH_REINDEX_BATCH_SIZE) ?? base.defaultBatchSize;
3626
+ const minBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_MIN_BATCH_SIZE) ?? base.minBatchSize;
3627
+ const maxBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_MAX_BATCH_SIZE) ?? base.maxBatchSize;
3628
+ const defaultBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_BATCH_SIZE) ?? base.defaultBatchSize;
3340
3629
  return {
3341
3630
  minBatchSize,
3342
3631
  maxBatchSize,
@@ -3367,7 +3656,7 @@ function coalesceFailedBlocks(blocks) {
3367
3656
  }
3368
3657
  async function processBlockRange(def, opts) {
3369
3658
  const source = resolveBlockSource(def);
3370
- const targetDb = getTargetDb2();
3659
+ const targetDb = getTargetDb3();
3371
3660
  const subgraphName = def.name;
3372
3661
  const { fromBlock, toBlock, status } = opts;
3373
3662
  const totalBlocks = toBlock - fromBlock + 1;
@@ -3410,7 +3699,7 @@ async function processBlockRange(def, opts) {
3410
3699
  while (currentHeight <= toBlock) {
3411
3700
  if (opts.signal?.aborted) {
3412
3701
  aborted = true;
3413
- logger9.info("Block processing aborted", {
3702
+ logger10.info("Block processing aborted", {
3414
3703
  subgraph: subgraphName,
3415
3704
  currentBlock: currentHeight,
3416
3705
  reason: String(opts.signal.reason ?? "unknown")
@@ -3452,14 +3741,16 @@ async function processBlockRange(def, opts) {
3452
3741
  }
3453
3742
  let result;
3454
3743
  try {
3455
- result = await processBlockWithRetry(def, subgraphName, height, {
3744
+ const mayWrite = blockData.txs.length > 0 || blockData.events.length > 0;
3745
+ const runBlock = () => processBlockWithRetry(def, subgraphName, height, {
3456
3746
  skipProgressUpdate: true,
3457
3747
  atomicProgress,
3458
3748
  preloaded: blockData
3459
3749
  });
3750
+ result = mayWrite ? await withSubgraphBlockWriteLock(subgraphName, runBlock) : await runBlock();
3460
3751
  } catch (err) {
3461
3752
  const errorMsg = getErrorMessage3(err);
3462
- logger9.error("Block processing failed persistently", {
3753
+ logger10.error("Block processing failed persistently", {
3463
3754
  subgraph: subgraphName,
3464
3755
  blockHeight: height,
3465
3756
  error: errorMsg
@@ -3504,8 +3795,8 @@ async function processBlockRange(def, opts) {
3504
3795
  }
3505
3796
  lastProgressFlushAt = now;
3506
3797
  }
3507
- if (blocksProcessed % LOG_INTERVAL === 0) {
3508
- logger9.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
3798
+ if (blocksProcessed % LOG_INTERVAL2 === 0) {
3799
+ logger10.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
3509
3800
  subgraph: subgraphName,
3510
3801
  processed: blocksProcessed,
3511
3802
  total: totalBlocks,
@@ -3525,7 +3816,7 @@ async function processBlockRange(def, opts) {
3525
3816
  if (batchFailedBlocks.length > 0 && opts.subgraphId) {
3526
3817
  const gaps = coalesceFailedBlocks(batchFailedBlocks);
3527
3818
  await recordGapBatch(targetDb, opts.subgraphId, subgraphName, gaps).catch((err) => {
3528
- logger9.warn("Failed to record subgraph gaps", {
3819
+ logger10.warn("Failed to record subgraph gaps", {
3529
3820
  subgraph: subgraphName,
3530
3821
  error: err instanceof Error ? err.message : String(err)
3531
3822
  });
@@ -3542,7 +3833,7 @@ async function processBlockRange(def, opts) {
3542
3833
  } else {
3543
3834
  await updateSubgraphStatus2(targetDb, subgraphName, status, jumpTo - 1);
3544
3835
  }
3545
- logger9.info("Sparse skip", {
3836
+ logger10.info("Sparse skip", {
3546
3837
  subgraph: subgraphName,
3547
3838
  from: batchEnd + 1,
3548
3839
  to: jumpTo - 1,
@@ -3577,16 +3868,16 @@ async function clearReindexMetadata(db, subgraphName) {
3577
3868
  }
3578
3869
  async function reindexSubgraph(def, opts) {
3579
3870
  const source = resolveBlockSource(def);
3580
- const targetDb = getTargetDb2();
3871
+ const targetDb = getTargetDb3();
3581
3872
  const client = getRawClient("target");
3582
3873
  const subgraphName = def.name;
3583
3874
  const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);
3584
3875
  await updateSubgraphStatus2(targetDb, subgraphName, "reindexing");
3585
- logger9.info("Reindex starting", { subgraph: subgraphName });
3876
+ logger10.info("Reindex starting", { subgraph: subgraphName });
3586
3877
  try {
3587
3878
  const { fromBlock, toBlock } = await resolveBlockRange(source, def, opts);
3588
3879
  if (fromBlock > toBlock) {
3589
- logger9.info("No blocks to reindex", {
3880
+ logger10.info("No blocks to reindex", {
3590
3881
  subgraph: subgraphName,
3591
3882
  fromBlock,
3592
3883
  toBlock
@@ -3600,7 +3891,7 @@ async function reindexSubgraph(def, opts) {
3600
3891
  await client.unsafe(stmt);
3601
3892
  }
3602
3893
  await updateSubgraphStatus2(targetDb, subgraphName, "reindexing", Math.max(0, fromBlock - 1));
3603
- logger9.info("Schema recreated for reindex", {
3894
+ logger10.info("Schema recreated for reindex", {
3604
3895
  subgraph: subgraphName,
3605
3896
  cursorResetTo: Math.max(0, fromBlock - 1)
3606
3897
  });
@@ -3614,7 +3905,7 @@ async function reindexSubgraph(def, opts) {
3614
3905
  last_error_at: null,
3615
3906
  updated_at: new Date
3616
3907
  }).where("name", "=", subgraphName).execute();
3617
- logger9.info("Reindexing blocks", {
3908
+ logger10.info("Reindexing blocks", {
3618
3909
  subgraph: subgraphName,
3619
3910
  fromBlock,
3620
3911
  toBlock,
@@ -3636,9 +3927,9 @@ async function reindexSubgraph(def, opts) {
3636
3927
  if (reason === "user-cancelled") {
3637
3928
  await updateSubgraphStatus2(targetDb, subgraphName, "active");
3638
3929
  await clearReindexMetadata(targetDb, subgraphName);
3639
- logger9.info("Reindex cancelled by user", { subgraph: subgraphName });
3930
+ logger10.info("Reindex cancelled by user", { subgraph: subgraphName });
3640
3931
  } else {
3641
- logger9.info("Reindex interrupted by shutdown, will resume", {
3932
+ logger10.info("Reindex interrupted by shutdown, will resume", {
3642
3933
  subgraph: subgraphName
3643
3934
  });
3644
3935
  }
@@ -3646,7 +3937,7 @@ async function reindexSubgraph(def, opts) {
3646
3937
  }
3647
3938
  await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
3648
3939
  await clearReindexMetadata(targetDb, subgraphName);
3649
- logger9.info("Reindex complete", {
3940
+ logger10.info("Reindex complete", {
3650
3941
  subgraph: subgraphName,
3651
3942
  blocks: result.blocksProcessed,
3652
3943
  events: result.totalEventsProcessed,
@@ -3659,7 +3950,7 @@ async function reindexSubgraph(def, opts) {
3659
3950
  });
3660
3951
  return { processed: result.blocksProcessed };
3661
3952
  } catch (err) {
3662
- logger9.error("Reindex failed", {
3953
+ logger10.error("Reindex failed", {
3663
3954
  subgraph: subgraphName,
3664
3955
  error: getErrorMessage3(err)
3665
3956
  });
@@ -3668,7 +3959,7 @@ async function reindexSubgraph(def, opts) {
3668
3959
  }
3669
3960
  }
3670
3961
  async function resumeReindex(def, opts) {
3671
- const targetDb = getTargetDb2();
3962
+ const targetDb = getTargetDb3();
3672
3963
  const subgraphName = def.name;
3673
3964
  const row = await targetDb.selectFrom("subgraphs").select([
3674
3965
  "id",
@@ -3681,7 +3972,7 @@ async function resumeReindex(def, opts) {
3681
3972
  const fromBlock = resolveReindexResumeBlock(row);
3682
3973
  const toBlock = Number(row.reindex_to_block);
3683
3974
  if (fromBlock == null) {
3684
- logger9.info("No reindex metadata, starting fresh reindex", {
3975
+ logger10.info("No reindex metadata, starting fresh reindex", {
3685
3976
  subgraph: subgraphName
3686
3977
  });
3687
3978
  return reindexSubgraph(def, {
@@ -3690,12 +3981,12 @@ async function resumeReindex(def, opts) {
3690
3981
  });
3691
3982
  }
3692
3983
  if (fromBlock > toBlock) {
3693
- logger9.info("Resume: no remaining blocks", { subgraph: subgraphName });
3984
+ logger10.info("Resume: no remaining blocks", { subgraph: subgraphName });
3694
3985
  await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
3695
3986
  await clearReindexMetadata(targetDb, subgraphName);
3696
3987
  return { processed: 0 };
3697
3988
  }
3698
- logger9.info("Resuming reindex", {
3989
+ logger10.info("Resuming reindex", {
3699
3990
  subgraph: subgraphName,
3700
3991
  fromBlock,
3701
3992
  toBlock,
@@ -3717,9 +4008,9 @@ async function resumeReindex(def, opts) {
3717
4008
  if (reason === "user-cancelled") {
3718
4009
  await updateSubgraphStatus2(targetDb, subgraphName, "active");
3719
4010
  await clearReindexMetadata(targetDb, subgraphName);
3720
- logger9.info("Resume cancelled by user", { subgraph: subgraphName });
4011
+ logger10.info("Resume cancelled by user", { subgraph: subgraphName });
3721
4012
  } else {
3722
- logger9.info("Resume interrupted by shutdown, will resume again", {
4013
+ logger10.info("Resume interrupted by shutdown, will resume again", {
3723
4014
  subgraph: subgraphName
3724
4015
  });
3725
4016
  }
@@ -3727,13 +4018,13 @@ async function resumeReindex(def, opts) {
3727
4018
  }
3728
4019
  await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
3729
4020
  await clearReindexMetadata(targetDb, subgraphName);
3730
- logger9.info("Resumed reindex complete", {
4021
+ logger10.info("Resumed reindex complete", {
3731
4022
  subgraph: subgraphName,
3732
4023
  blocks: result.blocksProcessed
3733
4024
  });
3734
4025
  return { processed: result.blocksProcessed };
3735
4026
  } catch (err) {
3736
- logger9.error("Resumed reindex failed", {
4027
+ logger10.error("Resumed reindex failed", {
3737
4028
  subgraph: subgraphName,
3738
4029
  error: getErrorMessage3(err)
3739
4030
  });
@@ -3742,9 +4033,9 @@ async function resumeReindex(def, opts) {
3742
4033
  }
3743
4034
  }
3744
4035
  async function backfillSubgraph(def, opts) {
3745
- const targetDb = getTargetDb2();
4036
+ const targetDb = getTargetDb3();
3746
4037
  const subgraphName = def.name;
3747
- logger9.info("Backfill starting", {
4038
+ logger10.info("Backfill starting", {
3748
4039
  subgraph: subgraphName,
3749
4040
  from: opts.fromBlock,
3750
4041
  to: opts.toBlock
@@ -3762,17 +4053,17 @@ async function backfillSubgraph(def, opts) {
3762
4053
  signal: opts.signal
3763
4054
  });
3764
4055
  if (result.aborted) {
3765
- logger9.info("Backfill aborted", { subgraph: subgraphName });
4056
+ logger10.info("Backfill aborted", { subgraph: subgraphName });
3766
4057
  return { processed: result.blocksProcessed };
3767
4058
  }
3768
4059
  const resolved = await resolveGaps(targetDb, subgraphName, opts.fromBlock, opts.toBlock).catch(() => 0);
3769
4060
  if (resolved > 0) {
3770
- logger9.info("Resolved subgraph gaps via backfill", {
4061
+ logger10.info("Resolved subgraph gaps via backfill", {
3771
4062
  subgraph: subgraphName,
3772
4063
  resolved
3773
4064
  });
3774
4065
  }
3775
- logger9.info("Backfill complete", {
4066
+ logger10.info("Backfill complete", {
3776
4067
  subgraph: subgraphName,
3777
4068
  blocks: result.blocksProcessed,
3778
4069
  events: result.totalEventsProcessed,
@@ -3780,7 +4071,7 @@ async function backfillSubgraph(def, opts) {
3780
4071
  });
3781
4072
  return { processed: result.blocksProcessed };
3782
4073
  } catch (err) {
3783
- logger9.error("Backfill failed", {
4074
+ logger10.error("Backfill failed", {
3784
4075
  subgraph: subgraphName,
3785
4076
  error: getErrorMessage3(err)
3786
4077
  });
@@ -4701,7 +4992,7 @@ function generateIndexSchema(target, opts = {}) {
4701
4992
  }
4702
4993
  var INDEX_CODEGEN_TABLES = Object.keys(SOURCE_READ_TYPES);
4703
4994
  // src/schema/deployer.ts
4704
- import { sql as sql4 } from "kysely";
4995
+ import { sql as sql5 } from "kysely";
4705
4996
  function toJsonSafe(obj) {
4706
4997
  return JSON.parse(JSON.stringify(obj, (_key, value) => typeof value === "bigint" ? value.toString() : value));
4707
4998
  }
@@ -4816,7 +5107,7 @@ function renderDeployPlan(def, schemaName) {
4816
5107
  async function deploySchema(db, def, handlerPath, opts) {
4817
5108
  validateSubgraphDefinition(def);
4818
5109
  const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);
4819
- const { getSubgraph, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
5110
+ const { getSubgraph: getSubgraph2, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
4820
5111
  const ddlDb = opts?.dataDb ?? db;
4821
5112
  const byo = opts?.dataDb != null;
4822
5113
  const refuseDestructiveOnByo = (reasons, diff) => {
@@ -4828,7 +5119,7 @@ async function deploySchema(db, def, handlerPath, opts) {
4828
5119
  grantScript: plan.grantScript
4829
5120
  });
4830
5121
  };
4831
- const existing = await getSubgraph(db, def.name, opts?.accountId);
5122
+ const existing = await getSubgraph2(db, def.name, opts?.accountId);
4832
5123
  const schemaName = opts?.schemaName ?? pgSchemaName(def.name);
4833
5124
  const newVersion = opts?.version ?? (existing ? bumpPatch(existing.version) : "1.0.0");
4834
5125
  const regData = {
@@ -4853,7 +5144,7 @@ async function deploySchema(db, def, handlerPath, opts) {
4853
5144
  databaseUrlEnc: opts?.databaseUrlEnc ?? null
4854
5145
  };
4855
5146
  if (existing) {
4856
- const schemaExists = await sql4`
5147
+ const schemaExists = await sql5`
4857
5148
  SELECT EXISTS (
4858
5149
  SELECT 1 FROM information_schema.schemata
4859
5150
  WHERE schema_name = ${schemaName}
@@ -4861,7 +5152,7 @@ async function deploySchema(db, def, handlerPath, opts) {
4861
5152
  `.execute(ddlDb).then((r) => r.rows[0]?.exists ?? false);
4862
5153
  if (!schemaExists) {
4863
5154
  for (const stmt of statements) {
4864
- await sql4.raw(stmt).execute(ddlDb);
5155
+ await sql5.raw(stmt).execute(ddlDb);
4865
5156
  }
4866
5157
  const sg2 = await registerSubgraph(db, regData);
4867
5158
  return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
@@ -4887,9 +5178,9 @@ async function deploySchema(db, def, handlerPath, opts) {
4887
5178
  if (existing.schema_hash === hash && opts?.forceReindex) {
4888
5179
  if (byo)
4889
5180
  refuseDestructiveOnByo(["force reindex"], null);
4890
- await sql4.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
5181
+ await sql5.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
4891
5182
  for (const stmt of statements) {
4892
- await sql4.raw(stmt).execute(ddlDb);
5183
+ await sql5.raw(stmt).execute(ddlDb);
4893
5184
  }
4894
5185
  const sg2 = await registerSubgraph(db, regData);
4895
5186
  return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
@@ -4901,9 +5192,9 @@ async function deploySchema(db, def, handlerPath, opts) {
4901
5192
  if (byo) {
4902
5193
  refuseDestructiveOnByo(reasons.length > 0 ? reasons : ["force reindex"], diff);
4903
5194
  }
4904
- await sql4.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
5195
+ await sql5.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
4905
5196
  for (const stmt of statements) {
4906
- await sql4.raw(stmt).execute(ddlDb);
5197
+ await sql5.raw(stmt).execute(ddlDb);
4907
5198
  }
4908
5199
  const sg3 = await registerSubgraph(db, regData);
4909
5200
  const deployDiff2 = toDeployDiff(diff, reasons);
@@ -4916,16 +5207,16 @@ async function deploySchema(db, def, handlerPath, opts) {
4916
5207
  }
4917
5208
  const addedDefs = diff.addedTables.map((tableName) => ({ tableName, tableDef: def.schema[tableName] })).filter((t) => t.tableDef !== undefined);
4918
5209
  if (addedDefs.some(({ tableDef }) => tableNeedsTrgm(tableDef))) {
4919
- await sql4.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
5210
+ await sql5.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
4920
5211
  }
4921
5212
  for (const { tableName, tableDef } of addedDefs) {
4922
5213
  for (const stmt of emitTableDDL(schemaName, tableName, tableDef)) {
4923
- await sql4.raw(stmt).execute(ddlDb);
5214
+ await sql5.raw(stmt).execute(ddlDb);
4924
5215
  }
4925
5216
  }
4926
5217
  for (const { tableName, tableDef } of addedDefs) {
4927
5218
  for (const stmt of emitForeignKeyDDL(schemaName, tableName, tableDef)) {
4928
- await sql4.raw(stmt).execute(ddlDb);
5219
+ await sql5.raw(stmt).execute(ddlDb);
4929
5220
  }
4930
5221
  }
4931
5222
  for (const [tableName, colDiff] of Object.entries(diff.tables)) {
@@ -4943,12 +5234,12 @@ async function deploySchema(db, def, handlerPath, opts) {
4943
5234
  if (!sqlType)
4944
5235
  continue;
4945
5236
  const nullable = col.nullable ? "" : ` NOT NULL DEFAULT ${getDefault(col.type)}`;
4946
- await sql4.raw(`ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`).execute(ddlDb);
5237
+ await sql5.raw(`ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`).execute(ddlDb);
4947
5238
  if (col.indexed) {
4948
- await sql4.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`).execute(ddlDb);
5239
+ await sql5.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`).execute(ddlDb);
4949
5240
  }
4950
5241
  if (col.search) {
4951
- await sql4.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
5242
+ await sql5.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
4952
5243
  }
4953
5244
  }
4954
5245
  }
@@ -4956,7 +5247,7 @@ async function deploySchema(db, def, handlerPath, opts) {
4956
5247
  const flagFlips = {};
4957
5248
  const needsTrgmForFlips = Object.entries(diff.tables).some(([tableName, colDiff]) => colDiff.indexChanged.some((colName) => def.schema[tableName]?.columns[colName]?.search && !existingSchema[tableName]?.columns[colName]?.search));
4958
5249
  if (needsTrgmForFlips) {
4959
- await sql4.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
5250
+ await sql5.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
4960
5251
  }
4961
5252
  for (const [tableName, colDiff] of Object.entries(diff.tables)) {
4962
5253
  if (colDiff.indexChanged.length === 0)
@@ -4971,14 +5262,14 @@ async function deploySchema(db, def, handlerPath, opts) {
4971
5262
  const plainIdx = `idx_${schemaName}_${tableName}_${colName}`;
4972
5263
  const trgmIdx = `idx_${schemaName}_${tableName}_${colName}_trgm`;
4973
5264
  if (now.indexed && !was?.indexed) {
4974
- await sql4.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${plainIdx} ON ${qualifiedName} (${colName})`).execute(ddlDb);
5265
+ await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${plainIdx} ON ${qualifiedName} (${colName})`).execute(ddlDb);
4975
5266
  } else if (!now.indexed && was?.indexed) {
4976
- await sql4.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${plainIdx}`).execute(ddlDb);
5267
+ await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${plainIdx}`).execute(ddlDb);
4977
5268
  }
4978
5269
  if (now.search && !was?.search) {
4979
- await sql4.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${trgmIdx} ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
5270
+ await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${trgmIdx} ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
4980
5271
  } else if (!now.search && was?.search) {
4981
- await sql4.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${trgmIdx}`).execute(ddlDb);
5272
+ await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${trgmIdx}`).execute(ddlDb);
4982
5273
  }
4983
5274
  }
4984
5275
  }
@@ -4987,28 +5278,28 @@ async function deploySchema(db, def, handlerPath, opts) {
4987
5278
  const qualifiedName = `${schemaName}.${tableName}`;
4988
5279
  for (const cols of conDiff.addedUniqueKeys) {
4989
5280
  const constraintName = `uq_${schemaName}_${tableName}_${cols.join("_")}`;
4990
- const exists = await sql4`
5281
+ const exists = await sql5`
4991
5282
  SELECT EXISTS (
4992
5283
  SELECT 1 FROM pg_constraint
4993
5284
  WHERE conname = ${constraintName}
4994
5285
  ) AS "exists"
4995
5286
  `.execute(ddlDb).then((r) => r.rows[0]?.exists ?? false);
4996
5287
  if (!exists) {
4997
- await sql4.raw(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(", ")})`).execute(ddlDb);
5288
+ await sql5.raw(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(", ")})`).execute(ddlDb);
4998
5289
  }
4999
5290
  addedUq[tableName] = [...addedUq[tableName] ?? [], cols];
5000
5291
  }
5001
5292
  for (const cols of conDiff.addedIndexes) {
5002
5293
  const i = (def.schema[tableName]?.indexes ?? []).findIndex((entry) => JSON.stringify(entry) === JSON.stringify(cols));
5003
5294
  const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;
5004
- await sql4.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(", ")})`).execute(ddlDb);
5295
+ await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(", ")})`).execute(ddlDb);
5005
5296
  }
5006
5297
  for (const cols of conDiff.removedIndexes) {
5007
5298
  const i = (existingSchema[tableName]?.indexes ?? []).findIndex((entry) => JSON.stringify(entry) === JSON.stringify(cols));
5008
5299
  if (i < 0)
5009
5300
  continue;
5010
5301
  const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;
5011
- await sql4.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${idxName}`).execute(ddlDb);
5302
+ await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${idxName}`).execute(ddlDb);
5012
5303
  }
5013
5304
  }
5014
5305
  const sg2 = await registerSubgraph(db, regData);
@@ -5034,7 +5325,7 @@ async function deploySchema(db, def, handlerPath, opts) {
5034
5325
  }
5035
5326
  }
5036
5327
  for (const stmt of statements) {
5037
- await sql4.raw(stmt).execute(ddlDb);
5328
+ await sql5.raw(stmt).execute(ddlDb);
5038
5329
  }
5039
5330
  const sg = await registerSubgraph(db, regData);
5040
5331
  return { action: "created", subgraphId: sg.id, version: newVersion };
@@ -5086,5 +5377,5 @@ export {
5086
5377
  ByoBreakingChangeError
5087
5378
  };
5088
5379
 
5089
- //# debugId=06A0A7FF47E0C5EE64756E2164756E21
5380
+ //# debugId=99416B000428839064756E2164756E21
5090
5381
  //# sourceMappingURL=index.js.map