gigadrive 2.7.4 → 2.8.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 +23 -0
- package/dist/index.cjs +1130 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1117 -220
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -24,15 +24,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_cli17 = require("@effect/cli");
|
|
28
28
|
var import_platform_node = require("@effect/platform-node");
|
|
29
29
|
var import_network_config2 = require("@gigadrive/network-config");
|
|
30
|
-
var
|
|
30
|
+
var import_effect31 = require("effect");
|
|
31
31
|
|
|
32
32
|
// package.json
|
|
33
33
|
var package_default = {
|
|
34
34
|
name: "gigadrive",
|
|
35
|
-
version: "2.
|
|
35
|
+
version: "2.8.0",
|
|
36
36
|
repository: {
|
|
37
37
|
type: "git",
|
|
38
38
|
url: "https://github.com/Gigadrive/sdk.git",
|
|
@@ -355,6 +355,24 @@ var DeploymentFailedError = class extends import_effect.Schema.TaggedError()("De
|
|
|
355
355
|
message: import_effect.Schema.String
|
|
356
356
|
}) {
|
|
357
357
|
};
|
|
358
|
+
var InvalidMicroVmOptionsError = class extends import_effect.Schema.TaggedError()(
|
|
359
|
+
"InvalidMicroVmOptionsError",
|
|
360
|
+
{ message: import_effect.Schema.String }
|
|
361
|
+
) {
|
|
362
|
+
};
|
|
363
|
+
var InvalidCopyTargetError = class extends import_effect.Schema.TaggedError()("InvalidCopyTargetError", {
|
|
364
|
+
message: import_effect.Schema.String
|
|
365
|
+
}) {
|
|
366
|
+
};
|
|
367
|
+
var LocalFileError = class extends import_effect.Schema.TaggedError()("LocalFileError", {
|
|
368
|
+
message: import_effect.Schema.String,
|
|
369
|
+
path: import_effect.Schema.String
|
|
370
|
+
}) {
|
|
371
|
+
};
|
|
372
|
+
var TerminalRequiredError = class extends import_effect.Schema.TaggedError()("TerminalRequiredError", {
|
|
373
|
+
message: import_effect.Schema.String
|
|
374
|
+
}) {
|
|
375
|
+
};
|
|
358
376
|
|
|
359
377
|
// src/services/api-client.ts
|
|
360
378
|
var import_sdk = require("@gigadrive/sdk");
|
|
@@ -559,6 +577,13 @@ var CLI_SCOPES = [
|
|
|
559
577
|
"network:deployments:trigger",
|
|
560
578
|
"network:ai_gateway:chat",
|
|
561
579
|
"network:ai_gateway:models",
|
|
580
|
+
"network:microvms:read",
|
|
581
|
+
"network:microvms:write",
|
|
582
|
+
"network:microvms:exec",
|
|
583
|
+
"network:microvms:delete",
|
|
584
|
+
"network:microvm_images:read",
|
|
585
|
+
"network:microvm_images:write",
|
|
586
|
+
"network:microvm_images:delete",
|
|
562
587
|
// Provisioning local-dev API credentials
|
|
563
588
|
"platform:api_keys:read",
|
|
564
589
|
"platform:api_keys:write",
|
|
@@ -2953,23 +2978,889 @@ var logoutCommand = import_cli11.Command.make(
|
|
|
2953
2978
|
)
|
|
2954
2979
|
);
|
|
2955
2980
|
|
|
2981
|
+
// src/commands/microvms/index.ts
|
|
2982
|
+
var import_cli12 = require("@effect/cli");
|
|
2983
|
+
var import_platform8 = require("@effect/platform");
|
|
2984
|
+
var import_sdk2 = require("@gigadrive/sdk");
|
|
2985
|
+
var import_effect24 = require("effect");
|
|
2986
|
+
|
|
2987
|
+
// src/lib/microvm.ts
|
|
2988
|
+
var REMOTE_PREFIX = "vm:";
|
|
2989
|
+
var parseCopyTarget = (value) => {
|
|
2990
|
+
if (!value.startsWith(REMOTE_PREFIX)) {
|
|
2991
|
+
return value.length === 0 ? "The path is empty." : { kind: "local", path: value };
|
|
2992
|
+
}
|
|
2993
|
+
const rest = value.slice(REMOTE_PREFIX.length);
|
|
2994
|
+
const separator = rest.indexOf(":");
|
|
2995
|
+
if (separator <= 0) return `"${value}" is not in the form vm:<id>:<path>.`;
|
|
2996
|
+
const microvmId = rest.slice(0, separator);
|
|
2997
|
+
const path2 = rest.slice(separator + 1);
|
|
2998
|
+
return { kind: "remote", microvmId, path: path2.length === 0 ? "." : path2 };
|
|
2999
|
+
};
|
|
3000
|
+
var posixBasename = (path2) => {
|
|
3001
|
+
const trimmed = path2.replace(/\/+$/, "");
|
|
3002
|
+
const index = trimmed.lastIndexOf("/");
|
|
3003
|
+
return index === -1 ? trimmed : trimmed.slice(index + 1);
|
|
3004
|
+
};
|
|
3005
|
+
var posixJoin = (...segments) => segments.filter((segment) => segment.length > 0).join("/").replace(/\/{2,}/g, "/");
|
|
3006
|
+
var relativeTo = (root, entry) => {
|
|
3007
|
+
const base = root.replace(/\/+$/, "");
|
|
3008
|
+
return entry.startsWith(`${base}/`) ? entry.slice(base.length + 1) : posixBasename(entry);
|
|
3009
|
+
};
|
|
3010
|
+
var parseKeyValues = (entries) => {
|
|
3011
|
+
const value = {};
|
|
3012
|
+
for (const entry of entries) {
|
|
3013
|
+
const index = entry.indexOf("=");
|
|
3014
|
+
if (index <= 0) return { ok: false, entry };
|
|
3015
|
+
value[entry.slice(0, index)] = entry.slice(index + 1);
|
|
3016
|
+
}
|
|
3017
|
+
return { ok: true, value };
|
|
3018
|
+
};
|
|
3019
|
+
var SIGNAL_NUMBERS = {
|
|
3020
|
+
SIGHUP: 1,
|
|
3021
|
+
SIGINT: 2,
|
|
3022
|
+
SIGQUIT: 3,
|
|
3023
|
+
SIGABRT: 6,
|
|
3024
|
+
SIGKILL: 9,
|
|
3025
|
+
SIGUSR1: 10,
|
|
3026
|
+
SIGSEGV: 11,
|
|
3027
|
+
SIGUSR2: 12,
|
|
3028
|
+
SIGPIPE: 13,
|
|
3029
|
+
SIGTERM: 15
|
|
3030
|
+
};
|
|
3031
|
+
var exitStatusOf = (command) => {
|
|
3032
|
+
if (command.exitCode !== null) return command.exitCode;
|
|
3033
|
+
if (command.signal) return 128 + (SIGNAL_NUMBERS[command.signal] ?? 0);
|
|
3034
|
+
return 1;
|
|
3035
|
+
};
|
|
3036
|
+
var formatMemory = (mb) => mb % 1024 === 0 ? `${mb / 1024} GiB` : `${mb} MiB`;
|
|
3037
|
+
var relativeTime = (iso, now = Date.now()) => {
|
|
3038
|
+
if (!iso) return "-";
|
|
3039
|
+
const delta = Date.parse(iso) - now;
|
|
3040
|
+
if (!Number.isFinite(delta)) return iso;
|
|
3041
|
+
const abs = Math.abs(delta);
|
|
3042
|
+
const text = abs < 6e4 ? `${Math.round(abs / 1e3)}s` : abs < 36e5 ? `${Math.round(abs / 6e4)}m` : abs < 864e5 ? `${Math.round(abs / 36e5)}h` : `${Math.round(abs / 864e5)}d`;
|
|
3043
|
+
return delta >= 0 ? `in ${text}` : `${text} ago`;
|
|
3044
|
+
};
|
|
3045
|
+
var formatTable = (rows) => {
|
|
3046
|
+
const widths = [];
|
|
3047
|
+
for (const row of rows) {
|
|
3048
|
+
row.forEach((cell, index) => {
|
|
3049
|
+
widths[index] = Math.max(widths[index] ?? 0, cell.length);
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
return rows.map(
|
|
3053
|
+
(row) => row.map((cell, index) => index === row.length - 1 ? cell : cell.padEnd(widths[index] ?? 0)).join(" ").trimEnd()
|
|
3054
|
+
);
|
|
3055
|
+
};
|
|
3056
|
+
var formatMicroVmTable = (vms, now = Date.now()) => formatTable([
|
|
3057
|
+
["ID", "STATUS", "IMAGE", "SIZE", "PORTS", "CREATED", "EXPIRES"],
|
|
3058
|
+
...vms.map((vm) => [
|
|
3059
|
+
vm.id,
|
|
3060
|
+
vm.status,
|
|
3061
|
+
vm.image.name,
|
|
3062
|
+
`${vm.vcpus} vCPU, ${formatMemory(vm.memoryMb)}`,
|
|
3063
|
+
vm.ports.map((entry) => entry.port).join(",") || "-",
|
|
3064
|
+
relativeTime(vm.createdAt, now),
|
|
3065
|
+
vm.status === "running" || vm.status === "starting" ? relativeTime(vm.expiresAt, now) : "-"
|
|
3066
|
+
])
|
|
3067
|
+
]);
|
|
3068
|
+
var describeMicroVm = (vm, now = Date.now()) => {
|
|
3069
|
+
const lines = [
|
|
3070
|
+
`ID: ${vm.id}`,
|
|
3071
|
+
`Status: ${vm.status}${vm.stopReason ? ` (${vm.stopReason})` : ""}`,
|
|
3072
|
+
`Image: ${vm.image.name}`,
|
|
3073
|
+
`Size: ${vm.vcpus} vCPU, ${formatMemory(vm.memoryMb)} memory, ${formatMemory(vm.diskMb)} disk`,
|
|
3074
|
+
`Region: ${vm.region}`,
|
|
3075
|
+
`Network: ${vm.network.egress === "deny" ? "outbound traffic blocked" : "internet access"}`,
|
|
3076
|
+
`Application: ${vm.applicationId}`,
|
|
3077
|
+
`Created: ${vm.createdAt}`
|
|
3078
|
+
];
|
|
3079
|
+
if (vm.expiresAt && (vm.status === "running" || vm.status === "starting")) {
|
|
3080
|
+
lines.push(`Expires: ${vm.expiresAt} (${relativeTime(vm.expiresAt, now)})`);
|
|
3081
|
+
}
|
|
3082
|
+
if (vm.stoppedAt) lines.push(`Stopped: ${vm.stoppedAt}`);
|
|
3083
|
+
const metadata = Object.entries(vm.metadata);
|
|
3084
|
+
if (metadata.length > 0) lines.push(`Metadata: ${metadata.map(([key, value]) => `${key}=${value}`).join(", ")}`);
|
|
3085
|
+
if (vm.ports.length > 0) {
|
|
3086
|
+
lines.push("Ports:");
|
|
3087
|
+
for (const entry of vm.ports) lines.push(` ${entry.port} ${entry.url}`);
|
|
3088
|
+
}
|
|
3089
|
+
return lines;
|
|
3090
|
+
};
|
|
3091
|
+
var imageSource = (image) => {
|
|
3092
|
+
if (image.builtin) return "built-in";
|
|
3093
|
+
const source = image.source;
|
|
3094
|
+
if (!source) return "-";
|
|
3095
|
+
return source.type === "dockerfile" ? "Dockerfile" : source.ref;
|
|
3096
|
+
};
|
|
3097
|
+
var formatImageTable = (images) => formatTable([
|
|
3098
|
+
["NAME", "STATUS", "SOURCE", "ID"],
|
|
3099
|
+
...images.map((image) => [image.name, image.status, imageSource(image), image.id])
|
|
3100
|
+
]);
|
|
3101
|
+
var formatBytes = (bytes) => {
|
|
3102
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
3103
|
+
const units = ["KiB", "MiB", "GiB", "TiB"];
|
|
3104
|
+
let value = bytes / 1024;
|
|
3105
|
+
let unit = 0;
|
|
3106
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
3107
|
+
value /= 1024;
|
|
3108
|
+
unit += 1;
|
|
3109
|
+
}
|
|
3110
|
+
return `${value.toFixed(1)} ${units[unit]}`;
|
|
3111
|
+
};
|
|
3112
|
+
var concatBytes = (chunks) => {
|
|
3113
|
+
if (chunks.length === 1) return chunks[0];
|
|
3114
|
+
const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
3115
|
+
const result = new Uint8Array(total);
|
|
3116
|
+
let offset = 0;
|
|
3117
|
+
for (const chunk of chunks) {
|
|
3118
|
+
result.set(chunk, offset);
|
|
3119
|
+
offset += chunk.length;
|
|
3120
|
+
}
|
|
3121
|
+
return result;
|
|
3122
|
+
};
|
|
3123
|
+
var StdinBatcher = class {
|
|
3124
|
+
constructor(send, options = {}) {
|
|
3125
|
+
this.send = send;
|
|
3126
|
+
this.options = options;
|
|
3127
|
+
this.delayMs = options.delayMs ?? 8;
|
|
3128
|
+
this.maxBytes = options.maxBytes ?? 64 * 1024;
|
|
3129
|
+
}
|
|
3130
|
+
send;
|
|
3131
|
+
options;
|
|
3132
|
+
pending = [];
|
|
3133
|
+
pendingBytes = 0;
|
|
3134
|
+
timer;
|
|
3135
|
+
inFlight;
|
|
3136
|
+
closed = false;
|
|
3137
|
+
delayMs;
|
|
3138
|
+
maxBytes;
|
|
3139
|
+
/** Queues a chunk. Ignored after {@link close}. */
|
|
3140
|
+
push(chunk) {
|
|
3141
|
+
if (this.closed || chunk.length === 0) return;
|
|
3142
|
+
this.pending.push(chunk);
|
|
3143
|
+
this.pendingBytes += chunk.length;
|
|
3144
|
+
if (this.pendingBytes >= this.maxBytes) this.schedule(0);
|
|
3145
|
+
else if (this.timer === void 0) this.schedule(this.delayMs);
|
|
3146
|
+
}
|
|
3147
|
+
/** Sends everything queued so far, after any request already in flight. */
|
|
3148
|
+
async flush() {
|
|
3149
|
+
while (this.inFlight) await this.inFlight;
|
|
3150
|
+
if (this.pending.length === 0) return;
|
|
3151
|
+
const data = concatBytes(this.pending);
|
|
3152
|
+
this.pending = [];
|
|
3153
|
+
this.pendingBytes = 0;
|
|
3154
|
+
this.inFlight = this.send(data).catch((error) => this.options.onError?.(error)).finally(() => {
|
|
3155
|
+
this.inFlight = void 0;
|
|
3156
|
+
});
|
|
3157
|
+
await this.inFlight;
|
|
3158
|
+
}
|
|
3159
|
+
/** Stops accepting chunks and sends what is left. */
|
|
3160
|
+
async close() {
|
|
3161
|
+
this.closed = true;
|
|
3162
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
3163
|
+
this.timer = void 0;
|
|
3164
|
+
await this.flush();
|
|
3165
|
+
}
|
|
3166
|
+
schedule(delay) {
|
|
3167
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
3168
|
+
this.timer = setTimeout(() => {
|
|
3169
|
+
this.timer = void 0;
|
|
3170
|
+
void this.flush();
|
|
3171
|
+
}, delay);
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
|
|
3175
|
+
// src/lib/microvm-session.ts
|
|
3176
|
+
async function attachCommand(command, io, options) {
|
|
3177
|
+
const batcher = new StdinBatcher((data) => command.write(data), {
|
|
3178
|
+
// Input after the command exited is expected to fail; nothing to report.
|
|
3179
|
+
onError: () => void 0
|
|
3180
|
+
});
|
|
3181
|
+
const cleanups = [];
|
|
3182
|
+
if (options.forwardInput) {
|
|
3183
|
+
cleanups.push(
|
|
3184
|
+
io.onInput(
|
|
3185
|
+
(chunk) => batcher.push(chunk),
|
|
3186
|
+
() => {
|
|
3187
|
+
if (!options.endInputOnEof) return;
|
|
3188
|
+
void batcher.close().then(() => command.end()).catch(() => void 0);
|
|
3189
|
+
}
|
|
3190
|
+
)
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
if (options.forwardResize) {
|
|
3194
|
+
cleanups.push(
|
|
3195
|
+
io.onResize(() => {
|
|
3196
|
+
const size = io.size();
|
|
3197
|
+
if (size) void command.resize(size.cols, size.rows).catch(() => void 0);
|
|
3198
|
+
})
|
|
3199
|
+
);
|
|
3200
|
+
}
|
|
3201
|
+
try {
|
|
3202
|
+
for await (const chunk of command.logs()) io.write(chunk.data, chunk.stream);
|
|
3203
|
+
} finally {
|
|
3204
|
+
for (const cleanup of cleanups) cleanup();
|
|
3205
|
+
await batcher.close();
|
|
3206
|
+
}
|
|
3207
|
+
return command.status === "exited" ? command.info : await command.wait();
|
|
3208
|
+
}
|
|
3209
|
+
var nodeSessionIo = () => ({
|
|
3210
|
+
onInput: (listener, onEnd) => {
|
|
3211
|
+
const encoder = new TextEncoder();
|
|
3212
|
+
const onData = (chunk) => listener(typeof chunk === "string" ? encoder.encode(chunk) : chunk);
|
|
3213
|
+
process.stdin.on("data", onData);
|
|
3214
|
+
process.stdin.on("end", onEnd);
|
|
3215
|
+
process.stdin.resume();
|
|
3216
|
+
return () => {
|
|
3217
|
+
process.stdin.off("data", onData);
|
|
3218
|
+
process.stdin.off("end", onEnd);
|
|
3219
|
+
process.stdin.pause();
|
|
3220
|
+
};
|
|
3221
|
+
},
|
|
3222
|
+
write: (data, stream) => {
|
|
3223
|
+
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
3224
|
+
},
|
|
3225
|
+
size: () => process.stdout.isTTY ? { cols: process.stdout.columns, rows: process.stdout.rows } : void 0,
|
|
3226
|
+
onResize: (listener) => {
|
|
3227
|
+
process.stdout.on("resize", listener);
|
|
3228
|
+
return () => {
|
|
3229
|
+
process.stdout.off("resize", listener);
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
});
|
|
3233
|
+
|
|
3234
|
+
// src/commands/microvms/index.ts
|
|
3235
|
+
var CONSOLE_URL2 = "https://console.gigadrive.de";
|
|
3236
|
+
var MICROVM_STATUSES = [
|
|
3237
|
+
"pending",
|
|
3238
|
+
"starting",
|
|
3239
|
+
"running",
|
|
3240
|
+
"stopping",
|
|
3241
|
+
"stopped",
|
|
3242
|
+
"failed"
|
|
3243
|
+
];
|
|
3244
|
+
var DEFAULT_SHELL = ["/bin/sh", "-c", "if command -v bash >/dev/null 2>&1; then exec bash -l; else exec sh -l; fi"];
|
|
3245
|
+
var appOption6 = import_cli12.Options.text("app").pipe(
|
|
3246
|
+
import_cli12.Options.withAlias("a"),
|
|
3247
|
+
import_cli12.Options.withDescription("Application ID (defaults to the linked application)"),
|
|
3248
|
+
import_cli12.Options.optional
|
|
3249
|
+
);
|
|
3250
|
+
var jsonOption2 = import_cli12.Options.boolean("json").pipe(import_cli12.Options.withDescription("Print the result as JSON"));
|
|
3251
|
+
var microvmIdArg = import_cli12.Args.text({ name: "microvm-id" }).pipe(import_cli12.Args.withDescription("The microVM ID"));
|
|
3252
|
+
var envOption = import_cli12.Options.text("env").pipe(
|
|
3253
|
+
import_cli12.Options.withAlias("e"),
|
|
3254
|
+
import_cli12.Options.withDescription("Environment variable as KEY=VALUE (repeatable)"),
|
|
3255
|
+
import_cli12.Options.repeated
|
|
3256
|
+
);
|
|
3257
|
+
var userOption = import_cli12.Options.text("user").pipe(
|
|
3258
|
+
import_cli12.Options.withAlias("u"),
|
|
3259
|
+
import_cli12.Options.withDescription("Run as this user (default: the image user)"),
|
|
3260
|
+
import_cli12.Options.optional
|
|
3261
|
+
);
|
|
3262
|
+
var cwdOption = import_cli12.Options.text("cwd").pipe(
|
|
3263
|
+
import_cli12.Options.withAlias("w"),
|
|
3264
|
+
import_cli12.Options.withDescription("Working directory inside the microVM"),
|
|
3265
|
+
import_cli12.Options.optional
|
|
3266
|
+
);
|
|
3267
|
+
var errorMessage2 = (action, error) => {
|
|
3268
|
+
switch (error._tag) {
|
|
3269
|
+
case "NotAuthenticatedError":
|
|
3270
|
+
return 'You are not logged in. Run "gigadrive login" to authenticate.';
|
|
3271
|
+
case "ApiRequestError":
|
|
3272
|
+
if (error.code === "microvm_not_running") {
|
|
3273
|
+
return `${error.message}
|
|
3274
|
+
The microVM has stopped. Create a new one with "gigadrive microvms create".`;
|
|
3275
|
+
}
|
|
3276
|
+
if (error.code === "quota_exceeded" || error.code === "plan_limit_exceeded") {
|
|
3277
|
+
return `${error.message}
|
|
3278
|
+
Stop microVMs you no longer need, or raise your plan's limits at ${CONSOLE_URL2}.`;
|
|
3279
|
+
}
|
|
3280
|
+
if (error.code === "microvm_busy") {
|
|
3281
|
+
return `${error.message}
|
|
3282
|
+
The microVM is busy. Wait a moment and try again.`;
|
|
3283
|
+
}
|
|
3284
|
+
if (error.code === "microvm_unreachable") {
|
|
3285
|
+
return `${error.message}
|
|
3286
|
+
The microVM could not be reached. Try again; if it keeps failing, check "gigadrive microvms get <id>".`;
|
|
3287
|
+
}
|
|
3288
|
+
if (error.code === "image_not_ready") {
|
|
3289
|
+
return `${error.message}
|
|
3290
|
+
The image is not built yet. Check it with "gigadrive microvms images ls".`;
|
|
3291
|
+
}
|
|
3292
|
+
return `Failed to ${action}: ${error.message}`;
|
|
3293
|
+
default:
|
|
3294
|
+
return error.message;
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
var reportErrors2 = (action) => (self) => import_effect24.Effect.tapError(self, (error) => import_effect24.Console.error(errorMessage2(action, error)));
|
|
3298
|
+
var parseDuration = (flag, value) => import_effect24.Effect.try({
|
|
3299
|
+
try: () => {
|
|
3300
|
+
if (/^\d+(\.\d+)?$/.test(value.trim())) throw new RangeError("missing unit");
|
|
3301
|
+
return (0, import_sdk2.durationToMs)(value);
|
|
3302
|
+
},
|
|
3303
|
+
catch: () => new InvalidMicroVmOptionsError({
|
|
3304
|
+
message: `${flag} must be a duration with a unit, such as 90s, 10m or 1h (got "${value}").`
|
|
3305
|
+
})
|
|
3306
|
+
});
|
|
3307
|
+
var optionalDuration = (flag, value) => import_effect24.Option.match(value, {
|
|
3308
|
+
onNone: () => import_effect24.Effect.succeed(void 0),
|
|
3309
|
+
onSome: (text) => parseDuration(flag, text)
|
|
3310
|
+
});
|
|
3311
|
+
var parseLifetime = (flag, value) => parseDuration(flag, value).pipe(
|
|
3312
|
+
import_effect24.Effect.filterOrFail(
|
|
3313
|
+
(ms) => ms >= 1 && ms <= import_sdk2.MICROVM_MAX_TIMEOUT_MS,
|
|
3314
|
+
() => new InvalidMicroVmOptionsError({ message: `${flag} can be at most 24h (got "${value}").` })
|
|
3315
|
+
)
|
|
3316
|
+
);
|
|
3317
|
+
var keyValues = (flag, entries) => {
|
|
3318
|
+
const parsed = parseKeyValues(entries);
|
|
3319
|
+
return parsed.ok ? import_effect24.Effect.succeed(entries.length > 0 ? parsed.value : void 0) : import_effect24.Effect.fail(new InvalidMicroVmOptionsError({ message: `${flag} expects KEY=VALUE, got "${parsed.entry}".` }));
|
|
3320
|
+
};
|
|
3321
|
+
var resolveApplicationId = (app) => import_effect24.Option.match(app, {
|
|
3322
|
+
onSome: (id) => import_effect24.Effect.succeed(id),
|
|
3323
|
+
onNone: () => import_effect24.Effect.gen(function* () {
|
|
3324
|
+
const projectLink = yield* ProjectLinkService;
|
|
3325
|
+
const link = yield* projectLink.load(process.cwd());
|
|
3326
|
+
return import_effect24.Option.match(link, { onNone: () => void 0, onSome: (value) => value.applicationId });
|
|
3327
|
+
})
|
|
3328
|
+
});
|
|
3329
|
+
var withClient = (run) => import_effect24.Effect.gen(function* () {
|
|
3330
|
+
const apiClient = yield* ApiClientService;
|
|
3331
|
+
const client = yield* apiClient.getClient;
|
|
3332
|
+
return yield* import_effect24.Effect.tryPromise({ try: () => run(client), catch: toApiRequestError });
|
|
3333
|
+
});
|
|
3334
|
+
var signalOnInterrupt = (signal) => (command, exit) => import_effect24.Exit.isInterrupted(exit) ? import_effect24.Effect.tryPromise(() => command.kill(signal)).pipe(import_effect24.Effect.timeout("2 seconds"), import_effect24.Effect.ignore) : import_effect24.Effect.void;
|
|
3335
|
+
var createInput = (flags) => import_effect24.Effect.gen(function* () {
|
|
3336
|
+
const env = yield* keyValues("--env", flags.env);
|
|
3337
|
+
const metadata = yield* keyValues("--metadata", flags.metadata);
|
|
3338
|
+
const timeoutMs = yield* import_effect24.Option.match(flags.timeout, {
|
|
3339
|
+
onNone: () => import_effect24.Effect.succeed(void 0),
|
|
3340
|
+
onSome: (text) => parseLifetime("--timeout", text)
|
|
3341
|
+
});
|
|
3342
|
+
const badPort = flags.ports.find((port) => !Number.isInteger(port) || port < 1 || port > 65535);
|
|
3343
|
+
if (badPort !== void 0) {
|
|
3344
|
+
return yield* new InvalidMicroVmOptionsError({ message: `--port must be between 1 and 65535 (got ${badPort}).` });
|
|
3345
|
+
}
|
|
3346
|
+
const applicationId = yield* resolveApplicationId(flags.app);
|
|
3347
|
+
const input = {
|
|
3348
|
+
...applicationId ? { applicationId } : {},
|
|
3349
|
+
...import_effect24.Option.match(flags.image, { onNone: () => ({}), onSome: (image) => ({ image }) }),
|
|
3350
|
+
...import_effect24.Option.match(flags.vcpus, {
|
|
3351
|
+
onNone: () => ({}),
|
|
3352
|
+
onSome: (vcpus) => ({ vcpus: Number(vcpus) })
|
|
3353
|
+
}),
|
|
3354
|
+
...import_effect24.Option.match(flags.memory, { onNone: () => ({}), onSome: (memoryMb) => ({ memoryMb }) }),
|
|
3355
|
+
...import_effect24.Option.match(flags.disk, { onNone: () => ({}), onSome: (diskMb) => ({ diskMb }) }),
|
|
3356
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
3357
|
+
...flags.ports.length > 0 ? { ports: [...flags.ports] } : {},
|
|
3358
|
+
...env ? { env } : {},
|
|
3359
|
+
...metadata ? { metadata } : {},
|
|
3360
|
+
...flags.denyEgress ? { network: { egress: "deny" } } : {},
|
|
3361
|
+
...import_effect24.Option.match(flags.region, { onNone: () => ({}), onSome: (region) => ({ region }) })
|
|
3362
|
+
};
|
|
3363
|
+
return input;
|
|
3364
|
+
});
|
|
3365
|
+
var createMicroVm = (flags) => import_effect24.Effect.gen(function* () {
|
|
3366
|
+
const apiClient = yield* ApiClientService;
|
|
3367
|
+
const input = yield* createInput(flags);
|
|
3368
|
+
if (!flags.json) yield* import_effect24.Console.error(`Creating a microVM from ${input.image ?? "node22"}...`);
|
|
3369
|
+
const vm = yield* apiClient.request((client) => client.microvms.create(input));
|
|
3370
|
+
if (flags.json) {
|
|
3371
|
+
yield* import_effect24.Console.log(JSON.stringify(vm, null, 2));
|
|
3372
|
+
return vm;
|
|
3373
|
+
}
|
|
3374
|
+
for (const line of describeMicroVm(vm)) yield* import_effect24.Console.log(line);
|
|
3375
|
+
yield* import_effect24.Console.log(`
|
|
3376
|
+
Run a command: gigadrive microvms exec ${vm.id} -- <command>`);
|
|
3377
|
+
yield* import_effect24.Console.log(`Open a shell: gigadrive microvms shell ${vm.id}`);
|
|
3378
|
+
return vm;
|
|
3379
|
+
});
|
|
3380
|
+
var createCommand = import_cli12.Command.make(
|
|
3381
|
+
"create",
|
|
3382
|
+
{
|
|
3383
|
+
app: appOption6,
|
|
3384
|
+
image: import_cli12.Options.text("image").pipe(
|
|
3385
|
+
import_cli12.Options.withAlias("i"),
|
|
3386
|
+
import_cli12.Options.withDescription(
|
|
3387
|
+
"Image name or ID: node22, node24, python3.13, python3.12, bun1, debian12, ubuntu24.04, or a custom image (default: node22)"
|
|
3388
|
+
),
|
|
3389
|
+
import_cli12.Options.optional
|
|
3390
|
+
),
|
|
3391
|
+
vcpus: import_cli12.Options.choice("vcpus", ["1", "2", "4"]).pipe(
|
|
3392
|
+
import_cli12.Options.withDescription("Number of vCPUs (default: 1)"),
|
|
3393
|
+
import_cli12.Options.optional
|
|
3394
|
+
),
|
|
3395
|
+
memory: import_cli12.Options.integer("memory").pipe(import_cli12.Options.withDescription("Memory in MiB (default: 2048)"), import_cli12.Options.optional),
|
|
3396
|
+
disk: import_cli12.Options.integer("disk").pipe(import_cli12.Options.withDescription("Disk in MiB (default: 10240)"), import_cli12.Options.optional),
|
|
3397
|
+
timeout: import_cli12.Options.text("timeout").pipe(
|
|
3398
|
+
import_cli12.Options.withAlias("t"),
|
|
3399
|
+
import_cli12.Options.withDescription("Lifetime before it stops automatically, such as 30m or 2h (default: 5m)"),
|
|
3400
|
+
import_cli12.Options.optional
|
|
3401
|
+
),
|
|
3402
|
+
ports: import_cli12.Options.integer("port").pipe(
|
|
3403
|
+
import_cli12.Options.withAlias("p"),
|
|
3404
|
+
import_cli12.Options.withDescription("Port to expose on a public preview URL (repeatable, up to 8)"),
|
|
3405
|
+
import_cli12.Options.repeated
|
|
3406
|
+
),
|
|
3407
|
+
env: envOption,
|
|
3408
|
+
metadata: import_cli12.Options.text("metadata").pipe(
|
|
3409
|
+
import_cli12.Options.withAlias("m"),
|
|
3410
|
+
import_cli12.Options.withDescription("Metadata as KEY=VALUE (repeatable)"),
|
|
3411
|
+
import_cli12.Options.repeated
|
|
3412
|
+
),
|
|
3413
|
+
denyEgress: import_cli12.Options.boolean("deny-egress").pipe(import_cli12.Options.withDescription("Block all outbound network traffic")),
|
|
3414
|
+
region: import_cli12.Options.text("region").pipe(import_cli12.Options.withDescription("Region to place the microVM in"), import_cli12.Options.optional),
|
|
3415
|
+
json: jsonOption2
|
|
3416
|
+
},
|
|
3417
|
+
(flags) => createMicroVm(flags).pipe(import_effect24.Effect.asVoid, reportErrors2("create the microVM"))
|
|
3418
|
+
).pipe(import_cli12.Command.withDescription("Create a microVM and wait until it runs"));
|
|
3419
|
+
var listMicroVms = (flags) => import_effect24.Effect.gen(function* () {
|
|
3420
|
+
const apiClient = yield* ApiClientService;
|
|
3421
|
+
const applicationId = yield* resolveApplicationId(flags.app);
|
|
3422
|
+
const status = import_effect24.Option.getOrUndefined(flags.status);
|
|
3423
|
+
const showAll = flags.all || status !== void 0;
|
|
3424
|
+
const vms = yield* apiClient.request(async (client) => {
|
|
3425
|
+
const items = [];
|
|
3426
|
+
for await (const vm of client.microvms.listAll({ applicationId, status, limit: Math.min(flags.limit, 100) })) {
|
|
3427
|
+
if (!showAll && (vm.status === "stopped" || vm.status === "failed")) continue;
|
|
3428
|
+
items.push(vm);
|
|
3429
|
+
if (items.length >= flags.limit) break;
|
|
3430
|
+
}
|
|
3431
|
+
return items;
|
|
3432
|
+
});
|
|
3433
|
+
if (flags.json) return yield* import_effect24.Console.log(JSON.stringify(vms, null, 2));
|
|
3434
|
+
if (vms.length === 0) {
|
|
3435
|
+
return yield* import_effect24.Console.log(
|
|
3436
|
+
showAll ? "No microVMs found." : 'No running microVMs. Create one with "gigadrive microvms create".'
|
|
3437
|
+
);
|
|
3438
|
+
}
|
|
3439
|
+
for (const line of formatMicroVmTable(vms)) yield* import_effect24.Console.log(line);
|
|
3440
|
+
});
|
|
3441
|
+
var listCommand2 = import_cli12.Command.make(
|
|
3442
|
+
"ls",
|
|
3443
|
+
{
|
|
3444
|
+
app: appOption6,
|
|
3445
|
+
status: import_cli12.Options.choice("status", MICROVM_STATUSES).pipe(
|
|
3446
|
+
import_cli12.Options.withAlias("s"),
|
|
3447
|
+
import_cli12.Options.withDescription("Only microVMs in this status"),
|
|
3448
|
+
import_cli12.Options.optional
|
|
3449
|
+
),
|
|
3450
|
+
all: import_cli12.Options.boolean("all").pipe(import_cli12.Options.withDescription("Include stopped and failed microVMs")),
|
|
3451
|
+
limit: import_cli12.Options.integer("limit").pipe(
|
|
3452
|
+
import_cli12.Options.withDescription("Show at most this many (default: 50)"),
|
|
3453
|
+
import_cli12.Options.withDefault(50)
|
|
3454
|
+
),
|
|
3455
|
+
json: jsonOption2
|
|
3456
|
+
},
|
|
3457
|
+
(flags) => listMicroVms(flags).pipe(reportErrors2("list microVMs"))
|
|
3458
|
+
).pipe(import_cli12.Command.withDescription("List microVMs"));
|
|
3459
|
+
var getCommand = import_cli12.Command.make(
|
|
3460
|
+
"get",
|
|
3461
|
+
{ microvmId: microvmIdArg, json: jsonOption2 },
|
|
3462
|
+
({ microvmId, json }) => import_effect24.Effect.gen(function* () {
|
|
3463
|
+
const apiClient = yield* ApiClientService;
|
|
3464
|
+
const vm = yield* apiClient.request((client) => client.microvms.get(microvmId));
|
|
3465
|
+
if (json) return yield* import_effect24.Console.log(JSON.stringify(vm, null, 2));
|
|
3466
|
+
for (const line of describeMicroVm(vm)) yield* import_effect24.Console.log(line);
|
|
3467
|
+
}).pipe(reportErrors2("get the microVM"))
|
|
3468
|
+
).pipe(import_cli12.Command.withDescription("Show a microVM"));
|
|
3469
|
+
var execInMicroVm = (flags, io = nodeSessionIo()) => import_effect24.Effect.gen(function* () {
|
|
3470
|
+
const env = yield* keyValues("--env", flags.env);
|
|
3471
|
+
const timeout = yield* optionalDuration("--timeout", flags.timeout);
|
|
3472
|
+
const [cmd, ...args] = flags.command;
|
|
3473
|
+
const options = {
|
|
3474
|
+
cwd: import_effect24.Option.getOrUndefined(flags.cwd),
|
|
3475
|
+
env,
|
|
3476
|
+
user: import_effect24.Option.getOrUndefined(flags.user),
|
|
3477
|
+
sudo: flags.sudo,
|
|
3478
|
+
timeout,
|
|
3479
|
+
stdin: flags.interactive
|
|
3480
|
+
};
|
|
3481
|
+
const info = yield* import_effect24.Effect.acquireUseRelease(
|
|
3482
|
+
withClient(async (client) => {
|
|
3483
|
+
const vm = await import_sdk2.MicroVM.get(flags.microvmId, { client });
|
|
3484
|
+
return args.length > 0 ? vm.spawn(cmd, args, options) : vm.spawn(cmd, options);
|
|
3485
|
+
}),
|
|
3486
|
+
(command) => import_effect24.Effect.tryPromise({
|
|
3487
|
+
try: () => attachCommand(command, io, {
|
|
3488
|
+
forwardInput: flags.interactive,
|
|
3489
|
+
endInputOnEof: true,
|
|
3490
|
+
forwardResize: false
|
|
3491
|
+
}),
|
|
3492
|
+
catch: toApiRequestError
|
|
3493
|
+
}),
|
|
3494
|
+
signalOnInterrupt("SIGINT")
|
|
3495
|
+
);
|
|
3496
|
+
return exitStatusOf(info);
|
|
3497
|
+
});
|
|
3498
|
+
var setExitCode = (status) => import_effect24.Effect.sync(() => {
|
|
3499
|
+
process.exitCode = status;
|
|
3500
|
+
});
|
|
3501
|
+
var execCommand = import_cli12.Command.make(
|
|
3502
|
+
"exec",
|
|
3503
|
+
{
|
|
3504
|
+
microvmId: microvmIdArg,
|
|
3505
|
+
command: import_cli12.Args.text({ name: "command" }).pipe(
|
|
3506
|
+
import_cli12.Args.withDescription('The command and its arguments, after "--". One quoted argument runs through /bin/sh -c'),
|
|
3507
|
+
import_cli12.Args.atLeast(1)
|
|
3508
|
+
),
|
|
3509
|
+
cwd: cwdOption,
|
|
3510
|
+
env: envOption,
|
|
3511
|
+
user: userOption,
|
|
3512
|
+
sudo: import_cli12.Options.boolean("sudo").pipe(import_cli12.Options.withDescription("Run as root")),
|
|
3513
|
+
timeout: import_cli12.Options.text("timeout").pipe(
|
|
3514
|
+
import_cli12.Options.withAlias("t"),
|
|
3515
|
+
import_cli12.Options.withDescription("Kill the command after this long, such as 30s or 10m"),
|
|
3516
|
+
import_cli12.Options.optional
|
|
3517
|
+
),
|
|
3518
|
+
interactive: import_cli12.Options.boolean("interactive").pipe(
|
|
3519
|
+
import_cli12.Options.withAlias("i"),
|
|
3520
|
+
import_cli12.Options.withDescription("Forward local stdin to the command")
|
|
3521
|
+
)
|
|
3522
|
+
},
|
|
3523
|
+
(flags) => execInMicroVm(flags).pipe(import_effect24.Effect.flatMap(setExitCode), reportErrors2("run the command"))
|
|
3524
|
+
).pipe(import_cli12.Command.withDescription("Run a command in a microVM and exit with its exit code: exec <id> -- <command...>"));
|
|
3525
|
+
var openShell = (flags, io = nodeSessionIo()) => import_effect24.Effect.gen(function* () {
|
|
3526
|
+
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
3527
|
+
return yield* new TerminalRequiredError({
|
|
3528
|
+
message: 'microvms shell needs an interactive terminal. Use "gigadrive microvms exec <id> -- <command>" in scripts.'
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
const term = yield* import_effect24.Config.string("TERM").pipe(import_effect24.Config.withDefault("xterm-256color"));
|
|
3532
|
+
const size = io.size() ?? { cols: 80, rows: 24 };
|
|
3533
|
+
const [cmd, ...args] = import_effect24.Option.match(flags.shell, { onNone: () => DEFAULT_SHELL, onSome: (shell) => [shell] });
|
|
3534
|
+
const options = {
|
|
3535
|
+
pty: { cols: size.cols, rows: size.rows },
|
|
3536
|
+
env: { TERM: term },
|
|
3537
|
+
cwd: import_effect24.Option.getOrUndefined(flags.cwd),
|
|
3538
|
+
user: import_effect24.Option.getOrUndefined(flags.user)
|
|
3539
|
+
};
|
|
3540
|
+
const info = yield* import_effect24.Effect.acquireUseRelease(
|
|
3541
|
+
withClient(async (client) => {
|
|
3542
|
+
const vm = await import_sdk2.MicroVM.get(flags.microvmId, { client });
|
|
3543
|
+
return args.length > 0 ? vm.spawn(cmd, args, options) : vm.spawn(cmd, options);
|
|
3544
|
+
}),
|
|
3545
|
+
(command) => import_effect24.Effect.acquireUseRelease(
|
|
3546
|
+
import_effect24.Effect.sync(() => process.stdin.setRawMode(true)),
|
|
3547
|
+
() => import_effect24.Effect.tryPromise({
|
|
3548
|
+
try: () => attachCommand(command, io, { forwardInput: true, endInputOnEof: false, forwardResize: true }),
|
|
3549
|
+
catch: toApiRequestError
|
|
3550
|
+
}),
|
|
3551
|
+
() => import_effect24.Effect.sync(() => process.stdin.setRawMode(false))
|
|
3552
|
+
),
|
|
3553
|
+
signalOnInterrupt("SIGHUP")
|
|
3554
|
+
);
|
|
3555
|
+
return exitStatusOf(info);
|
|
3556
|
+
});
|
|
3557
|
+
var shellCommand = import_cli12.Command.make(
|
|
3558
|
+
"shell",
|
|
3559
|
+
{
|
|
3560
|
+
microvmId: microvmIdArg,
|
|
3561
|
+
shell: import_cli12.Options.text("shell").pipe(
|
|
3562
|
+
import_cli12.Options.withDescription("Program to run instead of the login shell, such as python3"),
|
|
3563
|
+
import_cli12.Options.optional
|
|
3564
|
+
),
|
|
3565
|
+
cwd: cwdOption,
|
|
3566
|
+
user: userOption
|
|
3567
|
+
},
|
|
3568
|
+
(flags) => openShell(flags).pipe(import_effect24.Effect.flatMap(setExitCode), reportErrors2("open a shell"))
|
|
3569
|
+
).pipe(import_cli12.Command.withDescription("Open an interactive shell in a microVM"));
|
|
3570
|
+
var localError = (path2, action) => () => new LocalFileError({ message: `Failed to ${action} ${path2}`, path: path2 });
|
|
3571
|
+
var parseTarget = (value) => {
|
|
3572
|
+
const target = parseCopyTarget(value);
|
|
3573
|
+
return typeof target === "string" ? import_effect24.Effect.fail(new InvalidCopyTargetError({ message: target })) : import_effect24.Effect.succeed(target);
|
|
3574
|
+
};
|
|
3575
|
+
var remoteStat = (client, microvmId, path2) => import_effect24.Effect.tryPromise({ try: () => client.microvms.files.stat(microvmId, path2), catch: toApiRequestError }).pipe(
|
|
3576
|
+
import_effect24.Effect.map(import_effect24.Option.some),
|
|
3577
|
+
import_effect24.Effect.catchIf(
|
|
3578
|
+
(error) => error.statusCode === 404,
|
|
3579
|
+
() => import_effect24.Effect.succeed(import_effect24.Option.none())
|
|
3580
|
+
)
|
|
3581
|
+
);
|
|
3582
|
+
var upload = (client, source, target) => import_effect24.Effect.gen(function* () {
|
|
3583
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
3584
|
+
const path2 = yield* import_platform8.Path.Path;
|
|
3585
|
+
const info = yield* fs.stat(source).pipe(import_effect24.Effect.mapError(localError(source, "read")));
|
|
3586
|
+
const existing = yield* remoteStat(client, target.microvmId, target.path);
|
|
3587
|
+
const intoDirectory = target.path.endsWith("/") || import_effect24.Option.exists(existing, (entry) => entry.type === "directory");
|
|
3588
|
+
const destination = intoDirectory ? posixJoin(target.path, path2.basename(source)) : target.path;
|
|
3589
|
+
const files = [];
|
|
3590
|
+
if (info.type === "Directory") {
|
|
3591
|
+
const entries = yield* fs.readDirectory(source, { recursive: true }).pipe(import_effect24.Effect.mapError(localError(source, "list")));
|
|
3592
|
+
for (const entry of entries) {
|
|
3593
|
+
const local = path2.join(source, entry);
|
|
3594
|
+
const stat = yield* fs.stat(local).pipe(import_effect24.Effect.mapError(localError(local, "read")));
|
|
3595
|
+
if (stat.type === "File")
|
|
3596
|
+
files.push({ local, remote: posixJoin(destination, entry.split(path2.sep).join("/")) });
|
|
3597
|
+
}
|
|
3598
|
+
} else {
|
|
3599
|
+
files.push({ local: source, remote: destination });
|
|
3600
|
+
}
|
|
3601
|
+
let bytes = 0;
|
|
3602
|
+
for (const file of files) {
|
|
3603
|
+
const content = yield* fs.readFile(file.local).pipe(import_effect24.Effect.mapError(localError(file.local, "read")));
|
|
3604
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
3605
|
+
try: () => client.microvms.files.write(target.microvmId, file.remote, content),
|
|
3606
|
+
catch: toApiRequestError
|
|
3607
|
+
});
|
|
3608
|
+
bytes += result.bytes;
|
|
3609
|
+
}
|
|
3610
|
+
return { files: files.length, bytes };
|
|
3611
|
+
});
|
|
3612
|
+
var download = (client, source, target) => import_effect24.Effect.gen(function* () {
|
|
3613
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
3614
|
+
const path2 = yield* import_platform8.Path.Path;
|
|
3615
|
+
const entry = yield* import_effect24.Effect.tryPromise({
|
|
3616
|
+
try: () => client.microvms.files.stat(source.microvmId, source.path),
|
|
3617
|
+
catch: toApiRequestError
|
|
3618
|
+
});
|
|
3619
|
+
const targetExists = yield* fs.exists(target).pipe(import_effect24.Effect.mapError(localError(target, "check")));
|
|
3620
|
+
const targetIsDirectory = targetExists ? (yield* fs.stat(target).pipe(import_effect24.Effect.mapError(localError(target, "read")))).type === "Directory" : false;
|
|
3621
|
+
const intoDirectory = targetIsDirectory || target.endsWith(path2.sep) || target.endsWith("/");
|
|
3622
|
+
const destination = intoDirectory ? path2.join(target, posixBasename(entry.path)) : target;
|
|
3623
|
+
const files = [];
|
|
3624
|
+
if (entry.type === "directory") {
|
|
3625
|
+
const listing = yield* import_effect24.Effect.tryPromise({
|
|
3626
|
+
try: () => client.microvms.files.list(source.microvmId, entry.path, { recursive: true }),
|
|
3627
|
+
catch: toApiRequestError
|
|
3628
|
+
});
|
|
3629
|
+
if (listing.truncated) {
|
|
3630
|
+
yield* import_effect24.Console.error(
|
|
3631
|
+
`${entry.path} has too many files to list at once; only part of it is copied. Copy its subdirectories separately.`
|
|
3632
|
+
);
|
|
3633
|
+
}
|
|
3634
|
+
for (const child of listing.entries) {
|
|
3635
|
+
if (child.type !== "file") continue;
|
|
3636
|
+
const segments = relativeTo(entry.path, child.path).split("/");
|
|
3637
|
+
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
3638
|
+
yield* import_effect24.Console.error(`Skipped ${child.path}: its path leaves ${entry.path}.`);
|
|
3639
|
+
continue;
|
|
3640
|
+
}
|
|
3641
|
+
files.push({ remote: child.path, local: path2.join(destination, ...segments) });
|
|
3642
|
+
}
|
|
3643
|
+
yield* fs.makeDirectory(destination, { recursive: true }).pipe(import_effect24.Effect.mapError(localError(destination, "create")));
|
|
3644
|
+
} else {
|
|
3645
|
+
files.push({ remote: entry.path, local: destination });
|
|
3646
|
+
}
|
|
3647
|
+
let bytes = 0;
|
|
3648
|
+
for (const file of files) {
|
|
3649
|
+
const content = yield* import_effect24.Effect.tryPromise({
|
|
3650
|
+
try: () => client.microvms.files.read(source.microvmId, file.remote),
|
|
3651
|
+
catch: toApiRequestError
|
|
3652
|
+
});
|
|
3653
|
+
yield* fs.makeDirectory(path2.dirname(file.local), { recursive: true }).pipe(import_effect24.Effect.mapError(localError(file.local, "create the directory of")));
|
|
3654
|
+
yield* fs.writeFile(file.local, content).pipe(import_effect24.Effect.mapError(localError(file.local, "write")));
|
|
3655
|
+
bytes += content.length;
|
|
3656
|
+
}
|
|
3657
|
+
return { files: files.length, bytes };
|
|
3658
|
+
});
|
|
3659
|
+
var copyFiles = (sourceSpec, targetSpec) => import_effect24.Effect.gen(function* () {
|
|
3660
|
+
const source = yield* parseTarget(sourceSpec);
|
|
3661
|
+
const target = yield* parseTarget(targetSpec);
|
|
3662
|
+
const apiClient = yield* ApiClientService;
|
|
3663
|
+
const client = yield* apiClient.getClient;
|
|
3664
|
+
if (source.kind === "local" && target.kind === "remote") return yield* upload(client, source.path, target);
|
|
3665
|
+
if (source.kind === "remote" && target.kind === "local") return yield* download(client, source, target.path);
|
|
3666
|
+
return yield* new InvalidCopyTargetError({
|
|
3667
|
+
message: 'One side must be local and the other vm:<id>:<path>, e.g. "gigadrive microvms cp ./app vm:<id>:/app".'
|
|
3668
|
+
});
|
|
3669
|
+
});
|
|
3670
|
+
var copyCommand = import_cli12.Command.make(
|
|
3671
|
+
"cp",
|
|
3672
|
+
{
|
|
3673
|
+
source: import_cli12.Args.text({ name: "source" }).pipe(import_cli12.Args.withDescription("Local path or vm:<id>:<path>")),
|
|
3674
|
+
target: import_cli12.Args.text({ name: "target" }).pipe(import_cli12.Args.withDescription("Local path or vm:<id>:<path>"))
|
|
3675
|
+
},
|
|
3676
|
+
({ source, target }) => copyFiles(source, target).pipe(
|
|
3677
|
+
import_effect24.Effect.flatMap(
|
|
3678
|
+
(result) => import_effect24.Console.log(`Copied ${result.files} file${result.files === 1 ? "" : "s"} (${formatBytes(result.bytes)}).`)
|
|
3679
|
+
),
|
|
3680
|
+
reportErrors2("copy")
|
|
3681
|
+
)
|
|
3682
|
+
).pipe(import_cli12.Command.withDescription("Copy files between this machine and a microVM (vm:<id>:<path>)"));
|
|
3683
|
+
var microvmIdsArg = import_cli12.Args.text({ name: "microvm-id" }).pipe(
|
|
3684
|
+
import_cli12.Args.withDescription("One or more microVM IDs"),
|
|
3685
|
+
import_cli12.Args.atLeast(1)
|
|
3686
|
+
);
|
|
3687
|
+
var stopCommand = import_cli12.Command.make(
|
|
3688
|
+
"stop",
|
|
3689
|
+
{ microvmIds: microvmIdsArg },
|
|
3690
|
+
({ microvmIds }) => import_effect24.Effect.forEach(
|
|
3691
|
+
microvmIds,
|
|
3692
|
+
(microvmId) => import_effect24.Effect.gen(function* () {
|
|
3693
|
+
const apiClient = yield* ApiClientService;
|
|
3694
|
+
yield* apiClient.request((client) => client.microvms.stop(microvmId));
|
|
3695
|
+
yield* import_effect24.Console.log(`Stopped ${microvmId}.`);
|
|
3696
|
+
}),
|
|
3697
|
+
{ discard: true }
|
|
3698
|
+
).pipe(reportErrors2("stop the microVM"))
|
|
3699
|
+
).pipe(import_cli12.Command.withDescription("Stop microVMs; their disk and memory are discarded"));
|
|
3700
|
+
var removeCommand2 = import_cli12.Command.make(
|
|
3701
|
+
"rm",
|
|
3702
|
+
{ microvmIds: microvmIdsArg },
|
|
3703
|
+
({ microvmIds }) => import_effect24.Effect.forEach(
|
|
3704
|
+
microvmIds,
|
|
3705
|
+
(microvmId) => import_effect24.Effect.gen(function* () {
|
|
3706
|
+
const apiClient = yield* ApiClientService;
|
|
3707
|
+
yield* apiClient.request((client) => client.microvms.delete(microvmId));
|
|
3708
|
+
yield* import_effect24.Console.log(`Deleted ${microvmId}.`);
|
|
3709
|
+
}),
|
|
3710
|
+
{ discard: true }
|
|
3711
|
+
).pipe(reportErrors2("delete the microVM"))
|
|
3712
|
+
).pipe(import_cli12.Command.withDescription("Delete microVMs, stopping them first"));
|
|
3713
|
+
var extendMicroVm = (microvmId, duration) => import_effect24.Effect.gen(function* () {
|
|
3714
|
+
const timeoutMs = yield* parseLifetime("The duration", duration);
|
|
3715
|
+
const apiClient = yield* ApiClientService;
|
|
3716
|
+
const vm = yield* apiClient.request((client) => client.microvms.extendTimeout(microvmId, timeoutMs));
|
|
3717
|
+
yield* import_effect24.Console.log(`${vm.id} now stops at ${vm.expiresAt ?? "an unknown time"}.`);
|
|
3718
|
+
return vm;
|
|
3719
|
+
});
|
|
3720
|
+
var extendCommand = import_cli12.Command.make(
|
|
3721
|
+
"extend",
|
|
3722
|
+
{
|
|
3723
|
+
microvmId: microvmIdArg,
|
|
3724
|
+
duration: import_cli12.Args.text({ name: "duration" }).pipe(
|
|
3725
|
+
import_cli12.Args.withDescription("New remaining lifetime from now, such as 30m")
|
|
3726
|
+
)
|
|
3727
|
+
},
|
|
3728
|
+
({ microvmId, duration }) => extendMicroVm(microvmId, duration).pipe(import_effect24.Effect.asVoid, reportErrors2("extend the microVM"))
|
|
3729
|
+
).pipe(import_cli12.Command.withDescription("Set how long a microVM keeps running, counted from now"));
|
|
3730
|
+
var imagesListCommand = import_cli12.Command.make(
|
|
3731
|
+
"ls",
|
|
3732
|
+
{ app: appOption6, json: jsonOption2 },
|
|
3733
|
+
({ app, json }) => import_effect24.Effect.gen(function* () {
|
|
3734
|
+
const apiClient = yield* ApiClientService;
|
|
3735
|
+
const applicationId = yield* resolveApplicationId(app);
|
|
3736
|
+
const images = yield* apiClient.request((client) => client.microvms.images.list({ applicationId }));
|
|
3737
|
+
if (json) return yield* import_effect24.Console.log(JSON.stringify(images, null, 2));
|
|
3738
|
+
for (const line of formatImageTable(images)) yield* import_effect24.Console.log(line);
|
|
3739
|
+
}).pipe(reportErrors2("list images"))
|
|
3740
|
+
).pipe(import_cli12.Command.withDescription("List built-in and custom images"));
|
|
3741
|
+
var createImage = (flags) => import_effect24.Effect.gen(function* () {
|
|
3742
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
3743
|
+
const apiClient = yield* ApiClientService;
|
|
3744
|
+
if (import_effect24.Option.isSome(flags.from) === import_effect24.Option.isSome(flags.dockerfile)) {
|
|
3745
|
+
return yield* new InvalidMicroVmOptionsError({
|
|
3746
|
+
message: "Pass exactly one of --from <registry reference> or --dockerfile <path>."
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3749
|
+
const from = import_effect24.Option.isSome(flags.from) ? flags.from.value : {
|
|
3750
|
+
dockerfile: yield* fs.readFileString(import_effect24.Option.getOrElse(flags.dockerfile, () => "Dockerfile")).pipe(
|
|
3751
|
+
import_effect24.Effect.mapError(
|
|
3752
|
+
localError(
|
|
3753
|
+
import_effect24.Option.getOrElse(flags.dockerfile, () => "Dockerfile"),
|
|
3754
|
+
"read"
|
|
3755
|
+
)
|
|
3756
|
+
)
|
|
3757
|
+
)
|
|
3758
|
+
};
|
|
3759
|
+
const applicationId = yield* resolveApplicationId(flags.app);
|
|
3760
|
+
let image = yield* apiClient.request(
|
|
3761
|
+
(client) => client.microvms.images.create({ name: flags.name, from, ...applicationId ? { applicationId } : {} })
|
|
3762
|
+
);
|
|
3763
|
+
if (flags.wait) {
|
|
3764
|
+
if (!flags.json) yield* import_effect24.Console.error(`Building ${image.name}...`);
|
|
3765
|
+
image = yield* apiClient.request(
|
|
3766
|
+
(client) => client.microvms.images.waitUntilReady(image.id, {
|
|
3767
|
+
onStatus: (current) => {
|
|
3768
|
+
if (!flags.json) process.stderr.write(` ${current.status}
|
|
3769
|
+
`);
|
|
3770
|
+
}
|
|
3771
|
+
})
|
|
3772
|
+
);
|
|
3773
|
+
}
|
|
3774
|
+
if (flags.json) {
|
|
3775
|
+
yield* import_effect24.Console.log(JSON.stringify(image, null, 2));
|
|
3776
|
+
} else if (image.status === "ready") {
|
|
3777
|
+
yield* import_effect24.Console.log(`${image.name} is ready. Use it with: gigadrive microvms create --image ${image.name}`);
|
|
3778
|
+
} else {
|
|
3779
|
+
yield* import_effect24.Console.log(
|
|
3780
|
+
`${image.name} is ${image.status} (${image.id}). Check it with "gigadrive microvms images ls".`
|
|
3781
|
+
);
|
|
3782
|
+
}
|
|
3783
|
+
return image;
|
|
3784
|
+
});
|
|
3785
|
+
var imagesCreateCommand = import_cli12.Command.make(
|
|
3786
|
+
"create",
|
|
3787
|
+
{
|
|
3788
|
+
name: import_cli12.Args.text({ name: "name" }).pipe(
|
|
3789
|
+
import_cli12.Args.withDescription('Image name: lowercase letters, digits, ".", "_", "-"')
|
|
3790
|
+
),
|
|
3791
|
+
app: appOption6,
|
|
3792
|
+
from: import_cli12.Options.text("from").pipe(
|
|
3793
|
+
import_cli12.Options.withDescription("Public linux/amd64 registry image, such as python:3.13 or ghcr.io/acme/tool:1"),
|
|
3794
|
+
import_cli12.Options.optional
|
|
3795
|
+
),
|
|
3796
|
+
dockerfile: import_cli12.Options.text("dockerfile").pipe(
|
|
3797
|
+
import_cli12.Options.withAlias("f"),
|
|
3798
|
+
import_cli12.Options.withDescription("Build from this Dockerfile instead"),
|
|
3799
|
+
import_cli12.Options.optional
|
|
3800
|
+
),
|
|
3801
|
+
wait: import_cli12.Options.boolean("wait").pipe(import_cli12.Options.withDescription("Wait until the build finished")),
|
|
3802
|
+
json: jsonOption2
|
|
3803
|
+
},
|
|
3804
|
+
(flags) => createImage(flags).pipe(import_effect24.Effect.asVoid, reportErrors2("create the image"))
|
|
3805
|
+
).pipe(import_cli12.Command.withDescription("Build a custom image from a registry image or a Dockerfile"));
|
|
3806
|
+
var removeImage = (idOrName, app) => import_effect24.Effect.gen(function* () {
|
|
3807
|
+
const apiClient = yield* ApiClientService;
|
|
3808
|
+
const applicationId = yield* resolveApplicationId(app);
|
|
3809
|
+
const images = yield* apiClient.request((client) => client.microvms.images.list({ applicationId }));
|
|
3810
|
+
const image = images.find((candidate) => candidate.id === idOrName) ?? images.find((candidate) => !candidate.builtin && candidate.name === idOrName) ?? { id: idOrName, name: idOrName };
|
|
3811
|
+
yield* apiClient.request((client) => client.microvms.images.delete(image.id));
|
|
3812
|
+
yield* import_effect24.Console.log(`Deleted image ${image.name}.`);
|
|
3813
|
+
});
|
|
3814
|
+
var imagesRemoveCommand = import_cli12.Command.make(
|
|
3815
|
+
"rm",
|
|
3816
|
+
{
|
|
3817
|
+
image: import_cli12.Args.text({ name: "image" }).pipe(import_cli12.Args.withDescription("Image ID or name")),
|
|
3818
|
+
app: appOption6
|
|
3819
|
+
},
|
|
3820
|
+
({ image, app }) => removeImage(image, app).pipe(reportErrors2("delete the image"))
|
|
3821
|
+
).pipe(import_cli12.Command.withDescription("Delete a custom image"));
|
|
3822
|
+
var imagesCommand = import_cli12.Command.make("images", {}, () => import_effect24.Effect.void).pipe(
|
|
3823
|
+
import_cli12.Command.withDescription("Built-in and custom microVM images"),
|
|
3824
|
+
import_cli12.Command.withSubcommands([imagesListCommand, imagesCreateCommand, imagesRemoveCommand])
|
|
3825
|
+
);
|
|
3826
|
+
var SUBCOMMANDS = [
|
|
3827
|
+
createCommand,
|
|
3828
|
+
listCommand2,
|
|
3829
|
+
getCommand,
|
|
3830
|
+
execCommand,
|
|
3831
|
+
shellCommand,
|
|
3832
|
+
copyCommand,
|
|
3833
|
+
stopCommand,
|
|
3834
|
+
removeCommand2,
|
|
3835
|
+
extendCommand,
|
|
3836
|
+
imagesCommand
|
|
3837
|
+
];
|
|
3838
|
+
var microvmsCommand = import_cli12.Command.make("microvms", {}, () => import_effect24.Effect.void).pipe(
|
|
3839
|
+
import_cli12.Command.withDescription("Isolated Linux machines for running code: create, exec, shell, cp, stop"),
|
|
3840
|
+
import_cli12.Command.withSubcommands(SUBCOMMANDS)
|
|
3841
|
+
);
|
|
3842
|
+
var vmCommand = import_cli12.Command.make("vm", {}, () => import_effect24.Effect.void).pipe(
|
|
3843
|
+
import_cli12.Command.withDescription('Alias of "gigadrive microvms"'),
|
|
3844
|
+
import_cli12.Command.withSubcommands(SUBCOMMANDS)
|
|
3845
|
+
);
|
|
3846
|
+
|
|
2956
3847
|
// src/commands/platform/index.ts
|
|
2957
|
-
var
|
|
2958
|
-
var
|
|
3848
|
+
var import_cli14 = require("@effect/cli");
|
|
3849
|
+
var import_effect28 = require("effect");
|
|
2959
3850
|
|
|
2960
3851
|
// src/commands/platform/deploy/index.ts
|
|
2961
|
-
var
|
|
2962
|
-
var
|
|
3852
|
+
var import_cli13 = require("@effect/cli");
|
|
3853
|
+
var import_platform10 = require("@effect/platform");
|
|
2963
3854
|
var import_commons = require("@gigadrive/commons");
|
|
2964
|
-
var
|
|
3855
|
+
var import_effect27 = require("effect");
|
|
2965
3856
|
var os4 = __toESM(require("os"), 1);
|
|
2966
3857
|
var path = __toESM(require("path"), 1);
|
|
2967
3858
|
|
|
2968
3859
|
// src/services/archive.ts
|
|
2969
|
-
var
|
|
3860
|
+
var import_platform9 = require("@effect/platform");
|
|
2970
3861
|
var import_build_utils3 = require("@gigadrive/build-utils");
|
|
2971
3862
|
var import_archiver = __toESM(require("archiver"), 1);
|
|
2972
|
-
var
|
|
3863
|
+
var import_effect25 = require("effect");
|
|
2973
3864
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
2974
3865
|
var nodeFs = __toESM(require("fs"), 1);
|
|
2975
3866
|
var nodeFsPromises = __toESM(require("fs/promises"), 1);
|
|
@@ -2994,15 +3885,15 @@ var CONTAINER_BUILD_FILE_PATTERNS = [
|
|
|
2994
3885
|
];
|
|
2995
3886
|
var DOCKER_BUILD_IGNORE_FILE = ".dockerignore";
|
|
2996
3887
|
var readIgnoreFile = (fs, ignorePath) => fs.readFileString(ignorePath, "utf8").pipe(
|
|
2997
|
-
|
|
2998
|
-
|
|
3888
|
+
import_effect25.Effect.map((content) => content.split("\n").filter((line) => line.trim() !== "")),
|
|
3889
|
+
import_effect25.Effect.catchAll(() => import_effect25.Effect.succeed([]))
|
|
2999
3890
|
);
|
|
3000
|
-
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules, ignoreFileNames) =>
|
|
3001
|
-
const items = yield* fs.readDirectory(dir).pipe(
|
|
3891
|
+
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules, ignoreFileNames) => import_effect25.Effect.gen(function* () {
|
|
3892
|
+
const items = yield* fs.readDirectory(dir).pipe(import_effect25.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${dir}` })));
|
|
3002
3893
|
for (const item of items) {
|
|
3003
3894
|
const fullPath = pathService.join(dir, item);
|
|
3004
3895
|
const relativePath = pathService.relative(baseDir, fullPath);
|
|
3005
|
-
const stat = yield*
|
|
3896
|
+
const stat = yield* import_effect25.Effect.tryPromise({
|
|
3006
3897
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
3007
3898
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
3008
3899
|
});
|
|
@@ -3022,8 +3913,8 @@ var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules, ignoreF
|
|
|
3022
3913
|
yield* collectIgnorePatterns(fs, pathService, fullPath, baseDir, ignoreRules, ignoreFileNames);
|
|
3023
3914
|
}
|
|
3024
3915
|
}
|
|
3025
|
-
}).pipe(
|
|
3026
|
-
var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManagedIgnore, buildsContainerImages) =>
|
|
3916
|
+
}).pipe(import_effect25.Effect.catchAll(() => import_effect25.Effect.void));
|
|
3917
|
+
var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManagedIgnore, buildsContainerImages) => import_effect25.Effect.gen(function* () {
|
|
3027
3918
|
const ignoreRules = (0, import_ignore.default)();
|
|
3028
3919
|
const ignoreFileNames = buildsContainerImages ? IGNORE_FILE_NAMES.filter((name) => name !== DOCKER_BUILD_IGNORE_FILE) : IGNORE_FILE_NAMES;
|
|
3029
3920
|
if (useManagedIgnore) {
|
|
@@ -3044,14 +3935,14 @@ var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManage
|
|
|
3044
3935
|
}
|
|
3045
3936
|
return ignoreRules;
|
|
3046
3937
|
});
|
|
3047
|
-
var getFilesToInclude = (fs, pathService, dir, ignoreRules) =>
|
|
3938
|
+
var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect25.Effect.gen(function* () {
|
|
3048
3939
|
const filesToInclude = [];
|
|
3049
|
-
const walkDir = (currentDir) =>
|
|
3050
|
-
const items = yield* fs.readDirectory(currentDir).pipe(
|
|
3940
|
+
const walkDir = (currentDir) => import_effect25.Effect.gen(function* () {
|
|
3941
|
+
const items = yield* fs.readDirectory(currentDir).pipe(import_effect25.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${currentDir}` })));
|
|
3051
3942
|
for (const item of items) {
|
|
3052
3943
|
const fullPath = pathService.join(currentDir, item);
|
|
3053
3944
|
const relativePath = pathService.relative(dir, fullPath);
|
|
3054
|
-
const stat = yield*
|
|
3945
|
+
const stat = yield* import_effect25.Effect.tryPromise({
|
|
3055
3946
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
3056
3947
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
3057
3948
|
});
|
|
@@ -3065,19 +3956,19 @@ var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect24.E
|
|
|
3065
3956
|
}
|
|
3066
3957
|
}
|
|
3067
3958
|
}
|
|
3068
|
-
}).pipe(
|
|
3959
|
+
}).pipe(import_effect25.Effect.catchAll(() => import_effect25.Effect.void));
|
|
3069
3960
|
yield* walkDir(dir);
|
|
3070
3961
|
return filesToInclude;
|
|
3071
3962
|
});
|
|
3072
|
-
var ArchiveService = class extends
|
|
3963
|
+
var ArchiveService = class extends import_effect25.Effect.Service()("ArchiveService", {
|
|
3073
3964
|
accessors: true,
|
|
3074
|
-
effect:
|
|
3075
|
-
const fs = yield*
|
|
3076
|
-
const pathService = yield*
|
|
3077
|
-
const createZipArchive =
|
|
3078
|
-
yield*
|
|
3079
|
-
yield*
|
|
3080
|
-
yield*
|
|
3965
|
+
effect: import_effect25.Effect.gen(function* () {
|
|
3966
|
+
const fs = yield* import_platform9.FileSystem.FileSystem;
|
|
3967
|
+
const pathService = yield* import_platform9.Path.Path;
|
|
3968
|
+
const createZipArchive = import_effect25.Effect.fn("ArchiveService.createZipArchive")(function* (inputDir, outputFile, options = {}) {
|
|
3969
|
+
yield* import_effect25.Effect.annotateCurrentSpan("inputDir", inputDir);
|
|
3970
|
+
yield* import_effect25.Effect.annotateCurrentSpan("outputFile", outputFile);
|
|
3971
|
+
yield* import_effect25.Effect.log("Creating zip archive", { inputDir, outputFile });
|
|
3081
3972
|
const ignoreRules = yield* initializeIgnoreRules(
|
|
3082
3973
|
fs,
|
|
3083
3974
|
pathService,
|
|
@@ -3086,7 +3977,7 @@ var ArchiveService = class extends import_effect24.Effect.Service()("ArchiveServ
|
|
|
3086
3977
|
options.useManagedIgnore !== false,
|
|
3087
3978
|
options.buildsContainerImages === true
|
|
3088
3979
|
);
|
|
3089
|
-
const filesToInclude = options.whitelist ? yield*
|
|
3980
|
+
const filesToInclude = options.whitelist ? yield* import_effect25.Effect.tryPromise({
|
|
3090
3981
|
try: () => Promise.all(
|
|
3091
3982
|
options.whitelist.map((file) => (0, import_build_utils3.getFilesForPattern)(file, inputDir, options.excludeFiles ?? []))
|
|
3092
3983
|
),
|
|
@@ -3094,25 +3985,25 @@ var ArchiveService = class extends import_effect24.Effect.Service()("ArchiveServ
|
|
|
3094
3985
|
message: "Failed to resolve whitelist patterns",
|
|
3095
3986
|
cause: error instanceof Error ? error.message : String(error)
|
|
3096
3987
|
})
|
|
3097
|
-
}) : yield*
|
|
3988
|
+
}) : yield* import_effect25.Effect.gen(function* () {
|
|
3098
3989
|
if (options.excludeFiles && options.excludeFiles.length > 0) {
|
|
3099
3990
|
ignoreRules.add(options.excludeFiles);
|
|
3100
3991
|
}
|
|
3101
3992
|
return yield* getFilesToInclude(fs, pathService, inputDir, ignoreRules).pipe(
|
|
3102
|
-
|
|
3993
|
+
import_effect25.Effect.map((files) => [files])
|
|
3103
3994
|
);
|
|
3104
3995
|
});
|
|
3105
|
-
const archiveExists = yield* fs.exists(outputFile).pipe(
|
|
3996
|
+
const archiveExists = yield* fs.exists(outputFile).pipe(import_effect25.Effect.catchAll(() => import_effect25.Effect.succeed(false)));
|
|
3106
3997
|
if (archiveExists) {
|
|
3107
3998
|
yield* fs.remove(outputFile).pipe(
|
|
3108
|
-
|
|
3999
|
+
import_effect25.Effect.mapError(
|
|
3109
4000
|
(error) => new ArchiveCreateError({
|
|
3110
4001
|
message: `Failed to remove existing archive: ${String(error)}`
|
|
3111
4002
|
})
|
|
3112
4003
|
)
|
|
3113
4004
|
);
|
|
3114
4005
|
}
|
|
3115
|
-
yield*
|
|
4006
|
+
yield* import_effect25.Effect.tryPromise({
|
|
3116
4007
|
try: () => new Promise((resolve, reject) => {
|
|
3117
4008
|
const output = nodeFs.createWriteStream(outputFile);
|
|
3118
4009
|
const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
|
|
@@ -3131,14 +4022,14 @@ var ArchiveService = class extends import_effect24.Effect.Service()("ArchiveServ
|
|
|
3131
4022
|
})
|
|
3132
4023
|
});
|
|
3133
4024
|
const fileInfo = yield* fs.stat(outputFile).pipe(
|
|
3134
|
-
|
|
4025
|
+
import_effect25.Effect.mapError(
|
|
3135
4026
|
(error) => new ArchiveCreateError({
|
|
3136
4027
|
message: `Failed to stat archive: ${String(error)}`
|
|
3137
4028
|
})
|
|
3138
4029
|
)
|
|
3139
4030
|
);
|
|
3140
4031
|
const size = Number(fileInfo.size);
|
|
3141
|
-
yield*
|
|
4032
|
+
yield* import_effect25.Effect.log("Archive created", { size });
|
|
3142
4033
|
return { path: outputFile, size };
|
|
3143
4034
|
});
|
|
3144
4035
|
return { createZipArchive };
|
|
@@ -3147,32 +4038,32 @@ var ArchiveService = class extends import_effect24.Effect.Service()("ArchiveServ
|
|
|
3147
4038
|
};
|
|
3148
4039
|
|
|
3149
4040
|
// src/services/deployment-api.ts
|
|
3150
|
-
var
|
|
3151
|
-
var DeploymentApiService = class extends
|
|
4041
|
+
var import_effect26 = require("effect");
|
|
4042
|
+
var DeploymentApiService = class extends import_effect26.Effect.Service()("DeploymentApiService", {
|
|
3152
4043
|
accessors: true,
|
|
3153
4044
|
dependencies: [ApiClientService.Default],
|
|
3154
|
-
effect:
|
|
4045
|
+
effect: import_effect26.Effect.gen(function* () {
|
|
3155
4046
|
const apiClient = yield* ApiClientService;
|
|
3156
4047
|
const getClient = apiClient.getClient.pipe(
|
|
3157
|
-
|
|
4048
|
+
import_effect26.Effect.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
|
|
3158
4049
|
);
|
|
3159
|
-
const createDeployment =
|
|
3160
|
-
yield*
|
|
3161
|
-
yield*
|
|
4050
|
+
const createDeployment = import_effect26.Effect.fn("DeploymentApiService.createDeployment")(function* (applicationId) {
|
|
4051
|
+
yield* import_effect26.Effect.annotateCurrentSpan("applicationId", applicationId);
|
|
4052
|
+
yield* import_effect26.Effect.log("Creating deployment", { applicationId });
|
|
3162
4053
|
const client = yield* getClient;
|
|
3163
|
-
const deployment = yield*
|
|
4054
|
+
const deployment = yield* import_effect26.Effect.tryPromise({
|
|
3164
4055
|
try: () => client.deployments.create({ applicationId }),
|
|
3165
4056
|
catch: (error) => new DeploymentCreateError({
|
|
3166
4057
|
message: `Failed to create deployment: ${error instanceof Error ? error.message : String(error)}`
|
|
3167
4058
|
})
|
|
3168
4059
|
});
|
|
3169
|
-
yield*
|
|
4060
|
+
yield* import_effect26.Effect.log("Deployment created", { deploymentId: deployment.id });
|
|
3170
4061
|
return deployment.id;
|
|
3171
4062
|
});
|
|
3172
|
-
const startMultipartUpload =
|
|
3173
|
-
yield*
|
|
4063
|
+
const startMultipartUpload = import_effect26.Effect.fn("DeploymentApiService.startMultipartUpload")(function* (deploymentId) {
|
|
4064
|
+
yield* import_effect26.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
3174
4065
|
const client = yield* getClient;
|
|
3175
|
-
const result = yield*
|
|
4066
|
+
const result = yield* import_effect26.Effect.tryPromise({
|
|
3176
4067
|
try: () => client.deployments.startUpload(deploymentId),
|
|
3177
4068
|
catch: (error) => new UploadStartError({
|
|
3178
4069
|
message: `Failed to start multipart upload: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -3180,9 +4071,9 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3180
4071
|
});
|
|
3181
4072
|
return result.uploadId;
|
|
3182
4073
|
});
|
|
3183
|
-
const getPresignedUrl =
|
|
4074
|
+
const getPresignedUrl = import_effect26.Effect.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
|
|
3184
4075
|
const client = yield* getClient;
|
|
3185
|
-
const result = yield*
|
|
4076
|
+
const result = yield* import_effect26.Effect.tryPromise({
|
|
3186
4077
|
try: () => client.deployments.getPresignedUrl(deploymentId, uploadId, partNumber),
|
|
3187
4078
|
catch: (error) => new PresignedUrlError({
|
|
3188
4079
|
message: `Failed to get presigned URL: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -3191,11 +4082,11 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3191
4082
|
});
|
|
3192
4083
|
return result.url;
|
|
3193
4084
|
});
|
|
3194
|
-
const uploadPart =
|
|
3195
|
-
yield*
|
|
3196
|
-
yield*
|
|
4085
|
+
const uploadPart = import_effect26.Effect.fn("DeploymentApiService.uploadPart")(function* (presignedUrl, data, partNumber) {
|
|
4086
|
+
yield* import_effect26.Effect.annotateCurrentSpan("partNumber", partNumber);
|
|
4087
|
+
yield* import_effect26.Effect.annotateCurrentSpan("size", data.length);
|
|
3197
4088
|
const client = yield* getClient;
|
|
3198
|
-
const result = yield*
|
|
4089
|
+
const result = yield* import_effect26.Effect.tryPromise({
|
|
3199
4090
|
try: () => client.deployments.uploadPart(presignedUrl, data, partNumber),
|
|
3200
4091
|
catch: (error) => new UploadPartError({
|
|
3201
4092
|
message: `Failed to upload part ${partNumber}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -3204,21 +4095,21 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3204
4095
|
});
|
|
3205
4096
|
return result;
|
|
3206
4097
|
});
|
|
3207
|
-
const completeUpload =
|
|
3208
|
-
yield*
|
|
3209
|
-
yield*
|
|
4098
|
+
const completeUpload = import_effect26.Effect.fn("DeploymentApiService.completeUpload")(function* (deploymentId, uploadId, parts) {
|
|
4099
|
+
yield* import_effect26.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
4100
|
+
yield* import_effect26.Effect.annotateCurrentSpan("partsCount", parts.length);
|
|
3210
4101
|
const client = yield* getClient;
|
|
3211
|
-
yield*
|
|
4102
|
+
yield* import_effect26.Effect.tryPromise({
|
|
3212
4103
|
try: () => client.deployments.completeUpload(deploymentId, uploadId, parts),
|
|
3213
4104
|
catch: (error) => new UploadCompleteError({
|
|
3214
4105
|
message: `Failed to complete upload: ${error instanceof Error ? error.message : String(error)}`
|
|
3215
4106
|
})
|
|
3216
4107
|
});
|
|
3217
|
-
yield*
|
|
4108
|
+
yield* import_effect26.Effect.log("Upload completed successfully");
|
|
3218
4109
|
});
|
|
3219
|
-
const getDeploymentStatus =
|
|
4110
|
+
const getDeploymentStatus = import_effect26.Effect.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
|
|
3220
4111
|
const client = yield* getClient;
|
|
3221
|
-
const deployment = yield*
|
|
4112
|
+
const deployment = yield* import_effect26.Effect.tryPromise({
|
|
3222
4113
|
try: () => client.deployments.get(deploymentId),
|
|
3223
4114
|
catch: (error) => new DeploymentStatusError({
|
|
3224
4115
|
message: `Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -3226,9 +4117,9 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3226
4117
|
});
|
|
3227
4118
|
return deployment.status;
|
|
3228
4119
|
});
|
|
3229
|
-
const getLogs =
|
|
4120
|
+
const getLogs = import_effect26.Effect.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
|
|
3230
4121
|
const client = yield* getClient;
|
|
3231
|
-
const result = yield*
|
|
4122
|
+
const result = yield* import_effect26.Effect.tryPromise({
|
|
3232
4123
|
try: () => client.deployments.getLogs(deploymentId, options),
|
|
3233
4124
|
catch: (error) => new DeploymentLogsFetchError({
|
|
3234
4125
|
message: `Failed to get logs: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -3236,9 +4127,9 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3236
4127
|
});
|
|
3237
4128
|
return result;
|
|
3238
4129
|
});
|
|
3239
|
-
const getHostnames =
|
|
4130
|
+
const getHostnames = import_effect26.Effect.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
|
|
3240
4131
|
const client = yield* getClient;
|
|
3241
|
-
const result = yield*
|
|
4132
|
+
const result = yield* import_effect26.Effect.tryPromise({
|
|
3242
4133
|
try: () => client.deployments.getHostnames(deploymentId),
|
|
3243
4134
|
catch: (error) => new DeploymentHostnamesFetchError({
|
|
3244
4135
|
message: `Failed to get hostnames: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -3261,39 +4152,39 @@ var DeploymentApiService = class extends import_effect25.Effect.Service()("Deplo
|
|
|
3261
4152
|
};
|
|
3262
4153
|
|
|
3263
4154
|
// src/commands/platform/deploy/index.ts
|
|
3264
|
-
var
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
4155
|
+
var appOption7 = import_cli13.Options.text("app").pipe(
|
|
4156
|
+
import_cli13.Options.withAlias("a"),
|
|
4157
|
+
import_cli13.Options.withDescription("Application ID to deploy to (overrides the linked application)"),
|
|
4158
|
+
import_cli13.Options.optional
|
|
3268
4159
|
);
|
|
3269
|
-
var orgOption6 =
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
4160
|
+
var orgOption6 = import_cli13.Options.text("org").pipe(
|
|
4161
|
+
import_cli13.Options.withAlias("o"),
|
|
4162
|
+
import_cli13.Options.withDescription("Organization ID to use when automatically creating an application"),
|
|
4163
|
+
import_cli13.Options.optional
|
|
3273
4164
|
);
|
|
3274
|
-
var nameOption2 =
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
4165
|
+
var nameOption2 = import_cli13.Options.text("name").pipe(
|
|
4166
|
+
import_cli13.Options.withAlias("n"),
|
|
4167
|
+
import_cli13.Options.withDescription("Application name to use when automatically creating an application"),
|
|
4168
|
+
import_cli13.Options.optional
|
|
3278
4169
|
);
|
|
3279
|
-
var createAndLinkDeploymentApplication = (input) =>
|
|
4170
|
+
var createAndLinkDeploymentApplication = (input) => import_effect27.Effect.gen(function* () {
|
|
3280
4171
|
const projectLink = yield* ProjectLinkService;
|
|
3281
4172
|
const apiClient = yield* ApiClientService;
|
|
3282
4173
|
const { items: organizations } = yield* apiClient.request((client) => client.organizations.list());
|
|
3283
|
-
const availableOrganizations =
|
|
4174
|
+
const availableOrganizations = import_effect27.Option.match(input.org, {
|
|
3284
4175
|
onNone: () => organizations,
|
|
3285
4176
|
onSome: (organizationId) => organizations.filter((organization2) => organization2.id === organizationId)
|
|
3286
4177
|
});
|
|
3287
4178
|
if (availableOrganizations.length === 0) {
|
|
3288
4179
|
return yield* new NoOrganizationsFoundError({
|
|
3289
|
-
message:
|
|
4180
|
+
message: import_effect27.Option.match(input.org, {
|
|
3290
4181
|
onNone: () => 'No organization is available for this deployment. Create an organization, then run "gigadrive deploy" again.',
|
|
3291
4182
|
onSome: (organizationId) => `Organization "${organizationId}" was not found among your organizations.`
|
|
3292
4183
|
})
|
|
3293
4184
|
});
|
|
3294
4185
|
}
|
|
3295
|
-
const organization = availableOrganizations.length === 1 ? availableOrganizations[0] : yield*
|
|
3296
|
-
|
|
4186
|
+
const organization = availableOrganizations.length === 1 ? availableOrganizations[0] : yield* import_cli13.Prompt.run(
|
|
4187
|
+
import_cli13.Prompt.select({
|
|
3297
4188
|
message: "Select an organization for this application",
|
|
3298
4189
|
choices: availableOrganizations.map((candidate) => ({
|
|
3299
4190
|
title: candidate.name,
|
|
@@ -3302,7 +4193,7 @@ var createAndLinkDeploymentApplication = (input) => import_effect26.Effect.gen(f
|
|
|
3302
4193
|
})
|
|
3303
4194
|
);
|
|
3304
4195
|
const inferredName = path.basename(input.cwd) || "Application";
|
|
3305
|
-
const applicationName =
|
|
4196
|
+
const applicationName = import_effect27.Option.match(input.name, {
|
|
3306
4197
|
onNone: () => inferredName,
|
|
3307
4198
|
onSome: (name) => name
|
|
3308
4199
|
}).trim();
|
|
@@ -3316,37 +4207,37 @@ var createAndLinkDeploymentApplication = (input) => import_effect26.Effect.gen(f
|
|
|
3316
4207
|
applicationId: application.id,
|
|
3317
4208
|
organizationId: organization.id
|
|
3318
4209
|
});
|
|
3319
|
-
yield*
|
|
4210
|
+
yield* import_effect27.Console.log(`Created and linked application ${application.name} (${application.id}).`);
|
|
3320
4211
|
return application.id;
|
|
3321
4212
|
});
|
|
3322
|
-
var resolveLinkedDeploymentApplication = (input) =>
|
|
4213
|
+
var resolveLinkedDeploymentApplication = (input) => import_effect27.Effect.gen(function* () {
|
|
3323
4214
|
const projectLink = yield* ProjectLinkService;
|
|
3324
4215
|
const existingLink = yield* projectLink.load(input.cwd);
|
|
3325
|
-
return yield*
|
|
4216
|
+
return yield* import_effect27.Option.match(existingLink, {
|
|
3326
4217
|
onNone: () => createAndLinkDeploymentApplication(input),
|
|
3327
|
-
onSome: (link) =>
|
|
4218
|
+
onSome: (link) => import_effect27.Effect.succeed(link.applicationId)
|
|
3328
4219
|
});
|
|
3329
4220
|
});
|
|
3330
|
-
var resolveDeploymentApplication = (input) =>
|
|
4221
|
+
var resolveDeploymentApplication = (input) => import_effect27.Option.match(input.app, {
|
|
3331
4222
|
onNone: () => resolveLinkedDeploymentApplication(input),
|
|
3332
|
-
onSome:
|
|
4223
|
+
onSome: import_effect27.Effect.succeed
|
|
3333
4224
|
});
|
|
3334
|
-
var deployCommand =
|
|
4225
|
+
var deployCommand = import_cli13.Command.make(
|
|
3335
4226
|
"deploy",
|
|
3336
|
-
{ app:
|
|
3337
|
-
({ app, org, name }) =>
|
|
4227
|
+
{ app: appOption7, org: orgOption6, name: nameOption2 },
|
|
4228
|
+
({ app, org, name }) => import_effect27.Effect.gen(function* () {
|
|
3338
4229
|
const projectConfig = yield* ProjectConfigService;
|
|
3339
4230
|
const deploymentApi = yield* DeploymentApiService;
|
|
3340
4231
|
const archiveService = yield* ArchiveService;
|
|
3341
|
-
const pathService = yield*
|
|
4232
|
+
const pathService = yield* import_platform10.Path.Path;
|
|
3342
4233
|
const cwd = process.cwd();
|
|
3343
|
-
yield*
|
|
4234
|
+
yield* import_effect27.Effect.log("Starting deploy command");
|
|
3344
4235
|
const { config } = yield* projectConfig.resolve(cwd);
|
|
3345
4236
|
const applicationId = yield* resolveDeploymentApplication({ app, org, name, cwd });
|
|
3346
|
-
yield*
|
|
4237
|
+
yield* import_effect27.Console.log("Creating deployment...");
|
|
3347
4238
|
const deploymentId = yield* deploymentApi.createDeployment(applicationId);
|
|
3348
|
-
yield*
|
|
3349
|
-
yield*
|
|
4239
|
+
yield* import_effect27.Console.log(`Deployment ID: ${deploymentId}`);
|
|
4240
|
+
yield* import_effect27.Console.log("Creating archive...");
|
|
3350
4241
|
const archivePath = pathService.join(os4.tmpdir(), `project-${Date.now()}.zip`);
|
|
3351
4242
|
const archive = yield* archiveService.createZipArchive(config.userArchive?.rootOverwrite || cwd, archivePath, {
|
|
3352
4243
|
whitelist: config.userArchive?.fileWhitelist,
|
|
@@ -3356,68 +4247,68 @@ var deployCommand = import_cli12.Command.make(
|
|
|
3356
4247
|
...config.sidecars ?? []
|
|
3357
4248
|
].some((container) => container.source.type === "dockerfile")
|
|
3358
4249
|
});
|
|
3359
|
-
yield*
|
|
3360
|
-
yield*
|
|
4250
|
+
yield* import_effect27.Console.log(`Archive created (${(0, import_commons.formatFileSize)(archive.size)})`);
|
|
4251
|
+
yield* import_effect27.Console.log("Uploading archive...");
|
|
3361
4252
|
yield* uploadArchive(deploymentId, archivePath, archive.size);
|
|
3362
|
-
yield*
|
|
3363
|
-
yield*
|
|
4253
|
+
yield* import_effect27.Console.log("Upload complete.");
|
|
4254
|
+
yield* import_effect27.Console.log("The deployment pipeline is now being provisioned. This may take a few seconds.");
|
|
3364
4255
|
yield* pollDeployment(deploymentId);
|
|
3365
4256
|
}).pipe(
|
|
3366
|
-
|
|
3367
|
-
QuitException: () =>
|
|
3368
|
-
NotAuthenticatedError: (err) =>
|
|
3369
|
-
|
|
4257
|
+
import_effect27.Effect.catchTags({
|
|
4258
|
+
QuitException: () => import_effect27.Console.log("Cancelled."),
|
|
4259
|
+
NotAuthenticatedError: (err) => import_effect27.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
4260
|
+
import_effect27.Effect.andThen(import_effect27.Effect.fail(err))
|
|
3370
4261
|
),
|
|
3371
|
-
ApiRequestError: (err) =>
|
|
3372
|
-
NoOrganizationsFoundError: (err) =>
|
|
3373
|
-
ProjectLinkReadError: (err) =>
|
|
3374
|
-
ProjectLinkWriteError: (err) =>
|
|
3375
|
-
ConfigNotFoundError: (err) =>
|
|
3376
|
-
ConfigParseError: (err) =>
|
|
3377
|
-
ConfigValidationError: (err) =>
|
|
4262
|
+
ApiRequestError: (err) => import_effect27.Console.error(`Application setup failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4263
|
+
NoOrganizationsFoundError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4264
|
+
ProjectLinkReadError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4265
|
+
ProjectLinkWriteError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4266
|
+
ConfigNotFoundError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4267
|
+
ConfigParseError: (err) => import_effect27.Console.error(`Config parse error: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4268
|
+
ConfigValidationError: (err) => import_effect27.Effect.gen(function* () {
|
|
3378
4269
|
for (const e of err.errors) {
|
|
3379
|
-
yield*
|
|
4270
|
+
yield* import_effect27.Console.error(e);
|
|
3380
4271
|
}
|
|
3381
|
-
yield*
|
|
3382
|
-
}).pipe(
|
|
3383
|
-
DeploymentCreateError: (err) =>
|
|
3384
|
-
ArchiveCreateError: (err) =>
|
|
3385
|
-
UploadStartError: (err) =>
|
|
3386
|
-
UploadPartError: (err) =>
|
|
3387
|
-
UploadCompleteError: (err) =>
|
|
3388
|
-
PresignedUrlError: (err) =>
|
|
3389
|
-
DeploymentAuthError: (err) =>
|
|
3390
|
-
DeploymentFailedError: (err) =>
|
|
4272
|
+
yield* import_effect27.Console.error(err.message);
|
|
4273
|
+
}).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4274
|
+
DeploymentCreateError: (err) => import_effect27.Console.error(`Deployment creation failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4275
|
+
ArchiveCreateError: (err) => import_effect27.Console.error(`Archive creation failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4276
|
+
UploadStartError: (err) => import_effect27.Console.error(`Upload failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4277
|
+
UploadPartError: (err) => import_effect27.Console.error(`Upload failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4278
|
+
UploadCompleteError: (err) => import_effect27.Console.error(`Upload failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4279
|
+
PresignedUrlError: (err) => import_effect27.Console.error(`Upload failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4280
|
+
DeploymentAuthError: (err) => import_effect27.Console.error(`Authentication failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
4281
|
+
DeploymentFailedError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err)))
|
|
3391
4282
|
})
|
|
3392
4283
|
)
|
|
3393
4284
|
);
|
|
3394
|
-
var uploadArchive = (deploymentId, archivePath, fileSize) =>
|
|
4285
|
+
var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect27.Effect.gen(function* () {
|
|
3395
4286
|
const deploymentApi = yield* DeploymentApiService;
|
|
3396
|
-
const fs = yield*
|
|
4287
|
+
const fs = yield* import_platform10.FileSystem.FileSystem;
|
|
3397
4288
|
const uploadId = yield* deploymentApi.startMultipartUpload(deploymentId);
|
|
3398
4289
|
const FILE_CHUNK_SIZE = 10 * 1024 * 1024;
|
|
3399
4290
|
const numChunks = Math.ceil(fileSize / FILE_CHUNK_SIZE);
|
|
3400
|
-
yield*
|
|
3401
|
-
const parts = yield*
|
|
4291
|
+
yield* import_effect27.Effect.log("Starting multipart upload", { uploadId, numChunks, fileSize });
|
|
4292
|
+
const parts = yield* import_effect27.Effect.all(
|
|
3402
4293
|
Array.from({ length: numChunks }, (_, i) => {
|
|
3403
4294
|
const partNumber = i + 1;
|
|
3404
4295
|
const start = i * FILE_CHUNK_SIZE;
|
|
3405
4296
|
const bytesToRead = partNumber < numChunks ? FILE_CHUNK_SIZE : fileSize - start;
|
|
3406
|
-
return
|
|
4297
|
+
return import_effect27.Effect.gen(function* () {
|
|
3407
4298
|
const presignedUrl = yield* deploymentApi.getPresignedUrl(deploymentId, uploadId, partNumber);
|
|
3408
|
-
const chunkData = yield*
|
|
3409
|
-
|
|
4299
|
+
const chunkData = yield* import_effect27.Stream.runCollect(fs.stream(archivePath, { offset: start, bytesToRead })).pipe(
|
|
4300
|
+
import_effect27.Effect.map((chunks) => {
|
|
3410
4301
|
const arrays = Array.from(chunks);
|
|
3411
4302
|
return Buffer.concat(arrays);
|
|
3412
4303
|
}),
|
|
3413
|
-
|
|
4304
|
+
import_effect27.Effect.mapError(
|
|
3414
4305
|
(error) => new UploadPartError({
|
|
3415
4306
|
message: `Failed to read chunk ${partNumber}: ${String(error)}`,
|
|
3416
4307
|
partNumber
|
|
3417
4308
|
})
|
|
3418
4309
|
)
|
|
3419
4310
|
);
|
|
3420
|
-
yield*
|
|
4311
|
+
yield* import_effect27.Effect.log(`Uploading part ${partNumber}/${numChunks}`, { size: chunkData.length });
|
|
3421
4312
|
return yield* deploymentApi.uploadPart(presignedUrl, chunkData, partNumber);
|
|
3422
4313
|
});
|
|
3423
4314
|
}),
|
|
@@ -3425,20 +4316,20 @@ var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect26.Eff
|
|
|
3425
4316
|
);
|
|
3426
4317
|
yield* deploymentApi.completeUpload(deploymentId, uploadId, parts);
|
|
3427
4318
|
});
|
|
3428
|
-
var pollDeployment = (deploymentId) =>
|
|
4319
|
+
var pollDeployment = (deploymentId) => import_effect27.Effect.gen(function* () {
|
|
3429
4320
|
const deploymentApi = yield* DeploymentApiService;
|
|
3430
4321
|
let lastStatus = "PENDING";
|
|
3431
4322
|
let logOffset = 0;
|
|
3432
|
-
yield*
|
|
3433
|
-
yield*
|
|
3434
|
-
|
|
3435
|
-
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(
|
|
4323
|
+
yield* import_effect27.Console.log("Status: Pending");
|
|
4324
|
+
yield* import_effect27.Effect.repeat(
|
|
4325
|
+
import_effect27.Effect.gen(function* () {
|
|
4326
|
+
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(import_effect27.Effect.catchTag("DeploymentStatusError", () => import_effect27.Effect.succeed(lastStatus)));
|
|
3436
4327
|
if (newStatus !== lastStatus) {
|
|
3437
4328
|
lastStatus = newStatus;
|
|
3438
4329
|
const label = newStatus.charAt(0) + newStatus.slice(1).toLowerCase();
|
|
3439
|
-
yield*
|
|
4330
|
+
yield* import_effect27.Console.log(`Status: ${label}`);
|
|
3440
4331
|
}
|
|
3441
|
-
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(
|
|
4332
|
+
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(import_effect27.Effect.catchTag("DeploymentLogsFetchError", () => import_effect27.Effect.succeed(null)));
|
|
3442
4333
|
if (logsPage) {
|
|
3443
4334
|
for (const logEntry of logsPage.items) {
|
|
3444
4335
|
logOffset++;
|
|
@@ -3446,86 +4337,86 @@ var pollDeployment = (deploymentId) => import_effect26.Effect.gen(function* () {
|
|
|
3446
4337
|
}
|
|
3447
4338
|
}
|
|
3448
4339
|
if (newStatus === "ACTIVE") {
|
|
3449
|
-
const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(
|
|
4340
|
+
const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(import_effect27.Effect.catchTag("DeploymentHostnamesFetchError", () => import_effect27.Effect.succeed([])));
|
|
3450
4341
|
const active = hostnames.find((h) => h.active) ?? hostnames.at(0);
|
|
3451
4342
|
if (active) {
|
|
3452
|
-
yield*
|
|
4343
|
+
yield* import_effect27.Console.log(`Deployed to https://${active.hostname}`);
|
|
3453
4344
|
} else {
|
|
3454
|
-
yield*
|
|
4345
|
+
yield* import_effect27.Console.log("Deployment is live.");
|
|
3455
4346
|
}
|
|
3456
|
-
return yield*
|
|
4347
|
+
return yield* import_effect27.Effect.fail("done");
|
|
3457
4348
|
}
|
|
3458
4349
|
if (newStatus === "FAILED") {
|
|
3459
|
-
return yield*
|
|
4350
|
+
return yield* import_effect27.Effect.fail(
|
|
3460
4351
|
new DeploymentFailedError({
|
|
3461
4352
|
message: "The deployment failed. Please check the logs for more information."
|
|
3462
4353
|
})
|
|
3463
4354
|
);
|
|
3464
4355
|
}
|
|
3465
4356
|
}),
|
|
3466
|
-
|
|
4357
|
+
import_effect27.Schedule.addDelay(import_effect27.Schedule.forever, () => import_effect27.Duration.seconds(1))
|
|
3467
4358
|
).pipe(
|
|
3468
|
-
|
|
3469
|
-
if (err === "done") return
|
|
3470
|
-
return
|
|
4359
|
+
import_effect27.Effect.catchAll((err) => {
|
|
4360
|
+
if (err === "done") return import_effect27.Effect.void;
|
|
4361
|
+
return import_effect27.Effect.fail(err);
|
|
3471
4362
|
})
|
|
3472
4363
|
);
|
|
3473
4364
|
});
|
|
3474
4365
|
var printLog = (logEntry) => {
|
|
3475
4366
|
switch (logEntry.type) {
|
|
3476
4367
|
case "ERROR":
|
|
3477
|
-
return
|
|
4368
|
+
return import_effect27.Console.error(logEntry.message);
|
|
3478
4369
|
case "WARN":
|
|
3479
|
-
return
|
|
4370
|
+
return import_effect27.Console.warn(logEntry.message);
|
|
3480
4371
|
default:
|
|
3481
|
-
return
|
|
4372
|
+
return import_effect27.Console.log(logEntry.message);
|
|
3482
4373
|
}
|
|
3483
4374
|
};
|
|
3484
4375
|
|
|
3485
4376
|
// src/commands/platform/index.ts
|
|
3486
|
-
var platformBase =
|
|
3487
|
-
var platformCommand = platformBase.pipe(
|
|
4377
|
+
var platformBase = import_cli14.Command.make("platform", {}, () => import_effect28.Effect.void);
|
|
4378
|
+
var platformCommand = platformBase.pipe(import_cli14.Command.withSubcommands([deployCommand]));
|
|
3488
4379
|
|
|
3489
4380
|
// src/commands/setup/index.ts
|
|
3490
|
-
var
|
|
3491
|
-
var
|
|
3492
|
-
var fileArg2 =
|
|
3493
|
-
|
|
3494
|
-
|
|
4381
|
+
var import_cli15 = require("@effect/cli");
|
|
4382
|
+
var import_effect29 = require("effect");
|
|
4383
|
+
var fileArg2 = import_cli15.Args.text({ name: "file" }).pipe(
|
|
4384
|
+
import_cli15.Args.withDescription("Output file to write (default: .env.local)"),
|
|
4385
|
+
import_cli15.Args.optional
|
|
3495
4386
|
);
|
|
3496
|
-
var
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
4387
|
+
var appOption8 = import_cli15.Options.text("app").pipe(
|
|
4388
|
+
import_cli15.Options.withAlias("a"),
|
|
4389
|
+
import_cli15.Options.withDescription("Application ID to set up (skips the interactive picker)"),
|
|
4390
|
+
import_cli15.Options.optional
|
|
3500
4391
|
);
|
|
3501
|
-
var orgOption7 =
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
4392
|
+
var orgOption7 = import_cli15.Options.text("org").pipe(
|
|
4393
|
+
import_cli15.Options.withAlias("o"),
|
|
4394
|
+
import_cli15.Options.withDescription("Only list applications belonging to this organization ID when picking"),
|
|
4395
|
+
import_cli15.Options.optional
|
|
3505
4396
|
);
|
|
3506
|
-
var environmentOption2 =
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
4397
|
+
var environmentOption2 = import_cli15.Options.text("environment").pipe(
|
|
4398
|
+
import_cli15.Options.withAlias("e"),
|
|
4399
|
+
import_cli15.Options.withDescription("Environment slug to resolve overrides for (e.g. preview)"),
|
|
4400
|
+
import_cli15.Options.optional
|
|
3510
4401
|
);
|
|
3511
|
-
var yesOption3 =
|
|
3512
|
-
|
|
3513
|
-
|
|
4402
|
+
var yesOption3 = import_cli15.Options.boolean("yes").pipe(
|
|
4403
|
+
import_cli15.Options.withAlias("y"),
|
|
4404
|
+
import_cli15.Options.withDescription("Overwrite an existing file without confirmation")
|
|
3514
4405
|
);
|
|
3515
|
-
var rotateOption2 =
|
|
3516
|
-
|
|
4406
|
+
var rotateOption2 = import_cli15.Options.boolean("rotate").pipe(
|
|
4407
|
+
import_cli15.Options.withDescription("Force a fresh API key, revoking the previous one")
|
|
3517
4408
|
);
|
|
3518
|
-
var setupCommand =
|
|
4409
|
+
var setupCommand = import_cli15.Command.make(
|
|
3519
4410
|
"setup",
|
|
3520
4411
|
{
|
|
3521
4412
|
file: fileArg2,
|
|
3522
|
-
app:
|
|
4413
|
+
app: appOption8,
|
|
3523
4414
|
org: orgOption7,
|
|
3524
4415
|
environment: environmentOption2,
|
|
3525
4416
|
yes: yesOption3,
|
|
3526
4417
|
rotate: rotateOption2
|
|
3527
4418
|
},
|
|
3528
|
-
({ file, app, org, environment, yes, rotate }) =>
|
|
4419
|
+
({ file, app, org, environment, yes, rotate }) => import_effect29.Effect.gen(function* () {
|
|
3529
4420
|
const apiClient = yield* ApiClientService;
|
|
3530
4421
|
const projectLink = yield* ProjectLinkService;
|
|
3531
4422
|
const envFile = yield* EnvFileService;
|
|
@@ -3533,29 +4424,29 @@ var setupCommand = import_cli14.Command.make(
|
|
|
3533
4424
|
const cwd = process.cwd();
|
|
3534
4425
|
const existingLink = yield* projectLink.load(cwd);
|
|
3535
4426
|
let applicationId;
|
|
3536
|
-
if (
|
|
4427
|
+
if (import_effect29.Option.isSome(existingLink)) {
|
|
3537
4428
|
applicationId = existingLink.value.applicationId;
|
|
3538
|
-
if (
|
|
3539
|
-
yield*
|
|
4429
|
+
if (import_effect29.Option.isSome(app) || import_effect29.Option.isSome(org)) {
|
|
4430
|
+
yield* import_effect29.Console.log(
|
|
3540
4431
|
`Note: this directory is already linked to ${applicationId}; ignoring --app/--org. Run "gigadrive unlink" first to target a different application.`
|
|
3541
4432
|
);
|
|
3542
4433
|
}
|
|
3543
4434
|
} else {
|
|
3544
|
-
const organizationId =
|
|
4435
|
+
const organizationId = import_effect29.Option.getOrUndefined(org);
|
|
3545
4436
|
const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
|
|
3546
4437
|
if (apps.length === 0) {
|
|
3547
|
-
return yield*
|
|
4438
|
+
return yield* import_effect29.Effect.fail(
|
|
3548
4439
|
new NoApplicationsFoundError({
|
|
3549
4440
|
message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive setup" again.'
|
|
3550
4441
|
})
|
|
3551
4442
|
);
|
|
3552
4443
|
}
|
|
3553
|
-
const explicitAppId =
|
|
4444
|
+
const explicitAppId = import_effect29.Option.getOrUndefined(app);
|
|
3554
4445
|
let chosen;
|
|
3555
4446
|
if (explicitAppId !== void 0) {
|
|
3556
4447
|
const match = apps.find((a) => a.id === explicitAppId);
|
|
3557
4448
|
if (match === void 0) {
|
|
3558
|
-
return yield*
|
|
4449
|
+
return yield* import_effect29.Effect.fail(
|
|
3559
4450
|
new ApplicationNotFoundError({
|
|
3560
4451
|
message: `Application "${explicitAppId}" was not found among your applications.`
|
|
3561
4452
|
})
|
|
@@ -3565,8 +4456,8 @@ var setupCommand = import_cli14.Command.make(
|
|
|
3565
4456
|
} else if (apps.length === 1) {
|
|
3566
4457
|
chosen = apps[0];
|
|
3567
4458
|
} else {
|
|
3568
|
-
chosen = yield*
|
|
3569
|
-
|
|
4459
|
+
chosen = yield* import_cli15.Prompt.run(
|
|
4460
|
+
import_cli15.Prompt.select({
|
|
3570
4461
|
message: "Select an application to set up",
|
|
3571
4462
|
choices: apps.map((a) => ({ title: `${a.name} (${a.organization.name})`, value: a }))
|
|
3572
4463
|
})
|
|
@@ -3574,83 +4465,83 @@ var setupCommand = import_cli14.Command.make(
|
|
|
3574
4465
|
}
|
|
3575
4466
|
applicationId = chosen.id;
|
|
3576
4467
|
yield* projectLink.save(cwd, { applicationId, organizationId: chosen.organization.id });
|
|
3577
|
-
yield*
|
|
4468
|
+
yield* import_effect29.Console.log(`Linked this directory to application ${applicationId}.`);
|
|
3578
4469
|
}
|
|
3579
|
-
const target =
|
|
3580
|
-
const environmentSlug =
|
|
4470
|
+
const target = import_effect29.Option.getOrElse(file, () => ".env.local");
|
|
4471
|
+
const environmentSlug = import_effect29.Option.getOrUndefined(environment);
|
|
3581
4472
|
const { items, omittedSensitive } = yield* apiClient.request(
|
|
3582
4473
|
(client) => client.applications.envVars.pull(applicationId, environmentSlug ? { environment: environmentSlug } : void 0)
|
|
3583
4474
|
);
|
|
3584
4475
|
const existing = yield* envFile.read(target);
|
|
3585
|
-
if (
|
|
3586
|
-
const overwrite = yield*
|
|
3587
|
-
|
|
4476
|
+
if (import_effect29.Option.isSome(existing) && !yes) {
|
|
4477
|
+
const overwrite = yield* import_cli15.Prompt.run(
|
|
4478
|
+
import_cli15.Prompt.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
|
|
3588
4479
|
);
|
|
3589
4480
|
if (!overwrite) {
|
|
3590
|
-
return yield*
|
|
4481
|
+
return yield* import_effect29.Console.log("Cancelled.");
|
|
3591
4482
|
}
|
|
3592
4483
|
}
|
|
3593
4484
|
const credentialEntries2 = yield* localCredentials.provision({
|
|
3594
4485
|
applicationId,
|
|
3595
4486
|
rotate,
|
|
3596
|
-
existingContent:
|
|
4487
|
+
existingContent: import_effect29.Option.getOrUndefined(existing)
|
|
3597
4488
|
});
|
|
3598
4489
|
const entries = [...items.map((v) => ({ key: v.key, value: v.value })), ...credentialEntries2];
|
|
3599
4490
|
yield* envFile.write(target, entries);
|
|
3600
4491
|
const gitignored = yield* envFile.ensureGitignored(cwd, target);
|
|
3601
|
-
yield*
|
|
3602
|
-
yield*
|
|
4492
|
+
yield* import_effect29.Console.log("\nLocal dev environment ready.");
|
|
4493
|
+
yield* import_effect29.Console.log(` \u2022 Wrote ${items.length} variable(s) and API credentials to ${target}.`);
|
|
3603
4494
|
if (omittedSensitive > 0) {
|
|
3604
|
-
yield*
|
|
4495
|
+
yield* import_effect29.Console.log(
|
|
3605
4496
|
` \u2022 Skipped ${omittedSensitive} sensitive variable(s) (only production/preview hold secrets).`
|
|
3606
4497
|
);
|
|
3607
4498
|
}
|
|
3608
4499
|
if (gitignored) {
|
|
3609
|
-
yield*
|
|
4500
|
+
yield* import_effect29.Console.log(` \u2022 Added ${target} to .gitignore.`);
|
|
3610
4501
|
}
|
|
3611
|
-
yield*
|
|
4502
|
+
yield* import_effect29.Console.log(" \u2022 Your app can now call the Gigadrive API via the SDK (GIGADRIVE_CLIENT_ID/SECRET).");
|
|
3612
4503
|
}).pipe(
|
|
3613
|
-
|
|
4504
|
+
import_effect29.Effect.catchTags({
|
|
3614
4505
|
// Ctrl+C during a prompt is a deliberate cancel — exit 0.
|
|
3615
|
-
QuitException: () =>
|
|
3616
|
-
NotAuthenticatedError: (err) =>
|
|
3617
|
-
|
|
4506
|
+
QuitException: () => import_effect29.Console.log("Cancelled."),
|
|
4507
|
+
NotAuthenticatedError: (err) => import_effect29.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
4508
|
+
import_effect29.Effect.andThen(import_effect29.Effect.fail(err))
|
|
3618
4509
|
),
|
|
3619
|
-
ApiRequestError: (err) =>
|
|
3620
|
-
NoApplicationsFoundError: (err) =>
|
|
3621
|
-
ApplicationNotFoundError: (err) =>
|
|
3622
|
-
ProjectLinkReadError: (err) =>
|
|
3623
|
-
ProjectLinkWriteError: (err) =>
|
|
3624
|
-
EnvFileReadError: (err) =>
|
|
3625
|
-
EnvFileWriteError: (err) =>
|
|
3626
|
-
DevCredentialsStoreReadError: (err) =>
|
|
3627
|
-
DevCredentialsStoreWriteError: (err) =>
|
|
4510
|
+
ApiRequestError: (err) => import_effect29.Console.error(`Setup failed: ${err.message}`).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4511
|
+
NoApplicationsFoundError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4512
|
+
ApplicationNotFoundError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4513
|
+
ProjectLinkReadError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4514
|
+
ProjectLinkWriteError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4515
|
+
EnvFileReadError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4516
|
+
EnvFileWriteError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4517
|
+
DevCredentialsStoreReadError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err))),
|
|
4518
|
+
DevCredentialsStoreWriteError: (err) => import_effect29.Console.error(err.message).pipe(import_effect29.Effect.andThen(import_effect29.Effect.fail(err)))
|
|
3628
4519
|
})
|
|
3629
4520
|
)
|
|
3630
4521
|
);
|
|
3631
4522
|
|
|
3632
4523
|
// src/commands/whoami/index.ts
|
|
3633
|
-
var
|
|
3634
|
-
var
|
|
3635
|
-
var whoamiCommand =
|
|
4524
|
+
var import_cli16 = require("@effect/cli");
|
|
4525
|
+
var import_effect30 = require("effect");
|
|
4526
|
+
var whoamiCommand = import_cli16.Command.make(
|
|
3636
4527
|
"whoami",
|
|
3637
4528
|
{},
|
|
3638
|
-
() =>
|
|
4529
|
+
() => import_effect30.Effect.gen(function* () {
|
|
3639
4530
|
const auth = yield* AuthService;
|
|
3640
4531
|
const info = yield* auth.getUserInfo;
|
|
3641
|
-
yield*
|
|
4532
|
+
yield* import_effect30.Console.log(JSON.stringify(info, null, 2));
|
|
3642
4533
|
}).pipe(
|
|
3643
|
-
|
|
3644
|
-
NotAuthenticatedError: () =>
|
|
3645
|
-
UserInfoFetchError: (err) =>
|
|
3646
|
-
OAuthDiscoveryError: (err) =>
|
|
4534
|
+
import_effect30.Effect.catchTags({
|
|
4535
|
+
NotAuthenticatedError: () => import_effect30.Console.log('You are not logged in. Run "gigadrive login" to authenticate.'),
|
|
4536
|
+
UserInfoFetchError: (err) => import_effect30.Console.error(`Failed to retrieve user info: ${err.message}`),
|
|
4537
|
+
OAuthDiscoveryError: (err) => import_effect30.Console.error(`Failed to retrieve user info: ${err.message}`)
|
|
3647
4538
|
})
|
|
3648
4539
|
)
|
|
3649
4540
|
);
|
|
3650
4541
|
|
|
3651
4542
|
// src/index.ts
|
|
3652
|
-
var gigadrive =
|
|
3653
|
-
|
|
4543
|
+
var gigadrive = import_cli17.Command.make("gigadrive", {}, () => import_effect31.Effect.void).pipe(
|
|
4544
|
+
import_cli17.Command.withSubcommands([
|
|
3654
4545
|
loginCommand,
|
|
3655
4546
|
logoutCommand,
|
|
3656
4547
|
whoamiCommand,
|
|
@@ -3661,6 +4552,8 @@ var gigadrive = import_cli16.Command.make("gigadrive", {}, () => import_effect30
|
|
|
3661
4552
|
deploymentsCommand,
|
|
3662
4553
|
domainsCommand,
|
|
3663
4554
|
aiCommand,
|
|
4555
|
+
microvmsCommand,
|
|
4556
|
+
vmCommand,
|
|
3664
4557
|
buildCommand,
|
|
3665
4558
|
debugCommand,
|
|
3666
4559
|
deployCommand,
|
|
@@ -3668,11 +4561,11 @@ var gigadrive = import_cli16.Command.make("gigadrive", {}, () => import_effect30
|
|
|
3668
4561
|
setupCommand
|
|
3669
4562
|
])
|
|
3670
4563
|
);
|
|
3671
|
-
var cli =
|
|
4564
|
+
var cli = import_cli17.Command.run(gigadrive, {
|
|
3672
4565
|
name: "Gigadrive CLI",
|
|
3673
4566
|
version: package_default.version
|
|
3674
4567
|
});
|
|
3675
|
-
var BaseServices =
|
|
4568
|
+
var BaseServices = import_effect31.Layer.mergeAll(
|
|
3676
4569
|
OAuthConfigService.Default,
|
|
3677
4570
|
AuthStorageService.Default,
|
|
3678
4571
|
PackageManagerService.Default,
|
|
@@ -3682,13 +4575,13 @@ var BaseServices = import_effect30.Layer.mergeAll(
|
|
|
3682
4575
|
ProjectLinkService.Default,
|
|
3683
4576
|
EnvFileService.Default,
|
|
3684
4577
|
DevCredentialsStore.Default
|
|
3685
|
-
).pipe(
|
|
3686
|
-
var ApiClientLive =
|
|
3687
|
-
var DeploymentApiLive =
|
|
3688
|
-
var LocalCredentialsLive =
|
|
3689
|
-
var ServicesLive =
|
|
3690
|
-
var AppLive =
|
|
3691
|
-
|
|
3692
|
-
);
|
|
3693
|
-
import_platform_node.NodeRuntime.runMain(
|
|
4578
|
+
).pipe(import_effect31.Layer.provideMerge(AuthService.Default));
|
|
4579
|
+
var ApiClientLive = import_effect31.Layer.provide(ApiClientService.Default, BaseServices);
|
|
4580
|
+
var DeploymentApiLive = import_effect31.Layer.provide(DeploymentApiService.Default, BaseServices);
|
|
4581
|
+
var LocalCredentialsLive = import_effect31.Layer.provide(LocalCredentialsService.Default, BaseServices);
|
|
4582
|
+
var ServicesLive = import_effect31.Layer.mergeAll(BaseServices, ApiClientLive, DeploymentApiLive, LocalCredentialsLive);
|
|
4583
|
+
var AppLive = import_effect31.Layer.mergeAll(ServicesLive, import_effect31.Logger.minimumLogLevel(import_effect31.LogLevel.Info)).pipe(
|
|
4584
|
+
import_effect31.Layer.provideMerge(import_platform_node.NodeContext.layer)
|
|
4585
|
+
);
|
|
4586
|
+
import_platform_node.NodeRuntime.runMain(import_effect31.Effect.provide(cli(process.argv), AppLive));
|
|
3694
4587
|
//# sourceMappingURL=index.cjs.map
|