Files
twenty/packages
znn a08f424cc5 suport non aws providers 1 (#21927)
Title: Relax @IsAWSRegion validation constraint for custom S3-compatible
storage endpoints

Summary: This PR updates the @IsAWSRegion decorator to support
non-standard region slugs (e.g., fr-par) when a custom S3-compatible
storage provider is used.

Previously, the decorator enforced a strict regex
(/^[a-z]{2}-[a-z]+-\d{1}$/) for all region variables, which caused
runtime validation errors and worker crashes when users tried to
configure non-AWS providers like Scaleway or DigitalOcean that use
different region formats.

This change introduces a conditional check: If the property being
validated is STORAGE_S3_REGION and a STORAGE_S3_ENDPOINT is defined on
the configuration object, the strict regex constraint is bypassed, and
any non-empty string is accepted.

Changes Made
is-aws-region.decorator.ts: Updated the IsAWSRegionConstraint class to
accept args: ValidationArguments. Added logic to bypass the regex
validation if args.property === 'STORAGE_S3_REGION' and
object.STORAGE_S3_ENDPOINT is present.
TypeScript Typings: **The AwsRegion interface intentionally remains
strictly typed as `${string}-${string}-${number}`. This preserves strict
compile-time types for standard usage, while class-validator and
class-transformer gracefully handle the runtime relaxation during
environment variable loading.**

Testing
I have added below script to test this function

```
const { validate, ValidateIf } = require('class-validator');
const { IsAWSRegion } = require('./packages/twenty-server/dist/engine/core-modules/twenty-config/decorators/is-aws-region.decorator');

class TestConfig {
  constructor(region, endpoint) {
    this.STORAGE_S3_REGION = region;
    this.STORAGE_S3_ENDPOINT = endpoint;
  }
}

ValidateIf((env) => !env.STORAGE_S3_ENDPOINT)(TestConfig.prototype, 'STORAGE_S3_REGION');
IsAWSRegion()(TestConfig.prototype, 'STORAGE_S3_REGION');

const config = new TestConfig('fr-par', 'https://s3.fr-par.scw.cloud');
validate(config).then(errors => {
  if (errors.length > 0) {
    console.error('Validation failed:');
    errors.forEach(err => {
      console.error(`Property: ${err.property}`);
      console.error(`Constraints:`, err.constraints);
    });
  } else {
    console.log('Validation passed!');
  }
});

```


Screenshots

before
<img width="1210" height="188" alt="Screenshot_2026-06-22_12-51-51"
src="https://github.com/user-attachments/assets/4cd0613e-79bd-43db-8d90-5dd0f5341002"
/>

after
<img width="1394" height="152" alt="Screenshot_2026-06-22_12-52-28"
src="https://github.com/user-attachments/assets/e5287fb5-8462-46ce-a078-f5657dd689a5"
/>

Closes https://github.com/twentyhq/twenty/issues/21908



<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21927?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-06-22 13:36:46 +02:00
..