disk 0.8.9 → 0.8.11
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/cli.js +64 -1
- package/dist/index.cjs +69 -1
- package/dist/index.d.cts +305 -1
- package/dist/index.d.ts +305 -1
- package/dist/index.js +68 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -99,6 +99,7 @@ var Disk = class {
|
|
|
99
99
|
metrics;
|
|
100
100
|
connectedClients;
|
|
101
101
|
authorizedUsers;
|
|
102
|
+
allowedIps;
|
|
102
103
|
/** @internal */
|
|
103
104
|
_client;
|
|
104
105
|
/** @internal */
|
|
@@ -120,6 +121,7 @@ var Disk = class {
|
|
|
120
121
|
this.metrics = data.metrics;
|
|
121
122
|
this.connectedClients = data.connectedClients;
|
|
122
123
|
this.authorizedUsers = data.authorizedUsers;
|
|
124
|
+
this.allowedIps = data.allowedIps;
|
|
123
125
|
this._client = client;
|
|
124
126
|
this._archilRegion = archilRegion;
|
|
125
127
|
}
|
|
@@ -139,7 +141,8 @@ var Disk = class {
|
|
|
139
141
|
mounts: this.mounts,
|
|
140
142
|
metrics: this.metrics,
|
|
141
143
|
connectedClients: this.connectedClients,
|
|
142
|
-
authorizedUsers: this.authorizedUsers
|
|
144
|
+
authorizedUsers: this.authorizedUsers,
|
|
145
|
+
allowedIps: this.allowedIps
|
|
143
146
|
};
|
|
144
147
|
}
|
|
145
148
|
async addUser(user) {
|
|
@@ -175,6 +178,32 @@ var Disk = class {
|
|
|
175
178
|
async removeTokenUser(identifier) {
|
|
176
179
|
await this.removeUser("token", identifier);
|
|
177
180
|
}
|
|
181
|
+
async getAllowedIPs() {
|
|
182
|
+
const data = await unwrap(
|
|
183
|
+
this._client.GET("/api/disks/{id}/allowed-ips", {
|
|
184
|
+
params: { path: { id: this.id } }
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
return data.allowedIps;
|
|
188
|
+
}
|
|
189
|
+
async setAllowedIPs(allowedIps) {
|
|
190
|
+
const data = await unwrap(
|
|
191
|
+
this._client.PUT("/api/disks/{id}/allowed-ips", {
|
|
192
|
+
params: { path: { id: this.id } },
|
|
193
|
+
body: { allowedIps }
|
|
194
|
+
})
|
|
195
|
+
);
|
|
196
|
+
return data.allowedIps;
|
|
197
|
+
}
|
|
198
|
+
async addAllowedIP(ip) {
|
|
199
|
+
const current = await this.getAllowedIPs();
|
|
200
|
+
if (current.includes(ip)) return current;
|
|
201
|
+
return this.setAllowedIPs([...current, ip]);
|
|
202
|
+
}
|
|
203
|
+
async removeAllowedIP(ip) {
|
|
204
|
+
const current = await this.getAllowedIPs();
|
|
205
|
+
return this.setAllowedIPs(current.filter((i) => i !== ip));
|
|
206
|
+
}
|
|
178
207
|
async delete() {
|
|
179
208
|
await unwrapEmpty(
|
|
180
209
|
this._client.DELETE("/api/disks/{id}", {
|
|
@@ -309,9 +338,17 @@ var Tokens = class {
|
|
|
309
338
|
};
|
|
310
339
|
|
|
311
340
|
// src/archil.ts
|
|
341
|
+
function isExecMountSpec(m) {
|
|
342
|
+
return typeof m === "object" && m !== null && "disk" in m;
|
|
343
|
+
}
|
|
344
|
+
function diskIdFromMount(m) {
|
|
345
|
+
return typeof m === "string" ? m : m.id;
|
|
346
|
+
}
|
|
312
347
|
var Archil = class {
|
|
313
348
|
disks;
|
|
314
349
|
tokens;
|
|
350
|
+
/** @internal */
|
|
351
|
+
_client;
|
|
315
352
|
constructor(opts = {}) {
|
|
316
353
|
const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
|
|
317
354
|
const region = opts.region ?? process.env.ARCHIL_REGION;
|
|
@@ -326,9 +363,35 @@ var Archil = class {
|
|
|
326
363
|
region,
|
|
327
364
|
baseUrl: opts.baseUrl
|
|
328
365
|
});
|
|
366
|
+
this._client = client;
|
|
329
367
|
this.disks = new Disks(client, region);
|
|
330
368
|
this.tokens = new Tokens(client);
|
|
331
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
372
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
373
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
374
|
+
*/
|
|
375
|
+
async exec(opts) {
|
|
376
|
+
const disks = {};
|
|
377
|
+
for (const [relPath, mount] of Object.entries(opts.disks)) {
|
|
378
|
+
if (isExecMountSpec(mount)) {
|
|
379
|
+
const entry = {
|
|
380
|
+
disk: diskIdFromMount(mount.disk),
|
|
381
|
+
readOnly: mount.readOnly ?? false
|
|
382
|
+
};
|
|
383
|
+
if (mount.subdirectory !== void 0) entry.subdirectory = mount.subdirectory;
|
|
384
|
+
disks[relPath] = entry;
|
|
385
|
+
} else {
|
|
386
|
+
disks[relPath] = diskIdFromMount(mount);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return unwrap(
|
|
390
|
+
this._client.POST("/api/exec", {
|
|
391
|
+
body: { disks, command: opts.command }
|
|
392
|
+
})
|
|
393
|
+
);
|
|
394
|
+
}
|
|
332
395
|
};
|
|
333
396
|
|
|
334
397
|
// src/index.ts
|
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
createApiKey: () => createApiKey,
|
|
40
40
|
createDisk: () => createDisk,
|
|
41
41
|
deleteApiKey: () => deleteApiKey,
|
|
42
|
+
exec: () => exec,
|
|
42
43
|
getDisk: () => getDisk,
|
|
43
44
|
listApiKeys: () => listApiKeys,
|
|
44
45
|
listDisks: () => listDisks
|
|
@@ -141,6 +142,7 @@ var Disk = class {
|
|
|
141
142
|
metrics;
|
|
142
143
|
connectedClients;
|
|
143
144
|
authorizedUsers;
|
|
145
|
+
allowedIps;
|
|
144
146
|
/** @internal */
|
|
145
147
|
_client;
|
|
146
148
|
/** @internal */
|
|
@@ -162,6 +164,7 @@ var Disk = class {
|
|
|
162
164
|
this.metrics = data.metrics;
|
|
163
165
|
this.connectedClients = data.connectedClients;
|
|
164
166
|
this.authorizedUsers = data.authorizedUsers;
|
|
167
|
+
this.allowedIps = data.allowedIps;
|
|
165
168
|
this._client = client;
|
|
166
169
|
this._archilRegion = archilRegion;
|
|
167
170
|
}
|
|
@@ -181,7 +184,8 @@ var Disk = class {
|
|
|
181
184
|
mounts: this.mounts,
|
|
182
185
|
metrics: this.metrics,
|
|
183
186
|
connectedClients: this.connectedClients,
|
|
184
|
-
authorizedUsers: this.authorizedUsers
|
|
187
|
+
authorizedUsers: this.authorizedUsers,
|
|
188
|
+
allowedIps: this.allowedIps
|
|
185
189
|
};
|
|
186
190
|
}
|
|
187
191
|
async addUser(user) {
|
|
@@ -217,6 +221,32 @@ var Disk = class {
|
|
|
217
221
|
async removeTokenUser(identifier) {
|
|
218
222
|
await this.removeUser("token", identifier);
|
|
219
223
|
}
|
|
224
|
+
async getAllowedIPs() {
|
|
225
|
+
const data = await unwrap(
|
|
226
|
+
this._client.GET("/api/disks/{id}/allowed-ips", {
|
|
227
|
+
params: { path: { id: this.id } }
|
|
228
|
+
})
|
|
229
|
+
);
|
|
230
|
+
return data.allowedIps;
|
|
231
|
+
}
|
|
232
|
+
async setAllowedIPs(allowedIps) {
|
|
233
|
+
const data = await unwrap(
|
|
234
|
+
this._client.PUT("/api/disks/{id}/allowed-ips", {
|
|
235
|
+
params: { path: { id: this.id } },
|
|
236
|
+
body: { allowedIps }
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
return data.allowedIps;
|
|
240
|
+
}
|
|
241
|
+
async addAllowedIP(ip) {
|
|
242
|
+
const current = await this.getAllowedIPs();
|
|
243
|
+
if (current.includes(ip)) return current;
|
|
244
|
+
return this.setAllowedIPs([...current, ip]);
|
|
245
|
+
}
|
|
246
|
+
async removeAllowedIP(ip) {
|
|
247
|
+
const current = await this.getAllowedIPs();
|
|
248
|
+
return this.setAllowedIPs(current.filter((i) => i !== ip));
|
|
249
|
+
}
|
|
220
250
|
async delete() {
|
|
221
251
|
await unwrapEmpty(
|
|
222
252
|
this._client.DELETE("/api/disks/{id}", {
|
|
@@ -351,9 +381,17 @@ var Tokens = class {
|
|
|
351
381
|
};
|
|
352
382
|
|
|
353
383
|
// src/archil.ts
|
|
384
|
+
function isExecMountSpec(m) {
|
|
385
|
+
return typeof m === "object" && m !== null && "disk" in m;
|
|
386
|
+
}
|
|
387
|
+
function diskIdFromMount(m) {
|
|
388
|
+
return typeof m === "string" ? m : m.id;
|
|
389
|
+
}
|
|
354
390
|
var Archil = class {
|
|
355
391
|
disks;
|
|
356
392
|
tokens;
|
|
393
|
+
/** @internal */
|
|
394
|
+
_client;
|
|
357
395
|
constructor(opts = {}) {
|
|
358
396
|
const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
|
|
359
397
|
const region = opts.region ?? process.env.ARCHIL_REGION;
|
|
@@ -368,9 +406,35 @@ var Archil = class {
|
|
|
368
406
|
region,
|
|
369
407
|
baseUrl: opts.baseUrl
|
|
370
408
|
});
|
|
409
|
+
this._client = client;
|
|
371
410
|
this.disks = new Disks(client, region);
|
|
372
411
|
this.tokens = new Tokens(client);
|
|
373
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
415
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
416
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
417
|
+
*/
|
|
418
|
+
async exec(opts) {
|
|
419
|
+
const disks = {};
|
|
420
|
+
for (const [relPath, mount] of Object.entries(opts.disks)) {
|
|
421
|
+
if (isExecMountSpec(mount)) {
|
|
422
|
+
const entry = {
|
|
423
|
+
disk: diskIdFromMount(mount.disk),
|
|
424
|
+
readOnly: mount.readOnly ?? false
|
|
425
|
+
};
|
|
426
|
+
if (mount.subdirectory !== void 0) entry.subdirectory = mount.subdirectory;
|
|
427
|
+
disks[relPath] = entry;
|
|
428
|
+
} else {
|
|
429
|
+
disks[relPath] = diskIdFromMount(mount);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return unwrap(
|
|
433
|
+
this._client.POST("/api/exec", {
|
|
434
|
+
body: { disks, command: opts.command }
|
|
435
|
+
})
|
|
436
|
+
);
|
|
437
|
+
}
|
|
374
438
|
};
|
|
375
439
|
|
|
376
440
|
// src/index.ts
|
|
@@ -404,6 +468,9 @@ function createApiKey(req) {
|
|
|
404
468
|
function deleteApiKey(id) {
|
|
405
469
|
return archil().tokens.delete(id);
|
|
406
470
|
}
|
|
471
|
+
function exec(opts) {
|
|
472
|
+
return archil().exec(opts);
|
|
473
|
+
}
|
|
407
474
|
// Annotate the CommonJS export names for ESM import in node:
|
|
408
475
|
0 && (module.exports = {
|
|
409
476
|
Archil,
|
|
@@ -415,6 +482,7 @@ function deleteApiKey(id) {
|
|
|
415
482
|
createApiKey,
|
|
416
483
|
createDisk,
|
|
417
484
|
deleteApiKey,
|
|
485
|
+
exec,
|
|
418
486
|
getDisk,
|
|
419
487
|
listApiKeys,
|
|
420
488
|
listDisks
|
package/dist/index.d.cts
CHANGED
|
@@ -102,6 +102,30 @@ interface paths {
|
|
|
102
102
|
patch?: never;
|
|
103
103
|
trace?: never;
|
|
104
104
|
};
|
|
105
|
+
"/api/disks/{id}/allowed-ips": {
|
|
106
|
+
parameters: {
|
|
107
|
+
query?: never;
|
|
108
|
+
header?: never;
|
|
109
|
+
path?: never;
|
|
110
|
+
cookie?: never;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Get IP allowlist
|
|
114
|
+
* @description Returns the current IP allowlist for a disk.
|
|
115
|
+
*/
|
|
116
|
+
get: operations["getAllowedIPs"];
|
|
117
|
+
/**
|
|
118
|
+
* Set IP allowlist
|
|
119
|
+
* @description Replaces the IP allowlist for a disk. When non-empty, only clients connecting from listed IPs or CIDR ranges can mount the disk. Pass an empty array to remove all restrictions.
|
|
120
|
+
*/
|
|
121
|
+
put: operations["setAllowedIPs"];
|
|
122
|
+
post?: never;
|
|
123
|
+
delete?: never;
|
|
124
|
+
options?: never;
|
|
125
|
+
head?: never;
|
|
126
|
+
patch?: never;
|
|
127
|
+
trace?: never;
|
|
128
|
+
};
|
|
105
129
|
"/api/disks/{id}/exec": {
|
|
106
130
|
parameters: {
|
|
107
131
|
query?: never;
|
|
@@ -124,6 +148,33 @@ interface paths {
|
|
|
124
148
|
patch?: never;
|
|
125
149
|
trace?: never;
|
|
126
150
|
};
|
|
151
|
+
"/api/exec": {
|
|
152
|
+
parameters: {
|
|
153
|
+
query?: never;
|
|
154
|
+
header?: never;
|
|
155
|
+
path?: never;
|
|
156
|
+
cookie?: never;
|
|
157
|
+
};
|
|
158
|
+
get?: never;
|
|
159
|
+
put?: never;
|
|
160
|
+
/**
|
|
161
|
+
* Execute a command with multiple disks mounted
|
|
162
|
+
* @description Launches a container with the supplied set of disks each mounted at its
|
|
163
|
+
* own relative path under `/mnt/archil`, runs the command to completion,
|
|
164
|
+
* and shuts down the container. Activation is atomic: every disk mounts
|
|
165
|
+
* or none of them do.
|
|
166
|
+
*
|
|
167
|
+
* Relative paths must be non-empty, non-absolute, and contain no `.` /
|
|
168
|
+
* `..` segments. Mounting two disks at the same relative path is an
|
|
169
|
+
* error.
|
|
170
|
+
*/
|
|
171
|
+
post: operations["exec"];
|
|
172
|
+
delete?: never;
|
|
173
|
+
options?: never;
|
|
174
|
+
head?: never;
|
|
175
|
+
patch?: never;
|
|
176
|
+
trace?: never;
|
|
177
|
+
};
|
|
127
178
|
"/api/tokens": {
|
|
128
179
|
parameters: {
|
|
129
180
|
query?: never;
|
|
@@ -197,6 +248,14 @@ interface components {
|
|
|
197
248
|
name: string;
|
|
198
249
|
/** @description Storage mount to attach. Omit for archil-managed storage. */
|
|
199
250
|
mounts?: components["schemas"]["MountConfig"][];
|
|
251
|
+
/**
|
|
252
|
+
* @description IP allowlist for mount access. When non-empty, only clients connecting from these IPs or CIDR ranges can mount the disk. An empty list (default) allows all IPs.
|
|
253
|
+
* @example [
|
|
254
|
+
* "203.0.113.0/24",
|
|
255
|
+
* "198.51.100.42"
|
|
256
|
+
* ]
|
|
257
|
+
*/
|
|
258
|
+
allowedIps?: string[];
|
|
200
259
|
/**
|
|
201
260
|
* @deprecated
|
|
202
261
|
* @description Deprecated. Use AddDiskUser after creation instead. When provided, suppresses the default auto-generated token user.
|
|
@@ -438,6 +497,24 @@ interface components {
|
|
|
438
497
|
metrics?: components["schemas"]["DiskMetrics"];
|
|
439
498
|
connectedClients?: components["schemas"]["ConnectedClient"][];
|
|
440
499
|
authorizedUsers?: components["schemas"]["AuthorizedUser"][];
|
|
500
|
+
/**
|
|
501
|
+
* @description IP allowlist for mount access. Empty means all IPs are allowed.
|
|
502
|
+
* @example [
|
|
503
|
+
* "203.0.113.0/24"
|
|
504
|
+
* ]
|
|
505
|
+
*/
|
|
506
|
+
allowedIps?: string[];
|
|
507
|
+
/**
|
|
508
|
+
* @description Capabilities supported by this disk. Determined at creation
|
|
509
|
+
* time and immutable thereafter. Defined values:
|
|
510
|
+
*
|
|
511
|
+
* * `checkpoints` — checkpoints can be created on this disk. Not
|
|
512
|
+
* available for disks with bring-your-own buckets.
|
|
513
|
+
* @example [
|
|
514
|
+
* "checkpoints"
|
|
515
|
+
* ]
|
|
516
|
+
*/
|
|
517
|
+
capabilities?: "checkpoints"[];
|
|
441
518
|
};
|
|
442
519
|
MountResponse: {
|
|
443
520
|
/** @description Mount identifier */
|
|
@@ -538,6 +615,19 @@ interface components {
|
|
|
538
615
|
success: boolean;
|
|
539
616
|
data: components["schemas"]["AuthorizedUser"];
|
|
540
617
|
};
|
|
618
|
+
ApiResponse_AllowedIPs: {
|
|
619
|
+
/** @example true */
|
|
620
|
+
success: boolean;
|
|
621
|
+
data: {
|
|
622
|
+
/**
|
|
623
|
+
* @example [
|
|
624
|
+
* "203.0.113.0/24",
|
|
625
|
+
* "198.51.100.42"
|
|
626
|
+
* ]
|
|
627
|
+
*/
|
|
628
|
+
allowedIps: string[];
|
|
629
|
+
};
|
|
630
|
+
};
|
|
541
631
|
CreateApiTokenRequest: {
|
|
542
632
|
/** @description Token name */
|
|
543
633
|
name: string;
|
|
@@ -616,6 +706,58 @@ interface components {
|
|
|
616
706
|
success: boolean;
|
|
617
707
|
data: components["schemas"]["ExecDiskResult"];
|
|
618
708
|
};
|
|
709
|
+
ExecRequest: {
|
|
710
|
+
/**
|
|
711
|
+
* @description Map of relative path under `/mnt/archil` to the disk to mount
|
|
712
|
+
* there. At least one entry is required. Relative paths must be
|
|
713
|
+
* non-empty, non-absolute, and contain no `.` or `..` segments.
|
|
714
|
+
*
|
|
715
|
+
* Each value is either a plain disk ID string (mounts the disk's
|
|
716
|
+
* root, read-write) or an object that additionally selects a
|
|
717
|
+
* subdirectory of the disk and/or marks the mount as read-only.
|
|
718
|
+
* @example {
|
|
719
|
+
* "data": "dsk-abc123",
|
|
720
|
+
* "logs": {
|
|
721
|
+
* "disk": "dsk-def456",
|
|
722
|
+
* "subdirectory": "app/logs",
|
|
723
|
+
* "readOnly": true
|
|
724
|
+
* }
|
|
725
|
+
* }
|
|
726
|
+
*/
|
|
727
|
+
disks: {
|
|
728
|
+
[key: string]: string | components["schemas"]["ExecMount"];
|
|
729
|
+
};
|
|
730
|
+
/**
|
|
731
|
+
* @description Shell command to execute inside the container
|
|
732
|
+
* @example ls -la /mnt/archil/data /mnt/archil/logs
|
|
733
|
+
*/
|
|
734
|
+
command: string;
|
|
735
|
+
};
|
|
736
|
+
ExecMount: {
|
|
737
|
+
/**
|
|
738
|
+
* @description Disk ID to mount at this relative path
|
|
739
|
+
* @example dsk-abc123
|
|
740
|
+
*/
|
|
741
|
+
disk: string;
|
|
742
|
+
/**
|
|
743
|
+
* @description Subdirectory of the disk to expose at the mountpoint. Must be a
|
|
744
|
+
* relative path with no `.` or `..` segments. When omitted, the
|
|
745
|
+
* disk's root is exposed.
|
|
746
|
+
* @example app/logs
|
|
747
|
+
*/
|
|
748
|
+
subdirectory?: string;
|
|
749
|
+
/**
|
|
750
|
+
* @description When true, the disk is mounted read-only inside the container.
|
|
751
|
+
* Writes against the mount fail with EROFS.
|
|
752
|
+
* @default false
|
|
753
|
+
*/
|
|
754
|
+
readOnly: boolean;
|
|
755
|
+
};
|
|
756
|
+
ApiResponse_Exec: {
|
|
757
|
+
/** @example true */
|
|
758
|
+
success: boolean;
|
|
759
|
+
data: components["schemas"]["ExecDiskResult"];
|
|
760
|
+
};
|
|
619
761
|
};
|
|
620
762
|
responses: {
|
|
621
763
|
/** @description Invalid or missing authentication credentials */
|
|
@@ -871,6 +1013,72 @@ interface operations {
|
|
|
871
1013
|
500: components["responses"]["InternalError"];
|
|
872
1014
|
};
|
|
873
1015
|
};
|
|
1016
|
+
getAllowedIPs: {
|
|
1017
|
+
parameters: {
|
|
1018
|
+
query?: never;
|
|
1019
|
+
header?: never;
|
|
1020
|
+
path: {
|
|
1021
|
+
/** @description Disk ID (format `dsk-{16 hex chars}`) */
|
|
1022
|
+
id: components["parameters"]["DiskId"];
|
|
1023
|
+
};
|
|
1024
|
+
cookie?: never;
|
|
1025
|
+
};
|
|
1026
|
+
requestBody?: never;
|
|
1027
|
+
responses: {
|
|
1028
|
+
/** @description Current IP allowlist */
|
|
1029
|
+
200: {
|
|
1030
|
+
headers: {
|
|
1031
|
+
[name: string]: unknown;
|
|
1032
|
+
};
|
|
1033
|
+
content: {
|
|
1034
|
+
"application/json": components["schemas"]["ApiResponse_AllowedIPs"];
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
1037
|
+
401: components["responses"]["Unauthorized"];
|
|
1038
|
+
404: components["responses"]["NotFound"];
|
|
1039
|
+
500: components["responses"]["InternalError"];
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1042
|
+
setAllowedIPs: {
|
|
1043
|
+
parameters: {
|
|
1044
|
+
query?: never;
|
|
1045
|
+
header?: never;
|
|
1046
|
+
path: {
|
|
1047
|
+
/** @description Disk ID (format `dsk-{16 hex chars}`) */
|
|
1048
|
+
id: components["parameters"]["DiskId"];
|
|
1049
|
+
};
|
|
1050
|
+
cookie?: never;
|
|
1051
|
+
};
|
|
1052
|
+
requestBody: {
|
|
1053
|
+
content: {
|
|
1054
|
+
"application/json": {
|
|
1055
|
+
/**
|
|
1056
|
+
* @description List of IPs or CIDR ranges. Empty array removes restrictions.
|
|
1057
|
+
* @example [
|
|
1058
|
+
* "203.0.113.0/24",
|
|
1059
|
+
* "198.51.100.42"
|
|
1060
|
+
* ]
|
|
1061
|
+
*/
|
|
1062
|
+
allowedIps: string[];
|
|
1063
|
+
};
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
responses: {
|
|
1067
|
+
/** @description Allowlist updated */
|
|
1068
|
+
200: {
|
|
1069
|
+
headers: {
|
|
1070
|
+
[name: string]: unknown;
|
|
1071
|
+
};
|
|
1072
|
+
content: {
|
|
1073
|
+
"application/json": components["schemas"]["ApiResponse_AllowedIPs"];
|
|
1074
|
+
};
|
|
1075
|
+
};
|
|
1076
|
+
400: components["responses"]["ValidationError"];
|
|
1077
|
+
401: components["responses"]["Unauthorized"];
|
|
1078
|
+
404: components["responses"]["NotFound"];
|
|
1079
|
+
500: components["responses"]["InternalError"];
|
|
1080
|
+
};
|
|
1081
|
+
};
|
|
874
1082
|
execDisk: {
|
|
875
1083
|
parameters: {
|
|
876
1084
|
query?: never;
|
|
@@ -911,6 +1119,43 @@ interface operations {
|
|
|
911
1119
|
};
|
|
912
1120
|
};
|
|
913
1121
|
};
|
|
1122
|
+
exec: {
|
|
1123
|
+
parameters: {
|
|
1124
|
+
query?: never;
|
|
1125
|
+
header?: never;
|
|
1126
|
+
path?: never;
|
|
1127
|
+
cookie?: never;
|
|
1128
|
+
};
|
|
1129
|
+
requestBody: {
|
|
1130
|
+
content: {
|
|
1131
|
+
"application/json": components["schemas"]["ExecRequest"];
|
|
1132
|
+
};
|
|
1133
|
+
};
|
|
1134
|
+
responses: {
|
|
1135
|
+
/** @description Command completed */
|
|
1136
|
+
200: {
|
|
1137
|
+
headers: {
|
|
1138
|
+
[name: string]: unknown;
|
|
1139
|
+
};
|
|
1140
|
+
content: {
|
|
1141
|
+
"application/json": components["schemas"]["ApiResponse_Exec"];
|
|
1142
|
+
};
|
|
1143
|
+
};
|
|
1144
|
+
400: components["responses"]["ValidationError"];
|
|
1145
|
+
401: components["responses"]["Unauthorized"];
|
|
1146
|
+
404: components["responses"]["NotFound"];
|
|
1147
|
+
500: components["responses"]["InternalError"];
|
|
1148
|
+
/** @description Command timed out */
|
|
1149
|
+
504: {
|
|
1150
|
+
headers: {
|
|
1151
|
+
[name: string]: unknown;
|
|
1152
|
+
};
|
|
1153
|
+
content: {
|
|
1154
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
1155
|
+
};
|
|
1156
|
+
};
|
|
1157
|
+
};
|
|
1158
|
+
};
|
|
914
1159
|
listApiTokens: {
|
|
915
1160
|
parameters: {
|
|
916
1161
|
query?: {
|
|
@@ -1014,6 +1259,7 @@ type AwsStsUser = components["schemas"]["AwsStsUser"];
|
|
|
1014
1259
|
type CreateApiTokenRequest = components["schemas"]["CreateApiTokenRequest"];
|
|
1015
1260
|
type ApiTokenResponse = components["schemas"]["ApiTokenResponse"];
|
|
1016
1261
|
type ExecDiskResult = components["schemas"]["ExecDiskResult"];
|
|
1262
|
+
type ExecRequest = components["schemas"]["ExecRequest"];
|
|
1017
1263
|
type DiskStatus = DiskResponse["status"];
|
|
1018
1264
|
|
|
1019
1265
|
interface MountOptions {
|
|
@@ -1039,6 +1285,7 @@ declare class Disk {
|
|
|
1039
1285
|
readonly metrics?: DiskMetrics;
|
|
1040
1286
|
readonly connectedClients?: ConnectedClient[];
|
|
1041
1287
|
readonly authorizedUsers?: AuthorizedUser[];
|
|
1288
|
+
readonly allowedIps?: string[];
|
|
1042
1289
|
/** @internal */
|
|
1043
1290
|
private readonly _client;
|
|
1044
1291
|
/** @internal */
|
|
@@ -1053,6 +1300,10 @@ declare class Disk {
|
|
|
1053
1300
|
identifier: string;
|
|
1054
1301
|
}>;
|
|
1055
1302
|
removeTokenUser(identifier: string): Promise<void>;
|
|
1303
|
+
getAllowedIPs(): Promise<string[]>;
|
|
1304
|
+
setAllowedIPs(allowedIps: string[]): Promise<string[]>;
|
|
1305
|
+
addAllowedIP(ip: string): Promise<string[]>;
|
|
1306
|
+
removeAllowedIP(ip: string): Promise<string[]>;
|
|
1056
1307
|
delete(): Promise<void>;
|
|
1057
1308
|
/**
|
|
1058
1309
|
* Execute a command in a container with this disk mounted.
|
|
@@ -1120,10 +1371,57 @@ interface ArchilOptions {
|
|
|
1120
1371
|
/** Override the control plane base URL (useful for testing). */
|
|
1121
1372
|
baseUrl?: string;
|
|
1122
1373
|
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Options that apply to a single mounted disk in an exec request.
|
|
1376
|
+
* Use this object form when you need to pin the mount to a subdirectoryectory
|
|
1377
|
+
* of the disk and/or mount it read-only; for the default case (mount
|
|
1378
|
+
* the disk's root, read-write), pass a `Disk` or disk-id string instead.
|
|
1379
|
+
*/
|
|
1380
|
+
interface ExecMountSpec {
|
|
1381
|
+
/** Disk to mount, by `Disk` instance or raw disk id string. */
|
|
1382
|
+
disk: Disk | string;
|
|
1383
|
+
/**
|
|
1384
|
+
* Subdirectory of the disk to expose at the mountpoint. Must be a
|
|
1385
|
+
* relative path with no `.` or `..` segments. When omitted, the disk's
|
|
1386
|
+
* root is exposed.
|
|
1387
|
+
*/
|
|
1388
|
+
subdirectory?: string;
|
|
1389
|
+
/**
|
|
1390
|
+
* When true, mount the disk read-only inside the container. Writes
|
|
1391
|
+
* against the mount fail with EROFS. Defaults to false.
|
|
1392
|
+
*/
|
|
1393
|
+
readOnly?: boolean;
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* One disk to mount in an exec request. Either a `Disk`/disk-id string
|
|
1397
|
+
* (mounts the disk's root, read-write) or an `ExecMountSpec` object that
|
|
1398
|
+
* additionally selects a subdirectoryectory of the disk and/or marks the mount
|
|
1399
|
+
* as read-only. Used by Archil#exec — the map key is the relative path
|
|
1400
|
+
* under /mnt/archil at which to mount the disk.
|
|
1401
|
+
*/
|
|
1402
|
+
type ExecMount = Disk | string | ExecMountSpec;
|
|
1403
|
+
interface ExecOptions {
|
|
1404
|
+
/**
|
|
1405
|
+
* Disks to mount, keyed by the relative path under `/mnt/archil` at which
|
|
1406
|
+
* to mount each one. At least one entry is required. Paths must be
|
|
1407
|
+
* non-empty, non-absolute, and contain no `.` or `..` segments.
|
|
1408
|
+
*/
|
|
1409
|
+
disks: Record<string, ExecMount>;
|
|
1410
|
+
/** Shell command to run inside the container. */
|
|
1411
|
+
command: string;
|
|
1412
|
+
}
|
|
1123
1413
|
declare class Archil {
|
|
1124
1414
|
readonly disks: Disks;
|
|
1125
1415
|
readonly tokens: Tokens;
|
|
1416
|
+
/** @internal */
|
|
1417
|
+
private readonly _client;
|
|
1126
1418
|
constructor(opts?: ArchilOptions);
|
|
1419
|
+
/**
|
|
1420
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
1421
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
1422
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
1423
|
+
*/
|
|
1424
|
+
exec(opts: ExecOptions): Promise<ExecDiskResult>;
|
|
1127
1425
|
}
|
|
1128
1426
|
|
|
1129
1427
|
declare class ArchilApiError extends Error {
|
|
@@ -1141,5 +1439,11 @@ declare function createApiKey(req: CreateApiTokenRequest): Promise<ApiTokenRespo
|
|
|
1141
1439
|
token?: string;
|
|
1142
1440
|
}>;
|
|
1143
1441
|
declare function deleteApiKey(id: string): Promise<void>;
|
|
1442
|
+
/**
|
|
1443
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
1444
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
1445
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
1446
|
+
*/
|
|
1447
|
+
declare function exec(opts: ExecOptions): Promise<ExecDiskResult>;
|
|
1144
1448
|
|
|
1145
|
-
export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, type CreateDiskResult, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type ExecResult, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens, configure, createApiKey, createDisk, deleteApiKey, getDisk, listApiKeys, listDisks };
|
|
1449
|
+
export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, type CreateDiskResult, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type ExecMount, type ExecMountSpec, type ExecOptions, type ExecRequest, type ExecResult, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens, configure, createApiKey, createDisk, deleteApiKey, exec, getDisk, listApiKeys, listDisks };
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,30 @@ interface paths {
|
|
|
102
102
|
patch?: never;
|
|
103
103
|
trace?: never;
|
|
104
104
|
};
|
|
105
|
+
"/api/disks/{id}/allowed-ips": {
|
|
106
|
+
parameters: {
|
|
107
|
+
query?: never;
|
|
108
|
+
header?: never;
|
|
109
|
+
path?: never;
|
|
110
|
+
cookie?: never;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Get IP allowlist
|
|
114
|
+
* @description Returns the current IP allowlist for a disk.
|
|
115
|
+
*/
|
|
116
|
+
get: operations["getAllowedIPs"];
|
|
117
|
+
/**
|
|
118
|
+
* Set IP allowlist
|
|
119
|
+
* @description Replaces the IP allowlist for a disk. When non-empty, only clients connecting from listed IPs or CIDR ranges can mount the disk. Pass an empty array to remove all restrictions.
|
|
120
|
+
*/
|
|
121
|
+
put: operations["setAllowedIPs"];
|
|
122
|
+
post?: never;
|
|
123
|
+
delete?: never;
|
|
124
|
+
options?: never;
|
|
125
|
+
head?: never;
|
|
126
|
+
patch?: never;
|
|
127
|
+
trace?: never;
|
|
128
|
+
};
|
|
105
129
|
"/api/disks/{id}/exec": {
|
|
106
130
|
parameters: {
|
|
107
131
|
query?: never;
|
|
@@ -124,6 +148,33 @@ interface paths {
|
|
|
124
148
|
patch?: never;
|
|
125
149
|
trace?: never;
|
|
126
150
|
};
|
|
151
|
+
"/api/exec": {
|
|
152
|
+
parameters: {
|
|
153
|
+
query?: never;
|
|
154
|
+
header?: never;
|
|
155
|
+
path?: never;
|
|
156
|
+
cookie?: never;
|
|
157
|
+
};
|
|
158
|
+
get?: never;
|
|
159
|
+
put?: never;
|
|
160
|
+
/**
|
|
161
|
+
* Execute a command with multiple disks mounted
|
|
162
|
+
* @description Launches a container with the supplied set of disks each mounted at its
|
|
163
|
+
* own relative path under `/mnt/archil`, runs the command to completion,
|
|
164
|
+
* and shuts down the container. Activation is atomic: every disk mounts
|
|
165
|
+
* or none of them do.
|
|
166
|
+
*
|
|
167
|
+
* Relative paths must be non-empty, non-absolute, and contain no `.` /
|
|
168
|
+
* `..` segments. Mounting two disks at the same relative path is an
|
|
169
|
+
* error.
|
|
170
|
+
*/
|
|
171
|
+
post: operations["exec"];
|
|
172
|
+
delete?: never;
|
|
173
|
+
options?: never;
|
|
174
|
+
head?: never;
|
|
175
|
+
patch?: never;
|
|
176
|
+
trace?: never;
|
|
177
|
+
};
|
|
127
178
|
"/api/tokens": {
|
|
128
179
|
parameters: {
|
|
129
180
|
query?: never;
|
|
@@ -197,6 +248,14 @@ interface components {
|
|
|
197
248
|
name: string;
|
|
198
249
|
/** @description Storage mount to attach. Omit for archil-managed storage. */
|
|
199
250
|
mounts?: components["schemas"]["MountConfig"][];
|
|
251
|
+
/**
|
|
252
|
+
* @description IP allowlist for mount access. When non-empty, only clients connecting from these IPs or CIDR ranges can mount the disk. An empty list (default) allows all IPs.
|
|
253
|
+
* @example [
|
|
254
|
+
* "203.0.113.0/24",
|
|
255
|
+
* "198.51.100.42"
|
|
256
|
+
* ]
|
|
257
|
+
*/
|
|
258
|
+
allowedIps?: string[];
|
|
200
259
|
/**
|
|
201
260
|
* @deprecated
|
|
202
261
|
* @description Deprecated. Use AddDiskUser after creation instead. When provided, suppresses the default auto-generated token user.
|
|
@@ -438,6 +497,24 @@ interface components {
|
|
|
438
497
|
metrics?: components["schemas"]["DiskMetrics"];
|
|
439
498
|
connectedClients?: components["schemas"]["ConnectedClient"][];
|
|
440
499
|
authorizedUsers?: components["schemas"]["AuthorizedUser"][];
|
|
500
|
+
/**
|
|
501
|
+
* @description IP allowlist for mount access. Empty means all IPs are allowed.
|
|
502
|
+
* @example [
|
|
503
|
+
* "203.0.113.0/24"
|
|
504
|
+
* ]
|
|
505
|
+
*/
|
|
506
|
+
allowedIps?: string[];
|
|
507
|
+
/**
|
|
508
|
+
* @description Capabilities supported by this disk. Determined at creation
|
|
509
|
+
* time and immutable thereafter. Defined values:
|
|
510
|
+
*
|
|
511
|
+
* * `checkpoints` — checkpoints can be created on this disk. Not
|
|
512
|
+
* available for disks with bring-your-own buckets.
|
|
513
|
+
* @example [
|
|
514
|
+
* "checkpoints"
|
|
515
|
+
* ]
|
|
516
|
+
*/
|
|
517
|
+
capabilities?: "checkpoints"[];
|
|
441
518
|
};
|
|
442
519
|
MountResponse: {
|
|
443
520
|
/** @description Mount identifier */
|
|
@@ -538,6 +615,19 @@ interface components {
|
|
|
538
615
|
success: boolean;
|
|
539
616
|
data: components["schemas"]["AuthorizedUser"];
|
|
540
617
|
};
|
|
618
|
+
ApiResponse_AllowedIPs: {
|
|
619
|
+
/** @example true */
|
|
620
|
+
success: boolean;
|
|
621
|
+
data: {
|
|
622
|
+
/**
|
|
623
|
+
* @example [
|
|
624
|
+
* "203.0.113.0/24",
|
|
625
|
+
* "198.51.100.42"
|
|
626
|
+
* ]
|
|
627
|
+
*/
|
|
628
|
+
allowedIps: string[];
|
|
629
|
+
};
|
|
630
|
+
};
|
|
541
631
|
CreateApiTokenRequest: {
|
|
542
632
|
/** @description Token name */
|
|
543
633
|
name: string;
|
|
@@ -616,6 +706,58 @@ interface components {
|
|
|
616
706
|
success: boolean;
|
|
617
707
|
data: components["schemas"]["ExecDiskResult"];
|
|
618
708
|
};
|
|
709
|
+
ExecRequest: {
|
|
710
|
+
/**
|
|
711
|
+
* @description Map of relative path under `/mnt/archil` to the disk to mount
|
|
712
|
+
* there. At least one entry is required. Relative paths must be
|
|
713
|
+
* non-empty, non-absolute, and contain no `.` or `..` segments.
|
|
714
|
+
*
|
|
715
|
+
* Each value is either a plain disk ID string (mounts the disk's
|
|
716
|
+
* root, read-write) or an object that additionally selects a
|
|
717
|
+
* subdirectory of the disk and/or marks the mount as read-only.
|
|
718
|
+
* @example {
|
|
719
|
+
* "data": "dsk-abc123",
|
|
720
|
+
* "logs": {
|
|
721
|
+
* "disk": "dsk-def456",
|
|
722
|
+
* "subdirectory": "app/logs",
|
|
723
|
+
* "readOnly": true
|
|
724
|
+
* }
|
|
725
|
+
* }
|
|
726
|
+
*/
|
|
727
|
+
disks: {
|
|
728
|
+
[key: string]: string | components["schemas"]["ExecMount"];
|
|
729
|
+
};
|
|
730
|
+
/**
|
|
731
|
+
* @description Shell command to execute inside the container
|
|
732
|
+
* @example ls -la /mnt/archil/data /mnt/archil/logs
|
|
733
|
+
*/
|
|
734
|
+
command: string;
|
|
735
|
+
};
|
|
736
|
+
ExecMount: {
|
|
737
|
+
/**
|
|
738
|
+
* @description Disk ID to mount at this relative path
|
|
739
|
+
* @example dsk-abc123
|
|
740
|
+
*/
|
|
741
|
+
disk: string;
|
|
742
|
+
/**
|
|
743
|
+
* @description Subdirectory of the disk to expose at the mountpoint. Must be a
|
|
744
|
+
* relative path with no `.` or `..` segments. When omitted, the
|
|
745
|
+
* disk's root is exposed.
|
|
746
|
+
* @example app/logs
|
|
747
|
+
*/
|
|
748
|
+
subdirectory?: string;
|
|
749
|
+
/**
|
|
750
|
+
* @description When true, the disk is mounted read-only inside the container.
|
|
751
|
+
* Writes against the mount fail with EROFS.
|
|
752
|
+
* @default false
|
|
753
|
+
*/
|
|
754
|
+
readOnly: boolean;
|
|
755
|
+
};
|
|
756
|
+
ApiResponse_Exec: {
|
|
757
|
+
/** @example true */
|
|
758
|
+
success: boolean;
|
|
759
|
+
data: components["schemas"]["ExecDiskResult"];
|
|
760
|
+
};
|
|
619
761
|
};
|
|
620
762
|
responses: {
|
|
621
763
|
/** @description Invalid or missing authentication credentials */
|
|
@@ -871,6 +1013,72 @@ interface operations {
|
|
|
871
1013
|
500: components["responses"]["InternalError"];
|
|
872
1014
|
};
|
|
873
1015
|
};
|
|
1016
|
+
getAllowedIPs: {
|
|
1017
|
+
parameters: {
|
|
1018
|
+
query?: never;
|
|
1019
|
+
header?: never;
|
|
1020
|
+
path: {
|
|
1021
|
+
/** @description Disk ID (format `dsk-{16 hex chars}`) */
|
|
1022
|
+
id: components["parameters"]["DiskId"];
|
|
1023
|
+
};
|
|
1024
|
+
cookie?: never;
|
|
1025
|
+
};
|
|
1026
|
+
requestBody?: never;
|
|
1027
|
+
responses: {
|
|
1028
|
+
/** @description Current IP allowlist */
|
|
1029
|
+
200: {
|
|
1030
|
+
headers: {
|
|
1031
|
+
[name: string]: unknown;
|
|
1032
|
+
};
|
|
1033
|
+
content: {
|
|
1034
|
+
"application/json": components["schemas"]["ApiResponse_AllowedIPs"];
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
1037
|
+
401: components["responses"]["Unauthorized"];
|
|
1038
|
+
404: components["responses"]["NotFound"];
|
|
1039
|
+
500: components["responses"]["InternalError"];
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1042
|
+
setAllowedIPs: {
|
|
1043
|
+
parameters: {
|
|
1044
|
+
query?: never;
|
|
1045
|
+
header?: never;
|
|
1046
|
+
path: {
|
|
1047
|
+
/** @description Disk ID (format `dsk-{16 hex chars}`) */
|
|
1048
|
+
id: components["parameters"]["DiskId"];
|
|
1049
|
+
};
|
|
1050
|
+
cookie?: never;
|
|
1051
|
+
};
|
|
1052
|
+
requestBody: {
|
|
1053
|
+
content: {
|
|
1054
|
+
"application/json": {
|
|
1055
|
+
/**
|
|
1056
|
+
* @description List of IPs or CIDR ranges. Empty array removes restrictions.
|
|
1057
|
+
* @example [
|
|
1058
|
+
* "203.0.113.0/24",
|
|
1059
|
+
* "198.51.100.42"
|
|
1060
|
+
* ]
|
|
1061
|
+
*/
|
|
1062
|
+
allowedIps: string[];
|
|
1063
|
+
};
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
responses: {
|
|
1067
|
+
/** @description Allowlist updated */
|
|
1068
|
+
200: {
|
|
1069
|
+
headers: {
|
|
1070
|
+
[name: string]: unknown;
|
|
1071
|
+
};
|
|
1072
|
+
content: {
|
|
1073
|
+
"application/json": components["schemas"]["ApiResponse_AllowedIPs"];
|
|
1074
|
+
};
|
|
1075
|
+
};
|
|
1076
|
+
400: components["responses"]["ValidationError"];
|
|
1077
|
+
401: components["responses"]["Unauthorized"];
|
|
1078
|
+
404: components["responses"]["NotFound"];
|
|
1079
|
+
500: components["responses"]["InternalError"];
|
|
1080
|
+
};
|
|
1081
|
+
};
|
|
874
1082
|
execDisk: {
|
|
875
1083
|
parameters: {
|
|
876
1084
|
query?: never;
|
|
@@ -911,6 +1119,43 @@ interface operations {
|
|
|
911
1119
|
};
|
|
912
1120
|
};
|
|
913
1121
|
};
|
|
1122
|
+
exec: {
|
|
1123
|
+
parameters: {
|
|
1124
|
+
query?: never;
|
|
1125
|
+
header?: never;
|
|
1126
|
+
path?: never;
|
|
1127
|
+
cookie?: never;
|
|
1128
|
+
};
|
|
1129
|
+
requestBody: {
|
|
1130
|
+
content: {
|
|
1131
|
+
"application/json": components["schemas"]["ExecRequest"];
|
|
1132
|
+
};
|
|
1133
|
+
};
|
|
1134
|
+
responses: {
|
|
1135
|
+
/** @description Command completed */
|
|
1136
|
+
200: {
|
|
1137
|
+
headers: {
|
|
1138
|
+
[name: string]: unknown;
|
|
1139
|
+
};
|
|
1140
|
+
content: {
|
|
1141
|
+
"application/json": components["schemas"]["ApiResponse_Exec"];
|
|
1142
|
+
};
|
|
1143
|
+
};
|
|
1144
|
+
400: components["responses"]["ValidationError"];
|
|
1145
|
+
401: components["responses"]["Unauthorized"];
|
|
1146
|
+
404: components["responses"]["NotFound"];
|
|
1147
|
+
500: components["responses"]["InternalError"];
|
|
1148
|
+
/** @description Command timed out */
|
|
1149
|
+
504: {
|
|
1150
|
+
headers: {
|
|
1151
|
+
[name: string]: unknown;
|
|
1152
|
+
};
|
|
1153
|
+
content: {
|
|
1154
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
1155
|
+
};
|
|
1156
|
+
};
|
|
1157
|
+
};
|
|
1158
|
+
};
|
|
914
1159
|
listApiTokens: {
|
|
915
1160
|
parameters: {
|
|
916
1161
|
query?: {
|
|
@@ -1014,6 +1259,7 @@ type AwsStsUser = components["schemas"]["AwsStsUser"];
|
|
|
1014
1259
|
type CreateApiTokenRequest = components["schemas"]["CreateApiTokenRequest"];
|
|
1015
1260
|
type ApiTokenResponse = components["schemas"]["ApiTokenResponse"];
|
|
1016
1261
|
type ExecDiskResult = components["schemas"]["ExecDiskResult"];
|
|
1262
|
+
type ExecRequest = components["schemas"]["ExecRequest"];
|
|
1017
1263
|
type DiskStatus = DiskResponse["status"];
|
|
1018
1264
|
|
|
1019
1265
|
interface MountOptions {
|
|
@@ -1039,6 +1285,7 @@ declare class Disk {
|
|
|
1039
1285
|
readonly metrics?: DiskMetrics;
|
|
1040
1286
|
readonly connectedClients?: ConnectedClient[];
|
|
1041
1287
|
readonly authorizedUsers?: AuthorizedUser[];
|
|
1288
|
+
readonly allowedIps?: string[];
|
|
1042
1289
|
/** @internal */
|
|
1043
1290
|
private readonly _client;
|
|
1044
1291
|
/** @internal */
|
|
@@ -1053,6 +1300,10 @@ declare class Disk {
|
|
|
1053
1300
|
identifier: string;
|
|
1054
1301
|
}>;
|
|
1055
1302
|
removeTokenUser(identifier: string): Promise<void>;
|
|
1303
|
+
getAllowedIPs(): Promise<string[]>;
|
|
1304
|
+
setAllowedIPs(allowedIps: string[]): Promise<string[]>;
|
|
1305
|
+
addAllowedIP(ip: string): Promise<string[]>;
|
|
1306
|
+
removeAllowedIP(ip: string): Promise<string[]>;
|
|
1056
1307
|
delete(): Promise<void>;
|
|
1057
1308
|
/**
|
|
1058
1309
|
* Execute a command in a container with this disk mounted.
|
|
@@ -1120,10 +1371,57 @@ interface ArchilOptions {
|
|
|
1120
1371
|
/** Override the control plane base URL (useful for testing). */
|
|
1121
1372
|
baseUrl?: string;
|
|
1122
1373
|
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Options that apply to a single mounted disk in an exec request.
|
|
1376
|
+
* Use this object form when you need to pin the mount to a subdirectoryectory
|
|
1377
|
+
* of the disk and/or mount it read-only; for the default case (mount
|
|
1378
|
+
* the disk's root, read-write), pass a `Disk` or disk-id string instead.
|
|
1379
|
+
*/
|
|
1380
|
+
interface ExecMountSpec {
|
|
1381
|
+
/** Disk to mount, by `Disk` instance or raw disk id string. */
|
|
1382
|
+
disk: Disk | string;
|
|
1383
|
+
/**
|
|
1384
|
+
* Subdirectory of the disk to expose at the mountpoint. Must be a
|
|
1385
|
+
* relative path with no `.` or `..` segments. When omitted, the disk's
|
|
1386
|
+
* root is exposed.
|
|
1387
|
+
*/
|
|
1388
|
+
subdirectory?: string;
|
|
1389
|
+
/**
|
|
1390
|
+
* When true, mount the disk read-only inside the container. Writes
|
|
1391
|
+
* against the mount fail with EROFS. Defaults to false.
|
|
1392
|
+
*/
|
|
1393
|
+
readOnly?: boolean;
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* One disk to mount in an exec request. Either a `Disk`/disk-id string
|
|
1397
|
+
* (mounts the disk's root, read-write) or an `ExecMountSpec` object that
|
|
1398
|
+
* additionally selects a subdirectoryectory of the disk and/or marks the mount
|
|
1399
|
+
* as read-only. Used by Archil#exec — the map key is the relative path
|
|
1400
|
+
* under /mnt/archil at which to mount the disk.
|
|
1401
|
+
*/
|
|
1402
|
+
type ExecMount = Disk | string | ExecMountSpec;
|
|
1403
|
+
interface ExecOptions {
|
|
1404
|
+
/**
|
|
1405
|
+
* Disks to mount, keyed by the relative path under `/mnt/archil` at which
|
|
1406
|
+
* to mount each one. At least one entry is required. Paths must be
|
|
1407
|
+
* non-empty, non-absolute, and contain no `.` or `..` segments.
|
|
1408
|
+
*/
|
|
1409
|
+
disks: Record<string, ExecMount>;
|
|
1410
|
+
/** Shell command to run inside the container. */
|
|
1411
|
+
command: string;
|
|
1412
|
+
}
|
|
1123
1413
|
declare class Archil {
|
|
1124
1414
|
readonly disks: Disks;
|
|
1125
1415
|
readonly tokens: Tokens;
|
|
1416
|
+
/** @internal */
|
|
1417
|
+
private readonly _client;
|
|
1126
1418
|
constructor(opts?: ArchilOptions);
|
|
1419
|
+
/**
|
|
1420
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
1421
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
1422
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
1423
|
+
*/
|
|
1424
|
+
exec(opts: ExecOptions): Promise<ExecDiskResult>;
|
|
1127
1425
|
}
|
|
1128
1426
|
|
|
1129
1427
|
declare class ArchilApiError extends Error {
|
|
@@ -1141,5 +1439,11 @@ declare function createApiKey(req: CreateApiTokenRequest): Promise<ApiTokenRespo
|
|
|
1141
1439
|
token?: string;
|
|
1142
1440
|
}>;
|
|
1143
1441
|
declare function deleteApiKey(id: string): Promise<void>;
|
|
1442
|
+
/**
|
|
1443
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
1444
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
1445
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
1446
|
+
*/
|
|
1447
|
+
declare function exec(opts: ExecOptions): Promise<ExecDiskResult>;
|
|
1144
1448
|
|
|
1145
|
-
export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, type CreateDiskResult, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type ExecResult, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens, configure, createApiKey, createDisk, deleteApiKey, getDisk, listApiKeys, listDisks };
|
|
1449
|
+
export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, type CreateDiskResult, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type ExecMount, type ExecMountSpec, type ExecOptions, type ExecRequest, type ExecResult, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens, configure, createApiKey, createDisk, deleteApiKey, exec, getDisk, listApiKeys, listDisks };
|
package/dist/index.js
CHANGED
|
@@ -93,6 +93,7 @@ var Disk = class {
|
|
|
93
93
|
metrics;
|
|
94
94
|
connectedClients;
|
|
95
95
|
authorizedUsers;
|
|
96
|
+
allowedIps;
|
|
96
97
|
/** @internal */
|
|
97
98
|
_client;
|
|
98
99
|
/** @internal */
|
|
@@ -114,6 +115,7 @@ var Disk = class {
|
|
|
114
115
|
this.metrics = data.metrics;
|
|
115
116
|
this.connectedClients = data.connectedClients;
|
|
116
117
|
this.authorizedUsers = data.authorizedUsers;
|
|
118
|
+
this.allowedIps = data.allowedIps;
|
|
117
119
|
this._client = client;
|
|
118
120
|
this._archilRegion = archilRegion;
|
|
119
121
|
}
|
|
@@ -133,7 +135,8 @@ var Disk = class {
|
|
|
133
135
|
mounts: this.mounts,
|
|
134
136
|
metrics: this.metrics,
|
|
135
137
|
connectedClients: this.connectedClients,
|
|
136
|
-
authorizedUsers: this.authorizedUsers
|
|
138
|
+
authorizedUsers: this.authorizedUsers,
|
|
139
|
+
allowedIps: this.allowedIps
|
|
137
140
|
};
|
|
138
141
|
}
|
|
139
142
|
async addUser(user) {
|
|
@@ -169,6 +172,32 @@ var Disk = class {
|
|
|
169
172
|
async removeTokenUser(identifier) {
|
|
170
173
|
await this.removeUser("token", identifier);
|
|
171
174
|
}
|
|
175
|
+
async getAllowedIPs() {
|
|
176
|
+
const data = await unwrap(
|
|
177
|
+
this._client.GET("/api/disks/{id}/allowed-ips", {
|
|
178
|
+
params: { path: { id: this.id } }
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
return data.allowedIps;
|
|
182
|
+
}
|
|
183
|
+
async setAllowedIPs(allowedIps) {
|
|
184
|
+
const data = await unwrap(
|
|
185
|
+
this._client.PUT("/api/disks/{id}/allowed-ips", {
|
|
186
|
+
params: { path: { id: this.id } },
|
|
187
|
+
body: { allowedIps }
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
return data.allowedIps;
|
|
191
|
+
}
|
|
192
|
+
async addAllowedIP(ip) {
|
|
193
|
+
const current = await this.getAllowedIPs();
|
|
194
|
+
if (current.includes(ip)) return current;
|
|
195
|
+
return this.setAllowedIPs([...current, ip]);
|
|
196
|
+
}
|
|
197
|
+
async removeAllowedIP(ip) {
|
|
198
|
+
const current = await this.getAllowedIPs();
|
|
199
|
+
return this.setAllowedIPs(current.filter((i) => i !== ip));
|
|
200
|
+
}
|
|
172
201
|
async delete() {
|
|
173
202
|
await unwrapEmpty(
|
|
174
203
|
this._client.DELETE("/api/disks/{id}", {
|
|
@@ -303,9 +332,17 @@ var Tokens = class {
|
|
|
303
332
|
};
|
|
304
333
|
|
|
305
334
|
// src/archil.ts
|
|
335
|
+
function isExecMountSpec(m) {
|
|
336
|
+
return typeof m === "object" && m !== null && "disk" in m;
|
|
337
|
+
}
|
|
338
|
+
function diskIdFromMount(m) {
|
|
339
|
+
return typeof m === "string" ? m : m.id;
|
|
340
|
+
}
|
|
306
341
|
var Archil = class {
|
|
307
342
|
disks;
|
|
308
343
|
tokens;
|
|
344
|
+
/** @internal */
|
|
345
|
+
_client;
|
|
309
346
|
constructor(opts = {}) {
|
|
310
347
|
const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
|
|
311
348
|
const region = opts.region ?? process.env.ARCHIL_REGION;
|
|
@@ -320,9 +357,35 @@ var Archil = class {
|
|
|
320
357
|
region,
|
|
321
358
|
baseUrl: opts.baseUrl
|
|
322
359
|
});
|
|
360
|
+
this._client = client;
|
|
323
361
|
this.disks = new Disks(client, region);
|
|
324
362
|
this.tokens = new Tokens(client);
|
|
325
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Run a command in a container with multiple disks mounted simultaneously,
|
|
366
|
+
* each at its own relative path under `/mnt/archil`. Blocks until the
|
|
367
|
+
* command completes and returns its stdout, stderr, exit code, and timing.
|
|
368
|
+
*/
|
|
369
|
+
async exec(opts) {
|
|
370
|
+
const disks = {};
|
|
371
|
+
for (const [relPath, mount] of Object.entries(opts.disks)) {
|
|
372
|
+
if (isExecMountSpec(mount)) {
|
|
373
|
+
const entry = {
|
|
374
|
+
disk: diskIdFromMount(mount.disk),
|
|
375
|
+
readOnly: mount.readOnly ?? false
|
|
376
|
+
};
|
|
377
|
+
if (mount.subdirectory !== void 0) entry.subdirectory = mount.subdirectory;
|
|
378
|
+
disks[relPath] = entry;
|
|
379
|
+
} else {
|
|
380
|
+
disks[relPath] = diskIdFromMount(mount);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return unwrap(
|
|
384
|
+
this._client.POST("/api/exec", {
|
|
385
|
+
body: { disks, command: opts.command }
|
|
386
|
+
})
|
|
387
|
+
);
|
|
388
|
+
}
|
|
326
389
|
};
|
|
327
390
|
|
|
328
391
|
// src/index.ts
|
|
@@ -356,6 +419,9 @@ function createApiKey(req) {
|
|
|
356
419
|
function deleteApiKey(id) {
|
|
357
420
|
return archil().tokens.delete(id);
|
|
358
421
|
}
|
|
422
|
+
function exec(opts) {
|
|
423
|
+
return archil().exec(opts);
|
|
424
|
+
}
|
|
359
425
|
export {
|
|
360
426
|
Archil,
|
|
361
427
|
ArchilApiError,
|
|
@@ -366,6 +432,7 @@ export {
|
|
|
366
432
|
createApiKey,
|
|
367
433
|
createDisk,
|
|
368
434
|
deleteApiKey,
|
|
435
|
+
exec,
|
|
369
436
|
getDisk,
|
|
370
437
|
listApiKeys,
|
|
371
438
|
listDisks
|