@hoststack.dev/sdk 0.8.0 → 0.8.2
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 +23 -17
- package/dist/index.cjs +71 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -33
- package/dist/index.d.ts +99 -33
- package/dist/index.js +70 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Official TypeScript SDK for [HostStack](https://hoststack.dev) — the European
|
|
|
11
11
|
- **Website:** [hoststack.dev](https://hoststack.dev)
|
|
12
12
|
- **Documentation:** [hoststack.dev/docs](https://hoststack.dev/docs)
|
|
13
13
|
- **SDK reference:** [hoststack.dev/docs/sdk](https://hoststack.dev/docs/sdk)
|
|
14
|
-
- **Source:** [github.com/
|
|
14
|
+
- **Source:** [github.com/miccidk/hoststack](https://github.com/miccidk/hoststack/tree/master/packages/sdk)
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -53,18 +53,18 @@ 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`, `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
|
-
| `client.notifications` | `listChannels`, `createChannel`, `updateChannel`, `deleteChannel`, `testChannel`
|
|
56
|
+
| Resource | Methods |
|
|
57
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `client.projects` | `list`, `get`, `create`, `update`, `delete` |
|
|
59
|
+
| `client.services` | `list`, `get`, `create`, `update`, `delete`, `suspend`, `resume`, `getMetrics`, `getMetricsHistory`, `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`, `query`, `upgradeToHa` |
|
|
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
|
+
| `client.notifications` | `listChannels`, `createChannel`, `updateChannel`, `deleteChannel`, `testChannel` |
|
|
68
68
|
|
|
69
69
|
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)**.
|
|
70
70
|
|
|
@@ -76,7 +76,9 @@ Every method's first argument is the team id — accepts either the numeric id o
|
|
|
76
76
|
import {
|
|
77
77
|
HostStack,
|
|
78
78
|
AuthenticationError,
|
|
79
|
+
ForbiddenError,
|
|
79
80
|
NotFoundError,
|
|
81
|
+
ConflictError,
|
|
80
82
|
RateLimitError,
|
|
81
83
|
HostStackError,
|
|
82
84
|
} from '@hoststack.dev/sdk';
|
|
@@ -87,11 +89,15 @@ try {
|
|
|
87
89
|
if (err instanceof NotFoundError) {
|
|
88
90
|
// 404
|
|
89
91
|
} else if (err instanceof AuthenticationError) {
|
|
90
|
-
// 401
|
|
92
|
+
// 401 — API key missing or expired
|
|
93
|
+
} else if (err instanceof ForbiddenError) {
|
|
94
|
+
// 403 — key lacks the required scope (e.g. deploy_only trying to mutate)
|
|
95
|
+
} else if (err instanceof ConflictError) {
|
|
96
|
+
// 409 — resource state prevents the op (already exists, in-flight migration, …)
|
|
91
97
|
} else if (err instanceof RateLimitError) {
|
|
92
|
-
// 429 — err.retryAfter is seconds to wait
|
|
98
|
+
// 429 — err.retryAfter is seconds to wait (from Retry-After header), or undefined
|
|
93
99
|
} else if (err instanceof HostStackError) {
|
|
94
|
-
// any other API error — err.
|
|
100
|
+
// any other API error — err.statusCode and err.body are available
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
```
|
|
@@ -104,7 +110,7 @@ try {
|
|
|
104
110
|
|
|
105
111
|
## Support
|
|
106
112
|
|
|
107
|
-
- Issues: [github.com/
|
|
113
|
+
- Issues: [github.com/miccidk/hoststack/issues](https://github.com/miccidk/hoststack/issues)
|
|
108
114
|
- Docs: [hoststack.dev/docs](https://hoststack.dev/docs)
|
|
109
115
|
- Homepage: [hoststack.dev](https://hoststack.dev)
|
|
110
116
|
|
package/dist/index.cjs
CHANGED
|
@@ -3,28 +3,49 @@
|
|
|
3
3
|
// src/errors.ts
|
|
4
4
|
var HostStackError = class extends Error {
|
|
5
5
|
statusCode;
|
|
6
|
-
|
|
6
|
+
/** Raw response body, if it parsed as JSON. Useful for surfacing field-level validation errors. */
|
|
7
|
+
body;
|
|
8
|
+
constructor(statusCode, message, body) {
|
|
7
9
|
super(message);
|
|
8
10
|
this.name = "HostStackError";
|
|
9
11
|
this.statusCode = statusCode;
|
|
12
|
+
this.body = body;
|
|
10
13
|
}
|
|
11
14
|
};
|
|
12
15
|
var AuthenticationError = class extends HostStackError {
|
|
13
|
-
constructor(message = "Authentication failed
|
|
14
|
-
super(401, message);
|
|
16
|
+
constructor(message = "Authentication failed \u2014 check your API key.", body) {
|
|
17
|
+
super(401, message, body);
|
|
15
18
|
this.name = "AuthenticationError";
|
|
16
19
|
}
|
|
17
20
|
};
|
|
21
|
+
var ForbiddenError = class extends HostStackError {
|
|
22
|
+
constructor(message = "Permission denied \u2014 API key lacks the required scope.", body) {
|
|
23
|
+
super(403, message, body);
|
|
24
|
+
this.name = "ForbiddenError";
|
|
25
|
+
}
|
|
26
|
+
};
|
|
18
27
|
var NotFoundError = class extends HostStackError {
|
|
19
|
-
constructor(message = "Resource not found.") {
|
|
20
|
-
super(404, message);
|
|
28
|
+
constructor(message = "Resource not found.", body) {
|
|
29
|
+
super(404, message, body);
|
|
21
30
|
this.name = "NotFoundError";
|
|
22
31
|
}
|
|
23
32
|
};
|
|
33
|
+
var ConflictError = class extends HostStackError {
|
|
34
|
+
constructor(message = "Conflict \u2014 the resource state prevents this operation.", body) {
|
|
35
|
+
super(409, message, body);
|
|
36
|
+
this.name = "ConflictError";
|
|
37
|
+
}
|
|
38
|
+
};
|
|
24
39
|
var RateLimitError = class extends HostStackError {
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Seconds to wait before retrying, parsed from the `Retry-After` response
|
|
42
|
+
* header. `undefined` if the server didn't send one.
|
|
43
|
+
*/
|
|
44
|
+
retryAfter;
|
|
45
|
+
constructor(message = "Rate limit exceeded \u2014 back off and retry.", retryAfter, body) {
|
|
46
|
+
super(429, message, body);
|
|
27
47
|
this.name = "RateLimitError";
|
|
48
|
+
this.retryAfter = retryAfter;
|
|
28
49
|
}
|
|
29
50
|
};
|
|
30
51
|
|
|
@@ -69,9 +90,15 @@ var DatabasesResource = class {
|
|
|
69
90
|
constructor(client) {
|
|
70
91
|
this.client = client;
|
|
71
92
|
}
|
|
72
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* List databases for the team. Pass `projectId` to scope to one
|
|
95
|
+
* project; omit it to list every database the team owns.
|
|
96
|
+
*/
|
|
73
97
|
async list(teamId, projectId) {
|
|
74
98
|
const tid = await this.client.resolveId(teamId, { kind: "team" });
|
|
99
|
+
if (projectId === void 0) {
|
|
100
|
+
return this.client.request("GET", `/api/databases/${tid}`);
|
|
101
|
+
}
|
|
75
102
|
const pid = await this.client.resolveId(projectId, { kind: "project", teamId: tid });
|
|
76
103
|
return this.client.request("GET", `/api/databases/${tid}?projectId=${pid}`);
|
|
77
104
|
}
|
|
@@ -287,7 +314,8 @@ var DomainsResource = class {
|
|
|
287
314
|
/** Add a custom domain. */
|
|
288
315
|
async add(teamId, data) {
|
|
289
316
|
const tid = await this.client.resolveId(teamId, { kind: "team" });
|
|
290
|
-
|
|
317
|
+
const sid = await this.client.resolveId(data.serviceId, { kind: "service", teamId: tid });
|
|
318
|
+
return this.client.request("POST", `/api/domains/${tid}`, { ...data, serviceId: sid });
|
|
291
319
|
}
|
|
292
320
|
/** Update a domain. */
|
|
293
321
|
async update(teamId, domainId, data) {
|
|
@@ -374,22 +402,24 @@ var EnvVarsResource = class {
|
|
|
374
402
|
async update(teamId, serviceId, envVarId, data) {
|
|
375
403
|
const tid = await this.client.resolveId(teamId, { kind: "team" });
|
|
376
404
|
const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
|
|
377
|
-
const eid =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
405
|
+
const eid = typeof envVarId === "number" ? envVarId : Number.parseInt(envVarId, 10);
|
|
406
|
+
if (Number.isNaN(eid)) {
|
|
407
|
+
throw new Error(
|
|
408
|
+
`Invalid envVarId "${envVarId}": expected a numeric id (env vars have no publicId \u2014 read it from list()).`
|
|
409
|
+
);
|
|
410
|
+
}
|
|
382
411
|
return this.client.request("PATCH", `/api/services/${tid}/${sid}/env/${eid}`, data);
|
|
383
412
|
}
|
|
384
413
|
/** Delete an environment variable. */
|
|
385
414
|
async delete(teamId, serviceId, envVarId) {
|
|
386
415
|
const tid = await this.client.resolveId(teamId, { kind: "team" });
|
|
387
416
|
const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
|
|
388
|
-
const eid =
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
417
|
+
const eid = typeof envVarId === "number" ? envVarId : Number.parseInt(envVarId, 10);
|
|
418
|
+
if (Number.isNaN(eid)) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
`Invalid envVarId "${envVarId}": expected a numeric id (env vars have no publicId \u2014 read it from list()).`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
393
423
|
return this.client.request("DELETE", `/api/services/${tid}/${sid}/env/${eid}`);
|
|
394
424
|
}
|
|
395
425
|
/** Bulk set environment variables (create or update). */
|
|
@@ -606,7 +636,13 @@ var ServicesResource = class {
|
|
|
606
636
|
const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
|
|
607
637
|
return this.client.request("POST", `/api/services/${tid}/${sid}/resume`);
|
|
608
638
|
}
|
|
609
|
-
/**
|
|
639
|
+
/**
|
|
640
|
+
* Get the latest metrics snapshot for a service.
|
|
641
|
+
*
|
|
642
|
+
* Returns `metrics: null` before the first agent sample lands;
|
|
643
|
+
* `serverOverview: null` when the service is not currently placed
|
|
644
|
+
* (suspended, between deploys, etc).
|
|
645
|
+
*/
|
|
610
646
|
async getMetrics(teamId, serviceId) {
|
|
611
647
|
const tid = await this.client.resolveId(teamId, { kind: "team" });
|
|
612
648
|
const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
|
|
@@ -750,8 +786,7 @@ var PREFIX = {
|
|
|
750
786
|
database: "db_",
|
|
751
787
|
domain: "dom_",
|
|
752
788
|
volume: "vol_",
|
|
753
|
-
|
|
754
|
-
environment: "environment_",
|
|
789
|
+
environment: "env_",
|
|
755
790
|
cronExecution: "cjob_"
|
|
756
791
|
};
|
|
757
792
|
var HostStack = class {
|
|
@@ -822,13 +857,20 @@ var HostStack = class {
|
|
|
822
857
|
const message = data.error ?? `HTTP ${res.status}`;
|
|
823
858
|
switch (res.status) {
|
|
824
859
|
case 401:
|
|
825
|
-
throw new AuthenticationError(message);
|
|
860
|
+
throw new AuthenticationError(message, data);
|
|
861
|
+
case 403:
|
|
862
|
+
throw new ForbiddenError(message, data);
|
|
826
863
|
case 404:
|
|
827
|
-
throw new NotFoundError(message);
|
|
828
|
-
case
|
|
829
|
-
throw new
|
|
864
|
+
throw new NotFoundError(message, data);
|
|
865
|
+
case 409:
|
|
866
|
+
throw new ConflictError(message, data);
|
|
867
|
+
case 429: {
|
|
868
|
+
const header = res.headers.get("Retry-After");
|
|
869
|
+
const retryAfter = header && /^\d+$/.test(header) ? Number(header) : void 0;
|
|
870
|
+
throw new RateLimitError(message, retryAfter, data);
|
|
871
|
+
}
|
|
830
872
|
default:
|
|
831
|
-
throw new HostStackError(res.status, message);
|
|
873
|
+
throw new HostStackError(res.status, message, data);
|
|
832
874
|
}
|
|
833
875
|
}
|
|
834
876
|
if (res.status === 204) {
|
|
@@ -904,13 +946,6 @@ var HostStack = class {
|
|
|
904
946
|
);
|
|
905
947
|
return r.domains ?? [];
|
|
906
948
|
}
|
|
907
|
-
case "envVar": {
|
|
908
|
-
const r = await this.request(
|
|
909
|
-
"GET",
|
|
910
|
-
`/api/services/${scope.teamId}/${scope.serviceId}/env`
|
|
911
|
-
);
|
|
912
|
-
return r.envVars ?? [];
|
|
913
|
-
}
|
|
914
949
|
case "volume": {
|
|
915
950
|
const r = await this.request("GET", `/api/services/${scope.teamId}/${scope.serviceId}/volumes`);
|
|
916
951
|
return r.volumes ?? [];
|
|
@@ -943,7 +978,6 @@ function cacheScope(scope) {
|
|
|
943
978
|
return `${scope.kind}:${scope.teamId}`;
|
|
944
979
|
case "deploy":
|
|
945
980
|
case "volume":
|
|
946
|
-
case "envVar":
|
|
947
981
|
case "cronExecution":
|
|
948
982
|
return `${scope.kind}:${scope.teamId}:${scope.serviceId}`;
|
|
949
983
|
}
|
|
@@ -971,6 +1005,8 @@ function wrapArray(items, params) {
|
|
|
971
1005
|
}
|
|
972
1006
|
|
|
973
1007
|
exports.AuthenticationError = AuthenticationError;
|
|
1008
|
+
exports.ConflictError = ConflictError;
|
|
1009
|
+
exports.ForbiddenError = ForbiddenError;
|
|
974
1010
|
exports.HostStack = HostStack;
|
|
975
1011
|
exports.HostStackError = HostStackError;
|
|
976
1012
|
exports.NotFoundError = NotFoundError;
|