sentinel-qa 0.0.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.
Files changed (101) hide show
  1. package/dist/__tests__/capture-patterns.test.d.ts +2 -0
  2. package/dist/__tests__/capture-patterns.test.d.ts.map +1 -0
  3. package/dist/__tests__/capture-patterns.test.js +82 -0
  4. package/dist/__tests__/capture-patterns.test.js.map +1 -0
  5. package/dist/__tests__/event-spec-schema.test.d.ts +2 -0
  6. package/dist/__tests__/event-spec-schema.test.d.ts.map +1 -0
  7. package/dist/__tests__/event-spec-schema.test.js +75 -0
  8. package/dist/__tests__/event-spec-schema.test.js.map +1 -0
  9. package/dist/__tests__/event-validation.test.d.ts +2 -0
  10. package/dist/__tests__/event-validation.test.d.ts.map +1 -0
  11. package/dist/__tests__/event-validation.test.js +146 -0
  12. package/dist/__tests__/event-validation.test.js.map +1 -0
  13. package/dist/__tests__/markdown-report.test.d.ts +2 -0
  14. package/dist/__tests__/markdown-report.test.d.ts.map +1 -0
  15. package/dist/__tests__/markdown-report.test.js +104 -0
  16. package/dist/__tests__/markdown-report.test.js.map +1 -0
  17. package/dist/__tests__/test-status-store.test.d.ts +2 -0
  18. package/dist/__tests__/test-status-store.test.d.ts.map +1 -0
  19. package/dist/__tests__/test-status-store.test.js +197 -0
  20. package/dist/__tests__/test-status-store.test.js.map +1 -0
  21. package/dist/event-validation/capture-patterns.d.ts +26 -0
  22. package/dist/event-validation/capture-patterns.d.ts.map +1 -0
  23. package/dist/event-validation/capture-patterns.js +152 -0
  24. package/dist/event-validation/capture-patterns.js.map +1 -0
  25. package/dist/event-validation/index.d.ts +6 -0
  26. package/dist/event-validation/index.d.ts.map +1 -0
  27. package/dist/event-validation/index.js +4 -0
  28. package/dist/event-validation/index.js.map +1 -0
  29. package/dist/event-validation/schema.d.ts +59 -0
  30. package/dist/event-validation/schema.d.ts.map +1 -0
  31. package/dist/event-validation/schema.js +22 -0
  32. package/dist/event-validation/schema.js.map +1 -0
  33. package/dist/event-validation/types.d.ts +43 -0
  34. package/dist/event-validation/types.d.ts.map +1 -0
  35. package/dist/event-validation/types.js +2 -0
  36. package/dist/event-validation/types.js.map +1 -0
  37. package/dist/event-validation/validator.d.ts +14 -0
  38. package/dist/event-validation/validator.d.ts.map +1 -0
  39. package/dist/event-validation/validator.js +97 -0
  40. package/dist/event-validation/validator.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +43 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/registry/registry.d.ts +12 -0
  46. package/dist/registry/registry.d.ts.map +1 -0
  47. package/dist/registry/registry.js +51 -0
  48. package/dist/registry/registry.js.map +1 -0
  49. package/dist/registry/types.d.ts +28 -0
  50. package/dist/registry/types.d.ts.map +1 -0
  51. package/dist/registry/types.js +2 -0
  52. package/dist/registry/types.js.map +1 -0
  53. package/dist/report/markdown.d.ts +13 -0
  54. package/dist/report/markdown.d.ts.map +1 -0
  55. package/dist/report/markdown.js +137 -0
  56. package/dist/report/markdown.js.map +1 -0
  57. package/dist/report/report-store.d.ts +28 -0
  58. package/dist/report/report-store.d.ts.map +1 -0
  59. package/dist/report/report-store.js +69 -0
  60. package/dist/report/report-store.js.map +1 -0
  61. package/dist/schemas/tools.d.ts +40 -0
  62. package/dist/schemas/tools.d.ts.map +1 -0
  63. package/dist/schemas/tools.js +26 -0
  64. package/dist/schemas/tools.js.map +1 -0
  65. package/dist/store/test-status-store.d.ts +18 -0
  66. package/dist/store/test-status-store.d.ts.map +1 -0
  67. package/dist/store/test-status-store.js +79 -0
  68. package/dist/store/test-status-store.js.map +1 -0
  69. package/dist/store/test-store.d.ts +15 -0
  70. package/dist/store/test-store.d.ts.map +1 -0
  71. package/dist/store/test-store.js +24 -0
  72. package/dist/store/test-store.js.map +1 -0
  73. package/dist/tools/get-report.d.ts +4 -0
  74. package/dist/tools/get-report.d.ts.map +1 -0
  75. package/dist/tools/get-report.js +48 -0
  76. package/dist/tools/get-report.js.map +1 -0
  77. package/dist/tools/get-selectors.d.ts +4 -0
  78. package/dist/tools/get-selectors.d.ts.map +1 -0
  79. package/dist/tools/get-selectors.js +19 -0
  80. package/dist/tools/get-selectors.js.map +1 -0
  81. package/dist/tools/list-apps.d.ts +4 -0
  82. package/dist/tools/list-apps.d.ts.map +1 -0
  83. package/dist/tools/list-apps.js +8 -0
  84. package/dist/tools/list-apps.js.map +1 -0
  85. package/dist/tools/run-tests.d.ts +7 -0
  86. package/dist/tools/run-tests.d.ts.map +1 -0
  87. package/dist/tools/run-tests.js +233 -0
  88. package/dist/tools/run-tests.js.map +1 -0
  89. package/dist/tools/save-tests.d.ts +4 -0
  90. package/dist/tools/save-tests.d.ts.map +1 -0
  91. package/dist/tools/save-tests.js +13 -0
  92. package/dist/tools/save-tests.js.map +1 -0
  93. package/dist/utils/logger.d.ts +7 -0
  94. package/dist/utils/logger.d.ts.map +1 -0
  95. package/dist/utils/logger.js +11 -0
  96. package/dist/utils/logger.js.map +1 -0
  97. package/dist/utils/yaml-loader.d.ts +2 -0
  98. package/dist/utils/yaml-loader.d.ts.map +1 -0
  99. package/dist/utils/yaml-loader.js +7 -0
  100. package/dist/utils/yaml-loader.js.map +1 -0
  101. package/package.json +34 -0
@@ -0,0 +1,197 @@
1
+ import { describe, it, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, rm, readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { parse } from 'yaml';
7
+ import { TestStatusStore } from '../store/test-status-store.js';
8
+ let tempDir;
9
+ let store;
10
+ describe('TestStatusStore', () => {
11
+ beforeEach(async () => {
12
+ tempDir = await mkdtemp(join(tmpdir(), 'sentinel-test-'));
13
+ store = new TestStatusStore(tempDir);
14
+ });
15
+ afterEach(async () => {
16
+ await rm(tempDir, { recursive: true, force: true });
17
+ });
18
+ describe('load', () => {
19
+ it('should return empty array for non-existent app', async () => {
20
+ const result = await store.load('non-existent');
21
+ assert.deepStrictEqual(result, []);
22
+ });
23
+ });
24
+ describe('save and load round-trip', () => {
25
+ it('should persist and retrieve statuses via YAML', async () => {
26
+ const statuses = [
27
+ {
28
+ id: 'TC-001',
29
+ status: 'stable',
30
+ passRate: 1.0,
31
+ runHistory: [true, true, true, true, true],
32
+ lastRun: '2026-03-14T10:30:00.000Z',
33
+ },
34
+ {
35
+ id: 'TC-002',
36
+ status: 'quarantine',
37
+ passRate: 0.6,
38
+ runHistory: [true, false, true, true, false],
39
+ lastRun: '2026-03-14T10:30:00.000Z',
40
+ failureReason: 'Timing issue',
41
+ },
42
+ ];
43
+ await store.save('my-app', statuses);
44
+ const loaded = await store.load('my-app');
45
+ assert.equal(loaded.length, 2);
46
+ assert.equal(loaded[0].id, 'TC-001');
47
+ assert.equal(loaded[0].status, 'stable');
48
+ assert.equal(loaded[0].passRate, 1.0);
49
+ assert.deepStrictEqual(loaded[0].runHistory, [true, true, true, true, true]);
50
+ assert.equal(loaded[1].id, 'TC-002');
51
+ assert.equal(loaded[1].status, 'quarantine');
52
+ assert.equal(loaded[1].failureReason, 'Timing issue');
53
+ });
54
+ it('should write valid YAML to disk', async () => {
55
+ await store.save('my-app', [
56
+ { id: 'TC-001', status: 'new', passRate: 1, runHistory: [true], lastRun: '2026-01-01T00:00:00.000Z' },
57
+ ]);
58
+ const raw = await readFile(join(tempDir, 'my-app', 'status.yaml'), 'utf-8');
59
+ const parsed = parse(raw);
60
+ assert.equal(parsed.tests.length, 1);
61
+ assert.equal(parsed.tests[0].id, 'TC-001');
62
+ });
63
+ });
64
+ describe('getStatus', () => {
65
+ it('should return null for unknown test', async () => {
66
+ const result = await store.getStatus('my-app', 'TC-999');
67
+ assert.equal(result, null);
68
+ });
69
+ it('should return matching test status', async () => {
70
+ await store.save('my-app', [
71
+ { id: 'TC-001', status: 'stable', passRate: 1, runHistory: [true], lastRun: '2026-01-01T00:00:00.000Z' },
72
+ ]);
73
+ const result = await store.getStatus('my-app', 'TC-001');
74
+ assert.notEqual(result, null);
75
+ assert.equal(result.id, 'TC-001');
76
+ assert.equal(result.status, 'stable');
77
+ });
78
+ });
79
+ describe('recordRun', () => {
80
+ it('should create new entry on first run', async () => {
81
+ const result = await store.recordRun('my-app', 'TC-001', true);
82
+ assert.equal(result.id, 'TC-001');
83
+ assert.equal(result.status, 'new');
84
+ assert.deepStrictEqual(result.runHistory, [true]);
85
+ assert.equal(result.passRate, 1);
86
+ });
87
+ it('should accumulate run history', async () => {
88
+ await store.recordRun('my-app', 'TC-001', true);
89
+ await store.recordRun('my-app', 'TC-001', false);
90
+ const result = await store.recordRun('my-app', 'TC-001', true);
91
+ assert.deepStrictEqual(result.runHistory, [true, false, true]);
92
+ assert.equal(result.passRate, 2 / 3);
93
+ });
94
+ it('should promote to stable after 5/5 passes', async () => {
95
+ for (let i = 0; i < 4; i++) {
96
+ await store.recordRun('my-app', 'TC-001', true);
97
+ }
98
+ const result = await store.recordRun('my-app', 'TC-001', true);
99
+ assert.equal(result.status, 'stable');
100
+ assert.equal(result.passRate, 1);
101
+ assert.equal(result.runHistory.length, 5);
102
+ });
103
+ it('should quarantine at 4/5 passes', async () => {
104
+ await store.recordRun('my-app', 'TC-001', true);
105
+ await store.recordRun('my-app', 'TC-001', true);
106
+ await store.recordRun('my-app', 'TC-001', true);
107
+ await store.recordRun('my-app', 'TC-001', true);
108
+ const result = await store.recordRun('my-app', 'TC-001', false);
109
+ assert.equal(result.status, 'quarantine');
110
+ assert.equal(result.passRate, 0.8);
111
+ });
112
+ it('should quarantine at 3/5 passes', async () => {
113
+ await store.recordRun('my-app', 'TC-001', true);
114
+ await store.recordRun('my-app', 'TC-001', false);
115
+ await store.recordRun('my-app', 'TC-001', true);
116
+ await store.recordRun('my-app', 'TC-001', false);
117
+ const result = await store.recordRun('my-app', 'TC-001', true);
118
+ assert.equal(result.status, 'quarantine');
119
+ assert.equal(result.passRate, 0.6);
120
+ });
121
+ it('should reject at 2/5 passes', async () => {
122
+ await store.recordRun('my-app', 'TC-001', true);
123
+ await store.recordRun('my-app', 'TC-001', false);
124
+ await store.recordRun('my-app', 'TC-001', false);
125
+ await store.recordRun('my-app', 'TC-001', false);
126
+ const result = await store.recordRun('my-app', 'TC-001', true);
127
+ assert.equal(result.status, 'rejected');
128
+ assert.equal(result.passRate, 0.4);
129
+ });
130
+ it('should reject at 0/5 passes', async () => {
131
+ for (let i = 0; i < 5; i++) {
132
+ await store.recordRun('my-app', 'TC-001', false);
133
+ }
134
+ const result = await store.getStatus('my-app', 'TC-001');
135
+ assert.equal(result.status, 'rejected');
136
+ assert.equal(result.passRate, 0);
137
+ });
138
+ it('should keep only last 5 runs', async () => {
139
+ // 5 failures → rejected
140
+ for (let i = 0; i < 5; i++) {
141
+ await store.recordRun('my-app', 'TC-001', false);
142
+ }
143
+ let result = await store.getStatus('my-app', 'TC-001');
144
+ assert.equal(result.status, 'rejected');
145
+ // Now 5 passes → should become stable (old failures dropped)
146
+ for (let i = 0; i < 5; i++) {
147
+ await store.recordRun('my-app', 'TC-001', true);
148
+ }
149
+ result = await store.getStatus('my-app', 'TC-001');
150
+ assert.equal(result.status, 'stable');
151
+ assert.equal(result.runHistory.length, 5);
152
+ assert.deepStrictEqual(result.runHistory, [true, true, true, true, true]);
153
+ });
154
+ it('should not promote/demote with fewer than 5 runs', async () => {
155
+ await store.recordRun('my-app', 'TC-001', false);
156
+ await store.recordRun('my-app', 'TC-001', false);
157
+ await store.recordRun('my-app', 'TC-001', false);
158
+ const result = await store.recordRun('my-app', 'TC-001', false);
159
+ // Only 4 runs — should still be 'new'
160
+ assert.equal(result.status, 'new');
161
+ assert.equal(result.runHistory.length, 4);
162
+ });
163
+ it('should calculate passRate correctly for partial history', async () => {
164
+ await store.recordRun('my-app', 'TC-001', true);
165
+ const result = await store.recordRun('my-app', 'TC-001', false);
166
+ assert.equal(result.passRate, 0.5);
167
+ assert.equal(result.runHistory.length, 2);
168
+ });
169
+ it('should set failureReason on quarantine', async () => {
170
+ await store.recordRun('my-app', 'TC-001', true);
171
+ await store.recordRun('my-app', 'TC-001', true);
172
+ await store.recordRun('my-app', 'TC-001', true);
173
+ await store.recordRun('my-app', 'TC-001', false);
174
+ const result = await store.recordRun('my-app', 'TC-001', true);
175
+ assert.equal(result.status, 'quarantine');
176
+ assert.ok(result.failureReason);
177
+ });
178
+ it('should clear failureReason on promotion to stable', async () => {
179
+ // First get to quarantine
180
+ await store.recordRun('my-app', 'TC-001', true);
181
+ await store.recordRun('my-app', 'TC-001', true);
182
+ await store.recordRun('my-app', 'TC-001', true);
183
+ await store.recordRun('my-app', 'TC-001', false);
184
+ await store.recordRun('my-app', 'TC-001', true);
185
+ let result = await store.getStatus('my-app', 'TC-001');
186
+ assert.equal(result.status, 'quarantine');
187
+ // Now push 5 passes
188
+ for (let i = 0; i < 5; i++) {
189
+ await store.recordRun('my-app', 'TC-001', true);
190
+ }
191
+ result = await store.getStatus('my-app', 'TC-001');
192
+ assert.equal(result.status, 'stable');
193
+ assert.equal(result.failureReason, undefined);
194
+ });
195
+ });
196
+ });
197
+ //# sourceMappingURL=test-status-store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-status-store.test.js","sourceRoot":"","sources":["../../src/__tests__/test-status-store.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGhE,IAAI,OAAe,CAAC;AACpB,IAAI,KAAsB,CAAC;AAE3B,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAC1D,KAAK,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;QACpB,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAChD,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,QAAQ,GAAiB;gBAC7B;oBACE,EAAE,EAAE,QAAQ;oBACZ,MAAM,EAAE,QAAQ;oBAChB,QAAQ,EAAE,GAAG;oBACb,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;oBAC1C,OAAO,EAAE,0BAA0B;iBACpC;gBACD;oBACE,EAAE,EAAE,QAAQ;oBACZ,MAAM,EAAE,YAAY;oBACpB,QAAQ,EAAE,GAAG;oBACb,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC;oBAC5C,OAAO,EAAE,0BAA0B;oBACnC,aAAa,EAAE,cAAc;iBAC9B;aACF,CAAC;YAEF,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YAE7E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;gBACzB,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE;aACtG,CAAC,CAAC;YAEH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CAAC;YAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAA4B,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACzD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;gBACzB,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE;aACzG,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACzD,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YAC/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAEhE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACnD,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAEzD,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,wBAAwB;YACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACnD,CAAC;YACD,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAEzC,6DAA6D;YAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,eAAe,CAAC,MAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAEhE,sCAAsC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACvE,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAEhE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAE/D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC1C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,0BAA0B;YAC1B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAEhD,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAE3C,oBAAoB;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClD,CAAC;YACD,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,MAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * URL patterns for known analytics SDK endpoints.
3
+ * Used by Playwright to intercept analytics network requests.
4
+ */
5
+ export interface AnalyticsPattern {
6
+ /** Human-readable SDK name */
7
+ sdk: string;
8
+ /** URL patterns to match (supports glob-like matching) */
9
+ urlPatterns: string[];
10
+ /** Function to extract event name and params from request body/URL */
11
+ parseRequest: (url: string, body: string | null) => ParsedEvent[];
12
+ }
13
+ export interface ParsedEvent {
14
+ event_name: string;
15
+ params: Record<string, unknown>;
16
+ }
17
+ /**
18
+ * Built-in analytics SDK patterns.
19
+ */
20
+ export declare const ANALYTICS_PATTERNS: AnalyticsPattern[];
21
+ /**
22
+ * Check if a URL matches any analytics pattern.
23
+ * Returns the matching pattern or null.
24
+ */
25
+ export declare function matchAnalyticsUrl(url: string): AnalyticsPattern | null;
26
+ //# sourceMappingURL=capture-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-patterns.d.ts","sourceRoot":"","sources":["../../src/event-validation/capture-patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,sEAAsE;IACtE,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,EAAE,CAAC;CACnE;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AA2FD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EAiChD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAYtE"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * URL patterns for known analytics SDK endpoints.
3
+ * Used by Playwright to intercept analytics network requests.
4
+ */
5
+ /**
6
+ * Parse Google Analytics 4 (GA4) Measurement Protocol requests.
7
+ * Endpoint: google-analytics.com/g/collect
8
+ */
9
+ function parseGA4Request(url, _body) {
10
+ const events = [];
11
+ try {
12
+ const urlObj = new URL(url);
13
+ const eventName = urlObj.searchParams.get('en');
14
+ if (eventName) {
15
+ const params = {};
16
+ for (const [key, value] of urlObj.searchParams.entries()) {
17
+ if (key !== 'en' && key !== 'v' && key !== 'tid') {
18
+ params[key] = isNaN(Number(value)) ? value : Number(value);
19
+ }
20
+ }
21
+ events.push({ event_name: eventName, params });
22
+ }
23
+ }
24
+ catch { /* ignore parse errors */ }
25
+ return events;
26
+ }
27
+ /**
28
+ * Parse Firebase Analytics requests.
29
+ * Endpoint: firebase-installations.googleapis.com, firebaselogging
30
+ */
31
+ function parseFirebaseRequest(_url, body) {
32
+ const events = [];
33
+ if (!body)
34
+ return events;
35
+ try {
36
+ const data = JSON.parse(body);
37
+ if (Array.isArray(data.events)) {
38
+ for (const event of data.events) {
39
+ events.push({
40
+ event_name: event.name ?? event.event_name ?? 'unknown',
41
+ params: event.params ?? {},
42
+ });
43
+ }
44
+ }
45
+ }
46
+ catch { /* ignore parse errors */ }
47
+ return events;
48
+ }
49
+ /**
50
+ * Parse Amplitude Analytics requests.
51
+ * Endpoint: api.amplitude.com
52
+ */
53
+ function parseAmplitudeRequest(_url, body) {
54
+ const events = [];
55
+ if (!body)
56
+ return events;
57
+ try {
58
+ const data = JSON.parse(body);
59
+ const eventList = data.events ?? (Array.isArray(data) ? data : [data]);
60
+ for (const event of eventList) {
61
+ events.push({
62
+ event_name: event.event_type ?? event.event_name ?? 'unknown',
63
+ params: event.event_properties ?? event.user_properties ?? {},
64
+ });
65
+ }
66
+ }
67
+ catch { /* ignore parse errors */ }
68
+ return events;
69
+ }
70
+ /**
71
+ * Parse Mixpanel Analytics requests.
72
+ * Endpoint: api.mixpanel.com/track
73
+ */
74
+ function parseMixpanelRequest(_url, body) {
75
+ const events = [];
76
+ if (!body)
77
+ return events;
78
+ try {
79
+ // Mixpanel sends base64-encoded data or JSON
80
+ let data;
81
+ try {
82
+ data = JSON.parse(body);
83
+ }
84
+ catch {
85
+ data = JSON.parse(Buffer.from(body, 'base64').toString());
86
+ }
87
+ const eventList = Array.isArray(data) ? data : [data];
88
+ for (const event of eventList) {
89
+ events.push({
90
+ event_name: event.event ?? 'unknown',
91
+ params: event.properties ?? {},
92
+ });
93
+ }
94
+ }
95
+ catch { /* ignore parse errors */ }
96
+ return events;
97
+ }
98
+ /**
99
+ * Built-in analytics SDK patterns.
100
+ */
101
+ export const ANALYTICS_PATTERNS = [
102
+ {
103
+ sdk: 'Google Analytics 4',
104
+ urlPatterns: [
105
+ '**/google-analytics.com/g/collect**',
106
+ '**/analytics.google.com/g/collect**',
107
+ ],
108
+ parseRequest: parseGA4Request,
109
+ },
110
+ {
111
+ sdk: 'Firebase Analytics',
112
+ urlPatterns: [
113
+ '**/firebaselogging/**',
114
+ '**/firebase-installations.googleapis.com/**',
115
+ '**/app-measurement.com/**',
116
+ ],
117
+ parseRequest: parseFirebaseRequest,
118
+ },
119
+ {
120
+ sdk: 'Amplitude',
121
+ urlPatterns: [
122
+ '**/api.amplitude.com/**',
123
+ '**/api2.amplitude.com/**',
124
+ ],
125
+ parseRequest: parseAmplitudeRequest,
126
+ },
127
+ {
128
+ sdk: 'Mixpanel',
129
+ urlPatterns: [
130
+ '**/api.mixpanel.com/**',
131
+ ],
132
+ parseRequest: parseMixpanelRequest,
133
+ },
134
+ ];
135
+ /**
136
+ * Check if a URL matches any analytics pattern.
137
+ * Returns the matching pattern or null.
138
+ */
139
+ export function matchAnalyticsUrl(url) {
140
+ for (const pattern of ANALYTICS_PATTERNS) {
141
+ for (const urlPattern of pattern.urlPatterns) {
142
+ // Simple substring matching for URL patterns
143
+ // Strip leading ** and trailing ** for contains-style matching
144
+ const cleanPattern = urlPattern.replace(/^\*\*\//, '').replace(/\/?\*\*$/, '');
145
+ if (url.includes(cleanPattern)) {
146
+ return pattern;
147
+ }
148
+ }
149
+ }
150
+ return null;
151
+ }
152
+ //# sourceMappingURL=capture-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-patterns.js","sourceRoot":"","sources":["../../src/event-validation/capture-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { validateEvents } from './validator.js';
2
+ export { matchAnalyticsUrl, ANALYTICS_PATTERNS } from './capture-patterns.js';
3
+ export { validateEventSpec, eventSpecConfigSchema } from './schema.js';
4
+ export type { CapturedEvent, EventValidationResult, EventMatchResult, ParamError, UnexpectedEvent, } from './types.js';
5
+ export type { AnalyticsPattern, ParsedEvent } from './capture-patterns.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/event-validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { validateEvents } from './validator.js';
2
+ export { matchAnalyticsUrl, ANALYTICS_PATTERNS } from './capture-patterns.js';
3
+ export { validateEventSpec, eventSpecConfigSchema } from './schema.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/event-validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for validating event spec YAML input.
4
+ */
5
+ export declare const eventParamSchema: z.ZodRecord<z.ZodString, z.ZodEnum<["string", "number", "boolean"]>>;
6
+ export declare const eventSpecEntrySchema: z.ZodObject<{
7
+ trigger: z.ZodString;
8
+ event_name: z.ZodString;
9
+ required_params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "number", "boolean"]>>>;
10
+ optional_params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "number", "boolean"]>>>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ trigger: string;
13
+ event_name: string;
14
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
15
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
16
+ }, {
17
+ trigger: string;
18
+ event_name: string;
19
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
20
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
21
+ }>;
22
+ export declare const eventSpecConfigSchema: z.ZodObject<{
23
+ events: z.ZodArray<z.ZodObject<{
24
+ trigger: z.ZodString;
25
+ event_name: z.ZodString;
26
+ required_params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "number", "boolean"]>>>;
27
+ optional_params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["string", "number", "boolean"]>>>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ trigger: string;
30
+ event_name: string;
31
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
32
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
33
+ }, {
34
+ trigger: string;
35
+ event_name: string;
36
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
37
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
38
+ }>, "many">;
39
+ }, "strip", z.ZodTypeAny, {
40
+ events: {
41
+ trigger: string;
42
+ event_name: string;
43
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
44
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
45
+ }[];
46
+ }, {
47
+ events: {
48
+ trigger: string;
49
+ event_name: string;
50
+ required_params?: Record<string, "string" | "number" | "boolean"> | undefined;
51
+ optional_params?: Record<string, "string" | "number" | "boolean"> | undefined;
52
+ }[];
53
+ }>;
54
+ /**
55
+ * Validate an event spec config object against the Zod schema.
56
+ * Returns the parsed result or throws on validation failure.
57
+ */
58
+ export declare function validateEventSpec(data: unknown): z.infer<typeof eventSpecConfigSchema>;
59
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/event-validation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB,sEAG5B,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;EAK/B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEhC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAEtF"}
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for validating event spec YAML input.
4
+ */
5
+ export const eventParamSchema = z.record(z.string(), z.enum(['string', 'number', 'boolean']));
6
+ export const eventSpecEntrySchema = z.object({
7
+ trigger: z.string().describe('Description of what triggers this event'),
8
+ event_name: z.string().describe('Analytics event name'),
9
+ required_params: eventParamSchema.optional().describe('Required parameters with type'),
10
+ optional_params: eventParamSchema.optional().describe('Optional parameters with type'),
11
+ });
12
+ export const eventSpecConfigSchema = z.object({
13
+ events: z.array(eventSpecEntrySchema),
14
+ });
15
+ /**
16
+ * Validate an event spec config object against the Zod schema.
17
+ * Returns the parsed result or throws on validation failure.
18
+ */
19
+ export function validateEventSpec(data) {
20
+ return eventSpecConfigSchema.parse(data);
21
+ }
22
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/event-validation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CACtC,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CACxC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;IACvE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;IACvD,eAAe,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IACtF,eAAe,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;CACvF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;CACtC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A captured analytics event from network interception or device logs.
3
+ */
4
+ export interface CapturedEvent {
5
+ event_name: string;
6
+ params: Record<string, unknown>;
7
+ timestamp?: string;
8
+ source_url?: string;
9
+ }
10
+ /**
11
+ * Result of comparing a single expected event against captured events.
12
+ */
13
+ export interface EventMatchResult {
14
+ event_name: string;
15
+ trigger: string;
16
+ status: 'matched' | 'missing' | 'param_error';
17
+ param_errors?: ParamError[];
18
+ }
19
+ export interface ParamError {
20
+ param: string;
21
+ expected: string;
22
+ got: string;
23
+ }
24
+ /**
25
+ * An unexpected event that was captured but not in the spec.
26
+ */
27
+ export interface UnexpectedEvent {
28
+ event_name: string;
29
+ params: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Full validation result comparing spec vs captured events.
33
+ */
34
+ export interface EventValidationResult {
35
+ total_expected: number;
36
+ matched: number;
37
+ missing: number;
38
+ param_errors: number;
39
+ unexpected_count: number;
40
+ results: EventMatchResult[];
41
+ unexpected: UnexpectedEvent[];
42
+ }
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/event-validation/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;IAC9C,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/event-validation/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { EventSpecEntry } from '../registry/types.js';
2
+ import type { CapturedEvent, EventValidationResult } from './types.js';
3
+ /**
4
+ * Validate captured events against an event spec.
5
+ *
6
+ * For each expected event in the spec:
7
+ * - Check if a matching captured event exists (by event_name)
8
+ * - If found, validate required_params (presence + type)
9
+ * - If not found, mark as missing
10
+ *
11
+ * Any captured events not in the spec are listed as unexpected.
12
+ */
13
+ export declare function validateEvents(spec: EventSpecEntry[], captured: CapturedEvent[]): EventValidationResult;
14
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/event-validation/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EAItB,MAAM,YAAY,CAAC;AAkBpB;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,cAAc,EAAE,EACtB,QAAQ,EAAE,aAAa,EAAE,GACxB,qBAAqB,CA+EvB"}