@siax/create-siax-app (0.1.2)
Installation
@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/npm install @siax/create-siax-app@0.1.2"@siax/create-siax-app": "0.1.2"About this package
create-siax-app
App-generatorn för SIAX K6 (M0B). Producerar ett komplett apprepo som klarar
🥉 Brons direkt vid skapandet — siax-doctor --fail-on=block ger exit 0 på
det genererade repot, utan att någon rör en fil efteråt.
Zero dependencies. Körs med enbart Node 20.11+.
node index.mjs --ci --name "Gute Taxi" --bundle-id io.siax.gutetaxi \
--capabilities location,notifications,offline --out ../
Utan --ci frågar generatorn interaktivt (bara när stdin är en terminal — den
hänger aldrig i ett workflow).
Varför den finns
Alternativet är att kopiera ett befintligt apprepo. Det har provats i estatet
och ger samma utfall varje gång: fem repon med fem versioner av samma CI, och en
säkerhetsfix som landar i ett av dem. Generatorn är det som gör app nummer tio
billig — och det som gör att en normändring kan rullas ut till alla appar
samtidigt (--upgrade).
Vad som FAKTISKT är byggt
| Kontroll | Läge | Bevis |
|---|---|---|
| MOB-07 — genererat repo klarar Brons direkt | ✅ | test/doctor.test.mjs kör den riktiga doctorn mot ett genererat repo, --fail-on=block, och kräver measuredScore: 100 |
| MOB-08 — allt ett K6-apprepo måste ha | ✅ | test/generate.test.mjs verifierar 52 obligatoriska sökvägar + normkontrollerna |
| MOB-09 — idempotent och uppgraderingsbar | ✅ | test/upgrade.test.mjs: omkörning = noll ändringar, appkod skrivs aldrig över, ändrad generatorfil ger konflikt (och läker inte av sig själv) |
| MOB-10 — endast valda kapabiliteter genereras | ✅ | test/capabilities.test.mjs + test/generate.test.mjs: två kapabilitetssvar ger olika repon, behörighetstexter valideras (DIST-06) |
node --test "test/**/*.test.mjs" → 65 tester, 65 gröna (2026-08-09).
⚠️ Använd glob-formen.
node --test tooling/create-siax-appger på Node 22+ falskt grönt: katalogen tolkas som ett testfall, rapporteras som ett passerande test, och inget körs. Samma fälla gällernode --test test.
Vad generatorn lägger i repot
siax.repo.json kind=app, platformRepo=M0B, sdkPackages[], bundleIds
siax.config.json deploy-deskriptor för appens API, fyra miljöer
app.json Expo-identitet (appens fil)
app.config.js slår ihop app.json + config/capabilities.json + miljö
config/capabilities.json HÄRLEDD ur kapabilitetsvalen — behörigheter, plugins
config/environments/*.json dev, test, staging, prod (endast env-NAMN)
config/ota.json OTA-kanaler, stegvis utrullning i prod
.gitea/workflows/ ci, security, nightly, release (ALDRIG .github/)
Dockerfile multi-stage, node:22-alpine, non-root, healthcheck
services/api/ appens eget API: health, ready, /v1/me med riktig
ID0-JWT-verifiering (RS256/ES256 mot JWKS, node:crypto)
services/api/migrations/0001_init.sql tenant_id + radnivåsäkerhet
contracts/openapi.yaml kontraktet, inklusive kapabiliteternas rutter
src/ env, api-klient, ID0-konfig, App.tsx, kapabilitetsmoduler
store/{ios,android}/ butiksmetadata som versionerad artefakt (DIST-01)
docs/ ARCHITECTURE, ADR, runbooks, klientstod.md, synk.md
test/ konformitetstester som kör utan npm install
scripts/ BLD-14-kontroll och OTA-publicering
.siax-generator.json ägarskapsmanifest (se nedan)
Ägarskapsmodellen (MOB-09)
Varje genererad fil har ett deklarerat ägarskap i .siax-generator.json,
tillsammans med en sha256 av det generatorn senast skrev:
| Ägarskap | Betydelse | Exempel |
|---|---|---|
managed |
Generatorn äger filen. Skrivs över vid uppgradering endast om hashen på disk matchar den vi skrev sist. | .gitea/workflows/*, Dockerfile, config/capabilities.json, docs/runbook/* |
seed |
Skrivs en gång, rörs sedan aldrig. | src/App.tsx, README.md, migrationer, butikstexter, docs/synk.md |
merge |
Generatorn äger ett namnrum av nycklar, resten bevaras ordagrant. | package.json |
Har någon ändrat en managed-fil rapporteras det som en konflikt och filen
lämnas orörd. Konflikten läker inte av sig själv: manifestet behåller den
gamla hashen, så nästa körning rapporterar den igen tills den lösts. Rätt
åtgärd är oftast att flytta ändringen till generatorn här i M0B; --force
finns för när man verkligen menar det.
merge-regeln för package.json: generatorn äger beroenden i namnrummet
@siax/*, expo, expo-*, react, react-dom, react-native, typescript,
@types/react samt en fast lista scriptnamn. Allt annat bevaras. En borttagen
kapabilitet får därför sitt beroende bortstädat, medan appens egna beroenden och
scripts överlever.
node index.mjs --upgrade --dir <apprepo> --dry-run # visa
node index.mjs --upgrade --dir <apprepo> # utför
node index.mjs --upgrade --dir <apprepo> --strict # exit 2 vid konflikt
Torrkörningen använder samma kodväg som en riktig körning (plan → apply med
dryRun), inte en separat låtsasimplementation som kan divergera.
Kapabiliteter (MOB-10)
camera, location, notifications, purchases, ai, storage, offline.
Varje kapabilitet drar med sig — och bara den — sitt @siax/mobile-*-paket, sin
expo-modul (pinnad till rätt SDK-linje), sina behörigheter med texter, sina
env-NAMN och sina API-rutter. Registret namnger också vilken K1-kärnbusstjänst
som äger funktionen, så att MOB-02 är synlig i datan och inte bara i en
kommentar.
Behörighetstexterna valideras innan något skrivs (DIST-06): minst 30 tecken,
ingen platshållare, och de nämner appen vid namn. Egen text sätts med
--permission-text camera="…" eller med Info.plist-nyckeln direkt.
Kombinationsregler finns där de behövs — camera + storage ger
NSPhotoLibraryUsageDescription, utan vilken iOS kraschar när bildväljaren
öppnas.
Expo-SDK-matrisen
src/expo-sdk.mjs pinnar en hel SDK-linje åt gången (SDK 51 och 52 i dag).
Generatorn gissar aldrig fram versionsnummer: begär man en linje som inte
finns i matrisen vägrar den, med instruktionen att lägga till raden efter att ha
läst Expos release notes. Ett repo som blandar RN- och expo-modulversioner
bygger inte, och felet syns först i en runner-körning som tar tjugo minuter.
Det som medvetet INTE är gjort
package-lock.jsonär ett frö. Den har npm:s riktiga struktur (lockfileVersion: 3) och rotpaketets beroendeintervall, men inget upplöst träd — det kräver nätverk och kan inte genereras offline.npm installmaterialiserar den. Det står i det genererade README:t, i CI-workflowet (som varnar) och i manifestet (lockfileMaterialized: false). SUP-01 är alltså uppfylld strukturellt, inte i sak, tills någon körtnpm install.@siax/mobile-*är pinnade till0.0.0(--sdk-versionför att ändra) — den version paketen har i M0B i dag. De är ännu inte publicerade till Giteas npm-registry, sånpm installi ett genererat repo kan inte lösa dem förrän M2 publicerat. Endast@siax/uioch@siax/tokens(0.1.0) är publicerade.- Ingen ikon, ingen startskärm. En genererad platshållarikon är precis den
sortens sak som glider hela vägen till en butiksinlämning.
assets/README.mdbeskriver vad som krävs. - Klientens skärmar.
src/App.tsxvisar miljö och valda kapabiliteter. Den ärseed— appen tar över direkt. - Kapabilitetsmodulerna anropar appens EGET API, inte SDK:t. De är skrivna
mot rutter generatorn själv genererar (
/v1/ai/completem.fl.) i stället för mot@siax/mobile-*-signaturer som inte kunnat verifieras här. Det är medvetet: hellre kod som bevisligen stämmer än kod som ser rikare ut och inte kompilerar. - Typkontroll av det genererade repot kräver
npm install(React Native levererar sina egna typer). Generatorn syntaxkontrollerar sina utdata, mentsckörs först i det genererade repots CI. - Ingen interaktiv frågeslinga för allt. Prompten täcker namn, bundle-id och
kapabiliteter; övrigt sätts med flaggor.
--cistänger av prompten helt.
Bevis (2026-08-09)
$ node index.mjs --ci --name "Gute Taxi" --bundle-id io.siax.gutetaxi \
--capabilities location,notifications,offline,ai --dir <tmp>/gute-taxi
nya 79 · uppdaterade 0 · ... · konflikter 0
$ node C:/siax-std/packages/doctor/src/doctor.mjs --repo <tmp>/gute-taxi --fail-on=block
Mätt poäng: 100/100 över 38 mätbara kontroller.
EXIT=0
$ cd <tmp>/gute-taxi && node --test "test/**/*.test.mjs"
tests 14 · pass 14 · fail 0 # utan npm install
$ node --test "test/**/*.test.mjs" # generatorns egna tester
tests 65 · pass 65 · fail 0
Även varianten --operational-state running --node server11 ger 100/100 (då
mäts även REPO-06, CD-01 och CD-03).
Struktur
index.mjs bin-ingång (tunn — CLI:t är importerbart och testbart)
src/cli.mjs argv → exitkod, injicerbar utskrift
src/args.mjs argv-parser (repeterbara nyckel=värde-flaggor)
src/spec.mjs AppSpec: normalisering + validering, alla fel på en gång
src/capabilities.mjs kapabilitetsregistret + DIST-06-validering
src/expo-sdk.mjs den verifierade SDK-matrisen
src/manifest.mjs ägarskap, hashning, plan, tillämpning
src/generate.mjs filkarta → plan → skrivning
src/prompt.mjs interaktivt läge (aldrig i CI)
src/templates/*.mjs mallarna, en modul per område
test/*.test.mjs 65 tester, node:test, zero dependencies
Mallarna är JS-funktioner, inte statiska filer med platshållare. Skälet är kapabilitetslogiken: en mallfil hade behövt villkorsspråk för att generera olika behörigheter, plugins, rutter och beroenden per val — och då är det enklare och mer läsbart att det är riktig kod från början.