@coopenomics/parser 2025.10.15 → 2025.11.6

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
@@ -32,50 +32,20 @@ const redisPort = getEnvVar("REDIS_PORT");
32
32
  const redisHost = getEnvVar("REDIS_HOST");
33
33
  const redisPassword = getEnvVar("REDIS_PASSWORD");
34
34
  const redisStreamLimit = Number(getEnvVar("REDIS_STREAM_LIMIT"));
35
- const subsribedTables = [
36
- // документы
37
- { code: "draft", table: "drafts" },
38
- { code: "draft", table: "translations" },
39
- // meet
40
- { code: "meet", table: "meets" },
41
- { code: "meet", table: "questions" },
42
- // совет
43
- { code: "soviet", table: "decisions" },
44
- { code: "soviet", table: "boards" },
45
- { code: "soviet", table: "participants" },
46
- // registrator.joincoop
47
- { code: "soviet", table: "joincoops" },
48
- // регистратор
49
- { code: "registrator", table: "accounts" },
50
- { code: "registrator", table: "coops" }
51
- ];
52
- const subsribedActions = [
53
- { code: "eosio.token", action: "transfer", notify: true },
54
- { code: "registrator", action: "confirmreg", notify: true },
55
- { code: "soviet", action: "votefor" },
56
- { code: "soviet", action: "voteagainst" },
57
- { code: "soviet", action: "newsubmitted" },
58
- { code: "soviet", action: "newresolved" },
59
- { code: "soviet", action: "newdecision" },
60
- { code: "soviet", action: "newpackage" },
61
- { code: "soviet", action: "newact" },
62
- { code: "soviet", action: "newlink" },
63
- { code: "soviet", action: "newagreement" },
64
- { code: "soviet", action: "newdeclined" },
65
- // // registrator.joincoop
66
- { code: "soviet", action: "joincoop" },
67
- { code: "soviet", action: "joincoopdec" },
68
- { code: "soviet", action: "updateboard", notify: true },
69
- { code: "soviet", action: "createboard", notify: true },
70
- { code: "meet", action: "newgdecision", notify: true },
71
- { code: "wallet", action: "createwthd", notify: true },
72
- { code: "ledger", action: "debet", notify: true },
73
- { code: "ledger", action: "credit", notify: true },
74
- { code: "ledger", action: "block", notify: true },
75
- { code: "ledger", action: "unblock", notify: true },
76
- { code: "ledger", action: "writeoff", notify: true },
77
- { code: "ledger", action: "writeoffcnsl", notify: true }
35
+ const subscribedContracts = [
36
+ "draft",
37
+ "meet",
38
+ "soviet",
39
+ "registrator",
40
+ "eosio.token",
41
+ "capital",
42
+ "wallet",
43
+ "ledger"
78
44
  ];
45
+ const subsribedActions = subscribedContracts.map((contract) => ({
46
+ code: contract,
47
+ action: "*"
48
+ }));
79
49
 
80
50
  var __defProp = Object.defineProperty;
81
51
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -200,6 +170,16 @@ async function publishEvent(type, event) {
200
170
  await redis.xadd(streamName, "*", "event", message);
201
171
  await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
202
172
  }
173
+ async function publishDelta(type, delta) {
174
+ const message = JSON.stringify({ type, delta });
175
+ await redis.xadd(streamName, "*", "delta", message);
176
+ await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
177
+ }
178
+ async function publishFork(type, block_num) {
179
+ const message = JSON.stringify({ type, block_num });
180
+ await redis.xadd(streamName, "*", "fork", message);
181
+ await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
182
+ }
203
183
 
204
184
  class AnyAnyActionParser {
205
185
  async process(db, action) {
@@ -224,11 +204,9 @@ async function ActionsParser(db, reader) {
224
204
  console.log(`
225
205
  ACTION - account: ${action.account}, name: ${action.name}, authorization: ${JSON.stringify(action.authorization)}, data: ${JSON.stringify(action.data)}`);
226
206
  const parser = ActionParserFactory.create(action.account, action.name);
227
- const source = subsribedActions.find((el) => el.action === action.name && el.code === action.account);
228
207
  if (parser) {
229
208
  await parser.process(db, action);
230
- if (source?.notify)
231
- await publishEvent("action", action);
209
+ await publishEvent("action", action);
232
210
  }
233
211
  });
234
212
  console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
@@ -269,17 +247,41 @@ async function DeltasParser(db, reader) {
269
247
  rows$.subscribe(async (delta) => {
270
248
  console.log(`
271
249
  DELTA - code: ${delta.code}, scope: ${delta.scope}, table: ${delta.table}, primary_key: ${delta.primary_key}, data: ${JSON.stringify(delta.value)}`);
272
- const source = subsribedTables.find((el) => el.code === delta.code && el.table === delta.table);
273
250
  const parser = DeltaParserFactory.create(delta.code, delta.scope, delta.table);
274
251
  if (parser) {
275
252
  await parser.process(db, delta);
276
- if (source?.notify)
277
- await publishEvent("delta", delta);
253
+ await publishDelta("delta", delta);
278
254
  }
279
255
  });
280
256
  console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0434\u0435\u043B\u044C\u0442\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
281
257
  }
282
258
 
259
+ class AnyForkParser {
260
+ async process(db, block_num) {
261
+ console.log(`FORK detected at block: ${block_num}`);
262
+ }
263
+ }
264
+
265
+ class ForkParserFactory {
266
+ static create() {
267
+ return new AnyForkParser();
268
+ }
269
+ }
270
+
271
+ async function ForksParser(db, reader) {
272
+ const { forks$ } = reader;
273
+ forks$.subscribe(async (block_num) => {
274
+ console.log(`
275
+ FORK detected at block: ${block_num}`);
276
+ const parser = ForkParserFactory.create();
277
+ if (parser) {
278
+ await parser.process(db, block_num);
279
+ await publishFork("fork", block_num);
280
+ }
281
+ });
282
+ console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0444\u043E\u0440\u043A\u0438 \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
283
+ }
284
+
283
285
  const getInfo = () => fetch__default(`${eosioApi}/v1/chain/get_info`).then((res) => res.json());
284
286
  function fetchAbi(account_name) {
285
287
  return fetch__default(`${eosioApi}/v1/chain/get_abi`, {
@@ -289,34 +291,59 @@ function fetchAbi(account_name) {
289
291
  })
290
292
  }).then(async (res) => {
291
293
  const response = await res.json();
294
+ if (!response.abi) {
295
+ console.warn(`ABI \u0434\u043B\u044F \u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442\u0430 ${account_name} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D (\u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D \u0432 \u0431\u043B\u043E\u043A\u0447\u0435\u0439\u043D\u0435)`);
296
+ }
292
297
  return {
293
298
  account_name,
294
299
  abi: response.abi
295
300
  };
296
301
  });
297
302
  }
303
+ function extractTablesFromAbi(abi) {
304
+ if (!abi || !abi.tables)
305
+ return [];
306
+ return abi.tables.map((table) => table.name);
307
+ }
298
308
 
299
- const table_rows_whitelist = () => subsribedTables;
300
309
  const actions_whitelist = () => subsribedActions;
301
- console.log(subsribedTables);
302
- console.log(subsribedActions);
310
+ console.log("Actions whitelist (auto-generated from subscribedContracts):", subsribedActions);
303
311
  async function loadReader(db) {
304
312
  let currentBlock = await db.getCurrentBlock();
305
313
  const info = await getInfo();
306
- if (currentBlock === 0)
314
+ if (Number(startBlock) === 1) {
315
+ if (currentBlock === 0) {
316
+ currentBlock = Number(info.head_block_num);
317
+ }
318
+ } else {
307
319
  currentBlock = Number(startBlock);
320
+ }
308
321
  console.log("\u0421\u0442\u0430\u0440\u0442\u0443\u0435\u043C \u0441 \u0431\u043B\u043E\u043A\u0430: ", currentBlock);
309
322
  console.log("\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u043C \u043D\u0430 \u0431\u043B\u043E\u043A\u0435: ", finishBlock);
310
323
  console.log("\u0412\u044B\u0441\u043E\u0442\u0430 \u0446\u0435\u043F\u043E\u0447\u043A\u0438: ", info.head_block_num);
311
324
  console.log("\u041E\u0447\u0438\u0449\u0430\u0435\u043C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0438 \u0434\u0435\u043B\u044C\u0442\u044B \u043F\u043E\u0441\u043B\u0435 \u0431\u043B\u043E\u043A\u0430: ", currentBlock);
312
325
  await db.purgeAfterBlock(currentBlock);
313
- const unique_contract_names = [...new Set(table_rows_whitelist().map((row) => row.code)), ...new Set(actions_whitelist().map((row) => row.code))];
326
+ const unique_contract_names = [.../* @__PURE__ */ new Set([...subscribedContracts, ...actions_whitelist().map((row) => row.code)])];
314
327
  const abisArr = await Promise.all(unique_contract_names.map((account_name) => fetchAbi(account_name)));
315
328
  const contract_abis = () => {
316
329
  const numap = /* @__PURE__ */ new Map();
317
330
  abisArr.forEach(({ account_name, abi }) => numap.set(account_name, abi));
318
331
  return numap;
319
332
  };
333
+ const table_rows_whitelist = () => {
334
+ const tables = [];
335
+ abisArr.forEach(({ account_name, abi }) => {
336
+ if (subscribedContracts.includes(account_name)) {
337
+ const tableNames = extractTablesFromAbi(abi);
338
+ tableNames.forEach((tableName) => {
339
+ tables.push({ code: account_name, table: tableName });
340
+ });
341
+ }
342
+ });
343
+ return tables;
344
+ };
345
+ const tablesWhitelist = table_rows_whitelist();
346
+ console.log("Tables whitelist (auto-generated from ABI):", tablesWhitelist);
320
347
  const delta_whitelist = () => [
321
348
  "account_metadata",
322
349
  "contract_table",
@@ -357,6 +384,7 @@ class Parser {
357
384
  BlockParser(db, reader);
358
385
  ActionsParser(db, reader);
359
386
  DeltasParser(db, reader);
387
+ ForksParser(db, reader);
360
388
  } catch (e) {
361
389
  console.error("\u041E\u0448\u0438\u0431\u043A\u0430: ", e);
362
390
  this.start();
package/dist/index.mjs CHANGED
@@ -23,50 +23,20 @@ const redisPort = getEnvVar("REDIS_PORT");
23
23
  const redisHost = getEnvVar("REDIS_HOST");
24
24
  const redisPassword = getEnvVar("REDIS_PASSWORD");
25
25
  const redisStreamLimit = Number(getEnvVar("REDIS_STREAM_LIMIT"));
26
- const subsribedTables = [
27
- // документы
28
- { code: "draft", table: "drafts" },
29
- { code: "draft", table: "translations" },
30
- // meet
31
- { code: "meet", table: "meets" },
32
- { code: "meet", table: "questions" },
33
- // совет
34
- { code: "soviet", table: "decisions" },
35
- { code: "soviet", table: "boards" },
36
- { code: "soviet", table: "participants" },
37
- // registrator.joincoop
38
- { code: "soviet", table: "joincoops" },
39
- // регистратор
40
- { code: "registrator", table: "accounts" },
41
- { code: "registrator", table: "coops" }
42
- ];
43
- const subsribedActions = [
44
- { code: "eosio.token", action: "transfer", notify: true },
45
- { code: "registrator", action: "confirmreg", notify: true },
46
- { code: "soviet", action: "votefor" },
47
- { code: "soviet", action: "voteagainst" },
48
- { code: "soviet", action: "newsubmitted" },
49
- { code: "soviet", action: "newresolved" },
50
- { code: "soviet", action: "newdecision" },
51
- { code: "soviet", action: "newpackage" },
52
- { code: "soviet", action: "newact" },
53
- { code: "soviet", action: "newlink" },
54
- { code: "soviet", action: "newagreement" },
55
- { code: "soviet", action: "newdeclined" },
56
- // // registrator.joincoop
57
- { code: "soviet", action: "joincoop" },
58
- { code: "soviet", action: "joincoopdec" },
59
- { code: "soviet", action: "updateboard", notify: true },
60
- { code: "soviet", action: "createboard", notify: true },
61
- { code: "meet", action: "newgdecision", notify: true },
62
- { code: "wallet", action: "createwthd", notify: true },
63
- { code: "ledger", action: "debet", notify: true },
64
- { code: "ledger", action: "credit", notify: true },
65
- { code: "ledger", action: "block", notify: true },
66
- { code: "ledger", action: "unblock", notify: true },
67
- { code: "ledger", action: "writeoff", notify: true },
68
- { code: "ledger", action: "writeoffcnsl", notify: true }
26
+ const subscribedContracts = [
27
+ "draft",
28
+ "meet",
29
+ "soviet",
30
+ "registrator",
31
+ "eosio.token",
32
+ "capital",
33
+ "wallet",
34
+ "ledger"
69
35
  ];
36
+ const subsribedActions = subscribedContracts.map((contract) => ({
37
+ code: contract,
38
+ action: "*"
39
+ }));
70
40
 
71
41
  var __defProp = Object.defineProperty;
72
42
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -191,6 +161,16 @@ async function publishEvent(type, event) {
191
161
  await redis.xadd(streamName, "*", "event", message);
192
162
  await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
193
163
  }
164
+ async function publishDelta(type, delta) {
165
+ const message = JSON.stringify({ type, delta });
166
+ await redis.xadd(streamName, "*", "delta", message);
167
+ await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
168
+ }
169
+ async function publishFork(type, block_num) {
170
+ const message = JSON.stringify({ type, block_num });
171
+ await redis.xadd(streamName, "*", "fork", message);
172
+ await redis.xtrim(streamName, "MAXLEN", "~", redisStreamLimit);
173
+ }
194
174
 
195
175
  class AnyAnyActionParser {
196
176
  async process(db, action) {
@@ -215,11 +195,9 @@ async function ActionsParser(db, reader) {
215
195
  console.log(`
216
196
  ACTION - account: ${action.account}, name: ${action.name}, authorization: ${JSON.stringify(action.authorization)}, data: ${JSON.stringify(action.data)}`);
217
197
  const parser = ActionParserFactory.create(action.account, action.name);
218
- const source = subsribedActions.find((el) => el.action === action.name && el.code === action.account);
219
198
  if (parser) {
220
199
  await parser.process(db, action);
221
- if (source?.notify)
222
- await publishEvent("action", action);
200
+ await publishEvent("action", action);
223
201
  }
224
202
  });
225
203
  console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
@@ -260,17 +238,41 @@ async function DeltasParser(db, reader) {
260
238
  rows$.subscribe(async (delta) => {
261
239
  console.log(`
262
240
  DELTA - code: ${delta.code}, scope: ${delta.scope}, table: ${delta.table}, primary_key: ${delta.primary_key}, data: ${JSON.stringify(delta.value)}`);
263
- const source = subsribedTables.find((el) => el.code === delta.code && el.table === delta.table);
264
241
  const parser = DeltaParserFactory.create(delta.code, delta.scope, delta.table);
265
242
  if (parser) {
266
243
  await parser.process(db, delta);
267
- if (source?.notify)
268
- await publishEvent("delta", delta);
244
+ await publishDelta("delta", delta);
269
245
  }
270
246
  });
271
247
  console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0434\u0435\u043B\u044C\u0442\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
272
248
  }
273
249
 
250
+ class AnyForkParser {
251
+ async process(db, block_num) {
252
+ console.log(`FORK detected at block: ${block_num}`);
253
+ }
254
+ }
255
+
256
+ class ForkParserFactory {
257
+ static create() {
258
+ return new AnyForkParser();
259
+ }
260
+ }
261
+
262
+ async function ForksParser(db, reader) {
263
+ const { forks$ } = reader;
264
+ forks$.subscribe(async (block_num) => {
265
+ console.log(`
266
+ FORK detected at block: ${block_num}`);
267
+ const parser = ForkParserFactory.create();
268
+ if (parser) {
269
+ await parser.process(db, block_num);
270
+ await publishFork("fork", block_num);
271
+ }
272
+ });
273
+ console.log("\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0430 \u0444\u043E\u0440\u043A\u0438 \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u0430");
274
+ }
275
+
274
276
  const getInfo = () => fetch(`${eosioApi}/v1/chain/get_info`).then((res) => res.json());
275
277
  function fetchAbi(account_name) {
276
278
  return fetch(`${eosioApi}/v1/chain/get_abi`, {
@@ -280,34 +282,59 @@ function fetchAbi(account_name) {
280
282
  })
281
283
  }).then(async (res) => {
282
284
  const response = await res.json();
285
+ if (!response.abi) {
286
+ console.warn(`ABI \u0434\u043B\u044F \u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442\u0430 ${account_name} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D (\u043A\u043E\u043D\u0442\u0440\u0430\u043A\u0442 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D \u0432 \u0431\u043B\u043E\u043A\u0447\u0435\u0439\u043D\u0435)`);
287
+ }
283
288
  return {
284
289
  account_name,
285
290
  abi: response.abi
286
291
  };
287
292
  });
288
293
  }
294
+ function extractTablesFromAbi(abi) {
295
+ if (!abi || !abi.tables)
296
+ return [];
297
+ return abi.tables.map((table) => table.name);
298
+ }
289
299
 
290
- const table_rows_whitelist = () => subsribedTables;
291
300
  const actions_whitelist = () => subsribedActions;
292
- console.log(subsribedTables);
293
- console.log(subsribedActions);
301
+ console.log("Actions whitelist (auto-generated from subscribedContracts):", subsribedActions);
294
302
  async function loadReader(db) {
295
303
  let currentBlock = await db.getCurrentBlock();
296
304
  const info = await getInfo();
297
- if (currentBlock === 0)
305
+ if (Number(startBlock) === 1) {
306
+ if (currentBlock === 0) {
307
+ currentBlock = Number(info.head_block_num);
308
+ }
309
+ } else {
298
310
  currentBlock = Number(startBlock);
311
+ }
299
312
  console.log("\u0421\u0442\u0430\u0440\u0442\u0443\u0435\u043C \u0441 \u0431\u043B\u043E\u043A\u0430: ", currentBlock);
300
313
  console.log("\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u043C \u043D\u0430 \u0431\u043B\u043E\u043A\u0435: ", finishBlock);
301
314
  console.log("\u0412\u044B\u0441\u043E\u0442\u0430 \u0446\u0435\u043F\u043E\u0447\u043A\u0438: ", info.head_block_num);
302
315
  console.log("\u041E\u0447\u0438\u0449\u0430\u0435\u043C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0438 \u0434\u0435\u043B\u044C\u0442\u044B \u043F\u043E\u0441\u043B\u0435 \u0431\u043B\u043E\u043A\u0430: ", currentBlock);
303
316
  await db.purgeAfterBlock(currentBlock);
304
- const unique_contract_names = [...new Set(table_rows_whitelist().map((row) => row.code)), ...new Set(actions_whitelist().map((row) => row.code))];
317
+ const unique_contract_names = [.../* @__PURE__ */ new Set([...subscribedContracts, ...actions_whitelist().map((row) => row.code)])];
305
318
  const abisArr = await Promise.all(unique_contract_names.map((account_name) => fetchAbi(account_name)));
306
319
  const contract_abis = () => {
307
320
  const numap = /* @__PURE__ */ new Map();
308
321
  abisArr.forEach(({ account_name, abi }) => numap.set(account_name, abi));
309
322
  return numap;
310
323
  };
324
+ const table_rows_whitelist = () => {
325
+ const tables = [];
326
+ abisArr.forEach(({ account_name, abi }) => {
327
+ if (subscribedContracts.includes(account_name)) {
328
+ const tableNames = extractTablesFromAbi(abi);
329
+ tableNames.forEach((tableName) => {
330
+ tables.push({ code: account_name, table: tableName });
331
+ });
332
+ }
333
+ });
334
+ return tables;
335
+ };
336
+ const tablesWhitelist = table_rows_whitelist();
337
+ console.log("Tables whitelist (auto-generated from ABI):", tablesWhitelist);
311
338
  const delta_whitelist = () => [
312
339
  "account_metadata",
313
340
  "contract_table",
@@ -348,6 +375,7 @@ class Parser {
348
375
  BlockParser(db, reader);
349
376
  ActionsParser(db, reader);
350
377
  DeltasParser(db, reader);
378
+ ForksParser(db, reader);
351
379
  } catch (e) {
352
380
  console.error("\u041E\u0448\u0438\u0431\u043A\u0430: ", e);
353
381
  this.start();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopenomics/parser",
3
3
  "type": "module",
4
- "version": "2025.10.15",
4
+ "version": "2025.11.6",
5
5
  "private": false,
6
6
  "packageManager": "pnpm@9.0.6",
7
7
  "description": "",
@@ -85,5 +85,5 @@
85
85
  "vite": "^5.2.10",
86
86
  "vitest": "^1.5.2"
87
87
  },
88
- "gitHead": "e47b2a971e8b2fe129b0035be97addcbfce07aa3"
88
+ "gitHead": "9292acec8c60d4697e1f069a0a9f1846fb119802"
89
89
  }