@classytic/mongokit 3.35.0 → 3.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,15 +3,25 @@ import { Document, Model } from "mongoose";
3
3
  import { SchemaBuilderOptions, SchemaGenerator } from "@classytic/repo-core/schema";
4
4
  import { AdapterRepositoryInput, AdapterSchemaContext, AdapterValidationResult, DataAdapter, OpenApiSchemas, RepositoryLike, SchemaMetadata } from "@classytic/repo-core/adapter";
5
5
  //#region src/adapter/mongoose-adapter.d.ts
6
- /**
7
- * Options for creating a Mongoose adapter.
8
- *
9
- * `TDoc` is auto-inferred from the Mongoose model — no explicit type
10
- * needed in most call sites.
11
- */
12
- interface MongooseAdapterOptions<TDoc = unknown> {
13
- /** Mongoose model instance — preserves document type for type safety. */
14
- model: Model<TDoc>;
6
+ interface MongooseAdapterOptions<TDoc = unknown, TModelDoc = unknown> {
7
+ /**
8
+ * The Mongoose model. Still a real `Model`, so a Schema or a hand-built
9
+ * object literal is a COMPILE error — but its document type is INDEPENDENT of
10
+ * `TDoc`.
11
+ *
12
+ * `Model<T>` is invariant in `T`, so `Model<TDoc>` here forced every caller
13
+ * whose repository speaks a lean entity (string ids) while its schema-inferred
14
+ * model carries hydrated documents to cast: the two describe one collection
15
+ * and can never unify. The adapter reads the model for `modelName` and
16
+ * `.schema.paths` metadata only, never for document typing.
17
+ *
18
+ * Decoupling the two parameters removes a static check, so the constructor
19
+ * restores it at RUNTIME by comparing this model against the one the
20
+ * repository owns — see `assertModelMatchesRepository`. That check is
21
+ * strictly stronger: it also rejects two DIFFERENT collections that happen to
22
+ * share a document shape, which no type could distinguish.
23
+ */
24
+ model: Model<TModelDoc>;
15
25
  /**
16
26
  * Repository implementing CRUD operations.
17
27
  *
@@ -58,13 +68,19 @@ interface MongooseAdapterOptions<TDoc = unknown> {
58
68
  * Mongoose data adapter — implements the `DataAdapter<TDoc>` contract from
59
69
  * `@classytic/repo-core/adapter`.
60
70
  */
61
- declare class MongooseAdapter<TDoc = unknown> implements DataAdapter<TDoc> {
71
+ declare class MongooseAdapter<TDoc = unknown, TModelDoc = unknown> implements DataAdapter<TDoc> {
62
72
  readonly type: "mongoose";
63
73
  readonly name: string;
64
- readonly model: Model<TDoc>;
74
+ /**
75
+ * The model as given. Its document type is NOT `TDoc` — a lean repository
76
+ * legitimately pairs with a hydrated schema-inferred model, so claiming
77
+ * `Model<TDoc>` here was an assertion the code could not honour. Read it for
78
+ * `modelName` and `.schema`; narrow it yourself if you need document typing.
79
+ */
80
+ readonly model: Model<unknown>;
65
81
  readonly repository: RepositoryLike<TDoc>;
66
82
  private readonly schemaGenerator?;
67
- constructor(options: MongooseAdapterOptions<TDoc>);
83
+ constructor(options: MongooseAdapterOptions<TDoc, TModelDoc>);
68
84
  /**
69
85
  * Lightweight path-existence check for hosts that infer absent fields
70
86
  * (e.g. arc's `defineResource()` infers `tenantField: false` when the
@@ -159,8 +175,8 @@ declare class MongooseAdapter<TDoc = unknown> implements DataAdapter<TDoc> {
159
175
  * const adapter = createMongooseAdapter(ProductModel, productRepository);
160
176
  * ```
161
177
  */
162
- declare function createMongooseAdapter<TDoc = unknown>(model: Model<TDoc>, repository: AdapterRepositoryInput<TDoc>): DataAdapter<TDoc>;
163
- declare function createMongooseAdapter<TDoc = unknown>(options: MongooseAdapterOptions<TDoc>): DataAdapter<TDoc>;
178
+ declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(model: Model<TModelDoc>, repository: AdapterRepositoryInput<TDoc>): DataAdapter<TDoc>;
179
+ declare function createMongooseAdapter<TDoc = unknown, TModelDoc = unknown>(options: MongooseAdapterOptions<TDoc, TModelDoc>): DataAdapter<TDoc>;
164
180
  //#endregion
165
181
  //#region src/adapter/types.d.ts
166
182
  /**
@@ -1,2 +1,2 @@
1
- import { n as createMongooseAdapter, r as isMongooseModel, t as MongooseAdapter } from "../adapter-DlaOGcQN.mjs";
1
+ import { n as createMongooseAdapter, r as isMongooseModel, t as MongooseAdapter } from "../adapter-Bfqz8yHE.mjs";
2
2
  export { MongooseAdapter, createMongooseAdapter, isMongooseModel };
@@ -65,18 +65,60 @@ function formatInvalidRepositoryError(repository, model) {
65
65
  ].join("\n");
66
66
  }
67
67
  /**
68
+ * Options for creating a Mongoose adapter.
69
+ *
70
+ * `TDoc` is auto-inferred from the Mongoose model — no explicit type
71
+ * needed in most call sites.
72
+ */
73
+ /**
74
+ * The model and the repository must name the SAME collection.
75
+ *
76
+ * Decoupling their document types (so a lean repository pairs with a hydrated
77
+ * schema-inferred model) removes the static cross-check that `Model<TDoc>` +
78
+ * `AdapterRepositoryInput<TDoc>` gave. This restores it where it can actually be
79
+ * decided — at construction, against `Repository.Model`, which every kit-native
80
+ * repository carries. It is strictly stronger than the type was: two different
81
+ * collections sharing a document shape were always statically indistinguishable.
82
+ *
83
+ * Silent when the repository does not expose a model (a BYO/mock repository) —
84
+ * absence of an answer is not a negative answer, and refusing there would break
85
+ * every legitimate custom repository.
86
+ */
87
+ function assertModelMatchesRepository(model, repository) {
88
+ const repoModel = repository?.Model;
89
+ const repoModelName = typeof repoModel?.modelName === "string" ? repoModel.modelName : void 0;
90
+ if (repoModelName === void 0 || repoModelName === model.modelName) return;
91
+ throw new TypeError([
92
+ `MongooseAdapter: model/repository mismatch — model is '${model.modelName}' but the repository is bound to '${repoModelName}'.`,
93
+ "",
94
+ "The adapter reads schema metadata from the MODEL (arc infers a missing",
95
+ "`tenantField` from it) and reads/writes through the REPOSITORY. Mismatched,",
96
+ "the tenant probe answers about the wrong collection and queries are either",
97
+ "filtered to zero rows or left unscoped — neither of which errors.",
98
+ "",
99
+ "Fix: pass the model that repository was constructed with."
100
+ ].join("\n"));
101
+ }
102
+ /**
68
103
  * Mongoose data adapter — implements the `DataAdapter<TDoc>` contract from
69
104
  * `@classytic/repo-core/adapter`.
70
105
  */
71
106
  var MongooseAdapter = class {
72
107
  type = "mongoose";
73
108
  name;
109
+ /**
110
+ * The model as given. Its document type is NOT `TDoc` — a lean repository
111
+ * legitimately pairs with a hydrated schema-inferred model, so claiming
112
+ * `Model<TDoc>` here was an assertion the code could not honour. Read it for
113
+ * `modelName` and `.schema`; narrow it yourself if you need document typing.
114
+ */
74
115
  model;
75
116
  repository;
76
117
  schemaGenerator;
77
118
  constructor(options) {
78
119
  if (!isMongooseModel(options.model)) throw new TypeError(formatInvalidModelError(options.model));
79
120
  if (!isRepository(options.repository)) throw new TypeError(formatInvalidRepositoryError(options.repository, options.model));
121
+ assertModelMatchesRepository(options.model, options.repository);
80
122
  this.model = options.model;
81
123
  this.repository = asRepositoryLike(options.repository);
82
124
  this.schemaGenerator = options.schemaGenerator === false ? void 0 : options.schemaGenerator ?? buildCrudSchemasFromModel;
@@ -1,5 +1,5 @@
1
1
  import { n as Repository } from "../Repository-BArvU32x.mjs";
2
- import { n as createMongooseAdapter } from "../adapter-DlaOGcQN.mjs";
2
+ import { n as createMongooseAdapter } from "../adapter-Bfqz8yHE.mjs";
3
3
  import { asReadOnlyRepo } from "@classytic/repo-core/repository";
4
4
  import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
5
5
  //#region src/better-auth/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.35.0",
3
+ "version": "3.36.0",
4
4
  "description": "Production-grade MongoDB repositories - smart pagination, events, and plugins. Built on @classytic/repo-core.",
5
5
  "type": "module",
6
6
  "sideEffects": false,