{"version":3,"sources":["jsdelivr-header.js","/npm/@pyk/ponder-core@0.0.56/src/index.ts","/npm/@pyk/ponder-core@0.0.56/src/Ponder.ts","/npm/@pyk/ponder-core@0.0.56/src/backfill/BackfillService.ts","/npm/@pyk/ponder-core@0.0.56/src/common/utils.ts","/npm/@pyk/ponder-core@0.0.56/src/common/createQueue.ts","/npm/@pyk/ponder-core@0.0.56/src/common/LoggerService.ts","/npm/@pyk/ponder-core@0.0.56/src/common/types.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/base.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/utils.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/queue.ts","/npm/@pyk/ponder-core@0.0.56/src/backfill/blockBackfillQueue.ts","/npm/@pyk/ponder-core@0.0.56/src/backfill/logBackfillQueue.ts","/npm/@pyk/ponder-core@0.0.56/src/codegen/CodegenService.ts","/npm/@pyk/ponder-core@0.0.56/src/codegen/buildContractTypes.ts","/npm/@pyk/ponder-core@0.0.56/src/codegen/buildEntityTypes.ts","/npm/@pyk/ponder-core@0.0.56/src/codegen/buildEventTypes.ts","/npm/@pyk/ponder-core@0.0.56/src/codegen/utils.ts","/npm/@pyk/ponder-core@0.0.56/src/config/abi.ts","/npm/@pyk/ponder-core@0.0.56/src/config/networks.ts","/npm/@pyk/ponder-core@0.0.56/src/config/contracts.ts","/npm/@pyk/ponder-core@0.0.56/src/config/logFilters.ts","/npm/@pyk/ponder-core@0.0.56/src/config/encodeLogFilterKey.ts","/npm/@pyk/ponder-core@0.0.56/src/database/cache/mappers.ts","/npm/@pyk/ponder-core@0.0.56/src/database/cache/postgresCacheStore.ts","/npm/@pyk/ponder-core@0.0.56/src/database/cache/sqliteCacheStore.ts","/npm/@pyk/ponder-core@0.0.56/src/database/cache/cacheStore.ts","/npm/@pyk/ponder-core@0.0.56/src/database/db.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/postgres.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/sqlite.ts","/npm/@pyk/ponder-core@0.0.56/src/database/entity/postgresEntityStore.ts","/npm/@pyk/ponder-core@0.0.56/src/database/entity/utils.ts","/npm/@pyk/ponder-core@0.0.56/src/database/entity/sqliteEntityStore.ts","/npm/@pyk/ponder-core@0.0.56/src/database/entity/entityStore.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/ErrorService.ts","/npm/@pyk/ponder-core@0.0.56/src/frontfill/FrontfillService.ts","/npm/@pyk/ponder-core@0.0.56/src/frontfill/blockFrontfillQueue.ts","/npm/@pyk/ponder-core@0.0.56/src/frontfill/logFrontfillQueue.ts","/npm/@pyk/ponder-core@0.0.56/src/handlers/EventHandlerService.ts","/npm/@pyk/ponder-core@0.0.56/src/errors/eventHandler.ts","/npm/@pyk/ponder-core@0.0.56/src/handlers/buildInjectedContract.ts","/npm/@pyk/ponder-core@0.0.56/src/handlers/getStackTrace.ts","/npm/@pyk/ponder-core@0.0.56/src/reload/ReloadService.ts","/npm/@pyk/ponder-core@0.0.56/src/schema/buildSchema.ts","/npm/@pyk/ponder-core@0.0.56/src/server/graphql/buildGqlSchema.ts","/npm/@pyk/ponder-core@0.0.56/src/server/graphql/buildEntityType.ts","/npm/@pyk/ponder-core@0.0.56/src/server/graphql/buildPluralField.ts","/npm/@pyk/ponder-core@0.0.56/src/server/graphql/buildSingularField.ts","/npm/@pyk/ponder-core@0.0.56/src/reload/readGraphqlSchema.ts","/npm/@pyk/ponder-core@0.0.56/src/reload/readHandlers.ts","/npm/@pyk/ponder-core@0.0.56/src/server/ServerService.ts","/npm/@pyk/ponder-core@0.0.56/src/ui/app.tsx","/npm/@pyk/ponder-core@0.0.56/src/ui/BackfillBar.tsx","/npm/@pyk/ponder-core@0.0.56/src/ui/ProgressBar.tsx","/npm/@pyk/ponder-core@0.0.56/src/ui/HandlersBar.tsx","/npm/@pyk/ponder-core@0.0.56/src/ui/UiService.ts"],"names":[],"mappings":"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","file":"/npm/@pyk/ponder-core@0.0.56/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@pyk/ponder-core@0.0.56/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","export type { Block, Log, Model, Transaction } from \"@/common/types\";\nexport type { PonderOptions } from \"@/config/options\";\nexport type { PonderConfig, ResolvedPonderConfig } from \"@/config/ponderConfig\";\nexport { Ponder } from \"@/Ponder\";\nexport { PonderApp } from \"@/reload/readHandlers\";\n","import pico from \"picocolors\";\n\nimport { BackfillService } from \"@/backfill/BackfillService\";\nimport { CodegenService } from \"@/codegen/CodegenService\";\nimport { LoggerService, MessageKind } from \"@/common/LoggerService\";\nimport { formatEta, formatPercentage } from \"@/common/utils\";\nimport { buildContracts, Contract } from \"@/config/contracts\";\nimport { buildLogFilters, LogFilter } from \"@/config/logFilters\";\nimport { Network } from \"@/config/networks\";\nimport { PonderOptions } from \"@/config/options\";\nimport { ResolvedPonderConfig } from \"@/config/ponderConfig\";\nimport { buildCacheStore, CacheStore } from \"@/database/cache/cacheStore\";\nimport { buildDb, PonderDatabase } from \"@/database/db\";\nimport { buildEntityStore, EntityStore } from \"@/database/entity/entityStore\";\nimport { ErrorService } from \"@/errors/ErrorService\";\nimport { FrontfillService } from \"@/frontfill/FrontfillService\";\nimport { EventHandlerService } from \"@/handlers/EventHandlerService\";\nimport { ReloadService } from \"@/reload/ReloadService\";\nimport { ServerService } from \"@/server/ServerService\";\nimport { UiService } from \"@/ui/UiService\";\n\nexport type Resources = {\n  options: PonderOptions;\n  config: ResolvedPonderConfig;\n  database: PonderDatabase;\n  cacheStore: CacheStore;\n  entityStore: EntityStore;\n  logFilters: LogFilter[];\n  contracts: Contract[];\n  logger: LoggerService;\n  errors: ErrorService;\n};\n\nexport class Ponder {\n  resources: Resources;\n\n  frontfillService: FrontfillService;\n  backfillService: BackfillService;\n  serverService: ServerService;\n  reloadService: ReloadService;\n  eventHandlerService: EventHandlerService;\n  codegenService: CodegenService;\n  uiService: UiService;\n\n  constructor({\n    options,\n    config,\n  }: {\n    options: PonderOptions;\n    config: ResolvedPonderConfig;\n  }) {\n    const logger = new LoggerService({ options });\n    const errors = new ErrorService();\n    const database = buildDb({ options, config, logger });\n    const cacheStore = buildCacheStore({ database });\n    const entityStore = buildEntityStore({ database });\n    const logFilters = buildLogFilters({ options, config });\n    const contracts = buildContracts({ options, config });\n\n    const resources: Resources = {\n      options,\n      config,\n      database,\n      cacheStore,\n      entityStore,\n      logFilters,\n      contracts,\n      logger,\n      errors,\n    };\n    this.resources = resources;\n\n    this.frontfillService = new FrontfillService({ resources });\n    this.backfillService = new BackfillService({ resources });\n    this.serverService = new ServerService({ resources });\n    this.reloadService = new ReloadService({ resources });\n    this.eventHandlerService = new EventHandlerService({ resources });\n    this.codegenService = new CodegenService({ resources });\n    this.uiService = new UiService({ resources });\n  }\n\n  async setup() {\n    this.registerDevAndStartHandlers();\n    this.registerUiHandlers();\n\n    // If any of the provided networks do not have a valid RPC url,\n    // kill the app here. This happens here rather than in the constructor because\n    // `ponder codegen` should still be able to if an RPC url is missing. In fact,\n    // that is part of the happy path for `create-ponder`.\n    const networksMissingRpcUrl: Network[] = [];\n    this.resources.logFilters.forEach((logFilter) => {\n      if (!logFilter.network.rpcUrl) {\n        networksMissingRpcUrl.push(logFilter.network);\n      }\n    });\n    if (networksMissingRpcUrl.length > 0) {\n      return new Error(\n        `missing RPC URL for networks (${networksMissingRpcUrl.map(\n          (n) => `\"${n.name}\"`\n        )}). Did you forget to add an RPC URL in .env.local?`\n      );\n    }\n\n    // Start the HTTP server.\n    this.serverService.start();\n\n    // These files depend only on ponder.config.ts, so can generate once on setup.\n    // Note that loadHandlers depends on the index.ts file being present.\n    this.codegenService.generateAppFile();\n\n    // Note that this must occur before loadSchema and loadHandlers.\n    await this.resources.cacheStore.migrate();\n\n    // Manually trigger loading schema and handlers. Subsequent loads\n    // are triggered by changes to project files (handled in ReloadService).\n    this.reloadService.loadSchema();\n    await this.reloadService.loadHandlers();\n  }\n\n  async dev() {\n    const setupError = await this.setup();\n    if (setupError) {\n      this.resources.logger.logMessage(MessageKind.ERROR, setupError.message);\n      await this.kill();\n      return;\n    }\n\n    await this.frontfillService.getLatestBlockNumbers();\n    this.frontfillService.startFrontfill();\n    this.reloadService.watch();\n    await this.backfillService.backfill();\n    await this.eventHandlerService.processEvents();\n  }\n\n  async start() {\n    const setupError = await this.setup();\n    if (setupError) {\n      this.resources.logger.logMessage(MessageKind.ERROR, setupError.message);\n      await this.kill();\n      return;\n    }\n\n    // When ran with `ponder start`, handler errors should kill the process.\n    this.resources.errors.on(\"handlerError\", async () => {\n      process.exitCode = 1;\n      await this.kill();\n    });\n\n    await this.frontfillService.getLatestBlockNumbers();\n    this.frontfillService.startFrontfill();\n    await this.backfillService.backfill();\n    await this.eventHandlerService.processEvents();\n  }\n\n  async codegen() {\n    this.codegenService.generateAppFile();\n\n    const result = this.reloadService.loadSchema();\n    if (result) {\n      const { schema, graphqlSchema } = result;\n      this.codegenService.generateAppFile({ schema });\n      this.codegenService.generateSchemaFile({ graphqlSchema });\n    }\n\n    await this.kill();\n  }\n\n  async kill() {\n    this.frontfillService.clearListeners();\n    this.backfillService.clearListeners();\n\n    await this.reloadService.kill?.();\n    this.uiService.kill();\n    this.eventHandlerService.killQueue();\n    await this.serverService.teardown();\n    await this.resources.entityStore.teardown();\n\n    await this.frontfillService.kill();\n    await this.backfillService.kill();\n  }\n\n  private registerDevAndStartHandlers() {\n    this.reloadService.on(\"ponderConfigChanged\", async () => {\n      await this.kill();\n    });\n\n    this.reloadService.on(\"newSchema\", async ({ schema, graphqlSchema }) => {\n      this.codegenService.generateAppFile({ schema });\n      this.codegenService.generateSchemaFile({ graphqlSchema });\n\n      this.serverService.reload({ graphqlSchema });\n\n      await this.resources.entityStore.load({ schema });\n      this.eventHandlerService.resetEventQueue({ schema });\n      await this.eventHandlerService.processEvents();\n    });\n\n    this.reloadService.on(\"newHandlers\", async ({ handlers }) => {\n      await this.resources.entityStore.reset();\n      this.eventHandlerService.resetEventQueue({ handlers });\n      await this.eventHandlerService.processEvents();\n    });\n\n    this.frontfillService.on(\"frontfillStarted\", async () => {\n      await this.eventHandlerService.processEvents();\n    });\n    this.backfillService.on(\"backfillStarted\", async () => {\n      this.eventHandlerService.isBackfillStarted = true;\n      await this.eventHandlerService.processEvents();\n    });\n\n    this.frontfillService.on(\"eventsAdded\", async () => {\n      await this.eventHandlerService.processEvents();\n    });\n    this.backfillService.on(\"eventsAdded\", async () => {\n      await this.eventHandlerService.processEvents();\n    });\n\n    this.backfillService.on(\"backfillCompleted\", async () => {\n      this.resources.logger.logMessage(\n        MessageKind.BACKFILL,\n        \"backfill complete\"\n      );\n      await this.eventHandlerService.processEvents();\n    });\n\n    this.eventHandlerService.on(\"eventsProcessed\", ({ toTimestamp }) => {\n      if (this.serverService.isBackfillEventProcessingComplete) return;\n\n      // If a batch of events are processed and the new toTimestamp is greater than\n      // the backfill cutoff timestamp, backfill event processing is complete, and the\n      // server should begin responding as healthy.\n      if (toTimestamp >= this.frontfillService.backfillCutoffTimestamp) {\n        this.serverService.isBackfillEventProcessingComplete = true;\n        this.resources.logger.logMessage(\n          MessageKind.INDEXER,\n          \"backfill event processing complete (server now responding as healthy)\"\n        );\n        // TODO: figure out how to remove this listener from within itself?\n      }\n    });\n  }\n\n  private registerUiHandlers() {\n    this.resources.errors.on(\"handlerError\", ({ error }) => {\n      this.resources.logger.logMessage(MessageKind.ERROR, error.message);\n    });\n\n    this.frontfillService.on(\"networkConnected\", (e) => {\n      this.uiService.ui.networks.push(e.network);\n    });\n\n    this.backfillService.on(\"logFilterStarted\", ({ name, cacheRate }) => {\n      this.resources.logger.logMessage(\n        MessageKind.BACKFILL,\n        `started backfill for ${pico.bold(name)} (${formatPercentage(\n          cacheRate\n        )} cached)`\n      );\n\n      this.uiService.ui.stats[name].cacheRate = cacheRate;\n    });\n\n    this.backfillService.on(\"logTasksAdded\", ({ name, count }) => {\n      this.uiService.ui.stats[name].logTotal += count;\n    });\n    this.backfillService.on(\"blockTasksAdded\", ({ name, count }) => {\n      this.uiService.ui.stats[name].blockTotal += count;\n    });\n\n    this.backfillService.on(\"logTaskCompleted\", ({ name }) => {\n      if (this.uiService.ui.stats[name].logCurrent === 0) {\n        this.uiService.ui.stats[name].logStartTimestamp = Date.now();\n      }\n\n      this.uiService.ui.stats[name] = {\n        ...this.uiService.ui.stats[name],\n        logCurrent: this.uiService.ui.stats[name].logCurrent + 1,\n        logAvgDuration:\n          (Date.now() - this.uiService.ui.stats[name].logStartTimestamp) /\n          this.uiService.ui.stats[name].logCurrent,\n        logAvgBlockCount:\n          this.uiService.ui.stats[name].blockTotal /\n          this.uiService.ui.stats[name].logCurrent,\n      };\n    });\n    this.backfillService.on(\"blockTaskCompleted\", ({ name }) => {\n      if (this.uiService.ui.stats[name].blockCurrent === 0) {\n        this.uiService.ui.stats[name].blockStartTimestamp = Date.now();\n      }\n\n      this.uiService.ui.stats[name] = {\n        ...this.uiService.ui.stats[name],\n        blockCurrent: this.uiService.ui.stats[name].blockCurrent + 1,\n        blockAvgDuration:\n          (Date.now() - this.uiService.ui.stats[name].blockStartTimestamp) /\n          this.uiService.ui.stats[name].blockCurrent,\n      };\n    });\n    this.backfillService.on(\"backfillCompleted\", ({ duration }) => {\n      this.uiService.ui.isBackfillComplete = true;\n      this.uiService.ui.backfillDuration = formatEta(duration);\n    });\n\n    this.frontfillService.on(\"logTaskCompleted\", ({ network, logData }) => {\n      Object.entries(logData).forEach(([blockNumber, logInfo]) => {\n        const total = Object.values(logInfo).reduce((sum, a) => sum + a, 0);\n        this.resources.logger.logMessage(\n          MessageKind.FRONTFILL,\n          `${network} @ ${blockNumber} (${total} matched events)`\n        );\n      });\n    });\n\n    this.frontfillService.on(\"logTaskFailed\", ({ network, error }) => {\n      this.resources.logger.logMessage(\n        MessageKind.WARNING,\n        `(${network}) log frontfill task failed with error: ${error.message}`\n      );\n    });\n    this.frontfillService.on(\"blockTaskFailed\", ({ network, error }) => {\n      this.resources.logger.logMessage(\n        MessageKind.WARNING,\n        `(${network}) block frontfill task failed with error: ${error.message}`\n      );\n    });\n\n    this.eventHandlerService.on(\"taskStarted\", () => {\n      this.uiService.ui.handlersCurrent += 1;\n    });\n    this.eventHandlerService.on(\"taskCompleted\", ({ timestamp }) => {\n      if (timestamp) this.uiService.ui.handlersToTimestamp = timestamp;\n      this.uiService.render();\n    });\n\n    this.eventHandlerService.on(\n      \"eventsAdded\",\n      ({ totalCount, handledCount }) => {\n        this.uiService.ui.handlersTotal += totalCount;\n        this.uiService.ui.handlersHandledTotal += handledCount;\n      }\n    );\n    this.eventHandlerService.on(\"eventsProcessed\", ({ toTimestamp }) => {\n      this.uiService.ui.handlersToTimestamp = toTimestamp;\n    });\n    this.eventHandlerService.on(\"eventQueueReset\", () => {\n      this.uiService.ui.handlersCurrent = 0;\n      this.uiService.ui.handlersTotal = 0;\n      this.uiService.ui.handlersHandledTotal = 0;\n      this.uiService.ui.handlersToTimestamp = 0;\n    });\n\n    this.serverService.on(\"serverStarted\", ({ desiredPort, port }) => {\n      if (desiredPort !== port) {\n        this.resources.logger.logMessage(\n          MessageKind.EVENT,\n          `port ${desiredPort} unavailable, server listening on port ${port}`\n        );\n      } else {\n        this.resources.logger.logMessage(\n          MessageKind.EVENT,\n          `server listening on port ${port}`\n        );\n      }\n      this.uiService.ui.port = port;\n    });\n\n    this.resources.errors.on(\"handlerError\", () => {\n      this.uiService.ui.handlerError = true;\n    });\n    this.resources.errors.on(\"handlerErrorCleared\", () => {\n      this.uiService.ui.handlerError = false;\n    });\n  }\n}\n","import Emittery from \"emittery\";\n\nimport { endBenchmark, p1_excluding_all, startBenchmark } from \"@/common/utils\";\nimport { LogFilter } from \"@/config/logFilters\";\nimport { Resources } from \"@/Ponder\";\n\nimport { createBlockBackfillQueue } from \"./blockBackfillQueue\";\nimport { createLogBackfillQueue } from \"./logBackfillQueue\";\n\nexport type BackfillServiceEvents = {\n  logFilterStarted: { name: string; cacheRate: number };\n\n  logTasksAdded: { name: string; count: number };\n  blockTasksAdded: { name: string; count: number };\n\n  logTaskFailed: { name: string; error: Error };\n  blockTaskFailed: { name: string; error: Error };\n\n  logTaskCompleted: { name: string };\n  blockTaskCompleted: { name: string };\n\n  eventsAdded: undefined;\n\n  backfillStarted: { logFilterCount: number };\n  backfillCompleted: { duration: number };\n};\n\nexport class BackfillService extends Emittery<BackfillServiceEvents> {\n  resources: Resources;\n\n  private killFunctions: (() => Promise<void>)[] = [];\n  private drainFunctions: (() => Promise<void>)[] = [];\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n  }\n\n  async backfill() {\n    const backfillStartedAt = startBenchmark();\n\n    await Promise.all(\n      this.resources.logFilters.map(async (logFilter) => {\n        await this.startBackfillForLogFilter({ logFilter });\n      })\n    );\n\n    this.emit(\"backfillStarted\", {\n      logFilterCount: this.resources.logFilters.length,\n    });\n\n    await Promise.all(this.drainFunctions.map((f) => f()));\n\n    const backfillDuration = endBenchmark(backfillStartedAt);\n    this.emit(\"backfillCompleted\", { duration: backfillDuration });\n  }\n\n  async kill() {\n    await Promise.all(this.killFunctions.map((f) => f()));\n  }\n\n  private async startBackfillForLogFilter({\n    logFilter,\n  }: {\n    logFilter: LogFilter;\n  }) {\n    if (!logFilter.endBlock) {\n      throw new Error(\n        `Log filter does not have an end block: ${logFilter.name}`\n      );\n    }\n\n    // Create queues.\n    const blockBackfillQueue = createBlockBackfillQueue({\n      backfillService: this,\n      logFilter,\n    });\n\n    const logBackfillQueue = createLogBackfillQueue({\n      backfillService: this,\n      logFilter,\n      blockBackfillQueue,\n    });\n\n    const { startBlock, endBlock } = logFilter;\n\n    if (startBlock > endBlock) {\n      throw new Error(\n        `Start block number (${startBlock}) is greater than end block number (${endBlock}).\n         Are you sure the RPC endpoint is for the correct network?\n        `\n      );\n    }\n\n    const cachedRanges =\n      await this.resources.cacheStore.getLogFilterCachedRanges({\n        filterKey: logFilter.filter.key,\n      });\n    const requiredBlockRanges = p1_excluding_all(\n      [logFilter.startBlock, logFilter.endBlock],\n      cachedRanges.map((r) => [r.startBlock, r.endBlock])\n    );\n\n    const requiredBlockCount = requiredBlockRanges.reduce((acc, cur) => {\n      return acc + (cur[1] + 1 - cur[0]);\n    }, 0);\n    const cacheRate = Math.max(\n      0,\n      1 - requiredBlockCount / (logFilter.endBlock - logFilter.startBlock)\n    );\n\n    this.emit(\"logFilterStarted\", {\n      name: logFilter.name,\n      cacheRate: cacheRate,\n    });\n\n    for (const blockRange of requiredBlockRanges) {\n      const [startBlock, endBlock] = blockRange;\n\n      let fromBlock = startBlock;\n      let toBlock = Math.min(fromBlock + logFilter.maxBlockRange - 1, endBlock);\n\n      while (fromBlock <= endBlock) {\n        logBackfillQueue.addTask({ fromBlock, toBlock, isRetry: false });\n\n        fromBlock = toBlock + 1;\n        toBlock = Math.min(fromBlock + logFilter.maxBlockRange - 1, endBlock);\n      }\n    }\n\n    this.killFunctions.push(async () => {\n      logBackfillQueue.clear();\n      await logBackfillQueue.onIdle();\n      blockBackfillQueue.clear();\n      await blockBackfillQueue.onIdle();\n    });\n\n    this.drainFunctions.push(async () => {\n      await logBackfillQueue.onIdle();\n      await blockBackfillQueue.onIdle();\n    });\n  }\n}\n","import { createHash } from \"crypto\";\nimport { readFileSync } from \"fs\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const ensureDirExists = (filePath: string) => {\n  const dirname = path.dirname(filePath);\n  if (existsSync(dirname)) {\n    return;\n  }\n  mkdirSync(dirname, { recursive: true });\n};\n\nexport const groupBy = <T>(array: T[], fn: (item: T) => string | number) => {\n  return array.reduce<{ [k: string | number]: T[] }>((acc, item) => {\n    const key = fn(item);\n    (acc[key] = acc[key] || []).push(item);\n    return acc;\n  }, {});\n};\n\nexport const registerKilledProcessListener = (fn: () => Promise<unknown>) => {\n  let isKillListenerInProgress = false;\n\n  const listener = async () => {\n    if (isKillListenerInProgress) return;\n    isKillListenerInProgress = true;\n    await fn();\n    process.exit(0);\n  };\n\n  process.on(\"SIGINT\", listener); // CTRL+C\n  process.on(\"SIGQUIT\", listener); // Keyboard quit\n  process.on(\"SIGTERM\", listener); // `kill` command\n};\n\nexport const startBenchmark = () => process.hrtime();\nexport const endBenchmark = (hrt: [number, number]) => {\n  const diffHrt = process.hrtime(hrt);\n  return Math.round(diffHrt[0] * 1000 + diffHrt[1] / 1000000);\n};\n\nexport const formatEta = (ms: number) => {\n  // If less than 1 second, return ms.\n  if (ms < 1000) return `${Math.round(ms)}ms`;\n  const seconds = Math.floor(ms / 1000);\n\n  const h = Math.floor(seconds / 3600);\n  const m = Math.floor((seconds - h * 3600) / 60);\n  const s = seconds - h * 3600 - m * 60;\n\n  const hstr = h > 0 ? `${h}h ` : \"\";\n  const mstr = m > 0 || h > 0 ? `${m}m ` : \"\";\n  const sstr = s > 0 || m > 0 ? `${s}s` : \"\";\n\n  return `${hstr}${mstr}${sstr}`;\n};\n\nexport const formatPercentage = (cacheRate: number) => {\n  const decimal = Math.round(cacheRate * 1000) / 10;\n  return Number.isInteger(decimal) && decimal < 100\n    ? `${decimal}.0%`\n    : `${decimal}%`;\n};\n\nconst latestFileHash: Record<string, string | undefined> = {};\n\nexport const isFileChanged = (filePath: string) => {\n  // TODO: I think this throws if the file being watched gets deleted while\n  // the development server is running. Should handle this case gracefully.\n  try {\n    const content = readFileSync(filePath, \"utf-8\");\n    const hash = createHash(\"md5\").update(content).digest(\"hex\");\n\n    const prevHash = latestFileHash[filePath];\n    latestFileHash[filePath] = hash;\n    if (!prevHash) {\n      // If there is no previous hash, this file is being changed for the first time.\n      return true;\n    } else {\n      // If there is a previous hash, check if the content hash has changed.\n      return prevHash !== hash;\n    }\n  } catch (e) {\n    return true;\n  }\n};\n\n// These methods are used in the cached interval calculations\n// From https://stackoverflow.com/a/33857786/12841788\n\n/* This method is just a small helper method that takes an array\n * and returns a new array with duplicates removed\n */\nfunction remove_duplicates(arr: number[][]) {\n  const lookup: Record<string, number> = {};\n  const results = [];\n  for (let i = 0; i < arr.length; i++) {\n    const el = arr[i];\n    const key = el.toString();\n    if (lookup[key]) continue;\n    lookup[key] = 1;\n    results.push(el);\n  }\n  return results;\n}\n\n/* This method takes 2 points p1 and p2 and returns an array of\n * points with the range of p2 removed, i.e. p1 = [1,7]\n * p2 = [4,5] returned = [[1,3],[6,7]]\n */\nexport function p1_excluding_p2(p1: number[], p2: number[]) {\n  if (p1[1] < p2[0]) return [p1]; // line p1 finishes before the exclusion line p2\n  if (p1[0] > p2[1]) return [p1]; // line p1 starts after exclusion line p1\n  const lines = [];\n  // calculate p1 before p2 starts\n  const line1 = [p1[0], Math.min(p1[1], p2[0] - 1)];\n  if (line1[0] <= line1[1]) lines.push(line1);\n  // calculate p1 after p2 ends\n  const line2 = [p2[1] + 1, p1[1]];\n  if (line2[0] <= line2[1]) lines.push(line2);\n  // these contain the lines we calculated above\n  return lines;\n}\n\n/* this performs the exact same operation as above, only it allows you to pass\n * multiple points (but still just 1 exclusion point) and returns results\n * in an identical format as above, i.e. points = [[1,7],[0,1]]\n *  p2 = [4,5] returned = [[0,1],[1,3],[6,7]]\n */\nfunction points_excluding_p2(points: number[][], p2: number[]) {\n  const results: number[][] = [];\n  for (let i = 0; i < points.length; i++) {\n    const lines = p1_excluding_p2(points[i], p2);\n    results.push(...lines);\n  }\n  return results;\n}\n\n/* this method performs the same operation only this time it takes one point\n * and multiple exclusion points and returns an array of the results.\n * this is the important method of: given 1 point and many\n * exclusion points, return the remaining new ranges\n */\nexport function p1_excluding_all(p1: number[], exclude: number[][]) {\n  let checking = [p1];\n  for (let i = 0; i < exclude.length; i++) {\n    checking = points_excluding_p2(checking, exclude[i]);\n  }\n  return remove_duplicates(checking);\n}\n\n/* This function merges intervals (inclusive on both ends).\n * I modified the SO impl to handle [inclusive, inclusive] intervals.\n * From: https://stackoverflow.com/a/26391774/12841788\n */\nexport function merge_intervals(intervals: number[][]) {\n  intervals.sort((a, b) => a[0] - b[0]);\n  const result: number[][] = [];\n  let last: number[];\n  intervals.forEach((interval) => {\n    if (interval[1] < interval[0])\n      throw new Error(`Cannot merge invalid interval: ${interval}`);\n    interval = [interval[0], interval[1] + 1];\n    if (!last || interval[0] > last[1]) {\n      result.push((last = interval));\n    } else if (interval[1] > last[1]) {\n      last[1] = interval[1];\n    }\n  });\n  return result.map((r) => [r[0], r[1] - 1]);\n}\n","import Emittery from \"emittery\";\nimport PQueue, { DefaultAddOptions, Options, Queue as TPQueue } from \"p-queue\";\n\n// Note that the returned queue is not actually an Emittery, it's an EventEmitter3.\n// But it follows the Emittery types for \"on\" and \"emit\", so this works.\nexport type Queue<TTask, TReturn = void> = PQueue & {\n  addTask: (task: TTask, options?: { priority?: number }) => Promise<void>;\n  addTasks: (tasks: TTask[], options?: { priority?: number }) => Promise<void>;\n} & Pick<\n    Emittery<{\n      completed: { result: TReturn };\n      error: { error: Error; task: TTask };\n    }>,\n    \"on\" | \"emit\"\n  >;\n\nexport type Worker<TTask, TContext = undefined, TReturn = void> = (arg: {\n  task: TTask;\n  context: TContext;\n  queue: Queue<TTask, TReturn>;\n}) => Promise<TReturn>;\n\nexport function createQueue<TTask, TContext, TReturn>({\n  worker,\n  context,\n  options,\n}: {\n  worker: Worker<TTask, TContext, TReturn>;\n  context: TContext;\n  options: Options<\n    TPQueue<() => Promise<unknown>, DefaultAddOptions>,\n    DefaultAddOptions\n  >;\n}): Queue<TTask, TReturn> {\n  const queue = new PQueue(options) as Queue<TTask, TReturn>;\n\n  const buildTask = (task: TTask, queue: Queue<TTask, TReturn>) => async () => {\n    return await worker({ task, context, queue });\n  };\n\n  queue.addTask = async (task, options) => {\n    try {\n      const result = await queue.add(buildTask(task, queue), options);\n      queue.emit(\"completed\", { result });\n    } catch (error_) {\n      queue.emit(\"error\", { error: error_ as Error, task });\n    }\n  };\n\n  queue.addTasks = async (tasks, options) => {\n    await Promise.all(\n      tasks.map(async (task) => {\n        try {\n          const result = await queue.add(buildTask(task, queue), options);\n          queue.emit(\"completed\", { result });\n        } catch (error_) {\n          queue.emit(\"error\", { error: error_ as Error, task });\n        }\n      })\n    );\n  };\n\n  return queue;\n}\n","import pico from \"picocolors\";\n\nimport { PonderOptions } from \"../config/options\";\n\nexport enum LogLevel {\n  // Silent 0\n  Error, // 1\n  Info, // 2\n  Warn, // 3\n  Debug, // 4\n  Trace, // 5\n}\n\nexport enum MessageKind {\n  EVENT = \"event\",\n  ERROR = \"error\",\n  WARNING = \"warning\",\n  BACKFILL = \"backfill\",\n  FRONTFILL = \"frontfill\",\n  INDEXER = \"indexer\",\n}\n\nexport class LoggerService {\n  logLevel: number;\n\n  constructor({ options }: { options: PonderOptions }) {\n    this.logLevel = options.logLevel;\n  }\n\n  error = (...args: Parameters<typeof console.log>) => {\n    if (this.logLevel > LogLevel.Error) console.log(...args);\n  };\n  info = (...args: Parameters<typeof console.log>) => {\n    if (this.logLevel > LogLevel.Info) console.log(...args);\n  };\n  warn = (...args: Parameters<typeof console.log>) => {\n    if (this.logLevel > LogLevel.Warn) console.log(...args);\n  };\n  debug = (...args: Parameters<typeof console.log>) => {\n    if (this.logLevel > LogLevel.Debug) console.log(...args);\n  };\n  trace = (...args: Parameters<typeof console.log>) => {\n    if (this.logLevel > LogLevel.Trace) console.log(...args);\n  };\n\n  private maxWidth = 0;\n  // This function is specifically for message logs.\n  logMessage(kind: MessageKind, message: string) {\n    this.maxWidth = Math.max(this.maxWidth, kind.length);\n    const padded = kind.padEnd(this.maxWidth, \" \");\n\n    switch (kind) {\n      case MessageKind.EVENT: {\n        this.info(pico.magenta(padded) + \" - \" + message);\n        break;\n      }\n      case MessageKind.ERROR: {\n        this.error(pico.red(padded) + \" - \" + message);\n        break;\n      }\n      case MessageKind.WARNING: {\n        this.error(pico.yellow(padded) + \" - \" + message);\n        break;\n      }\n      case MessageKind.BACKFILL: {\n        this.info(pico.yellow(padded) + \" - \" + message);\n        break;\n      }\n      case MessageKind.FRONTFILL: {\n        this.info(pico.cyan(padded) + \" - \" + message);\n        break;\n      }\n      case MessageKind.INDEXER: {\n        this.info(pico.blue(padded) + \" - \" + message);\n        break;\n      }\n    }\n  }\n}\n","import type {\n  Block as ViemBlock,\n  Hash,\n  Hex,\n  Log as ViemLog,\n  Transaction as ViemTransaction,\n} from \"viem\";\n\nexport type Model<T extends { id: string | number | bigint }> = {\n  create: (options: { id: T[\"id\"]; data: Omit<T, \"id\"> }) => Promise<T>;\n\n  update: (options: {\n    id: T[\"id\"];\n    data: Omit<Partial<T>, \"id\">;\n  }) => Promise<T>;\n\n  upsert: (options: {\n    id: T[\"id\"];\n    create: Omit<T, \"id\">;\n    update: Omit<Partial<T>, \"id\">;\n  }) => Promise<T>;\n\n  findUnique: (options: { id: T[\"id\"] }) => Promise<T | null>;\n\n  delete: (options: { id: T[\"id\"] }) => Promise<boolean>;\n};\n\nexport type Block = Omit<\n  ViemBlock,\n  \"hash\" | \"logsBloom\" | \"nonce\" | \"number\"\n> & {\n  /** Block hash */\n  hash: Hash;\n  /** Logs bloom filter */\n  logsBloom: Hex;\n  /** Proof-of-work hash */\n  nonce: Hex;\n  /** Block number */\n  number: bigint;\n};\n\nfunction isFinalizedBlock(block: ViemBlock): block is Block {\n  return !!(\n    block.hash !== null &&\n    block.logsBloom !== null &&\n    block.nonce !== null &&\n    block.number !== null\n  );\n}\n\nexport function parseBlock(block: ViemBlock) {\n  return isFinalizedBlock(block) ? block : null;\n}\n\nexport type Transaction = Omit<\n  ViemTransaction,\n  \"blockHash\" | \"blockNumber\" | \"transactionIndex\"\n> & {\n  /** Hash of block containing this transaction */\n  blockHash: Hash;\n  /** Number of block containing this transaction */\n  blockNumber: bigint;\n  /** Index of this transaction in the block */\n  transactionIndex: number;\n};\n\nfunction isFinalizedTransaction(transaction: ViemTransaction) {\n  return !!(\n    transaction.blockHash !== null &&\n    transaction.blockNumber !== null &&\n    transaction.transactionIndex !== null\n  );\n}\n\nexport function parseTransactions(\n  rawTransactions: ViemTransaction[]\n): Transaction[] {\n  return rawTransactions.reduce<Transaction[]>(\n    (transactions, rawTransaction) => {\n      if (isFinalizedTransaction(rawTransaction)) {\n        transactions.push(rawTransaction as Transaction);\n      }\n      return transactions;\n    },\n    []\n  );\n}\n\nexport type Log = Omit<\n  ViemLog,\n  | \"blockHash\"\n  | \"blockNumber\"\n  | \"logIndex\"\n  | \"transactionHash\"\n  | \"transactionIndex\"\n> & {\n  /** Hash of block containing this log */\n  blockHash: Hash;\n  /** Number of block containing this log */\n  blockNumber: bigint;\n  /** Index of this log within its block */\n  logIndex: number;\n  /** Hash of the transaction that created this log */\n  transactionHash: Hash;\n  /** Index of the transaction that created this log */\n  transactionIndex: number;\n\n  /** Globally unique identifier for this log */\n  logId: `${Hash}-${number}`;\n  /** Value used internally by Ponder to sort logs across networks */\n  logSortKey: bigint;\n  /** Chain ID */\n  chainId: number;\n  /** Unix timestamp of when the block containing this log was collated */\n  blockTimestamp: bigint | null;\n\n  // TODO: remove these from the public type.\n  topic0: Hex | null;\n  topic1: Hex | null;\n  topic2: Hex | null;\n  topic3: Hex | null;\n};\n\nfunction isFinalizedLog(log: ViemLog): log is Log {\n  return !!(\n    log.blockHash !== null &&\n    log.blockNumber !== null &&\n    log.logIndex !== null &&\n    log.transactionHash !== null &&\n    log.transactionIndex !== null\n  );\n}\n\nexport function parseLogs(\n  rawLogs: ViemLog[],\n  { chainId }: { chainId: number }\n): Log[] {\n  return rawLogs.reduce<Log[]>((logs, rawLog) => {\n    if (isFinalizedLog(rawLog)) {\n      logs.push({\n        ...rawLog,\n        logId: `${rawLog.blockHash}-${rawLog.logIndex}`,\n        logSortKey: rawLog.blockNumber * 100000n + BigInt(rawLog.logIndex),\n        blockTimestamp: null,\n        topic0: rawLog.topics[0] ? (rawLog.topics[0] as Hex) : null,\n        topic1: rawLog.topics[1] ? (rawLog.topics[1] as Hex) : null,\n        topic2: rawLog.topics[2] ? (rawLog.topics[2] as Hex) : null,\n        topic3: rawLog.topics[3] ? (rawLog.topics[3] as Hex) : null,\n        chainId: chainId,\n      });\n    }\n    return logs;\n  }, []);\n}\n","type BaseErrorParameters = {\n  metaMessages?: string[];\n} & (\n  | {\n      cause?: never;\n      details?: string;\n    }\n  | {\n      cause: BaseError | Error;\n      details?: never;\n    }\n);\n\n// Adapted from viem.\n// https://github.com/wagmi-dev/viem/blob/021ce8e5a3fb02db6139564345a91fc77cba08a6/src/errors/base.ts#L17\nexport class BaseError extends Error {\n  details?: string;\n  metaMessages?: string[];\n  shortMessage: string;\n\n  name = \"PonderError\";\n\n  constructor(shortMessage: string, args: BaseErrorParameters = {}) {\n    const details =\n      args.cause instanceof BaseError\n        ? args.cause.details\n        : args.cause?.message\n        ? args.cause.message\n        : args.details;\n\n    const message = [\n      shortMessage || \"An error occurred.\",\n      // \"\",\n      ...(args.metaMessages ? [...args.metaMessages, \"\"] : []),\n      ...(details ? [`Details: ${details}`] : []),\n    ].join(\"\\n\");\n\n    super(message);\n\n    if (args.cause) this.cause = args.cause;\n    if (!details) this.details = message;\n    this.metaMessages = args.metaMessages;\n    this.shortMessage = shortMessage;\n  }\n}\n","// Adapted from viem.\n// https://github.com/wagmi-dev/viem/blob/021ce8e5a3fb02db6139564345a91fc77cba08a6/src/errors/transaction.ts#L6-L19\nexport function prettyPrint(\n  args: Record<string, bigint | number | string | undefined | false>\n) {\n  const entries = Object.entries(args)\n    .map(([key, value]) => {\n      if (value === undefined || value === false) return null;\n\n      const trimmedValue =\n        typeof value === \"string\" && value.length > 80\n          ? value.slice(0, 80).concat(\"...\")\n          : value;\n\n      return [key, trimmedValue];\n    })\n    .filter(Boolean) as [string, string][];\n  const maxLength = entries.reduce(\n    (acc, [key]) => Math.max(acc, key.length),\n    0\n  );\n  return entries\n    .map(([key, value]) => `  ${`${key}:`.padEnd(maxLength + 1)}  ${value}`)\n    .join(\"\\n\");\n}\n","import { BaseError } from \"./base\";\nimport { prettyPrint } from \"./utils\";\n\nexport class QueueError extends BaseError {\n  name = \"QueueError\";\n\n  constructor({\n    queueName,\n    task,\n    cause,\n  }: {\n    queueName: string;\n    task: any;\n    cause: Error;\n  }) {\n    const metaMessages = [];\n    metaMessages.push(`Task:\\n${prettyPrint(task)}`);\n    if (cause.stack) metaMessages.push(`Stack: ${cause.stack}`);\n\n    const shortMessage = `${queueName} error`;\n\n    super(shortMessage, {\n      metaMessages,\n    });\n  }\n}\n","import { Hash, Transaction as ViemTransaction } from \"viem\";\n\nimport { createQueue, Queue, Worker } from \"@/common/createQueue\";\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { parseBlock, parseTransactions } from \"@/common/types\";\nimport { LogFilter } from \"@/config/logFilters\";\nimport { QueueError } from \"@/errors/queue\";\n\nimport { BackfillService } from \"./BackfillService\";\n\nexport type BlockBackfillTask = {\n  blockNumberToCacheFrom: number;\n  blockNumber: number;\n  requiredTxHashes: Set<Hash>;\n};\n\nexport type BlockBackfillWorkerContext = {\n  backfillService: BackfillService;\n  logFilter: LogFilter;\n};\n\nexport type BlockBackfillQueue = Queue<BlockBackfillTask>;\n\nexport const createBlockBackfillQueue = (\n  context: BlockBackfillWorkerContext\n) => {\n  const queue = createQueue({\n    worker: blockBackfillWorker,\n    context,\n    options: {\n      concurrency: 10,\n    },\n  });\n\n  // Pass queue events on to service layer.\n  queue.on(\"add\", () => {\n    context.backfillService.emit(\"blockTasksAdded\", {\n      name: context.logFilter.name,\n      count: 1,\n    });\n  });\n\n  queue.on(\"error\", ({ error }) => {\n    context.backfillService.emit(\"blockTaskFailed\", {\n      name: context.logFilter.name,\n      error,\n    });\n  });\n\n  queue.on(\"completed\", () => {\n    context.backfillService.emit(\"blockTaskCompleted\", {\n      name: context.logFilter.name,\n    });\n  });\n\n  // Default to a simple retry.\n  queue.on(\"error\", ({ task, error }) => {\n    const queueError = new QueueError({\n      queueName: \"Block backfill queue\",\n      task: task,\n      cause: error,\n    });\n    context.backfillService.resources.logger.logMessage(\n      MessageKind.ERROR,\n      queueError.message\n    );\n\n    queue.addTask(task);\n  });\n\n  return queue;\n};\n\nconst blockBackfillWorker: Worker<\n  BlockBackfillTask,\n  BlockBackfillWorkerContext\n> = async ({ task, context }) => {\n  const { blockNumber, requiredTxHashes, blockNumberToCacheFrom } = task;\n  const { backfillService, logFilter } = context;\n  const { client } = logFilter.network;\n\n  const rawBlock = await client.getBlock({\n    blockNumber: BigInt(blockNumber),\n    includeTransactions: true,\n  });\n\n  const block = parseBlock(rawBlock);\n\n  // If the log is pending, log a warning.\n  if (!block) {\n    backfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending block (blockNumber: ${blockNumber})`\n    );\n    return;\n  }\n\n  const allTransactions = parseTransactions(\n    block.transactions as ViemTransaction[]\n  );\n\n  // If any pending transactions were present in the block, log a warning.\n  if (allTransactions.length !== block.transactions.length) {\n    backfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending transactions in block (blockNumber: ${blockNumber}, count: ${\n        block.transactions.length - allTransactions.length\n      })`\n    );\n    return;\n  }\n\n  // Filter down to only required transactions (transactions that emitted events we care about).\n  const transactions = allTransactions.filter((tx) =>\n    requiredTxHashes.has(tx.hash)\n  );\n\n  await Promise.all([\n    backfillService.resources.cacheStore.insertBlock(block),\n    backfillService.resources.cacheStore.insertTransactions(transactions),\n    backfillService.resources.cacheStore.insertLogFilterCachedRange({\n      range: {\n        filterKey: logFilter.filter.key,\n        startBlock: blockNumberToCacheFrom,\n        endBlock: blockNumber,\n        endBlockTimestamp: Number(block.timestamp),\n      },\n    }),\n  ]);\n\n  backfillService.emit(\"eventsAdded\");\n};\n","import { Hash, HttpRequestError, InvalidParamsRpcError } from \"viem\";\n\nimport { createQueue, Queue, Worker } from \"@/common/createQueue\";\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { parseLogs } from \"@/common/types\";\nimport { LogFilter } from \"@/config/logFilters\";\nimport { QueueError } from \"@/errors/queue\";\n\nimport { BackfillService } from \"./BackfillService\";\nimport type {\n  BlockBackfillQueue,\n  BlockBackfillTask,\n} from \"./blockBackfillQueue\";\n\nexport type LogBackfillTask = {\n  fromBlock: number;\n  toBlock: number;\n  isRetry: boolean;\n};\n\nexport type LogBackfillWorkerContext = {\n  backfillService: BackfillService;\n  logFilter: LogFilter;\n  blockBackfillQueue: BlockBackfillQueue;\n};\n\nexport type LogBackfillQueue = Queue<LogBackfillTask>;\n\nexport const createLogBackfillQueue = (\n  context: LogBackfillWorkerContext\n): LogBackfillQueue => {\n  const queue = createQueue({\n    worker: logBackfillWorker,\n    context,\n    options: {\n      concurrency: 10,\n    },\n  });\n\n  // Pass queue events on to service layer.\n  queue.on(\"add\", () => {\n    context.backfillService.emit(\"logTasksAdded\", {\n      name: context.logFilter.name,\n      count: 1,\n    });\n  });\n\n  queue.on(\"error\", ({ error }) => {\n    context.backfillService.emit(\"logTaskFailed\", {\n      name: context.logFilter.name,\n      error,\n    });\n  });\n\n  queue.on(\"completed\", () => {\n    context.backfillService.emit(\"logTaskCompleted\", {\n      name: context.logFilter.name,\n    });\n  });\n\n  queue.on(\"error\", ({ error, task }) => {\n    // Handle Alchemy response size error.\n    if (\n      error instanceof InvalidParamsRpcError &&\n      error.details.startsWith(\"Log response size exceeded.\")\n    ) {\n      const safe = error.details.split(\"this block range should work: \")[1];\n      const safeStart = Number(safe.split(\", \")[0].slice(1));\n      const safeEnd = Number(safe.split(\", \")[1].slice(0, -1));\n\n      queue.addTask({\n        fromBlock: safeStart,\n        toBlock: safeEnd,\n        isRetry: true,\n      });\n      queue.addTask({\n        fromBlock: safeEnd,\n        toBlock: task.toBlock,\n        isRetry: true,\n      });\n\n      return;\n    }\n\n    // Handle Quicknode block range limit error (should never happen).\n    if (\n      error instanceof HttpRequestError &&\n      error.details.includes(\n        \"eth_getLogs and eth_newFilter are limited to a 10,000 blocks range\"\n      )\n    ) {\n      const midpoint = Math.floor(\n        (task.toBlock - task.fromBlock) / 2 + task.fromBlock\n      );\n      queue.addTask({\n        fromBlock: task.fromBlock,\n        toBlock: midpoint,\n        isRetry: true,\n      });\n      queue.addTask({\n        fromBlock: midpoint + 1,\n        toBlock: task.toBlock,\n        isRetry: true,\n      });\n\n      return;\n    }\n\n    const queueError = new QueueError({\n      queueName: \"Log backfill queue\",\n      task: task,\n      cause: error,\n    });\n    context.backfillService.resources.logger.logMessage(\n      MessageKind.ERROR,\n      queueError.message\n    );\n\n    // Default to a simple retry.\n    queue.addTask(task);\n  });\n\n  return queue;\n};\n\nconst logBackfillWorker: Worker<\n  LogBackfillTask,\n  LogBackfillWorkerContext\n> = async ({ task, context }) => {\n  const { fromBlock, toBlock, isRetry } = task;\n  const { backfillService, logFilter, blockBackfillQueue } = context;\n  const { client } = logFilter.network;\n\n  const rawLogs = await client.getLogs({\n    address:\n      logFilter.filter.address !== null ? logFilter.filter.address : undefined,\n    fromBlock: BigInt(fromBlock),\n    toBlock: BigInt(toBlock),\n    event: logFilter.filter.event,\n    args: logFilter.filter.args as unknown as undefined,\n  });\n\n  const logs = parseLogs(rawLogs, { chainId: logFilter.network.chainId });\n\n  // If any pending logs were present in the response, log a warning.\n  if (logs.length !== rawLogs.length) {\n    backfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending logs (count: ${\n        logs.length - rawLogs.length\n      })`\n    );\n  }\n\n  await backfillService.resources.cacheStore.insertLogs(logs);\n\n  const txHashesByBlockNumber = logs.reduce<Record<number, Set<Hash>>>(\n    (acc, log) => {\n      const blockNumber = Number(log.blockNumber);\n      acc[blockNumber] ||= new Set<Hash>();\n      acc[blockNumber].add(log.transactionHash);\n      return acc;\n    },\n    {}\n  );\n  const requiredBlockNumbers = Object.keys(txHashesByBlockNumber)\n    .map(Number)\n    .sort((a, b) => a - b);\n\n  let blockNumberToCacheFrom = fromBlock;\n  const blockBackfillTasks: BlockBackfillTask[] = [];\n\n  for (const blockNumber of requiredBlockNumbers) {\n    blockBackfillTasks.push({\n      blockNumberToCacheFrom,\n      blockNumber,\n      requiredTxHashes: txHashesByBlockNumber[blockNumber],\n    });\n    blockNumberToCacheFrom = blockNumber + 1;\n  }\n\n  // If there is a gap between the last required block and the toBlock\n  // of the log batch, add another task to cover the gap. This is necessary\n  // to properly updates the log filter cached range data.\n  if (blockNumberToCacheFrom <= toBlock) {\n    blockBackfillTasks.push({\n      blockNumberToCacheFrom,\n      blockNumber: toBlock,\n      requiredTxHashes: new Set(),\n    });\n  }\n\n  blockBackfillQueue.addTasks(blockBackfillTasks, {\n    priority: isRetry ? 1 : 0,\n  });\n};\n","import Emittery from \"emittery\";\nimport { GraphQLSchema, printSchema } from \"graphql\";\nimport { writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { ensureDirExists } from \"@/common/utils\";\nimport { Resources } from \"@/Ponder\";\nimport { Schema } from \"@/schema/types\";\n\nimport { buildContractTypes } from \"./buildContractTypes\";\nimport { buildEntityTypes } from \"./buildEntityTypes\";\nimport { buildEventTypes } from \"./buildEventTypes\";\nimport { formatPrettier } from \"./utils\";\n\nexport class CodegenService extends Emittery {\n  resources: Resources;\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n  }\n\n  generateAppFile({ schema }: { schema?: Schema } = {}) {\n    const entities = schema?.entities || [];\n\n    const raw = `\n      /* Autogenerated file. Do not edit manually. */\n  \n      import { PonderApp } from \"@ponder/core\";\n      import type { Block, Log, Transaction, Model } from \"@ponder/core\";\n      import type { AbiParameterToPrimitiveType } from \"abitype\";\n      import type { BlockTag, Hash } from \"viem\";\n\n      /* ENTITY TYPES */\n\n      ${buildEntityTypes(entities)}\n  \n      /* CONTRACT TYPES */\n\n      type CallOverrides =\n      | {\n          /** The block number at which to execute the contract call. */\n          blockNumber?: bigint\n          blockTag?: never\n        }\n      | {\n          blockNumber?: never\n          /** The block tag at which to execute the contract call. */\n          blockTag?: BlockTag\n        }\n\n      ${buildContractTypes(this.resources.contracts)}\n\n      /* CONTEXT TYPES */\n\n      export type Context = {\n        contracts: {\n          ${this.resources.contracts\n            .map((contract) => `${contract.name}: ${contract.name};`)\n            .join(\"\")}\n        },\n        entities: {\n          ${entities\n            .map((entity) => `${entity.name}: Model<${entity.name}>;`)\n            .join(\"\")}\n        },\n      }\n\n  \n      /* HANDLER TYPES */\n    \n      ${buildEventTypes(this.resources.logFilters)}\n\n      export const ponder = new PonderApp<AppType>();\n    `;\n\n    const final = formatPrettier(raw);\n\n    const filePath = path.join(this.resources.options.generatedDir, \"index.ts\");\n    ensureDirExists(filePath);\n    writeFileSync(filePath, final, \"utf8\");\n  }\n\n  generateSchemaFile({ graphqlSchema }: { graphqlSchema: GraphQLSchema }) {\n    const header = `\n      \"\"\" Autogenerated file. Do not edit manually. \"\"\"\n    `;\n\n    const body = printSchema(graphqlSchema);\n    const final = header + body;\n\n    const filePath = path.join(\n      this.resources.options.generatedDir,\n      \"schema.graphql\"\n    );\n    ensureDirExists(filePath);\n    writeFileSync(filePath, final, \"utf8\");\n  }\n}\n","import { AbiParameter } from \"abitype\";\n\nimport type { Contract } from \"@/config/contracts\";\n\ntype AbiReadOrViewFunction = {\n  type: \"function\";\n  stateMutability: \"pure\" | \"view\";\n  inputs: readonly AbiParameter[];\n  name: string;\n  outputs: readonly AbiParameter[];\n};\n\nexport const buildContractTypes = (contracts: Contract[]) => {\n  return contracts\n    .map((contract) => {\n      const abiReadOrViewFunctions = contract.abi.filter(\n        (item): item is AbiReadOrViewFunction =>\n          item.type === \"function\" &&\n          (item.stateMutability === \"pure\" || item.stateMutability === \"view\")\n      );\n\n      const abiReadOrViewFunctionTypes = abiReadOrViewFunctions\n        .map(({ name, inputs, outputs }) => {\n          const argsType = `${inputs\n            .map(\n              (input, index) =>\n                `${\n                  input.name !== \"\" ? input.name : `arg_${index}`\n                }: AbiParameterToPrimitiveType<${JSON.stringify(input)}>`\n            )\n            .concat(`overrides?: CallOverrides`)\n            .join(\",\")}`;\n\n          let returnType: string;\n          if (outputs.length > 1) {\n            returnType = `{${outputs\n              .map(\n                (output, index) =>\n                  `${\n                    output.name !== \"\" ? output.name : `arg_${index}`\n                  }: AbiParameterToPrimitiveType<${JSON.stringify(output)}>`\n              )\n              .join(\",\")}}`;\n          } else {\n            returnType = `${outputs\n              .map(\n                (output) =>\n                  `AbiParameterToPrimitiveType<${JSON.stringify(output)}>`\n              )\n              .join(\",\")}`;\n          }\n\n          return `${name}: (${argsType}) => Promise<${returnType}>`;\n        })\n        .join(\";\");\n\n      return `export type ${contract.name} = { ${abiReadOrViewFunctionTypes} };`;\n    })\n    .join(\"\\n\");\n};\n","/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport { Kind } from \"graphql\";\n\nimport { Entity, FieldKind } from \"@/schema/types\";\n\nconst gqlScalarToTsType: Record<string, string | undefined> = {\n  String: \"string\",\n  Boolean: \"boolean\",\n  Int: \"number\",\n  Float: \"number\",\n  BigInt: \"bigint\",\n  Bytes: \"string\",\n};\n\nexport const buildEntityTypes = (entities: Entity[]) => {\n  const entityModelTypes = entities\n    .map((entity) => {\n      return `export type ${entity.name} = {\n        ${entity.fields\n          .map((field) => {\n            switch (field.kind) {\n              case FieldKind.SCALAR: {\n                const scalarTsType = gqlScalarToTsType[field.scalarTypeName];\n                if (!scalarTsType) {\n                  throw new Error(\n                    `TypeScript type not found for scalar: ${field.scalarTypeName}`\n                  );\n                }\n                return `${field.name}${\n                  field.notNull ? \"\" : \"?\"\n                }: ${scalarTsType};`;\n              }\n              case FieldKind.ENUM: {\n                return `${field.name}${\n                  field.notNull ? \"\" : \"?\"\n                }: ${field.enumValues.map((val) => `\"${val}\"`).join(\" | \")};`;\n              }\n              case FieldKind.LIST: {\n                // This is trash\n                let tsBaseType: string;\n                if (\n                  Object.keys(gqlScalarToTsType).includes(\n                    field.baseGqlType.toString()\n                  )\n                ) {\n                  const scalarTypeName = field.baseGqlType.toString();\n                  const scalarTsType = gqlScalarToTsType[scalarTypeName];\n                  if (!scalarTsType) {\n                    throw new Error(\n                      `TypeScript type not found for scalar: ${scalarTypeName}`\n                    );\n                  }\n                  tsBaseType = scalarTsType;\n                } else if (\n                  // @ts-ignore\n                  field.baseGqlType.astNode?.kind === Kind.ENUM_TYPE_DEFINITION\n                ) {\n                  const enumValues = // @ts-ignore\n                    (field.baseGqlType.astNode?.values || []).map(\n                      // @ts-ignore\n                      (v) => v.name.value\n                    );\n                  tsBaseType = `(${enumValues\n                    // @ts-ignore\n                    .map((v) => `\"${v}\"`)\n                    .join(\" | \")})`;\n                } else {\n                  throw new Error(\n                    `Unable to generate type for field: ${field.name}`\n                  );\n                }\n\n                if (!field.isListElementNotNull) {\n                  tsBaseType = `(${tsBaseType} | null)`;\n                }\n\n                return `${field.name}${\n                  field.notNull ? \"\" : \"?\"\n                }: ${tsBaseType}[];`;\n              }\n              case FieldKind.RELATIONSHIP: {\n                return `${field.name}${field.notNull ? \"\" : \"?\"}: string;`;\n              }\n            }\n          })\n          .join(\"\")}\n        };`;\n    })\n    .join(\"\");\n\n  return entityModelTypes;\n};\n","import { AbiEvent } from \"abitype\";\n\nimport { LogFilter } from \"@/config/logFilters\";\n\nexport const buildEventTypes = (logFilters: LogFilter[]) => {\n  const allHandlers = logFilters.map((logFilter) => {\n    const abiEvents = logFilter.abi.filter(\n      (item): item is AbiEvent => item.type === \"event\"\n    );\n\n    return abiEvents\n      .map(({ name, inputs }) => {\n        const paramsType = `{${inputs\n          .map(\n            (input) => `${input.name}:\n                AbiParameterToPrimitiveType<${JSON.stringify(input)}>`\n          )\n          .join(\";\")}}`;\n\n        return `[\"${logFilter.name}:${name}\"]: ({\n            event, context\n            }: {\n              event: {\n                name: \"${name}\";\n                params: ${paramsType};\n                log: Log;\n                block: Block;\n                transaction: Transaction;\n              };\n              context: Context;\n            }) => Promise<any> | any;`;\n      })\n      .join(\"\");\n  });\n\n  allHandlers.unshift(\n    `[\"setup\"]: ({ context }: { context: Context; }) => Promise<any> | any;`\n  );\n\n  const final = `\n    export type AppType = {\n      ${allHandlers.join(\"\")}\n    }\n  `;\n\n  return final;\n};\n","import prettier from \"prettier\";\n\nlet prettierConfig: prettier.Options = { parser: \"typescript\" };\n\nconst loadPrettierConfig = async () => {\n  if (prettierConfig) return prettierConfig;\n\n  const configFile = await prettier.resolveConfigFile();\n  if (configFile) {\n    const foundConfig = await prettier.resolveConfig(configFile);\n    if (foundConfig) {\n      prettierConfig = foundConfig;\n    }\n  }\n};\n\n// Just call this once on process start\nloadPrettierConfig();\n\nexport const formatPrettier = (\n  source: string,\n  configOverrides?: Partial<prettier.Options>\n) => {\n  return prettier.format(source, { ...prettierConfig, ...configOverrides });\n};\n","import { Abi } from \"abitype\";\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const buildAbi = ({\n  abiConfig,\n  configFilePath,\n}: {\n  abiConfig: string | any[] | object | (string | any[] | object)[];\n  configFilePath: string;\n}) => {\n  let resolvedAbi: Abi;\n  const filePaths: string[] = [];\n\n  if (\n    typeof abiConfig === \"string\" ||\n    (Array.isArray(abiConfig) &&\n      (abiConfig.length === 0 || typeof abiConfig[0] === \"object\"))\n  ) {\n    // If abiConfig is a string or an ABI itself, treat it as a single ABI.\n    const { abi, filePath } = buildSingleAbi({ abiConfig, configFilePath });\n    resolvedAbi = abi;\n    if (filePath) filePaths.push(filePath);\n  } else {\n    // Otherwise, handle as an array of of ABIs.\n    const results = (abiConfig as (object | any[])[]).map((a) =>\n      buildSingleAbi({ abiConfig: a, configFilePath })\n    );\n\n    const mergedAbi = results\n      .map(({ abi }) => abi.filter((item) => item.type !== \"constructor\"))\n      .flat()\n      .flat();\n    const mergedUniqueAbi = [\n      ...new Map(\n        mergedAbi.map((item) => [JSON.stringify(item), item])\n      ).values(),\n    ];\n\n    filePaths.push(\n      ...results.map((r) => r.filePath).filter((f): f is string => !!f)\n    );\n\n    resolvedAbi = mergedUniqueAbi;\n  }\n\n  return {\n    abi: resolvedAbi,\n    filePaths,\n  };\n};\n\nconst buildSingleAbi = ({\n  abiConfig,\n  configFilePath,\n}: {\n  abiConfig: string | any[] | object;\n  configFilePath: string;\n}) => {\n  let filePath: string | undefined = undefined;\n  let abi: Abi;\n\n  if (typeof abiConfig === \"string\") {\n    // If a string, treat it as a file path.\n    filePath = path.isAbsolute(abiConfig)\n      ? abiConfig\n      : path.join(path.dirname(configFilePath), abiConfig);\n\n    const abiString = readFileSync(filePath, \"utf-8\");\n    abi = JSON.parse(abiString);\n  } else {\n    // Otherwise, treat as the ABI itself\n    abi = abiConfig as unknown as Abi;\n  }\n\n  // NOTE: Not currently using the filePath arg here, but eventually\n  // could use it to watch for changes and reload.\n  return { abi, filePath };\n};\n","import { createPublicClient, http, PublicClient } from \"viem\";\nimport { mainnet } from \"viem/chains\";\n\nimport { ResolvedPonderConfig } from \"@/config/ponderConfig\";\n\nexport type Network = {\n  name: string;\n  chainId: number;\n  client: PublicClient;\n  rpcUrl?: string;\n  pollingInterval: number;\n  defaultMaxBlockRange: number;\n};\n\nconst clients: Record<number, PublicClient | undefined> = {};\n\nexport function buildNetwork({\n  network,\n}: {\n  network: ResolvedPonderConfig[\"networks\"][0];\n}) {\n  let client = clients[network.chainId];\n\n  if (!client) {\n    client = createPublicClient({\n      transport: http(network.rpcUrl),\n      chain: {\n        ...mainnet,\n        name: network.name,\n        id: network.chainId,\n        network: network.name,\n      },\n    });\n    clients[network.chainId] = client;\n  }\n\n  const resolvedNetwork: Network = {\n    name: network.name,\n    chainId: network.chainId,\n    client,\n    rpcUrl: network.rpcUrl,\n    pollingInterval: network.pollingInterval ?? 1_000,\n    defaultMaxBlockRange: getDefaultMaxBlockRange(network),\n  };\n\n  return resolvedNetwork;\n}\n\nfunction getDefaultMaxBlockRange(network: {\n  rpcUrl?: string;\n  chainId: number;\n}) {\n  // Quicknode enforces a hard limit of 10_000.\n  if (network.rpcUrl !== undefined && network.rpcUrl.includes(\"quiknode.pro\")) {\n    return 10_000;\n  }\n\n  // Otherwise (e.g. Alchemy) use an optimistically high block limit and lean\n  // on the error handler to resolve failures.\n\n  let maxBlockRange: number;\n  switch (network.chainId) {\n    // Mainnet.\n    case 1:\n    case 3:\n    case 4:\n    case 5:\n    case 42:\n    case 11155111:\n      maxBlockRange = 2_000;\n      break;\n    // Optimism.\n    case 10:\n    case 420:\n      maxBlockRange = 50_000;\n      break;\n    // Polygon.\n    case 137:\n    case 80001:\n      maxBlockRange = 50_000;\n      break;\n    // Arbitrum.\n    case 42161:\n    case 421613:\n      maxBlockRange = 50_000;\n      break;\n    default:\n      maxBlockRange = 50_000;\n  }\n\n  return maxBlockRange;\n}\n","import { Abi, Address } from \"abitype\";\n\nimport { PonderOptions } from \"@/config/options\";\nimport { ResolvedPonderConfig } from \"@/config/ponderConfig\";\n\nimport { buildAbi } from \"./abi\";\nimport { buildNetwork, Network } from \"./networks\";\n\nexport type Contract = {\n  name: string;\n  address: Address;\n  network: Network;\n  abi: Abi;\n};\n\nexport function buildContracts({\n  config,\n  options,\n}: {\n  config: ResolvedPonderConfig;\n  options: PonderOptions;\n}): Contract[] {\n  return (config.contracts ?? []).map((contract) => {\n    const address = contract.address.toLowerCase() as Address;\n\n    const { abi } = buildAbi({\n      abiConfig: contract.abi,\n      configFilePath: options.configFile,\n    });\n\n    // Get the contract network/provider.\n    const rawNetwork = config.networks.find((n) => n.name === contract.network);\n    if (!rawNetwork) {\n      throw new Error(\n        `Network [${contract.network}] not found for contract: ${contract.name}`\n      );\n    }\n\n    const network = buildNetwork({ network: rawNetwork });\n\n    return {\n      name: contract.name,\n      address,\n      network: network,\n      abi,\n    };\n  });\n}\n","import { Abi, AbiEvent, Address } from \"abitype\";\nimport { encodeEventTopics } from \"viem\";\n\nimport { PonderOptions } from \"@/config/options\";\nimport { ResolvedPonderConfig } from \"@/config/ponderConfig\";\n\nimport { buildAbi } from \"./abi\";\nimport { encodeLogFilterKey } from \"./encodeLogFilterKey\";\nimport { buildNetwork, Network } from \"./networks\";\n\nexport type LogFilter = {\n  name: string;\n  network: Network;\n  abi: Abi;\n  filter: {\n    key: string; // `${chainId}-${address}-${topics}`\n    address?: `0x${string}` | `0x${string}`[];\n    topics?: (`0x${string}` | `0x${string}`[] | null)[];\n    event?: AbiEvent;\n    args?: any[];\n  };\n  startBlock: number;\n  endBlock: number | undefined;\n  maxBlockRange: number;\n};\n\nexport function buildLogFilters({\n  config,\n  options,\n}: {\n  config: ResolvedPonderConfig;\n  options: PonderOptions;\n}) {\n  const contractLogFilters = (config.contracts ?? [])\n    .filter((contract) => contract.isLogEventSource ?? true)\n    .map((contract) => {\n      const { abi } = buildAbi({\n        abiConfig: contract.abi,\n        configFilePath: options.configFile,\n      });\n\n      // Get the contract network/provider.\n      const rawNetwork = config.networks.find(\n        (n) => n.name === contract.network\n      );\n      if (!rawNetwork) {\n        throw new Error(\n          `Network [${contract.network}] not found for contract: ${contract.name}`\n        );\n      }\n\n      const network = buildNetwork({ network: rawNetwork });\n\n      const address = contract.address.toLowerCase() as Address;\n      const topics = undefined;\n      const key = encodeLogFilterKey({\n        chainId: network.chainId,\n        address,\n        topics,\n      });\n\n      // TODO: don't store event and args here, only store topics and\n      // call transport.request methods directly. Or, viem supports topics.\n      const event = undefined;\n      const args = undefined;\n\n      const logFilter: LogFilter = {\n        name: contract.name,\n        network,\n        abi,\n        filter: {\n          key,\n          address,\n          topics,\n          event,\n          args,\n        },\n        startBlock: contract.startBlock ?? 0,\n        endBlock: contract.endBlock,\n        maxBlockRange: contract.maxBlockRange ?? network.defaultMaxBlockRange,\n      };\n\n      return logFilter;\n    });\n\n  const filterLogFilters = (config.filters ?? []).map((filter) => {\n    const { abi } = buildAbi({\n      abiConfig: filter.abi,\n      configFilePath: options.configFile,\n    });\n\n    // Get the contract network/provider.\n    const rawNetwork = config.networks.find((n) => n.name === filter.network);\n    if (!rawNetwork) {\n      throw new Error(\n        `Network [${filter.network}] not found for filter: ${filter.name}`\n      );\n    }\n\n    const network = buildNetwork({ network: rawNetwork });\n\n    const address = Array.isArray(filter.filter.address)\n      ? filter.filter.address.map((a) => a.toLowerCase() as Address)\n      : typeof filter.filter.address === \"string\"\n      ? (filter.filter.address.toLowerCase() as Address)\n      : undefined;\n\n    const topics = filter.filter.event\n      ? encodeEventTopics({\n          abi: [filter.filter.event],\n          eventName: filter.filter.event.name,\n          args: filter.filter.args as any,\n        })\n      : undefined;\n\n    const key = encodeLogFilterKey({\n      chainId: network.chainId,\n      address,\n      topics,\n    });\n\n    // TODO: don't store event and args here, only store topics and\n    // call transport.request methods directly. Or, viem supports topics.\n    const event = filter.filter.event;\n    const args = filter.filter.args;\n\n    const logFilter: LogFilter = {\n      name: filter.name,\n      network,\n      abi,\n      filter: {\n        key,\n        address,\n        topics,\n        event,\n        args,\n      },\n      startBlock: filter.startBlock ?? 0,\n      endBlock: filter.endBlock,\n      maxBlockRange: filter.maxBlockRange ?? network.defaultMaxBlockRange,\n    };\n\n    return logFilter;\n  });\n\n  const logFilters = contractLogFilters.concat(filterLogFilters);\n\n  return logFilters;\n}\n","import { Address, Hex } from \"viem\";\n\nexport function encodeLogFilterKey({\n  chainId,\n  address,\n  topics,\n}: {\n  chainId: number;\n  address?: Address | Address[];\n  topics?: (Hex | Hex[] | null)[];\n}) {\n  return `${chainId}-${JSON.stringify(address ?? null)}-${JSON.stringify(\n    topics ?? null\n  )}`;\n}\n\nexport function decodeLogFilterKey({ key }: { key: string }) {\n  const [chainId, addressString, topicsString] = key.split(\"-\");\n\n  return {\n    chainId: Number(chainId),\n    address:\n      (JSON.parse(addressString) as Address | Address[] | null) ?? undefined,\n    topics:\n      (JSON.parse(topicsString) as (Hex | Hex[] | null)[] | null) ?? undefined,\n  };\n}\n","import { Hex } from \"viem\";\n\nimport { Block, Log, Transaction } from \"../../common/types\";\n\nexport type DatabaseBlock = Omit<Block, \"totalDifficulty\" | \"baseFeePerGas\"> & {\n  totalDifficulty: string | null;\n  baseFeePerGas: string;\n  // TODO: properly reflect that 6 additional fields are being persisted as strings.\n};\n\nexport function encodeBlock(block: Block): DatabaseBlock {\n  return {\n    ...block,\n\n    // totalDifficulty can be too large for better-sqlite3 to accept as a bigint,\n    // so must manually convert to string before passing it.\n    totalDifficulty:\n      block.totalDifficulty !== null ? block.totalDifficulty.toString() : null,\n\n    // baseFeePerGas is null on some chains. It should probably be optional in the\n    // database as well, actually.\n    baseFeePerGas:\n      block.totalDifficulty !== null ? block.totalDifficulty.toString() : \"0x0\",\n  };\n}\n\nexport function decodeBlock(block: DatabaseBlock): Block {\n  return {\n    ...block,\n\n    // These fields are currently persisted as strings, and must\n    // be manually converted back to bigints to match viem types.\n    number: BigInt(block.number),\n    timestamp: BigInt(block.timestamp),\n    size: BigInt(block.size),\n    gasLimit: BigInt(block.gasLimit),\n    gasUsed: BigInt(block.gasUsed),\n    baseFeePerGas:\n      block.baseFeePerGas !== null ? BigInt(block.baseFeePerGas) : null,\n    totalDifficulty:\n      block.totalDifficulty !== null ? BigInt(block.totalDifficulty) : null,\n  };\n}\n\nexport type DatabaseTransaction = Omit<\n  Transaction,\n  \"maxFeePerGas\" | \"maxPriorityFeePerGas\" | \"value\"\n> & {\n  maxFeePerGas: bigint | null;\n  maxPriorityFeePerGas: bigint | null;\n  value: string;\n};\n\nexport function encodeTransaction(\n  transaction: Transaction\n): DatabaseTransaction {\n  return {\n    ...transaction,\n\n    // These fields can be undefined on the input object, but they need to be\n    // defined as null for SQLite to handle them properly.\n    maxFeePerGas: transaction.maxFeePerGas ?? null,\n    maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ?? null,\n\n    // totalDifficulty can be too large for better-sqlite3 to accept as a bigint,\n    // so must manually convert to string before passing it.\n    value: transaction.value.toString(),\n  };\n}\n\nexport function decodeTransaction(\n  transaction: DatabaseTransaction\n): Transaction {\n  return {\n    ...(transaction as unknown as Transaction),\n\n    // These fields are currently persisted as strings, and must\n    // be manually converted back to bigints to match viem types.\n    blockNumber: BigInt(transaction.blockNumber),\n    value: BigInt(transaction.value),\n    gas: BigInt(transaction.gas),\n\n    // These fields are persisted as string | null, and must be\n    // converted to bigint | undefined.\n    gasPrice: transaction.gasPrice ? BigInt(transaction.gasPrice) : undefined,\n    maxFeePerGas:\n      transaction.maxFeePerGas !== null\n        ? BigInt(transaction.maxFeePerGas)\n        : undefined,\n    maxPriorityFeePerGas:\n      transaction.maxPriorityFeePerGas !== null\n        ? BigInt(transaction.maxPriorityFeePerGas)\n        : undefined,\n  } as Transaction;\n}\n\nexport type DatabaseLog = Omit<Log, \"removed\"> & {\n  removed: number;\n};\n\nexport function encodeLog(log: Log): DatabaseLog {\n  return {\n    ...log,\n    removed: log.removed === true ? 1 : 0,\n  };\n}\n\nexport function decodeLog(log: DatabaseLog): Log {\n  return {\n    ...log,\n    removed: log.removed === 1 ? true : false,\n    topics: [log.topic0, log.topic1, log.topic2, log.topic3].filter(\n      (t): t is Hex => t !== null\n    ) as [Hex, ...Hex[]] | [],\n    logSortKey: BigInt(log.logSortKey),\n    blockNumber: BigInt(log.blockNumber),\n    blockTimestamp:\n      log.blockTimestamp !== null ? BigInt(log.blockTimestamp) : null,\n  };\n}\n","import type { Pool, PoolClient } from \"pg\";\nimport { Address, Hex } from \"viem\";\n\nimport type { Block, Log, Transaction } from \"@/common/types\";\nimport { merge_intervals } from \"@/common/utils\";\n\nimport type {\n  CacheStore,\n  ContractCall,\n  LogFilterCachedRange,\n} from \"./cacheStore\";\nimport {\n  DatabaseBlock,\n  DatabaseLog,\n  DatabaseTransaction,\n  decodeBlock,\n  decodeLog,\n  decodeTransaction,\n  encodeBlock,\n  encodeLog,\n  encodeTransaction,\n} from \"./mappers\";\n\nexport const POSTGRES_TABLE_PREFIX = \"__ponder__v3__\";\n\nconst logFilterCachedRangesTableName = `${POSTGRES_TABLE_PREFIX}logFilterCachedRanges`;\nconst logsTableName = `${POSTGRES_TABLE_PREFIX}logs`;\nconst blocksTableName = `${POSTGRES_TABLE_PREFIX}blocks`;\nconst transactionsTableName = `${POSTGRES_TABLE_PREFIX}transactions`;\nconst contractCallsTableName = `${POSTGRES_TABLE_PREFIX}contractCalls`;\n\nexport class PostgresCacheStore implements CacheStore {\n  pool: Pool;\n\n  constructor({ pool }: { pool: Pool }) {\n    this.pool = pool;\n  }\n\n  migrate = async () => {\n    const client = await this.pool.connect();\n\n    try {\n      await client.query(\"BEGIN\");\n\n      await client.query(`\n        CREATE TABLE IF NOT EXISTS \"${logFilterCachedRangesTableName}\" (\n          \"id\" SERIAL PRIMARY KEY,\n          \"filterKey\" TEXT NOT NULL,\n          \"startBlock\" INTEGER NOT NULL,\n          \"endBlock\" INTEGER NOT NULL,\n          \"endBlockTimestamp\" INTEGER NOT NULL\n        )\n      `);\n      await client.query(`\n        CREATE INDEX IF NOT EXISTS \"${logFilterCachedRangesTableName}FilterKey\"\n        ON \"${logFilterCachedRangesTableName}\" (\"filterKey\")\n      `);\n\n      await client.query(`\n        CREATE TABLE IF NOT EXISTS \"${logsTableName}\" (\n          \"logId\" TEXT PRIMARY KEY,\n          \"logSortKey\" BIGINT NOT NULL,\n          \"address\" TEXT NOT NULL,\n          \"data\" TEXT NOT NULL,\n          \"topic0\" TEXT,\n          \"topic1\" TEXT,\n          \"topic2\" TEXT,\n          \"topic3\" TEXT,\n          \"blockHash\" TEXT NOT NULL,\n          \"blockNumber\" INTEGER NOT NULL,\n          \"logIndex\" INTEGER NOT NULL,\n          \"transactionHash\" TEXT NOT NULL,\n          \"transactionIndex\" INTEGER NOT NULL,\n          \"removed\" INTEGER NOT NULL,\n          \"blockTimestamp\" INTEGER,\n          \"chainId\" INTEGER NOT NULL\n        )\n      `);\n      await client.query(`\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}Address\"\n        ON \"${logsTableName}\" (\"address\")\n      `);\n      await client.query(`\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}Topic0\"\n        ON \"${logsTableName}\" (\"topic0\")\n      `);\n      await client.query(`\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}BlockTimestamp\"\n        ON \"${logsTableName}\" (\"blockTimestamp\")\n      `);\n      await client.query(`\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}ChainId\"\n        ON \"${logsTableName}\" (\"chainId\")\n      `);\n\n      await client.query(`\n        CREATE TABLE IF NOT EXISTS \"${blocksTableName}\" (\n          \"hash\" TEXT PRIMARY KEY,\n          \"number\" INTEGER NOT NULL,\n          \"timestamp\" INTEGER NOT NULL,\n          \"gasLimit\" TEXT NOT NULL,\n          \"gasUsed\" TEXT NOT NULL,\n          \"baseFeePerGas\" TEXT NOT NULL,\n          \"miner\" TEXT NOT NULL,\n          \"extraData\" TEXT NOT NULL,\n          \"size\" INTEGER NOT NULL,\n          \"parentHash\" TEXT NOT NULL,\n          \"stateRoot\" TEXT NOT NULL,\n          \"transactionsRoot\" TEXT NOT NULL,\n          \"receiptsRoot\" TEXT NOT NULL,\n          \"logsBloom\" TEXT NOT NULL,\n          \"totalDifficulty\" TEXT NOT NULL\n        )\n      `);\n\n      await client.query(`\n        CREATE TABLE IF NOT EXISTS \"${transactionsTableName}\" (\n          \"hash\" TEXT PRIMARY KEY,\n          \"nonce\" INTEGER NOT NULL,\n          \"from\" TEXT NOT NULL,\n          \"to\" TEXT,\n          \"value\" TEXT NOT NULL,\n          \"input\" TEXT NOT NULL,\n          \"gas\" TEXT NOT NULL,\n          \"gasPrice\" TEXT NOT NULL,\n          \"maxFeePerGas\" TEXT,\n          \"maxPriorityFeePerGas\" TEXT,\n          \"blockHash\" TEXT NOT NULL,\n          \"blockNumber\" INTEGER NOT NULL,\n          \"transactionIndex\" INTEGER NOT NULL,\n          \"chainId\" INTEGER\n        )\n      `);\n\n      await client.query(`\n        CREATE TABLE IF NOT EXISTS \"${contractCallsTableName}\" (\n          \"key\" TEXT PRIMARY KEY,\n          \"result\" TEXT NOT NULL\n        )\n      `);\n\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  };\n\n  getLogFilterCachedRanges = async ({ filterKey }: { filterKey: string }) => {\n    const result = await this.pool.query<LogFilterCachedRange>(\n      `SELECT * FROM \"${logFilterCachedRangesTableName}\" WHERE \"filterKey\" = $1`,\n      [filterKey]\n    );\n\n    return result.rows;\n  };\n\n  insertLogFilterCachedRange = async ({\n    range: newRange,\n  }: {\n    range: LogFilterCachedRange;\n  }) => {\n    const client = await this.pool.connect();\n\n    try {\n      await client.query(\"BEGIN\");\n\n      const { rows: existingRanges } = await client.query<LogFilterCachedRange>(\n        `DELETE FROM \"${logFilterCachedRangesTableName}\" WHERE \"filterKey\" = $1 RETURNING *`,\n        [newRange.filterKey]\n      );\n\n      const mergedRanges: LogFilterCachedRange[] = merge_intervals([\n        ...existingRanges.map((r) => [r.startBlock, r.endBlock]),\n        [newRange.startBlock, newRange.endBlock],\n      ]).map((range) => {\n        const [startBlock, endBlock] = range;\n\n        // For each new merged range, its endBlock will be found EITHER in the newly\n        // added range OR among the endBlocks of the removed range.\n        // Find it so we can propogate the endBlockTimestamp correctly.\n        const endBlockTimestamp = [newRange, ...existingRanges].find(\n          (old) => old.endBlock === endBlock\n        )?.endBlockTimestamp;\n        if (!endBlockTimestamp) {\n          throw new Error(`Old range with endBlock: ${endBlock} not found`);\n        }\n\n        return {\n          filterKey: newRange.filterKey,\n          startBlock,\n          endBlock,\n          endBlockTimestamp,\n        };\n      });\n\n      await client.query(\n        `\n        INSERT INTO \"${logFilterCachedRangesTableName}\" (\n          \"filterKey\",\n          \"startBlock\",\n          \"endBlock\",\n          \"endBlockTimestamp\"\n        ) VALUES ${this.buildInsertParams(4, mergedRanges.length)}\n        `,\n        mergedRanges\n          .map((r) => [\n            r.filterKey,\n            r.startBlock,\n            r.endBlock,\n            r.endBlockTimestamp,\n          ])\n          .flat()\n      );\n\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  };\n\n  insertLogs = async (logs: Log[]) => {\n    if (logs.length === 0) return;\n\n    const client = await this.pool.connect();\n\n    try {\n      await client.query(\"BEGIN\");\n\n      const batchSize = 1000;\n      for (let i = 0; i < logs.length; i += batchSize) {\n        const batch = logs.slice(i, i + batchSize);\n        await this.insertLogBatch(client, batch);\n      }\n\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  };\n\n  private async insertLogBatch(client: PoolClient, logs: Log[]) {\n    const params = logs\n      .map((rawLog) => {\n        const log = encodeLog(rawLog);\n        return [\n          log.logId,\n          log.logSortKey,\n          log.address,\n          log.data,\n          log.topic0,\n          log.topic1,\n          log.topic2,\n          log.topic3,\n          log.blockHash,\n          log.blockNumber,\n          log.logIndex,\n          log.transactionHash,\n          log.transactionIndex,\n          log.removed,\n          log.chainId,\n        ];\n      })\n      .flat();\n\n    const query = `\n      INSERT INTO \"${logsTableName}\" (\n        \"logId\",\n        \"logSortKey\",\n        \"address\",\n        \"data\",\n        \"topic0\",\n        \"topic1\",\n        \"topic2\",\n        \"topic3\",\n        \"blockHash\",\n        \"blockNumber\",\n        \"logIndex\",\n        \"transactionHash\",\n        \"transactionIndex\",\n        \"removed\",\n        \"chainId\"\n      ) VALUES ${this.buildInsertParams(15, logs.length)}\n      ON CONFLICT(\"logId\") DO NOTHING\n    `;\n\n    await client.query(query, params);\n  }\n\n  insertBlock = async (rawBlock: Block) => {\n    const block = encodeBlock(rawBlock);\n    const blockParams = [\n      block.hash,\n      block.number,\n      block.timestamp,\n      block.gasLimit,\n      block.gasUsed,\n      block.baseFeePerGas,\n      block.miner,\n      block.extraData,\n      block.size,\n      block.parentHash,\n      block.stateRoot,\n      block.transactionsRoot,\n      block.receiptsRoot,\n      block.logsBloom,\n      block.totalDifficulty,\n    ];\n    const blockQuery = `\n      INSERT INTO \"${blocksTableName}\" (\n        \"hash\",\n        \"number\",\n        \"timestamp\",\n        \"gasLimit\",\n        \"gasUsed\",\n        \"baseFeePerGas\",\n        \"miner\",\n        \"extraData\",\n        \"size\",\n        \"parentHash\",\n        \"stateRoot\",\n        \"transactionsRoot\",\n        \"receiptsRoot\",\n        \"logsBloom\",\n        \"totalDifficulty\"\n      ) VALUES ${this.buildInsertParams(15, 1)}\n      ON CONFLICT(\"hash\") DO NOTHING\n    `;\n\n    const logQuery = `\n      UPDATE \"${logsTableName}\"\n      SET \"blockTimestamp\" = $1\n      WHERE \"blockHash\" = $2\n    `;\n    const logParams = [block.timestamp, block.hash];\n\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n\n      await client.query(blockQuery, blockParams);\n      await client.query(logQuery, logParams);\n\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  };\n\n  insertTransactions = async (transactions: Transaction[]) => {\n    if (transactions.length === 0) return;\n\n    const params = transactions\n      .map((rawTransaction) => {\n        const transaction = encodeTransaction(rawTransaction);\n        return [\n          transaction.hash,\n          transaction.nonce,\n          transaction.from,\n          transaction.to,\n          transaction.value,\n          transaction.input,\n          transaction.gas,\n          transaction.gasPrice,\n          transaction.maxFeePerGas,\n          transaction.maxPriorityFeePerGas,\n          transaction.blockHash,\n          transaction.blockNumber,\n          transaction.transactionIndex,\n          transaction.chainId,\n        ];\n      })\n      .flat();\n\n    const query = `\n      INSERT INTO \"${transactionsTableName}\" (\n        \"hash\",\n        \"nonce\",\n        \"from\",\n        \"to\",\n        \"value\",\n        \"input\",\n        \"gas\",\n        \"gasPrice\",\n        \"maxFeePerGas\",\n        \"maxPriorityFeePerGas\",\n        \"blockHash\",\n        \"blockNumber\",\n        \"transactionIndex\",\n        \"chainId\"\n      ) VALUES ${this.buildInsertParams(14, transactions.length)}\n      ON CONFLICT(\"hash\") DO NOTHING\n    `;\n\n    await this.pool.query(query, params);\n  };\n\n  getLogs = async ({\n    fromBlockTimestamp,\n    toBlockTimestamp,\n    chainId,\n    address,\n    topics,\n  }: {\n    fromBlockTimestamp: number;\n    toBlockTimestamp: number;\n    chainId: number;\n    address?: Address | Address[];\n    topics?: (Hex | Hex[] | null)[];\n  }) => {\n    let filterStatement = \"\";\n    const filterParams: string[] = [];\n\n    if (address) {\n      filterStatement += ` AND \"address\"`;\n      if (typeof address === \"string\") {\n        filterStatement += `= $${filterParams.length + 4}`;\n        filterParams.push(address);\n      } else {\n        filterStatement += ` IN (${[...Array(address.length).keys()]\n          .map(() => `$${filterParams.length + 4}`)\n          .join(\",\")})`;\n        filterParams.push(...address);\n      }\n    }\n\n    (topics ?? []).forEach((topic, index) => {\n      filterStatement += ` AND \"topic${index}\"`;\n      if (typeof topic === \"string\") {\n        filterStatement += ` = $${filterParams.length + 4}`;\n        filterParams.push(topic);\n      } else if (Array.isArray(topic)) {\n        filterStatement += ` IN (${[...Array(topic.length).keys()]\n          .map((i) => `$${i + filterParams.length + 4}`)\n          .join(\",\")})`;\n        filterParams.push(...topic);\n      } else {\n        filterStatement += ` = NULL`;\n      }\n    });\n\n    const { rows } = await this.pool.query<DatabaseLog>(\n      `\n      SELECT * FROM \"${logsTableName}\"\n      WHERE \"blockTimestamp\" > $1\n      AND \"blockTimestamp\" <= $2\n      AND \"chainId\" = $3\n      ${filterStatement}\n      `,\n      [fromBlockTimestamp, toBlockTimestamp, chainId, ...filterParams]\n    );\n\n    return rows.map(decodeLog);\n  };\n\n  getBlock = async (hash: string) => {\n    const { rows, rowCount } = await this.pool.query<DatabaseBlock>(\n      `\n      SELECT * FROM \"${blocksTableName}\" WHERE \"hash\" = $1\n      `,\n      [hash]\n    );\n\n    if (rowCount == 0) return null;\n    return decodeBlock(rows[0]);\n  };\n\n  getTransaction = async (hash: string) => {\n    const { rows, rowCount } = await this.pool.query<DatabaseTransaction>(\n      `\n      SELECT * FROM \"${transactionsTableName}\" WHERE \"hash\" = $1\n      `,\n      [hash]\n    );\n\n    if (rowCount == 0) return null;\n    return decodeTransaction(rows[0]);\n  };\n\n  upsertContractCall = async (contractCall: ContractCall) => {\n    await this.pool.query(\n      `\n      INSERT INTO \"${contractCallsTableName}\" (\"key\", \"result\")\n      VALUES ($1, $2)\n      ON CONFLICT(\"key\") DO NOTHING\n      `,\n      [contractCall.key, contractCall.result]\n    );\n  };\n\n  getContractCall = async (contractCallKey: string) => {\n    const { rows, rowCount } = await this.pool.query<ContractCall>(\n      `SELECT * FROM \"${contractCallsTableName}\" WHERE \"key\" = $1`,\n      [contractCallKey]\n    );\n\n    if (rowCount == 0) return null;\n    return rows[0];\n  };\n\n  private buildInsertParams = (propertyCount: number, itemCount: number) =>\n    [...Array(itemCount).keys()]\n      .map(\n        (itemIndex) =>\n          `(${[...Array(propertyCount).keys()]\n            .map(\n              (propertyIndex) =>\n                `$${itemIndex * propertyCount + (propertyIndex + 1)}`\n            )\n            .join(\",\")})`\n      )\n      .join(\",\");\n}\n","import { Address } from \"abitype\";\nimport type Sqlite from \"better-sqlite3\";\nimport { Hex } from \"viem\";\n\nimport type { Block, Log, Transaction } from \"@/common/types\";\nimport { merge_intervals } from \"@/common/utils\";\n\nimport type {\n  CacheStore,\n  ContractCall,\n  LogFilterCachedRange,\n} from \"./cacheStore\";\nimport {\n  DatabaseBlock,\n  DatabaseLog,\n  DatabaseTransaction,\n  decodeBlock,\n  decodeLog,\n  decodeTransaction,\n  encodeBlock,\n  encodeLog,\n  encodeTransaction,\n} from \"./mappers\";\n\nexport const SQLITE_TABLE_PREFIX = \"__ponder__v3__\";\n\nconst logFilterCachedRangesTableName = `${SQLITE_TABLE_PREFIX}logFilterCachedRanges`;\nconst logsTableName = `${SQLITE_TABLE_PREFIX}logs`;\nconst blocksTableName = `${SQLITE_TABLE_PREFIX}blocks`;\nconst transactionsTableName = `${SQLITE_TABLE_PREFIX}transactions`;\nconst contractCallsTableName = `${SQLITE_TABLE_PREFIX}contractCalls`;\n\n// There are some quirks about the way the SQLite persists data that require\n// slightly different types. Specifically, bigints larger than 9223372036854775807\n// must be persisted as strings, and any fields than can be undefined on the objects\n// coming from viem (notably the transaction fee parameters) must be explcitly defined\n// as `null` rather than `undefined`.\n\nexport class SqliteCacheStore implements CacheStore {\n  db: Sqlite.Database;\n\n  constructor({ db }: { db: Sqlite.Database }) {\n    this.db = db;\n  }\n\n  migrate = async () => {\n    this.db\n      .prepare(\n        `\n        CREATE TABLE IF NOT EXISTS \"${logFilterCachedRangesTableName}\" (\n          \"id\" INTEGER PRIMARY KEY,\n          \"filterKey\" TEXT NOT NULL,\n          \"startBlock\" INTEGER NOT NULL,\n          \"endBlock\" INTEGER NOT NULL,\n          \"endBlockTimestamp\" INTEGER NOT NULL\n        )\n        `\n      )\n      .run();\n    this.db\n      .prepare(\n        `\n        CREATE INDEX IF NOT EXISTS \"${logFilterCachedRangesTableName}FilterKey\"\n        ON \"${logFilterCachedRangesTableName}\" (\"filterKey\")\n        `\n      )\n      .run();\n\n    this.db\n      .prepare(\n        `\n        CREATE TABLE IF NOT EXISTS \"${logsTableName}\" (\n          \"logId\" TEXT PRIMARY KEY,\n          \"logSortKey\" INTEGER NOT NULL,\n          \"address\" TEXT NOT NULL,\n          \"data\" TEXT NOT NULL,\n          \"topic0\" TEXT,\n          \"topic1\" TEXT,\n          \"topic2\" TEXT,\n          \"topic3\" TEXT,\n          \"blockHash\" TEXT NOT NULL,\n          \"blockNumber\" INTEGER NOT NULL,\n          \"logIndex\" INTEGER NOT NULL,\n          \"transactionHash\" TEXT NOT NULL,\n          \"transactionIndex\" INTEGER NOT NULL,\n          \"removed\" INTEGER NOT NULL,\n          \"blockTimestamp\" INTEGER,\n          \"chainId\" INT NOT NULL\n        )\n        `\n      )\n      .run();\n\n    this.db\n      .prepare(\n        `\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}Address\"\n        ON \"${logsTableName}\" (\"address\")\n        `\n      )\n      .run();\n    this.db\n      .prepare(\n        `\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}Topic0\"\n        ON \"${logsTableName}\" (\"topic0\")\n        `\n      )\n      .run();\n    this.db\n      .prepare(\n        `\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}BlockTimestamp\"\n        ON \"${logsTableName}\" (\"blockTimestamp\")\n        `\n      )\n      .run();\n    this.db\n      .prepare(\n        `\n        CREATE INDEX IF NOT EXISTS \"${logsTableName}ChainId\"\n        ON \"${logsTableName}\" (\"chainId\")\n        `\n      )\n      .run();\n\n    this.db\n      .prepare(\n        `\n        CREATE TABLE IF NOT EXISTS \"${blocksTableName}\" (\n          \"hash\" TEXT PRIMARY KEY,\n          \"number\" INTEGER NOT NULL,\n          \"timestamp\" INTEGER NOT NULL,\n          \"gasLimit\" TEXT NOT NULL,\n          \"gasUsed\" TEXT NOT NULL,\n          \"baseFeePerGas\" TEXT NOT NULL,\n          \"miner\" TEXT NOT NULL,\n          \"extraData\" TEXT NOT NULL,\n          \"size\" INTEGER NOT NULL,\n          \"parentHash\" TEXT NOT NULL,\n          \"stateRoot\" TEXT NOT NULL,\n          \"transactionsRoot\" TEXT NOT NULL,\n          \"receiptsRoot\" TEXT NOT NULL,\n          \"logsBloom\" TEXT NOT NULL,\n          \"totalDifficulty\" TEXT NOT NULL\n        )\n        `\n      )\n      .run();\n\n    this.db\n      .prepare(\n        `\n        CREATE TABLE IF NOT EXISTS \"${transactionsTableName}\" (\n          \"hash\" TEXT PRIMARY KEY,\n          \"nonce\" INTEGER NOT NULL,\n          \"from\" TEXT NOT NULL,\n          \"to\" TEXT,\n          \"value\" TEXT NOT NULL,\n          \"input\" TEXT NOT NULL,\n          \"gas\" TEXT NOT NULL,\n          \"gasPrice\" TEXT NOT NULL,\n          \"maxFeePerGas\" TEXT,\n          \"maxPriorityFeePerGas\" TEXT,\n          \"blockHash\" TEXT NOT NULL,\n          \"blockNumber\" INTEGER NOT NULL,\n          \"transactionIndex\" INTEGER NOT NULL,\n          \"chainId\" INT\n        )\n        `\n      )\n      .run();\n\n    this.db\n      .prepare(\n        `\n        CREATE TABLE IF NOT EXISTS \"${contractCallsTableName}\" (\n          \"key\" TEXT PRIMARY KEY,\n          \"result\" TEXT NOT NULL\n        )\n        `\n      )\n      .run();\n  };\n\n  getLogFilterCachedRanges = async ({ filterKey }: { filterKey: string }) => {\n    const rows = this.db\n      .prepare(\n        `SELECT * FROM \"${logFilterCachedRangesTableName}\" WHERE \"filterKey\" = @filterKey`\n      )\n      .all({ filterKey }) as LogFilterCachedRange[];\n\n    return rows;\n  };\n\n  insertLogFilterCachedRange = async ({\n    range: newRange,\n  }: {\n    range: LogFilterCachedRange;\n  }) => {\n    const deleteStatement = this.db.prepare<{ filterKey: string }>(`\n      DELETE FROM \"${logFilterCachedRangesTableName}\" WHERE \"filterKey\" = @filterKey RETURNING *  \n    `);\n\n    const insertStatement = this.db.prepare<LogFilterCachedRange>(`\n      INSERT INTO \"${logFilterCachedRangesTableName}\" (\n        \"filterKey\",\n        \"startBlock\",\n        \"endBlock\",\n        \"endBlockTimestamp\"\n      ) VALUES (\n        @filterKey,\n        @startBlock,\n        @endBlock,\n        @endBlockTimestamp\n      )\n    `);\n\n    const txn = this.db.transaction((newRange: LogFilterCachedRange) => {\n      const { filterKey } = newRange;\n\n      // Delete and return all ranges for this contract\n      const existingRanges = deleteStatement.all({ filterKey });\n\n      const mergedRanges: LogFilterCachedRange[] = merge_intervals([\n        ...existingRanges.map((r) => [r.startBlock, r.endBlock]),\n        [newRange.startBlock, newRange.endBlock],\n      ]).map((range) => {\n        const [startBlock, endBlock] = range;\n\n        // For each new merged range, its endBlock will be found EITHER in the newly\n        // added range OR among the endBlocks of the removed ranges.\n        // Find it so we can propogate the endBlockTimestamp correctly.\n        const endBlockTimestamp = [newRange, ...existingRanges].find(\n          (old) => old.endBlock === endBlock\n        )?.endBlockTimestamp;\n        if (!endBlockTimestamp) {\n          throw new Error(`Old range with endBlock: ${endBlock} not found`);\n        }\n\n        return {\n          filterKey: newRange.filterKey,\n          startBlock,\n          endBlock,\n          endBlockTimestamp,\n        };\n      });\n\n      mergedRanges.forEach((m) => {\n        insertStatement.run(m);\n      });\n    });\n\n    txn(newRange);\n  };\n\n  insertLogs = async (logs: Log[]) => {\n    const insertLog = this.db.prepare(\n      `\n      INSERT INTO \"${logsTableName}\" (\n        \"logId\",\n        \"logSortKey\",\n        \"address\",\n        \"data\",\n        \"topic0\",\n        \"topic1\",\n        \"topic2\",\n        \"topic3\",\n        \"blockHash\",\n        \"blockNumber\",\n        \"logIndex\",\n        \"transactionHash\",\n        \"transactionIndex\",\n        \"removed\",\n        \"chainId\"\n      ) VALUES (\n        @logId,\n        @logSortKey,\n        @address,\n        @data,\n        @topic0,\n        @topic1,\n        @topic2,\n        @topic3,\n        @blockHash,\n        @blockNumber,\n        @logIndex,\n        @transactionHash,\n        @transactionIndex,\n        @removed,\n        @chainId\n      ) ON CONFLICT(\"logId\") DO NOTHING\n      `\n    );\n\n    const insertLogsTx = this.db.transaction((logs: Log[]) => {\n      logs.forEach((log) => {\n        insertLog.run(encodeLog(log));\n      });\n    });\n\n    insertLogsTx(logs);\n  };\n\n  insertBlock = async (block: Block) => {\n    this.db\n      .prepare(\n        `\n          INSERT INTO \"${blocksTableName}\" (\n            \"hash\",\n            \"number\",\n            \"timestamp\",\n            \"gasLimit\",\n            \"gasUsed\",\n            \"baseFeePerGas\",\n            \"miner\",\n            \"extraData\",\n            \"size\",\n            \"parentHash\",\n            \"stateRoot\",\n            \"transactionsRoot\",\n            \"receiptsRoot\",\n            \"logsBloom\",\n            \"totalDifficulty\"\n          ) VALUES (\n            @hash,\n            @number,\n            @timestamp,\n            @gasLimit,\n            @gasUsed,\n            @baseFeePerGas,\n            @miner,\n            @extraData,\n            @size,\n            @parentHash,\n            @stateRoot,\n            @transactionsRoot,\n            @receiptsRoot,\n            @logsBloom,\n            @totalDifficulty\n          ) ON CONFLICT(\"hash\") DO NOTHING\n        `\n      )\n      .run(encodeBlock(block));\n\n    this.db\n      .prepare(\n        `\n          UPDATE \"${logsTableName}\"\n          SET \"blockTimestamp\" = @blockTimestamp\n          WHERE \"blockHash\" = @blockHash\n          `\n      )\n      .run({\n        blockHash: block.hash,\n        blockTimestamp: block.timestamp,\n      });\n  };\n\n  insertTransactions = async (transactions: Transaction[]) => {\n    const insertTransaction = this.db.prepare(\n      `\n      INSERT INTO \"${transactionsTableName}\" (\n        \"hash\",\n        \"nonce\",\n        \"from\",\n        \"to\",\n        \"value\",\n        \"input\",\n        \"gas\",\n        \"gasPrice\",\n        \"maxFeePerGas\",\n        \"maxPriorityFeePerGas\",\n        \"blockHash\",\n        \"blockNumber\",\n        \"transactionIndex\",\n        \"chainId\"\n      ) VALUES (\n        @hash,\n        @nonce,\n        @from,\n        @to,\n        @value,\n        @input,\n        @gas,\n        @gasPrice,\n        @maxFeePerGas,\n        @maxPriorityFeePerGas,\n        @blockHash,\n        @blockNumber,\n        @transactionIndex,\n        @chainId\n      ) ON CONFLICT(\\`hash\\`) DO NOTHING\n      `\n    );\n\n    const insertTransactionsTx = this.db.transaction(\n      (transactions: Transaction[]) => {\n        transactions.forEach((transaction) => {\n          insertTransaction.run(encodeTransaction(transaction));\n        });\n      }\n    );\n\n    insertTransactionsTx(transactions);\n  };\n\n  getLogs = async ({\n    fromBlockTimestamp,\n    toBlockTimestamp,\n    chainId,\n    address,\n    topics,\n  }: {\n    fromBlockTimestamp: number;\n    toBlockTimestamp: number;\n    chainId: number;\n    address?: Address | Address[];\n    topics?: (Hex | Hex[] | null)[];\n  }) => {\n    let filterStatement = \"\";\n    const filterParams: string[] = [];\n\n    if (address) {\n      filterStatement += ` AND \"address\"`;\n      if (typeof address === \"string\") {\n        filterStatement += ` = ?`;\n        filterParams.push(address);\n      } else {\n        filterStatement += ` IN (${[...Array(address.length).keys()]\n          .map(() => `?`)\n          .join(\",\")})`;\n        filterParams.push(...address);\n      }\n    }\n\n    (topics ?? []).forEach((topic, index) => {\n      filterStatement += ` AND \"topic${index}\"`;\n      if (typeof topic === \"string\") {\n        filterStatement += ` = ?`;\n        filterParams.push(topic);\n      } else if (Array.isArray(topic)) {\n        filterStatement += ` IN (${[...Array(topic.length).keys()]\n          .map(() => `?`)\n          .join(\",\")})`;\n        filterParams.push(...topic);\n      } else {\n        filterStatement += ` = NULL`;\n      }\n    });\n\n    const logs: DatabaseLog[] = this.db\n      .prepare(\n        `\n          SELECT * FROM \"${logsTableName}\"\n          WHERE \"blockTimestamp\" > @fromBlockTimestamp\n          AND \"blockTimestamp\" <= @toBlockTimestamp\n          AND \"chainId\" = @chainId\n          ${filterStatement}\n          `\n      )\n      .all(...filterParams, {\n        chainId,\n        fromBlockTimestamp,\n        toBlockTimestamp,\n      });\n\n    return logs.map(decodeLog);\n  };\n\n  getBlock = async (hash: string) => {\n    const block: DatabaseBlock = this.db\n      .prepare(\n        `\n        SELECT * FROM \"${blocksTableName}\" WHERE \"hash\" = @hash\n        `\n      )\n      .get({ hash });\n\n    if (!block) return null;\n\n    return decodeBlock(block);\n  };\n\n  getTransaction = async (hash: string) => {\n    const transaction: DatabaseTransaction = this.db\n      .prepare(\n        `\n        SELECT * FROM \"${transactionsTableName}\" WHERE \"hash\" = @hash\n        `\n      )\n      .get({ hash });\n\n    if (!transaction) return null;\n\n    return decodeTransaction(transaction);\n  };\n\n  upsertContractCall = async (contractCall: ContractCall) => {\n    this.db\n      .prepare(\n        `\n          INSERT INTO \"${contractCallsTableName}\" (\"key\", \"result\")\n          VALUES (@key, @result)\n          ON CONFLICT(\"key\") DO UPDATE SET\n          \"result\"=excluded.\"result\"\n          RETURNING *\n          `\n      )\n      .run(contractCall);\n  };\n\n  getContractCall = async (contractCallKey: string) => {\n    const result: ContractCall | null = this.db\n      .prepare(`SELECT * FROM \"${contractCallsTableName}\" WHERE \"key\" = @key`)\n      .get({ key: contractCallKey });\n\n    if (!result) return null;\n\n    return result;\n  };\n}\n","import { Address, Hex } from \"viem\";\n\nimport type { Block, Log, Transaction } from \"@/common/types\";\n\nimport { PonderDatabase } from \"../db\";\nimport { PostgresCacheStore } from \"./postgresCacheStore\";\nimport { SqliteCacheStore } from \"./sqliteCacheStore\";\n\nexport type LogFilterCachedRange = {\n  filterKey: string; // `${chainId}-${address}-${topics}`\n  startBlock: number;\n  endBlock: number;\n  endBlockTimestamp: number;\n};\n\nexport type ContractCall = {\n  key: string; // `${chainId}-${blockNumber}-${address}-${data}`\n  result: string; // Stringified JSON of the contract call result\n};\n\nexport interface CacheStore {\n  migrate(): Promise<void>;\n\n  getLogFilterCachedRanges(arg: {\n    filterKey: string;\n  }): Promise<LogFilterCachedRange[]>;\n  insertLogFilterCachedRange(arg: {\n    range: LogFilterCachedRange;\n  }): Promise<void>;\n\n  insertLogs(logs: Log[]): Promise<void>;\n  insertBlock(block: Omit<Block, \"transactions\">): Promise<void>;\n  insertTransactions(transactions: Transaction[]): Promise<void>;\n\n  upsertContractCall(contractCall: ContractCall): Promise<void>;\n  getContractCall(contractCallKey: string): Promise<ContractCall | null>;\n\n  getLogs(arg: {\n    fromBlockTimestamp: number;\n    toBlockTimestamp: number;\n    chainId: number;\n    address?: Address | Address[];\n    topics?: (Hex | Hex[] | null)[];\n  }): Promise<Log[]>;\n\n  getBlock(hash: string): Promise<Omit<Block, \"transactions\"> | null>;\n\n  getTransaction(hash: string): Promise<Transaction | null>;\n}\n\nexport const buildCacheStore = ({ database }: { database: PonderDatabase }) => {\n  switch (database.kind) {\n    case \"sqlite\": {\n      return new SqliteCacheStore({ db: database.db });\n    }\n    case \"postgres\": {\n      return new PostgresCacheStore({ pool: database.pool });\n    }\n  }\n};\n","import Sqlite from \"better-sqlite3\";\nimport path from \"node:path\";\nimport { DatabaseError, Pool } from \"pg\";\n\nimport { LoggerService } from \"@/common/LoggerService\";\nimport { ensureDirExists } from \"@/common/utils\";\nimport { PonderOptions } from \"@/config/options\";\nimport { ResolvedPonderConfig } from \"@/config/ponderConfig\";\nimport { PostgresError } from \"@/errors/postgres\";\nimport { SqliteError } from \"@/errors/sqlite\";\n\n// Monkeypatch Pool.query to get more informative stack traces. I have no idea why this works.\n// https://stackoverflow.com/a/70601114\nconst originalPoolQuery = Pool.prototype.query;\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nPool.prototype.query = async function query(\n  ...args: [queryText: string, values: any[], callback: () => void]\n) {\n  try {\n    return await originalPoolQuery.apply(this, args);\n  } catch (error) {\n    const [statement, parameters] = args;\n\n    if (error instanceof DatabaseError) {\n      throw new PostgresError({\n        statement,\n        parameters: parameters ?? [],\n        pgError: error,\n      });\n    }\n\n    throw error;\n  }\n};\n\nconst patchSqliteDatabase = ({ db }: { db: Sqlite.Database }) => {\n  const oldPrepare = db.prepare;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  db.prepare = (source: string) => {\n    const statement = oldPrepare.apply(db, [source]);\n\n    const wrapper =\n      (fn: (...args: any) => void) =>\n      (...args: any) => {\n        try {\n          return fn.apply(statement, args);\n        } catch (error) {\n          throw new SqliteError({\n            statement: source,\n            parameters: args,\n            sqliteError: error as Error,\n          });\n        }\n      };\n\n    for (const method of [\"run\", \"get\", \"all\"]) {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      statement[method] = wrapper(statement[method]);\n    }\n\n    return statement;\n  };\n\n  return db;\n};\n\nexport interface SqliteDb {\n  kind: \"sqlite\";\n  db: Sqlite.Database;\n}\n\nexport interface PostgresDb {\n  kind: \"postgres\";\n  pool: Pool;\n}\n\nexport type PonderDatabase = SqliteDb | PostgresDb;\n\nexport const buildDb = ({\n  options,\n  config,\n  logger,\n}: {\n  options: PonderOptions;\n  config: ResolvedPonderConfig;\n  logger: LoggerService;\n}): PonderDatabase => {\n  let resolvedDatabaseConfig: NonNullable<ResolvedPonderConfig[\"database\"]>;\n\n  const defaultSqliteFilename = path.join(options.ponderDir, \"cache.db\");\n\n  if (config.database) {\n    if (config.database.kind === \"postgres\") {\n      resolvedDatabaseConfig = {\n        kind: \"postgres\",\n        connectionString: config.database.connectionString,\n      };\n    } else {\n      resolvedDatabaseConfig = {\n        kind: \"sqlite\",\n        filename: config.database.filename ?? defaultSqliteFilename,\n      };\n    }\n  } else {\n    if (process.env.DATABASE_URL) {\n      resolvedDatabaseConfig = {\n        kind: \"postgres\",\n        connectionString: process.env.DATABASE_URL,\n      };\n    } else {\n      resolvedDatabaseConfig = {\n        kind: \"sqlite\",\n        filename: defaultSqliteFilename,\n      };\n    }\n  }\n\n  if (resolvedDatabaseConfig.kind === \"sqlite\") {\n    ensureDirExists(resolvedDatabaseConfig.filename!);\n    const rawDb = Sqlite(resolvedDatabaseConfig.filename!, {\n      verbose: logger.trace,\n    });\n    rawDb.pragma(\"journal_mode = WAL\");\n\n    const db = patchSqliteDatabase({ db: rawDb });\n\n    return { kind: \"sqlite\", db };\n  } else {\n    const pool = new Pool({\n      connectionString: resolvedDatabaseConfig.connectionString,\n    });\n\n    return { kind: \"postgres\", pool };\n  }\n};\n","import { DatabaseError } from \"pg\";\n\nimport { BaseError } from \"./base\";\nimport { prettyPrint } from \"./utils\";\n\nexport class PostgresError extends BaseError {\n  name = \"PostgresError\";\n\n  constructor({\n    statement,\n    parameters,\n    pgError,\n  }: {\n    statement: string;\n    parameters: (string | number | bigint)[];\n    pgError: DatabaseError;\n  }) {\n    const params = parameters.reduce<Record<number, any>>(\n      (acc, parameter, idx) => {\n        acc[idx + 1] =\n          typeof parameter === \"string\" && parameter.length > 80\n            ? parameter.slice(0, 80).concat(\"...\")\n            : parameter;\n        return acc;\n      },\n      {}\n    );\n\n    const metaMessages = [];\n    if (pgError.detail) metaMessages.push(`Detail:\\n  ${pgError.detail}`);\n    metaMessages.push(`Statement:\\n  ${statement}`);\n    metaMessages.push(`Parameters:\\n${prettyPrint(params)}`);\n\n    const shortMessage = `PostgreSQL error: ${pgError.message}`;\n\n    super(shortMessage, {\n      metaMessages,\n    });\n  }\n}\n","import { BaseError } from \"./base\";\nimport { prettyPrint } from \"./utils\";\n\nexport class SqliteError extends BaseError {\n  name = \"SqliteError\";\n\n  constructor({\n    statement,\n    parameters,\n    sqliteError,\n  }: {\n    statement: string;\n    parameters: (string | number | bigint)[];\n    sqliteError: Error;\n  }) {\n    const params = parameters.reduce<Record<number, any>>(\n      (acc, parameter, idx) => {\n        acc[idx + 1] = parameter;\n        return acc;\n      },\n      {}\n    );\n\n    const metaMessages = [];\n    metaMessages.push(`Statement:\\n  ${statement}`);\n    metaMessages.push(`Parameters:\\n${prettyPrint(params)}`);\n\n    const shortMessage = `SQLite error: ${sqliteError.message}`;\n\n    super(shortMessage, {\n      metaMessages,\n    });\n  }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { Pool } from \"pg\";\n\nimport {\n  Entity,\n  EnumField,\n  FieldKind,\n  ListField,\n  RelationshipField,\n  ScalarField,\n  Schema,\n} from \"@/schema/types\";\n\nimport type { EntityFilter, EntityInstance, EntityStore } from \"./entityStore\";\nimport {\n  getColumnValuePairs,\n  getWhereValue,\n  sqlSymbolsForFilterType,\n} from \"./utils\";\n\nexport class PostgresEntityStore implements EntityStore {\n  pool: Pool;\n  schema?: Schema;\n  instanceId?: string;\n\n  constructor({ pool }: { pool: Pool }) {\n    this.pool = pool;\n  }\n\n  async load({ schema: newSchema }: { schema: Schema }) {\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n\n      if (this.schema) {\n        for (const entity of this.schema.entities) {\n          await client.query(\n            `DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`\n          );\n        }\n      }\n\n      this.instanceId = randomUUID();\n\n      for (const entity of newSchema.entities) {\n        const createTableStatement = this.getCreateTableStatement(entity);\n        await client.query(createTableStatement);\n      }\n\n      await client.query(\"COMMIT\");\n      this.schema = newSchema;\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  }\n\n  async reset() {\n    if (!this.schema) return;\n\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n      for (const entity of this.schema.entities) {\n        await client.query(\n          `DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`\n        );\n      }\n\n      this.instanceId = randomUUID();\n\n      for (const entity of this.schema.entities) {\n        const createTableStatement = this.getCreateTableStatement(entity);\n        await client.query(createTableStatement);\n      }\n\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  }\n\n  async teardown() {\n    if (!this.schema) return;\n\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n      for (const entity of this.schema.entities) {\n        await client.query(\n          `DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`\n        );\n      }\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  }\n\n  private getCreateTableStatement(entity: Entity) {\n    const gqlScalarToSqlType: Record<string, string | undefined> = {\n      Boolean: \"integer\",\n      Int: \"integer\",\n      String: \"text\",\n      BigInt: \"numeric(78)\", // Store BigInts as numerics large enough for Solidity's MAX_INT (2**256 - 1).\n      Bytes: \"text\",\n      Float: \"text\",\n    };\n\n    const columnStatements = entity.fields\n      .filter(\n        (\n          field\n        ): field is RelationshipField | ScalarField | ListField | EnumField =>\n          field.kind !== FieldKind.DERIVED\n      )\n      .map((field) => {\n        switch (field.kind) {\n          case FieldKind.SCALAR: {\n            const type = gqlScalarToSqlType[field.scalarTypeName];\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            const pk = field.name === \"id\" ? \"PRIMARY KEY\" : \"\";\n            return `\"${field.name}\" ${type} ${notNull} ${pk}`;\n          }\n          case FieldKind.ENUM: {\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n\n            return `\"${field.name}\" TEXT CHECK (\"${\n              field.name\n            }\" IN (${field.enumValues\n              .map((v) => `'${v}'`)\n              .join(\", \")})) ${notNull}`;\n          }\n          case FieldKind.LIST: {\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            return `\"${field.name}\" TEXT ${notNull}`;\n          }\n          case FieldKind.RELATIONSHIP: {\n            const type = gqlScalarToSqlType[field.relatedEntityIdType.name];\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            return `\"${field.name}\" ${type} ${notNull}`;\n          }\n        }\n      });\n\n    const tableName = `${entity.name}_${this.instanceId}`;\n    return `CREATE TABLE \"${tableName}\" (${columnStatements.join(\", \")})`;\n  }\n\n  findUniqueEntity = async ({\n    entityName,\n    id,\n  }: {\n    entityName: string;\n    id: string;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const statement = `SELECT \"${tableName}\".* FROM \"${tableName}\" WHERE \"${tableName}\".\"id\" = $1`;\n    const { rows, rowCount } = await this.pool.query(statement, [id]);\n\n    if (rowCount === 0) return null;\n    return this.deserialize({ entityName, instance: rows[0] });\n  };\n\n  createEntity = async ({\n    entityName,\n    id,\n    data,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const pairs = getColumnValuePairs({ ...data, id });\n    const insertValues = pairs.map(({ value }) => value);\n    const insertFragment = `(${pairs\n      .map(({ column }) => column)\n      .join(\", \")}) VALUES (${insertValues\n      .map((_, idx) => `$${idx + 1}`)\n      .join(\", \")})`;\n\n    const statement = `INSERT INTO \"${tableName}\" ${insertFragment} RETURNING *`;\n    const { rows } = await this.pool.query(statement, insertValues);\n\n    return this.deserialize({ entityName, instance: rows[0] });\n  };\n\n  updateEntity = async ({\n    entityName,\n    id,\n    data,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const pairs = getColumnValuePairs(data);\n    const updateValues = pairs.map(({ value }) => value);\n    const updateFragment = pairs\n      .map(({ column }, idx) => `${column} = $${idx + 1}`)\n      .join(\", \");\n\n    const statement = `UPDATE \"${tableName}\" SET ${updateFragment} WHERE \"id\" = $${\n      pairs.length + 1\n    } RETURNING *`;\n    updateValues.push(id.toString());\n\n    const { rows } = await this.pool.query(statement, updateValues);\n\n    return this.deserialize({ entityName, instance: rows[0] });\n  };\n\n  upsertEntity = async ({\n    entityName,\n    id,\n    create,\n    update,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    create: Record<string, unknown>;\n    update: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const insertPairs = getColumnValuePairs({ ...create, id });\n    const insertValues = insertPairs.map(({ value }) => value);\n    const insertFragment = `(${insertPairs\n      .map(({ column }) => column)\n      .join(\", \")}) VALUES (${insertValues\n      .map((_, idx) => `$${idx + 1}`)\n      .join(\", \")})`;\n\n    const updatePairs = getColumnValuePairs({ ...update, id });\n    const updateValues = updatePairs.map(({ value }) => value);\n    const updateFragment = updatePairs\n      .map(({ column }, idx) => `${column} = $${idx + 1 + insertValues.length}`)\n      .join(\", \");\n\n    const statement = `INSERT INTO \"${tableName}\" ${insertFragment} ON CONFLICT(\"id\") DO UPDATE SET ${updateFragment} RETURNING *`;\n    const { rows } = await this.pool.query(statement, [\n      ...insertValues,\n      ...updateValues,\n    ]);\n\n    return this.deserialize({ entityName, instance: rows[0] });\n  };\n\n  deleteEntity = async ({\n    entityName,\n    id,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const statement = `DELETE FROM \"${tableName}\" WHERE \"id\" = $1`;\n    const { rowCount } = await this.pool.query(statement, [id]);\n\n    return rowCount === 1;\n  };\n\n  getEntities = async ({\n    entityName,\n    filter,\n  }: {\n    entityName: string;\n    filter?: EntityFilter;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const where = filter?.where;\n    const first = filter?.first;\n    const skip = filter?.skip;\n    const orderBy = filter?.orderBy;\n    const orderDirection = filter?.orderDirection;\n\n    const fragments = [];\n\n    if (where) {\n      const whereFragments = Object.entries(where).map(([field, value]) => {\n        const [fieldName, rawFilterType] = field.split(/_(.*)/s);\n        // This is a hack to handle the \"\" operator, which the regex above doesn't handle\n        const filterType = rawFilterType === undefined ? \"\" : rawFilterType;\n        const sqlSymbols = sqlSymbolsForFilterType[filterType];\n        if (!sqlSymbols) {\n          throw new Error(\n            `SQL operators not found for filter type: ${filterType}`\n          );\n        }\n\n        const whereValue = getWhereValue(value, sqlSymbols);\n\n        return `\"${fieldName}\" ${whereValue}`;\n      });\n\n      fragments.push(`WHERE ${whereFragments.join(\" AND \")}`);\n    }\n\n    if (orderBy) {\n      fragments.push(`ORDER BY \"${orderBy}\"`);\n    }\n\n    if (orderDirection) {\n      fragments.push(`${orderDirection}`);\n    }\n\n    if (first) {\n      fragments.push(`LIMIT ${first}`);\n    }\n\n    if (skip) {\n      fragments.push(`OFFSET ${skip}`);\n    }\n\n    const statement = `SELECT * FROM \"${tableName}\" ${fragments.join(\" \")}`;\n    const { rows } = await this.pool.query(statement);\n\n    return rows.map((instance) => this.deserialize({ entityName, instance }));\n  };\n\n  deserialize = ({\n    entityName,\n    instance,\n  }: {\n    entityName: string;\n    instance: Record<string, unknown>;\n  }) => {\n    if (!this.schema) {\n      throw new Error(`EntityStore has not been initialized with a schema yet`);\n    }\n\n    const entity = this.schema?.entities.find((e) => e.name === entityName);\n    if (!entity) {\n      throw new Error(`Entity not found in schema for ID: ${entityName}`);\n    }\n\n    const deserializedInstance = { ...instance };\n\n    // For each property on the instance, look for a field defined on the entity\n    // with the same name and apply any required deserialization transforms.\n    Object.entries(instance).forEach(([fieldName, value]) => {\n      const field = entity.fieldByName[fieldName];\n      if (!field) return;\n\n      switch (field.kind) {\n        case FieldKind.SCALAR: {\n          if (field.scalarTypeName === \"Boolean\") {\n            deserializedInstance[fieldName] = value === 1 ? true : false;\n          } else {\n            deserializedInstance[fieldName] = value;\n          }\n          break;\n        }\n        case FieldKind.LIST: {\n          deserializedInstance[fieldName] = JSON.parse(value as string);\n          break;\n        }\n        default: {\n          deserializedInstance[fieldName] = value;\n        }\n      }\n    });\n\n    return deserializedInstance as EntityInstance;\n  };\n}\n","export const sqlSymbolsForFilterType: Record<\n  string,\n  | {\n      operator: string;\n      patternPrefix?: string;\n      patternSuffix?: string;\n    }\n  | undefined\n> = {\n  // universal\n  \"\": { operator: \"=\" },\n  not: { operator: \"!=\" },\n  // singular\n  in: { operator: \"in\" },\n  not_in: { operator: \"not in\" },\n  // plural\n  contains: { operator: \"like\", patternPrefix: \"%\", patternSuffix: \"%\" },\n  contains_nocase: {\n    operator: \"like\",\n    patternPrefix: \"%\",\n    patternSuffix: \"%\",\n  },\n  not_contains: {\n    operator: \"not like\",\n    patternPrefix: \"%\",\n    patternSuffix: \"%\",\n  },\n  not_contains_nocase: {\n    operator: \"not like\",\n    patternPrefix: \"%\",\n    patternSuffix: \"%\",\n  },\n  // numeric\n  gt: { operator: \">\" },\n  lt: { operator: \"<\" },\n  gte: { operator: \">=\" },\n  lte: { operator: \"<=\" },\n  // string\n  starts_with: { operator: \"like\", patternSuffix: \"%\" },\n  starts_with_nocase: { operator: \"like\", patternSuffix: \"%\" },\n  ends_with: { operator: \"like\", patternPrefix: \"%\" },\n  ends_with_nocase: { operator: \"like\", patternPrefix: \"%\" },\n  not_starts_with: { operator: \"not like\", patternSuffix: \"%\" },\n  not_starts_with_nocase: { operator: \"not like\", patternSuffix: \"%\" },\n  not_ends_with: { operator: \"not like\", patternSuffix: \"%\" },\n  not_ends_with_nocase: { operator: \"not like\", patternSuffix: \"%\" },\n};\n\n// Accepts an instance being passed to `insert`, `update`, or `upsert` and\n// returns a list of column names and values to be persisted.\nexport const getWhereValue = (\n  value:\n    | boolean\n    | number\n    | string\n    | (number | string | boolean)[]\n    | undefined\n    | null,\n  sqlSymbols: {\n    operator: string;\n    patternPrefix?: string;\n    patternSuffix?: string;\n  }\n): string => {\n  const { operator, patternPrefix, patternSuffix } = sqlSymbols;\n\n  if (value === null) {\n    if ([\"=\", \"!=\"].includes(operator)) {\n      return `${operator === \"=\" ? \"IS\" : \"IS NOT\"} ${value}`;\n    } else {\n      return `${operator} ${value}`;\n    }\n  }\n\n  if (typeof value === \"object\" && value.length) {\n    return `${operator} (${value\n      .map((v) => {\n        if (typeof v === \"boolean\") {\n          return v ? 1 : 0;\n        } else if (typeof v === \"string\") {\n          return `'${v}'`;\n        } else {\n          return `${v}`;\n        }\n      })\n      .join(\",\")})`;\n  }\n\n  if (typeof value === \"boolean\") {\n    return `${operator} ${value ? 1 : 0}`;\n  }\n\n  // At this point we assume the value is a string.\n  let finalValue = value;\n  if (patternPrefix) finalValue = `${patternPrefix}${finalValue}`;\n  if (patternSuffix) finalValue = `${finalValue}${patternSuffix}`;\n\n  return `${operator} '${finalValue}'`;\n};\n\n// Accepts an instance being passed to `insert`, `update`, or `upsert` and\n// returns a list of column names and values to be persisted.\nexport const getColumnValuePairs = (instance: Record<string, unknown>) => {\n  return Object.entries(instance)\n    .map(([fieldName, value]) => {\n      let persistedValue: number | string | null;\n      if (typeof value === \"boolean\") {\n        persistedValue = value ? 1 : 0;\n      } else if (typeof value === \"bigint\") {\n        persistedValue = value.toString();\n      } else if (typeof value === \"undefined\") {\n        persistedValue = null;\n      } else if (Array.isArray(value)) {\n        persistedValue = JSON.stringify(value);\n      } else {\n        persistedValue = value as number | string | null;\n      }\n\n      return {\n        column: `\"${fieldName}\"`,\n        value: persistedValue,\n      };\n    })\n    .filter(\n      (\n        col\n      ): col is {\n        column: string;\n        value: string | number;\n      } => col.value !== null\n    );\n};\n","import type Sqlite from \"better-sqlite3\";\nimport { randomUUID } from \"node:crypto\";\n\nimport {\n  Entity,\n  EnumField,\n  FieldKind,\n  ListField,\n  RelationshipField,\n  ScalarField,\n  Schema,\n} from \"@/schema/types\";\n\nimport { EntityFilter, EntityInstance, EntityStore } from \"./entityStore\";\nimport {\n  getColumnValuePairs,\n  getWhereValue,\n  sqlSymbolsForFilterType,\n} from \"./utils\";\n\nexport class SqliteEntityStore implements EntityStore {\n  db: Sqlite.Database;\n  schema?: Schema;\n  instanceId?: string;\n\n  constructor({ db }: { db: Sqlite.Database }) {\n    this.db = db;\n  }\n\n  load({ schema: newSchema }: { schema: Schema }) {\n    if (this.schema) {\n      this.schema.entities.forEach((entity) => {\n        this.db\n          .prepare(`DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`)\n          .run();\n      });\n    }\n\n    this.instanceId = randomUUID();\n\n    for (const entity of newSchema.entities) {\n      const createTableStatement = this.getCreateTableStatement(entity);\n      this.db.prepare(createTableStatement).run();\n    }\n\n    this.schema = newSchema;\n  }\n\n  reset() {\n    if (!this.schema) return;\n\n    for (const entity of this.schema.entities) {\n      this.db\n        .prepare(`DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`)\n        .run();\n    }\n\n    this.instanceId = randomUUID();\n\n    for (const entity of this.schema.entities) {\n      const createTableStatement = this.getCreateTableStatement(entity);\n      this.db.prepare(createTableStatement).run();\n    }\n  }\n\n  teardown() {\n    if (!this.schema) return;\n\n    for (const entity of this.schema.entities) {\n      this.db\n        .prepare(`DROP TABLE IF EXISTS \"${entity.name}_${this.instanceId}\"`)\n        .run();\n    }\n  }\n\n  private getCreateTableStatement(entity: Entity) {\n    const gqlScalarToSqlType: Record<string, string | undefined> = {\n      Boolean: \"integer\",\n      Int: \"integer\",\n      String: \"text\",\n      BigInt: \"text\",\n      Bytes: \"text\",\n      Float: \"text\",\n    };\n\n    const columnStatements = entity.fields\n      .filter(\n        (\n          field\n        ): field is RelationshipField | ScalarField | ListField | EnumField =>\n          field.kind !== FieldKind.DERIVED\n      )\n      .map((field) => {\n        switch (field.kind) {\n          case FieldKind.SCALAR: {\n            const type = gqlScalarToSqlType[field.scalarTypeName];\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            const pk = field.name === \"id\" ? \"PRIMARY KEY\" : \"\";\n            return `\"${field.name}\" ${type} ${notNull} ${pk}`;\n          }\n          case FieldKind.ENUM: {\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n\n            return `\"${field.name}\" TEXT CHECK (\"${\n              field.name\n            }\" IN (${field.enumValues\n              .map((v) => `'${v}'`)\n              .join(\", \")})) ${notNull}`;\n          }\n          case FieldKind.LIST: {\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            return `\"${field.name}\" TEXT ${notNull}`;\n          }\n          case FieldKind.RELATIONSHIP: {\n            const type = gqlScalarToSqlType[field.relatedEntityIdType.name];\n            const notNull = field.notNull ? \"NOT NULL\" : \"\";\n            return `\"${field.name}\" ${type} ${notNull}`;\n          }\n        }\n      });\n\n    const tableName = `${entity.name}_${this.instanceId}`;\n    return `CREATE TABLE \"${tableName}\" (${columnStatements.join(\", \")})`;\n  }\n\n  findUniqueEntity = async ({\n    entityName,\n    id,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const statement = `SELECT \"${tableName}\".* FROM \"${tableName}\" WHERE \"${tableName}\".\"id\" = ?`;\n    const instance = this.db.prepare(statement).get(id);\n\n    if (!instance) return null;\n\n    return this.deserialize({ entityName, instance });\n  };\n\n  createEntity = async ({\n    entityName,\n    id,\n    data,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const pairs = getColumnValuePairs({ ...data, id });\n    const insertValues = pairs.map((s) => s.value);\n    const insertFragment = `(${pairs\n      .map((s) => s.column)\n      .join(\", \")}) VALUES (${insertValues.map(() => \"?\").join(\", \")})`;\n\n    const statement = `INSERT INTO \"${tableName}\" ${insertFragment} RETURNING *`;\n\n    const insertedEntity = this.db.prepare(statement).get(...insertValues);\n\n    return this.deserialize({ entityName, instance: insertedEntity });\n  };\n\n  updateEntity = async ({\n    entityName,\n    id,\n    data,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const pairs = getColumnValuePairs(data);\n\n    const updatePairs = pairs.filter(({ column }) => column !== \"id\");\n    const updateValues = updatePairs.map(({ value }) => value);\n    const updateFragment = updatePairs\n      .map(({ column }) => `${column} = ?`)\n      .join(\", \");\n\n    const statement = `UPDATE \"${tableName}\" SET ${updateFragment} WHERE \"id\" = ? RETURNING *`;\n    updateValues.push(`${id}`);\n\n    const updatedEntity = this.db.prepare(statement).get(...updateValues);\n\n    return this.deserialize({ entityName, instance: updatedEntity });\n  };\n\n  upsertEntity = async ({\n    entityName,\n    id,\n    create,\n    update,\n  }: {\n    entityName: string;\n    id: string | number | bigint;\n    create: Record<string, unknown>;\n    update: Record<string, unknown>;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    // Add the passed `id` to the create object.\n    const insertPairs = getColumnValuePairs({ ...create, id });\n    const insertValues = insertPairs.map((s) => s.value);\n    const insertFragment = `(${insertPairs\n      .map((s) => s.column)\n      .join(\", \")}) VALUES (${insertValues.map(() => \"?\").join(\", \")})`;\n\n    const updatePairs = getColumnValuePairs({ ...update, id });\n    const updateValues = updatePairs.map(({ value }) => value);\n    const updateFragment = updatePairs\n      .map(({ column }) => `${column} = ?`)\n      .join(\", \");\n\n    const statement = `INSERT INTO \"${tableName}\" ${insertFragment} ON CONFLICT(\"id\") DO UPDATE SET ${updateFragment} RETURNING *`;\n\n    const upsertedEntity = this.db\n      .prepare(statement)\n      .get(...insertValues, ...updateValues);\n\n    return this.deserialize({ entityName, instance: upsertedEntity });\n  };\n\n  deleteEntity = async ({\n    entityName,\n    id,\n  }: {\n    entityName: string;\n    id: string;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const statement = `DELETE FROM \"${tableName}\" WHERE \"id\" = ?`;\n\n    const { changes } = this.db.prepare(statement).run(id);\n\n    // `changes` is equal to the number of rows that were updated/inserted/deleted by the query.\n    return changes === 1;\n  };\n\n  getEntities = async ({\n    entityName,\n    filter,\n  }: {\n    entityName: string;\n    filter?: EntityFilter;\n  }) => {\n    const tableName = `${entityName}_${this.instanceId}`;\n\n    const where = filter?.where;\n    const first = filter?.first;\n    const skip = filter?.skip;\n    const orderBy = filter?.orderBy;\n    const orderDirection = filter?.orderDirection;\n\n    const fragments = [];\n\n    if (where) {\n      const whereFragments = Object.entries(where).map(([field, value]) => {\n        const [fieldName, rawFilterType] = field.split(/_(.*)/s);\n\n        // This is a hack to handle the \"\" operator, which the regex above doesn't handle\n        const filterType = rawFilterType === undefined ? \"\" : rawFilterType;\n        const sqlSymbols = sqlSymbolsForFilterType[filterType];\n        if (!sqlSymbols) {\n          throw new Error(\n            `SQL operators not found for filter type: ${filterType}`\n          );\n        }\n\n        const whereValue = getWhereValue(value, sqlSymbols);\n\n        return `\"${fieldName}\" ${whereValue}`;\n      });\n\n      fragments.push(`WHERE ${whereFragments.join(\" AND \")}`);\n    }\n\n    if (orderBy) {\n      const entity = this.schema?.entities.find((e) => e.name === entityName);\n      const orderByField = entity?.fieldByName[orderBy] as ScalarField;\n      // Bigints are stored as strings in SQLite. This means when trying to\n      // order by a bigint field, the values are sorted as strings. This\n      // fixes the issue by casting them as REAL for the purposes of sorting.\n      if (orderByField.scalarTypeName === \"BigInt\") {\n        fragments.push(`ORDER BY CAST(\"${orderBy}\" AS REAL)`);\n      } else {\n        fragments.push(`ORDER BY \"${orderBy}\"`);\n      }\n    }\n\n    if (orderDirection) {\n      fragments.push(`${orderDirection}`);\n    }\n\n    if (first) {\n      fragments.push(`LIMIT ${first}`);\n    }\n\n    if (skip) {\n      if (!first) {\n        fragments.push(`LIMIT -1`); // Must add a no-op limit for SQLite to handle offset\n      }\n      fragments.push(`OFFSET ${skip}`);\n    }\n\n    const statement = `SELECT * FROM \"${tableName}\" ${fragments.join(\" \")}`;\n\n    const instances = this.db.prepare(statement).all();\n\n    return instances.map((instance) =>\n      this.deserialize({ entityName, instance })\n    );\n  };\n\n  deserialize = ({\n    entityName,\n    instance,\n  }: {\n    entityName: string;\n    instance: Record<string, unknown>;\n  }) => {\n    const entity = this.schema?.entities.find((e) => e.name === entityName);\n    if (!entity) {\n      throw new Error(`Entity not found in schema with name: ${entityName}`);\n    }\n\n    const deserializedInstance = { ...instance };\n\n    // For each property on the instance, look for a field defined on the entity\n    // with the same name and apply any required deserialization transforms.\n    Object.entries(instance).forEach(([fieldName, value]) => {\n      const field = entity.fieldByName[fieldName];\n      if (!field) return;\n\n      switch (field.kind) {\n        case FieldKind.SCALAR: {\n          if (field.scalarTypeName === \"Boolean\") {\n            deserializedInstance[fieldName] = value === 1 ? true : false;\n          } else {\n            deserializedInstance[fieldName] = value;\n          }\n          break;\n        }\n        case FieldKind.LIST: {\n          deserializedInstance[fieldName] = JSON.parse(value as string);\n          break;\n        }\n        default: {\n          deserializedInstance[fieldName] = value;\n        }\n      }\n    });\n\n    return deserializedInstance as EntityInstance;\n  };\n}\n","import type { Schema } from \"@/schema/types\";\n\nimport { PonderDatabase } from \"../db\";\nimport { PostgresEntityStore } from \"./postgresEntityStore\";\nimport { SqliteEntityStore } from \"./sqliteEntityStore\";\n\nexport type EntityFilter = {\n  where?: {\n    [key: string]:\n      | number\n      | string\n      | number[]\n      | string[]\n      | true\n      | false\n      | undefined\n      | null;\n  };\n  first?: number;\n  skip?: number;\n  orderBy?: string;\n  orderDirection?: \"asc\" | \"desc\";\n};\n\nexport type EntityInstance = Record<string, unknown> & {\n  id: string | number | bigint;\n};\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport interface EntityStore {\n  schema?: Schema;\n\n  load(arg: { schema: Schema }): MaybePromise<void>;\n  reset(): MaybePromise<void>;\n  teardown(): MaybePromise<void>;\n\n  findUniqueEntity(arg: {\n    entityName: string;\n    id: string | number | bigint;\n  }): Promise<EntityInstance | null>;\n\n  createEntity(arg: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Omit<EntityInstance, \"id\">;\n  }): Promise<EntityInstance>;\n\n  updateEntity(arg: {\n    entityName: string;\n    id: string | number | bigint;\n    data: Omit<Partial<EntityInstance>, \"id\">;\n  }): Promise<EntityInstance>;\n\n  upsertEntity(arg: {\n    entityName: string;\n    id: string | number | bigint;\n    create: Omit<EntityInstance, \"id\">;\n    update: Omit<Partial<EntityInstance>, \"id\">;\n  }): Promise<EntityInstance>;\n\n  deleteEntity(arg: {\n    entityName: string;\n    id: string | number | bigint;\n  }): Promise<boolean>;\n\n  getEntities(arg: {\n    entityName: string;\n    filter?: EntityFilter;\n  }): Promise<EntityInstance[]>;\n}\n\nexport const buildEntityStore = ({\n  database,\n}: {\n  database: PonderDatabase;\n}) => {\n  switch (database.kind) {\n    case \"sqlite\": {\n      return new SqliteEntityStore({ db: database.db });\n    }\n    case \"postgres\": {\n      return new PostgresEntityStore({ pool: database.pool });\n    }\n  }\n};\n","import Emittery from \"emittery\";\n\ntype ErrorServiceEvents = {\n  handlerError: { error: Error };\n  handlerErrorCleared: undefined;\n};\n\nexport class ErrorService extends Emittery<ErrorServiceEvents> {\n  isHandlerError = false;\n\n  submitHandlerError({ error }: { error: Error }) {\n    this.isHandlerError = true;\n    this.emit(\"handlerError\", { error });\n  }\n\n  clearHandlerError() {\n    this.isHandlerError = false;\n    this.emit(\"handlerErrorCleared\");\n  }\n}\n","import Emittery from \"emittery\";\nimport { Address, Log as ViemLog } from \"viem\";\n\nimport { LogFilter } from \"@/config/logFilters\";\nimport { Network } from \"@/config/networks\";\nimport { Resources } from \"@/Ponder\";\n\nimport { createBlockFrontfillQueue } from \"./blockFrontfillQueue\";\nimport { createLogFrontfillQueue } from \"./logFrontfillQueue\";\n\nexport type FrontfillServiceEvents = {\n  networkConnected: {\n    network: string;\n    blockNumber: number;\n    blockTimestamp: number;\n  };\n  frontfillStarted: { logFilterGroupCount: number };\n\n  logTasksAdded: { network: string; count: number };\n  logTaskFailed: { network: string; error: Error };\n  logTaskCompleted: {\n    network: string;\n    logData: Record<number, Record<string, number>>;\n  };\n\n  blockTasksAdded: { network: string; count: number };\n  blockTaskFailed: { network: string; error: Error };\n  blockTaskCompleted: { network: string };\n\n  nextLogBatch: { network: string };\n  eventsAdded: undefined;\n};\n\nexport type LogFilterGroup = {\n  id: string;\n  filterKeys: string[];\n  filter: Omit<LogFilter[\"filter\"], \"key\">;\n  network: Network;\n  startBlockNumber: number;\n  startBlockTimestamp: number;\n};\n\nexport class FrontfillService extends Emittery<FrontfillServiceEvents> {\n  resources: Resources;\n\n  private killFunctions: (() => Promise<void>)[] = [];\n  private nextBatchIdleFunctions: (() => Promise<void>)[] = [];\n\n  logFilterGroups: LogFilterGroup[] = [];\n  currentBlockNumbers: Record<string, number> = {};\n\n  backfillCutoffTimestamp = Number.POSITIVE_INFINITY;\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n  }\n\n  async getLatestBlockNumbers() {\n    const liveLogFilters = this.resources.logFilters.filter(\n      (f) => f.endBlock === undefined\n    );\n\n    // If there are no live log filters, set backfillCutoffTimestamp to the\n    // greatest timestamp among all the end blocks of all historical log filters.\n    if (liveLogFilters.length === 0) {\n      this.backfillCutoffTimestamp = await this.getMaxEndBlockTimestamp();\n      return;\n    }\n\n    const liveNetworks = [\n      ...new Map(\n        liveLogFilters.map((f) => [f.network.name, f.network])\n      ).values(),\n    ];\n\n    await Promise.all(\n      liveNetworks.map(async (network) => {\n        const block = await network.client.getBlock({\n          blockTag: \"latest\",\n          includeTransactions: false,\n        });\n\n        const latestBlockData = {\n          blockNumber: Number(block.number),\n          blockTimestamp: Number(block.timestamp),\n        };\n\n        // Create a live log filter group for all \"simple\" log filters on this network.\n        // A \"simple\" log filter has just one contract address and no topics.\n        const simpleLogFilters = this.resources.logFilters.filter(\n          (f): f is LogFilter & { address: Address } =>\n            f.network.name === network.name && // Is on this network.\n            f.endBlock === undefined && // Is a live filter.\n            typeof f.filter.address === \"string\" && // Is a single contract.\n            f.filter.topics === undefined // Is simple.\n        );\n        if (simpleLogFilters.length > 0) {\n          const groupId = `${network.name}-simple`;\n          this.logFilterGroups.push({\n            id: groupId,\n            filterKeys: simpleLogFilters.map((f) => f.filter.key),\n            filter: {\n              address: simpleLogFilters.map((f) => f.filter.address as Address),\n            },\n            network,\n            startBlockNumber: latestBlockData.blockNumber,\n            startBlockTimestamp: latestBlockData.blockTimestamp,\n          });\n          this.currentBlockNumbers[groupId] = latestBlockData.blockNumber;\n        }\n\n        // Create a live log filter group for each \"complex\" log filter on this network.\n        // This includes any log filters that specify topics, or don't specify a single address.\n        const complexLogFilters = this.resources.logFilters.filter(\n          (f) =>\n            f.network.name === network.name && // Is on this network.\n            f.endBlock === undefined && // Is a live filter.\n            (typeof f.filter.address !== \"string\" || // Is not a single contract.\n              f.filter.topics !== undefined) // Is not simple.\n        );\n        complexLogFilters.forEach((logFilter, index) => {\n          const groupId = `${network.name}-complex-${index}`;\n          this.logFilterGroups.push({\n            id: groupId,\n            filterKeys: [logFilter.filter.key],\n            filter: logFilter.filter,\n            network,\n            startBlockNumber: latestBlockData.blockNumber,\n            startBlockTimestamp: latestBlockData.blockTimestamp,\n          });\n          this.currentBlockNumbers[groupId] = latestBlockData.blockNumber;\n        });\n\n        // Set `endBlock` to the latest block number for any log filters that did not specify one.\n        // This dangerously mutates `resources.logFilters`, and should be reconsidered.\n        this.resources.logFilters.forEach((logFilter) => {\n          if (logFilter.network.name === network.name) {\n            logFilter.endBlock = latestBlockData.blockNumber;\n          }\n        });\n\n        // Update the max timestamp.\n        this.backfillCutoffTimestamp = Math.min(\n          this.backfillCutoffTimestamp,\n          latestBlockData.blockTimestamp\n        );\n\n        this.emit(\"networkConnected\", {\n          network: network.name,\n          ...latestBlockData,\n        });\n      })\n    );\n  }\n\n  startFrontfill() {\n    // If there are no live networks, return early.\n    if (this.logFilterGroups.length === 0) return;\n\n    this.logFilterGroups.forEach((group) => {\n      const blockFrontfillQueue = createBlockFrontfillQueue({\n        frontfillService: this,\n        group,\n      });\n\n      const logFrontfillQueue = createLogFrontfillQueue({\n        frontfillService: this,\n        group,\n        blockFrontfillQueue,\n      });\n\n      const handleLogs = async (logs: ViemLog[]) => {\n        this.emit(\"nextLogBatch\", { network: group.network.name });\n        if (logs.length === 0) return;\n\n        await logFrontfillQueue.addTask({ logs });\n      };\n\n      const unwatch = group.network.client.watchEvent({\n        address: group.filter.address,\n        event: group.filter.event,\n        args: group.filter.args as unknown as undefined,\n        onLogs: handleLogs,\n        pollingInterval: group.network.pollingInterval,\n        batch: true,\n      });\n\n      this.killFunctions.push(async () => {\n        unwatch();\n        logFrontfillQueue.clear();\n        await logFrontfillQueue.onIdle();\n        blockFrontfillQueue.clear();\n        await blockFrontfillQueue.onIdle();\n      });\n\n      this.nextBatchIdleFunctions.push(async () => {\n        let listener: (\n          event: FrontfillServiceEvents[\"nextLogBatch\"]\n        ) => void = () => undefined;\n\n        await new Promise<void>((resolve, reject) => {\n          const timeout = setTimeout(\n            () =>\n              reject(\n                new Error(\n                  `Did not receive event \"newLogBatch\" within timeout (${\n                    group.network.pollingInterval * 2\n                  }ms)`\n                )\n              ),\n            group.network.pollingInterval * 10\n          );\n          listener = ({ network: _network }) => {\n            if (_network === group.network.name) {\n              clearTimeout(timeout);\n              resolve();\n            }\n          };\n          this.on(\"nextLogBatch\", listener);\n        });\n\n        this.off(\"nextLogBatch\", listener);\n\n        await logFrontfillQueue.onIdle();\n        await blockFrontfillQueue.onIdle();\n      });\n    });\n\n    this.emit(\"frontfillStarted\", {\n      logFilterGroupCount: this.logFilterGroups.length,\n    });\n  }\n\n  async kill() {\n    await Promise.all(this.killFunctions.map((f) => f()));\n  }\n\n  // This function returns a promise that resolves when the next\n  // `eth_getFilterChanges` request is complete AND all tasks\n  // resulting from that batch of logs have been processed,\n  // for ALL live networks.\n  async nextBatchesIdle() {\n    await Promise.all(this.nextBatchIdleFunctions.map((f) => f()));\n  }\n\n  private async getMaxEndBlockTimestamp() {\n    const blocks = await Promise.all(\n      this.resources.logFilters\n        .filter((logFilter) => logFilter.endBlock !== undefined)\n        .map(async (logFilter) => {\n          return await logFilter.network.client.getBlock({\n            blockNumber: BigInt(logFilter.endBlock!),\n            includeTransactions: false,\n          });\n        })\n    );\n\n    const maxEndBlockTimestamp = Math.max(\n      ...blocks.map((block) => Number(block.timestamp))\n    );\n\n    return maxEndBlockTimestamp;\n  }\n}\n","import { Hash, Transaction as ViemTransaction } from \"viem\";\n\nimport { createQueue, Queue, Worker } from \"@/common/createQueue\";\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { parseBlock, parseTransactions } from \"@/common/types\";\n\nimport { FrontfillService, LogFilterGroup } from \"./FrontfillService\";\n\nexport type BlockFrontfillTask = {\n  blockNumberToCacheFrom: number;\n  blockNumber: number;\n  requiredTxHashes: Set<Hash>;\n};\n\nexport type BlockFrontfillWorkerContext = {\n  frontfillService: FrontfillService;\n  group: LogFilterGroup;\n};\n\nexport type BlockFrontfillQueue = Queue<BlockFrontfillTask>;\n\nexport const createBlockFrontfillQueue = (\n  context: BlockFrontfillWorkerContext\n) => {\n  const queue = createQueue({\n    worker: blockFrontfillWorker,\n    context,\n    options: {\n      concurrency: 1,\n    },\n  });\n\n  // Pass queue events on to service layer.\n  queue.on(\"add\", () => {\n    context.frontfillService.emit(\"blockTasksAdded\", {\n      network: context.group.network.name,\n      count: 1,\n    });\n  });\n\n  queue.on(\"error\", ({ error }) => {\n    context.frontfillService.emit(\"blockTaskFailed\", {\n      network: context.group.network.name,\n      error,\n    });\n  });\n\n  queue.on(\"completed\", () => {\n    context.frontfillService.emit(\"blockTaskCompleted\", {\n      network: context.group.network.name,\n    });\n  });\n\n  // Default to a simple retry.\n  queue.on(\"error\", ({ task }) => {\n    queue.addTask(task);\n  });\n\n  return queue;\n};\n\nconst blockFrontfillWorker: Worker<\n  BlockFrontfillTask,\n  BlockFrontfillWorkerContext\n> = async ({ task, context }) => {\n  const { blockNumber, requiredTxHashes, blockNumberToCacheFrom } = task;\n  const { frontfillService, group } = context;\n  const { client } = group.network;\n\n  const rawBlock = await client.getBlock({\n    blockNumber: BigInt(blockNumber),\n    includeTransactions: true,\n  });\n\n  const block = parseBlock(rawBlock);\n\n  // If the block is pending, log a warning.\n  if (!block) {\n    frontfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending block (number: ${blockNumber})`\n    );\n    return;\n  }\n\n  const allTransactions = parseTransactions(\n    block.transactions as ViemTransaction[]\n  );\n\n  // If any pending transactions were present in the block, log a warning.\n  if (allTransactions.length !== block.transactions.length) {\n    frontfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending transactions in block (number: ${blockNumber}, count: ${\n        block.transactions.length - allTransactions.length\n      })`\n    );\n    return;\n  }\n\n  // Filter down to only required transactions (transactions that emitted events we care about).\n  const transactions = allTransactions.filter((tx) =>\n    requiredTxHashes.has(tx.hash)\n  );\n\n  await Promise.all([\n    frontfillService.resources.cacheStore.insertBlock(block),\n    frontfillService.resources.cacheStore.insertTransactions(transactions),\n    ...group.filterKeys.map((filterKey) =>\n      frontfillService.resources.cacheStore.insertLogFilterCachedRange({\n        range: {\n          filterKey,\n          startBlock: blockNumberToCacheFrom,\n          endBlock: blockNumber,\n          endBlockTimestamp: Number(block.timestamp),\n        },\n      })\n    ),\n  ]);\n\n  context.frontfillService.emit(\"eventsAdded\");\n};\n","import { Hash, Log as ViemLog } from \"viem\";\n\nimport { createQueue, Queue, Worker } from \"@/common/createQueue\";\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { parseLogs } from \"@/common/types\";\n\nimport { BlockFrontfillQueue, BlockFrontfillTask } from \"./blockFrontfillQueue\";\nimport { FrontfillService, LogFilterGroup } from \"./FrontfillService\";\n\nexport type LogFrontfillTask = {\n  logs: ViemLog[];\n};\n\ntype LogFrontfillTaskResult = Record<number, Record<string, number>>;\n\nexport type LogFrontfillWorkerContext = {\n  frontfillService: FrontfillService;\n  group: LogFilterGroup;\n  blockFrontfillQueue: BlockFrontfillQueue;\n};\n\nexport type LogFrontfillQueue = Queue<LogFrontfillTask, LogFrontfillTaskResult>;\n\nexport const createLogFrontfillQueue = (context: LogFrontfillWorkerContext) => {\n  const queue = createQueue({\n    worker: logFrontfillWorker,\n    context,\n    options: {\n      concurrency: 1,\n    },\n  });\n\n  // Pass queue events on to service layer.\n  queue.on(\"add\", () => {\n    context.frontfillService.emit(\"logTasksAdded\", {\n      network: context.group.network.name,\n      count: 1,\n    });\n  });\n\n  queue.on(\"error\", ({ error }) => {\n    context.frontfillService.emit(\"logTaskFailed\", {\n      network: context.group.network.name,\n      error,\n    });\n  });\n\n  queue.on(\"completed\", ({ result }) => {\n    context.frontfillService.emit(\"logTaskCompleted\", {\n      network: context.group.network.name,\n      logData: result,\n    });\n  });\n\n  // Default to a simple retry.\n  queue.on(\"error\", ({ task }) => {\n    queue.addTask(task);\n  });\n\n  return queue;\n};\n\n// This worker stores the new logs recieved from `eth_getFilterChanges`,\n// then enqueues tasks to fetch the block (and transaction) for each log.\nconst logFrontfillWorker: Worker<\n  LogFrontfillTask,\n  LogFrontfillWorkerContext,\n  LogFrontfillTaskResult\n> = async ({ task, context }) => {\n  const { logs: rawLogs } = task;\n  const { frontfillService, group, blockFrontfillQueue } = context;\n\n  const logs = parseLogs(rawLogs, { chainId: group.network.chainId });\n\n  // If any pending logs were present in the response, log a warning.\n  if (logs.length !== rawLogs.length) {\n    frontfillService.resources.logger.logMessage(\n      MessageKind.WARNING,\n      `Received unexpected pending logs (count: ${\n        logs.length - rawLogs.length\n      })`\n    );\n  }\n\n  // If there are no new logs, return early.\n  if (logs.length === 0) return {};\n\n  await frontfillService.resources.cacheStore.insertLogs(logs);\n\n  const txHashesByBlockNumber = logs.reduce<Record<number, Set<Hash>>>(\n    (acc, log) => {\n      const blockNumber = Number(log.blockNumber);\n      acc[blockNumber] ||= new Set<Hash>();\n      acc[blockNumber].add(log.transactionHash);\n      return acc;\n    },\n    {}\n  );\n  const requiredBlockNumbers = Object.keys(txHashesByBlockNumber)\n    .map(Number)\n    .sort((a, b) => a - b);\n\n  // Get the previous current block number for this log group.\n  const fromBlock = frontfillService.currentBlockNumbers[group.id];\n  // Calculate the new current block number from the received logs.\n  const toBlock = Math.max(...requiredBlockNumbers);\n\n  let blockNumberToCacheFrom = fromBlock;\n  const blockFrontfillTasks: BlockFrontfillTask[] = [];\n\n  for (const blockNumber of requiredBlockNumbers) {\n    blockFrontfillTasks.push({\n      blockNumberToCacheFrom,\n      blockNumber,\n      requiredTxHashes: txHashesByBlockNumber[blockNumber],\n    });\n    blockNumberToCacheFrom = blockNumber + 1;\n  }\n\n  // Wait for child tasks to be done.\n  await blockFrontfillQueue.addTasks(blockFrontfillTasks);\n\n  // Store the new current block number for this log group.\n  frontfillService.currentBlockNumbers[group.id] = toBlock;\n\n  await blockFrontfillQueue.onIdle();\n\n  // This is a mapping of block number -> contract address -> log count\n  // that is used for logging the number of events in this batch.\n  return logs.reduce<Record<number, Record<string, number>>>((acc, log) => {\n    acc[Number(log.blockNumber)] ||= {};\n    acc[Number(log.blockNumber)][log.address] ||= 0;\n    acc[Number(log.blockNumber)][log.address] += 1;\n    return acc;\n  }, {});\n};\n","import { E_CANCELED, Mutex } from \"async-mutex\";\nimport Emittery from \"emittery\";\nimport { decodeEventLog, encodeEventTopics, Hex } from \"viem\";\n\nimport { createQueue, Queue, Worker } from \"@/common/createQueue\";\nimport type { Log, Model } from \"@/common/types\";\nimport { EntityInstance } from \"@/database/entity/entityStore\";\nimport { EventHandlerError } from \"@/errors/eventHandler\";\nimport { Resources } from \"@/Ponder\";\nimport { Handlers } from \"@/reload/readHandlers\";\nimport { Schema } from \"@/schema/types\";\n\nimport {\n  buildInjectedContract,\n  ReadOnlyContract,\n} from \"./buildInjectedContract\";\nimport { getStackTraceAndCodeFrame } from \"./getStackTrace\";\n\ntype EventHandlerServiceEvents = {\n  taskStarted: undefined;\n  taskCompleted: { timestamp?: number };\n\n  eventsAdded: {\n    handledCount: number;\n    totalCount: number;\n    fromTimestamp: number;\n    toTimestamp: number;\n  };\n  eventsProcessed: { count: number; toTimestamp: number };\n  eventQueueReset: undefined;\n};\n\ntype SetupTask = { kind: \"SETUP\" };\ntype LogTask = { kind: \"LOG\"; logFilterName: string; log: Log };\ntype EventHandlerTask = SetupTask | LogTask;\ntype EventHandlerQueue = Queue<EventHandlerTask>;\n\nexport class EventHandlerService extends Emittery<EventHandlerServiceEvents> {\n  resources: Resources;\n\n  private handlers?: Handlers;\n  private schema?: Schema;\n  private queue?: EventHandlerQueue;\n\n  private injectedContracts: Record<string, ReadOnlyContract | undefined> = {};\n\n  isBackfillStarted = false;\n\n  private eventProcessingMutex: Mutex;\n  private eventsHandledToTimestamp = 0;\n\n  currentLogEventBlockNumber = 0n;\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n\n    // Build the injected contract objects. They depend only on contract config,\n    // so they can't be hot reloaded.\n    this.resources.contracts.forEach((contract) => {\n      this.injectedContracts[contract.name] = buildInjectedContract({\n        contract,\n        eventHandlerService: this,\n      });\n    });\n\n    // Setup the event processing mutex.\n    this.eventProcessingMutex = new Mutex();\n  }\n\n  killQueue() {\n    this.queue?.clear();\n  }\n\n  resetEventQueue({\n    handlers: newHandlers,\n    schema: newSchema,\n  }: {\n    handlers?: Handlers;\n    schema?: Schema;\n  } = {}) {\n    if (newHandlers) this.handlers = newHandlers;\n    if (newSchema) this.schema = newSchema;\n\n    if (!this.handlers || !this.schema) return;\n\n    this.eventProcessingMutex.cancel();\n    this.eventProcessingMutex = new Mutex();\n    this.eventsHandledToTimestamp = 0;\n\n    this.queue = this.createEventQueue({\n      handlers: this.handlers,\n      schema: this.schema,\n    });\n\n    this.emit(\"eventQueueReset\");\n\n    // If the setup handler is present, add the setup event.\n    if (this.handlers.setup) {\n      this.queue.addTask({ kind: \"SETUP\" });\n      this.emit(\"eventsAdded\", {\n        handledCount: 1,\n        totalCount: 1,\n        fromTimestamp: this.eventsHandledToTimestamp,\n        toTimestamp: this.eventsHandledToTimestamp,\n      });\n    }\n  }\n\n  async processEvents() {\n    if (!this.isBackfillStarted) return;\n    if (this.resources.errors.isHandlerError) return;\n\n    try {\n      await this.eventProcessingMutex.runExclusive(async () => {\n        if (!this.queue) return;\n\n        const { hasNewLogs, toTimestamp, events, totalLogCount } =\n          await this.getNewEvents({\n            fromTimestamp: this.eventsHandledToTimestamp,\n          });\n\n        if (!hasNewLogs) return;\n\n        // Add new events to the queue.\n        for (const event of events) {\n          this.queue.addTask({\n            kind: \"LOG\",\n            logFilterName: event.logFilterName,\n            log: event.log,\n          });\n        }\n\n        this.emit(\"eventsAdded\", {\n          handledCount: events.length,\n          totalCount: totalLogCount ?? events.length,\n          fromTimestamp: this.eventsHandledToTimestamp,\n          toTimestamp: toTimestamp,\n        });\n\n        // Process new events that were added to the queue.\n        this.queue.start();\n        await this.queue.onEmpty();\n        this.queue.pause();\n\n        this.eventsHandledToTimestamp = toTimestamp;\n\n        this.emit(\"eventsProcessed\", {\n          count: events.length,\n          toTimestamp: toTimestamp,\n        });\n      });\n    } catch (error) {\n      // Pending locks get cancelled in resetEventQueue. This is expected, so it's safe to\n      // ignore the error that is thrown when a pending lock is cancelled.\n      if (error !== E_CANCELED) throw error;\n    }\n  }\n\n  private createEventQueue({\n    handlers,\n    schema,\n  }: {\n    handlers: Handlers;\n    schema: Schema;\n  }) {\n    const context = this.buildContext({ schema });\n\n    const eventHandlerWorker: Worker<EventHandlerTask> = async ({\n      task,\n      queue,\n    }) => {\n      this.emit(\"taskStarted\");\n\n      switch (task.kind) {\n        case \"SETUP\": {\n          const setupHandler = handlers[\"setup\"];\n          if (!setupHandler) {\n            this.resources.logger.warn(`Handler not found for event: setup`);\n            return;\n          }\n\n          try {\n            // Running user code here!\n            await setupHandler({ context });\n          } catch (error_) {\n            // Remove all remaining tasks from the queue.\n            queue.clear();\n\n            const error = error_ as Error;\n            const { stackTrace, codeFrame } = getStackTraceAndCodeFrame(\n              error,\n              this.resources.options\n            );\n            this.resources.errors.submitHandlerError({\n              error: new EventHandlerError({\n                eventName: \"setup\",\n                stackTrace: stackTrace,\n                codeFrame: codeFrame,\n                cause: error,\n              }),\n            });\n          }\n\n          this.emit(\"taskCompleted\", {});\n\n          break;\n        }\n        case \"LOG\": {\n          const { logFilterName, log } = task;\n\n          const logFilter = this.resources.logFilters.find(\n            (f) => f.name === logFilterName\n          );\n          if (!logFilter) {\n            this.resources.logger.warn(\n              `Filter not found for log with address: ${log.address}`\n            );\n            return;\n          }\n\n          const decodedLog = decodeEventLog({\n            // TODO: Remove this filter once viem is fixed.\n            abi: logFilter.abi.filter((item) => item.type !== \"constructor\"),\n            data: log.data,\n            topics: [log.topic0, log.topic1, log.topic2, log.topic3].filter(\n              (t) => !!t\n            ) as [signature: Hex, ...args: Hex[]] | [],\n          });\n\n          if (!decodedLog) {\n            this.resources.logger.warn(\n              `Event log not found in ABI, data: ${log.data} topics: ${[\n                log.topic0,\n                log.topic1,\n                log.topic2,\n                log.topic3,\n              ]}`\n            );\n            return;\n          }\n          const { eventName, args } = decodedLog;\n          const params = args as any;\n\n          const handler = handlers[logFilterName]?.[eventName];\n          if (!handler) {\n            this.resources.logger.warn(\n              `Handler not found for log event: ${logFilterName}:${eventName}`\n            );\n            return;\n          }\n\n          this.resources.logger.trace(\n            `Handling event: ${logFilterName}:${eventName}`\n          );\n\n          // Get block & transaction from the cache store and attach to the event.\n          const block = await this.resources.cacheStore.getBlock(log.blockHash);\n          if (!block) {\n            throw new Error(`Block with hash not found: ${log.blockHash}`);\n          }\n\n          const transaction = await this.resources.cacheStore.getTransaction(\n            log.transactionHash\n          );\n          if (!transaction) {\n            throw new Error(\n              `Transaction with hash not found: ${log.transactionHash}`\n            );\n          }\n\n          const event = { name: eventName, params, log, block, transaction };\n\n          // This enables contract calls occurring within the\n          // handler code to use the event block number by default.\n          this.currentLogEventBlockNumber = event.block.number;\n\n          try {\n            // Running user code here!\n            await handler({ event, context });\n          } catch (error_) {\n            // Remove all remaining tasks from the queue.\n            queue.clear();\n\n            const error = error_ as Error;\n            const { stackTrace, codeFrame } = getStackTraceAndCodeFrame(\n              error,\n              this.resources.options\n            );\n            this.resources.errors.submitHandlerError({\n              error: new EventHandlerError({\n                stackTrace: stackTrace,\n                codeFrame: codeFrame,\n                cause: error,\n                eventName: event.name,\n                blockNumber: event.block.number,\n                params: event.params,\n              }),\n            });\n          }\n\n          this.emit(\"taskCompleted\", {\n            timestamp: Number(event.block.timestamp),\n          });\n\n          break;\n        }\n      }\n    };\n\n    const queue = createQueue({\n      worker: eventHandlerWorker,\n      context: undefined,\n      options: {\n        concurrency: 1,\n        autoStart: false,\n      },\n    });\n\n    return queue;\n  }\n\n  private async getNewEvents({ fromTimestamp }: { fromTimestamp: number }) {\n    // Check the cached metadata for all filters. If the minimum cached block across\n    // all filters is greater than the lastHandledLogTimestamp, fetch the newly available\n    // logs and add them to the queue.\n    const cachedToTimestamps = await Promise.all(\n      this.resources.logFilters.map(async (logFilter) => {\n        const cachedRanges =\n          await this.resources.cacheStore.getLogFilterCachedRanges({\n            filterKey: logFilter.filter.key,\n          });\n\n        // Find the cached interval that includes the filter's startBlock.\n        const startingCachedRange = cachedRanges.find(\n          (range) =>\n            range.startBlock <= logFilter.startBlock &&\n            range.endBlock >= logFilter.startBlock\n        );\n\n        // If there is no cached data that includes the start block, return -1.\n        if (!startingCachedRange) return -1;\n\n        return startingCachedRange.endBlockTimestamp;\n      })\n    );\n\n    // If any of the filters have no cached data yet, return early\n    if (cachedToTimestamps.includes(-1)) {\n      return { hasNewLogs: false, events: [], toTimestamp: fromTimestamp };\n    }\n\n    // If the minimum cached timestamp across all filters is less than the\n    // latest processed timestamp, we can't process any new logs.\n    const toTimestamp = Math.min(...cachedToTimestamps);\n    if (toTimestamp <= fromTimestamp) {\n      return { hasNewLogs: false, events: [], toTimestamp: fromTimestamp };\n    }\n\n    // For UI/reporting purposes, also keep track of the total number of logs\n    // found (not just those being handled)\n    let totalLogCount = 0;\n\n    // NOTE: cacheStore.getLogs is exclusive to the left and inclusive to the right.\n    // This is fine because this.latestProcessedTimestamp starts at zero.\n    const events = await Promise.all(\n      this.resources.logFilters.map(async (logFilter) => {\n        const handledEventNames = Object.keys(\n          (this.handlers ?? {})[logFilter.name] ?? {}\n        );\n        const handledTopics = handledEventNames.map((eventName) => {\n          // TODO: Disambiguate overloaded ABI event signatures BEFORE getting here.\n          const topics = encodeEventTopics({\n            abi: logFilter.abi,\n            eventName,\n          });\n          return topics[0];\n        });\n\n        const [handledLogs, totalLogs] = await Promise.all([\n          this.resources.cacheStore.getLogs({\n            fromBlockTimestamp: fromTimestamp,\n            toBlockTimestamp: toTimestamp,\n            chainId: logFilter.network.chainId,\n            address: logFilter.filter.address,\n            topics: [handledTopics],\n          }),\n          this.resources.cacheStore.getLogs({\n            fromBlockTimestamp: fromTimestamp,\n            toBlockTimestamp: toTimestamp,\n            chainId: logFilter.network.chainId,\n            address: logFilter.filter.address,\n            topics: logFilter.filter.topics,\n          }),\n        ]);\n\n        totalLogCount += totalLogs.length;\n\n        return handledLogs.map((log) => ({\n          logFilterName: logFilter.name,\n          log,\n        }));\n      })\n    );\n\n    const sortedEvents = events\n      .flat()\n      .sort((a, b) =>\n        a.log.logSortKey < b.log.logSortKey\n          ? -1\n          : a.log.logSortKey > b.log.logSortKey\n          ? 1\n          : 0\n      );\n\n    return {\n      hasNewLogs: true,\n      toTimestamp,\n      events: sortedEvents,\n      totalLogCount,\n    };\n  }\n\n  private buildContext({ schema }: { schema: Schema }) {\n    // Build entity models for event handler context.\n    const entityModels: Record<string, Model<EntityInstance>> = {};\n    schema.entities.forEach((entity) => {\n      const entityName = entity.name;\n\n      entityModels[entityName] = {\n        findUnique: ({ id }) =>\n          this.resources.entityStore.findUniqueEntity({ entityName, id }),\n        create: ({ id, data }) =>\n          this.resources.entityStore.createEntity({ entityName, id, data }),\n        update: ({ id, data }) =>\n          this.resources.entityStore.updateEntity({ entityName, id, data }),\n        upsert: ({ id, create, update }) =>\n          this.resources.entityStore.upsertEntity({\n            entityName,\n            id,\n            create,\n            update,\n          }),\n        delete: ({ id }) =>\n          this.resources.entityStore.deleteEntity({ entityName, id }),\n      };\n    });\n\n    return {\n      contracts: this.injectedContracts,\n      entities: entityModels,\n    };\n  }\n}\n","import { BaseError } from \"./base\";\nimport { prettyPrint } from \"./utils\";\n\nexport class EventHandlerError extends BaseError {\n  name = \"EventHandlerError\";\n\n  constructor({\n    eventName,\n    blockNumber,\n    params,\n    stackTrace,\n    codeFrame,\n    cause,\n  }: {\n    eventName: string;\n    blockNumber?: bigint;\n    params?: any;\n    stackTrace?: string;\n    codeFrame?: string;\n    cause?: Error;\n  }) {\n    const shortMessage =\n      `Error while handling \\`${eventName}\\` event` +\n      (blockNumber ? ` at block ${blockNumber}` : \"\");\n\n    const metaMessages = [];\n\n    if (stackTrace) metaMessages.push(`Trace:\\n${stackTrace}`);\n    if (codeFrame) metaMessages.push(codeFrame);\n    if (params) metaMessages.push(`Event params:\\n${prettyPrint(params)}`);\n\n    super(shortMessage, {\n      metaMessages,\n      cause,\n    });\n  }\n}\n","import { AbiParameter } from \"abitype\";\nimport { BlockTag, encodeFunctionData } from \"viem\";\n\nimport { Contract } from \"@/config/contracts\";\n\nimport { EventHandlerService } from \"./EventHandlerService\";\n\nexport type ReadOnlyContract = {\n  [key: string]: (...args: any[]) => Promise<any>;\n};\n\ntype AbiReadFunction = {\n  type: \"function\";\n  stateMutability: \"pure\" | \"view\";\n  inputs: readonly AbiParameter[];\n  name: string;\n  outputs: readonly AbiParameter[];\n};\n\ntype CallOverrides =\n  | {\n      /** The block number at which to execute the contract call. */\n      blockNumber?: bigint;\n      blockTag?: never;\n    }\n  | {\n      blockNumber?: never;\n      /** The block tag at which to execute the contract call. */\n      blockTag?: BlockTag;\n    };\n\nexport function buildInjectedContract({\n  contract,\n  eventHandlerService,\n}: {\n  contract: Contract;\n  eventHandlerService: EventHandlerService;\n}) {\n  const injectedContract: ReadOnlyContract = {};\n\n  const readFunctions = contract.abi.filter(\n    (item): item is AbiReadFunction =>\n      item.type === \"function\" &&\n      (item.stateMutability === \"pure\" || item.stateMutability === \"view\")\n  );\n\n  readFunctions.forEach((readFunction) => {\n    injectedContract[readFunction.name] = async (...args) => {\n      let overrides: CallOverrides;\n\n      // If the length of the args is one greater than the length of the inputs,\n      // an overrides argument was provided.\n      if (args.length === readFunction.inputs.length + 1) {\n        overrides = args.pop();\n      } else {\n        overrides = {\n          blockNumber: eventHandlerService.currentLogEventBlockNumber,\n        };\n      }\n\n      // If `overrides` uses a blockNumber (either provided by the user or using the)\n      // default of currentLogEventBlockNumber, enable caching.\n      const isCachingEnabled = overrides.blockNumber !== undefined;\n\n      let result: any;\n\n      if (!isCachingEnabled) {\n        result = await contract.network.client.readContract({\n          address: contract.address,\n          abi: contract.abi,\n          functionName: readFunction.name as never,\n          args: args,\n          ...overrides,\n        });\n      }\n\n      if (isCachingEnabled) {\n        const calldata = encodeFunctionData({\n          abi: contract.abi,\n          args: args,\n          functionName: readFunction.name as never,\n        });\n\n        const contractCallCacheKey = `${contract.network.chainId}-${overrides.blockNumber}-${contract.address}-${calldata}`;\n\n        const cachedContractCall =\n          await eventHandlerService.resources.cacheStore.getContractCall(\n            contractCallCacheKey\n          );\n\n        if (cachedContractCall) {\n          result = JSON.parse(cachedContractCall.result, reviveJsonBigInt);\n        } else {\n          result = await contract.network.client.readContract({\n            address: contract.address,\n            abi: contract.abi,\n            functionName: readFunction.name as never,\n            args: args,\n          });\n\n          await eventHandlerService.resources.cacheStore.upsertContractCall({\n            key: contractCallCacheKey,\n            result: JSON.stringify(result, serializeJsonBigInt),\n          });\n        }\n      }\n\n      let resultObject: any;\n      if (readFunction.outputs.length > 1) {\n        resultObject = {} as Record<string, any>;\n        readFunction.outputs.forEach((output, index) => {\n          const propertyName = output.name ? output.name : `arg_${index}`;\n          resultObject[propertyName] = (result as any[])[index];\n        });\n      } else {\n        resultObject = result;\n      }\n\n      return resultObject;\n    };\n  });\n\n  return injectedContract;\n}\n\nfunction reviveJsonBigInt(_: string, value: any) {\n  if (typeof value?.__bigint__ === \"string\") {\n    return BigInt(value.__bigint__);\n  }\n  return value;\n}\n\nfunction serializeJsonBigInt(_: string, value: any) {\n  if (typeof value === \"bigint\") {\n    return { __bigint__: value.toString() };\n  }\n  return value;\n}\n","import { codeFrameColumns } from \"@babel/code-frame\";\nimport {\n  DecodedSourceMap,\n  originalPositionFor,\n  sourceContentFor,\n  TraceMap,\n} from \"@jridgewell/trace-mapping\";\nimport type { MimeBuffer } from \"data-uri-to-buffer\";\nimport dataUriToBuffer from \"data-uri-to-buffer\";\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { parse as parseStackTrace, StackFrame } from \"stacktrace-parser\";\n\nimport { PonderOptions } from \"@/config/options\";\n\nexport const getStackTraceAndCodeFrame = (\n  error: Error,\n  options: PonderOptions\n) => {\n  if (!error.stack) return { stackTrace: undefined, codeFrame: undefined };\n\n  const buildDir = path.join(options.ponderDir, \"out\");\n\n  const stackTrace = parseStackTrace(error.stack);\n\n  let codeFrame: string | undefined;\n\n  const sourceMappedStackTrace = stackTrace\n    .map((frame) => {\n      if (!frame.file || !frame.lineNumber) return;\n\n      const sourceMappedStackFrame = getSourceMappedStackFrame(\n        frame.file,\n        frame.lineNumber,\n        frame.column\n      );\n\n      // If this frame cannot be mapped to the user code build directory, skip it.\n      if (!sourceMappedStackFrame) return;\n\n      const {\n        sourceFile,\n        sourceLineNumber,\n        sourceColumnNumber,\n        sourceContent,\n      } = sourceMappedStackFrame;\n\n      // If this is the first frame within the build directory, generate the code frame.\n      if (\n        frame.file.includes(buildDir) &&\n        codeFrame == null &&\n        sourceContent !== null\n      ) {\n        codeFrame = codeFrameColumns(\n          sourceContent,\n          {\n            start: {\n              line: sourceLineNumber,\n              column: sourceColumnNumber ?? undefined,\n            },\n          },\n          {\n            highlightCode: true,\n          }\n        );\n      }\n\n      return {\n        ...frame,\n        file: sourceFile,\n        lineNumber: sourceLineNumber,\n        column: sourceColumnNumber,\n      } as StackFrame;\n    })\n    .filter((f): f is StackFrame => !!f);\n\n  if (sourceMappedStackTrace.length === 0 || !codeFrame) {\n    return { stackTrace: undefined, codeFrame: undefined };\n  }\n\n  const formattedStackTrace = sourceMappedStackTrace\n    .map(\n      (frame) =>\n        `    at ${frame.methodName} (${frame.file}:${frame.lineNumber}${\n          frame.column !== null ? `:${frame.column}` : \"\"\n        })`\n    )\n    .join(\"\\n\");\n\n  return { stackTrace: formattedStackTrace, codeFrame };\n};\n\nfunction getSourceMappedStackFrame(\n  file: string,\n  lineNumber: number,\n  columnNumber: number | null\n) {\n  let fileContents: string;\n  try {\n    fileContents = readFileSync(file, { encoding: \"utf-8\" });\n  } catch (_) {\n    return null;\n  }\n\n  const sourceMap = getRawSourceMap(fileContents);\n  if (!sourceMap) return null;\n\n  const result = getSourcePositionAndContent(\n    sourceMap,\n    lineNumber,\n    columnNumber\n  );\n\n  const sourceFileRelative = result?.sourcePosition?.source;\n\n  const sourceLineNumber = result?.sourcePosition?.line;\n  const sourceColumnNumber = result?.sourcePosition?.column ?? null;\n  const sourceContent = result?.sourceContent ?? null;\n\n  if (!sourceFileRelative || !sourceLineNumber) return null;\n\n  const sourceFile = path.resolve(path.dirname(file), sourceFileRelative);\n\n  return {\n    sourceFile,\n    sourceLineNumber,\n    sourceColumnNumber,\n    sourceContent,\n  };\n}\n\nfunction getSourceMapUrl(fileContents: string): string | null {\n  const regex = /\\/\\/[#@] ?sourceMappingURL=([^\\s'\"]+)\\s*$/gm;\n  let match = null;\n  for (;;) {\n    const next = regex.exec(fileContents);\n    if (next == null) {\n      break;\n    }\n    match = next;\n  }\n  if (!(match && match[1])) {\n    return null;\n  }\n  return match[1].toString();\n}\n\nfunction getRawSourceMap(fileContents: string): DecodedSourceMap | null {\n  const sourceUrl = getSourceMapUrl(fileContents);\n  if (!sourceUrl?.startsWith(\"data:\")) {\n    return null;\n  }\n\n  let buffer: MimeBuffer;\n  try {\n    buffer = dataUriToBuffer(sourceUrl);\n  } catch (err) {\n    console.error(\"Failed to parse source map URL:\", err);\n    return null;\n  }\n\n  if (buffer.type !== \"application/json\") {\n    console.error(`Unknown source map type: ${buffer.typeFull}.`);\n    return null;\n  }\n\n  try {\n    return JSON.parse(buffer.toString());\n  } catch {\n    console.error(\"Failed to parse source map.\");\n    return null;\n  }\n}\n\nfunction getSourcePositionAndContent(\n  rawSourceMap: DecodedSourceMap,\n  lineNumber: number,\n  columnNumber: number | null\n) {\n  const tracer = new TraceMap(rawSourceMap);\n\n  const sourcePosition = originalPositionFor(tracer, {\n    line: lineNumber,\n    column: columnNumber ?? 0,\n  });\n\n  if (!sourcePosition.source) {\n    return null;\n  }\n\n  const sourceContent = sourceContentFor(tracer, sourcePosition.source) ?? null;\n\n  return {\n    sourcePosition,\n    sourceContent,\n  };\n}\n","import chokidar from \"chokidar\";\nimport Emittery from \"emittery\";\nimport { GraphQLSchema } from \"graphql\";\nimport { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport pico from \"picocolors\";\n\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { Resources } from \"@/Ponder\";\nimport { buildSchema } from \"@/schema/buildSchema\";\nimport { Schema } from \"@/schema/types\";\nimport { buildGqlSchema } from \"@/server/graphql/buildGqlSchema\";\n\nimport { readGraphqlSchema } from \"./readGraphqlSchema\";\nimport { Handlers, readHandlers } from \"./readHandlers\";\n\ntype ReloadServiceEvents = {\n  ponderConfigChanged: undefined;\n  projectFileChanged: undefined;\n  newHandlers: { handlers: Handlers };\n  newSchema: { schema: Schema; graphqlSchema: GraphQLSchema };\n};\n\nexport class ReloadService extends Emittery<ReloadServiceEvents> {\n  resources: Resources;\n\n  latestFileHashes: Record<string, string | undefined> = {};\n  kill?: () => Promise<void>;\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n  }\n\n  watch() {\n    const watchFiles = [\n      this.resources.options.configFile,\n      this.resources.options.schemaFile,\n      this.resources.options.srcDir,\n    ];\n\n    const watcher = chokidar.watch(watchFiles);\n    this.kill = async () => {\n      await watcher.close();\n    };\n\n    watcher.on(\"change\", async (filePath) => {\n      if (filePath === this.resources.options.configFile) {\n        this.resources.logger.logMessage(\n          MessageKind.ERROR,\n          \"detected change in ponder.config.ts. \" +\n            pico.bold(\"Restart the server.\")\n        );\n        this.emit(\"ponderConfigChanged\");\n        return;\n      }\n\n      if (this.isFileChanged(filePath)) {\n        const fileName = path.basename(filePath);\n\n        this.resources.logger.logMessage(\n          MessageKind.EVENT,\n          \"detected change in \" + pico.bold(fileName)\n        );\n\n        this.resources.errors.clearHandlerError();\n\n        if (filePath === this.resources.options.schemaFile) {\n          this.loadSchema();\n        } else {\n          await this.loadHandlers();\n        }\n      }\n    });\n  }\n\n  async loadHandlers() {\n    try {\n      const handlers = await readHandlers({\n        options: this.resources.options,\n        logger: this.resources.logger,\n      });\n      this.emit(\"newHandlers\", { handlers });\n    } catch (error_) {\n      const error = error_ as Error;\n      error.message = \"Building event handlers: \" + error.message;\n      this.resources.errors.submitHandlerError({ error });\n    }\n  }\n\n  loadSchema() {\n    try {\n      const userGraphqlSchema = readGraphqlSchema({\n        options: this.resources.options,\n      });\n      const schema = buildSchema(userGraphqlSchema);\n      const graphqlSchema = buildGqlSchema(schema);\n      this.emit(\"newSchema\", { schema, graphqlSchema });\n      return { schema, graphqlSchema };\n    } catch (error_) {\n      const error = error_ as Error;\n      error.message = \"Building schema: \" + error.message;\n      error.stack = \"\";\n      this.resources.errors.submitHandlerError({ error });\n    }\n  }\n\n  private isFileChanged(filePath: string) {\n    // TODO: I think this throws if the file being watched gets deleted while\n    // the development server is running. Should handle this case gracefully.\n    try {\n      const content = readFileSync(filePath, \"utf-8\");\n      const hash = createHash(\"md5\").update(content).digest(\"hex\");\n\n      const prevHash = this.latestFileHashes[filePath];\n      this.latestFileHashes[filePath] = hash;\n      if (!prevHash) {\n        // If there is no previous hash, this file is being changed for the first time.\n        return true;\n      } else {\n        // If there is a previous hash, check if the content hash has changed.\n        return prevHash !== hash;\n      }\n    } catch (e) {\n      return true;\n    }\n  }\n}\n","import {\n  FieldDefinitionNode,\n  GraphQLBoolean,\n  GraphQLEnumType,\n  GraphQLFloat,\n  GraphQLID,\n  GraphQLInputObjectType,\n  GraphQLInt,\n  GraphQLObjectType,\n  GraphQLScalarType,\n  GraphQLSchema,\n  GraphQLString,\n  Kind,\n  StringValueNode,\n} from \"graphql\";\n\nimport {\n  DerivedField,\n  Entity,\n  EnumField,\n  Field,\n  FieldKind,\n  ListField,\n  RelationshipField,\n  ScalarField,\n  Schema,\n} from \"./types\";\n\nconst gqlScalarTypeByName: Record<string, GraphQLScalarType | undefined> = {\n  ID: GraphQLID,\n  Int: GraphQLInt,\n  Float: GraphQLFloat,\n  String: GraphQLString,\n  Boolean: GraphQLBoolean,\n  BigInt: GraphQLString,\n  Bytes: GraphQLString,\n};\n\nexport const buildSchema = (graphqlSchema: GraphQLSchema): Schema => {\n  const gqlEntityTypes = getEntityTypes(graphqlSchema);\n  const gqlEnumTypes = getEnumTypes(graphqlSchema);\n\n  const userDefinedScalars = getUserDefinedScalarTypes(graphqlSchema);\n  if (userDefinedScalars.length > 0) {\n    throw new Error(\n      `Custom scalars are not supported: ${userDefinedScalars[0]}`\n    );\n  }\n\n  const entities = gqlEntityTypes.map((entity) => {\n    const entityName = entity.name;\n    const entityIsImmutable = !!entity.astNode?.directives\n      ?.find((directive) => directive.name.value === \"entity\")\n      ?.arguments?.find(\n        (arg) =>\n          arg.name.value === \"immutable\" &&\n          arg.value.kind === \"BooleanValue\" &&\n          arg.value.value\n      );\n\n    const gqlFields = entity.astNode?.fields || [];\n\n    const fields = gqlFields.map((field) => {\n      const originalFieldType = field.type;\n\n      const {\n        fieldName,\n        fieldTypeName,\n        isNotNull,\n        isList,\n        isListElementNotNull,\n      } = unwrapFieldDefinition(field);\n\n      // Try to find a type that matches the base type of this field.\n      const scalarBaseType = gqlScalarTypeByName[fieldTypeName];\n      const enumBaseType = gqlEnumTypes.find((t) => t.name === fieldTypeName);\n      const entityBaseType = gqlEntityTypes.find(\n        (t) => t.name === fieldTypeName\n      );\n\n      const derivedFromDirective = field.directives?.find(\n        (directive) => directive.name.value === \"derivedFrom\"\n      );\n\n      // Handle derived fields.\n      if (derivedFromDirective) {\n        if (!entityBaseType || !isList) {\n          throw new Error(\n            `Resolved type of a @derivedFrom field must be a list of entities`\n          );\n        }\n\n        const derivedFromFieldArgument = derivedFromDirective.arguments?.find(\n          (arg) =>\n            arg.name.value === \"field\" && arg.value.kind === \"StringValue\"\n        );\n        if (!derivedFromFieldArgument) {\n          throw new Error(\n            `The @derivedFrom directive requires an argument: field`\n          );\n        }\n\n        const derivedFromFieldName = (\n          derivedFromFieldArgument.value as StringValueNode\n        ).value;\n\n        const baseTypeAsInputType =\n          entityBaseType as unknown as GraphQLInputObjectType;\n\n        return <DerivedField>{\n          name: fieldName,\n          kind: FieldKind.DERIVED,\n          baseGqlType: baseTypeAsInputType,\n          originalFieldType,\n          notNull: isNotNull,\n          derivedFromEntityName: entityBaseType.name,\n          derivedFromFieldName: derivedFromFieldName,\n        };\n      }\n\n      // Handle relationship types.\n      if (entityBaseType) {\n        if (isList) {\n          throw new Error(\n            `Invalid field: ${entityName}.${fieldName}. Lists of entities must use the @derivedFrom directive.`\n          );\n        }\n\n        const relatedEntityIdField = entityBaseType.astNode?.fields?.find(\n          (f) => f.name.value === \"id\"\n        );\n        if (!relatedEntityIdField) {\n          throw new Error(\n            `Related entity is missing an id field: ${entityBaseType.name}`\n          );\n        }\n\n        const { fieldTypeName } = unwrapFieldDefinition(relatedEntityIdField);\n        const relatedEntityIdType = gqlScalarTypeByName[fieldTypeName];\n        if (!relatedEntityIdType) {\n          throw new Error(\n            `Related entity id field is not a scalar: ${entityBaseType.name}`\n          );\n        }\n\n        // Everything downstream requires the base type as a GraphQLInputObject type, but idk how to safely convert it.\n        // AFAICT, the GraphQLObjectType is a strict superset of GraphQLInputObject, so this should be fine.\n        const entityBaseTypeAsInputType =\n          entityBaseType as unknown as GraphQLInputObjectType;\n\n        return <RelationshipField>{\n          name: fieldName,\n          kind: FieldKind.RELATIONSHIP,\n          baseGqlType: entityBaseTypeAsInputType,\n          originalFieldType,\n          notNull: isNotNull,\n          relatedEntityName: entityBaseType.name,\n          relatedEntityIdType: relatedEntityIdType,\n        };\n      }\n\n      // Handle list types.\n      if (isList) {\n        if (scalarBaseType) {\n          return <ListField>{\n            name: fieldName,\n            kind: FieldKind.LIST,\n            baseGqlType: scalarBaseType,\n            originalFieldType,\n            notNull: isNotNull,\n            isListElementNotNull,\n          };\n        }\n\n        if (enumBaseType) {\n          return <ListField>{\n            name: fieldName,\n            kind: FieldKind.LIST,\n            baseGqlType: enumBaseType,\n            originalFieldType,\n            notNull: isNotNull,\n            isListElementNotNull,\n          };\n        }\n      }\n\n      // Handle scalar types.\n      if (scalarBaseType) {\n        const baseType = scalarBaseType;\n\n        // Validate the id field.\n        if (fieldName === \"id\") {\n          if (!isNotNull) {\n            throw new Error(`${entityName}.id field must be non-null`);\n          }\n          if (isList) {\n            throw new Error(`${entityName}.id field must not be a list`);\n          }\n          if (![\"BigInt\", \"String\", \"Int\", \"Bytes\"].includes(baseType.name)) {\n            throw new Error(\n              `${entityName}.id field must be a String, BigInt, Int, or Bytes.`\n            );\n          }\n        }\n\n        return <ScalarField>{\n          name: fieldName,\n          kind: FieldKind.SCALAR,\n          notNull: isNotNull,\n          originalFieldType,\n          scalarTypeName: fieldTypeName,\n          scalarGqlType: baseType,\n        };\n      }\n\n      // Handle enum types.\n      if (enumBaseType) {\n        const enumValues = (enumBaseType.astNode?.values || []).map(\n          (v) => v.name.value\n        );\n        return <EnumField>{\n          name: fieldName,\n          kind: FieldKind.ENUM,\n          enumGqlType: enumBaseType,\n          originalFieldType,\n          notNull: isNotNull,\n          enumValues,\n        };\n      }\n\n      throw new Error(`Unhandled field type: ${fieldTypeName}`);\n    });\n\n    const fieldByName: Record<string, Field> = {};\n    fields.forEach((field) => {\n      fieldByName[field.name] = field;\n    });\n\n    return <Entity>{\n      name: entityName,\n      gqlType: entity,\n      isImmutable: entityIsImmutable,\n      fields,\n      fieldByName,\n    };\n  });\n\n  const schema: Schema = {\n    entities,\n  };\n\n  return schema;\n};\n\n// ------------------------------- UTILITIES -------------------------------- //\n\n// Find the name and base type of a field definition,\n// handling any wrapper types (NON_NULL_TYPE and LIST_TYPE).\nconst unwrapFieldDefinition = (field: FieldDefinitionNode) => {\n  const fieldName = field.name.value;\n  let fieldType = field.type;\n  let isNotNull = false;\n  let isList = false;\n  let isListElementNotNull = false;\n\n  // First check if the field is non-null and unwrap it.\n  if (fieldType.kind === Kind.NON_NULL_TYPE) {\n    isNotNull = true;\n    fieldType = fieldType.type;\n  }\n\n  // Then check if the field is a list and unwrap it.\n  if (fieldType.kind === Kind.LIST_TYPE) {\n    isList = true;\n    fieldType = fieldType.type;\n\n    // Now check if the list element type is non-null\n    if (fieldType.kind === Kind.NON_NULL_TYPE) {\n      isListElementNotNull = true;\n      fieldType = fieldType.type;\n    }\n  }\n\n  if (fieldType.kind === Kind.LIST_TYPE) {\n    throw new Error(\n      `Invalid field \"${fieldName}\": nested lists are not supported`\n    );\n  }\n\n  return {\n    fieldName,\n    fieldTypeName: fieldType.name.value,\n    isNotNull,\n    isList,\n    isListElementNotNull,\n  };\n};\n\n// Find all types in the schema that are marked with the @entity directive.\nconst getEntityTypes = (schema: GraphQLSchema) => {\n  const entities = Object.values(schema.getTypeMap())\n    .filter((type): type is GraphQLObjectType => {\n      return type.astNode?.kind === Kind.OBJECT_TYPE_DEFINITION;\n    })\n    .filter((type) => {\n      return !!type.astNode?.directives?.find(\n        (directive) => directive.name.value === \"entity\"\n      );\n    });\n\n  return entities;\n};\n\n// Find all scalar types in the schema that were created by the user.\nconst getUserDefinedScalarTypes = (schema: GraphQLSchema) => {\n  return Object.values(schema.getTypeMap()).filter(\n    (type) =>\n      !!type.astNode &&\n      type.astNode.kind === Kind.SCALAR_TYPE_DEFINITION &&\n      ![\"BigInt\", \"Bytes\"].includes(type.name)\n  ) as GraphQLScalarType[];\n};\n\n// Find all types in the schema that were created by the user.\nconst getEnumTypes = (schema: GraphQLSchema) => {\n  return Object.values(schema.getTypeMap()).filter(\n    (type) => !!type.astNode && type.astNode.kind === Kind.ENUM_TYPE_DEFINITION\n  ) as GraphQLEnumType[];\n};\n","import { GraphQLFieldConfig, GraphQLObjectType, GraphQLSchema } from \"graphql\";\n\nimport { EntityStore } from \"@/database/entity/entityStore\";\nimport { Schema } from \"@/schema/types\";\n\nimport { buildEntityType } from \"./buildEntityType\";\nimport { buildPluralField } from \"./buildPluralField\";\nimport { buildSingularField } from \"./buildSingularField\";\n\nexport type Source = { request: unknown };\nexport type Context = { store: EntityStore };\n\nconst buildGqlSchema = (schema: Schema): GraphQLSchema => {\n  const queryFields: Record<string, GraphQLFieldConfig<Source, Context>> = {};\n\n  const entityTypes: Record<string, GraphQLObjectType<Source, Context>> = {};\n\n  // First build the entity types. These have resolvers defined for any\n  // relationship or derived fields. This is also important for the thunk nonsense.\n  for (const entity of schema.entities) {\n    entityTypes[entity.name] = buildEntityType(entity, entityTypes);\n  }\n\n  for (const entity of schema.entities) {\n    const entityGqlType = entityTypes[entity.name];\n\n    const singularFieldName =\n      entity.name.charAt(0).toLowerCase() + entity.name.slice(1);\n    queryFields[singularFieldName] = buildSingularField(entity, entityGqlType);\n\n    const pluralFieldName = singularFieldName + \"s\";\n    queryFields[pluralFieldName] = buildPluralField(entity, entityGqlType);\n  }\n\n  const queryType = new GraphQLObjectType({\n    name: \"Query\",\n    fields: queryFields,\n  });\n\n  const gqlSchema = new GraphQLSchema({\n    query: queryType,\n  });\n\n  return gqlSchema;\n};\n\nexport { buildGqlSchema };\n","import {\n  GraphQLFieldConfigMap,\n  GraphQLFieldResolver,\n  GraphQLList,\n  GraphQLNonNull,\n  GraphQLObjectType,\n  GraphQLOutputType,\n} from \"graphql\";\n\nimport type { Entity } from \"@/schema/types\";\nimport { FieldKind } from \"@/schema/types\";\n\nimport type { Context, Source } from \"./buildGqlSchema\";\n\nexport const buildEntityType = (\n  entity: Entity,\n  entityTypes: Record<string, GraphQLObjectType<Source, Context>>\n): GraphQLObjectType<Source, Context> => {\n  return new GraphQLObjectType({\n    name: entity.name,\n    fields: () => {\n      const fieldConfigMap: GraphQLFieldConfigMap<Source, Context> = {};\n\n      // Build resolvers for relationship fields on the entity.\n      entity.fields.forEach((field) => {\n        switch (field.kind) {\n          case FieldKind.SCALAR: {\n            fieldConfigMap[field.name] = {\n              type: field.notNull\n                ? new GraphQLNonNull(field.scalarGqlType)\n                : field.scalarGqlType,\n            };\n            break;\n          }\n          case FieldKind.ENUM: {\n            fieldConfigMap[field.name] = {\n              type: field.notNull\n                ? new GraphQLNonNull(field.enumGqlType)\n                : field.enumGqlType,\n            };\n            break;\n          }\n          case FieldKind.RELATIONSHIP: {\n            const resolver: GraphQLFieldResolver<Source, Context> = async (\n              parent,\n              args,\n              context\n            ) => {\n              const { store } = context;\n\n              // The parent object gets passed in here with relationship fields defined as the\n              // string ID of the related entity. Here, we get the ID and query for that entity.\n              // Then, the GraphQL server serves the resolved object here instead of the ID.\n              // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n              // @ts-ignore\n              const relatedInstanceId = parent[field.name];\n\n              return await store.findUniqueEntity({\n                entityName: field.relatedEntityName,\n                id: relatedInstanceId,\n              });\n            };\n\n            fieldConfigMap[field.name] = {\n              type: entityTypes[field.baseGqlType.name],\n              resolve: resolver,\n            };\n\n            break;\n          }\n          case FieldKind.DERIVED: {\n            const resolver: GraphQLFieldResolver<Source, Context> = async (\n              parent,\n              args,\n              context\n            ) => {\n              const { store } = context;\n\n              // The parent object gets passed in here with relationship fields defined as the\n              // string ID of the related entity. Here, we get the ID and query for that entity.\n              // Then, the GraphQL server serves the resolved object here instead of the ID.\n              // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n              // @ts-ignore\n              const entityId = parent.id;\n\n              return await store.getEntities({\n                entityName: field.derivedFromEntityName,\n                filter: {\n                  where: {\n                    [field.derivedFromFieldName]: entityId,\n                  },\n                },\n              });\n            };\n\n            fieldConfigMap[field.name] = {\n              type: new GraphQLNonNull(\n                new GraphQLList(\n                  new GraphQLNonNull(entityTypes[field.baseGqlType.name])\n                )\n              ),\n              resolve: resolver,\n            };\n\n            break;\n          }\n          case FieldKind.LIST: {\n            const listType = new GraphQLList(\n              field.isListElementNotNull\n                ? new GraphQLNonNull(field.baseGqlType as GraphQLOutputType)\n                : field.baseGqlType\n            );\n            fieldConfigMap[field.name] = {\n              type: field.notNull ? new GraphQLNonNull(listType) : listType,\n            };\n            break;\n          }\n        }\n      });\n\n      return fieldConfigMap;\n    },\n  });\n};\n","import {\n  GraphQLFieldConfig,\n  GraphQLFieldResolver,\n  GraphQLID,\n  GraphQLInputObjectType,\n  GraphQLInputType,\n  GraphQLInt,\n  GraphQLList,\n  GraphQLNonNull,\n  GraphQLObjectType,\n  GraphQLString,\n} from \"graphql\";\n\nimport type { Entity } from \"@/schema/types\";\nimport { FieldKind } from \"@/schema/types\";\n\nimport type { Context, Source } from \"./buildGqlSchema\";\n\ntype WhereInputArg = {\n  [key: string]: number | string;\n};\ntype PluralArgs = {\n  where?: WhereInputArg;\n  first?: number;\n  skip?: number;\n  orderBy?: string;\n  orderDirection?: \"asc\" | \"desc\";\n};\ntype PluralResolver = GraphQLFieldResolver<Source, Context, PluralArgs>;\n\nconst operators = {\n  universal: [\"\", \"_not\"],\n  singular: [\"_in\", \"_not_in\"],\n  plural: [\n    \"_contains\",\n    \"_not_contains\",\n    \"_contains_nocase\",\n    \"_not_contains_nocase\",\n  ],\n  numeric: [\"_gt\", \"_lt\", \"_gte\", \"_lte\"],\n  string: [\n    \"_contains\",\n    \"_contains_nocase\",\n    \"_not_contains\",\n    \"_not_contains_nocase\",\n    \"_starts_with\",\n    \"_starts_with_nocase\",\n    \"_ends_with\",\n    \"_ends_with_nocase\",\n    \"_not_starts_with\",\n    \"_not_starts_with_nocase\",\n    \"_not_ends_with\",\n    \"_not_ends_with_nocase\",\n  ],\n};\n\nconst buildPluralField = (\n  entity: Entity,\n  entityType: GraphQLObjectType<Source, Context>\n): GraphQLFieldConfig<Source, Context> => {\n  const filterFields: Record<string, { type: GraphQLInputType }> = {};\n\n  entity.fields.forEach((field) => {\n    switch (field.kind) {\n      case FieldKind.SCALAR: {\n        // Scalar fields => universal, singular, numeric OR string depending on base type\n        // Note: Booleans => universal and singular only.\n        operators.universal.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: field.scalarGqlType,\n          };\n        });\n\n        operators.numeric.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: field.scalarGqlType,\n          };\n        });\n\n        operators.singular.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: new GraphQLList(field.scalarGqlType),\n          };\n        });\n\n        if ([\"String\"].includes(field.scalarGqlType.name)) {\n          operators.string.forEach((suffix) => {\n            filterFields[`${field.name}${suffix}`] = {\n              type: field.scalarGqlType,\n            };\n          });\n        }\n\n        break;\n      }\n      case FieldKind.ENUM: {\n        // Enum fields => universal, singular\n        operators.universal.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = { type: field.enumGqlType };\n        });\n\n        operators.singular.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: new GraphQLList(field.enumGqlType),\n          };\n        });\n        break;\n      }\n      case FieldKind.LIST: {\n        // List fields => universal, plural\n        operators.universal.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = { type: field.baseGqlType };\n        });\n\n        operators.plural.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = { type: field.baseGqlType };\n        });\n        break;\n      }\n      case FieldKind.RELATIONSHIP: {\n        // Relationship fields => universal, numeric, singular, string ALL with ID basetype\n        operators.universal.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = { type: GraphQLID };\n        });\n\n        operators.numeric.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: GraphQLID,\n          };\n        });\n\n        operators.singular.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: new GraphQLList(GraphQLID),\n          };\n        });\n\n        operators.string.forEach((suffix) => {\n          filterFields[`${field.name}${suffix}`] = {\n            type: GraphQLID,\n          };\n        });\n\n        // TODO: Add complex \"{fieldName}_\" filter field.\n        break;\n      }\n      case FieldKind.DERIVED: {\n        // TODO: Add derived filter fields.\n        break;\n      }\n    }\n  });\n\n  const filterType = new GraphQLInputObjectType({\n    name: `${entity.name}Filter`,\n    fields: filterFields,\n  });\n\n  const resolver: PluralResolver = async (_, args, context) => {\n    const { store } = context;\n\n    const filter = args;\n\n    return await store.getEntities({ entityName: entity.name, filter });\n  };\n\n  return {\n    type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(entityType))),\n    args: {\n      where: { type: filterType },\n      first: { type: GraphQLInt },\n      skip: { type: GraphQLInt },\n      orderBy: { type: GraphQLString },\n      orderDirection: { type: GraphQLString },\n    },\n    resolve: resolver,\n  };\n};\n\nexport { buildPluralField };\n","import {\n  GraphQLFieldConfig,\n  GraphQLFieldResolver,\n  GraphQLID,\n  GraphQLNonNull,\n  GraphQLObjectType,\n} from \"graphql\";\n\nimport type { Entity } from \"@/schema/types\";\n\nimport type { Context, Source } from \"./buildGqlSchema\";\n\ntype SingularArgs = {\n  id?: string;\n};\ntype SingularResolver = GraphQLFieldResolver<Source, Context, SingularArgs>;\n\nconst buildSingularField = (\n  entity: Entity,\n  entityType: GraphQLObjectType<Source, Context>\n): GraphQLFieldConfig<Source, Context> => {\n  const resolver: SingularResolver = async (_, args, context) => {\n    const { store } = context;\n    const { id } = args;\n\n    if (!id) return null;\n\n    const entityInstance = await store.findUniqueEntity({\n      entityName: entity.name,\n      id,\n    });\n\n    // // Build resolvers for relationship fields on the entity.\n    // entity.fields\n    //   .filter(\n    //     (field): field is RelationshipField =>\n    //       field.kind === FieldKind.RELATIONSHIP\n    //   )\n    //   .forEach((field) => {\n    //     const relatedEntityId = entityInstance[field.name];\n    //     entityInstance[field.name] = async () => {\n    //       return await store.getEntity(field.baseGqlType.name, relatedEntityId);\n    //     };\n    //   });\n\n    // // Build resolvers for derived fields on the entity.\n    // entity.fields\n    //   .filter(\n    //     (field): field is DerivedField => field.kind === FieldKind.DERIVED\n    //   )\n    //   .forEach((derivedField) => {\n    //     entityInstance[derivedField.name] = async () => {\n    //       return await store.getEntityDerivedField(\n    //         entity.name,\n    //         id,\n    //         derivedField.name\n    //       );\n    //     };\n    //   });\n\n    return entityInstance;\n  };\n\n  return {\n    type: entityType,\n    args: {\n      id: { type: new GraphQLNonNull(GraphQLID) },\n    },\n    resolve: resolver,\n  };\n};\n\nexport { buildSingularField };\n","import { buildSchema } from \"graphql\";\nimport { readFileSync } from \"node:fs\";\n\nimport { PonderOptions } from \"@/config/options\";\n\nexport const schemaHeader = `\n\"Directs the executor to process this type as a Ponder entity.\"\ndirective @entity(immutable: Boolean = false) on OBJECT\n\n\"Creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API.\"\ndirective @derivedFrom(field: String!) on FIELD_DEFINITION\n\nscalar Bytes\nscalar BigInt\n`;\n\nexport const readGraphqlSchema = ({ options }: { options: PonderOptions }) => {\n  const schemaBody = readFileSync(options.schemaFile);\n  const schemaSource = schemaHeader + schemaBody.toString();\n\n  const schema = buildSchema(schemaSource);\n  return schema;\n};\n","import { build, formatMessagesSync, Message } from \"esbuild\";\nimport glob from \"glob\";\nimport { existsSync, rmSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { replaceTscAliasPaths } from \"tsc-alias\";\n\nimport { LoggerService, MessageKind } from \"@/common/LoggerService\";\nimport type { Block, Log, Transaction } from \"@/common/types\";\nimport { PonderOptions } from \"@/config/options\";\n\nexport interface LogEvent {\n  name: string;\n  params: Record<string, any>;\n  log: Log;\n  block: Omit<Block, \"transactions\">;\n  transaction: Transaction;\n}\n\nexport type SetupEventHandler = ({\n  context,\n}: {\n  context: unknown;\n}) => Promise<void> | void;\nexport type LogEventHandler = ({\n  event,\n  context,\n}: {\n  event: LogEvent;\n  context: unknown;\n}) => Promise<void> | void;\nexport type LogEventHandlers = Record<string, LogEventHandler | undefined>;\nexport type Handlers = Record<string, LogEventHandlers | undefined> & {\n  setup?: SetupEventHandler;\n};\n\n// @ponder/core creates an instance of this class called `ponder`\nexport class PonderApp<EventHandlers = Record<string, LogEventHandler>> {\n  private handlers: Handlers = {};\n  private errors: Error[] = [];\n\n  on<EventName extends Extract<keyof EventHandlers, string>>(\n    name: EventName,\n    handler: EventHandlers[EventName]\n  ) {\n    if (name === \"setup\") {\n      this.handlers.setup = handler as SetupEventHandler;\n      return;\n    }\n\n    const [contractName, eventName] = name.split(\":\");\n    if (!contractName || !eventName) {\n      this.errors.push(new Error(`Invalid event name: ${name}`));\n      return;\n    }\n\n    this.handlers[contractName] ||= {};\n    if (this.handlers[contractName]![eventName]) {\n      this.errors.push(\n        new Error(`Cannot add multiple handlers for event: ${name}`)\n      );\n      return;\n    }\n    this.handlers[contractName]![eventName] = handler as LogEventHandler;\n  }\n}\n\nexport const readHandlers = async ({\n  options,\n  logger,\n}: {\n  options: PonderOptions;\n  logger: LoggerService;\n}) => {\n  const entryAppFilename = path.join(options.generatedDir, \"index.ts\");\n  if (!existsSync(entryAppFilename)) {\n    throw new Error(\n      `generated/index.ts file not found, expected: ${entryAppFilename}`\n    );\n  }\n\n  const entryGlob = options.srcDir + \"/**/*.ts\";\n  const entryFilenames = [...glob.sync(entryGlob), entryAppFilename];\n\n  const buildDir = path.join(options.ponderDir, \"out\");\n  rmSync(buildDir, { recursive: true, force: true });\n\n  try {\n    await build({\n      entryPoints: entryFilenames,\n      outdir: buildDir,\n      platform: \"node\",\n      bundle: false,\n      format: \"cjs\",\n      logLevel: \"silent\",\n      sourcemap: \"inline\",\n    });\n  } catch (err) {\n    const error = err as Error & { errors: Message[]; warnings: Message[] };\n    // Hack to use esbuilds very pretty stack traces when rendering errors to the user.\n    const stackTraces = formatMessagesSync(error.errors, {\n      kind: \"error\",\n      color: true,\n    });\n    error.stack = stackTraces.join(\"\\n\");\n\n    throw error;\n  }\n\n  const tsconfigPath = path.join(options.rootDir, \"tsconfig.json\");\n  if (existsSync(tsconfigPath)) {\n    await replaceTscAliasPaths({\n      configFile: tsconfigPath,\n      outDir: buildDir,\n    });\n  } else {\n    logger.logMessage(\n      MessageKind.WARNING,\n      `tsconfig.json not found, unable to resolve \"@/*\" path aliases. Expected at: ${tsconfigPath}`\n    );\n  }\n\n  const outGlob = buildDir + \"/**/*.js\";\n  const outFilenames = glob.sync(outGlob);\n\n  // Remove all out modules from the require cache, because we are loading\n  // them several times in the same process and need the latest version each time.\n  // https://ar.al/2021/02/22/cache-busting-in-node.js-dynamic-esm-imports/\n  outFilenames.forEach((file) => delete require.cache[require.resolve(file)]);\n\n  const outAppFilename = path.join(buildDir, \"generated/index.js\");\n\n  // Require all the user-defined files first.\n  const outUserFilenames = outFilenames.filter(\n    (name) => name !== outAppFilename\n  );\n\n  const requireErrors = outUserFilenames\n    .map((file) => {\n      try {\n        require(file);\n      } catch (err) {\n        return err as Error;\n      }\n    })\n    .filter((err): err is Error => err !== undefined);\n\n  if (requireErrors.length > 0) {\n    throw requireErrors[0];\n  }\n\n  // Then require the `_app.ts` file to grab the `app` instance.\n  const result = require(outAppFilename);\n\n  const app = result.ponder;\n\n  if (!app) {\n    throw new Error(`ponder not exported from generated/index.ts`);\n  }\n  if (!(app.constructor.name === \"PonderApp\")) {\n    throw new Error(`exported ponder not instanceof PonderApp`);\n  }\n  if (app[\"errors\"].length > 0) {\n    const error = app[\"errors\"][0];\n    throw error;\n  }\n\n  const handlers = app[\"handlers\"] as Handlers;\n\n  return handlers;\n};\n","import cors from \"cors\";\nimport detectPort from \"detect-port\";\nimport Emittery from \"emittery\";\nimport express from \"express\";\nimport { graphqlHTTP } from \"express-graphql\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type http from \"node:http\";\n\nimport { MessageKind } from \"@/common/LoggerService\";\nimport { Resources } from \"@/Ponder\";\n\nexport type ServerServiceEvents = {\n  serverStarted: { desiredPort: number; port: number };\n};\n\nexport class ServerService extends Emittery<ServerServiceEvents> {\n  resources: Resources;\n\n  app?: express.Express;\n  server?: http.Server;\n  private graphqlMiddleware?: express.Handler;\n\n  isBackfillEventProcessingComplete = false;\n\n  constructor({ resources }: { resources: Resources }) {\n    super();\n    this.resources = resources;\n  }\n\n  async start() {\n    this.app = express();\n    this.app.use(cors());\n\n    // If the desired port is unavailable, detect-port will find the next available port.\n    const resolvedPort = await detectPort(this.resources.options.port);\n\n    this.server = this.app.listen(resolvedPort);\n\n    this.emit(\"serverStarted\", {\n      desiredPort: this.resources.options.port,\n      port: resolvedPort,\n    });\n\n    // By default, the server will respond as unhealthy until the backfill events have\n    // been processed OR 4.5 minutes have passed since the app was created. This\n    // enables zero-downtime deployments on PaaS platforms like Railway and Render.\n    // Also see https://github.com/0xOlias/ponder/issues/24\n    this.app.get(\"/health\", (_, res) => {\n      if (this.isBackfillEventProcessingComplete) {\n        return res.status(200).send();\n      }\n\n      const max = this.resources.options.maxHealthcheckDuration;\n      const elapsed = Math.floor(process.uptime());\n\n      if (elapsed > max) {\n        this.resources.logger.logMessage(\n          MessageKind.WARNING,\n          `Backfill & log processing time has exceeded the max healthcheck duration of ${max} seconds (current: ${elapsed}). Sevice is now responding as healthy and may serve incomplete data.`\n        );\n        return res.status(200).send();\n      }\n\n      return res.status(503).send();\n    });\n  }\n\n  reload({ graphqlSchema }: { graphqlSchema: GraphQLSchema }) {\n    // This uses a small hack to update the GraphQL server on the fly.\n    this.graphqlMiddleware = graphqlHTTP({\n      schema: graphqlSchema,\n      context: {\n        store: this.resources.entityStore,\n      },\n      graphiql: true,\n    });\n\n    this.app?.use(\"/\", (...args) => this.graphqlMiddleware?.(...args));\n  }\n\n  teardown() {\n    this.server?.unref();\n    return new Promise<void>((resolve, reject) => {\n      this.server?.close((err) => {\n        if (err) return reject(err);\n        resolve();\n      });\n    });\n  }\n}\n","import { Box, Newline, render as inkRender, Text } from \"ink\";\nimport React from \"react\";\n\nimport { LogFilter } from \"@/config/logFilters\";\n\nimport { BackfillBar } from \"./BackfillBar\";\nimport { HandlersBar } from \"./HandlersBar\";\n\nexport type UiState = {\n  port: number;\n\n  stats: Record<\n    string,\n    {\n      cacheRate: number;\n\n      logStartTimestamp: number;\n      logTotal: number;\n      logCurrent: number;\n      logAvgDuration: number;\n      logAvgBlockCount: number;\n\n      blockStartTimestamp: number;\n      blockTotal: number;\n      blockCurrent: number;\n      blockAvgDuration: number;\n\n      eta: number;\n    }\n  >;\n\n  isBackfillComplete: boolean;\n  backfillDuration: string;\n\n  handlerError: boolean;\n  handlersCurrent: number;\n  handlersTotal: number;\n  handlersHandledTotal: number;\n  handlersToTimestamp: number;\n\n  networks: string[];\n};\n\nexport const buildUiState = ({ logFilters }: { logFilters: LogFilter[] }) => {\n  const ui: UiState = {\n    port: 0,\n\n    stats: {},\n\n    isBackfillComplete: false,\n    backfillDuration: \"\",\n\n    handlerError: false,\n    handlersCurrent: 0,\n    handlersTotal: 0,\n    handlersHandledTotal: 0,\n    handlersToTimestamp: 0,\n\n    networks: [],\n  };\n\n  logFilters.forEach((logFilter) => {\n    ui.stats[logFilter.name] = {\n      cacheRate: 0,\n      logStartTimestamp: 0,\n      logTotal: 0,\n      logCurrent: 0,\n      logAvgDuration: 0,\n      logAvgBlockCount: 0,\n      blockStartTimestamp: 0,\n      blockTotal: 0,\n      blockCurrent: 0,\n      blockAvgDuration: 0,\n      eta: 0,\n    };\n  });\n\n  return ui;\n};\n\nconst App = (ui: UiState) => {\n  const {\n    port,\n    stats,\n    isBackfillComplete,\n    backfillDuration,\n    handlersCurrent,\n    handlerError,\n    networks,\n  } = ui;\n\n  if (handlerError) {\n    return (\n      <Box flexDirection=\"column\">\n        <Text> </Text>\n        <Text color=\"cyan\">\n          Resolve the error and save your changes to reload the server.\n        </Text>\n      </Box>\n    );\n  }\n\n  return (\n    <Box flexDirection=\"column\">\n      {/* Newline above interface */}\n      <Text> </Text>\n      <Box flexDirection=\"row\">\n        <Text bold={true}>Backfill </Text>\n        {isBackfillComplete ? (\n          <Text color=\"greenBright\">\n            (done in {backfillDuration})<Newline />\n          </Text>\n        ) : (\n          <Text color=\"yellowBright\">(in progress)</Text>\n        )}\n      </Box>\n      {!isBackfillComplete && (\n        <Box flexDirection=\"column\">\n          {Object.entries(stats).map(([contract, stat]) => (\n            <BackfillBar key={contract} contract={contract} stat={stat} />\n          ))}\n          <Text> </Text>\n        </Box>\n      )}\n\n      <HandlersBar ui={ui} />\n\n      {networks.length > 0 && (\n        <Box flexDirection=\"column\">\n          <Text bold={true}>Networks</Text>\n          {networks.map((network) => (\n            <Box flexDirection=\"row\" key={network}>\n              <Text>\n                {network.slice(0, 1).toUpperCase() + network.slice(1)} (live)\n              </Text>\n            </Box>\n          ))}\n          <Text> </Text>\n        </Box>\n      )}\n\n      {handlersCurrent > 0 && (\n        <Box flexDirection=\"column\">\n          <Text bold={true}>GraphQL </Text>\n          <Box flexDirection=\"row\">\n            <Text>Server live at http://localhost:{port}</Text>\n          </Box>\n        </Box>\n      )}\n    </Box>\n  );\n};\n\nexport const setupInkApp = (ui: UiState) => {\n  const { rerender, unmount: inkUnmount, clear } = inkRender(<App {...ui} />);\n\n  const render = (ui: UiState) => {\n    rerender(<App {...ui} />);\n  };\n\n  const unmount = () => {\n    clear();\n    inkUnmount();\n  };\n  return { render, unmount };\n};\n","import { Box, Text } from \"ink\";\nimport React from \"react\";\n\nimport { formatEta } from \"@/common/utils\";\n\nimport { UiState } from \"./app\";\nimport { ProgressBar } from \"./ProgressBar\";\n\nexport const BackfillBar = ({\n  contract,\n  stat,\n}: {\n  contract: string;\n  stat: UiState[\"stats\"][0];\n}) => {\n  const current = stat.logCurrent + stat.blockCurrent;\n  const total = stat.logTotal + stat.blockTotal;\n\n  // Only display the ETA text once 5 log tasks have been processed\n  const backfillEtaText =\n    stat.logTotal > 5 && stat.eta > 0 ? ` | ~${formatEta(stat.eta)}` : null;\n  // const backfillCountText = total > 0 ? ` | ${current}/${total}` : null;\n\n  // const cacheRateDecimal = Math.round(stat.cacheRate * 1000) / 10;\n  // const cacheRateText = Number.isInteger(cacheRateDecimal)\n  //   ? `${cacheRateDecimal}.0%`\n  //   : `${cacheRateDecimal}%`;\n\n  const rate =\n    (current / Math.max(total, 1)) * (1 - stat.cacheRate) + stat.cacheRate;\n\n  const completionDecimal = Math.round(rate * 1000) / 10;\n  const completionText =\n    Number.isInteger(completionDecimal) && completionDecimal < 100\n      ? `${completionDecimal}.0%`\n      : `${completionDecimal}%`;\n\n  return (\n    <Box flexDirection=\"column\">\n      <Text>\n        {contract}\n        {/* ({cacheRateText} cached) */}\n      </Text>\n      <Box flexDirection=\"row\">\n        <ProgressBar\n          current={current}\n          end={Math.max(total, 1)}\n          cachedRate={stat.cacheRate}\n        />\n        <Text>\n          {\" \"}\n          {completionText}\n          {backfillEtaText}\n          {/* {backfillCountText} */}\n        </Text>\n      </Box>\n      {/* <Text> </Text> */}\n    </Box>\n  );\n};\n","import { Text } from \"ink\";\nimport React from \"react\";\n\nexport const ProgressBar = ({\n  current = 5,\n  end = 10,\n  width = 36,\n  cachedRate = 0,\n}) => {\n  const maxTotalCount = width || process.stdout.columns || 80;\n\n  const cachedCount = Math.min(\n    Math.floor(maxTotalCount * cachedRate),\n    maxTotalCount\n  );\n\n  const maxCount = maxTotalCount - cachedCount;\n\n  const fraction = current / end;\n  const count = Math.min(Math.floor(maxCount * fraction), maxCount);\n\n  return (\n    <Text>\n      <Text>{\"█\".repeat(cachedCount)}</Text>\n      <Text>{\"█\".repeat(count)}</Text>\n      <Text>{\"░\".repeat(maxCount - count)}</Text>\n    </Text>\n  );\n};\n","import { Box, Text } from \"ink\";\nimport React from \"react\";\n\nimport { UiState } from \"./app\";\nimport { ProgressBar } from \"./ProgressBar\";\n\nexport const HandlersBar = ({ ui }: { ui: UiState }) => {\n  const completionRate =\n    ui.handlersCurrent / Math.max(ui.handlersHandledTotal, 1);\n  const completionDecimal = Math.round(completionRate * 1000) / 10;\n  const completionText =\n    Number.isInteger(completionDecimal) && completionDecimal < 100\n      ? `${completionDecimal}.0%`\n      : `${completionDecimal}%`;\n\n  const date = new Date(ui.handlersToTimestamp * 1000);\n  const year = date.getFullYear();\n  const months = [\n    \"Jan\",\n    \"Feb\",\n    \"Mar\",\n    \"Apr\",\n    \"May\",\n    \"Jun\",\n    \"Jul\",\n    \"Aug\",\n    \"Sep\",\n    \"Oct\",\n    \"Nov\",\n    \"Dec\",\n  ];\n  const month = months[date.getMonth()];\n  const day = date.getDate();\n  const dateText = `${month} ${day}, ${year}`;\n\n  const isUpToDate =\n    ui.isBackfillComplete && ui.handlersCurrent === ui.handlersHandledTotal;\n  const isStarted = ui.handlersToTimestamp > 0;\n\n  const titleText = () => {\n    if (isUpToDate) return <Text color=\"greenBright\">(up to date)</Text>;\n    if (isStarted)\n      return (\n        <Text color=\"yellowBright\">\n          (up to {ui.handlersToTimestamp === 0 ? \"\" : dateText})\n        </Text>\n      );\n    return <Text>(not started)</Text>;\n  };\n\n  const countText = () => {\n    if (isUpToDate)\n      return (\n        <Text>\n          {\" \"}\n          | {ui.handlersCurrent}/{ui.handlersHandledTotal} events (\n          {ui.handlersTotal} total)\n        </Text>\n      );\n    if (isStarted)\n      return (\n        <Text>\n          {\" \"}\n          | {ui.handlersCurrent}/\n          {\"?\".repeat(ui.handlersCurrent.toString().length)} events (\n          {ui.handlersTotal} total)\n        </Text>\n      );\n    return null;\n  };\n\n  return (\n    <Box flexDirection=\"column\">\n      <Box flexDirection=\"row\">\n        <Text bold={true}>Handlers </Text>\n        <Text>{titleText()}</Text>\n      </Box>\n      {/* {!isUpToDate && ( */}\n      <Box flexDirection=\"row\">\n        <ProgressBar\n          current={ui.handlersCurrent}\n          end={Math.max(ui.handlersHandledTotal, 1)}\n        />\n        <Text>\n          {\" \"}\n          {completionText}\n          {countText()}\n        </Text>\n      </Box>\n      {/* )} */}\n\n      <Text> </Text>\n    </Box>\n  );\n};\n","import { MessageKind } from \"@/common/LoggerService\";\nimport { formatEta } from \"@/common/utils\";\nimport { Resources } from \"@/Ponder\";\n\nimport { buildUiState, setupInkApp, UiState } from \"./app\";\n\nexport class UiService {\n  resources: Resources;\n\n  ui: UiState;\n  renderInterval: NodeJS.Timer;\n  etaInterval: NodeJS.Timer;\n  render: () => void;\n  unmount: () => void;\n\n  constructor({ resources }: { resources: Resources }) {\n    this.resources = resources;\n\n    this.ui = buildUiState({\n      logFilters: this.resources.logFilters,\n    });\n\n    if (this.resources.options.uiEnabled) {\n      const { render, unmount } = setupInkApp(this.ui);\n      this.render = () => render(this.ui);\n      this.unmount = unmount;\n    } else {\n      this.render = () => undefined;\n      this.unmount = () => undefined;\n    }\n\n    this.renderInterval = setInterval(() => {\n      this.render();\n    }, 17);\n\n    this.etaInterval = setInterval(() => {\n      this.updateBackfillEta();\n      if (!this.resources.options.uiEnabled) this.logBackfillProgress();\n    }, 1000);\n  }\n\n  kill() {\n    this.unmount();\n    clearInterval(this.renderInterval);\n    clearInterval(this.etaInterval);\n  }\n\n  private updateBackfillEta = () => {\n    this.resources.logFilters.forEach((contract) => {\n      const stats = this.ui.stats[contract.name];\n\n      const logTime =\n        (stats.logTotal - stats.logCurrent) * stats.logAvgDuration;\n\n      const blockTime =\n        (stats.blockTotal - stats.blockCurrent) * stats.blockAvgDuration;\n\n      const estimatedAdditionalBlocks =\n        (stats.logTotal - stats.logCurrent) * stats.logAvgBlockCount;\n\n      const estimatedAdditionalBlockTime =\n        estimatedAdditionalBlocks * stats.blockAvgDuration;\n\n      const eta = Math.max(logTime, blockTime + estimatedAdditionalBlockTime);\n\n      this.ui.stats[contract.name].eta = Number.isNaN(eta) ? 0 : eta;\n    });\n  };\n\n  private logBackfillProgress() {\n    if (this.ui.isBackfillComplete) return;\n\n    this.resources.logFilters.forEach((contract) => {\n      const stat = this.ui.stats[contract.name];\n\n      const current = stat.logCurrent + stat.blockCurrent;\n      const total = stat.logTotal + stat.blockTotal;\n      const isDone = current === total;\n      if (isDone) return;\n      const etaText =\n        stat.logCurrent > 5 && stat.eta > 0\n          ? `~${formatEta(stat.eta)}`\n          : \"not started\";\n\n      const countText = `${current}/${total}`;\n\n      this.resources.logger.logMessage(\n        MessageKind.BACKFILL,\n        `${contract.name}: ${`(${etaText + \" | \" + countText})`}`\n      );\n    });\n  }\n}\n"]}