@sparkvault/sdk 1.10.0 → 1.10.1

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.
@@ -8180,48 +8180,66 @@ class UploadRenderer {
8180
8180
  }
8181
8181
  // Build full upload URL
8182
8182
  const uploadUrl = location.startsWith('http') ? location : `${url.origin}${location}`;
8183
- // Step 2: Upload file in chunks
8183
+ // Step 2: Upload file in chunks with progress tracking
8184
8184
  let offset = 0;
8185
8185
  const totalSize = file.size;
8186
8186
  while (offset < totalSize) {
8187
- const end = Math.min(offset + chunkSize, totalSize);
8188
- const chunk = file.slice(offset, end);
8189
- // Upload chunk
8190
- const patchResponse = await fetch(uploadUrl, {
8191
- method: 'PATCH',
8192
- headers: {
8193
- 'Tus-Resumable': TUS_VERSION,
8194
- 'Upload-Offset': String(offset),
8195
- 'Content-Type': 'application/offset+octet-stream',
8196
- },
8197
- body: chunk,
8198
- });
8199
- if (!patchResponse.ok) {
8200
- const errorText = await patchResponse.text();
8201
- throw new Error(`Chunk upload failed: ${patchResponse.status} ${errorText}`);
8202
- }
8203
- // Update offset from server response
8204
- const newOffsetHeader = patchResponse.headers.get('Upload-Offset');
8205
- const newOffset = newOffsetHeader ? parseInt(newOffsetHeader, 10) : end;
8187
+ const chunkStart = offset;
8188
+ const chunkEnd = Math.min(offset + chunkSize, totalSize);
8189
+ const chunk = file.slice(chunkStart, chunkEnd);
8190
+ // Upload chunk with XHR for progress events
8191
+ const newOffset = await this.uploadChunkWithProgress(uploadUrl, chunk, chunkStart, totalSize, TUS_VERSION, file, ingotId, requestId);
8206
8192
  offset = newOffset;
8207
- // Update progress
8208
- const progress = Math.round((offset / totalSize) * 100);
8209
- this.setState({
8210
- view: 'uploading',
8211
- file,
8212
- ingotId,
8213
- requestId,
8214
- progress,
8215
- bytesUploaded: offset,
8216
- });
8217
- this.callbacks.onProgress?.({
8218
- bytesUploaded: offset,
8219
- bytesTotal: totalSize,
8220
- percentage: progress,
8221
- phase: 'uploading',
8222
- });
8223
8193
  }
8224
8194
  }
8195
+ /**
8196
+ * Upload a single chunk using XMLHttpRequest for progress tracking
8197
+ */
8198
+ uploadChunkWithProgress(uploadUrl, chunk, chunkStart, totalSize, tusVersion, file, ingotId, requestId) {
8199
+ return new Promise((resolve, reject) => {
8200
+ const xhr = new XMLHttpRequest();
8201
+ // Track progress within this chunk
8202
+ xhr.upload.onprogress = (e) => {
8203
+ if (e.lengthComputable) {
8204
+ // Calculate total progress: completed chunks + progress within current chunk
8205
+ const totalUploaded = chunkStart + e.loaded;
8206
+ const progress = Math.round((totalUploaded / totalSize) * 100);
8207
+ this.setState({
8208
+ view: 'uploading',
8209
+ file,
8210
+ ingotId,
8211
+ requestId,
8212
+ progress,
8213
+ bytesUploaded: totalUploaded,
8214
+ });
8215
+ this.callbacks.onProgress?.({
8216
+ bytesUploaded: totalUploaded,
8217
+ bytesTotal: totalSize,
8218
+ percentage: progress,
8219
+ phase: 'uploading',
8220
+ });
8221
+ }
8222
+ };
8223
+ xhr.onload = () => {
8224
+ if (xhr.status >= 200 && xhr.status < 300) {
8225
+ // Get new offset from server response
8226
+ const newOffsetHeader = xhr.getResponseHeader('Upload-Offset');
8227
+ const newOffset = newOffsetHeader ? parseInt(newOffsetHeader, 10) : chunkStart + chunk.size;
8228
+ resolve(newOffset);
8229
+ }
8230
+ else {
8231
+ reject(new Error(`Chunk upload failed with status ${xhr.status}`));
8232
+ }
8233
+ };
8234
+ xhr.onerror = () => reject(new Error('Chunk upload failed'));
8235
+ xhr.ontimeout = () => reject(new Error('Chunk upload timed out'));
8236
+ xhr.open('PATCH', uploadUrl);
8237
+ xhr.setRequestHeader('Tus-Resumable', tusVersion);
8238
+ xhr.setRequestHeader('Upload-Offset', String(chunkStart));
8239
+ xhr.setRequestHeader('Content-Type', 'application/offset+octet-stream');
8240
+ xhr.send(chunk);
8241
+ });
8242
+ }
8225
8243
  async runCeremony(file, ingotId, requestId) {
8226
8244
  for (let i = 0; i < CEREMONY_STEPS.length; i++) {
8227
8245
  this.setState({