@proveanything/smartlinks 1.15.14 → 1.15.16

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.
@@ -1,4 +1,4 @@
1
- import { Asset, AssetResponse, UploadAssetOptions, UploadFromUrlOptions, ListAssetsOptions, GetAssetOptions, RemoveAssetOptions, AdminListAssetsOptions, AdminListAssetsResponse, UpdateAssetOptions, ReplaceAssetFileOptions, DeleteAssetOptions, BulkDeleteAssetsOptions, RequestUploadTokenOptions, UploadTokenResponse, PublicTokenUploadOptions } from "../types/asset";
1
+ import { Asset, AssetResponse, UploadAssetOptions, UploadFromUrlOptions, ListAssetsOptions, GetAssetOptions, RemoveAssetOptions, AdminListAssetsOptions, AdminListAssetsResponse, UpdateAssetOptions, ReplaceAssetFileOptions, DeleteAssetOptions, BulkDeleteAssetsOptions, RequestUploadTokenOptions, UploadTokenResponse, PublicTokenUploadOptions, CreateResumableUploadOptions, ResumableUploadHandle } from "../types/asset";
2
2
  export declare namespace asset {
3
3
  /**
4
4
  * Error type for asset uploads
@@ -136,4 +136,27 @@ export declare namespace asset {
136
136
  * has `reviewRequired: true`.
137
137
  */
138
138
  function publicUploadWithToken(options: PublicTokenUploadOptions): Promise<Asset>;
139
+ /** Thrown by a resumable `start()`/`resume()` when the caller pauses mid-transfer. */
140
+ class UploadPausedError extends Error {
141
+ constructor();
142
+ }
143
+ /**
144
+ * Open a resumable upload for a large file (e.g. video). The bytes are chunked
145
+ * directly to storage and can be paused/resumed — including after a page reload
146
+ * or app restart, by persisting `handle.id` and calling {@link resumeUpload}.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * const handle = await asset.createResumableUpload({ file, scope, appId })
151
+ * localStorage.setItem('pendingUpload', handle.id) // survives reload
152
+ * const uploaded = await handle.start({ onProgress: p => setPct(p) })
153
+ * ```
154
+ */
155
+ function createResumableUpload(options: CreateResumableUploadOptions): Promise<ResumableUploadHandle>;
156
+ /**
157
+ * Resume a previously-created resumable upload after a reload/app restart.
158
+ * Pass the persisted `handle.id` and the same `File`; the transfer continues
159
+ * from the offset storage already holds rather than restarting.
160
+ */
161
+ function resumeUpload(handleId: string, file: File): Promise<ResumableUploadHandle>;
139
162
  }
package/dist/api/asset.js CHANGED
@@ -104,6 +104,14 @@ export var asset;
104
104
  }
105
105
  };
106
106
  xhr.onerror = () => reject(new AssetUploadError("Network error during asset upload", 'NETWORK_ERROR'));
107
+ if (options.signal) {
108
+ if (options.signal.aborted) {
109
+ xhr.abort();
110
+ return reject(new AssetUploadError("Upload aborted", 'NETWORK_ERROR'));
111
+ }
112
+ options.signal.addEventListener('abort', () => xhr.abort(), { once: true });
113
+ xhr.onabort = () => reject(new AssetUploadError("Upload aborted", 'NETWORK_ERROR'));
114
+ }
107
115
  xhr.send(formData);
108
116
  });
109
117
  }
@@ -529,4 +537,174 @@ export var asset;
529
537
  return response.json();
530
538
  }
531
539
  asset.publicUploadWithToken = publicUploadWithToken;
540
+ // ---------------------------------------------------------------------------
541
+ // Resumable uploads (large files, e.g. video) — GCS-backed, chunked, resumable
542
+ // ---------------------------------------------------------------------------
543
+ const RESUMABLE_CHUNK_SIZE = 8 * 1024 * 1024; // 8 MiB — must be a multiple of 256 KiB (GCS rule)
544
+ const RESUMABLE_MAX_RETRIES = 5;
545
+ /** Thrown by a resumable `start()`/`resume()` when the caller pauses mid-transfer. */
546
+ class UploadPausedError extends Error {
547
+ constructor() { super('Upload paused'); this.name = 'UploadPausedError'; }
548
+ }
549
+ asset.UploadPausedError = UploadPausedError;
550
+ function backoff(attempt) {
551
+ const ms = Math.min(30000, 1000 * Math.pow(2, attempt - 1));
552
+ return new Promise(r => setTimeout(r, ms));
553
+ }
554
+ class ResumableUpload {
555
+ constructor(uploadId, // signed JWT — capability for finalize
556
+ sessionUrl, // GCS resumable session URI
557
+ file, finalizePath, finalizeBody) {
558
+ this.uploadId = uploadId;
559
+ this.sessionUrl = sessionUrl;
560
+ this.file = file;
561
+ this.finalizePath = finalizePath;
562
+ this.finalizeBody = finalizeBody;
563
+ this._paused = false;
564
+ this._offset = 0;
565
+ }
566
+ get id() {
567
+ const st = { u: this.uploadId, s: this.sessionUrl, n: this.file.name, z: this.file.size, f: this.finalizePath };
568
+ return JSON.stringify(st);
569
+ }
570
+ get size() { return this.file.size; }
571
+ pause() { this._paused = true; }
572
+ resume(options) {
573
+ this._paused = false;
574
+ return this.start(options);
575
+ }
576
+ async start(options) {
577
+ this._paused = false;
578
+ const onProgress = options === null || options === void 0 ? void 0 : options.onProgress;
579
+ const signal = options === null || options === void 0 ? void 0 : options.signal;
580
+ // Probe the storage offset first — this is what makes resume work after a reload.
581
+ this._offset = await this.probeOffset(signal);
582
+ while (this._offset < this.file.size) {
583
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
584
+ throw new AssetUploadError('Upload aborted', 'NETWORK_ERROR');
585
+ if (this._paused)
586
+ throw new UploadPausedError();
587
+ const end = Math.min(this._offset + RESUMABLE_CHUNK_SIZE, this.file.size);
588
+ const complete = await this.putChunk(this._offset, end, signal);
589
+ this._offset = end;
590
+ if (onProgress)
591
+ onProgress(Math.round((this._offset / this.file.size) * 100));
592
+ if (complete)
593
+ break;
594
+ }
595
+ return post(this.finalizePath, this.finalizeBody);
596
+ }
597
+ // PUT with `bytes * /total` returns the current stored offset (or completion).
598
+ async probeOffset(signal) {
599
+ const res = await this.putWithRetry({ 'Content-Range': `bytes */${this.file.size}` }, undefined, signal);
600
+ if (res.status === 200 || res.status === 201)
601
+ return this.file.size;
602
+ if (res.status === 308) {
603
+ const range = res.headers.get('Range');
604
+ const m = range && /bytes=0-(\d+)/.exec(range);
605
+ return m ? parseInt(m[1], 10) + 1 : 0;
606
+ }
607
+ if (res.status === 404 || res.status === 410)
608
+ throw new AssetUploadError('Upload session expired', 'UNKNOWN');
609
+ throw new AssetUploadError(`Unexpected resume-probe status ${res.status}`, 'UNKNOWN');
610
+ }
611
+ // Returns true when the final chunk completed the upload (2xx from GCS).
612
+ async putChunk(start, end, signal) {
613
+ const blob = this.file.slice(start, end);
614
+ const res = await this.putWithRetry({ 'Content-Range': `bytes ${start}-${end - 1}/${this.file.size}` }, blob, signal);
615
+ if (res.status === 200 || res.status === 201)
616
+ return true;
617
+ if (res.status === 308)
618
+ return false;
619
+ throw new AssetUploadError(`Chunk upload failed (${res.status})`, res.status === 413 ? 'FILE_TOO_LARGE' : 'UNKNOWN');
620
+ }
621
+ async putWithRetry(headers, body, signal) {
622
+ let attempt = 0;
623
+ while (true) {
624
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
625
+ throw new AssetUploadError('Upload aborted', 'NETWORK_ERROR');
626
+ try {
627
+ const res = await fetch(this.sessionUrl, { method: 'PUT', headers, body, signal });
628
+ if (res.status >= 500 && attempt < RESUMABLE_MAX_RETRIES) {
629
+ attempt++;
630
+ await backoff(attempt);
631
+ continue;
632
+ }
633
+ return res;
634
+ }
635
+ catch (err) {
636
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
637
+ throw new AssetUploadError('Upload aborted', 'NETWORK_ERROR');
638
+ if (attempt < RESUMABLE_MAX_RETRIES) {
639
+ attempt++;
640
+ await backoff(attempt);
641
+ continue;
642
+ }
643
+ throw new AssetUploadError('Network error during resumable upload', 'NETWORK_ERROR');
644
+ }
645
+ }
646
+ }
647
+ }
648
+ function resumableBasePath(opts) {
649
+ const prefix = (opts.admin && !opts.token) ? '/admin' : '/public';
650
+ return `${prefix}/collection/${encodeURIComponent(opts.collectionId)}/asset/resumable`;
651
+ }
652
+ /**
653
+ * Open a resumable upload for a large file (e.g. video). The bytes are chunked
654
+ * directly to storage and can be paused/resumed — including after a page reload
655
+ * or app restart, by persisting `handle.id` and calling {@link resumeUpload}.
656
+ *
657
+ * @example
658
+ * ```ts
659
+ * const handle = await asset.createResumableUpload({ file, scope, appId })
660
+ * localStorage.setItem('pendingUpload', handle.id) // survives reload
661
+ * const uploaded = await handle.start({ onProgress: p => setPct(p) })
662
+ * ```
663
+ */
664
+ async function createResumableUpload(options) {
665
+ const { file, scope, name, appId, token, admin } = options;
666
+ const base = resumableBasePath({ admin, token, collectionId: scope.collectionId });
667
+ const startBody = {
668
+ filename: name || file.name,
669
+ mime: file.type || 'application/octet-stream',
670
+ appId,
671
+ };
672
+ if (scope.type !== 'collection')
673
+ startBody.productId = scope.productId;
674
+ if (scope.type === 'proof')
675
+ startBody.proofId = scope.proofId;
676
+ const started = await post(base, startBody, token ? { 'X-Upload-Token': token } : undefined);
677
+ const finalizePath = `${base}/${encodeURIComponent(started.uploadId)}/complete`;
678
+ const finalizeBody = {};
679
+ if (name)
680
+ finalizeBody.name = name;
681
+ if (options.metadata)
682
+ finalizeBody.metadata = options.metadata;
683
+ return new ResumableUpload(started.uploadId, started.sessionUrl, file, finalizePath, finalizeBody);
684
+ }
685
+ asset.createResumableUpload = createResumableUpload;
686
+ /**
687
+ * Resume a previously-created resumable upload after a reload/app restart.
688
+ * Pass the persisted `handle.id` and the same `File`; the transfer continues
689
+ * from the offset storage already holds rather than restarting.
690
+ */
691
+ async function resumeUpload(handleId, file) {
692
+ let st;
693
+ try {
694
+ st = JSON.parse(handleId);
695
+ }
696
+ catch (_b) {
697
+ throw new AssetUploadError('Invalid resumable upload handle', 'UNKNOWN');
698
+ }
699
+ if (!st.u || !st.s || !st.f)
700
+ throw new AssetUploadError('Invalid resumable upload handle', 'UNKNOWN');
701
+ if (typeof st.z === 'number' && file.size !== st.z) {
702
+ throw new AssetUploadError('Resumed file does not match the original upload', 'UNKNOWN');
703
+ }
704
+ const finalizeBody = {};
705
+ if (st.n)
706
+ finalizeBody.name = st.n;
707
+ return new ResumableUpload(st.u, st.s, file, st.f, finalizeBody);
708
+ }
709
+ asset.resumeUpload = resumeUpload;
532
710
  })(asset || (asset = {}));
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.15.14 | Generated: 2026-07-29T07:45:17.540Z
3
+ Version: 1.15.16 | Generated: 2026-08-15T11:42:50.997Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -170,6 +170,9 @@ Replace or augment globally applied custom headers.
170
170
  **setBearerToken**(token: string | undefined) → `void`
171
171
  Allows setting the bearerToken at runtime (e.g. after login/logout). Clears the HTTP cache whenever the token actually changes so that stale user-scoped responses (e.g. /account/profile) are not served after a login or logout event.
172
172
 
173
+ **getBearerToken**() → `string | undefined`
174
+ Returns the bearer token currently held by the SDK, or `undefined` if none is set. In proxy mode, credentials are held by the parent frame, not the local SDK, so this returns `undefined` even when the caller is authenticated.
175
+
173
176
  **getBaseURL**() → `string | null`
174
177
  Get the currently configured API base URL. Returns null if initializeApi() has not been called yet.
175
178
 
@@ -2456,6 +2459,7 @@ interface UploadAssetOptions {
2456
2459
  onProgress?: (percent: number) => void
2457
2460
  appId?: string
2458
2461
  admin?: boolean
2462
+ signal?: AbortSignal
2459
2463
  }
2460
2464
  ```
2461
2465
 
@@ -2636,6 +2640,43 @@ interface PublicTokenUploadOptions {
2636
2640
  }
2637
2641
  ```
2638
2642
 
2643
+ **CreateResumableUploadOptions** (interface)
2644
+ ```typescript
2645
+ interface CreateResumableUploadOptions {
2646
+ file: File
2647
+ scope:
2648
+ | { type: 'collection'; collectionId: string }
2649
+ | { type: 'product'; collectionId: string; productId: string }
2650
+ | { type: 'proof'; collectionId: string; productId: string; proofId: string }
2651
+ name?: string
2652
+ metadata?: Record<string, any>
2653
+ appId?: string
2654
+ admin?: boolean
2655
+ * Upload token id (from {@link requestUploadToken}) for public/unauthenticated
2656
+ * uploads. When provided, the public resumable route is used.
2657
+ token?: string
2658
+ }
2659
+ ```
2660
+
2661
+ **ResumableStartOptions** (interface)
2662
+ ```typescript
2663
+ interface ResumableStartOptions {
2664
+ onProgress?: (percent: number) => void
2665
+ signal?: AbortSignal
2666
+ }
2667
+ ```
2668
+
2669
+ **ResumableUploadHandle** (interface)
2670
+ ```typescript
2671
+ interface ResumableUploadHandle {
2672
+ readonly id: string
2673
+ readonly size: number
2674
+ start(options?: ResumableStartOptions): Promise<Asset>
2675
+ pause(): void
2676
+ resume(options?: ResumableStartOptions): Promise<Asset>
2677
+ }
2678
+ ```
2679
+
2639
2680
  **AssetResponse** = `Asset`
2640
2681
 
2641
2682
  ### attestation
@@ -8476,6 +8517,12 @@ Request a single-use upload token for a public (unauthenticated) upload. The tok
8476
8517
  **publicUploadWithToken**(options: PublicTokenUploadOptions) → `Promise<Asset>`
8477
8518
  Upload a file using a single-use upload token (no admin auth required). Assets are created with `status: 'pending_review'` when the token policy has `reviewRequired: true`.
8478
8519
 
8520
+ **createResumableUpload**(options: CreateResumableUploadOptions) → `Promise<ResumableUploadHandle>`
8521
+ Open a resumable upload for a large file (e.g. video). The bytes are chunked directly to storage and can be paused/resumed — including after a page reload or app restart, by persisting `handle.id` and calling {@link resumeUpload}. ```ts const handle = await asset.createResumableUpload({ file, scope, appId }) localStorage.setItem('pendingUpload', handle.id) // survives reload const uploaded = await handle.start({ onProgress: p => setPct(p) }) ```
8522
+
8523
+ **resumeUpload**(handleId: string, file: File) → `Promise<ResumableUploadHandle>`
8524
+ Resume a previously-created resumable upload after a reload/app restart. Pass the persisted `handle.id` and the same `File`; the transfer continues from the offset storage already holds rather than restarting.
8525
+
8479
8526
  ### async
8480
8527
 
8481
8528
  **enqueueAsyncJob**(collectionId: string,
package/dist/http.d.ts CHANGED
@@ -49,6 +49,12 @@ export declare function setExtraHeaders(headers: Record<string, string>): void;
49
49
  * login or logout event.
50
50
  */
51
51
  export declare function setBearerToken(token: string | undefined): void;
52
+ /**
53
+ * Returns the bearer token currently held by the SDK, or `undefined` if none is set.
54
+ * In proxy mode, credentials are held by the parent frame, not the local SDK,
55
+ * so this returns `undefined` even when the caller is authenticated.
56
+ */
57
+ export declare function getBearerToken(): string | undefined;
52
58
  /**
53
59
  * Get the currently configured API base URL.
54
60
  * Returns null if initializeApi() has not been called yet.
package/dist/http.js CHANGED
@@ -466,6 +466,14 @@ export function setBearerToken(token) {
466
466
  if (cachePersistence !== 'none')
467
467
  idbClear().catch(() => { });
468
468
  }
469
+ /**
470
+ * Returns the bearer token currently held by the SDK, or `undefined` if none is set.
471
+ * In proxy mode, credentials are held by the parent frame, not the local SDK,
472
+ * so this returns `undefined` even when the caller is authenticated.
473
+ */
474
+ export function getBearerToken() {
475
+ return bearerToken;
476
+ }
469
477
  /**
470
478
  * Get the currently configured API base URL.
471
479
  * Returns null if initializeApi() has not been called yet.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, isProxyEnabled, setBearerToken } from "./http";
1
+ export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, isProxyEnabled, setBearerToken, getBearerToken } from "./http";
2
2
  export * from "./api";
3
3
  export * from "./types";
4
4
  export { iframe } from "./iframe";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  // Top-level entrypoint of the npm package. Re-export initializeApi + all namespaces.
3
- export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, isProxyEnabled, setBearerToken } from "./http";
3
+ export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, isProxyEnabled, setBearerToken, getBearerToken } from "./http";
4
4
  export * from "./api";
5
5
  export * from "./types";
6
6
  // Iframe namespace
package/dist/openapi.yaml CHANGED
@@ -17731,6 +17731,8 @@ components:
17731
17731
  type: string
17732
17732
  admin:
17733
17733
  type: boolean
17734
+ signal:
17735
+ $ref: "#/components/schemas/AbortSignal"
17734
17736
  required:
17735
17737
  - file
17736
17738
  UploadFromUrlOptions:
@@ -17996,6 +17998,39 @@ components:
17996
17998
  - collectionId
17997
17999
  - tokenId
17998
18000
  - file
18001
+ CreateResumableUploadOptions:
18002
+ type: object
18003
+ properties:
18004
+ file:
18005
+ $ref: "#/components/schemas/File"
18006
+ name:
18007
+ type: string
18008
+ metadata:
18009
+ type: object
18010
+ additionalProperties: true
18011
+ appId:
18012
+ type: string
18013
+ admin:
18014
+ type: boolean
18015
+ token:
18016
+ type: string
18017
+ required:
18018
+ - file
18019
+ ResumableStartOptions:
18020
+ type: object
18021
+ properties:
18022
+ signal:
18023
+ $ref: "#/components/schemas/AbortSignal"
18024
+ ResumableUploadHandle:
18025
+ type: object
18026
+ properties:
18027
+ id:
18028
+ type: string
18029
+ size:
18030
+ type: number
18031
+ required:
18032
+ - id
18033
+ - size
17999
18034
  AttestationResponse:
18000
18035
  type: object
18001
18036
  properties:
@@ -122,6 +122,8 @@ export interface UploadAssetOptions {
122
122
  appId?: string;
123
123
  /** Optional: Upload via admin route instead of public */
124
124
  admin?: boolean;
125
+ /** Optional: Abort the in-flight upload (browser fetch/XHR only) */
126
+ signal?: AbortSignal;
125
127
  }
126
128
  /**
127
129
  * Options for uploading an asset from a URL.
@@ -304,3 +306,57 @@ export interface PublicTokenUploadOptions {
304
306
  metadata?: Record<string, any>;
305
307
  onProgress?: (percent: number) => void;
306
308
  }
309
+ /**
310
+ * Options for opening a resumable upload. Mirrors {@link UploadAssetOptions}
311
+ * but the transfer is chunked directly to storage and can be paused/resumed,
312
+ * including after a page reload or app restart.
313
+ */
314
+ export interface CreateResumableUploadOptions {
315
+ file: File;
316
+ scope: {
317
+ type: 'collection';
318
+ collectionId: string;
319
+ } | {
320
+ type: 'product';
321
+ collectionId: string;
322
+ productId: string;
323
+ } | {
324
+ type: 'proof';
325
+ collectionId: string;
326
+ productId: string;
327
+ proofId: string;
328
+ };
329
+ name?: string;
330
+ metadata?: Record<string, any>;
331
+ appId?: string;
332
+ /** Upload via admin route (default) or, when set, the public token route. */
333
+ admin?: boolean;
334
+ /**
335
+ * Upload token id (from {@link requestUploadToken}) for public/unauthenticated
336
+ * uploads. When provided, the public resumable route is used.
337
+ */
338
+ token?: string;
339
+ }
340
+ export interface ResumableStartOptions {
341
+ /** Progress callback (0-100), driven by bytes confirmed by storage. */
342
+ onProgress?: (percent: number) => void;
343
+ /** Abort the in-flight transfer. */
344
+ signal?: AbortSignal;
345
+ }
346
+ /**
347
+ * A handle to a resumable upload. `id` is durable — persist it (e.g. in
348
+ * IndexedDB) alongside a reference to the file and pass it to
349
+ * {@link asset.resumeUpload} after a reload to continue mid-file.
350
+ */
351
+ export interface ResumableUploadHandle {
352
+ /** Durable, persistable upload id (survives reload/app restart). */
353
+ readonly id: string;
354
+ /** Total bytes of the file being uploaded. */
355
+ readonly size: number;
356
+ /** Begin (or continue) uploading, resuming from the storage offset. */
357
+ start(options?: ResumableStartOptions): Promise<Asset>;
358
+ /** Pause after the current chunk. */
359
+ pause(): void;
360
+ /** Resume a paused transfer. */
361
+ resume(options?: ResumableStartOptions): Promise<Asset>;
362
+ }
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.15.14 | Generated: 2026-07-29T07:45:17.540Z
3
+ Version: 1.15.16 | Generated: 2026-08-15T11:42:50.997Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -170,6 +170,9 @@ Replace or augment globally applied custom headers.
170
170
  **setBearerToken**(token: string | undefined) → `void`
171
171
  Allows setting the bearerToken at runtime (e.g. after login/logout). Clears the HTTP cache whenever the token actually changes so that stale user-scoped responses (e.g. /account/profile) are not served after a login or logout event.
172
172
 
173
+ **getBearerToken**() → `string | undefined`
174
+ Returns the bearer token currently held by the SDK, or `undefined` if none is set. In proxy mode, credentials are held by the parent frame, not the local SDK, so this returns `undefined` even when the caller is authenticated.
175
+
173
176
  **getBaseURL**() → `string | null`
174
177
  Get the currently configured API base URL. Returns null if initializeApi() has not been called yet.
175
178
 
@@ -2456,6 +2459,7 @@ interface UploadAssetOptions {
2456
2459
  onProgress?: (percent: number) => void
2457
2460
  appId?: string
2458
2461
  admin?: boolean
2462
+ signal?: AbortSignal
2459
2463
  }
2460
2464
  ```
2461
2465
 
@@ -2636,6 +2640,43 @@ interface PublicTokenUploadOptions {
2636
2640
  }
2637
2641
  ```
2638
2642
 
2643
+ **CreateResumableUploadOptions** (interface)
2644
+ ```typescript
2645
+ interface CreateResumableUploadOptions {
2646
+ file: File
2647
+ scope:
2648
+ | { type: 'collection'; collectionId: string }
2649
+ | { type: 'product'; collectionId: string; productId: string }
2650
+ | { type: 'proof'; collectionId: string; productId: string; proofId: string }
2651
+ name?: string
2652
+ metadata?: Record<string, any>
2653
+ appId?: string
2654
+ admin?: boolean
2655
+ * Upload token id (from {@link requestUploadToken}) for public/unauthenticated
2656
+ * uploads. When provided, the public resumable route is used.
2657
+ token?: string
2658
+ }
2659
+ ```
2660
+
2661
+ **ResumableStartOptions** (interface)
2662
+ ```typescript
2663
+ interface ResumableStartOptions {
2664
+ onProgress?: (percent: number) => void
2665
+ signal?: AbortSignal
2666
+ }
2667
+ ```
2668
+
2669
+ **ResumableUploadHandle** (interface)
2670
+ ```typescript
2671
+ interface ResumableUploadHandle {
2672
+ readonly id: string
2673
+ readonly size: number
2674
+ start(options?: ResumableStartOptions): Promise<Asset>
2675
+ pause(): void
2676
+ resume(options?: ResumableStartOptions): Promise<Asset>
2677
+ }
2678
+ ```
2679
+
2639
2680
  **AssetResponse** = `Asset`
2640
2681
 
2641
2682
  ### attestation
@@ -8476,6 +8517,12 @@ Request a single-use upload token for a public (unauthenticated) upload. The tok
8476
8517
  **publicUploadWithToken**(options: PublicTokenUploadOptions) → `Promise<Asset>`
8477
8518
  Upload a file using a single-use upload token (no admin auth required). Assets are created with `status: 'pending_review'` when the token policy has `reviewRequired: true`.
8478
8519
 
8520
+ **createResumableUpload**(options: CreateResumableUploadOptions) → `Promise<ResumableUploadHandle>`
8521
+ Open a resumable upload for a large file (e.g. video). The bytes are chunked directly to storage and can be paused/resumed — including after a page reload or app restart, by persisting `handle.id` and calling {@link resumeUpload}. ```ts const handle = await asset.createResumableUpload({ file, scope, appId }) localStorage.setItem('pendingUpload', handle.id) // survives reload const uploaded = await handle.start({ onProgress: p => setPct(p) }) ```
8522
+
8523
+ **resumeUpload**(handleId: string, file: File) → `Promise<ResumableUploadHandle>`
8524
+ Resume a previously-created resumable upload after a reload/app restart. Pass the persisted `handle.id` and the same `File`; the transfer continues from the offset storage already holds rather than restarting.
8525
+
8479
8526
  ### async
8480
8527
 
8481
8528
  **enqueueAsyncJob**(collectionId: string,
package/openapi.yaml CHANGED
@@ -17731,6 +17731,8 @@ components:
17731
17731
  type: string
17732
17732
  admin:
17733
17733
  type: boolean
17734
+ signal:
17735
+ $ref: "#/components/schemas/AbortSignal"
17734
17736
  required:
17735
17737
  - file
17736
17738
  UploadFromUrlOptions:
@@ -17996,6 +17998,39 @@ components:
17996
17998
  - collectionId
17997
17999
  - tokenId
17998
18000
  - file
18001
+ CreateResumableUploadOptions:
18002
+ type: object
18003
+ properties:
18004
+ file:
18005
+ $ref: "#/components/schemas/File"
18006
+ name:
18007
+ type: string
18008
+ metadata:
18009
+ type: object
18010
+ additionalProperties: true
18011
+ appId:
18012
+ type: string
18013
+ admin:
18014
+ type: boolean
18015
+ token:
18016
+ type: string
18017
+ required:
18018
+ - file
18019
+ ResumableStartOptions:
18020
+ type: object
18021
+ properties:
18022
+ signal:
18023
+ $ref: "#/components/schemas/AbortSignal"
18024
+ ResumableUploadHandle:
18025
+ type: object
18026
+ properties:
18027
+ id:
18028
+ type: string
18029
+ size:
18030
+ type: number
18031
+ required:
18032
+ - id
18033
+ - size
17999
18034
  AttestationResponse:
18000
18035
  type: object
18001
18036
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.15.14",
3
+ "version": "1.15.16",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",