@alepha/bucket-azure 0.9.3 → 0.9.5

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
@@ -10,20 +10,28 @@ This package is part of the Alepha framework and can be installed via the all-in
10
10
  npm install alepha
11
11
  ```
12
12
 
13
- Alternatively, you can install it individually:
14
-
15
- ```bash
16
- npm install @alepha/core @alepha/bucket-azure
17
- ```
18
-
19
13
  ## Module
20
14
 
21
15
  Plugin for Alepha Bucket that provides Azure Blob Storage capabilities.
22
16
 
17
+ This module can be imported and used as follows:
18
+
19
+ ```typescript
20
+ import { Alepha, run } from "alepha";
21
+ import { AlephaBucketAzure } from "alepha/bucket/azure";
22
+
23
+ const alepha = Alepha.create()
24
+ .with(AlephaBucketAzure);
25
+
26
+ run(alepha);
27
+ ```
28
+
23
29
  ## API Reference
24
30
 
25
31
  ### Providers
26
32
 
33
+ Providers are classes that encapsulate specific functionality and can be injected into your application. They handle initialization, configuration, and lifecycle management.
34
+
27
35
  #### AzureFileStorageProvider
28
36
 
29
37
  Azure Blog Storage implementation of File Storage Provider.
package/dist/index.cjs CHANGED
@@ -27,6 +27,7 @@ const node_crypto = __toESM(require("node:crypto"));
27
27
  const node_stream = __toESM(require("node:stream"));
28
28
  const __alepha_datetime = __toESM(require("@alepha/datetime"));
29
29
  const __alepha_file = __toESM(require("@alepha/file"));
30
+ const __alepha_logger = __toESM(require("@alepha/logger"));
30
31
  const __azure_storage_blob = __toESM(require("@azure/storage-blob"));
31
32
 
32
33
  //#region src/providers/AzureFileStorageProvider.ts
@@ -35,7 +36,7 @@ const envSchema = __alepha_core.t.object({ AZ_STORAGE_CONNECTION_STRING: __aleph
35
36
  * Azure Blog Storage implementation of File Storage Provider.
36
37
  */
37
38
  var AzureFileStorageProvider = class {
38
- log = (0, __alepha_core.$logger)();
39
+ log = (0, __alepha_logger.$logger)();
39
40
  env = (0, __alepha_core.$env)(envSchema);
40
41
  alepha = (0, __alepha_core.$inject)(__alepha_core.Alepha);
41
42
  time = (0, __alepha_core.$inject)(__alepha_datetime.DateTimeProvider);
@@ -50,21 +51,19 @@ var AzureFileStorageProvider = class {
50
51
  handler: async () => {
51
52
  for (const bucket of this.alepha.descriptors(__alepha_bucket.$bucket)) {
52
53
  if (bucket.provider !== this) continue;
53
- const containerName = bucket.name.replaceAll("/", "-").toLowerCase();
54
- this.log.debug(`Prepare container ${containerName}...`);
54
+ const containerName = this.convertName(bucket.name);
55
+ this.log.debug(`Prepare container '${containerName}' ...`);
55
56
  if (!this.containers[containerName]) this.containers[containerName] = await this.createContainerClient(containerName);
56
- this.log.info(`Container ${bucket} OK`);
57
+ this.log.info(`Container '${bucket.name}' OK`);
57
58
  }
58
59
  }
59
60
  });
60
- async createContainer(containerName) {
61
- if (this.containers[containerName]) return this.containers[containerName];
62
- const container = await this.createContainerClient(containerName);
63
- this.containers[containerName] = container;
64
- return container;
61
+ convertName(name) {
62
+ return name.replaceAll("/", "-").toLowerCase();
65
63
  }
66
64
  async upload(bucketName, file, fileId) {
67
65
  fileId ??= this.createId();
66
+ this.log.trace(`Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`);
68
67
  const block = this.getBlock(bucketName, fileId);
69
68
  const metadata = {
70
69
  name: file.name,
@@ -85,6 +84,7 @@ var AzureFileStorageProvider = class {
85
84
  return fileId;
86
85
  }
87
86
  async download(bucketName, fileId) {
87
+ this.log.trace(`Downloading file '${fileId}' from bucket '${bucketName}'...`);
88
88
  const block = this.getBlock(bucketName, fileId);
89
89
  const blob = await block.download().catch((error) => {
90
90
  if (error instanceof Error) throw new __alepha_bucket.FileNotFoundError("Error downloading file", { cause: error });
@@ -97,9 +97,11 @@ var AzureFileStorageProvider = class {
97
97
  });
98
98
  }
99
99
  async exists(bucketName, fileId) {
100
+ this.log.trace(`Checking existence of file '${fileId}' in bucket '${bucketName}'...`);
100
101
  return await this.getBlock(bucketName, fileId).exists();
101
102
  }
102
103
  async delete(bucketName, fileId) {
104
+ this.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);
103
105
  try {
104
106
  await this.getBlock(bucketName, fileId).delete();
105
107
  } catch (error) {
@@ -108,8 +110,9 @@ var AzureFileStorageProvider = class {
108
110
  }
109
111
  }
110
112
  getBlock(container, fileId) {
111
- if (!this.containers[container]) throw new __alepha_bucket.FileNotFoundError(`File '${fileId}' not found - container '${container}' does not exists`);
112
- return this.containers[container].getBlockBlobClient(fileId);
113
+ const containerName = this.convertName(container);
114
+ if (!this.containers[containerName]) throw new __alepha_bucket.FileNotFoundError(`File '${fileId}' not found - container '${container}' does not exists`);
115
+ return this.containers[containerName].getBlockBlobClient(fileId);
113
116
  }
114
117
  async createContainerClient(name) {
115
118
  const container = this.blobServiceClient.getContainerClient(name);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Alepha","DateTimeProvider","$bucket","containerName: string","bucketName: string","file: FileLike","fileId?: string","fileId: string","FileNotFoundError","container: string","name: string","FileStorageProvider","AlephaBucket"],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\t$logger,\n\tAlepha,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport {\n\tBlobServiceClient,\n\ttype BlockBlobClient,\n\ttype ContainerClient,\n\ttype StoragePipelineOptions,\n} from \"@azure/storage-blob\";\n\nconst envSchema = t.object({\n\tAZ_STORAGE_CONNECTION_STRING: t.string({\n\t\tsize: \"long\",\n\t}),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Azure Blog Storage implementation of File Storage Provider.\n */\nexport class AzureFileStorageProvider implements FileStorageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly time = $inject(DateTimeProvider);\n\tprotected readonly containers: Record<string, ContainerClient> = {};\n\tprotected readonly blobServiceClient: BlobServiceClient;\n\n\tpublic readonly options: StoragePipelineOptions = {};\n\n\tconstructor() {\n\t\tthis.blobServiceClient = BlobServiceClient.fromConnectionString(\n\t\t\tthis.env.AZ_STORAGE_CONNECTION_STRING,\n\t\t\tthis.options,\n\t\t);\n\t}\n\n\tprotected readonly onStart = $hook({\n\t\ton: \"start\",\n\t\thandler: async () => {\n\t\t\tfor (const bucket of this.alepha.descriptors($bucket)) {\n\t\t\t\tif (bucket.provider !== this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst containerName = bucket.name.replaceAll(\"/\", \"-\").toLowerCase();\n\t\t\t\tthis.log.debug(`Prepare container ${containerName}...`);\n\n\t\t\t\tif (!this.containers[containerName]) {\n\t\t\t\t\tthis.containers[containerName] =\n\t\t\t\t\t\tawait this.createContainerClient(containerName);\n\t\t\t\t}\n\n\t\t\t\tthis.log.info(`Container ${bucket} OK`);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic async createContainer(\n\t\tcontainerName: string,\n\t): Promise<ContainerClient> {\n\t\tif (this.containers[containerName]) {\n\t\t\treturn this.containers[containerName];\n\t\t}\n\t\tconst container = await this.createContainerClient(containerName);\n\t\tthis.containers[containerName] = container;\n\t\treturn container;\n\t}\n\n\tpublic async upload(\n\t\tbucketName: string,\n\t\tfile: FileLike,\n\t\tfileId?: string,\n\t): Promise<string> {\n\t\tfileId ??= this.createId();\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst metadata = {\n\t\t\tname: file.name,\n\t\t\ttype: file.type,\n\t\t};\n\n\t\tif (file.filepath) {\n\t\t\tawait block.uploadFile(file.filepath, {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else if (file.size > 0) {\n\t\t\tawait block.uploadData(await file.arrayBuffer(), {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait block.uploadStream(\n\t\t\t\tReadable.from(file.stream()),\n\t\t\t\tfile.size || undefined,\n\t\t\t\t5,\n\t\t\t\t{\n\t\t\t\t\tmetadata,\n\t\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn fileId;\n\t}\n\n\tpublic async download(bucketName: string, fileId: string): Promise<FileLike> {\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst blob = await block.download().catch((error) => {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error downloading file\", { cause: error });\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t});\n\n\t\tif (!blob.readableStreamBody) {\n\t\t\tthrow new FileNotFoundError(\"File not found - empty stream body\");\n\t\t}\n\n\t\treturn createFile(blob.readableStreamBody, {\n\t\t\t...blob.metadata,\n\t\t\tsize: blob.contentLength,\n\t\t});\n\t}\n\n\tpublic async exists(bucketName: string, fileId: string): Promise<boolean> {\n\t\treturn await this.getBlock(bucketName, fileId).exists();\n\t}\n\n\tpublic async delete(bucketName: string, fileId: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.getBlock(bucketName, fileId).delete();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error deleting file\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getBlock(container: string, fileId: string): BlockBlobClient {\n\t\tif (!this.containers[container]) {\n\t\t\tthrow new FileNotFoundError(\n\t\t\t\t`File '${fileId}' not found - container '${container}' does not exists`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.containers[container].getBlockBlobClient(fileId);\n\t}\n\n\tprotected async createContainerClient(\n\t\tname: string,\n\t): Promise<ContainerClient> {\n\t\tconst container = this.blobServiceClient.getContainerClient(name);\n\n\t\tawait this.time.deadline(\n\t\t\t(abortSignal) => container.createIfNotExists({ abortSignal }),\n\t\t\t[5, \"seconds\"],\n\t\t);\n\n\t\treturn container;\n\t}\n\n\tprotected createId(): string {\n\t\treturn randomUUID();\n\t}\n}\n","import { AlephaBucket, FileStorageProvider } from \"@alepha/bucket\";\nimport { $module } from \"@alepha/core\";\nimport { AzureFileStorageProvider } from \"./providers/AzureFileStorageProvider.ts\";\n\nexport * from \"./providers/AzureFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Bucket that provides Azure Blob Storage capabilities.\n *\n * @see {@link AzureFileStorageProvider}\n * @module alepha.bucket.azure\n */\nexport const AlephaBucketAzure = $module({\n\tname: \"alepha.bucket.azure\",\n\tservices: [AzureFileStorageProvider],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with({\n\t\t\t\toptional: true,\n\t\t\t\tprovide: FileStorageProvider,\n\t\t\t\tuse: AzureFileStorageProvider,\n\t\t\t})\n\t\t\t.with(AlephaBucket),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["t","Alepha","DateTimeProvider","BlobServiceClient","$bucket","Readable","FileNotFoundError","FileStorageProvider","AlephaBucket"],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport { $logger } from \"@alepha/logger\";\nimport {\n\tBlobServiceClient,\n\ttype BlockBlobClient,\n\ttype ContainerClient,\n\ttype StoragePipelineOptions,\n} from \"@azure/storage-blob\";\n\nconst envSchema = t.object({\n\tAZ_STORAGE_CONNECTION_STRING: t.string({\n\t\tsize: \"long\",\n\t}),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Azure Blog Storage implementation of File Storage Provider.\n */\nexport class AzureFileStorageProvider implements FileStorageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly time = $inject(DateTimeProvider);\n\tprotected readonly containers: Record<string, ContainerClient> = {};\n\tprotected readonly blobServiceClient: BlobServiceClient;\n\n\tpublic readonly options: StoragePipelineOptions = {};\n\n\tconstructor() {\n\t\tthis.blobServiceClient = BlobServiceClient.fromConnectionString(\n\t\t\tthis.env.AZ_STORAGE_CONNECTION_STRING,\n\t\t\tthis.options,\n\t\t);\n\t}\n\n\tprotected readonly onStart = $hook({\n\t\ton: \"start\",\n\t\thandler: async () => {\n\t\t\tfor (const bucket of this.alepha.descriptors($bucket)) {\n\t\t\t\tif (bucket.provider !== this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst containerName = this.convertName(bucket.name);\n\n\t\t\t\tthis.log.debug(`Prepare container '${containerName}' ...`);\n\n\t\t\t\tif (!this.containers[containerName]) {\n\t\t\t\t\tthis.containers[containerName] =\n\t\t\t\t\t\tawait this.createContainerClient(containerName);\n\t\t\t\t}\n\n\t\t\t\tthis.log.info(`Container '${bucket.name}' OK`);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic convertName(name: string): string {\n\t\t// Azure Blob Storage does not allow uppercase letters in container names\n\t\treturn name.replaceAll(\"/\", \"-\").toLowerCase();\n\t}\n\n\tpublic async upload(\n\t\tbucketName: string,\n\t\tfile: FileLike,\n\t\tfileId?: string,\n\t): Promise<string> {\n\t\tfileId ??= this.createId();\n\n\t\tthis.log.trace(\n\t\t\t`Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`,\n\t\t);\n\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst metadata = {\n\t\t\tname: file.name,\n\t\t\ttype: file.type,\n\t\t};\n\n\t\tif (file.filepath) {\n\t\t\tawait block.uploadFile(file.filepath, {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else if (file.size > 0) {\n\t\t\tawait block.uploadData(await file.arrayBuffer(), {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait block.uploadStream(\n\t\t\t\tReadable.from(file.stream()),\n\t\t\t\tfile.size || undefined,\n\t\t\t\t5,\n\t\t\t\t{\n\t\t\t\t\tmetadata,\n\t\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn fileId;\n\t}\n\n\tpublic async download(bucketName: string, fileId: string): Promise<FileLike> {\n\t\tthis.log.trace(\n\t\t\t`Downloading file '${fileId}' from bucket '${bucketName}'...`,\n\t\t);\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst blob = await block.download().catch((error) => {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error downloading file\", { cause: error });\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t});\n\n\t\tif (!blob.readableStreamBody) {\n\t\t\tthrow new FileNotFoundError(\"File not found - empty stream body\");\n\t\t}\n\n\t\treturn createFile(blob.readableStreamBody, {\n\t\t\t...blob.metadata,\n\t\t\tsize: blob.contentLength,\n\t\t});\n\t}\n\n\tpublic async exists(bucketName: string, fileId: string): Promise<boolean> {\n\t\tthis.log.trace(\n\t\t\t`Checking existence of file '${fileId}' in bucket '${bucketName}'...`,\n\t\t);\n\t\treturn await this.getBlock(bucketName, fileId).exists();\n\t}\n\n\tpublic async delete(bucketName: string, fileId: string): Promise<void> {\n\t\tthis.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);\n\t\ttry {\n\t\t\tawait this.getBlock(bucketName, fileId).delete();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error deleting file\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getBlock(container: string, fileId: string): BlockBlobClient {\n\t\tconst containerName = this.convertName(container);\n\n\t\tif (!this.containers[containerName]) {\n\t\t\tthrow new FileNotFoundError(\n\t\t\t\t`File '${fileId}' not found - container '${container}' does not exists`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.containers[containerName].getBlockBlobClient(fileId);\n\t}\n\n\tprotected async createContainerClient(\n\t\tname: string,\n\t): Promise<ContainerClient> {\n\t\tconst container = this.blobServiceClient.getContainerClient(name);\n\n\t\tawait this.time.deadline(\n\t\t\t(abortSignal) => container.createIfNotExists({ abortSignal }),\n\t\t\t[5, \"seconds\"],\n\t\t);\n\n\t\treturn container;\n\t}\n\n\tprotected createId(): string {\n\t\treturn randomUUID();\n\t}\n}\n","import { AlephaBucket, FileStorageProvider } from \"@alepha/bucket\";\nimport { $module } from \"@alepha/core\";\nimport { AzureFileStorageProvider } from \"./providers/AzureFileStorageProvider.ts\";\n\nexport * from \"./providers/AzureFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Bucket that provides Azure Blob Storage capabilities.\n *\n * @see {@link AzureFileStorageProvider}\n * @module alepha.bucket.azure\n */\nexport const AlephaBucketAzure = $module({\n\tname: \"alepha.bucket.azure\",\n\tservices: [AzureFileStorageProvider],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with({\n\t\t\t\toptional: true,\n\t\t\t\tprovide: FileStorageProvider,\n\t\t\t\tuse: AzureFileStorageProvider,\n\t\t\t})\n\t\t\t.with(AlephaBucket),\n});\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _alepha_core1 from "@alepha/core";
2
- import * as _alepha_core0 from "@alepha/core";
3
2
  import { Alepha, FileLike, Static } from "@alepha/core";
3
+ import * as _alepha_logger0 from "@alepha/logger";
4
4
  import { FileStorageProvider } from "@alepha/bucket";
5
5
  import { DateTimeProvider } from "@alepha/datetime";
6
6
  import { BlobServiceClient, BlockBlobClient, ContainerClient, StoragePipelineOptions } from "@azure/storage-blob";
@@ -16,7 +16,7 @@ declare module "@alepha/core" {
16
16
  * Azure Blog Storage implementation of File Storage Provider.
17
17
  */
18
18
  declare class AzureFileStorageProvider implements FileStorageProvider {
19
- protected readonly log: _alepha_core1.Logger;
19
+ protected readonly log: _alepha_logger0.Logger;
20
20
  protected readonly env: {
21
21
  AZ_STORAGE_CONNECTION_STRING: string;
22
22
  };
@@ -27,7 +27,7 @@ declare class AzureFileStorageProvider implements FileStorageProvider {
27
27
  readonly options: StoragePipelineOptions;
28
28
  constructor();
29
29
  protected readonly onStart: _alepha_core1.HookDescriptor<"start">;
30
- createContainer(containerName: string): Promise<ContainerClient>;
30
+ convertName(name: string): string;
31
31
  upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
32
32
  download(bucketName: string, fileId: string): Promise<FileLike>;
33
33
  exists(bucketName: string, fileId: string): Promise<boolean>;
@@ -44,9 +44,7 @@ declare class AzureFileStorageProvider implements FileStorageProvider {
44
44
  * @see {@link AzureFileStorageProvider}
45
45
  * @module alepha.bucket.azure
46
46
  */
47
- declare const AlephaBucketAzure: _alepha_core0.Service<_alepha_core0.Module>;
48
- //# sourceMappingURL=index.d.ts.map
49
-
47
+ declare const AlephaBucketAzure: _alepha_core1.Service<_alepha_core1.Module>;
50
48
  //#endregion
51
49
  export { AlephaBucketAzure, AzureFileStorageProvider };
52
50
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cA0BM,yBAAS;gCAIb,aAAA,CAAA;;;EAJI,UAAA,GAIJ,SAGqB,OAHrB,CAG6B,MAH7B,CAAA,OAG2C,SAH3C,CAAA,CAAA,CAAA,CAAA;;;AAJa;AAAA;AAAA,cAaF,wBAAA,YAAoC,mBAblC,CAAA;EAAA,mBAO8B,GAAA,EAMP,aAAA,CACf,MAPsB;EAAS,mBAAvB,GAAA,EAAA;IAAR,4BAAA,EAAA,MAAA;EAAO,CAAA;EAAA,mBAAA,MAAA,EASJ,MATI;EAMjB,mBAAA,IAAA,EAIW,gBAJc;EAAA,mBAAA,UAAA,EAKN,MALM,CAAA,MAAA,EAKS,eALT,CAAA;EAAA,mBACf,iBAAA,EAKgB,iBALhB;EAAA,SAEG,OAAA,EAKA,sBALA;EAAA,WACF,CAAA;EAAA,mBACuB,OAAA,EAGC,aAAA,CASrB,cAZoB,CAAA,OAAA,CAAA;EAAe,eAA9B,CAAA,aAAA,EAAA,MAAA,CAAA,EAmC5B,OAnC4B,CAmCpB,eAnCoB,CAAA;EAAM,MACC,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EA6C/B,QA7C+B,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA+CnC,OA/CmC,CAAA,MAAA,CAAA;EAAiB,QAE9B,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAqFkC,OArFlC,CAqF0C,QArF1C,CAAA;EAAsB,MAAA,CAAA,UASrB,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAiG+B,OAjG/B,CAAA,OAAA,CAAA;EAAA,MAuBf,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA8E8C,OA9E9C,CAAA,IAAA,CAAA;EAAe,QAAvB,CAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAyFiD,eAzFjD;EAAO,UAWH,qBAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EA0FJ,OA1FI,CA0FI,eA1FJ,CAAA;EAAQ,UAEZ,QAAA,CAAA,CAAA,EAAA,MAAA;;;;;;;;;;cC9ES,mBAAiB,aAAA,CAAA,QAW5B,aAAA,CAX4B,MAAA;ADUD"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cA0BM,yBAAS;gCAIb,aAAA,CAAA;;;EAJI,UAAA,GAIJ,SAGqB,OAHrB,CAG6B,MAH7B,CAAA,OAG2C,SAH3C,CAAA,CAAA,CAAA,CAAA;;;;AAJa;AAAA,cAaF,wBAAA,YAAoC,mBAblC,CAAA;qBAO8B,GAAA,EAMP,eAAA,CACf,MAPsB;qBAAd,GAAA,EAAA;IAAR,4BAAA,EAAA,MAAA;EAAO,CAAA;EAAA,mBAAA,MAAA,EASJ,MATI;EAMjB,mBAAA,IAAA,EAIW,gBAJc;EAAA,mBAAA,UAAA,EAKN,MALM,CAAA,MAAA,EAKS,eALT,CAAA;qBACf,iBAAA,EAKgB,iBALhB;WAEG,OAAA,EAKA,sBALA;aACF,CAAA;qBACuB,OAAA,EAGC,aAAA,CASrB,cAZoB,CAAA,OAAA,CAAA;aAAf,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;QACO,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAwC/B,QAxC+B,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA0CnC,OA1CmC,CAAA,MAAA,CAAA;UAEb,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAqFkC,OArFlC,CAqF0C,QArF1C,CAAA;QAAsB,CAAA,UASrB,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAoG+B,OApG/B,CAAA,OAAA,CAAA;QA6BnB,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA8EkD,OA9ElD,CAAA,IAAA,CAAA;UAEJ,CAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAwFiD,eAxFjD;YA6CgE,qBAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAyDhE,OAzDgE,CAyDxD,eAzDwD,CAAA;YAAR,QAAA,CAAA,CAAA,EAAA,MAAA;;;;;;;;;;cCtH/C,mBAAiB,aAAA,CAAA,QAW5B,aAAA,CAX4B,MAAA"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { FileStorageProvider } from "@alepha/bucket";
2
2
  import * as _alepha_core1 from "@alepha/core";
3
- import * as _alepha_core0 from "@alepha/core";
4
3
  import { Alepha, FileLike, Static } from "@alepha/core";
5
4
  import { DateTimeProvider } from "@alepha/datetime";
5
+ import * as _alepha_logger0 from "@alepha/logger";
6
6
  import { BlobServiceClient, BlockBlobClient, ContainerClient, StoragePipelineOptions } from "@azure/storage-blob";
7
7
 
8
8
  //#region src/providers/AzureFileStorageProvider.d.ts
@@ -16,7 +16,7 @@ declare module "@alepha/core" {
16
16
  * Azure Blog Storage implementation of File Storage Provider.
17
17
  */
18
18
  declare class AzureFileStorageProvider implements FileStorageProvider {
19
- protected readonly log: _alepha_core1.Logger;
19
+ protected readonly log: _alepha_logger0.Logger;
20
20
  protected readonly env: {
21
21
  AZ_STORAGE_CONNECTION_STRING: string;
22
22
  };
@@ -27,7 +27,7 @@ declare class AzureFileStorageProvider implements FileStorageProvider {
27
27
  readonly options: StoragePipelineOptions;
28
28
  constructor();
29
29
  protected readonly onStart: _alepha_core1.HookDescriptor<"start">;
30
- createContainer(containerName: string): Promise<ContainerClient>;
30
+ convertName(name: string): string;
31
31
  upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
32
32
  download(bucketName: string, fileId: string): Promise<FileLike>;
33
33
  exists(bucketName: string, fileId: string): Promise<boolean>;
@@ -44,9 +44,7 @@ declare class AzureFileStorageProvider implements FileStorageProvider {
44
44
  * @see {@link AzureFileStorageProvider}
45
45
  * @module alepha.bucket.azure
46
46
  */
47
- declare const AlephaBucketAzure: _alepha_core0.Service<_alepha_core0.Module>;
48
- //# sourceMappingURL=index.d.ts.map
49
-
47
+ declare const AlephaBucketAzure: _alepha_core1.Service<_alepha_core1.Module>;
50
48
  //#endregion
51
49
  export { AlephaBucketAzure, AzureFileStorageProvider };
52
50
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cA0BM,yBAAS;gCAIb,aAAA,CAAA;;;EAJI,UAAA,GAIJ,SAGqB,OAHrB,CAG6B,MAH7B,CAAA,OAG2C,SAH3C,CAAA,CAAA,CAAA,CAAA;;;AAJa;AAAA;AAAA,cAaF,wBAAA,YAAoC,mBAblC,CAAA;EAAA,mBAO8B,GAAA,EAMP,aAAA,CACf,MAPsB;EAAS,mBAAvB,GAAA,EAAA;IAAR,4BAAA,EAAA,MAAA;EAAO,CAAA;EAAA,mBAAA,MAAA,EASJ,MATI;EAMjB,mBAAA,IAAA,EAIW,gBAJc;EAAA,mBAAA,UAAA,EAKN,MALM,CAAA,MAAA,EAKS,eALT,CAAA;EAAA,mBACf,iBAAA,EAKgB,iBALhB;EAAA,SAEG,OAAA,EAKA,sBALA;EAAA,WACF,CAAA;EAAA,mBACuB,OAAA,EAGC,aAAA,CASrB,cAZoB,CAAA,OAAA,CAAA;EAAe,eAA9B,CAAA,aAAA,EAAA,MAAA,CAAA,EAmC5B,OAnC4B,CAmCpB,eAnCoB,CAAA;EAAM,MACC,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EA6C/B,QA7C+B,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA+CnC,OA/CmC,CAAA,MAAA,CAAA;EAAiB,QAE9B,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAqFkC,OArFlC,CAqF0C,QArF1C,CAAA;EAAsB,MAAA,CAAA,UASrB,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAiG+B,OAjG/B,CAAA,OAAA,CAAA;EAAA,MAuBf,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA8E8C,OA9E9C,CAAA,IAAA,CAAA;EAAe,QAAvB,CAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAyFiD,eAzFjD;EAAO,UAWH,qBAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EA0FJ,OA1FI,CA0FI,eA1FJ,CAAA;EAAQ,UAEZ,QAAA,CAAA,CAAA,EAAA,MAAA;;;;;;;;;;cC9ES,mBAAiB,aAAA,CAAA,QAW5B,aAAA,CAX4B,MAAA;ADUD"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cA0BM,yBAAS;gCAIb,aAAA,CAAA;;;EAJI,UAAA,GAIJ,SAGqB,OAHrB,CAG6B,MAH7B,CAAA,OAG2C,SAH3C,CAAA,CAAA,CAAA,CAAA;;;;AAJa;AAAA,cAaF,wBAAA,YAAoC,mBAblC,CAAA;qBAO8B,GAAA,EAMP,eAAA,CACf,MAPsB;qBAAd,GAAA,EAAA;IAAR,4BAAA,EAAA,MAAA;EAAO,CAAA;EAAA,mBAAA,MAAA,EASJ,MATI;EAMjB,mBAAA,IAAA,EAIW,gBAJc;EAAA,mBAAA,UAAA,EAKN,MALM,CAAA,MAAA,EAKS,eALT,CAAA;qBACf,iBAAA,EAKgB,iBALhB;WAEG,OAAA,EAKA,sBALA;aACF,CAAA;qBACuB,OAAA,EAGC,aAAA,CASrB,cAZoB,CAAA,OAAA,CAAA;aAAf,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;QACO,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EAwC/B,QAxC+B,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA0CnC,OA1CmC,CAAA,MAAA,CAAA;UAEb,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAqFkC,OArFlC,CAqF0C,QArF1C,CAAA;QAAsB,CAAA,UASrB,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAoG+B,OApG/B,CAAA,OAAA,CAAA;QA6BnB,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA8EkD,OA9ElD,CAAA,IAAA,CAAA;UAEJ,CAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAwFiD,eAxFjD;YA6CgE,qBAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAyDhE,OAzDgE,CAyDxD,eAzDwD,CAAA;YAAR,QAAA,CAAA,CAAA,EAAA,MAAA;;;;;;;;;;cCtH/C,mBAAiB,aAAA,CAAA,QAW5B,aAAA,CAX4B,MAAA"}
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { $bucket, AlephaBucket, FileNotFoundError, FileStorageProvider } from "@alepha/bucket";
2
- import { $env, $hook, $inject, $logger, $module, Alepha, t } from "@alepha/core";
2
+ import { $env, $hook, $inject, $module, Alepha, t } from "@alepha/core";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { Readable } from "node:stream";
5
5
  import { DateTimeProvider } from "@alepha/datetime";
6
6
  import { createFile } from "@alepha/file";
7
+ import { $logger } from "@alepha/logger";
7
8
  import { BlobServiceClient } from "@azure/storage-blob";
8
9
 
9
10
  //#region src/providers/AzureFileStorageProvider.ts
@@ -27,21 +28,19 @@ var AzureFileStorageProvider = class {
27
28
  handler: async () => {
28
29
  for (const bucket of this.alepha.descriptors($bucket)) {
29
30
  if (bucket.provider !== this) continue;
30
- const containerName = bucket.name.replaceAll("/", "-").toLowerCase();
31
- this.log.debug(`Prepare container ${containerName}...`);
31
+ const containerName = this.convertName(bucket.name);
32
+ this.log.debug(`Prepare container '${containerName}' ...`);
32
33
  if (!this.containers[containerName]) this.containers[containerName] = await this.createContainerClient(containerName);
33
- this.log.info(`Container ${bucket} OK`);
34
+ this.log.info(`Container '${bucket.name}' OK`);
34
35
  }
35
36
  }
36
37
  });
37
- async createContainer(containerName) {
38
- if (this.containers[containerName]) return this.containers[containerName];
39
- const container = await this.createContainerClient(containerName);
40
- this.containers[containerName] = container;
41
- return container;
38
+ convertName(name) {
39
+ return name.replaceAll("/", "-").toLowerCase();
42
40
  }
43
41
  async upload(bucketName, file, fileId) {
44
42
  fileId ??= this.createId();
43
+ this.log.trace(`Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`);
45
44
  const block = this.getBlock(bucketName, fileId);
46
45
  const metadata = {
47
46
  name: file.name,
@@ -62,6 +61,7 @@ var AzureFileStorageProvider = class {
62
61
  return fileId;
63
62
  }
64
63
  async download(bucketName, fileId) {
64
+ this.log.trace(`Downloading file '${fileId}' from bucket '${bucketName}'...`);
65
65
  const block = this.getBlock(bucketName, fileId);
66
66
  const blob = await block.download().catch((error) => {
67
67
  if (error instanceof Error) throw new FileNotFoundError("Error downloading file", { cause: error });
@@ -74,9 +74,11 @@ var AzureFileStorageProvider = class {
74
74
  });
75
75
  }
76
76
  async exists(bucketName, fileId) {
77
+ this.log.trace(`Checking existence of file '${fileId}' in bucket '${bucketName}'...`);
77
78
  return await this.getBlock(bucketName, fileId).exists();
78
79
  }
79
80
  async delete(bucketName, fileId) {
81
+ this.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);
80
82
  try {
81
83
  await this.getBlock(bucketName, fileId).delete();
82
84
  } catch (error) {
@@ -85,8 +87,9 @@ var AzureFileStorageProvider = class {
85
87
  }
86
88
  }
87
89
  getBlock(container, fileId) {
88
- if (!this.containers[container]) throw new FileNotFoundError(`File '${fileId}' not found - container '${container}' does not exists`);
89
- return this.containers[container].getBlockBlobClient(fileId);
90
+ const containerName = this.convertName(container);
91
+ if (!this.containers[containerName]) throw new FileNotFoundError(`File '${fileId}' not found - container '${container}' does not exists`);
92
+ return this.containers[containerName].getBlockBlobClient(fileId);
90
93
  }
91
94
  async createContainerClient(name) {
92
95
  const container = this.blobServiceClient.getContainerClient(name);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["containerName: string","bucketName: string","file: FileLike","fileId?: string","fileId: string","container: string","name: string"],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\t$logger,\n\tAlepha,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport {\n\tBlobServiceClient,\n\ttype BlockBlobClient,\n\ttype ContainerClient,\n\ttype StoragePipelineOptions,\n} from \"@azure/storage-blob\";\n\nconst envSchema = t.object({\n\tAZ_STORAGE_CONNECTION_STRING: t.string({\n\t\tsize: \"long\",\n\t}),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Azure Blog Storage implementation of File Storage Provider.\n */\nexport class AzureFileStorageProvider implements FileStorageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly time = $inject(DateTimeProvider);\n\tprotected readonly containers: Record<string, ContainerClient> = {};\n\tprotected readonly blobServiceClient: BlobServiceClient;\n\n\tpublic readonly options: StoragePipelineOptions = {};\n\n\tconstructor() {\n\t\tthis.blobServiceClient = BlobServiceClient.fromConnectionString(\n\t\t\tthis.env.AZ_STORAGE_CONNECTION_STRING,\n\t\t\tthis.options,\n\t\t);\n\t}\n\n\tprotected readonly onStart = $hook({\n\t\ton: \"start\",\n\t\thandler: async () => {\n\t\t\tfor (const bucket of this.alepha.descriptors($bucket)) {\n\t\t\t\tif (bucket.provider !== this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst containerName = bucket.name.replaceAll(\"/\", \"-\").toLowerCase();\n\t\t\t\tthis.log.debug(`Prepare container ${containerName}...`);\n\n\t\t\t\tif (!this.containers[containerName]) {\n\t\t\t\t\tthis.containers[containerName] =\n\t\t\t\t\t\tawait this.createContainerClient(containerName);\n\t\t\t\t}\n\n\t\t\t\tthis.log.info(`Container ${bucket} OK`);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic async createContainer(\n\t\tcontainerName: string,\n\t): Promise<ContainerClient> {\n\t\tif (this.containers[containerName]) {\n\t\t\treturn this.containers[containerName];\n\t\t}\n\t\tconst container = await this.createContainerClient(containerName);\n\t\tthis.containers[containerName] = container;\n\t\treturn container;\n\t}\n\n\tpublic async upload(\n\t\tbucketName: string,\n\t\tfile: FileLike,\n\t\tfileId?: string,\n\t): Promise<string> {\n\t\tfileId ??= this.createId();\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst metadata = {\n\t\t\tname: file.name,\n\t\t\ttype: file.type,\n\t\t};\n\n\t\tif (file.filepath) {\n\t\t\tawait block.uploadFile(file.filepath, {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else if (file.size > 0) {\n\t\t\tawait block.uploadData(await file.arrayBuffer(), {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait block.uploadStream(\n\t\t\t\tReadable.from(file.stream()),\n\t\t\t\tfile.size || undefined,\n\t\t\t\t5,\n\t\t\t\t{\n\t\t\t\t\tmetadata,\n\t\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn fileId;\n\t}\n\n\tpublic async download(bucketName: string, fileId: string): Promise<FileLike> {\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst blob = await block.download().catch((error) => {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error downloading file\", { cause: error });\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t});\n\n\t\tif (!blob.readableStreamBody) {\n\t\t\tthrow new FileNotFoundError(\"File not found - empty stream body\");\n\t\t}\n\n\t\treturn createFile(blob.readableStreamBody, {\n\t\t\t...blob.metadata,\n\t\t\tsize: blob.contentLength,\n\t\t});\n\t}\n\n\tpublic async exists(bucketName: string, fileId: string): Promise<boolean> {\n\t\treturn await this.getBlock(bucketName, fileId).exists();\n\t}\n\n\tpublic async delete(bucketName: string, fileId: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.getBlock(bucketName, fileId).delete();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error deleting file\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getBlock(container: string, fileId: string): BlockBlobClient {\n\t\tif (!this.containers[container]) {\n\t\t\tthrow new FileNotFoundError(\n\t\t\t\t`File '${fileId}' not found - container '${container}' does not exists`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.containers[container].getBlockBlobClient(fileId);\n\t}\n\n\tprotected async createContainerClient(\n\t\tname: string,\n\t): Promise<ContainerClient> {\n\t\tconst container = this.blobServiceClient.getContainerClient(name);\n\n\t\tawait this.time.deadline(\n\t\t\t(abortSignal) => container.createIfNotExists({ abortSignal }),\n\t\t\t[5, \"seconds\"],\n\t\t);\n\n\t\treturn container;\n\t}\n\n\tprotected createId(): string {\n\t\treturn randomUUID();\n\t}\n}\n","import { AlephaBucket, FileStorageProvider } from \"@alepha/bucket\";\nimport { $module } from \"@alepha/core\";\nimport { AzureFileStorageProvider } from \"./providers/AzureFileStorageProvider.ts\";\n\nexport * from \"./providers/AzureFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Bucket that provides Azure Blob Storage capabilities.\n *\n * @see {@link AzureFileStorageProvider}\n * @module alepha.bucket.azure\n */\nexport const AlephaBucketAzure = $module({\n\tname: \"alepha.bucket.azure\",\n\tservices: [AzureFileStorageProvider],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with({\n\t\t\t\toptional: true,\n\t\t\t\tprovide: FileStorageProvider,\n\t\t\t\tuse: AzureFileStorageProvider,\n\t\t\t})\n\t\t\t.with(AlephaBucket),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/providers/AzureFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport { $logger } from \"@alepha/logger\";\nimport {\n\tBlobServiceClient,\n\ttype BlockBlobClient,\n\ttype ContainerClient,\n\ttype StoragePipelineOptions,\n} from \"@azure/storage-blob\";\n\nconst envSchema = t.object({\n\tAZ_STORAGE_CONNECTION_STRING: t.string({\n\t\tsize: \"long\",\n\t}),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Azure Blog Storage implementation of File Storage Provider.\n */\nexport class AzureFileStorageProvider implements FileStorageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly time = $inject(DateTimeProvider);\n\tprotected readonly containers: Record<string, ContainerClient> = {};\n\tprotected readonly blobServiceClient: BlobServiceClient;\n\n\tpublic readonly options: StoragePipelineOptions = {};\n\n\tconstructor() {\n\t\tthis.blobServiceClient = BlobServiceClient.fromConnectionString(\n\t\t\tthis.env.AZ_STORAGE_CONNECTION_STRING,\n\t\t\tthis.options,\n\t\t);\n\t}\n\n\tprotected readonly onStart = $hook({\n\t\ton: \"start\",\n\t\thandler: async () => {\n\t\t\tfor (const bucket of this.alepha.descriptors($bucket)) {\n\t\t\t\tif (bucket.provider !== this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst containerName = this.convertName(bucket.name);\n\n\t\t\t\tthis.log.debug(`Prepare container '${containerName}' ...`);\n\n\t\t\t\tif (!this.containers[containerName]) {\n\t\t\t\t\tthis.containers[containerName] =\n\t\t\t\t\t\tawait this.createContainerClient(containerName);\n\t\t\t\t}\n\n\t\t\t\tthis.log.info(`Container '${bucket.name}' OK`);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic convertName(name: string): string {\n\t\t// Azure Blob Storage does not allow uppercase letters in container names\n\t\treturn name.replaceAll(\"/\", \"-\").toLowerCase();\n\t}\n\n\tpublic async upload(\n\t\tbucketName: string,\n\t\tfile: FileLike,\n\t\tfileId?: string,\n\t): Promise<string> {\n\t\tfileId ??= this.createId();\n\n\t\tthis.log.trace(\n\t\t\t`Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`,\n\t\t);\n\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst metadata = {\n\t\t\tname: file.name,\n\t\t\ttype: file.type,\n\t\t};\n\n\t\tif (file.filepath) {\n\t\t\tawait block.uploadFile(file.filepath, {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else if (file.size > 0) {\n\t\t\tawait block.uploadData(await file.arrayBuffer(), {\n\t\t\t\tmetadata,\n\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait block.uploadStream(\n\t\t\t\tReadable.from(file.stream()),\n\t\t\t\tfile.size || undefined,\n\t\t\t\t5,\n\t\t\t\t{\n\t\t\t\t\tmetadata,\n\t\t\t\t\tblobHTTPHeaders: {\n\t\t\t\t\t\tblobContentType: file.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\treturn fileId;\n\t}\n\n\tpublic async download(bucketName: string, fileId: string): Promise<FileLike> {\n\t\tthis.log.trace(\n\t\t\t`Downloading file '${fileId}' from bucket '${bucketName}'...`,\n\t\t);\n\t\tconst block = this.getBlock(bucketName, fileId);\n\n\t\tconst blob = await block.download().catch((error) => {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error downloading file\", { cause: error });\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t});\n\n\t\tif (!blob.readableStreamBody) {\n\t\t\tthrow new FileNotFoundError(\"File not found - empty stream body\");\n\t\t}\n\n\t\treturn createFile(blob.readableStreamBody, {\n\t\t\t...blob.metadata,\n\t\t\tsize: blob.contentLength,\n\t\t});\n\t}\n\n\tpublic async exists(bucketName: string, fileId: string): Promise<boolean> {\n\t\tthis.log.trace(\n\t\t\t`Checking existence of file '${fileId}' in bucket '${bucketName}'...`,\n\t\t);\n\t\treturn await this.getBlock(bucketName, fileId).exists();\n\t}\n\n\tpublic async delete(bucketName: string, fileId: string): Promise<void> {\n\t\tthis.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);\n\t\ttry {\n\t\t\tawait this.getBlock(bucketName, fileId).delete();\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error deleting file\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getBlock(container: string, fileId: string): BlockBlobClient {\n\t\tconst containerName = this.convertName(container);\n\n\t\tif (!this.containers[containerName]) {\n\t\t\tthrow new FileNotFoundError(\n\t\t\t\t`File '${fileId}' not found - container '${container}' does not exists`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.containers[containerName].getBlockBlobClient(fileId);\n\t}\n\n\tprotected async createContainerClient(\n\t\tname: string,\n\t): Promise<ContainerClient> {\n\t\tconst container = this.blobServiceClient.getContainerClient(name);\n\n\t\tawait this.time.deadline(\n\t\t\t(abortSignal) => container.createIfNotExists({ abortSignal }),\n\t\t\t[5, \"seconds\"],\n\t\t);\n\n\t\treturn container;\n\t}\n\n\tprotected createId(): string {\n\t\treturn randomUUID();\n\t}\n}\n","import { AlephaBucket, FileStorageProvider } from \"@alepha/bucket\";\nimport { $module } from \"@alepha/core\";\nimport { AzureFileStorageProvider } from \"./providers/AzureFileStorageProvider.ts\";\n\nexport * from \"./providers/AzureFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Bucket that provides Azure Blob Storage capabilities.\n *\n * @see {@link AzureFileStorageProvider}\n * @module alepha.bucket.azure\n */\nexport const AlephaBucketAzure = $module({\n\tname: \"alepha.bucket.azure\",\n\tservices: [AzureFileStorageProvider],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with({\n\t\t\t\toptional: true,\n\t\t\t\tprovide: FileStorageProvider,\n\t\t\t\tuse: AzureFileStorageProvider,\n\t\t\t})\n\t\t\t.with(AlephaBucket),\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "storage-blob"
11
11
  ],
12
12
  "author": "Feunard",
13
- "version": "0.9.3",
13
+ "version": "0.9.5",
14
14
  "type": "module",
15
15
  "engines": {
16
16
  "node": ">=22.0.0"
@@ -23,19 +23,24 @@
23
23
  "src"
24
24
  ],
25
25
  "dependencies": {
26
- "@alepha/bucket": "0.9.3",
27
- "@alepha/core": "0.9.3",
28
- "@alepha/datetime": "0.9.3",
29
- "@alepha/file": "0.9.3",
30
- "@azure/storage-blob": "12.28.0"
26
+ "@alepha/bucket": "0.9.5",
27
+ "@alepha/core": "0.9.5",
28
+ "@alepha/datetime": "0.9.5",
29
+ "@alepha/file": "0.9.5",
30
+ "@alepha/logger": "0.9.5",
31
+ "@azure/storage-blob": "^12.29.0"
31
32
  },
32
33
  "devDependencies": {
33
- "tsdown": "^0.13.2",
34
+ "@biomejs/biome": "^2.2.4",
35
+ "tsdown": "^0.15.1",
36
+ "typescript": "^5.9.2",
34
37
  "vitest": "^3.2.4"
35
38
  },
36
39
  "scripts": {
37
40
  "test": "vitest run",
38
- "build": "tsdown -c ../../tsdown.config.ts"
41
+ "lint": "biome check --write --unsafe",
42
+ "build": "tsdown -c ../../tsdown.config.ts",
43
+ "check": "tsc"
39
44
  },
40
45
  "repository": {
41
46
  "type": "git",
@@ -9,7 +9,6 @@ import {
9
9
  $env,
10
10
  $hook,
11
11
  $inject,
12
- $logger,
13
12
  Alepha,
14
13
  type FileLike,
15
14
  type Static,
@@ -17,6 +16,7 @@ import {
17
16
  } from "@alepha/core";
18
17
  import { DateTimeProvider } from "@alepha/datetime";
19
18
  import { createFile } from "@alepha/file";
19
+ import { $logger } from "@alepha/logger";
20
20
  import {
21
21
  BlobServiceClient,
22
22
  type BlockBlobClient,
@@ -62,28 +62,23 @@ export class AzureFileStorageProvider implements FileStorageProvider {
62
62
  continue;
63
63
  }
64
64
 
65
- const containerName = bucket.name.replaceAll("/", "-").toLowerCase();
66
- this.log.debug(`Prepare container ${containerName}...`);
65
+ const containerName = this.convertName(bucket.name);
66
+
67
+ this.log.debug(`Prepare container '${containerName}' ...`);
67
68
 
68
69
  if (!this.containers[containerName]) {
69
70
  this.containers[containerName] =
70
71
  await this.createContainerClient(containerName);
71
72
  }
72
73
 
73
- this.log.info(`Container ${bucket} OK`);
74
+ this.log.info(`Container '${bucket.name}' OK`);
74
75
  }
75
76
  },
76
77
  });
77
78
 
78
- public async createContainer(
79
- containerName: string,
80
- ): Promise<ContainerClient> {
81
- if (this.containers[containerName]) {
82
- return this.containers[containerName];
83
- }
84
- const container = await this.createContainerClient(containerName);
85
- this.containers[containerName] = container;
86
- return container;
79
+ public convertName(name: string): string {
80
+ // Azure Blob Storage does not allow uppercase letters in container names
81
+ return name.replaceAll("/", "-").toLowerCase();
87
82
  }
88
83
 
89
84
  public async upload(
@@ -92,6 +87,11 @@ export class AzureFileStorageProvider implements FileStorageProvider {
92
87
  fileId?: string,
93
88
  ): Promise<string> {
94
89
  fileId ??= this.createId();
90
+
91
+ this.log.trace(
92
+ `Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`,
93
+ );
94
+
95
95
  const block = this.getBlock(bucketName, fileId);
96
96
 
97
97
  const metadata = {
@@ -131,6 +131,9 @@ export class AzureFileStorageProvider implements FileStorageProvider {
131
131
  }
132
132
 
133
133
  public async download(bucketName: string, fileId: string): Promise<FileLike> {
134
+ this.log.trace(
135
+ `Downloading file '${fileId}' from bucket '${bucketName}'...`,
136
+ );
134
137
  const block = this.getBlock(bucketName, fileId);
135
138
 
136
139
  const blob = await block.download().catch((error) => {
@@ -152,10 +155,14 @@ export class AzureFileStorageProvider implements FileStorageProvider {
152
155
  }
153
156
 
154
157
  public async exists(bucketName: string, fileId: string): Promise<boolean> {
158
+ this.log.trace(
159
+ `Checking existence of file '${fileId}' in bucket '${bucketName}'...`,
160
+ );
155
161
  return await this.getBlock(bucketName, fileId).exists();
156
162
  }
157
163
 
158
164
  public async delete(bucketName: string, fileId: string): Promise<void> {
165
+ this.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);
159
166
  try {
160
167
  await this.getBlock(bucketName, fileId).delete();
161
168
  } catch (error) {
@@ -167,13 +174,15 @@ export class AzureFileStorageProvider implements FileStorageProvider {
167
174
  }
168
175
 
169
176
  public getBlock(container: string, fileId: string): BlockBlobClient {
170
- if (!this.containers[container]) {
177
+ const containerName = this.convertName(container);
178
+
179
+ if (!this.containers[containerName]) {
171
180
  throw new FileNotFoundError(
172
181
  `File '${fileId}' not found - container '${container}' does not exists`,
173
182
  );
174
183
  }
175
184
 
176
- return this.containers[container].getBlockBlobClient(fileId);
185
+ return this.containers[containerName].getBlockBlobClient(fileId);
177
186
  }
178
187
 
179
188
  protected async createContainerClient(