@classytic/mongokit 3.43.1 → 3.44.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 +14 -0
- package/dist/{PaginationEngine-DZnkbSrr.mjs → PaginationEngine-C9iS0U5l.mjs} +13 -27
- package/dist/{PaginationEngine-CRHyuUtw.d.mts → PaginationEngine-D17AthKw.d.mts} +1 -3
- package/dist/{Repository-DnL4xk5w.d.mts → Repository-B6oL6OMv.d.mts} +33 -11
- package/dist/{Repository-Dj6xqPxJ.mjs → Repository-eMRYZ_2Y.mjs} +204 -92
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +2 -2
- package/dist/{actions-ChYfkPYP.mjs → actions-DExyXMTy.mjs} +3 -4
- package/dist/adapter/index.d.mts +6 -10
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-CkMoMF83.mjs → adapter-Qzgc3ZD_.mjs} +4 -6
- package/dist/ai/index.d.mts +21 -8
- package/dist/ai/index.mjs +15 -9
- package/dist/better-auth/index.d.mts +17 -19
- package/dist/better-auth/index.mjs +3 -4
- package/dist/{coercion-BjdPX3YF.d.mts → coercion-COp9DRNw.d.mts} +0 -2
- package/dist/{create-repository-CJtVdwig.d.mts → create-repository-BOFUYj1l.d.mts} +5 -7
- package/dist/{create-repository-UjwPWR1z.mjs → create-repository-D7MQpIZo.mjs} +4 -5
- package/dist/{derive-DRBiegRH.mjs → derive-Dxsc31fV.mjs} +3 -6
- package/dist/{error-BuByZwKU.mjs → error-DjdmPLWO.mjs} +1 -2
- package/dist/{field-selection-FSQFLpsU.mjs → field-selection-DPFaFw9Y.mjs} +1 -2
- package/dist/{id-chunks-BmAwsqNk.mjs → id-chunks-DH-RAZWG.mjs} +13 -8
- package/dist/{id-resolution-BqDrk0S2.mjs → id-resolution-Cqh49d9J.mjs} +1 -2
- package/dist/idempotency/index.d.mts +4 -7
- package/dist/idempotency/index.mjs +1 -2
- package/dist/{index-SYF8N28D.d.mts → index-8QUEsOFI.d.mts} +3 -4
- package/dist/{index-C0AjVqX3.d.mts → index-ehGZLbrd.d.mts} +2 -8
- package/dist/index.d.mts +63 -96
- package/dist/index.mjs +36 -52
- package/dist/indexes/verify-indexes.d.mts +8 -11
- package/dist/indexes/verify-indexes.mjs +1 -2
- package/dist/{indexes-DIjMpYES.d.mts → indexes-FfyOuhDK.d.mts} +0 -2
- package/dist/{join-scope-DSAznE8E.mjs → join-scope-C1gOtZ59.mjs} +2 -3
- package/dist/kernel-conformance/index.d.mts +39 -13
- package/dist/kernel-conformance/index.mjs +4 -7
- package/dist/lock/index.d.mts +134 -7
- package/dist/lock/index.mjs +349 -14
- package/dist/{logger-K7dPmu2U.mjs → logger-hbWOlj_X.mjs} +1 -2
- package/dist/{method-registry.plugin-C63pGn1d.mjs → method-registry.plugin-CGAepsBU.mjs} +3 -5
- package/dist/{model-registry-ClKtWiHa.mjs → model-registry-DrVfJ3Nt.mjs} +1 -2
- package/dist/{mongooseToJsonSchema-C3k4ide0.mjs → mongooseToJsonSchema-DMDotz4_.mjs} +2 -3
- package/dist/{multi-tenant.plugin-B_q9NUHc.d.mts → multi-tenant.plugin-DfeDMiI8.d.mts} +143 -11
- package/dist/{operations-XiFgG5US.d.mts → operations-Dw9OFV0V.d.mts} +14 -5
- package/dist/outbox/index.d.mts +24 -9
- package/dist/outbox/index.mjs +17 -6
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/pagination/utils/limits.d.mts +6 -9
- package/dist/pagination/utils/limits.mjs +2 -3
- package/dist/{pagination-D6psses0.d.mts → pagination-DAUg5zOY.d.mts} +2 -10
- package/dist/{plugin-options-Cirmb4Kp.d.mts → plugin-options-Bpcuz9kS.d.mts} +2 -4
- package/dist/plugins/index.d.mts +6 -7
- package/dist/plugins/index.mjs +6 -7
- package/dist/query/primitives/coercion.d.mts +1 -1
- package/dist/query/primitives/coercion.mjs +2 -3
- package/dist/query/primitives/geo.d.mts +11 -14
- package/dist/query/primitives/geo.mjs +1 -2
- package/dist/query/primitives/indexes.d.mts +1 -1
- package/dist/query/primitives/indexes.mjs +1 -2
- package/dist/{query-defaults-BxUcSOoF.mjs → query-defaults-aUoKlEbh.mjs} +2 -3
- package/dist/read-model/index.d.mts +18 -21
- package/dist/read-model/index.mjs +3 -4
- package/dist/{repository-MqAP409e.d.mts → repository-DzVIwhU2.d.mts} +25 -29
- package/dist/retention-purge-DqcYvRnG.d.mts +35 -0
- package/dist/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-D8jQpDG7.mjs} +1 -2
- package/dist/search/index.d.mts +1 -1
- package/dist/search/index.mjs +1 -1
- package/dist/sync/index.d.mts +95 -15
- package/dist/sync/index.mjs +308 -62
- package/dist/tenant/index.d.mts +8 -11
- package/dist/tenant/index.mjs +1 -2
- package/dist/testkit/index.d.mts +179 -23
- package/dist/testkit/index.mjs +421 -23
- package/dist/{timestamp.plugin-DpOWavVI.mjs → timestamp.plugin-Bz_zL9PX.mjs} +192 -49
- package/dist/{to-plain-vksRrLtc.mjs → to-plain-CEKv_ylg.mjs} +2 -4
- package/dist/{to-plain-o5tUY2nV.d.mts → to-plain-PO5r1Qoy.d.mts} +2 -16
- package/dist/{transaction-DmiB4k2P.mjs → transaction-C2PFxfIv.mjs} +5 -8
- package/dist/{type-utils-CLzRFtIA.d.mts → type-utils-CKvuewAL.d.mts} +0 -2
- package/dist/{update-WgeAUJ_I.mjs → update-DcfmNbJe.mjs} +12 -20
- package/dist/usage/index.d.mts +2 -5
- package/dist/usage/index.mjs +8 -6
- package/dist/utils/index.d.mts +8 -10
- package/dist/utils/index.mjs +7 -7
- package/dist/{validation-chain.plugin-BAeC5eVT.d.mts → validation-chain.plugin-B3gZCZj4.d.mts} +135 -48
- package/dist/{validation-chain.plugin-DRApTmkN.mjs → validation-chain.plugin-DNY6MIF6.mjs} +207 -55
- package/llms.txt +33 -0
- package/package.json +29 -25
- package/skills/mongokit/SKILL.md +112 -0
- package/skills/mongokit/references/pagination-search.md +87 -0
- package/skills/mongokit/references/plugins-tenancy.md +102 -0
- package/skills/mongokit/references/repository-api.md +83 -0
- package/skills/mongokit/references/transactions-outbox.md +101 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { a as ALL_OPERATIONS, s as OP_REGISTRY, t as HOOK_PRIORITY } from "./Repository-
|
|
2
|
-
import { n as warn } from "./logger-
|
|
3
|
-
import { n as declareCollectionScope } from "./join-scope-
|
|
1
|
+
import { a as ALL_OPERATIONS, s as OP_REGISTRY, t as HOOK_PRIORITY } from "./Repository-eMRYZ_2Y.mjs";
|
|
2
|
+
import { n as warn } from "./logger-hbWOlj_X.mjs";
|
|
3
|
+
import { n as declareCollectionScope } from "./join-scope-C1gOtZ59.mjs";
|
|
4
4
|
import { throwIfAborted, withRetry } from "@classytic/repo-core/repository";
|
|
5
5
|
import mongoose from "mongoose";
|
|
6
6
|
import { cachePlugin } from "@classytic/repo-core/cache";
|
|
7
7
|
import { adminBypass, payloadHasTenantField } from "@classytic/repo-core/plugins";
|
|
8
|
-
|
|
8
|
+
// src/plugins/audit-log.plugin.ts
|
|
9
9
|
/**
|
|
10
10
|
* Audit log plugin that logs all repository operations
|
|
11
11
|
*
|
|
@@ -102,8 +102,7 @@ function auditLogPlugin(logger) {
|
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
//#region src/plugins/audit-trail.plugin.ts
|
|
105
|
+
// src/plugins/audit-trail.plugin.ts
|
|
107
106
|
/**
|
|
108
107
|
* Audit Trail Plugin
|
|
109
108
|
*
|
|
@@ -631,8 +630,7 @@ var AuditTrailQuery = class {
|
|
|
631
630
|
});
|
|
632
631
|
}
|
|
633
632
|
};
|
|
634
|
-
|
|
635
|
-
//#region src/plugins/custom-id.plugin.ts
|
|
633
|
+
// src/plugins/custom-id.plugin.ts
|
|
636
634
|
/**
|
|
637
635
|
* Custom ID Plugin
|
|
638
636
|
*
|
|
@@ -711,10 +709,54 @@ const counterSchema = new mongoose.Schema({
|
|
|
711
709
|
* Falls back to the default mongoose connection if none is provided.
|
|
712
710
|
* Lazy-init to avoid model registration errors if mongoose isn't connected yet.
|
|
713
711
|
*/
|
|
714
|
-
function getCounterModel(connection) {
|
|
712
|
+
function getCounterModel(connection, collection) {
|
|
715
713
|
const conn = connection ?? mongoose.connection;
|
|
716
|
-
|
|
717
|
-
return conn.
|
|
714
|
+
const modelName = collection === void 0 || collection === "_mongokit_counters" ? "_MongoKitCounter" : `_MongoKitCounter:${collection}`;
|
|
715
|
+
if (conn.models[modelName]) return conn.models[modelName];
|
|
716
|
+
return conn.model(modelName, counterSchema, collection ?? "_mongokit_counters");
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Bind the atomic counter API to a connection and, optionally, a
|
|
720
|
+
* collection other than `_mongokit_counters`.
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* const counters = createSequenceCounter({ connection, collection: 'app_counters' });
|
|
724
|
+
* await withTransaction(connection, async (session) => {
|
|
725
|
+
* const seq = await counters.next('alert.stream', 1, session);
|
|
726
|
+
* });
|
|
727
|
+
*/
|
|
728
|
+
function createSequenceCounter(options = {}) {
|
|
729
|
+
const { connection, collection } = options;
|
|
730
|
+
assertCounterCollection("createSequenceCounter", collection);
|
|
731
|
+
const model = () => getCounterModel(connection, collection);
|
|
732
|
+
return {
|
|
733
|
+
next: (counterKey, increment = 1, session) => incrementCounter(model(), counterKey, increment, session),
|
|
734
|
+
read: (counterKey, session) => readCounter(model(), counterKey, session),
|
|
735
|
+
ensureAtLeast: (counterKey, floor, session) => raiseCounter(model(), counterKey, floor, session),
|
|
736
|
+
nextInPeriod: (baseKey, periodOptions) => nextInPeriod(model(), baseKey, periodOptions)
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
function assertCounterCollection(fn, collection) {
|
|
740
|
+
if (collection !== void 0 && (typeof collection !== "string" || collection.length === 0)) throw new Error(`${fn}: collection must be a non-empty string`);
|
|
741
|
+
}
|
|
742
|
+
async function incrementCounter(Counter, counterKey, increment, session) {
|
|
743
|
+
const result = await Counter.findOneAndUpdate({ _id: counterKey }, { $inc: { seq: increment } }, {
|
|
744
|
+
upsert: true,
|
|
745
|
+
returnDocument: "after",
|
|
746
|
+
session
|
|
747
|
+
});
|
|
748
|
+
if (!result) throw new Error(`Failed to increment counter '${counterKey}'`);
|
|
749
|
+
return result.seq;
|
|
750
|
+
}
|
|
751
|
+
async function raiseCounter(Counter, counterKey, floor, session) {
|
|
752
|
+
if (!Number.isSafeInteger(floor) || floor < 0) throw new Error(`ensureSequenceAtLeast: floor must be a non-negative integer, got ${floor}`);
|
|
753
|
+
const result = await Counter.findOneAndUpdate({ _id: counterKey }, { $max: { seq: floor } }, {
|
|
754
|
+
upsert: true,
|
|
755
|
+
returnDocument: "after",
|
|
756
|
+
session
|
|
757
|
+
});
|
|
758
|
+
if (!result) throw new Error(`Failed to seed counter '${counterKey}'`);
|
|
759
|
+
return result.seq;
|
|
718
760
|
}
|
|
719
761
|
/**
|
|
720
762
|
* Atomically increment and return the next sequence value for a given key.
|
|
@@ -746,20 +788,17 @@ function getCounterModel(connection) {
|
|
|
746
788
|
* });
|
|
747
789
|
*/
|
|
748
790
|
async function getNextSequence(counterKey, increment = 1, connection, session) {
|
|
749
|
-
|
|
750
|
-
upsert: true,
|
|
751
|
-
returnDocument: "after",
|
|
752
|
-
session
|
|
753
|
-
});
|
|
754
|
-
if (!result) throw new Error(`Failed to increment counter '${counterKey}'`);
|
|
755
|
-
return result.seq;
|
|
791
|
+
return incrementCounter(getCounterModel(connection), counterKey, increment, session);
|
|
756
792
|
}
|
|
757
793
|
/**
|
|
758
794
|
* Current value of a counter, or `null` when it has never been created.
|
|
759
795
|
* `null` and `0` differ: only a missing counter needs seeding.
|
|
760
796
|
*/
|
|
761
|
-
async function readSequence(counterKey, connection) {
|
|
762
|
-
|
|
797
|
+
async function readSequence(counterKey, connection, session) {
|
|
798
|
+
return readCounter(getCounterModel(connection), counterKey, session);
|
|
799
|
+
}
|
|
800
|
+
async function readCounter(Counter, counterKey, session) {
|
|
801
|
+
const doc = await Counter.findById(counterKey, null, session ? { session } : {}).lean();
|
|
763
802
|
return doc ? doc.seq : null;
|
|
764
803
|
}
|
|
765
804
|
/**
|
|
@@ -772,14 +811,109 @@ async function readSequence(counterKey, connection) {
|
|
|
772
811
|
*
|
|
773
812
|
* @returns The counter's value after the raise.
|
|
774
813
|
*/
|
|
775
|
-
async function ensureSequenceAtLeast(counterKey, floor, connection) {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
814
|
+
async function ensureSequenceAtLeast(counterKey, floor, connection, session) {
|
|
815
|
+
return raiseCounter(getCounterModel(connection), counterKey, floor, session);
|
|
816
|
+
}
|
|
817
|
+
const SEQUENCE_PERIODS = /* @__PURE__ */ new Set([
|
|
818
|
+
"year",
|
|
819
|
+
"month",
|
|
820
|
+
"day"
|
|
821
|
+
]);
|
|
822
|
+
/** One cached formatter per zone; construction is the expensive part of Intl. */
|
|
823
|
+
const civilFormatters = /* @__PURE__ */ new Map();
|
|
824
|
+
function civilFormatter(fn, timeZone) {
|
|
825
|
+
if (typeof timeZone !== "string" || timeZone.length === 0) throw new Error(`${fn}: timeZone must be a non-empty IANA time zone (e.g. 'Asia/Riyadh')`);
|
|
826
|
+
let formatter = civilFormatters.get(timeZone);
|
|
827
|
+
if (!formatter) {
|
|
828
|
+
try {
|
|
829
|
+
formatter = new Intl.DateTimeFormat("en-US", {
|
|
830
|
+
timeZone,
|
|
831
|
+
calendar: "gregory",
|
|
832
|
+
numberingSystem: "latn",
|
|
833
|
+
year: "numeric",
|
|
834
|
+
month: "2-digit",
|
|
835
|
+
day: "2-digit"
|
|
836
|
+
});
|
|
837
|
+
} catch {
|
|
838
|
+
throw new Error(`${fn}: unknown time zone '${timeZone}'`);
|
|
839
|
+
}
|
|
840
|
+
civilFormatters.set(timeZone, formatter);
|
|
841
|
+
}
|
|
842
|
+
return formatter;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* The civil date of an instant in a zone. Read from the zone's own rules
|
|
846
|
+
* (Intl), never by adding a fixed offset, so DST shifts and zone-rule changes
|
|
847
|
+
* (a skipped or repeated local day) land on the date a wall clock there shows.
|
|
848
|
+
*/
|
|
849
|
+
function civilParts(fn, at, timeZone) {
|
|
850
|
+
const formatter = civilFormatter(fn, timeZone);
|
|
851
|
+
let year = "";
|
|
852
|
+
let month = "";
|
|
853
|
+
let day = "";
|
|
854
|
+
for (const part of formatter.formatToParts(at)) if (part.type === "year") year = part.value;
|
|
855
|
+
else if (part.type === "month") month = part.value;
|
|
856
|
+
else if (part.type === "day") day = part.value;
|
|
857
|
+
return {
|
|
858
|
+
year: year.padStart(4, "0"),
|
|
859
|
+
month,
|
|
860
|
+
day
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function assertInstant(fn, at) {
|
|
864
|
+
if (!(at instanceof Date) || Number.isNaN(at.getTime())) throw new Error(`${fn}: at must be a valid Date`);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* The civil period of an instant in an IANA time zone: `'2026'` (year),
|
|
868
|
+
* `'2026-03'` (month) or `'2026-03-14'` (day). The period suffix every
|
|
869
|
+
* period-scoped counter key ends with.
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* civilPeriodKey(new Date('2026-12-31T21:00:00Z'), 'year', 'Asia/Riyadh'); // '2027'
|
|
873
|
+
* civilPeriodKey(new Date('2026-12-31T21:00:00Z'), 'year', 'UTC'); // '2026'
|
|
874
|
+
*/
|
|
875
|
+
function civilPeriodKey(at, period, timeZone) {
|
|
876
|
+
assertInstant("civilPeriodKey", at);
|
|
877
|
+
if (!SEQUENCE_PERIODS.has(period)) throw new Error(`civilPeriodKey: period must be 'year', 'month' or 'day', got '${period}'`);
|
|
878
|
+
const { year, month, day } = civilParts("civilPeriodKey", at, timeZone);
|
|
879
|
+
if (period === "year") return year;
|
|
880
|
+
if (period === "month") return `${year}-${month}`;
|
|
881
|
+
return `${year}-${month}-${day}`;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* The counter key and civil period for a base key at an instant. Use it to
|
|
885
|
+
* `read` / `ensureAtLeast` the same counter `getNextPeriodSequence` bumps.
|
|
886
|
+
*/
|
|
887
|
+
function periodCounterKey(baseKey, options) {
|
|
888
|
+
if (typeof baseKey !== "string" || baseKey.length === 0) throw new Error("periodCounterKey: baseKey must be a non-empty string");
|
|
889
|
+
const period = civilPeriodKey(options.at ?? /* @__PURE__ */ new Date(), options.period, options.timeZone);
|
|
890
|
+
return {
|
|
891
|
+
counterKey: `${baseKey}${options.keySeparator ?? ":"}${period}`,
|
|
892
|
+
period
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Atomically issue the next value of a counter that resets every civil
|
|
897
|
+
* year / month / day in an IANA time zone. The period is derived from `at`
|
|
898
|
+
* (default now) in `timeZone`, so every replica agrees on it whatever its
|
|
899
|
+
* `TZ`, and DST never moves a boundary.
|
|
900
|
+
*
|
|
901
|
+
* @example Yearly reference `OC-2026-000123` in Riyadh
|
|
902
|
+
* const { seq, period } = await getNextPeriodSequence('occ.occurrence', {
|
|
903
|
+
* period: 'year', timeZone: 'Asia/Riyadh', at: reportedAt, connection, session,
|
|
904
|
+
* });
|
|
905
|
+
* const ref = `OC-${period}-${String(seq).padStart(6, '0')}`;
|
|
906
|
+
*/
|
|
907
|
+
async function getNextPeriodSequence(baseKey, options) {
|
|
908
|
+
return nextInPeriod(getCounterModel(options.connection), baseKey, options);
|
|
909
|
+
}
|
|
910
|
+
async function nextInPeriod(Counter, baseKey, options) {
|
|
911
|
+
const { counterKey, period } = periodCounterKey(baseKey, options);
|
|
912
|
+
return {
|
|
913
|
+
seq: await incrementCounter(Counter, counterKey, options.increment ?? 1, options.session),
|
|
914
|
+
period,
|
|
915
|
+
counterKey
|
|
916
|
+
};
|
|
783
917
|
}
|
|
784
918
|
/**
|
|
785
919
|
* Generator: Simple sequential counter.
|
|
@@ -796,10 +930,11 @@ async function ensureSequenceAtLeast(counterKey, floor, connection) {
|
|
|
796
930
|
* ```
|
|
797
931
|
*/
|
|
798
932
|
function sequentialId(options) {
|
|
799
|
-
const { prefix, model, padding = 4, separator = "-", counterKey } = options;
|
|
933
|
+
const { prefix, model, padding = 4, separator = "-", counterKey, counterCollection } = options;
|
|
800
934
|
const key = counterKey || model.modelName;
|
|
935
|
+
assertCounterCollection("sequentialId", counterCollection);
|
|
801
936
|
return async (context) => {
|
|
802
|
-
const seq = await
|
|
937
|
+
const seq = await incrementCounter(getCounterModel(context._counterConnection, counterCollection), key, 1, context.session);
|
|
803
938
|
return `${prefix}${separator}${String(seq).padStart(padding, "0")}`;
|
|
804
939
|
};
|
|
805
940
|
}
|
|
@@ -834,21 +969,31 @@ function sequentialId(options) {
|
|
|
834
969
|
* ```
|
|
835
970
|
*/
|
|
836
971
|
function dateSequentialId(options) {
|
|
837
|
-
const { prefix, model, partition = "monthly", padding = 4, separator = "-", scope = "global", tenantKey = "organizationId", timezone = "local" } = options;
|
|
972
|
+
const { prefix, model, partition = "monthly", padding = 4, separator = "-", scope = "global", tenantKey = "organizationId", timezone = "local", timeZone, at, counterKey: baseCounterKey, counterCollection } = options;
|
|
973
|
+
assertCounterCollection("dateSequentialId", counterCollection);
|
|
974
|
+
if (timeZone !== void 0) civilFormatter("dateSequentialId", timeZone);
|
|
975
|
+
if (baseCounterKey !== void 0 && (typeof baseCounterKey !== "string" || baseCounterKey.length === 0)) throw new Error("dateSequentialId: counterKey must be a non-empty string");
|
|
838
976
|
/** Per-generator, not module-level — two generators warn independently. */
|
|
839
977
|
const overflowWarned = /* @__PURE__ */ new Set();
|
|
840
978
|
const paddingCeiling = 10 ** padding;
|
|
841
979
|
return async (context) => {
|
|
842
|
-
const now = /* @__PURE__ */ new Date();
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
980
|
+
const now = at?.(context) ?? /* @__PURE__ */ new Date();
|
|
981
|
+
assertInstant("dateSequentialId", now);
|
|
982
|
+
let year;
|
|
983
|
+
let month;
|
|
984
|
+
let day;
|
|
985
|
+
if (timeZone !== void 0) ({year, month, day} = civilParts("dateSequentialId", now, timeZone));
|
|
986
|
+
else {
|
|
987
|
+
const utc = timezone === "utc";
|
|
988
|
+
year = String(utc ? now.getUTCFullYear() : now.getFullYear());
|
|
989
|
+
month = String((utc ? now.getUTCMonth() : now.getMonth()) + 1).padStart(2, "0");
|
|
990
|
+
day = String(utc ? now.getUTCDate() : now.getDate()).padStart(2, "0");
|
|
991
|
+
}
|
|
992
|
+
let keyBase = baseCounterKey ?? model.modelName;
|
|
848
993
|
if (scope === "tenant") {
|
|
849
994
|
const tenantId = context[tenantKey];
|
|
850
995
|
if (tenantId === void 0 || tenantId === null || tenantId === "") throw new Error(`[mongokit] dateSequentialId: scope 'tenant' requires '${tenantKey}' in context for '${model.modelName}' create, but none was provided. Pass it per call (repo.create(data, { ${tenantKey}: '<id>' })) or resolve it ambiently; the generator never falls back to the global counter.`);
|
|
851
|
-
keyBase = `${
|
|
996
|
+
keyBase = `${keyBase}:${String(tenantId)}`;
|
|
852
997
|
}
|
|
853
998
|
let datePart;
|
|
854
999
|
let counterKey;
|
|
@@ -865,7 +1010,7 @@ function dateSequentialId(options) {
|
|
|
865
1010
|
datePart = `${year}${separator}${month}`;
|
|
866
1011
|
counterKey = `${keyBase}:${year}-${month}`;
|
|
867
1012
|
}
|
|
868
|
-
const seq = await
|
|
1013
|
+
const seq = await incrementCounter(getCounterModel(context._counterConnection, counterCollection), counterKey, 1, context.session);
|
|
869
1014
|
if (seq >= paddingCeiling && !overflowWarned.has(counterKey)) {
|
|
870
1015
|
overflowWarned.add(counterKey);
|
|
871
1016
|
warn(`[mongokit] dateSequentialId: '${model.modelName}' sequence ${seq} exceeds padding ${padding} (max ${paddingCeiling - 1}) for period '${counterKey}'. Ids remain unique but no longer sort lexically — raise \`padding\` for new periods, or use a finer \`partition\`.`);
|
|
@@ -957,8 +1102,7 @@ function customIdPlugin(options) {
|
|
|
957
1102
|
}
|
|
958
1103
|
};
|
|
959
1104
|
}
|
|
960
|
-
|
|
961
|
-
//#region src/utils/scope.ts
|
|
1105
|
+
// src/utils/scope.ts
|
|
962
1106
|
/** Tenant context keys forwarded even when no tenant plugin declared one. */
|
|
963
1107
|
const CONVENTIONAL_TENANT_KEYS = ["organizationId", "tenantId"];
|
|
964
1108
|
const ATTRIBUTION_KEYS = [
|
|
@@ -1013,8 +1157,7 @@ function forwardScope(source, tenantKeys = CONVENTIONAL_TENANT_KEYS) {
|
|
|
1013
1157
|
function isScopeKey(key, tenantKeys = CONVENTIONAL_TENANT_KEYS) {
|
|
1014
1158
|
return key === "bypassTenant" || tenantKeys.includes(key) || ATTRIBUTION_KEYS.includes(key);
|
|
1015
1159
|
}
|
|
1016
|
-
|
|
1017
|
-
//#region src/plugins/multi-tenant.plugin.ts
|
|
1160
|
+
// src/plugins/multi-tenant.plugin.ts
|
|
1018
1161
|
/**
|
|
1019
1162
|
* Multi-Tenant Plugin
|
|
1020
1163
|
*
|
|
@@ -1063,6 +1206,9 @@ function multiTenantPlugin(options = {}) {
|
|
|
1063
1206
|
const extraOps = [{
|
|
1064
1207
|
op: "getDeleted",
|
|
1065
1208
|
policyKey: "filters"
|
|
1209
|
+
}, {
|
|
1210
|
+
op: "searchSimilar",
|
|
1211
|
+
policyKey: "filters"
|
|
1066
1212
|
}];
|
|
1067
1213
|
return {
|
|
1068
1214
|
name: "multi-tenant",
|
|
@@ -1256,8 +1402,7 @@ function multiTenantPlugin(options = {}) {
|
|
|
1256
1402
|
function adminBypass$1(options) {
|
|
1257
1403
|
return adminBypass(options);
|
|
1258
1404
|
}
|
|
1259
|
-
|
|
1260
|
-
//#region src/plugins/soft-delete.plugin.ts
|
|
1405
|
+
// src/plugins/soft-delete.plugin.ts
|
|
1261
1406
|
/**
|
|
1262
1407
|
* Build the deletion-state filter for either side of the soft-delete
|
|
1263
1408
|
* boundary. One parameterized helper covers both directions so the two
|
|
@@ -1563,8 +1708,7 @@ function softDeletePlugin(options = {}) {
|
|
|
1563
1708
|
}
|
|
1564
1709
|
};
|
|
1565
1710
|
}
|
|
1566
|
-
|
|
1567
|
-
//#region src/plugins/timestamp.plugin.ts
|
|
1711
|
+
// src/plugins/timestamp.plugin.ts
|
|
1568
1712
|
/**
|
|
1569
1713
|
* Timestamp plugin that auto-injects timestamps
|
|
1570
1714
|
*
|
|
@@ -1602,5 +1746,4 @@ function timestampPlugin() {
|
|
|
1602
1746
|
}
|
|
1603
1747
|
};
|
|
1604
1748
|
}
|
|
1605
|
-
|
|
1606
|
-
export { AuditTrailQuery as _, declareTenantContextKey as a, auditLogPlugin as b, tenantContextKeysOf as c, ensureSequenceAtLeast as d, getNextSequence as f, cachePlugin as g, sequentialId as h, multiTenantPlugin as i, customIdPlugin as l, readSequence as m, softDeletePlugin as n, forwardScope as o, prefixedId as p, adminBypass$1 as r, isScopeKey as s, timestampPlugin as t, dateSequentialId as u, auditTrailPlugin as v, ensureAuditTrailReady as y };
|
|
1749
|
+
export { ensureAuditTrailReady as C, auditTrailPlugin as S, prefixedId as _, declareTenantContextKey as a, cachePlugin as b, tenantContextKeysOf as c, customIdPlugin as d, dateSequentialId as f, periodCounterKey as g, getNextSequence as h, multiTenantPlugin as i, civilPeriodKey as l, getNextPeriodSequence as m, softDeletePlugin as n, forwardScope as o, ensureSequenceAtLeast as p, adminBypass$1 as r, isScopeKey as s, timestampPlugin as t, createSequenceCounter as u, readSequence as v, auditLogPlugin as w, AuditTrailQuery as x, sequentialId as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/memory-cache.ts
|
|
2
2
|
/**
|
|
3
3
|
* Creates an in-memory cache adapter
|
|
4
4
|
*
|
|
@@ -63,8 +63,7 @@ function createMemoryCache(maxEntries = 1e3) {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
//#region src/utils/to-plain.ts
|
|
66
|
+
// src/utils/to-plain.ts
|
|
68
67
|
/**
|
|
69
68
|
* Convert a hydrated Mongoose (sub)document to a plain object — the
|
|
70
69
|
* spread-safety primitive for domain verbs that rebuild embedded lines.
|
|
@@ -94,5 +93,4 @@ function createMemoryCache(maxEntries = 1e3) {
|
|
|
94
93
|
function toPlain(value) {
|
|
95
94
|
return value !== null && value !== void 0 && typeof value.toObject === "function" ? value.toObject() : value;
|
|
96
95
|
}
|
|
97
|
-
//#endregion
|
|
98
96
|
export { createMemoryCache as n, toPlain as t };
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { y as UserContext } from "./repository-
|
|
2
|
-
import { r as FieldPreset } from "./plugin-options-
|
|
1
|
+
import { y as UserContext } from "./repository-DzVIwhU2.mjs";
|
|
2
|
+
import { r as FieldPreset } from "./plugin-options-Bpcuz9kS.mjs";
|
|
3
3
|
import mongoose, { Schema } from "mongoose";
|
|
4
4
|
import { CacheAdapter } from "@classytic/repo-core/cache";
|
|
5
5
|
import { HttpError } from "@classytic/repo-core/errors";
|
|
6
6
|
import { CrudSchemas, SchemaBuilderOptions } from "@classytic/repo-core/schema";
|
|
7
|
-
//#region src/utils/error.d.ts
|
|
8
7
|
/** Optional structured fields for createError. */
|
|
9
8
|
interface CreateErrorOptions {
|
|
10
9
|
/** Stable machine-readable code (e.g. `SEARCH_NOT_CONFIGURED`). */
|
|
@@ -70,8 +69,6 @@ interface ParseDuplicateKeyOptions {
|
|
|
70
69
|
* Returns `null` when the error is not a duplicate-key error.
|
|
71
70
|
*/
|
|
72
71
|
declare function parseDuplicateKeyError(error: unknown, options?: ParseDuplicateKeyOptions): HttpError | null;
|
|
73
|
-
//#endregion
|
|
74
|
-
//#region src/utils/field-selection.d.ts
|
|
75
72
|
/**
|
|
76
73
|
* Get allowed fields for a user based on their context
|
|
77
74
|
*
|
|
@@ -138,8 +135,6 @@ declare function filterResponseData<T extends Record<string, unknown>>(data: T |
|
|
|
138
135
|
* });
|
|
139
136
|
*/
|
|
140
137
|
declare function createFieldPreset(config: Partial<FieldPreset>): FieldPreset;
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/utils/id-resolution.d.ts
|
|
143
138
|
/** Normalized _id type — covers the common Mongoose _id declarations */
|
|
144
139
|
type IdType = 'objectid' | 'string' | 'number' | 'uuid' | 'unknown';
|
|
145
140
|
/**
|
|
@@ -212,8 +207,6 @@ declare function isValidIdForType(id: unknown, idType: IdType): boolean;
|
|
|
212
207
|
* await col.deleteMany({ customerId: { $in: idVariants(userId) } });
|
|
213
208
|
*/
|
|
214
209
|
declare function idVariants(id: unknown): unknown[];
|
|
215
|
-
//#endregion
|
|
216
|
-
//#region src/utils/logger.d.ts
|
|
217
210
|
/**
|
|
218
211
|
* Internal Logger
|
|
219
212
|
*
|
|
@@ -244,8 +237,6 @@ interface LoggerConfig {
|
|
|
244
237
|
* Pass `false` to silence all output.
|
|
245
238
|
*/
|
|
246
239
|
declare function configureLogger(config: Partial<LoggerConfig> | false): void;
|
|
247
|
-
//#endregion
|
|
248
|
-
//#region src/utils/memory-cache.d.ts
|
|
249
240
|
/**
|
|
250
241
|
* Creates an in-memory cache adapter
|
|
251
242
|
*
|
|
@@ -257,8 +248,6 @@ declare function configureLogger(config: Partial<LoggerConfig> | false): void;
|
|
|
257
248
|
* @param maxEntries - Maximum cache entries before oldest are evicted (default: 1000)
|
|
258
249
|
*/
|
|
259
250
|
declare function createMemoryCache(maxEntries?: number): CacheAdapter;
|
|
260
|
-
//#endregion
|
|
261
|
-
//#region src/utils/mongooseToJsonSchema.d.ts
|
|
262
251
|
/**
|
|
263
252
|
* Return shape for the schema builders. Structurally a `CrudSchemas` plus
|
|
264
253
|
* an `[key: string]: unknown` index signature so the function reference
|
|
@@ -298,8 +287,6 @@ declare function buildCrudSchemasFromMongooseSchema(mongooseSchema: Schema, opti
|
|
|
298
287
|
* `SchemaGenerator<Model<unknown>>`, so the contract claim above is unchanged.
|
|
299
288
|
*/
|
|
300
289
|
declare function buildCrudSchemasFromModel<TDoc = unknown>(mongooseModel: mongoose.Model<TDoc>, options?: SchemaBuilderOptions): CrudSchemasFramework;
|
|
301
|
-
//#endregion
|
|
302
|
-
//#region src/utils/to-plain.d.ts
|
|
303
290
|
/**
|
|
304
291
|
* Convert a hydrated Mongoose (sub)document to a plain object — the
|
|
305
292
|
* spread-safety primitive for domain verbs that rebuild embedded lines.
|
|
@@ -327,5 +314,4 @@ declare function buildCrudSchemasFromModel<TDoc = unknown>(mongooseModel: mongoo
|
|
|
327
314
|
* defensively over values that may or may not be hydrated.
|
|
328
315
|
*/
|
|
329
316
|
declare function toPlain<T>(value: T): T;
|
|
330
|
-
//#endregion
|
|
331
317
|
export { parseDuplicateKeyError as S, getMongooseProjection as _, createMemoryCache as a, createError as b, IdType as c, isObjectIdInstance as d, isValidIdForType as f, getFieldsForUser as g, filterResponseData as h, buildCrudSchemasFromMongooseSchema as i, getSchemaIdType as l, createFieldPreset as m, CrudSchemasFramework as n, LoggerConfig as o, toObjectId as p, buildCrudSchemasFromModel as r, configureLogger as s, toPlain as t, idVariants as u, CreateErrorOptions as v, isDuplicateKeyError as x, ParseDuplicateKeyOptions as y };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { d as setTransactionDeadline } from "./query-defaults-aUoKlEbh.mjs";
|
|
2
|
+
import { t as createError } from "./error-DjdmPLWO.mjs";
|
|
3
3
|
import mongoose from "mongoose";
|
|
4
4
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
5
|
-
|
|
5
|
+
// src/capabilities.ts
|
|
6
6
|
/**
|
|
7
7
|
* Read the provenance of a capability descriptor's `transactions` flag.
|
|
8
8
|
* A descriptor without the field is a static declaration (`'declared'`) —
|
|
@@ -252,8 +252,7 @@ async function probeMongoCapabilities(connection, options = {}) {
|
|
|
252
252
|
PROBE_INFLIGHT.set(key, run);
|
|
253
253
|
return DERIVED[await run];
|
|
254
254
|
}
|
|
255
|
-
|
|
256
|
-
//#region src/tx-bound.ts
|
|
255
|
+
// src/tx-bound.ts
|
|
257
256
|
/**
|
|
258
257
|
* Map of session-aware method name → positional index of the `{ session }`
|
|
259
258
|
* options bag. Keep this list in sync with the method signatures in
|
|
@@ -391,8 +390,7 @@ function createTxBoundRepo(outer, session) {
|
|
|
391
390
|
};
|
|
392
391
|
} });
|
|
393
392
|
}
|
|
394
|
-
|
|
395
|
-
//#region src/transaction.ts
|
|
393
|
+
// src/transaction.ts
|
|
396
394
|
/**
|
|
397
395
|
* Cross-repo transaction helper.
|
|
398
396
|
*
|
|
@@ -678,5 +676,4 @@ function isTransactionUnsupported(error) {
|
|
|
678
676
|
function supportsTransactions(connection) {
|
|
679
677
|
return resolveTransactionSupport(connection) !== "no";
|
|
680
678
|
}
|
|
681
|
-
//#endregion
|
|
682
679
|
export { supportsTransactions as a, MONGOKIT_CAPABILITIES as c, probeMongoCapabilities as d, resetCapabilityProbeCache as f, transactionResolutionOf as h, runTransaction as i, capabilitiesForSupport as l, resolveTransactionSupport as m, batchTransaction as n, withTransaction as o, resolveMongoCapabilities as p, isTransactionUnsupported as r, createTxBoundRepo as s, TRANSACTION_ERROR_CODES as t, classifyHelloReply as u };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Document, Model } from "mongoose";
|
|
2
2
|
import { ValidationResult } from "@classytic/repo-core/schema";
|
|
3
|
-
//#region src/types/type-utils.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Infer document type from a Mongoose Model
|
|
6
5
|
* @example
|
|
@@ -159,5 +158,4 @@ type UpdateWithValidationResult<T> = {
|
|
|
159
158
|
violations?: ValidationResult['violations'];
|
|
160
159
|
};
|
|
161
160
|
};
|
|
162
|
-
//#endregion
|
|
163
161
|
export { InferRawDoc as a, NonNullableFields as c, Strict as d, UpdatePatch as f, InferDocument as i, PartialBy as l, DeepPartial as n, KeysOfType as o, UpdateWithValidationResult as p, DocField as r, MongoOperatorUpdate as s, CreateInput as t, RequiredBy as u };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as applyToQuery } from "./query-defaults-
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
|
|
2
|
+
import { t as createError } from "./error-DjdmPLWO.mjs";
|
|
3
|
+
import { n as warn } from "./logger-hbWOlj_X.mjs";
|
|
4
|
+
import { i as applyToQuery } from "./query-defaults-aUoKlEbh.mjs";
|
|
5
5
|
import { coerceFilterDates, isFilter } from "@classytic/repo-core/filter";
|
|
6
|
-
|
|
6
|
+
// src/actions/create.ts
|
|
7
7
|
var create_exports = /* @__PURE__ */ __exportAll({
|
|
8
8
|
create: () => create,
|
|
9
9
|
createDefault: () => createDefault,
|
|
@@ -109,8 +109,7 @@ async function upsert(Model, query, data, options = {}) {
|
|
|
109
109
|
...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
//#region src/filter/cast-schema.ts
|
|
112
|
+
// src/filter/cast-schema.ts
|
|
114
113
|
/** Operators whose operand is a single scalar to cast. */
|
|
115
114
|
const SCALAR_OPS = /* @__PURE__ */ new Set([
|
|
116
115
|
"$eq",
|
|
@@ -225,8 +224,7 @@ function castFilterToSchema(filter, schema) {
|
|
|
225
224
|
}
|
|
226
225
|
return changed ? out : filter;
|
|
227
226
|
}
|
|
228
|
-
|
|
229
|
-
//#region src/filter/compile.ts
|
|
227
|
+
// src/filter/compile.ts
|
|
230
228
|
/**
|
|
231
229
|
* Compile a Filter IR node to a MongoDB query object. Returns `{}`
|
|
232
230
|
* when the node is `TRUE` (or an empty `and`) so callers can merge
|
|
@@ -464,8 +462,7 @@ function asOperators(condition) {
|
|
|
464
462
|
function escapeRegexChar(ch) {
|
|
465
463
|
return /[.*+?^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
|
|
466
464
|
}
|
|
467
|
-
|
|
468
|
-
//#region src/query/LookupBuilder.ts
|
|
465
|
+
// src/query/LookupBuilder.ts
|
|
469
466
|
/** Stages that are never valid inside a $lookup pipeline */
|
|
470
467
|
const BLOCKED_PIPELINE_STAGES = [
|
|
471
468
|
"$out",
|
|
@@ -852,8 +849,7 @@ function compileSelectToProjection(select) {
|
|
|
852
849
|
* - For read-heavy workloads: Consider caching or materialized views
|
|
853
850
|
* - For real-time dashboards: Consider separate aggregation collections
|
|
854
851
|
*/
|
|
855
|
-
|
|
856
|
-
//#region src/actions/aggregate.ts
|
|
852
|
+
// src/actions/aggregate.ts
|
|
857
853
|
var aggregate_exports = /* @__PURE__ */ __exportAll({
|
|
858
854
|
aggregate: () => aggregate,
|
|
859
855
|
aggregatePaginate: () => aggregatePaginate,
|
|
@@ -1023,8 +1019,7 @@ async function minMax(Model, field, query = {}, options = {}) {
|
|
|
1023
1019
|
max: null
|
|
1024
1020
|
};
|
|
1025
1021
|
}
|
|
1026
|
-
|
|
1027
|
-
//#region src/actions/delete.ts
|
|
1022
|
+
// src/actions/delete.ts
|
|
1028
1023
|
var delete_exports = /* @__PURE__ */ __exportAll({
|
|
1029
1024
|
deleteById: () => deleteById,
|
|
1030
1025
|
deleteByQuery: () => deleteByQuery,
|
|
@@ -1113,8 +1108,7 @@ async function restore(Model, id, options = {}) {
|
|
|
1113
1108
|
id: String(id)
|
|
1114
1109
|
};
|
|
1115
1110
|
}
|
|
1116
|
-
|
|
1117
|
-
//#region src/actions/read.ts
|
|
1111
|
+
// src/actions/read.ts
|
|
1118
1112
|
var read_exports = /* @__PURE__ */ __exportAll({
|
|
1119
1113
|
count: () => count,
|
|
1120
1114
|
exists: () => exists,
|
|
@@ -1251,8 +1245,7 @@ async function exists(Model, query, options = {}) {
|
|
|
1251
1245
|
applyToQuery(q, options.queryOptions ?? {});
|
|
1252
1246
|
return q;
|
|
1253
1247
|
}
|
|
1254
|
-
|
|
1255
|
-
//#region src/actions/update.ts
|
|
1248
|
+
// src/actions/update.ts
|
|
1256
1249
|
var update_exports = /* @__PURE__ */ __exportAll({
|
|
1257
1250
|
findOneAndUpdate: () => findOneAndUpdate,
|
|
1258
1251
|
increment: () => increment,
|
|
@@ -1435,5 +1428,4 @@ async function pushToArray(Model, id, field, value, options = {}) {
|
|
|
1435
1428
|
async function pullFromArray(Model, id, field, value, options = {}) {
|
|
1436
1429
|
return update(Model, id, { $pull: { [field]: value } }, options);
|
|
1437
1430
|
}
|
|
1438
|
-
//#endregion
|
|
1439
1431
|
export { isCreateManyPartialError as C, create_exports as S, SHORTHAND_OPS as _, count as a, create as b, getByQuery as c, deleteById as d, deleteByQuery as f, LookupBuilder as g, distinct as h, update_exports as i, getOrCreate as l, aggregate_exports as m, update as n, exists as o, delete_exports as p, updateByQuery as r, getById as s, findOneAndUpdate as t, read_exports as u, compileFilterToMongo as v, upsert as w, createMany as x, castFilterToSchema as y };
|
package/dist/usage/index.d.mts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Connection } from "mongoose";
|
|
2
2
|
import { UsageStore } from "@classytic/repo-core/usage";
|
|
3
|
-
//#region src/usage/index.d.ts
|
|
4
3
|
/** Adapter-construction options. */
|
|
5
|
-
interface MongoUsageStoreOptions {
|
|
4
|
+
export interface MongoUsageStoreOptions {
|
|
6
5
|
/**
|
|
7
6
|
* Mongoose connection. Defaults to `mongoose.connection` (the
|
|
8
7
|
* default global connection). Apps using a named connection pass
|
|
@@ -18,6 +17,4 @@ interface MongoUsageStoreOptions {
|
|
|
18
17
|
* Build a Mongo-backed usage store. Idempotent — the underlying model
|
|
19
18
|
* is registered once per `(connection, modelName)` pair.
|
|
20
19
|
*/
|
|
21
|
-
declare function createMongoUsageStore(options?: MongoUsageStoreOptions): UsageStore;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { MongoUsageStoreOptions, createMongoUsageStore };
|
|
20
|
+
export declare function createMongoUsageStore(options?: MongoUsageStoreOptions): UsageStore;
|
package/dist/usage/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as isDuplicateKeyError } from "../error-
|
|
1
|
+
import { n as isDuplicateKeyError } from "../error-DjdmPLWO.mjs";
|
|
2
2
|
import mongoose, { Schema } from "mongoose";
|
|
3
|
-
|
|
3
|
+
// src/usage/index.ts
|
|
4
4
|
/**
|
|
5
5
|
* Build a Mongo-backed usage store. Idempotent — the underlying model
|
|
6
6
|
* is registered once per `(connection, modelName)` pair.
|
|
@@ -8,9 +8,12 @@ import mongoose, { Schema } from "mongoose";
|
|
|
8
8
|
function createMongoUsageStore(options = {}) {
|
|
9
9
|
const { connection, collectionName = "usage_counters", modelName = "MongoUsageCounter" } = options;
|
|
10
10
|
const model = getOrCreateModel(connection ?? mongoose, modelName, collectionName);
|
|
11
|
+
const ready = model.init();
|
|
12
|
+
ready.catch(() => void 0);
|
|
11
13
|
return {
|
|
12
14
|
name: "mongo",
|
|
13
15
|
async increment(bucket, amount) {
|
|
16
|
+
await ready;
|
|
14
17
|
const filter = {
|
|
15
18
|
actor: bucket.actor,
|
|
16
19
|
period: bucket.period,
|
|
@@ -28,9 +31,9 @@ function createMongoUsageStore(options = {}) {
|
|
|
28
31
|
actor,
|
|
29
32
|
period
|
|
30
33
|
}).select("kind count").lean();
|
|
31
|
-
const
|
|
32
|
-
for (const row of rows)
|
|
33
|
-
return
|
|
34
|
+
const sums = /* @__PURE__ */ new Map();
|
|
35
|
+
for (const row of rows) sums.set(row.kind, (sums.get(row.kind) ?? 0) + row.count);
|
|
36
|
+
return Object.fromEntries(sums);
|
|
34
37
|
}
|
|
35
38
|
};
|
|
36
39
|
}
|
|
@@ -63,5 +66,4 @@ function getOrCreateModel(conn, modelName, collectionName) {
|
|
|
63
66
|
}, { unique: true });
|
|
64
67
|
return conn.model(modelName, schema, collectionName);
|
|
65
68
|
}
|
|
66
|
-
//#endregion
|
|
67
69
|
export { createMongoUsageStore };
|