Апликације
Креирајте, постављајте и контролишите 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: BearerBeeuni API-ју —createAppViewerBeeuni(request)ради управо то. Направите једног клијента по захтеву; не чувајте токен. - После промене смерница приступа, стари токени престају да раде. Следећи
захтев кроз гејт садржи нови. У прегледачу,
beeuniAppViewerToken()се сам опоравља: када API одбије његов токен, SDK поново чита/_beeuni/viewerи једном понавља позив. - Улога прегледача је горња граница. Токен може да уради тачно оно што
прегледач може у Beeuni-ју, никада више. На пројекту са дозволама агената,
memberтреба да има одобрење за агента који ваша App покреће: без његаPOST /projects/:id/sessionsодговара са403 no_agent_access. Одобрите прегледачима агента, а не ширу улогу. - Ко има прегледач. Особа која отвори App својом Beeuni пријавом — или
приступним линком, који је пријављује као ту особу — има један. App
passwordнема ниједан: лозинка доказује дељену тајну, а не особу. Apppublicима један само за посетиоца који је стигао преко приступног линка; голи 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.