@apibara/plugin-sqlite 2.1.0-beta.2 → 2.1.0-beta.20

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.cjs CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  const indexer = require('@apibara/indexer');
4
4
  const plugins = require('@apibara/indexer/plugins');
5
- const protocol = require('@apibara/protocol');
6
5
  const internal = require('@apibara/indexer/internal');
7
6
  const plugins$1 = require('@apibara/indexer/internal/plugins');
7
+ const protocol = require('@apibara/protocol');
8
8
 
9
9
  class SqliteStorageError extends Error {
10
10
  constructor(message, options) {
@@ -267,6 +267,7 @@ function sqliteStorage({
267
267
  }) {
268
268
  return plugins.defineIndexerPlugin((indexer) => {
269
269
  let indexerId = "";
270
+ let prevFinality;
270
271
  indexer.hooks.hook("run:before", async () => {
271
272
  const { indexerName: indexerFileName, availableIndexers } = plugins$1.useInternalContext();
272
273
  indexerId = internal.generateIndexerId(indexerFileName, identifier);
@@ -368,31 +369,38 @@ function sqliteStorage({
368
369
  });
369
370
  indexer.hooks.hook("handler:middleware", ({ use }) => {
370
371
  use(async (ctx, next) => {
371
- if (!ctx.finality) {
372
+ const { endCursor, finality, cursor } = ctx;
373
+ if (!finality) {
372
374
  throw new SqliteStorageError("finality is undefined");
373
375
  }
374
- if (!ctx.endCursor || !protocol.isCursor(ctx.endCursor)) {
376
+ if (!endCursor) {
375
377
  throw new SqliteStorageError(
376
378
  "endCursor is undefined or not a cursor"
377
379
  );
378
380
  }
379
381
  await withTransaction(database, async (db) => {
382
+ if (prevFinality === "pending") {
383
+ if (enableKeyValueStore) {
384
+ invalidateKV(db, cursor);
385
+ }
386
+ }
380
387
  if (enableKeyValueStore) {
381
388
  ctx[KV_PROPERTY] = new KeyValueStore(
382
389
  db,
383
- ctx.endCursor,
384
- ctx.finality,
390
+ endCursor,
391
+ finality,
385
392
  serializeFn,
386
393
  deserializeFn
387
394
  );
388
395
  }
389
396
  await next();
390
- if (enablePersistState) {
391
- persistState({ db, endCursor: ctx.endCursor, indexerId });
397
+ if (enablePersistState && finality !== "pending") {
398
+ persistState({ db, endCursor, indexerId });
392
399
  }
393
400
  if (enableKeyValueStore) {
394
401
  delete ctx[KV_PROPERTY];
395
402
  }
403
+ prevFinality = finality;
396
404
  });
397
405
  });
398
406
  });
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { useIndexerContext } from '@apibara/indexer';
2
2
  import { defineIndexerPlugin } from '@apibara/indexer/plugins';
3
- import { normalizeCursor, isCursor } from '@apibara/protocol';
4
3
  import { generateIndexerId } from '@apibara/indexer/internal';
5
4
  import { useInternalContext } from '@apibara/indexer/internal/plugins';
5
+ import { normalizeCursor } from '@apibara/protocol';
6
6
 
7
7
  class SqliteStorageError extends Error {
8
8
  constructor(message, options) {
@@ -265,6 +265,7 @@ function sqliteStorage({
265
265
  }) {
266
266
  return defineIndexerPlugin((indexer) => {
267
267
  let indexerId = "";
268
+ let prevFinality;
268
269
  indexer.hooks.hook("run:before", async () => {
269
270
  const { indexerName: indexerFileName, availableIndexers } = useInternalContext();
270
271
  indexerId = generateIndexerId(indexerFileName, identifier);
@@ -366,31 +367,38 @@ function sqliteStorage({
366
367
  });
367
368
  indexer.hooks.hook("handler:middleware", ({ use }) => {
368
369
  use(async (ctx, next) => {
369
- if (!ctx.finality) {
370
+ const { endCursor, finality, cursor } = ctx;
371
+ if (!finality) {
370
372
  throw new SqliteStorageError("finality is undefined");
371
373
  }
372
- if (!ctx.endCursor || !isCursor(ctx.endCursor)) {
374
+ if (!endCursor) {
373
375
  throw new SqliteStorageError(
374
376
  "endCursor is undefined or not a cursor"
375
377
  );
376
378
  }
377
379
  await withTransaction(database, async (db) => {
380
+ if (prevFinality === "pending") {
381
+ if (enableKeyValueStore) {
382
+ invalidateKV(db, cursor);
383
+ }
384
+ }
378
385
  if (enableKeyValueStore) {
379
386
  ctx[KV_PROPERTY] = new KeyValueStore(
380
387
  db,
381
- ctx.endCursor,
382
- ctx.finality,
388
+ endCursor,
389
+ finality,
383
390
  serializeFn,
384
391
  deserializeFn
385
392
  );
386
393
  }
387
394
  await next();
388
- if (enablePersistState) {
389
- persistState({ db, endCursor: ctx.endCursor, indexerId });
395
+ if (enablePersistState && finality !== "pending") {
396
+ persistState({ db, endCursor, indexerId });
390
397
  }
391
398
  if (enableKeyValueStore) {
392
399
  delete ctx[KV_PROPERTY];
393
400
  }
401
+ prevFinality = finality;
394
402
  });
395
403
  });
396
404
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/plugin-sqlite",
3
- "version": "2.1.0-beta.2",
3
+ "version": "2.1.0-beta.20",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -28,6 +28,7 @@
28
28
  "devDependencies": {
29
29
  "@types/better-sqlite3": "^7.6.11",
30
30
  "@types/node": "^20.14.0",
31
+ "better-sqlite3": "^9.0.0",
31
32
  "unbuild": "^2.0.0",
32
33
  "vitest": "^1.6.0"
33
34
  },
@@ -35,7 +36,7 @@
35
36
  "better-sqlite3": "^9.0.0"
36
37
  },
37
38
  "dependencies": {
38
- "@apibara/indexer": "2.1.0-beta.2",
39
- "@apibara/protocol": "2.1.0-beta.2"
39
+ "@apibara/indexer": "2.1.0-beta.20",
40
+ "@apibara/protocol": "2.1.0-beta.20"
40
41
  }
41
42
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useIndexerContext } from "@apibara/indexer";
2
2
  import { defineIndexerPlugin } from "@apibara/indexer/plugins";
3
- import { isCursor } from "@apibara/protocol";
3
+ import type { Cursor, DataFinality } from "@apibara/protocol";
4
4
  import type { Database as SqliteDatabase } from "better-sqlite3";
5
5
 
6
6
  import { generateIndexerId } from "@apibara/indexer/internal";
@@ -76,6 +76,7 @@ export function sqliteStorage<TFilter, TBlock>({
76
76
  }: SqliteStorageOptions) {
77
77
  return defineIndexerPlugin<TFilter, TBlock>((indexer) => {
78
78
  let indexerId = "";
79
+ let prevFinality: DataFinality | undefined;
79
80
 
80
81
  indexer.hooks.hook("run:before", async () => {
81
82
  const { indexerName: indexerFileName, availableIndexers } =
@@ -206,22 +207,35 @@ export function sqliteStorage<TFilter, TBlock>({
206
207
 
207
208
  indexer.hooks.hook("handler:middleware", ({ use }) => {
208
209
  use(async (ctx, next) => {
209
- if (!ctx.finality) {
210
+ const { endCursor, finality, cursor } = ctx as {
211
+ cursor: Cursor;
212
+ endCursor: Cursor;
213
+ finality: DataFinality;
214
+ };
215
+
216
+ if (!finality) {
210
217
  throw new SqliteStorageError("finality is undefined");
211
218
  }
212
219
 
213
- if (!ctx.endCursor || !isCursor(ctx.endCursor)) {
220
+ if (!endCursor) {
214
221
  throw new SqliteStorageError(
215
222
  "endCursor is undefined or not a cursor",
216
223
  );
217
224
  }
218
225
 
219
226
  await withTransaction(database, async (db) => {
227
+ if (prevFinality === "pending") {
228
+ // invalidate if previous block's finality was "pending"
229
+ if (enableKeyValueStore) {
230
+ invalidateKV(db, cursor);
231
+ }
232
+ }
233
+
220
234
  if (enableKeyValueStore) {
221
235
  ctx[KV_PROPERTY] = new KeyValueStore(
222
236
  db,
223
- ctx.endCursor,
224
- ctx.finality,
237
+ endCursor,
238
+ finality,
225
239
  serializeFn,
226
240
  deserializeFn,
227
241
  );
@@ -229,13 +243,15 @@ export function sqliteStorage<TFilter, TBlock>({
229
243
 
230
244
  await next();
231
245
 
232
- if (enablePersistState) {
233
- persistState({ db, endCursor: ctx.endCursor, indexerId });
246
+ if (enablePersistState && finality !== "pending") {
247
+ persistState({ db, endCursor, indexerId });
234
248
  }
235
249
 
236
250
  if (enableKeyValueStore) {
237
251
  delete ctx[KV_PROPERTY];
238
252
  }
253
+
254
+ prevFinality = finality;
239
255
  });
240
256
  });
241
257
  });
package/src/kv.ts CHANGED
@@ -72,7 +72,7 @@ export function invalidateKV(db: Database, cursor: Cursor) {
72
72
  );
73
73
  }
74
74
 
75
- type KeyValueRow = {
75
+ export type KeyValueRow = {
76
76
  from_block: number;
77
77
  to_block: number;
78
78
  k: string;
@@ -100,6 +100,19 @@ export function invalidateState(props: {
100
100
  );
101
101
  }
102
102
 
103
+ export type CheckpointRow = {
104
+ id: string;
105
+ order_key: number;
106
+ unique_key: string | null;
107
+ };
108
+
109
+ export type FilterRow = {
110
+ id: string;
111
+ filter: string;
112
+ from_block: number;
113
+ to_block: number | null;
114
+ };
115
+
103
116
  const statements = {
104
117
  createCheckpointsTable: `
105
118
  CREATE TABLE IF NOT EXISTS checkpoints (