gigadrive 2.14.0 → 2.16.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/dist/index.cjs +208 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +208 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { Effect as Effect29, Layer, LogLevel, Logger } from "effect";
|
|
|
9
9
|
// package.json
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "gigadrive",
|
|
12
|
-
version: "2.
|
|
12
|
+
version: "2.16.0",
|
|
13
13
|
repository: {
|
|
14
14
|
type: "git",
|
|
15
15
|
url: "https://github.com/Gigadrive/sdk.git",
|
|
@@ -3063,6 +3063,7 @@ var describeMicroVm = (vm, now = Date.now()) => {
|
|
|
3063
3063
|
`Size: ${vm.vcpus} vCPU, ${formatMemory(vm.memoryMb)} memory, ${formatMemory(vm.diskMb)} disk`,
|
|
3064
3064
|
`Region: ${vm.region}`,
|
|
3065
3065
|
`Network: ${vm.network.egress === "deny" ? "outbound traffic blocked" : vm.network.allow && vm.network.allow.length > 0 ? `only ${vm.network.allow.join(", ")}` : "internet access"}`,
|
|
3066
|
+
...(vm.network.inject ?? []).map((rule) => `Injects: ${rule.headers.join(", ")} for ${rule.domain}`),
|
|
3066
3067
|
`Previews: ${vm.network.previews === "private" ? "private (preview token required)" : "public"}`,
|
|
3067
3068
|
`Application: ${vm.applicationId}`,
|
|
3068
3069
|
`Created: ${vm.createdAt}`
|
|
@@ -3098,6 +3099,17 @@ var formatWebhookTable = (webhooks) => formatTable([
|
|
|
3098
3099
|
webhook.id
|
|
3099
3100
|
])
|
|
3100
3101
|
]);
|
|
3102
|
+
var formatVolumeTable = (volumes) => formatTable([
|
|
3103
|
+
["NAME", "SIZE", "STORED", "STATUS", "LAST SAVED", "ID"],
|
|
3104
|
+
...volumes.map((volume) => [
|
|
3105
|
+
volume.name,
|
|
3106
|
+
`${String(volume.sizeMb)} MiB`,
|
|
3107
|
+
volume.storedBytes === null ? "-" : formatBytes(volume.storedBytes),
|
|
3108
|
+
volume.attachedMicrovmId ? `${volume.status} (${volume.attachedMicrovmId})` : volume.status,
|
|
3109
|
+
volume.lastSaveError ? `failed: ${volume.lastSaveError}` : volume.lastSavedAt ?? "never",
|
|
3110
|
+
volume.id
|
|
3111
|
+
])
|
|
3112
|
+
]);
|
|
3101
3113
|
var formatDeliveryTable = (deliveries) => formatTable([
|
|
3102
3114
|
["CREATED", "EVENT", "STATUS", "ATTEMPTS", "RESPONSE", "MICROVM"],
|
|
3103
3115
|
...deliveries.map((delivery) => [
|
|
@@ -3343,6 +3355,45 @@ var withClient = (run) => Effect22.gen(function* () {
|
|
|
3343
3355
|
return yield* Effect22.tryPromise({ try: () => run(client), catch: toApiRequestError });
|
|
3344
3356
|
});
|
|
3345
3357
|
var signalOnInterrupt = (signal) => (command, exit) => Exit.isInterrupted(exit) ? Effect22.tryPromise(() => command.kill(signal)).pipe(Effect22.timeout("2 seconds"), Effect22.ignore) : Effect22.void;
|
|
3358
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3359
|
+
var parseVolumeFlags = (values) => Effect22.gen(function* () {
|
|
3360
|
+
if (values.length > 4) {
|
|
3361
|
+
return yield* new InvalidMicroVmOptionsError({ message: "--volume takes at most 4 volumes." });
|
|
3362
|
+
}
|
|
3363
|
+
const volumes = [];
|
|
3364
|
+
for (const value of values) {
|
|
3365
|
+
const separator = value.indexOf(":");
|
|
3366
|
+
const volumeId = separator > 0 ? value.slice(0, separator) : "";
|
|
3367
|
+
const mountPath = separator > 0 ? value.slice(separator + 1) : "";
|
|
3368
|
+
if (volumeId === "" || !mountPath.startsWith("/")) {
|
|
3369
|
+
return yield* new InvalidMicroVmOptionsError({
|
|
3370
|
+
message: `--volume must be VOLUME:PATH with an absolute path, such as cache:/cache (got ${value}).`
|
|
3371
|
+
});
|
|
3372
|
+
}
|
|
3373
|
+
volumes.push({ volumeId, mountPath });
|
|
3374
|
+
}
|
|
3375
|
+
return volumes;
|
|
3376
|
+
});
|
|
3377
|
+
var parseInjectFlags = (values) => Effect22.gen(function* () {
|
|
3378
|
+
const rules = /* @__PURE__ */ new Map();
|
|
3379
|
+
for (const value of values) {
|
|
3380
|
+
const colon = value.indexOf(":");
|
|
3381
|
+
const equals = value.indexOf("=", colon + 1);
|
|
3382
|
+
const domain = colon > 0 ? value.slice(0, colon).trim().toLowerCase() : "";
|
|
3383
|
+
const name = colon > 0 && equals > colon ? value.slice(colon + 1, equals).trim() : "";
|
|
3384
|
+
if (domain === "" || name === "" || equals === value.length - 1) {
|
|
3385
|
+
return yield* new InvalidMicroVmOptionsError({
|
|
3386
|
+
// The entry is not echoed: it may hold the credential.
|
|
3387
|
+
message: '--inject must be DOMAIN:HEADER=VALUE, such as "api.openai.com:Authorization=Bearer $OPENAI_API_KEY".'
|
|
3388
|
+
});
|
|
3389
|
+
}
|
|
3390
|
+
rules.set(domain, { ...rules.get(domain), [name]: value.slice(equals + 1) });
|
|
3391
|
+
}
|
|
3392
|
+
if (rules.size > 8) {
|
|
3393
|
+
return yield* new InvalidMicroVmOptionsError({ message: "--inject takes at most 8 domains." });
|
|
3394
|
+
}
|
|
3395
|
+
return [...rules].map(([domain, headers]) => ({ domain, headers }));
|
|
3396
|
+
});
|
|
3346
3397
|
var checkEgressFlags = (denyEgress, allowEgress) => Effect22.gen(function* () {
|
|
3347
3398
|
if (denyEgress && allowEgress.length > 0) {
|
|
3348
3399
|
return yield* new InvalidMicroVmOptionsError({
|
|
@@ -3373,6 +3424,14 @@ var createInput = (flags) => Effect22.gen(function* () {
|
|
|
3373
3424
|
if (badPort !== void 0) {
|
|
3374
3425
|
return yield* new InvalidMicroVmOptionsError({ message: `--port must be between 1 and 65535 (got ${badPort}).` });
|
|
3375
3426
|
}
|
|
3427
|
+
const inject = yield* parseInjectFlags(flags.inject);
|
|
3428
|
+
if (inject.length > 0 && flags.denyEgress) {
|
|
3429
|
+
return yield* new InvalidMicroVmOptionsError({ message: "--inject cannot be combined with --deny-egress." });
|
|
3430
|
+
}
|
|
3431
|
+
const volumes = yield* parseVolumeFlags(flags.volumes);
|
|
3432
|
+
if (volumes.length > 0 && flags.pauseOnTimeout) {
|
|
3433
|
+
return yield* new InvalidMicroVmOptionsError({ message: "--volume cannot be combined with --pause-on-timeout." });
|
|
3434
|
+
}
|
|
3376
3435
|
const applicationId = yield* resolveApplicationId(flags.app);
|
|
3377
3436
|
const input = {
|
|
3378
3437
|
...applicationId ? { applicationId } : {},
|
|
@@ -3389,11 +3448,13 @@ var createInput = (flags) => Effect22.gen(function* () {
|
|
|
3389
3448
|
...flags.ports.length > 0 ? { ports: [...flags.ports] } : {},
|
|
3390
3449
|
...env ? { env } : {},
|
|
3391
3450
|
...metadata ? { metadata } : {},
|
|
3392
|
-
...
|
|
3451
|
+
...volumes.length > 0 ? { volumes } : {},
|
|
3452
|
+
...flags.denyEgress || flags.privatePreviews || flags.allowEgress.length > 0 || inject.length > 0 ? {
|
|
3393
3453
|
network: {
|
|
3394
3454
|
egress: flags.denyEgress ? "deny" : "allow",
|
|
3395
3455
|
...flags.privatePreviews ? { previews: "private" } : {},
|
|
3396
|
-
...flags.allowEgress.length > 0 ? { allow: flags.allowEgress.map((entry) => entry.trim()) } : {}
|
|
3456
|
+
...flags.allowEgress.length > 0 ? { allow: flags.allowEgress.map((entry) => entry.trim()) } : {},
|
|
3457
|
+
...inject.length > 0 ? { inject } : {}
|
|
3397
3458
|
}
|
|
3398
3459
|
} : {},
|
|
3399
3460
|
...Option14.match(flags.region, { onNone: () => ({}), onSome: (region) => ({ region }) })
|
|
@@ -3402,7 +3463,26 @@ var createInput = (flags) => Effect22.gen(function* () {
|
|
|
3402
3463
|
});
|
|
3403
3464
|
var createMicroVm = (flags) => Effect22.gen(function* () {
|
|
3404
3465
|
const apiClient = yield* ApiClientService;
|
|
3405
|
-
const
|
|
3466
|
+
const parsed = yield* createInput(flags);
|
|
3467
|
+
const named = (parsed.volumes ?? []).filter((volume) => !UUID.test(volume.volumeId));
|
|
3468
|
+
const known = named.length > 0 ? yield* apiClient.request(
|
|
3469
|
+
(client) => client.microvms.volumes.list({ ...parsed.applicationId ? { applicationId: parsed.applicationId } : {} })
|
|
3470
|
+
) : [];
|
|
3471
|
+
const volumes = [];
|
|
3472
|
+
for (const volume of parsed.volumes ?? []) {
|
|
3473
|
+
if (UUID.test(volume.volumeId)) {
|
|
3474
|
+
volumes.push(volume);
|
|
3475
|
+
continue;
|
|
3476
|
+
}
|
|
3477
|
+
const match = known.find((entry) => entry.name === volume.volumeId);
|
|
3478
|
+
if (match === void 0) {
|
|
3479
|
+
return yield* new InvalidMicroVmOptionsError({
|
|
3480
|
+
message: `No volume is named ${volume.volumeId}. Create it with "gigadrive microvms volumes create ${volume.volumeId}".`
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
volumes.push({ volumeId: match.id, mountPath: volume.mountPath });
|
|
3484
|
+
}
|
|
3485
|
+
const input = volumes.length > 0 ? { ...parsed, volumes } : parsed;
|
|
3406
3486
|
if (!flags.json) yield* Console12.error(`Creating a microVM from ${input.image ?? "node22"}...`);
|
|
3407
3487
|
const vm = yield* apiClient.request((client) => client.microvms.create(input));
|
|
3408
3488
|
if (flags.json) {
|
|
@@ -3465,6 +3545,12 @@ var createCommand = Command12.make(
|
|
|
3465
3545
|
),
|
|
3466
3546
|
Options7.repeated
|
|
3467
3547
|
),
|
|
3548
|
+
inject: Options7.text("inject").pipe(
|
|
3549
|
+
Options7.withDescription(
|
|
3550
|
+
"Add a header to HTTPS requests to a domain, as DOMAIN:HEADER=VALUE (repeatable, up to 8 domains); the value never enters the microVM"
|
|
3551
|
+
),
|
|
3552
|
+
Options7.repeated
|
|
3553
|
+
),
|
|
3468
3554
|
pauseOnTimeout: Options7.boolean("pause-on-timeout").pipe(
|
|
3469
3555
|
Options7.withDescription("Pause the microVM when its timeout ends instead of stopping it")
|
|
3470
3556
|
),
|
|
@@ -3473,6 +3559,13 @@ var createCommand = Command12.make(
|
|
|
3473
3559
|
"Resume the paused microVM when a command, file call or public preview request reaches it"
|
|
3474
3560
|
)
|
|
3475
3561
|
),
|
|
3562
|
+
volumes: Options7.text("volume").pipe(
|
|
3563
|
+
Options7.withAlias("v"),
|
|
3564
|
+
Options7.withDescription(
|
|
3565
|
+
"Attach a volume as VOLUME:PATH, by ID or name, such as cache:/cache (repeatable, up to 4; saved when the microVM stops)"
|
|
3566
|
+
),
|
|
3567
|
+
Options7.repeated
|
|
3568
|
+
),
|
|
3476
3569
|
region: Options7.text("region").pipe(Options7.withDescription("Region to place the microVM in"), Options7.optional),
|
|
3477
3570
|
json: jsonOption2
|
|
3478
3571
|
},
|
|
@@ -3827,15 +3920,31 @@ var updateMicroVmNetwork = (microvmId, flags) => Effect22.gen(function* () {
|
|
|
3827
3920
|
});
|
|
3828
3921
|
}
|
|
3829
3922
|
yield* checkEgressFlags(flags.denyEgress, flags.allowEgress);
|
|
3923
|
+
const inject = yield* parseInjectFlags(flags.inject);
|
|
3924
|
+
if (inject.length > 0 && flags.denyEgress) {
|
|
3925
|
+
return yield* new InvalidMicroVmOptionsError({ message: "--inject cannot be combined with --deny-egress." });
|
|
3926
|
+
}
|
|
3927
|
+
if (flags.clearInject && (inject.length > 0 || flags.denyEgress)) {
|
|
3928
|
+
return yield* new InvalidMicroVmOptionsError({
|
|
3929
|
+
message: "--clear-inject cannot be combined with --inject or --deny-egress."
|
|
3930
|
+
});
|
|
3931
|
+
}
|
|
3830
3932
|
const apiClient = yield* ApiClientService;
|
|
3831
3933
|
const vm = yield* apiClient.request(
|
|
3832
3934
|
(client) => client.microvms.updateNetwork(
|
|
3833
3935
|
microvmId,
|
|
3834
|
-
flags.denyEgress ? { egress: "deny" } :
|
|
3936
|
+
flags.denyEgress ? { egress: "deny" } : {
|
|
3937
|
+
egress: "allow",
|
|
3938
|
+
...flags.allowEgress.length > 0 ? { allow: flags.allowEgress.map((entry) => entry.trim()) } : {},
|
|
3939
|
+
...inject.length > 0 || flags.clearInject ? { inject } : {}
|
|
3940
|
+
}
|
|
3835
3941
|
)
|
|
3836
3942
|
);
|
|
3837
3943
|
const reach = vm.network.egress === "deny" ? "no outbound traffic" : vm.network.allow ? vm.network.allow.join(", ") : "the whole internet";
|
|
3838
3944
|
yield* Console12.log(`${vm.id} now reaches ${reach}.`);
|
|
3945
|
+
for (const rule of vm.network.inject ?? []) {
|
|
3946
|
+
yield* Console12.log(`Adds ${rule.headers.join(", ")} to HTTPS requests to ${rule.domain}.`);
|
|
3947
|
+
}
|
|
3839
3948
|
return vm;
|
|
3840
3949
|
});
|
|
3841
3950
|
var networkCommand = Command12.make(
|
|
@@ -3851,6 +3960,15 @@ var networkCommand = Command12.make(
|
|
|
3851
3960
|
),
|
|
3852
3961
|
allowAllEgress: Options7.boolean("allow-all-egress").pipe(
|
|
3853
3962
|
Options7.withDescription("Reach the whole internet again (private networks stay blocked)")
|
|
3963
|
+
),
|
|
3964
|
+
inject: Options7.text("inject").pipe(
|
|
3965
|
+
Options7.withDescription(
|
|
3966
|
+
"Add a header to HTTPS requests to a domain, as DOMAIN:HEADER=VALUE (repeatable, up to 8 domains); the value never enters the microVM"
|
|
3967
|
+
),
|
|
3968
|
+
Options7.repeated
|
|
3969
|
+
),
|
|
3970
|
+
clearInject: Options7.boolean("clear-inject").pipe(
|
|
3971
|
+
Options7.withDescription("Remove every header rule added with --inject")
|
|
3854
3972
|
)
|
|
3855
3973
|
},
|
|
3856
3974
|
({ microvmId, ...flags }) => updateMicroVmNetwork(microvmId, flags).pipe(Effect22.asVoid, reportErrors2("update the microVM network"))
|
|
@@ -3955,6 +4073,90 @@ var imagesCommand = Command12.make("images", {}, () => Effect22.void).pipe(
|
|
|
3955
4073
|
Command12.withDescription("Built-in and custom microVM images"),
|
|
3956
4074
|
Command12.withSubcommands([imagesListCommand, imagesCreateCommand, imagesRemoveCommand])
|
|
3957
4075
|
);
|
|
4076
|
+
var volumeIdArg = Args5.text({ name: "volume-id" }).pipe(Args5.withDescription("The volume ID"));
|
|
4077
|
+
var volumesListCommand = Command12.make(
|
|
4078
|
+
"ls",
|
|
4079
|
+
{ app: appOption6, json: jsonOption2 },
|
|
4080
|
+
({ app, json }) => Effect22.gen(function* () {
|
|
4081
|
+
const apiClient = yield* ApiClientService;
|
|
4082
|
+
const applicationId = yield* resolveApplicationId(app);
|
|
4083
|
+
const volumes = yield* apiClient.request((client) => client.microvms.volumes.list({ applicationId }));
|
|
4084
|
+
if (json) return yield* Console12.log(JSON.stringify(volumes, null, 2));
|
|
4085
|
+
if (volumes.length === 0)
|
|
4086
|
+
return yield* Console12.log('No volumes yet. Create one with "gigadrive microvms volumes create <name>".');
|
|
4087
|
+
for (const line of formatVolumeTable(volumes)) yield* Console12.log(line);
|
|
4088
|
+
}).pipe(reportErrors2("list volumes"))
|
|
4089
|
+
).pipe(Command12.withDescription("List the application's volumes"));
|
|
4090
|
+
var createVolume = (flags) => Effect22.gen(function* () {
|
|
4091
|
+
const apiClient = yield* ApiClientService;
|
|
4092
|
+
const applicationId = yield* resolveApplicationId(flags.app);
|
|
4093
|
+
const volume = yield* apiClient.request(
|
|
4094
|
+
(client) => client.microvms.volumes.create({
|
|
4095
|
+
name: flags.name,
|
|
4096
|
+
...Option14.match(flags.size, { onNone: () => ({}), onSome: (sizeMb) => ({ sizeMb }) }),
|
|
4097
|
+
...applicationId ? { applicationId } : {}
|
|
4098
|
+
})
|
|
4099
|
+
);
|
|
4100
|
+
if (flags.json) {
|
|
4101
|
+
yield* Console12.log(JSON.stringify(volume, null, 2));
|
|
4102
|
+
} else {
|
|
4103
|
+
yield* Console12.log(`Created volume ${volume.name} (${String(volume.sizeMb)} MiB, ${volume.id}).`);
|
|
4104
|
+
yield* Console12.log(`Attach it: gigadrive microvms create --volume ${volume.name}:/data`);
|
|
4105
|
+
}
|
|
4106
|
+
return volume;
|
|
4107
|
+
});
|
|
4108
|
+
var volumesCreateCommand = Command12.make(
|
|
4109
|
+
"create",
|
|
4110
|
+
{
|
|
4111
|
+
name: Args5.text({ name: "name" }).pipe(
|
|
4112
|
+
Args5.withDescription("Lowercase letters, digits and -, unique per application")
|
|
4113
|
+
),
|
|
4114
|
+
size: Options7.integer("size").pipe(
|
|
4115
|
+
Options7.withDescription("Size in MiB, 1024 to 51200 (default: 10240)"),
|
|
4116
|
+
Options7.optional
|
|
4117
|
+
),
|
|
4118
|
+
app: appOption6,
|
|
4119
|
+
json: jsonOption2
|
|
4120
|
+
},
|
|
4121
|
+
(flags) => createVolume(flags).pipe(Effect22.asVoid, reportErrors2("create the volume"))
|
|
4122
|
+
).pipe(Command12.withDescription("Create an empty volume"));
|
|
4123
|
+
var volumesRenameCommand = Command12.make(
|
|
4124
|
+
"rename",
|
|
4125
|
+
{ volumeId: volumeIdArg, name: Args5.text({ name: "name" }).pipe(Args5.withDescription("The new name")) },
|
|
4126
|
+
({ volumeId, name }) => Effect22.gen(function* () {
|
|
4127
|
+
const apiClient = yield* ApiClientService;
|
|
4128
|
+
const volume = yield* apiClient.request((client) => client.microvms.volumes.rename(volumeId, name));
|
|
4129
|
+
yield* Console12.log(`Renamed the volume to ${volume.name}.`);
|
|
4130
|
+
}).pipe(reportErrors2("rename the volume"))
|
|
4131
|
+
).pipe(Command12.withDescription("Rename a volume"));
|
|
4132
|
+
var volumesSaveCommand = Command12.make(
|
|
4133
|
+
"save",
|
|
4134
|
+
{ microvmId: Args5.text({ name: "microvm-id" }).pipe(Args5.withDescription("A running microVM with volumes")) },
|
|
4135
|
+
({ microvmId }) => Effect22.gen(function* () {
|
|
4136
|
+
const apiClient = yield* ApiClientService;
|
|
4137
|
+
yield* apiClient.request((client) => client.microvms.saveVolumes(microvmId));
|
|
4138
|
+
yield* Console12.log(`Saved the volumes of ${microvmId}.`);
|
|
4139
|
+
}).pipe(reportErrors2("save the volumes"))
|
|
4140
|
+
).pipe(Command12.withDescription("Save a running microVM's volumes without stopping it"));
|
|
4141
|
+
var volumesRemoveCommand = Command12.make(
|
|
4142
|
+
"rm",
|
|
4143
|
+
{ volumeId: volumeIdArg },
|
|
4144
|
+
({ volumeId }) => Effect22.gen(function* () {
|
|
4145
|
+
const apiClient = yield* ApiClientService;
|
|
4146
|
+
yield* apiClient.request((client) => client.microvms.volumes.delete(volumeId));
|
|
4147
|
+
yield* Console12.log(`Deleted volume ${volumeId}.`);
|
|
4148
|
+
}).pipe(reportErrors2("delete the volume"))
|
|
4149
|
+
).pipe(Command12.withDescription("Delete a volume and its contents (it must not be attached)"));
|
|
4150
|
+
var volumesCommand = Command12.make("volumes", {}, () => Effect22.void).pipe(
|
|
4151
|
+
Command12.withDescription("Persistent filesystems that outlive the microVMs they are attached to"),
|
|
4152
|
+
Command12.withSubcommands([
|
|
4153
|
+
volumesListCommand,
|
|
4154
|
+
volumesCreateCommand,
|
|
4155
|
+
volumesRenameCommand,
|
|
4156
|
+
volumesSaveCommand,
|
|
4157
|
+
volumesRemoveCommand
|
|
4158
|
+
])
|
|
4159
|
+
);
|
|
3958
4160
|
var WEBHOOK_EVENTS = [
|
|
3959
4161
|
"microvm.created",
|
|
3960
4162
|
"microvm.running",
|
|
@@ -4083,6 +4285,7 @@ var SUBCOMMANDS = [
|
|
|
4083
4285
|
extendCommand,
|
|
4084
4286
|
networkCommand,
|
|
4085
4287
|
imagesCommand,
|
|
4288
|
+
volumesCommand,
|
|
4086
4289
|
webhooksCommand
|
|
4087
4290
|
];
|
|
4088
4291
|
var microvmsCommand = Command12.make("microvms", {}, () => Effect22.void).pipe(
|