diff --git a/.changeset/lucky-insects-reply.md b/.changeset/lucky-insects-reply.md new file mode 100644 index 00000000..92b9b44b --- /dev/null +++ b/.changeset/lucky-insects-reply.md @@ -0,0 +1,6 @@ +--- +"@demo/wallet": patch +"@bnb-chain/greenfield-js-sdk": patch +--- + +feat: Uploading progress diff --git a/examples/nextjs/src/components/feegrant/createObj.tsx b/examples/nextjs/src/components/feegrant/createObj.tsx index 905e6e14..cedc38f5 100644 --- a/examples/nextjs/src/components/feegrant/createObj.tsx +++ b/examples/nextjs/src/components/feegrant/createObj.tsx @@ -1,12 +1,16 @@ import { client } from '@/client'; import { ACCOUNT_PRIVATEKEY } from '@/config/env'; import { + bytesFromBase64, GRNToString, + Long, MsgCreateObjectTypeUrl, newBucketGRN, newObjectGRN, PermissionTypes, + RedundancyType, toTimestamp, + VisibilityType, } from '@bnb-chain/greenfield-js-sdk'; import { Wallet } from '@ethersproject/wallet'; import { ChangeEvent, useState } from 'react'; @@ -135,16 +139,16 @@ export const CreateObj = () => { creator: granteeAddr, bucketName: bucketName, objectName: objectName, - visibility: 'VISIBILITY_TYPE_PUBLIC_READ', - redundancyType: 'REDUNDANCY_EC_TYPE', - contentLength: fileBytes.byteLength, - expectCheckSums, - fileType: file.type, - }, - { - type: 'ECDSA', - privateKey: privateKey, + visibility: VisibilityType.VISIBILITY_TYPE_PRIVATE, + redundancyType: RedundancyType.REDUNDANCY_EC_TYPE, + payloadSize: Long.fromInt(fileBytes.byteLength), + expectChecksums: expectCheckSums.map((x) => bytesFromBase64(x)), + contentType: file.type, }, + // { + // type: 'ECDSA', + // privateKey: privateKey, + // }, ); const simulateInfo = await createObjectTx.simulate({ diff --git a/examples/nextjs/src/components/object/create/index.tsx b/examples/nextjs/src/components/object/create/index.tsx index 133b03e1..f0c3cde0 100644 --- a/examples/nextjs/src/components/object/create/index.tsx +++ b/examples/nextjs/src/components/object/create/index.tsx @@ -6,6 +6,7 @@ import { RedundancyType, VisibilityType, } from '@bnb-chain/greenfield-js-sdk'; +import { OnProgressEvent } from '@bnb-chain/greenfield-js-sdk/src/types/common'; import { ReedSolomon } from '@bnb-chain/reed-solomon'; import { ChangeEvent, useState } from 'react'; import { useAccount } from 'wagmi'; @@ -122,6 +123,9 @@ export const CreateObject = () => { body: file, txnHash: txHash, duration: 20000, + onProgress: (e: OnProgressEvent) => { + console.log('progress: ', e.percent); + }, }, { type: 'EDDSA', @@ -197,6 +201,9 @@ export const CreateObject = () => { delegatedOpts: { visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, }, + onProgress: (e: OnProgressEvent) => { + console.log('progress: ', e.percent); + }, }, { type: 'EDDSA', @@ -230,6 +237,7 @@ export const CreateObject = () => { bucketName: createObjectInfo.bucketName, objectName: createObjectInfo.objectName, body: file, + timeout: 20000, delegatedOpts: { visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, }, diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index 183e0869..6ee4a252 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -80,7 +80,9 @@ "lodash.set": "^4.3.2", "lodash.sortby": "^4.7.0", "long": "^5.2.1", + "mime-types": "^2.1.35", "reflect-metadata": "^0.1.13", + "superagent": "^8.1.2", "tsyringe": "^4.8.0" }, "devDependencies": { @@ -93,6 +95,8 @@ "@types/lodash.set": "^4.3.7", "@types/lodash.sortby": "^4.7.7", "@types/mime": "^3.0.1", + "@types/mime-types": "^2.1.4", + "@types/superagent": "^8.1.6", "@types/xml2js": "^0.4.11", "dotenv": "^16.0.3", "jest": "^29.5.0", diff --git a/packages/js-sdk/rollup.config.js b/packages/js-sdk/rollup.config.js index 9c6c0651..a4053398 100644 --- a/packages/js-sdk/rollup.config.js +++ b/packages/js-sdk/rollup.config.js @@ -52,7 +52,7 @@ export default async () => { ], }, { - input: './src/index.ts', + input: ['./src/index.ts', './src/node/adapter.ts'], output: { dir: './dist/cjs', format: 'cjs', diff --git a/packages/js-sdk/src/api/objects.ts b/packages/js-sdk/src/api/objects.ts index 85dfa717..471df8ef 100644 --- a/packages/js-sdk/src/api/objects.ts +++ b/packages/js-sdk/src/api/objects.ts @@ -1,24 +1,5 @@ -import { - getDelegatedCreateFolderMetaInfo, - parseDelegatedCreateFolderResponse, -} from '@/clients/spclient/spApis/delegatedCreateFolder'; -import { - getObjectOffsetInfo, - parseObjectOffsetResponse, -} from '@/clients/spclient/spApis/getObjectOffset'; -import { - getObjectStatusInfo, - parseObjectStatusResponse, -} from '@/clients/spclient/spApis/getObjectStatus'; import { getResumablePutObjectMetaInfo } from '@/clients/spclient/spApis/resumablePutObject'; -import { DelegatedOpts } from '@/types/sp/Common'; -import { - DelegateCreateFolderRepsonse, - DelegatedCreateFolderRequest, -} from '@/types/sp/DelegateCreateFolder'; -import { DelegatedPubObjectRequest } from '@/types/sp/DelegatedPubObject'; -import { UploadProgressResponse } from '@/types/sp/UploadProgress'; -import { assertAuthType, assertStringRequire } from '@/utils/asserts/params'; +import { DelegatedOpts, UploadFile } from '@/types/sp/Common'; import { ActionType, Principal, @@ -56,16 +37,28 @@ import { } from '..'; import { RpcQueryClient } from '../clients/queryclient'; import { + HTTPHeaderRegPubKey, encodePath, getAuthorization, getSortQuery, - HTTPHeaderRegPubKey, } from '../clients/spclient/auth'; +import { + getDelegatedCreateFolderMetaInfo, + parseDelegatedCreateFolderResponse, +} from '../clients/spclient/spApis/delegatedCreateFolder'; import { getGetObjectMetaInfo } from '../clients/spclient/spApis/getObject'; import { getObjectMetaInfo, parseGetObjectMetaResponse, } from '../clients/spclient/spApis/getObjectMeta'; +import { + getObjectOffsetInfo, + parseObjectOffsetResponse, +} from '../clients/spclient/spApis/getObjectOffset'; +import { + getObjectStatusInfo, + parseObjectStatusResponse, +} from '../clients/spclient/spApis/getObjectStatus'; import { getListObjectPoliciesMetaInfo, parseGetListObjectPoliciesResponse, @@ -94,14 +87,22 @@ import { ListObjectsByIDsResponse, Long, ObjectStatus, + OnProgress, SpResponse, TxResponse, UploadOffsetResponse, } from '../types'; +import { + DelegateCreateFolderRepsonse, + DelegatedCreateFolderRequest, +} from '../types/sp/DelegateCreateFolder'; +import { DelegatedPubObjectRequest } from '../types/sp/DelegatedPubObject'; import { GetObjectRequest } from '../types/sp/GetObject'; import { GetObjectMetaRequest, GetObjectMetaResponse } from '../types/sp/GetObjectMeta'; import { ListObjectsByBucketNameResponse } from '../types/sp/ListObjectsByBucketName'; import { PutObjectRequest } from '../types/sp/PutObject'; +import { UploadProgressResponse } from '../types/sp/UploadProgress'; +import { assertAuthType, assertFileType, assertStringRequire } from '../utils/asserts/params'; import { checkObjectName, generateUrlByBucketName, @@ -249,7 +250,15 @@ export class Objects implements IObject { } public async delegateUploadObject(params: DelegatedPubObjectRequest, authType: AuthType) { - const { bucketName, objectName, body, resumableOpts, timeout = 30000, delegatedOpts } = params; + const { + bucketName, + objectName, + body, + resumableOpts, + timeout = 30000, + delegatedOpts, + onProgress, + } = params; assertAuthType(authType); verifyBucketName(bucketName); @@ -280,8 +289,9 @@ export class Objects implements IObject { body, authType, delegatedOpts, - timeout, + duration: timeout, txnHash: '', + onProgress, }); } @@ -292,6 +302,7 @@ export class Objects implements IObject { body, partSize, authType, + timeout, delegatedOpts, ); } @@ -300,7 +311,7 @@ export class Objects implements IObject { params: PutObjectRequest, authType: AuthType, ): Promise> { - const { bucketName, objectName, body, duration = 30000, resumableOpts } = params; + const { bucketName, objectName, body, duration = 30000, resumableOpts, onProgress } = params; assertAuthType(authType); verifyBucketName(bucketName); verifyObjectName(objectName); @@ -341,7 +352,8 @@ export class Objects implements IObject { body, txnHash, authType, - timeout: duration, + duration, + onProgress, }); } @@ -352,6 +364,7 @@ export class Objects implements IObject { body, partSize, authType, + duration, ); } @@ -359,24 +372,26 @@ export class Objects implements IObject { endpoint: string; bucketName: string; objectName: string; - body: File; + body: UploadFile; txnHash: string; authType: AuthType; delegatedOpts?: DelegatedOpts; - timeout: number; + duration: number; + onProgress?: OnProgress; }): Promise> { const { authType, body, bucketName, delegatedOpts, - timeout: duration, + duration, endpoint, objectName, txnHash, + onProgress, } = params; - const { reqMeta, optionsWithOutHeaders, url } = await getPutObjectMetaInfo(endpoint, { + const { reqMeta, optionsWithOutHeaders, url, file } = await getPutObjectMetaInfo(endpoint, { bucketName, objectName, contentType: body.type, @@ -387,14 +402,19 @@ export class Objects implements IObject { const signHeaders = await this.spClient.signHeaders(reqMeta, authType); try { - const result = await this.spClient.callApi( + const result = await this.spClient.upload( url, { ...optionsWithOutHeaders, headers: signHeaders, }, duration, + file, + { + onProgress, + }, ); + const { status } = result; return { code: 0, message: 'Put object success.', statusCode: status }; @@ -426,9 +446,10 @@ export class Objects implements IObject { endpoint: string, bucketName: string, objectName: string, - body: File, + body: UploadFile, partSize: number, authType: AuthType, + timeout: number, delegatedOpts?: DelegatedOpts, ) { let offset = 0; @@ -444,11 +465,12 @@ export class Objects implements IObject { const { totalPartsCount } = this.splitPartInfo(body.size, partSize); // split file + const file = assertFileType(body) ? body.content : body; const chunks = []; for (let i = 0; i < totalPartsCount; i++) { const start = i * partSize; const end = Math.min(start + partSize, body.size); - const chunk = body.slice(start, end); + const chunk = file.slice(start, end); chunks.push(chunk); } @@ -478,7 +500,7 @@ export class Objects implements IObject { ...optionsWithOutHeaders, headers: signHeaders, }, - 30000, + timeout, ); } catch (error: any) { return { @@ -918,7 +940,7 @@ export class Objects implements IObject { const signHeaders = await this.spClient.signHeaders(reqMeta, authType); try { - const result = await this.spClient.callApi( + const result = await this.spClient.callApiV2( url, { ...optionsWithOutHeaders, @@ -928,7 +950,8 @@ export class Objects implements IObject { ); const { status } = result; - const xmlData = await result.text(); + //@ts-ignore + const xmlData = result.text; const res = parseDelegatedCreateFolderResponse(xmlData); return { code: 0, message: 'Create folder success.', statusCode: status, body: res }; diff --git a/packages/js-sdk/src/clients/spclient/spApis/putObject.ts b/packages/js-sdk/src/clients/spclient/spApis/putObject.ts index f45fd687..6bd00f74 100644 --- a/packages/js-sdk/src/clients/spclient/spApis/putObject.ts +++ b/packages/js-sdk/src/clients/spclient/spApis/putObject.ts @@ -1,5 +1,6 @@ import { EMPTY_STRING_SHA256, METHOD_PUT } from '@/constants'; import { ReqMeta, VisibilityType } from '@/types'; +import { UploadFile } from '@/types/sp/Common'; import { generateUrlByBucketName } from '@/utils/asserts/s3'; import { encodePath, getSortQueryParams } from '../auth'; @@ -10,7 +11,7 @@ export const getPutObjectMetaInfo = async ( objectName: string; bucketName: string; contentType: string; - body: File; + body: UploadFile; txnHash?: string; delegatedOpts?: { visibility: VisibilityType; @@ -48,12 +49,12 @@ export const getPutObjectMetaInfo = async ( const optionsWithOutHeaders: Omit = { method: METHOD_PUT, - body, }; return { url: url.href, optionsWithOutHeaders, reqMeta, + file: body, }; }; diff --git a/packages/js-sdk/src/clients/spclient/spClient.ts b/packages/js-sdk/src/clients/spclient/spClient.ts index 6765813e..92ce675a 100644 --- a/packages/js-sdk/src/clients/spclient/spClient.ts +++ b/packages/js-sdk/src/clients/spclient/spClient.ts @@ -9,13 +9,17 @@ import { } from '@/clients/spclient/auth'; import { parseError } from '@/clients/spclient/spApis/parseError'; import { SP_NOT_AVAILABLE_ERROR_CODE, SP_NOT_AVAILABLE_ERROR_MSG } from '@/constants/http'; +import { OnProgress } from '@/types'; import { AuthType, ReqMeta } from '@/types/auth'; import { fetchWithTimeout } from '@/utils/http'; +import { hexlify } from '@ethersproject/bytes'; +import { ed25519 } from '@noble/curves/ed25519'; +import superagent from 'superagent'; import { injectable } from 'tsyringe'; import { getGetObjectMetaInfo } from './spApis/getObject'; import { getPutObjectMetaInfo } from './spApis/putObject'; -import { ed25519 } from '@noble/curves/ed25519'; -import { hexlify } from '@ethersproject/bytes'; +import { assertFileType, assertHttpMethod } from '@/utils'; +import { UploadFile } from '@/types/sp/Common'; export interface ISpClient { callApi( @@ -97,6 +101,130 @@ export class SpClient implements ISpClient { } } + public async callApiV2( + url: string, + options: RequestInit, + timeout = 30000, + customError?: { + message: string; + code: number; + }, + ) { + assertHttpMethod(options.method); + + try { + const R = new superagent.Request(options.method, url); + if (options.headers) { + (options.headers as Headers).forEach((v: string, k: string) => { + R.set(k, v); + }); + } + R.timeout(timeout); + R.ok((res) => res.status < 500); + + const response = await R.send(); + const { status } = response; + + if (status === SP_NOT_AVAILABLE_ERROR_CODE) { + throw { + code: SP_NOT_AVAILABLE_ERROR_CODE, + message: SP_NOT_AVAILABLE_ERROR_MSG, + statusCode: status, + }; + } + + if (!response.ok) { + const xmlError = response.text; + const { code, message } = await parseError(xmlError); + + throw { + code: code || customError?.code, + message: message || customError?.message, + statusCode: status, + }; + } + + return response; + } catch (error) { + return Promise.reject(error); + } + } + + /** + * just use for uploading object: + * because fetch can't support upload progress + */ + public async upload( + url: string, + options: RequestInit, + timeout: number, + uploadFile: UploadFile, + callback?: { + onProgress?: OnProgress; + customError?: { + message: string; + code: number; + }; + }, + ) { + const R = superagent.put(url); + R.timeout(timeout); + R.ok((res) => res.status < 500); + + if (options.headers) { + (options.headers as Headers).forEach((v: string, k: string) => { + R.set(k, v); + }); + } + + try { + const R = superagent.put(url); + R.buffer(true); + R.timeout(timeout); + R.ok((res) => res.status < 500); + + if (options.headers) { + (options.headers as Headers).forEach((v: string, k: string) => { + R.set(k, v); + }); + } + + if (callback && callback.onProgress) { + R.on('progress', (e) => { + callback.onProgress?.(e); + }); + } + + const file = assertFileType(uploadFile) ? uploadFile.content : uploadFile; + const response = await R.send(file); + const { status } = response; + + if (status === SP_NOT_AVAILABLE_ERROR_CODE) { + throw { + code: SP_NOT_AVAILABLE_ERROR_CODE, + message: SP_NOT_AVAILABLE_ERROR_MSG, + statusCode: status, + }; + } + + if (!response.ok) { + const xmlError = response.text; + + const { code, message } = await parseError(xmlError); + + throw { + code: callback?.customError?.code || code, + message: callback?.customError?.message || message, + statusCode: status, + }; + } + + return response; + } catch (error) { + return Promise.reject(error); + } + } + public async signHeaders(reqMeta: Partial, authType: AuthType) { const metaHeaders: Headers = newRequestHeadersByMeta(reqMeta); diff --git a/packages/js-sdk/src/node/adapter.ts b/packages/js-sdk/src/node/adapter.ts new file mode 100644 index 00000000..5f5d9af2 --- /dev/null +++ b/packages/js-sdk/src/node/adapter.ts @@ -0,0 +1,21 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import mimeTypes from 'mime-types'; +import { NodeFile } from '@/types/sp/Common'; + +export function createFile(filePath: string): NodeFile { + const stats = fs.statSync(filePath); + const fileSize = stats.size; + + const extname = path.extname(filePath); + const type = mimeTypes.lookup(extname); + + if (!type) throw new Error(`Unsupported file type: ${filePath}`); + + return { + name: filePath, + type, + size: fileSize, + content: fs.readFileSync(filePath), + }; +} diff --git a/packages/js-sdk/src/types/common.ts b/packages/js-sdk/src/types/common.ts index 57dcb12b..cb7e648a 100644 --- a/packages/js-sdk/src/types/common.ts +++ b/packages/js-sdk/src/types/common.ts @@ -10,3 +10,11 @@ export { } from '@bnb-chain/greenfield-cosmos-types/greenfield/storage/common'; export { Long }; import Long from 'long'; + +export type OnProgressEvent = { + direction: string; + percent: number; + total: number; + loaded: number; +}; +export type OnProgress = (event: OnProgressEvent) => void; diff --git a/packages/js-sdk/src/types/sp/Common.ts b/packages/js-sdk/src/types/sp/Common.ts index 921f2901..348231dc 100644 --- a/packages/js-sdk/src/types/sp/Common.ts +++ b/packages/js-sdk/src/types/sp/Common.ts @@ -334,3 +334,11 @@ export type ResumableOpts = { disableResumable: boolean; partSize?: number; }; + +export type NodeFile = { + name: string; + type: string; + size: number; + content: Buffer; +}; +export type UploadFile = File | NodeFile; diff --git a/packages/js-sdk/src/types/sp/DelegatedPubObject.ts b/packages/js-sdk/src/types/sp/DelegatedPubObject.ts index 0b62a474..fab479c5 100644 --- a/packages/js-sdk/src/types/sp/DelegatedPubObject.ts +++ b/packages/js-sdk/src/types/sp/DelegatedPubObject.ts @@ -1,12 +1,14 @@ -import { DelegatedOpts, ResumableOpts } from './Common'; +import { OnProgress } from '../common'; +import { DelegatedOpts, ResumableOpts, UploadFile } from './Common'; export type DelegatedPubObjectRequest = { bucketName: string; objectName: string; - body: File; + body: UploadFile; delegatedOpts: DelegatedOpts; endpoint?: string; timeout?: number; contentType?: string; resumableOpts?: ResumableOpts; + onProgress?: OnProgress; }; diff --git a/packages/js-sdk/src/types/sp/PutObject.ts b/packages/js-sdk/src/types/sp/PutObject.ts index 413bf874..4d226497 100644 --- a/packages/js-sdk/src/types/sp/PutObject.ts +++ b/packages/js-sdk/src/types/sp/PutObject.ts @@ -1,11 +1,16 @@ -import { ResumableOpts } from './Common'; +import { OnProgress } from '../common'; +import { ResumableOpts, UploadFile } from './Common'; export type PutObjectRequest = { + endpoint?: string; bucketName: string; objectName: string; + body: UploadFile; txnHash?: string; - body: File; duration?: number; - endpoint?: string; resumableOpts?: ResumableOpts; + /** + * resumable upload is not supported `onProgress` + */ + onProgress?: OnProgress; }; diff --git a/packages/js-sdk/src/utils/asserts/params.ts b/packages/js-sdk/src/utils/asserts/params.ts index cdae6b49..471b7b55 100644 --- a/packages/js-sdk/src/utils/asserts/params.ts +++ b/packages/js-sdk/src/utils/asserts/params.ts @@ -1,3 +1,4 @@ +import { NodeFile, UploadFile } from '@/types/sp/Common'; import { AuthType } from '../..'; export const assertStringRequire = (s: string, errMsg: string) => { @@ -21,3 +22,16 @@ export const assertAuthType = (authType: AuthType) => { assertStringRequire(authType.domain, 'domain param is required'); } }; + +export function assertFileType(file: UploadFile): file is NodeFile { + if ('content' in file) { + return true; + } + + return false; +} + +export function assertHttpMethod(method?: string): asserts method is 'GET' | 'POST' | 'PUT' { + if (method !== 'GET' && method !== 'POST' && method !== 'PUT') + throw new Error('method should be GET, POST or PUT'); +} diff --git a/packages/js-sdk/tests/upload.spec.ts b/packages/js-sdk/tests/upload.spec.ts new file mode 100644 index 00000000..d6e214b6 --- /dev/null +++ b/packages/js-sdk/tests/upload.spec.ts @@ -0,0 +1,48 @@ +import { describe, expect, test } from '@jest/globals'; +import { VisibilityType } from '../src'; +import { ACCOUNT_PRIVATEKEY } from './env'; +import { client } from './utils'; +import { createFile } from '../src/node/adapter'; + +describe('upload', () => { + test('delegrateCreateFolder', async () => { + const res = await client.object.delegateCreateFolder( + { + bucketName: 'dfg', + objectName: 'f1/', + delegatedOpts: { + visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, + }, + }, + { + type: 'ECDSA', + privateKey: ACCOUNT_PRIVATEKEY, + }, + ); + + expect(res.code).toBe(0); + }, 50000); + + test('delegrateUpload', async () => { + const file = createFile('./README.md'); + + const res = await client.object.delegateUploadObject( + { + bucketName: 'dfg', + objectName: 'b333', + body: file, + delegatedOpts: { + visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, + }, + }, + { + type: 'ECDSA', + privateKey: ACCOUNT_PRIVATEKEY, + }, + ); + + // eslint-disable-next-line no-console + console.log('res', res); + expect(res.code).toEqual(0); + }, 10000); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f8a9660..bcfd35cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -407,9 +407,15 @@ importers: long: specifier: ^5.2.1 version: 5.2.1 + mime-types: + specifier: ^2.1.35 + version: 2.1.35 reflect-metadata: specifier: ^0.1.13 version: 0.1.13 + superagent: + specifier: ^8.1.2 + version: 8.1.2 tsyringe: specifier: ^4.8.0 version: 4.8.0 @@ -441,6 +447,12 @@ importers: '@types/mime': specifier: ^3.0.1 version: 3.0.1 + '@types/mime-types': + specifier: ^2.1.4 + version: 2.1.4 + '@types/superagent': + specifier: ^8.1.6 + version: 8.1.6 '@types/xml2js': specifier: ^0.4.11 version: 0.4.11 @@ -3250,6 +3262,9 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + '@types/cross-spawn@6.0.3': resolution: {integrity: sha512-BDAkU7WHHRHnvBf5z89lcvACsvkz/n7Tv+HyD/uW76O29HoH1Tk/W6iQrepaZVbisvlEek4ygwT8IW7ow9XLAA==} @@ -3376,6 +3391,12 @@ packages: '@types/mdx@2.0.10': resolution: {integrity: sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==} + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + + '@types/mime-types@2.1.4': + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + '@types/mime@1.3.2': resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} @@ -3505,6 +3526,9 @@ packages: '@types/stack-utils@2.0.1': resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + '@types/superagent@8.1.6': + resolution: {integrity: sha512-yzBOv+6meEHSzV2NThYYOA6RtqvPr3Hbob9ZLp3i07SH27CrYVfm8CrF7ydTmidtelsFiKx2I4gZAiAOamGgvQ==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -4088,6 +4112,9 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -4688,6 +4715,9 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -4768,6 +4798,9 @@ packages: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + copy-text-to-clipboard@3.2.0: resolution: {integrity: sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==} engines: {node: '>=12'} @@ -5188,6 +5221,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff-sequences@29.4.3: resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5904,6 +5940,9 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + formidable@2.1.2: + resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -6222,6 +6261,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hexoid@1.0.0: + resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} + engines: {node: '>=8'} + hey-listen@1.0.8: resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} @@ -7528,6 +7571,11 @@ packages: engines: {node: '>=4'} hasBin: true + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -9380,6 +9428,10 @@ packages: peerDependencies: postcss: ^8.2.15 + superagent@8.1.2: + resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} + engines: {node: '>=6.4.0 <13 || >=14'} + superstruct@0.14.2: resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} @@ -13877,7 +13929,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.10.5 + '@types/node': 18.16.18 '@types/yargs': 17.0.31 chalk: 4.1.2 @@ -14771,7 +14823,9 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 20.10.5 + '@types/node': 18.16.18 + + '@types/cookiejar@2.1.5': {} '@types/cross-spawn@6.0.3': dependencies: @@ -14883,7 +14937,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 20.10.5 + '@types/node': 18.16.18 '@types/lodash.clonedeep@4.5.7': dependencies: @@ -14917,6 +14971,10 @@ snapshots: '@types/mdx@2.0.10': {} + '@types/methods@1.1.4': {} + + '@types/mime-types@2.1.4': {} + '@types/mime@1.3.2': {} '@types/mime@3.0.1': {} @@ -14929,7 +14987,7 @@ snapshots: '@types/mute-stream@0.0.1': dependencies: - '@types/node': 20.6.0 + '@types/node': 18.16.18 '@types/node@12.20.55': {} @@ -15014,7 +15072,7 @@ snapshots: '@types/responselike@1.0.0': dependencies: - '@types/node': 20.10.5 + '@types/node': 18.16.18 '@types/retry@0.12.0': {} @@ -15055,6 +15113,12 @@ snapshots: '@types/stack-utils@2.0.1': {} + '@types/superagent@8.1.6': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 18.16.18 + '@types/trusted-types@2.0.7': {} '@types/unist@2.0.10': {} @@ -15161,7 +15225,7 @@ snapshots: debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.2 + semver: 7.5.4 tsutils: 3.21.0(typescript@4.9.5) optionalDependencies: typescript: 4.9.5 @@ -16231,7 +16295,7 @@ snapshots: array-buffer-byte-length@1.0.0: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 is-array-buffer: 3.0.2 array-flatten@1.1.1: {} @@ -16274,6 +16338,8 @@ snapshots: arrify@1.0.1: {} + asap@2.0.6: {} + assertion-error@1.1.0: {} ast-types-flow@0.0.7: {} @@ -16670,7 +16736,7 @@ snapshots: builtins@5.0.1: dependencies: - semver: 7.5.2 + semver: 7.5.4 busboy@1.6.0: dependencies: @@ -16704,8 +16770,8 @@ snapshots: call-bind@1.0.2: dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 call-bind@1.0.5: dependencies: @@ -16980,6 +17046,8 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 + component-emitter@1.3.1: {} + compressible@2.0.18: dependencies: mime-db: 1.52.0 @@ -17061,6 +17129,8 @@ snapshots: cookie@0.5.0: {} + cookiejar@2.1.4: {} + copy-text-to-clipboard@3.2.0: {} copy-to-clipboard@3.3.3: @@ -17430,9 +17500,9 @@ snapshots: deep-equal@2.2.1: dependencies: array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 + call-bind: 1.0.5 es-get-iterator: 1.1.3 - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 is-arguments: 1.1.1 is-array-buffer: 3.0.2 is-date-object: 1.0.5 @@ -17540,6 +17610,11 @@ snapshots: dependencies: dequal: 2.0.3 + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + diff-sequences@29.4.3: {} diff@4.0.2: {} @@ -17714,11 +17789,11 @@ snapshots: dependencies: array-buffer-byte-length: 1.0.0 available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.5 es-set-tostringtag: 2.0.1 es-to-primitive: 1.2.1 function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 get-symbol-description: 1.0.0 globalthis: 1.0.3 gopd: 1.0.1 @@ -17749,8 +17824,8 @@ snapshots: es-get-iterator@1.1.3: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 has-symbols: 1.0.3 is-arguments: 1.1.1 is-map: 2.0.2 @@ -17763,7 +17838,7 @@ snapshots: es-set-tostringtag@2.0.1: dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 has: 1.0.3 has-tostringtag: 1.0.0 @@ -18479,6 +18554,13 @@ snapshots: format@0.2.2: {} + formidable@2.1.2: + dependencies: + dezalgo: 1.0.4 + hexoid: 1.0.0 + once: 1.4.0 + qs: 6.11.2 + forwarded@0.2.0: {} fraction.js@4.3.7: {} @@ -18530,7 +18612,7 @@ snapshots: function.prototype.name@1.1.5: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 es-abstract: 1.21.2 functions-have-names: 1.2.3 @@ -18545,7 +18627,7 @@ snapshots: get-intrinsic@1.2.1: dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -18580,8 +18662,8 @@ snapshots: get-symbol-description@1.0.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 get-tsconfig@4.5.0: {} @@ -18689,7 +18771,7 @@ snapshots: gopd@1.0.1: dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 got@12.6.1: dependencies: @@ -18778,7 +18860,7 @@ snapshots: has-property-descriptors@1.0.0: dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 has-property-descriptors@1.0.1: dependencies: @@ -18907,6 +18989,8 @@ snapshots: he@1.2.0: {} + hexoid@1.0.0: {} + hey-listen@1.0.8: {} history@4.10.1: @@ -19115,7 +19199,7 @@ snapshots: internal-slot@1.0.5: dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.2 has: 1.0.3 side-channel: 1.0.4 @@ -19159,13 +19243,13 @@ snapshots: is-arguments@1.1.1: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 is-array-buffer@3.0.2: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 is-typed-array: 1.1.10 is-arrayish@0.2.1: {} @@ -19182,7 +19266,7 @@ snapshots: is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 is-builtin-module@3.2.1: @@ -19290,7 +19374,7 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 is-regexp@1.0.0: {} @@ -19303,7 +19387,7 @@ snapshots: is-shared-array-buffer@1.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 is-stream@1.1.0: {} @@ -19330,7 +19414,7 @@ snapshots: is-typed-array@1.1.10: dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.5 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 @@ -19347,12 +19431,12 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 is-weakset@2.0.2: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 is-windows@1.0.2: {} @@ -19695,7 +19779,7 @@ snapshots: jest-util: 29.5.0 natural-compare: 1.4.0 pretty-format: 29.5.0 - semver: 7.5.2 + semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -19711,7 +19795,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.5 + '@types/node': 18.16.18 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -20701,6 +20785,8 @@ snapshots: mime@1.6.0: {} + mime@2.6.0: {} + mime@3.0.0: {} mimic-fn@2.1.0: {} @@ -20938,14 +21024,14 @@ snapshots: object-is@1.1.5: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 object-keys@1.1.1: {} object.assign@4.1.4: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 @@ -21947,7 +22033,7 @@ snapshots: regexp.prototype.flags@1.5.0: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 functions-have-names: 1.2.3 @@ -22191,8 +22277,8 @@ snapshots: safe-regex-test@1.0.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 is-regex: 1.1.4 safe-resolve@1.0.0: {} @@ -22393,8 +22479,8 @@ snapshots: side-channel@1.0.4: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 object-inspect: 1.12.3 signal-exit@3.0.7: {} @@ -22636,19 +22722,19 @@ snapshots: string.prototype.trim@1.2.7: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 es-abstract: 1.21.2 string.prototype.trimend@1.0.6: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 es-abstract: 1.21.2 string.prototype.trimstart@1.0.6: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 define-properties: 1.2.0 es-abstract: 1.21.2 @@ -22728,6 +22814,21 @@ snapshots: postcss: 8.4.38 postcss-selector-parser: 6.0.13 + superagent@8.1.2: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.3.4(supports-color@8.1.1) + fast-safe-stringify: 2.1.1 + form-data: 4.0.0 + formidable: 2.1.2 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.11.2 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + superstruct@0.14.2: {} superstruct@1.0.3: {} @@ -23002,7 +23103,7 @@ snapshots: typed-array-length@1.0.4: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 for-each: 0.3.3 is-typed-array: 1.1.10 @@ -23027,7 +23128,7 @@ snapshots: unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -23603,7 +23704,7 @@ snapshots: which-typed-array@1.1.9: dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.5 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0