@contello/uploader 8.21.5 → 8.21.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -104,8 +104,8 @@ function uploadViaXhr({ url, project, token }, file, meta, options) {
104
104
  }));
105
105
  data.append("file", file);
106
106
  const xhr = new XMLHttpRequest();
107
- xhr.setRequestHeader("Authorization", `Bearer ${token}`);
108
107
  xhr.open("POST", `${url}/api/v1/assets`, true);
108
+ xhr.setRequestHeader("Authorization", `Bearer ${token}`);
109
109
  xhr.upload.addEventListener("progress", (event) => {
110
110
  if (event.lengthComputable) obs.next({ progress: event.loaded / event.total * 100 });
111
111
  });
package/dist/index.js CHANGED
@@ -103,8 +103,8 @@ function uploadViaXhr({ url, project, token }, file, meta, options) {
103
103
  }));
104
104
  data.append("file", file);
105
105
  const xhr = new XMLHttpRequest();
106
- xhr.setRequestHeader("Authorization", `Bearer ${token}`);
107
106
  xhr.open("POST", `${url}/api/v1/assets`, true);
107
+ xhr.setRequestHeader("Authorization", `Bearer ${token}`);
108
108
  xhr.upload.addEventListener("progress", (event) => {
109
109
  if (event.lengthComputable) obs.next({ progress: event.loaded / event.total * 100 });
110
110
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/upload-metadata.ts","../src/implementations/ws.ts","../src/implementations/xhr.ts","../src/uploader.ts"],"sourcesContent":["export type UploadAssetMetadata = {\n name?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n annotations?: UploadAssetAnnotation[] | undefined;\n collectionRefs?: string[] | undefined;\n image?: UploadAssetImageMetadata | undefined;\n retentionPolicy?: UploadAssetRetentionPolicy | undefined;\n generatePreview?: boolean | undefined;\n createdAt?: string | undefined;\n updatedAt?: string | undefined;\n};\n\nexport type UploadAssetAnnotation = {\n key: string;\n value: string;\n};\n\nexport type UploadAssetProgress = {\n progress: number;\n};\n\nexport enum UploadAssetRetentionPolicy {\n retain = 'retain',\n deleteIfNotUsed = 'deleteIfNotUsed',\n}\n\nexport type UploadAssetImageMetadata = {\n transformations: UploadAssetImageTransformation[];\n};\n\nexport type UploadAssetImageTransformation =\n | UploadAssetExtractTransformation\n | UploadAssetFitTransformation\n | UploadAssetConvertTransformation;\n\nexport type UploadAssetExtractTransformation = {\n name: 'extract';\n options: {\n top: number;\n left: number;\n areaWidth: number;\n areaHeight: number;\n rotate?: 0 | 90 | 180 | 270 | undefined;\n };\n};\n\nexport type UploadAssetFitTransformation = {\n name: 'fit';\n options: {\n width: number;\n height: number;\n };\n};\n\nexport type UploadAssetConvertTransformation = {\n name: 'convert';\n options:\n | UploadAssetConvertTransformationJpegOptions\n | UploadAssetConvertTransformationPngOptions\n | UploadAssetConvertTransformationAvifOptions;\n};\n\nexport type UploadAssetConvertTransformationJpegOptions = {\n format: 'jpeg';\n options: {\n quality: number; // 0-100\n interlace: boolean;\n };\n};\n\nexport type UploadAssetConvertTransformationPngOptions = {\n format: 'png';\n options: {\n compressionLevel: number; // 0-9\n };\n};\n\nexport type UploadAssetConvertTransformationAvifOptions = {\n format: 'avif';\n options: {\n quality: number; // 0-100\n lossless: boolean;\n };\n};\n","import { Observable } from 'rxjs';\nimport type { UploadAssetMetadata, UploadAssetProgress } from '../upload-metadata';\nimport type { ContelloUploaderParams } from '../uploader';\n\ntype InitFrame = {\n type: 'init';\n metadata: UploadAssetMetadata & { projectRef: string };\n token: string;\n};\n\ntype AckMessage = { type: 'ack' };\n\ntype ProgressMessage = { type: 'progress'; bytesReceived: number };\n\ntype DoneMessage = { type: 'done'; id: string };\n\n/** Uploads a file via WebSocket using chunked binary transfer. Emits progress events and the asset ID on completion. */\nexport function uploadViaWebSocket(\n { url, project, token, chunkSize }: Required<ContelloUploaderParams>,\n file: File,\n meta: UploadAssetMetadata | undefined,\n options: { abort?: AbortSignal } | undefined,\n) {\n const metadata = { ...meta, projectRef: project };\n\n return new Observable<UploadAssetProgress | { id: string }>((obs) => {\n const parsedUrl = new URL(url);\n\n const ws = new WebSocket(\n `${parsedUrl.protocol === 'https:' ? 'wss' : 'ws'}://${parsedUrl.host}/api/v1/assets/ws`,\n 'contello-file-upload-v1',\n );\n\n let offset = 0;\n\n let done = false;\n let ackReceived = false;\n\n ws.addEventListener('open', () => {\n const initFrame: InitFrame = {\n type: 'init',\n metadata: {\n ...metadata,\n name: file.name,\n mimeType: file.type,\n size: file.size,\n },\n token,\n };\n\n ws.send(JSON.stringify(initFrame));\n\n function readSlice() {\n void (async () => {\n try {\n const buffer = await file.slice(offset, offset + chunkSize).arrayBuffer();\n\n handleArrayBuffer(buffer);\n } catch (error) {\n obs.error(error);\n }\n })();\n }\n\n function markAsDone() {\n ws.send(JSON.stringify({ type: 'done' }));\n }\n\n function startUpload() {\n if (ackReceived) {\n readSlice();\n }\n }\n\n function handleArrayBuffer(buffer: ArrayBuffer) {\n // bail between chunks if the upload was aborted — abortHandler already closed the socket and errored\n if (options?.abort?.aborted) {\n return;\n }\n\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(buffer);\n offset += buffer.byteLength;\n\n if (offset < file.size) {\n readSlice();\n } else {\n markAsDone();\n }\n } else {\n obs.error(new Error('WebSocket is closed'));\n }\n }\n\n ws.addEventListener('message', (event) => {\n const message: AckMessage | ProgressMessage | DoneMessage = JSON.parse(event.data);\n\n if (message.type === 'ack') {\n ackReceived = true;\n startUpload();\n return;\n }\n\n if (message.type === 'progress') {\n return obs.next({ progress: (message.bytesReceived / file.size) * 100 });\n }\n\n if (message.type === 'done') {\n if (message.id) {\n done = true;\n\n obs.next({ id: message.id });\n obs.complete();\n } else {\n obs.error(new Error('No asset id received'));\n }\n\n return ws.close();\n }\n\n obs.error(new Error(`WebSocket message with unknown type ${JSON.stringify(message)}`));\n ws.close();\n });\n });\n\n ws.addEventListener('error', (error) => obs.error(error));\n\n ws.addEventListener('close', () => {\n if (!done) {\n obs.error(new Error('Connection closed'));\n }\n });\n\n const abortHandler = () => {\n if (done) {\n return;\n }\n\n ws.close();\n obs.error(new Error('Upload aborted'));\n };\n\n options?.abort?.addEventListener('abort', abortHandler);\n\n return () => {\n options?.abort?.removeEventListener('abort', abortHandler);\n ws.close();\n };\n });\n}\n","import { Observable } from 'rxjs';\nimport type { UploadAssetMetadata, UploadAssetProgress } from '../upload-metadata';\nimport type { ContelloUploaderParams } from '../uploader';\n\n/** Uploads a file via XMLHttpRequest with multipart form data. Emits progress events and the asset ID on completion. */\nexport function uploadViaXhr(\n { url, project, token }: Required<ContelloUploaderParams>,\n file: File,\n meta: UploadAssetMetadata | undefined,\n options: { abort?: AbortSignal } | undefined,\n) {\n return new Observable<UploadAssetProgress | { id: string }>((obs) => {\n const data = new FormData();\n\n data.append('metadata', JSON.stringify({ ...meta, projectRef: project }));\n data.append('file', file);\n\n const xhr = new XMLHttpRequest();\n\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n\n xhr.open('POST', `${url}/api/v1/assets`, true);\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n obs.next({ progress: (event.loaded / event.total) * 100 });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n const { id }: { id: string } = JSON.parse(xhr.responseText);\n\n obs.next({ id });\n\n return obs.complete();\n }\n\n obs.error(new Error(`${xhr.status}: ${xhr.statusText}`));\n });\n\n xhr.addEventListener('error', (error) => obs.error(error));\n xhr.send(data);\n\n options?.abort?.addEventListener('abort', () => xhr.abort());\n\n return () => xhr.abort();\n });\n}\n","import { filter, firstValueFrom } from 'rxjs';\nimport { uploadViaWebSocket } from './implementations/ws';\nimport { uploadViaXhr } from './implementations/xhr';\nimport type { UploadAssetMetadata } from './upload-metadata';\n\nexport type ContelloUploaderParams = {\n /**\n * Base URL of the Contello server.\n * Example: 'https://example.com'\n */\n url: string;\n /**\n * Project identifier for the Contello project.\n * Example: 'myProjectId'\n */\n project: string;\n /**\n * Authentication token for the Contello API.\n * Example: 'app-a123b456c7890d123456789'\n */\n token: string;\n /**\n * Transport protocol to use for uploading files.\n * 'http' uses XMLHttpRequest, 'ws' uses WebSocket.\n * @default 'ws'\n */\n transport?: 'http' | 'ws';\n /**\n * Size of each chunk in bytes when uploading files.\n * Default is 4MB.\n * @default 4_194_304\n */\n chunkSize?: number;\n};\n\n/**\n * ContelloUploader is a class for uploading files to a Contello server.\n * It supports both WebSocket and HTTP transports.\n */\nexport class ContelloUploader {\n private params: Required<ContelloUploaderParams>;\n\n constructor(params: ContelloUploaderParams) {\n this.params = {\n url: params.url,\n project: params.project,\n token: params.token,\n transport: params.transport || 'ws',\n chunkSize: params.chunkSize || 4 * 1024 * 1024,\n };\n }\n\n /** Uploads a file and resolves with the asset ID once complete. */\n async upload(\n file: File,\n meta?: UploadAssetMetadata | undefined,\n options?: { abort?: AbortSignal } | undefined,\n ): Promise<{ id: string }> {\n return firstValueFrom(this.uploadWithEvents(file, meta, options).pipe(filter((r) => 'id' in r)));\n }\n\n /** Uploads a file and returns an Observable emitting progress events and the final asset ID. */\n uploadWithEvents(file: File, meta?: UploadAssetMetadata | undefined, options?: { abort?: AbortSignal } | undefined) {\n if (this.params.transport === 'http') {\n return uploadViaXhr(this.params, file, meta, options);\n }\n\n return uploadViaWebSocket(this.params, file, meta, options);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/upload-metadata.ts","../src/implementations/ws.ts","../src/implementations/xhr.ts","../src/uploader.ts"],"sourcesContent":["export type UploadAssetMetadata = {\n name?: string | undefined;\n mimeType?: string | undefined;\n size?: number | undefined;\n annotations?: UploadAssetAnnotation[] | undefined;\n collectionRefs?: string[] | undefined;\n image?: UploadAssetImageMetadata | undefined;\n retentionPolicy?: UploadAssetRetentionPolicy | undefined;\n generatePreview?: boolean | undefined;\n createdAt?: string | undefined;\n updatedAt?: string | undefined;\n};\n\nexport type UploadAssetAnnotation = {\n key: string;\n value: string;\n};\n\nexport type UploadAssetProgress = {\n progress: number;\n};\n\nexport enum UploadAssetRetentionPolicy {\n retain = 'retain',\n deleteIfNotUsed = 'deleteIfNotUsed',\n}\n\nexport type UploadAssetImageMetadata = {\n transformations: UploadAssetImageTransformation[];\n};\n\nexport type UploadAssetImageTransformation =\n | UploadAssetExtractTransformation\n | UploadAssetFitTransformation\n | UploadAssetConvertTransformation;\n\nexport type UploadAssetExtractTransformation = {\n name: 'extract';\n options: {\n top: number;\n left: number;\n areaWidth: number;\n areaHeight: number;\n rotate?: 0 | 90 | 180 | 270 | undefined;\n };\n};\n\nexport type UploadAssetFitTransformation = {\n name: 'fit';\n options: {\n width: number;\n height: number;\n };\n};\n\nexport type UploadAssetConvertTransformation = {\n name: 'convert';\n options:\n | UploadAssetConvertTransformationJpegOptions\n | UploadAssetConvertTransformationPngOptions\n | UploadAssetConvertTransformationAvifOptions;\n};\n\nexport type UploadAssetConvertTransformationJpegOptions = {\n format: 'jpeg';\n options: {\n quality: number; // 0-100\n interlace: boolean;\n };\n};\n\nexport type UploadAssetConvertTransformationPngOptions = {\n format: 'png';\n options: {\n compressionLevel: number; // 0-9\n };\n};\n\nexport type UploadAssetConvertTransformationAvifOptions = {\n format: 'avif';\n options: {\n quality: number; // 0-100\n lossless: boolean;\n };\n};\n","import { Observable } from 'rxjs';\nimport type { UploadAssetMetadata, UploadAssetProgress } from '../upload-metadata';\nimport type { ContelloUploaderParams } from '../uploader';\n\ntype InitFrame = {\n type: 'init';\n metadata: UploadAssetMetadata & { projectRef: string };\n token: string;\n};\n\ntype AckMessage = { type: 'ack' };\n\ntype ProgressMessage = { type: 'progress'; bytesReceived: number };\n\ntype DoneMessage = { type: 'done'; id: string };\n\n/** Uploads a file via WebSocket using chunked binary transfer. Emits progress events and the asset ID on completion. */\nexport function uploadViaWebSocket(\n { url, project, token, chunkSize }: Required<ContelloUploaderParams>,\n file: File,\n meta: UploadAssetMetadata | undefined,\n options: { abort?: AbortSignal } | undefined,\n) {\n const metadata = { ...meta, projectRef: project };\n\n return new Observable<UploadAssetProgress | { id: string }>((obs) => {\n const parsedUrl = new URL(url);\n\n const ws = new WebSocket(\n `${parsedUrl.protocol === 'https:' ? 'wss' : 'ws'}://${parsedUrl.host}/api/v1/assets/ws`,\n 'contello-file-upload-v1',\n );\n\n let offset = 0;\n\n let done = false;\n let ackReceived = false;\n\n ws.addEventListener('open', () => {\n const initFrame: InitFrame = {\n type: 'init',\n metadata: {\n ...metadata,\n name: file.name,\n mimeType: file.type,\n size: file.size,\n },\n token,\n };\n\n ws.send(JSON.stringify(initFrame));\n\n function readSlice() {\n void (async () => {\n try {\n const buffer = await file.slice(offset, offset + chunkSize).arrayBuffer();\n\n handleArrayBuffer(buffer);\n } catch (error) {\n obs.error(error);\n }\n })();\n }\n\n function markAsDone() {\n ws.send(JSON.stringify({ type: 'done' }));\n }\n\n function startUpload() {\n if (ackReceived) {\n readSlice();\n }\n }\n\n function handleArrayBuffer(buffer: ArrayBuffer) {\n // bail between chunks if the upload was aborted — abortHandler already closed the socket and errored\n if (options?.abort?.aborted) {\n return;\n }\n\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(buffer);\n offset += buffer.byteLength;\n\n if (offset < file.size) {\n readSlice();\n } else {\n markAsDone();\n }\n } else {\n obs.error(new Error('WebSocket is closed'));\n }\n }\n\n ws.addEventListener('message', (event) => {\n const message: AckMessage | ProgressMessage | DoneMessage = JSON.parse(event.data);\n\n if (message.type === 'ack') {\n ackReceived = true;\n startUpload();\n return;\n }\n\n if (message.type === 'progress') {\n return obs.next({ progress: (message.bytesReceived / file.size) * 100 });\n }\n\n if (message.type === 'done') {\n if (message.id) {\n done = true;\n\n obs.next({ id: message.id });\n obs.complete();\n } else {\n obs.error(new Error('No asset id received'));\n }\n\n return ws.close();\n }\n\n obs.error(new Error(`WebSocket message with unknown type ${JSON.stringify(message)}`));\n ws.close();\n });\n });\n\n ws.addEventListener('error', (error) => obs.error(error));\n\n ws.addEventListener('close', () => {\n if (!done) {\n obs.error(new Error('Connection closed'));\n }\n });\n\n const abortHandler = () => {\n if (done) {\n return;\n }\n\n ws.close();\n obs.error(new Error('Upload aborted'));\n };\n\n options?.abort?.addEventListener('abort', abortHandler);\n\n return () => {\n options?.abort?.removeEventListener('abort', abortHandler);\n ws.close();\n };\n });\n}\n","import { Observable } from 'rxjs';\nimport type { UploadAssetMetadata, UploadAssetProgress } from '../upload-metadata';\nimport type { ContelloUploaderParams } from '../uploader';\n\n/** Uploads a file via XMLHttpRequest with multipart form data. Emits progress events and the asset ID on completion. */\nexport function uploadViaXhr(\n { url, project, token }: Required<ContelloUploaderParams>,\n file: File,\n meta: UploadAssetMetadata | undefined,\n options: { abort?: AbortSignal } | undefined,\n) {\n return new Observable<UploadAssetProgress | { id: string }>((obs) => {\n const data = new FormData();\n\n data.append('metadata', JSON.stringify({ ...meta, projectRef: project }));\n data.append('file', file);\n\n const xhr = new XMLHttpRequest();\n\n xhr.open('POST', `${url}/api/v1/assets`, true);\n\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n obs.next({ progress: (event.loaded / event.total) * 100 });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n const { id }: { id: string } = JSON.parse(xhr.responseText);\n\n obs.next({ id });\n\n return obs.complete();\n }\n\n obs.error(new Error(`${xhr.status}: ${xhr.statusText}`));\n });\n\n xhr.addEventListener('error', (error) => obs.error(error));\n xhr.send(data);\n\n options?.abort?.addEventListener('abort', () => xhr.abort());\n\n return () => xhr.abort();\n });\n}\n","import { filter, firstValueFrom } from 'rxjs';\nimport { uploadViaWebSocket } from './implementations/ws';\nimport { uploadViaXhr } from './implementations/xhr';\nimport type { UploadAssetMetadata } from './upload-metadata';\n\nexport type ContelloUploaderParams = {\n /**\n * Base URL of the Contello server.\n * Example: 'https://example.com'\n */\n url: string;\n /**\n * Project identifier for the Contello project.\n * Example: 'myProjectId'\n */\n project: string;\n /**\n * Authentication token for the Contello API.\n * Example: 'app-a123b456c7890d123456789'\n */\n token: string;\n /**\n * Transport protocol to use for uploading files.\n * 'http' uses XMLHttpRequest, 'ws' uses WebSocket.\n * @default 'ws'\n */\n transport?: 'http' | 'ws';\n /**\n * Size of each chunk in bytes when uploading files.\n * Default is 4MB.\n * @default 4_194_304\n */\n chunkSize?: number;\n};\n\n/**\n * ContelloUploader is a class for uploading files to a Contello server.\n * It supports both WebSocket and HTTP transports.\n */\nexport class ContelloUploader {\n private params: Required<ContelloUploaderParams>;\n\n constructor(params: ContelloUploaderParams) {\n this.params = {\n url: params.url,\n project: params.project,\n token: params.token,\n transport: params.transport || 'ws',\n chunkSize: params.chunkSize || 4 * 1024 * 1024,\n };\n }\n\n /** Uploads a file and resolves with the asset ID once complete. */\n async upload(\n file: File,\n meta?: UploadAssetMetadata | undefined,\n options?: { abort?: AbortSignal } | undefined,\n ): Promise<{ id: string }> {\n return firstValueFrom(this.uploadWithEvents(file, meta, options).pipe(filter((r) => 'id' in r)));\n }\n\n /** Uploads a file and returns an Observable emitting progress events and the final asset ID. */\n uploadWithEvents(file: File, meta?: UploadAssetMetadata | undefined, options?: { abort?: AbortSignal } | undefined) {\n if (this.params.transport === 'http') {\n return uploadViaXhr(this.params, file, meta, options);\n }\n\n return uploadViaWebSocket(this.params, file, meta, options);\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contello/uploader",
3
- "version": "8.21.5",
3
+ "version": "8.21.6",
4
4
  "description": "File uploader for Contello CMS with WebSocket and HTTP transports",
5
5
  "type": "module",
6
6
  "license": "MIT",