@apibara/indexer 2.0.0-beta.0 → 2.0.0-beta.4

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.
Files changed (66) hide show
  1. package/package.json +30 -19
  2. package/src/context.ts +8 -3
  3. package/src/hooks/index.ts +1 -0
  4. package/src/hooks/useSink.ts +13 -0
  5. package/src/index.ts +1 -0
  6. package/src/indexer.test.ts +70 -41
  7. package/src/indexer.ts +168 -168
  8. package/src/plugins/config.ts +4 -4
  9. package/src/plugins/kv.ts +2 -2
  10. package/src/plugins/persistence.test.ts +10 -6
  11. package/src/plugins/persistence.ts +3 -3
  12. package/src/sink.ts +21 -24
  13. package/src/sinks/csv.test.ts +15 -3
  14. package/src/sinks/csv.ts +68 -7
  15. package/src/sinks/drizzle/Int8Range.ts +52 -0
  16. package/src/sinks/drizzle/delete.ts +42 -0
  17. package/src/sinks/drizzle/drizzle.test.ts +239 -0
  18. package/src/sinks/drizzle/drizzle.ts +115 -0
  19. package/src/sinks/drizzle/index.ts +6 -0
  20. package/src/sinks/drizzle/insert.ts +39 -0
  21. package/src/sinks/drizzle/select.ts +44 -0
  22. package/src/sinks/drizzle/transaction.ts +49 -0
  23. package/src/sinks/drizzle/update.ts +47 -0
  24. package/src/sinks/drizzle/utils.ts +36 -0
  25. package/src/sinks/sqlite.test.ts +13 -1
  26. package/src/sinks/sqlite.ts +65 -5
  27. package/src/testing/indexer.ts +15 -8
  28. package/src/testing/setup.ts +5 -5
  29. package/src/testing/vcr.ts +42 -4
  30. package/src/vcr/record.ts +2 -2
  31. package/src/vcr/replay.ts +3 -3
  32. package/.turbo/turbo-build.log +0 -37
  33. package/CHANGELOG.md +0 -83
  34. package/LICENSE.txt +0 -202
  35. package/build.config.ts +0 -16
  36. package/dist/index.cjs +0 -34
  37. package/dist/index.d.cts +0 -21
  38. package/dist/index.d.mts +0 -21
  39. package/dist/index.d.ts +0 -21
  40. package/dist/index.mjs +0 -19
  41. package/dist/shared/indexer.371c0482.mjs +0 -15
  42. package/dist/shared/indexer.3852a4d3.d.ts +0 -91
  43. package/dist/shared/indexer.50aa7ab0.mjs +0 -268
  44. package/dist/shared/indexer.7c118fb5.d.cts +0 -28
  45. package/dist/shared/indexer.7c118fb5.d.mts +0 -28
  46. package/dist/shared/indexer.7c118fb5.d.ts +0 -28
  47. package/dist/shared/indexer.a27bcb35.d.cts +0 -91
  48. package/dist/shared/indexer.c8ef02ea.cjs +0 -289
  49. package/dist/shared/indexer.e05aedca.cjs +0 -19
  50. package/dist/shared/indexer.f7dd57e5.d.mts +0 -91
  51. package/dist/sinks/csv.cjs +0 -66
  52. package/dist/sinks/csv.d.cts +0 -34
  53. package/dist/sinks/csv.d.mts +0 -34
  54. package/dist/sinks/csv.d.ts +0 -34
  55. package/dist/sinks/csv.mjs +0 -59
  56. package/dist/sinks/sqlite.cjs +0 -71
  57. package/dist/sinks/sqlite.d.cts +0 -41
  58. package/dist/sinks/sqlite.d.mts +0 -41
  59. package/dist/sinks/sqlite.d.ts +0 -41
  60. package/dist/sinks/sqlite.mjs +0 -68
  61. package/dist/testing/index.cjs +0 -63
  62. package/dist/testing/index.d.cts +0 -29
  63. package/dist/testing/index.d.mts +0 -29
  64. package/dist/testing/index.d.ts +0 -29
  65. package/dist/testing/index.mjs +0 -59
  66. package/tsconfig.json +0 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/indexer",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.4",
4
4
  "type": "module",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./dist/index.mjs",
@@ -23,6 +23,12 @@
23
23
  "require": "./dist/sinks/csv.cjs",
24
24
  "default": "./dist/sinks/csv.mjs"
25
25
  },
26
+ "./sinks/drizzle": {
27
+ "types": "./dist/sinks/drizzle/index.d.ts",
28
+ "import": "./dist/sinks/drizzle/index.mjs",
29
+ "require": "./dist/sinks/drizzle/index.cjs",
30
+ "default": "./dist/sinks/drizzle/index.mjs"
31
+ },
26
32
  "./testing": {
27
33
  "types": "./dist/testing/index.d.ts",
28
34
  "import": "./dist/testing/index.mjs",
@@ -30,43 +36,48 @@
30
36
  "default": "./dist/testing/index.mjs"
31
37
  }
32
38
  },
33
- "publishConfig": {
34
- "files": [
35
- "dist",
36
- "src",
37
- "README.md"
38
- ]
39
+ "publishConfig": {},
40
+ "scripts": {
41
+ "build": "unbuild",
42
+ "lint": "biome check .",
43
+ "typecheck": "tsc --noEmit",
44
+ "lint:fix": "pnpm lint --write",
45
+ "test": "vitest",
46
+ "test:ci": "vitest run",
47
+ "format": "biome format . --write"
39
48
  },
40
49
  "devDependencies": {
41
50
  "@types/better-sqlite3": "^7.6.11",
42
51
  "@types/node": "^20.14.0",
52
+ "@types/pg": "^8.11.10",
43
53
  "better-sqlite3": "^11.1.2",
44
54
  "csv-stringify": "^6.5.0",
55
+ "drizzle-orm": "^0.33.0",
56
+ "pg": "^8.12.0",
57
+ "postgres-range": "^1.1.4",
45
58
  "unbuild": "^2.0.0",
46
59
  "vitest": "^1.6.0"
47
60
  },
48
61
  "dependencies": {
62
+ "@apibara/protocol": "2.0.0-beta.4",
49
63
  "@opentelemetry/api": "^1.9.0",
50
64
  "consola": "^3.2.3",
51
65
  "hookable": "^5.5.3",
52
66
  "klona": "^2.0.6",
53
67
  "nice-grpc": "^2.1.8",
54
- "unctx": "^2.3.1",
55
- "@apibara/protocol": "2.0.0-beta.1"
68
+ "unctx": "^2.3.1"
56
69
  },
57
70
  "peerDependencies": {
58
71
  "better-sqlite3": "^11.1.2",
59
72
  "csv-stringify": "^6.5.0",
73
+ "drizzle-orm": "^0.33.0",
74
+ "postgres-range": "^1.1.4",
60
75
  "vitest": "^1.6.0"
61
76
  },
62
- "scripts": {
63
- "build": "unbuild",
64
- "lint": "biome check .",
65
- "typecheck": "tsc --noEmit",
66
- "lint:fix": "pnpm lint --write",
67
- "test": "vitest",
68
- "test:ci": "vitest run",
69
- "format": "biome format . --write"
70
- },
77
+ "files": [
78
+ "dist",
79
+ "src",
80
+ "README.md"
81
+ ],
71
82
  "types": "./dist/index.d.ts"
72
- }
83
+ }
package/src/context.ts CHANGED
@@ -1,14 +1,19 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { getContext } from "unctx";
3
+ import type { Sink } from "./sink";
3
4
 
4
5
  // biome-ignore lint/suspicious/noExplicitAny: context type
5
- export interface IndexerContext extends Record<string, any> {}
6
+ export interface IndexerContext<TTxnParams = any> extends Record<string, any> {
7
+ sink?: Sink<TTxnParams>;
8
+ sinkTransaction?: TTxnParams;
9
+ }
6
10
 
7
11
  export const indexerAsyncContext = getContext<IndexerContext>("indexer", {
8
12
  asyncContext: true,
9
13
  AsyncLocalStorage,
10
14
  });
11
15
 
12
- export function useIndexerContext() {
13
- return indexerAsyncContext.use();
16
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
17
+ export function useIndexerContext<TTxnParams = any>() {
18
+ return indexerAsyncContext.use() as IndexerContext<TTxnParams>;
14
19
  }
@@ -1 +1,2 @@
1
1
  export * from "./useKVStore";
2
+ export * from "./useSink";
@@ -0,0 +1,13 @@
1
+ import type { IndexerContext } from "../context";
2
+
3
+ export function useSink<TTxnParams>({
4
+ context,
5
+ }: {
6
+ context: IndexerContext<TTxnParams>;
7
+ }) {
8
+ if (!context.sinkTransaction) {
9
+ throw new Error("Transaction context doesn't exist!");
10
+ }
11
+
12
+ return context.sinkTransaction;
13
+ }
package/src/index.ts CHANGED
@@ -4,3 +4,4 @@ export { useIndexerContext } from "./context";
4
4
 
5
5
  export * from "./plugins";
6
6
  export * from "./vcr";
7
+ export * from "./hooks";
@@ -4,12 +4,12 @@ import {
4
4
  type MockFilter,
5
5
  } from "@apibara/protocol/testing";
6
6
  import Database from "better-sqlite3";
7
- import { klona } from "klona/full";
8
7
  import { describe, expect, it } from "vitest";
8
+ import { useSink } from "./hooks";
9
9
  import { run } from "./indexer";
10
10
  import { SqlitePersistence, sqlitePersistence } from "./plugins/persistence";
11
11
  import { generateMockMessages, vcr } from "./testing";
12
- import { type MockRet, getMockIndexer } from "./testing/indexer";
12
+ import { getMockIndexer } from "./testing/indexer";
13
13
 
14
14
  describe("Run Test", () => {
15
15
  it("should stream messages", async () => {
@@ -18,7 +18,18 @@ describe("Run Test", () => {
18
18
  });
19
19
 
20
20
  const sink = vcr();
21
- await run(client, getMockIndexer(), sink);
21
+
22
+ const indexer = getMockIndexer({
23
+ sink,
24
+ override: {
25
+ transform: async ({ context, endCursor, block: { data } }) => {
26
+ const { writer } = useSink({ context });
27
+ writer.insert([{ data }]);
28
+ },
29
+ },
30
+ });
31
+
32
+ await run(client, indexer);
22
33
 
23
34
  expect(sink.result).toMatchInlineSnapshot(`
24
35
  [
@@ -246,28 +257,37 @@ describe("Run Test", () => {
246
257
 
247
258
  const db = Database(":memory:");
248
259
 
249
- const persistence = sqlitePersistence<MockFilter, MockBlock, MockRet>({
250
- database: db,
251
- });
260
+ const sink = vcr();
252
261
 
253
262
  // create mock indexer with persistence plugin
254
- const indexer = klona(getMockIndexer([persistence]));
255
- indexer.options.startingCursor = { orderKey: 100n };
256
- indexer.options.factory = async (block) => {
257
- if (block.data === "B") {
258
- return { filter: { filter: "B" } };
259
- }
260
-
261
- if (block.data === "C") {
262
- return { filter: { filter: "C" } };
263
- }
264
-
265
- return {};
266
- };
267
-
268
- const sink = vcr();
263
+ const indexer = getMockIndexer({
264
+ plugins: [
265
+ sqlitePersistence({
266
+ database: db,
267
+ }),
268
+ ],
269
+ sink,
270
+ override: {
271
+ startingCursor: { orderKey: 100n },
272
+ factory: async ({ block }) => {
273
+ if (block.data === "B") {
274
+ return { filter: { filter: "B" } };
275
+ }
276
+
277
+ if (block.data === "C") {
278
+ return { filter: { filter: "C" } };
279
+ }
280
+
281
+ return {};
282
+ },
283
+ transform: async ({ context, endCursor, block: { data } }) => {
284
+ const { writer } = useSink({ context });
285
+ writer.insert([{ data }]);
286
+ },
287
+ },
288
+ });
269
289
 
270
- await run(client, indexer, sink);
290
+ await run(client, indexer);
271
291
 
272
292
  const store = new SqlitePersistence<MockFilter>(db);
273
293
 
@@ -423,28 +443,37 @@ describe("Run Test", () => {
423
443
 
424
444
  const db = Database(":memory:");
425
445
 
426
- const persistence = sqlitePersistence<MockFilter, MockBlock, MockRet>({
427
- database: db,
428
- });
446
+ const sink = vcr();
429
447
 
430
448
  // create mock indexer with persistence plugin
431
- const indexer = klona(getMockIndexer([persistence]));
432
- indexer.options.startingCursor = { orderKey: 100n };
433
- indexer.options.factory = async (block) => {
434
- if (block.data === "B") {
435
- return { filter: { filter: "B" } };
436
- }
437
-
438
- if (block.data === "C") {
439
- return { filter: { filter: "C" } };
440
- }
441
-
442
- return {};
443
- };
444
-
445
- const sink = vcr();
449
+ const indexer = getMockIndexer({
450
+ plugins: [
451
+ sqlitePersistence({
452
+ database: db,
453
+ }),
454
+ ],
455
+ sink,
456
+ override: {
457
+ startingCursor: { orderKey: 100n },
458
+ factory: async ({ block }) => {
459
+ if (block.data === "B") {
460
+ return { filter: { filter: "B" } };
461
+ }
462
+
463
+ if (block.data === "C") {
464
+ return { filter: { filter: "C" } };
465
+ }
466
+
467
+ return {};
468
+ },
469
+ transform: async ({ context, endCursor, block: { data } }) => {
470
+ const { writer } = useSink({ context });
471
+ writer.insert([{ data }]);
472
+ },
473
+ },
474
+ });
446
475
 
447
- await expect(() => run(client, indexer, sink)).rejects.toThrowError(
476
+ await expect(() => run(client, indexer)).rejects.toThrowError(
448
477
  "this error should occurr!",
449
478
  );
450
479