Files
sharper.ly/apps/cms/config/plugins.ts
T

144 lines
4.5 KiB
TypeScript
Raw Normal View History

2026-09-11 02:46:56 +02:00
import type { Core } from '@strapi/strapi';
/**
* Media types the Media Library accepts.
*
* The site publishes reports, guidance notes and event material, so office
* documents and PDFs are allowed next to the usual image/video/audio types.
*/
const allowedMediaTypes = [
'image/*',
'video/*',
'audio/*',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.*',
'text/plain',
'text/csv',
];
/**
* Types that are never accepted, even if they slip past `allowedMediaTypes`.
* SVG is denied on purpose: it can carry script and is served from the same
* origin as the API.
*/
const deniedTypes = [
'image/svg+xml',
'application/vnd.microsoft.portable-executable',
'application/x-msdownload',
'application/x-msdos-program',
'application/x-executable',
'application/x-dosexec',
'application/x-sh',
'text/x-shellscript',
'application/x-mach-binary',
];
/**
* The locales the site ships with.
*
* `en` is the default (LTR) and `ar` is the right-to-left translation. The web
* app mirrors these codes in its URL prefixes (`/en/...`, `/ar/...`), so the
* codes here are part of the public contract - do not rename them.
*
* The i18n plugin itself does not read this key; it is our own declaration and
* is read back at boot by `src/bootstrap/locales.ts`, which creates any missing
* locale and pins the default one. Adding a locale is therefore a one-line edit
* here plus a restart.
*/
const locales = [
{ code: 'en', name: 'English (en)', isDefault: true },
{ code: 'ar', name: 'Arabic (ar)' },
];
const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Plugin => ({
/**
* Internationalisation - core plugin, listed explicitly so the two supported
* locales live in version control rather than only in the database.
*/
i18n: {
enabled: true,
config: {
defaultLocale: 'en',
locales,
},
},
'users-permissions': {
config: {
jwtSecret: env('JWT_SECRET'),
/**
* "refresh" uses the SessionManager (short-lived access token + refresh
* token) instead of the legacy long-lived plugin JWT.
*/
jwtManagement: 'refresh',
sessions: {
// Refresh token is stored in a cookie that JavaScript cannot read.
httpOnly: true,
},
/**
* Rate limit on the auth endpoints (login, forgot-password, ...).
* Tightened from the Strapi default of 10 requests per minute.
*/
ratelimit: {
interval: env.int('AUTH_RATE_LIMIT_INTERVAL', 60_000),
max: env.int('AUTH_RATE_LIMIT_MAX', 5),
},
},
},
/**
* Uploads stay on the default `local` provider: files land in
* `apps/cms/public/uploads` and are served by `strapi::public`.
*
* TO SWITCH TO S3 IN PRODUCTION
* -----------------------------
* 1. Add the provider package to apps/cms/package.json:
* "@strapi/provider-upload-aws-s3": "5.53.0"
* 2. Replace the `provider` / `providerOptions` keys below with:
*
* provider: 'aws-s3',
* providerOptions: {
* baseUrl: env('CDN_URL'), // optional CloudFront/CDN origin
* rootPath: env('S3_ROOT_PATH'), // optional key prefix
* s3Options: {
* credentials: {
* accessKeyId: env('AWS_ACCESS_KEY_ID'),
* secretAccessKey: env('AWS_ACCESS_SECRET'),
* },
* region: env('AWS_REGION'),
* params: {
* ACL: env('AWS_ACL', 'private'),
* signedUrlExpires: env.int('AWS_SIGNED_URL_EXPIRES', 15 * 60),
* Bucket: env('AWS_BUCKET'),
* },
* },
* },
* actionOptions: { upload: {}, uploadStream: {}, delete: {} },
*
* 3. Add the bucket/CDN host to the Content Security Policy in
* `config/middlewares.ts` (`img-src` and `media-src`), otherwise the admin
* panel shows broken thumbnails.
* 4. Set the AWS_* / CDN_URL variables listed in `.env.example`.
*/
upload: {
config: {
provider: 'local',
providerOptions: {
// Cache-Control max-age (seconds) sent for locally served uploads.
localServer: {
maxage: env.int('UPLOAD_LOCAL_MAX_AGE', 300_000),
},
},
// Hard ceiling per file, in bytes. Defaults to 50 MB.
sizeLimit: env.int('UPLOAD_MAX_FILE_SIZE', 50 * 1024 * 1024),
security: {
allowedTypes: allowedMediaTypes,
deniedTypes,
},
},
},
});
export default config;