@ntegral/strapi-provider-upload-azure-storage-blob
Version:
Strapi provider for uploads to Azure using @azure/storage-blob
207 lines (187 loc) • 5.97 kB
text/typescript
import { DefaultAzureCredential } from "@azure/identity";
import {
AnonymousCredential,
BlobServiceClient,
StorageSharedKeyCredential,
} from "@azure/storage-blob";
type StorageBlobConfig = {
tenant: string;
client: string;
secret: string;
account: string;
accountKey: string;
containerName: string;
connectionString: string;
sasToken: string;
serviceBaseURL: string;
defaultPath: string;
};
type StrapiFile = File & {
path: string;
url: string;
hash: string;
ext: string;
buffer: string;
mime: string;
};
const trimParam = (str: any) =>
typeof str === "string" ? str.trim() : undefined;
// A helper method used to read a Node.js readable stream into a Buffer
async function streamToBuffer(
readableStream: NodeJS.ReadableStream
): Promise<Buffer> {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
readableStream.on("data", (data: Buffer | string) => {
chunks.push(data instanceof Buffer ? data : Buffer.from(data));
});
readableStream.on("end", () => {
resolve(Buffer.concat(chunks));
});
readableStream.on("error", reject);
});
}
const createClient = (config: StorageBlobConfig) => {
const account = <string>trimParam(config.account);
const accountKey = <string>trimParam(config.accountKey);
const connStr = trimParam(config.connectionString);
const tenant = <string>trimParam(config.tenant);
const client = <string>trimParam(config.client);
const secret = <string>trimParam(config.secret);
const sasToken = <string>trimParam(config.sasToken);
const serviceBaseURL =
trimParam(config.serviceBaseURL) ||
`https://${account}.blob.core.windows.net`;
if (tenant && client && secret && account) {
//Azure Active Directory
const defaultCredential = new DefaultAzureCredential();
return new BlobServiceClient(serviceBaseURL, defaultCredential);
} else if (sasToken) {
const anonymousCredential = new AnonymousCredential();
return new BlobServiceClient(
`${serviceBaseURL}${sasToken}`,
anonymousCredential
);
} else if (connStr) {
return BlobServiceClient.fromConnectionString(connStr);
} else if (account && accountKey) {
const sharedKeyCredential = new StorageSharedKeyCredential(
account,
accountKey
);
return new BlobServiceClient(serviceBaseURL, sharedKeyCredential);
} else {
throw new Error(
"Error in configuration, please be sure to configure the Azure account and accountKey or the connectionString."
);
}
};
module.exports = {
provider: "azure-storage-blob",
auth: {
tenant: {
label: "Azure Tenant Id",
type: "text",
},
client: {
label: "Azure Client Id",
type: "text",
},
secret: {
label: "Azure Client Secret",
type: "text",
},
account: {
label: "Account Name",
type: "text",
},
accountKey: {
label: "Secret Access Key",
type: "text",
},
connectionString: {
label: "Connection String",
type: "text",
},
containerName: {
label: "Container name",
type: "text",
},
sasToken: {
label: "SAS Token",
type: "text",
},
defaultPath: {
label: "The path to use when there is none being specified",
type: "text",
},
},
init: (config: StorageBlobConfig) => {
const defaultPath = trimParam(config.defaultPath) || "assets";
const containerName = <string>trimParam(config.containerName);
const client = <BlobServiceClient>createClient(config);
return {
uploadStream(file: StrapiFile, customParams = {}) {
return new Promise<void>(async (resolve, reject) => {
try {
const containerClient = client.getContainerClient(containerName);
// create blobClient for container
const blobClient = containerClient.getBlockBlobClient(
`${defaultPath}/${file.name}`
);
// set mimetype as determined from browser with file upload control
const options = {
blobHTTPHeaders: { blobContentType: file.mime, ...customParams },
};
// convert stream to buffer
const bufferedStream = await streamToBuffer(file.stream as any);
// upload file
await blobClient.uploadData(bufferedStream, options);
// console.log(result)
file.url = blobClient.url;
resolve();
} catch (error) {
reject(error);
}
});
},
upload(file: StrapiFile, customParams = {}) {
return new Promise<void>(async (resolve, reject) => {
try {
const containerClient = client.getContainerClient(containerName);
// create blobClient for container
const blobClient = containerClient.getBlockBlobClient(
`${defaultPath}/${file.name}`
);
// set mimetype as determined from browser with file upload control
const options = {
blobHTTPHeaders: { blobContentType: file.mime, ...customParams },
};
// upload file
await blobClient.uploadData(file, options);
file.url = blobClient.url;
resolve();
} catch (error) {
reject(error);
}
});
},
delete(file: StrapiFile, customParams = {}) {
return new Promise<void>(async (resolve, reject) => {
try {
const containerClient = client.getContainerClient(containerName);
// create blobClient for container
const blobClient = containerClient.getBlobClient(
`${defaultPath}/${file.name}`
);
await blobClient.delete();
file.url = blobClient.url;
resolve();
} catch (error) {
reject(error);
}
});
},
};
},
};