@sqd-pipes/delta-db 0.0.1-alpha.7 → 0.0.1-alpha.8

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/README.md CHANGED
@@ -1,83 +1,173 @@
1
- # @subsquid/delta-db
1
+ # @sqd-pipes/delta-db
2
2
 
3
- Embedded rollback-aware computation engine for blockchain data. Routes raw events through **reducers** and **materialized views**, producing delta records (insert/update/delete) for downstream targets.
3
+ Embedded rollback-aware computation engine for blockchain data. Routes raw events through **reducers** (TypeScript functions) and **materialized views**, producing delta records (insert/update/delete) for downstream targets.
4
4
 
5
- ## Build
6
-
7
- Requires **Rust** (stable) and **Node.js** >= 18.
5
+ ## Install
8
6
 
9
7
  ```bash
10
- cd packages/delta-db-node
11
- npm install
8
+ pnpm add @sqd-pipes/delta-db
9
+ ```
12
10
 
13
- # Debug build
14
- npx napi build --cargo-cwd ../.. --features napi
11
+ ## Build from source
12
+
13
+ Requires **Rust** (stable) and **Node.js** >= 18.
15
14
 
16
- # Release build
17
- npx napi build --cargo-cwd ../.. --features napi --release
15
+ ```bash
16
+ pnpm install
17
+ pnpm run build # release
18
+ pnpm run build:debug # debug
18
19
  ```
19
20
 
20
- This produces `delta-db.node` (native binary) and regenerates `index.d.ts`.
21
+ ## Quick start
21
22
 
22
- If `index.js` is missing after build, create it:
23
+ ```typescript
24
+ import { Pipeline, uint64, string, float64, interval } from '@sqd-pipes/delta-db'
23
25
 
24
- ```js
25
- const { DeltaDb } = require('./delta-db.node')
26
- module.exports.DeltaDb = DeltaDb
27
- ```
26
+ const p = new Pipeline()
28
27
 
29
- ## Test
28
+ const swaps = p.table('swaps', {
29
+ block_number: uint64(),
30
+ pool: string(),
31
+ amount: float64(),
32
+ })
30
33
 
31
- ```bash
32
- npm test
34
+ swaps
35
+ .createReducer('totals', {
36
+ groupBy: 'pool',
37
+ initialState: { volume: 0 },
38
+ reduce(state, row) {
39
+ const volume = state.volume + row.amount
40
+ return [{ volume }, { pool: row.pool, volume }]
41
+ },
42
+ })
43
+ .createView('pool_volume', {
44
+ groupBy: ['pool'],
45
+ select: (agg) => ({
46
+ pool: agg.key.pool,
47
+ totalVolume: agg.sum('volume'),
48
+ tradeCount: agg.count(),
49
+ }),
50
+ })
51
+
52
+ const db = p.build() // in-memory
53
+ // const db = p.build({ dataDir: './data' }) // persistent (RocksDB)
54
+
55
+ db.processBatch('swaps', 1000, [
56
+ { pool: 'ETH/USDC', amount: 100 },
57
+ { pool: 'ETH/USDC', amount: 200 },
58
+ ])
59
+
60
+ const batch = db.flush()!
61
+ // batch.tables.pool_volume → [{ key: { pool: 'ETH/USDC' }, values: { totalVolume: 300, tradeCount: 2 } }]
33
62
  ```
34
63
 
35
- ## Usage
64
+ ## API
36
65
 
37
- ### Direct API
66
+ ### Pipeline builder
38
67
 
39
68
  ```typescript
40
- import { DeltaDb } from '@subsquid/delta-db'
41
-
42
- const db = DeltaDb.open({
43
- schema: `
44
- CREATE TABLE swaps (
45
- block_number UInt64,
46
- pool String,
47
- amount Float64
48
- );
49
- CREATE MATERIALIZED VIEW volume AS
50
- SELECT pool, sum(amount) AS total, count() AS cnt
51
- FROM swaps GROUP BY pool;
52
- `,
53
- dataDir: './data', // optional, enables persistence
69
+ const p = new Pipeline()
70
+
71
+ // Define a table — column types are inferred into the row type
72
+ const table = p.table('name', {
73
+ block_number: uint64(),
74
+ user: string(),
75
+ amount: float64(),
76
+ timestamp: datetime(),
77
+ metadata: json<MyType>(), // json() is generic
54
78
  })
55
79
 
56
- const batch = db.ingest({
57
- data: {
58
- swaps: [
59
- { block_number: 1000, pool: 'ETH/USDC', amount: 100 },
60
- ],
80
+ // Create a reducer from a table (or another reducer)
81
+ const reducer = table.createReducer('reducer_name', {
82
+ groupBy: 'user', // validated against row keys
83
+ initialState: { total: 0 }, // state type inferred
84
+ reduce(state, row) { // state & row fully typed
85
+ return [
86
+ { total: state.total + row.amount }, // new state
87
+ { user: row.user, total: ... }, // emit (or null to skip)
88
+ ]
61
89
  },
62
- rollbackChain: [{ number: 1000, hash: '0x...' }],
63
- finalizedHead: { number: 999, hash: '0x...' },
64
90
  })
65
- // batch.records → [{ table: 'swaps', op: 'insert', ... }, { table: 'volume', op: 'insert', ... }]
91
+
92
+ // Chain a reducer from another reducer's output
93
+ const chained = reducer.createReducer('downstream', { ... })
94
+
95
+ // Create a materialized view
96
+ reducer.createView('summary', {
97
+ groupBy: ['user'],
98
+ select: (agg) => ({
99
+ user: agg.key.user,
100
+ total: agg.sum('total'), // validated against emit keys
101
+ count: agg.count(),
102
+ first: agg.first('total'),
103
+ last: agg.last('total'),
104
+ }),
105
+ })
106
+
107
+ // Time-window grouping
108
+ reducer.createView('candles_5m', {
109
+ groupBy: ['pool', interval('timestamp', '5 minutes').as('window_start')],
110
+ select: (agg) => ({
111
+ pool: agg.key.pool,
112
+ windowStart: agg.key.window_start,
113
+ open: agg.first('price'),
114
+ high: agg.max('price'),
115
+ low: agg.min('price'),
116
+ close: agg.last('price'),
117
+ volume: agg.sum('volume'),
118
+ }),
119
+ })
120
+
121
+ // Build the database
122
+ const db = p.build() // in-memory
123
+ const db = p.build({ dataDir: './data' }) // RocksDB persistence
124
+ const db = p.build({ dataDir: ':memory:' }) // explicit in-memory (SQLite convention)
66
125
  ```
67
126
 
68
- ### Pipes SDK
127
+ ### Column types
128
+
129
+ | Function | SQL type | TypeScript type |
130
+ |-------------|------------|-----------------|
131
+ | `uint64()` | `UInt64` | `number` |
132
+ | `int64()` | `Int64` | `number` |
133
+ | `float64()` | `Float64` | `number` |
134
+ | `uint256()` | `Uint256` | `bigint` |
135
+ | `string()` | `String` | `string` |
136
+ | `datetime()` | `DateTime` | `number` |
137
+ | `boolean()` | `Boolean` | `boolean` |
138
+ | `bytes()` | `Bytes` | `Uint8Array` |
139
+ | `base58()` | `Base58` | `string` |
140
+ | `json<T>()` | `Json` | `T` (default `any`) |
141
+
142
+ ### DeltaDb (low-level)
69
143
 
70
144
  ```typescript
71
- import { deltaDbTarget } from '@subsquid/delta-db/pipes'
72
-
73
- await source
74
- .pipe(decoder)
75
- .pipeTo(deltaDbTarget({
76
- schema: '...',
77
- dataDir: './data',
78
- transform: (data) => ({ transfers: data.transfers.map(formatRow) }),
79
- onDelta: async ({ batch }) => {
80
- await clickhouse.insert(batch.records)
81
- },
82
- }))
145
+ import { DeltaDb } from '@sqd-pipes/delta-db'
146
+
147
+ const db = DeltaDb.open({ schema: 'CREATE TABLE ...', dataDir: './data' })
148
+
149
+ db.processBatch('table', blockNumber, rows)
150
+ db.rollback(forkPoint)
151
+ db.finalize(blockNumber)
152
+ db.flush() // DeltaBatch | null
153
+ db.ingest(input) // atomic: process + finalize + flush
154
+ ```
155
+
156
+ ### Aggregation functions
157
+
158
+ `sum`, `count`, `min`, `max`, `avg`, `first`, `last`
159
+
160
+ ### Virtual tables
161
+
162
+ Tables declared with `{ virtual: true }` are processed by reducers but don't emit raw row deltas:
163
+
164
+ ```typescript
165
+ const orders = p.table('orders', { ... }, { virtual: true })
166
+ ```
167
+
168
+ ## Test
169
+
170
+ ```bash
171
+ pnpm test
172
+ pnpm run lint
83
173
  ```
@@ -0,0 +1,20 @@
1
+ export interface ColumnType<T = any> {
2
+ readonly _sql: string;
3
+ /** Phantom field for type inference — not present at runtime. */
4
+ readonly _type?: T;
5
+ }
6
+ export declare const uint64: () => ColumnType<number>;
7
+ export declare const int64: () => ColumnType<number>;
8
+ export declare const float64: () => ColumnType<number>;
9
+ export declare const uint256: () => ColumnType<bigint>;
10
+ export declare const string: () => ColumnType<string>;
11
+ export declare const datetime: () => ColumnType<number>;
12
+ export declare const boolean: () => ColumnType<boolean>;
13
+ export declare const bytes: () => ColumnType<Uint8Array<ArrayBufferLike>>;
14
+ export declare const base58: () => ColumnType<string>;
15
+ export declare function json<T = any>(): ColumnType<T>;
16
+ /** Infer the row type from a column definition record. */
17
+ export type InferRow<T extends Record<string, ColumnType>> = {
18
+ [K in keyof T]: T[K] extends ColumnType<infer V> ? V : unknown;
19
+ };
20
+ //# sourceMappingURL=column.d.ts.map
package/dist/column.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.base58 = exports.bytes = exports.boolean = exports.datetime = exports.string = exports.uint256 = exports.float64 = exports.int64 = exports.uint64 = void 0;
4
+ exports.json = json;
5
+ function col(sql) {
6
+ return () => ({ _sql: sql });
7
+ }
8
+ exports.uint64 = col('UInt64');
9
+ exports.int64 = col('Int64');
10
+ exports.float64 = col('Float64');
11
+ exports.uint256 = col('Uint256');
12
+ exports.string = col('String');
13
+ exports.datetime = col('DateTime');
14
+ exports.boolean = col('Boolean');
15
+ exports.bytes = col('Bytes');
16
+ exports.base58 = col('Base58');
17
+ function json() {
18
+ return { _sql: 'Json' };
19
+ }
20
+ //# sourceMappingURL=column.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column.js","sourceRoot":"","sources":["../src/column.ts"],"names":[],"mappings":";;;AAmBA,oBAEC;AAfD,SAAS,GAAG,CAAI,GAAW;IACzB,OAAO,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;AAC9B,CAAC;AAEY,QAAA,MAAM,GAAG,GAAG,CAAS,QAAQ,CAAC,CAAA;AAC9B,QAAA,KAAK,GAAG,GAAG,CAAS,OAAO,CAAC,CAAA;AAC5B,QAAA,OAAO,GAAG,GAAG,CAAS,SAAS,CAAC,CAAA;AAChC,QAAA,OAAO,GAAG,GAAG,CAAS,SAAS,CAAC,CAAA;AAChC,QAAA,MAAM,GAAG,GAAG,CAAS,QAAQ,CAAC,CAAA;AAC9B,QAAA,QAAQ,GAAG,GAAG,CAAS,UAAU,CAAC,CAAA;AAClC,QAAA,OAAO,GAAG,GAAG,CAAU,SAAS,CAAC,CAAA;AACjC,QAAA,KAAK,GAAG,GAAG,CAAa,OAAO,CAAC,CAAA;AAChC,QAAA,MAAM,GAAG,GAAG,CAAS,QAAQ,CAAC,CAAA;AAC3C,SAAgB,IAAI;IAClB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC"}
package/dist/ddl.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { ColumnType } from './column';
2
+ import type { StateFieldDef } from './delta-db';
3
+ export declare function parseDuration(s: string): number;
4
+ export interface IntervalExpr {
5
+ _type: 'interval';
6
+ column: string;
7
+ seconds: number;
8
+ alias?: string;
9
+ as(alias: string): IntervalExpr;
10
+ }
11
+ export declare function interval(column: string, duration: string): IntervalExpr;
12
+ export interface AggExpr {
13
+ _type: 'agg';
14
+ func: string;
15
+ column: string | null;
16
+ }
17
+ export interface KeyRef {
18
+ _type: 'key';
19
+ column: string;
20
+ }
21
+ export interface AggProxy<TSource = any> {
22
+ key: Record<string, KeyRef>;
23
+ sum(column: string & keyof TSource): AggExpr;
24
+ count(): AggExpr;
25
+ first(column: string & keyof TSource): AggExpr;
26
+ last(column: string & keyof TSource): AggExpr;
27
+ min(column: string & keyof TSource): AggExpr;
28
+ max(column: string & keyof TSource): AggExpr;
29
+ avg(column: string & keyof TSource): AggExpr;
30
+ }
31
+ export type GroupByItem = string | IntervalExpr;
32
+ export interface ReducerOptions<TState, TRow, TEmit> {
33
+ groupBy: (string & keyof TRow) | (string & keyof TRow)[];
34
+ initialState: TState;
35
+ reduce: (state: TState, row: TRow) => [TState, TEmit | TEmit[] | null];
36
+ }
37
+ export interface ViewOptions<TSource = any> {
38
+ groupBy: GroupByItem | GroupByItem[];
39
+ select: (agg: AggProxy<TSource>) => Record<string, AggExpr | KeyRef>;
40
+ }
41
+ export declare function inferStateFields(initialState: Record<string, unknown>): StateFieldDef[];
42
+ export declare function tableToSql(name: string, columns: Record<string, ColumnType>, virtual: boolean): string;
43
+ export declare function reducerToSql(name: string, source: string, groupBy: string[], stateFields: StateFieldDef[]): string;
44
+ export declare function viewToSql(name: string, source: string, groupByItems: GroupByItem[], selectFn: (agg: AggProxy<any>) => Record<string, AggExpr | KeyRef>): string;
45
+ //# sourceMappingURL=ddl.d.ts.map
package/dist/ddl.js ADDED
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDuration = parseDuration;
4
+ exports.interval = interval;
5
+ exports.inferStateFields = inferStateFields;
6
+ exports.tableToSql = tableToSql;
7
+ exports.reducerToSql = reducerToSql;
8
+ exports.viewToSql = viewToSql;
9
+ // ─── Duration parsing ────────────────────────────────────────────
10
+ const DURATION_UNITS = {
11
+ second: 1,
12
+ seconds: 1,
13
+ sec: 1,
14
+ s: 1,
15
+ minute: 60,
16
+ minutes: 60,
17
+ min: 60,
18
+ m: 60,
19
+ hour: 3600,
20
+ hours: 3600,
21
+ hr: 3600,
22
+ h: 3600,
23
+ day: 86400,
24
+ days: 86400,
25
+ d: 86400,
26
+ };
27
+ function parseDuration(s) {
28
+ const match = s.trim().match(/^(\d+)\s*(\w+)$/);
29
+ if (!match) {
30
+ throw new Error(`invalid duration: '${s}'`);
31
+ }
32
+ const n = parseInt(match[1], 10);
33
+ const unit = match[2].toLowerCase();
34
+ const mult = DURATION_UNITS[unit];
35
+ if (!mult) {
36
+ throw new Error(`unknown duration unit: '${unit}'`);
37
+ }
38
+ return n * mult;
39
+ }
40
+ function makeInterval(column, seconds, alias) {
41
+ return {
42
+ _type: 'interval',
43
+ column,
44
+ seconds,
45
+ alias,
46
+ as(a) {
47
+ return makeInterval(column, seconds, a);
48
+ },
49
+ };
50
+ }
51
+ function interval(column, duration) {
52
+ return makeInterval(column, parseDuration(duration));
53
+ }
54
+ // ─── Type inference from initialState ────────────────────────────
55
+ function inferStateFields(initialState) {
56
+ const fields = [];
57
+ for (const [name, value] of Object.entries(initialState)) {
58
+ let columnType;
59
+ let defaultValue;
60
+ switch (typeof value) {
61
+ case 'number':
62
+ columnType = 'Float64';
63
+ defaultValue = String(value);
64
+ break;
65
+ case 'bigint':
66
+ columnType = 'UInt64';
67
+ defaultValue = String(value);
68
+ break;
69
+ case 'string':
70
+ columnType = 'String';
71
+ defaultValue = `'${value}'`;
72
+ break;
73
+ case 'boolean':
74
+ columnType = 'Boolean';
75
+ defaultValue = value ? 'true' : 'false';
76
+ break;
77
+ case 'object':
78
+ columnType = 'Json';
79
+ defaultValue = `'${JSON.stringify(value)}'`;
80
+ break;
81
+ default:
82
+ columnType = 'String';
83
+ defaultValue = `'${String(value)}'`;
84
+ }
85
+ fields.push({ name, columnType, defaultValue });
86
+ }
87
+ return fields;
88
+ }
89
+ // ─── DDL generators ──────────────────────────────────────────────
90
+ function tableToSql(name, columns, virtual) {
91
+ const prefix = virtual ? 'CREATE VIRTUAL TABLE' : 'CREATE TABLE';
92
+ const cols = Object.entries(columns)
93
+ .map(([name, ct]) => `${name} ${ct._sql}`)
94
+ .join(', ');
95
+ return `${prefix} ${name} (${cols});`;
96
+ }
97
+ function reducerToSql(name, source, groupBy, stateFields) {
98
+ const gb = groupBy.join(', ');
99
+ const state = stateFields
100
+ .map((f) => `${f.name} ${f.columnType} DEFAULT ${f.defaultValue}`)
101
+ .join(', ');
102
+ return `CREATE REDUCER ${name} SOURCE ${source} GROUP BY ${gb} STATE (${state}) LANGUAGE EXTERNAL;`;
103
+ }
104
+ function viewToSql(name, source, groupByItems, selectFn) {
105
+ const groupByCols = [];
106
+ const intervalDefs = [];
107
+ for (const item of groupByItems) {
108
+ if (typeof item === 'string') {
109
+ groupByCols.push(item);
110
+ }
111
+ else if (item._type === 'interval') {
112
+ const alias = item.alias || `${item.column}_interval`;
113
+ intervalDefs.push({ column: item.column, seconds: item.seconds, alias });
114
+ groupByCols.push(alias);
115
+ }
116
+ }
117
+ const keyProxy = new Proxy({}, {
118
+ get(_target, prop) {
119
+ return { _type: 'key', column: prop };
120
+ },
121
+ });
122
+ const aggProxy = {
123
+ key: keyProxy,
124
+ sum(col) {
125
+ return { _type: 'agg', func: 'sum', column: col };
126
+ },
127
+ count() {
128
+ return { _type: 'agg', func: 'count', column: null };
129
+ },
130
+ first(col) {
131
+ return { _type: 'agg', func: 'first', column: col };
132
+ },
133
+ last(col) {
134
+ return { _type: 'agg', func: 'last', column: col };
135
+ },
136
+ min(col) {
137
+ return { _type: 'agg', func: 'min', column: col };
138
+ },
139
+ max(col) {
140
+ return { _type: 'agg', func: 'max', column: col };
141
+ },
142
+ avg(col) {
143
+ return { _type: 'agg', func: 'avg', column: col };
144
+ },
145
+ };
146
+ const selectResult = selectFn(aggProxy);
147
+ const selectItems = [];
148
+ for (const [alias, expr] of Object.entries(selectResult)) {
149
+ if (expr._type === 'key') {
150
+ const intv = intervalDefs.find((d) => d.alias === expr.column);
151
+ if (intv) {
152
+ selectItems.push(`toStartOfInterval(${intv.column}, INTERVAL ${intv.seconds} SECOND) AS ${alias}`);
153
+ }
154
+ else {
155
+ selectItems.push(alias === expr.column ? alias : `${expr.column} AS ${alias}`);
156
+ }
157
+ }
158
+ else if (expr._type === 'agg') {
159
+ const arg = expr.column ? `(${expr.column})` : '()';
160
+ selectItems.push(`${expr.func}${arg} AS ${alias}`);
161
+ }
162
+ }
163
+ return `CREATE MATERIALIZED VIEW ${name} AS SELECT ${selectItems.join(', ')} FROM ${source} GROUP BY ${groupByCols.join(', ')};`;
164
+ }
165
+ //# sourceMappingURL=ddl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ddl.js","sourceRoot":"","sources":["../src/ddl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ export interface DeltaDbConfig {
2
+ schema: string;
3
+ dataDir?: string;
4
+ maxBufferSize?: number;
5
+ }
6
+ export interface DeltaDbCursor {
7
+ number: number;
8
+ hash: string;
9
+ }
10
+ export type DeltaOperation = 'insert' | 'update' | 'delete';
11
+ export interface DeltaRecord {
12
+ table: string;
13
+ operation: DeltaOperation;
14
+ key: Record<string, any>;
15
+ values: Record<string, any>;
16
+ prevValues: Record<string, any> | null;
17
+ }
18
+ export interface DeltaBatch {
19
+ sequence: number;
20
+ finalizedHead: DeltaDbCursor | null;
21
+ latestHead: DeltaDbCursor | null;
22
+ tables: Record<string, DeltaRecord[]>;
23
+ }
24
+ export interface IngestInput {
25
+ data: Record<string, Record<string, any>[]>;
26
+ rollbackChain?: DeltaDbCursor[];
27
+ finalizedHead: DeltaDbCursor;
28
+ onDelta?: (batch: DeltaBatch) => void;
29
+ }
30
+ export interface StateFieldDef {
31
+ name: string;
32
+ columnType: string;
33
+ defaultValue: string;
34
+ }
35
+ export interface ExternalReducerOptions<TState = any, TRow = any, TEmit = any> {
36
+ name: string;
37
+ source: string;
38
+ groupBy: string[];
39
+ state: StateFieldDef[];
40
+ reduce: (state: TState, row: TRow) => [TState, TEmit | TEmit[] | null];
41
+ }
42
+ export declare class DeltaDb {
43
+ #private;
44
+ private constructor();
45
+ static open(config: DeltaDbConfig): DeltaDb;
46
+ processBatch(table: string, block: number, rows: Record<string, any>[]): boolean;
47
+ rollback(forkPoint: number): void;
48
+ finalize(block: number): void;
49
+ ingest(input: IngestInput): DeltaBatch | null;
50
+ resolveForkCursor(previousBlocks: DeltaDbCursor[]): DeltaDbCursor | null;
51
+ flush(): DeltaBatch | null;
52
+ ack(sequence: number): void;
53
+ get pendingCount(): number;
54
+ get isBackpressured(): boolean;
55
+ get cursor(): DeltaDbCursor | null;
56
+ registerReducer<TState = any, TRow = any, TEmit = any>(options: ExternalReducerOptions<TState, TRow, TEmit>): void;
57
+ }
58
+ //# sourceMappingURL=delta-db.d.ts.map
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeltaDb = void 0;
4
+ const msgpack_1 = require("@msgpack/msgpack");
5
+ const native_js_1 = require("./native/native.js");
6
+ const encoder = new msgpack_1.Encoder({ useBigInt64: true });
7
+ // ─── DeltaDb class ───────────────────────────────────────────────
8
+ class DeltaDb {
9
+ #native;
10
+ constructor(native) {
11
+ this.#native = native;
12
+ }
13
+ static open(config) {
14
+ return new DeltaDb(native_js_1.DeltaDb.open(config));
15
+ }
16
+ processBatch(table, block, rows) {
17
+ return this.#native.processBatch(table, block, Buffer.from(encoder.encode(rows)));
18
+ }
19
+ rollback(forkPoint) {
20
+ this.#native.rollback(forkPoint);
21
+ }
22
+ finalize(block) {
23
+ this.#native.finalize(block);
24
+ }
25
+ ingest(input) {
26
+ const buf = this.#native.ingest({
27
+ data: Buffer.from(encoder.encode(input.data)),
28
+ rollbackChain: input.rollbackChain,
29
+ finalizedHead: input.finalizedHead,
30
+ });
31
+ const batch = buf ? (0, msgpack_1.decode)(buf) : null;
32
+ if (batch && input.onDelta) {
33
+ input.onDelta(batch);
34
+ this.#native.ack(batch.sequence);
35
+ }
36
+ return batch;
37
+ }
38
+ resolveForkCursor(previousBlocks) {
39
+ return this.#native.resolveForkCursor(previousBlocks);
40
+ }
41
+ flush() {
42
+ const buf = this.#native.flush();
43
+ return buf ? (0, msgpack_1.decode)(buf) : null;
44
+ }
45
+ ack(sequence) {
46
+ this.#native.ack(sequence);
47
+ }
48
+ get pendingCount() {
49
+ return this.#native.pendingCount;
50
+ }
51
+ get isBackpressured() {
52
+ return this.#native.isBackpressured;
53
+ }
54
+ get cursor() {
55
+ return this.#native.cursor;
56
+ }
57
+ registerReducer(options) {
58
+ const { reduce } = options;
59
+ const batchFn = (groups) => {
60
+ return groups.map(({ state, rows }) => {
61
+ let s = state;
62
+ const emits = [];
63
+ for (const row of rows) {
64
+ const [newState, emit] = reduce(s, row);
65
+ s = newState;
66
+ if (emit != null) {
67
+ if (Array.isArray(emit)) {
68
+ for (let i = 0; i < emit.length; i++)
69
+ emits.push(emit[i]);
70
+ }
71
+ else {
72
+ emits.push(emit);
73
+ }
74
+ }
75
+ }
76
+ return { state: s, emits };
77
+ });
78
+ };
79
+ this.#native.registerReducer({
80
+ name: options.name,
81
+ source: options.source,
82
+ groupBy: options.groupBy,
83
+ state: options.state,
84
+ }, batchFn);
85
+ }
86
+ }
87
+ exports.DeltaDb = DeltaDb;
88
+ //# sourceMappingURL=delta-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta-db.js","sourceRoot":"","sources":["../src/delta-db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './column';
2
+ export { type AggExpr, type AggProxy, type GroupByItem, type IntervalExpr, interval, type KeyRef, type ReducerOptions, type ViewOptions, } from './ddl';
3
+ export { type DeltaBatch, DeltaDb, type DeltaDbConfig, type DeltaDbCursor, type DeltaOperation, type DeltaRecord, type ExternalReducerOptions, type IngestInput, type StateFieldDef, } from './delta-db';
4
+ export { Pipeline, ReducerHandle, TableHandle, ViewHandle } from './pipeline';
5
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ViewHandle = exports.TableHandle = exports.ReducerHandle = exports.Pipeline = exports.DeltaDb = exports.interval = void 0;
18
+ __exportStar(require("./column"), exports);
19
+ var ddl_1 = require("./ddl");
20
+ Object.defineProperty(exports, "interval", { enumerable: true, get: function () { return ddl_1.interval; } });
21
+ var delta_db_1 = require("./delta-db");
22
+ Object.defineProperty(exports, "DeltaDb", { enumerable: true, get: function () { return delta_db_1.DeltaDb; } });
23
+ var pipeline_1 = require("./pipeline");
24
+ Object.defineProperty(exports, "Pipeline", { enumerable: true, get: function () { return pipeline_1.Pipeline; } });
25
+ Object.defineProperty(exports, "ReducerHandle", { enumerable: true, get: function () { return pipeline_1.ReducerHandle; } });
26
+ Object.defineProperty(exports, "TableHandle", { enumerable: true, get: function () { return pipeline_1.TableHandle; } });
27
+ Object.defineProperty(exports, "ViewHandle", { enumerable: true, get: function () { return pipeline_1.ViewHandle; } });
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAAwB;AACxB,6BASc;AAJZ,+FAAA,QAAQ,OAAA;AAKV,uCAUmB;AARjB,mGAAA,OAAO,OAAA;AAST,uCAA6E;AAApE,oGAAA,QAAQ,OAAA;AAAE,yGAAA,aAAa,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,sGAAA,UAAU,OAAA"}
@@ -1,3 +1,8 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
1
6
  /** Configuration for opening a DeltaDb instance. */
2
7
  export interface DeltaDbConfig {
3
8
  /** SQL schema definition string. */
@@ -10,69 +15,73 @@ export interface DeltaDbConfig {
10
15
  /** Maximum buffer size before backpressure (default: 10000). */
11
16
  maxBufferSize?: number
12
17
  }
13
-
14
18
  /** Block cursor: number + hash. */
15
19
  export interface DeltaDbCursor {
16
20
  number: number
17
21
  hash: string
18
22
  }
19
-
20
- export type DeltaOperation = 'insert' | 'update' | 'delete'
21
-
22
- export interface DeltaRecord {
23
- table: string
24
- operation: DeltaOperation
25
- key: Record<string, any>
26
- values: Record<string, any>
27
- prevValues: Record<string, any> | null
28
- }
29
-
30
- export interface DeltaBatch {
31
- sequence: number
32
- finalizedHead: DeltaDbCursor | null
33
- latestHead: DeltaDbCursor | null
34
- /** Records grouped by table name. */
35
- tables: Record<string, DeltaRecord[]>
36
- }
37
-
38
23
  /** Input for the atomic `ingest()` method. */
39
24
  export interface IngestInput {
40
- /** Table name → rows: `{tableName: [{col: val}, ...], ...}`. */
41
- data: Record<string, Record<string, any>[]>
25
+ /** Table name → rows, msgpack-encoded as `{tableName: [{col: val}, ...], ...}`. */
26
+ data: Buffer
42
27
  /** Unfinalized blocks with hashes for fork resolution. */
43
- rollbackChain?: DeltaDbCursor[]
28
+ rollbackChain?: Array<DeltaDbCursor>
44
29
  /** Finalized head cursor — both number and hash stored. */
45
30
  finalizedHead: DeltaDbCursor
46
- /** Called with each delta batch. When provided, batch is auto-acked. */
47
- onDelta?: (batch: DeltaBatch) => void
48
31
  }
49
-
50
- /** Delta DB wrapper. */
32
+ /** State field definition for external reducers. */
33
+ export interface ExternalStateField {
34
+ name: string
35
+ /** Column type: "Float64", "UInt64", "Int64", "String", "Boolean", "Json" */
36
+ columnType: string
37
+ /** Default value as a string literal (e.g., "0", "'hello'", "{}") */
38
+ defaultValue: string
39
+ }
40
+ /** Configuration for registering an external reducer. */
41
+ export interface ExternalReducerConfig {
42
+ name: string
43
+ source: string
44
+ groupBy: Array<string>
45
+ state: Array<ExternalStateField>
46
+ }
47
+ /** Delta DB N-API wrapper. */
51
48
  export declare class DeltaDb {
52
49
  /** Open a new DeltaDb instance. */
53
50
  static open(config: DeltaDbConfig): DeltaDb
51
+ /**
52
+ * Register an external reducer with a JS batch callback.
53
+ *
54
+ * The callback receives an array of `{ state, rows }` groups and must
55
+ * return an array of `{ state, emits }` results (same length, same order).
56
+ *
57
+ * Must be called before any `processBatch` or `ingest` calls.
58
+ */
59
+ registerReducer(config: ExternalReducerConfig, callback: (...args: any[]) => any): void
54
60
  /**
55
61
  * Process a batch of rows for a raw table.
62
+ * `rows` is a msgpack-encoded Buffer: `[{col: val, ...}, ...]`.
56
63
  * Returns true if backpressure should be applied.
57
64
  */
58
- processBatch(table: string, block: number, rows: Record<string, any>[]): boolean
65
+ processBatch(table: string, block: number, rows: Buffer): boolean
59
66
  /** Roll back all state after fork_point. */
60
67
  rollback(forkPoint: number): void
61
68
  /** Finalize all state up to and including the given block. */
62
69
  finalize(block: number): void
63
70
  /**
64
71
  * Atomic ingest: process all tables, store rollback chain, finalize, flush.
65
- * Returns the delta batch, or null if no records produced.
66
- * When `onDelta` is provided in input, it is called and batch is auto-acked.
72
+ * Returns a msgpack-encoded DeltaBatch buffer, or null if no records produced.
67
73
  */
68
- ingest(input: IngestInput): DeltaBatch | null
74
+ ingest(input: IngestInput): Buffer | null
69
75
  /**
70
76
  * Find the common ancestor between our state and the Portal's chain.
71
77
  * Returns the matching block cursor, or null if no common ancestor found.
72
78
  */
73
- resolveForkCursor(previousBlocks: DeltaDbCursor[]): DeltaDbCursor | null
74
- /** Flush buffered deltas into a batch. Returns null if no pending records. */
75
- flush(): DeltaBatch | null
79
+ resolveForkCursor(previousBlocks: Array<DeltaDbCursor>): DeltaDbCursor | null
80
+ /**
81
+ * Flush buffered deltas into a msgpack-encoded batch.
82
+ * Returns null if no pending records.
83
+ */
84
+ flush(): Buffer | null
76
85
  /** Acknowledge a flushed batch by sequence number. */
77
86
  ack(sequence: number): void
78
87
  /** Number of pending (unflushed) delta records. */
@@ -1,7 +1,6 @@
1
1
  /* Platform-aware native module loader for @sqd-pipes/delta-db */
2
-
3
- const { existsSync } = require('fs')
4
- const { join } = require('path')
2
+ const { existsSync } = require('node:fs')
3
+ const { join } = require('node:path')
5
4
 
6
5
  const { platform, arch } = process
7
6
 
@@ -17,6 +16,7 @@ function getPlatformFile() {
17
16
  }
18
17
 
19
18
  const key = `${platform}-${arch}`
19
+ // @ts-ignore
20
20
  return suffixes[key] ? `delta-db.${suffixes[key]}.node` : null
21
21
  }
22
22
 
@@ -50,6 +50,7 @@ if (!nativeBinding) {
50
50
  `Failed to load native binding for ${platform}-${arch}.`,
51
51
  platformFile ? `Looked for: ${platformFile}` : `Unsupported platform: ${platform}-${arch}`,
52
52
  '',
53
+ // @ts-ignore
53
54
  loadError ? `Error: ${loadError.message}` : '',
54
55
  '',
55
56
  'Build from source: npm run build',
@@ -0,0 +1,33 @@
1
+ import type { ColumnType, InferRow } from './column';
2
+ import { type ReducerOptions, type ViewOptions } from './ddl';
3
+ import { DeltaDb } from './delta-db';
4
+ export declare class Pipeline {
5
+ #private;
6
+ table<TCols extends Record<string, ColumnType>>(name: string, columns: TCols, opts?: {
7
+ virtual?: boolean;
8
+ }): TableHandle<InferRow<TCols>>;
9
+ build(opts?: {
10
+ dataDir?: string;
11
+ maxBufferSize?: number;
12
+ }): DeltaDb;
13
+ }
14
+ export declare class TableHandle<TRow = any> {
15
+ #private;
16
+ constructor(pipeline: Pipeline, name: string);
17
+ get name(): string;
18
+ createReducer<TState, TEmit>(name: string, opts: ReducerOptions<TState, TRow, TEmit>): ReducerHandle<TEmit>;
19
+ createView(name: string, opts: ViewOptions<TRow>): ViewHandle;
20
+ }
21
+ export declare class ReducerHandle<TOutput = any> {
22
+ #private;
23
+ constructor(pipeline: Pipeline, name: string);
24
+ get name(): string;
25
+ createReducer<TState, TEmit>(name: string, opts: ReducerOptions<TState, TOutput, TEmit>): ReducerHandle<TEmit>;
26
+ createView(name: string, opts: ViewOptions<TOutput>): ViewHandle;
27
+ }
28
+ export declare class ViewHandle {
29
+ #private;
30
+ constructor(name: string);
31
+ get name(): string;
32
+ }
33
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ViewHandle = exports.ReducerHandle = exports.TableHandle = exports.Pipeline = void 0;
4
+ const ddl_1 = require("./ddl");
5
+ const delta_db_1 = require("./delta-db");
6
+ // ─── Pipeline ────────────────────────────────────────────────────
7
+ class Pipeline {
8
+ #tables = [];
9
+ #reducers = [];
10
+ #views = [];
11
+ table(name, columns, opts) {
12
+ this.#tables.push({ name, columns, virtual: opts?.virtual ?? false });
13
+ return new TableHandle(this, name);
14
+ }
15
+ /** @internal */
16
+ _addReducer(name, source, opts) {
17
+ const groupBy = Array.isArray(opts.groupBy) ? opts.groupBy : [opts.groupBy];
18
+ const stateFields = (0, ddl_1.inferStateFields)(opts.initialState);
19
+ this.#reducers.push({ name, source, groupBy, stateFields, reduce: opts.reduce });
20
+ return new ReducerHandle(this, name);
21
+ }
22
+ /** @internal */
23
+ _addView(name, source, opts) {
24
+ const groupByItems = Array.isArray(opts.groupBy) ? opts.groupBy : [opts.groupBy];
25
+ const sql = (0, ddl_1.viewToSql)(name, source, groupByItems, opts.select);
26
+ this.#views.push({ sql });
27
+ return new ViewHandle(name);
28
+ }
29
+ build(opts) {
30
+ const ddl = [];
31
+ for (const t of this.#tables) {
32
+ ddl.push((0, ddl_1.tableToSql)(t.name, t.columns, t.virtual));
33
+ }
34
+ for (const r of this.#reducers) {
35
+ ddl.push((0, ddl_1.reducerToSql)(r.name, r.source, r.groupBy, r.stateFields));
36
+ }
37
+ for (const v of this.#views) {
38
+ ddl.push(v.sql);
39
+ }
40
+ // ':memory:' (or omitted) uses in-memory storage — same convention as SQLite
41
+ const dataDir = opts?.dataDir === ':memory:' ? undefined : opts?.dataDir;
42
+ const db = delta_db_1.DeltaDb.open({
43
+ schema: ddl.join('\n'),
44
+ dataDir,
45
+ maxBufferSize: opts?.maxBufferSize,
46
+ });
47
+ for (const r of this.#reducers) {
48
+ db.registerReducer({
49
+ name: r.name,
50
+ source: r.source,
51
+ groupBy: r.groupBy,
52
+ state: r.stateFields,
53
+ reduce: r.reduce,
54
+ });
55
+ }
56
+ return db;
57
+ }
58
+ }
59
+ exports.Pipeline = Pipeline;
60
+ // ─── Handles ─────────────────────────────────────────────────────
61
+ class TableHandle {
62
+ #pipeline;
63
+ #name;
64
+ constructor(pipeline, name) {
65
+ this.#pipeline = pipeline;
66
+ this.#name = name;
67
+ }
68
+ get name() {
69
+ return this.#name;
70
+ }
71
+ createReducer(name, opts) {
72
+ return this.#pipeline._addReducer(name, this.#name, opts);
73
+ }
74
+ createView(name, opts) {
75
+ return this.#pipeline._addView(name, this.#name, opts);
76
+ }
77
+ }
78
+ exports.TableHandle = TableHandle;
79
+ class ReducerHandle {
80
+ #pipeline;
81
+ #name;
82
+ constructor(pipeline, name) {
83
+ this.#pipeline = pipeline;
84
+ this.#name = name;
85
+ }
86
+ get name() {
87
+ return this.#name;
88
+ }
89
+ createReducer(name, opts) {
90
+ return this.#pipeline._addReducer(name, this.#name, opts);
91
+ }
92
+ createView(name, opts) {
93
+ return this.#pipeline._addView(name, this.#name, opts);
94
+ }
95
+ }
96
+ exports.ReducerHandle = ReducerHandle;
97
+ class ViewHandle {
98
+ #name;
99
+ constructor(name) {
100
+ this.#name = name;
101
+ }
102
+ get name() {
103
+ return this.#name;
104
+ }
105
+ }
106
+ exports.ViewHandle = ViewHandle;
107
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,31 +1,40 @@
1
1
  {
2
2
  "name": "@sqd-pipes/delta-db",
3
- "version": "0.0.1-alpha.7",
3
+ "version": "0.0.1-alpha.8",
4
4
  "description": "Embedded rollback-aware computation engine for blockchain data",
5
- "main": "src/index.js",
6
- "types": "src/index.d.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "napi": {
8
8
  "name": "delta-db"
9
9
  },
10
10
  "scripts": {
11
- "build": "napi build --cargo-cwd ../../.. --features napi --release --platform --dts native.d.ts --js false src",
12
- "build:debug": "napi build --cargo-cwd ../../.. --features napi --platform --dts native.d.ts --js false src",
11
+ "build:native": "napi build --cargo-cwd ../../.. --features napi --release --platform --dts native.d.ts --js false src/native",
12
+ "build:native:debug": "napi build --cargo-cwd ../../.. --features napi --platform --dts native.d.ts --js false src/native",
13
+ "build:ts": "tsc -p tsconfig.build.json && cp -r src/native dist/native",
14
+ "build": "pnpm run build:native && pnpm run build:ts",
13
15
  "artifacts": "napi artifacts",
14
16
  "test": "vitest run",
15
- "test:watch": "vitest"
17
+ "test:watch": "vitest",
18
+ "lint": "biome check",
19
+ "lint:fix": "biome check --fix"
16
20
  },
17
21
  "dependencies": {
18
22
  "@msgpack/msgpack": "^3.0.0"
19
23
  },
20
24
  "devDependencies": {
25
+ "@biomejs/biome": "^2.4.7",
21
26
  "@napi-rs/cli": "^2.18.0",
27
+ "@types/node": "^25.5.0",
28
+ "typescript": "^5.9.3",
22
29
  "vitest": "^3.0.0"
23
30
  },
24
31
  "files": [
25
- "src/index.js",
26
- "src/index.d.ts",
27
- "src/native.js",
28
- "src/*.node"
32
+ "dist/**/*.js",
33
+ "dist/**/*.d.ts",
34
+ "dist/**/*.js.map",
35
+ "src/native/native.js",
36
+ "src/native/native.d.ts",
37
+ "src/native/*.node"
29
38
  ],
30
39
  "license": "MIT"
31
40
  }
@@ -0,0 +1,93 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /** Configuration for opening a DeltaDb instance. */
7
+ export interface DeltaDbConfig {
8
+ /** SQL schema definition string. */
9
+ schema: string
10
+ /**
11
+ * Path to RocksDB data directory for persistence.
12
+ * When omitted, uses in-memory storage (data lost on restart).
13
+ */
14
+ dataDir?: string
15
+ /** Maximum buffer size before backpressure (default: 10000). */
16
+ maxBufferSize?: number
17
+ }
18
+ /** Block cursor: number + hash. */
19
+ export interface DeltaDbCursor {
20
+ number: number
21
+ hash: string
22
+ }
23
+ /** Input for the atomic `ingest()` method. */
24
+ export interface IngestInput {
25
+ /** Table name → rows, msgpack-encoded as `{tableName: [{col: val}, ...], ...}`. */
26
+ data: Buffer
27
+ /** Unfinalized blocks with hashes for fork resolution. */
28
+ rollbackChain?: Array<DeltaDbCursor>
29
+ /** Finalized head cursor — both number and hash stored. */
30
+ finalizedHead: DeltaDbCursor
31
+ }
32
+ /** State field definition for external reducers. */
33
+ export interface ExternalStateField {
34
+ name: string
35
+ /** Column type: "Float64", "UInt64", "Int64", "String", "Boolean", "Json" */
36
+ columnType: string
37
+ /** Default value as a string literal (e.g., "0", "'hello'", "{}") */
38
+ defaultValue: string
39
+ }
40
+ /** Configuration for registering an external reducer. */
41
+ export interface ExternalReducerConfig {
42
+ name: string
43
+ source: string
44
+ groupBy: Array<string>
45
+ state: Array<ExternalStateField>
46
+ }
47
+ /** Delta DB N-API wrapper. */
48
+ export declare class DeltaDb {
49
+ /** Open a new DeltaDb instance. */
50
+ static open(config: DeltaDbConfig): DeltaDb
51
+ /**
52
+ * Register an external reducer with a JS batch callback.
53
+ *
54
+ * The callback receives an array of `{ state, rows }` groups and must
55
+ * return an array of `{ state, emits }` results (same length, same order).
56
+ *
57
+ * Must be called before any `processBatch` or `ingest` calls.
58
+ */
59
+ registerReducer(config: ExternalReducerConfig, callback: (...args: any[]) => any): void
60
+ /**
61
+ * Process a batch of rows for a raw table.
62
+ * `rows` is a msgpack-encoded Buffer: `[{col: val, ...}, ...]`.
63
+ * Returns true if backpressure should be applied.
64
+ */
65
+ processBatch(table: string, block: number, rows: Buffer): boolean
66
+ /** Roll back all state after fork_point. */
67
+ rollback(forkPoint: number): void
68
+ /** Finalize all state up to and including the given block. */
69
+ finalize(block: number): void
70
+ /**
71
+ * Atomic ingest: process all tables, store rollback chain, finalize, flush.
72
+ * Returns a msgpack-encoded DeltaBatch buffer, or null if no records produced.
73
+ */
74
+ ingest(input: IngestInput): Buffer | null
75
+ /**
76
+ * Find the common ancestor between our state and the Portal's chain.
77
+ * Returns the matching block cursor, or null if no common ancestor found.
78
+ */
79
+ resolveForkCursor(previousBlocks: Array<DeltaDbCursor>): DeltaDbCursor | null
80
+ /**
81
+ * Flush buffered deltas into a msgpack-encoded batch.
82
+ * Returns null if no pending records.
83
+ */
84
+ flush(): Buffer | null
85
+ /** Acknowledge a flushed batch by sequence number. */
86
+ ack(sequence: number): void
87
+ /** Number of pending (unflushed) delta records. */
88
+ get pendingCount(): number
89
+ /** Whether backpressure should be applied. */
90
+ get isBackpressured(): boolean
91
+ /** Current cursor: latest processed block + hash. Null if no blocks processed. */
92
+ get cursor(): DeltaDbCursor | null
93
+ }
@@ -0,0 +1,61 @@
1
+ /* Platform-aware native module loader for @sqd-pipes/delta-db */
2
+ const { existsSync } = require('node:fs')
3
+ const { join } = require('node:path')
4
+
5
+ const { platform, arch } = process
6
+
7
+ let nativeBinding = null
8
+ let loadError = null
9
+
10
+ function getPlatformFile() {
11
+ const suffixes = {
12
+ 'darwin-x64': 'darwin-x64',
13
+ 'darwin-arm64': 'darwin-arm64',
14
+ 'linux-x64': 'linux-x64-gnu',
15
+ 'linux-arm64': 'linux-arm64-gnu',
16
+ }
17
+
18
+ const key = `${platform}-${arch}`
19
+ // @ts-ignore
20
+ return suffixes[key] ? `delta-db.${suffixes[key]}.node` : null
21
+ }
22
+
23
+ // Try platform-specific file (e.g. delta-db.linux-x64-gnu.node)
24
+ const platformFile = getPlatformFile()
25
+ if (platformFile) {
26
+ const platformPath = join(__dirname, platformFile)
27
+ if (existsSync(platformPath)) {
28
+ try {
29
+ nativeBinding = require(platformPath)
30
+ } catch (e) {
31
+ loadError = e
32
+ }
33
+ }
34
+ }
35
+
36
+ // Fallback: try unqualified .node file (local dev build)
37
+ if (!nativeBinding) {
38
+ const localFile = join(__dirname, 'delta-db.node')
39
+ if (existsSync(localFile)) {
40
+ try {
41
+ nativeBinding = require(localFile)
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ }
46
+ }
47
+
48
+ if (!nativeBinding) {
49
+ const help = [
50
+ `Failed to load native binding for ${platform}-${arch}.`,
51
+ platformFile ? `Looked for: ${platformFile}` : `Unsupported platform: ${platform}-${arch}`,
52
+ '',
53
+ // @ts-ignore
54
+ loadError ? `Error: ${loadError.message}` : '',
55
+ '',
56
+ 'Build from source: npm run build',
57
+ ].join('\n')
58
+ throw new Error(help)
59
+ }
60
+
61
+ module.exports = nativeBinding
Binary file
package/src/index.js DELETED
@@ -1,91 +0,0 @@
1
- const { DeltaDb: NativeDeltaDb } = require('./native.js')
2
- const { Encoder, decode } = require('@msgpack/msgpack')
3
-
4
- const encoder = new Encoder({ useBigInt64: true })
5
-
6
- class DeltaDb {
7
- /** @type {InstanceType<typeof NativeDeltaDb>} */
8
- #native
9
-
10
- /** @param {InstanceType<typeof NativeDeltaDb>} native */
11
- constructor(native) {
12
- this.#native = native
13
- }
14
-
15
- /** Open a new DeltaDb instance. */
16
- static open(config) {
17
- return new DeltaDb(NativeDeltaDb.open(config))
18
- }
19
-
20
- /**
21
- * Process a batch of rows for a raw table.
22
- * Returns true if backpressure should be applied.
23
- */
24
- processBatch(table, block, rows) {
25
- return this.#native.processBatch(table, block, Buffer.from(encoder.encode(rows)))
26
- }
27
-
28
- /** Roll back all state after fork_point. */
29
- rollback(forkPoint) {
30
- this.#native.rollback(forkPoint)
31
- }
32
-
33
- /** Finalize all state up to and including the given block. */
34
- finalize(block) {
35
- this.#native.finalize(block)
36
- }
37
-
38
- /**
39
- * Atomic ingest: process all tables, store rollback chain, finalize, flush.
40
- * Returns the delta batch, or null if no records produced.
41
- */
42
- ingest(input) {
43
- const buf = this.#native.ingest({
44
- data: Buffer.from(encoder.encode(input.data)),
45
- rollbackChain: input.rollbackChain,
46
- finalizedHead: input.finalizedHead,
47
- })
48
- const batch = buf ? decode(buf) : null
49
- if (batch && input.onDelta) {
50
- input.onDelta(batch)
51
- this.#native.ack(batch.sequence)
52
- }
53
- return batch
54
- }
55
-
56
- /**
57
- * Find the common ancestor between our state and the Portal's chain.
58
- * Returns the matching block cursor, or null if no common ancestor found.
59
- */
60
- resolveForkCursor(previousBlocks) {
61
- return this.#native.resolveForkCursor(previousBlocks)
62
- }
63
-
64
- /** Flush buffered deltas into a batch. Returns null if no pending records. */
65
- flush() {
66
- const buf = this.#native.flush()
67
- return buf ? decode(buf) : null
68
- }
69
-
70
- /** Acknowledge a flushed batch by sequence number. */
71
- ack(sequence) {
72
- this.#native.ack(sequence)
73
- }
74
-
75
- /** Number of pending (unflushed) delta records. */
76
- get pendingCount() {
77
- return this.#native.pendingCount
78
- }
79
-
80
- /** Whether backpressure should be applied. */
81
- get isBackpressured() {
82
- return this.#native.isBackpressured
83
- }
84
-
85
- /** Current cursor: latest processed block + hash. Null if no blocks processed. */
86
- get cursor() {
87
- return this.#native.cursor
88
- }
89
- }
90
-
91
- module.exports.DeltaDb = DeltaDb