-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathuseTelemetryState.ts
More file actions
125 lines (91 loc) · 3.46 KB
/
useTelemetryState.ts
File metadata and controls
125 lines (91 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';
import { cryptoRandomObjectId } from '@apify/utilities';
import { TELEMETRY_FILE_PATH } from '../../consts.js';
import { info } from '../../outputs.js';
import type { AuthJSON } from '../../types.js';
import { getApifyAPIBaseUrl, getLocalUserInfo } from '../../utils.js';
type TelemetryState = TelemetryStateV0 | TelemetryStateV1;
type LatestTelemetryState = TelemetryStateV1;
interface TelemetryStateV0 {
distinctId: string;
version?: never;
}
interface TelemetryStateV1 {
version: 1;
enabled: boolean;
userId?: string | null;
anonymousId: string;
}
const telemetryWarningText = [
'Apify collects telemetry data about general usage of Apify CLI to help us improve the product.',
'This feature is enabled by default, and you can disable it by setting the "APIFY_CLI_DISABLE_TELEMETRY" environment variable to "1", or by running "apify telemetry disable".',
'You can find more information about our telemetry in https://docs.apify.com/cli/docs/telemetry.',
].join('\n');
function createAnonymousId() {
return `CLI:${cryptoRandomObjectId()}`;
}
export function isTelemetryDisabledInThisEnv() {
return getApifyAPIBaseUrl() !== 'https://api.apify.com';
}
async function migrateStateV0ToV1(state: TelemetryState) {
if (state.version && state.version >= 1) {
return false;
}
const casted = state as TelemetryStateV0;
const existingAuthState = await getLocalUserInfo().catch(() => ({}) as AuthJSON);
updateTelemetryState({ version: 1, enabled: true } as never, (stateToUpdate) => {
if (existingAuthState.id && casted.distinctId === existingAuthState.id) {
stateToUpdate.anonymousId = createAnonymousId();
stateToUpdate.userId = existingAuthState.id;
} else {
stateToUpdate.anonymousId = casted.distinctId;
}
});
return true;
}
export async function useTelemetryState(): Promise<LatestTelemetryState> {
const filePath = TELEMETRY_FILE_PATH();
const exists = existsSync(filePath);
if (!exists) {
const existingAuthState = await getLocalUserInfo().catch(() => ({}) as AuthJSON);
updateTelemetryState({
version: 1,
enabled: true,
anonymousId: createAnonymousId(),
userId: existingAuthState.id,
});
// First time we are tracking telemetry, so we want to notify user about it.
info({ message: telemetryWarningText });
return useTelemetryState();
}
const state = JSON.parse(readFileSync(filePath, 'utf-8')) as TelemetryState;
if (await migrateStateV0ToV1(state)) {
return useTelemetryState();
}
const casted = state as LatestTelemetryState;
return casted;
}
export type StateUpdater = (state: LatestTelemetryState) => void;
function updateTelemetryState(state: LatestTelemetryState, updater?: StateUpdater) {
// Update the state in memory
const stateClone = { ...state };
updater?.(stateClone);
const filePath = TELEMETRY_FILE_PATH();
const dirPath = dirname(filePath);
mkdirSync(dirPath, { recursive: true });
writeFileSync(TELEMETRY_FILE_PATH(), JSON.stringify(stateClone, null, '\t'));
}
export async function updateUserId(userId: string | null) {
if (isTelemetryDisabledInThisEnv()) return;
const state = await useTelemetryState();
updateTelemetryState(state, (stateToUpdate) => {
stateToUpdate.userId = userId;
});
}
export async function updateTelemetryEnabled(enabled: boolean) {
const state = await useTelemetryState();
updateTelemetryState(state, (stateToUpdate) => {
stateToUpdate.enabled = enabled;
});
}