tracklane 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/conformance.d.ts +61 -0
- package/dist/conformance.js +153 -0
- package/dist/conformance.js.map +1 -0
- package/package.json +13 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { m as ServerProvider, p as ResolvedContext, t as BrowserProvider } from "./browser-CddkJdvX.js";
|
|
2
|
+
//#region src/conformance.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Runs the shared conformance suite against a browser provider.
|
|
5
|
+
*
|
|
6
|
+
* @param create - Builds the provider under test. Called per assertion, so a
|
|
7
|
+
* provider that accumulates state between runs fails rather than hides.
|
|
8
|
+
* @param captured - Everything the provider handed the vendor since the last
|
|
9
|
+
* reset, in order.
|
|
10
|
+
* @param reset - Clears what `captured` returns.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* describe('ga4 browser conformance', () => {
|
|
15
|
+
* conformsAsBrowserProvider({
|
|
16
|
+
* create: () => ga4('G-ABC'),
|
|
17
|
+
* captured: () => calls,
|
|
18
|
+
* reset: () => { calls = []; },
|
|
19
|
+
* });
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function conformsAsBrowserProvider(options: {
|
|
24
|
+
create: () => BrowserProvider;
|
|
25
|
+
captured: () => unknown[];
|
|
26
|
+
reset: () => void;
|
|
27
|
+
}): void;
|
|
28
|
+
/**
|
|
29
|
+
* Runs the shared conformance suite against a server provider.
|
|
30
|
+
*
|
|
31
|
+
* @param create - Builds the provider under test, per assertion.
|
|
32
|
+
* @param captured - Everything the provider sent since the last reset.
|
|
33
|
+
* @param reset - Clears what `captured` returns, and restores a successful
|
|
34
|
+
* transport.
|
|
35
|
+
* @param fail - Makes the next send fail at the transport, so the suite can
|
|
36
|
+
* check that the provider is loud about it.
|
|
37
|
+
* @param context - A resolved context with a fixed timestamp.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* describe('ga4 server conformance', () => {
|
|
42
|
+
* conformsAsServerProvider({
|
|
43
|
+
* create: () => ga4(credentials),
|
|
44
|
+
* captured: () => fetchMock.mock.calls,
|
|
45
|
+
* reset: () => { fetchMock.mockClear(); },
|
|
46
|
+
* fail: () => { fetchMock.mockResolvedValueOnce(new Response(null, { status: 500 })); },
|
|
47
|
+
* context,
|
|
48
|
+
* });
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function conformsAsServerProvider(options: {
|
|
53
|
+
create: () => ServerProvider;
|
|
54
|
+
captured: () => unknown[];
|
|
55
|
+
reset: () => void;
|
|
56
|
+
fail: () => void;
|
|
57
|
+
context: () => ResolvedContext;
|
|
58
|
+
}): void;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { conformsAsBrowserProvider, conformsAsServerProvider };
|
|
61
|
+
//# sourceMappingURL=conformance.d.ts.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { expect, it } from "vitest";
|
|
2
|
+
//#region src/conformance.ts
|
|
3
|
+
/**
|
|
4
|
+
* The behaviour every provider owes, which the types cannot express.
|
|
5
|
+
*
|
|
6
|
+
* ADR-0004 requires this suite because a provider can satisfy
|
|
7
|
+
* {@link BrowserProvider} or {@link ServerProvider} perfectly and still break
|
|
8
|
+
* a rule the whole library rests on. The interface cannot say "never invent an
|
|
9
|
+
* identifier" or "never expand a consent signal"; a test can.
|
|
10
|
+
*
|
|
11
|
+
* These are invariants, not vendor behaviour. What GA4 sends and how it spells
|
|
12
|
+
* it belongs in the GA4 tests. What follows must hold for a provider written
|
|
13
|
+
* by anyone, for a vendor nobody here has heard of.
|
|
14
|
+
*
|
|
15
|
+
* **Published as `tracklane/conformance`**, because the claim that a provider
|
|
16
|
+
* written elsewhere uses the same contract as the ones shipped here is only
|
|
17
|
+
* true if it can run the same checks. `vitest` is an optional peer: import this
|
|
18
|
+
* from a test file and call one of the two functions below inside a `describe`.
|
|
19
|
+
*
|
|
20
|
+
* **A wrapper owes the same invariants as a provider.** Wrapping a shipped
|
|
21
|
+
* provider and delegating (see the provider documentation) produces an object
|
|
22
|
+
* that the dispatcher cannot tell apart from any other, so run it through here
|
|
23
|
+
* too. On the server half that catches the expensive mistake: a wrapper whose
|
|
24
|
+
* `track` does not `await` the provider it delegates to resolves before the
|
|
25
|
+
* request settles, which a serverless runtime turns into a conversion that
|
|
26
|
+
* never left. {@link conformsAsServerProvider} fails on it, because a vendor
|
|
27
|
+
* refusal can no longer reach the caller.
|
|
28
|
+
*/
|
|
29
|
+
const DEFAULTS = ["passthrough", "ignore"];
|
|
30
|
+
/** A payload with nothing in it that could excuse a difference between runs. */
|
|
31
|
+
const STABLE_DATA = {
|
|
32
|
+
transaction_id: "T-1",
|
|
33
|
+
value: 49.9,
|
|
34
|
+
currency: "BRL"
|
|
35
|
+
};
|
|
36
|
+
function assertIdentity(provider) {
|
|
37
|
+
it("names itself, once and stably", () => {
|
|
38
|
+
expect(provider.name).toBeTruthy();
|
|
39
|
+
expect(provider.name.trim()).toBe(provider.name);
|
|
40
|
+
});
|
|
41
|
+
it("declares what happens to an event it has no binding for", () => {
|
|
42
|
+
expect(DEFAULTS).toContain(provider.default);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Runs the shared conformance suite against a browser provider.
|
|
47
|
+
*
|
|
48
|
+
* @param create - Builds the provider under test. Called per assertion, so a
|
|
49
|
+
* provider that accumulates state between runs fails rather than hides.
|
|
50
|
+
* @param captured - Everything the provider handed the vendor since the last
|
|
51
|
+
* reset, in order.
|
|
52
|
+
* @param reset - Clears what `captured` returns.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* describe('ga4 browser conformance', () => {
|
|
57
|
+
* conformsAsBrowserProvider({
|
|
58
|
+
* create: () => ga4('G-ABC'),
|
|
59
|
+
* captured: () => calls,
|
|
60
|
+
* reset: () => { calls = []; },
|
|
61
|
+
* });
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function conformsAsBrowserProvider(options) {
|
|
66
|
+
const { create, captured, reset } = options;
|
|
67
|
+
assertIdentity(create());
|
|
68
|
+
it("sends the same thing twice for the same event", () => {
|
|
69
|
+
reset();
|
|
70
|
+
create().track("purchase", STABLE_DATA, {});
|
|
71
|
+
const first = JSON.stringify(captured());
|
|
72
|
+
reset();
|
|
73
|
+
create().track("purchase", STABLE_DATA, {});
|
|
74
|
+
const second = JSON.stringify(captured());
|
|
75
|
+
expect(second).toBe(first);
|
|
76
|
+
});
|
|
77
|
+
it("forwards the deduplication id only when it was given one", () => {
|
|
78
|
+
reset();
|
|
79
|
+
create().track("purchase", STABLE_DATA, {});
|
|
80
|
+
const without = JSON.stringify(captured());
|
|
81
|
+
reset();
|
|
82
|
+
create().track("purchase", STABLE_DATA, { dedupId: "DEDUP-XYZ" });
|
|
83
|
+
const with_ = JSON.stringify(captured());
|
|
84
|
+
if (with_ !== without) expect(with_).toContain("DEDUP-XYZ");
|
|
85
|
+
expect(without).not.toContain("DEDUP-XYZ");
|
|
86
|
+
});
|
|
87
|
+
it("never expands a consent signal it was not given", () => {
|
|
88
|
+
const provider = create();
|
|
89
|
+
if (!provider.consent) return;
|
|
90
|
+
reset();
|
|
91
|
+
provider.consent("update", { analytics_storage: "denied" });
|
|
92
|
+
expect(JSON.stringify(captured())).not.toContain("granted");
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Runs the shared conformance suite against a server provider.
|
|
97
|
+
*
|
|
98
|
+
* @param create - Builds the provider under test, per assertion.
|
|
99
|
+
* @param captured - Everything the provider sent since the last reset.
|
|
100
|
+
* @param reset - Clears what `captured` returns, and restores a successful
|
|
101
|
+
* transport.
|
|
102
|
+
* @param fail - Makes the next send fail at the transport, so the suite can
|
|
103
|
+
* check that the provider is loud about it.
|
|
104
|
+
* @param context - A resolved context with a fixed timestamp.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* describe('ga4 server conformance', () => {
|
|
109
|
+
* conformsAsServerProvider({
|
|
110
|
+
* create: () => ga4(credentials),
|
|
111
|
+
* captured: () => fetchMock.mock.calls,
|
|
112
|
+
* reset: () => { fetchMock.mockClear(); },
|
|
113
|
+
* fail: () => { fetchMock.mockResolvedValueOnce(new Response(null, { status: 500 })); },
|
|
114
|
+
* context,
|
|
115
|
+
* });
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
function conformsAsServerProvider(options) {
|
|
120
|
+
const { create, captured, reset, fail, context } = options;
|
|
121
|
+
const noop = () => {};
|
|
122
|
+
assertIdentity(create());
|
|
123
|
+
it("sends the same thing twice for the same event", async () => {
|
|
124
|
+
reset();
|
|
125
|
+
await create().track("purchase", STABLE_DATA, context(), noop);
|
|
126
|
+
const first = JSON.stringify(captured());
|
|
127
|
+
reset();
|
|
128
|
+
await create().track("purchase", STABLE_DATA, context(), noop);
|
|
129
|
+
expect(JSON.stringify(captured())).toBe(first);
|
|
130
|
+
});
|
|
131
|
+
it("forwards the deduplication id only when it was given one", async () => {
|
|
132
|
+
reset();
|
|
133
|
+
await create().track("purchase", STABLE_DATA, context(), noop);
|
|
134
|
+
const without = JSON.stringify(captured());
|
|
135
|
+
reset();
|
|
136
|
+
await create().track("purchase", STABLE_DATA, {
|
|
137
|
+
...context(),
|
|
138
|
+
dedupId: "DEDUP-XYZ"
|
|
139
|
+
}, noop);
|
|
140
|
+
const with_ = JSON.stringify(captured());
|
|
141
|
+
if (with_ !== without) expect(with_).toContain("DEDUP-XYZ");
|
|
142
|
+
expect(without).not.toContain("DEDUP-XYZ");
|
|
143
|
+
});
|
|
144
|
+
it("throws when the vendor did not accept the send", async () => {
|
|
145
|
+
reset();
|
|
146
|
+
fail();
|
|
147
|
+
await expect(create().track("purchase", STABLE_DATA, context(), noop)).rejects.toThrow();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
export { conformsAsBrowserProvider, conformsAsServerProvider };
|
|
152
|
+
|
|
153
|
+
//# sourceMappingURL=conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.js","names":[],"sources":["../src/conformance.ts"],"sourcesContent":["import { expect, it } from 'vitest';\nimport type { BrowserProvider } from './browser.js';\nimport type { ResolvedContext, ServerProvider } from './server.js';\nimport type { EventData, ProviderDefault } from './vocabulary.js';\n\n/**\n * The behaviour every provider owes, which the types cannot express.\n *\n * ADR-0004 requires this suite because a provider can satisfy\n * {@link BrowserProvider} or {@link ServerProvider} perfectly and still break\n * a rule the whole library rests on. The interface cannot say \"never invent an\n * identifier\" or \"never expand a consent signal\"; a test can.\n *\n * These are invariants, not vendor behaviour. What GA4 sends and how it spells\n * it belongs in the GA4 tests. What follows must hold for a provider written\n * by anyone, for a vendor nobody here has heard of.\n *\n * **Published as `tracklane/conformance`**, because the claim that a provider\n * written elsewhere uses the same contract as the ones shipped here is only\n * true if it can run the same checks. `vitest` is an optional peer: import this\n * from a test file and call one of the two functions below inside a `describe`.\n *\n * **A wrapper owes the same invariants as a provider.** Wrapping a shipped\n * provider and delegating (see the provider documentation) produces an object\n * that the dispatcher cannot tell apart from any other, so run it through here\n * too. On the server half that catches the expensive mistake: a wrapper whose\n * `track` does not `await` the provider it delegates to resolves before the\n * request settles, which a serverless runtime turns into a conversion that\n * never left. {@link conformsAsServerProvider} fails on it, because a vendor\n * refusal can no longer reach the caller.\n */\n\nconst DEFAULTS: ProviderDefault[] = ['passthrough', 'ignore'];\n\n/** A payload with nothing in it that could excuse a difference between runs. */\nconst STABLE_DATA: EventData = { transaction_id: 'T-1', value: 49.9, currency: 'BRL' };\n\nfunction assertIdentity(provider: { name: string; default: ProviderDefault }): void {\n it('names itself, once and stably', () => {\n // The name is what a duplicate registration is detected by, and what an\n // error report is attributed to.\n expect(provider.name).toBeTruthy();\n expect(provider.name.trim()).toBe(provider.name);\n });\n\n it('declares what happens to an event it has no binding for', () => {\n expect(DEFAULTS).toContain(provider.default);\n });\n}\n\n/**\n * Runs the shared conformance suite against a browser provider.\n *\n * @param create - Builds the provider under test. Called per assertion, so a\n * provider that accumulates state between runs fails rather than hides.\n * @param captured - Everything the provider handed the vendor since the last\n * reset, in order.\n * @param reset - Clears what `captured` returns.\n *\n * @example\n * ```ts\n * describe('ga4 browser conformance', () => {\n * conformsAsBrowserProvider({\n * create: () => ga4('G-ABC'),\n * captured: () => calls,\n * reset: () => { calls = []; },\n * });\n * });\n * ```\n */\nexport function conformsAsBrowserProvider(options: {\n create: () => BrowserProvider;\n captured: () => unknown[];\n reset: () => void;\n}): void {\n const { create, captured, reset } = options;\n\n assertIdentity(create());\n\n it('sends the same thing twice for the same event', () => {\n // The library never invents an identifier, and this is how that rule is\n // caught rather than trusted: a generated id, a random value or a clock\n // read makes two identical calls differ.\n reset();\n create().track('purchase', STABLE_DATA, {});\n const first = JSON.stringify(captured());\n\n reset();\n create().track('purchase', STABLE_DATA, {});\n const second = JSON.stringify(captured());\n\n expect(second).toBe(first);\n });\n\n it('forwards the deduplication id only when it was given one', () => {\n reset();\n create().track('purchase', STABLE_DATA, {});\n const without = JSON.stringify(captured());\n\n reset();\n create().track('purchase', STABLE_DATA, { dedupId: 'DEDUP-XYZ' });\n const with_ = JSON.stringify(captured());\n\n // Either the vendor has the concept, and the value appears where it did\n // not before, or it has none and nothing changes. Inventing one to fill\n // the slot is the failure this catches.\n if (with_ !== without) expect(with_).toContain('DEDUP-XYZ');\n expect(without).not.toContain('DEDUP-XYZ');\n });\n\n it('never expands a consent signal it was not given', () => {\n const provider = create();\n if (!provider.consent) return;\n\n reset();\n provider.consent('update', { analytics_storage: 'denied' });\n\n // One denial in must never become a grant out. Collapsing Google's\n // vocabulary for a coarser vendor is translation; widening it invents a\n // permission the visitor never gave.\n expect(JSON.stringify(captured())).not.toContain('granted');\n });\n}\n\n/**\n * Runs the shared conformance suite against a server provider.\n *\n * @param create - Builds the provider under test, per assertion.\n * @param captured - Everything the provider sent since the last reset.\n * @param reset - Clears what `captured` returns, and restores a successful\n * transport.\n * @param fail - Makes the next send fail at the transport, so the suite can\n * check that the provider is loud about it.\n * @param context - A resolved context with a fixed timestamp.\n *\n * @example\n * ```ts\n * describe('ga4 server conformance', () => {\n * conformsAsServerProvider({\n * create: () => ga4(credentials),\n * captured: () => fetchMock.mock.calls,\n * reset: () => { fetchMock.mockClear(); },\n * fail: () => { fetchMock.mockResolvedValueOnce(new Response(null, { status: 500 })); },\n * context,\n * });\n * });\n * ```\n */\nexport function conformsAsServerProvider(options: {\n create: () => ServerProvider;\n captured: () => unknown[];\n reset: () => void;\n fail: () => void;\n context: () => ResolvedContext;\n}): void {\n const { create, captured, reset, fail, context } = options;\n const noop = (): void => {};\n\n assertIdentity(create());\n\n it('sends the same thing twice for the same event', async () => {\n // The context carries a fixed timestamp, so any difference between these\n // two is something the provider produced on its own.\n reset();\n await create().track('purchase', STABLE_DATA, context(), noop);\n const first = JSON.stringify(captured());\n\n reset();\n await create().track('purchase', STABLE_DATA, context(), noop);\n\n expect(JSON.stringify(captured())).toBe(first);\n });\n\n it('forwards the deduplication id only when it was given one', async () => {\n reset();\n await create().track('purchase', STABLE_DATA, context(), noop);\n const without = JSON.stringify(captured());\n\n reset();\n await create().track('purchase', STABLE_DATA, { ...context(), dedupId: 'DEDUP-XYZ' }, noop);\n const with_ = JSON.stringify(captured());\n\n if (with_ !== without) expect(with_).toContain('DEDUP-XYZ');\n expect(without).not.toContain('DEDUP-XYZ');\n });\n\n it('throws when the vendor did not accept the send', async () => {\n // Adapters stay honest and loud. Swallowing a non-2xx is how a host ends\n // up believing it is measuring something, and the dispatcher is already\n // there to isolate the throw and report it.\n reset();\n fail();\n\n await expect(create().track('purchase', STABLE_DATA, context(), noop)).rejects.toThrow();\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,WAA8B,CAAC,eAAe,QAAQ;;AAG5D,MAAM,cAAyB;CAAE,gBAAgB;CAAO,OAAO;CAAM,UAAU;AAAM;AAErF,SAAS,eAAe,UAA4D;CAClF,GAAG,uCAAuC;EAGxC,OAAO,SAAS,IAAI,CAAC,CAAC,WAAW;EACjC,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI;CACjD,CAAC;CAED,GAAG,iEAAiE;EAClE,OAAO,QAAQ,CAAC,CAAC,UAAU,SAAS,OAAO;CAC7C,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,0BAA0B,SAIjC;CACP,MAAM,EAAE,QAAQ,UAAU,UAAU;CAEpC,eAAe,OAAO,CAAC;CAEvB,GAAG,uDAAuD;EAIxD,MAAM;EACN,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,CAAC,CAAC;EAC1C,MAAM,QAAQ,KAAK,UAAU,SAAS,CAAC;EAEvC,MAAM;EACN,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,CAAC,CAAC;EAC1C,MAAM,SAAS,KAAK,UAAU,SAAS,CAAC;EAExC,OAAO,MAAM,CAAC,CAAC,KAAK,KAAK;CAC3B,CAAC;CAED,GAAG,kEAAkE;EACnE,MAAM;EACN,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,CAAC,CAAC;EAC1C,MAAM,UAAU,KAAK,UAAU,SAAS,CAAC;EAEzC,MAAM;EACN,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,EAAE,SAAS,YAAY,CAAC;EAChE,MAAM,QAAQ,KAAK,UAAU,SAAS,CAAC;EAKvC,IAAI,UAAU,SAAS,OAAO,KAAK,CAAC,CAAC,UAAU,WAAW;EAC1D,OAAO,OAAO,CAAC,CAAC,IAAI,UAAU,WAAW;CAC3C,CAAC;CAED,GAAG,yDAAyD;EAC1D,MAAM,WAAW,OAAO;EACxB,IAAI,CAAC,SAAS,SAAS;EAEvB,MAAM;EACN,SAAS,QAAQ,UAAU,EAAE,mBAAmB,SAAS,CAAC;EAK1D,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,SAAS;CAC5D,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,yBAAyB,SAMhC;CACP,MAAM,EAAE,QAAQ,UAAU,OAAO,MAAM,YAAY;CACnD,MAAM,aAAmB,CAAC;CAE1B,eAAe,OAAO,CAAC;CAEvB,GAAG,iDAAiD,YAAY;EAG9D,MAAM;EACN,MAAM,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,QAAQ,GAAG,IAAI;EAC7D,MAAM,QAAQ,KAAK,UAAU,SAAS,CAAC;EAEvC,MAAM;EACN,MAAM,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,QAAQ,GAAG,IAAI;EAE7D,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK;CAC/C,CAAC;CAED,GAAG,4DAA4D,YAAY;EACzE,MAAM;EACN,MAAM,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,QAAQ,GAAG,IAAI;EAC7D,MAAM,UAAU,KAAK,UAAU,SAAS,CAAC;EAEzC,MAAM;EACN,MAAM,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa;GAAE,GAAG,QAAQ;GAAG,SAAS;EAAY,GAAG,IAAI;EAC1F,MAAM,QAAQ,KAAK,UAAU,SAAS,CAAC;EAEvC,IAAI,UAAU,SAAS,OAAO,KAAK,CAAC,CAAC,UAAU,WAAW;EAC1D,OAAO,OAAO,CAAC,CAAC,IAAI,UAAU,WAAW;CAC3C,CAAC;CAED,GAAG,kDAAkD,YAAY;EAI/D,MAAM;EACN,KAAK;EAEL,MAAM,OAAO,OAAO,CAAC,CAAC,MAAM,YAAY,aAAa,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,QAAQ;CACzF,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tracklane",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "One interface between your application and every tool that receives events, for the browser and server. GA4, Meta and PostHog today; LinkedIn and X next.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"analytics",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"types": "./dist/server.d.ts",
|
|
40
40
|
"default": "./dist/server.js"
|
|
41
41
|
},
|
|
42
|
+
"./conformance": {
|
|
43
|
+
"types": "./dist/conformance.d.ts",
|
|
44
|
+
"default": "./dist/conformance.js"
|
|
45
|
+
},
|
|
42
46
|
"./package.json": "./package.json"
|
|
43
47
|
},
|
|
44
48
|
"files": [
|
|
@@ -60,6 +64,14 @@
|
|
|
60
64
|
"typescript": "^6.0.3",
|
|
61
65
|
"vitest": "4.1.10"
|
|
62
66
|
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"vitest": ">=3"
|
|
69
|
+
},
|
|
70
|
+
"peerDependenciesMeta": {
|
|
71
|
+
"vitest": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
63
75
|
"scripts": {
|
|
64
76
|
"build": "tsdown",
|
|
65
77
|
"dev": "tsdown --watch",
|