@apibara/indexer 2.0.0-beta.0 → 2.0.0-beta.3
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/package.json +30 -19
- package/src/context.ts +8 -3
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSink.ts +13 -0
- package/src/index.ts +1 -0
- package/src/indexer.test.ts +70 -41
- package/src/indexer.ts +168 -168
- package/src/plugins/config.ts +4 -4
- package/src/plugins/kv.ts +2 -2
- package/src/plugins/persistence.test.ts +10 -6
- package/src/plugins/persistence.ts +3 -3
- package/src/sink.ts +21 -24
- package/src/sinks/csv.test.ts +15 -3
- package/src/sinks/csv.ts +68 -7
- package/src/sinks/drizzle/Int8Range.ts +52 -0
- package/src/sinks/drizzle/delete.ts +42 -0
- package/src/sinks/drizzle/drizzle.test.ts +239 -0
- package/src/sinks/drizzle/drizzle.ts +115 -0
- package/src/sinks/drizzle/index.ts +6 -0
- package/src/sinks/drizzle/insert.ts +39 -0
- package/src/sinks/drizzle/select.ts +44 -0
- package/src/sinks/drizzle/transaction.ts +49 -0
- package/src/sinks/drizzle/update.ts +47 -0
- package/src/sinks/drizzle/utils.ts +36 -0
- package/src/sinks/sqlite.test.ts +13 -1
- package/src/sinks/sqlite.ts +65 -5
- package/src/testing/indexer.ts +15 -8
- package/src/testing/setup.ts +5 -5
- package/src/testing/vcr.ts +42 -4
- package/src/vcr/record.ts +2 -2
- package/src/vcr/replay.ts +3 -3
- package/.turbo/turbo-build.log +0 -37
- package/CHANGELOG.md +0 -83
- package/LICENSE.txt +0 -202
- package/build.config.ts +0 -16
- package/dist/index.cjs +0 -34
- package/dist/index.d.cts +0 -21
- package/dist/index.d.mts +0 -21
- package/dist/index.d.ts +0 -21
- package/dist/index.mjs +0 -19
- package/dist/shared/indexer.371c0482.mjs +0 -15
- package/dist/shared/indexer.3852a4d3.d.ts +0 -91
- package/dist/shared/indexer.50aa7ab0.mjs +0 -268
- package/dist/shared/indexer.7c118fb5.d.cts +0 -28
- package/dist/shared/indexer.7c118fb5.d.mts +0 -28
- package/dist/shared/indexer.7c118fb5.d.ts +0 -28
- package/dist/shared/indexer.a27bcb35.d.cts +0 -91
- package/dist/shared/indexer.c8ef02ea.cjs +0 -289
- package/dist/shared/indexer.e05aedca.cjs +0 -19
- package/dist/shared/indexer.f7dd57e5.d.mts +0 -91
- package/dist/sinks/csv.cjs +0 -66
- package/dist/sinks/csv.d.cts +0 -34
- package/dist/sinks/csv.d.mts +0 -34
- package/dist/sinks/csv.d.ts +0 -34
- package/dist/sinks/csv.mjs +0 -59
- package/dist/sinks/sqlite.cjs +0 -71
- package/dist/sinks/sqlite.d.cts +0 -41
- package/dist/sinks/sqlite.d.mts +0 -41
- package/dist/sinks/sqlite.d.ts +0 -41
- package/dist/sinks/sqlite.mjs +0 -68
- package/dist/testing/index.cjs +0 -63
- package/dist/testing/index.d.cts +0 -29
- package/dist/testing/index.d.mts +0 -29
- package/dist/testing/index.d.ts +0 -29
- package/dist/testing/index.mjs +0 -59
- package/tsconfig.json +0 -11
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs$1 = require('node:fs/promises');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
const hookable = require('hookable');
|
|
6
|
-
const full = require('klona/full');
|
|
7
|
-
const assert = require('node:assert');
|
|
8
|
-
const fs = require('node:fs');
|
|
9
|
-
const testing = require('@apibara/protocol/testing');
|
|
10
|
-
const consola = require('consola');
|
|
11
|
-
const node_async_hooks = require('node:async_hooks');
|
|
12
|
-
const unctx = require('unctx');
|
|
13
|
-
const api = require('@opentelemetry/api');
|
|
14
|
-
const sink = require('./indexer.e05aedca.cjs');
|
|
15
|
-
|
|
16
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
17
|
-
|
|
18
|
-
const fs__default$1 = /*#__PURE__*/_interopDefaultCompat(fs$1);
|
|
19
|
-
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
20
|
-
const assert__default = /*#__PURE__*/_interopDefaultCompat(assert);
|
|
21
|
-
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
22
|
-
const consola__default = /*#__PURE__*/_interopDefaultCompat(consola);
|
|
23
|
-
|
|
24
|
-
const indexerAsyncContext = unctx.getContext("indexer", {
|
|
25
|
-
asyncContext: true,
|
|
26
|
-
AsyncLocalStorage: node_async_hooks.AsyncLocalStorage
|
|
27
|
-
});
|
|
28
|
-
function useIndexerContext() {
|
|
29
|
-
return indexerAsyncContext.use();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const tracer = api.trace.getTracer("@apibara/indexer");
|
|
33
|
-
|
|
34
|
-
function defineIndexer(streamConfig) {
|
|
35
|
-
return (config) => ({
|
|
36
|
-
streamConfig,
|
|
37
|
-
...config
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
function createIndexer({
|
|
41
|
-
streamConfig,
|
|
42
|
-
...options
|
|
43
|
-
}) {
|
|
44
|
-
const indexer = {
|
|
45
|
-
options,
|
|
46
|
-
streamConfig,
|
|
47
|
-
hooks: hookable.createHooks()
|
|
48
|
-
};
|
|
49
|
-
if (indexer.options.debug) {
|
|
50
|
-
hookable.createDebugger(indexer.hooks, { tag: "indexer" });
|
|
51
|
-
}
|
|
52
|
-
indexer.hooks.addHooks(indexer.options.hooks ?? {});
|
|
53
|
-
for (const plugin of indexer.options.plugins ?? []) {
|
|
54
|
-
plugin(indexer);
|
|
55
|
-
}
|
|
56
|
-
return indexer;
|
|
57
|
-
}
|
|
58
|
-
async function run(client, indexer, sinkArg) {
|
|
59
|
-
await indexerAsyncContext.callAsync({}, async () => {
|
|
60
|
-
await indexer.hooks.callHook("run:before");
|
|
61
|
-
const sink$1 = sinkArg ?? sink.defaultSink();
|
|
62
|
-
sink$1.hook("write", async ({ data }) => {
|
|
63
|
-
await indexer.hooks.callHook("sink:write", { data });
|
|
64
|
-
});
|
|
65
|
-
sink$1.hook("flush", async ({ endCursor, finality }) => {
|
|
66
|
-
await indexer.hooks.callHook("sink:flush", { endCursor, finality });
|
|
67
|
-
});
|
|
68
|
-
const isFactoryMode = indexer.options.factory !== void 0;
|
|
69
|
-
const request = indexer.streamConfig.Request.make({
|
|
70
|
-
filter: isFactoryMode ? [indexer.options.filter, {}] : [indexer.options.filter],
|
|
71
|
-
finality: indexer.options.finality,
|
|
72
|
-
startingCursor: indexer.options.startingCursor
|
|
73
|
-
});
|
|
74
|
-
const options = {};
|
|
75
|
-
await indexer.hooks.callHook("connect:before", { request, options });
|
|
76
|
-
let mainFilter;
|
|
77
|
-
if (isFactoryMode) {
|
|
78
|
-
mainFilter = request.filter[1];
|
|
79
|
-
}
|
|
80
|
-
let stream = client.streamData(request, options);
|
|
81
|
-
await indexer.hooks.callHook("connect:after");
|
|
82
|
-
let state = {
|
|
83
|
-
_tag: "normal"
|
|
84
|
-
};
|
|
85
|
-
while (true) {
|
|
86
|
-
for await (const message of stream) {
|
|
87
|
-
await indexer.hooks.callHook("message", { message });
|
|
88
|
-
switch (message._tag) {
|
|
89
|
-
case "data": {
|
|
90
|
-
await tracer.startActiveSpan("message data", async (span) => {
|
|
91
|
-
const blocks = message.data.data;
|
|
92
|
-
const { cursor, endCursor, finality } = message.data;
|
|
93
|
-
let block;
|
|
94
|
-
const output = [];
|
|
95
|
-
if (isFactoryMode) {
|
|
96
|
-
assert__default(indexer.options.factory !== void 0);
|
|
97
|
-
const [factoryBlock, mainBlock] = blocks;
|
|
98
|
-
block = mainBlock;
|
|
99
|
-
if (state._tag === "normal" && factoryBlock !== null) {
|
|
100
|
-
const { data, filter } = await indexer.options.factory(factoryBlock);
|
|
101
|
-
if (!filter) {
|
|
102
|
-
output.push(...data ?? []);
|
|
103
|
-
} else {
|
|
104
|
-
mainFilter = indexer.streamConfig.mergeFilter(
|
|
105
|
-
mainFilter,
|
|
106
|
-
filter
|
|
107
|
-
);
|
|
108
|
-
const request2 = indexer.streamConfig.Request.make({
|
|
109
|
-
filter: [indexer.options.filter, mainFilter],
|
|
110
|
-
finality: indexer.options.finality,
|
|
111
|
-
startingCursor: cursor
|
|
112
|
-
});
|
|
113
|
-
await indexer.hooks.callHook("connect:factory", {
|
|
114
|
-
request: request2,
|
|
115
|
-
endCursor
|
|
116
|
-
});
|
|
117
|
-
stream = client.streamData(request2, options);
|
|
118
|
-
state = {
|
|
119
|
-
_tag: "recover",
|
|
120
|
-
data
|
|
121
|
-
};
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
} else if (state._tag === "recover") {
|
|
125
|
-
output.push(...state.data ?? []);
|
|
126
|
-
state = { _tag: "normal" };
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
block = blocks[0];
|
|
130
|
-
}
|
|
131
|
-
if (block) {
|
|
132
|
-
await tracer.startActiveSpan("handler", async (span2) => {
|
|
133
|
-
await indexer.hooks.callHook("handler:before", {
|
|
134
|
-
block,
|
|
135
|
-
endCursor,
|
|
136
|
-
finality
|
|
137
|
-
});
|
|
138
|
-
try {
|
|
139
|
-
const transformOutput = await indexer.options.transform({
|
|
140
|
-
block,
|
|
141
|
-
cursor,
|
|
142
|
-
endCursor,
|
|
143
|
-
finality
|
|
144
|
-
});
|
|
145
|
-
output.push(...transformOutput);
|
|
146
|
-
await indexer.hooks.callHook("handler:after", { output });
|
|
147
|
-
} catch (error) {
|
|
148
|
-
assert__default(error instanceof Error);
|
|
149
|
-
await indexer.hooks.callHook("handler:exception", {
|
|
150
|
-
error
|
|
151
|
-
});
|
|
152
|
-
throw error;
|
|
153
|
-
}
|
|
154
|
-
span2.end();
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
if (output.length > 0) {
|
|
158
|
-
await tracer.startActiveSpan("sink write", async (span2) => {
|
|
159
|
-
await sink$1.write({
|
|
160
|
-
data: output,
|
|
161
|
-
cursor,
|
|
162
|
-
endCursor,
|
|
163
|
-
finality
|
|
164
|
-
});
|
|
165
|
-
span2.end();
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
span.end();
|
|
169
|
-
});
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
default: {
|
|
173
|
-
consola__default.warn("unexpected message", message);
|
|
174
|
-
throw new Error("not implemented");
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (state._tag !== "normal") {
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (state._tag !== "normal") {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
await indexer.hooks.callHook("run:after");
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function deserialize(str) {
|
|
191
|
-
return JSON.parse(
|
|
192
|
-
str,
|
|
193
|
-
(_, value) => typeof value === "string" && value.match(/^\d+n$/) ? BigInt(value.slice(0, -1)) : value
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
function serialize(obj) {
|
|
197
|
-
return JSON.stringify(
|
|
198
|
-
obj,
|
|
199
|
-
(_, value) => typeof value === "bigint" ? `${value.toString()}n` : value,
|
|
200
|
-
" "
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
function isCassetteAvailable(vcrConfig, cassetteName) {
|
|
204
|
-
const filePath = path__default.join(vcrConfig.cassetteDir, `${cassetteName}.json`);
|
|
205
|
-
return fs__default.existsSync(filePath);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async function record(vcrConfig, client, indexerArg, cassetteOptions) {
|
|
209
|
-
const indexer = full.klona(indexerArg);
|
|
210
|
-
const messages = [];
|
|
211
|
-
indexer.hooks.addHooks({
|
|
212
|
-
"connect:before"({ options, request }) {
|
|
213
|
-
request.startingCursor = cassetteOptions.startingCursor;
|
|
214
|
-
options.endingCursor = cassetteOptions.endingCursor;
|
|
215
|
-
},
|
|
216
|
-
message({ message }) {
|
|
217
|
-
messages.push(message);
|
|
218
|
-
},
|
|
219
|
-
async "run:after"() {
|
|
220
|
-
const output = {
|
|
221
|
-
filter: indexer.options.filter,
|
|
222
|
-
messages
|
|
223
|
-
};
|
|
224
|
-
const filePath = path__default.join(
|
|
225
|
-
vcrConfig.cassetteDir,
|
|
226
|
-
`${cassetteOptions.name}.json`
|
|
227
|
-
);
|
|
228
|
-
await fs__default$1.writeFile(filePath, serialize(output), { flag: "w" });
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
await run(client, indexer);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
var __defProp = Object.defineProperty;
|
|
235
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
236
|
-
var __publicField = (obj, key, value) => {
|
|
237
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
238
|
-
return value;
|
|
239
|
-
};
|
|
240
|
-
class VcrSink extends sink.Sink {
|
|
241
|
-
constructor() {
|
|
242
|
-
super(...arguments);
|
|
243
|
-
__publicField(this, "result", []);
|
|
244
|
-
}
|
|
245
|
-
async write({ data, endCursor, finality }) {
|
|
246
|
-
await this.callHook("write", { data });
|
|
247
|
-
this.result.push({ data, endCursor });
|
|
248
|
-
await this.callHook("flush", { endCursor, finality });
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
function vcr() {
|
|
252
|
-
return new VcrSink();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async function replay(vcrConfig, indexer, cassetteName) {
|
|
256
|
-
const client = loadCassette(vcrConfig, cassetteName);
|
|
257
|
-
const sink = vcr();
|
|
258
|
-
await run(client, indexer, sink);
|
|
259
|
-
return {
|
|
260
|
-
outputs: sink.result
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function loadCassette(vcrConfig, cassetteName) {
|
|
264
|
-
const filePath = path__default.join(vcrConfig.cassetteDir, `${cassetteName}.json`);
|
|
265
|
-
const data = fs__default.readFileSync(filePath, "utf8");
|
|
266
|
-
const cassetteData = deserialize(data);
|
|
267
|
-
const { filter, messages } = cassetteData;
|
|
268
|
-
return new testing.MockClient((request, options) => {
|
|
269
|
-
assert__default.deepStrictEqual(
|
|
270
|
-
request.filter,
|
|
271
|
-
filter,
|
|
272
|
-
"Request and Cassette filter mismatch"
|
|
273
|
-
);
|
|
274
|
-
return messages;
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
exports.VcrSink = VcrSink;
|
|
279
|
-
exports.createIndexer = createIndexer;
|
|
280
|
-
exports.defineIndexer = defineIndexer;
|
|
281
|
-
exports.deserialize = deserialize;
|
|
282
|
-
exports.isCassetteAvailable = isCassetteAvailable;
|
|
283
|
-
exports.loadCassette = loadCassette;
|
|
284
|
-
exports.record = record;
|
|
285
|
-
exports.replay = replay;
|
|
286
|
-
exports.run = run;
|
|
287
|
-
exports.serialize = serialize;
|
|
288
|
-
exports.useIndexerContext = useIndexerContext;
|
|
289
|
-
exports.vcr = vcr;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const hookable = require('hookable');
|
|
4
|
-
|
|
5
|
-
class Sink extends hookable.Hookable {
|
|
6
|
-
}
|
|
7
|
-
class DefaultSink extends Sink {
|
|
8
|
-
async write({ data, endCursor, finality }) {
|
|
9
|
-
await this.callHook("write", { data });
|
|
10
|
-
await this.callHook("flush", { endCursor, finality });
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function defaultSink() {
|
|
14
|
-
return new DefaultSink();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
exports.DefaultSink = DefaultSink;
|
|
18
|
-
exports.Sink = Sink;
|
|
19
|
-
exports.defaultSink = defaultSink;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { StreamDataRequest, StreamDataOptions, Cursor, DataFinality, StreamDataResponse, StreamConfig, Client } from '@apibara/protocol';
|
|
2
|
-
import { NestedHooks, Hookable } from 'hookable';
|
|
3
|
-
import { c as Sink, S as SinkData } from './indexer.7c118fb5.mjs';
|
|
4
|
-
|
|
5
|
-
type IndexerPlugin<TFilter, TBlock, TRet> = (indexer: Indexer<TFilter, TBlock, TRet>) => void;
|
|
6
|
-
declare function defineIndexerPlugin<TFilter, TBlock, TRet>(def: IndexerPlugin<TFilter, TBlock, TRet>): IndexerPlugin<TFilter, TBlock, TRet>;
|
|
7
|
-
|
|
8
|
-
interface IndexerHooks<TFilter, TBlock, TRet> {
|
|
9
|
-
"run:before": () => void;
|
|
10
|
-
"run:after": () => void;
|
|
11
|
-
"connect:before": ({ request, options, }: {
|
|
12
|
-
request: StreamDataRequest<TFilter>;
|
|
13
|
-
options: StreamDataOptions;
|
|
14
|
-
}) => void;
|
|
15
|
-
"connect:after": () => void;
|
|
16
|
-
"connect:factory": ({ request, endCursor, }: {
|
|
17
|
-
request: StreamDataRequest<TFilter>;
|
|
18
|
-
endCursor?: Cursor;
|
|
19
|
-
}) => void;
|
|
20
|
-
"handler:before": ({ block, finality, endCursor, }: {
|
|
21
|
-
block: TBlock;
|
|
22
|
-
finality: DataFinality;
|
|
23
|
-
endCursor?: Cursor;
|
|
24
|
-
}) => void;
|
|
25
|
-
"handler:after": ({ output }: {
|
|
26
|
-
output: TRet[];
|
|
27
|
-
}) => void;
|
|
28
|
-
"handler:exception": ({ error }: {
|
|
29
|
-
error: Error;
|
|
30
|
-
}) => void;
|
|
31
|
-
"sink:write": ({ data }: {
|
|
32
|
-
data: TRet[];
|
|
33
|
-
}) => void;
|
|
34
|
-
"sink:flush": ({ endCursor, finality, }: {
|
|
35
|
-
endCursor?: Cursor;
|
|
36
|
-
finality: DataFinality;
|
|
37
|
-
}) => void;
|
|
38
|
-
message: ({ message }: {
|
|
39
|
-
message: StreamDataResponse<TBlock>;
|
|
40
|
-
}) => void;
|
|
41
|
-
}
|
|
42
|
-
interface IndexerConfig<TFilter, TBlock, TRet> {
|
|
43
|
-
streamUrl: string;
|
|
44
|
-
filter: TFilter;
|
|
45
|
-
finality?: DataFinality;
|
|
46
|
-
startingCursor?: Cursor;
|
|
47
|
-
factory?: (block: TBlock) => Promise<{
|
|
48
|
-
filter?: TFilter;
|
|
49
|
-
data?: TRet[];
|
|
50
|
-
}>;
|
|
51
|
-
transform: (args: {
|
|
52
|
-
block: TBlock;
|
|
53
|
-
cursor?: Cursor | undefined;
|
|
54
|
-
endCursor?: Cursor | undefined;
|
|
55
|
-
finality: DataFinality;
|
|
56
|
-
}) => Promise<TRet[]>;
|
|
57
|
-
hooks?: NestedHooks<IndexerHooks<TFilter, TBlock, TRet>>;
|
|
58
|
-
plugins?: ReadonlyArray<IndexerPlugin<TFilter, TBlock, TRet>>;
|
|
59
|
-
debug?: boolean;
|
|
60
|
-
}
|
|
61
|
-
interface IndexerWithStreamConfig<TFilter, TBlock, TRet> extends IndexerConfig<TFilter, TBlock, TRet> {
|
|
62
|
-
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
63
|
-
}
|
|
64
|
-
declare function defineIndexer<TFilter, TBlock>(streamConfig: StreamConfig<TFilter, TBlock>): <TRet>(config: IndexerConfig<TFilter, TBlock, TRet>) => IndexerWithStreamConfig<TFilter, TBlock, TRet>;
|
|
65
|
-
interface Indexer<TFilter, TBlock, TRet> {
|
|
66
|
-
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
67
|
-
options: IndexerConfig<TFilter, TBlock, TRet>;
|
|
68
|
-
hooks: Hookable<IndexerHooks<TFilter, TBlock, TRet>>;
|
|
69
|
-
}
|
|
70
|
-
declare function createIndexer<TFilter, TBlock, TRet>({ streamConfig, ...options }: IndexerWithStreamConfig<TFilter, TBlock, TRet>): Indexer<TFilter, TBlock, TRet>;
|
|
71
|
-
declare function run<TFilter, TBlock, TRet>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock, TRet>, sinkArg?: Sink): Promise<void>;
|
|
72
|
-
|
|
73
|
-
type VcrConfig = {
|
|
74
|
-
cassetteDir: string;
|
|
75
|
-
};
|
|
76
|
-
type CassetteOptions = {
|
|
77
|
-
name: string;
|
|
78
|
-
startingCursor: Cursor;
|
|
79
|
-
endingCursor: Cursor;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
declare function replay<TFilter, TBlock, TRet>(vcrConfig: VcrConfig, indexer: Indexer<TFilter, TBlock, TRet>, cassetteName: string): Promise<VcrReplayResult>;
|
|
83
|
-
type VcrReplayResult = {
|
|
84
|
-
outputs: Array<{
|
|
85
|
-
endCursor?: Cursor;
|
|
86
|
-
data: SinkData[];
|
|
87
|
-
}>;
|
|
88
|
-
};
|
|
89
|
-
declare function loadCassette<TFilter, TBlock>(vcrConfig: VcrConfig, cassetteName: string): Client<TFilter, TBlock>;
|
|
90
|
-
|
|
91
|
-
export { type CassetteOptions as C, type Indexer as I, type VcrConfig as V, type IndexerHooks as a, type IndexerConfig as b, type IndexerWithStreamConfig as c, defineIndexer as d, createIndexer as e, type IndexerPlugin as f, defineIndexerPlugin as g, replay as h, type VcrReplayResult as i, loadCassette as l, run as r };
|
package/dist/sinks/csv.cjs
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const csvStringify = require('csv-stringify');
|
|
5
|
-
const sink = require('../shared/indexer.e05aedca.cjs');
|
|
6
|
-
require('hookable');
|
|
7
|
-
|
|
8
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
9
|
-
|
|
10
|
-
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
11
|
-
|
|
12
|
-
class CsvSink extends sink.Sink {
|
|
13
|
-
constructor(_stringifier, _config) {
|
|
14
|
-
super();
|
|
15
|
-
this._stringifier = _stringifier;
|
|
16
|
-
this._config = _config;
|
|
17
|
-
}
|
|
18
|
-
async write({ data, endCursor, finality }) {
|
|
19
|
-
await this.callHook("write", { data });
|
|
20
|
-
data = this.processCursorColumn(data, endCursor);
|
|
21
|
-
await this.insertToCSV(data);
|
|
22
|
-
await this.callHook("flush", { endCursor, finality });
|
|
23
|
-
}
|
|
24
|
-
async insertToCSV(data) {
|
|
25
|
-
if (data.length === 0)
|
|
26
|
-
return;
|
|
27
|
-
return await new Promise((resolve, reject) => {
|
|
28
|
-
for (const row of data) {
|
|
29
|
-
this._stringifier.write(row, (err) => {
|
|
30
|
-
if (err)
|
|
31
|
-
throw new Error(err.message);
|
|
32
|
-
if (row === data[data.length - 1]) {
|
|
33
|
-
resolve();
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
processCursorColumn(data, endCursor) {
|
|
40
|
-
const { cursorColumn } = this._config;
|
|
41
|
-
if (cursorColumn && data.some(
|
|
42
|
-
(row) => Number(row[cursorColumn]) !== Number(endCursor?.orderKey)
|
|
43
|
-
)) {
|
|
44
|
-
throw new Error(
|
|
45
|
-
`Mismatch of ${cursorColumn} and Cursor ${Number(endCursor?.orderKey)}`
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
if (cursorColumn) {
|
|
49
|
-
return data;
|
|
50
|
-
}
|
|
51
|
-
return data.map((row) => ({
|
|
52
|
-
...row,
|
|
53
|
-
_cursor: Number(endCursor?.orderKey)
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const csv = (args) => {
|
|
58
|
-
const { csvOptions, filepath, ...sinkOptions } = args;
|
|
59
|
-
const stringifier = csvStringify.stringify({ ...csvOptions });
|
|
60
|
-
const writeStream = fs__default.createWriteStream(filepath, { flags: "a" });
|
|
61
|
-
stringifier.pipe(writeStream);
|
|
62
|
-
return new CsvSink(stringifier, sinkOptions);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
exports.CsvSink = CsvSink;
|
|
66
|
-
exports.csv = csv;
|
package/dist/sinks/csv.d.cts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Options, Stringifier } from 'csv-stringify';
|
|
2
|
-
import { c as Sink, b as SinkWriteArgs } from '../shared/indexer.7c118fb5.cjs';
|
|
3
|
-
import '@apibara/protocol';
|
|
4
|
-
import 'hookable';
|
|
5
|
-
|
|
6
|
-
type CsvArgs = {
|
|
7
|
-
/**
|
|
8
|
-
* csv-stringy options
|
|
9
|
-
* @reference https://csv.js.org/stringify/options/
|
|
10
|
-
*/
|
|
11
|
-
csvOptions?: Options;
|
|
12
|
-
/**
|
|
13
|
-
* filepath for your csv file
|
|
14
|
-
*/
|
|
15
|
-
filepath: string;
|
|
16
|
-
};
|
|
17
|
-
type CsvSinkOptions = {
|
|
18
|
-
/**
|
|
19
|
-
* An optional column name used to store the cursor value. If specified,
|
|
20
|
-
* the value of this column must match the `endCursor.orderKey` for each row.
|
|
21
|
-
*/
|
|
22
|
-
cursorColumn?: string;
|
|
23
|
-
};
|
|
24
|
-
declare class CsvSink extends Sink {
|
|
25
|
-
private _stringifier;
|
|
26
|
-
private _config;
|
|
27
|
-
constructor(_stringifier: Stringifier, _config: CsvSinkOptions);
|
|
28
|
-
write({ data, endCursor, finality }: SinkWriteArgs): Promise<void>;
|
|
29
|
-
private insertToCSV;
|
|
30
|
-
private processCursorColumn;
|
|
31
|
-
}
|
|
32
|
-
declare const csv: <TData extends Record<string, unknown>>(args: CsvArgs & CsvSinkOptions) => CsvSink;
|
|
33
|
-
|
|
34
|
-
export { type CsvArgs, CsvSink, type CsvSinkOptions, csv };
|
package/dist/sinks/csv.d.mts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Options, Stringifier } from 'csv-stringify';
|
|
2
|
-
import { c as Sink, b as SinkWriteArgs } from '../shared/indexer.7c118fb5.mjs';
|
|
3
|
-
import '@apibara/protocol';
|
|
4
|
-
import 'hookable';
|
|
5
|
-
|
|
6
|
-
type CsvArgs = {
|
|
7
|
-
/**
|
|
8
|
-
* csv-stringy options
|
|
9
|
-
* @reference https://csv.js.org/stringify/options/
|
|
10
|
-
*/
|
|
11
|
-
csvOptions?: Options;
|
|
12
|
-
/**
|
|
13
|
-
* filepath for your csv file
|
|
14
|
-
*/
|
|
15
|
-
filepath: string;
|
|
16
|
-
};
|
|
17
|
-
type CsvSinkOptions = {
|
|
18
|
-
/**
|
|
19
|
-
* An optional column name used to store the cursor value. If specified,
|
|
20
|
-
* the value of this column must match the `endCursor.orderKey` for each row.
|
|
21
|
-
*/
|
|
22
|
-
cursorColumn?: string;
|
|
23
|
-
};
|
|
24
|
-
declare class CsvSink extends Sink {
|
|
25
|
-
private _stringifier;
|
|
26
|
-
private _config;
|
|
27
|
-
constructor(_stringifier: Stringifier, _config: CsvSinkOptions);
|
|
28
|
-
write({ data, endCursor, finality }: SinkWriteArgs): Promise<void>;
|
|
29
|
-
private insertToCSV;
|
|
30
|
-
private processCursorColumn;
|
|
31
|
-
}
|
|
32
|
-
declare const csv: <TData extends Record<string, unknown>>(args: CsvArgs & CsvSinkOptions) => CsvSink;
|
|
33
|
-
|
|
34
|
-
export { type CsvArgs, CsvSink, type CsvSinkOptions, csv };
|
package/dist/sinks/csv.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Options, Stringifier } from 'csv-stringify';
|
|
2
|
-
import { c as Sink, b as SinkWriteArgs } from '../shared/indexer.7c118fb5.js';
|
|
3
|
-
import '@apibara/protocol';
|
|
4
|
-
import 'hookable';
|
|
5
|
-
|
|
6
|
-
type CsvArgs = {
|
|
7
|
-
/**
|
|
8
|
-
* csv-stringy options
|
|
9
|
-
* @reference https://csv.js.org/stringify/options/
|
|
10
|
-
*/
|
|
11
|
-
csvOptions?: Options;
|
|
12
|
-
/**
|
|
13
|
-
* filepath for your csv file
|
|
14
|
-
*/
|
|
15
|
-
filepath: string;
|
|
16
|
-
};
|
|
17
|
-
type CsvSinkOptions = {
|
|
18
|
-
/**
|
|
19
|
-
* An optional column name used to store the cursor value. If specified,
|
|
20
|
-
* the value of this column must match the `endCursor.orderKey` for each row.
|
|
21
|
-
*/
|
|
22
|
-
cursorColumn?: string;
|
|
23
|
-
};
|
|
24
|
-
declare class CsvSink extends Sink {
|
|
25
|
-
private _stringifier;
|
|
26
|
-
private _config;
|
|
27
|
-
constructor(_stringifier: Stringifier, _config: CsvSinkOptions);
|
|
28
|
-
write({ data, endCursor, finality }: SinkWriteArgs): Promise<void>;
|
|
29
|
-
private insertToCSV;
|
|
30
|
-
private processCursorColumn;
|
|
31
|
-
}
|
|
32
|
-
declare const csv: <TData extends Record<string, unknown>>(args: CsvArgs & CsvSinkOptions) => CsvSink;
|
|
33
|
-
|
|
34
|
-
export { type CsvArgs, CsvSink, type CsvSinkOptions, csv };
|
package/dist/sinks/csv.mjs
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { stringify } from 'csv-stringify';
|
|
3
|
-
import { S as Sink } from '../shared/indexer.371c0482.mjs';
|
|
4
|
-
import 'hookable';
|
|
5
|
-
|
|
6
|
-
class CsvSink extends Sink {
|
|
7
|
-
constructor(_stringifier, _config) {
|
|
8
|
-
super();
|
|
9
|
-
this._stringifier = _stringifier;
|
|
10
|
-
this._config = _config;
|
|
11
|
-
}
|
|
12
|
-
async write({ data, endCursor, finality }) {
|
|
13
|
-
await this.callHook("write", { data });
|
|
14
|
-
data = this.processCursorColumn(data, endCursor);
|
|
15
|
-
await this.insertToCSV(data);
|
|
16
|
-
await this.callHook("flush", { endCursor, finality });
|
|
17
|
-
}
|
|
18
|
-
async insertToCSV(data) {
|
|
19
|
-
if (data.length === 0)
|
|
20
|
-
return;
|
|
21
|
-
return await new Promise((resolve, reject) => {
|
|
22
|
-
for (const row of data) {
|
|
23
|
-
this._stringifier.write(row, (err) => {
|
|
24
|
-
if (err)
|
|
25
|
-
throw new Error(err.message);
|
|
26
|
-
if (row === data[data.length - 1]) {
|
|
27
|
-
resolve();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
processCursorColumn(data, endCursor) {
|
|
34
|
-
const { cursorColumn } = this._config;
|
|
35
|
-
if (cursorColumn && data.some(
|
|
36
|
-
(row) => Number(row[cursorColumn]) !== Number(endCursor?.orderKey)
|
|
37
|
-
)) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`Mismatch of ${cursorColumn} and Cursor ${Number(endCursor?.orderKey)}`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (cursorColumn) {
|
|
43
|
-
return data;
|
|
44
|
-
}
|
|
45
|
-
return data.map((row) => ({
|
|
46
|
-
...row,
|
|
47
|
-
_cursor: Number(endCursor?.orderKey)
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const csv = (args) => {
|
|
52
|
-
const { csvOptions, filepath, ...sinkOptions } = args;
|
|
53
|
-
const stringifier = stringify({ ...csvOptions });
|
|
54
|
-
const writeStream = fs.createWriteStream(filepath, { flags: "a" });
|
|
55
|
-
stringifier.pipe(writeStream);
|
|
56
|
-
return new CsvSink(stringifier, sinkOptions);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export { CsvSink, csv };
|