@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.
- package/lib/cjs/cli/cli.js +61 -0
- package/lib/cjs/cli/commands/arns.js +317 -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 +124 -11
- package/lib/cjs/cli/utils.js +3 -19
- package/lib/cjs/common/arnsActions.js +102 -0
- package/lib/cjs/common/factory.js +1 -3
- package/lib/cjs/common/http.js +20 -5
- package/lib/cjs/common/index.js +6 -0
- package/lib/cjs/common/payment.js +482 -3
- package/lib/cjs/common/signer.js +27 -6
- package/lib/cjs/common/token/ario.js +104 -83
- package/lib/cjs/common/token/index.js +0 -11
- package/lib/cjs/common/token/solana.js +1 -0
- package/lib/cjs/common/turbo.js +131 -0
- package/lib/cjs/common/upload.js +3 -2
- package/lib/cjs/node/factory.js +1 -3
- package/lib/cjs/types.js +44 -3
- package/lib/cjs/utils/common.js +5 -21
- package/lib/cjs/utils/errors.js +38 -1
- package/lib/cjs/utils/uuid.js +31 -0
- package/lib/cjs/web/factory.js +1 -3
- package/lib/cjs/web/signer.js +4 -2
- package/lib/esm/cli/cli.js +63 -2
- package/lib/esm/cli/commands/arns.js +300 -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 +123 -10
- package/lib/esm/cli/utils.js +4 -20
- package/lib/esm/common/arnsActions.js +93 -0
- package/lib/esm/common/factory.js +1 -3
- package/lib/esm/common/http.js +19 -4
- package/lib/esm/common/index.js +6 -0
- package/lib/esm/common/payment.js +482 -3
- package/lib/esm/common/signer.js +28 -7
- package/lib/esm/common/token/ario.js +102 -84
- package/lib/esm/common/token/index.js +1 -12
- package/lib/esm/common/token/solana.js +1 -0
- package/lib/esm/common/turbo.js +131 -0
- package/lib/esm/common/upload.js +4 -3
- package/lib/esm/node/factory.js +1 -3
- package/lib/esm/types.js +43 -2
- package/lib/esm/utils/common.js +4 -20
- package/lib/esm/utils/errors.js +35 -0
- package/lib/esm/utils/uuid.js +28 -0
- package/lib/esm/web/factory.js +1 -3
- package/lib/esm/web/signer.js +4 -2
- package/lib/types/cli/commands/arns.d.ts +86 -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 +238 -10
- package/lib/types/cli/options.d.ts.map +1 -1
- package/lib/types/cli/types.d.ts +41 -2
- package/lib/types/cli/types.d.ts.map +1 -1
- package/lib/types/cli/utils.d.ts.map +1 -1
- package/lib/types/common/arnsActions.d.ts +43 -0
- package/lib/types/common/arnsActions.d.ts.map +1 -0
- package/lib/types/common/factory.d.ts +1 -1
- package/lib/types/common/factory.d.ts.map +1 -1
- package/lib/types/common/http.d.ts +14 -1
- package/lib/types/common/http.d.ts.map +1 -1
- package/lib/types/common/index.d.ts +2 -0
- package/lib/types/common/index.d.ts.map +1 -1
- package/lib/types/common/payment.d.ts +230 -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/ario.d.ts +13 -9
- package/lib/types/common/token/ario.d.ts.map +1 -1
- package/lib/types/common/token/index.d.ts.map +1 -1
- package/lib/types/common/token/solana.d.ts.map +1 -1
- package/lib/types/common/turbo.d.ts +140 -1
- package/lib/types/common/turbo.d.ts.map +1 -1
- package/lib/types/common/upload.d.ts.map +1 -1
- package/lib/types/node/factory.d.ts +1 -1
- package/lib/types/node/factory.d.ts.map +1 -1
- package/lib/types/types.d.ts +483 -7
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/utils/common.d.ts +0 -12
- 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/uuid.d.ts +7 -0
- package/lib/types/utils/uuid.d.ts.map +1 -0
- package/lib/types/web/factory.d.ts +1 -1
- package/lib/types/web/factory.d.ts.map +1 -1
- package/lib/types/web/signer.d.ts +1 -1
- package/lib/types/web/signer.d.ts.map +1 -1
- package/package.json +3 -2
package/lib/cjs/cli/utils.js
CHANGED
|
@@ -124,7 +124,9 @@ async function privateKeyFromOptions({ mnemonic, privateKey, walletFile, token,
|
|
|
124
124
|
}
|
|
125
125
|
else if (walletFile !== undefined) {
|
|
126
126
|
const wallet = JSON.parse((0, fs_1.readFileSync)(walletFile, 'utf-8'));
|
|
127
|
-
return token === 'solana'
|
|
127
|
+
return token === 'solana' || token === 'ario'
|
|
128
|
+
? bs58_1.default.encode(wallet)
|
|
129
|
+
: wallet;
|
|
128
130
|
}
|
|
129
131
|
else if (privateKey !== undefined) {
|
|
130
132
|
return privateKey;
|
|
@@ -138,8 +140,6 @@ function configFromOptions(options) {
|
|
|
138
140
|
let paymentUrl = undefined;
|
|
139
141
|
let uploadUrl = undefined;
|
|
140
142
|
let gatewayUrl = undefined;
|
|
141
|
-
let processId = undefined;
|
|
142
|
-
let cuUrl = undefined;
|
|
143
143
|
if (options.local && options.dev) {
|
|
144
144
|
throw new Error('Cannot use both --local and --dev flags');
|
|
145
145
|
}
|
|
@@ -148,10 +148,6 @@ function configFromOptions(options) {
|
|
|
148
148
|
paymentUrl = index_js_1.developmentTurboConfiguration.paymentServiceConfig.url;
|
|
149
149
|
uploadUrl = index_js_1.developmentTurboConfiguration.uploadServiceConfig.url;
|
|
150
150
|
gatewayUrl = common_js_1.tokenToDevGatewayMap[token];
|
|
151
|
-
if (options.token === 'ario') {
|
|
152
|
-
processId = common_js_1.tokenToDevAoConfigMap[token].processId;
|
|
153
|
-
cuUrl = common_js_1.tokenToDevAoConfigMap[token].cuUrl;
|
|
154
|
-
}
|
|
155
151
|
}
|
|
156
152
|
else if (options.local) {
|
|
157
153
|
// Use local endpoints
|
|
@@ -163,10 +159,6 @@ function configFromOptions(options) {
|
|
|
163
159
|
// Use default endpoints
|
|
164
160
|
paymentUrl = index_js_1.defaultTurboConfiguration.paymentServiceConfig.url;
|
|
165
161
|
uploadUrl = index_js_1.defaultTurboConfiguration.uploadServiceConfig.url;
|
|
166
|
-
if (options.token === 'ario') {
|
|
167
|
-
processId = common_js_1.defaultProdAoConfigs[token].processId;
|
|
168
|
-
cuUrl = common_js_1.defaultProdAoConfigs[token].cuUrl;
|
|
169
|
-
}
|
|
170
162
|
}
|
|
171
163
|
// Override gateway, payment, and upload service default endpoints if provided
|
|
172
164
|
if (options.gateway !== undefined) {
|
|
@@ -178,19 +170,11 @@ function configFromOptions(options) {
|
|
|
178
170
|
if (options.uploadUrl !== undefined) {
|
|
179
171
|
uploadUrl = options.uploadUrl;
|
|
180
172
|
}
|
|
181
|
-
if (options.cuUrl !== undefined) {
|
|
182
|
-
cuUrl = options.cuUrl;
|
|
183
|
-
}
|
|
184
|
-
if (options.processId !== undefined) {
|
|
185
|
-
processId = options.processId;
|
|
186
|
-
}
|
|
187
173
|
const config = {
|
|
188
174
|
paymentServiceConfig: { url: paymentUrl },
|
|
189
175
|
uploadServiceConfig: { url: uploadUrl },
|
|
190
176
|
gatewayUrl,
|
|
191
177
|
token,
|
|
192
|
-
processId,
|
|
193
|
-
cuUrl,
|
|
194
178
|
};
|
|
195
179
|
return config;
|
|
196
180
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildArNSCustodyMessage = buildArNSCustodyMessage;
|
|
7
|
+
exports.arNSOwnerProofHeaders = arNSOwnerProofHeaders;
|
|
8
|
+
exports.solanaOwnerSigner = solanaOwnerSigner;
|
|
9
|
+
exports.emptySignatureSlots = emptySignatureSlots;
|
|
10
|
+
/**
|
|
11
|
+
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
12
|
+
*
|
|
13
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
* you may not use this file except in compliance with the License.
|
|
15
|
+
* You may obtain a copy of the License at
|
|
16
|
+
*
|
|
17
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
*
|
|
19
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
* See the License for the specific language governing permissions and
|
|
23
|
+
* limitations under the License.
|
|
24
|
+
*/
|
|
25
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
26
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
27
|
+
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
28
|
+
const base64_js_1 = require("../utils/base64.js");
|
|
29
|
+
/**
|
|
30
|
+
* Canonical ACTION-BOUND message for the owner proof.
|
|
31
|
+
*
|
|
32
|
+
* MUST match the bundler's `buildArNSCustodyMessage` byte for byte
|
|
33
|
+
* (newline-delimited) or every signature is rejected. The bundler rebuilds this
|
|
34
|
+
* from the request and verifies the signature over `message + nonce`, so a
|
|
35
|
+
* signature captured for one operation cannot authorize a different one, and
|
|
36
|
+
* the nonce is consumed on use so the same one cannot be replayed (e.g. to
|
|
37
|
+
* revert a record to an older value).
|
|
38
|
+
*/
|
|
39
|
+
function buildArNSCustodyMessage(action, fields) {
|
|
40
|
+
return ['arns', action, ...fields].join('\n');
|
|
41
|
+
}
|
|
42
|
+
/** Solana's signature-type discriminator in Turbo's signed-request scheme. */
|
|
43
|
+
const SOLANA_SIGNATURE_TYPE = 4;
|
|
44
|
+
/**
|
|
45
|
+
* The ANT owner's half of the envelope, in its own `x-owner-*` headers.
|
|
46
|
+
*
|
|
47
|
+
* Two signatures travel on a record action — the PAYER's signed request over
|
|
48
|
+
* `"" + nonce`, and the OWNER's action-bound proof over `message + nonce` —
|
|
49
|
+
* from two different keys, usually on two different chains. They cannot share
|
|
50
|
+
* one header set: whichever verifier ran second would reject a signature that
|
|
51
|
+
* was never meant for it.
|
|
52
|
+
*/
|
|
53
|
+
async function arNSOwnerProofHeaders(owner, message, nonce) {
|
|
54
|
+
const address = await owner.getAddress();
|
|
55
|
+
const signature = await owner.signMessage(Uint8Array.from(Buffer.from(message + nonce)));
|
|
56
|
+
return {
|
|
57
|
+
// A Solana address IS the base58-encoded 32-byte ed25519 public key, so
|
|
58
|
+
// decoding the address recovers exactly the bytes the bundler verifies
|
|
59
|
+
// against. Keeps ArNSOwnerSigner minimal — no separate getPublicKey().
|
|
60
|
+
'x-owner-public-key': (0, base64_js_1.toB64Url)(Buffer.from(bs58_1.default.decode(address))),
|
|
61
|
+
'x-owner-nonce': nonce,
|
|
62
|
+
'x-owner-signature': (0, base64_js_1.toB64Url)(Buffer.from(signature)),
|
|
63
|
+
'x-owner-signature-type': String(SOLANA_SIGNATURE_TYPE),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build an {@link ArNSOwnerSigner} from a raw Solana secret key.
|
|
68
|
+
*
|
|
69
|
+
* For servers and tests. A browser wallet (Phantom, Solflare, or a console's
|
|
70
|
+
* embedded wallet) should implement the interface directly against its own
|
|
71
|
+
* `signTransaction` / `signMessage` rather than exposing a secret key.
|
|
72
|
+
*
|
|
73
|
+
* Note the owner needs a key to SIGN with, not a funded account: Turbo is the
|
|
74
|
+
* fee payer on every sponsored action, so this wallet's SOL balance can stay
|
|
75
|
+
* at zero for the entire life of the name.
|
|
76
|
+
*/
|
|
77
|
+
function solanaOwnerSigner(secretKey) {
|
|
78
|
+
const keypair = web3_js_1.Keypair.fromSecretKey(typeof secretKey === 'string' ? bs58_1.default.decode(secretKey) : secretKey);
|
|
79
|
+
return {
|
|
80
|
+
getAddress: () => keypair.publicKey.toBase58(),
|
|
81
|
+
signTransaction: async (transactionBase64) => {
|
|
82
|
+
const tx = web3_js_1.VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64'));
|
|
83
|
+
// Sign the bytes as returned. Turbo's fee-payer signature already covers
|
|
84
|
+
// this exact message; rebuilding it from parts invalidates that and the
|
|
85
|
+
// submission is rejected.
|
|
86
|
+
tx.sign([keypair]);
|
|
87
|
+
return Buffer.from(tx.serialize()).toString('base64');
|
|
88
|
+
},
|
|
89
|
+
signMessage: async (message) => tweetnacl_1.default.sign.detached(message, keypair.secretKey),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Count the signature slots a prepared transaction still has empty.
|
|
94
|
+
*
|
|
95
|
+
* Turbo pre-signs as fee payer and leaves exactly one slot for the owner, so a
|
|
96
|
+
* client can assert that before prompting a wallet — a cheap way to catch a
|
|
97
|
+
* malformed or already-signed transaction before bothering the user.
|
|
98
|
+
*/
|
|
99
|
+
function emptySignatureSlots(transactionBase64) {
|
|
100
|
+
const tx = web3_js_1.VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64'));
|
|
101
|
+
return tx.signatures.filter((sig) => sig.every((byte) => byte === 0)).length;
|
|
102
|
+
}
|
|
@@ -46,7 +46,7 @@ class TurboBaseFactory {
|
|
|
46
46
|
paymentService,
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
getAuthenticatedTurbo({ privateKey, signer: providedSigner, paymentServiceConfig = {}, uploadServiceConfig = {}, token, gatewayUrl, tokenMap, tokenTools, logger, walletAdapter,
|
|
49
|
+
getAuthenticatedTurbo({ privateKey, signer: providedSigner, paymentServiceConfig = {}, uploadServiceConfig = {}, token, gatewayUrl, tokenMap, tokenTools, logger, walletAdapter, }) {
|
|
50
50
|
token = token === 'pol' ? 'matic' : token;
|
|
51
51
|
if (!token) {
|
|
52
52
|
if (providedSigner) {
|
|
@@ -104,8 +104,6 @@ class TurboBaseFactory {
|
|
|
104
104
|
tokenTools = tokenMap.arweave;
|
|
105
105
|
}
|
|
106
106
|
tokenTools = index_js_1.defaultTokenMap[token]?.({
|
|
107
|
-
cuUrl,
|
|
108
|
-
processId,
|
|
109
107
|
gatewayUrl,
|
|
110
108
|
logger,
|
|
111
109
|
});
|
package/lib/cjs/common/http.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TurboHTTPService = exports.defaultRetryConfig = void 0;
|
|
3
|
+
exports.TurboHTTPService = exports.x402UploadEndpoints = exports.defaultRetryConfig = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
6
6
|
*
|
|
@@ -34,6 +34,18 @@ const defaultHeaders = {
|
|
|
34
34
|
'x-turbo-source-version': version_js_1.version,
|
|
35
35
|
'x-turbo-source-identifier': 'turbo-sdk',
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Canonical x402 upload routes on the upload service.
|
|
39
|
+
*
|
|
40
|
+
* These were previously `/x402/data-item/{signed,unsigned}`. The service
|
|
41
|
+
* renamed them to `/x402/upload/*` and kept a `data-item/signed` alias, but not
|
|
42
|
+
* a `data-item/unsigned` one — so every unsigned x402 upload 404ed. Both
|
|
43
|
+
* canonical paths are served by all released upload-service versions.
|
|
44
|
+
*/
|
|
45
|
+
exports.x402UploadEndpoints = {
|
|
46
|
+
signed: '/x402/upload/signed',
|
|
47
|
+
unsigned: '/x402/upload/unsigned',
|
|
48
|
+
};
|
|
37
49
|
class TurboHTTPService {
|
|
38
50
|
constructor({ url, logger, retryConfig = (0, exports.defaultRetryConfig)(logger), }) {
|
|
39
51
|
this.logger = logger;
|
|
@@ -47,7 +59,7 @@ class TurboHTTPService {
|
|
|
47
59
|
signal,
|
|
48
60
|
}), allowedStatuses);
|
|
49
61
|
}
|
|
50
|
-
async post({ endpoint, signal, allowedStatuses = [200, 202], headers, data, x402Options, }) {
|
|
62
|
+
async post({ endpoint, signal, allowedStatuses = [200, 202], headers, data, x402Options, retry = true, }) {
|
|
51
63
|
if (x402Options !== undefined) {
|
|
52
64
|
return this.x402Post({
|
|
53
65
|
signal,
|
|
@@ -59,9 +71,10 @@ class TurboHTTPService {
|
|
|
59
71
|
}
|
|
60
72
|
// Convert all data types to fetch-compatible body
|
|
61
73
|
const { body, duplex } = await toFetchBody(data);
|
|
62
|
-
// Use retry for Buffer/Uint8Array, tryRequest for streams
|
|
74
|
+
// Use retry for Buffer/Uint8Array, tryRequest for streams. Callers can opt
|
|
75
|
+
// out of retry for non-idempotent signed writes via `retry: false`.
|
|
63
76
|
const isReusableData = data instanceof Buffer || data instanceof Uint8Array;
|
|
64
|
-
const requestFn = isReusableData
|
|
77
|
+
const requestFn = isReusableData && retry
|
|
65
78
|
? this.withRetry.bind(this)
|
|
66
79
|
: this.tryRequest.bind(this);
|
|
67
80
|
return requestFn(() => fetch(this.baseURL + endpoint, {
|
|
@@ -123,7 +136,9 @@ class TurboHTTPService {
|
|
|
123
136
|
throw new errors_js_1.FailedRequestError('Max retries reached - ' + lastError?.message, lastError?.status);
|
|
124
137
|
}
|
|
125
138
|
async x402Post({ signal, allowedStatuses, headers, data, x402Options, }) {
|
|
126
|
-
const endpoint =
|
|
139
|
+
const endpoint = x402Options.unsignedData
|
|
140
|
+
? exports.x402UploadEndpoints.unsigned
|
|
141
|
+
: exports.x402UploadEndpoints.signed;
|
|
127
142
|
this.logger.debug('Using X402 options for POST request', {
|
|
128
143
|
endpoint,
|
|
129
144
|
x402Options,
|
package/lib/cjs/common/index.js
CHANGED
|
@@ -31,6 +31,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
31
31
|
*/
|
|
32
32
|
__exportStar(require("./upload.js"), exports);
|
|
33
33
|
__exportStar(require("./payment.js"), exports);
|
|
34
|
+
// The ANT-owner helpers. Without this the documented
|
|
35
|
+
// `import { solanaOwnerSigner } from '@ardrive/turbo-sdk'` does not resolve.
|
|
36
|
+
__exportStar(require("./arnsActions.js"), exports);
|
|
34
37
|
__exportStar(require("./turbo.js"), exports);
|
|
35
38
|
__exportStar(require("./currency.js"), exports);
|
|
36
39
|
__exportStar(require("./token/index.js"), exports);
|
|
40
|
+
// Typed errors so consumers can `catch (e) { if (e instanceof InsufficientCreditsError) ... }`
|
|
41
|
+
// e.g. to prompt a top-up on a 402 ArNS purchase.
|
|
42
|
+
__exportStar(require("../utils/errors.js"), exports);
|