@ardrive/turbo-sdk 1.0.0-beta.1 → 1.0.0-beta.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/README.md +48 -14
- package/bundles/web.bundle.min.js +142 -34
- package/lib/cjs/common/currency.js +42 -0
- package/lib/cjs/common/index.js +1 -0
- package/lib/cjs/common/payment.js +38 -6
- package/lib/cjs/common/turbo.js +22 -11
- package/lib/cjs/common/upload.js +9 -3
- package/lib/cjs/node/signer.js +33 -2
- package/lib/cjs/utils/readableStream.js +6 -4
- package/lib/cjs/web/signer.js +9 -4
- package/lib/esm/common/currency.js +27 -0
- package/lib/esm/common/index.js +1 -0
- package/lib/esm/common/payment.js +38 -6
- package/lib/esm/common/turbo.js +22 -11
- package/lib/esm/common/upload.js +9 -3
- package/lib/esm/node/signer.js +33 -2
- package/lib/esm/utils/readableStream.js +6 -4
- package/lib/esm/web/signer.js +9 -4
- package/lib/types/common/currency.d.ts +43 -0
- package/lib/types/common/currency.d.ts.map +1 -0
- package/lib/types/common/index.d.ts +1 -0
- package/lib/types/common/index.d.ts.map +1 -1
- package/lib/types/common/payment.d.ts +13 -5
- package/lib/types/common/payment.d.ts.map +1 -1
- package/lib/types/common/turbo.d.ts +8 -7
- package/lib/types/common/turbo.d.ts.map +1 -1
- package/lib/types/common/upload.d.ts +2 -2
- package/lib/types/common/upload.d.ts.map +1 -1
- package/lib/types/node/signer.d.ts +8 -3
- package/lib/types/node/signer.d.ts.map +1 -1
- package/lib/types/types.d.ts +42 -8
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/utils/readableStream.d.ts +2 -1
- package/lib/types/utils/readableStream.d.ts.map +1 -1
- package/lib/types/web/signer.d.ts +7 -3
- package/lib/types/web/signer.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/cjs/common/turbo.js
CHANGED
@@ -11,7 +11,7 @@ class TurboUnauthenticatedClient {
|
|
11
11
|
/**
|
12
12
|
* Returns the supported fiat currency conversion rate for 1AR based on current market prices.
|
13
13
|
*/
|
14
|
-
|
14
|
+
getFiatToAR({ currency, }) {
|
15
15
|
return this.paymentService.getFiatToAR({ currency });
|
16
16
|
}
|
17
17
|
/**
|
@@ -20,42 +20,49 @@ class TurboUnauthenticatedClient {
|
|
20
20
|
* Note: this does not take into account varying adjustments and promotions for different sizes of data. If you want to calculate the total
|
21
21
|
* cost in 'winc' for a given number of bytes, use getUploadCosts.
|
22
22
|
*/
|
23
|
-
|
23
|
+
getFiatRates() {
|
24
24
|
return this.paymentService.getFiatRates();
|
25
25
|
}
|
26
26
|
/**
|
27
27
|
* Returns a comprehensive list of supported countries that can purchase credits through the Turbo Payment Service.
|
28
28
|
*/
|
29
|
-
|
29
|
+
getSupportedCountries() {
|
30
30
|
return this.paymentService.getSupportedCountries();
|
31
31
|
}
|
32
32
|
/**
|
33
33
|
* Returns a list of all supported fiat currencies.
|
34
34
|
*/
|
35
|
-
|
35
|
+
getSupportedCurrencies() {
|
36
36
|
return this.paymentService.getSupportedCurrencies();
|
37
37
|
}
|
38
38
|
/**
|
39
39
|
* Determines the price in 'winc' to upload one data item of a specific size in bytes, including all Turbo cost adjustments and fees.
|
40
40
|
*/
|
41
|
-
|
41
|
+
getUploadCosts({ bytes, }) {
|
42
42
|
return this.paymentService.getUploadCosts({ bytes });
|
43
43
|
}
|
44
44
|
/**
|
45
45
|
* Determines the amount of 'winc' that would be returned for a given currency and amount, including all Turbo cost adjustments and fees.
|
46
46
|
*/
|
47
|
-
|
48
|
-
return this.paymentService.getWincForFiat(
|
47
|
+
getWincForFiat(params) {
|
48
|
+
return this.paymentService.getWincForFiat(params);
|
49
49
|
}
|
50
50
|
/**
|
51
51
|
* Uploads a signed data item to the Turbo Upload Service.
|
52
52
|
*/
|
53
|
-
|
53
|
+
uploadSignedDataItem({ dataItemStreamFactory, dataItemSizeFactory, signal, }) {
|
54
54
|
return this.uploadService.uploadSignedDataItem({
|
55
55
|
dataItemStreamFactory,
|
56
|
+
dataItemSizeFactory,
|
56
57
|
signal,
|
57
58
|
});
|
58
59
|
}
|
60
|
+
/**
|
61
|
+
* Creates a Turbo Checkout Session for a given amount and currency.
|
62
|
+
*/
|
63
|
+
createCheckoutSession(params) {
|
64
|
+
return this.paymentService.createCheckoutSession(params);
|
65
|
+
}
|
59
66
|
}
|
60
67
|
exports.TurboUnauthenticatedClient = TurboUnauthenticatedClient;
|
61
68
|
class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
|
@@ -65,14 +72,18 @@ class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
|
|
65
72
|
/**
|
66
73
|
* Returns the current balance of the user's wallet in 'winc'.
|
67
74
|
*/
|
68
|
-
|
75
|
+
getBalance() {
|
69
76
|
return this.paymentService.getBalance();
|
70
77
|
}
|
71
78
|
/**
|
72
79
|
* Signs and uploads raw data to the Turbo Upload Service.
|
73
80
|
*/
|
74
|
-
|
75
|
-
return this.uploadService.uploadFile({
|
81
|
+
uploadFile({ fileStreamFactory, fileSizeFactory, signal, }) {
|
82
|
+
return this.uploadService.uploadFile({
|
83
|
+
fileStreamFactory,
|
84
|
+
fileSizeFactory,
|
85
|
+
signal,
|
86
|
+
});
|
76
87
|
}
|
77
88
|
}
|
78
89
|
exports.TurboAuthenticatedClient = TurboAuthenticatedClient;
|
package/lib/cjs/common/upload.js
CHANGED
@@ -9,7 +9,8 @@ class TurboUnauthenticatedUploadService {
|
|
9
9
|
retryConfig,
|
10
10
|
});
|
11
11
|
}
|
12
|
-
async uploadSignedDataItem({ dataItemStreamFactory, signal, }) {
|
12
|
+
async uploadSignedDataItem({ dataItemStreamFactory, dataItemSizeFactory, signal, }) {
|
13
|
+
const fileSize = dataItemSizeFactory();
|
13
14
|
// TODO: add p-limit constraint or replace with separate upload class
|
14
15
|
return this.httpService.post({
|
15
16
|
endpoint: `/tx`,
|
@@ -17,6 +18,7 @@ class TurboUnauthenticatedUploadService {
|
|
17
18
|
data: dataItemStreamFactory(),
|
18
19
|
headers: {
|
19
20
|
'content-type': 'application/octet-stream',
|
21
|
+
'content-length': `${fileSize}`,
|
20
22
|
},
|
21
23
|
});
|
22
24
|
}
|
@@ -28,10 +30,13 @@ class TurboAuthenticatedUploadService extends TurboUnauthenticatedUploadService
|
|
28
30
|
super({ url, retryConfig });
|
29
31
|
this.signer = signer;
|
30
32
|
}
|
31
|
-
async uploadFile({ fileStreamFactory, signal, }) {
|
32
|
-
const
|
33
|
+
async uploadFile({ fileStreamFactory, fileSizeFactory, signal, }) {
|
34
|
+
const { dataItemStreamFactory, dataItemSizeFactory } = await this.signer.signDataItem({
|
33
35
|
fileStreamFactory,
|
36
|
+
fileSizeFactory,
|
34
37
|
});
|
38
|
+
const signedDataItem = dataItemStreamFactory();
|
39
|
+
const fileSize = dataItemSizeFactory();
|
35
40
|
// TODO: add p-limit constraint or replace with separate upload class
|
36
41
|
return this.httpService.post({
|
37
42
|
endpoint: `/tx`,
|
@@ -39,6 +44,7 @@ class TurboAuthenticatedUploadService extends TurboUnauthenticatedUploadService
|
|
39
44
|
data: signedDataItem,
|
40
45
|
headers: {
|
41
46
|
'content-type': 'application/octet-stream',
|
47
|
+
'content-length': `${fileSize}`,
|
42
48
|
},
|
43
49
|
});
|
44
50
|
}
|
package/lib/cjs/node/signer.js
CHANGED
@@ -30,10 +30,18 @@ class TurboNodeArweaveSigner {
|
|
30
30
|
this.privateKey = privateKey;
|
31
31
|
this.signer = new arbundles_1.ArweaveSigner(this.privateKey);
|
32
32
|
}
|
33
|
-
signDataItem({ fileStreamFactory, }) {
|
33
|
+
async signDataItem({ fileStreamFactory, fileSizeFactory, }) {
|
34
34
|
// TODO: replace with our own signer implementation
|
35
35
|
const [stream1, stream2] = [fileStreamFactory(), fileStreamFactory()];
|
36
|
-
|
36
|
+
const signedDataItem = await (0, arbundles_1.streamSigner)(stream1, stream2, this.signer);
|
37
|
+
// TODO: support target, anchor, and tags
|
38
|
+
const signedDataItemSize = this.calculateSignedDataHeadersSize({
|
39
|
+
dataSize: fileSizeFactory(),
|
40
|
+
});
|
41
|
+
return {
|
42
|
+
dataItemStreamFactory: () => signedDataItem,
|
43
|
+
dataItemSizeFactory: () => signedDataItemSize,
|
44
|
+
};
|
37
45
|
}
|
38
46
|
// NOTE: this might be better in a parent class or elsewhere - easy enough to leave in here now and does require specific environment version of crypto
|
39
47
|
async generateSignedRequestHeaders() {
|
@@ -46,5 +54,28 @@ class TurboNodeArweaveSigner {
|
|
46
54
|
'x-signature': (0, base64_js_1.toB64Url)(Buffer.from(signature)),
|
47
55
|
};
|
48
56
|
}
|
57
|
+
// TODO: make dynamic that accepts anchor and target and tags to return the size of the headers + data
|
58
|
+
// reference https://github.com/ArweaveTeam/arweave-standards/blob/master/ans/ANS-104.md#13-dataitem-format
|
59
|
+
calculateSignedDataHeadersSize({ dataSize }) {
|
60
|
+
const anchor = 1; // + whatever they provide (max of 33)
|
61
|
+
const target = 1; // + whatever they provide (max of 33)
|
62
|
+
const tags = 0;
|
63
|
+
const signatureLength = 512;
|
64
|
+
const ownerLength = 512;
|
65
|
+
const signatureTypeLength = 2;
|
66
|
+
const numOfTagsLength = 8; // https://github.com/Bundlr-Network/arbundles/blob/master/src/tags.ts#L191-L198
|
67
|
+
const numOfTagsBytesLength = 8;
|
68
|
+
return [
|
69
|
+
anchor,
|
70
|
+
target,
|
71
|
+
tags,
|
72
|
+
signatureLength,
|
73
|
+
ownerLength,
|
74
|
+
signatureTypeLength,
|
75
|
+
numOfTagsLength,
|
76
|
+
numOfTagsBytesLength,
|
77
|
+
dataSize,
|
78
|
+
].reduce((totalSize, currentSize) => (totalSize += currentSize));
|
79
|
+
}
|
49
80
|
}
|
50
81
|
exports.TurboNodeArweaveSigner = TurboNodeArweaveSigner;
|
@@ -1,17 +1,19 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.readableStreamToBuffer = void 0;
|
4
|
-
async function readableStreamToBuffer({ stream, }) {
|
4
|
+
async function readableStreamToBuffer({ stream, size, }) {
|
5
5
|
const reader = stream.getReader();
|
6
|
-
const
|
6
|
+
const buffer = Buffer.alloc(size);
|
7
|
+
let offset = 0;
|
7
8
|
let done = false;
|
8
9
|
while (!done) {
|
9
10
|
const { done: streamDone, value } = await reader.read();
|
10
11
|
done = streamDone;
|
11
12
|
if (!done) {
|
12
|
-
|
13
|
+
buffer.set(value, offset);
|
14
|
+
offset += value.byteLength;
|
13
15
|
}
|
14
16
|
}
|
15
|
-
return
|
17
|
+
return buffer;
|
16
18
|
}
|
17
19
|
exports.readableStreamToBuffer = readableStreamToBuffer;
|
package/lib/cjs/web/signer.js
CHANGED
@@ -30,15 +30,20 @@ class TurboWebArweaveSigner {
|
|
30
30
|
this.privateKey = privateKey;
|
31
31
|
this.signer = new arbundles_1.ArweaveSigner(this.privateKey);
|
32
32
|
}
|
33
|
-
async signDataItem({ fileStreamFactory, }) {
|
33
|
+
async signDataItem({ fileStreamFactory, fileSizeFactory, }) {
|
34
34
|
// TODO: converts the readable stream to a buffer bc incrementally signing ReadableStreams is not trivial
|
35
35
|
const buffer = await (0, readableStream_js_1.readableStreamToBuffer)({
|
36
36
|
stream: fileStreamFactory(),
|
37
|
-
|
37
|
+
size: fileSizeFactory(),
|
38
38
|
});
|
39
|
-
|
39
|
+
// TODO: support target, anchor and tags for upload
|
40
|
+
const signedDataItem = (0, arbundles_1.createData)(buffer, this.signer, {});
|
40
41
|
await signedDataItem.sign(this.signer);
|
41
|
-
return
|
42
|
+
return {
|
43
|
+
// while this returns a Buffer - it needs to match our return type for uploading
|
44
|
+
dataItemStreamFactory: () => signedDataItem.getRaw(),
|
45
|
+
dataItemSizeFactory: () => signedDataItem.getRaw().length,
|
46
|
+
};
|
42
47
|
}
|
43
48
|
// NOTE: this might be better in a parent class or elsewhere - easy enough to leave in here now and does require specific environment version of crypto
|
44
49
|
async generateSignedRequestHeaders() {
|
@@ -0,0 +1,27 @@
|
|
1
|
+
export class ZeroDecimalCurrency {
|
2
|
+
constructor(amount, type) {
|
3
|
+
this.amount = amount;
|
4
|
+
this.type = type;
|
5
|
+
}
|
6
|
+
}
|
7
|
+
export class TwoDecimalCurrency {
|
8
|
+
constructor(a, type) {
|
9
|
+
this.a = a;
|
10
|
+
this.type = type;
|
11
|
+
}
|
12
|
+
get amount() {
|
13
|
+
return this.a * 100;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
// Two decimal currencies that are supported by the Turbo API
|
17
|
+
export const USD = (usd) => new TwoDecimalCurrency(usd, 'usd');
|
18
|
+
export const EUR = (eur) => new TwoDecimalCurrency(eur, 'eur');
|
19
|
+
export const GBP = (gbp) => new TwoDecimalCurrency(gbp, 'gbp');
|
20
|
+
export const CAD = (cad) => new TwoDecimalCurrency(cad, 'cad');
|
21
|
+
export const AUD = (aud) => new TwoDecimalCurrency(aud, 'aud');
|
22
|
+
export const INR = (inr) => new TwoDecimalCurrency(inr, 'inr');
|
23
|
+
export const SGD = (sgd) => new TwoDecimalCurrency(sgd, 'sgd');
|
24
|
+
export const HKD = (hkd) => new TwoDecimalCurrency(hkd, 'hkd');
|
25
|
+
export const BRL = (brl) => new TwoDecimalCurrency(brl, 'brl');
|
26
|
+
// Zero decimal currencies that are supported by the Turbo API
|
27
|
+
export const JPY = (jpy) => new ZeroDecimalCurrency(jpy, 'jpy');
|
package/lib/esm/common/index.js
CHANGED
@@ -6,22 +6,22 @@ export class TurboUnauthenticatedPaymentService {
|
|
6
6
|
retryConfig,
|
7
7
|
});
|
8
8
|
}
|
9
|
-
|
9
|
+
getFiatRates() {
|
10
10
|
return this.httpService.get({
|
11
11
|
endpoint: '/rates',
|
12
12
|
});
|
13
13
|
}
|
14
|
-
|
14
|
+
getFiatToAR({ currency, }) {
|
15
15
|
return this.httpService.get({
|
16
16
|
endpoint: `/rates/${currency}`,
|
17
17
|
});
|
18
18
|
}
|
19
|
-
|
19
|
+
getSupportedCountries() {
|
20
20
|
return this.httpService.get({
|
21
21
|
endpoint: '/countries',
|
22
22
|
});
|
23
23
|
}
|
24
|
-
|
24
|
+
getSupportedCurrencies() {
|
25
25
|
return this.httpService.get({
|
26
26
|
endpoint: '/currencies',
|
27
27
|
});
|
@@ -33,11 +33,34 @@ export class TurboUnauthenticatedPaymentService {
|
|
33
33
|
const wincCostsForBytes = await Promise.all(fetchPricePromises);
|
34
34
|
return wincCostsForBytes;
|
35
35
|
}
|
36
|
-
|
36
|
+
getWincForFiat({ amount, }) {
|
37
|
+
const { amount: paymentAmount, type: currencyType } = amount;
|
37
38
|
return this.httpService.get({
|
38
|
-
endpoint: `/price/${
|
39
|
+
endpoint: `/price/${currencyType}/${paymentAmount}`,
|
39
40
|
});
|
40
41
|
}
|
42
|
+
appendPromoCodesToQuery(promoCodes) {
|
43
|
+
const promoCodesQuery = promoCodes.join(',');
|
44
|
+
return promoCodesQuery ? `?promoCode=${promoCodesQuery}` : '';
|
45
|
+
}
|
46
|
+
async getCheckout({ amount, owner, promoCodes = [] }, headers) {
|
47
|
+
const { amount: paymentAmount, type: currencyType } = amount;
|
48
|
+
const endpoint = `/top-up/checkout-session/${owner}/${currencyType}/${paymentAmount}${this.appendPromoCodesToQuery(promoCodes)}`;
|
49
|
+
const { adjustments, paymentSession, topUpQuote } = await this.httpService.get({
|
50
|
+
endpoint,
|
51
|
+
headers,
|
52
|
+
});
|
53
|
+
return {
|
54
|
+
winc: topUpQuote.winstonCreditAmount,
|
55
|
+
adjustments,
|
56
|
+
url: paymentSession.url,
|
57
|
+
paymentAmount: topUpQuote.paymentAmount,
|
58
|
+
quotedPaymentAmount: topUpQuote.quotedPaymentAmount,
|
59
|
+
};
|
60
|
+
}
|
61
|
+
createCheckoutSession(params) {
|
62
|
+
return this.getCheckout(params);
|
63
|
+
}
|
41
64
|
}
|
42
65
|
// NOTE: to avoid redundancy, we use inheritance here - but generally prefer composition over inheritance
|
43
66
|
export class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymentService {
|
@@ -55,4 +78,13 @@ export class TurboAuthenticatedPaymentService extends TurboUnauthenticatedPaymen
|
|
55
78
|
// 404's don't return a balance, so default to 0
|
56
79
|
return balance.winc ? balance : { winc: '0' };
|
57
80
|
}
|
81
|
+
async getWincForFiat({ amount, promoCodes = [], }) {
|
82
|
+
return this.httpService.get({
|
83
|
+
endpoint: `/price/${amount.type}/${amount.amount}${this.appendPromoCodesToQuery(promoCodes)}`,
|
84
|
+
headers: await this.signer.generateSignedRequestHeaders(),
|
85
|
+
});
|
86
|
+
}
|
87
|
+
async createCheckoutSession(params) {
|
88
|
+
return this.getCheckout(params, await this.signer.generateSignedRequestHeaders());
|
89
|
+
}
|
58
90
|
}
|
package/lib/esm/common/turbo.js
CHANGED
@@ -8,7 +8,7 @@ export class TurboUnauthenticatedClient {
|
|
8
8
|
/**
|
9
9
|
* Returns the supported fiat currency conversion rate for 1AR based on current market prices.
|
10
10
|
*/
|
11
|
-
|
11
|
+
getFiatToAR({ currency, }) {
|
12
12
|
return this.paymentService.getFiatToAR({ currency });
|
13
13
|
}
|
14
14
|
/**
|
@@ -17,42 +17,49 @@ export class TurboUnauthenticatedClient {
|
|
17
17
|
* Note: this does not take into account varying adjustments and promotions for different sizes of data. If you want to calculate the total
|
18
18
|
* cost in 'winc' for a given number of bytes, use getUploadCosts.
|
19
19
|
*/
|
20
|
-
|
20
|
+
getFiatRates() {
|
21
21
|
return this.paymentService.getFiatRates();
|
22
22
|
}
|
23
23
|
/**
|
24
24
|
* Returns a comprehensive list of supported countries that can purchase credits through the Turbo Payment Service.
|
25
25
|
*/
|
26
|
-
|
26
|
+
getSupportedCountries() {
|
27
27
|
return this.paymentService.getSupportedCountries();
|
28
28
|
}
|
29
29
|
/**
|
30
30
|
* Returns a list of all supported fiat currencies.
|
31
31
|
*/
|
32
|
-
|
32
|
+
getSupportedCurrencies() {
|
33
33
|
return this.paymentService.getSupportedCurrencies();
|
34
34
|
}
|
35
35
|
/**
|
36
36
|
* Determines the price in 'winc' to upload one data item of a specific size in bytes, including all Turbo cost adjustments and fees.
|
37
37
|
*/
|
38
|
-
|
38
|
+
getUploadCosts({ bytes, }) {
|
39
39
|
return this.paymentService.getUploadCosts({ bytes });
|
40
40
|
}
|
41
41
|
/**
|
42
42
|
* Determines the amount of 'winc' that would be returned for a given currency and amount, including all Turbo cost adjustments and fees.
|
43
43
|
*/
|
44
|
-
|
45
|
-
return this.paymentService.getWincForFiat(
|
44
|
+
getWincForFiat(params) {
|
45
|
+
return this.paymentService.getWincForFiat(params);
|
46
46
|
}
|
47
47
|
/**
|
48
48
|
* Uploads a signed data item to the Turbo Upload Service.
|
49
49
|
*/
|
50
|
-
|
50
|
+
uploadSignedDataItem({ dataItemStreamFactory, dataItemSizeFactory, signal, }) {
|
51
51
|
return this.uploadService.uploadSignedDataItem({
|
52
52
|
dataItemStreamFactory,
|
53
|
+
dataItemSizeFactory,
|
53
54
|
signal,
|
54
55
|
});
|
55
56
|
}
|
57
|
+
/**
|
58
|
+
* Creates a Turbo Checkout Session for a given amount and currency.
|
59
|
+
*/
|
60
|
+
createCheckoutSession(params) {
|
61
|
+
return this.paymentService.createCheckoutSession(params);
|
62
|
+
}
|
56
63
|
}
|
57
64
|
export class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
|
58
65
|
constructor({ paymentService, uploadService, }) {
|
@@ -61,13 +68,17 @@ export class TurboAuthenticatedClient extends TurboUnauthenticatedClient {
|
|
61
68
|
/**
|
62
69
|
* Returns the current balance of the user's wallet in 'winc'.
|
63
70
|
*/
|
64
|
-
|
71
|
+
getBalance() {
|
65
72
|
return this.paymentService.getBalance();
|
66
73
|
}
|
67
74
|
/**
|
68
75
|
* Signs and uploads raw data to the Turbo Upload Service.
|
69
76
|
*/
|
70
|
-
|
71
|
-
return this.uploadService.uploadFile({
|
77
|
+
uploadFile({ fileStreamFactory, fileSizeFactory, signal, }) {
|
78
|
+
return this.uploadService.uploadFile({
|
79
|
+
fileStreamFactory,
|
80
|
+
fileSizeFactory,
|
81
|
+
signal,
|
82
|
+
});
|
72
83
|
}
|
73
84
|
}
|
package/lib/esm/common/upload.js
CHANGED
@@ -6,7 +6,8 @@ export class TurboUnauthenticatedUploadService {
|
|
6
6
|
retryConfig,
|
7
7
|
});
|
8
8
|
}
|
9
|
-
async uploadSignedDataItem({ dataItemStreamFactory, signal, }) {
|
9
|
+
async uploadSignedDataItem({ dataItemStreamFactory, dataItemSizeFactory, signal, }) {
|
10
|
+
const fileSize = dataItemSizeFactory();
|
10
11
|
// TODO: add p-limit constraint or replace with separate upload class
|
11
12
|
return this.httpService.post({
|
12
13
|
endpoint: `/tx`,
|
@@ -14,6 +15,7 @@ export class TurboUnauthenticatedUploadService {
|
|
14
15
|
data: dataItemStreamFactory(),
|
15
16
|
headers: {
|
16
17
|
'content-type': 'application/octet-stream',
|
18
|
+
'content-length': `${fileSize}`,
|
17
19
|
},
|
18
20
|
});
|
19
21
|
}
|
@@ -24,10 +26,13 @@ export class TurboAuthenticatedUploadService extends TurboUnauthenticatedUploadS
|
|
24
26
|
super({ url, retryConfig });
|
25
27
|
this.signer = signer;
|
26
28
|
}
|
27
|
-
async uploadFile({ fileStreamFactory, signal, }) {
|
28
|
-
const
|
29
|
+
async uploadFile({ fileStreamFactory, fileSizeFactory, signal, }) {
|
30
|
+
const { dataItemStreamFactory, dataItemSizeFactory } = await this.signer.signDataItem({
|
29
31
|
fileStreamFactory,
|
32
|
+
fileSizeFactory,
|
30
33
|
});
|
34
|
+
const signedDataItem = dataItemStreamFactory();
|
35
|
+
const fileSize = dataItemSizeFactory();
|
31
36
|
// TODO: add p-limit constraint or replace with separate upload class
|
32
37
|
return this.httpService.post({
|
33
38
|
endpoint: `/tx`,
|
@@ -35,6 +40,7 @@ export class TurboAuthenticatedUploadService extends TurboUnauthenticatedUploadS
|
|
35
40
|
data: signedDataItem,
|
36
41
|
headers: {
|
37
42
|
'content-type': 'application/octet-stream',
|
43
|
+
'content-length': `${fileSize}`,
|
38
44
|
},
|
39
45
|
});
|
40
46
|
}
|
package/lib/esm/node/signer.js
CHANGED
@@ -24,10 +24,18 @@ export class TurboNodeArweaveSigner {
|
|
24
24
|
this.privateKey = privateKey;
|
25
25
|
this.signer = new ArweaveSigner(this.privateKey);
|
26
26
|
}
|
27
|
-
signDataItem({ fileStreamFactory, }) {
|
27
|
+
async signDataItem({ fileStreamFactory, fileSizeFactory, }) {
|
28
28
|
// TODO: replace with our own signer implementation
|
29
29
|
const [stream1, stream2] = [fileStreamFactory(), fileStreamFactory()];
|
30
|
-
|
30
|
+
const signedDataItem = await streamSigner(stream1, stream2, this.signer);
|
31
|
+
// TODO: support target, anchor, and tags
|
32
|
+
const signedDataItemSize = this.calculateSignedDataHeadersSize({
|
33
|
+
dataSize: fileSizeFactory(),
|
34
|
+
});
|
35
|
+
return {
|
36
|
+
dataItemStreamFactory: () => signedDataItem,
|
37
|
+
dataItemSizeFactory: () => signedDataItemSize,
|
38
|
+
};
|
31
39
|
}
|
32
40
|
// NOTE: this might be better in a parent class or elsewhere - easy enough to leave in here now and does require specific environment version of crypto
|
33
41
|
async generateSignedRequestHeaders() {
|
@@ -40,4 +48,27 @@ export class TurboNodeArweaveSigner {
|
|
40
48
|
'x-signature': toB64Url(Buffer.from(signature)),
|
41
49
|
};
|
42
50
|
}
|
51
|
+
// TODO: make dynamic that accepts anchor and target and tags to return the size of the headers + data
|
52
|
+
// reference https://github.com/ArweaveTeam/arweave-standards/blob/master/ans/ANS-104.md#13-dataitem-format
|
53
|
+
calculateSignedDataHeadersSize({ dataSize }) {
|
54
|
+
const anchor = 1; // + whatever they provide (max of 33)
|
55
|
+
const target = 1; // + whatever they provide (max of 33)
|
56
|
+
const tags = 0;
|
57
|
+
const signatureLength = 512;
|
58
|
+
const ownerLength = 512;
|
59
|
+
const signatureTypeLength = 2;
|
60
|
+
const numOfTagsLength = 8; // https://github.com/Bundlr-Network/arbundles/blob/master/src/tags.ts#L191-L198
|
61
|
+
const numOfTagsBytesLength = 8;
|
62
|
+
return [
|
63
|
+
anchor,
|
64
|
+
target,
|
65
|
+
tags,
|
66
|
+
signatureLength,
|
67
|
+
ownerLength,
|
68
|
+
signatureTypeLength,
|
69
|
+
numOfTagsLength,
|
70
|
+
numOfTagsBytesLength,
|
71
|
+
dataSize,
|
72
|
+
].reduce((totalSize, currentSize) => (totalSize += currentSize));
|
73
|
+
}
|
43
74
|
}
|
@@ -1,13 +1,15 @@
|
|
1
|
-
export async function readableStreamToBuffer({ stream, }) {
|
1
|
+
export async function readableStreamToBuffer({ stream, size, }) {
|
2
2
|
const reader = stream.getReader();
|
3
|
-
const
|
3
|
+
const buffer = Buffer.alloc(size);
|
4
|
+
let offset = 0;
|
4
5
|
let done = false;
|
5
6
|
while (!done) {
|
6
7
|
const { done: streamDone, value } = await reader.read();
|
7
8
|
done = streamDone;
|
8
9
|
if (!done) {
|
9
|
-
|
10
|
+
buffer.set(value, offset);
|
11
|
+
offset += value.byteLength;
|
10
12
|
}
|
11
13
|
}
|
12
|
-
return
|
14
|
+
return buffer;
|
13
15
|
}
|
package/lib/esm/web/signer.js
CHANGED
@@ -24,15 +24,20 @@ export class TurboWebArweaveSigner {
|
|
24
24
|
this.privateKey = privateKey;
|
25
25
|
this.signer = new ArweaveSigner(this.privateKey);
|
26
26
|
}
|
27
|
-
async signDataItem({ fileStreamFactory, }) {
|
27
|
+
async signDataItem({ fileStreamFactory, fileSizeFactory, }) {
|
28
28
|
// TODO: converts the readable stream to a buffer bc incrementally signing ReadableStreams is not trivial
|
29
29
|
const buffer = await readableStreamToBuffer({
|
30
30
|
stream: fileStreamFactory(),
|
31
|
-
|
31
|
+
size: fileSizeFactory(),
|
32
32
|
});
|
33
|
-
|
33
|
+
// TODO: support target, anchor and tags for upload
|
34
|
+
const signedDataItem = createData(buffer, this.signer, {});
|
34
35
|
await signedDataItem.sign(this.signer);
|
35
|
-
return
|
36
|
+
return {
|
37
|
+
// while this returns a Buffer - it needs to match our return type for uploading
|
38
|
+
dataItemStreamFactory: () => signedDataItem.getRaw(),
|
39
|
+
dataItemSizeFactory: () => signedDataItem.getRaw().length,
|
40
|
+
};
|
36
41
|
}
|
37
42
|
// NOTE: this might be better in a parent class or elsewhere - easy enough to leave in here now and does require specific environment version of crypto
|
38
43
|
async generateSignedRequestHeaders() {
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (C) 2022-2023 Permanent Data Solutions, Inc. All Rights Reserved.
|
3
|
+
*
|
4
|
+
* This program is free software: you can redistribute it and/or modify
|
5
|
+
* it under the terms of the GNU Affero General Public License as published by
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
7
|
+
* (at your option) any later version.
|
8
|
+
*
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
* GNU Affero General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
15
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
*/
|
17
|
+
import { Currency } from '../types.js';
|
18
|
+
export interface CurrencyMap {
|
19
|
+
amount: number;
|
20
|
+
type: Currency;
|
21
|
+
}
|
22
|
+
export declare class ZeroDecimalCurrency implements CurrencyMap {
|
23
|
+
readonly amount: number;
|
24
|
+
readonly type: Currency;
|
25
|
+
constructor(amount: number, type: Currency);
|
26
|
+
}
|
27
|
+
export declare class TwoDecimalCurrency implements CurrencyMap {
|
28
|
+
private a;
|
29
|
+
readonly type: Currency;
|
30
|
+
constructor(a: number, type: Currency);
|
31
|
+
get amount(): number;
|
32
|
+
}
|
33
|
+
export declare const USD: (usd: number) => TwoDecimalCurrency;
|
34
|
+
export declare const EUR: (eur: number) => TwoDecimalCurrency;
|
35
|
+
export declare const GBP: (gbp: number) => TwoDecimalCurrency;
|
36
|
+
export declare const CAD: (cad: number) => TwoDecimalCurrency;
|
37
|
+
export declare const AUD: (aud: number) => TwoDecimalCurrency;
|
38
|
+
export declare const INR: (inr: number) => TwoDecimalCurrency;
|
39
|
+
export declare const SGD: (sgd: number) => TwoDecimalCurrency;
|
40
|
+
export declare const HKD: (hkd: number) => TwoDecimalCurrency;
|
41
|
+
export declare const BRL: (brl: number) => TwoDecimalCurrency;
|
42
|
+
export declare const JPY: (jpy: number) => ZeroDecimalCurrency;
|
43
|
+
//# sourceMappingURL=currency.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"currency.d.ts","sourceRoot":"","sources":["../../../src/common/currency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,qBAAa,mBAAoB,YAAW,WAAW;aAEnC,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,QAAQ;gBADd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ;CAEjC;AAED,qBAAa,kBAAmB,YAAW,WAAW;IAElD,OAAO,CAAC,CAAC;aACO,IAAI,EAAE,QAAQ;gBADtB,CAAC,EAAE,MAAM,EACD,IAAI,EAAE,QAAQ;IAGhC,IAAI,MAAM,WAET;CACF;AAGD,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AACvE,eAAO,MAAM,GAAG,QAAS,MAAM,uBAAuC,CAAC;AAGvE,eAAO,MAAM,GAAG,QAAS,MAAM,wBAAwC,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
|