@classytic/mongokit 3.2.0 → 3.2.2
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 +470 -193
- package/dist/actions/index.d.mts +9 -0
- package/dist/actions/index.mjs +15 -0
- package/dist/aggregate-BAi4Do-X.mjs +767 -0
- package/dist/aggregate-CCHI7F51.d.mts +269 -0
- package/dist/ai/index.d.mts +125 -0
- package/dist/ai/index.mjs +203 -0
- package/dist/cache-keys-C8Z9B5sw.mjs +204 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/create-BuO6xt0v.mjs +55 -0
- package/dist/custom-id.plugin-B_zIs6gE.mjs +1818 -0
- package/dist/custom-id.plugin-BzZI4gnE.d.mts +893 -0
- package/dist/index.d.mts +1012 -0
- package/dist/index.mjs +1906 -0
- package/dist/limits-DsNeCx4D.mjs +299 -0
- package/dist/logger-D8ily-PP.mjs +51 -0
- package/dist/mongooseToJsonSchema-COdDEkIJ.mjs +317 -0
- package/dist/{mongooseToJsonSchema-CaRF_bCN.d.ts → mongooseToJsonSchema-Wbvjfwkn.d.mts} +16 -89
- package/dist/pagination/PaginationEngine.d.mts +93 -0
- package/dist/pagination/PaginationEngine.mjs +196 -0
- package/dist/plugins/index.d.mts +3 -0
- package/dist/plugins/index.mjs +3 -0
- package/dist/types-D-gploPr.d.mts +1241 -0
- package/dist/utils/{index.d.ts → index.d.mts} +14 -21
- package/dist/utils/index.mjs +5 -0
- package/package.json +21 -21
- package/dist/actions/index.d.ts +0 -3
- package/dist/actions/index.js +0 -5
- package/dist/ai/index.d.ts +0 -175
- package/dist/ai/index.js +0 -206
- package/dist/chunks/chunk-2ZN65ZOP.js +0 -93
- package/dist/chunks/chunk-44KXLGPO.js +0 -388
- package/dist/chunks/chunk-DEVXDBRL.js +0 -1226
- package/dist/chunks/chunk-I7CWNAJB.js +0 -46
- package/dist/chunks/chunk-JWUAVZ3L.js +0 -8
- package/dist/chunks/chunk-UE2IEXZJ.js +0 -306
- package/dist/chunks/chunk-URLJFIR7.js +0 -22
- package/dist/chunks/chunk-VWKIKZYF.js +0 -737
- package/dist/chunks/chunk-WSFCRVEQ.js +0 -7
- package/dist/index-BDn5fSTE.d.ts +0 -516
- package/dist/index.d.ts +0 -1422
- package/dist/index.js +0 -1893
- package/dist/pagination/PaginationEngine.d.ts +0 -117
- package/dist/pagination/PaginationEngine.js +0 -3
- package/dist/plugins/index.d.ts +0 -922
- package/dist/plugins/index.js +0 -6
- package/dist/types-Jni1KgkP.d.ts +0 -780
- package/dist/utils/index.js +0 -5
|
@@ -0,0 +1,204 @@
|
|
|
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
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/utils/cache-keys.ts
|
|
101
|
+
/**
|
|
102
|
+
* Simple hash function for query parameters
|
|
103
|
+
* Using djb2 algorithm - fast and good distribution
|
|
104
|
+
*/
|
|
105
|
+
function hashString(str) {
|
|
106
|
+
let hash = 5381;
|
|
107
|
+
for (let i = 0; i < str.length; i++) hash = (hash << 5) + hash ^ str.charCodeAt(i);
|
|
108
|
+
return (hash >>> 0).toString(16);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Normalize and stringify an object for hashing
|
|
112
|
+
* Ensures deterministic key generation regardless of property order
|
|
113
|
+
*/
|
|
114
|
+
function stableStringify(obj) {
|
|
115
|
+
if (obj === null || obj === void 0) return "";
|
|
116
|
+
if (typeof obj !== "object") return String(obj);
|
|
117
|
+
if (Array.isArray(obj)) return "[" + obj.map(stableStringify).join(",") + "]";
|
|
118
|
+
return "{" + Object.keys(obj).sort().map((key) => `${key}:${stableStringify(obj[key])}`).join(",") + "}";
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Generate cache key for getById operations
|
|
122
|
+
*
|
|
123
|
+
* Format: {prefix}:id:{model}:{documentId}
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* byIdKey('mk', 'User', '507f1f77bcf86cd799439011')
|
|
127
|
+
* // => 'mk:id:User:507f1f77bcf86cd799439011'
|
|
128
|
+
*/
|
|
129
|
+
function byIdKey(prefix, model, id) {
|
|
130
|
+
return `${prefix}:id:${model}:${id}`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generate cache key for single-document queries
|
|
134
|
+
*
|
|
135
|
+
* Format: {prefix}:one:{model}:{queryHash}
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* byQueryKey('mk', 'User', { email: 'john@example.com' })
|
|
139
|
+
* // => 'mk:one:User:a1b2c3d4'
|
|
140
|
+
*/
|
|
141
|
+
function byQueryKey(prefix, model, query, options) {
|
|
142
|
+
return `${prefix}:one:${model}:${hashString(stableStringify({
|
|
143
|
+
q: query,
|
|
144
|
+
s: options?.select,
|
|
145
|
+
p: options?.populate
|
|
146
|
+
}))}`;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Generate cache key for paginated list queries
|
|
150
|
+
*
|
|
151
|
+
* Format: {prefix}:list:{model}:{version}:{queryHash}
|
|
152
|
+
*
|
|
153
|
+
* The version component enables efficient bulk invalidation:
|
|
154
|
+
* - On any mutation, bump the version
|
|
155
|
+
* - All list cache keys become invalid without scanning/deleting each
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* listQueryKey('mk', 'User', 1, { filters: { status: 'active' }, page: 1, limit: 20 })
|
|
159
|
+
* // => 'mk:list:User:1:e5f6g7h8'
|
|
160
|
+
*/
|
|
161
|
+
function listQueryKey(prefix, model, version, params) {
|
|
162
|
+
return `${prefix}:list:${model}:${version}:${hashString(stableStringify({
|
|
163
|
+
f: params.filters,
|
|
164
|
+
s: params.sort,
|
|
165
|
+
pg: params.page,
|
|
166
|
+
lm: params.limit,
|
|
167
|
+
af: params.after,
|
|
168
|
+
sl: params.select,
|
|
169
|
+
pp: params.populate
|
|
170
|
+
}))}`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Generate cache key for collection version tag
|
|
174
|
+
*
|
|
175
|
+
* Format: {prefix}:ver:{model}
|
|
176
|
+
*
|
|
177
|
+
* Used to track mutation version for list invalidation
|
|
178
|
+
*/
|
|
179
|
+
function versionKey(prefix, model) {
|
|
180
|
+
return `${prefix}:ver:${model}`;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Generate pattern for clearing all cache keys for a model
|
|
184
|
+
*
|
|
185
|
+
* Format: {prefix}:*:{model}:*
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* modelPattern('mk', 'User')
|
|
189
|
+
* // => 'mk:*:User:*'
|
|
190
|
+
*/
|
|
191
|
+
function modelPattern(prefix, model) {
|
|
192
|
+
return `${prefix}:*:${model}:*`;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Generate pattern for clearing all list cache keys for a model
|
|
196
|
+
*
|
|
197
|
+
* Format: {prefix}:list:{model}:*
|
|
198
|
+
*/
|
|
199
|
+
function listPattern(prefix, model) {
|
|
200
|
+
return `${prefix}:list:${model}:*`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
export { modelPattern as a, filterResponseData as c, listQueryKey as i, getFieldsForUser as l, byQueryKey as n, versionKey as o, listPattern as r, createFieldPreset as s, byIdKey as t, getMongooseProjection as u };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) {
|
|
6
|
+
__defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (!no_symbols) {
|
|
12
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
}
|
|
14
|
+
return target;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { __exportAll as t };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/actions/create.ts
|
|
4
|
+
var create_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
create: () => create,
|
|
6
|
+
createDefault: () => createDefault,
|
|
7
|
+
createMany: () => createMany,
|
|
8
|
+
upsert: () => upsert
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Create single document
|
|
12
|
+
*/
|
|
13
|
+
async function create(Model, data, options = {}) {
|
|
14
|
+
const document = new Model(data);
|
|
15
|
+
await document.save({ session: options.session });
|
|
16
|
+
return document;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create multiple documents
|
|
20
|
+
*/
|
|
21
|
+
async function createMany(Model, dataArray, options = {}) {
|
|
22
|
+
return Model.insertMany(dataArray, {
|
|
23
|
+
session: options.session,
|
|
24
|
+
ordered: options.ordered !== false
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create with defaults (useful for initialization)
|
|
29
|
+
*/
|
|
30
|
+
async function createDefault(Model, overrides = {}, options = {}) {
|
|
31
|
+
const defaults = {};
|
|
32
|
+
Model.schema.eachPath((path, schemaType) => {
|
|
33
|
+
const schemaOptions = schemaType.options;
|
|
34
|
+
if (schemaOptions.default !== void 0 && path !== "_id") defaults[path] = typeof schemaOptions.default === "function" ? schemaOptions.default() : schemaOptions.default;
|
|
35
|
+
});
|
|
36
|
+
return create(Model, {
|
|
37
|
+
...defaults,
|
|
38
|
+
...overrides
|
|
39
|
+
}, options);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Upsert (create or update)
|
|
43
|
+
*/
|
|
44
|
+
async function upsert(Model, query, data, options = {}) {
|
|
45
|
+
return Model.findOneAndUpdate(query, { $setOnInsert: data }, {
|
|
46
|
+
upsert: true,
|
|
47
|
+
returnDocument: "after",
|
|
48
|
+
runValidators: true,
|
|
49
|
+
session: options.session,
|
|
50
|
+
...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { upsert as i, createMany as n, create_exports as r, create as t };
|