SIAX Technology (sax3l)

@siax/mobile-api (0.1.0)

Published 2026-08-10 11:40:47 +00:00 by admin

Installation

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

About this package

@siax/mobile-api

Transportlagret under den API-klient som genereras ur appens OpenAPI (API-04). Handskrivna dubbletter av en genererad operation är en avvikelse.

Status: transportlagret är implementerat och testat. Generatorn själv finns inte — den hör till M3 (app-generatorn). Det som finns här är runtimet generatorn ska skriva ut anrop till, plus en createClient som tar en operationstabell. Paketet är ännu inte publicerat och inte kört mot ett riktigt API.

Vad transporten gör åt varje anrop

Kontroll Vad som faktiskt sker Var
VER-01 x-siax-app-version, x-siax-app-build, x-siax-platform, x-siax-os-version, x-siax-runtime-version på varje anrop (+ valfria app-id, update-id, device-model) src/client-info.ts
API-10 Idempotensnyckel på muterande metoder, samma nyckel över alla omförsök src/idempotency.ts
API-07 application/problem+json (RFC 9457) tolkas till ProblemDetailsError, utökningar bevarade src/problem.ts
API-09 Cursor-paginering som asynkron iterator, med skydd mot upprepad cursor src/pagination.ts
SCALE-05 Strömbrytare: closed → open → half_open → closed src/circuit-breaker.ts
SCALE-06 Timeout per anrop, skild från användarens avbrott src/transport.ts
OBS-03 W3C traceparent; traceId finns på varje svar OCH varje fel src/trace.ts
Omförsök med exponentiell backoff, full jitter, Retry-After och retry-budget src/backoff.ts

Använda paketet

import { createTransport, createClient, ProblemDetailsError } from '@siax/mobile-api';

const transport = createTransport({
  baseUrl: process.env.EXPO_PUBLIC_API_BASE_URL!, // env-NAMN, aldrig ett värde i koden
  client: {
    appVersion: Application.nativeApplicationVersion!,
    buildNumber: Application.nativeBuildVersion!,
    platform: Platform.OS === 'ios' ? 'ios' : 'android',
    osVersion: String(Platform.Version),
    runtimeVersion: Updates.runtimeVersion!,
    updateId: Updates.updateId ?? undefined,
  },
  // Kopplingen till ID0 — @siax/mobile-auth förnyar token vid behov.
  getAuthorization: async () => `Bearer ${await session.getAccessToken()}`,
  onAttempt: (t) => posthog.capture('api_attempt', { ...t, error: undefined }),
});

const api = createClient(transport, [
  { operationId: 'listOrders', method: 'GET', path: '/v1/orders', paginated: true },
  { operationId: 'createOrder', method: 'POST', path: '/v1/orders' },
] as const);

try {
  await api.createOrder({ body: { amount: 50 } }); // får automatiskt en idempotensnyckel
} catch (error) {
  if (error instanceof ProblemDetailsError) showToast(problemMessage(error.problem));
}

Paginering:

const listOrders = createPaginatedOperation<Order>(transport, {
  operationId: 'listOrders', method: 'GET', path: '/v1/orders', paginated: true,
});
for await (const order of listOrders({ query: { limit: 50 } })) render(order);

Designbeslut värda att känna till

  • Idempotensnyckeln genereras en gång per LOGISK begäran. En nyckel per försök ser identisk ut i koden och är funktionellt samma sak som ingen nyckel. Det finns ett test som hävdar att alla tre försöken bär samma nyckel.
  • POST/PATCH försöks bara om när de har en nyckel. Sätter du idempotencyKey: false stängs omförsöken av samtidigt — annars vore avstängningen en tyst risk för dubbel debitering.
  • 429 öppnar inte strömbrytaren. Servern mår bra; den skyddar sig. Att bryta strömmen för det vore att straffa oss för vår egen anropstakt. Retry-After respekteras däremot, och går före backoff-beräkningen.
  • Retry-budget, inte bara maxförsök. En budget hindrar att alla klienter tredubblar lasten precis när servern minst tål det.
  • Timeout ≠ avbrott. En timeout försöks om; ett avbrott från anroparen (skärmen lämnades) försöks aldrig om. Skillnaden kräver en egen AbortControllerAbortSignal.timeout() kan inte skilja på fallen.
  • Kroppen läses innanför tidsgränsen. En server som skickar huvuden och sedan tystnar mitt i kroppen träffar också timeouten.
  • Ett HTML-svar blir aldrig Problem Details. Bara application/problem+json tolkas som RFC 9457; en 502-sida från en proxy blir ett vanligt HttpError.

Tester

node --test "packages/mobile-api/test/*.test.ts"

59 tester, alla gröna (körning 2026-08-09, Node 24.14). Inga testberoenden: node:test + node:assert, inget npm install krävs.

Runtime-krav: Node 22.18+ eller 24 — källkoden är ren TypeScript som körs via Nodes inbyggda type stripping (erasableSyntaxOnly i tsconfig.json håller koden inom vad strippningen klarar).

Vad som INTE är gjort (AR-5)

  • Ingen OpenAPI-generator. Operationstabellen skrivs för hand tills M3 genererar den. createClient returnerar Operation<unknown> — de genererade typerna per operation kommer med generatorn.
  • Ingen offline-kö och ingen cachning. Ett anrop som misslyckas efter alla omförsök kastar. Kö och konfliktlösning hör till @siax/mobile-sync (M11).
  • Ingen automatisk omförhandling vid 401. Transporten hämtar Authorization per försök, så en förnyad token används vid omförsök — men ett 401 utlöser inte i sig ett refresh. Kopplingen görs i getAuthorization.
  • Strömbrytaren är per transport, inte per host eller endpoint. En app som pratar med flera bas-URL:er ska skapa en transport per URL.
  • Ingen mätvärdesexport. onAttempt är kroken; ingen PostHog- eller GlitchTip-koppling är inbyggd (det vore MOB-02-överträdelse att bygga en).
  • Ingen tsc-körning. typescript är inte ett beroende i repot i denna omgång, så tsconfig.json är ett kontrakt som ännu inte upprätthålls av CI.
  • Aldrig kört mot ett riktigt API. Alla tester går mot en injicerad transport.

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.

Details
npm
2026-08-10 11:40:47 +00:00
1
UNLICENSED
24 KiB
Assets (1)
Versions (2) View all
0.1.1 2026-08-10
0.1.0 2026-08-10