@thru/indexer 0.2.20 → 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,8 @@
1
1
  import { pgTable, timestamp, text, bigint, boolean, integer, index } from 'drizzle-orm/pg-core';
2
- import { z as z$1 } from 'zod';
2
+ import { z } from 'zod';
3
3
  import { createConsoleLogger, createEventReplay, createAccountsByOwnerReplay, AccountView } from '@thru/replay';
4
- import { eq, getTableColumns, sql, gte, lte, desc, and } from 'drizzle-orm';
5
- import { encodeAddress } from '@thru/helpers';
6
- import { z, OpenAPIHono, createRoute } from '@hono/zod-openapi';
7
- import { createSelectSchema, createInsertSchema } from 'drizzle-zod';
4
+ import { eq, sql } from 'drizzle-orm';
5
+ import { encodeAddress } from '@thru/sdk/helpers';
8
6
 
9
7
  // src/schema/builder.ts
10
8
  function createBuilder(state) {
@@ -162,29 +160,29 @@ function generateZodSchema(schema) {
162
160
  let zodType;
163
161
  switch (colDef._columnType) {
164
162
  case "text":
165
- zodType = z$1.string();
163
+ zodType = z.string();
166
164
  break;
167
165
  case "bigint":
168
- zodType = z$1.bigint();
166
+ zodType = z.bigint();
169
167
  break;
170
168
  case "integer":
171
- zodType = z$1.number().int();
169
+ zodType = z.number().int();
172
170
  break;
173
171
  case "boolean":
174
- zodType = z$1.boolean();
172
+ zodType = z.boolean();
175
173
  break;
176
174
  case "timestamp":
177
- zodType = z$1.date();
175
+ zodType = z.date();
178
176
  break;
179
177
  default:
180
- zodType = z$1.unknown();
178
+ zodType = z.unknown();
181
179
  }
182
180
  if (colDef._nullable) {
183
181
  zodType = zodType.nullable();
184
182
  }
185
183
  shape[key] = zodType;
186
184
  }
187
- return z$1.object(shape);
185
+ return z.object(shape);
188
186
  }
189
187
  function validateParsedData(schema, data, streamName) {
190
188
  const zodSchema = generateZodSchema(schema);
@@ -192,7 +190,7 @@ function validateParsedData(schema, data, streamName) {
192
190
  if (result.success) {
193
191
  return { success: true, data: result.data };
194
192
  }
195
- const errorMessages = result.error.errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
193
+ const errorMessages = result.error.issues.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
196
194
  return {
197
195
  success: false,
198
196
  error: `Stream "${streamName}" parse returned invalid data:
@@ -287,18 +285,18 @@ async function getAllCheckpoints(db) {
287
285
  // src/checkpoint/index.ts
288
286
  function getSchemaExports(config) {
289
287
  const { eventStreams = [], accountStreams = [], tableNames = {} } = config;
290
- const exports$1 = {
288
+ const exports = {
291
289
  checkpointTable
292
290
  };
293
291
  for (const stream of eventStreams) {
294
292
  const exportName = tableNames[stream.name] ?? `${stream.name}Table`;
295
- exports$1[exportName] = stream.table;
293
+ exports[exportName] = stream.table;
296
294
  }
297
295
  for (const stream of accountStreams) {
298
296
  const exportName = tableNames[stream.name] ?? `${stream.name.replace(/-/g, "")}Table`;
299
- exports$1[exportName] = stream.table;
297
+ exports[exportName] = stream.table;
300
298
  }
301
- return exports$1;
299
+ return exports;
302
300
  }
303
301
 
304
302
  // src/streams/processor.ts
@@ -742,297 +740,6 @@ async function runAccountStreamProcessor(stream, options, abortSignal) {
742
740
  );
743
741
  return stats;
744
742
  }
745
- var paginationQuerySchema = z.object({
746
- limit: z.coerce.number().int().min(1).max(100).default(20).openapi({
747
- description: "Number of results to return (1-100)",
748
- example: 20
749
- }),
750
- offset: z.coerce.number().int().min(0).default(0).openapi({
751
- description: "Number of results to skip",
752
- example: 0
753
- }),
754
- cursor: z.string().optional().openapi({
755
- description: "Cursor for pagination (format: slot:id)",
756
- example: "3181195:abc123"
757
- })
758
- });
759
- var paginationResponseSchema = z.object({
760
- limit: z.number().openapi({ example: 20 }),
761
- offset: z.number().openapi({ example: 0 }),
762
- hasMore: z.boolean().openapi({ example: true }),
763
- nextCursor: z.string().nullable().openapi({ example: "3181195:abc123" })
764
- });
765
- function dataResponse(schema) {
766
- return z.object({ data: schema });
767
- }
768
- function listResponse(schema) {
769
- return z.object({
770
- data: z.array(schema),
771
- pagination: paginationResponseSchema
772
- });
773
- }
774
- var errorSchema = z.object({
775
- error: z.string().openapi({ example: "Not found" }),
776
- code: z.string().optional().openapi({ example: "NOT_FOUND" })
777
- }).openapi("Error");
778
- function paginate(rows, query, getCursor) {
779
- const hasMore = rows.length > query.limit;
780
- const data = hasMore ? rows.slice(0, -1) : rows;
781
- const lastItem = data[data.length - 1];
782
- let nextCursor = null;
783
- if (hasMore && lastItem) {
784
- if (getCursor) {
785
- nextCursor = getCursor(lastItem);
786
- } else {
787
- const item = lastItem;
788
- if (item.slot !== void 0 && item.id !== void 0) {
789
- nextCursor = `${item.slot}:${item.id}`;
790
- }
791
- }
792
- }
793
- return {
794
- data,
795
- pagination: {
796
- limit: query.limit,
797
- offset: query.offset,
798
- hasMore,
799
- nextCursor
800
- }
801
- };
802
- }
803
- function parseCursor(cursor) {
804
- const colonIndex = cursor.indexOf(":");
805
- if (colonIndex === -1) return null;
806
- try {
807
- const slot = BigInt(cursor.slice(0, colonIndex));
808
- const id = cursor.slice(colonIndex + 1);
809
- return { slot, id };
810
- } catch {
811
- return null;
812
- }
813
- }
814
- function pascalCase3(str) {
815
- return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
816
- }
817
- function generateSchemas(table, name, suffix = "") {
818
- const rowSchema = createSelectSchema(table);
819
- const insertSchema = createInsertSchema(table);
820
- const apiFields = {};
821
- const columns = getTableColumns(table);
822
- for (const [colName, col] of Object.entries(columns)) {
823
- const dataType = col.dataType;
824
- const notNull = col.notNull;
825
- let fieldSchema;
826
- switch (dataType) {
827
- case "bigint":
828
- fieldSchema = z.string().openapi({ description: `${colName} (bigint)` });
829
- break;
830
- case "date":
831
- fieldSchema = z.string().openapi({ description: `${colName} (ISO timestamp)` });
832
- break;
833
- case "string":
834
- fieldSchema = z.string();
835
- break;
836
- case "number":
837
- fieldSchema = z.number();
838
- break;
839
- case "boolean":
840
- fieldSchema = z.boolean();
841
- break;
842
- default:
843
- fieldSchema = z.any();
844
- }
845
- if (!notNull) {
846
- fieldSchema = fieldSchema.nullable();
847
- }
848
- apiFields[colName] = fieldSchema;
849
- }
850
- const schemaName = suffix ? `${pascalCase3(name)}${suffix}` : pascalCase3(name);
851
- const apiSchema = z.object(apiFields).openapi(schemaName);
852
- const serialize = (row) => {
853
- const result = {};
854
- for (const [key, value] of Object.entries(row)) {
855
- if (typeof value === "bigint") {
856
- result[key] = value.toString();
857
- } else if (value instanceof Date) {
858
- result[key] = value.toISOString();
859
- } else {
860
- result[key] = value;
861
- }
862
- }
863
- return result;
864
- };
865
- return {
866
- row: rowSchema,
867
- insert: insertSchema,
868
- api: apiSchema,
869
- serialize
870
- };
871
- }
872
-
873
- // src/api/routes.ts
874
- function pascalCase4(str) {
875
- return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
876
- }
877
- function buildRoutes(config) {
878
- const {
879
- db,
880
- name,
881
- table,
882
- schemas,
883
- filters,
884
- idField,
885
- resourceType,
886
- includeSlotFilters,
887
- sortField,
888
- secondarySortField
889
- } = config;
890
- const router = new OpenAPIHono();
891
- const tag = pascalCase4(name);
892
- const filterFields = {};
893
- for (const field of filters) {
894
- filterFields[field] = z.string().optional().openapi({
895
- description: `Filter by ${field}`
896
- });
897
- }
898
- if (includeSlotFilters) {
899
- filterFields.fromSlot = z.string().optional().openapi({
900
- description: "Minimum slot number"
901
- });
902
- filterFields.toSlot = z.string().optional().openapi({
903
- description: "Maximum slot number"
904
- });
905
- }
906
- const listQuerySchema = paginationQuerySchema.extend(filterFields);
907
- const listRoute = createRoute({
908
- method: "get",
909
- path: "/",
910
- tags: [tag],
911
- summary: `List ${name} ${resourceType}s`,
912
- description: `Returns a paginated list of ${name} ${resourceType}s with optional filtering.`,
913
- request: { query: listQuerySchema },
914
- responses: {
915
- 200: {
916
- description: `List of ${name} ${resourceType}s`,
917
- content: { "application/json": { schema: listResponse(schemas.api) } }
918
- }
919
- }
920
- });
921
- router.openapi(listRoute, async (c) => {
922
- const query = c.req.valid("query");
923
- const conditions = [];
924
- for (const field of filters) {
925
- const value = query[field];
926
- if (value !== void 0 && value !== "") {
927
- conditions.push(eq(table[field], value));
928
- }
929
- }
930
- if (includeSlotFilters) {
931
- if (query.fromSlot) {
932
- conditions.push(gte(table.slot, BigInt(query.fromSlot)));
933
- }
934
- if (query.toSlot) {
935
- conditions.push(lte(table.slot, BigInt(query.toSlot)));
936
- }
937
- }
938
- if (query.cursor && secondarySortField) {
939
- const parsed = parseCursor(query.cursor);
940
- if (parsed) {
941
- conditions.push(
942
- sql`(${table.slot} < ${parsed.slot} OR (${table.slot} = ${parsed.slot} AND ${table[secondarySortField]} < ${parsed.id}))`
943
- );
944
- }
945
- }
946
- const orderBy = secondarySortField ? [desc(table[sortField]), desc(table[secondarySortField])] : [desc(table[sortField])];
947
- const rows = await db.select().from(table).where(conditions.length > 0 ? and(...conditions) : void 0).orderBy(...orderBy).limit(query.limit + 1).offset(query.cursor ? 0 : query.offset);
948
- const result = paginate(rows, query);
949
- return c.json({
950
- data: result.data.map(
951
- (row) => schemas.serialize(row)
952
- ),
953
- pagination: result.pagination
954
- });
955
- });
956
- const getRoute = createRoute({
957
- method: "get",
958
- path: `/{${idField}}`,
959
- tags: [tag],
960
- summary: `Get ${name} ${resourceType} by ${idField}`,
961
- description: `Returns a single ${name} ${resourceType} by its ${idField}.`,
962
- request: {
963
- params: z.object({
964
- [idField]: z.string().openapi({ description: `${pascalCase4(resourceType)} ${idField}` })
965
- })
966
- },
967
- responses: {
968
- 200: {
969
- description: `${pascalCase4(name)} ${resourceType} found`,
970
- content: { "application/json": { schema: dataResponse(schemas.api) } }
971
- },
972
- 404: {
973
- description: `${pascalCase4(resourceType)} not found`,
974
- content: { "application/json": { schema: errorSchema } }
975
- }
976
- }
977
- });
978
- router.openapi(getRoute, async (c) => {
979
- const id = c.req.param(idField);
980
- const [row] = await db.select().from(table).where(eq(table[idField], id)).limit(1);
981
- if (!row) {
982
- return c.json({ error: "Not found" }, 404);
983
- }
984
- return c.json({
985
- data: schemas.serialize(row)
986
- });
987
- });
988
- return router;
989
- }
990
- function mountStreamRoutes(app, options) {
991
- const {
992
- db,
993
- eventStreams = [],
994
- accountStreams = [],
995
- pathPrefix = "/api/v1"
996
- } = options;
997
- for (const stream of eventStreams) {
998
- if (stream.api?.enabled === false) continue;
999
- const schemas = generateSchemas(stream.table, stream.name, "Event");
1000
- const filters = stream.api?.filters ?? [];
1001
- const idField = stream.api?.idField ?? "id";
1002
- const router = buildRoutes({
1003
- db,
1004
- name: stream.name,
1005
- table: stream.table,
1006
- schemas,
1007
- filters,
1008
- idField,
1009
- resourceType: "event",
1010
- includeSlotFilters: true,
1011
- sortField: "slot",
1012
- secondarySortField: "id"
1013
- });
1014
- app.route(`${pathPrefix}/${stream.name}`, router);
1015
- }
1016
- for (const stream of accountStreams) {
1017
- if (stream.api?.enabled === false) continue;
1018
- const schemas = generateSchemas(stream.table, stream.name, "Account");
1019
- const filters = stream.api?.filters ?? [];
1020
- const idField = stream.api?.idField ?? "address";
1021
- const router = buildRoutes({
1022
- db,
1023
- name: stream.name,
1024
- table: stream.table,
1025
- schemas,
1026
- filters,
1027
- idField,
1028
- resourceType: "account",
1029
- includeSlotFilters: false,
1030
- sortField: "updatedAt",
1031
- secondarySortField: void 0
1032
- });
1033
- app.route(`${pathPrefix}/${stream.name}`, router);
1034
- }
1035
- }
1036
743
  var Indexer = class {
1037
744
  config;
1038
745
  abortController = null;
@@ -1223,6 +930,6 @@ var Indexer = class {
1223
930
  }
1224
931
  };
1225
932
 
1226
- export { Indexer, checkpointTable, columnBuilder, dataResponse, defineAccountStream, defineEventStream, deleteCheckpoint, errorSchema, generateSchemas, generateZodSchema, getAllCheckpoints, getCheckpoint, getSchemaExports, listResponse, mountStreamRoutes, paginate, paginationQuerySchema, paginationResponseSchema, parseCursor, t, updateCheckpoint, validateParsedData };
933
+ export { Indexer, checkpointTable, columnBuilder, defineAccountStream, defineEventStream, deleteCheckpoint, generateZodSchema, getAllCheckpoints, getCheckpoint, getSchemaExports, t, updateCheckpoint, validateParsedData };
1227
934
  //# sourceMappingURL=index.mjs.map
1228
935
  //# sourceMappingURL=index.mjs.map