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