@ar.io/sdk 3.1.0-alpha.1 → 3.1.0-alpha.10
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/bundles/web.bundle.min.js +68 -68
- package/lib/cjs/cli/cli.js +19 -69
- package/lib/cjs/cli/commands/arnsPurchaseCommands.js +167 -0
- package/lib/cjs/cli/commands/gatewayWriteCommands.js +8 -4
- package/lib/cjs/cli/commands/readCommands.js +1 -22
- package/lib/cjs/cli/commands/transfer.js +5 -1
- package/lib/cjs/cli/options.js +8 -7
- package/lib/cjs/cli/utils.js +39 -7
- package/lib/cjs/common/contracts/ao-process.js +34 -16
- package/lib/cjs/common/io.js +76 -116
- package/lib/cjs/utils/arweave.js +22 -13
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/cli.js +21 -71
- package/lib/esm/cli/commands/arnsPurchaseCommands.js +159 -0
- package/lib/esm/cli/commands/gatewayWriteCommands.js +6 -2
- package/lib/esm/cli/commands/readCommands.js +2 -23
- package/lib/esm/cli/commands/transfer.js +6 -2
- package/lib/esm/cli/options.js +7 -6
- package/lib/esm/cli/utils.js +34 -5
- package/lib/esm/common/contracts/ao-process.js +34 -16
- package/lib/esm/common/io.js +77 -117
- package/lib/esm/utils/arweave.js +21 -11
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/arnsPurchaseCommands.d.ts +22 -0
- package/lib/types/cli/options.d.ts +1 -9
- package/lib/types/cli/types.d.ts +3 -5
- package/lib/types/cli/utils.d.ts +16 -3
- package/lib/types/common/contracts/ao-process.d.ts +1 -0
- package/lib/types/common/io.d.ts +14 -43
- package/lib/types/types/common.d.ts +1 -0
- package/lib/types/types/io.d.ts +15 -9
- package/lib/types/utils/arweave.d.ts +6 -18
- package/lib/types/version.d.ts +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { assertConfirmationPrompt, assertEnoughBalanceForArNSPurchase, fundFromFromOptions, positiveIntegerFromOptions, recordTypeFromOptions, requiredPositiveIntegerFromOptions, requiredStringFromOptions, writeARIOFromOptions, writeActionTagsFromOptions, } from '../utils.js';
|
|
2
|
+
export async function buyRecordCLICommand(o) {
|
|
3
|
+
const { ario, signerAddress } = writeARIOFromOptions(o);
|
|
4
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
5
|
+
const type = recordTypeFromOptions(o);
|
|
6
|
+
const years = positiveIntegerFromOptions(o, 'years');
|
|
7
|
+
const fundFrom = fundFromFromOptions(o);
|
|
8
|
+
const processId = o.processId;
|
|
9
|
+
if (processId === undefined) {
|
|
10
|
+
// TODO: Spawn ANT process, register it to ANT registry, get process ID
|
|
11
|
+
throw new Error('Process ID must be provided for buy-record');
|
|
12
|
+
}
|
|
13
|
+
if (!o.skipConfirmation) {
|
|
14
|
+
const existingRecord = await ario.getArNSRecord({
|
|
15
|
+
name,
|
|
16
|
+
});
|
|
17
|
+
if (existingRecord !== undefined) {
|
|
18
|
+
throw new Error(`ArNS Record ${name} is already owned`);
|
|
19
|
+
}
|
|
20
|
+
await assertEnoughBalanceForArNSPurchase({
|
|
21
|
+
ario,
|
|
22
|
+
address: signerAddress,
|
|
23
|
+
costDetailsParams: {
|
|
24
|
+
intent: 'Buy-Record',
|
|
25
|
+
type,
|
|
26
|
+
name,
|
|
27
|
+
years,
|
|
28
|
+
fundFrom,
|
|
29
|
+
fromAddress: signerAddress,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
await assertConfirmationPrompt(`Are you sure you want to ${type} the record ${name}?`, o);
|
|
33
|
+
}
|
|
34
|
+
return ario.buyRecord({
|
|
35
|
+
name: requiredStringFromOptions(o, 'name'),
|
|
36
|
+
processId,
|
|
37
|
+
type,
|
|
38
|
+
years,
|
|
39
|
+
fundFrom: fundFromFromOptions(o),
|
|
40
|
+
}, writeActionTagsFromOptions(o));
|
|
41
|
+
}
|
|
42
|
+
export async function upgradeRecordCLICommand(o) {
|
|
43
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
44
|
+
const { ario, signerAddress } = writeARIOFromOptions(o);
|
|
45
|
+
const fundFrom = fundFromFromOptions(o);
|
|
46
|
+
if (!o.skipConfirmation) {
|
|
47
|
+
const existingRecord = await ario.getArNSRecord({
|
|
48
|
+
name,
|
|
49
|
+
});
|
|
50
|
+
if (existingRecord === undefined) {
|
|
51
|
+
throw new Error(`ArNS Record ${name} does not exist`);
|
|
52
|
+
}
|
|
53
|
+
if (existingRecord.type === 'permabuy') {
|
|
54
|
+
throw new Error(`ArNS Record ${name} is already a permabuy`);
|
|
55
|
+
}
|
|
56
|
+
await assertEnoughBalanceForArNSPurchase({
|
|
57
|
+
ario,
|
|
58
|
+
address: signerAddress,
|
|
59
|
+
costDetailsParams: {
|
|
60
|
+
intent: 'Upgrade-Name',
|
|
61
|
+
name,
|
|
62
|
+
fundFrom,
|
|
63
|
+
fromAddress: signerAddress,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
await assertConfirmationPrompt(`Are you sure you want to upgrade the lease of ${name} to a permabuy?`, o);
|
|
67
|
+
}
|
|
68
|
+
return ario.upgradeRecord({
|
|
69
|
+
name,
|
|
70
|
+
fundFrom,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export async function extendLeaseCLICommand(o) {
|
|
74
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
75
|
+
const years = requiredPositiveIntegerFromOptions(o, 'years');
|
|
76
|
+
const fundFrom = fundFromFromOptions(o);
|
|
77
|
+
const { ario, signerAddress } = writeARIOFromOptions(o);
|
|
78
|
+
if (!o.skipConfirmation) {
|
|
79
|
+
const existingRecord = await ario.getArNSRecord({
|
|
80
|
+
name,
|
|
81
|
+
});
|
|
82
|
+
if (existingRecord === undefined) {
|
|
83
|
+
throw new Error(`ArNS Record ${name} does not exist`);
|
|
84
|
+
}
|
|
85
|
+
if (existingRecord.type === 'permabuy') {
|
|
86
|
+
throw new Error(`ArNS Record ${name} is a permabuy and cannot be extended`);
|
|
87
|
+
}
|
|
88
|
+
await assertEnoughBalanceForArNSPurchase({
|
|
89
|
+
ario: ario,
|
|
90
|
+
address: signerAddress,
|
|
91
|
+
costDetailsParams: {
|
|
92
|
+
intent: 'Extend-Lease',
|
|
93
|
+
name,
|
|
94
|
+
years,
|
|
95
|
+
fundFrom,
|
|
96
|
+
fromAddress: signerAddress,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
await assertConfirmationPrompt(`Are you sure you want to extend the lease of ${name} by ${years}?`, o);
|
|
100
|
+
}
|
|
101
|
+
return ario.extendLease({
|
|
102
|
+
name,
|
|
103
|
+
years,
|
|
104
|
+
}, writeActionTagsFromOptions(o));
|
|
105
|
+
}
|
|
106
|
+
export async function increaseUndernameLimitCLICommand(o) {
|
|
107
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
108
|
+
const increaseCount = requiredPositiveIntegerFromOptions(o, 'increaseCount');
|
|
109
|
+
const fundFrom = fundFromFromOptions(o);
|
|
110
|
+
const { ario, signerAddress } = writeARIOFromOptions(o);
|
|
111
|
+
if (!o.skipConfirmation) {
|
|
112
|
+
const existingRecord = await ario.getArNSRecord({
|
|
113
|
+
name,
|
|
114
|
+
});
|
|
115
|
+
if (existingRecord === undefined) {
|
|
116
|
+
throw new Error(`ArNS Record ${name} does not exist`);
|
|
117
|
+
}
|
|
118
|
+
await assertEnoughBalanceForArNSPurchase({
|
|
119
|
+
ario,
|
|
120
|
+
address: signerAddress,
|
|
121
|
+
costDetailsParams: {
|
|
122
|
+
intent: 'Increase-Undername-Limit',
|
|
123
|
+
name,
|
|
124
|
+
quantity: increaseCount,
|
|
125
|
+
fundFrom,
|
|
126
|
+
fromAddress: signerAddress,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
await assertConfirmationPrompt(`Are you sure you want to increase the undername limit of ${name} by ${increaseCount}?`, o);
|
|
130
|
+
}
|
|
131
|
+
return ario.increaseUndernameLimit({
|
|
132
|
+
name,
|
|
133
|
+
increaseCount,
|
|
134
|
+
}, writeActionTagsFromOptions(o));
|
|
135
|
+
}
|
|
136
|
+
export async function requestPrimaryNameCLICommand(o) {
|
|
137
|
+
const { ario, signerAddress } = writeARIOFromOptions(o);
|
|
138
|
+
const fundFrom = fundFromFromOptions(o);
|
|
139
|
+
const name = requiredStringFromOptions(o, 'name');
|
|
140
|
+
if (!o.skipConfirmation) {
|
|
141
|
+
// TODO: Assert name requested is not already owned?
|
|
142
|
+
// TODO: More assertions?
|
|
143
|
+
await assertEnoughBalanceForArNSPurchase({
|
|
144
|
+
ario,
|
|
145
|
+
address: signerAddress,
|
|
146
|
+
costDetailsParams: {
|
|
147
|
+
intent: 'Primary-Name-Request',
|
|
148
|
+
name,
|
|
149
|
+
fromAddress: signerAddress,
|
|
150
|
+
fundFrom,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
await assertConfirmationPrompt(`Are you sure you want to request the primary name ${name}?`, o);
|
|
154
|
+
}
|
|
155
|
+
return ario.requestPrimaryName({
|
|
156
|
+
name,
|
|
157
|
+
fundFrom,
|
|
158
|
+
}, writeActionTagsFromOptions(o));
|
|
159
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import prompts from 'prompts';
|
|
17
17
|
import { mARIOToken } from '../../node/index.js';
|
|
18
|
-
import { assertConfirmationPrompt,
|
|
18
|
+
import { assertConfirmationPrompt, assertEnoughMARIOBalance, formatARIOWithCommas, gatewaySettingsFromOptions, redelegateParamsFromOptions, requiredAddressFromOptions, requiredMARIOFromOptions, requiredStringArrayFromOptions, requiredStringFromOptions, requiredTargetAndQuantityFromOptions, stringifyJsonForCLIDisplay, writeARIOFromOptions, writeActionTagsFromOptions, } from '../utils.js';
|
|
19
19
|
export async function joinNetwork(options) {
|
|
20
20
|
const { ario, signerAddress } = writeARIOFromOptions(options);
|
|
21
21
|
const mARIOQuantity = requiredMARIOFromOptions(options, 'operatorStake');
|
|
@@ -34,7 +34,11 @@ export async function joinNetwork(options) {
|
|
|
34
34
|
if (settings.operators.minStake > mARIOQuantity.valueOf()) {
|
|
35
35
|
throw new Error(`The minimum operator stake is ${formatARIOWithCommas(new mARIOToken(settings.operators.minStake).toARIO())} ARIO. Please provide a higher stake.`);
|
|
36
36
|
}
|
|
37
|
-
await
|
|
37
|
+
await assertEnoughMARIOBalance({
|
|
38
|
+
ario,
|
|
39
|
+
address: signerAddress,
|
|
40
|
+
mARIOQuantity,
|
|
41
|
+
});
|
|
38
42
|
await assertConfirmationPrompt(`Gateway Settings:\n\n${JSON.stringify(settings, null, 2)}\n\nYou are about to stake ${formatARIOWithCommas(mARIOQuantity.toARIO())} ARIO to join the AR.IO network\nAre you sure?\n`, options);
|
|
39
43
|
}
|
|
40
44
|
const result = await ario.joinNetwork(settings, writeActionTagsFromOptions(options));
|
|
@@ -1,21 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { fundFromOptions, isValidFundFrom, } from '../../types/io.js';
|
|
17
1
|
import { mARIOToken } from '../../types/token.js';
|
|
18
|
-
import { addressFromOptions, epochInputFromOptions, formatARIOWithCommas, getTokenCostParamsFromOptions, paginationParamsFromOptions, readARIOFromOptions, requiredAddressFromOptions, requiredStringFromOptions, } from '../utils.js';
|
|
2
|
+
import { addressFromOptions, epochInputFromOptions, formatARIOWithCommas, fundFromFromOptions, getTokenCostParamsFromOptions, paginationParamsFromOptions, readARIOFromOptions, requiredAddressFromOptions, requiredStringFromOptions, } from '../utils.js';
|
|
19
3
|
export async function getGateway(o) {
|
|
20
4
|
const address = requiredAddressFromOptions(o);
|
|
21
5
|
const gateway = await readARIOFromOptions(o).getGateway({
|
|
@@ -123,14 +107,9 @@ export async function getTokenCost(o) {
|
|
|
123
107
|
return output;
|
|
124
108
|
}
|
|
125
109
|
export async function getCostDetails(o) {
|
|
126
|
-
if (o.fundFrom !== undefined) {
|
|
127
|
-
if (!isValidFundFrom(o.fundFrom)) {
|
|
128
|
-
throw new Error(`Invalid fund from: ${o.fundFrom}. Please use one of ${fundFromOptions.join(', ')}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
110
|
const costDetails = await readARIOFromOptions(o).getCostDetails({
|
|
132
111
|
...getTokenCostParamsFromOptions(o),
|
|
133
|
-
fundFrom: o
|
|
112
|
+
fundFrom: fundFromFromOptions(o),
|
|
134
113
|
});
|
|
135
114
|
const output = {
|
|
136
115
|
...costDetails,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { assertEnoughMARIOBalance, confirmationPrompt, formatARIOWithCommas, requiredTargetAndQuantityFromOptions, writeARIOFromOptions, writeActionTagsFromOptions, } from '../utils.js';
|
|
2
2
|
export async function transfer(options) {
|
|
3
3
|
const { target, arioQuantity } = requiredTargetAndQuantityFromOptions(options);
|
|
4
4
|
const { ario, signerAddress } = writeARIOFromOptions(options);
|
|
5
5
|
if (!options.skipConfirmation) {
|
|
6
|
-
await
|
|
6
|
+
await assertEnoughMARIOBalance({
|
|
7
|
+
ario,
|
|
8
|
+
address: signerAddress,
|
|
9
|
+
mARIOQuantity: arioQuantity.toMARIO(),
|
|
10
|
+
});
|
|
7
11
|
const confirm = await confirmationPrompt(`Are you sure you want to transfer ${formatARIOWithCommas(arioQuantity)} ARIO to ${target}?`);
|
|
8
12
|
if (!confirm) {
|
|
9
13
|
return { message: 'Transfer aborted by user' };
|
package/lib/esm/cli/options.js
CHANGED
|
@@ -252,11 +252,13 @@ export const globalOptions = [
|
|
|
252
252
|
optionMap.cuUrl,
|
|
253
253
|
];
|
|
254
254
|
export const writeActionOptions = [optionMap.skipConfirmation, optionMap.tags];
|
|
255
|
-
export const
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
export const arnsPurchaseOptions = [
|
|
256
|
+
...writeActionOptions,
|
|
257
|
+
optionMap.name,
|
|
258
|
+
optionMap.fundFrom,
|
|
259
|
+
];
|
|
258
260
|
export const epochOptions = [optionMap.epochIndex, optionMap.timestamp];
|
|
259
|
-
export const addressAndVaultIdOptions = [
|
|
261
|
+
export const addressAndVaultIdOptions = [optionMap.address, optionMap.vaultId];
|
|
260
262
|
export const nameWriteOptions = [...writeActionOptions, optionMap.name];
|
|
261
263
|
export const paginationOptions = [
|
|
262
264
|
optionMap.cursor,
|
|
@@ -313,8 +315,7 @@ export const joinNetworkOptions = [
|
|
|
313
315
|
optionMap.operatorStake,
|
|
314
316
|
];
|
|
315
317
|
export const buyRecordOptions = [
|
|
316
|
-
...
|
|
317
|
-
optionMap.name,
|
|
318
|
+
...arnsPurchaseOptions,
|
|
318
319
|
optionMap.quantity,
|
|
319
320
|
optionMap.type,
|
|
320
321
|
optionMap.years,
|
package/lib/esm/cli/utils.js
CHANGED
|
@@ -17,7 +17,7 @@ import { connect } from '@permaweb/aoconnect';
|
|
|
17
17
|
import { program } from 'commander';
|
|
18
18
|
import { readFileSync } from 'fs';
|
|
19
19
|
import prompts from 'prompts';
|
|
20
|
-
import { ANT, AOProcess, ARIO, ARIOToken, ARIO_DEVNET_PROCESS_ID, ARIO_TESTNET_PROCESS_ID, ArweaveSigner, Logger, createAoSigner, fromB64Url, initANTStateForAddress, isValidIntent, mARIOToken, sha256B64Url, validIntents, } from '../node/index.js';
|
|
20
|
+
import { ANT, AOProcess, ARIO, ARIOToken, ARIO_DEVNET_PROCESS_ID, ARIO_TESTNET_PROCESS_ID, ArweaveSigner, Logger, createAoSigner, fromB64Url, fundFromOptions, initANTStateForAddress, isValidFundFrom, isValidIntent, mARIOToken, sha256B64Url, validIntents, } from '../node/index.js';
|
|
21
21
|
import { globalOptions } from './options.js';
|
|
22
22
|
export function stringifyJsonForCLIDisplay(json) {
|
|
23
23
|
return JSON.stringify(json, null, 2);
|
|
@@ -141,6 +141,9 @@ export function formatARIOWithCommas(value) {
|
|
|
141
141
|
}
|
|
142
142
|
return integerWithCommas + '.' + decimalPart;
|
|
143
143
|
}
|
|
144
|
+
export function formatMARIOToARIOWithCommas(value) {
|
|
145
|
+
return formatARIOWithCommas(value.toARIO());
|
|
146
|
+
}
|
|
144
147
|
/** helper to get address from --address option first, then check wallet options */
|
|
145
148
|
export function addressFromOptions(options) {
|
|
146
149
|
if (options.address !== undefined) {
|
|
@@ -265,16 +268,34 @@ export function recordTypeFromOptions(options) {
|
|
|
265
268
|
}
|
|
266
269
|
return options.type;
|
|
267
270
|
}
|
|
268
|
-
export function
|
|
271
|
+
export function requiredMARIOFromOptions(options, key) {
|
|
269
272
|
if (options[key] === undefined) {
|
|
270
273
|
throw new Error(`No ${key} provided. Use --${key} denominated in ARIO`);
|
|
271
274
|
}
|
|
272
275
|
return new ARIOToken(+options[key]).toMARIO();
|
|
273
276
|
}
|
|
274
|
-
export async function
|
|
277
|
+
export async function assertEnoughBalanceForArNSPurchase({ ario, address, costDetailsParams, }) {
|
|
278
|
+
const costDetails = await ario.getCostDetails(costDetailsParams);
|
|
279
|
+
if (costDetails.fundingPlan) {
|
|
280
|
+
if (costDetails.fundingPlan.shortfall > 0) {
|
|
281
|
+
throw new Error(`Insufficient balance for action. Shortfall: ${formatMARIOToARIOWithCommas(new mARIOToken(costDetails.fundingPlan.shortfall))}\n${JSON.stringify(costDetails, null, 2)}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
await assertEnoughMARIOBalance({
|
|
286
|
+
ario,
|
|
287
|
+
address,
|
|
288
|
+
mARIOQuantity: costDetails.tokenCost,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
export async function assertEnoughMARIOBalance({ address, ario, mARIOQuantity, }) {
|
|
293
|
+
if (typeof mARIOQuantity === 'number') {
|
|
294
|
+
mARIOQuantity = new mARIOToken(mARIOQuantity);
|
|
295
|
+
}
|
|
275
296
|
const balance = await ario.getBalance({ address });
|
|
276
|
-
if (balance <
|
|
277
|
-
throw new Error(`Insufficient ARIO balance for action. Balance available: ${new mARIOToken(balance)
|
|
297
|
+
if (balance < mARIOQuantity.valueOf()) {
|
|
298
|
+
throw new Error(`Insufficient ARIO balance for action. Balance available: ${formatMARIOToARIOWithCommas(new mARIOToken(balance))} ARIO`);
|
|
278
299
|
}
|
|
279
300
|
}
|
|
280
301
|
export async function confirmationPrompt(message) {
|
|
@@ -383,3 +404,11 @@ export function getTokenCostParamsFromOptions(o) {
|
|
|
383
404
|
fromAddress: addressFromOptions(o),
|
|
384
405
|
};
|
|
385
406
|
}
|
|
407
|
+
export function fundFromFromOptions(o) {
|
|
408
|
+
if (o.fundFrom !== undefined) {
|
|
409
|
+
if (!isValidFundFrom(o.fundFrom)) {
|
|
410
|
+
throw new Error(`Invalid fund from: ${o.fundFrom}. Please use one of ${fundFromOptions.join(', ')}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return o.fundFrom ?? 'balance';
|
|
414
|
+
}
|
|
@@ -28,6 +28,12 @@ export class AOProcess {
|
|
|
28
28
|
this.logger = logger;
|
|
29
29
|
this.ao = ao;
|
|
30
30
|
}
|
|
31
|
+
isMessageDataEmpty(messageData) {
|
|
32
|
+
return (messageData === undefined ||
|
|
33
|
+
messageData === 'null' || // This is what the CU returns for 'nil' values that are json.encoded
|
|
34
|
+
messageData === '' ||
|
|
35
|
+
messageData === null);
|
|
36
|
+
}
|
|
31
37
|
async read({ tags, retries = 3, fromAddress, }) {
|
|
32
38
|
let attempts = 0;
|
|
33
39
|
let lastError;
|
|
@@ -48,20 +54,18 @@ export class AOProcess {
|
|
|
48
54
|
this.logger.debug(`Read interaction result`, {
|
|
49
55
|
result,
|
|
50
56
|
});
|
|
57
|
+
const error = errorMessageFromOutput(result);
|
|
58
|
+
if (error !== undefined) {
|
|
59
|
+
throw new Error(error);
|
|
60
|
+
}
|
|
51
61
|
if (result.Messages === undefined || result.Messages.length === 0) {
|
|
52
62
|
this.logger.debug(`Process ${this.processId} does not support provided action.`, result, tags);
|
|
53
63
|
throw new Error(`Process ${this.processId} does not support provided action.`);
|
|
54
64
|
}
|
|
55
|
-
const tagsOutput = result.Messages?.[0]?.Tags;
|
|
56
65
|
const messageData = result.Messages?.[0]?.Data;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
throw new Error(`${error}${messageData ? `: ${messageData}` : ''}`);
|
|
61
|
-
}
|
|
62
|
-
// return empty object if no data is returned
|
|
63
|
-
if (messageData === undefined) {
|
|
64
|
-
return {};
|
|
66
|
+
// return undefined if no data is returned
|
|
67
|
+
if (this.isMessageDataEmpty(messageData)) {
|
|
68
|
+
return undefined;
|
|
65
69
|
}
|
|
66
70
|
const response = safeDecode(result.Messages[0].Data);
|
|
67
71
|
return response;
|
|
@@ -69,7 +73,7 @@ export class AOProcess {
|
|
|
69
73
|
catch (e) {
|
|
70
74
|
attempts++;
|
|
71
75
|
this.logger.debug(`Read attempt ${attempts} failed`, {
|
|
72
|
-
error: e,
|
|
76
|
+
error: e instanceof Error ? e.message : e,
|
|
73
77
|
tags,
|
|
74
78
|
});
|
|
75
79
|
lastError = e;
|
|
@@ -116,11 +120,8 @@ export class AOProcess {
|
|
|
116
120
|
messageId,
|
|
117
121
|
processId: this.processId,
|
|
118
122
|
});
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
output.Messages?.[0]?.Tags?.find((tag) => tag.name === 'Error')
|
|
122
|
-
?.value;
|
|
123
|
-
if (error) {
|
|
123
|
+
const error = errorMessageFromOutput(output);
|
|
124
|
+
if (error !== undefined) {
|
|
124
125
|
throw new WriteInteractionError(error);
|
|
125
126
|
}
|
|
126
127
|
// check if there are any Messages in the output
|
|
@@ -130,7 +131,7 @@ export class AOProcess {
|
|
|
130
131
|
if (output.Messages.length === 0) {
|
|
131
132
|
throw new Error(`Process ${this.processId} does not support provided action.`);
|
|
132
133
|
}
|
|
133
|
-
if (output.Messages[0].Data
|
|
134
|
+
if (this.isMessageDataEmpty(output.Messages[0].Data)) {
|
|
134
135
|
return { id: messageId };
|
|
135
136
|
}
|
|
136
137
|
const resultData = safeDecode(output.Messages[0].Data);
|
|
@@ -167,3 +168,20 @@ export class AOProcess {
|
|
|
167
168
|
throw lastError;
|
|
168
169
|
}
|
|
169
170
|
}
|
|
171
|
+
function errorMessageFromOutput(output) {
|
|
172
|
+
const errorData = output.Error;
|
|
173
|
+
if (errorData !== undefined) {
|
|
174
|
+
// TODO: Could clean this one up too, current error is verbose, but not always deterministic for parsing
|
|
175
|
+
// Throw the whole raw error if AO process level error
|
|
176
|
+
return errorData;
|
|
177
|
+
}
|
|
178
|
+
const error = output.Messages?.[0]?.Tags?.find((tag) => tag.name === 'Error')?.value;
|
|
179
|
+
if (error !== undefined) {
|
|
180
|
+
// from [string "aos"]:6846: Name is already registered
|
|
181
|
+
const lineNumber = error.match(/\d+/)?.[0];
|
|
182
|
+
const message = error.replace(/\[string "aos"\]:\d+:/, '');
|
|
183
|
+
// to more user friendly: Name is already registered (line 6846)
|
|
184
|
+
return `${message} (line ${lineNumber})`.trim();
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|