SIAX Technology (sax3l)

@siax/mobile-sync (0.1.1)

Published 2026-08-10 12:03:21 +00:00 by admin

Installation

@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/
npm install @siax/mobile-sync@0.1.1
"@siax/mobile-sync": "0.1.1"

About this package

@siax/mobile-sync

Offline-first lokalt lager och synkkö för K6-appar. Konfliktmodell per entitet krävs (OFFL-05).

Status: implementerad och testad. 69 tester, 69 gröna (node --test), plus strikt typkontroll (tsc --noEmit, TypeScript 6). Noll runtime-beroenden. Ingen tjänst är driftsatt och paketet är ännu inte publicerat till Giteas npm-registry.

Kärnbussgränsen (MOB-02)

Detta paket är en yta, inte en tjänst. Om du står i begrepp att implementera något som ID0, INF0, ST0RE, N0D, AUD0, N0TIFY, B00K, CL0UD eller 1P redan gör — bygg ytan, inte tjänsten.

Konkret i det här paketet:

Beroende Hur det konsumeras
Identitet (ID0) getAuthToken() injiceras i transporten. Paketet läser aldrig en token själv.
Objektlager (ST0RE) UploadTransport injiceras. Paketet talar inte med MinIO.
Audit (AUD0), analys (PostHog), fel (GlitchTip) Paketet avger händelser via SyncObserver. Värdappen vidarebefordrar.
Synk-endpoint Ägs av appens eget API (ARCHITECTURE.md §5). SyncTransport injiceras.

Inga hemligheter i koden (SEC-01/MSEC-01): all konfiguration kommer in som parametrar.

Vad som FAKTISKT är byggt

Kontroll Status Var
OFFL-01 lokalt först, fungerar i flygplansläge src/engine.tsput/patch/remove/get/list rör aldrig nätet
OFFL-02 SQLite bakom injicerbart SqliteDriver src/sqlite.ts, src/adapters/expo-sqlite.ts
OFFL-03 persistent kö som överlever krasch och återupptas src/queue.ts — lease + recoverAbandoned()
OFFL-04 klientgenererad idempotensnyckel per operation src/clock.ts, unik kolumn i siax_sync_queue
OFFL-05 konfliktmodell per entitet, typframtvingad src/conflict.tsConflictPolicyMap<TMap> med -?
OFFL-06 konflikter presenteras, aldrig tyst förlust src/store.ts konfliktjournal med discarded_doc
OFFL-07 status pending/syncing/done/failed + orsak engine.status()
OFFL-10 versionerade migrationer, klarar versionshopp src/migrations.ts, src/schema.ts (v1→v4)
OFFL-11 delta-synk med markör engine.pull(), CursorStore
OFFL-13 återupptagbara uppladdningar src/upload.ts

Utöver kraven: FIFO med head-of-line blocking per post, exponentiell backoff med jitter, dead-letter med explicit återupptagning, och en HTTP-transport som översätter statuskoder till konflikt / retrybart / permanent avslag.

Vad som INTE är byggt

  • Ingen synkserver. Endpointen ägs av respektive apps API. Kontraktet står i docs/synk.md §5, klientsidan finns som createHttpSyncTransport().
  • Ingen bakgrundsschemaläggning. Appen anropar flush()/pull() själv (t.ex. vid AppState-övergång eller från expo-background-task).
  • Ingen kryptering av den lokala databasen. SQLCipher är driverns ansvar; nyckeln ska komma från enhetens keystore.
  • Ingen exempelapp (MOB-13 kräver en per paket — den saknas fortfarande).
  • Inte publicerat till https://git.siax.io/api/packages/sax3l/npm/.
  • Ingen op-sqlite-adapter. Bara expo-formen finns; op-sqlite går att koppla in via withSavepointTransactions() men det är inte gjort och inte testat.
  • Ingen komprimering eller batchning av push — en operation per HTTP-anrop.

Kom igång

import * as SQLite from 'expo-sqlite';
import { createSyncEngine, createExpoSqliteDriver, createHttpSyncTransport, defineConflictPolicies } from '@siax/mobile-sync';

type Note = { readonly id: string; readonly title: string; readonly body: string; readonly updatedAt: number };
type AppEntities = { readonly note: Note };   // OBS: `type`, inte `interface`

const engine = await createSyncEngine<AppEntities>({
  driver: createExpoSqliteDriver(await SQLite.openDatabaseAsync('app.db')),
  transport: createHttpSyncTransport({
    baseUrl: process.env.EXPO_PUBLIC_API_URL ?? '',   // NAMN, aldrig ett värde i koden
    getAuthToken: () => auth.getAccessToken(),        // från ID0 via @siax/mobile-auth
  }),
  conflicts: defineConflictPolicies<AppEntities>({
    note: { kind: 'user-choice' },                    // utelämna raden ⇒ kompileringsfel
  }),
  observer: { onEvent: (event) => telemetry.forward(event) },  // vidare till AUD0/PostHog
});

await engine.put('note', 'n1', { id: 'n1', title: 'Utkast', body: '', updatedAt: Date.now() });
await engine.flush();   // gör inget destruktivt om nätet är nere
await engine.pull('note');

const status = await engine.status();
for (const conflict of await engine.pendingConflicts()) {
  // visa conflict.summary + conflict.fields, låt användaren välja
  await engine.resolveConflict(conflict.conflictId, { kind: 'keep-local' });
}

Konfliktmodellerna, trådformatet, statusarna och migrationsreglerna dokumenteras i docs/synk.md.

Tester

node --test "packages/mobile-sync/test/*.test.ts"    # 69 tester
cd packages/mobile-sync && npm test                  # samma sak
cd packages/mobile-sync && npm run typecheck         # tsc --noEmit, strict

Inga testberoenden: node:test + node:assert, Node 22+ kör .ts direkt via type stripping. node:sqlite används i test/helpers/ som riktig SQLite-motor, så testerna kör samma SQL som telefonen kommer att köra — inte en attrapp som håller med.

Node-fälla i den här miljön: node --test <katalog> fungerar INTE på Node 24.14 här — katalogargumentet tolkas som en modul att köra (med en package.json i katalogen körs main och 1 tomt "test" rapporteras som grönt). Använd glob-formen ovan, eller node --test utan argument från paketkatalogen (då räknas även de tre hjälpfilerna in och summan blir 72).

Testerna täcker bland annat: flygplansläge (skrivning + läsning utan nät), omstart mitt i en flush, tappat serversvar utan dubbel effekt, alla tre konfliktmodellerna genom hela motorn, användarval med bevarad förlorare, versionshopp 1→4 med datatransformationer, delta mot full hämtning, utgången markör, och avbruten uppladdning som återupptas av en ny instans från serverns offset.

test/types.check.ts är ett kompileringstest för OFFL-05: fyra @ts-expect-error-fall som slutar kompilera om typskyddet försvinner. Det körs av npm run typecheck, inte av testkörningen.

Details
npm
2026-08-10 12:03:21 +00:00
1
UNLICENSED
latest
44 KiB
Assets (1)
Versions (2) View all
0.1.1 2026-08-10
0.1.0 2026-08-10