@sanity/sdk 2.11.1 → 2.12.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.
- package/dist/_chunks-dts/utils.d.ts +171 -19
- package/dist/_chunks-es/_internal.js +41 -26
- package/dist/_chunks-es/_internal.js.map +1 -1
- package/dist/_chunks-es/createGroqSearchFilter.js +15 -4
- package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -1
- package/dist/_chunks-es/telemetryManager.js +25 -19
- package/dist/_chunks-es/telemetryManager.js.map +1 -1
- package/dist/_chunks-es/version.js +1 -1
- package/dist/_exports/_internal.d.ts +27 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +355 -75
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/_exports/index.ts +23 -2
- package/src/config/sanityConfig.ts +12 -0
- package/src/document/actions.test.ts +112 -1
- package/src/document/actions.ts +148 -1
- package/src/document/applyDocumentActions.ts +4 -3
- package/src/document/documentStore.ts +6 -5
- package/src/document/events.test.ts +57 -2
- package/src/document/events.ts +43 -24
- package/src/document/processActions/edit.ts +9 -44
- package/src/document/processActions/processActions.ts +44 -3
- package/src/document/processActions/releaseArchive.ts +77 -0
- package/src/document/processActions/releaseCreate.ts +59 -0
- package/src/document/processActions/releaseDelete.ts +65 -0
- package/src/document/processActions/releaseEdit.ts +36 -0
- package/src/document/processActions/releasePublish.ts +45 -0
- package/src/document/processActions/releaseSchedule.ts +87 -0
- package/src/document/processActions/releaseUtil.ts +31 -0
- package/src/document/processActions/shared.ts +94 -2
- package/src/document/processActions.test.ts +423 -1
- package/src/document/reducers.ts +40 -5
- package/src/releases/getPerspectiveState.test.ts +1 -1
- package/src/releases/releasesStore.test.ts +50 -1
- package/src/releases/releasesStore.ts +41 -18
- package/src/releases/utils/sortReleases.test.ts +2 -2
- package/src/releases/utils/sortReleases.ts +1 -1
- package/src/telemetry/environment.test.ts +119 -0
- package/src/telemetry/environment.ts +92 -0
- package/src/telemetry/{__telemetry__/sdk.telemetry.ts → events.ts} +9 -9
- package/src/telemetry/initTelemetry.test.ts +240 -16
- package/src/telemetry/initTelemetry.ts +39 -16
- package/src/telemetry/telemetryManager.test.ts +129 -65
- package/src/telemetry/telemetryManager.ts +41 -29
- package/src/telemetry/devMode.test.ts +0 -60
- package/src/telemetry/devMode.ts +0 -41
|
@@ -38,6 +38,13 @@ describe('createTelemetryManager', () => {
|
|
|
38
38
|
|
|
39
39
|
const getClient = () => mockClient as never
|
|
40
40
|
|
|
41
|
+
const baseOptions = {
|
|
42
|
+
sessionId: 'test-session-id',
|
|
43
|
+
getClient,
|
|
44
|
+
projectId: 'abc123',
|
|
45
|
+
environment: 'development' as const,
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
beforeEach(() => {
|
|
42
49
|
vi.clearAllMocks()
|
|
43
50
|
})
|
|
@@ -47,11 +54,7 @@ describe('createTelemetryManager', () => {
|
|
|
47
54
|
})
|
|
48
55
|
|
|
49
56
|
it('creates a batched store with the given session ID', () => {
|
|
50
|
-
createTelemetryManager(
|
|
51
|
-
sessionId: 'test-session-id',
|
|
52
|
-
getClient,
|
|
53
|
-
projectId: 'abc123',
|
|
54
|
-
})
|
|
57
|
+
createTelemetryManager(baseOptions)
|
|
55
58
|
|
|
56
59
|
expect(createBatchedStore).toHaveBeenCalledWith(
|
|
57
60
|
'test-session-id',
|
|
@@ -62,11 +65,7 @@ describe('createTelemetryManager', () => {
|
|
|
62
65
|
})
|
|
63
66
|
|
|
64
67
|
it('logs session started with SDK version and provided data', () => {
|
|
65
|
-
const manager = createTelemetryManager(
|
|
66
|
-
sessionId: 'test-session-id',
|
|
67
|
-
getClient,
|
|
68
|
-
projectId: 'abc123',
|
|
69
|
-
})
|
|
68
|
+
const manager = createTelemetryManager(baseOptions)
|
|
70
69
|
|
|
71
70
|
const storeInstance = vi.mocked(createBatchedStore).mock.results[0].value
|
|
72
71
|
const logger = storeInstance.logger
|
|
@@ -78,7 +77,7 @@ describe('createTelemetryManager', () => {
|
|
|
78
77
|
})
|
|
79
78
|
|
|
80
79
|
expect(logger.log).toHaveBeenCalledWith(
|
|
81
|
-
expect.objectContaining({name: 'SDK
|
|
80
|
+
expect.objectContaining({name: 'SDK Session Started'}),
|
|
82
81
|
expect.objectContaining({
|
|
83
82
|
version: '2.8.0-test',
|
|
84
83
|
projectId: 'abc123',
|
|
@@ -89,11 +88,7 @@ describe('createTelemetryManager', () => {
|
|
|
89
88
|
})
|
|
90
89
|
|
|
91
90
|
it('deduplicates hook first-used events by name', () => {
|
|
92
|
-
const manager = createTelemetryManager(
|
|
93
|
-
sessionId: 'test-session-id',
|
|
94
|
-
getClient,
|
|
95
|
-
projectId: 'abc123',
|
|
96
|
-
})
|
|
91
|
+
const manager = createTelemetryManager(baseOptions)
|
|
97
92
|
|
|
98
93
|
const storeInstance = vi.mocked(createBatchedStore).mock.results[0].value
|
|
99
94
|
const logger = storeInstance.logger
|
|
@@ -111,11 +106,7 @@ describe('createTelemetryManager', () => {
|
|
|
111
106
|
})
|
|
112
107
|
|
|
113
108
|
it('tracks hooksUsed set', () => {
|
|
114
|
-
const manager = createTelemetryManager(
|
|
115
|
-
sessionId: 'test-session-id',
|
|
116
|
-
getClient,
|
|
117
|
-
projectId: 'abc123',
|
|
118
|
-
})
|
|
109
|
+
const manager = createTelemetryManager(baseOptions)
|
|
119
110
|
|
|
120
111
|
manager.logHookFirstUsed('useQuery')
|
|
121
112
|
manager.logHookFirstUsed('useDocument')
|
|
@@ -123,19 +114,15 @@ describe('createTelemetryManager', () => {
|
|
|
123
114
|
expect(manager.hooksUsed).toEqual(new Set(['useQuery', 'useDocument']))
|
|
124
115
|
})
|
|
125
116
|
|
|
126
|
-
it('logs
|
|
127
|
-
const manager = createTelemetryManager(
|
|
128
|
-
sessionId: 'test-session-id',
|
|
129
|
-
getClient,
|
|
130
|
-
projectId: 'abc123',
|
|
131
|
-
})
|
|
117
|
+
it('logs error events', () => {
|
|
118
|
+
const manager = createTelemetryManager(baseOptions)
|
|
132
119
|
|
|
133
120
|
const storeInstance = vi.mocked(createBatchedStore).mock.results[0].value
|
|
134
121
|
const logger = storeInstance.logger
|
|
135
122
|
|
|
136
|
-
manager.
|
|
123
|
+
manager.logError('TypeError', 'documentStore')
|
|
137
124
|
|
|
138
|
-
expect(logger.log).toHaveBeenCalledWith(expect.objectContaining({name: 'SDK
|
|
125
|
+
expect(logger.log).toHaveBeenCalledWith(expect.objectContaining({name: 'SDK Error'}), {
|
|
139
126
|
errorType: 'TypeError',
|
|
140
127
|
hookName: 'documentStore',
|
|
141
128
|
})
|
|
@@ -144,11 +131,7 @@ describe('createTelemetryManager', () => {
|
|
|
144
131
|
it('logs session ended with duration and hooksUsed on endSession', () => {
|
|
145
132
|
vi.useFakeTimers()
|
|
146
133
|
|
|
147
|
-
const manager = createTelemetryManager(
|
|
148
|
-
sessionId: 'test-session-id',
|
|
149
|
-
getClient,
|
|
150
|
-
projectId: 'abc123',
|
|
151
|
-
})
|
|
134
|
+
const manager = createTelemetryManager(baseOptions)
|
|
152
135
|
|
|
153
136
|
const storeInstance = vi.mocked(createBatchedStore).mock.results[0].value
|
|
154
137
|
const logger = storeInstance.logger
|
|
@@ -160,7 +143,7 @@ describe('createTelemetryManager', () => {
|
|
|
160
143
|
manager.endSession()
|
|
161
144
|
|
|
162
145
|
expect(logger.log).toHaveBeenCalledWith(
|
|
163
|
-
expect.objectContaining({name: 'SDK
|
|
146
|
+
expect.objectContaining({name: 'SDK Session Ended'}),
|
|
164
147
|
expect.objectContaining({
|
|
165
148
|
durationSeconds: 5,
|
|
166
149
|
hooksUsed: ['useQuery'],
|
|
@@ -170,13 +153,114 @@ describe('createTelemetryManager', () => {
|
|
|
170
153
|
vi.useRealTimers()
|
|
171
154
|
})
|
|
172
155
|
|
|
156
|
+
describe('environment context', () => {
|
|
157
|
+
type EnrichedContext = {
|
|
158
|
+
environment?: string
|
|
159
|
+
version?: string
|
|
160
|
+
origin?: string
|
|
161
|
+
traceCorrelationId?: string
|
|
162
|
+
}
|
|
163
|
+
type EnrichedEvent = {
|
|
164
|
+
type?: string
|
|
165
|
+
name?: string
|
|
166
|
+
version?: number
|
|
167
|
+
traceId?: string
|
|
168
|
+
sessionId?: string
|
|
169
|
+
createdAt?: string
|
|
170
|
+
data?: unknown
|
|
171
|
+
context: EnrichedContext
|
|
172
|
+
}
|
|
173
|
+
const getRequestBody = () => {
|
|
174
|
+
const [args] = mockClient.request.mock.calls as unknown as Array<
|
|
175
|
+
[{body: {batch: EnrichedEvent[]}}]
|
|
176
|
+
>
|
|
177
|
+
return args[0].body
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
it('records "development" in the enriched batch context and preserves the event payload', async () => {
|
|
181
|
+
createTelemetryManager({...baseOptions, environment: 'development'})
|
|
182
|
+
|
|
183
|
+
const storeOptions = vi.mocked(createBatchedStore).mock.calls[0][1]
|
|
184
|
+
await storeOptions.sendEvents([
|
|
185
|
+
{
|
|
186
|
+
type: 'log',
|
|
187
|
+
version: 1,
|
|
188
|
+
name: 'SDK Session Started',
|
|
189
|
+
sessionId: 'test-session-id',
|
|
190
|
+
createdAt: '2026-01-01T00:00:00Z',
|
|
191
|
+
data: {projectId: 'p1'},
|
|
192
|
+
} as never,
|
|
193
|
+
])
|
|
194
|
+
|
|
195
|
+
const [event] = getRequestBody().batch
|
|
196
|
+
expect(event.context.environment).toBe('development')
|
|
197
|
+
expect(event.type).toBe('log')
|
|
198
|
+
expect(event.name).toBe('SDK Session Started')
|
|
199
|
+
expect(event.version).toBe(1)
|
|
200
|
+
expect(event.sessionId).toBe('test-session-id')
|
|
201
|
+
expect(event.data).toEqual({projectId: 'p1'})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('records "production" in the enriched batch context', async () => {
|
|
205
|
+
createTelemetryManager({...baseOptions, environment: 'production'})
|
|
206
|
+
|
|
207
|
+
const storeOptions = vi.mocked(createBatchedStore).mock.calls[0][1]
|
|
208
|
+
await storeOptions.sendEvents([
|
|
209
|
+
{
|
|
210
|
+
type: 'log',
|
|
211
|
+
version: 1,
|
|
212
|
+
name: 'SDK Session Started',
|
|
213
|
+
sessionId: 'test-session-id',
|
|
214
|
+
createdAt: '2026-01-01T00:00:00Z',
|
|
215
|
+
data: {},
|
|
216
|
+
} as never,
|
|
217
|
+
])
|
|
218
|
+
|
|
219
|
+
expect(getRequestBody().batch[0].context.environment).toBe('production')
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('preserves pre-existing context fields from trace events and lets SDK fields take precedence on conflict', async () => {
|
|
223
|
+
// Trace events from `@sanity/telemetry` arrive with a top-level
|
|
224
|
+
// `context` (see `TelemetryTraceStartEvent`, etc.). Replacing rather
|
|
225
|
+
// than merging would silently drop those fields. The SDK-managed
|
|
226
|
+
// fields (`version`, `environment`, `origin`) should also win on key
|
|
227
|
+
// collision so they remain authoritative. The rest of the trace
|
|
228
|
+
// event (`type`, `name`, `traceId`, `sessionId`, `createdAt`) must
|
|
229
|
+
// survive — downstream consumers (Rudderstack via telemetry-sink)
|
|
230
|
+
// read those fields directly off each batch entry.
|
|
231
|
+
createTelemetryManager({...baseOptions, environment: 'production'})
|
|
232
|
+
|
|
233
|
+
const storeOptions = vi.mocked(createBatchedStore).mock.calls[0][1]
|
|
234
|
+
await storeOptions.sendEvents([
|
|
235
|
+
{
|
|
236
|
+
type: 'trace.start',
|
|
237
|
+
name: 'some.trace',
|
|
238
|
+
version: 1,
|
|
239
|
+
traceId: 't1',
|
|
240
|
+
sessionId: 'test-session-id',
|
|
241
|
+
createdAt: '2026-01-01T00:00:00Z',
|
|
242
|
+
context: {
|
|
243
|
+
traceCorrelationId: 'abc-123',
|
|
244
|
+
environment: 'should-be-overwritten',
|
|
245
|
+
},
|
|
246
|
+
} as never,
|
|
247
|
+
])
|
|
248
|
+
|
|
249
|
+
const [event] = getRequestBody().batch
|
|
250
|
+
expect(event.context.traceCorrelationId).toBe('abc-123')
|
|
251
|
+
expect(event.context.environment).toBe('production')
|
|
252
|
+
expect(event.context.version).toBe('2.8.0-test')
|
|
253
|
+
expect(event.type).toBe('trace.start')
|
|
254
|
+
expect(event.name).toBe('some.trace')
|
|
255
|
+
expect(event.traceId).toBe('t1')
|
|
256
|
+
expect(event.sessionId).toBe('test-session-id')
|
|
257
|
+
expect(event.createdAt).toBe('2026-01-01T00:00:00Z')
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
|
|
173
261
|
describe('endSession teardown', () => {
|
|
174
262
|
it('always uses flush + end (no sendBeacon due to auth header limitation)', () => {
|
|
175
|
-
const manager = createTelemetryManager(
|
|
176
|
-
sessionId: 'test-session-id',
|
|
177
|
-
getClient,
|
|
178
|
-
projectId: 'abc123',
|
|
179
|
-
})
|
|
263
|
+
const manager = createTelemetryManager(baseOptions)
|
|
180
264
|
|
|
181
265
|
const storeInstance = vi.mocked(createBatchedStore).mock.results[0].value
|
|
182
266
|
|
|
@@ -191,11 +275,7 @@ describe('createTelemetryManager', () => {
|
|
|
191
275
|
it('checkConsent returns true when user has opted in', async () => {
|
|
192
276
|
mockClient.request.mockResolvedValue({status: 'granted'})
|
|
193
277
|
|
|
194
|
-
const manager = createTelemetryManager(
|
|
195
|
-
sessionId: 'test-session-id',
|
|
196
|
-
getClient,
|
|
197
|
-
projectId: 'abc123',
|
|
198
|
-
})
|
|
278
|
+
const manager = createTelemetryManager(baseOptions)
|
|
199
279
|
|
|
200
280
|
const result = await manager.checkConsent()
|
|
201
281
|
expect(result).toBe(true)
|
|
@@ -207,11 +287,7 @@ describe('createTelemetryManager', () => {
|
|
|
207
287
|
it('checkConsent returns false when user has denied telemetry', async () => {
|
|
208
288
|
mockClient.request.mockResolvedValue({status: 'denied'})
|
|
209
289
|
|
|
210
|
-
const manager = createTelemetryManager(
|
|
211
|
-
sessionId: 'test-session-id',
|
|
212
|
-
getClient,
|
|
213
|
-
projectId: 'abc123',
|
|
214
|
-
})
|
|
290
|
+
const manager = createTelemetryManager(baseOptions)
|
|
215
291
|
|
|
216
292
|
expect(await manager.checkConsent()).toBe(false)
|
|
217
293
|
})
|
|
@@ -219,11 +295,7 @@ describe('createTelemetryManager', () => {
|
|
|
219
295
|
it('checkConsent returns false when consent is unset', async () => {
|
|
220
296
|
mockClient.request.mockResolvedValue({status: 'unset'})
|
|
221
297
|
|
|
222
|
-
const manager = createTelemetryManager(
|
|
223
|
-
sessionId: 'test-session-id',
|
|
224
|
-
getClient,
|
|
225
|
-
projectId: 'abc123',
|
|
226
|
-
})
|
|
298
|
+
const manager = createTelemetryManager(baseOptions)
|
|
227
299
|
|
|
228
300
|
expect(await manager.checkConsent()).toBe(false)
|
|
229
301
|
})
|
|
@@ -231,11 +303,7 @@ describe('createTelemetryManager', () => {
|
|
|
231
303
|
it('checkConsent returns false on network failure', async () => {
|
|
232
304
|
mockClient.request.mockRejectedValue(new Error('Network error'))
|
|
233
305
|
|
|
234
|
-
const manager = createTelemetryManager(
|
|
235
|
-
sessionId: 'test-session-id',
|
|
236
|
-
getClient,
|
|
237
|
-
projectId: 'abc123',
|
|
238
|
-
})
|
|
306
|
+
const manager = createTelemetryManager(baseOptions)
|
|
239
307
|
|
|
240
308
|
expect(await manager.checkConsent()).toBe(false)
|
|
241
309
|
})
|
|
@@ -243,11 +311,7 @@ describe('createTelemetryManager', () => {
|
|
|
243
311
|
it('caches consent after the first call', async () => {
|
|
244
312
|
mockClient.request.mockResolvedValue({status: 'granted'})
|
|
245
313
|
|
|
246
|
-
createTelemetryManager(
|
|
247
|
-
sessionId: 'test-session-id',
|
|
248
|
-
getClient,
|
|
249
|
-
projectId: 'abc123',
|
|
250
|
-
})
|
|
314
|
+
createTelemetryManager(baseOptions)
|
|
251
315
|
|
|
252
316
|
const storeOptions = vi.mocked(createBatchedStore).mock.calls[0][1]
|
|
253
317
|
const resolveConsent = storeOptions.resolveConsent
|
|
@@ -10,12 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
import {createLogger} from '../utils/logger'
|
|
12
12
|
import {CORE_SDK_VERSION} from '../version'
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
SDKDevSessionEnded,
|
|
16
|
-
SDKDevSessionStarted,
|
|
17
|
-
SDKHookMounted,
|
|
18
|
-
} from './__telemetry__/sdk.telemetry'
|
|
13
|
+
import {type TelemetryEnvironment} from './environment'
|
|
14
|
+
import {SDKError, SDKHookMounted, SDKSessionEnded, SDKSessionStarted} from './events'
|
|
19
15
|
|
|
20
16
|
const FLUSH_INTERVAL_MS = 30_000
|
|
21
17
|
const CONSENT_TAG = 'telemetry-consent.sdk'
|
|
@@ -24,10 +20,13 @@ const BATCH_TAG = 'telemetry.batch'
|
|
|
24
20
|
const log = createLogger('telemetry')
|
|
25
21
|
|
|
26
22
|
/**
|
|
27
|
-
* Manages
|
|
23
|
+
* Manages telemetry for a single SDK instance.
|
|
28
24
|
*
|
|
29
25
|
* Wraps `@sanity/telemetry`'s batched store with SDK-specific concerns:
|
|
30
26
|
* consent caching, session lifecycle events, and hook usage tracking.
|
|
27
|
+
* The `environment` is captured at construction time and recorded in
|
|
28
|
+
* the event context so downstream pipelines can distinguish dev and
|
|
29
|
+
* production sessions.
|
|
31
30
|
*
|
|
32
31
|
* @internal
|
|
33
32
|
*/
|
|
@@ -40,16 +39,16 @@ export interface TelemetryManager {
|
|
|
40
39
|
*/
|
|
41
40
|
checkConsent(): Promise<boolean>
|
|
42
41
|
|
|
43
|
-
/** Log a "SDK
|
|
42
|
+
/** Log a "SDK Session Started" event */
|
|
44
43
|
logSessionStarted(data: {projectId: string; perspective: string; authMethod: string}): void
|
|
45
44
|
|
|
46
|
-
/** Log a "SDK Hook
|
|
45
|
+
/** Log a "SDK Hook Mounted" event (deduplicated per hook name) */
|
|
47
46
|
logHookFirstUsed(hookName: string): void
|
|
48
47
|
|
|
49
|
-
/** Log a "SDK
|
|
50
|
-
|
|
48
|
+
/** Log a "SDK Error" event */
|
|
49
|
+
logError(errorType: string, hookName: string): void
|
|
51
50
|
|
|
52
|
-
/** Log a "SDK
|
|
51
|
+
/** Log a "SDK Session Ended" event and tear down the store */
|
|
53
52
|
endSession(): void
|
|
54
53
|
|
|
55
54
|
/** Tear down the store without logging a session-end event */
|
|
@@ -63,6 +62,7 @@ interface TelemetryManagerOptions {
|
|
|
63
62
|
sessionId: string
|
|
64
63
|
getClient: () => SanityClient
|
|
65
64
|
projectId: string
|
|
65
|
+
environment: TelemetryEnvironment
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -75,7 +75,7 @@ interface TelemetryManagerOptions {
|
|
|
75
75
|
* @internal
|
|
76
76
|
*/
|
|
77
77
|
export function createTelemetryManager(options: TelemetryManagerOptions): TelemetryManager {
|
|
78
|
-
const {sessionId, getClient, projectId} = options
|
|
78
|
+
const {sessionId, getClient, projectId, environment} = options
|
|
79
79
|
const startedAt = Date.now()
|
|
80
80
|
const emittedHooks = new Set<string>()
|
|
81
81
|
|
|
@@ -97,18 +97,28 @@ export function createTelemetryManager(options: TelemetryManagerOptions): Teleme
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
const enrichBatch = (batch: TelemetryEvent[]) =>
|
|
100
|
-
batch.map((event) =>
|
|
101
|
-
|
|
102
|
-
context
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
batch.map((event) => {
|
|
101
|
+
// Trace events (`trace.start` / `trace.log` / `trace.error` /
|
|
102
|
+
// `trace.complete`) arrive with their own caller-provided `context`.
|
|
103
|
+
// Log / userProperties events don't. Narrow via `in` so `event`
|
|
104
|
+
// stays typed as `TelemetryEvent`, then merge so we don't drop the
|
|
105
|
+
// trace context. SDK-owned fields below win on conflict.
|
|
106
|
+
const existing =
|
|
107
|
+
'context' in event ? (event.context as Record<string, unknown> | undefined) : undefined
|
|
108
|
+
return {
|
|
109
|
+
...event,
|
|
110
|
+
context: {
|
|
111
|
+
...existing,
|
|
112
|
+
version: CORE_SDK_VERSION,
|
|
113
|
+
environment,
|
|
114
|
+
origin: typeof window !== 'undefined' ? window.location.origin : 'node',
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
})
|
|
108
118
|
|
|
109
119
|
const sendEvents = async (batch: TelemetryEvent[]): Promise<unknown> => {
|
|
110
120
|
const client = getClient()
|
|
111
|
-
log.debug('sending event batch', {batchSize: batch.length})
|
|
121
|
+
log.debug('sending event batch', {batchSize: batch.length, environment})
|
|
112
122
|
return client.request({
|
|
113
123
|
uri: '/intake/batch',
|
|
114
124
|
method: 'POST',
|
|
@@ -135,13 +145,14 @@ export function createTelemetryManager(options: TelemetryManagerOptions): Teleme
|
|
|
135
145
|
},
|
|
136
146
|
|
|
137
147
|
logSessionStarted(data) {
|
|
138
|
-
log.debug('event: SDK
|
|
148
|
+
log.debug('event: SDK Session Started', {
|
|
139
149
|
projectId: data.projectId,
|
|
140
150
|
perspective: data.perspective,
|
|
141
151
|
authMethod: data.authMethod,
|
|
142
152
|
version: CORE_SDK_VERSION,
|
|
153
|
+
environment,
|
|
143
154
|
})
|
|
144
|
-
logger.log(
|
|
155
|
+
logger.log(SDKSessionStarted, {
|
|
145
156
|
version: CORE_SDK_VERSION,
|
|
146
157
|
...data,
|
|
147
158
|
})
|
|
@@ -154,18 +165,19 @@ export function createTelemetryManager(options: TelemetryManagerOptions): Teleme
|
|
|
154
165
|
logger.log(SDKHookMounted, {hookName})
|
|
155
166
|
},
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
log.debug('event: SDK
|
|
159
|
-
logger.log(
|
|
168
|
+
logError(errorType: string, hookName: string) {
|
|
169
|
+
log.debug('event: SDK Error', {errorType, hookName})
|
|
170
|
+
logger.log(SDKError, {errorType, hookName})
|
|
160
171
|
},
|
|
161
172
|
|
|
162
173
|
endSession() {
|
|
163
174
|
const durationSeconds = Math.round((Date.now() - startedAt) / 1000)
|
|
164
|
-
log.debug('event: SDK
|
|
175
|
+
log.debug('event: SDK Session Ended', {
|
|
165
176
|
durationSeconds,
|
|
166
177
|
hooksUsed: [...emittedHooks],
|
|
178
|
+
environment,
|
|
167
179
|
})
|
|
168
|
-
logger.log(
|
|
180
|
+
logger.log(SDKSessionEnded, {
|
|
169
181
|
durationSeconds,
|
|
170
182
|
hooksUsed: [...emittedHooks],
|
|
171
183
|
})
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import {afterEach, describe, expect, it, vi} from 'vitest'
|
|
2
|
-
|
|
3
|
-
import {isDevMode} from './devMode'
|
|
4
|
-
|
|
5
|
-
describe('isDevMode', () => {
|
|
6
|
-
afterEach(() => {
|
|
7
|
-
vi.unstubAllEnvs()
|
|
8
|
-
vi.unstubAllGlobals()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
it('returns false when NODE_ENV is production', () => {
|
|
12
|
-
vi.stubEnv('NODE_ENV', 'production')
|
|
13
|
-
vi.stubGlobal('window', undefined)
|
|
14
|
-
expect(isDevMode()).toBe(false)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('returns true when running on localhost', () => {
|
|
18
|
-
vi.stubEnv('NODE_ENV', 'development')
|
|
19
|
-
vi.stubGlobal('window', {
|
|
20
|
-
location: {href: 'http://localhost:3000/'},
|
|
21
|
-
})
|
|
22
|
-
expect(isDevMode()).toBe(true)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('returns true when running on 127.0.0.1', () => {
|
|
26
|
-
vi.stubEnv('NODE_ENV', 'development')
|
|
27
|
-
vi.stubGlobal('window', {
|
|
28
|
-
location: {href: 'http://127.0.0.1:3000/'},
|
|
29
|
-
})
|
|
30
|
-
expect(isDevMode()).toBe(true)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('returns true on localhost even when NODE_ENV is production', () => {
|
|
34
|
-
vi.stubEnv('NODE_ENV', 'production')
|
|
35
|
-
vi.stubGlobal('window', {
|
|
36
|
-
location: {href: 'http://localhost:3000/'},
|
|
37
|
-
})
|
|
38
|
-
expect(isDevMode()).toBe(true)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('returns false for a non-local URL', () => {
|
|
42
|
-
vi.stubEnv('NODE_ENV', 'test')
|
|
43
|
-
vi.stubGlobal('window', {
|
|
44
|
-
location: {href: 'https://myapp.sanity.studio/'},
|
|
45
|
-
})
|
|
46
|
-
expect(isDevMode()).toBe(false)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('returns true when NODE_ENV is development and no window', () => {
|
|
50
|
-
vi.stubEnv('NODE_ENV', 'development')
|
|
51
|
-
vi.stubGlobal('window', undefined)
|
|
52
|
-
expect(isDevMode()).toBe(true)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('returns false when NODE_ENV is test and no window', () => {
|
|
56
|
-
vi.stubEnv('NODE_ENV', 'test')
|
|
57
|
-
vi.stubGlobal('window', undefined)
|
|
58
|
-
expect(isDevMode()).toBe(false)
|
|
59
|
-
})
|
|
60
|
-
})
|
package/src/telemetry/devMode.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks whether the current URL points to a local development server.
|
|
3
|
-
*
|
|
4
|
-
* @param win - The window object to check
|
|
5
|
-
* @returns True if running on localhost or 127.0.0.1
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
function isLocalUrl(win: Window): boolean {
|
|
9
|
-
const url = win.location?.href
|
|
10
|
-
if (!url) return false
|
|
11
|
-
return (
|
|
12
|
-
url.startsWith('http://localhost') ||
|
|
13
|
-
url.startsWith('https://localhost') ||
|
|
14
|
-
url.startsWith('http://127.0.0.1') ||
|
|
15
|
-
url.startsWith('https://127.0.0.1')
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Determines whether the SDK should enable dev-mode telemetry for the
|
|
21
|
-
* SDK consumer (i.e. a developer building an app with `@sanity/sdk`).
|
|
22
|
-
*
|
|
23
|
-
* Browser: returns true only when the URL is `localhost` or `127.0.0.1`.
|
|
24
|
-
* The URL check is the primary signal because consumer bundlers may or
|
|
25
|
-
* may not forward `NODE_ENV` to the browser reliably.
|
|
26
|
-
*
|
|
27
|
-
* Node (scripts / non-browser): falls back to `NODE_ENV === 'development'`.
|
|
28
|
-
*
|
|
29
|
-
* Bracket-notation `process.env['NODE_ENV']` is used to avoid bundler
|
|
30
|
-
* dead-code replacement.
|
|
31
|
-
*
|
|
32
|
-
* @returns True if the SDK is running in a development environment
|
|
33
|
-
* @internal
|
|
34
|
-
*/
|
|
35
|
-
export function isDevMode(): boolean {
|
|
36
|
-
if (typeof window !== 'undefined') {
|
|
37
|
-
return isLocalUrl(window)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'development'
|
|
41
|
-
}
|