@certik/skynet 0.18.9 → 0.19.1

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 (71) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -2
  3. package/{abi.js → abi.ts} +5 -132
  4. package/{address.js → address.ts} +4 -4
  5. package/{api.js → api.ts} +80 -20
  6. package/{app.js → app.ts} +138 -25
  7. package/{availability.js → availability.ts} +18 -21
  8. package/bun.lockb +0 -0
  9. package/{cli.js → cli.ts} +1 -1
  10. package/{const.js → const.ts} +42 -3
  11. package/databricks.ts +82 -0
  12. package/{date.js → date.ts} +5 -5
  13. package/{deploy.js → deploy.ts} +157 -44
  14. package/{dynamodb.js → dynamodb.ts} +159 -186
  15. package/env.ts +25 -0
  16. package/eslint.config.mjs +7 -0
  17. package/examples/{api.js → api.ts} +7 -6
  18. package/examples/{indexer.js → indexer.ts} +9 -10
  19. package/examples/{mode-indexer.js → mode-indexer.ts} +18 -10
  20. package/graphql.ts +43 -0
  21. package/{indexer.js → indexer.ts} +228 -109
  22. package/{log.js → log.ts} +6 -6
  23. package/{opsgenie.js → opsgenie.ts} +29 -6
  24. package/package.json +17 -11
  25. package/{s3.js → s3.ts} +29 -19
  26. package/search.ts +37 -0
  27. package/selector.ts +72 -0
  28. package/{slack.js → slack.ts} +19 -12
  29. package/snowflake.ts +51 -0
  30. package/tsconfig.json +26 -0
  31. package/util.ts +35 -0
  32. package/web3.ts +41 -0
  33. package/.eslintignore +0 -1
  34. package/.eslintrc.json +0 -20
  35. package/abi.d.ts +0 -20
  36. package/address.d.ts +0 -2
  37. package/api.d.ts +0 -12
  38. package/app.d.ts +0 -118
  39. package/availability.d.ts +0 -18
  40. package/cli.d.ts +0 -4
  41. package/const.d.ts +0 -42
  42. package/databricks.js +0 -82
  43. package/deploy.d.ts +0 -51
  44. package/dns.d.ts +0 -1
  45. package/dns.js +0 -27
  46. package/dynamodb.d.ts +0 -63
  47. package/env.d.ts +0 -6
  48. package/env.js +0 -42
  49. package/examples/consumer.js +0 -30
  50. package/examples/producer.js +0 -63
  51. package/graphql.d.ts +0 -3
  52. package/graphql.js +0 -22
  53. package/indexer.d.ts +0 -32
  54. package/log.d.ts +0 -8
  55. package/opsgenie.d.ts +0 -8
  56. package/proxy.d.ts +0 -9
  57. package/proxy.js +0 -154
  58. package/s3.d.ts +0 -36
  59. package/search.d.ts +0 -5
  60. package/search.js +0 -29
  61. package/selector.d.ts +0 -19
  62. package/selector.js +0 -71
  63. package/slack.d.ts +0 -10
  64. package/snowflake.d.ts +0 -4
  65. package/snowflake.js +0 -33
  66. package/sqs.d.ts +0 -3
  67. package/sqs.js +0 -5
  68. package/util.d.ts +0 -5
  69. package/util.js +0 -61
  70. package/web3.d.ts +0 -25
  71. package/web3.js +0 -113
@@ -6,14 +6,24 @@ import {
6
6
  PutCommand,
7
7
  QueryCommand,
8
8
  UpdateCommand,
9
- TransactWriteCommand,
9
+ } from "@aws-sdk/lib-dynamodb";
10
+ import type {
11
+ ScanCommandInput,
12
+ PutCommandInput,
13
+ GetCommandInput,
14
+ QueryCommandInput,
15
+ UpdateCommandOutput,
16
+ UpdateCommandInput,
17
+ ScanCommandOutput,
10
18
  } from "@aws-sdk/lib-dynamodb";
11
19
  import { DynamoDBClient, DescribeTableCommand } from "@aws-sdk/client-dynamodb";
20
+ import type { KeySchemaElement, GlobalSecondaryIndexDescription } from "@aws-sdk/client-dynamodb";
12
21
  import { wait } from "./availability.js";
22
+ import { arrayGroup } from "./util.js";
13
23
 
14
- let _dynamoDB;
24
+ let _dynamoDB: DynamoDBClient;
15
25
 
16
- let _docClient;
26
+ let _docClient: DynamoDBDocumentClient;
17
27
 
18
28
  function getDynamoDB(forceNew = false) {
19
29
  if (!_dynamoDB || forceNew) {
@@ -46,47 +56,44 @@ function getDocClient(forceNew = false) {
46
56
  return _docClient;
47
57
  }
48
58
 
49
- function mergeQueries(q1, q2) {
50
- return {
51
- Items: q1.Items.concat(q2.Items),
52
- Count: q1.Count + q2.Count,
53
- ScannedCount: q1.ScannedCount + q2.ScannedCount,
54
- };
55
- }
56
-
57
- async function scanWholeTable(options) {
59
+ async function scanWholeTable(options: ScanCommandInput) {
58
60
  const dynamodb = getDocClient();
59
61
 
60
- let items = {
61
- Items: [],
62
- Count: 0,
63
- ScannedCount: 0,
64
- };
62
+ let items: ScanCommandOutput["Items"] = [];
63
+ let count = 0;
64
+ let scannedCount = 0;
65
65
 
66
66
  let data = await dynamodb.send(new ScanCommand(options));
67
67
 
68
68
  while (data.LastEvaluatedKey) {
69
- items = mergeQueries(items, data);
69
+ if (data.Items) {
70
+ items = items.concat(data.Items);
71
+ }
72
+ count += data.Count || 0;
73
+ scannedCount += data.ScannedCount || 0;
70
74
 
71
75
  data = await dynamodb.send(new ScanCommand({ ...options, ExclusiveStartKey: data.LastEvaluatedKey }));
72
76
  }
73
77
 
74
- items = mergeQueries(items, data);
75
-
76
- return items;
77
- }
78
-
79
- function toSlices(items) {
80
- let slices = [];
81
-
82
- for (let start = 0; start < items.length; start += 25) {
83
- slices.push(items.slice(start, start + 25));
78
+ if (data.Items) {
79
+ items = items.concat(data.Items);
84
80
  }
81
+ count += data.Count || 0;
82
+ scannedCount += data.ScannedCount || 0;
85
83
 
86
- return slices;
84
+ return {
85
+ Items: items,
86
+ Count: count,
87
+ ScannedCount: scannedCount,
88
+ };
87
89
  }
88
90
 
89
- async function batchCreateRecords(tableName, records, maxWritingCapacity, verbose = false) {
91
+ async function batchCreateRecords(
92
+ tableName: string,
93
+ records: Record<string, unknown>[],
94
+ maxWritingCapacity?: number,
95
+ verbose = false,
96
+ ) {
90
97
  if (verbose) {
91
98
  console.log(`creating ${records.length} items in ${tableName}`);
92
99
  }
@@ -96,7 +103,7 @@ async function batchCreateRecords(tableName, records, maxWritingCapacity, verbos
96
103
  // an arbitrary number to ensure while first loop is entered
97
104
  let prevRemainingCount = remainingItems.length + 1;
98
105
  let factor = 1;
99
- let rejection = undefined;
106
+ let rejection: PromiseRejectedResult | undefined = undefined;
100
107
 
101
108
  while (remainingItems.length > 0 && factor <= 128 && !rejection) {
102
109
  if (prevRemainingCount === remainingItems.length) {
@@ -108,35 +115,36 @@ async function batchCreateRecords(tableName, records, maxWritingCapacity, verbos
108
115
  console.log(`WARNING: no progress for a long time for batchCreateRecords, please check`);
109
116
  }
110
117
 
111
- const slices = toSlices(remainingItems.slice(0, maxWritingCapacity));
118
+ const slices = arrayGroup(remainingItems.slice(0, maxWritingCapacity), 25);
112
119
  const results = await Promise.allSettled(
113
- slices.map((rs) => {
114
- const params = {
115
- RequestItems: {
116
- [tableName]: rs.map((record) => {
117
- return { PutRequest: { Item: record } };
118
- }),
119
- },
120
- };
121
-
122
- return docClient.send(new BatchWriteCommand(params));
123
- }),
120
+ slices.map((rs) =>
121
+ docClient.send(
122
+ new BatchWriteCommand({
123
+ RequestItems: {
124
+ [tableName]: rs.map((record) => ({ PutRequest: { Item: record } })),
125
+ },
126
+ }),
127
+ ),
128
+ ),
124
129
  );
125
130
 
131
+ const isFulfilled = <T>(p: PromiseSettledResult<T>): p is PromiseFulfilledResult<T> => p.status === "fulfilled";
132
+ const isRejected = <T>(p: PromiseSettledResult<T>): p is PromiseRejectedResult => p.status === "rejected";
133
+
126
134
  prevRemainingCount = remainingItems.length;
135
+ remainingItems = remainingItems.slice(maxWritingCapacity);
127
136
 
128
- remainingItems = results.reduce((acc, rs, idx) => {
129
- if (rs.status === "rejected") {
137
+ results.forEach((rs, idx) => {
138
+ if (isRejected(rs)) {
130
139
  // whole slice fails, redo whole slice
131
- acc = acc.concat(slices[idx]);
140
+ remainingItems = remainingItems.concat(slices[idx]);
132
141
  rejection = rs;
133
- } else if (Object.keys(rs.value.UnprocessedItems).length > 0) {
142
+ } else if (isFulfilled(rs) && rs.value.UnprocessedItems && Object.keys(rs.value.UnprocessedItems).length > 0) {
134
143
  // partially fails, redo unprocessedItems
135
- acc = acc.concat(rs.value.UnprocessedItems[tableName].map((it) => it.PutRequest.Item));
144
+ const unprocessedItems = rs.value.UnprocessedItems[tableName].map((it) => it.PutRequest?.Item ?? []).flat();
145
+ remainingItems = remainingItems.concat(unprocessedItems);
136
146
  }
137
-
138
- return acc;
139
- }, remainingItems.slice(maxWritingCapacity));
147
+ });
140
148
 
141
149
  if (verbose) {
142
150
  console.log(`processed=${prevRemainingCount - remainingItems.length}, remaining=${remainingItems.length}`);
@@ -156,7 +164,7 @@ async function batchCreateRecords(tableName, records, maxWritingCapacity, verbos
156
164
  }
157
165
  }
158
166
 
159
- async function createRecord(tableName, fields, verbose = false) {
167
+ async function createRecord(tableName: string, fields: PutCommandInput["Item"], verbose = false) {
160
168
  if (verbose) {
161
169
  console.log("creating", tableName, fields);
162
170
  }
@@ -170,7 +178,7 @@ async function createRecord(tableName, fields, verbose = false) {
170
178
  return docClient.send(new PutCommand(params));
171
179
  }
172
180
 
173
- async function readRecord(tableName, key, verbose = false) {
181
+ async function readRecord<T>(tableName: string, key: GetCommandInput["Key"], verbose = false) {
174
182
  if (verbose) {
175
183
  console.log("reading", tableName, key);
176
184
  }
@@ -184,16 +192,20 @@ async function readRecord(tableName, key, verbose = false) {
184
192
  }),
185
193
  );
186
194
 
187
- return record.Item;
195
+ return record.Item as T;
188
196
  }
189
197
 
190
- async function getRecordsByKey(tableName, keys, indexName) {
198
+ async function getRecordsByKey<TReturn, TKey extends Record<string, unknown> = Record<string, unknown>>(
199
+ tableName: string,
200
+ keys: TKey,
201
+ indexName?: string,
202
+ ) {
191
203
  const docClient = getDocClient();
192
204
 
193
205
  const keyNames = Object.keys(keys);
194
206
  const conditionExpression = keyNames.map((key) => `#${key} = :${key}`).join(" and ");
195
207
 
196
- const params = {
208
+ const params: QueryCommandInput = {
197
209
  TableName: tableName,
198
210
  KeyConditionExpression: conditionExpression,
199
211
  ExpressionAttributeNames: generateExpressionNames(keyNames),
@@ -204,12 +216,10 @@ async function getRecordsByKey(tableName, keys, indexName) {
204
216
  params.IndexName = indexName;
205
217
  }
206
218
 
207
- let data;
208
-
209
219
  try {
210
- data = await docClient.send(new QueryCommand(params));
220
+ let data = await docClient.send(new QueryCommand(params));
211
221
 
212
- let items = data.Items;
222
+ let items = data.Items ?? [];
213
223
 
214
224
  while (data.LastEvaluatedKey) {
215
225
  data = await docClient.send(
@@ -219,13 +229,15 @@ async function getRecordsByKey(tableName, keys, indexName) {
219
229
  }),
220
230
  );
221
231
 
222
- items = items.concat(data.Items);
232
+ if (data.Items) {
233
+ items = items.concat(data.Items);
234
+ }
223
235
  }
224
236
 
225
- return items;
237
+ return items as TReturn[];
226
238
  } catch (err) {
227
239
  console.log(err);
228
- if (err.statusCode && err.statusCode === 400) {
240
+ if (err instanceof Error && "statusCode" in err && err.statusCode === 400) {
229
241
  return null;
230
242
  }
231
243
 
@@ -234,9 +246,9 @@ async function getRecordsByKey(tableName, keys, indexName) {
234
246
  }
235
247
 
236
248
  // Dual purpose for compatibility. If indexName is provided, it will use query command to get the record; if not, use get command which is most efficient.
237
- async function getRecordByKey(tableName, keys, indexName) {
249
+ async function getRecordByKey<T>(tableName: string, keys: Record<string, unknown>, indexName?: string) {
238
250
  if (indexName) {
239
- const records = await getRecordsByKey(tableName, keys, indexName);
251
+ const records = await getRecordsByKey<T>(tableName, keys, indexName);
240
252
 
241
253
  if (records) {
242
254
  return records[0];
@@ -244,25 +256,28 @@ async function getRecordByKey(tableName, keys, indexName) {
244
256
  return null;
245
257
  }
246
258
  } else {
247
- return readRecord(tableName, keys);
259
+ return readRecord<T>(tableName, keys);
248
260
  }
249
261
  }
250
262
 
251
- function generateExpressionNames(keys) {
252
- return keys.reduce((acc, key) => {
253
- acc[`#${key}`] = key;
254
- return acc;
255
- }, {});
263
+ function generateExpressionNames(keys: string[]): QueryCommandInput["ExpressionAttributeNames"] {
264
+ return keys.reduce((acc, key) => ({ ...acc, [`#${key}`]: key }), {});
256
265
  }
257
266
 
258
- function generateExpressionValues(keys, fields) {
259
- return keys.reduce((acc, key) => {
260
- acc[`:${key}`] = fields[key];
261
- return acc;
262
- }, {});
267
+ function generateExpressionValues(
268
+ keys: string[],
269
+ fields: Record<string, unknown>,
270
+ ): QueryCommandInput["ExpressionAttributeValues"] {
271
+ return keys.reduce((acc, key) => ({ ...acc, [`:${key}`]: fields[key] }), {});
263
272
  }
264
273
 
265
- async function updateRecordByKey(tableName, idKey, fields, conditionExpressions = null, verbose = false) {
274
+ async function updateRecordByKey(
275
+ tableName: string,
276
+ idKey: Record<string, unknown>,
277
+ fields: Record<string, unknown>,
278
+ conditionExpressions = null,
279
+ verbose = false,
280
+ ) {
266
281
  if (verbose) {
267
282
  console.log("update", tableName, idKey, fields);
268
283
  }
@@ -273,14 +288,14 @@ async function updateRecordByKey(tableName, idKey, fields, conditionExpressions
273
288
  const fieldsToDelete = Object.keys(fields).filter((f) => fields[f] === undefined);
274
289
  const fieldsToUpdate = Object.keys(fields).filter((k) => !idKeyNames.includes(k) && !fieldsToDelete.includes(k));
275
290
 
276
- let data;
291
+ let data: UpdateCommandOutput | undefined;
277
292
 
278
293
  if (fieldsToDelete.length > 0) {
279
294
  if (verbose) {
280
295
  console.log("delete fields", tableName, fieldsToDelete);
281
296
  }
282
297
 
283
- const deleteParams = {
298
+ const deleteParams: UpdateCommandInput = {
284
299
  TableName: tableName,
285
300
  Key: idKey,
286
301
  ExpressionAttributeNames: generateExpressionNames(fieldsToDelete),
@@ -302,7 +317,7 @@ async function updateRecordByKey(tableName, idKey, fields, conditionExpressions
302
317
 
303
318
  const updateExpressions = fieldsToUpdate.map((key) => `#${key} = :${key}`);
304
319
 
305
- const params = {
320
+ const params: UpdateCommandInput = {
306
321
  TableName: tableName,
307
322
  Key: idKey,
308
323
  ExpressionAttributeNames: generateExpressionNames(fieldsToUpdate),
@@ -318,70 +333,10 @@ async function updateRecordByKey(tableName, idKey, fields, conditionExpressions
318
333
  data = await docClient.send(new UpdateCommand(params));
319
334
  }
320
335
 
321
- return data && data.Attributes;
322
- }
323
-
324
- async function createTableIfNotExist(
325
- tableName,
326
- attributeDefinitions = [
327
- {
328
- AttributeName: "id",
329
- AttributeType: "S",
330
- },
331
- ],
332
- keySchema = [
333
- {
334
- AttributeName: "id",
335
- KeyType: "HASH",
336
- },
337
- ],
338
- otherOptions = {},
339
- verbose = false,
340
- ) {
341
- const dynamodb = getDynamoDB();
342
-
343
- try {
344
- const table = await dynamodb.send(new DescribeTableCommand({ TableName: tableName }));
345
-
346
- if (verbose) {
347
- console.log(`table ${tableName} already exist`, table);
348
- }
349
- return table;
350
- } catch (_tableDoesNotExistErr) {
351
- const createRequest = await dynamodb
352
- .createTable({
353
- TableName: tableName,
354
- AttributeDefinitions: attributeDefinitions,
355
- KeySchema: keySchema,
356
- ProvisionedThroughput: {
357
- ReadCapacityUnits: 5,
358
- WriteCapacityUnits: 5,
359
- },
360
- ...otherOptions,
361
- })
362
- .promise();
363
-
364
- if (verbose) {
365
- console.log(`table ${tableName} creating`);
366
- }
367
-
368
- let isCreated = false;
369
-
370
- while (!isCreated) {
371
- await wait(5000);
372
-
373
- const t = await dynamodb.send(new DescribeTableCommand({ TableName: tableName }));
374
-
375
- console.log("waiting for table to become active");
376
-
377
- isCreated = t.Table.TableStatus === "ACTIVE";
378
- }
379
-
380
- return createRequest;
381
- }
336
+ return data?.Attributes;
382
337
  }
383
338
 
384
- async function batchDeleteRecords(tableName, keys) {
339
+ async function batchDeleteRecords(tableName: string, keys: Record<string, unknown>[]) {
385
340
  const docClient = getDocClient();
386
341
 
387
342
  for (let start = 0; start < keys.length; start += 25) {
@@ -399,37 +354,63 @@ async function batchDeleteRecords(tableName, keys) {
399
354
  }
400
355
  }
401
356
 
402
- function getKeyName(keySchema, type) {
357
+ function getKeyName(keySchema: KeySchemaElement[], type: string) {
403
358
  const key = keySchema.find((k) => k.KeyType === type);
404
359
 
405
- return key && key.AttributeName;
360
+ return key?.AttributeName;
406
361
  }
407
362
 
408
- function getIndexKeyName(globalSecondaryIndexes, indexName, type) {
363
+ function getIndexKeyName(globalSecondaryIndexes: GlobalSecondaryIndexDescription[], indexName: string, type: string) {
409
364
  const idx = globalSecondaryIndexes.find((i) => i.IndexName === indexName);
410
365
 
411
- return idx && getKeyName(idx.KeySchema, type);
366
+ return idx?.KeySchema && getKeyName(idx.KeySchema, type);
412
367
  }
413
368
 
414
- async function deleteRecordsByHashKey(tableName, indexName, hashKeyValue, verbose = false) {
369
+ async function deleteRecordsByHashKey(
370
+ tableName: string,
371
+ indexName: string | undefined,
372
+ hashKeyValue: string,
373
+ verbose = false,
374
+ ) {
415
375
  const docClient = getDocClient();
416
376
 
417
377
  const meta = await getDynamoDB().send(new DescribeTableCommand({ TableName: tableName }));
418
378
 
379
+ if (!meta.Table) {
380
+ throw new Error(`cannot find table ${tableName}`);
381
+ }
382
+
383
+ if (indexName && !meta.Table.GlobalSecondaryIndexes) {
384
+ throw new Error(`cannot find global secondary indexes for table ${tableName}`);
385
+ }
386
+
387
+ if (!meta.Table.KeySchema) {
388
+ throw new Error(`cannot find key schema for table ${tableName}`);
389
+ }
390
+
419
391
  const hashKeyName = indexName
420
- ? getIndexKeyName(meta.Table.GlobalSecondaryIndexes, indexName, "HASH")
392
+ ? getIndexKeyName(meta.Table.GlobalSecondaryIndexes!, indexName, "HASH")
421
393
  : getKeyName(meta.Table.KeySchema, "HASH");
422
394
 
423
395
  if (!hashKeyName) {
424
- throw new Error(`cannot find corresponding index`, indexName);
396
+ throw new Error(`cannot find hash key name for table ${tableName}`);
425
397
  }
426
398
 
427
399
  const mainHashKeyName = getKeyName(meta.Table.KeySchema, "HASH");
400
+
401
+ if (!mainHashKeyName) {
402
+ throw new Error(`cannot find main hash key name for table ${tableName}`);
403
+ }
404
+
428
405
  const mainRangeKeyName = getKeyName(meta.Table.KeySchema, "RANGE");
429
406
 
407
+ if (!mainRangeKeyName) {
408
+ throw new Error(`cannot find main range key name for table ${tableName}`);
409
+ }
410
+
430
411
  let totalDeleted = 0;
431
412
 
432
- let params = {
413
+ const params: QueryCommandInput = {
433
414
  TableName: tableName,
434
415
  KeyConditionExpression: "#hashKeyName = :hashKeyValue",
435
416
  ExpressionAttributeNames: { "#hashKeyName": hashKeyName },
@@ -442,30 +423,7 @@ async function deleteRecordsByHashKey(tableName, indexName, hashKeyValue, verbos
442
423
 
443
424
  let data = await docClient.send(new QueryCommand(params));
444
425
 
445
- await batchDeleteRecords(
446
- tableName,
447
- data.Items.map((item) =>
448
- mainRangeKeyName
449
- ? {
450
- [mainHashKeyName]: item[mainHashKeyName],
451
- [mainRangeKeyName]: item[mainRangeKeyName],
452
- }
453
- : {
454
- [mainHashKeyName]: item[mainHashKeyName],
455
- },
456
- ),
457
- );
458
-
459
- totalDeleted += data.Items.length;
460
-
461
- while (data.LastEvaluatedKey) {
462
- data = await docClient.send(
463
- new QueryCommand({
464
- ...params,
465
- ExclusiveStartKey: data.LastEvaluatedKey,
466
- }),
467
- );
468
-
426
+ if (data.Items) {
469
427
  await batchDeleteRecords(
470
428
  tableName,
471
429
  data.Items.map((item) =>
@@ -483,6 +441,33 @@ async function deleteRecordsByHashKey(tableName, indexName, hashKeyValue, verbos
483
441
  totalDeleted += data.Items.length;
484
442
  }
485
443
 
444
+ while (data.LastEvaluatedKey) {
445
+ data = await docClient.send(
446
+ new QueryCommand({
447
+ ...params,
448
+ ExclusiveStartKey: data.LastEvaluatedKey,
449
+ }),
450
+ );
451
+
452
+ if (data.Items) {
453
+ await batchDeleteRecords(
454
+ tableName,
455
+ data.Items.map((item) =>
456
+ mainRangeKeyName
457
+ ? {
458
+ [mainHashKeyName]: item[mainHashKeyName],
459
+ [mainRangeKeyName]: item[mainRangeKeyName],
460
+ }
461
+ : {
462
+ [mainHashKeyName]: item[mainHashKeyName],
463
+ },
464
+ ),
465
+ );
466
+
467
+ totalDeleted += data.Items.length;
468
+ }
469
+ }
470
+
486
471
  if (verbose) {
487
472
  console.log(`successfully delete ${totalDeleted} items`);
488
473
  }
@@ -490,16 +475,6 @@ async function deleteRecordsByHashKey(tableName, indexName, hashKeyValue, verbos
490
475
  return totalDeleted;
491
476
  }
492
477
 
493
- async function transactWrite(items) {
494
- const docClient = getDocClient();
495
-
496
- return docClient.send(
497
- new TransactWriteCommand({
498
- TransactItems: items,
499
- }),
500
- );
501
- }
502
-
503
478
  export {
504
479
  getDocClient,
505
480
  // export common dynamodb commands to make it easier to use
@@ -517,6 +492,4 @@ export {
517
492
  updateRecordByKey,
518
493
  batchDeleteRecords,
519
494
  deleteRecordsByHashKey,
520
- createTableIfNotExist,
521
- transactWrite,
522
495
  };
package/env.ts ADDED
@@ -0,0 +1,25 @@
1
+ function ensureAndGet(envName: string, defaultValue?: string) {
2
+ return process.env[envName] || defaultValue;
3
+ }
4
+
5
+ function getEnvironment() {
6
+ return ensureAndGet("SKYNET_ENVIRONMENT", "dev");
7
+ }
8
+
9
+ function getEnvOrThrow(envName: string) {
10
+ if (!process.env[envName]) {
11
+ throw new Error(`Must set environment variable ${envName}`);
12
+ }
13
+
14
+ return process.env[envName];
15
+ }
16
+
17
+ function isProduction() {
18
+ return getEnvironment() === "prd";
19
+ }
20
+
21
+ function isDev() {
22
+ return getEnvironment() === "dev";
23
+ }
24
+
25
+ export { ensureAndGet, getEnvOrThrow, getEnvironment, isProduction, isDev };
@@ -0,0 +1,7 @@
1
+ import eslint from '@eslint/js';
2
+ import tseslint from 'typescript-eslint';
3
+
4
+ export default tseslint.config(
5
+ eslint.configs.recommended,
6
+ tseslint.configs.recommended,
7
+ );
@@ -7,19 +7,20 @@
7
7
  // $ examples/api deploy
8
8
  // $ examples/api --help
9
9
 
10
- import { api, every, SENSITIVE_VALUE, ERROR_LEVEL } from "../app.js";
10
+ import type { Request, Response, NextFunction } from "express";
11
+ import { api, SENSITIVE_VALUE } from "../app.ts";
11
12
 
12
13
  // an example middleware
13
- async function exampleMiddleware(req, res, next) {
14
+ async function exampleMiddleware(req: Request, res: Response, next: NextFunction) {
14
15
  console.log("before request!");
15
16
  next();
16
17
  console.log("after request!");
17
18
  }
18
19
 
19
- async function getProjectsHandler({ req, res, verbose }) {
20
+ async function getProjectsHandler({ req, res, verbose }: { req: Request; res: Response; verbose?: boolean }) {
20
21
  console.log("receieved call", req.query, verbose);
21
22
 
22
- const type = req.query.type;
23
+ const type = req.query["type"];
23
24
 
24
25
  if (!type) {
25
26
  res.status(400).end("must provide type parameter");
@@ -29,7 +30,7 @@ async function getProjectsHandler({ req, res, verbose }) {
29
30
  res.json([{ id: "proj-1", name: "Test Project 1" }]);
30
31
  }
31
32
 
32
- async function createProjectHandler({ req, res, verbose }) {
33
+ async function createProjectHandler({ req, res, verbose }: { req: Request; res: Response; verbose?: boolean }) {
33
34
  console.log("receieved call", req.body, verbose);
34
35
 
35
36
  res.json({ success: true });
@@ -61,7 +62,7 @@ const app = api({
61
62
  serve: {
62
63
  prefix: "/example-api", // deployed to a sub path
63
64
  port: 12345,
64
- apiKey: process.env.EXAMPLE_API_KEY,
65
+ apiKey: process.env["EXAMPLE_API_KEY"],
65
66
  cpu: 600,
66
67
  mem: 600,
67
68
  instances: 3, // run 3 instances
@@ -7,15 +7,7 @@
7
7
  // $ examples/indexer deploy --protocol eth
8
8
  // $ examples/indexer --help
9
9
 
10
- import { indexer, every, ERROR_LEVEL } from "../app.js";
11
-
12
- async function build({ protocol, verbose }) {
13
- console.log("build called with", protocol, verbose);
14
-
15
- if (protocol === "eth") {
16
- throw new Error("use eth to test error handling");
17
- }
18
- }
10
+ import { indexer, every } from "../app.ts";
19
11
 
20
12
  const app = indexer({
21
13
  name: "example-indexer",
@@ -23,6 +15,7 @@ const app = indexer({
23
15
  selector: {
24
16
  // for more flags check meow documentation at https://github.com/sindresorhus/meow
25
17
  protocol: {
18
+ isRequired: true,
26
19
  type: "string",
27
20
  description: "which chain to index",
28
21
  },
@@ -33,7 +26,13 @@ const app = indexer({
33
26
  },
34
27
 
35
28
  build: {
36
- func: build,
29
+ func: ({ protocol, verbose }) => {
30
+ console.log("build called with", protocol, verbose);
31
+
32
+ if (protocol === "eth") {
33
+ throw new Error("use eth to test error handling");
34
+ }
35
+ },
37
36
  schedule: every(1).minute,
38
37
  killTimeout: "90s",
39
38
  cpu: 600,