@ardrive/turbo-sdk 1.42.0 → 1.43.0-alpha.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/lib/cjs/cli/cli.js +97 -0
- package/lib/cjs/cli/commands/arns.js +475 -0
- package/lib/cjs/cli/commands/freeStatus.js +47 -0
- package/lib/cjs/cli/commands/index.js +3 -0
- package/lib/cjs/cli/commands/paymentHistory.js +25 -0
- package/lib/cjs/cli/options.js +202 -1
- package/lib/cjs/common/arnsActions.js +125 -0
- package/lib/cjs/common/chunked.js +51 -1
- package/lib/cjs/common/folderIndex.js +401 -0
- package/lib/cjs/common/http.js +40 -6
- package/lib/cjs/common/index.js +7 -0
- package/lib/cjs/common/payment.js +548 -2
- package/lib/cjs/common/signer.js +27 -6
- package/lib/cjs/common/token/index.js +0 -11
- package/lib/cjs/common/turbo.js +162 -0
- package/lib/cjs/common/upload.js +314 -31
- package/lib/cjs/node/folderIndex.js +132 -0
- package/lib/cjs/node/index.js +1 -0
- package/lib/cjs/node/upload.js +7 -0
- package/lib/cjs/types.js +53 -3
- package/lib/cjs/utils/common.js +0 -4
- package/lib/cjs/utils/errors.js +38 -1
- package/lib/cjs/utils/folderIndex.js +88 -0
- package/lib/cjs/utils/uuid.js +31 -0
- package/lib/cjs/web/signer.js +4 -2
- package/lib/esm/cli/cli.js +99 -2
- package/lib/esm/cli/commands/arns.js +450 -0
- package/lib/esm/cli/commands/freeStatus.js +44 -0
- package/lib/esm/cli/commands/index.js +3 -0
- package/lib/esm/cli/commands/paymentHistory.js +22 -0
- package/lib/esm/cli/options.js +201 -0
- package/lib/esm/common/arnsActions.js +114 -0
- package/lib/esm/common/chunked.js +51 -1
- package/lib/esm/common/folderIndex.js +396 -0
- package/lib/esm/common/http.js +39 -5
- package/lib/esm/common/index.js +7 -0
- package/lib/esm/common/payment.js +548 -2
- package/lib/esm/common/signer.js +28 -7
- package/lib/esm/common/token/index.js +1 -12
- package/lib/esm/common/turbo.js +162 -0
- package/lib/esm/common/upload.js +316 -33
- package/lib/esm/node/folderIndex.js +129 -0
- package/lib/esm/node/index.js +1 -0
- package/lib/esm/node/upload.js +7 -0
- package/lib/esm/types.js +52 -2
- package/lib/esm/utils/common.js +0 -4
- package/lib/esm/utils/errors.js +35 -0
- package/lib/esm/utils/folderIndex.js +81 -0
- package/lib/esm/utils/uuid.js +28 -0
- package/lib/esm/web/signer.js +4 -2
- package/lib/types/cli/commands/arns.d.ts +147 -0
- package/lib/types/cli/commands/arns.d.ts.map +1 -0
- package/lib/types/cli/commands/freeStatus.d.ts +3 -0
- package/lib/types/cli/commands/freeStatus.d.ts.map +1 -0
- package/lib/types/cli/commands/index.d.ts +3 -0
- package/lib/types/cli/commands/index.d.ts.map +1 -1
- package/lib/types/cli/commands/paymentHistory.d.ts +18 -0
- package/lib/types/cli/commands/paymentHistory.d.ts.map +1 -0
- package/lib/types/cli/options.d.ts +423 -0
- package/lib/types/cli/options.d.ts.map +1 -1
- package/lib/types/cli/types.d.ts +78 -0
- package/lib/types/cli/types.d.ts.map +1 -1
- package/lib/types/common/arnsActions.d.ts +58 -0
- package/lib/types/common/arnsActions.d.ts.map +1 -0
- package/lib/types/common/chunked.d.ts +47 -2
- package/lib/types/common/chunked.d.ts.map +1 -1
- package/lib/types/common/folderIndex.d.ts +54 -0
- package/lib/types/common/folderIndex.d.ts.map +1 -0
- package/lib/types/common/http.d.ts +25 -2
- package/lib/types/common/http.d.ts.map +1 -1
- package/lib/types/common/index.d.ts +3 -0
- package/lib/types/common/index.d.ts.map +1 -1
- package/lib/types/common/payment.d.ts +291 -1
- package/lib/types/common/payment.d.ts.map +1 -1
- package/lib/types/common/signer.d.ts +12 -6
- package/lib/types/common/signer.d.ts.map +1 -1
- package/lib/types/common/token/index.d.ts.map +1 -1
- package/lib/types/common/turbo.d.ts +183 -1
- package/lib/types/common/turbo.d.ts.map +1 -1
- package/lib/types/common/upload.d.ts +41 -0
- package/lib/types/common/upload.d.ts.map +1 -1
- package/lib/types/node/folderIndex.d.ts +28 -0
- package/lib/types/node/folderIndex.d.ts.map +1 -0
- package/lib/types/node/index.d.ts +1 -0
- package/lib/types/node/index.d.ts.map +1 -1
- package/lib/types/node/upload.d.ts +1 -0
- package/lib/types/node/upload.d.ts.map +1 -1
- package/lib/types/types.d.ts +694 -3
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/utils/common.d.ts.map +1 -1
- package/lib/types/utils/errors.d.ts +29 -0
- package/lib/types/utils/errors.d.ts.map +1 -1
- package/lib/types/utils/folderIndex.d.ts +47 -0
- package/lib/types/utils/folderIndex.d.ts.map +1 -0
- package/lib/types/utils/uuid.d.ts +7 -0
- package/lib/types/utils/uuid.d.ts.map +1 -0
- package/lib/types/web/signer.d.ts +1 -1
- package/lib/types/web/signer.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,450 @@
|
|
|
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 { BigNumber } from 'bignumber.js';
|
|
17
|
+
import { solanaOwnerSigner } from '../../common/arnsActions.js';
|
|
18
|
+
import { TurboFactory } from '../../node/factory.js';
|
|
19
|
+
import { arNSActions, } from '../../types.js';
|
|
20
|
+
import { FiatPaymentsDisabledError, InsufficientCreditsError, } from '../../utils/errors.js';
|
|
21
|
+
import { wincPerCredit } from '../constants.js';
|
|
22
|
+
import { configFromOptions, turboFromOptions } from '../utils.js';
|
|
23
|
+
/**
|
|
24
|
+
* The ANT owner's Solana key.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately separate from the wallet that pays: the payer holds Turbo
|
|
27
|
+
* credits (and may be Arweave or Ethereum), while the owner holds the ANT and
|
|
28
|
+
* must be Solana. The owner needs a key to SIGN with, not a funded account —
|
|
29
|
+
* Turbo is the fee payer on every sponsored action.
|
|
30
|
+
*/
|
|
31
|
+
function ownerFromOptions(options) {
|
|
32
|
+
if (options.ownerKey === undefined || options.ownerKey === '') {
|
|
33
|
+
throw new Error('Must provide --owner-key (a base58 Solana secret key) — it owns the ANT and signs for it. ' +
|
|
34
|
+
'This is separate from the wallet paying in Turbo Credits.');
|
|
35
|
+
}
|
|
36
|
+
return solanaOwnerSigner(options.ownerKey);
|
|
37
|
+
}
|
|
38
|
+
/** The four ARIO-purchase actions are priced via `arnsPrice`, not this route. */
|
|
39
|
+
const ARNS_PURCHASE_ACTIONS = new Set([
|
|
40
|
+
'buy-name',
|
|
41
|
+
'extend-lease',
|
|
42
|
+
'upgrade-name',
|
|
43
|
+
'increase-undername-limit',
|
|
44
|
+
]);
|
|
45
|
+
export function requiredNameFromOptions(options) {
|
|
46
|
+
if (options.name === undefined || options.name.length === 0) {
|
|
47
|
+
throw new Error('Must provide an ArNS --name');
|
|
48
|
+
}
|
|
49
|
+
return options.name;
|
|
50
|
+
}
|
|
51
|
+
export function positiveIntFromOption(value, flag) {
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
throw new Error(`Must provide ${flag}`);
|
|
54
|
+
}
|
|
55
|
+
const num = +value;
|
|
56
|
+
if (!Number.isFinite(num) || !Number.isInteger(num) || num <= 0) {
|
|
57
|
+
throw new Error(`${flag} must be a positive integer`);
|
|
58
|
+
}
|
|
59
|
+
return num;
|
|
60
|
+
}
|
|
61
|
+
export function typeFromOptions(value) {
|
|
62
|
+
if (value !== 'lease' && value !== 'permabuy') {
|
|
63
|
+
throw new Error("Must provide --type of 'lease' or 'permabuy'");
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
/** Parses `--action` for `arns-action-price`, rejecting the four purchase actions. */
|
|
68
|
+
export function actionFromOptions(options) {
|
|
69
|
+
const { action } = options;
|
|
70
|
+
if (action === undefined || action.length === 0) {
|
|
71
|
+
throw new Error(`Must provide --action. One of: ${arNSActions.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
if (!arNSActions.includes(action)) {
|
|
74
|
+
throw new Error(`Invalid --action '${action}'. One of: ${arNSActions.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
if (ARNS_PURCHASE_ACTIONS.has(action)) {
|
|
77
|
+
throw new Error(`'${action}' is priced via \`turbo arns-price\`, not \`arns-action-price\` — ` +
|
|
78
|
+
'it spends ARIO, not just the flat credits margin this route quotes.');
|
|
79
|
+
}
|
|
80
|
+
return action;
|
|
81
|
+
}
|
|
82
|
+
/** `null` clears the field (Set-Record-Metadata's tri-state), `undefined` leaves it unchanged. */
|
|
83
|
+
function metadataFieldFromOptions(value, clear, flag) {
|
|
84
|
+
// Commander registers each value flag and its --clear-* partner separately, so
|
|
85
|
+
// it accepts both. Silently letting the clear win would discard a value the
|
|
86
|
+
// caller explicitly passed.
|
|
87
|
+
if (clear && value !== undefined) {
|
|
88
|
+
throw new Error(`Cannot pass both --${flag} and --clear-${flag}. Pass one: the value to set it, or the clear flag to unset it.`);
|
|
89
|
+
}
|
|
90
|
+
return clear ? null : value;
|
|
91
|
+
}
|
|
92
|
+
export function paidByFromArNSOptions(paidBy) {
|
|
93
|
+
return paidBy !== undefined && paidBy.length > 0 ? paidBy : undefined;
|
|
94
|
+
}
|
|
95
|
+
// A price quote depends only on the name (length), type, and years — NOT on the
|
|
96
|
+
// ANT the name will resolve to. The service ignores `processId` for pricing, but
|
|
97
|
+
// the SDK's Buy-Name validation still requires a non-empty one, so we substitute
|
|
98
|
+
// this obvious placeholder when the user omits `--process-id` from `arns-price`.
|
|
99
|
+
// (`buy-arns-name` still requires a real `--process-id`.)
|
|
100
|
+
const PRICING_PLACEHOLDER_PROCESS_ID = 'pricing-only-no-process-id';
|
|
101
|
+
/**
|
|
102
|
+
* Infer the ArNS pricing intent from the provided flags:
|
|
103
|
+
* - `--type` present -> Buy-Name (lease needs --years; --process-id optional for pricing)
|
|
104
|
+
* - `--increase-qty` present -> Increase-Undername-Limit
|
|
105
|
+
* - `--years` present (no type) -> Extend-Lease
|
|
106
|
+
* - otherwise -> Upgrade-Name
|
|
107
|
+
*/
|
|
108
|
+
export function arnsPriceParamsFromOptions(options) {
|
|
109
|
+
const name = requiredNameFromOptions(options);
|
|
110
|
+
if (options.type !== undefined) {
|
|
111
|
+
const type = typeFromOptions(options.type);
|
|
112
|
+
const processId = options.processId ?? PRICING_PLACEHOLDER_PROCESS_ID;
|
|
113
|
+
if (type === 'lease') {
|
|
114
|
+
return {
|
|
115
|
+
intent: 'Buy-Name',
|
|
116
|
+
name,
|
|
117
|
+
type: 'lease',
|
|
118
|
+
years: positiveIntFromOption(options.years, '--years'),
|
|
119
|
+
processId,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
intent: 'Buy-Name',
|
|
124
|
+
name,
|
|
125
|
+
type: 'permabuy',
|
|
126
|
+
processId,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (options.increaseQty !== undefined) {
|
|
130
|
+
return {
|
|
131
|
+
intent: 'Increase-Undername-Limit',
|
|
132
|
+
name,
|
|
133
|
+
increaseQty: positiveIntFromOption(options.increaseQty, '--increase-qty'),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (options.years !== undefined) {
|
|
137
|
+
return {
|
|
138
|
+
intent: 'Extend-Lease',
|
|
139
|
+
name,
|
|
140
|
+
years: positiveIntFromOption(options.years, '--years'),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { intent: 'Upgrade-Name', name };
|
|
144
|
+
}
|
|
145
|
+
function creditsFromWinc(winc) {
|
|
146
|
+
return new BigNumber(winc).dividedBy(wincPerCredit).toFixed(12);
|
|
147
|
+
}
|
|
148
|
+
/** Rethrow a 402 as a clear, actionable "top up" message. */
|
|
149
|
+
/**
|
|
150
|
+
* Takes the promise rather than a thunk: wrapping the call in a closure would
|
|
151
|
+
* discard the `undefined` narrowing each handler's guard clauses establish.
|
|
152
|
+
*/
|
|
153
|
+
async function withCreditErrorMapping(promise) {
|
|
154
|
+
try {
|
|
155
|
+
return await promise;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof InsufficientCreditsError) {
|
|
159
|
+
throw new Error('Insufficient Turbo credits to complete this ArNS action. ' +
|
|
160
|
+
'Top up your balance (e.g. `turbo top-up` or `turbo crypto-fund`) and retry.');
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function logPurchaseResult(action, result) {
|
|
166
|
+
console.log(JSON.stringify({
|
|
167
|
+
message: `${action} completed!`,
|
|
168
|
+
nonce: result.nonce,
|
|
169
|
+
antId: result.antId,
|
|
170
|
+
// Solana transaction id of the on-chain write.
|
|
171
|
+
messageId: result.messageId,
|
|
172
|
+
...(result.alreadyCompleted === true ? { alreadyCompleted: true } : {}),
|
|
173
|
+
}, null, 2));
|
|
174
|
+
// Credit-paid buys go through the actions API, so the nonce lives in the
|
|
175
|
+
// action namespace. `arns-purchase-status` reads `/arns/purchase/`, a
|
|
176
|
+
// separate namespace that answers "Purchase status not found" for this nonce.
|
|
177
|
+
console.log(`\nTrack this with:\n turbo arns-action-status --nonce ${result.nonce}`);
|
|
178
|
+
}
|
|
179
|
+
export async function arnsPrice(options, turbo) {
|
|
180
|
+
const params = arnsPriceParamsFromOptions(options);
|
|
181
|
+
const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
|
|
182
|
+
const { winc, wincTotal, antSpawnSurchargeWinc, mARIO } = await client.getArNSPriceForName(params);
|
|
183
|
+
// `wincTotal` is the figure to pay. `winc` is the name only and excludes the
|
|
184
|
+
// ANT spawn surcharge, which for a Buy-Name can exceed the name's own price,
|
|
185
|
+
// so printing it as the price under-quotes what `buy-arns-name` then debits.
|
|
186
|
+
console.log(JSON.stringify({
|
|
187
|
+
name: params.name,
|
|
188
|
+
intent: params.intent,
|
|
189
|
+
wincTotal,
|
|
190
|
+
credits: creditsFromWinc(wincTotal),
|
|
191
|
+
nameOnlyWinc: winc,
|
|
192
|
+
antSpawnSurchargeWinc,
|
|
193
|
+
mARIO,
|
|
194
|
+
}, null, 2));
|
|
195
|
+
}
|
|
196
|
+
export async function arnsFiatQuote(options, turbo) {
|
|
197
|
+
const params = arnsPriceParamsFromOptions(options);
|
|
198
|
+
// `arnsPriceParamsFromOptions` substitutes PRICING_PLACEHOLDER_PROCESS_ID for
|
|
199
|
+
// an omitted Buy-Name `processId`, which is fine for a price lookup but NOT
|
|
200
|
+
// here: a quote records a real purchase, and that placeholder is not a valid
|
|
201
|
+
// ANT. Send `processId` only when the caller actually supplied one — omitting
|
|
202
|
+
// it is what tells Turbo to custodially provision the ANT.
|
|
203
|
+
if (options.processId === undefined) {
|
|
204
|
+
delete params.processId;
|
|
205
|
+
}
|
|
206
|
+
const address = options.address;
|
|
207
|
+
if (address === undefined) {
|
|
208
|
+
throw new Error('A destination --address is required for a fiat ArNS quote.');
|
|
209
|
+
}
|
|
210
|
+
const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
|
|
211
|
+
try {
|
|
212
|
+
const { purchaseQuote, paymentSession, adjustments, fees } = await client.getArNSFiatPurchaseQuote({
|
|
213
|
+
...params,
|
|
214
|
+
address,
|
|
215
|
+
currency: (options.currency ?? 'usd'),
|
|
216
|
+
method: options.method,
|
|
217
|
+
promoCodes: options.promoCode,
|
|
218
|
+
});
|
|
219
|
+
console.log(JSON.stringify({
|
|
220
|
+
name: purchaseQuote.name,
|
|
221
|
+
intent: purchaseQuote.intent,
|
|
222
|
+
nonce: purchaseQuote.nonce,
|
|
223
|
+
paymentAmount: purchaseQuote.paymentAmount,
|
|
224
|
+
currency: purchaseQuote.currencyType,
|
|
225
|
+
quoteExpirationDate: purchaseQuote.quoteExpirationDate,
|
|
226
|
+
paymentSessionId: paymentSession.id,
|
|
227
|
+
// Present for a payment intent / embedded checkout; a hosted
|
|
228
|
+
// checkout session returns `url` instead.
|
|
229
|
+
clientSecret: paymentSession.client_secret ?? undefined,
|
|
230
|
+
checkoutUrl: paymentSession.url ?? undefined,
|
|
231
|
+
adjustments,
|
|
232
|
+
fees,
|
|
233
|
+
}, null, 2));
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
if (error instanceof FiatPaymentsDisabledError) {
|
|
237
|
+
console.error('Fiat (Stripe) payments are disabled on this payment service. Use the credit-paid commands (buy-arns-name, extend-arns-lease, ...) instead.');
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export async function buyArNSName(options, turbo) {
|
|
244
|
+
const name = requiredNameFromOptions(options);
|
|
245
|
+
const type = typeFromOptions(options.type);
|
|
246
|
+
const paidBy = paidByFromArNSOptions(options.paidBy);
|
|
247
|
+
// Every buy mints a fresh ANT straight to `--owner-key`; Turbo never holds
|
|
248
|
+
// it, and there is no bring-your-own-ANT path any more.
|
|
249
|
+
const owner = ownerFromOptions(options);
|
|
250
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
251
|
+
const result = await withCreditErrorMapping(type === 'lease'
|
|
252
|
+
? client.buyArNSName({
|
|
253
|
+
name,
|
|
254
|
+
owner,
|
|
255
|
+
type: 'lease',
|
|
256
|
+
years: positiveIntFromOption(options.years, '--years'),
|
|
257
|
+
paidBy,
|
|
258
|
+
})
|
|
259
|
+
: client.buyArNSName({ name, owner, type: 'permabuy', paidBy }));
|
|
260
|
+
logPurchaseResult('ArNS name purchase', result);
|
|
261
|
+
}
|
|
262
|
+
export async function extendArNSLease(options, turbo) {
|
|
263
|
+
const name = requiredNameFromOptions(options);
|
|
264
|
+
const years = positiveIntFromOption(options.years, '--years');
|
|
265
|
+
const paidBy = paidByFromArNSOptions(options.paidBy);
|
|
266
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
267
|
+
const result = await withCreditErrorMapping(client.extendArNSLease({ name, years, paidBy }));
|
|
268
|
+
logPurchaseResult('ArNS lease extension', result);
|
|
269
|
+
}
|
|
270
|
+
export async function increaseArNSUndernames(options, turbo) {
|
|
271
|
+
const name = requiredNameFromOptions(options);
|
|
272
|
+
const increaseQty = positiveIntFromOption(options.increaseQty, '--increase-qty');
|
|
273
|
+
const paidBy = paidByFromArNSOptions(options.paidBy);
|
|
274
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
275
|
+
const result = await withCreditErrorMapping(client.increaseArNSUndernameLimit({ name, increaseQty, paidBy }));
|
|
276
|
+
logPurchaseResult('ArNS undername limit increase', result);
|
|
277
|
+
}
|
|
278
|
+
export async function upgradeArNSName(options, turbo) {
|
|
279
|
+
const name = requiredNameFromOptions(options);
|
|
280
|
+
const paidBy = paidByFromArNSOptions(options.paidBy);
|
|
281
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
282
|
+
const result = await withCreditErrorMapping(client.upgradeArNSName({ name, paidBy }));
|
|
283
|
+
logPurchaseResult('ArNS name upgrade (to permabuy)', result);
|
|
284
|
+
}
|
|
285
|
+
export async function arnsPurchaseStatus(options, turbo) {
|
|
286
|
+
if (options.nonce === undefined || options.nonce.length === 0) {
|
|
287
|
+
throw new Error('Must provide a --nonce to look up purchase status');
|
|
288
|
+
}
|
|
289
|
+
const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
|
|
290
|
+
const status = await client.getArNSPurchaseStatus({ nonce: options.nonce });
|
|
291
|
+
const state = status.failedDate !== undefined
|
|
292
|
+
? 'failed'
|
|
293
|
+
: status.messageId
|
|
294
|
+
? 'success'
|
|
295
|
+
: 'pending';
|
|
296
|
+
console.log(JSON.stringify({ state, ...status }, null, 2));
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Status of a credit-paid ArNS action (buy, extend, upgrade, increase, and the
|
|
300
|
+
* eight non-purchase actions). Distinct from `arns-purchase-status`, which
|
|
301
|
+
* reads the `/arns/purchase/` namespace that fiat quotes land in.
|
|
302
|
+
*
|
|
303
|
+
* Authenticated because `getArNSActionStatus` lives on the authenticated
|
|
304
|
+
* client, though the route itself needs no signature.
|
|
305
|
+
*/
|
|
306
|
+
export async function arnsActionStatus(options, turbo) {
|
|
307
|
+
if (options.nonce === undefined || options.nonce.length === 0) {
|
|
308
|
+
throw new Error('Must provide a --nonce to look up action status');
|
|
309
|
+
}
|
|
310
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
311
|
+
const status = await client.getArNSActionStatus(options.nonce);
|
|
312
|
+
const state = status.failedDate !== undefined
|
|
313
|
+
? 'failed'
|
|
314
|
+
: status.messageId
|
|
315
|
+
? 'success'
|
|
316
|
+
: 'pending';
|
|
317
|
+
console.log(JSON.stringify({ state, ...status }, null, 2));
|
|
318
|
+
}
|
|
319
|
+
export async function transferArNSAnt(options, turbo) {
|
|
320
|
+
if (options.antId === undefined) {
|
|
321
|
+
throw new Error('Must provide an --ant-id to transfer');
|
|
322
|
+
}
|
|
323
|
+
if (options.target === undefined) {
|
|
324
|
+
throw new Error('Must provide a --target address to transfer the ANT to');
|
|
325
|
+
}
|
|
326
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
327
|
+
const result = await withCreditErrorMapping(client.transferArNSAnt({
|
|
328
|
+
antId: options.antId,
|
|
329
|
+
owner: ownerFromOptions(options),
|
|
330
|
+
target: options.target,
|
|
331
|
+
}));
|
|
332
|
+
console.log(JSON.stringify({ message: 'ANT transfer submitted!', ...result }, null, 2));
|
|
333
|
+
}
|
|
334
|
+
export async function setArNSRecord(options, turbo) {
|
|
335
|
+
if (options.antId === undefined) {
|
|
336
|
+
throw new Error('Must provide an --ant-id to set a record on');
|
|
337
|
+
}
|
|
338
|
+
if (options.transactionId === undefined) {
|
|
339
|
+
throw new Error('Must provide a --transaction-id for the record');
|
|
340
|
+
}
|
|
341
|
+
const ttlSeconds = positiveIntFromOption(options.ttlSeconds, '--ttl-seconds');
|
|
342
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
343
|
+
const result = await withCreditErrorMapping(client.setArNSRecord({
|
|
344
|
+
antId: options.antId,
|
|
345
|
+
owner: ownerFromOptions(options),
|
|
346
|
+
undername: options.undername ?? '@',
|
|
347
|
+
transactionId: options.transactionId,
|
|
348
|
+
ttlSeconds,
|
|
349
|
+
}));
|
|
350
|
+
console.log(JSON.stringify({ message: 'ArNS record set!', ...result }, null, 2));
|
|
351
|
+
}
|
|
352
|
+
export async function removeArNSRecord(options, turbo) {
|
|
353
|
+
if (options.antId === undefined) {
|
|
354
|
+
throw new Error('Must provide an --ant-id to remove a record from');
|
|
355
|
+
}
|
|
356
|
+
if (options.undername === undefined || options.undername.length === 0) {
|
|
357
|
+
throw new Error('Must provide an --undername to remove');
|
|
358
|
+
}
|
|
359
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
360
|
+
const result = await withCreditErrorMapping(client.removeArNSRecord({
|
|
361
|
+
antId: options.antId,
|
|
362
|
+
owner: ownerFromOptions(options),
|
|
363
|
+
undername: options.undername,
|
|
364
|
+
}));
|
|
365
|
+
console.log(JSON.stringify({ message: 'ArNS record removed!', ...result }, null, 2));
|
|
366
|
+
}
|
|
367
|
+
export async function addArNSController(options, turbo) {
|
|
368
|
+
if (options.antId === undefined) {
|
|
369
|
+
throw new Error('Must provide an --ant-id to add a controller to');
|
|
370
|
+
}
|
|
371
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
372
|
+
const result = await withCreditErrorMapping(client.addArNSController({
|
|
373
|
+
antId: options.antId,
|
|
374
|
+
owner: ownerFromOptions(options),
|
|
375
|
+
target: options.target,
|
|
376
|
+
}));
|
|
377
|
+
console.log(JSON.stringify({ message: 'ArNS controller added!', ...result }, null, 2));
|
|
378
|
+
}
|
|
379
|
+
export async function removeArNSController(options, turbo) {
|
|
380
|
+
if (options.antId === undefined) {
|
|
381
|
+
throw new Error('Must provide an --ant-id to remove a controller from');
|
|
382
|
+
}
|
|
383
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
384
|
+
const result = await withCreditErrorMapping(client.removeArNSController({
|
|
385
|
+
antId: options.antId,
|
|
386
|
+
owner: ownerFromOptions(options),
|
|
387
|
+
target: options.target,
|
|
388
|
+
}));
|
|
389
|
+
console.log(JSON.stringify({ message: 'ArNS controller removed!', ...result }, null, 2));
|
|
390
|
+
}
|
|
391
|
+
export async function transferArNSRecord(options, turbo) {
|
|
392
|
+
if (options.antId === undefined) {
|
|
393
|
+
throw new Error('Must provide an --ant-id whose record to transfer');
|
|
394
|
+
}
|
|
395
|
+
if (options.undername === undefined || options.undername.length === 0) {
|
|
396
|
+
throw new Error('Must provide an --undername to transfer');
|
|
397
|
+
}
|
|
398
|
+
if (options.target === undefined) {
|
|
399
|
+
throw new Error('Must provide a --target address to transfer the record to');
|
|
400
|
+
}
|
|
401
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
402
|
+
const result = await withCreditErrorMapping(client.transferArNSRecord({
|
|
403
|
+
antId: options.antId,
|
|
404
|
+
owner: ownerFromOptions(options),
|
|
405
|
+
undername: options.undername,
|
|
406
|
+
target: options.target,
|
|
407
|
+
}));
|
|
408
|
+
console.log(JSON.stringify({ message: 'ArNS record transferred!', ...result }, null, 2));
|
|
409
|
+
}
|
|
410
|
+
export async function setArNSRecordMetadata(options, turbo) {
|
|
411
|
+
if (options.antId === undefined) {
|
|
412
|
+
throw new Error('Must provide an --ant-id to set record metadata on');
|
|
413
|
+
}
|
|
414
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
415
|
+
const result = await withCreditErrorMapping(client.setArNSRecordMetadata({
|
|
416
|
+
antId: options.antId,
|
|
417
|
+
owner: ownerFromOptions(options),
|
|
418
|
+
undername: options.undername ?? '@',
|
|
419
|
+
displayName: metadataFieldFromOptions(options.displayName, options.clearDisplayName, 'display-name'),
|
|
420
|
+
recordLogo: metadataFieldFromOptions(options.recordLogo, options.clearRecordLogo, 'record-logo'),
|
|
421
|
+
recordDescription: metadataFieldFromOptions(options.recordDescription, options.clearRecordDescription, 'record-description'),
|
|
422
|
+
recordKeywords: metadataFieldFromOptions(options.recordKeywords, options.clearRecordKeywords, 'record-keywords'),
|
|
423
|
+
}));
|
|
424
|
+
console.log(JSON.stringify({ message: 'ArNS record metadata set!', ...result }, null, 2));
|
|
425
|
+
}
|
|
426
|
+
export async function removeArNSRecordMetadata(options, turbo) {
|
|
427
|
+
if (options.antId === undefined) {
|
|
428
|
+
throw new Error('Must provide an --ant-id to remove record metadata from');
|
|
429
|
+
}
|
|
430
|
+
if (options.undername === undefined || options.undername.length === 0) {
|
|
431
|
+
throw new Error('Must provide an --undername');
|
|
432
|
+
}
|
|
433
|
+
const client = turbo ?? (await turboFromOptions(options));
|
|
434
|
+
const result = await withCreditErrorMapping(client.removeArNSRecordMetadata({
|
|
435
|
+
antId: options.antId,
|
|
436
|
+
owner: ownerFromOptions(options),
|
|
437
|
+
undername: options.undername,
|
|
438
|
+
}));
|
|
439
|
+
console.log(JSON.stringify({ message: 'ArNS record metadata removed!', ...result }, null, 2));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Preview what one of the eight non-purchase actions will debit, without
|
|
443
|
+
* creating it.
|
|
444
|
+
*/
|
|
445
|
+
export async function arnsActionPrice(options, turbo) {
|
|
446
|
+
const action = actionFromOptions(options);
|
|
447
|
+
const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
|
|
448
|
+
const { wincQty } = await client.getArNSActionPrice(action);
|
|
449
|
+
console.log(JSON.stringify({ action, wincQty, credits: creditsFromWinc(wincQty) }, null, 2));
|
|
450
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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 { TurboFactory } from '../../node/factory.js';
|
|
17
|
+
import { addressOrPrivateKeyFromOptions, configFromOptions } from '../utils.js';
|
|
18
|
+
export async function freeStatus(options) {
|
|
19
|
+
const config = configFromOptions(options);
|
|
20
|
+
const { address, privateKey } = await addressOrPrivateKeyFromOptions(options);
|
|
21
|
+
const { bytesRemaining, nativeAddress } = await (async () => {
|
|
22
|
+
if (address !== undefined) {
|
|
23
|
+
return {
|
|
24
|
+
...(await TurboFactory.unauthenticated(config).getFreeStatus(address)),
|
|
25
|
+
nativeAddress: address,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (privateKey === undefined) {
|
|
29
|
+
throw new Error('Must provide an (--address) or use a valid wallet');
|
|
30
|
+
}
|
|
31
|
+
const turbo = TurboFactory.authenticated({
|
|
32
|
+
...config,
|
|
33
|
+
privateKey,
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
...(await turbo.getFreeStatus()),
|
|
37
|
+
nativeAddress: await turbo.signer.getNativeAddress(),
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
console.log(`Turbo free-tier allowance for Native Address "${nativeAddress}"\n` +
|
|
41
|
+
(bytesRemaining === null
|
|
42
|
+
? 'Free bytes remaining: unlimited (exempt/partner wallet)'
|
|
43
|
+
: `Free bytes remaining: ${bytesRemaining}`));
|
|
44
|
+
}
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
export * from './arns.js';
|
|
16
17
|
export * from './balance.js';
|
|
17
18
|
export * from './cryptoFund.js';
|
|
19
|
+
export * from './freeStatus.js';
|
|
20
|
+
export * from './paymentHistory.js';
|
|
18
21
|
export * from './price.js';
|
|
19
22
|
export * from './topUp.js';
|
|
20
23
|
export * from './uploadFile.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { turboFromOptions } from '../utils.js';
|
|
2
|
+
export async function paymentHistory(options) {
|
|
3
|
+
// Signature-required and self-scoped: a wallet is mandatory (there is no
|
|
4
|
+
// --address form), and the service returns only this signer's own top-ups.
|
|
5
|
+
const turbo = await turboFromOptions(options);
|
|
6
|
+
const limit = options.limit !== undefined ? +options.limit : undefined;
|
|
7
|
+
if (limit !== undefined &&
|
|
8
|
+
(!Number.isInteger(limit) || limit < 1 || limit > 100)) {
|
|
9
|
+
throw new Error('--limit must be an integer between 1 and 100');
|
|
10
|
+
}
|
|
11
|
+
const { payments, hasMore, cursor } = await turbo.getPaymentHistory({
|
|
12
|
+
limit,
|
|
13
|
+
cursor: options.cursor,
|
|
14
|
+
});
|
|
15
|
+
// stdout carries only the JSON page and the next-page hint goes to stderr, so
|
|
16
|
+
// `... | jq` works at the default log level. (--debug intentionally routes SDK
|
|
17
|
+
// logs to stdout and will interleave — expected when you ask for debug output.)
|
|
18
|
+
console.log(JSON.stringify({ payments, hasMore, cursor }, null, 2));
|
|
19
|
+
if (hasMore) {
|
|
20
|
+
console.error(`\nMore results available — fetch the next page with --cursor ${cursor}`);
|
|
21
|
+
}
|
|
22
|
+
}
|