@vrplatform/log 2.0.0-alpha.4 → 2.0.0-alpha.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/main/log/baselog.d.ts +0 -1
- package/build/main/log/baselog.js +1 -16
- package/build/main/log/baselog.js.map +1 -1
- package/build/main/log/common.d.ts +1 -10
- package/build/main/log/common.js +3 -13
- package/build/main/log/common.js.map +1 -1
- package/build/main/log/index.d.ts +2 -2
- package/build/main/log/index.js +7 -6
- package/build/main/log/index.js.map +1 -1
- package/build/main/log/type.d.ts +18 -0
- package/build/main/log/type.js +12 -0
- package/build/main/log/type.js.map +1 -1
- package/build/main/tracking/_intercom.d.ts +109 -0
- package/build/main/tracking/_intercom.js +139 -0
- package/build/main/tracking/_intercom.js.map +1 -0
- package/build/main/tracking/index.d.ts +102 -48
- package/build/main/tracking/index.js +183 -69
- package/build/main/tracking/index.js.map +1 -1
- package/build/main/tracking/intercom.d.ts +2 -1
- package/build/main/tracking/intercom.js.map +1 -1
- package/build/main/tracking/types.d.ts +87 -0
- package/build/main/tracking/types.js +3 -0
- package/build/main/tracking/types.js.map +1 -0
- package/build/main/utils/convertKeysToSnakeCase.d.ts +1 -0
- package/build/main/utils/convertKeysToSnakeCase.js +23 -0
- package/build/main/utils/convertKeysToSnakeCase.js.map +1 -0
- package/build/main/utils/convertValuesToString.d.ts +5 -0
- package/build/main/utils/convertValuesToString.js +11 -0
- package/build/main/utils/convertValuesToString.js.map +1 -0
- package/build/main/utils/index.d.ts +3 -0
- package/build/main/utils/index.js +20 -0
- package/build/main/utils/index.js.map +1 -0
- package/build/main/utils/isTest.d.ts +1 -0
- package/build/main/utils/isTest.js +18 -0
- package/build/main/utils/isTest.js.map +1 -0
- package/build/module/log/baselog.d.ts +0 -1
- package/build/module/log/baselog.js +1 -2
- package/build/module/log/baselog.js.map +1 -1
- package/build/module/log/common.d.ts +1 -10
- package/build/module/log/common.js +1 -11
- package/build/module/log/common.js.map +1 -1
- package/build/module/log/index.d.ts +2 -2
- package/build/module/log/index.js +2 -1
- package/build/module/log/index.js.map +1 -1
- package/build/module/log/type.d.ts +18 -0
- package/build/module/log/type.js +11 -1
- package/build/module/log/type.js.map +1 -1
- package/build/module/tracking/_intercom.d.ts +109 -0
- package/build/module/tracking/_intercom.js +136 -0
- package/build/module/tracking/_intercom.js.map +1 -0
- package/build/module/tracking/index.d.ts +102 -48
- package/build/module/tracking/index.js +167 -67
- package/build/module/tracking/index.js.map +1 -1
- package/build/module/tracking/intercom.d.ts +2 -1
- package/build/module/tracking/intercom.js.map +1 -1
- package/build/module/tracking/types.d.ts +87 -0
- package/build/module/tracking/types.js +2 -0
- package/build/module/tracking/types.js.map +1 -0
- package/build/module/utils/convertKeysToSnakeCase.d.ts +1 -0
- package/build/module/utils/convertKeysToSnakeCase.js +19 -0
- package/build/module/utils/convertKeysToSnakeCase.js.map +1 -0
- package/build/module/utils/convertValuesToString.d.ts +5 -0
- package/build/module/utils/convertValuesToString.js +8 -0
- package/build/module/utils/convertValuesToString.js.map +1 -0
- package/build/module/utils/index.d.ts +3 -0
- package/build/module/utils/index.js +4 -0
- package/build/module/utils/index.js.map +1 -0
- package/build/module/utils/isTest.d.ts +1 -0
- package/build/module/utils/isTest.js +14 -0
- package/build/module/utils/isTest.js.map +1 -0
- package/package.json +2 -1
- package/src/log/baselog.ts +2 -3
- package/src/log/common.ts +1 -14
- package/src/log/index.ts +6 -6
- package/src/log/type.ts +23 -0
- package/src/tracking/{intercom.ts → _intercom.ts} +2 -1
- package/src/tracking/index.ts +326 -106
- package/src/tracking/types.ts +181 -0
- package/src/utils/convertKeysToSnakeCase.ts +21 -0
- package/src/utils/convertValuesToString.ts +10 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/isTest.ts +16 -0
package/src/tracking/index.ts
CHANGED
|
@@ -1,56 +1,152 @@
|
|
|
1
|
+
declare module 'intercom-client' {
|
|
2
|
+
export namespace Intercom {
|
|
3
|
+
export interface CreateContactRequestWithExternalId {
|
|
4
|
+
/** A unique identifier for the contact which is given to Intercom */
|
|
5
|
+
external_id: string;
|
|
6
|
+
/** The contacts phone */
|
|
7
|
+
phone?: string;
|
|
8
|
+
/** The contacts name */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** An image URL containing the avatar of a contact */
|
|
11
|
+
avatar?: string;
|
|
12
|
+
/** The time specified for when a contact signed up */
|
|
13
|
+
signed_up_at?: number;
|
|
14
|
+
/** The time when the contact was last seen (either where the Intercom Messenger was installed or when specified manually) */
|
|
15
|
+
last_seen_at?: number;
|
|
16
|
+
/** The id of an admin that has been assigned account ownership of the contact */
|
|
17
|
+
owner_id?: number;
|
|
18
|
+
/** Whether the contact is unsubscribed from emails */
|
|
19
|
+
unsubscribed_from_emails?: boolean;
|
|
20
|
+
/** The custom attributes which are set for the contact */
|
|
21
|
+
custom_attributes?: ContactCustomAttributes;
|
|
22
|
+
}
|
|
23
|
+
interface UpdateContactRequest {
|
|
24
|
+
/** The role of the contact. */
|
|
25
|
+
role?: 'user' | 'lead';
|
|
26
|
+
/** A unique identifier for the contact which is given to Intercom */
|
|
27
|
+
external_id?: string;
|
|
28
|
+
/** The contacts email */
|
|
29
|
+
email?: string;
|
|
30
|
+
/** The contacts phone */
|
|
31
|
+
phone?: string;
|
|
32
|
+
/** The contacts name */
|
|
33
|
+
name?: string;
|
|
34
|
+
/** An image URL containing the avatar of a contact */
|
|
35
|
+
avatar?: string;
|
|
36
|
+
/** The time specified for when a contact signed up */
|
|
37
|
+
signed_up_at?: number;
|
|
38
|
+
/** The time when the contact was last seen (either where the Intercom Messenger was installed or when specified manually) */
|
|
39
|
+
last_seen_at?: number;
|
|
40
|
+
/** The id of an admin that has been assigned account ownership of the contact */
|
|
41
|
+
owner_id?: number;
|
|
42
|
+
/** Whether the contact is unsubscribed from emails */
|
|
43
|
+
unsubscribed_from_emails?: boolean;
|
|
44
|
+
/** The custom attributes which are set for the contact */
|
|
45
|
+
custom_attributes?: ContactCustomAttributes;
|
|
46
|
+
}
|
|
47
|
+
interface ContactCustomAttributes {
|
|
48
|
+
Onboarding_Support?: string; // The customer's preferred onboarding level
|
|
49
|
+
userType?: string; // User Type (user or owner)
|
|
50
|
+
// ARCHIVED
|
|
51
|
+
// article_id?: string; // undefined
|
|
52
|
+
// workflowInstanceId?: number; // undefined
|
|
53
|
+
// Active_Listings?: string; // The number of active listings a user has
|
|
54
|
+
// Accounting_Software?: string; // The client's accounting software
|
|
55
|
+
}
|
|
56
|
+
interface CreateOrUpdateCompanyRequest {
|
|
57
|
+
/** The name of the Company */
|
|
58
|
+
name?: string;
|
|
59
|
+
/** The company id you have defined for the company. Can't be updated */
|
|
60
|
+
company_id?: string;
|
|
61
|
+
/** The name of the plan you have associated with the company. */
|
|
62
|
+
plan?: string;
|
|
63
|
+
/** The number of employees in this company. */
|
|
64
|
+
size?: number;
|
|
65
|
+
/** The URL for this company's website. Please note that the value specified here is not validated. Accepts any string. */
|
|
66
|
+
website?: string;
|
|
67
|
+
/** The industry that this company operates in. */
|
|
68
|
+
industry?: string;
|
|
69
|
+
/** A hash of key/value pairs containing any other data about the company you want Intercom to store. */
|
|
70
|
+
custom_attributes?: CompanyCustomAttributes;
|
|
71
|
+
/** The time the company was created by you. */
|
|
72
|
+
remote_created_at?: number;
|
|
73
|
+
/** How much revenue the company generates for your business. Note that this will truncate floats. i.e. it only allow for whole integers, 155.98 will be truncated to 155. Note that this has an upper limit of 2\*\*31-1 or 2147483647.. */
|
|
74
|
+
monthly_spend?: number;
|
|
75
|
+
}
|
|
76
|
+
interface CompanyCustomAttributes {
|
|
77
|
+
teamId?: string; // undefined
|
|
78
|
+
team?: string; // undefined
|
|
79
|
+
type?: string; // undefined
|
|
80
|
+
status?: string; // undefined
|
|
81
|
+
pms?: string; // undefined
|
|
82
|
+
accountingSoftware?: string; // Accounting software used by the team.
|
|
83
|
+
creation_source?: string; // undefined
|
|
84
|
+
activeListings?: number; // Active Listings
|
|
85
|
+
paymentMethodType?: string; // Payment Method
|
|
86
|
+
partnerName?: string; // Partner Name
|
|
87
|
+
billingPortalUrl?: string; // Billing Portal URL
|
|
88
|
+
billingStatus?: string; // undefined
|
|
89
|
+
billingPartner?: string; // Name of billing partner
|
|
90
|
+
// ARCHIVED
|
|
91
|
+
// firstName?: string; // undefined
|
|
92
|
+
// lastName?: string; // undefined
|
|
93
|
+
// email?: string; // undefined
|
|
94
|
+
// apps?: string; // All active connections besides pms/accounting
|
|
95
|
+
// accountingPartner?: string; // Name of accounting partner
|
|
96
|
+
// 'SaaS User'?: boolean; // undefined
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
1
101
|
import { Analytics } from '@june-so/analytics-node';
|
|
102
|
+
import { Intercom, IntercomClient } from 'intercom-client';
|
|
103
|
+
import { fetcher } from 'intercom-client/core/fetcher/Fetcher';
|
|
2
104
|
import { PostHog } from 'posthog-node';
|
|
3
|
-
import { useLog } from '../log';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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));
|
|
20
|
-
|
|
21
|
-
export type TrackingProps = {
|
|
22
|
-
name: string;
|
|
23
|
-
dataset: string;
|
|
24
|
-
env: {
|
|
25
|
-
INTERCOM_TOKEN: string;
|
|
26
|
-
JUNESO_ANALYTICS_WRITE_KEY: string;
|
|
27
|
-
POSTHOG_API_KEY: string;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
export type Tracking = ReturnType<typeof useTracking>;
|
|
105
|
+
import { type WorkerLog, useLog } from '../log';
|
|
106
|
+
import { convertKeysToSnakeCase, isTest } from '../utils';
|
|
107
|
+
import { convertValuesToString } from '../utils/convertValuesToString';
|
|
108
|
+
import type {
|
|
109
|
+
GroupProps,
|
|
110
|
+
IdentifyProps,
|
|
111
|
+
TrackProps,
|
|
112
|
+
TrackingProps,
|
|
113
|
+
} from './types';
|
|
31
114
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
userId?: string;
|
|
37
|
-
anonymousId: string;
|
|
38
|
-
}
|
|
39
|
-
);
|
|
115
|
+
export * from './types';
|
|
116
|
+
export * from 'intercom-client';
|
|
117
|
+
|
|
118
|
+
export type Tracking = ReturnType<typeof useTracking>;
|
|
40
119
|
|
|
41
120
|
export const useTracking = (
|
|
42
121
|
{ dataset, env, name }: TrackingProps,
|
|
43
122
|
isDev?: boolean
|
|
44
|
-
)
|
|
45
|
-
|
|
123
|
+
): {
|
|
124
|
+
track: (props: TrackProps) => Promise<void>;
|
|
125
|
+
identify: (props: IdentifyProps) => Promise<void>;
|
|
126
|
+
group: (props: GroupProps) => Promise<void>;
|
|
127
|
+
shutdown: () => Promise<any>;
|
|
128
|
+
log: WorkerLog;
|
|
129
|
+
june?: Analytics;
|
|
130
|
+
intercom?: IntercomClient;
|
|
131
|
+
posthog?: PostHog;
|
|
132
|
+
} => {
|
|
133
|
+
const log = useLog({ name, dataset, env });
|
|
134
|
+
|
|
46
135
|
const intercom = env.INTERCOM_TOKEN
|
|
47
|
-
?
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
136
|
+
? new IntercomClient({
|
|
137
|
+
token: env.INTERCOM_TOKEN,
|
|
138
|
+
fetcher: (args) =>
|
|
139
|
+
fetcher({
|
|
140
|
+
...args,
|
|
141
|
+
headers: { ...args.headers, accept: 'application/json' },
|
|
142
|
+
}),
|
|
143
|
+
})
|
|
51
144
|
: undefined;
|
|
52
|
-
|
|
53
|
-
|
|
145
|
+
|
|
146
|
+
const june = env.JUNESO_TOKEN ? new Analytics(env.JUNESO_TOKEN) : undefined;
|
|
147
|
+
|
|
148
|
+
const posthog = env.POSTHOG_TOKEN
|
|
149
|
+
? new PostHog(env.POSTHOG_TOKEN, {
|
|
54
150
|
host: 'https://app.posthog.com',
|
|
55
151
|
})
|
|
56
152
|
: undefined;
|
|
@@ -59,94 +155,218 @@ export const useTracking = (
|
|
|
59
155
|
// General
|
|
60
156
|
track: async ({
|
|
61
157
|
userId,
|
|
158
|
+
anonymousId,
|
|
62
159
|
groupId,
|
|
63
160
|
event,
|
|
64
161
|
properties,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
groupId
|
|
68
|
-
event: string;
|
|
69
|
-
properties: Record<string, any>;
|
|
70
|
-
}) => {
|
|
71
|
-
if (isDev || isTest(userId, groupId)) return;
|
|
72
|
-
|
|
73
|
-
posthog?.capture({
|
|
74
|
-
distinctId: userId,
|
|
75
|
-
event,
|
|
76
|
-
groups: {
|
|
77
|
-
tenant: groupId,
|
|
78
|
-
},
|
|
79
|
-
properties,
|
|
80
|
-
});
|
|
81
|
-
juneso?.track({
|
|
82
|
-
userId,
|
|
83
|
-
event,
|
|
84
|
-
properties,
|
|
85
|
-
context: { groupId },
|
|
86
|
-
});
|
|
162
|
+
timestamp,
|
|
163
|
+
}: TrackProps) => {
|
|
164
|
+
if (isDev || isTest(userId || anonymousId || '', groupId)) return;
|
|
87
165
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
166
|
+
if (anonymousId) {
|
|
167
|
+
posthog?.capture({
|
|
168
|
+
distinctId: anonymousId,
|
|
169
|
+
event,
|
|
170
|
+
groups: {
|
|
171
|
+
tenant: groupId,
|
|
172
|
+
},
|
|
173
|
+
timestamp,
|
|
174
|
+
properties: convertKeysToSnakeCase(properties),
|
|
93
175
|
});
|
|
94
|
-
|
|
95
|
-
|
|
176
|
+
|
|
177
|
+
june?.track(
|
|
178
|
+
{
|
|
179
|
+
anonymousId,
|
|
180
|
+
event,
|
|
181
|
+
properties,
|
|
182
|
+
timestamp,
|
|
183
|
+
context: { groupId },
|
|
184
|
+
},
|
|
185
|
+
(err) => {
|
|
186
|
+
if (err) console.error(err);
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// no intercom for anonymous
|
|
191
|
+
} else if (userId) {
|
|
192
|
+
posthog?.capture({
|
|
193
|
+
distinctId: userId,
|
|
194
|
+
event,
|
|
195
|
+
groups: {
|
|
196
|
+
tenant: groupId,
|
|
197
|
+
},
|
|
198
|
+
timestamp,
|
|
199
|
+
properties: convertKeysToSnakeCase(properties),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
june?.track(
|
|
203
|
+
{
|
|
204
|
+
userId,
|
|
205
|
+
event,
|
|
206
|
+
properties,
|
|
207
|
+
timestamp,
|
|
208
|
+
context: { groupId },
|
|
209
|
+
},
|
|
210
|
+
(err) => {
|
|
211
|
+
if (err) console.error(err);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const intercomUserId = (
|
|
216
|
+
await intercom?.contacts.search({
|
|
217
|
+
query: {
|
|
218
|
+
field: 'external_id',
|
|
219
|
+
operator: Intercom.SingleFilterSearchRequestOperator.Equals,
|
|
220
|
+
value: userId,
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
)?.data.at(0)?.id;
|
|
224
|
+
if (intercomUserId)
|
|
225
|
+
await intercom?.events.create({
|
|
226
|
+
user_id: intercomUserId,
|
|
227
|
+
event_name: event,
|
|
228
|
+
metadata: convertValuesToString(properties),
|
|
229
|
+
created_at: timestamp ? timestamp.getTime() : Date.now(),
|
|
230
|
+
});
|
|
96
231
|
}
|
|
97
232
|
},
|
|
98
|
-
identify: ({
|
|
233
|
+
identify: async ({
|
|
99
234
|
traits,
|
|
100
235
|
userId,
|
|
101
236
|
disableGeoip,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
traits: Record<string, any>;
|
|
105
|
-
disableGeoip?: boolean;
|
|
106
|
-
}) => {
|
|
237
|
+
timestamp,
|
|
238
|
+
}: IdentifyProps) => {
|
|
107
239
|
if (isDev || isTest(userId)) return;
|
|
108
240
|
|
|
109
241
|
posthog?.identify({
|
|
110
242
|
distinctId: userId,
|
|
111
|
-
properties: traits,
|
|
243
|
+
properties: convertKeysToSnakeCase(traits),
|
|
112
244
|
disableGeoip,
|
|
113
245
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
246
|
+
|
|
247
|
+
june?.identify(
|
|
248
|
+
{
|
|
249
|
+
userId,
|
|
250
|
+
traits,
|
|
251
|
+
timestamp,
|
|
252
|
+
},
|
|
253
|
+
(err) => (err ? console.error(err) : {})
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// upsert intercom user
|
|
257
|
+
const data = {
|
|
258
|
+
external_id: userId,
|
|
259
|
+
email: traits?.email,
|
|
260
|
+
name:
|
|
261
|
+
traits?.name ||
|
|
262
|
+
(traits?.firstName
|
|
263
|
+
? `${traits.firstName} ${traits.lastName}`
|
|
264
|
+
: traits?.lastName),
|
|
265
|
+
avatar: traits?.avatar,
|
|
266
|
+
signed_up_at: traits?.createdAt
|
|
267
|
+
? new Date(traits.createdAt).getTime() / 1000
|
|
268
|
+
: undefined,
|
|
269
|
+
last_seen_at: new Date().getTime() / 1000,
|
|
270
|
+
custom_attributes: { userType: traits?.role },
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const intercomUser = (
|
|
274
|
+
await intercom?.contacts.search({
|
|
275
|
+
query: {
|
|
276
|
+
field: 'external_id',
|
|
277
|
+
operator: Intercom.SingleFilterSearchRequestOperator.Equals,
|
|
278
|
+
value: userId,
|
|
279
|
+
},
|
|
280
|
+
})
|
|
281
|
+
)?.data.at(0);
|
|
282
|
+
if (intercomUser?.id)
|
|
283
|
+
await intercom?.contacts.update(intercomUser?.id, data);
|
|
284
|
+
else await intercom?.contacts.create(data);
|
|
118
285
|
},
|
|
119
|
-
group: ({
|
|
286
|
+
group: async ({
|
|
120
287
|
traits,
|
|
121
288
|
groupId,
|
|
122
289
|
userId,
|
|
123
290
|
anonymousId,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
traits?: Record<string, any>;
|
|
127
|
-
}>) => {
|
|
291
|
+
timestamp,
|
|
292
|
+
}: GroupProps) => {
|
|
128
293
|
if (isDev || isTest(userId || anonymousId || '', groupId)) return;
|
|
129
294
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
295
|
+
const cid = traits?.billingCustomerId || traits?.hyperlineCustomerId;
|
|
296
|
+
const intercomCompany = await intercom?.companies.create({
|
|
297
|
+
name: traits?.name,
|
|
298
|
+
company_id: groupId,
|
|
299
|
+
// plan: string;
|
|
300
|
+
remote_created_at: traits?.createdAt
|
|
301
|
+
? new Date(traits.createdAt).getTime() / 1000
|
|
302
|
+
: undefined,
|
|
303
|
+
// monthly_spend: number;
|
|
304
|
+
custom_attributes: {
|
|
305
|
+
teamId: groupId,
|
|
306
|
+
team: traits?.name,
|
|
307
|
+
type: traits?.type,
|
|
308
|
+
status: traits?.status,
|
|
309
|
+
pms: traits?.pms,
|
|
310
|
+
accountingSoftware: traits?.accountingSoftware,
|
|
311
|
+
activeListings: traits?.activeListings,
|
|
312
|
+
// paymentMethodType: string; // Payment Method
|
|
313
|
+
partnerName: traits?.partner || traits?.accountingPartner,
|
|
314
|
+
billingPortalUrl: cid
|
|
315
|
+
? `https://billing.vrplatform.app/portal/${cid}`
|
|
316
|
+
: undefined,
|
|
317
|
+
billingStatus: traits?.billingSubscriptionStatus,
|
|
318
|
+
billingPartner:
|
|
319
|
+
traits?.billingPartner ||
|
|
320
|
+
traits?.partner ||
|
|
321
|
+
traits?.accountingPartner,
|
|
322
|
+
},
|
|
135
323
|
});
|
|
136
|
-
|
|
137
|
-
|
|
324
|
+
|
|
325
|
+
if (anonymousId) {
|
|
326
|
+
posthog?.groupIdentify({
|
|
327
|
+
groupKey: groupId,
|
|
328
|
+
groupType: 'tenant',
|
|
329
|
+
properties: convertKeysToSnakeCase(traits),
|
|
330
|
+
distinctId: anonymousId,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
june?.group({ anonymousId, groupId, traits, timestamp }, (err) =>
|
|
334
|
+
err ? console.error(err) : {}
|
|
335
|
+
);
|
|
336
|
+
} else if (userId) {
|
|
337
|
+
posthog?.groupIdentify({
|
|
338
|
+
groupKey: groupId,
|
|
339
|
+
groupType: 'tenant',
|
|
340
|
+
properties: convertKeysToSnakeCase(traits),
|
|
341
|
+
distinctId: userId,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
june?.group({ userId, groupId, traits, timestamp }, (err) =>
|
|
345
|
+
err ? console.error(err) : {}
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
// attach intercom user to intercom company
|
|
349
|
+
const intercomUser = (
|
|
350
|
+
await intercom?.contacts.search({
|
|
351
|
+
query: {
|
|
352
|
+
field: 'external_id',
|
|
353
|
+
operator: Intercom.SingleFilterSearchRequestOperator.Equals,
|
|
354
|
+
value: userId,
|
|
355
|
+
},
|
|
356
|
+
})
|
|
357
|
+
)?.data.at(0);
|
|
358
|
+
if (intercomUser?.id && intercomCompany?.id)
|
|
359
|
+
intercom?.companies.attachContact(intercomUser?.id, {
|
|
360
|
+
id: intercomCompany?.id,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
138
363
|
},
|
|
139
364
|
shutdown: async () =>
|
|
140
|
-
Promise.all([
|
|
141
|
-
|
|
142
|
-
juneso?.closeAndFlush(),
|
|
143
|
-
axiom.flush(),
|
|
144
|
-
]),
|
|
145
|
-
// Posthog specific
|
|
146
|
-
alias: posthog?.alias,
|
|
147
|
-
isFeatureEnabled: posthog?.isFeatureEnabled,
|
|
148
|
-
// export intercom and axiom
|
|
365
|
+
Promise.all([posthog?.shutdown(), june?.closeAndFlush(), log?.flush()]),
|
|
366
|
+
// export dependencies
|
|
149
367
|
intercom,
|
|
150
|
-
|
|
368
|
+
posthog,
|
|
369
|
+
june,
|
|
370
|
+
log,
|
|
151
371
|
};
|
|
152
372
|
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { LogBindings } from '../log';
|
|
2
|
+
|
|
3
|
+
type AuthEvent =
|
|
4
|
+
| 'account_signin_completed'
|
|
5
|
+
| 'account_signup_code_requested'
|
|
6
|
+
| 'account_signup_code_completed'
|
|
7
|
+
| 'account_signup_code_failed'
|
|
8
|
+
| 'account_signup_completed'
|
|
9
|
+
| 'account_password_reset_requested'
|
|
10
|
+
| 'account_password_reset_failed'
|
|
11
|
+
| 'account_password_reset_completed'
|
|
12
|
+
| 'account_invitation_accepted'
|
|
13
|
+
| 'account_signed_out';
|
|
14
|
+
|
|
15
|
+
type TeamEvent =
|
|
16
|
+
| 'team_added'
|
|
17
|
+
| 'team_info_updated'
|
|
18
|
+
| 'team_deleted'
|
|
19
|
+
| 'team_member_removed';
|
|
20
|
+
|
|
21
|
+
type ConnectionEvent =
|
|
22
|
+
| 'connection_created'
|
|
23
|
+
| 'connection_reconnected'
|
|
24
|
+
| 'connection_deleted'
|
|
25
|
+
| 'connection_requested';
|
|
26
|
+
|
|
27
|
+
type OwnershipEvent =
|
|
28
|
+
| 'ownership_created'
|
|
29
|
+
| 'ownership_updated'
|
|
30
|
+
| 'ownership_deleted';
|
|
31
|
+
|
|
32
|
+
type OwnerEvent =
|
|
33
|
+
| 'owner_created'
|
|
34
|
+
| 'owner_updated'
|
|
35
|
+
| 'owner_deleted'
|
|
36
|
+
| 'owner_tax_info_modal_opened'
|
|
37
|
+
| 'owner_tax_info_modal_submitted';
|
|
38
|
+
|
|
39
|
+
type SetupEvent =
|
|
40
|
+
| 'setup_classes_set'
|
|
41
|
+
| 'setup_accounting_version_completed'
|
|
42
|
+
| 'setup_accounting_config_completed'
|
|
43
|
+
| 'setup_owner_imported'
|
|
44
|
+
| 'setup_listing_imported';
|
|
45
|
+
|
|
46
|
+
type AutomationEvent =
|
|
47
|
+
| 'automation_created'
|
|
48
|
+
| 'automation_updated'
|
|
49
|
+
| 'automation_deleted';
|
|
50
|
+
|
|
51
|
+
type TaxStatementEvent =
|
|
52
|
+
| 'tax_statement_preview_opened'
|
|
53
|
+
| 'tax_statement_downloaded';
|
|
54
|
+
|
|
55
|
+
type GLOwnerStatementEvent =
|
|
56
|
+
| 'gl_owner_statement_preview_opened'
|
|
57
|
+
| 'gl_owner_statement_downloaded';
|
|
58
|
+
|
|
59
|
+
type HyperlineEvent =
|
|
60
|
+
| 'hyperline_invoice_ready'
|
|
61
|
+
| 'hyperline_invoice_settled'
|
|
62
|
+
| 'hyperline_trial_started'
|
|
63
|
+
| 'hyperline_trial_ended'
|
|
64
|
+
| 'hyperline_subscription_activated'
|
|
65
|
+
| 'hyperline_subscription_cancelled'
|
|
66
|
+
| 'hyperline_subscription_created'
|
|
67
|
+
| 'hyperline_subscription_errored'
|
|
68
|
+
| 'hyperline_subscription_paused'
|
|
69
|
+
| 'hyperline_subscription_voided'
|
|
70
|
+
| 'hyperline_subscription_charged'
|
|
71
|
+
| 'hyperline_customer_created'
|
|
72
|
+
| 'hyperline_customer_updated'
|
|
73
|
+
| 'hyperline_payment_method_created'
|
|
74
|
+
| 'hyperline_payment_method_errored'
|
|
75
|
+
| 'hyperline_payment_method_deleted';
|
|
76
|
+
|
|
77
|
+
type ListingEvent = 'listing_activated' | 'listing_deactivated';
|
|
78
|
+
|
|
79
|
+
type ReportEvent = 'listings_reported';
|
|
80
|
+
|
|
81
|
+
type UserEvent = 'update_refresh_accepted' | 'owner_statement_opened';
|
|
82
|
+
|
|
83
|
+
type TestEvent = 'test_event' | 'test_error';
|
|
84
|
+
|
|
85
|
+
export type TrackingEvent =
|
|
86
|
+
| AuthEvent
|
|
87
|
+
| TeamEvent
|
|
88
|
+
| ConnectionEvent
|
|
89
|
+
| OwnershipEvent
|
|
90
|
+
| OwnerEvent
|
|
91
|
+
| SetupEvent
|
|
92
|
+
| AutomationEvent
|
|
93
|
+
| TaxStatementEvent
|
|
94
|
+
| GLOwnerStatementEvent
|
|
95
|
+
| HyperlineEvent
|
|
96
|
+
| UserEvent
|
|
97
|
+
| ListingEvent
|
|
98
|
+
| ReportEvent
|
|
99
|
+
| TestEvent;
|
|
100
|
+
|
|
101
|
+
export type TrackingProps = {
|
|
102
|
+
name: string;
|
|
103
|
+
dataset: string;
|
|
104
|
+
env: {
|
|
105
|
+
INTERCOM_TOKEN?: string;
|
|
106
|
+
JUNESO_TOKEN?: string;
|
|
107
|
+
POSTHOG_TOKEN?: string;
|
|
108
|
+
} & LogBindings;
|
|
109
|
+
debugging?: boolean;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type TrackProps = OptionalUser<{
|
|
113
|
+
groupId: string;
|
|
114
|
+
event: TrackingEvent;
|
|
115
|
+
properties: Record<string, string | number | boolean | null | undefined>;
|
|
116
|
+
timestamp?: Date;
|
|
117
|
+
}>;
|
|
118
|
+
export type IdentifyProps = {
|
|
119
|
+
userId: string;
|
|
120
|
+
traits?: {
|
|
121
|
+
id?: string;
|
|
122
|
+
email?: string;
|
|
123
|
+
avatar?: string;
|
|
124
|
+
name?: string;
|
|
125
|
+
firstName?: string;
|
|
126
|
+
lastName?: string;
|
|
127
|
+
createdAt?: string;
|
|
128
|
+
country?: string;
|
|
129
|
+
isSuperAdmin?: boolean;
|
|
130
|
+
isVrpAdmin?: boolean;
|
|
131
|
+
isPartnerAdmin?: boolean;
|
|
132
|
+
isTeamAdmin?: boolean;
|
|
133
|
+
role?: UserRole;
|
|
134
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
135
|
+
};
|
|
136
|
+
disableGeoip?: boolean;
|
|
137
|
+
timestamp?: Date;
|
|
138
|
+
};
|
|
139
|
+
export type GroupProps = OptionalUser<{
|
|
140
|
+
groupId: string;
|
|
141
|
+
traits?: {
|
|
142
|
+
name?: string;
|
|
143
|
+
type?: TenantType;
|
|
144
|
+
avatar?: string;
|
|
145
|
+
createdAt?: string;
|
|
146
|
+
partner?: string;
|
|
147
|
+
partnerId?: string;
|
|
148
|
+
billingCustomerId?: string;
|
|
149
|
+
billingSubscriptionStatus?: string; // todo: update type as enum
|
|
150
|
+
status?: TenantStatus;
|
|
151
|
+
isOnboarding?: boolean;
|
|
152
|
+
accountingPartner?: string;
|
|
153
|
+
billingPartner?: string;
|
|
154
|
+
pms?: string;
|
|
155
|
+
apps?: string;
|
|
156
|
+
accountingSoftware?: string;
|
|
157
|
+
activeListings?: number;
|
|
158
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
159
|
+
};
|
|
160
|
+
timestamp?: Date;
|
|
161
|
+
}>;
|
|
162
|
+
|
|
163
|
+
export type UserRole =
|
|
164
|
+
| 'super-admin'
|
|
165
|
+
| 'vrp-admin'
|
|
166
|
+
| 'partner-admin'
|
|
167
|
+
| 'team-admin'
|
|
168
|
+
| 'admin'
|
|
169
|
+
| 'owner'
|
|
170
|
+
| 'user';
|
|
171
|
+
export type TenantType = 'admin' | 'partner' | 'propertyManager';
|
|
172
|
+
export type TenantStatus = 'active' | 'inactive';
|
|
173
|
+
|
|
174
|
+
type OptionalUser<T> = T &
|
|
175
|
+
(
|
|
176
|
+
| { userId: string; anonymousId?: string }
|
|
177
|
+
| {
|
|
178
|
+
userId?: string;
|
|
179
|
+
anonymousId: string;
|
|
180
|
+
}
|
|
181
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const convertKeysToSnakeCase = (obj?: Record<string, any>) => {
|
|
2
|
+
const result: Record<string, any> = {};
|
|
3
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
4
|
+
|
|
5
|
+
for (const key in obj) {
|
|
6
|
+
if (hasOwnProperty.call(obj, key)) {
|
|
7
|
+
const snakeKey = key.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
|
|
8
|
+
if (
|
|
9
|
+
typeof obj[key] === 'object' &&
|
|
10
|
+
!Array.isArray(obj[key]) &&
|
|
11
|
+
obj[key] !== null
|
|
12
|
+
) {
|
|
13
|
+
result[snakeKey] = convertKeysToSnakeCase(obj[key]);
|
|
14
|
+
} else {
|
|
15
|
+
result[snakeKey] = obj[key];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result;
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function convertValuesToString(obj: { [key: string]: any }): {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
} {
|
|
4
|
+
const result: { [key: string]: string } = {};
|
|
5
|
+
|
|
6
|
+
for (const key of Object.keys(obj))
|
|
7
|
+
if (obj[key] !== undefined) result[key] = obj[key].toString();
|
|
8
|
+
|
|
9
|
+
return result;
|
|
10
|
+
}
|