@roxyon/api-client 0.2.0 → 0.3.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.
package/dist/index.cjs CHANGED
@@ -26,13 +26,16 @@ __export(index_exports, {
26
26
  DEFAULT_APP: () => DEFAULT_APP,
27
27
  DEFAULT_BAAS_URL: () => DEFAULT_BAAS_URL,
28
28
  DEFAULT_CONSOLE_URL: () => DEFAULT_CONSOLE_URL,
29
+ DatabasesApi: () => DatabasesApi,
29
30
  DomainsApi: () => DomainsApi,
31
+ EmailApi: () => EmailApi,
30
32
  LUMEN_BUILD: () => LUMEN_BUILD,
31
33
  RUNTIMES: () => RUNTIMES,
32
34
  Roxyon: () => Roxyon,
33
35
  RoxyonApiError: () => RoxyonApiError,
34
36
  RoxyonClient: () => RoxyonClient,
35
37
  SitesApi: () => SitesApi,
38
+ SshApi: () => SshApi,
36
39
  SubscriptionsApi: () => SubscriptionsApi,
37
40
  TokensApi: () => TokensApi,
38
41
  assertOk: () => assertOk,
@@ -622,6 +625,41 @@ var RoxyonClient = class {
622
625
  }
623
626
  };
624
627
 
628
+ // src/databases.ts
629
+ var DatabasesApi = class {
630
+ constructor(client) {
631
+ this.client = client;
632
+ }
633
+ client;
634
+ async list(subscriptionId) {
635
+ const r = await this.client.get("/Databases", {
636
+ fields: "objectId,Name,Username,Status",
637
+ limit: -1,
638
+ order: "-createdAt",
639
+ where: { Subscription: subscriptionId, eye: { in: "1,0" } }
640
+ });
641
+ return r.results ?? [];
642
+ }
643
+ /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */
644
+ async create(input) {
645
+ const r = await this.client.console("POST", "/databases/create", {
646
+ body: input,
647
+ tolerateHttpError: true
648
+ });
649
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not create the database.", { body: r });
650
+ return r;
651
+ }
652
+ /** `POST /databases/delete` */
653
+ async delete(databaseId) {
654
+ const r = await this.client.console("POST", "/databases/delete", {
655
+ body: { database: databaseId },
656
+ tolerateHttpError: true
657
+ });
658
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not delete the database.", { body: r });
659
+ return r;
660
+ }
661
+ };
662
+
625
663
  // src/domains.ts
626
664
  var DomainsApi = class {
627
665
  constructor(client) {
@@ -652,6 +690,41 @@ var DomainsApi = class {
652
690
  }
653
691
  };
654
692
 
693
+ // src/email.ts
694
+ var EmailApi = class {
695
+ constructor(client) {
696
+ this.client = client;
697
+ }
698
+ client;
699
+ async list(subscriptionId) {
700
+ const r = await this.client.get("/Emails", {
701
+ fields: "objectId,Email,LocalPart,Status,Quota",
702
+ limit: -1,
703
+ order: "-createdAt",
704
+ where: { Subscription: subscriptionId, eye: { in: "1,0" } }
705
+ });
706
+ return r.results ?? [];
707
+ }
708
+ /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */
709
+ async create(input) {
710
+ const r = await this.client.console("POST", "/emails/create", {
711
+ body: input,
712
+ tolerateHttpError: true
713
+ });
714
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not create the mailbox.", { body: r });
715
+ return r;
716
+ }
717
+ /** `POST /emails/delete` */
718
+ async delete(emailId) {
719
+ const r = await this.client.console("POST", "/emails/delete", {
720
+ body: { email: emailId },
721
+ tolerateHttpError: true
722
+ });
723
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not delete the mailbox.", { body: r });
724
+ return r;
725
+ }
726
+ };
727
+
655
728
  // src/sites.ts
656
729
  var SitesApi = class {
657
730
  constructor(client) {
@@ -696,6 +769,30 @@ var SitesApi = class {
696
769
  }
697
770
  };
698
771
 
772
+ // src/ssh.ts
773
+ var SshApi = class {
774
+ constructor(client) {
775
+ this.client = client;
776
+ }
777
+ client;
778
+ /** `POST /ssh/password` */
779
+ async resetPassword(input = {}) {
780
+ const r = await this.client.console("POST", "/ssh/password", {
781
+ body: input,
782
+ tolerateHttpError: true
783
+ });
784
+ if (!r?.ok) {
785
+ throw new RoxyonApiError(
786
+ r?.error || "Could not reset the password.",
787
+ {
788
+ body: r
789
+ }
790
+ );
791
+ }
792
+ return r;
793
+ }
794
+ };
795
+
699
796
  // src/subscriptions.ts
700
797
  var SubscriptionsApi = class {
701
798
  constructor(client) {
@@ -871,6 +968,9 @@ var Roxyon = class {
871
968
  domains;
872
969
  applications;
873
970
  sites;
971
+ databases;
972
+ email;
973
+ ssh;
874
974
  constructor(options = {}) {
875
975
  this.client = options instanceof RoxyonClient ? options : new RoxyonClient(options);
876
976
  this.auth = new AuthApi(this.client);
@@ -880,6 +980,9 @@ var Roxyon = class {
880
980
  this.domains = new DomainsApi(this.client);
881
981
  this.applications = new ApplicationsApi(this.client);
882
982
  this.sites = new SitesApi(this.client);
983
+ this.databases = new DatabasesApi(this.client);
984
+ this.email = new EmailApi(this.client);
985
+ this.ssh = new SshApi(this.client);
883
986
  }
884
987
  get sessionToken() {
885
988
  return this.client.getSessionToken();
@@ -893,13 +996,16 @@ var Roxyon = class {
893
996
  DEFAULT_APP,
894
997
  DEFAULT_BAAS_URL,
895
998
  DEFAULT_CONSOLE_URL,
999
+ DatabasesApi,
896
1000
  DomainsApi,
1001
+ EmailApi,
897
1002
  LUMEN_BUILD,
898
1003
  RUNTIMES,
899
1004
  Roxyon,
900
1005
  RoxyonApiError,
901
1006
  RoxyonClient,
902
1007
  SitesApi,
1008
+ SshApi,
903
1009
  SubscriptionsApi,
904
1010
  TokensApi,
905
1011
  assertOk,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.ts","../src/constants.ts","../src/query.ts","../src/client.ts","../src/domains.ts","../src/sites.ts","../src/subscriptions.ts","../src/tokens.ts","../src/env.ts","../src/runtimes.ts"],"sourcesContent":["import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.js';\nimport { RoxyonClient, type RoxyonClientOptions } from './client.js';\nimport { DomainsApi } from './domains.js';\nimport { SitesApi } from './sites.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 { SubscriptionsApi } from './subscriptions.js';\nexport type { Subscription, Privilege } from './subscriptions.js';\nexport { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.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\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 }\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","/**\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 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 json = { error: text || `HTTP ${res.status}`, _raw: text };\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 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}\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 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 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\nexport type TokenScope = 'deploy' | 'logs' | 'read';\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}\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: { scopes?: TokenScope[]; expiresInDays?: number } = {},\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 },\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","/**\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":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/account.ts","../src/applications.ts","../src/auth.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/env.ts","../src/runtimes.ts"],"sourcesContent":["import { AccountApi } from './account.js';\nimport { ApplicationsApi } from './applications.js';\nimport { AuthApi } from './auth.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 { AccountApi } from './account.js';\nexport type {\n AccountApp,\n AccountContext,\n AccountSubscription,\n AccountDomain,\n} from './account.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\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 }\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","/**\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 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 json = { error: text || `HTTP ${res.status}`, _raw: text };\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 async list(subscriptionId: string): Promise<DatabaseSummary[]> {\n const r = await this.client.get<{ results?: DatabaseSummary[] }>('/Databases', {\n fields: 'objectId,Name,Username,Status',\n limit: -1,\n order: '-createdAt',\n where: { Subscription: subscriptionId, eye: { in: '1,0' } },\n });\n return r.results ?? [];\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 async list(subscriptionId: string): Promise<EmailSummary[]> {\n const r = await this.client.get<{ results?: EmailSummary[] }>('/Emails', {\n fields: 'objectId,Email,LocalPart,Status,Quota',\n limit: -1,\n order: '-createdAt',\n where: { Subscription: subscriptionId, eye: { in: '1,0' } },\n });\n return r.results ?? [];\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\nexport type TokenScope = 'deploy' | 'logs' | 'read';\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}\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: { scopes?: TokenScope[]; expiresInDays?: number } = {},\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 },\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","/**\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":[]}