@taqueria/plugin-ipfs-pinata 0.7.2-rc2 → 0.8.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 (3) hide show
  1. package/index.js +46 -46
  2. package/index.js.map +1 -1
  3. package/package.json +3 -3
package/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import {Plugin as $8CNkB$Plugin, Task as $8CNkB$Task, PositionalArg as $8CNkB$PositionalArg, sendJsonRes as $8CNkB$sendJsonRes, sendAsyncErr as $8CNkB$sendAsyncErr} from "@taqueria/node-sdk";
2
- import $8CNkB$path from "path";
1
+ import {Plugin as $khbt3$Plugin, Task as $khbt3$Task, PositionalArg as $khbt3$PositionalArg, sendJsonRes as $khbt3$sendJsonRes, sendAsyncErr as $khbt3$sendAsyncErr} from "@taqueria/node-sdk";
2
+ import $khbt3$path from "path";
3
3
  import "dotenv/config";
4
- import $8CNkB$fspromises from "fs/promises";
5
- import $8CNkB$formdata from "form-data";
6
- import $8CNkB$fs from "fs";
7
- import $8CNkB$ipfsonlyhash from "ipfs-only-hash";
8
- import $8CNkB$nodefetch from "node-fetch";
4
+ import $khbt3$fspromises from "fs/promises";
5
+ import $khbt3$formdata from "form-data";
6
+ import $khbt3$fs from "fs";
7
+ import $khbt3$ipfsonlyhash from "ipfs-only-hash";
8
+ import $khbt3$nodefetch from "node-fetch";
9
9
 
10
10
 
11
11
 
@@ -14,34 +14,34 @@ import $8CNkB$nodefetch from "node-fetch";
14
14
 
15
15
  // Async generator
16
16
  // https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
17
- async function* $362846282c87e345$var$getFiles(fileOrDirPath) {
18
- const dirInfo = await (0, $8CNkB$fspromises).stat(fileOrDirPath);
17
+ async function* $11f5d2da33680230$var$getFiles(fileOrDirPath) {
18
+ const dirInfo = await (0, $khbt3$fspromises).stat(fileOrDirPath);
19
19
  if (dirInfo.isFile()) {
20
20
  yield fileOrDirPath;
21
21
  return;
22
22
  }
23
- const dirents = await (0, $8CNkB$fspromises).readdir(fileOrDirPath, {
23
+ const dirents = await (0, $khbt3$fspromises).readdir(fileOrDirPath, {
24
24
  withFileTypes: true
25
25
  });
26
26
  for (const dirent of dirents){
27
- const res = (0, $8CNkB$path).resolve(fileOrDirPath, dirent.name);
28
- if (dirent.isDirectory()) yield* $362846282c87e345$var$getFiles(res);
27
+ const res = (0, $khbt3$path).resolve(fileOrDirPath, dirent.name);
28
+ if (dirent.isDirectory()) yield* $11f5d2da33680230$var$getFiles(res);
29
29
  else yield res;
30
30
  }
31
31
  }
32
- const $362846282c87e345$var$createFileProvider = async ({ fileOrDirPath: fileOrDirPath , filter: filter , shouldEstimateFileCount: shouldEstimateFileCount })=>{
33
- fileOrDirPath = (0, $8CNkB$path).resolve(fileOrDirPath);
34
- const pathInfo = await (0, $8CNkB$fspromises).stat(fileOrDirPath);
32
+ const $11f5d2da33680230$var$createFileProvider = async ({ fileOrDirPath: fileOrDirPath , filter: filter , shouldEstimateFileCount: shouldEstimateFileCount })=>{
33
+ fileOrDirPath = (0, $khbt3$path).resolve(fileOrDirPath);
34
+ const pathInfo = await (0, $khbt3$fspromises).stat(fileOrDirPath);
35
35
  if (!pathInfo.isFile() && !pathInfo.isDirectory()) throw new Error(`The path '${fileOrDirPath}' is not a file or directory`);
36
36
  let estimateFileCount = undefined;
37
37
  if (shouldEstimateFileCount) {
38
38
  estimateFileCount = 0;
39
- for await (const filePath of $362846282c87e345$var$getFiles(fileOrDirPath)){
39
+ for await (const filePath of $11f5d2da33680230$var$getFiles(fileOrDirPath)){
40
40
  if (filter && !filter(filePath)) continue;
41
41
  estimateFileCount++;
42
42
  }
43
43
  }
44
- const fileGenerator = $362846282c87e345$var$getFiles(fileOrDirPath);
44
+ const fileGenerator = $11f5d2da33680230$var$getFiles(fileOrDirPath);
45
45
  const getNextFile = async ()=>{
46
46
  let nextFile = (await fileGenerator.next()).value;
47
47
  if (!filter) return nextFile;
@@ -53,8 +53,8 @@ const $362846282c87e345$var$createFileProvider = async ({ fileOrDirPath: fileOrD
53
53
  estimateFileCount: estimateFileCount
54
54
  };
55
55
  };
56
- const $362846282c87e345$export$8f4b23801f8f7529 = async ({ fileOrDirPath: fileOrDirPath , processFile: processFile , filter: filter , parallelCount: parallelCount = 10 , onProgress: onProgress })=>{
57
- const { getNextFile: getNextFile , estimateFileCount: estimateFileCount } = await $362846282c87e345$var$createFileProvider({
56
+ const $11f5d2da33680230$export$8f4b23801f8f7529 = async ({ fileOrDirPath: fileOrDirPath , processFile: processFile , filter: filter , parallelCount: parallelCount = 10 , onProgress: onProgress })=>{
57
+ const { getNextFile: getNextFile , estimateFileCount: estimateFileCount } = await $11f5d2da33680230$var$createFileProvider({
58
58
  fileOrDirPath: fileOrDirPath,
59
59
  filter: filter,
60
60
  shouldEstimateFileCount: true
@@ -105,7 +105,7 @@ const $362846282c87e345$export$8f4b23801f8f7529 = async ({ fileOrDirPath: fileOr
105
105
 
106
106
 
107
107
 
108
- const $8299ce3b64e7f5fc$export$77ce72def6804f3 = async ({ auth: auth , item: item })=>{
108
+ const $3f348f69899f8bee$export$77ce72def6804f3 = async ({ auth: auth , item: item })=>{
109
109
  // The data api to check for existing file is limited to 30 requests per minute
110
110
  // While uploading allows 180 requests per minute
111
111
  // i.e. it's faster to just upload again
@@ -116,12 +116,12 @@ const $8299ce3b64e7f5fc$export$77ce72def6804f3 = async ({ auth: auth , item: ite
116
116
  // ipfsHash,
117
117
  // };
118
118
  // }
119
- const data = new (0, $8CNkB$formdata)();
120
- data.append("file", (0, $8CNkB$fs).createReadStream(item.filePath));
119
+ const data = new (0, $khbt3$formdata)();
120
+ data.append("file", (0, $khbt3$fs).createReadStream(item.filePath));
121
121
  data.append("pinataMetadata", JSON.stringify({
122
122
  name: item.name
123
123
  }));
124
- const response = await (0, $8CNkB$nodefetch)(`https://api.pinata.cloud/pinning/pinFileToIPFS`, {
124
+ const response = await (0, $khbt3$nodefetch)(`https://api.pinata.cloud/pinning/pinFileToIPFS`, {
125
125
  headers: {
126
126
  Authorization: `Bearer ${auth.pinataJwtToken}`,
127
127
  "Content-Type": `multipart/form-data; boundary=${data._boundary}`
@@ -135,9 +135,9 @@ const $8299ce3b64e7f5fc$export$77ce72def6804f3 = async ({ auth: auth , item: ite
135
135
  ipfsHash: uploadResult.IpfsHash
136
136
  };
137
137
  };
138
- const $8299ce3b64e7f5fc$var$checkIfFileIsPinned = async ({ auth: auth , item: item })=>{
139
- const ipfsHash = await (0, $8CNkB$ipfsonlyhash).of((0, $8CNkB$fs).createReadStream(item.filePath));
140
- const response = await (0, $8CNkB$nodefetch)(`https://api.pinata.cloud/data/pinList?status=pinned&hashContains=${ipfsHash}`, {
138
+ const $3f348f69899f8bee$var$checkIfFileIsPinned = async ({ auth: auth , item: item })=>{
139
+ const ipfsHash = await (0, $khbt3$ipfsonlyhash).of((0, $khbt3$fs).createReadStream(item.filePath));
140
+ const response = await (0, $khbt3$nodefetch)(`https://api.pinata.cloud/data/pinList?status=pinned&hashContains=${ipfsHash}`, {
141
141
  headers: {
142
142
  Authorization: `Bearer ${auth.pinataJwtToken}`
143
143
  },
@@ -153,12 +153,12 @@ const $8299ce3b64e7f5fc$var$checkIfFileIsPinned = async ({ auth: auth , item: it
153
153
  };
154
154
 
155
155
 
156
- async function $6b0ddb031a0df909$export$1391212d75b2ee65(timeout) {
156
+ async function $81b0536a41de4891$export$1391212d75b2ee65(timeout) {
157
157
  return await new Promise((resolve)=>{
158
158
  setTimeout(resolve, timeout);
159
159
  });
160
160
  }
161
- const $6b0ddb031a0df909$export$568be7ef485b9273 = ({ retryCount: retryCount = 5 , targetRequestsPerMinute: targetRequestsPerMinute = 180 })=>{
161
+ const $81b0536a41de4891$export$568be7ef485b9273 = ({ retryCount: retryCount = 5 , targetRequestsPerMinute: targetRequestsPerMinute = 180 })=>{
162
162
  let averageTimePerRequest = 5000;
163
163
  let targetTimePerRequest = 60000 / targetRequestsPerMinute;
164
164
  let lastTime = Date.now();
@@ -169,7 +169,7 @@ const $6b0ddb031a0df909$export$568be7ef485b9273 = ({ retryCount: retryCount = 5
169
169
  try {
170
170
  let delayTimeMs = Math.max(10, targetTimePerRequest - averageTimePerRequest);
171
171
  // Partially randomized delay to ensure parallel requests don't line up
172
- await $6b0ddb031a0df909$export$1391212d75b2ee65(Math.floor(delayTimeMs * (1 + 0.5 * Math.random())));
172
+ await $81b0536a41de4891$export$1391212d75b2ee65(Math.floor(delayTimeMs * (1 + 0.5 * Math.random())));
173
173
  const result = await process();
174
174
  const timeNow = Date.now();
175
175
  const timeElapsed = timeNow - lastTime;
@@ -194,25 +194,25 @@ const $6b0ddb031a0df909$export$568be7ef485b9273 = ({ retryCount: retryCount = 5
194
194
 
195
195
 
196
196
 
197
- const $b297f5d0aa12bc82$var$publishToIpfs = async (fileOrDirPath, auth)=>{
197
+ const $e26bf59b4820ce36$var$publishToIpfs = async (fileOrDirPath, auth)=>{
198
198
  if (!fileOrDirPath) throw new Error(`path was not provided`);
199
199
  // Pinata is limited to 180 requests per minute
200
200
  // So for the first 180 requests they can go fast
201
- const { processWithBackoff: processWithBackoff } = (0, $6b0ddb031a0df909$export$568be7ef485b9273)({
201
+ const { processWithBackoff: processWithBackoff } = (0, $81b0536a41de4891$export$568be7ef485b9273)({
202
202
  retryCount: 5,
203
203
  targetRequestsPerMinute: 180
204
204
  });
205
- const result = await (0, $362846282c87e345$export$8f4b23801f8f7529)({
205
+ const result = await (0, $11f5d2da33680230$export$8f4b23801f8f7529)({
206
206
  fileOrDirPath: fileOrDirPath,
207
207
  parallelCount: 10,
208
208
  processFile: async (filePath)=>{
209
209
  // // TEMP: Debug
210
210
  // console.log(`publishing: ${filePath}`);
211
- return processWithBackoff(()=>(0, $8299ce3b64e7f5fc$export$77ce72def6804f3)({
211
+ return processWithBackoff(()=>(0, $3f348f69899f8bee$export$77ce72def6804f3)({
212
212
  auth: auth,
213
213
  item: {
214
214
  filePath: filePath,
215
- name: (0, $8CNkB$path).basename(filePath)
215
+ name: (0, $khbt3$path).basename(filePath)
216
216
  }
217
217
  }));
218
218
  },
@@ -247,12 +247,12 @@ const $b297f5d0aa12bc82$var$publishToIpfs = async (fileOrDirPath, auth)=>{
247
247
  ]
248
248
  };
249
249
  };
250
- const $b297f5d0aa12bc82$var$pinToIpfs = async (hash, auth)=>{
250
+ const $e26bf59b4820ce36$var$pinToIpfs = async (hash, auth)=>{
251
251
  if (!hash) throw new Error(`ipfs hash was not provided`);
252
252
  // TODO: Implement pinning
253
253
  throw new Error("pinToIpfs: Not Implemented");
254
254
  };
255
- const $b297f5d0aa12bc82$var$execute = async (opts)=>{
255
+ const $e26bf59b4820ce36$var$execute = async (opts)=>{
256
256
  const { task: task , path: path , hash: hash , config: config , } = opts;
257
257
  const auth = {
258
258
  // TODO: Where should this be stored?
@@ -262,41 +262,41 @@ const $b297f5d0aa12bc82$var$execute = async (opts)=>{
262
262
  if (!auth.pinataJwtToken) throw new Error(`The 'credentials.pinataJwtToken' was not found in config`);
263
263
  switch(task){
264
264
  case "publish":
265
- return $b297f5d0aa12bc82$var$publishToIpfs(path, auth);
265
+ return $e26bf59b4820ce36$var$publishToIpfs(path, auth);
266
266
  case "pin":
267
- return $b297f5d0aa12bc82$var$pinToIpfs(hash, auth);
267
+ return $e26bf59b4820ce36$var$pinToIpfs(hash, auth);
268
268
  default:
269
269
  throw new Error(`${task} is not an understood task by the ipfs-pinata plugin`);
270
270
  }
271
271
  };
272
- var $b297f5d0aa12bc82$export$2e2bcd8739ae039 = async (args)=>{
272
+ var $e26bf59b4820ce36$export$2e2bcd8739ae039 = async (args)=>{
273
273
  const opts = args;
274
274
  try {
275
- const resultRaw = await $b297f5d0aa12bc82$var$execute(opts);
275
+ const resultRaw = await $e26bf59b4820ce36$var$execute(opts);
276
276
  // TODO: Fix deno parsing
277
277
  // Without this, `data.reduce is not a function`
278
278
  const result = "data" in resultRaw ? resultRaw.data : resultRaw;
279
- return (0, $8CNkB$sendJsonRes)(result);
279
+ return (0, $khbt3$sendJsonRes)(result);
280
280
  } catch (err) {
281
281
  const error = err;
282
- if (error.message) return (0, $8CNkB$sendAsyncErr)(error.message);
282
+ if (error.message) return (0, $khbt3$sendAsyncErr)(error.message);
283
283
  }
284
284
  };
285
285
 
286
286
 
287
- (0, $8CNkB$Plugin).create(()=>({
287
+ (0, $khbt3$Plugin).create(()=>({
288
288
  schema: "0.1",
289
289
  version: "0.4.0",
290
290
  alias: "pinata",
291
291
  tasks: [
292
- (0, $8CNkB$Task).create({
292
+ (0, $khbt3$Task).create({
293
293
  task: "publish",
294
294
  command: "publish [path]",
295
295
  description: "Upload and pin files using your pinata account.",
296
296
  aliases: [],
297
297
  handler: "proxy",
298
298
  positionals: [
299
- (0, $8CNkB$PositionalArg).create({
299
+ (0, $khbt3$PositionalArg).create({
300
300
  placeholder: "path",
301
301
  description: "Directory or file path to publish",
302
302
  type: "string"
@@ -305,7 +305,7 @@ var $b297f5d0aa12bc82$export$2e2bcd8739ae039 = async (args)=>{
305
305
  encoding: "json"
306
306
  }),
307
307
  ],
308
- proxy: $b297f5d0aa12bc82$export$2e2bcd8739ae039
308
+ proxy: $e26bf59b4820ce36$export$2e2bcd8739ae039
309
309
  }), process.argv);
310
310
 
311
311
 
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["index.ts","src/proxy.ts","src/file-processing.ts","src/pinata-api.ts","src/utils.ts"],"sourcesContent":["import { Option, Plugin, PositionalArg, Task } from '@taqueria/node-sdk';\nimport proxy from './src/proxy';\n\nPlugin.create(() => ({\n\tschema: '0.1',\n\tversion: '0.4.0',\n\talias: 'pinata',\n\ttasks: [\n\t\tTask.create({\n\t\t\ttask: 'publish',\n\t\t\tcommand: 'publish [path]',\n\t\t\tdescription: 'Upload and pin files using your pinata account.',\n\t\t\taliases: [],\n\t\t\thandler: 'proxy',\n\t\t\tpositionals: [\n\t\t\t\tPositionalArg.create({\n\t\t\t\t\tplaceholder: 'path',\n\t\t\t\t\tdescription: 'Directory or file path to publish',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t}),\n\t\t\t],\n\t\t\tencoding: 'json',\n\t\t}),\n\t\t// Pinning Not Implemented Yet\n\t\t// Task.create({\n\t\t// \ttask: 'pin',\n\t\t// \tcommand: 'pin [hash]',\n\t\t// \tdescription: 'Pin a file already on ipfs with your pinata account.',\n\t\t// \taliases: [],\n\t\t// \thandler: 'proxy',\n\t\t// \tpositionals: [\n\t\t// \t\tPositionalArg.create({\n\t\t// \t\t\tplaceholder: 'hash',\n\t\t// \t\t\tdescription: 'Ipfs hash of the file or directory that is already on the ipfs network.',\n\t\t// \t\t\ttype: 'string',\n\t\t// \t\t}),\n\t\t// \t]\n\t\t// }),\n\t],\n\tproxy,\n}), process.argv);\n","import { sendAsyncErr, sendAsyncRes, sendErr, sendJsonRes } from '@taqueria/node-sdk';\nimport { LoadedConfig, RequestArgs, SanitizedAbsPath } from '@taqueria/node-sdk/types';\nimport path from 'path';\nimport { processFiles } from './file-processing';\nimport { PinataAuth, publishFileToIpfs } from './pinata-api';\nimport { createProcessBackoffController } from './utils';\n\n// Load .env for jwt token\n// TODO: How should this be stored in a secure way?\nimport 'dotenv/config';\n\n// TODO: What should this be, it was removed from the sdk\ntype PluginResponse =\n\t| void\n\t| {\n\t\trender: 'table';\n\t\tdata: unknown[];\n\t};\n\ninterface Opts extends RequestArgs.ProxyRequestArgs {\n\treadonly path?: string;\n\treadonly hash?: string;\n}\n\nconst publishToIpfs = async (fileOrDirPath: undefined | string, auth: PinataAuth): Promise<PluginResponse> => {\n\tif (!fileOrDirPath) {\n\t\tthrow new Error(`path was not provided`);\n\t}\n\n\t// Pinata is limited to 180 requests per minute\n\t// So for the first 180 requests they can go fast\n\n\tconst { processWithBackoff } = createProcessBackoffController({\n\t\tretryCount: 5,\n\t\ttargetRequestsPerMinute: 180,\n\t});\n\n\tconst result = await processFiles({\n\t\tfileOrDirPath,\n\t\tparallelCount: 10,\n\t\tprocessFile: async filePath => {\n\t\t\t// // TEMP: Debug\n\t\t\t// console.log(`publishing: ${filePath}`);\n\n\t\t\treturn processWithBackoff(() =>\n\t\t\t\tpublishFileToIpfs({\n\t\t\t\t\tauth,\n\t\t\t\t\titem: { filePath, name: path.basename(filePath) },\n\t\t\t\t})\n\t\t\t);\n\t\t},\n\t\tonProgress: ({ processedFilesCount, estimateFileCount }) => {\n\t\t\tif (estimateFileCount && processedFilesCount % 10) {\n\t\t\t\tlet ratio = processedFilesCount / estimateFileCount;\n\t\t\t\tif (ratio > 1) ratio = 1;\n\n\t\t\t\t// // TODO: Call task sdk progress\n\t\t\t\t// console.log(`Progress: ${(ratio * 100).toFixed(0)}%`);\n\t\t\t}\n\t\t},\n\t});\n\n\t// // TEMP: DEBUG: Show error\n\t// if (result.failures.length) {\n\t// \tconsole.log('❗ Failures:\\n' + result.failures.map(f => `${f.filePath}: ${f.error}`).join('\\n'));\n\t// }\n\n\treturn {\n\t\trender: 'table',\n\t\tdata: [\n\t\t\t...result.failures.map(x => ({\n\t\t\t\t'?': '❌',\n\t\t\t\tfilePath: x.filePath,\n\t\t\t\tipfsHash: undefined,\n\t\t\t\terror: (x.error as { message?: string })?.message ?? JSON.stringify(x.error),\n\t\t\t})),\n\t\t\t...result.successes.map(x => ({\n\t\t\t\t'?': '✔',\n\t\t\t\tfilePath: x.filePath,\n\t\t\t\tipfsHash: x.result.ipfsHash,\n\t\t\t\terror: undefined,\n\t\t\t})),\n\t\t],\n\t};\n};\n\nconst pinToIpfs = async (hash: undefined | string, auth: PinataAuth): Promise<PluginResponse> => {\n\tif (!hash) {\n\t\tthrow new Error(`ipfs hash was not provided`);\n\t}\n\n\t// TODO: Implement pinning\n\tthrow new Error('pinToIpfs: Not Implemented');\n};\n\nconst execute = async (opts: Opts): Promise<PluginResponse> => {\n\tconst {\n\t\ttask,\n\t\tpath,\n\t\thash,\n\t\tconfig,\n\t} = opts;\n\n\tconst auth: PinataAuth = {\n\t\t// TODO: Where should this be stored?\n\t\t// pinataJwtToken: (config as Record<string, any>).credentials.pinataJwtToken,\n\t\tpinataJwtToken: process.env['pinataJwtToken'] as string,\n\t};\n\n\tif (!auth.pinataJwtToken) {\n\t\tthrow new Error(`The 'credentials.pinataJwtToken' was not found in config`);\n\t}\n\n\tswitch (task) {\n\t\tcase 'publish':\n\t\t\treturn publishToIpfs(path, auth);\n\t\tcase 'pin':\n\t\t\treturn pinToIpfs(hash, auth);\n\t\tdefault:\n\t\t\tthrow new Error(`${task} is not an understood task by the ipfs-pinata plugin`);\n\t}\n};\n\nexport default async (args: RequestArgs.ProxyRequestArgs): Promise<PluginResponse> => {\n\tconst opts = args as Opts;\n\n\ttry {\n\t\tconst resultRaw = await execute(opts) as Record<string, unknown>;\n\t\t// TODO: Fix deno parsing\n\t\t// Without this, `data.reduce is not a function`\n\t\tconst result = ('data' in resultRaw) ? resultRaw.data : resultRaw;\n\t\treturn sendJsonRes(result);\n\t} catch (err) {\n\t\tconst error = err as Error;\n\t\tif (error.message) {\n\t\t\treturn sendAsyncErr(error.message);\n\t\t}\n\t}\n};\n","import fs from 'fs/promises';\nimport path from 'path';\n\n// Async generator\n// https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search\nasync function* getFiles(fileOrDirPath: string): AsyncGenerator<string, void, unknown> {\n\tconst dirInfo = await fs.stat(fileOrDirPath);\n\tif (dirInfo.isFile()) {\n\t\tyield fileOrDirPath;\n\t\treturn;\n\t}\n\n\tconst dirents = await fs.readdir(fileOrDirPath, { withFileTypes: true });\n\tfor (const dirent of dirents) {\n\t\tconst res = path.resolve(fileOrDirPath, dirent.name);\n\t\tif (dirent.isDirectory()) {\n\t\t\tyield* getFiles(res);\n\t\t} else {\n\t\t\tyield res;\n\t\t}\n\t}\n}\n\nconst createFileProvider = async ({\n\tfileOrDirPath,\n\tfilter,\n\tshouldEstimateFileCount,\n}: {\n\tfileOrDirPath: string;\n\tfilter?: (filePath: string) => boolean;\n\tshouldEstimateFileCount?: boolean;\n}) => {\n\tfileOrDirPath = path.resolve(fileOrDirPath);\n\tconst pathInfo = await fs.stat(fileOrDirPath);\n\tif (\n\t\t!pathInfo.isFile()\n\t\t&& !pathInfo.isDirectory()\n\t) {\n\t\tthrow new Error(`The path '${fileOrDirPath}' is not a file or directory`);\n\t}\n\n\tlet estimateFileCount = undefined as undefined | number;\n\tif (shouldEstimateFileCount) {\n\t\testimateFileCount = 0;\n\t\tfor await (const filePath of getFiles(fileOrDirPath)) {\n\t\t\tif (filter && !filter(filePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\testimateFileCount++;\n\t\t}\n\t}\n\n\tconst fileGenerator = getFiles(fileOrDirPath);\n\tconst getNextFile = async () => {\n\t\tlet nextFile = (await fileGenerator.next()).value;\n\t\tif (!filter) {\n\t\t\treturn nextFile;\n\t\t}\n\n\t\twhile (nextFile && !filter(nextFile)) {\n\t\t\tnextFile = await getNextFile();\n\t\t}\n\n\t\treturn nextFile;\n\t};\n\treturn {\n\t\tgetNextFile,\n\t\testimateFileCount,\n\t};\n};\n\ntype ProgressInfo = { processedFilesCount: number; estimateFileCount: undefined | number };\nexport const processFiles = async <TResult>({\n\tfileOrDirPath,\n\tprocessFile,\n\tfilter,\n\tparallelCount = 10,\n\tonProgress,\n}: {\n\tfileOrDirPath: string;\n\tprocessFile: (filePath: string, progress: ProgressInfo) => Promise<TResult>;\n\tfilter?: (filePath: string) => boolean;\n\tparallelCount?: number;\n\tonProgress?: (progress: ProgressInfo) => void;\n}) => {\n\tconst { getNextFile, estimateFileCount } = await createFileProvider({\n\t\tfileOrDirPath,\n\t\tfilter,\n\t\tshouldEstimateFileCount: true,\n\t});\n\n\tconst successes = [] as { filePath: string; result: TResult }[];\n\tconst failures = [] as { filePath: string; error: unknown }[];\n\n\tonProgress?.({\n\t\tprocessedFilesCount: 0,\n\t\testimateFileCount,\n\t});\n\n\tawait Promise.all([...new Array(parallelCount)].map(async x => {\n\t\tlet fileToProcess = await getNextFile();\n\t\twhile (fileToProcess) {\n\t\t\tconst progressInfo = {\n\t\t\t\tprocessedFilesCount: successes.length + failures.length,\n\t\t\t\testimateFileCount,\n\t\t\t};\n\t\t\tonProgress?.(progressInfo);\n\n\t\t\ttry {\n\t\t\t\tconst result = await processFile(fileToProcess, progressInfo);\n\t\t\t\tsuccesses.push({ filePath: fileToProcess, result });\n\t\t\t} catch (err) {\n\t\t\t\tfailures.push({ filePath: fileToProcess, error: err });\n\t\t\t}\n\n\t\t\tfileToProcess = await getNextFile();\n\t\t}\n\t}));\n\n\tonProgress?.({\n\t\tprocessedFilesCount: successes.length + failures.length,\n\t\testimateFileCount,\n\t});\n\n\treturn {\n\t\tsuccesses,\n\t\tfailures,\n\t};\n};\n","import FormData from 'form-data';\nimport fs from 'fs';\nimport Hash from 'ipfs-only-hash';\nimport fetch from 'node-fetch';\n\nexport type PinataAuth = {\n\tpinataJwtToken: string;\n};\n\nexport type PublishFileResult = {\n\tipfsHash: string;\n};\n\nexport const publishFileToIpfs = async ({\n\tauth,\n\titem,\n}: {\n\tauth: PinataAuth;\n\titem: {\n\t\tname: string;\n\t\tfilePath: string;\n\t};\n}): Promise<PublishFileResult> => {\n\t// The data api to check for existing file is limited to 30 requests per minute\n\t// While uploading allows 180 requests per minute\n\t// i.e. it's faster to just upload again\n\n\t// // Skip if already pinned\n\t// const { isPinned, ipfsHash } = await checkIfFileIsPinned({ auth, item });\n\t// if (isPinned) {\n\t// \treturn {\n\t// \t\tipfsHash,\n\t// \t};\n\t// }\n\n\tconst data = new FormData();\n\tdata.append('file', fs.createReadStream(item.filePath));\n\tdata.append(\n\t\t'pinataMetadata',\n\t\tJSON.stringify({\n\t\t\tname: item.name,\n\t\t}),\n\t);\n\n\tconst response = await fetch(`https://api.pinata.cloud/pinning/pinFileToIPFS`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${auth.pinataJwtToken}`,\n\t\t\t'Content-Type': `multipart/form-data; boundary=${(data as unknown as { _boundary: string })._boundary}`,\n\t\t},\n\t\tbody: data,\n\t\tmethod: 'post',\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to upload '${item.name}' to ipfs ${response.statusText}`);\n\t}\n\n\tconst uploadResult = await response.json() as {\n\t\tIpfsHash: string; // This is the IPFS multi-hash provided back for your content,\n\t\tPinSize: string; // This is how large (in bytes) the content you just pinned is,\n\t\tTimestamp: string; // This is the timestamp for your content pinning (represented in ISO 8601 format)\n\t};\n\n\treturn {\n\t\tipfsHash: uploadResult.IpfsHash,\n\t};\n};\n\nconst checkIfFileIsPinned = async ({\n\tauth,\n\titem,\n}: {\n\tauth: PinataAuth;\n\titem: {\n\t\tname: string;\n\t\tfilePath: string;\n\t};\n}) => {\n\tconst ipfsHash = await Hash.of(fs.createReadStream(item.filePath));\n\n\tconst response = await fetch(`https://api.pinata.cloud/data/pinList?status=pinned&hashContains=${ipfsHash}`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${auth.pinataJwtToken}`,\n\t\t},\n\t\tmethod: 'get',\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to query '${item.name}' status from pinata ${response.statusText}`);\n\t}\n\n\tconst pinResult = await response.json() as {\n\t\tcount: number;\n\t\trows: {\n\t\t\tid: string;\n\t\t\tipfs_pin_hash: string;\n\t\t\tsize: number;\n\t\t\tuser_id: string;\n\t\t\tdate_pinned: null | string;\n\t\t\tdate_unpinned: null | string;\n\t\t\tmetadata: {\n\t\t\t\tname: string;\n\t\t\t\tkeyvalues: null | string;\n\t\t\t};\n\t\t\tregions: {\n\t\t\t\tregionId: string;\n\t\t\t\tcurrentReplicationCount: number;\n\t\t\t\tdesiredReplicationCount: number;\n\t\t\t}[];\n\t\t}[];\n\t};\n\n\tconst isPinned = pinResult.rows.some(x =>\n\t\tx.ipfs_pin_hash === ipfsHash\n\t\t&& x.date_pinned\n\t\t&& !x.date_unpinned\n\t);\n\n\treturn {\n\t\tisPinned,\n\t\tipfsHash,\n\t};\n};\n","export async function delay(timeout: number): Promise<void> {\n\treturn await new Promise(resolve => {\n\t\tsetTimeout(resolve, timeout);\n\t});\n}\n\nexport const createProcessBackoffController = ({\n\tretryCount = 5,\n\ttargetRequestsPerMinute = 180,\n}: {\n\tretryCount?: number;\n\ttargetRequestsPerMinute?: number;\n}) => {\n\tlet averageTimePerRequest = 5000;\n\tlet targetTimePerRequest = 60000 / targetRequestsPerMinute;\n\tlet lastTime = Date.now();\n\n\tconst processWithBackoff = async <TResult>(process: () => Promise<TResult>) => {\n\t\tlet attempt = 0;\n\t\tlet lastError = undefined as unknown;\n\t\twhile (attempt < retryCount) {\n\t\t\ttry {\n\t\t\t\tlet delayTimeMs = Math.max(10, targetTimePerRequest - averageTimePerRequest);\n\n\t\t\t\t// Partially randomized delay to ensure parallel requests don't line up\n\t\t\t\tawait delay(Math.floor(delayTimeMs * (1 + 0.5 * Math.random())));\n\n\t\t\t\tconst result = await process();\n\n\t\t\t\tconst timeNow = Date.now();\n\t\t\t\tconst timeElapsed = timeNow - lastTime;\n\t\t\t\tlastTime = timeNow;\n\n\t\t\t\t// Running average\n\t\t\t\taverageTimePerRequest = averageTimePerRequest * 0.97 + timeElapsed * 0.03;\n\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tlastError = err;\n\t\t\t}\n\n\t\t\t// Quickly increase time to wait if failure (allow negatives to wait longer than target)\n\t\t\taverageTimePerRequest -= (attempt + 1) * 1000;\n\t\t\tattempt++;\n\t\t}\n\n\t\t// All attempts failed\n\t\tthrow lastError;\n\t};\n\n\treturn {\n\t\tprocessWithBackoff,\n\t};\n};\n"],"names":[],"version":3,"file":"index.js.map","sourceRoot":"/"}
1
+ {"mappings":"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","sources":["taqueria-plugin-ipfs-pinata/index.ts","taqueria-plugin-ipfs-pinata/src/proxy.ts","taqueria-plugin-ipfs-pinata/src/file-processing.ts","taqueria-plugin-ipfs-pinata/src/pinata-api.ts","taqueria-plugin-ipfs-pinata/src/utils.ts"],"sourcesContent":["import { Option, Plugin, PositionalArg, Task } from '@taqueria/node-sdk';\nimport proxy from './src/proxy';\n\nPlugin.create(() => ({\n\tschema: '0.1',\n\tversion: '0.4.0',\n\talias: 'pinata',\n\ttasks: [\n\t\tTask.create({\n\t\t\ttask: 'publish',\n\t\t\tcommand: 'publish [path]',\n\t\t\tdescription: 'Upload and pin files using your pinata account.',\n\t\t\taliases: [],\n\t\t\thandler: 'proxy',\n\t\t\tpositionals: [\n\t\t\t\tPositionalArg.create({\n\t\t\t\t\tplaceholder: 'path',\n\t\t\t\t\tdescription: 'Directory or file path to publish',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t}),\n\t\t\t],\n\t\t\tencoding: 'json',\n\t\t}),\n\t\t// Pinning Not Implemented Yet\n\t\t// Task.create({\n\t\t// \ttask: 'pin',\n\t\t// \tcommand: 'pin [hash]',\n\t\t// \tdescription: 'Pin a file already on ipfs with your pinata account.',\n\t\t// \taliases: [],\n\t\t// \thandler: 'proxy',\n\t\t// \tpositionals: [\n\t\t// \t\tPositionalArg.create({\n\t\t// \t\t\tplaceholder: 'hash',\n\t\t// \t\t\tdescription: 'Ipfs hash of the file or directory that is already on the ipfs network.',\n\t\t// \t\t\ttype: 'string',\n\t\t// \t\t}),\n\t\t// \t]\n\t\t// }),\n\t],\n\tproxy,\n}), process.argv);\n","import { sendAsyncErr, sendAsyncRes, sendErr, sendJsonRes } from '@taqueria/node-sdk';\nimport { LoadedConfig, RequestArgs, SanitizedAbsPath } from '@taqueria/node-sdk/types';\nimport path from 'path';\nimport { processFiles } from './file-processing';\nimport { PinataAuth, publishFileToIpfs } from './pinata-api';\nimport { createProcessBackoffController } from './utils';\n\n// Load .env for jwt token\n// TODO: How should this be stored in a secure way?\nimport 'dotenv/config';\n\n// TODO: What should this be, it was removed from the sdk\ntype PluginResponse =\n\t| void\n\t| {\n\t\trender: 'table';\n\t\tdata: unknown[];\n\t};\n\ninterface Opts extends RequestArgs.ProxyRequestArgs {\n\treadonly path?: string;\n\treadonly hash?: string;\n}\n\nconst publishToIpfs = async (fileOrDirPath: undefined | string, auth: PinataAuth): Promise<PluginResponse> => {\n\tif (!fileOrDirPath) {\n\t\tthrow new Error(`path was not provided`);\n\t}\n\n\t// Pinata is limited to 180 requests per minute\n\t// So for the first 180 requests they can go fast\n\n\tconst { processWithBackoff } = createProcessBackoffController({\n\t\tretryCount: 5,\n\t\ttargetRequestsPerMinute: 180,\n\t});\n\n\tconst result = await processFiles({\n\t\tfileOrDirPath,\n\t\tparallelCount: 10,\n\t\tprocessFile: async filePath => {\n\t\t\t// // TEMP: Debug\n\t\t\t// console.log(`publishing: ${filePath}`);\n\n\t\t\treturn processWithBackoff(() =>\n\t\t\t\tpublishFileToIpfs({\n\t\t\t\t\tauth,\n\t\t\t\t\titem: { filePath, name: path.basename(filePath) },\n\t\t\t\t})\n\t\t\t);\n\t\t},\n\t\tonProgress: ({ processedFilesCount, estimateFileCount }) => {\n\t\t\tif (estimateFileCount && processedFilesCount % 10) {\n\t\t\t\tlet ratio = processedFilesCount / estimateFileCount;\n\t\t\t\tif (ratio > 1) ratio = 1;\n\n\t\t\t\t// // TODO: Call task sdk progress\n\t\t\t\t// console.log(`Progress: ${(ratio * 100).toFixed(0)}%`);\n\t\t\t}\n\t\t},\n\t});\n\n\t// // TEMP: DEBUG: Show error\n\t// if (result.failures.length) {\n\t// \tconsole.log('❗ Failures:\\n' + result.failures.map(f => `${f.filePath}: ${f.error}`).join('\\n'));\n\t// }\n\n\treturn {\n\t\trender: 'table',\n\t\tdata: [\n\t\t\t...result.failures.map(x => ({\n\t\t\t\t'?': '❌',\n\t\t\t\tfilePath: x.filePath,\n\t\t\t\tipfsHash: undefined,\n\t\t\t\terror: (x.error as { message?: string })?.message ?? JSON.stringify(x.error),\n\t\t\t})),\n\t\t\t...result.successes.map(x => ({\n\t\t\t\t'?': '✔',\n\t\t\t\tfilePath: x.filePath,\n\t\t\t\tipfsHash: x.result.ipfsHash,\n\t\t\t\terror: undefined,\n\t\t\t})),\n\t\t],\n\t};\n};\n\nconst pinToIpfs = async (hash: undefined | string, auth: PinataAuth): Promise<PluginResponse> => {\n\tif (!hash) {\n\t\tthrow new Error(`ipfs hash was not provided`);\n\t}\n\n\t// TODO: Implement pinning\n\tthrow new Error('pinToIpfs: Not Implemented');\n};\n\nconst execute = async (opts: Opts): Promise<PluginResponse> => {\n\tconst {\n\t\ttask,\n\t\tpath,\n\t\thash,\n\t\tconfig,\n\t} = opts;\n\n\tconst auth: PinataAuth = {\n\t\t// TODO: Where should this be stored?\n\t\t// pinataJwtToken: (config as Record<string, any>).credentials.pinataJwtToken,\n\t\tpinataJwtToken: process.env['pinataJwtToken'] as string,\n\t};\n\n\tif (!auth.pinataJwtToken) {\n\t\tthrow new Error(`The 'credentials.pinataJwtToken' was not found in config`);\n\t}\n\n\tswitch (task) {\n\t\tcase 'publish':\n\t\t\treturn publishToIpfs(path, auth);\n\t\tcase 'pin':\n\t\t\treturn pinToIpfs(hash, auth);\n\t\tdefault:\n\t\t\tthrow new Error(`${task} is not an understood task by the ipfs-pinata plugin`);\n\t}\n};\n\nexport default async (args: RequestArgs.ProxyRequestArgs): Promise<PluginResponse> => {\n\tconst opts = args as Opts;\n\n\ttry {\n\t\tconst resultRaw = await execute(opts) as Record<string, unknown>;\n\t\t// TODO: Fix deno parsing\n\t\t// Without this, `data.reduce is not a function`\n\t\tconst result = ('data' in resultRaw) ? resultRaw.data : resultRaw;\n\t\treturn sendJsonRes(result);\n\t} catch (err) {\n\t\tconst error = err as Error;\n\t\tif (error.message) {\n\t\t\treturn sendAsyncErr(error.message);\n\t\t}\n\t}\n};\n","import fs from 'fs/promises';\nimport path from 'path';\n\n// Async generator\n// https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search\nasync function* getFiles(fileOrDirPath: string): AsyncGenerator<string, void, unknown> {\n\tconst dirInfo = await fs.stat(fileOrDirPath);\n\tif (dirInfo.isFile()) {\n\t\tyield fileOrDirPath;\n\t\treturn;\n\t}\n\n\tconst dirents = await fs.readdir(fileOrDirPath, { withFileTypes: true });\n\tfor (const dirent of dirents) {\n\t\tconst res = path.resolve(fileOrDirPath, dirent.name);\n\t\tif (dirent.isDirectory()) {\n\t\t\tyield* getFiles(res);\n\t\t} else {\n\t\t\tyield res;\n\t\t}\n\t}\n}\n\nconst createFileProvider = async ({\n\tfileOrDirPath,\n\tfilter,\n\tshouldEstimateFileCount,\n}: {\n\tfileOrDirPath: string;\n\tfilter?: (filePath: string) => boolean;\n\tshouldEstimateFileCount?: boolean;\n}) => {\n\tfileOrDirPath = path.resolve(fileOrDirPath);\n\tconst pathInfo = await fs.stat(fileOrDirPath);\n\tif (\n\t\t!pathInfo.isFile()\n\t\t&& !pathInfo.isDirectory()\n\t) {\n\t\tthrow new Error(`The path '${fileOrDirPath}' is not a file or directory`);\n\t}\n\n\tlet estimateFileCount = undefined as undefined | number;\n\tif (shouldEstimateFileCount) {\n\t\testimateFileCount = 0;\n\t\tfor await (const filePath of getFiles(fileOrDirPath)) {\n\t\t\tif (filter && !filter(filePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\testimateFileCount++;\n\t\t}\n\t}\n\n\tconst fileGenerator = getFiles(fileOrDirPath);\n\tconst getNextFile = async () => {\n\t\tlet nextFile = (await fileGenerator.next()).value;\n\t\tif (!filter) {\n\t\t\treturn nextFile;\n\t\t}\n\n\t\twhile (nextFile && !filter(nextFile)) {\n\t\t\tnextFile = await getNextFile();\n\t\t}\n\n\t\treturn nextFile;\n\t};\n\treturn {\n\t\tgetNextFile,\n\t\testimateFileCount,\n\t};\n};\n\ntype ProgressInfo = { processedFilesCount: number; estimateFileCount: undefined | number };\nexport const processFiles = async <TResult>({\n\tfileOrDirPath,\n\tprocessFile,\n\tfilter,\n\tparallelCount = 10,\n\tonProgress,\n}: {\n\tfileOrDirPath: string;\n\tprocessFile: (filePath: string, progress: ProgressInfo) => Promise<TResult>;\n\tfilter?: (filePath: string) => boolean;\n\tparallelCount?: number;\n\tonProgress?: (progress: ProgressInfo) => void;\n}) => {\n\tconst { getNextFile, estimateFileCount } = await createFileProvider({\n\t\tfileOrDirPath,\n\t\tfilter,\n\t\tshouldEstimateFileCount: true,\n\t});\n\n\tconst successes = [] as { filePath: string; result: TResult }[];\n\tconst failures = [] as { filePath: string; error: unknown }[];\n\n\tonProgress?.({\n\t\tprocessedFilesCount: 0,\n\t\testimateFileCount,\n\t});\n\n\tawait Promise.all([...new Array(parallelCount)].map(async x => {\n\t\tlet fileToProcess = await getNextFile();\n\t\twhile (fileToProcess) {\n\t\t\tconst progressInfo = {\n\t\t\t\tprocessedFilesCount: successes.length + failures.length,\n\t\t\t\testimateFileCount,\n\t\t\t};\n\t\t\tonProgress?.(progressInfo);\n\n\t\t\ttry {\n\t\t\t\tconst result = await processFile(fileToProcess, progressInfo);\n\t\t\t\tsuccesses.push({ filePath: fileToProcess, result });\n\t\t\t} catch (err) {\n\t\t\t\tfailures.push({ filePath: fileToProcess, error: err });\n\t\t\t}\n\n\t\t\tfileToProcess = await getNextFile();\n\t\t}\n\t}));\n\n\tonProgress?.({\n\t\tprocessedFilesCount: successes.length + failures.length,\n\t\testimateFileCount,\n\t});\n\n\treturn {\n\t\tsuccesses,\n\t\tfailures,\n\t};\n};\n","import FormData from 'form-data';\nimport fs from 'fs';\nimport Hash from 'ipfs-only-hash';\nimport fetch from 'node-fetch';\n\nexport type PinataAuth = {\n\tpinataJwtToken: string;\n};\n\nexport type PublishFileResult = {\n\tipfsHash: string;\n};\n\nexport const publishFileToIpfs = async ({\n\tauth,\n\titem,\n}: {\n\tauth: PinataAuth;\n\titem: {\n\t\tname: string;\n\t\tfilePath: string;\n\t};\n}): Promise<PublishFileResult> => {\n\t// The data api to check for existing file is limited to 30 requests per minute\n\t// While uploading allows 180 requests per minute\n\t// i.e. it's faster to just upload again\n\n\t// // Skip if already pinned\n\t// const { isPinned, ipfsHash } = await checkIfFileIsPinned({ auth, item });\n\t// if (isPinned) {\n\t// \treturn {\n\t// \t\tipfsHash,\n\t// \t};\n\t// }\n\n\tconst data = new FormData();\n\tdata.append('file', fs.createReadStream(item.filePath));\n\tdata.append(\n\t\t'pinataMetadata',\n\t\tJSON.stringify({\n\t\t\tname: item.name,\n\t\t}),\n\t);\n\n\tconst response = await fetch(`https://api.pinata.cloud/pinning/pinFileToIPFS`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${auth.pinataJwtToken}`,\n\t\t\t'Content-Type': `multipart/form-data; boundary=${(data as unknown as { _boundary: string })._boundary}`,\n\t\t},\n\t\tbody: data,\n\t\tmethod: 'post',\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to upload '${item.name}' to ipfs ${response.statusText}`);\n\t}\n\n\tconst uploadResult = await response.json() as {\n\t\tIpfsHash: string; // This is the IPFS multi-hash provided back for your content,\n\t\tPinSize: string; // This is how large (in bytes) the content you just pinned is,\n\t\tTimestamp: string; // This is the timestamp for your content pinning (represented in ISO 8601 format)\n\t};\n\n\treturn {\n\t\tipfsHash: uploadResult.IpfsHash,\n\t};\n};\n\nconst checkIfFileIsPinned = async ({\n\tauth,\n\titem,\n}: {\n\tauth: PinataAuth;\n\titem: {\n\t\tname: string;\n\t\tfilePath: string;\n\t};\n}) => {\n\tconst ipfsHash = await Hash.of(fs.createReadStream(item.filePath));\n\n\tconst response = await fetch(`https://api.pinata.cloud/data/pinList?status=pinned&hashContains=${ipfsHash}`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${auth.pinataJwtToken}`,\n\t\t},\n\t\tmethod: 'get',\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to query '${item.name}' status from pinata ${response.statusText}`);\n\t}\n\n\tconst pinResult = await response.json() as {\n\t\tcount: number;\n\t\trows: {\n\t\t\tid: string;\n\t\t\tipfs_pin_hash: string;\n\t\t\tsize: number;\n\t\t\tuser_id: string;\n\t\t\tdate_pinned: null | string;\n\t\t\tdate_unpinned: null | string;\n\t\t\tmetadata: {\n\t\t\t\tname: string;\n\t\t\t\tkeyvalues: null | string;\n\t\t\t};\n\t\t\tregions: {\n\t\t\t\tregionId: string;\n\t\t\t\tcurrentReplicationCount: number;\n\t\t\t\tdesiredReplicationCount: number;\n\t\t\t}[];\n\t\t}[];\n\t};\n\n\tconst isPinned = pinResult.rows.some(x =>\n\t\tx.ipfs_pin_hash === ipfsHash\n\t\t&& x.date_pinned\n\t\t&& !x.date_unpinned\n\t);\n\n\treturn {\n\t\tisPinned,\n\t\tipfsHash,\n\t};\n};\n","export async function delay(timeout: number): Promise<void> {\n\treturn await new Promise(resolve => {\n\t\tsetTimeout(resolve, timeout);\n\t});\n}\n\nexport const createProcessBackoffController = ({\n\tretryCount = 5,\n\ttargetRequestsPerMinute = 180,\n}: {\n\tretryCount?: number;\n\ttargetRequestsPerMinute?: number;\n}) => {\n\tlet averageTimePerRequest = 5000;\n\tlet targetTimePerRequest = 60000 / targetRequestsPerMinute;\n\tlet lastTime = Date.now();\n\n\tconst processWithBackoff = async <TResult>(process: () => Promise<TResult>) => {\n\t\tlet attempt = 0;\n\t\tlet lastError = undefined as unknown;\n\t\twhile (attempt < retryCount) {\n\t\t\ttry {\n\t\t\t\tlet delayTimeMs = Math.max(10, targetTimePerRequest - averageTimePerRequest);\n\n\t\t\t\t// Partially randomized delay to ensure parallel requests don't line up\n\t\t\t\tawait delay(Math.floor(delayTimeMs * (1 + 0.5 * Math.random())));\n\n\t\t\t\tconst result = await process();\n\n\t\t\t\tconst timeNow = Date.now();\n\t\t\t\tconst timeElapsed = timeNow - lastTime;\n\t\t\t\tlastTime = timeNow;\n\n\t\t\t\t// Running average\n\t\t\t\taverageTimePerRequest = averageTimePerRequest * 0.97 + timeElapsed * 0.03;\n\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tlastError = err;\n\t\t\t}\n\n\t\t\t// Quickly increase time to wait if failure (allow negatives to wait longer than target)\n\t\t\taverageTimePerRequest -= (attempt + 1) * 1000;\n\t\t\tattempt++;\n\t\t}\n\n\t\t// All attempts failed\n\t\tthrow lastError;\n\t};\n\n\treturn {\n\t\tprocessWithBackoff,\n\t};\n};\n"],"names":[],"version":3,"file":"index.js.map","sourceRoot":"../"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taqueria/plugin-ipfs-pinata",
3
- "version": "0.7.2-rc2",
3
+ "version": "0.8.0",
4
4
  "description": "A plugin for Taqueria providing ipfs publishing and pinning using the Pinata service",
5
5
  "keywords": [
6
6
  "taqueria",
@@ -33,7 +33,7 @@
33
33
  "directory": "taqueria-plugin-ipfs-pinata"
34
34
  },
35
35
  "dependencies": {
36
- "@taqueria/node-sdk": "^0.7.0-rc1",
36
+ "@taqueria/node-sdk": "^0.8.0",
37
37
  "dotenv": "^16.0.0",
38
38
  "form-data": "^4.0.0",
39
39
  "ipfs-only-hash": "^4.0.0",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node-fetch": "^2.6.1",
44
- "parcel": "^2.6.0",
44
+ "parcel": "2.6.1",
45
45
  "typescript": "4.7.2"
46
46
  }
47
47
  }