disk 0.8.0 → 0.8.9
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/{LICENSE.md → LICENSE} +10 -9
- package/README.md +111 -78
- package/dist/cli.js +592 -0
- package/dist/index.cjs +421 -0
- package/dist/index.d.cts +1145 -0
- package/dist/index.d.ts +1145 -0
- package/dist/index.js +372 -0
- package/package.json +39 -32
- package/lib/disk.js +0 -381
- package/lib/partition.js +0 -117
package/dist/index.js
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import createClient from "openapi-fetch";
|
|
3
|
+
|
|
4
|
+
// src/errors.ts
|
|
5
|
+
var ArchilApiError = class extends Error {
|
|
6
|
+
status;
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, status, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "ArchilApiError";
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/regions.ts
|
|
17
|
+
var REGION_URLS = {
|
|
18
|
+
"aws-us-east-1": "https://control.green.us-east-1.aws.prod.archil.com",
|
|
19
|
+
"aws-us-west-2": "https://control.green.us-west-2.aws.prod.archil.com",
|
|
20
|
+
"aws-eu-west-1": "https://control.green.eu-west-1.aws.prod.archil.com",
|
|
21
|
+
"gcp-us-central1": "https://control.blue.us-central1.gcp.prod.archil.com"
|
|
22
|
+
};
|
|
23
|
+
function resolveBaseUrl(region) {
|
|
24
|
+
const url = REGION_URLS[region];
|
|
25
|
+
if (!url) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Unknown region "${region}". Valid regions: ${Object.keys(REGION_URLS).join(", ")}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return url;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
function createApiClient(opts) {
|
|
35
|
+
const baseUrl = opts.baseUrl ?? resolveBaseUrl(opts.region);
|
|
36
|
+
return createClient({
|
|
37
|
+
baseUrl,
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `key-${opts.apiKey.replace(/^key-/, "")}`
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function unwrap(promise) {
|
|
44
|
+
const { data: body, error, response } = await promise;
|
|
45
|
+
if (error || !body) {
|
|
46
|
+
const errBody = error;
|
|
47
|
+
throw new ArchilApiError(
|
|
48
|
+
errBody?.error ?? `API request failed with status ${response.status}`,
|
|
49
|
+
response.status
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (!body.success) {
|
|
53
|
+
throw new ArchilApiError(
|
|
54
|
+
body.error ?? "Unknown API error",
|
|
55
|
+
response.status
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return body.data;
|
|
59
|
+
}
|
|
60
|
+
async function unwrapEmpty(promise) {
|
|
61
|
+
const { data: body, error, response } = await promise;
|
|
62
|
+
if (error || !body) {
|
|
63
|
+
const errBody = error;
|
|
64
|
+
throw new ArchilApiError(
|
|
65
|
+
errBody?.error ?? `API request failed with status ${response.status}`,
|
|
66
|
+
response.status
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (!body.success) {
|
|
70
|
+
throw new ArchilApiError(
|
|
71
|
+
body.error ?? "Unknown API error",
|
|
72
|
+
response.status
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/disk.ts
|
|
78
|
+
import { createRequire } from "module";
|
|
79
|
+
import { pathToFileURL } from "url";
|
|
80
|
+
var Disk = class {
|
|
81
|
+
id;
|
|
82
|
+
name;
|
|
83
|
+
organization;
|
|
84
|
+
status;
|
|
85
|
+
provider;
|
|
86
|
+
region;
|
|
87
|
+
createdAt;
|
|
88
|
+
fsHandlerStatus;
|
|
89
|
+
lastAccessed;
|
|
90
|
+
dataSize;
|
|
91
|
+
monthlyUsage;
|
|
92
|
+
mounts;
|
|
93
|
+
metrics;
|
|
94
|
+
connectedClients;
|
|
95
|
+
authorizedUsers;
|
|
96
|
+
/** @internal */
|
|
97
|
+
_client;
|
|
98
|
+
/** @internal */
|
|
99
|
+
_archilRegion;
|
|
100
|
+
/** @internal */
|
|
101
|
+
constructor(data, client, archilRegion) {
|
|
102
|
+
this.id = data.id;
|
|
103
|
+
this.name = data.name;
|
|
104
|
+
this.organization = data.organization;
|
|
105
|
+
this.status = data.status;
|
|
106
|
+
this.provider = data.provider;
|
|
107
|
+
this.region = data.region;
|
|
108
|
+
this.createdAt = data.createdAt;
|
|
109
|
+
this.fsHandlerStatus = data.fsHandlerStatus;
|
|
110
|
+
this.lastAccessed = data.lastAccessed;
|
|
111
|
+
this.dataSize = data.dataSize;
|
|
112
|
+
this.monthlyUsage = data.monthlyUsage;
|
|
113
|
+
this.mounts = data.mounts;
|
|
114
|
+
this.metrics = data.metrics;
|
|
115
|
+
this.connectedClients = data.connectedClients;
|
|
116
|
+
this.authorizedUsers = data.authorizedUsers;
|
|
117
|
+
this._client = client;
|
|
118
|
+
this._archilRegion = archilRegion;
|
|
119
|
+
}
|
|
120
|
+
toJSON() {
|
|
121
|
+
return {
|
|
122
|
+
id: this.id,
|
|
123
|
+
name: this.name,
|
|
124
|
+
organization: this.organization,
|
|
125
|
+
status: this.status,
|
|
126
|
+
provider: this.provider,
|
|
127
|
+
region: this.region,
|
|
128
|
+
createdAt: this.createdAt,
|
|
129
|
+
fsHandlerStatus: this.fsHandlerStatus,
|
|
130
|
+
lastAccessed: this.lastAccessed,
|
|
131
|
+
dataSize: this.dataSize,
|
|
132
|
+
monthlyUsage: this.monthlyUsage,
|
|
133
|
+
mounts: this.mounts,
|
|
134
|
+
metrics: this.metrics,
|
|
135
|
+
connectedClients: this.connectedClients,
|
|
136
|
+
authorizedUsers: this.authorizedUsers
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async addUser(user) {
|
|
140
|
+
return unwrap(
|
|
141
|
+
this._client.POST("/api/disks/{id}/users", {
|
|
142
|
+
params: { path: { id: this.id } },
|
|
143
|
+
body: user
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
async removeUser(userType, identifier) {
|
|
148
|
+
await unwrapEmpty(
|
|
149
|
+
this._client.DELETE("/api/disks/{id}/users/{userType}", {
|
|
150
|
+
params: {
|
|
151
|
+
path: { id: this.id, userType },
|
|
152
|
+
query: { identifier }
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
async createToken(nickname) {
|
|
158
|
+
const user = await unwrap(
|
|
159
|
+
this._client.POST("/api/disks/{id}/users", {
|
|
160
|
+
params: { path: { id: this.id } },
|
|
161
|
+
body: { type: "token", nickname }
|
|
162
|
+
})
|
|
163
|
+
);
|
|
164
|
+
if (!user.token || !user.identifier) {
|
|
165
|
+
throw new Error("Server did not return a generated token");
|
|
166
|
+
}
|
|
167
|
+
return user;
|
|
168
|
+
}
|
|
169
|
+
async removeTokenUser(identifier) {
|
|
170
|
+
await this.removeUser("token", identifier);
|
|
171
|
+
}
|
|
172
|
+
async delete() {
|
|
173
|
+
await unwrapEmpty(
|
|
174
|
+
this._client.DELETE("/api/disks/{id}", {
|
|
175
|
+
params: { path: { id: this.id } }
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Execute a command in a container with this disk mounted.
|
|
181
|
+
* Blocks until the command completes and returns stdout, stderr, and exit code.
|
|
182
|
+
*/
|
|
183
|
+
async exec(command) {
|
|
184
|
+
return unwrap(
|
|
185
|
+
this._client.POST("/api/disks/{id}/exec", {
|
|
186
|
+
params: { path: { id: this.id } },
|
|
187
|
+
body: { command }
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Connect to this disk's data plane via the native ArchilClient.
|
|
193
|
+
*
|
|
194
|
+
* Requires the native module to be available (platform-specific .node binary).
|
|
195
|
+
*/
|
|
196
|
+
async mount(opts) {
|
|
197
|
+
let ArchilClient;
|
|
198
|
+
try {
|
|
199
|
+
const base = typeof import.meta !== "undefined" && import.meta.url ? import.meta.url : pathToFileURL(__filename).href;
|
|
200
|
+
const nativeRequire = createRequire(base);
|
|
201
|
+
const native = nativeRequire("@archildata/native");
|
|
202
|
+
ArchilClient = native.ArchilClient;
|
|
203
|
+
} catch {
|
|
204
|
+
throw new Error(
|
|
205
|
+
"Native client not available. Install @archildata/native (platform-specific binary) or use ArchilClient.connect() directly."
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return ArchilClient.connect({
|
|
209
|
+
region: this._archilRegion,
|
|
210
|
+
diskName: `${this.organization}/${this.name}`,
|
|
211
|
+
authToken: opts?.authToken,
|
|
212
|
+
logLevel: opts?.logLevel,
|
|
213
|
+
serverAddress: opts?.serverAddress,
|
|
214
|
+
insecure: opts?.insecure
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// src/disks.ts
|
|
220
|
+
var Disks = class {
|
|
221
|
+
/** @internal */
|
|
222
|
+
_client;
|
|
223
|
+
/** @internal */
|
|
224
|
+
_region;
|
|
225
|
+
/** @internal */
|
|
226
|
+
constructor(client, region) {
|
|
227
|
+
this._client = client;
|
|
228
|
+
this._region = region;
|
|
229
|
+
}
|
|
230
|
+
async list(opts) {
|
|
231
|
+
const data = await unwrap(
|
|
232
|
+
this._client.GET("/api/disks", {
|
|
233
|
+
params: { query: { limit: opts?.limit, cursor: opts?.cursor, name: opts?.name } }
|
|
234
|
+
})
|
|
235
|
+
);
|
|
236
|
+
return data.map(
|
|
237
|
+
(d) => new Disk(d, this._client, this._region)
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
async get(id) {
|
|
241
|
+
const data = await unwrap(
|
|
242
|
+
this._client.GET("/api/disks/{id}", {
|
|
243
|
+
params: { path: { id } }
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
return new Disk(data, this._client, this._region);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Create a new disk with an auto-generated mount token.
|
|
250
|
+
*
|
|
251
|
+
* Returns the Disk, the one-time token (save it — it cannot be retrieved
|
|
252
|
+
* again), and the token identifier for later management.
|
|
253
|
+
*/
|
|
254
|
+
async create(req) {
|
|
255
|
+
const created = await unwrap(
|
|
256
|
+
this._client.POST("/api/disks", { body: req })
|
|
257
|
+
);
|
|
258
|
+
const resp = created;
|
|
259
|
+
if (!resp.diskId) {
|
|
260
|
+
throw new Error("API returned success but no diskId");
|
|
261
|
+
}
|
|
262
|
+
const authorizedUsers = resp.authorizedUsers ?? [];
|
|
263
|
+
const tokenUser = authorizedUsers.find((u) => u.token);
|
|
264
|
+
const disk = await this.get(resp.diskId);
|
|
265
|
+
return {
|
|
266
|
+
disk,
|
|
267
|
+
token: tokenUser?.token ?? null,
|
|
268
|
+
tokenIdentifier: tokenUser?.identifier ?? null,
|
|
269
|
+
authorizedUsers
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// src/tokens.ts
|
|
275
|
+
var Tokens = class {
|
|
276
|
+
/** @internal */
|
|
277
|
+
_client;
|
|
278
|
+
/** @internal */
|
|
279
|
+
constructor(client) {
|
|
280
|
+
this._client = client;
|
|
281
|
+
}
|
|
282
|
+
async list(opts) {
|
|
283
|
+
const data = await unwrap(
|
|
284
|
+
this._client.GET("/api/tokens", {
|
|
285
|
+
params: { query: { limit: opts?.limit, cursor: opts?.cursor } }
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
return data.tokens ?? [];
|
|
289
|
+
}
|
|
290
|
+
async create(req) {
|
|
291
|
+
const data = await unwrap(
|
|
292
|
+
this._client.POST("/api/tokens", { body: req })
|
|
293
|
+
);
|
|
294
|
+
return data;
|
|
295
|
+
}
|
|
296
|
+
async delete(id) {
|
|
297
|
+
await unwrapEmpty(
|
|
298
|
+
this._client.DELETE("/api/tokens/{id}", {
|
|
299
|
+
params: { path: { id } }
|
|
300
|
+
})
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/archil.ts
|
|
306
|
+
var Archil = class {
|
|
307
|
+
disks;
|
|
308
|
+
tokens;
|
|
309
|
+
constructor(opts = {}) {
|
|
310
|
+
const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
|
|
311
|
+
const region = opts.region ?? process.env.ARCHIL_REGION;
|
|
312
|
+
if (!apiKey) {
|
|
313
|
+
throw new Error("Missing API key: pass apiKey in options or set ARCHIL_API_KEY environment variable");
|
|
314
|
+
}
|
|
315
|
+
if (!region) {
|
|
316
|
+
throw new Error("Missing region: pass region in options or set ARCHIL_REGION environment variable");
|
|
317
|
+
}
|
|
318
|
+
const client = createApiClient({
|
|
319
|
+
apiKey,
|
|
320
|
+
region,
|
|
321
|
+
baseUrl: opts.baseUrl
|
|
322
|
+
});
|
|
323
|
+
this.disks = new Disks(client, region);
|
|
324
|
+
this.tokens = new Tokens(client);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// src/index.ts
|
|
329
|
+
var _options;
|
|
330
|
+
var _instance;
|
|
331
|
+
function configure(options) {
|
|
332
|
+
_options = options;
|
|
333
|
+
_instance = void 0;
|
|
334
|
+
}
|
|
335
|
+
function archil() {
|
|
336
|
+
if (!_instance) {
|
|
337
|
+
_instance = new Archil(_options);
|
|
338
|
+
}
|
|
339
|
+
return _instance;
|
|
340
|
+
}
|
|
341
|
+
function createDisk(req) {
|
|
342
|
+
return archil().disks.create(req);
|
|
343
|
+
}
|
|
344
|
+
function listDisks(opts) {
|
|
345
|
+
return archil().disks.list(opts);
|
|
346
|
+
}
|
|
347
|
+
function getDisk(id) {
|
|
348
|
+
return archil().disks.get(id);
|
|
349
|
+
}
|
|
350
|
+
function listApiKeys(opts) {
|
|
351
|
+
return archil().tokens.list(opts);
|
|
352
|
+
}
|
|
353
|
+
function createApiKey(req) {
|
|
354
|
+
return archil().tokens.create(req);
|
|
355
|
+
}
|
|
356
|
+
function deleteApiKey(id) {
|
|
357
|
+
return archil().tokens.delete(id);
|
|
358
|
+
}
|
|
359
|
+
export {
|
|
360
|
+
Archil,
|
|
361
|
+
ArchilApiError,
|
|
362
|
+
Disk,
|
|
363
|
+
Disks,
|
|
364
|
+
Tokens,
|
|
365
|
+
configure,
|
|
366
|
+
createApiKey,
|
|
367
|
+
createDisk,
|
|
368
|
+
deleteApiKey,
|
|
369
|
+
getDisk,
|
|
370
|
+
listApiKeys,
|
|
371
|
+
listDisks
|
|
372
|
+
};
|
package/package.json
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "disk",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
"version": "0.8.9",
|
|
4
|
+
"description": "Pure-JS client and CLI for Archil disks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"disk": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
20
23
|
],
|
|
21
|
-
"main": "lib/disk",
|
|
22
24
|
"scripts": {
|
|
23
|
-
"
|
|
25
|
+
"generate": "openapi-typescript ../../api/controlplane/openapi.yaml -o src/generated/openapi.d.ts",
|
|
26
|
+
"build": "npm run generate && tsup src/index.ts --format cjs,esm --dts && tsup bin/cli.ts --format esm --outDir dist --no-splitting",
|
|
27
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
28
|
+
"typecheck": "npm run generate && tsc --noEmit"
|
|
24
29
|
},
|
|
25
30
|
"dependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"mbr": "^1.1.2"
|
|
31
|
+
"commander": "^14.0.3",
|
|
32
|
+
"openapi-fetch": "^0.13.5"
|
|
29
33
|
},
|
|
30
34
|
"devDependencies": {
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
35
|
+
"@types/node": "^20.19.33",
|
|
36
|
+
"openapi-typescript": "^7.6.1",
|
|
37
|
+
"tsup": "^8.4.0",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
34
39
|
},
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/jhermsmeier/node-disk.git"
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">= 18"
|
|
39
42
|
},
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
+
"keywords": [
|
|
44
|
+
"archil",
|
|
45
|
+
"disk",
|
|
46
|
+
"filesystem",
|
|
47
|
+
"cli"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT"
|
|
43
50
|
}
|