@hoststack.dev/sdk 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.js CHANGED
@@ -196,11 +196,9 @@ var DeploysResource = class {
196
196
  teamId: tid,
197
197
  serviceId: sid
198
198
  });
199
- return this.client.request(
200
- "POST",
201
- `/api/services/${tid}/${sid}/deploys/${did}/promote`,
202
- { targetEnvironmentId }
203
- );
199
+ return this.client.request("POST", `/api/services/${tid}/${sid}/deploys/${did}/promote`, {
200
+ targetEnvironmentId
201
+ });
204
202
  }
205
203
  /**
206
204
  * Get build logs for a deploy.
@@ -354,6 +352,62 @@ var EnvVarsResource = class {
354
352
  }
355
353
  };
356
354
 
355
+ // src/resources/notifications.ts
356
+ var NotificationsResource = class {
357
+ constructor(client) {
358
+ this.client = client;
359
+ }
360
+ /**
361
+ * List notification channels for the team. Webhook URLs are
362
+ * server-side masked in the response so this is safe to log.
363
+ */
364
+ async listChannels(teamId) {
365
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
366
+ return this.client.request("GET", `/api/notifications/${tid}/channels`);
367
+ }
368
+ /**
369
+ * Create a Slack/Discord/email notification channel.
370
+ *
371
+ * For type=email, `webhookUrl` is the recipient email address; for
372
+ * type=slack/discord it's the incoming webhook URL.
373
+ *
374
+ * `events` is the explicit subscription list — an empty array means
375
+ * "receive nothing". The platform pre-selects the critical-event
376
+ * set on the dashboard, but SDK callers must pass the list
377
+ * explicitly so behaviour is deterministic.
378
+ */
379
+ async createChannel(teamId, data) {
380
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
381
+ return this.client.request("POST", `/api/notifications/${tid}/channels`, data);
382
+ }
383
+ /**
384
+ * Update a channel's name / active state / event subscriptions. The
385
+ * webhook URL and type are immutable — create a new channel if
386
+ * those need to change.
387
+ */
388
+ async updateChannel(teamId, channelId, data) {
389
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
390
+ return this.client.request(
391
+ "PATCH",
392
+ `/api/notifications/${tid}/channels/${channelId}`,
393
+ data
394
+ );
395
+ }
396
+ /** Delete a notification channel. */
397
+ async deleteChannel(teamId, channelId) {
398
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
399
+ return this.client.request("DELETE", `/api/notifications/${tid}/channels/${channelId}`);
400
+ }
401
+ /**
402
+ * Fire a test event to the channel so the user can confirm the
403
+ * webhook is wired correctly. Returns the dispatch outcome.
404
+ */
405
+ async testChannel(teamId, channelId) {
406
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
407
+ return this.client.request("POST", `/api/notifications/${tid}/channels/${channelId}/test`);
408
+ }
409
+ };
410
+
357
411
  // src/resources/projects.ts
358
412
  var ProjectsResource = class {
359
413
  constructor(client) {
@@ -451,10 +505,23 @@ var ServicesResource = class {
451
505
  constructor(client) {
452
506
  this.client = client;
453
507
  }
454
- /** List all services for the active team. */
455
- async list(teamId) {
508
+ /**
509
+ * List services for the active team.
510
+ *
511
+ * Optional filters narrow by project, environment, status, or type.
512
+ * The server treats unknown enum values as no match (returns empty)
513
+ * rather than 400-ing.
514
+ */
515
+ async list(teamId, filters) {
456
516
  const tid = await this.client.resolveId(teamId, { kind: "team" });
457
- return this.client.request("GET", `/api/services/${tid}`);
517
+ const params = new URLSearchParams();
518
+ if (filters?.projectId !== void 0) params.set("projectId", String(filters.projectId));
519
+ if (filters?.environmentId !== void 0)
520
+ params.set("environmentId", String(filters.environmentId));
521
+ if (filters?.status) params.set("status", filters.status);
522
+ if (filters?.type) params.set("type", filters.type);
523
+ const qs = params.toString();
524
+ return this.client.request("GET", `/api/services/${tid}${qs ? `?${qs}` : ""}`);
458
525
  }
459
526
  /** Get a single service by ID. */
460
527
  async get(teamId, serviceId) {
@@ -497,6 +564,25 @@ var ServicesResource = class {
497
564
  const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
498
565
  return this.client.request("GET", `/api/services/${tid}/${sid}/metrics`);
499
566
  }
567
+ /**
568
+ * Get a metrics time series for a service.
569
+ *
570
+ * `from`/`to` accept ISO-8601 timestamps. Omit both for the trailing
571
+ * hour. Server picks the resolution: raw samples ≤7d, hourly pre-
572
+ * aggregates ≤30d, daily beyond that. Up to ~500 points returned.
573
+ */
574
+ async getMetricsHistory(teamId, serviceId, options) {
575
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
576
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
577
+ const params = new URLSearchParams();
578
+ if (options?.from) params.set("from", options.from);
579
+ if (options?.to) params.set("to", options.to);
580
+ const qs = params.toString();
581
+ return this.client.request(
582
+ "GET",
583
+ `/api/services/${tid}/${sid}/metrics/history${qs ? `?${qs}` : ""}`
584
+ );
585
+ }
500
586
  /** Get service configuration. */
501
587
  async getConfig(teamId, serviceId) {
502
588
  const tid = await this.client.resolveId(teamId, { kind: "team" });
@@ -555,11 +641,7 @@ var ServicesResource = class {
555
641
  const tid = await this.client.resolveId(teamId, { kind: "team" });
556
642
  const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
557
643
  const basePath = `/api/services/${tid}/${sid}/runtime-logs`;
558
- yield* streamLogsViaPolling(
559
- (path) => this.client.request("GET", path),
560
- basePath,
561
- options
562
- );
644
+ yield* streamLogsViaPolling((path) => this.client.request("GET", path), basePath, options);
563
645
  }
564
646
  };
565
647
 
@@ -647,6 +729,12 @@ var HostStack = class {
647
729
  cron;
648
730
  /** Manage persistent disks attached to services. */
649
731
  volumes;
732
+ /**
733
+ * Manage notification channels — Slack/Discord webhooks + email
734
+ * recipients with per-channel event filters. Used for deploy
735
+ * failures, restart loops, ACME failures, git auth losses, etc.
736
+ */
737
+ notifications;
650
738
  constructor(options) {
651
739
  if (!options.apiKey) {
652
740
  throw new Error("apiKey is required");
@@ -662,6 +750,7 @@ var HostStack = class {
662
750
  this.environments = new EnvironmentsResource(this);
663
751
  this.cron = new CronResource(this);
664
752
  this.volumes = new VolumesResource(this);
753
+ this.notifications = new NotificationsResource(this);
665
754
  }
666
755
  /**
667
756
  * Make an authenticated request to the HostStack API.
@@ -753,17 +842,11 @@ var HostStack = class {
753
842
  return r.services ?? [];
754
843
  }
755
844
  case "deploy": {
756
- const r = await this.request(
757
- "GET",
758
- `/api/services/${scope.teamId}/${scope.serviceId}/deploys?perPage=100`
759
- );
845
+ const r = await this.request("GET", `/api/services/${scope.teamId}/${scope.serviceId}/deploys?perPage=100`);
760
846
  return r.data ?? [];
761
847
  }
762
848
  case "database": {
763
- const r = await this.request(
764
- "GET",
765
- `/api/databases/${scope.teamId}`
766
- );
849
+ const r = await this.request("GET", `/api/databases/${scope.teamId}`);
767
850
  return r.databases ?? [];
768
851
  }
769
852
  case "domain": {