@fixl-tech/igp-personalization 1.1.2
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/README.md +511 -0
- package/dist/catalog.d.ts +5 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +76 -0
- package/dist/catalog.js.map +1 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +101 -0
- package/dist/client.js.map +1 -0
- package/dist/designs.d.ts +12 -0
- package/dist/designs.d.ts.map +1 -0
- package/dist/designs.js +44 -0
- package/dist/designs.js.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +31 -0
- package/dist/errors.js.map +1 -0
- package/dist/ids.d.ts +2 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +12 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/products.d.ts +12 -0
- package/dist/products.d.ts.map +1 -0
- package/dist/products.js +41 -0
- package/dist/products.js.map +1 -0
- package/dist/signing.d.ts +12 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +55 -0
- package/dist/signing.js.map +1 -0
- package/dist/storage/json-file.d.ts +6 -0
- package/dist/storage/json-file.d.ts.map +1 -0
- package/dist/storage/json-file.js +62 -0
- package/dist/storage/json-file.js.map +1 -0
- package/dist/storage/memory.d.ts +3 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +36 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/studio.d.ts +6 -0
- package/dist/studio.d.ts.map +1 -0
- package/dist/studio.js +16 -0
- package/dist/studio.js.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +8 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +101 -0
- package/dist/validation.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
# igp-personalization
|
|
2
|
+
|
|
3
|
+
Unified TypeScript SDK for IGP-style product personalization. This package combines the old `igp-personalization-core` and `igp-personalization-sdk` responsibilities into one typed package:
|
|
4
|
+
|
|
5
|
+
- Local, in-process personalization engine through `createStudio(...)`.
|
|
6
|
+
- Storage adapters through `createMemoryStorage()` and `createJsonFileStorage(...)`.
|
|
7
|
+
- Product and design validation helpers.
|
|
8
|
+
- HMAC request signing shared by server and client code.
|
|
9
|
+
- Hosted API client through `new Client(...)`.
|
|
10
|
+
|
|
11
|
+
The package is written in TypeScript, builds to CommonJS in `dist/`, and emits `.d.ts` declarations for full type safety.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install igp-personalization
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Node.js 18+ because the remote client uses the built-in `fetch`, `FormData`, and `Blob` APIs.
|
|
20
|
+
|
|
21
|
+
## Build From This Repo
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd personalization-unified-sdk
|
|
25
|
+
npm install
|
|
26
|
+
npm run build
|
|
27
|
+
npm test
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Output is generated into `dist/`:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
dist/index.js
|
|
34
|
+
dist/index.d.ts
|
|
35
|
+
dist/**/*.js
|
|
36
|
+
dist/**/*.d.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Import
|
|
40
|
+
|
|
41
|
+
CommonJS:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const {
|
|
45
|
+
Client,
|
|
46
|
+
createStudio,
|
|
47
|
+
createMemoryStorage,
|
|
48
|
+
createJsonFileStorage,
|
|
49
|
+
signing,
|
|
50
|
+
} = require('igp-personalization');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
TypeScript:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {
|
|
57
|
+
Client,
|
|
58
|
+
createStudio,
|
|
59
|
+
createMemoryStorage,
|
|
60
|
+
type DesignInput,
|
|
61
|
+
type Product,
|
|
62
|
+
} from 'igp-personalization';
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Local Studio Engine
|
|
66
|
+
|
|
67
|
+
Use `createStudio({ storage })` when you want the personalization logic to run inside your own process without HTTP.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createStudio, createMemoryStorage } from 'igp-personalization';
|
|
71
|
+
|
|
72
|
+
const studio = createStudio({
|
|
73
|
+
storage: createMemoryStorage(),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const products = await studio.products.list();
|
|
77
|
+
const mug = await studio.products.get('mug-white-11oz');
|
|
78
|
+
|
|
79
|
+
const design = await studio.designs.save({
|
|
80
|
+
productId: mug.id,
|
|
81
|
+
productName: mug.name,
|
|
82
|
+
layers: [{ type: 'text', text: 'Happy Birthday!', x: 300, y: 300 }],
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `createStudio({ storage })`
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
{
|
|
92
|
+
storage,
|
|
93
|
+
products,
|
|
94
|
+
designs,
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Throws if the storage adapter does not expose `collection(name)`.
|
|
99
|
+
|
|
100
|
+
## Product Functions
|
|
101
|
+
|
|
102
|
+
### `studio.products.list()`
|
|
103
|
+
|
|
104
|
+
Returns all built-in products plus custom products from storage.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const products = await studio.products.list();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `studio.products.get(id)`
|
|
111
|
+
|
|
112
|
+
Returns one product by ID.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const product = await studio.products.get('mug-white-11oz');
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Throws `NotFoundError` if the product does not exist.
|
|
119
|
+
|
|
120
|
+
### `studio.products.addCustom(input)`
|
|
121
|
+
|
|
122
|
+
Creates a custom product.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const product = await studio.products.addCustom({
|
|
126
|
+
name: 'Tote Bag',
|
|
127
|
+
mockupUrl: '/mockups/tote.svg',
|
|
128
|
+
price: 499,
|
|
129
|
+
category: 'Bags',
|
|
130
|
+
canvasWidth: 600,
|
|
131
|
+
canvasHeight: 600,
|
|
132
|
+
printAreas: [
|
|
133
|
+
{ x: 60, y: 80, width: 280, height: 300, shape: 'rectangle' },
|
|
134
|
+
],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Throws `ValidationError` when required fields are missing or print areas are invalid.
|
|
139
|
+
|
|
140
|
+
### `studio.products.removeCustom(id)`
|
|
141
|
+
|
|
142
|
+
Deletes a custom product.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
await studio.products.removeCustom('custom-abc123');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Throws `NotFoundError` if the ID is unknown.
|
|
149
|
+
|
|
150
|
+
## Design Functions
|
|
151
|
+
|
|
152
|
+
### `studio.designs.list()`
|
|
153
|
+
|
|
154
|
+
Returns saved designs, newest first.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
const designs = await studio.designs.list();
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `studio.designs.get(id)`
|
|
161
|
+
|
|
162
|
+
Returns one saved design.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const design = await studio.designs.get('design_id');
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Throws `NotFoundError` if the design does not exist.
|
|
169
|
+
|
|
170
|
+
### `studio.designs.save(input)`
|
|
171
|
+
|
|
172
|
+
Saves a design.
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const design = await studio.designs.save({
|
|
176
|
+
productId: 'mug-white-11oz',
|
|
177
|
+
productName: 'Classic White Mug (11oz)',
|
|
178
|
+
layers: [
|
|
179
|
+
{ type: 'text', text: 'Happy Birthday!', x: 300, y: 300 },
|
|
180
|
+
{ type: 'image', url: 'https://cdn.example.com/logo.png', x: 120, y: 180 },
|
|
181
|
+
],
|
|
182
|
+
previewDataUrl: 'data:image/png;base64,...',
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Throws `ValidationError` if `productId` or `layers[]` is missing.
|
|
187
|
+
|
|
188
|
+
### `studio.designs.delete(id)`
|
|
189
|
+
|
|
190
|
+
Deletes a saved design.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
await studio.designs.delete('design_id');
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Throws `NotFoundError` if the design does not exist.
|
|
197
|
+
|
|
198
|
+
## Storage Adapters
|
|
199
|
+
|
|
200
|
+
A storage adapter implements:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
interface StorageAdapter {
|
|
204
|
+
collection(name: string): {
|
|
205
|
+
all(): Promise<Array<{ id: string }>>;
|
|
206
|
+
get(id: string): Promise<{ id: string } | null>;
|
|
207
|
+
put(doc: { id: string }): Promise<void>;
|
|
208
|
+
remove(id: string): Promise<boolean>;
|
|
209
|
+
count?(): Promise<number>;
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### `createMemoryStorage()`
|
|
215
|
+
|
|
216
|
+
Ephemeral storage for tests, scripts, and demos.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
const storage = createMemoryStorage();
|
|
220
|
+
const studio = createStudio({ storage });
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `createJsonFileStorage({ dir })`
|
|
224
|
+
|
|
225
|
+
Persists each collection as a JSON file under `dir`.
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const storage = createJsonFileStorage({ dir: './data' });
|
|
229
|
+
const studio = createStudio({ storage });
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
This creates files such as:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
data/designs.json
|
|
236
|
+
data/custom-products.json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Validation Helpers
|
|
240
|
+
|
|
241
|
+
### `sanitizePoints(points)`
|
|
242
|
+
|
|
243
|
+
Validates custom polygon points. Returns sanitized points or `null`.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
const points = sanitizePoints([
|
|
247
|
+
[10, 10],
|
|
248
|
+
[100, 10],
|
|
249
|
+
[100, 100],
|
|
250
|
+
]);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `sanitizeArea(area, index?)`
|
|
254
|
+
|
|
255
|
+
Validates and normalizes one print area. Returns a `PrintArea` or `null`.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
const area = sanitizeArea({
|
|
259
|
+
x: 10,
|
|
260
|
+
y: 20,
|
|
261
|
+
width: 200,
|
|
262
|
+
height: 120,
|
|
263
|
+
shape: 'rounded-rect',
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### `buildCustomProductFields(input)`
|
|
268
|
+
|
|
269
|
+
Validates custom product input and returns normalized fields without ID or timestamps. `ProductService.addCustom(...)` uses this internally.
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
const fields = buildCustomProductFields({
|
|
273
|
+
name: 'Poster',
|
|
274
|
+
mockupUrl: '/mockups/poster.svg',
|
|
275
|
+
printAreas: [{ x: 50, y: 50, width: 300, height: 400, shape: 'rectangle' }],
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### `validateDesignInput(input)`
|
|
280
|
+
|
|
281
|
+
Throws `ValidationError` unless the design has `productId` and `layers[]`.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
validateDesignInput({
|
|
285
|
+
productId: 'mug-white-11oz',
|
|
286
|
+
layers: [{ type: 'text', text: 'Hello' }],
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Signing
|
|
291
|
+
|
|
292
|
+
The SDK signs requests with:
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
HMAC-SHA256(secret, "METHOD\nPATH\nTIMESTAMP\nSHA256(body)")
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### `signing.sign(input)`
|
|
299
|
+
|
|
300
|
+
Creates a signature.
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
const signature = signing.sign({
|
|
304
|
+
secret: 'sk_test',
|
|
305
|
+
method: 'POST',
|
|
306
|
+
path: '/v1/designs',
|
|
307
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
308
|
+
body: JSON.stringify({ productId: 'mug-white-11oz', layers: [] }),
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### `signing.verify(input)`
|
|
313
|
+
|
|
314
|
+
Verifies the signature and timestamp skew.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
const ok = signing.verify({
|
|
318
|
+
secret: 'sk_test',
|
|
319
|
+
method: 'POST',
|
|
320
|
+
path: '/v1/designs',
|
|
321
|
+
timestamp,
|
|
322
|
+
body,
|
|
323
|
+
signature,
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### `signing.buildStringToSign(input)`
|
|
328
|
+
|
|
329
|
+
Returns the canonical string used by HMAC.
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
const canonical = signing.buildStringToSign({
|
|
333
|
+
method: 'GET',
|
|
334
|
+
path: '/v1/products',
|
|
335
|
+
timestamp: 1710000000,
|
|
336
|
+
body: '',
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### `signing.sha256Hex(input)`
|
|
341
|
+
|
|
342
|
+
Returns the SHA-256 hex digest of a string or buffer.
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
const digest = signing.sha256Hex('hello');
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The individual functions `sign`, `verify`, `buildStringToSign`, and `sha256Hex` are also exported directly.
|
|
349
|
+
|
|
350
|
+
## Hosted API Client
|
|
351
|
+
|
|
352
|
+
Use `Client` when calling the hosted `/v1` API. The API secret stays on your server and is never sent over the network.
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
import { Client } from 'igp-personalization';
|
|
356
|
+
|
|
357
|
+
const client = new Client({
|
|
358
|
+
apiKey: process.env.PERSONALIZATION_API_KEY!,
|
|
359
|
+
apiSecret: process.env.PERSONALIZATION_API_SECRET!,
|
|
360
|
+
baseUrl: 'https://api.yourco.com',
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### `client.products.list()`
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
const products = await client.products.list();
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### `client.products.get(id)`
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
const product = await client.products.get('mug-white-11oz');
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### `client.products.addCustom(input)`
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
const product = await client.products.addCustom({
|
|
380
|
+
name: 'Tote Bag',
|
|
381
|
+
mockupUrl: '/mockups/tote.svg',
|
|
382
|
+
printAreas: [{ x: 60, y: 80, width: 280, height: 300, shape: 'rectangle' }],
|
|
383
|
+
});
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### `client.products.removeCustom(id)`
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
await client.products.removeCustom('custom-abc123');
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### `client.designs.list()`
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
const designs = await client.designs.list();
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### `client.designs.get(id)`
|
|
399
|
+
|
|
400
|
+
```ts
|
|
401
|
+
const design = await client.designs.get('design_id');
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### `client.designs.save(input)`
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
const saved = await client.designs.save({
|
|
408
|
+
productId: 'mug-white-11oz',
|
|
409
|
+
layers: [{ type: 'text', text: 'Hello', x: 100, y: 120 }],
|
|
410
|
+
});
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### `client.designs.delete(id)`
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
await client.designs.delete('design_id');
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### `client.uploadImage(data, options?)`
|
|
420
|
+
|
|
421
|
+
Uploads an image using multipart form data. `data` can be a `Buffer`, `Uint8Array`, or `Blob`.
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
import fs from 'fs';
|
|
425
|
+
|
|
426
|
+
const uploaded = await client.uploadImage(fs.readFileSync('./logo.png'), {
|
|
427
|
+
filename: 'logo.png',
|
|
428
|
+
contentType: 'image/png',
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
console.log(uploaded.url);
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### `client.account()`
|
|
435
|
+
|
|
436
|
+
Returns the authenticated tenant, usage, and limits.
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
const account = await client.account();
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Errors
|
|
443
|
+
|
|
444
|
+
### `ValidationError`
|
|
445
|
+
|
|
446
|
+
Thrown by local validation when input is invalid.
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
try {
|
|
450
|
+
await studio.designs.save({} as never);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
if (error instanceof ValidationError) {
|
|
453
|
+
console.error(error.code, error.message);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### `NotFoundError`
|
|
459
|
+
|
|
460
|
+
Thrown by local services when a product or design is missing.
|
|
461
|
+
|
|
462
|
+
### `PersonalizationApiError`
|
|
463
|
+
|
|
464
|
+
Thrown by `Client` when the hosted API returns a non-2xx response.
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
try {
|
|
468
|
+
await client.designs.save({} as never);
|
|
469
|
+
} catch (error) {
|
|
470
|
+
if (error instanceof PersonalizationApiError) {
|
|
471
|
+
console.error(error.status, error.body);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Common statuses:
|
|
477
|
+
|
|
478
|
+
- `400`: invalid request payload.
|
|
479
|
+
- `401`: invalid API key or signature.
|
|
480
|
+
- `402`: plan limit reached.
|
|
481
|
+
- `413`: upload too large.
|
|
482
|
+
- `429`: rate limit or quota exceeded.
|
|
483
|
+
|
|
484
|
+
## Public Exports
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
Client
|
|
488
|
+
PersonalizationApiError
|
|
489
|
+
createStudio
|
|
490
|
+
createMemoryStorage
|
|
491
|
+
createJsonFileStorage
|
|
492
|
+
ProductService
|
|
493
|
+
DesignService
|
|
494
|
+
BUILTIN_PRODUCTS
|
|
495
|
+
ALLOWED_SHAPES
|
|
496
|
+
normalizeProduct
|
|
497
|
+
sanitizeArea
|
|
498
|
+
sanitizePoints
|
|
499
|
+
buildCustomProductFields
|
|
500
|
+
validateDesignInput
|
|
501
|
+
signing
|
|
502
|
+
sign
|
|
503
|
+
verify
|
|
504
|
+
buildStringToSign
|
|
505
|
+
sha256Hex
|
|
506
|
+
createId
|
|
507
|
+
ValidationError
|
|
508
|
+
NotFoundError
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Type exports include `Product`, `PrintArea`, `Design`, `DesignInput`, `CustomProductInput`, `StorageAdapter`, `StorageCollection`, `Studio`, `ClientOptions`, `UploadResult`, and signing input types.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Product } from './types';
|
|
2
|
+
export declare const ALLOWED_SHAPES: readonly ["rectangle", "rounded-rect", "ellipse", "diamond", "hexagon", "heart", "star", "custom"];
|
|
3
|
+
export declare const BUILTIN_PRODUCTS: Product[];
|
|
4
|
+
export declare function normalizeProduct(product: Product): Product;
|
|
5
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,cAAc,oGASmB,CAAC;AAE/C,eAAO,MAAM,gBAAgB,EAAE,OAAO,EA6CrC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAY1D"}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BUILTIN_PRODUCTS = exports.ALLOWED_SHAPES = void 0;
|
|
4
|
+
exports.normalizeProduct = normalizeProduct;
|
|
5
|
+
exports.ALLOWED_SHAPES = [
|
|
6
|
+
'rectangle',
|
|
7
|
+
'rounded-rect',
|
|
8
|
+
'ellipse',
|
|
9
|
+
'diamond',
|
|
10
|
+
'hexagon',
|
|
11
|
+
'heart',
|
|
12
|
+
'star',
|
|
13
|
+
'custom',
|
|
14
|
+
];
|
|
15
|
+
exports.BUILTIN_PRODUCTS = [
|
|
16
|
+
{
|
|
17
|
+
id: 'mug-white-11oz',
|
|
18
|
+
name: 'Classic White Mug (11oz)',
|
|
19
|
+
price: 349,
|
|
20
|
+
category: 'Drinkware',
|
|
21
|
+
mockup: '/mockups/mug.svg',
|
|
22
|
+
canvasWidth: 600,
|
|
23
|
+
canvasHeight: 600,
|
|
24
|
+
printAreas: [{ id: 'a1', name: 'Front', x: 150, y: 180, width: 300, height: 220, shape: 'rectangle' }],
|
|
25
|
+
custom: false,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'photo-frame-a4',
|
|
29
|
+
name: 'Wooden Photo Frame (A4)',
|
|
30
|
+
price: 799,
|
|
31
|
+
category: 'Home Decor',
|
|
32
|
+
mockup: '/mockups/frame.svg',
|
|
33
|
+
canvasWidth: 600,
|
|
34
|
+
canvasHeight: 600,
|
|
35
|
+
printAreas: [{ id: 'a1', name: 'Photo', x: 110, y: 90, width: 380, height: 420, shape: 'rectangle' }],
|
|
36
|
+
custom: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'tshirt-round-neck',
|
|
40
|
+
name: 'Round Neck T-Shirt (Cotton)',
|
|
41
|
+
price: 599,
|
|
42
|
+
category: 'Apparel',
|
|
43
|
+
mockup: '/mockups/tshirt.svg',
|
|
44
|
+
canvasWidth: 600,
|
|
45
|
+
canvasHeight: 600,
|
|
46
|
+
printAreas: [{ id: 'a1', name: 'Chest', x: 200, y: 200, width: 200, height: 260, shape: 'rectangle' }],
|
|
47
|
+
custom: false,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'cushion-16x16',
|
|
51
|
+
name: 'Cushion Cover (16x16 in)',
|
|
52
|
+
price: 499,
|
|
53
|
+
category: 'Home Decor',
|
|
54
|
+
mockup: '/mockups/cushion.svg',
|
|
55
|
+
canvasWidth: 600,
|
|
56
|
+
canvasHeight: 600,
|
|
57
|
+
printAreas: [{ id: 'a1', name: 'Front', x: 140, y: 140, width: 320, height: 320, shape: 'rounded-rect' }],
|
|
58
|
+
custom: false,
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
function normalizeProduct(product) {
|
|
62
|
+
let next = product;
|
|
63
|
+
if ((!Array.isArray(next.printAreas) || next.printAreas.length === 0) && next.printArea) {
|
|
64
|
+
next = {
|
|
65
|
+
...next,
|
|
66
|
+
printAreas: [{ id: 'a1', name: 'Area 1', ...next.printArea }],
|
|
67
|
+
printArea: undefined,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (!Number.isFinite(next.canvasWidth) || next.canvasWidth <= 0)
|
|
71
|
+
next = { ...next, canvasWidth: 600 };
|
|
72
|
+
if (!Number.isFinite(next.canvasHeight) || next.canvasHeight <= 0)
|
|
73
|
+
next = { ...next, canvasHeight: 600 };
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AccountResult, ClientOptions, CustomProductInput, Design, DesignInput, Product, UploadOptions, UploadResult } from './types';
|
|
2
|
+
export declare class Client {
|
|
3
|
+
readonly apiKey: string;
|
|
4
|
+
readonly apiSecret: string;
|
|
5
|
+
readonly baseUrl: string;
|
|
6
|
+
readonly products: {
|
|
7
|
+
list: () => Promise<Product[]>;
|
|
8
|
+
get: (id: string) => Promise<Product>;
|
|
9
|
+
addCustom: (input: CustomProductInput) => Promise<Product>;
|
|
10
|
+
removeCustom: (id: string) => Promise<{
|
|
11
|
+
ok: true;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
readonly designs: {
|
|
15
|
+
list: () => Promise<Design[]>;
|
|
16
|
+
get: (id: string) => Promise<Design>;
|
|
17
|
+
save: (input: DesignInput) => Promise<{
|
|
18
|
+
id: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
}>;
|
|
21
|
+
delete: (id: string) => Promise<{
|
|
22
|
+
ok: true;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
private readonly fetchImpl;
|
|
26
|
+
constructor({ apiKey, apiSecret, baseUrl, fetchImpl }: ClientOptions);
|
|
27
|
+
account(): Promise<AccountResult>;
|
|
28
|
+
uploadImage(data: Buffer | Uint8Array | Blob, { filename, contentType }?: UploadOptions): Promise<UploadResult>;
|
|
29
|
+
private headers;
|
|
30
|
+
private request;
|
|
31
|
+
private handle;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,OAAO,EACP,aAAa,EACb,YAAY,EACb,MAAM,SAAS,CAAC;AAMjB,qBAAa,MAAM;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE;QACjB,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/B,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACtC,SAAS,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3D,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,EAAE,EAAE,IAAI,CAAA;SAAE,CAAC,CAAC;KACrD,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE;QAChB,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9B,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACzE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,EAAE,EAAE,IAAI,CAAA;SAAE,CAAC,CAAC;KAC/C,CAAC;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,EAAE,MAAM,EAAE,SAAS,EAAE,OAAiC,EAAE,SAAS,EAAE,EAAE,aAAa;IA2B9F,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;IAI3B,WAAW,CACf,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,EAChC,EAAE,QAAuB,EAAE,WAAyB,EAAE,GAAE,aAAkB,GACzE,OAAO,CAAC,YAAY,CAAC;IAYxB,OAAO,CAAC,OAAO;YAiBD,OAAO;YAkBP,MAAM;CAoBrB"}
|