@proveanything/smartlinks 1.1.24 → 1.1.26

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/API_SUMMARY.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.1.24 | Generated: 2026-01-11T11:29:10.460Z
3
+ Version: 1.1.26 | Generated: 2026-01-17T11:03:13.776Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -57,6 +57,9 @@ The Smartlinks SDK is organized into the following namespaces:
57
57
 
58
58
  Core HTTP functions for API configuration and communication:
59
59
 
60
+ **isProxyEnabled**() → `boolean`
61
+ Return whether proxy mode is currently enabled.
62
+
60
63
  **initializeApi**(options: {
61
64
  baseURL: string
62
65
  apiKey?: string
@@ -78,6 +81,11 @@ Replace or augment globally applied custom headers.
78
81
  **setBearerToken**(token: string | undefined) → `void`
79
82
  Allows setting the bearerToken at runtime (e.g. after login/logout).
80
83
 
84
+ **proxyUploadFormData**(path: string,
85
+ formData: FormData,
86
+ onProgress?: (percent: number) → `void`
87
+ Upload a FormData payload via proxy with progress events using chunked postMessage. Parent is expected to implement the counterpart protocol.
88
+
81
89
  **request**(path: string) → `Promise<T>`
82
90
  Internal helper that performs a GET request to \`\${baseURL}\${path}\`, injecting headers for apiKey or bearerToken if present. Returns the parsed JSON as T, or throws an Error.
83
91
 
@@ -1518,7 +1526,7 @@ interface Proof {
1518
1526
  tokenId: string
1519
1527
  userId: string
1520
1528
  claimable?: boolean
1521
- transient?: boolean
1529
+ virtual?: boolean
1522
1530
  values: Record<string, any>
1523
1531
  }
1524
1532
  ```
@@ -1528,7 +1536,7 @@ interface Proof {
1528
1536
  interface ProofCreateRequest {
1529
1537
  values: Record<string, any>
1530
1538
  claimable?: boolean
1531
- transient?: boolean
1539
+ virtual?: boolean
1532
1540
  }
1533
1541
  ```
1534
1542
 
@@ -1809,7 +1817,8 @@ type AccountInfoResponse = {
1809
1817
  };
1810
1818
  sub: string;
1811
1819
  uid: string;
1812
- user_id: string;
1820
+ userId: string;
1821
+ contactId: string
1813
1822
  whitelabel: {
1814
1823
  [key: string]: any;
1815
1824
  }
package/README.md CHANGED
@@ -180,6 +180,90 @@ await asset.remove({
180
180
  }
181
181
  ```
182
182
 
183
+ #### Proxy mode and uploads
184
+
185
+ When `initializeApi({ proxyMode: true })` is active (e.g., SDK runs inside an iframe and the parent performs API calls), the SDK serializes `FormData` for upload into a proxy-safe shape and posts a message to the parent window. The parent proxy handler should detect this payload and reconstruct a native `FormData` before performing the actual HTTP request.
186
+
187
+ - SDK proxy message body shape for uploads:
188
+ - `{ _isFormData: true, entries: Array<[name: string, value: string | File]> }`
189
+ - Each entry’s value is either a string or a `File` object (structured-cloneable).
190
+ - Direct XHR uploads are only used when NOT in proxy mode. In proxy mode, the SDK uses the proxy channel and `postMessage`.
191
+
192
+ Progress support in proxy mode:
193
+
194
+ - If you pass `onProgress`, the SDK uses an enhanced upload protocol with chunked messages and progress events.
195
+ - Unified envelope protocol (single message shape):
196
+ - Iframe → Parent
197
+ - `{ _smartlinksProxyUpload: true, phase: 'start', id, path, method: 'POST', headers, fields, fileInfo }`
198
+ - `{ _smartlinksProxyUpload: true, phase: 'chunk', id, seq, chunk: ArrayBuffer }`
199
+ - `{ _smartlinksProxyUpload: true, phase: 'end', id }`
200
+ - Parent → Iframe
201
+ - `{ _smartlinksProxyUpload: true, phase: 'ack', id, seq }` (reply via `event.source.postMessage`)
202
+ - `{ _smartlinksProxyUpload: true, phase: 'progress', id, percent }` (reply via `event.source.postMessage`)
203
+ - `{ _smartlinksProxyUpload: true, phase: 'done', id, ok, data? | error? }` (reply via `event.source.postMessage`)
204
+
205
+ Example parent handler (buffered, simple):
206
+
207
+ ```html
208
+ <script>
209
+ const uploads = new Map();
210
+ window.addEventListener('message', async (e) => {
211
+ const m = e.data;
212
+ if (!m || m._smartlinksProxyUpload !== true) return;
213
+ const target = e.source; // reply to the sender iframe
214
+ const origin = e.origin; // consider validating and passing a strict origin
215
+ switch (m.phase) {
216
+ case 'start': {
217
+ uploads.set(m.id, { chunks: [], fields: m.fields, fileInfo: m.fileInfo, path: m.path, headers: m.headers });
218
+ break;
219
+ }
220
+ case 'chunk': {
221
+ const u = uploads.get(m.id);
222
+ if (!u) break;
223
+ u.chunks.push(new Uint8Array(m.chunk));
224
+ target && target.postMessage({ _smartlinksProxyUpload: true, phase: 'ack', id: m.id, seq: m.seq }, origin);
225
+ break;
226
+ }
227
+ case 'end': {
228
+ const u = uploads.get(m.id);
229
+ if (!u) break;
230
+ const blob = new Blob(u.chunks, { type: u.fileInfo.type || 'application/octet-stream' });
231
+ const fd = new FormData();
232
+ for (const [k, v] of u.fields) fd.append(k, v);
233
+ fd.append(u.fileInfo.key || 'file', blob, u.fileInfo.name || 'upload.bin');
234
+
235
+ const xhr = new XMLHttpRequest();
236
+ xhr.open('POST', (window.SMARTLINKS_API_BASEURL || '') + u.path);
237
+ for (const [k, v] of Object.entries(u.headers || {})) xhr.setRequestHeader(k, v);
238
+ xhr.upload.onprogress = (ev) => {
239
+ if (ev.lengthComputable) {
240
+ const pct = Math.round((ev.loaded / ev.total) * 100);
241
+ target && target.postMessage({ _smartlinksProxyUpload: true, phase: 'progress', id: m.id, percent: pct }, origin);
242
+ }
243
+ };
244
+ xhr.onload = () => {
245
+ const ok = xhr.status >= 200 && xhr.status < 300;
246
+ try {
247
+ const data = JSON.parse(xhr.responseText);
248
+ target && target.postMessage({ _smartlinksProxyUpload: true, phase: 'done', id: m.id, ok, data, error: ok ? undefined : data?.message }, origin);
249
+ } catch (err) {
250
+ target && target.postMessage({ _smartlinksProxyUpload: true, phase: 'done', id: m.id, ok: false, error: 'Invalid server response' }, origin);
251
+ }
252
+ };
253
+ xhr.onerror = () => target && target.postMessage({ _smartlinksProxyUpload: true, phase: 'done', id: m.id, ok: false, error: 'Network error' }, origin);
254
+ xhr.send(fd);
255
+ uploads.delete(m.id);
256
+ break;
257
+ }
258
+ }
259
+ });
260
+ </script>
261
+ ```
262
+
263
+ If you maintain the parent proxy, ensure its handler for `_smartlinksProxyRequest`:
264
+ - Detects `body._isFormData === true` and rebuilds `const fd = new FormData(); for (const [k,v] of body.entries) fd.append(k, v);`
265
+ - Issues the HTTP request with that `FormData` and returns the parsed JSON response back to the iframe.
266
+
183
267
  ### AI helpers
184
268
 
185
269
  ```ts
package/dist/api/asset.js CHANGED
@@ -1,4 +1,4 @@
1
- import { request, post, del, getApiHeaders } from "../http";
1
+ import { request, post, del, getApiHeaders, isProxyEnabled, proxyUploadFormData } from "../http";
2
2
  export var asset;
3
3
  (function (asset) {
4
4
  /**
@@ -41,8 +41,8 @@ export var asset;
41
41
  formData.append("name", options.name);
42
42
  if (options.metadata)
43
43
  formData.append("metadata", JSON.stringify(options.metadata));
44
- // If progress callback provided, use XHR for progress events (browser-only)
45
- if (options.onProgress && typeof window !== "undefined") {
44
+ // If progress callback provided and NOT in proxy mode, use XHR for progress events (browser-only)
45
+ if (options.onProgress && typeof window !== "undefined" && !isProxyEnabled()) {
46
46
  const url = (typeof window !== "undefined" && window.SMARTLINKS_API_BASEURL)
47
47
  ? window.SMARTLINKS_API_BASEURL + path
48
48
  : path;
@@ -85,7 +85,17 @@ export var asset;
85
85
  xhr.send(formData);
86
86
  });
87
87
  }
88
- // Otherwise use fetch helper
88
+ // If in proxy mode and progress requested, use enhanced proxy upload to support progress
89
+ if (options.onProgress && isProxyEnabled()) {
90
+ try {
91
+ return await proxyUploadFormData(path, formData, options.onProgress);
92
+ }
93
+ catch (e) {
94
+ const msg = (e === null || e === void 0 ? void 0 : e.message) || 'Upload failed';
95
+ throw new AssetUploadError(msg, 'UNKNOWN');
96
+ }
97
+ }
98
+ // Otherwise use fetch helper (in proxy mode this becomes a postMessage with serialized FormData)
89
99
  try {
90
100
  return await post(path, formData);
91
101
  }
@@ -41,7 +41,8 @@ export type AccountInfoResponse = {
41
41
  };
42
42
  sub: string;
43
43
  uid: string;
44
- user_id: string;
44
+ userId: string;
45
+ contactId: string;
45
46
  whitelabel: {
46
47
  [key: string]: any;
47
48
  };
package/dist/http.d.ts CHANGED
@@ -5,6 +5,8 @@ type Logger = {
5
5
  error?: (...args: any[]) => void;
6
6
  log?: (...args: any[]) => void;
7
7
  } | ((...args: any[]) => void);
8
+ /** Return whether proxy mode is currently enabled. */
9
+ export declare function isProxyEnabled(): boolean;
8
10
  export declare function initializeApi(options: {
9
11
  baseURL: string;
10
12
  apiKey?: string;
@@ -23,6 +25,11 @@ export declare function setExtraHeaders(headers: Record<string, string>): void;
23
25
  * Allows setting the bearerToken at runtime (e.g. after login/logout).
24
26
  */
25
27
  export declare function setBearerToken(token: string | undefined): void;
28
+ /**
29
+ * Upload a FormData payload via proxy with progress events using chunked postMessage.
30
+ * Parent is expected to implement the counterpart protocol.
31
+ */
32
+ export declare function proxyUploadFormData<T>(path: string, formData: FormData, onProgress?: (percent: number) => void): Promise<T>;
26
33
  /**
27
34
  * Internal helper that performs a GET request to \`\${baseURL}\${path}\`,
28
35
  * injecting headers for apiKey or bearerToken if present.
package/dist/http.js CHANGED
@@ -19,6 +19,10 @@ function logDebug(...args) {
19
19
  if (logger.log)
20
20
  return logger.log(...args);
21
21
  }
22
+ /** Return whether proxy mode is currently enabled. */
23
+ export function isProxyEnabled() {
24
+ return proxyMode;
25
+ }
22
26
  function maskSensitive(value) {
23
27
  if (!value)
24
28
  return value;
@@ -138,15 +142,26 @@ function ensureProxyListener() {
138
142
  window._smartlinksProxyListener = true;
139
143
  }
140
144
  // Proxy request implementation
145
+ function serializeFormDataForProxy(fd) {
146
+ const entries = [];
147
+ // FormData#forEach iterates values which can be string | Blob (File extends Blob)
148
+ fd.forEach((value, key) => {
149
+ entries.push([key, value]);
150
+ });
151
+ return { _isFormData: true, entries };
152
+ }
141
153
  async function proxyRequest(method, path, body, headers, options) {
142
154
  ensureProxyListener();
155
+ const payloadBody = (typeof FormData !== 'undefined' && body instanceof FormData)
156
+ ? serializeFormDataForProxy(body)
157
+ : body;
143
158
  const id = generateProxyId();
144
159
  const msg = {
145
160
  _smartlinksProxyRequest: true,
146
161
  id,
147
162
  method,
148
163
  path,
149
- body,
164
+ body: payloadBody,
150
165
  headers,
151
166
  options,
152
167
  };
@@ -157,6 +172,140 @@ async function proxyRequest(method, path, body, headers, options) {
157
172
  // Optionally: add a timeout here to reject if no response
158
173
  });
159
174
  }
175
+ /**
176
+ * Upload a FormData payload via proxy with progress events using chunked postMessage.
177
+ * Parent is expected to implement the counterpart protocol.
178
+ */
179
+ export async function proxyUploadFormData(path, formData, onProgress) {
180
+ var _a;
181
+ if (!proxyMode) {
182
+ throw new Error('proxyUploadFormData called when proxyMode is disabled');
183
+ }
184
+ ensureProxyListener();
185
+ // Extract file and plain fields
186
+ let fileKey = null;
187
+ let file = null;
188
+ const fields = [];
189
+ formData.forEach((value, key) => {
190
+ const isFile = typeof value !== 'string';
191
+ if (!file && isFile) {
192
+ fileKey = key;
193
+ file = value; // File | Blob in browser
194
+ }
195
+ else {
196
+ fields.push([key, String(value)]);
197
+ }
198
+ });
199
+ if (!file || !fileKey) {
200
+ throw new Error('proxyUploadFormData requires a File/Blob in FormData');
201
+ }
202
+ const id = generateProxyId();
203
+ const headers = getApiHeaders();
204
+ let resolveDone;
205
+ let rejectDone;
206
+ const done = new Promise((resolve, reject) => { resolveDone = resolve; rejectDone = reject; });
207
+ function handleMessage(event) {
208
+ const msg = event.data;
209
+ if (!msg || msg.id !== id)
210
+ return;
211
+ // Unified envelope support
212
+ if (msg._smartlinksProxyUpload === true) {
213
+ if (msg.phase === 'progress' && typeof msg.percent === 'number') {
214
+ try {
215
+ onProgress && onProgress(Math.max(0, Math.min(100, Math.round(msg.percent))));
216
+ }
217
+ catch (_a) { }
218
+ return;
219
+ }
220
+ if (msg.phase === 'done') {
221
+ window.removeEventListener('message', handleMessage);
222
+ if (msg.ok) {
223
+ resolveDone(msg.data);
224
+ }
225
+ else {
226
+ rejectDone(new Error(msg.error || 'Upload failed'));
227
+ }
228
+ return;
229
+ }
230
+ return;
231
+ }
232
+ // Backward-compat flags (older docs)
233
+ if (msg._smartlinksProxyUploadProgress === true && typeof msg.percent === 'number') {
234
+ try {
235
+ onProgress && onProgress(Math.max(0, Math.min(100, Math.round(msg.percent))));
236
+ }
237
+ catch (_b) { }
238
+ return;
239
+ }
240
+ if (msg._smartlinksProxyUploadDone === true) {
241
+ window.removeEventListener('message', handleMessage);
242
+ if (msg.ok) {
243
+ resolveDone(msg.data);
244
+ }
245
+ else {
246
+ rejectDone(new Error(msg.error || 'Upload failed'));
247
+ }
248
+ return;
249
+ }
250
+ }
251
+ window.addEventListener('message', handleMessage);
252
+ // Start
253
+ const startMsg = {
254
+ _smartlinksProxyUpload: true,
255
+ phase: 'start',
256
+ id,
257
+ path,
258
+ method: 'POST',
259
+ headers,
260
+ fields,
261
+ fileInfo: { name: file.name || fileKey, size: file.size || undefined, type: file.type || undefined, key: fileKey },
262
+ };
263
+ window.parent.postMessage(startMsg, '*');
264
+ // Send chunks with simple ack pacing
265
+ const CHUNK_SIZE = 256 * 1024; // 256KB
266
+ const totalSize = (_a = file.size) !== null && _a !== void 0 ? _a : 0;
267
+ let offset = 0;
268
+ let seq = 0;
269
+ while (totalSize && offset < totalSize) {
270
+ const end = Math.min(offset + CHUNK_SIZE, totalSize);
271
+ const blob = file.slice(offset, end);
272
+ // eslint-disable-next-line no-await-in-loop
273
+ const buf = await blob.arrayBuffer();
274
+ const chunkMsg = {
275
+ _smartlinksProxyUpload: true,
276
+ phase: 'chunk',
277
+ id,
278
+ seq,
279
+ chunk: buf,
280
+ };
281
+ window.parent.postMessage(chunkMsg, '*', [buf]);
282
+ // Wait for ack for this seq
283
+ // eslint-disable-next-line no-await-in-loop
284
+ await new Promise((res) => {
285
+ function onAck(ev) {
286
+ const m = ev.data;
287
+ // Unified envelope ack
288
+ if (m && m._smartlinksProxyUpload === true && m.id === id && m.phase === 'ack' && m.seq === seq) {
289
+ window.removeEventListener('message', onAck);
290
+ res();
291
+ return;
292
+ }
293
+ // Backward-compat ack
294
+ if (m && m._smartlinksProxyUploadAck === true && m.id === id && m.seq === seq) {
295
+ window.removeEventListener('message', onAck);
296
+ res();
297
+ }
298
+ }
299
+ window.addEventListener('message', onAck);
300
+ });
301
+ offset = end;
302
+ seq += 1;
303
+ }
304
+ // End
305
+ const endMsg = { _smartlinksProxyUpload: true, phase: 'end', id };
306
+ window.parent.postMessage(endMsg, '*');
307
+ return done;
308
+ }
160
309
  /**
161
310
  * Internal helper that performs a GET request to \`\${baseURL}\${path}\`,
162
311
  * injecting headers for apiKey or bearerToken if present.
@@ -16,8 +16,8 @@ export interface Proof {
16
16
  userId: string;
17
17
  /** Is this proof available to be claimed */
18
18
  claimable?: boolean;
19
- /** Is this proof transient */
20
- transient?: boolean;
19
+ /** Is this proof virtual */
20
+ virtual?: boolean;
21
21
  /** Arbitrary key-value pairs for proof values */
22
22
  values: Record<string, any>;
23
23
  }
@@ -25,7 +25,7 @@ export type ProofResponse = Proof;
25
25
  export interface ProofCreateRequest {
26
26
  values: Record<string, any>;
27
27
  claimable?: boolean;
28
- transient?: boolean;
28
+ virtual?: boolean;
29
29
  }
30
30
  export type ProofUpdateRequest = Partial<ProofCreateRequest>;
31
31
  export type ProofClaimRequest = Record<string, any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",