@customerio/cdp-analytics-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/LICENSE.MD +22 -0
  2. package/README.md +3 -0
  3. package/dist/cjs/analytics/dispatch.js +54 -0
  4. package/dist/cjs/analytics/dispatch.js.map +1 -0
  5. package/dist/cjs/analytics/index.js +3 -0
  6. package/dist/cjs/analytics/index.js.map +1 -0
  7. package/dist/cjs/callback/index.js +46 -0
  8. package/dist/cjs/callback/index.js.map +1 -0
  9. package/dist/cjs/connection/index.js +16 -0
  10. package/dist/cjs/connection/index.js.map +1 -0
  11. package/dist/cjs/context/index.js +87 -0
  12. package/dist/cjs/context/index.js.map +1 -0
  13. package/dist/cjs/emitter/index.js +66 -0
  14. package/dist/cjs/emitter/index.js.map +1 -0
  15. package/dist/cjs/emitter/interface.js +3 -0
  16. package/dist/cjs/emitter/interface.js.map +1 -0
  17. package/dist/cjs/events/index.js +149 -0
  18. package/dist/cjs/events/index.js.map +1 -0
  19. package/dist/cjs/events/interfaces.js +3 -0
  20. package/dist/cjs/events/interfaces.js.map +1 -0
  21. package/dist/cjs/index.js +25 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/logger/index.js +62 -0
  24. package/dist/cjs/logger/index.js.map +1 -0
  25. package/dist/cjs/plugins/index.js +3 -0
  26. package/dist/cjs/plugins/index.js.map +1 -0
  27. package/dist/cjs/priority-queue/backoff.js +10 -0
  28. package/dist/cjs/priority-queue/backoff.js.map +1 -0
  29. package/dist/cjs/priority-queue/index.js +92 -0
  30. package/dist/cjs/priority-queue/index.js.map +1 -0
  31. package/dist/cjs/queue/delivery.js +69 -0
  32. package/dist/cjs/queue/delivery.js.map +1 -0
  33. package/dist/cjs/queue/event-queue.js +340 -0
  34. package/dist/cjs/queue/event-queue.js.map +1 -0
  35. package/dist/cjs/stats/index.js +96 -0
  36. package/dist/cjs/stats/index.js.map +1 -0
  37. package/dist/cjs/task/task-group.js +24 -0
  38. package/dist/cjs/task/task-group.js.map +1 -0
  39. package/dist/cjs/user/index.js +3 -0
  40. package/dist/cjs/user/index.js.map +1 -0
  41. package/dist/cjs/utils/bind-all.js +18 -0
  42. package/dist/cjs/utils/bind-all.js.map +1 -0
  43. package/dist/cjs/utils/environment.js +12 -0
  44. package/dist/cjs/utils/environment.js.map +1 -0
  45. package/dist/cjs/utils/get-global.js +21 -0
  46. package/dist/cjs/utils/get-global.js.map +1 -0
  47. package/dist/cjs/utils/group-by.js +28 -0
  48. package/dist/cjs/utils/group-by.js.map +1 -0
  49. package/dist/cjs/utils/has-properties.js +13 -0
  50. package/dist/cjs/utils/has-properties.js.map +1 -0
  51. package/dist/cjs/utils/is-plain-object.js +28 -0
  52. package/dist/cjs/utils/is-plain-object.js.map +1 -0
  53. package/dist/cjs/utils/is-thenable.js +15 -0
  54. package/dist/cjs/utils/is-thenable.js.map +1 -0
  55. package/dist/cjs/utils/p-while.js +25 -0
  56. package/dist/cjs/utils/p-while.js.map +1 -0
  57. package/dist/cjs/utils/pick.js +10 -0
  58. package/dist/cjs/utils/pick.js.map +1 -0
  59. package/dist/cjs/utils/ts-helpers.js +3 -0
  60. package/dist/cjs/utils/ts-helpers.js.map +1 -0
  61. package/dist/cjs/validation/assertions.js +41 -0
  62. package/dist/cjs/validation/assertions.js.map +1 -0
  63. package/dist/cjs/validation/helpers.js +26 -0
  64. package/dist/cjs/validation/helpers.js.map +1 -0
  65. package/dist/esm/analytics/dispatch.js +49 -0
  66. package/dist/esm/analytics/dispatch.js.map +1 -0
  67. package/dist/esm/analytics/index.js +2 -0
  68. package/dist/esm/analytics/index.js.map +1 -0
  69. package/dist/esm/callback/index.js +40 -0
  70. package/dist/esm/callback/index.js.map +1 -0
  71. package/dist/esm/connection/index.js +11 -0
  72. package/dist/esm/connection/index.js.map +1 -0
  73. package/dist/esm/context/index.js +84 -0
  74. package/dist/esm/context/index.js.map +1 -0
  75. package/dist/esm/emitter/index.js +63 -0
  76. package/dist/esm/emitter/index.js.map +1 -0
  77. package/dist/esm/emitter/interface.js +2 -0
  78. package/dist/esm/emitter/interface.js.map +1 -0
  79. package/dist/esm/events/index.js +146 -0
  80. package/dist/esm/events/index.js.map +1 -0
  81. package/dist/esm/events/interfaces.js +2 -0
  82. package/dist/esm/events/interfaces.js.map +1 -0
  83. package/dist/esm/index.js +19 -0
  84. package/dist/esm/index.js.map +1 -0
  85. package/dist/esm/logger/index.js +59 -0
  86. package/dist/esm/logger/index.js.map +1 -0
  87. package/dist/esm/plugins/index.js +2 -0
  88. package/dist/esm/plugins/index.js.map +1 -0
  89. package/dist/esm/priority-queue/backoff.js +6 -0
  90. package/dist/esm/priority-queue/backoff.js.map +1 -0
  91. package/dist/esm/priority-queue/index.js +89 -0
  92. package/dist/esm/priority-queue/index.js.map +1 -0
  93. package/dist/esm/queue/delivery.js +64 -0
  94. package/dist/esm/queue/delivery.js.map +1 -0
  95. package/dist/esm/queue/event-queue.js +337 -0
  96. package/dist/esm/queue/event-queue.js.map +1 -0
  97. package/dist/esm/stats/index.js +93 -0
  98. package/dist/esm/stats/index.js.map +1 -0
  99. package/dist/esm/task/task-group.js +20 -0
  100. package/dist/esm/task/task-group.js.map +1 -0
  101. package/dist/esm/user/index.js +2 -0
  102. package/dist/esm/user/index.js.map +1 -0
  103. package/dist/esm/utils/bind-all.js +14 -0
  104. package/dist/esm/utils/bind-all.js.map +1 -0
  105. package/dist/esm/utils/environment.js +7 -0
  106. package/dist/esm/utils/environment.js.map +1 -0
  107. package/dist/esm/utils/get-global.js +17 -0
  108. package/dist/esm/utils/get-global.js.map +1 -0
  109. package/dist/esm/utils/group-by.js +24 -0
  110. package/dist/esm/utils/group-by.js.map +1 -0
  111. package/dist/esm/utils/has-properties.js +9 -0
  112. package/dist/esm/utils/has-properties.js.map +1 -0
  113. package/dist/esm/utils/is-plain-object.js +24 -0
  114. package/dist/esm/utils/is-plain-object.js.map +1 -0
  115. package/dist/esm/utils/is-thenable.js +11 -0
  116. package/dist/esm/utils/is-thenable.js.map +1 -0
  117. package/dist/esm/utils/p-while.js +21 -0
  118. package/dist/esm/utils/p-while.js.map +1 -0
  119. package/dist/esm/utils/pick.js +6 -0
  120. package/dist/esm/utils/pick.js.map +1 -0
  121. package/dist/esm/utils/ts-helpers.js +2 -0
  122. package/dist/esm/utils/ts-helpers.js.map +1 -0
  123. package/dist/esm/validation/assertions.js +37 -0
  124. package/dist/esm/validation/assertions.js.map +1 -0
  125. package/dist/esm/validation/helpers.js +18 -0
  126. package/dist/esm/validation/helpers.js.map +1 -0
  127. package/dist/types/analytics/dispatch.d.ts +20 -0
  128. package/dist/types/analytics/dispatch.d.ts.map +1 -0
  129. package/dist/types/analytics/index.d.ts +12 -0
  130. package/dist/types/analytics/index.d.ts.map +1 -0
  131. package/dist/types/callback/index.d.ts +11 -0
  132. package/dist/types/callback/index.d.ts.map +1 -0
  133. package/dist/types/connection/index.d.ts +3 -0
  134. package/dist/types/connection/index.d.ts.map +1 -0
  135. package/dist/types/context/index.d.ts +44 -0
  136. package/dist/types/context/index.d.ts.map +1 -0
  137. package/dist/types/emitter/index.d.ts +25 -0
  138. package/dist/types/emitter/index.d.ts.map +1 -0
  139. package/dist/types/emitter/interface.d.ts +27 -0
  140. package/dist/types/emitter/interface.d.ts.map +1 -0
  141. package/dist/types/events/index.d.ts +27 -0
  142. package/dist/types/events/index.d.ts.map +1 -0
  143. package/dist/types/events/interfaces.d.ts +373 -0
  144. package/dist/types/events/interfaces.d.ts.map +1 -0
  145. package/dist/types/index.d.ts +19 -0
  146. package/dist/types/index.d.ts.map +1 -0
  147. package/dist/types/logger/index.d.ts +19 -0
  148. package/dist/types/logger/index.d.ts.map +1 -0
  149. package/dist/types/plugins/index.d.ts +25 -0
  150. package/dist/types/plugins/index.d.ts.map +1 -0
  151. package/dist/types/priority-queue/backoff.d.ts +13 -0
  152. package/dist/types/priority-queue/backoff.d.ts.map +1 -0
  153. package/dist/types/priority-queue/index.d.ts +25 -0
  154. package/dist/types/priority-queue/index.d.ts.map +1 -0
  155. package/dist/types/queue/delivery.d.ts +5 -0
  156. package/dist/types/queue/delivery.d.ts.map +1 -0
  157. package/dist/types/queue/event-queue.d.ts +43 -0
  158. package/dist/types/queue/event-queue.d.ts.map +1 -0
  159. package/dist/types/stats/index.d.ts +34 -0
  160. package/dist/types/stats/index.d.ts.map +1 -0
  161. package/dist/types/task/task-group.d.ts +6 -0
  162. package/dist/types/task/task-group.d.ts.map +1 -0
  163. package/dist/types/user/index.d.ts +6 -0
  164. package/dist/types/user/index.d.ts.map +1 -0
  165. package/dist/types/utils/bind-all.d.ts +4 -0
  166. package/dist/types/utils/bind-all.d.ts.map +1 -0
  167. package/dist/types/utils/environment.d.ts +3 -0
  168. package/dist/types/utils/environment.d.ts.map +1 -0
  169. package/dist/types/utils/get-global.d.ts +2 -0
  170. package/dist/types/utils/get-global.d.ts.map +1 -0
  171. package/dist/types/utils/group-by.d.ts +4 -0
  172. package/dist/types/utils/group-by.d.ts.map +1 -0
  173. package/dist/types/utils/has-properties.d.ts +4 -0
  174. package/dist/types/utils/has-properties.d.ts.map +1 -0
  175. package/dist/types/utils/is-plain-object.d.ts +2 -0
  176. package/dist/types/utils/is-plain-object.d.ts.map +1 -0
  177. package/dist/types/utils/is-thenable.d.ts +6 -0
  178. package/dist/types/utils/is-thenable.d.ts.map +1 -0
  179. package/dist/types/utils/p-while.d.ts +2 -0
  180. package/dist/types/utils/p-while.d.ts.map +1 -0
  181. package/dist/types/utils/pick.d.ts +2 -0
  182. package/dist/types/utils/pick.d.ts.map +1 -0
  183. package/dist/types/utils/ts-helpers.d.ts +13 -0
  184. package/dist/types/utils/ts-helpers.d.ts.map +1 -0
  185. package/dist/types/validation/assertions.d.ts +7 -0
  186. package/dist/types/validation/assertions.d.ts.map +1 -0
  187. package/dist/types/validation/helpers.d.ts +7 -0
  188. package/dist/types/validation/helpers.d.ts.map +1 -0
  189. package/package.json +39 -0
  190. package/src/analytics/dispatch.ts +58 -0
  191. package/src/analytics/index.ts +11 -0
  192. package/src/callback/index.ts +51 -0
  193. package/src/connection/index.ts +13 -0
  194. package/src/context/index.ts +123 -0
  195. package/src/emitter/index.ts +65 -0
  196. package/src/emitter/interface.ts +31 -0
  197. package/src/events/index.ts +280 -0
  198. package/src/events/interfaces.ts +447 -0
  199. package/src/index.ts +18 -0
  200. package/src/logger/index.ts +74 -0
  201. package/src/plugins/index.ts +43 -0
  202. package/src/priority-queue/backoff.ts +24 -0
  203. package/src/priority-queue/index.ts +103 -0
  204. package/src/queue/delivery.ts +73 -0
  205. package/src/queue/event-queue.ts +320 -0
  206. package/src/stats/index.ts +88 -0
  207. package/src/task/task-group.ts +31 -0
  208. package/src/user/index.ts +7 -0
  209. package/src/utils/bind-all.ts +19 -0
  210. package/src/utils/environment.ts +7 -0
  211. package/src/utils/get-global.ts +16 -0
  212. package/src/utils/group-by.ts +30 -0
  213. package/src/utils/has-properties.ts +7 -0
  214. package/src/utils/is-plain-object.ts +26 -0
  215. package/src/utils/is-thenable.ts +9 -0
  216. package/src/utils/p-while.ts +12 -0
  217. package/src/utils/pick.ts +8 -0
  218. package/src/utils/ts-helpers.ts +13 -0
  219. package/src/validation/assertions.ts +43 -0
  220. package/src/validation/helpers.ts +27 -0
@@ -0,0 +1,447 @@
1
+ import { CoreContext } from '../context'
2
+ import { ID } from '../user'
3
+ import { DeepNullable } from '../utils/ts-helpers'
4
+
5
+ export type Callback<Ctx extends CoreContext = CoreContext> = (
6
+ ctx: Ctx
7
+ ) => Promise<unknown> | unknown
8
+
9
+ export type CustomerioEventType =
10
+ | 'track'
11
+ | 'page'
12
+ | 'identify'
13
+ | 'group'
14
+ | 'alias'
15
+ | 'screen'
16
+
17
+ export type JSONPrimitive = string | number | boolean | null
18
+ export type JSONValue = JSONPrimitive | JSONObject | JSONArray
19
+ export type JSONObject = { [member: string]: JSONValue }
20
+ export type JSONArray = JSONValue[]
21
+
22
+ export type EventProperties = Record<string, any>
23
+
24
+ export type Integrations = {
25
+ All?: boolean
26
+ [integration: string]: boolean | JSONObject | undefined
27
+ }
28
+
29
+ export interface CoreOptions {
30
+ integrations?: Integrations
31
+ timestamp?: Timestamp
32
+ context?: CoreExtraContext
33
+ anonymousId?: string
34
+ userId?: string
35
+ traits?: Traits
36
+ // ugh, this is ugly, but we allow literally any property to be passed to options (which get spread onto the event)
37
+ [key: string]: any
38
+ }
39
+
40
+ /**
41
+ * Context is a dictionary of extra information that provides useful context about a datapoint, for example the user’s ip address or locale. You should only use Context fields for their intended meaning.
42
+ */
43
+ export interface CoreExtraContext {
44
+ /**
45
+ * This is usually used to flag an .identify() call to just update the trait, rather than "last seen".
46
+ */
47
+ active?: boolean
48
+
49
+ /**
50
+ * Current user's IP address.
51
+ */
52
+ ip?: string
53
+
54
+ /**
55
+ * Locale string for the current user, for example en-US.
56
+ * @example en-US
57
+ */
58
+ locale?: string
59
+ /**
60
+ * Dictionary of information about the user’s current location.
61
+ */
62
+ location?: {
63
+ /**
64
+ * @example San Francisco
65
+ */
66
+ city?: string
67
+ /**
68
+ * @example United States
69
+ */
70
+ country?: string
71
+ /**
72
+ * @example 40.2964197
73
+ */
74
+ latitude?: string
75
+ /**
76
+ * @example -76.9411617
77
+ */
78
+ longitude?: string
79
+ /**
80
+ * @example CA
81
+ */
82
+ region?: string
83
+ /**
84
+ * @example 100
85
+ */
86
+ speed?: number
87
+ }
88
+
89
+ /**
90
+ * Dictionary of information about the current web page.
91
+ */
92
+ page?: {
93
+ /**
94
+ * @example /academy/
95
+ */
96
+ path?: string
97
+ /**
98
+ * @example https://www.foo.com/
99
+ */
100
+ referrer?: string
101
+ /**
102
+ * @example projectId=123
103
+ */
104
+ search?: string
105
+ /**
106
+ * @example Analytics Academy
107
+ */
108
+ title?: string
109
+ /**
110
+ * @example https://foobar.com/academy/
111
+ */
112
+ url?: string
113
+ }
114
+
115
+ /**
116
+ * User agent of the device making the request.
117
+ */
118
+ userAgent?: string
119
+
120
+ /**
121
+ * Information about the current library.
122
+ *
123
+ * **Automatically filled out by the library.**
124
+ *
125
+ * This type should probably be "never"
126
+ */
127
+ library?: {
128
+ /**
129
+ * @example analytics-node-next/latest
130
+ */
131
+ name: string
132
+ /**
133
+ * @example "1.43.1"
134
+ */
135
+ version: string
136
+ }
137
+
138
+ /**
139
+ * This is useful in cases where you need to track an event,
140
+ * but also associate information from a previous identify call.
141
+ * You should fill this object the same way you would fill traits in an identify call.
142
+ */
143
+ traits?: Traits
144
+
145
+ /**
146
+ * Dictionary of information about the campaign that resulted in the API call, containing name, source, medium, term, content, and any other custom UTM parameter.
147
+ */
148
+ campaign?: {
149
+ name: string
150
+ term: string
151
+ source: string
152
+ medium: string
153
+ content: string
154
+ }
155
+
156
+ /**
157
+ * Dictionary of information about the way the user was referred to the website or app.
158
+ */
159
+ referrer?: {
160
+ type?: string
161
+ name?: string
162
+ url?: string
163
+ link?: string
164
+
165
+ id?: string // undocumented
166
+ btid?: string // undocumented?
167
+ urid?: string // undocumented?
168
+ }
169
+
170
+ amp?: {
171
+ // undocumented?
172
+ id: string
173
+ }
174
+
175
+ [key: string]: any
176
+ }
177
+
178
+ export interface CoreCustomerioEvent {
179
+ messageId?: string
180
+ type: CustomerioEventType
181
+
182
+ // page specific
183
+ category?: string
184
+ name?: string
185
+
186
+ properties?: EventProperties
187
+
188
+ traits?: Traits // Traits is only defined in 'identify' and 'group', even if it can be passed in other calls.
189
+
190
+ integrations?: Integrations
191
+ context?: CoreExtraContext
192
+ options?: CoreOptions
193
+
194
+ userId?: ID
195
+ anonymousId?: ID
196
+ groupId?: ID
197
+ previousId?: ID
198
+
199
+ event?: string
200
+
201
+ writeKey?: string
202
+
203
+ sentAt?: Date
204
+
205
+ _metadata?: CustomerioEventMetadata
206
+
207
+ timestamp?: Timestamp
208
+ }
209
+
210
+ export interface CustomerioEventMetadata {
211
+ failedInitializations?: unknown[]
212
+ bundled?: string[]
213
+ unbundled?: string[]
214
+ nodeVersion?: string
215
+ bundledConfigIds?: string[]
216
+ unbundledConfigIds?: string[]
217
+ bundledIds?: string[]
218
+ }
219
+
220
+ export type Timestamp = Date | string
221
+
222
+ /**
223
+ * A Plan allows users to specify events and which destinations they would like them to be sent to
224
+ */
225
+ export interface Plan {
226
+ track?: TrackPlan
227
+ identify?: TrackPlan
228
+ group?: TrackPlan
229
+ }
230
+
231
+ export interface TrackPlan {
232
+ [key: string]: PlanEvent | undefined
233
+ // __default SHOULD always exist, but marking as optional for extra safety.
234
+ __default?: PlanEvent
235
+ }
236
+
237
+ export interface PlanEvent {
238
+ /**
239
+ * Whether or not this plan event is enabled
240
+ */
241
+ enabled: boolean
242
+ /**
243
+ * Which integrations the plan event applies to
244
+ */
245
+ integrations?: {
246
+ [key: string]: boolean
247
+ }
248
+ }
249
+
250
+ type DbId = string | number // TODO: the docs says that this can only be a string?
251
+ type PhoneNumber = string | number // TODO: the docs say this can only be a string?
252
+
253
+ /**
254
+ * Traits are pieces of information you know about a group.
255
+ */
256
+ type BaseGroupTraits = DeepNullable<{
257
+ /**
258
+ * Street address of a group.
259
+ */
260
+ address?: BaseUserTraits['address']
261
+
262
+ /**
263
+ * URL to an avatar image for the group.
264
+ */
265
+ avatar?: BaseUserTraits['avatar']
266
+
267
+ /**
268
+ * Date the group's account was first created. We recommend ISO-8601 date strings.
269
+ */
270
+ createdAt?: BaseUserTraits['createdAt']
271
+
272
+ /**
273
+ * Description of a group
274
+ */
275
+ description?: BaseUserTraits['description']
276
+ /**
277
+ * Email address of group.
278
+ */
279
+ email?: BaseUserTraits['email']
280
+ /**
281
+ * Number of employees of a group, typically used for companies.
282
+ */
283
+ employees?: string | number // TODO: the docs says that this must be a string?
284
+
285
+ /**
286
+ * Unique ID in your database for a group.
287
+ */
288
+ id?: BaseUserTraits['id']
289
+
290
+ /**
291
+ * Industry a group is part of.
292
+ */
293
+ industry?: BaseUserTraits['industry']
294
+
295
+ /**
296
+ * Name of a group.
297
+ */
298
+ name?: BaseUserTraits['name']
299
+
300
+ /**
301
+ * Phone number of a group
302
+ */
303
+ phone?: BaseUserTraits['phone']
304
+
305
+ /**
306
+ * Website of a group.
307
+ */
308
+ website?: BaseUserTraits['website']
309
+
310
+ /**
311
+ * Plan that a group is in.
312
+ */
313
+ plan?: BaseUserTraits['plan']
314
+ }>
315
+
316
+ /**
317
+ * Traits are pieces of information you know about a user.
318
+ */
319
+ type BaseUserTraits = DeepNullable<{
320
+ /**
321
+ * Unique ID in your database for a user
322
+ */
323
+ id?: DbId
324
+
325
+ /**
326
+ * Industry a user works in
327
+ */
328
+ industry?: string
329
+
330
+ /**
331
+ * First name of a user.
332
+ */
333
+ firstName?: string
334
+
335
+ /**
336
+ * Last name of a user.
337
+ */
338
+ lastName?: string
339
+
340
+ /**
341
+ * Full name of a user. If you only pass a first and last name we will automatically fill in the full name for you.
342
+ */
343
+ name?: string
344
+
345
+ /**
346
+ * Phone number of a user
347
+ */
348
+ phone?: PhoneNumber
349
+
350
+ /**
351
+ * Title of a user, usually related to their position at a specific company.
352
+ * @example VP of Engineering
353
+ */
354
+ title?: string
355
+
356
+ /**
357
+ * User's username. This should be unique to each user, like the usernames of Twitter or GitHub.
358
+ */
359
+ username?: string
360
+
361
+ /**
362
+ * Website of a user.
363
+ */
364
+ website?: string
365
+
366
+ /**
367
+ * Street address of a user.
368
+ */
369
+ address?: {
370
+ city?: string
371
+ country?: string
372
+ postalCode?: string
373
+ state?: string
374
+ street?: string
375
+ }
376
+ /**
377
+ * Age of a user.
378
+ */
379
+ age?: number
380
+
381
+ /**
382
+ * URL to an avatar image for the user.
383
+ */
384
+ avatar?: string
385
+
386
+ /**
387
+ * User's birthday.
388
+ */
389
+ birthday?: Timestamp
390
+
391
+ /**
392
+ * User's company.
393
+ */
394
+ company?: {
395
+ name?: string
396
+ id?: DbId
397
+ industry?: BaseUserTraits['industry']
398
+ employee_count?: number
399
+ plan?: BaseUserTraits['plan']
400
+ }
401
+
402
+ /**
403
+ Plan that a user is in.
404
+
405
+ * @example enterprise
406
+ */
407
+ plan?: string
408
+
409
+ /**
410
+ * Date the user's account was first created. We recommend using ISO-8601 date strings.
411
+ */
412
+ createdAt?: Timestamp
413
+
414
+ /**
415
+ * Description of user, such as bio.
416
+ */
417
+ description?: string
418
+
419
+ /**
420
+ * Email address of a user.
421
+ */
422
+ email?: string
423
+
424
+ /**
425
+ * @example female
426
+ */
427
+ gender?: string
428
+ }>
429
+
430
+ /**
431
+ * Traits are pieces of information you know about a group.
432
+ */
433
+ export type GroupTraits = BaseGroupTraits & {
434
+ [customTrait: string]: any
435
+ }
436
+
437
+ /**
438
+ * Traits are pieces of information you know about a user.
439
+ */
440
+ export type UserTraits = BaseUserTraits & {
441
+ [customTrait: string]: any
442
+ }
443
+
444
+ /**
445
+ * Traits are pieces of information you know about a user or group.
446
+ */
447
+ export type Traits = UserTraits | GroupTraits
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ export * from './emitter'
2
+ export * from './emitter/interface'
3
+ export * from './plugins'
4
+ export * from './events/interfaces'
5
+ export * from './events'
6
+ export * from './callback'
7
+ export * from './priority-queue'
8
+ export { backoff } from './priority-queue/backoff'
9
+ export * from './context'
10
+ export * from './queue/event-queue'
11
+ export * from './analytics'
12
+ export * from './analytics/dispatch'
13
+ export * from './validation/helpers'
14
+ export * from './validation/assertions'
15
+ export * from './utils/bind-all'
16
+ export * from './stats'
17
+ export { CoreLogger } from './logger'
18
+ export * from './queue/delivery'
@@ -0,0 +1,74 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
2
+ export type LogMessage = {
3
+ level: LogLevel
4
+ message: string
5
+ time?: Date
6
+ extras?: Record<string, any>
7
+ }
8
+
9
+ export interface GenericLogger {
10
+ log(level: LogLevel, message: string, extras?: object): void
11
+ flush(): void
12
+ logs: LogMessage[]
13
+ }
14
+
15
+ export class CoreLogger implements GenericLogger {
16
+ private _logs: LogMessage[] = []
17
+
18
+ log(level: LogLevel, message: string, extras?: object) {
19
+ const time = new Date()
20
+ this._logs.push({
21
+ level,
22
+ message,
23
+ time,
24
+ extras,
25
+ })
26
+ }
27
+
28
+ public get logs(): LogMessage[] {
29
+ return this._logs
30
+ }
31
+
32
+ public flush(): void {
33
+ if (this.logs.length > 1) {
34
+ const formatted = this._logs.reduce((logs, log) => {
35
+ const line = {
36
+ ...log,
37
+ json: JSON.stringify(log.extras, null, ' '),
38
+ extras: log.extras,
39
+ }
40
+
41
+ delete line['time']
42
+
43
+ let key = log.time?.toISOString() ?? ''
44
+ if (logs[key]) {
45
+ key = `${key}-${Math.random()}`
46
+ }
47
+
48
+ return {
49
+ ...logs,
50
+ [key]: line,
51
+ }
52
+ }, {} as Record<string, LogMessage>)
53
+
54
+ // ie doesn't like console.table
55
+ if (console.table) {
56
+ console.table(formatted)
57
+ } else {
58
+ console.log(formatted)
59
+ }
60
+ } else {
61
+ this.logs.forEach((logEntry) => {
62
+ const { level, message, extras } = logEntry
63
+
64
+ if (level === 'info' || level === 'debug') {
65
+ console.log(message, extras ?? '')
66
+ } else {
67
+ console[level](message, extras ?? '')
68
+ }
69
+ })
70
+ }
71
+
72
+ this._logs = []
73
+ }
74
+ }
@@ -0,0 +1,43 @@
1
+ import type { CoreAnalytics } from '../analytics'
2
+ import type { CoreContext } from '../context'
3
+
4
+ interface CorePluginConfig {
5
+ options: any
6
+ priority: 'critical' | 'non-critical' // whether AJS should expect this plugin to be loaded before starting event delivery
7
+ }
8
+
9
+ export type PluginType =
10
+ | 'before'
11
+ | 'after'
12
+ | 'destination'
13
+ | 'enrichment'
14
+ | 'utility'
15
+
16
+ // enrichment - modifies the event. Enrichment can happen in parallel, by reducing all changes in the final event. Failures in this stage could halt event delivery.
17
+ // destination - runs in parallel at the end of the lifecycle. Cannot modify the event, can fail and not halt execution.
18
+ // utility - do not affect lifecycle. Should be run and executed once. Their `track/identify` calls don't really do anything. example
19
+
20
+ export interface CorePlugin<
21
+ Ctx extends CoreContext = CoreContext,
22
+ Analytics extends CoreAnalytics = any
23
+ > {
24
+ name: string
25
+ alternativeNames?: string[]
26
+ version: string
27
+ type: PluginType
28
+ isLoaded: () => boolean
29
+ load: (
30
+ ctx: Ctx,
31
+ instance: Analytics,
32
+ config?: CorePluginConfig
33
+ ) => Promise<unknown>
34
+
35
+ unload?: (ctx: Ctx, instance: Analytics) => Promise<unknown> | unknown
36
+ ready?: () => Promise<unknown>
37
+ track?: (ctx: Ctx) => Promise<Ctx> | Ctx
38
+ identify?: (ctx: Ctx) => Promise<Ctx> | Ctx
39
+ page?: (ctx: Ctx) => Promise<Ctx> | Ctx
40
+ group?: (ctx: Ctx) => Promise<Ctx> | Ctx
41
+ alias?: (ctx: Ctx) => Promise<Ctx> | Ctx
42
+ screen?: (ctx: Ctx) => Promise<Ctx> | Ctx
43
+ }
@@ -0,0 +1,24 @@
1
+ type BackoffParams = {
2
+ /** The number of milliseconds before starting the first retry. Default is 500 */
3
+ minTimeout?: number
4
+
5
+ /** The maximum number of milliseconds between two retries. Default is Infinity */
6
+ maxTimeout?: number
7
+
8
+ /** The exponential factor to use. Default is 2. */
9
+ factor?: number
10
+
11
+ /** The current attempt */
12
+ attempt: number
13
+ }
14
+
15
+ export function backoff(params: BackoffParams): number {
16
+ const random = Math.random() + 1
17
+ const {
18
+ minTimeout = 500,
19
+ factor = 2,
20
+ attempt,
21
+ maxTimeout = Infinity,
22
+ } = params
23
+ return Math.min(random * minTimeout * Math.pow(factor, attempt), maxTimeout)
24
+ }
@@ -0,0 +1,103 @@
1
+ import { Emitter } from '../emitter'
2
+ import { backoff } from './backoff'
3
+
4
+ /**
5
+ * @internal
6
+ */
7
+ export const ON_REMOVE_FROM_FUTURE = 'onRemoveFromFuture'
8
+
9
+ interface QueueItem {
10
+ id: string
11
+ }
12
+
13
+ export class PriorityQueue<Item extends QueueItem = QueueItem> extends Emitter {
14
+ protected future: Item[] = []
15
+ protected queue: Item[]
16
+ protected seen: Record<string, number>
17
+
18
+ public maxAttempts: number
19
+
20
+ constructor(
21
+ maxAttempts: number,
22
+ queue: Item[],
23
+ seen?: Record<string, number>
24
+ ) {
25
+ super()
26
+ this.maxAttempts = maxAttempts
27
+ this.queue = queue
28
+ this.seen = seen ?? {}
29
+ }
30
+
31
+ push(...items: Item[]): boolean[] {
32
+ const accepted = items.map((operation) => {
33
+ const attempts = this.updateAttempts(operation)
34
+
35
+ if (attempts > this.maxAttempts || this.includes(operation)) {
36
+ return false
37
+ }
38
+
39
+ this.queue.push(operation)
40
+ return true
41
+ })
42
+
43
+ this.queue = this.queue.sort(
44
+ (a, b) => this.getAttempts(a) - this.getAttempts(b)
45
+ )
46
+ return accepted
47
+ }
48
+
49
+ pushWithBackoff(item: Item): boolean {
50
+ if (this.getAttempts(item) === 0) {
51
+ return this.push(item)[0]
52
+ }
53
+
54
+ const attempt = this.updateAttempts(item)
55
+
56
+ if (attempt > this.maxAttempts || this.includes(item)) {
57
+ return false
58
+ }
59
+
60
+ const timeout = backoff({ attempt: attempt - 1 })
61
+
62
+ setTimeout(() => {
63
+ this.queue.push(item)
64
+ // remove from future list
65
+ this.future = this.future.filter((f) => f.id !== item.id)
66
+ // Lets listeners know that a 'future' message is now available in the queue
67
+ this.emit(ON_REMOVE_FROM_FUTURE)
68
+ }, timeout)
69
+
70
+ this.future.push(item)
71
+ return true
72
+ }
73
+
74
+ public getAttempts(item: Item): number {
75
+ return this.seen[item.id] ?? 0
76
+ }
77
+
78
+ public updateAttempts(item: Item): number {
79
+ this.seen[item.id] = this.getAttempts(item) + 1
80
+ return this.getAttempts(item)
81
+ }
82
+
83
+ includes(item: Item): boolean {
84
+ return (
85
+ this.queue.includes(item) ||
86
+ this.future.includes(item) ||
87
+ Boolean(this.queue.find((i) => i.id === item.id)) ||
88
+ Boolean(this.future.find((i) => i.id === item.id))
89
+ )
90
+ }
91
+
92
+ pop(): Item | undefined {
93
+ return this.queue.shift()
94
+ }
95
+
96
+ public get length(): number {
97
+ return this.queue.length
98
+ }
99
+
100
+ public get todo(): number {
101
+ return this.queue.length + this.future.length
102
+ }
103
+ }