@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.
Files changed (88) hide show
  1. package/.babelrc +1 -1
  2. package/.eslintrc +7 -7
  3. package/.husky/pre-commit +6 -0
  4. package/.nvmrc +1 -1
  5. package/README.md +22 -6
  6. package/lib/pinata-sdk.js +780 -604
  7. package/lib/pinata-sdk.min.js +5 -5
  8. package/package.json +83 -71
  9. package/src/commands/data/getFilesByCount/{getFilesByCount.js → getFilesByCount.ts} +9 -13
  10. package/src/commands/data/index.ts +4 -0
  11. package/src/commands/data/pinList/pinList.ts +77 -0
  12. package/src/commands/data/pinList/{queryBuilder.js → queryBuilder.ts} +6 -16
  13. package/src/commands/data/{testAuthentication.js → testAuthentication.ts} +10 -18
  14. package/src/commands/data/userPinnedDataTotal.ts +24 -0
  15. package/src/commands/pinning/{hashMetadata.js → hashMetadata.ts} +12 -21
  16. package/src/commands/pinning/index.ts +8 -0
  17. package/src/commands/pinning/{pinByHash.js → pinByHash.ts} +24 -20
  18. package/src/commands/pinning/{pinFileToIPFS.js → pinFileToIPFS.ts} +29 -24
  19. package/src/commands/pinning/{pinFromFS.js → pinFromFS.ts} +17 -39
  20. package/src/commands/pinning/{pinJSONToIPFS.js → pinJSONToIPFS.ts} +8 -20
  21. package/src/commands/pinning/pinJobs/pinJobs.ts +50 -0
  22. package/src/commands/pinning/pinJobs/{queryBuilder.js → queryBuilder.ts} +2 -8
  23. package/src/commands/pinning/{unpin.js → unpin.ts} +6 -19
  24. package/src/constants.ts +4 -0
  25. package/src/index.ts +120 -0
  26. package/src/third-party/base-path-converter.d.ts +3 -0
  27. package/src/third-party/is-ipfs.d.ts +5 -0
  28. package/src/third-party/recursive-fs.d.ts +5 -0
  29. package/src/util/{errorResponse.js → errorResponse.ts} +1 -1
  30. package/src/util/validators.ts +175 -0
  31. package/test/commands/data/getFilesByCount/{getFilesByCount.test.js → getFilesByCount.test.ts} +36 -39
  32. package/test/commands/data/pinList/pinList.test.ts +102 -0
  33. package/test/commands/data/pinList/{queryBuilder.test.js → queryBuilder.test.ts} +9 -10
  34. package/test/commands/data/pinlist-sample-api.ts +540 -0
  35. package/test/commands/data/testAuthentication.test.ts +34 -0
  36. package/test/commands/data/userPinnedDataTotal.test.ts +29 -0
  37. package/test/commands/pinning/hashMetadata.test.ts +76 -0
  38. package/test/commands/pinning/pinByHash.test.ts +46 -0
  39. package/test/commands/pinning/pinFileToIPFS.test.ts +53 -0
  40. package/test/commands/pinning/pinFromFS.ts +32 -0
  41. package/test/commands/pinning/pinJSONToIPFS.test.ts +42 -0
  42. package/test/commands/pinning/pinJobs/pinJobs.test.ts +29 -0
  43. package/test/commands/pinning/pinJobs/{queryBuilder.test.js → queryBuilder.test.ts} +5 -5
  44. package/test/commands/pinning/{unpin.test.js → unpin.test.ts} +9 -10
  45. package/test/util/{validators.test.js → validators.test.ts} +60 -18
  46. package/tsconfig.json +2 -2
  47. package/types/commands/data/getFilesByCount/getFilesByCount.d.ts +4 -2
  48. package/types/commands/data/index.d.ts +4 -0
  49. package/types/commands/data/pinList/pinList.d.ts +45 -8
  50. package/types/commands/data/pinList/queryBuilder.d.ts +1 -7
  51. package/types/commands/data/testAuthentication.d.ts +5 -7
  52. package/types/commands/data/userPinnedDataTotal.d.ts +2 -7
  53. package/types/commands/pinning/hashMetadata.d.ts +3 -9
  54. package/types/commands/pinning/hashPinPolicy.d.ts +1 -1
  55. package/types/commands/pinning/index.d.ts +8 -0
  56. package/types/commands/pinning/pinByHash.d.ts +14 -9
  57. package/types/commands/pinning/pinFileToIPFS.d.ts +25 -1
  58. package/types/commands/pinning/pinFromFS.d.ts +3 -9
  59. package/types/commands/pinning/pinJSONToIPFS.d.ts +3 -9
  60. package/types/commands/pinning/pinJobs/pinJobs.d.ts +20 -8
  61. package/types/commands/pinning/pinJobs/queryBuilder.d.ts +1 -7
  62. package/types/commands/pinning/unpin.d.ts +2 -8
  63. package/types/commands/pinning/userPinPolicy.d.ts +1 -1
  64. package/types/constants.d.ts +2 -1
  65. package/types/index.d.ts +38 -331
  66. package/types/util/errorResponse.d.ts +1 -1
  67. package/types/util/validators.d.ts +43 -26
  68. package/webpack.config.js +50 -53
  69. package/src/commands/data/pinList/pinList.js +0 -41
  70. package/src/commands/data/userPinnedDataTotal.js +0 -36
  71. package/src/commands/pinning/hashPinPolicy.js +0 -57
  72. package/src/commands/pinning/pinJobs/pinJobs.js +0 -42
  73. package/src/commands/pinning/userPinPolicy.js +0 -46
  74. package/src/constants.js +0 -1
  75. package/src/index.js +0 -262
  76. package/src/util/validators.js +0 -118
  77. package/test/commands/data/pinList/pinList.test.js +0 -98
  78. package/test/commands/data/pinlist-sample-api.js +0 -540
  79. package/test/commands/data/testAuthentication.test.js +0 -30
  80. package/test/commands/data/userPinnedDataTotal.test.js +0 -29
  81. package/test/commands/pinning/hashMetadata.test.js +0 -77
  82. package/test/commands/pinning/hashPinPolicy.test.js +0 -65
  83. package/test/commands/pinning/pinByHash.test.js +0 -47
  84. package/test/commands/pinning/pinFileToIPFS.test.js +0 -55
  85. package/test/commands/pinning/pinFromFS.js +0 -33
  86. package/test/commands/pinning/pinJSONToIPFS.test.js +0 -43
  87. package/test/commands/pinning/pinJobs/pinJobs.test.js +0 -29
  88. package/test/commands/pinning/userPinPolicy.test.js +0 -51
@@ -1,29 +1,23 @@
1
1
  import axios from 'axios';
2
- import { baseUrl } from './../../constants';
2
+ import { baseUrl } from '../../constants';
3
3
  import NodeFormData from 'form-data';
4
- import {validateApiKeys, validateMetadata, validatePinataOptions} from '../../util/validators';
4
+ import {createConfigForAxiosHeadersWithFormData, validateMetadata, validatePinataOptions} from '../../util/validators';
5
5
  import basePathConverter from 'base-path-converter';
6
6
  import { handleError } from '../../util/errorResponse';
7
- const fs = require('fs');
8
- const recursive = require('recursive-fs');
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
- fs.stat(sourcePath, (err, stats) => {
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
- withCredentials: true,
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
- let data = new NodeFormData();
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
- withCredentials: true,
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 './../../constants';
3
- import { validateApiKeys, validateMetadata, validatePinataOptions } from '../../util/validators';
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
- withCredentials: true,
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 './../../constants';
3
- import { validateApiKeys } from '../../util/validators';
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
- withCredentials: true,
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
  }
@@ -0,0 +1,4 @@
1
+ export const baseUrl = 'https://api.pinata.cloud';
2
+
3
+ export const ERROR_NO_CREDENTIALS_PROVIDED =
4
+ 'No credentials provided! Please provide your pinata api key and pinata secret api key or your pinata JWT key as an argument when you start this script';
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;
@@ -0,0 +1,3 @@
1
+ declare module 'base-path-converter' {
2
+ export default function(sourcePath: string, filePath: string): string;
3
+ }
@@ -0,0 +1,5 @@
1
+ declare module 'is-ipfs' {
2
+ export function cid (cid: string): boolean
3
+ export function isPeerMultiaddr(addr: string): boolean;
4
+ export function peerMultiaddr(addr: string): boolean;
5
+ }
@@ -0,0 +1,5 @@
1
+ declare module 'recursive-fs' {
2
+ export function readdirr(sourcePath: string, callback: (err: any, dirs: any, files: any) => void): void
3
+
4
+ }
5
+
@@ -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
+ }