avo-inspector 2.2.0 → 2.2.2-alpha

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 (108) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +95 -0
  3. package/bin/avo-inspector.js +97 -0
  4. package/dist/AvoBatcher.d.ts +4 -2
  5. package/dist/AvoEncryption.d.ts +33 -0
  6. package/dist/AvoInspector.d.ts +31 -3
  7. package/dist/AvoNetworkCallsHandler.d.ts +28 -3
  8. package/dist/AvoSchemaParser.d.ts +12 -1
  9. package/dist/browser.js.LICENSE.txt +5 -0
  10. package/dist/eventSpec/AvoEventSpecCache.d.ts +73 -0
  11. package/dist/eventSpec/AvoEventSpecFetchTypes.d.ts +109 -0
  12. package/dist/eventSpec/AvoEventSpecFetcher.d.ts +54 -0
  13. package/dist/eventSpec/EventValidator.d.ts +90 -0
  14. package/dist/eventSpec/cache.d.ts +73 -0
  15. package/dist/eventSpec/index.d.ts +4 -0
  16. package/dist/eventSpec/types.d.ts +74 -0
  17. package/dist/index.js +2 -1
  18. package/dist/index.js.LICENSE.txt +5 -0
  19. package/dist-browser/AvoAnonymousId.d.ts +26 -0
  20. package/dist-browser/AvoBatcher.d.ts +26 -0
  21. package/dist-browser/AvoDeduplicator.d.ts +20 -0
  22. package/dist-browser/AvoEncryption.d.ts +33 -0
  23. package/dist-browser/AvoGuid.d.ts +3 -0
  24. package/dist-browser/AvoInspector.d.ts +78 -0
  25. package/dist-browser/AvoInspectorEnv.d.ts +7 -0
  26. package/dist-browser/AvoNetworkCallsHandler.d.ts +74 -0
  27. package/dist-browser/AvoSchemaParser.d.ts +20 -0
  28. package/dist-browser/AvoStorage.d.ts +22 -0
  29. package/dist-browser/__mocks__/xhr.d.ts +12 -0
  30. package/dist-browser/__mocks__/xhrError.d.ts +12 -0
  31. package/dist-browser/__tests__/AnonymousId_test.d.ts +1 -0
  32. package/dist-browser/__tests__/AvoEncryption_test.d.ts +1 -0
  33. package/dist-browser/__tests__/AvoInspectorEventSpec_test.d.ts +1 -0
  34. package/dist-browser/__tests__/AvoInspector_test.d.ts +1 -0
  35. package/dist-browser/__tests__/BatcherPublic_test.d.ts +1 -0
  36. package/dist-browser/__tests__/Batcher_test.d.ts +1 -0
  37. package/dist-browser/__tests__/Deduplicator_test.d.ts +1 -0
  38. package/dist-browser/__tests__/EncryptedPropertyTracking_test.d.ts +1 -0
  39. package/dist-browser/__tests__/EventSpecCache_test.d.ts +1 -0
  40. package/dist-browser/__tests__/EventSpecFetcher_test.d.ts +1 -0
  41. package/dist-browser/__tests__/EventValidator_test.d.ts +1 -0
  42. package/dist-browser/__tests__/NetworkCallsHandler_test.d.ts +1 -0
  43. package/dist-browser/__tests__/Parsing_test.d.ts +1 -0
  44. package/dist-browser/__tests__/Storage_test.d.ts +1 -0
  45. package/dist-browser/__tests__/ValidationIntegration_test.d.ts +1 -0
  46. package/dist-browser/__tests__/constants.d.ts +36 -0
  47. package/dist-browser/__tests__/helpers/encryptionHelpers.d.ts +13 -0
  48. package/dist-browser/__tests__/helpers/mockFactories.d.ts +49 -0
  49. package/dist-browser/eventSpec/AvoEventSpecCache.d.ts +73 -0
  50. package/dist-browser/eventSpec/AvoEventSpecFetchTypes.d.ts +109 -0
  51. package/dist-browser/eventSpec/AvoEventSpecFetcher.d.ts +55 -0
  52. package/dist-browser/eventSpec/EventValidator.d.ts +90 -0
  53. package/dist-browser/eventSpec/index.d.ts +4 -0
  54. package/dist-browser/index.d.ts +2 -0
  55. package/dist-browser/utils.d.ts +3 -0
  56. package/dist-native/AvoBatcher.d.ts +24 -0
  57. package/dist-native/AvoBatcher.js +82 -0
  58. package/dist-native/AvoDeduplicator.d.ts +36 -0
  59. package/dist-native/AvoDeduplicator.js +142 -0
  60. package/dist-native/AvoGuid.d.ts +3 -0
  61. package/dist-native/AvoGuid.js +14 -0
  62. package/dist-native/AvoInspector.d.ts +52 -0
  63. package/dist-native/AvoInspector.js +220 -0
  64. package/dist-native/AvoInspectorEnv.d.ts +7 -0
  65. package/dist-native/AvoInspectorEnv.js +8 -0
  66. package/dist-native/AvoInstallationId.d.ts +5 -0
  67. package/dist-native/AvoInstallationId.js +36 -0
  68. package/dist-native/AvoNetworkCallsHandler.d.ts +48 -0
  69. package/dist-native/AvoNetworkCallsHandler.js +142 -0
  70. package/dist-native/AvoSchemaParser.d.ts +11 -0
  71. package/dist-native/AvoSchemaParser.js +95 -0
  72. package/dist-native/AvoSessionTracker.d.ts +15 -0
  73. package/dist-native/AvoSessionTracker.js +104 -0
  74. package/dist-native/AvoStorage.d.ts +22 -0
  75. package/dist-native/AvoStorage.js +336 -0
  76. package/dist-native/__mocks__/xhr.d.ts +12 -0
  77. package/dist-native/__mocks__/xhr.js +14 -0
  78. package/dist-native/__mocks__/xhrError.d.ts +12 -0
  79. package/dist-native/__mocks__/xhrError.js +14 -0
  80. package/dist-native/__tests__/AvoInspector.d.ts +1 -0
  81. package/dist-native/__tests__/AvoInspector.js +207 -0
  82. package/dist-native/__tests__/Batcher.d.ts +1 -0
  83. package/dist-native/__tests__/Batcher.js +280 -0
  84. package/dist-native/__tests__/BatcherPublic.d.ts +1 -0
  85. package/dist-native/__tests__/BatcherPublic.js +82 -0
  86. package/dist-native/__tests__/Deduplicator.d.ts +1 -0
  87. package/dist-native/__tests__/Deduplicator.js +111 -0
  88. package/dist-native/__tests__/InstallationId.d.ts +1 -0
  89. package/dist-native/__tests__/InstallationId.js +40 -0
  90. package/dist-native/__tests__/NetworkCallsHandler.d.ts +1 -0
  91. package/dist-native/__tests__/NetworkCallsHandler.js +132 -0
  92. package/dist-native/__tests__/Parsing.d.ts +1 -0
  93. package/dist-native/__tests__/Parsing.js +115 -0
  94. package/dist-native/__tests__/Sessions.d.ts +1 -0
  95. package/dist-native/__tests__/Sessions.js +179 -0
  96. package/dist-native/__tests__/Storage.d.ts +1 -0
  97. package/dist-native/__tests__/Storage.js +173 -0
  98. package/dist-native/__tests__/constants.d.ts +36 -0
  99. package/dist-native/__tests__/constants.js +47 -0
  100. package/dist-native/index.d.ts +2 -0
  101. package/dist-native/index.js +7 -0
  102. package/dist-native/utils.d.ts +3 -0
  103. package/dist-native/utils.js +42 -0
  104. package/jest.config.js +6 -0
  105. package/package.json +8 -2
  106. package/webpack.browserConfig.js +1 -1
  107. package/webpack.config.js +1 -1
  108. package/.claude/settings.local.json +0 -9
package/CHANGELOG.md CHANGED
@@ -1,3 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.2.1-alpha] - 2025-11-24
9
+
10
+ ### Added
11
+
12
+ - **ECC Property Value Encryption**: Optional `publicEncryptionKey` parameter on SDK initialization enables zero-knowledge encryption of property values in dev/staging environments using ECIES (Elliptic Curve Integrated Encryption Scheme). Avo never has access to the private key, ensuring complete data privacy.
13
+ - Uses secp256k1 curve with AES-256-GCM for hybrid encryption
14
+ - Only encrypts in dev/staging environments (production sends schema only)
15
+ - Adds optional `encryptedPropertyValue` field to event schema
16
+ - CLI tool for key generation: `npx avo-inspector generate-keys`
17
+ - Note: Key generation and decryption are not exported from SDK (use CLI tool for keys, decryption happens in Avo's dashboard)
18
+
19
+ - **EventSpec Fetching**: Automatically fetches and caches event specifications from Avo API in dev/staging environments
20
+ - Non-blocking async API calls
21
+ - In-memory caching for performance
22
+ - NOT called in production (prod remains simple and fast)
23
+ - Foundation for Phase 2: event validation
24
+
25
+ ### Changed
26
+
27
+ - Production environment now optimized: no property values, no encryption, no EventSpec API calls
28
+ - Dev/Staging environments now support rich debugging with encrypted values and event specs
29
+
30
+ ### Dependencies
31
+
32
+ - Added `eciesjs` ^0.4.11 for ECC/ECIES encryption
33
+
1
34
  ## 2.2.0
2
35
 
3
36
  - Add anonymous ID support to track events without user identification
@@ -22,4 +55,4 @@ Security update
22
55
 
23
56
  ## 1.3.0
24
57
 
25
- Multiple Avo Inspector instances support, with the optional `suffix` constructor parameter
58
+ Multiple Avo Inspector instances support, with the optional `suffix` constructor parameter
package/README.md CHANGED
@@ -98,6 +98,101 @@ let schema = inspector.extractSchema({
98
98
 
99
99
  You can experiment with this method to see how more complex schemas look, for example with nested lists and objects.
100
100
 
101
+ # Property Value Encryption (Dev/Staging Only)
102
+
103
+ Inspector supports encrypting property values in development and staging environments. This allows you to see actual property values in Avo's debugging tools without exposing sensitive data, since only you hold the private decryption key.
104
+
105
+ ## Key Features
106
+
107
+ - Uses ECC (Elliptic Curve Cryptography) with secp256k1 for strong security
108
+ - Zero-knowledge architecture: Avo never has access to your private key
109
+ - No message size limitations
110
+ - Only active in dev/staging environments (production is unaffected)
111
+
112
+ ## Generating Keys
113
+
114
+ Use the built-in CLI tool to generate a key pair:
115
+
116
+ ```bash
117
+ npx avo-inspector generate-keys
118
+ ```
119
+
120
+ This will output:
121
+ - **Public key**: Pass this to the SDK to enable encryption
122
+ - **Private key**: Save this externally (you'll use it to decrypt values in Avo's dashboard)
123
+
124
+ ## Using Encryption
125
+
126
+ Pass the `publicKey` parameter when initializing Inspector:
127
+
128
+ ```javascript
129
+ import * as Inspector from "avo-inspector";
130
+
131
+ let inspector = new Inspector.AvoInspector({
132
+ apiKey: "your api key",
133
+ env: Inspector.AvoInspectorEnv.Dev,
134
+ version: "1.0.0",
135
+ publicEncryptionKey: "your-public-key-hex-string" // Enable encryption
136
+ });
137
+ ```
138
+
139
+ **Note:** The public key is not a secret - you can hardcode it, store it in `.env`, or configure it however you prefer. The SDK only uses the public key to encrypt values before sending them to Avo.
140
+
141
+ **Private key:** Save it securely (password manager, secure notes). Never expose it to the SDK. You only need it when viewing encrypted values in Avo's dashboard.
142
+
143
+ When encryption is enabled:
144
+ - Property values are encrypted before being sent to Avo
145
+ - You can decrypt them in Avo's dashboard using your private key
146
+ - Works with all data types: strings, numbers, booleans, objects, arrays, null
147
+ - Handles large payloads (1KB+) without issues
148
+
149
+ # Client-Side Validation (Dev/Staging Only)
150
+
151
+ When initialized with a `publicKey` in dev or staging environments, Inspector performs client-side validation of your events against your Avo Tracking Plan.
152
+
153
+ ## How It Works
154
+
155
+ 1. **Event Spec Fetching**: When you track an event, Inspector fetches the event specification from Avo's backend (results are cached for performance).
156
+
157
+ 2. **Event Matching**: Inspector matches your event to the closest event in your tracking plan, considering event names, mapped names, and variant-specific properties.
158
+
159
+ 3. **Property Validation**: Your event properties are validated against the spec rules:
160
+ - Required properties are present
161
+ - Property types match (string, int, float, boolean, object, list)
162
+ - Numeric values are within min/max bounds
163
+ - String values match regex patterns
164
+ - Enum values are in the allowed list
165
+ - Pinned values match exactly (variant-specific fixed values)
166
+ - No unexpected properties are sent
167
+
168
+ 4. **Immediate Reporting**: Validated events bypass batching and are sent immediately to Inspector, ensuring you get real-time feedback.
169
+
170
+ ## Validation Errors
171
+
172
+ If logging is enabled, validation errors are logged to the console:
173
+
174
+ ```javascript
175
+ inspector.enableLogging(true);
176
+
177
+ // If "User Signed Up" requires an "email" property:
178
+ inspector.trackSchemaFromEvent("User Signed Up", { name: "John" });
179
+ // Console: [Avo Inspector] Validation errors for event "User Signed Up": [{ code: "RequiredMissing", propertyName: "email" }]
180
+ ```
181
+
182
+ ## Important: trackSchema Does Not Validate
183
+
184
+ **Note:** Client-side validation only works with `trackSchemaFromEvent`, which has access to actual property values needed for validation.
185
+
186
+ The `trackSchema` method only sends pre-extracted schemas and **does not perform client-side validation** - it goes through the normal batching flow.
187
+
188
+ ```javascript
189
+ // ✅ Validates against tracking plan (when publicKey is provided)
190
+ inspector.trackSchemaFromEvent("Event Name", { prop: "value" });
191
+
192
+ // ❌ Does NOT validate - only sends schema, uses batching
193
+ inspector.trackSchema("Event Name", [{ propertyName: "prop", propertyType: "string" }]);
194
+ ```
195
+
101
196
  # Batching control
102
197
 
103
198
  In order to ensure our SDK doesn't have a large impact on performance or battery life it supports event schemas batching.
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Use eciesjs directly for ECC key generation
4
+ const { PrivateKey } = require('eciesjs');
5
+
6
+ function generateKeyPair() {
7
+ // Generate a new random private key (32 bytes / 256 bits)
8
+ const privateKey = new PrivateKey();
9
+
10
+ // Derive the public key from the private key
11
+ const publicKey = privateKey.publicKey;
12
+
13
+ return {
14
+ publicKey: publicKey.toHex(),
15
+ privateKey: privateKey.toHex()
16
+ };
17
+ }
18
+
19
+ const command = process.argv[2];
20
+
21
+ function showHelp() {
22
+ console.log(`
23
+ ╔═══════════════════════════════════════════════════════════════╗
24
+ ║ AVO INSPECTOR CLI ║
25
+ ╚═══════════════════════════════════════════════════════════════╝
26
+
27
+ Usage:
28
+ npx avo-inspector <command>
29
+
30
+ Commands:
31
+ generate-keys Generate ECC key pair for property encryption
32
+ help Show this help message
33
+
34
+ Examples:
35
+ npx avo-inspector generate-keys
36
+ `);
37
+ }
38
+
39
+ function generateKeys() {
40
+ console.log(`
41
+ ╔═══════════════════════════════════════════════════════════════╗
42
+ ║ Generating ECC Key Pair (secp256k1)... ║
43
+ ╚═══════════════════════════════════════════════════════════════╝
44
+ `);
45
+
46
+ try {
47
+ const { publicKey, privateKey } = generateKeyPair();
48
+
49
+ console.log('✅ Key pair generated successfully!\n');
50
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
51
+ console.log('📋 PUBLIC KEY (safe to share with Avo SDK):\n');
52
+ console.log(publicKey);
53
+ console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
54
+ console.log('🔐 PRIVATE KEY (⚠️ KEEP SECURE - DO NOT COMMIT TO GIT):\n');
55
+ console.log(privateKey);
56
+ console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
57
+ console.log('📝 Next Steps:\n');
58
+ console.log('1. Use the PUBLIC KEY in your SDK initialization:\n');
59
+ console.log(' const inspector = new AvoInspector({');
60
+ console.log(' apiKey: "your-api-key",');
61
+ console.log(' env: AvoInspectorEnv.Dev,');
62
+ console.log(' version: "1.0.0",');
63
+ console.log(' publicKey: "<paste public key above>"');
64
+ console.log(' });\n');
65
+ console.log(' 💡 The public key is not a secret - you can hardcode it or use .env\n');
66
+ console.log('2. Save the PRIVATE KEY externally (password manager, secure notes)');
67
+ console.log(' - The SDK never uses the private key');
68
+ console.log(' - You only need it to decrypt values in Avo\'s dashboard\n');
69
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
70
+ console.log('ℹ️ Note: Property encryption only works in dev/staging environments.');
71
+ console.log(' Production data is never encrypted for performance.\n');
72
+ } catch (error) {
73
+ console.error('❌ Error generating keys:', error.message);
74
+ process.exit(1);
75
+ }
76
+ }
77
+
78
+ // Main command router
79
+ switch (command) {
80
+ case 'generate-keys':
81
+ generateKeys();
82
+ break;
83
+ case 'help':
84
+ case '--help':
85
+ case '-h':
86
+ showHelp();
87
+ break;
88
+ case undefined:
89
+ console.error('❌ No command specified\n');
90
+ showHelp();
91
+ process.exit(1);
92
+ break;
93
+ default:
94
+ console.error(`❌ Unknown command: ${command}\n`);
95
+ showHelp();
96
+ process.exit(1);
97
+ }
@@ -1,11 +1,13 @@
1
1
  import { type AvoNetworkCallsHandler } from "./AvoNetworkCallsHandler";
2
+ import type { EventSpecMetadata } from "./eventSpec/AvoEventSpecFetchTypes";
3
+ import type { ValidationIssue } from "./eventSpec/EventValidator";
2
4
  export interface AvoBatcherType {
3
5
  handleSessionStarted: () => void;
4
6
  handleTrackSchema: (eventName: string, schema: Array<{
5
7
  propertyName: string;
6
8
  propertyType: string;
7
9
  children?: any;
8
- }>, eventId: string | null, eventHash: string | null) => void;
10
+ }>, eventId: string | null, eventHash: string | null, variantId?: string | null, eventSpecMetadata?: EventSpecMetadata, validationErrors?: ValidationIssue[]) => void;
9
11
  }
10
12
  export declare class AvoBatcher implements AvoBatcherType {
11
13
  private events;
@@ -17,7 +19,7 @@ export declare class AvoBatcher implements AvoBatcherType {
17
19
  propertyName: string;
18
20
  propertyType: string;
19
21
  children?: any;
20
- }>, eventId: string | null, eventHash: string | null): void;
22
+ }>, eventId: string | null, eventHash: string | null, variantId?: string | null, eventSpecMetadata?: EventSpecMetadata, validationErrors?: ValidationIssue[]): void;
21
23
  private checkIfBatchNeedsToBeSent;
22
24
  private saveEvents;
23
25
  static get cacheKey(): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Generates a new ECC key pair for encryption/decryption.
3
+ * Uses secp256k1 curve (P-256 family) which provides 128-bit security.
4
+ *
5
+ * @returns An object containing the private and public keys as hex strings
6
+ */
7
+ export declare function generateKeyPair(): {
8
+ privateKey: string;
9
+ publicKey: string;
10
+ };
11
+ /**
12
+ * Encrypts a value using ECC public key encryption (ECIES).
13
+ * The encrypted output can only be decrypted by the client using their private key.
14
+ * This ensures that Avo cannot decrypt the values on the backend.
15
+ *
16
+ * ECIES uses hybrid encryption (ECDH + AES-256-GCM) which provides:
17
+ * - No message size limitations
18
+ * - Fast encryption even for large values
19
+ * - Strong authentication via GCM
20
+ *
21
+ * @param value - The value to encrypt (any type - will be JSON stringified)
22
+ * @param publicKey - The ECC public key in hex format provided by the client
23
+ * @returns Base64-encoded encrypted string that can only be decrypted with the private key
24
+ */
25
+ export declare function encryptValue(value: any, publicKey: string): string;
26
+ /**
27
+ * Decrypts a value that was encrypted with encryptValue.
28
+ *
29
+ * @param encryptedValue - The base64-encoded encrypted string
30
+ * @param privateKey - The ECC private key in hex format
31
+ * @returns The original decrypted value (parsed from JSON)
32
+ */
33
+ export declare function decryptValue(encryptedValue: string, privateKey: string): any;
@@ -8,6 +8,11 @@ export declare class AvoInspector {
8
8
  avoDeduplicator: AvoDeduplicator;
9
9
  apiKey: string;
10
10
  version: string;
11
+ private avoNetworkCallsHandler;
12
+ private publicEncryptionKey?;
13
+ private streamId?;
14
+ private eventSpecCache?;
15
+ private eventSpecFetcher?;
11
16
  static avoStorage: AvoStorage;
12
17
  private static _batchSize;
13
18
  static get batchSize(): number;
@@ -26,25 +31,48 @@ export declare class AvoInspector {
26
31
  version: string;
27
32
  appName?: string;
28
33
  suffix?: string;
34
+ publicEncryptionKey?: string;
29
35
  });
30
- trackSchemaFromEvent(eventName: string, eventProperties: Record<string, any>): Array<{
36
+ trackSchemaFromEvent(eventName: string, eventProperties: Record<string, any>): Promise<Array<{
31
37
  propertyName: string;
32
38
  propertyType: string;
39
+ encryptedPropertyValue?: string;
33
40
  children?: any;
34
- }>;
41
+ }>>;
35
42
  private _avoFunctionTrackSchemaFromEvent;
36
43
  trackSchema(eventName: string, eventSchema: Array<{
37
44
  propertyName: string;
38
45
  propertyType: string;
46
+ encryptedPropertyValue?: string;
39
47
  children?: any;
40
- }>): void;
48
+ }>): Promise<void>;
41
49
  private trackSchemaInternal;
42
50
  enableLogging(enable: boolean): void;
43
51
  extractSchema(eventProperties: Record<string, any>, shouldLogIfEnabled?: boolean): Array<{
44
52
  propertyName: string;
45
53
  propertyType: string;
54
+ encryptedPropertyValue?: string;
46
55
  children?: any;
47
56
  }>;
48
57
  setBatchSize(newBatchSize: number): void;
49
58
  setBatchFlushSeconds(newBatchFlushSeconds: number): void;
59
+ /**
60
+ * Fetches the event spec if spec fetching is enabled.
61
+ * Used by trackSchema when we don't have raw properties to validate.
62
+ *
63
+ * Note: EventSpec fetching only happens in dev/staging environments.
64
+ */
65
+ private fetchEventSpecIfNeeded;
66
+ /**
67
+ * Fetches event spec and validates the event against it.
68
+ * Returns ValidationResult if spec is available, null otherwise.
69
+ *
70
+ * Note: EventSpec fetching and validation only happens in dev/staging environments.
71
+ */
72
+ private fetchAndValidateEvent;
73
+ /**
74
+ * Sends an event immediately with validation data (bypasses batching).
75
+ * Logs validation errors if shouldLog is true.
76
+ */
77
+ private sendEventWithValidation;
50
78
  }
@@ -1,3 +1,5 @@
1
+ import type { EventSpecMetadata } from "./eventSpec/AvoEventSpecFetchTypes";
2
+ import type { ValidationIssue } from "./eventSpec/EventValidator";
1
3
  export interface BaseBody {
2
4
  apiKey: string;
3
5
  appName: string;
@@ -17,14 +19,23 @@ export interface SessionStartedBody extends BaseBody {
17
19
  }
18
20
  export interface EventSchemaBody extends BaseBody {
19
21
  type: "event";
20
- eventName: string;
22
+ /** ID of the matched base event */
23
+ eventId: string | null;
24
+ /** ID of the matched variant (if any) */
25
+ variantId?: string | null;
26
+ /** Name seen in code */
27
+ eventName?: string;
28
+ /** Event spec metadata from EventSpecResponse */
29
+ eventSpecMetadata?: EventSpecMetadata;
30
+ /** Array of validation issues found during validation */
31
+ validationErrors?: ValidationIssue[];
21
32
  eventProperties: Array<{
22
33
  propertyName: string;
23
34
  propertyType: string;
35
+ encryptedPropertyValue?: string;
24
36
  children?: any;
25
37
  }>;
26
38
  avoFunction: boolean;
27
- eventId: string | null;
28
39
  eventHash: string | null;
29
40
  }
30
41
  export declare class AvoNetworkCallsHandler {
@@ -44,6 +55,20 @@ export declare class AvoNetworkCallsHandler {
44
55
  propertyName: string;
45
56
  propertyType: string;
46
57
  children?: any;
47
- }>, eventId: string | null, eventHash: string | null): EventSchemaBody;
58
+ }>, eventId: string | null, eventHash: string | null, variantId?: string | null, eventSpecMetadata?: EventSpecMetadata, validationErrors?: ValidationIssue[]): EventSchemaBody;
48
59
  private createBaseCallBody;
60
+ /**
61
+ * Calls Inspector API immediately with a single event (bypasses batching).
62
+ * Used when event spec validation is available.
63
+ * Note: Does not drop due to sampling - validated events are always sent.
64
+ */
65
+ callInspectorImmediately(eventBody: EventSchemaBody, onCompleted: (error: Error | null) => any): void;
66
+ /**
67
+ * Check if event should be dropped based on sampling rate.
68
+ */
69
+ private shouldDropBySampling;
70
+ /**
71
+ * Core Inspector API call logic shared by batch and immediate calls.
72
+ */
73
+ private callInspectorApi;
49
74
  }
@@ -1,7 +1,18 @@
1
1
  export declare class AvoSchemaParser {
2
- static extractSchema(eventProperties: Record<string, any>): Array<{
2
+ /**
3
+ * Returns true only if we have a valid encryption key and can send encrypted values.
4
+ * If no key is present, returns false and no property values will be sent.
5
+ */
6
+ private static canSendEncryptedValues;
7
+ /**
8
+ * Returns the encrypted property value if encryption is enabled, otherwise undefined.
9
+ * Never returns unencrypted values - only encrypted or nothing.
10
+ */
11
+ private static getEncryptedPropertyValueIfEnabled;
12
+ static extractSchema(eventProperties: Record<string, any>, publicEncryptionKey?: string, env?: string): Array<{
3
13
  propertyName: string;
4
14
  propertyType: string;
15
+ encryptedPropertyValue?: string;
5
16
  children?: any;
6
17
  }>;
7
18
  private static removeDuplicates;
@@ -0,0 +1,5 @@
1
+ /*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) */
2
+
3
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
4
+
5
+ /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
@@ -0,0 +1,73 @@
1
+ import type { EventSpecResponse } from "./AvoEventSpecFetchTypes";
2
+ /**
3
+ * EventSpecCache implements a dual-condition cache with LRU eviction.
4
+ *
5
+ * Cache Policy:
6
+ * - Entries expire after 5 minutes OR 50 cache hits, whichever comes first
7
+ * - When 50 cache hits occur globally, the oldest cached entry is evicted
8
+ * - Each cache entry tracks: spec, timestamp, and hit count
9
+ *
10
+ * Cache Key Format: ${apiKey}:${streamId}:${eventName}
11
+ *
12
+ * Note: Event count only increments on cache hits, not on every tracked event.
13
+ * This ensures the cache evicts based on actual usage, not overall tracking volume.
14
+ */
15
+ export declare class EventSpecCache {
16
+ /** Cache storage: key -> CacheEntry */
17
+ private cache;
18
+ /** Time-to-live in milliseconds (5 minutes) */
19
+ private readonly TTL_MS;
20
+ /** Maximum cache hit count before rotating cache (50 hits) */
21
+ private readonly MAX_EVENT_COUNT;
22
+ /** Global cache hit counter to track when to rotate cache */
23
+ private globalEventCount;
24
+ /** Whether to log debug information */
25
+ private readonly shouldLog;
26
+ constructor(shouldLog?: boolean);
27
+ /**
28
+ * Generates a cache key from the provided parameters.
29
+ */
30
+ private generateKey;
31
+ /**
32
+ * Retrieves an event spec response from the cache if it exists and is valid.
33
+ * Returns null if the entry is missing, expired, or has exceeded event count.
34
+ *
35
+ * On cache hit, increments the hit count for this entry and the global counter.
36
+ */
37
+ get(apiKey: string, streamId: string, eventName: string): EventSpecResponse | null;
38
+ /**
39
+ * Stores an event spec response in the cache.
40
+ */
41
+ set(apiKey: string, streamId: string, eventName: string, spec: EventSpecResponse): void;
42
+ /**
43
+ * Determines if a cache entry should be evicted based on:
44
+ * - Age (older than 5 minutes)
45
+ * - Hit count (50 or more cache hits)
46
+ */
47
+ private shouldEvict;
48
+ /**
49
+ * Evicts the oldest cache entry based on timestamp.
50
+ * This implements the LRU (Least Recently Used) eviction policy.
51
+ */
52
+ private evictOldest;
53
+ /**
54
+ * Clears all cached entries. Useful for testing.
55
+ */
56
+ clear(): void;
57
+ /**
58
+ * Returns the current size of the cache.
59
+ */
60
+ size(): number;
61
+ /**
62
+ * Returns cache statistics for debugging.
63
+ */
64
+ getStats(): {
65
+ size: number;
66
+ globalEventCount: number;
67
+ entries: Array<{
68
+ key: string;
69
+ age: number;
70
+ eventCount: number;
71
+ }>;
72
+ };
73
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * This file is generated. Internal development changes should be made in the generator
3
+ * and the file should be re-generated. External contributions are welcome to submit
4
+ * changes directly to this file, and we'll apply them to the generator internally.
5
+ */
6
+ /**
7
+ * Represents the type specification for a property.
8
+ * Can be a primitive type or a nested object structure.
9
+ */
10
+ export interface PropertyTypeSpec {
11
+ /** The type category: "primitive" for simple types, "object" for nested structures */
12
+ type: "primitive" | "object";
13
+ /** For primitive: the type name (e.g., "string", "int"). For object: nested property specs */
14
+ value: string | Record<string, PropertySpec>;
15
+ }
16
+ /**
17
+ * Represents the specification for a single property in an event.
18
+ * Supports recursive nesting for object types.
19
+ */
20
+ export interface PropertySpec {
21
+ /** Unique identifier for this property */
22
+ id: string;
23
+ /** Type specification - contains type category and value */
24
+ t: PropertyTypeSpec;
25
+ /** Required flag */
26
+ r: boolean;
27
+ /** Is list (array) flag */
28
+ l?: boolean;
29
+ /** Minimum value (for numeric types) */
30
+ min?: number;
31
+ /** Maximum value (for numeric types) */
32
+ max?: number;
33
+ /** Enum values (allowed values for the property) */
34
+ v?: string[];
35
+ /** Regex pattern for string validation */
36
+ rx?: string;
37
+ }
38
+ /**
39
+ * Represents a variant of an event with additional or modified properties.
40
+ */
41
+ export interface VariantSpec {
42
+ /** Unique identifier for this variant */
43
+ variantId: string;
44
+ /** Event ID for this variant (base event id) */
45
+ eventId: string;
46
+ /** Suffix to append to the base event name */
47
+ nameSuffix: string;
48
+ /** Name of the variant in this source (if different from canonical name) */
49
+ mappedName?: string;
50
+ /** Properties specific to this variant */
51
+ props: Record<string, PropertySpec>;
52
+ }
53
+ /**
54
+ * Represents the complete specification for an event, including base event
55
+ * and optional variants.
56
+ */
57
+ export interface EventSpec {
58
+ /** Unique identifier for this event */
59
+ id: string;
60
+ /** Canonical Avo name for this event */
61
+ name: string;
62
+ /** Name of the event in this source (if different from canonical name) */
63
+ mappedName?: string;
64
+ /** Properties for this event */
65
+ props: Record<string, PropertySpec>;
66
+ /** Variants of this event with additional/modified properties */
67
+ variants: VariantSpec[];
68
+ }
69
+ /**
70
+ * Metadata returned with the event spec response.
71
+ */
72
+ export interface EventSpecMetadata {
73
+ /** Schema identifier */
74
+ schemaId: string;
75
+ /** Branch identifier */
76
+ branchId: string;
77
+ /** Latest action identifier (replaces versionId/createdAt) */
78
+ latestActionId: string;
79
+ /** Optional source identifier */
80
+ sourceId?: string;
81
+ }
82
+ /**
83
+ * Response structure from the getEventSpec endpoint.
84
+ * Contains an array of potential event matches (due to name mapping).
85
+ */
86
+ export interface EventSpecResponse {
87
+ /** Array of potential event matches */
88
+ events: EventSpec[];
89
+ /** Metadata about the schema and source */
90
+ metadata: EventSpecMetadata;
91
+ }
92
+ /** Cache entry for storing event specs with metadata. */
93
+ export interface EventSpecCacheEntry {
94
+ /** The cached event specification response */
95
+ spec: EventSpecResponse;
96
+ /** Timestamp when this entry was cached */
97
+ timestamp: number;
98
+ /** Number of events processed since this entry was cached */
99
+ eventCount: number;
100
+ }
101
+ /** Parameters for fetching event specifications from the API. */
102
+ export interface FetchEventSpecParams {
103
+ /** The API key */
104
+ apiKey: string;
105
+ /** The stream ID */
106
+ streamId: string;
107
+ /** The name of the event */
108
+ eventName: string;
109
+ }