@heyanon/sdk 2.4.0 → 2.4.2

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.js CHANGED
@@ -635,6 +635,592 @@ function normalizeAddress(chain, address) {
635
635
  return address;
636
636
  }
637
637
 
638
+ // src/utils/messages-releaser.ts
639
+ var MessagesReleaser = class {
640
+ constructor(opts = {}) {
641
+ this._messages = [];
642
+ this._separator = "\n";
643
+ if (opts?.separator) {
644
+ this._separator = opts.separator;
645
+ }
646
+ }
647
+ get separator() {
648
+ return this._separator;
649
+ }
650
+ get messages() {
651
+ return this._messages;
652
+ }
653
+ release(lastMessage) {
654
+ if (lastMessage) {
655
+ this.add(lastMessage);
656
+ }
657
+ const message = this._messages.length > 0 ? this._separator.concat(this._messages.join(this._separator)) : "";
658
+ this.reset();
659
+ return message;
660
+ }
661
+ add(...msgs) {
662
+ this._messages.push(...msgs);
663
+ }
664
+ reset() {
665
+ this._messages = [];
666
+ }
667
+ };
668
+
669
+ // src/utils/try-steps-executor.ts
670
+ var TryStepsExecutor = class {
671
+ constructor(initialReleaser, initialOnFailureFn) {
672
+ this.msgsReleaser = initialReleaser || new MessagesReleaser();
673
+ this.onFailureFn = initialOnFailureFn;
674
+ }
675
+ async executeStep(executeFn, onSuccessMessage, onFailureMessage) {
676
+ try {
677
+ const result = await executeFn();
678
+ this.msgsReleaser.add(onSuccessMessage);
679
+ return result;
680
+ } catch (error) {
681
+ await this.onFailureFn(onFailureMessage);
682
+ throw error;
683
+ }
684
+ }
685
+ };
686
+
687
+ // src/utils/workflow-retry.ts
688
+ var WorkflowBreakError = class extends Error {
689
+ /**
690
+ * Create a new WorkflowBreakError
691
+ * @param breakReason Optional reason for breaking the workflow
692
+ */
693
+ constructor(breakReason) {
694
+ super("Workflow execution was interrupted");
695
+ this.name = "WorkflowBreakError";
696
+ this.breakReason = breakReason;
697
+ }
698
+ };
699
+ var WorkflowAction = class {
700
+ /**
701
+ * Create a new WorkflowAction
702
+ * @param options Action configuration
703
+ */
704
+ constructor(options) {
705
+ /**
706
+ * Current attempt number
707
+ */
708
+ this.currentAttempt = 0;
709
+ this.name = options.name;
710
+ this.action = options.action;
711
+ this.attempts = options.attempts || 1;
712
+ this.delayMs = options.delayMs || 0;
713
+ this.onRetry = options.onRetry;
714
+ this.onSuccess = options.onSuccess;
715
+ this.onFailed = options.onFailed;
716
+ }
717
+ /**
718
+ * Get the name of the action
719
+ * @returns The name of the action
720
+ */
721
+ getName() {
722
+ return this.name;
723
+ }
724
+ /**
725
+ * Private retry method for action execution
726
+ * @param fn The function to retry
727
+ * @param context The workflow context
728
+ * @returns Promise with the result of the function
729
+ * @throws {Error} If all retry attempts fail
730
+ */
731
+ async retry(fn, context) {
732
+ for (let attempt = 1; attempt <= this.attempts; attempt++) {
733
+ try {
734
+ this.currentAttempt = attempt;
735
+ return await fn();
736
+ } catch (error) {
737
+ if (error instanceof WorkflowBreakError) {
738
+ throw error;
739
+ }
740
+ if (attempt < this.attempts && this.onRetry) {
741
+ try {
742
+ await this.onRetry(this.currentAttempt, error, context);
743
+ } catch (error2) {
744
+ if (error2 instanceof WorkflowBreakError) {
745
+ context.getWorkflow().break(context.getWorkflow().getBreakReason());
746
+ } else {
747
+ context.getWorkflow().break(error2);
748
+ }
749
+ }
750
+ }
751
+ if (attempt === this.attempts) {
752
+ throw error;
753
+ }
754
+ if (this.delayMs >= 0) {
755
+ this.delayMs === 0 ? await new Promise((resolve) => setImmediate(resolve, this.delayMs)) : await new Promise((resolve) => setTimeout(resolve, this.delayMs));
756
+ }
757
+ }
758
+ }
759
+ throw new Error(`Failed to execute action ${this.name} after ${this.attempts} attempts`);
760
+ }
761
+ /**
762
+ * Execute the action with retry logic
763
+ * @param context The workflow context containing results from previous actions
764
+ * @returns Promise with the result of the action
765
+ * @throws {Error} If all retry attempts fail
766
+ * @throws {WorkflowBreakError} If the workflow is broken
767
+ */
768
+ async execute(context) {
769
+ try {
770
+ return await this.retry(async () => {
771
+ const result = await this.action(context);
772
+ if (this.onSuccess) {
773
+ try {
774
+ await this.onSuccess(this.currentAttempt, result, context);
775
+ } catch (error) {
776
+ if (error instanceof WorkflowBreakError) {
777
+ context.getWorkflow().break(context.getWorkflow().getBreakReason());
778
+ } else {
779
+ context.getWorkflow().break(error);
780
+ }
781
+ }
782
+ }
783
+ return result;
784
+ }, context);
785
+ } catch (error) {
786
+ if (error instanceof WorkflowBreakError) {
787
+ throw error;
788
+ }
789
+ if (this.onFailed) {
790
+ try {
791
+ await this.onFailed(this.currentAttempt, error, context);
792
+ } catch (error2) {
793
+ if (error2 instanceof WorkflowBreakError) {
794
+ context.getWorkflow().break(context.getWorkflow().getBreakReason());
795
+ } else {
796
+ context.getWorkflow().break(error2);
797
+ }
798
+ }
799
+ }
800
+ throw error;
801
+ }
802
+ }
803
+ };
804
+ var WorkflowContext = class {
805
+ /**
806
+ * Create a new WorkflowContext
807
+ * @param workflow The workflow instance
808
+ */
809
+ constructor(workflow) {
810
+ /**
811
+ * Results from previous actions, stored by name
812
+ */
813
+ this.resultsByName = /* @__PURE__ */ new Map();
814
+ /**
815
+ * Results from previous actions, stored by index
816
+ */
817
+ this.resultsByIndex = [];
818
+ /**
819
+ * Current attempt number
820
+ */
821
+ this.currentAttempt = 0;
822
+ /**
823
+ * Current action name
824
+ */
825
+ this.currentActionName = "";
826
+ this.workflow = workflow;
827
+ }
828
+ /**
829
+ * Get the current attempt number
830
+ * @returns The current attempt number (1-based)
831
+ */
832
+ getAttempt() {
833
+ return this.currentAttempt;
834
+ }
835
+ /**
836
+ * Set the current attempt number
837
+ * @param attempt The attempt number to set
838
+ */
839
+ setAttempt(attempt) {
840
+ this.currentAttempt = attempt;
841
+ }
842
+ /**
843
+ * Get the current action name
844
+ * @returns The name of the currently executed action
845
+ */
846
+ getActionName() {
847
+ return this.currentActionName;
848
+ }
849
+ /**
850
+ * Set the current action name
851
+ * @param name The name of the action to set
852
+ */
853
+ setActionName(name) {
854
+ this.currentActionName = name;
855
+ }
856
+ /**
857
+ * Get the result of a specific action by name
858
+ * @param name The name of the action result to retrieve
859
+ * @returns The result of the action with the specified name
860
+ * @throws {Error} If no result is available with the specified name
861
+ */
862
+ getResultByName(name) {
863
+ if (!this.resultsByName.has(name)) {
864
+ throw new Error(`No result available with name "${name}"`);
865
+ }
866
+ return this.resultsByName.get(name);
867
+ }
868
+ /**
869
+ * Get all results from previous actions
870
+ * @returns Array of all results
871
+ */
872
+ getAllResults() {
873
+ return [...this.resultsByIndex];
874
+ }
875
+ /**
876
+ * Add a result to the context
877
+ * @param name The name of the action
878
+ * @param result The result to add
879
+ */
880
+ addResult(name, result) {
881
+ this.resultsByName.set(name, result);
882
+ this.resultsByIndex.push(result);
883
+ }
884
+ /**
885
+ * Get the results by name
886
+ * @returns Map of results by name
887
+ */
888
+ getResultsByName() {
889
+ return this.resultsByName;
890
+ }
891
+ /**
892
+ * Get the workflow instance
893
+ * @returns The workflow instance
894
+ */
895
+ getWorkflow() {
896
+ return this.workflow;
897
+ }
898
+ };
899
+ var WorkflowResult = class {
900
+ /**
901
+ * Create a new WorkflowResult
902
+ * @param results Array of results from actions
903
+ * @param actionNames Array of action names corresponding to the results
904
+ */
905
+ constructor(results = [], actionNames = []) {
906
+ /**
907
+ * Results from actions, stored by name
908
+ */
909
+ this.resultsByName = /* @__PURE__ */ new Map();
910
+ /**
911
+ * Results from actions, stored by index
912
+ */
913
+ this.resultsByIndex = [];
914
+ /**
915
+ * Failures from actions, stored by action name and attempt number
916
+ */
917
+ this.failuresByAction = /* @__PURE__ */ new Map();
918
+ this.resultsByIndex = [...results];
919
+ actionNames.forEach((name, index) => {
920
+ if (index < results.length) {
921
+ this.resultsByName.set(name, results[index]);
922
+ }
923
+ });
924
+ }
925
+ /**
926
+ * Add a result to the workflow result
927
+ * @param name The name of the action
928
+ * @param result The result to add
929
+ */
930
+ addResult(name, result) {
931
+ this.resultsByName.set(name, result);
932
+ this.resultsByIndex.push(result);
933
+ }
934
+ /**
935
+ * Add a failure to the workflow result
936
+ * @param name The name of the action that failed
937
+ * @param attempt The attempt number
938
+ * @param reason The reason for the failure
939
+ */
940
+ addFailure(name, attempt, reason) {
941
+ if (!this.failuresByAction.has(name)) {
942
+ this.failuresByAction.set(name, /* @__PURE__ */ new Map());
943
+ }
944
+ this.failuresByAction.get(name).set(attempt, reason);
945
+ }
946
+ /**
947
+ * Get all failures for a specific action
948
+ * @param name The name of the action
949
+ * @returns Map of attempt numbers to failure reasons
950
+ */
951
+ getFailuresByAction(name) {
952
+ return this.failuresByAction.get(name) || /* @__PURE__ */ new Map();
953
+ }
954
+ /**
955
+ * Get all failures across all actions
956
+ * @returns Map of action names to maps of attempt numbers to failure reasons
957
+ */
958
+ getAllFailures() {
959
+ return new Map(this.failuresByAction);
960
+ }
961
+ /**
962
+ * Check if an action failed in a specific attempt
963
+ * @param name The name of the action
964
+ * @param attempt The attempt number
965
+ * @returns True if the action failed in the specified attempt
966
+ */
967
+ hasFailure(name, attempt) {
968
+ return this.failuresByAction.has(name) && this.failuresByAction.get(name).has(attempt);
969
+ }
970
+ /**
971
+ * Get the failure reason for an action in a specific attempt
972
+ * @param name The name of the action
973
+ * @param attempt The attempt number
974
+ * @returns The failure reason or undefined if no failure occurred
975
+ */
976
+ getFailure(name, attempt) {
977
+ return this.failuresByAction.get(name)?.get(attempt);
978
+ }
979
+ /**
980
+ * Get all attempts when an action failed
981
+ * @param name The name of the action
982
+ * @returns Array of attempt numbers
983
+ */
984
+ getFailureAttempts(name) {
985
+ if (!this.failuresByAction.has(name)) {
986
+ return [];
987
+ }
988
+ return Array.from(this.failuresByAction.get(name).keys());
989
+ }
990
+ /**
991
+ * Get all actions that failed
992
+ * @returns Array of action names
993
+ */
994
+ getFailedActions() {
995
+ return Array.from(this.failuresByAction.keys());
996
+ }
997
+ /**
998
+ * Get all actions that failed with a specific reason
999
+ * @param reason The failure reason to search for
1000
+ * @returns Array of action names
1001
+ */
1002
+ getActionsFailedWithReason(reason) {
1003
+ const failedActions = [];
1004
+ this.failuresByAction.forEach((attemptFailures, name) => {
1005
+ attemptFailures.forEach((failureReason) => {
1006
+ if (this.areReasonsEqual(failureReason, reason)) {
1007
+ failedActions.push(name);
1008
+ }
1009
+ });
1010
+ });
1011
+ return [...new Set(failedActions)];
1012
+ }
1013
+ /**
1014
+ * Compare two reasons for equality
1015
+ * @param reason1 First reason
1016
+ * @param reason2 Second reason
1017
+ * @returns True if the reasons are equal
1018
+ * @private
1019
+ */
1020
+ areReasonsEqual(reason1, reason2) {
1021
+ if (reason1 instanceof Error && reason2 instanceof Error) {
1022
+ return reason1.message === reason2.message;
1023
+ }
1024
+ if (typeof reason1 === "string" && typeof reason2 === "string") {
1025
+ return reason1 === reason2;
1026
+ }
1027
+ try {
1028
+ return JSON.stringify(reason1) === JSON.stringify(reason2);
1029
+ } catch {
1030
+ return String(reason1) === String(reason2);
1031
+ }
1032
+ }
1033
+ /**
1034
+ * Get the result of a specific action by name
1035
+ * @param name The name of the action
1036
+ * @returns The result of the action with the specified name
1037
+ * @throws {Error} If no result is available with the specified name
1038
+ */
1039
+ getResult(name) {
1040
+ if (!this.resultsByName.has(name)) {
1041
+ throw new Error(`No result available with name "${name}"`);
1042
+ }
1043
+ return this.resultsByName.get(name);
1044
+ }
1045
+ /**
1046
+ * Get the result of the last action in the workflow
1047
+ * @returns The result of the last action
1048
+ * @throws {Error} If no results are available
1049
+ */
1050
+ getLastActionResult() {
1051
+ if (this.resultsByIndex.length === 0) {
1052
+ throw new Error("No results available");
1053
+ }
1054
+ return this.resultsByIndex[this.resultsByIndex.length - 1];
1055
+ }
1056
+ /**
1057
+ * Get all results from the workflow
1058
+ * @returns Array of all results
1059
+ */
1060
+ getAllResults() {
1061
+ return [...this.resultsByIndex];
1062
+ }
1063
+ /**
1064
+ * Get the number of results
1065
+ * @returns The number of results
1066
+ */
1067
+ getResultCount() {
1068
+ return this.resultsByIndex.length;
1069
+ }
1070
+ };
1071
+ var WorkflowRetry = class {
1072
+ /**
1073
+ * Create a new WorkflowRetry instance
1074
+ * @param options Configuration options for the workflow and actions
1075
+ */
1076
+ constructor(options = {}) {
1077
+ /**
1078
+ * List of actions to execute in the workflow
1079
+ */
1080
+ this.actions = [];
1081
+ /**
1082
+ * Flag indicating if the workflow was broken
1083
+ */
1084
+ this.isBroken = false;
1085
+ this.attempts = options.attempts || 1;
1086
+ this.delayMs = options.delayMs || 0;
1087
+ this.onBreak = options.onBreak;
1088
+ this.onSuccess = options.onSuccess;
1089
+ this.onFailed = options.onFailed;
1090
+ this.onRetry = options.onRetry;
1091
+ }
1092
+ /**
1093
+ * Break the workflow execution with an error
1094
+ * @param reason Optional reason for breaking the workflow
1095
+ * @param customError Optional custom error to throw instead of WorkflowBreakError
1096
+ * @throws {WorkflowBreakError} Always throws to break the workflow
1097
+ */
1098
+ break(reason) {
1099
+ this.isBroken = true;
1100
+ this.breakReason = reason;
1101
+ throw new WorkflowBreakError();
1102
+ }
1103
+ /**
1104
+ * Check if the workflow was broken
1105
+ * @returns True if the workflow was broken
1106
+ */
1107
+ wasBroken() {
1108
+ return this.isBroken;
1109
+ }
1110
+ /**
1111
+ * Get the reason for breaking the workflow
1112
+ * @returns The reason for breaking the workflow
1113
+ */
1114
+ getBreakReason() {
1115
+ return this.breakReason;
1116
+ }
1117
+ /**
1118
+ * Add an action to the workflow
1119
+ * @param options Action options including the action function and retry configuration
1120
+ * @returns The WorkflowRetry instance for method chaining
1121
+ */
1122
+ addAction(options) {
1123
+ const workflowAction = new WorkflowAction(options);
1124
+ this.actions.push(workflowAction);
1125
+ return this;
1126
+ }
1127
+ /**
1128
+ * Private retry method for workflow execution
1129
+ * @param fn The function to retry
1130
+ * @param context The workflow context
1131
+ * @returns Promise with the result of the function
1132
+ * @throws {Error} If all retry attempts fail
1133
+ */
1134
+ async retry(fn, context) {
1135
+ for (let attempt = 1; attempt <= this.attempts; attempt++) {
1136
+ try {
1137
+ context.setAttempt(attempt);
1138
+ return await fn();
1139
+ } catch (error) {
1140
+ if (error instanceof WorkflowBreakError) {
1141
+ throw error;
1142
+ }
1143
+ if (attempt < this.attempts && this.onRetry) {
1144
+ try {
1145
+ await this.onRetry(error, context);
1146
+ } catch (error2) {
1147
+ if (error2 instanceof WorkflowBreakError) {
1148
+ this.break(this.breakReason);
1149
+ } else {
1150
+ this.break(error2);
1151
+ }
1152
+ }
1153
+ }
1154
+ if (attempt === this.attempts) {
1155
+ throw error;
1156
+ }
1157
+ if (this.delayMs >= 0) {
1158
+ this.delayMs === 0 ? await new Promise((resolve) => setImmediate(resolve, this.delayMs)) : await new Promise((resolve) => setTimeout(resolve, this.delayMs));
1159
+ }
1160
+ }
1161
+ }
1162
+ throw new Error(`Failed to execute workflow after ${this.attempts} attempts`);
1163
+ }
1164
+ /**
1165
+ * Execute all actions in the workflow with retry logic
1166
+ * @returns Promise with a WorkflowResult object containing the results
1167
+ * @throws {Error} If any action fails after all retry attempts
1168
+ * @throws {WorkflowBreakError} If the workflow is broken
1169
+ */
1170
+ async execute() {
1171
+ const context = new WorkflowContext(this);
1172
+ this.isBroken = false;
1173
+ try {
1174
+ return await this.retry(async () => {
1175
+ const workflowResult = new WorkflowResult();
1176
+ for (const action of this.actions) {
1177
+ context.setActionName(action.getName());
1178
+ const actionResult = await action.execute(context);
1179
+ workflowResult.addResult(action.getName(), actionResult);
1180
+ context.addResult(action.getName(), actionResult);
1181
+ }
1182
+ if (this.onSuccess) {
1183
+ try {
1184
+ await this.onSuccess(context);
1185
+ } catch (error) {
1186
+ if (error instanceof WorkflowBreakError) {
1187
+ this.break(this.breakReason);
1188
+ } else {
1189
+ this.break(error);
1190
+ }
1191
+ }
1192
+ }
1193
+ return workflowResult;
1194
+ }, context);
1195
+ } catch (error) {
1196
+ if (this.onBreak && error instanceof WorkflowBreakError) {
1197
+ try {
1198
+ await this.onBreak(this.breakReason, context);
1199
+ } catch (error2) {
1200
+ if (error2 instanceof WorkflowBreakError && this.breakReason instanceof Error) {
1201
+ throw this.breakReason;
1202
+ }
1203
+ throw error2;
1204
+ }
1205
+ }
1206
+ if (error instanceof WorkflowBreakError && this.breakReason instanceof Error) {
1207
+ throw this.breakReason;
1208
+ }
1209
+ if (this.onFailed && !(error instanceof WorkflowBreakError)) {
1210
+ try {
1211
+ await this.onFailed(error, context);
1212
+ } catch (error2) {
1213
+ if (error2 instanceof WorkflowBreakError && this.breakReason instanceof Error) {
1214
+ throw this.breakReason;
1215
+ }
1216
+ throw error2;
1217
+ }
1218
+ }
1219
+ throw error;
1220
+ }
1221
+ }
1222
+ };
1223
+
638
1224
  // src/adapter/transformers/toResult.ts
639
1225
  function toResult(data, error = false) {
640
1226
  const formatedData = typeof data === "string" ? data : stringify(data);
@@ -664,9 +1250,16 @@ var AdapterTag = /* @__PURE__ */ ((AdapterTag2) => {
664
1250
  exports.AdapterTag = AdapterTag;
665
1251
  exports.Chain = Chain;
666
1252
  exports.EVM = evm_exports;
1253
+ exports.MessagesReleaser = MessagesReleaser;
667
1254
  exports.Solana = solana_exports;
668
1255
  exports.TON = ton_exports;
1256
+ exports.TryStepsExecutor = TryStepsExecutor;
669
1257
  exports.WalletType = WalletType;
1258
+ exports.WorkflowAction = WorkflowAction;
1259
+ exports.WorkflowBreakError = WorkflowBreakError;
1260
+ exports.WorkflowContext = WorkflowContext;
1261
+ exports.WorkflowResult = WorkflowResult;
1262
+ exports.WorkflowRetry = WorkflowRetry;
670
1263
  exports.allChains = allChains;
671
1264
  exports.allEvmChains = allEvmChains;
672
1265
  exports.getTimestamp = getTimestamp;