From 845ebe569bbc830bdc977ff239b720697a76de65 Mon Sep 17 00:00:00 2001 From: "omegent-app[bot]" <306514130+omegent-app[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2026 10:30:28 +0000 Subject: [PATCH] fix(query): keep tag-aware guard on projectComputed only `project()` is used for view DTOs that intentionally reshape domain fields. Tag-scoped ProjectableFromDomain stays on projectComputed (overview path). Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com> --- .changeset/projectable-key-guard-project.md | 8 ++++++++ packages/effect-app/src/Model/query/dsl.ts | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 .changeset/projectable-key-guard-project.md diff --git a/.changeset/projectable-key-guard-project.md b/.changeset/projectable-key-guard-project.md new file mode 100644 index 000000000..45052bae9 --- /dev/null +++ b/.changeset/projectable-key-guard-project.md @@ -0,0 +1,8 @@ +--- +"effect-app": patch +"@effect-app/infra": patch +"@effect-app/vue": patch +"@effect-app/vue-components": patch +--- + +Keep tag-aware `ProjectableFromDomain` for `projectComputed` only; restore loose key-presence guard for `project()` so view DTOs with reshaped fields keep typechecking. diff --git a/packages/effect-app/src/Model/query/dsl.ts b/packages/effect-app/src/Model/query/dsl.ts index 86a1c8d60..8cbd7b166 100644 --- a/packages/effect-app/src/Model/query/dsl.ts +++ b/packages/effect-app/src/Model/query/dsl.ts @@ -153,6 +153,16 @@ export type ProjectableFromDomain< ExtraKeys extends PropertyKey = never > = ProjectableGuard +/** + * Loose key-presence guard for {@link project}: every projection key must exist + * on *some* domain member (`KeysOfUnion`). Does **not** enforce per-tag + * ownership — views may reshape freely. Use {@link ProjectableFromDomain} / + * `projectComputed` when tag-scoped ownership matters. + */ +type ProjectableKeyGuard = [I] extends [FieldValues] + ? (Exclude | "_tag"> extends never ? unknown : never) + : unknown + export type RelationDirection = "some" | "every" export type Relation = { relation: RelationDirection } export type Query = QueryTogether @@ -606,7 +616,7 @@ export const project: { >( schema: & S.Codec, I, R> - & ProjectableGuard>, + & ProjectableKeyGuard>, mode: "collect" ): ( current: Q @@ -621,7 +631,7 @@ export const project: { >( schema: & S.Codec - & ProjectableGuard>, + & ProjectableKeyGuard>, mode: "project" ): ( current: Q @@ -635,7 +645,7 @@ export const project: { >( schema: & S.Codec - & ProjectableGuard> + & ProjectableKeyGuard> ): ( current: Q ) => QueryProjection, A, R, ExtractTType, E>