hyperbrane 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -11
- package/dist/agent/agentClient.d.ts +5 -0
- package/dist/agent/agentClient.js +4 -0
- package/dist/agent/agentService.d.ts +9 -30
- package/dist/agent/agentService.js +62 -293
- package/dist/agent/agentStorage.d.ts +1 -20
- package/dist/agent/agentStorage.js +0 -30
- package/dist/agent/api.d.ts +89 -133
- package/dist/agent/api.js +4 -4
- package/dist/agent/client.d.ts +3 -1
- package/dist/agent/client.js +2 -3
- package/dist/agent/control.d.ts +23 -0
- package/dist/agent/control.js +479 -0
- package/dist/agent/hostTranscript.d.ts +0 -6
- package/dist/agent/hostTranscript.js +3 -14
- package/dist/agent/session/backend.d.ts +17 -30
- package/dist/agent/session/claude/home.d.ts +0 -1
- package/dist/agent/session/claude/home.js +0 -1
- package/dist/agent/session/claude/provision.d.ts +10 -0
- package/dist/agent/session/claude/provision.js +17 -0
- package/dist/agent/session/claude/transcript.d.ts +2 -7
- package/dist/agent/session/claude/transcript.js +68 -14
- package/dist/agent/session/client.d.ts +1 -10
- package/dist/agent/session/client.js +0 -3
- package/dist/agent/session/codex/provision.d.ts +14 -0
- package/dist/agent/session/codex/provision.js +25 -0
- package/dist/agent/session/fileTranscript.d.ts +6 -49
- package/dist/agent/session/fileTranscript.js +26 -82
- package/dist/agent/session/install.d.ts +5 -0
- package/dist/agent/session/install.js +35 -0
- package/dist/agent/session/sessionStorage.d.ts +4 -35
- package/dist/agent/session/sessionStorage.js +10 -16
- package/dist/agent/session/sharedConnection.d.ts +0 -8
- package/dist/agent/session/sharedConnection.js +0 -7
- package/dist/agent/session/storedTranscripts.d.ts +1 -6
- package/dist/agent/session/storedTranscripts.js +0 -3
- package/dist/agent/session/worker/jsonRpc.d.ts +2 -13
- package/dist/agent/session/worker/jsonRpc.js +2 -11
- package/dist/agent/session/worker/protocol.d.ts +27 -18
- package/dist/agent/session/worker/protocol.js +32 -16
- package/dist/agent/session/worker/workerParams.d.ts +0 -5
- package/dist/agent/session/worker/workerParams.js +15 -14
- package/dist/agent/session/workerConnection.d.ts +2 -13
- package/dist/agent/session/workerConnection.js +7 -12
- package/dist/agent/session/workerGatewayConnection.d.ts +18 -0
- package/dist/agent/session/workerGatewayConnection.js +86 -0
- package/dist/agent/vendor-types/manifest.json +87 -0
- package/dist/agent/workerBundle.d.ts +4 -19
- package/dist/agent/workerBundle.generated.js +1 -1
- package/dist/agent/workerBundle.js +3 -30
- package/dist/agent/workerReplacement.d.ts +3 -0
- package/dist/agent/workerReplacement.js +49 -0
- package/dist/cli/agent.js +44 -16
- package/dist/cli/command.d.ts +10 -11
- package/dist/cli/command.js +0 -4
- package/dist/cli/dimension.js +6 -6
- package/dist/cli/gateway.js +3 -6
- package/dist/cli/main.js +14 -31
- package/dist/cli/streamPrinter.d.ts +2 -10
- package/dist/cli/streamPrinter.js +16 -46
- package/dist/cli/table.d.ts +0 -3
- package/dist/cli/table.js +0 -4
- package/dist/dimension/api.d.ts +39 -27
- package/dist/dimension/api.js +28 -47
- package/dist/dimension/client.d.ts +5 -0
- package/dist/dimension/client.js +4 -0
- package/dist/dimension/control.d.ts +21 -0
- package/dist/dimension/control.js +328 -0
- package/dist/dimension/image.d.ts +0 -5
- package/dist/dimension/image.js +0 -8
- package/dist/dimension/imageFiles.generated.js +1 -1
- package/dist/dimension/paths.d.ts +5 -4
- package/dist/dimension/paths.js +15 -6
- package/dist/dimension/service.d.ts +8 -21
- package/dist/dimension/service.js +60 -224
- package/dist/dimension/transport-worker.d.ts +1 -0
- package/dist/dimension/transport-worker.js +151 -0
- package/dist/dimension/transportBundle.d.ts +2 -0
- package/dist/dimension/transportBundle.generated.d.ts +1 -0
- package/dist/dimension/transportBundle.generated.js +2 -0
- package/dist/dimension/transportBundle.js +4 -0
- package/dist/dimension/transportClient.d.ts +10 -0
- package/dist/dimension/transportClient.js +115 -0
- package/dist/dimension/transportProtocol.d.ts +53 -0
- package/dist/dimension/transportProtocol.js +8 -0
- package/dist/index.d.ts +5 -8
- package/dist/index.js +5 -16
- package/dist/lib/control.d.ts +8 -0
- package/dist/lib/control.js +62 -0
- package/dist/lib/docker.d.ts +0 -22
- package/dist/lib/docker.js +0 -10
- package/dist/lib/image.d.ts +0 -3
- package/dist/lib/image.js +0 -2
- package/dist/lib/jsonDirectory.d.ts +0 -13
- package/dist/lib/jsonDirectory.js +10 -15
- package/dist/lib/scriptBundle.d.ts +6 -0
- package/dist/lib/scriptBundle.js +28 -0
- package/dist/lib/sh.d.ts +2 -0
- package/dist/lib/sh.js +8 -0
- package/dist/lib/sleep.d.ts +0 -1
- package/dist/lib/sleep.js +0 -1
- package/dist/lib/streamFetch.d.ts +15 -0
- package/dist/lib/streamFetch.js +150 -0
- package/dist/lib/tar.d.ts +0 -1
- package/dist/lib/tar.js +5 -11
- package/dist/portal-gateway/api.d.ts +13 -44
- package/dist/portal-gateway/api.js +1 -3
- package/dist/portal-gateway/control.d.ts +42 -0
- package/dist/portal-gateway/control.js +657 -0
- package/dist/portal-gateway/gatewayClient.d.ts +5 -0
- package/dist/portal-gateway/gatewayClient.js +4 -0
- package/dist/portal-gateway/gatewayService.d.ts +8 -35
- package/dist/portal-gateway/gatewayService.js +79 -253
- package/dist/portal-gateway/image.d.ts +1 -2
- package/dist/portal-gateway/image.js +1 -3
- package/dist/portal-gateway/imageFiles.generated.js +3 -3
- package/dist/portal-gateway/portalClient.d.ts +5 -0
- package/dist/portal-gateway/portalClient.js +4 -0
- package/dist/portal-gateway/portalService.d.ts +5 -47
- package/dist/portal-gateway/portalService.js +19 -317
- package/dist/portal-gateway/transport-worker.d.ts +1 -0
- package/dist/portal-gateway/transport-worker.js +205 -0
- package/dist/portal-gateway/transportBundle.d.ts +2 -0
- package/dist/portal-gateway/transportBundle.generated.d.ts +1 -0
- package/dist/portal-gateway/transportBundle.generated.js +2 -0
- package/dist/portal-gateway/transportBundle.js +4 -0
- package/dist/portal-gateway/upstream.d.ts +12 -82
- package/dist/portal-gateway/upstream.js +0 -1
- package/dist/sandbox/api.d.ts +121 -178
- package/dist/sandbox/api.js +5 -7
- package/dist/sandbox/client.d.ts +2 -0
- package/dist/sandbox/client.js +4 -0
- package/dist/sandbox/data-endpoints/dataEndpoints.d.ts +13 -0
- package/dist/sandbox/data-endpoints/dataEndpoints.js +100 -0
- package/dist/sandbox/data-endpoints/firewalledPorts.d.ts +4 -0
- package/dist/sandbox/data-endpoints/firewalledPorts.js +28 -0
- package/dist/sandbox/lib/httpOverStream.d.ts +3 -0
- package/dist/sandbox/lib/httpOverStream.js +21 -0
- package/dist/sandbox/lib/remoteFileOperations.d.ts +10 -0
- package/dist/sandbox/lib/remoteFileOperations.js +70 -0
- package/dist/sandbox/lib/shellCommand.d.ts +3 -0
- package/dist/sandbox/lib/shellCommand.js +7 -0
- package/dist/sandbox/providers/boat/boatService.d.ts +2 -0
- package/dist/sandbox/providers/boat/boatService.js +321 -0
- package/dist/sandbox/providers/exedev/exeDevService.d.ts +2 -0
- package/dist/sandbox/providers/exedev/exeDevService.js +127 -0
- package/dist/sandbox/providers/exedev/exeDevToken.d.ts +1 -0
- package/dist/sandbox/providers/exedev/exeDevToken.js +54 -0
- package/dist/sandbox/providers/local/localService.d.ts +2 -0
- package/dist/sandbox/providers/local/localService.js +219 -0
- package/dist/sandbox/providers/ssh/sshService.d.ts +2 -0
- package/dist/sandbox/providers/ssh/sshService.js +82 -0
- package/dist/sandbox/providers/ssh/sshTransport.d.ts +12 -0
- package/dist/sandbox/providers/ssh/sshTransport.js +216 -0
- package/dist/sandbox/service.d.ts +2 -0
- package/dist/sandbox/service.js +18 -0
- package/dist/sandbox/storage/descriptors.d.ts +6 -0
- package/dist/sandbox/storage/descriptors.js +25 -0
- package/dist/sandbox/storage/sandboxStorage.d.ts +11 -0
- package/dist/sandbox/storage/sandboxStorage.js +42 -0
- package/dist/upstreams/anthropic.d.ts +0 -5
- package/dist/upstreams/anthropic.js +1 -8
- package/dist/upstreams/index.d.ts +2 -6
- package/dist/upstreams/index.js +0 -4
- package/dist/upstreams/openai.d.ts +0 -5
- package/dist/upstreams/openai.js +1 -13
- package/package.json +12 -4
- package/dist/agent/gatewaySignIns.d.ts +0 -5
- package/dist/agent/gatewaySignIns.js +0 -11
- package/dist/agent/session/codex/home.d.ts +0 -2
- package/dist/agent/session/codex/home.js +0 -4
- package/dist/agent/session/codex/messages.d.ts +0 -30
- package/dist/agent/session/codex/messages.js +0 -135
- package/dist/agent/session/codex/transcript.d.ts +0 -12
- package/dist/agent/session/codex/transcript.js +0 -22
- package/dist/agent/session/sdkMessages.d.ts +0 -15
- package/dist/agent/session/sdkMessages.js +0 -28
- package/dist/agent/session/workerSseConnection.d.ts +0 -15
- package/dist/agent/session/workerSseConnection.js +0 -26
- package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.d.ts +0 -10
- package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.d.ts +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.d.ts +0 -22
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageDetail.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/ImageDetail.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.d.ts +0 -11
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.d.ts +0 -23
- package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/MessagePhase.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/MessagePhase.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/SleepItem.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/SleepItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/WebSearchItem.d.ts +0 -14
- package/dist/agent/vendor-types/codex/app-server/WebSearchItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.d.ts +0 -3
- package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.d.ts +0 -19
- package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.d.ts +0 -10
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.d.ts +0 -8
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.d.ts +0 -3
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.d.ts +0 -8
- package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/TextElement.d.ts +0 -11
- package/dist/agent/vendor-types/codex/app-server/v2/TextElement.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.d.ts +0 -215
- package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/UserInput.d.ts +0 -35
- package/dist/agent/vendor-types/codex/app-server/v2/UserInput.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.d.ts +0 -14
- package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.js +0 -2
- package/dist/cli/services.d.ts +0 -19
- package/dist/cli/services.js +0 -33
- package/dist/dimension/http.d.ts +0 -7
- package/dist/dimension/http.js +0 -77
- package/dist/dimension/storage.d.ts +0 -39
- package/dist/dimension/storage.js +0 -79
- package/dist/portal-gateway/fakes.d.ts +0 -3
- package/dist/portal-gateway/fakes.js +0 -11
- package/dist/portal-gateway/gatewayStorage.d.ts +0 -66
- package/dist/portal-gateway/gatewayStorage.js +0 -125
- package/dist/portal-gateway/portalStorage.d.ts +0 -34
- package/dist/portal-gateway/portalStorage.js +0 -44
- package/dist/sandbox/boatService.d.ts +0 -52
- package/dist/sandbox/boatService.js +0 -343
- package/dist/sandbox/containerService.d.ts +0 -15
- package/dist/sandbox/containerService.js +0 -184
- package/dist/sandbox/endpointProxy.d.ts +0 -90
- package/dist/sandbox/endpointProxy.js +0 -701
- package/dist/sandbox/exeDevAuth.d.ts +0 -16
- package/dist/sandbox/exeDevAuth.js +0 -49
- package/dist/sandbox/localService.d.ts +0 -19
- package/dist/sandbox/localService.js +0 -200
- package/dist/sandbox/sseConnection.d.ts +0 -41
- package/dist/sandbox/sseConnection.js +0 -166
- package/dist/sandbox/sshService.d.ts +0 -30
- package/dist/sandbox/sshService.js +0 -680
package/dist/lib/docker.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { components, operations } from "./docker-api.ts";
|
|
2
2
|
import type { Sandbox } from "../sandbox/api.ts";
|
|
3
|
-
/** Engine API version the client speaks. After changing it, run `bun run generate:docker-api`. */
|
|
4
3
|
export declare const DOCKER_API_VERSION = "v1.44";
|
|
5
4
|
type Schemas = components["schemas"];
|
|
6
5
|
export type ContainerInspect = operations["ContainerInspect"]["responses"][200]["content"]["application/json"];
|
|
@@ -11,16 +10,13 @@ export type ImageSummary = Schemas["ImageSummary"];
|
|
|
11
10
|
export type DockerEvent = Schemas["EventMessage"];
|
|
12
11
|
export type ContainerResources = Pick<Schemas["Resources"], "Memory" | "MemorySwap" | "NanoCpus">;
|
|
13
12
|
export type ContainerStats = {
|
|
14
|
-
/** Bytes, excluding reclaimable page cache (same number `docker stats` shows). */
|
|
15
13
|
memoryUsage: number;
|
|
16
|
-
/** Cores in use, e.g. 0.25 = a quarter of one core. */
|
|
17
14
|
cpuUsage: number;
|
|
18
15
|
};
|
|
19
16
|
export type ExecOptions = {
|
|
20
17
|
cmd: string[];
|
|
21
18
|
user?: string;
|
|
22
19
|
env?: Record<string, string>;
|
|
23
|
-
/** Defaults to the container's working directory. */
|
|
24
20
|
workdir?: string;
|
|
25
21
|
};
|
|
26
22
|
export type ExecResult = {
|
|
@@ -30,7 +26,6 @@ export type ExecResult = {
|
|
|
30
26
|
};
|
|
31
27
|
export type BuildOptions = {
|
|
32
28
|
tag: string;
|
|
33
|
-
/** Build context: file path inside the context -> file contents. Must include "Dockerfile". */
|
|
34
29
|
context: Record<string, string>;
|
|
35
30
|
labels?: Record<string, string>;
|
|
36
31
|
};
|
|
@@ -38,41 +33,24 @@ export type BuildOptions = {
|
|
|
38
33
|
export interface DockerClient {
|
|
39
34
|
imageExists(image: string): Promise<boolean>;
|
|
40
35
|
buildImage(options: BuildOptions): Promise<void>;
|
|
41
|
-
/** Filters use docker's syntax, e.g. { label: ["hyperbrane"], reference: ["hyperbrane-dimension"] }. */
|
|
42
36
|
listImages(filters: Record<string, string[]>): Promise<ImageSummary[]>;
|
|
43
|
-
/** Removes a tag (and the image, once untagged). No-op if missing; DockerError 409 while a container uses it. */
|
|
44
37
|
removeImage(image: string): Promise<void>;
|
|
45
38
|
inspectContainer(name: string): Promise<ContainerInspect | null>;
|
|
46
39
|
listContainers(label: string): Promise<ContainerSummary[]>;
|
|
47
|
-
/** Throws DockerError with status 409 if a container with this name already exists. */
|
|
48
40
|
createContainer(name: string, spec: ContainerCreateSpec): Promise<void>;
|
|
49
|
-
/** No-op if the container is already running. */
|
|
50
41
|
startContainer(name: string): Promise<void>;
|
|
51
|
-
/** No-op if the container is already stopped. */
|
|
52
42
|
stopContainer(name: string): Promise<void>;
|
|
53
|
-
/** Stops the container (if running) and starts it again. */
|
|
54
43
|
restartContainer(name: string): Promise<void>;
|
|
55
|
-
/** Force-removes the container and its anonymous volumes. No-op if it doesn't exist. */
|
|
56
44
|
removeContainer(name: string): Promise<void>;
|
|
57
45
|
containerStats(name: string): Promise<ContainerStats>;
|
|
58
|
-
/** Changes a container's resource limits in place: no restart. */
|
|
59
46
|
updateContainer(name: string, resources: ContainerResources): Promise<void>;
|
|
60
47
|
exec(name: string, options: ExecOptions): Promise<ExecResult>;
|
|
61
|
-
/**
|
|
62
|
-
* Extracts `files` (path relative to `directory` -> contents) into the container, owned by root.
|
|
63
|
-
* `directory` must exist. DockerError 404 if the container or the directory doesn't.
|
|
64
|
-
*/
|
|
65
48
|
putArchive(name: string, directory: string, files: Record<string, string | Uint8Array>): Promise<void>;
|
|
66
|
-
/**
|
|
67
|
-
* Streams events as they happen, e.g. filters { type: ["container"], event: ["start"] }. Ends when
|
|
68
|
-
* `signal` aborts (quietly) or the daemon drops the connection.
|
|
69
|
-
*/
|
|
70
49
|
events(filters: Record<string, string[]>, signal: AbortSignal): AsyncIterable<DockerEvent>;
|
|
71
50
|
}
|
|
72
51
|
export declare class DockerError extends Error {
|
|
73
52
|
readonly status: number;
|
|
74
53
|
constructor(status: number, message: string);
|
|
75
54
|
}
|
|
76
|
-
/** Talks to the docker daemon whose API socket is at `socketPath` inside `sandbox`. */
|
|
77
55
|
export declare function createDockerClient(sandbox: Sandbox, socketPath?: string): DockerClient;
|
|
78
56
|
export {};
|
package/dist/lib/docker.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import createClient from "openapi-fetch";
|
|
2
2
|
import { createTar } from "./tar.js";
|
|
3
|
-
/** Engine API version the client speaks. After changing it, run `bun run generate:docker-api`. */
|
|
4
3
|
export const DOCKER_API_VERSION = "v1.44";
|
|
5
4
|
export class DockerError extends Error {
|
|
6
5
|
status;
|
|
@@ -10,14 +9,12 @@ export class DockerError extends Error {
|
|
|
10
9
|
this.name = "DockerError";
|
|
11
10
|
}
|
|
12
11
|
}
|
|
13
|
-
/** Returns the data of a successful call (or of one whose status is listed in `allowed`), else throws DockerError. */
|
|
14
12
|
function unwrap({ data, error, response }, allowed = []) {
|
|
15
13
|
if (response.ok || allowed.includes(response.status))
|
|
16
14
|
return data;
|
|
17
15
|
const message = error?.message ?? response.statusText;
|
|
18
16
|
throw new DockerError(response.status, message);
|
|
19
17
|
}
|
|
20
|
-
/** Talks to the docker daemon whose API socket is at `socketPath` inside `sandbox`. */
|
|
21
18
|
export function createDockerClient(sandbox, socketPath = "/var/run/docker.sock") {
|
|
22
19
|
function sandboxFetch(timeout) {
|
|
23
20
|
return async (request) => sandbox.fetch(request.url, {
|
|
@@ -40,12 +37,10 @@ export function createDockerClient(sandbox, socketPath = "/var/run/docker.sock")
|
|
|
40
37
|
const result = await api.POST("/build", {
|
|
41
38
|
params: { query: { t: tag, labels: JSON.stringify(labels), rm: true, forcerm: true } },
|
|
42
39
|
headers: { "Content-type": "application/x-tar" },
|
|
43
|
-
// The spec models the binary tar stream as a string.
|
|
44
40
|
body: tar,
|
|
45
41
|
bodySerializer: (body) => body,
|
|
46
42
|
parseAs: "text",
|
|
47
43
|
});
|
|
48
|
-
// The build streams JSON lines; failures arrive in-band with HTTP 200.
|
|
49
44
|
const log = [];
|
|
50
45
|
for (const line of (unwrap(result) ?? "").split("\n").filter(Boolean)) {
|
|
51
46
|
const event = JSON.parse(line);
|
|
@@ -93,7 +88,6 @@ export function createDockerClient(sandbox, socketPath = "/var/run/docker.sock")
|
|
|
93
88
|
unwrap(await api.POST("/containers/{id}/update", { params: { path: { id: name } }, body: resources }));
|
|
94
89
|
}
|
|
95
90
|
async function containerStats(name) {
|
|
96
|
-
// stream=false without one-shot waits for two samples, which the CPU delta needs.
|
|
97
91
|
const result = await api.GET("/containers/{id}/stats", {
|
|
98
92
|
params: { path: { id: name }, query: { stream: false } },
|
|
99
93
|
});
|
|
@@ -126,7 +120,6 @@ export function createDockerClient(sandbox, socketPath = "/var/run/docker.sock")
|
|
|
126
120
|
const result = await api.PUT("/containers/{id}/archive", {
|
|
127
121
|
params: { path: { id: name }, query: { path: directory } },
|
|
128
122
|
headers: { "Content-type": "application/x-tar" },
|
|
129
|
-
// The spec models the binary tar stream as a string.
|
|
130
123
|
body: tar,
|
|
131
124
|
bodySerializer: (body) => body,
|
|
132
125
|
parseAs: "text",
|
|
@@ -139,13 +132,11 @@ export function createDockerClient(sandbox, socketPath = "/var/run/docker.sock")
|
|
|
139
132
|
params: { query: { filters: JSON.stringify(filters) } },
|
|
140
133
|
parseAs: "stream",
|
|
141
134
|
signal,
|
|
142
|
-
// The stream stays silent while nothing happens; an idle timeout would cut it.
|
|
143
135
|
fetch: sandboxFetch(false),
|
|
144
136
|
});
|
|
145
137
|
const body = unwrap(result);
|
|
146
138
|
if (!body)
|
|
147
139
|
return;
|
|
148
|
-
// One JSON object per line.
|
|
149
140
|
const decoder = new TextDecoder();
|
|
150
141
|
let buffered = "";
|
|
151
142
|
for await (const chunk of body) {
|
|
@@ -193,7 +184,6 @@ function toContainerStats(raw) {
|
|
|
193
184
|
const cpuUsage = systemDelta > 0 && cpuDelta > 0 ? (cpuDelta / systemDelta) * cpus : 0;
|
|
194
185
|
return { memoryUsage, cpuUsage };
|
|
195
186
|
}
|
|
196
|
-
/** Splits docker's multiplexed attach stream: 8-byte header (stream id, 3 pad, uint32 BE size) per frame. */
|
|
197
187
|
function demuxStream(bytes) {
|
|
198
188
|
const decoder = new TextDecoder();
|
|
199
189
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
package/dist/lib/image.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { type DockerClient } from "./docker.ts";
|
|
2
2
|
export type ImageSpec = {
|
|
3
3
|
repository: string;
|
|
4
|
-
/** Bump whenever the build context changes; the tag is how an existing build is recognised. */
|
|
5
4
|
version: string;
|
|
6
|
-
/** Build context: file path -> contents. Must include "Dockerfile". */
|
|
7
5
|
context: Record<string, string>;
|
|
8
6
|
};
|
|
9
7
|
export interface ManagedImage {
|
|
10
8
|
readonly tag: string;
|
|
11
|
-
/** Builds the image if it isn't present yet, removes outdated versions, and returns its tag. */
|
|
12
9
|
ensure(): Promise<string>;
|
|
13
10
|
}
|
|
14
11
|
export declare function createManagedImage(docker: DockerClient, { repository, version, context }: ImageSpec): ManagedImage;
|
package/dist/lib/image.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DockerError } from "./docker.js";
|
|
2
2
|
export function createManagedImage(docker, { repository, version, context }) {
|
|
3
3
|
const tag = `${repository}:${version}`;
|
|
4
|
-
// Concurrent builds of the same tag (from any process) are harmless: they produce the same image.
|
|
5
4
|
async function ensure() {
|
|
6
5
|
if (!(await docker.imageExists(tag))) {
|
|
7
6
|
await docker.buildImage({ tag, context, labels: { hyperbrane: "true", "hyperbrane.image.version": version } });
|
|
@@ -9,7 +8,6 @@ export function createManagedImage(docker, { repository, version, context }) {
|
|
|
9
8
|
await removeOutdatedImages().catch((error) => console.warn(`removing outdated ${repository} images failed:`, error));
|
|
10
9
|
return tag;
|
|
11
10
|
}
|
|
12
|
-
// Images still used by a container are skipped (docker answers 409) and retried on a later ensure().
|
|
13
11
|
async function removeOutdatedImages() {
|
|
14
12
|
const images = await docker.listImages({ label: ["hyperbrane"], reference: [repository] });
|
|
15
13
|
const outdated = images
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import { type Sandbox } from "../sandbox/api.ts";
|
|
2
|
-
/**
|
|
3
|
-
* One JSON file per record in a sandbox directory, so no operation rewrites a shared file and every
|
|
4
|
-
* write is a single atomic sandbox operation. Safe to use from several processes at once.
|
|
5
|
-
*/
|
|
6
2
|
export interface JsonDirectory<T> {
|
|
7
|
-
/** Null if missing. */
|
|
8
3
|
read(name: string): Promise<T | null>;
|
|
9
|
-
/** Stores the record unless one with that name exists; returns whichever record is stored afterwards. */
|
|
10
4
|
insert(name: string, record: T): Promise<T>;
|
|
11
|
-
/** Replaces the record. */
|
|
12
5
|
save(name: string, record: T): Promise<void>;
|
|
13
|
-
/** No-op if missing. */
|
|
14
6
|
remove(name: string): Promise<void>;
|
|
15
|
-
/** Empty if the directory doesn't exist yet. */
|
|
16
7
|
list(): Promise<T[]>;
|
|
17
|
-
/** list, each record with its name. */
|
|
18
8
|
entries(): Promise<[string, T][]>;
|
|
19
9
|
}
|
|
20
10
|
export declare class InvalidNameError extends Error {
|
|
21
11
|
name: string;
|
|
22
12
|
}
|
|
23
|
-
/** Throws InvalidNameError unless `name` is safe to use as a path segment. */
|
|
24
13
|
export declare function checkName(name: string): string;
|
|
25
|
-
/** `dir` resolves to a sandbox path; it's re-resolved per call so it can depend on the sandbox's home. */
|
|
26
14
|
export declare function createJsonDirectory<T>(sandbox: Sandbox, dir: () => Promise<string>): JsonDirectory<T>;
|
|
27
|
-
/** ~/.local/share/hyperbrane of the sandbox's user. */
|
|
28
15
|
export declare function defaultDataDir(sandbox: Sandbox): Promise<string>;
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { SandboxNotFoundError } from "../sandbox/api.js";
|
|
2
|
+
import { sh } from "./sh.js";
|
|
2
3
|
const EXTENSION = ".json";
|
|
3
|
-
// Same alphabet as dimension names; keeps names safe to use as file and directory names.
|
|
4
4
|
const NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,62}$/;
|
|
5
5
|
export class InvalidNameError extends Error {
|
|
6
6
|
name = "InvalidNameError";
|
|
7
7
|
}
|
|
8
|
-
/** Throws InvalidNameError unless `name` is safe to use as a path segment. */
|
|
9
8
|
export function checkName(name) {
|
|
10
9
|
if (!NAME_PATTERN.test(name)) {
|
|
11
10
|
throw new InvalidNameError(`Invalid name "${name}": use letters, digits, "_", "." and "-", up to 63 characters`);
|
|
12
11
|
}
|
|
13
12
|
return name;
|
|
14
13
|
}
|
|
15
|
-
/** `dir` resolves to a sandbox path; it's re-resolved per call so it can depend on the sandbox's home. */
|
|
16
14
|
export function createJsonDirectory(sandbox, dir) {
|
|
17
15
|
async function pathFor(name) {
|
|
18
16
|
return `${await dir()}/${checkName(name)}${EXTENSION}`;
|
|
@@ -37,7 +35,6 @@ export function createJsonDirectory(sandbox, dir) {
|
|
|
37
35
|
const path = await pathFor(name);
|
|
38
36
|
if (await sandbox.writeFileExclusive(path, serialize(record)))
|
|
39
37
|
return record;
|
|
40
|
-
// Lost to an existing record; if that one was removed in the meantime, try again.
|
|
41
38
|
return (await readPath(path)) ?? insert(name, record);
|
|
42
39
|
}
|
|
43
40
|
async function save(name, record) {
|
|
@@ -46,11 +43,9 @@ export function createJsonDirectory(sandbox, dir) {
|
|
|
46
43
|
async function remove(name) {
|
|
47
44
|
await sandbox.removeFile(await pathFor(name));
|
|
48
45
|
}
|
|
49
|
-
// One command for the whole directory: over SSH or Boat, a call per record adds up. Falls back to
|
|
50
|
-
// listing and reading where the command can't run.
|
|
51
46
|
async function entries() {
|
|
52
47
|
const path = await dir();
|
|
53
|
-
const all = await sandbox.runCommand(["sh", "-c", LIST_SCRIPT, "sh", path]).catch(() => null);
|
|
48
|
+
const all = await sandbox.runCommand(["sh", "-c", LIST_SCRIPT, "sh", path], { env: { MISSING: String(MISSING), EXTENSION } }).catch(() => null);
|
|
54
49
|
if (all?.exitCode === MISSING)
|
|
55
50
|
return [];
|
|
56
51
|
if (all?.exitCode === 0) {
|
|
@@ -76,7 +71,6 @@ export function createJsonDirectory(sandbox, dir) {
|
|
|
76
71
|
return [];
|
|
77
72
|
throw error;
|
|
78
73
|
}
|
|
79
|
-
// A record removed between listing and reading is simply skipped.
|
|
80
74
|
const records = await Promise.all(files
|
|
81
75
|
.filter((file) => file.endsWith(EXTENSION))
|
|
82
76
|
.map(async (file) => [file.slice(0, -EXTENSION.length), await readPath(`${path}/${file}`)]));
|
|
@@ -87,16 +81,17 @@ export function createJsonDirectory(sandbox, dir) {
|
|
|
87
81
|
}
|
|
88
82
|
return { read, insert, save, remove, list, entries };
|
|
89
83
|
}
|
|
90
|
-
/** list's command exits with it when the directory doesn't exist. */
|
|
91
84
|
const MISSING = 44;
|
|
92
|
-
/** Ends each record list's command prints (its file name, a newline, its JSON): a record separator, which JSON escapes inside strings. */
|
|
93
85
|
const RECORD_END = "\n\x1e\n";
|
|
94
|
-
const LIST_SCRIPT = `
|
|
95
|
-
|
|
86
|
+
const LIST_SCRIPT = sh `
|
|
87
|
+
cd "$1" 2>/dev/null || exit "$MISSING"
|
|
88
|
+
for file in *"$EXTENSION"; do
|
|
96
89
|
[ -f "$file" ] || continue
|
|
97
|
-
printf '%s
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
printf '%s\n' "$file"
|
|
91
|
+
cat "$file"
|
|
92
|
+
printf '\n\036\n'
|
|
93
|
+
done
|
|
94
|
+
`;
|
|
100
95
|
export async function defaultDataDir(sandbox) {
|
|
101
96
|
return `${await sandbox.homeDirectory()}/.local/share/hyperbrane`;
|
|
102
97
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
export function scriptBundle(entry, generated) {
|
|
4
|
+
let bundled;
|
|
5
|
+
async function load() {
|
|
6
|
+
const fromSources = "Bun" in globalThis && existsSync(entry());
|
|
7
|
+
const source = fromSources ? await buildScript(entry()) : await generated();
|
|
8
|
+
return { source, build: createHash("sha256").update(source).digest("hex").slice(0, 16) };
|
|
9
|
+
}
|
|
10
|
+
return () => {
|
|
11
|
+
bundled ??= load().catch((error) => {
|
|
12
|
+
bundled = undefined;
|
|
13
|
+
throw error;
|
|
14
|
+
});
|
|
15
|
+
return bundled;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export async function buildScript(entry) {
|
|
19
|
+
for (let attempt = 1;; attempt++) {
|
|
20
|
+
const result = await Bun.build({ entrypoints: [entry], target: "bun" }).catch((error) => error);
|
|
21
|
+
if (!(result instanceof Error))
|
|
22
|
+
return result.outputs[0].text();
|
|
23
|
+
const logs = (result.errors ?? [result]).map(String).join("\n");
|
|
24
|
+
if (attempt >= BUILD_ATTEMPTS || !/Could not resolve|Unseekable reading file/.test(logs))
|
|
25
|
+
throw new Error(`bundling ${entry} failed:\n${logs}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const BUILD_ATTEMPTS = 3;
|
package/dist/lib/sh.d.ts
ADDED
package/dist/lib/sh.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function sh(strings, ...values) {
|
|
2
|
+
if (values.length > 0)
|
|
3
|
+
throw new Error("sh`…` takes no interpolations: pass inputs as environment variables or arguments");
|
|
4
|
+
return scriptText(strings.raw[0]);
|
|
5
|
+
}
|
|
6
|
+
export function scriptText(raw) {
|
|
7
|
+
return raw.replace(/\\(\$\{|`)/g, "$1").replace(/^\n/, "");
|
|
8
|
+
}
|
package/dist/lib/sleep.d.ts
CHANGED
package/dist/lib/sleep.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type HttpStream = {
|
|
2
|
+
write(data: string | Uint8Array): unknown;
|
|
3
|
+
on(event: "data", listener: (chunk: Buffer) => void): unknown;
|
|
4
|
+
on(event: "error", listener: (error: Error) => void): unknown;
|
|
5
|
+
on(event: "end" | "close", listener: () => void): unknown;
|
|
6
|
+
destroy(): unknown;
|
|
7
|
+
};
|
|
8
|
+
export type StreamFetchInit = {
|
|
9
|
+
method?: string;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
body?: string | Uint8Array;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
timeout?: number | false;
|
|
14
|
+
};
|
|
15
|
+
export declare function fetchOverStream(stream: HttpStream, url: string, init: StreamFetchInit, where: string): Promise<Response>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export function fetchOverStream(stream, url, init, where) {
|
|
2
|
+
if (init.signal?.aborted) {
|
|
3
|
+
stream.destroy();
|
|
4
|
+
return Promise.reject(init.signal.reason);
|
|
5
|
+
}
|
|
6
|
+
const target = new URL(url);
|
|
7
|
+
const body = init.body === undefined ? undefined : typeof init.body === "string" ? Buffer.from(init.body) : Buffer.from(init.body);
|
|
8
|
+
const head = [`${init.method ?? "GET"} ${target.pathname}${target.search} HTTP/1.1`, `Host: ${target.host}`, "Connection: close"];
|
|
9
|
+
for (const [name, value] of Object.entries(init.headers ?? {}))
|
|
10
|
+
head.push(`${name}: ${value}`);
|
|
11
|
+
if (body)
|
|
12
|
+
head.push(`Content-Length: ${body.length}`);
|
|
13
|
+
stream.write(`${head.join("\r\n")}\r\n\r\n`);
|
|
14
|
+
if (body)
|
|
15
|
+
stream.write(body);
|
|
16
|
+
let idle;
|
|
17
|
+
let fail = () => { };
|
|
18
|
+
const touch = () => {
|
|
19
|
+
if (typeof init.timeout !== "number")
|
|
20
|
+
return;
|
|
21
|
+
clearTimeout(idle);
|
|
22
|
+
idle = setTimeout(() => fail(new Error(`fetch ${url} on ${where}: no data for ${init.timeout}ms`)), init.timeout);
|
|
23
|
+
};
|
|
24
|
+
const abort = () => fail(init.signal.reason instanceof Error ? init.signal.reason : new Error("aborted"));
|
|
25
|
+
init.signal?.addEventListener("abort", abort, { once: true });
|
|
26
|
+
const finish = () => {
|
|
27
|
+
clearTimeout(idle);
|
|
28
|
+
init.signal?.removeEventListener("abort", abort);
|
|
29
|
+
stream.destroy();
|
|
30
|
+
};
|
|
31
|
+
touch();
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let buffer = Buffer.alloc(0);
|
|
34
|
+
let responded = false;
|
|
35
|
+
let controller = null;
|
|
36
|
+
let framing = { kind: "close" };
|
|
37
|
+
let done = false;
|
|
38
|
+
const end = () => {
|
|
39
|
+
if (done)
|
|
40
|
+
return;
|
|
41
|
+
done = true;
|
|
42
|
+
finish();
|
|
43
|
+
try {
|
|
44
|
+
controller?.close();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
fail = (error) => {
|
|
50
|
+
if (done)
|
|
51
|
+
return;
|
|
52
|
+
done = true;
|
|
53
|
+
finish();
|
|
54
|
+
if (!responded)
|
|
55
|
+
reject(error);
|
|
56
|
+
else
|
|
57
|
+
controller?.error(error);
|
|
58
|
+
};
|
|
59
|
+
const pumpBody = () => {
|
|
60
|
+
if (framing.kind === "close") {
|
|
61
|
+
if (buffer.length)
|
|
62
|
+
controller?.enqueue(new Uint8Array(buffer));
|
|
63
|
+
buffer = Buffer.alloc(0);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (framing.kind === "length") {
|
|
67
|
+
const take = buffer.subarray(0, framing.left);
|
|
68
|
+
if (take.length)
|
|
69
|
+
controller?.enqueue(new Uint8Array(take));
|
|
70
|
+
framing.left -= take.length;
|
|
71
|
+
buffer = buffer.subarray(take.length);
|
|
72
|
+
return framing.left === 0;
|
|
73
|
+
}
|
|
74
|
+
for (;;) {
|
|
75
|
+
const lineEnd = buffer.indexOf("\r\n");
|
|
76
|
+
if (lineEnd < 0)
|
|
77
|
+
return false;
|
|
78
|
+
const size = parseInt(buffer.subarray(0, lineEnd).toString(), 16);
|
|
79
|
+
if (Number.isNaN(size))
|
|
80
|
+
throw new Error("malformed chunked body");
|
|
81
|
+
if (size === 0)
|
|
82
|
+
return true;
|
|
83
|
+
if (buffer.length < lineEnd + 2 + size + 2)
|
|
84
|
+
return false;
|
|
85
|
+
controller?.enqueue(new Uint8Array(buffer.subarray(lineEnd + 2, lineEnd + 2 + size)));
|
|
86
|
+
buffer = buffer.subarray(lineEnd + 2 + size + 2);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const onData = (chunk) => {
|
|
90
|
+
if (done)
|
|
91
|
+
return;
|
|
92
|
+
touch();
|
|
93
|
+
buffer = buffer.length ? Buffer.concat([buffer, chunk]) : chunk;
|
|
94
|
+
try {
|
|
95
|
+
if (!responded) {
|
|
96
|
+
const headEnd = buffer.indexOf("\r\n\r\n");
|
|
97
|
+
if (headEnd < 0)
|
|
98
|
+
return;
|
|
99
|
+
const [statusLine = "", ...lines] = buffer.subarray(0, headEnd).toString("latin1").split("\r\n");
|
|
100
|
+
buffer = buffer.subarray(headEnd + 4);
|
|
101
|
+
const status = Number(statusLine.split(" ")[1]);
|
|
102
|
+
if (status >= 100 && status < 200)
|
|
103
|
+
return onData(Buffer.alloc(0));
|
|
104
|
+
const headers = new Headers();
|
|
105
|
+
for (const line of lines) {
|
|
106
|
+
const colon = line.indexOf(":");
|
|
107
|
+
if (colon > 0)
|
|
108
|
+
headers.append(line.slice(0, colon).trim(), line.slice(colon + 1).trim());
|
|
109
|
+
}
|
|
110
|
+
responded = true;
|
|
111
|
+
if (status === 204 || status === 304 || init.method === "HEAD") {
|
|
112
|
+
resolve(new Response(null, { status, headers }));
|
|
113
|
+
return end();
|
|
114
|
+
}
|
|
115
|
+
if (headers.get("transfer-encoding")?.toLowerCase().includes("chunked"))
|
|
116
|
+
framing = { kind: "chunked" };
|
|
117
|
+
else if (headers.has("content-length"))
|
|
118
|
+
framing = { kind: "length", left: Number(headers.get("content-length")) };
|
|
119
|
+
const responseBody = new ReadableStream({
|
|
120
|
+
start(c) {
|
|
121
|
+
controller = c;
|
|
122
|
+
},
|
|
123
|
+
cancel() {
|
|
124
|
+
done = true;
|
|
125
|
+
finish();
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
resolve(new Response(responseBody, { status, headers }));
|
|
129
|
+
}
|
|
130
|
+
if (pumpBody())
|
|
131
|
+
end();
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
fail(error);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
stream.on("data", onData);
|
|
138
|
+
stream.on("error", (error) => fail(new Error(`fetch ${url} on ${where} failed: ${error.message}`)));
|
|
139
|
+
const ended = () => {
|
|
140
|
+
if (!responded)
|
|
141
|
+
return fail(new Error(`fetch ${url} on ${where} failed: the socket closed before a response`));
|
|
142
|
+
if (framing.kind === "close")
|
|
143
|
+
end();
|
|
144
|
+
else
|
|
145
|
+
fail(new Error(`fetch ${url} on ${where} failed: the response was cut short`));
|
|
146
|
+
};
|
|
147
|
+
stream.on("end", ended);
|
|
148
|
+
stream.on("close", ended);
|
|
149
|
+
});
|
|
150
|
+
}
|
package/dist/lib/tar.d.ts
CHANGED
package/dist/lib/tar.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
// A minimal tar (ustar) writer: regular files only, which is all a docker build context or
|
|
2
|
-
// putArchive needs (docker creates missing parent directories). Portable stand-in for Bun.Archive,
|
|
3
|
-
// so the services run under Node too.
|
|
4
1
|
const BLOCK = 512;
|
|
5
2
|
function octal(value, width) {
|
|
6
|
-
// width includes the trailing NUL.
|
|
7
3
|
return value.toString(8).padStart(width - 1, "0") + "\0";
|
|
8
4
|
}
|
|
9
5
|
function header(name, size, mode, mtime) {
|
|
@@ -18,7 +14,6 @@ function header(name, size, mode, mtime) {
|
|
|
18
14
|
let path = name;
|
|
19
15
|
let prefix = "";
|
|
20
16
|
if (encoder.encode(name).length > 100) {
|
|
21
|
-
// ustar splits long paths at a "/" into prefix (155) and name (100).
|
|
22
17
|
const cut = name.lastIndexOf("/", 155);
|
|
23
18
|
if (cut <= 0)
|
|
24
19
|
throw new Error(`tar: "${name}" is too long`);
|
|
@@ -27,12 +22,12 @@ function header(name, size, mode, mtime) {
|
|
|
27
22
|
}
|
|
28
23
|
put(path, 0, 100);
|
|
29
24
|
put(octal(mode, 8), 100, 8);
|
|
30
|
-
put(octal(0, 8), 108, 8);
|
|
31
|
-
put(octal(0, 8), 116, 8);
|
|
25
|
+
put(octal(0, 8), 108, 8);
|
|
26
|
+
put(octal(0, 8), 116, 8);
|
|
32
27
|
put(octal(size, 12), 124, 12);
|
|
33
28
|
put(octal(mtime, 12), 136, 12);
|
|
34
|
-
put(" ", 148, 8);
|
|
35
|
-
put("0", 156, 1);
|
|
29
|
+
put(" ", 148, 8);
|
|
30
|
+
put("0", 156, 1);
|
|
36
31
|
put("ustar\0", 257, 6);
|
|
37
32
|
put("00", 263, 2);
|
|
38
33
|
put(prefix, 345, 155);
|
|
@@ -42,7 +37,6 @@ function header(name, size, mode, mtime) {
|
|
|
42
37
|
put(sum.toString(8).padStart(6, "0") + "\0 ", 148, 8);
|
|
43
38
|
return block;
|
|
44
39
|
}
|
|
45
|
-
/** Packs `files` (path -> contents) into a tar archive. Files are mode 0644, owned by root. */
|
|
46
40
|
export function createTar(files) {
|
|
47
41
|
const encoder = new TextEncoder();
|
|
48
42
|
const mtime = Math.floor(Date.now() / 1000);
|
|
@@ -54,7 +48,7 @@ export function createTar(files) {
|
|
|
54
48
|
if (padding)
|
|
55
49
|
parts.push(new Uint8Array(padding));
|
|
56
50
|
}
|
|
57
|
-
parts.push(new Uint8Array(BLOCK * 2));
|
|
51
|
+
parts.push(new Uint8Array(BLOCK * 2));
|
|
58
52
|
const out = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));
|
|
59
53
|
let offset = 0;
|
|
60
54
|
for (const part of parts) {
|