@proveanything/smartlinks 1.1.23 → 1.1.25
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 +106 -5
- package/README.md +160 -10
- package/dist/api/asset.d.ts +28 -1
- package/dist/api/asset.js +173 -46
- package/dist/http.d.ts +7 -0
- package/dist/http.js +150 -1
- package/dist/types/asset.d.ts +136 -2
- package/dist/types/template.d.ts +21 -1
- 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.25 | Generated: 2026-01-13T20:40:07.743Z
|
|
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
|
|
|
@@ -125,15 +133,84 @@ interface AppConfigurationResponse {
|
|
|
125
133
|
|
|
126
134
|
### asset
|
|
127
135
|
|
|
128
|
-
**
|
|
136
|
+
**Asset** (interface)
|
|
129
137
|
```typescript
|
|
130
|
-
interface
|
|
138
|
+
interface Asset {
|
|
131
139
|
id: string
|
|
132
|
-
name: string
|
|
133
140
|
url: string
|
|
141
|
+
name: string
|
|
142
|
+
mimeType?: string
|
|
143
|
+
size?: number
|
|
144
|
+
createdAt?: string
|
|
145
|
+
metadata?: Record<string, any>
|
|
146
|
+
assetType?: string
|
|
147
|
+
type?: string
|
|
148
|
+
collectionId?: string
|
|
149
|
+
hash?: string
|
|
150
|
+
thumbnails?: {
|
|
151
|
+
x100?: string
|
|
152
|
+
x200?: string
|
|
153
|
+
x512?: string
|
|
154
|
+
[key: string]: string | undefined
|
|
155
|
+
}
|
|
156
|
+
site?: string
|
|
157
|
+
cleanName?: string
|
|
134
158
|
}
|
|
135
159
|
```
|
|
136
160
|
|
|
161
|
+
**UploadAssetOptions** (interface)
|
|
162
|
+
```typescript
|
|
163
|
+
interface UploadAssetOptions {
|
|
164
|
+
file: File
|
|
165
|
+
scope:
|
|
166
|
+
| { type: 'collection'; collectionId: string }
|
|
167
|
+
| { type: 'product'; collectionId: string; productId: string }
|
|
168
|
+
| { type: 'proof'; collectionId: string; productId: string; proofId: string }
|
|
169
|
+
name?: string
|
|
170
|
+
metadata?: Record<string, any>
|
|
171
|
+
onProgress?: (percent: number) => void
|
|
172
|
+
appId?: string
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**ListAssetsOptions** (interface)
|
|
177
|
+
```typescript
|
|
178
|
+
interface ListAssetsOptions {
|
|
179
|
+
scope:
|
|
180
|
+
| { type: 'collection'; collectionId: string }
|
|
181
|
+
| { type: 'product'; collectionId: string; productId: string }
|
|
182
|
+
| { type: 'proof'; collectionId: string; productId: string; proofId: string }
|
|
183
|
+
appId?: string
|
|
184
|
+
mimeTypePrefix?: string
|
|
185
|
+
limit?: number
|
|
186
|
+
offset?: number
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**GetAssetOptions** (interface)
|
|
191
|
+
```typescript
|
|
192
|
+
interface GetAssetOptions {
|
|
193
|
+
assetId: string
|
|
194
|
+
scope:
|
|
195
|
+
| { type: 'collection'; collectionId: string }
|
|
196
|
+
| { type: 'product'; collectionId: string; productId: string }
|
|
197
|
+
| { type: 'proof'; collectionId: string; productId: string; proofId: string }
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**RemoveAssetOptions** (interface)
|
|
202
|
+
```typescript
|
|
203
|
+
interface RemoveAssetOptions {
|
|
204
|
+
assetId: string
|
|
205
|
+
scope:
|
|
206
|
+
| { type: 'collection'; collectionId: string }
|
|
207
|
+
| { type: 'product'; collectionId: string; productId: string }
|
|
208
|
+
| { type: 'proof'; collectionId: string; productId: string; proofId: string }
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**AssetResponse** = `Asset`
|
|
213
|
+
|
|
137
214
|
### attestation
|
|
138
215
|
|
|
139
216
|
**AttestationResponse** (interface)
|
|
@@ -1552,12 +1629,18 @@ interface TemplateBase {
|
|
|
1552
1629
|
collectionId: string
|
|
1553
1630
|
name: string
|
|
1554
1631
|
description?: string
|
|
1555
|
-
type:
|
|
1632
|
+
type: 'pdf' | 'email' | 'multichannel' | 'label'
|
|
1556
1633
|
resizeMode?: string
|
|
1557
1634
|
pdf?: {
|
|
1558
1635
|
base: { url: string }
|
|
1559
1636
|
orientation: 'portrait' | 'landscape'
|
|
1560
1637
|
}
|
|
1638
|
+
channels?: {
|
|
1639
|
+
email?: {subject: string; body: string},
|
|
1640
|
+
sms?: { body: string },
|
|
1641
|
+
push: { title: string; body: string, url?: string, iconUrl?: string },
|
|
1642
|
+
wallet?: { header: string; body: string; imageUri?: string }
|
|
1643
|
+
}
|
|
1561
1644
|
subject?: string
|
|
1562
1645
|
body?: string
|
|
1563
1646
|
css?: string
|
|
@@ -1794,27 +1877,36 @@ Post a chat message to the AI (admin or public)
|
|
|
1794
1877
|
|
|
1795
1878
|
### asset
|
|
1796
1879
|
|
|
1880
|
+
**upload**(options: UploadAssetOptions) → `Promise<Asset>`
|
|
1881
|
+
Upload an asset file
|
|
1882
|
+
|
|
1797
1883
|
**getForCollection**(collectionId: string,
|
|
1798
1884
|
assetId: string) → `Promise<AssetResponse>`
|
|
1885
|
+
Upload an asset file
|
|
1799
1886
|
|
|
1800
1887
|
**listForCollection**(collectionId: string) → `Promise<AssetResponse[]>`
|
|
1888
|
+
Upload an asset file
|
|
1801
1889
|
|
|
1802
1890
|
**getForProduct**(collectionId: string,
|
|
1803
1891
|
productId: string,
|
|
1804
1892
|
assetId: string) → `Promise<AssetResponse>`
|
|
1893
|
+
Upload an asset file
|
|
1805
1894
|
|
|
1806
1895
|
**listForProduct**(collectionId: string,
|
|
1807
1896
|
productId: string) → `Promise<AssetResponse[]>`
|
|
1897
|
+
Upload an asset file
|
|
1808
1898
|
|
|
1809
1899
|
**getForProof**(collectionId: string,
|
|
1810
1900
|
productId: string,
|
|
1811
1901
|
proofId: string,
|
|
1812
1902
|
assetId: string) → `Promise<AssetResponse>`
|
|
1903
|
+
Upload an asset file
|
|
1813
1904
|
|
|
1814
1905
|
**listForProof**(collectionId: string,
|
|
1815
1906
|
productId: string,
|
|
1816
1907
|
proofId: string,
|
|
1817
1908
|
appId?: string) → `Promise<AssetResponse[]>`
|
|
1909
|
+
Upload an asset file
|
|
1818
1910
|
|
|
1819
1911
|
**uploadAsset**(collectionId: string,
|
|
1820
1912
|
productId: string,
|
|
@@ -1824,6 +1916,15 @@ Post a chat message to the AI (admin or public)
|
|
|
1824
1916
|
onProgress?: (percent: number) → `void`
|
|
1825
1917
|
Uploads an asset file to a proof, with optional extraData as JSON. Supports progress reporting via onProgress callback (browser only).
|
|
1826
1918
|
|
|
1919
|
+
**list**(options: ListAssetsOptions) → `Promise<Asset[]>`
|
|
1920
|
+
List assets for a given scope
|
|
1921
|
+
|
|
1922
|
+
**get**(options: GetAssetOptions) → `Promise<Asset>`
|
|
1923
|
+
Get an asset by id within a scope (public)
|
|
1924
|
+
|
|
1925
|
+
**remove**(options: RemoveAssetOptions) → `Promise<void>`
|
|
1926
|
+
Remove an asset by id within a scope (admin)
|
|
1927
|
+
|
|
1827
1928
|
### async
|
|
1828
1929
|
|
|
1829
1930
|
**enqueueAsyncJob**(collectionId: string,
|
package/README.md
CHANGED
|
@@ -96,24 +96,174 @@ await product.update('collectionId', 'productId', { description: 'Updated' })
|
|
|
96
96
|
await product.remove('collectionId', 'productId')
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
### Assets
|
|
99
|
+
### Assets
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Upload, list, get, and remove assets within a scope (collection/product/proof).
|
|
102
|
+
|
|
103
|
+
#### Upload (new)
|
|
102
104
|
|
|
103
105
|
```ts
|
|
104
106
|
import { asset } from '@proveanything/smartlinks'
|
|
105
107
|
|
|
106
|
-
const
|
|
107
|
-
'collectionId',
|
|
108
|
-
'productId',
|
|
109
|
-
'proofId',
|
|
108
|
+
const uploaded = await asset.upload({
|
|
110
109
|
file, // File from an <input type="file">
|
|
111
|
-
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
console.log(
|
|
110
|
+
scope: { type: 'proof', collectionId, productId, proofId },
|
|
111
|
+
name: 'hero.png',
|
|
112
|
+
metadata: { description: 'Uploaded via SDK' },
|
|
113
|
+
onProgress: (p) => console.log(`Upload: ${p}%`),
|
|
114
|
+
// appId: 'microapp-123' // optional
|
|
115
|
+
})
|
|
116
|
+
console.log('Uploaded asset:', uploaded)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Deprecated upload helper (wraps to the new `upload` internally):
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
// @deprecated Use asset.upload(options)
|
|
123
|
+
const legacy = await asset.uploadAsset(collectionId, productId, proofId, file)
|
|
115
124
|
```
|
|
116
125
|
|
|
126
|
+
#### List
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// Collection assets, first 20 images
|
|
130
|
+
const list1 = await asset.list({
|
|
131
|
+
scope: { type: 'collection', collectionId },
|
|
132
|
+
mimeTypePrefix: 'image/',
|
|
133
|
+
limit: 20,
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
// Product assets, filter by appId
|
|
137
|
+
const list2 = await asset.list({
|
|
138
|
+
scope: { type: 'product', collectionId, productId },
|
|
139
|
+
appId: 'microapp-123',
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Get (scoped)
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const a = await asset.get({
|
|
147
|
+
assetId,
|
|
148
|
+
scope: { type: 'proof', collectionId, productId, proofId },
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Remove (scoped, admin)
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
await asset.remove({
|
|
156
|
+
assetId,
|
|
157
|
+
scope: { type: 'product', collectionId, productId },
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Asset response example
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"name": "Screenshot 2025-09-15 at 15.21.14",
|
|
166
|
+
"assetType": "Image",
|
|
167
|
+
"type": "png",
|
|
168
|
+
"collectionId": "ChaseAtlantic",
|
|
169
|
+
"url": "https://cdn.smartlinks.app/sites%2FChaseAtlantic%2Fimages%2F2025%2F9%2FScreenshot%202025-09-15%20at%2015%2C21%2C14-1757946214537.png",
|
|
170
|
+
"createdAt": "2005-10-10T23:15:03",
|
|
171
|
+
"hash": "fb98140a6b41ee69b824f29cc8b6795444246f871e4ab2379528b34a4d16284e",
|
|
172
|
+
"thumbnails": {
|
|
173
|
+
"x100": "https://cdn.smartlinks.app/..._100x100.png",
|
|
174
|
+
"x200": "https://cdn.smartlinks.app/..._200x200.png",
|
|
175
|
+
"x512": "https://cdn.smartlinks.app/..._512x512.png"
|
|
176
|
+
},
|
|
177
|
+
"id": "7k1cGErrlmQ94J8yDlVj",
|
|
178
|
+
"site": "ChaseAtlantic",
|
|
179
|
+
"cleanName": "Screenshot 2025-09-15 at 15.21"
|
|
180
|
+
}
|
|
181
|
+
```
|
|
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
|
+
|
|
117
267
|
### AI helpers
|
|
118
268
|
|
|
119
269
|
```ts
|
package/dist/api/asset.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { AssetResponse } from "../types/asset";
|
|
1
|
+
import { Asset, AssetResponse, UploadAssetOptions, ListAssetsOptions, GetAssetOptions, RemoveAssetOptions } from "../types/asset";
|
|
2
2
|
export declare namespace asset {
|
|
3
|
+
/**
|
|
4
|
+
* Error type for asset uploads
|
|
5
|
+
*/
|
|
6
|
+
class AssetUploadError extends Error {
|
|
7
|
+
readonly code: 'FILE_TOO_LARGE' | 'INVALID_TYPE' | 'NETWORK_ERROR' | 'UNAUTHORIZED' | 'QUOTA_EXCEEDED' | 'UNKNOWN';
|
|
8
|
+
readonly details?: Record<string, any> | undefined;
|
|
9
|
+
constructor(message: string, code: 'FILE_TOO_LARGE' | 'INVALID_TYPE' | 'NETWORK_ERROR' | 'UNAUTHORIZED' | 'QUOTA_EXCEEDED' | 'UNKNOWN', details?: Record<string, any> | undefined);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Upload an asset file
|
|
13
|
+
* @returns The uploaded asset with its public URL
|
|
14
|
+
* @throws AssetUploadError if upload fails
|
|
15
|
+
*/
|
|
16
|
+
function upload(options: UploadAssetOptions): Promise<Asset>;
|
|
3
17
|
function getForCollection(collectionId: string, assetId: string): Promise<AssetResponse>;
|
|
4
18
|
function listForCollection(collectionId: string): Promise<AssetResponse[]>;
|
|
5
19
|
function getForProduct(collectionId: string, productId: string, assetId: string): Promise<AssetResponse>;
|
|
@@ -8,6 +22,7 @@ export declare namespace asset {
|
|
|
8
22
|
function listForProof(collectionId: string, productId: string, proofId: string, appId?: string): Promise<AssetResponse[]>;
|
|
9
23
|
/**
|
|
10
24
|
* Uploads an asset file to a proof, with optional extraData as JSON.
|
|
25
|
+
* @deprecated Use `asset.upload(options)` instead.
|
|
11
26
|
* Supports progress reporting via onProgress callback (browser only).
|
|
12
27
|
* @param collectionId - The collection ID
|
|
13
28
|
* @param productId - The product ID
|
|
@@ -18,4 +33,16 @@ export declare namespace asset {
|
|
|
18
33
|
* @returns Promise resolving to an AssetResponse object
|
|
19
34
|
*/
|
|
20
35
|
function uploadAsset(collectionId: string, productId: string, proofId: string, file: File, extraData?: Record<string, any>, onProgress?: (percent: number) => void): Promise<AssetResponse>;
|
|
36
|
+
/**
|
|
37
|
+
* List assets for a given scope
|
|
38
|
+
*/
|
|
39
|
+
function list(options: ListAssetsOptions): Promise<Asset[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get an asset by id within a scope (public)
|
|
42
|
+
*/
|
|
43
|
+
function get(options: GetAssetOptions): Promise<Asset>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove an asset by id within a scope (admin)
|
|
46
|
+
*/
|
|
47
|
+
function remove(options: RemoveAssetOptions): Promise<void>;
|
|
21
48
|
}
|
package/dist/api/asset.js
CHANGED
|
@@ -1,6 +1,124 @@
|
|
|
1
|
-
import { request, getApiHeaders } from "../http";
|
|
1
|
+
import { request, post, del, getApiHeaders, isProxyEnabled, proxyUploadFormData } from "../http";
|
|
2
2
|
export var asset;
|
|
3
3
|
(function (asset) {
|
|
4
|
+
/**
|
|
5
|
+
* Error type for asset uploads
|
|
6
|
+
*/
|
|
7
|
+
class AssetUploadError extends Error {
|
|
8
|
+
constructor(message, code, details) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
this.name = 'AssetUploadError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
asset.AssetUploadError = AssetUploadError;
|
|
16
|
+
function buildScopeBase(scope) {
|
|
17
|
+
if (scope.type === 'collection') {
|
|
18
|
+
return `/public/collection/${encodeURIComponent(scope.collectionId)}`;
|
|
19
|
+
}
|
|
20
|
+
if (scope.type === 'product') {
|
|
21
|
+
return `/public/collection/${encodeURIComponent(scope.collectionId)}/product/${encodeURIComponent(scope.productId)}`;
|
|
22
|
+
}
|
|
23
|
+
// proof
|
|
24
|
+
return `/public/collection/${encodeURIComponent(scope.collectionId)}/product/${encodeURIComponent(scope.productId)}/proof/${encodeURIComponent(scope.proofId)}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Upload an asset file
|
|
28
|
+
* @returns The uploaded asset with its public URL
|
|
29
|
+
* @throws AssetUploadError if upload fails
|
|
30
|
+
*/
|
|
31
|
+
async function upload(options) {
|
|
32
|
+
const base = buildScopeBase(options.scope);
|
|
33
|
+
let path = `${base}/asset`;
|
|
34
|
+
if (options.appId) {
|
|
35
|
+
const qp = new URLSearchParams({ appId: options.appId });
|
|
36
|
+
path += `?${qp.toString()}`;
|
|
37
|
+
}
|
|
38
|
+
const formData = new FormData();
|
|
39
|
+
formData.append("file", options.file);
|
|
40
|
+
if (options.name)
|
|
41
|
+
formData.append("name", options.name);
|
|
42
|
+
if (options.metadata)
|
|
43
|
+
formData.append("metadata", JSON.stringify(options.metadata));
|
|
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
|
+
const url = (typeof window !== "undefined" && window.SMARTLINKS_API_BASEURL)
|
|
47
|
+
? window.SMARTLINKS_API_BASEURL + path
|
|
48
|
+
: path;
|
|
49
|
+
const headers = getApiHeaders ? getApiHeaders() : {};
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const xhr = new XMLHttpRequest();
|
|
52
|
+
xhr.open("POST", url);
|
|
53
|
+
for (const [key, value] of Object.entries(headers))
|
|
54
|
+
xhr.setRequestHeader(key, value);
|
|
55
|
+
xhr.upload.onprogress = (event) => {
|
|
56
|
+
if (options.onProgress && event.lengthComputable) {
|
|
57
|
+
const percent = Math.round((event.loaded / event.total) * 100);
|
|
58
|
+
options.onProgress(percent);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
xhr.onload = () => {
|
|
62
|
+
const status = xhr.status;
|
|
63
|
+
const text = xhr.responseText;
|
|
64
|
+
if (status >= 200 && status < 300) {
|
|
65
|
+
try {
|
|
66
|
+
resolve(JSON.parse(text));
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
reject(new AssetUploadError("Failed to parse server response", 'UNKNOWN'));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
try {
|
|
74
|
+
const errBody = JSON.parse(text);
|
|
75
|
+
const code = mapStatusToUploadErrorCode(status, errBody === null || errBody === void 0 ? void 0 : errBody.code);
|
|
76
|
+
reject(new AssetUploadError((errBody === null || errBody === void 0 ? void 0 : errBody.message) || `Upload failed (${status})`, code, errBody));
|
|
77
|
+
}
|
|
78
|
+
catch (_a) {
|
|
79
|
+
const code = mapStatusToUploadErrorCode(status);
|
|
80
|
+
reject(new AssetUploadError(`Asset upload failed with status ${status}`, code));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
xhr.onerror = () => reject(new AssetUploadError("Network error during asset upload", 'NETWORK_ERROR'));
|
|
85
|
+
xhr.send(formData);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
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)
|
|
99
|
+
try {
|
|
100
|
+
return await post(path, formData);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
// Map generic Error to AssetUploadError
|
|
104
|
+
const msg = (e === null || e === void 0 ? void 0 : e.message) || 'Upload failed';
|
|
105
|
+
throw new AssetUploadError(msg, 'UNKNOWN');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
asset.upload = upload;
|
|
109
|
+
function mapStatusToUploadErrorCode(status, serverCode) {
|
|
110
|
+
if (status === 401 || status === 403)
|
|
111
|
+
return 'UNAUTHORIZED';
|
|
112
|
+
if (status === 413)
|
|
113
|
+
return 'FILE_TOO_LARGE';
|
|
114
|
+
if (status === 415)
|
|
115
|
+
return 'INVALID_TYPE';
|
|
116
|
+
if (status === 429)
|
|
117
|
+
return 'QUOTA_EXCEEDED';
|
|
118
|
+
if (status === 0)
|
|
119
|
+
return 'NETWORK_ERROR';
|
|
120
|
+
return 'UNKNOWN';
|
|
121
|
+
}
|
|
4
122
|
// Collection-level
|
|
5
123
|
async function getForCollection(collectionId, assetId) {
|
|
6
124
|
const path = `/public/collection/${encodeURIComponent(collectionId)}/asset/${encodeURIComponent(assetId)}`;
|
|
@@ -39,6 +157,7 @@ export var asset;
|
|
|
39
157
|
asset.listForProof = listForProof;
|
|
40
158
|
/**
|
|
41
159
|
* Uploads an asset file to a proof, with optional extraData as JSON.
|
|
160
|
+
* @deprecated Use `asset.upload(options)` instead.
|
|
42
161
|
* Supports progress reporting via onProgress callback (browser only).
|
|
43
162
|
* @param collectionId - The collection ID
|
|
44
163
|
* @param productId - The product ID
|
|
@@ -49,52 +168,60 @@ export var asset;
|
|
|
49
168
|
* @returns Promise resolving to an AssetResponse object
|
|
50
169
|
*/
|
|
51
170
|
async function uploadAsset(collectionId, productId, proofId, file, extraData, onProgress) {
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
formData.append("extraData", JSON.stringify(extraData));
|
|
60
|
-
}
|
|
61
|
-
// Use getApiHeaders from http module
|
|
62
|
-
const headers = getApiHeaders ? getApiHeaders() : {};
|
|
63
|
-
return new Promise((resolve, reject) => {
|
|
64
|
-
const xhr = new XMLHttpRequest();
|
|
65
|
-
xhr.open("POST", url);
|
|
66
|
-
// Set headers for API key and bearer token if available
|
|
67
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
68
|
-
xhr.setRequestHeader(key, value);
|
|
69
|
-
}
|
|
70
|
-
xhr.upload.onprogress = (event) => {
|
|
71
|
-
if (onProgress && event.lengthComputable) {
|
|
72
|
-
const percent = Math.round((event.loaded / event.total) * 100);
|
|
73
|
-
onProgress(percent);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
xhr.onload = () => {
|
|
77
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
78
|
-
try {
|
|
79
|
-
resolve(JSON.parse(xhr.responseText));
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
reject(new Error("Failed to parse server response"));
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
try {
|
|
87
|
-
const errBody = JSON.parse(xhr.responseText);
|
|
88
|
-
reject(new Error(`Error ${errBody.code}: ${errBody.message}`));
|
|
89
|
-
}
|
|
90
|
-
catch (_a) {
|
|
91
|
-
reject(new Error(`Asset upload failed with status ${xhr.status}`));
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
xhr.onerror = () => reject(new Error("Network error during asset upload"));
|
|
96
|
-
xhr.send(formData);
|
|
171
|
+
// Route through new upload API for backward compatibility
|
|
172
|
+
const res = await upload({
|
|
173
|
+
file,
|
|
174
|
+
name: file === null || file === void 0 ? void 0 : file.name,
|
|
175
|
+
metadata: extraData,
|
|
176
|
+
onProgress,
|
|
177
|
+
scope: { type: 'proof', collectionId, productId, proofId },
|
|
97
178
|
});
|
|
179
|
+
return res;
|
|
98
180
|
}
|
|
99
181
|
asset.uploadAsset = uploadAsset;
|
|
182
|
+
/**
|
|
183
|
+
* List assets for a given scope
|
|
184
|
+
*/
|
|
185
|
+
async function list(options) {
|
|
186
|
+
const base = buildScopeBase(options.scope);
|
|
187
|
+
const params = new URLSearchParams();
|
|
188
|
+
if (options.appId)
|
|
189
|
+
params.set('appId', options.appId);
|
|
190
|
+
if (options.mimeTypePrefix)
|
|
191
|
+
params.set('mimeTypePrefix', options.mimeTypePrefix);
|
|
192
|
+
if (typeof options.limit === 'number')
|
|
193
|
+
params.set('limit', String(options.limit));
|
|
194
|
+
if (typeof options.offset === 'number')
|
|
195
|
+
params.set('offset', String(options.offset));
|
|
196
|
+
const path = `${base}/asset${params.toString() ? `?${params}` : ''}`;
|
|
197
|
+
return request(path);
|
|
198
|
+
}
|
|
199
|
+
asset.list = list;
|
|
200
|
+
/**
|
|
201
|
+
* Get an asset by id within a scope (public)
|
|
202
|
+
*/
|
|
203
|
+
async function get(options) {
|
|
204
|
+
const base = buildScopeBase(options.scope);
|
|
205
|
+
const path = `${base}/asset/${encodeURIComponent(options.assetId)}`;
|
|
206
|
+
return request(path);
|
|
207
|
+
}
|
|
208
|
+
asset.get = get;
|
|
209
|
+
/**
|
|
210
|
+
* Remove an asset by id within a scope (admin)
|
|
211
|
+
*/
|
|
212
|
+
async function remove(options) {
|
|
213
|
+
const scope = options.scope;
|
|
214
|
+
let path;
|
|
215
|
+
if (scope.type === 'collection') {
|
|
216
|
+
path = `/admin/collection/${encodeURIComponent(scope.collectionId)}/asset/${encodeURIComponent(options.assetId)}`;
|
|
217
|
+
}
|
|
218
|
+
else if (scope.type === 'product') {
|
|
219
|
+
path = `/admin/collection/${encodeURIComponent(scope.collectionId)}/product/${encodeURIComponent(scope.productId)}/asset/${encodeURIComponent(options.assetId)}`;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
path = `/admin/collection/${encodeURIComponent(scope.collectionId)}/product/${encodeURIComponent(scope.productId)}/proof/${encodeURIComponent(scope.proofId)}/asset/${encodeURIComponent(options.assetId)}`;
|
|
223
|
+
}
|
|
224
|
+
return del(path);
|
|
225
|
+
}
|
|
226
|
+
asset.remove = remove;
|
|
100
227
|
})(asset || (asset = {}));
|
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/asset.d.ts
CHANGED
|
@@ -1,8 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response from any asset upload or retrieval operation
|
|
3
|
+
*/
|
|
1
4
|
/**
|
|
2
5
|
* Represents an Asset object.
|
|
6
|
+
*
|
|
7
|
+
* Example server response shape:
|
|
8
|
+
* @example
|
|
9
|
+
* {
|
|
10
|
+
* "name": "Screenshot 2025-09-15 at 15.21.14",
|
|
11
|
+
* "assetType": "Image",
|
|
12
|
+
* "type": "png",
|
|
13
|
+
* "collectionId": "myCollection",
|
|
14
|
+
* "url": "https://cdn.smartlinks.app/s25-09-15%20at14537.png",
|
|
15
|
+
* "createdAt": "2005-10-10T23:15:03",
|
|
16
|
+
* "hash": "fb98140a6b41ee69b824f29cc8b6795444246f871e4ab2379528b34a4d16284e",
|
|
17
|
+
* "thumbnails": {
|
|
18
|
+
* "x100": "https://cdn.smartlinks.app/sit2F..._100x100.png",
|
|
19
|
+
* "x200": "https://cdn.smartlinks.app/sit2F..._200x200.png",
|
|
20
|
+
* "x512": "https://cdn.smartlinks.app/sit2F..._512x512.png"
|
|
21
|
+
* },
|
|
22
|
+
* "id": "7k1cGErrlmQ94J8yDlVj",
|
|
23
|
+
* "site": "ChaseAtlantic",
|
|
24
|
+
* "cleanName": "Screenshot 2025-09-15 at 15.21"
|
|
25
|
+
* }
|
|
3
26
|
*/
|
|
4
|
-
export interface
|
|
27
|
+
export interface Asset {
|
|
28
|
+
/** Unique identifier for the asset */
|
|
5
29
|
id: string;
|
|
6
|
-
|
|
30
|
+
/** The public URL to access the asset */
|
|
7
31
|
url: string;
|
|
32
|
+
/** Original filename */
|
|
33
|
+
name: string;
|
|
34
|
+
/** MIME type (e.g., 'image/jpeg', 'video/mp4') */
|
|
35
|
+
mimeType?: string;
|
|
36
|
+
/** File size in bytes */
|
|
37
|
+
size?: number;
|
|
38
|
+
/** When the asset was uploaded */
|
|
39
|
+
createdAt?: string;
|
|
40
|
+
/** Any custom metadata attached during upload */
|
|
41
|
+
metadata?: Record<string, any>;
|
|
42
|
+
/** Optional: broader classification like 'Image' or 'Video' */
|
|
43
|
+
assetType?: string;
|
|
44
|
+
/** Optional: file extension/type shorthand (e.g., 'png') */
|
|
45
|
+
type?: string;
|
|
46
|
+
/** Optional: owning collection identifier */
|
|
47
|
+
collectionId?: string;
|
|
48
|
+
/** Optional: content hash */
|
|
49
|
+
hash?: string;
|
|
50
|
+
/** Optional: CDN thumbnail URLs */
|
|
51
|
+
thumbnails?: {
|
|
52
|
+
x100?: string;
|
|
53
|
+
x200?: string;
|
|
54
|
+
x512?: string;
|
|
55
|
+
[key: string]: string | undefined;
|
|
56
|
+
};
|
|
57
|
+
/** Optional: site identifier alias */
|
|
58
|
+
site?: string;
|
|
59
|
+
/** Optional: prettified name */
|
|
60
|
+
cleanName?: string;
|
|
61
|
+
}
|
|
62
|
+
export type AssetResponse = Asset;
|
|
63
|
+
export interface UploadAssetOptions {
|
|
64
|
+
/** The file to upload (from input[type="file"] or drag-drop) */
|
|
65
|
+
file: File;
|
|
66
|
+
/** Where to attach the asset */
|
|
67
|
+
scope: {
|
|
68
|
+
type: 'collection';
|
|
69
|
+
collectionId: string;
|
|
70
|
+
} | {
|
|
71
|
+
type: 'product';
|
|
72
|
+
collectionId: string;
|
|
73
|
+
productId: string;
|
|
74
|
+
} | {
|
|
75
|
+
type: 'proof';
|
|
76
|
+
collectionId: string;
|
|
77
|
+
productId: string;
|
|
78
|
+
proofId: string;
|
|
79
|
+
};
|
|
80
|
+
/** Optional: Custom filename (defaults to file.name) */
|
|
81
|
+
name?: string;
|
|
82
|
+
/** Optional: Custom metadata to store with the asset */
|
|
83
|
+
metadata?: Record<string, any>;
|
|
84
|
+
/** Optional: Progress callback (0-100) */
|
|
85
|
+
onProgress?: (percent: number) => void;
|
|
86
|
+
/** Optional: App ID for scoping to a specific microapp */
|
|
87
|
+
appId?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface ListAssetsOptions {
|
|
90
|
+
scope: {
|
|
91
|
+
type: 'collection';
|
|
92
|
+
collectionId: string;
|
|
93
|
+
} | {
|
|
94
|
+
type: 'product';
|
|
95
|
+
collectionId: string;
|
|
96
|
+
productId: string;
|
|
97
|
+
} | {
|
|
98
|
+
type: 'proof';
|
|
99
|
+
collectionId: string;
|
|
100
|
+
productId: string;
|
|
101
|
+
proofId: string;
|
|
102
|
+
};
|
|
103
|
+
/** Filter by app ID */
|
|
104
|
+
appId?: string;
|
|
105
|
+
/** Filter by MIME type prefix (e.g., 'image/', 'video/') */
|
|
106
|
+
mimeTypePrefix?: string;
|
|
107
|
+
/** Pagination */
|
|
108
|
+
limit?: number;
|
|
109
|
+
offset?: number;
|
|
110
|
+
}
|
|
111
|
+
export interface GetAssetOptions {
|
|
112
|
+
assetId: string;
|
|
113
|
+
scope: {
|
|
114
|
+
type: 'collection';
|
|
115
|
+
collectionId: string;
|
|
116
|
+
} | {
|
|
117
|
+
type: 'product';
|
|
118
|
+
collectionId: string;
|
|
119
|
+
productId: string;
|
|
120
|
+
} | {
|
|
121
|
+
type: 'proof';
|
|
122
|
+
collectionId: string;
|
|
123
|
+
productId: string;
|
|
124
|
+
proofId: string;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface RemoveAssetOptions {
|
|
128
|
+
assetId: string;
|
|
129
|
+
scope: {
|
|
130
|
+
type: 'collection';
|
|
131
|
+
collectionId: string;
|
|
132
|
+
} | {
|
|
133
|
+
type: 'product';
|
|
134
|
+
collectionId: string;
|
|
135
|
+
productId: string;
|
|
136
|
+
} | {
|
|
137
|
+
type: 'proof';
|
|
138
|
+
collectionId: string;
|
|
139
|
+
productId: string;
|
|
140
|
+
proofId: string;
|
|
141
|
+
};
|
|
8
142
|
}
|
package/dist/types/template.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface TemplateBase {
|
|
|
3
3
|
collectionId: string;
|
|
4
4
|
name: string;
|
|
5
5
|
description?: string;
|
|
6
|
-
type:
|
|
6
|
+
type: 'pdf' | 'email' | 'multichannel' | 'label';
|
|
7
7
|
resizeMode?: string;
|
|
8
8
|
pdf?: {
|
|
9
9
|
base: {
|
|
@@ -11,6 +11,26 @@ export interface TemplateBase {
|
|
|
11
11
|
};
|
|
12
12
|
orientation: 'portrait' | 'landscape';
|
|
13
13
|
};
|
|
14
|
+
channels?: {
|
|
15
|
+
email?: {
|
|
16
|
+
subject: string;
|
|
17
|
+
body: string;
|
|
18
|
+
};
|
|
19
|
+
sms?: {
|
|
20
|
+
body: string;
|
|
21
|
+
};
|
|
22
|
+
push: {
|
|
23
|
+
title: string;
|
|
24
|
+
body: string;
|
|
25
|
+
url?: string;
|
|
26
|
+
iconUrl?: string;
|
|
27
|
+
};
|
|
28
|
+
wallet?: {
|
|
29
|
+
header: string;
|
|
30
|
+
body: string;
|
|
31
|
+
imageUri?: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
14
34
|
subject?: string;
|
|
15
35
|
body?: string;
|
|
16
36
|
css?: string;
|