@generazioneai/events 0.1.0 → 0.3.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/CHANGELOG.md +33 -0
- package/README.md +55 -8
- package/dist/consumers.service.d.ts.map +1 -1
- package/dist/consumers.service.js +5 -7
- package/dist/consumers.service.js.map +1 -1
- package/dist/drizzle/index.d.ts +3 -0
- package/dist/drizzle/index.d.ts.map +1 -0
- package/dist/drizzle/index.js +10 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/drizzle/schema.d.ts +279 -0
- package/dist/drizzle/schema.d.ts.map +1 -0
- package/dist/drizzle/schema.js +37 -0
- package/dist/drizzle/schema.js.map +1 -0
- package/dist/drizzle/store.d.ts +51 -0
- package/dist/drizzle/store.d.ts.map +1 -0
- package/dist/drizzle/store.js +118 -0
- package/dist/drizzle/store.js.map +1 -0
- package/dist/events.module.d.ts.map +1 -1
- package/dist/events.module.js +6 -2
- package/dist/events.module.js.map +1 -1
- package/dist/final-mode.d.ts +23 -0
- package/dist/final-mode.d.ts.map +1 -0
- package/dist/final-mode.js +56 -0
- package/dist/final-mode.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.d.ts +8 -0
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +28 -0
- package/dist/metrics.js.map +1 -1
- package/dist/outbox.service.d.ts +11 -15
- package/dist/outbox.service.d.ts.map +1 -1
- package/dist/outbox.service.js +27 -32
- package/dist/outbox.service.js.map +1 -1
- package/dist/prisma-resolver.d.ts +9 -1
- package/dist/prisma-resolver.d.ts.map +1 -1
- package/dist/prisma-resolver.js +14 -1
- package/dist/prisma-resolver.js.map +1 -1
- package/dist/relay.service.d.ts.map +1 -1
- package/dist/relay.service.js +10 -14
- package/dist/relay.service.js.map +1 -1
- package/dist/store.d.ts +91 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +78 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +27 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -6
- package/dist/types.js.map +1 -1
- package/package.json +33 -5
- package/sql/002-events-outbox-inbox-snake-rientro.sql +3 -0
- package/sql/002-events-outbox-inbox-snake.sql +29 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox.service.js","sourceRoot":"","sources":["../src/outbox.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"outbox.service.js","sourceRoot":"","sources":["../src/outbox.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { ModuleRef } from '@nestjs/core';
|
|
2
|
+
import { type OutboxStore } from './store';
|
|
2
3
|
import type { EventsModuleOptions, PrismaLike } from './types';
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Risolve la persistenza quando serve (non alla costruzione: il suo modulo può non essere ancora pronto): lo `store` di
|
|
6
|
+
* `EventsModule.forRoot({ store })` (Drizzle) oppure, di serie, quello di Prisma sopra `PrismaService`. Il nome è rimasto
|
|
7
|
+
* quello di quando c'era solo Prisma.
|
|
8
|
+
*/
|
|
4
9
|
export declare class PrismaResolver {
|
|
5
10
|
private readonly ref;
|
|
6
11
|
private readonly raw;
|
|
7
12
|
private cached?;
|
|
13
|
+
private cachedStore?;
|
|
8
14
|
constructor(ref: ModuleRef, raw: EventsModuleOptions);
|
|
9
15
|
get(): PrismaLike;
|
|
16
|
+
/** Lo store scelto in `forRoot`: `store` se c'è, altrimenti Prisma. Con tutti e due, vince `store`. */
|
|
17
|
+
store(): OutboxStore;
|
|
10
18
|
}
|
|
11
19
|
//# sourceMappingURL=prisma-resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prisma-resolver.d.ts","sourceRoot":"","sources":["../src/prisma-resolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"prisma-resolver.d.ts","sourceRoot":"","sources":["../src/prisma-resolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;GAIG;AACH,qBACa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACQ,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJlD,OAAO,CAAC,MAAM,CAAC,CAAa;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAc;gBAEf,GAAG,EAAE,SAAS,EACc,GAAG,EAAE,mBAAmB;IAGvE,GAAG,IAAI,UAAU;IAajB,uGAAuG;IACvG,KAAK,IAAI,WAAW;CAMrB"}
|
package/dist/prisma-resolver.js
CHANGED
|
@@ -16,8 +16,13 @@ exports.PrismaResolver = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const core_1 = require("@nestjs/core");
|
|
18
18
|
const errors_1 = require("./errors");
|
|
19
|
+
const store_1 = require("./store");
|
|
19
20
|
const tokens_1 = require("./tokens");
|
|
20
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Risolve la persistenza quando serve (non alla costruzione: il suo modulo può non essere ancora pronto): lo `store` di
|
|
23
|
+
* `EventsModule.forRoot({ store })` (Drizzle) oppure, di serie, quello di Prisma sopra `PrismaService`. Il nome è rimasto
|
|
24
|
+
* quello di quando c'era solo Prisma.
|
|
25
|
+
*/
|
|
21
26
|
let PrismaResolver = class PrismaResolver {
|
|
22
27
|
constructor(ref, raw) {
|
|
23
28
|
this.ref = ref;
|
|
@@ -36,6 +41,14 @@ let PrismaResolver = class PrismaResolver {
|
|
|
36
41
|
this.cached = inst;
|
|
37
42
|
return inst;
|
|
38
43
|
}
|
|
44
|
+
/** Lo store scelto in `forRoot`: `store` se c'è, altrimenti Prisma. Con tutti e due, vince `store`. */
|
|
45
|
+
store() {
|
|
46
|
+
if (this.cachedStore)
|
|
47
|
+
return this.cachedStore;
|
|
48
|
+
const s = this.raw.store ?? new store_1.PrismaOutboxStore(() => this.get());
|
|
49
|
+
this.cachedStore = s;
|
|
50
|
+
return s;
|
|
51
|
+
}
|
|
39
52
|
};
|
|
40
53
|
exports.PrismaResolver = PrismaResolver;
|
|
41
54
|
exports.PrismaResolver = PrismaResolver = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prisma-resolver.js","sourceRoot":"","sources":["../src/prisma-resolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,uCAAyC;AACzC,qCAAuC;AACvC,qCAA8C;AAG9C
|
|
1
|
+
{"version":3,"file":"prisma-resolver.js","sourceRoot":"","sources":["../src/prisma-resolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,uCAAyC;AACzC,qCAAuC;AACvC,mCAA8D;AAC9D,qCAA8C;AAG9C;;;;GAIG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAc;IAGzB,YACmB,GAAc,EACc,GAAwB;QADpD,QAAG,GAAH,GAAG,CAAW;QACc,QAAG,GAAH,GAAG,CAAqB;IACpE,CAAC;IAEJ,GAAG;QACD,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACpC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,UAAU,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;YACrF,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YAC3C,CAAC,CAAC,CAAC,CAA2B,CAAC;QACjC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;YACrD,MAAM,IAAI,oBAAW,CAAC,eAAe,EAAE,kFAAkF,CAAC,CAAC;QAC7H,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uGAAuG;IACvG,KAAK;QACH,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,yBAAiB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;CACF,CAAA;AA5BY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,eAAM,EAAC,2BAAkB,CAAC,CAAA;qCADL,gBAAS;GAJtB,cAAc,CA4B1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay.service.d.ts","sourceRoot":"","sources":["../src/relay.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"relay.service.d.ts","sourceRoot":"","sources":["../src/relay.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEpE;;;;;GAKG;AACH,qBACa,WAAW;IASI,OAAO,CAAC,QAAQ,CAAC,IAAI;IAC7C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,SAAS,CAAK;gBAGqB,IAAI,EAAE,qBAAqB,EACnD,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa;IAGzC,KAAK,IAAI,IAAI;IAMP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,OAAO,CAAC,QAAQ;YAKF,IAAI;IAYlB,6EAA6E;IACvE,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;YA+BpB,OAAO;YAuBP,YAAY;CAc3B"}
|
package/dist/relay.service.js
CHANGED
|
@@ -75,22 +75,20 @@ let OutboxRelay = class OutboxRelay {
|
|
|
75
75
|
try {
|
|
76
76
|
if (!this.conn.connected)
|
|
77
77
|
return 0;
|
|
78
|
-
const
|
|
79
|
-
return await
|
|
80
|
-
const rows = await tx
|
|
81
|
-
FROM outbox_events WHERE "publishedAt" IS NULL ORDER BY "id" LIMIT ${Math.floor(this.opts.relayBatchSize)}
|
|
82
|
-
FOR UPDATE SKIP LOCKED`);
|
|
78
|
+
const store = this.prisma.store();
|
|
79
|
+
return await store.transaction(async (tx) => {
|
|
80
|
+
const rows = await store.claimPending(tx, this.opts.relayBatchSize);
|
|
83
81
|
let done = 0;
|
|
84
82
|
for (const r of rows) {
|
|
85
83
|
try {
|
|
86
84
|
await this.publish(r);
|
|
87
85
|
}
|
|
88
86
|
catch (e) {
|
|
89
|
-
await tx
|
|
87
|
+
await store.markFailed(tx, r.id, String(e?.message ?? e).slice(0, 500));
|
|
90
88
|
this.log.warn(`pubblicazione di ${r.subject} (${r.id}) fallita: ${e?.message ?? e}`);
|
|
91
89
|
break;
|
|
92
90
|
}
|
|
93
|
-
await tx
|
|
91
|
+
await store.markPublished(tx, r.id);
|
|
94
92
|
this.metrics.inc('events_published_total', { subject: r.subject });
|
|
95
93
|
done++;
|
|
96
94
|
}
|
|
@@ -127,18 +125,16 @@ let OutboxRelay = class OutboxRelay {
|
|
|
127
125
|
}
|
|
128
126
|
async housekeeping() {
|
|
129
127
|
const now = Date.now();
|
|
130
|
-
const
|
|
128
|
+
const store = this.prisma.store();
|
|
131
129
|
if (now - this.lastGauges > 5_000) {
|
|
132
130
|
this.lastGauges = now;
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
this.metrics.set('
|
|
136
|
-
this.metrics.set('events_outbox_oldest_seconds', Number(row?.oldest ?? 0));
|
|
131
|
+
const { pending, oldestSeconds } = await store.pendingStats();
|
|
132
|
+
this.metrics.set('events_outbox_pending', pending);
|
|
133
|
+
this.metrics.set('events_outbox_oldest_seconds', oldestSeconds);
|
|
137
134
|
}
|
|
138
135
|
if (now - this.lastPrune > 600_000) {
|
|
139
136
|
this.lastPrune = now;
|
|
140
|
-
await
|
|
141
|
-
await prisma.$executeRawUnsafe(`DELETE FROM inbox_processed WHERE "processedAt" < CURRENT_TIMESTAMP - make_interval(days => ${Math.floor(this.opts.inboxRetentionDays)})`);
|
|
137
|
+
await store.prune(this.opts.outboxRetentionDays, this.opts.inboxRetentionDays);
|
|
142
138
|
}
|
|
143
139
|
}
|
|
144
140
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay.service.js","sourceRoot":"","sources":["../src/relay.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4D;AAC5D,4DAAiE;AACjE,6CAAgD;AAChD,uCAA0C;AAC1C,uDAAmD;AACnD,qCAA0C;
|
|
1
|
+
{"version":3,"file":"relay.service.js","sourceRoot":"","sources":["../src/relay.service.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { EventsError } from './errors';
|
|
2
|
+
import type { PrismaLike, PrismaTx } from './types';
|
|
3
|
+
/** Una riga dell'outbox, com'è letta dal relay. `payload` e `headers` sono già oggetti (mai stringhe JSON). */
|
|
4
|
+
export interface OutboxRow {
|
|
5
|
+
id: string;
|
|
6
|
+
subject: string;
|
|
7
|
+
aggregateType: string;
|
|
8
|
+
aggregateId: string;
|
|
9
|
+
aggregateVersion: number;
|
|
10
|
+
juridicalId: string | null;
|
|
11
|
+
payload: unknown;
|
|
12
|
+
headers: {
|
|
13
|
+
occurredAt?: string;
|
|
14
|
+
traceparent?: string;
|
|
15
|
+
} | null;
|
|
16
|
+
}
|
|
17
|
+
/** La riga che `enqueue` scrive. `payload` e `headers` sono JSON già serializzato (testo). */
|
|
18
|
+
export interface OutboxInsert {
|
|
19
|
+
id: string;
|
|
20
|
+
subject: string;
|
|
21
|
+
aggregateType: string;
|
|
22
|
+
aggregateId: string;
|
|
23
|
+
aggregateVersion: number;
|
|
24
|
+
juridicalId: string | null;
|
|
25
|
+
payload: string;
|
|
26
|
+
headers: string;
|
|
27
|
+
}
|
|
28
|
+
export interface OutboxTransactionOptions {
|
|
29
|
+
timeout?: number;
|
|
30
|
+
maxWait?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tutto quello che la libreria chiede al database, dietro un'interfaccia sola: così lo stesso outbox, relay e consumer girano
|
|
34
|
+
* sopra Prisma (`PrismaOutboxStore`, di serie) o Drizzle (`@generazioneai/events/drizzle`). `Tx` è il tipo della transazione
|
|
35
|
+
* del chiamante: il `tx` di `prisma.$transaction(async (tx) => …)` o quello di `db.transaction(async (tx) => …)` di Drizzle.
|
|
36
|
+
*
|
|
37
|
+
* Contratto di ogni implementazione: un'unica transazione per `transaction()`; `claimPending` blocca le righe con
|
|
38
|
+
* `FOR UPDATE SKIP LOCKED` (più relay non si pestano i piedi); `claimInbox` è atomico (`ON CONFLICT DO NOTHING`).
|
|
39
|
+
*/
|
|
40
|
+
export interface OutboxStore<Tx = any> {
|
|
41
|
+
/** Nome per i log (`prisma`, `drizzle`). */
|
|
42
|
+
readonly kind: string;
|
|
43
|
+
/** Forma minima: `tx` ha ciò che serve a eseguire SQL. Non prova che sia una transazione (lo fa `assertInTransaction`). */
|
|
44
|
+
accepts(tx: unknown): tx is Tx;
|
|
45
|
+
/** Lancia `EVENTS_OUTSIDE_TX` se `tx` non è dentro un blocco di transazione (prova con `SAVEPOINT`, che Postgres ammette solo lì). */
|
|
46
|
+
assertInTransaction(tx: Tx, subject: string | undefined): Promise<void>;
|
|
47
|
+
insert(tx: Tx, row: OutboxInsert): Promise<void>;
|
|
48
|
+
transaction<R>(fn: (tx: Tx) => Promise<R>, options?: OutboxTransactionOptions): Promise<R>;
|
|
49
|
+
claimPending(tx: Tx, limit: number): Promise<OutboxRow[]>;
|
|
50
|
+
markPublished(tx: Tx, id: string): Promise<void>;
|
|
51
|
+
markFailed(tx: Tx, id: string, error: string): Promise<void>;
|
|
52
|
+
/** `true` se `(consumer, eventId)` è nuovo e ora è registrato; `false` se c'era già. */
|
|
53
|
+
claimInbox(tx: Tx, consumer: string, eventId: string): Promise<boolean>;
|
|
54
|
+
pendingStats(): Promise<{
|
|
55
|
+
pending: number;
|
|
56
|
+
oldestSeconds: number;
|
|
57
|
+
}>;
|
|
58
|
+
prune(outboxDays: number, inboxDays: number): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
export declare const outsideTransaction: (subject: string | undefined, cause?: unknown, kind?: string) => EventsError;
|
|
61
|
+
export declare const OUTBOX_INSERT = "INSERT INTO outbox_events\n (\"id\",\"subject\",\"aggregateType\",\"aggregateId\",\"aggregateVersion\",\"juridicalId\",\"payload\",\"headers\")\n VALUES ($1::uuid,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb)";
|
|
62
|
+
/**
|
|
63
|
+
* Lo store di Prisma (colonne in camelCase tra virgolette, come in `prisma/events.prisma`). Le operazioni su un `tx` non
|
|
64
|
+
* toccano il client radice; `transaction`, `pendingStats` e `prune` lo cercano al momento dell'uso (`root`).
|
|
65
|
+
*/
|
|
66
|
+
export declare class PrismaOutboxStore implements OutboxStore<PrismaTx> {
|
|
67
|
+
private readonly root;
|
|
68
|
+
readonly kind = "prisma";
|
|
69
|
+
/** Client di transazione già verificati (un `tx` vive quanto la sua transazione: la prova si fa una volta sola). */
|
|
70
|
+
private readonly verified;
|
|
71
|
+
constructor(root?: () => PrismaLike);
|
|
72
|
+
accepts(tx: unknown): tx is PrismaTx;
|
|
73
|
+
/**
|
|
74
|
+
* Riconosce una transazione dal lato del database, non dalla forma del client (in Prisma 7 il `tx` ha anch'esso `$transaction`):
|
|
75
|
+
* `SAVEPOINT` esiste solo dentro un blocco di transazione, altrimenti Postgres risponde 25P01. Con il client radice (una query
|
|
76
|
+
* in autocommit) fallisce → `EVENTS_OUTSIDE_TX`. Un `tx` verificato non si riprova.
|
|
77
|
+
*/
|
|
78
|
+
assertInTransaction(tx: PrismaTx, subject: string | undefined): Promise<void>;
|
|
79
|
+
insert(tx: PrismaTx, r: OutboxInsert): Promise<void>;
|
|
80
|
+
transaction<R>(fn: (tx: PrismaTx) => Promise<R>, options?: OutboxTransactionOptions): Promise<R>;
|
|
81
|
+
claimPending(tx: PrismaTx, limit: number): Promise<OutboxRow[]>;
|
|
82
|
+
markPublished(tx: PrismaTx, id: string): Promise<void>;
|
|
83
|
+
markFailed(tx: PrismaTx, id: string, error: string): Promise<void>;
|
|
84
|
+
claimInbox(tx: PrismaTx, consumer: string, eventId: string): Promise<boolean>;
|
|
85
|
+
pendingStats(): Promise<{
|
|
86
|
+
pending: number;
|
|
87
|
+
oldestSeconds: number;
|
|
88
|
+
}>;
|
|
89
|
+
prune(outboxDays: number, inboxDays: number): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrismaOutboxStore = exports.OUTBOX_INSERT = exports.outsideTransaction = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const outsideTransaction = (subject, cause, kind) => new errors_1.EventsError('EVENTS_OUTSIDE_TX', `enqueue(${subject}) va chiamato dentro la transazione del dato passando il tx, non il client${kind && cause === undefined ? ` (il tx passato non ha la forma attesa dallo store ${kind}: controlla \`prisma\` / \`store\` di EventsModule.forRoot)` : ''}${cause ? ` (${cause?.message ?? cause})` : ''}`);
|
|
6
|
+
exports.outsideTransaction = outsideTransaction;
|
|
7
|
+
exports.OUTBOX_INSERT = `INSERT INTO outbox_events
|
|
8
|
+
("id","subject","aggregateType","aggregateId","aggregateVersion","juridicalId","payload","headers")
|
|
9
|
+
VALUES ($1::uuid,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb)`;
|
|
10
|
+
/**
|
|
11
|
+
* Lo store di Prisma (colonne in camelCase tra virgolette, come in `prisma/events.prisma`). Le operazioni su un `tx` non
|
|
12
|
+
* toccano il client radice; `transaction`, `pendingStats` e `prune` lo cercano al momento dell'uso (`root`).
|
|
13
|
+
*/
|
|
14
|
+
class PrismaOutboxStore {
|
|
15
|
+
constructor(root = () => {
|
|
16
|
+
throw new errors_1.EventsError('EVENTS_CONFIG', 'EventsModule.forRoot({ prisma }) non risolve a un PrismaService con $transaction');
|
|
17
|
+
}) {
|
|
18
|
+
this.root = root;
|
|
19
|
+
this.kind = 'prisma';
|
|
20
|
+
/** Client di transazione già verificati (un `tx` vive quanto la sua transazione: la prova si fa una volta sola). */
|
|
21
|
+
this.verified = new WeakSet();
|
|
22
|
+
}
|
|
23
|
+
accepts(tx) {
|
|
24
|
+
return !!tx && typeof tx.$executeRawUnsafe === 'function';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Riconosce una transazione dal lato del database, non dalla forma del client (in Prisma 7 il `tx` ha anch'esso `$transaction`):
|
|
28
|
+
* `SAVEPOINT` esiste solo dentro un blocco di transazione, altrimenti Postgres risponde 25P01. Con il client radice (una query
|
|
29
|
+
* in autocommit) fallisce → `EVENTS_OUTSIDE_TX`. Un `tx` verificato non si riprova.
|
|
30
|
+
*/
|
|
31
|
+
async assertInTransaction(tx, subject) {
|
|
32
|
+
if (!this.accepts(tx))
|
|
33
|
+
throw (0, exports.outsideTransaction)(subject, undefined, this.kind);
|
|
34
|
+
if (this.verified.has(tx))
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
await tx.$executeRawUnsafe('SAVEPOINT genai_events_probe');
|
|
38
|
+
await tx.$executeRawUnsafe('RELEASE SAVEPOINT genai_events_probe');
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
throw (0, exports.outsideTransaction)(subject, e);
|
|
42
|
+
}
|
|
43
|
+
this.verified.add(tx);
|
|
44
|
+
}
|
|
45
|
+
async insert(tx, r) {
|
|
46
|
+
await tx.$executeRawUnsafe(exports.OUTBOX_INSERT, r.id, r.subject, r.aggregateType, r.aggregateId, r.aggregateVersion, r.juridicalId, r.payload, r.headers);
|
|
47
|
+
}
|
|
48
|
+
transaction(fn, options) {
|
|
49
|
+
return this.root().$transaction(fn, options);
|
|
50
|
+
}
|
|
51
|
+
claimPending(tx, limit) {
|
|
52
|
+
return tx.$queryRawUnsafe(`SELECT "id","subject","aggregateType","aggregateId","aggregateVersion","juridicalId","payload","headers"
|
|
53
|
+
FROM outbox_events WHERE "publishedAt" IS NULL ORDER BY "id" LIMIT ${Math.floor(limit)}
|
|
54
|
+
FOR UPDATE SKIP LOCKED`);
|
|
55
|
+
}
|
|
56
|
+
async markPublished(tx, id) {
|
|
57
|
+
await tx.$executeRawUnsafe(`UPDATE outbox_events SET "publishedAt" = CURRENT_TIMESTAMP, "attempts" = "attempts" + 1, "lastError" = NULL WHERE "id" = $1::uuid`, id);
|
|
58
|
+
}
|
|
59
|
+
async markFailed(tx, id, error) {
|
|
60
|
+
await tx.$executeRawUnsafe(`UPDATE outbox_events SET "attempts" = "attempts" + 1, "lastError" = $2 WHERE "id" = $1::uuid`, id, error);
|
|
61
|
+
}
|
|
62
|
+
async claimInbox(tx, consumer, eventId) {
|
|
63
|
+
const n = await tx.$executeRawUnsafe(`INSERT INTO inbox_processed ("consumer","eventId") VALUES ($1,$2::uuid) ON CONFLICT DO NOTHING`, consumer, eventId);
|
|
64
|
+
return n !== 0;
|
|
65
|
+
}
|
|
66
|
+
async pendingStats() {
|
|
67
|
+
const [row] = await this.root().$queryRawUnsafe(`SELECT COUNT(*) AS pending, EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - MIN("createdAt")))::float8 AS oldest
|
|
68
|
+
FROM outbox_events WHERE "publishedAt" IS NULL`);
|
|
69
|
+
return { pending: Number(row?.pending ?? 0), oldestSeconds: Number(row?.oldest ?? 0) };
|
|
70
|
+
}
|
|
71
|
+
async prune(outboxDays, inboxDays) {
|
|
72
|
+
const prisma = this.root();
|
|
73
|
+
await prisma.$executeRawUnsafe(`DELETE FROM outbox_events WHERE "publishedAt" IS NOT NULL AND "publishedAt" < CURRENT_TIMESTAMP - make_interval(days => ${Math.floor(outboxDays)})`);
|
|
74
|
+
await prisma.$executeRawUnsafe(`DELETE FROM inbox_processed WHERE "processedAt" < CURRENT_TIMESTAMP - make_interval(days => ${Math.floor(inboxDays)})`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.PrismaOutboxStore = PrismaOutboxStore;
|
|
78
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OutboxStore } from './store';
|
|
1
2
|
/** Busta di ogni evento (versione 1). Il corpo del messaggio NATS è questo oggetto in JSON. */
|
|
2
3
|
export interface EventEnvelope<T = unknown> {
|
|
3
4
|
v: 1;
|
|
@@ -14,11 +15,22 @@ export interface EventEnvelope<T = unknown> {
|
|
|
14
15
|
/** Solo id e stati, mai dati personali. */
|
|
15
16
|
data: T;
|
|
16
17
|
}
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Servizi che pubblicano o consumano eventi (contratto del treno 3+4). `checkflow` pubblica solo su `audit.checkflow[.…]` (stream
|
|
20
|
+
* `AUDIT`) e consuma `evt.id.*`: nessuno stream `EVT_CHECKFLOW` finché non c'è chi lo consuma (eccezione E6 della spec di CheckFlow),
|
|
21
|
+
* quindi lo registra con `createStream: false`.
|
|
22
|
+
*/
|
|
23
|
+
export type EventsService = 'id' | 'hr' | 'train' | 'ops' | 'notify' | 'ai' | 'sign' | 'bill' | 'audit' | 'checkflow';
|
|
24
|
+
/**
|
|
25
|
+
* `EVENTS_MODE`: off = niente; outbox = si scrive l'outbox ma non si pubblica né si consuma; on = tutto.
|
|
26
|
+
* 0.3 (via gli interruttori, 2026-11-10): sempre `on`; `off`/`outbox` (opzione `mode` o env) solo in sviluppo locale e nei test.
|
|
27
|
+
*/
|
|
20
28
|
export type EventsMode = 'off' | 'outbox' | 'on';
|
|
21
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* `EVENTS_SIGNATURE`: off = nessuna firma; shadow = firma e verifica senza rifiutare; enforce = rifiuta le firme assenti o errate.
|
|
31
|
+
* 0.3 (via gli interruttori): sempre `enforce`; `off`/`shadow` solo in sviluppo locale e nei test. La firma la fa chi ha il
|
|
32
|
+
* `signer`, la verifica chi ha il `verifier` (parametri del servizio): senza, una riga nel log all'avvio, mai un errore.
|
|
33
|
+
*/
|
|
22
34
|
export type EventsSignatureMode = 'off' | 'shadow' | 'enforce';
|
|
23
35
|
/** Il pezzo di Prisma che serve alla libreria dentro una transazione (il `tx` di `$transaction(async tx => …)`). */
|
|
24
36
|
export interface PrismaTx {
|
|
@@ -52,7 +64,8 @@ export interface OnEventOptions {
|
|
|
52
64
|
/** Messaggi senza ack tollerati dal consumer (default 100). */
|
|
53
65
|
maxAckPending?: number;
|
|
54
66
|
}
|
|
55
|
-
|
|
67
|
+
/** Il gestore di `@OnEvent`: `tx` è la transazione dello store (Prisma di serie; con lo store Drizzle è il `tx` di Drizzle, `Tx` lo dichiara). */
|
|
68
|
+
export type EventHandler<T = any, Tx = PrismaTx> = (evt: EventEnvelope<T>, tx: Tx) => Promise<void>;
|
|
56
69
|
export interface EnqueueParams<T = unknown> {
|
|
57
70
|
/** `evt.<servizio>.<entità>.<fatto>` al passato. */
|
|
58
71
|
subject: string;
|
|
@@ -69,11 +82,16 @@ export interface EventsModuleOptions {
|
|
|
69
82
|
service: EventsService;
|
|
70
83
|
/** Default `EVT_<SERVICE>`. */
|
|
71
84
|
stream?: string;
|
|
72
|
-
/** La classe (o il token) di `PrismaService` da risolvere dal contenitore di Nest, oppure direttamente l'istanza. */
|
|
73
|
-
prisma
|
|
74
|
-
/**
|
|
85
|
+
/** La classe (o il token) di `PrismaService` da risolvere dal contenitore di Nest, oppure direttamente l'istanza. Non serve con `store`. */
|
|
86
|
+
prisma?: unknown;
|
|
87
|
+
/**
|
|
88
|
+
* La persistenza di outbox e inbox, al posto di Prisma: per Drizzle `createDrizzleOutboxStore({ db })` da
|
|
89
|
+
* `@generazioneai/events/drizzle`. Se ci sono `store` e `prisma`, vince `store`.
|
|
90
|
+
*/
|
|
91
|
+
store?: OutboxStore;
|
|
92
|
+
/** 0.3: sempre `on` fuori dallo sviluppo locale (lì: questa opzione, `EVENTS_MODE`, `on`). */
|
|
75
93
|
mode?: EventsMode;
|
|
76
|
-
/**
|
|
94
|
+
/** 0.3: sempre `enforce` fuori dallo sviluppo locale (lì: questa opzione, `EVENTS_SIGNATURE`, `enforce`). */
|
|
77
95
|
signatureMode?: EventsSignatureMode;
|
|
78
96
|
signer?: EventSigner;
|
|
79
97
|
verifier?: EventVerifier;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,CAAC,EAAE,CAAC,CAAC;IACL,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,IAAI,EAAE,CAAC,CAAC;CACT;AAED
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_RETRY_SCHEDULE_MS = void 0;
|
|
4
4
|
exports.resolveOptions = resolveOptions;
|
|
5
|
+
const final_mode_1 = require("./final-mode");
|
|
5
6
|
exports.DEFAULT_RETRY_SCHEDULE_MS = [10_000, 60_000, 300_000, 1_800_000, 7_200_000, 21_600_000, 43_200_000];
|
|
6
7
|
function resolveOptions(o, env = process.env) {
|
|
7
|
-
const mode = (o.mode ?? env.EVENTS_MODE
|
|
8
|
-
const sig = (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const mode = (0, final_mode_1.finalMode)({ name: 'EVENTS_MODE', final: 'on', allowed: ['off', 'outbox', 'on'], requested: o.mode ?? env.EVENTS_MODE, env });
|
|
9
|
+
const sig = (0, final_mode_1.finalMode)({
|
|
10
|
+
name: 'EVENTS_SIGNATURE',
|
|
11
|
+
final: 'enforce',
|
|
12
|
+
allowed: ['off', 'shadow', 'enforce'],
|
|
13
|
+
requested: o.signatureMode ?? env.EVENTS_SIGNATURE,
|
|
14
|
+
env,
|
|
15
|
+
});
|
|
13
16
|
return {
|
|
14
17
|
service: o.service,
|
|
15
18
|
stream: o.stream ?? `EVT_${o.service.toUpperCase()}`,
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA8JA,wCA6BC;AA1LD,6CAAyC;AAiI5B,QAAA,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AA4BjH,SAAgB,cAAc,CAAC,CAAsB,EAAE,MAAyB,OAAO,CAAC,GAAG;IACzF,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAU,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IACnJ,MAAM,GAAG,GAAG,IAAA,sBAAS,EAAC;QACpB,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAU;QAC9C,SAAS,EAAE,CAAC,CAAC,aAAa,IAAI,GAAG,CAAC,gBAAgB;QAClD,GAAG;KACJ,CAAC,CAAC;IACH,OAAO;QACL,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE;QACpD,IAAI;QACJ,aAAa,EAAE,GAAG;QAClB,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;QACpC,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzG,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QACvH,eAAe,EAAE,CAAC,CAAC,eAAe,IAAI,iCAAyB;QAC/D,eAAe,EAAE,CAAC,CAAC,eAAe,IAAI,GAAG;QACzC,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,GAAG;QACvC,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK;QACzB,mBAAmB,EAAE,CAAC,CAAC,mBAAmB,IAAI,CAAC;QAC/C,kBAAkB,EAAE,CAAC,CAAC,kBAAkB,IAAI,EAAE;QAC9C,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,QAAQ;QACzD,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@generazioneai/events",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Eventi durevoli fra i servizi (ADR-009): outbox transazionale, relay su NATS JetStream, consumer durevoli con inbox idempotente, riprove con attesa crescente e dead letter comune.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Eventi durevoli fra i servizi (ADR-009): outbox transazionale, relay su NATS JetStream, consumer durevoli con inbox idempotente, riprove con attesa crescente e dead letter comune. Persistenza su Prisma o su Drizzle (@generazioneai/events/drizzle).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./drizzle": {
|
|
13
|
+
"types": "./dist/drizzle/index.d.ts",
|
|
14
|
+
"default": "./dist/drizzle/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./sql/*": "./sql/*",
|
|
17
|
+
"./prisma/*": "./prisma/*",
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"typesVersions": {
|
|
21
|
+
"*": {
|
|
22
|
+
"drizzle": [
|
|
23
|
+
"dist/drizzle/index.d.ts"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
7
27
|
"files": [
|
|
8
28
|
"dist",
|
|
9
29
|
"sql",
|
|
@@ -31,18 +51,23 @@
|
|
|
31
51
|
"test:prepare": "prisma generate --config test/prisma/prisma.config.ts"
|
|
32
52
|
},
|
|
33
53
|
"dependencies": {
|
|
54
|
+
"@opentelemetry/api": "~1.9.0",
|
|
34
55
|
"@nats-io/jetstream": "^3.4.0",
|
|
35
56
|
"@nats-io/transport-node": "^3.4.0"
|
|
36
57
|
},
|
|
37
58
|
"peerDependencies": {
|
|
38
|
-
"@generazioneai/authz": "^0.7.0",
|
|
59
|
+
"@generazioneai/authz": "^0.7.0 || ^0.8.0",
|
|
39
60
|
"@nestjs/common": "^11.0.0 || ^12.0.0",
|
|
40
61
|
"@nestjs/core": "^11.0.0 || ^12.0.0",
|
|
41
|
-
"reflect-metadata": "^0.2.0"
|
|
62
|
+
"reflect-metadata": "^0.2.0",
|
|
63
|
+
"drizzle-orm": ">=0.36.0"
|
|
42
64
|
},
|
|
43
65
|
"peerDependenciesMeta": {
|
|
44
66
|
"@generazioneai/authz": {
|
|
45
67
|
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"drizzle-orm": {
|
|
70
|
+
"optional": true
|
|
46
71
|
}
|
|
47
72
|
},
|
|
48
73
|
"devDependencies": {
|
|
@@ -53,7 +78,9 @@
|
|
|
53
78
|
"@prisma/client": "^7.8.0",
|
|
54
79
|
"@types/node": "^22.0.0",
|
|
55
80
|
"@types/pg": "^8.15.0",
|
|
81
|
+
"drizzle-orm": "^0.45.2",
|
|
56
82
|
"pg": "^8.16.0",
|
|
83
|
+
"postgres": "^3.4.9",
|
|
57
84
|
"prisma": "^7.8.0",
|
|
58
85
|
"rxjs": "^7.8.1",
|
|
59
86
|
"typescript": "^5.1.3"
|
|
@@ -62,7 +89,8 @@
|
|
|
62
89
|
"jetstream",
|
|
63
90
|
"nats",
|
|
64
91
|
"outbox",
|
|
65
|
-
"events"
|
|
92
|
+
"events",
|
|
93
|
+
"drizzle"
|
|
66
94
|
],
|
|
67
95
|
"license": "UNLICENSED",
|
|
68
96
|
"homepage": "https://github.com/GenerazioneAI-SRL/authz/tree/main/packages/events#readme"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- @generazioneai/events 0.2.0: outbox e inbox per lo store Drizzle (colonne in snake_case, timestamptz). Solo aggiunte; il rientro è
|
|
2
|
+
-- 002-events-outbox-inbox-snake-rientro.sql. Equivalente SQL di `outboxEvents` e `inboxProcessed` in `@generazioneai/events/drizzle`:
|
|
3
|
+
-- con drizzle-kit si ri-esportano dallo schema e la migrazione la genera lui; questo file serve a chi scrive le migrazioni a mano.
|
|
4
|
+
-- Non usarlo insieme a 001 (stesse tabelle, colonne con altri nomi).
|
|
5
|
+
CREATE TABLE IF NOT EXISTS "outbox_events" (
|
|
6
|
+
"id" UUID NOT NULL,
|
|
7
|
+
"subject" TEXT NOT NULL,
|
|
8
|
+
"aggregate_type" TEXT NOT NULL,
|
|
9
|
+
"aggregate_id" TEXT NOT NULL,
|
|
10
|
+
"aggregate_version" INTEGER NOT NULL,
|
|
11
|
+
"juridical_id" TEXT,
|
|
12
|
+
"payload" JSONB NOT NULL,
|
|
13
|
+
"headers" JSONB,
|
|
14
|
+
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT now(),
|
|
15
|
+
"published_at" TIMESTAMPTZ(3),
|
|
16
|
+
"attempts" INTEGER NOT NULL DEFAULT 0,
|
|
17
|
+
"last_error" TEXT,
|
|
18
|
+
CONSTRAINT "outbox_events_pkey" PRIMARY KEY ("id")
|
|
19
|
+
);
|
|
20
|
+
-- il relay legge solo le righe non pubblicate, in ordine di id (UUID v7 = ordine di scrittura)
|
|
21
|
+
CREATE INDEX IF NOT EXISTS "outbox_events_published_at_id_idx" ON "outbox_events" ("published_at", "id");
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS "inbox_processed" (
|
|
24
|
+
"consumer" TEXT NOT NULL,
|
|
25
|
+
"event_id" UUID NOT NULL,
|
|
26
|
+
"processed_at" TIMESTAMPTZ(3) NOT NULL DEFAULT now(),
|
|
27
|
+
CONSTRAINT "inbox_processed_consumer_event_id_pk" PRIMARY KEY ("consumer", "event_id")
|
|
28
|
+
);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS "inbox_processed_processed_at_idx" ON "inbox_processed" ("processed_at");
|