@vrplatform/log 2.0.0-alpha.8 → 2.0.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.
Files changed (48) hide show
  1. package/build/main/log/baselog.d.ts +0 -1
  2. package/build/main/log/baselog.js +1 -16
  3. package/build/main/log/baselog.js.map +1 -1
  4. package/build/main/log/common.d.ts +1 -10
  5. package/build/main/log/common.js +3 -13
  6. package/build/main/log/common.js.map +1 -1
  7. package/build/main/log/index.d.ts +2 -2
  8. package/build/main/log/index.js +7 -6
  9. package/build/main/log/index.js.map +1 -1
  10. package/build/main/log/type.d.ts +18 -0
  11. package/build/main/log/type.js +12 -0
  12. package/build/main/log/type.js.map +1 -1
  13. package/build/main/tracking/index.d.ts +33 -35
  14. package/build/main/tracking/index.js +140 -71
  15. package/build/main/tracking/index.js.map +1 -1
  16. package/build/main/tracking/intercom.d.ts +2 -1
  17. package/build/main/tracking/intercom.js.map +1 -1
  18. package/build/main/tracking/types.d.ts +16 -0
  19. package/build/main/tracking/types.js +3 -0
  20. package/build/main/tracking/types.js.map +1 -0
  21. package/build/module/log/baselog.d.ts +0 -1
  22. package/build/module/log/baselog.js +1 -2
  23. package/build/module/log/baselog.js.map +1 -1
  24. package/build/module/log/common.d.ts +1 -10
  25. package/build/module/log/common.js +1 -11
  26. package/build/module/log/common.js.map +1 -1
  27. package/build/module/log/index.d.ts +2 -2
  28. package/build/module/log/index.js +2 -1
  29. package/build/module/log/index.js.map +1 -1
  30. package/build/module/log/type.d.ts +18 -0
  31. package/build/module/log/type.js +11 -1
  32. package/build/module/log/type.js.map +1 -1
  33. package/build/module/tracking/index.d.ts +33 -35
  34. package/build/module/tracking/index.js +121 -68
  35. package/build/module/tracking/index.js.map +1 -1
  36. package/build/module/tracking/intercom.d.ts +2 -1
  37. package/build/module/tracking/intercom.js.map +1 -1
  38. package/build/module/tracking/types.d.ts +16 -0
  39. package/build/module/tracking/types.js +2 -0
  40. package/build/module/tracking/types.js.map +1 -0
  41. package/package.json +2 -1
  42. package/src/log/baselog.ts +2 -3
  43. package/src/log/common.ts +1 -14
  44. package/src/log/index.ts +6 -6
  45. package/src/log/type.ts +23 -0
  46. package/src/tracking/index.ts +173 -91
  47. package/src/tracking/intercom.ts +2 -1
  48. package/src/tracking/types.ts +97 -0
@@ -1,9 +1,8 @@
1
- import { getCorrelationId, requestToContext } from './common';
2
- import type { BaseLog, ChildLogOptions, Log } from './type';
3
- export * from './type';
4
1
  import { Axiom } from '@axiomhq/js';
5
2
  import { serializeError } from 'serialize-error';
6
3
  import { logger } from './color';
4
+ import { getCorrelationId, requestToContext } from './common';
5
+ import type { BaseLog, ChildLogOptions, Log } from './type';
7
6
 
8
7
  let lastMessageTimestamp: number | undefined = undefined;
9
8
 
package/src/log/common.ts CHANGED
@@ -1,17 +1,4 @@
1
- import type { RequestLike } from './type';
2
-
3
- // Headers
4
- export const CONNECTION_ID_HEADER = 'X-Connection-ID';
5
- export const WORKFLOW_ID_HEADER = 'X-Workflow-ID';
6
- export const TASK_QUEUE_HEADER = 'X-Task-Queue';
7
- export const CORRELATION_ID_HEADER = 'X-Correlation-ID';
8
- export const VERIFICATION_HEADER = 'X-Verification-Key';
9
-
10
- // Env
11
- export const AXIOM_AUTH_TOKEN_ENV = 'AXIOM_AUTH_TOKEN';
12
- export const AXIOM_ORG_ID_ENV = 'AXIOM_ORG_ID';
13
- export const AXIOM_DATASET_ENV = 'AXIOM_DATASET';
14
- export const LOG_ENV = 'LOG';
1
+ import { CORRELATION_ID_HEADER, type RequestLike } from './type';
15
2
 
16
3
  export const requestHeadersToCapture = ['user-agent'];
17
4
 
package/src/log/index.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { createBaseLog } from './baselog';
2
+ import { getCorrelationId, getEnvironment, requestToContext } from './common';
2
3
  import {
3
4
  AXIOM_AUTH_TOKEN_ENV,
4
5
  AXIOM_DATASET_ENV,
5
6
  AXIOM_ORG_ID_ENV,
6
7
  LOG_ENV,
8
+ type LogBindings,
9
+ type RequestLike,
7
10
  TASK_QUEUE_HEADER,
8
11
  WORKFLOW_ID_HEADER,
9
- getCorrelationId,
10
- getEnvironment,
11
- requestToContext,
12
- } from './common';
13
- import type { RequestLike, WorkerLog } from './type';
12
+ type WorkerLog,
13
+ } from './type';
14
14
 
15
15
  export * from './common';
16
16
  export * from './baselog';
@@ -37,7 +37,7 @@ export function useLog({
37
37
  correlationId?: string;
38
38
  version?: string;
39
39
  dataset?: string;
40
- env?: Record<string, any>;
40
+ env?: LogBindings;
41
41
  context?: Record<string, any>;
42
42
  executionContext?: {
43
43
  waitUntil(promise: Promise<any>): void;
package/src/log/type.ts CHANGED
@@ -1,3 +1,26 @@
1
+ // Headers
2
+ export const CONNECTION_ID_HEADER = 'X-Connection-ID';
3
+ export const WORKFLOW_ID_HEADER = 'X-Workflow-ID';
4
+ export const TASK_QUEUE_HEADER = 'X-Task-Queue';
5
+ export const CORRELATION_ID_HEADER = 'X-Correlation-ID';
6
+ export const VERIFICATION_HEADER = 'X-Verification-Key';
7
+
8
+ // Env
9
+ export const AXIOM_AUTH_TOKEN_ENV = 'AXIOM_AUTH_TOKEN';
10
+ export const AXIOM_ORG_ID_ENV = 'AXIOM_ORG_ID';
11
+ export const AXIOM_DATASET_ENV = 'AXIOM_DATASET';
12
+ export const LOG_ENV = 'LOG';
13
+
14
+ export type LogBindings = {
15
+ [LOG_ENV]?: string;
16
+ [AXIOM_AUTH_TOKEN_ENV]?: string;
17
+ [AXIOM_ORG_ID_ENV]?: string;
18
+ [AXIOM_DATASET_ENV]?: string;
19
+ NODE_ENV?: string;
20
+ IS_LOCAL_DEV?: string;
21
+ MACHINE_NAME?: string;
22
+ };
23
+
1
24
  export type LogFn = (
2
25
  message: any,
3
26
  additionalContext?: Record<string, any>
@@ -1,22 +1,53 @@
1
1
  import { Analytics } from '@june-so/analytics-node';
2
2
  import { PostHog } from 'posthog-node';
3
- import { useLog } from '../log';
3
+ import { type LogBindings, type WorkerLog, useLog } from '../log';
4
4
  import { useIntercom } from './intercom';
5
+ import type { TrackingEvent } from './types';
5
6
 
6
- const E2E_TEST_USERS = [
7
- '9e7dfc88-503c-4222-9905-9116169d2203', // lars+checkly@finalytic.co
8
- '113d73d8-ee21-46b7-a12a-a74f632401ca', // e2e-invite-member@finalytic.io
9
- '917b7c4e-cb03-491c-9e94-d33a5bdeca05', // e2e-invite-owner@finalytic.io
10
- 'ec8e5572-74d0-4ae6-af73-bca8db9a27e9', // e2e-sign-up@finalytic.io
11
- ];
12
- const E2E_TEST_TEAMS = [
13
- 'c4fd21b4-8447-43a2-bdcb-f06a85a935ad', // VRP Automated Testing
14
- '8f21060e-afe6-410a-b2f4-00a3caa20786', // test_company_xxxx
15
- ];
16
-
17
- const isTest = (userId: string, groupId?: string) =>
18
- E2E_TEST_USERS.includes(userId) ||
19
- (groupId && E2E_TEST_TEAMS.includes(groupId));
7
+ export * from './types';
8
+
9
+ const E2E_TEST_USERS = {
10
+ 'e2e-invite-member@finalytic.io': '113d73d8-ee21-46b7-a12a-a74f632401ca',
11
+ 'e2e-invite-owner@finalytic.io': '917b7c4e-cb03-491c-9e94-d33a5bdeca05',
12
+ 'e2e-sign-up@finalytic.io': 'ec8e5572-74d0-4ae6-af73-bca8db9a27e9',
13
+ 'lars+checkly@finalytic.co': '9e7dfc88-503c-4222-9905-9116169d2203',
14
+ };
15
+
16
+ const E2E_TEST_TEAMS = {
17
+ 'VRP Automated Testing': 'c4fd21b4-8447-43a2-bdcb-f06a85a935ad',
18
+ test_company_xxxx: '8f21060e-afe6-410a-b2f4-00a3caa20786',
19
+ };
20
+
21
+ export const isTest = (userId: string, groupId?: string, userEmail?: string) =>
22
+ Object.values(E2E_TEST_USERS).includes(userId) ||
23
+ (groupId && Object.values(E2E_TEST_TEAMS).includes(groupId)) ||
24
+ (userEmail && Object.keys(E2E_TEST_USERS).includes(userEmail));
25
+
26
+ const camelToSnakeCase = (str: string) =>
27
+ str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
28
+
29
+ // todo: move to utils
30
+ export const convertKeysToSnakeCase = (obj?: Record<string, any>) => {
31
+ const result: Record<string, any> = {};
32
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
33
+
34
+ for (const key in obj) {
35
+ if (hasOwnProperty.call(obj, key)) {
36
+ const snakeKey = camelToSnakeCase(key);
37
+ if (
38
+ typeof obj[key] === 'object' &&
39
+ !Array.isArray(obj[key]) &&
40
+ obj[key] !== null
41
+ ) {
42
+ result[snakeKey] = convertKeysToSnakeCase(obj[key]);
43
+ } else {
44
+ result[snakeKey] = obj[key];
45
+ }
46
+ }
47
+ }
48
+
49
+ return result;
50
+ };
20
51
 
21
52
  export type TrackingProps = {
22
53
  name: string;
@@ -25,10 +56,28 @@ export type TrackingProps = {
25
56
  INTERCOM_TOKEN?: string;
26
57
  JUNESO_TOKEN?: string;
27
58
  POSTHOG_TOKEN?: string;
28
- };
59
+ } & LogBindings;
60
+ debugging?: boolean;
29
61
  };
30
62
  export type Tracking = ReturnType<typeof useTracking>;
31
63
 
64
+ export type TrackProps = OptionalUser<{
65
+ groupId: string;
66
+ event: TrackingEvent;
67
+ properties: Record<string, string | number | boolean | null | undefined>;
68
+ timestamp?: Date;
69
+ }>;
70
+ export type IdentifyProps = {
71
+ userId: string;
72
+ traits: Record<string, string | number | boolean | null | undefined>;
73
+ disableGeoip?: boolean;
74
+ timestamp?: Date;
75
+ };
76
+ export type GroupProps = OptionalUser<{
77
+ groupId: string;
78
+ traits?: Record<string, string | number | boolean | null | undefined>;
79
+ timestamp?: Date;
80
+ }>;
32
81
  type OptionalUser<T> = T &
33
82
  (
34
83
  | { userId: string; anonymousId?: string }
@@ -41,12 +90,24 @@ type OptionalUser<T> = T &
41
90
  export const useTracking = (
42
91
  { dataset, env, name }: TrackingProps,
43
92
  isDev?: boolean
44
- ) => {
45
- const axiom = useLog({ name, dataset, env });
46
- const intercom = env.INTERCOM_TOKEN
47
- ? useIntercom(env.INTERCOM_TOKEN, axiom)
93
+ ): {
94
+ track: (props: TrackProps) => Promise<void>;
95
+ identify: (props: IdentifyProps) => Promise<void>;
96
+ group: (props: GroupProps) => Promise<void>;
97
+ shutdown: () => Promise<any>;
98
+ log: WorkerLog;
99
+ june?: Analytics;
100
+ _intercom?: ReturnType<typeof useIntercom>;
101
+ posthog?: PostHog;
102
+ } => {
103
+ const log = useLog({ name, dataset, env });
104
+
105
+ const _intercom = env.INTERCOM_TOKEN
106
+ ? useIntercom(env.INTERCOM_TOKEN, log)
48
107
  : undefined;
49
- const juneso = env.JUNESO_TOKEN ? new Analytics(env.JUNESO_TOKEN) : undefined;
108
+
109
+ const june = env.JUNESO_TOKEN ? new Analytics(env.JUNESO_TOKEN) : undefined;
110
+
50
111
  const posthog = env.POSTHOG_TOKEN
51
112
  ? new PostHog(env.POSTHOG_TOKEN, {
52
113
  host: 'https://app.posthog.com',
@@ -57,112 +118,133 @@ export const useTracking = (
57
118
  // General
58
119
  track: async ({
59
120
  userId,
121
+ anonymousId,
60
122
  groupId,
61
123
  event,
62
124
  properties,
63
- }: {
64
- userId: string;
65
- groupId: string;
66
- event: string;
67
- properties: Record<string, any>;
68
- }) => {
69
- if (isDev || isTest(userId, groupId)) return;
70
-
71
- posthog?.capture({
72
- distinctId: userId,
73
- event,
74
- groups: {
75
- tenant: groupId,
76
- },
77
- properties,
78
- });
79
- juneso?.track(
80
- {
81
- userId,
125
+ timestamp,
126
+ }: TrackProps) => {
127
+ if (isDev || isTest(userId || anonymousId || '', groupId)) return;
128
+
129
+ if (anonymousId) {
130
+ posthog?.capture({
131
+ distinctId: anonymousId,
82
132
  event,
83
- properties,
84
- context: { groupId },
85
- },
86
- (err) => {
87
- if (err) console.error(err);
88
- }
89
- );
133
+ groups: {
134
+ tenant: groupId,
135
+ },
136
+ timestamp,
137
+ properties: convertKeysToSnakeCase(properties),
138
+ });
139
+ june?.track(
140
+ {
141
+ anonymousId,
142
+ event,
143
+ properties,
144
+ timestamp,
145
+ context: { groupId },
146
+ },
147
+ (err) => {
148
+ if (err) console.error(err);
149
+ }
150
+ );
90
151
 
91
- try {
92
- await intercom?.trackEvent({
93
- user_id: userId,
94
- event_name: event,
95
- metadata: properties,
152
+ // no intercom for anonymous
153
+ } else if (userId) {
154
+ posthog?.capture({
155
+ distinctId: userId,
156
+ event,
157
+ groups: {
158
+ tenant: groupId,
159
+ },
160
+ timestamp,
161
+ properties: convertKeysToSnakeCase(properties),
96
162
  });
97
- } catch (error: any) {
98
- console.error(error);
163
+ june?.track(
164
+ {
165
+ userId,
166
+ event,
167
+ properties,
168
+ timestamp,
169
+ context: { groupId },
170
+ },
171
+ (err) => {
172
+ if (err) console.error(err);
173
+ }
174
+ );
175
+
176
+ try {
177
+ await _intercom?.trackEvent({
178
+ user_id: userId,
179
+ event_name: event,
180
+ metadata: properties,
181
+ });
182
+ } catch (error: any) {
183
+ console.error(error);
184
+ }
99
185
  }
100
186
  },
101
- identify: ({
187
+ identify: async ({
102
188
  traits,
103
189
  userId,
104
190
  disableGeoip,
105
- }: {
106
- userId: string;
107
- traits: Record<string, any>;
108
- disableGeoip?: boolean;
109
- }) => {
191
+ timestamp,
192
+ }: IdentifyProps) => {
110
193
  if (isDev || isTest(userId)) return;
111
194
 
112
195
  posthog?.identify({
113
196
  distinctId: userId,
114
- properties: traits,
197
+ properties: convertKeysToSnakeCase(traits),
115
198
  disableGeoip,
116
199
  });
117
- juneso?.identify(
200
+ june?.identify(
118
201
  {
119
202
  userId,
120
203
  traits,
204
+ timestamp,
121
205
  },
122
206
  (err) => {
123
207
  if (err) console.error(err);
124
208
  }
125
209
  );
126
210
  },
127
- group: ({
211
+ group: async ({
128
212
  traits,
129
213
  groupId,
130
214
  userId,
131
215
  anonymousId,
132
- }: OptionalUser<{
133
- groupId: string;
134
- traits?: Record<string, any>;
135
- }>) => {
216
+ timestamp,
217
+ }: GroupProps) => {
136
218
  if (isDev || isTest(userId || anonymousId || '', groupId)) return;
137
219
 
138
- posthog?.groupIdentify({
139
- groupKey: groupId,
140
- groupType: 'tenant',
141
- properties: traits,
142
- distinctId: userId,
143
- });
144
- if (anonymousId)
145
- juneso?.group({ anonymousId, groupId, traits }, (err) =>
146
- console.error(err)
147
- );
148
- else if (userId)
149
- juneso?.group({ userId, groupId, traits }, (err) => {
220
+ if (anonymousId) {
221
+ posthog?.groupIdentify({
222
+ groupKey: groupId,
223
+ groupType: 'tenant',
224
+ properties: convertKeysToSnakeCase(traits),
225
+ distinctId: anonymousId,
226
+ });
227
+ june?.group({ anonymousId, groupId, traits, timestamp }, (err) => {
150
228
  if (err) console.error(err);
151
229
  });
230
+ } else if (userId) {
231
+ posthog?.groupIdentify({
232
+ groupKey: groupId,
233
+ groupType: 'tenant',
234
+ properties: convertKeysToSnakeCase(traits),
235
+ distinctId: userId,
236
+ });
237
+ june?.group({ userId, groupId, traits, timestamp }, (err) => {
238
+ if (err) console.error(err);
239
+ });
240
+ }
152
241
  },
153
242
  shutdown: async () =>
154
- Promise.all([
155
- posthog?.shutdown(),
156
- juneso?.closeAndFlush(),
157
- axiom?.flush(),
158
- ]),
159
- // Posthog specific
160
- alias: posthog?.alias,
161
- isFeatureEnabled: posthog?.isFeatureEnabled,
162
- // export intercom and axiom
163
- intercom,
243
+ Promise.all([posthog?.shutdown(), june?.closeAndFlush(), log?.flush()]),
244
+ // export dependencies
245
+ _intercom,
164
246
  posthog,
165
- june: juneso,
166
- log: axiom,
247
+ june,
248
+ log,
167
249
  };
168
250
  };
@@ -113,6 +113,7 @@ export class IntercomAPI {
113
113
  email?: string;
114
114
  name?: string;
115
115
  custom_attributes: Record<string, any>;
116
+ [key: string]: any;
116
117
  };
117
118
  }) {
118
119
  return await this.fetch(`/contacts/${contactId}`, {
@@ -217,7 +218,7 @@ export class IntercomAPI {
217
218
  tenantId: string;
218
219
  data: {
219
220
  name: string;
220
- remote_created_at: string;
221
+ remote_created_at: number;
221
222
  custom_attributes: Record<string, any>;
222
223
  };
223
224
  }) {
@@ -0,0 +1,97 @@
1
+ type AuthEvent =
2
+ | 'account_signin_completed'
3
+ | 'account_signup_code_requested'
4
+ | 'account_signup_code_completed'
5
+ | 'account_signup_code_failed'
6
+ | 'account_signup_completed'
7
+ | 'account_password_reset_requested'
8
+ | 'account_password_reset_failed'
9
+ | 'account_password_reset_completed'
10
+ | 'account_invitation_accepted'
11
+ | 'account_signed_out';
12
+
13
+ type TeamEvent =
14
+ | 'team_added'
15
+ | 'team_info_updated'
16
+ | 'team_deleted'
17
+ | 'team_member_removed';
18
+
19
+ type ConnectionEvent =
20
+ | 'connection_created'
21
+ | 'connection_reconnected'
22
+ | 'connection_deleted'
23
+ | 'connection_requested';
24
+
25
+ type OwnershipEvent =
26
+ | 'ownership_created'
27
+ | 'ownership_updated'
28
+ | 'ownership_deleted';
29
+
30
+ type OwnerEvent =
31
+ | 'owner_created'
32
+ | 'owner_updated'
33
+ | 'owner_deleted'
34
+ | 'owner_tax_info_modal_opened'
35
+ | 'owner_tax_info_modal_submitted';
36
+
37
+ type SetupEvent =
38
+ | 'setup_classes_set'
39
+ | 'setup_accounting_version_completed'
40
+ | 'setup_accounting_config_completed'
41
+ | 'setup_owner_imported'
42
+ | 'setup_listing_imported';
43
+
44
+ type AutomationEvent =
45
+ | 'automation_created'
46
+ | 'automation_updated'
47
+ | 'automation_deleted';
48
+
49
+ type TaxStatementEvent =
50
+ | 'tax_statement_preview_opened'
51
+ | 'tax_statement_downloaded';
52
+
53
+ type GLOwnerStatementEvent =
54
+ | 'gl_owner_statement_preview_opened'
55
+ | 'gl_owner_statement_downloaded';
56
+
57
+ type HyperlineEvent =
58
+ | 'hyperline_invoice_ready'
59
+ | 'hyperline_invoice_settled'
60
+ | 'hyperline_trial_started'
61
+ | 'hyperline_trial_ended'
62
+ | 'hyperline_subscription_activated'
63
+ | 'hyperline_subscription_cancelled'
64
+ | 'hyperline_subscription_created'
65
+ | 'hyperline_subscription_errored'
66
+ | 'hyperline_subscription_paused'
67
+ | 'hyperline_subscription_voided'
68
+ | 'hyperline_subscription_charged'
69
+ | 'hyperline_customer_created'
70
+ | 'hyperline_customer_updated'
71
+ | 'hyperline_payment_method_created'
72
+ | 'hyperline_payment_method_errored'
73
+ | 'hyperline_payment_method_deleted';
74
+
75
+ type ListingEvent = 'listing_activated' | 'listing_deactivated';
76
+
77
+ type ReportEvent = 'listings_reported';
78
+
79
+ type UserEvent = 'update_refresh_accepted' | 'owner_statement_opened';
80
+
81
+ type TestEvent = 'test_event' | 'test_error';
82
+
83
+ export type TrackingEvent =
84
+ | AuthEvent
85
+ | TeamEvent
86
+ | ConnectionEvent
87
+ | OwnershipEvent
88
+ | OwnerEvent
89
+ | SetupEvent
90
+ | AutomationEvent
91
+ | TaxStatementEvent
92
+ | GLOwnerStatementEvent
93
+ | HyperlineEvent
94
+ | UserEvent
95
+ | ListingEvent
96
+ | ReportEvent
97
+ | TestEvent;