@classytic/mongokit 3.13.1 → 3.13.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.
@@ -2934,8 +2934,11 @@ var Repository = class extends RepositoryBase {
2934
2934
  * `context.filter`, which is merged into the pre-aggregate `$match`
2935
2935
  * before compilation.
2936
2936
  */
2937
- async aggregate(req) {
2938
- const context = await this._buildContext("aggregate", { aggRequest: req });
2937
+ async aggregate(req, options = {}) {
2938
+ const context = await this._buildContext("aggregate", {
2939
+ aggRequest: req,
2940
+ ...options
2941
+ });
2939
2942
  const cached = this._cachedValue(context);
2940
2943
  if (cached !== void 0) {
2941
2944
  await this._emitHook("after:aggregate", {
@@ -2988,8 +2991,11 @@ var Repository = class extends RepositoryBase {
2988
2991
  * `after`. Scales to arbitrary group counts because the planner
2989
2992
  * uses `(sort_keys) > (cursor)` instead of `OFFSET N`.
2990
2993
  */
2991
- async aggregatePaginate(req) {
2992
- const context = await this._buildContext("aggregatePaginate", { aggRequest: req });
2994
+ async aggregatePaginate(req, options = {}) {
2995
+ const context = await this._buildContext("aggregatePaginate", {
2996
+ aggRequest: req,
2997
+ ...options
2998
+ });
2993
2999
  const limit = Math.max(1, Math.min(req.limit ?? 20, 1e3));
2994
3000
  const session = context.session;
2995
3001
  const useKeyset = isKeysetMode(req);
@@ -1,4 +1,4 @@
1
- import { n as Repository } from "../Repository-d5gWSROf.mjs";
1
+ import { n as Repository } from "../Repository-DwJFh3XA.mjs";
2
2
  import { n as createMongooseAdapter } from "../adapter-DTDMnUOH.mjs";
3
3
  import { pluralizeBetterAuthCollection, resolveBetterAuthCollections } from "@classytic/repo-core/better-auth";
4
4
  //#region src/better-auth/index.ts
package/dist/index.d.mts CHANGED
@@ -7,7 +7,7 @@ import { n as SchemaIndexes } from "./indexes-CgOF7Wjd.mjs";
7
7
  import { a as createFieldPreset, c as getMongooseProjection, d as parseDuplicateKeyError, i as configureLogger, l as createError, n as buildCrudSchemasFromMongooseSchema, o as filterResponseData, r as createMemoryCache, s as getFieldsForUser, t as buildCrudSchemasFromModel, u as isDuplicateKeyError } from "./mongooseToJsonSchema-BgRAaXX-.mjs";
8
8
  import * as _$mongoose from "mongoose";
9
9
  import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
10
- import { AggPaginationRequest, AggRequest, AggResult, KeysetAggPaginationResult, RepositoryBase } from "@classytic/repo-core/repository";
10
+ import { AggPaginationRequest, AggRequest, AggResult, KeysetAggPaginationResult, QueryOptions, RepositoryBase } from "@classytic/repo-core/repository";
11
11
  import { UpdateInput } from "@classytic/repo-core/update";
12
12
  import { AggregatePaginationResult, KeysetPaginationResult, OffsetPaginationResult, OffsetPaginationResultCore } from "@classytic/repo-core/pagination";
13
13
  import { HttpError } from "@classytic/repo-core/errors";
@@ -1639,7 +1639,7 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
1639
1639
  * `context.filter`, which is merged into the pre-aggregate `$match`
1640
1640
  * before compilation.
1641
1641
  */
1642
- aggregate<TRow extends Record<string, unknown> = Record<string, unknown>>(req: AggRequest): Promise<AggResult<TRow>>;
1642
+ aggregate<TRow extends Record<string, unknown> = Record<string, unknown>>(req: AggRequest, options?: QueryOptions): Promise<AggResult<TRow>>;
1643
1643
  /**
1644
1644
  * Invalidate every aggregate-cache entry tagged with ANY of the
1645
1645
  * given tags. Delegates to the unified cache plugin's handle
@@ -1670,7 +1670,7 @@ declare class Repository<TDoc = unknown> extends RepositoryBase {
1670
1670
  * `after`. Scales to arbitrary group counts because the planner
1671
1671
  * uses `(sort_keys) > (cursor)` instead of `OFFSET N`.
1672
1672
  */
1673
- aggregatePaginate<TRow extends Record<string, unknown> = Record<string, unknown>>(req: AggPaginationRequest): Promise<OffsetPaginationResultCore<TRow> | KeysetAggPaginationResult<TRow>>;
1673
+ aggregatePaginate<TRow extends Record<string, unknown> = Record<string, unknown>>(req: AggPaginationRequest, options?: QueryOptions): Promise<OffsetPaginationResultCore<TRow> | KeysetAggPaginationResult<TRow>>;
1674
1674
  /**
1675
1675
  * Internal: the actual aggregate-paginate execution body. Extracted
1676
1676
  * so `aggregatePaginate` can wrap it in the cache layer without
package/dist/index.mjs CHANGED
@@ -2,9 +2,9 @@ import { b as LookupBuilder, x as compileFilterToMongo } from "./update-C-3viiw1
2
2
  import { n as warn, t as configureLogger } from "./logger-DprijP5h.mjs";
3
3
  import { n as isDuplicateKeyError, r as parseDuplicateKeyError, t as createError } from "./error-B00pI7dV.mjs";
4
4
  import { t as actions_exports } from "./actions/index.mjs";
5
- import { a as withTransaction, c as MUTATING_OPERATIONS, d as operationsByPolicyKey, i as isTransactionUnsupported, l as OP_REGISTRY, n as Repository, o as AggregationBuilder, r as batchTransaction, s as ALL_OPERATIONS, t as HOOK_PRIORITY, u as READ_OPERATIONS } from "./Repository-d5gWSROf.mjs";
5
+ import { a as withTransaction, c as MUTATING_OPERATIONS, d as operationsByPolicyKey, i as isTransactionUnsupported, l as OP_REGISTRY, n as Repository, o as AggregationBuilder, r as batchTransaction, s as ALL_OPERATIONS, t as HOOK_PRIORITY, u as READ_OPERATIONS } from "./Repository-DwJFh3XA.mjs";
6
6
  import { t as PaginationEngine } from "./PaginationEngine-CfQRM1yz.mjs";
7
- import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, f as adminBypass, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "./validation-chain.plugin-BLVp_Pw2.mjs";
7
+ import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, f as adminBypass, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "./validation-chain.plugin-Pj2aD17U.mjs";
8
8
  import { i as getMongooseProjection, n as filterResponseData, r as getFieldsForUser, t as createFieldPreset } from "./field-selection-Br3WPOEb.mjs";
9
9
  import { isGeoOperator, parseGeoFilter } from "./query/primitives/geo.mjs";
10
10
  import { buildFieldTypeMap, coerceFieldValue, coerceHeuristic } from "./query/primitives/coercion.mjs";
@@ -0,0 +1,28 @@
1
+ import { Connection } from "mongoose";
2
+ import { BaseLockAdapterOptions, LockAdapter } from "@classytic/repo-core/lock";
3
+
4
+ //#region src/lock/index.d.ts
5
+ /** Adapter-construction options. */
6
+ interface MongoLockAdapterOptions extends BaseLockAdapterOptions {
7
+ /**
8
+ * Mongoose connection. Defaults to `mongoose.connection` (the
9
+ * default global connection) — most apps connect once via
10
+ * `mongoose.connect()` and want every primitive to share that
11
+ * handle. Apps using a named connection
12
+ * (`mongoose.createConnection(...)`) pass it explicitly.
13
+ */
14
+ connection?: Connection;
15
+ /** Collection name. Default `mongo_locks`. */
16
+ collectionName?: string;
17
+ /** Override the Mongoose model name. Default `MongoLock`. */
18
+ modelName?: string;
19
+ }
20
+ /**
21
+ * Build a Mongo-backed lock adapter. Idempotent — the underlying
22
+ * model is registered once per `(connection, modelName)` pair, so
23
+ * calling this multiple times with the same options shares the same
24
+ * collection (no duplicate-model errors).
25
+ */
26
+ declare function createMongoLockAdapter(options?: MongoLockAdapterOptions): LockAdapter;
27
+ //#endregion
28
+ export { MongoLockAdapterOptions, createMongoLockAdapter };
@@ -0,0 +1,92 @@
1
+ import mongoose, { Schema } from "mongoose";
2
+ //#region src/lock/index.ts
3
+ /**
4
+ * Build a Mongo-backed lock adapter. Idempotent — the underlying
5
+ * model is registered once per `(connection, modelName)` pair, so
6
+ * calling this multiple times with the same options shares the same
7
+ * collection (no duplicate-model errors).
8
+ */
9
+ function createMongoLockAdapter(options = {}) {
10
+ const { connection, collectionName = "mongo_locks", modelName = "MongoLock", defaultLeaseMs = 3e4 } = options;
11
+ const model = getOrCreateModel(connection ?? mongoose, modelName, collectionName);
12
+ return {
13
+ async tryAcquire(name, holderId, leaseMs) {
14
+ const ms = leaseMs > 0 ? leaseMs : defaultLeaseMs;
15
+ const now = /* @__PURE__ */ new Date();
16
+ const expiresAt = new Date(now.getTime() + ms);
17
+ try {
18
+ const result = await model.findOneAndUpdate({
19
+ _id: name,
20
+ $or: [{ expiresAt: { $lt: now } }, { holder: holderId }]
21
+ }, {
22
+ $set: {
23
+ holder: holderId,
24
+ expiresAt
25
+ },
26
+ $setOnInsert: { acquiredAt: now }
27
+ }, {
28
+ upsert: true,
29
+ returnDocument: "after",
30
+ setDefaultsOnInsert: true
31
+ }).lean();
32
+ return !!result && result.holder === holderId;
33
+ } catch (err) {
34
+ if (err?.code === 11e3) return false;
35
+ throw err;
36
+ }
37
+ },
38
+ async release(name, holderId) {
39
+ return !!await model.findOneAndDelete({
40
+ _id: name,
41
+ holder: holderId
42
+ }).lean();
43
+ },
44
+ async inspect(name) {
45
+ const doc = await model.findById(name).lean();
46
+ if (!doc) return null;
47
+ if (doc.expiresAt.getTime() <= Date.now()) return null;
48
+ return {
49
+ name,
50
+ holder: doc.holder,
51
+ expiresAt: doc.expiresAt,
52
+ acquiredAt: doc.acquiredAt
53
+ };
54
+ }
55
+ };
56
+ }
57
+ /**
58
+ * Idempotent model registration. Mongoose throws OverwriteModelError
59
+ * if `model('Name', schema)` is called twice with the same name on
60
+ * the same connection — this guard makes the adapter safe to
61
+ * construct multiple times in tests / hot-reload setups.
62
+ */
63
+ function getOrCreateModel(conn, modelName, collectionName) {
64
+ const existing = "models" in conn ? conn.models[modelName] : void 0;
65
+ if (existing) return existing;
66
+ const schema = new Schema({
67
+ _id: {
68
+ type: String,
69
+ required: true
70
+ },
71
+ holder: {
72
+ type: String,
73
+ required: true
74
+ },
75
+ expiresAt: {
76
+ type: Date,
77
+ required: true
78
+ },
79
+ acquiredAt: {
80
+ type: Date,
81
+ required: true
82
+ }
83
+ }, {
84
+ versionKey: false,
85
+ timestamps: false,
86
+ _id: false
87
+ });
88
+ schema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
89
+ return conn.model(modelName, schema, collectionName);
90
+ }
91
+ //#endregion
92
+ export { createMongoLockAdapter };
@@ -1,2 +1,2 @@
1
- import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "../validation-chain.plugin-BLVp_Pw2.mjs";
1
+ import { A as aggregateHelpersPlugin, C as sequentialId, D as AuditTrailQuery, E as batchOperationsPlugin, O as auditTrailPlugin, S as prefixedId, T as cachePlugin, _ as fieldFilterPlugin, a as uniqueField, b as dateSequentialId, c as createTenantContext, d as observabilityPlugin, g as leasePlugin, h as methodRegistryPlugin, i as requireField, k as auditLogPlugin, l as subdocumentPlugin, m as mongoOperationsPlugin, n as blockIf, o as validationChainPlugin, p as multiTenantPlugin, r as immutableField, s as timestampPlugin, t as autoInject, u as softDeletePlugin, v as elasticSearchPlugin, w as cascadePlugin, x as getNextSequence, y as customIdPlugin } from "../validation-chain.plugin-Pj2aD17U.mjs";
2
2
  export { AuditTrailQuery, aggregateHelpersPlugin, auditLogPlugin, auditTrailPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, createTenantContext, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, getNextSequence, immutableField, leasePlugin, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
@@ -1,7 +1,7 @@
1
1
  import { _ as upsert } from "./update-C-3viiw1.mjs";
2
2
  import { n as warn } from "./logger-DprijP5h.mjs";
3
3
  import { t as createError } from "./error-B00pI7dV.mjs";
4
- import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-d5gWSROf.mjs";
4
+ import { l as OP_REGISTRY, s as ALL_OPERATIONS, t as HOOK_PRIORITY } from "./Repository-DwJFh3XA.mjs";
5
5
  import { r as getFieldsForUser } from "./field-selection-Br3WPOEb.mjs";
6
6
  import mongoose from "mongoose";
7
7
  import { cachePlugin } from "@classytic/repo-core/cache";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/mongokit",
3
- "version": "3.13.1",
3
+ "version": "3.13.2",
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,
@@ -40,6 +40,10 @@
40
40
  "types": "./dist/better-auth/index.d.mts",
41
41
  "default": "./dist/better-auth/index.mjs"
42
42
  },
43
+ "./lock": {
44
+ "types": "./dist/lock/index.d.mts",
45
+ "default": "./dist/lock/index.mjs"
46
+ },
43
47
  "./query/primitives/geo": {
44
48
  "types": "./dist/query/primitives/geo.d.mts",
45
49
  "default": "./dist/query/primitives/geo.mjs"