@studio-vaai/js-tracking 0.2.3 → 0.3.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 CHANGED
@@ -1,73 +1,30 @@
1
1
  # @studio-vaai/js-tracking
2
2
 
3
- Typed analytics events for studio vaai, plus a [Umami](https://umami.is) transport
4
- that posts to `/api/send` via keepalive `fetch`.
5
-
6
- ## Public surface
3
+ Typed analytics events and a fetch transport for studio vaai analytics.
7
4
 
8
5
  ```ts
9
- interface TrackingClient {
10
- trackEvent(event: TrackingEvent, options?: TrackOptions): TrackResult;
11
- }
12
- ```
13
-
14
- Synchronous and fire-and-forget — the default transport dispatches via
15
- `fetch` with `keepalive: true` and `credentials: "omit"` so events survive
16
- page unload and work against cross-origin Umami hosts that return
17
- `Access-Control-Allow-Origin: *`. The returned `TrackResult` reflects whether
18
- the request was queued (or the event was buffered for later flush), not
19
- whether the server acknowledged it.
20
-
21
- Event-specific by design: every event must appear in `TrackingEvent` (see
22
- [`src/events.ts`](src/events.ts)). Until the first variant lands, `trackEvent`
23
- is uncallable — which forces a central declaration of every event the SDK can
24
- send.
6
+ import { createFetchTrackingClient } from "@studio-vaai/js-tracking";
25
7
 
26
- The Umami-script-style `track()` / `identify()` overloads live as
27
- closure-private helpers inside the transport in
28
- [`src/impl/fetch-umami-tracking-client.ts`](src/impl/fetch-umami-tracking-client.ts);
29
- they are not part of the public API.
30
-
31
- ## Usage
32
-
33
- ```ts
34
- import { createFetchUmamiTrackingClient } from "@studio-vaai/js-tracking";
35
-
36
- // Static config: websiteId known at construction.
37
- const tracking = createFetchUmamiTrackingClient({
38
- sdkVersion: "@studio-vaai/react-components@0.2.3",
39
- websiteId: "00000000-0000-0000-0000-000000000000",
40
- // baseUrl defaults to https://a.studio-vaai.com
8
+ const tracking = createFetchTrackingClient({
9
+ clientApiKey: "sv_client_…",
10
+ sdkVersion: "my-integration@1.0.0",
11
+ distinctId: "visitor-id",
12
+ // baseUrl: "https://a.studio-vaai.com", // default; override for local development
41
13
  });
42
-
43
- // Once you've declared the event in src/events.ts:
44
- tracking.trackEvent({ name: "try_on_started", data: { productId } });
14
+ tracking.trackEvent({ name: "consent-granted", data: { "product-id": "p1" } });
45
15
  ```
46
16
 
47
- ### Lazy resolver (per-shop config)
48
-
49
- Pass `resolveConfig` instead of `websiteId` when the Umami website is only
50
- known after an async lookup (e.g. fetched via `client.tracking.getTracking()`).
51
- Events fired before the resolver settles are buffered internally and flushed
52
- in order on success.
17
+ When using `js-client`, reuse its key and fetch implementation:
53
18
 
54
19
  ```ts
55
- const tracking = createFetchUmamiTrackingClient({
56
- sdkVersion: "@studio-vaai/react-components@0.2.3",
57
- resolveConfig: async () => {
58
- const r = await client.tracking.getTracking({});
59
- if (!r.ok) throw new ApiFailureError(r.error);
60
- return { websiteId: r.data.umamiWebsiteId, baseUrl: r.data.umamiBaseUrl };
61
- },
62
- });
20
+ const tracking = client.analytics.createTrackingClient({ sdkVersion: "my-integration@1" });
63
21
  ```
64
22
 
65
- ## Adding an event
66
-
67
- Declare it in [`src/events.ts`](src/events.ts) as a new `TrackingEvent` union
68
- variant (snake_case `name`, flat-primitive `data`). Call sites then get full
69
- autocomplete + type-checking on `name` and `data`.
70
-
71
- ## License
23
+ React providers create this transport automatically unless supplied with an explicit
24
+ `tracking` implementation. Requests use your existing `X-Client-Api-Key`. Browser
25
+ events must originate from one of the shop's allowed storefront origins.
72
26
 
73
- MIT
27
+ Events use `fetch` with `keepalive: true`, `credentials: "omit"`, and JSON POSTs to
28
+ `/api/send`. Context is derived from browser APIs and supports defaults and per-event
29
+ overrides. The return value reports whether the request was queued, not delivered.
30
+ Asynchronous errors are absorbed so analytics cannot interrupt the host application.
package/dist/base.d.ts CHANGED
@@ -16,26 +16,26 @@ export interface TrackFailure {
16
16
  * branch product behaviour on `ok`, but may surface a warning in dev.
17
17
  *
18
18
  * Returned synchronously from {@link TrackingClient.trackEvent} — reflects
19
- * whether the event was queued for delivery (via keepalive fetch or a buffer
20
- * waiting on a lazy resolver), not whether the server received it.
19
+ * whether the event was queued for delivery via keepalive fetch, not whether
20
+ * the server received it.
21
21
  */
22
22
  export type TrackResult = TrackSuccess | TrackFailure;
23
23
  /**
24
24
  * Ambient page/session metadata that decorates every event. Mirrors the Umami
25
- * `/api/send` payload so transports can pass it through unchanged.
25
+ * `/api/send` payload. The fetch transport strips URL query strings and fragments.
26
26
  *
27
27
  * Browser transports auto-populate these from `window`/`document`/`navigator`
28
28
  * when fields are absent; pass overrides via {@link TrackOptions.context} for
29
29
  * SSR, web workers, or tests.
30
30
  */
31
31
  export interface EventContext {
32
- /** Page URL path + query, e.g. `/products/abc?ref=hero`. */
32
+ /** Page path or URL, e.g. `/products/abc`. The fetch transport strips query strings and fragments. */
33
33
  url?: string;
34
34
  /** Document title. */
35
35
  title?: string;
36
36
  /** Hostname seen by the visitor, e.g. `shop.example.com`. */
37
37
  hostname?: string;
38
- /** HTTP `Referer` (sic) — origin page that linked to the current one. */
38
+ /** Referring page URL. The fetch transport strips query strings and fragments. */
39
39
  referrer?: string;
40
40
  /** BCP-47 language tag, e.g. `en-US`. */
41
41
  language?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,sGAAsG;IACtG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}
package/dist/client.d.ts CHANGED
@@ -6,21 +6,17 @@ export declare const SDK_PACKAGE_ID: "@studio-vaai/js-tracking";
6
6
  export type TrackingClientConfig = Record<never, never>;
7
7
  /**
8
8
  * Transport-agnostic event sender. Implementations live under `impl/` (e.g.
9
- * the Umami beacon transport) — consumers depend on this interface so the
9
+ * the collector transport) — consumers depend on this interface so the
10
10
  * underlying analytics backend can be swapped without touching call sites.
11
11
  */
12
12
  export interface TrackingClient {
13
13
  /**
14
- * Send a single typed event. Synchronous and fire-and-forget — implementations
15
- * dispatch via fire-and-forget `fetch` with `keepalive: true`. Returns a
14
+ * Send a single typed event. Synchronous and fire-and-forget —
15
+ * implementations dispatch via `fetch` with `keepalive: true`. Returns a
16
16
  * {@link TrackResult} reflecting whether the event was successfully queued
17
- * for delivery, NOT
18
- * whether the server acknowledged it. Never throws — analytics must not
19
- * break the host app.
20
- *
21
- * Buffered events (e.g. while a lazy resolver is in flight) return
22
- * `{ ok: true }` immediately; if the eventual flush fails, the caller is
23
- * not notified — that's the price of fire-and-forget analytics.
17
+ * for delivery, NOT whether the server acknowledged it. Never throws —
18
+ * analytics must not break the host app.
19
+
24
20
  */
25
21
  trackEvent(event: TrackingEvent, options?: TrackOptions): TrackResult;
26
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,sBAAsB;AACtB,eAAO,MAAM,cAAc,EAAG,0BAAmC,CAAC;AAElE,6CAA6C;AAC7C,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;CACvE;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAElF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,sBAAsB;AACtB,eAAO,MAAM,cAAc,EAAG,0BAAmC,CAAC;AAElE,6CAA6C;AAE7C,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;OAOG;IACH,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;CACvE;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAElF"}
package/dist/client.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import { TrackingClientNotImplementedError } from "./errors.js";
2
- //#region src/client.ts
2
+ // src/client.ts
3
3
  /** Npm package id. */
4
4
  var SDK_PACKAGE_ID = "@studio-vaai/js-tracking";
5
5
  /** Contract-only stub — throws; a transport package supplies a real implementation. */
6
6
  function createTrackingClient(_config) {
7
7
  throw new TrackingClientNotImplementedError();
8
8
  }
9
- //#endregion
10
9
  export { SDK_PACKAGE_ID, createTrackingClient };
package/dist/errors.js CHANGED
@@ -1,11 +1,10 @@
1
- //#region src/errors.ts
1
+ // src/errors.ts
2
2
  /** Thrown by the contract-only {@link createTrackingClient} stub. */
3
3
  var TrackingClientNotImplementedError = class extends Error {
4
4
  code = "tracking_client_not_implemented";
5
5
  constructor() {
6
- super("@studio-vaai/js-tracking: createTrackingClient has no runtime implementation; use a transport like createFetchUmamiTrackingClient.");
6
+ super("@studio-vaai/js-tracking: createTrackingClient has no runtime implementation; use a transport like createFetchTrackingClient.");
7
7
  this.name = "TrackingClientNotImplementedError";
8
8
  }
9
9
  };
10
- //#endregion
11
10
  export { TrackingClientNotImplementedError };
package/dist/events.d.ts CHANGED
@@ -18,7 +18,7 @@ export interface TrackingEventBase {
18
18
  }
19
19
  /**
20
20
  * Fields present on every event's `data`. The transport additionally injects
21
- * `sdk-version` from {@link FetchUmamiTrackingClientConfig.sdkVersion}, so
21
+ * `sdk-version` from {@link FetchTrackingClientConfig.sdkVersion}, so
22
22
  * callers never set that themselves.
23
23
  */
24
24
  interface CommonData {
@@ -118,6 +118,23 @@ interface TryOnInitiatedEvent extends TrackingEventBase {
118
118
  readonly name: "try-on-initiated";
119
119
  readonly data: CommonData & VariantData;
120
120
  }
121
+ /**
122
+ * Fires when the shopper deliberately selects a size the fit gate marks as
123
+ * unwearable for their body (the chip carries a "too small"/"too big" badge, so
124
+ * the pick is informed). The gated size is never rendered — the flow pre-pivots
125
+ * the try-on to the recommended size — so this event is the only signal of the
126
+ * shopper's insistence, and its rate per product is direct feedback on how much
127
+ * shoppers trust or contest the gate's verdicts.
128
+ */
129
+ interface GatedSizeSelectedEvent extends TrackingEventBase {
130
+ readonly name: "gated-size-selected";
131
+ readonly data: CommonData & {
132
+ /** The gated size slug the shopper picked. */
133
+ readonly "variant-size": string;
134
+ /** The gate's verdict for that size. */
135
+ readonly gate: "too_small" | "too_large";
136
+ };
137
+ }
121
138
  interface CartItemAddedEvent extends TrackingEventBase {
122
139
  readonly name: "cart-item-added";
123
140
  readonly data: CommonData & VariantData;
@@ -132,11 +149,26 @@ interface ViewClosedEvent extends TrackingEventBase {
132
149
  readonly "current-step": Step;
133
150
  };
134
151
  }
152
+ /**
153
+ * Fires once when the backend assigns a visitor to an arm of the try-on
154
+ * rollout A/B test. Feature-level (no `product-id`) — it gates the entry point
155
+ * before any product context exists. Correlate `variant` against downstream
156
+ * conversion events in Umami to measure the test.
157
+ */
158
+ interface ExperimentAssignedEvent extends TrackingEventBase {
159
+ readonly name: "experiment-assigned";
160
+ readonly data: {
161
+ /** Experiment identifier; currently always `try-on-enabled`. */
162
+ readonly experiment: "try-on-enabled";
163
+ /** Assigned arm. */
164
+ readonly variant: "enabled" | "disabled";
165
+ };
166
+ }
135
167
  /**
136
168
  * Discriminated union of every event the SDK can send. Add new events by
137
169
  * declaring a variant interface above and appending it to the union — call
138
170
  * sites get full autocomplete + type-checking on `name` and `data`.
139
171
  */
140
- export type TrackingEvent = EntrypointImpressionEvent | EntrypointClickedEvent | IntroOpenedEvent | ConsentGrantedEvent | ImageRecordInitiatedEvent | ImageRecordAbortedEvent | ImageUploadInitiatedEvent | ImageUploadAbortedEvent | ImageUploadedEvent | HeightEnteredEvent | VariantSelectionInitiatedEvent | TryOnInitiatedEvent | CartItemAddedEvent | OrderPlacedEvent | ViewClosedEvent;
172
+ export type TrackingEvent = EntrypointImpressionEvent | EntrypointClickedEvent | IntroOpenedEvent | ConsentGrantedEvent | ImageRecordInitiatedEvent | ImageRecordAbortedEvent | ImageUploadInitiatedEvent | ImageUploadAbortedEvent | ImageUploadedEvent | HeightEnteredEvent | VariantSelectionInitiatedEvent | TryOnInitiatedEvent | GatedSizeSelectedEvent | CartItemAddedEvent | OrderPlacedEvent | ViewClosedEvent | ExperimentAssignedEvent;
141
173
  export {};
142
174
  //# sourceMappingURL=events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,UAAU,UAAU;IAClB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,UAAU,yBAA0B,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,gEAAgE;QAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,UAAU,sBAAuB,SAAQ,iBAAiB;IACxD,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC;KAC/B,CAAC;CACH;AAED,UAAU,gBAAiB,SAAQ,iBAAiB;IAClD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,gHAAgH;QAChH,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;KACvB,CAAC;CACH;AAED,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,UAAU,yBAA0B,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;KAClC,CAAC;CACH;AAED,UAAU,uBAAwB,SAAQ,iBAAiB;IACzD,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;KAClC,CAAC;CACH;AAED,UAAU,yBAA0B,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;KAClC,CAAC;CACH;AAED,UAAU,uBAAwB,SAAQ,iBAAiB;IACzD,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;KAClC,CAAC;CACH;AAED,UAAU,kBAAmB,SAAQ,iBAAiB;IACpD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,cAAc,EAAE,mBAAmB,GAAG,sBAAsB,GAAG,QAAQ,CAAC;KAClF,CAAC;CACH;AAED,UAAU,kBAAmB,SAAQ,iBAAiB;IACpD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,sDAAsD;QACtD,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;KACvB,CAAC;CACH;AAED,gFAAgF;AAChF,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,wBAAwB,CAAC;AAEpE,UAAU,8BAA+B,SAAQ,iBAAiB;IAChE,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,qCAAqC;QACrC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;QACtB;;;;WAIG;QACH,QAAQ,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC;KACpC,CAAC;CACH;AAED;;;;;;GAMG;AACH,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAE1E,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;CACzC;AAED,UAAU,kBAAmB,SAAQ,iBAAiB;IACpD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;CACzC;AAED,UAAU,gBAAiB,SAAQ,iBAAiB;IAClD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;CACzC;AAED,UAAU,eAAgB,SAAQ,iBAAiB;IACjD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG;QAC1B,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC;KAC/B,CAAC;CACH;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,yBAAyB,GACzB,sBAAsB,GACtB,gBAAgB,GAChB,mBAAmB,GACnB,yBAAyB,GACzB,uBAAuB,GACvB,yBAAyB,GACzB,uBAAuB,GACvB,kBAAkB,GAClB,kBAAkB,GAClB,8BAA8B,GAC9B,mBAAmB,GACnB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,CAAC"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { EventContext } from "../base.js";
2
+ import type { TrackingClient } from "../client.js";
3
+ export declare const DEFAULT_COLLECTOR_BASE_URL: "https://a.studio-vaai.com";
4
+ export interface FetchTrackingClientConfig {
5
+ clientApiKey: string;
6
+ baseUrl?: string;
7
+ sdkVersion: string;
8
+ distinctId?: string | (() => string);
9
+ fetch?: typeof fetch;
10
+ defaultContext?: EventContext;
11
+ }
12
+ /** Direct collector transport. Returns whether the request was queued, never delivery acknowledgement. */
13
+ export declare function createFetchTrackingClient(config: FetchTrackingClientConfig): TrackingClient;
14
+ //# sourceMappingURL=fetch-tracking-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-tracking-client.d.ts","sourceRoot":"","sources":["../../src/impl/fetch-tracking-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,eAAO,MAAM,0BAA0B,EAAG,2BAAoC,CAAC;AAE/E,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,cAAc,CAAC,EAAE,YAAY,CAAC;CAC/B;AAiFD,0GAA0G;AAC1G,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,cAAc,CA8C3F"}
@@ -0,0 +1,99 @@
1
+ // src/impl/fetch-tracking-client.ts
2
+ var DEFAULT_COLLECTOR_BASE_URL = "https://a.studio-vaai.com";
3
+ function deriveBrowserContext() {
4
+ const ctx = {};
5
+ if (typeof globalThis === "undefined") return ctx;
6
+ const w = globalThis.window;
7
+ if (typeof w === "undefined") return ctx;
8
+ const loc = w.location;
9
+ if (typeof loc !== "undefined") {
10
+ ctx.hostname = loc.hostname;
11
+ ctx.url = loc.pathname;
12
+ }
13
+ const doc = w.document;
14
+ if (typeof doc !== "undefined") {
15
+ ctx.title = doc.title;
16
+ if (doc.referrer !== "") ctx.referrer = doc.referrer;
17
+ }
18
+ const nav = w.navigator;
19
+ if (typeof nav !== "undefined") ctx.language = nav.language;
20
+ const scr = w.screen;
21
+ if (typeof scr !== "undefined") ctx.screen = `${String(scr.width)}x${String(scr.height)}`;
22
+ return ctx;
23
+ }
24
+ function mergeContext(base, defaults, overrides) {
25
+ return {
26
+ ...base,
27
+ ...defaults,
28
+ ...overrides
29
+ };
30
+ }
31
+ /** Keep page paths while excluding query parameters and fragments that may identify shoppers. */
32
+ function withoutURLParameters(value) {
33
+ return value.split(/[?#]/, 1)[0] ?? "";
34
+ }
35
+ function applyContext(payload, ctx) {
36
+ if (typeof ctx.hostname !== "undefined") payload.hostname = ctx.hostname;
37
+ if (typeof ctx.language !== "undefined") payload.language = ctx.language;
38
+ if (typeof ctx.screen !== "undefined") payload.screen = ctx.screen;
39
+ if (typeof ctx.title !== "undefined") payload.title = ctx.title;
40
+ if (typeof ctx.url !== "undefined") payload.url = withoutURLParameters(ctx.url);
41
+ if (typeof ctx.referrer !== "undefined") payload.referrer = withoutURLParameters(ctx.referrer);
42
+ }
43
+ function networkError(message, details) {
44
+ return details === void 0 ? {
45
+ kind: "network",
46
+ message
47
+ } : {
48
+ kind: "network",
49
+ message,
50
+ details
51
+ };
52
+ }
53
+ /** Direct collector transport. Returns whether the request was queued, never delivery acknowledgement. */
54
+ function createFetchTrackingClient(config) {
55
+ const fetchImpl = config.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : null);
56
+ const endpoint = `${(config.baseUrl ?? "https://a.studio-vaai.com").replace(/\/$/, "")}/api/send`;
57
+ return { trackEvent: (event, options) => {
58
+ if (fetchImpl === null) return {
59
+ ok: false,
60
+ error: networkError("fetch is not available in this environment")
61
+ };
62
+ const payload = {};
63
+ applyContext(payload, mergeContext(deriveBrowserContext(), config.defaultContext, options?.context));
64
+ try {
65
+ const distinctId = typeof config.distinctId === "function" ? config.distinctId() : config.distinctId;
66
+ const body = JSON.stringify({
67
+ type: "event",
68
+ payload: {
69
+ ...payload,
70
+ name: event.name,
71
+ ...distinctId === void 0 ? {} : { id: distinctId.slice(0, 50) },
72
+ data: {
73
+ ...event.data,
74
+ "sdk-version": config.sdkVersion
75
+ }
76
+ }
77
+ });
78
+ fetchImpl(endpoint, {
79
+ method: "POST",
80
+ headers: {
81
+ "Content-Type": "application/json",
82
+ "X-Client-Api-Key": config.clientApiKey
83
+ },
84
+ credentials: "omit",
85
+ referrerPolicy: "no-referrer",
86
+ keepalive: true,
87
+ mode: "cors",
88
+ body
89
+ }).catch(() => {});
90
+ return { ok: true };
91
+ } catch (error) {
92
+ return {
93
+ ok: false,
94
+ error: networkError("Failed to queue analytics request", error)
95
+ };
96
+ }
97
+ } };
98
+ }
99
+ export { DEFAULT_COLLECTOR_BASE_URL, createFetchTrackingClient };
package/dist/index.d.ts CHANGED
@@ -5,6 +5,6 @@ export { TrackingClientNotImplementedError } from "./errors.js";
5
5
  export type { TrackingEvent, TrackingEventBase, VariantSelectionVia } from "./events.js";
6
6
  export type { ImageFlowSource } from "./image-flow-source.js";
7
7
  export type { Step } from "./steps.js";
8
- export type { FetchUmamiTrackingClientConfig, ResolvedUmamiConfig, } from "./impl/fetch-umami-tracking-client.js";
9
- export { createFetchUmamiTrackingClient, DEFAULT_UMAMI_BASE_URL, } from "./impl/fetch-umami-tracking-client.js";
8
+ export type { FetchTrackingClientConfig } from "./impl/fetch-tracking-client.js";
9
+ export { createFetchTrackingClient, DEFAULT_COLLECTOR_BASE_URL, } from "./impl/fetch-tracking-client.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,iCAAiC,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EACV,8BAA8B,EAC9B,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,uCAAuC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,iCAAiC,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EACL,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,iCAAiC,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TrackingClientNotImplementedError } from "./errors.js";
2
1
  import { SDK_PACKAGE_ID, createTrackingClient } from "./client.js";
3
- import { DEFAULT_UMAMI_BASE_URL, createFetchUmamiTrackingClient } from "./impl/fetch-umami-tracking-client.js";
4
- export { DEFAULT_UMAMI_BASE_URL, SDK_PACKAGE_ID, TrackingClientNotImplementedError, createFetchUmamiTrackingClient, createTrackingClient };
2
+ import { TrackingClientNotImplementedError } from "./errors.js";
3
+ import { DEFAULT_COLLECTOR_BASE_URL, createFetchTrackingClient } from "./impl/fetch-tracking-client.js";
4
+ export { DEFAULT_COLLECTOR_BASE_URL, SDK_PACKAGE_ID, TrackingClientNotImplementedError, createFetchTrackingClient, createTrackingClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studio-vaai/js-tracking",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "description": "Typed analytics events for studio vaai, plus a fetch-based Umami transport.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -17,7 +17,7 @@
17
17
  "access": "public"
18
18
  },
19
19
  "devDependencies": {
20
- "vite": "8.0.5"
20
+ "vite": "8.3.6"
21
21
  },
22
22
  "scripts": {
23
23
  "build": "vite build --config vite.lib.config.ts && rm -f tsconfig.tsbuildinfo && tsgo --emitDeclarationOnly",
@@ -1,64 +0,0 @@
1
- import type { EventContext } from "../base.js";
2
- import type { TrackingClient, TrackingClientConfig } from "../client.js";
3
- /** Default Umami base URL (int/prod Umami). */
4
- export declare const DEFAULT_UMAMI_BASE_URL: "https://a.studio-vaai.com";
5
- /** Per-shop Umami config the {@link FetchUmamiTrackingClientConfig.resolveConfig} resolver returns. */
6
- export interface ResolvedUmamiConfig {
7
- /** Umami website UUID for this shop. */
8
- websiteId: string;
9
- /** Optional override; defaults to {@link DEFAULT_UMAMI_BASE_URL} when omitted. */
10
- baseUrl?: string;
11
- }
12
- export interface FetchUmamiTrackingClientConfig extends TrackingClientConfig {
13
- /**
14
- * Stamped on every event as the `sdk-version` field. Higher SDK layers
15
- * (e.g. `@studio-vaai/react-components`) pass their own
16
- * `"<pkg>@<version>"` here so the analytics view shows the version of the
17
- * SDK merchants actually install — not this internal tracking package.
18
- */
19
- sdkVersion: string;
20
- /**
21
- * Static Umami website UUID. Provide this OR {@link resolveConfig}, not both.
22
- * Use the static form when the website id is known at client construction.
23
- */
24
- websiteId?: string;
25
- /** Static Umami base URL. Used together with {@link websiteId}. Defaults to {@link DEFAULT_UMAMI_BASE_URL}. */
26
- baseUrl?: string;
27
- /**
28
- * Lazy resolver for per-shop Umami config. Provide this OR {@link websiteId},
29
- * not both. Runs once when the client is constructed; events fired before
30
- * the promise settles are buffered internally and flushed (in order) the
31
- * moment the resolver returns. Buffered events have already returned
32
- * `{ ok: true }` to the caller — if the eventual flush fails (resolver
33
- * rejected or the request could not be queued) the caller is not notified.
34
- */
35
- resolveConfig?: () => Promise<ResolvedUmamiConfig>;
36
- /**
37
- * Override `fetch`. Defaults to `globalThis.fetch` bound to `globalThis` so
38
- * the native browser implementation doesn't trip on `this`-binding rules.
39
- */
40
- fetch?: typeof fetch;
41
- /**
42
- * Ambient context applied to every payload, before per-call overrides. Useful
43
- * for SSR-known fields or to pin a hostname different from `window.location`.
44
- */
45
- defaultContext?: EventContext;
46
- }
47
- /**
48
- * Umami `/api/send` transport for {@link TrackingClient}. Dispatches via
49
- * fire-and-forget `fetch` with `keepalive: true` so events survive page unload,
50
- * and `credentials: "omit"` so cross-origin Umami hosts may use
51
- * `Access-Control-Allow-Origin: *`. The return value reports whether the
52
- * request was queued, not whether the server acknowledged it. Errors are never
53
- * thrown — analytics cannot break the host app.
54
- *
55
- * Supports two configuration modes:
56
- * - **Static**: pass `websiteId` (and optionally `baseUrl`) at construction.
57
- * Events fire immediately.
58
- * - **Lazy**: pass `resolveConfig` for per-shop Umami config that's only known
59
- * asynchronously (e.g. fetched via `client.tracking.getTracking()`). Events
60
- * fired before the resolver settles are buffered in order and flushed once
61
- * the config is available.
62
- */
63
- export declare function createFetchUmamiTrackingClient(config: FetchUmamiTrackingClientConfig): TrackingClient;
64
- //# sourceMappingURL=fetch-umami-tracking-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch-umami-tracking-client.d.ts","sourceRoot":"","sources":["../../src/impl/fetch-umami-tracking-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGzE,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,EAAG,2BAAoC,CAAC;AAE3E,uGAAuG;AACvG,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,8BAA+B,SAAQ,oBAAoB;IAC1E;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+GAA+G;IAC/G,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnD;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,YAAY,CAAC;CAC/B;AAyHD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,8BAA8B,GACrC,cAAc,CAwJhB"}
@@ -1,176 +0,0 @@
1
- //#region src/impl/fetch-umami-tracking-client.ts
2
- /** Default Umami base URL (int/prod Umami). */
3
- var DEFAULT_UMAMI_BASE_URL = "https://a.studio-vaai.com";
4
- var UMAMI_FETCH_INIT = {
5
- method: "POST",
6
- headers: { "Content-Type": "application/json" },
7
- credentials: "omit",
8
- keepalive: true,
9
- mode: "cors"
10
- };
11
- function deriveBrowserContext() {
12
- const ctx = {};
13
- if (typeof globalThis === "undefined") return ctx;
14
- const w = globalThis.window;
15
- if (typeof w === "undefined") return ctx;
16
- const loc = w.location;
17
- if (typeof loc !== "undefined") {
18
- ctx.hostname = loc.hostname;
19
- ctx.url = `${loc.pathname}${loc.search}`;
20
- }
21
- const doc = w.document;
22
- if (typeof doc !== "undefined") {
23
- ctx.title = doc.title;
24
- if (doc.referrer !== "") ctx.referrer = doc.referrer;
25
- }
26
- const nav = w.navigator;
27
- if (typeof nav !== "undefined") ctx.language = nav.language;
28
- const scr = w.screen;
29
- if (typeof scr !== "undefined") ctx.screen = `${String(scr.width)}x${String(scr.height)}`;
30
- return ctx;
31
- }
32
- function mergeContext(base, defaults, overrides) {
33
- return {
34
- ...base,
35
- ...defaults,
36
- ...overrides
37
- };
38
- }
39
- function applyContext(payload, ctx) {
40
- if (typeof ctx.hostname !== "undefined") payload.hostname = ctx.hostname;
41
- if (typeof ctx.language !== "undefined") payload.language = ctx.language;
42
- if (typeof ctx.screen !== "undefined") payload.screen = ctx.screen;
43
- if (typeof ctx.title !== "undefined") payload.title = ctx.title;
44
- if (typeof ctx.url !== "undefined") payload.url = ctx.url;
45
- if (typeof ctx.referrer !== "undefined") payload.referrer = ctx.referrer;
46
- }
47
- function networkError(message, details) {
48
- return details === void 0 ? {
49
- kind: "network",
50
- message
51
- } : {
52
- kind: "network",
53
- message,
54
- details
55
- };
56
- }
57
- function bakeState(websiteId, baseUrl) {
58
- return {
59
- endpoint: `${(baseUrl ?? "https://a.studio-vaai.com").replace(/\/$/, "")}/api/send`,
60
- websiteId
61
- };
62
- }
63
- function defaultFetchImpl() {
64
- if (typeof globalThis.fetch !== "function") return null;
65
- return globalThis.fetch.bind(globalThis);
66
- }
67
- /**
68
- * Umami `/api/send` transport for {@link TrackingClient}. Dispatches via
69
- * fire-and-forget `fetch` with `keepalive: true` so events survive page unload,
70
- * and `credentials: "omit"` so cross-origin Umami hosts may use
71
- * `Access-Control-Allow-Origin: *`. The return value reports whether the
72
- * request was queued, not whether the server acknowledged it. Errors are never
73
- * thrown — analytics cannot break the host app.
74
- *
75
- * Supports two configuration modes:
76
- * - **Static**: pass `websiteId` (and optionally `baseUrl`) at construction.
77
- * Events fire immediately.
78
- * - **Lazy**: pass `resolveConfig` for per-shop Umami config that's only known
79
- * asynchronously (e.g. fetched via `client.tracking.getTracking()`). Events
80
- * fired before the resolver settles are buffered in order and flushed once
81
- * the config is available.
82
- */
83
- function createFetchUmamiTrackingClient(config) {
84
- const fetchImpl = config.fetch ?? defaultFetchImpl();
85
- let resolved = null;
86
- let resolverError = null;
87
- const pending = [];
88
- const staticWebsiteId = config.websiteId;
89
- const resolverFn = config.resolveConfig;
90
- if (staticWebsiteId === void 0 && resolverFn === void 0) throw new Error("createFetchUmamiTrackingClient: provide either `websiteId` or `resolveConfig`");
91
- if (staticWebsiteId !== void 0 && resolverFn !== void 0) throw new Error("createFetchUmamiTrackingClient: pass either `websiteId` or `resolveConfig`, not both");
92
- if (staticWebsiteId !== void 0) resolved = bakeState(staticWebsiteId, config.baseUrl);
93
- else if (resolverFn !== void 0) {
94
- if (config.baseUrl !== void 0) throw new Error("createFetchUmamiTrackingClient: `baseUrl` is set by the resolver in lazy mode — drop the static `baseUrl`");
95
- (async () => {
96
- try {
97
- const r = await resolverFn();
98
- resolved = bakeState(r.websiteId, r.baseUrl);
99
- } catch (error) {
100
- resolverError = {
101
- kind: "unknown",
102
- message: "Failed to resolve Umami tracking config",
103
- details: error
104
- };
105
- }
106
- while (pending.length > 0) {
107
- const item = pending.shift();
108
- if (item === void 0) break;
109
- if (resolved === null) continue;
110
- sendNow(resolved, item.event, item.options);
111
- }
112
- })();
113
- }
114
- function dispatchEvent(state, body) {
115
- let json;
116
- try {
117
- json = JSON.stringify(body);
118
- } catch (error) {
119
- return {
120
- ok: false,
121
- error: networkError("Failed to serialise event", error)
122
- };
123
- }
124
- if (fetchImpl === null) return {
125
- ok: false,
126
- error: networkError("fetch is not available in this environment")
127
- };
128
- try {
129
- (async () => {
130
- try {
131
- await fetchImpl(state.endpoint, {
132
- ...UMAMI_FETCH_INIT,
133
- body: json
134
- });
135
- } catch {}
136
- })();
137
- } catch (error) {
138
- return {
139
- ok: false,
140
- error: networkError("Failed to queue Umami request", error)
141
- };
142
- }
143
- return { ok: true };
144
- }
145
- function track(state, name, data, contextOverrides) {
146
- const payload = { website: state.websiteId };
147
- applyContext(payload, mergeContext(deriveBrowserContext(), config.defaultContext, contextOverrides));
148
- if (typeof name !== "undefined") payload.name = name;
149
- if (typeof data !== "undefined") payload.data = { ...data };
150
- return dispatchEvent(state, {
151
- type: "event",
152
- payload
153
- });
154
- }
155
- function sendNow(state, event, options) {
156
- const data = {
157
- ...event.data ?? {},
158
- "sdk-version": config.sdkVersion
159
- };
160
- return track(state, event.name, data, options?.context);
161
- }
162
- return { trackEvent: (event, options) => {
163
- if (resolved !== null) return sendNow(resolved, event, options);
164
- if (resolverError !== null) return {
165
- ok: false,
166
- error: resolverError
167
- };
168
- pending.push({
169
- event,
170
- options
171
- });
172
- return { ok: true };
173
- } };
174
- }
175
- //#endregion
176
- export { DEFAULT_UMAMI_BASE_URL, createFetchUmamiTrackingClient };