@sealant/sdk-next 0.40.0-next.768 → 0.40.0-next.770

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() {
@@ -524,6 +524,68 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
524
524
  readonly reachable: import("effect/Schema").Literal<true>;
525
525
  }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").RegistriesNotFoundError | typeof import("@sealant/api-contracts").RegistriesBadGatewayError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
526
526
  };
527
+ readonly resourceDomains: {
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
+ readonly key: import("effect/Schema").String;
530
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
531
+ readonly resourceDomainId: import("effect/Schema").String;
532
+ readonly key: import("effect/Schema").String;
533
+ readonly createdAt: import("effect/Schema").String;
534
+ 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
+ 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
+ readonly resourceDomainId: import("effect/Schema").String;
538
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
539
+ readonly resourceDomainId: import("effect/Schema").String;
540
+ readonly key: import("effect/Schema").String;
541
+ readonly createdAt: import("effect/Schema").String;
542
+ }>>, 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>;
543
+ 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<{
544
+ readonly resourceDomainId: import("effect/Schema").String;
545
+ readonly userId: import("effect/Schema").String;
546
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
547
+ readonly userId: import("effect/Schema").String;
548
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
549
+ readonly version: import("effect/Schema").Int;
550
+ readonly updatedAt: import("effect/Schema").String;
551
+ }>>, 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>;
552
+ 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<{
553
+ readonly resourceDomainId: import("effect/Schema").String;
554
+ readonly userId: import("effect/Schema").String;
555
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
556
+ readonly version: import("effect/Schema").Int;
557
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
558
+ readonly userId: import("effect/Schema").String;
559
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
560
+ readonly version: import("effect/Schema").Int;
561
+ readonly updatedAt: import("effect/Schema").String;
562
+ }>>, 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>;
563
+ 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<{
564
+ readonly resourceDomainId: import("effect/Schema").String;
565
+ }>>, import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
566
+ readonly limit: import("effect/Schema").optional<import("effect/Schema").FiniteFromString>;
567
+ readonly cursor: import("effect/Schema").optional<import("effect/Schema").String>;
568
+ }>>, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
569
+ readonly items: import("effect/Schema").$Array<import("effect/Schema").Struct<{
570
+ readonly userId: import("effect/Schema").String;
571
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
572
+ readonly version: import("effect/Schema").Int;
573
+ readonly updatedAt: import("effect/Schema").String;
574
+ }>>;
575
+ readonly nextCursor: import("effect/Schema").optional<import("effect/Schema").String>;
576
+ }>>, 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>;
577
+ 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<{
578
+ readonly resourceDomainId: import("effect/Schema").String;
579
+ readonly userId: import("effect/Schema").String;
580
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
581
+ readonly version: import("effect/Schema").Int;
582
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
583
+ readonly userId: import("effect/Schema").String;
584
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
585
+ readonly version: import("effect/Schema").Int;
586
+ readonly updatedAt: import("effect/Schema").String;
587
+ }>>, 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>;
588
+ };
527
589
  readonly runs: {
528
590
  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<{
529
591
  readonly workspaceId: import("effect/Schema").String;
@@ -2469,6 +2531,68 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
2469
2531
  readonly reachable: import("effect/Schema").Literal<true>;
2470
2532
  }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").RegistriesNotFoundError | typeof import("@sealant/api-contracts").RegistriesBadGatewayError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2471
2533
  };
2534
+ readonly resourceDomains: {
2535
+ 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<{
2536
+ readonly key: import("effect/Schema").String;
2537
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2538
+ readonly resourceDomainId: import("effect/Schema").String;
2539
+ readonly key: import("effect/Schema").String;
2540
+ readonly createdAt: import("effect/Schema").String;
2541
+ readonly created: import("effect/Schema").Boolean;
2542
+ }>>, import("effect/Schema").toCodecJson<typeof import("@sealant/api-contracts").ResourceDomainForbiddenError | typeof import("@sealant/api-contracts").ResourceDomainInternalServerError>, import("@sealant/api-contracts").RequestRefusal, never>, never, never>;
2543
+ 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<{
2544
+ readonly resourceDomainId: import("effect/Schema").String;
2545
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2546
+ readonly resourceDomainId: import("effect/Schema").String;
2547
+ readonly key: import("effect/Schema").String;
2548
+ readonly createdAt: import("effect/Schema").String;
2549
+ }>>, 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>;
2550
+ 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<{
2551
+ readonly resourceDomainId: import("effect/Schema").String;
2552
+ readonly userId: import("effect/Schema").String;
2553
+ }>>, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2554
+ readonly userId: import("effect/Schema").String;
2555
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2556
+ readonly version: import("effect/Schema").Int;
2557
+ readonly updatedAt: import("effect/Schema").String;
2558
+ }>>, 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>;
2559
+ 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<{
2560
+ readonly resourceDomainId: import("effect/Schema").String;
2561
+ readonly userId: import("effect/Schema").String;
2562
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2563
+ readonly version: import("effect/Schema").Int;
2564
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2565
+ readonly userId: import("effect/Schema").String;
2566
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2567
+ readonly version: import("effect/Schema").Int;
2568
+ readonly updatedAt: import("effect/Schema").String;
2569
+ }>>, 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>;
2570
+ 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<{
2571
+ readonly resourceDomainId: import("effect/Schema").String;
2572
+ }>>, import("effect/Schema").toCodecStringTree<import("effect/Schema").Struct<{
2573
+ readonly limit: import("effect/Schema").optional<import("effect/Schema").FiniteFromString>;
2574
+ readonly cursor: import("effect/Schema").optional<import("effect/Schema").String>;
2575
+ }>>, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2576
+ readonly items: import("effect/Schema").$Array<import("effect/Schema").Struct<{
2577
+ readonly userId: import("effect/Schema").String;
2578
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2579
+ readonly version: import("effect/Schema").Int;
2580
+ readonly updatedAt: import("effect/Schema").String;
2581
+ }>>;
2582
+ readonly nextCursor: import("effect/Schema").optional<import("effect/Schema").String>;
2583
+ }>>, 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>;
2584
+ 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<{
2585
+ readonly resourceDomainId: import("effect/Schema").String;
2586
+ readonly userId: import("effect/Schema").String;
2587
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2588
+ readonly version: import("effect/Schema").Int;
2589
+ }>>, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
2590
+ readonly userId: import("effect/Schema").String;
2591
+ readonly state: import("effect/Schema").Literals<readonly ["member", "revoked"]>;
2592
+ readonly version: import("effect/Schema").Int;
2593
+ readonly updatedAt: import("effect/Schema").String;
2594
+ }>>, 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>;
2595
+ };
2472
2596
  readonly runs: {
2473
2597
  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<{
2474
2598
  readonly workspaceId: import("effect/Schema").String;
@@ -1434,3 +1434,48 @@ 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) => Effect.Effect<{
1438
+ readonly resourceDomainId: string;
1439
+ readonly key: string;
1440
+ readonly createdAt: string;
1441
+ readonly created: boolean;
1442
+ }, import("effect/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RequestRefusedError | import("@sealant/api-contracts").ResourceDomainForbiddenError | import("@sealant/api-contracts").ResourceDomainInternalServerError | import("effect/Schema").SchemaError, SealantApiClient>;
1443
+ export declare const getResourceDomainOp: (resourceDomainId: string) => Effect.Effect<{
1444
+ readonly resourceDomainId: string;
1445
+ readonly key: string;
1446
+ readonly createdAt: string;
1447
+ }, 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>;
1448
+ export declare const grantResourceDomainMemberOp: (resourceDomainId: string, userId: string, payload: {
1449
+ readonly version: number;
1450
+ }) => Effect.Effect<{
1451
+ readonly userId: string;
1452
+ readonly state: "member" | "revoked";
1453
+ readonly version: number;
1454
+ readonly updatedAt: string;
1455
+ }, 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>;
1456
+ export declare const revokeResourceDomainMemberOp: (resourceDomainId: string, userId: string, payload: {
1457
+ readonly version: number;
1458
+ }) => Effect.Effect<{
1459
+ readonly userId: string;
1460
+ readonly state: "member" | "revoked";
1461
+ readonly version: number;
1462
+ readonly updatedAt: string;
1463
+ }, 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>;
1464
+ export declare const getResourceDomainMemberOp: (resourceDomainId: string, userId: string) => Effect.Effect<{
1465
+ readonly userId: string;
1466
+ readonly state: "member" | "revoked";
1467
+ readonly version: number;
1468
+ readonly updatedAt: string;
1469
+ }, 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>;
1470
+ export declare const listResourceDomainMembersOp: (resourceDomainId: string, query: {
1471
+ readonly limit?: number | undefined;
1472
+ readonly cursor?: string | undefined;
1473
+ }) => Effect.Effect<{
1474
+ readonly items: readonly {
1475
+ readonly userId: string;
1476
+ readonly state: "member" | "revoked";
1477
+ readonly version: number;
1478
+ readonly updatedAt: string;
1479
+ }[];
1480
+ readonly nextCursor?: string | undefined;
1481
+ }, 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>;
@@ -86,3 +86,16 @@ 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) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.ensureResourceDomain({ payload: { key } }));
91
+ export const getResourceDomainOp = (resourceDomainId) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.getResourceDomain({ params: { resourceDomainId } }));
92
+ export const grantResourceDomainMemberOp = (resourceDomainId, userId, payload) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.grantResourceDomainMember({
93
+ params: { resourceDomainId, userId },
94
+ payload,
95
+ }));
96
+ export const revokeResourceDomainMemberOp = (resourceDomainId, userId, payload) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.revokeResourceDomainMember({
97
+ params: { resourceDomainId, userId },
98
+ payload,
99
+ }));
100
+ export const getResourceDomainMemberOp = (resourceDomainId, userId) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.getResourceDomainMember({ params: { resourceDomainId, userId } }));
101
+ export const listResourceDomainMembersOp = (resourceDomainId, query) => Effect.flatMap(SealantApiClient, (client) => client.resourceDomains.listResourceDomainMembers({ params: { resourceDomainId }, query }));
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, 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,71 @@
1
+ import type { SdkRuntime } from "./effect/runtime.js";
2
+ export interface ScopeInfo {
3
+ /** `rdm:<uuid>`. No person field of the API accepts it. */
4
+ readonly id: string;
5
+ /** `<application>:<name>`, unique across every application. */
6
+ readonly key: string;
7
+ readonly createdAt: string;
8
+ }
9
+ export interface EnsuredScope extends ScopeInfo {
10
+ /** True when this call created the scope. */
11
+ readonly created: boolean;
12
+ }
13
+ /**
14
+ * The application's latest decision about one person in a scope. A revoked member keeps its row,
15
+ * so its version stays readable.
16
+ */
17
+ export interface ScopeMember {
18
+ readonly userId: string;
19
+ readonly state: "member" | "revoked";
20
+ readonly version: number;
21
+ readonly updatedAt: string;
22
+ }
23
+ /**
24
+ * `version` is the application's own number for its decision about this person, rising with each
25
+ * decision it makes (its record's revision, say). The scope keeps the highest. The same version
26
+ * with the same state is a repeat and answers the member unchanged. The same version with the
27
+ * other state, or a lower one, rejects (409, `ResourceDomainMemberVersionConflictError`, whose
28
+ * `current` is the decision that stands) and changes nothing. So a delayed grant never undoes a
29
+ * newer revoke, and nothing needs reading first.
30
+ */
31
+ export interface ScopeMemberDecision {
32
+ readonly version: number;
33
+ }
34
+ /** A page of a scope's members. `nextCursor` is present when more follow. */
35
+ export interface ScopeMemberPage {
36
+ readonly items: readonly ScopeMember[];
37
+ readonly nextCursor?: string;
38
+ }
39
+ export interface ScopeMembers {
40
+ grant(userId: string, decision: ScopeMemberDecision): Promise<ScopeMember>;
41
+ revoke(userId: string, decision: ScopeMemberDecision): Promise<ScopeMember>;
42
+ /**
43
+ * One person's decision. Rejects with 404 `ResourceDomainMemberNotFoundError` when there is none,
44
+ * `ResourceDomainPersonNotFoundError` when the person does not exist.
45
+ */
46
+ get(userId: string): Promise<ScopeMember>;
47
+ /**
48
+ * A page of the people with a decision in the scope, revoked ones included, by user id: `limit`
49
+ * of them (100 unless named, at most 500), after the previous page's `nextCursor` as `cursor`.
50
+ */
51
+ list(options?: {
52
+ readonly limit?: number;
53
+ readonly cursor?: string;
54
+ }): Promise<ScopeMemberPage>;
55
+ }
56
+ /** A client acting as one scope. It has no method that could reach a credential or a harness. */
57
+ export interface ScopeClient {
58
+ readonly id: string;
59
+ get(): Promise<ScopeInfo>;
60
+ readonly members: ScopeMembers;
61
+ }
62
+ export interface ScopesNamespace {
63
+ /** The scope with this key, created on the first call; later and concurrent calls answer it. */
64
+ ensure(options: {
65
+ readonly key: string;
66
+ }): Promise<EnsuredScope>;
67
+ get(scopeId: string): Promise<ScopeInfo>;
68
+ /** A client for this scope alone, and the only way to its members. Nothing is checked until its first call. */
69
+ actAs(scopeId: string): ScopeClient;
70
+ }
71
+ export declare const makeScopes: (runtime: SdkRuntime) => ScopesNamespace;
package/dist/scopes.js ADDED
@@ -0,0 +1,31 @@
1
+ import { ensureResourceDomainOp, getResourceDomainMemberOp, getResourceDomainOp, grantResourceDomainMemberOp, listResourceDomainMembersOp, revokeResourceDomainMemberOp, } from "./effect/operations.js";
2
+ const toScope = (wire) => ({
3
+ id: wire.resourceDomainId,
4
+ key: wire.key,
5
+ createdAt: wire.createdAt,
6
+ });
7
+ export const makeScopes = (runtime) => {
8
+ const get = async (scopeId) => toScope(await runtime.run(getResourceDomainOp(scopeId)));
9
+ return {
10
+ ensure: async ({ key }) => {
11
+ const wire = await runtime.run(ensureResourceDomainOp(key));
12
+ return { ...toScope(wire), created: wire.created };
13
+ },
14
+ get,
15
+ actAs: (scopeId) => ({
16
+ id: scopeId,
17
+ get: () => get(scopeId),
18
+ members: {
19
+ grant: (userId, decision) => runtime.run(grantResourceDomainMemberOp(scopeId, userId, { version: decision.version })),
20
+ revoke: (userId, decision) => runtime.run(revokeResourceDomainMemberOp(scopeId, userId, { version: decision.version })),
21
+ get: (userId) => runtime.run(getResourceDomainMemberOp(scopeId, userId)),
22
+ list: async (options) => {
23
+ const page = await runtime.run(listResourceDomainMembersOp(scopeId, { ...options }));
24
+ return page.nextCursor === undefined
25
+ ? { items: page.items }
26
+ : { items: page.items, nextCursor: page.nextCursor };
27
+ },
28
+ },
29
+ }),
30
+ };
31
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/sdk-next",
3
- "version": "0.40.0-next.768",
3
+ "version": "0.40.0-next.770",
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.768"
29
+ "@sealant/api-contracts": "npm:@sealant/api-contracts-next@0.40.0-next.770"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "effect": "^4.0.5"
33
33
  },
34
- "gitHead": "f1e27d77cf3498dcd6eab47bd2fa9619094b2b63",
34
+ "gitHead": "1e8b4f1153f5107504649c863c305cd31f424d58",
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  }