@entifix/mongo 0.1.1 → 0.1.3
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 +4 -4
- package/dist/saga/store.d.ts +24 -0
- package/dist/saga/store.d.ts.map +1 -0
- package/dist/saga/store.js +210 -0
- package/dist/saga/store.js.map +1 -0
- package/dist/transactions/index.d.ts +1 -0
- package/dist/transactions/index.d.ts.map +1 -1
- package/dist/transactions/index.js +1 -0
- package/dist/transactions/index.js.map +1 -1
- package/package.json +6 -10
package/README.md
CHANGED
|
@@ -12,10 +12,10 @@ pnpm add @entifix/mongo effect
|
|
|
12
12
|
|
|
13
13
|
## Entry points
|
|
14
14
|
|
|
15
|
-
| Import | What it holds
|
|
16
|
-
| ----------------------------- |
|
|
17
|
-
| `@entifix/mongo` | Repository, link resolver, query translation, client and database Layers, tenant resolver, health probe
|
|
18
|
-
| `@entifix/mongo/transactions` | Transactional outbox and inbox for `@entifix/transactions`,
|
|
15
|
+
| Import | What it holds |
|
|
16
|
+
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| `@entifix/mongo` | Repository, link resolver, query translation, client and database Layers, tenant resolver, health probe |
|
|
18
|
+
| `@entifix/mongo/transactions` | Transactional outbox and inbox for `@entifix/transactions`, the relay that drains the outbox, and the saga store (`makeMongoSagaStore`, `MongoSagaStoreLayer`) |
|
|
19
19
|
|
|
20
20
|
## Optional peers
|
|
21
21
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EntifixConnError } from '@entifix/core';
|
|
2
|
+
import { type SagaStore, SagaStoreTag } from '@entifix/transactions';
|
|
3
|
+
import { Effect, Layer } from 'effect';
|
|
4
|
+
import type { Db } from 'mongodb';
|
|
5
|
+
import { MongoDatabaseTag } from '../mongo-database/mongo-database.js';
|
|
6
|
+
/**
|
|
7
|
+
* Saga instances: one document per flow, the durable record a coordinator
|
|
8
|
+
* resumes from (r10c ADR 0055).
|
|
9
|
+
*/
|
|
10
|
+
export declare const SAGA_COLLECTION = "saga_instances";
|
|
11
|
+
/**
|
|
12
|
+
* A unique index on `sagaId`, so a resumed coordinator can never create a
|
|
13
|
+
* second instance for one flow, and `{ state, updatedAt }` for the sweep —
|
|
14
|
+
* without it every pass is a scan of every saga ever run, on a schedule.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ensureSagaIndexes: (db: Db) => Effect.Effect<void, EntifixConnError, never>;
|
|
17
|
+
/** {@link SagaStore} over one Mongo database. */
|
|
18
|
+
export declare const makeMongoSagaStore: (db: Db) => SagaStore;
|
|
19
|
+
/**
|
|
20
|
+
* Provides {@link SagaStoreTag} from the service's own database, creating the
|
|
21
|
+
* indexes first.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MongoSagaStoreLayer: Layer.Layer<SagaStoreTag, EntifixConnError, MongoDatabaseTag>;
|
|
24
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/saga/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAIL,KAAK,SAAS,EACd,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAahD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,EAAE,iDAUpC,CAAC;AAEL,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,GAAI,IAAI,EAAE,KAAG,SAoI3C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,+DAO/B,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { EntifixConnError } from '@entifix/core';
|
|
3
|
+
import { SagaStoreTag } from '@entifix/transactions';
|
|
4
|
+
import { Effect, Layer } from 'effect';
|
|
5
|
+
import { MongoDatabaseTag } from '../mongo-database/mongo-database.js';
|
|
6
|
+
/**
|
|
7
|
+
* Saga instances: one document per flow, the durable record a coordinator
|
|
8
|
+
* resumes from (r10c ADR 0055).
|
|
9
|
+
*/ export const SAGA_COLLECTION = 'saga_instances';
|
|
10
|
+
/** The two states a sweep treats as unfinished. */ const UNFINISHED = [
|
|
11
|
+
'RUNNING',
|
|
12
|
+
'COMPENSATING'
|
|
13
|
+
];
|
|
14
|
+
const failed = (message, sagaId)=>(error)=>new EntifixConnError(message, error, {
|
|
15
|
+
sagaId
|
|
16
|
+
});
|
|
17
|
+
const sagaCollection = (db)=>db.collection(SAGA_COLLECTION);
|
|
18
|
+
const deadline = (olderThanMs)=>new Date(Date.now() - olderThanMs).toISOString();
|
|
19
|
+
/**
|
|
20
|
+
* A unique index on `sagaId`, so a resumed coordinator can never create a
|
|
21
|
+
* second instance for one flow, and `{ state, updatedAt }` for the sweep —
|
|
22
|
+
* without it every pass is a scan of every saga ever run, on a schedule.
|
|
23
|
+
*/ export const ensureSagaIndexes = (db)=>Effect.tryPromise({
|
|
24
|
+
try: async ()=>{
|
|
25
|
+
await sagaCollection(db).createIndex({
|
|
26
|
+
sagaId: 1
|
|
27
|
+
}, {
|
|
28
|
+
unique: true
|
|
29
|
+
});
|
|
30
|
+
await sagaCollection(db).createIndex({
|
|
31
|
+
state: 1,
|
|
32
|
+
updatedAt: 1
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
catch: (error)=>new EntifixConnError('Failed to ensure saga indexes', error, {
|
|
36
|
+
database: db.databaseName
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
/** {@link SagaStore} over one Mongo database. */ export const makeMongoSagaStore = (db)=>{
|
|
40
|
+
const collection = sagaCollection(db);
|
|
41
|
+
const stamp = ()=>new Date().toISOString();
|
|
42
|
+
return {
|
|
43
|
+
start: (instance)=>Effect.tryPromise({
|
|
44
|
+
try: async ()=>{
|
|
45
|
+
// `$setOnInsert` with an upsert rather than `insertOne`: a coordinator
|
|
46
|
+
// restarted mid-flight re-enters with an id it already wrote, and
|
|
47
|
+
// refusing that would turn a recoverable resume into a hard failure.
|
|
48
|
+
await collection.updateOne({
|
|
49
|
+
sagaId: instance.sagaId
|
|
50
|
+
}, {
|
|
51
|
+
$setOnInsert: _extends({}, instance, {
|
|
52
|
+
updatedAt: stamp()
|
|
53
|
+
})
|
|
54
|
+
}, {
|
|
55
|
+
upsert: true
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
catch: failed('Failed to start the saga instance', instance.sagaId)
|
|
59
|
+
}),
|
|
60
|
+
beginStep: (sagaId, stepIndex)=>Effect.tryPromise({
|
|
61
|
+
try: async ()=>{
|
|
62
|
+
await collection.updateOne({
|
|
63
|
+
sagaId
|
|
64
|
+
}, {
|
|
65
|
+
$set: {
|
|
66
|
+
stepIndex,
|
|
67
|
+
updatedAt: stamp()
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
catch: failed('Failed to record the step transition', sagaId)
|
|
72
|
+
}),
|
|
73
|
+
recordOutcome: (sagaId, outcome)=>Effect.tryPromise({
|
|
74
|
+
try: async ()=>{
|
|
75
|
+
await collection.updateOne({
|
|
76
|
+
sagaId
|
|
77
|
+
}, // `$push`, never a read-modify-write of the array: two outcomes
|
|
78
|
+
// recorded from one process would otherwise lose one another, and a
|
|
79
|
+
// lost outcome is a compensation that cannot address what it undoes.
|
|
80
|
+
{
|
|
81
|
+
$push: {
|
|
82
|
+
outcomes: outcome
|
|
83
|
+
},
|
|
84
|
+
$set: {
|
|
85
|
+
updatedAt: stamp()
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
catch: failed('Failed to record the step outcome', sagaId)
|
|
90
|
+
}),
|
|
91
|
+
settle: (sagaId, state, error)=>Effect.tryPromise({
|
|
92
|
+
try: async ()=>{
|
|
93
|
+
await collection.updateOne({
|
|
94
|
+
sagaId
|
|
95
|
+
}, {
|
|
96
|
+
$set: {
|
|
97
|
+
state,
|
|
98
|
+
error,
|
|
99
|
+
updatedAt: stamp()
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
catch: failed('Failed to settle the saga instance', sagaId)
|
|
104
|
+
}),
|
|
105
|
+
/**
|
|
106
|
+
* Take ownership of a stale instance, or answer `undefined`.
|
|
107
|
+
*
|
|
108
|
+
* ⚠️ **One conditional write, not a read and then a write.** The filter
|
|
109
|
+
* repeats `findStale`'s predicate, so two sweepers racing the same instance
|
|
110
|
+
* produce one winner: the loser's filter no longer matches because the
|
|
111
|
+
* winner re-stamped `updatedAt`. That stamp is also what stops the next tick
|
|
112
|
+
* finding the instance this sweep is still working on.
|
|
113
|
+
*/ claimForResume: (sagaId, olderThanMs)=>Effect.tryPromise({
|
|
114
|
+
try: async ()=>{
|
|
115
|
+
const claimed = await collection.findOneAndUpdate({
|
|
116
|
+
sagaId,
|
|
117
|
+
state: {
|
|
118
|
+
$in: [
|
|
119
|
+
...UNFINISHED
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
updatedAt: {
|
|
123
|
+
$lt: deadline(olderThanMs)
|
|
124
|
+
}
|
|
125
|
+
}, {
|
|
126
|
+
$inc: {
|
|
127
|
+
resumeAttempts: 1
|
|
128
|
+
},
|
|
129
|
+
$set: {
|
|
130
|
+
updatedAt: stamp()
|
|
131
|
+
}
|
|
132
|
+
}, {
|
|
133
|
+
returnDocument: 'after',
|
|
134
|
+
projection: {
|
|
135
|
+
_id: 0
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return claimed != null ? claimed : undefined;
|
|
139
|
+
},
|
|
140
|
+
catch: failed('Failed to claim the saga instance', sagaId)
|
|
141
|
+
}),
|
|
142
|
+
/**
|
|
143
|
+
* Flag one step's calls as given back, addressing the outcome by its step
|
|
144
|
+
* id: outcomes are `$push`ed, so an index is a fact about arrival order and
|
|
145
|
+
* a resumed walk must not depend on one.
|
|
146
|
+
*/ markCompensated: (sagaId, stepId)=>Effect.tryPromise({
|
|
147
|
+
try: async ()=>{
|
|
148
|
+
await collection.updateOne({
|
|
149
|
+
sagaId
|
|
150
|
+
}, {
|
|
151
|
+
$set: {
|
|
152
|
+
'outcomes.$[entry].compensated': true,
|
|
153
|
+
updatedAt: stamp()
|
|
154
|
+
}
|
|
155
|
+
}, {
|
|
156
|
+
arrayFilters: [
|
|
157
|
+
{
|
|
158
|
+
'entry.stepId': stepId
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
catch: failed('Failed to mark the step compensated', sagaId)
|
|
164
|
+
}),
|
|
165
|
+
get: (sagaId)=>Effect.tryPromise({
|
|
166
|
+
try: async ()=>{
|
|
167
|
+
var _ref;
|
|
168
|
+
return (_ref = await collection.findOne({
|
|
169
|
+
sagaId
|
|
170
|
+
}, {
|
|
171
|
+
projection: {
|
|
172
|
+
_id: 0
|
|
173
|
+
}
|
|
174
|
+
})) != null ? _ref : undefined;
|
|
175
|
+
},
|
|
176
|
+
catch: failed('Failed to read the saga instance', sagaId)
|
|
177
|
+
}),
|
|
178
|
+
/**
|
|
179
|
+
* Instances stuck mid-flight past a deadline. ⚠️ `COMPENSATING` counts: a
|
|
180
|
+
* coordinator that died while unwinding is the state that leaves holds in
|
|
181
|
+
* place, and the one an operator most needs to find.
|
|
182
|
+
*/ findStale: (olderThanMs)=>Effect.tryPromise({
|
|
183
|
+
try: async ()=>await collection.find({
|
|
184
|
+
state: {
|
|
185
|
+
$in: [
|
|
186
|
+
...UNFINISHED
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
updatedAt: {
|
|
190
|
+
$lt: deadline(olderThanMs)
|
|
191
|
+
}
|
|
192
|
+
}, {
|
|
193
|
+
projection: {
|
|
194
|
+
_id: 0
|
|
195
|
+
}
|
|
196
|
+
}).toArray(),
|
|
197
|
+
catch: failed('Failed to find stale saga instances', '')
|
|
198
|
+
})
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Provides {@link SagaStoreTag} from the service's own database, creating the
|
|
203
|
+
* indexes first.
|
|
204
|
+
*/ export const MongoSagaStoreLayer = Layer.effect(SagaStoreTag, Effect.gen(function*() {
|
|
205
|
+
const db = yield* MongoDatabaseTag;
|
|
206
|
+
yield* ensureSagaIndexes(db);
|
|
207
|
+
return makeMongoSagaStore(db);
|
|
208
|
+
}));
|
|
209
|
+
|
|
210
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/saga/store.ts"],"sourcesContent":["import { EntifixConnError } from '@entifix/core';\nimport {\n type SagaInstance,\n type SagaState,\n type SagaStepOutcome,\n type SagaStore,\n SagaStoreTag,\n} from '@entifix/transactions';\nimport { Effect, Layer } from 'effect';\nimport type { Db } from 'mongodb';\n\nimport { MongoDatabaseTag } from '../mongo-database/mongo-database.js';\n\n/**\n * Saga instances: one document per flow, the durable record a coordinator\n * resumes from (r10c ADR 0055).\n */\nexport const SAGA_COLLECTION = 'saga_instances';\n\n/** The two states a sweep treats as unfinished. */\nconst UNFINISHED: readonly SagaState[] = ['RUNNING', 'COMPENSATING'];\n\nconst failed = (message: string, sagaId: string) => (error: unknown) =>\n new EntifixConnError(message, error, { sagaId });\n\nconst sagaCollection = (db: Db) => db.collection<SagaInstance>(SAGA_COLLECTION);\n\nconst deadline = (olderThanMs: number) =>\n new Date(Date.now() - olderThanMs).toISOString();\n\n/**\n * A unique index on `sagaId`, so a resumed coordinator can never create a\n * second instance for one flow, and `{ state, updatedAt }` for the sweep —\n * without it every pass is a scan of every saga ever run, on a schedule.\n */\nexport const ensureSagaIndexes = (db: Db) =>\n Effect.tryPromise({\n try: async () => {\n await sagaCollection(db).createIndex({ sagaId: 1 }, { unique: true });\n await sagaCollection(db).createIndex({ state: 1, updatedAt: 1 });\n },\n catch: error =>\n new EntifixConnError('Failed to ensure saga indexes', error, {\n database: db.databaseName,\n }),\n });\n\n/** {@link SagaStore} over one Mongo database. */\nexport const makeMongoSagaStore = (db: Db): SagaStore => {\n const collection = sagaCollection(db);\n const stamp = () => new Date().toISOString();\n\n return {\n start: instance =>\n Effect.tryPromise({\n try: async () => {\n // `$setOnInsert` with an upsert rather than `insertOne`: a coordinator\n // restarted mid-flight re-enters with an id it already wrote, and\n // refusing that would turn a recoverable resume into a hard failure.\n await collection.updateOne(\n { sagaId: instance.sagaId },\n { $setOnInsert: { ...instance, updatedAt: stamp() } },\n { upsert: true },\n );\n },\n catch: failed('Failed to start the saga instance', instance.sagaId),\n }),\n\n beginStep: (sagaId, stepIndex) =>\n Effect.tryPromise({\n try: async () => {\n await collection.updateOne(\n { sagaId },\n { $set: { stepIndex, updatedAt: stamp() } },\n );\n },\n catch: failed('Failed to record the step transition', sagaId),\n }),\n\n recordOutcome: (sagaId, outcome: SagaStepOutcome) =>\n Effect.tryPromise({\n try: async () => {\n await collection.updateOne(\n { sagaId },\n // `$push`, never a read-modify-write of the array: two outcomes\n // recorded from one process would otherwise lose one another, and a\n // lost outcome is a compensation that cannot address what it undoes.\n { $push: { outcomes: outcome }, $set: { updatedAt: stamp() } },\n );\n },\n catch: failed('Failed to record the step outcome', sagaId),\n }),\n\n settle: (sagaId, state, error) =>\n Effect.tryPromise({\n try: async () => {\n await collection.updateOne(\n { sagaId },\n { $set: { state, error, updatedAt: stamp() } },\n );\n },\n catch: failed('Failed to settle the saga instance', sagaId),\n }),\n\n /**\n * Take ownership of a stale instance, or answer `undefined`.\n *\n * ⚠️ **One conditional write, not a read and then a write.** The filter\n * repeats `findStale`'s predicate, so two sweepers racing the same instance\n * produce one winner: the loser's filter no longer matches because the\n * winner re-stamped `updatedAt`. That stamp is also what stops the next tick\n * finding the instance this sweep is still working on.\n */\n claimForResume: (sagaId, olderThanMs) =>\n Effect.tryPromise({\n try: async () => {\n const claimed = await collection.findOneAndUpdate(\n {\n sagaId,\n state: { $in: [...UNFINISHED] },\n updatedAt: { $lt: deadline(olderThanMs) },\n },\n { $inc: { resumeAttempts: 1 }, $set: { updatedAt: stamp() } },\n { returnDocument: 'after', projection: { _id: 0 } },\n );\n return (claimed ?? undefined) as SagaInstance | undefined;\n },\n catch: failed('Failed to claim the saga instance', sagaId),\n }),\n\n /**\n * Flag one step's calls as given back, addressing the outcome by its step\n * id: outcomes are `$push`ed, so an index is a fact about arrival order and\n * a resumed walk must not depend on one.\n */\n markCompensated: (sagaId, stepId) =>\n Effect.tryPromise({\n try: async () => {\n await collection.updateOne(\n { sagaId },\n {\n $set: {\n 'outcomes.$[entry].compensated': true,\n updatedAt: stamp(),\n },\n },\n { arrayFilters: [{ 'entry.stepId': stepId }] },\n );\n },\n catch: failed('Failed to mark the step compensated', sagaId),\n }),\n\n get: sagaId =>\n Effect.tryPromise({\n try: async () =>\n ((await collection.findOne({ sagaId }, { projection: { _id: 0 } })) ??\n undefined) as SagaInstance | undefined,\n catch: failed('Failed to read the saga instance', sagaId),\n }),\n\n /**\n * Instances stuck mid-flight past a deadline. ⚠️ `COMPENSATING` counts: a\n * coordinator that died while unwinding is the state that leaves holds in\n * place, and the one an operator most needs to find.\n */\n findStale: olderThanMs =>\n Effect.tryPromise({\n try: async () =>\n (await collection\n .find(\n {\n state: { $in: [...UNFINISHED] },\n updatedAt: { $lt: deadline(olderThanMs) },\n },\n { projection: { _id: 0 } },\n )\n .toArray()) as SagaInstance[],\n catch: failed('Failed to find stale saga instances', ''),\n }),\n };\n};\n\n/**\n * Provides {@link SagaStoreTag} from the service's own database, creating the\n * indexes first.\n */\nexport const MongoSagaStoreLayer = Layer.effect(\n SagaStoreTag,\n Effect.gen(function* () {\n const db = yield* MongoDatabaseTag;\n yield* ensureSagaIndexes(db);\n return makeMongoSagaStore(db);\n }),\n);\n"],"names":["EntifixConnError","SagaStoreTag","Effect","Layer","MongoDatabaseTag","SAGA_COLLECTION","UNFINISHED","failed","message","sagaId","error","sagaCollection","db","collection","deadline","olderThanMs","Date","now","toISOString","ensureSagaIndexes","tryPromise","try","createIndex","unique","state","updatedAt","catch","database","databaseName","makeMongoSagaStore","stamp","start","instance","updateOne","$setOnInsert","upsert","beginStep","stepIndex","$set","recordOutcome","outcome","$push","outcomes","settle","claimForResume","claimed","findOneAndUpdate","$in","$lt","$inc","resumeAttempts","returnDocument","projection","_id","undefined","markCompensated","stepId","arrayFilters","get","findOne","findStale","find","toArray","MongoSagaStoreLayer","effect","gen"],"mappings":";AAAA,SAASA,gBAAgB,QAAQ,gBAAgB;AACjD,SAKEC,YAAY,QACP,wBAAwB;AAC/B,SAASC,MAAM,EAAEC,KAAK,QAAQ,SAAS;AAGvC,SAASC,gBAAgB,QAAQ,sCAAsC;AAEvE;;;CAGC,GACD,OAAO,MAAMC,kBAAkB,iBAAiB;AAEhD,iDAAiD,GACjD,MAAMC,aAAmC;IAAC;IAAW;CAAe;AAEpE,MAAMC,SAAS,CAACC,SAAiBC,SAAmB,CAACC,QACnD,IAAIV,iBAAiBQ,SAASE,OAAO;YAAED;QAAO;AAEhD,MAAME,iBAAiB,CAACC,KAAWA,GAAGC,UAAU,CAAeR;AAE/D,MAAMS,WAAW,CAACC,cAChB,IAAIC,KAAKA,KAAKC,GAAG,KAAKF,aAAaG,WAAW;AAEhD;;;;CAIC,GACD,OAAO,MAAMC,oBAAoB,CAACP,KAChCV,OAAOkB,UAAU,CAAC;QAChBC,KAAK;YACH,MAAMV,eAAeC,IAAIU,WAAW,CAAC;gBAAEb,QAAQ;YAAE,GAAG;gBAAEc,QAAQ;YAAK;YACnE,MAAMZ,eAAeC,IAAIU,WAAW,CAAC;gBAAEE,OAAO;gBAAGC,WAAW;YAAE;QAChE;QACAC,OAAOhB,CAAAA,QACL,IAAIV,iBAAiB,iCAAiCU,OAAO;gBAC3DiB,UAAUf,GAAGgB,YAAY;YAC3B;IACJ,GAAG;AAEL,+CAA+C,GAC/C,OAAO,MAAMC,qBAAqB,CAACjB;IACjC,MAAMC,aAAaF,eAAeC;IAClC,MAAMkB,QAAQ,IAAM,IAAId,OAAOE,WAAW;IAE1C,OAAO;QACLa,OAAOC,CAAAA,WACL9B,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,uEAAuE;oBACvE,kEAAkE;oBAClE,qEAAqE;oBACrE,MAAMR,WAAWoB,SAAS,CACxB;wBAAExB,QAAQuB,SAASvB,MAAM;oBAAC,GAC1B;wBAAEyB,cAAc,aAAKF;4BAAUP,WAAWK;;oBAAU,GACpD;wBAAEK,QAAQ;oBAAK;gBAEnB;gBACAT,OAAOnB,OAAO,qCAAqCyB,SAASvB,MAAM;YACpE;QAEF2B,WAAW,CAAC3B,QAAQ4B,YAClBnC,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,MAAMR,WAAWoB,SAAS,CACxB;wBAAExB;oBAAO,GACT;wBAAE6B,MAAM;4BAAED;4BAAWZ,WAAWK;wBAAQ;oBAAE;gBAE9C;gBACAJ,OAAOnB,OAAO,wCAAwCE;YACxD;QAEF8B,eAAe,CAAC9B,QAAQ+B,UACtBtC,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,MAAMR,WAAWoB,SAAS,CACxB;wBAAExB;oBAAO,GACT,gEAAgE;oBAChE,oEAAoE;oBACpE,qEAAqE;oBACrE;wBAAEgC,OAAO;4BAAEC,UAAUF;wBAAQ;wBAAGF,MAAM;4BAAEb,WAAWK;wBAAQ;oBAAE;gBAEjE;gBACAJ,OAAOnB,OAAO,qCAAqCE;YACrD;QAEFkC,QAAQ,CAAClC,QAAQe,OAAOd,QACtBR,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,MAAMR,WAAWoB,SAAS,CACxB;wBAAExB;oBAAO,GACT;wBAAE6B,MAAM;4BAAEd;4BAAOd;4BAAOe,WAAWK;wBAAQ;oBAAE;gBAEjD;gBACAJ,OAAOnB,OAAO,sCAAsCE;YACtD;QAEF;;;;;;;;KAQC,GACDmC,gBAAgB,CAACnC,QAAQM,cACvBb,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,MAAMwB,UAAU,MAAMhC,WAAWiC,gBAAgB,CAC/C;wBACErC;wBACAe,OAAO;4BAAEuB,KAAK;mCAAIzC;6BAAW;wBAAC;wBAC9BmB,WAAW;4BAAEuB,KAAKlC,SAASC;wBAAa;oBAC1C,GACA;wBAAEkC,MAAM;4BAAEC,gBAAgB;wBAAE;wBAAGZ,MAAM;4BAAEb,WAAWK;wBAAQ;oBAAE,GAC5D;wBAAEqB,gBAAgB;wBAASC,YAAY;4BAAEC,KAAK;wBAAE;oBAAE;oBAEpD,OAAQR,kBAAAA,UAAWS;gBACrB;gBACA5B,OAAOnB,OAAO,qCAAqCE;YACrD;QAEF;;;;KAIC,GACD8C,iBAAiB,CAAC9C,QAAQ+C,SACxBtD,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;oBACH,MAAMR,WAAWoB,SAAS,CACxB;wBAAExB;oBAAO,GACT;wBACE6B,MAAM;4BACJ,iCAAiC;4BACjCb,WAAWK;wBACb;oBACF,GACA;wBAAE2B,cAAc;4BAAC;gCAAE,gBAAgBD;4BAAO;yBAAE;oBAAC;gBAEjD;gBACA9B,OAAOnB,OAAO,uCAAuCE;YACvD;QAEFiD,KAAKjD,CAAAA,SACHP,OAAOkB,UAAU,CAAC;gBAChBC,KAAK;wBACD;4BAAA,OAAA,MAAMR,WAAW8C,OAAO,CAAC;wBAAElD;oBAAO,GAAG;wBAAE2C,YAAY;4BAAEC,KAAK;wBAAE;oBAAE,cAA9D,OACAC;;gBACJ5B,OAAOnB,OAAO,oCAAoCE;YACpD;QAEF;;;;KAIC,GACDmD,WAAW7C,CAAAA,cACTb,OAAOkB,UAAU,CAAC;gBAChBC,KAAK,UACF,MAAMR,WACJgD,IAAI,CACH;wBACErC,OAAO;4BAAEuB,KAAK;mCAAIzC;6BAAW;wBAAC;wBAC9BmB,WAAW;4BAAEuB,KAAKlC,SAASC;wBAAa;oBAC1C,GACA;wBAAEqC,YAAY;4BAAEC,KAAK;wBAAE;oBAAE,GAE1BS,OAAO;gBACZpC,OAAOnB,OAAO,uCAAuC;YACvD;IACJ;AACF,EAAE;AAEF;;;CAGC,GACD,OAAO,MAAMwD,sBAAsB5D,MAAM6D,MAAM,CAC7C/D,cACAC,OAAO+D,GAAG,CAAC;IACT,MAAMrD,KAAK,OAAOR;IAClB,OAAOe,kBAAkBP;IACzB,OAAOiB,mBAAmBjB;AAC5B,IACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transactions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transactions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/transactions/index.ts"],"sourcesContent":["/**\n * The half of this package that needs `@entifix/transactions`: the\n * transactional outbox ADR 0028 writes inside the entity's own Mongo\n * transaction, and the inbox that makes a redelivered command idempotent.\n *\n * Behind a subpath so entity CRUD over Mongo does not arrive with the saga\n * engine attached. Package-level dependencies are not per-subpath, so what\n * actually keeps it optional is the `peerDependenciesMeta.optional` entry in\n * the manifest — importing this module without that peer installed is the\n * error, and it is the adopter's to make deliberately.\n */\nexport * from '../inbox/store.js';\nexport * from '../outbox/metrics.js';\nexport * from '../outbox/relay.js';\nexport * from '../outbox/store.js';\n"],"names":[],"mappings":"AAAA;;;;;;;;;;CAUC,GACD,cAAc,oBAAoB;AAClC,cAAc,uBAAuB;AACrC,cAAc,qBAAqB;AACnC,cAAc,qBAAqB"}
|
|
1
|
+
{"version":3,"sources":["../../src/transactions/index.ts"],"sourcesContent":["/**\n * The half of this package that needs `@entifix/transactions`: the\n * transactional outbox ADR 0028 writes inside the entity's own Mongo\n * transaction, and the inbox that makes a redelivered command idempotent.\n *\n * Behind a subpath so entity CRUD over Mongo does not arrive with the saga\n * engine attached. Package-level dependencies are not per-subpath, so what\n * actually keeps it optional is the `peerDependenciesMeta.optional` entry in\n * the manifest — importing this module without that peer installed is the\n * error, and it is the adopter's to make deliberately.\n */\nexport * from '../inbox/store.js';\nexport * from '../outbox/metrics.js';\nexport * from '../outbox/relay.js';\nexport * from '../outbox/store.js';\nexport * from '../saga/store.js';\n"],"names":[],"mappings":"AAAA;;;;;;;;;;CAUC,GACD,cAAc,oBAAoB;AAClC,cAAc,uBAAuB;AACrC,cAAc,qBAAqB;AACnC,cAAc,qBAAqB;AACnC,cAAc,mBAAmB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entifix/mongo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "MongoDB adapter: an entity repository, RSQL-to-Mongo query translation, per-tenant databases, and an optional transactional outbox.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,10 +37,6 @@
|
|
|
37
37
|
],
|
|
38
38
|
"nx": {
|
|
39
39
|
"tags": [
|
|
40
|
-
"layer:entifix",
|
|
41
|
-
"scope:shared",
|
|
42
|
-
"entifix:client",
|
|
43
|
-
"runtime:datastore",
|
|
44
40
|
"tier:2"
|
|
45
41
|
],
|
|
46
42
|
"sourceRoot": "packages/ts/mongo-client/src",
|
|
@@ -63,17 +59,17 @@
|
|
|
63
59
|
"dependencies": {
|
|
64
60
|
"@swc/helpers": "0.5.23",
|
|
65
61
|
"mongodb": "7.5.0",
|
|
66
|
-
"@entifix/
|
|
67
|
-
"@entifix/
|
|
62
|
+
"@entifix/business": "0.1.3",
|
|
63
|
+
"@entifix/core": "0.1.3"
|
|
68
64
|
},
|
|
69
65
|
"devDependencies": {
|
|
70
66
|
"effect": "3.22.1",
|
|
71
|
-
"@entifix/transactions": "0.1.
|
|
72
|
-
"@entifix/testing-unit": "0.1.
|
|
67
|
+
"@entifix/transactions": "0.1.3",
|
|
68
|
+
"@entifix/testing-unit": "0.1.3"
|
|
73
69
|
},
|
|
74
70
|
"peerDependencies": {
|
|
75
71
|
"effect": ">=3.22 <4",
|
|
76
|
-
"@entifix/transactions": "0.1.
|
|
72
|
+
"@entifix/transactions": "0.1.3"
|
|
77
73
|
},
|
|
78
74
|
"peerDependenciesMeta": {
|
|
79
75
|
"@entifix/transactions": {
|