@snowcone-app/sdk 0.1.12 → 0.1.13
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 +99 -63
- package/dist/{chunk-UJFJ7REN.js → chunk-6MV7TDTM.js} +186 -18
- package/dist/index.cjs +756 -170
- package/dist/index.d.cts +130 -29
- package/dist/index.d.ts +130 -29
- package/dist/index.js +561 -144
- package/dist/react.cjs +203 -20
- package/dist/react.d.cts +13 -1
- package/dist/react.d.ts +13 -1
- package/dist/react.js +18 -3
- package/dist/{websocket-B8_XAwWx.d.ts → websocket-Dum3OooZ.d.cts} +55 -3
- package/dist/{websocket-B8_XAwWx.d.cts → websocket-Dum3OooZ.d.ts} +55 -3
- package/package.json +21 -11
- package/dist/chunk-HOYSZQET.js +0 -476
- package/dist/chunk-IIUCW2O4.js +0 -457
- package/dist/websocket-GXMYofWp.d.cts +0 -330
- package/dist/websocket-GXMYofWp.d.ts +0 -330
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-7VO4EL2V.js";
|
|
4
4
|
import {
|
|
5
5
|
RealtimeMockupService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6MV7TDTM.js";
|
|
7
7
|
|
|
8
8
|
// src/validation.ts
|
|
9
9
|
import { z } from "zod";
|
|
@@ -46,10 +46,19 @@ var CatalogProductSchema = z.object({
|
|
|
46
46
|
).optional(),
|
|
47
47
|
placements: z.array(
|
|
48
48
|
z.object({
|
|
49
|
+
// The one additive multi-placement field (rev 5 P1): a URL-safe slug
|
|
50
|
+
// used as the public param key (`asset.front`). Optional — older catalog
|
|
51
|
+
// docs predate it.
|
|
52
|
+
key: z.string().optional(),
|
|
49
53
|
label: z.string(),
|
|
50
|
-
type:
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
// Live data has placements with `type: null` (and ingestion may omit it
|
|
55
|
+
// entirely), not just "image"/"color". The previous strict enum threw on
|
|
56
|
+
// real catalog docs. Accept image | color | null | absent.
|
|
57
|
+
type: z.enum(["image", "color"]).nullable().optional(),
|
|
58
|
+
// Live data carries width/height of 0 (and `.int()` rejected nothing of
|
|
59
|
+
// import here). Drop `.int()` and allow nullable so 0 / null / float pass.
|
|
60
|
+
width: z.number().nullable().optional(),
|
|
61
|
+
height: z.number().nullable().optional(),
|
|
53
62
|
defaultScaleMode: z.enum(["fill", "fit"]).optional(),
|
|
54
63
|
fitMarginTop: z.number().int().optional(),
|
|
55
64
|
fitMarginRight: z.number().int().optional(),
|
|
@@ -70,7 +79,7 @@ var SignatureCache = class {
|
|
|
70
79
|
memoryCache = /* @__PURE__ */ new Map();
|
|
71
80
|
maxMemoryEntries;
|
|
72
81
|
maxLocalStorageEntries;
|
|
73
|
-
localStorageKey = "
|
|
82
|
+
localStorageKey = "snowcone_signature_cache";
|
|
74
83
|
localStorageAvailable;
|
|
75
84
|
constructor(maxMemoryEntries = 500, maxLocalStorageEntries = 100) {
|
|
76
85
|
this.maxMemoryEntries = maxMemoryEntries;
|
|
@@ -167,8 +176,8 @@ var SignatureCache = class {
|
|
|
167
176
|
};
|
|
168
177
|
|
|
169
178
|
// src/mockup/service.ts
|
|
170
|
-
var DEFAULT_IMAGE_URL = typeof process !== "undefined" && process.env?.
|
|
171
|
-
var DEFAULT_SIGNER_URL = typeof process !== "undefined" && process.env?.
|
|
179
|
+
var DEFAULT_IMAGE_URL = typeof process !== "undefined" && process.env?.SNOWCONE_IMAGE_URL || "https://cdn.snowcone.app";
|
|
180
|
+
var DEFAULT_SIGNER_URL = typeof process !== "undefined" && process.env?.SNOWCONE_SIGNER_URL || "https://s.snowcone.app/sign";
|
|
172
181
|
var RATE_LIMIT_PER_MINUTE = 450;
|
|
173
182
|
var RATE_LIMIT_PER_SECOND = 20;
|
|
174
183
|
var MockupServiceImpl = class {
|
|
@@ -176,11 +185,11 @@ var MockupServiceImpl = class {
|
|
|
176
185
|
cache;
|
|
177
186
|
rateLimitState;
|
|
178
187
|
fetch;
|
|
179
|
-
constructor(
|
|
188
|
+
constructor(config, customFetch) {
|
|
180
189
|
this.config = {
|
|
181
|
-
imageUrl:
|
|
182
|
-
signerUrl:
|
|
183
|
-
|
|
190
|
+
imageUrl: config.imageUrl || DEFAULT_IMAGE_URL,
|
|
191
|
+
signerUrl: config.signerUrl || DEFAULT_SIGNER_URL,
|
|
192
|
+
shop: config.shop || typeof process !== "undefined" && process.env?.SNOWCONE_SHOP_ID || ""
|
|
184
193
|
};
|
|
185
194
|
this.cache = new SignatureCache();
|
|
186
195
|
this.fetch = customFetch || fetch.bind(globalThis);
|
|
@@ -193,12 +202,21 @@ var MockupServiceImpl = class {
|
|
|
193
202
|
if (!options.design || !options.product) {
|
|
194
203
|
throw new Error("Missing required options: design and product are required");
|
|
195
204
|
}
|
|
196
|
-
if (!this.config.
|
|
197
|
-
throw new Error("
|
|
205
|
+
if (!this.config.shop) {
|
|
206
|
+
throw new Error("Shop ID is required for mockup generation");
|
|
207
|
+
}
|
|
208
|
+
for (const element of options.design) {
|
|
209
|
+
if (element.type === "image" && element.imageUrl) {
|
|
210
|
+
if (element.imageUrl.startsWith("blob:")) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`[snowcone-sdk] Cannot generate mockup: design element for placement "${element.placement}" uses a blob URL ("${element.imageUrl.slice(0, 60)}..."). Blob URLs are local to this browser tab and cannot be downloaded by the mockup rendering server. Upload the image to a publicly accessible URL or convert it to a data URL before requesting a mockup.`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
198
216
|
}
|
|
199
217
|
this.checkRateLimits();
|
|
200
218
|
const relativeUrl = this.buildMockupUrlWithParams(options);
|
|
201
|
-
const cacheKey = `${relativeUrl}:${this.config.
|
|
219
|
+
const cacheKey = `${relativeUrl}:${this.config.shop}`;
|
|
202
220
|
const cachedUrl = this.cache.get(cacheKey);
|
|
203
221
|
if (cachedUrl) {
|
|
204
222
|
return cachedUrl;
|
|
@@ -283,17 +301,12 @@ var MockupServiceImpl = class {
|
|
|
283
301
|
}
|
|
284
302
|
}
|
|
285
303
|
async getSignedUrl(relativeUrl) {
|
|
286
|
-
const urlWithAccountId = relativeUrl + (relativeUrl.includes("?") ? "&" : "?") + `
|
|
304
|
+
const urlWithAccountId = relativeUrl + (relativeUrl.includes("?") ? "&" : "?") + `shop=${encodeURIComponent(this.config.shop)}`;
|
|
287
305
|
const cacheKey = urlWithAccountId;
|
|
288
306
|
const cachedUrl = this.cache.get(cacheKey);
|
|
289
307
|
if (cachedUrl) {
|
|
290
308
|
return cachedUrl;
|
|
291
309
|
}
|
|
292
|
-
if (this.config.signerUrl?.includes("localhost") || this.config.signerUrl === "mock") {
|
|
293
|
-
const signedUrl = this.config.imageUrl + urlWithAccountId + "&sig=bypass-sig-for-k6-load-test";
|
|
294
|
-
this.cache.set(cacheKey, signedUrl);
|
|
295
|
-
return signedUrl;
|
|
296
|
-
}
|
|
297
310
|
const signerUrl = new URL(this.config.signerUrl);
|
|
298
311
|
signerUrl.searchParams.set("url", urlWithAccountId);
|
|
299
312
|
try {
|
|
@@ -340,6 +353,456 @@ var MockupServiceImpl = class {
|
|
|
340
353
|
}
|
|
341
354
|
};
|
|
342
355
|
|
|
356
|
+
// ../mockup-url/src/index.ts
|
|
357
|
+
var PARAMS = {
|
|
358
|
+
shop: "shop",
|
|
359
|
+
asset: "asset",
|
|
360
|
+
assets: "assets",
|
|
361
|
+
placement: "placement",
|
|
362
|
+
variant: "variant",
|
|
363
|
+
mockup: "mockup",
|
|
364
|
+
width: "width",
|
|
365
|
+
grain: "grain",
|
|
366
|
+
aspect: "aspect",
|
|
367
|
+
/** Live preview/calibration mask overrides (not cached). */
|
|
368
|
+
maskOverrides: "maskOverrides",
|
|
369
|
+
/**
|
|
370
|
+
* Render-only option picks (the `affectsCombinations:false` attributes), as a
|
|
371
|
+
* base64 JSON map `{ attributeName: choiceLabel }`. rendercenter already parses
|
|
372
|
+
* this and resolves per-choice underlays from it; the builder emits it so the
|
|
373
|
+
* edge resolver can forward render-only picks (e.g. a cap's Crown/Strap color)
|
|
374
|
+
* without changing rendercenter's grammar.
|
|
375
|
+
*/
|
|
376
|
+
optionSelections: "optionSelections",
|
|
377
|
+
signature: "signature",
|
|
378
|
+
seal: "seal"
|
|
379
|
+
};
|
|
380
|
+
function asSimpleAsset(design) {
|
|
381
|
+
if (design.length !== 1) return null;
|
|
382
|
+
const el = design[0];
|
|
383
|
+
if (el.type === "color" || el.hex) return null;
|
|
384
|
+
if (!el.imageUrl) return null;
|
|
385
|
+
if (el.position || el.size || el.tiles != null) return null;
|
|
386
|
+
if (el.alignment && el.alignment !== "center") return null;
|
|
387
|
+
return { imageUrl: el.imageUrl, placement: el.placement };
|
|
388
|
+
}
|
|
389
|
+
var ALLOWED_WIDTHS = [
|
|
390
|
+
400,
|
|
391
|
+
600,
|
|
392
|
+
800,
|
|
393
|
+
1e3,
|
|
394
|
+
1200,
|
|
395
|
+
1400,
|
|
396
|
+
1600,
|
|
397
|
+
1800,
|
|
398
|
+
2e3,
|
|
399
|
+
2500,
|
|
400
|
+
3e3,
|
|
401
|
+
4e3
|
|
402
|
+
];
|
|
403
|
+
function normalizeWidth(width) {
|
|
404
|
+
for (let i = ALLOWED_WIDTHS.length - 1; i >= 0; i--) {
|
|
405
|
+
if (ALLOWED_WIDTHS[i] <= width) return ALLOWED_WIDTHS[i];
|
|
406
|
+
}
|
|
407
|
+
return ALLOWED_WIDTHS[0];
|
|
408
|
+
}
|
|
409
|
+
function normalizeDesignElements(design) {
|
|
410
|
+
return design.map((element) => {
|
|
411
|
+
const normalized = {};
|
|
412
|
+
const keys = Object.keys(element).sort();
|
|
413
|
+
for (const key of keys) {
|
|
414
|
+
if (key === "width" || key === "height" || key === "type") continue;
|
|
415
|
+
if (key === "alignment" && element[key] === "center") {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
const value = element[key];
|
|
419
|
+
if (value !== void 0 && value !== null) normalized[key] = value;
|
|
420
|
+
}
|
|
421
|
+
return normalized;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
function buildMockupUrl(options, cfg) {
|
|
425
|
+
for (const element of options.design) {
|
|
426
|
+
if (element.type === "image" && element.imageUrl?.startsWith("blob:")) {
|
|
427
|
+
throw new Error(
|
|
428
|
+
`[snowcone] Cannot generate mockup: design element for placement "${element.placement}" uses a blob URL ("${element.imageUrl.slice(0, 60)}..."). Blob URLs are local to this browser tab and cannot be downloaded by the mockup rendering server. Upload the image to a publicly accessible URL or convert it to a data URL before requesting a mockup.`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const width = normalizeWidth(options.width);
|
|
433
|
+
const base = cfg.mockupBaseUrl.replace(/\/+$/, "");
|
|
434
|
+
const path = `/${encodeURIComponent(options.productId)}`;
|
|
435
|
+
let queryString = `${PARAMS.shop}=${encodeURIComponent(cfg.shop)}`;
|
|
436
|
+
const simple = asSimpleAsset(options.design);
|
|
437
|
+
if (simple) {
|
|
438
|
+
queryString += `&${PARAMS.asset}=${encodeURIComponent(simple.imageUrl)}`;
|
|
439
|
+
if (simple.placement) {
|
|
440
|
+
queryString += `&${PARAMS.placement}=${encodeURIComponent(simple.placement)}`;
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
const encodedAssets = encodeURIComponent(
|
|
444
|
+
btoa(JSON.stringify(normalizeDesignElements(options.design)))
|
|
445
|
+
);
|
|
446
|
+
queryString += `&${PARAMS.assets}=${encodedAssets}`;
|
|
447
|
+
}
|
|
448
|
+
queryString += `&${PARAMS.variant}=${encodeURIComponent(options.variantId)}`;
|
|
449
|
+
queryString += `&${PARAMS.mockup}=${encodeURIComponent(options.mockupId)}`;
|
|
450
|
+
queryString += `&${PARAMS.width}=${width}`;
|
|
451
|
+
if (options.optionSelections && Object.keys(options.optionSelections).length > 0) {
|
|
452
|
+
const sorted = {};
|
|
453
|
+
for (const k of Object.keys(options.optionSelections).sort()) {
|
|
454
|
+
sorted[k] = options.optionSelections[k];
|
|
455
|
+
}
|
|
456
|
+
const optionSelectionsBase64 = btoa(JSON.stringify(sorted));
|
|
457
|
+
queryString += `&${PARAMS.optionSelections}=${encodeURIComponent(
|
|
458
|
+
optionSelectionsBase64
|
|
459
|
+
)}`;
|
|
460
|
+
}
|
|
461
|
+
if (options.effects?.grain) {
|
|
462
|
+
queryString += `&${PARAMS.grain}=${options.effects.grain}`;
|
|
463
|
+
}
|
|
464
|
+
if (options.aspect && options.aspect !== "16:9") {
|
|
465
|
+
queryString += `&${PARAMS.aspect}=${encodeURIComponent(options.aspect)}`;
|
|
466
|
+
}
|
|
467
|
+
if (options.maskOverrides && options.maskOverrides.length > 0) {
|
|
468
|
+
const maskOverridesBase64 = btoa(JSON.stringify(options.maskOverrides));
|
|
469
|
+
queryString += `&${PARAMS.maskOverrides}=${encodeURIComponent(maskOverridesBase64)}`;
|
|
470
|
+
}
|
|
471
|
+
return `${base}${path}?${queryString}`;
|
|
472
|
+
}
|
|
473
|
+
var PARAM_PREFIX = {
|
|
474
|
+
asset: "asset.",
|
|
475
|
+
color: "color.",
|
|
476
|
+
tile: "tile.",
|
|
477
|
+
align: "align.",
|
|
478
|
+
opt: "opt."
|
|
479
|
+
};
|
|
480
|
+
var DEFAULT_PUBLIC_BASE_URL = "https://img.snowcone.app";
|
|
481
|
+
function buildPublicMockupUrl(options, cfg = {}) {
|
|
482
|
+
const base = (cfg.baseUrl ?? DEFAULT_PUBLIC_BASE_URL).replace(/\/+$/, "");
|
|
483
|
+
const path = `/${encodeURIComponent(options.productCode)}`;
|
|
484
|
+
const enc = encodeURIComponent;
|
|
485
|
+
const parts = [];
|
|
486
|
+
parts.push(`${PARAMS.shop}=${enc(options.shop)}`);
|
|
487
|
+
if (options.design) {
|
|
488
|
+
for (const key of Object.keys(options.design).sort()) {
|
|
489
|
+
const fill = options.design[key];
|
|
490
|
+
const k = enc(key);
|
|
491
|
+
if (typeof fill === "string") {
|
|
492
|
+
parts.push(`${PARAM_PREFIX.asset}${k}=${enc(fill)}`);
|
|
493
|
+
} else if ("color" in fill) {
|
|
494
|
+
parts.push(`${PARAM_PREFIX.color}${k}=${enc(fill.color)}`);
|
|
495
|
+
} else {
|
|
496
|
+
parts.push(`${PARAM_PREFIX.asset}${k}=${enc(fill.src)}`);
|
|
497
|
+
if (fill.tile !== void 0) {
|
|
498
|
+
parts.push(`${PARAM_PREFIX.tile}${k}=${fill.tile}`);
|
|
499
|
+
}
|
|
500
|
+
if (fill.align !== void 0) {
|
|
501
|
+
parts.push(`${PARAM_PREFIX.align}${k}=${enc(fill.align)}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
} else if (options.assetUrl !== void 0) {
|
|
506
|
+
parts.push(`${PARAMS.asset}=${enc(options.assetUrl)}`);
|
|
507
|
+
}
|
|
508
|
+
if (options.placement !== void 0) {
|
|
509
|
+
parts.push(`${PARAMS.placement}=${enc(options.placement)}`);
|
|
510
|
+
}
|
|
511
|
+
if (options.options) {
|
|
512
|
+
for (const attr of Object.keys(options.options).sort()) {
|
|
513
|
+
parts.push(`${PARAM_PREFIX.opt}${enc(attr)}=${enc(options.options[attr])}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (options.variant !== void 0) {
|
|
517
|
+
parts.push(`${PARAMS.variant}=${enc(options.variant)}`);
|
|
518
|
+
}
|
|
519
|
+
if (options.mockup !== void 0) {
|
|
520
|
+
parts.push(`${PARAMS.mockup}=${enc(options.mockup)}`);
|
|
521
|
+
}
|
|
522
|
+
if (options.width !== void 0) parts.push(`${PARAMS.width}=${options.width}`);
|
|
523
|
+
if (options.aspect !== void 0 && options.aspect !== "16:9") {
|
|
524
|
+
parts.push(`${PARAMS.aspect}=${enc(options.aspect)}`);
|
|
525
|
+
}
|
|
526
|
+
return `${base}${path}?${parts.join("&")}`;
|
|
527
|
+
}
|
|
528
|
+
function canonicalForSig(url) {
|
|
529
|
+
const hashIdx = url.indexOf("#");
|
|
530
|
+
const noHash = hashIdx === -1 ? url : url.slice(0, hashIdx);
|
|
531
|
+
const qIdx = noHash.indexOf("?");
|
|
532
|
+
const beforeQuery = qIdx === -1 ? noHash : noHash.slice(0, qIdx);
|
|
533
|
+
const rawQuery = qIdx === -1 ? "" : noHash.slice(qIdx + 1);
|
|
534
|
+
let pathname;
|
|
535
|
+
const schemeMatch = beforeQuery.match(/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//);
|
|
536
|
+
if (schemeMatch) {
|
|
537
|
+
const afterScheme = beforeQuery.slice(schemeMatch[0].length);
|
|
538
|
+
const slashIdx = afterScheme.indexOf("/");
|
|
539
|
+
pathname = slashIdx === -1 ? "/" : afterScheme.slice(slashIdx);
|
|
540
|
+
} else {
|
|
541
|
+
pathname = beforeQuery;
|
|
542
|
+
}
|
|
543
|
+
const pairs = [];
|
|
544
|
+
if (rawQuery.length > 0) {
|
|
545
|
+
for (const segment of rawQuery.split("&")) {
|
|
546
|
+
if (segment.length === 0) continue;
|
|
547
|
+
const eq = segment.indexOf("=");
|
|
548
|
+
const rawKey = eq === -1 ? segment : segment.slice(0, eq);
|
|
549
|
+
const rawValue = eq === -1 ? "" : segment.slice(eq + 1);
|
|
550
|
+
const key = decodeURIComponent(rawKey);
|
|
551
|
+
if (key === "signature") continue;
|
|
552
|
+
pairs.push({ key, raw: rawValue });
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
pairs.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
556
|
+
const canonicalQuery = pairs.map((p) => `${p.key}=${p.raw}`).join("&");
|
|
557
|
+
return `${pathname}?${canonicalQuery}`;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/mockup/hmac.ts
|
|
561
|
+
var K = new Uint32Array([
|
|
562
|
+
1116352408,
|
|
563
|
+
1899447441,
|
|
564
|
+
3049323471,
|
|
565
|
+
3921009573,
|
|
566
|
+
961987163,
|
|
567
|
+
1508970993,
|
|
568
|
+
2453635748,
|
|
569
|
+
2870763221,
|
|
570
|
+
3624381080,
|
|
571
|
+
310598401,
|
|
572
|
+
607225278,
|
|
573
|
+
1426881987,
|
|
574
|
+
1925078388,
|
|
575
|
+
2162078206,
|
|
576
|
+
2614888103,
|
|
577
|
+
3248222580,
|
|
578
|
+
3835390401,
|
|
579
|
+
4022224774,
|
|
580
|
+
264347078,
|
|
581
|
+
604807628,
|
|
582
|
+
770255983,
|
|
583
|
+
1249150122,
|
|
584
|
+
1555081692,
|
|
585
|
+
1996064986,
|
|
586
|
+
2554220882,
|
|
587
|
+
2821834349,
|
|
588
|
+
2952996808,
|
|
589
|
+
3210313671,
|
|
590
|
+
3336571891,
|
|
591
|
+
3584528711,
|
|
592
|
+
113926993,
|
|
593
|
+
338241895,
|
|
594
|
+
666307205,
|
|
595
|
+
773529912,
|
|
596
|
+
1294757372,
|
|
597
|
+
1396182291,
|
|
598
|
+
1695183700,
|
|
599
|
+
1986661051,
|
|
600
|
+
2177026350,
|
|
601
|
+
2456956037,
|
|
602
|
+
2730485921,
|
|
603
|
+
2820302411,
|
|
604
|
+
3259730800,
|
|
605
|
+
3345764771,
|
|
606
|
+
3516065817,
|
|
607
|
+
3600352804,
|
|
608
|
+
4094571909,
|
|
609
|
+
275423344,
|
|
610
|
+
430227734,
|
|
611
|
+
506948616,
|
|
612
|
+
659060556,
|
|
613
|
+
883997877,
|
|
614
|
+
958139571,
|
|
615
|
+
1322822218,
|
|
616
|
+
1537002063,
|
|
617
|
+
1747873779,
|
|
618
|
+
1955562222,
|
|
619
|
+
2024104815,
|
|
620
|
+
2227730452,
|
|
621
|
+
2361852424,
|
|
622
|
+
2428436474,
|
|
623
|
+
2756734187,
|
|
624
|
+
3204031479,
|
|
625
|
+
3329325298
|
|
626
|
+
]);
|
|
627
|
+
function rotr(x, n) {
|
|
628
|
+
return x >>> n | x << 32 - n;
|
|
629
|
+
}
|
|
630
|
+
function sha256(bytes) {
|
|
631
|
+
const h = new Uint32Array([
|
|
632
|
+
1779033703,
|
|
633
|
+
3144134277,
|
|
634
|
+
1013904242,
|
|
635
|
+
2773480762,
|
|
636
|
+
1359893119,
|
|
637
|
+
2600822924,
|
|
638
|
+
528734635,
|
|
639
|
+
1541459225
|
|
640
|
+
]);
|
|
641
|
+
const bitLen = bytes.length * 8;
|
|
642
|
+
const withOne = bytes.length + 1;
|
|
643
|
+
const total = withOne + (56 - withOne % 64 + 64) % 64 + 8;
|
|
644
|
+
const msg = new Uint8Array(total);
|
|
645
|
+
msg.set(bytes);
|
|
646
|
+
msg[bytes.length] = 128;
|
|
647
|
+
const hi = Math.floor(bitLen / 4294967296);
|
|
648
|
+
const lo = bitLen >>> 0;
|
|
649
|
+
msg[total - 8] = hi >>> 24 & 255;
|
|
650
|
+
msg[total - 7] = hi >>> 16 & 255;
|
|
651
|
+
msg[total - 6] = hi >>> 8 & 255;
|
|
652
|
+
msg[total - 5] = hi & 255;
|
|
653
|
+
msg[total - 4] = lo >>> 24 & 255;
|
|
654
|
+
msg[total - 3] = lo >>> 16 & 255;
|
|
655
|
+
msg[total - 2] = lo >>> 8 & 255;
|
|
656
|
+
msg[total - 1] = lo & 255;
|
|
657
|
+
const w = new Uint32Array(64);
|
|
658
|
+
for (let off = 0; off < total; off += 64) {
|
|
659
|
+
for (let i = 0; i < 16; i++) {
|
|
660
|
+
const j = off + i * 4;
|
|
661
|
+
w[i] = (msg[j] << 24 | msg[j + 1] << 16 | msg[j + 2] << 8 | msg[j + 3]) >>> 0;
|
|
662
|
+
}
|
|
663
|
+
for (let i = 16; i < 64; i++) {
|
|
664
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ w[i - 15] >>> 3;
|
|
665
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ w[i - 2] >>> 10;
|
|
666
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
|
|
667
|
+
}
|
|
668
|
+
let a = h[0];
|
|
669
|
+
let b = h[1];
|
|
670
|
+
let c = h[2];
|
|
671
|
+
let d = h[3];
|
|
672
|
+
let e = h[4];
|
|
673
|
+
let f = h[5];
|
|
674
|
+
let g = h[6];
|
|
675
|
+
let hh = h[7];
|
|
676
|
+
for (let i = 0; i < 64; i++) {
|
|
677
|
+
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
678
|
+
const ch = e & f ^ ~e & g;
|
|
679
|
+
const t1 = hh + S1 + ch + K[i] + w[i] >>> 0;
|
|
680
|
+
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
681
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
682
|
+
const t2 = S0 + maj >>> 0;
|
|
683
|
+
hh = g;
|
|
684
|
+
g = f;
|
|
685
|
+
f = e;
|
|
686
|
+
e = d + t1 >>> 0;
|
|
687
|
+
d = c;
|
|
688
|
+
c = b;
|
|
689
|
+
b = a;
|
|
690
|
+
a = t1 + t2 >>> 0;
|
|
691
|
+
}
|
|
692
|
+
h[0] = h[0] + a >>> 0;
|
|
693
|
+
h[1] = h[1] + b >>> 0;
|
|
694
|
+
h[2] = h[2] + c >>> 0;
|
|
695
|
+
h[3] = h[3] + d >>> 0;
|
|
696
|
+
h[4] = h[4] + e >>> 0;
|
|
697
|
+
h[5] = h[5] + f >>> 0;
|
|
698
|
+
h[6] = h[6] + g >>> 0;
|
|
699
|
+
h[7] = h[7] + hh >>> 0;
|
|
700
|
+
}
|
|
701
|
+
const out = new Uint8Array(32);
|
|
702
|
+
for (let i = 0; i < 8; i++) {
|
|
703
|
+
out[i * 4] = h[i] >>> 24 & 255;
|
|
704
|
+
out[i * 4 + 1] = h[i] >>> 16 & 255;
|
|
705
|
+
out[i * 4 + 2] = h[i] >>> 8 & 255;
|
|
706
|
+
out[i * 4 + 3] = h[i] & 255;
|
|
707
|
+
}
|
|
708
|
+
return out;
|
|
709
|
+
}
|
|
710
|
+
function utf8(str) {
|
|
711
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(str);
|
|
712
|
+
const bytes = [];
|
|
713
|
+
for (let i = 0; i < str.length; i++) {
|
|
714
|
+
let c = str.charCodeAt(i);
|
|
715
|
+
if (c < 128) bytes.push(c);
|
|
716
|
+
else if (c < 2048) {
|
|
717
|
+
bytes.push(192 | c >> 6, 128 | c & 63);
|
|
718
|
+
} else if (c >= 55296 && c <= 56319) {
|
|
719
|
+
const c2 = str.charCodeAt(++i);
|
|
720
|
+
c = 65536 + ((c & 1023) << 10) + (c2 & 1023);
|
|
721
|
+
bytes.push(
|
|
722
|
+
240 | c >> 18,
|
|
723
|
+
128 | c >> 12 & 63,
|
|
724
|
+
128 | c >> 6 & 63,
|
|
725
|
+
128 | c & 63
|
|
726
|
+
);
|
|
727
|
+
} else {
|
|
728
|
+
bytes.push(
|
|
729
|
+
224 | c >> 12,
|
|
730
|
+
128 | c >> 6 & 63,
|
|
731
|
+
128 | c & 63
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return new Uint8Array(bytes);
|
|
736
|
+
}
|
|
737
|
+
function toHex(bytes) {
|
|
738
|
+
let hex = "";
|
|
739
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
740
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
741
|
+
}
|
|
742
|
+
return hex;
|
|
743
|
+
}
|
|
744
|
+
function hmacSha256Hex(secret, message) {
|
|
745
|
+
const blockSize = 64;
|
|
746
|
+
let key = utf8(secret);
|
|
747
|
+
if (key.length > blockSize) key = sha256(key);
|
|
748
|
+
if (key.length < blockSize) {
|
|
749
|
+
const padded = new Uint8Array(blockSize);
|
|
750
|
+
padded.set(key);
|
|
751
|
+
key = padded;
|
|
752
|
+
}
|
|
753
|
+
const oKeyPad = new Uint8Array(blockSize);
|
|
754
|
+
const iKeyPad = new Uint8Array(blockSize);
|
|
755
|
+
for (let i = 0; i < blockSize; i++) {
|
|
756
|
+
oKeyPad[i] = key[i] ^ 92;
|
|
757
|
+
iKeyPad[i] = key[i] ^ 54;
|
|
758
|
+
}
|
|
759
|
+
const msg = utf8(message);
|
|
760
|
+
const inner = new Uint8Array(blockSize + msg.length);
|
|
761
|
+
inner.set(iKeyPad);
|
|
762
|
+
inner.set(msg, blockSize);
|
|
763
|
+
const innerHash = sha256(inner);
|
|
764
|
+
const outer = new Uint8Array(blockSize + innerHash.length);
|
|
765
|
+
outer.set(oKeyPad);
|
|
766
|
+
outer.set(innerHash, blockSize);
|
|
767
|
+
return toHex(sha256(outer));
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/mockup/getMockupUrl.ts
|
|
771
|
+
var DEFAULT_MOCKUP_BASE = "https://img.snowcone.app";
|
|
772
|
+
function getMockupUrl(a, b, c) {
|
|
773
|
+
let productCode;
|
|
774
|
+
let opts;
|
|
775
|
+
let legacyAsset;
|
|
776
|
+
if (typeof b === "string") {
|
|
777
|
+
legacyAsset = a;
|
|
778
|
+
productCode = b;
|
|
779
|
+
opts = c ?? {};
|
|
780
|
+
} else {
|
|
781
|
+
productCode = a;
|
|
782
|
+
opts = b;
|
|
783
|
+
}
|
|
784
|
+
const base = (opts.base ?? DEFAULT_MOCKUP_BASE).replace(/\/+$/, "");
|
|
785
|
+
const assetUrl = opts.asset ?? legacyAsset;
|
|
786
|
+
const url = buildPublicMockupUrl(
|
|
787
|
+
{
|
|
788
|
+
productCode,
|
|
789
|
+
shop: opts.shop,
|
|
790
|
+
...opts.design ? { design: opts.design } : {},
|
|
791
|
+
...assetUrl !== void 0 ? { assetUrl } : {},
|
|
792
|
+
...opts.options ? { options: opts.options } : {},
|
|
793
|
+
...opts.width !== void 0 ? { width: opts.width } : {},
|
|
794
|
+
...opts.aspect !== void 0 ? { aspect: opts.aspect } : {},
|
|
795
|
+
...opts.mockup ?? opts.view ? { mockup: opts.mockup ?? opts.view } : {},
|
|
796
|
+
...opts.variant !== void 0 ? { variant: opts.variant } : {},
|
|
797
|
+
...opts.placement !== void 0 ? { placement: opts.placement } : {}
|
|
798
|
+
},
|
|
799
|
+
{ baseUrl: base }
|
|
800
|
+
);
|
|
801
|
+
if (!opts.secret) return url;
|
|
802
|
+
const signature = hmacSha256Hex(opts.secret, canonicalForSig(url)).slice(0, 16);
|
|
803
|
+
return `${url}&signature=${signature}`;
|
|
804
|
+
}
|
|
805
|
+
|
|
343
806
|
// src/state/optionSelection.ts
|
|
344
807
|
function resolveBestCombination(selection, attributes, combinations) {
|
|
345
808
|
const relevant = Object.fromEntries(
|
|
@@ -1010,7 +1473,7 @@ function resolveUrlFromDOM(relativeUrl) {
|
|
|
1010
1473
|
const filename = pathParts[pathParts.length - 1];
|
|
1011
1474
|
if (!filename) return null;
|
|
1012
1475
|
const filenameWithoutExt = filename.replace(/\.[^.]+$/, "");
|
|
1013
|
-
const images = document.querySelectorAll("img");
|
|
1476
|
+
const images = Array.from(document.querySelectorAll("img"));
|
|
1014
1477
|
for (const img of images) {
|
|
1015
1478
|
const src = img.getAttribute("src");
|
|
1016
1479
|
if (!src) continue;
|
|
@@ -1022,6 +1485,9 @@ function resolveUrlFromDOM(relativeUrl) {
|
|
|
1022
1485
|
}
|
|
1023
1486
|
function normalizeImageUrl(url) {
|
|
1024
1487
|
if (!url) return null;
|
|
1488
|
+
if (url.startsWith("blob:")) {
|
|
1489
|
+
return null;
|
|
1490
|
+
}
|
|
1025
1491
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1026
1492
|
return url;
|
|
1027
1493
|
}
|
|
@@ -1040,18 +1506,18 @@ function normalizeImageUrl(url) {
|
|
|
1040
1506
|
const absoluteUrl = new URL(url, window.location.origin).href;
|
|
1041
1507
|
if (absoluteUrl.includes("localhost") || absoluteUrl.includes("127.0.0.1")) {
|
|
1042
1508
|
console.warn(
|
|
1043
|
-
`[
|
|
1509
|
+
`[snowcone-sdk] Artwork URL "${absoluteUrl}" uses localhost. This will work in your browser but won't work for mockup generation. Deploy your app or use publicly accessible URLs for production mockups.`
|
|
1044
1510
|
);
|
|
1045
1511
|
}
|
|
1046
1512
|
return absoluteUrl;
|
|
1047
1513
|
} catch (e) {
|
|
1048
|
-
console.warn(`[
|
|
1514
|
+
console.warn(`[snowcone-sdk] Failed to normalize URL "${url}":`, e);
|
|
1049
1515
|
return url;
|
|
1050
1516
|
}
|
|
1051
1517
|
}
|
|
1052
1518
|
if (url.startsWith("/") || url.startsWith(".")) {
|
|
1053
1519
|
console.warn(
|
|
1054
|
-
`[
|
|
1520
|
+
`[snowcone-sdk] Relative URL "${url}" detected during SSR. URL will be resolved on the client. Consider using absolute URLs for SSR compatibility.`
|
|
1055
1521
|
);
|
|
1056
1522
|
}
|
|
1057
1523
|
return url;
|
|
@@ -1154,95 +1620,39 @@ function filterImagePlacements(placements) {
|
|
|
1154
1620
|
}
|
|
1155
1621
|
|
|
1156
1622
|
// src/mockup/urlGenerator.ts
|
|
1157
|
-
var
|
|
1158
|
-
function
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
const envImageUrl = env?.MERCHIFY_IMAGE_URL || env?.NEXT_PUBLIC_MERCH_MOCKUP_URL;
|
|
1165
|
-
const envSignerUrl = env?.MERCHIFY_SIGNER_URL || env?.NEXT_PUBLIC_MERCH_SIGNER_URL;
|
|
1166
|
-
const envAccountId = env?.MERCHIFY_ACCOUNT_ID || env?.NEXT_PUBLIC_MERCH_ACCOUNT_ID;
|
|
1167
|
-
return {
|
|
1168
|
-
endpoint: winConfig.endpoint || envEndpoint || void 0,
|
|
1169
|
-
mockupUrl: winConfig.mockupUrl || envImageUrl || DEFAULT_MOCKUP_URL,
|
|
1170
|
-
signerUrl: winConfig.signerUrl || envSignerUrl || void 0,
|
|
1171
|
-
accountId: winConfig.accountId || envAccountId || DEFAULT_ACCOUNT_ID,
|
|
1172
|
-
mode: winConfig.mode || "mock"
|
|
1173
|
-
};
|
|
1623
|
+
var maxWidthCache = /* @__PURE__ */ new Map();
|
|
1624
|
+
function buildMockupUrl2(options, cfg) {
|
|
1625
|
+
const { ar, ...rest } = options;
|
|
1626
|
+
return buildMockupUrl(
|
|
1627
|
+
{ ...rest, aspect: ar },
|
|
1628
|
+
{ mockupBaseUrl: cfg.mockupBaseUrl, shop: cfg.shop }
|
|
1629
|
+
);
|
|
1174
1630
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
cachedMockupConfig = { ...base, ...overrides };
|
|
1180
|
-
} else if (!cachedMockupConfig) {
|
|
1181
|
-
cachedMockupConfig = resolveDefaultConfig();
|
|
1182
|
-
}
|
|
1183
|
-
const hostname = typeof window !== "undefined" ? window.location.hostname : "";
|
|
1184
|
-
const isLocalDev = hostname === "localhost" || hostname === "127.0.0.1" || hostname.includes("192.168.") || hostname.endsWith(".local") || hostname.endsWith(".lvh.me") || hostname === "lvh.me";
|
|
1185
|
-
if (!localhostWarningShown && typeof window !== "undefined" && !isLocalDev && cachedMockupConfig?.mockupUrl?.includes("localhost")) {
|
|
1186
|
-
console.error(
|
|
1187
|
-
`[@snowcone-app/sdk] WARNING: Using localhost mockup URL in production environment.
|
|
1188
|
-
mockupUrl: ${cachedMockupConfig.mockupUrl}
|
|
1189
|
-
This was likely caused by building with .env.local present.
|
|
1190
|
-
Redeploy with "pnpm run deploy" to fix.`
|
|
1191
|
-
);
|
|
1192
|
-
localhostWarningShown = true;
|
|
1193
|
-
}
|
|
1194
|
-
return cachedMockupConfig;
|
|
1631
|
+
function resolveMockupBaseUrl() {
|
|
1632
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
1633
|
+
const winConfig = typeof window !== "undefined" && window.snowcone || {};
|
|
1634
|
+
return winConfig.mockupUrl || env?.SNOWCONE_IMAGE_URL || env?.NEXT_PUBLIC_MERCH_MOCKUP_URL || "https://cdn.snowcone.app";
|
|
1195
1635
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
const keys = Object.keys(element).sort();
|
|
1201
|
-
for (const key of keys) {
|
|
1202
|
-
if (key === "width" || key === "height" || key === "type") {
|
|
1203
|
-
continue;
|
|
1204
|
-
}
|
|
1205
|
-
if (key === "alignment" && element[key] === "center") {
|
|
1206
|
-
continue;
|
|
1207
|
-
}
|
|
1208
|
-
const value = element[key];
|
|
1209
|
-
if (value !== void 0 && value !== null) {
|
|
1210
|
-
normalized[key] = value;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
return normalized;
|
|
1214
|
-
});
|
|
1636
|
+
function resolveShop() {
|
|
1637
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
1638
|
+
const winConfig = typeof window !== "undefined" && window.snowcone || {};
|
|
1639
|
+
return winConfig.shop || env?.SNOWCONE_SHOP_ID || env?.NEXT_PUBLIC_SNOWCONE_SHOP_ID || "SHOP_NOT_CONFIGURED";
|
|
1215
1640
|
}
|
|
1216
1641
|
function mockupUrl(options) {
|
|
1217
|
-
const
|
|
1218
|
-
const
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
queryString += `&width=${options.width}`;
|
|
1228
|
-
queryString += `&accountId=${encodeURIComponent(accountId)}`;
|
|
1229
|
-
if (options.effects?.grain) {
|
|
1230
|
-
queryString += `&grain=${options.effects.grain}`;
|
|
1231
|
-
}
|
|
1232
|
-
if (options.ar && options.ar !== "16:9") {
|
|
1233
|
-
queryString += `&ar=${encodeURIComponent(options.ar)}`;
|
|
1234
|
-
}
|
|
1235
|
-
if (options.maskOverrides && options.maskOverrides.length > 0) {
|
|
1236
|
-
const maskOverridesBase64 = btoa(JSON.stringify(options.maskOverrides));
|
|
1237
|
-
queryString += `&maskOverrides=${encodeURIComponent(maskOverridesBase64)}`;
|
|
1238
|
-
}
|
|
1239
|
-
if (mockupConfig.mode === "mock") {
|
|
1240
|
-
const mockSignature = "bypass-sig-for-k6-load-test";
|
|
1241
|
-
queryString += `&sig=${encodeURIComponent(mockSignature)}`;
|
|
1642
|
+
const mockupBaseUrl = resolveMockupBaseUrl();
|
|
1643
|
+
const shop = resolveShop();
|
|
1644
|
+
const encodedDesign = encodeURIComponent(
|
|
1645
|
+
btoa(JSON.stringify(normalizeDesignElements(options.design)))
|
|
1646
|
+
);
|
|
1647
|
+
let width = normalizeWidth(options.width);
|
|
1648
|
+
const cacheKey = `${options.productId}:${options.mockupId}:${options.variantId}:${encodedDesign}`;
|
|
1649
|
+
const cachedWidth = maxWidthCache.get(cacheKey);
|
|
1650
|
+
if (cachedWidth !== void 0 && cachedWidth >= width) {
|
|
1651
|
+
width = cachedWidth;
|
|
1242
1652
|
} else {
|
|
1243
|
-
|
|
1653
|
+
maxWidthCache.set(cacheKey, width);
|
|
1244
1654
|
}
|
|
1245
|
-
return
|
|
1655
|
+
return buildMockupUrl2({ ...options, width }, { mockupBaseUrl, shop });
|
|
1246
1656
|
}
|
|
1247
1657
|
function getVariant(selection, product) {
|
|
1248
1658
|
const combination = findBestCombination(
|
|
@@ -1408,6 +1818,12 @@ function validateImageUrl(url) {
|
|
|
1408
1818
|
message: "Image URL is required",
|
|
1409
1819
|
value: url
|
|
1410
1820
|
});
|
|
1821
|
+
} else if (url.startsWith("blob:")) {
|
|
1822
|
+
errors.push({
|
|
1823
|
+
field: "imageUrl",
|
|
1824
|
+
message: "Blob URLs (blob:...) cannot be used for mockup generation \u2014 they are local to the browser and not accessible by the rendering server. Upload the image to a public URL first, or export the canvas to a data URL.",
|
|
1825
|
+
value: url
|
|
1826
|
+
});
|
|
1411
1827
|
} else if (
|
|
1412
1828
|
// Allow absolute URLs
|
|
1413
1829
|
!url.startsWith("http://") && !url.startsWith("https://") && // Allow data URLs
|
|
@@ -2406,11 +2822,11 @@ var UniversalContextProvider = class extends EventEmitter {
|
|
|
2406
2822
|
config;
|
|
2407
2823
|
consumers = /* @__PURE__ */ new Set();
|
|
2408
2824
|
initialized = false;
|
|
2409
|
-
constructor(
|
|
2825
|
+
constructor(config = {}) {
|
|
2410
2826
|
super();
|
|
2411
|
-
this.config =
|
|
2827
|
+
this.config = config;
|
|
2412
2828
|
this.contextManager = new ProductContextManager();
|
|
2413
|
-
this.loader = new ProductLoader(this.contextManager,
|
|
2829
|
+
this.loader = new ProductLoader(this.contextManager, config.fetcher);
|
|
2414
2830
|
this.setupSubscriptions();
|
|
2415
2831
|
}
|
|
2416
2832
|
/**
|
|
@@ -2528,7 +2944,7 @@ var ContextInjector = class {
|
|
|
2528
2944
|
static forVue(provider) {
|
|
2529
2945
|
return {
|
|
2530
2946
|
install(app) {
|
|
2531
|
-
app.provide("
|
|
2947
|
+
app.provide("snowconeContext", provider);
|
|
2532
2948
|
},
|
|
2533
2949
|
inject() {
|
|
2534
2950
|
return provider;
|
|
@@ -2556,7 +2972,7 @@ var ContextInjector = class {
|
|
|
2556
2972
|
// Attach to element
|
|
2557
2973
|
attach(element) {
|
|
2558
2974
|
element.__contextProvider = provider;
|
|
2559
|
-
element.addEventListener("
|
|
2975
|
+
element.addEventListener("snowcone:request-context", (event) => {
|
|
2560
2976
|
event.detail.context = provider.getContext();
|
|
2561
2977
|
});
|
|
2562
2978
|
},
|
|
@@ -2574,8 +2990,8 @@ var ContextInjector = class {
|
|
|
2574
2990
|
};
|
|
2575
2991
|
}
|
|
2576
2992
|
};
|
|
2577
|
-
function createUniversalProvider(
|
|
2578
|
-
return new UniversalContextProvider(
|
|
2993
|
+
function createUniversalProvider(config) {
|
|
2994
|
+
return new UniversalContextProvider(config);
|
|
2579
2995
|
}
|
|
2580
2996
|
function withContext(Base) {
|
|
2581
2997
|
return class extends Base {
|
|
@@ -3580,8 +3996,8 @@ var StandardComponents = {
|
|
|
3580
3996
|
Product: {
|
|
3581
3997
|
metadata: {
|
|
3582
3998
|
name: "Product",
|
|
3583
|
-
tagName: "
|
|
3584
|
-
displayName: "
|
|
3999
|
+
tagName: "snowcone-product",
|
|
4000
|
+
displayName: "SnowconeProduct",
|
|
3585
4001
|
description: "Product context provider component",
|
|
3586
4002
|
props: {
|
|
3587
4003
|
productId: { type: "string" },
|
|
@@ -3607,8 +4023,8 @@ var StandardComponents = {
|
|
|
3607
4023
|
ProductOptions: {
|
|
3608
4024
|
metadata: {
|
|
3609
4025
|
name: "ProductOptions",
|
|
3610
|
-
tagName: "
|
|
3611
|
-
displayName: "
|
|
4026
|
+
tagName: "snowcone-product-options",
|
|
4027
|
+
displayName: "SnowconeProductOptions",
|
|
3612
4028
|
description: "Product options selection component",
|
|
3613
4029
|
props: {
|
|
3614
4030
|
attributes: { type: "object" },
|
|
@@ -3628,8 +4044,8 @@ var StandardComponents = {
|
|
|
3628
4044
|
ProductPrice: {
|
|
3629
4045
|
metadata: {
|
|
3630
4046
|
name: "ProductPrice",
|
|
3631
|
-
tagName: "
|
|
3632
|
-
displayName: "
|
|
4047
|
+
tagName: "snowcone-product-price",
|
|
4048
|
+
displayName: "SnowconeProductPrice",
|
|
3633
4049
|
description: "Product price display component",
|
|
3634
4050
|
props: {
|
|
3635
4051
|
price: { type: "number" },
|
|
@@ -3645,8 +4061,8 @@ var StandardComponents = {
|
|
|
3645
4061
|
ProductImage: {
|
|
3646
4062
|
metadata: {
|
|
3647
4063
|
name: "ProductImage",
|
|
3648
|
-
tagName: "
|
|
3649
|
-
displayName: "
|
|
4064
|
+
tagName: "snowcone-product-image",
|
|
4065
|
+
displayName: "SnowconeProductImage",
|
|
3650
4066
|
description: "Product mockup image component",
|
|
3651
4067
|
props: {
|
|
3652
4068
|
productId: { type: "string" },
|
|
@@ -3665,8 +4081,8 @@ var StandardComponents = {
|
|
|
3665
4081
|
AddToCart: {
|
|
3666
4082
|
metadata: {
|
|
3667
4083
|
name: "AddToCart",
|
|
3668
|
-
tagName: "
|
|
3669
|
-
displayName: "
|
|
4084
|
+
tagName: "snowcone-add-to-cart",
|
|
4085
|
+
displayName: "SnowconeAddToCart",
|
|
3670
4086
|
description: "Add to cart button component",
|
|
3671
4087
|
props: {
|
|
3672
4088
|
text: { type: "string", default: "Add to Cart" },
|
|
@@ -4233,8 +4649,8 @@ function createSvelteComponent(descriptor, svelte) {
|
|
|
4233
4649
|
}
|
|
4234
4650
|
|
|
4235
4651
|
// src/index.ts
|
|
4236
|
-
function getFetcher(
|
|
4237
|
-
return
|
|
4652
|
+
function getFetcher(config) {
|
|
4653
|
+
return config?.fetcher || globalThis.fetch.bind(globalThis);
|
|
4238
4654
|
}
|
|
4239
4655
|
function validateProductLoose(product) {
|
|
4240
4656
|
try {
|
|
@@ -4243,11 +4659,11 @@ function validateProductLoose(product) {
|
|
|
4243
4659
|
return product;
|
|
4244
4660
|
}
|
|
4245
4661
|
}
|
|
4246
|
-
async function listProducts(
|
|
4247
|
-
const f = getFetcher(
|
|
4248
|
-
const meilisearchHost =
|
|
4249
|
-
const meilisearchApiKey =
|
|
4250
|
-
const meilisearchIndex =
|
|
4662
|
+
async function listProducts(config) {
|
|
4663
|
+
const f = getFetcher(config);
|
|
4664
|
+
const meilisearchHost = config?.meilisearch?.host || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_HOST || "https://search.snowcone.app";
|
|
4665
|
+
const meilisearchApiKey = config?.meilisearch?.apiKey || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_API_KEY || "eee819b849798ad9091228c486ec05d0931e5292";
|
|
4666
|
+
const meilisearchIndex = config?.meilisearch?.index || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_INDEX || "snowcone";
|
|
4251
4667
|
const headers = {
|
|
4252
4668
|
"Content-Type": "application/json"
|
|
4253
4669
|
};
|
|
@@ -4260,7 +4676,7 @@ async function listProducts(config2) {
|
|
|
4260
4676
|
headers,
|
|
4261
4677
|
body: JSON.stringify({
|
|
4262
4678
|
q: "",
|
|
4263
|
-
limit:
|
|
4679
|
+
limit: config?.limit || 1e3,
|
|
4264
4680
|
filter: "mockups IS NOT EMPTY"
|
|
4265
4681
|
})
|
|
4266
4682
|
});
|
|
@@ -4269,11 +4685,11 @@ async function listProducts(config2) {
|
|
|
4269
4685
|
const items = (data.hits || []).map((p) => validateProductLoose(p));
|
|
4270
4686
|
return { items, total: data.estimatedTotalHits || items.length };
|
|
4271
4687
|
}
|
|
4272
|
-
async function getProduct(idOrSlug,
|
|
4273
|
-
const f = getFetcher(
|
|
4274
|
-
const meilisearchHost =
|
|
4275
|
-
const meilisearchApiKey =
|
|
4276
|
-
const meilisearchIndex =
|
|
4688
|
+
async function getProduct(idOrSlug, config) {
|
|
4689
|
+
const f = getFetcher(config);
|
|
4690
|
+
const meilisearchHost = config?.meilisearch?.host || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_HOST || "https://search.snowcone.app";
|
|
4691
|
+
const meilisearchApiKey = config?.meilisearch?.apiKey || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_API_KEY || "eee819b849798ad9091228c486ec05d0931e5292";
|
|
4692
|
+
const meilisearchIndex = config?.meilisearch?.index || typeof process !== "undefined" && process.env?.NEXT_PUBLIC_MEILISEARCH_INDEX || "snowcone";
|
|
4277
4693
|
const headers = {
|
|
4278
4694
|
"Content-Type": "application/json"
|
|
4279
4695
|
};
|
|
@@ -4288,13 +4704,13 @@ async function getProduct(idOrSlug, config2) {
|
|
|
4288
4704
|
const raw = await res.json();
|
|
4289
4705
|
return validateProductLoose(raw);
|
|
4290
4706
|
}
|
|
4291
|
-
function createClient(
|
|
4292
|
-
const fetcher = getFetcher(
|
|
4293
|
-
const mockupService = new MockupServiceImpl(
|
|
4707
|
+
function createClient(config) {
|
|
4708
|
+
const fetcher = getFetcher(config);
|
|
4709
|
+
const mockupService = new MockupServiceImpl(config.mockup || {}, fetcher);
|
|
4294
4710
|
return {
|
|
4295
4711
|
catalog: {
|
|
4296
|
-
listProducts: (overrides) => listProducts({ ...
|
|
4297
|
-
getProduct: (idOrSlug, overrides) => getProduct(idOrSlug, { ...
|
|
4712
|
+
listProducts: (overrides) => listProducts({ ...config, ...overrides }),
|
|
4713
|
+
getProduct: (idOrSlug, overrides) => getProduct(idOrSlug, { ...config, ...overrides })
|
|
4298
4714
|
},
|
|
4299
4715
|
mockup: mockupService
|
|
4300
4716
|
};
|
|
@@ -4318,6 +4734,7 @@ export {
|
|
|
4318
4734
|
DEFAULT_ARTWORK_URL,
|
|
4319
4735
|
DEFAULT_ASPECT_RATIO,
|
|
4320
4736
|
DEFAULT_COLOR,
|
|
4737
|
+
DEFAULT_MOCKUP_BASE,
|
|
4321
4738
|
DEFAULT_PLACEMENT_DIMENSIONS,
|
|
4322
4739
|
Elements,
|
|
4323
4740
|
ErrorManager,
|
|
@@ -4342,9 +4759,9 @@ export {
|
|
|
4342
4759
|
VueAdapter,
|
|
4343
4760
|
adapterRegistry,
|
|
4344
4761
|
autoRegister,
|
|
4762
|
+
buildMockupUrl2 as buildMockupUrl,
|
|
4345
4763
|
componentRegistry,
|
|
4346
4764
|
computeDisabledChoices,
|
|
4347
|
-
config,
|
|
4348
4765
|
createAddToCartEvent,
|
|
4349
4766
|
createAddToCartHandler,
|
|
4350
4767
|
createCartDetail,
|
|
@@ -4384,6 +4801,7 @@ export {
|
|
|
4384
4801
|
getEffectiveAlignment,
|
|
4385
4802
|
getIncompleteSelectionMessage,
|
|
4386
4803
|
getMissingSelections,
|
|
4804
|
+
getMockupUrl,
|
|
4387
4805
|
getOptionRenderType,
|
|
4388
4806
|
getPricePreview,
|
|
4389
4807
|
getProduct,
|
|
@@ -4401,7 +4819,6 @@ export {
|
|
|
4401
4819
|
prepareOptionRenderData,
|
|
4402
4820
|
registerStandardComponents,
|
|
4403
4821
|
resolveBestCombination,
|
|
4404
|
-
resolveMockupConfig,
|
|
4405
4822
|
resolveMockupId,
|
|
4406
4823
|
resolveVariantId,
|
|
4407
4824
|
retryOperation,
|