@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 +13 -4
- package/README.md +84 -0
- package/dist/api/asset.js +14 -4
- package/dist/api/auth.d.ts +2 -1
- package/dist/http.d.ts +7 -0
- package/dist/http.js +150 -1
- package/dist/types/proof.d.ts +3 -3
- package/package.json +1 -1
package/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.1.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
}
|
package/dist/api/auth.d.ts
CHANGED
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.
|
package/dist/types/proof.d.ts
CHANGED
|
@@ -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
|
|
20
|
-
|
|
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
|
-
|
|
28
|
+
virtual?: boolean;
|
|
29
29
|
}
|
|
30
30
|
export type ProofUpdateRequest = Partial<ProofCreateRequest>;
|
|
31
31
|
export type ProofClaimRequest = Record<string, any>;
|