|
| 1 | +// Lecture + validation Zod des variables Matomo exposées au bundle (VITE_*). |
| 2 | +// SPA statique : aucun secret ici (cf. CLAUDE.md "Variables d'environnement"). |
| 3 | + |
| 4 | +import { z } from "zod"; |
| 5 | + |
| 6 | +// Coerce "true"/true vers boolean ; undefined -> false. |
| 7 | +const booleanFromEnv = z |
| 8 | + .union([z.boolean(), z.string()]) |
| 9 | + .optional() |
| 10 | + .transform((value) => value === true || value === "true"); |
| 11 | + |
| 12 | +const matomoEnvSchema = z.object({ |
| 13 | + url: z.url().optional(), |
| 14 | + siteId: z.string().min(1).optional(), |
| 15 | + funnelId: z.string().min(1).optional(), |
| 16 | + debug: booleanFromEnv, |
| 17 | + // Dimensions personnalisées : nom logique -> id numérique Matomo. |
| 18 | + dimensions: z.record(z.string(), z.coerce.number().int().positive()), |
| 19 | +}); |
| 20 | + |
| 21 | +export type MatomoEnv = z.infer<typeof matomoEnvSchema>; |
| 22 | + |
| 23 | +export interface MatomoSettings { |
| 24 | + env: MatomoEnv; |
| 25 | + /** init + envoi réel : env complètes ET build production. */ |
| 26 | + enabled: boolean; |
| 27 | + /** log des events sans envoi (activable en dev via VITE_DEBUG_MATOMO). */ |
| 28 | + debug: boolean; |
| 29 | +} |
| 30 | + |
| 31 | +const DIMENSION_KEY = /^VITE_MATOMO_DIMENSION_(.+)_ID$/; |
| 32 | + |
| 33 | +const DISABLED: MatomoSettings = { |
| 34 | + env: { debug: false, dimensions: {} }, |
| 35 | + enabled: false, |
| 36 | + debug: false, |
| 37 | +}; |
| 38 | + |
| 39 | +// Fonction pure (testable) : parse un environnement brut et décide de l'activation. |
| 40 | +export function parseMatomoEnv( |
| 41 | + rawEnv: Record<string, string | undefined>, |
| 42 | + isProd: boolean, |
| 43 | +): MatomoSettings { |
| 44 | + const dimensions: Record<string, string | undefined> = {}; |
| 45 | + for (const key of Object.keys(rawEnv)) { |
| 46 | + const match = DIMENSION_KEY.exec(key); |
| 47 | + if (match) dimensions[match[1].toLowerCase()] = rawEnv[key]; |
| 48 | + } |
| 49 | + |
| 50 | + const result = matomoEnvSchema.safeParse({ |
| 51 | + url: rawEnv.VITE_MATOMO_URL, |
| 52 | + siteId: rawEnv.VITE_MATOMO_SITE_ID, |
| 53 | + funnelId: rawEnv.VITE_MATOMO_FUNNEL_ID, |
| 54 | + debug: rawEnv.VITE_DEBUG_MATOMO, |
| 55 | + dimensions, |
| 56 | + }); |
| 57 | + |
| 58 | + if (!result.success) { |
| 59 | + // Analytics ne doit jamais casser l'app : on désactive sur configuration invalide. |
| 60 | + console.warn("[ODICE matomo] configuration invalide, analytics désactivé", result.error.issues); |
| 61 | + return DISABLED; |
| 62 | + } |
| 63 | + |
| 64 | + const env = result.data; |
| 65 | + const hasCore = Boolean(env.url && env.siteId); |
| 66 | + return { env, enabled: isProd && hasCore, debug: env.debug }; |
| 67 | +} |
| 68 | + |
| 69 | +export const matomoSettings: MatomoSettings = parseMatomoEnv( |
| 70 | + import.meta.env as unknown as Record<string, string | undefined>, |
| 71 | + import.meta.env.PROD, |
| 72 | +); |
0 commit comments