@hoststack.dev/sdk 0.4.0 → 0.5.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/README.md CHANGED
@@ -53,19 +53,21 @@ Generate an API key from your [HostStack dashboard → Settings → API Keys](ht
53
53
 
54
54
  ## Resources
55
55
 
56
- | Resource | Methods |
57
- | --- | --- |
58
- | `client.projects` | `list`, `get`, `create`, `update`, `delete` |
59
- | `client.services` | `list`, `get`, `create`, `update`, `delete`, `suspend`, `resume`, `getMetrics`, `getConfig`, `updateConfig`, `getRuntimeLogs`, `streamLogs` |
60
- | `client.deploys` | `list`, `get`, `trigger`, `cancel`, `rollback`, `getLogs` |
61
- | `client.databases` | `list`, `get`, `create`, `update`, `delete`, `suspend`, `resume`, `getCredentials`, `resetPassword` |
62
- | `client.domains` | `list`, `add`, `update`, `remove`, `verify` |
63
- | `client.envVars` | `list`, `create`, `update`, `delete`, `bulkSet` |
64
- | `client.environments` | `list`, `get`, `create`, `update`, `delete` |
65
- | `client.cron` | `list`, `get`, `trigger` |
66
- | `client.deploys` | `…`, `promote(teamId, serviceId, deployId, targetEnvId)` — image-based promotion across envs |
67
-
68
- Every method's first argument is `teamId: number`. Full API reference: **[hoststack.dev/docs/sdk](https://hoststack.dev/docs/sdk)**.
56
+ | Resource | Methods |
57
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
58
+ | `client.projects` | `list`, `get`, `create`, `update`, `delete` |
59
+ | `client.services` | `list`, `get`, `create`, `update`, `delete`, `suspend`, `resume`, `getMetrics`, `getConfig`, `updateConfig`, `getRuntimeLogs`, `streamLogs` |
60
+ | `client.deploys` | `list`, `get`, `trigger`, `cancel`, `rollback`, `promote`, `getLogs` |
61
+ | `client.databases` | `list`, `get`, `create`, `update`, `delete`, `suspend`, `resume`, `getCredentials`, `resetPassword` |
62
+ | `client.domains` | `list`, `add`, `update`, `remove`, `verify` |
63
+ | `client.envVars` | `list`, `create`, `update`, `delete`, `bulkSet` |
64
+ | `client.volumes` | `list`, `create`, `update`, `delete` |
65
+ | `client.environments` | `list`, `get`, `create`, `update`, `delete` |
66
+ | `client.cron` | `list`, `get`, `trigger` |
67
+
68
+ Every method's first argument is the team id — accepts either the numeric id or the `team_…` publicId (the SDK resolves publicIds to numeric ids internally and caches the lookup). Full API reference: **[hoststack.dev/docs/sdk](https://hoststack.dev/docs/sdk)**.
69
+
70
+ `client.deploys.promote(teamId, serviceId, deployId, targetEnvironmentId)` performs image-based promotion: it pins the same built image into a sibling environment without rebuilding.
69
71
 
70
72
  ## Error handling
71
73
 
@@ -96,7 +98,8 @@ try {
96
98
  ## Related packages
97
99
 
98
100
  - **[@hoststack.dev/cli](https://www.npmjs.com/package/@hoststack.dev/cli)** — command-line interface for HostStack
99
- - **[Terraform provider](https://github.com/gethoststack/terraform-provider-hoststack)** — manage HostStack resources as IaC
101
+ - **[@hoststack.dev/mcp](https://www.npmjs.com/package/@hoststack.dev/mcp)** — MCP server for Claude, Cursor, and other AI agents
102
+ - **Terraform provider** — see [hoststack.dev/docs](https://hoststack.dev/docs) for installation and resource reference
100
103
 
101
104
  ## Support
102
105
 
package/dist/index.cjs CHANGED
@@ -198,11 +198,9 @@ var DeploysResource = class {
198
198
  teamId: tid,
199
199
  serviceId: sid
200
200
  });
201
- return this.client.request(
202
- "POST",
203
- `/api/services/${tid}/${sid}/deploys/${did}/promote`,
204
- { targetEnvironmentId }
205
- );
201
+ return this.client.request("POST", `/api/services/${tid}/${sid}/deploys/${did}/promote`, {
202
+ targetEnvironmentId
203
+ });
206
204
  }
207
205
  /**
208
206
  * Get build logs for a deploy.
@@ -356,6 +354,65 @@ var EnvVarsResource = class {
356
354
  }
357
355
  };
358
356
 
357
+ // src/resources/notifications.ts
358
+ var NotificationsResource = class {
359
+ constructor(client) {
360
+ this.client = client;
361
+ }
362
+ /**
363
+ * List notification channels for the team. Webhook URLs are
364
+ * server-side masked in the response so this is safe to log.
365
+ */
366
+ async listChannels(teamId) {
367
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
368
+ return this.client.request("GET", `/api/notifications/${tid}/channels`);
369
+ }
370
+ /**
371
+ * Create a Slack/Discord/email notification channel.
372
+ *
373
+ * For type=email, `webhookUrl` is the recipient email address; for
374
+ * type=slack/discord it's the incoming webhook URL.
375
+ *
376
+ * `events` is the explicit subscription list — an empty array means
377
+ * "receive nothing". The platform pre-selects the critical-event
378
+ * set on the dashboard, but SDK callers must pass the list
379
+ * explicitly so behaviour is deterministic.
380
+ */
381
+ async createChannel(teamId, data) {
382
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
383
+ return this.client.request("POST", `/api/notifications/${tid}/channels`, data);
384
+ }
385
+ /**
386
+ * Update a channel's name / active state / event subscriptions. The
387
+ * webhook URL and type are immutable — create a new channel if
388
+ * those need to change.
389
+ */
390
+ async updateChannel(teamId, channelId, data) {
391
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
392
+ return this.client.request(
393
+ "PATCH",
394
+ `/api/notifications/${tid}/channels/${channelId}`,
395
+ data
396
+ );
397
+ }
398
+ /** Delete a notification channel. */
399
+ async deleteChannel(teamId, channelId) {
400
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
401
+ return this.client.request("DELETE", `/api/notifications/${tid}/channels/${channelId}`);
402
+ }
403
+ /**
404
+ * Fire a test event to the channel so the user can confirm the
405
+ * webhook is wired correctly. Returns the dispatch outcome.
406
+ */
407
+ async testChannel(teamId, channelId) {
408
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
409
+ return this.client.request(
410
+ "POST",
411
+ `/api/notifications/${tid}/channels/${channelId}/test`
412
+ );
413
+ }
414
+ };
415
+
359
416
  // src/resources/projects.ts
360
417
  var ProjectsResource = class {
361
418
  constructor(client) {
@@ -453,10 +510,23 @@ var ServicesResource = class {
453
510
  constructor(client) {
454
511
  this.client = client;
455
512
  }
456
- /** List all services for the active team. */
457
- async list(teamId) {
513
+ /**
514
+ * List services for the active team.
515
+ *
516
+ * Optional filters narrow by project, environment, status, or type.
517
+ * The server treats unknown enum values as no match (returns empty)
518
+ * rather than 400-ing.
519
+ */
520
+ async list(teamId, filters) {
458
521
  const tid = await this.client.resolveId(teamId, { kind: "team" });
459
- return this.client.request("GET", `/api/services/${tid}`);
522
+ const params = new URLSearchParams();
523
+ if (filters?.projectId !== void 0) params.set("projectId", String(filters.projectId));
524
+ if (filters?.environmentId !== void 0)
525
+ params.set("environmentId", String(filters.environmentId));
526
+ if (filters?.status) params.set("status", filters.status);
527
+ if (filters?.type) params.set("type", filters.type);
528
+ const qs = params.toString();
529
+ return this.client.request("GET", `/api/services/${tid}${qs ? `?${qs}` : ""}`);
460
530
  }
461
531
  /** Get a single service by ID. */
462
532
  async get(teamId, serviceId) {
@@ -499,6 +569,25 @@ var ServicesResource = class {
499
569
  const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
500
570
  return this.client.request("GET", `/api/services/${tid}/${sid}/metrics`);
501
571
  }
572
+ /**
573
+ * Get a metrics time series for a service.
574
+ *
575
+ * `from`/`to` accept ISO-8601 timestamps. Omit both for the trailing
576
+ * hour. Server picks the resolution: raw samples ≤7d, hourly pre-
577
+ * aggregates ≤30d, daily beyond that. Up to ~500 points returned.
578
+ */
579
+ async getMetricsHistory(teamId, serviceId, options) {
580
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
581
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
582
+ const params = new URLSearchParams();
583
+ if (options?.from) params.set("from", options.from);
584
+ if (options?.to) params.set("to", options.to);
585
+ const qs = params.toString();
586
+ return this.client.request(
587
+ "GET",
588
+ `/api/services/${tid}/${sid}/metrics/history${qs ? `?${qs}` : ""}`
589
+ );
590
+ }
502
591
  /** Get service configuration. */
503
592
  async getConfig(teamId, serviceId) {
504
593
  const tid = await this.client.resolveId(teamId, { kind: "team" });
@@ -557,11 +646,7 @@ var ServicesResource = class {
557
646
  const tid = await this.client.resolveId(teamId, { kind: "team" });
558
647
  const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
559
648
  const basePath = `/api/services/${tid}/${sid}/runtime-logs`;
560
- yield* streamLogsViaPolling(
561
- (path) => this.client.request("GET", path),
562
- basePath,
563
- options
564
- );
649
+ yield* streamLogsViaPolling((path) => this.client.request("GET", path), basePath, options);
565
650
  }
566
651
  };
567
652
 
@@ -649,6 +734,12 @@ var HostStack = class {
649
734
  cron;
650
735
  /** Manage persistent disks attached to services. */
651
736
  volumes;
737
+ /**
738
+ * Manage notification channels — Slack/Discord webhooks + email
739
+ * recipients with per-channel event filters. Used for deploy
740
+ * failures, restart loops, ACME failures, git auth losses, etc.
741
+ */
742
+ notifications;
652
743
  constructor(options) {
653
744
  if (!options.apiKey) {
654
745
  throw new Error("apiKey is required");
@@ -664,6 +755,7 @@ var HostStack = class {
664
755
  this.environments = new EnvironmentsResource(this);
665
756
  this.cron = new CronResource(this);
666
757
  this.volumes = new VolumesResource(this);
758
+ this.notifications = new NotificationsResource(this);
667
759
  }
668
760
  /**
669
761
  * Make an authenticated request to the HostStack API.
@@ -755,17 +847,11 @@ var HostStack = class {
755
847
  return r.services ?? [];
756
848
  }
757
849
  case "deploy": {
758
- const r = await this.request(
759
- "GET",
760
- `/api/services/${scope.teamId}/${scope.serviceId}/deploys?perPage=100`
761
- );
850
+ const r = await this.request("GET", `/api/services/${scope.teamId}/${scope.serviceId}/deploys?perPage=100`);
762
851
  return r.data ?? [];
763
852
  }
764
853
  case "database": {
765
- const r = await this.request(
766
- "GET",
767
- `/api/databases/${scope.teamId}`
768
- );
854
+ const r = await this.request("GET", `/api/databases/${scope.teamId}`);
769
855
  return r.databases ?? [];
770
856
  }
771
857
  case "domain": {