@keetanetwork/anchor 0.0.38 → 0.0.40

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 (103) hide show
  1. package/client/index.d.ts +6 -0
  2. package/client/index.d.ts.map +1 -1
  3. package/client/index.js +7 -0
  4. package/client/index.js.map +1 -1
  5. package/lib/block-listener.d.ts +93 -0
  6. package/lib/block-listener.d.ts.map +1 -0
  7. package/lib/block-listener.js +259 -0
  8. package/lib/block-listener.js.map +1 -0
  9. package/lib/encrypted-container.d.ts +53 -3
  10. package/lib/encrypted-container.d.ts.map +1 -1
  11. package/lib/encrypted-container.js +549 -93
  12. package/lib/encrypted-container.js.map +1 -1
  13. package/lib/error.d.ts.map +1 -1
  14. package/lib/error.js +3 -1
  15. package/lib/error.js.map +1 -1
  16. package/lib/http-server/index.d.ts +14 -1
  17. package/lib/http-server/index.d.ts.map +1 -1
  18. package/lib/http-server/index.js +144 -12
  19. package/lib/http-server/index.js.map +1 -1
  20. package/lib/queue/drivers/queue_firestore.d.ts +29 -0
  21. package/lib/queue/drivers/queue_firestore.d.ts.map +1 -0
  22. package/lib/queue/drivers/queue_firestore.js +279 -0
  23. package/lib/queue/drivers/queue_firestore.js.map +1 -0
  24. package/lib/queue/index.d.ts +74 -3
  25. package/lib/queue/index.d.ts.map +1 -1
  26. package/lib/queue/index.js +161 -36
  27. package/lib/queue/index.js.map +1 -1
  28. package/lib/resolver.d.ts +61 -15
  29. package/lib/resolver.d.ts.map +1 -1
  30. package/lib/resolver.js +1132 -686
  31. package/lib/resolver.js.map +1 -1
  32. package/lib/utils/signing.d.ts +12 -3
  33. package/lib/utils/signing.d.ts.map +1 -1
  34. package/lib/utils/signing.js +7 -13
  35. package/lib/utils/signing.js.map +1 -1
  36. package/npm-shrinkwrap.json +6 -6
  37. package/package.json +2 -1
  38. package/services/asset-movement/client.d.ts +10 -3
  39. package/services/asset-movement/client.d.ts.map +1 -1
  40. package/services/asset-movement/client.js +36 -3
  41. package/services/asset-movement/client.js.map +1 -1
  42. package/services/asset-movement/common.d.ts +57 -22
  43. package/services/asset-movement/common.d.ts.map +1 -1
  44. package/services/asset-movement/common.js +370 -70
  45. package/services/asset-movement/common.js.map +1 -1
  46. package/services/fx/client.d.ts +15 -3
  47. package/services/fx/client.d.ts.map +1 -1
  48. package/services/fx/client.js +18 -0
  49. package/services/fx/client.js.map +1 -1
  50. package/services/fx/common.d.ts +1 -1
  51. package/services/fx/common.js.map +1 -1
  52. package/services/fx/server.d.ts +59 -9
  53. package/services/fx/server.d.ts.map +1 -1
  54. package/services/fx/server.js +337 -140
  55. package/services/fx/server.js.map +1 -1
  56. package/services/fx/util.d.ts +26 -8
  57. package/services/fx/util.d.ts.map +1 -1
  58. package/services/fx/util.js +92 -4
  59. package/services/fx/util.js.map +1 -1
  60. package/services/storage/client.d.ts +322 -0
  61. package/services/storage/client.d.ts.map +1 -0
  62. package/services/storage/client.js +1058 -0
  63. package/services/storage/client.js.map +1 -0
  64. package/services/storage/common.d.ts +653 -0
  65. package/services/storage/common.d.ts.map +1 -0
  66. package/services/storage/common.generated.d.ts +17 -0
  67. package/services/storage/common.generated.d.ts.map +1 -0
  68. package/services/storage/common.generated.js +863 -0
  69. package/services/storage/common.generated.js.map +1 -0
  70. package/services/storage/common.js +587 -0
  71. package/services/storage/common.js.map +1 -0
  72. package/services/storage/lib/validators.d.ts +64 -0
  73. package/services/storage/lib/validators.d.ts.map +1 -0
  74. package/services/storage/lib/validators.js +82 -0
  75. package/services/storage/lib/validators.js.map +1 -0
  76. package/services/storage/server.d.ts +127 -0
  77. package/services/storage/server.d.ts.map +1 -0
  78. package/services/storage/server.js +626 -0
  79. package/services/storage/server.js.map +1 -0
  80. package/services/storage/test-utils.d.ts +70 -0
  81. package/services/storage/test-utils.d.ts.map +1 -0
  82. package/services/storage/test-utils.js +347 -0
  83. package/services/storage/test-utils.js.map +1 -0
  84. package/services/storage/utils.d.ts +3 -0
  85. package/services/storage/utils.d.ts.map +1 -0
  86. package/services/storage/utils.js +10 -0
  87. package/services/storage/utils.js.map +1 -0
  88. package/services/username/client.d.ts +145 -0
  89. package/services/username/client.d.ts.map +1 -0
  90. package/services/username/client.js +681 -0
  91. package/services/username/client.js.map +1 -0
  92. package/services/username/common.d.ts +136 -0
  93. package/services/username/common.d.ts.map +1 -0
  94. package/services/username/common.generated.d.ts +13 -0
  95. package/services/username/common.generated.d.ts.map +1 -0
  96. package/services/username/common.generated.js +256 -0
  97. package/services/username/common.generated.js.map +1 -0
  98. package/services/username/common.js +226 -0
  99. package/services/username/common.js.map +1 -0
  100. package/services/username/server.d.ts +51 -0
  101. package/services/username/server.d.ts.map +1 -0
  102. package/services/username/server.js +264 -0
  103. package/services/username/server.js.map +1 -0
@@ -1,8 +1,10 @@
1
1
  import { __addDisposableResource, __disposeResources } from "tslib";
2
+ import { assertNever } from '../utils/never.js';
2
3
  import { asleep } from '../utils/asleep.js';
3
4
  import { Errors } from './common.js';
4
5
  import { MethodLogger, ManageStatusUpdates, ConvertStringToRequestID } from './internal.js';
5
6
  import { AsyncDisposableStack } from '../utils/defer.js';
7
+ const keetaAnchorPipeableQueueStatuses = ['completed', 'failed_permanently'];
6
8
  /**
7
9
  * An in-memory implementation of the KeetaAnchorQueueStorageDriver
8
10
  */
@@ -214,9 +216,74 @@ export class KeetaAnchorQueueRunner {
214
216
  /**
215
217
  * Configuration for this queue
216
218
  */
219
+ /**
220
+ * The maximum number of times to retry a failed job before giving up
221
+ * and marking it as permanently failed
222
+ */
217
223
  maxRetries = 5;
224
+ /**
225
+ * The amount of time to allow a job to run before considering it
226
+ * timed out and marking it as aborted, the `aborted` processor
227
+ * (if provided) will be responsible for determining what to do with
228
+ * the job at that point (e.g. retry it, mark it as failed, etc)
229
+ * because some work from the job may have been completed
230
+ * before the timeout was reached -- it could even still be on-going
231
+ * after the timeout is reached, so the `aborted` processor should be
232
+ * prepared to handle that situation as well.
233
+ */
218
234
  processTimeout = 300_000; /* 5 minutes */
235
+ /**
236
+ * When piping a batch of jobs to another runner, this is the number
237
+ * of jobs to include in each batch (max).
238
+ */
219
239
  batchSize = 100;
240
+ /**
241
+ * The amount of time to wait before retrying a failed job -- this should
242
+ * be long enough to allow any transient issues to be resolved (e.g. a downstream
243
+ * service to come back up, etc) but not so long that it causes excessive
244
+ * delays in processing.
245
+ *
246
+ * Keep in mind that after the {@link maxRetries} is reached, the job will
247
+ * be marked as permanently failed, so if the retry delay is too low then
248
+ * it could cause jobs to be marked as permanently failed before transient
249
+ * issues have a chance to be resolved.
250
+ */
251
+ get retryDelay() {
252
+ if (this.internalRetryDelay !== undefined) {
253
+ return (this.internalRetryDelay);
254
+ }
255
+ return (this.processTimeout * 10);
256
+ }
257
+ set retryDelay(value) {
258
+ this.internalRetryDelay = value;
259
+ }
260
+ internalRetryDelay;
261
+ /**
262
+ * The number of {@link processTimeout} intervals to wait before
263
+ * considering a job to be stuck -- this is for jobs that are
264
+ * still in the 'processing' state but have not updated their
265
+ * timestamp in a long time, which likely indicates that the worker
266
+ * processing the job has died or is otherwise no longer making
267
+ * progress on the job.
268
+ *
269
+ * Like the `aborted` status, the `stuck` status means the job is in
270
+ * an indeterminate state where it may have done some of the work of
271
+ * the processor but we don't know how much (if any) of it was
272
+ * completed, so the `stuck` processor should be prepared to handle
273
+ * that situation. It is unlikely that the job is still being actively
274
+ * processed by a worker at this point, but it is possible, so the
275
+ * `stuck` processor should be prepared to handle that as well.
276
+ */
277
+ get stuckMultiplier() {
278
+ if (this.internalStuckMultiplier !== undefined) {
279
+ return (this.internalStuckMultiplier);
280
+ }
281
+ return (10);
282
+ }
283
+ set stuckMultiplier(value) {
284
+ this.internalStuckMultiplier = value;
285
+ }
286
+ internalStuckMultiplier;
220
287
  /**
221
288
  * How many runners can process this queue in parallel
222
289
  */
@@ -278,6 +345,16 @@ export class KeetaAnchorQueueRunner {
278
345
  })();
279
346
  return (await this.initializePromise);
280
347
  }
348
+ setConfiguration(parameters) {
349
+ const parameterNames = ['batchSize', 'maxRetries', 'processTimeout', 'retryDelay', 'stuckMultiplier'];
350
+ for (const parameterName of parameterNames) {
351
+ const value = parameters[parameterName];
352
+ if (value === undefined) {
353
+ continue;
354
+ }
355
+ this[parameterName] = value;
356
+ }
357
+ }
281
358
  methodLogger(method) {
282
359
  return (MethodLogger(this.logger, {
283
360
  class: 'KeetaAnchorQueueRunner',
@@ -292,12 +369,11 @@ export class KeetaAnchorQueueRunner {
292
369
  throw (new Error('This is a testing only method'));
293
370
  }
294
371
  return ({
295
- setParams: (maxBatchSize, processTimeout, maxRetries, maxWorkers) => {
296
- this.batchSize = maxBatchSize;
297
- this.processTimeout = processTimeout;
298
- this.maxRetries = maxRetries;
299
- if (maxWorkers !== undefined) {
300
- this.maxRunners = maxWorkers;
372
+ setParams: (params) => {
373
+ const { maxRunners, ...configParams } = params;
374
+ this.setConfiguration(configParams);
375
+ if (maxRunners !== undefined) {
376
+ this.maxRunners = maxRunners;
301
377
  }
302
378
  },
303
379
  queue: () => {
@@ -446,7 +522,7 @@ export class KeetaAnchorQueueRunner {
446
522
  return;
447
523
  }
448
524
  const lockAge = moment.getTime() - lockEntry.updated.getTime();
449
- if (lockAge > this.processTimeout * 10) {
525
+ if (lockAge > this.processTimeout * this.stuckMultiplier) {
450
526
  logger?.warn('Processing lock is stale, taking over lock for worker ID', this.workerID);
451
527
  await this.queue.setStatus(this.runnerLockKey, '@internal', {
452
528
  oldStatus: 'processing',
@@ -574,6 +650,9 @@ export class KeetaAnchorQueueRunner {
574
650
  */
575
651
  const pipes = [...this.pipes];
576
652
  for (const pipe of pipes) {
653
+ if (pipe.exclusiveTarget === false) {
654
+ continue;
655
+ }
577
656
  let remainingTime = undefined;
578
657
  if (timeout !== undefined) {
579
658
  const elapsed = Date.now() - startTime;
@@ -634,7 +713,7 @@ export class KeetaAnchorQueueRunner {
634
713
  }
635
714
  }
636
715
  async markStuckRequestsAsStuck() {
637
- const stuckThreshold = this.processTimeout * 10;
716
+ const stuckThreshold = this.processTimeout * this.stuckMultiplier;
638
717
  const logger = this.methodLogger('markStuckRequestsAsStuck');
639
718
  const now = Date.now();
640
719
  const requests = await this.queue.query({ status: 'processing', limit: 100, updatedBefore: new Date(now - stuckThreshold) });
@@ -655,7 +734,7 @@ export class KeetaAnchorQueueRunner {
655
734
  }
656
735
  }
657
736
  async requeueFailedRequests() {
658
- const retryDelay = this.processTimeout * 10;
737
+ const retryDelay = this.retryDelay;
659
738
  const maxRetries = this.maxRetries;
660
739
  const logger = this.methodLogger('requeueFailedRequests');
661
740
  const now = Date.now();
@@ -675,19 +754,30 @@ export class KeetaAnchorQueueRunner {
675
754
  }
676
755
  }
677
756
  }
678
- async moveCompletedToNextStage() {
757
+ async moveCompletedToNextStage(statusTarget) {
679
758
  const logger = this.methodLogger('moveCompletedToNextStage');
680
- const pipes = [...this.pipes];
759
+ const pipes = [...this.pipes].filter(function (pipe) {
760
+ return (pipe.acceptStatus === statusTarget);
761
+ });
681
762
  if (pipes.length === 0) {
682
763
  return;
683
764
  }
684
- const allRequests = await this.queue.query({ status: 'completed', limit: 100 });
765
+ const allRequests = await this.queue.query({ status: statusTarget, limit: 100 });
685
766
  let requests = allRequests;
686
767
  const RequestSentToPipes = new Map();
687
768
  function IncrRequestSentToPipes(requestID) {
688
769
  const sentCount = RequestSentToPipes.get(requestID) ?? 0;
689
770
  RequestSentToPipes.set(requestID, sentCount + 1);
690
771
  }
772
+ const getNextPipeRequestInput = (entry) => {
773
+ if (statusTarget === 'completed') {
774
+ return (this.decodeResponse(entry.output));
775
+ }
776
+ else if (statusTarget === 'failed_permanently') {
777
+ return (this.decodeRequest(entry.request));
778
+ }
779
+ assertNever(statusTarget);
780
+ };
691
781
  for (const pipe of pipes) {
692
782
  logger?.debug('Processing pipe to target', pipe.target.id, pipe.isBatchPipe ? '(batch pipe)' : '(single item pipe)');
693
783
  if (pipe.isBatchPipe) {
@@ -726,14 +816,14 @@ export class KeetaAnchorQueueRunner {
726
816
  return (!iterationTargetSeenRequestIDs.has(entry.id) && !skipRequestIDs.has(entry.id));
727
817
  })) {
728
818
  iterationTargetSeenRequestIDs.clear();
729
- logger?.debug(`Preparing to move completed requests to next stage ${pipe.target.id} (min=${pipe.minBatchSize}, max=${pipe.maxBatchSize}), have ${requests.length} completed requests available`);
819
+ logger?.debug(`Preparing to move ${statusTarget} requests to next stage ${pipe.target.id} (min=${pipe.minBatchSize}, max=${pipe.maxBatchSize}), have ${requests.length} ${statusTarget} requests available`);
730
820
  /**
731
821
  * Compute a batch of entries to send to the next stage,
732
822
  * constrained to the max batch size of the pipe and
733
823
  * the entries which have non-null outputs
734
824
  */
735
825
  const batchRaw = requests.map((entry) => {
736
- return ({ output: this.decodeResponse(entry.output), id: entry.id });
826
+ return ({ output: getNextPipeRequestInput(entry), id: entry.id });
737
827
  }).filter(function (entry) {
738
828
  if (entry === null) {
739
829
  return (false);
@@ -747,10 +837,10 @@ export class KeetaAnchorQueueRunner {
747
837
  if (batchRaw.length < pipe.minBatchSize) {
748
838
  sequentialFailureCount++;
749
839
  if (sequentialFailureCount >= 3) {
750
- logger?.debug(`Not enough completed requests to move to next stage ${pipe.target.id}, stopping batch processing`);
840
+ logger?.debug(`Not enough ${statusTarget} requests to move to next stage ${pipe.target.id}, stopping batch processing`);
751
841
  break;
752
842
  }
753
- logger?.debug(`Not moving completed requests to next stage ${pipe.target.id} because batch size ${batchRaw.length} is less than minimum size ${pipe.minBatchSize}`);
843
+ logger?.debug(`Not moving ${statusTarget} requests to next stage ${pipe.target.id} because batch size ${batchRaw.length} is less than minimum size ${pipe.minBatchSize}`);
754
844
  continue;
755
845
  }
756
846
  sequentialFailureCount = 0;
@@ -769,8 +859,10 @@ export class KeetaAnchorQueueRunner {
769
859
  const batchOutput = batchRaw.map(function (entry) {
770
860
  return (entry.output);
771
861
  });
772
- logger?.debug(`Moving batch of ${batchOutput.length} completed requests to next pipe`, pipe.target.id, '(input entry IDs:', Array.from(batchLocalIDs), '->', `${pipe.target.id}:${String(batchID)})`);
862
+ logger?.debug(`Moving batch of ${batchOutput.length} ${statusTarget} requests to next pipe`, pipe.target.id, '(input entry IDs:', Array.from(batchLocalIDs), '->', `${pipe.target.id}:${String(batchID)})`);
773
863
  try {
864
+ // There is no way for typescript to cleanly infer the type here, so we assert it.
865
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
774
866
  await pipe.target.add(batchOutput, {
775
867
  id: batchID,
776
868
  /* Use the set of IDs as the idempotent IDs for the batch */
@@ -816,12 +908,14 @@ export class KeetaAnchorQueueRunner {
816
908
  for (const request of requests) {
817
909
  let shouldMarkAsMoved = true;
818
910
  try {
819
- const output = this.decodeResponse(request.output);
911
+ const output = getNextPipeRequestInput(request);
820
912
  if (output === null) {
821
913
  logger?.debug(`Completed request with id ${String(request.id)} has no output -- next stage will not be run`);
822
914
  }
823
915
  else {
824
- logger?.debug(`Moving completed request with id ${String(request.id)} to next pipe`, pipe.target.id);
916
+ logger?.debug(`Moving ${statusTarget} request with id ${String(request.id)} to next pipe`, pipe.target.id);
917
+ // There is no way for typescript to cleanly infer the type here, so we assert it.
918
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
825
919
  await pipe.target.add(output, { id: request.id });
826
920
  }
827
921
  }
@@ -839,11 +933,11 @@ export class KeetaAnchorQueueRunner {
839
933
  for (const request of allRequests) {
840
934
  const sentCount = RequestSentToPipes.get(request.id) ?? 0;
841
935
  if (sentCount !== TotalPipes) {
842
- logger?.debug(`Completed request with id ${String(request.id)} was only moved to ${sentCount} out of ${TotalPipes} pipes -- not marking as moved`);
936
+ logger?.debug(`${statusTarget} request with id ${String(request.id)} was only moved to ${sentCount} out of ${TotalPipes} pipes -- not marking as moved`);
843
937
  continue;
844
938
  }
845
- logger?.debug(`Marking completed request with id ${String(request.id)} as moved`);
846
- await this.queue.setStatus(request.id, 'moved', { oldStatus: 'completed', by: this.workerID });
939
+ logger?.debug(`Marking ${statusTarget} request with id ${String(request.id)} as moved`);
940
+ await this.queue.setStatus(request.id, 'moved', { oldStatus: statusTarget, by: this.workerID });
847
941
  }
848
942
  }
849
943
  async maintain() {
@@ -876,14 +970,19 @@ export class KeetaAnchorQueueRunner {
876
970
  catch (error) {
877
971
  logger?.debug('Failed to requeue failed requests:', error);
878
972
  }
879
- try {
880
- await this.moveCompletedToNextStage();
881
- }
882
- catch (error) {
883
- logger?.debug('Failed to move completed requests to next stage:', error);
973
+ for (const pipeStatus of keetaAnchorPipeableQueueStatuses) {
974
+ try {
975
+ await this.moveCompletedToNextStage(pipeStatus);
976
+ }
977
+ catch (error) {
978
+ logger?.debug(`Failed to move ${pipeStatus} requests to next stage:`, error);
979
+ }
884
980
  }
885
981
  for (const pipe of this.pipes) {
886
982
  try {
983
+ if (pipe.exclusiveTarget === false) {
984
+ continue;
985
+ }
887
986
  await pipe.target.maintain();
888
987
  }
889
988
  catch (error) {
@@ -902,22 +1001,46 @@ export class KeetaAnchorQueueRunner {
902
1001
  /**
903
1002
  * Pipe the the completed entries of this runner to another runner
904
1003
  */
905
- pipe(target) {
1004
+ pipe(target, options) {
906
1005
  this.pipes.push({
1006
+ ...options,
907
1007
  isBatchPipe: false,
908
- target: target
1008
+ target: target,
1009
+ acceptStatus: 'completed'
1010
+ });
1011
+ return (target);
1012
+ }
1013
+ pipeFailed(target, options) {
1014
+ this.pipes.push({
1015
+ ...options,
1016
+ isBatchPipe: false,
1017
+ target: target,
1018
+ acceptStatus: 'failed_permanently'
909
1019
  });
910
1020
  return (target);
911
1021
  }
912
1022
  /**
913
1023
  * Pipe batches of completed entries from this runner to another runner
914
1024
  */
915
- pipeBatch(target, maxBatchSize = 100, minBatchSize = 1) {
1025
+ pipeBatch(target, maxBatchSize = 100, minBatchSize = 1, options) {
1026
+ this.pipes.push({
1027
+ ...options,
1028
+ isBatchPipe: true,
1029
+ target: target,
1030
+ minBatchSize: minBatchSize,
1031
+ maxBatchSize: maxBatchSize,
1032
+ acceptStatus: 'completed'
1033
+ });
1034
+ return (target);
1035
+ }
1036
+ pipeBatchFailed(target, maxBatchSize = 100, minBatchSize = 1, options) {
916
1037
  this.pipes.push({
1038
+ ...options,
917
1039
  isBatchPipe: true,
918
1040
  target: target,
919
1041
  minBatchSize: minBatchSize,
920
- maxBatchSize: maxBatchSize
1042
+ maxBatchSize: maxBatchSize,
1043
+ acceptStatus: 'failed_permanently'
921
1044
  });
922
1045
  return (target);
923
1046
  }
@@ -956,13 +1079,15 @@ export class KeetaAnchorQueueRunnerJSONConfigProc extends KeetaAnchorQueueRunner
956
1079
  processor;
957
1080
  constructor(config) {
958
1081
  super(config);
959
- this.processor = config.processor;
960
- if (config.processorStuck) {
961
- this.processorStuck = config.processorStuck;
1082
+ const { processor, processorStuck, processorAborted, ...parameters } = config;
1083
+ this.processor = processor;
1084
+ if (processorStuck) {
1085
+ this.processorStuck = processorStuck;
962
1086
  }
963
- if (config.processorAborted) {
964
- this.processorAborted = config.processorAborted;
1087
+ if (processorAborted) {
1088
+ this.processorAborted = processorAborted;
965
1089
  }
1090
+ this.setConfiguration(parameters);
966
1091
  }
967
1092
  }
968
1093
  //# sourceMappingURL=index.js.map