@certik/skynet 0.18.9 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +2 -2
  4. package/{abi.js → abi.ts} +5 -132
  5. package/{address.js → address.ts} +4 -4
  6. package/{api.js → api.ts} +79 -19
  7. package/{app.js → app.ts} +138 -25
  8. package/{availability.js → availability.ts} +18 -21
  9. package/bun.lockb +0 -0
  10. package/{cli.js → cli.ts} +1 -1
  11. package/{const.js → const.ts} +42 -3
  12. package/databricks.ts +82 -0
  13. package/{date.js → date.ts} +5 -5
  14. package/{deploy.js → deploy.ts} +157 -44
  15. package/{dynamodb.js → dynamodb.ts} +159 -186
  16. package/env.ts +25 -0
  17. package/eslint.config.mjs +7 -0
  18. package/examples/{api.js → api.ts} +7 -6
  19. package/examples/{indexer.js → indexer.ts} +9 -10
  20. package/examples/{mode-indexer.js → mode-indexer.ts} +18 -10
  21. package/graphql.ts +43 -0
  22. package/{indexer.js → indexer.ts} +228 -109
  23. package/{log.js → log.ts} +6 -6
  24. package/{opsgenie.js → opsgenie.ts} +29 -6
  25. package/package.json +17 -11
  26. package/{s3.js → s3.ts} +29 -19
  27. package/search.ts +37 -0
  28. package/selector.ts +72 -0
  29. package/{slack.js → slack.ts} +19 -12
  30. package/snowflake.ts +51 -0
  31. package/tsconfig.json +26 -0
  32. package/util.ts +35 -0
  33. package/web3.ts +41 -0
  34. package/.eslintignore +0 -1
  35. package/.eslintrc.json +0 -20
  36. package/abi.d.ts +0 -20
  37. package/address.d.ts +0 -2
  38. package/api.d.ts +0 -12
  39. package/app.d.ts +0 -118
  40. package/availability.d.ts +0 -18
  41. package/cli.d.ts +0 -4
  42. package/const.d.ts +0 -42
  43. package/databricks.js +0 -82
  44. package/deploy.d.ts +0 -51
  45. package/dns.d.ts +0 -1
  46. package/dns.js +0 -27
  47. package/dynamodb.d.ts +0 -63
  48. package/env.d.ts +0 -6
  49. package/env.js +0 -42
  50. package/examples/consumer.js +0 -30
  51. package/examples/producer.js +0 -63
  52. package/graphql.d.ts +0 -3
  53. package/graphql.js +0 -22
  54. package/indexer.d.ts +0 -32
  55. package/log.d.ts +0 -8
  56. package/opsgenie.d.ts +0 -8
  57. package/proxy.d.ts +0 -9
  58. package/proxy.js +0 -154
  59. package/s3.d.ts +0 -36
  60. package/search.d.ts +0 -5
  61. package/search.js +0 -29
  62. package/selector.d.ts +0 -19
  63. package/selector.js +0 -71
  64. package/slack.d.ts +0 -10
  65. package/snowflake.d.ts +0 -4
  66. package/snowflake.js +0 -33
  67. package/sqs.d.ts +0 -3
  68. package/sqs.js +0 -5
  69. package/util.d.ts +0 -5
  70. package/util.js +0 -61
  71. package/web3.d.ts +0 -25
  72. package/web3.js +0 -113
@@ -8,13 +8,19 @@
8
8
  // $ examples/mode-indexer deploy --protocol eth
9
9
  // $ examples/mode-indexer --help
10
10
 
11
- import { modeIndexer, every, SENSITIVE_VALUE } from "../app.js";
11
+ import { modeIndexer, every } from "../app.ts";
12
12
 
13
- async function build({ protocol, from, to, verbose }) {
14
- console.log("build called with", protocol, from, to, verbose);
15
- }
16
-
17
- async function validate({ protocol, from, to, verbose }) {
13
+ async function validate({
14
+ protocol,
15
+ from,
16
+ to,
17
+ verbose,
18
+ }: {
19
+ protocol?: string;
20
+ from?: string;
21
+ to?: string;
22
+ verbose?: boolean;
23
+ }) {
18
24
  console.log("validate called with", protocol, from, to, verbose);
19
25
  }
20
26
 
@@ -33,14 +39,16 @@ const app = modeIndexer({
33
39
 
34
40
  state: {
35
41
  type: "date", // can be omitted, default is block
36
- getMinId: async () => "2022-09-26", // default returns 1
37
- getMaxId: async ({ protocol }) => {
38
- return "2022-10-18";
42
+ getMinId: async () => "2022-09-26" as string,
43
+ getMaxId: async () => {
44
+ return "2022-10-18" as string;
39
45
  },
40
46
  },
41
47
 
42
48
  build: {
43
- func: build,
49
+ func: ({ protocol, from, to, verbose }) => {
50
+ console.log("build called with", protocol, from, to, verbose);
51
+ },
44
52
  batchSize: 5,
45
53
  concurrency: 2, // default is 1, no concurrency
46
54
 
package/graphql.ts ADDED
@@ -0,0 +1,43 @@
1
+ type GraphqlVariables = { [key: string]: unknown };
2
+
3
+ type GraphQLError = {
4
+ message: string;
5
+ locations?: { line: number; column: number }[];
6
+ path?: string[];
7
+ extensions?: Record<string, unknown>;
8
+ };
9
+
10
+ type GraphQLResponse<TData> = {
11
+ data: TData;
12
+ errors?: GraphQLError[];
13
+ };
14
+
15
+ export async function gql<T>(query: string, variables: GraphqlVariables = {}) {
16
+ const endpoint = process.env["SKYNET_GRAPHQL_ENDPOINT"];
17
+ const apiKey = process.env["SKYNET_GRAPHQL_API_KEY"];
18
+
19
+ if (!endpoint || !apiKey) {
20
+ throw new Error("SKYNET_GRAPHQL_ENDPOINT or SKYNET_GRAPHQL_API_KEY is not set");
21
+ }
22
+
23
+ const res = await fetch(endpoint, {
24
+ method: "POST",
25
+ headers: {
26
+ "x-api-key": apiKey,
27
+ "content-type": "application/json",
28
+ },
29
+ body: JSON.stringify({ query: query.trim(), variables }),
30
+ });
31
+
32
+ if (res.ok) {
33
+ const { data, errors }: GraphQLResponse<T> = await res.json();
34
+
35
+ if (errors && errors.length > 0) {
36
+ throw new Error(JSON.stringify(errors, null, 2));
37
+ }
38
+
39
+ return data;
40
+ } else {
41
+ throw new Error(await res.text());
42
+ }
43
+ }
@@ -1,41 +1,78 @@
1
1
  import meow from "meow";
2
- import { createRecord, getRecordByKey } from "./dynamodb.js";
3
- import { getEnvironment } from "./env.js";
4
- import { exponentialRetry } from "./availability.js";
5
- import { range as numberRange, fillRange as fillNumberRange } from "./util.js";
6
- import { getSelectorFlags, getSelectorDesc, toSelectorString } from "./selector.js";
7
- import { getBinaryName } from "./cli.js";
8
- import { inline } from "./log.js";
9
- import { findDateAfter, dateRange, daysInRange as fillDateRange } from "./date.js";
2
+ import { createRecord, getRecordByKey } from "./dynamodb.ts";
3
+ import { getEnvironment } from "./env.ts";
4
+ import { exponentialRetry } from "./availability.ts";
5
+ import { range as numberRange, fillRange as fillNumberRange } from "./util.ts";
6
+ import { getSelectorDesc, getSelectorFlags, toSelectorString } from "./selector.ts";
7
+ import type { SelectorFlags, Selector } from "./selector.ts";
8
+ import { getBinaryName } from "./cli.ts";
9
+ import { inline } from "./log.ts";
10
+ import { findDateAfter, dateRange, daysInRange as fillDateRange } from "./date.ts";
10
11
 
11
12
  const STATE_TABLE_NAME = "skynet-" + getEnvironment() + "-indexer-state";
12
13
 
13
- async function getIndexerState(name, selectorFlags) {
14
- const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
15
- name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
16
- });
17
-
18
- if (!stateItem) {
19
- return "N/A";
14
+ type IndexerStateValue = string | number;
15
+ type RebuildStateValue = "init" | "running" | "succeed" | "failed";
16
+
17
+ type StatelessIndexerFlags<TSelector extends Selector> = SelectorFlags<
18
+ TSelector & { verbose: { type: "boolean"; default: false } }
19
+ >;
20
+ type StatelessBuildFunction<TSelector extends Selector> = ({
21
+ verbose,
22
+ ...selectorFlags
23
+ }: StatelessIndexerFlags<TSelector>) => Promise<void> | void;
24
+
25
+ type ModeIndexerFlags<TSelector extends Selector> = SelectorFlags<
26
+ TSelector & {
27
+ verbose: { type: "boolean"; default: false };
28
+ mode: { type: "string"; default: "delta" };
29
+ from: { aliases: ["since"]; type: "string" };
30
+ to: { aliases: ["until"]; type: "string" };
31
+ status: { type: "boolean"; default: false };
20
32
  }
33
+ >;
34
+ type ModeBuildFunction<T extends IndexerStateValue, TSelector extends Selector> = ({
35
+ from,
36
+ to,
37
+ verbose,
38
+ ...selectorFlags
39
+ }: { from: T; to: T; verbose: boolean } & ModeIndexerFlags<TSelector>) => Promise<void | T[]> | void | T[];
40
+
41
+ type ValidateFunction<TSelector extends Selector> = ({
42
+ from,
43
+ to,
44
+ verbose,
45
+ ...selectorFlags
46
+ }: ModeIndexerFlags<TSelector>) => Promise<void> | void;
47
+
48
+ type State<T extends IndexerStateValue, TSelector extends Selector> = {
49
+ type: string;
50
+ updateInterval?: () => number;
51
+ getMinId: (selectorFlags: ModeIndexerFlags<TSelector>) => Promise<T>;
52
+ getMaxId: (selectorFlags: ModeIndexerFlags<TSelector>) => Promise<T>;
53
+ };
21
54
 
22
- return stateItem.value;
23
- }
55
+ type IndexerState<T> = {
56
+ name: string;
57
+ value: T;
58
+ };
24
59
 
25
- async function getIndexerLatestId(name, selectorFlags) {
26
- const record = await getRecordByKey(STATE_TABLE_NAME, {
60
+ async function getIndexerLatestId<T extends IndexerStateValue, TSelector extends Selector>(
61
+ name: string,
62
+ selectorFlags: ModeIndexerFlags<TSelector>,
63
+ ) {
64
+ const record = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
27
65
  name: `${name}Since(${toSelectorString(selectorFlags)})`,
28
66
  });
29
67
 
30
- if (record) {
31
- return record.value;
32
- }
33
-
34
- return 0;
68
+ return record?.value;
35
69
  }
36
70
 
37
- async function getIndexerValidatedId(name, selectorFlags) {
38
- const record = await getRecordByKey(STATE_TABLE_NAME, {
71
+ async function getIndexerValidatedId<T extends IndexerStateValue, TSelector extends Selector>(
72
+ name: string,
73
+ selectorFlags: ModeIndexerFlags<TSelector>,
74
+ ) {
75
+ const record = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
39
76
  name: `${name}Validate(${toSelectorString(selectorFlags)})`,
40
77
  });
41
78
 
@@ -43,25 +80,33 @@ async function getIndexerValidatedId(name, selectorFlags) {
43
80
  return record.value;
44
81
  }
45
82
 
46
- return 0;
83
+ return undefined;
47
84
  }
48
85
 
49
- function increaseId(type, currentId, n) {
86
+ function increaseId<T extends IndexerStateValue = IndexerStateValue>(type: string, currentId: T, n: number): T {
50
87
  if (type === "date") {
51
- return findDateAfter(currentId, n);
88
+ if (typeof currentId !== "string") {
89
+ throw new Error("invalid type for date id");
90
+ }
91
+
92
+ return findDateAfter(currentId, n) as T;
93
+ }
94
+
95
+ if (typeof currentId !== "number") {
96
+ throw new Error("Invalid type for numeric id");
52
97
  }
53
98
 
54
- return currentId + n;
99
+ return (currentId + n) as T;
55
100
  }
56
101
 
57
102
  // for those indexers that can have progress tracked by a numeric state.type
58
103
  // such as block height, or timestamp
59
104
  // managing state would be helpful to reduce the build time
60
105
  // and avoid unnecessary computation & storage
61
- function createModeIndexerApp({
106
+ function createModeIndexerApp<T extends IndexerStateValue, TSelector extends Selector>({
62
107
  binaryName,
63
108
  name,
64
- selector = {},
109
+ selector = {} as TSelector,
65
110
  build,
66
111
  // number of items run in a batch, determines the { from, to } to the build function
67
112
  buildBatchSize = 1,
@@ -76,48 +121,86 @@ function createModeIndexerApp({
76
121
  // commit updates every rolling window = validateBatchSize * validateConcurrency
77
122
  maxRetry = 2,
78
123
  state,
124
+ }: {
125
+ binaryName: string;
126
+ name: string;
127
+ selector: TSelector;
128
+ build: ModeBuildFunction<T, TSelector>;
129
+ maxRetry?: number;
130
+ buildBatchSize?: number;
131
+ buildConcurrency?: number;
132
+ validate?: ValidateFunction<TSelector>;
133
+ validateBatchSize?: number;
134
+ validateConcurrency?: number;
135
+ state: State<T, TSelector>;
79
136
  }) {
80
- const finalState = {
137
+ const defaultState = {
81
138
  type: "block",
82
139
  getMinId: async () => 1,
83
140
  getMaxId: async () => {
84
141
  throw new Error("must implement getMaxId");
85
142
  },
143
+ };
144
+ const finalState = {
145
+ ...defaultState,
86
146
  ...state,
87
147
  };
88
148
 
89
149
  // type based range functions
90
- function range(from, to, step) {
91
- if (finalState.type === "date") {
92
- return dateRange(from, to, step);
150
+ function range<T extends IndexerStateValue>(from: T, to: T, step: number) {
151
+ if (typeof from === "string" && typeof to === "string") {
152
+ if (finalState.type === "date") {
153
+ return dateRange(from, to, step) as [T, T][];
154
+ }
155
+
156
+ throw new Error("Invalid type for numeric range");
157
+ }
158
+
159
+ if (typeof from === "number" && typeof to === "number") {
160
+ return numberRange(from, to, step) as [T, T][];
93
161
  }
94
162
 
95
- return numberRange(from, to, step);
163
+ throw new Error("Invalid type for range");
96
164
  }
97
165
 
98
- function fillRange(from, to) {
99
- if (finalState.type === "date") {
100
- return fillDateRange(from, to);
166
+ function fillRange(from: T, to: T) {
167
+ if (typeof from === "string" && typeof to === "string") {
168
+ if (finalState.type === "date") {
169
+ return fillDateRange(from, to) as T[];
170
+ }
171
+
172
+ throw new Error("Invalid type for numeric range");
173
+ }
174
+
175
+ if (typeof from === "number" && typeof to === "number") {
176
+ return fillNumberRange(from, to) as T[];
101
177
  }
102
178
 
103
- return fillNumberRange(from, to);
179
+ throw new Error("Invalid type for range");
104
180
  }
105
181
 
106
- function offsetRange(from, to) {
182
+ function offsetRange(from: T, to: T) {
107
183
  return fillRange(from, to).length;
108
184
  }
109
185
 
110
- async function runMode({ mode, from, to, status, verbose, ...selectorFlags }) {
186
+ async function runMode(flags: ModeIndexerFlags<TSelector>) {
187
+ const { mode, from: fromUntyped, to: toUntyped, status, verbose: verboseUntyped, ...untypeSelectorFlags } = flags;
188
+
189
+ const from = fromUntyped as T;
190
+ const to = toUntyped as T;
191
+ const verbose = verboseUntyped as boolean;
192
+ const selectorFlags = untypeSelectorFlags as ModeIndexerFlags<TSelector>;
193
+
111
194
  if (status) {
112
- const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
195
+ const stateItem = await getRecordByKey<IndexerState<RebuildStateValue>>(STATE_TABLE_NAME, {
113
196
  name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
114
197
  });
115
198
 
116
- const fromItem = await getRecordByKey(STATE_TABLE_NAME, {
199
+ const fromItem = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
117
200
  name: `${name}Since(${toSelectorString(selectorFlags)})`,
118
201
  });
119
202
 
120
- const validateItem = await getRecordByKey(STATE_TABLE_NAME, {
203
+ const validateItem = await getRecordByKey<IndexerState<T>>(STATE_TABLE_NAME, {
121
204
  name: `${name}Validate(${toSelectorString(selectorFlags)})`,
122
205
  });
123
206
 
@@ -137,22 +220,27 @@ function createModeIndexerApp({
137
220
  await runReset(selectorFlags);
138
221
  await runRebuild(selectorFlags, rebuildFrom, rebuildTo, verbose);
139
222
  } else if (mode === "resume-rebuild") {
140
- const previousRebuildEnds = await getIndexerLatestId(name, selectorFlags);
223
+ const previousRebuildEnds = await getIndexerLatestId<T, TSelector>(
224
+ name,
225
+ selectorFlags as ModeIndexerFlags<TSelector>,
226
+ );
141
227
 
142
228
  const rebuildFrom =
143
- from || increaseId(finalState.type, previousRebuildEnds, 1) || (await finalState.getMinId(selectorFlags));
229
+ from ||
230
+ (previousRebuildEnds !== undefined && increaseId(finalState.type, previousRebuildEnds, 1)) ||
231
+ (await finalState.getMinId(selectorFlags));
144
232
  const rebuildTo = to || (await finalState.getMaxId(selectorFlags));
145
233
 
146
234
  await runRebuild(selectorFlags, rebuildFrom, rebuildTo, verbose);
147
235
  } else if (mode === "validate" || mode === "validation") {
148
- const previousRebuildEnds = await getIndexerLatestId(name, selectorFlags);
236
+ const previousRebuildEnds = await getIndexerLatestId<T, TSelector>(name, selectorFlags);
149
237
 
150
238
  if (!previousRebuildEnds) {
151
239
  inline.log(`[MODE INDEXER] cannot validate without a successful rebuild`);
152
240
  process.exit(0);
153
241
  }
154
242
 
155
- const previousValidatedTo = await getIndexerValidatedId(name, selectorFlags);
243
+ const previousValidatedTo = await getIndexerValidatedId<T, TSelector>(name, selectorFlags);
156
244
 
157
245
  const validateFrom = from || previousValidatedTo || (await finalState.getMinId(selectorFlags));
158
246
  const validateTo = to || previousRebuildEnds;
@@ -177,7 +265,7 @@ function createModeIndexerApp({
177
265
 
178
266
  await runRange(selectorFlags, from, to, verbose);
179
267
  } else {
180
- const stateItem = await getRecordByKey(STATE_TABLE_NAME, {
268
+ const stateItem = await getRecordByKey<IndexerState<string>>(STATE_TABLE_NAME, {
181
269
  name: `${name}RebuildState(${toSelectorString(selectorFlags)})`,
182
270
  });
183
271
 
@@ -187,14 +275,20 @@ function createModeIndexerApp({
187
275
  process.exit(0);
188
276
  }
189
277
 
190
- const deltaFrom = increaseId(finalState.type, await getIndexerLatestId(name, selectorFlags), 1);
278
+ const latestId = await getIndexerLatestId<T, TSelector>(name, selectorFlags);
279
+
280
+ if (!latestId) {
281
+ throw new Error(`[MODE INDEXER] cannot find the latest ${finalState.type}`);
282
+ }
283
+
284
+ const deltaFrom = increaseId(finalState.type, latestId, 1);
191
285
  const deltaTo = await state.getMaxId(selectorFlags);
192
286
 
193
287
  await runDelta(selectorFlags, deltaFrom, deltaTo, verbose);
194
288
  }
195
289
  }
196
290
 
197
- async function runRange(selectorFlags, from, to, verbose) {
291
+ async function runRange(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
198
292
  const startTime = Date.now();
199
293
 
200
294
  inline.log(
@@ -215,7 +309,13 @@ function createModeIndexerApp({
215
309
  }
216
310
  }
217
311
 
218
- async function runValidate(selectorFlags, from, to, shouldSaveState, verbose) {
312
+ async function runValidate(
313
+ selectorFlags: ModeIndexerFlags<TSelector>,
314
+ from: T,
315
+ to: T,
316
+ shouldSaveState?: boolean,
317
+ verbose?: boolean,
318
+ ) {
219
319
  if (!validate) {
220
320
  inline.log(`[MODE INDEXER] the indexer doesn't support validate mode, validate function not implemented`);
221
321
  process.exit(1);
@@ -236,7 +336,7 @@ function createModeIndexerApp({
236
336
  `[MODE INDEXER] from=${from}, to=${to}, batchSize=${validateBatchSize}, concurrency=${validateConcurrency}`,
237
337
  );
238
338
 
239
- for (let [windowStart, windowEnd] of windows) {
339
+ for (const [windowStart, windowEnd] of windows) {
240
340
  inline.log(`[MODE INDEXER] validating window ${windowStart}~${windowEnd}, concurrency=${validateConcurrency}`);
241
341
 
242
342
  const batches = range(windowStart, windowEnd, validateBatchSize);
@@ -291,47 +391,54 @@ function createModeIndexerApp({
291
391
  );
292
392
  }
293
393
 
294
- async function execBuild(selectorFlags, from, to, verbose, shouldSaveState = false) {
295
- let failedIds = [];
394
+ async function execBuild(
395
+ selectorFlags: ModeIndexerFlags<TSelector>,
396
+ from: T,
397
+ to: T,
398
+ verbose: boolean,
399
+ shouldSaveState = false,
400
+ ) {
401
+ let failedIds: T[] = [];
296
402
 
297
403
  const windows = range(from, to, buildBatchSize * buildConcurrency);
298
404
 
299
- for (let [windowStart, windowEnd] of windows) {
405
+ for (const [windowStart, windowEnd] of windows) {
300
406
  inline.log(`[MODE INDEXER] building window ${windowStart}~${windowEnd}, concurrency = ${buildConcurrency}`);
301
407
 
302
408
  const batches = range(windowStart, windowEnd, buildBatchSize);
303
409
 
304
410
  // add a retry for errors
305
411
  const batchResults = await Promise.all(
306
- batches.map(async ([batchStart, batchEnd]) => {
307
- await exponentialRetry(
308
- async () => {
309
- try {
310
- const ids = await build({
311
- ...selectorFlags,
312
- from: batchStart,
313
- to: batchEnd,
314
- verbose,
315
- });
316
-
317
- if (ids && ids.length > 0) {
318
- return ids;
319
- } else {
320
- return false;
412
+ batches.map(
413
+ async ([batchStart, batchEnd]) =>
414
+ await exponentialRetry(
415
+ async () => {
416
+ try {
417
+ const ids = await build({
418
+ ...selectorFlags,
419
+ from: batchStart,
420
+ to: batchEnd,
421
+ verbose,
422
+ });
423
+
424
+ if (ids && ids.length > 0) {
425
+ return ids;
426
+ } else {
427
+ return false;
428
+ }
429
+ } catch (err) {
430
+ inline.error(`[MODE INDEXER] got error in build`, err);
431
+
432
+ return fillRange(batchStart, batchEnd);
321
433
  }
322
- } catch (err) {
323
- inline.error(`[MODE INDEXER] got error in build`, err);
324
-
325
- return fillRange(batchStart, batchEnd);
326
- }
327
- },
328
- {
329
- maxRetry,
330
- test: (r) => !r,
331
- verbose,
332
- },
333
- );
334
- }),
434
+ },
435
+ {
436
+ maxRetry,
437
+ test: (r) => !r,
438
+ verbose,
439
+ },
440
+ ),
441
+ ),
335
442
  );
336
443
 
337
444
  if (shouldSaveState) {
@@ -357,7 +464,7 @@ function createModeIndexerApp({
357
464
  return failedIds;
358
465
  }
359
466
 
360
- async function runRebuild(selectorFlags, from, to, verbose) {
467
+ async function runRebuild(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
361
468
  const startTime = Date.now();
362
469
 
363
470
  inline.log(
@@ -403,7 +510,7 @@ function createModeIndexerApp({
403
510
  }
404
511
  }
405
512
 
406
- async function runDelta(selectorFlags, from, to, verbose) {
513
+ async function runDelta(selectorFlags: ModeIndexerFlags<TSelector>, from: T, to: T, verbose: boolean) {
407
514
  const startTime = Date.now();
408
515
 
409
516
  if (to < from) {
@@ -437,7 +544,7 @@ function createModeIndexerApp({
437
544
 
438
545
  await createRecord(STATE_TABLE_NAME, {
439
546
  name: `${name}Since(${toSelectorString(selectorFlags)})`,
440
- value: Math.min(to, failedIds[0]),
547
+ value: to < failedIds[0] ? to : failedIds[0],
441
548
  });
442
549
 
443
550
  process.exit(1);
@@ -462,7 +569,7 @@ function createModeIndexerApp({
462
569
  }
463
570
  }
464
571
 
465
- async function runReset(selectorFlags) {
572
+ async function runReset(selectorFlags: ModeIndexerFlags<TSelector>) {
466
573
  const startTime = Date.now();
467
574
 
468
575
  inline.log(`[MODE INDEXER] starting reset, ${toSelectorString(selectorFlags, ", ")}`);
@@ -486,7 +593,7 @@ function createModeIndexerApp({
486
593
  inline.log(`[MODE INDEXER] reset successfully in ${Date.now() - startTime}ms`);
487
594
  }
488
595
 
489
- function run() {
596
+ async function run() {
490
597
  if (!binaryName) {
491
598
  binaryName = getBinaryName();
492
599
  }
@@ -498,7 +605,7 @@ function createModeIndexerApp({
498
605
  $ ${binaryName} <options>
499
606
 
500
607
  Options
501
- ${getSelectorDesc(selector)}
608
+ ${selector ? getSelectorDesc(selector) : ""}
502
609
  --mode could be delta/rebuild/resume-rebuild/validate/one/range/reset
503
610
  --from min ${finalState.type} to build
504
611
  --to max ${finalState.type} to build
@@ -535,20 +642,32 @@ ${getSelectorDesc(selector)}
535
642
  },
536
643
  );
537
644
 
538
- return runMode(cli.flags).catch((err) => {
645
+ try {
646
+ return runMode(cli.flags);
647
+ } catch (err) {
539
648
  inline.error(err);
540
649
  process.exit(1);
541
- });
650
+ }
542
651
  }
543
652
 
544
653
  return { run };
545
654
  }
546
655
 
547
- // for those indexers that does not rely on a curosr
656
+ // for indexers that don't rely on a cursor
548
657
  // e.g. should always rebuild everything from scratch
549
658
  // or that the state can be easily inferred from existing data
550
- function createIndexerApp({ binaryName, selector = {}, build, maxRetry = 2 }) {
551
- function run() {
659
+ function createIndexerApp<TSelector extends Selector>({
660
+ binaryName,
661
+ selector = {} as TSelector,
662
+ build,
663
+ maxRetry = 2,
664
+ }: {
665
+ binaryName: string;
666
+ selector?: TSelector;
667
+ build: StatelessBuildFunction<TSelector>;
668
+ maxRetry?: number;
669
+ }) {
670
+ async function run() {
552
671
  if (!binaryName) {
553
672
  binaryName = getBinaryName();
554
673
  }
@@ -559,7 +678,7 @@ function createIndexerApp({ binaryName, selector = {}, build, maxRetry = 2 }) {
559
678
  $ ${binaryName} <options>
560
679
 
561
680
  Options
562
- ${getSelectorDesc(selector)}
681
+ ${selector ? getSelectorDesc(selector) : ""}
563
682
  --verbose Output debug messages
564
683
  `,
565
684
  {
@@ -576,7 +695,12 @@ ${getSelectorDesc(selector)}
576
695
  },
577
696
  );
578
697
 
579
- async function runBuild({ verbose, ...selectorFlags }) {
698
+ async function runBuild(flags: StatelessIndexerFlags<TSelector>) {
699
+ const { verbose: untypedVerbose, ...untypedSelectorFlags } = flags;
700
+
701
+ const verbose = untypedVerbose as boolean;
702
+ const selectorFlags = untypedSelectorFlags as StatelessIndexerFlags<TSelector>;
703
+
580
704
  const startTime = Date.now();
581
705
 
582
706
  if (Object.keys(selectorFlags).length > 0) {
@@ -588,7 +712,7 @@ ${getSelectorDesc(selector)}
588
712
  const result = await exponentialRetry(
589
713
  async () => {
590
714
  try {
591
- await build({ verbose, ...selectorFlags });
715
+ await build(flags);
592
716
 
593
717
  return true;
594
718
  } catch (err) {
@@ -600,7 +724,7 @@ ${getSelectorDesc(selector)}
600
724
  {
601
725
  maxRetry,
602
726
  test: (r) => r,
603
- verbose,
727
+ verbose: verbose as boolean,
604
728
  },
605
729
  );
606
730
 
@@ -620,11 +744,6 @@ ${getSelectorDesc(selector)}
620
744
  return { run };
621
745
  }
622
746
 
623
- export {
624
- increaseId,
625
- createModeIndexerApp,
626
- createIndexerApp,
627
- getIndexerState,
628
- getIndexerLatestId,
629
- getIndexerValidatedId,
630
- };
747
+ export { increaseId, createModeIndexerApp, createIndexerApp };
748
+
749
+ export type { IndexerStateValue, State, StatelessBuildFunction, ModeBuildFunction, ValidateFunction };
@@ -1,8 +1,8 @@
1
- function isObject(a) {
1
+ function isObject(a: unknown): a is Record<string, unknown> {
2
2
  return !!a && a.constructor === Object;
3
3
  }
4
4
 
5
- function print(o) {
5
+ function print(o: unknown): string {
6
6
  if (Array.isArray(o)) {
7
7
  return `[${o.map(print).join(", ")}]`;
8
8
  }
@@ -16,7 +16,7 @@ function print(o) {
16
16
  return `${o}`;
17
17
  }
18
18
 
19
- function getLine(params) {
19
+ function getLine(params: unknown[]) {
20
20
  let line = "";
21
21
 
22
22
  // Convert to string and filter out newline to tabs (AWS Athena)
@@ -34,12 +34,12 @@ function timestamp() {
34
34
  }
35
35
 
36
36
  const inline = {
37
- log: function (...args) {
37
+ log: function (...args: unknown[]) {
38
38
  console.log(`${timestamp()} ${getLine(args)}`);
39
39
  },
40
- error: function (...args) {
40
+ error: function (...args: unknown[]) {
41
41
  console.error(`${timestamp()} ${getLine(args)}`);
42
42
  },
43
43
  };
44
44
 
45
- export { getLine, print, inline };
45
+ export { print, getLine, inline };