feat: add SCHEMA_SYNC_SAFE flag to prevent destructive schema imports#96
feat: add SCHEMA_SYNC_SAFE flag to prevent destructive schema imports#96alphanull wants to merge 1 commit intobcc-code:mainfrom
Conversation
When SCHEMA_SYNC_SAFE=true, all DELETE operations are filtered from the schema diff before applying. This allows project-specific collections, fields and relations to coexist with a base schema snapshot without being dropped on import. Use case: multi-project setups where a base template schema is imported into projects that extend it with their own collections and fields. Made-with: Cursor
|
What about using the |
|
Good point. They operate on different layers — Combining both behaviors under Our use case: we use schema-sync in a multi-project template setup. A base repository defines the schema, flows, dashboards and permissions which are are shared / used with all derived projects. Derived project repositories merge base updates via git merge upstream/main and redeploy. On startup, the project's Directus instance imports the updated base snapshot — but projects also extend the schema with their own collections and fields, which must not be dropped. Without this flag, |
|
Ok, let's keep it separate. I'll review after copilot has given it a look |
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “safe sync” mode for schema imports so that importing a base snapshot won’t delete project-specific schema additions.
Changes:
- Introduces
SCHEMA_SYNC_SAFEenv flag and passes it into schema sync options. - Adds
filterNonDestructive()to remove DELETE operations from the schema diff before applying it.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/schemaExporter.ts |
Adds safe-mode diff filtering to prevent destructive schema apply operations. |
src/index.ts |
Wires SCHEMA_SYNC_SAFE env var into SchemaExporter options. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| constructor( | ||
| protected getSchemaService: () => Promise<InstanceType<ExtensionsServices['SchemaService']>>, | ||
| protected logger: ApiExtensionContext['logger'], | ||
| protected options = { split: true } | ||
| protected options = { split: true, safe: false } | ||
| ) { |
There was a problem hiding this comment.
SchemaExporter now expects an options object that includes safe, but several call sites (e.g. the CLI export-schema action) pass { split } only. With strict TS settings, this makes the constructor parameter type too narrow and will cause a compile error. Consider typing options as a partial (e.g. { split?: boolean; safe?: boolean }) and merging with defaults inside the constructor so callers can omit safe.
| const schemaOptions = { | ||
| split: typeof env.SCHEMA_SYNC_SPLIT === 'boolean' ? env.SCHEMA_SYNC_SPLIT : true, | ||
| safe: !!env.SCHEMA_SYNC_SAFE, | ||
| }; |
There was a problem hiding this comment.
schemaOptions now includes safe, but the CLI export-schema command later passes the raw args object (typed as { split: boolean }) into new SchemaExporter(...). After this change, that args object is missing the safe property and will not satisfy the constructor’s inferred option type under strict TS. Update the CLI path to merge defaults (e.g. pass { split: args.split, safe: schemaOptions.safe }) or change the constructor to accept partial options.
|
Could you apply the changes by copilot? |
When SCHEMA_SYNC_SAFE=true, all DELETE operations are filtered from the schema diff before applying. This allows project-specific collections, fields and relations to coexist with a base schema snapshot without being dropped on import.
Use case: multi-project setups where a base template schema is imported into projects that extend it with their own collections and fields.