@cofy-x/axern-sdk 0.7.0 → 0.8.1
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/README.md +5 -14
- package/dist/client/index.d.ts +39 -0
- package/dist/client/index.js +154 -1
- package/dist/index.d.ts +1 -1
- package/dist/node/archive.js +1 -1
- package/dist/node/attached_process.js +2 -2
- package/dist/node/capabilities.js +1 -1
- package/dist/node/computer_use.js +1 -1
- package/dist/node/context.d.ts +1 -1
- package/dist/node/context.js +1 -1
- package/dist/node/exec.js +1 -1
- package/dist/node/files.js +1 -1
- package/dist/node/process.d.ts +11 -6
- package/dist/node/process.js +45 -6
- package/dist/proto/axern/control/common/v1/common.proto +16 -1
- package/dist/proto/axern/control/run/v1/run.proto +3 -4
- package/dist/proto/axern/control/tunnel/v1/tunnel.proto +17 -19
- package/dist/proto/axern/node/sandbox/v1/node.proto +47 -0
- package/dist/sandbox/index.d.ts +2 -2
- package/dist/sandbox/index.js +13 -5
- package/dist/types.d.ts +0 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/proto/axern/control/gateway/v1/gateway.proto +0 -51
package/README.md
CHANGED
|
@@ -80,18 +80,6 @@ const sandbox = await new Sandbox({
|
|
|
80
80
|
|
|
81
81
|
`NetworkPolicy.allowDomains("example.com", "*.example.com")` allows only strict HTTP/HTTPS destinations validated by DNS plus HTTP Host or TLS SNI. `NetworkPolicy.strict({ cidrRules: [...] })` adds explicit TCP/UDP CIDR and port grants; `NetworkPolicy.denyAll()` allows no egress.
|
|
82
82
|
|
|
83
|
-
Run a tool from a separate image with `execImage` or `processImage`. OCI and Nydus refs use the same image field. When `mounts` is omitted, the SDK requests `/workspace -> /workspace`; pass `mounts: []` for no shared paths. Use `new Sandbox({ image })` when the image should be the sandbox rootfs with normal files, exec, process, tunnel, and lifecycle APIs; image-backed processes are temporary side processes attached to an existing sandbox.
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
import { workspaceMount } from "@cofy-x/axern-sdk";
|
|
87
|
-
|
|
88
|
-
const result = await sandbox.execImage("ghcr.io/cofy-x/agent:latest", "tool run", {
|
|
89
|
-
check: true,
|
|
90
|
-
mounts: [workspaceMount("/workspace")],
|
|
91
|
-
});
|
|
92
|
-
console.log(result.stdoutText());
|
|
93
|
-
```
|
|
94
|
-
|
|
95
83
|
`AxernClient` requires an explicit endpoint. Use `AxernClient.fromContext()` in interactive examples or `AxernClient.fromEnv()` in environment-driven automation. Neither the client constructor nor `Sandbox` silently reads the user directory.
|
|
96
84
|
|
|
97
85
|
## Configuration
|
|
@@ -106,6 +94,7 @@ Common options:
|
|
|
106
94
|
- `requestCpu`, `requestMemory`, `requestEphemeralStorage`: scheduler resource requests such as `500m`, `512MiB`, and `1GiB`; numeric CPU values are cores and numeric memory/storage values are bytes
|
|
107
95
|
- `limitCpu`, `limitMemory`, `limitEphemeralStorage`: runtime hard limits; numeric CPU values are cores and numeric memory/storage values are bytes
|
|
108
96
|
- `readyTimeoutMs`: Run allocation startup timeout
|
|
97
|
+
- `declaredOutputs`: bounded files or directory-as-tar outputs sealed before runtime cleanup
|
|
109
98
|
|
|
110
99
|
Tunnel options:
|
|
111
100
|
|
|
@@ -152,6 +141,8 @@ The SDK loads protobuf definitions through `@grpc/proto-loader`. Dynamic proto a
|
|
|
152
141
|
|
|
153
142
|
This SDK is Node.js-first. Browser automation runs as caller-owned workload software through process and Computer Use operations; generated TypeScript proto stubs and full control-plane administration APIs remain outside its public contract.
|
|
154
143
|
|
|
155
|
-
##
|
|
144
|
+
## Declared And Stream Output
|
|
145
|
+
|
|
146
|
+
Pass `declaredOutputs` when creating a Run or Sandbox, then use `getSealedOutputManifest(runId)` and `downloadSealedOutput(runId, outputId, writable)` after the Run becomes terminal. Full downloads verify size and SHA-256 while respecting the destination stream's backpressure. Declared output is Node-local for 15 minutes after cleanup starts: it survives axnoded restart but not Node-disk loss. Limits are 16 paths, 64 MiB per file, 256 MiB per tar, and 256 MiB total. It is not a persistent workspace or object store.
|
|
156
147
|
|
|
157
|
-
|
|
148
|
+
Attached Process queues at most 64 unread events, pauses the gRPC stream at the bound, and resumes below the low-water mark. `write`, `closeStdin`, signal, and resize promises resolve only after the gRPC write callback. Closing an attached process attempts `TERM`; durable workload termination remains Run cancellation. `Sandbox.close()` reports cleanup failures and does not wait for a terminal Run, so call `waitRun()` when terminal confirmation is required.
|
package/dist/client/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import * as grpc from "@grpc/grpc-js";
|
|
7
|
+
import type { Writable } from "node:stream";
|
|
7
8
|
import { AllocationClient } from "../node/client.js";
|
|
8
9
|
import type { ResourceQuantity } from "../resources.js";
|
|
9
10
|
import type { NetworkPolicy } from "../network-policy.js";
|
|
@@ -40,8 +41,37 @@ export interface CreateRunOptions {
|
|
|
40
41
|
limitCpu?: ResourceQuantity;
|
|
41
42
|
limitMemory?: ResourceQuantity;
|
|
42
43
|
limitEphemeralStorage?: ResourceQuantity;
|
|
44
|
+
declaredOutputs?: readonly DeclaredOutput[];
|
|
43
45
|
labels?: Record<string, string>;
|
|
44
46
|
}
|
|
47
|
+
export type DeclaredOutputFormat = "file" | "tar";
|
|
48
|
+
export interface DeclaredOutput {
|
|
49
|
+
path: string;
|
|
50
|
+
format: DeclaredOutputFormat;
|
|
51
|
+
mediaType?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface SealedOutput {
|
|
54
|
+
outputId: string;
|
|
55
|
+
path: string;
|
|
56
|
+
sizeBytes: number;
|
|
57
|
+
sha256: string;
|
|
58
|
+
mediaType: string;
|
|
59
|
+
format?: DeclaredOutputFormat;
|
|
60
|
+
status: "available" | "missing" | "rejected" | "capture_failed" | "node_unavailable" | "unspecified";
|
|
61
|
+
reason: string;
|
|
62
|
+
sealedAt?: Record<string, unknown>;
|
|
63
|
+
expiresAt?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
export interface ListOptions {
|
|
66
|
+
namespace?: string;
|
|
67
|
+
labels?: Record<string, string>;
|
|
68
|
+
cursor?: string;
|
|
69
|
+
pageSize?: number;
|
|
70
|
+
}
|
|
71
|
+
export interface ListResult<T> {
|
|
72
|
+
items: T[];
|
|
73
|
+
nextCursor: string;
|
|
74
|
+
}
|
|
45
75
|
export interface ExtensionCapability {
|
|
46
76
|
name: string;
|
|
47
77
|
value?: string;
|
|
@@ -68,10 +98,19 @@ export declare class AxernClient {
|
|
|
68
98
|
close(): void;
|
|
69
99
|
createEnvironment(options: CreateEnvironmentOptions): Promise<Record<string, unknown>>;
|
|
70
100
|
deleteEnvironment(environmentId: string): Promise<void>;
|
|
101
|
+
getEnvironment(environmentId: string): Promise<Record<string, unknown>>;
|
|
102
|
+
listEnvironments(options?: ListOptions): Promise<ListResult<Record<string, unknown>>>;
|
|
71
103
|
createRun(options: CreateRunOptions): Promise<Record<string, unknown>>;
|
|
104
|
+
getRun(runId: string): Promise<Record<string, unknown>>;
|
|
105
|
+
listRuns(options?: ListOptions & {
|
|
106
|
+
statuses?: number[];
|
|
107
|
+
}): Promise<ListResult<Record<string, unknown>>>;
|
|
108
|
+
waitRun(runId: string, timeoutMs?: number): Promise<Record<string, unknown>>;
|
|
72
109
|
cancelRun(runId: string): Promise<void>;
|
|
73
110
|
watchRun(runId: string, options?: WatchRunOptions): AsyncGenerator<Record<string, unknown>>;
|
|
74
111
|
readRunOutput(runId: string, options?: ReadRunOutputOptions): AsyncGenerator<Record<string, unknown>>;
|
|
112
|
+
getSealedOutputManifest(runId: string): Promise<SealedOutput[]>;
|
|
113
|
+
downloadSealedOutput(runId: string, outputId: string, destination: Writable): Promise<SealedOutput>;
|
|
75
114
|
allocation(allocationId: string): AllocationClient;
|
|
76
115
|
tunnelClient(): TunnelControlClient;
|
|
77
116
|
tunnelTransport(): GatewayTransportOptions;
|
package/dist/client/index.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import * as grpc from "@grpc/grpc-js";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
7
8
|
import { readFileSync } from "node:fs";
|
|
8
9
|
import { loadAxernContext, loadAxernEnv, normalizeProxyMode } from "../config/index.js";
|
|
9
|
-
import { mapRpcError } from "../errors/index.js";
|
|
10
|
+
import { SandboxStateError, SandboxTimeoutError, mapRpcError } from "../errors/index.js";
|
|
10
11
|
import { serviceConstructor, unary } from "../generated/proto.js";
|
|
11
12
|
import { AllocationClient } from "../node/client.js";
|
|
12
13
|
import { buildResourceSpec } from "../resources.js";
|
|
@@ -114,6 +115,24 @@ export class AxernClient {
|
|
|
114
115
|
throw mapRpcError(error, "delete environment");
|
|
115
116
|
}
|
|
116
117
|
}
|
|
118
|
+
async getEnvironment(environmentId) {
|
|
119
|
+
try {
|
|
120
|
+
const response = await unary(this.environmentControl, "GetEnvironment", { environment_id: required("environmentId", environmentId) });
|
|
121
|
+
return response.environment;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
throw mapRpcError(error, "get environment");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async listEnvironments(options = {}) {
|
|
128
|
+
try {
|
|
129
|
+
const response = await unary(this.environmentControl, "ListEnvironments", { filter: { namespace: options.namespace ?? "", labels: options.labels ?? {}, cursor: options.cursor ?? "", page_size: options.pageSize ?? 0 } });
|
|
130
|
+
return { items: response.environments ?? [], nextCursor: response.next_cursor ?? "" };
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw mapRpcError(error, "list environments");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
117
136
|
async createRun(options) {
|
|
118
137
|
const resources = buildResourceSpec(options);
|
|
119
138
|
try {
|
|
@@ -130,6 +149,11 @@ export class AxernClient {
|
|
|
130
149
|
extension_capability_requirements: (options.extensionCapabilities ?? []).map((capability) => ({
|
|
131
150
|
capability: { name: capability.name, value: capability.value ?? "" },
|
|
132
151
|
})),
|
|
152
|
+
declared_outputs: (options.declaredOutputs ?? []).map((output) => ({
|
|
153
|
+
path: output.path,
|
|
154
|
+
format: output.format === "file" ? 1 : 2,
|
|
155
|
+
media_type: output.mediaType ?? "",
|
|
156
|
+
})),
|
|
133
157
|
resources,
|
|
134
158
|
},
|
|
135
159
|
labels: options.labels ?? {},
|
|
@@ -140,6 +164,44 @@ export class AxernClient {
|
|
|
140
164
|
throw mapRpcError(error, "create run");
|
|
141
165
|
}
|
|
142
166
|
}
|
|
167
|
+
async getRun(runId) {
|
|
168
|
+
try {
|
|
169
|
+
const response = await unary(this.runControl, "GetRun", { run_id: required("runId", runId) });
|
|
170
|
+
return response.run;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
throw mapRpcError(error, "get run");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async listRuns(options = {}) {
|
|
177
|
+
try {
|
|
178
|
+
const response = await unary(this.runControl, "ListRuns", { filter: { namespace: options.namespace ?? "", labels: options.labels ?? {}, statuses: options.statuses ?? [], cursor: options.cursor ?? "", page_size: options.pageSize ?? 0 } });
|
|
179
|
+
return { items: response.runs ?? [], nextCursor: response.next_cursor ?? "" };
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
throw mapRpcError(error, "list runs");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async waitRun(runId, timeoutMs) {
|
|
186
|
+
const initial = await this.getRun(runId);
|
|
187
|
+
if (terminalRun(initial))
|
|
188
|
+
return initial;
|
|
189
|
+
const controller = new AbortController();
|
|
190
|
+
const timer = timeoutMs === undefined ? undefined : setTimeout(() => controller.abort(), timeoutMs);
|
|
191
|
+
try {
|
|
192
|
+
for await (const run of this.watchRun(runId, { afterVersion: Number(initial.version ?? 0), signal: controller.signal })) {
|
|
193
|
+
if (terminalRun(run))
|
|
194
|
+
return run;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
if (timer !== undefined)
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
}
|
|
201
|
+
if (controller.signal.aborted)
|
|
202
|
+
throw new SandboxTimeoutError(`run ${runId} wait timed out`);
|
|
203
|
+
throw new SandboxStateError(`run ${runId} watch ended before a terminal state`);
|
|
204
|
+
}
|
|
143
205
|
async cancelRun(runId) {
|
|
144
206
|
try {
|
|
145
207
|
await unary(this.runControl, "CancelRun", { run_id: required("runId", runId) });
|
|
@@ -238,6 +300,63 @@ export class AxernClient {
|
|
|
238
300
|
retryDelayMs = Math.min(retryDelayMs * 2, 2_000);
|
|
239
301
|
}
|
|
240
302
|
}
|
|
303
|
+
async getSealedOutputManifest(runId) {
|
|
304
|
+
const run = await this.getRun(runId);
|
|
305
|
+
const allocationId = String(run.allocation_id ?? "");
|
|
306
|
+
if (allocationId === "")
|
|
307
|
+
throw new Error(`run ${runId} has no allocation`);
|
|
308
|
+
const NodeSandbox = serviceConstructor(["axern", "node", "sandbox", "v1", "NodeSandbox"]);
|
|
309
|
+
const node = new NodeSandbox(this.endpoint, this.credentials, this.controlOptions);
|
|
310
|
+
try {
|
|
311
|
+
const response = await unary(node, "GetSealedOutputManifest", { allocation_id: allocationId });
|
|
312
|
+
return (response.outputs ?? []).map(sealedOutput);
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
throw mapRpcError(error, "get sealed output manifest", allocationId);
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
node.close();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async downloadSealedOutput(runId, outputId, destination) {
|
|
322
|
+
const outputs = await this.getSealedOutputManifest(runId);
|
|
323
|
+
const selected = outputs.find((output) => output.outputId === outputId);
|
|
324
|
+
if (selected === undefined || selected.status !== "available") {
|
|
325
|
+
throw new Error(`sealed output ${outputId} is not available`);
|
|
326
|
+
}
|
|
327
|
+
const run = await this.getRun(runId);
|
|
328
|
+
const allocationId = String(run.allocation_id ?? "");
|
|
329
|
+
const NodeSandbox = serviceConstructor(["axern", "node", "sandbox", "v1", "NodeSandbox"]);
|
|
330
|
+
const node = new NodeSandbox(this.endpoint, this.credentials, this.controlOptions);
|
|
331
|
+
const stream = serverStream(node, "DownloadSealedOutput", { allocation_id: allocationId, output_id: outputId, offset: "0" });
|
|
332
|
+
const digest = createHash("sha256");
|
|
333
|
+
let offset = 0;
|
|
334
|
+
try {
|
|
335
|
+
for await (const response of stream) {
|
|
336
|
+
const data = Buffer.from(response.data ?? []);
|
|
337
|
+
const nextOffset = Number(response.next_offset ?? offset + data.length);
|
|
338
|
+
if (nextOffset !== offset + data.length)
|
|
339
|
+
throw new Error("sealed output returned a non-contiguous offset");
|
|
340
|
+
digest.update(data);
|
|
341
|
+
await writeChunk(destination, data);
|
|
342
|
+
offset = nextOffset;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
347
|
+
throw mapRpcError(error, "download sealed output", allocationId);
|
|
348
|
+
}
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
finally {
|
|
352
|
+
node.close();
|
|
353
|
+
}
|
|
354
|
+
if (offset !== selected.sizeBytes)
|
|
355
|
+
throw new Error("sealed output size does not match its manifest");
|
|
356
|
+
if (digest.digest("hex") !== selected.sha256)
|
|
357
|
+
throw new Error("sealed output digest does not match its manifest");
|
|
358
|
+
return selected;
|
|
359
|
+
}
|
|
241
360
|
allocation(allocationId) {
|
|
242
361
|
return new AllocationClient({
|
|
243
362
|
allocationId: required("allocationId", allocationId),
|
|
@@ -261,6 +380,40 @@ function transientReadError(error) {
|
|
|
261
380
|
const code = error.code;
|
|
262
381
|
return code === grpc.status.UNAVAILABLE || code === grpc.status.DEADLINE_EXCEEDED;
|
|
263
382
|
}
|
|
383
|
+
function terminalRun(run) {
|
|
384
|
+
const status = Number(run.status ?? 0);
|
|
385
|
+
return status === 4 || status === 5 || status === 6;
|
|
386
|
+
}
|
|
387
|
+
function sealedOutput(value) {
|
|
388
|
+
const formats = { 1: "file", 2: "tar" };
|
|
389
|
+
const statuses = ["unspecified", "available", "missing", "rejected", "capture_failed", "node_unavailable"];
|
|
390
|
+
return {
|
|
391
|
+
outputId: String(value.output_id ?? ""),
|
|
392
|
+
path: String(value.path ?? ""),
|
|
393
|
+
sizeBytes: Number(value.size_bytes ?? 0),
|
|
394
|
+
sha256: String(value.sha256 ?? ""),
|
|
395
|
+
mediaType: String(value.media_type ?? ""),
|
|
396
|
+
format: formats[Number(value.format ?? 0)],
|
|
397
|
+
status: statuses[Number(value.status ?? 0)] ?? "unspecified",
|
|
398
|
+
reason: String(value.reason ?? ""),
|
|
399
|
+
sealedAt: value.sealed_at,
|
|
400
|
+
expiresAt: value.expires_at,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function writeChunk(destination, chunk) {
|
|
404
|
+
if (destination.write(chunk))
|
|
405
|
+
return Promise.resolve();
|
|
406
|
+
return new Promise((resolve, reject) => {
|
|
407
|
+
const cleanup = () => {
|
|
408
|
+
destination.off("drain", drained);
|
|
409
|
+
destination.off("error", failed);
|
|
410
|
+
};
|
|
411
|
+
const drained = () => { cleanup(); resolve(); };
|
|
412
|
+
const failed = (error) => { cleanup(); reject(error); };
|
|
413
|
+
destination.once("drain", drained);
|
|
414
|
+
destination.once("error", failed);
|
|
415
|
+
});
|
|
416
|
+
}
|
|
264
417
|
function sleep(milliseconds, signal) {
|
|
265
418
|
if (signal?.aborted)
|
|
266
419
|
return Promise.resolve();
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
export { AxernClient } from "./client/index.js";
|
|
7
|
-
export type { AxernClientOptions, CreateEnvironmentOptions, CreateRunOptions, } from "./client/index.js";
|
|
7
|
+
export type { AxernClientOptions, CreateEnvironmentOptions, CreateRunOptions, DeclaredOutput, DeclaredOutputFormat, ListOptions, ListResult, SealedOutput, } from "./client/index.js";
|
|
8
8
|
export { loadAxernContext, loadAxernEnv } from "./config/index.js";
|
|
9
9
|
export type { AxernConfig } from "./config/index.js";
|
|
10
10
|
export { AxernError, AxernRpcError, isNotFound, isCancelled, isUnavailable, errorRetryable, isPermissionDenied, isTimeout, rpcCode, SandboxExecError, SandboxStateError, SandboxTimeoutError, SandboxValidationError, } from "./errors/index.js";
|
package/dist/node/archive.js
CHANGED
|
@@ -8,7 +8,7 @@ import { nonEmptyPath } from "../validation.js";
|
|
|
8
8
|
import { downloadArchiveStream, uploadArchiveStream } from "./streams.js";
|
|
9
9
|
export async function uploadArchive(ctx, path, chunks, options = {}) {
|
|
10
10
|
try {
|
|
11
|
-
await ctx.withAuthRetry(
|
|
11
|
+
await ctx.withAuthRetry((client) => uploadArchiveStream(client, ctx.authRequest({
|
|
12
12
|
path: nonEmptyPath(path),
|
|
13
13
|
format: 1,
|
|
14
14
|
create_parents: options.createParents ?? true,
|
|
@@ -18,12 +18,12 @@ export async function process(ctx, command, options = {}) {
|
|
|
18
18
|
call,
|
|
19
19
|
closeClient: () => client.close(),
|
|
20
20
|
});
|
|
21
|
-
call.write({
|
|
21
|
+
await new Promise((resolve, reject) => call.write({
|
|
22
22
|
open: ctx.authRequest({
|
|
23
23
|
spec: execSpec(argv, options),
|
|
24
24
|
...(initialSize === undefined ? {} : { initial_size: initialSize }),
|
|
25
25
|
}),
|
|
26
|
-
});
|
|
26
|
+
}, (error) => error == null ? resolve() : reject(error)));
|
|
27
27
|
try {
|
|
28
28
|
await sandboxProcess.waitReady();
|
|
29
29
|
return sandboxProcess;
|
|
@@ -7,7 +7,7 @@ import { mapRpcError } from "../errors/index.js";
|
|
|
7
7
|
import { unary } from "../generated/proto.js";
|
|
8
8
|
export async function capabilityStatus(ctx, options = {}) {
|
|
9
9
|
try {
|
|
10
|
-
const response = await ctx.withAuthRetry(
|
|
10
|
+
const response = await ctx.withAuthRetry((client) => unary(client, "CapabilityStatus", ctx.authRequest({}), options.rpcTimeoutMs));
|
|
11
11
|
return {
|
|
12
12
|
ready: response.ready === true,
|
|
13
13
|
capabilities: strings(response.capabilities),
|
|
@@ -68,7 +68,7 @@ export async function computerUseKeyboard(ctx, options = {}) {
|
|
|
68
68
|
}
|
|
69
69
|
async function computerUseUnary(ctx, method, payload, rpcTimeoutMs) {
|
|
70
70
|
try {
|
|
71
|
-
return await ctx.withAuthRetry(
|
|
71
|
+
return await ctx.withAuthRetry((client) => unary(client, method, ctx.authRequest(payload), rpcTimeoutMs));
|
|
72
72
|
}
|
|
73
73
|
catch (error) {
|
|
74
74
|
throw mapRpcError(error, `sandbox ${method}`, ctx.allocationId);
|
package/dist/node/context.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare class NodeClientContext {
|
|
|
16
16
|
private readonly credentials;
|
|
17
17
|
private readonly channelOptions;
|
|
18
18
|
constructor(options: NodeClientContextOptions);
|
|
19
|
-
withAuthRetry<T>(
|
|
19
|
+
withAuthRetry<T>(operation: (client: grpc.Client) => Promise<T>): Promise<T>;
|
|
20
20
|
rpcClient(): grpc.Client;
|
|
21
21
|
authRequest(payload: Record<string, unknown>): Record<string, unknown>;
|
|
22
22
|
}
|
package/dist/node/context.js
CHANGED
|
@@ -15,7 +15,7 @@ export class NodeClientContext {
|
|
|
15
15
|
this.credentials = options.credentials;
|
|
16
16
|
this.channelOptions = options.channelOptions ?? {};
|
|
17
17
|
}
|
|
18
|
-
async withAuthRetry(
|
|
18
|
+
async withAuthRetry(operation) {
|
|
19
19
|
const client = this.rpcClient();
|
|
20
20
|
try {
|
|
21
21
|
return await operation(client);
|
package/dist/node/exec.js
CHANGED
|
@@ -9,7 +9,7 @@ import { normalizeCommand } from "../validation.js";
|
|
|
9
9
|
export async function exec(ctx, command, options = {}) {
|
|
10
10
|
const argv = normalizeCommand(command);
|
|
11
11
|
try {
|
|
12
|
-
const response = await ctx.withAuthRetry(
|
|
12
|
+
const response = await ctx.withAuthRetry(async (client) => unary(client, "Exec", ctx.authRequest({
|
|
13
13
|
spec: execSpec(argv, options),
|
|
14
14
|
}), options.rpcTimeoutMs));
|
|
15
15
|
const result = execResult(response);
|
package/dist/node/files.js
CHANGED
|
@@ -70,7 +70,7 @@ export async function touch(ctx, path, options = {}) {
|
|
|
70
70
|
}
|
|
71
71
|
async function fileUnary(ctx, method, payload) {
|
|
72
72
|
try {
|
|
73
|
-
return await ctx.withAuthRetry(
|
|
73
|
+
return await ctx.withAuthRetry((client) => unary(client, method, ctx.authRequest(payload)));
|
|
74
74
|
}
|
|
75
75
|
catch (error) {
|
|
76
76
|
throw mapRpcError(error, `sandbox ${method}`, ctx.allocationId);
|
package/dist/node/process.d.ts
CHANGED
|
@@ -19,18 +19,23 @@ export declare class SandboxProcess {
|
|
|
19
19
|
private error;
|
|
20
20
|
private ended;
|
|
21
21
|
private exit?;
|
|
22
|
+
private paused;
|
|
23
|
+
private closed;
|
|
24
|
+
private static readonly maxQueuedEvents;
|
|
25
|
+
private static readonly resumeQueuedEvents;
|
|
22
26
|
constructor(options: SandboxProcessOptions);
|
|
23
|
-
write(data: Buffer | Uint8Array | string): void
|
|
24
|
-
closeStdin(): void
|
|
25
|
-
resize(cols: number, rows: number): void
|
|
26
|
-
signal(signal: string): void
|
|
27
|
-
terminate(): void
|
|
28
|
-
kill(): void
|
|
27
|
+
write(data: Buffer | Uint8Array | string): Promise<void>;
|
|
28
|
+
closeStdin(): Promise<void>;
|
|
29
|
+
resize(cols: number, rows: number): Promise<void>;
|
|
30
|
+
signal(signal: string): Promise<void>;
|
|
31
|
+
terminate(): Promise<void>;
|
|
32
|
+
kill(): Promise<void>;
|
|
29
33
|
waitReady(): Promise<void>;
|
|
30
34
|
wait(): Promise<ProcessResult>;
|
|
31
35
|
close(): Promise<void>;
|
|
32
36
|
events(): AsyncIterable<ProcessEvent>;
|
|
33
37
|
private nextEvent;
|
|
34
38
|
private enqueue;
|
|
39
|
+
private writeRequest;
|
|
35
40
|
private finish;
|
|
36
41
|
}
|
package/dist/node/process.js
CHANGED
|
@@ -13,6 +13,10 @@ export class SandboxProcess {
|
|
|
13
13
|
error;
|
|
14
14
|
ended = false;
|
|
15
15
|
exit;
|
|
16
|
+
paused = false;
|
|
17
|
+
closed = false;
|
|
18
|
+
static maxQueuedEvents = 64;
|
|
19
|
+
static resumeQueuedEvents = 32;
|
|
16
20
|
constructor(options) {
|
|
17
21
|
this.allocationId = options.allocationId;
|
|
18
22
|
this.call = options.call;
|
|
@@ -25,22 +29,22 @@ export class SandboxProcess {
|
|
|
25
29
|
this.call.on("end", () => this.finish());
|
|
26
30
|
}
|
|
27
31
|
write(data) {
|
|
28
|
-
this.
|
|
32
|
+
return this.writeRequest({ stdin: Buffer.isBuffer(data) ? data : Buffer.from(data) });
|
|
29
33
|
}
|
|
30
34
|
closeStdin() {
|
|
31
|
-
this.
|
|
35
|
+
return this.writeRequest({ close_stdin: true });
|
|
32
36
|
}
|
|
33
37
|
resize(cols, rows) {
|
|
34
|
-
this.
|
|
38
|
+
return this.writeRequest({ resize: { cols, rows } });
|
|
35
39
|
}
|
|
36
40
|
signal(signal) {
|
|
37
|
-
this.
|
|
41
|
+
return this.writeRequest({ signal: { signal } });
|
|
38
42
|
}
|
|
39
43
|
terminate() {
|
|
40
|
-
this.signal("TERM");
|
|
44
|
+
return this.signal("TERM");
|
|
41
45
|
}
|
|
42
46
|
kill() {
|
|
43
|
-
this.signal("KILL");
|
|
47
|
+
return this.signal("KILL");
|
|
44
48
|
}
|
|
45
49
|
async waitReady() {
|
|
46
50
|
const next = await this.nextEvent();
|
|
@@ -69,7 +73,14 @@ export class SandboxProcess {
|
|
|
69
73
|
throw new Error("sandbox process stream ended before exit");
|
|
70
74
|
}
|
|
71
75
|
async close() {
|
|
76
|
+
if (this.closed)
|
|
77
|
+
return;
|
|
78
|
+
if (!this.ended && this.exit === undefined) {
|
|
79
|
+
await this.terminate().catch(() => undefined);
|
|
80
|
+
}
|
|
81
|
+
this.closed = true;
|
|
72
82
|
this.call.end();
|
|
83
|
+
this.call.cancel();
|
|
73
84
|
this.closeClient();
|
|
74
85
|
}
|
|
75
86
|
async *events() {
|
|
@@ -90,6 +101,10 @@ export class SandboxProcess {
|
|
|
90
101
|
nextEvent() {
|
|
91
102
|
const event = this.queue.shift();
|
|
92
103
|
if (event !== undefined) {
|
|
104
|
+
if (this.paused && this.queue.length <= SandboxProcess.resumeQueuedEvents) {
|
|
105
|
+
this.paused = false;
|
|
106
|
+
this.call.resume();
|
|
107
|
+
}
|
|
93
108
|
return Promise.resolve({ done: false, value: event });
|
|
94
109
|
}
|
|
95
110
|
if (this.ended) {
|
|
@@ -108,8 +123,32 @@ export class SandboxProcess {
|
|
|
108
123
|
waiter({ done: false, value: event });
|
|
109
124
|
}
|
|
110
125
|
else {
|
|
126
|
+
if (this.queue.length >= SandboxProcess.maxQueuedEvents) {
|
|
127
|
+
this.error = new Error("sandbox process consumer is too slow; event queue limit exceeded");
|
|
128
|
+
this.call.cancel();
|
|
129
|
+
this.finish();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
111
132
|
this.queue.push(event);
|
|
133
|
+
if (!this.paused && this.queue.length >= SandboxProcess.maxQueuedEvents) {
|
|
134
|
+
this.paused = true;
|
|
135
|
+
this.call.pause();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
writeRequest(request) {
|
|
140
|
+
if (this.closed || this.ended) {
|
|
141
|
+
return Promise.reject(new Error("sandbox process stream is closed"));
|
|
112
142
|
}
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
this.call.write(request, (error) => {
|
|
145
|
+
if (error !== undefined && error !== null) {
|
|
146
|
+
reject(mapRpcError(error, "sandbox process write", this.allocationId));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
resolve();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
113
152
|
}
|
|
114
153
|
finish() {
|
|
115
154
|
if (this.ended) {
|
|
@@ -100,7 +100,21 @@ message SecretFile {
|
|
|
100
100
|
message ImageMount {
|
|
101
101
|
string image = 1;
|
|
102
102
|
string target = 2;
|
|
103
|
-
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
enum DeclaredOutputFormat {
|
|
106
|
+
DECLARED_OUTPUT_FORMAT_UNSPECIFIED = 0;
|
|
107
|
+
DECLARED_OUTPUT_FORMAT_FILE = 1;
|
|
108
|
+
DECLARED_OUTPUT_FORMAT_TAR = 2;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// DeclaredOutput identifies one bounded Allocation-local result that must be
|
|
112
|
+
// sealed before runtime cleanup. It is a Run output contract, not a durable
|
|
113
|
+
// artifact or workspace identity.
|
|
114
|
+
message DeclaredOutput {
|
|
115
|
+
string path = 1;
|
|
116
|
+
DeclaredOutputFormat format = 2;
|
|
117
|
+
string media_type = 3;
|
|
104
118
|
}
|
|
105
119
|
|
|
106
120
|
message ExecutionConfig {
|
|
@@ -114,6 +128,7 @@ message ExecutionConfig {
|
|
|
114
128
|
repeated SecretEnvVar secret_env = 8;
|
|
115
129
|
repeated SecretFile secret_files = 9;
|
|
116
130
|
repeated ImageMount image_mounts = 10;
|
|
131
|
+
repeated DeclaredOutput declared_outputs = 11;
|
|
117
132
|
}
|
|
118
133
|
|
|
119
134
|
// AllocationLifecycleState tracks only placement and infrastructure cleanup.
|
|
@@ -36,13 +36,12 @@ message Run {
|
|
|
36
36
|
// Latest allocation capability condition projection. It is independent
|
|
37
37
|
// from Run lifecycle status and message.
|
|
38
38
|
axern.control.capability.v1.CapabilityConditionSet capability_conditions = 14;
|
|
39
|
-
string node_id = 15;
|
|
40
39
|
// Immutable Environment input frozen atomically with Run admission. The
|
|
41
40
|
// source record may be deleted after this Run is created.
|
|
42
|
-
axern.control.environment.v1.EnvironmentSpec environment_spec =
|
|
43
|
-
axern.control.environment.v1.ResolvedEnvironmentSpec resolved_environment_spec =
|
|
41
|
+
axern.control.environment.v1.EnvironmentSpec environment_spec = 15;
|
|
42
|
+
axern.control.environment.v1.ResolvedEnvironmentSpec resolved_environment_spec = 16;
|
|
44
43
|
// Node-local stdout/stderr availability deadline; node loss may make bytes unavailable earlier.
|
|
45
|
-
google.protobuf.Timestamp output_expires_at =
|
|
44
|
+
google.protobuf.Timestamp output_expires_at = 17;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
message RunListFilter {
|
|
@@ -66,22 +66,21 @@ enum TunnelSessionEventReasonCode {
|
|
|
66
66
|
message TunnelSession {
|
|
67
67
|
string session_id = 1;
|
|
68
68
|
string allocation_id = 2;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
string
|
|
74
|
-
|
|
75
|
-
google.protobuf.Timestamp
|
|
76
|
-
google.protobuf.Timestamp
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
google.protobuf.Timestamp
|
|
80
|
-
|
|
81
|
-
int64
|
|
82
|
-
|
|
83
|
-
string
|
|
84
|
-
string creator_principal_id = 18;
|
|
69
|
+
int32 remote_port = 3;
|
|
70
|
+
string client_edge_target = 4;
|
|
71
|
+
TunnelSessionStatus status = 5;
|
|
72
|
+
string reason = 6;
|
|
73
|
+
string bound_addr = 7;
|
|
74
|
+
google.protobuf.Timestamp created_at = 8;
|
|
75
|
+
google.protobuf.Timestamp updated_at = 9;
|
|
76
|
+
google.protobuf.Timestamp expires_at = 10;
|
|
77
|
+
string relay_id = 11;
|
|
78
|
+
google.protobuf.Timestamp ready_at = 12;
|
|
79
|
+
google.protobuf.Timestamp last_peer_event_at = 13;
|
|
80
|
+
int64 bytes_in = 14;
|
|
81
|
+
int64 bytes_out = 15;
|
|
82
|
+
string namespace = 16;
|
|
83
|
+
string creator_principal_id = 17;
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
message TunnelSessionEvent {
|
|
@@ -122,9 +121,8 @@ message GetTunnelSessionResponse {
|
|
|
122
121
|
|
|
123
122
|
message ListTunnelSessionsRequest {
|
|
124
123
|
string allocation_id = 1;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
string namespace = 4;
|
|
124
|
+
bool include_terminal = 2;
|
|
125
|
+
string namespace = 3;
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
message ListTunnelSessionsResponse {
|
|
@@ -3,6 +3,8 @@ syntax = "proto3";
|
|
|
3
3
|
package axern.node.sandbox.v1;
|
|
4
4
|
|
|
5
5
|
import "axern/common/file/v1/file.proto";
|
|
6
|
+
import "axern/control/common/v1/common.proto";
|
|
7
|
+
import "google/protobuf/timestamp.proto";
|
|
6
8
|
|
|
7
9
|
option go_package = "github.com/cofy-x/axern/sdk/go/gen/axern/node/sandbox/v1;nodesandboxv1";
|
|
8
10
|
|
|
@@ -92,6 +94,49 @@ message ReadOutputResponse {
|
|
|
92
94
|
int64 observed_at_unix_milli = 6;
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
enum SealedOutputStatus {
|
|
98
|
+
SEALED_OUTPUT_STATUS_UNSPECIFIED = 0;
|
|
99
|
+
SEALED_OUTPUT_STATUS_AVAILABLE = 1;
|
|
100
|
+
SEALED_OUTPUT_STATUS_MISSING = 2;
|
|
101
|
+
SEALED_OUTPUT_STATUS_REJECTED = 3;
|
|
102
|
+
SEALED_OUTPUT_STATUS_CAPTURE_FAILED = 4;
|
|
103
|
+
SEALED_OUTPUT_STATUS_NODE_UNAVAILABLE = 5;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
message SealedOutput {
|
|
107
|
+
string output_id = 1;
|
|
108
|
+
string path = 2;
|
|
109
|
+
int64 size_bytes = 3;
|
|
110
|
+
string sha256 = 4;
|
|
111
|
+
string media_type = 5;
|
|
112
|
+
axern.control.common.v1.DeclaredOutputFormat format = 6;
|
|
113
|
+
SealedOutputStatus status = 7;
|
|
114
|
+
string reason = 8;
|
|
115
|
+
google.protobuf.Timestamp sealed_at = 9;
|
|
116
|
+
google.protobuf.Timestamp expires_at = 10;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
message GetSealedOutputManifestRequest {
|
|
120
|
+
string allocation_id = 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
message GetSealedOutputManifestResponse {
|
|
124
|
+
repeated SealedOutput outputs = 1;
|
|
125
|
+
google.protobuf.Timestamp expires_at = 2;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
message DownloadSealedOutputRequest {
|
|
129
|
+
string allocation_id = 1;
|
|
130
|
+
string output_id = 2;
|
|
131
|
+
int64 offset = 3;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
message DownloadSealedOutputResponse {
|
|
135
|
+
bytes data = 1;
|
|
136
|
+
int64 next_offset = 2;
|
|
137
|
+
bool eof = 3;
|
|
138
|
+
}
|
|
139
|
+
|
|
95
140
|
// Capabilities
|
|
96
141
|
|
|
97
142
|
message CapabilityStatusRequest {
|
|
@@ -338,6 +383,8 @@ service NodeSandbox {
|
|
|
338
383
|
rpc Exec(ExecRequest) returns (ExecResponse) {}
|
|
339
384
|
rpc Process(stream ProcessRequest) returns (stream ProcessResponse) {}
|
|
340
385
|
rpc ReadOutput(ReadOutputRequest) returns (stream ReadOutputResponse) {}
|
|
386
|
+
rpc GetSealedOutputManifest(GetSealedOutputManifestRequest) returns (GetSealedOutputManifestResponse) {}
|
|
387
|
+
rpc DownloadSealedOutput(DownloadSealedOutputRequest) returns (stream DownloadSealedOutputResponse) {}
|
|
341
388
|
rpc CapabilityStatus(CapabilityStatusRequest) returns (CapabilityStatusResponse) {}
|
|
342
389
|
rpc StatFile(StatFileRequest) returns (StatFileResponse) {}
|
|
343
390
|
rpc ListDir(ListDirRequest) returns (ListDirResponse) {}
|
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { AxernClient } from "../client/index.js";
|
|
7
|
-
import type { ExtensionCapability } from "../client/index.js";
|
|
7
|
+
import type { DeclaredOutput, ExtensionCapability } from "../client/index.js";
|
|
8
8
|
import type { SandboxProcess } from "../node/process.js";
|
|
9
9
|
import type { ResourceQuantity } from "../resources.js";
|
|
10
10
|
import type { NetworkPolicy } from "../network-policy.js";
|
|
@@ -20,6 +20,7 @@ export interface SandboxOptions {
|
|
|
20
20
|
cwd?: string;
|
|
21
21
|
networkPolicy?: NetworkPolicy;
|
|
22
22
|
extensionCapabilities?: readonly ExtensionCapability[];
|
|
23
|
+
declaredOutputs?: readonly DeclaredOutput[];
|
|
23
24
|
requestCpu?: ResourceQuantity;
|
|
24
25
|
requestMemory?: ResourceQuantity;
|
|
25
26
|
requestEphemeralStorage?: ResourceQuantity;
|
|
@@ -36,7 +37,6 @@ export interface SandboxState {
|
|
|
36
37
|
environmentId: string;
|
|
37
38
|
runId: string;
|
|
38
39
|
allocationId: string;
|
|
39
|
-
nodeId: string;
|
|
40
40
|
startedAt: Date;
|
|
41
41
|
}
|
|
42
42
|
export interface SandboxMetadata extends SandboxState {
|
package/dist/sandbox/index.js
CHANGED
|
@@ -60,6 +60,7 @@ export class Sandbox {
|
|
|
60
60
|
cwd: this.options.cwd,
|
|
61
61
|
networkPolicy: this.options.networkPolicy,
|
|
62
62
|
extensionCapabilities: this.options.extensionCapabilities,
|
|
63
|
+
declaredOutputs: this.options.declaredOutputs,
|
|
63
64
|
requestCpu: this.options.requestCpu,
|
|
64
65
|
requestMemory: this.options.requestMemory,
|
|
65
66
|
requestEphemeralStorage: this.options.requestEphemeralStorage,
|
|
@@ -74,7 +75,6 @@ export class Sandbox {
|
|
|
74
75
|
environmentId,
|
|
75
76
|
runId: this.runId,
|
|
76
77
|
allocationId: String(runningRun.allocation_id ?? ""),
|
|
77
|
-
nodeId: String(runningRun.node_id ?? ""),
|
|
78
78
|
startedAt: new Date(),
|
|
79
79
|
};
|
|
80
80
|
this.currentMetadata = sandboxMetadata(this.options, this.currentState);
|
|
@@ -93,11 +93,17 @@ export class Sandbox {
|
|
|
93
93
|
return this;
|
|
94
94
|
}
|
|
95
95
|
catch (error) {
|
|
96
|
-
|
|
96
|
+
try {
|
|
97
|
+
await this.close();
|
|
98
|
+
}
|
|
99
|
+
catch (cleanupError) {
|
|
100
|
+
throw new AggregateError([error, cleanupError], "sandbox start and cleanup failed");
|
|
101
|
+
}
|
|
97
102
|
throw error;
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
async close() {
|
|
106
|
+
const errors = [];
|
|
101
107
|
const runId = this.runId;
|
|
102
108
|
const tunnelRuntime = this.tunnelRuntime;
|
|
103
109
|
this.runId = "";
|
|
@@ -105,17 +111,19 @@ export class Sandbox {
|
|
|
105
111
|
this.currentState = undefined;
|
|
106
112
|
this.currentMetadata = undefined;
|
|
107
113
|
if (tunnelRuntime !== undefined) {
|
|
108
|
-
await tunnelRuntime.stop().catch(() =>
|
|
114
|
+
await tunnelRuntime.stop().catch((error) => errors.push(error));
|
|
109
115
|
}
|
|
110
116
|
if (runId !== "") {
|
|
111
|
-
await this.client.cancelRun(runId).catch(() =>
|
|
117
|
+
await this.client.cancelRun(runId).catch((error) => errors.push(error));
|
|
112
118
|
}
|
|
113
119
|
if (this.createdEnvironment && this.environmentId !== "") {
|
|
114
120
|
const environmentId = this.environmentId;
|
|
115
121
|
this.environmentId = "";
|
|
116
122
|
this.createdEnvironment = false;
|
|
117
|
-
await this.client.deleteEnvironment(environmentId).catch(() =>
|
|
123
|
+
await this.client.deleteEnvironment(environmentId).catch((error) => errors.push(error));
|
|
118
124
|
}
|
|
125
|
+
if (errors.length > 0)
|
|
126
|
+
throw new AggregateError(errors, "sandbox cleanup failed");
|
|
119
127
|
}
|
|
120
128
|
async exec(command, options = {}) {
|
|
121
129
|
return this.nodeClient().exec(command, options);
|
package/dist/types.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export interface ExecOptions {
|
|
|
12
12
|
user?: string;
|
|
13
13
|
tty?: boolean;
|
|
14
14
|
check?: boolean;
|
|
15
|
-
leaseTtlSeconds?: number;
|
|
16
15
|
rpcTimeoutMs?: number;
|
|
17
16
|
}
|
|
18
17
|
export interface ExecResult {
|
|
@@ -91,11 +90,9 @@ export interface DownloadDirOptions {
|
|
|
91
90
|
export interface UploadArchiveOptions {
|
|
92
91
|
createParents?: boolean;
|
|
93
92
|
overwrite?: boolean;
|
|
94
|
-
leaseTtlSeconds?: number;
|
|
95
93
|
rpcTimeoutMs?: number;
|
|
96
94
|
}
|
|
97
95
|
export interface DownloadArchiveOptions {
|
|
98
|
-
leaseTtlSeconds?: number;
|
|
99
96
|
rpcTimeoutMs?: number;
|
|
100
97
|
}
|
|
101
98
|
export interface TunnelOptions {
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
syntax = "proto3";
|
|
2
|
-
|
|
3
|
-
package axern.control.gateway.v1;
|
|
4
|
-
|
|
5
|
-
option go_package = "github.com/cofy-x/axern/sdk/go/gen/axern/control/gateway/v1;gatewayv1";
|
|
6
|
-
|
|
7
|
-
import "google/protobuf/timestamp.proto";
|
|
8
|
-
import "google/protobuf/empty.proto";
|
|
9
|
-
message ResolveAllocationTerminalRequest {
|
|
10
|
-
string allocation_id = 1;
|
|
11
|
-
int64 ttl_seconds = 2;
|
|
12
|
-
string credential_fingerprint = 3;
|
|
13
|
-
AllocationAccessPurpose purpose = 4;
|
|
14
|
-
string credential_kind = 5;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
enum AllocationAccessPurpose {
|
|
18
|
-
ALLOCATION_ACCESS_PURPOSE_UNSPECIFIED = 0;
|
|
19
|
-
ALLOCATION_ACCESS_PURPOSE_INTERACTIVE = 1;
|
|
20
|
-
ALLOCATION_ACCESS_PURPOSE_RUN_OUTPUT = 2;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
message ResolveAllocationTerminalResponse {
|
|
24
|
-
string allocation_id = 1;
|
|
25
|
-
string run_id = 2;
|
|
26
|
-
string node_id = 3;
|
|
27
|
-
string node_target = 4;
|
|
28
|
-
AllocationAccessGrant access_grant = 5;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
message AllocationAccessGrant {
|
|
32
|
-
string grant_id = 1;
|
|
33
|
-
string allocation_id = 2;
|
|
34
|
-
string node_id = 3;
|
|
35
|
-
string plaintext_token = 4;
|
|
36
|
-
google.protobuf.Timestamp expires_at = 5;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
message ResolveTunnelRelayTargetRequest {
|
|
40
|
-
string session_id = 1;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
message ResolveTunnelRelayTargetResponse {
|
|
44
|
-
string node_edge_target = 1;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
service GatewayControl {
|
|
48
|
-
rpc AuthorizeAllocationAccess(ResolveAllocationTerminalRequest) returns (google.protobuf.Empty) {}
|
|
49
|
-
rpc ResolveAllocationTerminal(ResolveAllocationTerminalRequest) returns (ResolveAllocationTerminalResponse) {}
|
|
50
|
-
rpc ResolveTunnelRelayTarget(ResolveTunnelRelayTargetRequest) returns (ResolveTunnelRelayTargetResponse) {}
|
|
51
|
-
}
|