@futdevpro/nts-dynamo 1.15.356 → 1.15.357

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The minimal MongoDB collection surface `DyNTS_RateLimit_MongoStore` needs — structurally satisfied by a native
3
+ * driver `Collection` and by `mongoose.connection.collection(name)`, so the store has no hard driver dependency.
4
+ */
5
+ export interface DyNTS_RateLimit_MongoCollection_Interface {
6
+ findOneAndUpdate(filter: object, update: object[], options: object): Promise<unknown>;
7
+ createIndex(spec: object, options: object): Promise<unknown>;
8
+ }
9
+ //# sourceMappingURL=rate-limit-mongo-collection.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-mongo-collection.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-mongo-collection.interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,yCAAyC;IACxD,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtF,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=rate-limit-mongo-collection.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-mongo-collection.interface.js","sourceRoot":"","sources":["../../../../src/_modules/rate-limit/_models/rate-limit-mongo-collection.interface.ts"],"names":[],"mappings":""}
@@ -1,5 +1,8 @@
1
1
  export { DyNTS_RateLimit_Middleware } from './rate-limit.middleware';
2
2
  export { DyNTS_RateLimit_InMemoryStore } from './rate-limit-in-memory.store';
3
+ export { DyNTS_RateLimit_MongoStore } from './rate-limit-mongo.store';
4
+ export { DyNTS_RateLimit_Request_Util } from './rate-limit-request.util';
5
+ export { DyNTS_RateLimit_MongoCollection_Interface } from './_models/rate-limit-mongo-collection.interface';
3
6
  export { DyNTS_RateLimit_Config } from './_models/rate-limit-config.interface';
4
7
  export { DyNTS_RateLimit_ConsumeRequest_Interface } from './_models/rate-limit-consume-request.interface';
5
8
  export { DyNTS_RateLimit_ConsumeResult_Interface } from './_models/rate-limit-consume-result.interface';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAC1G,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,yCAAyC,EAAE,MAAM,iDAAiD,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAC1G,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AACvF,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC"}
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DyNTS_RateLimitStoreKind_Type = exports.DyNTS_RateLimit_InMemoryStore = exports.DyNTS_RateLimit_Middleware = void 0;
3
+ exports.DyNTS_RateLimitStoreKind_Type = exports.DyNTS_RateLimit_Request_Util = exports.DyNTS_RateLimit_MongoStore = exports.DyNTS_RateLimit_InMemoryStore = exports.DyNTS_RateLimit_Middleware = void 0;
4
4
  var rate_limit_middleware_1 = require("./rate-limit.middleware");
5
5
  Object.defineProperty(exports, "DyNTS_RateLimit_Middleware", { enumerable: true, get: function () { return rate_limit_middleware_1.DyNTS_RateLimit_Middleware; } });
6
6
  var rate_limit_in_memory_store_1 = require("./rate-limit-in-memory.store");
7
7
  Object.defineProperty(exports, "DyNTS_RateLimit_InMemoryStore", { enumerable: true, get: function () { return rate_limit_in_memory_store_1.DyNTS_RateLimit_InMemoryStore; } });
8
+ var rate_limit_mongo_store_1 = require("./rate-limit-mongo.store");
9
+ Object.defineProperty(exports, "DyNTS_RateLimit_MongoStore", { enumerable: true, get: function () { return rate_limit_mongo_store_1.DyNTS_RateLimit_MongoStore; } });
10
+ var rate_limit_request_util_1 = require("./rate-limit-request.util");
11
+ Object.defineProperty(exports, "DyNTS_RateLimit_Request_Util", { enumerable: true, get: function () { return rate_limit_request_util_1.DyNTS_RateLimit_Request_Util; } });
8
12
  var rate_limit_store_kind_type_enum_1 = require("./_enums/rate-limit-store-kind.type-enum");
9
13
  Object.defineProperty(exports, "DyNTS_RateLimitStoreKind_Type", { enumerable: true, get: function () { return rate_limit_store_kind_type_enum_1.DyNTS_RateLimitStoreKind_Type; } });
10
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":";;;AAAA,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,2EAA6E;AAApE,2IAAA,6BAA6B,OAAA;AAMtC,4FAAyF;AAAhF,gJAAA,6BAA6B,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/index.ts"],"names":[],"mappings":";;;AAAA,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,2EAA6E;AAApE,2IAAA,6BAA6B,OAAA;AACtC,mEAAsE;AAA7D,oIAAA,0BAA0B,OAAA;AACnC,qEAAyE;AAAhE,uIAAA,4BAA4B,OAAA;AAOrC,4FAAyF;AAAhF,gJAAA,6BAA6B,OAAA"}
@@ -14,6 +14,5 @@ export declare class DyNTS_RateLimit_InMemoryStore implements DyNTS_RateLimit_St
14
14
  reset(): void;
15
15
  /** Returns only the aggregate local bucket count for diagnostics. */
16
16
  getTrackedBucketCount(): number;
17
- private assertRequest;
18
17
  }
19
18
  //# sourceMappingURL=rate-limit-in-memory.store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-in-memory.store.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-in-memory.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAC1G,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAOvF,+FAA+F;AAC/F,qBAAa,6BAA8B,YAAW,+BAA+B;IACnF,SAAgB,SAAS,EAAE,6BAA6B,CAA0C;IAClG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoE;IAE5F,gGAAgG;IACnF,OAAO,CAClB,OAAO,EAAE,wCAAwC,GAChD,OAAO,CAAC,uCAAuC,CAAC;IA4BnD,2FAA2F;IACpF,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAgBjC,sDAAsD;IAC/C,KAAK,IAAI,IAAI;IAIpB,qEAAqE;IAC9D,qBAAqB,IAAI,MAAM;IAItC,OAAO,CAAC,aAAa;CAiBtB"}
1
+ {"version":3,"file":"rate-limit-in-memory.store.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-in-memory.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAC1G,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAQvF,+FAA+F;AAC/F,qBAAa,6BAA8B,YAAW,+BAA+B;IACnF,SAAgB,SAAS,EAAE,6BAA6B,CAA0C;IAClG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoE;IAE5F,gGAAgG;IACnF,OAAO,CAClB,OAAO,EAAE,wCAAwC,GAChD,OAAO,CAAC,uCAAuC,CAAC;IA4BnD,2FAA2F;IACpF,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAgBjC,sDAAsD;IAC/C,KAAK,IAAI,IAAI;IAIpB,qEAAqE;IAC9D,qBAAqB,IAAI,MAAM;CAGvC"}
@@ -2,13 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DyNTS_RateLimit_InMemoryStore = void 0;
4
4
  const rate_limit_store_kind_type_enum_1 = require("./_enums/rate-limit-store-kind.type-enum");
5
+ const rate_limit_request_util_1 = require("./rate-limit-request.util");
5
6
  /** Deterministic single-process store for tests and explicitly single-instance development. */
6
7
  class DyNTS_RateLimit_InMemoryStore {
7
8
  storeKind = rate_limit_store_kind_type_enum_1.DyNTS_RateLimitStoreKind_Type.inMemory;
8
9
  records = new Map();
9
10
  /** Consumes permit units with exact sliding-window semantics and no background cleanup task. */
10
11
  async consume(request) {
11
- this.assertRequest(request);
12
+ rate_limit_request_util_1.DyNTS_RateLimit_Request_Util.assertValid(request);
12
13
  const windowStart = request.now - request.policy.windowMs;
13
14
  const existing = this.records.get(request.bucketKey);
14
15
  const recent = (existing?.timestamps ?? []).filter((timestamp) => timestamp > windowStart);
@@ -50,22 +51,6 @@ class DyNTS_RateLimit_InMemoryStore {
50
51
  getTrackedBucketCount() {
51
52
  return this.records.size;
52
53
  }
53
- assertRequest(request) {
54
- const isValid = Boolean(request.bucketKey.trim())
55
- && request.bucketKey.length <= 512
56
- && Number.isSafeInteger(request.now)
57
- && request.now >= 0
58
- && Number.isSafeInteger(request.cost)
59
- && request.cost > 0
60
- && Number.isSafeInteger(request.policy.limit)
61
- && request.policy.limit > 0
62
- && Number.isSafeInteger(request.policy.windowMs)
63
- && request.policy.windowMs > 0
64
- && request.cost <= request.policy.limit;
65
- if (!isValid) {
66
- throw new Error('DYNTS_RATE_LIMIT_STORE_REQUEST_INVALID');
67
- }
68
- }
69
54
  }
70
55
  exports.DyNTS_RateLimit_InMemoryStore = DyNTS_RateLimit_InMemoryStore;
71
56
  //# sourceMappingURL=rate-limit-in-memory.store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-in-memory.store.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-in-memory.store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rate-limit-in-memory.store.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-in-memory.store.ts"],"names":[],"mappings":";;;AAAA,8FAAyF;AAIzF,uEAAyE;AAOzE,+FAA+F;AAC/F,MAAa,6BAA6B;IACxB,SAAS,GAAkC,+DAA6B,CAAC,QAAQ,CAAC;IACjF,OAAO,GAA0D,IAAI,GAAG,EAAE,CAAC;IAE5F,gGAAgG;IACzF,KAAK,CAAC,OAAO,CAClB,OAAiD;QAEjD,sDAA4B,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAElD,MAAM,WAAW,GAAW,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClE,MAAM,QAAQ,GAAyD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC3G,MAAM,MAAM,GAAa,CAAC,QAAQ,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAC1D,CAAC,SAAiB,EAAW,EAAE,CAAC,SAAS,GAAG,WAAW,CACxD,CAAC;QACF,MAAM,OAAO,GAAY,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAE9E,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,IAAI,KAAK,GAAW,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC7D,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE;YAClC,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ;SAClC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;YAC5D,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ;SAC9D,CAAC;IACJ,CAAC;IAED,2FAA2F;IACpF,OAAO,CAAC,GAAW;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAW,KAAK,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,MAAM,GAA6C,KAAK,CAAC,CAAC,CAAC,CAAC;YAClE,MAAM,MAAM,GAAa,MAAM,CAAC,UAAU,CAAC,MAAM,CAC/C,CAAC,SAAiB,EAAW,EAAE,CAAC,SAAS,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,CAClE,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED,sDAAsD;IAC/C,KAAK;QACV,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,qEAAqE;IAC9D,qBAAqB;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF;AA7DD,sEA6DC"}
@@ -0,0 +1,34 @@
1
+ import { DyNTS_RateLimitStoreKind_Type } from './_enums/rate-limit-store-kind.type-enum';
2
+ import { DyNTS_RateLimit_ConsumeRequest_Interface } from './_models/rate-limit-consume-request.interface';
3
+ import { DyNTS_RateLimit_ConsumeResult_Interface } from './_models/rate-limit-consume-result.interface';
4
+ import { DyNTS_RateLimit_MongoCollection_Interface } from './_models/rate-limit-mongo-collection.interface';
5
+ import { DyNTS_RateLimit_Store_Interface } from './_models/rate-limit-store.interface';
6
+ /**
7
+ * BFR-OLDLIGHTSITE-009 — the SHARED (multi-process, multi-replica) rate-limit store, on MongoDB.
8
+ *
9
+ * Every permit request is ONE atomic `findOneAndUpdate` with an aggregation-pipeline update on the bucket document:
10
+ * drop the timestamps outside the sliding window → decide `allowed` from the remaining count + cost → append `cost`
11
+ * copies of `now` only when allowed. MongoDB applies a single-document update atomically, so concurrent requests from
12
+ * any number of processes / replicas serialize on the bucket — no read-modify-write race, no lock.
13
+ * Semantics are identical to `DyNTS_RateLimit_InMemoryStore` (exact sliding window, same result fields).
14
+ *
15
+ * Cleanup: `ensureIndexes()` creates a TTL index on `expiresAt` (set to `now + windowMs` on every request), so idle
16
+ * buckets expire without a background task. MongoDB ≥ 4.2 (pipeline updates).
17
+ *
18
+ * Usage: `new DyNTS_RateLimit_MongoStore({ collection: mongoose.connection.collection('dynts_rate_limits') })`.
19
+ */
20
+ export declare class DyNTS_RateLimit_MongoStore implements DyNTS_RateLimit_Store_Interface {
21
+ readonly storeKind: DyNTS_RateLimitStoreKind_Type;
22
+ private readonly collection;
23
+ /** Creates the store on the shared bucket collection — every replica must point at the SAME collection. */
24
+ constructor(set: {
25
+ collection: DyNTS_RateLimit_MongoCollection_Interface;
26
+ });
27
+ /** Creates the TTL index that expires idle buckets. Idempotent — call once at boot. */
28
+ ensureIndexes(): Promise<void>;
29
+ /** Consumes permit units atomically across every process that shares the collection. */
30
+ consume(request: DyNTS_RateLimit_ConsumeRequest_Interface): Promise<DyNTS_RateLimit_ConsumeResult_Interface>;
31
+ /** Driver ≥ 6 returns the document; older drivers / `includeResultMetadata` wrap it in `{ value }`. */
32
+ private static unwrap;
33
+ }
34
+ //# sourceMappingURL=rate-limit-mongo.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-mongo.store.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-mongo.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAC1G,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,yCAAyC,EAAE,MAAM,iDAAiD,CAAC;AAC5G,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAWvF;;;;;;;;;;;;;GAaG;AACH,qBAAa,0BAA2B,YAAW,+BAA+B;IAChF,SAAgB,SAAS,EAAE,6BAA6B,CAAwC;IAChG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4C;IAEvE,2GAA2G;gBAC/F,GAAG,EAAE;QAAE,UAAU,EAAE,yCAAyC,CAAA;KAAE;IAO1E,uFAAuF;IAC1E,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C,wFAAwF;IAC3E,OAAO,CAClB,OAAO,EAAE,wCAAwC,GAChD,OAAO,CAAC,uCAAuC,CAAC;IAwCnD,uGAAuG;IACvG,OAAO,CAAC,MAAM,CAAC,MAAM;CAWtB"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_RateLimit_MongoStore = void 0;
4
+ const rate_limit_store_kind_type_enum_1 = require("./_enums/rate-limit-store-kind.type-enum");
5
+ const rate_limit_request_util_1 = require("./rate-limit-request.util");
6
+ /**
7
+ * BFR-OLDLIGHTSITE-009 — the SHARED (multi-process, multi-replica) rate-limit store, on MongoDB.
8
+ *
9
+ * Every permit request is ONE atomic `findOneAndUpdate` with an aggregation-pipeline update on the bucket document:
10
+ * drop the timestamps outside the sliding window → decide `allowed` from the remaining count + cost → append `cost`
11
+ * copies of `now` only when allowed. MongoDB applies a single-document update atomically, so concurrent requests from
12
+ * any number of processes / replicas serialize on the bucket — no read-modify-write race, no lock.
13
+ * Semantics are identical to `DyNTS_RateLimit_InMemoryStore` (exact sliding window, same result fields).
14
+ *
15
+ * Cleanup: `ensureIndexes()` creates a TTL index on `expiresAt` (set to `now + windowMs` on every request), so idle
16
+ * buckets expire without a background task. MongoDB ≥ 4.2 (pipeline updates).
17
+ *
18
+ * Usage: `new DyNTS_RateLimit_MongoStore({ collection: mongoose.connection.collection('dynts_rate_limits') })`.
19
+ */
20
+ class DyNTS_RateLimit_MongoStore {
21
+ storeKind = rate_limit_store_kind_type_enum_1.DyNTS_RateLimitStoreKind_Type.shared;
22
+ collection;
23
+ /** Creates the store on the shared bucket collection — every replica must point at the SAME collection. */
24
+ constructor(set) {
25
+ if (!set?.collection) {
26
+ throw new Error('DYNTS_RATE_LIMIT_MONGO_STORE_COLLECTION_MISSING');
27
+ }
28
+ this.collection = set.collection;
29
+ }
30
+ /** Creates the TTL index that expires idle buckets. Idempotent — call once at boot. */
31
+ async ensureIndexes() {
32
+ await this.collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0, name: 'dynts_rate_limit_ttl' });
33
+ }
34
+ /** Consumes permit units atomically across every process that shares the collection. */
35
+ async consume(request) {
36
+ rate_limit_request_util_1.DyNTS_RateLimit_Request_Util.assertValid(request);
37
+ const windowStart = request.now - request.policy.windowMs;
38
+ const permits = new Array(request.cost).fill(request.now);
39
+ const raw = await this.collection.findOneAndUpdate({ _id: request.bucketKey }, [
40
+ {
41
+ $set: {
42
+ ts: {
43
+ $filter: { input: { $ifNull: ['$ts', []] }, as: 't', cond: { $gt: ['$$t', windowStart] } },
44
+ },
45
+ },
46
+ },
47
+ { $set: { allowed: { $lte: [{ $add: [{ $size: '$ts' }, request.cost] }, request.policy.limit] } } },
48
+ {
49
+ $set: {
50
+ ts: { $cond: ['$allowed', { $concatArrays: ['$ts', { $literal: permits }] }, '$ts'] },
51
+ expiresAt: { $literal: new Date(request.now + request.policy.windowMs) },
52
+ },
53
+ },
54
+ ], { upsert: true, returnDocument: 'after' });
55
+ const bucket = DyNTS_RateLimit_MongoStore.unwrap(raw);
56
+ if (!bucket || !Array.isArray(bucket.ts) || typeof bucket.allowed !== 'boolean') {
57
+ // fail CLOSED: an unreadable store answer must never let a request through as "allowed"
58
+ throw new Error('DYNTS_RATE_LIMIT_MONGO_STORE_RESULT_INVALID');
59
+ }
60
+ return {
61
+ allowed: bucket.allowed,
62
+ remaining: Math.max(0, request.policy.limit - bucket.ts.length),
63
+ resetAt: (bucket.ts[0] ?? request.now) + request.policy.windowMs,
64
+ };
65
+ }
66
+ /** Driver ≥ 6 returns the document; older drivers / `includeResultMetadata` wrap it in `{ value }`. */
67
+ static unwrap(raw) {
68
+ if (raw === null || typeof raw !== 'object') {
69
+ return null;
70
+ }
71
+ if ('value' in raw && !('_id' in raw)) {
72
+ return raw.value;
73
+ }
74
+ return raw;
75
+ }
76
+ }
77
+ exports.DyNTS_RateLimit_MongoStore = DyNTS_RateLimit_MongoStore;
78
+ //# sourceMappingURL=rate-limit-mongo.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-mongo.store.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-mongo.store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { DyNTS_RateLimit_ConsumeRequest_Interface } from './_models/rate-limit-consume-request.interface';
2
+ /** Shared validation of a permit request — every rate-limit store rejects the same malformed input the same way. */
3
+ export declare class DyNTS_RateLimit_Request_Util {
4
+ /** Throws `DYNTS_RATE_LIMIT_STORE_REQUEST_INVALID` for an empty/oversized key, a bad clock, cost or policy. */
5
+ static assertValid(request: DyNTS_RateLimit_ConsumeRequest_Interface): void;
6
+ }
7
+ //# sourceMappingURL=rate-limit-request.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-request.util.d.ts","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-request.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,gDAAgD,CAAC;AAE1G,oHAAoH;AACpH,qBAAa,4BAA4B;IAEvC,+GAA+G;IAC/G,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,wCAAwC,GAAG,IAAI;CAiB5E"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_RateLimit_Request_Util = void 0;
4
+ /** Shared validation of a permit request — every rate-limit store rejects the same malformed input the same way. */
5
+ class DyNTS_RateLimit_Request_Util {
6
+ /** Throws `DYNTS_RATE_LIMIT_STORE_REQUEST_INVALID` for an empty/oversized key, a bad clock, cost or policy. */
7
+ static assertValid(request) {
8
+ const isValid = Boolean(request.bucketKey.trim())
9
+ && request.bucketKey.length <= 512
10
+ && Number.isSafeInteger(request.now)
11
+ && request.now >= 0
12
+ && Number.isSafeInteger(request.cost)
13
+ && request.cost > 0
14
+ && Number.isSafeInteger(request.policy.limit)
15
+ && request.policy.limit > 0
16
+ && Number.isSafeInteger(request.policy.windowMs)
17
+ && request.policy.windowMs > 0
18
+ && request.cost <= request.policy.limit;
19
+ if (!isValid) {
20
+ throw new Error('DYNTS_RATE_LIMIT_STORE_REQUEST_INVALID');
21
+ }
22
+ }
23
+ }
24
+ exports.DyNTS_RateLimit_Request_Util = DyNTS_RateLimit_Request_Util;
25
+ //# sourceMappingURL=rate-limit-request.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-request.util.js","sourceRoot":"","sources":["../../../src/_modules/rate-limit/rate-limit-request.util.ts"],"names":[],"mappings":";;;AAEA,oHAAoH;AACpH,MAAa,4BAA4B;IAEvC,+GAA+G;IAC/G,MAAM,CAAC,WAAW,CAAC,OAAiD;QAClE,MAAM,OAAO,GAAY,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;eACrD,OAAO,CAAC,SAAS,CAAC,MAAM,IAAI,GAAG;eAC/B,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC;eACjC,OAAO,CAAC,GAAG,IAAI,CAAC;eAChB,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;eAClC,OAAO,CAAC,IAAI,GAAG,CAAC;eAChB,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;eAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC;eACxB,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;eAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC;eAC3B,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAE1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AApBD,oEAoBC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/nts-dynamo",
3
- "version": "01.15.356",
3
+ "version": "01.15.357",
4
4
  "description": "Dynamic NodeTS (NodeJS-Typescript), MongoDB Backend System Framework by Future Development Program Ltd.",
5
5
  "DyBu_settings": {
6
6
  "packageType": "server-package",
@@ -512,7 +512,7 @@
512
512
  }
513
513
  },
514
514
  "devDependencies": {
515
- "@futdevpro/fsm-dynamo": "1.20.94",
515
+ "@futdevpro/fsm-dynamo": "1.20.95",
516
516
  "@futdevpro/dynamo-eslint": "1.20.55",
517
517
  "@discordjs/opus": "^0.10.0",
518
518
  "@discordjs/voice": "^0.18.0",