@deorta-dev/nestjs-repository-core 0.1.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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.es.md +260 -0
  3. package/README.md +259 -0
  4. package/dist/base-repository.service.d.ts +73 -0
  5. package/dist/base-repository.service.d.ts.map +1 -0
  6. package/dist/base-repository.service.js +309 -0
  7. package/dist/base-repository.service.js.map +1 -0
  8. package/dist/decorators/index.d.ts +2 -0
  9. package/dist/decorators/index.d.ts.map +1 -0
  10. package/dist/decorators/index.js +18 -0
  11. package/dist/decorators/index.js.map +1 -0
  12. package/dist/decorators/repository-inject.decorator.d.ts +20 -0
  13. package/dist/decorators/repository-inject.decorator.d.ts.map +1 -0
  14. package/dist/decorators/repository-inject.decorator.js +29 -0
  15. package/dist/decorators/repository-inject.decorator.js.map +1 -0
  16. package/dist/index.d.ts +7 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +23 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/repository.module.d.ts +13 -0
  21. package/dist/repository.module.d.ts.map +1 -0
  22. package/dist/repository.module.js +92 -0
  23. package/dist/repository.module.js.map +1 -0
  24. package/dist/schema/index.d.ts +4 -0
  25. package/dist/schema/index.d.ts.map +1 -0
  26. package/dist/schema/index.js +20 -0
  27. package/dist/schema/index.js.map +1 -0
  28. package/dist/schema/sync-checkpoint.schema.d.ts +22 -0
  29. package/dist/schema/sync-checkpoint.schema.d.ts.map +1 -0
  30. package/dist/schema/sync-checkpoint.schema.js +13 -0
  31. package/dist/schema/sync-checkpoint.schema.js.map +1 -0
  32. package/dist/schema/tombstone.schema.d.ts +24 -0
  33. package/dist/schema/tombstone.schema.d.ts.map +1 -0
  34. package/dist/schema/tombstone.schema.js +15 -0
  35. package/dist/schema/tombstone.schema.js.map +1 -0
  36. package/dist/schema/with-cache-ttl.d.ts +14 -0
  37. package/dist/schema/with-cache-ttl.d.ts.map +1 -0
  38. package/dist/schema/with-cache-ttl.js +24 -0
  39. package/dist/schema/with-cache-ttl.js.map +1 -0
  40. package/dist/sync/backup-sync.service.d.ts +61 -0
  41. package/dist/sync/backup-sync.service.d.ts.map +1 -0
  42. package/dist/sync/backup-sync.service.js +156 -0
  43. package/dist/sync/backup-sync.service.js.map +1 -0
  44. package/dist/sync/index.d.ts +2 -0
  45. package/dist/sync/index.d.ts.map +1 -0
  46. package/dist/sync/index.js +18 -0
  47. package/dist/sync/index.js.map +1 -0
  48. package/dist/types.d.ts +122 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +3 -0
  51. package/dist/types.js.map +1 -0
  52. package/dist/utils/index.d.ts +3 -0
  53. package/dist/utils/index.d.ts.map +1 -0
  54. package/dist/utils/index.js +19 -0
  55. package/dist/utils/index.js.map +1 -0
  56. package/dist/utils/pending-ops-queue.d.ts +44 -0
  57. package/dist/utils/pending-ops-queue.d.ts.map +1 -0
  58. package/dist/utils/pending-ops-queue.js +82 -0
  59. package/dist/utils/pending-ops-queue.js.map +1 -0
  60. package/dist/utils/repository-token.util.d.ts +7 -0
  61. package/dist/utils/repository-token.util.d.ts.map +1 -0
  62. package/dist/utils/repository-token.util.js +21 -0
  63. package/dist/utils/repository-token.util.js.map +1 -0
  64. package/package.json +45 -0
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PendingOpsQueue = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ /**
6
+ * Cola en memoria de operaciones que no se pudieron aplicar de inmediato en
7
+ * una conexión secundaria (caché o backup) porque la conexión no estaba
8
+ * lista o la operación falló. Se reintenta periódicamente y, además,
9
+ * apenas la conexión emite el evento `connected`.
10
+ *
11
+ * Las operaciones que se encolan aquí son siempre upserts/deletes por `_id`
12
+ * (idempotentes), así que reintentarlas en orden FIFO, incluso varias
13
+ * veces, es seguro.
14
+ *
15
+ * Nota: esta cola vive en memoria del proceso. Si el proceso se reinicia
16
+ * mientras hay operaciones pendientes, se pierden — pero no hay pérdida de
17
+ * datos real, porque `BackupSyncService` (para backups) vuelve a poner al
18
+ * día cualquier backup comparando contra `main` en su próxima corrida. Para
19
+ * la caché, un siguiente `find`/`findOne` simplemente la repuebla.
20
+ */
21
+ class PendingOpsQueue {
22
+ constructor(label, intervalMs = 5000, maxQueueSize = 1000) {
23
+ this.label = label;
24
+ this.intervalMs = intervalMs;
25
+ this.maxQueueSize = maxQueueSize;
26
+ this.queue = [];
27
+ this.flushing = false;
28
+ this.logger = new common_1.Logger(`PendingOps:${label}`);
29
+ }
30
+ size() {
31
+ return this.queue.length;
32
+ }
33
+ enqueue(run, opLabel = this.label) {
34
+ if (this.queue.length >= this.maxQueueSize) {
35
+ const dropped = this.queue.shift();
36
+ this.logger.warn(`Cola llena (${this.maxQueueSize}), se descarta la operación pendiente más antigua (${dropped?.label}).`);
37
+ }
38
+ this.queue.push({ label: opLabel, run, attempts: 0, enqueuedAt: new Date() });
39
+ }
40
+ start() {
41
+ if (this.timer)
42
+ return;
43
+ this.timer = setInterval(() => {
44
+ this.flush().catch((err) => this.logger.error(err));
45
+ }, this.intervalMs);
46
+ }
47
+ stop() {
48
+ if (this.timer)
49
+ clearInterval(this.timer);
50
+ this.timer = undefined;
51
+ }
52
+ /** Reintenta de inmediato apenas la conexión vuelve a estar disponible, sin esperar al siguiente tick del timer. */
53
+ watchConnection(connection) {
54
+ connection.on('connected', () => {
55
+ this.flush().catch((err) => this.logger.error(err));
56
+ });
57
+ }
58
+ async flush() {
59
+ if (this.flushing || !this.queue.length)
60
+ return;
61
+ this.flushing = true;
62
+ try {
63
+ const pending = this.queue;
64
+ this.queue = [];
65
+ for (const item of pending) {
66
+ try {
67
+ await item.run();
68
+ }
69
+ catch (err) {
70
+ item.attempts += 1;
71
+ this.queue.push(item); // se reintenta en la próxima pasada
72
+ this.logger.debug(`Reintento fallido (#${item.attempts}) para "${item.label}": ${err?.message}`);
73
+ }
74
+ }
75
+ }
76
+ finally {
77
+ this.flushing = false;
78
+ }
79
+ }
80
+ }
81
+ exports.PendingOpsQueue = PendingOpsQueue;
82
+ //# sourceMappingURL=pending-ops-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-ops-queue.js","sourceRoot":"","sources":["../../src/utils/pending-ops-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Type } from '@nestjs/common';
2
+ /** Ej: getRepositoryToken(Position) -> "PositionRepositoryService" */
3
+ export declare function getRepositoryToken<T>(entity: Type<T>): string;
4
+ export declare function getBackupSyncToken<T>(entity: Type<T>): string;
5
+ export declare function getTombstoneModelName<T>(entity: Type<T>): string;
6
+ export declare function getSyncCheckpointModelName<T>(entity: Type<T>): string;
7
+ //# sourceMappingURL=repository-token.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-token.util.d.ts","sourceRoot":"","sources":["../../src/utils/repository-token.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAItC,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAE7D;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAE7D;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAEhE;AAED,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAErE"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRepositoryToken = getRepositoryToken;
4
+ exports.getBackupSyncToken = getBackupSyncToken;
5
+ exports.getTombstoneModelName = getTombstoneModelName;
6
+ exports.getSyncCheckpointModelName = getSyncCheckpointModelName;
7
+ const SERVICE_SUFFIX = 'RepositoryService';
8
+ /** Ej: getRepositoryToken(Position) -> "PositionRepositoryService" */
9
+ function getRepositoryToken(entity) {
10
+ return `${entity.name}${SERVICE_SUFFIX}`;
11
+ }
12
+ function getBackupSyncToken(entity) {
13
+ return `${entity.name}BackupSyncService`;
14
+ }
15
+ function getTombstoneModelName(entity) {
16
+ return `${entity.name}Tombstone`;
17
+ }
18
+ function getSyncCheckpointModelName(entity) {
19
+ return `${entity.name}SyncCheckpoint`;
20
+ }
21
+ //# sourceMappingURL=repository-token.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-token.util.js","sourceRoot":"","sources":["../../src/utils/repository-token.util.ts"],"names":[],"mappings":";;AAKA,gDAEC;AAED,gDAEC;AAED,sDAEC;AAED,gEAEC;AAjBD,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAE3C,sEAAsE;AACtE,SAAgB,kBAAkB,CAAI,MAAe;IACjD,OAAO,GAAG,MAAM,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC;AAC7C,CAAC;AAED,SAAgB,kBAAkB,CAAI,MAAe;IACjD,OAAO,GAAG,MAAM,CAAC,IAAI,mBAAmB,CAAC;AAC7C,CAAC;AAED,SAAgB,qBAAqB,CAAI,MAAe;IACpD,OAAO,GAAG,MAAM,CAAC,IAAI,WAAW,CAAC;AACrC,CAAC;AAED,SAAgB,0BAA0B,CAAI,MAAe;IACzD,OAAO,GAAG,MAAM,CAAC,IAAI,gBAAgB,CAAC;AAC1C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@deorta-dev/nestjs-repository-core",
3
+ "version": "0.1.0",
4
+ "description": "Genera repositorios genéricos para NestJS + Mongoose por entidad (sin crear una clase por entidad), con caché read-through con TTL y backups de solo-escritura resilientes a desconexiones.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.build.json",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "nestjs",
19
+ "mongoose",
20
+ "repository",
21
+ "orm",
22
+ "cache",
23
+ "backup",
24
+ "ttl"
25
+ ],
26
+ "license": "MIT",
27
+ "peerDependencies": {
28
+ "@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0",
29
+ "@nestjs/mongoose": "^9.0.0 || ^10.0.0 || ^11.0.0",
30
+ "mongoose": "^7.0.0 || ^8.0.0",
31
+ "class-transformer": "^0.5.0",
32
+ "reflect-metadata": "^0.1.13 || ^0.2.0",
33
+ "rxjs": "^7.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@nestjs/common": "^10.4.15",
37
+ "@nestjs/mongoose": "^10.1.0",
38
+ "@types/node": "^20.17.9",
39
+ "class-transformer": "^0.5.1",
40
+ "mongoose": "^8.9.2",
41
+ "reflect-metadata": "^0.1.14",
42
+ "rxjs": "^7.8.1",
43
+ "typescript": "^5.7.2"
44
+ }
45
+ }