@shopify/oxygen-cli 4.4.10-unstable.202405292053.0 → 4.4.10

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @shopify/oxygen-cli
2
2
 
3
+ ## 4.4.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 86a0203: Update tsup from 8.0.2 to 8.1.0
8
+ - e70aed8: Update @types/node from 20.12.13 to 20.14.0
9
+ - 765b37a: Update oclif from 4.11.3 to 4.12.3
10
+
3
11
  ## 4.4.9
4
12
 
5
13
  ### Patch Changes
@@ -7,6 +15,7 @@
7
15
  - e9a6a36: Update vite from 5.2.11 to 5.2.12
8
16
  - a3a4b2a: Update @changesets/cli from 2.27.3 to 2.27.4
9
17
  - ee4f6e8: Update @changesets/cli from 2.27.4 to 2.27.5
18
+ - 2954ed4: Update @types/node from 20.12.12 to 20.12.13
10
19
  - 48cb065: Added AuthBypassTokenDuration flag in CLI and Deployment
11
20
 
12
21
  ## 4.4.8
@@ -151,8 +151,7 @@ async function uploadResumable(location, filePath, lastReceivedByte, agent) {
151
151
  }
152
152
  async function resumableUploadStatus(location, fileSize, agent) {
153
153
  const getLastByte = (range) => {
154
- if (!range || range.split("-").length !== 2)
155
- return 0;
154
+ if (!range || range.split("-").length !== 2) return 0;
156
155
  const rangeParts = range.split("-");
157
156
  return parseInt(rangeParts[1], 10);
158
157
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/deploy/upload-files.ts"],"names":[],"mappings":"AACA,SAAQ,aAAY;AAEpB,SAAQ,OAAO,gBAAe;AAC9B,SAAQ,4BAA2B;AACnC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAQ,gBAAe;AACvB,SAAQ,gBAAe;AAEvB,SAAQ,sBAAqB;AAC7B,SAAyB,kBAAiB;AAwB1C,eAAsB,YAAY,SAA4C;AAC5E,QAAM,EAAC,QAAQ,QAAQ,SAAS,MAAK,IAAI;AACzC,aAAW,aAAa,QAAQ,MAAM,aAAa,MAAM;AAEzD,QAAM,kBACJ,QAAQ,OAAO,CAAC,OAAO,WAAW,QAAQ,OAAO,UAAU,CAAC,IAAI;AAClE,UAAQ,iBAAiB,IAAI,WAAW,mBAAmB,eAAe;AAC1E,UAAQ,iBAAiB,IAAI,WAAW,kBAAkB,QAAQ,MAAM;AAExE,QAAM,QAAQ,IAAI,MAAM,EAAC,WAAW,KAAI,CAAC;AACzC,SAAO,qBAAqB;AAC5B,QAAM,YAAY,YAAY,IAAI;AAClC,SAAO,SAAS,SAAS,GAAG,OAAO,WAAqC;AACtE,UAAM,WAAW,QAAQ,QAAQ,KAAK;AAAA,EACxC,CAAC,EACE,KAAK,MAAM;AACV,UAAM,UAAU,YAAY,IAAI;AAChC,WAAO,wBAAwB;AAC/B,YAAQ,iBAAiB,IAAI,WAAW,YAAY,UAAU,SAAS;AACvE,oBAAgB,+BAA+B,MAAM;AAAA,EACvD,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,WAAO,qBAAqB,GAAG;AAC/B,UAAM;AAAA,EACR,CAAC,EACA,QAAQ,MAAM;AACb,UAAM,QAAQ;AAAA,EAChB,CAAC;AACL;AAEA,eAAe,WACb,QACA,QACA,OACA;AACA,QAAM,kBACJ,OAAO,aAAa,WAChB,SAAS,OAAO,UAAW,OAAO,SAAU,IAC5C,SAAS,OAAO,UAAW,OAAO,SAAU;AAElD,MAAI,OAAO,eAAe,QAAQ,OAAO,WAAW,SAAS,GAAG;AAE9D,UAAM,OAAO,SAAS;AACtB,WAAO,WAAW,QAAQ,CAAC,UAAU;AACnC,WAAK,OAAO,MAAM,MAAM,MAAM,KAAK;AAAA,IACrC,CAAC;AACD,SAAK;AAAA,MACH;AAAA,MACA,qBAAqB,SAAS,iBAAiB,OAAO,QAAQ,CAAC;AAAA,IACjE;AACA,UAAM,WAAW,MAAM,QAAQ,KAAK;AAAA,EACtC,OAAO;AAEL,UAAM,WAAW,MAAM,wBAAwB,QAAQ,KAAK;AAC5D,UAAM;AAAA,MACJ,SAAS,iBAAiB,OAAO,QAAQ;AAAA,MACzC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,WACb,MACA,QACA,OACA,gBAAgB,GAChB;AACA,MAAI;AACF,UAAM,kBAAkB;AACxB,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM;AAC/B,iBAAW,MAAM;AAAA,IACnB,GAAG,eAAe;AAElB,UAAM,WAAW,MAAM,MAAM,OAAO,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,WAAW;AAAA,MACnB,SAAS;AAAA,QACP,YAAY;AAAA,MACd;AAAA,MACA;AAAA,IACF,CAAC;AACD,iBAAa,OAAO;AAEpB,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,GAAG,SAAS,MAAM,EAAE;AAAA,IACtC;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,YAAY,KAAK,QAAQ,GAAG;AAC9B,YAAM,IAAI,MAAM,mBAAmB,OAAO,QAAQ,EAAE;AAAA,IACtD;AAEA,QAAI,gBAAgB,OAAO,eAAe,iBAAiB,GAAG;AAC5D,YAAM,WAAW,MAAM,QAAQ,OAAO,gBAAgB,CAAC;AAAA,IACzD,OAAO;AACL,UAAI,eAAe,SAAS,IAAI,SAAS,cAAc;AACrD,cAAM,IAAI,MAAM,oCAAoC,OAAO,QAAQ,EAAE;AAAA,MACvE;AACA,YAAM,IAAI,MAAM,yBAAyB,OAAO,QAAQ,EAAE;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,eAAe,wBACb,QACA,OACoC;AACpC,SAAO,MAAM,OAAO,WAAW;AAAA,IAC7B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,oBAAoB;AAAA,MACpB,+BAA+B,KAAK,OAAO,QAAQ;AAAA,MACnD,cAAc;AAAA,IAChB;AAAA,IACA;AAAA,EACF,CAAC,EACE,KAAK,CAAC,QAAQ;AACb,WAAO;AAAA,MACL,YAAY,IAAI,QAAQ,IAAI,sBAAsB;AAAA,MAClD,UAAU,IAAI,QAAQ,IAAI,UAAU;AAAA,MACpC;AAAA,IACF;AAAA,EACF,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAM,IAAI;AAAA,MACR,gDAAgD,OAAO,QAAQ,iBAAiB,IAAI,UAAU;AAAA,IAChG;AAAA,EACF,CAAC;AACL;AAEA,eAAe,uBACb,eACA,UACA,OACA,YAAY,GACZ,gBAAgB,GAChB;AACA,QAAM;AAAA,IACJ,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,MAAM,OAAO,QAAQ;AACrB,QAAI,YAAY,KAAK,QAAQ,GAAG;AAC9B,YAAM,IAAI,MAAM,mBAAmB,SAAS,OAAO,QAAQ,EAAE;AAAA,IAC/D;AAEA,QACE,OACA,iBAAiB,OAAO,eAAe,yBAAyB,GAChE;AACA,YAAM,IAAI;AAAA,QACR,yBAAyB,SAAS,OAAO,QAAQ,UAAU,eAAe,yBAAyB;AAAA,MACrG;AAAA,IACF;AACA,UAAM,SAAS,MAAM;AAAA,MACnB,SAAS;AAAA,MACT,SAAS,OAAO;AAAA,MAChB;AAAA,IACF;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,uBAAuB,OAAO;AACpC,YAAM,UAAU,gBAAgB;AAChC,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,gBACb,UACA,UACA,kBACA,OACiB;AACjB,QAAM,OAAO,qBAAqB,UAAU,EAAC,OAAO,iBAAgB,CAAC;AACrE,SAAO,MAAM,UAAU;AAAA,IACrB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN;AAAA,EACF,CAAC,EAAE,KAAK,CAAC,QAAQ;AACf,WAAO,IAAI;AAAA,EACb,CAAC;AACH;AAEA,eAAe,sBACb,UACA,UACA,OACgC;AAChC,QAAM,cAAc,CAAC,UAAiC;AACpD,QAAI,CAAC,SAAS,MAAM,MAAM,GAAG,EAAE,WAAW;AAAG,aAAO;AACpD,UAAM,aAAa,MAAM,MAAM,GAAG;AAClC,WAAO,SAAS,WAAW,CAAC,GAAI,EAAE;AAAA,EACpC;AAEA,SAAO,MAAM,UAAU;AAAA,IACrB,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,iBAAiB,WAAW,QAAQ;AAAA,IACtC;AAAA,IACA;AAAA,EACF,CAAC,EACE,KAAK,CAAC,QAAQ;AACb,WAAO;AAAA,MACL,UAAU,IAAI,WAAW;AAAA,MACzB,kBAAkB,YAAY,IAAI,QAAQ,IAAI,OAAO,CAAC;AAAA,IACxD;AAAA,EACF,CAAC,EACA,MAAM,CAAC,QAAQ;AAEd,YAAQ,MAAM,GAAG;AACjB,WAAO;AAAA,MACL,UAAU;AAAA,MACV,kBAAkB;AAAA,IACpB;AAAA,EACF,CAAC;AACL;AAEA,SAAS,YAAY,KAAc,MAAuB;AACxD,SAAO,eAAe,SAAS,UAAU,OAAO,IAAI,SAAS;AAC/D","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport {Agent} from 'https';\n\nimport {fetch, formData} from '@shopify/cli-kit/node/http';\nimport {createFileReadStream} from '@shopify/cli-kit/node/fs';\nimport {\n Logger,\n outputCompleted,\n outputInfo,\n} from '@shopify/cli-kit/node/output';\nimport {joinPath} from '@shopify/cli-kit/node/path';\nimport {mapLimit} from 'async';\n\nimport {deployDefaults} from '../utils/utils.js';\nimport {MetricsExporter, MetricName} from '../utils/metrics-exporter.js';\n\nimport {DeploymentConfig, DeploymentHooks} from './types.js';\nimport {DeploymentTargetResponse} from './graphql/deployment-initiate.js';\n\ninterface InitiateResumableResponse {\n target: DeploymentTargetResponse;\n sessionUri: string;\n location: string;\n}\n\ninterface ResumableUploadStatus {\n complete: boolean;\n lastReceivedByte: number;\n}\n\ninterface UploadFilesOptions {\n config: DeploymentConfig;\n hooks?: DeploymentHooks;\n logger: Logger;\n metricsExporter?: MetricsExporter;\n targets: DeploymentTargetResponse[];\n}\n\nexport async function uploadFiles(options: UploadFilesOptions): Promise<void> {\n const {config, logger, targets, hooks} = options;\n outputInfo(`Uploading ${targets.length} files...`, logger);\n\n const totalUploadSize =\n targets.reduce((total, target) => total + target.fileSize, 0) / 1024;\n options.metricsExporter?.add(MetricName.TotalSizeUploaded, totalUploadSize);\n options.metricsExporter?.add(MetricName.NumFilesUploaded, targets.length);\n\n const agent = new Agent({keepAlive: true});\n hooks?.onUploadFilesStart?.();\n const startTime = performance.now();\n return mapLimit(targets, 6, async (target: DeploymentTargetResponse) => {\n await uploadFile(config, target, agent);\n })\n .then(() => {\n const endTime = performance.now();\n hooks?.onUploadFilesComplete?.();\n options.metricsExporter?.add(MetricName.UploadTime, endTime - startTime);\n outputCompleted(`Files uploaded successfully`, logger);\n })\n .catch((err) => {\n hooks?.onUploadFilesError?.(err);\n throw err;\n })\n .finally(() => {\n agent.destroy();\n });\n}\n\nasync function uploadFile(\n config: DeploymentConfig,\n target: DeploymentTargetResponse,\n agent: Agent,\n) {\n const localFolderPath =\n target.fileType === 'WORKER'\n ? joinPath(config.rootPath!, config.workerDir!)\n : joinPath(config.rootPath!, config.assetsDir!);\n\n if (target.parameters !== null && target.parameters.length > 0) {\n // If parameters exist perform a form upload\n const form = formData();\n target.parameters.forEach((param) => {\n form.append(param.name, param.value);\n });\n form.append(\n 'file',\n createFileReadStream(joinPath(localFolderPath, target.filePath)),\n );\n await formUpload(form, target, agent);\n } else {\n // If no parameters exist perform a resumable upload\n const initData = await initiateResumableUpload(target, agent);\n await performResumableUpload(\n joinPath(localFolderPath, target.filePath),\n initData,\n agent,\n );\n }\n}\n\nasync function formUpload(\n form: ReturnType<typeof formData>,\n target: DeploymentTargetResponse,\n agent: Agent,\n attemptNumber = 0,\n) {\n try {\n const timeoutDuration = 120000;\n const controller = new AbortController();\n const timeout = setTimeout(() => {\n controller.abort();\n }, timeoutDuration);\n\n const response = await fetch(target.uploadUrl, {\n method: 'POST',\n body: form,\n signal: controller.signal,\n headers: {\n Connection: 'keep-alive',\n },\n agent,\n });\n clearTimeout(timeout);\n\n if (!response.ok) {\n throw new Error(`${response.status}`);\n }\n } catch (err) {\n if (isErrorCode(err, 'ENOENT')) {\n throw new Error(`File not found: ${target.filePath}`);\n }\n\n if (attemptNumber < Number(deployDefaults.maxUploadAttempts)) {\n await formUpload(form, target, agent, attemptNumber + 1);\n } else {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Request timeout whilst uploading ${target.filePath}`);\n }\n throw new Error(`Failed to upload file ${target.filePath}`);\n }\n }\n}\n\nasync function initiateResumableUpload(\n target: DeploymentTargetResponse,\n agent: Agent,\n): Promise<InitiateResumableResponse> {\n return fetch(target.uploadUrl, {\n method: 'POST',\n headers: {\n 'x-goog-resumable': 'start',\n 'X-Goog-Content-Length-Range': `0,${target.fileSize}`,\n 'User-Agent': 'oxygen-cli',\n },\n agent,\n })\n .then((res) => {\n return {\n sessionUri: res.headers.get('x-guploader-uploadid')!,\n location: res.headers.get('location')!,\n target,\n };\n })\n .catch((err) => {\n throw new Error(\n `Failed to initiate resumable upload for file ${target.filePath} (status code ${err.statusCode})`,\n );\n });\n}\n\nasync function performResumableUpload(\n localFilePath: string,\n initData: InitiateResumableResponse,\n agent: Agent,\n startByte = 0,\n attemptNumber = 0,\n) {\n await uploadResumable(\n initData.location,\n localFilePath,\n startByte,\n agent,\n ).catch(async (err) => {\n if (isErrorCode(err, 'ENOENT')) {\n throw new Error(`File not found: ${initData.target.filePath}`);\n }\n\n if (\n err &&\n attemptNumber >= Number(deployDefaults.maxResumabeUploadAttempts)\n ) {\n throw new Error(\n `Failed to upload file ${initData.target.filePath} after ${deployDefaults.maxResumabeUploadAttempts} attempts`,\n );\n }\n const status = await resumableUploadStatus(\n initData.location,\n initData.target.fileSize,\n agent,\n );\n if (!status.complete) {\n const nextAttemptStartByte = status.lastReceivedByte;\n const attempt = attemptNumber + 1;\n await performResumableUpload(\n localFilePath,\n initData,\n agent,\n nextAttemptStartByte,\n attempt,\n );\n }\n });\n}\n\nasync function uploadResumable(\n location: string,\n filePath: string,\n lastReceivedByte: number,\n agent: Agent,\n): Promise<number> {\n const file = createFileReadStream(filePath, {start: lastReceivedByte});\n return fetch(location, {\n method: 'PUT',\n body: file,\n agent,\n }).then((res) => {\n return res.status;\n });\n}\n\nasync function resumableUploadStatus(\n location: string,\n fileSize: number,\n agent: Agent,\n): Promise<ResumableUploadStatus> {\n const getLastByte = (range: string | null): number => {\n if (!range || range.split('-').length !== 2) return 0;\n const rangeParts = range.split('-');\n return parseInt(rangeParts[1]!, 10);\n };\n\n return fetch(location, {\n method: 'PUT',\n headers: {\n 'Content-Length': '0',\n 'Content-Range': `bytes */${fileSize}`,\n },\n agent,\n })\n .then((res) => {\n return {\n complete: res.status === 200,\n lastReceivedByte: getLastByte(res.headers.get('range')),\n };\n })\n .catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err);\n return {\n complete: false,\n lastReceivedByte: 0,\n };\n });\n}\n\nfunction isErrorCode(err: unknown, code: string): boolean {\n return err instanceof Error && 'code' in err && err.code === code;\n}\n"]}
1
+ {"version":3,"sources":["../../src/deploy/upload-files.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport {Agent} from 'https';\n\nimport {fetch, formData} from '@shopify/cli-kit/node/http';\nimport {createFileReadStream} from '@shopify/cli-kit/node/fs';\nimport {\n Logger,\n outputCompleted,\n outputInfo,\n} from '@shopify/cli-kit/node/output';\nimport {joinPath} from '@shopify/cli-kit/node/path';\nimport {mapLimit} from 'async';\n\nimport {deployDefaults} from '../utils/utils.js';\nimport {MetricsExporter, MetricName} from '../utils/metrics-exporter.js';\n\nimport {DeploymentConfig, DeploymentHooks} from './types.js';\nimport {DeploymentTargetResponse} from './graphql/deployment-initiate.js';\n\ninterface InitiateResumableResponse {\n target: DeploymentTargetResponse;\n sessionUri: string;\n location: string;\n}\n\ninterface ResumableUploadStatus {\n complete: boolean;\n lastReceivedByte: number;\n}\n\ninterface UploadFilesOptions {\n config: DeploymentConfig;\n hooks?: DeploymentHooks;\n logger: Logger;\n metricsExporter?: MetricsExporter;\n targets: DeploymentTargetResponse[];\n}\n\nexport async function uploadFiles(options: UploadFilesOptions): Promise<void> {\n const {config, logger, targets, hooks} = options;\n outputInfo(`Uploading ${targets.length} files...`, logger);\n\n const totalUploadSize =\n targets.reduce((total, target) => total + target.fileSize, 0) / 1024;\n options.metricsExporter?.add(MetricName.TotalSizeUploaded, totalUploadSize);\n options.metricsExporter?.add(MetricName.NumFilesUploaded, targets.length);\n\n const agent = new Agent({keepAlive: true});\n hooks?.onUploadFilesStart?.();\n const startTime = performance.now();\n return mapLimit(targets, 6, async (target: DeploymentTargetResponse) => {\n await uploadFile(config, target, agent);\n })\n .then(() => {\n const endTime = performance.now();\n hooks?.onUploadFilesComplete?.();\n options.metricsExporter?.add(MetricName.UploadTime, endTime - startTime);\n outputCompleted(`Files uploaded successfully`, logger);\n })\n .catch((err) => {\n hooks?.onUploadFilesError?.(err);\n throw err;\n })\n .finally(() => {\n agent.destroy();\n });\n}\n\nasync function uploadFile(\n config: DeploymentConfig,\n target: DeploymentTargetResponse,\n agent: Agent,\n) {\n const localFolderPath =\n target.fileType === 'WORKER'\n ? joinPath(config.rootPath!, config.workerDir!)\n : joinPath(config.rootPath!, config.assetsDir!);\n\n if (target.parameters !== null && target.parameters.length > 0) {\n // If parameters exist perform a form upload\n const form = formData();\n target.parameters.forEach((param) => {\n form.append(param.name, param.value);\n });\n form.append(\n 'file',\n createFileReadStream(joinPath(localFolderPath, target.filePath)),\n );\n await formUpload(form, target, agent);\n } else {\n // If no parameters exist perform a resumable upload\n const initData = await initiateResumableUpload(target, agent);\n await performResumableUpload(\n joinPath(localFolderPath, target.filePath),\n initData,\n agent,\n );\n }\n}\n\nasync function formUpload(\n form: ReturnType<typeof formData>,\n target: DeploymentTargetResponse,\n agent: Agent,\n attemptNumber = 0,\n) {\n try {\n const timeoutDuration = 120000;\n const controller = new AbortController();\n const timeout = setTimeout(() => {\n controller.abort();\n }, timeoutDuration);\n\n const response = await fetch(target.uploadUrl, {\n method: 'POST',\n body: form,\n signal: controller.signal,\n headers: {\n Connection: 'keep-alive',\n },\n agent,\n });\n clearTimeout(timeout);\n\n if (!response.ok) {\n throw new Error(`${response.status}`);\n }\n } catch (err) {\n if (isErrorCode(err, 'ENOENT')) {\n throw new Error(`File not found: ${target.filePath}`);\n }\n\n if (attemptNumber < Number(deployDefaults.maxUploadAttempts)) {\n await formUpload(form, target, agent, attemptNumber + 1);\n } else {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Request timeout whilst uploading ${target.filePath}`);\n }\n throw new Error(`Failed to upload file ${target.filePath}`);\n }\n }\n}\n\nasync function initiateResumableUpload(\n target: DeploymentTargetResponse,\n agent: Agent,\n): Promise<InitiateResumableResponse> {\n return fetch(target.uploadUrl, {\n method: 'POST',\n headers: {\n 'x-goog-resumable': 'start',\n 'X-Goog-Content-Length-Range': `0,${target.fileSize}`,\n 'User-Agent': 'oxygen-cli',\n },\n agent,\n })\n .then((res) => {\n return {\n sessionUri: res.headers.get('x-guploader-uploadid')!,\n location: res.headers.get('location')!,\n target,\n };\n })\n .catch((err) => {\n throw new Error(\n `Failed to initiate resumable upload for file ${target.filePath} (status code ${err.statusCode})`,\n );\n });\n}\n\nasync function performResumableUpload(\n localFilePath: string,\n initData: InitiateResumableResponse,\n agent: Agent,\n startByte = 0,\n attemptNumber = 0,\n) {\n await uploadResumable(\n initData.location,\n localFilePath,\n startByte,\n agent,\n ).catch(async (err) => {\n if (isErrorCode(err, 'ENOENT')) {\n throw new Error(`File not found: ${initData.target.filePath}`);\n }\n\n if (\n err &&\n attemptNumber >= Number(deployDefaults.maxResumabeUploadAttempts)\n ) {\n throw new Error(\n `Failed to upload file ${initData.target.filePath} after ${deployDefaults.maxResumabeUploadAttempts} attempts`,\n );\n }\n const status = await resumableUploadStatus(\n initData.location,\n initData.target.fileSize,\n agent,\n );\n if (!status.complete) {\n const nextAttemptStartByte = status.lastReceivedByte;\n const attempt = attemptNumber + 1;\n await performResumableUpload(\n localFilePath,\n initData,\n agent,\n nextAttemptStartByte,\n attempt,\n );\n }\n });\n}\n\nasync function uploadResumable(\n location: string,\n filePath: string,\n lastReceivedByte: number,\n agent: Agent,\n): Promise<number> {\n const file = createFileReadStream(filePath, {start: lastReceivedByte});\n return fetch(location, {\n method: 'PUT',\n body: file,\n agent,\n }).then((res) => {\n return res.status;\n });\n}\n\nasync function resumableUploadStatus(\n location: string,\n fileSize: number,\n agent: Agent,\n): Promise<ResumableUploadStatus> {\n const getLastByte = (range: string | null): number => {\n if (!range || range.split('-').length !== 2) return 0;\n const rangeParts = range.split('-');\n return parseInt(rangeParts[1]!, 10);\n };\n\n return fetch(location, {\n method: 'PUT',\n headers: {\n 'Content-Length': '0',\n 'Content-Range': `bytes */${fileSize}`,\n },\n agent,\n })\n .then((res) => {\n return {\n complete: res.status === 200,\n lastReceivedByte: getLastByte(res.headers.get('range')),\n };\n })\n .catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err);\n return {\n complete: false,\n lastReceivedByte: 0,\n };\n });\n}\n\nfunction isErrorCode(err: unknown, code: string): boolean {\n return err instanceof Error && 'code' in err && err.code === code;\n}\n"]}
@@ -194,5 +194,5 @@
194
194
  ]
195
195
  }
196
196
  },
197
- "version": "4.4.10-unstable.202405292053.0"
197
+ "version": "4.4.10"
198
198
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "4.4.10-unstable.202405292053.0",
8
+ "version": "4.4.10",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "build": "tsup --sourcemap --clean --config ./tsup.config.ts && oclif manifest",
@@ -51,12 +51,12 @@
51
51
  "@shopify/eslint-plugin": "^44.0.0",
52
52
  "@shopify/prettier-config": "^1.1.2",
53
53
  "@types/async": "^3.2.24",
54
- "@types/node": "^20.12.12",
54
+ "@types/node": "^20.14.0",
55
55
  "eslint": "^8.57.0",
56
56
  "eslint-plugin-prettier": "^5.1.3",
57
57
  "node-fetch": "^3.3.2",
58
58
  "oclif": "^4",
59
- "tsup": "^8.0.2",
59
+ "tsup": "^8.1.0",
60
60
  "typescript": "^5.4.5",
61
61
  "vite": "^5.2.12",
62
62
  "vitest": "^1.6.0"