@askdialog/dialog-sdk 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAEL,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,qBAAa,MAAM;IACjB,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B,OAAO,CAAC,UAAU,CAGhB;IACF,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;gBAE1B,EACV,MAAM,EACN,MAAM,EACN,WAAW,EACX,SAAS,EACT,KAAK,EACL,MAAM,GACP,EAAE,iBAAiB;IAepB,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,KAAK,IAAI,KAAK,CAExB;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,aAAa,IAAI,aAAa,CAExC;IAEM,2BAA2B,IAAI,kBAAkB,GAAG,IAAI;IAI/D,OAAO,CAAC,uBAAuB;IAkBlB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAK5D,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAKjD,cAAc,IAAI,IAAI;IAItB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAIxD,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAOxD,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAIjE,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAInD,UAAU,CACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAIhB,SAAS,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBV,sBAAsB,CAAC,EAC5B,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI;IAkBD,2BAA2B,CAChC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,GAClD,IAAI;IA0BP,OAAO,CAAC,cAAc;CA4BvB"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAEL,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,qBAAa,MAAM;IACjB,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B,OAAO,CAAC,UAAU,CAGhB;IACF,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;gBAE1B,EACV,MAAM,EACN,MAAM,EACN,WAAW,EACX,SAAS,EACT,KAAK,EACL,MAAM,GACP,EAAE,iBAAiB;IAYpB,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,KAAK,IAAI,KAAK,CAExB;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,aAAa,IAAI,aAAa,CAExC;IAEM,2BAA2B,IAAI,kBAAkB,GAAG,IAAI;IAI/D,OAAO,CAAC,uBAAuB;IAkBlB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAK5D,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAKjD,cAAc,IAAI,IAAI;IAItB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAIxD,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAOxD,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAIjE,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAInD,UAAU,CACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAIhB,SAAS,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBV,sBAAsB,CAAC,EAC5B,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI;IAkBD,2BAA2B,CAChC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,GAClD,IAAI;IA0BP,OAAO,CAAC,cAAc;CA4BvB"}
package/dist/Dialog.js CHANGED
@@ -8,6 +8,7 @@ import { DialogEvents, } from "./types/events";
8
8
  import { EventsHandler } from "./EventsHandler";
9
9
  import { loadSuggestions } from "./services/suggestions";
10
10
  import { config } from "./config";
11
+ import { exposeSdkOnWindowDialog } from "./windowAudit";
11
12
  export class Dialog {
12
13
  static VERSION = packageJson.version;
13
14
  _apiKey;
@@ -25,10 +26,7 @@ export class Dialog {
25
26
  this._theme = { ...defaultTheme, ...theme };
26
27
  this._userId = this._createOrRetrieveUserId(userId);
27
28
  this._eventsHandler = new EventsHandler(locale, userId);
28
- window.dialog = {
29
- instance: this,
30
- version: Dialog.VERSION,
31
- };
29
+ exposeSdkOnWindowDialog(this, Dialog.VERSION);
32
30
  this._loadAssistant();
33
31
  }
34
32
  get apiKey() {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=windowAudit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowAudit.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/windowAudit.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,87 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { addAuditCapability, exposeSdkOnWindowDialog, registerDialogInstallation, } from "../windowAudit";
3
+ const globalWithWindow = globalThis;
4
+ const getAudit = () => globalWithWindow.window?.dialog?.audit;
5
+ const fakeInstance = { apiKey: "test" };
6
+ beforeEach(() => {
7
+ globalWithWindow.window = {};
8
+ });
9
+ afterEach(() => {
10
+ delete globalWithWindow.window;
11
+ vi.clearAllMocks();
12
+ });
13
+ describe("exposeSdkOnWindowDialog", () => {
14
+ it("exposes instance and version when window.dialog is absent", () => {
15
+ exposeSdkOnWindowDialog(fakeInstance, "2.1.0");
16
+ const dialog = globalWithWindow.window?.dialog;
17
+ expect(dialog?.instance).toBe(fakeInstance);
18
+ expect(dialog?.version).toBe("2.1.0");
19
+ expect(getAudit()?.methods[0]).toMatchObject({
20
+ method: "sdk",
21
+ version: "2.1.0",
22
+ });
23
+ });
24
+ it("preserves keys owned by GTM (setVariant/getVariant/_queue)", () => {
25
+ const setVariant = vi.fn();
26
+ const getVariant = vi.fn();
27
+ const queue = [["setVariant", { variantId: "VAR_1" }]];
28
+ globalWithWindow.window = {
29
+ dialog: { setVariant, getVariant, _queue: queue },
30
+ };
31
+ exposeSdkOnWindowDialog(fakeInstance, "2.1.0");
32
+ const dialog = globalWithWindow.window.dialog;
33
+ expect(dialog?.setVariant).toBe(setVariant);
34
+ expect(dialog?.getVariant).toBe(getVariant);
35
+ expect(dialog?._queue).toBe(queue);
36
+ expect(dialog?.instance).toBe(fakeInstance);
37
+ expect(getAudit()?.methods[0]).toMatchObject({
38
+ method: "sdk",
39
+ version: "2.1.0",
40
+ });
41
+ });
42
+ it("preserves audit entries registered by another path and warns on coexistence", () => {
43
+ registerDialogInstallation({ method: "gtm", source: "dialog-instant.js" });
44
+ exposeSdkOnWindowDialog(fakeInstance, "2.1.0");
45
+ const audit = getAudit();
46
+ expect(audit?.methods.map((entry) => entry.method)).toEqual(["gtm", "sdk"]);
47
+ expect(audit?.warnings).toEqual([
48
+ "multiple installation methods detected: gtm, sdk",
49
+ ]);
50
+ });
51
+ it("does not duplicate the sdk entry when instantiated twice", () => {
52
+ exposeSdkOnWindowDialog(fakeInstance, "2.1.0");
53
+ exposeSdkOnWindowDialog(fakeInstance, "2.1.0");
54
+ expect(getAudit()?.methods).toHaveLength(1);
55
+ });
56
+ it("is a no-op without a window (SSR safety)", () => {
57
+ delete globalWithWindow.window;
58
+ expect(() => exposeSdkOnWindowDialog(fakeInstance, "2.1.0")).not.toThrow();
59
+ expect(() => addAuditCapability("pdp-block")).not.toThrow();
60
+ });
61
+ });
62
+ describe("registerDialogInstallation", () => {
63
+ it("only fills missing fields on re-registration of the same method", () => {
64
+ registerDialogInstallation({ method: "react", version: "2.0.2" });
65
+ registerDialogInstallation({ method: "react", version: "9.9.9" });
66
+ expect(getAudit()?.methods).toHaveLength(1);
67
+ expect(getAudit()?.methods[0]?.version).toBe("2.0.2");
68
+ });
69
+ it("fills missing nested build fields without erasing existing ones", () => {
70
+ registerDialogInstallation({ method: "gtm", build: { commit: "abc1234" } });
71
+ registerDialogInstallation({
72
+ method: "gtm",
73
+ build: { commit: "fff9999", version: "1.2.3" },
74
+ });
75
+ expect(getAudit()?.methods[0]?.build).toEqual({
76
+ commit: "abc1234",
77
+ version: "1.2.3",
78
+ });
79
+ });
80
+ });
81
+ describe("addAuditCapability", () => {
82
+ it("adds capabilities without duplicates", () => {
83
+ addAuditCapability("pdp-block");
84
+ addAuditCapability("pdp-block");
85
+ expect(getAudit()?.capabilities).toEqual(["pdp-block"]);
86
+ });
87
+ });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./Dialog";
2
2
  export * from "./EventsHandler";
3
3
  export * from "./types";
4
+ export * from "./windowAudit";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./Dialog";
2
2
  export * from "./EventsHandler";
3
3
  export * from "./types";
4
+ export * from "./windowAudit";
@@ -1,10 +1,12 @@
1
1
  import { Dialog } from "../Dialog";
2
+ import { DialogAudit } from "../windowAudit";
2
3
  declare global {
3
4
  interface Window {
4
5
  dialog?: {
5
6
  instance?: Dialog;
6
7
  version?: string;
7
- };
8
+ audit?: DialogAudit;
9
+ } & Record<string, unknown>;
8
10
  }
9
11
  }
10
12
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../../src/types/global.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH;CACF;AAED,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../../src/types/global.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QAGd,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,KAAK,CAAC,EAAE,WAAW,CAAC;SACrB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC7B;CACF;AAED,OAAO,EAAE,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { Dialog } from "./Dialog";
2
+ /**
3
+ * Miniature copy of the window.dialog.audit merge helper — canonical source:
4
+ * dialog-ecom/packages/lib-dialog-window (contract: dialogAuditSchema in
5
+ * dialog-ecom's @dialog/shared-schemas). Kept in sync by hand: the surface is
6
+ * public and additive-only — never overwrite keys owned by other installation
7
+ * paths (GTM setVariant/getVariant/_queue, widget audit entries).
8
+ */
9
+ export type DialogInstallationMethod = "shopify-extension" | "gtm" | "sdk" | "react" | "vue" | "prestashop";
10
+ export type DialogAuditCapability = "setVariant" | "assistant-modal" | "assistant-bar" | "pdp-block";
11
+ export interface DialogAuditMethodEntry {
12
+ method: DialogInstallationMethod;
13
+ version?: string;
14
+ build?: {
15
+ version?: string;
16
+ commit?: string;
17
+ };
18
+ source?: string;
19
+ registeredAt: string;
20
+ }
21
+ export interface DialogAudit {
22
+ methods: DialogAuditMethodEntry[];
23
+ context: {
24
+ hostname?: string;
25
+ platform?: string;
26
+ organizationSlug?: string;
27
+ };
28
+ capabilities: DialogAuditCapability[];
29
+ consent?: unknown;
30
+ warnings: string[];
31
+ }
32
+ export type DialogInstallationEntryInput = Omit<DialogAuditMethodEntry, "registeredAt">;
33
+ export declare const registerDialogInstallation: (entry: DialogInstallationEntryInput) => void;
34
+ export declare const addAuditCapability: (capability: DialogAuditCapability) => void;
35
+ /**
36
+ * Exposes the SDK on window.dialog without erasing fields owned by other
37
+ * installation paths (e.g. GTM's setVariant/getVariant), then registers the
38
+ * sdk entry in window.dialog.audit.
39
+ */
40
+ export declare const exposeSdkOnWindowDialog: (instance: Dialog, version: string) => void;
41
+ //# sourceMappingURL=windowAudit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowAudit.d.ts","sourceRoot":"","sources":["../src/windowAudit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAChC,mBAAmB,GACnB,KAAK,GACL,KAAK,GACL,OAAO,GACP,KAAK,GACL,YAAY,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAC7B,YAAY,GACZ,iBAAiB,GACjB,eAAe,GACf,WAAW,CAAC;AAEhB,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,wBAAwB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,OAAO,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAC7C,sBAAsB,EACtB,cAAc,CACf,CAAC;AAwDF,eAAO,MAAM,0BAA0B,GACrC,OAAO,4BAA4B,KAClC,IAmBF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,YAAY,qBAAqB,KAAG,IAQtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,EAChB,SAAS,MAAM,KACd,IAUF,CAAC"}
@@ -0,0 +1,78 @@
1
+ const MULTIPLE_METHODS_WARNING_PREFIX = "multiple installation methods detected:";
2
+ const getHost = () => typeof window === "undefined"
3
+ ? undefined
4
+ : window;
5
+ const ensureAudit = () => {
6
+ const host = getHost();
7
+ if (host === undefined) {
8
+ return undefined;
9
+ }
10
+ host.dialog = host.dialog ?? {};
11
+ host.dialog.audit = host.dialog.audit ?? {
12
+ methods: [],
13
+ context: {},
14
+ capabilities: [],
15
+ warnings: [],
16
+ };
17
+ return host.dialog.audit;
18
+ };
19
+ const refreshCoexistenceWarning = (audit) => {
20
+ audit.warnings = audit.warnings.filter((warning) => !warning.startsWith(MULTIPLE_METHODS_WARNING_PREFIX));
21
+ if (audit.methods.length >= 2) {
22
+ const methods = audit.methods.map((entry) => entry.method).join(", ");
23
+ audit.warnings.push(`${MULTIPLE_METHODS_WARNING_PREFIX} ${methods}`);
24
+ }
25
+ };
26
+ // First write wins per nested field: an existing partial build (e.g. commit
27
+ // only) never blocks a later registration from filling the missing fields.
28
+ const mergeBuildFields = (existing, entry) => {
29
+ if (entry === undefined) {
30
+ return existing;
31
+ }
32
+ return {
33
+ version: existing?.version ?? entry.version,
34
+ commit: existing?.commit ?? entry.commit,
35
+ };
36
+ };
37
+ export const registerDialogInstallation = (entry) => {
38
+ const audit = ensureAudit();
39
+ if (audit === undefined) {
40
+ return;
41
+ }
42
+ const existing = audit.methods.find((candidate) => candidate.method === entry.method);
43
+ if (existing === undefined) {
44
+ audit.methods.push({ ...entry, registeredAt: new Date().toISOString() });
45
+ refreshCoexistenceWarning(audit);
46
+ return;
47
+ }
48
+ // First write wins per field: a later registration only fills gaps and
49
+ // never erases what another script recorded.
50
+ existing.version = existing.version ?? entry.version;
51
+ existing.build = mergeBuildFields(existing.build, entry.build);
52
+ existing.source = existing.source ?? entry.source;
53
+ };
54
+ export const addAuditCapability = (capability) => {
55
+ const audit = ensureAudit();
56
+ if (audit === undefined) {
57
+ return;
58
+ }
59
+ if (!audit.capabilities.includes(capability)) {
60
+ audit.capabilities.push(capability);
61
+ }
62
+ };
63
+ /**
64
+ * Exposes the SDK on window.dialog without erasing fields owned by other
65
+ * installation paths (e.g. GTM's setVariant/getVariant), then registers the
66
+ * sdk entry in window.dialog.audit.
67
+ */
68
+ export const exposeSdkOnWindowDialog = (instance, version) => {
69
+ if (typeof window === "undefined") {
70
+ return;
71
+ }
72
+ window.dialog = {
73
+ ...window.dialog,
74
+ instance,
75
+ version,
76
+ };
77
+ registerDialogInstallation({ method: "sdk", version });
78
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askdialog/dialog-sdk",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "private": false,
5
5
  "description": "Dialog SDK",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,8 @@
28
28
  "devDependencies": {
29
29
  "esbuild": "^0.25.12",
30
30
  "eslint-import-resolver-typescript": "^4.4.4",
31
- "eslint-plugin-import": "^2.32.0"
31
+ "eslint-plugin-import": "^2.32.0",
32
+ "vitest": "^3.0.0"
32
33
  },
33
34
  "publishConfig": {
34
35
  "access": "public"
@@ -44,6 +45,7 @@
44
45
  "build:prod": "pnpm run clean && pnpm run set-config production && tsc",
45
46
  "lint": "eslint .",
46
47
  "lint:fix": "eslint . --fix",
48
+ "test": "vitest run",
47
49
  "test-type": "tsc --noEmit",
48
50
  "link": "pnpm link --global",
49
51
  "unlink": "pnpm unlink",