@honeyhive/control-plane-sdk 1.0.0 → 1.1.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.
@@ -5,17 +5,33 @@ import {
5
5
  type ListAlertsRequest,
6
6
  type CreateAlertRequest,
7
7
  type GetAlertRequest,
8
+ type CreateWorkspaceRequest,
9
+ type GetWorkspaceRequest,
10
+ type UpdateWorkspaceRequest,
11
+ type DeleteWorkspaceRequest,
8
12
  type CreateProjectRequest,
9
13
  type GetProjectRequest,
10
14
  type UpdateProjectRequest,
11
15
  type DeleteProjectRequest,
16
+ type CreateVirtualDataplaneRequest,
17
+ type GetVirtualDataplaneRequest,
18
+ type UpdateVirtualDataplaneRequest,
19
+ type DeleteVirtualDataplaneRequest,
12
20
  type ListAlertsResponse,
13
21
  type CreateAlertResponse,
14
22
  type GetAlertResponse,
23
+ type CreateWorkspaceResponse,
24
+ type GetWorkspaceResponse,
25
+ type UpdateWorkspaceResponse,
26
+ type DeleteWorkspaceResponse,
15
27
  type CreateProjectResponse,
16
28
  type GetProjectResponse,
17
29
  type UpdateProjectResponse,
18
30
  type DeleteProjectResponse,
31
+ type CreateVirtualDataplaneResponse,
32
+ type GetVirtualDataplaneResponse,
33
+ type UpdateVirtualDataplaneResponse,
34
+ type DeleteVirtualDataplaneResponse,
19
35
  } from './apiTypes.js';
20
36
  import { type ClientConfig, type FetchOptions, createApiClient, unwrap } from '../util.js';
21
37
 
@@ -82,6 +98,130 @@ class AlertsNamespace {
82
98
  }
83
99
  }
84
100
 
101
+ /** @inline */
102
+ class WorkspacesNamespace {
103
+ #client: ReturnType<typeof createApiClient<paths>>;
104
+
105
+ constructor(client: ReturnType<typeof createApiClient<paths>>) {
106
+ this.#client = client;
107
+ }
108
+
109
+ /**
110
+ * Create a workspace
111
+ *
112
+ * Create a workspace in a virtual data plane. The parent virtual data plane is identified by
113
+ * the `virtual_dataplane_id` path parameter alone; the `x-hh-dataplane-id` header does not
114
+ * participate. Your organization's virtual data plane ids are listed on the API keys page of
115
+ * your organization settings in the HoneyHive app. Most organizations have exactly one.
116
+ *
117
+ * The new workspace contains no projects. Create one with
118
+ * `POST /v1/workspaces/{workspace_id}/projects` if you need it, because a workspace with no
119
+ * projects has nowhere to log events.
120
+ *
121
+ * The optional `workspace_creator` field names the user (by email) who receives the
122
+ * workspace-creator membership on the new workspace. The named user must already be a member
123
+ * of the virtual data plane. When omitted, the workspace is created without any membership.
124
+ * The field is only accepted on API-key-initiated requests. User-initiated creation always
125
+ * makes the calling user the creator, so sending the field returns a 400.
126
+ *
127
+ * The roles that membership carries come from your organization's role configuration. An
128
+ * organization that grants no role on workspace creation is a supported case: the request
129
+ * still succeeds and the named user receives no access. A 200 response is not by itself
130
+ * confirmation that the named user was granted anything.
131
+ *
132
+ * A `workspace_creator` who is already signed in does not see the new workspace immediately.
133
+ * A session captures its scope tree and permission grants when it is created, so a membership
134
+ * granted afterwards is not reflected in it. Creating the workspace marks that user's sessions
135
+ * for refresh, and the refresh takes effect on their next request to the control plane, so an
136
+ * idle browser tab may need a page reload.
137
+ */
138
+ public create(
139
+ request: CreateWorkspaceRequest,
140
+ options?: FetchOptions,
141
+ ): Promise<CreateWorkspaceResponse> {
142
+ const { virtual_dataplane_id, ...body } = request;
143
+ return unwrap(
144
+ this.#client.POST('/v1/virtual_dataplanes/{virtual_dataplane_id}/workspaces', {
145
+ params: { path: { virtual_dataplane_id } },
146
+ body,
147
+ ...options,
148
+ }),
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Get a workspace
154
+ *
155
+ * Retrieve a single workspace by id. The workspace is identified by the `workspace_id` path
156
+ * parameter alone; the `x-hh-workspace-id` header does not participate.
157
+ *
158
+ * The returned `name` is the workspace's display name. The globally unique slug the workspace
159
+ * was assigned at creation is an internal detail and is not part of this contract.
160
+ */
161
+ public get(request: GetWorkspaceRequest, options?: FetchOptions): Promise<GetWorkspaceResponse> {
162
+ const { workspace_id } = request;
163
+ return unwrap(
164
+ this.#client.GET('/v1/workspaces/{workspace_id}', {
165
+ params: { path: { workspace_id } },
166
+ ...options,
167
+ }),
168
+ );
169
+ }
170
+
171
+ /**
172
+ * Update a workspace
173
+ *
174
+ * Update a workspace's display name and/or description. The workspace is identified by the
175
+ * `workspace_id` path parameter alone; the `x-hh-workspace-id` header does not participate.
176
+ * Only fields included in the request body are modified.
177
+ *
178
+ * The workspace's internal slug is not part of this contract and cannot be changed here.
179
+ */
180
+ public update(
181
+ request: UpdateWorkspaceRequest,
182
+ options?: FetchOptions,
183
+ ): Promise<UpdateWorkspaceResponse> {
184
+ const { workspace_id, ...body } = request;
185
+ return unwrap(
186
+ this.#client.PUT('/v1/workspaces/{workspace_id}', {
187
+ params: { path: { workspace_id } },
188
+ body,
189
+ ...options,
190
+ }),
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Delete a workspace
196
+ *
197
+ * Delete a workspace. The workspace is soft-deleted (archived) and no longer appears in reads;
198
+ * the response returns the archived workspace. The workspace is identified by the
199
+ * `workspace_id` path parameter alone; the `x-hh-workspace-id` header does not participate.
200
+ *
201
+ * **Deleting a workspace also archives every project inside it**, so the events, datasets,
202
+ * and evaluations in those projects are no longer reachable. Because that reaches well
203
+ * beyond the resource named in the URL, a workspace that still has active projects is
204
+ * rejected with a 409 unless the request sets `dangerously_delete_child_scopes=true`.
205
+ * Projects that were already archived do not count, so a workspace emptied one project at a
206
+ * time deletes without the flag.
207
+ *
208
+ * The response describes only the workspace. It does not enumerate the projects archived
209
+ * alongside it, so read them first if you need that list.
210
+ */
211
+ public delete(
212
+ request: DeleteWorkspaceRequest,
213
+ options?: FetchOptions,
214
+ ): Promise<DeleteWorkspaceResponse> {
215
+ const { workspace_id, dangerously_delete_child_scopes } = request;
216
+ return unwrap(
217
+ this.#client.DELETE('/v1/workspaces/{workspace_id}', {
218
+ params: { path: { workspace_id }, query: { dangerously_delete_child_scopes } },
219
+ ...options,
220
+ }),
221
+ );
222
+ }
223
+ }
224
+
85
225
  /** @inline */
86
226
  class ProjectsNamespace {
87
227
  #client: ReturnType<typeof createApiClient<paths>>;
@@ -94,13 +234,25 @@ class ProjectsNamespace {
94
234
  * Create a project
95
235
  *
96
236
  * Create a project in a workspace. The parent workspace is identified by the `workspace_id`
97
- * path parameter alone; the `x-hh-workspace-id` header does not participate.
237
+ * path parameter alone; the `x-hh-workspace-id` header does not participate. A workspace's id
238
+ * is listed on the API keys page of its workspace settings in the HoneyHive app.
98
239
  *
99
240
  * The optional `project_creator` field names the user (by email) who receives the
100
241
  * project-creator membership on the new project. The named user must already be a member of
101
242
  * the workspace. When omitted, the project is created without any membership. The field is
102
- * only accepted on API-key-initiated requests — user-initiated creation always makes the
103
- * calling user the creator and rejects the field with a 400.
243
+ * only accepted on API-key-initiated requests. User-initiated creation always makes the
244
+ * calling user the creator, so sending the field returns a 400.
245
+ *
246
+ * The roles that membership carries come from your organization's role configuration. An
247
+ * organization that grants no role on project creation is a supported case: the request
248
+ * still succeeds and the named user receives no access. A 200 response is not by itself
249
+ * confirmation that the named user was granted anything.
250
+ *
251
+ * A `project_creator` who is already signed in does not see the new project immediately. A
252
+ * session captures its scope tree and permission grants when it is created, so a membership
253
+ * granted afterwards is not reflected in it. Creating the project marks that user's sessions
254
+ * for refresh, and the refresh takes effect on their next request to the control plane, so
255
+ * an idle browser tab may need a page reload.
104
256
  */
105
257
  public create(
106
258
  request: CreateProjectRequest,
@@ -174,14 +326,175 @@ class ProjectsNamespace {
174
326
  }
175
327
  }
176
328
 
329
+ /** @inline */
330
+ class VirtualDataplanesNamespace {
331
+ #client: ReturnType<typeof createApiClient<paths>>;
332
+
333
+ constructor(client: ReturnType<typeof createApiClient<paths>>) {
334
+ this.#client = client;
335
+ }
336
+
337
+ /**
338
+ * Create a virtual data plane
339
+ *
340
+ * Create a virtual data plane in an organization. The parent organization is identified by the
341
+ * `org_id` path parameter alone; the `x-hh-org-id` header does not participate. Your
342
+ * organization's id is listed on the API keys page of your organization settings in the
343
+ * HoneyHive app.
344
+ *
345
+ * A virtual data plane is a logical tenant boundary hosted on a physical cluster, and several
346
+ * of them commonly share one cluster. Workspaces are created inside it.
347
+ *
348
+ * `cluster_id` is optional, and omitting it is the common case: the new virtual data plane is
349
+ * placed on the same cluster as the organization's existing ones. Two situations require it
350
+ * explicitly, and both return a 400 that says so rather than guessing: an organization whose
351
+ * existing virtual data planes span more than one cluster, and an organization that has none
352
+ * yet. Every response includes `cluster_id`, so reading an existing virtual data plane tells
353
+ * you which value to send.
354
+ *
355
+ * A cluster admits an organization only if your control plane administrator configured it to,
356
+ * so a `cluster_id` you can read from a sibling virtual data plane is not necessarily one you
357
+ * may place a new virtual data plane on. A cluster that does not admit this organization
358
+ * returns a 403. When you named the cluster, the fix is a configuration change your
359
+ * administrator makes. When this endpoint inferred the cluster, send an explicit `cluster_id`
360
+ * to place the virtual data plane on another cluster.
361
+ *
362
+ * Deployments differ in who places virtual data planes. Where HoneyHive assigns them to
363
+ * organizations automatically, this endpoint returns a 403 for every request and the
364
+ * placement is not yours to make. Deployments whose administrators own the scope tree are
365
+ * the ones this endpoint serves.
366
+ *
367
+ * The optional `dataplane_creator` field names the user (by email) who receives the
368
+ * dataplane-creator membership on the new virtual data plane. The named user must already be a
369
+ * member of the organization. When omitted, it is created without any membership. The field is
370
+ * only accepted on API-key-initiated requests; user-initiated creation always makes the
371
+ * calling user the creator, so sending the field returns a 400.
372
+ *
373
+ * The roles that membership carries come from your organization's role configuration. An
374
+ * organization that grants no role on dataplane creation is a supported case: the request
375
+ * still succeeds and the named user receives no access. A 200 response is not by itself
376
+ * confirmation that the named user was granted anything.
377
+ *
378
+ * A `dataplane_creator` who is already signed in does not see the new virtual data plane
379
+ * immediately. A session captures its scope tree and permission grants when it is created, so
380
+ * a membership granted afterwards is not reflected in it; the refresh takes effect on their
381
+ * next request to the control plane.
382
+ */
383
+ public create(
384
+ request: CreateVirtualDataplaneRequest,
385
+ options?: FetchOptions,
386
+ ): Promise<CreateVirtualDataplaneResponse> {
387
+ const { org_id, ...body } = request;
388
+ return unwrap(
389
+ this.#client.POST('/v1/orgs/{org_id}/virtual_dataplanes', {
390
+ params: { path: { org_id } },
391
+ body,
392
+ ...options,
393
+ }),
394
+ );
395
+ }
396
+
397
+ /**
398
+ * Get a virtual data plane
399
+ *
400
+ * Retrieve a single virtual data plane by id. It is identified by the `virtual_dataplane_id`
401
+ * path parameter alone; the `x-hh-dataplane-id` header does not participate.
402
+ *
403
+ * The returned `name` is the display name. The globally unique slug assigned at creation is
404
+ * an internal detail and is not part of this contract. `cluster_id` is the physical cluster
405
+ * hosting this virtual data plane, and it is the value to send when creating another one
406
+ * beside it.
407
+ *
408
+ * Reads work on every deployment, including those where HoneyHive assigns virtual data
409
+ * planes automatically and the write endpoints are unavailable.
410
+ */
411
+ public get(
412
+ request: GetVirtualDataplaneRequest,
413
+ options?: FetchOptions,
414
+ ): Promise<GetVirtualDataplaneResponse> {
415
+ const { virtual_dataplane_id } = request;
416
+ return unwrap(
417
+ this.#client.GET('/v1/virtual_dataplanes/{virtual_dataplane_id}', {
418
+ params: { path: { virtual_dataplane_id } },
419
+ ...options,
420
+ }),
421
+ );
422
+ }
423
+
424
+ /**
425
+ * Update a virtual data plane
426
+ *
427
+ * Update a virtual data plane's display name. It is identified by the `virtual_dataplane_id`
428
+ * path parameter alone; the `x-hh-dataplane-id` header does not participate.
429
+ *
430
+ * `name` is the only field this endpoint changes. `cluster_id` is placement rather than
431
+ * description: the workspaces and projects inside a virtual data plane hold data on the
432
+ * cluster hosting it, so moving one is a migration and not an update. A request that omits
433
+ * `name`, or sends the current one, changes nothing.
434
+ *
435
+ * This endpoint is unavailable where HoneyHive assigns virtual data planes automatically,
436
+ * and returns a 403 there.
437
+ */
438
+ public update(
439
+ request: UpdateVirtualDataplaneRequest,
440
+ options?: FetchOptions,
441
+ ): Promise<UpdateVirtualDataplaneResponse> {
442
+ const { virtual_dataplane_id, ...body } = request;
443
+ return unwrap(
444
+ this.#client.PUT('/v1/virtual_dataplanes/{virtual_dataplane_id}', {
445
+ params: { path: { virtual_dataplane_id } },
446
+ body,
447
+ ...options,
448
+ }),
449
+ );
450
+ }
451
+
452
+ /**
453
+ * Delete a virtual data plane
454
+ *
455
+ * Delete a virtual data plane. It is soft-deleted (archived) and no longer appears in reads;
456
+ * the response returns the archived virtual data plane. It is identified by the
457
+ * `virtual_dataplane_id` path parameter alone; the `x-hh-dataplane-id` header does not
458
+ * participate.
459
+ *
460
+ * **Deleting a virtual data plane also archives every workspace inside it and every project
461
+ * inside those workspaces**, so the events, datasets, and evaluations in them are no longer
462
+ * reachable. Because that reaches two levels below the resource named in the URL, a virtual
463
+ * data plane with active workspaces is rejected with a 409 unless the request sets
464
+ * `dangerously_delete_child_scopes=true`. Workspaces that were already archived do not count.
465
+ *
466
+ * The response describes only the virtual data plane. It does not enumerate what the cascade
467
+ * archived, so read that first if you need the list.
468
+ *
469
+ * This endpoint is unavailable where HoneyHive assigns virtual data planes automatically,
470
+ * and returns a 403 there.
471
+ */
472
+ public delete(
473
+ request: DeleteVirtualDataplaneRequest,
474
+ options?: FetchOptions,
475
+ ): Promise<DeleteVirtualDataplaneResponse> {
476
+ const { virtual_dataplane_id, dangerously_delete_child_scopes } = request;
477
+ return unwrap(
478
+ this.#client.DELETE('/v1/virtual_dataplanes/{virtual_dataplane_id}', {
479
+ params: { path: { virtual_dataplane_id }, query: { dangerously_delete_child_scopes } },
480
+ ...options,
481
+ }),
482
+ );
483
+ }
484
+ }
485
+
177
486
  export class Client {
178
487
  #client: ReturnType<typeof createApiClient<paths>>;
179
488
  readonly alerts: AlertsNamespace;
489
+ readonly workspaces: WorkspacesNamespace;
180
490
  readonly projects: ProjectsNamespace;
491
+ readonly virtualDataplanes: VirtualDataplanesNamespace;
181
492
 
182
493
  constructor(options: ClientConfig = {}) {
183
494
  this.#client = createApiClient<paths>(options);
184
495
  this.alerts = new AlertsNamespace(this.#client);
496
+ this.workspaces = new WorkspacesNamespace(this.#client);
185
497
  this.projects = new ProjectsNamespace(this.#client);
498
+ this.virtualDataplanes = new VirtualDataplanesNamespace(this.#client);
186
499
  }
187
500
  }