@ardrive/turbo-sdk 1.36.0 → 1.37.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.
Files changed (72) hide show
  1. package/README.md +15 -0
  2. package/bundles/web.bundle.min.js +172510 -144495
  3. package/lib/cjs/cli/options.js +6 -0
  4. package/lib/cjs/cli/utils.js +9 -1
  5. package/lib/cjs/common/chunked.js +1 -1
  6. package/lib/cjs/common/factory.js +2 -6
  7. package/lib/cjs/common/http.js +118 -1
  8. package/lib/cjs/common/logger.js +50 -59
  9. package/lib/cjs/common/payment.js +2 -2
  10. package/lib/cjs/common/signer.js +36 -1
  11. package/lib/cjs/common/token/ario.js +1 -1
  12. package/lib/cjs/common/token/arweave.js +1 -1
  13. package/lib/cjs/common/token/erc20.js +1 -1
  14. package/lib/cjs/common/token/ethereum.js +1 -1
  15. package/lib/cjs/common/token/kyve.js +1 -1
  16. package/lib/cjs/common/token/polygon.js +1 -1
  17. package/lib/cjs/common/token/solana.js +1 -1
  18. package/lib/cjs/common/upload.js +25 -3
  19. package/lib/cjs/common/winstonLogger.js +66 -0
  20. package/lib/cjs/types.js +9 -1
  21. package/lib/cjs/utils/axiosClient.js +1 -1
  22. package/lib/cjs/version.js +1 -1
  23. package/lib/esm/cli/options.js +6 -0
  24. package/lib/esm/cli/utils.js +10 -2
  25. package/lib/esm/common/chunked.js +2 -2
  26. package/lib/esm/common/factory.js +3 -7
  27. package/lib/esm/common/http.js +117 -1
  28. package/lib/esm/common/logger.js +48 -57
  29. package/lib/esm/common/payment.js +3 -3
  30. package/lib/esm/common/signer.js +36 -2
  31. package/lib/esm/common/token/ario.js +2 -2
  32. package/lib/esm/common/token/arweave.js +2 -2
  33. package/lib/esm/common/token/erc20.js +2 -2
  34. package/lib/esm/common/token/ethereum.js +2 -2
  35. package/lib/esm/common/token/kyve.js +2 -2
  36. package/lib/esm/common/token/polygon.js +2 -2
  37. package/lib/esm/common/token/solana.js +2 -2
  38. package/lib/esm/common/upload.js +27 -5
  39. package/lib/esm/common/winstonLogger.js +62 -0
  40. package/lib/esm/types.js +7 -0
  41. package/lib/esm/utils/axiosClient.js +2 -2
  42. package/lib/esm/version.js +1 -1
  43. package/lib/types/cli/options.d.ts +17 -0
  44. package/lib/types/cli/options.d.ts.map +1 -1
  45. package/lib/types/cli/types.d.ts +1 -0
  46. package/lib/types/cli/types.d.ts.map +1 -1
  47. package/lib/types/cli/utils.d.ts.map +1 -1
  48. package/lib/types/common/chunked.d.ts.map +1 -1
  49. package/lib/types/common/factory.d.ts +4 -5
  50. package/lib/types/common/factory.d.ts.map +1 -1
  51. package/lib/types/common/http.d.ts +10 -2
  52. package/lib/types/common/http.d.ts.map +1 -1
  53. package/lib/types/common/logger.d.ts +17 -26
  54. package/lib/types/common/logger.d.ts.map +1 -1
  55. package/lib/types/common/payment.d.ts.map +1 -1
  56. package/lib/types/common/signer.d.ts +3 -0
  57. package/lib/types/common/signer.d.ts.map +1 -1
  58. package/lib/types/common/token/ario.d.ts.map +1 -1
  59. package/lib/types/common/token/arweave.d.ts.map +1 -1
  60. package/lib/types/common/token/erc20.d.ts.map +1 -1
  61. package/lib/types/common/token/ethereum.d.ts.map +1 -1
  62. package/lib/types/common/token/kyve.d.ts.map +1 -1
  63. package/lib/types/common/token/polygon.d.ts.map +1 -1
  64. package/lib/types/common/token/solana.d.ts.map +1 -1
  65. package/lib/types/common/upload.d.ts +2 -1
  66. package/lib/types/common/upload.d.ts.map +1 -1
  67. package/lib/types/common/winstonLogger.d.ts +14 -0
  68. package/lib/types/common/winstonLogger.d.ts.map +1 -0
  69. package/lib/types/types.d.ts +24 -12
  70. package/lib/types/types.d.ts.map +1 -1
  71. package/lib/types/version.d.ts +1 -1
  72. package/package.json +9 -1
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TurboWinstonLogger = void 0;
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 version_js_1 = require("../version.js");
20
+ class TurboWinstonLogger {
21
+ constructor({ level = 'info', } = {}) {
22
+ try {
23
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
24
+ this.winston = require('winston');
25
+ }
26
+ catch (error) {
27
+ throw new Error('Winston is not installed. Install it with: npm install winston');
28
+ }
29
+ this.logger = this.winston.createLogger({
30
+ level: level === 'none' ? 'error' : level,
31
+ silent: level === 'none',
32
+ defaultMeta: {
33
+ name: 'ar-io-sdk',
34
+ version: version_js_1.version,
35
+ },
36
+ format: this.winston.format.combine(this.winston.format.timestamp(), this.winston.format.json()),
37
+ transports: [
38
+ new this.winston.transports.Console({
39
+ format: this.winston.format.combine(this.winston.format.timestamp(), this.winston.format.json()),
40
+ }),
41
+ ],
42
+ });
43
+ }
44
+ info(message, ...args) {
45
+ this.logger.info(message, ...args);
46
+ }
47
+ warn(message, ...args) {
48
+ this.logger.warn(message, ...args);
49
+ }
50
+ error(message, ...args) {
51
+ this.logger.error(message, ...args);
52
+ }
53
+ debug(message, ...args) {
54
+ this.logger.debug(message, ...args);
55
+ }
56
+ setLogLevel(level) {
57
+ if (level === 'none') {
58
+ this.logger.silent = true;
59
+ }
60
+ else {
61
+ this.logger.silent = false;
62
+ this.logger.level = level;
63
+ }
64
+ }
65
+ }
66
+ exports.TurboWinstonLogger = TurboWinstonLogger;
package/lib/cjs/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validChunkingModes = exports.isJWK = exports.isWebUploadFolderParams = exports.isNodeUploadFolderParams = exports.multipartFinalizedStatus = exports.multipartFailedStatus = exports.multipartPendingStatus = exports.OnDemandFunding = exports.ExistingBalanceFunding = exports.supportedEvmSignerTokens = exports.tokenTypes = exports.fiatCurrencyTypes = void 0;
3
+ exports.validChunkingModes = exports.isJWK = exports.isWebUploadFolderParams = exports.isNodeUploadFolderParams = exports.multipartFinalizedStatus = exports.multipartFailedStatus = exports.multipartPendingStatus = exports.X402Funding = exports.OnDemandFunding = exports.ExistingBalanceFunding = exports.supportedEvmSignerTokens = exports.tokenTypes = exports.fiatCurrencyTypes = void 0;
4
4
  exports.isCurrency = isCurrency;
5
5
  exports.isKyvePrivateKey = isKyvePrivateKey;
6
6
  exports.isEthPrivateKey = isEthPrivateKey;
@@ -62,6 +62,14 @@ class OnDemandFunding {
62
62
  }
63
63
  }
64
64
  exports.OnDemandFunding = OnDemandFunding;
65
+ class X402Funding {
66
+ constructor({ signer, maxMUSDCAmount, }) {
67
+ this.signer = signer;
68
+ this.maxMUSDCAmount =
69
+ maxMUSDCAmount !== undefined ? new bignumber_js_1.BigNumber(maxMUSDCAmount) : undefined;
70
+ }
71
+ }
72
+ exports.X402Funding = X402Funding;
65
73
  exports.multipartPendingStatus = [
66
74
  'ASSEMBLING',
67
75
  'VALIDATING',
@@ -26,7 +26,7 @@ exports.defaultRequestHeaders = {
26
26
  'x-turbo-source-version': version_js_1.version,
27
27
  'x-turbo-source-identifier': 'turbo-sdk',
28
28
  };
29
- const defaultRetryConfig = (logger = logger_js_1.TurboWinstonLogger.default) => ({
29
+ const defaultRetryConfig = (logger = logger_js_1.Logger.default) => ({
30
30
  retryDelay: (retryCount) => Math.min(1000 * 2 ** (retryCount - 1), 30 * 1000), // exponential backoff up to 30s
31
31
  retries: 5,
32
32
  onRetry: (retryCount, error) => {
@@ -17,4 +17,4 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.version = void 0;
19
19
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
20
- exports.version = '1.36.0';
20
+ exports.version = '1.37.0-alpha.2';
@@ -183,6 +183,11 @@ export const optionMap = {
183
183
  description: 'Enable on-demand crypto top-ups during upload if balance is insufficient',
184
184
  default: false,
185
185
  },
186
+ x402: {
187
+ alias: '--x402',
188
+ description: 'Pay for the action using x402 funding (if available). Requires token `base-usdc`.',
189
+ default: false,
190
+ },
186
191
  topUpBufferMultiplier: {
187
192
  alias: '--top-up-buffer-multiplier <topUpBufferMultiplier>',
188
193
  description: 'Multiplier to apply to the estimated top-up amount to avoid underpayment during on-demand top-ups. Defaults to 1.1 (10% buffer).',
@@ -212,6 +217,7 @@ const onDemandOptions = [
212
217
  optionMap.onDemand,
213
218
  optionMap.topUpBufferMultiplier,
214
219
  optionMap.maxCryptoTopUpValue,
220
+ optionMap.x402,
215
221
  ];
216
222
  export const uploadOptions = [
217
223
  ...walletOptions,
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import bs58 from 'bs58';
17
17
  import { readFileSync, statSync } from 'fs';
18
- import { ExistingBalanceFunding, OnDemandFunding, TurboFactory, defaultTurboConfiguration, developmentTurboConfiguration, fiatCurrencyTypes, isCurrency, isTokenType, privateKeyFromKyveMnemonic, tokenToBaseMap, } from '../node/index.js';
18
+ import { ExistingBalanceFunding, OnDemandFunding, TurboFactory, X402Funding, defaultTurboConfiguration, developmentTurboConfiguration, fiatCurrencyTypes, isCurrency, isTokenType, privateKeyFromKyveMnemonic, tokenToBaseMap, } from '../node/index.js';
19
19
  import { defaultProdAoConfigs, tokenToDevAoConfigMap, tokenToDevGatewayMap, } from '../utils/common.js';
20
20
  import { NoWalletProvidedError } from './errors.js';
21
21
  export function exitWithErrorLog(error) {
@@ -246,7 +246,10 @@ export function getTagsFromOptions(options) {
246
246
  return parseTags(options.tags);
247
247
  }
248
248
  export function onDemandOptionsFromOptions(options) {
249
- if (!options.onDemand) {
249
+ if (options.x402 && options.onDemand) {
250
+ throw new Error('Cannot use both --x402 and --on-demand flags');
251
+ }
252
+ if (!options.onDemand && !options.x402) {
250
253
  return { fundingMode: new ExistingBalanceFunding() };
251
254
  }
252
255
  const value = options.maxCryptoTopUpValue;
@@ -258,6 +261,11 @@ export function onDemandOptionsFromOptions(options) {
258
261
  const token = tokenFromOptions(options);
259
262
  maxTokenAmount = tokenToBaseMap[token](value).toString();
260
263
  }
264
+ if (options.x402) {
265
+ return {
266
+ fundingMode: new X402Funding({ maxMUSDCAmount: maxTokenAmount }),
267
+ };
268
+ }
261
269
  if (options.topUpBufferMultiplier !== undefined &&
262
270
  (isNaN(options.topUpBufferMultiplier) || options.topUpBufferMultiplier < 1)) {
263
271
  throw new Error('topUpBufferMultiplier must be a number >= 1');
@@ -19,7 +19,7 @@ import { multipartFailedStatus, validChunkingModes, } from '../types.js';
19
19
  import { sleep } from '../utils/common.js';
20
20
  import { FailedRequestError } from '../utils/errors.js';
21
21
  import { TurboEventEmitter, createStreamWithUploadEvents } from './events.js';
22
- import { TurboWinstonLogger } from './logger.js';
22
+ import { Logger } from './logger.js';
23
23
  const fiveMiB = 5 * 1024 * 1024; // 5 MiB
24
24
  const fiveHundredMiB = fiveMiB * 100; // 500 MiB
25
25
  export const defaultMaxChunkConcurrency = 5;
@@ -35,7 +35,7 @@ const chunkingHeader = { 'x-chunking-version': '2' };
35
35
  * uploading them in parallel, and emitting progress/error events.
36
36
  */
37
37
  export class ChunkedUploader {
38
- constructor({ http, token, maxChunkConcurrency = defaultMaxChunkConcurrency, maxFinalizeMs, chunkByteCount = defaultChunkByteCount, logger = TurboWinstonLogger.default, chunkingMode = 'auto', dataItemByteCount, }) {
38
+ constructor({ http, token, maxChunkConcurrency = defaultMaxChunkConcurrency, maxFinalizeMs, chunkByteCount = defaultChunkByteCount, logger = Logger.default, chunkingMode = 'auto', dataItemByteCount, }) {
39
39
  this.assertChunkParams({
40
40
  chunkByteCount,
41
41
  chunkingMode,
@@ -15,20 +15,16 @@
15
15
  */
16
16
  import { HexInjectedSolanaSigner, InjectedEthereumSigner, SignatureConfig, } from '@dha-team/arbundles';
17
17
  import { isEthereumWalletAdapter, isSolanaWalletAdapter, supportedEvmSignerTokens, } from '../types.js';
18
- import { TurboWinstonLogger } from './logger.js';
18
+ import { Logger } from './logger.js';
19
19
  import { TurboAuthenticatedPaymentService, TurboUnauthenticatedPaymentService, } from './payment.js';
20
20
  import { defaultTokenMap } from './token/index.js';
21
21
  import { TurboAuthenticatedClient, TurboUnauthenticatedClient, } from './turbo.js';
22
22
  import { TurboUnauthenticatedUploadService } from './upload.js';
23
23
  export class TurboBaseFactory {
24
- /* @deprecated - use TurboWinstonLogger directly */
24
+ /* @deprecated - use Logger directly */
25
25
  static setLogLevel(level) {
26
26
  this.logger.setLogLevel(level);
27
27
  }
28
- /* @deprecated - use TurboWinstonLogger directly */
29
- static setLogFormat(format) {
30
- this.logger.setLogFormat(format);
31
- }
32
28
  static unauthenticated({ paymentServiceConfig = {}, uploadServiceConfig = {}, token, } = {}) {
33
29
  token = token === 'pol' ? 'matic' : token;
34
30
  token ??= 'arweave'; // default to arweave if token is not provided
@@ -147,4 +143,4 @@ export class TurboBaseFactory {
147
143
  throw new Error('Unsupported wallet adapter -- wallet adapter is currently only supported for Solana and Ethereum');
148
144
  }
149
145
  }
150
- TurboBaseFactory.logger = TurboWinstonLogger.default;
146
+ TurboBaseFactory.logger = Logger.default;
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { AxiosError, CanceledError } from 'axios';
17
17
  import { Readable } from 'node:stream';
18
+ import { wrapFetchWithPayment } from 'x402-fetch';
18
19
  import { createAxiosInstance, defaultRetryConfig, } from '../utils/axiosClient.js';
19
20
  import { sleep } from '../utils/common.js';
20
21
  import { FailedRequestError } from '../utils/errors.js';
@@ -33,7 +34,46 @@ export class TurboHTTPService {
33
34
  async get({ endpoint, signal, allowedStatuses = [200, 202], headers, }) {
34
35
  return this.retryRequest(() => this.axios.get(endpoint, { headers, signal }), allowedStatuses);
35
36
  }
36
- async post({ endpoint, signal, allowedStatuses = [200, 202], headers, data, }) {
37
+ async post({ endpoint, signal, allowedStatuses = [200, 202], headers, data, x402Options, }) {
38
+ if (x402Options !== undefined) {
39
+ this.logger.debug('Using X402 options for POST request', {
40
+ endpoint,
41
+ x402Options,
42
+ });
43
+ const { body, duplex } = await toX402FetchBody(data);
44
+ try {
45
+ const maxMUSDCAmount = x402Options.maxMUSDCAmount !== undefined
46
+ ? BigInt(x402Options.maxMUSDCAmount.toString())
47
+ : undefined;
48
+ const fetchWithPay = wrapFetchWithPayment(fetch, x402Options.signer, maxMUSDCAmount);
49
+ const res = await fetchWithPay(this.axios.defaults.baseURL + '/x402/data-item/signed', {
50
+ method: 'POST',
51
+ headers,
52
+ body,
53
+ signal,
54
+ ...(duplex ? { duplex } : {}), // Use duplex only where streams are working
55
+ });
56
+ if (!allowedStatuses.includes(res.status)) {
57
+ const errorText = await res.text();
58
+ throw new FailedRequestError(
59
+ // Return error message from server if available
60
+ errorText || res.statusText, res.status);
61
+ }
62
+ return res.json();
63
+ }
64
+ catch (error) {
65
+ if (error instanceof FailedRequestError) {
66
+ throw error; // rethrow FailedRequestError
67
+ }
68
+ // Handle CanceledError specifically
69
+ if (error.message.includes('The operation was aborted')) {
70
+ throw new CanceledError();
71
+ }
72
+ // Log the error and throw a FailedRequestError
73
+ this.logger.error('Error posting data', { endpoint, error });
74
+ throw new FailedRequestError(error instanceof Error ? error.message : 'Unknown error', error.response?.status);
75
+ }
76
+ }
37
77
  // Buffer and Readable → keep Axios (streams work fine there)
38
78
  if (!(data instanceof ReadableStream)) {
39
79
  if (data instanceof Readable) {
@@ -137,3 +177,79 @@ async function toFetchBody(data) {
137
177
  const blob = await new Response(data).blob();
138
178
  return { body: blob }; // browser sets length
139
179
  }
180
+ const isNode = typeof process !== 'undefined' && !!process.versions?.node;
181
+ const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
182
+ function isFirefoxOrSafari() {
183
+ if (!isBrowser)
184
+ return false;
185
+ const ua = navigator.userAgent;
186
+ return ua.includes('Firefox') || ua.includes('Safari');
187
+ }
188
+ /** Create a re-usable body for x402 fetch protocol */
189
+ export async function toX402FetchBody(data) {
190
+ //
191
+ // 🔹 NODE: always buffer to a non-stream body (Buffer)
192
+ // so fetchWithPayment can reuse it safely.
193
+ //
194
+ if (isNode) {
195
+ let buf;
196
+ // Web ReadableStream → Buffer
197
+ if (typeof ReadableStream !== 'undefined' &&
198
+ data instanceof ReadableStream) {
199
+ const ab = await new Response(data).arrayBuffer();
200
+ buf = Buffer.from(ab);
201
+ }
202
+ // Node Readable → Buffer
203
+ else if (data instanceof Readable) {
204
+ const chunks = [];
205
+ for await (const chunk of data) {
206
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
207
+ }
208
+ buf = Buffer.concat(chunks.map((c) => Uint8Array.from(c)));
209
+ }
210
+ // Buffer / Uint8Array
211
+ else if (Buffer.isBuffer(data)) {
212
+ buf = data;
213
+ }
214
+ else if (data instanceof Uint8Array) {
215
+ buf = Buffer.from(data);
216
+ }
217
+ else {
218
+ throw new Error('Unsupported body type for toFetchBody (Node)');
219
+ }
220
+ // For Buffer body, Node *does not* need duplex.
221
+ return { body: buf };
222
+ }
223
+ //
224
+ // 🔹 BROWSER: keep your previous behavior (streams/Blob), no duplex.
225
+ //
226
+ let body;
227
+ // Already a web ReadableStream
228
+ if (typeof ReadableStream !== 'undefined' && data instanceof ReadableStream) {
229
+ body = data;
230
+ }
231
+ // Node Readable in browser (rare, but be safe) → Blob
232
+ else if (data instanceof Readable) {
233
+ const chunks = [];
234
+ for await (const chunk of data) {
235
+ const buf = typeof chunk === 'string'
236
+ ? new TextEncoder().encode(chunk)
237
+ : new Uint8Array(chunk);
238
+ chunks.push(buf);
239
+ }
240
+ body = new Blob(chunks);
241
+ }
242
+ // Buffer / Uint8Array
243
+ else if (Buffer.isBuffer(data) || data instanceof Uint8Array) {
244
+ body = new Blob([Uint8Array.from(data)]);
245
+ }
246
+ else {
247
+ throw new Error('Unsupported body type for toFetchBody (browser)');
248
+ }
249
+ // Firefox / Safari – avoid streaming uploads
250
+ if (isFirefoxOrSafari() && body instanceof ReadableStream) {
251
+ const blob = await new Response(body).blob();
252
+ return { body: blob };
253
+ }
254
+ return { body };
255
+ }
@@ -13,76 +13,67 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { createLogger, format, transports, } from 'winston';
17
16
  import { version } from '../version.js';
18
- export class TurboWinstonLogger {
19
- constructor({ level = 'info', logFormat = 'simple', } = {}) {
20
- this.silent = false;
21
- if (level === 'none') {
22
- this.silent = true;
17
+ export class Logger {
18
+ constructor({ level = 'info', } = {}) {
19
+ this.level = 'info';
20
+ this.levels = {
21
+ debug: 0,
22
+ info: 1,
23
+ warn: 2,
24
+ error: 3,
25
+ none: 999,
26
+ };
27
+ this.level = level;
28
+ }
29
+ formatMessage(level, message, ...args) {
30
+ const timestamp = new Date().toISOString();
31
+ const meta = {
32
+ timestamp,
33
+ level,
34
+ message,
35
+ name: 'turbo-sdk',
36
+ version,
37
+ };
38
+ if (args.length > 0) {
39
+ return JSON.stringify({ ...meta, args });
23
40
  }
24
- if (typeof window !== 'undefined') {
25
- this.logger = console;
41
+ return JSON.stringify(meta);
42
+ }
43
+ log(level, message, ...args) {
44
+ if (this.levels[level] < this.levels[this.level]) {
45
+ return;
26
46
  }
27
- else {
28
- this.logger = createLogger({
29
- level,
30
- silent: this.silent,
31
- defaultMeta: {
32
- name: 'turbo-sdk',
33
- version,
34
- },
35
- format: format.combine(format.timestamp(), format.json()),
36
- transports: [
37
- new transports.Console({
38
- format: getLogFormat(logFormat),
39
- }),
40
- ],
41
- });
47
+ const formattedMessage = this.formatMessage(level, message, ...args);
48
+ switch (level) {
49
+ case 'debug':
50
+ console.debug(formattedMessage);
51
+ break;
52
+ case 'info':
53
+ console.info(formattedMessage);
54
+ break;
55
+ case 'warn':
56
+ console.warn(formattedMessage);
57
+ break;
58
+ case 'error':
59
+ console.error(formattedMessage);
60
+ break;
42
61
  }
43
62
  }
44
63
  info(message, ...args) {
45
- if (this.silent)
46
- return;
47
- this.logger.info(message, ...args);
64
+ this.log('info', message, ...args);
48
65
  }
49
66
  warn(message, ...args) {
50
- if (this.silent)
51
- return;
52
- this.logger.warn(message, ...args);
67
+ this.log('warn', message, ...args);
53
68
  }
54
69
  error(message, ...args) {
55
- if (this.silent)
56
- return;
57
- this.logger.error(message, ...args);
70
+ this.log('error', message, ...args);
58
71
  }
59
72
  debug(message, ...args) {
60
- if (this.silent)
61
- return;
62
- this.logger.debug(message, ...args);
73
+ this.log('debug', message, ...args);
63
74
  }
64
75
  setLogLevel(level) {
65
- this.silent = level === 'none';
66
- if ('silent' in this.logger) {
67
- this.logger.silent = level === 'none';
68
- }
69
- if ('level' in this.logger) {
70
- this.logger.level = level;
71
- }
72
- }
73
- setLogFormat(logFormat) {
74
- if ('format' in this.logger) {
75
- this.logger.format = getLogFormat(logFormat);
76
- }
76
+ this.level = level;
77
77
  }
78
78
  }
79
- TurboWinstonLogger.default = new TurboWinstonLogger();
80
- function getLogFormat(logFormat) {
81
- return format.combine(format((info) => {
82
- if (info.stack && info.level !== 'error') {
83
- delete info.stack;
84
- }
85
- return info;
86
- })(), format.errors({ stack: true }), // Ensure errors show a stack trace
87
- format.timestamp(), logFormat === 'json' ? format.json() : format.simple());
88
- }
79
+ Logger.default = new Logger();
@@ -17,12 +17,12 @@ import { BigNumber } from 'bignumber.js';
17
17
  import { defaultRetryConfig } from '../utils/axiosClient.js';
18
18
  import { isAnyValidUserAddress } from '../utils/common.js';
19
19
  import { TurboHTTPService } from './http.js';
20
- import { TurboWinstonLogger } from './logger.js';
20
+ import { Logger } from './logger.js';
21
21
  import { exponentMap, tokenToBaseMap } from './token/index.js';
22
22
  export const developmentPaymentServiceURL = 'https://payment.ardrive.dev';
23
23
  export const defaultPaymentServiceURL = 'https://payment.ardrive.io';
24
24
  export class TurboUnauthenticatedPaymentService {
25
- constructor({ url = defaultPaymentServiceURL, logger = TurboWinstonLogger.default, retryConfig = defaultRetryConfig(logger), token = 'arweave', }) {
25
+ constructor({ url = defaultPaymentServiceURL, logger = Logger.default, retryConfig = defaultRetryConfig(logger), token = 'arweave', }) {
26
26
  this.logger = logger;
27
27
  this.httpService = new TurboHTTPService({
28
28
  url: `${url}/v1`,
@@ -241,7 +241,7 @@ export class TurboUnauthenticatedPaymentService {
241
241
  }
242
242
  // NOTE: to avoid redundancy, we use inheritance here - but generally prefer composition over inheritance
243
243
  export class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentService {
244
- constructor({ url = defaultPaymentServiceURL, retryConfig, signer, logger = TurboWinstonLogger.default, token = 'arweave', tokenTools, }) {
244
+ constructor({ url = defaultPaymentServiceURL, retryConfig, signer, logger = Logger.default, token = 'arweave', tokenTools, }) {
245
245
  super({ url, retryConfig, logger, token });
246
246
  this.signer = signer;
247
247
  this.tokenTools = tokenTools;
@@ -25,16 +25,19 @@ import { randomBytes } from 'crypto';
25
25
  import { Wallet as EthereumWallet, ethers, parseEther } from 'ethers';
26
26
  import { computeAddress } from 'ethers';
27
27
  import nacl from 'tweetnacl';
28
+ import { createWalletClient, custom, http } from 'viem';
29
+ import { privateKeyToAccount } from 'viem/accounts';
30
+ import { baseSepolia } from 'viem/chains';
28
31
  import { isEthereumWalletAdapter, isSolanaWalletAdapter, } from '../types.js';
29
32
  import { fromB64Url, ownerToAddress as ownerToB64Address, toB64Url, } from '../utils/base64.js';
30
- import { TurboWinstonLogger } from './logger.js';
33
+ import { Logger } from './logger.js';
31
34
  import { ethDataFromTurboCreditDestinationAddress } from './token/ethereum.js';
32
35
  import { memoProgramId } from './token/solana.js';
33
36
  /**
34
37
  * Abstract class for signing TurboDataItems.
35
38
  */
36
39
  export class TurboDataItemAbstractSigner {
37
- constructor({ signer, logger = TurboWinstonLogger.default, token, walletAdapter, }) {
40
+ constructor({ signer, logger = Logger.default, token, walletAdapter, }) {
38
41
  this.logger = logger;
39
42
  this.signer = signer;
40
43
  this.token = token;
@@ -148,3 +151,34 @@ export class TurboDataItemAbstractSigner {
148
151
  return this.signer.sign(dataToSign);
149
152
  }
150
153
  }
154
+ export async function makeX402Signer(arbundlesSigner) {
155
+ // Node: our SDK uses EthereumSigner with a raw private key
156
+ if (arbundlesSigner instanceof EthereumSigner) {
157
+ return createWalletClient({
158
+ account: privateKeyToAccount(('0x' +
159
+ Buffer.from(arbundlesSigner.key).toString('hex'))),
160
+ chain: baseSepolia,
161
+ transport: http(),
162
+ });
163
+ }
164
+ // Browser: use injected wallet + selected account
165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
166
+ if (typeof window !== 'undefined' && window.ethereum) {
167
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
168
+ const provider = window.ethereum;
169
+ // ask wallet for an account
170
+ const accounts = (await provider.request({
171
+ method: 'eth_requestAccounts',
172
+ }));
173
+ if (accounts === undefined || accounts.length === 0) {
174
+ throw new Error('No accounts returned from wallet');
175
+ }
176
+ const account = accounts[0];
177
+ return createWalletClient({
178
+ account,
179
+ chain: baseSepolia,
180
+ transport: custom(provider),
181
+ });
182
+ }
183
+ throw new Error('Unable to construct x402 signer for x402 options');
184
+ }
@@ -18,9 +18,9 @@ import { connect, createDataItemSigner } from '@permaweb/aoconnect';
18
18
  import { BigNumber } from 'bignumber.js';
19
19
  import { defaultProdAoConfigs, sleep } from '../../utils/common.js';
20
20
  import { version } from '../../version.js';
21
- import { TurboWinstonLogger } from '../logger.js';
21
+ import { Logger } from '../logger.js';
22
22
  export class ARIOToken {
23
- constructor({ cuUrl = defaultProdAoConfigs.ario.cuUrl, logger = TurboWinstonLogger.default, pollingOptions = {
23
+ constructor({ cuUrl = defaultProdAoConfigs.ario.cuUrl, logger = Logger.default, pollingOptions = {
24
24
  initialBackoffMs: 500,
25
25
  pollingIntervalMs: 0, // no polling for ARIO process
26
26
  maxAttempts: 0, // no polling for ARIO process
@@ -17,13 +17,13 @@ import ArweaveModule from 'arweave';
17
17
  import { BigNumber } from 'bignumber.js';
18
18
  import { sha256B64Url, toB64Url } from '../../utils/base64.js';
19
19
  import { sleep } from '../../utils/common.js';
20
- import { TurboWinstonLogger } from '../logger.js';
20
+ import { Logger } from '../logger.js';
21
21
  const ArweaveClass =
22
22
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
23
23
  // @ts-ignore -- Access the correct class constructor for Arweave
24
24
  ArweaveModule.default?.default || ArweaveModule.default || ArweaveModule;
25
25
  export class ArweaveToken {
26
- constructor({ gatewayUrl = 'https://arweave.net', arweave, logger = TurboWinstonLogger.default, mintU = true, pollingOptions = {
26
+ constructor({ gatewayUrl = 'https://arweave.net', arweave, logger = Logger.default, mintU = true, pollingOptions = {
27
27
  maxAttempts: 10,
28
28
  pollingIntervalMs: 3_000,
29
29
  initialBackoffMs: 7_000,
@@ -17,10 +17,10 @@ import { EthereumSigner } from '@dha-team/arbundles';
17
17
  import { Wallet as EthereumWallet, JsonRpcProvider, ethers } from 'ethers';
18
18
  import { isEthereumWalletAdapter, } from '../../types.js';
19
19
  import { defaultProdGatewayUrls } from '../../utils/common.js';
20
- import { TurboWinstonLogger } from '../logger.js';
20
+ import { Logger } from '../logger.js';
21
21
  import { EthereumToken, ethDataFromTurboCreditDestinationAddress, } from './ethereum.js';
22
22
  export class ERC20Token extends EthereumToken {
23
- constructor({ tokenContractAddress, logger = TurboWinstonLogger.default, gatewayUrl = defaultProdGatewayUrls.ethereum, pollingOptions, }) {
23
+ constructor({ tokenContractAddress, logger = Logger.default, gatewayUrl = defaultProdGatewayUrls.ethereum, pollingOptions, }) {
24
24
  super({ logger, gatewayUrl, pollingOptions });
25
25
  this.tokenContract = new ethers.Contract(tokenContractAddress, [
26
26
  'function decimals() view returns (uint8)',
@@ -16,7 +16,7 @@
16
16
  import { BigNumber } from 'bignumber.js';
17
17
  import { ethers, hexlify, toUtf8Bytes } from 'ethers';
18
18
  import { defaultProdGatewayUrls } from '../../utils/common.js';
19
- import { TurboWinstonLogger } from '../logger.js';
19
+ import { Logger } from '../logger.js';
20
20
  export const weiToTokenAmount = (wei) => wei;
21
21
  export const ETHToTokenAmount = (eth) => new BigNumber(eth).times(1e18).valueOf();
22
22
  export const defaultEthereumPollingOptions = {
@@ -25,7 +25,7 @@ export const defaultEthereumPollingOptions = {
25
25
  pollingIntervalMs: 1_500,
26
26
  };
27
27
  export class EthereumToken {
28
- constructor({ logger = TurboWinstonLogger.default, gatewayUrl = defaultProdGatewayUrls.ethereum, pollingOptions = defaultEthereumPollingOptions, } = {}) {
28
+ constructor({ logger = Logger.default, gatewayUrl = defaultProdGatewayUrls.ethereum, pollingOptions = defaultEthereumPollingOptions, } = {}) {
29
29
  this.logger = logger;
30
30
  this.gatewayUrl = gatewayUrl;
31
31
  this.pollingOptions = pollingOptions;
@@ -23,14 +23,14 @@ import { BigNumber } from 'bignumber.js';
23
23
  import { createAxiosInstance } from '../../utils/axiosClient.js';
24
24
  import { defaultProdGatewayUrls } from '../../utils/common.js';
25
25
  import { sleep } from '../../utils/common.js';
26
- import { TurboWinstonLogger } from '../logger.js';
26
+ import { Logger } from '../logger.js';
27
27
  function hasKyveTxResponse(response) {
28
28
  return response.tx_response !== undefined;
29
29
  }
30
30
  export const ukyveToTokenAmount = (winston) => winston;
31
31
  export const KYVEToTokenAmount = (sol) => new BigNumber(sol).times(1e6).valueOf();
32
32
  export class KyveToken {
33
- constructor({ logger = TurboWinstonLogger.default, gatewayUrl = defaultProdGatewayUrls.kyve, pollingOptions = {
33
+ constructor({ logger = Logger.default, gatewayUrl = defaultProdGatewayUrls.kyve, pollingOptions = {
34
34
  maxAttempts: 5,
35
35
  pollingIntervalMs: 1_000,
36
36
  initialBackoffMs: 500,
@@ -1,5 +1,5 @@
1
1
  import { defaultProdGatewayUrls } from '../../utils/common.js';
2
- import { TurboWinstonLogger } from '../logger.js';
2
+ import { Logger } from '../logger.js';
3
3
  import { ETHToTokenAmount, EthereumToken } from './ethereum.js';
4
4
  export const POLToTokenAmount = ETHToTokenAmount;
5
5
  export const defaultPolygonPollingOptions = {
@@ -8,7 +8,7 @@ export const defaultPolygonPollingOptions = {
8
8
  pollingIntervalMs: 1_000,
9
9
  };
10
10
  export class PolygonToken extends EthereumToken {
11
- constructor({ logger = TurboWinstonLogger.default, gatewayUrl = defaultProdGatewayUrls.pol, pollingOptions = defaultPolygonPollingOptions, } = {}) {
11
+ constructor({ logger = Logger.default, gatewayUrl = defaultProdGatewayUrls.pol, pollingOptions = defaultPolygonPollingOptions, } = {}) {
12
12
  super({ logger, gatewayUrl, pollingOptions });
13
13
  }
14
14
  }