@milaboratories/pl-drivers 1.2.35 → 1.3.1

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.
Files changed (38) hide show
  1. package/dist/clients/download.d.ts +6 -2
  2. package/dist/clients/download.d.ts.map +1 -1
  3. package/dist/clients/helpers.d.ts +2 -2
  4. package/dist/clients/helpers.d.ts.map +1 -1
  5. package/dist/drivers/helpers/ls_list_entry.d.ts +8 -13
  6. package/dist/drivers/helpers/ls_list_entry.d.ts.map +1 -1
  7. package/dist/drivers/helpers/ls_storage_entry.d.ts +6 -8
  8. package/dist/drivers/helpers/ls_storage_entry.d.ts.map +1 -1
  9. package/dist/drivers/ls.d.ts +40 -12
  10. package/dist/drivers/ls.d.ts.map +1 -1
  11. package/dist/drivers/types.d.ts +80 -0
  12. package/dist/drivers/types.d.ts.map +1 -0
  13. package/dist/drivers/upload.d.ts +18 -26
  14. package/dist/drivers/upload.d.ts.map +1 -1
  15. package/dist/helpers/validate.d.ts +2 -0
  16. package/dist/helpers/validate.d.ts.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +820 -792
  22. package/dist/index.mjs.map +1 -1
  23. package/package.json +5 -5
  24. package/src/clients/download.test.ts +17 -15
  25. package/src/clients/download.ts +34 -21
  26. package/src/clients/helpers.ts +13 -43
  27. package/src/drivers/download_blob.test.ts +4 -4
  28. package/src/drivers/helpers/ls_list_entry.test.ts +5 -7
  29. package/src/drivers/helpers/ls_list_entry.ts +31 -36
  30. package/src/drivers/helpers/ls_storage_entry.ts +18 -62
  31. package/src/drivers/logs.test.ts +3 -3
  32. package/src/drivers/ls.test.ts +112 -30
  33. package/src/drivers/ls.ts +233 -83
  34. package/src/drivers/types.ts +41 -0
  35. package/src/drivers/upload.test.ts +43 -82
  36. package/src/drivers/upload.ts +59 -111
  37. package/src/helpers/validate.ts +6 -0
  38. package/src/index.ts +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-drivers",
3
- "version": "1.2.35",
3
+ "version": "1.3.1",
4
4
  "description": "Drivers and a low-level clients for log streaming, downloading and uploading files from and to pl",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -27,10 +27,10 @@
27
27
  "undici": "^6.19.8",
28
28
  "zod": "^3.23.8",
29
29
  "@milaboratories/ts-helpers": "^1.1.0",
30
- "@milaboratories/computable": "^2.1.13",
31
- "@milaboratories/pl-client": "^2.5.2",
32
- "@milaboratories/pl-model-common": "^1.3.15",
33
- "@milaboratories/pl-tree": "^1.4.3"
30
+ "@milaboratories/computable": "^2.2.0",
31
+ "@milaboratories/pl-tree": "^1.4.4",
32
+ "@milaboratories/pl-client": "^2.5.3",
33
+ "@milaboratories/pl-model-common": "^1.4.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "typescript": "~5.5.4",
@@ -6,7 +6,18 @@ import { ConsoleLoggerAdapter } from '@milaboratories/ts-helpers';
6
6
  import { GrpcTransport } from '@protobuf-ts/grpc-transport';
7
7
  import { Dispatcher } from 'undici';
8
8
  import { text } from 'node:stream/consumers';
9
- import { ClientDownload } from '../clients/download';
9
+ import { ClientDownload, parseLocalFileUrl } from '../clients/download';
10
+ import { test, expect } from '@jest/globals';
11
+
12
+ test('should parse local file url even on Windows', () => {
13
+ const url = "storage://main/67z%5C2vy%5C65i%5C67z2vy65i0xwhjwsfsef_ex3k3hxe7qdc2cvtdfkdnhdp9kwlt7-7dmcy0kthe6u.json";
14
+ const expectedFullPath = 'C:\\Users\\test\\67z\\2vy\\65i\\67z2vy65i0xwhjwsfsef_ex3k3hxe7qdc2cvtdfkdnhdp9kwlt7-7dmcy0kthe6u.json';
15
+
16
+ const got = parseLocalFileUrl(url, new Map([['main', 'C:\\Users\\test']]))
17
+ .replace(path.sep, '\\'); // for testing on *nix systems
18
+
19
+ expect(got).toEqual(expectedFullPath);
20
+ })
10
21
 
11
22
  test('client download from a local file', async () => {
12
23
  await TestHelpers.withTempRoot(async (client) => {
@@ -20,22 +31,13 @@ test('client download from a local file', async () => {
20
31
 
21
32
  const clientDownload = client.getDriver({
22
33
  name: 'ClientDownload',
23
- init: (
24
- pl: PlClient,
25
- grpcTransport: GrpcTransport,
26
- httpDispatcher: Dispatcher
27
- ) =>
28
- new ClientDownload(
29
- grpcTransport,
30
- httpDispatcher,
31
- new ConsoleLoggerAdapter(),
32
- { tmp: storageRoot }
33
- )
34
+ init: (pl: PlClient, grpcTransport: GrpcTransport, httpDispatcher: Dispatcher) =>
35
+ new ClientDownload(grpcTransport, httpDispatcher, new ConsoleLoggerAdapter(), [
36
+ { storageId: 'tmp', localPath: storageRoot }
37
+ ])
34
38
  });
35
39
 
36
- const localFile = await clientDownload.readLocalFile(
37
- `storage://tmp/${fName}`
38
- );
40
+ const localFile = await clientDownload.readLocalFile(`storage://tmp/${fName}`);
39
41
 
40
42
  expect(localFile.size).toBe(2);
41
43
  expect(await text(localFile.content)).toBe('42');
@@ -14,11 +14,13 @@ import {
14
14
  } from '../proto/github.com/milaboratory/pl/controllers/shared/grpc/downloadapi/protocol';
15
15
  import { ResourceInfo } from '@milaboratories/pl-tree';
16
16
  import { DownloadHelper, DownloadResponse } from '../helpers/download';
17
+ import { LocalStorageProjection } from '../drivers/types';
18
+ import { validateAbsolute } from '../helpers/validate';
17
19
 
18
20
  const storageProtocol = 'storage://';
19
- const localPathRegex = /storage:\/\/(?<storageId>.*?)\/(?<localPath>.*)/;
20
21
 
21
22
  export class UnknownStorageError extends Error {}
23
+
22
24
  export class WrongLocalFileUrl extends Error {}
23
25
 
24
26
  /** Gets URLs for downloading from pl-core, parses them and reads or downloads
@@ -26,15 +28,21 @@ export class WrongLocalFileUrl extends Error {}
26
28
  export class ClientDownload {
27
29
  public readonly grpcClient: DownloadClient;
28
30
  private readonly downloadHelper: DownloadHelper;
31
+ private readonly localStorageIdsToRoot: Map<string, string>;
29
32
 
30
33
  constructor(
31
34
  public readonly grpcTransport: GrpcTransport,
32
35
  public readonly httpClient: Dispatcher,
33
36
  public readonly logger: MiLogger,
34
- private readonly localStorageIdsToRoot: Record<string, string>
37
+ /** Pl storages available locally */
38
+ localProjections: LocalStorageProjection[]
35
39
  ) {
40
+ for (const lp of localProjections) if (lp.localPath !== '') validateAbsolute(lp.localPath);
36
41
  this.grpcClient = new DownloadClient(this.grpcTransport);
37
42
  this.downloadHelper = new DownloadHelper(httpClient);
43
+ this.localStorageIdsToRoot = new Map(
44
+ localProjections.map((lp) => [lp.storageId, lp.localPath])
45
+ );
38
46
  }
39
47
 
40
48
  close() {}
@@ -65,30 +73,16 @@ export class ClientDownload {
65
73
  return this.isLocal(downloadUrl)
66
74
  ? await this.readLocalFile(downloadUrl)
67
75
  : await this.downloadHelper.downloadRemoteFile(
68
- downloadUrl,
69
- headersFromProto(headers),
70
- signal
71
- );
76
+ downloadUrl,
77
+ headersFromProto(headers),
78
+ signal
79
+ );
72
80
  }
73
81
 
74
82
  private isLocal = (url: string) => url.startsWith(storageProtocol);
75
83
 
76
84
  async readLocalFile(url: string): Promise<DownloadResponse> {
77
- const parsed = url.match(localPathRegex);
78
- if (parsed === null || parsed.length != 3) {
79
- throw new WrongLocalFileUrl(
80
- `url for local filepath ${url} does not match regex ${localPathRegex}, parsed: ${parsed}`
81
- );
82
- }
83
-
84
- const [_, storageId, localPath] = parsed;
85
-
86
- if (this.localStorageIdsToRoot[storageId] == undefined)
87
- throw new UnknownStorageError(`Unknown storage location: ${storageId}`);
88
-
89
- const storageRoot = this.localStorageIdsToRoot[storageId];
90
-
91
- const fullPath = path.join(storageRoot, localPath);
85
+ const fullPath = parseLocalFileUrl(url, this.localStorageIdsToRoot);
92
86
  const stat = await fsp.stat(fullPath);
93
87
  const size = stat.size;
94
88
 
@@ -99,6 +93,25 @@ export class ClientDownload {
99
93
  }
100
94
  }
101
95
 
96
+ export function parseLocalFileUrl(
97
+ url: string,
98
+ localStorageIdsToRoot: Map<string, string>,
99
+ ): string {
100
+ const parsed = new URL(url);
101
+ if (parsed.pathname == '')
102
+ throw new WrongLocalFileUrl(`url for local filepath ${url} does not match url scheme`);
103
+
104
+ const storageId = parsed.host;
105
+ const storageRoot = localStorageIdsToRoot.get(storageId);
106
+ if (storageRoot === undefined)
107
+ throw new UnknownStorageError(`Unknown storage location: ${storageId}`);
108
+
109
+ const localPath = decodeURIComponent(parsed.pathname.slice(1));
110
+ const fullPath = storageRoot === '' ? localPath : path.join(storageRoot, localPath);
111
+
112
+ return fullPath;
113
+ }
114
+
102
115
  export function headersFromProto(
103
116
  headers: DownloadAPI_GetDownloadURL_HTTPHeader[]
104
117
  ): Record<string, string> {
@@ -7,78 +7,48 @@ import { ClientLogs } from './logs';
7
7
  import { ClientProgress } from './progress';
8
8
  import { ClientUpload } from './upload';
9
9
  import { ClientLs } from './ls_api';
10
-
11
- export const PL_STORAGE_TO_PATH = process.env.PL_STORAGE_TO_PATH
12
- ? Object.fromEntries(
13
- process.env.PL_STORAGE_TO_PATH.split(';').map((kv) => kv.split(':'))
14
- )
15
- : {};
10
+ import { LocalStorageProjection } from '../drivers/types';
16
11
 
17
12
  export function createDownloadClient(
18
13
  logger: MiLogger,
19
14
  client: PlClient,
20
- localStorageIdsToRoot?: Record<string, string>
15
+ localProjections: LocalStorageProjection[]
21
16
  ) {
22
- if (localStorageIdsToRoot === undefined)
23
- localStorageIdsToRoot = PL_STORAGE_TO_PATH;
24
- const clientDownload = client.getDriver({
17
+ return client.getDriver({
25
18
  name: 'DownloadBlob',
26
- init: (
27
- _: PlClient,
28
- grpcTransport: GrpcTransport,
29
- httpDispatcher: Dispatcher
30
- ) =>
31
- new ClientDownload(
32
- grpcTransport,
33
- httpDispatcher,
34
- logger,
35
- localStorageIdsToRoot!
36
- )
19
+ init: (_: PlClient, grpcTransport: GrpcTransport, httpDispatcher: Dispatcher) =>
20
+ new ClientDownload(grpcTransport, httpDispatcher, logger, localProjections)
37
21
  });
38
-
39
- return clientDownload;
40
22
  }
41
23
 
42
24
  export function createLogsClient(client: PlClient, logger: MiLogger) {
43
25
  return client.getDriver({
44
26
  name: 'StreamLogs',
45
- init: (
46
- _: PlClient,
47
- grpcTransport: GrpcTransport,
48
- httpDispatcher: Dispatcher
49
- ) => new ClientLogs(grpcTransport, httpDispatcher, logger)
27
+ init: (_: PlClient, grpcTransport: GrpcTransport, httpDispatcher: Dispatcher) =>
28
+ new ClientLogs(grpcTransport, httpDispatcher, logger)
50
29
  });
51
30
  }
52
31
 
53
32
  export function createUploadProgressClient(client: PlClient, logger: MiLogger) {
54
33
  return client.getDriver({
55
34
  name: 'UploadProgress',
56
- init: (
57
- _: PlClient,
58
- grpcTransport: GrpcTransport,
59
- httpDispatcher: Dispatcher
60
- ) => new ClientProgress(grpcTransport, httpDispatcher, client, logger)
35
+ init: (_: PlClient, grpcTransport: GrpcTransport, httpDispatcher: Dispatcher) =>
36
+ new ClientProgress(grpcTransport, httpDispatcher, client, logger)
61
37
  });
62
38
  }
63
39
 
64
40
  export function createUploadBlobClient(client: PlClient, logger: MiLogger) {
65
41
  return client.getDriver({
66
42
  name: 'UploadBlob',
67
- init: (
68
- _: PlClient,
69
- grpcTransport: GrpcTransport,
70
- httpDispatcher: Dispatcher
71
- ) => new ClientUpload(grpcTransport, httpDispatcher, client, logger)
43
+ init: (_: PlClient, grpcTransport: GrpcTransport, httpDispatcher: Dispatcher) =>
44
+ new ClientUpload(grpcTransport, httpDispatcher, client, logger)
72
45
  });
73
46
  }
74
47
 
75
48
  export function createLsFilesClient(client: PlClient, logger: MiLogger) {
76
49
  return client.getDriver({
77
50
  name: 'LsFiles',
78
- init: (
79
- _client: PlClient,
80
- grpcTransport: GrpcTransport,
81
- _httpDispatcher: Dispatcher
82
- ) => new ClientLs(grpcTransport, logger)
51
+ init: (_client: PlClient, grpcTransport: GrpcTransport, _httpDispatcher: Dispatcher) =>
52
+ new ClientLs(grpcTransport, logger)
83
53
  });
84
54
  }
@@ -32,7 +32,7 @@ test.skip('should download a blob and read its content', async () => {
32
32
 
33
33
  const driver = new DownloadDriver(
34
34
  logger,
35
- createDownloadClient(logger, client),
35
+ createDownloadClient(logger, client, []),
36
36
  createLogsClient(client, logger),
37
37
  dir,
38
38
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -60,7 +60,7 @@ test.skip('should get on demand blob without downloading a blob', async () => {
60
60
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-download-2-'));
61
61
  const driver = new DownloadDriver(
62
62
  logger,
63
- createDownloadClient(logger, client),
63
+ createDownloadClient(logger, client, []),
64
64
  createLogsClient(client, logger),
65
65
  dir,
66
66
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -85,7 +85,7 @@ test.skip('should get undefined when releasing a blob from a small cache and the
85
85
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-download-3-'));
86
86
  const driver = new DownloadDriver(
87
87
  logger,
88
- createDownloadClient(logger, client),
88
+ createDownloadClient(logger, client, []),
89
89
  createLogsClient(client, logger),
90
90
  dir,
91
91
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -122,7 +122,7 @@ test.skip('should get the blob when releasing a blob, but a cache is big enough
122
122
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-download-4-'));
123
123
  const driver = new DownloadDriver(
124
124
  logger,
125
- createDownloadClient(logger, client),
125
+ createDownloadClient(logger, client, []),
126
126
  createLogsClient(client, logger),
127
127
  dir,
128
128
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -1,9 +1,7 @@
1
- import {
2
- ConsoleLoggerAdapter,
3
- HmacSha256Signer
4
- } from '@milaboratories/ts-helpers';
5
- import { fromFileHandle, toFileHandle, toListItem } from './ls_list_entry';
1
+ import { ConsoleLoggerAdapter, HmacSha256Signer } from '@milaboratories/ts-helpers';
2
+ import { parseUploadHandle, toFileHandle, toListItem } from './ls_list_entry';
6
3
  import type { Dirent, Stats } from 'node:fs';
4
+ import { ImportFileHandleUpload } from '@milaboratories/pl-model-common';
7
5
 
8
6
  test('toFileHandle should ok when encode data for UploadBlob', () => {
9
7
  const signer = new HmacSha256Signer('abc');
@@ -20,8 +18,8 @@ test('toFileHandle should ok when encode data for UploadBlob', () => {
20
18
  fullName: 'C:\\programFiles\\file.txt',
21
19
  lastModified: { seconds: 150n, nanos: 260 }
22
20
  }
23
- });
24
- const got = fromFileHandle(handle);
21
+ }) as ImportFileHandleUpload;
22
+ const got = parseUploadHandle(handle);
25
23
 
26
24
  expect(got.modificationTime).toEqual('150');
27
25
  expect(got.localPath).toEqual('C:\\programFiles\\file.txt');
@@ -2,13 +2,15 @@ import { MiLogger, notEmpty, Signer } from '@milaboratories/ts-helpers';
2
2
  import * as sdk from '@milaboratories/pl-model-common';
3
3
  import { Timestamp } from '../../proto/google/protobuf/timestamp';
4
4
  import { Dirent, Stats } from 'node:fs';
5
+ import { z } from 'zod';
6
+ import { ImportFileHandleIndexData, ImportFileHandleUploadData } from '../types';
5
7
 
6
8
  /** A duck-typing interface for grpc results. */
7
9
  export interface ListResponse {
8
10
  items: ListItem[];
9
11
  delimiter: string;
10
12
  }
11
-
13
+ /** @deprecated */
12
14
  export interface ListItem {
13
15
  isDir: boolean;
14
16
  name: string;
@@ -18,15 +20,14 @@ export interface ListItem {
18
20
  directory: string;
19
21
  }
20
22
 
21
- /** */
23
+ /** @deprecated */
22
24
  export function toLsEntries(info: {
23
25
  storageName: string;
24
26
  list: ListResponse;
25
27
  signer: Signer;
26
28
  remote: boolean;
27
29
  }): sdk.ListFilesResult {
28
- const parent =
29
- info.list.items.length > 0 ? info.list.items[0]?.directory : undefined;
30
+ const parent = info.list.items.length > 0 ? info.list.items[0]?.directory : undefined;
30
31
 
31
32
  return {
32
33
  parent: parent,
@@ -34,6 +35,7 @@ export function toLsEntries(info: {
34
35
  };
35
36
  }
36
37
 
38
+ /** @deprecated */
37
39
  function toLsEntry(
38
40
  item: ListItem,
39
41
  info: {
@@ -58,6 +60,7 @@ function toLsEntry(
58
60
  };
59
61
  }
60
62
 
63
+ /** @deprecated */
61
64
  export function toFileHandle(info: {
62
65
  storageName: string;
63
66
  item: ListItem;
@@ -65,10 +68,10 @@ export function toFileHandle(info: {
65
68
  remote: boolean;
66
69
  }): sdk.ImportFileHandle {
67
70
  if (info.remote) {
68
- return createIndexHandle(info);
71
+ return createIndexImportHandle(info.storageName, info.item.fullName);
69
72
  }
70
73
 
71
- return createUploadHandle(
74
+ return createUploadImportHandle(
72
75
  info.item.fullName,
73
76
  info.signer,
74
77
  info.item.size,
@@ -76,50 +79,44 @@ export function toFileHandle(info: {
76
79
  );
77
80
  }
78
81
 
79
- export type UploadHandleData = {
80
- /** Local file path, to take data for upload */
81
- localPath: string;
82
- /** Path signature, to check this data was generated by us */
83
- pathSignature: string;
84
- /** File size in bytes */
85
- sizeBytes: string;
86
- /** Modification time unix timestamp in seconds */
87
- modificationTime: string;
88
- };
89
-
90
- function createIndexHandle(info: {
91
- storageName: string;
92
- item: ListItem;
93
- }): sdk.ImportFileHandleIndex {
94
- const data = encodeURIComponent(
95
- JSON.stringify({
96
- storageId: info.storageName,
97
- path: info.item.fullName
98
- })
99
- );
82
+ export function createIndexImportHandle(
83
+ storageName: string,
84
+ path: string
85
+ ): sdk.ImportFileHandleIndex {
86
+ const data: ImportFileHandleIndexData = {
87
+ storageId: storageName,
88
+ path: path
89
+ };
100
90
 
101
- return `index://index/${data}`;
91
+ return `index://index/${encodeURIComponent(JSON.stringify(data))}`;
102
92
  }
103
93
 
104
- export function createUploadHandle(
94
+ export function createUploadImportHandle(
105
95
  localPath: string,
106
96
  signer: Signer,
107
97
  sizeBytes: bigint,
108
98
  modificationTimeSeconds: bigint
109
99
  ): sdk.ImportFileHandleUpload {
110
- const data: UploadHandleData = {
100
+ const data: ImportFileHandleUploadData = {
111
101
  localPath,
112
102
  pathSignature: signer.sign(localPath),
113
103
  sizeBytes: String(sizeBytes),
114
104
  modificationTime: String(modificationTimeSeconds)
115
105
  };
116
106
 
117
- return `upload://upload/${encodeURIComponent(JSON.stringify(data))}` as sdk.ImportFileHandleUpload;
107
+ return `upload://upload/${encodeURIComponent(JSON.stringify(data))}`;
108
+ }
109
+
110
+ export function parseUploadHandle(handle: sdk.ImportFileHandleUpload): ImportFileHandleUploadData {
111
+ const url = new URL(handle);
112
+ return ImportFileHandleUploadData.parse(
113
+ JSON.parse(decodeURIComponent(url.pathname.substring(1)))
114
+ );
118
115
  }
119
116
 
120
- export function fromFileHandle(handle: sdk.ImportFileHandle) {
117
+ export function parseIndexHandle(handle: sdk.ImportFileHandleIndex): ImportFileHandleIndexData {
121
118
  const url = new URL(handle);
122
- return JSON.parse(decodeURIComponent(url.pathname.substring(1)));
119
+ return ImportFileHandleIndexData.parse(JSON.parse(decodeURIComponent(url.pathname.substring(1))));
123
120
  }
124
121
 
125
122
  export function toListItem(
@@ -132,9 +129,7 @@ export function toListItem(
132
129
  }
133
130
  ): ListItem | undefined {
134
131
  if (!(info.dirent.isFile() || info.dirent.isDirectory())) {
135
- logger.warn(
136
- `tried to get non-dir and non-file ${info.dirent.name}, skip it`
137
- );
132
+ logger.warn(`tried to get non-dir and non-file ${info.dirent.name}, skip it`);
138
133
  return;
139
134
  }
140
135
 
@@ -1,38 +1,17 @@
1
1
  import * as sdk from '@milaboratories/pl-model-common';
2
- import {
3
- bigintToResourceId,
4
- ResourceId,
5
- ResourceType
6
- } from '@milaboratories/pl-client';
2
+ import { bigintToResourceId, ResourceId, ResourceType } from '@milaboratories/pl-client';
7
3
  import { assertNever } from '@milaboratories/ts-helpers';
8
4
 
9
- /**
10
- * Converts local and remote storages to StorageEntries.
11
- */
12
- export function toStorageEntry(
13
- locals: Record<string, string>,
14
- remotes: Record<string, ResourceId>
15
- ): sdk.StorageEntry[] {
16
- const localEntries = Object.entries(locals).map(localToEntry);
17
- const remoteEntries = Object.entries(remotes).map(remoteToEntry);
18
-
19
- return localEntries.concat(remoteEntries);
20
- }
21
-
22
- export type StorageHandleData =
23
- | RemoteStorageHandleData
24
- | LocalStorageHandleData;
5
+ export type StorageHandleData = RemoteStorageHandleData | LocalStorageHandleData;
25
6
 
26
7
  /**
27
8
  * Gets a storage handle and gives an underlying data from it.
28
9
  */
29
- export function fromStorageHandle(
30
- handle: sdk.StorageHandle
31
- ): StorageHandleData {
10
+ export function parseStorageHandle(handle: sdk.StorageHandle): StorageHandleData {
32
11
  if (isRemoteStorageHandle(handle)) {
33
- return fromRemoteHandle(handle);
12
+ return parseRemoteStorageHandle(handle);
34
13
  } else if (isLocalStorageHandle(handle)) {
35
- return fromLocalHandle(handle);
14
+ return parseLocalStorageHandle(handle);
36
15
  }
37
16
 
38
17
  assertNever(handle);
@@ -43,42 +22,31 @@ export function fromStorageHandle(
43
22
  //
44
23
 
45
24
  export type LocalStorageHandleData = {
46
- remote: false;
25
+ isRemote: false;
47
26
  name: string;
48
- path: string;
27
+ rootPath: string;
49
28
  };
50
29
 
51
- function localToEntry([name, path]: [string, string]): sdk.StorageEntry {
52
- return {
53
- name: name,
54
- handle: toLocalHandle(name, path),
55
- initialFullPath: path
56
- };
57
- }
58
-
59
30
  const localHandleRegex = /^local:\/\/(?<name>.*)\/(?<path>.*)$/;
60
31
 
61
- export function isLocalStorageHandle(
62
- handle: sdk.StorageHandle
63
- ): handle is sdk.StorageHandleLocal {
32
+ export function isLocalStorageHandle(handle: sdk.StorageHandle): handle is sdk.StorageHandleLocal {
64
33
  return localHandleRegex.test(handle);
65
34
  }
66
35
 
67
- function toLocalHandle(name: string, path: string): sdk.StorageHandleLocal {
36
+ export function createLocalStorageHandle(name: string, path: string): sdk.StorageHandleLocal {
68
37
  return `local://${name}/${encodeURIComponent(path)}`;
69
38
  }
70
39
 
71
- function fromLocalHandle(handle: string): LocalStorageHandleData {
40
+ function parseLocalStorageHandle(handle: string): LocalStorageHandleData {
72
41
  const parsed = handle.match(localHandleRegex);
73
- if (parsed == null)
74
- throw new Error(`Local list handle wasn't parsed: ${handle}`);
42
+ if (parsed == null) throw new Error(`Local list handle wasn't parsed: ${handle}`);
75
43
 
76
44
  const { name, path } = parsed.groups!;
77
45
 
78
46
  return {
79
- path: decodeURIComponent(path),
47
+ rootPath: decodeURIComponent(path),
80
48
  name,
81
- remote: false
49
+ isRemote: false
82
50
  };
83
51
  }
84
52
 
@@ -87,20 +55,12 @@ function fromLocalHandle(handle: string): LocalStorageHandleData {
87
55
  //
88
56
 
89
57
  export type RemoteStorageHandleData = {
90
- remote: true;
58
+ isRemote: true;
91
59
  name: string;
92
60
  id: ResourceId;
93
61
  type: ResourceType;
94
62
  };
95
63
 
96
- function remoteToEntry([name, rId]: [string, ResourceId]): sdk.StorageEntry {
97
- return {
98
- name: name,
99
- handle: toRemoteHandle(name, rId),
100
- initialFullPath: ''
101
- };
102
- }
103
-
104
64
  const remoteHandleRegex = /^remote:\/\/(?<name>.*)\/(?<resourceId>.*)$/;
105
65
 
106
66
  export function isRemoteStorageHandle(
@@ -109,24 +69,20 @@ export function isRemoteStorageHandle(
109
69
  return remoteHandleRegex.test(handle);
110
70
  }
111
71
 
112
- function toRemoteHandle(
113
- name: string,
114
- rId: ResourceId
115
- ): sdk.StorageHandleRemote {
72
+ export function createRemoteStorageHandle(name: string, rId: ResourceId): sdk.StorageHandleRemote {
116
73
  return `remote://${name}/${BigInt(rId)}`;
117
74
  }
118
75
 
119
- function fromRemoteHandle(handle: string): RemoteStorageHandleData {
76
+ function parseRemoteStorageHandle(handle: string): RemoteStorageHandleData {
120
77
  const parsed = handle.match(remoteHandleRegex);
121
- if (parsed == null)
122
- throw new Error(`Remote list handle wasn't parsed: ${handle}`);
78
+ if (parsed == null) throw new Error(`Remote list handle wasn't parsed: ${handle}`);
123
79
  const { name, resourceId } = parsed.groups!;
124
80
 
125
81
  return {
126
82
  id: bigintToResourceId(BigInt(resourceId)),
127
83
  type: storageType(name),
128
84
  name,
129
- remote: true
85
+ isRemote: true
130
86
  };
131
87
  }
132
88
 
@@ -39,7 +39,7 @@ test('should get all logs', async () => {
39
39
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-1-'));
40
40
  const download = new DownloadDriver(
41
41
  logger,
42
- createDownloadClient(logger, client),
42
+ createDownloadClient(logger, client, []),
43
43
  createLogsClient(client, logger),
44
44
  dir,
45
45
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -91,7 +91,7 @@ test('should get last line with a prefix', async () => {
91
91
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-2-'));
92
92
  const download = new DownloadDriver(
93
93
  logger,
94
- createDownloadClient(logger, client),
94
+ createDownloadClient(logger, client, []),
95
95
  createLogsClient(client, logger),
96
96
  dir,
97
97
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),
@@ -145,7 +145,7 @@ test('should get log smart object and get log lines from that', async () => {
145
145
  const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'test-logs-3-'));
146
146
  const download = new DownloadDriver(
147
147
  logger,
148
- createDownloadClient(logger, client),
148
+ createDownloadClient(logger, client, []),
149
149
  createLogsClient(client, logger),
150
150
  dir,
151
151
  new HmacSha256Signer(HmacSha256Signer.generateSecret()),