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