@lucidcms/plugin-s3
Version:
The official S3 plugin for Lucid
342 lines (329 loc) • 9.8 kB
JavaScript
import { AwsClient } from "aws4fetch";
//#region src/clients/aws-client.ts
let awsClient = null;
const getS3Client = (pluginOptions) => {
if (!awsClient) awsClient = new AwsClient(pluginOptions.clientOptions);
return awsClient;
};
var aws_client_default = getS3Client;
//#endregion
//#region src/translations/en-gb.json
var object_body_undefined = "The object get request Body is undefined.";
var object_missing_metadata = "An error occurred while fetching the object metadata.";
var get_metadata_failed = "Get metadata failed with status {{status}} and message {{statusText}}.";
var an_unknown_error_occurred = "An unknown error occurred";
var delete_multiple_failed = "Delete multiple failed with status {{status}} and message {{statusText}}.";
var delete_single_failed = "Delete single failed with status {{status}} and message {{statusText}}.";
var stream_failed = "Stream failed with status {{status}} and message {{statusText}}.";
var upload_failed = "Upload failed with status {{status}} and message {{statusText}}.";
var en_gb_default = {
object_body_undefined,
object_missing_metadata,
get_metadata_failed,
an_unknown_error_occurred,
delete_multiple_failed,
delete_single_failed,
stream_failed,
upload_failed
};
//#endregion
//#region src/translations/index.ts
const selectedLang = en_gb_default;
const T = (key, data) => {
const translation = selectedLang[key];
if (!translation) return key;
if (!data) return translation;
return translation.replace(/\{\{(\w+)\}\}/g, (_, p1) => data[p1]);
};
var translations_default = T;
//#endregion
//#region src/services/steam.ts
var steam_default = (client, pluginOptions) => {
const stream = async (key, options) => {
try {
const headers = {};
if (options?.range) {
const start = options.range.start;
const end = options.range.end;
headers.Range = end !== void 0 ? `bytes=${start}-${end}` : `bytes=${start}-`;
}
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}/${key}`, {
method: "GET",
headers
}));
const result = await fetch(response);
if (!result.ok) return {
error: { message: translations_default("stream_failed", {
status: result.status,
statusText: result.statusText
}) },
data: void 0
};
if (!result.body) return {
error: { message: translations_default("object_body_undefined") },
data: void 0
};
let isPartialContent = false;
let totalSize;
let range;
const contentRange = result.headers.get("content-range");
if (contentRange) {
isPartialContent = true;
const match = contentRange.match(/bytes (\d+)-(\d+)\/(\d+)/);
if (match?.[1] && match[2] && match[3]) {
range = {
start: Number.parseInt(match[1], 10),
end: Number.parseInt(match[2], 10)
};
totalSize = Number.parseInt(match[3], 10);
}
}
const contentLength = result.headers.get("content-length");
const contentType = result.headers.get("content-type");
return {
error: void 0,
data: {
contentLength: contentLength ? Number.parseInt(contentLength, 10) : void 0,
contentType: contentType || void 0,
body: result.body,
isPartialContent,
totalSize: totalSize || (contentLength ? Number.parseInt(contentLength, 10) : void 0),
range
}
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return stream;
};
//#endregion
//#region src/services/delete-single.ts
var delete_single_default = (client, pluginOptions) => {
const deletSingle = async (key) => {
try {
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}/${key}`, { method: "DELETE" }));
const result = await fetch(response);
if (!result.ok) return {
error: {
type: "plugin",
message: translations_default("delete_single_failed", {
status: result.status,
statusText: result.statusText
})
},
data: void 0
};
return {
error: void 0,
data: void 0
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return deletSingle;
};
//#endregion
//#region src/services/delete-multiple.ts
var delete_multiple_default = (client, pluginOptions) => {
const deleteMultiple = async (keys) => {
try {
const deleteXml = `<?xml version="1.0" encoding="UTF-8"?>
<Delete>
${keys.map((key) => `<Object><Key>${key}</Key></Object>`).join("")}
</Delete>`;
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}?delete`, {
method: "POST",
body: deleteXml,
headers: { "Content-Type": "application/xml" }
}));
const result = await fetch(response);
if (!result.ok) return {
error: {
type: "plugin",
message: translations_default("delete_multiple_failed", {
status: result.status,
statusText: result.statusText
})
},
data: void 0
};
return {
error: void 0,
data: void 0
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return deleteMultiple;
};
//#endregion
//#region src/services/upload-single.ts
var upload_single_default = (client, pluginOptions) => {
const uploadSingle = async (props) => {
try {
const headers = new Headers();
if (props.meta.mimeType) headers.set("Content-Type", props.meta.mimeType);
if (props.meta.extension) headers.set("x-amz-meta-extension", props.meta.extension);
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}/${props.key}`, {
method: "PUT",
body: props.data,
headers
}));
const result = await fetch(response);
if (!result.ok) return {
error: {
type: "plugin",
message: translations_default("upload_failed", {
status: result.status,
statusText: result.statusText
})
},
data: void 0
};
const etag = result.headers.get("etag")?.replace(/"/g, "");
return {
error: void 0,
data: { etag }
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return uploadSingle;
};
//#endregion
//#region src/constants.ts
const PLUGIN_KEY = "plugin-s3";
const LUCID_VERSION = "0.x.x";
const PRESIGNED_URL_EXPIRY = 3600;
//#endregion
//#region src/services/get-presigned-url.ts
var get_presigned_url_default = (client, pluginOptions) => {
const getPresignedUrl = async (key, meta) => {
try {
const headers = new Headers();
if (meta.mimeType) headers.set("Content-Type", meta.mimeType);
if (meta.extension) headers.set("x-amz-meta-extension", meta.extension);
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}/${key}?X-Amz-Expires=${PRESIGNED_URL_EXPIRY}`, { method: "PUT" }), {
headers,
aws: { signQuery: true }
});
return {
error: void 0,
data: {
url: response.url.toString(),
headers: Object.fromEntries(response.headers.entries())
}
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return getPresignedUrl;
};
//#endregion
//#region src/services/get-metadata.ts
var get_metadata_default = (client, pluginOptions) => {
const getMetadata = async (key) => {
try {
const response = await client.sign(new Request(`${pluginOptions.endpoint}/${pluginOptions.bucket}/${key}`, { method: "HEAD" }));
const result = await fetch(response);
if (!result.ok) return {
error: {
type: "plugin",
message: translations_default("get_metadata_failed", {
status: result.status,
statusText: result.statusText
})
},
data: void 0
};
const contentLength = result.headers.get("content-length");
if (!contentLength) return {
error: { message: translations_default("object_missing_metadata") },
data: void 0
};
const contentType = result.headers.get("content-type");
const etag = result.headers.get("etag");
return {
error: void 0,
data: {
size: Number.parseInt(contentLength, 10),
mimeType: contentType || null,
etag: etag || null
}
};
} catch (e) {
return {
error: {
type: "plugin",
message: e instanceof Error ? e.message : translations_default("an_unknown_error_occurred")
},
data: void 0
};
}
};
return getMetadata;
};
//#endregion
//#region src/plugin.ts
const plugin = async (config, pluginOptions) => {
const client = aws_client_default(pluginOptions);
config.media = {
...config.media,
strategy: {
getPresignedUrl: get_presigned_url_default(client, pluginOptions),
getMeta: get_metadata_default(client, pluginOptions),
stream: steam_default(client, pluginOptions),
uploadSingle: upload_single_default(client, pluginOptions),
deleteSingle: delete_single_default(client, pluginOptions),
deleteMultiple: delete_multiple_default(client, pluginOptions)
}
};
return {
key: PLUGIN_KEY,
lucid: LUCID_VERSION,
config
};
};
var plugin_default = plugin;
//#endregion
//#region src/index.ts
const lucidS3Plugin = (pluginOptions) => (config) => plugin_default(config, pluginOptions);
var src_default = lucidS3Plugin;
//#endregion
export { src_default as default };
//# sourceMappingURL=index.js.map