@entifix/mongo 0.9.0 → 0.10.1

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 (54) hide show
  1. package/dist/adapters/make-mongo-facet-counter.d.ts.map +1 -1
  2. package/dist/adapters/make-mongo-facet-counter.js +3 -4
  3. package/dist/adapters/make-mongo-facet-counter.js.map +1 -1
  4. package/dist/adapters/make-mongo-link-resolver.d.ts.map +1 -1
  5. package/dist/adapters/make-mongo-link-resolver.js +2 -4
  6. package/dist/adapters/make-mongo-link-resolver.js.map +1 -1
  7. package/dist/adapters/make-mongo-repository.d.ts +3 -3
  8. package/dist/adapters/make-mongo-repository.d.ts.map +1 -1
  9. package/dist/adapters/make-mongo-repository.js +11 -18
  10. package/dist/adapters/make-mongo-repository.js.map +1 -1
  11. package/dist/adapters/mongo-facet-counter-factory.d.ts.map +1 -1
  12. package/dist/adapters/mongo-facet-counter-factory.js +2 -4
  13. package/dist/adapters/mongo-facet-counter-factory.js.map +1 -1
  14. package/dist/adapters/mongo-repository-factory.d.ts.map +1 -1
  15. package/dist/adapters/mongo-repository-factory.js +2 -4
  16. package/dist/adapters/mongo-repository-factory.js.map +1 -1
  17. package/dist/errors/translate-mongo-error.d.ts +30 -0
  18. package/dist/errors/translate-mongo-error.d.ts.map +1 -0
  19. package/dist/errors/translate-mongo-error.js +74 -0
  20. package/dist/errors/translate-mongo-error.js.map +1 -0
  21. package/dist/inbox/store.d.ts +1 -2
  22. package/dist/inbox/store.d.ts.map +1 -1
  23. package/dist/inbox/store.js +3 -8
  24. package/dist/inbox/store.js.map +1 -1
  25. package/dist/mongo-database/mongo-database.d.ts +3 -3
  26. package/dist/mongo-database/mongo-database.d.ts.map +1 -1
  27. package/dist/mongo-database/mongo-database.js +2 -2
  28. package/dist/mongo-database/mongo-database.js.map +1 -1
  29. package/dist/mongo-database/mongo-tenant-directory.d.ts.map +1 -1
  30. package/dist/mongo-database/mongo-tenant-directory.js +2 -4
  31. package/dist/mongo-database/mongo-tenant-directory.js.map +1 -1
  32. package/dist/mongo-database/mongo-tenant-resolver.d.ts.map +1 -1
  33. package/dist/mongo-database/mongo-tenant-resolver.js +18 -7
  34. package/dist/mongo-database/mongo-tenant-resolver.js.map +1 -1
  35. package/dist/outbox/relay.d.ts +50 -9
  36. package/dist/outbox/relay.d.ts.map +1 -1
  37. package/dist/outbox/relay.js +67 -26
  38. package/dist/outbox/relay.js.map +1 -1
  39. package/dist/outbox/store.d.ts +3 -3
  40. package/dist/outbox/store.d.ts.map +1 -1
  41. package/dist/outbox/store.js +8 -22
  42. package/dist/outbox/store.js.map +1 -1
  43. package/dist/saga/store.d.ts +3 -4
  44. package/dist/saga/store.d.ts.map +1 -1
  45. package/dist/saga/store.js +10 -15
  46. package/dist/saga/store.js.map +1 -1
  47. package/dist/unit-of-work/command-inbox.d.ts +2 -3
  48. package/dist/unit-of-work/command-inbox.d.ts.map +1 -1
  49. package/dist/unit-of-work/command-inbox.js +3 -7
  50. package/dist/unit-of-work/command-inbox.js.map +1 -1
  51. package/dist/unit-of-work/mongo-unit-of-work.d.ts.map +1 -1
  52. package/dist/unit-of-work/mongo-unit-of-work.js +30 -26
  53. package/dist/unit-of-work/mongo-unit-of-work.js.map +1 -1
  54. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/unit-of-work/mongo-unit-of-work.ts"],"sourcesContent":["import { type DomainEvent, EntifixConnError } from '@entifix/core';\nimport type {\n UnitClaim,\n UnitOfWork,\n UnitOutcome,\n UnitRunOptions,\n} from '@entifix/transactions';\nimport { Context, Effect, Layer, Option, Result, Schedule } from 'effect';\nimport type { ClientSession, Db } from 'mongodb';\n\nimport {\n ensureInboxIndexes,\n INBOX_COLLECTION,\n inboxDocument,\n isDuplicateKey,\n} from '../inbox/store.js';\nimport {\n MongoClientTag,\n MongoDatabaseTag,\n} from '../mongo-database/mongo-database.js';\nimport {\n ensureOutboxIndexes,\n OUTBOX_COLLECTION,\n outboxDocument,\n} from '../outbox/store.js';\nimport {\n COMMAND_INBOX_COLLECTION,\n commandClaimDocument,\n ensureCommandInboxIndexes,\n readCommandReplay,\n rememberCommandReplay,\n} from './command-inbox.js';\n\n/**\n * What a Mongo unit's body writes through: the database and the session bound\n * to the unit's transaction. Every write must pass `{ session }`, or it is not\n * part of the unit.\n */\nexport interface MongoUnit {\n readonly db: Db;\n readonly session: ClientSession;\n}\n\n/** What starts a session — a `MongoClient`, structurally. */\nexport interface MongoSessionSource {\n startSession(): ClientSession;\n}\n\n/**\n * How many times a unit runs before a transient conflict is reported as the\n * failure it is, and how long it waits between runs.\n *\n * Measured against a real replica set: eight units incrementing one document\n * at once conflict on every attempt but one, so a short fixed retry count\n * starves most of them. A jittered exponential back-off spreads the reruns so\n * each eventually runs alone.\n */\nconst ATTEMPTS = 10;\nconst BACK_OFF = Schedule.exponential('5 millis', 1.5).pipe(Schedule.jittered);\n\nconst hasErrorLabel = (error: unknown, label: string): boolean => {\n const candidate = error as {\n hasErrorLabel?: (label: string) => boolean;\n errorLabels?: readonly string[];\n } | null;\n return (\n candidate?.hasErrorLabel?.(label) ??\n candidate?.errorLabels?.includes(label) ??\n false\n );\n};\n\n/**\n * Whether a server label is on `error` or anywhere in its cause chain — a\n * driver error reaches here wrapped once by the adapter and possibly again by\n * the body that called the driver.\n */\nconst labelledInChain = (error: unknown, label: string): boolean => {\n let current: unknown = error;\n for (let depth = 0; current != null && depth < 5; depth += 1) {\n if (hasErrorLabel(current, label)) return true;\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n};\n\nconst isTransient = (error: unknown): boolean =>\n error instanceof EntifixConnError &&\n labelledInChain(error, 'TransientTransactionError');\n\nconst driver = <A>(\n message: string,\n run: () => Promise<A>,\n details?: Record<string, unknown>,\n) =>\n Effect.tryPromise({\n try: run,\n catch: error => new EntifixConnError(message, error, details),\n });\n\n/** A duplicate-key rejection answered as `duplicate` rather than as an error. */\nconst insertOrDuplicate = (\n message: string,\n run: () => Promise<unknown>,\n details?: Record<string, unknown>,\n) =>\n Effect.tryPromise({\n try: async () => {\n try {\n await run();\n return 'inserted' as const;\n } catch (error) {\n if (isDuplicateKey(error)) return 'duplicate' as const;\n throw error;\n }\n },\n catch: error => new EntifixConnError(message, error, details),\n });\n\nconst takeClaim = (db: Db, session: ClientSession, claim: UnitClaim) =>\n claim.kind === 'event'\n ? insertOrDuplicate(\n 'Failed to claim an event',\n () =>\n db\n .collection(INBOX_COLLECTION)\n .insertOne(inboxDocument(claim.consumer, claim.eventId), {\n session,\n }),\n { consumer: claim.consumer, eventId: claim.eventId },\n )\n : insertOrDuplicate(\n 'Failed to claim a command',\n () =>\n db\n .collection(COMMAND_INBOX_COLLECTION)\n .insertOne(commandClaimDocument(claim.commandId), { session }),\n { commandId: claim.commandId },\n );\n\n/**\n * Commits, retrying a commit whose result the server could not report. Such a\n * commit may or may not have applied, and Mongo makes retrying it safe.\n */\nconst commit = (session: ClientSession) =>\n driver('Failed to commit a unit of work', () =>\n session.commitTransaction(),\n ).pipe(\n Effect.retry({\n times: ATTEMPTS - 1,\n while: error => labelledInChain(error, 'UnknownTransactionCommitResult'),\n }),\n );\n\n/** Rolls back, and never fails: the unit is already ending for another reason. */\nconst abort = (session: ClientSession) =>\n driver('Failed to abort a unit of work', () =>\n session.abortTransaction(),\n ).pipe(Effect.ignore);\n\ntype Decision<A> =\n | { readonly kind: 'commit'; readonly value: A }\n | { readonly kind: 'duplicate' };\n\n/**\n * A {@link UnitOfWork} per database, sharing one client — the shape a\n * per-organization store needs, where the database is resolved inside the\n * request. Each database's indexes are ensured once, before its first unit.\n */\nexport const makeMongoUnitsOfWork = (client: MongoSessionSource) => {\n const ensured = new Map<string, Promise<void>>();\n\n const ensureIndexes = (db: Db) =>\n Effect.suspend(() => {\n const key = db.databaseName;\n const done = ensured.get(key);\n if (done !== undefined) {\n return driver('Failed to ensure unit-of-work indexes', () => done);\n }\n const pending = Effect.runPromise(\n Effect.all([\n ensureOutboxIndexes(db),\n ensureInboxIndexes(db),\n ensureCommandInboxIndexes(db),\n ]),\n ).then(() => undefined);\n ensured.set(key, pending);\n // A failed ensure must be retried by the next unit, not remembered.\n pending.catch(() => ensured.delete(key));\n return driver('Failed to ensure unit-of-work indexes', () => pending);\n });\n\n const forDatabase = (db: Db): UnitOfWork<MongoUnit> => {\n const attempt = <A, E, R>(\n body: (unit: {\n readonly handle: MongoUnit;\n emit(event: DomainEvent): void;\n }) => Effect.Effect<A, E, R>,\n options: UnitRunOptions<A, R> | undefined,\n ) =>\n Effect.acquireUseRelease(\n Effect.sync(() => client.startSession()),\n session =>\n Effect.gen(function* () {\n yield* Effect.try({\n try: () => session.startTransaction(),\n catch: error =>\n new EntifixConnError('Failed to start a unit of work', error),\n });\n\n const work = Effect.gen(function* () {\n const claim = options?.claim;\n if (\n claim &&\n (yield* takeClaim(db, session, claim)) === 'duplicate'\n ) {\n return { kind: 'duplicate' } as Decision<A>;\n }\n\n const emitted: DomainEvent[] = [];\n const value = yield* body({\n handle: { db, session },\n emit: event => void emitted.push(event),\n });\n\n if (emitted.length > 0) {\n const written = yield* insertOrDuplicate(\n 'Failed to record a unit of work’s events',\n () =>\n db\n .collection(OUTBOX_COLLECTION)\n .insertMany(emitted.map(outboxDocument), { session }),\n );\n // An event id already recorded is the outbox's own\n // idempotency claim: what it announces committed before.\n if (written === 'duplicate') {\n return { kind: 'duplicate' } as Decision<A>;\n }\n }\n\n if (claim?.kind === 'command' && options?.replay) {\n const replay = options.replay(value);\n yield* driver('Failed to remember a command’s answer', () =>\n rememberCommandReplay(db, session, claim.commandId, replay),\n );\n }\n return { kind: 'commit', value } as Decision<A>;\n });\n\n const decided = yield* Effect.result(work);\n\n if (Result.isFailure(decided)) {\n yield* abort(session);\n const failure = decided.failure;\n if (failure instanceof EntifixConnError) {\n return yield* Effect.fail(failure);\n }\n // A conflict the body surfaced without wrapping is still the\n // store's, not a business decision: it is retried, not aborted.\n if (labelledInChain(failure, 'TransientTransactionError')) {\n return yield* Effect.fail(\n new EntifixConnError(\n 'A unit of work hit a transient conflict',\n failure,\n ),\n );\n }\n return {\n _tag: 'aborted',\n reason: failure as Exclude<E, EntifixConnError>,\n } as UnitOutcome<A, Exclude<E, EntifixConnError>>;\n }\n\n if (decided.success.kind === 'duplicate') {\n yield* abort(session);\n const replay =\n options?.claim?.kind === 'command'\n ? yield* readCommandReplay(db, options.claim.commandId)\n : Option.none();\n return { _tag: 'duplicate', replay } as UnitOutcome<\n A,\n Exclude<E, EntifixConnError>\n >;\n }\n\n yield* commit(session);\n return {\n _tag: 'committed',\n value: decided.success.value,\n } as UnitOutcome<A, Exclude<E, EntifixConnError>>;\n }),\n session =>\n driver('Failed to end a session', () => session.endSession()).pipe(\n Effect.ignore,\n ),\n );\n\n return {\n run: (body, options) =>\n Effect.gen(function* () {\n yield* ensureIndexes(db);\n const outcome = yield* attempt(body, options).pipe(\n // The whole unit runs again, body included: that is why the body\n // must be retry-safe.\n Effect.retry({\n times: ATTEMPTS - 1,\n while: isTransient,\n schedule: BACK_OFF,\n }),\n );\n if (outcome._tag === 'committed' && options?.afterCommit) {\n yield* options.afterCommit.pipe(Effect.ignore);\n }\n return outcome;\n }),\n replay: commandId => readCommandReplay(db, commandId),\n };\n };\n\n return { forDatabase };\n};\n\n/** A {@link UnitOfWork} over one database. */\nexport const makeMongoUnitOfWork = (options: {\n readonly client: MongoSessionSource;\n readonly db: Db;\n}): UnitOfWork<MongoUnit> =>\n makeMongoUnitsOfWork(options.client).forDatabase(options.db);\n\n/** The unit of work over the service's own database. */\nexport class MongoUnitOfWorkTag extends Context.Service<\n MongoUnitOfWorkTag,\n UnitOfWork<MongoUnit>\n>()('MongoUnitOfWorkTag') {}\n\n/**\n * Provides {@link MongoUnitOfWorkTag} from the client and the named database\n * {@link MongoDatabaseLayer} opened.\n */\nexport const MongoUnitOfWorkLayer = Layer.effect(\n MongoUnitOfWorkTag,\n Effect.gen(function* () {\n const client = yield* MongoClientTag;\n const db = yield* MongoDatabaseTag;\n return makeMongoUnitOfWork({ client, db });\n }),\n);\n"],"names":["EntifixConnError","Context","Effect","Layer","Option","Result","Schedule","ensureInboxIndexes","INBOX_COLLECTION","inboxDocument","isDuplicateKey","MongoClientTag","MongoDatabaseTag","ensureOutboxIndexes","OUTBOX_COLLECTION","outboxDocument","COMMAND_INBOX_COLLECTION","commandClaimDocument","ensureCommandInboxIndexes","readCommandReplay","rememberCommandReplay","ATTEMPTS","BACK_OFF","exponential","pipe","jittered","hasErrorLabel","error","label","candidate","errorLabels","includes","labelledInChain","current","depth","cause","isTransient","driver","message","run","details","tryPromise","try","catch","insertOrDuplicate","takeClaim","db","session","claim","kind","collection","insertOne","consumer","eventId","commandId","commit","commitTransaction","retry","times","while","abort","abortTransaction","ignore","makeMongoUnitsOfWork","client","ensured","Map","ensureIndexes","suspend","key","databaseName","done","get","undefined","pending","runPromise","all","then","set","delete","forDatabase","attempt","body","options","acquireUseRelease","sync","startSession","gen","startTransaction","work","emitted","value","handle","emit","event","push","length","written","insertMany","map","replay","decided","result","isFailure","failure","fail","_tag","reason","success","none","endSession","outcome","schedule","afterCommit","makeMongoUnitOfWork","MongoUnitOfWorkTag","Service","MongoUnitOfWorkLayer","effect"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/unit-of-work/mongo-unit-of-work.ts"],"sourcesContent":["import {\n Contention,\n type DomainEvent,\n isFailure,\n isStoreFault,\n type StoreFault,\n} from '@entifix/core';\nimport type {\n UnitClaim,\n UnitOfWork,\n UnitOutcome,\n UnitRunOptions,\n} from '@entifix/transactions';\nimport { Context, Effect, Layer, Option, Result, Schedule } from 'effect';\nimport type { ClientSession, Db } from 'mongodb';\n\nimport { translateMongoFault } from '../errors/translate-mongo-error.js';\nimport {\n ensureInboxIndexes,\n INBOX_COLLECTION,\n inboxDocument,\n isDuplicateKey,\n} from '../inbox/store.js';\nimport {\n MongoClientTag,\n MongoDatabaseTag,\n} from '../mongo-database/mongo-database.js';\nimport {\n ensureOutboxIndexes,\n OUTBOX_COLLECTION,\n outboxDocument,\n} from '../outbox/store.js';\nimport {\n COMMAND_INBOX_COLLECTION,\n commandClaimDocument,\n ensureCommandInboxIndexes,\n readCommandReplay,\n rememberCommandReplay,\n} from './command-inbox.js';\n\n/**\n * What a Mongo unit's body writes through: the database and the session bound\n * to the unit's transaction. Every write must pass `{ session }`, or it is not\n * part of the unit.\n */\nexport interface MongoUnit {\n readonly db: Db;\n readonly session: ClientSession;\n}\n\n/** What starts a session — a `MongoClient`, structurally. */\nexport interface MongoSessionSource {\n startSession(): ClientSession;\n}\n\n/**\n * How many times a unit runs before a transient conflict is reported as the\n * failure it is, and how long it waits between runs.\n *\n * Measured against a real replica set: eight units incrementing one document\n * at once conflict on every attempt but one, so a short fixed retry count\n * starves most of them. A jittered exponential back-off spreads the reruns so\n * each eventually runs alone.\n */\nconst ATTEMPTS = 10;\nconst BACK_OFF = Schedule.exponential('5 millis', 1.5).pipe(Schedule.jittered);\n\nconst hasErrorLabel = (error: unknown, label: string): boolean => {\n const candidate = error as {\n hasErrorLabel?: (label: string) => boolean;\n errorLabels?: readonly string[];\n } | null;\n return (\n candidate?.hasErrorLabel?.(label) ??\n candidate?.errorLabels?.includes(label) ??\n false\n );\n};\n\n/**\n * Whether a server label is on `error` or anywhere in its cause chain — a\n * driver error reaches here wrapped once by the adapter and possibly again by\n * the body that called the driver.\n */\nconst labelledInChain = (error: unknown, label: string): boolean => {\n let current: unknown = error;\n for (let depth = 0; current != null && depth < 5; depth += 1) {\n if (hasErrorLabel(current, label)) return true;\n current = (current as { cause?: unknown }).cause;\n }\n return false;\n};\n\n/** A transient conflict, which reruns the whole unit. */\nconst isTransient = (error: unknown): boolean =>\n isFailure(error) && error._tag === 'Contention';\n\nconst fault = (error: unknown): StoreFault => translateMongoFault(error);\n\nconst driver = <A>(run: () => Promise<A>) =>\n Effect.tryPromise({ try: run, catch: fault });\n\n/** A duplicate-key rejection answered as `duplicate` rather than as an error. */\nconst insertOrDuplicate = (run: () => Promise<unknown>) =>\n Effect.tryPromise({\n try: async () => {\n try {\n await run();\n return 'inserted' as const;\n } catch (error) {\n if (isDuplicateKey(error)) return 'duplicate' as const;\n throw error;\n }\n },\n catch: fault,\n });\n\nconst takeClaim = (db: Db, session: ClientSession, claim: UnitClaim) =>\n claim.kind === 'event'\n ? insertOrDuplicate(() =>\n db\n .collection(INBOX_COLLECTION)\n .insertOne(inboxDocument(claim.consumer, claim.eventId), {\n session,\n }),\n )\n : insertOrDuplicate(() =>\n db\n .collection(COMMAND_INBOX_COLLECTION)\n .insertOne(commandClaimDocument(claim.commandId), { session }),\n );\n\n/**\n * Commits, retrying a commit whose result the server could not report. Such a\n * commit may or may not have applied, and Mongo makes retrying it safe.\n */\n/**\n * Retried on the **driver's** error, before translation: the label that says\n * the commit's result is unknown lives on it, and a translated failure no\n * longer carries it.\n */\nconst commit = (session: ClientSession) =>\n Effect.tryPromise({\n try: () => session.commitTransaction(),\n catch: error => error,\n }).pipe(\n Effect.retry({\n times: ATTEMPTS - 1,\n while: error => labelledInChain(error, 'UnknownTransactionCommitResult'),\n }),\n Effect.mapError(fault),\n );\n\n/** Rolls back, and never fails: the unit is already ending for another reason. */\nconst abort = (session: ClientSession) =>\n driver(() => session.abortTransaction()).pipe(Effect.ignore);\n\ntype Decision<A> =\n | { readonly kind: 'commit'; readonly value: A }\n | { readonly kind: 'duplicate' };\n\n/**\n * A {@link UnitOfWork} per database, sharing one client — the shape a\n * per-organization store needs, where the database is resolved inside the\n * request. Each database's indexes are ensured once, before its first unit.\n */\nexport const makeMongoUnitsOfWork = (client: MongoSessionSource) => {\n const ensured = new Map<string, Promise<void>>();\n\n const ensureIndexes = (db: Db) =>\n Effect.suspend(() => {\n const key = db.databaseName;\n const done = ensured.get(key);\n if (done !== undefined) {\n return driver(() => done);\n }\n const pending = Effect.runPromise(\n Effect.all([\n ensureOutboxIndexes(db),\n ensureInboxIndexes(db),\n ensureCommandInboxIndexes(db),\n ]),\n ).then(() => undefined);\n ensured.set(key, pending);\n // A failed ensure must be retried by the next unit, not remembered.\n pending.catch(() => ensured.delete(key));\n return driver(() => pending);\n });\n\n const forDatabase = (db: Db): UnitOfWork<MongoUnit> => {\n const attempt = <A, E, R>(\n body: (unit: {\n readonly handle: MongoUnit;\n emit(event: DomainEvent): void;\n }) => Effect.Effect<A, E, R>,\n options: UnitRunOptions<A, R> | undefined,\n ) =>\n Effect.acquireUseRelease(\n Effect.sync(() => client.startSession()),\n session =>\n Effect.gen(function* () {\n yield* Effect.try({\n try: () => session.startTransaction(),\n catch: fault,\n });\n\n const work = Effect.gen(function* () {\n const claim = options?.claim;\n if (\n claim &&\n (yield* takeClaim(db, session, claim)) === 'duplicate'\n ) {\n return { kind: 'duplicate' } as Decision<A>;\n }\n\n const emitted: DomainEvent[] = [];\n const value = yield* body({\n handle: { db, session },\n emit: event => void emitted.push(event),\n });\n\n if (emitted.length > 0) {\n const written = yield* insertOrDuplicate(() =>\n db\n .collection(OUTBOX_COLLECTION)\n .insertMany(emitted.map(outboxDocument), { session }),\n );\n // An event id already recorded is the outbox's own\n // idempotency claim: what it announces committed before.\n if (written === 'duplicate') {\n return { kind: 'duplicate' } as Decision<A>;\n }\n }\n\n if (claim?.kind === 'command' && options?.replay) {\n const replay = options.replay(value);\n yield* driver(() =>\n rememberCommandReplay(db, session, claim.commandId, replay),\n );\n }\n return { kind: 'commit', value } as Decision<A>;\n });\n\n const decided = yield* Effect.result(work);\n\n if (Result.isFailure(decided)) {\n yield* abort(session);\n const failure = decided.failure;\n if (isStoreFault(failure)) {\n return yield* Effect.fail(failure);\n }\n // A conflict the body surfaced without translating is still the\n // store's, not a business decision: it is retried, not aborted.\n if (labelledInChain(failure, 'TransientTransactionError')) {\n return yield* Effect.fail(new Contention());\n }\n return {\n _tag: 'aborted',\n reason: failure as Exclude<E, StoreFault>,\n } as UnitOutcome<A, Exclude<E, StoreFault>>;\n }\n\n if (decided.success.kind === 'duplicate') {\n yield* abort(session);\n const replay =\n options?.claim?.kind === 'command'\n ? yield* readCommandReplay(db, options.claim.commandId)\n : Option.none();\n return { _tag: 'duplicate', replay } as UnitOutcome<\n A,\n Exclude<E, StoreFault>\n >;\n }\n\n yield* commit(session);\n return {\n _tag: 'committed',\n value: decided.success.value,\n } as UnitOutcome<A, Exclude<E, StoreFault>>;\n }),\n session => driver(() => session.endSession()).pipe(Effect.ignore),\n );\n\n return {\n run: (body, options) =>\n Effect.gen(function* () {\n yield* ensureIndexes(db);\n const outcome = yield* attempt(body, options).pipe(\n // The whole unit runs again, body included: that is why the body\n // must be retry-safe.\n Effect.retry({\n times: ATTEMPTS - 1,\n while: isTransient,\n schedule: BACK_OFF,\n }),\n );\n if (outcome._tag === 'committed' && options?.afterCommit) {\n yield* options.afterCommit.pipe(Effect.ignore);\n }\n return outcome;\n }),\n replay: commandId => readCommandReplay(db, commandId),\n };\n };\n\n return { forDatabase };\n};\n\n/** A {@link UnitOfWork} over one database. */\nexport const makeMongoUnitOfWork = (options: {\n readonly client: MongoSessionSource;\n readonly db: Db;\n}): UnitOfWork<MongoUnit> =>\n makeMongoUnitsOfWork(options.client).forDatabase(options.db);\n\n/** The unit of work over the service's own database. */\nexport class MongoUnitOfWorkTag extends Context.Service<\n MongoUnitOfWorkTag,\n UnitOfWork<MongoUnit>\n>()('MongoUnitOfWorkTag') {}\n\n/**\n * Provides {@link MongoUnitOfWorkTag} from the client and the named database\n * {@link MongoDatabaseLayer} opened.\n */\nexport const MongoUnitOfWorkLayer = Layer.effect(\n MongoUnitOfWorkTag,\n Effect.gen(function* () {\n const client = yield* MongoClientTag;\n const db = yield* MongoDatabaseTag;\n return makeMongoUnitOfWork({ client, db });\n }),\n);\n"],"names":["Contention","isFailure","isStoreFault","Context","Effect","Layer","Option","Result","Schedule","translateMongoFault","ensureInboxIndexes","INBOX_COLLECTION","inboxDocument","isDuplicateKey","MongoClientTag","MongoDatabaseTag","ensureOutboxIndexes","OUTBOX_COLLECTION","outboxDocument","COMMAND_INBOX_COLLECTION","commandClaimDocument","ensureCommandInboxIndexes","readCommandReplay","rememberCommandReplay","ATTEMPTS","BACK_OFF","exponential","pipe","jittered","hasErrorLabel","error","label","candidate","errorLabels","includes","labelledInChain","current","depth","cause","isTransient","_tag","fault","driver","run","tryPromise","try","catch","insertOrDuplicate","takeClaim","db","session","claim","kind","collection","insertOne","consumer","eventId","commandId","commit","commitTransaction","retry","times","while","mapError","abort","abortTransaction","ignore","makeMongoUnitsOfWork","client","ensured","Map","ensureIndexes","suspend","key","databaseName","done","get","undefined","pending","runPromise","all","then","set","delete","forDatabase","attempt","body","options","acquireUseRelease","sync","startSession","gen","startTransaction","work","emitted","value","handle","emit","event","push","length","written","insertMany","map","replay","decided","result","failure","fail","reason","success","none","endSession","outcome","schedule","afterCommit","makeMongoUnitOfWork","MongoUnitOfWorkTag","Service","MongoUnitOfWorkLayer","effect"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entifix/mongo",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
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": {
@@ -57,17 +57,17 @@
57
57
  "dependencies": {
58
58
  "@swc/helpers": "0.5.23",
59
59
  "mongodb": "7.7.0",
60
- "@entifix/business": "0.9.0",
61
- "@entifix/core": "0.9.0"
60
+ "@entifix/core": "0.10.1",
61
+ "@entifix/business": "0.10.1"
62
62
  },
63
63
  "devDependencies": {
64
- "effect": "4.0.5",
65
- "@entifix/testing-unit": "0.9.0",
66
- "@entifix/transactions": "0.9.0"
64
+ "effect": "4.0.6",
65
+ "@entifix/transactions": "0.10.1",
66
+ "@entifix/testing-unit": "0.10.1"
67
67
  },
68
68
  "peerDependencies": {
69
- "effect": "^4.0.5",
70
- "@entifix/transactions": "0.9.0"
69
+ "effect": "^4.0.6",
70
+ "@entifix/transactions": "0.10.1"
71
71
  },
72
72
  "peerDependenciesMeta": {
73
73
  "@entifix/transactions": {