@toyz/loom-analytics 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # @toyz/loom-analytics
2
+
3
+ Zero-dependency, transport-swappable analytics for [Loom](https://github.com/Toyz/loom). Decorator-driven event tracking.
4
+
5
+ ```
6
+ npm install @toyz/loom-analytics
7
+ ```
8
+
9
+ **One dependency:** `@toyz/loom`. That's it.
10
+
11
+ ---
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Register a Transport
16
+
17
+ ```ts
18
+ import { app } from "@toyz/loom";
19
+ import { AnalyticsTransport } from "@toyz/loom-analytics";
20
+
21
+ class PostHogTransport extends AnalyticsTransport {
22
+ track(event: string, meta?: Record<string, any>): void {
23
+ posthog.capture(event, meta);
24
+ }
25
+ }
26
+
27
+ app.use(AnalyticsTransport, new PostHogTransport());
28
+ ```
29
+
30
+ ### 2. Track Events
31
+
32
+ One decorator, three targets:
33
+
34
+ ```ts
35
+ import { track } from "@toyz/loom-analytics";
36
+
37
+ // Track page views — fires on mount
38
+ @track("page.dashboard", { section: "main" })
39
+ class Dashboard extends LoomElement {
40
+ // Track actions — fires after method call
41
+ @track("button.save")
42
+ handleSave() {
43
+ // ...
44
+ }
45
+
46
+ // Track state changes — fires on set
47
+ @track("theme.change")
48
+ accessor theme = "dark";
49
+ }
50
+ ```
51
+
52
+ ---
53
+
54
+ ## API
55
+
56
+ ### `@track(event, meta?)`
57
+
58
+ Multi-kind decorator for event tracking. Works on classes, methods, and accessors.
59
+
60
+ | Target | When it fires | Auto metadata |
61
+ | -------- | ----------------------- | ----------------------------- |
62
+ | Class | `connectedCallback` | `{ element: "tag-name" }` |
63
+ | Method | After method invocation | `{ method: "name", args }` |
64
+ | Accessor | On set | `{ property: "name", value }` |
65
+
66
+ ### `AnalyticsTransport`
67
+
68
+ Abstract class — implement to send events to any backend.
69
+
70
+ ```ts
71
+ abstract class AnalyticsTransport {
72
+ abstract track(event: string, meta?: Record<string, any>): void;
73
+ }
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Custom Transports
79
+
80
+ Swap backends with one DI line:
81
+
82
+ ```ts
83
+ // Google Analytics
84
+ class GATransport extends AnalyticsTransport {
85
+ track(event: string, meta?: Record<string, any>): void {
86
+ gtag("event", event, meta);
87
+ }
88
+ }
89
+
90
+ // Console (dev mode)
91
+ class ConsoleTransport extends AnalyticsTransport {
92
+ track(event: string, meta?: Record<string, any>): void {
93
+ console.log(`[analytics] ${event}`, meta);
94
+ }
95
+ }
96
+
97
+ app.use(AnalyticsTransport, new GATransport());
98
+ ```
99
+
100
+ Every `@track` in the app uses the registered transport. No component changes.
101
+
102
+ ---
103
+
104
+ ## Testing
105
+
106
+ ```ts
107
+ import { MockAnalytics } from "@toyz/loom-analytics/testing";
108
+
109
+ const analytics = new MockAnalytics();
110
+ app.use(AnalyticsTransport, analytics);
111
+
112
+ // ... interact with component ...
113
+
114
+ // Assertions
115
+ analytics.assertTracked("button.save");
116
+ analytics.assertTracked("theme.change", { value: "light" });
117
+ analytics.assertNotTracked("page.error");
118
+
119
+ // Inspect history
120
+ console.log(analytics.events);
121
+ // [{ event: "button.save", meta: { ... }, timestamp: ... }]
122
+
123
+ // Reset between tests
124
+ analytics.reset();
125
+ ```
126
+
127
+ ---
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,9 @@
1
+ /**
2
+ * LoomAnalytics — Barrel exports
3
+ *
4
+ * Zero-dependency, transport-swappable analytics for Loom.
5
+ * Decorator-driven event tracking with TC39 Stage 3 decorators.
6
+ */
7
+ export { track } from "./track";
8
+ export { AnalyticsTransport } from "./transport";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * LoomAnalytics — Barrel exports
3
+ *
4
+ * Zero-dependency, transport-swappable analytics for Loom.
5
+ * Decorator-driven event tracking with TC39 Stage 3 decorators.
6
+ */
7
+ // Decorator
8
+ export { track } from "./track";
9
+ // Transport
10
+ export { AnalyticsTransport } from "./transport";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY;AACZ,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,YAAY;AACZ,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * LoomAnalytics — MockAnalytics (testing transport)
3
+ *
4
+ * Records all tracked events for assertions in tests.
5
+ *
6
+ * ```ts
7
+ * const analytics = new MockAnalytics();
8
+ * app.use(AnalyticsTransport, analytics);
9
+ *
10
+ * // ... interact with component ...
11
+ *
12
+ * analytics.assertTracked("button.click");
13
+ * analytics.assertNotTracked("page.error");
14
+ * console.log(analytics.events);
15
+ * ```
16
+ */
17
+ import { AnalyticsTransport } from "./transport";
18
+ export interface TrackedEvent {
19
+ event: string;
20
+ meta?: Record<string, any>;
21
+ timestamp: number;
22
+ }
23
+ export declare class MockAnalytics extends AnalyticsTransport {
24
+ /** All tracked events, in order */
25
+ readonly events: TrackedEvent[];
26
+ /** Track an event — records to the events array */
27
+ track(event: string, meta?: Record<string, any>): void;
28
+ /** Assert that an event was tracked, optionally matching metadata */
29
+ assertTracked(event: string, meta?: Record<string, any>): void;
30
+ /** Assert that an event was NOT tracked */
31
+ assertNotTracked(event: string): void;
32
+ /** Clear all recorded events */
33
+ reset(): void;
34
+ /** Partial metadata match */
35
+ private metaMatches;
36
+ }
37
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAc,SAAQ,kBAAkB;IACnD,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,CAAM;IAErC,mDAAmD;IACnD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAItD,qEAAqE;IACrE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAY9D,2CAA2C;IAC3C,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IASrC,gCAAgC;IAChC,KAAK,IAAI,IAAI;IAIb,6BAA6B;IAC7B,OAAO,CAAC,WAAW;CASpB"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * LoomAnalytics — MockAnalytics (testing transport)
3
+ *
4
+ * Records all tracked events for assertions in tests.
5
+ *
6
+ * ```ts
7
+ * const analytics = new MockAnalytics();
8
+ * app.use(AnalyticsTransport, analytics);
9
+ *
10
+ * // ... interact with component ...
11
+ *
12
+ * analytics.assertTracked("button.click");
13
+ * analytics.assertNotTracked("page.error");
14
+ * console.log(analytics.events);
15
+ * ```
16
+ */
17
+ import { AnalyticsTransport } from "./transport";
18
+ export class MockAnalytics extends AnalyticsTransport {
19
+ /** All tracked events, in order */
20
+ events = [];
21
+ /** Track an event — records to the events array */
22
+ track(event, meta) {
23
+ this.events.push({ event, meta, timestamp: Date.now() });
24
+ }
25
+ /** Assert that an event was tracked, optionally matching metadata */
26
+ assertTracked(event, meta) {
27
+ const match = this.events.find((e) => e.event === event && (!meta || this.metaMatches(e.meta, meta)));
28
+ if (!match) {
29
+ const recorded = this.events.map((e) => e.event).join(", ") || "(none)";
30
+ throw new Error(`[MockAnalytics] Expected "${event}" to be tracked. Recorded: ${recorded}`);
31
+ }
32
+ }
33
+ /** Assert that an event was NOT tracked */
34
+ assertNotTracked(event) {
35
+ const match = this.events.find((e) => e.event === event);
36
+ if (match) {
37
+ throw new Error(`[MockAnalytics] Expected "${event}" to NOT be tracked, but it was.`);
38
+ }
39
+ }
40
+ /** Clear all recorded events */
41
+ reset() {
42
+ this.events.length = 0;
43
+ }
44
+ /** Partial metadata match */
45
+ metaMatches(actual, expected) {
46
+ if (!actual)
47
+ return false;
48
+ return Object.entries(expected).every(([key, value]) => actual[key] === value);
49
+ }
50
+ }
51
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAQjD,MAAM,OAAO,aAAc,SAAQ,kBAAkB;IACnD,mCAAmC;IAC1B,MAAM,GAAmB,EAAE,CAAC;IAErC,mDAAmD;IACnD,KAAK,CAAC,KAAa,EAAE,IAA0B;QAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,qEAAqE;IACrE,aAAa,CAAC,KAAa,EAAE,IAA0B;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACtE,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;YACxE,MAAM,IAAI,KAAK,CACb,6BAA6B,KAAK,8BAA8B,QAAQ,EAAE,CAC3E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,gBAAgB,CAAC,KAAa;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACzD,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,6BAA6B,KAAK,kCAAkC,CACrE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,6BAA6B;IACrB,WAAW,CACjB,MAAuC,EACvC,QAA6B;QAE7B,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CACnC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CACxC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * LoomAnalytics — @track decorator
3
+ *
4
+ * Raw TC39 Stage 3 decorator for event tracking.
5
+ * Dispatches on `context.kind` to support class, method, and accessor targets.
6
+ *
7
+ * - **method**: wraps the method — fires track() after each invocation
8
+ * - **accessor**: wraps the setter — fires track() on every set
9
+ *
10
+ * ```ts
11
+ * @track("user.save")
12
+ * handleSave() { ... }
13
+ *
14
+ * @track("theme.change")
15
+ * accessor theme = "dark";
16
+ * ```
17
+ */
18
+ export declare function track(event: string, meta?: Record<string, any>): (value: any, context: DecoratorContext) => any;
19
+ //# sourceMappingURL=track.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IACrD,OAAO,GAAG,EAAE,SAAS,gBAAgB,KAAG,GAAG,CA2DpD"}
package/dist/track.js ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * LoomAnalytics — @track decorator
3
+ *
4
+ * Raw TC39 Stage 3 decorator for event tracking.
5
+ * Dispatches on `context.kind` to support class, method, and accessor targets.
6
+ *
7
+ * - **method**: wraps the method — fires track() after each invocation
8
+ * - **accessor**: wraps the setter — fires track() on every set
9
+ *
10
+ * ```ts
11
+ * @track("user.save")
12
+ * handleSave() { ... }
13
+ *
14
+ * @track("theme.change")
15
+ * accessor theme = "dark";
16
+ * ```
17
+ */
18
+ import { app } from "@toyz/loom";
19
+ import { AnalyticsTransport } from "./transport";
20
+ export function track(event, meta) {
21
+ return (value, context) => {
22
+ switch (context.kind) {
23
+ case "class": {
24
+ // Class decorator: stamp an addInitializer that fires on connect
25
+ // Since we can't hook connectedCallback from here, we stamp a marker
26
+ // and let the test/runtime check for it. For simplicity, we fire
27
+ // track at class-definition time for class-level usage (page views).
28
+ // Actually — we can use addInitializer for per-instance setup, but
29
+ // it doesn't have `this` for class decorators in esbuild.
30
+ // Pragmatic solution: wrap the constructor via a returned subclass.
31
+ // BUT esbuild drops class decorator return values.
32
+ // Final approach: directly wrap connectedCallback on the prototype.
33
+ const ctor = value;
34
+ const originalConnected = ctor.prototype.connectedCallback;
35
+ ctor.prototype.connectedCallback = function () {
36
+ if (originalConnected)
37
+ originalConnected.call(this);
38
+ app.get(AnalyticsTransport).track(event, {
39
+ ...meta,
40
+ element: this.tagName.toLowerCase(),
41
+ });
42
+ };
43
+ break;
44
+ }
45
+ case "method": {
46
+ // Method decorator: wrap to fire after invocation
47
+ const method = value;
48
+ const key = String(context.name);
49
+ context.addInitializer(function () {
50
+ const original = method;
51
+ this[key] = function (...args) {
52
+ const result = original.apply(this, args);
53
+ app.get(AnalyticsTransport).track(event, { ...meta, method: key, args });
54
+ return result;
55
+ };
56
+ });
57
+ break;
58
+ }
59
+ case "accessor": {
60
+ // Accessor decorator: wrap the setter to fire on set
61
+ const target = value;
62
+ const key = String(context.name);
63
+ return {
64
+ get() {
65
+ return target.get.call(this);
66
+ },
67
+ set(v) {
68
+ target.set.call(this, v);
69
+ app.get(AnalyticsTransport).track(event, {
70
+ ...meta,
71
+ property: key,
72
+ value: v,
73
+ });
74
+ },
75
+ };
76
+ }
77
+ }
78
+ };
79
+ }
80
+ //# sourceMappingURL=track.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,IAA0B;IAC7D,OAAO,CAAC,KAAU,EAAE,OAAyB,EAAO,EAAE;QACpD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,iEAAiE;gBACjE,qEAAqE;gBACrE,kEAAkE;gBAClE,qEAAqE;gBACrE,mEAAmE;gBACnE,0DAA0D;gBAC1D,oEAAoE;gBACpE,mDAAmD;gBACnD,oEAAoE;gBACpE,MAAM,IAAI,GAAG,KAAiB,CAAC;gBAC/B,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;gBAC3D,IAAI,CAAC,SAAS,CAAC,iBAAiB,GAAG;oBACjC,IAAI,iBAAiB;wBAAE,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE;wBACvC,GAAG,IAAI;wBACP,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;qBACpC,CAAC,CAAC;gBACL,CAAC,CAAC;gBACF,MAAM;YACR,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,kDAAkD;gBAClD,MAAM,MAAM,GAAG,KAAiB,CAAC;gBACjC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACjC,OAAO,CAAC,cAAc,CAAC;oBACrB,MAAM,QAAQ,GAAG,MAAM,CAAC;oBACvB,IAAY,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,IAAW;wBAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;wBAC1C,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;wBACzE,OAAO,MAAM,CAAC;oBAChB,CAAC,CAAC;gBACJ,CAAC,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;YAED,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,qDAAqD;gBACrD,MAAM,MAAM,GAAG,KAA+C,CAAC;gBAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACjC,OAAO;oBACL,GAAG;wBACD,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC/B,CAAC;oBACD,GAAG,CAAY,CAAM;wBACnB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;wBACzB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE;4BACvC,GAAG,IAAI;4BACP,QAAQ,EAAE,GAAG;4BACb,KAAK,EAAE,CAAC;yBACT,CAAC,CAAC;oBACL,CAAC;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * LoomAnalytics — AnalyticsTransport
3
+ *
4
+ * Abstract base class for analytics transports.
5
+ * Implement this to send events to any analytics backend.
6
+ *
7
+ * ```ts
8
+ * class PostHogTransport extends AnalyticsTransport {
9
+ * track(event: string, meta?: Record<string, any>): void {
10
+ * posthog.capture(event, meta);
11
+ * }
12
+ * }
13
+ *
14
+ * app.use(AnalyticsTransport, new PostHogTransport());
15
+ * ```
16
+ */
17
+ export declare abstract class AnalyticsTransport {
18
+ /**
19
+ * Track an event with optional metadata.
20
+ *
21
+ * @param event - The event name (e.g. "button.click", "page.view")
22
+ * @param meta - Optional metadata payload
23
+ */
24
+ abstract track(event: string, meta?: Record<string, any>): void;
25
+ }
26
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,8BAAsB,kBAAkB;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;CAChE"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * LoomAnalytics — AnalyticsTransport
3
+ *
4
+ * Abstract base class for analytics transports.
5
+ * Implement this to send events to any analytics backend.
6
+ *
7
+ * ```ts
8
+ * class PostHogTransport extends AnalyticsTransport {
9
+ * track(event: string, meta?: Record<string, any>): void {
10
+ * posthog.capture(event, meta);
11
+ * }
12
+ * }
13
+ *
14
+ * app.use(AnalyticsTransport, new PostHogTransport());
15
+ * ```
16
+ */
17
+ export class AnalyticsTransport {
18
+ }
19
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAgB,kBAAkB;CAQvC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@toyz/loom-analytics",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Zero-dependency, transport-swappable analytics for Loom — decorator-driven event tracking",
6
+ "license": "MIT",
7
+ "author": "toyz",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Toyz/loom.git",
11
+ "directory": "loom-analytics"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "main": "./dist/index.js",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ },
25
+ "./testing": {
26
+ "types": "./dist/testing.d.ts",
27
+ "import": "./dist/testing.js"
28
+ }
29
+ },
30
+ "scripts": {
31
+ "build": "tsc",
32
+ "dev": "tsc --watch",
33
+ "test": "vitest run",
34
+ "clean": "rm -rf dist",
35
+ "prepublishOnly": "npm run clean && npm run build"
36
+ },
37
+ "dependencies": {
38
+ "@toyz/loom": "^0.12.0"
39
+ },
40
+ "devDependencies": {
41
+ "happy-dom": "^17.4.4",
42
+ "typescript": "^5.7.0",
43
+ "vitest": "^3.0.0"
44
+ },
45
+ "keywords": [
46
+ "loom",
47
+ "analytics",
48
+ "decorators",
49
+ "tracking",
50
+ "web-components"
51
+ ]
52
+ }