@hoststack.dev/sdk 0.1.0 → 0.2.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.cjs CHANGED
@@ -33,30 +33,34 @@ var CronResource = class {
33
33
  constructor(client) {
34
34
  this.client = client;
35
35
  }
36
- client;
37
36
  /** List cron executions for a service. */
38
37
  async list(teamId, serviceId, options) {
38
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
39
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
39
40
  const params = new URLSearchParams();
40
41
  if (options?.limit) params.set("limit", String(options.limit));
41
42
  const qs = params.toString();
42
43
  return this.client.request(
43
44
  "GET",
44
- `/api/services/${teamId}/${serviceId}/cron-executions${qs ? `?${qs}` : ""}`
45
+ `/api/services/${tid}/${sid}/cron-executions${qs ? `?${qs}` : ""}`
45
46
  );
46
47
  }
47
48
  /** Get a single cron execution by ID. */
48
49
  async get(teamId, serviceId, executionId) {
49
- return this.client.request(
50
- "GET",
51
- `/api/services/${teamId}/${serviceId}/cron-executions/${executionId}`
52
- );
50
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
51
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
52
+ const eid = await this.client.resolveId(executionId, {
53
+ kind: "cronExecution",
54
+ teamId: tid,
55
+ serviceId: sid
56
+ });
57
+ return this.client.request("GET", `/api/services/${tid}/${sid}/cron-executions/${eid}`);
53
58
  }
54
59
  /** Trigger an immediate cron execution. */
55
60
  async trigger(teamId, serviceId) {
56
- return this.client.request(
57
- "POST",
58
- `/api/services/${teamId}/${serviceId}/cron-executions/trigger`
59
- );
61
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
62
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
63
+ return this.client.request("POST", `/api/services/${tid}/${sid}/cron-executions/trigger`);
60
64
  }
61
65
  };
62
66
 
@@ -65,42 +69,58 @@ var DatabasesResource = class {
65
69
  constructor(client) {
66
70
  this.client = client;
67
71
  }
68
- client;
69
72
  /** List all databases for a project. */
70
73
  async list(teamId, projectId) {
71
- return this.client.request("GET", `/api/databases/${teamId}?projectId=${projectId}`);
74
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
75
+ const pid = await this.client.resolveId(projectId, { kind: "project", teamId: tid });
76
+ return this.client.request("GET", `/api/databases/${tid}?projectId=${pid}`);
72
77
  }
73
78
  /** Get a single database by ID. */
74
79
  async get(teamId, databaseId) {
75
- return this.client.request("GET", `/api/databases/${teamId}/${databaseId}`);
80
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
81
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
82
+ return this.client.request("GET", `/api/databases/${tid}/${did}`);
76
83
  }
77
84
  /** Create a new database. */
78
85
  async create(teamId, data) {
79
- return this.client.request("POST", `/api/databases/${teamId}`, data);
86
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
87
+ return this.client.request("POST", `/api/databases/${tid}`, data);
80
88
  }
81
89
  /** Update a database. */
82
90
  async update(teamId, databaseId, data) {
83
- return this.client.request("PATCH", `/api/databases/${teamId}/${databaseId}`, data);
91
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
92
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
93
+ return this.client.request("PATCH", `/api/databases/${tid}/${did}`, data);
84
94
  }
85
95
  /** Delete a database. */
86
96
  async delete(teamId, databaseId) {
87
- return this.client.request("DELETE", `/api/databases/${teamId}/${databaseId}`);
97
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
98
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
99
+ return this.client.request("DELETE", `/api/databases/${tid}/${did}`);
88
100
  }
89
101
  /** Suspend a database. */
90
102
  async suspend(teamId, databaseId) {
91
- return this.client.request("POST", `/api/databases/${teamId}/${databaseId}/suspend`);
103
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
104
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
105
+ return this.client.request("POST", `/api/databases/${tid}/${did}/suspend`);
92
106
  }
93
107
  /** Resume a suspended database. */
94
108
  async resume(teamId, databaseId) {
95
- return this.client.request("POST", `/api/databases/${teamId}/${databaseId}/resume`);
109
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
110
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
111
+ return this.client.request("POST", `/api/databases/${tid}/${did}/resume`);
96
112
  }
97
113
  /** Get connection credentials. */
98
114
  async getCredentials(teamId, databaseId) {
99
- return this.client.request("GET", `/api/databases/${teamId}/${databaseId}/credentials`);
115
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
116
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
117
+ return this.client.request("GET", `/api/databases/${tid}/${did}/credentials`);
100
118
  }
101
119
  /** Reset the database password. */
102
120
  async resetPassword(teamId, databaseId) {
103
- return this.client.request("POST", `/api/databases/${teamId}/${databaseId}/reset-password`);
121
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
122
+ const did = await this.client.resolveId(databaseId, { kind: "database", teamId: tid });
123
+ return this.client.request("POST", `/api/databases/${tid}/${did}/reset-password`);
104
124
  }
105
125
  };
106
126
 
@@ -109,46 +129,61 @@ var DeploysResource = class {
109
129
  constructor(client) {
110
130
  this.client = client;
111
131
  }
112
- client;
113
132
  /** List deploys for a service. */
114
133
  async list(teamId, serviceId) {
115
- return this.client.request("GET", `/api/services/${teamId}/${serviceId}/deploys`);
134
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
135
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
136
+ return this.client.request("GET", `/api/services/${tid}/${sid}/deploys`);
116
137
  }
117
138
  /** Get a single deploy by ID. */
118
139
  async get(teamId, serviceId, deployId) {
119
- return this.client.request(
120
- "GET",
121
- `/api/services/${teamId}/${serviceId}/deploys/${deployId}`
122
- );
140
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
141
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
142
+ const did = await this.client.resolveId(deployId, {
143
+ kind: "deploy",
144
+ teamId: tid,
145
+ serviceId: sid
146
+ });
147
+ return this.client.request("GET", `/api/services/${tid}/${sid}/deploys/${did}`);
123
148
  }
124
149
  /** Trigger a new deploy. */
125
150
  async trigger(teamId, serviceId, data) {
126
- return this.client.request(
127
- "POST",
128
- `/api/services/${teamId}/${serviceId}/deploys`,
129
- data ?? {}
130
- );
151
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
152
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
153
+ return this.client.request("POST", `/api/services/${tid}/${sid}/deploys`, data ?? {});
131
154
  }
132
155
  /** Cancel an in-progress deploy. */
133
156
  async cancel(teamId, serviceId, deployId) {
134
- return this.client.request(
135
- "POST",
136
- `/api/services/${teamId}/${serviceId}/deploys/${deployId}/cancel`
137
- );
157
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
158
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
159
+ const did = await this.client.resolveId(deployId, {
160
+ kind: "deploy",
161
+ teamId: tid,
162
+ serviceId: sid
163
+ });
164
+ return this.client.request("POST", `/api/services/${tid}/${sid}/deploys/${did}/cancel`);
138
165
  }
139
166
  /** Rollback to a previous deploy. */
140
167
  async rollback(teamId, serviceId, deployId) {
141
- return this.client.request(
142
- "POST",
143
- `/api/services/${teamId}/${serviceId}/deploys/${deployId}/rollback`
144
- );
168
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
169
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
170
+ const did = await this.client.resolveId(deployId, {
171
+ kind: "deploy",
172
+ teamId: tid,
173
+ serviceId: sid
174
+ });
175
+ return this.client.request("POST", `/api/services/${tid}/${sid}/deploys/${did}/rollback`);
145
176
  }
146
177
  /** Get build logs for a deploy. */
147
178
  async getLogs(teamId, serviceId, deployId) {
148
- return this.client.request(
149
- "GET",
150
- `/api/services/${teamId}/${serviceId}/deploys/${deployId}/logs`
151
- );
179
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
180
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
181
+ const did = await this.client.resolveId(deployId, {
182
+ kind: "deploy",
183
+ teamId: tid,
184
+ serviceId: sid
185
+ });
186
+ return this.client.request("GET", `/api/services/${tid}/${sid}/deploys/${did}/logs`);
152
187
  }
153
188
  };
154
189
 
@@ -157,26 +192,33 @@ var DomainsResource = class {
157
192
  constructor(client) {
158
193
  this.client = client;
159
194
  }
160
- client;
161
195
  /** List all domains for the active team. */
162
196
  async list(teamId) {
163
- return this.client.request("GET", `/api/domains/${teamId}`);
197
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
198
+ return this.client.request("GET", `/api/domains/${tid}`);
164
199
  }
165
200
  /** Add a custom domain. */
166
201
  async add(teamId, data) {
167
- return this.client.request("POST", `/api/domains/${teamId}`, data);
202
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
203
+ return this.client.request("POST", `/api/domains/${tid}`, data);
168
204
  }
169
205
  /** Update a domain. */
170
206
  async update(teamId, domainId, data) {
171
- return this.client.request("PATCH", `/api/domains/${teamId}/${domainId}`, data);
207
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
208
+ const did = await this.client.resolveId(domainId, { kind: "domain", teamId: tid });
209
+ return this.client.request("PATCH", `/api/domains/${tid}/${did}`, data);
172
210
  }
173
211
  /** Remove a domain. */
174
212
  async remove(teamId, domainId) {
175
- return this.client.request("DELETE", `/api/domains/${teamId}/${domainId}`);
213
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
214
+ const did = await this.client.resolveId(domainId, { kind: "domain", teamId: tid });
215
+ return this.client.request("DELETE", `/api/domains/${tid}/${did}`);
176
216
  }
177
217
  /** Verify domain DNS configuration. */
178
218
  async verify(teamId, domainId) {
179
- return this.client.request("POST", `/api/domains/${teamId}/${domainId}/verify`);
219
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
220
+ const did = await this.client.resolveId(domainId, { kind: "domain", teamId: tid });
221
+ return this.client.request("POST", `/api/domains/${tid}/${did}/verify`);
180
222
  }
181
223
  };
182
224
 
@@ -185,33 +227,45 @@ var EnvVarsResource = class {
185
227
  constructor(client) {
186
228
  this.client = client;
187
229
  }
188
- client;
189
230
  /** List all environment variables for a service. */
190
231
  async list(teamId, serviceId) {
191
- return this.client.request("GET", `/api/services/${teamId}/${serviceId}/env`);
232
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
233
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
234
+ return this.client.request("GET", `/api/services/${tid}/${sid}/env`);
192
235
  }
193
236
  /** Create a new environment variable. */
194
237
  async create(teamId, serviceId, data) {
195
- return this.client.request("POST", `/api/services/${teamId}/${serviceId}/env`, data);
238
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
239
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
240
+ return this.client.request("POST", `/api/services/${tid}/${sid}/env`, data);
196
241
  }
197
242
  /** Update an environment variable. */
198
243
  async update(teamId, serviceId, envVarId, data) {
199
- return this.client.request(
200
- "PATCH",
201
- `/api/services/${teamId}/${serviceId}/env/${envVarId}`,
202
- data
203
- );
244
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
245
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
246
+ const eid = await this.client.resolveId(envVarId, {
247
+ kind: "envVar",
248
+ teamId: tid,
249
+ serviceId: sid
250
+ });
251
+ return this.client.request("PATCH", `/api/services/${tid}/${sid}/env/${eid}`, data);
204
252
  }
205
253
  /** Delete an environment variable. */
206
254
  async delete(teamId, serviceId, envVarId) {
207
- return this.client.request(
208
- "DELETE",
209
- `/api/services/${teamId}/${serviceId}/env/${envVarId}`
210
- );
255
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
256
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
257
+ const eid = await this.client.resolveId(envVarId, {
258
+ kind: "envVar",
259
+ teamId: tid,
260
+ serviceId: sid
261
+ });
262
+ return this.client.request("DELETE", `/api/services/${tid}/${sid}/env/${eid}`);
211
263
  }
212
264
  /** Bulk set environment variables (create or update). */
213
265
  async bulkSet(teamId, serviceId, data) {
214
- return this.client.request("PUT", `/api/services/${teamId}/${serviceId}/env/bulk`, data);
266
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
267
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
268
+ return this.client.request("PUT", `/api/services/${tid}/${sid}/env/bulk`, data);
215
269
  }
216
270
  };
217
271
 
@@ -220,26 +274,33 @@ var ProjectsResource = class {
220
274
  constructor(client) {
221
275
  this.client = client;
222
276
  }
223
- client;
224
277
  /** List all projects for the active team. */
225
278
  async list(teamId) {
226
- return this.client.request("GET", `/api/projects/${teamId}`);
279
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
280
+ return this.client.request("GET", `/api/projects/${tid}`);
227
281
  }
228
282
  /** Get a single project by ID. */
229
283
  async get(teamId, projectId) {
230
- return this.client.request("GET", `/api/projects/${teamId}/${projectId}`);
284
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
285
+ const pid = await this.client.resolveId(projectId, { kind: "project", teamId: tid });
286
+ return this.client.request("GET", `/api/projects/${tid}/${pid}`);
231
287
  }
232
288
  /** Create a new project. */
233
289
  async create(teamId, data) {
234
- return this.client.request("POST", `/api/projects/${teamId}`, data);
290
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
291
+ return this.client.request("POST", `/api/projects/${tid}`, data);
235
292
  }
236
293
  /** Update a project. */
237
294
  async update(teamId, projectId, data) {
238
- return this.client.request("PATCH", `/api/projects/${teamId}/${projectId}`, data);
295
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
296
+ const pid = await this.client.resolveId(projectId, { kind: "project", teamId: tid });
297
+ return this.client.request("PATCH", `/api/projects/${tid}/${pid}`, data);
239
298
  }
240
299
  /** Delete a project. */
241
300
  async delete(teamId, projectId) {
242
- return this.client.request("DELETE", `/api/projects/${teamId}/${projectId}`);
301
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
302
+ const pid = await this.client.resolveId(projectId, { kind: "project", teamId: tid });
303
+ return this.client.request("DELETE", `/api/projects/${tid}/${pid}`);
243
304
  }
244
305
  };
245
306
 
@@ -305,49 +366,68 @@ var ServicesResource = class {
305
366
  constructor(client) {
306
367
  this.client = client;
307
368
  }
308
- client;
309
369
  /** List all services for the active team. */
310
370
  async list(teamId) {
311
- return this.client.request("GET", `/api/services/${teamId}`);
371
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
372
+ return this.client.request("GET", `/api/services/${tid}`);
312
373
  }
313
374
  /** Get a single service by ID. */
314
375
  async get(teamId, serviceId) {
315
- return this.client.request("GET", `/api/services/${teamId}/${serviceId}`);
376
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
377
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
378
+ return this.client.request("GET", `/api/services/${tid}/${sid}`);
316
379
  }
317
380
  /** Create a new service. */
318
381
  async create(teamId, data) {
319
- return this.client.request("POST", `/api/services/${teamId}`, data);
382
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
383
+ return this.client.request("POST", `/api/services/${tid}`, data);
320
384
  }
321
385
  /** Update a service. */
322
386
  async update(teamId, serviceId, data) {
323
- return this.client.request("PATCH", `/api/services/${teamId}/${serviceId}`, data);
387
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
388
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
389
+ return this.client.request("PATCH", `/api/services/${tid}/${sid}`, data);
324
390
  }
325
391
  /** Delete a service. */
326
392
  async delete(teamId, serviceId) {
327
- return this.client.request("DELETE", `/api/services/${teamId}/${serviceId}`);
393
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
394
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
395
+ return this.client.request("DELETE", `/api/services/${tid}/${sid}`);
328
396
  }
329
397
  /** Suspend a service. */
330
398
  async suspend(teamId, serviceId) {
331
- return this.client.request("POST", `/api/services/${teamId}/${serviceId}/suspend`);
399
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
400
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
401
+ return this.client.request("POST", `/api/services/${tid}/${sid}/suspend`);
332
402
  }
333
403
  /** Resume a suspended service. */
334
404
  async resume(teamId, serviceId) {
335
- return this.client.request("POST", `/api/services/${teamId}/${serviceId}/resume`);
405
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
406
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
407
+ return this.client.request("POST", `/api/services/${tid}/${sid}/resume`);
336
408
  }
337
409
  /** Get service metrics. */
338
410
  async getMetrics(teamId, serviceId) {
339
- return this.client.request("GET", `/api/services/${teamId}/${serviceId}/metrics`);
411
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
412
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
413
+ return this.client.request("GET", `/api/services/${tid}/${sid}/metrics`);
340
414
  }
341
415
  /** Get service configuration. */
342
416
  async getConfig(teamId, serviceId) {
343
- return this.client.request("GET", `/api/services/${teamId}/${serviceId}/config`);
417
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
418
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
419
+ return this.client.request("GET", `/api/services/${tid}/${sid}/config`);
344
420
  }
345
421
  /** Update service configuration. */
346
422
  async updateConfig(teamId, serviceId, data) {
347
- return this.client.request("PATCH", `/api/services/${teamId}/${serviceId}/config`, data);
423
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
424
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
425
+ return this.client.request("PATCH", `/api/services/${tid}/${sid}/config`, data);
348
426
  }
349
427
  /** Get runtime logs for a service. */
350
428
  async getRuntimeLogs(teamId, serviceId, options) {
429
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
430
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
351
431
  const params = new URLSearchParams();
352
432
  if (options?.lines) params.set("lines", String(options.lines));
353
433
  if (options?.since) params.set("since", options.since);
@@ -355,7 +435,7 @@ var ServicesResource = class {
355
435
  const qs = params.toString();
356
436
  return this.client.request(
357
437
  "GET",
358
- `/api/services/${teamId}/${serviceId}/runtime-logs${qs ? `?${qs}` : ""}`
438
+ `/api/services/${tid}/${sid}/runtime-logs${qs ? `?${qs}` : ""}`
359
439
  );
360
440
  }
361
441
  /**
@@ -370,9 +450,11 @@ var ServicesResource = class {
370
450
  * }
371
451
  * ```
372
452
  */
373
- streamLogs(teamId, serviceId, options) {
374
- const basePath = `/api/services/${teamId}/${serviceId}/runtime-logs`;
375
- return streamLogsViaPolling(
453
+ async *streamLogs(teamId, serviceId, options) {
454
+ const tid = await this.client.resolveId(teamId, { kind: "team" });
455
+ const sid = await this.client.resolveId(serviceId, { kind: "service", teamId: tid });
456
+ const basePath = `/api/services/${tid}/${sid}/runtime-logs`;
457
+ yield* streamLogsViaPolling(
376
458
  (path) => this.client.request("GET", path),
377
459
  basePath,
378
460
  options
@@ -381,9 +463,21 @@ var ServicesResource = class {
381
463
  };
382
464
 
383
465
  // src/client.ts
466
+ var PREFIX = {
467
+ team: "team_",
468
+ project: "prj_",
469
+ service: "svc_",
470
+ deploy: "dpl_",
471
+ database: "db_",
472
+ domain: "dom_",
473
+ envVar: "env_",
474
+ cronExecution: "cjob_"
475
+ };
384
476
  var HostStack = class {
385
477
  apiKey;
386
478
  baseUrl;
479
+ // publicId → numeric id, scoped by parent context. Lifetime: client instance.
480
+ idCache = /* @__PURE__ */ new Map();
387
481
  /** Manage projects. */
388
482
  projects;
389
483
  /** Manage services (web, worker, cron). */
@@ -403,7 +497,7 @@ var HostStack = class {
403
497
  throw new Error("apiKey is required");
404
498
  }
405
499
  this.apiKey = options.apiKey;
406
- this.baseUrl = (options.baseUrl ?? "https://api.hoststack.dev").replace(/\/$/, "");
500
+ this.baseUrl = (options.baseUrl ?? "https://hoststack.dev").replace(/\/$/, "");
407
501
  this.projects = new ProjectsResource(this);
408
502
  this.services = new ServicesResource(this);
409
503
  this.deploys = new DeploysResource(this);
@@ -448,7 +542,109 @@ var HostStack = class {
448
542
  }
449
543
  return res.json();
450
544
  }
545
+ /**
546
+ * Resolve a publicId-or-numeric id input to a numeric database id. Numeric
547
+ * inputs short-circuit; publicIds (svc_xyz, dpl_xyz, etc.) are looked up
548
+ * via the relevant list endpoint and cached on this client instance.
549
+ *
550
+ * The API addresses everything by numeric id internally; this resolver lets
551
+ * SDK/MCP consumers pass either form interchangeably without burning extra
552
+ * round-trips on subsequent calls.
553
+ */
554
+ async resolveId(input, scope) {
555
+ if (typeof input === "number") return input;
556
+ if (/^\d+$/.test(input)) return Number.parseInt(input, 10);
557
+ const expectedPrefix = PREFIX[scope.kind];
558
+ if (!input.startsWith(expectedPrefix)) {
559
+ throw new HostStackError(
560
+ 400,
561
+ `Invalid ${scope.kind} id "${input}": expected ${expectedPrefix}xxx or numeric.`
562
+ );
563
+ }
564
+ const cacheKey = `${cacheScope(scope)}:${input}`;
565
+ const cached = this.idCache.get(cacheKey);
566
+ if (cached !== void 0) return cached;
567
+ const items = await this.fetchForResolution(scope);
568
+ const match = items.find((it) => it.publicId === input);
569
+ if (!match) {
570
+ throw new NotFoundError(`${scope.kind} ${input} not found`);
571
+ }
572
+ this.idCache.set(cacheKey, match.id);
573
+ return match.id;
574
+ }
575
+ async fetchForResolution(scope) {
576
+ switch (scope.kind) {
577
+ case "team": {
578
+ const r = await this.request(
579
+ "GET",
580
+ "/api/teams"
581
+ );
582
+ return r.teams ?? [];
583
+ }
584
+ case "project": {
585
+ const r = await this.request(
586
+ "GET",
587
+ `/api/projects/${scope.teamId}`
588
+ );
589
+ return r.projects ?? [];
590
+ }
591
+ case "service": {
592
+ const r = await this.request(
593
+ "GET",
594
+ `/api/services/${scope.teamId}`
595
+ );
596
+ return r.services ?? [];
597
+ }
598
+ case "deploy": {
599
+ const r = await this.request(
600
+ "GET",
601
+ `/api/services/${scope.teamId}/${scope.serviceId}/deploys`
602
+ );
603
+ return r.deploys ?? [];
604
+ }
605
+ case "database": {
606
+ const r = await this.request(
607
+ "GET",
608
+ `/api/databases/${scope.teamId}`
609
+ );
610
+ return r.databases ?? [];
611
+ }
612
+ case "domain": {
613
+ const r = await this.request(
614
+ "GET",
615
+ `/api/domains/${scope.teamId}`
616
+ );
617
+ return r.domains ?? [];
618
+ }
619
+ case "envVar": {
620
+ const r = await this.request(
621
+ "GET",
622
+ `/api/services/${scope.teamId}/${scope.serviceId}/env`
623
+ );
624
+ return r.envVars ?? [];
625
+ }
626
+ case "cronExecution": {
627
+ const r = await this.request("GET", `/api/services/${scope.teamId}/${scope.serviceId}/cron-executions`);
628
+ return r.executions ?? [];
629
+ }
630
+ }
631
+ }
451
632
  };
633
+ function cacheScope(scope) {
634
+ switch (scope.kind) {
635
+ case "team":
636
+ return "team";
637
+ case "project":
638
+ case "service":
639
+ case "database":
640
+ case "domain":
641
+ return `${scope.kind}:${scope.teamId}`;
642
+ case "deploy":
643
+ case "envVar":
644
+ case "cronExecution":
645
+ return `${scope.kind}:${scope.teamId}:${scope.serviceId}`;
646
+ }
647
+ }
452
648
 
453
649
  // src/pagination.ts
454
650
  function buildPaginationQuery(params) {