@classytic/mongokit 3.11.1 → 3.13.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.
- package/README.md +75 -5
- package/dist/{PaginationEngine-CvDFfVXT.mjs → PaginationEngine-CfQRM1yz.mjs} +16 -16
- package/dist/Repository-BY40uhcv.mjs +3603 -0
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/adapter/index.d.mts +190 -0
- package/dist/adapter/index.mjs +2 -0
- package/dist/adapter-DTDMnUOH.mjs +158 -0
- package/dist/ai/index.d.mts +1 -1
- package/dist/ai/index.mjs +3 -3
- package/dist/better-auth/index.d.mts +149 -0
- package/dist/better-auth/index.mjs +81 -0
- package/dist/field-selection-Br3WPOEb.mjs +99 -0
- package/dist/{index-dNTmpgK8.d.mts → index-BbHaKwi5.d.mts} +33 -13
- package/dist/index.d.mts +678 -36
- package/dist/index.mjs +240 -17
- package/dist/{logger-DJ7egMnd.mjs → logger-DprijP5h.mjs} +1 -5
- package/dist/{mongooseToJsonSchema-D1sdCOmj.mjs → mongooseToJsonSchema-BYbG894y.mjs} +68 -20
- package/dist/{mongooseToJsonSchema-DXxjFkLB.d.mts → mongooseToJsonSchema-BgRAaXX-.d.mts} +10 -2
- package/dist/pagination/PaginationEngine.d.mts +3 -2
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +2 -2
- package/dist/query/primitives/coercion.d.mts +1 -1
- package/dist/query/primitives/coercion.mjs +1 -1
- package/dist/query/primitives/indexes.d.mts +1 -1
- package/dist/{types-Dc2aDVUi.d.mts → types-BbaPZleN.d.mts} +419 -205
- package/dist/{update-DEJYcgfV.mjs → update-DLcSSa5b.mjs} +184 -45
- package/dist/utils/index.d.mts +2 -91
- package/dist/utils/index.mjs +5 -5
- package/dist/{validation-chain.plugin-B0VSdcwa.d.mts → validation-chain.plugin-CAPYCj_T.d.mts} +228 -98
- package/dist/validation-chain.plugin-_-WuNml2.mjs +2399 -0
- package/package.json +25 -5
- package/dist/field-selection-dI0m4RBs.mjs +0 -221
- package/dist/validation-chain.plugin-Dllv-cml.mjs +0 -5122
- /package/dist/{coercion-oM8G4b6m.d.mts → coercion-TRMmR49h.d.mts} +0 -0
- /package/dist/{id-resolution-e4BT9zAV.mjs → id-resolution-B0Odvvou.mjs} +0 -0
- /package/dist/{indexes-C26GNZRU.d.mts → indexes-CgOF7Wjd.d.mts} +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//#region src/utils/field-selection.ts
|
|
2
|
+
/**
|
|
3
|
+
* Get allowed fields for a user based on their context
|
|
4
|
+
*
|
|
5
|
+
* @param user - User object from request.user (or null for public)
|
|
6
|
+
* @param preset - Field preset configuration
|
|
7
|
+
* @returns Array of allowed field names
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const fields = getFieldsForUser(request.user, {
|
|
11
|
+
* public: ['id', 'name', 'price'],
|
|
12
|
+
* authenticated: ['description', 'features'],
|
|
13
|
+
* admin: ['createdAt', 'internalNotes']
|
|
14
|
+
* });
|
|
15
|
+
*/
|
|
16
|
+
function getFieldsForUser(user, preset) {
|
|
17
|
+
if (!preset) throw new Error("Field preset is required");
|
|
18
|
+
const fields = [...preset.public || []];
|
|
19
|
+
if (user) {
|
|
20
|
+
fields.push(...preset.authenticated || []);
|
|
21
|
+
const roles = Array.isArray(user.roles) ? user.roles : user.roles ? [user.roles] : [];
|
|
22
|
+
if (roles.includes("admin") || roles.includes("superadmin")) fields.push(...preset.admin || []);
|
|
23
|
+
}
|
|
24
|
+
return [...new Set(fields)];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get Mongoose projection string for query .select()
|
|
28
|
+
*
|
|
29
|
+
* @param user - User object from request.user
|
|
30
|
+
* @param preset - Field preset configuration
|
|
31
|
+
* @returns Space-separated field names for Mongoose .select()
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);
|
|
35
|
+
* const plans = await GymPlan.find({ organizationId }).select(projection).lean();
|
|
36
|
+
*/
|
|
37
|
+
function getMongooseProjection(user, preset) {
|
|
38
|
+
return getFieldsForUser(user, preset).join(" ");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Filter a single object to include only allowed fields
|
|
42
|
+
*/
|
|
43
|
+
function filterObject(obj, allowedFields) {
|
|
44
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
45
|
+
const filtered = {};
|
|
46
|
+
for (const field of allowedFields) if (field in obj) filtered[field] = obj[field];
|
|
47
|
+
return filtered;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Filter response data to include only allowed fields
|
|
51
|
+
*
|
|
52
|
+
* Use this for complex responses where Mongoose projections aren't applicable:
|
|
53
|
+
* - Aggregation pipeline results
|
|
54
|
+
* - Data from multiple sources
|
|
55
|
+
* - Custom computed fields
|
|
56
|
+
*
|
|
57
|
+
* For simple DB queries, prefer getMongooseProjection() (10x faster)
|
|
58
|
+
*
|
|
59
|
+
* @param data - Data to filter
|
|
60
|
+
* @param preset - Field preset configuration
|
|
61
|
+
* @param user - User object from request.user
|
|
62
|
+
* @returns Filtered data
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const stats = await calculateComplexStats();
|
|
66
|
+
* const filtered = filterResponseData(stats, fieldPresets.dashboard, request.user);
|
|
67
|
+
* return reply.send(filtered);
|
|
68
|
+
*/
|
|
69
|
+
function filterResponseData(data, preset, user = null) {
|
|
70
|
+
const allowedFields = getFieldsForUser(user, preset);
|
|
71
|
+
if (Array.isArray(data)) return data.map((item) => filterObject(item, allowedFields));
|
|
72
|
+
return filterObject(data, allowedFields);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Helper to create field presets (module-level)
|
|
76
|
+
*
|
|
77
|
+
* Each module should define its own field preset in its own directory.
|
|
78
|
+
* This keeps modules independent and self-contained.
|
|
79
|
+
*
|
|
80
|
+
* @param config - Field configuration
|
|
81
|
+
* @returns Field preset
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // In modules/gym-plan/gym-plan.fields.ts
|
|
85
|
+
* export const gymPlanFieldPreset = createFieldPreset({
|
|
86
|
+
* public: ['id', 'name', 'price'],
|
|
87
|
+
* authenticated: ['features', 'description'],
|
|
88
|
+
* admin: ['createdAt', 'updatedAt', 'internalNotes']
|
|
89
|
+
* });
|
|
90
|
+
*/
|
|
91
|
+
function createFieldPreset(config) {
|
|
92
|
+
return {
|
|
93
|
+
public: config.public || [],
|
|
94
|
+
authenticated: config.authenticated || [],
|
|
95
|
+
admin: config.admin || []
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { getMongooseProjection as i, filterResponseData as n, getFieldsForUser as r, createFieldPreset as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as ObjectId, Dt as LookupOptions, H as OperationOptions, I as MinMaxResult, J as PopulateSpec, T as GroupResult, Z as ReadPreferenceType, ft as UpdateManyResult, ht as UpdateWithValidationResult, i as AnyDocument, it as SelectSpec, p as CreateOptions, pt as UpdateOptions, ut as SortSpec, v as DeleteResult, w as FindOneAndUpdateOptions } from "./types-BbaPZleN.mjs";
|
|
2
2
|
import { Model, PipelineStage } from "mongoose";
|
|
3
3
|
|
|
4
4
|
//#region src/actions/aggregate.d.ts
|
|
@@ -21,7 +21,7 @@ declare function aggregatePaginate<TDoc = AnyDocument>(Model: Model<TDoc>, pipel
|
|
|
21
21
|
limit?: number;
|
|
22
22
|
session?: unknown;
|
|
23
23
|
}): Promise<{
|
|
24
|
-
|
|
24
|
+
data: TDoc[];
|
|
25
25
|
total: number;
|
|
26
26
|
page: number;
|
|
27
27
|
limit: number;
|
|
@@ -116,38 +116,43 @@ declare namespace delete_d_exports {
|
|
|
116
116
|
export { deleteById, deleteByQuery, deleteMany, restore, softDelete };
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
119
|
-
* Delete by ID
|
|
119
|
+
* Delete by ID. Returns `null` on miss (matches `update()` convention) —
|
|
120
|
+
* a second delete on the same id is a no-op, not an error.
|
|
120
121
|
*/
|
|
121
122
|
declare function deleteById<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: {
|
|
122
123
|
session?: unknown;
|
|
123
124
|
query?: Record<string, unknown>;
|
|
124
|
-
}): Promise<DeleteResult>;
|
|
125
|
+
}): Promise<DeleteResult | null>;
|
|
125
126
|
/**
|
|
126
|
-
* Delete many documents
|
|
127
|
+
* Delete many documents. Always returns a {@link DeleteResult} (never
|
|
128
|
+
* null) — a deleteMany with zero matches is a successful op with
|
|
129
|
+
* `count: 0`, not a miss.
|
|
127
130
|
*/
|
|
128
131
|
declare function deleteMany<TDoc = AnyDocument>(Model: Model<TDoc>, query: Record<string, unknown>, options?: {
|
|
129
132
|
session?: unknown;
|
|
130
133
|
}): Promise<DeleteResult>;
|
|
131
134
|
/**
|
|
132
|
-
* Delete by query
|
|
135
|
+
* Delete by query. Returns `null` on miss unless `throwOnNotFound: true`.
|
|
133
136
|
*/
|
|
134
137
|
declare function deleteByQuery(Model: Model<any>, query: Record<string, unknown>, options?: {
|
|
135
138
|
session?: unknown;
|
|
136
139
|
throwOnNotFound?: boolean;
|
|
137
|
-
}): Promise<DeleteResult>;
|
|
140
|
+
}): Promise<DeleteResult | null>;
|
|
138
141
|
/**
|
|
139
|
-
* Soft delete (set deleted flag)
|
|
142
|
+
* Soft delete (set deleted flag). Returns `null` on miss for parity with
|
|
143
|
+
* `deleteById`; callers that prefer a throw can wrap or use `throwOnNotFound`
|
|
144
|
+
* pattern at the call site.
|
|
140
145
|
*/
|
|
141
146
|
declare function softDelete<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: {
|
|
142
147
|
session?: unknown;
|
|
143
148
|
userId?: string;
|
|
144
|
-
}): Promise<DeleteResult>;
|
|
149
|
+
}): Promise<DeleteResult | null>;
|
|
145
150
|
/**
|
|
146
|
-
* Restore soft
|
|
151
|
+
* Restore soft-deleted document. Returns `null` on miss.
|
|
147
152
|
*/
|
|
148
153
|
declare function restore<TDoc = AnyDocument>(Model: Model<TDoc>, id: string | ObjectId, options?: {
|
|
149
154
|
session?: unknown;
|
|
150
|
-
}): Promise<DeleteResult>;
|
|
155
|
+
}): Promise<DeleteResult | null>;
|
|
151
156
|
declare namespace read_d_exports {
|
|
152
157
|
export { count, exists, getAll, getById, getByQuery, getOrCreate, tryGetByQuery };
|
|
153
158
|
}
|
|
@@ -190,12 +195,27 @@ declare function getAll<TDoc = AnyDocument>(Model: Model<TDoc>, query?: Record<s
|
|
|
190
195
|
readPreference?: ReadPreferenceType;
|
|
191
196
|
}): Promise<TDoc[]>;
|
|
192
197
|
/**
|
|
193
|
-
* Get or create document (upsert)
|
|
198
|
+
* Get or create document (atomic upsert).
|
|
199
|
+
*
|
|
200
|
+
* Returns `{ doc, created }` so callers can disambiguate the two
|
|
201
|
+
* outcomes without a follow-up read — load-bearing for race-detection
|
|
202
|
+
* in idempotency stores, lock acquisition, and "ensure-exists" flows.
|
|
203
|
+
*
|
|
204
|
+
* `created: true` ⇔ this caller's `createData` won the race and was
|
|
205
|
+
* just inserted; `created: false` ⇔ a doc matching `query` already
|
|
206
|
+
* existed and was returned unchanged.
|
|
207
|
+
*
|
|
208
|
+
* Mongo: `includeResultMetadata: true` returns the raw `ModifyResult`
|
|
209
|
+
* (`{ value, lastErrorObject, ok }`). `lastErrorObject.upserted` is
|
|
210
|
+
* the `_id` of a freshly-inserted row — present iff this call inserted.
|
|
194
211
|
*/
|
|
195
212
|
declare function getOrCreate<TDoc = AnyDocument>(Model: Model<TDoc>, query: Record<string, unknown>, createData: Record<string, unknown>, options?: {
|
|
196
213
|
session?: unknown;
|
|
197
214
|
updatePipeline?: boolean;
|
|
198
|
-
}): Promise<
|
|
215
|
+
}): Promise<{
|
|
216
|
+
doc: TDoc;
|
|
217
|
+
created: boolean;
|
|
218
|
+
}>;
|
|
199
219
|
/**
|
|
200
220
|
* Count documents matching query
|
|
201
221
|
*/
|