UNPKG

@adonisjs/drive

Version:

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

266 lines (258 loc) 8.15 kB
import { debug_default, errors_exports } from "./chunk-GRHMQSPS.js"; import "./chunk-MLKGABMK.js"; // index.ts export * from "flydrive"; // configure.ts import string from "@adonisjs/core/helpers/string"; // stubs/main.ts import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; var stubsRoot = dirname(fileURLToPath(import.meta.url)); // configure.ts var 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"] } }; var 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 services2 = typeof selectedServices === "string" ? [selectedServices] : selectedServices; const unknownServices = services2.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 = services2.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: services2 }); await codemods.updateRcFile((rcFile) => { rcFile.addProvider("@adonisjs/drive/drive_provider"); }); await codemods.defineEnvVariables( services2.reduce( (result, service) => { STORAGE_SERVICES[service].env.forEach((envVariable) => { result[envVariable.name] = envVariable.value; }); return result; }, { DRIVE_DISK: services2[0] } ) ); await codemods.defineEnvValidations({ leadingComment: "Variables for configuring the drive package", variables: services2.reduce( (result, service) => { STORAGE_SERVICES[service].env.forEach((envVariable) => { result[envVariable.name] = envVariable.schema; }); return result; }, { DRIVE_DISK: `Env.schema.enum(['${services2.join("', '")}'] as const)` } ) }); if (!pkgsToInstall.length) { return; } if (shouldInstallPackages) { await codemods.installPackages(pkgsToInstall); } else { await codemods.listPackagesToInstall(pkgsToInstall); } } // src/define_config.ts import { configProvider } from "@adonisjs/core"; import { RuntimeException } from "@adonisjs/core/exceptions"; // src/url_builder.ts function createURLBuilder(router, config, routeName) { const prefixUrl = config.appUrl || ""; return { async generateURL(key) { return router.builder().params({ "*": key.split("/") }).prefixUrl(prefixUrl).make(routeName); }, async generateSignedURL(key, _, options) { const { expiresIn, ...headers } = options; return router.builder().qs(headers).params({ "*": key.split("/") }).prefixUrl(prefixUrl).makeSigned(routeName, { expiresIn }); } }; } // src/define_config.ts function defineConfig(config) { return configProvider.create(async (app) => { const { services: services2, fakes, default: defaultDisk } = config; const servicesNames = Object.keys(services2); const disks = {}; const locallyServed = []; for (let serviceName of servicesNames) { const disk = services2[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 }; }); } var 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) { const router = await app.container.make("router"); fsConfig.urlBuilder = createURLBuilder(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 };