UNPKG

@adonisjs/drive

Version:

A thin wrapper on top of Flydrive to work seamlessly with AdonisJS

289 lines (288 loc) 7.92 kB
import { r as errors_exports, t as debug_default } from "./debug-BaNwyLMa.js"; import { RuntimeException } from "@adonisjs/core/exceptions"; import string from "@adonisjs/core/helpers/string"; import { configProvider } from "@adonisjs/core"; export * from "flydrive"; const stubsRoot = import.meta.dirname; const STORAGE_SERVICES = { fs: { name: "Local filesystem", env: [], dependencies: [] }, s3: { name: "AWS S3", env: [ { name: "AWS_ACCESS_KEY_ID", value: "", schema: "Env.schema.string()" }, { name: "AWS_SECRET_ACCESS_KEY", value: "", schema: "Env.schema.string()" }, { name: "AWS_REGION", value: "", schema: "Env.schema.string()" }, { name: "S3_BUCKET", value: "", schema: "Env.schema.string()" } ], dependencies: ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"] }, spaces: { name: "Digital Ocean Spaces", env: [ { name: "SPACES_KEY", value: "", schema: "Env.schema.string()" }, { name: "SPACES_SECRET", value: "", schema: "Env.schema.string()" }, { name: "SPACES_REGION", value: "", schema: "Env.schema.string()" }, { name: "SPACES_BUCKET", value: "", schema: "Env.schema.string()" }, { name: "SPACES_ENDPOINT", value: `https://\${SPACES_REGION}.digitaloceanspaces.com`, schema: "Env.schema.string()" } ], dependencies: ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"] }, r2: { name: "Cloudflare R2", env: [ { name: "R2_KEY", value: "", schema: "Env.schema.string()" }, { name: "R2_SECRET", value: "", schema: "Env.schema.string()" }, { name: "R2_BUCKET", value: "", schema: "Env.schema.string()" }, { name: "R2_ENDPOINT", value: "", schema: "Env.schema.string()" } ], dependencies: ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"] }, gcs: { name: "Google Cloud Storage", env: [{ name: "GCS_KEY", value: "file://gcs_key.json", schema: "Env.schema.string()" }, { name: "GCS_BUCKET", value: "", schema: "Env.schema.string()" }], dependencies: ["@google-cloud/storage"] }, supabase: { name: "Supabase Storage", env: [ { name: "SUPABASE_STORAGE_KEY", value: "", schema: "Env.schema.string()" }, { name: "SUPABASE_STORAGE_SECRET", value: "", schema: "Env.schema.string()" }, { name: "SUPABASE_STORAGE_REGION", value: "", schema: "Env.schema.string()" }, { name: "SUPABASE_STORAGE_BUCKET", value: "", schema: "Env.schema.string()" }, { name: "SUPABASE_ENDPOINT", value: "", schema: "Env.schema.string()" } ], dependencies: ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"] } }; const SERVICES_NAMES = Object.keys(STORAGE_SERVICES); async function configure(command) { let selectedServices = command.parsedFlags.services; let shouldInstallPackages = command.parsedFlags.install; if (!selectedServices) selectedServices = await command.prompt.multiple("Select the storage services you want to use", SERVICES_NAMES.map((service) => { return { name: service, message: STORAGE_SERVICES[service].name }; }), { validate(values) { return !values || !values.length ? "Please select one or more services" : true; } }); const services = typeof selectedServices === "string" ? [selectedServices] : selectedServices; const unknownServices = services.find((service) => !SERVICES_NAMES.includes(service)); if (unknownServices) { command.exitCode = 1; command.logger.logError(`Invalid service "${unknownServices}". Supported services are: ${string.sentence(SERVICES_NAMES)}`); return; } const pkgsToInstall = services.flatMap((service) => STORAGE_SERVICES[service].dependencies).map((pkg) => { return { name: pkg, isDevDependency: false }; }); if (!shouldInstallPackages && pkgsToInstall.length) shouldInstallPackages = await command.prompt.confirm("Do you want to install additional packages required by \"@adonisjs/drive\"?"); const codemods = await command.createCodemods(); await codemods.makeUsingStub(stubsRoot, "config/drive.stub", { services }); await codemods.updateRcFile((rcFile) => { rcFile.addProvider("@adonisjs/drive/drive_provider"); }); await codemods.defineEnvVariables(services.reduce((result, service) => { STORAGE_SERVICES[service].env.forEach((envVariable) => { result[envVariable.name] = envVariable.value; }); return result; }, { DRIVE_DISK: services[0] })); await codemods.defineEnvValidations({ leadingComment: "Variables for configuring the drive package", variables: services.reduce((result, service) => { STORAGE_SERVICES[service].env.forEach((envVariable) => { result[envVariable.name] = envVariable.schema; }); return result; }, { DRIVE_DISK: `Env.schema.enum(['${services.join("', '")}'] as const)` }) }); if (!pkgsToInstall.length) return; if (shouldInstallPackages) await codemods.installPackages(pkgsToInstall); else await codemods.listPackagesToInstall(pkgsToInstall); } function createURLBuilder(router, config, routeName) { const prefixUrl = config.appUrl || ""; return { async generateURL(key) { return router.urlBuilder.urlFor(routeName, { "*": key.split("/") }, { prefixUrl }); }, async generateSignedUploadURL() { throw new Error("Signed uploads are not supported by the FS driver"); }, async generateSignedURL(key, _, options) { const { expiresIn, ...headers } = options; return router.urlBuilder.signedUrlFor(routeName, { "*": key.split("/") }, { qs: headers, expiresIn, prefixUrl }); } }; } function defineConfig(config) { return configProvider.create(async (app) => { const { services, fakes, default: defaultDisk } = config; const servicesNames = Object.keys(services); const disks = {}; const locallyServed = []; for (let serviceName of servicesNames) { const disk = services[serviceName]; if (typeof disk === "function") disks[serviceName] = disk; else disks[serviceName] = await disk.resolver(serviceName, app, locallyServed); } return { config: { default: defaultDisk, fakes: { location: app.tmpPath("drive-fakes"), urlBuilder: { async generateURL(key, _) { return `/drive/fakes/${key}`; }, async generateSignedURL(key, _, __) { return `/drive/fakes/signed/${key}`; } }, ...fakes }, services: disks }, locallyServed }; }); } const services = { fs(config) { return { type: "provider", async resolver(name, app, locallyServed) { debug_default("configuring fs service"); if (config.serveFiles && !config.routeBasePath) throw new RuntimeException(`Invalid drive config. Missing "routeBasePath" option in "services.${name}" object`); const routeName = `drive.${name}.serve`; const fsConfig = { visibility: config.visibility, location: config.location }; if (config.serveFiles) { fsConfig.urlBuilder = createURLBuilder(await app.container.make("router"), config, routeName); locallyServed.push({ service: name, routeName, routePattern: `${config.routeBasePath.replace(/\/$/, "")}/*` }); } const { FSDriver } = await import("flydrive/drivers/fs"); return () => new FSDriver(fsConfig); } }; }, s3(config) { return { type: "provider", async resolver() { debug_default("configuring s3 service"); const { S3Driver } = await import("flydrive/drivers/s3"); return () => new S3Driver(config); } }; }, gcs(config) { return { type: "provider", async resolver() { debug_default("configuring gcs service"); const { GCSDriver } = await import("flydrive/drivers/gcs"); return () => new GCSDriver(config); } }; } }; export { configure, defineConfig, errors_exports as errors, services, stubsRoot };