@@ -3,13 +3,19 @@ import https from 'node:https'
3
3
4
4
import ci from 'ci-info'
5
5
import Conf from 'conf'
6
- import chalk from 'chalk'
6
+ import {
7
+ bold ,
8
+ yellow as y ,
9
+ red as r ,
10
+ green as g
11
+ } from 'chalk'
7
12
import {
8
13
type Configuration ,
9
14
type Device ,
10
15
type PackageName ,
11
16
type Project ,
12
- type Telemetry ,
17
+ type TelemetryVersion1 ,
18
+ type TelemetryVersion2and3 ,
13
19
} from '../types/telemetry'
14
20
import { type DatabaseProvider } from '../types'
15
21
import { type InitialisedList } from './core/initialise-lists'
@@ -25,17 +31,6 @@ const packageNames: PackageName[] = [
25
31
'@opensaas/keystone-nextjs-auth' ,
26
32
]
27
33
28
- type TelemetryVersion1 =
29
- | undefined
30
- | false
31
- | {
32
- device : { lastSentDate ?: string , informedAt : string }
33
- projects : {
34
- default : { lastSentDate ?: string , informedAt : string }
35
- [ projectPath : string ] : { lastSentDate ?: string , informedAt : string }
36
- }
37
- }
38
-
39
34
function log ( message : unknown ) {
40
35
if ( process . env . KEYSTONE_TELEMETRY_DEBUG === '1' ) {
41
36
console . log ( `${ message } ` )
@@ -46,38 +41,46 @@ function getTelemetryConfig () {
46
41
const userConfig = new Conf < Configuration > ( {
47
42
projectName : 'keystonejs' ,
48
43
projectSuffix : '' ,
49
- projectVersion : '2 .0.0' ,
44
+ projectVersion : '3 .0.0' ,
50
45
migrations : {
51
- '^2.0.0' : ( store : Conf < Configuration > ) => {
52
- const existing = store . get ( 'telemetry' ) as unknown as TelemetryVersion1
53
- if ( ! existing ) return
46
+ '^2.0.0' : ( store ) => {
47
+ const existing = store . get ( 'telemetry' ) as TelemetryVersion1
48
+ if ( ! existing ) return // skip non-configured or known opt-outs
54
49
55
- const replacement : Telemetry = {
56
- // every informedAt was a copy of device.informedAt, it was copied everywhere
57
- informedAt : existing . device . informedAt ,
50
+ const replacement : TelemetryVersion2and3 = {
51
+ informedAt : null , // re-inform
58
52
device : {
59
53
lastSentDate : existing . device . lastSentDate ?? null ,
60
54
} ,
61
- projects : { } , // manually copying this below
55
+ projects : { } , // see below
62
56
}
63
57
64
58
// copy existing project lastSentDate's
65
59
for ( const [ projectPath , project ] of Object . entries ( existing . projects ) ) {
66
- if ( projectPath === 'default' ) continue // informedAt moved to root
60
+ if ( projectPath === 'default' ) continue // informedAt moved to device.lastSentDate
67
61
68
62
// dont copy garbage
69
63
if ( typeof project !== 'object' ) continue
70
64
if ( typeof project . lastSentDate !== 'string' ) continue
71
65
if ( new Date ( project . lastSentDate ) . toString ( ) === 'Invalid Date' ) continue
72
66
73
- // only lastSentDate is retained
67
+ // retain lastSentDate
74
68
replacement . projects [ projectPath ] = {
75
69
lastSentDate : project . lastSentDate ,
76
70
}
77
71
}
78
72
79
73
store . set ( 'telemetry' , replacement )
80
74
} ,
75
+ '^3.0.0' : ( store ) => {
76
+ const existing = store . get ( 'telemetry' ) as TelemetryVersion2and3
77
+ if ( ! existing ) return // skip non-configured or known opt-outs
78
+
79
+ store . set ( 'telemetry' , {
80
+ ...existing ,
81
+ informedAt : null , // re-inform
82
+ } satisfies TelemetryVersion2and3 )
83
+ } ,
81
84
} ,
82
85
} )
83
86
@@ -97,8 +100,8 @@ function getDefaultedTelemetryConfig () {
97
100
device : {
98
101
lastSentDate : null ,
99
102
} ,
100
- projects : { } as Telemetry [ 'projects' ] , // help Typescript infer the type
101
- } ,
103
+ projects : { } ,
104
+ } as TelemetryVersion2and3 , // help Typescript infer the type
102
105
userConfig,
103
106
}
104
107
}
@@ -147,84 +150,64 @@ function collectPackageVersions () {
147
150
}
148
151
149
152
function printAbout ( ) {
150
- console . log (
151
- `${ chalk . yellow ( 'Keystone collects anonymous data when you run' ) } ${ chalk . green (
152
- '"keystone dev"'
153
- ) } `
154
- )
153
+ console . log ( `${ y `Keystone collects anonymous data when you run` } ${ g `"keystone dev"` } ` )
155
154
console . log ( )
156
- console . log (
157
- `For more information, including how to opt-out see https://keystonejs.com/telemetry`
158
- )
155
+ console . log ( `For more information, including how to opt-out see https://keystonejs.com/telemetry` )
159
156
}
160
157
161
158
export function printTelemetryStatus ( ) {
162
159
const { telemetry } = getTelemetryConfig ( )
163
160
164
161
if ( telemetry === undefined ) {
165
- console . log ( `Keystone telemetry has been reset to ${ chalk . yellow ( 'uninitialized' ) } ` )
166
- console . log ( )
167
- console . log (
168
- `Telemetry will be sent the next time you run ${ chalk . green (
169
- '"keystone dev"'
170
- ) } , unless you opt-out`
171
- )
172
- } else if ( telemetry === false ) {
173
- console . log ( `Keystone telemetry is ${ chalk . red ( 'disabled' ) } ` )
162
+ console . log ( `Keystone telemetry has been reset to ${ y `uninitialized` } ` )
174
163
console . log ( )
175
- console . log ( `Telemetry will ${ chalk . red ( 'not' ) } be sent by this system user` )
176
- } else if ( typeof telemetry === 'object' ) {
177
- console . log ( `Keystone telemetry is ${ chalk . green ( 'enabled' ) } ` )
164
+ console . log ( `Telemetry will be sent the next time you run ${ g `"keystone dev"` } , unless you opt-out` )
165
+ return
166
+ }
167
+
168
+ if ( telemetry === false ) {
169
+ console . log ( `Keystone telemetry is ${ r `disabled` } ` )
178
170
console . log ( )
171
+ console . log ( `Telemetry will ${ r `not` } be sent by this system user` )
172
+ return
173
+ }
179
174
180
- console . log ( ` Device telemetry was last sent on ${ telemetry . device . lastSentDate } ` )
181
- for ( const [ projectPath , project ] of Object . entries ( telemetry . projects ) ) {
182
- console . log (
183
- ` Project telemetry for "${ chalk . yellow ( projectPath ) } " was last sent on ${
184
- project ?. lastSentDate
185
- } `
186
- )
187
- }
175
+ console . log ( `Keystone telemetry is ${ g `enabled` } ` )
176
+ console . log ( )
188
177
189
- console . log ( )
190
- console . log (
191
- `Telemetry will be sent the next time you run ${ chalk . green (
192
- '"keystone dev"'
193
- ) } , unless you opt-out`
194
- )
178
+ console . log ( ` Device telemetry was last sent on ${ telemetry . device . lastSentDate } ` )
179
+ for ( const [ projectPath , project ] of Object . entries ( telemetry . projects ) ) {
180
+ console . log ( ` Project telemetry for "${ y ( projectPath ) } " was last sent on ${ project ?. lastSentDate } ` )
195
181
}
182
+
183
+ console . log ( )
184
+ console . log ( `Telemetry will be sent the next time you run ${ g `"keystone dev"` } , unless you opt-out` )
196
185
}
197
186
198
187
function inform ( ) {
199
188
const { telemetry, userConfig } = getDefaultedTelemetryConfig ( )
200
189
201
- // no telemetry? somehow our earlier checks missed an opt out , do nothing
202
- if ( telemetry === false ) return
190
+ // no telemetry? somehow we missed something , do nothing
191
+ if ( ! telemetry ) return
203
192
204
193
console . log ( ) // gap to help visiblity
205
- console . log ( `${ chalk . bold ( 'Keystone Telemetry' ) } ` )
194
+ console . log ( `${ bold ( 'Keystone Telemetry' ) } ` )
206
195
printAbout ( )
207
- console . log (
208
- `You can use ${ chalk . green (
209
- '"keystone telemetry --help"'
210
- ) } to update your preferences at any time`
211
- )
196
+ console . log ( `You can use ${ g `"keystone telemetry --help"` } to update your preferences at any time` )
212
197
console . log ( )
213
- console . log (
214
- `No telemetry data has been sent yet, but telemetry will be sent the next time you run ${ chalk . green (
215
- '"keystone dev"'
216
- ) } , unless you opt-out`
217
- )
198
+ console . log ( `No telemetry data has been sent, but telemetry will be sent the next time you run ${ g `"keystone dev"` } , unless you opt-out` )
218
199
console . log ( ) // gap to help visiblity
219
200
220
201
// update the informedAt
221
202
telemetry . informedAt = new Date ( ) . toJSON ( )
222
203
userConfig . set ( 'telemetry' , telemetry )
223
204
}
224
205
206
+ async function sendEvent ( eventType : 'project' , eventData : Project ) : Promise < void >
207
+ async function sendEvent ( eventType : 'device' , eventData : Device ) : Promise < void >
225
208
async function sendEvent ( eventType : 'project' | 'device' , eventData : Project | Device ) {
226
209
const endpoint = process . env . KEYSTONE_TELEMETRY_ENDPOINT || defaultTelemetryEndpoint
227
- const req = https . request ( `${ endpoint } /v1 /event/${ eventType } ` , {
210
+ const req = https . request ( `${ endpoint } /2 /event/${ eventType } ` , {
228
211
method : 'POST' ,
229
212
headers : {
230
213
'Content-Type' : 'application/json' ,
@@ -242,8 +225,8 @@ async function sendProjectTelemetryEvent (
242
225
) {
243
226
const { telemetry, userConfig } = getDefaultedTelemetryConfig ( )
244
227
245
- // no telemetry? somehow our earlier checks missed an opt out , do nothing
246
- if ( telemetry === false ) return
228
+ // no telemetry? somehow we missed something , do nothing
229
+ if ( ! telemetry ) return
247
230
248
231
const project = telemetry . projects [ cwd ] ?? { lastSentDate : null }
249
232
const { lastSentDate } = project
@@ -268,8 +251,8 @@ async function sendProjectTelemetryEvent (
268
251
async function sendDeviceTelemetryEvent ( ) {
269
252
const { telemetry, userConfig } = getDefaultedTelemetryConfig ( )
270
253
271
- // no telemetry? somehow our earlier checks missed an opt out , do nothing
272
- if ( telemetry === false ) return
254
+ // no telemetry? somehow we missed something , do nothing
255
+ if ( ! telemetry ) return
273
256
274
257
const { lastSentDate } = telemetry . device
275
258
if ( lastSentDate && lastSentDate >= todaysDate ) {
@@ -305,7 +288,8 @@ export async function runTelemetry (
305
288
const { telemetry } = getDefaultedTelemetryConfig ( )
306
289
307
290
// don't run if the user has opted out
308
- if ( telemetry === false ) return
291
+ // or if somehow our defaults are problematic, do nothing
292
+ if ( ! telemetry ) return
309
293
310
294
// don't send telemetry before we inform the user, allowing opt-out
311
295
if ( ! telemetry . informedAt ) return inform ( )
0 commit comments