@engage_so/core 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,75 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+ workflow_dispatch: # Allow manual trigger
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ node-version: [18.x, 20.x, 22.x]
17
+
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Setup Node.js ${{ matrix.node-version }}
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: ${{ matrix.node-version }}
26
+ cache: 'npm'
27
+
28
+ - name: Install dependencies
29
+ run: npm ci
30
+
31
+ - name: Build project
32
+ run: npm run build
33
+
34
+ - name: Run tests
35
+ run: npm test
36
+ env:
37
+ KEY: ${{ secrets.ENGAGE_API_KEY }}
38
+ SECRET: ${{ secrets.ENGAGE_API_SECRET }}
39
+
40
+ - name: Upload test results
41
+ uses: actions/upload-artifact@v4
42
+ if: always()
43
+ with:
44
+ name: test-results-node-${{ matrix.node-version }}
45
+ path: |
46
+ coverage/
47
+ test-results.xml
48
+ retention-days: 7
49
+
50
+ build-check:
51
+ runs-on: ubuntu-latest
52
+
53
+ steps:
54
+ - name: Checkout code
55
+ uses: actions/checkout@v4
56
+
57
+ - name: Setup Node.js
58
+ uses: actions/setup-node@v4
59
+ with:
60
+ node-version: '20.x'
61
+ cache: 'npm'
62
+
63
+ - name: Install dependencies
64
+ run: npm ci
65
+
66
+ - name: Build project
67
+ run: npm run build
68
+
69
+ - name: Check build output
70
+ run: |
71
+ echo "Checking if dist files were created..."
72
+ ls -la dist/
73
+ echo "Checking TypeScript declaration files..."
74
+ ls -la dist/*.d.ts
75
+ echo "Build successful!"
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # Engage JavaScript SDK
2
+
3
+ Engage is all you need to deliver personalized customer messaging and marketing automation through email, SMS and in-app messaging. The JavaScript SDK allows you to automatically capture user attributes and actions on your site or application.
4
+
5
+ [Learn more about the JavaScript SDK](https://docs.engage.so/en-us/a/62bbdd2f5bfea4dca4834046-javascript)
6
+
7
+ ## Getting Started
8
+
9
+ - [Create an Engage account](https://engage.so/) and setup an account to get your API key
10
+ - Follow the [integration guide](https://docs.engage.so/en-us/a/62bbdd2f5bfea4dca4834046-javascript)
11
+
12
+ ## License
13
+
14
+ MIT
package/jest.config.js CHANGED
@@ -4,4 +4,4 @@ module.exports = {
4
4
  },
5
5
  testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
6
6
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
7
- };
7
+ }
package/package.json CHANGED
@@ -1,16 +1,13 @@
1
1
  {
2
2
  "name": "@engage_so/core",
3
- "version": "2.1.1",
4
- "description": "Engage JS core.",
3
+ "version": "2.2.0",
4
+ "description": "Engage JavaScript SDK (core)",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "scripts": {
8
8
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
9
- "build": "tsc -p tsconfig.json",
10
- "prepublishOnly": "npm run build"
11
- },
12
- "publishConfig": {
13
- "access": "public"
9
+ "build": "rm -rf dist && tsc -p tsconfig.json",
10
+ "prepare": "npm run build"
14
11
  },
15
12
  "author": "Engage",
16
13
  "license": "MIT",
@@ -23,8 +20,6 @@
23
20
  "ts-standard": "^12.0.2"
24
21
  },
25
22
  "dependencies": {
26
- "buffer": "^6.0.3",
27
23
  "cross-fetch": "^4.0.0"
28
- },
29
- "gitHead": "6900dcf5defb812e5182bca56762860c838f5266"
24
+ }
30
25
  }
package/src/index.ts CHANGED
@@ -8,11 +8,11 @@ if (typeof btoa === 'undefined') {
8
8
  }
9
9
  }
10
10
 
11
- interface Key {
11
+ export interface Key {
12
12
  key?: string
13
13
  secret?: string
14
14
  }
15
- interface EventParameter {
15
+ export interface EventParameter {
16
16
  event: string
17
17
  value?: string | number | Date | boolean
18
18
  properties?: {
@@ -20,10 +20,10 @@ interface EventParameter {
20
20
  }
21
21
  timestamp?: string | number | Date
22
22
  }
23
- type UserAttrParams = {
23
+ export interface UserAttrParams {
24
24
  [key: string]: string | number | Date | boolean
25
25
  }
26
- type UserIdentifyParams = UserAttrParams & { id: string }
26
+ export type UserIdentifyParams = UserAttrParams & { id: string }
27
27
  type DataParameters = {
28
28
  [key: string]: string | number | Date | boolean
29
29
  } & {
@@ -31,7 +31,7 @@ type DataParameters = {
31
31
  [key: string]: string | number | Date | boolean
32
32
  }
33
33
  }
34
- type Methods = 'POST' | 'PUT' | 'DELETE'
34
+ type Methods = 'POST' | 'PUT' | 'DELETE' | 'GET'
35
35
  // type UserIdentifyParams = {
36
36
  // id: string
37
37
  // [key: string]: string | number | Date | boolean
@@ -40,21 +40,39 @@ type Methods = 'POST' | 'PUT' | 'DELETE'
40
40
 
41
41
  // const rootURL = 'https://api.engage.so/v1'
42
42
  let auth: string = ''
43
+ let currentUserId: string = ''
43
44
  const notMeta = ['created_at', 'is_account', 'number', 'device_token', 'device_platform', 'email', 'first_name', 'last_name', 'tz', 'app_version', 'app_build', 'app_last_active']
44
45
  const apiRoot = 'https://api.engage.so/v1'
45
46
 
46
- async function _request (url: string, params: Record<string, any> | null, method: Methods) {
47
+ function isNull (v: any | null | undefined): boolean {
48
+ return (v === null || v === undefined)
49
+ }
50
+ function isNullString (v: string | null | undefined): boolean {
51
+ return (v === null || v === undefined || v === '')
52
+ }
53
+
54
+ function resolveUserId (uid?: string): string {
55
+ if (!isNullString(uid)) {
56
+ return uid as string
57
+ }
58
+ if (isNullString(currentUserId)) {
59
+ throw new EngageError('User ID missing. Call identify() first or provide a uid parameter.')
60
+ }
61
+ return currentUserId
62
+ }
63
+
64
+ async function _request (url: string, params: Record<string, any> | null | undefined, method: Methods): Promise<object> {
47
65
  try {
48
66
  const o: any = {
49
67
  method,
50
68
  headers: {
51
69
  'Content-Type': 'application/json;charset=utf-8',
52
70
  Authorization: `Basic ${auth}`
53
- },
71
+ }
54
72
  // throwHttpErrors: false,
55
73
  // prefixUrl: rootURL
56
74
  }
57
- if (params) {
75
+ if (!isNull(params)) {
58
76
  o.body = JSON.stringify(params)
59
77
  }
60
78
  // const response = await ky(url, o)
@@ -62,7 +80,7 @@ async function _request (url: string, params: Record<string, any> | null, method
62
80
  const body: any = await response.json()
63
81
  let error = 'API connection error'
64
82
  if (!response.ok) {
65
- if (body && body.error) {
83
+ if (typeof body?.error === 'string') {
66
84
  error = body.error
67
85
  }
68
86
  return { error }
@@ -74,45 +92,49 @@ async function _request (url: string, params: Record<string, any> | null, method
74
92
  }
75
93
  // Alias of _request method
76
94
  // Same with _request for now but can later have modifications
77
- export function request (url: string, params: Record<string, any> | null, method: Methods): object {
78
- return _request(url, params, method)
95
+ export async function request (url: string, params: Record<string, any> | null | undefined, method: Methods = 'GET'): Promise<object> {
96
+ return await _request(url, params, method)
79
97
  }
80
98
 
81
- export function init (key: Key | string) {
82
- if (!key) {
99
+ export function init (key: Key | string): void {
100
+ if (isNull(key)) {
83
101
  throw new EngageError('You need to pass in your API key(s).')
84
102
  }
103
+
104
+ // Clear any stored user ID when reinitializing
105
+ currentUserId = ''
106
+
85
107
  const options: Key = {
86
- key: undefined,
108
+ key: '',
87
109
  secret: ''
88
110
  }
89
111
  if (typeof key === 'string') {
112
+ if (key === '') {
113
+ throw new EngageError('`key` is empty.')
114
+ }
90
115
  options.key = key
91
116
  } else {
92
- if (!key.key) {
117
+ if (isNullString(key.key)) {
93
118
  throw new EngageError('`key` missing in object.')
94
119
  }
95
- if (key.key) {
96
- options.key = `${key.key}`
97
- }
98
- if (key.secret) {
99
- options.secret = `${key.secret}`
120
+ options.key = key.key
121
+ if (!isNullString(key.secret)) {
122
+ options.secret = key.secret
100
123
  }
101
124
  }
102
125
  // Set auth
103
- // auth = Buffer.from(`${options.key}:${options.secret}`).toString('base64')
104
- auth = btoa(`${options.key}:${options.secret}`)
126
+ auth = btoa(`${options.key ?? ''}:${options.secret ?? ''}`)
105
127
  }
106
128
 
107
129
  // Data tracking
108
- export async function identify (user: UserIdentifyParams) {
109
- if (!user) {
130
+ export async function identify (user: UserIdentifyParams): Promise<object> {
131
+ if (isNull(user)) {
110
132
  throw new EngageError('You need to pass an object with at least an id.')
111
133
  }
112
- if (!user.id) {
134
+ if (isNullString(user.id)) {
113
135
  throw new EngageError('ID missing.')
114
136
  }
115
- if (user.email && (typeof user.email !== 'string' || !/^\S+@\S+$/.test(user.email))) {
137
+ if (!isNull(user.email) && (typeof user.email !== 'string' || !/^\S+@\S+$/.test(user.email))) {
116
138
  throw new EngageError('Email invalid.')
117
139
  }
118
140
  const params: DataParameters = {}
@@ -125,117 +147,219 @@ export async function identify (user: UserIdentifyParams) {
125
147
  }
126
148
  }
127
149
 
128
- return _request(`/users/${user.id}`, params, 'PUT')
150
+ // Store the user ID for use in other functions
151
+ currentUserId = user.id
152
+
153
+ return await _request(`/users/${user.id}`, params, 'PUT')
129
154
  }
130
- export async function addAttribute (uid: string, attributes: UserAttrParams) {
131
- if (!uid) {
132
- throw new EngageError('User ID missing.')
155
+
156
+ // Overloaded function signatures for addAttribute
157
+ export async function addAttribute (attributes: UserAttrParams): Promise<object>
158
+ export async function addAttribute (uid: string, attributes: UserAttrParams): Promise<object>
159
+ export async function addAttribute (uidOrAttributes: string | UserAttrParams, attributes?: UserAttrParams): Promise<object> {
160
+ let uid: string
161
+ let attrs: UserAttrParams
162
+
163
+ // Handle overloaded parameters
164
+ if (typeof uidOrAttributes === 'string') {
165
+ uid = resolveUserId(uidOrAttributes)
166
+ if (isNull(attributes)) {
167
+ throw new EngageError('Attributes missing when uid is provided.')
168
+ }
169
+ attrs = attributes as UserAttrParams
170
+ } else {
171
+ uid = resolveUserId()
172
+ attrs = uidOrAttributes
133
173
  }
134
- if (!attributes) {
174
+
175
+ if (isNull(attrs)) {
135
176
  throw new EngageError('Attributes missing.')
136
177
  }
137
- if (!Object.keys(attributes).length) {
178
+ if (Object.keys(attrs).length === 0) {
138
179
  throw new EngageError('Attributes missing.')
139
180
  }
140
181
  const params: DataParameters = {}
141
182
  params.meta = {}
142
- for (const k in attributes) {
183
+ for (const k in attrs) {
143
184
  if (notMeta.includes(k)) {
144
- params[k] = attributes[k]
185
+ params[k] = attrs[k]
145
186
  } else {
146
- params.meta[k] = attributes[k]
187
+ params.meta[k] = attrs[k]
147
188
  }
148
189
  }
149
- if (!Object.keys(params.meta).length) {
190
+ if (Object.keys(params.meta).length === 0) {
150
191
  delete params.meta
151
192
  }
152
193
 
153
- return _request(`/users/${uid}`, params, 'PUT')
194
+ return await _request(`/users/${uid}`, params, 'PUT')
154
195
  }
155
- export async function track (uid: string, data: EventParameter) {
156
- if (!uid) {
157
- throw new EngageError('User ID missing.')
196
+
197
+ // Overloaded function signatures for track
198
+ export async function track (data: EventParameter): Promise<object>
199
+ export async function track (uid: string, data: EventParameter): Promise<object>
200
+ export async function track (uidOrData: string | EventParameter, data?: EventParameter): Promise<object> {
201
+ let uid: string
202
+ let eventData: EventParameter
203
+
204
+ // Handle overloaded parameters
205
+ if (typeof uidOrData === 'string') {
206
+ uid = resolveUserId(uidOrData)
207
+ if (isNull(data)) {
208
+ throw new EngageError('Event data missing when uid is provided.')
209
+ }
210
+ eventData = data as EventParameter
211
+ } else {
212
+ uid = resolveUserId()
213
+ eventData = uidOrData
158
214
  }
159
- if (!data) {
215
+
216
+ if (isNull(eventData)) {
160
217
  throw new EngageError('Event data missing.')
161
218
  }
162
- if (typeof data === 'string') {
163
- data = {
164
- event: data,
219
+ if (typeof eventData === 'string') {
220
+ eventData = {
221
+ event: eventData,
165
222
  value: true
166
223
  }
167
224
  } else {
168
- if (!Object.keys(data).length) {
225
+ if (Object.keys(eventData).length === 0) {
169
226
  throw new EngageError('Attributes missing.')
170
227
  }
171
228
  }
172
229
 
173
- return _request(`/users/${uid}/events`, data, 'POST')
230
+ return await _request(`/users/${uid}/events`, eventData, 'POST')
174
231
  }
175
232
 
176
- export async function merge (sourceUid: string, destinationUid: string) {
177
- if (!sourceUid) {
178
- throw new EngageError('Source ID missing.')
233
+ // Overloaded function signatures for merge
234
+ export async function merge (destinationUid: string): Promise<object>
235
+ export async function merge (sourceUid: string, destinationUid: string): Promise<object>
236
+ export async function merge (sourceOrDestinationUid: string, destinationUid?: string): Promise<object> {
237
+ let sourceUid: string
238
+ let destUid: string
239
+
240
+ // Handle overloaded parameters
241
+ if (isNullString(destinationUid)) {
242
+ // Called with one parameter: merge(destinationUid)
243
+ sourceUid = resolveUserId()
244
+ destUid = sourceOrDestinationUid
245
+ } else {
246
+ // Called with two parameters: merge(sourceUid, destinationUid)
247
+ sourceUid = resolveUserId(sourceOrDestinationUid)
248
+ destUid = destinationUid as string
179
249
  }
180
- if (!destinationUid) {
250
+
251
+ if (isNullString(destUid)) {
181
252
  throw new EngageError('Destination ID missing.')
182
253
  }
183
254
 
184
- return _request(`/users/merge`, {
255
+ return await _request('/users/merge', {
185
256
  source: sourceUid,
186
- destination: destinationUid
257
+ destination: destUid
187
258
  }, 'POST')
188
259
  }
189
260
 
190
261
  // Account functions
191
- export async function addToAccount(uid: string, accountId: string, role: string) {
192
- if (!uid) {
262
+ export async function addToAccount (uid: string, accountId: string, role?: string): Promise<object> {
263
+ if (isNullString(uid)) {
193
264
  throw new EngageError('User ID missing.')
194
265
  }
195
- if (!accountId) {
266
+ if (isNullString(accountId)) {
196
267
  throw new EngageError('Account ID missing.')
197
268
  }
198
- if (role && typeof role !== 'string') {
269
+ if (!isNull(role) && typeof role !== 'string') {
199
270
  throw new EngageError('Role should be a text.')
200
271
  }
201
272
  const g: Record<string, string> = {
202
273
  id: accountId
203
274
  }
204
- if (role) {
205
- g.role = role
275
+ if (!isNullString(role)) {
276
+ g.role = role as string
206
277
  }
207
- return _request(`/users/${uid}/accounts`, { accounts: [g] }, 'POST')
278
+ return await _request(`/users/${uid}/accounts`, { accounts: [g] }, 'POST')
208
279
  }
209
- export async function removeFromAccount (uid: string, accountId: string){
210
- if (!uid) {
211
- throw new EngageError('User ID missing.')
280
+
281
+ // Overloaded function signatures for removeFromAccount
282
+ export async function removeFromAccount (accountId: string): Promise<object>
283
+ export async function removeFromAccount (uid: string, accountId: string): Promise<object>
284
+ export async function removeFromAccount (uidOrAccountId: string, accountId?: string): Promise<object> {
285
+ let uid: string
286
+ let acctId: string
287
+
288
+ // Handle overloaded parameters
289
+ if (isNullString(accountId)) {
290
+ // Called with one parameter: removeFromAccount(accountId)
291
+ uid = resolveUserId()
292
+ acctId = uidOrAccountId
293
+ } else {
294
+ // Called with two parameters: removeFromAccount(uid, accountId)
295
+ uid = resolveUserId(uidOrAccountId)
296
+ acctId = accountId as string
212
297
  }
213
- if (!accountId) {
298
+
299
+ if (isNullString(acctId)) {
214
300
  throw new EngageError('Account ID missing.')
215
301
  }
216
- return _request(`/users/${uid}/accounts/${accountId}`, null, 'DELETE')
302
+ return await _request(`/users/${uid}/accounts/${acctId}`, null, 'DELETE')
217
303
  }
218
- export async function changeAccountRole (uid: string, accountId: string, role: string) {
219
- if (!uid) {
220
- throw new EngageError('User ID missing.')
304
+
305
+ // Overloaded function signatures for changeAccountRole
306
+ export async function changeAccountRole (accountId: string, role: string): Promise<object>
307
+ export async function changeAccountRole (uid: string, accountId: string, role: string): Promise<object>
308
+ export async function changeAccountRole (uidOrAccountId: string, accountIdOrRole: string, role?: string): Promise<object> {
309
+ let uid: string
310
+ let accountId: string
311
+ let newRole: string
312
+
313
+ // Handle overloaded parameters
314
+ if (isNullString(role)) {
315
+ // Called with two parameters: changeAccountRole(accountId, role)
316
+ uid = resolveUserId()
317
+ accountId = uidOrAccountId
318
+ newRole = accountIdOrRole
319
+ } else {
320
+ // Called with three parameters: changeAccountRole(uid, accountId, role)
321
+ uid = resolveUserId(uidOrAccountId)
322
+ accountId = accountIdOrRole
323
+ newRole = role as string
221
324
  }
222
- if (!accountId) {
325
+
326
+ if (isNullString(accountId)) {
223
327
  throw new EngageError('Account ID missing.')
224
328
  }
225
- if (!role) {
329
+ if (isNullString(newRole)) {
226
330
  throw new EngageError('New role missing.')
227
331
  }
228
- return _request(`/users/${uid}/accounts/${accountId}`, { role }, 'PUT')
332
+ return await _request(`/users/${uid}/accounts/${accountId}`, { role: newRole }, 'PUT')
229
333
  }
230
- export async function convertToCustomer (uid: string) {
231
- if (!uid) {
232
- throw new EngageError('User ID missing.')
233
- }
234
- return _request(`/users/${uid}/convert`, { type: 'customer' }, 'POST')
334
+
335
+ // Overloaded function signatures for convertToCustomer
336
+ export async function convertToCustomer (): Promise<object>
337
+ export async function convertToCustomer (uid?: string): Promise<object> {
338
+ const userId = resolveUserId(uid)
339
+ return await _request(`/users/${userId}/convert`, { type: 'customer' }, 'POST')
235
340
  }
236
- export async function convertToAccount (uid: string) {
237
- if (!uid) {
238
- throw new EngageError('User ID missing.')
239
- }
240
- return _request(`/users/${uid}/convert`, { type: 'account' }, 'POST')
341
+
342
+ // Overloaded function signatures for convertToAccount
343
+ export async function convertToAccount (): Promise<object>
344
+ export async function convertToAccount (uid?: string): Promise<object> {
345
+ const userId = resolveUserId(uid)
346
+ return await _request(`/users/${userId}/convert`, { type: 'account' }, 'POST')
241
347
  }
348
+
349
+ // Create an object containing all exports for easy access
350
+ const EngageSDK = {
351
+ init,
352
+ identify,
353
+ addAttribute,
354
+ track,
355
+ merge,
356
+ addToAccount,
357
+ removeFromAccount,
358
+ changeAccountRole,
359
+ convertToCustomer,
360
+ convertToAccount,
361
+ request
362
+ }
363
+
364
+ // Export as default for import EngageSDK syntax
365
+ export default EngageSDK
@@ -29,57 +29,9 @@ describe('Init', () => {
29
29
  })
30
30
  })
31
31
 
32
- describe('Identify', () => {
33
- test('should throw if no parameter passed', async () => {
34
- await expect(Engage.identify()).rejects.toThrow('object')
35
- })
36
- test('should throw if empty string passed', async () => {
37
- await expect(Engage.identify('')).rejects.toThrow('id')
38
- })
39
- test('should throw if empty object passed', async () => {
40
- await expect(Engage.identify({})).rejects.toThrow(/id/i)
41
- })
42
- test('should not throw if no email passed', async () => {
43
- await expect(() => {
44
- Engage.identify({ id: gid })
45
- }).not.toThrow()
46
- })
47
- test('should throw if invalid email passed', async () => {
48
- await expect(Engage.identify({
49
- id,
50
- email: 'invalid'
51
- })).rejects.toThrow(/email/i)
52
- })
53
- test('should work if id and email passed', async () => {
54
- await expect(Engage.identify({
55
- id,
56
- email: 'fickledreams@yahoo.com'
57
- })).resolves.toMatchObject({
58
- uid: id,
59
- email: 'fickledreams@yahoo.com'
60
- })
61
- })
62
- test('should turn to account if has is_account', async () => {
63
- await expect(Engage.identify({
64
- id,
65
- is_account: true
66
- })).resolves.toMatchObject({
67
- is_account: true
68
- })
69
- })
70
- test('should turn to user if is_account is false', async () => {
71
- await expect(Engage.identify({
72
- id,
73
- is_account: false
74
- })).resolves.toMatchObject({
75
- is_account: false
76
- })
77
- })
78
- })
79
-
80
32
  describe('Add attribute', () => {
81
33
  test('should throw if no parameter passed', async () => {
82
- await expect(Engage.addAttribute()).rejects.toThrow('id')
34
+ await expect(Engage.addAttribute()).rejects.toThrow(/id/i)
83
35
  })
84
36
  test('should throw if no data attribute passed', async () => {
85
37
  await expect(Engage.addAttribute(id)).rejects.toThrow(/attributes/i)
@@ -115,7 +67,7 @@ describe('Add attribute', () => {
115
67
 
116
68
  describe('Track', () => {
117
69
  test('should throw if no parameter passed', async () => {
118
- await expect(Engage.track()).rejects.toThrow('ID')
70
+ await expect(Engage.track()).rejects.toThrow(/id/i)
119
71
  })
120
72
  test('should throw if no data attribute passed', async () => {
121
73
  await expect(Engage.track(id)).rejects.toThrow(/data/i)
@@ -229,3 +181,51 @@ describe('Remove from account', () => {
229
181
  })
230
182
  })
231
183
  })
184
+
185
+ describe('Identify', () => {
186
+ test('should throw if no parameter passed', async () => {
187
+ await expect(Engage.identify()).rejects.toThrow('object')
188
+ })
189
+ test('should throw if empty string passed', async () => {
190
+ await expect(Engage.identify('')).rejects.toThrow('ID')
191
+ })
192
+ test('should throw if empty object passed', async () => {
193
+ await expect(Engage.identify({})).rejects.toThrow('ID')
194
+ })
195
+ test('should not throw if no email passed', async () => {
196
+ await expect(() => {
197
+ Engage.identify({ id: gid })
198
+ }).not.toThrow()
199
+ })
200
+ test('should throw if invalid email passed', async () => {
201
+ await expect(Engage.identify({
202
+ id,
203
+ email: 'invalid'
204
+ })).rejects.toThrow(/email/i)
205
+ })
206
+ test('should work if id and email passed', async () => {
207
+ await expect(Engage.identify({
208
+ id,
209
+ email: 'fickledreams@yahoo.com'
210
+ })).resolves.toMatchObject({
211
+ uid: id,
212
+ email: 'fickledreams@yahoo.com'
213
+ })
214
+ })
215
+ test('should turn to account if has is_account', async () => {
216
+ await expect(Engage.identify({
217
+ id,
218
+ is_account: true
219
+ })).resolves.toMatchObject({
220
+ is_account: true
221
+ })
222
+ })
223
+ test('should turn to user if is_account is false', async () => {
224
+ await expect(Engage.identify({
225
+ id,
226
+ is_account: false
227
+ })).resolves.toMatchObject({
228
+ is_account: false
229
+ })
230
+ })
231
+ })
@@ -0,0 +1,41 @@
1
+ import * as Engage from '../src/index'
2
+ import EngageSDK from '../src/index'
3
+
4
+ describe('Object-Oriented Pattern', () => {
5
+ describe('Functional style imports', () => {
6
+ test('should work with named import init', () => {
7
+ expect(() => {
8
+ Engage.init('test-key')
9
+ }).not.toThrow()
10
+ })
11
+
12
+ test('should work with destructured init', () => {
13
+ const { init } = Engage
14
+ expect(() => {
15
+ init('test-key-2')
16
+ }).not.toThrow()
17
+ })
18
+ })
19
+
20
+ describe('Static class style imports', () => {
21
+ test('should work with default import init', () => {
22
+ expect(() => {
23
+ EngageSDK.init('test-key')
24
+ }).not.toThrow()
25
+ })
26
+
27
+ test('should have all expected methods on default export', () => {
28
+ expect(typeof EngageSDK.init).toBe('function')
29
+ expect(typeof EngageSDK.identify).toBe('function')
30
+ expect(typeof EngageSDK.addAttribute).toBe('function')
31
+ expect(typeof EngageSDK.track).toBe('function')
32
+ expect(typeof EngageSDK.merge).toBe('function')
33
+ expect(typeof EngageSDK.addToAccount).toBe('function')
34
+ expect(typeof EngageSDK.removeFromAccount).toBe('function')
35
+ expect(typeof EngageSDK.changeAccountRole).toBe('function')
36
+ expect(typeof EngageSDK.convertToCustomer).toBe('function')
37
+ expect(typeof EngageSDK.convertToAccount).toBe('function')
38
+ expect(typeof EngageSDK.request).toBe('function')
39
+ })
40
+ })
41
+ })
@@ -0,0 +1,133 @@
1
+ import * as Engage from '../src/index'
2
+
3
+ describe('Function Overloads', () => {
4
+ beforeEach(() => {
5
+ // Initialize SDK before each test
6
+ Engage.init({ key: 'test-key', secret: 'test-secret' })
7
+ })
8
+
9
+ describe('Identify and stored user ID', () => {
10
+ test('should store user ID when identify is called', async () => {
11
+ await expect(Engage.identify({ id: 'test-user-123', email: 'test@example.com' }))
12
+ .resolves.toMatchObject({ error: expect.any(String) })
13
+ })
14
+ })
15
+
16
+ describe('addAttribute overloads', () => {
17
+ test('should work with uid parameter', async () => {
18
+ await expect(Engage.addAttribute('test-user-123', { name: 'John' }))
19
+ .resolves.toMatchObject({ error: expect.any(String) })
20
+ })
21
+
22
+ test('should work without uid parameter after identify', async () => {
23
+ // First identify to store user ID
24
+ await Engage.identify({ id: 'test-user-123', email: 'test@example.com' })
25
+
26
+ // Then use addAttribute without uid
27
+ await expect(Engage.addAttribute({ name: 'John' }))
28
+ .resolves.toMatchObject({ error: expect.any(String) })
29
+ })
30
+
31
+ test('should throw error if no stored uid and no uid provided', async () => {
32
+ // Reset any stored user ID by re-initializing
33
+ Engage.init({ key: 'test-key', secret: 'test-secret' })
34
+
35
+ await expect(Engage.addAttribute({ name: 'John' }))
36
+ .rejects.toThrow('User ID missing. Call identify() first or provide a uid parameter.')
37
+ })
38
+ })
39
+
40
+ describe('track overloads', () => {
41
+ test('should work with uid parameter', async () => {
42
+ await expect(Engage.track('test-user-123', { event: 'login' }))
43
+ .resolves.toMatchObject({ error: expect.any(String) })
44
+ })
45
+
46
+ test('should work without uid parameter after identify', async () => {
47
+ // First identify to store user ID
48
+ await Engage.identify({ id: 'test-user-123', email: 'test@example.com' })
49
+
50
+ // Then use track without uid
51
+ await expect(Engage.track({ event: 'login' }))
52
+ .resolves.toMatchObject({ error: expect.any(String) })
53
+ })
54
+
55
+ test('should throw error if no stored uid and no uid provided', async () => {
56
+ // Reset any stored user ID by re-initializing
57
+ Engage.init({ key: 'test-key', secret: 'test-secret' })
58
+
59
+ await expect(Engage.track({ event: 'login' }))
60
+ .rejects.toThrow('User ID missing. Call identify() first or provide a uid parameter.')
61
+ })
62
+ })
63
+
64
+ describe('convertToCustomer overloads', () => {
65
+ test('should work with uid parameter', async () => {
66
+ await expect((Engage.convertToCustomer as any)('test-user-123'))
67
+ .resolves.toMatchObject({ error: expect.any(String) })
68
+ })
69
+
70
+ test('should work without uid parameter after identify', async () => {
71
+ // First identify to store user ID
72
+ await Engage.identify({ id: 'test-user-123', email: 'test@example.com' })
73
+
74
+ // Then use convertToCustomer without uid
75
+ await expect(Engage.convertToCustomer())
76
+ .resolves.toMatchObject({ error: expect.any(String) })
77
+ })
78
+
79
+ test('should throw error if no stored uid and no uid provided', async () => {
80
+ // Reset any stored user ID by re-initializing
81
+ Engage.init({ key: 'test-key', secret: 'test-secret' })
82
+
83
+ await expect(Engage.convertToCustomer())
84
+ .rejects.toThrow('User ID missing. Call identify() first or provide a uid parameter.')
85
+ })
86
+ })
87
+
88
+ describe('merge overloads', () => {
89
+ test('should work with both source and destination uid', async () => {
90
+ await expect(Engage.merge('source-user', 'dest-user'))
91
+ .resolves.toMatchObject({ error: expect.any(String) })
92
+ })
93
+
94
+ test('should work with destination uid only after identify', async () => {
95
+ // First identify to store user ID (source)
96
+ await Engage.identify({ id: 'source-user', email: 'test@example.com' })
97
+
98
+ // Then merge with destination only
99
+ await expect(Engage.merge('dest-user'))
100
+ .resolves.toMatchObject({ error: expect.any(String) })
101
+ })
102
+
103
+ test('should throw error if no stored uid and only destination provided', async () => {
104
+ // Reset any stored user ID by re-initializing
105
+ Engage.init({ key: 'test-key', secret: 'test-secret' })
106
+
107
+ await expect(Engage.merge('dest-user'))
108
+ .rejects.toThrow('User ID missing. Call identify() first or provide a uid parameter.')
109
+ })
110
+ })
111
+
112
+ describe('account management overloads', () => {
113
+ test('removeFromAccount should work with both signatures', async () => {
114
+ await expect(Engage.removeFromAccount('user-id', 'account-id'))
115
+ .resolves.toMatchObject({ error: expect.any(String) })
116
+
117
+ // After identify
118
+ await Engage.identify({ id: 'user-id', email: 'test@example.com' })
119
+ await expect(Engage.removeFromAccount('account-id'))
120
+ .resolves.toMatchObject({ error: expect.any(String) })
121
+ })
122
+
123
+ test('changeAccountRole should work with both signatures', async () => {
124
+ await expect(Engage.changeAccountRole('user-id', 'account-id', 'owner'))
125
+ .resolves.toMatchObject({ error: expect.any(String) })
126
+
127
+ // After identify
128
+ await Engage.identify({ id: 'user-id', email: 'test@example.com' })
129
+ await expect(Engage.changeAccountRole('account-id', 'owner'))
130
+ .resolves.toMatchObject({ error: expect.any(String) })
131
+ })
132
+ })
133
+ })
@@ -0,0 +1,121 @@
1
+ import * as Engage from '../src/index'
2
+ import EngageSDK from '../src/index'
3
+
4
+ describe('Method Overriding', () => {
5
+ describe('Individual function exports', () => {
6
+ test('should allow access to original init function', () => {
7
+ expect(() => {
8
+ Engage.init('test-key')
9
+ }).not.toThrow()
10
+ })
11
+
12
+ test('should allow method overriding by replacing function', async () => {
13
+ // Save original function
14
+ const originalTrack = Engage.track
15
+
16
+ // Create a mock function to override with
17
+ const customTrack = jest.fn().mockImplementation(async (uidOrData: any, data?: any) => {
18
+ // Call original function for proper behavior
19
+ const result = await originalTrack(uidOrData, data)
20
+ // Add custom flag to result
21
+ return { ...result, customFlag: 'overridden' }
22
+ })
23
+
24
+ // Override the function
25
+ ;(Engage as any).track = customTrack
26
+
27
+ // Test the overridden function
28
+ try {
29
+ const result = await (Engage as any).track('user123', { event: 'test-event' })
30
+ expect(result).toHaveProperty('customFlag', 'overridden')
31
+ expect(customTrack).toHaveBeenCalledWith('user123', { event: 'test-event' })
32
+ } catch (error) {
33
+ // Expected to fail due to API authentication, but should still call our custom function
34
+ expect(customTrack).toHaveBeenCalledWith('user123', { event: 'test-event' })
35
+ }
36
+
37
+ // Restore original function
38
+ ;(Engage as any).track = originalTrack
39
+ })
40
+
41
+ test('should maintain function reference integrity', () => {
42
+ const trackFunction = Engage.track
43
+ expect(typeof trackFunction).toBe('function')
44
+ expect(trackFunction).toBe(Engage.track)
45
+ })
46
+ })
47
+
48
+ describe('Default export overriding', () => {
49
+ test('should work with default export init', () => {
50
+ expect(() => {
51
+ EngageSDK.init('test-key-2')
52
+ }).not.toThrow()
53
+ })
54
+
55
+ test('should allow method overriding on default export', async () => {
56
+ // Save original function
57
+ const originalIdentify = EngageSDK.identify
58
+
59
+ // Create a mock function
60
+ const customIdentify = jest.fn().mockImplementation(async (user: any) => {
61
+ const result = await originalIdentify(user)
62
+ return { ...result, customProcessed: true }
63
+ })
64
+
65
+ // Override the function
66
+ ;(EngageSDK as any).identify = customIdentify
67
+
68
+ // Test the overridden function
69
+ try {
70
+ const result = await (EngageSDK as any).identify({ id: 'test-user', email: 'test@example.com' })
71
+ expect(result).toHaveProperty('customProcessed', true)
72
+ expect(customIdentify).toHaveBeenCalledWith({ id: 'test-user', email: 'test@example.com' })
73
+ } catch (error) {
74
+ // Expected to fail due to API authentication, but should still call our custom function
75
+ expect(customIdentify).toHaveBeenCalledWith({ id: 'test-user', email: 'test@example.com' })
76
+ }
77
+
78
+ // Restore original function
79
+ ;(EngageSDK as any).identify = originalIdentify
80
+ })
81
+
82
+ test('should have consistent function references between named and default exports', () => {
83
+ expect(typeof EngageSDK.init).toBe('function')
84
+ expect(typeof EngageSDK.track).toBe('function')
85
+ expect(typeof EngageSDK.identify).toBe('function')
86
+ })
87
+ })
88
+
89
+ describe('Overriding behavior validation', () => {
90
+ test('should allow chaining of overridden methods', async () => {
91
+ const originalAddAttribute = Engage.addAttribute
92
+
93
+ // First override
94
+ const firstOverride = jest.fn().mockImplementation(async (uidOrAttrs: any, attrs?: any) => {
95
+ const result = await (originalAddAttribute as any)(uidOrAttrs, attrs)
96
+ return { ...result, step1: 'complete' }
97
+ })
98
+
99
+ // Second override that calls first override
100
+ const secondOverride = jest.fn().mockImplementation(async (uidOrAttrs: any, attrs?: any) => {
101
+ const result = await firstOverride(uidOrAttrs, attrs)
102
+ return { ...result, step2: 'complete' }
103
+ })
104
+
105
+ ;(Engage as any).addAttribute = secondOverride
106
+
107
+ try {
108
+ await (Engage as any).addAttribute('test-user', { name: 'Test' })
109
+ expect(secondOverride).toHaveBeenCalled()
110
+ expect(firstOverride).toHaveBeenCalled()
111
+ } catch (error) {
112
+ // Expected to fail but should still call our functions
113
+ expect(secondOverride).toHaveBeenCalled()
114
+ expect(firstOverride).toHaveBeenCalled()
115
+ }
116
+
117
+ // Restore
118
+ ;(Engage as any).addAttribute = originalAddAttribute
119
+ })
120
+ })
121
+ })
package/tsconfig.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "module": "NodeNext",
5
5
  "declaration": true,
6
6
  "declarationMap": true,
7
- "outDir": "./dist",
7
+ "outDir": "./dist/",
8
8
  "esModuleInterop": true,
9
9
  "forceConsistentCasingInFileNames": true,
10
10
  "strict": true,
@@ -12,7 +12,6 @@
12
12
  },
13
13
  "exclude": [
14
14
  "node_modules",
15
- "tests",
16
- "dist"
15
+ "tests"
17
16
  ]
18
17
  }
package/.eslintignore DELETED
@@ -1,3 +0,0 @@
1
- dist
2
- node_modules
3
- tests
package/dist/error.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export declare class EngageError extends Error {
2
- constructor(message: string);
3
- }
4
- //# sourceMappingURL=error.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAY,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI7B"}
package/dist/error.js DELETED
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EngageError = void 0;
4
- class EngageError extends Error {
5
- constructor(message) {
6
- super(message);
7
- this.name = 'EngageError';
8
- }
9
- }
10
- exports.EngageError = EngageError;
package/dist/index.d.ts DELETED
@@ -1,32 +0,0 @@
1
- interface Key {
2
- key?: string;
3
- secret?: string;
4
- }
5
- interface EventParameter {
6
- event: string;
7
- value?: string | number | Date | boolean;
8
- properties?: {
9
- [key: string]: string | number | Date | boolean;
10
- };
11
- timestamp?: string | number | Date;
12
- }
13
- type UserAttrParams = {
14
- [key: string]: string | number | Date | boolean;
15
- };
16
- type UserIdentifyParams = UserAttrParams & {
17
- id: string;
18
- };
19
- type Methods = 'POST' | 'PUT' | 'DELETE';
20
- export declare function request(url: string, params: Record<string, any> | null, method: Methods): object;
21
- export declare function init(key: Key | string): void;
22
- export declare function identify(user: UserIdentifyParams): Promise<any>;
23
- export declare function addAttribute(uid: string, attributes: UserAttrParams): Promise<any>;
24
- export declare function track(uid: string, data: EventParameter): Promise<any>;
25
- export declare function merge(sourceUid: string, destinationUid: string): Promise<any>;
26
- export declare function addToAccount(uid: string, accountId: string, role: string): Promise<any>;
27
- export declare function removeFromAccount(uid: string, accountId: string): Promise<any>;
28
- export declare function changeAccountRole(uid: string, accountId: string, role: string): Promise<any>;
29
- export declare function convertToCustomer(uid: string): Promise<any>;
30
- export declare function convertToAccount(uid: string): Promise<any>;
31
- export {};
32
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,UAAU,GAAG;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AACD,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;IACxC,UAAU,CAAC,EAAE;QACX,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;KAChD,CAAA;IACD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CACnC;AACD,KAAK,cAAc,GAAG;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;CAChD,CAAA;AACD,KAAK,kBAAkB,GAAG,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAQzD,KAAK,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;AA2CxC,wBAAgB,OAAO,CAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAEjG;AAED,wBAAgB,IAAI,CAAE,GAAG,EAAE,GAAG,GAAG,MAAM,QAwBtC;AAGD,wBAAsB,QAAQ,CAAE,IAAI,EAAE,kBAAkB,gBAqBvD;AACD,wBAAsB,YAAY,CAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,gBAwB1E;AACD,wBAAsB,KAAK,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,gBAmB7D;AAED,wBAAsB,KAAK,CAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,gBAYrE;AAGD,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAiB9E;AACD,wBAAsB,iBAAiB,CAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gBAQtE;AACD,wBAAsB,iBAAiB,CAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAWpF;AACD,wBAAsB,iBAAiB,CAAE,GAAG,EAAE,MAAM,gBAKnD;AACD,wBAAsB,gBAAgB,CAAE,GAAG,EAAE,MAAM,gBAKlD"}
package/dist/index.js DELETED
@@ -1,256 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.convertToAccount = exports.convertToCustomer = exports.changeAccountRole = exports.removeFromAccount = exports.addToAccount = exports.merge = exports.track = exports.addAttribute = exports.identify = exports.init = exports.request = void 0;
16
- const buffer_1 = require("buffer");
17
- const cross_fetch_1 = __importDefault(require("cross-fetch"));
18
- const error_1 = require("./error");
19
- if (typeof btoa === 'undefined') {
20
- global.btoa = function (str) {
21
- return buffer_1.Buffer.from(str).toString('base64');
22
- };
23
- }
24
- // type UserIdentifyParams = {
25
- // id: string
26
- // [key: string]: string | number | Date | boolean
27
- // }
28
- // type UserAttrParams = Omit<UserIdentifyParams, 'id'>
29
- // const rootURL = 'https://api.engage.so/v1'
30
- let auth = '';
31
- const notMeta = ['created_at', 'is_account', 'number', 'device_token', 'device_platform', 'email', 'first_name', 'last_name', 'tz', 'app_version', 'app_build', 'app_last_active'];
32
- const apiRoot = 'https://api.engage.so/v1';
33
- function _request(url, params, method) {
34
- return __awaiter(this, void 0, void 0, function* () {
35
- try {
36
- const o = {
37
- method,
38
- headers: {
39
- 'Content-Type': 'application/json;charset=utf-8',
40
- Authorization: `Basic ${auth}`
41
- },
42
- // throwHttpErrors: false,
43
- // prefixUrl: rootURL
44
- };
45
- if (params) {
46
- o.body = JSON.stringify(params);
47
- }
48
- // const response = await ky(url, o)
49
- const response = yield (0, cross_fetch_1.default)(`${apiRoot}${url}`, o);
50
- const body = yield response.json();
51
- let error = 'API connection error';
52
- if (!response.ok) {
53
- if (body && body.error) {
54
- error = body.error;
55
- }
56
- return { error };
57
- }
58
- return body;
59
- }
60
- catch (e) {
61
- return { error: 'API connection error' };
62
- }
63
- });
64
- }
65
- // Alias of _request method
66
- // Same with _request for now but can later have modifications
67
- function request(url, params, method) {
68
- return _request(url, params, method);
69
- }
70
- exports.request = request;
71
- function init(key) {
72
- if (!key) {
73
- throw new error_1.EngageError('You need to pass in your API key(s).');
74
- }
75
- const options = {
76
- key: undefined,
77
- secret: ''
78
- };
79
- if (typeof key === 'string') {
80
- options.key = key;
81
- }
82
- else {
83
- if (!key.key) {
84
- throw new error_1.EngageError('`key` missing in object.');
85
- }
86
- if (key.key) {
87
- options.key = `${key.key}`;
88
- }
89
- if (key.secret) {
90
- options.secret = `${key.secret}`;
91
- }
92
- }
93
- // Set auth
94
- // auth = Buffer.from(`${options.key}:${options.secret}`).toString('base64')
95
- auth = btoa(`${options.key}:${options.secret}`);
96
- }
97
- exports.init = init;
98
- // Data tracking
99
- function identify(user) {
100
- return __awaiter(this, void 0, void 0, function* () {
101
- if (!user) {
102
- throw new error_1.EngageError('You need to pass an object with at least an id.');
103
- }
104
- if (!user.id) {
105
- throw new error_1.EngageError('ID missing.');
106
- }
107
- if (user.email && (typeof user.email !== 'string' || !/^\S+@\S+$/.test(user.email))) {
108
- throw new error_1.EngageError('Email invalid.');
109
- }
110
- const params = {};
111
- params.meta = {};
112
- for (const k in user) {
113
- if (k === 'id' || notMeta.includes(k)) {
114
- params[k] = user[k];
115
- }
116
- else {
117
- params.meta[k] = user[k];
118
- }
119
- }
120
- return _request(`/users/${user.id}`, params, 'PUT');
121
- });
122
- }
123
- exports.identify = identify;
124
- function addAttribute(uid, attributes) {
125
- return __awaiter(this, void 0, void 0, function* () {
126
- if (!uid) {
127
- throw new error_1.EngageError('User ID missing.');
128
- }
129
- if (!attributes) {
130
- throw new error_1.EngageError('Attributes missing.');
131
- }
132
- if (!Object.keys(attributes).length) {
133
- throw new error_1.EngageError('Attributes missing.');
134
- }
135
- const params = {};
136
- params.meta = {};
137
- for (const k in attributes) {
138
- if (notMeta.includes(k)) {
139
- params[k] = attributes[k];
140
- }
141
- else {
142
- params.meta[k] = attributes[k];
143
- }
144
- }
145
- if (!Object.keys(params.meta).length) {
146
- delete params.meta;
147
- }
148
- return _request(`/users/${uid}`, params, 'PUT');
149
- });
150
- }
151
- exports.addAttribute = addAttribute;
152
- function track(uid, data) {
153
- return __awaiter(this, void 0, void 0, function* () {
154
- if (!uid) {
155
- throw new error_1.EngageError('User ID missing.');
156
- }
157
- if (!data) {
158
- throw new error_1.EngageError('Event data missing.');
159
- }
160
- if (typeof data === 'string') {
161
- data = {
162
- event: data,
163
- value: true
164
- };
165
- }
166
- else {
167
- if (!Object.keys(data).length) {
168
- throw new error_1.EngageError('Attributes missing.');
169
- }
170
- }
171
- return _request(`/users/${uid}/events`, data, 'POST');
172
- });
173
- }
174
- exports.track = track;
175
- function merge(sourceUid, destinationUid) {
176
- return __awaiter(this, void 0, void 0, function* () {
177
- if (!sourceUid) {
178
- throw new error_1.EngageError('Source ID missing.');
179
- }
180
- if (!destinationUid) {
181
- throw new error_1.EngageError('Destination ID missing.');
182
- }
183
- return _request(`/users/merge`, {
184
- source: sourceUid,
185
- destination: destinationUid
186
- }, 'POST');
187
- });
188
- }
189
- exports.merge = merge;
190
- // Account functions
191
- function addToAccount(uid, accountId, role) {
192
- return __awaiter(this, void 0, void 0, function* () {
193
- if (!uid) {
194
- throw new error_1.EngageError('User ID missing.');
195
- }
196
- if (!accountId) {
197
- throw new error_1.EngageError('Account ID missing.');
198
- }
199
- if (role && typeof role !== 'string') {
200
- throw new error_1.EngageError('Role should be a text.');
201
- }
202
- const g = {
203
- id: accountId
204
- };
205
- if (role) {
206
- g.role = role;
207
- }
208
- return _request(`/users/${uid}/accounts`, { accounts: [g] }, 'POST');
209
- });
210
- }
211
- exports.addToAccount = addToAccount;
212
- function removeFromAccount(uid, accountId) {
213
- return __awaiter(this, void 0, void 0, function* () {
214
- if (!uid) {
215
- throw new error_1.EngageError('User ID missing.');
216
- }
217
- if (!accountId) {
218
- throw new error_1.EngageError('Account ID missing.');
219
- }
220
- return _request(`/users/${uid}/accounts/${accountId}`, null, 'DELETE');
221
- });
222
- }
223
- exports.removeFromAccount = removeFromAccount;
224
- function changeAccountRole(uid, accountId, role) {
225
- return __awaiter(this, void 0, void 0, function* () {
226
- if (!uid) {
227
- throw new error_1.EngageError('User ID missing.');
228
- }
229
- if (!accountId) {
230
- throw new error_1.EngageError('Account ID missing.');
231
- }
232
- if (!role) {
233
- throw new error_1.EngageError('New role missing.');
234
- }
235
- return _request(`/users/${uid}/accounts/${accountId}`, { role }, 'PUT');
236
- });
237
- }
238
- exports.changeAccountRole = changeAccountRole;
239
- function convertToCustomer(uid) {
240
- return __awaiter(this, void 0, void 0, function* () {
241
- if (!uid) {
242
- throw new error_1.EngageError('User ID missing.');
243
- }
244
- return _request(`/users/${uid}/convert`, { type: 'customer' }, 'POST');
245
- });
246
- }
247
- exports.convertToCustomer = convertToCustomer;
248
- function convertToAccount(uid) {
249
- return __awaiter(this, void 0, void 0, function* () {
250
- if (!uid) {
251
- throw new error_1.EngageError('User ID missing.');
252
- }
253
- return _request(`/users/${uid}/convert`, { type: 'account' }, 'POST');
254
- });
255
- }
256
- exports.convertToAccount = convertToAccount;