# Udgiv med Run

> Opret en app i Run, prøv den på din egen computer, udgiv versioner fra terminalen, en pipeline eller din AI-kodeassistent, og brug komplai fra appen gennem appens SDK.

Du skal bruge en færdigbygget browserapp, enten én HTML-fil eller en mappe med `index.html` som `dist`, og Run skal være slået til for jeres organisation. Kommandoerne i terminalen kræver Node.js 22.15 eller nyere. [Run](https://developers.komplai.dk/da/tools/run) beskriver, hvem der kan åbne en app, grænserne, og hvor data gemmes.

## Opret appen

1. Åbn **Run** i hubben, og vælg **Ny app**.
2. Skriv appens navn. Run foreslår en adresse ud fra navnet. Ret den, hvis du vil have en anden, eller tøm feltet for at få en tilfældig adresse.
3. Vælg **Opret app**. Appen åbner på sin egen side, klar til den første version.

En ny app har adgangen **Kun organisationen**: organisationens medlemmer logger ind i komplai for at åbne den.

## Byg til Run

- Lever én selvstændig HTML-fil eller en mappe eller ZIP-fil med `index.html` øverst. I en ZIP-fil må det hele også ligge i én mappe.
- Byg React, Vite eller et andet framework på din egen computer, og udgiv det færdige resultat, aldrig kildeprojektet.
- Brug relative adresser eller adresser, der starter med `/` på appens egen adresse. Ruter i browseren uden filendelse får appens HTML; en manglende JavaScript- eller CSS-fil giver stadig 404.
- Pakkeren udelader skjulte filer, `node_modules` og source maps og afviser symbolske links og projektfiler som `package.json`. Hold `.env`-filer og nøgler ude af det, du bygger: en browserapp kan ikke holde på en hemmelighed.

## Prøv appen på din egen computer

`dev` viser dit build på `http://localhost:5180`, som Run gør, med samme SDK, ruter og Content-Security-Policy og en lokal udgave af komplai:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish dev ./dist
```

- Alt, hvad appen angiver i `komplai.json`, regnes som godkendt. Noget, appen ikke har angivet, afvises med `capability_not_approved` som i Run.
- Du er `Udvikler` og administrator. `--as NAVN` ændrer navnet, og `--member` gør dig til medlem. På `http://localhost:5180/_komplai/dev` logger hver browser ind som sin egen person, så et privat vindue kan være person nummer to, og du kan afslutte sessionen for at prøve `session_expired`.
- Gemte data ligger i hukommelsen, til du stopper serveren.
- Redact finder kun mønstre. AI afvises med `ai_not_available_in_dev`, medmindre `KOMPLAI_API_KEY` indeholder en personlig API-nøgle med `chat:complete`. Så går kaldene til komplais API i EU-cloud eller gennem den forbindelse, appen angiver, og forbrug i EU-cloud tæller med i organisationens loft for AI-forbrug.
- Hændelser, fejl, tællinger og alle afvisninger bliver skrevet i terminalen.

`--port` vælger en anden port.

## Opret en udgivelsesnøgle

1. På appens side under **Udgiv den første version** (eller **Udgiv en ny version**) vælger du **Terminal**.
2. Vælg **Opret udgivelsesnøgle**. Nøglen vises kun én gang.
3. Kopiér den kommando, Run viser. Den indeholder adressen på kommandolinjeværktøjet og appens adresse til upload, men ingen nøgle.

En udgivelsesnøgle kan kun udgive nye versioner af den ene app. Den kan ikke oprette apps, ændre appens navn, adresse eller hvem der kan åbne den, åbne apps med adgangen **Kun organisationen**, eller bruge komplais AI. Den udløber efter 7 dage og holder op med at virke, når den bliver tilbagekaldt, når den, der oprettede den, forlader organisationen eller ikke længere må ændre appen, når appen bliver slettet, eller når Run bliver slået fra for organisationen. En app kan have 10 aktive nøgler. Du tilbagekalder en nøgle under **Udgivelsesnøgler** på appens side.

> **Hold nøglen ude af kode og chats**
>
> Læg aldrig udgivelsesnøglen i kode, Git, en kommando eller en chat med en AI-kodeassistent. Indsæt den, når terminalen spørger, eller sæt `KOMPLAI_PUBLISH_TOKEN` privat i din terminal eller dit værktøjs miljø.

## Udgiv en version

Se først, hvad der bliver udgivet. Kommandoen viser alle filer og kontrollerer manifestet som Run, uden at uploade noget:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --dry-run
```

Kør derefter kommandoen fra Run i projektets mappe. Udskift `./dist`, hvis dine færdige filer ligger i en anden mappe:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases
```

Kommandoen viser, hvilken app filerne skal til, beder dig bekræfte og spørger efter nøglen i et skjult felt. Den nye version er live med det samme på appens adresse. Åbn adressen, og kontrollér appen: en app med adgangen **Kun organisationen** beder dig logge ind i komplai, fordi udgivelsesnøglen ikke giver adgang til at se appen.

Hvis forbindelsen fejler, eller resultatet er usikkert, kan uploaden alligevel være gået igennem. Se i Run, hvilken version der er live, før du prøver igen. Kommandoen prøver aldrig igen af sig selv.

Gem adressen til upload én gang, så du ikke skal skrive den hver gang. `init` skriver `.komplai-publish.json` med adressen til upload og mappen med de færdige filer, aldrig nøglen:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish init --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist
```

Vil du selv uploade filerne med **Upload fil** på appens side, kan du pakke dem i en ZIP-fil uden at sende noget:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish pack ./dist --out app.zip
```

Installér kun kommandolinjeværktøjet fra pakkeadressen i den kommando, Run giver dig.

## Udgiv fra en pipeline eller et script

API'et til upload tager selve filen som body. Send en ZIP-fil som `application/zip` eller en enkelt HTML-fil som `text/html` med udgivelsesnøglen som Bearer-token:

```bash
curl https://hub.komplai.dk/api/publish/APP_UUID/releases \
  -H "Authorization: Bearer $KOMPLAI_PUBLISH_TOKEN" \
  -H "Content-Type: application/zip" \
  --data-binary @app.zip
```

Kommandolinjeværktøjet virker også i en pipeline. Det læser nøglen fra `KOMPLAI_PUBLISH_TOKEN`, og `--yes` springer bekræftelsen over:

```bash
npx --package=https://hub.komplai.dk/komplai-publish/komplai-publish-0.2.1.tgz komplai-publish ./dist --endpoint https://hub.komplai.dk/api/publish/APP_UUID/releases --yes
```

Adressen er til terminaler og byggeværktøjer. Den afviser alle forespørgsler med en `Origin`-header, så JavaScript i en browser kan ikke kalde den. En udgivelsesnøgle udløber efter 7 dage, så en pipeline skal have en ny nøgle fra Run derefter.

En vellykket upload svarer HTTP 200 med appens oplysninger: `id`, `activeRelease` (den version, der nu er live), `visibility` og de gemte versioner i `releases`, hver med id, oprettelsestidspunkt, udpakket størrelse i byte, antal filer og SHA-256-kontrolsummen af den uploadede fil. Ignorér felter, du ikke kender. Hvis arkivet eller en kapacitetskontrol fejler, er den version, der var live, stadig live.

| Status | Det skete |
| --- | --- |
| 400 | Arkivet eller formatet er ugyldigt, eller manifestet kan ikke bruges (`invalid_manifest`) |
| 401 | Nøglen er ugyldig, udløbet eller tilbagekaldt |
| 403 | Manglende tilladelse, en `Origin`-header, eller Run er slået fra for organisationen |
| 409 | Appen er offentlig, og versionen beder om noget, der kræver login (`public_app_capabilities`) |
| 413 | Uploaden er over grænsen |
| 429 | Grænsen for trafik eller samtidige forespørgsler er nået |
| 503 | Run er ikke tilgængeligt, eller resultatet er usikkert |
| 507 | Der er ikke plads til versionen |

Svaret er JSON med en `error`-kode og ingen oplysninger om nøglen. Efter en 503 skal du se i Run, hvilken version der er live, før du sender filen igen.

## Udgiv med din AI-kodeassistent

1. På appens side under **Udgiv en ny version** vælger du **AI-kodeassistent** og **Hent guiden (ZIP-fil)**. Den samme fil ligger på [hub.komplai.dk/komplai-publish/komplai-publish.zip](https://hub.komplai.dk/komplai-publish/komplai-publish.zip).
2. Pak den ud, og læg mappen `komplai-publish` i `.claude/skills` i din brugermappe til Claude Code eller i `.codex/skills` til Codex. I et projekt læser Claude Code også `.claude/skills`, og Codex læser `.agents/skills`. Andre assistenter kan læse `SKILL.md` og `API.md` i mappen.
3. Opret en udgivelsesnøgle, og giv assistenten kommandoen fra Run, aldrig nøglen.
4. Start en ny samtale, og bed assistenten bygge eller udgive appen. I Claude Code kan du også skrive `/komplai-publish`.

Assistenten prøver appen med `dev`, kontrollerer den med `--dry-run` og kører kommandoen; du indsætter nøglen, når terminalen spørger. Når du har godkendt udgivelsen og appen, må den tilføje `--yes` for at springe bekræftelsen over. Er resultatet usikkert, prøver den ikke igen: se først i Run, hvilken version der er live.

## Brug komplai fra appen

Hent SDK'et fra appens egen adresse. `/_komplai/run/v1.js` definerer `komplai` på siden, og `/_komplai/run/v1.mjs` eksporterer det som et modul. SDK'et sender alle kald til appens egen adresse med personens appsession, og Run kontrollerer sessionen, personens adgang og administratorens godkendelse ved hvert kald. Kald aldrig hubben eller komplais API fra appen, og læg aldrig en nøgle, et token eller en adgangskode i den.

Angiv i `komplai.json` ved siden af `index.html`, hvad appen bruger. Med Vite lægger du filen i `public/`, så den kommer med i `dist`. En enkelt HTML-fil kan have manifestet i `<script type="application/komplai+json">` i sin `<head>`. Manifestet bliver udleveret sammen med appen, så det må ikke indeholde noget hemmeligt, og det må højst fylde 16 KB.

```json
{
  "sdk": 1,
  "uses": {
    "identity": { "fields": ["name"], "reason": "Viser, hvem der har booket lokalet." },
    "data": {
      "bookings": {
        "scope": "app",
        "write": "members",
        "index": ["room", "day"],
        "retainDays": 365,
        "reason": "Bookinger, som alle i appen kan se."
      }
    },
    "log": { "events": ["booking_created"], "reason": "Skriver bookinger i Hændelsesloggen." }
  }
}
```

```html
<script src="/_komplai/run/v1.js"></script>
<ul id="bookings"></ul>
<script type="module">
  const list = document.getElementById("bookings");
  try {
    const me = await komplai.me();
    const bookings = komplai.data.collection("bookings");
    const booking = await bookings.add({ room: "A", day: "2026-11-02", name: me.name });
    await komplai.log.event("booking_created", { ref: booking.id });
    const { items } = await bookings.list({ where: { room: "A" } });
    for (const doc of items) {
      const item = document.createElement("li");
      item.textContent = `${doc.data.day}: ${doc.data.name}`;
      list.append(item);
    }
  } catch (error) {
    list.textContent = error.message;
  }
</script>
```

| Kald | Kræver i manifestet | Svarer |
| --- | --- | --- |
| `komplai.app()`, `komplai.theme.current`, `komplai.locale` | intet | Appens oplysninger, `light` eller `dark` og `da` eller `en` |
| `komplai.session` | intet; en offentlig app har ingen session | `expiresAt()`, `onExpired(fn)`, `renew()` og `signOut()` |
| `komplai.me()` | `identity` | `memberId` og de godkendte felter |
| `komplai.ai.chat({ messages })` | `ai.chat` | `{ text, model, processing, usage }` |
| `komplai.redact.findings(text)`, `.pseudonymise(text)`, `.restore(text, placeholders)` | `redact.text` | Fund med position og type eller tekst med betegnelser som `[PERSON-1]` |
| `komplai.data.collection(name)` | `data` | `add`, `get`, `list`, `update`, `remove`, `changes`, `watch` og `exportMine` |
| `komplai.log.event(name, { ref })`, `.error(error)`, `.count(name)` | `log.events`, `log.errors`, `log.counters` | Skriver hændelsen, rapporten eller tællingen |

I en samling med `scope` sat til `person` ser hver person kun sine egne dokumenter. Med `app` kan alle, der kan åbne appen, læse dem, og `write` afgør, om alle medlemmer (`members`) eller kun den, der oprettede appen, og organisationens administratorer (`managers`) skriver. Med `organisation` deler flere apps samlingen. Et medlem ændrer og sletter kun de dokumenter, medlemmet selv har oprettet; den, der oprettede appen, og administratorerne kan ændre alle. Send `{ ifVersion: doc.version }` med til `update`, når opdateringen ikke må overskrive en andens ændring.

Når et kald bliver afvist, får appen en `KomplaiError` med en `code`, en `status` og en `message` på personens sprog. Vis beskeden, og skriv data fra komplai ind på siden med `textContent`, aldrig `innerHTML`. De koder, du møder først:

- `capability_not_approved`: en administrator har ikke godkendt denne del for appen endnu.
- `session_expired`: personen er ikke længere logget ind i appen. `komplai.session.renew()` logger ind igen og vender tilbage til siden.
- `app_not_assigned`: personen har ikke adgang til det værktøj, appen bruger, fx Chat eller Redact.
- `version_conflict`: nogen har ændret dokumentet imens. Hent det, og prøv igen.

`API.md` i guiden viser alle kald, valgmuligheder, grænser og fejlkoder.

## Godkend det, appen bruger

Når du har udgivet en version, der beder om noget fra komplai, åbner en administrator appens side i Run og går til **Det må appen**. Hver del viser appens begrundelse og **Godkend** eller **Afvis**; en godkendt del kan senere tilbagekaldes.

- **AI**: administratoren vælger, hvor appen må bruge AI, i komplais EU-cloud inden for organisationens loft for AI-forbrug eller gennem en af organisationens egne forbindelser, og sætter appens egen månedlige grænse. Når grænsen er nået, stopper appens AI til næste måned.
- **Redact**: appen bruger mønstre og NER på komplais servere i Tyskland. Administratoren kan også tillade Redacts sprogmodel i komplais EU-cloud.
- **Sende data til …**: godkend først, hvor appen må sende data hen.

Prøv alle funktioner i Run efter godkendelsen: den lokale udgave godkender alt.

## Administrér appen

- **Versioner**: **Brug denne version** gør en tidligere version live igen.
- **Tag appen offline**: ingen kan åbne appen, før du udgiver eller vælger en version igen. **Vis den nyeste version igen** henter den tilbage.
- **Fejl i appen**: fejl, appen har sendt fra browseren de seneste 30 dage. Kun den, der oprettede appen, og organisationens administratorer kan se dem.
- **Hent appens data**: alle appens dokumenter, også dem, hver person har gemt kun for sig selv. Kun organisationens administratorer kan hente dem.
- **Slet app og alle versioner**: skriv appens navn for at bekræfte. Appens udgivelsesnøgler og links holder op med at virke, og adressen kan straks tages af andre. Det kan ikke fortrydes.

---

https://developers.komplai.dk/da/guides/run
