@pinata/sdk 1.2.0 → 2.0.0-beta.0
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/.babelrc +1 -1
- package/.eslintrc +7 -7
- package/.husky/pre-commit +6 -0
- package/.nvmrc +1 -1
- package/README.md +22 -6
- package/lib/pinata-sdk.js +780 -604
- package/lib/pinata-sdk.min.js +5 -5
- package/package.json +83 -71
- package/src/commands/data/getFilesByCount/{getFilesByCount.js → getFilesByCount.ts} +9 -13
- package/src/commands/data/index.ts +4 -0
- package/src/commands/data/pinList/pinList.ts +77 -0
- package/src/commands/data/pinList/{queryBuilder.js → queryBuilder.ts} +6 -16
- package/src/commands/data/{testAuthentication.js → testAuthentication.ts} +10 -18
- package/src/commands/data/userPinnedDataTotal.ts +24 -0
- package/src/commands/pinning/{hashMetadata.js → hashMetadata.ts} +12 -21
- package/src/commands/pinning/index.ts +8 -0
- package/src/commands/pinning/{pinByHash.js → pinByHash.ts} +24 -20
- package/src/commands/pinning/{pinFileToIPFS.js → pinFileToIPFS.ts} +29 -24
- package/src/commands/pinning/{pinFromFS.js → pinFromFS.ts} +17 -39
- package/src/commands/pinning/{pinJSONToIPFS.js → pinJSONToIPFS.ts} +8 -20
- package/src/commands/pinning/pinJobs/pinJobs.ts +50 -0
- package/src/commands/pinning/pinJobs/{queryBuilder.js → queryBuilder.ts} +2 -8
- package/src/commands/pinning/{unpin.js → unpin.ts} +6 -19
- package/src/constants.ts +4 -0
- package/src/index.ts +120 -0
- package/src/third-party/base-path-converter.d.ts +3 -0
- package/src/third-party/is-ipfs.d.ts +5 -0
- package/src/third-party/recursive-fs.d.ts +5 -0
- package/src/util/{errorResponse.js → errorResponse.ts} +1 -1
- package/src/util/validators.ts +175 -0
- package/test/commands/data/getFilesByCount/{getFilesByCount.test.js → getFilesByCount.test.ts} +36 -39
- package/test/commands/data/pinList/pinList.test.ts +102 -0
- package/test/commands/data/pinList/{queryBuilder.test.js → queryBuilder.test.ts} +9 -10
- package/test/commands/data/pinlist-sample-api.ts +540 -0
- package/test/commands/data/testAuthentication.test.ts +34 -0
- package/test/commands/data/userPinnedDataTotal.test.ts +29 -0
- package/test/commands/pinning/hashMetadata.test.ts +76 -0
- package/test/commands/pinning/pinByHash.test.ts +46 -0
- package/test/commands/pinning/pinFileToIPFS.test.ts +53 -0
- package/test/commands/pinning/pinFromFS.ts +32 -0
- package/test/commands/pinning/pinJSONToIPFS.test.ts +42 -0
- package/test/commands/pinning/pinJobs/pinJobs.test.ts +29 -0
- package/test/commands/pinning/pinJobs/{queryBuilder.test.js → queryBuilder.test.ts} +5 -5
- package/test/commands/pinning/{unpin.test.js → unpin.test.ts} +9 -10
- package/test/util/{validators.test.js → validators.test.ts} +60 -18
- package/tsconfig.json +2 -2
- package/types/commands/data/getFilesByCount/getFilesByCount.d.ts +4 -2
- package/types/commands/data/index.d.ts +4 -0
- package/types/commands/data/pinList/pinList.d.ts +45 -8
- package/types/commands/data/pinList/queryBuilder.d.ts +1 -7
- package/types/commands/data/testAuthentication.d.ts +5 -7
- package/types/commands/data/userPinnedDataTotal.d.ts +2 -7
- package/types/commands/pinning/hashMetadata.d.ts +3 -9
- package/types/commands/pinning/hashPinPolicy.d.ts +1 -1
- package/types/commands/pinning/index.d.ts +8 -0
- package/types/commands/pinning/pinByHash.d.ts +14 -9
- package/types/commands/pinning/pinFileToIPFS.d.ts +25 -1
- package/types/commands/pinning/pinFromFS.d.ts +3 -9
- package/types/commands/pinning/pinJSONToIPFS.d.ts +3 -9
- package/types/commands/pinning/pinJobs/pinJobs.d.ts +20 -8
- package/types/commands/pinning/pinJobs/queryBuilder.d.ts +1 -7
- package/types/commands/pinning/unpin.d.ts +2 -8
- package/types/commands/pinning/userPinPolicy.d.ts +1 -1
- package/types/constants.d.ts +2 -1
- package/types/index.d.ts +38 -331
- package/types/util/errorResponse.d.ts +1 -1
- package/types/util/validators.d.ts +43 -26
- package/webpack.config.js +50 -53
- package/src/commands/data/pinList/pinList.js +0 -41
- package/src/commands/data/userPinnedDataTotal.js +0 -36
- package/src/commands/pinning/hashPinPolicy.js +0 -57
- package/src/commands/pinning/pinJobs/pinJobs.js +0 -42
- package/src/commands/pinning/userPinPolicy.js +0 -46
- package/src/constants.js +0 -1
- package/src/index.js +0 -262
- package/src/util/validators.js +0 -118
- package/test/commands/data/pinList/pinList.test.js +0 -98
- package/test/commands/data/pinlist-sample-api.js +0 -540
- package/test/commands/data/testAuthentication.test.js +0 -30
- package/test/commands/data/userPinnedDataTotal.test.js +0 -29
- package/test/commands/pinning/hashMetadata.test.js +0 -77
- package/test/commands/pinning/hashPinPolicy.test.js +0 -65
- package/test/commands/pinning/pinByHash.test.js +0 -47
- package/test/commands/pinning/pinFileToIPFS.test.js +0 -55
- package/test/commands/pinning/pinFromFS.js +0 -33
- package/test/commands/pinning/pinJSONToIPFS.test.js +0 -43
- package/test/commands/pinning/pinJobs/pinJobs.test.js +0 -29
- package/test/commands/pinning/userPinPolicy.test.js +0 -51
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { baseUrl } from '
|
|
2
|
+
import { baseUrl } from '../../constants';
|
|
3
3
|
import NodeFormData from 'form-data';
|
|
4
|
-
import {
|
|
4
|
+
import {createConfigForAxiosHeadersWithFormData, validateMetadata, validatePinataOptions} from '../../util/validators';
|
|
5
5
|
import basePathConverter from 'base-path-converter';
|
|
6
6
|
import { handleError } from '../../util/errorResponse';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { PinataConfig } from '../..';
|
|
8
|
+
import { PinataPinOptions, PinataPinResponse } from './pinFileToIPFS';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as recursive from 'recursive-fs';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
* PinFromFS
|
|
12
|
-
* @param {string} pinataApiKey
|
|
13
|
-
* @param {string} pinataSecretApiKey
|
|
14
|
-
* @param {string} sourcePath
|
|
15
|
-
* @param {*} options
|
|
16
|
-
* @returns {Promise<unknown>}
|
|
17
|
-
*/
|
|
18
|
-
export default function pinFromFS(pinataApiKey, pinataSecretApiKey, sourcePath, options) {
|
|
19
|
-
validateApiKeys(pinataApiKey, pinataSecretApiKey);
|
|
12
|
+
export default function pinFromFS(config: PinataConfig, sourcePath: string, options?: PinataPinOptions): Promise<PinataPinResponse> {
|
|
20
13
|
|
|
21
14
|
return new Promise((resolve, reject) => {
|
|
22
15
|
const endpoint = `${baseUrl}/pinning/pinFileToIPFS`;
|
|
23
16
|
|
|
24
|
-
|
|
17
|
+
// eslint-disable-next-line consistent-return
|
|
18
|
+
fs.stat(sourcePath, (err: any, stats: any) => {
|
|
25
19
|
if (err) {
|
|
26
|
-
reject(err);
|
|
20
|
+
return reject(err);
|
|
27
21
|
}
|
|
28
22
|
if (stats.isFile()) {
|
|
29
23
|
//we need to create a single read stream instead of reading the directory recursively
|
|
@@ -45,16 +39,8 @@ export default function pinFromFS(pinataApiKey, pinataSecretApiKey, sourcePath,
|
|
|
45
39
|
axios.post(
|
|
46
40
|
endpoint,
|
|
47
41
|
data,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
maxContentLength: 'Infinity', //this is needed to prevent axios from erroring out with large directories
|
|
51
|
-
maxBodyLength: 'Infinity',
|
|
52
|
-
headers: {
|
|
53
|
-
'Content-type': `multipart/form-data; boundary= ${data._boundary}`,
|
|
54
|
-
'pinata_api_key': pinataApiKey,
|
|
55
|
-
'pinata_secret_api_key': pinataSecretApiKey
|
|
56
|
-
}
|
|
57
|
-
}).then(function (result) {
|
|
42
|
+
createConfigForAxiosHeadersWithFormData(config, data.getBoundary()))
|
|
43
|
+
.then(function (result) {
|
|
58
44
|
if (result.status !== 200) {
|
|
59
45
|
reject(new Error(`unknown server response while pinning File to IPFS: ${result}`));
|
|
60
46
|
}
|
|
@@ -64,14 +50,14 @@ export default function pinFromFS(pinataApiKey, pinataSecretApiKey, sourcePath,
|
|
|
64
50
|
reject(formattedError);
|
|
65
51
|
});
|
|
66
52
|
} else {
|
|
67
|
-
recursive.readdirr(sourcePath, function (err, dirs, files) {
|
|
53
|
+
recursive.readdirr(sourcePath, function (err: any, dirs: any, files: any) {
|
|
68
54
|
if (err) {
|
|
69
55
|
reject(new Error(err));
|
|
70
56
|
}
|
|
71
57
|
|
|
72
|
-
|
|
58
|
+
const data = new NodeFormData();
|
|
73
59
|
|
|
74
|
-
files.forEach((file) => {
|
|
60
|
+
files.forEach((file: any) => {
|
|
75
61
|
//for each file stream, we need to include the correct relative file path
|
|
76
62
|
data.append('file', fs.createReadStream(file), {
|
|
77
63
|
filepath: basePathConverter(sourcePath, file)
|
|
@@ -92,16 +78,8 @@ export default function pinFromFS(pinataApiKey, pinataSecretApiKey, sourcePath,
|
|
|
92
78
|
axios.post(
|
|
93
79
|
endpoint,
|
|
94
80
|
data,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
maxContentLength: 'Infinity',
|
|
98
|
-
maxBodyLength: 'Infinity', //this is needed to prevent axios from erroring out with large directories
|
|
99
|
-
headers: {
|
|
100
|
-
'Content-type': `multipart/form-data; boundary= ${data._boundary}`,
|
|
101
|
-
'pinata_api_key': pinataApiKey,
|
|
102
|
-
'pinata_secret_api_key': pinataSecretApiKey
|
|
103
|
-
}
|
|
104
|
-
}).then(function (result) {
|
|
81
|
+
createConfigForAxiosHeadersWithFormData(config, data.getBoundary()))
|
|
82
|
+
.then(function (result) {
|
|
105
83
|
if (result.status !== 200) {
|
|
106
84
|
reject(new Error(`unknown server response while pinning File to IPFS: ${result}`));
|
|
107
85
|
}
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { baseUrl } from '
|
|
3
|
-
import {
|
|
2
|
+
import { baseUrl } from '../../constants';
|
|
3
|
+
import { createConfigForAxiosHeaders, validateMetadata, validatePinataOptions } from '../../util/validators';
|
|
4
4
|
import { handleError } from '../../util/errorResponse';
|
|
5
|
+
import { PinataConfig } from '../..';
|
|
6
|
+
import { PinataPinOptions, PinataPinResponse } from './pinFileToIPFS';
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
* Pin JSON to IPFS
|
|
8
|
-
* @param {string} pinataApiKey
|
|
9
|
-
* @param {string} pinataSecretApiKey
|
|
10
|
-
* @param {*} body
|
|
11
|
-
* @param {*} options
|
|
12
|
-
* @returns {Promise<unknown>}
|
|
13
|
-
*/
|
|
14
|
-
export default function pinJSONToIPFS(pinataApiKey, pinataSecretApiKey, body, options) {
|
|
15
|
-
validateApiKeys(pinataApiKey, pinataSecretApiKey);
|
|
8
|
+
export default function pinJSONToIPFS(config: PinataConfig, body: any, options? : PinataPinOptions):Promise<PinataPinResponse> {
|
|
16
9
|
|
|
17
|
-
let requestBody = body;
|
|
10
|
+
let requestBody: any = body;
|
|
18
11
|
|
|
19
12
|
if (typeof body !== 'object') {
|
|
20
13
|
throw new Error('body must be a valid JSON object');
|
|
@@ -40,13 +33,8 @@ export default function pinJSONToIPFS(pinataApiKey, pinataSecretApiKey, body, op
|
|
|
40
33
|
axios.post(
|
|
41
34
|
endpoint,
|
|
42
35
|
requestBody,
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
headers: {
|
|
46
|
-
'pinata_api_key': pinataApiKey,
|
|
47
|
-
'pinata_secret_api_key': pinataSecretApiKey
|
|
48
|
-
}
|
|
49
|
-
}).then(function (result) {
|
|
36
|
+
{...createConfigForAxiosHeaders(config)})
|
|
37
|
+
.then(function (result) {
|
|
50
38
|
if (result.status !== 200) {
|
|
51
39
|
reject(new Error(`unknown server response while pinning JSON to IPFS: ${result}`));
|
|
52
40
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { baseUrl } from '../../../constants';
|
|
3
|
+
import { createConfigForAxiosHeaders } from '../../../util/validators';
|
|
4
|
+
import queryBuilder from './queryBuilder';
|
|
5
|
+
import { handleError } from '../../../util/errorResponse';
|
|
6
|
+
import { PinataConfig } from '../../..';
|
|
7
|
+
|
|
8
|
+
export interface PinataPinJobsResponseRow {
|
|
9
|
+
id: number | string;
|
|
10
|
+
ipfs_pin_hash: string;
|
|
11
|
+
date_queued: string;
|
|
12
|
+
name: string | undefined | null;
|
|
13
|
+
status: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PinataPinJobsResponse {
|
|
16
|
+
count: number;
|
|
17
|
+
rows: PinataPinJobsResponseRow[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PinataPinJobsFilterOptions {
|
|
21
|
+
sort: 'ASC' | 'DESC';
|
|
22
|
+
status?: string | undefined;
|
|
23
|
+
ipfs_pin_hash?: string | undefined;
|
|
24
|
+
limit?: number | undefined;
|
|
25
|
+
offset?: number | undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function pinJobs(config: PinataConfig, filters? : PinataPinJobsFilterOptions): Promise<PinataPinJobsResponse> {
|
|
29
|
+
|
|
30
|
+
let endpoint = `${baseUrl}/pinning/pinJobs`;
|
|
31
|
+
|
|
32
|
+
if (filters) {
|
|
33
|
+
endpoint = queryBuilder(endpoint, filters);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
axios.get(
|
|
38
|
+
endpoint,
|
|
39
|
+
{...createConfigForAxiosHeaders(config)})
|
|
40
|
+
.then(function (result) {
|
|
41
|
+
if (result.status !== 200) {
|
|
42
|
+
reject(new Error(`unknown server response while attempting to retrieve pin jobs: ${result}`));
|
|
43
|
+
}
|
|
44
|
+
resolve(result.data);
|
|
45
|
+
}).catch(function (error) {
|
|
46
|
+
const formattedError = handleError(error);
|
|
47
|
+
reject(formattedError);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import isIPFS from 'is-ipfs';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* Query Buidler
|
|
5
|
-
* @param {string} baseUrl
|
|
6
|
-
* @param {*} filters
|
|
7
|
-
* @returns {*}
|
|
8
|
-
*/
|
|
9
|
-
export default function queryBuilder(baseUrl, filters) {
|
|
3
|
+
export default function queryBuilder(baseUrl: string, filters?: any): string {
|
|
10
4
|
if (!baseUrl) {
|
|
11
5
|
throw new Error('no baseUrl provided');
|
|
12
6
|
}
|
|
@@ -19,7 +13,7 @@ export default function queryBuilder(baseUrl, filters) {
|
|
|
19
13
|
|
|
20
14
|
let firstFilterApplied = false; // we want to make sure that the "?" character is only applied once
|
|
21
15
|
|
|
22
|
-
function addFilter(newFilter) {
|
|
16
|
+
function addFilter(newFilter: string) {
|
|
23
17
|
if (firstFilterApplied) {
|
|
24
18
|
newUrl = `${newUrl}&${newFilter}`;
|
|
25
19
|
} else {
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { baseUrl } from '
|
|
3
|
-
import {
|
|
2
|
+
import { baseUrl } from '../../constants';
|
|
3
|
+
import { createConfigForAxiosHeaders } from '../../util/validators';
|
|
4
4
|
import isIPFS from 'is-ipfs';
|
|
5
5
|
import { handleError } from '../../util/errorResponse';
|
|
6
|
+
import { PinataConfig } from '../..';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
* Unpin
|
|
9
|
-
* @param {string} pinataApiKey
|
|
10
|
-
* @param {string} pinataSecretApiKey
|
|
11
|
-
* @param {string} hashToUnpin
|
|
12
|
-
* @returns {Promise<unknown>}
|
|
13
|
-
*/
|
|
14
|
-
export default function unpin(pinataApiKey, pinataSecretApiKey, hashToUnpin) {
|
|
15
|
-
validateApiKeys(pinataApiKey, pinataSecretApiKey);
|
|
16
|
-
|
|
8
|
+
export default function unpin(config: PinataConfig, hashToUnpin: string) {
|
|
17
9
|
if (!hashToUnpin) {
|
|
18
10
|
throw new Error('hashToUnpin value is required for removing a pin from Pinata');
|
|
19
11
|
}
|
|
@@ -26,13 +18,8 @@ export default function unpin(pinataApiKey, pinataSecretApiKey, hashToUnpin) {
|
|
|
26
18
|
return new Promise((resolve, reject) => {
|
|
27
19
|
axios.delete(
|
|
28
20
|
endpoint,
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
headers: {
|
|
32
|
-
'pinata_api_key': pinataApiKey,
|
|
33
|
-
'pinata_secret_api_key': pinataSecretApiKey
|
|
34
|
-
}
|
|
35
|
-
}).then(function (result) {
|
|
21
|
+
{...createConfigForAxiosHeaders(config)})
|
|
22
|
+
.then(function (result) {
|
|
36
23
|
if (result.status !== 200) {
|
|
37
24
|
reject(new Error(`unknown server response while removing pin from IPFS: ${result}`));
|
|
38
25
|
}
|
package/src/constants.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import pinByHash, {
|
|
2
|
+
PinataPinByHashPinOptions
|
|
3
|
+
} from './commands/pinning/pinByHash';
|
|
4
|
+
import hashMetadata from './commands/pinning/hashMetadata';
|
|
5
|
+
import pinFileToIPFS, {
|
|
6
|
+
PinataPinOptions
|
|
7
|
+
} from './commands/pinning/pinFileToIPFS';
|
|
8
|
+
import pinFromFS from './commands/pinning/pinFromFS';
|
|
9
|
+
import pinJSONToIPFS from './commands/pinning/pinJSONToIPFS';
|
|
10
|
+
import pinJobs, {
|
|
11
|
+
PinataPinJobsFilterOptions
|
|
12
|
+
} from './commands/pinning/pinJobs/pinJobs';
|
|
13
|
+
import unpin from './commands/pinning/unpin';
|
|
14
|
+
import testAuthentication from './commands/data/testAuthentication';
|
|
15
|
+
import pinList, {
|
|
16
|
+
PinataMetadata,
|
|
17
|
+
PinataPinListFilterOptions
|
|
18
|
+
} from './commands/data/pinList/pinList';
|
|
19
|
+
import getFilesByCount from './commands/data/getFilesByCount/getFilesByCount';
|
|
20
|
+
import userPinnedDataTotal from './commands/data/userPinnedDataTotal';
|
|
21
|
+
|
|
22
|
+
export interface PinataConfig {
|
|
23
|
+
pinataApiKey?: string;
|
|
24
|
+
pinataSecretApiKey?: string;
|
|
25
|
+
pinataJWTKey?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function refactorConfig(pinataConfigParam: PinataConfig): PinataConfig {
|
|
29
|
+
const config: PinataConfig = {};
|
|
30
|
+
if (pinataConfigParam.pinataApiKey) {
|
|
31
|
+
config.pinataApiKey = pinataConfigParam.pinataApiKey;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (pinataConfigParam.pinataSecretApiKey) {
|
|
35
|
+
config.pinataSecretApiKey = pinataConfigParam.pinataSecretApiKey;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (pinataConfigParam.pinataJWTKey) {
|
|
39
|
+
config.pinataJWTKey = pinataConfigParam.pinataJWTKey;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return config;
|
|
43
|
+
}
|
|
44
|
+
function sanitizeConfig(
|
|
45
|
+
pinataApiKey?: string | PinataConfig,
|
|
46
|
+
pinataSecretApiKey?: string
|
|
47
|
+
): PinataConfig {
|
|
48
|
+
let config: PinataConfig = {};
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
typeof pinataApiKey === 'string' &&
|
|
52
|
+
typeof pinataSecretApiKey === 'string'
|
|
53
|
+
) {
|
|
54
|
+
config.pinataApiKey = pinataApiKey;
|
|
55
|
+
config.pinataSecretApiKey = pinataSecretApiKey;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const isPinataConfigParam = typeof pinataApiKey === 'object';
|
|
59
|
+
if (isPinataConfigParam) {
|
|
60
|
+
config = refactorConfig(pinataApiKey);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return config;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class PinataClient {
|
|
67
|
+
config: PinataConfig;
|
|
68
|
+
|
|
69
|
+
constructor(
|
|
70
|
+
pinataApiKey?: string | PinataConfig,
|
|
71
|
+
pinataSecretApiKey?: string
|
|
72
|
+
) {
|
|
73
|
+
this.config = sanitizeConfig(pinataApiKey, pinataSecretApiKey);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
pinByHash(hashToPin: string, options?: PinataPinByHashPinOptions) {
|
|
77
|
+
return pinByHash(this.config, hashToPin, options);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
hashMetadata(ipfsPinHash: string, metadata: PinataMetadata) {
|
|
81
|
+
return hashMetadata(this.config, ipfsPinHash, metadata);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pinFileToIPFS(readableStream: any, options?: PinataPinOptions) {
|
|
85
|
+
return pinFileToIPFS(this.config, readableStream, options);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pinFromFS(sourcePath: string, options?: PinataPinOptions) {
|
|
89
|
+
return pinFromFS(this.config, sourcePath, options);
|
|
90
|
+
}
|
|
91
|
+
pinJSONToIPFS(body: any, options?: PinataPinOptions) {
|
|
92
|
+
return pinJSONToIPFS(this.config, body, options);
|
|
93
|
+
}
|
|
94
|
+
pinJobs(filters?: PinataPinJobsFilterOptions) {
|
|
95
|
+
return pinJobs(this.config, filters);
|
|
96
|
+
}
|
|
97
|
+
unpin(hashToUnpin: string) {
|
|
98
|
+
return unpin(this.config, hashToUnpin);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pinList(filters: PinataPinListFilterOptions) {
|
|
102
|
+
return pinList(this.config, filters);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getFilesByCount(filters: PinataPinListFilterOptions, maxCount?: number) {
|
|
106
|
+
return getFilesByCount(this.config, filters, maxCount);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
testAuthentication() {
|
|
110
|
+
return testAuthentication(this.config);
|
|
111
|
+
}
|
|
112
|
+
userPinnedDataTotal() {
|
|
113
|
+
return userPinnedDataTotal(this.config);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export * from './commands/data';
|
|
118
|
+
export * from './commands/pinning';
|
|
119
|
+
|
|
120
|
+
export default PinataClient;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const handleError = (error) => {
|
|
1
|
+
export const handleError = (error : any) => {
|
|
2
2
|
if (error && error.response && error.response && error.response.data && error.response.data.error) {
|
|
3
3
|
return error.response.data.error;
|
|
4
4
|
} else if (error.data && error.data.error) {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import isIPFS from 'is-ipfs';
|
|
2
|
+
import { PinataConfig } from '..';
|
|
3
|
+
import { ERROR_NO_CREDENTIALS_PROVIDED} from '../constants';
|
|
4
|
+
|
|
5
|
+
export function validateApiKeys(pinataApiKey?: string, pinataSecretApiKey?: string) {
|
|
6
|
+
if (!pinataApiKey || pinataApiKey === '') {
|
|
7
|
+
throw new Error(
|
|
8
|
+
'No pinataApiKey provided! Please provide your pinata api key as an argument when you start this script'
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
if (!pinataSecretApiKey || pinataSecretApiKey === '') {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'No pinataSecretApiKey provided! Please provide your pinata secret api key as an argument when you start this script'
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createConfigForAxiosHeaders(config: PinataConfig) {
|
|
19
|
+
if (
|
|
20
|
+
config.pinataApiKey && config.pinataApiKey.length > 0 &&
|
|
21
|
+
config.pinataSecretApiKey && config.pinataSecretApiKey.length > 0
|
|
22
|
+
) {
|
|
23
|
+
return {
|
|
24
|
+
withCredentials: true,
|
|
25
|
+
headers: {
|
|
26
|
+
pinata_api_key: config.pinataApiKey,
|
|
27
|
+
pinata_secret_api_key: config.pinataSecretApiKey
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (config.pinataJWTKey && config.pinataJWTKey.length > 0) {
|
|
33
|
+
return {
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${config.pinataJWTKey}`
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
throw new Error(ERROR_NO_CREDENTIALS_PROVIDED);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createConfigForAxiosHeadersWithFormData(config: PinataConfig, boundaryValue: string) {
|
|
44
|
+
const requestOptions = {
|
|
45
|
+
...createConfigForAxiosHeaders(config),
|
|
46
|
+
maxContentLength: Infinity, //this is needed to prevent axios from erroring out with large files
|
|
47
|
+
maxBodyLength: Infinity,
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-type': `multipart/form-data; boundary= ${boundaryValue}`
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return requestOptions;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function validateHostNodes(hostNodes: any) {
|
|
57
|
+
if (!Array.isArray(hostNodes)) {
|
|
58
|
+
throw new Error('host_nodes value must be an array');
|
|
59
|
+
}
|
|
60
|
+
hostNodes.forEach((node) => {
|
|
61
|
+
if (!isIPFS.peerMultiaddr(node)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`host_node array entry: ${node} is not a valid peer multiaddr`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function validateMetadata(metadata: any) {
|
|
70
|
+
if (metadata.name) {
|
|
71
|
+
if (
|
|
72
|
+
!(
|
|
73
|
+
typeof metadata.name === 'string' ||
|
|
74
|
+
metadata.name instanceof String
|
|
75
|
+
)
|
|
76
|
+
) {
|
|
77
|
+
throw new Error('metadata name must be of type string');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (metadata.keyvalues) {
|
|
82
|
+
if (!(typeof metadata.keyvalues === 'object')) {
|
|
83
|
+
throw new Error('metatadata keyvalues must be an object');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let i = 0;
|
|
87
|
+
|
|
88
|
+
Object.entries(metadata.keyvalues).forEach(function (keyValue: any) {
|
|
89
|
+
if (i > 9) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
'No more than 10 keyvalues can be provided for metadata entries'
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
// we want to make sure that the input is a string, a boolean, or a number, so we don't get an object passed in by accident
|
|
95
|
+
if (
|
|
96
|
+
!(
|
|
97
|
+
typeof keyValue[1] === 'string' ||
|
|
98
|
+
typeof keyValue[1] === 'boolean' ||
|
|
99
|
+
!isNaN(keyValue[1])
|
|
100
|
+
)
|
|
101
|
+
) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
'Metadata keyvalue values must be strings, booleans, or numbers'
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
i++;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function validatePinPolicyStructure(pinPolicy: { regions: any[]; }) {
|
|
112
|
+
//this function takes in a pin policy and checks the JSON structure to make sure it's valid
|
|
113
|
+
if (!pinPolicy) {
|
|
114
|
+
throw new Error('No pin policy provided');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!pinPolicy.regions) {
|
|
118
|
+
throw new Error('No regions provided in pin policy');
|
|
119
|
+
}
|
|
120
|
+
if (pinPolicy.regions.length) {
|
|
121
|
+
pinPolicy.regions.forEach((region) => {
|
|
122
|
+
if (
|
|
123
|
+
!region.id ||
|
|
124
|
+
!(
|
|
125
|
+
Object.prototype.toString.call(region.id) ===
|
|
126
|
+
'[object String]'
|
|
127
|
+
)
|
|
128
|
+
) {
|
|
129
|
+
throw new Error('region id must be a string');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
!(
|
|
134
|
+
region.desiredReplicationCount ||
|
|
135
|
+
region.desiredReplicationCount === 0
|
|
136
|
+
) ||
|
|
137
|
+
!Number.isInteger(region.desiredReplicationCount)
|
|
138
|
+
) {
|
|
139
|
+
throw new Error('desiredReplicationCount must be an integer');
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function validatePinataOptions(options: { cidVersion?: number; wrapWithDirectory?: boolean; hostNodes?: any; customPinPolicy?: any; }) {
|
|
146
|
+
if (typeof options !== 'object') {
|
|
147
|
+
throw new Error('options must be an object');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.cidVersion) {
|
|
151
|
+
// eslint-disable-next-line eqeqeq
|
|
152
|
+
if (options.cidVersion != 0 && options.cidVersion != 1) {
|
|
153
|
+
throw new Error('unsupported or invalid cidVersion');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (options.wrapWithDirectory) {
|
|
157
|
+
// eslint-disable-next-line eqeqeq
|
|
158
|
+
if (
|
|
159
|
+
options.wrapWithDirectory !== true &&
|
|
160
|
+
options.wrapWithDirectory !== false
|
|
161
|
+
) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
'wrapWithDirectory must be a boolean value of true or false'
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (options.hostNodes) {
|
|
169
|
+
validateHostNodes(options.hostNodes);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (options.customPinPolicy) {
|
|
173
|
+
validatePinPolicyStructure(options.customPinPolicy);
|
|
174
|
+
}
|
|
175
|
+
}
|