@latticexyz/store-indexer 2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f → 2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  sentry
4
- } from "../chunk-ALQNRR4A.js";
4
+ } from "../chunk-6CTSQZFV.js";
5
5
  import {
6
6
  getClientOptions
7
7
  } from "../chunk-MGRTFMMG.js";
@@ -6,7 +6,7 @@ import {
6
6
  debug,
7
7
  error,
8
8
  sentry
9
- } from "../chunk-ALQNRR4A.js";
9
+ } from "../chunk-6CTSQZFV.js";
10
10
  import {
11
11
  frontendEnvSchema,
12
12
  parseEnv
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  debug,
7
7
  sentry
8
- } from "../chunk-ALQNRR4A.js";
8
+ } from "../chunk-6CTSQZFV.js";
9
9
  import {
10
10
  getClientOptions
11
11
  } from "../chunk-MGRTFMMG.js";
@@ -33,6 +33,7 @@ import { drizzle } from "drizzle-orm/better-sqlite3";
33
33
  import Database from "better-sqlite3";
34
34
  import Koa from "koa";
35
35
  import cors from "@koa/cors";
36
+ import bodyParser from "koa-bodyparser";
36
37
  import { createKoaMiddleware } from "trpc-koa-adapter";
37
38
  import { createAppRouter } from "@latticexyz/store-sync/trpc-indexer";
38
39
  import { chainState as chainState2, schemaVersion, syncToSqlite } from "@latticexyz/store-sync/sqlite";
@@ -103,12 +104,13 @@ async function createQueryAdapter(database2) {
103
104
  import { combineLatest, filter, first } from "rxjs";
104
105
 
105
106
  // src/sqlite/apiRoutes.ts
107
+ import { sql } from "drizzle-orm";
106
108
  import Router from "@koa/router";
107
109
  import compose from "koa-compose";
108
110
  import { input } from "@latticexyz/store-sync/indexer-client";
109
111
  import { schemasTable, tablesWithRecordsToLogs as tablesWithRecordsToLogs2 } from "@latticexyz/store-sync";
110
112
  import { createBenchmark } from "@latticexyz/common";
111
- function apiRoutes(database2) {
113
+ function apiRoutes({ database: database2, enableUnsafeQueryApi = false }) {
112
114
  const router = new Router();
113
115
  router.get("/api/logs", compress(), async (ctx) => {
114
116
  const benchmark = createBenchmark("sqlite:logs");
@@ -136,6 +138,44 @@ function apiRoutes(database2) {
136
138
  debug(error);
137
139
  }
138
140
  });
141
+ router.post("/q", async (ctx) => {
142
+ if (!enableUnsafeQueryApi) {
143
+ ctx.status = 404;
144
+ ctx.body = JSON.stringify({ error: "Query endpoint is not enabled" });
145
+ return;
146
+ }
147
+ try {
148
+ const queries = Array.isArray(ctx.request.body) ? ctx.request.body : [];
149
+ if (queries.length === 0) {
150
+ ctx.status = 400;
151
+ ctx.body = JSON.stringify({ error: "No queries provided" });
152
+ return;
153
+ }
154
+ const result = [];
155
+ for (const { query } of queries) {
156
+ const data = database2.all(sql.raw(query));
157
+ if (!data || !Array.isArray(data)) {
158
+ throw new Error("Invalid query result");
159
+ }
160
+ if (data.length === 0) {
161
+ result.push([]);
162
+ continue;
163
+ }
164
+ if (!data[0]) {
165
+ throw new Error("Invalid row data");
166
+ }
167
+ const columns = Object.keys(data[0]).map((key) => key.replaceAll("_", "").toLowerCase());
168
+ const rows = data.map((row) => Object.values(row).map((value) => value?.toString() ?? ""));
169
+ result.push([columns, ...rows]);
170
+ }
171
+ ctx.status = 200;
172
+ ctx.body = JSON.stringify({ result });
173
+ } catch (error) {
174
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
175
+ ctx.status = 400;
176
+ ctx.body = JSON.stringify({ error: errorMessage });
177
+ }
178
+ });
139
179
  return compose([router.routes(), router.allowedMethods()]);
140
180
  }
141
181
 
@@ -147,7 +187,8 @@ var env = parseEnv(
147
187
  z.intersection(indexerEnvSchema, frontendEnvSchema),
148
188
  z.object({
149
189
  SQLITE_FILENAME: z.string().default("indexer.db"),
150
- SENTRY_DSN: z.string().optional()
190
+ SENTRY_DSN: z.string().optional(),
191
+ ENABLE_UNSAFE_QUERY_API: z.string().optional().default("false").transform((val) => val === "true")
151
192
  })
152
193
  )
153
194
  );
@@ -213,6 +254,7 @@ if (env.SENTRY_DSN) {
213
254
  server.use(sentry(env.SENTRY_DSN));
214
255
  }
215
256
  server.use(cors());
257
+ server.use(bodyParser());
216
258
  server.use(
217
259
  healthcheck({
218
260
  isReady: () => isCaughtUp
@@ -228,7 +270,7 @@ server.use(
228
270
  })
229
271
  );
230
272
  server.use(helloWorld());
231
- server.use(apiRoutes(database));
273
+ server.use(apiRoutes({ database, enableUnsafeQueryApi: env.ENABLE_UNSAFE_QUERY_API }));
232
274
  server.use(
233
275
  createKoaMiddleware({
234
276
  prefix: "/trpc",
@@ -240,4 +282,12 @@ server.use(
240
282
  );
241
283
  server.listen({ host: env.HOST, port: env.PORT });
242
284
  console.log(`sqlite indexer frontend listening on http://${env.HOST}:${env.PORT}`);
285
+ if (env.ENABLE_UNSAFE_QUERY_API) {
286
+ console.warn("\n\n\u26A0\uFE0F SECURITY WARNING \u26A0\uFE0F");
287
+ console.warn("=========================\n");
288
+ console.warn("UNSAFE QUERY API IS ENABLED");
289
+ console.warn("DO NOT USE IN PRODUCTION");
290
+ console.warn("This will expose your database to public access");
291
+ console.warn("\n=========================\n\n");
292
+ }
243
293
  //# sourceMappingURL=sqlite-indexer.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/sqlite-indexer.ts","../../src/sqlite/getTablesWithRecords.ts","../../src/sqlite/createQueryAdapter.ts","../../src/sqlite/apiRoutes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { eq } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport Database from \"better-sqlite3\";\nimport Koa from \"koa\";\nimport cors from \"@koa/cors\";\nimport { createKoaMiddleware } from \"trpc-koa-adapter\";\nimport { createAppRouter } from \"@latticexyz/store-sync/trpc-indexer\";\nimport { chainState, schemaVersion, syncToSqlite } from \"@latticexyz/store-sync/sqlite\";\nimport { createQueryAdapter } from \"../sqlite/createQueryAdapter\";\nimport { combineLatest, filter, first } from \"rxjs\";\nimport { frontendEnvSchema, indexerEnvSchema, parseEnv } from \"./parseEnv\";\nimport { healthcheck } from \"../koa-middleware/healthcheck\";\nimport { helloWorld } from \"../koa-middleware/helloWorld\";\nimport { apiRoutes } from \"../sqlite/apiRoutes\";\nimport { sentry } from \"../koa-middleware/sentry\";\nimport { metrics } from \"../koa-middleware/metrics\";\nimport { getClientOptions } from \"./getClientOptions\";\nimport { getRpcClient } from \"@latticexyz/block-logs-stream\";\nimport { getBlock, getChainId } from \"viem/actions\";\n\nconst env = parseEnv(\n z.intersection(\n z.intersection(indexerEnvSchema, frontendEnvSchema),\n z.object({\n SQLITE_FILENAME: z.string().default(\"indexer.db\"),\n SENTRY_DSN: z.string().optional(),\n }),\n ),\n);\n\nconst clientOptions = await getClientOptions(env);\n\nconst chainId = await getChainId(getRpcClient(clientOptions));\nconst database = drizzle(new Database(env.SQLITE_FILENAME));\n\nlet startBlock = env.START_BLOCK;\n\nasync function getCurrentChainState(): Promise<\n | {\n schemaVersion: number;\n chainId: number;\n lastUpdatedBlockNumber: bigint | null;\n lastError: string | null;\n }\n | undefined\n> {\n // This will throw if the DB doesn't exist yet, so we wrap in a try/catch and ignore the error.\n try {\n const currentChainStates = database.select().from(chainState).where(eq(chainState.chainId, chainId)).all();\n // TODO: replace this type workaround with `noUncheckedIndexedAccess: true` when we can fix all the issues related (https://github.com/latticexyz/mud/issues/1212)\n const currentChainState: (typeof currentChainStates)[number] | undefined = currentChainStates[0];\n return currentChainState;\n } catch (error) {\n // ignore errors, this is optional\n }\n}\n\nasync function getLatestStoredBlockNumber(): Promise<bigint | undefined> {\n const currentChainState = await getCurrentChainState();\n return currentChainState?.lastUpdatedBlockNumber ?? undefined;\n}\n\nasync function getDistanceFromFollowBlock(): Promise<bigint> {\n const [latestStoredBlockNumber, latestFollowBlock] = await Promise.all([\n getLatestStoredBlockNumber(),\n getBlock(getRpcClient(clientOptions), { blockTag: env.FOLLOW_BLOCK_TAG }),\n ]);\n return latestFollowBlock.number - (latestStoredBlockNumber ?? -1n);\n}\n\nconst currentChainState = await getCurrentChainState();\nif (currentChainState) {\n // Reset the db if the version changed\n if (currentChainState.schemaVersion != schemaVersion) {\n console.log(\n \"schema version changed from\",\n currentChainState.schemaVersion,\n \"to\",\n schemaVersion,\n \"recreating database\",\n );\n fs.truncateSync(env.SQLITE_FILENAME);\n } else if (currentChainState.lastUpdatedBlockNumber != null) {\n // Resume from latest block stored in DB. This will throw if the DB doesn't exist yet, so we wrap in a try/catch and ignore the error.\n console.log(\"resuming from block number\", currentChainState.lastUpdatedBlockNumber + 1n);\n startBlock = currentChainState.lastUpdatedBlockNumber + 1n;\n }\n}\n\nconst { latestBlockNumber$, storedBlockLogs$ } = await syncToSqlite({\n ...clientOptions,\n database,\n followBlockTag: env.FOLLOW_BLOCK_TAG,\n startBlock,\n maxBlockRange: env.MAX_BLOCK_RANGE,\n address: env.STORE_ADDRESS,\n});\n\nlet isCaughtUp = false;\ncombineLatest([latestBlockNumber$, storedBlockLogs$])\n .pipe(\n filter(\n ([latestBlockNumber, { blockNumber: lastBlockNumberProcessed }]) =>\n latestBlockNumber === lastBlockNumberProcessed,\n ),\n first(),\n )\n .subscribe(() => {\n isCaughtUp = true;\n console.log(\"all caught up\");\n });\n\nconst server = new Koa();\n\nif (env.SENTRY_DSN) {\n server.use(sentry(env.SENTRY_DSN));\n}\n\nserver.use(cors());\nserver.use(\n healthcheck({\n isReady: () => isCaughtUp,\n }),\n);\nserver.use(\n metrics({\n isHealthy: () => true,\n isReady: () => isCaughtUp,\n getLatestStoredBlockNumber,\n getDistanceFromFollowBlock,\n followBlockTag: env.FOLLOW_BLOCK_TAG,\n }),\n);\nserver.use(helloWorld());\nserver.use(apiRoutes(database));\n\nserver.use(\n createKoaMiddleware({\n prefix: \"/trpc\",\n router: createAppRouter(),\n createContext: async () => ({\n queryAdapter: await createQueryAdapter(database),\n }),\n }),\n);\n\nserver.listen({ host: env.HOST, port: env.PORT });\nconsole.log(`sqlite indexer frontend listening on http://${env.HOST}:${env.PORT}`);\n","import { asc, eq } from \"drizzle-orm\";\nimport { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport { buildTable, chainState, getTables } from \"@latticexyz/store-sync/sqlite\";\nimport { Hex, getAddress } from \"viem\";\nimport { decodeDynamicField } from \"@latticexyz/protocol-parser/internal\";\nimport { SyncFilter, TableRecord, TableWithRecords } from \"@latticexyz/store-sync\";\nimport { hexToResource } from \"@latticexyz/common\";\nimport { mapObject } from \"@latticexyz/common/utils\";\n\n// TODO: refactor sqlite and replace this with getLogs to match postgres (https://github.com/latticexyz/mud/issues/1970)\n\n/**\n * @deprecated\n * */\nexport function getTablesWithRecords(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n database: BaseSQLiteDatabase<\"sync\", any>,\n {\n chainId,\n address,\n filters = [],\n }: {\n readonly chainId: number;\n readonly address?: Hex;\n readonly filters?: readonly SyncFilter[];\n },\n): { blockNumber: bigint | null; tables: readonly TableWithRecords[] } {\n const metadata = database\n .select()\n .from(chainState)\n .where(eq(chainState.chainId, chainId))\n .limit(1)\n .all()\n .find(() => true);\n\n // If _any_ filter has a table ID, this will filter down all data to just those tables. Which mean we can't yet mix table filters with key-only filters.\n // TODO: improve this so we can express this in the query (need to be able to query data across tables more easily)\n const tableIds = Array.from(new Set(filters.map((filter) => filter.tableId)));\n const tables = getTables(database)\n .filter((table) => address == null || getAddress(address) === getAddress(table.address))\n .filter((table) => !tableIds.length || tableIds.includes(table.tableId));\n\n const tablesWithRecords = tables.map((table) => {\n const sqliteTable = buildTable(table);\n const records = database\n .select()\n .from(sqliteTable)\n .where(eq(sqliteTable.__isDeleted, false))\n .orderBy(\n asc(sqliteTable.__lastUpdatedBlockNumber),\n // TODO: add logIndex (https://github.com/latticexyz/mud/issues/1979)\n )\n .all();\n const filteredRecords = !filters.length\n ? records\n : records.filter((record) => {\n const keyTuple = decodeDynamicField(\"bytes32[]\", record.__key);\n return filters.some(\n (filter) =>\n filter.tableId === table.tableId &&\n (filter.key0 == null || filter.key0 === keyTuple[0]) &&\n (filter.key1 == null || filter.key1 === keyTuple[1]),\n );\n });\n const resource = hexToResource(table.tableId);\n return {\n ...table,\n type: resource.type as never,\n schema: mapObject({ ...table.keySchema, ...table.valueSchema }, (type) => ({ type, internalType: type })),\n key: Object.keys(table.keySchema),\n records: filteredRecords.map((record): TableRecord => {\n const key = Object.fromEntries(Object.entries(table.keySchema).map(([name]) => [name, record[name]]));\n const value = Object.fromEntries(Object.entries(table.valueSchema).map(([name]) => [name, record[name]]));\n return { key, value, fields: { ...key, ...value } };\n }),\n } satisfies TableWithRecords;\n });\n\n return {\n blockNumber: metadata?.lastUpdatedBlockNumber ?? null,\n tables: tablesWithRecords,\n };\n}\n","import { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport { QueryAdapter } from \"@latticexyz/store-sync/trpc-indexer\";\nimport { getTablesWithRecords } from \"./getTablesWithRecords\";\nimport { tablesWithRecordsToLogs } from \"@latticexyz/store-sync\";\n\n/**\n * Creates a storage adapter for the tRPC server/client to query data from SQLite.\n *\n * @param {BaseSQLiteDatabase<\"sync\", any>} database SQLite database object from Drizzle\n * @returns {Promise<QueryAdapter>} A set of methods used by tRPC endpoints.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function createQueryAdapter(database: BaseSQLiteDatabase<\"sync\", any>): Promise<QueryAdapter> {\n const adapter: QueryAdapter = {\n async getLogs(opts) {\n const { blockNumber, tables } = getTablesWithRecords(database, opts);\n const logs = tablesWithRecordsToLogs(tables);\n return { blockNumber: blockNumber ?? 0n, logs };\n },\n async findAll(opts) {\n return getTablesWithRecords(database, opts);\n },\n };\n return adapter;\n}\n","import { Middleware } from \"koa\";\nimport Router from \"@koa/router\";\nimport compose from \"koa-compose\";\nimport { input } from \"@latticexyz/store-sync/indexer-client\";\nimport { schemasTable, tablesWithRecordsToLogs } from \"@latticexyz/store-sync\";\nimport { debug } from \"../debug\";\nimport { createBenchmark } from \"@latticexyz/common\";\nimport { compress } from \"../koa-middleware/compress\";\nimport { getTablesWithRecords } from \"./getTablesWithRecords\";\nimport { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function apiRoutes(database: BaseSQLiteDatabase<\"sync\", any>): Middleware {\n const router = new Router();\n\n router.get(\"/api/logs\", compress(), async (ctx) => {\n const benchmark = createBenchmark(\"sqlite:logs\");\n\n let options: ReturnType<typeof input.parse>;\n\n try {\n options = input.parse(typeof ctx.query.input === \"string\" ? JSON.parse(ctx.query.input) : {});\n } catch (error) {\n ctx.status = 400;\n ctx.body = JSON.stringify(error);\n debug(error);\n return;\n }\n\n try {\n options.filters = options.filters.length > 0 ? [...options.filters, { tableId: schemasTable.tableId }] : [];\n benchmark(\"parse config\");\n const { blockNumber, tables } = getTablesWithRecords(database, options);\n benchmark(\"query tables with records\");\n const logs = tablesWithRecordsToLogs(tables);\n benchmark(\"convert records to logs\");\n\n ctx.body = JSON.stringify({ blockNumber: blockNumber?.toString() ?? \"-1\", logs });\n ctx.status = 200;\n } catch (error) {\n ctx.status = 500;\n ctx.body = JSON.stringify(error);\n debug(error);\n }\n });\n\n return compose([router.routes(), router.allowedMethods()]) as Middleware;\n}\n"],"mappings":"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","names":["eq","chainState","database","chainId","filter","database","tablesWithRecordsToLogs","database","tablesWithRecordsToLogs","chainState","eq","currentChainState"]}
1
+ {"version":3,"sources":["../../src/bin/sqlite-indexer.ts","../../src/sqlite/getTablesWithRecords.ts","../../src/sqlite/createQueryAdapter.ts","../../src/sqlite/apiRoutes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { eq } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport Database from \"better-sqlite3\";\nimport Koa from \"koa\";\nimport cors from \"@koa/cors\";\nimport bodyParser from \"koa-bodyparser\";\nimport { createKoaMiddleware } from \"trpc-koa-adapter\";\nimport { createAppRouter } from \"@latticexyz/store-sync/trpc-indexer\";\nimport { chainState, schemaVersion, syncToSqlite } from \"@latticexyz/store-sync/sqlite\";\nimport { createQueryAdapter } from \"../sqlite/createQueryAdapter\";\nimport { combineLatest, filter, first } from \"rxjs\";\nimport { frontendEnvSchema, indexerEnvSchema, parseEnv } from \"./parseEnv\";\nimport { healthcheck } from \"../koa-middleware/healthcheck\";\nimport { helloWorld } from \"../koa-middleware/helloWorld\";\nimport { apiRoutes } from \"../sqlite/apiRoutes\";\nimport { sentry } from \"../koa-middleware/sentry\";\nimport { metrics } from \"../koa-middleware/metrics\";\nimport { getClientOptions } from \"./getClientOptions\";\nimport { getRpcClient } from \"@latticexyz/block-logs-stream\";\nimport { getBlock, getChainId } from \"viem/actions\";\n\nconst env = parseEnv(\n z.intersection(\n z.intersection(indexerEnvSchema, frontendEnvSchema),\n z.object({\n SQLITE_FILENAME: z.string().default(\"indexer.db\"),\n SENTRY_DSN: z.string().optional(),\n ENABLE_UNSAFE_QUERY_API: z\n .string()\n .optional()\n .default(\"false\")\n .transform((val) => val === \"true\"),\n }),\n ),\n);\n\nconst clientOptions = await getClientOptions(env);\n\nconst chainId = await getChainId(getRpcClient(clientOptions));\nconst database = drizzle(new Database(env.SQLITE_FILENAME));\n\nlet startBlock = env.START_BLOCK;\n\nasync function getCurrentChainState(): Promise<\n | {\n schemaVersion: number;\n chainId: number;\n lastUpdatedBlockNumber: bigint | null;\n lastError: string | null;\n }\n | undefined\n> {\n // This will throw if the DB doesn't exist yet, so we wrap in a try/catch and ignore the error.\n try {\n const currentChainStates = database.select().from(chainState).where(eq(chainState.chainId, chainId)).all();\n // TODO: replace this type workaround with `noUncheckedIndexedAccess: true` when we can fix all the issues related (https://github.com/latticexyz/mud/issues/1212)\n const currentChainState: (typeof currentChainStates)[number] | undefined = currentChainStates[0];\n return currentChainState;\n } catch (error) {\n // ignore errors, this is optional\n }\n}\n\nasync function getLatestStoredBlockNumber(): Promise<bigint | undefined> {\n const currentChainState = await getCurrentChainState();\n return currentChainState?.lastUpdatedBlockNumber ?? undefined;\n}\n\nasync function getDistanceFromFollowBlock(): Promise<bigint> {\n const [latestStoredBlockNumber, latestFollowBlock] = await Promise.all([\n getLatestStoredBlockNumber(),\n getBlock(getRpcClient(clientOptions), { blockTag: env.FOLLOW_BLOCK_TAG }),\n ]);\n return latestFollowBlock.number - (latestStoredBlockNumber ?? -1n);\n}\n\nconst currentChainState = await getCurrentChainState();\nif (currentChainState) {\n // Reset the db if the version changed\n if (currentChainState.schemaVersion != schemaVersion) {\n console.log(\n \"schema version changed from\",\n currentChainState.schemaVersion,\n \"to\",\n schemaVersion,\n \"recreating database\",\n );\n fs.truncateSync(env.SQLITE_FILENAME);\n } else if (currentChainState.lastUpdatedBlockNumber != null) {\n // Resume from latest block stored in DB. This will throw if the DB doesn't exist yet, so we wrap in a try/catch and ignore the error.\n console.log(\"resuming from block number\", currentChainState.lastUpdatedBlockNumber + 1n);\n startBlock = currentChainState.lastUpdatedBlockNumber + 1n;\n }\n}\n\nconst { latestBlockNumber$, storedBlockLogs$ } = await syncToSqlite({\n ...clientOptions,\n database,\n followBlockTag: env.FOLLOW_BLOCK_TAG,\n startBlock,\n maxBlockRange: env.MAX_BLOCK_RANGE,\n address: env.STORE_ADDRESS,\n});\n\nlet isCaughtUp = false;\ncombineLatest([latestBlockNumber$, storedBlockLogs$])\n .pipe(\n filter(\n ([latestBlockNumber, { blockNumber: lastBlockNumberProcessed }]) =>\n latestBlockNumber === lastBlockNumberProcessed,\n ),\n first(),\n )\n .subscribe(() => {\n isCaughtUp = true;\n console.log(\"all caught up\");\n });\n\nconst server = new Koa();\n\nif (env.SENTRY_DSN) {\n server.use(sentry(env.SENTRY_DSN));\n}\n\nserver.use(cors());\nserver.use(bodyParser());\nserver.use(\n healthcheck({\n isReady: () => isCaughtUp,\n }),\n);\nserver.use(\n metrics({\n isHealthy: () => true,\n isReady: () => isCaughtUp,\n getLatestStoredBlockNumber,\n getDistanceFromFollowBlock,\n followBlockTag: env.FOLLOW_BLOCK_TAG,\n }),\n);\nserver.use(helloWorld());\nserver.use(apiRoutes({ database, enableUnsafeQueryApi: env.ENABLE_UNSAFE_QUERY_API }));\n\nserver.use(\n createKoaMiddleware({\n prefix: \"/trpc\",\n router: createAppRouter(),\n createContext: async () => ({\n queryAdapter: await createQueryAdapter(database),\n }),\n }),\n);\n\nserver.listen({ host: env.HOST, port: env.PORT });\nconsole.log(`sqlite indexer frontend listening on http://${env.HOST}:${env.PORT}`);\n\nif (env.ENABLE_UNSAFE_QUERY_API) {\n console.warn(\"\\n\\n⚠️ SECURITY WARNING ⚠️\");\n console.warn(\"=========================\\n\");\n console.warn(\"UNSAFE QUERY API IS ENABLED\");\n console.warn(\"DO NOT USE IN PRODUCTION\");\n console.warn(\"This will expose your database to public access\");\n console.warn(\"\\n=========================\\n\\n\");\n}\n","import { asc, eq } from \"drizzle-orm\";\nimport { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport { buildTable, chainState, getTables } from \"@latticexyz/store-sync/sqlite\";\nimport { Hex, getAddress } from \"viem\";\nimport { decodeDynamicField } from \"@latticexyz/protocol-parser/internal\";\nimport { SyncFilter, TableRecord, TableWithRecords } from \"@latticexyz/store-sync\";\nimport { hexToResource } from \"@latticexyz/common\";\nimport { mapObject } from \"@latticexyz/common/utils\";\n\n// TODO: refactor sqlite and replace this with getLogs to match postgres (https://github.com/latticexyz/mud/issues/1970)\n\n/**\n * @deprecated\n * */\nexport function getTablesWithRecords(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n database: BaseSQLiteDatabase<\"sync\", any>,\n {\n chainId,\n address,\n filters = [],\n }: {\n readonly chainId: number;\n readonly address?: Hex;\n readonly filters?: readonly SyncFilter[];\n },\n): { blockNumber: bigint | null; tables: readonly TableWithRecords[] } {\n const metadata = database\n .select()\n .from(chainState)\n .where(eq(chainState.chainId, chainId))\n .limit(1)\n .all()\n .find(() => true);\n\n // If _any_ filter has a table ID, this will filter down all data to just those tables. Which mean we can't yet mix table filters with key-only filters.\n // TODO: improve this so we can express this in the query (need to be able to query data across tables more easily)\n const tableIds = Array.from(new Set(filters.map((filter) => filter.tableId)));\n const tables = getTables(database)\n .filter((table) => address == null || getAddress(address) === getAddress(table.address))\n .filter((table) => !tableIds.length || tableIds.includes(table.tableId));\n\n const tablesWithRecords = tables.map((table) => {\n const sqliteTable = buildTable(table);\n const records = database\n .select()\n .from(sqliteTable)\n .where(eq(sqliteTable.__isDeleted, false))\n .orderBy(\n asc(sqliteTable.__lastUpdatedBlockNumber),\n // TODO: add logIndex (https://github.com/latticexyz/mud/issues/1979)\n )\n .all();\n const filteredRecords = !filters.length\n ? records\n : records.filter((record) => {\n const keyTuple = decodeDynamicField(\"bytes32[]\", record.__key);\n return filters.some(\n (filter) =>\n filter.tableId === table.tableId &&\n (filter.key0 == null || filter.key0 === keyTuple[0]) &&\n (filter.key1 == null || filter.key1 === keyTuple[1]),\n );\n });\n const resource = hexToResource(table.tableId);\n return {\n ...table,\n type: resource.type as never,\n schema: mapObject({ ...table.keySchema, ...table.valueSchema }, (type) => ({ type, internalType: type })),\n key: Object.keys(table.keySchema),\n records: filteredRecords.map((record): TableRecord => {\n const key = Object.fromEntries(Object.entries(table.keySchema).map(([name]) => [name, record[name]]));\n const value = Object.fromEntries(Object.entries(table.valueSchema).map(([name]) => [name, record[name]]));\n return { key, value, fields: { ...key, ...value } };\n }),\n } satisfies TableWithRecords;\n });\n\n return {\n blockNumber: metadata?.lastUpdatedBlockNumber ?? null,\n tables: tablesWithRecords,\n };\n}\n","import { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport { QueryAdapter } from \"@latticexyz/store-sync/trpc-indexer\";\nimport { getTablesWithRecords } from \"./getTablesWithRecords\";\nimport { tablesWithRecordsToLogs } from \"@latticexyz/store-sync\";\n\n/**\n * Creates a storage adapter for the tRPC server/client to query data from SQLite.\n *\n * @param {BaseSQLiteDatabase<\"sync\", any>} database SQLite database object from Drizzle\n * @returns {Promise<QueryAdapter>} A set of methods used by tRPC endpoints.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function createQueryAdapter(database: BaseSQLiteDatabase<\"sync\", any>): Promise<QueryAdapter> {\n const adapter: QueryAdapter = {\n async getLogs(opts) {\n const { blockNumber, tables } = getTablesWithRecords(database, opts);\n const logs = tablesWithRecordsToLogs(tables);\n return { blockNumber: blockNumber ?? 0n, logs };\n },\n async findAll(opts) {\n return getTablesWithRecords(database, opts);\n },\n };\n return adapter;\n}\n","import { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport { sql } from \"drizzle-orm\";\nimport { Middleware } from \"koa\";\nimport Router from \"@koa/router\";\nimport compose from \"koa-compose\";\nimport { input } from \"@latticexyz/store-sync/indexer-client\";\nimport { schemasTable, tablesWithRecordsToLogs } from \"@latticexyz/store-sync\";\nimport { debug } from \"../debug\";\nimport { createBenchmark } from \"@latticexyz/common\";\nimport { compress } from \"../koa-middleware/compress\";\nimport { getTablesWithRecords } from \"./getTablesWithRecords\";\n\ntype Props = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n database: BaseSQLiteDatabase<\"sync\", any>;\n enableUnsafeQueryApi?: boolean;\n};\n\nexport function apiRoutes({ database, enableUnsafeQueryApi = false }: Props): Middleware {\n const router = new Router();\n\n router.get(\"/api/logs\", compress(), async (ctx) => {\n const benchmark = createBenchmark(\"sqlite:logs\");\n\n let options: ReturnType<typeof input.parse>;\n\n try {\n options = input.parse(typeof ctx.query.input === \"string\" ? JSON.parse(ctx.query.input) : {});\n } catch (error) {\n ctx.status = 400;\n ctx.body = JSON.stringify(error);\n debug(error);\n return;\n }\n\n try {\n options.filters = options.filters.length > 0 ? [...options.filters, { tableId: schemasTable.tableId }] : [];\n benchmark(\"parse config\");\n const { blockNumber, tables } = getTablesWithRecords(database, options);\n benchmark(\"query tables with records\");\n const logs = tablesWithRecordsToLogs(tables);\n benchmark(\"convert records to logs\");\n\n ctx.body = JSON.stringify({ blockNumber: blockNumber?.toString() ?? \"-1\", logs });\n ctx.status = 200;\n } catch (error) {\n ctx.status = 500;\n ctx.body = JSON.stringify(error);\n debug(error);\n }\n });\n\n router.post(\"/q\", async (ctx) => {\n if (!enableUnsafeQueryApi) {\n ctx.status = 404;\n ctx.body = JSON.stringify({ error: \"Query endpoint is not enabled\" });\n return;\n }\n\n try {\n const queries = Array.isArray(ctx.request.body) ? ctx.request.body : [];\n if (queries.length === 0) {\n ctx.status = 400;\n ctx.body = JSON.stringify({ error: \"No queries provided\" });\n return;\n }\n\n const result = [];\n for (const { query } of queries) {\n const data = database.all(sql.raw(query)) as Record<string, unknown>[];\n if (!data || !Array.isArray(data)) {\n throw new Error(\"Invalid query result\");\n }\n\n if (data.length === 0) {\n result.push([]);\n continue;\n }\n\n if (!data[0]) {\n throw new Error(\"Invalid row data\");\n }\n\n const columns = Object.keys(data[0]).map((key) => key.replaceAll(\"_\", \"\").toLowerCase());\n const rows = data.map((row) => Object.values(row).map((value) => value?.toString() ?? \"\"));\n result.push([columns, ...rows]);\n }\n\n ctx.status = 200;\n ctx.body = JSON.stringify({ result });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"An unknown error occurred\";\n ctx.status = 400;\n ctx.body = JSON.stringify({ error: errorMessage });\n }\n });\n\n return compose([router.routes(), router.allowedMethods()]) as Middleware;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,OAAO;AACP,OAAO,QAAQ;AACf,SAAS,SAAS;AAClB,SAAS,MAAAA,WAAU;AACnB,SAAS,eAAe;AACxB,OAAO,cAAc;AACrB,OAAO,SAAS;AAChB,OAAO,UAAU;AACjB,OAAO,gBAAgB;AACvB,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,cAAAC,aAAY,eAAe,oBAAoB;;;ACZxD,SAAS,KAAK,UAAU;AAExB,SAAS,YAAY,YAAY,iBAAiB;AAClD,SAAc,kBAAkB;AAChC,SAAS,0BAA0B;AAEnC,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAOnB,SAAS,qBAEdC,WACA;AAAA,EACE,SAAAC;AAAA,EACA;AAAA,EACA,UAAU,CAAC;AACb,GAKqE;AACrE,QAAM,WAAWD,UACd,OAAO,EACP,KAAK,UAAU,EACf,MAAM,GAAG,WAAW,SAASC,QAAO,CAAC,EACrC,MAAM,CAAC,EACP,IAAI,EACJ,KAAK,MAAM,IAAI;AAIlB,QAAM,WAAW,MAAM,KAAK,IAAI,IAAI,QAAQ,IAAI,CAACC,YAAWA,QAAO,OAAO,CAAC,CAAC;AAC5E,QAAM,SAAS,UAAUF,SAAQ,EAC9B,OAAO,CAAC,UAAU,WAAW,QAAQ,WAAW,OAAO,MAAM,WAAW,MAAM,OAAO,CAAC,EACtF,OAAO,CAAC,UAAU,CAAC,SAAS,UAAU,SAAS,SAAS,MAAM,OAAO,CAAC;AAEzE,QAAM,oBAAoB,OAAO,IAAI,CAAC,UAAU;AAC9C,UAAM,cAAc,WAAW,KAAK;AACpC,UAAM,UAAUA,UACb,OAAO,EACP,KAAK,WAAW,EAChB,MAAM,GAAG,YAAY,aAAa,KAAK,CAAC,EACxC;AAAA,MACC,IAAI,YAAY,wBAAwB;AAAA;AAAA,IAE1C,EACC,IAAI;AACP,UAAM,kBAAkB,CAAC,QAAQ,SAC7B,UACA,QAAQ,OAAO,CAAC,WAAW;AACzB,YAAM,WAAW,mBAAmB,aAAa,OAAO,KAAK;AAC7D,aAAO,QAAQ;AAAA,QACb,CAACE,YACCA,QAAO,YAAY,MAAM,YACxBA,QAAO,QAAQ,QAAQA,QAAO,SAAS,SAAS,CAAC,OACjDA,QAAO,QAAQ,QAAQA,QAAO,SAAS,SAAS,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AACL,UAAM,WAAW,cAAc,MAAM,OAAO;AAC5C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,SAAS;AAAA,MACf,QAAQ,UAAU,EAAE,GAAG,MAAM,WAAW,GAAG,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,MAAM,cAAc,KAAK,EAAE;AAAA,MACxG,KAAK,OAAO,KAAK,MAAM,SAAS;AAAA,MAChC,SAAS,gBAAgB,IAAI,CAAC,WAAwB;AACpD,cAAM,MAAM,OAAO,YAAY,OAAO,QAAQ,MAAM,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC,CAAC;AACpG,cAAM,QAAQ,OAAO,YAAY,OAAO,QAAQ,MAAM,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC,CAAC;AACxG,eAAO,EAAE,KAAK,OAAO,QAAQ,EAAE,GAAG,KAAK,GAAG,MAAM,EAAE;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,aAAa,UAAU,0BAA0B;AAAA,IACjD,QAAQ;AAAA,EACV;AACF;;;AC/EA,SAAS,+BAA+B;AASxC,eAAsB,mBAAmBC,WAAkE;AACzG,QAAM,UAAwB;AAAA,IAC5B,MAAM,QAAQ,MAAM;AAClB,YAAM,EAAE,aAAa,OAAO,IAAI,qBAAqBA,WAAU,IAAI;AACnE,YAAM,OAAO,wBAAwB,MAAM;AAC3C,aAAO,EAAE,aAAa,eAAe,IAAI,KAAK;AAAA,IAChD;AAAA,IACA,MAAM,QAAQ,MAAM;AAClB,aAAO,qBAAqBA,WAAU,IAAI;AAAA,IAC5C;AAAA,EACF;AACA,SAAO;AACT;;;AFVA,SAAS,eAAe,QAAQ,aAAa;;;AGb7C,SAAS,WAAW;AAEpB,OAAO,YAAY;AACnB,OAAO,aAAa;AACpB,SAAS,aAAa;AACtB,SAAS,cAAc,2BAAAC,gCAA+B;AAEtD,SAAS,uBAAuB;AAUzB,SAAS,UAAU,EAAE,UAAAC,WAAU,uBAAuB,MAAM,GAAsB;AACvF,QAAM,SAAS,IAAI,OAAO;AAE1B,SAAO,IAAI,aAAa,SAAS,GAAG,OAAO,QAAQ;AACjD,UAAM,YAAY,gBAAgB,aAAa;AAE/C,QAAI;AAEJ,QAAI;AACF,gBAAU,MAAM,MAAM,OAAO,IAAI,MAAM,UAAU,WAAW,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC;AAAA,IAC9F,SAAS,OAAO;AACd,UAAI,SAAS;AACb,UAAI,OAAO,KAAK,UAAU,KAAK;AAC/B,YAAM,KAAK;AACX;AAAA,IACF;AAEA,QAAI;AACF,cAAQ,UAAU,QAAQ,QAAQ,SAAS,IAAI,CAAC,GAAG,QAAQ,SAAS,EAAE,SAAS,aAAa,QAAQ,CAAC,IAAI,CAAC;AAC1G,gBAAU,cAAc;AACxB,YAAM,EAAE,aAAa,OAAO,IAAI,qBAAqBA,WAAU,OAAO;AACtE,gBAAU,2BAA2B;AACrC,YAAM,OAAOC,yBAAwB,MAAM;AAC3C,gBAAU,yBAAyB;AAEnC,UAAI,OAAO,KAAK,UAAU,EAAE,aAAa,aAAa,SAAS,KAAK,MAAM,KAAK,CAAC;AAChF,UAAI,SAAS;AAAA,IACf,SAAS,OAAO;AACd,UAAI,SAAS;AACb,UAAI,OAAO,KAAK,UAAU,KAAK;AAC/B,YAAM,KAAK;AAAA,IACb;AAAA,EACF,CAAC;AAED,SAAO,KAAK,MAAM,OAAO,QAAQ;AAC/B,QAAI,CAAC,sBAAsB;AACzB,UAAI,SAAS;AACb,UAAI,OAAO,KAAK,UAAU,EAAE,OAAO,gCAAgC,CAAC;AACpE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,OAAO,CAAC;AACtE,UAAI,QAAQ,WAAW,GAAG;AACxB,YAAI,SAAS;AACb,YAAI,OAAO,KAAK,UAAU,EAAE,OAAO,sBAAsB,CAAC;AAC1D;AAAA,MACF;AAEA,YAAM,SAAS,CAAC;AAChB,iBAAW,EAAE,MAAM,KAAK,SAAS;AAC/B,cAAM,OAAOD,UAAS,IAAI,IAAI,IAAI,KAAK,CAAC;AACxC,YAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG;AACjC,gBAAM,IAAI,MAAM,sBAAsB;AAAA,QACxC;AAEA,YAAI,KAAK,WAAW,GAAG;AACrB,iBAAO,KAAK,CAAC,CAAC;AACd;AAAA,QACF;AAEA,YAAI,CAAC,KAAK,CAAC,GAAG;AACZ,gBAAM,IAAI,MAAM,kBAAkB;AAAA,QACpC;AAEA,cAAM,UAAU,OAAO,KAAK,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,IAAI,WAAW,KAAK,EAAE,EAAE,YAAY,CAAC;AACvF,cAAM,OAAO,KAAK,IAAI,CAAC,QAAQ,OAAO,OAAO,GAAG,EAAE,IAAI,CAAC,UAAU,OAAO,SAAS,KAAK,EAAE,CAAC;AACzF,eAAO,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;AAAA,MAChC;AAEA,UAAI,SAAS;AACb,UAAI,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,IACtC,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU;AAC9D,UAAI,SAAS;AACb,UAAI,OAAO,KAAK,UAAU,EAAE,OAAO,aAAa,CAAC;AAAA,IACnD;AAAA,EACF,CAAC;AAED,SAAO,QAAQ,CAAC,OAAO,OAAO,GAAG,OAAO,eAAe,CAAC,CAAC;AAC3D;;;AH5EA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,kBAAkB;AAErC,IAAM,MAAM;AAAA,EACV,EAAE;AAAA,IACA,EAAE,aAAa,kBAAkB,iBAAiB;AAAA,IAClD,EAAE,OAAO;AAAA,MACP,iBAAiB,EAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,MAChD,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,MAChC,yBAAyB,EACtB,OAAO,EACP,SAAS,EACT,QAAQ,OAAO,EACf,UAAU,CAAC,QAAQ,QAAQ,MAAM;AAAA,IACtC,CAAC;AAAA,EACH;AACF;AAEA,IAAM,gBAAgB,MAAM,iBAAiB,GAAG;AAEhD,IAAM,UAAU,MAAM,WAAW,aAAa,aAAa,CAAC;AAC5D,IAAM,WAAW,QAAQ,IAAI,SAAS,IAAI,eAAe,CAAC;AAE1D,IAAI,aAAa,IAAI;AAErB,eAAe,uBAQb;AAEA,MAAI;AACF,UAAM,qBAAqB,SAAS,OAAO,EAAE,KAAKE,WAAU,EAAE,MAAMC,IAAGD,YAAW,SAAS,OAAO,CAAC,EAAE,IAAI;AAEzG,UAAME,qBAAqE,mBAAmB,CAAC;AAC/F,WAAOA;AAAA,EACT,SAAS,OAAO;AAAA,EAEhB;AACF;AAEA,eAAe,6BAA0D;AACvE,QAAMA,qBAAoB,MAAM,qBAAqB;AACrD,SAAOA,oBAAmB,0BAA0B;AACtD;AAEA,eAAe,6BAA8C;AAC3D,QAAM,CAAC,yBAAyB,iBAAiB,IAAI,MAAM,QAAQ,IAAI;AAAA,IACrE,2BAA2B;AAAA,IAC3B,SAAS,aAAa,aAAa,GAAG,EAAE,UAAU,IAAI,iBAAiB,CAAC;AAAA,EAC1E,CAAC;AACD,SAAO,kBAAkB,UAAU,2BAA2B,CAAC;AACjE;AAEA,IAAM,oBAAoB,MAAM,qBAAqB;AACrD,IAAI,mBAAmB;AAErB,MAAI,kBAAkB,iBAAiB,eAAe;AACpD,YAAQ;AAAA,MACN;AAAA,MACA,kBAAkB;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,OAAG,aAAa,IAAI,eAAe;AAAA,EACrC,WAAW,kBAAkB,0BAA0B,MAAM;AAE3D,YAAQ,IAAI,8BAA8B,kBAAkB,yBAAyB,EAAE;AACvF,iBAAa,kBAAkB,yBAAyB;AAAA,EAC1D;AACF;AAEA,IAAM,EAAE,oBAAoB,iBAAiB,IAAI,MAAM,aAAa;AAAA,EAClE,GAAG;AAAA,EACH;AAAA,EACA,gBAAgB,IAAI;AAAA,EACpB;AAAA,EACA,eAAe,IAAI;AAAA,EACnB,SAAS,IAAI;AACf,CAAC;AAED,IAAI,aAAa;AACjB,cAAc,CAAC,oBAAoB,gBAAgB,CAAC,EACjD;AAAA,EACC;AAAA,IACE,CAAC,CAAC,mBAAmB,EAAE,aAAa,yBAAyB,CAAC,MAC5D,sBAAsB;AAAA,EAC1B;AAAA,EACA,MAAM;AACR,EACC,UAAU,MAAM;AACf,eAAa;AACb,UAAQ,IAAI,eAAe;AAC7B,CAAC;AAEH,IAAM,SAAS,IAAI,IAAI;AAEvB,IAAI,IAAI,YAAY;AAClB,SAAO,IAAI,OAAO,IAAI,UAAU,CAAC;AACnC;AAEA,OAAO,IAAI,KAAK,CAAC;AACjB,OAAO,IAAI,WAAW,CAAC;AACvB,OAAO;AAAA,EACL,YAAY;AAAA,IACV,SAAS,MAAM;AAAA,EACjB,CAAC;AACH;AACA,OAAO;AAAA,EACL,QAAQ;AAAA,IACN,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf;AAAA,IACA;AAAA,IACA,gBAAgB,IAAI;AAAA,EACtB,CAAC;AACH;AACA,OAAO,IAAI,WAAW,CAAC;AACvB,OAAO,IAAI,UAAU,EAAE,UAAU,sBAAsB,IAAI,wBAAwB,CAAC,CAAC;AAErF,OAAO;AAAA,EACL,oBAAoB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ,gBAAgB;AAAA,IACxB,eAAe,aAAa;AAAA,MAC1B,cAAc,MAAM,mBAAmB,QAAQ;AAAA,IACjD;AAAA,EACF,CAAC;AACH;AAEA,OAAO,OAAO,EAAE,MAAM,IAAI,MAAM,MAAM,IAAI,KAAK,CAAC;AAChD,QAAQ,IAAI,+CAA+C,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AAEjF,IAAI,IAAI,yBAAyB;AAC/B,UAAQ,KAAK,iDAA6B;AAC1C,UAAQ,KAAK,6BAA6B;AAC1C,UAAQ,KAAK,6BAA6B;AAC1C,UAAQ,KAAK,0BAA0B;AACvC,UAAQ,KAAK,iDAAiD;AAC9D,UAAQ,KAAK,iCAAiC;AAChD;","names":["eq","chainState","database","chainId","filter","database","tablesWithRecordsToLogs","database","tablesWithRecordsToLogs","chainState","eq","currentChainState"]}
@@ -19,7 +19,11 @@ function errorHandler() {
19
19
  } catch (err) {
20
20
  Sentry.withScope((scope) => {
21
21
  scope.addEventProcessor((event) => {
22
- return Sentry.addRequestDataToEvent(event, ctx.request);
22
+ return Sentry.addRequestDataToEvent(event, {
23
+ ...ctx.request,
24
+ body: ctx.request.body,
25
+ query: ctx.request.query
26
+ });
23
27
  });
24
28
  Sentry.captureException(err);
25
29
  });
@@ -33,10 +37,10 @@ function requestHandler() {
33
37
  const hub = Sentry.getCurrentHub();
34
38
  hub.configureScope(
35
39
  (scope) => scope.addEventProcessor(
36
- (event) => Sentry.addRequestDataToEvent(event, ctx.request, {
37
- include: {
38
- user: false
39
- }
40
+ (event) => Sentry.addRequestDataToEvent(event, {
41
+ ...ctx.request,
42
+ body: ctx.request.body,
43
+ query: ctx.request.query
40
44
  })
41
45
  )
42
46
  );
@@ -96,4 +100,4 @@ export {
96
100
  error,
97
101
  sentry
98
102
  };
99
- //# sourceMappingURL=chunk-ALQNRR4A.js.map
103
+ //# sourceMappingURL=chunk-6CTSQZFV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/koa-middleware/sentry.ts","../src/debug.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport { ProfilingIntegration } from \"@sentry/profiling-node\";\nimport { stripUrlQueryAndFragment } from \"@sentry/utils\";\nimport { debug } from \"../debug\";\nimport Koa from \"koa\";\nimport compose from \"koa-compose\";\n\nexport function errorHandler(): Koa.Middleware {\n return async function errorHandlerMiddleware(ctx, next) {\n try {\n await next();\n } catch (err) {\n Sentry.withScope((scope) => {\n scope.addEventProcessor((event) => {\n return Sentry.addRequestDataToEvent(event, {\n ...ctx.request,\n body: ctx.request.body as string | Record<string, unknown> | undefined,\n query: ctx.request.query as Record<string, unknown> | undefined,\n });\n });\n Sentry.captureException(err);\n });\n throw err;\n }\n };\n}\n\nexport function requestHandler(): Koa.Middleware {\n return async function requestHandlerMiddleware(ctx, next) {\n await Sentry.runWithAsyncContext(async () => {\n const hub = Sentry.getCurrentHub();\n hub.configureScope((scope) =>\n scope.addEventProcessor((event) =>\n Sentry.addRequestDataToEvent(event, {\n ...ctx.request,\n body: ctx.request.body as string | Record<string, unknown> | undefined,\n query: ctx.request.query as Record<string, unknown> | undefined,\n }),\n ),\n );\n await next();\n });\n };\n}\n\nexport function tracing(): Koa.Middleware {\n // creates a Sentry transaction per request\n return async function tracingMiddleware(ctx, next) {\n const reqMethod = (ctx.method || \"\").toUpperCase();\n const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);\n\n // Connect to trace of upstream app\n let traceparentData;\n if (ctx.request.get(\"sentry-trace\")) {\n traceparentData = Sentry.extractTraceparentData(ctx.request.get(\"sentry-trace\"));\n }\n\n const transaction = Sentry.startTransaction({\n name: `${reqMethod} ${reqUrl}`,\n op: \"http.server\",\n ...traceparentData,\n });\n\n ctx.__sentry_transaction = transaction;\n\n // We put the transaction on the scope so users can attach children to it\n Sentry.getCurrentHub().configureScope((scope) => {\n scope.setSpan(transaction);\n });\n\n ctx.res.on(\"finish\", () => {\n // Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction closes\n setImmediate(() => {\n // If you're using koa router, set the matched route as transaction name\n if (ctx._matchedRoute) {\n const mountPath = ctx.mountPath || \"\";\n transaction.setName(`${reqMethod} ${mountPath}${ctx._matchedRoute}`);\n }\n\n transaction.setHttpStatus(ctx.status);\n transaction.finish();\n });\n });\n\n await next();\n };\n}\n\nexport function sentry(dsn: string): Koa.Middleware {\n debug(\"Initializing Sentry\");\n Sentry.init({\n dsn,\n integrations: [\n // Automatically instrument Node.js libraries and frameworks\n ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),\n new ProfilingIntegration(),\n ],\n // Performance Monitoring\n tracesSampleRate: 1.0,\n // Set sampling rate for profiling - this is relative to tracesSampleRate\n profilesSampleRate: 1.0,\n });\n\n return compose([errorHandler(), requestHandler(), tracing()]);\n}\n","import createDebug from \"debug\";\n\nexport const debug = createDebug(\"mud:store-indexer\");\nexport const error = createDebug(\"mud:store-indexer\");\n\n// Pipe debug output to stdout instead of stderr\ndebug.log = console.debug.bind(console);\n\n// Pipe error output to stderr\nerror.log = console.error.bind(console);\n"],"mappings":";AAAA,YAAY,YAAY;AACxB,SAAS,4BAA4B;AACrC,SAAS,gCAAgC;;;ACFzC,OAAO,iBAAiB;AAEjB,IAAM,QAAQ,YAAY,mBAAmB;AAC7C,IAAM,QAAQ,YAAY,mBAAmB;AAGpD,MAAM,MAAM,QAAQ,MAAM,KAAK,OAAO;AAGtC,MAAM,MAAM,QAAQ,MAAM,KAAK,OAAO;;;ADJtC,OAAO,aAAa;AAEb,SAAS,eAA+B;AAC7C,SAAO,eAAe,uBAAuB,KAAK,MAAM;AACtD,QAAI;AACF,YAAM,KAAK;AAAA,IACb,SAAS,KAAK;AACZ,MAAO,iBAAU,CAAC,UAAU;AAC1B,cAAM,kBAAkB,CAAC,UAAU;AACjC,iBAAc,6BAAsB,OAAO;AAAA,YACzC,GAAG,IAAI;AAAA,YACP,MAAM,IAAI,QAAQ;AAAA,YAClB,OAAO,IAAI,QAAQ;AAAA,UACrB,CAAC;AAAA,QACH,CAAC;AACD,QAAO,wBAAiB,GAAG;AAAA,MAC7B,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,iBAAiC;AAC/C,SAAO,eAAe,yBAAyB,KAAK,MAAM;AACxD,UAAa,2BAAoB,YAAY;AAC3C,YAAM,MAAa,qBAAc;AACjC,UAAI;AAAA,QAAe,CAAC,UAClB,MAAM;AAAA,UAAkB,CAAC,UAChB,6BAAsB,OAAO;AAAA,YAClC,GAAG,IAAI;AAAA,YACP,MAAM,IAAI,QAAQ;AAAA,YAClB,OAAO,IAAI,QAAQ;AAAA,UACrB,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,KAAK;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAEO,SAAS,UAA0B;AAExC,SAAO,eAAe,kBAAkB,KAAK,MAAM;AACjD,UAAM,aAAa,IAAI,UAAU,IAAI,YAAY;AACjD,UAAM,SAAS,IAAI,OAAO,yBAAyB,IAAI,GAAG;AAG1D,QAAI;AACJ,QAAI,IAAI,QAAQ,IAAI,cAAc,GAAG;AACnC,wBAAyB,8BAAuB,IAAI,QAAQ,IAAI,cAAc,CAAC;AAAA,IACjF;AAEA,UAAM,cAAqB,wBAAiB;AAAA,MAC1C,MAAM,GAAG,SAAS,IAAI,MAAM;AAAA,MAC5B,IAAI;AAAA,MACJ,GAAG;AAAA,IACL,CAAC;AAED,QAAI,uBAAuB;AAG3B,IAAO,qBAAc,EAAE,eAAe,CAAC,UAAU;AAC/C,YAAM,QAAQ,WAAW;AAAA,IAC3B,CAAC;AAED,QAAI,IAAI,GAAG,UAAU,MAAM;AAEzB,mBAAa,MAAM;AAEjB,YAAI,IAAI,eAAe;AACrB,gBAAM,YAAY,IAAI,aAAa;AACnC,sBAAY,QAAQ,GAAG,SAAS,IAAI,SAAS,GAAG,IAAI,aAAa,EAAE;AAAA,QACrE;AAEA,oBAAY,cAAc,IAAI,MAAM;AACpC,oBAAY,OAAO;AAAA,MACrB,CAAC;AAAA,IACH,CAAC;AAED,UAAM,KAAK;AAAA,EACb;AACF;AAEO,SAAS,OAAO,KAA6B;AAClD,QAAM,qBAAqB;AAC3B,EAAO,YAAK;AAAA,IACV;AAAA,IACA,cAAc;AAAA;AAAA,MAEZ,GAAU,yDAAkD;AAAA,MAC5D,IAAI,qBAAqB;AAAA,IAC3B;AAAA;AAAA,IAEA,kBAAkB;AAAA;AAAA,IAElB,oBAAoB;AAAA,EACtB,CAAC;AAED,SAAO,QAAQ,CAAC,aAAa,GAAG,eAAe,GAAG,QAAQ,CAAC,CAAC;AAC9D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/store-indexer",
3
- "version": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f",
3
+ "version": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545",
4
4
  "description": "Minimal Typescript indexer for Store",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,12 +37,14 @@
37
37
  "@sentry/utils": "^7.86.0",
38
38
  "@trpc/client": "10.34.0",
39
39
  "@trpc/server": "10.34.0",
40
+ "@types/koa-bodyparser": "^4.3.12",
40
41
  "accepts": "^1.3.8",
41
42
  "better-sqlite3": "^8.6.0",
42
43
  "debug": "^4.3.4",
43
44
  "dotenv": "^16.0.3",
44
45
  "drizzle-orm": "^0.28.5",
45
46
  "koa": "^2.15.4",
47
+ "koa-bodyparser": "^4.4.1",
46
48
  "koa-compose": "^4.1.0",
47
49
  "postgres": "3.3.5",
48
50
  "prom-client": "^15.1.2",
@@ -50,11 +52,11 @@
50
52
  "superjson": "^1.12.4",
51
53
  "trpc-koa-adapter": "^1.1.3",
52
54
  "zod": "3.23.8",
53
- "@latticexyz/block-logs-stream": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f",
54
- "@latticexyz/common": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f",
55
- "@latticexyz/protocol-parser": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f",
56
- "@latticexyz/store": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f",
57
- "@latticexyz/store-sync": "2.2.22-d83a0fd5283b7bea7e9a5372ea3c45ab9aea350f"
55
+ "@latticexyz/block-logs-stream": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545",
56
+ "@latticexyz/common": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545",
57
+ "@latticexyz/protocol-parser": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545",
58
+ "@latticexyz/store": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545",
59
+ "@latticexyz/store-sync": "2.2.22-f0c0b982573f9953e1c726c0bef91671efaaa545"
58
60
  },
59
61
  "devDependencies": {
60
62
  "@types/accepts": "^1.3.7",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/koa-middleware/sentry.ts","../src/debug.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport { ProfilingIntegration } from \"@sentry/profiling-node\";\nimport { stripUrlQueryAndFragment } from \"@sentry/utils\";\nimport { debug } from \"../debug\";\nimport Koa from \"koa\";\nimport compose from \"koa-compose\";\n\nexport function errorHandler(): Koa.Middleware {\n return async function errorHandlerMiddleware(ctx, next) {\n try {\n await next();\n } catch (err) {\n Sentry.withScope((scope) => {\n scope.addEventProcessor((event) => {\n return Sentry.addRequestDataToEvent(event, ctx.request);\n });\n Sentry.captureException(err);\n });\n throw err;\n }\n };\n}\n\nexport function requestHandler(): Koa.Middleware {\n return async function requestHandlerMiddleware(ctx, next) {\n await Sentry.runWithAsyncContext(async () => {\n const hub = Sentry.getCurrentHub();\n hub.configureScope((scope) =>\n scope.addEventProcessor((event) =>\n Sentry.addRequestDataToEvent(event, ctx.request, {\n include: {\n user: false,\n },\n }),\n ),\n );\n await next();\n });\n };\n}\n\nexport function tracing(): Koa.Middleware {\n // creates a Sentry transaction per request\n return async function tracingMiddleware(ctx, next) {\n const reqMethod = (ctx.method || \"\").toUpperCase();\n const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);\n\n // Connect to trace of upstream app\n let traceparentData;\n if (ctx.request.get(\"sentry-trace\")) {\n traceparentData = Sentry.extractTraceparentData(ctx.request.get(\"sentry-trace\"));\n }\n\n const transaction = Sentry.startTransaction({\n name: `${reqMethod} ${reqUrl}`,\n op: \"http.server\",\n ...traceparentData,\n });\n\n ctx.__sentry_transaction = transaction;\n\n // We put the transaction on the scope so users can attach children to it\n Sentry.getCurrentHub().configureScope((scope) => {\n scope.setSpan(transaction);\n });\n\n ctx.res.on(\"finish\", () => {\n // Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction closes\n setImmediate(() => {\n // If you're using koa router, set the matched route as transaction name\n if (ctx._matchedRoute) {\n const mountPath = ctx.mountPath || \"\";\n transaction.setName(`${reqMethod} ${mountPath}${ctx._matchedRoute}`);\n }\n\n transaction.setHttpStatus(ctx.status);\n transaction.finish();\n });\n });\n\n await next();\n };\n}\n\nexport function sentry(dsn: string): Koa.Middleware {\n debug(\"Initializing Sentry\");\n Sentry.init({\n dsn,\n integrations: [\n // Automatically instrument Node.js libraries and frameworks\n ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),\n new ProfilingIntegration(),\n ],\n // Performance Monitoring\n tracesSampleRate: 1.0,\n // Set sampling rate for profiling - this is relative to tracesSampleRate\n profilesSampleRate: 1.0,\n });\n\n return compose([errorHandler(), requestHandler(), tracing()]);\n}\n","import createDebug from \"debug\";\n\nexport const debug = createDebug(\"mud:store-indexer\");\nexport const error = createDebug(\"mud:store-indexer\");\n\n// Pipe debug output to stdout instead of stderr\ndebug.log = console.debug.bind(console);\n\n// Pipe error output to stderr\nerror.log = console.error.bind(console);\n"],"mappings":";AAAA,YAAY,YAAY;AACxB,SAAS,4BAA4B;AACrC,SAAS,gCAAgC;;;ACFzC,OAAO,iBAAiB;AAEjB,IAAM,QAAQ,YAAY,mBAAmB;AAC7C,IAAM,QAAQ,YAAY,mBAAmB;AAGpD,MAAM,MAAM,QAAQ,MAAM,KAAK,OAAO;AAGtC,MAAM,MAAM,QAAQ,MAAM,KAAK,OAAO;;;ADJtC,OAAO,aAAa;AAEb,SAAS,eAA+B;AAC7C,SAAO,eAAe,uBAAuB,KAAK,MAAM;AACtD,QAAI;AACF,YAAM,KAAK;AAAA,IACb,SAAS,KAAK;AACZ,MAAO,iBAAU,CAAC,UAAU;AAC1B,cAAM,kBAAkB,CAAC,UAAU;AACjC,iBAAc,6BAAsB,OAAO,IAAI,OAAO;AAAA,QACxD,CAAC;AACD,QAAO,wBAAiB,GAAG;AAAA,MAC7B,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,iBAAiC;AAC/C,SAAO,eAAe,yBAAyB,KAAK,MAAM;AACxD,UAAa,2BAAoB,YAAY;AAC3C,YAAM,MAAa,qBAAc;AACjC,UAAI;AAAA,QAAe,CAAC,UAClB,MAAM;AAAA,UAAkB,CAAC,UAChB,6BAAsB,OAAO,IAAI,SAAS;AAAA,YAC/C,SAAS;AAAA,cACP,MAAM;AAAA,YACR;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,KAAK;AAAA,IACb,CAAC;AAAA,EACH;AACF;AAEO,SAAS,UAA0B;AAExC,SAAO,eAAe,kBAAkB,KAAK,MAAM;AACjD,UAAM,aAAa,IAAI,UAAU,IAAI,YAAY;AACjD,UAAM,SAAS,IAAI,OAAO,yBAAyB,IAAI,GAAG;AAG1D,QAAI;AACJ,QAAI,IAAI,QAAQ,IAAI,cAAc,GAAG;AACnC,wBAAyB,8BAAuB,IAAI,QAAQ,IAAI,cAAc,CAAC;AAAA,IACjF;AAEA,UAAM,cAAqB,wBAAiB;AAAA,MAC1C,MAAM,GAAG,SAAS,IAAI,MAAM;AAAA,MAC5B,IAAI;AAAA,MACJ,GAAG;AAAA,IACL,CAAC;AAED,QAAI,uBAAuB;AAG3B,IAAO,qBAAc,EAAE,eAAe,CAAC,UAAU;AAC/C,YAAM,QAAQ,WAAW;AAAA,IAC3B,CAAC;AAED,QAAI,IAAI,GAAG,UAAU,MAAM;AAEzB,mBAAa,MAAM;AAEjB,YAAI,IAAI,eAAe;AACrB,gBAAM,YAAY,IAAI,aAAa;AACnC,sBAAY,QAAQ,GAAG,SAAS,IAAI,SAAS,GAAG,IAAI,aAAa,EAAE;AAAA,QACrE;AAEA,oBAAY,cAAc,IAAI,MAAM;AACpC,oBAAY,OAAO;AAAA,MACrB,CAAC;AAAA,IACH,CAAC;AAED,UAAM,KAAK;AAAA,EACb;AACF;AAEO,SAAS,OAAO,KAA6B;AAClD,QAAM,qBAAqB;AAC3B,EAAO,YAAK;AAAA,IACV;AAAA,IACA,cAAc;AAAA;AAAA,MAEZ,GAAU,yDAAkD;AAAA,MAC5D,IAAI,qBAAqB;AAAA,IAC3B;AAAA;AAAA,IAEA,kBAAkB;AAAA;AAAA,IAElB,oBAAoB;AAAA,EACtB,CAAC;AAED,SAAO,QAAQ,CAAC,aAAa,GAAG,eAAe,GAAG,QAAQ,CAAC,CAAC;AAC9D;","names":[]}