Skip to content

Update outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users - #27945

Merged
ComfortablyCoding merged 28 commits into
directus:mainfrom
kheiner:fix/sdkschema-and-type-drift
Aug 7, 2026
Merged

Update outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users#27945
ComfortablyCoding merged 28 commits into
directus:mainfrom
kheiner:fix/sdkschema-and-type-drift

Conversation

@kheiner

@kheiner kheiner commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

What's Changed

Corrects nullability, missing fields, and one stale field across sdk/src/schema/*.ts and packages/types/src/*.ts for directus_files, directus_collections, directus_deployments (+ projects/runs), directus_settings, and directus_users, based on an audit against the DB migrations and runtime behavior. Links below point at main and cite the DB migration or runtime code backing each claim.

directus_files

  • sdk: added created_on (non-null) and tus_id/tus_data (nullable) was missing entirely.
    tus_id/tus_data,
    created_on/uploaded_on split
  • sdk: uploaded_on is now nullable - no default since the old NOT NULL uploaded_on was renamed to
    created_on in the same migration linked above.

directus_collections

  • sdk: added autosave_revision_interval (nullable) to meta was missing from sdk only.
    migration

directus_deployments / directus_deployment_projects / directus_deployment_runs

  • sdk: provider narrowed from string to 'vercel' | 'netlify', matching the enforced values in
    controllers/deployment.ts. Judgment call - see Review Notes.
  • sdk: added webhook_ids, webhook_secret, last_synced_at (DirectusDeployment) and url, framework, deployable (DirectusDeploymentProject) was missing entirely.
    migration
  • packages/types: added user_created to StoredProject and StoredRun as nullable :fk columns
    (migration),
  • sdk + packages/types: deployment_runs.status is now nullable. DB column has no default
    (migration), and the API's own internal type already treats it as nullable
    (deployment-runs.ts).

directus_settings

  • sdk: reordered to match packages/types/src/settings.ts's field order.
  • sdk: added public_favicon, mcp_oauth_enabled/_dcr_enabled/_cimd_enabled, project_owner, project_usage, org_name, product_updates, project_status was missing entirely.
    public_favicon,
    mcp_oauth_*,
    project_owner/project_usage/org_name/product_updates/project_status
  • packages/types: added mcp_oauth_dcr_enabled, mcp_oauth_cimd_enabled, project_status - same columns as above, missing here too (not sdk-only, as originally assumed).
  • sdk + packages/types: product_updates is now nullable - DB column has no NOT NULL (same project-owner migration linked above).
  • sdk: project_url is now nullable - column has no default, never made NOT NULL.
  • sdk + packages/types: project_color is now non-null - a later migration hardened it to NOT NULL with a backfill.
    migration
  • packages/types: module_bar is now nullable - column has no default.
  • packages/types: default_language is now non-null - column was created NOT NULL from the start.
    migration
  • app: added a null guard in system-modules.vue's valueToPreview for the module_bar nullability change above. See Review Notes.

directus_users

  • sdk: reordered to match packages/types/src/users.ts's field order.
  • sdk: removed the phantom theme field. The column was renamed to appearance and split into theme_dark/theme_light here:
    migration
    (packages/types never had this field).
  • sdk: added text_direction (non-null) was missing from sdk only.
    migration
  • sdk + packages/types: added 'inactive-license' to the status union.
    choices list,
    constant
  • sdk: tightened appearance to 'auto' | 'dark' | 'light' | null', matching its 3-value choices list and packages/types's existing typing.

Tested Scenarios

  • Verified every nullability/missing-field/phantom-field/enum claim above directly against the DB migrations and, where relevant, runtime service code (not just other type declarations).
  • pnpm --filter @directus/types build + pnpm --filter app exec vue-tsc --noEmit -p . after each field correction, to catch downstream breakage in app/.
  • Dry-run: cherry-picked Fix a type error in the module bar default configuration #27944's commit onto this branch to simulate the merge order, confirmed it clears the MODULE_BAR_DEFAULT cascade with no new errors, then reverted it back out since it will land as its own squash-merged commit. Merge order respected.

Review Notes / Questions / Concerns

  • provider narrowed to 'vercel' | 'netlify' - this was a judgment call, not backed by an established repo convention. The API enforces exactly these two values (controllers/deployment.ts), so a literal union matches real behavior better than string. But sdk/src/schema/*.ts has no established pattern for this - the only precedent is directus_users.status, which is already typed as an inline literal union in both sdk and packages/types. There's no named/exported constant or type alias convention to reuse instead (e.g. no type DeploymentProvider = ... anywhere in sdk/src/schema). Went with an inline literal union to match status's existing style. Flagging in case there's a preferred convention I'm not aware of, or reviewers would rather this stay as string?

  • ⚠️ uploaded_on nullability is correct, but there may be is a bug in onUploadFinish.

outdated:

uploaded_on is nullable by design: a TUS (resumable) upload creates a placeholder record before the upload completes, so uploaded_on is legitimately unset at that point.

However, onUploadFinish never appears to set uploaded_on on completion - the final updateOne call only includes tus_id/tus_data/metadata from extractMetadata(), none of which touch uploaded_on. If that's right, a file finished via TUS may keep uploaded_on: null indefinitely. Compare with the regular (non-TUS) upload path, which sets it explicitly:
files.ts:196.

Not verified against a live TUS upload. Is this a known/intentional gap, and should it be fixed here or filed separately?

#27945 (comment)

  • Should packages/types model relational-field expansion consistently for user_created-style fields?

    files.ts/versions.ts type these as plain string | null (:fk only); comments.ts/shares.ts type them as string | User (allows an expanded object). The new StoredProject/StoredRun.user_created fields went with string | null, matching the majority. Runtime-wise, the user-created/user-updated specials only ever resolve to a raw UUID or null - the User-object option comes from generic Directus field-expansion (any M2O relation can expand via the fields query param), not something specific to these two files. There's no existing convention to defer to. Keep string | null as the default going forward, or standardize on string | User everywhere?

  • The pre-existing, unrelated Field[] error at line 255 is untouched.

  • I sorted the order for directus_users and directus_settings in the SDK to match the listed order in Types because I was struggling to verify parity with the difference in order, it makes it harder to review the changes but easier to implement the fix (and maintain later). Sorry in advance.

    Is it worth it look at breaking out AI Settings into it's own object so it's easier to manage/review?
    Probably worth cleaning up sort order with groupings with a comment for better readability. I did not do that here.

outdated:
  • settings.module_bar: runtime guard added here; the type-safety cascade it exposed is fixed by Fix a type error in the module bar default configuration #27944 (fix/27943-module-bar-default-typing, off main), which this PR is blocked on.

    app/src/interfaces/_system/system-modules/system-modules.vue's valueToPreview called .flatMap(...) on Settings['module_bar'] with no null check. Added a guard ((value ?? MODULE_BAR_DEFAULT).flatMap(...), matching how use-visual-editing.ts:22 and module-bar.vue:21 already handle it) - that's fixed here.

    Making module_bar correctly nullable also surfaces 10 vue-tsc errors in the same file (confirmed via a cherry-pick-and-revert dry run), all rooted in MODULE_BAR_DEFAULT (app/src/constants.ts) being an untyped array literal that doesn't structurally match SettingsModuleBarLink | SettingsModuleBarModule, plus one InferDefault error from the withDefaults factory's as Settings['module_bar'] cast widening to include null. That's fixed in Fix a type error in the module bar default configuration #27944: an explicit type annotation on MODULE_BAR_DEFAULT, and dropping the now-unneeded cast on the factory default. Fix a type error in the module bar default configuration #27944 merges first; this branch rebases onto main once it lands.

Checklist

Leave unchecked where not applicable

  • Tests added/updated
  • Documentation PR created in directus/docs
  • OpenAPI updated
  • SDK (@directus/sdk) updated to reflect the changes
  • Types (@directus/types) updated to reflect the changes
  • GraphQL schema updated to reflect the changes
  • System data (@directus/system-data) updated for changes to system collections/fields/relations
  • Database migration added for schema/system changes
  • Environment variables documented for new/changed config
  • App translations added for new user-facing strings
  • Security implications apply

kheiner added 12 commits July 18, 2026 11:27
 - product_updates is nullable
 - module_bar is nullable
 - default_language and project_color are NOT nullable
- sorted to match @directus/types declaration
- sorted to match @directus/types declaration
 - status now includes 'inactive-license'
Gives MODULE_BAR_DEFAULT an explicit (SettingsModuleBarLink | SettingsModuleBarModule)[]
annotation instead of a bare literal, so it structurally satisfies the discriminated union
instead of widening `type` to `string`. Drops the now-unneeded `as Settings['module_bar']`
cast on system-modules.vue's withDefaults default, which was masking the same issue since
directus#18490. Also fixes DEFAULT_REPORT_FEATURE_URL, stale since the roadmap moved to .com.

Fixes directus#27943
…de errors"

This reverts commit 245c4df5d3f4

Cherry-picked temporarily to confirm this branch has no new vue-tsc
errors. Rebase onto main after directus#27943 merges to pick up the real change.
module_bar has no default and no NOT NULL constraint in the database, so it
can be NULL. valueToPreview called .flatMap() directly on the value with no
null check, which would crash the Settings > Project Settings UI. Guards
with (value ?? MODULE_BAR_DEFAULT), matching the pattern already used
elsewhere in this file.

Refs directus#27943
@kheiner

kheiner commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author
  • ⚠️ uploaded_on nullability is correct, but there may be a related bug in onUploadFinish.
    ...
    Not verified against a live TUS upload. Is this a known/intentional gap, and should it be fixed here or filed separately?

Verified issue #28042 and submitted PR for fix #28043 (draft due to PR limit for contributors but easy to review I think)

@ComfortablyCoding

Copy link
Copy Markdown
Member

Should packages/types model relational-field expansion consistently for user_created-style fields?

AFAIK, we don't have the same relational typing in packages/types as we do in the SDK setup. In general, we only model the field types we need there, which is typically just the id. So this adjustment seems expected for this relation.

Is it worth it look at breaking out AI Settings into it's own object so it's easier to manage/review?
Probably worth cleaning up sort order with groupings with a comment for better readability. I did not do that here.

I'd leave it for now, no meaningful improvement to doing so atm.

@ComfortablyCoding ComfortablyCoding left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Please see comments below.

Comment thread sdk/src/schema/deployment.ts
Comment thread app/src/interfaces/_system/system-modules/system-modules.vue Outdated
Comment thread sdk/src/schema/settings.ts
Comment thread sdk/src/schema/settings.ts Outdated
Comment thread sdk/src/schema/settings.ts Outdated
Comment thread sdk/src/schema/settings.ts Outdated
Comment thread .changeset/ripe-pugs-stand.md Outdated
Comment thread .changeset/ripe-pugs-stand.md Outdated
@kheiner

kheiner commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author
  • directus_settings: added missing public_registration_* fields, fixed DirectusFile relation typing on project_logo/public_foreground/public_background, corrected custom_aspect_ratios and basemaps shapes
  • system-modules.vue: narrowed valueToPreview to NonNullable<Settings['module_bar']> per suggestion
  • directus_deployments.credentials: narrowed the base type to '**********' | null to match read behavior (redacted for any request with accountability), while createDeployment/updateDeployment override the field so real credential objects still type-check on write
    • credentials is required on create, optional on update
  • Changeset: applied suggestions

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.11%. Comparing base (69139e6) to head (11a51cc).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #27945      +/-   ##
==========================================
+ Coverage   69.95%   70.11%   +0.16%     
==========================================
  Files        2453     2456       +3     
  Lines      167691   168560     +869     
  Branches    16542    16844     +302     
==========================================
+ Hits       117304   118193     +889     
+ Misses      50387    50367      -20     
Flag Coverage Δ
api 59.06% <ø> (+0.56%) ⬆️
app 78.82% <100.00%> (+0.03%) ⬆️
composables 83.87% <ø> (ø)
constants 4.66% <ø> (ø)
create-directus-extension 96.55% <ø> (ø)
create-directus-project 98.43% <ø> (ø)
env 99.74% <ø> (ø)
errors 96.29% <ø> (ø)
extensions 35.63% <ø> (ø)
extensions-registry 95.43% <ø> (ø)
extensions-sdk 14.37% <ø> (ø)
format-title 100.00% <ø> (ø)
memory 100.00% <ø> (ø)
pressure 77.63% <ø> (ø)
release-notes-generator 80.91% <ø> (ø)
schema-builder 81.42% <ø> (ø)
sdk 34.90% <ø> (ø)
storage 92.00% <ø> (ø)
storage-driver-azure 73.33% <ø> (ø)
storage-driver-cloudinary 80.62% <ø> (ø)
storage-driver-gcs 66.95% <ø> (ø)
storage-driver-local 69.76% <ø> (ø)
storage-driver-s3 52.16% <ø> (ø)
storage-driver-supabase 67.25% <ø> (ø)
system-data 32.42% <ø> (ø)
update-check 55.67% <ø> (ø)
utils 93.19% <ø> (ø)
validation 43.78% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ComfortablyCoding ComfortablyCoding left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks!

@ComfortablyCoding ComfortablyCoding changed the title Fix schema drift in @directus/sdk and @directus/types Update outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users Aug 7, 2026
Comment thread sdk/src/schema/settings.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants