@sealant/sdk 0.22.0 → 0.24.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.
|
@@ -1122,7 +1122,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
|
|
|
1122
1122
|
readonly registryId: string;
|
|
1123
1123
|
readonly repository: string;
|
|
1124
1124
|
readonly tag: string;
|
|
1125
|
-
}, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError), [Mode] extends ["response-only"] ? never : never>;
|
|
1125
|
+
}, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceRuntimeEnvReferencesUnsupportedError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError), [Mode] extends ["response-only"] ? never : never>;
|
|
1126
1126
|
readonly execWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
|
|
1127
1127
|
readonly params: {
|
|
1128
1128
|
readonly workspaceId: string;
|
|
@@ -1190,7 +1190,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
|
|
|
1190
1190
|
readonly repository?: string | undefined;
|
|
1191
1191
|
readonly tag?: string | undefined;
|
|
1192
1192
|
readonly runtime?: {
|
|
1193
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
1193
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
1194
1194
|
readonly resourceId: string;
|
|
1195
1195
|
readonly reference: string;
|
|
1196
1196
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -1225,7 +1225,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
|
|
|
1225
1225
|
readonly workspaceId: string;
|
|
1226
1226
|
readonly attemptId: string;
|
|
1227
1227
|
readonly runtime: {
|
|
1228
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
1228
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
1229
1229
|
readonly resourceId: string;
|
|
1230
1230
|
readonly reference: string;
|
|
1231
1231
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -1248,7 +1248,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
|
|
|
1248
1248
|
readonly triggerType: "api" | "manual" | "retry" | "schedule";
|
|
1249
1249
|
readonly triggerRef?: string | undefined;
|
|
1250
1250
|
readonly runtime?: {
|
|
1251
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
1251
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
1252
1252
|
readonly resourceId: string;
|
|
1253
1253
|
readonly reference: string;
|
|
1254
1254
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -1309,7 +1309,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
|
|
|
1309
1309
|
readonly repository?: string | undefined;
|
|
1310
1310
|
readonly tag?: string | undefined;
|
|
1311
1311
|
readonly runtime?: {
|
|
1312
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
1312
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
1313
1313
|
readonly resourceId: string;
|
|
1314
1314
|
readonly reference: string;
|
|
1315
1315
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -2492,7 +2492,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
|
|
|
2492
2492
|
readonly registryId: string;
|
|
2493
2493
|
readonly repository: string;
|
|
2494
2494
|
readonly tag: string;
|
|
2495
|
-
}, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError), [Mode] extends ["response-only"] ? never : never>;
|
|
2495
|
+
}, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceRuntimeEnvReferencesUnsupportedError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError), [Mode] extends ["response-only"] ? never : never>;
|
|
2496
2496
|
readonly execWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
|
|
2497
2497
|
readonly params: {
|
|
2498
2498
|
readonly workspaceId: string;
|
|
@@ -2560,7 +2560,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
|
|
|
2560
2560
|
readonly repository?: string | undefined;
|
|
2561
2561
|
readonly tag?: string | undefined;
|
|
2562
2562
|
readonly runtime?: {
|
|
2563
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
2563
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
2564
2564
|
readonly resourceId: string;
|
|
2565
2565
|
readonly reference: string;
|
|
2566
2566
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -2595,7 +2595,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
|
|
|
2595
2595
|
readonly workspaceId: string;
|
|
2596
2596
|
readonly attemptId: string;
|
|
2597
2597
|
readonly runtime: {
|
|
2598
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
2598
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
2599
2599
|
readonly resourceId: string;
|
|
2600
2600
|
readonly reference: string;
|
|
2601
2601
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -2618,7 +2618,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
|
|
|
2618
2618
|
readonly triggerType: "api" | "manual" | "retry" | "schedule";
|
|
2619
2619
|
readonly triggerRef?: string | undefined;
|
|
2620
2620
|
readonly runtime?: {
|
|
2621
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
2621
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
2622
2622
|
readonly resourceId: string;
|
|
2623
2623
|
readonly reference: string;
|
|
2624
2624
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -2679,7 +2679,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
|
|
|
2679
2679
|
readonly repository?: string | undefined;
|
|
2680
2680
|
readonly tag?: string | undefined;
|
|
2681
2681
|
readonly runtime?: {
|
|
2682
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
2682
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
2683
2683
|
readonly resourceId: string;
|
|
2684
2684
|
readonly reference: string;
|
|
2685
2685
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -36,7 +36,7 @@ export declare const createWorkspaceOp: (payload: {
|
|
|
36
36
|
readonly registryId: string;
|
|
37
37
|
readonly repository: string;
|
|
38
38
|
readonly tag: string;
|
|
39
|
-
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError, SealantApiClient>;
|
|
39
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceForbiddenError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError | import("@sealant/api-contracts").WorkspaceRuntimeEnvReferencesUnsupportedError | import("@sealant/api-contracts").WorkspaceServiceUnavailableError, SealantApiClient>;
|
|
40
40
|
export declare const getWorkspaceOp: (workspaceId: string, ownerUserId?: string | undefined) => Effect.Effect<{
|
|
41
41
|
readonly workspaceId: string;
|
|
42
42
|
readonly name: string;
|
|
@@ -46,7 +46,7 @@ export declare const getWorkspaceOp: (workspaceId: string, ownerUserId?: string
|
|
|
46
46
|
readonly repository?: string | undefined;
|
|
47
47
|
readonly tag?: string | undefined;
|
|
48
48
|
readonly runtime?: {
|
|
49
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
49
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
50
50
|
readonly resourceId: string;
|
|
51
51
|
readonly reference: string;
|
|
52
52
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
|
@@ -82,7 +82,7 @@ export declare const listWorkspacesOp: (query: {
|
|
|
82
82
|
readonly repository?: string | undefined;
|
|
83
83
|
readonly tag?: string | undefined;
|
|
84
84
|
readonly runtime?: {
|
|
85
|
-
readonly adapter: "docker" | "k3s" | "k8s";
|
|
85
|
+
readonly adapter: "cloudflare" | "docker" | "k3s" | "k8s";
|
|
86
86
|
readonly resourceId: string;
|
|
87
87
|
readonly reference: string;
|
|
88
88
|
readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
|
package/dist/facade/session.js
CHANGED
|
@@ -3,18 +3,19 @@ import { closeSessionOp, getSessionOp, getSessionOutputOp, resizeSessionOp, send
|
|
|
3
3
|
* Open the held-WebSocket terminal attachment (the data plane). One socket:
|
|
4
4
|
* binary frames are PTY bytes in both directions, text frames are control
|
|
5
5
|
* JSON (`{"t":"resize",...}` up, `{"t":"end"}` down). Auth rides the connect —
|
|
6
|
-
* `?token=` for apiKey clients (WebSocket cannot
|
|
7
|
-
*
|
|
6
|
+
* `?ownerUserId=` always, plus `?token=` for apiKey clients (WebSocket cannot
|
|
7
|
+
* set headers; a service principal needs the owner assertion *and* its key) —
|
|
8
|
+
* and never repeats per event.
|
|
8
9
|
*/
|
|
9
10
|
const openAttachment = (ctx, sessionId, options) => {
|
|
10
11
|
const config = ctx.config;
|
|
11
12
|
const url = new URL(`/v1/sessions/${sessionId}/attach`, config.baseUrl);
|
|
12
13
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
13
14
|
url.searchParams.set("from", (options?.from ?? 0n).toString());
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
// The owner assertion always rides the URL; a service principal needs it *alongside* its key,
|
|
16
|
+
// and WebSocket cannot carry headers, so the key rides the URL too.
|
|
17
|
+
url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
|
|
18
|
+
if (config.apiKey !== undefined) {
|
|
18
19
|
url.searchParams.set("token", config.apiKey);
|
|
19
20
|
}
|
|
20
21
|
return new Promise((resolve, reject) => {
|
|
@@ -126,9 +127,7 @@ async function* streamOverSse(ctx, sessionId, from, signal) {
|
|
|
126
127
|
const fetchImpl = config.fetch ?? fetch;
|
|
127
128
|
const url = new URL(`/v1/sessions/${sessionId}/output/stream`, config.baseUrl);
|
|
128
129
|
url.searchParams.set("from", from.toString());
|
|
129
|
-
|
|
130
|
-
url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
|
|
131
|
-
}
|
|
130
|
+
url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
|
|
132
131
|
const response = await fetchImpl(url, {
|
|
133
132
|
headers: {
|
|
134
133
|
accept: "text/event-stream",
|
package/dist/facade/workspace.js
CHANGED
|
@@ -214,10 +214,10 @@ const openForward = (ctx, workspaceId, port, options) => {
|
|
|
214
214
|
if (options?.protocol === "udp") {
|
|
215
215
|
url.searchParams.set("protocol", "udp");
|
|
216
216
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
// The owner assertion always rides the URL (a service principal needs it alongside its
|
|
218
|
+
// key, and WebSocket cannot carry headers — same contract as the session attach).
|
|
219
|
+
url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
|
|
220
|
+
if (config.apiKey !== undefined) {
|
|
221
221
|
url.searchParams.set("token", config.apiKey);
|
|
222
222
|
}
|
|
223
223
|
return new Promise((resolve, reject) => {
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* no contract change. The public `repository` is the SOURCE git repo (it becomes
|
|
5
5
|
* `spec.sources.workspace.url`); the contract's `repository`/`tag` are the OCI push coordinates, which
|
|
6
6
|
* we derive. `customization.enableSealantd` is forced on (it bakes + launches the daemon the run path
|
|
7
|
-
* connects to), the runtime target is
|
|
7
|
+
* connects to), the runtime target is `auto` (the deployment's default adapter — Docker on self-host, Kubernetes
|
|
8
|
+
* when the worker is configured for a cluster), and the
|
|
8
9
|
* foreground is a keepalive so the workspace idles with the daemon up and the harness is exec'd on
|
|
9
10
|
* demand by `run()` rather than launched at boot. `options.credentials`, if present, is lowered via
|
|
10
11
|
* `mapWorkspaceCredentials` (see `./credentials.js`) and folded into `spec.credentials`; the control
|
|
@@ -123,6 +124,12 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
123
124
|
})),
|
|
124
125
|
}),
|
|
125
126
|
...(userEnv === undefined || Object.keys(userEnv).length === 0 ? {} : { userEnv }),
|
|
127
|
+
...(options.envFrom === undefined || options.envFrom.length === 0
|
|
128
|
+
? {}
|
|
129
|
+
: { envFrom: options.envFrom.map(({ kind, name }) => ({ kind, name })) }),
|
|
130
|
+
...(options.kubernetes?.serviceAccountName === undefined
|
|
131
|
+
? {}
|
|
132
|
+
: { kubernetes: { serviceAccountName: options.kubernetes.serviceAccountName } }),
|
|
126
133
|
};
|
|
127
134
|
const spec = {
|
|
128
135
|
version: "1",
|
|
@@ -182,7 +189,9 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
182
189
|
os: options.baseImage !== undefined
|
|
183
190
|
? { family: "custom", mode: "require", baseImage: options.baseImage }
|
|
184
191
|
: { family: options.os ?? "fedora", mode: "prefer" },
|
|
185
|
-
|
|
192
|
+
// `auto` = the deployment's DEFAULT_RUNTIME_ADAPTER. SDK callers don't know (and must not
|
|
193
|
+
// care) whether the control plane runs workspaces as containers or Pods.
|
|
194
|
+
runtime: { family: "auto", mode: "prefer" },
|
|
186
195
|
},
|
|
187
196
|
lifecycle: {
|
|
188
197
|
startup: { foreground: { kind: "command", run: "sleep infinity", shell: "bash" } },
|
package/dist/types.d.ts
CHANGED
|
@@ -188,6 +188,12 @@ export interface WorkspaceServicesOptions {
|
|
|
188
188
|
*/
|
|
189
189
|
readonly docker?: boolean;
|
|
190
190
|
}
|
|
191
|
+
/** One cluster env source: a Kubernetes object whose keys become workspace environment. */
|
|
192
|
+
export interface WorkspaceEnvFromSource {
|
|
193
|
+
readonly kind: "secret" | "configmap";
|
|
194
|
+
/** Kubernetes object name (DNS-1123 subdomain) in the platform's workspaces namespace. */
|
|
195
|
+
readonly name: string;
|
|
196
|
+
}
|
|
191
197
|
export interface CreateOptions {
|
|
192
198
|
/**
|
|
193
199
|
* Source git repository to build the workspace around (e.g. `"github.com/acme/billing-service"`).
|
|
@@ -255,6 +261,31 @@ export interface CreateOptions {
|
|
|
255
261
|
* instead). Docker runtime only.
|
|
256
262
|
*/
|
|
257
263
|
readonly secretEnv?: Readonly<Record<string, string>>;
|
|
264
|
+
/**
|
|
265
|
+
* Cluster env sources — Kubernetes runtimes only. Each entry names one Kubernetes `Secret` or
|
|
266
|
+
* `ConfigMap` in the platform's workspaces namespace whose KEYS become workspace environment,
|
|
267
|
+
* resolved by the platform worker at workspace creation (a launch keeps its snapshot across
|
|
268
|
+
* container restarts; rotation reaches only later launches). Ordered, last wins across kinds.
|
|
269
|
+
* Only objects the operator opted in with the `sealant.sh/workspace-env: "true"` label
|
|
270
|
+
* resolve; platform-managed objects are refused unconditionally. Explicit `env` / `secretEnv`
|
|
271
|
+
* and platform-owned names always win over bound keys; bound Secret values ride the transient
|
|
272
|
+
* secret channel and are masked in captured output. On a deployment whose workspaces do not
|
|
273
|
+
* run on Kubernetes, create is refused synchronously with the stable error code
|
|
274
|
+
* `runtime-env-references-unsupported` — no workspace is created.
|
|
275
|
+
*/
|
|
276
|
+
readonly envFrom?: readonly WorkspaceEnvFromSource[];
|
|
277
|
+
/**
|
|
278
|
+
* Kubernetes-runtime-only settings. `serviceAccountName` is an explicit TRUST GRANT: the
|
|
279
|
+
* workspace Pod runs under it, and with IRSA / Workload Identity the session agent holds that
|
|
280
|
+
* role's full permissions for the whole session — bind a least-privilege role intended for
|
|
281
|
+
* untrusted code. Honored only against the install's allowlist
|
|
282
|
+
* (`SEALANT_K8S_ALLOWED_WORKSPACE_SERVICE_ACCOUNTS`); other names fail the launch readable.
|
|
283
|
+
* The Kubernetes API token is never automounted regardless. Non-Kubernetes deployments refuse
|
|
284
|
+
* at create time with `runtime-env-references-unsupported`.
|
|
285
|
+
*/
|
|
286
|
+
readonly kubernetes?: {
|
|
287
|
+
readonly serviceAccountName?: string;
|
|
288
|
+
};
|
|
258
289
|
/** Runtime-managed services that need more than installing an OS package. */
|
|
259
290
|
readonly services?: WorkspaceServicesOptions;
|
|
260
291
|
/** When true (default), resolve only once the workspace runtime is live. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealant/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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,7 +26,7 @@
|
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@sealant/api-contracts": "^0.
|
|
29
|
+
"@sealant/api-contracts": "^0.24.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@effect/vitest": "4.0.0-beta.85",
|