@vio-live/web-sdk 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/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/chunk-4CCGE7DE.js +3284 -0
- package/dist/chunk-4CCGE7DE.js.map +1 -0
- package/dist/chunk-5SPY7TH6.js +1618 -0
- package/dist/chunk-5SPY7TH6.js.map +1 -0
- package/dist/chunk-GGM2AIK5.js +3 -0
- package/dist/chunk-GGM2AIK5.js.map +1 -0
- package/dist/core/index.d.ts +748 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/index.d.ts +98 -0
- package/dist/ui/index.js +4 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/vio-checkout-D8B4Upk8.d.ts +301 -0
- package/package.json +76 -0
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vio Configuration — singleton holding apiKey, environment, base URLs,
|
|
5
|
+
* and optional payment-vendor publishable keys.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors `VioConfiguration.shared` in the iOS SDK. Initialised once via
|
|
8
|
+
* `Vio.init({ apiKey, ... })`; consumed via `Configuration.get()`.
|
|
9
|
+
*
|
|
10
|
+
* Secrets (apiKey) never come from inside the SDK — the consumer reads
|
|
11
|
+
* them from env vars / their config and passes them to `Vio.init`.
|
|
12
|
+
*/
|
|
13
|
+
type Environment = 'development' | 'testing' | 'production';
|
|
14
|
+
interface VioConfig {
|
|
15
|
+
/** Vio API key for this client app (from the Vio dashboard). */
|
|
16
|
+
apiKey: string;
|
|
17
|
+
/** Target environment. Defaults to 'development'. */
|
|
18
|
+
environment?: Environment;
|
|
19
|
+
/** Override REST API base. Defaults are env-aware. */
|
|
20
|
+
apiBase?: string;
|
|
21
|
+
/** Override GraphQL base. Defaults are env-aware. */
|
|
22
|
+
graphQLBase?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Stripe **publishable** key (`pk_test_xxx` or `pk_live_xxx`). Used for
|
|
25
|
+
* Apple Pay (via Payment Request) and Card flows. Public-safe — fine
|
|
26
|
+
* to expose in client bundles.
|
|
27
|
+
*/
|
|
28
|
+
stripePublishableKey?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Klarna **Client Identifier** for Express Checkout (KEC). Public-safe.
|
|
31
|
+
* From Merchant Portal → Payment settings → Client Identifiers. When set,
|
|
32
|
+
* the checkout shows the Klarna Express button; when absent it degrades
|
|
33
|
+
* to the plain method selector. Must match `klarnaEnvironment`.
|
|
34
|
+
*/
|
|
35
|
+
klarnaClientId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Klarna environment for the Express button. `playground` = sandbox
|
|
38
|
+
* (test orders, no real money), `production` = live. Defaults to
|
|
39
|
+
* `playground` so dev/test never hits live Klarna by accident.
|
|
40
|
+
*/
|
|
41
|
+
klarnaEnvironment?: 'playground' | 'production';
|
|
42
|
+
}
|
|
43
|
+
interface ResolvedConfig {
|
|
44
|
+
apiKey: string;
|
|
45
|
+
environment: Environment;
|
|
46
|
+
apiBase: string;
|
|
47
|
+
graphQLBase: string;
|
|
48
|
+
stripePublishableKey?: string;
|
|
49
|
+
klarnaClientId?: string;
|
|
50
|
+
klarnaEnvironment: 'playground' | 'production';
|
|
51
|
+
}
|
|
52
|
+
declare class ConfigurationSingleton {
|
|
53
|
+
private resolved;
|
|
54
|
+
init(input: VioConfig): void;
|
|
55
|
+
get(): ResolvedConfig;
|
|
56
|
+
get isInitialized(): boolean;
|
|
57
|
+
/** For tests only. */
|
|
58
|
+
reset(): void;
|
|
59
|
+
}
|
|
60
|
+
declare const Configuration: ConfigurationSingleton;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Vio types — Product / Sponsor / Bootstrap shapes.
|
|
64
|
+
*
|
|
65
|
+
* Product types mirror the Vio Commerce GraphQL schema.
|
|
66
|
+
* Sponsor / Bootstrap shapes mirror the iOS SDK's bootstrap response so
|
|
67
|
+
* we stay aligned cross-platform.
|
|
68
|
+
*/
|
|
69
|
+
type ImageSize = 'thumbnail' | 'small' | 'medium' | 'large' | 'full';
|
|
70
|
+
interface ProductPrice {
|
|
71
|
+
amount: number;
|
|
72
|
+
currency_code: string;
|
|
73
|
+
compare_at?: number | null;
|
|
74
|
+
amount_incl_taxes?: number | null;
|
|
75
|
+
compare_at_incl_taxes?: number | null;
|
|
76
|
+
tax_amount?: number | null;
|
|
77
|
+
tax_rate?: number | null;
|
|
78
|
+
}
|
|
79
|
+
interface ProductImage {
|
|
80
|
+
id: string;
|
|
81
|
+
url: string;
|
|
82
|
+
width?: number | null;
|
|
83
|
+
height?: number | null;
|
|
84
|
+
order?: number | null;
|
|
85
|
+
}
|
|
86
|
+
interface ProductOption {
|
|
87
|
+
id: number;
|
|
88
|
+
name: string;
|
|
89
|
+
order: number;
|
|
90
|
+
values: string[];
|
|
91
|
+
}
|
|
92
|
+
interface ProductCategory {
|
|
93
|
+
id: number;
|
|
94
|
+
name: string;
|
|
95
|
+
}
|
|
96
|
+
interface ProductVariant {
|
|
97
|
+
id: number;
|
|
98
|
+
barcode?: string | null;
|
|
99
|
+
quantity?: number | null;
|
|
100
|
+
sku?: string | null;
|
|
101
|
+
title?: string | null;
|
|
102
|
+
price: ProductPrice;
|
|
103
|
+
images: ProductImage[];
|
|
104
|
+
}
|
|
105
|
+
interface Product {
|
|
106
|
+
id: number;
|
|
107
|
+
brand?: string | null;
|
|
108
|
+
title: string;
|
|
109
|
+
description?: string | null;
|
|
110
|
+
tags?: string | null;
|
|
111
|
+
sku: string;
|
|
112
|
+
quantity?: number | null;
|
|
113
|
+
price: ProductPrice;
|
|
114
|
+
variants: ProductVariant[];
|
|
115
|
+
barcode?: string | null;
|
|
116
|
+
options: ProductOption[];
|
|
117
|
+
categories?: ProductCategory[] | null;
|
|
118
|
+
images: ProductImage[];
|
|
119
|
+
}
|
|
120
|
+
/** Per-sponsor commerce config sourced from Vio bootstrap. */
|
|
121
|
+
interface SponsorCommerceBlock {
|
|
122
|
+
apiKey: string;
|
|
123
|
+
channelId?: string | null;
|
|
124
|
+
paymentMethods?: string[];
|
|
125
|
+
}
|
|
126
|
+
interface Sponsor {
|
|
127
|
+
id: number;
|
|
128
|
+
name: string;
|
|
129
|
+
description?: string | null;
|
|
130
|
+
avatarUrl?: string | null;
|
|
131
|
+
logoUrl?: string | null;
|
|
132
|
+
primaryColor?: string | null;
|
|
133
|
+
secondaryColor?: string | null;
|
|
134
|
+
commerce: SponsorCommerceBlock;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Response shape of `GET /v2/mobile/config` (and likely future `/v2/web/config`).
|
|
138
|
+
* Matches the iOS SDK's `SdkBootstrapResponse` model.
|
|
139
|
+
*/
|
|
140
|
+
interface BootstrapResponse {
|
|
141
|
+
campaignId?: number;
|
|
142
|
+
primarySponsor?: Sponsor;
|
|
143
|
+
secondarySponsors?: Sponsor[];
|
|
144
|
+
market?: {
|
|
145
|
+
countryCode: string;
|
|
146
|
+
currencyCode: string;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A placement component returned by `/v2/mobile/campaigns/:id/components`.
|
|
151
|
+
* Used by `<vio-product-carousel campaign-id="...">` to know which products
|
|
152
|
+
* to render at a given slot.
|
|
153
|
+
*/
|
|
154
|
+
interface PlacementComponent {
|
|
155
|
+
id: number;
|
|
156
|
+
componentType: string;
|
|
157
|
+
locationId: string;
|
|
158
|
+
sponsorId?: number;
|
|
159
|
+
config: {
|
|
160
|
+
productIds?: number[];
|
|
161
|
+
[key: string]: unknown;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Helper: extract a useful display price from a Product. */
|
|
165
|
+
declare function displayPrice(product: Product): string;
|
|
166
|
+
/** Format a numeric amount + currency for Norwegian style: "1 299 kr". */
|
|
167
|
+
declare function formatPrice(amount: number, currency: string): string;
|
|
168
|
+
/** Helper: pick the first image URL (variant first, then product). */
|
|
169
|
+
declare function primaryImageUrl(product: Product): string | undefined;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Vio REST API client — talks to `api-dev.vio.live` (or override).
|
|
173
|
+
*
|
|
174
|
+
* Endpoints (mirrors the iOS SDK's surface):
|
|
175
|
+
* GET /v2/mobile/config bootstrap (sponsors + market)
|
|
176
|
+
* GET /v2/mobile/campaigns/:id/components placement components (TBD)
|
|
177
|
+
* POST /v2/mobile/campaigns/:id/cart-intent cross-device cart-intent (TBD)
|
|
178
|
+
*
|
|
179
|
+
* Auth: `X-API-Key: <apiKey>` header (the top-level Vio apiKey).
|
|
180
|
+
*
|
|
181
|
+
* Note: until the backend exposes a dedicated `/v2/web/*` surface we
|
|
182
|
+
* reuse the `/v2/mobile/*` paths — the apiKey identifies the client_app
|
|
183
|
+
* and the response shape is platform-agnostic enough.
|
|
184
|
+
*/
|
|
185
|
+
|
|
186
|
+
interface VioApiOptions {
|
|
187
|
+
/** REST API base URL, e.g. `https://api-dev.vio.live`. */
|
|
188
|
+
apiBase: string;
|
|
189
|
+
/** Top-level Vio apiKey for this client app. */
|
|
190
|
+
apiKey: string;
|
|
191
|
+
}
|
|
192
|
+
declare class VioApi {
|
|
193
|
+
private readonly apiBase;
|
|
194
|
+
private readonly apiKey;
|
|
195
|
+
constructor(options: VioApiOptions);
|
|
196
|
+
/**
|
|
197
|
+
* Bootstrap — fetches client app config (sponsors with commerce keys,
|
|
198
|
+
* default market, campaign id). Called once at SDK init.
|
|
199
|
+
*/
|
|
200
|
+
bootstrap(): Promise<BootstrapResponse>;
|
|
201
|
+
/**
|
|
202
|
+
* Get placement components for a campaign. Used by the carousel auto-fetch
|
|
203
|
+
* mode (`<vio-product-carousel campaign-id="36" location="news-favorites">`).
|
|
204
|
+
*/
|
|
205
|
+
getComponents(campaignId: number | string): Promise<PlacementComponent[]>;
|
|
206
|
+
private get;
|
|
207
|
+
}
|
|
208
|
+
declare class VioApiError extends Error {
|
|
209
|
+
readonly status: number;
|
|
210
|
+
readonly body: string;
|
|
211
|
+
readonly endpoint: string;
|
|
212
|
+
constructor(status: number, body: string, endpoint: string);
|
|
213
|
+
}
|
|
214
|
+
declare function createVioApi(options: VioApiOptions): VioApi;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Commerce GraphQL client — talks to Vio Commerce.
|
|
218
|
+
*
|
|
219
|
+
* Mirrors the iOS SDK's `SdkClient.channel.product` surface, but uses
|
|
220
|
+
* `graphql-request` (lightweight) instead of Apollo. Auth header: `Authorization: <apiKey>`
|
|
221
|
+
* (per-sponsor commerce apiKey, NOT the top-level Vio apiKey).
|
|
222
|
+
*
|
|
223
|
+
* Usage:
|
|
224
|
+
* const commerce = createCommerceClient({
|
|
225
|
+
* endpoint: 'https://graph-ql-dev.vio.live',
|
|
226
|
+
* apiKey: '<sponsor-commerce-apiKey>', // sponsor's commerce apiKey
|
|
227
|
+
* })
|
|
228
|
+
* const products = await commerce.channel.product.getByIds({
|
|
229
|
+
* product_ids: [408895, 408896],
|
|
230
|
+
* currency: 'NOK',
|
|
231
|
+
* image_size: 'large',
|
|
232
|
+
* })
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
interface CommerceClientOptions {
|
|
236
|
+
/** Vio Commerce GraphQL endpoint, e.g. `https://graph-ql-dev.vio.live`. */
|
|
237
|
+
endpoint: string;
|
|
238
|
+
/** Per-sponsor commerce apiKey (from bootstrap.primarySponsor.commerce.apiKey). */
|
|
239
|
+
apiKey: string;
|
|
240
|
+
}
|
|
241
|
+
interface GetProductsByIdsOptions {
|
|
242
|
+
product_ids: number[];
|
|
243
|
+
currency?: string | null;
|
|
244
|
+
image_size?: ImageSize | null;
|
|
245
|
+
useCache?: boolean;
|
|
246
|
+
shipping_country_code?: string | null;
|
|
247
|
+
}
|
|
248
|
+
declare class ChannelProduct {
|
|
249
|
+
private readonly client;
|
|
250
|
+
constructor(client: GraphQLClient);
|
|
251
|
+
/**
|
|
252
|
+
* Fetch a batch of products by their numeric ids.
|
|
253
|
+
* Returns an empty array if no ids are provided.
|
|
254
|
+
*/
|
|
255
|
+
getByIds(options: GetProductsByIdsOptions): Promise<Product[]>;
|
|
256
|
+
}
|
|
257
|
+
declare class Channel {
|
|
258
|
+
readonly product: ChannelProduct;
|
|
259
|
+
constructor(client: GraphQLClient);
|
|
260
|
+
}
|
|
261
|
+
/** CommerceClient — namespaced facade, mirrors the iOS SdkClient. */
|
|
262
|
+
declare class CommerceClient {
|
|
263
|
+
readonly channel: Channel;
|
|
264
|
+
/** Underlying graphql-request client (escape hatch for custom queries). */
|
|
265
|
+
readonly raw: GraphQLClient;
|
|
266
|
+
constructor(options: CommerceClientOptions);
|
|
267
|
+
}
|
|
268
|
+
declare function createCommerceClient(options: CommerceClientOptions): CommerceClient;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Cart types — multi-sponsor line items.
|
|
272
|
+
*
|
|
273
|
+
* Mirrors the iOS SDK's `SponsorCart` + `CartLineItem` structure so the
|
|
274
|
+
* mental model stays consistent across platforms.
|
|
275
|
+
*/
|
|
276
|
+
interface CartLineItem {
|
|
277
|
+
/** Unique local id for this line item (used for update/remove). */
|
|
278
|
+
id: string;
|
|
279
|
+
/** Vio Commerce product id. */
|
|
280
|
+
productId: number;
|
|
281
|
+
/** Sponsor (merchant) id this line item belongs to. */
|
|
282
|
+
sponsorId: number;
|
|
283
|
+
/** Optional variant id. */
|
|
284
|
+
variantId?: number;
|
|
285
|
+
/** Display brand (e.g. "COS"). */
|
|
286
|
+
brand: string;
|
|
287
|
+
/** Display product name. */
|
|
288
|
+
name: string;
|
|
289
|
+
/** Numeric unit price (inclusive of taxes when available). */
|
|
290
|
+
unitPrice: number;
|
|
291
|
+
/** Currency code (e.g. "NOK"). */
|
|
292
|
+
currency: string;
|
|
293
|
+
/** Display image URL. */
|
|
294
|
+
imageUrl: string;
|
|
295
|
+
/** Quantity. */
|
|
296
|
+
quantity: number;
|
|
297
|
+
}
|
|
298
|
+
interface SponsorCartState {
|
|
299
|
+
sponsorId: number;
|
|
300
|
+
sponsorName?: string;
|
|
301
|
+
items: CartLineItem[];
|
|
302
|
+
currency: string;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* CartManager — multi-sponsor cart state.
|
|
307
|
+
*
|
|
308
|
+
* Mirrors iOS's `CartManager` + `cartsBySponsor`. Holds local state in
|
|
309
|
+
* memory and persists to localStorage. Reactive: dispatches a `change`
|
|
310
|
+
* CustomEvent that UI components subscribe to (Web Components react via
|
|
311
|
+
* `requestUpdate()`).
|
|
312
|
+
*
|
|
313
|
+
* Server-side cart sync (Vio Commerce GraphQL CreateCart / AddToCart
|
|
314
|
+
* mutations) is deferred to checkout time via the CheckoutManager —
|
|
315
|
+
* this manager is purely client-side state for now.
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
interface CartChangeDetail {
|
|
319
|
+
cartsBySponsor: Map<number, SponsorCartState>;
|
|
320
|
+
itemCount: number;
|
|
321
|
+
}
|
|
322
|
+
interface AddProductOptions {
|
|
323
|
+
product: Product;
|
|
324
|
+
sponsorId: number;
|
|
325
|
+
sponsorName?: string;
|
|
326
|
+
quantity?: number;
|
|
327
|
+
variantId?: number;
|
|
328
|
+
}
|
|
329
|
+
/** Minimal product shape — for callers who only have e.g. mock data, not a full Product. */
|
|
330
|
+
interface AddManualOptions {
|
|
331
|
+
productId: number;
|
|
332
|
+
sponsorId: number;
|
|
333
|
+
sponsorName?: string;
|
|
334
|
+
brand: string;
|
|
335
|
+
name: string;
|
|
336
|
+
unitPrice: number;
|
|
337
|
+
currency: string;
|
|
338
|
+
imageUrl: string;
|
|
339
|
+
quantity?: number;
|
|
340
|
+
variantId?: number;
|
|
341
|
+
}
|
|
342
|
+
declare class CartManager extends EventTarget {
|
|
343
|
+
private cartsBySponsor;
|
|
344
|
+
constructor();
|
|
345
|
+
/** Add a Product DTO to a sponsor's cart. Bumps quantity if already present. */
|
|
346
|
+
addProduct(opts: AddProductOptions): CartLineItem;
|
|
347
|
+
/** Add a manually-specified line item (no Product DTO). */
|
|
348
|
+
addManual(opts: AddManualOptions): CartLineItem;
|
|
349
|
+
updateQuantity(lineItemId: string, sponsorId: number, quantity: number): void;
|
|
350
|
+
removeItem(lineItemId: string, sponsorId: number): void;
|
|
351
|
+
clearSponsorCart(sponsorId: number): void;
|
|
352
|
+
clearAllCarts(): void;
|
|
353
|
+
getAllCarts(): Map<number, SponsorCartState>;
|
|
354
|
+
getCart(sponsorId: number): SponsorCartState | undefined;
|
|
355
|
+
get itemCount(): number;
|
|
356
|
+
subtotalForSponsor(sponsorId: number): number;
|
|
357
|
+
get totalAcrossSponsors(): number;
|
|
358
|
+
get primaryCurrency(): string;
|
|
359
|
+
formatTotal(): string;
|
|
360
|
+
private persist;
|
|
361
|
+
private loadFromStorage;
|
|
362
|
+
private emit;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Apple Pay on the Web — via Stripe Payment Request API.
|
|
367
|
+
*
|
|
368
|
+
* Architecture decision (matches iOS Vio SDK pattern):
|
|
369
|
+
* - One Stripe **publishable key** for the Vio platform (global, set
|
|
370
|
+
* via `Vio.init({ stripePublishableKey })`).
|
|
371
|
+
* - One **Stripe Connect account id** per sponsor — sourced from
|
|
372
|
+
* `Vio.bootstrap()` response. Without it, the payment lands on the
|
|
373
|
+
* platform account instead of the merchant.
|
|
374
|
+
*
|
|
375
|
+
* Apple Pay on the Web prerequisites (Stripe-managed for us):
|
|
376
|
+
* - Stripe Connect account is enabled for Apple Pay
|
|
377
|
+
* - Domain registration for Apple Pay (Stripe handles via Dashboard)
|
|
378
|
+
* - Safari + macOS/iOS device with Apple Pay configured
|
|
379
|
+
*
|
|
380
|
+
* In Chrome / non-Apple browsers `canMakePayment()` returns null, so the
|
|
381
|
+
* UI hides the Apple Pay button automatically.
|
|
382
|
+
*/
|
|
383
|
+
interface ApplePayConfig {
|
|
384
|
+
/** Stripe platform publishable key (pk_live_xxx or pk_test_xxx). */
|
|
385
|
+
publishableKey: string;
|
|
386
|
+
/** Sponsor's Stripe Connect account (acct_xxx). Optional but recommended. */
|
|
387
|
+
connectedAccount?: string;
|
|
388
|
+
/** Amount in the smallest unit of the currency (e.g. øre for NOK, cents for USD). */
|
|
389
|
+
amount: number;
|
|
390
|
+
/** ISO currency code, lowercased internally for Stripe. */
|
|
391
|
+
currency: string;
|
|
392
|
+
/** Two-letter country code, e.g. "NO". */
|
|
393
|
+
country: string;
|
|
394
|
+
/** Label shown in the Apple Pay sheet (merchant or order name). */
|
|
395
|
+
label: string;
|
|
396
|
+
/** Whether to ask the user for payer name. */
|
|
397
|
+
requestPayerName?: boolean;
|
|
398
|
+
/** Whether to ask the user for payer email. */
|
|
399
|
+
requestPayerEmail?: boolean;
|
|
400
|
+
/** Whether to ask for shipping address. */
|
|
401
|
+
requestShipping?: boolean;
|
|
402
|
+
/**
|
|
403
|
+
* Shipping options shown natively in the Apple Pay sheet. `amount` is in the
|
|
404
|
+
* smallest unit (øre). When set, `requestShipping` is forced on and the sheet
|
|
405
|
+
* total = `amount` (items) + the selected option; switching options updates
|
|
406
|
+
* the total live (Apple Pay native shipping).
|
|
407
|
+
*/
|
|
408
|
+
shippingOptions?: Array<{
|
|
409
|
+
id: string;
|
|
410
|
+
label: string;
|
|
411
|
+
detail?: string;
|
|
412
|
+
amount: number;
|
|
413
|
+
}>;
|
|
414
|
+
}
|
|
415
|
+
interface ApplePayResult {
|
|
416
|
+
/** Stripe PaymentMethod id (pm_xxx) — pass to backend to confirm the PaymentIntent. */
|
|
417
|
+
paymentMethodId: string;
|
|
418
|
+
payerName?: string;
|
|
419
|
+
payerEmail?: string;
|
|
420
|
+
payerPhone?: string;
|
|
421
|
+
shippingAddress?: {
|
|
422
|
+
line1?: string;
|
|
423
|
+
line2?: string;
|
|
424
|
+
city?: string;
|
|
425
|
+
postal_code?: string;
|
|
426
|
+
state?: string;
|
|
427
|
+
country?: string;
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Check whether Apple Pay is available right now (Safari + supported device
|
|
432
|
+
* + Stripe configured + domain registered).
|
|
433
|
+
*
|
|
434
|
+
* Returns false on any failure path — never throws.
|
|
435
|
+
*/
|
|
436
|
+
declare function checkApplePayAvailability(config: ApplePayConfig): Promise<boolean>;
|
|
437
|
+
/**
|
|
438
|
+
* Show the Apple Pay sheet. Resolves with the payment method id (`pm_xxx`)
|
|
439
|
+
* after the user authorises, or rejects on cancel / error.
|
|
440
|
+
*
|
|
441
|
+
* The backend must then confirm a Stripe PaymentIntent with this
|
|
442
|
+
* payment method id (server-side step, not handled here).
|
|
443
|
+
*/
|
|
444
|
+
declare function showApplePaySheet(config: ApplePayConfig): Promise<ApplePayResult>;
|
|
445
|
+
|
|
446
|
+
/** One line in the express button's purchase data. Amounts in MINOR units. */
|
|
447
|
+
interface KlarnaLineItem {
|
|
448
|
+
name: string;
|
|
449
|
+
quantity: number;
|
|
450
|
+
/** Line total (unitPrice × quantity), minor units (e.g. øre for NOK). */
|
|
451
|
+
totalAmount: number;
|
|
452
|
+
/** Per-unit price, minor units. Optional. */
|
|
453
|
+
unitPrice?: number;
|
|
454
|
+
/** Merchant SKU / product reference. Optional. */
|
|
455
|
+
reference?: string;
|
|
456
|
+
/** Absolute image URL. Optional. */
|
|
457
|
+
imageUrl?: string;
|
|
458
|
+
}
|
|
459
|
+
/** Payment request handed to the KEC button. Amounts in MINOR units. */
|
|
460
|
+
interface KlarnaPaymentRequestData {
|
|
461
|
+
/** ISO currency code (e.g. "NOK"). */
|
|
462
|
+
currency: string;
|
|
463
|
+
/** Order total in minor units. */
|
|
464
|
+
amount: number;
|
|
465
|
+
/** Line items — shown in the Klarna sheet. */
|
|
466
|
+
supplementaryPurchaseData?: {
|
|
467
|
+
lineItems: KlarnaLineItem[];
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
interface KlarnaAuthorizeResult {
|
|
471
|
+
/** Authorization token — backend exchanges it for an order. */
|
|
472
|
+
authorizationToken: string;
|
|
473
|
+
/** Klarna may require a finalize step (multistep flows). */
|
|
474
|
+
finalizeRequired?: boolean;
|
|
475
|
+
/** Raw payload from the SDK, for debugging / forward-compat. */
|
|
476
|
+
raw?: unknown;
|
|
477
|
+
}
|
|
478
|
+
interface KlarnaButtonHandle {
|
|
479
|
+
unmount(): void;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
interface KlarnaPaymentsCategory {
|
|
483
|
+
identifier: string;
|
|
484
|
+
name: string;
|
|
485
|
+
asset_urls?: {
|
|
486
|
+
descriptive?: string;
|
|
487
|
+
standard?: string;
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
interface KpLoadResult {
|
|
491
|
+
show_form?: boolean;
|
|
492
|
+
error?: unknown;
|
|
493
|
+
}
|
|
494
|
+
interface KpAuthorizeResult {
|
|
495
|
+
approved?: boolean;
|
|
496
|
+
show_form?: boolean;
|
|
497
|
+
authorization_token?: string;
|
|
498
|
+
finalize_required?: boolean;
|
|
499
|
+
error?: unknown;
|
|
500
|
+
}
|
|
501
|
+
interface KlarnaPaymentsApi {
|
|
502
|
+
init(opts: {
|
|
503
|
+
client_token: string;
|
|
504
|
+
}): void;
|
|
505
|
+
load(opts: {
|
|
506
|
+
container: string | HTMLElement;
|
|
507
|
+
payment_method_category?: string;
|
|
508
|
+
}, data: Record<string, unknown>, cb?: (res: KpLoadResult) => void): void;
|
|
509
|
+
authorize(opts: {
|
|
510
|
+
payment_method_category?: string;
|
|
511
|
+
auto_finalize?: boolean;
|
|
512
|
+
}, data: Record<string, unknown>, cb?: (res: KpAuthorizeResult) => void): void;
|
|
513
|
+
}
|
|
514
|
+
interface KlarnaGlobal {
|
|
515
|
+
Payments: KlarnaPaymentsApi;
|
|
516
|
+
}
|
|
517
|
+
declare global {
|
|
518
|
+
interface Window {
|
|
519
|
+
Klarna?: KlarnaGlobal;
|
|
520
|
+
klarnaAsyncCallback?: () => void;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Checkout types — multi-sponsor compatible.
|
|
526
|
+
*
|
|
527
|
+
* Each checkout is scoped to a single sponsor (one transaction = one
|
|
528
|
+
* merchant, same as iOS multi-sponsor model). Multiple sponsors → multiple
|
|
529
|
+
* sequential checkouts.
|
|
530
|
+
*/
|
|
531
|
+
type PaymentMethod = 'apple-pay' | 'klarna' | 'vipps' | 'card';
|
|
532
|
+
interface CheckoutAddress {
|
|
533
|
+
firstName: string;
|
|
534
|
+
lastName: string;
|
|
535
|
+
email: string;
|
|
536
|
+
address: string;
|
|
537
|
+
postalCode: string;
|
|
538
|
+
city: string;
|
|
539
|
+
country?: string;
|
|
540
|
+
}
|
|
541
|
+
interface CheckoutState {
|
|
542
|
+
/** Sponsor id whose cart is being checked out. */
|
|
543
|
+
sponsorId: number;
|
|
544
|
+
/** Remote checkout id from Vio Commerce (set after CreateCheckout). */
|
|
545
|
+
remoteId?: string;
|
|
546
|
+
/** Snapshot of the delivery address. */
|
|
547
|
+
address?: CheckoutAddress;
|
|
548
|
+
/** Selected payment method. */
|
|
549
|
+
paymentMethod?: PaymentMethod;
|
|
550
|
+
/** Subtotal at open time (numeric). */
|
|
551
|
+
subtotal: number;
|
|
552
|
+
/** Currency code. */
|
|
553
|
+
currency: string;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* CheckoutManager — orchestrates the checkout flow.
|
|
558
|
+
*
|
|
559
|
+
* Stable contract: open / setAddress / selectPaymentMethod / close.
|
|
560
|
+
* Per-vendor payment integrations plug into the corresponding method:
|
|
561
|
+
* - Apple Pay → `startApplePay()` (Stripe Payment Request, this iteration)
|
|
562
|
+
* - Klarna / Vipps / Card → land in subsequent iterations
|
|
563
|
+
*
|
|
564
|
+
* Dispatches `change` (state changes) and `payment-select` (user picked
|
|
565
|
+
* a method) and `payment-complete` (vendor sheet completed successfully).
|
|
566
|
+
*/
|
|
567
|
+
|
|
568
|
+
interface CheckoutChangeDetail {
|
|
569
|
+
state: CheckoutState | null;
|
|
570
|
+
}
|
|
571
|
+
interface PaymentSelectDetail {
|
|
572
|
+
method: PaymentMethod;
|
|
573
|
+
state: CheckoutState;
|
|
574
|
+
}
|
|
575
|
+
interface PaymentCompleteDetail {
|
|
576
|
+
method: PaymentMethod;
|
|
577
|
+
state: CheckoutState;
|
|
578
|
+
result: ApplePayResult | KlarnaAuthorizeResult | unknown;
|
|
579
|
+
}
|
|
580
|
+
/** Handle for the Klarna Payments (classic widget) flow. */
|
|
581
|
+
interface KlarnaPaymentsHandle {
|
|
582
|
+
/** Categories offered by the session (pay_now / pay_later / pay_over_time). */
|
|
583
|
+
categories: KlarnaPaymentsCategory[];
|
|
584
|
+
/** Currently selected category. */
|
|
585
|
+
readonly selected: string;
|
|
586
|
+
/** (Re)load the widget for a category. */
|
|
587
|
+
load(category?: string): Promise<{
|
|
588
|
+
showForm: boolean;
|
|
589
|
+
}>;
|
|
590
|
+
/** Authorize the selected method and (on approval) create the order. */
|
|
591
|
+
authorize(): Promise<void>;
|
|
592
|
+
/** Tear down the mounted widget. */
|
|
593
|
+
unmount(): void;
|
|
594
|
+
}
|
|
595
|
+
declare class CheckoutManager extends EventTarget {
|
|
596
|
+
private readonly cartManager;
|
|
597
|
+
private state;
|
|
598
|
+
private applePayAvailableCache;
|
|
599
|
+
private klarnaAvailableCache;
|
|
600
|
+
private klarnaOrderInFlight;
|
|
601
|
+
constructor(cartManager: CartManager);
|
|
602
|
+
open(sponsorId: number): CheckoutState;
|
|
603
|
+
close(): void;
|
|
604
|
+
setAddress(address: CheckoutAddress): void;
|
|
605
|
+
selectPaymentMethod(method: PaymentMethod): void;
|
|
606
|
+
/**
|
|
607
|
+
* Returns true if Apple Pay can be shown on this device + Stripe config.
|
|
608
|
+
* Result is memoised — call `clearApplePayCache()` if config changes.
|
|
609
|
+
*/
|
|
610
|
+
isApplePayAvailable(country?: string): Promise<boolean>;
|
|
611
|
+
clearApplePayCache(): void;
|
|
612
|
+
/**
|
|
613
|
+
* Prepare Apple Pay for the product-page express button (no active checkout
|
|
614
|
+
* needed). Pre-creates the Stripe PaymentRequest + resolves canMakePayment so
|
|
615
|
+
* the returned `show()` can fire synchronously inside the tap (Apple blocks
|
|
616
|
+
* the sheet if `show()` is reached after an await). `show()` resolves the
|
|
617
|
+
* sheet, then dispatches `payment-complete` (→ confirmation) or
|
|
618
|
+
* `payment-error`. `available` is true only when Apple Pay will actually work.
|
|
619
|
+
*/
|
|
620
|
+
prepareApplePayFor(amount: number, currency: string, country?: string): Promise<{
|
|
621
|
+
available: boolean;
|
|
622
|
+
show: () => Promise<void>;
|
|
623
|
+
}>;
|
|
624
|
+
/**
|
|
625
|
+
* Prepare an Apple Pay express charge for an arbitrary amount (e.g. the whole
|
|
626
|
+
* cart) with NO active checkout. Unlike `prepareApplePayFor`, the returned
|
|
627
|
+
* `show()` RESOLVES with the result (or `null` on cancel/failure) and does
|
|
628
|
+
* NOT dispatch the global `payment-complete` — so no checkout overlay appears.
|
|
629
|
+
* The caller (the cart drawer) renders its own confirmation. `show()` must be
|
|
630
|
+
* called synchronously inside the tap (Apple's user-gesture rule).
|
|
631
|
+
*/
|
|
632
|
+
prepareApplePayExpress(amount: number, currency: string, country?: string): Promise<{
|
|
633
|
+
available: boolean;
|
|
634
|
+
show: () => Promise<ApplePayResult | null>;
|
|
635
|
+
}>;
|
|
636
|
+
/**
|
|
637
|
+
* Launches the Apple Pay sheet. Resolves with the Stripe PaymentMethod
|
|
638
|
+
* id once the user authorises — the backend then confirms the
|
|
639
|
+
* PaymentIntent with that id to actually capture the funds.
|
|
640
|
+
*/
|
|
641
|
+
startApplePay(options?: {
|
|
642
|
+
country?: string;
|
|
643
|
+
label?: string;
|
|
644
|
+
}): Promise<ApplePayResult>;
|
|
645
|
+
/**
|
|
646
|
+
* True if the Klarna Express button can be offered (clientId configured +
|
|
647
|
+
* SDK loads). Memoised per active checkout. Never throws.
|
|
648
|
+
*/
|
|
649
|
+
isKlarnaExpressAvailable(): Promise<boolean>;
|
|
650
|
+
clearKlarnaCache(): void;
|
|
651
|
+
/**
|
|
652
|
+
* Build the Klarna payment request from the active cart — amounts in the
|
|
653
|
+
* currency's minor unit (øre/cents), one line item per cart line.
|
|
654
|
+
*/
|
|
655
|
+
buildKlarnaPaymentRequest(): KlarnaPaymentRequestData;
|
|
656
|
+
/**
|
|
657
|
+
* Mount the Klarna Express button into `container`. On a successful
|
|
658
|
+
* authorization, fires `payment-complete` with the authorization token —
|
|
659
|
+
* the host (or vio-backend) then creates the Klarna order server-side.
|
|
660
|
+
*
|
|
661
|
+
* Returns the button handle so the UI can unmount on teardown.
|
|
662
|
+
*/
|
|
663
|
+
mountKlarnaExpress(container: HTMLElement): Promise<KlarnaButtonHandle>;
|
|
664
|
+
/**
|
|
665
|
+
* Klarna Payments — classic widget flow (server client_token). Creates a
|
|
666
|
+
* session on vio-backend, then mounts Klarna's inline widget into
|
|
667
|
+
* `container`. Returns a handle to switch category and to authorize → which
|
|
668
|
+
* on approval creates the order via the same backend /orders route as KEC.
|
|
669
|
+
*
|
|
670
|
+
* Unlike `mountKlarnaExpress`, this needs no public `klarnaClientId` and no
|
|
671
|
+
* origin handshake — auth is the server-side API key.
|
|
672
|
+
*/
|
|
673
|
+
mountKlarnaPayments(container: HTMLElement, opts?: {
|
|
674
|
+
withShipping?: boolean;
|
|
675
|
+
shippingId?: string;
|
|
676
|
+
}): Promise<KlarnaPaymentsHandle>;
|
|
677
|
+
/** True if the Klarna Payments widget lib can load (UI gate). */
|
|
678
|
+
klarnaPaymentsAvailable(): Promise<boolean>;
|
|
679
|
+
/** Cart snapshot + chosen shipping line/amount, for express purchases. */
|
|
680
|
+
private buildKlarnaInstantContext;
|
|
681
|
+
/**
|
|
682
|
+
* Express instant purchase — go straight to Klarna's own modal, no checkout
|
|
683
|
+
* overlay. Creates a session (with shipping options), loads the widget into a
|
|
684
|
+
* hidden container, then authorizes (which opens Klarna's confirm modal). On
|
|
685
|
+
* approval creates the order → `payment-complete` (host shows confirmation);
|
|
686
|
+
* on failure → `payment-error`. Call `open(sponsorId)` first.
|
|
687
|
+
*/
|
|
688
|
+
startKlarnaInstant(): Promise<void>;
|
|
689
|
+
/**
|
|
690
|
+
* REDIRECT path: call once on app load. If a Klarna purchase was launched
|
|
691
|
+
* (pending context persisted) and we're back with a token — from the URL or
|
|
692
|
+
* the SDK's resumed `complete` event — finish creating the order + confirm.
|
|
693
|
+
*/
|
|
694
|
+
resumeKlarnaReturn(): Promise<void>;
|
|
695
|
+
/** Snapshot of the active cart for redirect recovery (minor units). */
|
|
696
|
+
private buildKlarnaPendingContext;
|
|
697
|
+
/**
|
|
698
|
+
* POST the token + order lines to vio-backend (it holds the secret API key
|
|
699
|
+
* and creates the real Klarna order). On success → `payment-complete`; on
|
|
700
|
+
* failure → `payment-error`. Idempotent: clears the pending key so the
|
|
701
|
+
* popup and redirect paths can't double-fire.
|
|
702
|
+
*/
|
|
703
|
+
private completeKlarnaOrder;
|
|
704
|
+
get currentState(): CheckoutState | null;
|
|
705
|
+
get items(): CartLineItem[];
|
|
706
|
+
/**
|
|
707
|
+
* Resolve the Stripe Connect account for the active sponsor — for now
|
|
708
|
+
* pulled from bootstrap cache if present. Returns undefined if not set
|
|
709
|
+
* (Stripe will route to the platform account in that case).
|
|
710
|
+
*/
|
|
711
|
+
private findStripeConnectAccount;
|
|
712
|
+
private emit;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
declare class VioFacade {
|
|
716
|
+
private apiInstance;
|
|
717
|
+
private commerceClients;
|
|
718
|
+
private bootstrapPromise;
|
|
719
|
+
private cachedBootstrap;
|
|
720
|
+
private cartManager;
|
|
721
|
+
private checkoutManager;
|
|
722
|
+
init(config: VioConfig): void;
|
|
723
|
+
get isInitialized(): boolean;
|
|
724
|
+
get config(): ResolvedConfig;
|
|
725
|
+
/** Multi-sponsor cart manager. Reactive — listen via addEventListener('change', ...). */
|
|
726
|
+
get cart(): CartManager;
|
|
727
|
+
/** Checkout flow manager. Subscribes to cart state via the CartManager. */
|
|
728
|
+
get checkout(): CheckoutManager;
|
|
729
|
+
/** Lazy VioApi for REST endpoints on `api-dev.vio.live`. */
|
|
730
|
+
get api(): VioApi;
|
|
731
|
+
/**
|
|
732
|
+
* Bootstrap — fetches client config and caches it. Dedupes in-flight
|
|
733
|
+
* concurrent requests.
|
|
734
|
+
*/
|
|
735
|
+
bootstrap(): Promise<BootstrapResponse>;
|
|
736
|
+
get bootstrapCache(): BootstrapResponse | null;
|
|
737
|
+
/**
|
|
738
|
+
* Get a CommerceClient scoped to a specific sponsor (via bootstrap).
|
|
739
|
+
* Throws if bootstrap hasn't been called or the sponsor is unknown.
|
|
740
|
+
*/
|
|
741
|
+
commerceFor(sponsorId: number): CommerceClient;
|
|
742
|
+
/** Get a CommerceClient using an explicit commerce apiKey (skip bootstrap). */
|
|
743
|
+
commerceWithKey(commerceApiKey: string): CommerceClient;
|
|
744
|
+
private findSponsor;
|
|
745
|
+
}
|
|
746
|
+
declare const Vio: VioFacade;
|
|
747
|
+
|
|
748
|
+
export { type AddManualOptions, type AddProductOptions, type ApplePayConfig, type ApplePayResult, type BootstrapResponse, type CartChangeDetail, type CartLineItem, CartManager, type CheckoutAddress, type CheckoutChangeDetail, CheckoutManager, type CheckoutState, CommerceClient, Configuration, type Environment, type ImageSize, type PaymentCompleteDetail, type PaymentMethod, type PaymentSelectDetail, type PlacementComponent, type Product, type ProductCategory, type ProductImage, type ProductOption, type ProductPrice, type ProductVariant, type ResolvedConfig, type Sponsor, type SponsorCartState, type SponsorCommerceBlock, Vio, VioApi, VioApiError, type VioConfig, checkApplePayAvailability, createCommerceClient, createVioApi, displayPrice, formatPrice, primaryImageUrl, showApplePaySheet };
|