Пређи на садржај
BeeuniBeeuni
Српски
Esc
↑↓навигација↵отвори⌘Jпреглед
На овој страници

Апликације

Креирајте, постављајте и контролишите Beeuni апликације из SDK-а и из React-а.

Апликације су поставке у оквиру пројекта, свака са једним сталним URL-ом, непроменљивим издањима, машинама по групи процеса и трајним волуменима. Гранајте логику према app.capabilities. Ова страница покрива SDK интерфејс: фасаду apps на објекту пројекта, позиве за артефакте, издања, машине и волумене, токене за пријаву, извезене типове и React куке.

За модел, конфигурацију издања, врсте извора, CLI, стални URL и понашање при покретању из мировања, прочитајте Апликације.

const apps = beeuni.project(projectId).apps;

Фасада apps

Метод Обавија Шта ради
apps.list() GET /projects/:pid/apps Наводи апликације које позивалац може да отвори (менаџер пројекта види све)
apps.create(input) POST …/apps Креира апликацију и додељује јој стални URL
apps.get(appId) GET …/apps/:id Чита једну апликацију
apps.update(appId, input) PATCH …/apps/:id Преименује је или мења машину, време мировања до заустављања, режим рада (always_on), uses или labels. Режим рада се примењује у року од 5 минута; промена машине се примењује на следеће издање
apps.remove(appId) DELETE …/apps/:id Брише апликацију, њене машине и све слике издања; враћа images: {released, pending}. Њени волумени задржавају снимак final 7 дана
apps.start(appId) POST …/apps/:id/start Поставља desired_state на running и припрема извршно окружење. Статичка апликација одговара са 409 static_app_no_runtime
apps.stop(appId) POST …/apps/:id/stop Одмах обуставља извршавање; следећи захтев га наставља. Статичка апликација одговара са 409 static_app_no_runtime: нема извршно окружење и служи садржај док има активну поставку
apps.rollback(appId, deploymentId) POST …/apps/:id/rollback Креира НОВО издање из артефакта и конфигурације спремног издања и пушта га у рад као при постављању (202). Волумени задржавају своје податке

Артефакти су непроменљиви улаз за поставку:

Метод Обавија Шта ради
apps.artifacts.register(input) POST …/apps/artifacts Региструје archive или oci_image; враћа URL за отпремање архиве
apps.artifacts.uploadArchive(bytes, options?) — Региструје, отпрема, хешира и финализује један .tar.gz у једном позиву
apps.artifacts.finalize(artifactId, input) POST …/apps/artifacts/:id/finalize Потврђује sha256 и size_bytes за ручно отпремање

Издања (поставке) су непроменљива и нумерисана:

Метод Обавија Шта ради
apps.deployments.create(appId, input) POST …/apps/:id/deployments Покреће издање из артефакта, извора и опционог config издања
apps.deployments.list(appId) GET …/apps/:id/deployments Наводи историју постављања
apps.deployments.get(appId, deploymentId) GET …/deployments/:did Чита једну поставку и њене догађаје
apps.deployments.logs(appId, deploymentId, options?) GET …/deployments/:did/logs Чита евиденције извршног окружења помоћу курсора
apps.deployments.remove(appId, deploymentId) DELETE …/deployments/:did Брише једну поставку и њену слику; 409 за активну поставку или изградњу у току. Враћа image: 'released' | 'pending' | 'none'

Машине, скалирање и exec (серверска апликација; апликација без машина одговара са 409 app_no_machines):

Метод Обавија Шта ради
apps.machines.list(appId) GET …/apps/:id/machines Свака машина: machine_id, process_group, state, release, vm, volume
apps.machines.start/stop/restart(appId, machineId) POST …/machines/:mid/{start,stop,restart} Делује на једну машину; по завршетку враћа листу машина
apps.machines.destroy(appId, machineId) DELETE …/machines/:mid Уништава једну машину. Њен волумен остаје; њена група ради са једном машином мање
apps.scale(appId, count) PUT …/apps/:id/scale Машине по групи процеса ({ worker: 3 }, 0–20), примењује се у позадини (202). По завршетку враћа scale и machines
apps.exec(appId, { command, machine_id?, timeout_s? }) POST …/apps/:id/exec Извршава једну команду у покренутој машини (project.app.admin; бележи се у ревизијској евиденцији). timeout_s 1–300, подразумевано 60. По завршетку враћа exit_code, stdout, stderr (по 1 MiB), truncated

Волумени (трајни дискови):

Метод Обавија Шта ради
apps.volumes.list(appId) GET …/apps/:id/volumes Сваки волумен: name, process_group, machine_id, size_gb, status, attached, snapshot_retention_days
apps.volumes.create(appId, { name, size_gb, process_group?, snapshot_retention_days? }) POST …/volumes Унапред креира волумен; каснија машина из његове групе са тачком монтирања тог имена преузима га
apps.volumes.update(appId, volumeId, { size_gb?, snapshot_retention_days? }) PATCH …/volumes/:vid Повећава волумен (никада га не смањује; највише 100 GB) или мења период задржавања (1–60 дана)
apps.volumes.destroy(appId, volumeId, confirmName) DELETE …/volumes/:vid?confirm=<name> project.app.admin. Одбија се са 409 volume_attached док га машина користи као монтирани волумен. Задржава снимак final 7 дана
apps.volumes.snapshots(appId, volumeId) GET …/volumes/:vid/snapshots Снимци daily, manual и final
apps.volumes.snapshot(appId, volumeId) POST …/volumes/:vid/snapshots Снимак manual одмах
apps.volumes.restore(appId, volumeId, snapshotId) POST …/volumes/:vid/restore project.app.admin. Машина се зауставља, волумен се враћа на снимак, машина се покреће на њему (202)
apps.volumes.fork(appId, volumeId, { name, snapshot_id? }) POST …/volumes/:vid/fork Нов, неповезан волумен у истој апликацији, из снимка или тренутног садржаја

Токени за пријаву (могућност member_tokens; 409 app_capability_unsupported када је апликација нема):

Метод Обавија Шта ради
apps.token(appId) POST …/apps/:id/token Токен за пријаву у апликацију који важи 15 минута и идентификује позиваоца

Приступ је сопствена политика ауторизације апликације:

Метод Обавија Шта ради
apps.access.get(appId) GET …/apps/:id/access Чита политику. Захтева project.app.read
apps.access.update(appId, input) PATCH …/apps/:id/access Замењује политику и повећава њену ревизију
apps.access.session(appId) POST …/apps/:id/access-session Генерише URL који важи пет минута и размењује се за колачић ограничен на хост

Постављање статичког сајта

uploadArchive обавља цео поступак за артефакт: региструје артефакт, проверава га према max_bytes, отпрема бајтове помоћу PUT, израчунава SHA-256 и финализује га.

const apps = beeuni.project(projectId).apps;

const app = await apps.create({ slug: 'docs', name: 'Docs' });
const artifact = await apps.artifacts.uploadArchive(tarGzBytes, {
  onProgress: (uploaded, total) => console.log(`${uploaded}/${total}`),
});

const deployment = await apps.deployments.create(app.app_id, {
  artifact_id: artifact.artifact_id,
  source: { kind: 'static', spa: true },
});

console.log(app.url, deployment.status); // https://…apps.beeuni.ai  queued

create прихвата и поља машине: cpu, memory_gb, disk_gb, idle_timeout_seconds и always_on. Изоставите их за подразумеване вредности. Апликације немају месечни буџет: кредити налога плаћају рачунарске ресурсе. Стално укључена серверска апликација наплаћује се 24/7; она која ради на захтев само док је активна. always_on: true покреће серверску апликацију 24/7 (websockets, позадинске петље); false је зауставља после idle_timeout_seconds и покреће је при следећем захтеву. Статичка апликација нема извршно окружење: always_on је false.

API игнорише monthly_budget_usd ако га старији клијент пошаље (200, без грешке). Ниједан одговор апликације га не садржи.

uses наводи апликације, по slug-у, за које ова апликација може да добије токене за пријаву и којима може да приступи преко монтираних веза; подразумевано нема ниједне, а update(appId, { uses }) замењује листу (погледајте Апликације које апликација користи).

create и update враћају warnings, што је увек [].

const app = await beeuni.project(projectId).apps.create({ slug: 'worker', name: 'Worker', always_on: true });
console.log(app.always_on, app.hosting_type); // true null (until the first deploy)

Сачекајте поставку периодичном провером њеног статуса:

async function waitForReady(appId: string, deploymentId: string) {
  for (;;) {
    const { deployment } = await apps.deployments.get(appId, deploymentId);
    if (deployment.status === 'ready') return deployment;
    if (deployment.status === 'failed' || deployment.status === 'cancelled') {
      throw new Error(deployment.error ?? deployment.error_code ?? deployment.status);
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
}

Вредности статуса су queued, validating, building, provisioning, checking, ready, failed и cancelled.

Постављање OCI слике

Региструјте непроменљиву референцу слике, затим наведите команду процеса и јавни циљни порт:

const registered = await apps.artifacts.register({
  kind: 'oci_image',
  image: 'ghcr.io/hekmat/service:2026-08-07',
});

await apps.deployments.create(app.app_id, {
  artifact_id: registered.artifact.artifact_id,
  source: {
    kind: 'oci_image',
    image: 'ghcr.io/hekmat/service:2026-08-07',
    command: ['node', 'server.js'],
    port: 3000,
    readiness_path: '/health',
  },
});

register враћа upload: null за oci_image. Само archive добија URL за отпремање.

CreateAppDeploymentInput прихвата и environment (вредности извршног окружења које нису тајне), secrets (кључ извршног окружења повезан са именом тајне пројекта) и config (AppReleaseConfigInput, конфигурација издања). Неважећи config даје одговор 400 app_config_invalid са issues: [{ path, message }]; монтирање у извршном окружењу без волумена даје одговор 400 app_volumes_unsupported.

await apps.deployments.create(app.app_id, {
  artifact_id: registered.artifact.artifact_id,
  source: { kind: 'oci_image', image, command: ['node', 'server.js'] },
  config: {
    processes: { app: '', worker: 'node worker.js' },
    http_service: { internal_port: 3000, access: 'app', processes: ['app'] },
    mounts: [{ source: 'data', destination: '/data', initial_size_gb: 10, processes: ['app'] }],
    deploy: { release_command: 'node migrate.js' },
  },
});

Читање евиденција извршног окружења

let cursor = 0;
for (;;) {
  const page = await apps.deployments.logs(app.app_id, deployment.deployment_id, {
    after: cursor,
    limit: 200,
  });
  for (const entry of page.entries) console.log(entry.source, entry.line);
  cursor = page.next_cursor;
  if (page.entries.length === 0) break;
}

Сваки унос садржи cursor, time, source (app, appd, caddy) и line. Ред caddy је дневник приступа: метод, URI, статус, трајање и заглавља одговора. Он никада не садржи заглавља захтева, јер она садрже акредитиве гејта (токен и идентитет прегледача, улазни токен добављача).

Машине, скалирање и волумени

const apps = beeuni.project(projectId).apps;

const machines = await apps.machines.list(app.app_id);
await apps.scale(app.app_id, { worker: 3 });                     // 202: applied in the background

const { exit_code, stdout } = await apps.exec(app.app_id, { command: ['ls', '/data'] });

const [data] = await apps.volumes.list(app.app_id);
const snapshot = await apps.volumes.snapshot(app.app_id, data.volume_id);
await apps.volumes.restore(app.app_id, data.volume_id, snapshot.snapshot_id);   // project.app.admin
const copy = await apps.volumes.fork(app.app_id, data.volume_id, { name: 'data_copy' });

Машина задржава свој machine_id између издања; свако издање замењује њену кутију (instance_id). Једна машина истовремено монтира један волумен. Враћање је нова верзија волумена: замењени садржај остаје у његовој историји. Снимак монтираног волумена може да изостави последњих приближно 1 s уписа.

Convex backend

Convex backend је обична серверска App са волуменом, направљена на основу шаблона convex (beeuni apps launch --template convex --name db; погледајте Template convex). SDK нема позив специфичан за Convex. Прочитајте администраторски кључ са машине помоћу exec и омогућите UI App-у приступ backend-у помоћу uses:

const db = (await apps.list()).find((a) => a.slug === 'db')!;
const { stdout } = await apps.exec(db.app_id, { command: ['sh', '-c', 'cd /convex && ./generate_admin_key.sh'] });
// The admin key controls all code and data: never log it or ship it to a browser.

await apps.update(site.app_id, { uses: ['db'] }); // the site may mint db tokens and bind to it

db.services садржи URL адресе backend-а: http (URL Convex клијента) и site (HTTP радње).

Ваша App већ зна ко је гледа

App чији је хост Beeuni отвара неко ко је већ пријављен на Beeuni. Гејт за Apps их аутентификује пре него што се пошаље први бајт, па вашој App није потребна сопствена пријава — ни друга лозинка, ни екран за давање сагласности, ни преусмеравање.

У прегледачу:

import { createBeeuni, beeuniAppViewerToken } from '@beeuni/sdk';
import { useBeeuniAppViewer } from '@beeuni/sdk/react';

const beeuni = createBeeuni({
  backendUrl: '/_beeuni/api/v1',             // the gate, on your App's own origin
  getToken: beeuniAppViewerToken(),          // the viewer's own App-scoped token
});

function Header() {
  const { status, viewer } = useBeeuniAppViewer();
  return <span>{status === 'viewer' ? viewer.email : 'Signed out'}</span>;
}

Прегледач позива /_beeuni/api/v1/* на сопственом изворишту ваше App, никада https://api.beeuni.ai/v1 директно: API не одговара на CORS preflight са изворишта App, па директан позив у прегледачу не успева. Гејт прослеђује сваки позив Beeuni API-ју као пријављени прегледач, са токеном прегледача ограниченим на App. Правила:

  • Потребан му је viewer_token_scope: 'api'. У супротном одговара са 403 viewer_api_disabled.
  • Делује само за прегледач који је гејт пријавио (Beeuni пријава или приступни линк). Без тога одговара са 401 no_viewer_identity.
  • Одговара само на захтев са сопственог изворишта App. Захтев са другог сајта добија одговор 403 cross_site_request.
  • Прослеђује /v1/* осим /v1/oauth/* и MCP крајњих тачака, које дају одговор 404. Колачић ваше App и њено сопствено заглавље Authorization никада не стижу до API-ја, а API не може да постави колачић на вашој App.

На серверу ваше App, гејт потписује идентитет у сваком захтеву:

import { readAppViewer, createAppViewerBeeuni } from '@beeuni/sdk/server';

const viewer = await readAppViewer(request);
// { userId, email, name, picture, groupIds, groups, role, projectId, accountId, appId, accessMode, token }
if (!viewer) return new Response('Not found', { status: 404 });

// and, for an `api`-scoped App, act as them:
const beeuni = await createAppViewerBeeuni(request, { backendUrl });
await beeuni.projects.list();               // their projects, their role

readAppViewer проверава HMAC над заглављем помоћу BEEUNI_APP_VIEWER_SECRET, који Beeuni убацује у вашу App приликом деплојовања. Фалсификовано заглавље никада не пролази: гејт брише сваку копију коју је послао клијент пре прослеђивања, a потпис се прави тајном изведеном за сваку App.

Колико ваша App сазнаје

Једно подешавање у смерницама приступа App — Settings → Access у Beeuni-ју, beeuni apps access <app> --viewer off|identity|api или viewer_token_scope на PATCH /projects/:id/apps/:appId/access:

Опсег Шта ваша App прима
identity (подразумевано) ID, имејл, име, слику, улогу налога и Beeuni групе прегледача (ID-јеве и називе, само у налогу ове App), плус токен profile email. Довољно за приказивање сопствених података свакој особи и ограничење приступа по групи.
api Наведено изнад, плус токен који делује као та особа на Beeuni API-ју — ограничен њеном сопственом улогом.
off Ништа.

Токен никада није Beeuni сесија корисника: траје сат времена, садржи само те опсеге, а сваки токен који App изда престаје да важи када се App обрише или се промене њене смернице приступа.

Коришћење токена прегледача

  • На серверу га читајте за сваки захтев. Гејт ставља активни токен у x-beeuni-app-viewer-token у сваки проксирани захтев. Пошаљите га као Authorization: Bearer Beeuni API-ју — createAppViewerBeeuni(request) ради управо то. Направите једног клијента по захтеву; не чувајте токен.
  • После промене смерница приступа, стари токени престају да раде. Следећи захтев кроз гејт садржи нови. У прегледачу, beeuniAppViewerToken() се сам опоравља: када API одбије његов токен, SDK поново чита /_beeuni/viewer и једном понавља позив.
  • Улога прегледача је горња граница. Токен може да уради тачно оно што прегледач може у Beeuni-ју, никада више. На пројекту са дозволама агената, member треба да има одобрење за агента који ваша App покреће: без њега POST /projects/:id/sessions одговара са 403 no_agent_access. Одобрите прегледачима агента, а не ширу улогу.
  • Ко има прегледач. Особа која отвори App својом Beeuni пријавом — или приступним линком, који је пријављује као ту особу — има један. App password нема ниједан: лозинка доказује дељену тајну, а не особу. App public има један само за посетиоца који је стигао преко приступног линка; голи URL остаје анониман.
  • То је акредитив. Beeuni изоставља заглавља захтева из дневника приступа App (beeuni apps logs). Немојте евидентирати заглавље у сопственом коду.

App која се испоручује на сопственом домену (не на *.apps.beeuni.ai) нема гејт испред себе — тамо користите Sign in with Beeuni.

Један члан, у сваком окружењу

Beeuni потврђује исту особу на три места: прегледач пита гејт (/_beeuni/viewer), сервер App чита потписано заглавље, а App која проверава токене за пријаву (Convex backend или ваш сопствени сервер) прима Beeuni-јем потписан токен. readBeeuniMember претвара сваки од тих облика у један BeeuniMember, а requireBeeuniMember одлучује ко може да настави. Нема оквира нити зависности: исти код ради у прегледачу, Node-у, Bun-у, Worker-у и Convex функцији.

import {
  readBeeuniMember, requireBeeuniMember, verifyBeeuniToken,
  beeuniToken, beeuniBinding, fetchBeeuniAppViewer, BeeuniMemberError,
} from '@beeuni/sdk';

// Browser: who is looking (null when nobody).
const me = readBeeuniMember(await fetchBeeuniAppViewer());

// Browser → an App this App uses, on the same origin: its URL and a token fetcher.
const db = beeuniBinding('db');
const convex = new ConvexReactClient(db.url);
convex.setAuth(db.token);
// React: read the member with useQuery(api.members.me), never useConvexAuth() (see below).

// Browser: a token for this App itself, or for an App it uses.
const token = await beeuniToken()();
const dbToken = beeuniToken({ audience: 'db' });

// A Convex function: the runtime verified the token; enforce the rules.
const member = requireBeeuniMember(await ctx.auth.getUserIdentity(), { groups: ['Finance'] });

// A server App: verify the bearer. No options = the BEEUNI_AUTH_* env Beeuni injects.
// Any other server: pass the App's `auth` values.
const caller = await verifyBeeuniToken(bearer, { issuer: app.auth.issuer, audience: app.auth.audience, jwks: app.auth.jwks_uri });

У React-у немојте позивати useConvexAuth(): он баца грешку у обичном ConvexProvider (потребан му је ConvexProviderWithAuth, а beeuniBinding није верификован код тог добављача). Прочитајте пријављеног члана упитом:

// convex/members.ts
export const me = query({ args: {}, handler: async (ctx) => readBeeuniMember(await ctx.auth.getUserIdentity()) });
const me = useQuery(api.members.me);   // undefined: loading. null: signed out. Otherwise the member.

readBeeuniMember враћа null за анонимног позиваоца. Користите requireBeeuniMember само тамо где функција мора да баци грешку.

Поље Вредност
userId Beeuni ID корисника. Стабилан; на њему заснивајте редове.
email, name, picture Из профила члана. null када је непознато.
groups, groupIds Beeuni групе члана у овом налогу, по називу и ID-ју.
role Улога у налогу: owner, admin или member.
accountId, projectId Где се App налази.

requireBeeuniMember(claims, { groups, roles }) враћа члана или баца BeeuniMemberError са code unauthenticated (нико или токен који није прошао проверу) или forbidden (изван група или улога). Свака листа значи „било која од ових“; група се подудара по називу или ID-ју; празна листа не дозвољава приступ никоме.

Токени за пријаву

Један издавалац по пројекту потписује токене сваке App: iss = <API origin>/v1/projects/<projectId>, aud = ID App за коју је токен намењен, 15 минута. Његов скуп кључева је јаван на <issuer>/jwks.json, а назив му даје <issuer>/.well-known/openid-configuration. Свака App садржи вредности које верификују њене токене: app.auth.issuer, app.auth.audience, app.auth.jwks_uri. Токен садржи sub, email, name, picture, groups, group_ids, role, account_id и project_id; токен агента садржи kind: 'agent' и нема групе ни улогу.

Функција Шта ради
beeuniToken({ audience? }) Функција за преузимање токена (облик који клијенти за рад у реалном времену користе као повратну функцију за аутентификацију) за саму апликацију (подразумевано) или апликацију коју она користи. Чита /_beeuni/token на сопственом извору апликације. Кешира се до непосредно пре истека; { forceRefreshToken: true } поново шаље захтев. Враћа null када нема пријављеног посетиоца, а null уз једно упозорење у конзоли за апликацију коју не користи (403 app_not_linked). Никада не баца изузетак.
beeuniBinding(slug, { origin? }) { url, token } за апликацију коју ова апликација користи: url = <origin>/_beeuni/apps/<slug> (HTTP и WebSocket, исти извор, без CORS-а), token = beeuniToken({ audience: slug }).
verifyBeeuniToken(bearer, { issuer?, audience?, jwks? }) Проверава ES256 потпис, истек (толеранција од 60 s), издаваоца и публику. Подразумеване вредности: BEEUNI_AUTH_ISSUER, BEEUNI_AUTH_AUDIENCE, BEEUNI_AUTH_JWKS. Beeuni убацује све три у извршно окружење сваке серверске апликације (издавалац: пројекат; публика: сопствени ID апликације; скуп кључева: data: URI), па verifyBeeuniToken(bearer) тамо ради без опција. Никада не постављајте BEEUNI_AUTH_* у env серверске апликације: префикс BEEUNI_ је резервисан и beeuni validate га одбацује. Скуп кључева је објекат, JSON текст, data: URI или https URL (auth.jwks_uri, преузима се једном по процесу). Сваки неуспех баца BeeuniMemberError, укључујући недостајући скуп кључева или публику: један кључ пројекта потписује токене свих апликација, па је aud оно што спречава прихватање токена друге апликације. audience: false прихвата токен за било коју апликацију пројекта.
apps.token(appId) Токен који идентификује позиваоца, из API-ја (POST …/apps/:id/token). Сесија агента добија токен који идентификује њеног агента.

Члан кога уклоните из пројекта или групе губи приступ у року од једног периода важења токена; контрола приступа апликацији одбија га при следећем учитавању странице. Beeuni групе захтевају Enterprise план; улоге раде на сваком плану.

Управљање приступом

await apps.access.update(app.app_id, {
  mode: 'restricted',
  member_ids: [memberId],
  group_ids: [groupId],
});

const preview = await apps.access.session(app.app_id);
window.open(preview.url); // valid for five minutes

AppAccessConfig приказује password_configured, никада лозинку или њен хеш. Поставите лозинку помоћу { mode: 'password', password }. Свако ажурирање увећава revision, чиме се опозивају постојећи колачићи апликације.

Типови

Сваки тип у наставку извози се из @beeuni/sdk.

Тип Шта садржи
App Идентитет, capabilities, labels, scale, services (AppServiceSummary[]), machines (total, running, stopped), volumes (count, size_gb), config (AppReleaseConfig активног издања, или null), uses, used_by, auth, url, access_mode, access_revision, desired_state, active_deployment_id, hosting_type (активног издања: static, sandbox или null пре првог постављања), machine (величина групе која опслужује захтеве у активном издању), idle_timeout_seconds, always_on, retained_deployments, warnings (само креирање и ажурирање; увек []), last_request_at, viewer_can_access
AppCapability 'deployments' | 'rollback' | 'preview' | 'sleep' | 'static' | 'member_tokens' | 'machines' | 'scale' | 'exec' | 'volumes' | 'snapshots'
AppReleaseConfig · AppReleaseConfigInput Разрешена конфигурација издања (processes, services, mounts, vm, deploy) · изворно написани облик (processes, http_service, services, mounts, vm, deploy и скраћени облици port, command, readiness_path, always_on, resources)
AppServiceConfig · AppServiceAccess · AppAutoStop · AppCheck name, internal_port, protocol, access, auto_stop_machines, auto_start_machines, min_machines_running, processes, checks · 'public' | 'app' | 'admins' · 'off' | 'stop' | 'suspend' · type, port, path, interval_s, timeout_s, grace_period_s
AppMountConfig · AppVmConfig · AppDeployStrategy source, destination, initial_size_gb, snapshot_retention_days, processes · cpu, memory_gb, disk_gb, processes · 'rolling' | 'immediate' | 'bluegreen' | 'canary'
AppServiceSummary name, protocol, access, internal_port, processes, url (null када би ознака хоста била предугачка)
AppMachine · AppMachineState machine_id, instance_id, process_group, state, release (deployment_id, version), vm, volume, created_at, started_at, stopped_at · 'started' | 'starting' | 'stopped' | 'stopping' | 'provisioning'
AppVolume · AppVolumeSnapshot · CreateAppVolumeInput volume_id, name, process_group, machine_id, size_gb, status, attached, snapshot_retention_days, created_at · snapshot_id, kind (daily, manual, final), commit_id, created_at · name, size_gb, process_group, snapshot_retention_days
AppExecInput · AppExecResult command, machine_id, timeout_s · machine_id, exit_code, stdout, stderr, truncated
AppAuth issuer, audience (ID апликације), jwks_uri: јавне вредности које проверавају токене за пријављивање у апликацију
AppToken token, expires_at
BeeuniTokenOptions · BeeuniTokenFetcher · BeeuniBinding · VerifyBeeuniTokenOptions Помоћне функције за токене за пријављивање наведене изнад
AppDeployment version, status, source_kind, hosting_type (static: испоручује се из складишта, без извршног окружења; sandbox: машине), hosting_provider, runtime_spec, build_spec, error_code, attempt_count, created_by, actor_type, source_session_id, config (разрешена конфигурација издања), strategy, release_command_status (running, succeeded, failed или null)
AppRollback Вредност којом се разрешава apps.rollback: App уз издање у реду чекања у deployment
AppDeploymentDetail Један deployment уз његов events: догађаји животног циклуса и дневник изградње (редови build_log и један догађај log_truncated када изградња испише више од 5.000 редова)
AppAccessConfig mode, revision, member_ids, group_ids, password_configured
AppAccessMode 'private' | 'project' | 'restricted' | 'public' | 'password'
AppSource StaticAppSource | BundleAppSource | DockerfileAppSource | OciImageAppSource
AppArtifact kind, status, sha256, size_bytes, image_reference
AppLogEntry · AppLogsResponse Један ред дневника и једна страница уз next_cursor

apps.list() и useProjectApps враћају само апликације које позивалац сме да отвори према правилима приступа сваке апликације (приватно: креатор; ограничено: наведени чланови и групе; пројекат, лозинка и јавно: тим пројекта). Менаџер пројекта види сваку апликацију, па приватном апликацијом и даље може да се управља када њен креатор оде. Зато је viewer_can_access једнако true на свакој наведеној апликацији. get апликације коју позивалац не може да отвори враћа 404, а не 403. Третирајте undefined као непознато, а не као одбијено.

AppAccessMode је подешавање видљивости по ресурсу над моделом улога, а не улога. restricted наводи кориснике и групе — исте типове субјеката које користи модел улога. Погледајте Налози и приступ.

DockerfileAppSource и OciImageAppSource захтевају command. port је порт примарног сервиса: изоставите га само за издање које садржи само радни процес (config са processes и без сервиса). StaticAppSource и BundleAppSource не прихватају ниједно од та два.

React куке

@beeuni/sdk/react извози седам кука за апликације.

useProjectApps(projectId)

Апликације које позивалац сме да отвори, уз мутације њиховог животног циклуса. Свака мутација поништава кеш списка након успеха.

import { useProjectApps } from '@beeuni/sdk/react';

function AppList({ projectId }: { projectId: string }) {
  const apps = useProjectApps(projectId);
  if (!apps.data) return null;

  return (
    <ul>
      {apps.data.map((app) => (
        <li key={app.app_id}>
          <a href={app.url}>{app.slug}</a>
          <button onClick={() => apps.stop.mutate(app.app_id)}>Stop</button>
        </li>
      ))}
    </ul>
  );
}

Враћа поља упита уз create, update, start, stop и remove.

useAppDeployments(projectId, appId)

Непроменљива историја постављања, која се поново преузима сваких 5 s, тако да се приказ изградње која је у току сам ажурира.

const deployments = useAppDeployments(projectId, appId);

await deployments.deploy.mutateAsync({
  artifact_id: artifact.artifact_id,
  source: { kind: 'static', spa: true },
});
await deployments.rollback.mutateAsync(previousDeploymentId);

Обе мутације поништавају кеш списка постављања и списка апликација.

useAppDeployment(projectId, appId, deploymentId)

Једно постављање и његови догађаји, укључујући дневник изградње (AppDeploymentDetail). Проверава сваких 2 s док постављање не буде ready, failed или cancelled. Проследите null као deploymentId да остане неактивно.

const detail = useAppDeployment(projectId, appId, deploymentId);
const log = (detail.data?.events ?? [])
  .map((event) => (event.type === 'build_log' ? event.message : `[${event.type}] ${event.message}`))
  .join('\n');

Једна израда задржава првих 2.500 и последњих 2.500 редова. Редови се уписују у пакетима, најкасније 1 s након њиховог исписивања. Неуспешно или отказано постављање задржава евиденцију израде 14 дана.

useAppAccess(projectId, appId, options?)

Политика приступа и краткотрајна сесија приступа. Оба дела су засебни упити, а сваки од њих је опционалан.

const access = useAppAccess(projectId, appId, {
  policy: canEditAccess,
  session: app.viewer_can_access,
});

access.policy.data;  // AppAccessConfig
access.session.data; // { url, expires_at }
await access.update.mutateAsync({ mode: 'project' });
Опција Подразумевано Користите false када
policy true Површина само приказује App. GET …/access је административно читање и враћа 403 за позиваоца без дозвола менаџера пројекта.
session true Позивалац не сме да отвори App. Проследите app.viewer_can_access (увек true за наведени App).

Мрежа Apps која оставља обе опције на true покреће једно читање политике и једно креирање сесије по App-у, а сваки од њих је 403 за члана који не сме да отвори тај App.

useAppMachines(projectId, appId)

Машине једног App-а, које се проверавају сваких 5 s, плус start, stop, restart, destroy (сваки захтева machineId) и scale (захтева { [group]: count }). Свака мутација освежава машине и инвентар App-а. appMachinesKey(projectId, appId) је кључ упита.

const machines = useAppMachines(projectId, app.app_id);
await machines.scale.mutateAsync({ worker: 2 });
await machines.restart.mutateAsync(machineId);

useAppVolumes(projectId, appId)

Волумени једног App-а, плус snapshot (volumeId), restore ({ volumeId, snapshotId }), fork ({ volumeId, name, snapshotId? }), extend ({ volumeId, sizeGb }) и destroy ({ volumeId, name }). Свака мутација освежава волумене. appVolumesKey(projectId, appId) је кључ упита.

const volumes = useAppVolumes(projectId, app.app_id);
await volumes.snapshot.mutateAsync(volumeId);
await volumes.restore.mutateAsync({ volumeId, snapshotId });

useAppVolumeSnapshots(projectId, appId, volumeId)

Снимци једног волумена. Проследите null као volumeId да би остао неактиван.

Грешке

import { featureDisabledKey, isFeatureDisabledError } from '@beeuni/sdk';

try {
  await beeuni.project(projectId).apps.list();
} catch (error) {
  if (isFeatureDisabledError(error)) {
    console.log(`${featureDisabledKey(error)} is off for this project`);
  }
}

Остале одговоре које треба да обрадите:

  • 409 за дупликат slug-а, 402 са app_quota_exceeded када је налог достигао ограничење броја Apps, и 400 са app_machine_out_of_range за спецификацију изван њених граница.
  • 400 app_not_found (slugs) за непознат slug у uses.
  • 409 app_capability_unsupported (capability) за позив који App не нуди.
  • Постављање: 400 app_config_invalid (issues), 400 app_volumes_unsupported. Враћање: 409 release_not_ready.
  • Машине и exec: 409 app_no_machines, 404 machine_not_found, 409 machine_not_running, 400 process_group_unknown, 400 scale_out_of_range, 400 command_required.
  • Волумени: 400 volume_name_invalid, volume_size_invalid, volume_shrink_refused, volume_retention_invalid, snapshot_invalid, confirmation_required; 404 volume_not_found; 409 volume_attached.

token() одговара са Cache-Control: no-store.

Да ли вам је ова страница помогла?