@siax/mobile-analytics (0.1.1)
Installation
@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/npm install @siax/mobile-analytics@0.1.1"@siax/mobile-analytics": "0.1.1"About this package
@siax/mobile-analytics
Produktanalys till PostHog och traces till Tempo (OTLP/HTTP) — med en redigeringsmotor som gör MSEC-11 🔴 (ingen känslig data i events) till en kontroll i stället för en förhoppning.
Noll beroenden. Ingen posthog-react-native, ingen @opentelemetry/*.
Plattformens fetch räcker, och allt annat injiceras.
Kärnbussgränsen (MOB-02)
| Ansvar | Ägs av | Här |
|---|---|---|
| Lagra och analysera events | PostHog (flottan) | HTTP-klient mot /batch/ |
| Ta emot traces | Tempo (n0d-tempo) |
OTLP/HTTP-exportör |
| Felrapportering | GlitchTip | — |
| Feature flags | Unleash (server10) | — |
| Samtyckesregister | appen / ID0 | ConsentGate — ett gränssnitt |
| Redigering, kö, batchning, offline, trace-koppling | detta paket | ✅ |
Redigeringsmotorn — kontrollen som gör MSEC-11 verklig
Två oberoende lager, båda default-deny:
- Allowlista på egenskapsnamn. Ett fält som inte står på listan lämnar
aldrig enheten. Nästlade fält kräver punktnotation (
user.plan) och plattas ut. Objekt utan tillåten undersökväg, listor med objekt och för djupa strukturer kastas. - Namnspärr (
DENIED_NAME_TOKENS). Namn somuserEmail,ssnellerauthTokenblockeras även om någon allowlistat dem. Jämförelsen sker per namndel (userEmail→user+email), inte som delsträng, sårecipient_countfastnar inte på "ip". - Mönsterdetektering på värdena som ändå passerar:
| Detektor | Träffar | Extra kontroll |
|---|---|---|
jwt, bearer, api-key, secret-assignment |
tokens, Bearer …, sk_…, token=… |
— |
email |
e-postadresser | — |
personnummer |
10/12 siffror, med och utan -/+ |
Luhn |
card-number |
13–19 siffror med mellanslag/bindestreck | Luhn |
phone |
+46 70 … och 070-… |
8–15 siffror |
ipv4 |
punktnotation | oktetter ≤ 255 |
Tal granskas också: ett personnummer som skickas som number maskeras.
Träffar ersätts med [redacted:<detektor>] — bortfallet rapporteras via
onWarning med sökväg och detektornamn, aldrig värdet.
Medvetna avvägningar: ett personnummer eller kortnummer med felaktig kontrollsiffra passerar (Luhn-kravet finns för att slippa maskera ordernummer och datum). Mönstren använder inga lookbehind-uttryck, eftersom de måste fungera i Hermes och inte bara i V8.
Vad som FAKTISKT är byggt
createRedactor()/createDefaultRedactor()— allt ovan, plusmaxStringLength,maxDepth,maxArrayLengthoch spärr mot__proto__.createAnalytics()— samtyckesgrind → redigering → kö → transport, i den ordningen. Råa värden hamnar aldrig i bufferten och därmed aldrig på disk.- Samtyckesgrind (GDPR):
unknownskickar ingenting och buffrar ingenting.deniedtömmer kön — även en kö som legat kvar på disk sedan samtycket drogs tillbaka i en tidigare session raderas vidstart(). - Offline-buffring + batchning: peek/ack mot kön, så att event ligger kvar
tills servern bekräftat. Varje event bär ett stabilt id som går ut som
PostHogs
$insert_id→ en omsändning dubblerar inte. Drop-oldest vid köntaket, med räknare (overflowCount) så att bortfallet syns. - Poison-pill-hantering: 5xx/429/408 och nätfel behåller batchen; övriga 4xx släpper den, annars blockeras kön för alltid.
createPostHogTransport()—POST {host}/batch/, projektnyckeln injiceras (aldrig i kod, SEC-01).createTracer()— OTLP/HTTP-JSON till Tempo: span-hierarki, statuskoder, nanosekundstidsstämplar som strängar, automatisk export vid batchgräns. Span-attribut går genom samma redigeringsmotor, med en egen, snävare attributlista (http.urlsaknas medvetet).- OBS-03:
traceContext()eller en aktiv span sättertrace_id/span_idpå varje event, så att event och HTTP-trace går att lägga bredvid varandra. - Skyddsräcken kring identitet: ett
distinctIdsom matchar en detektor stoppar eventet, och eventnamn måste vara maskinnamn (^[a-z][a-z0-9_.:-]{0,63}$) så att fritext med persondata inte kan bli ett eventnamn.
Vad som INTE är byggt (medvetet)
- Ingen autocapture, ingen session replay, inga heatmaps. De samlar in per definition allt — motsatsen till default-deny.
- Ingen GlitchTip-/Sentry-koppling. Felrapportering är ett eget paket/ansvar.
- Ingen feature-flagg-läsning (Unleash) — hör hemma i
@siax/mobile-config. - Ingen sampling och ingen komprimering av batcher.
- Ingen persistent lagringsadapter.
QueueStorage/ConsentStorageär gränssnitt; AsyncStorage-/MMKV-implementationerna hör till apprepot. Endast en minnesvariant följer med (createMemoryQueueStorage). - Ingen automatisk HTTP-instrumentering.
@siax/mobile-apiskapar spans och ger trace-contexten hit — detta paket letar inte upp anrop på egen hand. - Ingen exponentiell backoff mellan flushförsök; nästa försök sker vid nästa
intervall eller nästa
flush().
Användning
import {
createAnalytics,
createDefaultRedactor,
createPostHogTransport,
createTracer,
} from '@siax/mobile-analytics';
const tracer = createTracer({
endpoint: process.env.TEMPO_OTLP_URL!, // env-NAMN, aldrig ett värde (SEC-01)
serviceName: 'demo-app',
});
const analytics = createAnalytics({
transport: createPostHogTransport({
host: process.env.POSTHOG_HOST!,
projectApiKey: process.env.POSTHOG_PROJECT_KEY!,
}),
distinctId: () => pseudonymousDeviceId, // aldrig e-post, aldrig personnummer
redactor: createDefaultRedactor(['search_term']),
storage: asyncStorageQueue, // överlever flygplansläge
tracer,
onWarning: (warning) => console.warn('[analytics]', warning.code, warning.detail),
});
await analytics.start();
await analytics.setConsent('granted'); // inget skickas innan detta
await analytics.capture('checkout_started', { plan: 'pro' });
Test
cd packages/mobile-analytics && node --test
60 tester, noll beroenden, node:test + node:assert. Testfilerna importerar
src/*.ts direkt, vilket kräver Node med typavskalning påslagen (Node 22.18+
eller 24; på 22.6–22.17 med --experimental-strip-types). Verifierat på Node
v24.14.0: 60/60 gröna.
Typkontroll av den publicerade koden:
cd packages/mobile-analytics && tsc --noEmit -p tsconfig.json
strict: true + erasableSyntaxOnly + verbatimModuleSyntax, rent.
tsconfig.json täcker src/ — testfilerna kan typkontrolleras först när
@types/node finns installerat i repot (inga beroenden installeras i denna omgång).