@neurodyn/react-ai-try-on 0.0.4 → 0.1.0
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/index.d.ts +280 -10
- package/dist/index.js +737 -160
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,34 +2,179 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
|
2
2
|
import { JSX } from 'react/jsx-runtime';
|
|
3
3
|
import * as React_2 from 'react';
|
|
4
4
|
|
|
5
|
-
export declare
|
|
5
|
+
export declare type AiTryOnActivationState = {
|
|
6
|
+
status: 'loading';
|
|
7
|
+
} | ({
|
|
8
|
+
status: 'ready';
|
|
9
|
+
} & Partial<AiTryOnExternalActivation>) | {
|
|
10
|
+
status: 'unavailable';
|
|
11
|
+
temporary?: boolean;
|
|
12
|
+
} | {
|
|
13
|
+
status: 'error';
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export declare function AiTryOnDialog({ defaultOpen, language, onOpenChange, open, productImageSrc, productName, productPrice, productType, productUrl, apiKey, externalGeneration, externalActivation, externalAddToCart, externalClient, ...props }: AiTryOnDialogProps): JSX.Element;
|
|
6
17
|
|
|
7
18
|
declare interface AiTryOnDialogOwnProps extends Omit<DialogProps, 'children' | 'modal'> {
|
|
8
19
|
/** UI language override. */
|
|
9
20
|
language?: AiTryOnLanguage;
|
|
10
|
-
/**
|
|
21
|
+
/** Display image; only the ordinary transport sends it to generation. External mode uses it as a preview. */
|
|
11
22
|
productImageSrc: string;
|
|
12
23
|
/** Product name for product preview alt text and product page CTA. */
|
|
13
24
|
productName: string;
|
|
14
25
|
/** Optional already-formatted product price shown in Add-to-Cart CTAs. */
|
|
15
26
|
productPrice?: string;
|
|
16
|
-
/** Canonical product category sent unchanged to AI try-on generation. */
|
|
17
|
-
productType: ProductType;
|
|
18
27
|
/** Product page URL opened from the result product CTA. */
|
|
19
28
|
productUrl?: string;
|
|
20
|
-
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare type AiTryOnDialogProps = AiTryOnDialogOwnProps & ({
|
|
32
|
+
productType: ProductType;
|
|
21
33
|
apiKey?: string;
|
|
34
|
+
externalGeneration?: never;
|
|
35
|
+
externalActivation?: never;
|
|
36
|
+
externalClient?: never;
|
|
37
|
+
externalAddToCart?: never;
|
|
38
|
+
} | AiTryOnExternalProps);
|
|
39
|
+
|
|
40
|
+
/** What an external integration resolves before the shopper may upload a photo. */
|
|
41
|
+
export declare interface AiTryOnExternalActivation {
|
|
42
|
+
/** The integration's backend is the only authority on availability. */
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
/** Set when the block should lift on its own, so the shopper is told to return. */
|
|
45
|
+
temporarilyUnavailable?: boolean;
|
|
46
|
+
/** Drives the existing photo guidance; absent means generic guidance. */
|
|
47
|
+
productType?: ProductType;
|
|
48
|
+
/** Replaces the storefront preview with the photo generation actually uses. */
|
|
49
|
+
productImageSrc?: string;
|
|
22
50
|
}
|
|
23
51
|
|
|
24
|
-
|
|
52
|
+
/** External integrations may resolve product data before the shopper may act. */
|
|
53
|
+
declare interface AiTryOnExternalProps {
|
|
54
|
+
externalGeneration: AiTryOnProcessPhoto;
|
|
55
|
+
/** Runs on every opening; until it resolves the dialog shows a loading screen. */
|
|
56
|
+
externalActivation?: () => Promise<AiTryOnExternalActivation>;
|
|
57
|
+
/** Transport for the open event. Without it external mode stays analytics-free. */
|
|
58
|
+
externalClient?: AiTryOnTransportClient;
|
|
59
|
+
/**
|
|
60
|
+
* Really adds the tried-on item to the host's cart. Supplying it brings the cart
|
|
61
|
+
* button back for external hosts, which otherwise only have a button that reports
|
|
62
|
+
* the intent and adds nothing.
|
|
63
|
+
*/
|
|
64
|
+
externalAddToCart?: () => Promise<void> | void;
|
|
65
|
+
/** Optional fallback category; activation overrides it. */
|
|
66
|
+
productType?: ProductType;
|
|
67
|
+
apiKey?: never;
|
|
25
68
|
}
|
|
26
69
|
|
|
70
|
+
export declare class AiTryOnGenerationError extends Error {
|
|
71
|
+
readonly code: AiTryOnGenerationErrorCode;
|
|
72
|
+
constructor(code: AiTryOnGenerationErrorCode);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Safe, transport-independent failures that may be presented to the shopper. */
|
|
76
|
+
export declare type AiTryOnGenerationErrorCode = 'tokens' | 'product' | 'service' | 'timeout' | 'photo-required';
|
|
77
|
+
|
|
27
78
|
declare type AiTryOnLanguage = keyof typeof resources;
|
|
28
79
|
|
|
80
|
+
export declare interface AiTryOnPhoto {
|
|
81
|
+
blob?: Blob;
|
|
82
|
+
file?: File;
|
|
83
|
+
id: string;
|
|
84
|
+
lastModified?: number;
|
|
85
|
+
name?: string;
|
|
86
|
+
size?: number;
|
|
87
|
+
src: string;
|
|
88
|
+
type?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
declare interface AiTryOnProcessingContext {
|
|
92
|
+
reportProgress: (progress: number) => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export declare type AiTryOnProcessPhoto = (photo: AiTryOnPhoto, context?: AiTryOnProcessingContext) => Promise<AiTryOnResult>;
|
|
96
|
+
|
|
97
|
+
export declare interface AiTryOnResult {
|
|
98
|
+
after: AiTryOnPhoto;
|
|
99
|
+
before: AiTryOnPhoto;
|
|
100
|
+
createdAt?: number;
|
|
101
|
+
id?: string;
|
|
102
|
+
productImageSrc?: string;
|
|
103
|
+
productName?: string;
|
|
104
|
+
productPrice?: string;
|
|
105
|
+
productUrl?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Transport-agnostic AI try-on client.
|
|
110
|
+
*
|
|
111
|
+
* Public Use and Internal Use each provide one implementation. The transport is
|
|
112
|
+
* selected once, before the first request, from the normalized API key
|
|
113
|
+
* (see {@link normalizeApiKey}); individual operations never choose their own
|
|
114
|
+
* endpoint. Per ADR-0002, a Public Use failure never falls back to Internal Use,
|
|
115
|
+
* and Internal Use never activates a Public Widget Session or emits Public
|
|
116
|
+
* Widget Analytics.
|
|
117
|
+
*/
|
|
118
|
+
declare interface AiTryOnTransportClient {
|
|
119
|
+
/** Request presigned upload URLs for the shopper and product images. */
|
|
120
|
+
requestUploadUrls: (count: number) => Promise<unknown>;
|
|
121
|
+
/** Call the unified synchronous try-on generation operation. */
|
|
122
|
+
generateTryOn: (data: TryOnGenerationRequest, options?: TryOnGenerationOptions) => Promise<unknown>;
|
|
123
|
+
/** Fire-and-forget Public Widget Analytics; a no-op in Internal Use. */
|
|
124
|
+
sendWidgetEvent: (event: AiTryOnWidgetEventName) => void;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare interface AiTryOnUploadOptions {
|
|
128
|
+
fetch?: typeof fetch;
|
|
129
|
+
signal?: AbortSignal;
|
|
130
|
+
/** Omitted by the ordinary processor, which has never bounded its uploads. */
|
|
131
|
+
timeoutMs?: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare type AiTryOnWidgetEventName = 'widget_opened' | 'add_to_cart_from_widget';
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Production operations for a storefront, or none without a mount.
|
|
138
|
+
*
|
|
139
|
+
* `basePath` is the App Proxy mount — `/apps/<subpath>` — and is supplied by the
|
|
140
|
+
* browser bundle rather than read from `import.meta.env` here: this package's
|
|
141
|
+
* build does not substitute `PUBLIC_*` vars, so a read at this level compiles to
|
|
142
|
+
* an empty string. Kept root-relative so it resolves against the shop's own
|
|
143
|
+
* domain from any product URL, including localised ones.
|
|
144
|
+
*/
|
|
145
|
+
export declare function createAppProxyOperations(basePath: string): ShopifyTryOnOperations | undefined;
|
|
146
|
+
|
|
147
|
+
export declare function createShopifyTryOnClient(options: ShopifyTryOnClientOptions): ShopifyTryOnClient;
|
|
148
|
+
|
|
29
149
|
declare type DialogProps = React_2.ComponentProps<typeof DialogPrimitive.Root>
|
|
30
150
|
|
|
31
151
|
export declare function isProductType(value: unknown): value is ProductType;
|
|
32
152
|
|
|
153
|
+
declare type IssueWidgetToken = (data: {
|
|
154
|
+
token?: string;
|
|
155
|
+
}, config?: WidgetSessionApiConfig) => Promise<IssueWidgetTokenResponseDtoOutput>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
159
|
+
* Do not edit manually.
|
|
160
|
+
*/
|
|
161
|
+
declare type IssueWidgetTokenResponseDtoOutput = {
|
|
162
|
+
/**
|
|
163
|
+
* @type string
|
|
164
|
+
*/
|
|
165
|
+
token: string;
|
|
166
|
+
/**
|
|
167
|
+
* @type string
|
|
168
|
+
*/
|
|
169
|
+
sid: string;
|
|
170
|
+
/**
|
|
171
|
+
* @minLength -9007199254740991
|
|
172
|
+
* @maxLength 9007199254740991
|
|
173
|
+
* @type integer
|
|
174
|
+
*/
|
|
175
|
+
expiresIn: number;
|
|
176
|
+
};
|
|
177
|
+
|
|
33
178
|
export declare const PRODUCT_TYPES: readonly ["full-body", "upper-body", "lower-body", "footwear", "headwear", "eyewear", "neck", "wrist", "bag", "waist"];
|
|
34
179
|
|
|
35
180
|
export declare type ProductType = typeof PRODUCT_TYPES[number];
|
|
@@ -37,6 +182,16 @@ export declare type ProductType = typeof PRODUCT_TYPES[number];
|
|
|
37
182
|
declare const resources: {
|
|
38
183
|
readonly en: {
|
|
39
184
|
readonly ns1: {
|
|
185
|
+
readonly activationLoading: "Checking this product…";
|
|
186
|
+
readonly activationLoadingSubtitle: "One moment while the store confirms try-on for this item.";
|
|
187
|
+
readonly activationTemporarilyUnavailable: "Try-on is paused for this store right now. Please check back later.";
|
|
188
|
+
readonly activationUnavailableTitle: "Try-on is unavailable";
|
|
189
|
+
readonly externalPhotoRequired: "Please upload your photo again.";
|
|
190
|
+
readonly externalNoTokens: "The store has no tokens remaining.";
|
|
191
|
+
readonly externalProductUnavailable: "Try-on is unavailable for this product.";
|
|
192
|
+
readonly externalServiceUnavailable: "Try-on is unavailable. Please try again later.";
|
|
193
|
+
readonly externalTimeout: "The request timed out. Please try again.";
|
|
194
|
+
readonly externalPhotoHint: "Upload a clear photo of yourself. The store chooses the item used for your try-on.";
|
|
40
195
|
readonly back: "Back";
|
|
41
196
|
readonly badge: "Try it on";
|
|
42
197
|
readonly confirmBadge: "Almost there";
|
|
@@ -126,7 +281,7 @@ declare const resources: {
|
|
|
126
281
|
readonly startUpload: "Choose your photo";
|
|
127
282
|
readonly termsJoiner: "&";
|
|
128
283
|
readonly termsLink: "Terms";
|
|
129
|
-
readonly termsPrefix: "By using this service,
|
|
284
|
+
readonly termsPrefix: "By using this service, you agree to";
|
|
130
285
|
readonly privacyLink: "privacy Policy";
|
|
131
286
|
readonly upperBodyIntroBadArmsCrossed: "Arms crossed hide the fit";
|
|
132
287
|
readonly upperBodyIntroBadObjectBlockingTorso: "Object blocks the torso";
|
|
@@ -150,6 +305,16 @@ declare const resources: {
|
|
|
150
305
|
};
|
|
151
306
|
readonly ru: {
|
|
152
307
|
readonly ns1: {
|
|
308
|
+
readonly activationLoading: "Проверяем товар…";
|
|
309
|
+
readonly activationLoadingSubtitle: "Магазин подтверждает примерку для этого товара.";
|
|
310
|
+
readonly activationTemporarilyUnavailable: "Примерка в этом магазине сейчас приостановлена. Загляните позже.";
|
|
311
|
+
readonly activationUnavailableTitle: "Примерка недоступна";
|
|
312
|
+
readonly externalPhotoRequired: "Загрузите фото заново.";
|
|
313
|
+
readonly externalNoTokens: "У магазина закончились токены.";
|
|
314
|
+
readonly externalProductUnavailable: "Примерка для этого товара недоступна.";
|
|
315
|
+
readonly externalServiceUnavailable: "Примерка недоступна. Попробуйте позже.";
|
|
316
|
+
readonly externalTimeout: "Время ожидания истекло. Попробуйте снова.";
|
|
317
|
+
readonly externalPhotoHint: "Загрузите чёткое фото себя. Изображение товара для примерки определяется настройками магазина.";
|
|
153
318
|
readonly back: "Назад";
|
|
154
319
|
readonly badge: "Примерить";
|
|
155
320
|
readonly confirmBadge: "Почти готово";
|
|
@@ -206,7 +371,7 @@ declare const resources: {
|
|
|
206
371
|
readonly headwearIntroTitle: "Загрузите фото головы и плеч";
|
|
207
372
|
readonly introCta: "Продолжить";
|
|
208
373
|
readonly introBadge: "Совет";
|
|
209
|
-
readonly myFits: "
|
|
374
|
+
readonly myFits: "Мои образы";
|
|
210
375
|
readonly lowerBodyIntroBadCoveredWaist: "Свободная одежда скрывает линию талии";
|
|
211
376
|
readonly lowerBodyIntroBadSitting: "В сидячей позе ноги согнуты";
|
|
212
377
|
readonly lowerBodyIntroGoodFullBody: "Фото в полный рост";
|
|
@@ -231,8 +396,8 @@ declare const resources: {
|
|
|
231
396
|
readonly resultReset: "Сохранить";
|
|
232
397
|
readonly resultShare: "Поделиться";
|
|
233
398
|
readonly resultTitle: "Вот как это выглядит на вас";
|
|
234
|
-
readonly resultTryAnother: "
|
|
235
|
-
readonly resultTryAnotherWithPrice: "
|
|
399
|
+
readonly resultTryAnother: "Добавить в корзину";
|
|
400
|
+
readonly resultTryAnotherWithPrice: "Добавить в корзину – {{price}}";
|
|
236
401
|
readonly share: "Поделиться";
|
|
237
402
|
readonly startHistory: "Смотреть прошлые результаты";
|
|
238
403
|
readonly startTitle: "Хотите увидеть это на себе?";
|
|
@@ -263,4 +428,109 @@ declare const resources: {
|
|
|
263
428
|
};
|
|
264
429
|
};
|
|
265
430
|
|
|
431
|
+
/** The isolated client does not inherit the shared client's default, so it is set here. */
|
|
432
|
+
export declare const SHOPIFY_REQUEST_TIMEOUT_MS = 30000;
|
|
433
|
+
|
|
434
|
+
export declare interface ShopifyActivation {
|
|
435
|
+
/** The backend decides availability; the frontend only refuses a malformed answer. */
|
|
436
|
+
available: boolean;
|
|
437
|
+
reason?: ShopifyUnavailableReason;
|
|
438
|
+
/** Canonical zone slug, when the backend resolved one. Drives the photo guidance. */
|
|
439
|
+
zoneType?: ProductType;
|
|
440
|
+
/** The photo the backend generates from, replacing the storefront preview. */
|
|
441
|
+
photoUrl?: string;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* One instance per dialog opening: it activates the product, holds the Widget
|
|
446
|
+
* Session, runs generation and emits the open event. Uploads and generation are
|
|
447
|
+
* reached through {@link createProcessPhoto}, never through the transport
|
|
448
|
+
* surface — the widget must not drive Shopify requests with the ordinary shapes.
|
|
449
|
+
*/
|
|
450
|
+
declare class ShopifyTryOnClient implements AiTryOnTransportClient {
|
|
451
|
+
private readonly createObjectUrl;
|
|
452
|
+
private readonly operations;
|
|
453
|
+
private readonly signal;
|
|
454
|
+
private session;
|
|
455
|
+
constructor({ createObjectUrl, operations, signal }: ShopifyTryOnClientOptions);
|
|
456
|
+
activate(target: ShopifyTryOnTarget): Promise<ShopifyActivation>;
|
|
457
|
+
createProcessPhoto(target: ShopifyTryOnTarget): AiTryOnProcessPhoto;
|
|
458
|
+
/**
|
|
459
|
+
* Every Shopify request funnels through here so a rejected HTTP status reaches
|
|
460
|
+
* the shopper as a stable code instead of a generic service failure.
|
|
461
|
+
*/
|
|
462
|
+
private run;
|
|
463
|
+
sendWidgetEvent(event: AiTryOnWidgetEventName): void;
|
|
464
|
+
/** Shopify uploads and generation go through {@link createProcessPhoto}. */
|
|
465
|
+
requestUploadUrls(): Promise<never>;
|
|
466
|
+
generateTryOn(): Promise<never>;
|
|
467
|
+
private baseConfig;
|
|
468
|
+
private requestConfig;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
declare interface ShopifyTryOnClientOptions {
|
|
472
|
+
createObjectUrl?: (blob: Blob) => string;
|
|
473
|
+
operations: ShopifyTryOnOperations;
|
|
474
|
+
signal?: AbortSignal;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* HTTP seam. Stage 1 supplies test operations; stage 2 supplies the generated
|
|
479
|
+
* `@vizbl/api` methods bound to an isolated client on the App Proxy path.
|
|
480
|
+
*/
|
|
481
|
+
export declare interface ShopifyTryOnOperations {
|
|
482
|
+
activate: (target: ShopifyTryOnTarget, config: WidgetSessionApiConfig) => Promise<unknown>;
|
|
483
|
+
requestUploadUrls: (count: number, config: WidgetSessionApiConfig) => Promise<unknown>;
|
|
484
|
+
generate: (data: ShopifyTryOnTarget & {
|
|
485
|
+
personImageKey: string;
|
|
486
|
+
}, config: WidgetSessionApiConfig) => Promise<unknown>;
|
|
487
|
+
/**
|
|
488
|
+
* Refreshes the Widget Session. Required: without it the session client falls
|
|
489
|
+
* back to the shared cabinet API instance and the refresh leaves the proxy.
|
|
490
|
+
*/
|
|
491
|
+
issueWidgetToken: IssueWidgetToken;
|
|
492
|
+
/** Overrides the direct PUT to storage; the demo uses it to keep photos local. */
|
|
493
|
+
uploadPhoto?: (uploadUrl: string, photo: Blob, options: {
|
|
494
|
+
signal?: AbortSignal;
|
|
495
|
+
timeoutMs: number;
|
|
496
|
+
}) => Promise<void>;
|
|
497
|
+
sendWidgetEvent?: (data: {
|
|
498
|
+
event: AiTryOnWidgetEventName;
|
|
499
|
+
timestamp: string;
|
|
500
|
+
}, config: WidgetSessionApiConfig) => Promise<unknown>;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* What the shopper is trying on. The variant is optional: a product page without
|
|
505
|
+
* a variant picker has none, and the backend then resolves the product's photo.
|
|
506
|
+
*/
|
|
507
|
+
export declare interface ShopifyTryOnTarget {
|
|
508
|
+
productId: string;
|
|
509
|
+
variantId?: string;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/** Why the backend refused, so the storefront can tell "come back later" from "not set up". */
|
|
513
|
+
declare type ShopifyUnavailableReason = 'not_enabled' | 'zone_not_configured' | 'no_product_photo' | 'tokens_exhausted';
|
|
514
|
+
|
|
515
|
+
declare interface TryOnGenerationOptions {
|
|
516
|
+
timeout?: number;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
declare interface TryOnGenerationRequest {
|
|
520
|
+
/** Validated canonical Product Type, sent unchanged to the unified generation operation. */
|
|
521
|
+
category: ProductType;
|
|
522
|
+
personImage: string;
|
|
523
|
+
productImages: string[];
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export declare function uploadImageToPresignedUrl(uploadUrl: string, imageBlob: Blob, options?: AiTryOnUploadOptions): Promise<void>;
|
|
527
|
+
|
|
528
|
+
declare interface WidgetSessionApiConfig {
|
|
529
|
+
baseURL?: string;
|
|
530
|
+
headers?: Record<string, string | undefined>;
|
|
531
|
+
signal?: AbortSignal;
|
|
532
|
+
timeout?: number;
|
|
533
|
+
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream';
|
|
534
|
+
}
|
|
535
|
+
|
|
266
536
|
export { }
|