@churnsignal/churnsignal-sdk-web 0.1.1 → 0.1.3
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 +65 -2
- package/dist/api-client.d.ts +0 -1
- package/dist/churnsignal-sdk-web.cjs.development.js +89 -31
- package/dist/churnsignal-sdk-web.cjs.development.js.map +1 -1
- package/dist/churnsignal-sdk-web.cjs.production.min.js +1 -1
- package/dist/churnsignal-sdk-web.cjs.production.min.js.map +1 -1
- package/dist/churnsignal-sdk-web.esm.js +89 -31
- package/dist/churnsignal-sdk-web.esm.js.map +1 -1
- package/dist/core/initialise.d.ts +4 -7
- package/dist/managers/sdk-instance-manager.d.ts +4 -3
- package/dist/utils/api-key-parser.d.ts +17 -0
- package/dist/utils/request-transformations.d.ts +1 -5
- package/package.json +1 -1
- package/src/api-client.ts +0 -6
- package/src/core/identify.ts +8 -0
- package/src/core/initialise.test.ts +14 -19
- package/src/core/initialise.ts +5 -13
- package/src/managers/sdk-instance-manager.ts +20 -14
- package/src/utils/api-key-parser.ts +76 -0
- package/src/utils/request-transformations.ts +4 -12
package/README.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
|
-
#
|
|
2
|
-
This SDK allows developers to seamlessly integrate
|
|
1
|
+
# CHURNSIGNAL SDK WEB
|
|
2
|
+
This SDK allows developers to seamlessly integrate ChurnSignal into their Web applications
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install @churnsignal/churnsignal-sdk-web
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
### Initialize the SDK
|
|
13
|
+
|
|
14
|
+
The SDK only requires your API key. All configuration (workspaceId, tenantId, baseUrl) is automatically extracted from the API key.
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { initialise, identify, track } from '@churnsignal/churnsignal-sdk-web';
|
|
18
|
+
|
|
19
|
+
// Initialize with your API key
|
|
20
|
+
const success = initialise(API_KEY);
|
|
21
|
+
|
|
22
|
+
if (success) {
|
|
23
|
+
console.log('SDK initialized successfully');
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Identify a User
|
|
28
|
+
|
|
29
|
+
Before tracking events, you need to identify the user:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
identify({ email: 'user@example.com' });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Track Events
|
|
36
|
+
|
|
37
|
+
Track user events with optional properties:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Track a simple event
|
|
41
|
+
track('button_clicked');
|
|
42
|
+
|
|
43
|
+
// Track an event with properties
|
|
44
|
+
track('purchase_completed', {
|
|
45
|
+
productId: '123',
|
|
46
|
+
amount: 99.99,
|
|
47
|
+
currency: 'USD'
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Complete Example
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { initialise, identify, track } from '@churnsignal/churnsignal-sdk-web';
|
|
55
|
+
|
|
56
|
+
// Initialize
|
|
57
|
+
initialise('your-api-key-here');
|
|
58
|
+
|
|
59
|
+
// Identify user
|
|
60
|
+
identify({ email: 'user@example.com' });
|
|
61
|
+
|
|
62
|
+
// Track events
|
|
63
|
+
track('page_viewed', { page: '/home' });
|
|
64
|
+
track('product_viewed', { productId: 'abc123' });
|
|
65
|
+
```
|
|
3
66
|
|
|
4
67
|
## Commands
|
|
5
68
|
|
package/dist/api-client.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ declare class ApiClient {
|
|
|
14
14
|
private apiKey;
|
|
15
15
|
private baseUrl?;
|
|
16
16
|
private workspaceId;
|
|
17
|
-
private tenantId?;
|
|
18
17
|
private user?;
|
|
19
18
|
constructor({ apiKey, baseUrl, config }: ApiClientProps);
|
|
20
19
|
fetchWithConfig: (endpoint: string, options?: RequestInit) => Promise<Response>;
|
|
@@ -28,6 +28,62 @@ var sanitiseUrl = function sanitiseUrl(url) {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
var DEFAULT_BASE_URLS = {
|
|
32
|
+
live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Parses an API key to extract workspaceId, tenantId, and baseUrl
|
|
36
|
+
* Expected format: cs_{environment}_tenantId_workspaceId_secret
|
|
37
|
+
* Matches backend parsing logic
|
|
38
|
+
*
|
|
39
|
+
* @param apiKey - The API key to parse
|
|
40
|
+
* @returns ParsedApiKey object with extracted data
|
|
41
|
+
* @throws Error if the API key format is invalid
|
|
42
|
+
*/
|
|
43
|
+
var parseApiKey = function parseApiKey(apiKey) {
|
|
44
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
45
|
+
throw new Error('API key must be a non-empty string');
|
|
46
|
+
}
|
|
47
|
+
// Check if it starts with cs_ prefix
|
|
48
|
+
if (!apiKey.startsWith('cs_')) {
|
|
49
|
+
throw new Error('Invalid API key format. Must start with "cs_"');
|
|
50
|
+
}
|
|
51
|
+
// Find the environment (cs_live_, cs_test_, cs_dev_, etc.)
|
|
52
|
+
var parts = apiKey.split('_');
|
|
53
|
+
if (parts.length < 2) {
|
|
54
|
+
throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');
|
|
55
|
+
}
|
|
56
|
+
var environment = parts[1];
|
|
57
|
+
var prefix = "cs_" + environment + "_";
|
|
58
|
+
if (!apiKey.startsWith(prefix)) {
|
|
59
|
+
throw new Error("Invalid API key format. Must start with \"" + prefix + "\"");
|
|
60
|
+
}
|
|
61
|
+
// Remove prefix (e.g., 'cs_live_')
|
|
62
|
+
var withoutPrefix = apiKey.substring(prefix.length);
|
|
63
|
+
// Split by underscore - format: tenantId_workspaceId_secret
|
|
64
|
+
var keyParts = withoutPrefix.split('_');
|
|
65
|
+
if (keyParts.length < 3) {
|
|
66
|
+
throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');
|
|
67
|
+
}
|
|
68
|
+
var tenantId = keyParts[0];
|
|
69
|
+
var workspaceId = keyParts[1];
|
|
70
|
+
// The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing
|
|
71
|
+
if (!tenantId) {
|
|
72
|
+
throw new Error('Tenant ID not found in API key');
|
|
73
|
+
}
|
|
74
|
+
if (!workspaceId) {
|
|
75
|
+
throw new Error('Workspace ID not found in API key');
|
|
76
|
+
}
|
|
77
|
+
// Determine baseUrl from environment
|
|
78
|
+
var baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;
|
|
79
|
+
return {
|
|
80
|
+
environment: environment,
|
|
81
|
+
workspaceId: workspaceId,
|
|
82
|
+
tenantId: tenantId,
|
|
83
|
+
baseUrl: baseUrl
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
31
87
|
function _extends() {
|
|
32
88
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
33
89
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -46,16 +102,12 @@ function _extends() {
|
|
|
46
102
|
var transformTrackRequestData = function transformTrackRequestData(_ref) {
|
|
47
103
|
var eventName = _ref.eventName,
|
|
48
104
|
eventProperties = _ref.eventProperties,
|
|
49
|
-
userProperties = _ref.userProperties
|
|
50
|
-
configProperties = _ref.configProperties;
|
|
105
|
+
userProperties = _ref.userProperties;
|
|
51
106
|
var transformedEvent = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
workspaceId: configProperties.workspaceId,
|
|
57
|
-
type: 'event',
|
|
58
|
-
data: eventProperties
|
|
107
|
+
type: eventName,
|
|
108
|
+
data: eventProperties || {},
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
userEmail: userProperties == null ? void 0 : userProperties.email
|
|
59
111
|
};
|
|
60
112
|
return JSON.stringify(transformedEvent);
|
|
61
113
|
};
|
|
@@ -98,7 +150,6 @@ var ApiClient = /*#__PURE__*/function () {
|
|
|
98
150
|
this.apiKey = apiKey;
|
|
99
151
|
this.baseUrl = baseUrl;
|
|
100
152
|
this.workspaceId = config.workspaceId;
|
|
101
|
-
this.tenantId = config.tenantId;
|
|
102
153
|
}
|
|
103
154
|
var _proto = ApiClient.prototype;
|
|
104
155
|
_proto.getApiKey = function getApiKey() {
|
|
@@ -131,10 +182,6 @@ var ApiClient = /*#__PURE__*/function () {
|
|
|
131
182
|
body: transformTrackRequestData({
|
|
132
183
|
eventName: eventName,
|
|
133
184
|
eventProperties: eventProperties,
|
|
134
|
-
configProperties: {
|
|
135
|
-
workspaceId: this.getWorkspaceId(),
|
|
136
|
-
tenantId: this.tenantId
|
|
137
|
-
},
|
|
138
185
|
userProperties: {
|
|
139
186
|
email: this.user.email
|
|
140
187
|
}
|
|
@@ -162,31 +209,33 @@ var SDKInstanceManager = /*#__PURE__*/function () {
|
|
|
162
209
|
/**
|
|
163
210
|
* @throws Error in case validation of parameters fails
|
|
164
211
|
* @param apiKey - required string value representing the API key
|
|
165
|
-
*
|
|
166
|
-
*
|
|
212
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
213
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
214
|
+
* but the original unparsed API key is sent to the API in requests
|
|
167
215
|
* @returns void
|
|
168
216
|
*/
|
|
169
217
|
var _proto = SDKInstanceManager.prototype;
|
|
170
|
-
_proto.initialise = function initialise(apiKey
|
|
218
|
+
_proto.initialise = function initialise(apiKey) {
|
|
171
219
|
if (this.getIsInitialised()) {
|
|
172
220
|
console.info('SDK is already initialised with API key');
|
|
173
221
|
return;
|
|
174
222
|
}
|
|
175
223
|
if (!apiKey || typeof apiKey !== 'string') {
|
|
176
|
-
throw new Error('SDK needs a valid API key to be
|
|
177
|
-
}
|
|
178
|
-
if (!baseUrl || typeof baseUrl !== 'string' || !isValidUrl(baseUrl)) {
|
|
179
|
-
throw new Error('SDK needs a valid base URL to be initialised');
|
|
180
|
-
}
|
|
181
|
-
if (!config.workspaceId) {
|
|
182
|
-
throw new Error('Workspace ID must be provided');
|
|
224
|
+
throw new Error('SDK needs a valid API key to be initialised');
|
|
183
225
|
}
|
|
184
|
-
|
|
185
|
-
|
|
226
|
+
// Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration
|
|
227
|
+
// The original unparsed API key will be sent to the API
|
|
228
|
+
var parsed = parseApiKey(apiKey);
|
|
229
|
+
this.config = {
|
|
230
|
+
workspaceId: parsed.workspaceId,
|
|
231
|
+
tenantId: parsed.tenantId
|
|
232
|
+
};
|
|
233
|
+
var sanitisedUrl = sanitiseUrl(parsed.baseUrl);
|
|
234
|
+
// Pass the original unparsed API key to ApiClient - it will be sent as-is to the API
|
|
186
235
|
this.apiClient = new ApiClient({
|
|
187
236
|
apiKey: apiKey,
|
|
188
237
|
baseUrl: sanitisedUrl,
|
|
189
|
-
config: config
|
|
238
|
+
config: this.config
|
|
190
239
|
});
|
|
191
240
|
this.isInitialised = true;
|
|
192
241
|
};
|
|
@@ -211,13 +260,14 @@ var instance = /*#__PURE__*/new SDKInstanceManager();
|
|
|
211
260
|
|
|
212
261
|
/**
|
|
213
262
|
* @param apiKey - required string value representing the API key
|
|
214
|
-
*
|
|
215
|
-
*
|
|
263
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
264
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
265
|
+
* but the original unparsed API key is sent to the API in requests
|
|
216
266
|
* @returns boolean indicating whether the initialisation of the sdk was successful or not
|
|
217
267
|
*/
|
|
218
|
-
var initialise = function initialise(apiKey
|
|
268
|
+
var initialise = function initialise(apiKey) {
|
|
219
269
|
try {
|
|
220
|
-
instance.initialise(apiKey
|
|
270
|
+
instance.initialise(apiKey);
|
|
221
271
|
return true;
|
|
222
272
|
} catch (e) {
|
|
223
273
|
console.info(e == null ? void 0 : e.message);
|
|
@@ -227,6 +277,14 @@ var initialise = function initialise(apiKey, baseUrl, config) {
|
|
|
227
277
|
|
|
228
278
|
var identify = function identify(user) {
|
|
229
279
|
var _sdkInstanceManager$g;
|
|
280
|
+
if (!instance.getIsInitialised()) {
|
|
281
|
+
console.error('SDK must be initialised first');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (!(user != null && user.email)) {
|
|
285
|
+
console.error('User email must be provided');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
230
288
|
(_sdkInstanceManager$g = instance.getApiClient()) == null || _sdkInstanceManager$g.identify(user);
|
|
231
289
|
};
|
|
232
290
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"churnsignal-sdk-web.cjs.development.js","sources":["../src/utils/url-validator.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/initialise.ts","../src/core/identify.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n };\n configProperties: {\n workspaceId: string;\n tenantId?: string\n };\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n configProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n name: eventName,\n timestamp: new Date().getTime().toString(),\n userEmail: userProperties?.email,\n tenantId: configProperties.tenantId, // TODO this will be handled on the API side, for now pass it in SDK setup\n workspaceId: configProperties.workspaceId,\n type: 'event',\n data: eventProperties,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private tenantId?: string;\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n this.tenantId = config.tenantId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n configProperties: {\n workspaceId: this.getWorkspaceId(),\n tenantId: this.tenantId,\n },\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { isValidUrl, sanitiseUrl } from '../utils/url-validator';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param config - required object value\n * @returns void\n */\n initialise(apiKey: string, baseUrl: string, config: Config) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be inialised');\n }\n if (!baseUrl || typeof baseUrl !== 'string' || !isValidUrl(baseUrl)) {\n throw new Error('SDK needs a valid base URL to be initialised');\n }\n if (!config.workspaceId) {\n throw new Error('Workspace ID must be provided');\n }\n this.config = config;\n let sanitisedUrl = sanitiseUrl(baseUrl);\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\nexport type InitConfig = {\n workspaceId: string\n tenantId: string; // TODO to be removed should be done on the API side\n};\n\n/**\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param options - optional object value\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (\n apiKey: string,\n baseUrl: string,\n config: InitConfig\n) => {\n try {\n sdkInstanceManager.initialise(apiKey, baseUrl, config);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","isValidUrl","url","test","sanitiseUrl","sanitisedUrl","trim","Error","urlObject","URL","hostname","toLowerCase","pathname","replace","toString","e","transformTrackRequestData","_ref","eventName","eventProperties","userProperties","configProperties","transformedEvent","name","timestamp","Date","getTime","userEmail","email","tenantId","workspaceId","type","data","JSON","stringify","sdkConfig","defaultHeaders","API_PREFIX","TRACK_ENDPOINT","ApiClient","apiKey","baseUrl","config","endpoint","options","method","_this","getBaseUrl","headers","_extends","getApiKey","fetch","_proto","prototype","getWorkspaceId","getUser","user","identify","track","fetchWithConfig","body","SDKInstanceManager","instance","isInitialised","initialise","getIsInitialised","console","info","apiClient","destroy","getApiClient","getConfig","sdkInstanceManager","message","_sdkInstanceManager$g","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"churnsignal-sdk-web.cjs.development.js","sources":["../src/utils/url-validator.ts","../src/utils/api-key-parser.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/initialise.ts","../src/core/identify.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","type ParsedApiKey = {\n environment: string;\n workspaceId: string;\n tenantId: string;\n baseUrl: string;\n};\n\nconst DEFAULT_BASE_URLS: Record<string, string> = {\n live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'\n};\n\n/**\n * Parses an API key to extract workspaceId, tenantId, and baseUrl\n * Expected format: cs_{environment}_tenantId_workspaceId_secret\n * Matches backend parsing logic\n * \n * @param apiKey - The API key to parse\n * @returns ParsedApiKey object with extracted data\n * @throws Error if the API key format is invalid\n */\nexport const parseApiKey = (apiKey: string): ParsedApiKey => {\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a non-empty string');\n }\n\n // Check if it starts with cs_ prefix\n if (!apiKey.startsWith('cs_')) {\n throw new Error('Invalid API key format. Must start with \"cs_\"');\n }\n\n // Find the environment (cs_live_, cs_test_, cs_dev_, etc.)\n const parts = apiKey.split('_');\n if (parts.length < 2) {\n throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');\n }\n\n const environment = parts[1];\n const prefix = `cs_${environment}_`;\n \n if (!apiKey.startsWith(prefix)) {\n throw new Error(`Invalid API key format. Must start with \"${prefix}\"`);\n }\n\n // Remove prefix (e.g., 'cs_live_')\n const withoutPrefix = apiKey.substring(prefix.length);\n\n // Split by underscore - format: tenantId_workspaceId_secret\n const keyParts = withoutPrefix.split('_');\n\n if (keyParts.length < 3) {\n throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');\n }\n\n const tenantId = keyParts[0];\n const workspaceId = keyParts[1];\n // The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing\n\n if (!tenantId) {\n throw new Error('Tenant ID not found in API key');\n }\n\n if (!workspaceId) {\n throw new Error('Workspace ID not found in API key');\n }\n\n // Determine baseUrl from environment\n const baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;\n\n return {\n environment,\n workspaceId,\n tenantId,\n baseUrl,\n };\n};\n\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n }\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n type: eventName,\n data: eventProperties || {},\n timestamp: Date.now(),\n userEmail: userProperties?.email,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { sanitiseUrl } from '../utils/url-validator';\nimport { parseApiKey } from '../utils/api-key-parser';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns void\n */\n initialise(apiKey: string) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be initialised');\n }\n\n // Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration\n // The original unparsed API key will be sent to the API\n const parsed = parseApiKey(apiKey);\n \n this.config = {\n workspaceId: parsed.workspaceId,\n tenantId: parsed.tenantId,\n };\n \n const sanitisedUrl = sanitiseUrl(parsed.baseUrl);\n // Pass the original unparsed API key to ApiClient - it will be sent as-is to the API\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config: this.config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\n/**\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (apiKey: string) => {\n try {\n sdkInstanceManager.initialise(apiKey);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!user?.email) {\n console.error('User email must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","isValidUrl","url","test","sanitiseUrl","sanitisedUrl","trim","Error","urlObject","URL","hostname","toLowerCase","pathname","replace","toString","e","DEFAULT_BASE_URLS","live","parseApiKey","apiKey","startsWith","parts","split","length","environment","prefix","withoutPrefix","substring","keyParts","tenantId","workspaceId","baseUrl","transformTrackRequestData","_ref","eventName","eventProperties","userProperties","transformedEvent","type","data","timestamp","Date","now","userEmail","email","JSON","stringify","sdkConfig","defaultHeaders","API_PREFIX","TRACK_ENDPOINT","ApiClient","config","endpoint","options","method","_this","getBaseUrl","headers","_extends","getApiKey","fetch","_proto","prototype","getWorkspaceId","getUser","user","identify","track","fetchWithConfig","body","SDKInstanceManager","instance","isInitialised","initialise","getIsInitialised","console","info","parsed","apiClient","destroy","getApiClient","getConfig","sdkInstanceManager","message","error","_sdkInstanceManager$g"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=/^https?:\/\//,e=
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=/^https?:\/\//,e={live:"https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/"};function i(){return(i=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var r in i)Object.prototype.hasOwnProperty.call(i,r)&&(t[r]=i[r])}return t}).apply(this,arguments)}var r={"Content-Type":"application/json"},n=function(){function t(t){var e=this,n=t.apiKey,s=t.baseUrl,o=t.config;this.workspaceId="",this.fetchWithConfig=function(t,n){void 0===n&&(n={method:"GET"});var s=e.getBaseUrl()+"/"+t,o=i({},r,{"x-api-key":e.getApiKey()},n.headers||{}),a=i({},n,{headers:o});return fetch(s,a)},this.apiKey=n,this.baseUrl=s,this.workspaceId=o.workspaceId}var e=t.prototype;return e.getApiKey=function(){return this.apiKey},e.getBaseUrl=function(){return this.baseUrl},e.getWorkspaceId=function(){return this.workspaceId},e.getUser=function(){return this.user},e.identify=function(t){this.user=t},e.track=function(t,e){if(!this.user)throw new Error("No identified users to track");var i,r,n;this.fetchWithConfig("sdk-prod/track",{method:"POST",body:(i={eventName:t,eventProperties:e,userProperties:{email:this.user.email}},r=i.userProperties,n={type:i.eventName,data:i.eventProperties||{},timestamp:Date.now(),userEmail:null==r?void 0:r.email},JSON.stringify(n))})},t}(),s=new(function(){function i(){return this.isInitialised=!1,this.config={workspaceId:""},i.instance||(this.config={workspaceId:""},this.isInitialised=!1,i.instance=this),i.instance}var r=i.prototype;return r.initialise=function(i){if(this.getIsInitialised())console.info("SDK is already initialised with API key");else{if(!i||"string"!=typeof i)throw new Error("SDK needs a valid API key to be initialised");var r=function(t){if(!t||"string"!=typeof t)throw new Error("API key must be a non-empty string");if(!t.startsWith("cs_"))throw new Error('Invalid API key format. Must start with "cs_"');var i=t.split("_");if(i.length<2)throw new Error("Invalid API key format. Must include environment (e.g., cs_live_)");var r=i[1],n="cs_"+r+"_";if(!t.startsWith(n))throw new Error('Invalid API key format. Must start with "'+n+'"');var s=t.substring(n.length).split("_");if(s.length<3)throw new Error("Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret");var o=s[0],a=s[1];if(!o)throw new Error("Tenant ID not found in API key");if(!a)throw new Error("Workspace ID not found in API key");return{environment:r,workspaceId:a,tenantId:o,baseUrl:e[r]||e.live}}(i);this.config={workspaceId:r.workspaceId,tenantId:r.tenantId};var s=function(e){var i=e.trim();if(!function(e){return t.test(e)}(e))throw new Error("URL must start with 'http://' or 'https://'");try{var r=new URL(i);return r.hostname=r.hostname.toLowerCase(),"/"!==r.pathname&&(r.pathname=r.pathname.replace(/\/+$/,"")||""),r.toString().replace(/\/+$/,"")}catch(t){throw new Error("Invalid URL provided")}}(r.baseUrl);this.apiClient=new n({apiKey:i,baseUrl:s,config:this.config}),this.isInitialised=!0}},r.destroy=function(){this.config={workspaceId:""},this.isInitialised=!1},r.getIsInitialised=function(){return this.isInitialised},r.getApiClient=function(){return this.apiClient},r.getConfig=function(){return this.config},i}());exports.identify=function(t){var e;s.getIsInitialised()?null!=t&&t.email?null==(e=s.getApiClient())||e.identify(t):console.error("User email must be provided"):console.error("SDK must be initialised first")},exports.initialise=function(t){try{return s.initialise(t),!0}catch(t){return console.info(null==t?void 0:t.message),!1}},exports.track=function(t,e){var i;s.getIsInitialised()?t&&"string"==typeof t?null==(i=s.getApiClient())||i.track(t,e):console.error("Event name must be provided"):console.error("SDK must be initialised first")};
|
|
2
2
|
//# sourceMappingURL=churnsignal-sdk-web.cjs.production.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"churnsignal-sdk-web.cjs.production.min.js","sources":["../src/utils/url-validator.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/identify.ts","../src/core/initialise.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n };\n configProperties: {\n workspaceId: string;\n tenantId?: string\n };\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n configProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n name: eventName,\n timestamp: new Date().getTime().toString(),\n userEmail: userProperties?.email,\n tenantId: configProperties.tenantId, // TODO this will be handled on the API side, for now pass it in SDK setup\n workspaceId: configProperties.workspaceId,\n type: 'event',\n data: eventProperties,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private tenantId?: string;\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n this.tenantId = config.tenantId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n configProperties: {\n workspaceId: this.getWorkspaceId(),\n tenantId: this.tenantId,\n },\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { isValidUrl, sanitiseUrl } from '../utils/url-validator';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param config - required object value\n * @returns void\n */\n initialise(apiKey: string, baseUrl: string, config: Config) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be inialised');\n }\n if (!baseUrl || typeof baseUrl !== 'string' || !isValidUrl(baseUrl)) {\n throw new Error('SDK needs a valid base URL to be initialised');\n }\n if (!config.workspaceId) {\n throw new Error('Workspace ID must be provided');\n }\n this.config = config;\n let sanitisedUrl = sanitiseUrl(baseUrl);\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\nexport type InitConfig = {\n workspaceId: string\n tenantId: string; // TODO to be removed should be done on the API side\n};\n\n/**\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param options - optional object value\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (\n apiKey: string,\n baseUrl: string,\n config: InitConfig\n) => {\n try {\n sdkInstanceManager.initialise(apiKey, baseUrl, config);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","isValidUrl","url","test","transformTrackRequestData","_ref","eventProperties","userProperties","configProperties","transformedEvent","name","eventName","timestamp","Date","getTime","toString","userEmail","email","tenantId","workspaceId","type","data","JSON","stringify","sdkConfig","Content-Type","ApiClient","apiKey","baseUrl","config","this","endpoint","options","method","_this","getBaseUrl","headers","_extends","x-api-key","getApiKey","fetch","_proto","prototype","getWorkspaceId","getUser","user","identify","track","Error","fetchWithConfig","API_PREFIX","body","instance","SDKInstanceManager","isInitialised","initialise","getIsInitialised","console","info","sanitisedUrl","trim","urlObject","URL","hostname","toLowerCase","pathname","replace","e","sanitiseUrl","apiClient","destroy","getApiClient","getConfig","_sdkInstanceManager$g","sdkInstanceManager","message","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"churnsignal-sdk-web.cjs.production.min.js","sources":["../src/utils/url-validator.ts","../src/utils/api-key-parser.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/identify.ts","../src/core/initialise.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","type ParsedApiKey = {\n environment: string;\n workspaceId: string;\n tenantId: string;\n baseUrl: string;\n};\n\nconst DEFAULT_BASE_URLS: Record<string, string> = {\n live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'\n};\n\n/**\n * Parses an API key to extract workspaceId, tenantId, and baseUrl\n * Expected format: cs_{environment}_tenantId_workspaceId_secret\n * Matches backend parsing logic\n * \n * @param apiKey - The API key to parse\n * @returns ParsedApiKey object with extracted data\n * @throws Error if the API key format is invalid\n */\nexport const parseApiKey = (apiKey: string): ParsedApiKey => {\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a non-empty string');\n }\n\n // Check if it starts with cs_ prefix\n if (!apiKey.startsWith('cs_')) {\n throw new Error('Invalid API key format. Must start with \"cs_\"');\n }\n\n // Find the environment (cs_live_, cs_test_, cs_dev_, etc.)\n const parts = apiKey.split('_');\n if (parts.length < 2) {\n throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');\n }\n\n const environment = parts[1];\n const prefix = `cs_${environment}_`;\n \n if (!apiKey.startsWith(prefix)) {\n throw new Error(`Invalid API key format. Must start with \"${prefix}\"`);\n }\n\n // Remove prefix (e.g., 'cs_live_')\n const withoutPrefix = apiKey.substring(prefix.length);\n\n // Split by underscore - format: tenantId_workspaceId_secret\n const keyParts = withoutPrefix.split('_');\n\n if (keyParts.length < 3) {\n throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');\n }\n\n const tenantId = keyParts[0];\n const workspaceId = keyParts[1];\n // The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing\n\n if (!tenantId) {\n throw new Error('Tenant ID not found in API key');\n }\n\n if (!workspaceId) {\n throw new Error('Workspace ID not found in API key');\n }\n\n // Determine baseUrl from environment\n const baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;\n\n return {\n environment,\n workspaceId,\n tenantId,\n baseUrl,\n };\n};\n\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n }\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n type: eventName,\n data: eventProperties || {},\n timestamp: Date.now(),\n userEmail: userProperties?.email,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { sanitiseUrl } from '../utils/url-validator';\nimport { parseApiKey } from '../utils/api-key-parser';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns void\n */\n initialise(apiKey: string) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be initialised');\n }\n\n // Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration\n // The original unparsed API key will be sent to the API\n const parsed = parseApiKey(apiKey);\n \n this.config = {\n workspaceId: parsed.workspaceId,\n tenantId: parsed.tenantId,\n };\n \n const sanitisedUrl = sanitiseUrl(parsed.baseUrl);\n // Pass the original unparsed API key to ApiClient - it will be sent as-is to the API\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config: this.config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!user?.email) {\n console.error('User email must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\n/**\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (apiKey: string) => {\n try {\n sdkInstanceManager.initialise(apiKey);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","DEFAULT_BASE_URLS","live","sdkConfig","Content-Type","ApiClient","_ref","apiKey","baseUrl","config","this","endpoint","options","method","url","_this","getBaseUrl","headers","_extends","x-api-key","getApiKey","fetch","workspaceId","_proto","prototype","getWorkspaceId","getUser","user","identify","track","eventName","eventProperties","Error","userProperties","transformedEvent","fetchWithConfig","API_PREFIX","body","email","type","data","timestamp","Date","now","userEmail","JSON","stringify","instance","SDKInstanceManager","isInitialised","initialise","getIsInitialised","console","info","parsed","startsWith","parts","split","length","environment","prefix","keyParts","substring","tenantId","parseApiKey","sanitisedUrl","trim","test","isValidUrl","urlObject","URL","hostname","toLowerCase","pathname","replace","toString","e","sanitiseUrl","apiClient","destroy","getApiClient","getConfig","sdkInstanceManager","_sdkInstanceManager$g","error","message"],"mappings":"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"}
|
|
@@ -24,6 +24,62 @@ var sanitiseUrl = function sanitiseUrl(url) {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
var DEFAULT_BASE_URLS = {
|
|
28
|
+
live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Parses an API key to extract workspaceId, tenantId, and baseUrl
|
|
32
|
+
* Expected format: cs_{environment}_tenantId_workspaceId_secret
|
|
33
|
+
* Matches backend parsing logic
|
|
34
|
+
*
|
|
35
|
+
* @param apiKey - The API key to parse
|
|
36
|
+
* @returns ParsedApiKey object with extracted data
|
|
37
|
+
* @throws Error if the API key format is invalid
|
|
38
|
+
*/
|
|
39
|
+
var parseApiKey = function parseApiKey(apiKey) {
|
|
40
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
41
|
+
throw new Error('API key must be a non-empty string');
|
|
42
|
+
}
|
|
43
|
+
// Check if it starts with cs_ prefix
|
|
44
|
+
if (!apiKey.startsWith('cs_')) {
|
|
45
|
+
throw new Error('Invalid API key format. Must start with "cs_"');
|
|
46
|
+
}
|
|
47
|
+
// Find the environment (cs_live_, cs_test_, cs_dev_, etc.)
|
|
48
|
+
var parts = apiKey.split('_');
|
|
49
|
+
if (parts.length < 2) {
|
|
50
|
+
throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');
|
|
51
|
+
}
|
|
52
|
+
var environment = parts[1];
|
|
53
|
+
var prefix = "cs_" + environment + "_";
|
|
54
|
+
if (!apiKey.startsWith(prefix)) {
|
|
55
|
+
throw new Error("Invalid API key format. Must start with \"" + prefix + "\"");
|
|
56
|
+
}
|
|
57
|
+
// Remove prefix (e.g., 'cs_live_')
|
|
58
|
+
var withoutPrefix = apiKey.substring(prefix.length);
|
|
59
|
+
// Split by underscore - format: tenantId_workspaceId_secret
|
|
60
|
+
var keyParts = withoutPrefix.split('_');
|
|
61
|
+
if (keyParts.length < 3) {
|
|
62
|
+
throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');
|
|
63
|
+
}
|
|
64
|
+
var tenantId = keyParts[0];
|
|
65
|
+
var workspaceId = keyParts[1];
|
|
66
|
+
// The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing
|
|
67
|
+
if (!tenantId) {
|
|
68
|
+
throw new Error('Tenant ID not found in API key');
|
|
69
|
+
}
|
|
70
|
+
if (!workspaceId) {
|
|
71
|
+
throw new Error('Workspace ID not found in API key');
|
|
72
|
+
}
|
|
73
|
+
// Determine baseUrl from environment
|
|
74
|
+
var baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;
|
|
75
|
+
return {
|
|
76
|
+
environment: environment,
|
|
77
|
+
workspaceId: workspaceId,
|
|
78
|
+
tenantId: tenantId,
|
|
79
|
+
baseUrl: baseUrl
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
27
83
|
function _extends() {
|
|
28
84
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
29
85
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -42,16 +98,12 @@ function _extends() {
|
|
|
42
98
|
var transformTrackRequestData = function transformTrackRequestData(_ref) {
|
|
43
99
|
var eventName = _ref.eventName,
|
|
44
100
|
eventProperties = _ref.eventProperties,
|
|
45
|
-
userProperties = _ref.userProperties
|
|
46
|
-
configProperties = _ref.configProperties;
|
|
101
|
+
userProperties = _ref.userProperties;
|
|
47
102
|
var transformedEvent = {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
workspaceId: configProperties.workspaceId,
|
|
53
|
-
type: 'event',
|
|
54
|
-
data: eventProperties
|
|
103
|
+
type: eventName,
|
|
104
|
+
data: eventProperties || {},
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
userEmail: userProperties == null ? void 0 : userProperties.email
|
|
55
107
|
};
|
|
56
108
|
return JSON.stringify(transformedEvent);
|
|
57
109
|
};
|
|
@@ -94,7 +146,6 @@ var ApiClient = /*#__PURE__*/function () {
|
|
|
94
146
|
this.apiKey = apiKey;
|
|
95
147
|
this.baseUrl = baseUrl;
|
|
96
148
|
this.workspaceId = config.workspaceId;
|
|
97
|
-
this.tenantId = config.tenantId;
|
|
98
149
|
}
|
|
99
150
|
var _proto = ApiClient.prototype;
|
|
100
151
|
_proto.getApiKey = function getApiKey() {
|
|
@@ -127,10 +178,6 @@ var ApiClient = /*#__PURE__*/function () {
|
|
|
127
178
|
body: transformTrackRequestData({
|
|
128
179
|
eventName: eventName,
|
|
129
180
|
eventProperties: eventProperties,
|
|
130
|
-
configProperties: {
|
|
131
|
-
workspaceId: this.getWorkspaceId(),
|
|
132
|
-
tenantId: this.tenantId
|
|
133
|
-
},
|
|
134
181
|
userProperties: {
|
|
135
182
|
email: this.user.email
|
|
136
183
|
}
|
|
@@ -158,31 +205,33 @@ var SDKInstanceManager = /*#__PURE__*/function () {
|
|
|
158
205
|
/**
|
|
159
206
|
* @throws Error in case validation of parameters fails
|
|
160
207
|
* @param apiKey - required string value representing the API key
|
|
161
|
-
*
|
|
162
|
-
*
|
|
208
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
209
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
210
|
+
* but the original unparsed API key is sent to the API in requests
|
|
163
211
|
* @returns void
|
|
164
212
|
*/
|
|
165
213
|
var _proto = SDKInstanceManager.prototype;
|
|
166
|
-
_proto.initialise = function initialise(apiKey
|
|
214
|
+
_proto.initialise = function initialise(apiKey) {
|
|
167
215
|
if (this.getIsInitialised()) {
|
|
168
216
|
console.info('SDK is already initialised with API key');
|
|
169
217
|
return;
|
|
170
218
|
}
|
|
171
219
|
if (!apiKey || typeof apiKey !== 'string') {
|
|
172
|
-
throw new Error('SDK needs a valid API key to be
|
|
173
|
-
}
|
|
174
|
-
if (!baseUrl || typeof baseUrl !== 'string' || !isValidUrl(baseUrl)) {
|
|
175
|
-
throw new Error('SDK needs a valid base URL to be initialised');
|
|
176
|
-
}
|
|
177
|
-
if (!config.workspaceId) {
|
|
178
|
-
throw new Error('Workspace ID must be provided');
|
|
220
|
+
throw new Error('SDK needs a valid API key to be initialised');
|
|
179
221
|
}
|
|
180
|
-
|
|
181
|
-
|
|
222
|
+
// Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration
|
|
223
|
+
// The original unparsed API key will be sent to the API
|
|
224
|
+
var parsed = parseApiKey(apiKey);
|
|
225
|
+
this.config = {
|
|
226
|
+
workspaceId: parsed.workspaceId,
|
|
227
|
+
tenantId: parsed.tenantId
|
|
228
|
+
};
|
|
229
|
+
var sanitisedUrl = sanitiseUrl(parsed.baseUrl);
|
|
230
|
+
// Pass the original unparsed API key to ApiClient - it will be sent as-is to the API
|
|
182
231
|
this.apiClient = new ApiClient({
|
|
183
232
|
apiKey: apiKey,
|
|
184
233
|
baseUrl: sanitisedUrl,
|
|
185
|
-
config: config
|
|
234
|
+
config: this.config
|
|
186
235
|
});
|
|
187
236
|
this.isInitialised = true;
|
|
188
237
|
};
|
|
@@ -207,13 +256,14 @@ var instance = /*#__PURE__*/new SDKInstanceManager();
|
|
|
207
256
|
|
|
208
257
|
/**
|
|
209
258
|
* @param apiKey - required string value representing the API key
|
|
210
|
-
*
|
|
211
|
-
*
|
|
259
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
260
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
261
|
+
* but the original unparsed API key is sent to the API in requests
|
|
212
262
|
* @returns boolean indicating whether the initialisation of the sdk was successful or not
|
|
213
263
|
*/
|
|
214
|
-
var initialise = function initialise(apiKey
|
|
264
|
+
var initialise = function initialise(apiKey) {
|
|
215
265
|
try {
|
|
216
|
-
instance.initialise(apiKey
|
|
266
|
+
instance.initialise(apiKey);
|
|
217
267
|
return true;
|
|
218
268
|
} catch (e) {
|
|
219
269
|
console.info(e == null ? void 0 : e.message);
|
|
@@ -223,6 +273,14 @@ var initialise = function initialise(apiKey, baseUrl, config) {
|
|
|
223
273
|
|
|
224
274
|
var identify = function identify(user) {
|
|
225
275
|
var _sdkInstanceManager$g;
|
|
276
|
+
if (!instance.getIsInitialised()) {
|
|
277
|
+
console.error('SDK must be initialised first');
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (!(user != null && user.email)) {
|
|
281
|
+
console.error('User email must be provided');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
226
284
|
(_sdkInstanceManager$g = instance.getApiClient()) == null || _sdkInstanceManager$g.identify(user);
|
|
227
285
|
};
|
|
228
286
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"churnsignal-sdk-web.esm.js","sources":["../src/utils/url-validator.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/initialise.ts","../src/core/identify.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n };\n configProperties: {\n workspaceId: string;\n tenantId?: string\n };\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n configProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n name: eventName,\n timestamp: new Date().getTime().toString(),\n userEmail: userProperties?.email,\n tenantId: configProperties.tenantId, // TODO this will be handled on the API side, for now pass it in SDK setup\n workspaceId: configProperties.workspaceId,\n type: 'event',\n data: eventProperties,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private tenantId?: string;\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n this.tenantId = config.tenantId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n configProperties: {\n workspaceId: this.getWorkspaceId(),\n tenantId: this.tenantId,\n },\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { isValidUrl, sanitiseUrl } from '../utils/url-validator';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param config - required object value\n * @returns void\n */\n initialise(apiKey: string, baseUrl: string, config: Config) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be inialised');\n }\n if (!baseUrl || typeof baseUrl !== 'string' || !isValidUrl(baseUrl)) {\n throw new Error('SDK needs a valid base URL to be initialised');\n }\n if (!config.workspaceId) {\n throw new Error('Workspace ID must be provided');\n }\n this.config = config;\n let sanitisedUrl = sanitiseUrl(baseUrl);\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\nexport type InitConfig = {\n workspaceId: string\n tenantId: string; // TODO to be removed should be done on the API side\n};\n\n/**\n * @param apiKey - required string value representing the API key\n * @param baseUrl - required string value representing the API endpoint\n * @param options - optional object value\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (\n apiKey: string,\n baseUrl: string,\n config: InitConfig\n) => {\n try {\n sdkInstanceManager.initialise(apiKey, baseUrl, config);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","isValidUrl","url","test","sanitiseUrl","sanitisedUrl","trim","Error","urlObject","URL","hostname","toLowerCase","pathname","replace","toString","e","transformTrackRequestData","_ref","eventName","eventProperties","userProperties","configProperties","transformedEvent","name","timestamp","Date","getTime","userEmail","email","tenantId","workspaceId","type","data","JSON","stringify","sdkConfig","defaultHeaders","API_PREFIX","TRACK_ENDPOINT","ApiClient","apiKey","baseUrl","config","endpoint","options","method","_this","getBaseUrl","headers","_extends","getApiKey","fetch","_proto","prototype","getWorkspaceId","getUser","user","identify","track","fetchWithConfig","body","SDKInstanceManager","instance","isInitialised","initialise","getIsInitialised","console","info","apiClient","destroy","getApiClient","getConfig","sdkInstanceManager","message","_sdkInstanceManager$g","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"churnsignal-sdk-web.esm.js","sources":["../src/utils/url-validator.ts","../src/utils/api-key-parser.ts","../src/utils/request-transformations.ts","../src/api-client.ts","../src/managers/sdk-instance-manager.ts","../src/core/initialise.ts","../src/core/identify.ts","../src/core/track.ts"],"sourcesContent":["const urlRegex = /^https?:\\/\\//;\n\nexport const isValidUrl = (url: string) => urlRegex.test(url);\n\nexport const sanitiseUrl = (url: string) => {\n // Trim whitespace\n const sanitisedUrl = url.trim();\n\n // Validate scheme\n if (!isValidUrl(url)) {\n throw new Error(\"URL must start with 'http://' or 'https://'\");\n }\n\n try {\n let urlObject = new URL(sanitisedUrl);\n\n urlObject.hostname = urlObject.hostname.toLowerCase();\n\n // Remove trailing slash\n if (urlObject.pathname !== '/') {\n urlObject.pathname = urlObject.pathname.replace(/\\/+$/, '') || '';\n }\n\n // Reconstruct the URL from its components\n // Note: The URL interface automatically handles encoding of the pathname\n return urlObject.toString().replace(/\\/+$/, '');\n } catch (e) {\n throw new Error('Invalid URL provided');\n }\n};\n","type ParsedApiKey = {\n environment: string;\n workspaceId: string;\n tenantId: string;\n baseUrl: string;\n};\n\nconst DEFAULT_BASE_URLS: Record<string, string> = {\n live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'\n};\n\n/**\n * Parses an API key to extract workspaceId, tenantId, and baseUrl\n * Expected format: cs_{environment}_tenantId_workspaceId_secret\n * Matches backend parsing logic\n * \n * @param apiKey - The API key to parse\n * @returns ParsedApiKey object with extracted data\n * @throws Error if the API key format is invalid\n */\nexport const parseApiKey = (apiKey: string): ParsedApiKey => {\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a non-empty string');\n }\n\n // Check if it starts with cs_ prefix\n if (!apiKey.startsWith('cs_')) {\n throw new Error('Invalid API key format. Must start with \"cs_\"');\n }\n\n // Find the environment (cs_live_, cs_test_, cs_dev_, etc.)\n const parts = apiKey.split('_');\n if (parts.length < 2) {\n throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');\n }\n\n const environment = parts[1];\n const prefix = `cs_${environment}_`;\n \n if (!apiKey.startsWith(prefix)) {\n throw new Error(`Invalid API key format. Must start with \"${prefix}\"`);\n }\n\n // Remove prefix (e.g., 'cs_live_')\n const withoutPrefix = apiKey.substring(prefix.length);\n\n // Split by underscore - format: tenantId_workspaceId_secret\n const keyParts = withoutPrefix.split('_');\n\n if (keyParts.length < 3) {\n throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');\n }\n\n const tenantId = keyParts[0];\n const workspaceId = keyParts[1];\n // The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing\n\n if (!tenantId) {\n throw new Error('Tenant ID not found in API key');\n }\n\n if (!workspaceId) {\n throw new Error('Workspace ID not found in API key');\n }\n\n // Determine baseUrl from environment\n const baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;\n\n return {\n environment,\n workspaceId,\n tenantId,\n baseUrl,\n };\n};\n\n","import { EventProperties } from '../api-client';\n\ntype TrackRequest = {\n eventName: string;\n eventProperties?: EventProperties;\n userProperties?: {\n email: string;\n }\n};\n\nexport const transformTrackRequestData = ({\n eventName,\n eventProperties,\n userProperties,\n}: TrackRequest) => {\n const transformedEvent = {\n type: eventName,\n data: eventProperties || {},\n timestamp: Date.now(),\n userEmail: userProperties?.email,\n };\n return JSON.stringify(transformedEvent);\n};\n\ntype IdentifyRequest = {\n email: string\n}\n\nexport const transformIdentifyRequestData = ({\n email\n}: IdentifyRequest) => {\n const transformedIdentify = {\n userEmail: email\n }\n return JSON.stringify(transformedIdentify);\n}","import {\n transformTrackRequestData,\n // transformIdentifyRequestData,\n} from './utils/request-transformations';\n\ntype ApiClientProps = {\n apiKey: string;\n baseUrl?: string;\n config: {\n workspaceId: string;\n tenantId?: string;\n };\n};\n\nexport type EventProperties = Record<string, any>;\n\ntype User = {\n email: string;\n};\n\nconst sdkConfig = {\n defaultHeaders: {\n 'Content-Type': 'application/json',\n },\n};\n\nconst API_PREFIX = 'sdk-prod';\n\nconst TRACK_ENDPOINT = `${API_PREFIX}/track`;\n// const IDENTIFY_USER_ENDPOINT = `${API_PREFIX}/identify`;\n\nclass ApiClient {\n private apiKey: string;\n private baseUrl?: string;\n private workspaceId: string = '';\n private user?: User;\n\n constructor({ apiKey, baseUrl, config }: ApiClientProps) {\n this.apiKey = apiKey;\n this.baseUrl = baseUrl;\n this.workspaceId = config.workspaceId;\n }\n\n // Wrapper function for fetch\n fetchWithConfig = (\n endpoint: string,\n options: RequestInit = { method: 'GET' }\n ) => {\n // Construct the full URL\n const url = `${this.getBaseUrl()}/${endpoint}`;\n\n // Merge the default headers with any headers provided in the options\n const headers = {\n ...sdkConfig.defaultHeaders,\n 'x-api-key': this.getApiKey(),\n ...(options.headers || {}),\n };\n\n // Merge the rest of the options with the headers\n const config = {\n ...options,\n headers,\n };\n\n // Execute the fetch call with the merged configuration\n return fetch(url, config);\n };\n\n getApiKey() {\n return this.apiKey;\n }\n\n getBaseUrl() {\n return this.baseUrl;\n }\n\n getWorkspaceId() {\n return this.workspaceId;\n }\n\n getUser() {\n return this.user;\n }\n\n identify(user: User) {\n this.user = user;\n // this.fetchWithConfig(IDENTIFY_USER_ENDPOINT, {\n // method: 'POST',\n // body: transformIdentifyRequestData({\n // ...user,\n // }),\n // });\n }\n\n track(eventName: string, eventProperties?: EventProperties) {\n if (!this.user) {\n throw new Error('No identified users to track');\n }\n this.fetchWithConfig(TRACK_ENDPOINT, {\n method: 'POST',\n body: transformTrackRequestData({\n eventName,\n eventProperties,\n userProperties: {\n email: this.user.email,\n },\n }),\n });\n }\n}\n\nexport default ApiClient;\n","import { sanitiseUrl } from '../utils/url-validator';\nimport { parseApiKey } from '../utils/api-key-parser';\nimport ApiClient from './../api-client';\n\ntype Config = {\n workspaceId: string;\n tenantId?: string;\n};\n\nclass SDKInstanceManager {\n private static instance: SDKInstanceManager;\n private isInitialised: boolean = false;\n private config: Config = { workspaceId: '' };\n private apiClient?: ApiClient;\n\n constructor() {\n if (!SDKInstanceManager.instance) {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n SDKInstanceManager.instance = this;\n }\n\n return SDKInstanceManager.instance;\n }\n\n /**\n * @throws Error in case validation of parameters fails\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns void\n */\n initialise(apiKey: string) {\n if (this.getIsInitialised()) {\n console.info('SDK is already initialised with API key');\n return;\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('SDK needs a valid API key to be initialised');\n }\n\n // Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration\n // The original unparsed API key will be sent to the API\n const parsed = parseApiKey(apiKey);\n \n this.config = {\n workspaceId: parsed.workspaceId,\n tenantId: parsed.tenantId,\n };\n \n const sanitisedUrl = sanitiseUrl(parsed.baseUrl);\n // Pass the original unparsed API key to ApiClient - it will be sent as-is to the API\n this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config: this.config });\n this.isInitialised = true;\n }\n\n destroy() {\n this.config = { workspaceId: '' };\n this.isInitialised = false;\n }\n\n getIsInitialised() {\n return this.isInitialised;\n }\n\n getApiClient() {\n return this.apiClient;\n }\n\n getConfig() {\n return this.config;\n }\n}\n\nconst instance = new SDKInstanceManager();\nexport { instance as default };\n","import sdkInstanceManager from './../managers/sdk-instance-manager';\n\n/**\n * @param apiKey - required string value representing the API key\n * Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}\n * The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)\n * but the original unparsed API key is sent to the API in requests\n * @returns boolean indicating whether the initialisation of the sdk was successful or not\n */\nexport const initialise = (apiKey: string) => {\n try {\n sdkInstanceManager.initialise(apiKey);\n return true;\n } catch (e) {\n console.info((e as any)?.message);\n return false;\n }\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\nexport const identify = (user: { email: string }) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!user?.email) {\n console.error('User email must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.identify(user);\n};\n","import sdkInstanceManager from '../managers/sdk-instance-manager';\n\ntype Properties = Record<string, any>;\n\nexport const track = (eventName: string, eventProperties?: Properties) => {\n if (!sdkInstanceManager.getIsInitialised()) {\n console.error('SDK must be initialised first');\n return;\n }\n if (!eventName || typeof eventName !== 'string') {\n console.error('Event name must be provided');\n return;\n }\n sdkInstanceManager.getApiClient()?.track(eventName, eventProperties);\n};\n"],"names":["urlRegex","isValidUrl","url","test","sanitiseUrl","sanitisedUrl","trim","Error","urlObject","URL","hostname","toLowerCase","pathname","replace","toString","e","DEFAULT_BASE_URLS","live","parseApiKey","apiKey","startsWith","parts","split","length","environment","prefix","withoutPrefix","substring","keyParts","tenantId","workspaceId","baseUrl","transformTrackRequestData","_ref","eventName","eventProperties","userProperties","transformedEvent","type","data","timestamp","Date","now","userEmail","email","JSON","stringify","sdkConfig","defaultHeaders","API_PREFIX","TRACK_ENDPOINT","ApiClient","config","endpoint","options","method","_this","getBaseUrl","headers","_extends","getApiKey","fetch","_proto","prototype","getWorkspaceId","getUser","user","identify","track","fetchWithConfig","body","SDKInstanceManager","instance","isInitialised","initialise","getIsInitialised","console","info","parsed","apiClient","destroy","getApiClient","getConfig","sdkInstanceManager","message","error","_sdkInstanceManager$g"],"mappings":"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"}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
export declare type InitConfig = {
|
|
2
|
-
workspaceId: string;
|
|
3
|
-
tenantId: string;
|
|
4
|
-
};
|
|
5
1
|
/**
|
|
6
2
|
* @param apiKey - required string value representing the API key
|
|
7
|
-
*
|
|
8
|
-
*
|
|
3
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
4
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
5
|
+
* but the original unparsed API key is sent to the API in requests
|
|
9
6
|
* @returns boolean indicating whether the initialisation of the sdk was successful or not
|
|
10
7
|
*/
|
|
11
|
-
export declare const initialise: (apiKey: string
|
|
8
|
+
export declare const initialise: (apiKey: string) => boolean;
|
|
@@ -12,11 +12,12 @@ declare class SDKInstanceManager {
|
|
|
12
12
|
/**
|
|
13
13
|
* @throws Error in case validation of parameters fails
|
|
14
14
|
* @param apiKey - required string value representing the API key
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
16
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
17
|
+
* but the original unparsed API key is sent to the API in requests
|
|
17
18
|
* @returns void
|
|
18
19
|
*/
|
|
19
|
-
initialise(apiKey: string
|
|
20
|
+
initialise(apiKey: string): void;
|
|
20
21
|
destroy(): void;
|
|
21
22
|
getIsInitialised(): boolean;
|
|
22
23
|
getApiClient(): ApiClient | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare type ParsedApiKey = {
|
|
2
|
+
environment: string;
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
tenantId: string;
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Parses an API key to extract workspaceId, tenantId, and baseUrl
|
|
9
|
+
* Expected format: cs_{environment}_tenantId_workspaceId_secret
|
|
10
|
+
* Matches backend parsing logic
|
|
11
|
+
*
|
|
12
|
+
* @param apiKey - The API key to parse
|
|
13
|
+
* @returns ParsedApiKey object with extracted data
|
|
14
|
+
* @throws Error if the API key format is invalid
|
|
15
|
+
*/
|
|
16
|
+
export declare const parseApiKey: (apiKey: string) => ParsedApiKey;
|
|
17
|
+
export {};
|
|
@@ -5,12 +5,8 @@ declare type TrackRequest = {
|
|
|
5
5
|
userProperties?: {
|
|
6
6
|
email: string;
|
|
7
7
|
};
|
|
8
|
-
configProperties: {
|
|
9
|
-
workspaceId: string;
|
|
10
|
-
tenantId?: string;
|
|
11
|
-
};
|
|
12
8
|
};
|
|
13
|
-
export declare const transformTrackRequestData: ({ eventName, eventProperties, userProperties,
|
|
9
|
+
export declare const transformTrackRequestData: ({ eventName, eventProperties, userProperties, }: TrackRequest) => string;
|
|
14
10
|
declare type IdentifyRequest = {
|
|
15
11
|
email: string;
|
|
16
12
|
};
|
package/package.json
CHANGED
package/src/api-client.ts
CHANGED
|
@@ -33,14 +33,12 @@ class ApiClient {
|
|
|
33
33
|
private apiKey: string;
|
|
34
34
|
private baseUrl?: string;
|
|
35
35
|
private workspaceId: string = '';
|
|
36
|
-
private tenantId?: string;
|
|
37
36
|
private user?: User;
|
|
38
37
|
|
|
39
38
|
constructor({ apiKey, baseUrl, config }: ApiClientProps) {
|
|
40
39
|
this.apiKey = apiKey;
|
|
41
40
|
this.baseUrl = baseUrl;
|
|
42
41
|
this.workspaceId = config.workspaceId;
|
|
43
|
-
this.tenantId = config.tenantId;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
// Wrapper function for fetch
|
|
@@ -103,10 +101,6 @@ class ApiClient {
|
|
|
103
101
|
body: transformTrackRequestData({
|
|
104
102
|
eventName,
|
|
105
103
|
eventProperties,
|
|
106
|
-
configProperties: {
|
|
107
|
-
workspaceId: this.getWorkspaceId(),
|
|
108
|
-
tenantId: this.tenantId,
|
|
109
|
-
},
|
|
110
104
|
userProperties: {
|
|
111
105
|
email: this.user.email,
|
|
112
106
|
},
|
package/src/core/identify.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import sdkInstanceManager from '../managers/sdk-instance-manager';
|
|
2
2
|
|
|
3
3
|
export const identify = (user: { email: string }) => {
|
|
4
|
+
if (!sdkInstanceManager.getIsInitialised()) {
|
|
5
|
+
console.error('SDK must be initialised first');
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (!user?.email) {
|
|
9
|
+
console.error('User email must be provided');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
4
12
|
sdkInstanceManager.getApiClient()?.identify(user);
|
|
5
13
|
};
|
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
import { destroy } from './destroy';
|
|
2
2
|
import { initialise } from './initialise';
|
|
3
3
|
|
|
4
|
-
const config = {
|
|
5
|
-
workspaceId: 'test-workspace-id',
|
|
6
|
-
tenantId: ''
|
|
7
|
-
};
|
|
8
|
-
|
|
9
4
|
describe('Initialise', () => {
|
|
10
5
|
afterEach(() => {
|
|
11
6
|
destroy();
|
|
12
7
|
})
|
|
13
8
|
it('returns false if no API key is provided', () => {
|
|
14
9
|
const apiKey = '';
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
expect(initialise(apiKey)).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
it('returns false if invalid API key format is provided', () => {
|
|
13
|
+
const apiKey = 'invalid-api-key';
|
|
14
|
+
expect(initialise(apiKey)).toBe(false);
|
|
17
15
|
});
|
|
18
|
-
it('returns false if
|
|
19
|
-
const apiKey = '
|
|
20
|
-
|
|
21
|
-
expect(initialise(apiKey, url, config)).toBe(false);
|
|
16
|
+
it('returns false if API key does not start with cs_', () => {
|
|
17
|
+
const apiKey = 'invalid_live_workspace_tenant_secret';
|
|
18
|
+
expect(initialise(apiKey)).toBe(false);
|
|
22
19
|
});
|
|
23
|
-
it('returns
|
|
24
|
-
const apiKey = '
|
|
25
|
-
|
|
26
|
-
expect(initialise(apiKey, url, config)).toBe(true);
|
|
20
|
+
it('returns false if API key is missing required parts', () => {
|
|
21
|
+
const apiKey = 'cs_live_workspace';
|
|
22
|
+
expect(initialise(apiKey)).toBe(false);
|
|
27
23
|
});
|
|
28
|
-
it('returns
|
|
29
|
-
const apiKey = '
|
|
30
|
-
|
|
31
|
-
expect(initialise(apiKey, url, {} as typeof config)).toBe(false);
|
|
24
|
+
it('returns true if valid API key is provided', () => {
|
|
25
|
+
const apiKey = 'cs_live_932d7af4c96211f09fe863681df5cd13_11ee2a25c7b811f0b155e51f5e29f8c8_633fd81b71d2b69543ac02b3e4ad1fa1f5fa14d5d4b2a517f2d917b37184abbf';
|
|
26
|
+
expect(initialise(apiKey)).toBe(true);
|
|
32
27
|
});
|
|
33
28
|
});
|
package/src/core/initialise.ts
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
import sdkInstanceManager from './../managers/sdk-instance-manager';
|
|
2
2
|
|
|
3
|
-
export type InitConfig = {
|
|
4
|
-
workspaceId: string
|
|
5
|
-
tenantId: string; // TODO to be removed should be done on the API side
|
|
6
|
-
};
|
|
7
|
-
|
|
8
3
|
/**
|
|
9
4
|
* @param apiKey - required string value representing the API key
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
6
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
7
|
+
* but the original unparsed API key is sent to the API in requests
|
|
12
8
|
* @returns boolean indicating whether the initialisation of the sdk was successful or not
|
|
13
9
|
*/
|
|
14
|
-
export const initialise = (
|
|
15
|
-
apiKey: string,
|
|
16
|
-
baseUrl: string,
|
|
17
|
-
config: InitConfig
|
|
18
|
-
) => {
|
|
10
|
+
export const initialise = (apiKey: string) => {
|
|
19
11
|
try {
|
|
20
|
-
sdkInstanceManager.initialise(apiKey
|
|
12
|
+
sdkInstanceManager.initialise(apiKey);
|
|
21
13
|
return true;
|
|
22
14
|
} catch (e) {
|
|
23
15
|
console.info((e as any)?.message);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sanitiseUrl } from '../utils/url-validator';
|
|
2
|
+
import { parseApiKey } from '../utils/api-key-parser';
|
|
2
3
|
import ApiClient from './../api-client';
|
|
3
4
|
|
|
4
5
|
type Config = {
|
|
@@ -25,27 +26,32 @@ class SDKInstanceManager {
|
|
|
25
26
|
/**
|
|
26
27
|
* @throws Error in case validation of parameters fails
|
|
27
28
|
* @param apiKey - required string value representing the API key
|
|
28
|
-
*
|
|
29
|
-
*
|
|
29
|
+
* Expected format: cs_{environment}_{workspaceId}_{tenantId}_{secret}
|
|
30
|
+
* The API key is parsed to extract configuration data (workspaceId, tenantId, baseUrl)
|
|
31
|
+
* but the original unparsed API key is sent to the API in requests
|
|
30
32
|
* @returns void
|
|
31
33
|
*/
|
|
32
|
-
initialise(apiKey: string
|
|
34
|
+
initialise(apiKey: string) {
|
|
33
35
|
if (this.getIsInitialised()) {
|
|
34
36
|
console.info('SDK is already initialised with API key');
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
39
|
if (!apiKey || typeof apiKey !== 'string') {
|
|
38
|
-
throw new Error('SDK needs a valid API key to be
|
|
40
|
+
throw new Error('SDK needs a valid API key to be initialised');
|
|
39
41
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
|
|
43
|
+
// Parse the API key to extract workspaceId, tenantId, and baseUrl for SDK configuration
|
|
44
|
+
// The original unparsed API key will be sent to the API
|
|
45
|
+
const parsed = parseApiKey(apiKey);
|
|
46
|
+
|
|
47
|
+
this.config = {
|
|
48
|
+
workspaceId: parsed.workspaceId,
|
|
49
|
+
tenantId: parsed.tenantId,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const sanitisedUrl = sanitiseUrl(parsed.baseUrl);
|
|
53
|
+
// Pass the original unparsed API key to ApiClient - it will be sent as-is to the API
|
|
54
|
+
this.apiClient = new ApiClient({ apiKey, baseUrl: sanitisedUrl, config: this.config });
|
|
49
55
|
this.isInitialised = true;
|
|
50
56
|
}
|
|
51
57
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
type ParsedApiKey = {
|
|
2
|
+
environment: string;
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
tenantId: string;
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const DEFAULT_BASE_URLS: Record<string, string> = {
|
|
9
|
+
live: 'https://rjwzrk7gs1.execute-api.eu-central-1.amazonaws.com/'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parses an API key to extract workspaceId, tenantId, and baseUrl
|
|
14
|
+
* Expected format: cs_{environment}_tenantId_workspaceId_secret
|
|
15
|
+
* Matches backend parsing logic
|
|
16
|
+
*
|
|
17
|
+
* @param apiKey - The API key to parse
|
|
18
|
+
* @returns ParsedApiKey object with extracted data
|
|
19
|
+
* @throws Error if the API key format is invalid
|
|
20
|
+
*/
|
|
21
|
+
export const parseApiKey = (apiKey: string): ParsedApiKey => {
|
|
22
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
23
|
+
throw new Error('API key must be a non-empty string');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check if it starts with cs_ prefix
|
|
27
|
+
if (!apiKey.startsWith('cs_')) {
|
|
28
|
+
throw new Error('Invalid API key format. Must start with "cs_"');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Find the environment (cs_live_, cs_test_, cs_dev_, etc.)
|
|
32
|
+
const parts = apiKey.split('_');
|
|
33
|
+
if (parts.length < 2) {
|
|
34
|
+
throw new Error('Invalid API key format. Must include environment (e.g., cs_live_)');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const environment = parts[1];
|
|
38
|
+
const prefix = `cs_${environment}_`;
|
|
39
|
+
|
|
40
|
+
if (!apiKey.startsWith(prefix)) {
|
|
41
|
+
throw new Error(`Invalid API key format. Must start with "${prefix}"`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Remove prefix (e.g., 'cs_live_')
|
|
45
|
+
const withoutPrefix = apiKey.substring(prefix.length);
|
|
46
|
+
|
|
47
|
+
// Split by underscore - format: tenantId_workspaceId_secret
|
|
48
|
+
const keyParts = withoutPrefix.split('_');
|
|
49
|
+
|
|
50
|
+
if (keyParts.length < 3) {
|
|
51
|
+
throw new Error('Invalid API key format. Expected format: cs_{environment}_tenantId_workspaceId_secret');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const tenantId = keyParts[0];
|
|
55
|
+
const workspaceId = keyParts[1];
|
|
56
|
+
// The rest (keyParts[2] onwards) is the secret, but we don't need it for parsing
|
|
57
|
+
|
|
58
|
+
if (!tenantId) {
|
|
59
|
+
throw new Error('Tenant ID not found in API key');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!workspaceId) {
|
|
63
|
+
throw new Error('Workspace ID not found in API key');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine baseUrl from environment
|
|
67
|
+
const baseUrl = DEFAULT_BASE_URLS[environment] || DEFAULT_BASE_URLS.live;
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
environment,
|
|
71
|
+
workspaceId,
|
|
72
|
+
tenantId,
|
|
73
|
+
baseUrl,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
@@ -5,27 +5,19 @@ type TrackRequest = {
|
|
|
5
5
|
eventProperties?: EventProperties;
|
|
6
6
|
userProperties?: {
|
|
7
7
|
email: string;
|
|
8
|
-
}
|
|
9
|
-
configProperties: {
|
|
10
|
-
workspaceId: string;
|
|
11
|
-
tenantId?: string
|
|
12
|
-
};
|
|
8
|
+
}
|
|
13
9
|
};
|
|
14
10
|
|
|
15
11
|
export const transformTrackRequestData = ({
|
|
16
12
|
eventName,
|
|
17
13
|
eventProperties,
|
|
18
14
|
userProperties,
|
|
19
|
-
configProperties,
|
|
20
15
|
}: TrackRequest) => {
|
|
21
16
|
const transformedEvent = {
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
type: eventName,
|
|
18
|
+
data: eventProperties || {},
|
|
19
|
+
timestamp: Date.now(),
|
|
24
20
|
userEmail: userProperties?.email,
|
|
25
|
-
tenantId: configProperties.tenantId, // TODO this will be handled on the API side, for now pass it in SDK setup
|
|
26
|
-
workspaceId: configProperties.workspaceId,
|
|
27
|
-
type: 'event',
|
|
28
|
-
data: eventProperties,
|
|
29
21
|
};
|
|
30
22
|
return JSON.stringify(transformedEvent);
|
|
31
23
|
};
|