@ms-cloudpack/remote-cache 0.1.4 → 0.1.6

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 (39) hide show
  1. package/lib/createRemoteCacheClient.d.ts +1 -1
  2. package/lib/createRemoteCacheClient.d.ts.map +1 -1
  3. package/lib/createRemoteCacheClient.js +14 -2
  4. package/lib/createRemoteCacheClient.js.map +1 -1
  5. package/lib/decorators/InMemoryDecorator.d.ts +15 -0
  6. package/lib/decorators/InMemoryDecorator.d.ts.map +1 -0
  7. package/lib/decorators/InMemoryDecorator.js +29 -0
  8. package/lib/decorators/InMemoryDecorator.js.map +1 -0
  9. package/lib/{RemoteCacheClientWithReporter.d.ts → decorators/ReporterDecorator.d.ts} +6 -5
  10. package/lib/decorators/ReporterDecorator.d.ts.map +1 -0
  11. package/lib/{RemoteCacheClientWithReporter.js → decorators/ReporterDecorator.js} +33 -4
  12. package/lib/decorators/ReporterDecorator.js.map +1 -0
  13. package/lib/decorators/RetryDecorator.d.ts +17 -0
  14. package/lib/decorators/RetryDecorator.d.ts.map +1 -0
  15. package/lib/decorators/RetryDecorator.js +27 -0
  16. package/lib/decorators/RetryDecorator.js.map +1 -0
  17. package/lib/getListOfBlobs.d.ts +6 -0
  18. package/lib/getListOfBlobs.d.ts.map +1 -0
  19. package/lib/getListOfBlobs.js +14 -0
  20. package/lib/getListOfBlobs.js.map +1 -0
  21. package/lib/retry/RetryManager.d.ts +20 -0
  22. package/lib/retry/RetryManager.d.ts.map +1 -0
  23. package/lib/retry/RetryManager.js +47 -0
  24. package/lib/retry/RetryManager.js.map +1 -0
  25. package/lib/retry/blockListIsInvalidRetryPolicy.d.ts +3 -0
  26. package/lib/retry/blockListIsInvalidRetryPolicy.d.ts.map +1 -0
  27. package/lib/retry/blockListIsInvalidRetryPolicy.js +8 -0
  28. package/lib/retry/blockListIsInvalidRetryPolicy.js.map +1 -0
  29. package/lib/tsdoc-metadata.json +1 -1
  30. package/lib/types/ConnectionStringOptions.d.ts +1 -0
  31. package/lib/types/ConnectionStringOptions.d.ts.map +1 -1
  32. package/lib/types/ConnectionStringOptions.js.map +1 -1
  33. package/lib/types/RetryPolicy.d.ts +15 -0
  34. package/lib/types/RetryPolicy.d.ts.map +1 -0
  35. package/lib/types/RetryPolicy.js +2 -0
  36. package/lib/types/RetryPolicy.js.map +1 -0
  37. package/package.json +1 -1
  38. package/lib/RemoteCacheClientWithReporter.d.ts.map +0 -1
  39. package/lib/RemoteCacheClientWithReporter.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import type { RemoteCacheClient } from './types/RemoteCacheClient.js';
2
1
  import type { TaskReporter } from '@ms-cloudpack/task-reporter';
3
2
  import type { ConnectionStringOptions } from './types/ConnectionStringOptions.js';
3
+ import type { RemoteCacheClient } from './types/RemoteCacheClient.js';
4
4
  export declare function createRemoteCacheClient(options: {
5
5
  connectionStringOptions: ConnectionStringOptions;
6
6
  reporter: TaskReporter;
@@ -1 +1 @@
1
- {"version":3,"file":"createRemoteCacheClient.d.ts","sourceRoot":"","sources":["../src/createRemoteCacheClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAElF,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACrD,uBAAuB,EAAE,uBAAuB,CAAC;IACjD,QAAQ,EAAE,YAAY,CAAC;CACxB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAe7B"}
1
+ {"version":3,"file":"createRemoteCacheClient.d.ts","sourceRoot":"","sources":["../src/createRemoteCacheClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAMhE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAKtE,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACrD,uBAAuB,EAAE,uBAAuB,CAAC;IACjD,QAAQ,EAAE,YAAY,CAAC;CACxB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuB7B"}
@@ -1,13 +1,25 @@
1
1
  import { AzureRemoteCacheClient } from './AzureRemoteCacheClient.js';
2
2
  import { getAuthenticatedConnectionString } from './authentication/getAuthenticatedConnectionString.js';
3
- import { RemoteCacheClientWithReporter } from './RemoteCacheClientWithReporter.js';
3
+ import { InMemoryDecorator } from './decorators/InMemoryDecorator.js';
4
+ import { ReporterDecorator } from './decorators/ReporterDecorator.js';
5
+ import { getListOfBlobs } from './getListOfBlobs.js';
6
+ import { RetryDecorator } from './decorators/RetryDecorator.js';
7
+ import { blockListIsInvalidRetryPolicy } from './retry/blockListIsInvalidRetryPolicy.js';
8
+ import { RetryManager } from './retry/RetryManager.js';
4
9
  export async function createRemoteCacheClient(options) {
5
10
  const { connectionStringOptions, reporter } = options;
6
11
  const { container } = connectionStringOptions;
7
12
  const connectionString = await getAuthenticatedConnectionString(connectionStringOptions);
8
- const client = new RemoteCacheClientWithReporter(new AzureRemoteCacheClient({
13
+ const cacheClientOptions = {
9
14
  container,
10
15
  connectionString,
16
+ };
17
+ const client = new ReporterDecorator(new RetryDecorator({
18
+ retryManager: new RetryManager([blockListIsInvalidRetryPolicy]),
19
+ cacheClient: new InMemoryDecorator({
20
+ cacheClient: new AzureRemoteCacheClient(cacheClientOptions),
21
+ getList: () => getListOfBlobs(cacheClientOptions),
22
+ }),
11
23
  }), reporter);
12
24
  return client;
13
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createRemoteCacheClient.js","sourceRoot":"","sources":["../src/createRemoteCacheClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,OAAO,EAAE,gCAAgC,EAAE,MAAM,sDAAsD,CAAC;AACxG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AAInF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAG7C;IACC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACtD,MAAM,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC;IAE9C,MAAM,gBAAgB,GAAG,MAAM,gCAAgC,CAAC,uBAAuB,CAAC,CAAC;IAEzF,MAAM,MAAM,GAAG,IAAI,6BAA6B,CAC9C,IAAI,sBAAsB,CAAC;QACzB,SAAS;QACT,gBAAgB;KACjB,CAAC,EACF,QAAQ,CACT,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { AzureRemoteCacheClient } from './AzureRemoteCacheClient.js';\nimport type { RemoteCacheClient } from './types/RemoteCacheClient.js';\nimport { getAuthenticatedConnectionString } from './authentication/getAuthenticatedConnectionString.js';\nimport { RemoteCacheClientWithReporter } from './RemoteCacheClientWithReporter.js';\nimport type { TaskReporter } from '@ms-cloudpack/task-reporter';\nimport type { ConnectionStringOptions } from './types/ConnectionStringOptions.js';\n\nexport async function createRemoteCacheClient(options: {\n connectionStringOptions: ConnectionStringOptions;\n reporter: TaskReporter;\n}): Promise<RemoteCacheClient> {\n const { connectionStringOptions, reporter } = options;\n const { container } = connectionStringOptions;\n\n const connectionString = await getAuthenticatedConnectionString(connectionStringOptions);\n\n const client = new RemoteCacheClientWithReporter(\n new AzureRemoteCacheClient({\n container,\n connectionString,\n }),\n reporter,\n );\n\n return client;\n}\n"]}
1
+ {"version":3,"file":"createRemoteCacheClient.js","sourceRoot":"","sources":["../src/createRemoteCacheClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,gCAAgC,EAAE,MAAM,sDAAsD,CAAC;AACxG,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAG7C;IACC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACtD,MAAM,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC;IAE9C,MAAM,gBAAgB,GAAG,MAAM,gCAAgC,CAAC,uBAAuB,CAAC,CAAC;IAEzF,MAAM,kBAAkB,GAAG;QACzB,SAAS;QACT,gBAAgB;KACjB,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAClC,IAAI,cAAc,CAAC;QACjB,YAAY,EAAE,IAAI,YAAY,CAAC,CAAC,6BAA6B,CAAC,CAAC;QAC/D,WAAW,EAAE,IAAI,iBAAiB,CAAC;YACjC,WAAW,EAAE,IAAI,sBAAsB,CAAC,kBAAkB,CAAC;YAC3D,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,kBAAkB,CAAC;SAClD,CAAC;KACH,CAAC,EACF,QAAQ,CACT,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type { TaskReporter } from '@ms-cloudpack/task-reporter';\nimport { AzureRemoteCacheClient } from './AzureRemoteCacheClient.js';\nimport { getAuthenticatedConnectionString } from './authentication/getAuthenticatedConnectionString.js';\nimport { InMemoryDecorator } from './decorators/InMemoryDecorator.js';\nimport { ReporterDecorator } from './decorators/ReporterDecorator.js';\nimport { getListOfBlobs } from './getListOfBlobs.js';\nimport type { ConnectionStringOptions } from './types/ConnectionStringOptions.js';\nimport type { RemoteCacheClient } from './types/RemoteCacheClient.js';\nimport { RetryDecorator } from './decorators/RetryDecorator.js';\nimport { blockListIsInvalidRetryPolicy } from './retry/blockListIsInvalidRetryPolicy.js';\nimport { RetryManager } from './retry/RetryManager.js';\n\nexport async function createRemoteCacheClient(options: {\n connectionStringOptions: ConnectionStringOptions;\n reporter: TaskReporter;\n}): Promise<RemoteCacheClient> {\n const { connectionStringOptions, reporter } = options;\n const { container } = connectionStringOptions;\n\n const connectionString = await getAuthenticatedConnectionString(connectionStringOptions);\n\n const cacheClientOptions = {\n container,\n connectionString,\n };\n\n const client = new ReporterDecorator(\n new RetryDecorator({\n retryManager: new RetryManager([blockListIsInvalidRetryPolicy]),\n cacheClient: new InMemoryDecorator({\n cacheClient: new AzureRemoteCacheClient(cacheClientOptions),\n getList: () => getListOfBlobs(cacheClientOptions),\n }),\n }),\n reporter,\n );\n\n return client;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { RemoteCacheClient, RemoteCacheClientOperationOptions, RemoteCacheClientOperationResult } from '../types/RemoteCacheClient.js';
2
+ /**
3
+ * A decorator for a RemoteCacheClient that keeps a list of remote resources locally.
4
+ */
5
+ export declare class InMemoryDecorator implements RemoteCacheClient {
6
+ private readonly cacheClient;
7
+ private readonly list;
8
+ constructor(options: {
9
+ cacheClient: RemoteCacheClient;
10
+ getList: () => Promise<Set<string>>;
11
+ });
12
+ uploadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
13
+ downloadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
14
+ }
15
+ //# sourceMappingURL=InMemoryDecorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryDecorator.d.ts","sourceRoot":"","sources":["../../src/decorators/InMemoryDecorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,iCAAiC,EACjC,gCAAgC,EACjC,MAAM,+BAA+B,CAAC;AAEvC;;GAEG;AACH,qBAAa,iBAAkB,YAAW,iBAAiB;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;gBAEhC,OAAO,EAAE;QAAE,WAAW,EAAE,iBAAiB,CAAC;QAAC,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;KAAE;IAKtF,YAAY,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAgBnG,cAAc,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,gCAAgC,CAAC;CAQ5G"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A decorator for a RemoteCacheClient that keeps a list of remote resources locally.
3
+ */
4
+ export class InMemoryDecorator {
5
+ constructor(options) {
6
+ this.cacheClient = options.cacheClient;
7
+ this.list = options.getList();
8
+ }
9
+ async uploadFolder(options) {
10
+ if ((await this.list).has(options.folderName)) {
11
+ // This resource already exists in the remote cache, no need to upload it again.
12
+ return 'already-exist';
13
+ }
14
+ const result = await this.cacheClient.uploadFolder(options);
15
+ if (result === 'success') {
16
+ // The upload is successful, add the resource to the list.
17
+ (await this.list).add(options.folderName);
18
+ }
19
+ return result;
20
+ }
21
+ async downloadFolder(options) {
22
+ if (!(await this.list).has(options.folderName)) {
23
+ // This resource doesn't exist in the remote cache, can't download it.
24
+ return 'not-found';
25
+ }
26
+ return this.cacheClient.downloadFolder(options);
27
+ }
28
+ }
29
+ //# sourceMappingURL=InMemoryDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryDecorator.js","sourceRoot":"","sources":["../../src/decorators/InMemoryDecorator.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAI5B,YAAY,OAAgF;QAC1F,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA0C;QAC3D,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC7C,gFAAgF;YAChF,OAAO,eAAe,CAAC;SACxB;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE5D,IAAI,MAAM,KAAK,SAAS,EAAE;YACxB,0DAA0D;YAC1D,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;SAC3C;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAA0C;QAC7D,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC9C,sEAAsE;YACtE,OAAO,WAAW,CAAC;SACpB;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;CACF","sourcesContent":["import type {\n RemoteCacheClient,\n RemoteCacheClientOperationOptions,\n RemoteCacheClientOperationResult,\n} from '../types/RemoteCacheClient.js';\n\n/**\n * A decorator for a RemoteCacheClient that keeps a list of remote resources locally.\n */\nexport class InMemoryDecorator implements RemoteCacheClient {\n private readonly cacheClient: RemoteCacheClient;\n private readonly list: Promise<Set<string>>;\n\n constructor(options: { cacheClient: RemoteCacheClient; getList: () => Promise<Set<string>> }) {\n this.cacheClient = options.cacheClient;\n this.list = options.getList();\n }\n\n async uploadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult> {\n if ((await this.list).has(options.folderName)) {\n // This resource already exists in the remote cache, no need to upload it again.\n return 'already-exist';\n }\n\n const result = await this.cacheClient.uploadFolder(options);\n\n if (result === 'success') {\n // The upload is successful, add the resource to the list.\n (await this.list).add(options.folderName);\n }\n\n return result;\n }\n\n async downloadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult> {\n if (!(await this.list).has(options.folderName)) {\n // This resource doesn't exist in the remote cache, can't download it.\n return 'not-found';\n }\n\n return this.cacheClient.downloadFolder(options);\n }\n}\n"]}
@@ -1,10 +1,11 @@
1
1
  import { type TaskReporter } from '@ms-cloudpack/task-reporter';
2
- import type { RemoteCacheClient, RemoteCacheClientOperationOptions } from './types/RemoteCacheClient.js';
3
- export declare class RemoteCacheClientWithReporter implements RemoteCacheClient {
2
+ import type { RemoteCacheClient, RemoteCacheClientOperationOptions, RemoteCacheClientOperationResult } from '../types/RemoteCacheClient.js';
3
+ export declare class ReporterDecorator implements RemoteCacheClient {
4
4
  private readonly client;
5
5
  private readonly reporter;
6
6
  constructor(client: RemoteCacheClient, reporter: TaskReporter);
7
- uploadFolder(options: RemoteCacheClientOperationOptions): Promise<import("./types/RemoteCacheClient.js").RemoteCacheClientOperationResult>;
8
- downloadFolder(options: RemoteCacheClientOperationOptions): Promise<import("./types/RemoteCacheClient.js").RemoteCacheClientOperationResult>;
7
+ private buildFailureMessage;
8
+ uploadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
9
+ downloadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
9
10
  }
10
- //# sourceMappingURL=RemoteCacheClientWithReporter.d.ts.map
11
+ //# sourceMappingURL=ReporterDecorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReporterDecorator.d.ts","sourceRoot":"","sources":["../../src/decorators/ReporterDecorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,KAAK,EACV,iBAAiB,EACjB,iCAAiC,EACjC,gCAAgC,EACjC,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,iBAAkB,YAAW,iBAAiB;IAEvD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,YAAY;IAGzC,OAAO,CAAC,mBAAmB;IAWrB,YAAY,CAAC,OAAO,EAAE,iCAAiC;IA0CvD,cAAc,CAAC,OAAO,EAAE,iCAAiC;CAyChE"}
@@ -1,13 +1,32 @@
1
1
  import { bulletedList } from '@ms-cloudpack/task-reporter';
2
- export class RemoteCacheClientWithReporter {
2
+ export class ReporterDecorator {
3
3
  constructor(client, reporter) {
4
4
  this.client = client;
5
5
  this.reporter = reporter;
6
6
  }
7
+ buildFailureMessage({ folderName, friendlyName, path }, error) {
8
+ const list = bulletedList([
9
+ `FolderName: ${folderName}`,
10
+ `Path: ${path}`,
11
+ `Name: ${friendlyName}`,
12
+ `Error: ${error instanceof Error ? error.message : '<Unknown>'}`,
13
+ ]);
14
+ return `\n${list}`;
15
+ }
7
16
  async uploadFolder(options) {
8
17
  const { folderName, path, friendlyName } = options;
9
18
  const task = this.reporter.addTask(`Uploading to remote cache: ${friendlyName}`);
10
- const uploadResult = await this.client.uploadFolder(options);
19
+ let uploadResult;
20
+ try {
21
+ uploadResult = await this.client.uploadFolder(options);
22
+ }
23
+ catch (e) {
24
+ task.complete({
25
+ status: 'fail',
26
+ message: this.buildFailureMessage(options, e),
27
+ });
28
+ throw e;
29
+ }
11
30
  switch (uploadResult) {
12
31
  case 'success':
13
32
  task.complete({
@@ -35,7 +54,17 @@ export class RemoteCacheClientWithReporter {
35
54
  async downloadFolder(options) {
36
55
  const { folderName, path, friendlyName } = options;
37
56
  const task = this.reporter.addTask(`Downloading from remote cache: ${friendlyName}`);
38
- const downloadResult = await this.client.downloadFolder(options);
57
+ let downloadResult;
58
+ try {
59
+ downloadResult = await this.client.downloadFolder(options);
60
+ }
61
+ catch (e) {
62
+ task.complete({
63
+ status: 'fail',
64
+ message: this.buildFailureMessage(options, e),
65
+ });
66
+ throw e;
67
+ }
39
68
  switch (downloadResult) {
40
69
  case 'success':
41
70
  task.complete({
@@ -61,4 +90,4 @@ export class RemoteCacheClientWithReporter {
61
90
  return downloadResult;
62
91
  }
63
92
  }
64
- //# sourceMappingURL=RemoteCacheClientWithReporter.js.map
93
+ //# sourceMappingURL=ReporterDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReporterDecorator.js","sourceRoot":"","sources":["../../src/decorators/ReporterDecorator.ts"],"names":[],"mappings":"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","sourcesContent":["import { bulletedList, type TaskReporter } from '@ms-cloudpack/task-reporter';\nimport type {\n RemoteCacheClient,\n RemoteCacheClientOperationOptions,\n RemoteCacheClientOperationResult,\n} from '../types/RemoteCacheClient.js';\n\nexport class ReporterDecorator implements RemoteCacheClient {\n constructor(\n private readonly client: RemoteCacheClient,\n private readonly reporter: TaskReporter,\n ) {}\n\n private buildFailureMessage({ folderName, friendlyName, path }: RemoteCacheClientOperationOptions, error: unknown) {\n const list = bulletedList([\n `FolderName: ${folderName}`,\n `Path: ${path}`,\n `Name: ${friendlyName}`,\n `Error: ${error instanceof Error ? error.message : '<Unknown>'}`,\n ]);\n\n return `\\n${list}`;\n }\n\n async uploadFolder(options: RemoteCacheClientOperationOptions) {\n const { folderName, path, friendlyName } = options;\n const task = this.reporter.addTask(`Uploading to remote cache: ${friendlyName}`);\n\n let uploadResult: RemoteCacheClientOperationResult;\n\n try {\n uploadResult = await this.client.uploadFolder(options);\n } catch (e) {\n task.complete({\n status: 'fail',\n message: this.buildFailureMessage(options, e),\n });\n throw e;\n }\n\n switch (uploadResult) {\n case 'success':\n task.complete({\n status: 'complete',\n details: bulletedList([`FolderName: ${folderName}`, `Path: ${path}`, `Name: ${friendlyName}`]),\n });\n break;\n case 'not-found':\n task.complete({\n status: 'skip',\n message: `Not found in the local cache.`,\n });\n break;\n case 'already-exist':\n task.complete({\n status: 'skip',\n message: `Package is already exist in the remote cache.`,\n });\n break;\n default:\n throw new Error(`Unknown upload result: ${uploadResult}`);\n }\n\n return uploadResult;\n }\n\n async downloadFolder(options: RemoteCacheClientOperationOptions) {\n const { folderName, path, friendlyName } = options;\n const task = this.reporter.addTask(`Downloading from remote cache: ${friendlyName}`);\n\n let downloadResult: RemoteCacheClientOperationResult;\n\n try {\n downloadResult = await this.client.downloadFolder(options);\n } catch (e) {\n task.complete({\n status: 'fail',\n message: this.buildFailureMessage(options, e),\n });\n throw e;\n }\n\n switch (downloadResult) {\n case 'success':\n task.complete({\n status: 'complete',\n details: bulletedList([`FolderName: ${folderName}`, `Path: ${path}`, `Name: ${friendlyName}`]),\n });\n break;\n case 'not-found':\n task.complete({\n status: 'skip',\n message: `Not found in the remote cache.`,\n });\n break;\n case 'already-exist':\n task.complete({\n status: 'skip',\n message: `Package is already exist in the local cache.`,\n });\n break;\n default:\n throw new Error(`Unknown download result: ${downloadResult}`);\n }\n\n return downloadResult;\n }\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import type { RemoteCacheClient, RemoteCacheClientOperationOptions, RemoteCacheClientOperationResult } from '../types/RemoteCacheClient.js';
2
+ import type { RetryManager } from '../retry/RetryManager.js';
3
+ /**
4
+ * A decorator that retries the upload/download operation if it fails.
5
+ */
6
+ export declare class RetryDecorator implements RemoteCacheClient {
7
+ private readonly cacheClient;
8
+ private readonly retryManager;
9
+ constructor(options: {
10
+ cacheClient: RemoteCacheClient;
11
+ retryManager: RetryManager;
12
+ });
13
+ private printRetryContext;
14
+ uploadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
15
+ downloadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult>;
16
+ }
17
+ //# sourceMappingURL=RetryDecorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryDecorator.d.ts","sourceRoot":"","sources":["../../src/decorators/RetryDecorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,iCAAiC,EACjC,gCAAgC,EACjC,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IACtD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAEhC,OAAO,EAAE;QAAE,WAAW,EAAE,iBAAiB,CAAC;QAAC,YAAY,EAAE,YAAY,CAAA;KAAE;IAKnF,OAAO,CAAC,iBAAiB;IAYnB,YAAY,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAOnG,cAAc,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,gCAAgC,CAAC;CAM5G"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A decorator that retries the upload/download operation if it fails.
3
+ */
4
+ export class RetryDecorator {
5
+ constructor(options) {
6
+ this.cacheClient = options.cacheClient;
7
+ this.retryManager = options.retryManager;
8
+ }
9
+ printRetryContext(operationName, options, retryContext) {
10
+ if (retryContext) {
11
+ console.warn(`Retrying ${operationName} ${options.friendlyName} ... [${retryContext.retryAttempt}/${retryContext.maxRetries}]`);
12
+ }
13
+ }
14
+ async uploadFolder(options) {
15
+ return this.retryManager.retry((retryContext) => {
16
+ this.printRetryContext('upload', options, retryContext);
17
+ return this.cacheClient.uploadFolder(options);
18
+ });
19
+ }
20
+ async downloadFolder(options) {
21
+ return this.retryManager.retry((retryContext) => {
22
+ this.printRetryContext('download', options, retryContext);
23
+ return this.cacheClient.downloadFolder(options);
24
+ });
25
+ }
26
+ }
27
+ //# sourceMappingURL=RetryDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryDecorator.js","sourceRoot":"","sources":["../../src/decorators/RetryDecorator.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,OAAO,cAAc;IAIzB,YAAY,OAAuE;QACjF,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;IAEO,iBAAiB,CACvB,aAAqB,EACrB,OAA0C,EAC1C,YAA2D;QAE3D,IAAI,YAAY,EAAE;YAChB,OAAO,CAAC,IAAI,CACV,YAAY,aAAa,IAAI,OAAO,CAAC,YAAY,SAAS,YAAY,CAAC,YAAY,IAAI,YAAY,CAAC,UAAU,GAAG,CAClH,CAAC;SACH;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA0C;QAC3D,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,EAAE;YAC9C,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAA0C;QAC7D,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,EAAE;YAC9C,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import type {\n RemoteCacheClient,\n RemoteCacheClientOperationOptions,\n RemoteCacheClientOperationResult,\n} from '../types/RemoteCacheClient.js';\nimport type { RetryManager } from '../retry/RetryManager.js';\n\n/**\n * A decorator that retries the upload/download operation if it fails.\n */\nexport class RetryDecorator implements RemoteCacheClient {\n private readonly cacheClient: RemoteCacheClient;\n private readonly retryManager: RetryManager;\n\n constructor(options: { cacheClient: RemoteCacheClient; retryManager: RetryManager }) {\n this.cacheClient = options.cacheClient;\n this.retryManager = options.retryManager;\n }\n\n private printRetryContext(\n operationName: string,\n options: RemoteCacheClientOperationOptions,\n retryContext?: { retryAttempt: number; maxRetries: number },\n ) {\n if (retryContext) {\n console.warn(\n `Retrying ${operationName} ${options.friendlyName} ... [${retryContext.retryAttempt}/${retryContext.maxRetries}]`,\n );\n }\n }\n\n async uploadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult> {\n return this.retryManager.retry((retryContext) => {\n this.printRetryContext('upload', options, retryContext);\n return this.cacheClient.uploadFolder(options);\n });\n }\n\n async downloadFolder(options: RemoteCacheClientOperationOptions): Promise<RemoteCacheClientOperationResult> {\n return this.retryManager.retry((retryContext) => {\n this.printRetryContext('download', options, retryContext);\n return this.cacheClient.downloadFolder(options);\n });\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { RemoteCacheClientOptions } from './types/RemoteCacheClientOptions.js';
2
+ /**
3
+ * Gets all the blobs in the remote cache.
4
+ */
5
+ export declare function getListOfBlobs({ container, connectionString }: RemoteCacheClientOptions): Promise<Set<string>>;
6
+ //# sourceMappingURL=getListOfBlobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getListOfBlobs.d.ts","sourceRoot":"","sources":["../src/getListOfBlobs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAGpF;;GAEG;AACH,wBAAsB,cAAc,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,wBAAwB,wBAQ7F"}
@@ -0,0 +1,14 @@
1
+ import { BlobServiceClient } from '@azure/storage-blob';
2
+ /**
3
+ * Gets all the blobs in the remote cache.
4
+ */
5
+ export async function getListOfBlobs({ container, connectionString }) {
6
+ const blobStorageClient = BlobServiceClient.fromConnectionString(connectionString);
7
+ const containerClient = blobStorageClient.getContainerClient(container);
8
+ const blobs = new Set();
9
+ for await (const blob of containerClient.listBlobsFlat()) {
10
+ blobs.add(blob.name);
11
+ }
12
+ return blobs;
13
+ }
14
+ //# sourceMappingURL=getListOfBlobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getListOfBlobs.js","sourceRoot":"","sources":["../src/getListOfBlobs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAA4B;IAC5F,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IACnF,MAAM,eAAe,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,eAAe,CAAC,aAAa,EAAE,EAAE;QACxD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KACtB;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { RemoteCacheClientOptions } from './types/RemoteCacheClientOptions.js';\nimport { BlobServiceClient } from '@azure/storage-blob';\n\n/**\n * Gets all the blobs in the remote cache.\n */\nexport async function getListOfBlobs({ container, connectionString }: RemoteCacheClientOptions) {\n const blobStorageClient = BlobServiceClient.fromConnectionString(connectionString);\n const containerClient = blobStorageClient.getContainerClient(container);\n const blobs = new Set<string>();\n for await (const blob of containerClient.listBlobsFlat()) {\n blobs.add(blob.name);\n }\n return blobs;\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { RetryPolicy } from '../types/RetryPolicy.js';
2
+ /**
3
+ * A manager that handles the retry logic.
4
+ */
5
+ export declare class RetryManager {
6
+ private readonly policies;
7
+ constructor(policies: RetryPolicy[]);
8
+ private findPolicy;
9
+ private sleep;
10
+ /**
11
+ * If the operation call fails and there is an applicable retry policy, it will retry the operation.
12
+ * @param operation The operation to call. The retry context is passed to the operation if it is in retry.
13
+ * @returns
14
+ */
15
+ retry<T>(operation: (retryContext?: {
16
+ retryAttempt: number;
17
+ maxRetries: number;
18
+ }) => Promise<T>): Promise<T>;
19
+ }
20
+ //# sourceMappingURL=RetryManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryManager.d.ts","sourceRoot":"","sources":["../../src/retry/RetryManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;GAEG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,WAAW,EAAE;IAEpD,OAAO,CAAC,UAAU,CAOhB;IAEF,OAAO,CAAC,KAAK;IAIb;;;;OAIG;IACU,KAAK,CAAC,CAAC,EAClB,SAAS,EAAE,CAAC,YAAY,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GACrF,OAAO,CAAC,CAAC,CAAC;CAyBd"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A manager that handles the retry logic.
3
+ */
4
+ export class RetryManager {
5
+ constructor(policies) {
6
+ this.policies = policies;
7
+ this.findPolicy = (error) => {
8
+ for (const policy of this.policies) {
9
+ if (policy.handle(error)) {
10
+ return policy;
11
+ }
12
+ }
13
+ return undefined;
14
+ };
15
+ }
16
+ sleep(ms) {
17
+ return new Promise((resolve) => setTimeout(resolve, ms));
18
+ }
19
+ /**
20
+ * If the operation call fails and there is an applicable retry policy, it will retry the operation.
21
+ * @param operation The operation to call. The retry context is passed to the operation if it is in retry.
22
+ * @returns
23
+ */
24
+ async retry(operation) {
25
+ let retryAttempt = 0;
26
+ let previousPolicy = undefined;
27
+ do {
28
+ try {
29
+ const retryContext = previousPolicy ? { retryAttempt, maxRetries: previousPolicy.maxRetries } : undefined;
30
+ return await operation(retryContext);
31
+ }
32
+ catch (e) {
33
+ const policy = this.findPolicy(e);
34
+ if (previousPolicy !== policy) {
35
+ retryAttempt = 0;
36
+ previousPolicy = policy;
37
+ }
38
+ if (!policy || retryAttempt++ >= policy.maxRetries) {
39
+ throw e;
40
+ }
41
+ await this.sleep(policy.wait(retryAttempt));
42
+ }
43
+ // eslint-disable-next-line no-constant-condition
44
+ } while (true);
45
+ }
46
+ }
47
+ //# sourceMappingURL=RetryManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryManager.js","sourceRoot":"","sources":["../../src/retry/RetryManager.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,YAAY;IACvB,YAA6B,QAAuB;QAAvB,aAAQ,GAAR,QAAQ,CAAe;QAE5C,eAAU,GAAG,CAAC,KAAc,EAA2B,EAAE;YAC/D,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE;gBAClC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;oBACxB,OAAO,MAAM,CAAC;iBACf;aACF;YACD,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC;IATqD,CAAC;IAWhD,KAAK,CAAC,EAAU;QACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,KAAK,CAChB,SAAsF;QAEtF,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,cAAc,GAA4B,SAAS,CAAC;QAExD,GAAG;YACD,IAAI;gBACF,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBAE1G,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;aACtC;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,cAAc,KAAK,MAAM,EAAE;oBAC7B,YAAY,GAAG,CAAC,CAAC;oBACjB,cAAc,GAAG,MAAM,CAAC;iBACzB;gBAED,IAAI,CAAC,MAAM,IAAI,YAAY,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE;oBAClD,MAAM,CAAC,CAAC;iBACT;gBAED,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;aAC7C;YACD,iDAAiD;SAClD,QAAQ,IAAI,EAAE;IACjB,CAAC;CACF","sourcesContent":["import type { RetryPolicy } from '../types/RetryPolicy.js';\n\n/**\n * A manager that handles the retry logic.\n */\nexport class RetryManager {\n constructor(private readonly policies: RetryPolicy[]) {}\n\n private findPolicy = (error: unknown): RetryPolicy | undefined => {\n for (const policy of this.policies) {\n if (policy.handle(error)) {\n return policy;\n }\n }\n return undefined;\n };\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * If the operation call fails and there is an applicable retry policy, it will retry the operation.\n * @param operation The operation to call. The retry context is passed to the operation if it is in retry.\n * @returns\n */\n public async retry<T>(\n operation: (retryContext?: { retryAttempt: number; maxRetries: number }) => Promise<T>,\n ): Promise<T> {\n let retryAttempt = 0;\n let previousPolicy: RetryPolicy | undefined = undefined;\n\n do {\n try {\n const retryContext = previousPolicy ? { retryAttempt, maxRetries: previousPolicy.maxRetries } : undefined;\n\n return await operation(retryContext);\n } catch (e) {\n const policy = this.findPolicy(e);\n if (previousPolicy !== policy) {\n retryAttempt = 0;\n previousPolicy = policy;\n }\n\n if (!policy || retryAttempt++ >= policy.maxRetries) {\n throw e;\n }\n\n await this.sleep(policy.wait(retryAttempt));\n }\n // eslint-disable-next-line no-constant-condition\n } while (true);\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { RetryPolicy } from '../types/RetryPolicy.js';
2
+ export declare const blockListIsInvalidRetryPolicy: RetryPolicy;
3
+ //# sourceMappingURL=blockListIsInvalidRetryPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockListIsInvalidRetryPolicy.d.ts","sourceRoot":"","sources":["../../src/retry/blockListIsInvalidRetryPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,eAAO,MAAM,6BAA6B,EAAE,WAM3C,CAAC"}
@@ -0,0 +1,8 @@
1
+ export const blockListIsInvalidRetryPolicy = {
2
+ maxRetries: 1,
3
+ handle: (error) => {
4
+ return error instanceof Error && error.message.indexOf('The specified block list is invalid.') > -1;
5
+ },
6
+ wait: () => 0,
7
+ };
8
+ //# sourceMappingURL=blockListIsInvalidRetryPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockListIsInvalidRetryPolicy.js","sourceRoot":"","sources":["../../src/retry/blockListIsInvalidRetryPolicy.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,6BAA6B,GAAgB;IACxD,UAAU,EAAE,CAAC;IACb,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QAChB,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,sCAAsC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;CACd,CAAC","sourcesContent":["import type { RetryPolicy } from '../types/RetryPolicy.js';\n\nexport const blockListIsInvalidRetryPolicy: RetryPolicy = {\n maxRetries: 1,\n handle: (error) => {\n return error instanceof Error && error.message.indexOf('The specified block list is invalid.') > -1;\n },\n wait: () => 0,\n};\n"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.36.3"
8
+ "packageVersion": "7.36.4"
9
9
  }
10
10
  ]
11
11
  }
@@ -4,6 +4,7 @@ export interface ConnectionStringOptions {
4
4
  permissions: {
5
5
  read: boolean;
6
6
  write: boolean;
7
+ list: boolean;
7
8
  };
8
9
  isInteractiveLogin: boolean;
9
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionStringOptions.d.ts","sourceRoot":"","sources":["../../src/types/ConnectionStringOptions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE;QACX,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,kBAAkB,EAAE,OAAO,CAAC;CAC7B"}
1
+ {"version":3,"file":"ConnectionStringOptions.d.ts","sourceRoot":"","sources":["../../src/types/ConnectionStringOptions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE;QACX,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;QACf,IAAI,EAAE,OAAO,CAAC;KACf,CAAC;IACF,kBAAkB,EAAE,OAAO,CAAC;CAC7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionStringOptions.js","sourceRoot":"","sources":["../../src/types/ConnectionStringOptions.ts"],"names":[],"mappings":"","sourcesContent":["export interface ConnectionStringOptions {\n storageAccount: string;\n container: string;\n permissions: {\n read: boolean;\n write: boolean;\n };\n isInteractiveLogin: boolean;\n}\n"]}
1
+ {"version":3,"file":"ConnectionStringOptions.js","sourceRoot":"","sources":["../../src/types/ConnectionStringOptions.ts"],"names":[],"mappings":"","sourcesContent":["export interface ConnectionStringOptions {\n storageAccount: string;\n container: string;\n permissions: {\n read: boolean;\n write: boolean;\n list: boolean;\n };\n isInteractiveLogin: boolean;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ export type RetryPolicy = {
2
+ /**
3
+ * The maximum number of retries.
4
+ */
5
+ maxRetries: number;
6
+ /**
7
+ * Given the error, return true if the operation should be handled by this policy.
8
+ */
9
+ handle: (error: unknown) => boolean;
10
+ /**
11
+ * Given the retry attempt, return the number of milliseconds to wait before retrying.
12
+ */
13
+ wait: (retryAttempt: number) => number;
14
+ };
15
+ //# sourceMappingURL=RetryPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryPolicy.d.ts","sourceRoot":"","sources":["../../src/types/RetryPolicy.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAEpC;;OAEG;IACH,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RetryPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RetryPolicy.js","sourceRoot":"","sources":["../../src/types/RetryPolicy.ts"],"names":[],"mappings":"","sourcesContent":["export type RetryPolicy = {\n /**\n * The maximum number of retries.\n */\n maxRetries: number;\n\n /**\n * Given the error, return true if the operation should be handled by this policy.\n */\n handle: (error: unknown) => boolean;\n\n /**\n * Given the retry attempt, return the number of milliseconds to wait before retrying.\n */\n wait: (retryAttempt: number) => number;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ms-cloudpack/remote-cache",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Manages syncing the local Cloudpack cached assets to/from a remote storage service.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- {"version":3,"file":"RemoteCacheClientWithReporter.d.ts","sourceRoot":"","sources":["../src/RemoteCacheClientWithReporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEzG,qBAAa,6BAA8B,YAAW,iBAAiB;IAEnE,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,YAAY;IAGnC,YAAY,CAAC,OAAO,EAAE,iCAAiC;IAgCvD,cAAc,CAAC,OAAO,EAAE,iCAAiC;CA+BhE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RemoteCacheClientWithReporter.js","sourceRoot":"","sources":["../src/RemoteCacheClientWithReporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC;AAG9E,MAAM,OAAO,6BAA6B;IACxC,YACmB,MAAyB,EACzB,QAAsB;QADtB,WAAM,GAAN,MAAM,CAAmB;QACzB,aAAQ,GAAR,QAAQ,CAAc;IACtC,CAAC;IAEJ,KAAK,CAAC,YAAY,CAAC,OAA0C;QAC3D,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC;QAEjF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE7D,QAAQ,YAAY,EAAE;YACpB,KAAK,SAAS;gBACZ,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,UAAU;oBAClB,OAAO,EAAE,YAAY,CAAC,CAAC,eAAe,UAAU,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC;iBAC/F,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,+BAA+B;iBACzC,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,eAAe;gBAClB,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,+CAA+C;iBACzD,CAAC,CAAC;gBACH,MAAM;YACR;gBACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;SAC7D;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAA0C;QAC7D,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,kCAAkC,YAAY,EAAE,CAAC,CAAC;QAErF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAEjE,QAAQ,cAAc,EAAE;YACtB,KAAK,SAAS;gBACZ,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,UAAU;oBAClB,OAAO,EAAE,YAAY,CAAC,CAAC,eAAe,UAAU,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC;iBAC/F,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,gCAAgC;iBAC1C,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,eAAe;gBAClB,IAAI,CAAC,QAAQ,CAAC;oBACZ,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,8CAA8C;iBACxD,CAAC,CAAC;gBACH,MAAM;YACR;gBACE,MAAM,IAAI,KAAK,CAAC,4BAA4B,cAAc,EAAE,CAAC,CAAC;SACjE;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;CACF","sourcesContent":["import { bulletedList, type TaskReporter } from '@ms-cloudpack/task-reporter';\nimport type { RemoteCacheClient, RemoteCacheClientOperationOptions } from './types/RemoteCacheClient.js';\n\nexport class RemoteCacheClientWithReporter implements RemoteCacheClient {\n constructor(\n private readonly client: RemoteCacheClient,\n private readonly reporter: TaskReporter,\n ) {}\n\n async uploadFolder(options: RemoteCacheClientOperationOptions) {\n const { folderName, path, friendlyName } = options;\n const task = this.reporter.addTask(`Uploading to remote cache: ${friendlyName}`);\n\n const uploadResult = await this.client.uploadFolder(options);\n\n switch (uploadResult) {\n case 'success':\n task.complete({\n status: 'complete',\n details: bulletedList([`FolderName: ${folderName}`, `Path: ${path}`, `Name: ${friendlyName}`]),\n });\n break;\n case 'not-found':\n task.complete({\n status: 'skip',\n message: `Not found in the local cache.`,\n });\n break;\n case 'already-exist':\n task.complete({\n status: 'skip',\n message: `Package is already exist in the remote cache.`,\n });\n break;\n default:\n throw new Error(`Unknown upload result: ${uploadResult}`);\n }\n\n return uploadResult;\n }\n\n async downloadFolder(options: RemoteCacheClientOperationOptions) {\n const { folderName, path, friendlyName } = options;\n const task = this.reporter.addTask(`Downloading from remote cache: ${friendlyName}`);\n\n const downloadResult = await this.client.downloadFolder(options);\n\n switch (downloadResult) {\n case 'success':\n task.complete({\n status: 'complete',\n details: bulletedList([`FolderName: ${folderName}`, `Path: ${path}`, `Name: ${friendlyName}`]),\n });\n break;\n case 'not-found':\n task.complete({\n status: 'skip',\n message: `Not found in the remote cache.`,\n });\n break;\n case 'already-exist':\n task.complete({\n status: 'skip',\n message: `Package is already exist in the local cache.`,\n });\n break;\n default:\n throw new Error(`Unknown download result: ${downloadResult}`);\n }\n\n return downloadResult;\n }\n}\n"]}