sdk-triggerx 0.1.16 → 0.1.18

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.
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateTimeBasedJobInput = validateTimeBasedJobInput;
4
+ exports.validateEventBasedJobInput = validateEventBasedJobInput;
5
+ exports.validateConditionBasedJobInput = validateConditionBasedJobInput;
6
+ exports.validateJobInput = validateJobInput;
7
+ const ethers_1 = require("ethers");
8
+ const errors_1 = require("./errors");
9
+ function isNonEmptyString(value) {
10
+ return typeof value === 'string' && value.trim().length > 0;
11
+ }
12
+ function isValidUrl(value) {
13
+ try {
14
+ // eslint-disable-next-line no-new
15
+ new URL(value);
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ function buildFunctionSignature(name, inputs) {
23
+ const types = (inputs || []).map((i) => i.type).join(',');
24
+ return `${name}(${types})`;
25
+ }
26
+ function parseAbi(abiString) {
27
+ if (!isNonEmptyString(abiString))
28
+ return null;
29
+ try {
30
+ const parsed = JSON.parse(abiString);
31
+ return Array.isArray(parsed) ? parsed : null;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ function validateContractBasics(address, abi, targetFunction, fieldPrefix = 'contract') {
38
+ if (!isNonEmptyString(address)) {
39
+ throw new errors_1.ValidationError(`${fieldPrefix}Address`, 'Contract address is required.');
40
+ }
41
+ if (!ethers_1.ethers.isAddress(address)) {
42
+ throw new errors_1.ValidationError(`${fieldPrefix}Address`, 'Invalid contract address.');
43
+ }
44
+ if (!isNonEmptyString(abi)) {
45
+ throw new errors_1.ValidationError(`${fieldPrefix}ABI`, 'Contract ABI must be provided.');
46
+ }
47
+ if (!isNonEmptyString(targetFunction)) {
48
+ throw new errors_1.ValidationError(`${fieldPrefix}Target`, 'Target function must be selected.');
49
+ }
50
+ }
51
+ function validateStaticArguments(abiString, targetFunction, args, fieldPrefix = 'contract') {
52
+ const abi = parseAbi(abiString);
53
+ if (!abi) {
54
+ // If ABI is invalid JSON, surface a clear error
55
+ throw new errors_1.ValidationError(`${fieldPrefix}ABI`, 'Contract ABI must be valid JSON array.');
56
+ }
57
+ const fnItem = abi.find((item) => item && item.type === 'function' && buildFunctionSignature(item.name, item.inputs) === targetFunction);
58
+ if (!fnItem)
59
+ return; // If we cannot find it, skip strict arg validation
60
+ const inputs = Array.isArray(fnItem.inputs) ? fnItem.inputs : [];
61
+ if (inputs.length === 0)
62
+ return;
63
+ if (!args || args.length < inputs.length) {
64
+ throw new errors_1.ValidationError(`${fieldPrefix}Args`, 'All function arguments are required for static argument type.');
65
+ }
66
+ const missing = inputs.findIndex((_, idx) => !isNonEmptyString(args[idx]));
67
+ if (missing !== -1) {
68
+ throw new errors_1.ValidationError(`${fieldPrefix}Args`, 'All function arguments are required for static argument type.');
69
+ }
70
+ }
71
+ function validateTimeBasedJobInput(input, argType) {
72
+ if (!isNonEmptyString(input.jobTitle)) {
73
+ throw new errors_1.ValidationError('jobTitle', 'Job title is required.');
74
+ }
75
+ if (!input.timeFrame || input.timeFrame <= 0) {
76
+ throw new errors_1.ValidationError('timeframe', 'Timeframe must be a positive number of seconds.');
77
+ }
78
+ if (!isNonEmptyString(input.timezone)) {
79
+ throw new errors_1.ValidationError('timezone', 'Timezone is required.');
80
+ }
81
+ if (!isNonEmptyString(input.chainId)) {
82
+ throw new errors_1.ValidationError('chainId', 'Chain ID is required.');
83
+ }
84
+ // Schedule-specific required fields
85
+ if (input.scheduleType === 'interval') {
86
+ if (input.timeInterval === undefined || input.timeInterval === null || input.timeInterval <= 0) {
87
+ throw new errors_1.ValidationError('timeInterval', 'timeInterval is required and must be > 0 when scheduleType is interval.');
88
+ }
89
+ if (input.timeInterval > input.timeFrame) {
90
+ throw new errors_1.ValidationError('timeInterval', 'Time interval cannot exceed the timeframe.');
91
+ }
92
+ }
93
+ else if (input.scheduleType === 'cron') {
94
+ if (!isNonEmptyString(input.cronExpression)) {
95
+ throw new errors_1.ValidationError('cronExpression', 'cronExpression is required when scheduleType is cron.');
96
+ }
97
+ }
98
+ else if (input.scheduleType === 'specific') {
99
+ if (!isNonEmptyString(input.specificSchedule)) {
100
+ throw new errors_1.ValidationError('specificSchedule', 'specificSchedule is required when scheduleType is specific.');
101
+ }
102
+ }
103
+ else {
104
+ throw new errors_1.ValidationError('scheduleType', 'scheduleType must be one of interval | cron | specific.');
105
+ }
106
+ if (input.walletMode !== 'safe') {
107
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
108
+ }
109
+ // Arg type checks
110
+ const isDynamic = argType === 'dynamic' || argType === 2;
111
+ if (isDynamic) {
112
+ if (!isNonEmptyString(input.dynamicArgumentsScriptUrl) || !isValidUrl(input.dynamicArgumentsScriptUrl)) {
113
+ throw new errors_1.ValidationError('contractIpfs', 'IPFS Code URL is required and must be valid for dynamic argument type.');
114
+ }
115
+ }
116
+ else {
117
+ if (input.walletMode !== 'safe') {
118
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
119
+ }
120
+ }
121
+ }
122
+ function validateEventBasedJobInput(input, argType) {
123
+ if (!isNonEmptyString(input.jobTitle)) {
124
+ throw new errors_1.ValidationError('jobTitle', 'Job title is required.');
125
+ }
126
+ if (!input.timeFrame || input.timeFrame <= 0) {
127
+ throw new errors_1.ValidationError('timeframe', 'Timeframe must be a positive number of seconds.');
128
+ }
129
+ if (!isNonEmptyString(input.timezone)) {
130
+ throw new errors_1.ValidationError('timezone', 'Timezone is required.');
131
+ }
132
+ if (!isNonEmptyString(input.chainId)) {
133
+ throw new errors_1.ValidationError('chainId', 'Chain ID is required.');
134
+ }
135
+ if (!isNonEmptyString(input.triggerChainId)) {
136
+ throw new errors_1.ValidationError('triggerChainId', 'Trigger chain ID is required.');
137
+ }
138
+ validateContractBasics(input.triggerContractAddress, input.abi, input.triggerEvent, 'eventContract');
139
+ if (input.walletMode !== 'safe') {
140
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
141
+ }
142
+ const isDynamic = argType === 'dynamic' || argType === 2;
143
+ if (isDynamic) {
144
+ if (!isNonEmptyString(input.dynamicArgumentsScriptUrl) || !isValidUrl(input.dynamicArgumentsScriptUrl)) {
145
+ throw new errors_1.ValidationError('contractIpfs', 'IPFS Code URL is required and must be valid for dynamic argument type.');
146
+ }
147
+ }
148
+ else {
149
+ if (input.walletMode !== 'safe') {
150
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
151
+ }
152
+ }
153
+ }
154
+ function validateConditionBasedJobInput(input, argType) {
155
+ if (!isNonEmptyString(input.jobTitle)) {
156
+ throw new errors_1.ValidationError('jobTitle', 'Job title is required.');
157
+ }
158
+ if (!input.timeFrame || input.timeFrame <= 0) {
159
+ throw new errors_1.ValidationError('timeframe', 'Timeframe must be a positive number of seconds.');
160
+ }
161
+ if (!isNonEmptyString(input.timezone)) {
162
+ throw new errors_1.ValidationError('timezone', 'Timezone is required.');
163
+ }
164
+ if (!isNonEmptyString(input.chainId)) {
165
+ throw new errors_1.ValidationError('chainId', 'Chain ID is required.');
166
+ }
167
+ // Condition fields
168
+ if (!isNonEmptyString(input.conditionType)) {
169
+ throw new errors_1.ValidationError('contractConditionType', 'Condition type is required.');
170
+ }
171
+ if (!isNonEmptyString(input.valueSourceType)) {
172
+ throw new errors_1.ValidationError('contractSourceType', 'Value source type is required.');
173
+ }
174
+ if (!isNonEmptyString(input.valueSourceUrl) || !isValidUrl(input.valueSourceUrl)) {
175
+ throw new errors_1.ValidationError('contractSourceUrl', 'Source URL is required and must be valid.');
176
+ }
177
+ if (input.conditionType === 'between') {
178
+ if (input.upperLimit === undefined || input.lowerLimit === undefined || input.upperLimit === null || input.lowerLimit === null) {
179
+ throw new errors_1.ValidationError('contractLimits', 'Both upper and lower limits are required.');
180
+ }
181
+ }
182
+ else {
183
+ if (input.upperLimit === undefined || input.upperLimit === null) {
184
+ throw new errors_1.ValidationError('contractLimits', 'Value is required.');
185
+ }
186
+ }
187
+ if (input.walletMode !== 'safe') {
188
+ validateContractBasics(input.targetContractAddress, input.abi, input.targetFunction, 'contract');
189
+ }
190
+ const isDynamic = argType === 'dynamic' || argType === 2;
191
+ if (isDynamic) {
192
+ if (!isNonEmptyString(input.dynamicArgumentsScriptUrl) || !isValidUrl(input.dynamicArgumentsScriptUrl)) {
193
+ throw new errors_1.ValidationError('contractIpfs', 'IPFS Code URL is required and must be valid for dynamic argument type.');
194
+ }
195
+ }
196
+ else {
197
+ if (input.walletMode !== 'safe') {
198
+ validateStaticArguments(input.abi, input.targetFunction, input.arguments, 'contract');
199
+ }
200
+ }
201
+ }
202
+ function validateJobInput(jobInput, argType) {
203
+ if ('scheduleType' in jobInput) {
204
+ validateTimeBasedJobInput(jobInput, argType);
205
+ }
206
+ else if ('triggerChainId' in jobInput) {
207
+ validateEventBasedJobInput(jobInput, argType);
208
+ }
209
+ else {
210
+ validateConditionBasedJobInput(jobInput, argType);
211
+ }
212
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdk-triggerx",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "SDK for interacting with the TriggerX backend and smart contracts.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,8 +38,8 @@
38
38
  "@typescript-eslint/parser": "^8.38.0",
39
39
  "dotenv": "^17.2.1",
40
40
  "eslint": "^9.32.0",
41
- "jest": "^30.0.5",
42
- "ts-jest": "^29.4.0",
41
+ "jest": "^30.2.0",
42
+ "ts-jest": "^29.4.5",
43
43
  "typescript": "^5.8.3"
44
44
  }
45
45
  }