From 5554887b91a294b70b7e9c2a032c9f70c41c5698 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 07:36:53 -0700 Subject: [PATCH 01/13] chore: ignore .worktrees directory Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9ad704285..6ca48cdfe 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ package-lock.json .vite-custom docs/superpowers pnpm-lock.yaml +.worktrees From b0c0d305ac1bfea9b4083e98f727e0a5d2c1f998 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 08:03:34 -0700 Subject: [PATCH 02/13] feat(core): accept models[] on StoreParameters with deprecation shim - New `models: string[]` parameter - `model` and `additionalModels` mapped to `models[]` with WARN log - Throws if both old and new shapes are set - Deprecation tests cover the five compat cases --- packages/core/src/stores/store.spec.ts | 42 ++++++++++++++++++++-- packages/core/src/stores/store.ts | 48 +++++++++++++++++++++----- packages/core/vitest.config.ts | 1 + 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/packages/core/src/stores/store.spec.ts b/packages/core/src/stores/store.spec.ts index 24ac91552..0c0ab3f6f 100644 --- a/packages/core/src/stores/store.spec.ts +++ b/packages/core/src/stores/store.spec.ts @@ -1,4 +1,4 @@ -import { test } from "@webda/test"; +import { suite, test } from "@webda/test"; import * as assert from "assert"; import { stub } from "sinon"; import { randomUUID } from "crypto"; @@ -6,7 +6,7 @@ import { TestIdent } from "../test/objects.js"; import { Ident, OperationContext, Store, User } from "../index.js"; import { CoreModel } from "../models/coremodel.js"; import { WebdaApplicationTest } from "../test/application.js"; -import { StoreEvents, StoreNotFoundError, UpdateConditionFailError } from "./store.js"; +import { StoreEvents, StoreNotFoundError, StoreParameters, UpdateConditionFailError } from "./store.js"; import { UuidModel } from "@webda/models"; /** @@ -653,4 +653,42 @@ abstract class StoreTest> extends WebdaApplicationTest { } } +@suite +class StoreParametersTest { + @test + acceptsModelsArrayOnly() { + const p = new StoreParameters().load({ models: ["MyApp/User", "MyApp/Task"] }); + assert.deepStrictEqual(p.models, ["MyApp/User", "MyApp/Task"]); + } + + @test + mapsLegacyModelToModelsArray() { + const p = new StoreParameters().load({ model: "MyApp/User" }); + assert.deepStrictEqual(p.models, ["MyApp/User"]); + } + + @test + mapsModelPlusAdditionalToFlatArray() { + const p = new StoreParameters().load({ + model: "MyApp/User", + additionalModels: ["MyApp/Task", "MyApp/Order"] + }); + assert.deepStrictEqual(p.models, ["MyApp/User", "MyApp/Task", "MyApp/Order"]); + } + + @test + throwsWhenBothModelAndModelsSet() { + assert.throws( + () => new StoreParameters().load({ model: "MyApp/User", models: ["MyApp/User"] }), + /ambiguous/i + ); + } + + @test + defaultsToRegistryEntryWhenNeitherSet() { + const p = new StoreParameters().load({}); + assert.deepStrictEqual(p.models, ["Webda/RegistryEntry"]); + } +} + export { StoreTest }; diff --git a/packages/core/src/stores/store.ts b/packages/core/src/stores/store.ts index e2c632b87..9c888422a 100644 --- a/packages/core/src/stores/store.ts +++ b/packages/core/src/stores/store.ts @@ -218,17 +218,21 @@ export interface StoreInterface { */ export class StoreParameters extends ServiceParameters { /** - * Webda model to use within the Store + * Models managed by this Store. * - * @default "Webda/CoreModel" + * @default ["Webda/RegistryEntry"] + */ + models?: string[]; + + /** + * Webda model to use within the Store. + * @deprecated Use `models: [model]` instead. Will be removed in 5.x. */ model?: string; + /** - * Additional models - * - * Allow this store to manage other models - * - * @default [] + * Additional models managed by this Store. + * @deprecated Merge into `models[]` instead. Will be removed in 5.x. */ additionalModels?: string[]; @@ -281,13 +285,39 @@ export class StoreParameters extends ServiceParameters { } // END_REFACTOR super.load(params); - this.model ??= "Webda/RegistryEntry"; + + // Deprecation mapping: model + additionalModels → models[] + const hasModels = Array.isArray(params.models); + const hasModel = typeof params.model === "string"; + const hasAdditional = Array.isArray(params.additionalModels) && params.additionalModels.length > 0; + + if (hasModels && (hasModel || hasAdditional)) { + throw new Error( + "StoreParameters: `models` and `model`/`additionalModels` are mutually exclusive — ambiguous configuration" + ); + } + + if (hasModels) { + this.models = [...params.models]; + } else if (hasModel || hasAdditional) { + useLog( + "WARN", + `StoreParameters: \`model\` and \`additionalModels\` are deprecated. Use \`models: [...]\` instead.` + ); + this.models = [params.model ?? "Webda/RegistryEntry", ...(params.additionalModels ?? [])]; + } else { + this.models = ["Webda/RegistryEntry"]; + } + + // Keep deprecated fields populated for any code that still reads them in this PR. + this.model ??= this.models[0]; + this.additionalModels ??= this.models.slice(1); + this.strict ??= false; this.defaultModel ??= true; this.forceModel ??= false; this.slowQueryThreshold ??= 30000; this.modelAliases ??= {}; - this.additionalModels ??= []; return this; } } diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index 2ba85efa0..186a1e554 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -62,6 +62,7 @@ export default defineConfig({ "src/services/service.spec.ts", "src/services/serviceparameters.spec.ts", // "src/session/*.spec.ts", + "src/stores/store.spec.ts", //"src/stores/*.spec.ts", "src/templates/*.spec.ts", "src/test/*.spec.ts", From 504e2a1ff77d947c8c8905b9e9f65568ed8161e5 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 08:16:39 -0700 Subject: [PATCH 03/13] fix(core): tighten StoreParameters ambiguity guard and clarify backfill comment Code review follow-ups for Task 1: - Conflict between models[] and additionalModels detected even when additionalModels is empty (presence check, not length) - Backfill comment explains why ??= is a no-op in the legacy branch - Two new tests: empty-additionalModels conflict and additionalModels-only fallback to Webda/RegistryEntry Co-Authored-By: Claude Sonnet 4.6 --- packages/core/src/stores/store.spec.ts | 14 ++++++++++++++ packages/core/src/stores/store.ts | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/core/src/stores/store.spec.ts b/packages/core/src/stores/store.spec.ts index 0c0ab3f6f..ec680a75b 100644 --- a/packages/core/src/stores/store.spec.ts +++ b/packages/core/src/stores/store.spec.ts @@ -689,6 +689,20 @@ class StoreParametersTest { const p = new StoreParameters().load({}); assert.deepStrictEqual(p.models, ["Webda/RegistryEntry"]); } + + @test + mapsAdditionalModelsAloneToRegistryFallback() { + const p = new StoreParameters().load({ additionalModels: ["MyApp/Task"] }); + assert.deepStrictEqual(p.models, ["Webda/RegistryEntry", "MyApp/Task"]); + } + + @test + throwsWhenModelsCombinedWithEmptyAdditionalModels() { + assert.throws( + () => new StoreParameters().load({ models: ["X"], additionalModels: [] }), + /ambiguous/i + ); + } } export { StoreTest }; diff --git a/packages/core/src/stores/store.ts b/packages/core/src/stores/store.ts index 9c888422a..72707344e 100644 --- a/packages/core/src/stores/store.ts +++ b/packages/core/src/stores/store.ts @@ -289,9 +289,14 @@ export class StoreParameters extends ServiceParameters { // Deprecation mapping: model + additionalModels → models[] const hasModels = Array.isArray(params.models); const hasModel = typeof params.model === "string"; - const hasAdditional = Array.isArray(params.additionalModels) && params.additionalModels.length > 0; - - if (hasModels && (hasModel || hasAdditional)) { + // Presence check (not length) used for the conflict guard so that + // `{ models: [...], additionalModels: [] }` is still detected as ambiguous. + const hasAdditionalKey = Array.isArray(params.additionalModels); + // Length check used for the deprecation branch: an empty additionalModels + // alongside a bare `model` is unambiguous and should not warn on its own. + const hasAdditional = hasAdditionalKey && params.additionalModels.length > 0; + + if (hasModels && (hasModel || hasAdditionalKey)) { throw new Error( "StoreParameters: `models` and `model`/`additionalModels` are mutually exclusive — ambiguous configuration" ); @@ -309,7 +314,10 @@ export class StoreParameters extends ServiceParameters { this.models = ["Webda/RegistryEntry"]; } - // Keep deprecated fields populated for any code that still reads them in this PR. + // When the caller passed `models[]` (or nothing at all), backfill the deprecated + // fields from the canonical `models[]` so any code still reading `parameters.model` + // or `parameters.additionalModels` keeps working. In the legacy-input branch + // `super.load(params)` already set both via Object.assign, so the `??=` is a no-op. this.model ??= this.models[0]; this.additionalModels ??= this.models.slice(1); From 8cd9361eed8116108bcaa18bafe0c2ad965119a8 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 08:37:53 -0700 Subject: [PATCH 04/13] feat(core): replace Store._model with _models[] and _modelMetadatas - Drop _model, _modelMetadata, _modelType from Store class - Add _models: ModelClass[] (index 0 = legacy primary) - Add _modelMetadatas: Map - computeParameters() walks parameters.models[] (canonical list from Task 1) - recursive() normalises ModelClass refs to string IDs as _modelsHierarchy keys - getModel() returns _models[0] (deprecated, kept for back-compat) - getModels() added as new public method - setModelDefinitionHelper() sets _models[0] for test-harness compat - Two new @test methods verify _models/_modelMetadatas and getModel() back-compat Co-Authored-By: Claude Sonnet 4.6 --- packages/core/src/stores/memory.spec.ts | 17 +++ packages/core/src/stores/store.spec.ts | 24 +++- packages/core/src/stores/store.ts | 158 ++++++++++-------------- 3 files changed, 108 insertions(+), 91 deletions(-) diff --git a/packages/core/src/stores/memory.spec.ts b/packages/core/src/stores/memory.spec.ts index 30fdb8a09..1d73b7a20 100644 --- a/packages/core/src/stores/memory.spec.ts +++ b/packages/core/src/stores/memory.spec.ts @@ -265,6 +265,23 @@ class AdditionalMemoryTest extends WebdaApplicationTest { }); } + @test + async populatesModelsArrayAndMetadatas() { + const store = new MemoryStore("multi", { models: ["WebdaDemo/Project", "WebdaDemo/SubProject"] }); + store.resolve(); + assert.strictEqual((store as any)._models.length, 2); + assert.strictEqual((store as any)._modelMetadatas.size, 2); + assert.strictEqual((store as any)._modelsHierarchy["WebdaDemo/Project"], 0); + assert.strictEqual((store as any)._modelsHierarchy["WebdaDemo/SubProject"], 0); + } + + @test + async getModelReturnsFirstForBackCompat() { + const store = new MemoryStore("first-model", { models: ["WebdaDemo/Project"] }); + store.resolve(); + assert.strictEqual(store.getModel()?.name, "Project"); + } + getTestConfiguration() { return "../../sample-app/webda.config.jsonc"; } diff --git a/packages/core/src/stores/store.spec.ts b/packages/core/src/stores/store.spec.ts index ec680a75b..33ef1f85f 100644 --- a/packages/core/src/stores/store.spec.ts +++ b/packages/core/src/stores/store.spec.ts @@ -3,7 +3,7 @@ import * as assert from "assert"; import { stub } from "sinon"; import { randomUUID } from "crypto"; import { TestIdent } from "../test/objects.js"; -import { Ident, OperationContext, Store, User } from "../index.js"; +import { Ident, MemoryStore, OperationContext, Store, User } from "../index.js"; import { CoreModel } from "../models/coremodel.js"; import { WebdaApplicationTest } from "../test/application.js"; import { StoreEvents, StoreNotFoundError, StoreParameters, UpdateConditionFailError } from "./store.js"; @@ -705,4 +705,26 @@ class StoreParametersTest { } } +@suite +class StoreFieldsMigrationTest extends WebdaApplicationTest { + @test + async populatesModelsArrayAndMetadatas() { + // Use the legacy `model` + `additionalModels` syntax (still in the schema). + // StoreParameters.load() maps them to models[] which computeParameters() walks. + const store = new MemoryStore("multi", { model: "Webda/Ident", additionalModels: ["Webda/User"] }); + store.resolve(); + assert.strictEqual((store as any)._models.length, 2); + assert.strictEqual((store as any)._modelMetadatas.size, 2); + assert.strictEqual((store as any)._modelsHierarchy["Webda/Ident"], 0); + assert.strictEqual((store as any)._modelsHierarchy["Webda/User"], 0); + } + + @test + async getModelReturnsFirstForBackCompat() { + const store = new MemoryStore("primaryModel", { model: "Webda/User" }); + store.resolve(); + assert.strictEqual(store.getModel()?.name, "User"); + } +} + export { StoreTest }; diff --git a/packages/core/src/stores/store.ts b/packages/core/src/stores/store.ts index 72707344e..24dda4694 100644 --- a/packages/core/src/stores/store.ts +++ b/packages/core/src/stores/store.ts @@ -358,22 +358,12 @@ abstract class Store { - /** - * Contains the current model - */ - _model: ModelClass; - /** - * Contains the current model metadata - */ - _modelMetadata: ModelMetadata; - /** - * Store the manager hierarchy with their depth - */ + /** All model classes managed by this store. Index 0 is the legacy "primary" model. */ + _models: ModelClass[] = []; + /** Metadata for each model in `_models`, keyed by Identifier. */ + _modelMetadatas: Map = new Map(); + /** Store the manager hierarchy with their depth */ _modelsHierarchy: { [key: string]: number } = {}; - /** - * Contains the current model type - */ - _modelType: string; /** * Override the resolved model class for this store at runtime. Used by @@ -383,7 +373,7 @@ abstract class Store 0; - if (isDefaultModel && !hasAdditional) { + const ids = this.parameters.models ?? []; + // Empty / default RegistryEntry → leave hierarchy empty (preserves test-only / fallback behaviour). + const isOnlyDefault = ids.length === 1 && ids[0] === "Webda/RegistryEntry"; + if (ids.length === 0 || isOnlyDefault) { return; } - // Guard: useModel throws on undefined and may return undefined/null for - // unknown models. Catch both so test-only or misconfigured stores stay - // harmless. - try { - this._model = useModel(this.parameters.model); - } catch { - this._model = undefined; - } - if (!this._model) { - useLog("TRACE", `Store ${this.getName?.() ?? "unknown"}: model not found: ${this.parameters.model}`); - return; - } - this._modelMetadata = useModelMetadata(this._model); - if (!this._modelMetadata) { - useLog("WARN", `Store ${this.getName?.() ?? "unknown"}: model metadata not found for ${this.parameters.model}`); - return; - } - useLog("TRACE", "METADATA", this._modelMetadata); - this._modelType = this._modelMetadata.Identifier; - - // Recursively populate _modelsHierarchy for a model's subclass tree. - // Each subclass identifier in meta.Subclasses is a string that we resolve - // via useModel. We keep the minimum depth seen for each identifier. - const recursive = (subclassIds: string[], depth: number) => { - for (const id of subclassIds) { - this._modelsHierarchy[id] = Math.min(depth, this._modelsHierarchy[id] ?? depth); + this._models = []; + this._modelMetadatas = new Map(); + this._modelsHierarchy = {}; + + // Subclasses in ModelMetadata are resolved to ModelClass objects at runtime + // (see Application.setModelMetadata). Accept both string IDs and ModelClass + // references so the hierarchy is keyed by string identifier throughout. + const recursive = (subclasses: (string | ModelClass)[], depth: number) => { + for (const entry of subclasses) { let subModel: ModelClass | undefined; - try { - subModel = useModel(id); - } catch { - continue; + let subId: string | undefined; + if (typeof entry === "string") { + subId = entry; + try { subModel = useModel(entry); } catch { continue; } + } else { + subModel = entry as ModelClass; + subId = useModelId(subModel); } - if (!subModel) continue; + if (!subId || !subModel) continue; + this._modelsHierarchy[subId] = Math.min(depth, this._modelsHierarchy[subId] ?? depth); const subMeta = useModelMetadata(subModel); if (!subMeta) continue; recursive(subMeta.Subclasses ?? [], depth + 1); } }; - // Compute the hierarchy — reset first so re-resolve is idempotent - this._modelsHierarchy = {}; - this._modelsHierarchy[this._modelMetadata.Identifier] = 0; - // Strict Store only stores their exact model - if (!this.parameters.strict) { - recursive(this._modelMetadata.Subclasses ?? [], 1); - } - // Add additional models (each treated as depth-0 roots with their own subtree) - if ((this.parameters.additionalModels ?? []).length) { - if (this.parameters.strict) { - useLog("ERROR", "Cannot add additional models in strict mode"); - } else { - for (const modelType of this.parameters.additionalModels!) { - let addModel: ModelClass | undefined; - try { - addModel = useModel(modelType); - } catch { - continue; - } - if (!addModel) continue; - const addMeta = useModelMetadata(addModel); - if (!addMeta) continue; - this._modelsHierarchy[addMeta.Identifier] = 0; - recursive(addMeta.Subclasses ?? [], 1); - } + for (const id of ids) { + let model: ModelClass | undefined; + try { + model = useModel(id); + } catch { + model = undefined; + } + if (!model) { + useLog("TRACE", `Store ${this.getName?.() ?? "unknown"}: model not found: ${id}`); + continue; + } + const meta = useModelMetadata(model); + if (!meta) { + useLog("WARN", `Store ${this.getName?.() ?? "unknown"}: model metadata not found for ${id}`); + continue; + } + useLog("TRACE", "METADATA", meta); + this._models.push(model); + this._modelMetadatas.set(meta.Identifier, meta); + this._modelsHierarchy[meta.Identifier] = 0; + if (!this.parameters.strict) { + recursive(meta.Subclasses ?? [], 1); } } } @@ -580,11 +549,20 @@ abstract class Store Date: Sat, 9 May 2026 10:05:38 -0700 Subject: [PATCH 05/13] fix(core): clean up Task 2 spec deviations - populatesModelsArrayAndMetadatas now uses models: [...] constructor arg and sets getParameters().models directly before resolve() to exercise computeParameters() via the canonical models[] path (not the legacy shim) - Removed dead-code test stubs from memory.spec.ts (file is excluded from vitest) - Dropped extra useLog TRACE noise from computeParameters() Co-Authored-By: Claude Sonnet 4.6 --- packages/core/src/stores/memory.spec.ts | 17 ----------------- packages/core/src/stores/store.spec.ts | 7 ++++--- packages/core/src/stores/store.ts | 1 - 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/packages/core/src/stores/memory.spec.ts b/packages/core/src/stores/memory.spec.ts index 1d73b7a20..30fdb8a09 100644 --- a/packages/core/src/stores/memory.spec.ts +++ b/packages/core/src/stores/memory.spec.ts @@ -265,23 +265,6 @@ class AdditionalMemoryTest extends WebdaApplicationTest { }); } - @test - async populatesModelsArrayAndMetadatas() { - const store = new MemoryStore("multi", { models: ["WebdaDemo/Project", "WebdaDemo/SubProject"] }); - store.resolve(); - assert.strictEqual((store as any)._models.length, 2); - assert.strictEqual((store as any)._modelMetadatas.size, 2); - assert.strictEqual((store as any)._modelsHierarchy["WebdaDemo/Project"], 0); - assert.strictEqual((store as any)._modelsHierarchy["WebdaDemo/SubProject"], 0); - } - - @test - async getModelReturnsFirstForBackCompat() { - const store = new MemoryStore("first-model", { models: ["WebdaDemo/Project"] }); - store.resolve(); - assert.strictEqual(store.getModel()?.name, "Project"); - } - getTestConfiguration() { return "../../sample-app/webda.config.jsonc"; } diff --git a/packages/core/src/stores/store.spec.ts b/packages/core/src/stores/store.spec.ts index 33ef1f85f..f376b9b12 100644 --- a/packages/core/src/stores/store.spec.ts +++ b/packages/core/src/stores/store.spec.ts @@ -709,9 +709,10 @@ class StoreParametersTest { class StoreFieldsMigrationTest extends WebdaApplicationTest { @test async populatesModelsArrayAndMetadatas() { - // Use the legacy `model` + `additionalModels` syntax (still in the schema). - // StoreParameters.load() maps them to models[] which computeParameters() walks. - const store = new MemoryStore("multi", { model: "Webda/Ident", additionalModels: ["Webda/User"] }); + const store = new MemoryStore("multi", { models: ["Webda/Ident", "Webda/User"] }); + // filterParameters strips unknown fields from the pre-schema-regen module; set models directly + // to exercise computeParameters() via the canonical models[] path (not the legacy shim). + store.getParameters().models = ["Webda/Ident", "Webda/User"]; store.resolve(); assert.strictEqual((store as any)._models.length, 2); assert.strictEqual((store as any)._modelMetadatas.size, 2); diff --git a/packages/core/src/stores/store.ts b/packages/core/src/stores/store.ts index 24dda4694..5bebeb710 100644 --- a/packages/core/src/stores/store.ts +++ b/packages/core/src/stores/store.ts @@ -491,7 +491,6 @@ abstract class Store Date: Sat, 9 May 2026 10:19:46 -0700 Subject: [PATCH 06/13] test(core): add subclass hierarchy + getModels() coverage for Task 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - walksSubclassHierarchyForNonStrictStore exercises recursive() ModelClass branch via Webda/User → Webda/SimpleUser depth-1 traversal - strictStoreSkipsSubclassWalk verifies strict-mode short-circuit - populatesModelsArrayAndMetadatas now also asserts getModels().length Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/core/src/stores/store.spec.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/core/src/stores/store.spec.ts b/packages/core/src/stores/store.spec.ts index f376b9b12..db151016a 100644 --- a/packages/core/src/stores/store.spec.ts +++ b/packages/core/src/stores/store.spec.ts @@ -718,6 +718,7 @@ class StoreFieldsMigrationTest extends WebdaApplicationTest { assert.strictEqual((store as any)._modelMetadatas.size, 2); assert.strictEqual((store as any)._modelsHierarchy["Webda/Ident"], 0); assert.strictEqual((store as any)._modelsHierarchy["Webda/User"], 0); + assert.strictEqual(store.getModels().length, 2); } @test @@ -726,6 +727,27 @@ class StoreFieldsMigrationTest extends WebdaApplicationTest { store.resolve(); assert.strictEqual(store.getModel()?.name, "User"); } + + @test + async walksSubclassHierarchyForNonStrictStore() { + // Webda/User has Webda/SimpleUser as a subclass (verified via webda.module.json). + // In non-strict mode the recursive walk should add the subclass at depth 1. + const store = new MemoryStore("hierarchical", { models: ["Webda/User"] }); + store.getParameters().models = ["Webda/User"]; + store.resolve(); + assert.strictEqual((store as any)._modelsHierarchy["Webda/User"], 0); + assert.strictEqual((store as any)._modelsHierarchy["Webda/SimpleUser"], 1); + } + + @test + async strictStoreSkipsSubclassWalk() { + // Same Webda/User parent, but strict: true should not add SimpleUser. + const store = new MemoryStore("strict", { models: ["Webda/User"], strict: true }); + store.getParameters().models = ["Webda/User"]; + store.resolve(); + assert.strictEqual((store as any)._modelsHierarchy["Webda/User"], 0); + assert.strictEqual((store as any)._modelsHierarchy["Webda/SimpleUser"], undefined); + } } export { StoreTest }; From 6397f2aeb61138598b7e0156c6eb93b9fae9a1b6 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 10:24:31 -0700 Subject: [PATCH 07/13] fix(fs): rewrite strict __type check against _modelsHierarchy Replaces dropped _modelType field. In strict mode, accept files whose __type matches a depth-0 model in this store's models[]; subclasses (depth > 0) remain excluded. Two new tests cover accept and reject paths. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/fs/src/filestore.spec.ts | 47 ++++++++++++++++++++++++++++++- packages/fs/src/filestore.ts | 2 +- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/packages/fs/src/filestore.spec.ts b/packages/fs/src/filestore.spec.ts index f9ada1171..febc773f9 100644 --- a/packages/fs/src/filestore.spec.ts +++ b/packages/fs/src/filestore.spec.ts @@ -1,6 +1,8 @@ import { suite, test } from "@webda/test"; import * as assert from "assert"; -import { existsSync } from "fs"; +import { existsSync, mkdirSync, writeFileSync, rmSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; import pkg from "fs-extra"; import * as sinon from "sinon"; import { CoreModel, Store, StoreNotFoundError, UpdateConditionFailError, User } from "@webda/core"; @@ -148,6 +150,49 @@ class FileStoreTest extends StoreTest> { usersStore.computeParameters(); assert.ok(existsSync(usersStore.getParameters().folder)); } + + @test + async strictModeRejectsForeignType() { + const tmpFolder = join(tmpdir(), `webda-fs-strict-reject-${Date.now()}`); + mkdirSync(tmpFolder); + try { + const store: FileStore = await this.addService( + FileStore, + { folder: tmpFolder, models: ["Webda/Ident"], strict: true }, + "StrictRejectStore" + ); + // Write a file directly with a __type that is NOT the configured model. + const uid = "strict-reject-test-uid"; + writeFileSync(join(tmpFolder, `${uid}.json`), JSON.stringify({ __type: "Webda/User", uuid: uid })); + // _get should return undefined because Webda/User is not at depth 0 in _modelsHierarchy + const result = await store["_get"](uid, false); + assert.strictEqual(result, undefined, "strict mode should reject a file whose __type is not the configured model"); + } finally { + rmSync(tmpFolder, { recursive: true, force: true }); + } + } + + @test + async strictModeAcceptsConfiguredType() { + const tmpFolder = join(tmpdir(), `webda-fs-strict-accept-${Date.now()}`); + mkdirSync(tmpFolder); + try { + const store: FileStore = await this.addService( + FileStore, + { folder: tmpFolder, models: ["Webda/Ident"], strict: true }, + "StrictAcceptStore" + ); + // Write a file directly with the matching __type. + const uid = "strict-accept-test-uid"; + writeFileSync(join(tmpFolder, `${uid}.json`), JSON.stringify({ __type: "Webda/Ident", uuid: uid })); + // _get should return the data because Webda/Ident is at depth 0 in _modelsHierarchy + const result = await store["_get"](uid, false); + assert.ok(result !== undefined, "strict mode should accept a file whose __type matches the configured model"); + assert.strictEqual(result.__type, "Webda/Ident"); + } finally { + rmSync(tmpFolder, { recursive: true, force: true }); + } + } } export { FileStoreTest }; diff --git a/packages/fs/src/filestore.ts b/packages/fs/src/filestore.ts index d96f349ea..a40e1f724 100644 --- a/packages/fs/src/filestore.ts +++ b/packages/fs/src/filestore.ts @@ -389,7 +389,7 @@ export class FileStore exte const res = await this._exists(uid); if (res) { const data = JSON.parse(fs.readFileSync(this.file(uid)).toString()); - if (data.__type !== this._modelType && this.parameters.strict) { + if (this.parameters.strict && this._modelsHierarchy[data.__type] !== 0) { return undefined; } return data; From dd5cef84ad4139508237be1784ff237f8a574da8 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 10:30:44 -0700 Subject: [PATCH 08/13] feat(postgres): migrate resolveTable to models[] and deprecate parameters.table for multi-model - One model in models[]: parameters.table maps to that model (compat shortcut) - Multiple models: parameters.table is ignored with WARN log at init() - parameters.tables[id] continues as the canonical per-model override - Default derivation (id.lower.replace('/', '_')) unchanged - 3 new tests cover single, multi, and explicit-map paths in a separate PostgresStoreResolveTableTest suite (no DB connection required) Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/postgres/src/postgresstore.spec.ts | 40 +++++++++++++++++++++ packages/postgres/src/postgresstore.ts | 14 +++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/packages/postgres/src/postgresstore.spec.ts b/packages/postgres/src/postgresstore.spec.ts index 5920ec53e..a4b73f7c7 100644 --- a/packages/postgres/src/postgresstore.spec.ts +++ b/packages/postgres/src/postgresstore.spec.ts @@ -2,6 +2,7 @@ import { suite, test } from "@webda/test"; import * as assert from "node:assert"; import pg from "pg"; import { WebdaApplicationTest } from "@webda/core/lib/test"; +import { useModel } from "@webda/core"; import PostgresStore from "./postgresstore.js"; const params = { @@ -147,4 +148,43 @@ export class PostgresStoreSmokeTest extends WebdaApplicationTest { this.store!.getParameters().views = [".*"]; this.store!.getParameters().viewPrefix = ""; } + +} + +/** + * Unit tests for resolveTable() that do not require a live PostgreSQL connection. + * Extends WebdaApplicationTest only for its model registry (useModel / useModelMetadata), + * but does NOT call addService() — so the DB-connect path is never triggered. + */ +@suite +export class PostgresStoreResolveTableTest extends WebdaApplicationTest { + @test + async resolveTableSingleModelUsesParametersTable() { + const store = new PostgresStore("singleTable", { models: ["Webda/Ident"], table: "idents" }); + // Bypass resolve()/init() — we only test the table-name resolution logic. + // Set parameters.models directly (schema workaround: Task 7 regenerates it). + store.getParameters().models = ["Webda/Ident"]; + assert.strictEqual(store.resolveTable(useModel("Webda/Ident")), "idents"); + } + + @test + async resolveTableMultiModelIgnoresParametersTable() { + const store = new PostgresStore("multiTable", { + models: ["Webda/Ident", "Webda/User"], + table: "idents" + }); + store.getParameters().models = ["Webda/Ident", "Webda/User"]; + assert.strictEqual(store.resolveTable(useModel("Webda/Ident")), "webda_ident"); + assert.strictEqual(store.resolveTable(useModel("Webda/User")), "webda_user"); + } + + @test + async resolveTableExplicitTablesMapWins() { + const store = new PostgresStore("explicitTable", { + models: ["Webda/User"], + tables: { "Webda/User": "users_v2" } + }); + store.getParameters().models = ["Webda/User"]; + assert.strictEqual(store.resolveTable(useModel("Webda/User")), "users_v2"); + } } diff --git a/packages/postgres/src/postgresstore.ts b/packages/postgres/src/postgresstore.ts index 3859a3a5e..a82006456 100644 --- a/packages/postgres/src/postgresstore.ts +++ b/packages/postgres/src/postgresstore.ts @@ -101,6 +101,12 @@ export class PostgresStore ex * @override */ async init(): Promise { + if (this.parameters.table && (this.parameters.models?.length ?? 0) > 1) { + useLog( + "WARN", + `PostgresStore "${this.getName()}": parameters.table is ignored when more than one model is configured. Use parameters.tables[id] instead.` + ); + } if (this.parameters.usePool) { this.client = acquirePool(this.parameters.postgresqlServer as PoolConfig); this.ownsPool = true; @@ -134,7 +140,7 @@ export class PostgresStore ex * * Resolution order: * 1. `parameters.tables[meta.Identifier]` — explicit per-model override - * 2. Primary model (matching `_modelMetadata.Identifier`) → `parameters.table` + * 2. Single-model back-compat: when only one model is configured, `parameters.table` maps to it * 3. Default — model identifier lowercased with "/" replaced by "_" * * @param model - the model class to resolve the table for @@ -149,11 +155,11 @@ export class PostgresStore ex if (this.parameters.tables?.[meta.Identifier]) { return this.parameters.tables[meta.Identifier]; } - // Primary model uses the configured table name - if (this._modelMetadata && meta.Identifier === this._modelMetadata.Identifier) { + // Single-model back-compat: parameters.table maps to the one model + if (this.parameters.models?.length === 1 && this.parameters.table) { return this.parameters.table; } - // Default: identifier lowercased, "/" → "_" + // Default derivation return meta.Identifier.toLowerCase().replace(/\//g, "_"); } From f308f65b49e49dea3ef563ca3cc478dd7d487aab Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 10:32:26 -0700 Subject: [PATCH 09/13] refactor: migrate remaining Store._model/_modelType references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fs/filestore.ts:205: this._model → this._models[0] - fs/filestore-unit.spec.ts: getWithStrictMode now sets _modelsHierarchy directly (matching what computeParameters does at runtime) - runtime/invitationservice.spec.ts: this.store._model = X → setModelDefinitionHelper(X) Closes the migration started in Task 2. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/fs/src/filestore-unit.spec.ts | 4 ++-- packages/fs/src/filestore.ts | 2 +- packages/runtime/src/services/invitationservice.spec.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/fs/src/filestore-unit.spec.ts b/packages/fs/src/filestore-unit.spec.ts index 330a96502..2332ce051 100644 --- a/packages/fs/src/filestore-unit.spec.ts +++ b/packages/fs/src/filestore-unit.spec.ts @@ -295,8 +295,8 @@ class FileBackedMapTest { @test async getWithStrictMode() { const strictStore = createFileStore(this.tmpDir, { strict: true }); - // @ts-ignore - set _modelType for strict filtering - strictStore._modelType = "MyModel"; + // @ts-ignore - configure hierarchy directly to mimic computeParameters() + strictStore._modelsHierarchy = { MyModel: 0 }; const data = { uuid: "strict1", __type: "OtherModel" }; fs.writeFileSync(path.join(this.tmpDir, "strict1.json"), JSON.stringify(data)); const result = await strictStore._get("strict1"); diff --git a/packages/fs/src/filestore.ts b/packages/fs/src/filestore.ts index a40e1f724..11c9ff3d1 100644 --- a/packages/fs/src/filestore.ts +++ b/packages/fs/src/filestore.ts @@ -202,7 +202,7 @@ export class FileStore exte .sort(); // Use the repository for this store's model to simulate a find - const repo = this.getRepository(this._model) as MemoryRepository; + const repo = this.getRepository(this._models[0]) as MemoryRepository; return MemoryRepository.simulateFind(query as any, files, repo as any); } diff --git a/packages/runtime/src/services/invitationservice.spec.ts b/packages/runtime/src/services/invitationservice.spec.ts index 194402968..f6d94b5dd 100644 --- a/packages/runtime/src/services/invitationservice.spec.ts +++ b/packages/runtime/src/services/invitationservice.spec.ts @@ -97,7 +97,7 @@ class InvitationTest extends WebdaInternalTest { await super.before(); this.store = this.webda.getService("Companies"); - this.store._model = MyCompany; + this.store.setModelDefinitionHelper(MyCompany); this.service = await this.addService( InvitationService, From 84ac94dfa2011090f7560d6c2f8887f86806206e Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 10:57:48 -0700 Subject: [PATCH 10/13] chore: regenerate webda.module.json schemas with models[] field After Tasks 1-5, StoreParameters exposes a flat models: string[] alongside deprecated model + additionalModels. Regenerated schemas accept both shapes. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/core/webda.module.json | 20 +++++++++++++++----- packages/fs/webda.module.json | 20 +++++++++++++++----- packages/postgres/webda.module.json | 20 +++++++++++++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/packages/core/webda.module.json b/packages/core/webda.module.json index b6ff78fd3..419e42ffc 100644 --- a/packages/core/webda.module.json +++ b/packages/core/webda.module.json @@ -1319,8 +1319,8 @@ "description": "Memory store", "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -1337,14 +1337,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -3832,5 +3842,5 @@ "rest-domain": "Webda/RESTOperationsTransport", "http-server": "Webda/HttpServer" }, - "sourceDigest": "6d6c8cbfa29410b7b9d07a680a68daf2" + "sourceDigest": "7139a4d4ffe747dc8a98f426b613b6b9" } \ No newline at end of file diff --git a/packages/fs/webda.module.json b/packages/fs/webda.module.json index d96aaf460..bb1bcf13f 100644 --- a/packages/fs/webda.module.json +++ b/packages/fs/webda.module.json @@ -153,8 +153,8 @@ "description": "Configuration parameters for the JSON-file-backed store.", "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -182,14 +182,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -304,5 +314,5 @@ } }, "behaviors": {}, - "sourceDigest": "c604b24ba0b9ea0416461a6abf35857f" + "sourceDigest": "aeb3db279a38d6f834e626b0cee3d51e" } \ No newline at end of file diff --git a/packages/postgres/webda.module.json b/packages/postgres/webda.module.json index 6aebc185b..31c0e07aa 100644 --- a/packages/postgres/webda.module.json +++ b/packages/postgres/webda.module.json @@ -2232,8 +2232,8 @@ }, "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -2258,14 +2258,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -2390,5 +2400,5 @@ } }, "behaviors": {}, - "sourceDigest": "b978479cb9042a8fefb9146a86c95666" + "sourceDigest": "d9dfe066ac2e66d394a64fc06189b747" } \ No newline at end of file From ce6f4112012ec4cb892cbbad4e06403fe1264928 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 11:35:23 -0700 Subject: [PATCH 11/13] Revert "chore: regenerate webda.module.json schemas with models[] field" This reverts commit 84ac94dfa2011090f7560d6c2f8887f86806206e. --- packages/core/webda.module.json | 20 +++++--------------- packages/fs/webda.module.json | 20 +++++--------------- packages/postgres/webda.module.json | 20 +++++--------------- 3 files changed, 15 insertions(+), 45 deletions(-) diff --git a/packages/core/webda.module.json b/packages/core/webda.module.json index 419e42ffc..b6ff78fd3 100644 --- a/packages/core/webda.module.json +++ b/packages/core/webda.module.json @@ -1319,8 +1319,8 @@ "description": "Memory store", "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -1337,24 +1337,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -3842,5 +3832,5 @@ "rest-domain": "Webda/RESTOperationsTransport", "http-server": "Webda/HttpServer" }, - "sourceDigest": "7139a4d4ffe747dc8a98f426b613b6b9" + "sourceDigest": "6d6c8cbfa29410b7b9d07a680a68daf2" } \ No newline at end of file diff --git a/packages/fs/webda.module.json b/packages/fs/webda.module.json index bb1bcf13f..d96aaf460 100644 --- a/packages/fs/webda.module.json +++ b/packages/fs/webda.module.json @@ -153,8 +153,8 @@ "description": "Configuration parameters for the JSON-file-backed store.", "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -182,24 +182,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -314,5 +304,5 @@ } }, "behaviors": {}, - "sourceDigest": "aeb3db279a38d6f834e626b0cee3d51e" + "sourceDigest": "c604b24ba0b9ea0416461a6abf35857f" } \ No newline at end of file diff --git a/packages/postgres/webda.module.json b/packages/postgres/webda.module.json index 31c0e07aa..6aebc185b 100644 --- a/packages/postgres/webda.module.json +++ b/packages/postgres/webda.module.json @@ -2232,8 +2232,8 @@ }, "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -2258,24 +2258,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -2400,5 +2390,5 @@ } }, "behaviors": {}, - "sourceDigest": "d9dfe066ac2e66d394a64fc06189b747" + "sourceDigest": "b978479cb9042a8fefb9146a86c95666" } \ No newline at end of file From 1f57114f7826a80042d8e5de6a907d6d4e288730 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 11:47:11 -0700 Subject: [PATCH 12/13] Reapply "chore: regenerate webda.module.json schemas with models[] field" This reverts commit ce6f4112012ec4cb892cbbad4e06403fe1264928. --- packages/core/webda.module.json | 20 +++++++++++++++----- packages/fs/webda.module.json | 20 +++++++++++++++----- packages/postgres/webda.module.json | 20 +++++++++++++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/packages/core/webda.module.json b/packages/core/webda.module.json index b6ff78fd3..419e42ffc 100644 --- a/packages/core/webda.module.json +++ b/packages/core/webda.module.json @@ -1319,8 +1319,8 @@ "description": "Memory store", "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -1337,14 +1337,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -3832,5 +3842,5 @@ "rest-domain": "Webda/RESTOperationsTransport", "http-server": "Webda/HttpServer" }, - "sourceDigest": "6d6c8cbfa29410b7b9d07a680a68daf2" + "sourceDigest": "7139a4d4ffe747dc8a98f426b613b6b9" } \ No newline at end of file diff --git a/packages/fs/webda.module.json b/packages/fs/webda.module.json index d96aaf460..bb1bcf13f 100644 --- a/packages/fs/webda.module.json +++ b/packages/fs/webda.module.json @@ -153,8 +153,8 @@ "description": "Configuration parameters for the JSON-file-backed store.", "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -182,14 +182,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -304,5 +314,5 @@ } }, "behaviors": {}, - "sourceDigest": "c604b24ba0b9ea0416461a6abf35857f" + "sourceDigest": "aeb3db279a38d6f834e626b0cee3d51e" } \ No newline at end of file diff --git a/packages/postgres/webda.module.json b/packages/postgres/webda.module.json index 6aebc185b..31c0e07aa 100644 --- a/packages/postgres/webda.module.json +++ b/packages/postgres/webda.module.json @@ -2232,8 +2232,8 @@ }, "properties": { "additionalModels": { - "default": [], - "description": "Additional models\n\nAllow this store to manage other models", + "deprecated": true, + "description": "Additional models managed by this Store.", "items": { "type": "string" }, @@ -2258,14 +2258,24 @@ "type": "boolean" }, "model": { - "default": "Webda/CoreModel", - "description": "Webda model to use within the Store", + "deprecated": true, + "description": "Webda model to use within the Store.", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, + "models": { + "default": [ + "Webda/RegistryEntry" + ], + "description": "Models managed by this Store.", + "items": { + "type": "string" + }, + "type": "array" + }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -2390,5 +2400,5 @@ } }, "behaviors": {}, - "sourceDigest": "b978479cb9042a8fefb9146a86c95666" + "sourceDigest": "d9dfe066ac2e66d394a64fc06189b747" } \ No newline at end of file From fa27845b1a4bdd7ca3b1b2bba48681c8ec16a8a6 Mon Sep 17 00:00:00 2001 From: Remi Cattiau Date: Sat, 9 May 2026 12:42:11 -0700 Subject: [PATCH 13/13] Revert "Reapply "chore: regenerate webda.module.json schemas with models[] field"" This reverts commit 1f57114f7826a80042d8e5de6a907d6d4e288730. --- packages/core/webda.module.json | 20 +++++--------------- packages/fs/webda.module.json | 20 +++++--------------- packages/postgres/webda.module.json | 20 +++++--------------- 3 files changed, 15 insertions(+), 45 deletions(-) diff --git a/packages/core/webda.module.json b/packages/core/webda.module.json index 419e42ffc..b6ff78fd3 100644 --- a/packages/core/webda.module.json +++ b/packages/core/webda.module.json @@ -1319,8 +1319,8 @@ "description": "Memory store", "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -1337,24 +1337,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -3842,5 +3832,5 @@ "rest-domain": "Webda/RESTOperationsTransport", "http-server": "Webda/HttpServer" }, - "sourceDigest": "7139a4d4ffe747dc8a98f426b613b6b9" + "sourceDigest": "6d6c8cbfa29410b7b9d07a680a68daf2" } \ No newline at end of file diff --git a/packages/fs/webda.module.json b/packages/fs/webda.module.json index bb1bcf13f..d96aaf460 100644 --- a/packages/fs/webda.module.json +++ b/packages/fs/webda.module.json @@ -153,8 +153,8 @@ "description": "Configuration parameters for the JSON-file-backed store.", "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -182,24 +182,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -314,5 +304,5 @@ } }, "behaviors": {}, - "sourceDigest": "aeb3db279a38d6f834e626b0cee3d51e" + "sourceDigest": "c604b24ba0b9ea0416461a6abf35857f" } \ No newline at end of file diff --git a/packages/postgres/webda.module.json b/packages/postgres/webda.module.json index 31c0e07aa..6aebc185b 100644 --- a/packages/postgres/webda.module.json +++ b/packages/postgres/webda.module.json @@ -2232,8 +2232,8 @@ }, "properties": { "additionalModels": { - "deprecated": true, - "description": "Additional models managed by this Store.", + "default": [], + "description": "Additional models\n\nAllow this store to manage other models", "items": { "type": "string" }, @@ -2258,24 +2258,14 @@ "type": "boolean" }, "model": { - "deprecated": true, - "description": "Webda model to use within the Store.", + "default": "Webda/CoreModel", + "description": "Webda model to use within the Store", "type": "string" }, "modelAliases": { "$ref": "#/definitions/modelAliases", "description": "Model Aliases to allow easier rename of Model" }, - "models": { - "default": [ - "Webda/RegistryEntry" - ], - "description": "Models managed by this Store.", - "items": { - "type": "string" - }, - "type": "array" - }, "noCache": { "default": false, "description": "Disable default memory cache", @@ -2400,5 +2390,5 @@ } }, "behaviors": {}, - "sourceDigest": "d9dfe066ac2e66d394a64fc06189b747" + "sourceDigest": "b978479cb9042a8fefb9146a86c95666" } \ No newline at end of file