@archildata/client 0.8.6 → 0.8.7

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 CHANGED
@@ -20,7 +20,7 @@ npm install @archildata/client
20
20
 
21
21
  An Archil "disk" is a filesystem that sits in front of your cloud storage. You create one by telling Archil which bucket to use. This doesn't move or copy your data — Archil reads and writes directly to your bucket.
22
22
 
23
- You also need to authorize a mount token on the disk. This is a separate credential from your API key it's what clients use to connect to the disk's data plane. Pick any string as the principal (it's just an identifier).
23
+ A mount token is automatically generated when you create a disk; it is recommended to save it.
24
24
 
25
25
  ```typescript
26
26
  import { Archil } from '@archildata/client/api';
@@ -30,25 +30,19 @@ const archil = new Archil({
30
30
  region: 'aws-us-east-1',
31
31
  });
32
32
 
33
- const MOUNT_TOKEN = 'my-secret-mount-token';
34
-
35
- const disk = await archil.disks.create({
33
+ const { disk, token } = await archil.disks.create({
36
34
  name: 'my-disk',
37
35
  mounts: [{
38
36
  type: 's3',
39
37
  bucketName: 'my-bucket',
40
38
  accessKeyId: 'AKIA...',
41
39
  secretAccessKey: '...',
42
- }],
43
- authMethods: [{
44
- type: 'token',
45
- principal: MOUNT_TOKEN,
46
- nickname: 'my-mount-token',
47
- tokenSuffix: MOUNT_TOKEN.slice(-4),
40
+ bucketPrefix: 'data/', // optional — only expose a subfolder of the bucket
48
41
  }],
49
42
  });
50
43
 
51
44
  console.log(`Created disk: ${disk.organization}/${disk.name}`);
45
+ console.log(`Mount token: ${token}`); // save this — it won't be shown again
52
46
  ```
53
47
 
54
48
  You only do this once. After that, the disk is available by name whenever you want to connect.
@@ -61,10 +55,10 @@ Install `@archildata/just-bash` to get a shell that runs against your disk:
61
55
  npm install @archildata/just-bash
62
56
  ```
63
57
 
64
- Then connect using the mount token you authorized above:
58
+ Then connect using the mount token from step 3:
65
59
 
66
60
  ```bash
67
- ARCHIL_TOKEN=my-secret-mount-token npx @archildata/just-bash aws-us-east-1 myaccount/my-disk
61
+ ARCHIL_DISK_TOKEN=<your-mount-token> npx @archildata/just-bash aws-us-east-1 myaccount/my-disk
68
62
  ```
69
63
 
70
64
  This drops you into an interactive shell. The files you see are the contents of your S3 bucket:
@@ -94,7 +88,7 @@ import { Bash } from 'just-bash';
94
88
  const client = await ArchilClient.connect({
95
89
  region: 'aws-us-east-1',
96
90
  diskName: 'myaccount/my-disk',
97
- authToken: 'my-secret-mount-token',
91
+ authToken: '<your-mount-token>',
98
92
  });
99
93
 
100
94
  // Create a filesystem adapter and a bash executor
@@ -146,7 +140,7 @@ import { ArchilClient } from '@archildata/client';
146
140
  const client = await ArchilClient.connect({
147
141
  region: 'aws-us-east-1',
148
142
  diskName: 'myaccount/my-disk',
149
- authToken: 'my-secret-mount-token',
143
+ authToken: '<your-mount-token>',
150
144
  });
151
145
  ```
152
146
 
@@ -254,17 +248,13 @@ const disks = await archil.disks.list();
254
248
  // Get a specific disk by ID
255
249
  const disk = await archil.disks.get('dsk-xxx');
256
250
 
257
- // Authorize another mount token on an existing disk
258
- const CI_TOKEN = 'ci-mount-token';
259
- await disk.addUser({
260
- type: 'token',
261
- principal: CI_TOKEN,
262
- nickname: 'ci-token',
263
- tokenSuffix: CI_TOKEN.slice(-4),
264
- });
251
+ // Add an additional mount token to an existing disk
252
+ const { token, identifier } = await disk.createToken('ci-token');
253
+ // save `token` — it's only returned once
254
+ // use `identifier` to manage or remove the token later
265
255
 
266
256
  // Remove access
267
- await disk.removeUser('token', CI_TOKEN);
257
+ await disk.removeTokenUser(identifier);
268
258
 
269
259
  // Delete a disk (this does not delete your bucket data)
270
260
  await disk.delete();
Binary file
@@ -21,8 +21,13 @@ interface paths {
21
21
  put?: never;
22
22
  /**
23
23
  * Create a new disk
24
- * @description Creates a new disk with the specified configuration. The disk will be
25
- * provisioned in the specified region with the given mounts and authentication methods.
24
+ * @description Creates a new disk with the specified configuration. A default token
25
+ * user is automatically generated and returned in the response, so the
26
+ * disk is immediately mountable. The one-time token appears in
27
+ * `authorizedUsers[].token` and cannot be retrieved again.
28
+ *
29
+ * To provide your own users instead, pass the deprecated `authMethods`
30
+ * field or call AddDiskUser after creation.
26
31
  */
27
32
  post: operations["createDisk"];
28
33
  delete?: never;
@@ -170,7 +175,10 @@ interface components {
170
175
  name: string;
171
176
  /** @description Storage mount to attach. Omit for archil-managed storage. */
172
177
  mounts?: components["schemas"]["MountConfig"][];
173
- /** @description Authentication methods for disk access */
178
+ /**
179
+ * @deprecated
180
+ * @description Deprecated. Use AddDiskUser after creation instead. When provided, suppresses the default auto-generated token user.
181
+ */
174
182
  authMethods?: components["schemas"]["DiskUser"][];
175
183
  };
176
184
  MountConfig: components["schemas"]["S3Mount"] | components["schemas"]["GCSMount"] | components["schemas"]["R2Mount"] | components["schemas"]["S3CompatibleMount"] | components["schemas"]["AzureBlobMount"];
@@ -344,9 +352,17 @@ interface components {
344
352
  * @enum {string}
345
353
  */
346
354
  type: "token";
347
- principal: string;
355
+ /**
356
+ * @deprecated
357
+ * @description Deprecated. Client-provided token. If omitted, the server generates a cryptographically secure token and returns it in the response.
358
+ */
359
+ principal?: string;
348
360
  nickname: string;
349
- tokenSuffix: string;
361
+ /**
362
+ * @deprecated
363
+ * @description Deprecated. Last 4 characters of the token. Required when principal is provided; ignored when the server generates the token.
364
+ */
365
+ tokenSuffix?: string;
350
366
  };
351
367
  AwsStsUser: {
352
368
  /**
@@ -461,10 +477,17 @@ interface components {
461
477
  AuthorizedUser: {
462
478
  /** @enum {string} */
463
479
  type?: "token" | "awssts";
464
- /** @description The user's principal identifier. Only populated for awssts type (the IAM ARN). Omitted for token type users to avoid exposing sensitive hashes. */
480
+ /**
481
+ * @deprecated
482
+ * @description Use identifier instead. Only populated for awssts type (the IAM ARN).
483
+ */
465
484
  principal?: string;
466
485
  nickname?: string;
467
486
  tokenSuffix?: string;
487
+ /** @description The generated mount token. Only present in the response when the server generates the token (i.e. principal was not provided). This value is shown exactly once and cannot be retrieved again. */
488
+ token?: string;
489
+ /** @description Stable identifier for this user, returned in creation and list responses. Use this value with DELETE /api/disks/{id}/users/{type}?identifier={identifier} to remove the user. For awssts users, this is the IAM ARN. */
490
+ identifier?: string;
468
491
  /** Format: date-time */
469
492
  createdAt?: string;
470
493
  };
@@ -485,6 +508,7 @@ interface components {
485
508
  data: {
486
509
  /** @example dsk-0123456789abcdef */
487
510
  diskId?: string;
511
+ authorizedUsers?: components["schemas"]["AuthorizedUser"][];
488
512
  };
489
513
  };
490
514
  ApiResponse_AuthorizedUser: {
@@ -749,9 +773,14 @@ interface operations {
749
773
  };
750
774
  removeDiskUser: {
751
775
  parameters: {
752
- query: {
753
- /** @description The user's principal identifier. For token type, this is the MD5 hash (hex-encoded) of the token principal. For awssts type, this is the full IAM ARN (e.g., arn:aws:iam::123456789012:role/MyRole). */
754
- principal: string;
776
+ query?: {
777
+ /** @description Identifier of the user to remove, as returned in the creation or list response. For awssts users, this is the IAM ARN. */
778
+ identifier?: string;
779
+ /**
780
+ * @deprecated
781
+ * @description Use identifier instead.
782
+ */
783
+ principal?: string;
755
784
  };
756
785
  header?: never;
757
786
  path: {
@@ -911,7 +940,12 @@ declare class Disk {
911
940
  /** @internal */
912
941
  constructor(data: DiskResponse, client: ApiClient, archilRegion: string);
913
942
  addUser(user: DiskUser): Promise<AuthorizedUser>;
914
- removeUser(userType: "token" | "awssts", principal: string): Promise<void>;
943
+ removeUser(userType: "token" | "awssts", identifier: string): Promise<void>;
944
+ createToken(nickname: string): Promise<AuthorizedUser & {
945
+ token: string;
946
+ identifier: string;
947
+ }>;
948
+ removeTokenUser(identifier: string): Promise<void>;
915
949
  delete(): Promise<void>;
916
950
  /**
917
951
  * Connect to this disk's data plane via the native ArchilClient.
@@ -925,6 +959,12 @@ interface ListDisksOptions {
925
959
  limit?: number;
926
960
  cursor?: string;
927
961
  }
962
+ interface CreateDiskResult {
963
+ disk: Disk;
964
+ token: string | null;
965
+ tokenIdentifier: string | null;
966
+ authorizedUsers: AuthorizedUser[];
967
+ }
928
968
  declare class Disks {
929
969
  /** @internal */
930
970
  private readonly _client;
@@ -935,11 +975,12 @@ declare class Disks {
935
975
  list(opts?: ListDisksOptions): Promise<Disk[]>;
936
976
  get(id: string): Promise<Disk>;
937
977
  /**
938
- * Create a new disk and return a Disk object with full details.
978
+ * Create a new disk with an auto-generated mount token.
939
979
  *
940
- * Internally calls POST /api/disks (returns diskId) then GET /api/disks/{id}.
980
+ * Returns the Disk, the one-time token (save it it cannot be retrieved
981
+ * again), and the token identifier for later management.
941
982
  */
942
- create(req: CreateDiskRequest): Promise<Disk>;
983
+ create(req: CreateDiskRequest): Promise<CreateDiskResult>;
943
984
  }
944
985
 
945
986
  interface ListTokensOptions {
@@ -959,15 +1000,17 @@ declare class Tokens {
959
1000
  }
960
1001
 
961
1002
  interface ArchilOptions {
962
- apiKey: string;
963
- region: string;
1003
+ /** API key. Falls back to ARCHIL_API_KEY env var if not provided. */
1004
+ apiKey?: string;
1005
+ /** Region. Falls back to ARCHIL_REGION env var if not provided. */
1006
+ region?: string;
964
1007
  /** Override the control plane base URL (useful for testing). */
965
1008
  baseUrl?: string;
966
1009
  }
967
1010
  declare class Archil {
968
1011
  readonly disks: Disks;
969
1012
  readonly tokens: Tokens;
970
- constructor(opts: ArchilOptions);
1013
+ constructor(opts?: ArchilOptions);
971
1014
  }
972
1015
 
973
1016
  declare class ArchilApiError extends Error {
@@ -976,4 +1019,4 @@ declare class ArchilApiError extends Error {
976
1019
  constructor(message: string, status: number, code?: string);
977
1020
  }
978
1021
 
979
- export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens };
1022
+ 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 GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens };
@@ -21,8 +21,13 @@ interface paths {
21
21
  put?: never;
22
22
  /**
23
23
  * Create a new disk
24
- * @description Creates a new disk with the specified configuration. The disk will be
25
- * provisioned in the specified region with the given mounts and authentication methods.
24
+ * @description Creates a new disk with the specified configuration. A default token
25
+ * user is automatically generated and returned in the response, so the
26
+ * disk is immediately mountable. The one-time token appears in
27
+ * `authorizedUsers[].token` and cannot be retrieved again.
28
+ *
29
+ * To provide your own users instead, pass the deprecated `authMethods`
30
+ * field or call AddDiskUser after creation.
26
31
  */
27
32
  post: operations["createDisk"];
28
33
  delete?: never;
@@ -170,7 +175,10 @@ interface components {
170
175
  name: string;
171
176
  /** @description Storage mount to attach. Omit for archil-managed storage. */
172
177
  mounts?: components["schemas"]["MountConfig"][];
173
- /** @description Authentication methods for disk access */
178
+ /**
179
+ * @deprecated
180
+ * @description Deprecated. Use AddDiskUser after creation instead. When provided, suppresses the default auto-generated token user.
181
+ */
174
182
  authMethods?: components["schemas"]["DiskUser"][];
175
183
  };
176
184
  MountConfig: components["schemas"]["S3Mount"] | components["schemas"]["GCSMount"] | components["schemas"]["R2Mount"] | components["schemas"]["S3CompatibleMount"] | components["schemas"]["AzureBlobMount"];
@@ -344,9 +352,17 @@ interface components {
344
352
  * @enum {string}
345
353
  */
346
354
  type: "token";
347
- principal: string;
355
+ /**
356
+ * @deprecated
357
+ * @description Deprecated. Client-provided token. If omitted, the server generates a cryptographically secure token and returns it in the response.
358
+ */
359
+ principal?: string;
348
360
  nickname: string;
349
- tokenSuffix: string;
361
+ /**
362
+ * @deprecated
363
+ * @description Deprecated. Last 4 characters of the token. Required when principal is provided; ignored when the server generates the token.
364
+ */
365
+ tokenSuffix?: string;
350
366
  };
351
367
  AwsStsUser: {
352
368
  /**
@@ -461,10 +477,17 @@ interface components {
461
477
  AuthorizedUser: {
462
478
  /** @enum {string} */
463
479
  type?: "token" | "awssts";
464
- /** @description The user's principal identifier. Only populated for awssts type (the IAM ARN). Omitted for token type users to avoid exposing sensitive hashes. */
480
+ /**
481
+ * @deprecated
482
+ * @description Use identifier instead. Only populated for awssts type (the IAM ARN).
483
+ */
465
484
  principal?: string;
466
485
  nickname?: string;
467
486
  tokenSuffix?: string;
487
+ /** @description The generated mount token. Only present in the response when the server generates the token (i.e. principal was not provided). This value is shown exactly once and cannot be retrieved again. */
488
+ token?: string;
489
+ /** @description Stable identifier for this user, returned in creation and list responses. Use this value with DELETE /api/disks/{id}/users/{type}?identifier={identifier} to remove the user. For awssts users, this is the IAM ARN. */
490
+ identifier?: string;
468
491
  /** Format: date-time */
469
492
  createdAt?: string;
470
493
  };
@@ -485,6 +508,7 @@ interface components {
485
508
  data: {
486
509
  /** @example dsk-0123456789abcdef */
487
510
  diskId?: string;
511
+ authorizedUsers?: components["schemas"]["AuthorizedUser"][];
488
512
  };
489
513
  };
490
514
  ApiResponse_AuthorizedUser: {
@@ -749,9 +773,14 @@ interface operations {
749
773
  };
750
774
  removeDiskUser: {
751
775
  parameters: {
752
- query: {
753
- /** @description The user's principal identifier. For token type, this is the MD5 hash (hex-encoded) of the token principal. For awssts type, this is the full IAM ARN (e.g., arn:aws:iam::123456789012:role/MyRole). */
754
- principal: string;
776
+ query?: {
777
+ /** @description Identifier of the user to remove, as returned in the creation or list response. For awssts users, this is the IAM ARN. */
778
+ identifier?: string;
779
+ /**
780
+ * @deprecated
781
+ * @description Use identifier instead.
782
+ */
783
+ principal?: string;
755
784
  };
756
785
  header?: never;
757
786
  path: {
@@ -911,7 +940,12 @@ declare class Disk {
911
940
  /** @internal */
912
941
  constructor(data: DiskResponse, client: ApiClient, archilRegion: string);
913
942
  addUser(user: DiskUser): Promise<AuthorizedUser>;
914
- removeUser(userType: "token" | "awssts", principal: string): Promise<void>;
943
+ removeUser(userType: "token" | "awssts", identifier: string): Promise<void>;
944
+ createToken(nickname: string): Promise<AuthorizedUser & {
945
+ token: string;
946
+ identifier: string;
947
+ }>;
948
+ removeTokenUser(identifier: string): Promise<void>;
915
949
  delete(): Promise<void>;
916
950
  /**
917
951
  * Connect to this disk's data plane via the native ArchilClient.
@@ -925,6 +959,12 @@ interface ListDisksOptions {
925
959
  limit?: number;
926
960
  cursor?: string;
927
961
  }
962
+ interface CreateDiskResult {
963
+ disk: Disk;
964
+ token: string | null;
965
+ tokenIdentifier: string | null;
966
+ authorizedUsers: AuthorizedUser[];
967
+ }
928
968
  declare class Disks {
929
969
  /** @internal */
930
970
  private readonly _client;
@@ -935,11 +975,12 @@ declare class Disks {
935
975
  list(opts?: ListDisksOptions): Promise<Disk[]>;
936
976
  get(id: string): Promise<Disk>;
937
977
  /**
938
- * Create a new disk and return a Disk object with full details.
978
+ * Create a new disk with an auto-generated mount token.
939
979
  *
940
- * Internally calls POST /api/disks (returns diskId) then GET /api/disks/{id}.
980
+ * Returns the Disk, the one-time token (save it it cannot be retrieved
981
+ * again), and the token identifier for later management.
941
982
  */
942
- create(req: CreateDiskRequest): Promise<Disk>;
983
+ create(req: CreateDiskRequest): Promise<CreateDiskResult>;
943
984
  }
944
985
 
945
986
  interface ListTokensOptions {
@@ -959,15 +1000,17 @@ declare class Tokens {
959
1000
  }
960
1001
 
961
1002
  interface ArchilOptions {
962
- apiKey: string;
963
- region: string;
1003
+ /** API key. Falls back to ARCHIL_API_KEY env var if not provided. */
1004
+ apiKey?: string;
1005
+ /** Region. Falls back to ARCHIL_REGION env var if not provided. */
1006
+ region?: string;
964
1007
  /** Override the control plane base URL (useful for testing). */
965
1008
  baseUrl?: string;
966
1009
  }
967
1010
  declare class Archil {
968
1011
  readonly disks: Disks;
969
1012
  readonly tokens: Tokens;
970
- constructor(opts: ArchilOptions);
1013
+ constructor(opts?: ArchilOptions);
971
1014
  }
972
1015
 
973
1016
  declare class ArchilApiError extends Error {
@@ -976,4 +1019,4 @@ declare class ArchilApiError extends Error {
976
1019
  constructor(message: string, status: number, code?: string);
977
1020
  }
978
1021
 
979
- export { type ApiTokenResponse, Archil, ArchilApiError, type ArchilOptions, type AuthorizedUser, type AwsStsUser, type AzureBlobMount, type ConnectedClient, type CreateApiTokenRequest, type CreateDiskRequest, Disk, type DiskMetrics, type DiskResponse, type DiskStatus, type DiskUser, Disks, type GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens };
1022
+ 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 GCSMount, type ListDisksOptions, type ListTokensOptions, type MountConfig, type MountConfigResponse, type MountOptions, type MountResponse, type R2Mount, type S3CompatibleMount, type S3Mount, type TokenUser, Tokens };
package/dist/api/index.js CHANGED
@@ -76,7 +76,7 @@ function createApiClient(opts) {
76
76
  return (0, import_openapi_fetch.default)({
77
77
  baseUrl,
78
78
  headers: {
79
- Authorization: `key-${opts.apiKey}`
79
+ Authorization: `key-${opts.apiKey.replace(/^key-/, "")}`
80
80
  }
81
81
  });
82
82
  }
@@ -166,16 +166,31 @@ var Disk = class {
166
166
  })
167
167
  );
168
168
  }
169
- async removeUser(userType, principal) {
169
+ async removeUser(userType, identifier) {
170
170
  await unwrapEmpty(
171
171
  this._client.DELETE("/api/disks/{id}/users/{userType}", {
172
172
  params: {
173
173
  path: { id: this.id, userType },
174
- query: { principal }
174
+ query: { identifier }
175
175
  }
176
176
  })
177
177
  );
178
178
  }
179
+ async createToken(nickname) {
180
+ const user = await unwrap(
181
+ this._client.POST("/api/disks/{id}/users", {
182
+ params: { path: { id: this.id } },
183
+ body: { type: "token", nickname }
184
+ })
185
+ );
186
+ if (!user.token || !user.identifier) {
187
+ throw new Error("Server did not return a generated token");
188
+ }
189
+ return user;
190
+ }
191
+ async removeTokenUser(identifier) {
192
+ await this.removeUser("token", identifier);
193
+ }
179
194
  async delete() {
180
195
  await unwrapEmpty(
181
196
  this._client.DELETE("/api/disks/{id}", {
@@ -241,19 +256,28 @@ var Disks = class {
241
256
  return new Disk(data, this._client, this._region);
242
257
  }
243
258
  /**
244
- * Create a new disk and return a Disk object with full details.
259
+ * Create a new disk with an auto-generated mount token.
245
260
  *
246
- * Internally calls POST /api/disks (returns diskId) then GET /api/disks/{id}.
261
+ * Returns the Disk, the one-time token (save it it cannot be retrieved
262
+ * again), and the token identifier for later management.
247
263
  */
248
264
  async create(req) {
249
265
  const created = await unwrap(
250
266
  this._client.POST("/api/disks", { body: req })
251
267
  );
252
- const diskId = created.diskId;
253
- if (!diskId) {
268
+ const resp = created;
269
+ if (!resp.diskId) {
254
270
  throw new Error("API returned success but no diskId");
255
271
  }
256
- return this.get(diskId);
272
+ const authorizedUsers = resp.authorizedUsers ?? [];
273
+ const tokenUser = authorizedUsers.find((u) => u.token);
274
+ const disk = await this.get(resp.diskId);
275
+ return {
276
+ disk,
277
+ token: tokenUser?.token ?? null,
278
+ tokenIdentifier: tokenUser?.identifier ?? null,
279
+ authorizedUsers
280
+ };
257
281
  }
258
282
  };
259
283
 
@@ -292,13 +316,21 @@ var Tokens = class {
292
316
  var Archil = class {
293
317
  disks;
294
318
  tokens;
295
- constructor(opts) {
319
+ constructor(opts = {}) {
320
+ const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
321
+ const region = opts.region ?? process.env.ARCHIL_REGION;
322
+ if (!apiKey) {
323
+ throw new Error("Missing API key: pass apiKey in options or set ARCHIL_API_KEY environment variable");
324
+ }
325
+ if (!region) {
326
+ throw new Error("Missing region: pass region in options or set ARCHIL_REGION environment variable");
327
+ }
296
328
  const client = createApiClient({
297
- apiKey: opts.apiKey,
298
- region: opts.region,
329
+ apiKey,
330
+ region,
299
331
  baseUrl: opts.baseUrl
300
332
  });
301
- this.disks = new Disks(client, opts.region);
333
+ this.disks = new Disks(client, region);
302
334
  this.tokens = new Tokens(client);
303
335
  }
304
336
  };
@@ -36,7 +36,7 @@ function createApiClient(opts) {
36
36
  return createClient({
37
37
  baseUrl,
38
38
  headers: {
39
- Authorization: `key-${opts.apiKey}`
39
+ Authorization: `key-${opts.apiKey.replace(/^key-/, "")}`
40
40
  }
41
41
  });
42
42
  }
@@ -125,16 +125,31 @@ var Disk = class {
125
125
  })
126
126
  );
127
127
  }
128
- async removeUser(userType, principal) {
128
+ async removeUser(userType, identifier) {
129
129
  await unwrapEmpty(
130
130
  this._client.DELETE("/api/disks/{id}/users/{userType}", {
131
131
  params: {
132
132
  path: { id: this.id, userType },
133
- query: { principal }
133
+ query: { identifier }
134
134
  }
135
135
  })
136
136
  );
137
137
  }
138
+ async createToken(nickname) {
139
+ const user = await unwrap(
140
+ this._client.POST("/api/disks/{id}/users", {
141
+ params: { path: { id: this.id } },
142
+ body: { type: "token", nickname }
143
+ })
144
+ );
145
+ if (!user.token || !user.identifier) {
146
+ throw new Error("Server did not return a generated token");
147
+ }
148
+ return user;
149
+ }
150
+ async removeTokenUser(identifier) {
151
+ await this.removeUser("token", identifier);
152
+ }
138
153
  async delete() {
139
154
  await unwrapEmpty(
140
155
  this._client.DELETE("/api/disks/{id}", {
@@ -200,19 +215,28 @@ var Disks = class {
200
215
  return new Disk(data, this._client, this._region);
201
216
  }
202
217
  /**
203
- * Create a new disk and return a Disk object with full details.
218
+ * Create a new disk with an auto-generated mount token.
204
219
  *
205
- * Internally calls POST /api/disks (returns diskId) then GET /api/disks/{id}.
220
+ * Returns the Disk, the one-time token (save it it cannot be retrieved
221
+ * again), and the token identifier for later management.
206
222
  */
207
223
  async create(req) {
208
224
  const created = await unwrap(
209
225
  this._client.POST("/api/disks", { body: req })
210
226
  );
211
- const diskId = created.diskId;
212
- if (!diskId) {
227
+ const resp = created;
228
+ if (!resp.diskId) {
213
229
  throw new Error("API returned success but no diskId");
214
230
  }
215
- return this.get(diskId);
231
+ const authorizedUsers = resp.authorizedUsers ?? [];
232
+ const tokenUser = authorizedUsers.find((u) => u.token);
233
+ const disk = await this.get(resp.diskId);
234
+ return {
235
+ disk,
236
+ token: tokenUser?.token ?? null,
237
+ tokenIdentifier: tokenUser?.identifier ?? null,
238
+ authorizedUsers
239
+ };
216
240
  }
217
241
  };
218
242
 
@@ -251,13 +275,21 @@ var Tokens = class {
251
275
  var Archil = class {
252
276
  disks;
253
277
  tokens;
254
- constructor(opts) {
278
+ constructor(opts = {}) {
279
+ const apiKey = opts.apiKey ?? process.env.ARCHIL_API_KEY;
280
+ const region = opts.region ?? process.env.ARCHIL_REGION;
281
+ if (!apiKey) {
282
+ throw new Error("Missing API key: pass apiKey in options or set ARCHIL_API_KEY environment variable");
283
+ }
284
+ if (!region) {
285
+ throw new Error("Missing region: pass region in options or set ARCHIL_REGION environment variable");
286
+ }
255
287
  const client = createApiClient({
256
- apiKey: opts.apiKey,
257
- region: opts.region,
288
+ apiKey,
289
+ region,
258
290
  baseUrl: opts.baseUrl
259
291
  });
260
- this.disks = new Disks(client, opts.region);
292
+ this.disks = new Disks(client, region);
261
293
  this.tokens = new Tokens(client);
262
294
  }
263
295
  };
package/main.mjs CHANGED
@@ -15,3 +15,4 @@ try {
15
15
  export const ArchilClient = native.ArchilClient;
16
16
  export const initLogging = native.initLogging;
17
17
  export const JsInodeType = native.JsInodeType;
18
+ export const MAXIMUM_READ_SIZE = native.MAXIMUM_READ_SIZE;
package/native.d.ts CHANGED
@@ -3,6 +3,11 @@
3
3
 
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
+ /**
7
+ * Maximum size (in bytes) of a single read request.
8
+ * Matches MAXIMUM_READ_SIZE in the Rust protocol layer (rust-common/src/network/mod.rs).
9
+ */
10
+ export declare const MAXIMUM_READ_SIZE: number
6
11
  /**
7
12
  * Initialize the Rust logger to output to stderr.
8
13
  *
package/native.js CHANGED
@@ -72,8 +72,9 @@ if (!existsSync(localPath)) {
72
72
 
73
73
  const nativeBinding = require(localPath)
74
74
 
75
- const { initLogging, ArchilClient, JsInodeType } = nativeBinding
75
+ const { initLogging, ArchilClient, JsInodeType, MAXIMUM_READ_SIZE } = nativeBinding
76
76
 
77
77
  module.exports.initLogging = initLogging
78
78
  module.exports.ArchilClient = ArchilClient
79
79
  module.exports.JsInodeType = JsInodeType
80
+ module.exports.MAXIMUM_READ_SIZE = MAXIMUM_READ_SIZE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archildata/client",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "High-performance Node.js client for Archil distributed filesystem",
5
5
  "main": "main.js",
6
6
  "types": "main.d.ts",