@miosa/sdk 1.1.0 → 1.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.
@@ -0,0 +1,528 @@
1
+ /**
2
+ * Phase 6 governance resources — policy, members, workspaces, bulk ops,
3
+ * billing, impersonation, and scoped API keys.
4
+ */
5
+
6
+ import type { HttpClient } from "../http.js";
7
+
8
+ // ── Types ──────────────────────────────────────────────────────────────────────
9
+
10
+ export type PolicyDoc = Record<string, unknown>;
11
+
12
+ export interface BulkJobResponse {
13
+ queued: number;
14
+ job_id: string;
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ export interface BulkJobStatus {
19
+ id: string;
20
+ status: "queued" | "running" | "completed" | "failed";
21
+ processed?: number;
22
+ errors?: unknown[];
23
+ [key: string]: unknown;
24
+ }
25
+
26
+ export interface MemberRecord {
27
+ id: string;
28
+ email?: string;
29
+ role: string;
30
+ [key: string]: unknown;
31
+ }
32
+
33
+ export interface Invoice {
34
+ id: string;
35
+ amount: number;
36
+ [key: string]: unknown;
37
+ }
38
+
39
+ export interface PaymentMethod {
40
+ id: string;
41
+ brand: string;
42
+ last4: string;
43
+ [key: string]: unknown;
44
+ }
45
+
46
+ // ── Effective policy typed accessors ─────────────────────────────────────────
47
+
48
+ export interface EffectivePolicyField<T = unknown> {
49
+ value: T;
50
+ source: "user" | "workspace" | "tenant" | "platform";
51
+ }
52
+
53
+ export interface EffectiveLifecycle {
54
+ default_idle_timeout_sec?: EffectivePolicyField<number>;
55
+ default_timeout_sec?: EffectivePolicyField<number>;
56
+ default_always_on?: EffectivePolicyField<boolean>;
57
+ [key: string]: EffectivePolicyField | undefined;
58
+ }
59
+
60
+ export interface EffectiveQuotas {
61
+ max_sandboxes?: EffectivePolicyField<number>;
62
+ max_concurrent_sandboxes?: EffectivePolicyField<number>;
63
+ max_computers?: EffectivePolicyField<number>;
64
+ [key: string]: EffectivePolicyField | undefined;
65
+ }
66
+
67
+ export interface EffectivePolicyDoc {
68
+ lifecycle: Record<string, EffectivePolicyField>;
69
+ quotas: Record<string, EffectivePolicyField>;
70
+ sizing?: Record<string, EffectivePolicyField>;
71
+ features?: Record<string, EffectivePolicyField>;
72
+ egress?: Record<string, EffectivePolicyField>;
73
+ [key: string]: Record<string, EffectivePolicyField> | undefined;
74
+ }
75
+
76
+ // ── Policy sub-resources ──────────────────────────────────────────────────────
77
+
78
+ export class TenantPolicy {
79
+ constructor(private readonly http: HttpClient) {}
80
+
81
+ async get(): Promise<PolicyDoc> {
82
+ const r = await this.http.get<{ data?: PolicyDoc }>("/tenant/policy");
83
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
84
+ }
85
+
86
+ async set(policy: PolicyDoc): Promise<PolicyDoc> {
87
+ const r = await this.http.put<{ data?: PolicyDoc }>(
88
+ "/tenant/policy",
89
+ policy,
90
+ );
91
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
92
+ }
93
+
94
+ async delete(): Promise<void> {
95
+ await this.http.delete<unknown>("/tenant/policy");
96
+ }
97
+ }
98
+
99
+ export class WorkspacePolicyResource {
100
+ constructor(
101
+ private readonly http: HttpClient,
102
+ private readonly workspaceId: string,
103
+ ) {}
104
+
105
+ async get(): Promise<PolicyDoc> {
106
+ const r = await this.http.get<{ data?: PolicyDoc }>(
107
+ `/workspaces/${this.workspaceId}/policy`,
108
+ );
109
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
110
+ }
111
+
112
+ async set(policy: PolicyDoc): Promise<PolicyDoc> {
113
+ const r = await this.http.put<{ data?: PolicyDoc }>(
114
+ `/workspaces/${this.workspaceId}/policy`,
115
+ policy,
116
+ );
117
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
118
+ }
119
+
120
+ async delete(): Promise<void> {
121
+ await this.http.delete<unknown>(`/workspaces/${this.workspaceId}/policy`);
122
+ }
123
+ }
124
+
125
+ export class ExternalUserPolicyResource {
126
+ constructor(
127
+ private readonly http: HttpClient,
128
+ private readonly userId: string,
129
+ ) {}
130
+
131
+ async get(): Promise<PolicyDoc> {
132
+ const r = await this.http.get<{ data?: PolicyDoc }>(
133
+ `/external-users/${this.userId}/policy`,
134
+ );
135
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
136
+ }
137
+
138
+ async set(policy: PolicyDoc): Promise<PolicyDoc> {
139
+ const r = await this.http.put<{ data?: PolicyDoc }>(
140
+ `/external-users/${this.userId}/policy`,
141
+ policy,
142
+ );
143
+ return (r as { data?: PolicyDoc }).data ?? (r as PolicyDoc);
144
+ }
145
+
146
+ async delete(): Promise<void> {
147
+ await this.http.delete<unknown>(`/external-users/${this.userId}/policy`);
148
+ }
149
+
150
+ async effective(): Promise<EffectivePolicyDoc> {
151
+ const r = await this.http.get<unknown>(
152
+ `/external-users/${this.userId}/effective-policy`,
153
+ );
154
+ const data =
155
+ (r as { data?: EffectivePolicyDoc }).data ?? (r as EffectivePolicyDoc);
156
+ return data as EffectivePolicyDoc;
157
+ }
158
+ }
159
+
160
+ // ── ExternalUsers proxy ───────────────────────────────────────────────────────
161
+
162
+ export class ExternalUserProxy {
163
+ readonly policy: ExternalUserPolicyResource;
164
+
165
+ constructor(http: HttpClient, userId: string) {
166
+ this.policy = new ExternalUserPolicyResource(http, userId);
167
+ }
168
+ }
169
+
170
+ export class ExternalUsers {
171
+ constructor(private readonly http: HttpClient) {}
172
+
173
+ call(externalUserId: string): ExternalUserProxy {
174
+ return new ExternalUserProxy(this.http, externalUserId);
175
+ }
176
+ }
177
+
178
+ // ── Tenant members ─────────────────────────────────────────────────────────────
179
+
180
+ export class TenantMembersResource {
181
+ constructor(private readonly http: HttpClient) {}
182
+
183
+ async list(): Promise<MemberRecord[]> {
184
+ const r = await this.http.get<{ data?: MemberRecord[] }>("/tenant/members");
185
+ return (r as { data?: MemberRecord[] }).data ?? (r as MemberRecord[]) ?? [];
186
+ }
187
+
188
+ async invite(email: string, role: string): Promise<MemberRecord> {
189
+ const r = await this.http.post<{ data?: MemberRecord }>("/tenant/members", {
190
+ email,
191
+ role,
192
+ });
193
+ return (r as { data?: MemberRecord }).data ?? (r as MemberRecord);
194
+ }
195
+
196
+ async updateRole(memberId: string, role: string): Promise<MemberRecord> {
197
+ const r = await this.http.patch<{ data?: MemberRecord }>(
198
+ `/tenant/members/${memberId}/role`,
199
+ { role },
200
+ );
201
+ return (r as { data?: MemberRecord }).data ?? (r as MemberRecord);
202
+ }
203
+
204
+ async remove(memberId: string): Promise<void> {
205
+ await this.http.delete<unknown>(`/tenant/members/${memberId}`);
206
+ }
207
+
208
+ async transferOwnership(
209
+ newOwnerUserId: string,
210
+ ): Promise<Record<string, unknown>> {
211
+ const r = await this.http.post<{ data?: Record<string, unknown> }>(
212
+ "/tenant/transfer-ownership",
213
+ { new_owner_user_id: newOwnerUserId },
214
+ );
215
+ return (
216
+ (r as { data?: Record<string, unknown> }).data ??
217
+ (r as Record<string, unknown>)
218
+ );
219
+ }
220
+ }
221
+
222
+ // ── Tenant events ─────────────────────────────────────────────────────────────
223
+
224
+ export interface AdminStreamEvent {
225
+ _event_type?: string;
226
+ [key: string]: unknown;
227
+ }
228
+
229
+ export class TenantEventStreamResource {
230
+ constructor(private readonly http: HttpClient) {}
231
+
232
+ stream(options?: {
233
+ types?: string[];
234
+ scope?: string;
235
+ }): AsyncIterableIterator<AdminStreamEvent> {
236
+ const params = new URLSearchParams();
237
+ if (options?.types?.length) params.set("types", options.types.join(","));
238
+ if (options?.scope) params.set("scope", options.scope);
239
+ const qs = params.toString() ? `?${params.toString()}` : "";
240
+ return this.http.stream<AdminStreamEvent>(`/tenant/events/stream${qs}`);
241
+ }
242
+ }
243
+
244
+ // ── GovernanceTenant ──────────────────────────────────────────────────────────
245
+
246
+ export class GovernanceTenant {
247
+ readonly policy: TenantPolicy;
248
+ readonly members: TenantMembersResource;
249
+ readonly events: TenantEventStreamResource;
250
+
251
+ constructor(http: HttpClient) {
252
+ this.policy = new TenantPolicy(http);
253
+ this.members = new TenantMembersResource(http);
254
+ this.events = new TenantEventStreamResource(http);
255
+ }
256
+
257
+ async current(): Promise<Record<string, unknown>> {
258
+ return (await this.policy["http" as never]) as never;
259
+ }
260
+ }
261
+
262
+ // ── Workspace sub-resources ────────────────────────────────────────────────────
263
+
264
+ export class WorkspaceMembersResource {
265
+ constructor(
266
+ private readonly http: HttpClient,
267
+ private readonly workspaceId: string,
268
+ ) {}
269
+
270
+ async list(): Promise<MemberRecord[]> {
271
+ const r = await this.http.get<{ data?: MemberRecord[] }>(
272
+ `/workspaces/${this.workspaceId}/members`,
273
+ );
274
+ return (r as { data?: MemberRecord[] }).data ?? (r as MemberRecord[]) ?? [];
275
+ }
276
+
277
+ async invite(email: string, role: string): Promise<MemberRecord> {
278
+ const r = await this.http.post<{ data?: MemberRecord }>(
279
+ `/workspaces/${this.workspaceId}/members`,
280
+ { email, role },
281
+ );
282
+ return (r as { data?: MemberRecord }).data ?? (r as MemberRecord);
283
+ }
284
+
285
+ async updateRole(memberId: string, role: string): Promise<MemberRecord> {
286
+ const r = await this.http.patch<{ data?: MemberRecord }>(
287
+ `/workspaces/${this.workspaceId}/members/${memberId}/role`,
288
+ { role },
289
+ );
290
+ return (r as { data?: MemberRecord }).data ?? (r as MemberRecord);
291
+ }
292
+
293
+ async remove(memberId: string): Promise<void> {
294
+ await this.http.delete<unknown>(
295
+ `/workspaces/${this.workspaceId}/members/${memberId}`,
296
+ );
297
+ }
298
+ }
299
+
300
+ export class WorkspaceProxy {
301
+ readonly policy: WorkspacePolicyResource;
302
+ readonly members: WorkspaceMembersResource;
303
+
304
+ constructor(
305
+ private readonly http: HttpClient,
306
+ private readonly workspaceId: string,
307
+ ) {
308
+ this.policy = new WorkspacePolicyResource(http, workspaceId);
309
+ this.members = new WorkspaceMembersResource(http, workspaceId);
310
+ }
311
+
312
+ async transfer(
313
+ resourceIds: string[],
314
+ targetWorkspaceId: string,
315
+ ): Promise<Record<string, unknown>> {
316
+ const r = await this.http.post<{ data?: Record<string, unknown> }>(
317
+ `/workspaces/${this.workspaceId}/transfer`,
318
+ { resource_ids: resourceIds, target_workspace_id: targetWorkspaceId },
319
+ );
320
+ return (
321
+ (r as { data?: Record<string, unknown> }).data ??
322
+ (r as Record<string, unknown>)
323
+ );
324
+ }
325
+ }
326
+
327
+ // ── GovernanceWorkspaces ──────────────────────────────────────────────────────
328
+
329
+ export class GovernanceWorkspaces {
330
+ constructor(private readonly http: HttpClient) {}
331
+
332
+ /** client.workspaces("ws_id") → proxy with .policy, .members, .transfer() */
333
+ workspace(workspaceId: string): WorkspaceProxy {
334
+ return new WorkspaceProxy(this.http, workspaceId);
335
+ }
336
+
337
+ async list(): Promise<Record<string, unknown>[]> {
338
+ const r = await this.http.get<{ data?: Record<string, unknown>[] }>(
339
+ "/workspaces",
340
+ );
341
+ const items =
342
+ (r as { data?: Record<string, unknown>[] }).data ??
343
+ (r as Record<string, unknown>[]);
344
+ return Array.isArray(items) ? items : [];
345
+ }
346
+
347
+ async create(
348
+ name: string,
349
+ opts?: { description?: string; metadata?: Record<string, unknown> },
350
+ ): Promise<Record<string, unknown>> {
351
+ const r = await this.http.post<{ data?: Record<string, unknown> }>(
352
+ "/workspaces",
353
+ { name, ...opts },
354
+ );
355
+ return (
356
+ (r as { data?: Record<string, unknown> }).data ??
357
+ (r as Record<string, unknown>)
358
+ );
359
+ }
360
+
361
+ async get(workspaceId: string): Promise<Record<string, unknown>> {
362
+ const r = await this.http.get<{ data?: Record<string, unknown> }>(
363
+ `/workspaces/${workspaceId}`,
364
+ );
365
+ return (
366
+ (r as { data?: Record<string, unknown> }).data ??
367
+ (r as Record<string, unknown>)
368
+ );
369
+ }
370
+
371
+ async update(
372
+ workspaceId: string,
373
+ fields: Record<string, unknown>,
374
+ ): Promise<Record<string, unknown>> {
375
+ const r = await this.http.patch<{ data?: Record<string, unknown> }>(
376
+ `/workspaces/${workspaceId}`,
377
+ fields,
378
+ );
379
+ return (
380
+ (r as { data?: Record<string, unknown> }).data ??
381
+ (r as Record<string, unknown>)
382
+ );
383
+ }
384
+
385
+ async delete(workspaceId: string): Promise<void> {
386
+ await this.http.delete<unknown>(`/workspaces/${workspaceId}`);
387
+ }
388
+ }
389
+
390
+ // ── Bulk ops ──────────────────────────────────────────────────────────────────
391
+
392
+ function bulkBody(opts: {
393
+ ids?: string[];
394
+ filter?: Record<string, unknown>;
395
+ }): Record<string, unknown> {
396
+ if (opts.ids !== undefined) return { ids: opts.ids };
397
+ if (opts.filter !== undefined) return { filter: opts.filter };
398
+ throw new Error("Provide either ids or filter");
399
+ }
400
+
401
+ export class BulkSandboxesResource {
402
+ constructor(private readonly http: HttpClient) {}
403
+
404
+ async pause(opts: {
405
+ ids?: string[];
406
+ filter?: Record<string, unknown>;
407
+ }): Promise<BulkJobResponse> {
408
+ return this.http.post<BulkJobResponse>(
409
+ "/bulk/sandboxes/pause",
410
+ bulkBody(opts),
411
+ );
412
+ }
413
+
414
+ async resume(opts: {
415
+ ids?: string[];
416
+ filter?: Record<string, unknown>;
417
+ }): Promise<BulkJobResponse> {
418
+ return this.http.post<BulkJobResponse>(
419
+ "/bulk/sandboxes/resume",
420
+ bulkBody(opts),
421
+ );
422
+ }
423
+
424
+ async destroy(opts: {
425
+ ids?: string[];
426
+ filter?: Record<string, unknown>;
427
+ }): Promise<BulkJobResponse> {
428
+ return this.http.post<BulkJobResponse>(
429
+ "/bulk/sandboxes/destroy",
430
+ bulkBody(opts),
431
+ );
432
+ }
433
+ }
434
+
435
+ export class BulkPolicyResource {
436
+ constructor(private readonly http: HttpClient) {}
437
+
438
+ async apply(opts: {
439
+ tier: string;
440
+ idsOrFilter: string[] | Record<string, unknown>;
441
+ policy: PolicyDoc;
442
+ }): Promise<BulkJobResponse> {
443
+ const body: Record<string, unknown> = {
444
+ tier: opts.tier,
445
+ policy: opts.policy,
446
+ };
447
+ if (Array.isArray(opts.idsOrFilter)) {
448
+ body["ids"] = opts.idsOrFilter;
449
+ } else {
450
+ body["filter"] = opts.idsOrFilter;
451
+ }
452
+ return this.http.post<BulkJobResponse>("/bulk/policy/apply", body);
453
+ }
454
+ }
455
+
456
+ export class BulkJobsResource {
457
+ constructor(private readonly http: HttpClient) {}
458
+
459
+ async get(jobId: string): Promise<BulkJobStatus> {
460
+ const r = await this.http.get<{ data?: BulkJobStatus }>(
461
+ `/bulk/jobs/${jobId}`,
462
+ );
463
+ return (r as { data?: BulkJobStatus }).data ?? (r as BulkJobStatus);
464
+ }
465
+ }
466
+
467
+ export class BulkResource {
468
+ readonly sandboxes: BulkSandboxesResource;
469
+ readonly policy: BulkPolicyResource;
470
+ readonly jobs: BulkJobsResource;
471
+
472
+ constructor(http: HttpClient) {
473
+ this.sandboxes = new BulkSandboxesResource(http);
474
+ this.policy = new BulkPolicyResource(http);
475
+ this.jobs = new BulkJobsResource(http);
476
+ }
477
+ }
478
+
479
+ // ── Billing ───────────────────────────────────────────────────────────────────
480
+
481
+ export class BillingInvoicesResource {
482
+ constructor(private readonly http: HttpClient) {}
483
+
484
+ async list(opts?: { limit?: number; cursor?: string }): Promise<Invoice[]> {
485
+ const params = new URLSearchParams();
486
+ if (opts?.limit !== undefined) params.set("limit", String(opts.limit));
487
+ if (opts?.cursor) params.set("cursor", opts.cursor);
488
+ const qs = params.toString() ? `?${params.toString()}` : "";
489
+ const r = await this.http.get<{ data?: Invoice[] }>(
490
+ `/billing/invoices${qs}`,
491
+ );
492
+ return (r as { data?: Invoice[] }).data ?? (r as Invoice[]) ?? [];
493
+ }
494
+
495
+ async get(invoiceId: string): Promise<Invoice> {
496
+ const r = await this.http.get<{ data?: Invoice }>(
497
+ `/billing/invoices/${invoiceId}`,
498
+ );
499
+ return (r as { data?: Invoice }).data ?? (r as Invoice);
500
+ }
501
+ }
502
+
503
+ export class BillingResource {
504
+ readonly invoices: BillingInvoicesResource;
505
+
506
+ constructor(private readonly http: HttpClient) {
507
+ this.invoices = new BillingInvoicesResource(http);
508
+ }
509
+
510
+ async paymentMethods(): Promise<PaymentMethod[]> {
511
+ const r = await this.http.get<{ data?: PaymentMethod[] }>(
512
+ "/billing/payment-methods",
513
+ );
514
+ return (
515
+ (r as { data?: PaymentMethod[] }).data ?? (r as PaymentMethod[]) ?? []
516
+ );
517
+ }
518
+
519
+ async upcoming(): Promise<Record<string, unknown>> {
520
+ const r = await this.http.get<{ data?: Record<string, unknown> }>(
521
+ "/billing/upcoming",
522
+ );
523
+ return (
524
+ (r as { data?: Record<string, unknown> }).data ??
525
+ (r as Record<string, unknown>)
526
+ );
527
+ }
528
+ }
@@ -49,13 +49,6 @@ export interface BucketCreateParams {
49
49
  visibility?: "private" | "public";
50
50
  quota_bytes?: number;
51
51
  public?: boolean;
52
- // White-label attribution
53
- externalWorkspaceId?: string;
54
- external_workspace_id?: string;
55
- externalUserId?: string;
56
- external_user_id?: string;
57
- externalProjectId?: string;
58
- external_project_id?: string;
59
52
  [key: string]: unknown;
60
53
  }
61
54
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tenant — current tenant info, preview domain, and branding.
2
+ * Tenant — current tenant info and plan/usage.
3
3
  */
4
4
 
5
5
  import type { HttpClient } from "../http.js";
@@ -14,101 +14,22 @@ export interface TenantPlan {
14
14
  [key: string]: unknown;
15
15
  }
16
16
 
17
- export interface PreviewDomainData {
18
- domain: string;
19
- verified_at?: string | null;
20
- cname_target?: string;
21
- [key: string]: unknown;
22
- }
23
-
24
- export interface PreviewDomainVerifyResult {
25
- verified: boolean;
26
- target?: string;
27
- records?: unknown[];
28
- [key: string]: unknown;
29
- }
30
-
31
- export interface BrandingData {
32
- product_name?: string;
33
- logo_url?: string;
34
- support_url?: string;
35
- support_email?: string;
36
- primary_color?: string;
37
- background_color?: string;
38
- [key: string]: unknown;
39
- }
40
-
41
17
  // ── Helpers ───────────────────────────────────────────────────────────────────
42
18
 
43
19
  function unwrap<T>(payload: unknown): T {
44
20
  if (payload && typeof payload === "object") {
45
21
  const p = payload as Record<string, unknown>;
46
- for (const k of ["data", "tenant", "branding", "preview_domain", "items"]) {
22
+ for (const k of ["data", "tenant", "items"]) {
47
23
  if (k in p) return p[k] as T;
48
24
  }
49
25
  }
50
26
  return payload as T;
51
27
  }
52
28
 
53
- // ── Sub-resources ─────────────────────────────────────────────────────────────
54
-
55
- export class PreviewDomain {
56
- constructor(private readonly http: HttpClient) {}
57
-
58
- /** GET /api/v1/tenant/preview-domain → {domain, verified_at, cname_target} */
59
- async get(): Promise<PreviewDomainData> {
60
- return unwrap(await this.http.get<unknown>("/tenant/preview-domain"));
61
- }
62
-
63
- /** PUT /api/v1/tenant/preview-domain — set the preview domain. */
64
- async set(domain: string): Promise<PreviewDomainData> {
65
- return unwrap(
66
- await this.http.put<unknown>("/tenant/preview-domain", { domain }),
67
- );
68
- }
69
-
70
- /** POST /api/v1/tenant/preview-domain/verify → {verified, target, records} */
71
- async verify(): Promise<PreviewDomainVerifyResult> {
72
- return unwrap(
73
- await this.http.post<unknown>("/tenant/preview-domain/verify", {}),
74
- );
75
- }
76
-
77
- /** DELETE /api/v1/tenant/preview-domain */
78
- async delete(): Promise<void> {
79
- await this.http.delete<unknown>("/tenant/preview-domain");
80
- }
81
- }
82
-
83
- export class Branding {
84
- constructor(private readonly http: HttpClient) {}
85
-
86
- /** GET /api/v1/tenant/branding */
87
- async get(): Promise<BrandingData> {
88
- return unwrap(await this.http.get<unknown>("/tenant/branding"));
89
- }
90
-
91
- /** PUT /api/v1/tenant/branding — keys: product_name, logo_url, support_url, support_email, primary_color, background_color */
92
- async set(branding: BrandingData): Promise<BrandingData> {
93
- return unwrap(await this.http.put<unknown>("/tenant/branding", branding));
94
- }
95
-
96
- /** DELETE /api/v1/tenant/branding */
97
- async delete(): Promise<void> {
98
- await this.http.delete<unknown>("/tenant/branding");
99
- }
100
- }
101
-
102
29
  // ── Main resource ─────────────────────────────────────────────────────────────
103
30
 
104
31
  export class Tenant {
105
- readonly preview_domain: PreviewDomain;
106
- readonly branding: Branding;
107
-
108
- constructor(private readonly http: HttpClient) {
109
- this.preview_domain = new PreviewDomain(http);
110
- this.branding = new Branding(http);
111
- }
32
+ constructor(private readonly http: HttpClient) {}
112
33
 
113
34
  /** Get the current tenant's plan, limits, and live usage counters. */
114
35
  async current(): Promise<TenantPlan> {
@@ -40,13 +40,6 @@ export interface VolumeCreateParams {
40
40
  sizeGb?: number;
41
41
  region?: string;
42
42
  idempotencyKey?: string;
43
- // White-label attribution
44
- externalWorkspaceId?: string;
45
- external_workspace_id?: string;
46
- externalUserId?: string;
47
- external_user_id?: string;
48
- externalProjectId?: string;
49
- external_project_id?: string;
50
43
  [key: string]: unknown;
51
44
  }
52
45