@proveanything/smartlinks 2.1.8 → 2.1.11
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/dist/api/claimSet.d.ts +37 -1
- package/dist/api/claimSet.js +83 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/partner.d.ts +19 -0
- package/dist/api/partner.js +35 -0
- package/dist/docs/API_SUMMARY.md +275 -35
- package/dist/docs/tag-ranges.md +75 -0
- package/dist/docs/theme-tokens.md +8 -0
- package/dist/http.js +3 -0
- package/dist/idbConnection.d.ts +14 -0
- package/dist/idbConnection.js +91 -0
- package/dist/openapi.yaml +1494 -680
- package/dist/persistentCache.js +36 -95
- package/dist/theme.css +20 -0
- package/dist/translationCache.js +49 -114
- package/dist/types/claimSet.d.ts +185 -0
- package/docs/API_SUMMARY.md +275 -35
- package/docs/tag-ranges.md +75 -0
- package/docs/theme-tokens.md +8 -0
- package/openapi.yaml +1494 -680
- package/package.json +87 -87
- package/scripts/publish.mjs +22 -7
package/dist/persistentCache.js
CHANGED
|
@@ -5,10 +5,15 @@
|
|
|
5
5
|
// isIdbAvailable() and wrapped in try/catch so that failures in private-
|
|
6
6
|
// browsing, quota-exceeded situations, or server-side environments are always
|
|
7
7
|
// silent — they never propagate errors to the caller.
|
|
8
|
+
//
|
|
9
|
+
// The connection itself is managed by idbConnection.ts, which re-opens it when
|
|
10
|
+
// the browser closes it behind our back (iOS Safari does this when the tab is
|
|
11
|
+
// backgrounded) instead of leaving the cache dead for the rest of the page.
|
|
12
|
+
import { createIdbConnection } from './idbConnection.js';
|
|
8
13
|
const DB_NAME = 'smartlinks-sdk-cache';
|
|
9
14
|
const STORE_NAME = 'responses';
|
|
10
15
|
const DB_VERSION = 1;
|
|
11
|
-
|
|
16
|
+
const connection = createIdbConnection(DB_NAME, STORE_NAME, DB_VERSION);
|
|
12
17
|
/**
|
|
13
18
|
* Returns true only in environments where IndexedDB is genuinely available.
|
|
14
19
|
* False in Node.js, and in some private-browsing contexts that stub indexedDB
|
|
@@ -22,36 +27,13 @@ export function isIdbAvailable() {
|
|
|
22
27
|
return false;
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
req.onupgradeneeded = (event) => {
|
|
32
|
-
const db = event.target.result;
|
|
33
|
-
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
34
|
-
db.createObjectStore(STORE_NAME);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
req.onsuccess = (event) => {
|
|
38
|
-
resolve(event.target.result);
|
|
39
|
-
};
|
|
40
|
-
req.onerror = () => {
|
|
41
|
-
dbPromise = null;
|
|
42
|
-
reject(req.error);
|
|
43
|
-
};
|
|
44
|
-
req.onblocked = () => {
|
|
45
|
-
dbPromise = null;
|
|
46
|
-
reject(new Error('[smartlinks] IndexedDB open blocked'));
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
dbPromise = null;
|
|
51
|
-
reject(err);
|
|
52
|
-
}
|
|
30
|
+
/** Resolve when the transaction settles, whatever the outcome. */
|
|
31
|
+
function settled(tx) {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
tx.oncomplete = () => resolve();
|
|
34
|
+
tx.onerror = () => resolve(); // quota exceeded etc — fail silently
|
|
35
|
+
tx.onabort = () => resolve();
|
|
53
36
|
});
|
|
54
|
-
return dbPromise;
|
|
55
37
|
}
|
|
56
38
|
/**
|
|
57
39
|
* Read an entry from IndexedDB.
|
|
@@ -62,18 +44,11 @@ export async function idbGet(key) {
|
|
|
62
44
|
if (!isIdbAvailable())
|
|
63
45
|
return null;
|
|
64
46
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
req.onsuccess = () => { var _a; return resolve((_a = req.result) !== null && _a !== void 0 ? _a : null); };
|
|
71
|
-
req.onerror = () => resolve(null);
|
|
72
|
-
}
|
|
73
|
-
catch (_a) {
|
|
74
|
-
resolve(null);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
47
|
+
return await connection.run('readonly', (store) => new Promise((resolve) => {
|
|
48
|
+
const req = store.get(key);
|
|
49
|
+
req.onsuccess = () => { var _a; return resolve((_a = req.result) !== null && _a !== void 0 ? _a : null); };
|
|
50
|
+
req.onerror = () => resolve(null);
|
|
51
|
+
}));
|
|
77
52
|
}
|
|
78
53
|
catch (_a) {
|
|
79
54
|
return null;
|
|
@@ -88,18 +63,9 @@ export async function idbSet(key, entry) {
|
|
|
88
63
|
if (!isIdbAvailable())
|
|
89
64
|
return;
|
|
90
65
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
95
|
-
tx.objectStore(STORE_NAME).put(entry, key);
|
|
96
|
-
tx.oncomplete = () => resolve();
|
|
97
|
-
tx.onerror = () => resolve(); // quota exceeded etc — fail silently
|
|
98
|
-
tx.onabort = () => resolve();
|
|
99
|
-
}
|
|
100
|
-
catch (_a) {
|
|
101
|
-
resolve();
|
|
102
|
-
}
|
|
66
|
+
await connection.run('readwrite', (store, tx) => {
|
|
67
|
+
store.put(entry, key);
|
|
68
|
+
return settled(tx);
|
|
103
69
|
});
|
|
104
70
|
}
|
|
105
71
|
catch (_a) {
|
|
@@ -114,18 +80,9 @@ export async function idbDelete(key) {
|
|
|
114
80
|
if (!isIdbAvailable())
|
|
115
81
|
return;
|
|
116
82
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
121
|
-
tx.objectStore(STORE_NAME).delete(key);
|
|
122
|
-
tx.oncomplete = () => resolve();
|
|
123
|
-
tx.onerror = () => resolve();
|
|
124
|
-
tx.onabort = () => resolve();
|
|
125
|
-
}
|
|
126
|
-
catch (_a) {
|
|
127
|
-
resolve();
|
|
128
|
-
}
|
|
83
|
+
await connection.run('readwrite', (store, tx) => {
|
|
84
|
+
store.delete(key);
|
|
85
|
+
return settled(tx);
|
|
129
86
|
});
|
|
130
87
|
}
|
|
131
88
|
catch (_a) { }
|
|
@@ -138,41 +95,25 @@ export async function idbClear(pattern) {
|
|
|
138
95
|
if (!isIdbAvailable())
|
|
139
96
|
return;
|
|
140
97
|
try {
|
|
141
|
-
const db = await openDb();
|
|
142
98
|
if (!pattern) {
|
|
143
|
-
await
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
tx.objectStore(STORE_NAME).clear();
|
|
147
|
-
tx.oncomplete = () => resolve();
|
|
148
|
-
tx.onerror = () => resolve();
|
|
149
|
-
tx.onabort = () => resolve();
|
|
150
|
-
}
|
|
151
|
-
catch (_a) {
|
|
152
|
-
resolve();
|
|
153
|
-
}
|
|
99
|
+
await connection.run('readwrite', (store, tx) => {
|
|
100
|
+
store.clear();
|
|
101
|
+
return settled(tx);
|
|
154
102
|
});
|
|
155
103
|
return;
|
|
156
104
|
}
|
|
157
105
|
// Pattern-based: enumerate all keys and delete matching ones.
|
|
158
|
-
await new Promise((resolve) => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (key.includes(pattern))
|
|
166
|
-
store.delete(key);
|
|
167
|
-
}
|
|
168
|
-
resolve();
|
|
169
|
-
};
|
|
170
|
-
req.onerror = () => resolve();
|
|
171
|
-
}
|
|
172
|
-
catch (_a) {
|
|
106
|
+
await connection.run('readwrite', (store) => new Promise((resolve) => {
|
|
107
|
+
const req = store.getAllKeys();
|
|
108
|
+
req.onsuccess = () => {
|
|
109
|
+
for (const key of req.result) {
|
|
110
|
+
if (key.includes(pattern))
|
|
111
|
+
store.delete(key);
|
|
112
|
+
}
|
|
173
113
|
resolve();
|
|
174
|
-
}
|
|
175
|
-
|
|
114
|
+
};
|
|
115
|
+
req.onerror = () => resolve();
|
|
116
|
+
}));
|
|
176
117
|
}
|
|
177
118
|
catch (_a) { }
|
|
178
119
|
}
|
package/dist/theme.css
CHANGED
|
@@ -41,6 +41,26 @@
|
|
|
41
41
|
--shadow-md: var(--sl-shadow-md, 0 0 #0000);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/* Dark mode without values. A host in dark mode should send a dark value-set (the --sl-* tokens); one
|
|
45
|
+
* that only sets the hook (.dark / data-theme="dark") left every colour on its light fallback — white
|
|
46
|
+
* cards and near-black text on a dark page. Under the hook the fallbacks are dark too; whatever the host
|
|
47
|
+
* does send still wins. (Re-declared on the hook's element, so it works wherever the host puts it.) */
|
|
48
|
+
.dark,
|
|
49
|
+
[data-theme="dark"] {
|
|
50
|
+
--color-background: var(--sl-color-bg, #09090b);
|
|
51
|
+
--color-surface: var(--sl-color-surface, #18181b);
|
|
52
|
+
--color-surface-raised:var(--sl-color-surface-raised, var(--sl-color-surface, #27272a));
|
|
53
|
+
--color-foreground: var(--sl-color-fg, #fafafa);
|
|
54
|
+
--color-muted: var(--sl-color-muted, #a1a1aa);
|
|
55
|
+
--color-border: var(--sl-color-border, #3f3f46);
|
|
56
|
+
--color-primary: var(--sl-color-accent, #6366f1);
|
|
57
|
+
--color-on-primary: var(--sl-color-on-accent, #ffffff);
|
|
58
|
+
--color-primary-soft: var(--sl-color-accent-soft, color-mix(in oklab, var(--sl-color-accent, #6366f1) 20%, transparent));
|
|
59
|
+
--color-success: var(--sl-color-success, #22c55e);
|
|
60
|
+
--color-danger: var(--sl-color-danger, #f87171);
|
|
61
|
+
color-scheme: dark;
|
|
62
|
+
}
|
|
63
|
+
|
|
44
64
|
/* shadcn bridge (optional): if the app uses shadcn's --primary/--background/etc. HSL variables,
|
|
45
65
|
* uncomment to drive them from the SmartLinks tokens too. Left commented so it never overrides an
|
|
46
66
|
* app that has deliberately customised its shadcn palette — opt in per app (see migration step 17).
|
package/dist/translationCache.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { createIdbConnection } from './idbConnection.js';
|
|
1
2
|
const DB_NAME = 'smartlinks-sdk-translations';
|
|
2
3
|
const STORE_NAME = 'translations';
|
|
3
4
|
const DB_VERSION = 1;
|
|
4
5
|
const DEFAULT_LOCAL_TRANSLATION_TTL_MS = 90 * 24 * 60 * 60000;
|
|
5
|
-
|
|
6
|
+
const connection = createIdbConnection(DB_NAME, STORE_NAME, DB_VERSION);
|
|
6
7
|
const memoryTranslationCache = new Map();
|
|
7
8
|
export function getDefaultTranslationCacheTtlMs() {
|
|
8
9
|
return DEFAULT_LOCAL_TRANSLATION_TTL_MS;
|
|
@@ -15,36 +16,13 @@ function isIndexedDbAvailable() {
|
|
|
15
16
|
return false;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
request.onupgradeneeded = (event) => {
|
|
25
|
-
const db = event.target.result;
|
|
26
|
-
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
27
|
-
db.createObjectStore(STORE_NAME);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
request.onsuccess = (event) => {
|
|
31
|
-
resolve(event.target.result);
|
|
32
|
-
};
|
|
33
|
-
request.onerror = () => {
|
|
34
|
-
dbPromise = null;
|
|
35
|
-
reject(request.error);
|
|
36
|
-
};
|
|
37
|
-
request.onblocked = () => {
|
|
38
|
-
dbPromise = null;
|
|
39
|
-
reject(new Error('[smartlinks] Translation IndexedDB open blocked'));
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
dbPromise = null;
|
|
44
|
-
reject(error);
|
|
45
|
-
}
|
|
19
|
+
/** Resolve when the transaction settles, whatever the outcome. */
|
|
20
|
+
function settled(tx) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
tx.oncomplete = () => resolve();
|
|
23
|
+
tx.onerror = () => resolve();
|
|
24
|
+
tx.onabort = () => resolve();
|
|
46
25
|
});
|
|
47
|
-
return dbPromise;
|
|
48
26
|
}
|
|
49
27
|
function stableContextKey(context) {
|
|
50
28
|
if (!context)
|
|
@@ -123,33 +101,26 @@ async function getEntry(key) {
|
|
|
123
101
|
if (!isIndexedDbAvailable())
|
|
124
102
|
return null;
|
|
125
103
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
};
|
|
147
|
-
request.onerror = () => resolve(null);
|
|
148
|
-
}
|
|
149
|
-
catch (_a) {
|
|
150
|
-
resolve(null);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
104
|
+
return await connection.run('readonly', (store) => new Promise((resolve) => {
|
|
105
|
+
const request = store.get(key);
|
|
106
|
+
request.onsuccess = () => {
|
|
107
|
+
var _a;
|
|
108
|
+
const result = (_a = request.result) !== null && _a !== void 0 ? _a : null;
|
|
109
|
+
if (!result) {
|
|
110
|
+
resolve(null);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (isExpired(result)) {
|
|
114
|
+
memoryTranslationCache.delete(key);
|
|
115
|
+
void deleteEntries([key]);
|
|
116
|
+
resolve(null);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
memoryTranslationCache.set(key, result);
|
|
120
|
+
resolve(result);
|
|
121
|
+
};
|
|
122
|
+
request.onerror = () => resolve(null);
|
|
123
|
+
}));
|
|
153
124
|
}
|
|
154
125
|
catch (_a) {
|
|
155
126
|
return null;
|
|
@@ -170,21 +141,11 @@ async function setEntries(entries) {
|
|
|
170
141
|
if (!isIndexedDbAvailable())
|
|
171
142
|
return;
|
|
172
143
|
try {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
177
|
-
const store = tx.objectStore(STORE_NAME);
|
|
178
|
-
for (const [key, entry] of entries) {
|
|
179
|
-
store.put(entry, key);
|
|
180
|
-
}
|
|
181
|
-
tx.oncomplete = () => resolve();
|
|
182
|
-
tx.onerror = () => resolve();
|
|
183
|
-
tx.onabort = () => resolve();
|
|
184
|
-
}
|
|
185
|
-
catch (_a) {
|
|
186
|
-
resolve();
|
|
144
|
+
await connection.run('readwrite', (store, tx) => {
|
|
145
|
+
for (const [key, entry] of entries) {
|
|
146
|
+
store.put(entry, key);
|
|
187
147
|
}
|
|
148
|
+
return settled(tx);
|
|
188
149
|
});
|
|
189
150
|
}
|
|
190
151
|
catch (_a) {
|
|
@@ -226,21 +187,11 @@ async function deleteEntries(keys) {
|
|
|
226
187
|
if (!isIndexedDbAvailable() || keys.length === 0)
|
|
227
188
|
return;
|
|
228
189
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
233
|
-
const store = tx.objectStore(STORE_NAME);
|
|
234
|
-
for (const key of keys) {
|
|
235
|
-
store.delete(key);
|
|
236
|
-
}
|
|
237
|
-
tx.oncomplete = () => resolve();
|
|
238
|
-
tx.onerror = () => resolve();
|
|
239
|
-
tx.onabort = () => resolve();
|
|
240
|
-
}
|
|
241
|
-
catch (_a) {
|
|
242
|
-
resolve();
|
|
190
|
+
await connection.run('readwrite', (store, tx) => {
|
|
191
|
+
for (const key of keys) {
|
|
192
|
+
store.delete(key);
|
|
243
193
|
}
|
|
194
|
+
return settled(tx);
|
|
244
195
|
});
|
|
245
196
|
}
|
|
246
197
|
catch (_a) {
|
|
@@ -256,41 +207,25 @@ export async function clearCachedTranslations(collectionId) {
|
|
|
256
207
|
if (!isIndexedDbAvailable())
|
|
257
208
|
return;
|
|
258
209
|
try {
|
|
259
|
-
const db = await openDb();
|
|
260
210
|
if (!collectionId) {
|
|
261
|
-
await
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
tx.objectStore(STORE_NAME).clear();
|
|
265
|
-
tx.oncomplete = () => resolve();
|
|
266
|
-
tx.onerror = () => resolve();
|
|
267
|
-
tx.onabort = () => resolve();
|
|
268
|
-
}
|
|
269
|
-
catch (_a) {
|
|
270
|
-
resolve();
|
|
271
|
-
}
|
|
211
|
+
await connection.run('readwrite', (store, tx) => {
|
|
212
|
+
store.clear();
|
|
213
|
+
return settled(tx);
|
|
272
214
|
});
|
|
273
215
|
return;
|
|
274
216
|
}
|
|
275
|
-
await new Promise((resolve) => {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
for (const key of request.result) {
|
|
282
|
-
if (key.startsWith(`${collectionId}::`)) {
|
|
283
|
-
store.delete(key);
|
|
284
|
-
}
|
|
217
|
+
await connection.run('readwrite', (store) => new Promise((resolve) => {
|
|
218
|
+
const request = store.getAllKeys();
|
|
219
|
+
request.onsuccess = () => {
|
|
220
|
+
for (const key of request.result) {
|
|
221
|
+
if (key.startsWith(`${collectionId}::`)) {
|
|
222
|
+
store.delete(key);
|
|
285
223
|
}
|
|
286
|
-
|
|
287
|
-
};
|
|
288
|
-
request.onerror = () => resolve();
|
|
289
|
-
}
|
|
290
|
-
catch (_a) {
|
|
224
|
+
}
|
|
291
225
|
resolve();
|
|
292
|
-
}
|
|
293
|
-
|
|
226
|
+
};
|
|
227
|
+
request.onerror = () => resolve();
|
|
228
|
+
}));
|
|
294
229
|
}
|
|
295
230
|
catch (_a) {
|
|
296
231
|
// Ignore deletion failures.
|
package/dist/types/claimSet.d.ts
CHANGED
|
@@ -122,3 +122,188 @@ export interface CreateClaimSetTagResponse {
|
|
|
122
122
|
/** Arbitrary extra fields */
|
|
123
123
|
data?: Record<string, unknown>;
|
|
124
124
|
}
|
|
125
|
+
/** Who a range call acts as: a collection on its own sets, or a partner on the partner's sets. */
|
|
126
|
+
export type ClaimSetScope = {
|
|
127
|
+
collectionId: string;
|
|
128
|
+
} | {
|
|
129
|
+
partnerId: string;
|
|
130
|
+
};
|
|
131
|
+
export type ClaimSetTagType = 'ntag424' | 'ntag21x' | 'qr';
|
|
132
|
+
export type ClaimSetRangeStatus = 'minting' | 'minted' | 'sent' | 'received' | 'assigned';
|
|
133
|
+
export interface ClaimSetRange {
|
|
134
|
+
id: string;
|
|
135
|
+
claimSetId: string;
|
|
136
|
+
namespace: string;
|
|
137
|
+
name: string;
|
|
138
|
+
notes: string | null;
|
|
139
|
+
startIndex: number;
|
|
140
|
+
endIndex: number;
|
|
141
|
+
quantity: number;
|
|
142
|
+
tagType: ClaimSetTagType;
|
|
143
|
+
fulfilment: 'printer' | 'sidekick';
|
|
144
|
+
/** The stored step: minting | minted | sent | received */
|
|
145
|
+
stage: 'minting' | 'minted' | 'sent' | 'received';
|
|
146
|
+
/** What to show: the stage, or 'assigned' once every tag is assigned */
|
|
147
|
+
status: ClaimSetRangeStatus;
|
|
148
|
+
intendedCollectionId: string | null;
|
|
149
|
+
intendedProductId: string | null;
|
|
150
|
+
intendedBatchId: string | null;
|
|
151
|
+
manufacturer: string | null;
|
|
152
|
+
orderRef: string | null;
|
|
153
|
+
counts: {
|
|
154
|
+
programmed: number;
|
|
155
|
+
assigned: number;
|
|
156
|
+
claimed: number;
|
|
157
|
+
};
|
|
158
|
+
sentAt: string | null;
|
|
159
|
+
receivedAt: string | null;
|
|
160
|
+
createdBy: string | null;
|
|
161
|
+
createdAt: string;
|
|
162
|
+
updatedAt: string;
|
|
163
|
+
}
|
|
164
|
+
export interface CreateClaimSetRangeRequest {
|
|
165
|
+
name: string;
|
|
166
|
+
/** 1 to 10,000 */
|
|
167
|
+
quantity: number;
|
|
168
|
+
/** Pre-assign every tag at mint time (you must administer the collection) */
|
|
169
|
+
intendedCollectionId?: string;
|
|
170
|
+
intendedProductId?: string;
|
|
171
|
+
intendedBatchId?: string;
|
|
172
|
+
fulfilment?: 'printer' | 'sidekick';
|
|
173
|
+
notes?: string;
|
|
174
|
+
manufacturer?: string;
|
|
175
|
+
orderRef?: string;
|
|
176
|
+
}
|
|
177
|
+
export interface UpdateClaimSetRangeRequest {
|
|
178
|
+
name?: string;
|
|
179
|
+
notes?: string | null;
|
|
180
|
+
manufacturer?: string | null;
|
|
181
|
+
orderRef?: string | null;
|
|
182
|
+
fulfilment?: 'printer' | 'sidekick';
|
|
183
|
+
stage?: 'minted' | 'sent' | 'received';
|
|
184
|
+
}
|
|
185
|
+
export interface ClaimSetRangeTag {
|
|
186
|
+
code: string;
|
|
187
|
+
/** The printed code: 3-character set id + code */
|
|
188
|
+
printed: string;
|
|
189
|
+
index: number;
|
|
190
|
+
uid: string | null;
|
|
191
|
+
/** Only for owners/admins, and only when asked for */
|
|
192
|
+
key?: string;
|
|
193
|
+
collectionId: string | null;
|
|
194
|
+
productId: string | null;
|
|
195
|
+
batchId: string | null;
|
|
196
|
+
proofId: string | null;
|
|
197
|
+
programmedAt: string | null;
|
|
198
|
+
scans: number;
|
|
199
|
+
}
|
|
200
|
+
export interface ClaimSetRangeTagsPage {
|
|
201
|
+
tags: ClaimSetRangeTag[];
|
|
202
|
+
/** The index to pass as `from` for the next page, or null */
|
|
203
|
+
next: number | null;
|
|
204
|
+
}
|
|
205
|
+
/** The next tag to program on a phone, with what to write. */
|
|
206
|
+
export interface ClaimSetRangeNextTag extends ClaimSetRangeTag {
|
|
207
|
+
url: string;
|
|
208
|
+
piccOffset?: number;
|
|
209
|
+
mirrorOffset?: number;
|
|
210
|
+
remaining: number;
|
|
211
|
+
}
|
|
212
|
+
export type ClaimSetImportResult = 'ok' | 'unchanged' | 'unknown_code' | 'duplicate_row' | 'index_mismatch' | 'no_uid' | 'bad_uid' | 'duplicate_uid' | 'uid_in_use' | 'uid_conflict';
|
|
213
|
+
export interface ImportClaimSetRangeUidsRequest {
|
|
214
|
+
/** The manufacturer's file as CSV text (the file we sent, with UID filled in) */
|
|
215
|
+
csv?: string;
|
|
216
|
+
/** …or already-parsed rows: [{ Code, Index?, UID }] */
|
|
217
|
+
rows?: Array<Record<string, string | number>>;
|
|
218
|
+
/** false (default) only checks; true writes the UIDs that matched */
|
|
219
|
+
commit?: boolean;
|
|
220
|
+
}
|
|
221
|
+
export interface ImportClaimSetRangeUidsResponse {
|
|
222
|
+
summary: {
|
|
223
|
+
rows: number;
|
|
224
|
+
ok: number;
|
|
225
|
+
unchanged: number;
|
|
226
|
+
problems: number;
|
|
227
|
+
notInFile: number;
|
|
228
|
+
committed: boolean;
|
|
229
|
+
};
|
|
230
|
+
rows: Array<{
|
|
231
|
+
line: number;
|
|
232
|
+
code: string;
|
|
233
|
+
index: number | null;
|
|
234
|
+
uid: string;
|
|
235
|
+
result: ClaimSetImportResult;
|
|
236
|
+
message?: string;
|
|
237
|
+
}>;
|
|
238
|
+
range: ClaimSetRange;
|
|
239
|
+
}
|
|
240
|
+
export interface AssignClaimSetRangeRequest {
|
|
241
|
+
/** Required unless clear */
|
|
242
|
+
collectionId?: string;
|
|
243
|
+
productId?: string;
|
|
244
|
+
batchId?: string;
|
|
245
|
+
/** Default: the whole range */
|
|
246
|
+
start?: number;
|
|
247
|
+
end?: number;
|
|
248
|
+
/** Unassign instead (tags bound to a proof are never cleared) */
|
|
249
|
+
clear?: boolean;
|
|
250
|
+
data?: Record<string, unknown>;
|
|
251
|
+
}
|
|
252
|
+
export interface AssignClaimSetRangeResponse {
|
|
253
|
+
changed: number;
|
|
254
|
+
skipped: Array<{
|
|
255
|
+
code: string;
|
|
256
|
+
index: number;
|
|
257
|
+
reason: 'other_range' | 'has_proof' | 'assigned_elsewhere';
|
|
258
|
+
collectionId?: string;
|
|
259
|
+
}>;
|
|
260
|
+
range: ClaimSetRange;
|
|
261
|
+
}
|
|
262
|
+
export interface ClaimSetRangeFile {
|
|
263
|
+
filename: string;
|
|
264
|
+
contentType: string;
|
|
265
|
+
/** export: the printer file */
|
|
266
|
+
csv?: string;
|
|
267
|
+
/** instructions as PDF: the file, base64 */
|
|
268
|
+
base64?: string;
|
|
269
|
+
/** instructions as Markdown */
|
|
270
|
+
markdown?: string;
|
|
271
|
+
}
|
|
272
|
+
export interface Partner {
|
|
273
|
+
id: string;
|
|
274
|
+
name: string;
|
|
275
|
+
status: 'active' | 'suspended';
|
|
276
|
+
tapDomains: string[];
|
|
277
|
+
features: Record<string, boolean>;
|
|
278
|
+
/** Your role (from partner.list / partner.get) */
|
|
279
|
+
role?: 'owner' | 'admin' | 'assigner';
|
|
280
|
+
/** Owners only */
|
|
281
|
+
members?: Array<{
|
|
282
|
+
userId: string;
|
|
283
|
+
role: 'owner' | 'admin' | 'assigner';
|
|
284
|
+
grantedBy: string | null;
|
|
285
|
+
grantedAt: string;
|
|
286
|
+
}>;
|
|
287
|
+
createdAt: string;
|
|
288
|
+
updatedAt: string;
|
|
289
|
+
}
|
|
290
|
+
export interface PartnerClaimSet {
|
|
291
|
+
id: string;
|
|
292
|
+
namespace: string;
|
|
293
|
+
name: string | null;
|
|
294
|
+
tagType: ClaimSetTagType;
|
|
295
|
+
tapDomain: string;
|
|
296
|
+
owner: {
|
|
297
|
+
type: 'platform' | 'partner' | 'collection' | 'user';
|
|
298
|
+
id: string | null;
|
|
299
|
+
};
|
|
300
|
+
codes: number;
|
|
301
|
+
deleted: boolean;
|
|
302
|
+
createdAt: string | null;
|
|
303
|
+
}
|
|
304
|
+
export interface CreatePartnerClaimSetRequest {
|
|
305
|
+
name: string;
|
|
306
|
+
tagType: ClaimSetTagType;
|
|
307
|
+
/** One of the partner's tap domains; default smartlinks.app */
|
|
308
|
+
tapDomain?: string;
|
|
309
|
+
}
|