@latticexyz/store-indexer 2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da → 2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401

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,44 @@ 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
+
114
+ // src/sqlite/formatSqlQuery.ts
115
+ import sqlParser from "node-sql-parser";
116
+ function formatSqlQuery(sqlQuery) {
117
+ const parser = new sqlParser.Parser();
118
+ const ast = parser.astify(sqlQuery);
119
+ updateNode(ast);
120
+ return parser.sqlify(ast, { database: "sqlite" });
121
+ }
122
+ function updateNode(node) {
123
+ if (Array.isArray(node)) {
124
+ node.forEach((item) => updateNode(item));
125
+ return;
126
+ }
127
+ if (node && typeof node === "object") {
128
+ const astNode = node;
129
+ if (astNode.type === "column_ref" && typeof astNode.column === "string" && /^[a-z]+[A-Z][a-z]*$/.test(astNode.column)) {
130
+ astNode.column = camelToSnakeCase(astNode.column);
131
+ }
132
+ for (const [, value] of Object.entries(astNode)) {
133
+ if (typeof value === "object" && value !== null) {
134
+ updateNode(value);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ function camelToSnakeCase(str) {
140
+ return str.replace(/([a-z]+)([A-Z][a-z]*)/g, "$1_$2").toLowerCase();
141
+ }
142
+
143
+ // src/sqlite/apiRoutes.ts
144
+ function apiRoutes({ database: database2, enableUnsafeQueryApi = false }) {
112
145
  const router = new Router();
113
146
  router.get("/api/logs", compress(), async (ctx) => {
114
147
  const benchmark = createBenchmark("sqlite:logs");
@@ -136,6 +169,45 @@ function apiRoutes(database2) {
136
169
  debug(error);
137
170
  }
138
171
  });
172
+ router.post("/q", async (ctx) => {
173
+ if (!enableUnsafeQueryApi) {
174
+ ctx.status = 404;
175
+ ctx.body = JSON.stringify({ error: "Query endpoint is not enabled" });
176
+ return;
177
+ }
178
+ try {
179
+ const queries = Array.isArray(ctx.request.body) ? ctx.request.body : [];
180
+ if (queries.length === 0) {
181
+ ctx.status = 400;
182
+ ctx.body = JSON.stringify({ error: "No queries provided" });
183
+ return;
184
+ }
185
+ const result = [];
186
+ for (const { query } of queries) {
187
+ const formattedQuery = formatSqlQuery(query);
188
+ const data = database2.all(sql.raw(formattedQuery));
189
+ if (!data || !Array.isArray(data)) {
190
+ throw new Error("Invalid query result");
191
+ }
192
+ if (data.length === 0) {
193
+ result.push([]);
194
+ continue;
195
+ }
196
+ if (!data[0]) {
197
+ throw new Error("Invalid row data");
198
+ }
199
+ const columns = Object.keys(data[0]).map((key) => key.replaceAll("_", "").toLowerCase());
200
+ const rows = data.map((row) => Object.values(row).map((value) => value?.toString() ?? ""));
201
+ result.push([columns, ...rows]);
202
+ }
203
+ ctx.status = 200;
204
+ ctx.body = JSON.stringify({ result });
205
+ } catch (error) {
206
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
207
+ ctx.status = 400;
208
+ ctx.body = JSON.stringify({ error: errorMessage });
209
+ }
210
+ });
139
211
  return compose([router.routes(), router.allowedMethods()]);
140
212
  }
141
213
 
@@ -147,7 +219,8 @@ var env = parseEnv(
147
219
  z.intersection(indexerEnvSchema, frontendEnvSchema),
148
220
  z.object({
149
221
  SQLITE_FILENAME: z.string().default("indexer.db"),
150
- SENTRY_DSN: z.string().optional()
222
+ SENTRY_DSN: z.string().optional(),
223
+ ENABLE_UNSAFE_QUERY_API: z.string().optional().default("false").transform((val) => val === "true")
151
224
  })
152
225
  )
153
226
  );
@@ -213,6 +286,7 @@ if (env.SENTRY_DSN) {
213
286
  server.use(sentry(env.SENTRY_DSN));
214
287
  }
215
288
  server.use(cors());
289
+ server.use(bodyParser());
216
290
  server.use(
217
291
  healthcheck({
218
292
  isReady: () => isCaughtUp
@@ -228,7 +302,7 @@ server.use(
228
302
  })
229
303
  );
230
304
  server.use(helloWorld());
231
- server.use(apiRoutes(database));
305
+ server.use(apiRoutes({ database, enableUnsafeQueryApi: env.ENABLE_UNSAFE_QUERY_API }));
232
306
  server.use(
233
307
  createKoaMiddleware({
234
308
  prefix: "/trpc",
@@ -240,4 +314,12 @@ server.use(
240
314
  );
241
315
  server.listen({ host: env.HOST, port: env.PORT });
242
316
  console.log(`sqlite indexer frontend listening on http://${env.HOST}:${env.PORT}`);
317
+ if (env.ENABLE_UNSAFE_QUERY_API) {
318
+ console.warn("\n\n\u26A0\uFE0F SECURITY WARNING \u26A0\uFE0F");
319
+ console.warn("=========================\n");
320
+ console.warn("UNSAFE QUERY API IS ENABLED");
321
+ console.warn("DO NOT USE IN PRODUCTION");
322
+ console.warn("This will expose your database to public access");
323
+ console.warn("\n=========================\n\n");
324
+ }
243
325
  //# 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","../../src/sqlite/formatSqlQuery.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\";\nimport { formatSqlQuery } from \"./formatSqlQuery\";\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 formattedQuery = formatSqlQuery(query);\n const data = database.all(sql.raw(formattedQuery)) 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","import sqlParser from \"node-sql-parser\";\n\ntype AstNode = {\n type?: string;\n [key: string]: unknown;\n};\n\n/**\n * Transforms camelCase identifiers to snake_case in SQL queries\n *\n * @param sqlQuery The SQL query to transform\n * @returns The transformed SQL query\n */\nexport function formatSqlQuery(sqlQuery: string): string {\n const parser = new sqlParser.Parser();\n const ast = parser.astify(sqlQuery);\n\n updateNode(ast);\n\n return parser.sqlify(ast, { database: \"sqlite\" });\n}\n\nfunction updateNode(node: unknown): void {\n if (Array.isArray(node)) {\n node.forEach((item) => updateNode(item));\n return;\n }\n\n if (node && typeof node === \"object\") {\n const astNode = node as AstNode;\n\n if (\n astNode.type === \"column_ref\" &&\n typeof astNode.column === \"string\" &&\n /^[a-z]+[A-Z][a-z]*$/.test(astNode.column)\n ) {\n astNode.column = camelToSnakeCase(astNode.column);\n }\n\n for (const [, value] of Object.entries(astNode)) {\n if (typeof value === \"object\" && value !== null) {\n updateNode(value);\n }\n }\n }\n}\n\nfunction camelToSnakeCase(str: string): string {\n return str.replace(/([a-z]+)([A-Z][a-z]*)/g, \"$1_$2\").toLowerCase();\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;;;ACRhC,OAAO,eAAe;AAaf,SAAS,eAAe,UAA0B;AACvD,QAAM,SAAS,IAAI,UAAU,OAAO;AACpC,QAAM,MAAM,OAAO,OAAO,QAAQ;AAElC,aAAW,GAAG;AAEd,SAAO,OAAO,OAAO,KAAK,EAAE,UAAU,SAAS,CAAC;AAClD;AAEA,SAAS,WAAW,MAAqB;AACvC,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,SAAK,QAAQ,CAAC,SAAS,WAAW,IAAI,CAAC;AACvC;AAAA,EACF;AAEA,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,UAAM,UAAU;AAEhB,QACE,QAAQ,SAAS,gBACjB,OAAO,QAAQ,WAAW,YAC1B,sBAAsB,KAAK,QAAQ,MAAM,GACzC;AACA,cAAQ,SAAS,iBAAiB,QAAQ,MAAM;AAAA,IAClD;AAEA,eAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC/C,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,SAAO,IAAI,QAAQ,0BAA0B,OAAO,EAAE,YAAY;AACpE;;;AD9BO,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,iBAAiB,eAAe,KAAK;AAC3C,cAAM,OAAOD,UAAS,IAAI,IAAI,IAAI,cAAc,CAAC;AACjD,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;;;AH9EA,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-fb2745a7b2d4735a67adffa69e70ec7d1085f4da",
3
+ "version": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401",
4
4
  "description": "Minimal Typescript indexer for Store",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,24 +37,27 @@
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",
49
+ "node-sql-parser": "^5.3.3",
47
50
  "postgres": "3.3.5",
48
51
  "prom-client": "^15.1.2",
49
52
  "rxjs": "7.5.5",
50
53
  "superjson": "^1.12.4",
51
54
  "trpc-koa-adapter": "^1.1.3",
52
55
  "zod": "3.23.8",
53
- "@latticexyz/block-logs-stream": "2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da",
54
- "@latticexyz/common": "2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da",
55
- "@latticexyz/protocol-parser": "2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da",
56
- "@latticexyz/store": "2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da",
57
- "@latticexyz/store-sync": "2.2.22-fb2745a7b2d4735a67adffa69e70ec7d1085f4da"
56
+ "@latticexyz/block-logs-stream": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401",
57
+ "@latticexyz/common": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401",
58
+ "@latticexyz/protocol-parser": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401",
59
+ "@latticexyz/store": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401",
60
+ "@latticexyz/store-sync": "2.2.22-fbf1be12730c08acd460aa36124a0565f4e73401"
58
61
  },
59
62
  "devDependencies": {
60
63
  "@types/accepts": "^1.3.7",
@@ -89,7 +92,7 @@
89
92
  "start:sqlite": "tsx src/bin/sqlite-indexer",
90
93
  "start:sqlite:local": "SQLITE_FILENAME=anvil.db RPC_HTTP_URL=http://127.0.0.1:8545 pnpm start:sqlite",
91
94
  "start:sqlite:testnet": "SQLITE_FILENAME=testnet.db RPC_HTTP_URL=https://rpc.holesky.redstone.xyz pnpm start:sqlite",
92
- "test": "tsc --noEmit",
95
+ "test": "tsc --noEmit && vitest --run --passWithNoTests",
93
96
  "test:ci": "pnpm run test"
94
97
  }
95
98
  }
@@ -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":[]}