@ardrive/turbo-sdk 1.41.3 → 1.42.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.
Files changed (97) hide show
  1. package/lib/cjs/cli/cli.js +61 -0
  2. package/lib/cjs/cli/commands/arns.js +317 -0
  3. package/lib/cjs/cli/commands/freeStatus.js +47 -0
  4. package/lib/cjs/cli/commands/index.js +3 -0
  5. package/lib/cjs/cli/commands/paymentHistory.js +25 -0
  6. package/lib/cjs/cli/options.js +124 -11
  7. package/lib/cjs/cli/utils.js +3 -19
  8. package/lib/cjs/common/arnsActions.js +102 -0
  9. package/lib/cjs/common/factory.js +1 -3
  10. package/lib/cjs/common/http.js +20 -5
  11. package/lib/cjs/common/index.js +6 -0
  12. package/lib/cjs/common/payment.js +482 -3
  13. package/lib/cjs/common/signer.js +27 -6
  14. package/lib/cjs/common/token/ario.js +104 -83
  15. package/lib/cjs/common/token/index.js +0 -11
  16. package/lib/cjs/common/token/solana.js +1 -0
  17. package/lib/cjs/common/turbo.js +131 -0
  18. package/lib/cjs/common/upload.js +3 -2
  19. package/lib/cjs/node/factory.js +1 -3
  20. package/lib/cjs/types.js +44 -3
  21. package/lib/cjs/utils/common.js +5 -21
  22. package/lib/cjs/utils/errors.js +38 -1
  23. package/lib/cjs/utils/uuid.js +31 -0
  24. package/lib/cjs/web/factory.js +1 -3
  25. package/lib/cjs/web/signer.js +4 -2
  26. package/lib/esm/cli/cli.js +63 -2
  27. package/lib/esm/cli/commands/arns.js +300 -0
  28. package/lib/esm/cli/commands/freeStatus.js +44 -0
  29. package/lib/esm/cli/commands/index.js +3 -0
  30. package/lib/esm/cli/commands/paymentHistory.js +22 -0
  31. package/lib/esm/cli/options.js +123 -10
  32. package/lib/esm/cli/utils.js +4 -20
  33. package/lib/esm/common/arnsActions.js +93 -0
  34. package/lib/esm/common/factory.js +1 -3
  35. package/lib/esm/common/http.js +19 -4
  36. package/lib/esm/common/index.js +6 -0
  37. package/lib/esm/common/payment.js +482 -3
  38. package/lib/esm/common/signer.js +28 -7
  39. package/lib/esm/common/token/ario.js +102 -84
  40. package/lib/esm/common/token/index.js +1 -12
  41. package/lib/esm/common/token/solana.js +1 -0
  42. package/lib/esm/common/turbo.js +131 -0
  43. package/lib/esm/common/upload.js +4 -3
  44. package/lib/esm/node/factory.js +1 -3
  45. package/lib/esm/types.js +43 -2
  46. package/lib/esm/utils/common.js +4 -20
  47. package/lib/esm/utils/errors.js +35 -0
  48. package/lib/esm/utils/uuid.js +28 -0
  49. package/lib/esm/web/factory.js +1 -3
  50. package/lib/esm/web/signer.js +4 -2
  51. package/lib/types/cli/commands/arns.d.ts +86 -0
  52. package/lib/types/cli/commands/arns.d.ts.map +1 -0
  53. package/lib/types/cli/commands/freeStatus.d.ts +3 -0
  54. package/lib/types/cli/commands/freeStatus.d.ts.map +1 -0
  55. package/lib/types/cli/commands/index.d.ts +3 -0
  56. package/lib/types/cli/commands/index.d.ts.map +1 -1
  57. package/lib/types/cli/commands/paymentHistory.d.ts +18 -0
  58. package/lib/types/cli/commands/paymentHistory.d.ts.map +1 -0
  59. package/lib/types/cli/options.d.ts +238 -10
  60. package/lib/types/cli/options.d.ts.map +1 -1
  61. package/lib/types/cli/types.d.ts +41 -2
  62. package/lib/types/cli/types.d.ts.map +1 -1
  63. package/lib/types/cli/utils.d.ts.map +1 -1
  64. package/lib/types/common/arnsActions.d.ts +43 -0
  65. package/lib/types/common/arnsActions.d.ts.map +1 -0
  66. package/lib/types/common/factory.d.ts +1 -1
  67. package/lib/types/common/factory.d.ts.map +1 -1
  68. package/lib/types/common/http.d.ts +14 -1
  69. package/lib/types/common/http.d.ts.map +1 -1
  70. package/lib/types/common/index.d.ts +2 -0
  71. package/lib/types/common/index.d.ts.map +1 -1
  72. package/lib/types/common/payment.d.ts +230 -1
  73. package/lib/types/common/payment.d.ts.map +1 -1
  74. package/lib/types/common/signer.d.ts +12 -6
  75. package/lib/types/common/signer.d.ts.map +1 -1
  76. package/lib/types/common/token/ario.d.ts +13 -9
  77. package/lib/types/common/token/ario.d.ts.map +1 -1
  78. package/lib/types/common/token/index.d.ts.map +1 -1
  79. package/lib/types/common/token/solana.d.ts.map +1 -1
  80. package/lib/types/common/turbo.d.ts +140 -1
  81. package/lib/types/common/turbo.d.ts.map +1 -1
  82. package/lib/types/common/upload.d.ts.map +1 -1
  83. package/lib/types/node/factory.d.ts +1 -1
  84. package/lib/types/node/factory.d.ts.map +1 -1
  85. package/lib/types/types.d.ts +483 -7
  86. package/lib/types/types.d.ts.map +1 -1
  87. package/lib/types/utils/common.d.ts +0 -12
  88. package/lib/types/utils/common.d.ts.map +1 -1
  89. package/lib/types/utils/errors.d.ts +29 -0
  90. package/lib/types/utils/errors.d.ts.map +1 -1
  91. package/lib/types/utils/uuid.d.ts +7 -0
  92. package/lib/types/utils/uuid.d.ts.map +1 -0
  93. package/lib/types/web/factory.d.ts +1 -1
  94. package/lib/types/web/factory.d.ts.map +1 -1
  95. package/lib/types/web/signer.d.ts +1 -1
  96. package/lib/types/web/signer.d.ts.map +1 -1
  97. package/package.json +3 -2
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uuidV4 = uuidV4;
4
+ /**
5
+ * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ const crypto_1 = require("crypto");
20
+ /**
21
+ * RFC 4122 version 4 UUID, derived from `randomBytes` (already used across the
22
+ * SDK in both the node and web builds). Avoids depending on
23
+ * `crypto.randomUUID`, whose availability varies by runtime/polyfill.
24
+ */
25
+ function uuidV4() {
26
+ const bytes = (0, crypto_1.randomBytes)(16);
27
+ bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
28
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
29
+ const hex = bytes.toString('hex');
30
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
31
+ }
@@ -37,7 +37,7 @@ class TurboFactory extends factory_js_1.TurboBaseFactory {
37
37
  // Import the TurboAuthenticatedUploadService class from the web upload module
38
38
  return new upload_js_1.TurboAuthenticatedUploadService(config);
39
39
  }
40
- static authenticated({ privateKey, signer: providedSigner, paymentServiceConfig = {}, uploadServiceConfig = {}, token, gatewayUrl, tokenMap, tokenTools, walletAdapter, cuUrl, processId, }) {
40
+ static authenticated({ privateKey, signer: providedSigner, paymentServiceConfig = {}, uploadServiceConfig = {}, token, gatewayUrl, tokenMap, tokenTools, walletAdapter, }) {
41
41
  return new TurboFactory().getAuthenticatedTurbo({
42
42
  privateKey,
43
43
  signer: providedSigner,
@@ -49,8 +49,6 @@ class TurboFactory extends factory_js_1.TurboBaseFactory {
49
49
  tokenTools,
50
50
  logger: this.logger,
51
51
  walletAdapter,
52
- cuUrl,
53
- processId,
54
52
  });
55
53
  }
56
54
  }
@@ -64,9 +64,11 @@ class TurboWebArweaveSigner extends signer_js_1.TurboDataItemAbstractSigner {
64
64
  dataItemSizeFactory: () => signedDataItemSize,
65
65
  };
66
66
  }
67
- async generateSignedRequestHeaders() {
67
+ async generateSignedRequestHeaders(nonce, additionalData) {
68
68
  await this.setPublicKey();
69
- return super.generateSignedRequestHeaders();
69
+ // Pass through the caller's nonce + action-binding data (previously dropped,
70
+ // which would override a route-required UUID nonce and the H-2 binding).
71
+ return super.generateSignedRequestHeaders(nonce, additionalData);
70
72
  }
71
73
  async signData(dataToSign) {
72
74
  await this.setPublicKey();
@@ -20,14 +20,15 @@ import { DataItem } from '@dha-team/arbundles';
20
20
  import { program } from 'commander';
21
21
  import { readFileSync, readdirSync } from 'fs';
22
22
  import { version } from '../version.js';
23
+ import { arnsFiatQuote, arnsPrice, arnsPurchaseStatus, buyArNSName, extendArNSLease, increaseArNSUndernames, removeArNSRecord, setArNSRecord, transferArNSAnt, upgradeArNSName, } from './commands/arns.js';
23
24
  import { fiatEstimate } from './commands/fiatEstimate.js';
24
- import { balance, cryptoFund, price, topUp, uploadFile, uploadFolder, } from './commands/index.js';
25
+ import { balance, cryptoFund, freeStatus, paymentHistory, price, topUp, uploadFile, uploadFolder, } from './commands/index.js';
25
26
  import { listShares } from './commands/listShares.js';
26
27
  import { revokeCredits } from './commands/revokeCredits.js';
27
28
  import { shareCredits } from './commands/shareCredits.js';
28
29
  import { tokenPrice } from './commands/tokenPrice.js';
29
30
  import { x402UploadUnsignedFile } from './commands/x402UploadUnsignedData.js';
30
- import { globalOptions, listSharesOptions, optionMap, revokeCreditsOptions, shareCreditsOptions, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
31
+ import { arnsFiatQuoteOptions, arnsPriceOptions, arnsPurchaseStatusOptions, buyArNSNameOptions, extendArNSLeaseOptions, globalOptions, increaseArNSUndernamesOptions, listSharesOptions, optionMap, removeArNSRecordOptions, revokeCreditsOptions, setArNSRecordOptions, shareCreditsOptions, transferArNSAntOptions, upgradeArNSNameOptions, uploadFileOptions, uploadFolderOptions, walletOptions, } from './options.js';
31
32
  import { applyOptions, runCommand } from './utils.js';
32
33
  applyOptions(program
33
34
  .name('turbo')
@@ -37,6 +38,16 @@ applyOptions(program
37
38
  applyOptions(program.command('balance').description('Get balance of a Turbo address'), [optionMap.address, ...walletOptions]).action(async (_commandOptions, command) => {
38
39
  await runCommand(command, balance);
39
40
  });
41
+ applyOptions(program
42
+ .command('free-status')
43
+ .description('Get the free-tier upload allowance remaining for a Turbo address'), [optionMap.address, ...walletOptions]).action(async (_commandOptions, command) => {
44
+ await runCommand(command, freeStatus);
45
+ });
46
+ applyOptions(program
47
+ .command('payment-history')
48
+ .description("Get the signing wallet's own top-up (payment) history"), [...walletOptions, optionMap.limit, optionMap.cursor]).action(async (_commandOptions, command) => {
49
+ await runCommand(command, paymentHistory);
50
+ });
40
51
  applyOptions(program.command('top-up').description('Top up a Turbo address with Fiat'), [...walletOptions, optionMap.address, optionMap.value, optionMap.currency]).action(async (_commandOptions, command) => {
41
52
  await runCommand(command, topUp);
42
53
  });
@@ -84,6 +95,56 @@ applyOptions(program
84
95
  .description('Lists all given or received Turbo credit share approvals for specified address or connected wallet'), listSharesOptions).action(async (_commandOptions, command) => {
85
96
  await runCommand(command, listShares);
86
97
  });
98
+ applyOptions(program
99
+ .command('arns-price')
100
+ .description('Get the Turbo Credit (winc + mARIO) price to buy, extend, increase undernames, or upgrade an ArNS name'), arnsPriceOptions).action(async (_commandOptions, command) => {
101
+ await runCommand(command, arnsPrice);
102
+ });
103
+ applyOptions(program
104
+ .command('arns-fiat-quote')
105
+ .description('Quote an ArNS purchase paid by credit card (Stripe) - no credits needed'), arnsFiatQuoteOptions).action(async (_commandOptions, command) => {
106
+ await runCommand(command, arnsFiatQuote);
107
+ });
108
+ applyOptions(program
109
+ .command('buy-arns-name')
110
+ .description('Buy an ArNS name (lease or permabuy) with Turbo Credits'), buyArNSNameOptions).action(async (_commandOptions, command) => {
111
+ await runCommand(command, buyArNSName);
112
+ });
113
+ applyOptions(program
114
+ .command('extend-arns-lease')
115
+ .description('Extend an ArNS name lease with Turbo Credits'), extendArNSLeaseOptions).action(async (_commandOptions, command) => {
116
+ await runCommand(command, extendArNSLease);
117
+ });
118
+ applyOptions(program
119
+ .command('increase-arns-undernames')
120
+ .description('Increase the undername limit of an ArNS name with Turbo Credits'), increaseArNSUndernamesOptions).action(async (_commandOptions, command) => {
121
+ await runCommand(command, increaseArNSUndernames);
122
+ });
123
+ applyOptions(program
124
+ .command('upgrade-arns-name')
125
+ .description('Upgrade an ArNS leased name to a permabuy with Turbo Credits'), upgradeArNSNameOptions).action(async (_commandOptions, command) => {
126
+ await runCommand(command, upgradeArNSName);
127
+ });
128
+ applyOptions(program
129
+ .command('arns-purchase-status')
130
+ .description('Get the status of an ArNS purchase by its nonce'), arnsPurchaseStatusOptions).action(async (_commandOptions, command) => {
131
+ await runCommand(command, arnsPurchaseStatus);
132
+ });
133
+ applyOptions(program
134
+ .command('transfer-arns-ant')
135
+ .description('Transfer a Turbo-custodied ANT to a Solana pubkey you control'), transferArNSAntOptions).action(async (_commandOptions, command) => {
136
+ await runCommand(command, transferArNSAnt);
137
+ });
138
+ applyOptions(program
139
+ .command('set-arns-record')
140
+ .description('Set a resolution record on a Turbo-custodied ANT'), setArNSRecordOptions).action(async (_commandOptions, command) => {
141
+ await runCommand(command, setArNSRecord);
142
+ });
143
+ applyOptions(program
144
+ .command('remove-arns-record')
145
+ .description('Remove a resolution record (undername) from a Turbo-custodied ANT'), removeArNSRecordOptions).action(async (_commandOptions, command) => {
146
+ await runCommand(command, removeArNSRecord);
147
+ });
87
148
  applyOptions(program
88
149
  .command('inspect-data-items')
89
150
  .description('Lists all given or received Turbo credit share approvals for specified address or connected wallet'), [optionMap.folderPath]).action(async (_commandOptions, command) => {
@@ -0,0 +1,300 @@
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 { FiatPaymentsDisabledError, InsufficientCreditsError, } from '../../utils/errors.js';
20
+ import { wincPerCredit } from '../constants.js';
21
+ import { configFromOptions, turboFromOptions } from '../utils.js';
22
+ /**
23
+ * The ANT owner's Solana key.
24
+ *
25
+ * Deliberately separate from the wallet that pays: the payer holds Turbo
26
+ * credits (and may be Arweave or Ethereum), while the owner holds the ANT and
27
+ * must be Solana. The owner needs a key to SIGN with, not a funded account —
28
+ * Turbo is the fee payer on every sponsored action.
29
+ */
30
+ function ownerFromOptions(options) {
31
+ if (options.ownerKey === undefined || options.ownerKey === '') {
32
+ throw new Error('Must provide --owner-key (a base58 Solana secret key) — it owns the ANT and signs for it. ' +
33
+ 'This is separate from the wallet paying in Turbo Credits.');
34
+ }
35
+ return solanaOwnerSigner(options.ownerKey);
36
+ }
37
+ export function requiredNameFromOptions(options) {
38
+ if (options.name === undefined || options.name.length === 0) {
39
+ throw new Error('Must provide an ArNS --name');
40
+ }
41
+ return options.name;
42
+ }
43
+ export function positiveIntFromOption(value, flag) {
44
+ if (value === undefined) {
45
+ throw new Error(`Must provide ${flag}`);
46
+ }
47
+ const num = +value;
48
+ if (!Number.isFinite(num) || !Number.isInteger(num) || num <= 0) {
49
+ throw new Error(`${flag} must be a positive integer`);
50
+ }
51
+ return num;
52
+ }
53
+ export function typeFromOptions(value) {
54
+ if (value !== 'lease' && value !== 'permabuy') {
55
+ throw new Error("Must provide --type of 'lease' or 'permabuy'");
56
+ }
57
+ return value;
58
+ }
59
+ export function paidByFromArNSOptions(paidBy) {
60
+ return paidBy !== undefined && paidBy.length > 0 ? paidBy : undefined;
61
+ }
62
+ // A price quote depends only on the name (length), type, and years — NOT on the
63
+ // ANT the name will resolve to. The service ignores `processId` for pricing, but
64
+ // the SDK's Buy-Name validation still requires a non-empty one, so we substitute
65
+ // this obvious placeholder when the user omits `--process-id` from `arns-price`.
66
+ // (`buy-arns-name` still requires a real `--process-id`.)
67
+ const PRICING_PLACEHOLDER_PROCESS_ID = 'pricing-only-no-process-id';
68
+ /**
69
+ * Infer the ArNS pricing intent from the provided flags:
70
+ * - `--type` present -> Buy-Name (lease needs --years; --process-id optional for pricing)
71
+ * - `--increase-qty` present -> Increase-Undername-Limit
72
+ * - `--years` present (no type) -> Extend-Lease
73
+ * - otherwise -> Upgrade-Name
74
+ */
75
+ export function arnsPriceParamsFromOptions(options) {
76
+ const name = requiredNameFromOptions(options);
77
+ if (options.type !== undefined) {
78
+ const type = typeFromOptions(options.type);
79
+ const processId = options.processId ?? PRICING_PLACEHOLDER_PROCESS_ID;
80
+ if (type === 'lease') {
81
+ return {
82
+ intent: 'Buy-Name',
83
+ name,
84
+ type: 'lease',
85
+ years: positiveIntFromOption(options.years, '--years'),
86
+ processId,
87
+ };
88
+ }
89
+ return {
90
+ intent: 'Buy-Name',
91
+ name,
92
+ type: 'permabuy',
93
+ processId,
94
+ };
95
+ }
96
+ if (options.increaseQty !== undefined) {
97
+ return {
98
+ intent: 'Increase-Undername-Limit',
99
+ name,
100
+ increaseQty: positiveIntFromOption(options.increaseQty, '--increase-qty'),
101
+ };
102
+ }
103
+ if (options.years !== undefined) {
104
+ return {
105
+ intent: 'Extend-Lease',
106
+ name,
107
+ years: positiveIntFromOption(options.years, '--years'),
108
+ };
109
+ }
110
+ return { intent: 'Upgrade-Name', name };
111
+ }
112
+ function creditsFromWinc(winc) {
113
+ return new BigNumber(winc).dividedBy(wincPerCredit).toFixed(12);
114
+ }
115
+ /** Rethrow a 402 as a clear, actionable "top up" message. */
116
+ async function withCreditErrorMapping(fn) {
117
+ try {
118
+ return await fn();
119
+ }
120
+ catch (error) {
121
+ if (error instanceof InsufficientCreditsError) {
122
+ throw new Error('Insufficient Turbo credits to complete this ArNS purchase. ' +
123
+ 'Top up your balance (e.g. `turbo top-up` or `turbo crypto-fund`) and retry.');
124
+ }
125
+ throw error;
126
+ }
127
+ }
128
+ function logPurchaseResult(action, result) {
129
+ console.log(JSON.stringify({
130
+ message: `${action} completed!`,
131
+ nonce: result.nonce,
132
+ antId: result.antId,
133
+ // Solana transaction id of the on-chain write.
134
+ messageId: result.messageId,
135
+ ...(result.alreadyCompleted === true ? { alreadyCompleted: true } : {}),
136
+ }, null, 2));
137
+ console.log(`\nTrack this purchase with:\n turbo arns-purchase-status --nonce ${result.nonce}`);
138
+ }
139
+ export async function arnsPrice(options, turbo) {
140
+ const params = arnsPriceParamsFromOptions(options);
141
+ const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
142
+ const { winc, mARIO } = await client.getArNSPriceForName(params);
143
+ console.log(JSON.stringify({
144
+ name: params.name,
145
+ intent: params.intent,
146
+ winc,
147
+ credits: creditsFromWinc(winc),
148
+ mARIO,
149
+ }, null, 2));
150
+ }
151
+ export async function arnsFiatQuote(options, turbo) {
152
+ const params = arnsPriceParamsFromOptions(options);
153
+ // `arnsPriceParamsFromOptions` substitutes PRICING_PLACEHOLDER_PROCESS_ID for
154
+ // an omitted Buy-Name `processId`, which is fine for a price lookup but NOT
155
+ // here: a quote records a real purchase, and that placeholder is not a valid
156
+ // ANT. Send `processId` only when the caller actually supplied one — omitting
157
+ // it is what tells Turbo to custodially provision the ANT.
158
+ if (options.processId === undefined) {
159
+ delete params.processId;
160
+ }
161
+ const address = options.address;
162
+ if (address === undefined) {
163
+ throw new Error('A destination --address is required for a fiat ArNS quote.');
164
+ }
165
+ const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
166
+ try {
167
+ const { purchaseQuote, paymentSession, adjustments, fees } = await client.getArNSFiatPurchaseQuote({
168
+ ...params,
169
+ address,
170
+ currency: (options.currency ?? 'usd'),
171
+ method: options.method,
172
+ promoCodes: options.promoCode,
173
+ });
174
+ console.log(JSON.stringify({
175
+ name: purchaseQuote.name,
176
+ intent: purchaseQuote.intent,
177
+ nonce: purchaseQuote.nonce,
178
+ paymentAmount: purchaseQuote.paymentAmount,
179
+ currency: purchaseQuote.currencyType,
180
+ quoteExpirationDate: purchaseQuote.quoteExpirationDate,
181
+ paymentSessionId: paymentSession.id,
182
+ // Present for a payment intent / embedded checkout; a hosted
183
+ // checkout session returns `url` instead.
184
+ clientSecret: paymentSession.client_secret ?? undefined,
185
+ checkoutUrl: paymentSession.url ?? undefined,
186
+ adjustments,
187
+ fees,
188
+ }, null, 2));
189
+ }
190
+ catch (error) {
191
+ if (error instanceof FiatPaymentsDisabledError) {
192
+ console.error('Fiat (Stripe) payments are disabled on this payment service. Use the credit-paid commands (buy-arns-name, extend-arns-lease, ...) instead.');
193
+ throw error;
194
+ }
195
+ throw error;
196
+ }
197
+ }
198
+ export async function buyArNSName(options, turbo) {
199
+ const name = requiredNameFromOptions(options);
200
+ const type = typeFromOptions(options.type);
201
+ const paidBy = paidByFromArNSOptions(options.paidBy);
202
+ // Every buy mints a fresh ANT straight to `--owner-key`; Turbo never holds
203
+ // it, and there is no bring-your-own-ANT path any more.
204
+ const owner = ownerFromOptions(options);
205
+ const client = turbo ?? (await turboFromOptions(options));
206
+ const result = await withCreditErrorMapping(() => type === 'lease'
207
+ ? client.buyArNSName({
208
+ name,
209
+ owner,
210
+ type: 'lease',
211
+ years: positiveIntFromOption(options.years, '--years'),
212
+ paidBy,
213
+ })
214
+ : client.buyArNSName({ name, owner, type: 'permabuy', paidBy }));
215
+ logPurchaseResult('ArNS name purchase', result);
216
+ }
217
+ export async function extendArNSLease(options, turbo) {
218
+ const name = requiredNameFromOptions(options);
219
+ const years = positiveIntFromOption(options.years, '--years');
220
+ const paidBy = paidByFromArNSOptions(options.paidBy);
221
+ const client = turbo ?? (await turboFromOptions(options));
222
+ const result = await withCreditErrorMapping(() => client.extendArNSLease({ name, years, paidBy }));
223
+ logPurchaseResult('ArNS lease extension', result);
224
+ }
225
+ export async function increaseArNSUndernames(options, turbo) {
226
+ const name = requiredNameFromOptions(options);
227
+ const increaseQty = positiveIntFromOption(options.increaseQty, '--increase-qty');
228
+ const paidBy = paidByFromArNSOptions(options.paidBy);
229
+ const client = turbo ?? (await turboFromOptions(options));
230
+ const result = await withCreditErrorMapping(() => client.increaseArNSUndernameLimit({ name, increaseQty, paidBy }));
231
+ logPurchaseResult('ArNS undername limit increase', result);
232
+ }
233
+ export async function upgradeArNSName(options, turbo) {
234
+ const name = requiredNameFromOptions(options);
235
+ const paidBy = paidByFromArNSOptions(options.paidBy);
236
+ const client = turbo ?? (await turboFromOptions(options));
237
+ const result = await withCreditErrorMapping(() => client.upgradeArNSName({ name, paidBy }));
238
+ logPurchaseResult('ArNS name upgrade (to permabuy)', result);
239
+ }
240
+ export async function arnsPurchaseStatus(options, turbo) {
241
+ if (options.nonce === undefined || options.nonce.length === 0) {
242
+ throw new Error('Must provide a --nonce to look up purchase status');
243
+ }
244
+ const client = turbo ?? TurboFactory.unauthenticated(configFromOptions(options));
245
+ const status = await client.getArNSPurchaseStatus({ nonce: options.nonce });
246
+ const state = status.failedDate !== undefined
247
+ ? 'failed'
248
+ : status.messageId
249
+ ? 'success'
250
+ : 'pending';
251
+ console.log(JSON.stringify({ state, ...status }, null, 2));
252
+ }
253
+ export async function transferArNSAnt(options, turbo) {
254
+ if (options.antId === undefined) {
255
+ throw new Error('Must provide an --ant-id to transfer');
256
+ }
257
+ if (options.target === undefined) {
258
+ throw new Error('Must provide a --target address to transfer the ANT to');
259
+ }
260
+ const client = turbo ?? (await turboFromOptions(options));
261
+ const result = await client.transferArNSAnt({
262
+ antId: options.antId,
263
+ owner: ownerFromOptions(options),
264
+ target: options.target,
265
+ });
266
+ console.log(JSON.stringify({ message: 'ANT transfer submitted!', ...result }, null, 2));
267
+ }
268
+ export async function setArNSRecord(options, turbo) {
269
+ if (options.antId === undefined) {
270
+ throw new Error('Must provide an --ant-id to set a record on');
271
+ }
272
+ if (options.transactionId === undefined) {
273
+ throw new Error('Must provide a --transaction-id for the record');
274
+ }
275
+ const ttlSeconds = positiveIntFromOption(options.ttlSeconds, '--ttl-seconds');
276
+ const client = turbo ?? (await turboFromOptions(options));
277
+ const result = await client.setArNSRecord({
278
+ antId: options.antId,
279
+ owner: ownerFromOptions(options),
280
+ undername: options.undername ?? '@',
281
+ transactionId: options.transactionId,
282
+ ttlSeconds,
283
+ });
284
+ console.log(JSON.stringify({ message: 'ArNS record set!', ...result }, null, 2));
285
+ }
286
+ export async function removeArNSRecord(options, turbo) {
287
+ if (options.antId === undefined) {
288
+ throw new Error('Must provide an --ant-id to remove a record from');
289
+ }
290
+ if (options.undername === undefined || options.undername.length === 0) {
291
+ throw new Error('Must provide an --undername to remove');
292
+ }
293
+ const client = turbo ?? (await turboFromOptions(options));
294
+ const result = await client.removeArNSRecord({
295
+ antId: options.antId,
296
+ owner: ownerFromOptions(options),
297
+ undername: options.undername,
298
+ });
299
+ console.log(JSON.stringify({ message: 'ArNS record removed!', ...result }, null, 2));
300
+ }
@@ -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
+ }