@cloudgate/sdk
v1.1.1
Published
Official TypeScript/JavaScript client for the CloudGate public API (v1): subscriptions, resources, billing, reports, support and organization administration.
Maintainers
Readme
@cloudgate/sdk
Official TypeScript/JavaScript client for the CloudGate public API v1. Node.js 18+, no runtime dependencies, ESM + CommonJS + type definitions.
Full API documentation: https://<your CloudGate domain>/public-api-docs.
npm install @cloudgate/sdkGet a key
Sign in to CloudGate, open Profile → API keys, create a key. Choose Read and write to order or change services. A key can do only what you can do in CloudGate.
Environments
One package works with every CloudGate environment and tenant: you choose the server with baseUrl and a key from that
same environment (a dev key works only on dev, a production key only on production). Each tenant has its own address.
# dev
export CLOUDGATE_BASE_URL=https://cloudgate-dev.obelion.ai
export CLOUDGATE_API_KEY=cg_test_...
# production — same code, different values
export CLOUDGATE_BASE_URL=https://<your CloudGate address>
export CLOUDGATE_API_KEY=cg_live_...const cg = new CloudGate(); // reads CLOUDGATE_BASE_URL and CLOUDGATE_API_KEYUse
import { CloudGate } from "@cloudgate/sdk";
const cg = new CloudGate({
baseUrl: "https://cloudgate.example.com", // or CLOUDGATE_BASE_URL
apiKey: process.env.CLOUDGATE_API_KEY, // or CLOUDGATE_API_KEY
});
const me = await cg.me(); // key, user, organization, tenant
if (!me.access.can_write) throw new Error("this key's owner is a viewer");
for await (const service of cg.services.list()) console.log(service.slug, service.name);
const offering = await cg.services.offerings("cs-linux-vm", { billing_cycle: "hourly" });
const price = await cg.services.quote("cs-linux-vm", { zone_id: 12, billing_cycle: "hourly", selections: [{ type_id: 3, item_id: 41 }] });
const vm = await cg.subscriptions.create({
service: "cs-linux-vm",
name: "ci-runner-1",
zone_id: 12,
billing_cycle: "hourly",
selections: [{ type_id: 3, item_id: 41 }],
service_key_id: 21,
sub_username: "",
sub_password: "",
eula_accepted: true,
});
await cg.subscriptions.waitFor(vm.id, "active", { timeoutMs: 20 * 60_000 });
await cg.subscriptions.stop(vm.id);
await cg.subscriptions.waitFor(vm.id, "stopped");
const actions = await cg.subscriptions.actions(vm.id); // each with an input_schema
await cg.subscriptions.runAction(vm.id, actions[0].action, { /* per input_schema */ });
await cg.subscriptions.delete(vm.id);
await cg.subscriptions.waitFor(vm.id, "deleted");Resources: me(), providers (list, regions), regions.zones, services (list, offerings, quote),
subscriptions (list, get, resources, create, start, stop, delete, actions, runAction, waitFor),
projects, departments, serviceKeys, keyPairs (list, create), invoices (list, get), usage.get,
wallet.get, activity.list, resources (summary, list(type), search, get, metrics, delete),
errorLogs.list, notifications (list, markRead, markAllRead), tickets (list, get, create, reply,
close), costs (subscriptions, resources). Every list() is an async iterator over all pages; collect() turns
one into an array.
for (const t of await cg.resources.summary()) console.log(t.type, t.count);
for await (const vm of cg.resources.list("VirtualMachine")) console.log(vm.name, vm.cloud_id);
for await (const e of cg.errorLogs.list({ severity: "high", status: "open" })) console.log(e.at, e.title);
const ticket = await cg.tickets.create({ title: "VM unreachable", details: "…", category: 2, subscription_id: vm.id });Management
The rest of what the website does, with the website's fields in and its answer out (typed Json; same permissions
as the key's owner):
| Client | Methods |
| --- | --- |
| subscriptionSettings | rename, placement, move, sync, architecture, preferences, setPreferences, notify, setNotify, bucketUsers, bucketPolicies, bucketLifecycle, bucketVersioning, harborInventory, linkedDatabases, linkableDatabases, linkedGpuVms, linkableGpuVms, replication, harborImages (all pages), harborInventory (one page + projects/users in meta) |
| monitoring | get, enable, update, disable |
| provisioning | addOns, addOnResourceGroups, addOnCompartments, addOnResources, replicate, replicationTargets, adoptUnmanagedResource, previewGpuVmConversion, convertGpuVm |
| bundles, bundleSubscriptions | list, retrieve, tiers; list, create, details, update, delete, addTiers, rename, move, sync |
| resourceOperations | syncStatus, sync, syncAllStatus, syncAll, bulkDelete, children, vpcs, vpcInventory |
| projectAdmin, departmentAdmin | create, retrieve, details, update, delete, setStatus (+ hierarchy) |
| users | list, create, retrieve, details, update, delete, setStatus, setFinancialAccess |
| serviceKeyAdmin | create (FormData with the credential file), retrieve, update, delete, setStatus, setMonitoring, regions, vendors |
| credentials (read_write keys) | kubeconfig, sshCertificate, rdpCredential, bucketUserSecretKey, backupBucket, backupBucketSecretKey, inference |
| billing | vendorInvoices (all pages), vendorInvoicesPage (one page + meta.statistics), invoicePdf, creditActivity, creditReservations, creditCapacity, validateVoucher, redeemVoucher |
| reports | list, retrieve (one page of rows + the report in meta.report), rows (all rows), delete, download, publish, preview(kind), create(kind), update(kind, id) |
| inquiries | list, create, retrieve, delete, reply, ticketProviders |
| profile | retrieve, update (FormData for the photo), notificationSettings, updateNotificationSettings |
Every list, management ones included (users.list(), reports.list(), inquiries.list(), billing.creditReservations()…), is an
async iterator that follows next_cursor for you. The …Page() methods and reports.retrieve() return one page
{ data, next_cursor, total_count?, meta? } when you need what a list carries besides its rows.
billing.creditActivity() returns the newest limit (1–100) entries only; narrow it by date.
Files (invoicePdf, reports.download, credentials.kubeconfig) come back as { data: Uint8Array, contentType,
filename }. Password, MFA and API keys themselves are managed in the website only.
const kubeconfig = await cg.credentials.kubeconfig(21, "cluster-cloud-id");
await fs.writeFile(kubeconfig.filename ?? "kubeconfig.yaml", kubeconfig.data);
const form = new FormData();
form.set("key_name", "prod");
form.set("vendor", "5");
form.set("file", new Blob([await fs.readFile("creds.json")]), "creds.json");
await cg.serviceKeyAdmin.create(form);Behaviour
- Retries
429,502,503,504and network errors up to 3 times (exponential backoff with jitter, or the server'sRetry-After). - Idempotency: every
POST/DELETEcarries anIdempotency-Keythat is reused by its retries, so a retried order is never placed twice. Pass your own with{ idempotencyKey }to make retries across process restarts safe. (Not forservices.quote— it writes nothing — orkeyPairs.create, whose private key is never stored.) Calls the server cannot replay — multipart bodies and anything undercredentials— are retried only on429. - Errors are typed:
AuthenticationError(401),PermissionError(403),NotFoundError(404),ValidationError(400/402/422),ConflictError(409),RateLimitError(429,retryAfterSeconds),ApiError(5xx/network),WaitError(fromwaitFor). All extendCloudGateErrorwithcode,status,requestId. - waitFor(id, target, { timeoutMs, intervalMs, signal, onPoll }) polls until the status is
target, and throwsWaitErroronfailed, on an unexpecteddeleted, on timeout or when cancelled.
Reference
Every CloudGate serves the full API reference at https://<your CloudGate address>/public-api-docs and the
machine-readable OpenAPI contract at https://<your CloudGate address>/api/public/v1/openapi.json.
Changes in 1.1.1
Ticket:statusandcategoryare typed as numbers (status 1 open, 2 in progress, 3 resolved, 4 closed, 5 pending; category 1 general, 2 billing, 3 technical, 4 other), and the newstatus_namegives the status as text.- MIT license.
No code changes are needed to upgrade.
Changes in 1.1.0
1.1.0 makes the management lists page like every other list (1.0.0 is deprecated). Code that read their website-shaped answers changes:
// 1.x
const { users } = await cg.users.list({ page: 1, limit: 50 });
// 1.1 — every user, page after page
for await (const user of cg.users.list()) console.log(user.email);The same applies to reports.list, reports.preview, inquiries.list, billing.vendorInvoices,
billing.creditReservations and profile.notificationSettings. reports.retrieve and the new …Page() methods
return one page (limit, cursor) with meta. Nothing else changed.
Versioning
Semantic versioning: from 1.1.0 on, 1.x adds methods and fields without breaking existing code; a breaking change would be 2.0.0.
License
MIT — see LICENSE.
