@vio-live/web-sdk 0.24.0 → 0.26.1
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 +132 -13
- package/dist/{chunk-N6U65DWG.js → chunk-6Q2M3MIK.js} +147 -41
- package/dist/chunk-6Q2M3MIK.js.map +1 -0
- package/dist/chunk-NCP76AXW.js +3 -0
- package/dist/{chunk-45YKS5UG.js.map → chunk-NCP76AXW.js.map} +1 -1
- package/dist/{chunk-AXJKB2CW.js → chunk-NXIYIY2D.js} +959 -140
- package/dist/chunk-NXIYIY2D.js.map +1 -0
- package/dist/core/index.d.ts +1695 -1102
- package/dist/core/index.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/{tokens-C3qiGvLV.d.ts → tokens-Bn7fK9ta.d.ts} +42 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +2 -1
- package/dist/chunk-45YKS5UG.js +0 -3
- package/dist/chunk-AXJKB2CW.js.map +0 -1
- package/dist/chunk-N6U65DWG.js.map +0 -1
package/dist/core/index.d.ts
CHANGED
|
@@ -47,6 +47,14 @@ interface VioConfig {
|
|
|
47
47
|
campaignId?: number;
|
|
48
48
|
/** Log the SDK's slot/attribution decisions at `console.debug` (manifest assignments per slot). */
|
|
49
49
|
debug?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The surface's privacy mode, when the host knows it (ADR-0035): `minimal`
|
|
52
|
+
* keeps the entry context (referrer, utm, landing page) off the order
|
|
53
|
+
* attribution. Without it the SDK asks the surface itself
|
|
54
|
+
* (`GET /v2/mobile/surface`), once per page load; a host-set `minimal`
|
|
55
|
+
* always wins.
|
|
56
|
+
*/
|
|
57
|
+
privacyMode?: 'standard' | 'minimal';
|
|
50
58
|
/** Override REST API base. Defaults are env-aware. */
|
|
51
59
|
apiBase?: string;
|
|
52
60
|
/** Override GraphQL base. Defaults are env-aware. */
|
|
@@ -84,6 +92,7 @@ interface ResolvedConfig {
|
|
|
84
92
|
contentTitle?: string;
|
|
85
93
|
campaignId?: number;
|
|
86
94
|
debug: boolean;
|
|
95
|
+
privacyMode?: 'standard' | 'minimal';
|
|
87
96
|
apiBase: string;
|
|
88
97
|
graphQLBase: string;
|
|
89
98
|
eventsBase: string;
|
|
@@ -234,7 +243,15 @@ interface BootstrapResponse {
|
|
|
234
243
|
webSocketBase?: string;
|
|
235
244
|
commerceGraphQL?: string;
|
|
236
245
|
};
|
|
237
|
-
|
|
246
|
+
/**
|
|
247
|
+
* `null` when the surface has no active campaign: a web, custom-web or Vev
|
|
248
|
+
* page then keeps selling with the sponsors of the surface's channels
|
|
249
|
+
* (`noActiveCampaign: true`, `campaigns: []`), and nothing it sells carries
|
|
250
|
+
* a campaign. Native apps get a 404 instead.
|
|
251
|
+
*/
|
|
252
|
+
campaign?: BootstrapCampaign | null;
|
|
253
|
+
/** True when `campaign` is null on purpose: no campaign is active on the surface. */
|
|
254
|
+
noActiveCampaign?: boolean;
|
|
238
255
|
primarySponsor?: Sponsor;
|
|
239
256
|
secondarySponsors?: Sponsor[];
|
|
240
257
|
features?: {
|
|
@@ -246,6 +263,12 @@ interface BootstrapResponse {
|
|
|
246
263
|
countryCode: string;
|
|
247
264
|
currencyCode: string;
|
|
248
265
|
};
|
|
266
|
+
/**
|
|
267
|
+
* The surface of the key, when the bootstrap says it (the campaigns
|
|
268
|
+
* service answers it on `/v2/mobile/surface` today; here when it adds it).
|
|
269
|
+
* Its `privacyMode` decides what the order attribution may carry.
|
|
270
|
+
*/
|
|
271
|
+
surface?: SurfaceResponse['surface'];
|
|
249
272
|
}
|
|
250
273
|
/**
|
|
251
274
|
* A slot this page declares to the campaigns service (ADR-0027 / ADR-0034):
|
|
@@ -257,6 +280,8 @@ interface ManifestLocation {
|
|
|
257
280
|
displayName?: string;
|
|
258
281
|
/** The campaign this location belongs to when it differs from the page's (`ManifestRequest.campaignId`). */
|
|
259
282
|
campaignId?: number;
|
|
283
|
+
/** The kind of element the slot holds — `card` | `carousel` | `detail` for the SDK's, a host's own word otherwise. For the dashboard. */
|
|
284
|
+
kind?: string;
|
|
260
285
|
}
|
|
261
286
|
/**
|
|
262
287
|
* Where something happened, as `Vio.attribution(slot)` answers it — the ONE
|
|
@@ -271,6 +296,29 @@ interface Attribution {
|
|
|
271
296
|
sponsorId?: number;
|
|
272
297
|
contentId?: string;
|
|
273
298
|
contentTitle?: string;
|
|
299
|
+
/** The page's URL within the 2 048 cap (`content_url`) — what Commerce keeps on the order and its lines. */
|
|
300
|
+
contentUrl?: string;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* How much context analytics and Commerce may keep of a visit to this
|
|
304
|
+
* surface. `minimal` drops what says WHICH screen someone was on and WHY —
|
|
305
|
+
* the page (`content_url`, `content_title`), the slot (`location_id`) and
|
|
306
|
+
* the entry (referrer, utm, landing page) — the collector drops it from the
|
|
307
|
+
* events on its side (vio-analytics `privacy.ts`); the SDK keeps it off the
|
|
308
|
+
* order and off the cart lines it sends to Commerce. What measures the
|
|
309
|
+
* funnel and bills the sale stays: the surface, the campaign, the kind of
|
|
310
|
+
* component, the products and the amounts. A mode the SDK could not learn
|
|
311
|
+
* counts as `minimal`.
|
|
312
|
+
*/
|
|
313
|
+
type SurfacePrivacyMode = 'standard' | 'minimal';
|
|
314
|
+
/** Response of `GET /v2/mobile/surface`: what the key may know of its own surface. */
|
|
315
|
+
interface SurfaceResponse {
|
|
316
|
+
surface?: {
|
|
317
|
+
id?: number;
|
|
318
|
+
name?: string;
|
|
319
|
+
status?: string;
|
|
320
|
+
privacyMode?: SurfacePrivacyMode | string | null;
|
|
321
|
+
} | null;
|
|
274
322
|
}
|
|
275
323
|
/** Body of `POST /v2/mobile/components/manifest`. */
|
|
276
324
|
interface ManifestRequest {
|
|
@@ -382,6 +430,12 @@ declare class VioApi {
|
|
|
382
430
|
* sends `mode: 'merge'`; see `Vio.declareSlots()` for the dedupe on top.
|
|
383
431
|
*/
|
|
384
432
|
declareManifest(body: ManifestRequest): Promise<ManifestResult>;
|
|
433
|
+
/**
|
|
434
|
+
* The surface of the key (`GET /v2/mobile/surface`): its id, name, status
|
|
435
|
+
* and `privacyMode` — what decides whether the order attribution may carry
|
|
436
|
+
* the entry context (ADR-0035). A 404 means a service that predates it.
|
|
437
|
+
*/
|
|
438
|
+
surface(): Promise<SurfaceResponse>;
|
|
385
439
|
/**
|
|
386
440
|
* Get placement components for a campaign. Used by the carousel auto-fetch
|
|
387
441
|
* mode (`<vio-product-carousel campaign-id="36" location="news-favorites">`).
|
|
@@ -469,15 +523,29 @@ declare function createCommerceClient(options: CommerceClientOptions): CommerceC
|
|
|
469
523
|
* mental model stays consistent across platforms.
|
|
470
524
|
*/
|
|
471
525
|
/**
|
|
472
|
-
* Where a unit in the cart came from (ADR-0027 / ADR-0034): the
|
|
473
|
-
* the place showed when it was added, the place (`slot`)
|
|
474
|
-
*
|
|
475
|
-
* title.
|
|
526
|
+
* Where a unit in the cart came from (ADR-0027 / ADR-0034 / ADR-0035): the
|
|
527
|
+
* campaign the place showed when it was added, the place (`slot`), the kind
|
|
528
|
+
* of element it was added from, and the content (article: its id, URL and
|
|
529
|
+
* title). What `Vio.attribution(slot)` answers, minus the sponsor, plus the
|
|
530
|
+
* element's kind. The purchase is split per campaign from these, and since
|
|
531
|
+
* 0.26 Commerce receives them with every add (`origin` on the line, ADR-0035
|
|
532
|
+
* phase B) so the order knows where each unit was sold from.
|
|
476
533
|
*/
|
|
477
534
|
interface CartOrigin {
|
|
478
535
|
campaignId?: number;
|
|
479
536
|
slot?: string;
|
|
480
537
|
contentId?: string;
|
|
538
|
+
/**
|
|
539
|
+
* The kind of component the units were added from, as Commerce and the
|
|
540
|
+
* collector name it: `card` | `carousel` | `detail` for the SDK's elements
|
|
541
|
+
* (`componentKindOf()` — from the element's `componentTemplateId`, else
|
|
542
|
+
* the kind word in the slot id).
|
|
543
|
+
*/
|
|
544
|
+
componentKind?: string;
|
|
545
|
+
/** The page the units were added from (`content_url`, ≤ 2 048), kept so a later +1 from the cart credits the same page. */
|
|
546
|
+
contentUrl?: string;
|
|
547
|
+
/** Its title (`content_title`, ≤ 255). */
|
|
548
|
+
contentTitle?: string;
|
|
481
549
|
}
|
|
482
550
|
/** One origin of a line and how many of its units came from it. */
|
|
483
551
|
interface CartLineOrigin extends CartOrigin {
|
|
@@ -538,9 +606,10 @@ interface SponsorCartState {
|
|
|
538
606
|
* CustomEvent that UI components subscribe to (Web Components react via
|
|
539
607
|
* `requestUpdate()`).
|
|
540
608
|
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
609
|
+
* The backend cart (Vio Commerce GraphQL CreateCart / AddItem / UpdateItem /
|
|
610
|
+
* DeleteItem) is kept in sync optimistically from here; since 0.26 every add
|
|
611
|
+
* and every increase tells it where the units come from (`origin`, ADR-0035
|
|
612
|
+
* phase B) so the order is born attributed — see `origin-wire.ts`.
|
|
544
613
|
*/
|
|
545
614
|
|
|
546
615
|
interface CartChangeDetail {
|
|
@@ -689,12 +758,15 @@ declare class CartManager extends EventTarget {
|
|
|
689
758
|
origin?: CartOrigin;
|
|
690
759
|
}): void;
|
|
691
760
|
/** Send a line's target quantity to the backend — ONE request in flight per
|
|
692
|
-
* line.
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
696
|
-
*
|
|
697
|
-
*
|
|
761
|
+
* line. Targets that arrive while one is in flight queue behind it as
|
|
762
|
+
* steps (`queueStep`): reduced like the line's origins, sent in order once
|
|
763
|
+
* the current request settles — one request per queued increase from a
|
|
764
|
+
* different origin, one for a net decrease — so the server ends on the
|
|
765
|
+
* last intent, credits every increase to its own origin, and never sees two
|
|
766
|
+
* updates racing each other. While the sync is active the line keeps its
|
|
767
|
+
* optimistic quantity through any backend response (see
|
|
768
|
+
* `updateFromBackendCart`); a rejection drops what was queued and
|
|
769
|
+
* reconciles the cart from the server. */
|
|
698
770
|
private syncQuantity;
|
|
699
771
|
removeItem(lineItemId: string, sponsorId: number): void;
|
|
700
772
|
clearSponsorCart(sponsorId: number): void;
|
|
@@ -719,9 +791,15 @@ declare class CartManager extends EventTarget {
|
|
|
719
791
|
private loadFromStorage;
|
|
720
792
|
private emit;
|
|
721
793
|
}
|
|
722
|
-
/**
|
|
794
|
+
/**
|
|
795
|
+
* Only the attribution fields, trimmed; `{}` when nothing is known. The kind
|
|
796
|
+
* of element is kept as Commerce and the collector name it (`card`,
|
|
797
|
+
* `carousel`, `detail` — `componentKindOf`), from `componentKind` or from
|
|
798
|
+
* the `componentTemplateId` an element's attribution carries (`product-card`);
|
|
799
|
+
* the page as origin + path (`contentUrl`) and its title, within Commerce's caps.
|
|
800
|
+
*/
|
|
723
801
|
declare function normalizeOrigin(origin: CartOrigin | null | undefined): CartOrigin;
|
|
724
|
-
/** Two origins are the same place when campaign, slot and
|
|
802
|
+
/** Two origins are the same place when campaign, slot, content and kind of element all match (the page's URL and title are attributes of the place, not its identity). */
|
|
725
803
|
declare function sameOrigin(a: CartOrigin, b: CartOrigin): boolean;
|
|
726
804
|
/**
|
|
727
805
|
* The origins of a line for reporting: what it carries, plus an empty origin
|
|
@@ -731,610 +809,1405 @@ declare function sameOrigin(a: CartOrigin, b: CartOrigin): boolean;
|
|
|
731
809
|
declare function lineOrigins(line: Pick<CartLineItem, 'origins' | 'quantity'>): CartLineOrigin[];
|
|
732
810
|
|
|
733
811
|
/**
|
|
734
|
-
*
|
|
735
|
-
*
|
|
736
|
-
* Vipps payment integration uses 2 GraphQL operations:
|
|
812
|
+
* What the commerce gateway may not know yet.
|
|
737
813
|
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
814
|
+
* The SDK ships ahead of the gateway more than once a quarter: a selection
|
|
815
|
+
* (`buyer_ref`, 2026-10-19), an argument (`origin` on the cart lines,
|
|
816
|
+
* `attribution` on the checkout — ADR-0035 phase B). A gateway that does not
|
|
817
|
+
* have the field refuses the WHOLE operation at validation — before anything
|
|
818
|
+
* runs, with no `data` — so each such operation is sent again without the
|
|
819
|
+
* field, once, and the answer remembered for the page load. An operation that
|
|
820
|
+
* DID run and failed is never repeated: for a mutation that would be a second
|
|
821
|
+
* charge, a second line in the cart.
|
|
740
822
|
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
823
|
+
* One mechanism for all of them, so the next field costs a token here and a
|
|
824
|
+
* call to `withGatewayFeature`, not a new copy of the retry.
|
|
743
825
|
*/
|
|
744
|
-
|
|
826
|
+
type GatewayFeature = 'buyer_ref' | 'line_origin' | 'checkout_attribution';
|
|
827
|
+
/** Whether this page load still expects the gateway to know `feature` (false once it refused it). */
|
|
828
|
+
declare function gatewayHas(feature: GatewayFeature): boolean;
|
|
829
|
+
/** Forget what this page load learned (tests). One feature, or all of them. */
|
|
830
|
+
declare function resetGatewayFeatures(feature?: GatewayFeature): void;
|
|
745
831
|
/**
|
|
746
|
-
*
|
|
832
|
+
* True when `err` is the gateway refusing something it does not know, named
|
|
833
|
+
* `token` (`Cannot query field "buyer_ref" on type …`, `Unknown argument
|
|
834
|
+
* "origin" on field …`, `Unknown type "CartLineOriginInput"`, `Field "origin" is
|
|
835
|
+
* not defined by type "LineItemInput"`): a validation error, with no `data`
|
|
836
|
+
* and no `path` because nothing ran — safe to send again without it, a
|
|
837
|
+
* mutation included. Anything that ran (data present, or an error with a
|
|
838
|
+
* path) or any other message is not.
|
|
747
839
|
*/
|
|
748
|
-
declare
|
|
840
|
+
declare function isUnknownTokenError(err: unknown, token: string): boolean;
|
|
841
|
+
/** `isUnknownTokenError` for any of the names a feature goes by. */
|
|
842
|
+
declare function isUnknownFeatureError(err: unknown, feature: GatewayFeature): boolean;
|
|
749
843
|
/**
|
|
750
|
-
*
|
|
844
|
+
* Runs `request(true)` (the operation with the feature); when the gateway
|
|
845
|
+
* does not know it, `request(false)` (without it) — and from then on, for
|
|
846
|
+
* this page load, straight to the latter. Said once in the console: a
|
|
847
|
+
* gateway behind the SDK is worth knowing about, and so is a renamed type.
|
|
751
848
|
*/
|
|
752
|
-
declare
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
849
|
+
declare function withGatewayFeature<T>(feature: GatewayFeature, request: (supported: boolean) => Promise<T>): Promise<T>;
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* A line origin as Commerce receives it (ADR-0035 phase B): `origin` on each
|
|
853
|
+
* line of `AddItem` and, when the quantity goes UP, on `UpdateItem` — the
|
|
854
|
+
* origin of the units that update adds. shopcart keeps every origin of a
|
|
855
|
+
* line with its units (`cart_item.origins`) and writes the order from them:
|
|
856
|
+
* `order_item.campaign_id` / `location_id` / `component_kind`, and the
|
|
857
|
+
* order's page when the checkout does not name one.
|
|
858
|
+
*
|
|
859
|
+
* snake_case on the wire, the caps of shopcart's `LineOriginDto` enforced
|
|
860
|
+
* here, once. Pure: `lineOriginWire()` takes the origin and the page.
|
|
861
|
+
*/
|
|
862
|
+
|
|
863
|
+
/** The largest `Int` GraphQL coerces; a bigger id would fail the whole mutation. */
|
|
864
|
+
declare const GRAPHQL_INT_MAX = 2147483647;
|
|
865
|
+
/** `LineOriginDto` (shopcart `cart/dtos/send/line-origin.dto.ts`). */
|
|
866
|
+
interface LineOriginWire {
|
|
867
|
+
campaign_id?: number;
|
|
868
|
+
location_id?: string;
|
|
869
|
+
component_kind?: string;
|
|
870
|
+
content_url?: string;
|
|
871
|
+
content_title?: string;
|
|
872
|
+
}
|
|
873
|
+
/** The caps of `LineOriginDto` — a longer value is refused whole by the API, so it is cut here. */
|
|
874
|
+
declare const LINE_ORIGIN_CAPS: Readonly<{
|
|
875
|
+
locationId: 100;
|
|
876
|
+
componentKind: 32;
|
|
877
|
+
contentUrl: 2048;
|
|
878
|
+
contentTitle: 255;
|
|
879
|
+
}>;
|
|
880
|
+
/** The page the units are added from, for an origin that does not carry its own. */
|
|
881
|
+
interface OriginPage {
|
|
882
|
+
contentUrl?: string;
|
|
883
|
+
contentTitle?: string;
|
|
884
|
+
}
|
|
885
|
+
interface LineOriginWireOptions {
|
|
886
|
+
/** The current page, for an origin that does not carry its own. */
|
|
887
|
+
page?: OriginPage;
|
|
758
888
|
/**
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
889
|
+
* The surface's privacy mode. Only on a `standard` surface do the slot
|
|
890
|
+
* (`location_id`) and the page (`content_url`, `content_title`) travel —
|
|
891
|
+
* which screen a unit was sold from is what `minimal` keeps private, the
|
|
892
|
+
* same promise the collector keeps for the events. `campaign_id` and
|
|
893
|
+
* `component_kind` always do. Default `unknown`: fail closed.
|
|
763
894
|
*/
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
interface CreatePaymentVippsResponse {
|
|
767
|
-
/** Absent when Express was asked for and refused. */
|
|
768
|
-
payment_url?: string;
|
|
769
|
-
/** The reference the seller reads in its Vipps portal. */
|
|
770
|
-
reference?: string;
|
|
771
|
-
express?: boolean;
|
|
772
|
-
reason?: string;
|
|
773
|
-
}
|
|
774
|
-
interface GetVippsStatusVariables extends Record<string, unknown> {
|
|
775
|
-
checkoutId: string;
|
|
776
|
-
}
|
|
777
|
-
interface VippsStatusResult {
|
|
778
|
-
state: string;
|
|
779
|
-
/** Set when this checkout was closed as a duplicate: the checkout that paid the cart. */
|
|
780
|
-
duplicate_of?: string | null;
|
|
895
|
+
privacyMode?: SurfacePrivacyMode | 'unknown';
|
|
781
896
|
}
|
|
782
|
-
type VippsPaymentState = 'CREATED' | 'INITIATED' | 'AUTHORIZED' | 'TERMINATED' | 'EXPIRED' | string;
|
|
783
897
|
/**
|
|
784
|
-
*
|
|
898
|
+
* The origin for the wire, or `undefined` when the SDK knows no PLACE for the
|
|
899
|
+
* units — no campaign, no slot, no kind of element (a host adding with no
|
|
900
|
+
* attribution): then nothing is sent and the line inherits the order's
|
|
901
|
+
* campaign on the server. The page is the origin's own when it has one — the
|
|
902
|
+
* page the units were added from — else the current page's, as origin + path;
|
|
903
|
+
* `campaign_id` only as a positive `Int` (the DTO's `@IsInt() @Min(1)`, the
|
|
904
|
+
* gateway's 32-bit coercion).
|
|
785
905
|
*/
|
|
786
|
-
declare function
|
|
906
|
+
declare function lineOriginWire(origin: CartOrigin | null | undefined, options?: LineOriginWireOptions): LineOriginWire | undefined;
|
|
907
|
+
|
|
787
908
|
/**
|
|
788
|
-
*
|
|
909
|
+
* The `client` block — the standard context of the visit (EVENTS_CONTRACT
|
|
910
|
+
* "client", 2026-10-19): language, where the session landed from (the
|
|
911
|
+
* referrer and `utm_*` of the LANDING page, remembered for the session),
|
|
912
|
+
* screen size and time zone. What the collector derives from the request
|
|
913
|
+
* itself — device type, OS, browser, country — is NOT sent: no User-Agent
|
|
914
|
+
* parsing here, no duplicate of what the server knows better.
|
|
915
|
+
*
|
|
916
|
+
* Pure like `content.ts`: everything takes the globals it reads (defaults to
|
|
917
|
+
* the real ones), never throws, and answers `{}` where there is no browser
|
|
918
|
+
* (SSR, old engines). Capped to the collector's limits in ONE place: an
|
|
919
|
+
* over-long value is cut — none of these is an identity, so a cut referrer
|
|
920
|
+
* is still the right dimension.
|
|
921
|
+
*
|
|
922
|
+
* Landing memory: the first page of a session writes its referrer and utm
|
|
923
|
+
* parameters to `sessionStorage`; later pages read them back, so an event on
|
|
924
|
+
* page three still says the visit came from the newsletter — their own
|
|
925
|
+
* `document.referrer` (an internal page) is never a source. The referrer is
|
|
926
|
+
* kept as origin + path (no query, no fragment: a referrer's query is its
|
|
927
|
+
* tracking tail, not where the visit came from) and dropped altogether when
|
|
928
|
+
* it is this same host (a self-referral says nothing about the entry). A URL
|
|
929
|
+
* with utm parameters is a new landing (another campaign click) that replaces
|
|
930
|
+
* the memory — unless it was reached from this same host, i.e. an internal
|
|
931
|
+
* link that propagates utm, which keeps the landing that was. Without
|
|
932
|
+
* storage, or without consent to persist, each page stands alone.
|
|
789
933
|
*/
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
declare const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
apiKey?: string;
|
|
807
|
-
/** Sponsor commerce key — goes in the Authorization header. */
|
|
808
|
-
commerceKey?: string;
|
|
809
|
-
/** True when the commerce key came from a resolved sponsor (bootstrap).
|
|
810
|
-
* False = we fell back to the host apiKey — writes like CreateCart should
|
|
811
|
-
* NOT proceed with the wrong key (the cart would be orphaned). */
|
|
812
|
-
sponsorResolved?: boolean;
|
|
813
|
-
}
|
|
934
|
+
interface ClientContext {
|
|
935
|
+
language?: string;
|
|
936
|
+
referrer?: string;
|
|
937
|
+
utm_source?: string;
|
|
938
|
+
utm_medium?: string;
|
|
939
|
+
utm_campaign?: string;
|
|
940
|
+
utm_term?: string;
|
|
941
|
+
utm_content?: string;
|
|
942
|
+
screen_w?: number;
|
|
943
|
+
screen_h?: number;
|
|
944
|
+
tz?: string;
|
|
945
|
+
}
|
|
946
|
+
declare const UTM_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
|
|
947
|
+
type UtmKey = (typeof UTM_KEYS)[number];
|
|
948
|
+
/** Commerce's cap for the landing page on the order's entry context (`entry.landing_url`, ADR-0035). */
|
|
949
|
+
declare const CLIENT_LANDING_URL_MAX_LENGTH = 2048;
|
|
814
950
|
/**
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
951
|
+
* What a session remembers of the page it landed on. `url` is the landing
|
|
952
|
+
* page itself — origin + path, like the referrer: no query (the utm are kept
|
|
953
|
+
* apart, the rest is a tracking tail), no fragment — for the order's entry
|
|
954
|
+
* context; the events do not carry it (the collector derives the landing).
|
|
819
955
|
*/
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
956
|
+
interface Landing {
|
|
957
|
+
referrer?: string;
|
|
958
|
+
utm?: Partial<Record<UtmKey, string>>;
|
|
959
|
+
url?: string;
|
|
960
|
+
}
|
|
961
|
+
interface StorageLike {
|
|
962
|
+
getItem(key: string): string | null;
|
|
963
|
+
setItem(key: string, value: string): void;
|
|
964
|
+
removeItem?(key: string): void;
|
|
965
|
+
}
|
|
966
|
+
/** The globals the block is read from — injectable for tests; defaults to the real ones. */
|
|
967
|
+
interface ClientEnvironment {
|
|
968
|
+
navigator?: {
|
|
969
|
+
language?: unknown;
|
|
970
|
+
} | null;
|
|
971
|
+
document?: {
|
|
972
|
+
referrer?: unknown;
|
|
973
|
+
} | null;
|
|
974
|
+
location?: {
|
|
975
|
+
search?: unknown;
|
|
976
|
+
host?: unknown;
|
|
977
|
+
href?: unknown;
|
|
978
|
+
} | null;
|
|
979
|
+
screen?: {
|
|
980
|
+
width?: unknown;
|
|
981
|
+
height?: unknown;
|
|
982
|
+
} | null;
|
|
983
|
+
/** The session memory for the landing; `null` = none (SSR, private mode, blocked). */
|
|
984
|
+
storage?: StorageLike | null;
|
|
985
|
+
/** The time zone; defaults to `Intl.DateTimeFormat().resolvedOptions().timeZone`. */
|
|
986
|
+
timeZone?: () => unknown;
|
|
828
987
|
}
|
|
829
|
-
/**
|
|
830
|
-
*
|
|
831
|
-
*
|
|
832
|
-
*
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
declare function
|
|
836
|
-
|
|
837
|
-
declare function
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
declare function
|
|
845
|
-
|
|
846
|
-
declare function
|
|
988
|
+
/**
|
|
989
|
+
* The landing of this session: what is remembered — unless this page is a
|
|
990
|
+
* landing itself (utm parameters in its URL, reached from outside this host)
|
|
991
|
+
* or nothing is remembered yet, when this page's referrer and utm are taken
|
|
992
|
+
* (and, with `persist`, kept).
|
|
993
|
+
*/
|
|
994
|
+
declare function resolveLanding(env?: ClientEnvironment, persist?: boolean): Landing;
|
|
995
|
+
/** The landing page as the landing keeps it: origin + path, no query, no fragment; capped. */
|
|
996
|
+
declare function landingUrl(raw: unknown): string | undefined;
|
|
997
|
+
/**
|
|
998
|
+
* The landing this session REMEMBERS — what was written by the first page —
|
|
999
|
+
* or null when nothing is stored (no storage, no consent, analytics never
|
|
1000
|
+
* started). Read only: for the order's entry context, which must not take the
|
|
1001
|
+
* page the shopper pays on for the page they came in through.
|
|
1002
|
+
*/
|
|
1003
|
+
declare function storedLanding(storage?: StorageLike | null | undefined): Landing | null;
|
|
1004
|
+
/** The block for the wire — read once per page load by the manager and reused on every event. */
|
|
1005
|
+
declare function resolveClientContext(env?: ClientEnvironment, landing?: Landing): ClientContext;
|
|
847
1006
|
|
|
848
1007
|
/**
|
|
849
|
-
*
|
|
1008
|
+
* Slots — the pure half of ADR-0027 / ADR-0034 on the web.
|
|
850
1009
|
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
1010
|
+
* A slot is a NAME for a place on a page. The page declares its slots to the
|
|
1011
|
+
* campaigns service (`Vio.declareSlots()` / `Vio.registerSlot()` in client.ts),
|
|
1012
|
+
* the dashboard assigns a campaign to each one, optionally with a date window,
|
|
1013
|
+
* and `GET /v2/mobile/config` answers with `campaigns[].slots[]` — only the
|
|
1014
|
+
* assignments whose window is open NOW. Whatever no slot names shows the
|
|
1015
|
+
* surface's default campaign (`campaign`).
|
|
853
1016
|
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
* seller's when they brought both keys, ours otherwise. The two are
|
|
858
|
-
* halves of one account: the browser confirms with the key what the
|
|
859
|
-
* server minted with the secret one.
|
|
860
|
-
* 2. Stripe's Payment Element is mounted in a LIGHT-DOM container, the way
|
|
861
|
-
* the other embedded widgets are. Card fields are Stripe's own iframes,
|
|
862
|
-
* so card data never touches this SDK or our servers.
|
|
863
|
-
* 3. `confirm()` pays. A 3-D Secure challenge opens in Stripe's own modal
|
|
864
|
-
* over the page: `redirect: 'if_required'` keeps the shopper here for
|
|
865
|
-
* cards, and still redirects for a method that has no other way.
|
|
866
|
-
* 4. The Commerce order is NOT born here. Stripe's `payment_intent.succeeded`
|
|
867
|
-
* webhook creates it, verified server-side; the checkout is polled for
|
|
868
|
-
* its status afterwards, exactly as the redirect return does.
|
|
1017
|
+
* Everything here is side-effect free and never throws on a malformed
|
|
1018
|
+
* bootstrap: a broken `campaigns[]` must never blank a product block or break
|
|
1019
|
+
* `track()`.
|
|
869
1020
|
*/
|
|
870
1021
|
|
|
871
|
-
/** What
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
customer?: string;
|
|
878
|
-
/**
|
|
879
|
-
* Stripe Connect (ADR-0022): the seller's connected account, where the
|
|
880
|
-
* intent lives. The browser must name it or Stripe answers "no such
|
|
881
|
-
* payment_intent". Absent for every seller not on Connect.
|
|
882
|
-
*/
|
|
883
|
-
stripe_account?: string;
|
|
884
|
-
}
|
|
885
|
-
/** What `confirm()` answers. The browser's word is never the order. */
|
|
886
|
-
type StripeConfirmOutcome = {
|
|
887
|
-
status: 'succeeded';
|
|
888
|
-
paymentIntentId?: string;
|
|
889
|
-
}
|
|
890
|
-
/** Authorised but not settled yet, or Stripe redirected and will return. */
|
|
891
|
-
| {
|
|
892
|
-
status: 'pending';
|
|
893
|
-
paymentIntentId?: string;
|
|
894
|
-
} | {
|
|
895
|
-
status: 'failed';
|
|
896
|
-
message?: string;
|
|
897
|
-
code?: string;
|
|
1022
|
+
/** What `Vio.declareSlots()` accepts per slot. */
|
|
1023
|
+
type SlotInput = string | {
|
|
1024
|
+
id: string;
|
|
1025
|
+
displayName?: string;
|
|
1026
|
+
campaignId?: number;
|
|
1027
|
+
kind?: string;
|
|
898
1028
|
};
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1029
|
+
/** The third argument of `Vio.registerSlot(id, displayName, …)`: the element's own campaign and what kind of element it is. */
|
|
1030
|
+
interface RegisterSlotOptions {
|
|
1031
|
+
campaignId?: number | string | null;
|
|
1032
|
+
/** `card` | `carousel` | `detail` for the SDK's elements; a host may name its own kind. */
|
|
1033
|
+
kind?: string;
|
|
902
1034
|
}
|
|
903
|
-
|
|
904
1035
|
/**
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1036
|
+
* The kind of component some units were sold from, as Commerce keeps it on
|
|
1037
|
+
* the order line (`order_item.component_kind`, ≤ 32) — the SAME rule the
|
|
1038
|
+
* collector applies for `breakdown?by=component_kind` (vio-analytics
|
|
1039
|
+
* `componentKind`), so the order and the events agree: what the element says
|
|
1040
|
+
* it is (`component_template_id`: `product-card`, `product-carousel`,
|
|
1041
|
+
* `product-detail`, a Vev block's `vev-card`) lower-cased and without its
|
|
1042
|
+
* `product-` / `vev-` prefix, else the kind word in the slot id the page
|
|
1043
|
+
* declared (`card-<key>`, `<scope>-carousel-2`, `detail-1`); `undefined` when
|
|
1044
|
+
* neither says.
|
|
1045
|
+
*/
|
|
1046
|
+
declare function componentKindOf(templateId: unknown, slot?: unknown): string | undefined;
|
|
1047
|
+
/** The kind as the manifest carries it: trimmed, lower-case, cut at 32 chars; `undefined` for nothing. */
|
|
1048
|
+
declare function normalizeSlotKind(value: unknown): string | undefined;
|
|
1049
|
+
type BootLike = Pick<BootstrapResponse, 'campaign' | 'campaigns' | 'primarySponsor' | 'secondarySponsors'>;
|
|
1050
|
+
/**
|
|
1051
|
+
* The campaign a slot shows right now. Among the `status === 'active'`
|
|
1052
|
+
* entries of `campaigns[]`, the one with an assignment named `slot` for this
|
|
1053
|
+
* platform (`platform` null on the assignment, or equal to `platform`) whose
|
|
1054
|
+
* window contains `now` (`startDate <= now < endDate`, null = open). When
|
|
1055
|
+
* several qualify, the surface's default campaign wins, else the first the
|
|
1056
|
+
* backend lists.
|
|
918
1057
|
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
1058
|
+
* No assignment → the PAGE's campaign (`pageCampaignId`: the element's own
|
|
1059
|
+
* `vio-campaign`, an ancestor's `data-vio-campaign`, or `Vio.init({ campaignId })`)
|
|
1060
|
+
* when `campaigns[]` lists it as active — an editorial page resolves to its
|
|
1061
|
+
* campaign before (and regardless of) the manifest round-trip. Else the
|
|
1062
|
+
* default campaign: the `campaigns[]` entry whose id is `campaign.id`, or a
|
|
1063
|
+
* minimal entry built from `campaign` (+ the top-level sponsors) when the
|
|
1064
|
+
* list does not carry it. No bootstrap → null.
|
|
921
1065
|
*/
|
|
922
|
-
|
|
923
|
-
/** Stripe platform publishable key (pk_live_xxx or pk_test_xxx). */
|
|
924
|
-
publishableKey: string;
|
|
925
|
-
/** Sponsor's Stripe Connect account (acct_xxx). Optional but recommended. */
|
|
926
|
-
connectedAccount?: string;
|
|
927
|
-
/** Amount in the smallest unit of the currency (e.g. øre for NOK, cents for USD). */
|
|
928
|
-
amount: number;
|
|
929
|
-
/** ISO currency code, lowercased internally for Stripe. */
|
|
930
|
-
currency: string;
|
|
931
|
-
/** Two-letter country code, e.g. "NO". */
|
|
932
|
-
country: string;
|
|
933
|
-
/** Label shown in the Apple Pay sheet (merchant or order name). */
|
|
934
|
-
label: string;
|
|
935
|
-
/** Whether to ask the user for payer name. */
|
|
936
|
-
requestPayerName?: boolean;
|
|
937
|
-
/** Whether to ask the user for payer email. */
|
|
938
|
-
requestPayerEmail?: boolean;
|
|
939
|
-
/** Whether to ask for shipping address. */
|
|
940
|
-
requestShipping?: boolean;
|
|
941
|
-
/**
|
|
942
|
-
* Shipping options shown natively in the Apple Pay sheet. `amount` is in the
|
|
943
|
-
* smallest unit (øre). When set, `requestShipping` is forced on and the sheet
|
|
944
|
-
* total = `amount` (items) + the selected option; switching options updates
|
|
945
|
-
* the total live (Apple Pay native shipping).
|
|
946
|
-
*/
|
|
947
|
-
shippingOptions?: Array<{
|
|
948
|
-
id: string;
|
|
949
|
-
label: string;
|
|
950
|
-
detail?: string;
|
|
951
|
-
amount: number;
|
|
952
|
-
}>;
|
|
953
|
-
/**
|
|
954
|
-
* Charge hook, run INSIDE the sheet's authorize event with the tokenized
|
|
955
|
-
* payment. Must perform the real (backend) charge and throw on failure —
|
|
956
|
-
* only then does the sheet close with success; a throw closes it with
|
|
957
|
-
* failure. Its resolved value is surfaced as `ApplePayResult.confirmation`.
|
|
958
|
-
*/
|
|
959
|
-
onAuthorize?: (result: ApplePayResult) => Promise<unknown>;
|
|
960
|
-
}
|
|
961
|
-
interface ApplePayResult {
|
|
962
|
-
/** Stripe PaymentMethod id (pm_xxx) — pass to backend to confirm the PaymentIntent. */
|
|
963
|
-
paymentMethodId: string;
|
|
964
|
-
payerName?: string;
|
|
965
|
-
payerEmail?: string;
|
|
966
|
-
payerPhone?: string;
|
|
967
|
-
shippingAddress?: {
|
|
968
|
-
line1?: string;
|
|
969
|
-
line2?: string;
|
|
970
|
-
city?: string;
|
|
971
|
-
postal_code?: string;
|
|
972
|
-
state?: string;
|
|
973
|
-
country?: string;
|
|
974
|
-
};
|
|
975
|
-
/** Whatever `onAuthorize` resolved with (e.g. backend order_id/status). */
|
|
976
|
-
confirmation?: unknown;
|
|
977
|
-
}
|
|
1066
|
+
declare function resolveSlotCampaign(boot: BootLike | null | undefined, slot: string | null | undefined, now?: number, platform?: string | null, pageCampaignId?: CampaignHint, sponsorId?: number | null): BootstrapCampaignEntry | null;
|
|
978
1067
|
/**
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
1068
|
+
* The sponsor rule: the active campaign of `campaigns[]` the sponsor takes
|
|
1069
|
+
* part in, as its primary or one of its secondaries — when it is in several,
|
|
1070
|
+
* the surface's default campaign if it is one of them, else the first one
|
|
1071
|
+
* the backend lists. Null when none (or on a malformed list).
|
|
983
1072
|
*/
|
|
984
|
-
declare function
|
|
1073
|
+
declare function sponsorCampaignEntry(boot: BootLike | null | undefined, sponsorId: number | null | undefined): BootstrapCampaignEntry | null;
|
|
985
1074
|
/**
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
-
* payment method id (server-side step, not handled here).
|
|
1075
|
+
* A page campaign as the callers give it: one id, or the candidates in
|
|
1076
|
+
* precedence order (the element's `vio-campaign`, an ancestor's
|
|
1077
|
+
* `data-vio-campaign`, `Vio.init`'s). An unusable level (invalid, paused,
|
|
1078
|
+
* unknown) falls through to the next one; `0`, `null`, `''` mean unset.
|
|
991
1079
|
*/
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
interface KlarnaPaymentsCategory {
|
|
1031
|
-
identifier: string;
|
|
1032
|
-
name: string;
|
|
1033
|
-
asset_urls?: {
|
|
1034
|
-
descriptive?: string;
|
|
1035
|
-
standard?: string;
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
|
-
interface KpLoadResult {
|
|
1039
|
-
show_form?: boolean;
|
|
1040
|
-
error?: unknown;
|
|
1041
|
-
}
|
|
1042
|
-
interface KpAuthorizeResult {
|
|
1043
|
-
approved?: boolean;
|
|
1044
|
-
show_form?: boolean;
|
|
1045
|
-
authorization_token?: string;
|
|
1046
|
-
finalize_required?: boolean;
|
|
1047
|
-
error?: unknown;
|
|
1048
|
-
}
|
|
1049
|
-
interface KlarnaPaymentsApi {
|
|
1050
|
-
init(opts: {
|
|
1051
|
-
client_token: string;
|
|
1052
|
-
}): void;
|
|
1053
|
-
load(opts: {
|
|
1054
|
-
container: string | HTMLElement;
|
|
1055
|
-
payment_method_category?: string;
|
|
1056
|
-
}, data: Record<string, unknown>, cb?: (res: KpLoadResult) => void): void;
|
|
1057
|
-
authorize(opts: {
|
|
1058
|
-
payment_method_category?: string;
|
|
1059
|
-
auto_finalize?: boolean;
|
|
1060
|
-
}, data: Record<string, unknown>, cb?: (res: KpAuthorizeResult) => void): void;
|
|
1061
|
-
/** Debug/lifecycle events — e.g. 'fullscreenOverlayShown'/'fullscreenOverlayHidden'. */
|
|
1062
|
-
on?(event: string, cb: () => void): void;
|
|
1063
|
-
}
|
|
1064
|
-
interface KlarnaGlobal {
|
|
1065
|
-
Payments: KlarnaPaymentsApi;
|
|
1066
|
-
}
|
|
1067
|
-
declare global {
|
|
1068
|
-
interface Window {
|
|
1069
|
-
Klarna?: KlarnaGlobal;
|
|
1070
|
-
klarnaAsyncCallback?: () => void;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1080
|
+
type CampaignHint = number | string | null | undefined | ReadonlyArray<number | string | null | undefined>;
|
|
1081
|
+
/**
|
|
1082
|
+
* A campaign id as the SDK accepts it: a positive safe integer, given as a
|
|
1083
|
+
* number or as a string of decimal digits (an attribute). Anything else —
|
|
1084
|
+
* `true`, `'0x10'`, `'1e3'`, an array, a float — is "absent".
|
|
1085
|
+
*/
|
|
1086
|
+
declare function toCampaignId(value: unknown): number | undefined;
|
|
1087
|
+
/** The usable ids of a hint, in order, without duplicates. */
|
|
1088
|
+
declare function campaignCandidates(hint: CampaignHint): number[];
|
|
1089
|
+
/**
|
|
1090
|
+
* The first candidate of `hint` that `campaigns[]` lists as ACTIVE (and, when
|
|
1091
|
+
* `sponsorId` is given, that the sponsor takes part in — primary or
|
|
1092
|
+
* secondary); null when none — a paused, ended or unknown page campaign is
|
|
1093
|
+
* ignored and the resolution moves on.
|
|
1094
|
+
*/
|
|
1095
|
+
declare function activeCampaignEntry(boot: BootLike | null | undefined, hint: CampaignHint, sponsorId?: number): BootstrapCampaignEntry | null;
|
|
1096
|
+
/** The kinds of Vio element that register themselves. */
|
|
1097
|
+
type SlotKind = 'card' | 'carousel' | 'detail';
|
|
1098
|
+
/**
|
|
1099
|
+
* The id an element gets when the host set no `vio-slot`:
|
|
1100
|
+
* `${scope ? scope + '-' : ''}${kind}-${ordinal + 1}` (`carousel-1`, `card-3`,
|
|
1101
|
+
* `article-123-carousel-1`), `ordinal` being the element's index among the
|
|
1102
|
+
* same-kind Vio elements WITH THE SAME SCOPE, in document order at connect
|
|
1103
|
+
* time. The scope is inherited from the DOM (`vio-scope` on the element, else
|
|
1104
|
+
* the nearest `data-vio-scope` ancestor): a Vev page or a Replit article
|
|
1105
|
+
* (`<body data-vio-scope="article-123">`) gets per-page slots with one line
|
|
1106
|
+
* and no per-element naming; a template that wants slots shared across
|
|
1107
|
+
* articles simply sets no scope. On purpose there is NO page path in the id:
|
|
1108
|
+
* the article goes to analytics as `content_id`, not into the slot. Stable
|
|
1109
|
+
* across reloads while the layout is; a layout change leaves a stale entry,
|
|
1110
|
+
* which ADR-0034 accepts.
|
|
1111
|
+
*/
|
|
1112
|
+
declare function autoSlotId(kind: SlotKind, ordinal: number, scope?: string | null): string;
|
|
1113
|
+
/** `"Carousel 1"`, `"Card 3"` — with ` · ${scopeName}` when the scope has a human label. */
|
|
1114
|
+
declare function autoSlotDisplayName(kind: SlotKind, ordinal: number, scopeName?: string | null): string;
|
|
1115
|
+
/** A scope value fit for an id: trimmed, inner whitespace → `-`. */
|
|
1116
|
+
declare function normalizeScope(scope: string | null | undefined): string;
|
|
1073
1117
|
|
|
1074
1118
|
/**
|
|
1075
|
-
*
|
|
1119
|
+
* Vio.analytics — the web SDK's half of the Vio Analytics pipeline.
|
|
1076
1120
|
*
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1121
|
+
* Events flow to the Vio collector (`POST <eventsBase>/v1/events`, repo
|
|
1122
|
+
* vio-live/vio-analytics) which owns raw storage (ClickHouse) and vendor
|
|
1123
|
+
* fan-out (Mixpanel today). THE SDK NEVER TALKS TO VENDORS — swapping or
|
|
1124
|
+
* dropping a vendor is a server-side change, zero client releases.
|
|
1125
|
+
* Wire contract: vio-analytics `docs/EVENTS_CONTRACT.md` (v1, snake_case).
|
|
1079
1126
|
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
* completes it right there — and renders Kustom's own receipt.
|
|
1127
|
+
* Design rules:
|
|
1128
|
+
* - SIDE-EFFECT-FREE MODULE. Nothing runs at import time (tsup/tree-shaking
|
|
1129
|
+
* contract, see lessons/web-sdk-tsup-singleton-and-build). Listeners are
|
|
1130
|
+
* installed by an explicit `Vio.analytics.start()`.
|
|
1131
|
+
* - `track()` works BEFORE `Vio.init()` — events queue and flush once the
|
|
1132
|
+
* SDK is configured (transport resolves at flush time, not at track time).
|
|
1133
|
+
* - SSR-safe: without `window` every call is a silent no-op.
|
|
1134
|
+
* - Retries are safe: `event_id` is stable per event, the collector
|
|
1135
|
+
* dedupes. Queue is bounded (drop-oldest) so a dead collector can never
|
|
1136
|
+
* grow memory unbounded.
|
|
1137
|
+
* - Anti-double-count: the SDK only reports what the server can't see.
|
|
1138
|
+
* Votes/participations are server truth; `ad_activation`/`cart_intent`
|
|
1139
|
+
* are mirrored server-side, never from here.
|
|
1094
1140
|
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1141
|
+
* Three sinks, matching the Vev precedent (vio-vev analytics.ts, which
|
|
1142
|
+
* becomes an adapter over this in F3):
|
|
1143
|
+
* 1. collector (default ON once started)
|
|
1144
|
+
* 2. window.dataLayer — GA4/GTM (opt-in `start({ dataLayer: true })`,
|
|
1145
|
+
* the publisher-facing feature; NOT part of the Vio pipeline)
|
|
1146
|
+
* 3. `vio:analytics` DOM event — always when started (inspector/bridges)
|
|
1098
1147
|
*/
|
|
1099
1148
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
/** The shopper picked a rate inside the widget. */
|
|
1134
|
-
onShippingOptionChange?: (option: KustomShippingChange) => void;
|
|
1135
|
-
/** The shopper could not pay (declined credit…): show another way. */
|
|
1136
|
-
onCannotComplete?: () => void;
|
|
1137
|
-
onNetworkError?: () => void;
|
|
1138
|
-
/** The shopper is about to leave for the confirmation page. */
|
|
1139
|
-
onRedirectInitiated?: () => void;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
/**
|
|
1143
|
-
* Qliro Checkout — embedded checkout via Vio Commerce.
|
|
1144
|
-
*
|
|
1145
|
-
* Same embed philosophy as Kustom (the widget collects address, shipping
|
|
1146
|
-
* AND payment), different provider API underneath — shopcart normalizes
|
|
1147
|
-
* Qliro's Merchant API (OrderId / CustomerCheckoutStatus / OrderHtmlSnippet)
|
|
1148
|
-
* to the { order_id, status, html_snippet } shape both flows share:
|
|
1149
|
-
*
|
|
1150
|
-
* 1. `Payment { CreatePaymentQliro }` creates the order and returns the
|
|
1151
|
-
* snippet (sponsor-key authed; the seller's MerchantApiKey/Secret live
|
|
1152
|
-
* server-side, per seller, never here).
|
|
1153
|
-
* 2. The snippet is injected (script-executing embed, shared with Kustom).
|
|
1154
|
-
* 3. On completion Qliro redirects to the confirmation URL
|
|
1155
|
-
* (`?checkout_id=…&payment_processor=QLIRO`); the SDK re-reads the
|
|
1156
|
-
* order via `Payment { GetQliroOrder(checkout_id) }` — Qliro
|
|
1157
|
-
* correlates by the OWNING CHECKOUT, not the order id — and renders
|
|
1158
|
-
* the snippet again, which shows Qliro's own receipt.
|
|
1159
|
-
*
|
|
1160
|
-
* The Commerce order is created server-side by Qliro's push webhook
|
|
1161
|
-
* (shopcart /checkout/payment/qliro/ok) — the browser never confirms money.
|
|
1162
|
-
*/
|
|
1163
|
-
|
|
1164
|
-
/** Normalized Qliro order (shopcart maps the PascalCase Merchant API). */
|
|
1165
|
-
interface QliroOrder {
|
|
1166
|
-
order_id: string;
|
|
1167
|
-
/** Qliro CustomerCheckoutStatus: InProcess | Completed | OnHold | Refused. */
|
|
1168
|
-
status: string;
|
|
1169
|
-
html_snippet: string;
|
|
1170
|
-
purchase_country?: string;
|
|
1171
|
-
purchase_currency?: string;
|
|
1172
|
-
total_price?: number;
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
/**
|
|
1176
|
-
* Qliro's browser-side protocol (`q1`).
|
|
1177
|
-
*
|
|
1178
|
-
* The embedded widget publishes a `q1` object on the window and calls a
|
|
1179
|
-
* globally-defined `q1Ready` once it has rendered. Everything the customer
|
|
1180
|
-
* does inside the iframe — picking a shipping method, changing their address,
|
|
1181
|
-
* having a payment declined — is only observable through these listeners.
|
|
1182
|
-
* Without them the widget is a black box: the customer can change the
|
|
1183
|
-
* shipping and our own summary keeps showing the old total.
|
|
1184
|
-
*
|
|
1185
|
-
* Two rules from Qliro's documentation shape this module:
|
|
1186
|
-
*
|
|
1187
|
-
* 1. **Lock before touching the backend.** Otherwise the customer can
|
|
1188
|
-
* complete the purchase while the order is still being synchronized.
|
|
1189
|
-
* 2. **Compare before unlocking.** Otherwise a second change interrupts the
|
|
1190
|
-
* synchronization of the first.
|
|
1191
|
-
*
|
|
1192
|
-
* We compare on `MerchantUpdateVersion`, the token Qliro echoes back through
|
|
1193
|
-
* `onOrderUpdated`, rather than on totals. Totals cannot be the test here: in
|
|
1194
|
-
* the modes where Qliro owns the shipping amount our total and Qliro's
|
|
1195
|
-
* legitimately differ, and the customer would sit locked out of a checkout
|
|
1196
|
-
* that is in fact up to date.
|
|
1197
|
-
*/
|
|
1198
|
-
|
|
1199
|
-
interface QliroSyncResult {
|
|
1200
|
-
order_id: string;
|
|
1201
|
-
/** Token to wait for in `onOrderUpdated` before unlocking. */
|
|
1202
|
-
update_version: string;
|
|
1203
|
-
total_price: number;
|
|
1149
|
+
declare const ANALYTICS_EVENT_NAMES: readonly ["view_item_list", "select_item", "view_item", "add_to_cart", "remove_from_cart", "view_cart", "begin_checkout", "purchase", "component_impression", "component_click", "ad_impression", "ad_click", "poll_impression", "contest_impression", "session_start", "session_end", "checkout_error", "sdk_error"];
|
|
1150
|
+
type AnalyticsEventName = (typeof ANALYTICS_EVENT_NAMES)[number];
|
|
1151
|
+
/** Camel-case for DX; mapped to the snake_case wire format at build time. */
|
|
1152
|
+
interface AnalyticsContext {
|
|
1153
|
+
campaignId?: number;
|
|
1154
|
+
broadcastId?: string;
|
|
1155
|
+
campaignComponentId?: number;
|
|
1156
|
+
appPlacementId?: number;
|
|
1157
|
+
locationId?: string;
|
|
1158
|
+
componentTemplateId?: string;
|
|
1159
|
+
sponsorId?: number;
|
|
1160
|
+
activationId?: number;
|
|
1161
|
+
contentUrl?: string;
|
|
1162
|
+
/**
|
|
1163
|
+
* The host's own id for the piece of content the component sits in — an
|
|
1164
|
+
* article id in a CMS, a page id in a site builder. Carried verbatim so the
|
|
1165
|
+
* host can join Vio's funnel back onto its own per-article reporting
|
|
1166
|
+
* (revenue stops being an estimate). Left alone by the SDK.
|
|
1167
|
+
*/
|
|
1168
|
+
contentId?: string | number;
|
|
1169
|
+
/** Human-readable content snapshot; auto-filled from document.title. */
|
|
1170
|
+
contentTitle?: string;
|
|
1171
|
+
/** Código corto del fallo (`sdk_error` / `checkout_error`). */
|
|
1172
|
+
errorCode?: string;
|
|
1173
|
+
variant?: string;
|
|
1174
|
+
/**
|
|
1175
|
+
* The slot (ADR-0027) the component sits in — its `vio-slot`. Attribution
|
|
1176
|
+
* follows it: the event's `campaign_id` is the campaign assigned to the slot
|
|
1177
|
+
* right now, before the sponsor rule. On the wire it fills `location_id`
|
|
1178
|
+
* when no explicit `locationId` is given (a slot IS a location id to the
|
|
1179
|
+
* campaigns service).
|
|
1180
|
+
*/
|
|
1181
|
+
slot?: string;
|
|
1204
1182
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
* 1. `Payment { CreatePaymentWalley }` initializes the session (sponsor-key
|
|
1213
|
-
* authed; the seller's own Walley credentials live server-side, per
|
|
1214
|
-
* seller, never here) and returns a SYNTHESIZED html_snippet — Walley's
|
|
1215
|
-
* real embed is a `<script data-token>` loader, so shopcart wraps it
|
|
1216
|
-
* in the same shape Kustom/Qliro use, and this module reuses their
|
|
1217
|
-
* exact script-executing injection.
|
|
1218
|
-
* 2. Walley's own script renders the iframe. On completion it dispatches
|
|
1219
|
-
* the DOM event `walleyCheckoutPurchaseCompleted` — the PRIMARY success
|
|
1220
|
-
* signal, no page reload needed. `redirectPageUri` is registered too
|
|
1221
|
-
* (`?checkout_id=…&payment_processor=WALLEY`, same contract as
|
|
1222
|
-
* Kustom/Qliro) as a safety net in case the event is missed (tab
|
|
1223
|
-
* backgrounded, page reload).
|
|
1224
|
-
* 3. Either path re-reads the session (`Payment { GetWalleyOrder }`) BY
|
|
1225
|
-
* OWNING CHECKOUT — same as Qliro — and re-renders Walley's own
|
|
1226
|
-
* receipt.
|
|
1227
|
-
*
|
|
1228
|
-
* The Commerce order itself is created server-side by Walley's notification
|
|
1229
|
-
* webhook (shopcart /checkout/payment/walley/ok) — the browser never
|
|
1230
|
-
* confirms money.
|
|
1231
|
-
*/
|
|
1232
|
-
|
|
1233
|
-
/** Normalized Walley session (shopcart maps privateId/publicToken/status). */
|
|
1234
|
-
interface WalleyOrder {
|
|
1235
|
-
order_id: string;
|
|
1236
|
-
/** Walley status: Initialized | CustomerIdentified | CommittedToPurchase | PurchaseCompleted | Aborted. */
|
|
1237
|
-
status: string;
|
|
1238
|
-
html_snippet: string;
|
|
1239
|
-
public_token?: string;
|
|
1240
|
-
purchase_country?: string;
|
|
1241
|
-
purchase_currency?: string;
|
|
1242
|
-
total_price?: number;
|
|
1183
|
+
interface AnalyticsItemInput {
|
|
1184
|
+
productId: number | string;
|
|
1185
|
+
name?: string;
|
|
1186
|
+
brand?: string;
|
|
1187
|
+
variantId?: number | string;
|
|
1188
|
+
price?: number;
|
|
1189
|
+
quantity?: number;
|
|
1243
1190
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
* shape this module:
|
|
1251
|
-
*
|
|
1252
|
-
* 1. There is no html_snippet. `Payment { CreatePaymentNexi }` creates the
|
|
1253
|
-
* payment server-side (the seller's SECRET key never leaves shopcart)
|
|
1254
|
-
* and returns the paymentId plus the PUBLIC checkout key; the browser
|
|
1255
|
-
* loads Nexi's `checkout.js` and mounts `new Dibs.Checkout({…})` in a
|
|
1256
|
-
* LIGHT-DOM container — Nexi refuses a container inside a shadow root
|
|
1257
|
-
* or another iframe.
|
|
1258
|
-
* 2. Nexi has no shipping picker. The payment is created with
|
|
1259
|
-
* `merchantHandlesShippingCost`, so Nexi holds its pay button until we
|
|
1260
|
-
* price the address the shopper typed: on `address-changed` the widget
|
|
1261
|
-
* is frozen, `Payment { UpdateNexiShipping }` re-prices for that country
|
|
1262
|
-
* and pushes the SHIPPING line, and the widget is thawed.
|
|
1263
|
-
*
|
|
1264
|
-
* Completion arrives as the `payment-completed` event — Nexi neither
|
|
1265
|
-
* redirects nor renders a receipt of its own, so the component shows Vio's
|
|
1266
|
-
* confirmation. Some methods inside Nexi (Vipps, Swish, MobilePay) leave the
|
|
1267
|
-
* page and come back to the SAME url with `?paymentId=…` appended; the
|
|
1268
|
-
* pending session is remembered in sessionStorage so the widget can be
|
|
1269
|
-
* re-mounted on that paymentId and finish.
|
|
1270
|
-
*
|
|
1271
|
-
* The Commerce order itself is created server-side by Nexi's webhook
|
|
1272
|
-
* (shopcart /checkout/payment/nexi/ok) — the browser never confirms money.
|
|
1273
|
-
*/
|
|
1274
|
-
|
|
1275
|
-
/** Normalized Nexi payment (shopcart maps the Payment API). */
|
|
1276
|
-
interface NexiOrder {
|
|
1277
|
-
/** Nexi paymentId (32 hex). */
|
|
1278
|
-
order_id: string;
|
|
1279
|
-
/** Created | Reserved | Charged | Cancelled | Terminated | Unknown. */
|
|
1280
|
-
status: string;
|
|
1281
|
-
/** Public checkout key for Dibs.Checkout. */
|
|
1282
|
-
checkout_key: string;
|
|
1283
|
-
/** checkout.js of the seller's environment (test or live). */
|
|
1284
|
-
checkout_js_url: string;
|
|
1285
|
-
purchase_country?: string;
|
|
1286
|
-
purchase_currency?: string;
|
|
1287
|
-
total_price?: number;
|
|
1191
|
+
interface AnalyticsCommerce {
|
|
1192
|
+
items?: AnalyticsItemInput[];
|
|
1193
|
+
value?: number;
|
|
1194
|
+
currency?: string;
|
|
1195
|
+
orderId?: string;
|
|
1196
|
+
paymentMethod?: string;
|
|
1288
1197
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
* announce its address again).
|
|
1198
|
+
* The buyer reference (`buyer_id` on the wire): shopcart's `buyer_ref`, a
|
|
1199
|
+
* keyed hash of the buyer's email — one person, one ref across orders and
|
|
1200
|
+
* devices, nothing reversible. Never an email (see core/buyer-ref.ts).
|
|
1293
1201
|
*/
|
|
1294
|
-
|
|
1295
|
-
/** How it was paid ("Visa", "Vipps"…) — once Nexi has the details. */
|
|
1296
|
-
payment_method?: string | null;
|
|
1297
|
-
/** Last four digits of the card. */
|
|
1298
|
-
card_last4?: string | null;
|
|
1299
|
-
/** Where the receipt goes. */
|
|
1300
|
-
email?: string | null;
|
|
1202
|
+
buyerId?: string;
|
|
1301
1203
|
}
|
|
1302
|
-
interface
|
|
1303
|
-
|
|
1204
|
+
interface TrackOptions {
|
|
1205
|
+
context?: AnalyticsContext;
|
|
1206
|
+
commerce?: AnalyticsCommerce;
|
|
1207
|
+
props?: Record<string, unknown>;
|
|
1208
|
+
}
|
|
1209
|
+
interface AnalyticsStartOptions {
|
|
1210
|
+
/** Where the SDK is embedded: 'vev' | 'replit' | 'custom' | … Default 'custom'. */
|
|
1211
|
+
host?: string;
|
|
1304
1212
|
/**
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1213
|
+
* Arrancar en modo cookieless hasta que el host llame `setConsent(true)`.
|
|
1214
|
+
* Default false: el SDK asume que el CMP del publisher ya decidió si nos
|
|
1215
|
+
* carga. Los publishers EU que necesitan medir antes del consentimiento
|
|
1216
|
+
* (o no pueden persistir sin él) ponen true.
|
|
1308
1217
|
*/
|
|
1309
|
-
|
|
1310
|
-
order_id: string;
|
|
1311
|
-
total_price?: number;
|
|
1312
|
-
shipping_name?: string;
|
|
1313
|
-
shipping_price?: number;
|
|
1314
|
-
/** The rate on the payment now. */
|
|
1315
|
-
shipping_id?: string;
|
|
1218
|
+
requireConsent?: boolean;
|
|
1316
1219
|
/**
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1220
|
+
* Install the automatic funnel listeners (vio:added-to-cart,
|
|
1221
|
+
* vio:checkout-open, vio:open-cart, vio:payment-success). Default true.
|
|
1222
|
+
* Hosts with their OWN instrumentation choke point (e.g. the Vev module,
|
|
1223
|
+
* which forwards every event through trackEvent()) set false so the same
|
|
1224
|
+
* user action is never tracked twice — they keep the session/batching/
|
|
1225
|
+
* transport engine and call track() themselves.
|
|
1319
1226
|
*/
|
|
1320
|
-
|
|
1321
|
-
/** The address it was priced for (alpha-2 country). */
|
|
1322
|
-
country?: string;
|
|
1323
|
-
postal_code?: string;
|
|
1324
|
-
/** market — the checkout's country, priced at creation; consumer — the shopper's address. */
|
|
1325
|
-
address_source?: 'market' | 'consumer' | null;
|
|
1326
|
-
/** Whether this call changed the amount on the payment. */
|
|
1327
|
-
changed?: boolean | null;
|
|
1227
|
+
autoTrack?: boolean;
|
|
1328
1228
|
/**
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1229
|
+
* Adopt the host's session id instead of minting one. A host that already
|
|
1230
|
+
* tracks its readers (its own impressions, dwell, clicks) needs Vio's
|
|
1231
|
+
* purchases to land in the SAME session, or the two datasets cannot be
|
|
1232
|
+
* joined. Pass the id the host already stores; omit it and the SDK keeps
|
|
1233
|
+
* its own rotating session.
|
|
1331
1234
|
*/
|
|
1332
|
-
|
|
1235
|
+
sessionId?: string;
|
|
1236
|
+
/** Send to the Vio collector. Default true. */
|
|
1237
|
+
collector?: boolean;
|
|
1238
|
+
/** Also push GA4 e-commerce events to window.dataLayer (publisher feature). */
|
|
1239
|
+
dataLayer?: boolean;
|
|
1240
|
+
/** console.debug every event. */
|
|
1241
|
+
debug?: boolean;
|
|
1333
1242
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1243
|
+
declare class AnalyticsManager extends EventTarget {
|
|
1244
|
+
private started;
|
|
1245
|
+
private options;
|
|
1246
|
+
private queue;
|
|
1247
|
+
private flushTimer;
|
|
1248
|
+
private retryAttempt;
|
|
1249
|
+
private retryNotBefore;
|
|
1250
|
+
private externalUserId;
|
|
1251
|
+
private sessionId;
|
|
1252
|
+
private requireConsent;
|
|
1253
|
+
private consentGranted;
|
|
1254
|
+
private anonIdCache;
|
|
1255
|
+
/** Set via start({ sessionId }) — the host owns the session, we follow. */
|
|
1256
|
+
private externalSessionId;
|
|
1257
|
+
private sessionStartedAt;
|
|
1258
|
+
/** Impression once-per-(session, component) guard; reset on session rotation. */
|
|
1259
|
+
private impressedComponents;
|
|
1260
|
+
/** Last NON-EMPTY cart snapshot — `purchase` uses it because several flows
|
|
1261
|
+
* (Apple Pay) clear the cart BEFORE `vio:payment-success` fires. */
|
|
1262
|
+
private lastCartSnapshot;
|
|
1263
|
+
/** The `client` block (language, landing referrer / utm, screen, tz): read once per page load, reused on every event. */
|
|
1264
|
+
private client;
|
|
1265
|
+
/** The landing it was read from — persisted later when consent arrives after the first event. */
|
|
1266
|
+
private landing;
|
|
1267
|
+
/** The landing this manager resolved on this page load (the first event's), or null before it; read only — for the order's entry context when nothing is stored yet. */
|
|
1268
|
+
get currentLanding(): Landing | null;
|
|
1269
|
+
private teardown;
|
|
1270
|
+
/**
|
|
1271
|
+
* Install listeners + begin flushing. Explicit on purpose (no module
|
|
1272
|
+
* side-effects). Safe to call twice (second call only updates options).
|
|
1273
|
+
*/
|
|
1274
|
+
/**
|
|
1275
|
+
* Consentimiento (ePrivacy/GDPR). Por defecto el SDK asume que el host ya
|
|
1276
|
+
* lo gestionó — su CMP decide si nos carga. Con `requireConsent: true`
|
|
1277
|
+
* arranca en modo **cookieless**: mide la visita con ids efímeros en
|
|
1278
|
+
* memoria y NO escribe nada en localStorage hasta que el host llame
|
|
1279
|
+
* `setConsent(true)`. Retirarlo borra lo persistido.
|
|
1280
|
+
*/
|
|
1281
|
+
setConsent(granted: boolean): void;
|
|
1282
|
+
/** ¿Podemos escribir en el dispositivo? */
|
|
1283
|
+
private get canPersist();
|
|
1284
|
+
start(options?: AnalyticsStartOptions): void;
|
|
1285
|
+
/** Stop timers + listeners (tests / SPA unmount). Queue survives. */
|
|
1286
|
+
stop(): void;
|
|
1287
|
+
/** Attach the partner's user id (opaque) to all subsequent events. */
|
|
1288
|
+
identify(externalUserId: string | null): void;
|
|
1289
|
+
/** Queue one event. Works pre-init and pre-start (SSR: no-op). */
|
|
1290
|
+
track(name: AnalyticsEventName, opts?: TrackOptions): void;
|
|
1291
|
+
/**
|
|
1292
|
+
* Impression helper: observes an element and tracks ONE
|
|
1293
|
+
* `component_impression` per (session, campaignComponentId) when the
|
|
1294
|
+
* contract's rule is met (≥50% visible, ≥1s dwell). Returns an
|
|
1295
|
+
* unobserve function.
|
|
1296
|
+
*/
|
|
1297
|
+
observeImpression(element: Element, context?: AnalyticsContext, opts?: {
|
|
1298
|
+
name?: Extract<AnalyticsEventName, 'component_impression' | 'ad_impression'>;
|
|
1299
|
+
/** Dedupe key override. Defaults to the strongest id available:
|
|
1300
|
+
* campaignComponentId → locationId → componentTemplateId. */
|
|
1301
|
+
key?: string;
|
|
1302
|
+
/** Called the one time the impression is tracked (e.g. to fire a
|
|
1303
|
+
* companion view_item_list). */
|
|
1304
|
+
onImpression?: () => void;
|
|
1305
|
+
}): () => void;
|
|
1306
|
+
/** Force a flush (mostly for tests). */
|
|
1307
|
+
flush(): Promise<void>;
|
|
1308
|
+
private buildEvent;
|
|
1309
|
+
/**
|
|
1310
|
+
* The `client` block: read once — the landing is remembered for the session
|
|
1311
|
+
* only when we may persist — then the same (frozen) object on every event.
|
|
1312
|
+
* `null` when there is nothing to say (no browser).
|
|
1313
|
+
*/
|
|
1314
|
+
private clientBlock;
|
|
1315
|
+
/** Guarda la sesión solo si podemos escribir en el dispositivo. */
|
|
1316
|
+
private persistSession;
|
|
1317
|
+
private anonId;
|
|
1318
|
+
/** Rolling session: renewed by activity, rotated after 30 min idle. */
|
|
1319
|
+
private ensureSession;
|
|
1320
|
+
private trackSessionEnd;
|
|
1321
|
+
private flushWithBeacon;
|
|
1322
|
+
/**
|
|
1323
|
+
* Auto-instrumentation over the SDK's own DOM events — the host app
|
|
1324
|
+
* writes ZERO tracking code for the commerce funnel.
|
|
1325
|
+
*/
|
|
1326
|
+
private installAutoListeners;
|
|
1327
|
+
/** The lines of the cart (current, else the pre-clear snapshot), optionally one sponsor's. */
|
|
1328
|
+
private cartLines;
|
|
1329
|
+
/**
|
|
1330
|
+
* The cart split per campaign — the shared rule of cart/slices.ts over the
|
|
1331
|
+
* current cart (else the pre-clear snapshot), plus whether any unit named
|
|
1332
|
+
* its campaign itself (a cart without origins is reported as before).
|
|
1333
|
+
*/
|
|
1334
|
+
private cartSlices;
|
|
1335
|
+
/**
|
|
1336
|
+
* The context of one of several per-campaign events: the slice's campaign,
|
|
1337
|
+
* slot and content — only its own; when the slice spans several slots or
|
|
1338
|
+
* articles the event names none rather than the one the click came from.
|
|
1339
|
+
*/
|
|
1340
|
+
private sliceContext;
|
|
1341
|
+
/**
|
|
1342
|
+
* The context of a single-campaign checkout/purchase: when the cart's origins
|
|
1343
|
+
* say which campaign they came from, the event says it too (plus the slot /
|
|
1344
|
+
* content when unique) — a cart without origins is exactly as before.
|
|
1345
|
+
*/
|
|
1346
|
+
private singleSliceContext;
|
|
1347
|
+
/** Current cart → commerce payload; falls back to the pre-clear snapshot. */
|
|
1348
|
+
private cartCommerce;
|
|
1349
|
+
private findLine;
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* The `campaign_id` of an event. In order: the context's explicit id; the
|
|
1353
|
+
* campaign assigned to the context's `slot` right now (ADR-0027 — only an
|
|
1354
|
+
* open assignment for the init platform counts, see `findSlotAssignment`);
|
|
1355
|
+
* the PAGE's campaign (`opts.pageCampaignId`, else `Vio.init({ campaignId })`)
|
|
1356
|
+
* when `campaigns[]` lists it as active (ADR-0034, amendment 3);
|
|
1357
|
+
* the active campaign of `campaigns[]` the event's sponsor takes part in, as
|
|
1358
|
+
* its primary or one of its secondaries — when it is in several, the
|
|
1359
|
+
* surface's default campaign if it is one of them, else the first one the
|
|
1360
|
+
* backend lists; the default campaign (`campaign.id`). `/v2/mobile/config`
|
|
1361
|
+
* has no top-level `campaignId` — reading one is why every event used to
|
|
1362
|
+
* leave with `campaign_id: 0` and the campaigns screen stayed empty.
|
|
1363
|
+
*
|
|
1364
|
+
* A malformed `campaigns[]` (not an array, a null entry) never breaks
|
|
1365
|
+
* `track()`: it falls back to `campaign.id`.
|
|
1366
|
+
*/
|
|
1367
|
+
declare function resolveCampaignId(ctx: Pick<AnalyticsContext, 'campaignId' | 'sponsorId' | 'slot'>, boot: Pick<BootstrapResponse, 'campaign' | 'campaigns'> | null | undefined, opts?: {
|
|
1368
|
+
pageCampaignId?: CampaignHint;
|
|
1369
|
+
}): number | undefined;
|
|
1370
|
+
/**
|
|
1371
|
+
* `detail` of `vio:payment-success` as the checkout emits it. Four paths,
|
|
1372
|
+
* three shapes: a redirect return (`orderId` = Vio's checkout id), the
|
|
1373
|
+
* confirmation drawer and a provider's own receipt (`result` from the
|
|
1374
|
+
* provider or the backend, plus Vio's `checkoutId`), and Apple Pay express
|
|
1375
|
+
* from the cart (`result` with the backend's `confirmation`, no sponsor).
|
|
1376
|
+
*/
|
|
1377
|
+
interface PaymentSuccessDetail {
|
|
1378
|
+
method?: string;
|
|
1379
|
+
sponsorId?: number | string;
|
|
1380
|
+
/** The slot the purchase started from, when the emitter knows it. */
|
|
1381
|
+
slot?: string;
|
|
1382
|
+
/** The campaign the emitter attributed the purchase to (its `Vio.attribution`). */
|
|
1383
|
+
campaignId?: number;
|
|
1384
|
+
/** Per-element content override (`vio-content-id` / `vio-content-title`), when the emitter carries one. */
|
|
1385
|
+
contentId?: string | number;
|
|
1386
|
+
contentTitle?: string;
|
|
1387
|
+
/** Redirect return: Vio's checkout id (the name predates `checkoutId`). */
|
|
1388
|
+
orderId?: string | number;
|
|
1389
|
+
/** Vio's checkout id — from the checkout state or the return URL. */
|
|
1390
|
+
checkoutId?: string | number;
|
|
1391
|
+
/**
|
|
1392
|
+
* The buyer reference the emitter learned with the payment — shopcart's
|
|
1393
|
+
* `buyer_ref`, a keyed hash of the email (`buyerRef` from the SDK's own
|
|
1394
|
+
* checkout; `buyer_ref` when a host passes the backend's answer through).
|
|
1395
|
+
* Becomes `commerce.buyer_id`; never an email.
|
|
1396
|
+
*/
|
|
1397
|
+
buyerRef?: string | null;
|
|
1398
|
+
buyer_ref?: string | null;
|
|
1399
|
+
result?: PaymentSuccessResult | null;
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* What the checkout attaches as `result`. Only `confirmation` carries a Vio
|
|
1403
|
+
* id: the order `ConfirmPaymentApplePay` created. `order.orderId` / `orderId`
|
|
1404
|
+
* are the PROVIDER's references (Qliro's, Walley's — the checkout itself
|
|
1405
|
+
* shows them as `providerRef`), and `chargedTotal` includes shipping on some
|
|
1406
|
+
* methods only. Analytics reads none of those.
|
|
1407
|
+
*/
|
|
1408
|
+
interface PaymentSuccessResult {
|
|
1409
|
+
confirmation?: {
|
|
1410
|
+
orderId?: string | number | null;
|
|
1411
|
+
status?: string;
|
|
1412
|
+
buyerRef?: string | null;
|
|
1413
|
+
buyer_ref?: string | null;
|
|
1414
|
+
} | null;
|
|
1415
|
+
/** The checkout as a host's backend answered it, when the host passes it through. */
|
|
1416
|
+
checkout?: {
|
|
1417
|
+
buyerRef?: string | null;
|
|
1418
|
+
buyer_ref?: string | null;
|
|
1419
|
+
} | null;
|
|
1420
|
+
buyerRef?: string | null;
|
|
1421
|
+
buyer_ref?: string | null;
|
|
1422
|
+
[key: string]: unknown;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* The buyer reference of a `vio:payment-success` / `vio:checkout-open`
|
|
1426
|
+
* detail, wherever its emitter put it: top-level (`buyerRef`, or `buyer_ref`
|
|
1427
|
+
* as the backend spells it), on the result, on the result's `confirmation`
|
|
1428
|
+
* (Apple Pay) or `checkout`. Only a reference survives — never an email
|
|
1429
|
+
* (`normalizeBuyerRef`).
|
|
1430
|
+
*/
|
|
1431
|
+
declare function buyerRefOf(d: {
|
|
1432
|
+
buyerRef?: unknown;
|
|
1433
|
+
buyer_ref?: unknown;
|
|
1434
|
+
result?: PaymentSuccessResult | null;
|
|
1435
|
+
} | null | undefined): string | undefined;
|
|
1436
|
+
/**
|
|
1437
|
+
* The `order_id` and `buyer_id` of a `purchase`. The id is ALWAYS a Vio id, never a provider's
|
|
1438
|
+
* reference. Normalized across every emitter: `orderId` (redirect return) →
|
|
1439
|
+
* `result.confirmation.orderId` (Apple Pay) → `checkoutId`. `value` and
|
|
1440
|
+
* `currency` are deliberately NOT read from the result: on every path they
|
|
1441
|
+
* come from the cart snapshot (sum of the items, no shipping), so revenue
|
|
1442
|
+
* stays comparable across payment methods — the charged total will arrive
|
|
1443
|
+
* through the server-side `order_paid` event. With nothing to say it
|
|
1444
|
+
* returns `{}`, so the cart snapshot keeps its keys.
|
|
1445
|
+
*/
|
|
1446
|
+
declare function purchaseFromPaymentSuccess(d: PaymentSuccessDetail): Pick<AnalyticsCommerce, 'orderId' | 'buyerId'>;
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* The cart split per campaign (ADR-0034) — ONE rule, shared by the SDK's own
|
|
1450
|
+
* `begin_checkout` / `purchase` events, by `Vio.cartSlices()` and so by any
|
|
1451
|
+
* host with its own analytics sink (Vev).
|
|
1452
|
+
*
|
|
1453
|
+
* Every unit of every line goes to the campaign of its origin — the one the
|
|
1454
|
+
* place showed when it was added — and units without one to the campaign the
|
|
1455
|
+
* caller's rule resolves for the line's sponsor (`resolveCampaign`). One slice
|
|
1456
|
+
* per campaign: its items (quantities from the origins, merged per product +
|
|
1457
|
+
* variant), its value with two decimals, and `slot` / `contentId` /
|
|
1458
|
+
* `sponsorId` only when they are the same for the whole slice. A cart with
|
|
1459
|
+
* one campaign is one slice. Pure; never throws on odd lines.
|
|
1460
|
+
*/
|
|
1461
|
+
|
|
1462
|
+
/** An item of a slice — the analytics item shape (ids as given, normalized on the wire). */
|
|
1463
|
+
type VioItem = AnalyticsItemInput;
|
|
1464
|
+
/** One campaign's share of the cart. */
|
|
1465
|
+
interface CartSlice {
|
|
1466
|
+
campaignId?: number;
|
|
1467
|
+
sponsorId?: number;
|
|
1468
|
+
slot?: string;
|
|
1469
|
+
contentId?: string;
|
|
1470
|
+
items: VioItem[];
|
|
1471
|
+
value: number;
|
|
1472
|
+
currency?: string;
|
|
1473
|
+
/** 1-based position of this slice and how many there are. */
|
|
1474
|
+
slice: number;
|
|
1475
|
+
slices: number;
|
|
1476
|
+
}
|
|
1477
|
+
/** The campaign of a unit without an explicit one: the caller's rule (slot assignment → sponsor → default). */
|
|
1478
|
+
type ResolveCampaign = (slot: string | undefined, sponsorId: number) => number | undefined;
|
|
1479
|
+
declare function cartSlicesFrom(lines: ReadonlyArray<CartLineItem>, resolveCampaign: ResolveCampaign, fallbackCurrency?: string): CartSlice[];
|
|
1480
|
+
|
|
1481
|
+
/**
|
|
1482
|
+
* The attribution of a checkout (ADR-0035 phase B): what the order is born
|
|
1483
|
+
* knowing about the surface it was sold from, the campaign of the page, the
|
|
1484
|
+
* page itself and where the shopper came in from. Sent as `attribution` on
|
|
1485
|
+
* `CreateCheckout` and on the `UpdateCheckout` right before paying; shopcart
|
|
1486
|
+
* keeps it on the checkout (`checkout.attribution`, merged key by key) and
|
|
1487
|
+
* writes `order.surface_id` / `campaign_id` / `content_url` / `content_title`
|
|
1488
|
+
* / `entry_source` from it when the order is created. The surface itself is
|
|
1489
|
+
* checked there against the cart's channel: a page cannot credit a sale to
|
|
1490
|
+
* somebody else's surface.
|
|
1491
|
+
*
|
|
1492
|
+
* Pure: `checkoutAttributionOf()` takes what the facade gathered. snake_case
|
|
1493
|
+
* on the wire, the caps of shopcart's `CheckoutAttributionDto` enforced here.
|
|
1494
|
+
*/
|
|
1495
|
+
|
|
1496
|
+
/** `EntryContextDto`: what the page knew when the shopper came in (the SDK's landing memory). */
|
|
1497
|
+
interface EntryContextWire {
|
|
1498
|
+
referrer?: string;
|
|
1499
|
+
utm_source?: string;
|
|
1500
|
+
utm_medium?: string;
|
|
1501
|
+
utm_campaign?: string;
|
|
1502
|
+
landing_url?: string;
|
|
1503
|
+
}
|
|
1504
|
+
/** `CheckoutAttributionDto` (shopcart `checkout/dtos/checkout-attribution.dto.ts`). */
|
|
1505
|
+
interface CheckoutAttributionWire {
|
|
1506
|
+
surface_key?: string;
|
|
1507
|
+
campaign_id?: number;
|
|
1508
|
+
content_url?: string;
|
|
1509
|
+
content_title?: string;
|
|
1510
|
+
entry?: EntryContextWire;
|
|
1511
|
+
}
|
|
1512
|
+
/** The caps of `CheckoutAttributionDto` / `EntryContextDto`. */
|
|
1513
|
+
declare const CHECKOUT_ATTRIBUTION_CAPS: Readonly<{
|
|
1514
|
+
surfaceKey: 255;
|
|
1515
|
+
contentUrl: 2048;
|
|
1516
|
+
contentTitle: 255;
|
|
1517
|
+
referrer: 2048;
|
|
1518
|
+
utm: 128;
|
|
1519
|
+
landingUrl: 2048;
|
|
1520
|
+
}>;
|
|
1521
|
+
interface CheckoutAttributionInput {
|
|
1522
|
+
/** The surface's SDK key (`Vio.init({ apiKey })`) — shopcart resolves the surface from it. */
|
|
1523
|
+
surfaceKey?: string;
|
|
1524
|
+
/** The campaign the PAGE belongs to, when the bootstrap lists it as active (`Vio.pageCampaign()`). */
|
|
1525
|
+
pageCampaignId?: number;
|
|
1526
|
+
/** The cart split per campaign (`Vio.cartSlices(sponsorId)`), for the campaign that explains most units when the page has none. */
|
|
1527
|
+
slices?: ReadonlyArray<CartSlice>;
|
|
1528
|
+
/** The page at pay time: `Vio.content()`'s url and title. */
|
|
1529
|
+
content?: {
|
|
1530
|
+
url?: string;
|
|
1531
|
+
title?: string;
|
|
1532
|
+
};
|
|
1533
|
+
/** Where the session came in (`resolveLanding()`): referrer, utm, landing page. */
|
|
1534
|
+
landing?: Landing | null;
|
|
1535
|
+
/**
|
|
1536
|
+
* The surface's privacy mode. Only on a `standard` surface do the page
|
|
1537
|
+
* (`content_url`, `content_title`) and the entry context travel: which
|
|
1538
|
+
* screen the sale was made on and why the shopper was there is what
|
|
1539
|
+
* `minimal` keeps private — the same promise the collector keeps for the
|
|
1540
|
+
* events. `unknown` (it could not be learnt) counts as `minimal`: what can
|
|
1541
|
+
* reveal it is only sent when the surface is known to allow it. The surface
|
|
1542
|
+
* and the campaign always travel.
|
|
1543
|
+
*/
|
|
1544
|
+
privacyMode?: SurfacePrivacyMode | 'unknown';
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* The attribution for the wire, or `undefined` when there is nothing to say.
|
|
1548
|
+
* The campaign is the page's; without one, the campaign that explains most
|
|
1549
|
+
* units of the cart under the same rule `purchase` is split by (ties: the
|
|
1550
|
+
* higher value, then the first). The page (origin + path) and the entry go
|
|
1551
|
+
* only on a `standard` surface.
|
|
1552
|
+
*/
|
|
1553
|
+
declare function checkoutAttributionOf(input: CheckoutAttributionInput): CheckoutAttributionWire | undefined;
|
|
1554
|
+
/** The landing as `entry`, capped; `undefined` when it says nothing. */
|
|
1555
|
+
declare function entryContextOf(landing: Landing | null | undefined): EntryContextWire | undefined;
|
|
1556
|
+
/**
|
|
1557
|
+
* The campaign that explains most units of the cart — over the slices
|
|
1558
|
+
* `purchase` is split by, so the order names the campaign the biggest
|
|
1559
|
+
* purchase event names. Ties go to the higher value, then to the first
|
|
1560
|
+
* slice. Units nobody attributes (a slice without campaign) never win.
|
|
1561
|
+
*/
|
|
1562
|
+
declare function dominantCampaignOf(slices: ReadonlyArray<CartSlice> | null | undefined): number | undefined;
|
|
1563
|
+
|
|
1564
|
+
/**
|
|
1565
|
+
* Vipps MobilePay Payment Adapter — GraphQL Integration & Types.
|
|
1566
|
+
*
|
|
1567
|
+
* Vipps payment integration uses 2 GraphQL operations:
|
|
1568
|
+
*
|
|
1569
|
+
* 1. `CreatePaymentVipps` mutation:
|
|
1570
|
+
* Initiates a Vipps payment session for a checkout and returns `payment_url`.
|
|
1571
|
+
*
|
|
1572
|
+
* 2. `GetVippsStatus` query:
|
|
1573
|
+
* Queries Vipps payment state directly for a checkout (`state`).
|
|
1574
|
+
*/
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* GraphQL mutation to create a Vipps payment session.
|
|
1578
|
+
*/
|
|
1579
|
+
declare const CREATE_PAYMENT_VIPPS_MUTATION = "\nmutation CreatePaymentVipps($checkoutId: String!, $email: String, $returnUrl: String!, $express: Boolean) {\n Payment {\n CreatePaymentVipps(checkout_id: $checkoutId, email: $email, return_url: $returnUrl, express: $express) {\n payment_url\n reference\n express\n reason\n }\n }\n}\n";
|
|
1580
|
+
/**
|
|
1581
|
+
* GraphQL query to fetch current Vipps payment status.
|
|
1582
|
+
*/
|
|
1583
|
+
declare const GET_VIPPS_STATUS_QUERY = "\nquery GetVippsStatus($checkoutId: String!) {\n Payment {\n GetVippsStatus(checkout_id: $checkoutId) {\n state\n duplicate_of\n }\n }\n}\n";
|
|
1584
|
+
interface CreatePaymentVippsVariables extends Record<string, unknown> {
|
|
1585
|
+
checkoutId: string;
|
|
1586
|
+
/** Optional since Express: Vipps hands the email back with the payment. */
|
|
1587
|
+
email?: string;
|
|
1588
|
+
returnUrl: string;
|
|
1589
|
+
/**
|
|
1590
|
+
* `true` asks for Express — address and delivery chosen inside the Vipps
|
|
1591
|
+
* app. When the cart cannot have it, no payment is created and the answer
|
|
1592
|
+
* says `express: false` with the reason; the caller then opens the
|
|
1593
|
+
* ordinary checkout.
|
|
1594
|
+
*/
|
|
1595
|
+
express?: boolean;
|
|
1596
|
+
}
|
|
1597
|
+
interface CreatePaymentVippsResponse {
|
|
1598
|
+
/** Absent when Express was asked for and refused. */
|
|
1599
|
+
payment_url?: string;
|
|
1600
|
+
/** The reference the seller reads in its Vipps portal. */
|
|
1601
|
+
reference?: string;
|
|
1602
|
+
express?: boolean;
|
|
1603
|
+
reason?: string;
|
|
1604
|
+
}
|
|
1605
|
+
interface GetVippsStatusVariables extends Record<string, unknown> {
|
|
1606
|
+
checkoutId: string;
|
|
1607
|
+
}
|
|
1608
|
+
interface VippsStatusResult {
|
|
1609
|
+
state: string;
|
|
1610
|
+
/** Set when this checkout was closed as a duplicate: the checkout that paid the cart. */
|
|
1611
|
+
duplicate_of?: string | null;
|
|
1612
|
+
}
|
|
1613
|
+
type VippsPaymentState = 'CREATED' | 'INITIATED' | 'AUTHORIZED' | 'TERMINATED' | 'EXPIRED' | string;
|
|
1614
|
+
/**
|
|
1615
|
+
* Executes the `CreatePaymentVipps` GraphQL mutation.
|
|
1616
|
+
*/
|
|
1617
|
+
declare function createPaymentVipps(variables: CreatePaymentVippsVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<CreatePaymentVippsResponse | null>;
|
|
1618
|
+
/**
|
|
1619
|
+
* Executes the `GetVippsStatus` GraphQL query.
|
|
1620
|
+
*/
|
|
1621
|
+
declare function getVippsStatus(variables: GetVippsStatusVariables | Record<string, unknown>, options?: CartQueryOptions): Promise<VippsStatusResult | null>;
|
|
1622
|
+
|
|
1623
|
+
declare const CREATE_CART_MUTATION = "\nmutation CreateCart($customerSessionId: String!, $currency: String!, $shippingCountry: String) {\n Cart {\n CreateCart(customer_session_id: $customerSessionId, currency: $currency, shipping_country: $shippingCountry) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
|
|
1624
|
+
declare const ADD_ITEM_MUTATION = "\nmutation AddItem($cartId: String!, $lineItems: [LineItemInput!]!) {\n Cart {\n AddItem(cart_id: $cartId, line_items: $lineItems) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
|
|
1625
|
+
declare const DELETE_ITEM_MUTATION = "\nmutation DeleteItem($cartId: String!, $cartItemId: String!) {\n Cart {\n DeleteItem(cart_id: $cartId, cart_item_id: $cartItemId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
|
|
1626
|
+
declare const UPDATE_ITEM_MUTATION: string;
|
|
1627
|
+
/** `UpdateItem` with the `origin` of the added units (`CartLineOriginInput`, snake_case fields — see `lineOriginWire`). */
|
|
1628
|
+
declare const UPDATE_ITEM_WITH_ORIGIN_MUTATION: string;
|
|
1629
|
+
declare const GET_CART_QUERY = "\nquery GetCart($cartId: String!) {\n Cart {\n GetCart(cart_id: $cartId) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
|
|
1630
|
+
declare const GET_LINE_ITEMS_BY_SUPPLIER_QUERY = "\nquery GetLineItemsBySupplier($cartId: String!) {\n Cart {\n GetLineItemsBySupplier(cart_id: $cartId) {\n supplier {\n id\n name\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n }\n }\n}\n";
|
|
1631
|
+
declare const UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION = "\nmutation UpdateShippingsBySupplier($cartId: String!, $data: [DataUpdateShippingsBySupplier!]!) {\n Cart {\n UpdateShippingsBySupplier(cart_id: $cartId, data: $data) {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n }\n}\n";
|
|
1632
|
+
declare const CREATE_CHECKOUT_MUTATION: string;
|
|
1633
|
+
/** `CreateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`, snake_case fields — see `checkoutAttributionOf`). */
|
|
1634
|
+
declare const CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
|
|
1635
|
+
declare const UPDATE_CHECKOUT_MUTATION: string;
|
|
1636
|
+
/** `UpdateCheckout` with the checkout's `attribution` (`CheckoutAttributionInput`). */
|
|
1637
|
+
declare const UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION: string;
|
|
1638
|
+
declare const GET_CHECKOUT_QUERY = "\nquery GetCheckout($checkoutId: String!) {\n Checkout {\n GetCheckout(checkout_id: $checkoutId) {\n buyer_accepts_purchase_conditions\n buyer_accepts_terms_conditions\n created_at\n updated_at\n id\n deleted_at\n success_url\n cancel_url\n payment_method\n email\n status\n checkout_url\n origin_payment_id\n duplicate_of\n billing_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n shipping_address {\n id\n first_name\n last_name\n phone_code\n phone\n company\n address1\n address2\n city\n province\n province_code\n country\n country_code\n zip\n }\n available_payment_methods {\n name\n }\n discount_code\n cart {\n cart_id\n customer_session_id\n shipping_country\n line_items {\n id\n supplier\n image {\n id\n url\n width\n height\n }\n sku\n barcode\n brand\n product_id\n title\n variant_id\n variant_title\n variant {\n option\n value\n }\n quantity\n price {\n amount\n currency_code\n discount\n compare_at\n compare_at_incl_taxes\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n shipping {\n id\n name\n description\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n available_shippings {\n id\n name\n description\n country_code\n price {\n amount\n currency_code\n amount_incl_taxes\n tax_amount\n tax_rate\n }\n }\n }\n subtotal\n shipping\n currency\n available_shipping_countries\n }\n totals {\n currency_code\n subtotal\n shipping\n total\n taxes\n tax_rate\n discounts\n }\n }\n }\n}\n";
|
|
1639
|
+
declare const GET_AVAILABLE_PAYMENT_METHODS_QUERY = "\nquery Config {\n Payment {\n GetAvailablePaymentMethods {\n config {\n name\n type\n value\n }\n name\n }\n }\n}\n";
|
|
1640
|
+
|
|
1641
|
+
/** Transport options for a cart/checkout GraphQL call. */
|
|
1642
|
+
interface CartQueryOptions {
|
|
1643
|
+
endpoint?: string;
|
|
1644
|
+
apiKey?: string;
|
|
1645
|
+
/** Sponsor commerce key — goes in the Authorization header. */
|
|
1646
|
+
commerceKey?: string;
|
|
1647
|
+
/** True when the commerce key came from a resolved sponsor (bootstrap).
|
|
1648
|
+
* False = we fell back to the host apiKey — writes like CreateCart should
|
|
1649
|
+
* NOT proceed with the wrong key (the cart would be orphaned). */
|
|
1650
|
+
sponsorResolved?: boolean;
|
|
1651
|
+
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Resolve endpoint + keys for cart GraphQL calls. Awaits Vio.bootstrap() once
|
|
1654
|
+
* if it hasn't run yet (the sponsor commerce keys come from bootstrap), then
|
|
1655
|
+
* uses the sponsor's commerce apiKey (via the Vio facade on globalThis,
|
|
1656
|
+
* avoiding an import cycle); falls back to the host apiKey.
|
|
1657
|
+
*/
|
|
1658
|
+
declare function getCartGraphQLOptions(sponsorId?: number): Promise<CartQueryOptions>;
|
|
1659
|
+
/** Stable per-browser customer session id (backend CreateCart requires one). */
|
|
1660
|
+
declare function getCustomerSessionId(): string;
|
|
1661
|
+
interface GraphQLEnvelope {
|
|
1662
|
+
data?: Record<string, Record<string, unknown>> | null;
|
|
1663
|
+
errors?: Array<{
|
|
1664
|
+
message?: string;
|
|
1665
|
+
path?: unknown;
|
|
1666
|
+
}>;
|
|
1667
|
+
}
|
|
1668
|
+
/** Execute a GraphQL query/mutation against the configured commerce endpoint.
|
|
1669
|
+
* Callers that skip `getCartGraphQLOptions()` (or pass a bare sponsorId) get
|
|
1670
|
+
* it resolved here instead of silently sending an unauthenticated request.
|
|
1671
|
+
* Rejects after `CART_GRAPHQL_TIMEOUT_MS` (and aborts the fetch). */
|
|
1672
|
+
declare function executeCartGraphQL(query: string, variables: Record<string, unknown>, options?: CartQueryOptions | number | undefined): Promise<GraphQLEnvelope>;
|
|
1673
|
+
declare function createCart(customerSessionId: string, currency: string, shippingCountry?: string | null, options?: CartQueryOptions): Promise<any>;
|
|
1674
|
+
/**
|
|
1675
|
+
* `AddItem`. A line may carry `origin` (`LineOriginWire`: where its units
|
|
1676
|
+
* come from — ADR-0035 phase B). A gateway that predates the field refuses
|
|
1677
|
+
* the whole mutation at validation (`LineItemInput` has no `origin`), so the
|
|
1678
|
+
* lines are sent again without it, once per page load — see gateway-features.
|
|
1679
|
+
*/
|
|
1680
|
+
declare function addItem(cartId: string, lineItems: unknown[], options?: CartQueryOptions): Promise<any>;
|
|
1681
|
+
declare function deleteItem(cartId: string, cartItemId: string, options?: CartQueryOptions): Promise<any>;
|
|
1682
|
+
/**
|
|
1683
|
+
* `UpdateItem`. `extra.origin` is where the units a quantity INCREASE adds
|
|
1684
|
+
* come from (ADR-0035 phase B); the server credits the new units to it. Sent
|
|
1685
|
+
* only with it; a gateway that predates the argument gets the legacy
|
|
1686
|
+
* mutation instead, once per page load — see gateway-features.
|
|
1687
|
+
*/
|
|
1688
|
+
declare function updateItem(cartId: string, cartItemId: string, shippingId?: string | null, qty?: number | null, options?: CartQueryOptions, extra?: {
|
|
1689
|
+
origin?: LineOriginWire;
|
|
1690
|
+
}): Promise<any>;
|
|
1691
|
+
declare function getCart(cartId: string, options?: CartQueryOptions): Promise<any>;
|
|
1692
|
+
declare function getLineItemsBySupplier(cartId: string, options?: CartQueryOptions): Promise<any>;
|
|
1693
|
+
declare function updateShippingsBySupplier(cartId: string, data: unknown[], options?: CartQueryOptions): Promise<any>;
|
|
1694
|
+
/**
|
|
1695
|
+
* `CreateCheckout`. With `extra.attribution` (`CheckoutAttributionWire`:
|
|
1696
|
+
* the surface, the page's campaign, the page and the entry — ADR-0035 phase
|
|
1697
|
+
* B) the checkout is born attributed; a gateway that predates the argument
|
|
1698
|
+
* gets the legacy mutation, once per page load — see gateway-features.
|
|
1699
|
+
*/
|
|
1700
|
+
declare function createCheckout(cartId: string, options?: CartQueryOptions, extra?: {
|
|
1701
|
+
attribution?: CheckoutAttributionWire;
|
|
1702
|
+
}): Promise<any>;
|
|
1703
|
+
/**
|
|
1704
|
+
* `UpdateCheckout`. `variables.attribution` (`CheckoutAttributionWire`) is
|
|
1705
|
+
* merged key by key over what the checkout has; a gateway that predates the
|
|
1706
|
+
* argument gets the legacy mutation without it, once per page load.
|
|
1707
|
+
*/
|
|
1708
|
+
declare function updateCheckout(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
|
|
1709
|
+
declare function getCheckout(checkoutId: string, options?: CartQueryOptions): Promise<any>;
|
|
1710
|
+
/** What a checkout says of itself after paying: its Vio order number, once the order exists, and its buyer reference. */
|
|
1711
|
+
interface CheckoutReference {
|
|
1712
|
+
orderNumber: number | null;
|
|
1713
|
+
buyerRef: string | null;
|
|
1714
|
+
}
|
|
1715
|
+
/** The order number (null while the order does not exist yet) and the buyer reference (null when the API does not say it). */
|
|
1716
|
+
declare function getCheckoutReference(checkoutId: string, options?: CartQueryOptions): Promise<CheckoutReference>;
|
|
1717
|
+
declare function getAvailablePaymentMethods(options?: CartQueryOptions): Promise<any>;
|
|
1718
|
+
declare const CREATE_PAYMENT_STRIPE_MUTATION = "\nmutation CreatePaymentStripe($checkoutId: String!, $successUrl: String!, $paymentMethod: String!, $email: String!) {\n Payment {\n CreatePaymentStripe(checkout_id: $checkoutId, success_url: $successUrl, payment_method: $paymentMethod, email: $email) {\n order_id\n checkout_url\n }\n }\n}\n";
|
|
1719
|
+
declare function createPaymentStripe(variables: Record<string, unknown>, options?: CartQueryOptions): Promise<any>;
|
|
1720
|
+
|
|
1721
|
+
/**
|
|
1722
|
+
* Stripe on our own page — the Payment Element, no redirect.
|
|
1723
|
+
*
|
|
1724
|
+
* The older web flow minted a Stripe Payment Link and sent the shopper to a
|
|
1725
|
+
* page hosted by Stripe. This one keeps them here (Angelo, 2026-09-24):
|
|
1726
|
+
*
|
|
1727
|
+
* 1. Vio Commerce creates a PaymentIntent for the checkout
|
|
1728
|
+
* (`Payment { CreatePaymentIntentStripe }`) and answers with its client
|
|
1729
|
+
* secret AND the publishable key of the account that minted it — the
|
|
1730
|
+
* seller's when they brought both keys, ours otherwise. The two are
|
|
1731
|
+
* halves of one account: the browser confirms with the key what the
|
|
1732
|
+
* server minted with the secret one.
|
|
1733
|
+
* 2. Stripe's Payment Element is mounted in a LIGHT-DOM container, the way
|
|
1734
|
+
* the other embedded widgets are. Card fields are Stripe's own iframes,
|
|
1735
|
+
* so card data never touches this SDK or our servers.
|
|
1736
|
+
* 3. `confirm()` pays. A 3-D Secure challenge opens in Stripe's own modal
|
|
1737
|
+
* over the page: `redirect: 'if_required'` keeps the shopper here for
|
|
1738
|
+
* cards, and still redirects for a method that has no other way.
|
|
1739
|
+
* 4. The Commerce order is NOT born here. Stripe's `payment_intent.succeeded`
|
|
1740
|
+
* webhook creates it, verified server-side; the checkout is polled for
|
|
1741
|
+
* its status afterwards, exactly as the redirect return does.
|
|
1742
|
+
*/
|
|
1743
|
+
|
|
1744
|
+
/** What the backend hands over to pay a checkout on our page. */
|
|
1745
|
+
interface StripeIntent {
|
|
1746
|
+
/** `pi_..._secret_...`: what the browser confirms. */
|
|
1747
|
+
client_secret: string;
|
|
1748
|
+
/** The key of the SAME account that minted the secret. */
|
|
1749
|
+
publishable_key: string;
|
|
1750
|
+
customer?: string;
|
|
1751
|
+
/**
|
|
1752
|
+
* Stripe Connect (ADR-0022): the seller's connected account, where the
|
|
1753
|
+
* intent lives. The browser must name it or Stripe answers "no such
|
|
1754
|
+
* payment_intent". Absent for every seller not on Connect.
|
|
1755
|
+
*/
|
|
1756
|
+
stripe_account?: string;
|
|
1757
|
+
}
|
|
1758
|
+
/** What `confirm()` answers. The browser's word is never the order. */
|
|
1759
|
+
type StripeConfirmOutcome = {
|
|
1760
|
+
status: 'succeeded';
|
|
1761
|
+
paymentIntentId?: string;
|
|
1762
|
+
}
|
|
1763
|
+
/** Authorised but not settled yet, or Stripe redirected and will return. */
|
|
1764
|
+
| {
|
|
1765
|
+
status: 'pending';
|
|
1766
|
+
paymentIntentId?: string;
|
|
1767
|
+
} | {
|
|
1768
|
+
status: 'failed';
|
|
1769
|
+
message?: string;
|
|
1770
|
+
code?: string;
|
|
1771
|
+
};
|
|
1772
|
+
interface StripeElementHandle {
|
|
1773
|
+
confirm(): Promise<StripeConfirmOutcome>;
|
|
1774
|
+
unmount(): void;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/**
|
|
1778
|
+
* Apple Pay on the Web — via Stripe Payment Request API.
|
|
1779
|
+
*
|
|
1780
|
+
* Architecture decision (matches iOS Vio SDK pattern):
|
|
1781
|
+
* - One Stripe **publishable key** for the Vio platform (global, set
|
|
1782
|
+
* via `Vio.init({ stripePublishableKey })`).
|
|
1783
|
+
* - One **Stripe Connect account id** per sponsor — sourced from
|
|
1784
|
+
* `Vio.bootstrap()` response. Without it, the payment lands on the
|
|
1785
|
+
* platform account instead of the merchant.
|
|
1786
|
+
*
|
|
1787
|
+
* Apple Pay on the Web prerequisites (Stripe-managed for us):
|
|
1788
|
+
* - Stripe Connect account is enabled for Apple Pay
|
|
1789
|
+
* - Domain registration for Apple Pay (Stripe handles via Dashboard)
|
|
1790
|
+
* - Safari + macOS/iOS device with Apple Pay configured
|
|
1791
|
+
*
|
|
1792
|
+
* In Chrome / non-Apple browsers `canMakePayment()` returns null, so the
|
|
1793
|
+
* UI hides the Apple Pay button automatically.
|
|
1794
|
+
*/
|
|
1795
|
+
interface ApplePayConfig {
|
|
1796
|
+
/** Stripe platform publishable key (pk_live_xxx or pk_test_xxx). */
|
|
1797
|
+
publishableKey: string;
|
|
1798
|
+
/** Sponsor's Stripe Connect account (acct_xxx). Optional but recommended. */
|
|
1799
|
+
connectedAccount?: string;
|
|
1800
|
+
/** Amount in the smallest unit of the currency (e.g. øre for NOK, cents for USD). */
|
|
1801
|
+
amount: number;
|
|
1802
|
+
/** ISO currency code, lowercased internally for Stripe. */
|
|
1803
|
+
currency: string;
|
|
1804
|
+
/** Two-letter country code, e.g. "NO". */
|
|
1805
|
+
country: string;
|
|
1806
|
+
/** Label shown in the Apple Pay sheet (merchant or order name). */
|
|
1807
|
+
label: string;
|
|
1808
|
+
/** Whether to ask the user for payer name. */
|
|
1809
|
+
requestPayerName?: boolean;
|
|
1810
|
+
/** Whether to ask the user for payer email. */
|
|
1811
|
+
requestPayerEmail?: boolean;
|
|
1812
|
+
/** Whether to ask for shipping address. */
|
|
1813
|
+
requestShipping?: boolean;
|
|
1814
|
+
/**
|
|
1815
|
+
* Shipping options shown natively in the Apple Pay sheet. `amount` is in the
|
|
1816
|
+
* smallest unit (øre). When set, `requestShipping` is forced on and the sheet
|
|
1817
|
+
* total = `amount` (items) + the selected option; switching options updates
|
|
1818
|
+
* the total live (Apple Pay native shipping).
|
|
1819
|
+
*/
|
|
1820
|
+
shippingOptions?: Array<{
|
|
1821
|
+
id: string;
|
|
1822
|
+
label: string;
|
|
1823
|
+
detail?: string;
|
|
1824
|
+
amount: number;
|
|
1825
|
+
}>;
|
|
1826
|
+
/**
|
|
1827
|
+
* Charge hook, run INSIDE the sheet's authorize event with the tokenized
|
|
1828
|
+
* payment. Must perform the real (backend) charge and throw on failure —
|
|
1829
|
+
* only then does the sheet close with success; a throw closes it with
|
|
1830
|
+
* failure. Its resolved value is surfaced as `ApplePayResult.confirmation`.
|
|
1831
|
+
*/
|
|
1832
|
+
onAuthorize?: (result: ApplePayResult) => Promise<unknown>;
|
|
1833
|
+
}
|
|
1834
|
+
interface ApplePayResult {
|
|
1835
|
+
/** Stripe PaymentMethod id (pm_xxx) — pass to backend to confirm the PaymentIntent. */
|
|
1836
|
+
paymentMethodId: string;
|
|
1837
|
+
payerName?: string;
|
|
1838
|
+
payerEmail?: string;
|
|
1839
|
+
payerPhone?: string;
|
|
1840
|
+
shippingAddress?: {
|
|
1841
|
+
line1?: string;
|
|
1842
|
+
line2?: string;
|
|
1843
|
+
city?: string;
|
|
1844
|
+
postal_code?: string;
|
|
1845
|
+
state?: string;
|
|
1846
|
+
country?: string;
|
|
1847
|
+
};
|
|
1848
|
+
/** Whatever `onAuthorize` resolved with (e.g. backend order_id/status). */
|
|
1849
|
+
confirmation?: unknown;
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Check whether Apple Pay is available right now (Safari + supported device
|
|
1853
|
+
* + Stripe configured + domain registered).
|
|
1854
|
+
*
|
|
1855
|
+
* Returns false on any failure path — never throws.
|
|
1856
|
+
*/
|
|
1857
|
+
declare function checkApplePayAvailability(config: ApplePayConfig): Promise<boolean>;
|
|
1858
|
+
/**
|
|
1859
|
+
* Show the Apple Pay sheet. Resolves with the payment method id (`pm_xxx`)
|
|
1860
|
+
* after the user authorises, or rejects on cancel / error.
|
|
1861
|
+
*
|
|
1862
|
+
* The backend must then confirm a Stripe PaymentIntent with this
|
|
1863
|
+
* payment method id (server-side step, not handled here).
|
|
1864
|
+
*/
|
|
1865
|
+
declare function showApplePaySheet(config: ApplePayConfig): Promise<ApplePayResult | null>;
|
|
1866
|
+
|
|
1867
|
+
/** One line in the express button's purchase data. Amounts in MINOR units. */
|
|
1868
|
+
interface KlarnaLineItem {
|
|
1869
|
+
name: string;
|
|
1870
|
+
quantity: number;
|
|
1871
|
+
/** Line total (unitPrice × quantity), minor units (e.g. øre for NOK). */
|
|
1872
|
+
totalAmount: number;
|
|
1873
|
+
/** Per-unit price, minor units. Optional. */
|
|
1874
|
+
unitPrice?: number;
|
|
1875
|
+
/** Merchant SKU / product reference. Optional. */
|
|
1876
|
+
reference?: string;
|
|
1877
|
+
/** Absolute image URL. Optional. */
|
|
1878
|
+
imageUrl?: string;
|
|
1879
|
+
}
|
|
1880
|
+
/** Payment request handed to the KEC button. Amounts in MINOR units. */
|
|
1881
|
+
interface KlarnaPaymentRequestData {
|
|
1882
|
+
/** ISO currency code (e.g. "NOK"). */
|
|
1883
|
+
currency: string;
|
|
1884
|
+
/** Order total in minor units. */
|
|
1885
|
+
amount: number;
|
|
1886
|
+
/** Line items — shown in the Klarna sheet. */
|
|
1887
|
+
supplementaryPurchaseData?: {
|
|
1888
|
+
lineItems: KlarnaLineItem[];
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
interface KlarnaAuthorizeResult {
|
|
1892
|
+
/** Authorization token — backend exchanges it for an order. */
|
|
1893
|
+
authorizationToken: string;
|
|
1894
|
+
/** Klarna may require a finalize step (multistep flows). */
|
|
1895
|
+
finalizeRequired?: boolean;
|
|
1896
|
+
/** Raw payload from the SDK, for debugging / forward-compat. */
|
|
1897
|
+
raw?: unknown;
|
|
1898
|
+
}
|
|
1899
|
+
interface KlarnaButtonHandle {
|
|
1900
|
+
unmount(): void;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
interface KlarnaPaymentsCategory {
|
|
1904
|
+
identifier: string;
|
|
1905
|
+
name: string;
|
|
1906
|
+
asset_urls?: {
|
|
1907
|
+
descriptive?: string;
|
|
1908
|
+
standard?: string;
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
interface KpLoadResult {
|
|
1912
|
+
show_form?: boolean;
|
|
1913
|
+
error?: unknown;
|
|
1914
|
+
}
|
|
1915
|
+
interface KpAuthorizeResult {
|
|
1916
|
+
approved?: boolean;
|
|
1917
|
+
show_form?: boolean;
|
|
1918
|
+
authorization_token?: string;
|
|
1919
|
+
finalize_required?: boolean;
|
|
1920
|
+
error?: unknown;
|
|
1921
|
+
}
|
|
1922
|
+
interface KlarnaPaymentsApi {
|
|
1923
|
+
init(opts: {
|
|
1924
|
+
client_token: string;
|
|
1925
|
+
}): void;
|
|
1926
|
+
load(opts: {
|
|
1927
|
+
container: string | HTMLElement;
|
|
1928
|
+
payment_method_category?: string;
|
|
1929
|
+
}, data: Record<string, unknown>, cb?: (res: KpLoadResult) => void): void;
|
|
1930
|
+
authorize(opts: {
|
|
1931
|
+
payment_method_category?: string;
|
|
1932
|
+
auto_finalize?: boolean;
|
|
1933
|
+
}, data: Record<string, unknown>, cb?: (res: KpAuthorizeResult) => void): void;
|
|
1934
|
+
/** Debug/lifecycle events — e.g. 'fullscreenOverlayShown'/'fullscreenOverlayHidden'. */
|
|
1935
|
+
on?(event: string, cb: () => void): void;
|
|
1936
|
+
}
|
|
1937
|
+
interface KlarnaGlobal {
|
|
1938
|
+
Payments: KlarnaPaymentsApi;
|
|
1939
|
+
}
|
|
1940
|
+
declare global {
|
|
1941
|
+
interface Window {
|
|
1942
|
+
Klarna?: KlarnaGlobal;
|
|
1943
|
+
klarnaAsyncCallback?: () => void;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/**
|
|
1948
|
+
* Kustom (former Klarna Checkout) — embedded KCO v3 checkout.
|
|
1949
|
+
*
|
|
1950
|
+
* Kustom kept the Klarna Checkout dialect on its own hosts, so the flow is
|
|
1951
|
+
* the classic KCO embed:
|
|
1952
|
+
*
|
|
1953
|
+
* 1. Vio Commerce creates the order (`Payment { CreatePaymentKustom }`,
|
|
1954
|
+
* authed with the sponsor's commerce API key; the seller's own
|
|
1955
|
+
* kco_*_api_* key lives server-side, per seller, never here). One order
|
|
1956
|
+
* per checkout: asking again while it is open UPDATES it.
|
|
1957
|
+
* 2. The response's `html_snippet` is injected into a LIGHT-DOM container
|
|
1958
|
+
* — it renders Kustom's iframe, which collects address, shipping AND
|
|
1959
|
+
* payment by itself (the widget does everything; no Vio address form).
|
|
1960
|
+
* 3. While it is open, the widget talks through `window._klarnaCheckout`:
|
|
1961
|
+
* we suspend it around a cart change (`Payment { SyncPaymentKustom }`),
|
|
1962
|
+
* and listen to its totals so our summary never disagrees with it.
|
|
1963
|
+
* 4. On completion Kustom redirects to the confirmation URL
|
|
1964
|
+
* (`?order_id=…&payment_processor=KUSTOM&checkout_id=…`), where the SDK
|
|
1965
|
+
* re-reads the order (`Payment { GetKustomOrder }`) — the backend
|
|
1966
|
+
* completes it right there — and renders Kustom's own receipt.
|
|
1967
|
+
*
|
|
1968
|
+
* The Commerce order is created server-side, from what Kustom says it
|
|
1969
|
+
* charged (Order Management), whether the shopper comes back or not (the
|
|
1970
|
+
* push) — the browser never confirms money.
|
|
1971
|
+
*/
|
|
1972
|
+
|
|
1973
|
+
/** A Kustom order as shopcart normalizes it (never Kustom's raw order). */
|
|
1974
|
+
interface KustomOrder {
|
|
1975
|
+
order_id: string;
|
|
1976
|
+
/** `checkout_incomplete` | `checkout_complete`, lower-cased by the backend. */
|
|
1977
|
+
status: string;
|
|
1978
|
+
html_snippet: string;
|
|
1979
|
+
purchase_country?: string;
|
|
1980
|
+
purchase_currency?: string;
|
|
1981
|
+
checkout_id?: string;
|
|
1982
|
+
environment?: string;
|
|
1983
|
+
/** Goods + the shipping shown or charged, decimal. */
|
|
1984
|
+
total_price?: number;
|
|
1985
|
+
shipping_name?: string;
|
|
1986
|
+
shipping_price?: number;
|
|
1987
|
+
/** Whether the Vio Commerce order exists (after completion). */
|
|
1988
|
+
order_created?: boolean;
|
|
1989
|
+
/** Kustom's short shopper-facing reference (after completion). */
|
|
1990
|
+
reference?: string;
|
|
1991
|
+
}
|
|
1992
|
+
interface KustomShippingChange {
|
|
1993
|
+
id?: string;
|
|
1994
|
+
name?: string;
|
|
1995
|
+
description?: string;
|
|
1996
|
+
/** Minor units, as the widget reports them. */
|
|
1997
|
+
price?: number;
|
|
1998
|
+
tax_amount?: number;
|
|
1999
|
+
tax_rate?: number;
|
|
2000
|
+
}
|
|
2001
|
+
interface KustomListenerHandlers {
|
|
2002
|
+
/** The iframe rendered. */
|
|
2003
|
+
onLoad?: (data: any) => void;
|
|
2004
|
+
/** The order total the widget shows, in MINOR units. */
|
|
2005
|
+
onOrderTotalChange?: (orderTotalMinor: number) => void;
|
|
2006
|
+
/** The shopper picked a rate inside the widget. */
|
|
2007
|
+
onShippingOptionChange?: (option: KustomShippingChange) => void;
|
|
2008
|
+
/** The shopper could not pay (declined credit…): show another way. */
|
|
2009
|
+
onCannotComplete?: () => void;
|
|
2010
|
+
onNetworkError?: () => void;
|
|
2011
|
+
/** The shopper is about to leave for the confirmation page. */
|
|
2012
|
+
onRedirectInitiated?: () => void;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
/**
|
|
2016
|
+
* Qliro Checkout — embedded checkout via Vio Commerce.
|
|
2017
|
+
*
|
|
2018
|
+
* Same embed philosophy as Kustom (the widget collects address, shipping
|
|
2019
|
+
* AND payment), different provider API underneath — shopcart normalizes
|
|
2020
|
+
* Qliro's Merchant API (OrderId / CustomerCheckoutStatus / OrderHtmlSnippet)
|
|
2021
|
+
* to the { order_id, status, html_snippet } shape both flows share:
|
|
2022
|
+
*
|
|
2023
|
+
* 1. `Payment { CreatePaymentQliro }` creates the order and returns the
|
|
2024
|
+
* snippet (sponsor-key authed; the seller's MerchantApiKey/Secret live
|
|
2025
|
+
* server-side, per seller, never here).
|
|
2026
|
+
* 2. The snippet is injected (script-executing embed, shared with Kustom).
|
|
2027
|
+
* 3. On completion Qliro redirects to the confirmation URL
|
|
2028
|
+
* (`?checkout_id=…&payment_processor=QLIRO`); the SDK re-reads the
|
|
2029
|
+
* order via `Payment { GetQliroOrder(checkout_id) }` — Qliro
|
|
2030
|
+
* correlates by the OWNING CHECKOUT, not the order id — and renders
|
|
2031
|
+
* the snippet again, which shows Qliro's own receipt.
|
|
2032
|
+
*
|
|
2033
|
+
* The Commerce order is created server-side by Qliro's push webhook
|
|
2034
|
+
* (shopcart /checkout/payment/qliro/ok) — the browser never confirms money.
|
|
2035
|
+
*/
|
|
2036
|
+
|
|
2037
|
+
/** Normalized Qliro order (shopcart maps the PascalCase Merchant API). */
|
|
2038
|
+
interface QliroOrder {
|
|
2039
|
+
order_id: string;
|
|
2040
|
+
/** Qliro CustomerCheckoutStatus: InProcess | Completed | OnHold | Refused. */
|
|
2041
|
+
status: string;
|
|
2042
|
+
html_snippet: string;
|
|
2043
|
+
purchase_country?: string;
|
|
2044
|
+
purchase_currency?: string;
|
|
2045
|
+
total_price?: number;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
/**
|
|
2049
|
+
* Qliro's browser-side protocol (`q1`).
|
|
2050
|
+
*
|
|
2051
|
+
* The embedded widget publishes a `q1` object on the window and calls a
|
|
2052
|
+
* globally-defined `q1Ready` once it has rendered. Everything the customer
|
|
2053
|
+
* does inside the iframe — picking a shipping method, changing their address,
|
|
2054
|
+
* having a payment declined — is only observable through these listeners.
|
|
2055
|
+
* Without them the widget is a black box: the customer can change the
|
|
2056
|
+
* shipping and our own summary keeps showing the old total.
|
|
2057
|
+
*
|
|
2058
|
+
* Two rules from Qliro's documentation shape this module:
|
|
2059
|
+
*
|
|
2060
|
+
* 1. **Lock before touching the backend.** Otherwise the customer can
|
|
2061
|
+
* complete the purchase while the order is still being synchronized.
|
|
2062
|
+
* 2. **Compare before unlocking.** Otherwise a second change interrupts the
|
|
2063
|
+
* synchronization of the first.
|
|
2064
|
+
*
|
|
2065
|
+
* We compare on `MerchantUpdateVersion`, the token Qliro echoes back through
|
|
2066
|
+
* `onOrderUpdated`, rather than on totals. Totals cannot be the test here: in
|
|
2067
|
+
* the modes where Qliro owns the shipping amount our total and Qliro's
|
|
2068
|
+
* legitimately differ, and the customer would sit locked out of a checkout
|
|
2069
|
+
* that is in fact up to date.
|
|
2070
|
+
*/
|
|
2071
|
+
|
|
2072
|
+
interface QliroSyncResult {
|
|
2073
|
+
order_id: string;
|
|
2074
|
+
/** Token to wait for in `onOrderUpdated` before unlocking. */
|
|
2075
|
+
update_version: string;
|
|
2076
|
+
total_price: number;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
/**
|
|
2080
|
+
* Walley (former Collector) — embedded checkout via Vio Commerce.
|
|
2081
|
+
*
|
|
2082
|
+
* Third embedded provider, same category as Kustom/Qliro: the widget
|
|
2083
|
+
* collects address, shipping AND payment by itself.
|
|
2084
|
+
*
|
|
2085
|
+
* 1. `Payment { CreatePaymentWalley }` initializes the session (sponsor-key
|
|
2086
|
+
* authed; the seller's own Walley credentials live server-side, per
|
|
2087
|
+
* seller, never here) and returns a SYNTHESIZED html_snippet — Walley's
|
|
2088
|
+
* real embed is a `<script data-token>` loader, so shopcart wraps it
|
|
2089
|
+
* in the same shape Kustom/Qliro use, and this module reuses their
|
|
2090
|
+
* exact script-executing injection.
|
|
2091
|
+
* 2. Walley's own script renders the iframe. On completion it dispatches
|
|
2092
|
+
* the DOM event `walleyCheckoutPurchaseCompleted` — the PRIMARY success
|
|
2093
|
+
* signal, no page reload needed. `redirectPageUri` is registered too
|
|
2094
|
+
* (`?checkout_id=…&payment_processor=WALLEY`, same contract as
|
|
2095
|
+
* Kustom/Qliro) as a safety net in case the event is missed (tab
|
|
2096
|
+
* backgrounded, page reload).
|
|
2097
|
+
* 3. Either path re-reads the session (`Payment { GetWalleyOrder }`) BY
|
|
2098
|
+
* OWNING CHECKOUT — same as Qliro — and re-renders Walley's own
|
|
2099
|
+
* receipt.
|
|
2100
|
+
*
|
|
2101
|
+
* The Commerce order itself is created server-side by Walley's notification
|
|
2102
|
+
* webhook (shopcart /checkout/payment/walley/ok) — the browser never
|
|
2103
|
+
* confirms money.
|
|
2104
|
+
*/
|
|
2105
|
+
|
|
2106
|
+
/** Normalized Walley session (shopcart maps privateId/publicToken/status). */
|
|
2107
|
+
interface WalleyOrder {
|
|
2108
|
+
order_id: string;
|
|
2109
|
+
/** Walley status: Initialized | CustomerIdentified | CommittedToPurchase | PurchaseCompleted | Aborted. */
|
|
2110
|
+
status: string;
|
|
2111
|
+
html_snippet: string;
|
|
2112
|
+
public_token?: string;
|
|
2113
|
+
purchase_country?: string;
|
|
2114
|
+
purchase_currency?: string;
|
|
2115
|
+
total_price?: number;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Nexi Checkout (formerly Nets Easy) — embedded checkout via Vio Commerce.
|
|
2120
|
+
*
|
|
2121
|
+
* Fourth embedded provider, same category as Kustom/Qliro/Walley: the widget
|
|
2122
|
+
* collects email, phone, addresses AND payment. Two things set it apart and
|
|
2123
|
+
* shape this module:
|
|
2124
|
+
*
|
|
2125
|
+
* 1. There is no html_snippet. `Payment { CreatePaymentNexi }` creates the
|
|
2126
|
+
* payment server-side (the seller's SECRET key never leaves shopcart)
|
|
2127
|
+
* and returns the paymentId plus the PUBLIC checkout key; the browser
|
|
2128
|
+
* loads Nexi's `checkout.js` and mounts `new Dibs.Checkout({…})` in a
|
|
2129
|
+
* LIGHT-DOM container — Nexi refuses a container inside a shadow root
|
|
2130
|
+
* or another iframe.
|
|
2131
|
+
* 2. Nexi has no shipping picker. The payment is created with
|
|
2132
|
+
* `merchantHandlesShippingCost`, so Nexi holds its pay button until we
|
|
2133
|
+
* price the address the shopper typed: on `address-changed` the widget
|
|
2134
|
+
* is frozen, `Payment { UpdateNexiShipping }` re-prices for that country
|
|
2135
|
+
* and pushes the SHIPPING line, and the widget is thawed.
|
|
2136
|
+
*
|
|
2137
|
+
* Completion arrives as the `payment-completed` event — Nexi neither
|
|
2138
|
+
* redirects nor renders a receipt of its own, so the component shows Vio's
|
|
2139
|
+
* confirmation. Some methods inside Nexi (Vipps, Swish, MobilePay) leave the
|
|
2140
|
+
* page and come back to the SAME url with `?paymentId=…` appended; the
|
|
2141
|
+
* pending session is remembered in sessionStorage so the widget can be
|
|
2142
|
+
* re-mounted on that paymentId and finish.
|
|
2143
|
+
*
|
|
2144
|
+
* The Commerce order itself is created server-side by Nexi's webhook
|
|
2145
|
+
* (shopcart /checkout/payment/nexi/ok) — the browser never confirms money.
|
|
2146
|
+
*/
|
|
2147
|
+
|
|
2148
|
+
/** Normalized Nexi payment (shopcart maps the Payment API). */
|
|
2149
|
+
interface NexiOrder {
|
|
2150
|
+
/** Nexi paymentId (32 hex). */
|
|
2151
|
+
order_id: string;
|
|
2152
|
+
/** Created | Reserved | Charged | Cancelled | Terminated | Unknown. */
|
|
2153
|
+
status: string;
|
|
2154
|
+
/** Public checkout key for Dibs.Checkout. */
|
|
2155
|
+
checkout_key: string;
|
|
2156
|
+
/** checkout.js of the seller's environment (test or live). */
|
|
2157
|
+
checkout_js_url: string;
|
|
2158
|
+
purchase_country?: string;
|
|
2159
|
+
purchase_currency?: string;
|
|
2160
|
+
total_price?: number;
|
|
2161
|
+
/**
|
|
2162
|
+
* Shipping to show next to the widget: the purchase country's rates while
|
|
2163
|
+
* no address is known (`reason: AWAITING_ADDRESS`, nothing charged), or what
|
|
2164
|
+
* the payment carries once one was priced (a resumed widget does not
|
|
2165
|
+
* announce its address again).
|
|
2166
|
+
*/
|
|
2167
|
+
shipping?: NexiShippingUpdate | null;
|
|
2168
|
+
/** How it was paid ("Visa", "Vipps"…) — once Nexi has the details. */
|
|
2169
|
+
payment_method?: string | null;
|
|
2170
|
+
/** Last four digits of the card. */
|
|
2171
|
+
card_last4?: string | null;
|
|
2172
|
+
/** Where the receipt goes. */
|
|
2173
|
+
email?: string | null;
|
|
2174
|
+
}
|
|
2175
|
+
interface NexiShippingUpdate {
|
|
2176
|
+
ok: boolean;
|
|
2177
|
+
/**
|
|
2178
|
+
* When !ok: NO_SHIPPING — Vio does not ship to that country; or
|
|
2179
|
+
* AWAITING_ADDRESS — nothing charged yet, `options` are the purchase
|
|
2180
|
+
* country's rates and `shipping_id` the suggested one.
|
|
2181
|
+
*/
|
|
2182
|
+
reason?: string;
|
|
2183
|
+
order_id: string;
|
|
2184
|
+
total_price?: number;
|
|
2185
|
+
shipping_name?: string;
|
|
2186
|
+
shipping_price?: number;
|
|
2187
|
+
/** The rate on the payment now. */
|
|
2188
|
+
shipping_id?: string;
|
|
2189
|
+
/**
|
|
2190
|
+
* Every rate the shopper may pick for this address, best first. Nexi has
|
|
2191
|
+
* no shipping picker of its own, so the checkout shows these.
|
|
2192
|
+
*/
|
|
2193
|
+
options?: NexiShippingOption[];
|
|
2194
|
+
/** The address it was priced for (alpha-2 country). */
|
|
2195
|
+
country?: string;
|
|
2196
|
+
postal_code?: string;
|
|
2197
|
+
/** market — the checkout's country, priced at creation; consumer — the shopper's address. */
|
|
2198
|
+
address_source?: 'market' | 'consumer' | null;
|
|
2199
|
+
/** Whether this call changed the amount on the payment. */
|
|
2200
|
+
changed?: boolean | null;
|
|
2201
|
+
/**
|
|
2202
|
+
* Client-side only: set when the amount changed as the shopper pressed pay,
|
|
2203
|
+
* so the payment was stopped and the widget reloaded.
|
|
2204
|
+
*/
|
|
2205
|
+
repriced_at_pay?: boolean;
|
|
2206
|
+
}
|
|
2207
|
+
interface NexiShippingOption {
|
|
2208
|
+
id: string;
|
|
2209
|
+
name: string;
|
|
2210
|
+
/** Incl. VAT, decimal. */
|
|
1338
2211
|
price: number;
|
|
1339
2212
|
}
|
|
1340
2213
|
|
|
@@ -1521,8 +2394,20 @@ interface KlarnaPaymentsHandle {
|
|
|
1521
2394
|
/** Tear down the mounted widget. */
|
|
1522
2395
|
unmount(): void;
|
|
1523
2396
|
}
|
|
2397
|
+
/**
|
|
2398
|
+
* What the facade lends the manager. `orderAttribution` answers the
|
|
2399
|
+
* attribution of the order about to be created for a sponsor's cart
|
|
2400
|
+
* (`Vio.orderAttribution`, ADR-0035 phase B) — the surface, the page's
|
|
2401
|
+
* campaign, the page and the entry; sent as `attribution` on `CreateCheckout`
|
|
2402
|
+
* and on the `UpdateCheckout` before paying. Optional: without it (a manager
|
|
2403
|
+
* built apart from the facade) nothing is sent and nothing changes.
|
|
2404
|
+
*/
|
|
2405
|
+
interface CheckoutManagerDeps {
|
|
2406
|
+
orderAttribution?: (sponsorId: number) => Promise<CheckoutAttributionWire | undefined> | CheckoutAttributionWire | undefined;
|
|
2407
|
+
}
|
|
1524
2408
|
declare class CheckoutManager extends EventTarget {
|
|
1525
2409
|
private readonly cartManager;
|
|
2410
|
+
private readonly deps;
|
|
1526
2411
|
private state;
|
|
1527
2412
|
/** Counts `open()` calls — see CheckoutState.session. */
|
|
1528
2413
|
private sessionSeq;
|
|
@@ -1560,12 +2445,18 @@ declare class CheckoutManager extends EventTarget {
|
|
|
1560
2445
|
/** Per-sponsor payment methods cache + in-flight dedupe. */
|
|
1561
2446
|
private paymentMethodsCache;
|
|
1562
2447
|
private paymentMethodsPromises;
|
|
1563
|
-
constructor(cartManager: CartManager);
|
|
2448
|
+
constructor(cartManager: CartManager, deps?: CheckoutManagerDeps);
|
|
1564
2449
|
open(sponsorId: number): CheckoutState;
|
|
1565
2450
|
close(): void;
|
|
1566
|
-
/**
|
|
2451
|
+
/**
|
|
2452
|
+
* The attribution of the order this sponsor's cart is about to become
|
|
2453
|
+
* (ADR-0035 phase B), through the facade; `undefined` when there is none
|
|
2454
|
+
* to give or it fails — attribution never costs a checkout.
|
|
2455
|
+
*/
|
|
2456
|
+
private attributionFor;
|
|
2457
|
+
/** Create the backend checkout for the sponsor's cart (auto-accepts terms); born attributed when the facade knows the attribution. */
|
|
1567
2458
|
createCheckout(sponsorId: number): Promise<any>;
|
|
1568
|
-
/** Update the backend checkout (terms are re-asserted unless overridden). */
|
|
2459
|
+
/** Update the backend checkout (terms are re-asserted unless overridden; the attribution rides along unless the caller gives its own). */
|
|
1569
2460
|
updateCheckout(variables: Record<string, unknown>, sponsorId?: number): Promise<any>;
|
|
1570
2461
|
getCheckout(checkoutId: string, sponsorId?: number): Promise<any>;
|
|
1571
2462
|
/**
|
|
@@ -1574,6 +2465,15 @@ declare class CheckoutManager extends EventTarget {
|
|
|
1574
2465
|
* receipt, and a receipt does not fail for it.
|
|
1575
2466
|
*/
|
|
1576
2467
|
getOrderNumber(checkoutId: string, sponsorId?: number): Promise<number | null>;
|
|
2468
|
+
/**
|
|
2469
|
+
* What a paid checkout says of itself: the order number (as above) and the
|
|
2470
|
+
* buyer reference — shopcart's keyed hash of the buyer's email, what the
|
|
2471
|
+
* `vio:payment-success` detail carries as `buyerRef` and analytics sends as
|
|
2472
|
+
* `buyer_id`. Never throws; `null` for whatever the API does not say.
|
|
2473
|
+
*/
|
|
2474
|
+
getOrderReference(checkoutId: string, sponsorId?: number): Promise<CheckoutReference>;
|
|
2475
|
+
/** In-flight `getOrderReference` per checkout id (see there). */
|
|
2476
|
+
private referenceInFlight;
|
|
1577
2477
|
/**
|
|
1578
2478
|
* Payment methods enabled for the sponsor (backend-configured). Memoised per
|
|
1579
2479
|
* sponsor with in-flight dedupe — several UI components ask on every open.
|
|
@@ -1805,523 +2705,150 @@ declare class CheckoutManager extends EventTarget {
|
|
|
1805
2705
|
* and the caller then reads the checkout to see it land.
|
|
1806
2706
|
*/
|
|
1807
2707
|
mountStripeCheckout(container: HTMLElement, sponsorId: number | undefined, formData: unknown, callbacks?: {
|
|
1808
|
-
onReady?: () => void;
|
|
1809
|
-
onLoadError?: (message: string) => void;
|
|
1810
|
-
}): Promise<{
|
|
1811
|
-
handle: StripeElementHandle;
|
|
1812
|
-
intent: StripeIntent;
|
|
1813
|
-
checkoutId: string;
|
|
1814
|
-
}>;
|
|
1815
|
-
/** Unmount the Payment Element. Safe when nothing is mounted. */
|
|
1816
|
-
destroyStripe(): void;
|
|
1817
|
-
/**
|
|
1818
|
-
* The Stripe publishable key for a sponsor, taken from its own commerce
|
|
1819
|
-
* channel (`GetAvailablePaymentMethods` → Stripe → config.publishableKey).
|
|
1820
|
-
*
|
|
1821
|
-
* The channel is the right source: the key belongs to the brand's Stripe
|
|
1822
|
-
* account, so two brands on one page each get theirs, and a host never has
|
|
1823
|
-
* to configure it. `Vio.init({ stripePublishableKey })` still wins when set,
|
|
1824
|
-
* which keeps existing integrations working and allows an override.
|
|
1825
|
-
*/
|
|
1826
|
-
private resolveStripePublishableKey;
|
|
1827
|
-
/**
|
|
1828
|
-
* Returns true if Apple Pay can be shown on this device + Stripe config.
|
|
1829
|
-
* Result is memoised — call `clearApplePayCache()` if config changes.
|
|
1830
|
-
*/
|
|
1831
|
-
isApplePayAvailable(country?: string): Promise<boolean>;
|
|
1832
|
-
clearApplePayCache(): void;
|
|
1833
|
-
/**
|
|
1834
|
-
* Prepare Apple Pay for the product-page express button (no active checkout
|
|
1835
|
-
* needed). Pre-creates the Stripe PaymentRequest + resolves canMakePayment so
|
|
1836
|
-
* the returned `show()` can fire synchronously inside the tap (Apple blocks
|
|
1837
|
-
* the sheet if `show()` is reached after an await). `show()` resolves the
|
|
1838
|
-
* sheet, then dispatches `payment-complete` (→ confirmation) or
|
|
1839
|
-
* `payment-error`. `available` is true only when Apple Pay will actually work.
|
|
1840
|
-
*/
|
|
1841
|
-
prepareApplePayFor(amount: number, currency: string, country?: string): Promise<{
|
|
1842
|
-
available: boolean;
|
|
1843
|
-
show: () => Promise<void>;
|
|
1844
|
-
}>;
|
|
1845
|
-
/**
|
|
1846
|
-
* Prepare an Apple Pay express charge for an arbitrary amount (e.g. the whole
|
|
1847
|
-
* cart) with NO active checkout. Unlike `prepareApplePayFor`, the returned
|
|
1848
|
-
* `show()` RESOLVES with the result (or `null` on cancel/failure) and does
|
|
1849
|
-
* NOT dispatch the global `payment-complete` — so no checkout overlay appears.
|
|
1850
|
-
* The caller (the cart drawer) renders its own confirmation. `show()` must be
|
|
1851
|
-
* called synchronously inside the tap (Apple's user-gesture rule).
|
|
1852
|
-
*/
|
|
1853
|
-
prepareApplePayExpress(amount: number, currency: string, country?: string, sponsorId?: number): Promise<{
|
|
1854
|
-
available: boolean;
|
|
1855
|
-
show: () => Promise<ApplePayResult | null>;
|
|
1856
|
-
}>;
|
|
1857
|
-
/** The charge closure run inside the Apple Pay sheet's authorize event —
|
|
1858
|
-
* shared by the checkout button and the cart's express button. Fail-closed:
|
|
1859
|
-
* any failure throws and the sheet closes with failure, nothing confirmed. */
|
|
1860
|
-
private buildApplePayAuthorize;
|
|
1861
|
-
/** Backend statuses from ConfirmPaymentApplePay that mean the charge did
|
|
1862
|
-
* NOT go through — anything here fails the sheet (fail-closed). */
|
|
1863
|
-
private static readonly APPLE_PAY_FAILED_STATUSES;
|
|
1864
|
-
/**
|
|
1865
|
-
* Launches the Apple Pay sheet and charges server-side INSIDE the sheet's
|
|
1866
|
-
* authorize event (round-5 wiring, contract from the commerce backend):
|
|
1867
|
-
* 1. ensure a backend checkout exists (create if missing)
|
|
1868
|
-
* 2. UpdateCheckout(paymentMethod: "Apple Pay" + payer email)
|
|
1869
|
-
* 3. CreatePaymentApplePay → gateway hints (pk_/acct_ stored by prefix)
|
|
1870
|
-
* 4. ConfirmPaymentApplePay(token, email, shipping) → the REAL charge;
|
|
1871
|
-
* a failed/absent confirmation throws → the sheet closes with failure
|
|
1872
|
-
* Resolves null if the user closes the sheet. On success, dispatches
|
|
1873
|
-
* `payment-complete` with the backend order id in `result.confirmation`.
|
|
1874
|
-
*/
|
|
1875
|
-
startApplePay(options?: {
|
|
1876
|
-
country?: string;
|
|
1877
|
-
label?: string;
|
|
1878
|
-
sponsorId?: number;
|
|
1879
|
-
}): Promise<ApplePayResult | null>;
|
|
1880
|
-
/**
|
|
1881
|
-
* True if the Klarna Express button can be offered (clientId configured +
|
|
1882
|
-
* SDK loads). Memoised per active checkout. Never throws.
|
|
1883
|
-
*/
|
|
1884
|
-
isKlarnaExpressAvailable(): Promise<boolean>;
|
|
1885
|
-
clearKlarnaCache(): void;
|
|
1886
|
-
/**
|
|
1887
|
-
* Build the Klarna payment request from the active cart — amounts in the
|
|
1888
|
-
* currency's minor unit (øre/cents), one line item per cart line.
|
|
1889
|
-
*/
|
|
1890
|
-
buildKlarnaPaymentRequest(): KlarnaPaymentRequestData;
|
|
1891
|
-
/**
|
|
1892
|
-
* Mount the Klarna Express button into `container`. On a successful
|
|
1893
|
-
* authorization, fires `payment-complete` with the authorization token —
|
|
1894
|
-
* the host (or vio-backend) then creates the Klarna order server-side.
|
|
1895
|
-
*
|
|
1896
|
-
* Returns the button handle so the UI can unmount on teardown.
|
|
1897
|
-
*/
|
|
1898
|
-
mountKlarnaExpress(container: HTMLElement): Promise<KlarnaButtonHandle>;
|
|
1899
|
-
/**
|
|
1900
|
-
* Klarna Payments — classic widget flow (server client_token). Creates a
|
|
1901
|
-
* session on vio-backend, then mounts Klarna's inline widget into
|
|
1902
|
-
* `container`. Returns a handle to switch category and to authorize → which
|
|
1903
|
-
* on approval creates the order via the same backend /orders route as KEC.
|
|
1904
|
-
*
|
|
1905
|
-
* Unlike `mountKlarnaExpress`, this needs no public `klarnaClientId` and no
|
|
1906
|
-
* origin handshake — auth is the server-side API key.
|
|
1907
|
-
*/
|
|
1908
|
-
mountKlarnaPayments(container: HTMLElement, opts?: {
|
|
1909
|
-
withShipping?: boolean;
|
|
1910
|
-
shippingId?: string;
|
|
1911
|
-
category?: string;
|
|
1912
|
-
}): Promise<KlarnaPaymentsHandle>;
|
|
1913
|
-
/** True if the Klarna Payments widget lib can load (UI gate). */
|
|
1914
|
-
klarnaPaymentsAvailable(): Promise<boolean>;
|
|
1915
|
-
/** Cart snapshot + chosen shipping line/amount, for express purchases. */
|
|
1916
|
-
private buildKlarnaInstantContext;
|
|
1917
|
-
/**
|
|
1918
|
-
* Express instant purchase — go straight to Klarna's own modal, no checkout
|
|
1919
|
-
* overlay. Creates a session (with shipping options), loads the widget into a
|
|
1920
|
-
* hidden container, then authorizes (which opens Klarna's confirm modal). On
|
|
1921
|
-
* approval creates the order → `payment-complete` (host shows confirmation);
|
|
1922
|
-
* on failure → `payment-error`. Call `open(sponsorId)` first.
|
|
1923
|
-
*/
|
|
1924
|
-
startKlarnaInstant(): Promise<void>;
|
|
1925
|
-
/**
|
|
1926
|
-
* REDIRECT path: call once on app load. If a Klarna purchase was launched
|
|
1927
|
-
* (pending context persisted) and we're back with a token — from the URL or
|
|
1928
|
-
* the SDK's resumed `complete` event — finish creating the order + confirm.
|
|
1929
|
-
*/
|
|
1930
|
-
resumeKlarnaReturn(): Promise<void>;
|
|
1931
|
-
/** Snapshot of the active cart for redirect recovery (minor units). */
|
|
1932
|
-
private buildKlarnaPendingContext;
|
|
1933
|
-
/**
|
|
1934
|
-
* POST the token + order lines to vio-backend (it holds the secret API key
|
|
1935
|
-
* and creates the real Klarna order). On success → `payment-complete`; on
|
|
1936
|
-
* failure → `payment-error`. Idempotent: clears the pending key so the
|
|
1937
|
-
* popup and redirect paths can't double-fire.
|
|
1938
|
-
*/
|
|
1939
|
-
private completeKlarnaOrder;
|
|
1940
|
-
get currentState(): CheckoutState | null;
|
|
1941
|
-
get items(): CartLineItem[];
|
|
2708
|
+
onReady?: () => void;
|
|
2709
|
+
onLoadError?: (message: string) => void;
|
|
2710
|
+
}): Promise<{
|
|
2711
|
+
handle: StripeElementHandle;
|
|
2712
|
+
intent: StripeIntent;
|
|
2713
|
+
checkoutId: string;
|
|
2714
|
+
}>;
|
|
2715
|
+
/** Unmount the Payment Element. Safe when nothing is mounted. */
|
|
2716
|
+
destroyStripe(): void;
|
|
1942
2717
|
/**
|
|
1943
|
-
*
|
|
1944
|
-
*
|
|
1945
|
-
*
|
|
2718
|
+
* The Stripe publishable key for a sponsor, taken from its own commerce
|
|
2719
|
+
* channel (`GetAvailablePaymentMethods` → Stripe → config.publishableKey).
|
|
2720
|
+
*
|
|
2721
|
+
* The channel is the right source: the key belongs to the brand's Stripe
|
|
2722
|
+
* account, so two brands on one page each get theirs, and a host never has
|
|
2723
|
+
* to configure it. `Vio.init({ stripePublishableKey })` still wins when set,
|
|
2724
|
+
* which keeps existing integrations working and allows an override.
|
|
1946
2725
|
*/
|
|
1947
|
-
private
|
|
1948
|
-
/** The sponsor's connected account, read fresh from its channel config. */
|
|
1949
|
-
private resolveStripeConnectAccount;
|
|
1950
|
-
private emit;
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
|
-
/**
|
|
1954
|
-
* Slots — the pure half of ADR-0027 / ADR-0034 on the web.
|
|
1955
|
-
*
|
|
1956
|
-
* A slot is a NAME for a place on a page. The page declares its slots to the
|
|
1957
|
-
* campaigns service (`Vio.declareSlots()` / `Vio.registerSlot()` in client.ts),
|
|
1958
|
-
* the dashboard assigns a campaign to each one, optionally with a date window,
|
|
1959
|
-
* and `GET /v2/mobile/config` answers with `campaigns[].slots[]` — only the
|
|
1960
|
-
* assignments whose window is open NOW. Whatever no slot names shows the
|
|
1961
|
-
* surface's default campaign (`campaign`).
|
|
1962
|
-
*
|
|
1963
|
-
* Everything here is side-effect free and never throws on a malformed
|
|
1964
|
-
* bootstrap: a broken `campaigns[]` must never blank a product block or break
|
|
1965
|
-
* `track()`.
|
|
1966
|
-
*/
|
|
1967
|
-
|
|
1968
|
-
/** What `Vio.declareSlots()` accepts per slot. */
|
|
1969
|
-
type SlotInput = string | {
|
|
1970
|
-
id: string;
|
|
1971
|
-
displayName?: string;
|
|
1972
|
-
campaignId?: number;
|
|
1973
|
-
};
|
|
1974
|
-
type BootLike = Pick<BootstrapResponse, 'campaign' | 'campaigns' | 'primarySponsor' | 'secondarySponsors'>;
|
|
1975
|
-
/**
|
|
1976
|
-
* The campaign a slot shows right now. Among the `status === 'active'`
|
|
1977
|
-
* entries of `campaigns[]`, the one with an assignment named `slot` for this
|
|
1978
|
-
* platform (`platform` null on the assignment, or equal to `platform`) whose
|
|
1979
|
-
* window contains `now` (`startDate <= now < endDate`, null = open). When
|
|
1980
|
-
* several qualify, the surface's default campaign wins, else the first the
|
|
1981
|
-
* backend lists.
|
|
1982
|
-
*
|
|
1983
|
-
* No assignment → the PAGE's campaign (`pageCampaignId`: the element's own
|
|
1984
|
-
* `vio-campaign`, an ancestor's `data-vio-campaign`, or `Vio.init({ campaignId })`)
|
|
1985
|
-
* when `campaigns[]` lists it as active — an editorial page resolves to its
|
|
1986
|
-
* campaign before (and regardless of) the manifest round-trip. Else the
|
|
1987
|
-
* default campaign: the `campaigns[]` entry whose id is `campaign.id`, or a
|
|
1988
|
-
* minimal entry built from `campaign` (+ the top-level sponsors) when the
|
|
1989
|
-
* list does not carry it. No bootstrap → null.
|
|
1990
|
-
*/
|
|
1991
|
-
declare function resolveSlotCampaign(boot: BootLike | null | undefined, slot: string | null | undefined, now?: number, platform?: string | null, pageCampaignId?: CampaignHint, sponsorId?: number | null): BootstrapCampaignEntry | null;
|
|
1992
|
-
/**
|
|
1993
|
-
* The sponsor rule: the active campaign of `campaigns[]` the sponsor takes
|
|
1994
|
-
* part in, as its primary or one of its secondaries — when it is in several,
|
|
1995
|
-
* the surface's default campaign if it is one of them, else the first one
|
|
1996
|
-
* the backend lists. Null when none (or on a malformed list).
|
|
1997
|
-
*/
|
|
1998
|
-
declare function sponsorCampaignEntry(boot: BootLike | null | undefined, sponsorId: number | null | undefined): BootstrapCampaignEntry | null;
|
|
1999
|
-
/**
|
|
2000
|
-
* A page campaign as the callers give it: one id, or the candidates in
|
|
2001
|
-
* precedence order (the element's `vio-campaign`, an ancestor's
|
|
2002
|
-
* `data-vio-campaign`, `Vio.init`'s). An unusable level (invalid, paused,
|
|
2003
|
-
* unknown) falls through to the next one; `0`, `null`, `''` mean unset.
|
|
2004
|
-
*/
|
|
2005
|
-
type CampaignHint = number | string | null | undefined | ReadonlyArray<number | string | null | undefined>;
|
|
2006
|
-
/**
|
|
2007
|
-
* A campaign id as the SDK accepts it: a positive safe integer, given as a
|
|
2008
|
-
* number or as a string of decimal digits (an attribute). Anything else —
|
|
2009
|
-
* `true`, `'0x10'`, `'1e3'`, an array, a float — is "absent".
|
|
2010
|
-
*/
|
|
2011
|
-
declare function toCampaignId(value: unknown): number | undefined;
|
|
2012
|
-
/** The usable ids of a hint, in order, without duplicates. */
|
|
2013
|
-
declare function campaignCandidates(hint: CampaignHint): number[];
|
|
2014
|
-
/**
|
|
2015
|
-
* The first candidate of `hint` that `campaigns[]` lists as ACTIVE (and, when
|
|
2016
|
-
* `sponsorId` is given, that the sponsor takes part in — primary or
|
|
2017
|
-
* secondary); null when none — a paused, ended or unknown page campaign is
|
|
2018
|
-
* ignored and the resolution moves on.
|
|
2019
|
-
*/
|
|
2020
|
-
declare function activeCampaignEntry(boot: BootLike | null | undefined, hint: CampaignHint, sponsorId?: number): BootstrapCampaignEntry | null;
|
|
2021
|
-
/** The kinds of Vio element that register themselves. */
|
|
2022
|
-
type SlotKind = 'card' | 'carousel' | 'detail';
|
|
2023
|
-
/**
|
|
2024
|
-
* The id an element gets when the host set no `vio-slot`:
|
|
2025
|
-
* `${scope ? scope + '-' : ''}${kind}-${ordinal + 1}` (`carousel-1`, `card-3`,
|
|
2026
|
-
* `article-123-carousel-1`), `ordinal` being the element's index among the
|
|
2027
|
-
* same-kind Vio elements WITH THE SAME SCOPE, in document order at connect
|
|
2028
|
-
* time. The scope is inherited from the DOM (`vio-scope` on the element, else
|
|
2029
|
-
* the nearest `data-vio-scope` ancestor): a Vev page or a Replit article
|
|
2030
|
-
* (`<body data-vio-scope="article-123">`) gets per-page slots with one line
|
|
2031
|
-
* and no per-element naming; a template that wants slots shared across
|
|
2032
|
-
* articles simply sets no scope. On purpose there is NO page path in the id:
|
|
2033
|
-
* the article goes to analytics as `content_id`, not into the slot. Stable
|
|
2034
|
-
* across reloads while the layout is; a layout change leaves a stale entry,
|
|
2035
|
-
* which ADR-0034 accepts.
|
|
2036
|
-
*/
|
|
2037
|
-
declare function autoSlotId(kind: SlotKind, ordinal: number, scope?: string | null): string;
|
|
2038
|
-
/** `"Carousel 1"`, `"Card 3"` — with ` · ${scopeName}` when the scope has a human label. */
|
|
2039
|
-
declare function autoSlotDisplayName(kind: SlotKind, ordinal: number, scopeName?: string | null): string;
|
|
2040
|
-
/** A scope value fit for an id: trimmed, inner whitespace → `-`. */
|
|
2041
|
-
declare function normalizeScope(scope: string | null | undefined): string;
|
|
2042
|
-
|
|
2043
|
-
/**
|
|
2044
|
-
* Vio.analytics — the web SDK's half of the Vio Analytics pipeline.
|
|
2045
|
-
*
|
|
2046
|
-
* Events flow to the Vio collector (`POST <eventsBase>/v1/events`, repo
|
|
2047
|
-
* vio-live/vio-analytics) which owns raw storage (ClickHouse) and vendor
|
|
2048
|
-
* fan-out (Mixpanel today). THE SDK NEVER TALKS TO VENDORS — swapping or
|
|
2049
|
-
* dropping a vendor is a server-side change, zero client releases.
|
|
2050
|
-
* Wire contract: vio-analytics `docs/EVENTS_CONTRACT.md` (v1, snake_case).
|
|
2051
|
-
*
|
|
2052
|
-
* Design rules:
|
|
2053
|
-
* - SIDE-EFFECT-FREE MODULE. Nothing runs at import time (tsup/tree-shaking
|
|
2054
|
-
* contract, see lessons/web-sdk-tsup-singleton-and-build). Listeners are
|
|
2055
|
-
* installed by an explicit `Vio.analytics.start()`.
|
|
2056
|
-
* - `track()` works BEFORE `Vio.init()` — events queue and flush once the
|
|
2057
|
-
* SDK is configured (transport resolves at flush time, not at track time).
|
|
2058
|
-
* - SSR-safe: without `window` every call is a silent no-op.
|
|
2059
|
-
* - Retries are safe: `event_id` is stable per event, the collector
|
|
2060
|
-
* dedupes. Queue is bounded (drop-oldest) so a dead collector can never
|
|
2061
|
-
* grow memory unbounded.
|
|
2062
|
-
* - Anti-double-count: the SDK only reports what the server can't see.
|
|
2063
|
-
* Votes/participations are server truth; `ad_activation`/`cart_intent`
|
|
2064
|
-
* are mirrored server-side, never from here.
|
|
2065
|
-
*
|
|
2066
|
-
* Three sinks, matching the Vev precedent (vio-vev analytics.ts, which
|
|
2067
|
-
* becomes an adapter over this in F3):
|
|
2068
|
-
* 1. collector (default ON once started)
|
|
2069
|
-
* 2. window.dataLayer — GA4/GTM (opt-in `start({ dataLayer: true })`,
|
|
2070
|
-
* the publisher-facing feature; NOT part of the Vio pipeline)
|
|
2071
|
-
* 3. `vio:analytics` DOM event — always when started (inspector/bridges)
|
|
2072
|
-
*/
|
|
2073
|
-
|
|
2074
|
-
declare const ANALYTICS_EVENT_NAMES: readonly ["view_item_list", "select_item", "view_item", "add_to_cart", "remove_from_cart", "view_cart", "begin_checkout", "purchase", "component_impression", "component_click", "ad_impression", "ad_click", "poll_impression", "contest_impression", "session_start", "session_end", "checkout_error", "sdk_error"];
|
|
2075
|
-
type AnalyticsEventName = (typeof ANALYTICS_EVENT_NAMES)[number];
|
|
2076
|
-
/** Camel-case for DX; mapped to the snake_case wire format at build time. */
|
|
2077
|
-
interface AnalyticsContext {
|
|
2078
|
-
campaignId?: number;
|
|
2079
|
-
broadcastId?: string;
|
|
2080
|
-
campaignComponentId?: number;
|
|
2081
|
-
appPlacementId?: number;
|
|
2082
|
-
locationId?: string;
|
|
2083
|
-
componentTemplateId?: string;
|
|
2084
|
-
sponsorId?: number;
|
|
2085
|
-
activationId?: number;
|
|
2086
|
-
contentUrl?: string;
|
|
2726
|
+
private resolveStripePublishableKey;
|
|
2087
2727
|
/**
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2090
|
-
* host can join Vio's funnel back onto its own per-article reporting
|
|
2091
|
-
* (revenue stops being an estimate). Left alone by the SDK.
|
|
2728
|
+
* Returns true if Apple Pay can be shown on this device + Stripe config.
|
|
2729
|
+
* Result is memoised — call `clearApplePayCache()` if config changes.
|
|
2092
2730
|
*/
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
contentTitle?: string;
|
|
2096
|
-
/** Código corto del fallo (`sdk_error` / `checkout_error`). */
|
|
2097
|
-
errorCode?: string;
|
|
2098
|
-
variant?: string;
|
|
2731
|
+
isApplePayAvailable(country?: string): Promise<boolean>;
|
|
2732
|
+
clearApplePayCache(): void;
|
|
2099
2733
|
/**
|
|
2100
|
-
*
|
|
2101
|
-
*
|
|
2102
|
-
*
|
|
2103
|
-
*
|
|
2104
|
-
*
|
|
2734
|
+
* Prepare Apple Pay for the product-page express button (no active checkout
|
|
2735
|
+
* needed). Pre-creates the Stripe PaymentRequest + resolves canMakePayment so
|
|
2736
|
+
* the returned `show()` can fire synchronously inside the tap (Apple blocks
|
|
2737
|
+
* the sheet if `show()` is reached after an await). `show()` resolves the
|
|
2738
|
+
* sheet, then dispatches `payment-complete` (→ confirmation) or
|
|
2739
|
+
* `payment-error`. `available` is true only when Apple Pay will actually work.
|
|
2105
2740
|
*/
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
name?: string;
|
|
2111
|
-
brand?: string;
|
|
2112
|
-
variantId?: number | string;
|
|
2113
|
-
price?: number;
|
|
2114
|
-
quantity?: number;
|
|
2115
|
-
}
|
|
2116
|
-
interface AnalyticsCommerce {
|
|
2117
|
-
items?: AnalyticsItemInput[];
|
|
2118
|
-
value?: number;
|
|
2119
|
-
currency?: string;
|
|
2120
|
-
orderId?: string;
|
|
2121
|
-
paymentMethod?: string;
|
|
2122
|
-
}
|
|
2123
|
-
interface TrackOptions {
|
|
2124
|
-
context?: AnalyticsContext;
|
|
2125
|
-
commerce?: AnalyticsCommerce;
|
|
2126
|
-
props?: Record<string, unknown>;
|
|
2127
|
-
}
|
|
2128
|
-
interface AnalyticsStartOptions {
|
|
2129
|
-
/** Where the SDK is embedded: 'vev' | 'replit' | 'custom' | … Default 'custom'. */
|
|
2130
|
-
host?: string;
|
|
2741
|
+
prepareApplePayFor(amount: number, currency: string, country?: string): Promise<{
|
|
2742
|
+
available: boolean;
|
|
2743
|
+
show: () => Promise<void>;
|
|
2744
|
+
}>;
|
|
2131
2745
|
/**
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2134
|
-
*
|
|
2135
|
-
*
|
|
2746
|
+
* Prepare an Apple Pay express charge for an arbitrary amount (e.g. the whole
|
|
2747
|
+
* cart) with NO active checkout. Unlike `prepareApplePayFor`, the returned
|
|
2748
|
+
* `show()` RESOLVES with the result (or `null` on cancel/failure) and does
|
|
2749
|
+
* NOT dispatch the global `payment-complete` — so no checkout overlay appears.
|
|
2750
|
+
* The caller (the cart drawer) renders its own confirmation. `show()` must be
|
|
2751
|
+
* called synchronously inside the tap (Apple's user-gesture rule).
|
|
2136
2752
|
*/
|
|
2137
|
-
|
|
2753
|
+
prepareApplePayExpress(amount: number, currency: string, country?: string, sponsorId?: number): Promise<{
|
|
2754
|
+
available: boolean;
|
|
2755
|
+
show: () => Promise<ApplePayResult | null>;
|
|
2756
|
+
}>;
|
|
2757
|
+
/** The charge closure run inside the Apple Pay sheet's authorize event —
|
|
2758
|
+
* shared by the checkout button and the cart's express button. Fail-closed:
|
|
2759
|
+
* any failure throws and the sheet closes with failure, nothing confirmed. */
|
|
2760
|
+
private buildApplePayAuthorize;
|
|
2761
|
+
/** Backend statuses from ConfirmPaymentApplePay that mean the charge did
|
|
2762
|
+
* NOT go through — anything here fails the sheet (fail-closed). */
|
|
2763
|
+
private static readonly APPLE_PAY_FAILED_STATUSES;
|
|
2138
2764
|
/**
|
|
2139
|
-
*
|
|
2140
|
-
*
|
|
2141
|
-
*
|
|
2142
|
-
*
|
|
2143
|
-
*
|
|
2144
|
-
*
|
|
2765
|
+
* Launches the Apple Pay sheet and charges server-side INSIDE the sheet's
|
|
2766
|
+
* authorize event (round-5 wiring, contract from the commerce backend):
|
|
2767
|
+
* 1. ensure a backend checkout exists (create if missing)
|
|
2768
|
+
* 2. UpdateCheckout(paymentMethod: "Apple Pay" + payer email)
|
|
2769
|
+
* 3. CreatePaymentApplePay → gateway hints (pk_/acct_ stored by prefix)
|
|
2770
|
+
* 4. ConfirmPaymentApplePay(token, email, shipping) → the REAL charge;
|
|
2771
|
+
* a failed/absent confirmation throws → the sheet closes with failure
|
|
2772
|
+
* Resolves null if the user closes the sheet. On success, dispatches
|
|
2773
|
+
* `payment-complete` with the backend order id in `result.confirmation`.
|
|
2145
2774
|
*/
|
|
2146
|
-
|
|
2775
|
+
startApplePay(options?: {
|
|
2776
|
+
country?: string;
|
|
2777
|
+
label?: string;
|
|
2778
|
+
sponsorId?: number;
|
|
2779
|
+
}): Promise<ApplePayResult | null>;
|
|
2147
2780
|
/**
|
|
2148
|
-
*
|
|
2149
|
-
*
|
|
2150
|
-
* purchases to land in the SAME session, or the two datasets cannot be
|
|
2151
|
-
* joined. Pass the id the host already stores; omit it and the SDK keeps
|
|
2152
|
-
* its own rotating session.
|
|
2781
|
+
* True if the Klarna Express button can be offered (clientId configured +
|
|
2782
|
+
* SDK loads). Memoised per active checkout. Never throws.
|
|
2153
2783
|
*/
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
collector?: boolean;
|
|
2157
|
-
/** Also push GA4 e-commerce events to window.dataLayer (publisher feature). */
|
|
2158
|
-
dataLayer?: boolean;
|
|
2159
|
-
/** console.debug every event. */
|
|
2160
|
-
debug?: boolean;
|
|
2161
|
-
}
|
|
2162
|
-
declare class AnalyticsManager extends EventTarget {
|
|
2163
|
-
private started;
|
|
2164
|
-
private options;
|
|
2165
|
-
private queue;
|
|
2166
|
-
private flushTimer;
|
|
2167
|
-
private retryAttempt;
|
|
2168
|
-
private retryNotBefore;
|
|
2169
|
-
private externalUserId;
|
|
2170
|
-
private sessionId;
|
|
2171
|
-
private requireConsent;
|
|
2172
|
-
private consentGranted;
|
|
2173
|
-
private anonIdCache;
|
|
2174
|
-
/** Set via start({ sessionId }) — the host owns the session, we follow. */
|
|
2175
|
-
private externalSessionId;
|
|
2176
|
-
private sessionStartedAt;
|
|
2177
|
-
/** Impression once-per-(session, component) guard; reset on session rotation. */
|
|
2178
|
-
private impressedComponents;
|
|
2179
|
-
/** Last NON-EMPTY cart snapshot — `purchase` uses it because several flows
|
|
2180
|
-
* (Apple Pay) clear the cart BEFORE `vio:payment-success` fires. */
|
|
2181
|
-
private lastCartSnapshot;
|
|
2182
|
-
private teardown;
|
|
2784
|
+
isKlarnaExpressAvailable(): Promise<boolean>;
|
|
2785
|
+
clearKlarnaCache(): void;
|
|
2183
2786
|
/**
|
|
2184
|
-
*
|
|
2185
|
-
*
|
|
2787
|
+
* Build the Klarna payment request from the active cart — amounts in the
|
|
2788
|
+
* currency's minor unit (øre/cents), one line item per cart line.
|
|
2186
2789
|
*/
|
|
2790
|
+
buildKlarnaPaymentRequest(): KlarnaPaymentRequestData;
|
|
2187
2791
|
/**
|
|
2188
|
-
*
|
|
2189
|
-
*
|
|
2190
|
-
*
|
|
2191
|
-
*
|
|
2192
|
-
*
|
|
2792
|
+
* Mount the Klarna Express button into `container`. On a successful
|
|
2793
|
+
* authorization, fires `payment-complete` with the authorization token —
|
|
2794
|
+
* the host (or vio-backend) then creates the Klarna order server-side.
|
|
2795
|
+
*
|
|
2796
|
+
* Returns the button handle so the UI can unmount on teardown.
|
|
2193
2797
|
*/
|
|
2194
|
-
|
|
2195
|
-
/** ¿Podemos escribir en el dispositivo? */
|
|
2196
|
-
private get canPersist();
|
|
2197
|
-
start(options?: AnalyticsStartOptions): void;
|
|
2198
|
-
/** Stop timers + listeners (tests / SPA unmount). Queue survives. */
|
|
2199
|
-
stop(): void;
|
|
2200
|
-
/** Attach the partner's user id (opaque) to all subsequent events. */
|
|
2201
|
-
identify(externalUserId: string | null): void;
|
|
2202
|
-
/** Queue one event. Works pre-init and pre-start (SSR: no-op). */
|
|
2203
|
-
track(name: AnalyticsEventName, opts?: TrackOptions): void;
|
|
2798
|
+
mountKlarnaExpress(container: HTMLElement): Promise<KlarnaButtonHandle>;
|
|
2204
2799
|
/**
|
|
2205
|
-
*
|
|
2206
|
-
*
|
|
2207
|
-
*
|
|
2208
|
-
*
|
|
2800
|
+
* Klarna Payments — classic widget flow (server client_token). Creates a
|
|
2801
|
+
* session on vio-backend, then mounts Klarna's inline widget into
|
|
2802
|
+
* `container`. Returns a handle to switch category and to authorize → which
|
|
2803
|
+
* on approval creates the order via the same backend /orders route as KEC.
|
|
2804
|
+
*
|
|
2805
|
+
* Unlike `mountKlarnaExpress`, this needs no public `klarnaClientId` and no
|
|
2806
|
+
* origin handshake — auth is the server-side API key.
|
|
2209
2807
|
*/
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
/** Force a flush (mostly for tests). */
|
|
2220
|
-
flush(): Promise<void>;
|
|
2221
|
-
private buildEvent;
|
|
2222
|
-
/** Guarda la sesión solo si podemos escribir en el dispositivo. */
|
|
2223
|
-
private persistSession;
|
|
2224
|
-
private anonId;
|
|
2225
|
-
/** Rolling session: renewed by activity, rotated after 30 min idle. */
|
|
2226
|
-
private ensureSession;
|
|
2227
|
-
private trackSessionEnd;
|
|
2228
|
-
private flushWithBeacon;
|
|
2808
|
+
mountKlarnaPayments(container: HTMLElement, opts?: {
|
|
2809
|
+
withShipping?: boolean;
|
|
2810
|
+
shippingId?: string;
|
|
2811
|
+
category?: string;
|
|
2812
|
+
}): Promise<KlarnaPaymentsHandle>;
|
|
2813
|
+
/** True if the Klarna Payments widget lib can load (UI gate). */
|
|
2814
|
+
klarnaPaymentsAvailable(): Promise<boolean>;
|
|
2815
|
+
/** Cart snapshot + chosen shipping line/amount, for express purchases. */
|
|
2816
|
+
private buildKlarnaInstantContext;
|
|
2229
2817
|
/**
|
|
2230
|
-
*
|
|
2231
|
-
*
|
|
2818
|
+
* Express instant purchase — go straight to Klarna's own modal, no checkout
|
|
2819
|
+
* overlay. Creates a session (with shipping options), loads the widget into a
|
|
2820
|
+
* hidden container, then authorizes (which opens Klarna's confirm modal). On
|
|
2821
|
+
* approval creates the order → `payment-complete` (host shows confirmation);
|
|
2822
|
+
* on failure → `payment-error`. Call `open(sponsorId)` first.
|
|
2232
2823
|
*/
|
|
2233
|
-
|
|
2234
|
-
/** The lines of the cart (current, else the pre-clear snapshot), optionally one sponsor's. */
|
|
2235
|
-
private cartLines;
|
|
2824
|
+
startKlarnaInstant(): Promise<void>;
|
|
2236
2825
|
/**
|
|
2237
|
-
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2826
|
+
* REDIRECT path: call once on app load. If a Klarna purchase was launched
|
|
2827
|
+
* (pending context persisted) and we're back with a token — from the URL or
|
|
2828
|
+
* the SDK's resumed `complete` event — finish creating the order + confirm.
|
|
2240
2829
|
*/
|
|
2241
|
-
|
|
2830
|
+
resumeKlarnaReturn(): Promise<void>;
|
|
2831
|
+
/** Snapshot of the active cart for redirect recovery (minor units). */
|
|
2832
|
+
private buildKlarnaPendingContext;
|
|
2242
2833
|
/**
|
|
2243
|
-
*
|
|
2244
|
-
*
|
|
2245
|
-
*
|
|
2834
|
+
* POST the token + order lines to vio-backend (it holds the secret API key
|
|
2835
|
+
* and creates the real Klarna order). On success → `payment-complete`; on
|
|
2836
|
+
* failure → `payment-error`. Idempotent: clears the pending key so the
|
|
2837
|
+
* popup and redirect paths can't double-fire.
|
|
2246
2838
|
*/
|
|
2247
|
-
private
|
|
2839
|
+
private completeKlarnaOrder;
|
|
2840
|
+
get currentState(): CheckoutState | null;
|
|
2841
|
+
get items(): CartLineItem[];
|
|
2248
2842
|
/**
|
|
2249
|
-
*
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2843
|
+
* Resolve the Stripe Connect account for the active sponsor — for now
|
|
2844
|
+
* pulled from bootstrap cache if present. Returns undefined if not set
|
|
2845
|
+
* (Stripe will route to the platform account in that case).
|
|
2252
2846
|
*/
|
|
2253
|
-
private
|
|
2254
|
-
/**
|
|
2255
|
-
private
|
|
2256
|
-
private
|
|
2257
|
-
}
|
|
2258
|
-
/**
|
|
2259
|
-
* The `campaign_id` of an event. In order: the context's explicit id; the
|
|
2260
|
-
* campaign assigned to the context's `slot` right now (ADR-0027 — only an
|
|
2261
|
-
* open assignment for the init platform counts, see `findSlotAssignment`);
|
|
2262
|
-
* the PAGE's campaign (`opts.pageCampaignId`, else `Vio.init({ campaignId })`)
|
|
2263
|
-
* when `campaigns[]` lists it as active (ADR-0034, amendment 3);
|
|
2264
|
-
* the active campaign of `campaigns[]` the event's sponsor takes part in, as
|
|
2265
|
-
* its primary or one of its secondaries — when it is in several, the
|
|
2266
|
-
* surface's default campaign if it is one of them, else the first one the
|
|
2267
|
-
* backend lists; the default campaign (`campaign.id`). `/v2/mobile/config`
|
|
2268
|
-
* has no top-level `campaignId` — reading one is why every event used to
|
|
2269
|
-
* leave with `campaign_id: 0` and the campaigns screen stayed empty.
|
|
2270
|
-
*
|
|
2271
|
-
* A malformed `campaigns[]` (not an array, a null entry) never breaks
|
|
2272
|
-
* `track()`: it falls back to `campaign.id`.
|
|
2273
|
-
*/
|
|
2274
|
-
declare function resolveCampaignId(ctx: Pick<AnalyticsContext, 'campaignId' | 'sponsorId' | 'slot'>, boot: Pick<BootstrapResponse, 'campaign' | 'campaigns'> | null | undefined, opts?: {
|
|
2275
|
-
pageCampaignId?: CampaignHint;
|
|
2276
|
-
}): number | undefined;
|
|
2277
|
-
/**
|
|
2278
|
-
* `detail` of `vio:payment-success` as the checkout emits it. Four paths,
|
|
2279
|
-
* three shapes: a redirect return (`orderId` = Vio's checkout id), the
|
|
2280
|
-
* confirmation drawer and a provider's own receipt (`result` from the
|
|
2281
|
-
* provider or the backend, plus Vio's `checkoutId`), and Apple Pay express
|
|
2282
|
-
* from the cart (`result` with the backend's `confirmation`, no sponsor).
|
|
2283
|
-
*/
|
|
2284
|
-
interface PaymentSuccessDetail {
|
|
2285
|
-
method?: string;
|
|
2286
|
-
sponsorId?: number | string;
|
|
2287
|
-
/** The slot the purchase started from, when the emitter knows it. */
|
|
2288
|
-
slot?: string;
|
|
2289
|
-
/** The campaign the emitter attributed the purchase to (its `Vio.attribution`). */
|
|
2290
|
-
campaignId?: number;
|
|
2291
|
-
/** Per-element content override (`vio-content-id` / `vio-content-title`), when the emitter carries one. */
|
|
2292
|
-
contentId?: string | number;
|
|
2293
|
-
contentTitle?: string;
|
|
2294
|
-
/** Redirect return: Vio's checkout id (the name predates `checkoutId`). */
|
|
2295
|
-
orderId?: string | number;
|
|
2296
|
-
/** Vio's checkout id — from the checkout state or the return URL. */
|
|
2297
|
-
checkoutId?: string | number;
|
|
2298
|
-
result?: PaymentSuccessResult | null;
|
|
2299
|
-
}
|
|
2300
|
-
/**
|
|
2301
|
-
* What the checkout attaches as `result`. Only `confirmation` carries a Vio
|
|
2302
|
-
* id: the order `ConfirmPaymentApplePay` created. `order.orderId` / `orderId`
|
|
2303
|
-
* are the PROVIDER's references (Qliro's, Walley's — the checkout itself
|
|
2304
|
-
* shows them as `providerRef`), and `chargedTotal` includes shipping on some
|
|
2305
|
-
* methods only. Analytics reads none of those.
|
|
2306
|
-
*/
|
|
2307
|
-
interface PaymentSuccessResult {
|
|
2308
|
-
confirmation?: {
|
|
2309
|
-
orderId?: string | number | null;
|
|
2310
|
-
status?: string;
|
|
2311
|
-
} | null;
|
|
2312
|
-
[key: string]: unknown;
|
|
2847
|
+
private findStripeConnectAccount;
|
|
2848
|
+
/** The sponsor's connected account, read fresh from its channel config. */
|
|
2849
|
+
private resolveStripeConnectAccount;
|
|
2850
|
+
private emit;
|
|
2313
2851
|
}
|
|
2314
|
-
/**
|
|
2315
|
-
* The `order_id` of a `purchase`: ALWAYS a Vio id, never a provider's
|
|
2316
|
-
* reference. Normalized across every emitter: `orderId` (redirect return) →
|
|
2317
|
-
* `result.confirmation.orderId` (Apple Pay) → `checkoutId`. `value` and
|
|
2318
|
-
* `currency` are deliberately NOT read from the result: on every path they
|
|
2319
|
-
* come from the cart snapshot (sum of the items, no shipping), so revenue
|
|
2320
|
-
* stays comparable across payment methods — the charged total will arrive
|
|
2321
|
-
* through the server-side `order_paid` event. With nothing to say it
|
|
2322
|
-
* returns `{}`, so the cart snapshot keeps its keys.
|
|
2323
|
-
*/
|
|
2324
|
-
declare function purchaseFromPaymentSuccess(d: PaymentSuccessDetail): Pick<AnalyticsCommerce, 'orderId'>;
|
|
2325
2852
|
|
|
2326
2853
|
/**
|
|
2327
2854
|
* Content (article) attribution — the other half of "where did this happen".
|
|
@@ -2340,11 +2867,32 @@ declare function purchaseFromPaymentSuccess(d: PaymentSuccessDetail): Pick<Analy
|
|
|
2340
2867
|
interface ContentRef {
|
|
2341
2868
|
id?: string;
|
|
2342
2869
|
title?: string;
|
|
2870
|
+
/** The page's URL as origin + path (no query, no fragment), capped — what the order and the cart's origins carry as `content_url`. */
|
|
2871
|
+
url?: string;
|
|
2343
2872
|
}
|
|
2344
2873
|
interface ContentInit {
|
|
2345
2874
|
contentId?: string | number | null;
|
|
2346
2875
|
contentTitle?: string | null;
|
|
2347
2876
|
}
|
|
2877
|
+
/** The collector (and Commerce's `order.content_url`) cap `content_url` at 2 048 chars. */
|
|
2878
|
+
declare const CONTENT_URL_MAX_LENGTH = 2048;
|
|
2879
|
+
/**
|
|
2880
|
+
* A page as the ORDER and the cart's origins name it (`content_url` to
|
|
2881
|
+
* Commerce): origin + path — no query string, no fragment — within the cap.
|
|
2882
|
+
* The query is where a page carries e-mails, tokens and tracking tails
|
|
2883
|
+
* (`?email=…&utm_…#frag`); none of that belongs on an order row. A site whose
|
|
2884
|
+
* article lives in the query or the hash identifies it through `contentId`
|
|
2885
|
+
* (`Vio.init({ contentId })`, `?vio_content=`), not through the URL. Also
|
|
2886
|
+
* the shape of the landing's referrer and page (client-context.ts).
|
|
2887
|
+
*/
|
|
2888
|
+
declare function originAndPath(raw: unknown, max?: number): string | undefined;
|
|
2889
|
+
/**
|
|
2890
|
+
* A page URL within the cap for the analytics EVENTS — as is, else without
|
|
2891
|
+
* its query string (a long one is usually the tracking tail, not the page),
|
|
2892
|
+
* else cut. The collector keeps the query there (`page_views` strip it
|
|
2893
|
+
* themselves); the order does not (`originAndPath`).
|
|
2894
|
+
*/
|
|
2895
|
+
declare function capContentUrl(value: unknown): string | undefined;
|
|
2348
2896
|
/**
|
|
2349
2897
|
* Id: `Vio.init({ contentId })` → `?vio_content=` → `<meta name="vio:content-id">`
|
|
2350
2898
|
* → `<link rel="canonical">` href or `<meta property="og:url">` (without query
|
|
@@ -2358,39 +2906,7 @@ declare function resolveContent(init?: ContentInit | null, doc?: Document | null
|
|
|
2358
2906
|
search?: string;
|
|
2359
2907
|
} | null | undefined): ContentRef;
|
|
2360
2908
|
|
|
2361
|
-
|
|
2362
|
-
* The cart split per campaign (ADR-0034) — ONE rule, shared by the SDK's own
|
|
2363
|
-
* `begin_checkout` / `purchase` events, by `Vio.cartSlices()` and so by any
|
|
2364
|
-
* host with its own analytics sink (Vev).
|
|
2365
|
-
*
|
|
2366
|
-
* Every unit of every line goes to the campaign of its origin — the one the
|
|
2367
|
-
* place showed when it was added — and units without one to the campaign the
|
|
2368
|
-
* caller's rule resolves for the line's sponsor (`resolveCampaign`). One slice
|
|
2369
|
-
* per campaign: its items (quantities from the origins, merged per product +
|
|
2370
|
-
* variant), its value with two decimals, and `slot` / `contentId` /
|
|
2371
|
-
* `sponsorId` only when they are the same for the whole slice. A cart with
|
|
2372
|
-
* one campaign is one slice. Pure; never throws on odd lines.
|
|
2373
|
-
*/
|
|
2374
|
-
|
|
2375
|
-
/** An item of a slice — the analytics item shape (ids as given, normalized on the wire). */
|
|
2376
|
-
type VioItem = AnalyticsItemInput;
|
|
2377
|
-
/** One campaign's share of the cart. */
|
|
2378
|
-
interface CartSlice {
|
|
2379
|
-
campaignId?: number;
|
|
2380
|
-
sponsorId?: number;
|
|
2381
|
-
slot?: string;
|
|
2382
|
-
contentId?: string;
|
|
2383
|
-
items: VioItem[];
|
|
2384
|
-
value: number;
|
|
2385
|
-
currency?: string;
|
|
2386
|
-
/** 1-based position of this slice and how many there are. */
|
|
2387
|
-
slice: number;
|
|
2388
|
-
slices: number;
|
|
2389
|
-
}
|
|
2390
|
-
/** The campaign of a unit without an explicit one: the caller's rule (slot assignment → sponsor → default). */
|
|
2391
|
-
type ResolveCampaign = (slot: string | undefined, sponsorId: number) => number | undefined;
|
|
2392
|
-
declare function cartSlicesFrom(lines: ReadonlyArray<CartLineItem>, resolveCampaign: ResolveCampaign, fallbackCurrency?: string): CartSlice[];
|
|
2393
|
-
|
|
2909
|
+
type PrivacyAnswer = SurfacePrivacyMode | 'unknown';
|
|
2394
2910
|
declare class VioFacade {
|
|
2395
2911
|
private apiInstance;
|
|
2396
2912
|
private commerceClients;
|
|
@@ -2403,7 +2919,7 @@ declare class VioFacade {
|
|
|
2403
2919
|
* (another key or environment) is still in flight after a re-init; its answer
|
|
2404
2920
|
* belongs to that configuration and must not land in this one. */
|
|
2405
2921
|
private generation;
|
|
2406
|
-
/** Slot ids present on the page (`Vio.registerSlot`): how many elements hold each, its display name
|
|
2922
|
+
/** Slot ids present on the page (`Vio.registerSlot`): how many elements hold each, its display name, its own campaign and its kind. */
|
|
2407
2923
|
private slotRegistry;
|
|
2408
2924
|
/** Slots already warned about (`dashboard`: the dashboard's assignment stands; `replaced`: this page moved it). */
|
|
2409
2925
|
private warnedDashboardSlots;
|
|
@@ -2420,6 +2936,10 @@ declare class VioFacade {
|
|
|
2420
2936
|
private cartManager;
|
|
2421
2937
|
private checkoutManager;
|
|
2422
2938
|
private analyticsManager;
|
|
2939
|
+
/** What the surface answered of its privacy mode (`GET /v2/mobile/surface`) and when; `unknown` expires after a minute. */
|
|
2940
|
+
private surfaceMode;
|
|
2941
|
+
/** The request in flight for it, if any. */
|
|
2942
|
+
private surfaceRequest;
|
|
2423
2943
|
init(config: VioConfig): void;
|
|
2424
2944
|
/**
|
|
2425
2945
|
* The content (article, page) this SDK instance is rendered in — what every
|
|
@@ -2435,7 +2955,7 @@ declare class VioFacade {
|
|
|
2435
2955
|
get config(): ResolvedConfig;
|
|
2436
2956
|
/** Multi-sponsor cart manager. Reactive — listen via addEventListener('change', ...). */
|
|
2437
2957
|
get cart(): CartManager;
|
|
2438
|
-
/** Checkout flow manager. Subscribes to cart state via the CartManager. */
|
|
2958
|
+
/** Checkout flow manager. Subscribes to cart state via the CartManager; asks here for the order's attribution. */
|
|
2439
2959
|
get checkout(): CheckoutManager;
|
|
2440
2960
|
/**
|
|
2441
2961
|
* Analytics — track() queues even pre-init; nothing is sent (and no
|
|
@@ -2479,12 +2999,19 @@ declare class VioFacade {
|
|
|
2479
2999
|
* the optional display name, and the element's own campaign when it has
|
|
2480
3000
|
* one: `vio-campaign` or an ancestor's `data-vio-campaign`). The registry is
|
|
2481
3001
|
* declared ONCE, debounced, after the first successful bootstrap — and again
|
|
2482
|
-
* whenever a new id, display name or
|
|
3002
|
+
* whenever a new id, display name, campaign or kind appears. A `displayName` /
|
|
2483
3003
|
* `campaignId` given later for an id already registered replaces the one
|
|
2484
|
-
* kept; `undefined` leaves it alone. The
|
|
3004
|
+
* kept; `undefined` leaves it alone. The third argument is the campaign id
|
|
3005
|
+
* (as before) or `{ campaignId?, kind? }`, and a fourth `{ kind? }` may
|
|
3006
|
+
* follow a positional campaign — the elements call
|
|
3007
|
+
* `registerSlot(id, name, campaignId, { kind })` so a facade from an older
|
|
3008
|
+
* bundle, which reads only three arguments, still gets the campaign. `kind`
|
|
3009
|
+
* is what kind of element holds the slot (`card` | `carousel` | `detail`);
|
|
3010
|
+
* the FIRST kind an id gets stays (the cards a carousel renders share its
|
|
3011
|
+
* id: the slot is the carousel's). The returned function unregisters;
|
|
2485
3012
|
* removal never re-declares.
|
|
2486
3013
|
*/
|
|
2487
|
-
registerSlot(name: string, displayName?: string,
|
|
3014
|
+
registerSlot(name: string, displayName?: string, campaignIdOrOptions?: number | string | null | RegisterSlotOptions, options?: RegisterSlotOptions): () => void;
|
|
2488
3015
|
/**
|
|
2489
3016
|
* The campaign a slot shows now, from the last bootstrap: its assigned and
|
|
2490
3017
|
* open campaign for the init platform, else the surface's default. With no
|
|
@@ -2523,6 +3050,58 @@ declare class VioFacade {
|
|
|
2523
3050
|
sponsorId?: number | string;
|
|
2524
3051
|
campaignId?: CampaignHint;
|
|
2525
3052
|
}): Attribution;
|
|
3053
|
+
/**
|
|
3054
|
+
* What the surface answered and is still believed: `standard` / `minimal`
|
|
3055
|
+
* for the configuration; `unknown` for a minute after a timeout or a
|
|
3056
|
+
* failure (then it is asked again). `null` = nothing believed.
|
|
3057
|
+
*/
|
|
3058
|
+
private believedSurfaceMode;
|
|
3059
|
+
/**
|
|
3060
|
+
* Ask the surface its privacy mode (`GET /v2/mobile/surface`), once —
|
|
3061
|
+
* started at `init()` and again by `bootstrap()`, never by the payment
|
|
3062
|
+
* path, which only reads what is known (`privacyModeNow`). Resolves what
|
|
3063
|
+
* was learnt within 1.5 s: the mode; `standard` for a service that predates
|
|
3064
|
+
* the endpoint (404) or a surface that names none; `unknown` for a word the
|
|
3065
|
+
* SDK does not know, a timeout or any other failure — believed for a
|
|
3066
|
+
* minute, then asked again. An answer that arrives after the cap still
|
|
3067
|
+
* lands for the next step. Never throws.
|
|
3068
|
+
*/
|
|
3069
|
+
preloadPrivacyMode(): Promise<PrivacyAnswer>;
|
|
3070
|
+
/**
|
|
3071
|
+
* How much of the visit the order attribution may carry (ADR-0035): the
|
|
3072
|
+
* surface's privacy mode, as known RIGHT NOW, without waiting —
|
|
3073
|
+
* `Vio.init({ privacyMode: 'minimal' })` when the host says so, else what
|
|
3074
|
+
* the bootstrap says of the surface, else what the surface answered to the
|
|
3075
|
+
* ask `init()` started (`preloadPrivacyMode`), else the host's `standard`
|
|
3076
|
+
* once the surface could not tell. `unknown` while nothing is known: then
|
|
3077
|
+
* the page, the slot and the entry stay off what goes to Commerce, because
|
|
3078
|
+
* what can reveal which screen someone was on, and why, is only sent when
|
|
3079
|
+
* the surface is known to allow it. The payment path reads this one.
|
|
3080
|
+
*/
|
|
3081
|
+
privacyModeNow(): PrivacyAnswer;
|
|
3082
|
+
/**
|
|
3083
|
+
* `privacyModeNow`, but waiting for the ask in flight when there is one
|
|
3084
|
+
* (at most its 1.5 s cap) — for the cart's lines, which are not the
|
|
3085
|
+
* payment path. Never throws.
|
|
3086
|
+
*/
|
|
3087
|
+
privacyMode(): Promise<PrivacyAnswer>;
|
|
3088
|
+
/**
|
|
3089
|
+
* The attribution of the order a sponsor's cart is about to become
|
|
3090
|
+
* (ADR-0035 phase B) — what `CreateCheckout` / `UpdateCheckout` send as
|
|
3091
|
+
* `attribution` and shopcart writes on the order: the surface (its SDK
|
|
3092
|
+
* key), the page's campaign (`pageCampaign()`; without one, the campaign
|
|
3093
|
+
* that explains most units of the cart under the same rule `purchase` is
|
|
3094
|
+
* split by — `cartSlices`) and, on a surface KNOWN to be `standard`
|
|
3095
|
+
* (`privacyModeNow`), the page (`content()`'s url as origin + path, and
|
|
3096
|
+
* title) and where the session came in: the landing the session REMEMBERS
|
|
3097
|
+
* (`storedLanding`, else the one analytics resolved on this page) — never
|
|
3098
|
+
* the page the shopper pays on taken for a landing. Synchronous: nothing
|
|
3099
|
+
* on the way to a payment waits for it. snake_case, capped to Commerce's
|
|
3100
|
+
* limits. `undefined` when there is nothing to say; never throws.
|
|
3101
|
+
*/
|
|
3102
|
+
orderAttribution(sponsorId?: number): CheckoutAttributionWire | undefined;
|
|
3103
|
+
/** The landing the session remembers: what the first page stored, else what analytics resolved on this page load (consent pending); null otherwise. */
|
|
3104
|
+
private rememberedLanding;
|
|
2526
3105
|
/**
|
|
2527
3106
|
* The cart split per campaign — the SAME rule `begin_checkout` / `purchase`
|
|
2528
3107
|
* use, for hosts with their own analytics sink (Vev). Every unit of every
|
|
@@ -2556,6 +3135,20 @@ declare class VioFacade {
|
|
|
2556
3135
|
}
|
|
2557
3136
|
declare const Vio: VioFacade;
|
|
2558
3137
|
|
|
3138
|
+
/**
|
|
3139
|
+
* The buyer reference — shopcart's `buyer_ref`: the keyed hash Commerce
|
|
3140
|
+
* computes from the buyer's email, so one person is one ref across orders,
|
|
3141
|
+
* devices and platforms, and nothing in it can be turned back into an email
|
|
3142
|
+
* without Commerce's secret. The SDK forwards it as analytics `buyer_id`
|
|
3143
|
+
* (EVENTS_CONTRACT `commerce.buyer_id`, ≤ 128 chars in the collector's
|
|
3144
|
+
* schema) and never puts anything else in its place: an email, a name, an
|
|
3145
|
+
* over-long value are dropped — not hashed client-side, not cut (a cut hash
|
|
3146
|
+
* is another identity).
|
|
3147
|
+
*/
|
|
3148
|
+
declare const BUYER_REF_MAX_LENGTH = 128;
|
|
3149
|
+
/** The reference when `value` is one; `undefined` for anything else (never an email). */
|
|
3150
|
+
declare function normalizeBuyerRef(value: unknown): string | undefined;
|
|
3151
|
+
|
|
2559
3152
|
/**
|
|
2560
3153
|
* SDK version reported in analytics events (`sdk_version`) and available
|
|
2561
3154
|
* to consumers. Kept as a constant (not a package.json import) so the
|
|
@@ -2563,7 +3156,7 @@ declare const Vio: VioFacade;
|
|
|
2563
3156
|
*
|
|
2564
3157
|
* RELEASE CHECKLIST: bump together with package.json (see CONTRIBUTING).
|
|
2565
3158
|
*/
|
|
2566
|
-
declare const SDK_VERSION = "0.
|
|
3159
|
+
declare const SDK_VERSION = "0.25.0";
|
|
2567
3160
|
|
|
2568
3161
|
/**
|
|
2569
3162
|
* Vipps MobilePay's own button, the way the design guidelines ask for it.
|
|
@@ -2592,4 +3185,4 @@ declare function vippsButtonAttributes(verb?: 'buy' | 'pay' | 'express' | 'conti
|
|
|
2592
3185
|
language?: string;
|
|
2593
3186
|
}): Record<string, string>;
|
|
2594
3187
|
|
|
2595
|
-
export { ADD_ITEM_MUTATION, type AddManualOptions, type AddProductOptions, type AnalyticsCommerce, type AnalyticsContext, type AnalyticsEventName, type AnalyticsItemInput, AnalyticsManager, type AnalyticsStartOptions, type ApplePayConfig, type ApplePayResult, type Attribution, type BootstrapCampaign, type BootstrapCampaignEntry, type BootstrapCampaignStatus, type BootstrapResponse, type BootstrapSlot, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, type CampaignHint, type CartChangeDetail, type CartLineItem, type CartLineOrigin, CartManager, type CartOrigin, type CartQueryOptions, type CartSlice, type CheckoutAddress, type CheckoutChangeDetail, CheckoutManager, type CheckoutState, CommerceClient, Configuration, type ContentRef, type CreatePaymentVippsResponse, type CreatePaymentVippsVariables, DELETE_ITEM_MUTATION, type Environment, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, type GetVippsStatusVariables, type ImageSize, type ManifestLocation, type ManifestRequest, type ManifestResult, type PaymentCompleteDetail, type PaymentMethod, type PaymentSelectDetail, type PaymentSuccessDetail, type PaymentSuccessResult, type PlacementComponent, type Product, type ProductCategory, type ProductImage, type ProductOption, type ProductPrice, type ProductVariant, type ResolvedConfig, SDK_VERSION, type SlotInput, type SlotKind, type Sponsor, type SponsorCartState, type SponsorCommerceBlock, type TrackOptions, UPDATE_CHECKOUT_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, type VioConfig, type VioItem, type VioPlatform, type VippsPaymentState, type VippsStatusResult, activeCampaignEntry, addItem, autoSlotDisplayName, autoSlotId, campaignCandidates, cartSlicesFrom, checkApplePayAvailability, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, ensureVippsButton, executeCartGraphQL, formatPrice, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, lineOrigins, normalizeOrigin, normalizeScope, primaryImageUrl, purchaseFromPaymentSuccess, resolveCampaignId, resolveContent, resolveSlotCampaign, sameOrigin, showApplePaySheet, sponsorCampaignEntry, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes };
|
|
3188
|
+
export { ADD_ITEM_MUTATION, type AddManualOptions, type AddProductOptions, type AnalyticsCommerce, type AnalyticsContext, type AnalyticsEventName, type AnalyticsItemInput, AnalyticsManager, type AnalyticsStartOptions, type ApplePayConfig, type ApplePayResult, type Attribution, BUYER_REF_MAX_LENGTH, type BootstrapCampaign, type BootstrapCampaignEntry, type BootstrapCampaignStatus, type BootstrapResponse, type BootstrapSlot, CHECKOUT_ATTRIBUTION_CAPS, CLIENT_LANDING_URL_MAX_LENGTH, CONTENT_URL_MAX_LENGTH, CREATE_CART_MUTATION, CREATE_CHECKOUT_MUTATION, CREATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, CREATE_PAYMENT_STRIPE_MUTATION, CREATE_PAYMENT_VIPPS_MUTATION, type CampaignHint, type CartChangeDetail, type CartLineItem, type CartLineOrigin, CartManager, type CartOrigin, type CartQueryOptions, type CartSlice, type CheckoutAddress, type CheckoutAttributionInput, type CheckoutAttributionWire, type CheckoutChangeDetail, CheckoutManager, type CheckoutManagerDeps, type CheckoutReference, type CheckoutState, type ClientContext, CommerceClient, Configuration, type ContentRef, type CreatePaymentVippsResponse, type CreatePaymentVippsVariables, DELETE_ITEM_MUTATION, type EntryContextWire, type Environment, GET_AVAILABLE_PAYMENT_METHODS_QUERY, GET_CART_QUERY, GET_CHECKOUT_QUERY, GET_LINE_ITEMS_BY_SUPPLIER_QUERY, GET_VIPPS_STATUS_QUERY, GRAPHQL_INT_MAX, type GatewayFeature, type GetVippsStatusVariables, type ImageSize, LINE_ORIGIN_CAPS, type Landing, type LineOriginWire, type LineOriginWireOptions, type ManifestLocation, type ManifestRequest, type ManifestResult, type OriginPage, type PaymentCompleteDetail, type PaymentMethod, type PaymentSelectDetail, type PaymentSuccessDetail, type PaymentSuccessResult, type PlacementComponent, type Product, type ProductCategory, type ProductImage, type ProductOption, type ProductPrice, type ProductVariant, type RegisterSlotOptions, type ResolvedConfig, SDK_VERSION, type SlotInput, type SlotKind, type Sponsor, type SponsorCartState, type SponsorCommerceBlock, type SurfacePrivacyMode, type SurfaceResponse, type TrackOptions, UPDATE_CHECKOUT_MUTATION, UPDATE_CHECKOUT_WITH_ATTRIBUTION_MUTATION, UPDATE_ITEM_MUTATION, UPDATE_ITEM_WITH_ORIGIN_MUTATION, UPDATE_SHIPPINGS_BY_SUPPLIER_MUTATION, VIPPS_BUTTON_SCRIPT, VIPPS_BUTTON_TAG, Vio, VioApi, VioApiError, type VioConfig, type VioItem, type VioPlatform, type VippsPaymentState, type VippsStatusResult, activeCampaignEntry, addItem, autoSlotDisplayName, autoSlotId, buyerRefOf, campaignCandidates, capContentUrl, cartSlicesFrom, checkApplePayAvailability, checkoutAttributionOf, componentKindOf, createCart, createCheckout, createCommerceClient, createPaymentStripe, createPaymentVipps, createVioApi, deleteItem, displayPrice, dominantCampaignOf, ensureVippsButton, entryContextOf, executeCartGraphQL, formatPrice, gatewayHas, getAvailablePaymentMethods, getCart, getCartGraphQLOptions, getCheckout, getCheckoutReference, getCustomerSessionId, getGlobalCurrency, getLineItemsBySupplier, getVippsStatus, isUnknownFeatureError, isUnknownTokenError, landingUrl, lineOriginWire, lineOrigins, normalizeBuyerRef, normalizeOrigin, normalizeScope, normalizeSlotKind, originAndPath, primaryImageUrl, purchaseFromPaymentSuccess, resetGatewayFeatures, resolveCampaignId, resolveClientContext, resolveContent, resolveLanding, resolveSlotCampaign, sameOrigin, showApplePaySheet, sponsorCampaignEntry, storedLanding, toCampaignId, updateCheckout, updateItem, updateShippingsBySupplier, vippsButtonAttributes, withGatewayFeature };
|