fix(web): honor analytics opt-out state

This commit is contained in:
digua committed 2026-06-23 22:58:22 +08:00
1 parent 9171cec5de
commit d49b1b8472
4 files changed
+104 -3

No files matched your search

@@ -0,0 +1,41 @@
import { describe, it } from 'node:test'
import assert from 'node:assert/strict'
import Fastify from 'fastify'
import type { HttpRouteContext } from '../../context'
import { registerTelemetryRoutes } from './telemetry'
describe('telemetry routes', () => {
it('reads and writes analytics enabled state through the shared service', async () => {
let enabled = true
const app = Fastify()
registerTelemetryRoutes(app, {
analyticsService: {
getEnabled: () => enabled,
setEnabled: (next: boolean) => {
enabled = next
},
},
} as unknown as HttpRouteContext)
await app.ready()
try {
const before = await app.inject({ method: 'GET', url: '/_web/telemetry/enabled' })
assert.equal(before.statusCode, 200)
assert.deepEqual(before.json(), { enabled: true })
const update = await app.inject({
method: 'POST',
url: '/_web/telemetry/enabled',
payload: { enabled: false },
})
assert.equal(update.statusCode, 200)
assert.deepEqual(update.json(), { success: true })
const after = await app.inject({ method: 'GET', url: '/_web/telemetry/enabled' })
assert.equal(after.statusCode, 200)
assert.deepEqual(after.json(), { enabled: false })
} finally {
await app.close()
}
})
})
@@ -2,6 +2,16 @@ import type { FastifyInstance } from 'fastify'
import type { HttpRouteContext } from '../../context'
export function registerTelemetryRoutes(server: FastifyInstance, ctx: HttpRouteContext): void {
server.get('/_web/telemetry/enabled', async () => {
return { enabled: ctx.analyticsService?.getEnabled() ?? false }
})
server.post<{ Body: { enabled?: boolean } }>('/_web/telemetry/enabled', async (req) => {
if (!ctx.analyticsService || typeof req.body?.enabled !== 'boolean') return { success: false }
ctx.analyticsService.setEnabled(req.body.enabled)
return { success: true }
})
server.post<{ Body: { eventName: string; properties?: Record<string, string | number> } }>(
'/_web/telemetry/track',
async (req, reply) => {
+35
View File
@@ -36,4 +36,39 @@ describe('WebPlatformAdapter', () => {
globalThis.fetch = originalFetch
}
})
it('reads analytics enabled state from the CLI web backend', async () => {
const originalFetch = globalThis.fetch
const requestedUrls: string[] = []
globalThis.fetch = ((input: RequestInfo | URL) => {
requestedUrls.push(String(input))
return Promise.resolve(new Response(JSON.stringify({ enabled: true })))
}) as typeof fetch
try {
assert.equal(await new WebPlatformAdapter().getAnalyticsEnabled(), true)
assert.deepEqual(requestedUrls, ['/_web/telemetry/enabled'])
} finally {
globalThis.fetch = originalFetch
}
})
it('writes analytics enabled state to the CLI web backend', async () => {
const originalFetch = globalThis.fetch
const requests: Array<{ url: string; init?: RequestInit }> = []
globalThis.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
requests.push({ url: String(input), init })
return Promise.resolve(new Response(JSON.stringify({ success: true })))
}) as typeof fetch
try {
const result = await new WebPlatformAdapter().setAnalyticsEnabled(false)
assert.deepEqual(result, { success: true })
assert.equal(requests[0].url, '/_web/telemetry/enabled')
assert.equal(requests[0].init?.method, 'POST')
assert.equal(requests[0].init?.body, JSON.stringify({ enabled: false }))
} finally {
globalThis.fetch = originalFetch
}
})
})
+18 -3
View File
@@ -45,11 +45,26 @@ export class WebPlatformAdapter implements PlatformAdapter {
}
async getAnalyticsEnabled(): Promise<boolean> {
return false
try {
const resp = await fetchWithAuth('/_web/telemetry/enabled')
const data = (await resp.json()) as { enabled?: boolean }
return data.enabled === true
} catch {
return false
}
}
async setAnalyticsEnabled(_enabled: boolean): Promise<{ success: boolean }> {
return { success: false }
async setAnalyticsEnabled(enabled: boolean): Promise<{ success: boolean }> {
try {
const resp = await fetchWithAuth('/_web/telemetry/enabled', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled }),
})
return (await resp.json()) as { success: boolean }
} catch {
return { success: false }
}
}
async trackDailyActive(locale: string): Promise<void> {