@sealant/sdk-next 0.40.0-next.769 → 0.40.0-next.771

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/client.d.ts CHANGED
@@ -1,6 +1,12 @@
1
+ import { type ScopesNamespace } from "./scopes.js";
1
2
  import type { AccessTokensNamespace, ConnectedAccountsNamespace, CreateOptions, InferenceNamespace, ListOptions, Run, SealantFeatures, SshKeysNamespace, Workspace, WorkspaceCreateState, WorkspaceImageInspection, WorkspaceSshNamespace, SealantConfig, UsersNamespace } from "./types.js";
2
3
  export declare class Sealant {
3
4
  #private;
5
+ /**
6
+ * Owners that are projects, not people: ensure one per project and name its members. With a
7
+ * service key; `actAs` gives a client for one scope that cannot reach a credential or a harness.
8
+ */
9
+ readonly scopes: ScopesNamespace;
4
10
  constructor(config: SealantConfig);
5
11
  /** The configured control-plane base URL. */
6
12
  get baseUrl(): string;
package/dist/client.js CHANGED
@@ -12,6 +12,7 @@ import { imageSpecKey } from "./internal/image-key.js";
12
12
  import { buildInferenceRespondRequest, mapInferenceResponse } from "./internal/inference.js";
13
13
  import { requireSshUser } from "./internal/process-user.js";
14
14
  import { mapSshKey, mapWorkspaceSshInfo } from "./internal/ssh.js";
15
+ import { makeScopes } from "./scopes.js";
15
16
  /** An idempotent create's state as the SDK reports it (an unknown wire state fails closed). */
16
17
  const toCreateState = (wire) => ({
17
18
  idempotencyKey: wire.idempotencyKey,
@@ -44,6 +45,11 @@ export class Sealant {
44
45
  #config;
45
46
  #runtime;
46
47
  #ctx;
48
+ /**
49
+ * Owners that are projects, not people: ensure one per project and name its members. With a
50
+ * service key; `actAs` gives a client for one scope that cannot reach a credential or a harness.
51
+ */
52
+ scopes;
47
53
  constructor(config) {
48
54
  if (config.baseUrl.trim().length === 0) {
49
55
  throw new SealantError("Sealant requires a non-empty `baseUrl`.", { code: "invalid_config" });
@@ -52,6 +58,7 @@ export class Sealant {
52
58
  this.#config = config;
53
59
  this.#runtime = makeSdkRuntime(internalConfig);
54
60
  this.#ctx = { runtime: this.#runtime, config: internalConfig };
61
+ this.scopes = makeScopes(this.#runtime);
55
62
  }
56
63
  /** The configured control-plane base URL. */
57
64
  get baseUrl() {
@@ -527,12 +527,13 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
527
527
  readonly resourceDomains: {
528
528
  readonly ensureResourceDomain: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"ensureResourceDomain", "POST", "/v1/resource-domains/", never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
529
529
  readonly key: import("effect/Schema").String;
530
+ readonly budget: import("effect/Schema").optional<import("effect/Schema").Struct<Record<"cpuMillicores" | "memoryBytes" | "storageBytes", import("effect/Schema").Int>>>;
530
531
  }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
531
532
  readonly resourceDomainId: import("effect/Schema").String;
532
533
  readonly key: import("effect/Schema").String;
533
534
  readonly createdAt: import("effect/Schema").String;
534
535
  readonly created: import("effect/Schema").Boolean;
535
- }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
536
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainBudgetDiffersError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
536
537
  readonly getResourceDomain: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomain", "GET", "/v1/resource-domains/:resourceDomainId", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
537
538
  readonly resourceDomainId: import("effect/Schema").String;
538
539
  }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
@@ -540,6 +541,106 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
540
541
  readonly key: import("effect/Schema").String;
541
542
  readonly createdAt: import("effect/Schema").String;
542
543
  }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
544
+ readonly getResourceDomainBudget: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomainBudget", "GET", "/v1/resource-domains/:resourceDomainId/budget", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
545
+ readonly resourceDomainId: import("effect/Schema").String;
546
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
547
+ readonly revision: import("effect/Schema").Int;
548
+ readonly storageBytes: import("effect/Schema").Struct<{
549
+ readonly limit: import("effect/Schema").Int;
550
+ readonly used: import("effect/Schema").Int;
551
+ readonly reserved: import("effect/Schema").Int;
552
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
553
+ readonly archived: import("effect/Schema").Int;
554
+ readonly protection: import("effect/Schema").Int;
555
+ }>;
556
+ readonly cpuMillicores: import("effect/Schema").Struct<{
557
+ readonly limit: import("effect/Schema").Int;
558
+ readonly used: import("effect/Schema").Int;
559
+ readonly reserved: import("effect/Schema").Int;
560
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
561
+ }>;
562
+ readonly memoryBytes: import("effect/Schema").Struct<{
563
+ readonly limit: import("effect/Schema").Int;
564
+ readonly used: import("effect/Schema").Int;
565
+ readonly reserved: import("effect/Schema").Int;
566
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
567
+ }>;
568
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
569
+ readonly getResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomainMember", "GET", "/v1/resource-domains/:resourceDomainId/members/:userId", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
570
+ readonly resourceDomainId: import("effect/Schema").String;
571
+ readonly userId: import("effect/Schema").String;
572
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
573
+ readonly userId: import("effect/Schema").String;
574
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
575
+ readonly version: import("effect/Schema").Int;
576
+ readonly updatedAt: import("effect/Schema").String;
577
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
578
+ readonly grantResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"grantResourceDomainMember", "POST", "/v1/resource-domains/:resourceDomainId/members/:userId/grant", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
579
+ readonly resourceDomainId: import("effect/Schema").String;
580
+ readonly userId: import("effect/Schema").String;
581
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
582
+ readonly version: import("effect/Schema").Int;
583
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
584
+ readonly userId: import("effect/Schema").String;
585
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
586
+ readonly version: import("effect/Schema").Int;
587
+ readonly updatedAt: import("effect/Schema").String;
588
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
589
+ readonly listResourceDomainMembers: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"listResourceDomainMembers", "GET", "/v1/resource-domains/:resourceDomainId/members", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
590
+ readonly resourceDomainId: import("effect/Schema").String;
591
+ }>>, import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
592
+ readonly limit: import("effect/Schema").optional<import("effect/Schema").FiniteFromString>;
593
+ readonly cursor: import("effect/Schema").optional<import("effect/Schema").String>;
594
+ }>>, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
595
+ readonly items: import("effect/Schema").$Array<import("effect/Schema").Struct<{
596
+ readonly userId: import("effect/Schema").String;
597
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
598
+ readonly version: import("effect/Schema").Int;
599
+ readonly updatedAt: import("effect/Schema").String;
600
+ }>>;
601
+ readonly nextCursor: import("effect/Schema").optional<import("effect/Schema").String>;
602
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
603
+ readonly revokeResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"revokeResourceDomainMember", "POST", "/v1/resource-domains/:resourceDomainId/members/:userId/revoke", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
604
+ readonly resourceDomainId: import("effect/Schema").String;
605
+ readonly userId: import("effect/Schema").String;
606
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
607
+ readonly version: import("effect/Schema").Int;
608
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
609
+ readonly userId: import("effect/Schema").String;
610
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
611
+ readonly version: import("effect/Schema").Int;
612
+ readonly updatedAt: import("effect/Schema").String;
613
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
614
+ readonly setResourceDomainBudget: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"setResourceDomainBudget", "PUT", "/v1/resource-domains/:resourceDomainId/budget", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
615
+ readonly resourceDomainId: import("effect/Schema").String;
616
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
617
+ readonly revision: import("effect/Schema").Int;
618
+ readonly cpuMillicores: import("effect/Schema").Int;
619
+ readonly memoryBytes: import("effect/Schema").Int;
620
+ readonly storageBytes: import("effect/Schema").Int;
621
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
622
+ readonly revision: import("effect/Schema").Int;
623
+ readonly storageBytes: import("effect/Schema").Struct<{
624
+ readonly limit: import("effect/Schema").Int;
625
+ readonly used: import("effect/Schema").Int;
626
+ readonly reserved: import("effect/Schema").Int;
627
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
628
+ readonly archived: import("effect/Schema").Int;
629
+ readonly protection: import("effect/Schema").Int;
630
+ }>;
631
+ readonly cpuMillicores: import("effect/Schema").Struct<{
632
+ readonly limit: import("effect/Schema").Int;
633
+ readonly used: import("effect/Schema").Int;
634
+ readonly reserved: import("effect/Schema").Int;
635
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
636
+ }>;
637
+ readonly memoryBytes: import("effect/Schema").Struct<{
638
+ readonly limit: import("effect/Schema").Int;
639
+ readonly used: import("effect/Schema").Int;
640
+ readonly reserved: import("effect/Schema").Int;
641
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
642
+ }>;
643
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainBudgetRevisionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
543
644
  };
544
645
  readonly runs: {
545
646
  readonly createRun: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"createRun", "POST", "/v1/runs/", never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
@@ -2489,12 +2590,13 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
2489
2590
  readonly resourceDomains: {
2490
2591
  readonly ensureResourceDomain: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"ensureResourceDomain", "POST", "/v1/resource-domains/", never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2491
2592
  readonly key: import("effect/Schema").String;
2593
+ readonly budget: import("effect/Schema").optional<import("effect/Schema").Struct<Record<"cpuMillicores" | "memoryBytes" | "storageBytes", import("effect/Schema").Int>>>;
2492
2594
  }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2493
2595
  readonly resourceDomainId: import("effect/Schema").String;
2494
2596
  readonly key: import("effect/Schema").String;
2495
2597
  readonly createdAt: import("effect/Schema").String;
2496
2598
  readonly created: import("effect/Schema").Boolean;
2497
- }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2599
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainBudgetDiffersError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2498
2600
  readonly getResourceDomain: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomain", "GET", "/v1/resource-domains/:resourceDomainId", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2499
2601
  readonly resourceDomainId: import("effect/Schema").String;
2500
2602
  }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
@@ -2502,6 +2604,106 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
2502
2604
  readonly key: import("effect/Schema").String;
2503
2605
  readonly createdAt: import("effect/Schema").String;
2504
2606
  }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2607
+ readonly getResourceDomainBudget: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomainBudget", "GET", "/v1/resource-domains/:resourceDomainId/budget", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2608
+ readonly resourceDomainId: import("effect/Schema").String;
2609
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2610
+ readonly revision: import("effect/Schema").Int;
2611
+ readonly storageBytes: import("effect/Schema").Struct<{
2612
+ readonly limit: import("effect/Schema").Int;
2613
+ readonly used: import("effect/Schema").Int;
2614
+ readonly reserved: import("effect/Schema").Int;
2615
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2616
+ readonly archived: import("effect/Schema").Int;
2617
+ readonly protection: import("effect/Schema").Int;
2618
+ }>;
2619
+ readonly cpuMillicores: import("effect/Schema").Struct<{
2620
+ readonly limit: import("effect/Schema").Int;
2621
+ readonly used: import("effect/Schema").Int;
2622
+ readonly reserved: import("effect/Schema").Int;
2623
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2624
+ }>;
2625
+ readonly memoryBytes: import("effect/Schema").Struct<{
2626
+ readonly limit: import("effect/Schema").Int;
2627
+ readonly used: import("effect/Schema").Int;
2628
+ readonly reserved: import("effect/Schema").Int;
2629
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2630
+ }>;
2631
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2632
+ readonly getResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"getResourceDomainMember", "GET", "/v1/resource-domains/:resourceDomainId/members/:userId", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2633
+ readonly resourceDomainId: import("effect/Schema").String;
2634
+ readonly userId: import("effect/Schema").String;
2635
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2636
+ readonly userId: import("effect/Schema").String;
2637
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2638
+ readonly version: import("effect/Schema").Int;
2639
+ readonly updatedAt: import("effect/Schema").String;
2640
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2641
+ readonly grantResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"grantResourceDomainMember", "POST", "/v1/resource-domains/:resourceDomainId/members/:userId/grant", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2642
+ readonly resourceDomainId: import("effect/Schema").String;
2643
+ readonly userId: import("effect/Schema").String;
2644
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2645
+ readonly version: import("effect/Schema").Int;
2646
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2647
+ readonly userId: import("effect/Schema").String;
2648
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2649
+ readonly version: import("effect/Schema").Int;
2650
+ readonly updatedAt: import("effect/Schema").String;
2651
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2652
+ readonly listResourceDomainMembers: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"listResourceDomainMembers", "GET", "/v1/resource-domains/:resourceDomainId/members", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2653
+ readonly resourceDomainId: import("effect/Schema").String;
2654
+ }>>, import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2655
+ readonly limit: import("effect/Schema").optional<import("effect/Schema").FiniteFromString>;
2656
+ readonly cursor: import("effect/Schema").optional<import("effect/Schema").String>;
2657
+ }>>, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2658
+ readonly items: import("effect/Schema").$Array<import("effect/Schema").Struct<{
2659
+ readonly userId: import("effect/Schema").String;
2660
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2661
+ readonly version: import("effect/Schema").Int;
2662
+ readonly updatedAt: import("effect/Schema").String;
2663
+ }>>;
2664
+ readonly nextCursor: import("effect/Schema").optional<import("effect/Schema").String>;
2665
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2666
+ readonly revokeResourceDomainMember: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"revokeResourceDomainMember", "POST", "/v1/resource-domains/:resourceDomainId/members/:userId/revoke", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2667
+ readonly resourceDomainId: import("effect/Schema").String;
2668
+ readonly userId: import("effect/Schema").String;
2669
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2670
+ readonly version: import("effect/Schema").Int;
2671
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2672
+ readonly userId: import("effect/Schema").String;
2673
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2674
+ readonly version: import("effect/Schema").Int;
2675
+ readonly updatedAt: import("effect/Schema").String;
2676
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2677
+ readonly setResourceDomainBudget: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"setResourceDomainBudget", "PUT", "/v1/resource-domains/:resourceDomainId/budget", import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2678
+ readonly resourceDomainId: import("effect/Schema").String;
2679
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2680
+ readonly revision: import("effect/Schema").Int;
2681
+ readonly cpuMillicores: import("effect/Schema").Int;
2682
+ readonly memoryBytes: import("effect/Schema").Int;
2683
+ readonly storageBytes: import("effect/Schema").Int;
2684
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2685
+ readonly revision: import("effect/Schema").Int;
2686
+ readonly storageBytes: import("effect/Schema").Struct<{
2687
+ readonly limit: import("effect/Schema").Int;
2688
+ readonly used: import("effect/Schema").Int;
2689
+ readonly reserved: import("effect/Schema").Int;
2690
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2691
+ readonly archived: import("effect/Schema").Int;
2692
+ readonly protection: import("effect/Schema").Int;
2693
+ }>;
2694
+ readonly cpuMillicores: import("effect/Schema").Struct<{
2695
+ readonly limit: import("effect/Schema").Int;
2696
+ readonly used: import("effect/Schema").Int;
2697
+ readonly reserved: import("effect/Schema").Int;
2698
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2699
+ }>;
2700
+ readonly memoryBytes: import("effect/Schema").Struct<{
2701
+ readonly limit: import("effect/Schema").Int;
2702
+ readonly used: import("effect/Schema").Int;
2703
+ readonly reserved: import("effect/Schema").Int;
2704
+ readonly warning: import("effect/Schema").Literals<readonly ["none", "80-percent", "95-percent", "full"]>;
2705
+ }>;
2706
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainNotFoundError | typeof import("@sealant/api-contracts").ResourceDomainBudgetRevisionConflictError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2505
2707
  };
2506
2708
  readonly runs: {
2507
2709
  readonly createRun: HttpApiClient.Client.Method<import("effect/http-api/HttpApiEndpoint").HttpApiEndpoint<"createRun", "POST", "/v1/runs/", never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
@@ -1434,3 +1434,103 @@ export declare const archiveSshKeyOp: (sshKeyId: string, ownerUserId: string) =>
1434
1434
  readonly fingerprint: string;
1435
1435
  readonly createdAt: string;
1436
1436
  }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SshKeyInternalServerError | import("@sealant/api-contracts").SshKeyNotFoundError, SealantApiClient>;
1437
+ export declare const ensureResourceDomainOp: (key: string, budget?: {
1438
+ readonly cpuMillicores: number;
1439
+ readonly memoryBytes: number;
1440
+ readonly storageBytes: number;
1441
+ } | undefined) => Effect.Effect<{
1442
+ readonly resourceDomainId: string;
1443
+ readonly key: string;
1444
+ readonly createdAt: string;
1445
+ readonly created: boolean;
1446
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainBudgetDiffersError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("effect/Schema").SchemaError, SealantApiClient>;
1447
+ export declare const getResourceDomainOp: (resourceDomainId: string) => Effect.Effect<{
1448
+ readonly resourceDomainId: string;
1449
+ readonly key: string;
1450
+ readonly createdAt: string;
1451
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1452
+ export declare const grantResourceDomainMemberOp: (resourceDomainId: string, userId: string, payload: {
1453
+ readonly version: number;
1454
+ }) => Effect.Effect<{
1455
+ readonly userId: string;
1456
+ readonly state: "member" | "revoked";
1457
+ readonly version: number;
1458
+ readonly updatedAt: string;
1459
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1460
+ export declare const revokeResourceDomainMemberOp: (resourceDomainId: string, userId: string, payload: {
1461
+ readonly version: number;
1462
+ }) => Effect.Effect<{
1463
+ readonly userId: string;
1464
+ readonly state: "member" | "revoked";
1465
+ readonly version: number;
1466
+ readonly updatedAt: string;
1467
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainMemberVersionConflictError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1468
+ export declare const getResourceDomainMemberOp: (resourceDomainId: string, userId: string) => Effect.Effect<{
1469
+ readonly userId: string;
1470
+ readonly state: "member" | "revoked";
1471
+ readonly version: number;
1472
+ readonly updatedAt: string;
1473
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainMemberNotFoundError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("@sealant/api-contracts").ResourceDomainPersonNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1474
+ export declare const listResourceDomainMembersOp: (resourceDomainId: string, query: {
1475
+ readonly limit?: number | undefined;
1476
+ readonly cursor?: string | undefined;
1477
+ }) => Effect.Effect<{
1478
+ readonly items: readonly {
1479
+ readonly userId: string;
1480
+ readonly state: "member" | "revoked";
1481
+ readonly version: number;
1482
+ readonly updatedAt: string;
1483
+ }[];
1484
+ readonly nextCursor?: string | undefined;
1485
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1486
+ export declare const getResourceDomainBudgetOp: (resourceDomainId: string) => Effect.Effect<{
1487
+ readonly revision: number;
1488
+ readonly storageBytes: {
1489
+ readonly limit: number;
1490
+ readonly used: number;
1491
+ readonly reserved: number;
1492
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1493
+ readonly archived: number;
1494
+ readonly protection: number;
1495
+ };
1496
+ readonly cpuMillicores: {
1497
+ readonly limit: number;
1498
+ readonly used: number;
1499
+ readonly reserved: number;
1500
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1501
+ };
1502
+ readonly memoryBytes: {
1503
+ readonly limit: number;
1504
+ readonly used: number;
1505
+ readonly reserved: number;
1506
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1507
+ };
1508
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
1509
+ export declare const setResourceDomainBudgetOp: (resourceDomainId: string, payload: {
1510
+ readonly revision: number;
1511
+ readonly cpuMillicores: number;
1512
+ readonly memoryBytes: number;
1513
+ readonly storageBytes: number;
1514
+ }) => Effect.Effect<{
1515
+ readonly revision: number;
1516
+ readonly storageBytes: {
1517
+ readonly limit: number;
1518
+ readonly used: number;
1519
+ readonly reserved: number;
1520
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1521
+ readonly archived: number;
1522
+ readonly protection: number;
1523
+ };
1524
+ readonly cpuMillicores: {
1525
+ readonly limit: number;
1526
+ readonly used: number;
1527
+ readonly reserved: number;
1528
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1529
+ };
1530
+ readonly memoryBytes: {
1531
+ readonly limit: number;
1532
+ readonly used: number;
1533
+ readonly reserved: number;
1534
+ readonly warning: "80-percent" | "95-percent" | "full" | "none";
1535
+ };
1536
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainBudgetRevisionConflictError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("@sealant/api-contracts").ResourceDomainNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
@@ -86,3 +86,20 @@ export const getSetupStateOp = () => Effect.flatMap(SealantApiClient, (client) =
86
86
  export const createSshKeyOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.sshKeys.createSshKey({ payload }));
87
87
  export const listSshKeysOp = (ownerUserId) => Effect.flatMap(SealantApiClient, (client) => client.sshKeys.listSshKeys({ query: { ownerUserId } }));
88
88
  export const archiveSshKeyOp = (sshKeyId, ownerUserId) => Effect.flatMap(SealantApiClient, (client) => client.sshKeys.archiveSshKey({ params: { sshKeyId }, query: { ownerUserId } }));
89
+ // ---- resource domains (the SDK's scopes) ----
90
+ export const ensureResourceDomainOp = (key, budget) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.ensureResourceDomain({
91
+ payload: budget === undefined ? { key } : { key, budget },
92
+ }));
93
+ export const getResourceDomainOp = (resourceDomainId) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.getResourceDomain({ params: { resourceDomainId } }));
94
+ export const grantResourceDomainMemberOp = (resourceDomainId, userId, payload) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.grantResourceDomainMember({
95
+ params: { resourceDomainId, userId },
96
+ payload,
97
+ }));
98
+ export const revokeResourceDomainMemberOp = (resourceDomainId, userId, payload) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.revokeResourceDomainMember({
99
+ params: { resourceDomainId, userId },
100
+ payload,
101
+ }));
102
+ export const getResourceDomainMemberOp = (resourceDomainId, userId) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.getResourceDomainMember({ params: { resourceDomainId, userId } }));
103
+ export const listResourceDomainMembersOp = (resourceDomainId, query) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.listResourceDomainMembers({ params: { resourceDomainId }, query }));
104
+ export const getResourceDomainBudgetOp = (resourceDomainId) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.getResourceDomainBudget({ params: { resourceDomainId } }));
105
+ export const setResourceDomainBudgetOp = (resourceDomainId, payload) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.setResourceDomainBudget({ params: { resourceDomainId }, payload }));
package/dist/index.d.ts CHANGED
@@ -18,5 +18,6 @@ export { Sealant } from "./client.js";
18
18
  export { claudeCode, codex, customHarness, opencode, pi } from "./harness.js";
19
19
  export { ForwardDialError, type ForwardDialFailure, type ForwardDialReason, ForwardResetError, SealantApiError, SealantError, SealantNotImplementedError, SealantRuntimeError, } from "./errors.js";
20
20
  export type * from "./types.js";
21
+ export type { EnsuredScope, ScopeBudget, ScopeBudgetDimension, ScopeBudgetLimits, ScopeBudgets, ScopeClient, ScopeInfo, ScopeMember, ScopeMemberDecision, ScopeMemberPage, ScopeMembers, ScopesNamespace, } from "./scopes.js";
21
22
  export { findWorkspaceEnvReservedRule, findWorkspaceSecretEnvReservedRule, formatWorkspaceEnvIssue, parseWorkspaceEnv, parseWorkspaceSecretEnv, WORKSPACE_ENV_MAX_ENTRIES, WORKSPACE_ENV_MAX_NAME_LENGTH, WORKSPACE_ENV_MAX_TOTAL_BYTES, WORKSPACE_ENV_MAX_VALUE_BYTES, WORKSPACE_ENV_NAME_PATTERN, WORKSPACE_ENV_SECRET_MARKERS, } from "@sealant/api-contracts/workspace-environment";
22
23
  export type { WorkspaceEnvIssue, WorkspaceEnvParseResult, WorkspaceEnvReservedRule, } from "@sealant/api-contracts/workspace-environment";
@@ -0,0 +1,123 @@
1
+ /**
2
+ * `sealant.scopes`: owners that are projects, not people (the control plane's resource domains).
3
+ *
4
+ * An application ensures one scope per project, by a global `<application>:<name>` key, and names
5
+ * the people who may reach it. A scope never holds a login or a provider credential and never runs
6
+ * a harness, so the client that acts as one (`actAs`) has no workspace, run, inference or
7
+ * credential methods at all. These calls need a service key and never use `ownerUserId`.
8
+ */
9
+ import { type ResourceDomainBudgetDimension } from "@sealant/api-contracts";
10
+ import type { SdkRuntime } from "./effect/runtime.js";
11
+ export interface ScopeInfo {
12
+ /** `rdm:<uuid>`. No person field of the API accepts it. */
13
+ readonly id: string;
14
+ /** `<application>:<name>`, unique across every application. */
15
+ readonly key: string;
16
+ readonly createdAt: string;
17
+ }
18
+ export interface EnsuredScope extends ScopeInfo {
19
+ /** True when this call created the scope. */
20
+ readonly created: boolean;
21
+ }
22
+ /**
23
+ * The application's latest decision about one person in a scope. A revoked member keeps its row,
24
+ * so its version stays readable.
25
+ */
26
+ export interface ScopeMember {
27
+ readonly userId: string;
28
+ readonly state: "member" | "revoked";
29
+ readonly version: number;
30
+ readonly updatedAt: string;
31
+ }
32
+ /**
33
+ * `version` is the application's own number for its decision about this person, rising with each
34
+ * decision it makes (its record's revision, say). The scope keeps the highest. The same version
35
+ * with the same state is a repeat and answers the member unchanged. The same version with the
36
+ * other state, or a lower one, rejects (409, `ResourceDomainMemberVersionConflictError`, whose
37
+ * `current` is the decision that stands) and changes nothing. So a delayed grant never undoes a
38
+ * newer revoke, and nothing needs reading first.
39
+ */
40
+ export interface ScopeMemberDecision {
41
+ readonly version: number;
42
+ }
43
+ /** A page of a scope's members. `nextCursor` is present when more follow. */
44
+ export interface ScopeMemberPage {
45
+ readonly items: readonly ScopeMember[];
46
+ readonly nextCursor?: string;
47
+ }
48
+ export interface ScopeMembers {
49
+ grant(userId: string, decision: ScopeMemberDecision): Promise<ScopeMember>;
50
+ revoke(userId: string, decision: ScopeMemberDecision): Promise<ScopeMember>;
51
+ /**
52
+ * One person's decision. Rejects with 404 `ResourceDomainMemberNotFoundError` when there is none,
53
+ * `ResourceDomainPersonNotFoundError` when the person does not exist.
54
+ */
55
+ get(userId: string): Promise<ScopeMember>;
56
+ /**
57
+ * A page of the people with a decision in the scope, revoked ones included, by user id: `limit`
58
+ * of them (100 unless named, at most 500), after the previous page's `nextCursor` as `cursor`.
59
+ */
60
+ list(options?: {
61
+ readonly limit?: number;
62
+ readonly cursor?: string;
63
+ }): Promise<ScopeMemberPage>;
64
+ }
65
+ /** Ceilings on what a scope's objects may hold (CPU millicores, memory and storage bytes). */
66
+ export type ScopeBudgetLimits = {
67
+ readonly [D in ResourceDomainBudgetDimension]: number;
68
+ };
69
+ /**
70
+ * `used` (confirmed to exist) and `reserved` (admitted, not yet confirmed) both count against
71
+ * `limit`; `warning` is the highest share of it they reach.
72
+ */
73
+ export interface ScopeBudgetDimension {
74
+ readonly limit: number;
75
+ readonly used: number;
76
+ readonly reserved: number;
77
+ readonly warning: "none" | "80-percent" | "95-percent" | "full";
78
+ }
79
+ /** Storage is one allowance, archived volumes and protection included; nothing is deleted to free it. */
80
+ export type ScopeBudget = {
81
+ /** Name it to change the budget: a change made since refuses yours. */
82
+ readonly revision: number;
83
+ } & {
84
+ readonly [D in ResourceDomainBudgetDimension]: ScopeBudgetDimension;
85
+ } & {
86
+ readonly storageBytes: {
87
+ readonly archived: number;
88
+ readonly protection: number;
89
+ };
90
+ };
91
+ export interface ScopeBudgets {
92
+ get(): Promise<ScopeBudget>;
93
+ /**
94
+ * Replace the budget at the `revision` you read. A change since rejects (409,
95
+ * `ResourceDomainBudgetRevisionConflictError`). It answers the budget it wrote, and changes
96
+ * nothing the scope holds.
97
+ */
98
+ set(change: ScopeBudgetLimits & {
99
+ readonly revision: number;
100
+ }): Promise<ScopeBudget>;
101
+ }
102
+ /** A client acting as one scope. It has no method that could reach a credential or a harness. */
103
+ export interface ScopeClient {
104
+ readonly id: string;
105
+ get(): Promise<ScopeInfo>;
106
+ readonly members: ScopeMembers;
107
+ readonly budget: ScopeBudgets;
108
+ }
109
+ export interface ScopesNamespace {
110
+ /**
111
+ * The scope with this key, created on the first call (with `budget`, or zero); later and
112
+ * concurrent calls answer it. Naming another budget rejects (409,
113
+ * `ResourceDomainBudgetDiffersError`, carrying the scope's id and its budget's revision).
114
+ */
115
+ ensure(options: {
116
+ readonly key: string;
117
+ readonly budget?: ScopeBudgetLimits;
118
+ }): Promise<EnsuredScope>;
119
+ get(scopeId: string): Promise<ScopeInfo>;
120
+ /** A client for this scope alone, and the only way to its members. Nothing is checked until its first call. */
121
+ actAs(scopeId: string): ScopeClient;
122
+ }
123
+ export declare const makeScopes: (runtime: SdkRuntime) => ScopesNamespace;
package/dist/scopes.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `sealant.scopes`: owners that are projects, not people (the control plane's resource domains).
3
+ *
4
+ * An application ensures one scope per project, by a global `<application>:<name>` key, and names
5
+ * the people who may reach it. A scope never holds a login or a provider credential and never runs
6
+ * a harness, so the client that acts as one (`actAs`) has no workspace, run, inference or
7
+ * credential methods at all. These calls need a service key and never use `ownerUserId`.
8
+ */
9
+ import { RESOURCE_DOMAIN_BUDGET_DIMENSIONS, } from "@sealant/api-contracts";
10
+ import * as Rec from "effect/Record";
11
+ import { ensureResourceDomainOp, getResourceDomainBudgetOp, getResourceDomainMemberOp, getResourceDomainOp, grantResourceDomainMemberOp, listResourceDomainMembersOp, revokeResourceDomainMemberOp, setResourceDomainBudgetOp, } from "./effect/operations.js";
12
+ const toScope = (wire) => ({
13
+ id: wire.resourceDomainId,
14
+ key: wire.key,
15
+ createdAt: wire.createdAt,
16
+ });
17
+ export const makeScopes = (runtime) => {
18
+ const get = async (scopeId) => toScope(await runtime.run(getResourceDomainOp(scopeId)));
19
+ return {
20
+ ensure: async ({ key, budget }) => {
21
+ const wire = await runtime.run(ensureResourceDomainOp(key, budget));
22
+ return { ...toScope(wire), created: wire.created };
23
+ },
24
+ get,
25
+ actAs: (scopeId) => ({
26
+ id: scopeId,
27
+ get: () => get(scopeId),
28
+ members: {
29
+ grant: (userId, decision) => runtime.run(grantResourceDomainMemberOp(scopeId, userId, { version: decision.version })),
30
+ revoke: (userId, decision) => runtime.run(revokeResourceDomainMemberOp(scopeId, userId, { version: decision.version })),
31
+ get: (userId) => runtime.run(getResourceDomainMemberOp(scopeId, userId)),
32
+ list: async (options) => {
33
+ const page = await runtime.run(listResourceDomainMembersOp(scopeId, { ...options }));
34
+ return page.nextCursor === undefined
35
+ ? { items: page.items }
36
+ : { items: page.items, nextCursor: page.nextCursor };
37
+ },
38
+ },
39
+ budget: {
40
+ get: () => runtime.run(getResourceDomainBudgetOp(scopeId)),
41
+ set: (change) => runtime.run(setResourceDomainBudgetOp(scopeId, {
42
+ ...Rec.map(RESOURCE_DOMAIN_BUDGET_DIMENSIONS, (_, dimension) => change[dimension]),
43
+ revision: change.revision,
44
+ })),
45
+ },
46
+ }),
47
+ };
48
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/sdk-next",
3
- "version": "0.40.0-next.769",
3
+ "version": "0.40.0-next.771",
4
4
  "description": "The fluent public SDK for Sealant — create a workspace, run a harness, replay the record.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -26,12 +26,12 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "dependencies": {
29
- "@sealant/api-contracts": "npm:@sealant/api-contracts-next@0.40.0-next.769"
29
+ "@sealant/api-contracts": "npm:@sealant/api-contracts-next@0.40.0-next.771"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "effect": "^4.0.5"
33
33
  },
34
- "gitHead": "ab6f8d9ccf2f282c542e388b994099cae91c1354",
34
+ "gitHead": "697e8d55f312105e4f52964dd5a7fb956c0c6d63",
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  }