@roxyon/api-client 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.ts","../src/billing.ts","../src/constants.ts","../src/query.ts","../src/client.ts","../src/databases.ts","../src/domains.ts","../src/email.ts","../src/sites.ts","../src/ssh.ts","../src/subscriptions.ts","../src/tokens.ts","../src/baas-data.ts","../src/env.ts","../src/runtimes.ts"],"sourcesContent":["import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.js';\nimport { BillingApi } from './billing.js';\nimport { RoxyonClient, type RoxyonClientOptions } from './client.js';\nimport { DatabasesApi } from './databases.js';\nimport { DomainsApi } from './domains.js';\nimport { EmailApi } from './email.js';\nimport { SitesApi } from './sites.js';\nimport { SshApi } from './ssh.js';\nimport { SubscriptionsApi } from './subscriptions.js';\nimport { TokensApi } from './tokens.js';\n\nexport { RoxyonClient } from './client.js';\nexport type { RoxyonClientOptions, RequestOptions } from './client.js';\nexport { AuthApi } from './auth.js';\nexport type { RoxyonUser, LoginResult, LoginPrecheck, SessionGrant } from './auth.js';\nexport { ApplicationsApi } from './applications.js';\nexport type {\n Application,\n ApplicationProcess,\n ApplicationRoute,\n CreateApplicationInput,\n CreateOnDeploy,\n DeployResult,\n} from './applications.js';\nexport { SitesApi } from './sites.js';\nexport type {\n DeployOptions,\n SiteFile,\n SiteFileContent,\n StaticDeployResult,\n} from './sites.js';\nexport { DomainsApi } from './domains.js';\nexport type { CreateDomainInput, CreateDomainResult, Domain } from './domains.js';\nexport { DatabasesApi } from './databases.js';\nexport type {\n CreateDatabaseInput,\n CreateDatabaseResult,\n DatabaseSummary,\n DeleteDatabaseResult,\n} from './databases.js';\nexport { EmailApi } from './email.js';\nexport type {\n CreateEmailInput,\n CreateEmailResult,\n EmailSummary,\n DeleteEmailResult,\n} from './email.js';\nexport { SshApi } from './ssh.js';\nexport type { ResetSshPasswordInput, ResetSshPasswordResult } from './ssh.js';\nexport { SubscriptionsApi } from './subscriptions.js';\nexport type { Subscription, Privilege } from './subscriptions.js';\nexport { BillingApi, BILLING_CYCLES, PAYABLE_STATUSES, isPayable } from './billing.js';\nexport type {\n BillingCycle,\n BillingSubscription,\n CatalogProduct,\n Invoice,\n OrderBudget,\n OrderInput,\n OrderResult,\n Quote,\n QuoteInput,\n} from './billing.js';\nexport { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.js';\nexport {\n BaasDataApi,\n BAAS_MAX_BATCH,\n BAAS_MAX_PAGE,\n DEFAULT_BAAS_V2_URL,\n} from './baas-data.js';\nexport type {\n BaasBatchRequest,\n BaasBatchResult,\n BaasDataOptions,\n BaasQuery,\n BaasRow,\n} from './baas-data.js';\nexport { TokensApi } from './tokens.js';\nexport type { TokenScope, TokenSummary, CreatedToken } from './tokens.js';\nexport { RoxyonApiError, rxError, isAuthError, assertOk } from './errors.js';\nexport { parseEnv, formatEnv, envFromStored } from './env.js';\nexport { RUNTIMES, LUMEN_BUILD } from './runtimes.js';\nexport type { RuntimeName, RuntimeSpec, DeployKind } from './runtimes.js';\nexport { toQueryString } from './query.js';\nexport { DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, DEFAULT_APP } from './constants.js';\n\n/**\n * Convenience facade bundling every sub-API over one {@link RoxyonClient}.\n *\n * ```ts\n * const roxyon = new Roxyon({ sessionToken }); // or a roxp_ PAT\n * const ctx = await roxyon.account.context(); // user + subs + domains\n * ```\n */\nexport class Roxyon {\n readonly client: RoxyonClient;\n readonly auth: AuthApi;\n readonly account: AccountApi;\n readonly tokens: TokensApi;\n readonly subscriptions: SubscriptionsApi;\n readonly domains: DomainsApi;\n readonly applications: ApplicationsApi;\n readonly sites: SitesApi;\n readonly databases: DatabasesApi;\n readonly email: EmailApi;\n readonly ssh: SshApi;\n readonly billing: BillingApi;\n\n constructor(options: RoxyonClientOptions | RoxyonClient = {}) {\n this.client = options instanceof RoxyonClient ? options : new RoxyonClient(options);\n this.auth = new AuthApi(this.client);\n this.account = new AccountApi(this.client);\n this.tokens = new TokensApi(this.client);\n this.subscriptions = new SubscriptionsApi(this.client);\n this.domains = new DomainsApi(this.client);\n this.applications = new ApplicationsApi(this.client);\n this.sites = new SitesApi(this.client);\n this.databases = new DatabasesApi(this.client);\n this.email = new EmailApi(this.client);\n this.ssh = new SshApi(this.client);\n this.billing = new BillingApi(this.client);\n }\n\n get sessionToken(): string | undefined {\n return this.client.getSessionToken();\n }\n}\n","/**\n * The Roxyon BaaS (\"RX\" engine) resolves failed writes rather than rejecting\n * them — a rejected promise never fires and a failure is shaped like a success\n * body with an `error` string on it (top-level, or inside `results[]`). Every\n * write must be run through {@link rxError} before it is treated as having\n * worked. This mirrors `rxError()` in `console.roxyon.com/src/index.js`.\n *\n * Known failure shapes:\n * { \"results\": [ { \"code\": 1054, \"error\": \"Unknown column ...\", \"type\": \"DBQueryError\" } ] }\n * { \"code\": 105, \"error\": \"Invalid Field Name\", \"type\": \"InvalidFieldName\" }\n */\n\nexport interface RxErrorBody {\n code?: number;\n error?: string;\n type?: string;\n results?: unknown;\n}\n\n/** Returns the error message from a BaaS response, or `''` when the call worked. */\nexport function rxError(r: unknown): string {\n if (r === null || r === undefined) return 'No response from the server.';\n if (typeof r !== 'object') return '';\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body.error;\n const rows = body.results;\n if (Array.isArray(rows)) {\n for (const row of rows) {\n if (row && typeof row === 'object' && typeof (row as RxErrorBody).error === 'string') {\n const msg = (row as RxErrorBody).error;\n if (msg) return msg;\n }\n }\n }\n return '';\n}\n\nexport class RoxyonApiError extends Error {\n readonly code?: number;\n readonly type?: string;\n readonly status?: number;\n readonly body: unknown;\n\n constructor(\n message: string,\n opts: { code?: number; type?: string; status?: number; body?: unknown } = {},\n ) {\n super(message);\n this.name = 'RoxyonApiError';\n this.code = opts.code;\n this.type = opts.type;\n this.status = opts.status;\n this.body = opts.body;\n }\n}\n\nconst AUTH_CODES = new Set([101, 141, 209, 1060, 1063, 401]);\nconst AUTH_HINTS = [\n 'invalid session',\n 'session token',\n 'unauthorized',\n 'not authorized',\n 'invalid token',\n 'expired',\n 'log in again',\n];\n\n/** True when an error looks like \"the session/token is gone\", so the caller can re-auth. */\nexport function isAuthError(err: unknown): boolean {\n if (err instanceof RoxyonApiError) {\n if (err.status === 401 || err.status === 403) return true;\n if (err.code !== undefined && AUTH_CODES.has(err.code)) return true;\n }\n const msg = (\n err instanceof Error ? err.message : typeof err === 'string' ? err : rxError(err)\n ).toLowerCase();\n return AUTH_HINTS.some((h) => msg.includes(h));\n}\n\n/** Locate the object (top-level or a `results[]` row) that carries the error. */\nfunction erroringNode(r: unknown): RxErrorBody | undefined {\n if (!r || typeof r !== 'object') return undefined;\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body;\n if (Array.isArray(body.results)) {\n for (const row of body.results) {\n if (row && typeof row === 'object' && (row as RxErrorBody).error) return row as RxErrorBody;\n }\n }\n return undefined;\n}\n\n/** Throw a {@link RoxyonApiError} if `r` carries a BaaS error; otherwise return it typed. */\nexport function assertOk<T>(r: T): T {\n const msg = rxError(r);\n if (msg) {\n const node = erroringNode(r);\n throw new RoxyonApiError(msg, { code: node?.code, type: node?.type, body: r });\n }\n return r;\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\nimport type { TokenScope } from './tokens.js';\n\nexport interface AccountSubscription {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AccountDomain {\n id: string;\n name: string;\n subscription: string;\n /** `active`, or `provisioning` while a freshly-added host comes up. */\n status?: string;\n}\n\nexport interface AccountContext {\n user: { id: string; email: string };\n scopes: (TokenScope | '*')[];\n subscriptions: AccountSubscription[];\n domains: AccountDomain[];\n}\n\nexport interface AccountApp {\n id: string;\n name: string;\n status: string;\n desiredState: string;\n runtime: string;\n configRevision: number;\n appliedRevision: number;\n lastError: string | null;\n repo: { url: string; branch: string } | null;\n}\n\n/**\n * `GET /account/context` — one call the CLI / MCP server use to plan a deploy:\n * the signed-in user, their subscriptions, and their domains. Resolvable by a\n * session token OR a Personal Access Token, so a CI job with only a PAT never\n * has to touch the BaaS. Infra details (nodes, datacenters, container names,\n * filesystem paths) are deliberately not surfaced here.\n */\nexport class AccountApi {\n private cache?: Promise<AccountContext>;\n\n constructor(private readonly client: RoxyonClient) {}\n\n context(opts: { fresh?: boolean } = {}): Promise<AccountContext> {\n if (!this.cache || opts.fresh) this.cache = this.fetch();\n return this.cache;\n }\n\n private async fetch(): Promise<AccountContext> {\n const r = await this.client.console<AccountContext & { ok?: boolean; error?: string }>(\n 'GET',\n '/account/context',\n { tolerateHttpError: true },\n );\n if (!r?.ok || !r.user?.id) {\n throw new RoxyonApiError(r?.error || 'Could not load the account context.', { body: r });\n }\n // Map explicitly — the endpoint may carry infra fields (node/datacenter/\n // container); keep only what a deploy actually needs so they never reach\n // an AI assistant's context or a log.\n return {\n user: { id: r.user.id, email: r.user.email },\n scopes: r.scopes ?? [],\n subscriptions: (r.subscriptions ?? []).map((s) => ({\n id: s.id,\n name: s.name,\n status: s.status,\n })),\n domains: (r.domains ?? []).map((d) => ({\n id: d.id,\n name: d.name,\n subscription: d.subscription,\n ...(d.status ? { status: d.status } : {}),\n })),\n };\n }\n\n /** `GET /account/apps` — the account's applications (list, PAT-safe). */\n async apps(): Promise<AccountApp[]> {\n const r = await this.client.console<{\n ok?: boolean;\n applications?: AccountApp[];\n error?: string;\n }>('GET', '/account/apps', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list applications.', { body: r });\n return (r.applications ?? []).map((a) => ({\n id: a.id,\n name: a.name,\n status: a.status,\n desiredState: a.desiredState,\n runtime: a.runtime,\n configRevision: a.configRevision,\n appliedRevision: a.appliedRevision,\n lastError: a.lastError,\n repo: a.repo,\n }));\n }\n\n /** One application by id, PAT-safe (filters {@link apps}). */\n async getApp(id: string): Promise<AccountApp | undefined> {\n return (await this.apps()).find((a) => a.id === id);\n }\n\n /** Pick the subscription to deploy against — the preferred one, else the only/first. */\n async resolveSubscription(preferred?: string): Promise<AccountSubscription> {\n const { subscriptions } = await this.context();\n if (subscriptions.length === 0) {\n throw new RoxyonApiError('This account has no subscriptions.');\n }\n if (preferred) {\n const hit = subscriptions.find((s) => s.id === preferred || s.name === preferred);\n if (hit) return hit;\n }\n return subscriptions[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError, assertOk } from './errors.js';\n\nexport interface Application {\n objectId: string;\n Name: string;\n Status?: string;\n DesiredState?: string;\n SourcePath?: string;\n Runtime?: string;\n RuntimeVersion?: string;\n Preset?: string;\n ConfigRevision?: number;\n AppliedRevision?: number;\n LastError?: string;\n Env?: string;\n RepoUrl?: string;\n Subscription?: string;\n [k: string]: unknown;\n}\n\nexport interface ApplicationProcess {\n objectId: string;\n Application?: string;\n Type?: string;\n Command?: string;\n Status?: string;\n Port?: number;\n}\n\nexport interface ApplicationRoute {\n objectId: string;\n Application?: string;\n Domain?: string;\n Path?: string;\n Enabled?: number | string;\n}\n\ninterface Results<T> {\n results?: T[];\n error?: string;\n}\n\nexport interface DeployResult {\n ok: boolean;\n application: string;\n created?: boolean;\n configRevision?: number;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\n/** Params for creating an application on its first deploy (no id yet). */\nexport interface CreateOnDeploy {\n host: string;\n folder?: string;\n runtime: 'node' | 'python' | 'php';\n runtimeVersion?: string;\n preset?: string;\n command?: string;\n public?: boolean;\n}\n\nexport interface CreateApplicationInput {\n subscription: string;\n name: string;\n /** Absolute source path: `/home/www/<host>/public_html/<folder>`. */\n sourcePath: string;\n runtime: string;\n runtimeVersion: string;\n preset: string;\n /** The web process start command. */\n command: string;\n /** Route host (`Domains.objectId`). */\n domainId: string;\n /** `.env`-style object stored as JSON on `Applications.Env`. */\n env?: Record<string, string>;\n /** Make the app public (route serves the app instead of the host's files). */\n public?: boolean;\n}\n\n/**\n * The Roxyon Applications system. Deployment is declarative: rows describe the\n * desired state and every meaningful change bumps `ConfigRevision`; a\n * server-side reconciler builds the source in an isolated release dir and\n * (re)starts a systemd unit, writing back `Status` / `AppliedRevision` /\n * `LastError`. Mirrors `applications.view` + `modals/app_form.view`.\n */\nexport class ApplicationsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Application[]> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n async get(id: string): Promise<Application | undefined> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: 1,\n where: { objectId: id },\n });\n return r.results?.[0];\n }\n\n /** Create the application + its web process + a route, matching `createNew()`. */\n async create(\n input: CreateApplicationInput,\n ): Promise<{ application: string; process: string; route: string }> {\n const appRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/Applications', {\n Subscription: input.subscription,\n Name: input.name,\n Preset: input.preset,\n SourcePath: input.sourcePath,\n Runtime: input.runtime,\n RuntimeVersion: input.runtimeVersion,\n Env: JSON.stringify(input.env ?? {}),\n Status: 'pending',\n DesiredState: 'running',\n ConfigRevision: 1,\n AppliedRevision: 0,\n LastError: '',\n }),\n );\n const appId = appRes.results?.[0]?.objectId;\n if (!appId) throw new RoxyonApiError('No application id returned.', { body: appRes });\n\n const procRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationProcesses', {\n Application: appId,\n Type: 'web',\n Port: 0, // allocated by the backend at deploy time\n Command: input.command,\n Status: 'pending',\n }),\n );\n const procId = procRes.results?.[0]?.objectId ?? '';\n\n const routeRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationRoutes', {\n Application: appId,\n Domain: input.domainId,\n Path: '/',\n Enabled: input.public ? 1 : 0,\n }),\n );\n const routeId = routeRes.results?.[0]?.objectId ?? '';\n\n return { application: appId, process: procId, route: routeId };\n }\n\n // ---- console endpoints (session token or PAT) ----\n\n /** Read an application's environment. `GET /applications/env`. */\n async getEnv(applicationId: string): Promise<Record<string, string>> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n error?: string;\n }>('GET', '/applications/env', {\n query: { application: applicationId },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not read the environment.', { body: r });\n return r.env ?? {};\n }\n\n /**\n * Merge `set` and delete `remove`, bumping `ConfigRevision`. `PORT`/`HOST` are\n * ignored (platform-managed). `POST /applications/env`. Returns the new env.\n */\n async setEnv(\n applicationId: string,\n changes: { set?: Record<string, string>; remove?: string[] },\n ): Promise<{ env: Record<string, string>; changed: string[]; configRevision: number }> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n changed?: string[];\n configRevision?: number;\n error?: string;\n }>('POST', '/applications/env', {\n query: { application: applicationId },\n body: { set: changes.set ?? {}, remove: changes.remove ?? [] },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not update the environment.', { body: r });\n return { env: r.env ?? {}, changed: r.changed ?? [], configRevision: r.configRevision ?? 0 };\n }\n\n /** Rebuild from the latest source and restart. `POST /applications/action`. */\n async deploy(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'deploy' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /** Bounce the process only — no rebuild. `POST /applications/action`. */\n async restart(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'restart' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /**\n * Tail the app's journal. `POST /applications/logs` returns one block per\n * process (`{ type, unit, output }`); this flattens them to lines, each\n * prefixed with the process type when there is more than one.\n */\n async logs(applicationId: string, lines = 100): Promise<string[]> {\n const r = await this.client.console<{\n processes?: Array<{ type?: string; unit?: string; output?: string }>;\n error?: string;\n }>('POST', '/applications/logs', {\n body: { application: applicationId, lines },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n const procs = r?.processes ?? [];\n const multi = procs.length > 1;\n const out: string[] = [];\n for (const p of procs) {\n const body = (p.output ?? '').split('\\n').filter(Boolean);\n for (const line of body) out.push(multi ? `[${p.type ?? 'web'}] ${line}` : line);\n }\n return out;\n }\n\n /** Connect a git remote for push-to-deploy. `POST /applications/repo/connect`. */\n async repoConnect(\n applicationId: string,\n repoUrl: string,\n branch = 'main',\n ): Promise<{\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n }> {\n const r = await this.client.console<{\n error?: string;\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n branch?: string;\n }>('POST', '/applications/repo/connect', {\n body: { application: applicationId, repoUrl, branch },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n return r;\n }\n\n /**\n * Upload a gzipped tarball of the project source. The endpoint lands it in the\n * application's `SourcePath` and bumps `ConfigRevision` (the reconciler then\n * builds it in a release dir exactly as for a git deploy).\n *\n * `POST /applications/deploy` — NEW endpoint (see `backend/` in this repo).\n */\n async uploadSource(target: string | CreateOnDeploy, tarball: Uint8Array): Promise<DeployResult> {\n const query: Record<string, string> =\n typeof target === 'string'\n ? { application: target }\n : {\n host: target.host,\n folder: target.folder ?? '',\n runtime: target.runtime,\n ...(target.runtimeVersion ? { runtimeVersion: target.runtimeVersion } : {}),\n ...(target.preset ? { preset: target.preset } : {}),\n ...(target.command ? { command: target.command } : {}),\n public: target.public === false ? '0' : '1',\n };\n const r = await this.client.console<DeployResult>('POST', '/applications/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Upload failed.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface SessionGrant {\n session_token: string;\n refresh_token?: string;\n expires_in?: number;\n status?: string;\n}\n\nexport interface RoxyonUser {\n objectId: string;\n Email?: string;\n Username?: string;\n Name?: string;\n Currency?: string;\n Language?: string;\n [k: string]: unknown;\n}\n\nexport interface LoginPrecheck {\n ok?: boolean;\n error?: string;\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\nexport interface LoginResult {\n sessionToken: string;\n refreshToken?: string;\n expiresIn?: number;\n /** True when an OTP code is still required — call {@link AuthApi.verifyOtp}. */\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\n/**\n * Wraps the console's login flow:\n * 1. `POST /_account/login-precheck` — validates credentials, decides whether\n * an OTP step-up is required, and (when it is) returns a `challengeId`.\n * 2a. no step-up -> `POST /Auth/login` finalises and returns a session token.\n * 2b. step-up -> caller collects the code, then `POST /Auth/login/otp-verify`.\n *\n * Mirrors `signin.view` / `otp.view` in `console.roxyon.com`.\n */\nexport class AuthApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /**\n * Best-effort device/step-up precheck. `/_account/login-precheck` is a console\n * cloud function that may be gated behind the REST key (not reachable from a\n * public client) — in that case this resolves to `{}` and login falls back to\n * `/Auth/login`, which is itself the security boundary and re-checks the\n * device. Only a definitive `{ ok: false }` / `stepUpRequired` is acted on.\n */\n async precheck(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginPrecheck> {\n try {\n const r = await this.client.post<LoginPrecheck & { code?: number }>(\n '/_account/login-precheck',\n { Email: email, Password: password, metadata },\n { tolerateHttpError: true },\n );\n // Endpoint not available to this client — ignore, let /Auth/login decide.\n if (r?.code === 401 || (r?.error && /rest api key/i.test(r.error))) return {};\n return r ?? {};\n } catch {\n return {};\n }\n }\n\n /**\n * Full login. Returns a session token on success, or `stepUpRequired` with a\n * `challengeId` when an OTP code is needed next.\n */\n async login(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginResult> {\n const pre = await this.precheck(email, password, metadata);\n if (pre.ok === false && pre.error && !pre.stepUpRequired) {\n throw new RoxyonApiError(pre.error, { type: 'CredentialsError' });\n }\n if (pre.stepUpRequired) {\n return { sessionToken: '', stepUpRequired: true, challengeId: pre.challengeId };\n }\n\n const grant = await this.client.post<\n SessionGrant & { error?: string; stepUpRequired?: boolean; challengeId?: string }\n >('/Auth/login', { Email: email, Password: password, metadata }, { tolerateHttpError: true });\n\n // Some accounts step up at /Auth/login itself rather than at precheck.\n if (grant?.stepUpRequired || (grant?.challengeId && !grant.session_token)) {\n return { sessionToken: '', stepUpRequired: true, challengeId: grant.challengeId };\n }\n if (!grant?.session_token) {\n throw new RoxyonApiError(grant?.error || 'Wrong email or password.', {\n type: 'CredentialsError',\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Complete an OTP step-up with the code the user received. */\n async verifyOtp(challengeId: string, code: string): Promise<LoginResult> {\n const grant = await this.client.post<SessionGrant & { error?: string }>(\n '/Auth/login/otp-verify',\n { challengeId, code },\n { tolerateHttpError: true },\n );\n if (grant?.status !== 'authenticated' || !grant.session_token) {\n throw new RoxyonApiError(grant?.error || 'That code did not verify.', {\n type: 'OtpError',\n body: grant,\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Start an OTP-only sign-in (no password). Returns a `challengeId`. */\n async startOtp(email: string): Promise<{ challengeId: string }> {\n const r = await this.client.post<{ challengeId?: string; error?: string }>(\n '/Auth/login/otp',\n { Email: email },\n { tolerateHttpError: true },\n );\n if (!r?.challengeId) {\n throw new RoxyonApiError(r?.error || 'Could not start OTP sign-in.', { body: r });\n }\n return { challengeId: r.challengeId };\n }\n\n /** The currently authenticated user. Requires a session token on the client. */\n async me(): Promise<RoxyonUser> {\n const user = await this.client.post<RoxyonUser & { error?: string }>('/Auth/me', {});\n if (!user?.objectId) {\n throw new RoxyonApiError(user?.error || 'Not signed in.', { status: 401, body: user });\n }\n return user;\n }\n\n async logout(): Promise<void> {\n await this.client.post('/Auth/logout', {}, { tolerateHttpError: true }).catch(() => undefined);\n this.client.setSessionToken(undefined);\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** Billing cycles the checkout accepts (Pricing::CYCLE_MONTHS). */\nexport const BILLING_CYCLES = ['monthly', 'quarterly', 'yearly', 'biennial'] as const;\nexport type BillingCycle = (typeof BILLING_CYCLES)[number];\n\n// Plans of this service are resellers' private resold copies, never the public catalog\n// (same filter as the console's own bootstrap).\nconst RESELLER_RESOLD_SERVICE_ID = 'bjMqdLqAKl';\n\nexport interface CatalogProduct {\n /** Plan objectId: what quotes and orders take. */\n planId: string;\n /** Plan code, e.g. `SCALE-S`. */\n sku: string;\n name: string;\n /** Service type, e.g. `cloud.vps.scale`, `cloud.hosting.solo`. */\n category: string;\n vcpu?: number;\n ramGb?: number;\n diskGb?: number;\n cpuType?: string;\n /** Dedicated IPv4 addresses included (servers). */\n ipv4Included?: number;\n /** List prices in USD before tax, per cycle. Quote for the buyer's currency and tax. */\n pricesUSD: Partial<Record<BillingCycle, number>>;\n /** Setup fee in USD per cycle, when not zero. */\n setupFeeUSD?: Partial<Record<BillingCycle, number>>;\n /** `out` = cannot be ordered right now. */\n stock: 'in' | 'out';\n /** Feature table as the console shows it. */\n features?: Record<string, unknown>;\n}\n\nexport interface QuoteInput {\n planId: string;\n cycle: BillingCycle;\n /** ISO 4217, e.g. `SAR`. Default USD. */\n currency?: string;\n /** ISO 3166 alpha-2, decides tax (e.g. `SA` = 15% VAT). Empty = no tax line. */\n country?: string;\n}\n\nexport interface Quote {\n planId: string;\n cycle: string;\n currency: string;\n lineItems: Array<{ label: string; amount: string; amountUSD: string }>;\n subtotal: string;\n taxRate: string;\n taxLabel: string;\n taxAmount: string;\n discountAmount: string;\n total: string;\n fxRate: string;\n baseAmountUSD: string;\n}\n\nexport interface OrderInput {\n /** Plan code from the catalog, e.g. `SCALE-S`. */\n sku: string;\n cycle: BillingCycle;\n /** A name for the service. */\n name: string;\n /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */\n username: string;\n /** Servers only: OS image, e.g. `ubuntu-24.04`. */\n image?: string;\n sshKey?: string;\n phpVersion?: string;\n datacenter?: string;\n currency?: string;\n country?: string;\n /** false/absent = dry run (quote + budget check, nothing written). */\n confirm?: boolean;\n}\n\nexport interface OrderBudget {\n monthlyUSD: number;\n spentUSD: number;\n remainingUSD: number;\n}\n\nexport interface OrderResult {\n dryRun?: boolean;\n plan: { id: string; sku: string; name: string; kind: 'hosting' | 'server'; cycle: string };\n /** Dry run: the server quote (same shape as GET /_payment/quote). */\n quote?: Record<string, unknown>;\n subscriptionId?: string;\n invoiceId?: string;\n total?: string;\n currency?: string;\n payUrl?: string;\n /** null for a console session (no token budget). */\n budget: OrderBudget | null;\n}\n\nexport interface BillingSubscription {\n id: string;\n name: string;\n status: string;\n plan: string;\n sku: string;\n cycle: string;\n price: string;\n currency: string;\n nextBillingDate: string | null;\n autoRenew: boolean;\n serverState: string | null;\n publicIp: string | null;\n}\n\nexport interface Invoice {\n id: string;\n number: string;\n type: string;\n status: string;\n total: string;\n currency: string;\n dueDate: string | null;\n subscription: string | null;\n createdAt: string;\n payUrl: string | null;\n}\n\n/** Invoice statuses a customer can still pay. */\nexport const PAYABLE_STATUSES = ['pending', 'overdue', 'failed'] as const;\n\nexport function isPayable(status: string): boolean {\n return (PAYABLE_STATUSES as readonly string[]).includes(status.toLowerCase());\n}\n\nfunction json<T>(v: unknown, fallback: T): T {\n if (v && typeof v === 'object') return v as T;\n if (typeof v !== 'string' || v === '') return fallback;\n try {\n return JSON.parse(v) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction numbers(v: unknown): Partial<Record<BillingCycle, number>> {\n const out: Partial<Record<BillingCycle, number>> = {};\n const src = json<Record<string, unknown>>(v, {});\n for (const c of BILLING_CYCLES) {\n const n = Number(src[c]);\n if (src[c] !== undefined && src[c] !== '' && Number.isFinite(n)) out[c] = n;\n }\n return out;\n}\n\ninterface PlanRow {\n objectId: string;\n Name?: string;\n Code?: string;\n Limits?: unknown;\n Features?: unknown;\n _Service?: { results?: Array<{ Type?: string }> };\n _Pricing?: {\n results?: Array<{\n Prices?: unknown;\n SetupFee?: unknown;\n MetaData?: unknown;\n IsActive?: unknown;\n }>;\n };\n}\n\n/**\n * Catalog + quotes (public, no sign-in) and the caller's own subscriptions + invoices\n * (console, session or PAT). Read-only: nothing here creates orders or invoices.\n */\nexport class BillingApi {\n constructor(\n private readonly client: RoxyonClient,\n private readonly pub: RoxyonClient = client.publicClient(),\n ) {}\n\n async catalog(): Promise<CatalogProduct[]> {\n const r = await this.pub.get<{ results?: PlanRow[]; error?: string }>('/Plans', {\n fields: '*',\n limit: -1,\n order: 'objectId',\n where: { Status: 'active', Service: { nin: RESELLER_RESOLD_SERVICE_ID } },\n include: [\n { className: 'Services', field: 'Service', fields: 'Type' },\n {\n className: 'Pricing',\n field: 'Plan',\n fields: 'Prices,SetupFee,MetaData,IsActive',\n reverse: 1,\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load the catalog.', { body: r });\n }\n const out: CatalogProduct[] = [];\n for (const p of r.results) {\n const pricing = p._Pricing?.results?.[0];\n // Same rule as roxyon.com's pricing page: a plan code, an active Pricing row, a monthly price.\n if (!p.Code || !pricing || Number(pricing.IsActive) === 0) continue;\n const limits = json<Record<string, unknown>>(p.Limits, {});\n const features = json<Record<string, unknown>>(p.Features, {});\n const meta = json<Record<string, unknown>>(pricing.MetaData, {});\n const network = json<Record<string, unknown>>(features.Network, {});\n const setup = numbers(pricing.SetupFee);\n const pricesUSD = numbers(pricing.Prices);\n if (pricesUSD.monthly === undefined) continue;\n const product: CatalogProduct = {\n planId: p.objectId,\n sku: p.Code ?? '',\n name: p.Name ?? '',\n category: p._Service?.results?.[0]?.Type ?? '',\n pricesUSD,\n stock: String(meta.stock ?? 'in').toLowerCase() === 'out' ? 'out' : 'in',\n };\n if (limits.vcpu != null) {\n product.vcpu = Number(limits.vcpu);\n product.ramGb = limits.memory_mb ? Math.round(Number(limits.memory_mb) / 1024) : 0;\n product.diskGb = Number(limits.disk_gb ?? 0);\n product.cpuType = String(limits.cpu_type ?? '');\n }\n if (network['Dedicated IPv4'] != null)\n product.ipv4Included = Number(network['Dedicated IPv4']);\n if (Object.values(setup).some((n) => n > 0)) product.setupFeeUSD = setup;\n if (Object.keys(features).length) product.features = features;\n out.push(product);\n }\n return out;\n }\n\n /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */\n async quote(input: QuoteInput): Promise<Quote> {\n if (!/^[A-Za-z0-9]{1,40}$/.test(input.planId))\n throw new Error(`Invalid planId \"${input.planId}\".`);\n if (!BILLING_CYCLES.includes(input.cycle))\n throw new Error(`Unsupported cycle \"${input.cycle}\".`);\n const q: Record<string, string | number> = {\n type: 'subscription.new',\n planId: input.planId,\n cycle: input.cycle,\n setup: 1,\n };\n if (input.currency) q.currency = input.currency.toUpperCase();\n if (input.country) q.country = input.country.toUpperCase();\n const r = await this.pub.get<\n Partial<Quote> & { ok?: boolean; error?: string; baseAmount?: string }\n >('/_payment/quote', q);\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not price this plan.', { body: r });\n return {\n planId: String(r.planId ?? input.planId),\n cycle: String(r.cycle ?? input.cycle),\n currency: String(r.currency ?? ''),\n lineItems: (r.lineItems ?? []).map((l) => ({\n label: l.label,\n amount: l.amount,\n amountUSD: l.amountUSD,\n })),\n subtotal: String(r.subtotal ?? ''),\n taxRate: String(r.taxRate ?? ''),\n taxLabel: String(r.taxLabel ?? ''),\n taxAmount: String(r.taxAmount ?? ''),\n discountAmount: String(r.discountAmount ?? ''),\n total: String(r.total ?? ''),\n fxRate: String(r.fxRate ?? ''),\n baseAmountUSD: String(r.baseAmount ?? ''),\n };\n }\n\n /**\n * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it\n * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the\n * `billing:order` scope, within that token's monthly budget and allowed SKUs.\n */\n async order(input: OrderInput): Promise<OrderResult> {\n const r = await this.client.console<\n Partial<OrderResult> & { ok?: boolean; error?: string; budget?: OrderBudget }\n >('POST', '/account/order', { body: input, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'The order was not placed.', { body: r });\n return r as OrderResult;\n }\n\n /** The caller's own subscriptions (rows they own), newest first. */\n async subscriptions(): Promise<BillingSubscription[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n subscriptions?: BillingSubscription[];\n }>('GET', '/account/subscriptions', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load subscriptions.', { body: r });\n return r.subscriptions ?? [];\n }\n\n /** The caller's own invoices, newest first. */\n async invoices(opts: { status?: string; limit?: number } = {}): Promise<Invoice[]> {\n const q: Record<string, string> = {};\n if (opts.status) q.status = opts.status;\n if (opts.limit) q.limit = String(opts.limit);\n const r = await this.client.console<{ ok?: boolean; error?: string; invoices?: Invoice[] }>(\n 'GET',\n '/account/invoices',\n { tolerateHttpError: true, query: q },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load invoices.', { body: r });\n // Only an open invoice can be paid (the first console release also linked void ones).\n return (r.invoices ?? []).map((i) => ({ ...i, payUrl: isPayable(i.status) ? i.payUrl : null }));\n }\n}\n","/**\n * Default endpoints and the public application credentials the client uses to\n * mint an anonymous token before a user logs in.\n *\n * `X-BEA-JavaScript-Key` is a **public** key (it ships in browser bundles by\n * design — see `console.roxyon.com/src/index.js`). It is safe to embed here.\n * The REST key is never embedded — user actions always run under a session\n * token or a Personal Access Token.\n *\n * TODO(M1): provision a dedicated `roxyon-cli` BaaS application and swap these\n * for its App-ID / JavaScript-Key so CLI traffic is attributable and rate-limited\n * separately from the web console. Until then the client reuses the console's\n * public pair, which is already exposed in shipped frontend code.\n */\nexport const DEFAULT_BAAS_URL = 'https://www.beaapis.com/1';\nexport const DEFAULT_CONSOLE_URL = 'https://console.roxyon.com';\n\nexport const DEFAULT_APP = {\n appId: 'jAtp2zHGU3FbnrQWrToALFakd_vbiY0ywihn4Hj54lw',\n javascriptKey: 'w2Y9USRg0COtNe-fUqOaC1OOOlNCnV2BG8GZF80w4x8',\n} as const;\n\n/** Header names, lower-cased (the API is case-insensitive but the SDK uses these). */\nexport const H = {\n appId: 'x-bea-application-id',\n jsKey: 'x-bea-javascript-key',\n restKey: 'x-bea-authorization',\n sessionToken: 'x-bea-session-token',\n accessToken: 'x-bea-access-token',\n refreshToken: 'x-bea-refresh-token',\n} as const;\n","/**\n * GET query serialisation for the BaaS, matching the `Obj2Par` helper in the\n * browser SDK (`rx.js`): nested objects become PHP-style bracket keys\n * (`where[User]=abc`, `where[Status][in]=a,b,c`).\n *\n * Two hard-won rules (see the `roxyon-api-write-failures` notes):\n * - The `in` operator takes a **comma-joined string, not an array**. An array\n * serialises to `where[X][in][0]=…` bracket notation the API does not read.\n * Pass `{ in: ['a', 'b'] }` here and we join it for you.\n * - A `select` subquery nested inside an `or` group crashes the API. Resolve\n * ids in a first query, then `or: [..., { objectId: { in: 'a,b' } }]`.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | { [k: string]: QueryValue };\n\nexport type QueryObject = Record<string, QueryValue>;\n\nfunction encode(k: string, v: string): string {\n return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;\n}\n\nfunction walk(value: QueryValue, prefix: string, out: string[]): void {\n if (value === null || value === undefined) return;\n\n if (Array.isArray(value)) {\n // A bare array under a normal key -> repeated bracket-index entries. The\n // only array we actually want is `in`, and that is handled below before we\n // ever get here, so this branch is a best-effort fallback.\n value.forEach((item, i) => walk(item, `${prefix}[${i}]`, out));\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n if (key === 'in' || key === 'nin' || key === 'notIn') {\n const joined = Array.isArray(child) ? child.join(',') : String(child);\n out.push(encode(`${prefix}[${key === 'notIn' ? 'nin' : key}]`, joined));\n continue;\n }\n walk(child, `${prefix}[${key}]`, out);\n }\n return;\n }\n\n out.push(encode(prefix, String(value)));\n}\n\n/** Serialise a query object to a `key=value&...` string (no leading `?`). */\nexport function toQueryString(query: QueryObject | undefined): string {\n if (!query) return '';\n const out: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n walk(value, key, out);\n }\n return out.join('&');\n}\n","import { DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, H } from './constants.js';\nimport { RoxyonApiError } from './errors.js';\nimport { type QueryObject, toQueryString } from './query.js';\n\nexport interface RoxyonClientOptions {\n /** BaaS application id. Defaults to the public console app. */\n appId?: string;\n /** Public JavaScript key, used to mint an anonymous token. */\n javascriptKey?: string;\n /** REST API key. Optional; grants full access — only for trusted server use. */\n restKey?: string;\n /** A user session token (from {@link AuthApi.login}). */\n sessionToken?: string;\n /** BaaS REST base, e.g. `https://www.beaapis.com/1`. */\n baseUrl?: string;\n /** Console base that serves the `/applications/*` endpoints. */\n consoleUrl?: string;\n /** Custom fetch (tests / proxies). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n query?: QueryObject;\n body?: unknown;\n headers?: Record<string, string>;\n /** Skip the Authorization/session header entirely (used for token minting). */\n skipAuth?: boolean;\n /** Send/parse the response even on a non-2xx status instead of throwing. */\n tolerateHttpError?: boolean;\n signal?: AbortSignal;\n}\n\ninterface AnonToken {\n access_token?: string;\n session_token?: string;\n refresh_token?: string;\n expires_in?: number;\n /** epoch ms this token becomes unusable */\n _expiresAt?: number;\n}\n\n/**\n * Low-level transport for the Roxyon BaaS and console app endpoints.\n *\n * Auth precedence per request: explicit `sessionToken` -> `restKey` ->\n * a lazily-minted anonymous access token (public app credentials).\n */\nexport class RoxyonClient {\n readonly baseUrl: string;\n readonly consoleUrl: string;\n private readonly appId: string;\n private readonly javascriptKey: string;\n private readonly restKey?: string;\n private readonly _fetch: typeof fetch;\n private sessionToken?: string;\n private anon?: AnonToken;\n\n constructor(opts: RoxyonClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_URL).replace(/\\/+$/, '');\n this.consoleUrl = (opts.consoleUrl ?? DEFAULT_CONSOLE_URL).replace(/\\/+$/, '');\n this.appId = opts.appId ?? DEFAULT_APP.appId;\n this.javascriptKey = opts.javascriptKey ?? DEFAULT_APP.javascriptKey;\n this.restKey = opts.restKey;\n this.sessionToken = opts.sessionToken;\n this._fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this._fetch !== 'function') {\n throw new Error('No fetch implementation available (need Node >= 20 or pass opts.fetch).');\n }\n }\n\n /** Same endpoints and app, no user credentials: for public reads (catalog, quotes)\n * that must work for PAT callers too, whose token the BaaS does not accept. */\n publicClient(): RoxyonClient {\n return new RoxyonClient({\n baseUrl: this.baseUrl,\n consoleUrl: this.consoleUrl,\n appId: this.appId,\n javascriptKey: this.javascriptKey,\n fetch: this._fetch,\n });\n }\n\n getSessionToken(): string | undefined {\n return this.sessionToken;\n }\n\n setSessionToken(token: string | undefined): void {\n this.sessionToken = token;\n }\n\n /** Mint (or reuse) an anonymous access token from the public app credentials. */\n private async anonToken(): Promise<AnonToken> {\n if (this.anon?._expiresAt && this.anon._expiresAt > Date.now() + 5_000) {\n return this.anon;\n }\n const res = await this._fetch(`${this.baseUrl}/Auth`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n [H.appId]: this.appId,\n [H.jsKey]: this.javascriptKey,\n },\n body: JSON.stringify({ scope: 'public' }),\n });\n const json = (await res.json().catch(() => ({}))) as AnonToken;\n if (!json.access_token && !json.session_token) {\n throw new RoxyonApiError('Could not obtain an anonymous BaaS token.', {\n status: res.status,\n body: json,\n });\n }\n json._expiresAt = Date.now() + (json.expires_in ? json.expires_in * 1000 : 3_600_000);\n this.anon = json;\n return json;\n }\n\n /** A Personal Access Token (`roxp_…`) authenticates the console endpoints via\n * `Authorization: Bearer`; it is not a BaaS session token. */\n private get isPat(): boolean {\n return this.sessionToken?.startsWith('roxp_') ?? false;\n }\n\n private async authHeaders(\n skipAuth: boolean,\n isConsole: boolean,\n ): Promise<Record<string, string>> {\n // IMPORTANT: never send X-BEA-Application-ID on an authenticated request.\n // The BaaS `/auth/*` router treats the App-ID header as \"mint me an\n // anonymous token\" and short-circuits — /Auth/login, /Auth/me etc. would\n // silently return a fresh anon token instead of doing their job. The App-ID\n // (+ JS key) is sent only by anonToken()'s own POST /Auth call.\n if (skipAuth) return {};\n if (this.isPat) {\n // Console: Bearer. BaaS: nothing — PAT clients resolve identity and\n // subscriptions through the console's /account/context instead.\n return isConsole ? { authorization: `Bearer ${this.sessionToken}` } : {};\n }\n if (this.sessionToken) return { [H.sessionToken]: this.sessionToken };\n if (this.restKey) return { [H.appId]: this.appId, [H.restKey]: this.restKey };\n const anon = await this.anonToken();\n if (anon.session_token) return { [H.sessionToken]: anon.session_token };\n return { [H.accessToken]: anon.access_token ?? '' };\n }\n\n /** A raw BaaS request. `path` is relative to {@link baseUrl} (leading `/`). */\n async request<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.baseUrl, method, path, opts);\n }\n\n /** A request against the console app endpoints ({@link consoleUrl}). */\n async console<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.consoleUrl, method, path, opts);\n }\n\n private async rawRequest<T>(\n root: string,\n method: string,\n path: string,\n opts: RequestOptions,\n ): Promise<T> {\n const qs = toQueryString(opts.query);\n const url = `${root}${path.startsWith('/') ? path : `/${path}`}${qs ? `?${qs}` : ''}`;\n const headers: Record<string, string> = {\n ...(await this.authHeaders(opts.skipAuth ?? false, root === this.consoleUrl)),\n ...opts.headers,\n };\n const hasBody = method !== 'GET' && method !== 'HEAD' && opts.body !== undefined;\n let body: string | Uint8Array | ArrayBuffer | FormData | undefined;\n if (hasBody) {\n if (\n typeof opts.body === 'string' ||\n opts.body instanceof Uint8Array ||\n opts.body instanceof ArrayBuffer ||\n (typeof FormData !== 'undefined' && opts.body instanceof FormData)\n ) {\n body = opts.body as string | Uint8Array | ArrayBuffer | FormData;\n } else {\n headers['content-type'] = headers['content-type'] ?? 'application/json';\n body = JSON.stringify(opts.body);\n }\n }\n\n let res: Response;\n try {\n res = await this._fetch(url, { method, headers, body, signal: opts.signal });\n } catch (cause) {\n throw new RoxyonApiError(`Network error calling ${method} ${url}`, { body: cause });\n }\n\n const text = await res.text();\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : {};\n } catch {\n // An HTML page means the route isn't served by the API (a console route not deployed yet falls through to\n // the web app): say so instead of handing the page to the caller as an error message.\n const html = /^\\s*</.test(text);\n json = {\n error: html\n ? `${method} ${path} is not available on this server yet (got a web page instead of the API).`\n : text || `HTTP ${res.status}`,\n _raw: html ? '' : text,\n };\n }\n\n if (!res.ok && !opts.tolerateHttpError) {\n const msg =\n (json &&\n typeof json === 'object' &&\n 'error' in json &&\n (json as { error: string }).error) ||\n `HTTP ${res.status} calling ${method} ${path}`;\n throw new RoxyonApiError(String(msg), { status: res.status, body: json });\n }\n return json as T;\n }\n\n get<T = unknown>(path: string, query?: QueryObject, opts?: RequestOptions): Promise<T> {\n return this.request<T>('GET', path, { ...opts, query });\n }\n post<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('POST', path, { ...opts, body });\n }\n put<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', path, { ...opts, body });\n }\n del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', path, { ...opts, body });\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateDatabaseInput {\n /** DB name suffix — the platform prefixes it with the subscription's own username (globally unique). */\n name: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one. */\n password?: string;\n}\n\nexport interface CreateDatabaseResult {\n ok: boolean;\n objectId: string;\n name: string;\n username: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n /** `<node-ip>:6033` — the ProxySQL endpoint to connect the app to. */\n host?: string;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface DatabaseSummary {\n objectId: string;\n Name: string;\n Username: string;\n Status: string;\n}\n\nexport interface DeleteDatabaseResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Databases (MySQL/MariaDB on the shared Galera cluster) attached to a subscription. */\nexport class DatabasesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */\n async list(subscriptionId: string): Promise<DatabaseSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n databases?: DatabaseSummary[];\n }>('POST', '/databases/list', {\n body: { subscription: subscriptionId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the databases.', { body: r });\n return r.databases ?? [];\n }\n\n /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */\n async create(input: CreateDatabaseInput): Promise<CreateDatabaseResult> {\n const r = await this.client.console<CreateDatabaseResult>('POST', '/databases/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the database.', { body: r });\n return r;\n }\n\n /** `POST /databases/delete` */\n async delete(databaseId: string): Promise<DeleteDatabaseResult> {\n const r = await this.client.console<DeleteDatabaseResult>('POST', '/databases/delete', {\n body: { database: databaseId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the database.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Domain {\n objectId: string;\n Name: string;\n}\n\nexport interface CreateDomainInput {\n /** FQDN to host — a subdomain of a domain the account already hosts, or `*.roxyon.com`. */\n host: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** `spa` → unmatched paths serve `/index.html`; default `static`. */\n siteType?: 'static' | 'spa';\n /** PHP version for the vhost (e.g. `\"8.3\"`). Unknown/omitted falls back to the platform default. */\n phpVersion?: string;\n}\n\nexport interface CreateDomainResult {\n ok: boolean;\n objectId: string;\n host: string;\n /** `subdomain` of an owned parent, or `primary`. */\n type: 'subdomain' | 'primary';\n /** `provisioning` while DNS/vhost/TLS come up, then `active` (or `failed`). */\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\n/** Domains (hosts) attached to a subscription. */\nexport class DomainsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Domain[]> {\n const r = await this.client.get<{ results?: Domain[] }>('/Domains', {\n fields: 'objectId,Name',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n /**\n * `POST /domains/create` — provision a subdomain (DNS + vhost + auto-TLS). The\n * server decides subdomain vs primary from the caller's existing hosts and\n * writes the `pending` row; the platform's reconciler does the rest.\n */\n async create(input: CreateDomainInput): Promise<CreateDomainResult> {\n const r = await this.client.console<CreateDomainResult>('POST', '/domains/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the domain.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateEmailInput {\n /** The part before `@`. */\n localPart: string;\n /** A hostname already on the account. */\n domain: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /** Mailbox quota in MB. Default 1024. */\n quota?: number;\n forwardTo?: string;\n saveCopy?: boolean;\n}\n\nexport interface CreateEmailResult {\n ok: boolean;\n objectId: string;\n email: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n quota?: number;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface EmailSummary {\n objectId: string;\n Email: string;\n LocalPart: string;\n Status: string;\n Quota?: number;\n}\n\nexport interface DeleteEmailResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Mailboxes attached to a subscription's domains. */\nexport class EmailApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */\n async list(subscriptionId: string): Promise<EmailSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n emails?: Omit<EmailSummary, 'LocalPart'>[];\n }>('POST', '/emails/list', { body: { subscription: subscriptionId }, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the mailboxes.', { body: r });\n return (r.emails ?? []).map((e) => ({ ...e, LocalPart: e.Email.split('@')[0] ?? '' }));\n }\n\n /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */\n async create(input: CreateEmailInput): Promise<CreateEmailResult> {\n const r = await this.client.console<CreateEmailResult>('POST', '/emails/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the mailbox.', { body: r });\n return r;\n }\n\n /** `POST /emails/delete` */\n async delete(emailId: string): Promise<DeleteEmailResult> {\n const r = await this.client.console<DeleteEmailResult>('POST', '/emails/delete', {\n body: { email: emailId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the mailbox.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface StaticDeployResult {\n ok: boolean;\n host: string;\n path: string;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\nexport interface DeployOptions {\n /** Replace the docroot contents instead of overlaying (keeps `.well-known`). */\n clean?: boolean;\n /** Flip the host to SPA routing: unmatched paths serve `/index.html`. */\n spa?: boolean;\n}\n\nexport interface SiteFile {\n /** POSIX path relative to the site root. */\n path: string;\n size: number;\n type: 'file' | 'dir';\n}\n\nexport interface SiteFileContent {\n path: string;\n size: number;\n encoding: 'utf8' | 'base64';\n content: string;\n}\n\n/**\n * Static-site hosting: the files under a host's document root\n * (`public_html[/<folder>]`), served directly by nginx. No Application row, no\n * process. All routes go to the console (`POST /sites/deploy`, `GET /sites/files`,\n * `GET /sites/file`) and authenticate with a session token or a `roxp_` PAT.\n */\nexport class SitesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** Upload a gzip tarball into `host`'s docroot (+ optional sub-`folder`). */\n async deploy(\n host: string,\n folder: string,\n tarball: Uint8Array,\n opts: DeployOptions = {},\n ): Promise<StaticDeployResult> {\n const query: Record<string, string> = { host, folder };\n if (opts.clean) query.clean = '1';\n if (opts.spa) query.spa = '1';\n const r = await this.client.console<StaticDeployResult>('POST', '/sites/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Static deploy failed.', { body: r });\n return r;\n }\n\n /** List the files currently in `host`'s docroot (optionally under `path`). */\n async listFiles(host: string, folder = '', path = ''): Promise<SiteFile[]> {\n const r = await this.client.console<{ ok?: boolean; files?: SiteFile[]; error?: string }>(\n 'GET',\n '/sites/files',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list site files.', { body: r });\n return r.files ?? [];\n }\n\n /** Read one file from `host`'s docroot. */\n async readFile(host: string, folder: string, path: string): Promise<SiteFileContent> {\n const r = await this.client.console<SiteFileContent & { ok?: boolean; error?: string }>(\n 'GET',\n '/sites/file',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok || typeof r.content !== 'string') {\n throw new RoxyonApiError(r?.error || 'Could not read the file.', { body: r });\n }\n return { path: r.path, size: r.size, encoding: r.encoding, content: r.content };\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface ResetSshPasswordInput {\n /** Subscription to reset. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one meeting the strength rules. */\n password?: string;\n}\n\nexport interface ResetSshPasswordResult {\n ok: boolean;\n subscription: string;\n /** Shown once — the platform never stores or re-shows it. */\n password: string;\n status: 'pending' | 'active' | 'failed';\n}\n\n/**\n * The shared shell password used for SSH, SFTP and the file manager on a\n * subscription's container (SSHpiper maps the username to the container).\n */\nexport class SshApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /ssh/password` */\n async resetPassword(input: ResetSshPasswordInput = {}): Promise<ResetSshPasswordResult> {\n const r = await this.client.console<ResetSshPasswordResult>('POST', '/ssh/password', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) {\n throw new RoxyonApiError(\n (r as { error?: string })?.error || 'Could not reset the password.',\n {\n body: r,\n },\n );\n }\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Subscription {\n objectId: string;\n Name?: string;\n Status?: string;\n [k: string]: unknown;\n}\n\nexport interface Privilege {\n objectId: string;\n Type?: string;\n Subscription?: string;\n _Subscription?: { results: Subscription[] };\n [k: string]: unknown;\n}\n\ninterface ListResponse<T> {\n results?: T[];\n error?: string;\n}\n\n/** Access to the caller's subscriptions (via their Privileges rows). */\nexport class SubscriptionsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** All subscriptions the signed-in user has a Privilege on. */\n async list(userId: string): Promise<Subscription[]> {\n const r = await this.client.get<ListResponse<Privilege>>('/Privileges', {\n where: { User: userId },\n fields: 'objectId,Type,Subscription',\n limit: -1,\n include: [\n {\n className: 'Subscriptions',\n field: 'Subscription',\n fields: 'objectId,Name,Status',\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load subscriptions.', {\n status: 401,\n body: r,\n });\n }\n const subs: Subscription[] = [];\n for (const priv of r.results) {\n const sub = priv._Subscription?.results?.[0];\n if (sub) subs.push(sub);\n }\n return subs;\n }\n\n /**\n * Resolve the subscription to act on. Prefers an exact `objectId` or `Name`\n * match against `preferred`; otherwise the first active subscription; otherwise\n * the first one. Throws when the account has none.\n */\n async resolve(userId: string, preferred?: string): Promise<Subscription> {\n const subs = await this.list(userId);\n if (subs.length === 0) {\n throw new RoxyonApiError(\n 'This account has no active subscription — add a plan in the console first.',\n );\n }\n if (preferred) {\n const hit = subs.find(\n (s) => s.objectId === preferred || s.Name === preferred || s.Username === preferred,\n );\n if (hit) return hit;\n throw new RoxyonApiError(`No subscription matches \"${preferred}\".`);\n }\n return subs.find((s) => s.Status === 'active') ?? subs[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */\nexport type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';\n\nexport interface TokenSummary {\n id: string;\n name: string;\n prefix: string;\n scopes: TokenScope[];\n lastUsedAt: string | null;\n expiresAt: string | null;\n createdAt: string;\n /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */\n monthlyBudgetUSD?: number | null;\n /** For `billing:order` tokens: plan codes it may order (empty = any). */\n allowedSkus?: string[];\n}\n\nexport interface CreatedToken {\n /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */\n token: string;\n name: string;\n scopes: TokenScope[];\n expiresAt: string | null;\n}\n\n/**\n * Personal Access Tokens — for the CLI in CI and for the MCP server running\n * headless. Managed only while signed in with a session (`roxyon login`); a PAT\n * cannot mint or revoke another PAT.\n *\n * `GET/POST/DELETE /account/tokens` — console endpoints.\n */\nexport class TokensApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(): Promise<TokenSummary[]> {\n const r = await this.client.console<{ ok?: boolean; tokens?: TokenSummary[]; error?: string }>(\n 'GET',\n '/account/tokens',\n { tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list tokens.', { body: r });\n return r.tokens ?? [];\n }\n\n async create(\n name: string,\n opts: {\n scopes?: TokenScope[];\n expiresInDays?: number;\n /** Required with `billing:order`. */\n monthlyBudgetUSD?: number;\n allowedSkus?: string[];\n } = {},\n ): Promise<CreatedToken> {\n const r = await this.client.console<CreatedToken & { ok?: boolean; error?: string }>(\n 'POST',\n '/account/tokens',\n {\n body: {\n name,\n scopes: opts.scopes ?? ['deploy', 'logs'],\n ...(opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {}),\n ...(opts.monthlyBudgetUSD ? { monthlyBudgetUSD: opts.monthlyBudgetUSD } : {}),\n ...(opts.allowedSkus?.length ? { allowedSkus: opts.allowedSkus } : {}),\n },\n tolerateHttpError: true,\n },\n );\n if (!r?.ok || !r.token) {\n throw new RoxyonApiError(r?.error || 'Could not create the token.', { body: r });\n }\n return { token: r.token, name: r.name, scopes: r.scopes, expiresAt: r.expiresAt ?? null };\n }\n\n async revoke(id: string): Promise<void> {\n const r = await this.client.console<{ ok?: boolean; error?: string }>(\n 'DELETE',\n '/account/tokens',\n { query: { id }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not revoke the token.', { body: r });\n }\n}\n","import { RoxyonApiError } from './errors.js';\n\n/** BaaS V2 base. V1 (`/1`) is frozen; app data tools speak V2 only. */\nexport const DEFAULT_BAAS_V2_URL = 'https://www.beaapis.com/2';\n\n/** V2 caps one page at 200 rows. */\nexport const BAAS_MAX_PAGE = 200;\n/** V2 takes 1 to 50 requests per batch. */\nexport const BAAS_MAX_BATCH = 50;\n\nexport interface BaasDataOptions {\n /** The app's secret key (`rxsk_…`): server scope, from the project's API keys in Roxyon Base. */\n secretKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\nexport type BaasRow = Record<string, unknown>;\n\nexport interface BaasQuery {\n /** e.g. `{ Status: 'active', Age: { gt: 18 } }`; `in` takes a comma-joined string. */\n where?: Record<string, unknown>;\n /** `*` and/or column names, comma separated. Defaults to `*`. */\n fields?: string;\n /** Comma list, `-` for descending, e.g. `-createdAt`. */\n order?: string;\n /** 1 to 200 (default 50). */\n limit?: number;\n skip?: number;\n /** Also return the total number of matching rows. */\n count?: boolean;\n}\n\nexport interface BaasBatchRequest {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n /** `/Class` or `/Class/<id>`. */\n path: string;\n body?: Record<string, unknown>;\n}\n\n/** One batch answer: `ok:false` with `error`/`message`, or that request's own V2 answer. */\nexport interface BaasBatchResult {\n status: number;\n ok?: boolean;\n error?: string;\n message?: string;\n result?: BaasRow;\n results?: BaasRow[];\n count?: number;\n id?: string;\n}\n\ninterface V2Body {\n ok?: boolean;\n error?: string;\n message?: string;\n details?: unknown;\n result?: BaasRow;\n results?: unknown[];\n count?: number;\n id?: string;\n}\n\n// Mirrors App.php: classes `^[A-Za-z][A-Za-z0-9_]{0,63}$` (no `_` system classes), ids `^[A-Za-z0-9]{1,40}$`.\nconst CLASS_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID_RE = /^[A-Za-z0-9]{1,40}$/;\n\nfunction checkClass(name: string): string {\n if (!CLASS_RE.test(name)) throw new Error(`Invalid class name \"${name}\".`);\n return name;\n}\n\nfunction checkId(id: string): string {\n if (!ID_RE.test(id)) throw new Error(`Invalid objectId \"${id}\".`);\n return id;\n}\n\n/**\n * Records of ONE app on BaaS V2, as that app's own backend (server scope, `X-RX-Secret-Key`).\n * Server scope passes every class rule, so treat the key like a database password. V2 answers\n * failures as `{ok:false, error, message}` with an HTTP status; every call throws on those.\n * Schema changes are not reachable with a secret key (console API only).\n */\nexport class BaasDataApi {\n private readonly baseUrl: string;\n private readonly secretKey: string;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: BaasDataOptions) {\n if (!opts.secretKey.startsWith('rxsk_')) {\n throw new Error('BaaS V2 needs the app secret key (starts with rxsk_).');\n }\n this.secretKey = opts.secretKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_V2_URL).replace(/\\/+$/, '');\n this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n private async call(\n method: string,\n path: string,\n opts: { query?: Record<string, string>; body?: unknown } = {},\n ): Promise<V2Body> {\n const qs =\n opts.query && Object.keys(opts.query).length ? `?${new URLSearchParams(opts.query)}` : '';\n const headers: Record<string, string> = { 'x-rx-secret-key': this.secretKey };\n if (opts.body !== undefined) headers['content-type'] = 'application/json';\n let res: Response;\n try {\n res = await this._fetch(`${this.baseUrl}${path}${qs}`, {\n method,\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n });\n } catch (e) {\n throw new RoxyonApiError(`Could not reach ${this.baseUrl}: ${(e as Error).message}`);\n }\n let body: V2Body = {};\n try {\n body = ((await res.json()) as V2Body) ?? {};\n } catch {\n // Non-JSON (proxy error page): handled below.\n }\n if (!res.ok || body.ok !== true) {\n const msg = body.message || body.error || `HTTP ${res.status}`;\n throw new RoxyonApiError(msg, { status: res.status, type: body.error, body });\n }\n return body;\n }\n\n private static recordPath(className: string, id?: string): string {\n return `/records/${checkClass(className)}${id === undefined ? '' : `/${checkId(id)}`}`;\n }\n\n async query(className: string, q: BaasQuery = {}): Promise<{ rows: BaasRow[]; count?: number }> {\n const limit = q.limit ?? 50;\n if (!Number.isInteger(limit) || limit < 1 || limit > BAAS_MAX_PAGE) {\n throw new Error(`limit must be 1 to ${BAAS_MAX_PAGE}.`);\n }\n const query: Record<string, string> = { fields: q.fields || '*', limit: String(limit) };\n // V2 takes where as JSON text, so operators and `in` strings survive unchanged.\n if (q.where && Object.keys(q.where).length) query.where = JSON.stringify(q.where);\n if (q.order) query.order = q.order;\n if (q.skip) query.skip = String(q.skip);\n if (q.count) query.count = '1';\n const r = await this.call('GET', BaasDataApi.recordPath(className), { query });\n return {\n rows: (r.results ?? []) as BaasRow[],\n ...(r.count !== undefined ? { count: r.count } : {}),\n };\n }\n\n async get(className: string, objectId: string): Promise<BaasRow> {\n const r = await this.call('GET', BaasDataApi.recordPath(className, objectId));\n return r.result ?? {};\n }\n\n /** Returns the created row as stored. */\n async create(className: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('POST', BaasDataApi.recordPath(className), { body: { data } });\n return r.result ?? {};\n }\n\n async update(className: string, objectId: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('PUT', BaasDataApi.recordPath(className, objectId), {\n body: { data },\n });\n return r.result ?? {};\n }\n\n /** The id goes in the URL path, never the body. */\n async delete(className: string, objectId: string): Promise<void> {\n await this.call('DELETE', BaasDataApi.recordPath(className, objectId));\n }\n\n /** 1 to 50 record requests in one call; one failing doesn't stop the others. */\n async batch(requests: BaasBatchRequest[]): Promise<BaasBatchResult[]> {\n if (requests.length < 1 || requests.length > BAAS_MAX_BATCH) {\n throw new Error(`A batch takes 1 to ${BAAS_MAX_BATCH} requests.`);\n }\n for (const req of requests) {\n const [cls, id, extra] = req.path.split('/').filter(Boolean);\n if (!cls || extra !== undefined)\n throw new Error(`Batch path \"${req.path}\" must be /Class or /Class/id.`);\n checkClass(cls);\n if (id !== undefined) checkId(id);\n }\n const r = await this.call('POST', '/batch', { body: { requests } });\n return (r.results ?? []) as BaasBatchResult[];\n }\n}\n","/**\n * `.env`-style block <-> JSON object, ported verbatim from `appfEnvParse` /\n * `appfEnvToLines` in `console.roxyon.com/.../modals/app_form.view` so the CLI\n * and the console form agree byte-for-byte on what `Applications.Env` holds.\n *\n * The server re-sanitises again (`ApplicationRenderer::envPair`), so this only\n * needs to be reasonable. `PORT` and `HOST` are set by the platform — callers\n * should not write them.\n */\nexport function parseEnv(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (let line of String(text || '').split(/\\r?\\n/)) {\n line = line.trim();\n if (!line || line.startsWith('#')) continue;\n line = line.replace(/^export\\s+/, '');\n const eq = line.indexOf('=');\n if (eq < 1) continue;\n const k = line.slice(0, eq).trim();\n let v = line.slice(eq + 1).trim();\n if (v.length >= 2 && (v[0] === '\"' || v[0] === \"'\") && v[v.length - 1] === v[0]) {\n v = v.slice(1, -1);\n }\n if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) out[k] = v;\n }\n return out;\n}\n\nexport function formatEnv(obj: Record<string, string> | null | undefined): string {\n if (!obj || typeof obj !== 'object') return '';\n return Object.keys(obj)\n .map((k) => `${k}=${obj[k] == null ? '' : String(obj[k])}`)\n .join('\\n');\n}\n\n/** Parse the JSON string stored on `Applications.Env`. */\nexport function envFromStored(jsonStr: string | undefined): Record<string, string> {\n if (!jsonStr) return {};\n try {\n const obj = JSON.parse(jsonStr);\n return obj && typeof obj === 'object' ? (obj as Record<string, string>) : {};\n } catch {\n return {};\n }\n}\n","/**\n * Runtime / version / framework catalog — a verbatim copy of the `RUNTIMES`\n * table in `console.roxyon.com/.../modals/app_form.view`. These are the versions\n * actually installed in the Cloud Hosting containers; offering an uninstalled\n * one produces a deploy that fails at build time for a reason the user cannot\n * act on.\n *\n * TODO(M4): the console form and this file should both import one shared JSON\n * published at `roxyon.com/runtimes.json` so they never drift.\n */\nexport type RuntimeName = 'lumen' | 'node' | 'python' | 'php';\n\nexport interface RuntimeSpec {\n versions: string[];\n defaultVersion: string;\n presets: Array<[value: string, label: string]>;\n command: string;\n}\n\nexport const RUNTIMES: Record<Exclude<RuntimeName, 'lumen'>, RuntimeSpec> = {\n node: {\n versions: ['23.11.1', '22.23.1', '20.20.2', '18.20.8'],\n defaultVersion: '20.20.2',\n presets: [\n ['nextjs', 'Next.js'],\n ['nuxt', 'Nuxt'],\n ['node', 'No framework'],\n ],\n command: 'npm run start',\n },\n python: {\n versions: ['3.11'],\n defaultVersion: '3.11',\n presets: [['python', 'No framework']],\n command: 'gunicorn app:app',\n },\n php: {\n versions: ['8.4', '8.3', '8.2', '8.1', '7.4'],\n defaultVersion: '8.4',\n presets: [\n ['swoole', 'Swoole'],\n ['php', 'No framework'],\n ],\n command: 'php8.4 server.php',\n },\n};\n\n/**\n * A LumenJS project (`runtime: \"lumen\"`) builds to static files with\n * `lm build --serverless` and is served straight from the host's document root\n * by nginx — no long-running process, no systemd unit, no Application row. It\n * deploys through the \"static\" path (upload the built `dist/` to\n * `/home/www/<host>/public_html[/<folder>]`).\n *\n * Node / Python / PHP projects deploy through the \"app\" path (the Applications\n * system: upload source, bump ConfigRevision, reconciler builds + runs it).\n */\nexport type DeployKind = 'static' | 'app';\n\nexport const LUMEN_BUILD = {\n command: 'lm build --serverless',\n /** Directory `lm build --serverless` writes to, relative to the project root. */\n outDir: 'dist',\n} as const;\n"],"mappings":"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","names":["json"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.ts","../src/billing.ts","../src/constants.ts","../src/query.ts","../src/client.ts","../src/databases.ts","../src/domains.ts","../src/email.ts","../src/sites.ts","../src/ssh.ts","../src/subscriptions.ts","../src/tokens.ts","../src/baas-data.ts","../src/env.ts","../src/runtimes.ts"],"sourcesContent":["import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.js';\nimport { BillingApi } from './billing.js';\nimport { RoxyonClient, type RoxyonClientOptions } from './client.js';\nimport { DatabasesApi } from './databases.js';\nimport { DomainsApi } from './domains.js';\nimport { EmailApi } from './email.js';\nimport { SitesApi } from './sites.js';\nimport { SshApi } from './ssh.js';\nimport { SubscriptionsApi } from './subscriptions.js';\nimport { TokensApi } from './tokens.js';\n\nexport { RoxyonClient } from './client.js';\nexport type { RoxyonClientOptions, RequestOptions } from './client.js';\nexport { AuthApi } from './auth.js';\nexport type { RoxyonUser, LoginResult, LoginPrecheck, SessionGrant } from './auth.js';\nexport { ApplicationsApi } from './applications.js';\nexport type {\n Application,\n ApplicationProcess,\n ApplicationRoute,\n CreateApplicationInput,\n CreateOnDeploy,\n DeployResult,\n} from './applications.js';\nexport { SitesApi } from './sites.js';\nexport type {\n DeployOptions,\n SiteFile,\n SiteFileContent,\n StaticDeployResult,\n} from './sites.js';\nexport { DomainsApi } from './domains.js';\nexport type { CreateDomainInput, CreateDomainResult, Domain } from './domains.js';\nexport { DatabasesApi } from './databases.js';\nexport type {\n CreateDatabaseInput,\n CreateDatabaseResult,\n DatabaseSummary,\n DeleteDatabaseResult,\n} from './databases.js';\nexport { EmailApi } from './email.js';\nexport type {\n CreateEmailInput,\n CreateEmailResult,\n EmailSummary,\n DeleteEmailResult,\n} from './email.js';\nexport { SshApi } from './ssh.js';\nexport type { ResetSshPasswordInput, ResetSshPasswordResult } from './ssh.js';\nexport { SubscriptionsApi } from './subscriptions.js';\nexport type { Subscription, Privilege } from './subscriptions.js';\nexport { BillingApi, BILLING_CYCLES, PAYABLE_STATUSES, isPayable } from './billing.js';\nexport type {\n BillingCycle,\n BillingSubscription,\n CatalogProduct,\n Invoice,\n OrderBudget,\n OrderInput,\n OrderResult,\n Quote,\n QuoteInput,\n} from './billing.js';\nexport { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.js';\nexport {\n BaasDataApi,\n BAAS_MAX_BATCH,\n BAAS_MAX_PAGE,\n DEFAULT_BAAS_V2_URL,\n} from './baas-data.js';\nexport type {\n BaasBatchRequest,\n BaasBatchResult,\n BaasDataOptions,\n BaasQuery,\n BaasRow,\n} from './baas-data.js';\nexport { TokensApi } from './tokens.js';\nexport type { TokenScope, TokenSummary, CreatedToken } from './tokens.js';\nexport { RoxyonApiError, rxError, isAuthError, assertOk } from './errors.js';\nexport { parseEnv, formatEnv, envFromStored } from './env.js';\nexport { RUNTIMES, LUMEN_BUILD } from './runtimes.js';\nexport type { RuntimeName, RuntimeSpec, DeployKind } from './runtimes.js';\nexport { toQueryString } from './query.js';\nexport { DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, DEFAULT_APP } from './constants.js';\n\n/**\n * Convenience facade bundling every sub-API over one {@link RoxyonClient}.\n *\n * ```ts\n * const roxyon = new Roxyon({ sessionToken }); // or a roxp_ PAT\n * const ctx = await roxyon.account.context(); // user + subs + domains\n * ```\n */\nexport class Roxyon {\n readonly client: RoxyonClient;\n readonly auth: AuthApi;\n readonly account: AccountApi;\n readonly tokens: TokensApi;\n readonly subscriptions: SubscriptionsApi;\n readonly domains: DomainsApi;\n readonly applications: ApplicationsApi;\n readonly sites: SitesApi;\n readonly databases: DatabasesApi;\n readonly email: EmailApi;\n readonly ssh: SshApi;\n readonly billing: BillingApi;\n\n constructor(options: RoxyonClientOptions | RoxyonClient = {}) {\n this.client = options instanceof RoxyonClient ? options : new RoxyonClient(options);\n this.auth = new AuthApi(this.client);\n this.account = new AccountApi(this.client);\n this.tokens = new TokensApi(this.client);\n this.subscriptions = new SubscriptionsApi(this.client);\n this.domains = new DomainsApi(this.client);\n this.applications = new ApplicationsApi(this.client);\n this.sites = new SitesApi(this.client);\n this.databases = new DatabasesApi(this.client);\n this.email = new EmailApi(this.client);\n this.ssh = new SshApi(this.client);\n this.billing = new BillingApi(this.client);\n }\n\n get sessionToken(): string | undefined {\n return this.client.getSessionToken();\n }\n}\n","/**\n * The Roxyon BaaS (\"RX\" engine) resolves failed writes rather than rejecting\n * them — a rejected promise never fires and a failure is shaped like a success\n * body with an `error` string on it (top-level, or inside `results[]`). Every\n * write must be run through {@link rxError} before it is treated as having\n * worked. This mirrors `rxError()` in `console.roxyon.com/src/index.js`.\n *\n * Known failure shapes:\n * { \"results\": [ { \"code\": 1054, \"error\": \"Unknown column ...\", \"type\": \"DBQueryError\" } ] }\n * { \"code\": 105, \"error\": \"Invalid Field Name\", \"type\": \"InvalidFieldName\" }\n */\n\nexport interface RxErrorBody {\n code?: number;\n error?: string;\n type?: string;\n results?: unknown;\n}\n\n/** Returns the error message from a BaaS response, or `''` when the call worked. */\nexport function rxError(r: unknown): string {\n if (r === null || r === undefined) return 'No response from the server.';\n if (typeof r !== 'object') return '';\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body.error;\n const rows = body.results;\n if (Array.isArray(rows)) {\n for (const row of rows) {\n if (row && typeof row === 'object' && typeof (row as RxErrorBody).error === 'string') {\n const msg = (row as RxErrorBody).error;\n if (msg) return msg;\n }\n }\n }\n return '';\n}\n\nexport class RoxyonApiError extends Error {\n readonly code?: number;\n readonly type?: string;\n readonly status?: number;\n readonly body: unknown;\n\n constructor(\n message: string,\n opts: { code?: number; type?: string; status?: number; body?: unknown } = {},\n ) {\n super(message);\n this.name = 'RoxyonApiError';\n this.code = opts.code;\n this.type = opts.type;\n this.status = opts.status;\n this.body = opts.body;\n }\n}\n\nconst AUTH_CODES = new Set([101, 141, 209, 1060, 1063, 401]);\nconst AUTH_HINTS = [\n 'invalid session',\n 'session token',\n 'unauthorized',\n 'not authorized',\n 'invalid token',\n 'expired',\n 'log in again',\n];\n\n/** True when an error looks like \"the session/token is gone\", so the caller can re-auth. */\nexport function isAuthError(err: unknown): boolean {\n if (err instanceof RoxyonApiError) {\n if (err.status === 401 || err.status === 403) return true;\n if (err.code !== undefined && AUTH_CODES.has(err.code)) return true;\n }\n const msg = (\n err instanceof Error ? err.message : typeof err === 'string' ? err : rxError(err)\n ).toLowerCase();\n return AUTH_HINTS.some((h) => msg.includes(h));\n}\n\n/** Locate the object (top-level or a `results[]` row) that carries the error. */\nfunction erroringNode(r: unknown): RxErrorBody | undefined {\n if (!r || typeof r !== 'object') return undefined;\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body;\n if (Array.isArray(body.results)) {\n for (const row of body.results) {\n if (row && typeof row === 'object' && (row as RxErrorBody).error) return row as RxErrorBody;\n }\n }\n return undefined;\n}\n\n/** Throw a {@link RoxyonApiError} if `r` carries a BaaS error; otherwise return it typed. */\nexport function assertOk<T>(r: T): T {\n const msg = rxError(r);\n if (msg) {\n const node = erroringNode(r);\n throw new RoxyonApiError(msg, { code: node?.code, type: node?.type, body: r });\n }\n return r;\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\nimport type { TokenScope } from './tokens.js';\n\nexport interface AccountSubscription {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AccountDomain {\n id: string;\n name: string;\n subscription: string;\n /** `active`, or `provisioning` while a freshly-added host comes up. */\n status?: string;\n}\n\nexport interface AccountContext {\n user: { id: string; email: string };\n scopes: (TokenScope | '*')[];\n subscriptions: AccountSubscription[];\n domains: AccountDomain[];\n}\n\nexport interface AccountApp {\n id: string;\n name: string;\n status: string;\n desiredState: string;\n runtime: string;\n configRevision: number;\n appliedRevision: number;\n lastError: string | null;\n repo: { url: string; branch: string } | null;\n}\n\n/**\n * `GET /account/context` — one call the CLI / MCP server use to plan a deploy:\n * the signed-in user, their subscriptions, and their domains. Resolvable by a\n * session token OR a Personal Access Token, so a CI job with only a PAT never\n * has to touch the BaaS. Infra details (nodes, datacenters, container names,\n * filesystem paths) are deliberately not surfaced here.\n */\nexport class AccountApi {\n private cache?: Promise<AccountContext>;\n\n constructor(private readonly client: RoxyonClient) {}\n\n context(opts: { fresh?: boolean } = {}): Promise<AccountContext> {\n if (!this.cache || opts.fresh) this.cache = this.fetch();\n return this.cache;\n }\n\n private async fetch(): Promise<AccountContext> {\n const r = await this.client.console<AccountContext & { ok?: boolean; error?: string }>(\n 'GET',\n '/account/context',\n { tolerateHttpError: true },\n );\n if (!r?.ok || !r.user?.id) {\n throw new RoxyonApiError(r?.error || 'Could not load the account context.', { body: r });\n }\n // Map explicitly — the endpoint may carry infra fields (node/datacenter/\n // container); keep only what a deploy actually needs so they never reach\n // an AI assistant's context or a log.\n return {\n user: { id: r.user.id, email: r.user.email },\n scopes: r.scopes ?? [],\n subscriptions: (r.subscriptions ?? []).map((s) => ({\n id: s.id,\n name: s.name,\n status: s.status,\n })),\n domains: (r.domains ?? []).map((d) => ({\n id: d.id,\n name: d.name,\n subscription: d.subscription,\n ...(d.status ? { status: d.status } : {}),\n })),\n };\n }\n\n /** `GET /account/apps` — the account's applications (list, PAT-safe). */\n async apps(): Promise<AccountApp[]> {\n const r = await this.client.console<{\n ok?: boolean;\n applications?: AccountApp[];\n error?: string;\n }>('GET', '/account/apps', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list applications.', { body: r });\n return (r.applications ?? []).map((a) => ({\n id: a.id,\n name: a.name,\n status: a.status,\n desiredState: a.desiredState,\n runtime: a.runtime,\n configRevision: a.configRevision,\n appliedRevision: a.appliedRevision,\n lastError: a.lastError,\n repo: a.repo,\n }));\n }\n\n /** One application by id, PAT-safe (filters {@link apps}). */\n async getApp(id: string): Promise<AccountApp | undefined> {\n return (await this.apps()).find((a) => a.id === id);\n }\n\n /** Pick the subscription to deploy against — the preferred one, else the only/first. */\n async resolveSubscription(preferred?: string): Promise<AccountSubscription> {\n const { subscriptions } = await this.context();\n if (subscriptions.length === 0) {\n throw new RoxyonApiError('This account has no subscriptions.');\n }\n if (preferred) {\n const hit = subscriptions.find((s) => s.id === preferred || s.name === preferred);\n if (hit) return hit;\n }\n return subscriptions[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError, assertOk } from './errors.js';\n\nexport interface Application {\n objectId: string;\n Name: string;\n Status?: string;\n DesiredState?: string;\n SourcePath?: string;\n Runtime?: string;\n RuntimeVersion?: string;\n Preset?: string;\n ConfigRevision?: number;\n AppliedRevision?: number;\n LastError?: string;\n Env?: string;\n RepoUrl?: string;\n Subscription?: string;\n [k: string]: unknown;\n}\n\nexport interface ApplicationProcess {\n objectId: string;\n Application?: string;\n Type?: string;\n Command?: string;\n Status?: string;\n Port?: number;\n}\n\nexport interface ApplicationRoute {\n objectId: string;\n Application?: string;\n Domain?: string;\n Path?: string;\n Enabled?: number | string;\n}\n\ninterface Results<T> {\n results?: T[];\n error?: string;\n}\n\nexport interface DeployResult {\n ok: boolean;\n application: string;\n created?: boolean;\n configRevision?: number;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\n/** Params for creating an application on its first deploy (no id yet). */\nexport interface CreateOnDeploy {\n host: string;\n folder?: string;\n runtime: 'node' | 'python' | 'php';\n runtimeVersion?: string;\n preset?: string;\n command?: string;\n public?: boolean;\n}\n\nexport interface CreateApplicationInput {\n subscription: string;\n name: string;\n /** Absolute source path: `/home/www/<host>/public_html/<folder>`. */\n sourcePath: string;\n runtime: string;\n runtimeVersion: string;\n preset: string;\n /** The web process start command. */\n command: string;\n /** Route host (`Domains.objectId`). */\n domainId: string;\n /** `.env`-style object stored as JSON on `Applications.Env`. */\n env?: Record<string, string>;\n /** Make the app public (route serves the app instead of the host's files). */\n public?: boolean;\n}\n\n/**\n * The Roxyon Applications system. Deployment is declarative: rows describe the\n * desired state and every meaningful change bumps `ConfigRevision`; a\n * server-side reconciler builds the source in an isolated release dir and\n * (re)starts a systemd unit, writing back `Status` / `AppliedRevision` /\n * `LastError`. Mirrors `applications.view` + `modals/app_form.view`.\n */\nexport class ApplicationsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Application[]> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n async get(id: string): Promise<Application | undefined> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: 1,\n where: { objectId: id },\n });\n return r.results?.[0];\n }\n\n /** Create the application + its web process + a route, matching `createNew()`. */\n async create(\n input: CreateApplicationInput,\n ): Promise<{ application: string; process: string; route: string }> {\n const appRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/Applications', {\n Subscription: input.subscription,\n Name: input.name,\n Preset: input.preset,\n SourcePath: input.sourcePath,\n Runtime: input.runtime,\n RuntimeVersion: input.runtimeVersion,\n Env: JSON.stringify(input.env ?? {}),\n Status: 'pending',\n DesiredState: 'running',\n ConfigRevision: 1,\n AppliedRevision: 0,\n LastError: '',\n }),\n );\n const appId = appRes.results?.[0]?.objectId;\n if (!appId) throw new RoxyonApiError('No application id returned.', { body: appRes });\n\n const procRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationProcesses', {\n Application: appId,\n Type: 'web',\n Port: 0, // allocated by the backend at deploy time\n Command: input.command,\n Status: 'pending',\n }),\n );\n const procId = procRes.results?.[0]?.objectId ?? '';\n\n const routeRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationRoutes', {\n Application: appId,\n Domain: input.domainId,\n Path: '/',\n Enabled: input.public ? 1 : 0,\n }),\n );\n const routeId = routeRes.results?.[0]?.objectId ?? '';\n\n return { application: appId, process: procId, route: routeId };\n }\n\n // ---- console endpoints (session token or PAT) ----\n\n /** Read an application's environment. `GET /applications/env`. */\n async getEnv(applicationId: string): Promise<Record<string, string>> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n error?: string;\n }>('GET', '/applications/env', {\n query: { application: applicationId },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not read the environment.', { body: r });\n return r.env ?? {};\n }\n\n /**\n * Merge `set` and delete `remove`, bumping `ConfigRevision`. `PORT`/`HOST` are\n * ignored (platform-managed). `POST /applications/env`. Returns the new env.\n */\n async setEnv(\n applicationId: string,\n changes: { set?: Record<string, string>; remove?: string[] },\n ): Promise<{ env: Record<string, string>; changed: string[]; configRevision: number }> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n changed?: string[];\n configRevision?: number;\n error?: string;\n }>('POST', '/applications/env', {\n query: { application: applicationId },\n body: { set: changes.set ?? {}, remove: changes.remove ?? [] },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not update the environment.', { body: r });\n return { env: r.env ?? {}, changed: r.changed ?? [], configRevision: r.configRevision ?? 0 };\n }\n\n /** Rebuild from the latest source and restart. `POST /applications/action`. */\n async deploy(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'deploy' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /** Bounce the process only — no rebuild. `POST /applications/action`. */\n async restart(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'restart' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /**\n * Tail the app's journal. `POST /applications/logs` returns one block per\n * process (`{ type, unit, output }`); this flattens them to lines, each\n * prefixed with the process type when there is more than one.\n */\n async logs(applicationId: string, lines = 100): Promise<string[]> {\n const r = await this.client.console<{\n processes?: Array<{ type?: string; unit?: string; output?: string }>;\n error?: string;\n }>('POST', '/applications/logs', {\n body: { application: applicationId, lines },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n const procs = r?.processes ?? [];\n const multi = procs.length > 1;\n const out: string[] = [];\n for (const p of procs) {\n const body = (p.output ?? '').split('\\n').filter(Boolean);\n for (const line of body) out.push(multi ? `[${p.type ?? 'web'}] ${line}` : line);\n }\n return out;\n }\n\n /** Connect a git remote for push-to-deploy. `POST /applications/repo/connect`. */\n async repoConnect(\n applicationId: string,\n repoUrl: string,\n branch = 'main',\n ): Promise<{\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n }> {\n const r = await this.client.console<{\n error?: string;\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n branch?: string;\n }>('POST', '/applications/repo/connect', {\n body: { application: applicationId, repoUrl, branch },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n return r;\n }\n\n /**\n * Upload a gzipped tarball of the project source. The endpoint lands it in the\n * application's `SourcePath` and bumps `ConfigRevision` (the reconciler then\n * builds it in a release dir exactly as for a git deploy).\n *\n * `POST /applications/deploy` — NEW endpoint (see `backend/` in this repo).\n */\n async uploadSource(target: string | CreateOnDeploy, tarball: Uint8Array): Promise<DeployResult> {\n const query: Record<string, string> =\n typeof target === 'string'\n ? { application: target }\n : {\n host: target.host,\n folder: target.folder ?? '',\n runtime: target.runtime,\n ...(target.runtimeVersion ? { runtimeVersion: target.runtimeVersion } : {}),\n ...(target.preset ? { preset: target.preset } : {}),\n ...(target.command ? { command: target.command } : {}),\n public: target.public === false ? '0' : '1',\n };\n const r = await this.client.console<DeployResult>('POST', '/applications/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Upload failed.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface SessionGrant {\n session_token: string;\n refresh_token?: string;\n expires_in?: number;\n status?: string;\n}\n\nexport interface RoxyonUser {\n objectId: string;\n Email?: string;\n Username?: string;\n Name?: string;\n Currency?: string;\n Language?: string;\n [k: string]: unknown;\n}\n\nexport interface LoginPrecheck {\n ok?: boolean;\n error?: string;\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\nexport interface LoginResult {\n sessionToken: string;\n refreshToken?: string;\n expiresIn?: number;\n /** True when an OTP code is still required — call {@link AuthApi.verifyOtp}. */\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\n/**\n * Wraps the console's login flow:\n * 1. `POST /_account/login-precheck` — validates credentials, decides whether\n * an OTP step-up is required, and (when it is) returns a `challengeId`.\n * 2a. no step-up -> `POST /Auth/login` finalises and returns a session token.\n * 2b. step-up -> caller collects the code, then `POST /Auth/login/otp-verify`.\n *\n * Mirrors `signin.view` / `otp.view` in `console.roxyon.com`.\n */\nexport class AuthApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /**\n * Best-effort device/step-up precheck. `/_account/login-precheck` is a console\n * cloud function that may be gated behind the REST key (not reachable from a\n * public client) — in that case this resolves to `{}` and login falls back to\n * `/Auth/login`, which is itself the security boundary and re-checks the\n * device. Only a definitive `{ ok: false }` / `stepUpRequired` is acted on.\n */\n async precheck(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginPrecheck> {\n try {\n const r = await this.client.post<LoginPrecheck & { code?: number }>(\n '/_account/login-precheck',\n { Email: email, Password: password, metadata },\n { tolerateHttpError: true },\n );\n // Endpoint not available to this client — ignore, let /Auth/login decide.\n if (r?.code === 401 || (r?.error && /rest api key/i.test(r.error))) return {};\n return r ?? {};\n } catch {\n return {};\n }\n }\n\n /**\n * Full login. Returns a session token on success, or `stepUpRequired` with a\n * `challengeId` when an OTP code is needed next.\n */\n async login(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginResult> {\n const pre = await this.precheck(email, password, metadata);\n if (pre.ok === false && pre.error && !pre.stepUpRequired) {\n throw new RoxyonApiError(pre.error, { type: 'CredentialsError' });\n }\n if (pre.stepUpRequired) {\n return { sessionToken: '', stepUpRequired: true, challengeId: pre.challengeId };\n }\n\n const grant = await this.client.post<\n SessionGrant & { error?: string; stepUpRequired?: boolean; challengeId?: string }\n >('/Auth/login', { Email: email, Password: password, metadata }, { tolerateHttpError: true });\n\n // Some accounts step up at /Auth/login itself rather than at precheck.\n if (grant?.stepUpRequired || (grant?.challengeId && !grant.session_token)) {\n return { sessionToken: '', stepUpRequired: true, challengeId: grant.challengeId };\n }\n if (!grant?.session_token) {\n throw new RoxyonApiError(grant?.error || 'Wrong email or password.', {\n type: 'CredentialsError',\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Complete an OTP step-up with the code the user received. */\n async verifyOtp(challengeId: string, code: string): Promise<LoginResult> {\n const grant = await this.client.post<SessionGrant & { error?: string }>(\n '/Auth/login/otp-verify',\n { challengeId, code },\n { tolerateHttpError: true },\n );\n if (grant?.status !== 'authenticated' || !grant.session_token) {\n throw new RoxyonApiError(grant?.error || 'That code did not verify.', {\n type: 'OtpError',\n body: grant,\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Start an OTP-only sign-in (no password). Returns a `challengeId`. */\n async startOtp(email: string): Promise<{ challengeId: string }> {\n const r = await this.client.post<{ challengeId?: string; error?: string }>(\n '/Auth/login/otp',\n { Email: email },\n { tolerateHttpError: true },\n );\n if (!r?.challengeId) {\n throw new RoxyonApiError(r?.error || 'Could not start OTP sign-in.', { body: r });\n }\n return { challengeId: r.challengeId };\n }\n\n /** The currently authenticated user. Requires a session token on the client. */\n async me(): Promise<RoxyonUser> {\n const user = await this.client.post<RoxyonUser & { error?: string }>('/Auth/me', {});\n if (!user?.objectId) {\n throw new RoxyonApiError(user?.error || 'Not signed in.', { status: 401, body: user });\n }\n return user;\n }\n\n async logout(): Promise<void> {\n await this.client.post('/Auth/logout', {}, { tolerateHttpError: true }).catch(() => undefined);\n this.client.setSessionToken(undefined);\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** Billing cycles the checkout accepts (Pricing::CYCLE_MONTHS). */\nexport const BILLING_CYCLES = ['monthly', 'quarterly', 'yearly', 'biennial'] as const;\nexport type BillingCycle = (typeof BILLING_CYCLES)[number];\n\n// Plans of this service are resellers' private resold copies, never the public catalog\n// (same filter as the console's own bootstrap).\nconst RESELLER_RESOLD_SERVICE_ID = 'bjMqdLqAKl';\n\nexport interface CatalogProduct {\n /** Plan objectId: what quotes and orders take. */\n planId: string;\n /** Plan code, e.g. `SCALE-S`. */\n sku: string;\n name: string;\n /** Service type, e.g. `cloud.vps.scale`, `cloud.hosting.solo`. */\n category: string;\n vcpu?: number;\n ramGb?: number;\n diskGb?: number;\n cpuType?: string;\n /** Dedicated IPv4 addresses included (servers). */\n ipv4Included?: number;\n /** List prices in USD before tax, per cycle. Quote for the buyer's currency and tax. */\n pricesUSD: Partial<Record<BillingCycle, number>>;\n /** Setup fee in USD per cycle, when not zero. */\n setupFeeUSD?: Partial<Record<BillingCycle, number>>;\n /** `out` = cannot be ordered right now. */\n stock: 'in' | 'out';\n /** Feature table as the console shows it. */\n features?: Record<string, unknown>;\n}\n\nexport interface QuoteInput {\n planId: string;\n cycle: BillingCycle;\n /** ISO 4217, e.g. `SAR`. Default USD. */\n currency?: string;\n /** ISO 3166 alpha-2, decides tax (e.g. `SA` = 15% VAT). Empty = no tax line. */\n country?: string;\n}\n\nexport interface Quote {\n planId: string;\n cycle: string;\n currency: string;\n lineItems: Array<{ label: string; amount: string; amountUSD: string }>;\n subtotal: string;\n taxRate: string;\n taxLabel: string;\n taxAmount: string;\n discountAmount: string;\n total: string;\n fxRate: string;\n baseAmountUSD: string;\n}\n\nexport interface OrderInput {\n /** Plan code from the catalog, e.g. `SCALE-S`. */\n sku: string;\n cycle: BillingCycle;\n /** A name for the service. */\n name: string;\n /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */\n username: string;\n /** Servers only: OS image, e.g. `ubuntu-24.04`. */\n image?: string;\n sshKey?: string;\n phpVersion?: string;\n datacenter?: string;\n currency?: string;\n country?: string;\n /** false/absent = dry run (quote + budget check, nothing written). */\n confirm?: boolean;\n}\n\nexport interface OrderBudget {\n monthlyUSD: number;\n spentUSD: number;\n remainingUSD: number;\n}\n\nexport interface OrderResult {\n dryRun?: boolean;\n plan: { id: string; sku: string; name: string; kind: 'hosting' | 'server'; cycle: string };\n /** Dry run: the server quote (same shape as GET /_payment/quote). */\n quote?: Record<string, unknown>;\n subscriptionId?: string;\n invoiceId?: string;\n total?: string;\n currency?: string;\n payUrl?: string;\n /** null for a console session (no token budget). */\n budget: OrderBudget | null;\n}\n\nexport interface BillingSubscription {\n id: string;\n name: string;\n status: string;\n plan: string;\n sku: string;\n cycle: string;\n price: string;\n currency: string;\n nextBillingDate: string | null;\n autoRenew: boolean;\n serverState: string | null;\n publicIp: string | null;\n}\n\nexport interface Invoice {\n id: string;\n number: string;\n type: string;\n status: string;\n total: string;\n currency: string;\n dueDate: string | null;\n subscription: string | null;\n createdAt: string;\n payUrl: string | null;\n}\n\n/** Invoice statuses a customer can still pay. */\nexport const PAYABLE_STATUSES = ['pending', 'overdue', 'failed'] as const;\n\nexport function isPayable(status: string): boolean {\n return (PAYABLE_STATUSES as readonly string[]).includes(status.toLowerCase());\n}\n\nfunction json<T>(v: unknown, fallback: T): T {\n if (v && typeof v === 'object') return v as T;\n if (typeof v !== 'string' || v === '') return fallback;\n try {\n return JSON.parse(v) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction numbers(v: unknown): Partial<Record<BillingCycle, number>> {\n const out: Partial<Record<BillingCycle, number>> = {};\n const src = json<Record<string, unknown>>(v, {});\n for (const c of BILLING_CYCLES) {\n const n = Number(src[c]);\n if (src[c] !== undefined && src[c] !== '' && Number.isFinite(n)) out[c] = n;\n }\n return out;\n}\n\ninterface PlanRow {\n objectId: string;\n Name?: string;\n Code?: string;\n Limits?: unknown;\n Features?: unknown;\n _Service?: { results?: Array<{ Type?: string }> };\n _Pricing?: {\n results?: Array<{\n Prices?: unknown;\n SetupFee?: unknown;\n MetaData?: unknown;\n IsActive?: unknown;\n }>;\n };\n}\n\n/**\n * Catalog + quotes (public, no sign-in) and the caller's own subscriptions + invoices\n * (console, session or PAT). Read-only: nothing here creates orders or invoices.\n */\nexport class BillingApi {\n constructor(\n private readonly client: RoxyonClient,\n private readonly pub: RoxyonClient = client.publicClient(),\n ) {}\n\n async catalog(): Promise<CatalogProduct[]> {\n const r = await this.pub.get<{ results?: PlanRow[]; error?: string }>('/Plans', {\n fields: '*',\n limit: -1,\n order: 'objectId',\n where: { Status: 'active', Service: { nin: RESELLER_RESOLD_SERVICE_ID } },\n include: [\n { className: 'Services', field: 'Service', fields: 'Type' },\n {\n className: 'Pricing',\n field: 'Plan',\n fields: 'Prices,SetupFee,MetaData,IsActive',\n reverse: 1,\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load the catalog.', { body: r });\n }\n const out: CatalogProduct[] = [];\n for (const p of r.results) {\n const pricing = p._Pricing?.results?.[0];\n // Same rule as roxyon.com's pricing page: a plan code, an active Pricing row, a monthly price.\n if (!p.Code || !pricing || Number(pricing.IsActive) === 0) continue;\n const limits = json<Record<string, unknown>>(p.Limits, {});\n const features = json<Record<string, unknown>>(p.Features, {});\n const meta = json<Record<string, unknown>>(pricing.MetaData, {});\n const network = json<Record<string, unknown>>(features.Network, {});\n const setup = numbers(pricing.SetupFee);\n const pricesUSD = numbers(pricing.Prices);\n if (pricesUSD.monthly === undefined) continue;\n const product: CatalogProduct = {\n planId: p.objectId,\n sku: p.Code ?? '',\n name: p.Name ?? '',\n category: p._Service?.results?.[0]?.Type ?? '',\n pricesUSD,\n stock: String(meta.stock ?? 'in').toLowerCase() === 'out' ? 'out' : 'in',\n };\n if (limits.vcpu != null) {\n product.vcpu = Number(limits.vcpu);\n product.ramGb = limits.memory_mb ? Math.round(Number(limits.memory_mb) / 1024) : 0;\n product.diskGb = Number(limits.disk_gb ?? 0);\n product.cpuType = String(limits.cpu_type ?? '');\n }\n if (network['Dedicated IPv4'] != null)\n product.ipv4Included = Number(network['Dedicated IPv4']);\n if (Object.values(setup).some((n) => n > 0)) product.setupFeeUSD = setup;\n if (Object.keys(features).length) product.features = features;\n out.push(product);\n }\n return out;\n }\n\n /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */\n async quote(input: QuoteInput): Promise<Quote> {\n if (!/^[A-Za-z0-9]{1,40}$/.test(input.planId))\n throw new Error(`Invalid planId \"${input.planId}\".`);\n if (!BILLING_CYCLES.includes(input.cycle))\n throw new Error(`Unsupported cycle \"${input.cycle}\".`);\n const q: Record<string, string | number> = {\n type: 'subscription.new',\n planId: input.planId,\n cycle: input.cycle,\n setup: 1,\n };\n if (input.currency) q.currency = input.currency.toUpperCase();\n if (input.country) q.country = input.country.toUpperCase();\n const r = await this.pub.get<\n Partial<Quote> & { ok?: boolean; error?: string; baseAmount?: string }\n >('/_payment/quote', q);\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not price this plan.', { body: r });\n return {\n planId: String(r.planId ?? input.planId),\n cycle: String(r.cycle ?? input.cycle),\n currency: String(r.currency ?? ''),\n lineItems: (r.lineItems ?? []).map((l) => ({\n label: l.label,\n amount: l.amount,\n amountUSD: l.amountUSD,\n })),\n subtotal: String(r.subtotal ?? ''),\n taxRate: String(r.taxRate ?? ''),\n taxLabel: String(r.taxLabel ?? ''),\n taxAmount: String(r.taxAmount ?? ''),\n discountAmount: String(r.discountAmount ?? ''),\n total: String(r.total ?? ''),\n fxRate: String(r.fxRate ?? ''),\n baseAmountUSD: String(r.baseAmount ?? ''),\n };\n }\n\n /**\n * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it\n * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the\n * `billing:order` scope, within that token's monthly budget and allowed SKUs.\n */\n async order(input: OrderInput): Promise<OrderResult> {\n const r = await this.client.console<\n Partial<OrderResult> & { ok?: boolean; error?: string; budget?: OrderBudget }\n >('POST', '/account/order', { body: input, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'The order was not placed.', { body: r });\n return r as OrderResult;\n }\n\n /** The caller's own subscriptions (rows they own), newest first. */\n async subscriptions(): Promise<BillingSubscription[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n subscriptions?: BillingSubscription[];\n }>('GET', '/account/subscriptions', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load subscriptions.', { body: r });\n return r.subscriptions ?? [];\n }\n\n /** The caller's own invoices, newest first. */\n async invoices(opts: { status?: string; limit?: number } = {}): Promise<Invoice[]> {\n const q: Record<string, string> = {};\n if (opts.status) q.status = opts.status;\n if (opts.limit) q.limit = String(opts.limit);\n const r = await this.client.console<{ ok?: boolean; error?: string; invoices?: Invoice[] }>(\n 'GET',\n '/account/invoices',\n { tolerateHttpError: true, query: q },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load invoices.', { body: r });\n // Only an open invoice can be paid (the first console release also linked void ones).\n return (r.invoices ?? []).map((i) => ({ ...i, payUrl: isPayable(i.status) ? i.payUrl : null }));\n }\n}\n","/**\n * Default endpoints and the public application credentials the client uses to\n * mint an anonymous token before a user logs in.\n *\n * `X-BEA-JavaScript-Key` is a **public** key (it ships in browser bundles by\n * design — see `console.roxyon.com/src/index.js`). It is safe to embed here.\n * The REST key is never embedded — user actions always run under a session\n * token or a Personal Access Token.\n *\n * TODO(M1): provision a dedicated `roxyon-cli` BaaS application and swap these\n * for its App-ID / JavaScript-Key so CLI traffic is attributable and rate-limited\n * separately from the web console. Until then the client reuses the console's\n * public pair, which is already exposed in shipped frontend code.\n */\nexport const DEFAULT_BAAS_URL = 'https://www.beaapis.com/1';\nexport const DEFAULT_CONSOLE_URL = 'https://console.roxyon.com';\n\nexport const DEFAULT_APP = {\n appId: 'jAtp2zHGU3FbnrQWrToALFakd_vbiY0ywihn4Hj54lw',\n javascriptKey: 'w2Y9USRg0COtNe-fUqOaC1OOOlNCnV2BG8GZF80w4x8',\n} as const;\n\n/** Header names, lower-cased (the API is case-insensitive but the SDK uses these). */\nexport const H = {\n appId: 'x-bea-application-id',\n jsKey: 'x-bea-javascript-key',\n restKey: 'x-bea-authorization',\n sessionToken: 'x-bea-session-token',\n accessToken: 'x-bea-access-token',\n refreshToken: 'x-bea-refresh-token',\n} as const;\n","/**\n * GET query serialisation for the BaaS, matching the `Obj2Par` helper in the\n * browser SDK (`rx.js`): nested objects become PHP-style bracket keys\n * (`where[User]=abc`, `where[Status][in]=a,b,c`).\n *\n * Two hard-won rules (see the `roxyon-api-write-failures` notes):\n * - The `in` operator takes a **comma-joined string, not an array**. An array\n * serialises to `where[X][in][0]=…` bracket notation the API does not read.\n * Pass `{ in: ['a', 'b'] }` here and we join it for you.\n * - A `select` subquery nested inside an `or` group crashes the API. Resolve\n * ids in a first query, then `or: [..., { objectId: { in: 'a,b' } }]`.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | { [k: string]: QueryValue };\n\nexport type QueryObject = Record<string, QueryValue>;\n\nfunction encode(k: string, v: string): string {\n return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;\n}\n\nfunction walk(value: QueryValue, prefix: string, out: string[]): void {\n if (value === null || value === undefined) return;\n\n if (Array.isArray(value)) {\n // A bare array under a normal key -> repeated bracket-index entries. The\n // only array we actually want is `in`, and that is handled below before we\n // ever get here, so this branch is a best-effort fallback.\n value.forEach((item, i) => walk(item, `${prefix}[${i}]`, out));\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n if (key === 'in' || key === 'nin' || key === 'notIn') {\n const joined = Array.isArray(child) ? child.join(',') : String(child);\n out.push(encode(`${prefix}[${key === 'notIn' ? 'nin' : key}]`, joined));\n continue;\n }\n walk(child, `${prefix}[${key}]`, out);\n }\n return;\n }\n\n out.push(encode(prefix, String(value)));\n}\n\n/** Serialise a query object to a `key=value&...` string (no leading `?`). */\nexport function toQueryString(query: QueryObject | undefined): string {\n if (!query) return '';\n const out: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n walk(value, key, out);\n }\n return out.join('&');\n}\n","import { DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, H } from './constants.js';\nimport { RoxyonApiError } from './errors.js';\nimport { type QueryObject, toQueryString } from './query.js';\n\nexport interface RoxyonClientOptions {\n /** BaaS application id. Defaults to the public console app. */\n appId?: string;\n /** Public JavaScript key, used to mint an anonymous token. */\n javascriptKey?: string;\n /** REST API key. Optional; grants full access — only for trusted server use. */\n restKey?: string;\n /** A user session token (from {@link AuthApi.login}). */\n sessionToken?: string;\n /** BaaS REST base, e.g. `https://www.beaapis.com/1`. */\n baseUrl?: string;\n /** Console base that serves the `/applications/*` endpoints. */\n consoleUrl?: string;\n /** Custom fetch (tests / proxies). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n query?: QueryObject;\n body?: unknown;\n headers?: Record<string, string>;\n /** Skip the Authorization/session header entirely (used for token minting). */\n skipAuth?: boolean;\n /** Send/parse the response even on a non-2xx status instead of throwing. */\n tolerateHttpError?: boolean;\n signal?: AbortSignal;\n}\n\ninterface AnonToken {\n access_token?: string;\n session_token?: string;\n refresh_token?: string;\n expires_in?: number;\n /** epoch ms this token becomes unusable */\n _expiresAt?: number;\n}\n\n/**\n * Low-level transport for the Roxyon BaaS and console app endpoints.\n *\n * Auth precedence per request: explicit `sessionToken` -> `restKey` ->\n * a lazily-minted anonymous access token (public app credentials).\n */\nexport class RoxyonClient {\n readonly baseUrl: string;\n readonly consoleUrl: string;\n private readonly appId: string;\n private readonly javascriptKey: string;\n private readonly restKey?: string;\n private readonly _fetch: typeof fetch;\n private sessionToken?: string;\n private anon?: AnonToken;\n\n constructor(opts: RoxyonClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_URL).replace(/\\/+$/, '');\n this.consoleUrl = (opts.consoleUrl ?? DEFAULT_CONSOLE_URL).replace(/\\/+$/, '');\n this.appId = opts.appId ?? DEFAULT_APP.appId;\n this.javascriptKey = opts.javascriptKey ?? DEFAULT_APP.javascriptKey;\n this.restKey = opts.restKey;\n this.sessionToken = opts.sessionToken;\n this._fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this._fetch !== 'function') {\n throw new Error('No fetch implementation available (need Node >= 20 or pass opts.fetch).');\n }\n }\n\n /** Same endpoints and app, no user credentials: for public reads (catalog, quotes)\n * that must work for PAT callers too, whose token the BaaS does not accept. */\n publicClient(): RoxyonClient {\n return new RoxyonClient({\n baseUrl: this.baseUrl,\n consoleUrl: this.consoleUrl,\n appId: this.appId,\n javascriptKey: this.javascriptKey,\n fetch: this._fetch,\n });\n }\n\n getSessionToken(): string | undefined {\n return this.sessionToken;\n }\n\n setSessionToken(token: string | undefined): void {\n this.sessionToken = token;\n }\n\n /** Mint (or reuse) an anonymous access token from the public app credentials. */\n private async anonToken(): Promise<AnonToken> {\n if (this.anon?._expiresAt && this.anon._expiresAt > Date.now() + 5_000) {\n return this.anon;\n }\n const res = await this._fetch(`${this.baseUrl}/Auth`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n [H.appId]: this.appId,\n [H.jsKey]: this.javascriptKey,\n },\n body: JSON.stringify({ scope: 'public' }),\n });\n const json = (await res.json().catch(() => ({}))) as AnonToken;\n if (!json.access_token && !json.session_token) {\n throw new RoxyonApiError('Could not obtain an anonymous BaaS token.', {\n status: res.status,\n body: json,\n });\n }\n json._expiresAt = Date.now() + (json.expires_in ? json.expires_in * 1000 : 3_600_000);\n this.anon = json;\n return json;\n }\n\n /** A Personal Access Token (`roxp_…`) authenticates the console endpoints via\n * `Authorization: Bearer`; it is not a BaaS session token. */\n private get isPat(): boolean {\n return this.sessionToken?.startsWith('roxp_') ?? false;\n }\n\n private async authHeaders(\n skipAuth: boolean,\n isConsole: boolean,\n ): Promise<Record<string, string>> {\n // IMPORTANT: never send X-BEA-Application-ID on an authenticated request.\n // The BaaS `/auth/*` router treats the App-ID header as \"mint me an\n // anonymous token\" and short-circuits — /Auth/login, /Auth/me etc. would\n // silently return a fresh anon token instead of doing their job. The App-ID\n // (+ JS key) is sent only by anonToken()'s own POST /Auth call.\n if (skipAuth) return {};\n if (this.isPat) {\n // Console: Bearer. BaaS: nothing — PAT clients resolve identity and\n // subscriptions through the console's /account/context instead.\n return isConsole ? { authorization: `Bearer ${this.sessionToken}` } : {};\n }\n if (this.sessionToken) return { [H.sessionToken]: this.sessionToken };\n if (this.restKey) return { [H.appId]: this.appId, [H.restKey]: this.restKey };\n const anon = await this.anonToken();\n if (anon.session_token) return { [H.sessionToken]: anon.session_token };\n return { [H.accessToken]: anon.access_token ?? '' };\n }\n\n /** A raw BaaS request. `path` is relative to {@link baseUrl} (leading `/`). */\n async request<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.baseUrl, method, path, opts);\n }\n\n /** A request against the console app endpoints ({@link consoleUrl}). */\n async console<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.consoleUrl, method, path, opts);\n }\n\n private async rawRequest<T>(\n root: string,\n method: string,\n path: string,\n opts: RequestOptions,\n ): Promise<T> {\n const qs = toQueryString(opts.query);\n const url = `${root}${path.startsWith('/') ? path : `/${path}`}${qs ? `?${qs}` : ''}`;\n const headers: Record<string, string> = {\n ...(await this.authHeaders(opts.skipAuth ?? false, root === this.consoleUrl)),\n ...opts.headers,\n };\n const hasBody = method !== 'GET' && method !== 'HEAD' && opts.body !== undefined;\n let body: string | Uint8Array | ArrayBuffer | FormData | undefined;\n if (hasBody) {\n if (\n typeof opts.body === 'string' ||\n opts.body instanceof Uint8Array ||\n opts.body instanceof ArrayBuffer ||\n (typeof FormData !== 'undefined' && opts.body instanceof FormData)\n ) {\n body = opts.body as string | Uint8Array | ArrayBuffer | FormData;\n } else {\n headers['content-type'] = headers['content-type'] ?? 'application/json';\n body = JSON.stringify(opts.body);\n }\n }\n\n let res: Response;\n try {\n res = await this._fetch(url, { method, headers, body, signal: opts.signal });\n } catch (cause) {\n throw new RoxyonApiError(`Network error calling ${method} ${url}`, { body: cause });\n }\n\n const text = await res.text();\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : {};\n } catch {\n // An HTML page means the route isn't served by the API (a console route not deployed yet falls through to\n // the web app): say so instead of handing the page to the caller as an error message.\n const html = /^\\s*</.test(text);\n json = {\n error: html\n ? `${method} ${path} is not available on this server yet (got a web page instead of the API).`\n : text || `HTTP ${res.status}`,\n _raw: html ? '' : text,\n };\n }\n\n if (!res.ok && !opts.tolerateHttpError) {\n const msg =\n (json &&\n typeof json === 'object' &&\n 'error' in json &&\n (json as { error: string }).error) ||\n `HTTP ${res.status} calling ${method} ${path}`;\n throw new RoxyonApiError(String(msg), { status: res.status, body: json });\n }\n return json as T;\n }\n\n get<T = unknown>(path: string, query?: QueryObject, opts?: RequestOptions): Promise<T> {\n return this.request<T>('GET', path, { ...opts, query });\n }\n post<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('POST', path, { ...opts, body });\n }\n put<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', path, { ...opts, body });\n }\n del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', path, { ...opts, body });\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateDatabaseInput {\n /** DB name suffix — the platform prefixes it with the subscription's own username (globally unique). */\n name: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /**\n * `mysql` (default: MySQL/MariaDB on the shared cluster) or `postgres` (PostgreSQL 15 inside the account's own hosting\n * container, at localhost:5432; the first one installs it, a few minutes) or `redis` (one Redis per account, 127.0.0.1:6379,\n * password-protected). Every hosting account has all three.\n */\n engine?: 'mysql' | 'postgres' | 'redis';\n}\n\nexport interface CreateDatabaseResult {\n ok: boolean;\n objectId: string;\n engine?: 'mysql' | 'postgres' | 'redis';\n port?: number;\n /** How to connect (PostgreSQL: the URL shape and the no-password psql login over SSH). */\n note?: string;\n name: string;\n username: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n /** `<node-ip>:6033` — the ProxySQL endpoint to connect the app to. */\n host?: string;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface DatabaseSummary {\n objectId: string;\n Name: string;\n Username: string;\n Status: string;\n /** `postgres` for PostgreSQL; empty or `mysql` for MySQL/MariaDB. */\n Engine?: string;\n}\n\nexport interface DeleteDatabaseResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Databases attached to a subscription: MySQL/MariaDB (shared Galera cluster) or PostgreSQL (in the account's container). */\nexport class DatabasesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */\n async list(subscriptionId: string): Promise<DatabaseSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n databases?: DatabaseSummary[];\n }>('POST', '/databases/list', {\n body: { subscription: subscriptionId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the databases.', { body: r });\n return r.databases ?? [];\n }\n\n /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */\n async create(input: CreateDatabaseInput): Promise<CreateDatabaseResult> {\n const r = await this.client.console<CreateDatabaseResult>('POST', '/databases/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the database.', { body: r });\n return r;\n }\n\n /** `POST /databases/delete` */\n async delete(databaseId: string): Promise<DeleteDatabaseResult> {\n const r = await this.client.console<DeleteDatabaseResult>('POST', '/databases/delete', {\n body: { database: databaseId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the database.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Domain {\n objectId: string;\n Name: string;\n}\n\nexport interface CreateDomainInput {\n /** FQDN to host — a subdomain of a domain the account already hosts, or `*.roxyon.com`. */\n host: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** `spa` → unmatched paths serve `/index.html`; default `static`. */\n siteType?: 'static' | 'spa';\n /** PHP version for the vhost (e.g. `\"8.3\"`). Unknown/omitted falls back to the platform default. */\n phpVersion?: string;\n}\n\nexport interface CreateDomainResult {\n ok: boolean;\n objectId: string;\n host: string;\n /** `subdomain` of an owned parent, or `primary`. */\n type: 'subdomain' | 'primary';\n /** `provisioning` while DNS/vhost/TLS come up, then `active` (or `failed`). */\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\n/** Domains (hosts) attached to a subscription. */\nexport class DomainsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Domain[]> {\n const r = await this.client.get<{ results?: Domain[] }>('/Domains', {\n fields: 'objectId,Name',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n /**\n * `POST /domains/create` — provision a subdomain (DNS + vhost + auto-TLS). The\n * server decides subdomain vs primary from the caller's existing hosts and\n * writes the `pending` row; the platform's reconciler does the rest.\n */\n async create(input: CreateDomainInput): Promise<CreateDomainResult> {\n const r = await this.client.console<CreateDomainResult>('POST', '/domains/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the domain.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateEmailInput {\n /** The part before `@`. */\n localPart: string;\n /** A hostname already on the account. */\n domain: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /** Mailbox quota in MB. Default 1024. */\n quota?: number;\n forwardTo?: string;\n saveCopy?: boolean;\n}\n\nexport interface CreateEmailResult {\n ok: boolean;\n objectId: string;\n email: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n quota?: number;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface EmailSummary {\n objectId: string;\n Email: string;\n LocalPart: string;\n Status: string;\n Quota?: number;\n}\n\nexport interface DeleteEmailResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Mailboxes attached to a subscription's domains. */\nexport class EmailApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */\n async list(subscriptionId: string): Promise<EmailSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n emails?: Omit<EmailSummary, 'LocalPart'>[];\n }>('POST', '/emails/list', { body: { subscription: subscriptionId }, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the mailboxes.', { body: r });\n return (r.emails ?? []).map((e) => ({ ...e, LocalPart: e.Email.split('@')[0] ?? '' }));\n }\n\n /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */\n async create(input: CreateEmailInput): Promise<CreateEmailResult> {\n const r = await this.client.console<CreateEmailResult>('POST', '/emails/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the mailbox.', { body: r });\n return r;\n }\n\n /** `POST /emails/delete` */\n async delete(emailId: string): Promise<DeleteEmailResult> {\n const r = await this.client.console<DeleteEmailResult>('POST', '/emails/delete', {\n body: { email: emailId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the mailbox.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface StaticDeployResult {\n ok: boolean;\n host: string;\n path: string;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\nexport interface DeployOptions {\n /** Replace the docroot contents instead of overlaying (keeps `.well-known`). */\n clean?: boolean;\n /** Flip the host to SPA routing: unmatched paths serve `/index.html`. */\n spa?: boolean;\n}\n\nexport interface SiteFile {\n /** POSIX path relative to the site root. */\n path: string;\n size: number;\n type: 'file' | 'dir';\n}\n\nexport interface SiteFileContent {\n path: string;\n size: number;\n encoding: 'utf8' | 'base64';\n content: string;\n}\n\n/**\n * Static-site hosting: the files under a host's document root\n * (`public_html[/<folder>]`), served directly by nginx. No Application row, no\n * process. All routes go to the console (`POST /sites/deploy`, `GET /sites/files`,\n * `GET /sites/file`) and authenticate with a session token or a `roxp_` PAT.\n */\nexport class SitesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** Upload a gzip tarball into `host`'s docroot (+ optional sub-`folder`). */\n async deploy(\n host: string,\n folder: string,\n tarball: Uint8Array,\n opts: DeployOptions = {},\n ): Promise<StaticDeployResult> {\n const query: Record<string, string> = { host, folder };\n if (opts.clean) query.clean = '1';\n if (opts.spa) query.spa = '1';\n const r = await this.client.console<StaticDeployResult>('POST', '/sites/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Static deploy failed.', { body: r });\n return r;\n }\n\n /** List the files currently in `host`'s docroot (optionally under `path`). */\n async listFiles(host: string, folder = '', path = ''): Promise<SiteFile[]> {\n const r = await this.client.console<{ ok?: boolean; files?: SiteFile[]; error?: string }>(\n 'GET',\n '/sites/files',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list site files.', { body: r });\n return r.files ?? [];\n }\n\n /** Read one file from `host`'s docroot. */\n async readFile(host: string, folder: string, path: string): Promise<SiteFileContent> {\n const r = await this.client.console<SiteFileContent & { ok?: boolean; error?: string }>(\n 'GET',\n '/sites/file',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok || typeof r.content !== 'string') {\n throw new RoxyonApiError(r?.error || 'Could not read the file.', { body: r });\n }\n return { path: r.path, size: r.size, encoding: r.encoding, content: r.content };\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface ResetSshPasswordInput {\n /** Subscription to reset. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one meeting the strength rules. */\n password?: string;\n}\n\nexport interface ResetSshPasswordResult {\n ok: boolean;\n subscription: string;\n /** Shown once — the platform never stores or re-shows it. */\n password: string;\n status: 'pending' | 'active' | 'failed';\n}\n\n/**\n * The shared shell password used for SSH, SFTP and the file manager on a\n * subscription's container (SSHpiper maps the username to the container).\n */\nexport class SshApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /ssh/password` */\n async resetPassword(input: ResetSshPasswordInput = {}): Promise<ResetSshPasswordResult> {\n const r = await this.client.console<ResetSshPasswordResult>('POST', '/ssh/password', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) {\n throw new RoxyonApiError(\n (r as { error?: string })?.error || 'Could not reset the password.',\n {\n body: r,\n },\n );\n }\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Subscription {\n objectId: string;\n Name?: string;\n Status?: string;\n [k: string]: unknown;\n}\n\nexport interface Privilege {\n objectId: string;\n Type?: string;\n Subscription?: string;\n _Subscription?: { results: Subscription[] };\n [k: string]: unknown;\n}\n\ninterface ListResponse<T> {\n results?: T[];\n error?: string;\n}\n\n/** Access to the caller's subscriptions (via their Privileges rows). */\nexport class SubscriptionsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** All subscriptions the signed-in user has a Privilege on. */\n async list(userId: string): Promise<Subscription[]> {\n const r = await this.client.get<ListResponse<Privilege>>('/Privileges', {\n where: { User: userId },\n fields: 'objectId,Type,Subscription',\n limit: -1,\n include: [\n {\n className: 'Subscriptions',\n field: 'Subscription',\n fields: 'objectId,Name,Status',\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load subscriptions.', {\n status: 401,\n body: r,\n });\n }\n const subs: Subscription[] = [];\n for (const priv of r.results) {\n const sub = priv._Subscription?.results?.[0];\n if (sub) subs.push(sub);\n }\n return subs;\n }\n\n /**\n * Resolve the subscription to act on. Prefers an exact `objectId` or `Name`\n * match against `preferred`; otherwise the first active subscription; otherwise\n * the first one. Throws when the account has none.\n */\n async resolve(userId: string, preferred?: string): Promise<Subscription> {\n const subs = await this.list(userId);\n if (subs.length === 0) {\n throw new RoxyonApiError(\n 'This account has no active subscription — add a plan in the console first.',\n );\n }\n if (preferred) {\n const hit = subs.find(\n (s) => s.objectId === preferred || s.Name === preferred || s.Username === preferred,\n );\n if (hit) return hit;\n throw new RoxyonApiError(`No subscription matches \"${preferred}\".`);\n }\n return subs.find((s) => s.Status === 'active') ?? subs[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */\nexport type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';\n\nexport interface TokenSummary {\n id: string;\n name: string;\n prefix: string;\n scopes: TokenScope[];\n lastUsedAt: string | null;\n expiresAt: string | null;\n createdAt: string;\n /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */\n monthlyBudgetUSD?: number | null;\n /** For `billing:order` tokens: plan codes it may order (empty = any). */\n allowedSkus?: string[];\n}\n\nexport interface CreatedToken {\n /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */\n token: string;\n name: string;\n scopes: TokenScope[];\n expiresAt: string | null;\n}\n\n/**\n * Personal Access Tokens — for the CLI in CI and for the MCP server running\n * headless. Managed only while signed in with a session (`roxyon login`); a PAT\n * cannot mint or revoke another PAT.\n *\n * `GET/POST/DELETE /account/tokens` — console endpoints.\n */\nexport class TokensApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(): Promise<TokenSummary[]> {\n const r = await this.client.console<{ ok?: boolean; tokens?: TokenSummary[]; error?: string }>(\n 'GET',\n '/account/tokens',\n { tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list tokens.', { body: r });\n return r.tokens ?? [];\n }\n\n async create(\n name: string,\n opts: {\n scopes?: TokenScope[];\n expiresInDays?: number;\n /** Required with `billing:order`. */\n monthlyBudgetUSD?: number;\n allowedSkus?: string[];\n } = {},\n ): Promise<CreatedToken> {\n const r = await this.client.console<CreatedToken & { ok?: boolean; error?: string }>(\n 'POST',\n '/account/tokens',\n {\n body: {\n name,\n scopes: opts.scopes ?? ['deploy', 'logs'],\n ...(opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {}),\n ...(opts.monthlyBudgetUSD ? { monthlyBudgetUSD: opts.monthlyBudgetUSD } : {}),\n ...(opts.allowedSkus?.length ? { allowedSkus: opts.allowedSkus } : {}),\n },\n tolerateHttpError: true,\n },\n );\n if (!r?.ok || !r.token) {\n throw new RoxyonApiError(r?.error || 'Could not create the token.', { body: r });\n }\n return { token: r.token, name: r.name, scopes: r.scopes, expiresAt: r.expiresAt ?? null };\n }\n\n async revoke(id: string): Promise<void> {\n const r = await this.client.console<{ ok?: boolean; error?: string }>(\n 'DELETE',\n '/account/tokens',\n { query: { id }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not revoke the token.', { body: r });\n }\n}\n","import { RoxyonApiError } from './errors.js';\n\n/** BaaS V2 base. V1 (`/1`) is frozen; app data tools speak V2 only. */\nexport const DEFAULT_BAAS_V2_URL = 'https://www.beaapis.com/2';\n\n/** V2 caps one page at 200 rows. */\nexport const BAAS_MAX_PAGE = 200;\n/** V2 takes 1 to 50 requests per batch. */\nexport const BAAS_MAX_BATCH = 50;\n\nexport interface BaasDataOptions {\n /** The app's secret key (`rxsk_…`): server scope, from the project's API keys in Roxyon Base. */\n secretKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\nexport type BaasRow = Record<string, unknown>;\n\nexport interface BaasQuery {\n /** e.g. `{ Status: 'active', Age: { gt: 18 } }`; `in` takes a comma-joined string. */\n where?: Record<string, unknown>;\n /** `*` and/or column names, comma separated. Defaults to `*`. */\n fields?: string;\n /** Comma list, `-` for descending, e.g. `-createdAt`. */\n order?: string;\n /** 1 to 200 (default 50). */\n limit?: number;\n skip?: number;\n /** Also return the total number of matching rows. */\n count?: boolean;\n}\n\nexport interface BaasBatchRequest {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n /** `/Class` or `/Class/<id>`. */\n path: string;\n body?: Record<string, unknown>;\n}\n\n/** One batch answer: `ok:false` with `error`/`message`, or that request's own V2 answer. */\nexport interface BaasBatchResult {\n status: number;\n ok?: boolean;\n error?: string;\n message?: string;\n result?: BaasRow;\n results?: BaasRow[];\n count?: number;\n id?: string;\n}\n\ninterface V2Body {\n ok?: boolean;\n error?: string;\n message?: string;\n details?: unknown;\n result?: BaasRow;\n results?: unknown[];\n count?: number;\n id?: string;\n}\n\n// Mirrors App.php: classes `^[A-Za-z][A-Za-z0-9_]{0,63}$` (no `_` system classes), ids `^[A-Za-z0-9]{1,40}$`.\nconst CLASS_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID_RE = /^[A-Za-z0-9]{1,40}$/;\n\nfunction checkClass(name: string): string {\n if (!CLASS_RE.test(name)) throw new Error(`Invalid class name \"${name}\".`);\n return name;\n}\n\nfunction checkId(id: string): string {\n if (!ID_RE.test(id)) throw new Error(`Invalid objectId \"${id}\".`);\n return id;\n}\n\n/**\n * Records of ONE app on BaaS V2, as that app's own backend (server scope, `X-RX-Secret-Key`).\n * Server scope passes every class rule, so treat the key like a database password. V2 answers\n * failures as `{ok:false, error, message}` with an HTTP status; every call throws on those.\n * Schema changes are not reachable with a secret key (console API only).\n */\nexport class BaasDataApi {\n private readonly baseUrl: string;\n private readonly secretKey: string;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: BaasDataOptions) {\n if (!opts.secretKey.startsWith('rxsk_')) {\n throw new Error('BaaS V2 needs the app secret key (starts with rxsk_).');\n }\n this.secretKey = opts.secretKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_V2_URL).replace(/\\/+$/, '');\n this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n private async call(\n method: string,\n path: string,\n opts: { query?: Record<string, string>; body?: unknown } = {},\n ): Promise<V2Body> {\n const qs =\n opts.query && Object.keys(opts.query).length ? `?${new URLSearchParams(opts.query)}` : '';\n const headers: Record<string, string> = { 'x-rx-secret-key': this.secretKey };\n if (opts.body !== undefined) headers['content-type'] = 'application/json';\n let res: Response;\n try {\n res = await this._fetch(`${this.baseUrl}${path}${qs}`, {\n method,\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n });\n } catch (e) {\n throw new RoxyonApiError(`Could not reach ${this.baseUrl}: ${(e as Error).message}`);\n }\n let body: V2Body = {};\n try {\n body = ((await res.json()) as V2Body) ?? {};\n } catch {\n // Non-JSON (proxy error page): handled below.\n }\n if (!res.ok || body.ok !== true) {\n const msg = body.message || body.error || `HTTP ${res.status}`;\n throw new RoxyonApiError(msg, { status: res.status, type: body.error, body });\n }\n return body;\n }\n\n private static recordPath(className: string, id?: string): string {\n return `/records/${checkClass(className)}${id === undefined ? '' : `/${checkId(id)}`}`;\n }\n\n async query(className: string, q: BaasQuery = {}): Promise<{ rows: BaasRow[]; count?: number }> {\n const limit = q.limit ?? 50;\n if (!Number.isInteger(limit) || limit < 1 || limit > BAAS_MAX_PAGE) {\n throw new Error(`limit must be 1 to ${BAAS_MAX_PAGE}.`);\n }\n const query: Record<string, string> = { fields: q.fields || '*', limit: String(limit) };\n // V2 takes where as JSON text, so operators and `in` strings survive unchanged.\n if (q.where && Object.keys(q.where).length) query.where = JSON.stringify(q.where);\n if (q.order) query.order = q.order;\n if (q.skip) query.skip = String(q.skip);\n if (q.count) query.count = '1';\n const r = await this.call('GET', BaasDataApi.recordPath(className), { query });\n return {\n rows: (r.results ?? []) as BaasRow[],\n ...(r.count !== undefined ? { count: r.count } : {}),\n };\n }\n\n async get(className: string, objectId: string): Promise<BaasRow> {\n const r = await this.call('GET', BaasDataApi.recordPath(className, objectId));\n return r.result ?? {};\n }\n\n /** Returns the created row as stored. */\n async create(className: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('POST', BaasDataApi.recordPath(className), { body: { data } });\n return r.result ?? {};\n }\n\n async update(className: string, objectId: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('PUT', BaasDataApi.recordPath(className, objectId), {\n body: { data },\n });\n return r.result ?? {};\n }\n\n /** The id goes in the URL path, never the body. */\n async delete(className: string, objectId: string): Promise<void> {\n await this.call('DELETE', BaasDataApi.recordPath(className, objectId));\n }\n\n /** 1 to 50 record requests in one call; one failing doesn't stop the others. */\n async batch(requests: BaasBatchRequest[]): Promise<BaasBatchResult[]> {\n if (requests.length < 1 || requests.length > BAAS_MAX_BATCH) {\n throw new Error(`A batch takes 1 to ${BAAS_MAX_BATCH} requests.`);\n }\n for (const req of requests) {\n const [cls, id, extra] = req.path.split('/').filter(Boolean);\n if (!cls || extra !== undefined)\n throw new Error(`Batch path \"${req.path}\" must be /Class or /Class/id.`);\n checkClass(cls);\n if (id !== undefined) checkId(id);\n }\n const r = await this.call('POST', '/batch', { body: { requests } });\n return (r.results ?? []) as BaasBatchResult[];\n }\n}\n","/**\n * `.env`-style block <-> JSON object, ported verbatim from `appfEnvParse` /\n * `appfEnvToLines` in `console.roxyon.com/.../modals/app_form.view` so the CLI\n * and the console form agree byte-for-byte on what `Applications.Env` holds.\n *\n * The server re-sanitises again (`ApplicationRenderer::envPair`), so this only\n * needs to be reasonable. `PORT` and `HOST` are set by the platform — callers\n * should not write them.\n */\nexport function parseEnv(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (let line of String(text || '').split(/\\r?\\n/)) {\n line = line.trim();\n if (!line || line.startsWith('#')) continue;\n line = line.replace(/^export\\s+/, '');\n const eq = line.indexOf('=');\n if (eq < 1) continue;\n const k = line.slice(0, eq).trim();\n let v = line.slice(eq + 1).trim();\n if (v.length >= 2 && (v[0] === '\"' || v[0] === \"'\") && v[v.length - 1] === v[0]) {\n v = v.slice(1, -1);\n }\n if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) out[k] = v;\n }\n return out;\n}\n\nexport function formatEnv(obj: Record<string, string> | null | undefined): string {\n if (!obj || typeof obj !== 'object') return '';\n return Object.keys(obj)\n .map((k) => `${k}=${obj[k] == null ? '' : String(obj[k])}`)\n .join('\\n');\n}\n\n/** Parse the JSON string stored on `Applications.Env`. */\nexport function envFromStored(jsonStr: string | undefined): Record<string, string> {\n if (!jsonStr) return {};\n try {\n const obj = JSON.parse(jsonStr);\n return obj && typeof obj === 'object' ? (obj as Record<string, string>) : {};\n } catch {\n return {};\n }\n}\n","/**\n * Runtime / version / framework catalog — a verbatim copy of the `RUNTIMES`\n * table in `console.roxyon.com/.../modals/app_form.view`. These are the versions\n * actually installed in the Cloud Hosting containers; offering an uninstalled\n * one produces a deploy that fails at build time for a reason the user cannot\n * act on.\n *\n * TODO(M4): the console form and this file should both import one shared JSON\n * published at `roxyon.com/runtimes.json` so they never drift.\n */\nexport type RuntimeName = 'lumen' | 'node' | 'python' | 'php';\n\nexport interface RuntimeSpec {\n versions: string[];\n defaultVersion: string;\n presets: Array<[value: string, label: string]>;\n command: string;\n}\n\nexport const RUNTIMES: Record<Exclude<RuntimeName, 'lumen'>, RuntimeSpec> = {\n node: {\n versions: ['23.11.1', '22.23.1', '20.20.2', '18.20.8'],\n defaultVersion: '20.20.2',\n presets: [\n ['nextjs', 'Next.js'],\n ['nuxt', 'Nuxt'],\n ['node', 'No framework'],\n ],\n command: 'npm run start',\n },\n python: {\n versions: ['3.11'],\n defaultVersion: '3.11',\n presets: [['python', 'No framework']],\n command: 'gunicorn app:app',\n },\n php: {\n versions: ['8.4', '8.3', '8.2', '8.1', '7.4'],\n defaultVersion: '8.4',\n presets: [\n ['swoole', 'Swoole'],\n ['php', 'No framework'],\n ],\n command: 'php8.4 server.php',\n },\n};\n\n/**\n * A LumenJS project (`runtime: \"lumen\"`) builds to static files with\n * `lm build --serverless` and is served straight from the host's document root\n * by nginx — no long-running process, no systemd unit, no Application row. It\n * deploys through the \"static\" path (upload the built `dist/` to\n * `/home/www/<host>/public_html[/<folder>]`).\n *\n * Node / Python / PHP projects deploy through the \"app\" path (the Applications\n * system: upload source, bump ConfigRevision, reconciler builds + runs it).\n */\nexport type DeployKind = 'static' | 'app';\n\nexport const LUMEN_BUILD = {\n command: 'lm build --serverless',\n /** Directory `lm build --serverless` writes to, relative to the project root. */\n outDir: 'dist',\n} as const;\n"],"mappings":"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","names":["json"]}
package/dist/index.d.cts CHANGED
@@ -531,10 +531,20 @@ interface CreateDatabaseInput {
531
531
  subscription?: string;
532
532
  /** Omit to have the platform generate one. */
533
533
  password?: string;
534
+ /**
535
+ * `mysql` (default: MySQL/MariaDB on the shared cluster) or `postgres` (PostgreSQL 15 inside the account's own hosting
536
+ * container, at localhost:5432; the first one installs it, a few minutes) or `redis` (one Redis per account, 127.0.0.1:6379,
537
+ * password-protected). Every hosting account has all three.
538
+ */
539
+ engine?: 'mysql' | 'postgres' | 'redis';
534
540
  }
535
541
  interface CreateDatabaseResult {
536
542
  ok: boolean;
537
543
  objectId: string;
544
+ engine?: 'mysql' | 'postgres' | 'redis';
545
+ port?: number;
546
+ /** How to connect (PostgreSQL: the URL shape and the no-password psql login over SSH). */
547
+ note?: string;
538
548
  name: string;
539
549
  username: string;
540
550
  /** Shown once — not retrievable afterwards. */
@@ -549,6 +559,8 @@ interface DatabaseSummary {
549
559
  Name: string;
550
560
  Username: string;
551
561
  Status: string;
562
+ /** `postgres` for PostgreSQL; empty or `mysql` for MySQL/MariaDB. */
563
+ Engine?: string;
552
564
  }
553
565
  interface DeleteDatabaseResult {
554
566
  ok: boolean;
@@ -556,7 +568,7 @@ interface DeleteDatabaseResult {
556
568
  status: 'deleting' | 'deleted' | 'failed';
557
569
  error?: string;
558
570
  }
559
- /** Databases (MySQL/MariaDB on the shared Galera cluster) attached to a subscription. */
571
+ /** Databases attached to a subscription: MySQL/MariaDB (shared Galera cluster) or PostgreSQL (in the account's container). */
560
572
  declare class DatabasesApi {
561
573
  private readonly client;
562
574
  constructor(client: RoxyonClient);
package/dist/index.d.ts CHANGED
@@ -531,10 +531,20 @@ interface CreateDatabaseInput {
531
531
  subscription?: string;
532
532
  /** Omit to have the platform generate one. */
533
533
  password?: string;
534
+ /**
535
+ * `mysql` (default: MySQL/MariaDB on the shared cluster) or `postgres` (PostgreSQL 15 inside the account's own hosting
536
+ * container, at localhost:5432; the first one installs it, a few minutes) or `redis` (one Redis per account, 127.0.0.1:6379,
537
+ * password-protected). Every hosting account has all three.
538
+ */
539
+ engine?: 'mysql' | 'postgres' | 'redis';
534
540
  }
535
541
  interface CreateDatabaseResult {
536
542
  ok: boolean;
537
543
  objectId: string;
544
+ engine?: 'mysql' | 'postgres' | 'redis';
545
+ port?: number;
546
+ /** How to connect (PostgreSQL: the URL shape and the no-password psql login over SSH). */
547
+ note?: string;
538
548
  name: string;
539
549
  username: string;
540
550
  /** Shown once — not retrievable afterwards. */
@@ -549,6 +559,8 @@ interface DatabaseSummary {
549
559
  Name: string;
550
560
  Username: string;
551
561
  Status: string;
562
+ /** `postgres` for PostgreSQL; empty or `mysql` for MySQL/MariaDB. */
563
+ Engine?: string;
552
564
  }
553
565
  interface DeleteDatabaseResult {
554
566
  ok: boolean;
@@ -556,7 +568,7 @@ interface DeleteDatabaseResult {
556
568
  status: 'deleting' | 'deleted' | 'failed';
557
569
  error?: string;
558
570
  }
559
- /** Databases (MySQL/MariaDB on the shared Galera cluster) attached to a subscription. */
571
+ /** Databases attached to a subscription: MySQL/MariaDB (shared Galera cluster) or PostgreSQL (in the account's container). */
560
572
  declare class DatabasesApi {
561
573
  private readonly client;
562
574
  constructor(client: RoxyonClient);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.ts","../src/billing.ts","../src/constants.ts","../src/query.ts","../src/client.ts","../src/databases.ts","../src/domains.ts","../src/email.ts","../src/sites.ts","../src/ssh.ts","../src/subscriptions.ts","../src/tokens.ts","../src/baas-data.ts","../src/env.ts","../src/runtimes.ts","../src/index.ts"],"sourcesContent":["/**\n * The Roxyon BaaS (\"RX\" engine) resolves failed writes rather than rejecting\n * them — a rejected promise never fires and a failure is shaped like a success\n * body with an `error` string on it (top-level, or inside `results[]`). Every\n * write must be run through {@link rxError} before it is treated as having\n * worked. This mirrors `rxError()` in `console.roxyon.com/src/index.js`.\n *\n * Known failure shapes:\n * { \"results\": [ { \"code\": 1054, \"error\": \"Unknown column ...\", \"type\": \"DBQueryError\" } ] }\n * { \"code\": 105, \"error\": \"Invalid Field Name\", \"type\": \"InvalidFieldName\" }\n */\n\nexport interface RxErrorBody {\n code?: number;\n error?: string;\n type?: string;\n results?: unknown;\n}\n\n/** Returns the error message from a BaaS response, or `''` when the call worked. */\nexport function rxError(r: unknown): string {\n if (r === null || r === undefined) return 'No response from the server.';\n if (typeof r !== 'object') return '';\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body.error;\n const rows = body.results;\n if (Array.isArray(rows)) {\n for (const row of rows) {\n if (row && typeof row === 'object' && typeof (row as RxErrorBody).error === 'string') {\n const msg = (row as RxErrorBody).error;\n if (msg) return msg;\n }\n }\n }\n return '';\n}\n\nexport class RoxyonApiError extends Error {\n readonly code?: number;\n readonly type?: string;\n readonly status?: number;\n readonly body: unknown;\n\n constructor(\n message: string,\n opts: { code?: number; type?: string; status?: number; body?: unknown } = {},\n ) {\n super(message);\n this.name = 'RoxyonApiError';\n this.code = opts.code;\n this.type = opts.type;\n this.status = opts.status;\n this.body = opts.body;\n }\n}\n\nconst AUTH_CODES = new Set([101, 141, 209, 1060, 1063, 401]);\nconst AUTH_HINTS = [\n 'invalid session',\n 'session token',\n 'unauthorized',\n 'not authorized',\n 'invalid token',\n 'expired',\n 'log in again',\n];\n\n/** True when an error looks like \"the session/token is gone\", so the caller can re-auth. */\nexport function isAuthError(err: unknown): boolean {\n if (err instanceof RoxyonApiError) {\n if (err.status === 401 || err.status === 403) return true;\n if (err.code !== undefined && AUTH_CODES.has(err.code)) return true;\n }\n const msg = (\n err instanceof Error ? err.message : typeof err === 'string' ? err : rxError(err)\n ).toLowerCase();\n return AUTH_HINTS.some((h) => msg.includes(h));\n}\n\n/** Locate the object (top-level or a `results[]` row) that carries the error. */\nfunction erroringNode(r: unknown): RxErrorBody | undefined {\n if (!r || typeof r !== 'object') return undefined;\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body;\n if (Array.isArray(body.results)) {\n for (const row of body.results) {\n if (row && typeof row === 'object' && (row as RxErrorBody).error) return row as RxErrorBody;\n }\n }\n return undefined;\n}\n\n/** Throw a {@link RoxyonApiError} if `r` carries a BaaS error; otherwise return it typed. */\nexport function assertOk<T>(r: T): T {\n const msg = rxError(r);\n if (msg) {\n const node = erroringNode(r);\n throw new RoxyonApiError(msg, { code: node?.code, type: node?.type, body: r });\n }\n return r;\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\nimport type { TokenScope } from './tokens.js';\n\nexport interface AccountSubscription {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AccountDomain {\n id: string;\n name: string;\n subscription: string;\n /** `active`, or `provisioning` while a freshly-added host comes up. */\n status?: string;\n}\n\nexport interface AccountContext {\n user: { id: string; email: string };\n scopes: (TokenScope | '*')[];\n subscriptions: AccountSubscription[];\n domains: AccountDomain[];\n}\n\nexport interface AccountApp {\n id: string;\n name: string;\n status: string;\n desiredState: string;\n runtime: string;\n configRevision: number;\n appliedRevision: number;\n lastError: string | null;\n repo: { url: string; branch: string } | null;\n}\n\n/**\n * `GET /account/context` — one call the CLI / MCP server use to plan a deploy:\n * the signed-in user, their subscriptions, and their domains. Resolvable by a\n * session token OR a Personal Access Token, so a CI job with only a PAT never\n * has to touch the BaaS. Infra details (nodes, datacenters, container names,\n * filesystem paths) are deliberately not surfaced here.\n */\nexport class AccountApi {\n private cache?: Promise<AccountContext>;\n\n constructor(private readonly client: RoxyonClient) {}\n\n context(opts: { fresh?: boolean } = {}): Promise<AccountContext> {\n if (!this.cache || opts.fresh) this.cache = this.fetch();\n return this.cache;\n }\n\n private async fetch(): Promise<AccountContext> {\n const r = await this.client.console<AccountContext & { ok?: boolean; error?: string }>(\n 'GET',\n '/account/context',\n { tolerateHttpError: true },\n );\n if (!r?.ok || !r.user?.id) {\n throw new RoxyonApiError(r?.error || 'Could not load the account context.', { body: r });\n }\n // Map explicitly — the endpoint may carry infra fields (node/datacenter/\n // container); keep only what a deploy actually needs so they never reach\n // an AI assistant's context or a log.\n return {\n user: { id: r.user.id, email: r.user.email },\n scopes: r.scopes ?? [],\n subscriptions: (r.subscriptions ?? []).map((s) => ({\n id: s.id,\n name: s.name,\n status: s.status,\n })),\n domains: (r.domains ?? []).map((d) => ({\n id: d.id,\n name: d.name,\n subscription: d.subscription,\n ...(d.status ? { status: d.status } : {}),\n })),\n };\n }\n\n /** `GET /account/apps` — the account's applications (list, PAT-safe). */\n async apps(): Promise<AccountApp[]> {\n const r = await this.client.console<{\n ok?: boolean;\n applications?: AccountApp[];\n error?: string;\n }>('GET', '/account/apps', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list applications.', { body: r });\n return (r.applications ?? []).map((a) => ({\n id: a.id,\n name: a.name,\n status: a.status,\n desiredState: a.desiredState,\n runtime: a.runtime,\n configRevision: a.configRevision,\n appliedRevision: a.appliedRevision,\n lastError: a.lastError,\n repo: a.repo,\n }));\n }\n\n /** One application by id, PAT-safe (filters {@link apps}). */\n async getApp(id: string): Promise<AccountApp | undefined> {\n return (await this.apps()).find((a) => a.id === id);\n }\n\n /** Pick the subscription to deploy against — the preferred one, else the only/first. */\n async resolveSubscription(preferred?: string): Promise<AccountSubscription> {\n const { subscriptions } = await this.context();\n if (subscriptions.length === 0) {\n throw new RoxyonApiError('This account has no subscriptions.');\n }\n if (preferred) {\n const hit = subscriptions.find((s) => s.id === preferred || s.name === preferred);\n if (hit) return hit;\n }\n return subscriptions[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError, assertOk } from './errors.js';\n\nexport interface Application {\n objectId: string;\n Name: string;\n Status?: string;\n DesiredState?: string;\n SourcePath?: string;\n Runtime?: string;\n RuntimeVersion?: string;\n Preset?: string;\n ConfigRevision?: number;\n AppliedRevision?: number;\n LastError?: string;\n Env?: string;\n RepoUrl?: string;\n Subscription?: string;\n [k: string]: unknown;\n}\n\nexport interface ApplicationProcess {\n objectId: string;\n Application?: string;\n Type?: string;\n Command?: string;\n Status?: string;\n Port?: number;\n}\n\nexport interface ApplicationRoute {\n objectId: string;\n Application?: string;\n Domain?: string;\n Path?: string;\n Enabled?: number | string;\n}\n\ninterface Results<T> {\n results?: T[];\n error?: string;\n}\n\nexport interface DeployResult {\n ok: boolean;\n application: string;\n created?: boolean;\n configRevision?: number;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\n/** Params for creating an application on its first deploy (no id yet). */\nexport interface CreateOnDeploy {\n host: string;\n folder?: string;\n runtime: 'node' | 'python' | 'php';\n runtimeVersion?: string;\n preset?: string;\n command?: string;\n public?: boolean;\n}\n\nexport interface CreateApplicationInput {\n subscription: string;\n name: string;\n /** Absolute source path: `/home/www/<host>/public_html/<folder>`. */\n sourcePath: string;\n runtime: string;\n runtimeVersion: string;\n preset: string;\n /** The web process start command. */\n command: string;\n /** Route host (`Domains.objectId`). */\n domainId: string;\n /** `.env`-style object stored as JSON on `Applications.Env`. */\n env?: Record<string, string>;\n /** Make the app public (route serves the app instead of the host's files). */\n public?: boolean;\n}\n\n/**\n * The Roxyon Applications system. Deployment is declarative: rows describe the\n * desired state and every meaningful change bumps `ConfigRevision`; a\n * server-side reconciler builds the source in an isolated release dir and\n * (re)starts a systemd unit, writing back `Status` / `AppliedRevision` /\n * `LastError`. Mirrors `applications.view` + `modals/app_form.view`.\n */\nexport class ApplicationsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Application[]> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n async get(id: string): Promise<Application | undefined> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: 1,\n where: { objectId: id },\n });\n return r.results?.[0];\n }\n\n /** Create the application + its web process + a route, matching `createNew()`. */\n async create(\n input: CreateApplicationInput,\n ): Promise<{ application: string; process: string; route: string }> {\n const appRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/Applications', {\n Subscription: input.subscription,\n Name: input.name,\n Preset: input.preset,\n SourcePath: input.sourcePath,\n Runtime: input.runtime,\n RuntimeVersion: input.runtimeVersion,\n Env: JSON.stringify(input.env ?? {}),\n Status: 'pending',\n DesiredState: 'running',\n ConfigRevision: 1,\n AppliedRevision: 0,\n LastError: '',\n }),\n );\n const appId = appRes.results?.[0]?.objectId;\n if (!appId) throw new RoxyonApiError('No application id returned.', { body: appRes });\n\n const procRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationProcesses', {\n Application: appId,\n Type: 'web',\n Port: 0, // allocated by the backend at deploy time\n Command: input.command,\n Status: 'pending',\n }),\n );\n const procId = procRes.results?.[0]?.objectId ?? '';\n\n const routeRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationRoutes', {\n Application: appId,\n Domain: input.domainId,\n Path: '/',\n Enabled: input.public ? 1 : 0,\n }),\n );\n const routeId = routeRes.results?.[0]?.objectId ?? '';\n\n return { application: appId, process: procId, route: routeId };\n }\n\n // ---- console endpoints (session token or PAT) ----\n\n /** Read an application's environment. `GET /applications/env`. */\n async getEnv(applicationId: string): Promise<Record<string, string>> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n error?: string;\n }>('GET', '/applications/env', {\n query: { application: applicationId },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not read the environment.', { body: r });\n return r.env ?? {};\n }\n\n /**\n * Merge `set` and delete `remove`, bumping `ConfigRevision`. `PORT`/`HOST` are\n * ignored (platform-managed). `POST /applications/env`. Returns the new env.\n */\n async setEnv(\n applicationId: string,\n changes: { set?: Record<string, string>; remove?: string[] },\n ): Promise<{ env: Record<string, string>; changed: string[]; configRevision: number }> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n changed?: string[];\n configRevision?: number;\n error?: string;\n }>('POST', '/applications/env', {\n query: { application: applicationId },\n body: { set: changes.set ?? {}, remove: changes.remove ?? [] },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not update the environment.', { body: r });\n return { env: r.env ?? {}, changed: r.changed ?? [], configRevision: r.configRevision ?? 0 };\n }\n\n /** Rebuild from the latest source and restart. `POST /applications/action`. */\n async deploy(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'deploy' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /** Bounce the process only — no rebuild. `POST /applications/action`. */\n async restart(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'restart' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /**\n * Tail the app's journal. `POST /applications/logs` returns one block per\n * process (`{ type, unit, output }`); this flattens them to lines, each\n * prefixed with the process type when there is more than one.\n */\n async logs(applicationId: string, lines = 100): Promise<string[]> {\n const r = await this.client.console<{\n processes?: Array<{ type?: string; unit?: string; output?: string }>;\n error?: string;\n }>('POST', '/applications/logs', {\n body: { application: applicationId, lines },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n const procs = r?.processes ?? [];\n const multi = procs.length > 1;\n const out: string[] = [];\n for (const p of procs) {\n const body = (p.output ?? '').split('\\n').filter(Boolean);\n for (const line of body) out.push(multi ? `[${p.type ?? 'web'}] ${line}` : line);\n }\n return out;\n }\n\n /** Connect a git remote for push-to-deploy. `POST /applications/repo/connect`. */\n async repoConnect(\n applicationId: string,\n repoUrl: string,\n branch = 'main',\n ): Promise<{\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n }> {\n const r = await this.client.console<{\n error?: string;\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n branch?: string;\n }>('POST', '/applications/repo/connect', {\n body: { application: applicationId, repoUrl, branch },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n return r;\n }\n\n /**\n * Upload a gzipped tarball of the project source. The endpoint lands it in the\n * application's `SourcePath` and bumps `ConfigRevision` (the reconciler then\n * builds it in a release dir exactly as for a git deploy).\n *\n * `POST /applications/deploy` — NEW endpoint (see `backend/` in this repo).\n */\n async uploadSource(target: string | CreateOnDeploy, tarball: Uint8Array): Promise<DeployResult> {\n const query: Record<string, string> =\n typeof target === 'string'\n ? { application: target }\n : {\n host: target.host,\n folder: target.folder ?? '',\n runtime: target.runtime,\n ...(target.runtimeVersion ? { runtimeVersion: target.runtimeVersion } : {}),\n ...(target.preset ? { preset: target.preset } : {}),\n ...(target.command ? { command: target.command } : {}),\n public: target.public === false ? '0' : '1',\n };\n const r = await this.client.console<DeployResult>('POST', '/applications/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Upload failed.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface SessionGrant {\n session_token: string;\n refresh_token?: string;\n expires_in?: number;\n status?: string;\n}\n\nexport interface RoxyonUser {\n objectId: string;\n Email?: string;\n Username?: string;\n Name?: string;\n Currency?: string;\n Language?: string;\n [k: string]: unknown;\n}\n\nexport interface LoginPrecheck {\n ok?: boolean;\n error?: string;\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\nexport interface LoginResult {\n sessionToken: string;\n refreshToken?: string;\n expiresIn?: number;\n /** True when an OTP code is still required — call {@link AuthApi.verifyOtp}. */\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\n/**\n * Wraps the console's login flow:\n * 1. `POST /_account/login-precheck` — validates credentials, decides whether\n * an OTP step-up is required, and (when it is) returns a `challengeId`.\n * 2a. no step-up -> `POST /Auth/login` finalises and returns a session token.\n * 2b. step-up -> caller collects the code, then `POST /Auth/login/otp-verify`.\n *\n * Mirrors `signin.view` / `otp.view` in `console.roxyon.com`.\n */\nexport class AuthApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /**\n * Best-effort device/step-up precheck. `/_account/login-precheck` is a console\n * cloud function that may be gated behind the REST key (not reachable from a\n * public client) — in that case this resolves to `{}` and login falls back to\n * `/Auth/login`, which is itself the security boundary and re-checks the\n * device. Only a definitive `{ ok: false }` / `stepUpRequired` is acted on.\n */\n async precheck(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginPrecheck> {\n try {\n const r = await this.client.post<LoginPrecheck & { code?: number }>(\n '/_account/login-precheck',\n { Email: email, Password: password, metadata },\n { tolerateHttpError: true },\n );\n // Endpoint not available to this client — ignore, let /Auth/login decide.\n if (r?.code === 401 || (r?.error && /rest api key/i.test(r.error))) return {};\n return r ?? {};\n } catch {\n return {};\n }\n }\n\n /**\n * Full login. Returns a session token on success, or `stepUpRequired` with a\n * `challengeId` when an OTP code is needed next.\n */\n async login(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginResult> {\n const pre = await this.precheck(email, password, metadata);\n if (pre.ok === false && pre.error && !pre.stepUpRequired) {\n throw new RoxyonApiError(pre.error, { type: 'CredentialsError' });\n }\n if (pre.stepUpRequired) {\n return { sessionToken: '', stepUpRequired: true, challengeId: pre.challengeId };\n }\n\n const grant = await this.client.post<\n SessionGrant & { error?: string; stepUpRequired?: boolean; challengeId?: string }\n >('/Auth/login', { Email: email, Password: password, metadata }, { tolerateHttpError: true });\n\n // Some accounts step up at /Auth/login itself rather than at precheck.\n if (grant?.stepUpRequired || (grant?.challengeId && !grant.session_token)) {\n return { sessionToken: '', stepUpRequired: true, challengeId: grant.challengeId };\n }\n if (!grant?.session_token) {\n throw new RoxyonApiError(grant?.error || 'Wrong email or password.', {\n type: 'CredentialsError',\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Complete an OTP step-up with the code the user received. */\n async verifyOtp(challengeId: string, code: string): Promise<LoginResult> {\n const grant = await this.client.post<SessionGrant & { error?: string }>(\n '/Auth/login/otp-verify',\n { challengeId, code },\n { tolerateHttpError: true },\n );\n if (grant?.status !== 'authenticated' || !grant.session_token) {\n throw new RoxyonApiError(grant?.error || 'That code did not verify.', {\n type: 'OtpError',\n body: grant,\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Start an OTP-only sign-in (no password). Returns a `challengeId`. */\n async startOtp(email: string): Promise<{ challengeId: string }> {\n const r = await this.client.post<{ challengeId?: string; error?: string }>(\n '/Auth/login/otp',\n { Email: email },\n { tolerateHttpError: true },\n );\n if (!r?.challengeId) {\n throw new RoxyonApiError(r?.error || 'Could not start OTP sign-in.', { body: r });\n }\n return { challengeId: r.challengeId };\n }\n\n /** The currently authenticated user. Requires a session token on the client. */\n async me(): Promise<RoxyonUser> {\n const user = await this.client.post<RoxyonUser & { error?: string }>('/Auth/me', {});\n if (!user?.objectId) {\n throw new RoxyonApiError(user?.error || 'Not signed in.', { status: 401, body: user });\n }\n return user;\n }\n\n async logout(): Promise<void> {\n await this.client.post('/Auth/logout', {}, { tolerateHttpError: true }).catch(() => undefined);\n this.client.setSessionToken(undefined);\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** Billing cycles the checkout accepts (Pricing::CYCLE_MONTHS). */\nexport const BILLING_CYCLES = ['monthly', 'quarterly', 'yearly', 'biennial'] as const;\nexport type BillingCycle = (typeof BILLING_CYCLES)[number];\n\n// Plans of this service are resellers' private resold copies, never the public catalog\n// (same filter as the console's own bootstrap).\nconst RESELLER_RESOLD_SERVICE_ID = 'bjMqdLqAKl';\n\nexport interface CatalogProduct {\n /** Plan objectId: what quotes and orders take. */\n planId: string;\n /** Plan code, e.g. `SCALE-S`. */\n sku: string;\n name: string;\n /** Service type, e.g. `cloud.vps.scale`, `cloud.hosting.solo`. */\n category: string;\n vcpu?: number;\n ramGb?: number;\n diskGb?: number;\n cpuType?: string;\n /** Dedicated IPv4 addresses included (servers). */\n ipv4Included?: number;\n /** List prices in USD before tax, per cycle. Quote for the buyer's currency and tax. */\n pricesUSD: Partial<Record<BillingCycle, number>>;\n /** Setup fee in USD per cycle, when not zero. */\n setupFeeUSD?: Partial<Record<BillingCycle, number>>;\n /** `out` = cannot be ordered right now. */\n stock: 'in' | 'out';\n /** Feature table as the console shows it. */\n features?: Record<string, unknown>;\n}\n\nexport interface QuoteInput {\n planId: string;\n cycle: BillingCycle;\n /** ISO 4217, e.g. `SAR`. Default USD. */\n currency?: string;\n /** ISO 3166 alpha-2, decides tax (e.g. `SA` = 15% VAT). Empty = no tax line. */\n country?: string;\n}\n\nexport interface Quote {\n planId: string;\n cycle: string;\n currency: string;\n lineItems: Array<{ label: string; amount: string; amountUSD: string }>;\n subtotal: string;\n taxRate: string;\n taxLabel: string;\n taxAmount: string;\n discountAmount: string;\n total: string;\n fxRate: string;\n baseAmountUSD: string;\n}\n\nexport interface OrderInput {\n /** Plan code from the catalog, e.g. `SCALE-S`. */\n sku: string;\n cycle: BillingCycle;\n /** A name for the service. */\n name: string;\n /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */\n username: string;\n /** Servers only: OS image, e.g. `ubuntu-24.04`. */\n image?: string;\n sshKey?: string;\n phpVersion?: string;\n datacenter?: string;\n currency?: string;\n country?: string;\n /** false/absent = dry run (quote + budget check, nothing written). */\n confirm?: boolean;\n}\n\nexport interface OrderBudget {\n monthlyUSD: number;\n spentUSD: number;\n remainingUSD: number;\n}\n\nexport interface OrderResult {\n dryRun?: boolean;\n plan: { id: string; sku: string; name: string; kind: 'hosting' | 'server'; cycle: string };\n /** Dry run: the server quote (same shape as GET /_payment/quote). */\n quote?: Record<string, unknown>;\n subscriptionId?: string;\n invoiceId?: string;\n total?: string;\n currency?: string;\n payUrl?: string;\n /** null for a console session (no token budget). */\n budget: OrderBudget | null;\n}\n\nexport interface BillingSubscription {\n id: string;\n name: string;\n status: string;\n plan: string;\n sku: string;\n cycle: string;\n price: string;\n currency: string;\n nextBillingDate: string | null;\n autoRenew: boolean;\n serverState: string | null;\n publicIp: string | null;\n}\n\nexport interface Invoice {\n id: string;\n number: string;\n type: string;\n status: string;\n total: string;\n currency: string;\n dueDate: string | null;\n subscription: string | null;\n createdAt: string;\n payUrl: string | null;\n}\n\n/** Invoice statuses a customer can still pay. */\nexport const PAYABLE_STATUSES = ['pending', 'overdue', 'failed'] as const;\n\nexport function isPayable(status: string): boolean {\n return (PAYABLE_STATUSES as readonly string[]).includes(status.toLowerCase());\n}\n\nfunction json<T>(v: unknown, fallback: T): T {\n if (v && typeof v === 'object') return v as T;\n if (typeof v !== 'string' || v === '') return fallback;\n try {\n return JSON.parse(v) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction numbers(v: unknown): Partial<Record<BillingCycle, number>> {\n const out: Partial<Record<BillingCycle, number>> = {};\n const src = json<Record<string, unknown>>(v, {});\n for (const c of BILLING_CYCLES) {\n const n = Number(src[c]);\n if (src[c] !== undefined && src[c] !== '' && Number.isFinite(n)) out[c] = n;\n }\n return out;\n}\n\ninterface PlanRow {\n objectId: string;\n Name?: string;\n Code?: string;\n Limits?: unknown;\n Features?: unknown;\n _Service?: { results?: Array<{ Type?: string }> };\n _Pricing?: {\n results?: Array<{\n Prices?: unknown;\n SetupFee?: unknown;\n MetaData?: unknown;\n IsActive?: unknown;\n }>;\n };\n}\n\n/**\n * Catalog + quotes (public, no sign-in) and the caller's own subscriptions + invoices\n * (console, session or PAT). Read-only: nothing here creates orders or invoices.\n */\nexport class BillingApi {\n constructor(\n private readonly client: RoxyonClient,\n private readonly pub: RoxyonClient = client.publicClient(),\n ) {}\n\n async catalog(): Promise<CatalogProduct[]> {\n const r = await this.pub.get<{ results?: PlanRow[]; error?: string }>('/Plans', {\n fields: '*',\n limit: -1,\n order: 'objectId',\n where: { Status: 'active', Service: { nin: RESELLER_RESOLD_SERVICE_ID } },\n include: [\n { className: 'Services', field: 'Service', fields: 'Type' },\n {\n className: 'Pricing',\n field: 'Plan',\n fields: 'Prices,SetupFee,MetaData,IsActive',\n reverse: 1,\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load the catalog.', { body: r });\n }\n const out: CatalogProduct[] = [];\n for (const p of r.results) {\n const pricing = p._Pricing?.results?.[0];\n // Same rule as roxyon.com's pricing page: a plan code, an active Pricing row, a monthly price.\n if (!p.Code || !pricing || Number(pricing.IsActive) === 0) continue;\n const limits = json<Record<string, unknown>>(p.Limits, {});\n const features = json<Record<string, unknown>>(p.Features, {});\n const meta = json<Record<string, unknown>>(pricing.MetaData, {});\n const network = json<Record<string, unknown>>(features.Network, {});\n const setup = numbers(pricing.SetupFee);\n const pricesUSD = numbers(pricing.Prices);\n if (pricesUSD.monthly === undefined) continue;\n const product: CatalogProduct = {\n planId: p.objectId,\n sku: p.Code ?? '',\n name: p.Name ?? '',\n category: p._Service?.results?.[0]?.Type ?? '',\n pricesUSD,\n stock: String(meta.stock ?? 'in').toLowerCase() === 'out' ? 'out' : 'in',\n };\n if (limits.vcpu != null) {\n product.vcpu = Number(limits.vcpu);\n product.ramGb = limits.memory_mb ? Math.round(Number(limits.memory_mb) / 1024) : 0;\n product.diskGb = Number(limits.disk_gb ?? 0);\n product.cpuType = String(limits.cpu_type ?? '');\n }\n if (network['Dedicated IPv4'] != null)\n product.ipv4Included = Number(network['Dedicated IPv4']);\n if (Object.values(setup).some((n) => n > 0)) product.setupFeeUSD = setup;\n if (Object.keys(features).length) product.features = features;\n out.push(product);\n }\n return out;\n }\n\n /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */\n async quote(input: QuoteInput): Promise<Quote> {\n if (!/^[A-Za-z0-9]{1,40}$/.test(input.planId))\n throw new Error(`Invalid planId \"${input.planId}\".`);\n if (!BILLING_CYCLES.includes(input.cycle))\n throw new Error(`Unsupported cycle \"${input.cycle}\".`);\n const q: Record<string, string | number> = {\n type: 'subscription.new',\n planId: input.planId,\n cycle: input.cycle,\n setup: 1,\n };\n if (input.currency) q.currency = input.currency.toUpperCase();\n if (input.country) q.country = input.country.toUpperCase();\n const r = await this.pub.get<\n Partial<Quote> & { ok?: boolean; error?: string; baseAmount?: string }\n >('/_payment/quote', q);\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not price this plan.', { body: r });\n return {\n planId: String(r.planId ?? input.planId),\n cycle: String(r.cycle ?? input.cycle),\n currency: String(r.currency ?? ''),\n lineItems: (r.lineItems ?? []).map((l) => ({\n label: l.label,\n amount: l.amount,\n amountUSD: l.amountUSD,\n })),\n subtotal: String(r.subtotal ?? ''),\n taxRate: String(r.taxRate ?? ''),\n taxLabel: String(r.taxLabel ?? ''),\n taxAmount: String(r.taxAmount ?? ''),\n discountAmount: String(r.discountAmount ?? ''),\n total: String(r.total ?? ''),\n fxRate: String(r.fxRate ?? ''),\n baseAmountUSD: String(r.baseAmount ?? ''),\n };\n }\n\n /**\n * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it\n * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the\n * `billing:order` scope, within that token's monthly budget and allowed SKUs.\n */\n async order(input: OrderInput): Promise<OrderResult> {\n const r = await this.client.console<\n Partial<OrderResult> & { ok?: boolean; error?: string; budget?: OrderBudget }\n >('POST', '/account/order', { body: input, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'The order was not placed.', { body: r });\n return r as OrderResult;\n }\n\n /** The caller's own subscriptions (rows they own), newest first. */\n async subscriptions(): Promise<BillingSubscription[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n subscriptions?: BillingSubscription[];\n }>('GET', '/account/subscriptions', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load subscriptions.', { body: r });\n return r.subscriptions ?? [];\n }\n\n /** The caller's own invoices, newest first. */\n async invoices(opts: { status?: string; limit?: number } = {}): Promise<Invoice[]> {\n const q: Record<string, string> = {};\n if (opts.status) q.status = opts.status;\n if (opts.limit) q.limit = String(opts.limit);\n const r = await this.client.console<{ ok?: boolean; error?: string; invoices?: Invoice[] }>(\n 'GET',\n '/account/invoices',\n { tolerateHttpError: true, query: q },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load invoices.', { body: r });\n // Only an open invoice can be paid (the first console release also linked void ones).\n return (r.invoices ?? []).map((i) => ({ ...i, payUrl: isPayable(i.status) ? i.payUrl : null }));\n }\n}\n","/**\n * Default endpoints and the public application credentials the client uses to\n * mint an anonymous token before a user logs in.\n *\n * `X-BEA-JavaScript-Key` is a **public** key (it ships in browser bundles by\n * design — see `console.roxyon.com/src/index.js`). It is safe to embed here.\n * The REST key is never embedded — user actions always run under a session\n * token or a Personal Access Token.\n *\n * TODO(M1): provision a dedicated `roxyon-cli` BaaS application and swap these\n * for its App-ID / JavaScript-Key so CLI traffic is attributable and rate-limited\n * separately from the web console. Until then the client reuses the console's\n * public pair, which is already exposed in shipped frontend code.\n */\nexport const DEFAULT_BAAS_URL = 'https://www.beaapis.com/1';\nexport const DEFAULT_CONSOLE_URL = 'https://console.roxyon.com';\n\nexport const DEFAULT_APP = {\n appId: 'jAtp2zHGU3FbnrQWrToALFakd_vbiY0ywihn4Hj54lw',\n javascriptKey: 'w2Y9USRg0COtNe-fUqOaC1OOOlNCnV2BG8GZF80w4x8',\n} as const;\n\n/** Header names, lower-cased (the API is case-insensitive but the SDK uses these). */\nexport const H = {\n appId: 'x-bea-application-id',\n jsKey: 'x-bea-javascript-key',\n restKey: 'x-bea-authorization',\n sessionToken: 'x-bea-session-token',\n accessToken: 'x-bea-access-token',\n refreshToken: 'x-bea-refresh-token',\n} as const;\n","/**\n * GET query serialisation for the BaaS, matching the `Obj2Par` helper in the\n * browser SDK (`rx.js`): nested objects become PHP-style bracket keys\n * (`where[User]=abc`, `where[Status][in]=a,b,c`).\n *\n * Two hard-won rules (see the `roxyon-api-write-failures` notes):\n * - The `in` operator takes a **comma-joined string, not an array**. An array\n * serialises to `where[X][in][0]=…` bracket notation the API does not read.\n * Pass `{ in: ['a', 'b'] }` here and we join it for you.\n * - A `select` subquery nested inside an `or` group crashes the API. Resolve\n * ids in a first query, then `or: [..., { objectId: { in: 'a,b' } }]`.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | { [k: string]: QueryValue };\n\nexport type QueryObject = Record<string, QueryValue>;\n\nfunction encode(k: string, v: string): string {\n return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;\n}\n\nfunction walk(value: QueryValue, prefix: string, out: string[]): void {\n if (value === null || value === undefined) return;\n\n if (Array.isArray(value)) {\n // A bare array under a normal key -> repeated bracket-index entries. The\n // only array we actually want is `in`, and that is handled below before we\n // ever get here, so this branch is a best-effort fallback.\n value.forEach((item, i) => walk(item, `${prefix}[${i}]`, out));\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n if (key === 'in' || key === 'nin' || key === 'notIn') {\n const joined = Array.isArray(child) ? child.join(',') : String(child);\n out.push(encode(`${prefix}[${key === 'notIn' ? 'nin' : key}]`, joined));\n continue;\n }\n walk(child, `${prefix}[${key}]`, out);\n }\n return;\n }\n\n out.push(encode(prefix, String(value)));\n}\n\n/** Serialise a query object to a `key=value&...` string (no leading `?`). */\nexport function toQueryString(query: QueryObject | undefined): string {\n if (!query) return '';\n const out: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n walk(value, key, out);\n }\n return out.join('&');\n}\n","import { DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, H } from './constants.js';\nimport { RoxyonApiError } from './errors.js';\nimport { type QueryObject, toQueryString } from './query.js';\n\nexport interface RoxyonClientOptions {\n /** BaaS application id. Defaults to the public console app. */\n appId?: string;\n /** Public JavaScript key, used to mint an anonymous token. */\n javascriptKey?: string;\n /** REST API key. Optional; grants full access — only for trusted server use. */\n restKey?: string;\n /** A user session token (from {@link AuthApi.login}). */\n sessionToken?: string;\n /** BaaS REST base, e.g. `https://www.beaapis.com/1`. */\n baseUrl?: string;\n /** Console base that serves the `/applications/*` endpoints. */\n consoleUrl?: string;\n /** Custom fetch (tests / proxies). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n query?: QueryObject;\n body?: unknown;\n headers?: Record<string, string>;\n /** Skip the Authorization/session header entirely (used for token minting). */\n skipAuth?: boolean;\n /** Send/parse the response even on a non-2xx status instead of throwing. */\n tolerateHttpError?: boolean;\n signal?: AbortSignal;\n}\n\ninterface AnonToken {\n access_token?: string;\n session_token?: string;\n refresh_token?: string;\n expires_in?: number;\n /** epoch ms this token becomes unusable */\n _expiresAt?: number;\n}\n\n/**\n * Low-level transport for the Roxyon BaaS and console app endpoints.\n *\n * Auth precedence per request: explicit `sessionToken` -> `restKey` ->\n * a lazily-minted anonymous access token (public app credentials).\n */\nexport class RoxyonClient {\n readonly baseUrl: string;\n readonly consoleUrl: string;\n private readonly appId: string;\n private readonly javascriptKey: string;\n private readonly restKey?: string;\n private readonly _fetch: typeof fetch;\n private sessionToken?: string;\n private anon?: AnonToken;\n\n constructor(opts: RoxyonClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_URL).replace(/\\/+$/, '');\n this.consoleUrl = (opts.consoleUrl ?? DEFAULT_CONSOLE_URL).replace(/\\/+$/, '');\n this.appId = opts.appId ?? DEFAULT_APP.appId;\n this.javascriptKey = opts.javascriptKey ?? DEFAULT_APP.javascriptKey;\n this.restKey = opts.restKey;\n this.sessionToken = opts.sessionToken;\n this._fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this._fetch !== 'function') {\n throw new Error('No fetch implementation available (need Node >= 20 or pass opts.fetch).');\n }\n }\n\n /** Same endpoints and app, no user credentials: for public reads (catalog, quotes)\n * that must work for PAT callers too, whose token the BaaS does not accept. */\n publicClient(): RoxyonClient {\n return new RoxyonClient({\n baseUrl: this.baseUrl,\n consoleUrl: this.consoleUrl,\n appId: this.appId,\n javascriptKey: this.javascriptKey,\n fetch: this._fetch,\n });\n }\n\n getSessionToken(): string | undefined {\n return this.sessionToken;\n }\n\n setSessionToken(token: string | undefined): void {\n this.sessionToken = token;\n }\n\n /** Mint (or reuse) an anonymous access token from the public app credentials. */\n private async anonToken(): Promise<AnonToken> {\n if (this.anon?._expiresAt && this.anon._expiresAt > Date.now() + 5_000) {\n return this.anon;\n }\n const res = await this._fetch(`${this.baseUrl}/Auth`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n [H.appId]: this.appId,\n [H.jsKey]: this.javascriptKey,\n },\n body: JSON.stringify({ scope: 'public' }),\n });\n const json = (await res.json().catch(() => ({}))) as AnonToken;\n if (!json.access_token && !json.session_token) {\n throw new RoxyonApiError('Could not obtain an anonymous BaaS token.', {\n status: res.status,\n body: json,\n });\n }\n json._expiresAt = Date.now() + (json.expires_in ? json.expires_in * 1000 : 3_600_000);\n this.anon = json;\n return json;\n }\n\n /** A Personal Access Token (`roxp_…`) authenticates the console endpoints via\n * `Authorization: Bearer`; it is not a BaaS session token. */\n private get isPat(): boolean {\n return this.sessionToken?.startsWith('roxp_') ?? false;\n }\n\n private async authHeaders(\n skipAuth: boolean,\n isConsole: boolean,\n ): Promise<Record<string, string>> {\n // IMPORTANT: never send X-BEA-Application-ID on an authenticated request.\n // The BaaS `/auth/*` router treats the App-ID header as \"mint me an\n // anonymous token\" and short-circuits — /Auth/login, /Auth/me etc. would\n // silently return a fresh anon token instead of doing their job. The App-ID\n // (+ JS key) is sent only by anonToken()'s own POST /Auth call.\n if (skipAuth) return {};\n if (this.isPat) {\n // Console: Bearer. BaaS: nothing — PAT clients resolve identity and\n // subscriptions through the console's /account/context instead.\n return isConsole ? { authorization: `Bearer ${this.sessionToken}` } : {};\n }\n if (this.sessionToken) return { [H.sessionToken]: this.sessionToken };\n if (this.restKey) return { [H.appId]: this.appId, [H.restKey]: this.restKey };\n const anon = await this.anonToken();\n if (anon.session_token) return { [H.sessionToken]: anon.session_token };\n return { [H.accessToken]: anon.access_token ?? '' };\n }\n\n /** A raw BaaS request. `path` is relative to {@link baseUrl} (leading `/`). */\n async request<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.baseUrl, method, path, opts);\n }\n\n /** A request against the console app endpoints ({@link consoleUrl}). */\n async console<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.consoleUrl, method, path, opts);\n }\n\n private async rawRequest<T>(\n root: string,\n method: string,\n path: string,\n opts: RequestOptions,\n ): Promise<T> {\n const qs = toQueryString(opts.query);\n const url = `${root}${path.startsWith('/') ? path : `/${path}`}${qs ? `?${qs}` : ''}`;\n const headers: Record<string, string> = {\n ...(await this.authHeaders(opts.skipAuth ?? false, root === this.consoleUrl)),\n ...opts.headers,\n };\n const hasBody = method !== 'GET' && method !== 'HEAD' && opts.body !== undefined;\n let body: string | Uint8Array | ArrayBuffer | FormData | undefined;\n if (hasBody) {\n if (\n typeof opts.body === 'string' ||\n opts.body instanceof Uint8Array ||\n opts.body instanceof ArrayBuffer ||\n (typeof FormData !== 'undefined' && opts.body instanceof FormData)\n ) {\n body = opts.body as string | Uint8Array | ArrayBuffer | FormData;\n } else {\n headers['content-type'] = headers['content-type'] ?? 'application/json';\n body = JSON.stringify(opts.body);\n }\n }\n\n let res: Response;\n try {\n res = await this._fetch(url, { method, headers, body, signal: opts.signal });\n } catch (cause) {\n throw new RoxyonApiError(`Network error calling ${method} ${url}`, { body: cause });\n }\n\n const text = await res.text();\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : {};\n } catch {\n // An HTML page means the route isn't served by the API (a console route not deployed yet falls through to\n // the web app): say so instead of handing the page to the caller as an error message.\n const html = /^\\s*</.test(text);\n json = {\n error: html\n ? `${method} ${path} is not available on this server yet (got a web page instead of the API).`\n : text || `HTTP ${res.status}`,\n _raw: html ? '' : text,\n };\n }\n\n if (!res.ok && !opts.tolerateHttpError) {\n const msg =\n (json &&\n typeof json === 'object' &&\n 'error' in json &&\n (json as { error: string }).error) ||\n `HTTP ${res.status} calling ${method} ${path}`;\n throw new RoxyonApiError(String(msg), { status: res.status, body: json });\n }\n return json as T;\n }\n\n get<T = unknown>(path: string, query?: QueryObject, opts?: RequestOptions): Promise<T> {\n return this.request<T>('GET', path, { ...opts, query });\n }\n post<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('POST', path, { ...opts, body });\n }\n put<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', path, { ...opts, body });\n }\n del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', path, { ...opts, body });\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateDatabaseInput {\n /** DB name suffix — the platform prefixes it with the subscription's own username (globally unique). */\n name: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one. */\n password?: string;\n}\n\nexport interface CreateDatabaseResult {\n ok: boolean;\n objectId: string;\n name: string;\n username: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n /** `<node-ip>:6033` — the ProxySQL endpoint to connect the app to. */\n host?: string;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface DatabaseSummary {\n objectId: string;\n Name: string;\n Username: string;\n Status: string;\n}\n\nexport interface DeleteDatabaseResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Databases (MySQL/MariaDB on the shared Galera cluster) attached to a subscription. */\nexport class DatabasesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */\n async list(subscriptionId: string): Promise<DatabaseSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n databases?: DatabaseSummary[];\n }>('POST', '/databases/list', {\n body: { subscription: subscriptionId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the databases.', { body: r });\n return r.databases ?? [];\n }\n\n /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */\n async create(input: CreateDatabaseInput): Promise<CreateDatabaseResult> {\n const r = await this.client.console<CreateDatabaseResult>('POST', '/databases/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the database.', { body: r });\n return r;\n }\n\n /** `POST /databases/delete` */\n async delete(databaseId: string): Promise<DeleteDatabaseResult> {\n const r = await this.client.console<DeleteDatabaseResult>('POST', '/databases/delete', {\n body: { database: databaseId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the database.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Domain {\n objectId: string;\n Name: string;\n}\n\nexport interface CreateDomainInput {\n /** FQDN to host — a subdomain of a domain the account already hosts, or `*.roxyon.com`. */\n host: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** `spa` → unmatched paths serve `/index.html`; default `static`. */\n siteType?: 'static' | 'spa';\n /** PHP version for the vhost (e.g. `\"8.3\"`). Unknown/omitted falls back to the platform default. */\n phpVersion?: string;\n}\n\nexport interface CreateDomainResult {\n ok: boolean;\n objectId: string;\n host: string;\n /** `subdomain` of an owned parent, or `primary`. */\n type: 'subdomain' | 'primary';\n /** `provisioning` while DNS/vhost/TLS come up, then `active` (or `failed`). */\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\n/** Domains (hosts) attached to a subscription. */\nexport class DomainsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Domain[]> {\n const r = await this.client.get<{ results?: Domain[] }>('/Domains', {\n fields: 'objectId,Name',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n /**\n * `POST /domains/create` — provision a subdomain (DNS + vhost + auto-TLS). The\n * server decides subdomain vs primary from the caller's existing hosts and\n * writes the `pending` row; the platform's reconciler does the rest.\n */\n async create(input: CreateDomainInput): Promise<CreateDomainResult> {\n const r = await this.client.console<CreateDomainResult>('POST', '/domains/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the domain.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateEmailInput {\n /** The part before `@`. */\n localPart: string;\n /** A hostname already on the account. */\n domain: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /** Mailbox quota in MB. Default 1024. */\n quota?: number;\n forwardTo?: string;\n saveCopy?: boolean;\n}\n\nexport interface CreateEmailResult {\n ok: boolean;\n objectId: string;\n email: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n quota?: number;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface EmailSummary {\n objectId: string;\n Email: string;\n LocalPart: string;\n Status: string;\n Quota?: number;\n}\n\nexport interface DeleteEmailResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Mailboxes attached to a subscription's domains. */\nexport class EmailApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */\n async list(subscriptionId: string): Promise<EmailSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n emails?: Omit<EmailSummary, 'LocalPart'>[];\n }>('POST', '/emails/list', { body: { subscription: subscriptionId }, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the mailboxes.', { body: r });\n return (r.emails ?? []).map((e) => ({ ...e, LocalPart: e.Email.split('@')[0] ?? '' }));\n }\n\n /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */\n async create(input: CreateEmailInput): Promise<CreateEmailResult> {\n const r = await this.client.console<CreateEmailResult>('POST', '/emails/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the mailbox.', { body: r });\n return r;\n }\n\n /** `POST /emails/delete` */\n async delete(emailId: string): Promise<DeleteEmailResult> {\n const r = await this.client.console<DeleteEmailResult>('POST', '/emails/delete', {\n body: { email: emailId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the mailbox.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface StaticDeployResult {\n ok: boolean;\n host: string;\n path: string;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\nexport interface DeployOptions {\n /** Replace the docroot contents instead of overlaying (keeps `.well-known`). */\n clean?: boolean;\n /** Flip the host to SPA routing: unmatched paths serve `/index.html`. */\n spa?: boolean;\n}\n\nexport interface SiteFile {\n /** POSIX path relative to the site root. */\n path: string;\n size: number;\n type: 'file' | 'dir';\n}\n\nexport interface SiteFileContent {\n path: string;\n size: number;\n encoding: 'utf8' | 'base64';\n content: string;\n}\n\n/**\n * Static-site hosting: the files under a host's document root\n * (`public_html[/<folder>]`), served directly by nginx. No Application row, no\n * process. All routes go to the console (`POST /sites/deploy`, `GET /sites/files`,\n * `GET /sites/file`) and authenticate with a session token or a `roxp_` PAT.\n */\nexport class SitesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** Upload a gzip tarball into `host`'s docroot (+ optional sub-`folder`). */\n async deploy(\n host: string,\n folder: string,\n tarball: Uint8Array,\n opts: DeployOptions = {},\n ): Promise<StaticDeployResult> {\n const query: Record<string, string> = { host, folder };\n if (opts.clean) query.clean = '1';\n if (opts.spa) query.spa = '1';\n const r = await this.client.console<StaticDeployResult>('POST', '/sites/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Static deploy failed.', { body: r });\n return r;\n }\n\n /** List the files currently in `host`'s docroot (optionally under `path`). */\n async listFiles(host: string, folder = '', path = ''): Promise<SiteFile[]> {\n const r = await this.client.console<{ ok?: boolean; files?: SiteFile[]; error?: string }>(\n 'GET',\n '/sites/files',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list site files.', { body: r });\n return r.files ?? [];\n }\n\n /** Read one file from `host`'s docroot. */\n async readFile(host: string, folder: string, path: string): Promise<SiteFileContent> {\n const r = await this.client.console<SiteFileContent & { ok?: boolean; error?: string }>(\n 'GET',\n '/sites/file',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok || typeof r.content !== 'string') {\n throw new RoxyonApiError(r?.error || 'Could not read the file.', { body: r });\n }\n return { path: r.path, size: r.size, encoding: r.encoding, content: r.content };\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface ResetSshPasswordInput {\n /** Subscription to reset. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one meeting the strength rules. */\n password?: string;\n}\n\nexport interface ResetSshPasswordResult {\n ok: boolean;\n subscription: string;\n /** Shown once — the platform never stores or re-shows it. */\n password: string;\n status: 'pending' | 'active' | 'failed';\n}\n\n/**\n * The shared shell password used for SSH, SFTP and the file manager on a\n * subscription's container (SSHpiper maps the username to the container).\n */\nexport class SshApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /ssh/password` */\n async resetPassword(input: ResetSshPasswordInput = {}): Promise<ResetSshPasswordResult> {\n const r = await this.client.console<ResetSshPasswordResult>('POST', '/ssh/password', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) {\n throw new RoxyonApiError(\n (r as { error?: string })?.error || 'Could not reset the password.',\n {\n body: r,\n },\n );\n }\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Subscription {\n objectId: string;\n Name?: string;\n Status?: string;\n [k: string]: unknown;\n}\n\nexport interface Privilege {\n objectId: string;\n Type?: string;\n Subscription?: string;\n _Subscription?: { results: Subscription[] };\n [k: string]: unknown;\n}\n\ninterface ListResponse<T> {\n results?: T[];\n error?: string;\n}\n\n/** Access to the caller's subscriptions (via their Privileges rows). */\nexport class SubscriptionsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** All subscriptions the signed-in user has a Privilege on. */\n async list(userId: string): Promise<Subscription[]> {\n const r = await this.client.get<ListResponse<Privilege>>('/Privileges', {\n where: { User: userId },\n fields: 'objectId,Type,Subscription',\n limit: -1,\n include: [\n {\n className: 'Subscriptions',\n field: 'Subscription',\n fields: 'objectId,Name,Status',\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load subscriptions.', {\n status: 401,\n body: r,\n });\n }\n const subs: Subscription[] = [];\n for (const priv of r.results) {\n const sub = priv._Subscription?.results?.[0];\n if (sub) subs.push(sub);\n }\n return subs;\n }\n\n /**\n * Resolve the subscription to act on. Prefers an exact `objectId` or `Name`\n * match against `preferred`; otherwise the first active subscription; otherwise\n * the first one. Throws when the account has none.\n */\n async resolve(userId: string, preferred?: string): Promise<Subscription> {\n const subs = await this.list(userId);\n if (subs.length === 0) {\n throw new RoxyonApiError(\n 'This account has no active subscription — add a plan in the console first.',\n );\n }\n if (preferred) {\n const hit = subs.find(\n (s) => s.objectId === preferred || s.Name === preferred || s.Username === preferred,\n );\n if (hit) return hit;\n throw new RoxyonApiError(`No subscription matches \"${preferred}\".`);\n }\n return subs.find((s) => s.Status === 'active') ?? subs[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */\nexport type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';\n\nexport interface TokenSummary {\n id: string;\n name: string;\n prefix: string;\n scopes: TokenScope[];\n lastUsedAt: string | null;\n expiresAt: string | null;\n createdAt: string;\n /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */\n monthlyBudgetUSD?: number | null;\n /** For `billing:order` tokens: plan codes it may order (empty = any). */\n allowedSkus?: string[];\n}\n\nexport interface CreatedToken {\n /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */\n token: string;\n name: string;\n scopes: TokenScope[];\n expiresAt: string | null;\n}\n\n/**\n * Personal Access Tokens — for the CLI in CI and for the MCP server running\n * headless. Managed only while signed in with a session (`roxyon login`); a PAT\n * cannot mint or revoke another PAT.\n *\n * `GET/POST/DELETE /account/tokens` — console endpoints.\n */\nexport class TokensApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(): Promise<TokenSummary[]> {\n const r = await this.client.console<{ ok?: boolean; tokens?: TokenSummary[]; error?: string }>(\n 'GET',\n '/account/tokens',\n { tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list tokens.', { body: r });\n return r.tokens ?? [];\n }\n\n async create(\n name: string,\n opts: {\n scopes?: TokenScope[];\n expiresInDays?: number;\n /** Required with `billing:order`. */\n monthlyBudgetUSD?: number;\n allowedSkus?: string[];\n } = {},\n ): Promise<CreatedToken> {\n const r = await this.client.console<CreatedToken & { ok?: boolean; error?: string }>(\n 'POST',\n '/account/tokens',\n {\n body: {\n name,\n scopes: opts.scopes ?? ['deploy', 'logs'],\n ...(opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {}),\n ...(opts.monthlyBudgetUSD ? { monthlyBudgetUSD: opts.monthlyBudgetUSD } : {}),\n ...(opts.allowedSkus?.length ? { allowedSkus: opts.allowedSkus } : {}),\n },\n tolerateHttpError: true,\n },\n );\n if (!r?.ok || !r.token) {\n throw new RoxyonApiError(r?.error || 'Could not create the token.', { body: r });\n }\n return { token: r.token, name: r.name, scopes: r.scopes, expiresAt: r.expiresAt ?? null };\n }\n\n async revoke(id: string): Promise<void> {\n const r = await this.client.console<{ ok?: boolean; error?: string }>(\n 'DELETE',\n '/account/tokens',\n { query: { id }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not revoke the token.', { body: r });\n }\n}\n","import { RoxyonApiError } from './errors.js';\n\n/** BaaS V2 base. V1 (`/1`) is frozen; app data tools speak V2 only. */\nexport const DEFAULT_BAAS_V2_URL = 'https://www.beaapis.com/2';\n\n/** V2 caps one page at 200 rows. */\nexport const BAAS_MAX_PAGE = 200;\n/** V2 takes 1 to 50 requests per batch. */\nexport const BAAS_MAX_BATCH = 50;\n\nexport interface BaasDataOptions {\n /** The app's secret key (`rxsk_…`): server scope, from the project's API keys in Roxyon Base. */\n secretKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\nexport type BaasRow = Record<string, unknown>;\n\nexport interface BaasQuery {\n /** e.g. `{ Status: 'active', Age: { gt: 18 } }`; `in` takes a comma-joined string. */\n where?: Record<string, unknown>;\n /** `*` and/or column names, comma separated. Defaults to `*`. */\n fields?: string;\n /** Comma list, `-` for descending, e.g. `-createdAt`. */\n order?: string;\n /** 1 to 200 (default 50). */\n limit?: number;\n skip?: number;\n /** Also return the total number of matching rows. */\n count?: boolean;\n}\n\nexport interface BaasBatchRequest {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n /** `/Class` or `/Class/<id>`. */\n path: string;\n body?: Record<string, unknown>;\n}\n\n/** One batch answer: `ok:false` with `error`/`message`, or that request's own V2 answer. */\nexport interface BaasBatchResult {\n status: number;\n ok?: boolean;\n error?: string;\n message?: string;\n result?: BaasRow;\n results?: BaasRow[];\n count?: number;\n id?: string;\n}\n\ninterface V2Body {\n ok?: boolean;\n error?: string;\n message?: string;\n details?: unknown;\n result?: BaasRow;\n results?: unknown[];\n count?: number;\n id?: string;\n}\n\n// Mirrors App.php: classes `^[A-Za-z][A-Za-z0-9_]{0,63}$` (no `_` system classes), ids `^[A-Za-z0-9]{1,40}$`.\nconst CLASS_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID_RE = /^[A-Za-z0-9]{1,40}$/;\n\nfunction checkClass(name: string): string {\n if (!CLASS_RE.test(name)) throw new Error(`Invalid class name \"${name}\".`);\n return name;\n}\n\nfunction checkId(id: string): string {\n if (!ID_RE.test(id)) throw new Error(`Invalid objectId \"${id}\".`);\n return id;\n}\n\n/**\n * Records of ONE app on BaaS V2, as that app's own backend (server scope, `X-RX-Secret-Key`).\n * Server scope passes every class rule, so treat the key like a database password. V2 answers\n * failures as `{ok:false, error, message}` with an HTTP status; every call throws on those.\n * Schema changes are not reachable with a secret key (console API only).\n */\nexport class BaasDataApi {\n private readonly baseUrl: string;\n private readonly secretKey: string;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: BaasDataOptions) {\n if (!opts.secretKey.startsWith('rxsk_')) {\n throw new Error('BaaS V2 needs the app secret key (starts with rxsk_).');\n }\n this.secretKey = opts.secretKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_V2_URL).replace(/\\/+$/, '');\n this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n private async call(\n method: string,\n path: string,\n opts: { query?: Record<string, string>; body?: unknown } = {},\n ): Promise<V2Body> {\n const qs =\n opts.query && Object.keys(opts.query).length ? `?${new URLSearchParams(opts.query)}` : '';\n const headers: Record<string, string> = { 'x-rx-secret-key': this.secretKey };\n if (opts.body !== undefined) headers['content-type'] = 'application/json';\n let res: Response;\n try {\n res = await this._fetch(`${this.baseUrl}${path}${qs}`, {\n method,\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n });\n } catch (e) {\n throw new RoxyonApiError(`Could not reach ${this.baseUrl}: ${(e as Error).message}`);\n }\n let body: V2Body = {};\n try {\n body = ((await res.json()) as V2Body) ?? {};\n } catch {\n // Non-JSON (proxy error page): handled below.\n }\n if (!res.ok || body.ok !== true) {\n const msg = body.message || body.error || `HTTP ${res.status}`;\n throw new RoxyonApiError(msg, { status: res.status, type: body.error, body });\n }\n return body;\n }\n\n private static recordPath(className: string, id?: string): string {\n return `/records/${checkClass(className)}${id === undefined ? '' : `/${checkId(id)}`}`;\n }\n\n async query(className: string, q: BaasQuery = {}): Promise<{ rows: BaasRow[]; count?: number }> {\n const limit = q.limit ?? 50;\n if (!Number.isInteger(limit) || limit < 1 || limit > BAAS_MAX_PAGE) {\n throw new Error(`limit must be 1 to ${BAAS_MAX_PAGE}.`);\n }\n const query: Record<string, string> = { fields: q.fields || '*', limit: String(limit) };\n // V2 takes where as JSON text, so operators and `in` strings survive unchanged.\n if (q.where && Object.keys(q.where).length) query.where = JSON.stringify(q.where);\n if (q.order) query.order = q.order;\n if (q.skip) query.skip = String(q.skip);\n if (q.count) query.count = '1';\n const r = await this.call('GET', BaasDataApi.recordPath(className), { query });\n return {\n rows: (r.results ?? []) as BaasRow[],\n ...(r.count !== undefined ? { count: r.count } : {}),\n };\n }\n\n async get(className: string, objectId: string): Promise<BaasRow> {\n const r = await this.call('GET', BaasDataApi.recordPath(className, objectId));\n return r.result ?? {};\n }\n\n /** Returns the created row as stored. */\n async create(className: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('POST', BaasDataApi.recordPath(className), { body: { data } });\n return r.result ?? {};\n }\n\n async update(className: string, objectId: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('PUT', BaasDataApi.recordPath(className, objectId), {\n body: { data },\n });\n return r.result ?? {};\n }\n\n /** The id goes in the URL path, never the body. */\n async delete(className: string, objectId: string): Promise<void> {\n await this.call('DELETE', BaasDataApi.recordPath(className, objectId));\n }\n\n /** 1 to 50 record requests in one call; one failing doesn't stop the others. */\n async batch(requests: BaasBatchRequest[]): Promise<BaasBatchResult[]> {\n if (requests.length < 1 || requests.length > BAAS_MAX_BATCH) {\n throw new Error(`A batch takes 1 to ${BAAS_MAX_BATCH} requests.`);\n }\n for (const req of requests) {\n const [cls, id, extra] = req.path.split('/').filter(Boolean);\n if (!cls || extra !== undefined)\n throw new Error(`Batch path \"${req.path}\" must be /Class or /Class/id.`);\n checkClass(cls);\n if (id !== undefined) checkId(id);\n }\n const r = await this.call('POST', '/batch', { body: { requests } });\n return (r.results ?? []) as BaasBatchResult[];\n }\n}\n","/**\n * `.env`-style block <-> JSON object, ported verbatim from `appfEnvParse` /\n * `appfEnvToLines` in `console.roxyon.com/.../modals/app_form.view` so the CLI\n * and the console form agree byte-for-byte on what `Applications.Env` holds.\n *\n * The server re-sanitises again (`ApplicationRenderer::envPair`), so this only\n * needs to be reasonable. `PORT` and `HOST` are set by the platform — callers\n * should not write them.\n */\nexport function parseEnv(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (let line of String(text || '').split(/\\r?\\n/)) {\n line = line.trim();\n if (!line || line.startsWith('#')) continue;\n line = line.replace(/^export\\s+/, '');\n const eq = line.indexOf('=');\n if (eq < 1) continue;\n const k = line.slice(0, eq).trim();\n let v = line.slice(eq + 1).trim();\n if (v.length >= 2 && (v[0] === '\"' || v[0] === \"'\") && v[v.length - 1] === v[0]) {\n v = v.slice(1, -1);\n }\n if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) out[k] = v;\n }\n return out;\n}\n\nexport function formatEnv(obj: Record<string, string> | null | undefined): string {\n if (!obj || typeof obj !== 'object') return '';\n return Object.keys(obj)\n .map((k) => `${k}=${obj[k] == null ? '' : String(obj[k])}`)\n .join('\\n');\n}\n\n/** Parse the JSON string stored on `Applications.Env`. */\nexport function envFromStored(jsonStr: string | undefined): Record<string, string> {\n if (!jsonStr) return {};\n try {\n const obj = JSON.parse(jsonStr);\n return obj && typeof obj === 'object' ? (obj as Record<string, string>) : {};\n } catch {\n return {};\n }\n}\n","/**\n * Runtime / version / framework catalog — a verbatim copy of the `RUNTIMES`\n * table in `console.roxyon.com/.../modals/app_form.view`. These are the versions\n * actually installed in the Cloud Hosting containers; offering an uninstalled\n * one produces a deploy that fails at build time for a reason the user cannot\n * act on.\n *\n * TODO(M4): the console form and this file should both import one shared JSON\n * published at `roxyon.com/runtimes.json` so they never drift.\n */\nexport type RuntimeName = 'lumen' | 'node' | 'python' | 'php';\n\nexport interface RuntimeSpec {\n versions: string[];\n defaultVersion: string;\n presets: Array<[value: string, label: string]>;\n command: string;\n}\n\nexport const RUNTIMES: Record<Exclude<RuntimeName, 'lumen'>, RuntimeSpec> = {\n node: {\n versions: ['23.11.1', '22.23.1', '20.20.2', '18.20.8'],\n defaultVersion: '20.20.2',\n presets: [\n ['nextjs', 'Next.js'],\n ['nuxt', 'Nuxt'],\n ['node', 'No framework'],\n ],\n command: 'npm run start',\n },\n python: {\n versions: ['3.11'],\n defaultVersion: '3.11',\n presets: [['python', 'No framework']],\n command: 'gunicorn app:app',\n },\n php: {\n versions: ['8.4', '8.3', '8.2', '8.1', '7.4'],\n defaultVersion: '8.4',\n presets: [\n ['swoole', 'Swoole'],\n ['php', 'No framework'],\n ],\n command: 'php8.4 server.php',\n },\n};\n\n/**\n * A LumenJS project (`runtime: \"lumen\"`) builds to static files with\n * `lm build --serverless` and is served straight from the host's document root\n * by nginx — no long-running process, no systemd unit, no Application row. It\n * deploys through the \"static\" path (upload the built `dist/` to\n * `/home/www/<host>/public_html[/<folder>]`).\n *\n * Node / Python / PHP projects deploy through the \"app\" path (the Applications\n * system: upload source, bump ConfigRevision, reconciler builds + runs it).\n */\nexport type DeployKind = 'static' | 'app';\n\nexport const LUMEN_BUILD = {\n command: 'lm build --serverless',\n /** Directory `lm build --serverless` writes to, relative to the project root. */\n outDir: 'dist',\n} as const;\n","import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.js';\nimport { BillingApi } from './billing.js';\nimport { RoxyonClient, type RoxyonClientOptions } from './client.js';\nimport { DatabasesApi } from './databases.js';\nimport { DomainsApi } from './domains.js';\nimport { EmailApi } from './email.js';\nimport { SitesApi } from './sites.js';\nimport { SshApi } from './ssh.js';\nimport { SubscriptionsApi } from './subscriptions.js';\nimport { TokensApi } from './tokens.js';\n\nexport { RoxyonClient } from './client.js';\nexport type { RoxyonClientOptions, RequestOptions } from './client.js';\nexport { AuthApi } from './auth.js';\nexport type { RoxyonUser, LoginResult, LoginPrecheck, SessionGrant } from './auth.js';\nexport { ApplicationsApi } from './applications.js';\nexport type {\n Application,\n ApplicationProcess,\n ApplicationRoute,\n CreateApplicationInput,\n CreateOnDeploy,\n DeployResult,\n} from './applications.js';\nexport { SitesApi } from './sites.js';\nexport type {\n DeployOptions,\n SiteFile,\n SiteFileContent,\n StaticDeployResult,\n} from './sites.js';\nexport { DomainsApi } from './domains.js';\nexport type { CreateDomainInput, CreateDomainResult, Domain } from './domains.js';\nexport { DatabasesApi } from './databases.js';\nexport type {\n CreateDatabaseInput,\n CreateDatabaseResult,\n DatabaseSummary,\n DeleteDatabaseResult,\n} from './databases.js';\nexport { EmailApi } from './email.js';\nexport type {\n CreateEmailInput,\n CreateEmailResult,\n EmailSummary,\n DeleteEmailResult,\n} from './email.js';\nexport { SshApi } from './ssh.js';\nexport type { ResetSshPasswordInput, ResetSshPasswordResult } from './ssh.js';\nexport { SubscriptionsApi } from './subscriptions.js';\nexport type { Subscription, Privilege } from './subscriptions.js';\nexport { BillingApi, BILLING_CYCLES, PAYABLE_STATUSES, isPayable } from './billing.js';\nexport type {\n BillingCycle,\n BillingSubscription,\n CatalogProduct,\n Invoice,\n OrderBudget,\n OrderInput,\n OrderResult,\n Quote,\n QuoteInput,\n} from './billing.js';\nexport { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.js';\nexport {\n BaasDataApi,\n BAAS_MAX_BATCH,\n BAAS_MAX_PAGE,\n DEFAULT_BAAS_V2_URL,\n} from './baas-data.js';\nexport type {\n BaasBatchRequest,\n BaasBatchResult,\n BaasDataOptions,\n BaasQuery,\n BaasRow,\n} from './baas-data.js';\nexport { TokensApi } from './tokens.js';\nexport type { TokenScope, TokenSummary, CreatedToken } from './tokens.js';\nexport { RoxyonApiError, rxError, isAuthError, assertOk } from './errors.js';\nexport { parseEnv, formatEnv, envFromStored } from './env.js';\nexport { RUNTIMES, LUMEN_BUILD } from './runtimes.js';\nexport type { RuntimeName, RuntimeSpec, DeployKind } from './runtimes.js';\nexport { toQueryString } from './query.js';\nexport { DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, DEFAULT_APP } from './constants.js';\n\n/**\n * Convenience facade bundling every sub-API over one {@link RoxyonClient}.\n *\n * ```ts\n * const roxyon = new Roxyon({ sessionToken }); // or a roxp_ PAT\n * const ctx = await roxyon.account.context(); // user + subs + domains\n * ```\n */\nexport class Roxyon {\n readonly client: RoxyonClient;\n readonly auth: AuthApi;\n readonly account: AccountApi;\n readonly tokens: TokensApi;\n readonly subscriptions: SubscriptionsApi;\n readonly domains: DomainsApi;\n readonly applications: ApplicationsApi;\n readonly sites: SitesApi;\n readonly databases: DatabasesApi;\n readonly email: EmailApi;\n readonly ssh: SshApi;\n readonly billing: BillingApi;\n\n constructor(options: RoxyonClientOptions | RoxyonClient = {}) {\n this.client = options instanceof RoxyonClient ? options : new RoxyonClient(options);\n this.auth = new AuthApi(this.client);\n this.account = new AccountApi(this.client);\n this.tokens = new TokensApi(this.client);\n this.subscriptions = new SubscriptionsApi(this.client);\n this.domains = new DomainsApi(this.client);\n this.applications = new ApplicationsApi(this.client);\n this.sites = new SitesApi(this.client);\n this.databases = new DatabasesApi(this.client);\n this.email = new EmailApi(this.client);\n this.ssh = new SshApi(this.client);\n this.billing = new BillingApi(this.client);\n }\n\n get sessionToken(): string | undefined {\n return this.client.getSessionToken();\n }\n}\n"],"mappings":"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","names":["json"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.ts","../src/billing.ts","../src/constants.ts","../src/query.ts","../src/client.ts","../src/databases.ts","../src/domains.ts","../src/email.ts","../src/sites.ts","../src/ssh.ts","../src/subscriptions.ts","../src/tokens.ts","../src/baas-data.ts","../src/env.ts","../src/runtimes.ts","../src/index.ts"],"sourcesContent":["/**\n * The Roxyon BaaS (\"RX\" engine) resolves failed writes rather than rejecting\n * them — a rejected promise never fires and a failure is shaped like a success\n * body with an `error` string on it (top-level, or inside `results[]`). Every\n * write must be run through {@link rxError} before it is treated as having\n * worked. This mirrors `rxError()` in `console.roxyon.com/src/index.js`.\n *\n * Known failure shapes:\n * { \"results\": [ { \"code\": 1054, \"error\": \"Unknown column ...\", \"type\": \"DBQueryError\" } ] }\n * { \"code\": 105, \"error\": \"Invalid Field Name\", \"type\": \"InvalidFieldName\" }\n */\n\nexport interface RxErrorBody {\n code?: number;\n error?: string;\n type?: string;\n results?: unknown;\n}\n\n/** Returns the error message from a BaaS response, or `''` when the call worked. */\nexport function rxError(r: unknown): string {\n if (r === null || r === undefined) return 'No response from the server.';\n if (typeof r !== 'object') return '';\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body.error;\n const rows = body.results;\n if (Array.isArray(rows)) {\n for (const row of rows) {\n if (row && typeof row === 'object' && typeof (row as RxErrorBody).error === 'string') {\n const msg = (row as RxErrorBody).error;\n if (msg) return msg;\n }\n }\n }\n return '';\n}\n\nexport class RoxyonApiError extends Error {\n readonly code?: number;\n readonly type?: string;\n readonly status?: number;\n readonly body: unknown;\n\n constructor(\n message: string,\n opts: { code?: number; type?: string; status?: number; body?: unknown } = {},\n ) {\n super(message);\n this.name = 'RoxyonApiError';\n this.code = opts.code;\n this.type = opts.type;\n this.status = opts.status;\n this.body = opts.body;\n }\n}\n\nconst AUTH_CODES = new Set([101, 141, 209, 1060, 1063, 401]);\nconst AUTH_HINTS = [\n 'invalid session',\n 'session token',\n 'unauthorized',\n 'not authorized',\n 'invalid token',\n 'expired',\n 'log in again',\n];\n\n/** True when an error looks like \"the session/token is gone\", so the caller can re-auth. */\nexport function isAuthError(err: unknown): boolean {\n if (err instanceof RoxyonApiError) {\n if (err.status === 401 || err.status === 403) return true;\n if (err.code !== undefined && AUTH_CODES.has(err.code)) return true;\n }\n const msg = (\n err instanceof Error ? err.message : typeof err === 'string' ? err : rxError(err)\n ).toLowerCase();\n return AUTH_HINTS.some((h) => msg.includes(h));\n}\n\n/** Locate the object (top-level or a `results[]` row) that carries the error. */\nfunction erroringNode(r: unknown): RxErrorBody | undefined {\n if (!r || typeof r !== 'object') return undefined;\n const body = r as RxErrorBody;\n if (typeof body.error === 'string' && body.error) return body;\n if (Array.isArray(body.results)) {\n for (const row of body.results) {\n if (row && typeof row === 'object' && (row as RxErrorBody).error) return row as RxErrorBody;\n }\n }\n return undefined;\n}\n\n/** Throw a {@link RoxyonApiError} if `r` carries a BaaS error; otherwise return it typed. */\nexport function assertOk<T>(r: T): T {\n const msg = rxError(r);\n if (msg) {\n const node = erroringNode(r);\n throw new RoxyonApiError(msg, { code: node?.code, type: node?.type, body: r });\n }\n return r;\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\nimport type { TokenScope } from './tokens.js';\n\nexport interface AccountSubscription {\n id: string;\n name: string;\n status: string;\n}\n\nexport interface AccountDomain {\n id: string;\n name: string;\n subscription: string;\n /** `active`, or `provisioning` while a freshly-added host comes up. */\n status?: string;\n}\n\nexport interface AccountContext {\n user: { id: string; email: string };\n scopes: (TokenScope | '*')[];\n subscriptions: AccountSubscription[];\n domains: AccountDomain[];\n}\n\nexport interface AccountApp {\n id: string;\n name: string;\n status: string;\n desiredState: string;\n runtime: string;\n configRevision: number;\n appliedRevision: number;\n lastError: string | null;\n repo: { url: string; branch: string } | null;\n}\n\n/**\n * `GET /account/context` — one call the CLI / MCP server use to plan a deploy:\n * the signed-in user, their subscriptions, and their domains. Resolvable by a\n * session token OR a Personal Access Token, so a CI job with only a PAT never\n * has to touch the BaaS. Infra details (nodes, datacenters, container names,\n * filesystem paths) are deliberately not surfaced here.\n */\nexport class AccountApi {\n private cache?: Promise<AccountContext>;\n\n constructor(private readonly client: RoxyonClient) {}\n\n context(opts: { fresh?: boolean } = {}): Promise<AccountContext> {\n if (!this.cache || opts.fresh) this.cache = this.fetch();\n return this.cache;\n }\n\n private async fetch(): Promise<AccountContext> {\n const r = await this.client.console<AccountContext & { ok?: boolean; error?: string }>(\n 'GET',\n '/account/context',\n { tolerateHttpError: true },\n );\n if (!r?.ok || !r.user?.id) {\n throw new RoxyonApiError(r?.error || 'Could not load the account context.', { body: r });\n }\n // Map explicitly — the endpoint may carry infra fields (node/datacenter/\n // container); keep only what a deploy actually needs so they never reach\n // an AI assistant's context or a log.\n return {\n user: { id: r.user.id, email: r.user.email },\n scopes: r.scopes ?? [],\n subscriptions: (r.subscriptions ?? []).map((s) => ({\n id: s.id,\n name: s.name,\n status: s.status,\n })),\n domains: (r.domains ?? []).map((d) => ({\n id: d.id,\n name: d.name,\n subscription: d.subscription,\n ...(d.status ? { status: d.status } : {}),\n })),\n };\n }\n\n /** `GET /account/apps` — the account's applications (list, PAT-safe). */\n async apps(): Promise<AccountApp[]> {\n const r = await this.client.console<{\n ok?: boolean;\n applications?: AccountApp[];\n error?: string;\n }>('GET', '/account/apps', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list applications.', { body: r });\n return (r.applications ?? []).map((a) => ({\n id: a.id,\n name: a.name,\n status: a.status,\n desiredState: a.desiredState,\n runtime: a.runtime,\n configRevision: a.configRevision,\n appliedRevision: a.appliedRevision,\n lastError: a.lastError,\n repo: a.repo,\n }));\n }\n\n /** One application by id, PAT-safe (filters {@link apps}). */\n async getApp(id: string): Promise<AccountApp | undefined> {\n return (await this.apps()).find((a) => a.id === id);\n }\n\n /** Pick the subscription to deploy against — the preferred one, else the only/first. */\n async resolveSubscription(preferred?: string): Promise<AccountSubscription> {\n const { subscriptions } = await this.context();\n if (subscriptions.length === 0) {\n throw new RoxyonApiError('This account has no subscriptions.');\n }\n if (preferred) {\n const hit = subscriptions.find((s) => s.id === preferred || s.name === preferred);\n if (hit) return hit;\n }\n return subscriptions[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError, assertOk } from './errors.js';\n\nexport interface Application {\n objectId: string;\n Name: string;\n Status?: string;\n DesiredState?: string;\n SourcePath?: string;\n Runtime?: string;\n RuntimeVersion?: string;\n Preset?: string;\n ConfigRevision?: number;\n AppliedRevision?: number;\n LastError?: string;\n Env?: string;\n RepoUrl?: string;\n Subscription?: string;\n [k: string]: unknown;\n}\n\nexport interface ApplicationProcess {\n objectId: string;\n Application?: string;\n Type?: string;\n Command?: string;\n Status?: string;\n Port?: number;\n}\n\nexport interface ApplicationRoute {\n objectId: string;\n Application?: string;\n Domain?: string;\n Path?: string;\n Enabled?: number | string;\n}\n\ninterface Results<T> {\n results?: T[];\n error?: string;\n}\n\nexport interface DeployResult {\n ok: boolean;\n application: string;\n created?: boolean;\n configRevision?: number;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\n/** Params for creating an application on its first deploy (no id yet). */\nexport interface CreateOnDeploy {\n host: string;\n folder?: string;\n runtime: 'node' | 'python' | 'php';\n runtimeVersion?: string;\n preset?: string;\n command?: string;\n public?: boolean;\n}\n\nexport interface CreateApplicationInput {\n subscription: string;\n name: string;\n /** Absolute source path: `/home/www/<host>/public_html/<folder>`. */\n sourcePath: string;\n runtime: string;\n runtimeVersion: string;\n preset: string;\n /** The web process start command. */\n command: string;\n /** Route host (`Domains.objectId`). */\n domainId: string;\n /** `.env`-style object stored as JSON on `Applications.Env`. */\n env?: Record<string, string>;\n /** Make the app public (route serves the app instead of the host's files). */\n public?: boolean;\n}\n\n/**\n * The Roxyon Applications system. Deployment is declarative: rows describe the\n * desired state and every meaningful change bumps `ConfigRevision`; a\n * server-side reconciler builds the source in an isolated release dir and\n * (re)starts a systemd unit, writing back `Status` / `AppliedRevision` /\n * `LastError`. Mirrors `applications.view` + `modals/app_form.view`.\n */\nexport class ApplicationsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Application[]> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n async get(id: string): Promise<Application | undefined> {\n const r = await this.client.get<Results<Application>>('/Applications', {\n fields:\n 'objectId,Name,Status,DesiredState,SourcePath,Runtime,RuntimeVersion,Preset,ConfigRevision,AppliedRevision,LastError,Env,RepoUrl,Subscription',\n limit: 1,\n where: { objectId: id },\n });\n return r.results?.[0];\n }\n\n /** Create the application + its web process + a route, matching `createNew()`. */\n async create(\n input: CreateApplicationInput,\n ): Promise<{ application: string; process: string; route: string }> {\n const appRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/Applications', {\n Subscription: input.subscription,\n Name: input.name,\n Preset: input.preset,\n SourcePath: input.sourcePath,\n Runtime: input.runtime,\n RuntimeVersion: input.runtimeVersion,\n Env: JSON.stringify(input.env ?? {}),\n Status: 'pending',\n DesiredState: 'running',\n ConfigRevision: 1,\n AppliedRevision: 0,\n LastError: '',\n }),\n );\n const appId = appRes.results?.[0]?.objectId;\n if (!appId) throw new RoxyonApiError('No application id returned.', { body: appRes });\n\n const procRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationProcesses', {\n Application: appId,\n Type: 'web',\n Port: 0, // allocated by the backend at deploy time\n Command: input.command,\n Status: 'pending',\n }),\n );\n const procId = procRes.results?.[0]?.objectId ?? '';\n\n const routeRes = assertOk(\n await this.client.post<Results<{ objectId: string }>>('/ApplicationRoutes', {\n Application: appId,\n Domain: input.domainId,\n Path: '/',\n Enabled: input.public ? 1 : 0,\n }),\n );\n const routeId = routeRes.results?.[0]?.objectId ?? '';\n\n return { application: appId, process: procId, route: routeId };\n }\n\n // ---- console endpoints (session token or PAT) ----\n\n /** Read an application's environment. `GET /applications/env`. */\n async getEnv(applicationId: string): Promise<Record<string, string>> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n error?: string;\n }>('GET', '/applications/env', {\n query: { application: applicationId },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not read the environment.', { body: r });\n return r.env ?? {};\n }\n\n /**\n * Merge `set` and delete `remove`, bumping `ConfigRevision`. `PORT`/`HOST` are\n * ignored (platform-managed). `POST /applications/env`. Returns the new env.\n */\n async setEnv(\n applicationId: string,\n changes: { set?: Record<string, string>; remove?: string[] },\n ): Promise<{ env: Record<string, string>; changed: string[]; configRevision: number }> {\n const r = await this.client.console<{\n ok?: boolean;\n env?: Record<string, string>;\n changed?: string[];\n configRevision?: number;\n error?: string;\n }>('POST', '/applications/env', {\n query: { application: applicationId },\n body: { set: changes.set ?? {}, remove: changes.remove ?? [] },\n tolerateHttpError: true,\n });\n if (!r?.ok)\n throw new RoxyonApiError(r?.error || 'Could not update the environment.', { body: r });\n return { env: r.env ?? {}, changed: r.changed ?? [], configRevision: r.configRevision ?? 0 };\n }\n\n /** Rebuild from the latest source and restart. `POST /applications/action`. */\n async deploy(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'deploy' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /** Bounce the process only — no rebuild. `POST /applications/action`. */\n async restart(applicationId: string): Promise<void> {\n const r = await this.client.console<{ error?: string }>('POST', '/applications/action', {\n body: { application: applicationId, action: 'restart' },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n }\n\n /**\n * Tail the app's journal. `POST /applications/logs` returns one block per\n * process (`{ type, unit, output }`); this flattens them to lines, each\n * prefixed with the process type when there is more than one.\n */\n async logs(applicationId: string, lines = 100): Promise<string[]> {\n const r = await this.client.console<{\n processes?: Array<{ type?: string; unit?: string; output?: string }>;\n error?: string;\n }>('POST', '/applications/logs', {\n body: { application: applicationId, lines },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n const procs = r?.processes ?? [];\n const multi = procs.length > 1;\n const out: string[] = [];\n for (const p of procs) {\n const body = (p.output ?? '').split('\\n').filter(Boolean);\n for (const line of body) out.push(multi ? `[${p.type ?? 'web'}] ${line}` : line);\n }\n return out;\n }\n\n /** Connect a git remote for push-to-deploy. `POST /applications/repo/connect`. */\n async repoConnect(\n applicationId: string,\n repoUrl: string,\n branch = 'main',\n ): Promise<{\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n }> {\n const r = await this.client.console<{\n error?: string;\n provider?: string;\n deployKey?: string;\n webhookUrl?: string;\n secret?: string;\n hint?: string;\n branch?: string;\n }>('POST', '/applications/repo/connect', {\n body: { application: applicationId, repoUrl, branch },\n tolerateHttpError: true,\n });\n if (r?.error) throw new RoxyonApiError(r.error);\n return r;\n }\n\n /**\n * Upload a gzipped tarball of the project source. The endpoint lands it in the\n * application's `SourcePath` and bumps `ConfigRevision` (the reconciler then\n * builds it in a release dir exactly as for a git deploy).\n *\n * `POST /applications/deploy` — NEW endpoint (see `backend/` in this repo).\n */\n async uploadSource(target: string | CreateOnDeploy, tarball: Uint8Array): Promise<DeployResult> {\n const query: Record<string, string> =\n typeof target === 'string'\n ? { application: target }\n : {\n host: target.host,\n folder: target.folder ?? '',\n runtime: target.runtime,\n ...(target.runtimeVersion ? { runtimeVersion: target.runtimeVersion } : {}),\n ...(target.preset ? { preset: target.preset } : {}),\n ...(target.command ? { command: target.command } : {}),\n public: target.public === false ? '0' : '1',\n };\n const r = await this.client.console<DeployResult>('POST', '/applications/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Upload failed.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface SessionGrant {\n session_token: string;\n refresh_token?: string;\n expires_in?: number;\n status?: string;\n}\n\nexport interface RoxyonUser {\n objectId: string;\n Email?: string;\n Username?: string;\n Name?: string;\n Currency?: string;\n Language?: string;\n [k: string]: unknown;\n}\n\nexport interface LoginPrecheck {\n ok?: boolean;\n error?: string;\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\nexport interface LoginResult {\n sessionToken: string;\n refreshToken?: string;\n expiresIn?: number;\n /** True when an OTP code is still required — call {@link AuthApi.verifyOtp}. */\n stepUpRequired?: boolean;\n challengeId?: string;\n}\n\n/**\n * Wraps the console's login flow:\n * 1. `POST /_account/login-precheck` — validates credentials, decides whether\n * an OTP step-up is required, and (when it is) returns a `challengeId`.\n * 2a. no step-up -> `POST /Auth/login` finalises and returns a session token.\n * 2b. step-up -> caller collects the code, then `POST /Auth/login/otp-verify`.\n *\n * Mirrors `signin.view` / `otp.view` in `console.roxyon.com`.\n */\nexport class AuthApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /**\n * Best-effort device/step-up precheck. `/_account/login-precheck` is a console\n * cloud function that may be gated behind the REST key (not reachable from a\n * public client) — in that case this resolves to `{}` and login falls back to\n * `/Auth/login`, which is itself the security boundary and re-checks the\n * device. Only a definitive `{ ok: false }` / `stepUpRequired` is acted on.\n */\n async precheck(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginPrecheck> {\n try {\n const r = await this.client.post<LoginPrecheck & { code?: number }>(\n '/_account/login-precheck',\n { Email: email, Password: password, metadata },\n { tolerateHttpError: true },\n );\n // Endpoint not available to this client — ignore, let /Auth/login decide.\n if (r?.code === 401 || (r?.error && /rest api key/i.test(r.error))) return {};\n return r ?? {};\n } catch {\n return {};\n }\n }\n\n /**\n * Full login. Returns a session token on success, or `stepUpRequired` with a\n * `challengeId` when an OTP code is needed next.\n */\n async login(\n email: string,\n password: string,\n metadata: Record<string, string> = {},\n ): Promise<LoginResult> {\n const pre = await this.precheck(email, password, metadata);\n if (pre.ok === false && pre.error && !pre.stepUpRequired) {\n throw new RoxyonApiError(pre.error, { type: 'CredentialsError' });\n }\n if (pre.stepUpRequired) {\n return { sessionToken: '', stepUpRequired: true, challengeId: pre.challengeId };\n }\n\n const grant = await this.client.post<\n SessionGrant & { error?: string; stepUpRequired?: boolean; challengeId?: string }\n >('/Auth/login', { Email: email, Password: password, metadata }, { tolerateHttpError: true });\n\n // Some accounts step up at /Auth/login itself rather than at precheck.\n if (grant?.stepUpRequired || (grant?.challengeId && !grant.session_token)) {\n return { sessionToken: '', stepUpRequired: true, challengeId: grant.challengeId };\n }\n if (!grant?.session_token) {\n throw new RoxyonApiError(grant?.error || 'Wrong email or password.', {\n type: 'CredentialsError',\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Complete an OTP step-up with the code the user received. */\n async verifyOtp(challengeId: string, code: string): Promise<LoginResult> {\n const grant = await this.client.post<SessionGrant & { error?: string }>(\n '/Auth/login/otp-verify',\n { challengeId, code },\n { tolerateHttpError: true },\n );\n if (grant?.status !== 'authenticated' || !grant.session_token) {\n throw new RoxyonApiError(grant?.error || 'That code did not verify.', {\n type: 'OtpError',\n body: grant,\n });\n }\n this.client.setSessionToken(grant.session_token);\n return {\n sessionToken: grant.session_token,\n refreshToken: grant.refresh_token,\n expiresIn: grant.expires_in,\n };\n }\n\n /** Start an OTP-only sign-in (no password). Returns a `challengeId`. */\n async startOtp(email: string): Promise<{ challengeId: string }> {\n const r = await this.client.post<{ challengeId?: string; error?: string }>(\n '/Auth/login/otp',\n { Email: email },\n { tolerateHttpError: true },\n );\n if (!r?.challengeId) {\n throw new RoxyonApiError(r?.error || 'Could not start OTP sign-in.', { body: r });\n }\n return { challengeId: r.challengeId };\n }\n\n /** The currently authenticated user. Requires a session token on the client. */\n async me(): Promise<RoxyonUser> {\n const user = await this.client.post<RoxyonUser & { error?: string }>('/Auth/me', {});\n if (!user?.objectId) {\n throw new RoxyonApiError(user?.error || 'Not signed in.', { status: 401, body: user });\n }\n return user;\n }\n\n async logout(): Promise<void> {\n await this.client.post('/Auth/logout', {}, { tolerateHttpError: true }).catch(() => undefined);\n this.client.setSessionToken(undefined);\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** Billing cycles the checkout accepts (Pricing::CYCLE_MONTHS). */\nexport const BILLING_CYCLES = ['monthly', 'quarterly', 'yearly', 'biennial'] as const;\nexport type BillingCycle = (typeof BILLING_CYCLES)[number];\n\n// Plans of this service are resellers' private resold copies, never the public catalog\n// (same filter as the console's own bootstrap).\nconst RESELLER_RESOLD_SERVICE_ID = 'bjMqdLqAKl';\n\nexport interface CatalogProduct {\n /** Plan objectId: what quotes and orders take. */\n planId: string;\n /** Plan code, e.g. `SCALE-S`. */\n sku: string;\n name: string;\n /** Service type, e.g. `cloud.vps.scale`, `cloud.hosting.solo`. */\n category: string;\n vcpu?: number;\n ramGb?: number;\n diskGb?: number;\n cpuType?: string;\n /** Dedicated IPv4 addresses included (servers). */\n ipv4Included?: number;\n /** List prices in USD before tax, per cycle. Quote for the buyer's currency and tax. */\n pricesUSD: Partial<Record<BillingCycle, number>>;\n /** Setup fee in USD per cycle, when not zero. */\n setupFeeUSD?: Partial<Record<BillingCycle, number>>;\n /** `out` = cannot be ordered right now. */\n stock: 'in' | 'out';\n /** Feature table as the console shows it. */\n features?: Record<string, unknown>;\n}\n\nexport interface QuoteInput {\n planId: string;\n cycle: BillingCycle;\n /** ISO 4217, e.g. `SAR`. Default USD. */\n currency?: string;\n /** ISO 3166 alpha-2, decides tax (e.g. `SA` = 15% VAT). Empty = no tax line. */\n country?: string;\n}\n\nexport interface Quote {\n planId: string;\n cycle: string;\n currency: string;\n lineItems: Array<{ label: string; amount: string; amountUSD: string }>;\n subtotal: string;\n taxRate: string;\n taxLabel: string;\n taxAmount: string;\n discountAmount: string;\n total: string;\n fxRate: string;\n baseAmountUSD: string;\n}\n\nexport interface OrderInput {\n /** Plan code from the catalog, e.g. `SCALE-S`. */\n sku: string;\n cycle: BillingCycle;\n /** A name for the service. */\n name: string;\n /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */\n username: string;\n /** Servers only: OS image, e.g. `ubuntu-24.04`. */\n image?: string;\n sshKey?: string;\n phpVersion?: string;\n datacenter?: string;\n currency?: string;\n country?: string;\n /** false/absent = dry run (quote + budget check, nothing written). */\n confirm?: boolean;\n}\n\nexport interface OrderBudget {\n monthlyUSD: number;\n spentUSD: number;\n remainingUSD: number;\n}\n\nexport interface OrderResult {\n dryRun?: boolean;\n plan: { id: string; sku: string; name: string; kind: 'hosting' | 'server'; cycle: string };\n /** Dry run: the server quote (same shape as GET /_payment/quote). */\n quote?: Record<string, unknown>;\n subscriptionId?: string;\n invoiceId?: string;\n total?: string;\n currency?: string;\n payUrl?: string;\n /** null for a console session (no token budget). */\n budget: OrderBudget | null;\n}\n\nexport interface BillingSubscription {\n id: string;\n name: string;\n status: string;\n plan: string;\n sku: string;\n cycle: string;\n price: string;\n currency: string;\n nextBillingDate: string | null;\n autoRenew: boolean;\n serverState: string | null;\n publicIp: string | null;\n}\n\nexport interface Invoice {\n id: string;\n number: string;\n type: string;\n status: string;\n total: string;\n currency: string;\n dueDate: string | null;\n subscription: string | null;\n createdAt: string;\n payUrl: string | null;\n}\n\n/** Invoice statuses a customer can still pay. */\nexport const PAYABLE_STATUSES = ['pending', 'overdue', 'failed'] as const;\n\nexport function isPayable(status: string): boolean {\n return (PAYABLE_STATUSES as readonly string[]).includes(status.toLowerCase());\n}\n\nfunction json<T>(v: unknown, fallback: T): T {\n if (v && typeof v === 'object') return v as T;\n if (typeof v !== 'string' || v === '') return fallback;\n try {\n return JSON.parse(v) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction numbers(v: unknown): Partial<Record<BillingCycle, number>> {\n const out: Partial<Record<BillingCycle, number>> = {};\n const src = json<Record<string, unknown>>(v, {});\n for (const c of BILLING_CYCLES) {\n const n = Number(src[c]);\n if (src[c] !== undefined && src[c] !== '' && Number.isFinite(n)) out[c] = n;\n }\n return out;\n}\n\ninterface PlanRow {\n objectId: string;\n Name?: string;\n Code?: string;\n Limits?: unknown;\n Features?: unknown;\n _Service?: { results?: Array<{ Type?: string }> };\n _Pricing?: {\n results?: Array<{\n Prices?: unknown;\n SetupFee?: unknown;\n MetaData?: unknown;\n IsActive?: unknown;\n }>;\n };\n}\n\n/**\n * Catalog + quotes (public, no sign-in) and the caller's own subscriptions + invoices\n * (console, session or PAT). Read-only: nothing here creates orders or invoices.\n */\nexport class BillingApi {\n constructor(\n private readonly client: RoxyonClient,\n private readonly pub: RoxyonClient = client.publicClient(),\n ) {}\n\n async catalog(): Promise<CatalogProduct[]> {\n const r = await this.pub.get<{ results?: PlanRow[]; error?: string }>('/Plans', {\n fields: '*',\n limit: -1,\n order: 'objectId',\n where: { Status: 'active', Service: { nin: RESELLER_RESOLD_SERVICE_ID } },\n include: [\n { className: 'Services', field: 'Service', fields: 'Type' },\n {\n className: 'Pricing',\n field: 'Plan',\n fields: 'Prices,SetupFee,MetaData,IsActive',\n reverse: 1,\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load the catalog.', { body: r });\n }\n const out: CatalogProduct[] = [];\n for (const p of r.results) {\n const pricing = p._Pricing?.results?.[0];\n // Same rule as roxyon.com's pricing page: a plan code, an active Pricing row, a monthly price.\n if (!p.Code || !pricing || Number(pricing.IsActive) === 0) continue;\n const limits = json<Record<string, unknown>>(p.Limits, {});\n const features = json<Record<string, unknown>>(p.Features, {});\n const meta = json<Record<string, unknown>>(pricing.MetaData, {});\n const network = json<Record<string, unknown>>(features.Network, {});\n const setup = numbers(pricing.SetupFee);\n const pricesUSD = numbers(pricing.Prices);\n if (pricesUSD.monthly === undefined) continue;\n const product: CatalogProduct = {\n planId: p.objectId,\n sku: p.Code ?? '',\n name: p.Name ?? '',\n category: p._Service?.results?.[0]?.Type ?? '',\n pricesUSD,\n stock: String(meta.stock ?? 'in').toLowerCase() === 'out' ? 'out' : 'in',\n };\n if (limits.vcpu != null) {\n product.vcpu = Number(limits.vcpu);\n product.ramGb = limits.memory_mb ? Math.round(Number(limits.memory_mb) / 1024) : 0;\n product.diskGb = Number(limits.disk_gb ?? 0);\n product.cpuType = String(limits.cpu_type ?? '');\n }\n if (network['Dedicated IPv4'] != null)\n product.ipv4Included = Number(network['Dedicated IPv4']);\n if (Object.values(setup).some((n) => n > 0)) product.setupFeeUSD = setup;\n if (Object.keys(features).length) product.features = features;\n out.push(product);\n }\n return out;\n }\n\n /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */\n async quote(input: QuoteInput): Promise<Quote> {\n if (!/^[A-Za-z0-9]{1,40}$/.test(input.planId))\n throw new Error(`Invalid planId \"${input.planId}\".`);\n if (!BILLING_CYCLES.includes(input.cycle))\n throw new Error(`Unsupported cycle \"${input.cycle}\".`);\n const q: Record<string, string | number> = {\n type: 'subscription.new',\n planId: input.planId,\n cycle: input.cycle,\n setup: 1,\n };\n if (input.currency) q.currency = input.currency.toUpperCase();\n if (input.country) q.country = input.country.toUpperCase();\n const r = await this.pub.get<\n Partial<Quote> & { ok?: boolean; error?: string; baseAmount?: string }\n >('/_payment/quote', q);\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not price this plan.', { body: r });\n return {\n planId: String(r.planId ?? input.planId),\n cycle: String(r.cycle ?? input.cycle),\n currency: String(r.currency ?? ''),\n lineItems: (r.lineItems ?? []).map((l) => ({\n label: l.label,\n amount: l.amount,\n amountUSD: l.amountUSD,\n })),\n subtotal: String(r.subtotal ?? ''),\n taxRate: String(r.taxRate ?? ''),\n taxLabel: String(r.taxLabel ?? ''),\n taxAmount: String(r.taxAmount ?? ''),\n discountAmount: String(r.discountAmount ?? ''),\n total: String(r.total ?? ''),\n fxRate: String(r.fxRate ?? ''),\n baseAmountUSD: String(r.baseAmount ?? ''),\n };\n }\n\n /**\n * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it\n * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the\n * `billing:order` scope, within that token's monthly budget and allowed SKUs.\n */\n async order(input: OrderInput): Promise<OrderResult> {\n const r = await this.client.console<\n Partial<OrderResult> & { ok?: boolean; error?: string; budget?: OrderBudget }\n >('POST', '/account/order', { body: input, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'The order was not placed.', { body: r });\n return r as OrderResult;\n }\n\n /** The caller's own subscriptions (rows they own), newest first. */\n async subscriptions(): Promise<BillingSubscription[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n subscriptions?: BillingSubscription[];\n }>('GET', '/account/subscriptions', { tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load subscriptions.', { body: r });\n return r.subscriptions ?? [];\n }\n\n /** The caller's own invoices, newest first. */\n async invoices(opts: { status?: string; limit?: number } = {}): Promise<Invoice[]> {\n const q: Record<string, string> = {};\n if (opts.status) q.status = opts.status;\n if (opts.limit) q.limit = String(opts.limit);\n const r = await this.client.console<{ ok?: boolean; error?: string; invoices?: Invoice[] }>(\n 'GET',\n '/account/invoices',\n { tolerateHttpError: true, query: q },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not load invoices.', { body: r });\n // Only an open invoice can be paid (the first console release also linked void ones).\n return (r.invoices ?? []).map((i) => ({ ...i, payUrl: isPayable(i.status) ? i.payUrl : null }));\n }\n}\n","/**\n * Default endpoints and the public application credentials the client uses to\n * mint an anonymous token before a user logs in.\n *\n * `X-BEA-JavaScript-Key` is a **public** key (it ships in browser bundles by\n * design — see `console.roxyon.com/src/index.js`). It is safe to embed here.\n * The REST key is never embedded — user actions always run under a session\n * token or a Personal Access Token.\n *\n * TODO(M1): provision a dedicated `roxyon-cli` BaaS application and swap these\n * for its App-ID / JavaScript-Key so CLI traffic is attributable and rate-limited\n * separately from the web console. Until then the client reuses the console's\n * public pair, which is already exposed in shipped frontend code.\n */\nexport const DEFAULT_BAAS_URL = 'https://www.beaapis.com/1';\nexport const DEFAULT_CONSOLE_URL = 'https://console.roxyon.com';\n\nexport const DEFAULT_APP = {\n appId: 'jAtp2zHGU3FbnrQWrToALFakd_vbiY0ywihn4Hj54lw',\n javascriptKey: 'w2Y9USRg0COtNe-fUqOaC1OOOlNCnV2BG8GZF80w4x8',\n} as const;\n\n/** Header names, lower-cased (the API is case-insensitive but the SDK uses these). */\nexport const H = {\n appId: 'x-bea-application-id',\n jsKey: 'x-bea-javascript-key',\n restKey: 'x-bea-authorization',\n sessionToken: 'x-bea-session-token',\n accessToken: 'x-bea-access-token',\n refreshToken: 'x-bea-refresh-token',\n} as const;\n","/**\n * GET query serialisation for the BaaS, matching the `Obj2Par` helper in the\n * browser SDK (`rx.js`): nested objects become PHP-style bracket keys\n * (`where[User]=abc`, `where[Status][in]=a,b,c`).\n *\n * Two hard-won rules (see the `roxyon-api-write-failures` notes):\n * - The `in` operator takes a **comma-joined string, not an array**. An array\n * serialises to `where[X][in][0]=…` bracket notation the API does not read.\n * Pass `{ in: ['a', 'b'] }` here and we join it for you.\n * - A `select` subquery nested inside an `or` group crashes the API. Resolve\n * ids in a first query, then `or: [..., { objectId: { in: 'a,b' } }]`.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | QueryValue[]\n | { [k: string]: QueryValue };\n\nexport type QueryObject = Record<string, QueryValue>;\n\nfunction encode(k: string, v: string): string {\n return `${encodeURIComponent(k)}=${encodeURIComponent(v)}`;\n}\n\nfunction walk(value: QueryValue, prefix: string, out: string[]): void {\n if (value === null || value === undefined) return;\n\n if (Array.isArray(value)) {\n // A bare array under a normal key -> repeated bracket-index entries. The\n // only array we actually want is `in`, and that is handled below before we\n // ever get here, so this branch is a best-effort fallback.\n value.forEach((item, i) => walk(item, `${prefix}[${i}]`, out));\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n if (key === 'in' || key === 'nin' || key === 'notIn') {\n const joined = Array.isArray(child) ? child.join(',') : String(child);\n out.push(encode(`${prefix}[${key === 'notIn' ? 'nin' : key}]`, joined));\n continue;\n }\n walk(child, `${prefix}[${key}]`, out);\n }\n return;\n }\n\n out.push(encode(prefix, String(value)));\n}\n\n/** Serialise a query object to a `key=value&...` string (no leading `?`). */\nexport function toQueryString(query: QueryObject | undefined): string {\n if (!query) return '';\n const out: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n walk(value, key, out);\n }\n return out.join('&');\n}\n","import { DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, H } from './constants.js';\nimport { RoxyonApiError } from './errors.js';\nimport { type QueryObject, toQueryString } from './query.js';\n\nexport interface RoxyonClientOptions {\n /** BaaS application id. Defaults to the public console app. */\n appId?: string;\n /** Public JavaScript key, used to mint an anonymous token. */\n javascriptKey?: string;\n /** REST API key. Optional; grants full access — only for trusted server use. */\n restKey?: string;\n /** A user session token (from {@link AuthApi.login}). */\n sessionToken?: string;\n /** BaaS REST base, e.g. `https://www.beaapis.com/1`. */\n baseUrl?: string;\n /** Console base that serves the `/applications/*` endpoints. */\n consoleUrl?: string;\n /** Custom fetch (tests / proxies). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n query?: QueryObject;\n body?: unknown;\n headers?: Record<string, string>;\n /** Skip the Authorization/session header entirely (used for token minting). */\n skipAuth?: boolean;\n /** Send/parse the response even on a non-2xx status instead of throwing. */\n tolerateHttpError?: boolean;\n signal?: AbortSignal;\n}\n\ninterface AnonToken {\n access_token?: string;\n session_token?: string;\n refresh_token?: string;\n expires_in?: number;\n /** epoch ms this token becomes unusable */\n _expiresAt?: number;\n}\n\n/**\n * Low-level transport for the Roxyon BaaS and console app endpoints.\n *\n * Auth precedence per request: explicit `sessionToken` -> `restKey` ->\n * a lazily-minted anonymous access token (public app credentials).\n */\nexport class RoxyonClient {\n readonly baseUrl: string;\n readonly consoleUrl: string;\n private readonly appId: string;\n private readonly javascriptKey: string;\n private readonly restKey?: string;\n private readonly _fetch: typeof fetch;\n private sessionToken?: string;\n private anon?: AnonToken;\n\n constructor(opts: RoxyonClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_URL).replace(/\\/+$/, '');\n this.consoleUrl = (opts.consoleUrl ?? DEFAULT_CONSOLE_URL).replace(/\\/+$/, '');\n this.appId = opts.appId ?? DEFAULT_APP.appId;\n this.javascriptKey = opts.javascriptKey ?? DEFAULT_APP.javascriptKey;\n this.restKey = opts.restKey;\n this.sessionToken = opts.sessionToken;\n this._fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this._fetch !== 'function') {\n throw new Error('No fetch implementation available (need Node >= 20 or pass opts.fetch).');\n }\n }\n\n /** Same endpoints and app, no user credentials: for public reads (catalog, quotes)\n * that must work for PAT callers too, whose token the BaaS does not accept. */\n publicClient(): RoxyonClient {\n return new RoxyonClient({\n baseUrl: this.baseUrl,\n consoleUrl: this.consoleUrl,\n appId: this.appId,\n javascriptKey: this.javascriptKey,\n fetch: this._fetch,\n });\n }\n\n getSessionToken(): string | undefined {\n return this.sessionToken;\n }\n\n setSessionToken(token: string | undefined): void {\n this.sessionToken = token;\n }\n\n /** Mint (or reuse) an anonymous access token from the public app credentials. */\n private async anonToken(): Promise<AnonToken> {\n if (this.anon?._expiresAt && this.anon._expiresAt > Date.now() + 5_000) {\n return this.anon;\n }\n const res = await this._fetch(`${this.baseUrl}/Auth`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n [H.appId]: this.appId,\n [H.jsKey]: this.javascriptKey,\n },\n body: JSON.stringify({ scope: 'public' }),\n });\n const json = (await res.json().catch(() => ({}))) as AnonToken;\n if (!json.access_token && !json.session_token) {\n throw new RoxyonApiError('Could not obtain an anonymous BaaS token.', {\n status: res.status,\n body: json,\n });\n }\n json._expiresAt = Date.now() + (json.expires_in ? json.expires_in * 1000 : 3_600_000);\n this.anon = json;\n return json;\n }\n\n /** A Personal Access Token (`roxp_…`) authenticates the console endpoints via\n * `Authorization: Bearer`; it is not a BaaS session token. */\n private get isPat(): boolean {\n return this.sessionToken?.startsWith('roxp_') ?? false;\n }\n\n private async authHeaders(\n skipAuth: boolean,\n isConsole: boolean,\n ): Promise<Record<string, string>> {\n // IMPORTANT: never send X-BEA-Application-ID on an authenticated request.\n // The BaaS `/auth/*` router treats the App-ID header as \"mint me an\n // anonymous token\" and short-circuits — /Auth/login, /Auth/me etc. would\n // silently return a fresh anon token instead of doing their job. The App-ID\n // (+ JS key) is sent only by anonToken()'s own POST /Auth call.\n if (skipAuth) return {};\n if (this.isPat) {\n // Console: Bearer. BaaS: nothing — PAT clients resolve identity and\n // subscriptions through the console's /account/context instead.\n return isConsole ? { authorization: `Bearer ${this.sessionToken}` } : {};\n }\n if (this.sessionToken) return { [H.sessionToken]: this.sessionToken };\n if (this.restKey) return { [H.appId]: this.appId, [H.restKey]: this.restKey };\n const anon = await this.anonToken();\n if (anon.session_token) return { [H.sessionToken]: anon.session_token };\n return { [H.accessToken]: anon.access_token ?? '' };\n }\n\n /** A raw BaaS request. `path` is relative to {@link baseUrl} (leading `/`). */\n async request<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.baseUrl, method, path, opts);\n }\n\n /** A request against the console app endpoints ({@link consoleUrl}). */\n async console<T = unknown>(method: string, path: string, opts: RequestOptions = {}): Promise<T> {\n return this.rawRequest<T>(this.consoleUrl, method, path, opts);\n }\n\n private async rawRequest<T>(\n root: string,\n method: string,\n path: string,\n opts: RequestOptions,\n ): Promise<T> {\n const qs = toQueryString(opts.query);\n const url = `${root}${path.startsWith('/') ? path : `/${path}`}${qs ? `?${qs}` : ''}`;\n const headers: Record<string, string> = {\n ...(await this.authHeaders(opts.skipAuth ?? false, root === this.consoleUrl)),\n ...opts.headers,\n };\n const hasBody = method !== 'GET' && method !== 'HEAD' && opts.body !== undefined;\n let body: string | Uint8Array | ArrayBuffer | FormData | undefined;\n if (hasBody) {\n if (\n typeof opts.body === 'string' ||\n opts.body instanceof Uint8Array ||\n opts.body instanceof ArrayBuffer ||\n (typeof FormData !== 'undefined' && opts.body instanceof FormData)\n ) {\n body = opts.body as string | Uint8Array | ArrayBuffer | FormData;\n } else {\n headers['content-type'] = headers['content-type'] ?? 'application/json';\n body = JSON.stringify(opts.body);\n }\n }\n\n let res: Response;\n try {\n res = await this._fetch(url, { method, headers, body, signal: opts.signal });\n } catch (cause) {\n throw new RoxyonApiError(`Network error calling ${method} ${url}`, { body: cause });\n }\n\n const text = await res.text();\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : {};\n } catch {\n // An HTML page means the route isn't served by the API (a console route not deployed yet falls through to\n // the web app): say so instead of handing the page to the caller as an error message.\n const html = /^\\s*</.test(text);\n json = {\n error: html\n ? `${method} ${path} is not available on this server yet (got a web page instead of the API).`\n : text || `HTTP ${res.status}`,\n _raw: html ? '' : text,\n };\n }\n\n if (!res.ok && !opts.tolerateHttpError) {\n const msg =\n (json &&\n typeof json === 'object' &&\n 'error' in json &&\n (json as { error: string }).error) ||\n `HTTP ${res.status} calling ${method} ${path}`;\n throw new RoxyonApiError(String(msg), { status: res.status, body: json });\n }\n return json as T;\n }\n\n get<T = unknown>(path: string, query?: QueryObject, opts?: RequestOptions): Promise<T> {\n return this.request<T>('GET', path, { ...opts, query });\n }\n post<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('POST', path, { ...opts, body });\n }\n put<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', path, { ...opts, body });\n }\n del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', path, { ...opts, body });\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateDatabaseInput {\n /** DB name suffix — the platform prefixes it with the subscription's own username (globally unique). */\n name: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /**\n * `mysql` (default: MySQL/MariaDB on the shared cluster) or `postgres` (PostgreSQL 15 inside the account's own hosting\n * container, at localhost:5432; the first one installs it, a few minutes) or `redis` (one Redis per account, 127.0.0.1:6379,\n * password-protected). Every hosting account has all three.\n */\n engine?: 'mysql' | 'postgres' | 'redis';\n}\n\nexport interface CreateDatabaseResult {\n ok: boolean;\n objectId: string;\n engine?: 'mysql' | 'postgres' | 'redis';\n port?: number;\n /** How to connect (PostgreSQL: the URL shape and the no-password psql login over SSH). */\n note?: string;\n name: string;\n username: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n /** `<node-ip>:6033` — the ProxySQL endpoint to connect the app to. */\n host?: string;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface DatabaseSummary {\n objectId: string;\n Name: string;\n Username: string;\n Status: string;\n /** `postgres` for PostgreSQL; empty or `mysql` for MySQL/MariaDB. */\n Engine?: string;\n}\n\nexport interface DeleteDatabaseResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Databases attached to a subscription: MySQL/MariaDB (shared Galera cluster) or PostgreSQL (in the account's container). */\nexport class DatabasesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */\n async list(subscriptionId: string): Promise<DatabaseSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n databases?: DatabaseSummary[];\n }>('POST', '/databases/list', {\n body: { subscription: subscriptionId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the databases.', { body: r });\n return r.databases ?? [];\n }\n\n /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */\n async create(input: CreateDatabaseInput): Promise<CreateDatabaseResult> {\n const r = await this.client.console<CreateDatabaseResult>('POST', '/databases/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the database.', { body: r });\n return r;\n }\n\n /** `POST /databases/delete` */\n async delete(databaseId: string): Promise<DeleteDatabaseResult> {\n const r = await this.client.console<DeleteDatabaseResult>('POST', '/databases/delete', {\n body: { database: databaseId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the database.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Domain {\n objectId: string;\n Name: string;\n}\n\nexport interface CreateDomainInput {\n /** FQDN to host — a subdomain of a domain the account already hosts, or `*.roxyon.com`. */\n host: string;\n /** Subscription to attach it to. Omit when the account has exactly one. */\n subscription?: string;\n /** `spa` → unmatched paths serve `/index.html`; default `static`. */\n siteType?: 'static' | 'spa';\n /** PHP version for the vhost (e.g. `\"8.3\"`). Unknown/omitted falls back to the platform default. */\n phpVersion?: string;\n}\n\nexport interface CreateDomainResult {\n ok: boolean;\n objectId: string;\n host: string;\n /** `subdomain` of an owned parent, or `primary`. */\n type: 'subdomain' | 'primary';\n /** `provisioning` while DNS/vhost/TLS come up, then `active` (or `failed`). */\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\n/** Domains (hosts) attached to a subscription. */\nexport class DomainsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(subscriptionId: string): Promise<Domain[]> {\n const r = await this.client.get<{ results?: Domain[] }>('/Domains', {\n fields: 'objectId,Name',\n limit: -1,\n order: 'Name',\n where: { Subscription: subscriptionId },\n });\n return r.results ?? [];\n }\n\n /**\n * `POST /domains/create` — provision a subdomain (DNS + vhost + auto-TLS). The\n * server decides subdomain vs primary from the caller's existing hosts and\n * writes the `pending` row; the platform's reconciler does the rest.\n */\n async create(input: CreateDomainInput): Promise<CreateDomainResult> {\n const r = await this.client.console<CreateDomainResult>('POST', '/domains/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the domain.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface CreateEmailInput {\n /** The part before `@`. */\n localPart: string;\n /** A hostname already on the account. */\n domain: string;\n /** Omit to have the platform generate one. */\n password?: string;\n /** Mailbox quota in MB. Default 1024. */\n quota?: number;\n forwardTo?: string;\n saveCopy?: boolean;\n}\n\nexport interface CreateEmailResult {\n ok: boolean;\n objectId: string;\n email: string;\n /** Shown once — not retrievable afterwards. */\n password?: string;\n quota?: number;\n status: 'provisioning' | 'active' | 'failed';\n error?: string;\n}\n\nexport interface EmailSummary {\n objectId: string;\n Email: string;\n LocalPart: string;\n Status: string;\n Quota?: number;\n}\n\nexport interface DeleteEmailResult {\n ok: boolean;\n objectId: string;\n status: 'deleting' | 'deleted' | 'failed';\n error?: string;\n}\n\n/** Mailboxes attached to a subscription's domains. */\nexport class EmailApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */\n async list(subscriptionId: string): Promise<EmailSummary[]> {\n const r = await this.client.console<{\n ok?: boolean;\n error?: string;\n emails?: Omit<EmailSummary, 'LocalPart'>[];\n }>('POST', '/emails/list', { body: { subscription: subscriptionId }, tolerateHttpError: true });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list the mailboxes.', { body: r });\n return (r.emails ?? []).map((e) => ({ ...e, LocalPart: e.Email.split('@')[0] ?? '' }));\n }\n\n /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */\n async create(input: CreateEmailInput): Promise<CreateEmailResult> {\n const r = await this.client.console<CreateEmailResult>('POST', '/emails/create', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not create the mailbox.', { body: r });\n return r;\n }\n\n /** `POST /emails/delete` */\n async delete(emailId: string): Promise<DeleteEmailResult> {\n const r = await this.client.console<DeleteEmailResult>('POST', '/emails/delete', {\n body: { email: emailId },\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not delete the mailbox.', { body: r });\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface StaticDeployResult {\n ok: boolean;\n host: string;\n path: string;\n files?: number;\n bytes?: number;\n error?: string;\n}\n\nexport interface DeployOptions {\n /** Replace the docroot contents instead of overlaying (keeps `.well-known`). */\n clean?: boolean;\n /** Flip the host to SPA routing: unmatched paths serve `/index.html`. */\n spa?: boolean;\n}\n\nexport interface SiteFile {\n /** POSIX path relative to the site root. */\n path: string;\n size: number;\n type: 'file' | 'dir';\n}\n\nexport interface SiteFileContent {\n path: string;\n size: number;\n encoding: 'utf8' | 'base64';\n content: string;\n}\n\n/**\n * Static-site hosting: the files under a host's document root\n * (`public_html[/<folder>]`), served directly by nginx. No Application row, no\n * process. All routes go to the console (`POST /sites/deploy`, `GET /sites/files`,\n * `GET /sites/file`) and authenticate with a session token or a `roxp_` PAT.\n */\nexport class SitesApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** Upload a gzip tarball into `host`'s docroot (+ optional sub-`folder`). */\n async deploy(\n host: string,\n folder: string,\n tarball: Uint8Array,\n opts: DeployOptions = {},\n ): Promise<StaticDeployResult> {\n const query: Record<string, string> = { host, folder };\n if (opts.clean) query.clean = '1';\n if (opts.spa) query.spa = '1';\n const r = await this.client.console<StaticDeployResult>('POST', '/sites/deploy', {\n query,\n headers: { 'content-type': 'application/gzip' },\n body: tarball,\n tolerateHttpError: true,\n });\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Static deploy failed.', { body: r });\n return r;\n }\n\n /** List the files currently in `host`'s docroot (optionally under `path`). */\n async listFiles(host: string, folder = '', path = ''): Promise<SiteFile[]> {\n const r = await this.client.console<{ ok?: boolean; files?: SiteFile[]; error?: string }>(\n 'GET',\n '/sites/files',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list site files.', { body: r });\n return r.files ?? [];\n }\n\n /** Read one file from `host`'s docroot. */\n async readFile(host: string, folder: string, path: string): Promise<SiteFileContent> {\n const r = await this.client.console<SiteFileContent & { ok?: boolean; error?: string }>(\n 'GET',\n '/sites/file',\n { query: { host, folder, path }, tolerateHttpError: true },\n );\n if (!r?.ok || typeof r.content !== 'string') {\n throw new RoxyonApiError(r?.error || 'Could not read the file.', { body: r });\n }\n return { path: r.path, size: r.size, encoding: r.encoding, content: r.content };\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface ResetSshPasswordInput {\n /** Subscription to reset. Omit when the account has exactly one. */\n subscription?: string;\n /** Omit to have the platform generate one meeting the strength rules. */\n password?: string;\n}\n\nexport interface ResetSshPasswordResult {\n ok: boolean;\n subscription: string;\n /** Shown once — the platform never stores or re-shows it. */\n password: string;\n status: 'pending' | 'active' | 'failed';\n}\n\n/**\n * The shared shell password used for SSH, SFTP and the file manager on a\n * subscription's container (SSHpiper maps the username to the container).\n */\nexport class SshApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** `POST /ssh/password` */\n async resetPassword(input: ResetSshPasswordInput = {}): Promise<ResetSshPasswordResult> {\n const r = await this.client.console<ResetSshPasswordResult>('POST', '/ssh/password', {\n body: input,\n tolerateHttpError: true,\n });\n if (!r?.ok) {\n throw new RoxyonApiError(\n (r as { error?: string })?.error || 'Could not reset the password.',\n {\n body: r,\n },\n );\n }\n return r;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\nexport interface Subscription {\n objectId: string;\n Name?: string;\n Status?: string;\n [k: string]: unknown;\n}\n\nexport interface Privilege {\n objectId: string;\n Type?: string;\n Subscription?: string;\n _Subscription?: { results: Subscription[] };\n [k: string]: unknown;\n}\n\ninterface ListResponse<T> {\n results?: T[];\n error?: string;\n}\n\n/** Access to the caller's subscriptions (via their Privileges rows). */\nexport class SubscriptionsApi {\n constructor(private readonly client: RoxyonClient) {}\n\n /** All subscriptions the signed-in user has a Privilege on. */\n async list(userId: string): Promise<Subscription[]> {\n const r = await this.client.get<ListResponse<Privilege>>('/Privileges', {\n where: { User: userId },\n fields: 'objectId,Type,Subscription',\n limit: -1,\n include: [\n {\n className: 'Subscriptions',\n field: 'Subscription',\n fields: 'objectId,Name,Status',\n },\n ],\n });\n if (!Array.isArray(r.results)) {\n throw new RoxyonApiError(r.error || 'Could not load subscriptions.', {\n status: 401,\n body: r,\n });\n }\n const subs: Subscription[] = [];\n for (const priv of r.results) {\n const sub = priv._Subscription?.results?.[0];\n if (sub) subs.push(sub);\n }\n return subs;\n }\n\n /**\n * Resolve the subscription to act on. Prefers an exact `objectId` or `Name`\n * match against `preferred`; otherwise the first active subscription; otherwise\n * the first one. Throws when the account has none.\n */\n async resolve(userId: string, preferred?: string): Promise<Subscription> {\n const subs = await this.list(userId);\n if (subs.length === 0) {\n throw new RoxyonApiError(\n 'This account has no active subscription — add a plan in the console first.',\n );\n }\n if (preferred) {\n const hit = subs.find(\n (s) => s.objectId === preferred || s.Name === preferred || s.Username === preferred,\n );\n if (hit) return hit;\n throw new RoxyonApiError(`No subscription matches \"${preferred}\".`);\n }\n return subs.find((s) => s.Status === 'active') ?? subs[0]!;\n }\n}\n","import type { RoxyonClient } from './client.js';\nimport { RoxyonApiError } from './errors.js';\n\n/** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */\nexport type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';\n\nexport interface TokenSummary {\n id: string;\n name: string;\n prefix: string;\n scopes: TokenScope[];\n lastUsedAt: string | null;\n expiresAt: string | null;\n createdAt: string;\n /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */\n monthlyBudgetUSD?: number | null;\n /** For `billing:order` tokens: plan codes it may order (empty = any). */\n allowedSkus?: string[];\n}\n\nexport interface CreatedToken {\n /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */\n token: string;\n name: string;\n scopes: TokenScope[];\n expiresAt: string | null;\n}\n\n/**\n * Personal Access Tokens — for the CLI in CI and for the MCP server running\n * headless. Managed only while signed in with a session (`roxyon login`); a PAT\n * cannot mint or revoke another PAT.\n *\n * `GET/POST/DELETE /account/tokens` — console endpoints.\n */\nexport class TokensApi {\n constructor(private readonly client: RoxyonClient) {}\n\n async list(): Promise<TokenSummary[]> {\n const r = await this.client.console<{ ok?: boolean; tokens?: TokenSummary[]; error?: string }>(\n 'GET',\n '/account/tokens',\n { tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not list tokens.', { body: r });\n return r.tokens ?? [];\n }\n\n async create(\n name: string,\n opts: {\n scopes?: TokenScope[];\n expiresInDays?: number;\n /** Required with `billing:order`. */\n monthlyBudgetUSD?: number;\n allowedSkus?: string[];\n } = {},\n ): Promise<CreatedToken> {\n const r = await this.client.console<CreatedToken & { ok?: boolean; error?: string }>(\n 'POST',\n '/account/tokens',\n {\n body: {\n name,\n scopes: opts.scopes ?? ['deploy', 'logs'],\n ...(opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {}),\n ...(opts.monthlyBudgetUSD ? { monthlyBudgetUSD: opts.monthlyBudgetUSD } : {}),\n ...(opts.allowedSkus?.length ? { allowedSkus: opts.allowedSkus } : {}),\n },\n tolerateHttpError: true,\n },\n );\n if (!r?.ok || !r.token) {\n throw new RoxyonApiError(r?.error || 'Could not create the token.', { body: r });\n }\n return { token: r.token, name: r.name, scopes: r.scopes, expiresAt: r.expiresAt ?? null };\n }\n\n async revoke(id: string): Promise<void> {\n const r = await this.client.console<{ ok?: boolean; error?: string }>(\n 'DELETE',\n '/account/tokens',\n { query: { id }, tolerateHttpError: true },\n );\n if (!r?.ok) throw new RoxyonApiError(r?.error || 'Could not revoke the token.', { body: r });\n }\n}\n","import { RoxyonApiError } from './errors.js';\n\n/** BaaS V2 base. V1 (`/1`) is frozen; app data tools speak V2 only. */\nexport const DEFAULT_BAAS_V2_URL = 'https://www.beaapis.com/2';\n\n/** V2 caps one page at 200 rows. */\nexport const BAAS_MAX_PAGE = 200;\n/** V2 takes 1 to 50 requests per batch. */\nexport const BAAS_MAX_BATCH = 50;\n\nexport interface BaasDataOptions {\n /** The app's secret key (`rxsk_…`): server scope, from the project's API keys in Roxyon Base. */\n secretKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\nexport type BaasRow = Record<string, unknown>;\n\nexport interface BaasQuery {\n /** e.g. `{ Status: 'active', Age: { gt: 18 } }`; `in` takes a comma-joined string. */\n where?: Record<string, unknown>;\n /** `*` and/or column names, comma separated. Defaults to `*`. */\n fields?: string;\n /** Comma list, `-` for descending, e.g. `-createdAt`. */\n order?: string;\n /** 1 to 200 (default 50). */\n limit?: number;\n skip?: number;\n /** Also return the total number of matching rows. */\n count?: boolean;\n}\n\nexport interface BaasBatchRequest {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n /** `/Class` or `/Class/<id>`. */\n path: string;\n body?: Record<string, unknown>;\n}\n\n/** One batch answer: `ok:false` with `error`/`message`, or that request's own V2 answer. */\nexport interface BaasBatchResult {\n status: number;\n ok?: boolean;\n error?: string;\n message?: string;\n result?: BaasRow;\n results?: BaasRow[];\n count?: number;\n id?: string;\n}\n\ninterface V2Body {\n ok?: boolean;\n error?: string;\n message?: string;\n details?: unknown;\n result?: BaasRow;\n results?: unknown[];\n count?: number;\n id?: string;\n}\n\n// Mirrors App.php: classes `^[A-Za-z][A-Za-z0-9_]{0,63}$` (no `_` system classes), ids `^[A-Za-z0-9]{1,40}$`.\nconst CLASS_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID_RE = /^[A-Za-z0-9]{1,40}$/;\n\nfunction checkClass(name: string): string {\n if (!CLASS_RE.test(name)) throw new Error(`Invalid class name \"${name}\".`);\n return name;\n}\n\nfunction checkId(id: string): string {\n if (!ID_RE.test(id)) throw new Error(`Invalid objectId \"${id}\".`);\n return id;\n}\n\n/**\n * Records of ONE app on BaaS V2, as that app's own backend (server scope, `X-RX-Secret-Key`).\n * Server scope passes every class rule, so treat the key like a database password. V2 answers\n * failures as `{ok:false, error, message}` with an HTTP status; every call throws on those.\n * Schema changes are not reachable with a secret key (console API only).\n */\nexport class BaasDataApi {\n private readonly baseUrl: string;\n private readonly secretKey: string;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: BaasDataOptions) {\n if (!opts.secretKey.startsWith('rxsk_')) {\n throw new Error('BaaS V2 needs the app secret key (starts with rxsk_).');\n }\n this.secretKey = opts.secretKey;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BAAS_V2_URL).replace(/\\/+$/, '');\n this._fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n private async call(\n method: string,\n path: string,\n opts: { query?: Record<string, string>; body?: unknown } = {},\n ): Promise<V2Body> {\n const qs =\n opts.query && Object.keys(opts.query).length ? `?${new URLSearchParams(opts.query)}` : '';\n const headers: Record<string, string> = { 'x-rx-secret-key': this.secretKey };\n if (opts.body !== undefined) headers['content-type'] = 'application/json';\n let res: Response;\n try {\n res = await this._fetch(`${this.baseUrl}${path}${qs}`, {\n method,\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n });\n } catch (e) {\n throw new RoxyonApiError(`Could not reach ${this.baseUrl}: ${(e as Error).message}`);\n }\n let body: V2Body = {};\n try {\n body = ((await res.json()) as V2Body) ?? {};\n } catch {\n // Non-JSON (proxy error page): handled below.\n }\n if (!res.ok || body.ok !== true) {\n const msg = body.message || body.error || `HTTP ${res.status}`;\n throw new RoxyonApiError(msg, { status: res.status, type: body.error, body });\n }\n return body;\n }\n\n private static recordPath(className: string, id?: string): string {\n return `/records/${checkClass(className)}${id === undefined ? '' : `/${checkId(id)}`}`;\n }\n\n async query(className: string, q: BaasQuery = {}): Promise<{ rows: BaasRow[]; count?: number }> {\n const limit = q.limit ?? 50;\n if (!Number.isInteger(limit) || limit < 1 || limit > BAAS_MAX_PAGE) {\n throw new Error(`limit must be 1 to ${BAAS_MAX_PAGE}.`);\n }\n const query: Record<string, string> = { fields: q.fields || '*', limit: String(limit) };\n // V2 takes where as JSON text, so operators and `in` strings survive unchanged.\n if (q.where && Object.keys(q.where).length) query.where = JSON.stringify(q.where);\n if (q.order) query.order = q.order;\n if (q.skip) query.skip = String(q.skip);\n if (q.count) query.count = '1';\n const r = await this.call('GET', BaasDataApi.recordPath(className), { query });\n return {\n rows: (r.results ?? []) as BaasRow[],\n ...(r.count !== undefined ? { count: r.count } : {}),\n };\n }\n\n async get(className: string, objectId: string): Promise<BaasRow> {\n const r = await this.call('GET', BaasDataApi.recordPath(className, objectId));\n return r.result ?? {};\n }\n\n /** Returns the created row as stored. */\n async create(className: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('POST', BaasDataApi.recordPath(className), { body: { data } });\n return r.result ?? {};\n }\n\n async update(className: string, objectId: string, data: BaasRow): Promise<BaasRow> {\n const r = await this.call('PUT', BaasDataApi.recordPath(className, objectId), {\n body: { data },\n });\n return r.result ?? {};\n }\n\n /** The id goes in the URL path, never the body. */\n async delete(className: string, objectId: string): Promise<void> {\n await this.call('DELETE', BaasDataApi.recordPath(className, objectId));\n }\n\n /** 1 to 50 record requests in one call; one failing doesn't stop the others. */\n async batch(requests: BaasBatchRequest[]): Promise<BaasBatchResult[]> {\n if (requests.length < 1 || requests.length > BAAS_MAX_BATCH) {\n throw new Error(`A batch takes 1 to ${BAAS_MAX_BATCH} requests.`);\n }\n for (const req of requests) {\n const [cls, id, extra] = req.path.split('/').filter(Boolean);\n if (!cls || extra !== undefined)\n throw new Error(`Batch path \"${req.path}\" must be /Class or /Class/id.`);\n checkClass(cls);\n if (id !== undefined) checkId(id);\n }\n const r = await this.call('POST', '/batch', { body: { requests } });\n return (r.results ?? []) as BaasBatchResult[];\n }\n}\n","/**\n * `.env`-style block <-> JSON object, ported verbatim from `appfEnvParse` /\n * `appfEnvToLines` in `console.roxyon.com/.../modals/app_form.view` so the CLI\n * and the console form agree byte-for-byte on what `Applications.Env` holds.\n *\n * The server re-sanitises again (`ApplicationRenderer::envPair`), so this only\n * needs to be reasonable. `PORT` and `HOST` are set by the platform — callers\n * should not write them.\n */\nexport function parseEnv(text: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (let line of String(text || '').split(/\\r?\\n/)) {\n line = line.trim();\n if (!line || line.startsWith('#')) continue;\n line = line.replace(/^export\\s+/, '');\n const eq = line.indexOf('=');\n if (eq < 1) continue;\n const k = line.slice(0, eq).trim();\n let v = line.slice(eq + 1).trim();\n if (v.length >= 2 && (v[0] === '\"' || v[0] === \"'\") && v[v.length - 1] === v[0]) {\n v = v.slice(1, -1);\n }\n if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) out[k] = v;\n }\n return out;\n}\n\nexport function formatEnv(obj: Record<string, string> | null | undefined): string {\n if (!obj || typeof obj !== 'object') return '';\n return Object.keys(obj)\n .map((k) => `${k}=${obj[k] == null ? '' : String(obj[k])}`)\n .join('\\n');\n}\n\n/** Parse the JSON string stored on `Applications.Env`. */\nexport function envFromStored(jsonStr: string | undefined): Record<string, string> {\n if (!jsonStr) return {};\n try {\n const obj = JSON.parse(jsonStr);\n return obj && typeof obj === 'object' ? (obj as Record<string, string>) : {};\n } catch {\n return {};\n }\n}\n","/**\n * Runtime / version / framework catalog — a verbatim copy of the `RUNTIMES`\n * table in `console.roxyon.com/.../modals/app_form.view`. These are the versions\n * actually installed in the Cloud Hosting containers; offering an uninstalled\n * one produces a deploy that fails at build time for a reason the user cannot\n * act on.\n *\n * TODO(M4): the console form and this file should both import one shared JSON\n * published at `roxyon.com/runtimes.json` so they never drift.\n */\nexport type RuntimeName = 'lumen' | 'node' | 'python' | 'php';\n\nexport interface RuntimeSpec {\n versions: string[];\n defaultVersion: string;\n presets: Array<[value: string, label: string]>;\n command: string;\n}\n\nexport const RUNTIMES: Record<Exclude<RuntimeName, 'lumen'>, RuntimeSpec> = {\n node: {\n versions: ['23.11.1', '22.23.1', '20.20.2', '18.20.8'],\n defaultVersion: '20.20.2',\n presets: [\n ['nextjs', 'Next.js'],\n ['nuxt', 'Nuxt'],\n ['node', 'No framework'],\n ],\n command: 'npm run start',\n },\n python: {\n versions: ['3.11'],\n defaultVersion: '3.11',\n presets: [['python', 'No framework']],\n command: 'gunicorn app:app',\n },\n php: {\n versions: ['8.4', '8.3', '8.2', '8.1', '7.4'],\n defaultVersion: '8.4',\n presets: [\n ['swoole', 'Swoole'],\n ['php', 'No framework'],\n ],\n command: 'php8.4 server.php',\n },\n};\n\n/**\n * A LumenJS project (`runtime: \"lumen\"`) builds to static files with\n * `lm build --serverless` and is served straight from the host's document root\n * by nginx — no long-running process, no systemd unit, no Application row. It\n * deploys through the \"static\" path (upload the built `dist/` to\n * `/home/www/<host>/public_html[/<folder>]`).\n *\n * Node / Python / PHP projects deploy through the \"app\" path (the Applications\n * system: upload source, bump ConfigRevision, reconciler builds + runs it).\n */\nexport type DeployKind = 'static' | 'app';\n\nexport const LUMEN_BUILD = {\n command: 'lm build --serverless',\n /** Directory `lm build --serverless` writes to, relative to the project root. */\n outDir: 'dist',\n} as const;\n","import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.js';\nimport { BillingApi } from './billing.js';\nimport { RoxyonClient, type RoxyonClientOptions } from './client.js';\nimport { DatabasesApi } from './databases.js';\nimport { DomainsApi } from './domains.js';\nimport { EmailApi } from './email.js';\nimport { SitesApi } from './sites.js';\nimport { SshApi } from './ssh.js';\nimport { SubscriptionsApi } from './subscriptions.js';\nimport { TokensApi } from './tokens.js';\n\nexport { RoxyonClient } from './client.js';\nexport type { RoxyonClientOptions, RequestOptions } from './client.js';\nexport { AuthApi } from './auth.js';\nexport type { RoxyonUser, LoginResult, LoginPrecheck, SessionGrant } from './auth.js';\nexport { ApplicationsApi } from './applications.js';\nexport type {\n Application,\n ApplicationProcess,\n ApplicationRoute,\n CreateApplicationInput,\n CreateOnDeploy,\n DeployResult,\n} from './applications.js';\nexport { SitesApi } from './sites.js';\nexport type {\n DeployOptions,\n SiteFile,\n SiteFileContent,\n StaticDeployResult,\n} from './sites.js';\nexport { DomainsApi } from './domains.js';\nexport type { CreateDomainInput, CreateDomainResult, Domain } from './domains.js';\nexport { DatabasesApi } from './databases.js';\nexport type {\n CreateDatabaseInput,\n CreateDatabaseResult,\n DatabaseSummary,\n DeleteDatabaseResult,\n} from './databases.js';\nexport { EmailApi } from './email.js';\nexport type {\n CreateEmailInput,\n CreateEmailResult,\n EmailSummary,\n DeleteEmailResult,\n} from './email.js';\nexport { SshApi } from './ssh.js';\nexport type { ResetSshPasswordInput, ResetSshPasswordResult } from './ssh.js';\nexport { SubscriptionsApi } from './subscriptions.js';\nexport type { Subscription, Privilege } from './subscriptions.js';\nexport { BillingApi, BILLING_CYCLES, PAYABLE_STATUSES, isPayable } from './billing.js';\nexport type {\n BillingCycle,\n BillingSubscription,\n CatalogProduct,\n Invoice,\n OrderBudget,\n OrderInput,\n OrderResult,\n Quote,\n QuoteInput,\n} from './billing.js';\nexport { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.js';\nexport {\n BaasDataApi,\n BAAS_MAX_BATCH,\n BAAS_MAX_PAGE,\n DEFAULT_BAAS_V2_URL,\n} from './baas-data.js';\nexport type {\n BaasBatchRequest,\n BaasBatchResult,\n BaasDataOptions,\n BaasQuery,\n BaasRow,\n} from './baas-data.js';\nexport { TokensApi } from './tokens.js';\nexport type { TokenScope, TokenSummary, CreatedToken } from './tokens.js';\nexport { RoxyonApiError, rxError, isAuthError, assertOk } from './errors.js';\nexport { parseEnv, formatEnv, envFromStored } from './env.js';\nexport { RUNTIMES, LUMEN_BUILD } from './runtimes.js';\nexport type { RuntimeName, RuntimeSpec, DeployKind } from './runtimes.js';\nexport { toQueryString } from './query.js';\nexport { DEFAULT_BAAS_URL, DEFAULT_CONSOLE_URL, DEFAULT_APP } from './constants.js';\n\n/**\n * Convenience facade bundling every sub-API over one {@link RoxyonClient}.\n *\n * ```ts\n * const roxyon = new Roxyon({ sessionToken }); // or a roxp_ PAT\n * const ctx = await roxyon.account.context(); // user + subs + domains\n * ```\n */\nexport class Roxyon {\n readonly client: RoxyonClient;\n readonly auth: AuthApi;\n readonly account: AccountApi;\n readonly tokens: TokensApi;\n readonly subscriptions: SubscriptionsApi;\n readonly domains: DomainsApi;\n readonly applications: ApplicationsApi;\n readonly sites: SitesApi;\n readonly databases: DatabasesApi;\n readonly email: EmailApi;\n readonly ssh: SshApi;\n readonly billing: BillingApi;\n\n constructor(options: RoxyonClientOptions | RoxyonClient = {}) {\n this.client = options instanceof RoxyonClient ? options : new RoxyonClient(options);\n this.auth = new AuthApi(this.client);\n this.account = new AccountApi(this.client);\n this.tokens = new TokensApi(this.client);\n this.subscriptions = new SubscriptionsApi(this.client);\n this.domains = new DomainsApi(this.client);\n this.applications = new ApplicationsApi(this.client);\n this.sites = new SitesApi(this.client);\n this.databases = new DatabasesApi(this.client);\n this.email = new EmailApi(this.client);\n this.ssh = new SshApi(this.client);\n this.billing = new BillingApi(this.client);\n }\n\n get sessionToken(): string | undefined {\n return this.client.getSessionToken();\n }\n}\n"],"mappings":"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","names":["json"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roxyon/api-client",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Typed client for the Roxyon BaaS (RX engine) and the Roxyon Applications deploy API.",
5
5
  "license": "MIT",
6
6
  "type": "module",