@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.
- package/LICENSE +21 -0
- package/README.es.md +260 -0
- package/README.md +259 -0
- package/dist/base-repository.service.d.ts +73 -0
- package/dist/base-repository.service.d.ts.map +1 -0
- package/dist/base-repository.service.js +309 -0
- package/dist/base-repository.service.js.map +1 -0
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +18 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/repository-inject.decorator.d.ts +20 -0
- package/dist/decorators/repository-inject.decorator.d.ts.map +1 -0
- package/dist/decorators/repository-inject.decorator.js +29 -0
- package/dist/decorators/repository-inject.decorator.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/repository.module.d.ts +13 -0
- package/dist/repository.module.d.ts.map +1 -0
- package/dist/repository.module.js +92 -0
- package/dist/repository.module.js.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +20 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/sync-checkpoint.schema.d.ts +22 -0
- package/dist/schema/sync-checkpoint.schema.d.ts.map +1 -0
- package/dist/schema/sync-checkpoint.schema.js +13 -0
- package/dist/schema/sync-checkpoint.schema.js.map +1 -0
- package/dist/schema/tombstone.schema.d.ts +24 -0
- package/dist/schema/tombstone.schema.d.ts.map +1 -0
- package/dist/schema/tombstone.schema.js +15 -0
- package/dist/schema/tombstone.schema.js.map +1 -0
- package/dist/schema/with-cache-ttl.d.ts +14 -0
- package/dist/schema/with-cache-ttl.d.ts.map +1 -0
- package/dist/schema/with-cache-ttl.js +24 -0
- package/dist/schema/with-cache-ttl.js.map +1 -0
- package/dist/sync/backup-sync.service.d.ts +61 -0
- package/dist/sync/backup-sync.service.d.ts.map +1 -0
- package/dist/sync/backup-sync.service.js +156 -0
- package/dist/sync/backup-sync.service.js.map +1 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +18 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/pending-ops-queue.d.ts +44 -0
- package/dist/utils/pending-ops-queue.d.ts.map +1 -0
- package/dist/utils/pending-ops-queue.js +82 -0
- package/dist/utils/pending-ops-queue.js.map +1 -0
- package/dist/utils/repository-token.util.d.ts +7 -0
- package/dist/utils/repository-token.util.d.ts.map +1 -0
- package/dist/utils/repository-token.util.js +21 -0
- package/dist/utils/repository-token.util.js.map +1 -0
- 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
|
+
}
|