@roxyon/api-client 0.4.0 → 0.6.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.d.cts CHANGED
@@ -81,7 +81,8 @@ declare class RoxyonClient {
81
81
  del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
82
82
  }
83
83
 
84
- type TokenScope = 'deploy' | 'logs' | 'read';
84
+ /** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */
85
+ type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';
85
86
  interface TokenSummary {
86
87
  id: string;
87
88
  name: string;
@@ -90,6 +91,10 @@ interface TokenSummary {
90
91
  lastUsedAt: string | null;
91
92
  expiresAt: string | null;
92
93
  createdAt: string;
94
+ /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */
95
+ monthlyBudgetUSD?: number | null;
96
+ /** For `billing:order` tokens: plan codes it may order (empty = any). */
97
+ allowedSkus?: string[];
93
98
  }
94
99
  interface CreatedToken {
95
100
  /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */
@@ -112,6 +117,9 @@ declare class TokensApi {
112
117
  create(name: string, opts?: {
113
118
  scopes?: TokenScope[];
114
119
  expiresInDays?: number;
120
+ /** Required with `billing:order`. */
121
+ monthlyBudgetUSD?: number;
122
+ allowedSkus?: string[];
115
123
  }): Promise<CreatedToken>;
116
124
  revoke(id: string): Promise<void>;
117
125
  }
@@ -419,6 +427,48 @@ interface Quote {
419
427
  fxRate: string;
420
428
  baseAmountUSD: string;
421
429
  }
430
+ interface OrderInput {
431
+ /** Plan code from the catalog, e.g. `SCALE-S`. */
432
+ sku: string;
433
+ cycle: BillingCycle;
434
+ /** A name for the service. */
435
+ name: string;
436
+ /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */
437
+ username: string;
438
+ /** Servers only: OS image, e.g. `ubuntu-24.04`. */
439
+ image?: string;
440
+ sshKey?: string;
441
+ phpVersion?: string;
442
+ datacenter?: string;
443
+ currency?: string;
444
+ country?: string;
445
+ /** false/absent = dry run (quote + budget check, nothing written). */
446
+ confirm?: boolean;
447
+ }
448
+ interface OrderBudget {
449
+ monthlyUSD: number;
450
+ spentUSD: number;
451
+ remainingUSD: number;
452
+ }
453
+ interface OrderResult {
454
+ dryRun?: boolean;
455
+ plan: {
456
+ id: string;
457
+ sku: string;
458
+ name: string;
459
+ kind: 'hosting' | 'server';
460
+ cycle: string;
461
+ };
462
+ /** Dry run: the server quote (same shape as GET /_payment/quote). */
463
+ quote?: Record<string, unknown>;
464
+ subscriptionId?: string;
465
+ invoiceId?: string;
466
+ total?: string;
467
+ currency?: string;
468
+ payUrl?: string;
469
+ /** null for a console session (no token budget). */
470
+ budget: OrderBudget | null;
471
+ }
422
472
  interface BillingSubscription {
423
473
  id: string;
424
474
  name: string;
@@ -459,6 +509,12 @@ declare class BillingApi {
459
509
  catalog(): Promise<CatalogProduct[]>;
460
510
  /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */
461
511
  quote(input: QuoteInput): Promise<Quote>;
512
+ /**
513
+ * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it
514
+ * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the
515
+ * `billing:order` scope, within that token's monthly budget and allowed SKUs.
516
+ */
517
+ order(input: OrderInput): Promise<OrderResult>;
462
518
  /** The caller's own subscriptions (rows they own), newest first. */
463
519
  subscriptions(): Promise<BillingSubscription[]>;
464
520
  /** The caller's own invoices, newest first. */
@@ -504,6 +560,7 @@ interface DeleteDatabaseResult {
504
560
  declare class DatabasesApi {
505
561
  private readonly client;
506
562
  constructor(client: RoxyonClient);
563
+ /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */
507
564
  list(subscriptionId: string): Promise<DatabaseSummary[]>;
508
565
  /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */
509
566
  create(input: CreateDatabaseInput): Promise<CreateDatabaseResult>;
@@ -587,6 +644,7 @@ interface DeleteEmailResult {
587
644
  declare class EmailApi {
588
645
  private readonly client;
589
646
  constructor(client: RoxyonClient);
647
+ /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */
590
648
  list(subscriptionId: string): Promise<EmailSummary[]>;
591
649
  /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */
592
650
  create(input: CreateEmailInput): Promise<CreateEmailResult>;
@@ -874,4 +932,4 @@ declare class Roxyon {
874
932
  get sessionToken(): string | undefined;
875
933
  }
876
934
 
877
- export { AccountApi, type AccountApp, type AccountContext, type AccountDomain, type AccountSubscription, type Application, type ApplicationProcess, type ApplicationRoute, ApplicationsApi, AuthApi, BAAS_MAX_BATCH, BAAS_MAX_PAGE, BILLING_CYCLES, type BaasBatchRequest, type BaasBatchResult, BaasDataApi, type BaasDataOptions, type BaasQuery, type BaasRow, BillingApi, type BillingCycle, type BillingSubscription, type CatalogProduct, type CreateApplicationInput, type CreateDatabaseInput, type CreateDatabaseResult, type CreateDomainInput, type CreateDomainResult, type CreateEmailInput, type CreateEmailResult, type CreateOnDeploy, type CreatedToken, DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_BAAS_V2_URL, DEFAULT_CONSOLE_URL, type DatabaseSummary, DatabasesApi, type DeleteDatabaseResult, type DeleteEmailResult, type DeployKind, type DeployOptions, type DeployResult, type Domain, DomainsApi, EmailApi, type EmailSummary, type Invoice, LUMEN_BUILD, type LoginPrecheck, type LoginResult, PAYABLE_STATUSES, type Privilege, type Quote, type QuoteInput, RUNTIMES, type RequestOptions, type ResetSshPasswordInput, type ResetSshPasswordResult, Roxyon, RoxyonApiError, RoxyonClient, type RoxyonClientOptions, type RoxyonUser, type RuntimeName, type RuntimeSpec, type SessionGrant, type SiteFile, type SiteFileContent, SitesApi, SshApi, type StaticDeployResult, type Subscription, SubscriptionsApi, type TokenScope, type TokenSummary, TokensApi, assertOk, envFromStored, formatEnv, isAuthError, isPayable, parseEnv, rxError, toQueryString };
935
+ export { AccountApi, type AccountApp, type AccountContext, type AccountDomain, type AccountSubscription, type Application, type ApplicationProcess, type ApplicationRoute, ApplicationsApi, AuthApi, BAAS_MAX_BATCH, BAAS_MAX_PAGE, BILLING_CYCLES, type BaasBatchRequest, type BaasBatchResult, BaasDataApi, type BaasDataOptions, type BaasQuery, type BaasRow, BillingApi, type BillingCycle, type BillingSubscription, type CatalogProduct, type CreateApplicationInput, type CreateDatabaseInput, type CreateDatabaseResult, type CreateDomainInput, type CreateDomainResult, type CreateEmailInput, type CreateEmailResult, type CreateOnDeploy, type CreatedToken, DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_BAAS_V2_URL, DEFAULT_CONSOLE_URL, type DatabaseSummary, DatabasesApi, type DeleteDatabaseResult, type DeleteEmailResult, type DeployKind, type DeployOptions, type DeployResult, type Domain, DomainsApi, EmailApi, type EmailSummary, type Invoice, LUMEN_BUILD, type LoginPrecheck, type LoginResult, type OrderBudget, type OrderInput, type OrderResult, PAYABLE_STATUSES, type Privilege, type Quote, type QuoteInput, RUNTIMES, type RequestOptions, type ResetSshPasswordInput, type ResetSshPasswordResult, Roxyon, RoxyonApiError, RoxyonClient, type RoxyonClientOptions, type RoxyonUser, type RuntimeName, type RuntimeSpec, type SessionGrant, type SiteFile, type SiteFileContent, SitesApi, SshApi, type StaticDeployResult, type Subscription, SubscriptionsApi, type TokenScope, type TokenSummary, TokensApi, assertOk, envFromStored, formatEnv, isAuthError, isPayable, parseEnv, rxError, toQueryString };
package/dist/index.d.ts CHANGED
@@ -81,7 +81,8 @@ declare class RoxyonClient {
81
81
  del<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
82
82
  }
83
83
 
84
- type TokenScope = 'deploy' | 'logs' | 'read';
84
+ /** `billing:order` lets the token place orders (human pays) within its monthly budget; never a default. */
85
+ type TokenScope = 'deploy' | 'logs' | 'read' | 'billing:order';
85
86
  interface TokenSummary {
86
87
  id: string;
87
88
  name: string;
@@ -90,6 +91,10 @@ interface TokenSummary {
90
91
  lastUsedAt: string | null;
91
92
  expiresAt: string | null;
92
93
  createdAt: string;
94
+ /** For `billing:order` tokens: the most it may order per calendar month, in USD before tax. */
95
+ monthlyBudgetUSD?: number | null;
96
+ /** For `billing:order` tokens: plan codes it may order (empty = any). */
97
+ allowedSkus?: string[];
93
98
  }
94
99
  interface CreatedToken {
95
100
  /** The full `roxp_…` secret — shown once. Use it as `ROXYON_TOKEN`. */
@@ -112,6 +117,9 @@ declare class TokensApi {
112
117
  create(name: string, opts?: {
113
118
  scopes?: TokenScope[];
114
119
  expiresInDays?: number;
120
+ /** Required with `billing:order`. */
121
+ monthlyBudgetUSD?: number;
122
+ allowedSkus?: string[];
115
123
  }): Promise<CreatedToken>;
116
124
  revoke(id: string): Promise<void>;
117
125
  }
@@ -419,6 +427,48 @@ interface Quote {
419
427
  fxRate: string;
420
428
  baseAmountUSD: string;
421
429
  }
430
+ interface OrderInput {
431
+ /** Plan code from the catalog, e.g. `SCALE-S`. */
432
+ sku: string;
433
+ cycle: BillingCycle;
434
+ /** A name for the service. */
435
+ name: string;
436
+ /** Account / server name: 2-63 lowercase letters, digits, dots, dashes; must be free. */
437
+ username: string;
438
+ /** Servers only: OS image, e.g. `ubuntu-24.04`. */
439
+ image?: string;
440
+ sshKey?: string;
441
+ phpVersion?: string;
442
+ datacenter?: string;
443
+ currency?: string;
444
+ country?: string;
445
+ /** false/absent = dry run (quote + budget check, nothing written). */
446
+ confirm?: boolean;
447
+ }
448
+ interface OrderBudget {
449
+ monthlyUSD: number;
450
+ spentUSD: number;
451
+ remainingUSD: number;
452
+ }
453
+ interface OrderResult {
454
+ dryRun?: boolean;
455
+ plan: {
456
+ id: string;
457
+ sku: string;
458
+ name: string;
459
+ kind: 'hosting' | 'server';
460
+ cycle: string;
461
+ };
462
+ /** Dry run: the server quote (same shape as GET /_payment/quote). */
463
+ quote?: Record<string, unknown>;
464
+ subscriptionId?: string;
465
+ invoiceId?: string;
466
+ total?: string;
467
+ currency?: string;
468
+ payUrl?: string;
469
+ /** null for a console session (no token budget). */
470
+ budget: OrderBudget | null;
471
+ }
422
472
  interface BillingSubscription {
423
473
  id: string;
424
474
  name: string;
@@ -459,6 +509,12 @@ declare class BillingApi {
459
509
  catalog(): Promise<CatalogProduct[]>;
460
510
  /** What checkout would charge for a new subscription: the server's own pricing (GET /_payment/quote). */
461
511
  quote(input: QuoteInput): Promise<Quote>;
512
+ /**
513
+ * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it
514
+ * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the
515
+ * `billing:order` scope, within that token's monthly budget and allowed SKUs.
516
+ */
517
+ order(input: OrderInput): Promise<OrderResult>;
462
518
  /** The caller's own subscriptions (rows they own), newest first. */
463
519
  subscriptions(): Promise<BillingSubscription[]>;
464
520
  /** The caller's own invoices, newest first. */
@@ -504,6 +560,7 @@ interface DeleteDatabaseResult {
504
560
  declare class DatabasesApi {
505
561
  private readonly client;
506
562
  constructor(client: RoxyonClient);
563
+ /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */
507
564
  list(subscriptionId: string): Promise<DatabaseSummary[]>;
508
565
  /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */
509
566
  create(input: CreateDatabaseInput): Promise<CreateDatabaseResult>;
@@ -587,6 +644,7 @@ interface DeleteEmailResult {
587
644
  declare class EmailApi {
588
645
  private readonly client;
589
646
  constructor(client: RoxyonClient);
647
+ /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */
590
648
  list(subscriptionId: string): Promise<EmailSummary[]>;
591
649
  /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */
592
650
  create(input: CreateEmailInput): Promise<CreateEmailResult>;
@@ -874,4 +932,4 @@ declare class Roxyon {
874
932
  get sessionToken(): string | undefined;
875
933
  }
876
934
 
877
- export { AccountApi, type AccountApp, type AccountContext, type AccountDomain, type AccountSubscription, type Application, type ApplicationProcess, type ApplicationRoute, ApplicationsApi, AuthApi, BAAS_MAX_BATCH, BAAS_MAX_PAGE, BILLING_CYCLES, type BaasBatchRequest, type BaasBatchResult, BaasDataApi, type BaasDataOptions, type BaasQuery, type BaasRow, BillingApi, type BillingCycle, type BillingSubscription, type CatalogProduct, type CreateApplicationInput, type CreateDatabaseInput, type CreateDatabaseResult, type CreateDomainInput, type CreateDomainResult, type CreateEmailInput, type CreateEmailResult, type CreateOnDeploy, type CreatedToken, DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_BAAS_V2_URL, DEFAULT_CONSOLE_URL, type DatabaseSummary, DatabasesApi, type DeleteDatabaseResult, type DeleteEmailResult, type DeployKind, type DeployOptions, type DeployResult, type Domain, DomainsApi, EmailApi, type EmailSummary, type Invoice, LUMEN_BUILD, type LoginPrecheck, type LoginResult, PAYABLE_STATUSES, type Privilege, type Quote, type QuoteInput, RUNTIMES, type RequestOptions, type ResetSshPasswordInput, type ResetSshPasswordResult, Roxyon, RoxyonApiError, RoxyonClient, type RoxyonClientOptions, type RoxyonUser, type RuntimeName, type RuntimeSpec, type SessionGrant, type SiteFile, type SiteFileContent, SitesApi, SshApi, type StaticDeployResult, type Subscription, SubscriptionsApi, type TokenScope, type TokenSummary, TokensApi, assertOk, envFromStored, formatEnv, isAuthError, isPayable, parseEnv, rxError, toQueryString };
935
+ export { AccountApi, type AccountApp, type AccountContext, type AccountDomain, type AccountSubscription, type Application, type ApplicationProcess, type ApplicationRoute, ApplicationsApi, AuthApi, BAAS_MAX_BATCH, BAAS_MAX_PAGE, BILLING_CYCLES, type BaasBatchRequest, type BaasBatchResult, BaasDataApi, type BaasDataOptions, type BaasQuery, type BaasRow, BillingApi, type BillingCycle, type BillingSubscription, type CatalogProduct, type CreateApplicationInput, type CreateDatabaseInput, type CreateDatabaseResult, type CreateDomainInput, type CreateDomainResult, type CreateEmailInput, type CreateEmailResult, type CreateOnDeploy, type CreatedToken, DEFAULT_APP, DEFAULT_BAAS_URL, DEFAULT_BAAS_V2_URL, DEFAULT_CONSOLE_URL, type DatabaseSummary, DatabasesApi, type DeleteDatabaseResult, type DeleteEmailResult, type DeployKind, type DeployOptions, type DeployResult, type Domain, DomainsApi, EmailApi, type EmailSummary, type Invoice, LUMEN_BUILD, type LoginPrecheck, type LoginResult, type OrderBudget, type OrderInput, type OrderResult, PAYABLE_STATUSES, type Privilege, type Quote, type QuoteInput, RUNTIMES, type RequestOptions, type ResetSshPasswordInput, type ResetSshPasswordResult, Roxyon, RoxyonApiError, RoxyonClient, type RoxyonClientOptions, type RoxyonUser, type RuntimeName, type RuntimeSpec, type SessionGrant, type SiteFile, type SiteFileContent, SitesApi, SshApi, type StaticDeployResult, type Subscription, SubscriptionsApi, type TokenScope, type TokenSummary, TokensApi, assertOk, envFromStored, formatEnv, isAuthError, isPayable, parseEnv, rxError, toQueryString };
package/dist/index.js CHANGED
@@ -443,7 +443,7 @@ var BillingApi = class {
443
443
  {
444
444
  className: "Pricing",
445
445
  field: "Plan",
446
- fields: "Prices,SetupFee,MetaData",
446
+ fields: "Prices,SetupFee,MetaData,IsActive",
447
447
  reverse: 1
448
448
  }
449
449
  ]
@@ -454,18 +454,20 @@ var BillingApi = class {
454
454
  const out = [];
455
455
  for (const p of r.results) {
456
456
  const pricing = p._Pricing?.results?.[0];
457
- if (!pricing) continue;
457
+ if (!p.Code || !pricing || Number(pricing.IsActive) === 0) continue;
458
458
  const limits = json(p.Limits, {});
459
459
  const features = json(p.Features, {});
460
460
  const meta = json(pricing.MetaData, {});
461
461
  const network = json(features.Network, {});
462
462
  const setup = numbers(pricing.SetupFee);
463
+ const pricesUSD = numbers(pricing.Prices);
464
+ if (pricesUSD.monthly === void 0) continue;
463
465
  const product = {
464
466
  planId: p.objectId,
465
467
  sku: p.Code ?? "",
466
468
  name: p.Name ?? "",
467
469
  category: p._Service?.results?.[0]?.Type ?? "",
468
- pricesUSD: numbers(pricing.Prices),
470
+ pricesUSD,
469
471
  stock: String(meta.stock ?? "in").toLowerCase() === "out" ? "out" : "in"
470
472
  };
471
473
  if (limits.vcpu != null) {
@@ -517,6 +519,16 @@ var BillingApi = class {
517
519
  baseAmountUSD: String(r.baseAmount ?? "")
518
520
  };
519
521
  }
522
+ /**
523
+ * A new order for the caller (POST /account/order): dry run unless `confirm`. The engine prices and creates it
524
+ * (Subscription in payment + pending invoice); a person pays at `payUrl`. Needs a session or a PAT with the
525
+ * `billing:order` scope, within that token's monthly budget and allowed SKUs.
526
+ */
527
+ async order(input) {
528
+ const r = await this.client.console("POST", "/account/order", { body: input, tolerateHttpError: true });
529
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "The order was not placed.", { body: r });
530
+ return r;
531
+ }
520
532
  /** The caller's own subscriptions (rows they own), newest first. */
521
533
  async subscriptions() {
522
534
  const r = await this.client.console("GET", "/account/subscriptions", { tolerateHttpError: true });
@@ -702,7 +714,11 @@ var RoxyonClient = class _RoxyonClient {
702
714
  try {
703
715
  json2 = text ? JSON.parse(text) : {};
704
716
  } catch {
705
- json2 = { error: text || `HTTP ${res.status}`, _raw: text };
717
+ const html = /^\s*</.test(text);
718
+ json2 = {
719
+ error: html ? `${method} ${path} is not available on this server yet (got a web page instead of the API).` : text || `HTTP ${res.status}`,
720
+ _raw: html ? "" : text
721
+ };
706
722
  }
707
723
  if (!res.ok && !opts.tolerateHttpError) {
708
724
  const msg = json2 && typeof json2 === "object" && "error" in json2 && json2.error || `HTTP ${res.status} calling ${method} ${path}`;
@@ -730,14 +746,14 @@ var DatabasesApi = class {
730
746
  this.client = client;
731
747
  }
732
748
  client;
749
+ /** `POST /databases/list` — through the console, because PAT/OAuth callers can't read /Databases directly. */
733
750
  async list(subscriptionId) {
734
- const r = await this.client.get("/Databases", {
735
- fields: "objectId,Name,Username,Status",
736
- limit: -1,
737
- order: "-createdAt",
738
- where: { Subscription: subscriptionId, eye: { in: "1,0" } }
751
+ const r = await this.client.console("POST", "/databases/list", {
752
+ body: { subscription: subscriptionId },
753
+ tolerateHttpError: true
739
754
  });
740
- return r.results ?? [];
755
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not list the databases.", { body: r });
756
+ return r.databases ?? [];
741
757
  }
742
758
  /** `POST /databases/create` — provision a database + user; the reconciler does the rest. */
743
759
  async create(input) {
@@ -795,14 +811,11 @@ var EmailApi = class {
795
811
  this.client = client;
796
812
  }
797
813
  client;
814
+ /** `POST /emails/list` — through the console, because PAT/OAuth callers can't read /Emails directly. */
798
815
  async list(subscriptionId) {
799
- const r = await this.client.get("/Emails", {
800
- fields: "objectId,Email,LocalPart,Status,Quota",
801
- limit: -1,
802
- order: "-createdAt",
803
- where: { Subscription: subscriptionId, eye: { in: "1,0" } }
804
- });
805
- return r.results ?? [];
816
+ const r = await this.client.console("POST", "/emails/list", { body: { subscription: subscriptionId }, tolerateHttpError: true });
817
+ if (!r?.ok) throw new RoxyonApiError(r?.error || "Could not list the mailboxes.", { body: r });
818
+ return (r.emails ?? []).map((e) => ({ ...e, LocalPart: e.Email.split("@")[0] ?? "" }));
806
819
  }
807
820
  /** `POST /emails/create` — provision a mailbox; the reconciler does the rest. */
808
821
  async create(input) {
@@ -971,7 +984,9 @@ var TokensApi = class {
971
984
  body: {
972
985
  name,
973
986
  scopes: opts.scopes ?? ["deploy", "logs"],
974
- ...opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {}
987
+ ...opts.expiresInDays ? { expiresInDays: opts.expiresInDays } : {},
988
+ ...opts.monthlyBudgetUSD ? { monthlyBudgetUSD: opts.monthlyBudgetUSD } : {},
989
+ ...opts.allowedSkus?.length ? { allowedSkus: opts.allowedSkus } : {}
975
990
  },
976
991
  tolerateHttpError: true
977
992
  }