@decaf-ts/core 0.26.5 → 0.27.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 (42) hide show
  1. package/README.md +87 -1
  2. package/dist/core.cjs +1 -1
  3. package/dist/core.cjs.map +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/core.js.map +1 -1
  6. package/lib/cjs/auth/decorators.cjs +27 -30
  7. package/lib/cjs/auth/decorators.cjs.map +1 -1
  8. package/lib/cjs/index.cjs +3 -3
  9. package/lib/cjs/persistence/Adapter.cjs +9 -1
  10. package/lib/cjs/persistence/Adapter.cjs.map +1 -1
  11. package/lib/cjs/persistence/ContextLock.cjs +110 -61
  12. package/lib/cjs/persistence/ContextLock.cjs.map +1 -1
  13. package/lib/cjs/persistence/ObserverHandler.cjs +1 -1
  14. package/lib/cjs/persistence/ObserverHandler.cjs.map +1 -1
  15. package/lib/cjs/persistence/constants.cjs +1 -0
  16. package/lib/cjs/persistence/constants.cjs.map +1 -1
  17. package/lib/cjs/persistence/transactions.cjs +57 -24
  18. package/lib/cjs/persistence/transactions.cjs.map +1 -1
  19. package/lib/esm/auth/decorators.js +27 -30
  20. package/lib/esm/auth/decorators.js.map +1 -1
  21. package/lib/esm/index.js +3 -3
  22. package/lib/esm/persistence/Adapter.js +10 -2
  23. package/lib/esm/persistence/Adapter.js.map +1 -1
  24. package/lib/esm/persistence/ContextLock.js +108 -59
  25. package/lib/esm/persistence/ContextLock.js.map +1 -1
  26. package/lib/esm/persistence/ObserverHandler.js +1 -1
  27. package/lib/esm/persistence/ObserverHandler.js.map +1 -1
  28. package/lib/esm/persistence/constants.js +1 -0
  29. package/lib/esm/persistence/constants.js.map +1 -1
  30. package/lib/esm/persistence/transactions.js +55 -22
  31. package/lib/esm/persistence/transactions.js.map +1 -1
  32. package/lib/types/index.d.cts +3 -3
  33. package/lib/types/index.d.mts +3 -3
  34. package/lib/types/persistence/Adapter.d.cts +10 -2
  35. package/lib/types/persistence/Adapter.d.mts +10 -2
  36. package/lib/types/persistence/ContextLock.d.cts +72 -14
  37. package/lib/types/persistence/ContextLock.d.mts +72 -14
  38. package/lib/types/persistence/transactions.d.cts +20 -3
  39. package/lib/types/persistence/transactions.d.mts +20 -3
  40. package/lib/types/persistence/types.d.cts +9 -0
  41. package/lib/types/persistence/types.d.mts +9 -0
  42. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/persistence/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/persistence/constants.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,12 @@ import { TransactionalKeys } from "@decaf-ts/transactional-decorators";
4
4
  import { ModelService } from "./../services/ModelService.js";
5
5
  import { Repository } from "./../repository/Repository.js";
6
6
  import { Adapter } from "./Adapter.js";
7
- import { ContextLock } from "./ContextLock.js";
8
- export function getAdapterTransaction(obj, ...args) {
7
+ /**
8
+ * @description Resolves the transaction lock for a `@transactional`-decorated call
9
+ * @summary Finds the underlying adapter for the decorated object (Adapter, Repository, or
10
+ * ModelService) and asks it for a fresh `ContextLock` via `Adapter.transactionLock()`
11
+ */
12
+ export function resolveTransactionLock(obj, ...args) {
9
13
  let adapter;
10
14
  if (obj instanceof ModelService)
11
15
  adapter = obj.repo.adapter;
@@ -17,9 +21,6 @@ export function getAdapterTransaction(obj, ...args) {
17
21
  throw new InternalError(`Could not find adapter to extract transaction`);
18
22
  return adapter.transactionLock(...args);
19
23
  }
20
- export function getContextLock(obj, ...args) {
21
- return new ContextLock(getAdapterTransaction(obj, ...args));
22
- }
23
24
  function innerTransactional(...data) {
24
25
  return function (target, propertyKey, descriptor) {
25
26
  if (!descriptor)
@@ -31,27 +32,43 @@ function innerTransactional(...data) {
31
32
  descriptor.value = new Proxy(descriptor.value, {
32
33
  async apply(obj, thisArg, argArray) {
33
34
  const { log, ctx } = (await thisArg["logCtx"](argArray, obj.name, true)).for(obj);
34
- const lock = ctx.getOrUndefined("transactionLock") || getContextLock(thisArg);
35
- ctx.put("transactionLock", lock);
36
- await lock.acquire();
35
+ // Reuse an in-flight transaction (nested @transactional call) instead of starting a new one
36
+ const existing = ctx.getOrUndefined("transactionLock");
37
+ const lock = existing || resolveTransactionLock(thisArg);
38
+ lock.depth++;
39
+ if (!existing) {
40
+ // only cache the lock once begin() succeeds, so a rejected begin() (e.g.
41
+ // maxConcurrentTransactions=0) leaves no stale lock/depth on the context
42
+ await lock.begin(ctx);
43
+ ctx.cache.put("transactionLock", lock);
44
+ }
37
45
  let results;
38
46
  try {
39
47
  results = await obj.call(thisArg, ...argArray, ctx);
40
48
  }
41
49
  catch (e) {
50
+ // An inner @transactional frame may have already rolled back and ended
51
+ // the transaction (depth forced to 0); enclosing frames must not roll back again
52
+ const alreadyEnded = lock.depth === 0;
53
+ lock.depth = 0;
54
+ if (!alreadyEnded) {
55
+ try {
56
+ await lock.rollback(e, ctx);
57
+ }
58
+ catch (rollbackError) {
59
+ log.error(`Failed to rollback transaction`, rollbackError);
60
+ }
61
+ }
62
+ throw e;
63
+ }
64
+ lock.depth--;
65
+ if (lock.depth === 0) {
42
66
  try {
43
- await lock.rollback(e);
67
+ await lock.commit(ctx);
44
68
  }
45
69
  catch (e) {
46
- log.error(`Failed to rollback transaction`, e);
70
+ throw new InternalError(`Failed to commit transaction: ${e}`);
47
71
  }
48
- throw e;
49
- }
50
- try {
51
- await lock.release();
52
- }
53
- catch (e) {
54
- throw new InternalError(`Failed to release transaction: ${e}`);
55
72
  }
56
73
  return results;
57
74
  },
@@ -59,9 +76,25 @@ function innerTransactional(...data) {
59
76
  return descriptor;
60
77
  };
61
78
  }
62
- Decoration.for(TransactionalKeys.TRANSACTIONAL)
63
- .define({
64
- decorator: innerTransactional,
65
- })
66
- .apply();
79
+ /**
80
+ * @description Method decorator that wraps a method in core's transaction-lock mechanism
81
+ * @summary `@decaf-ts/transactional-decorators` exports its own `transactional()` factory, and that
82
+ * factory re-registers its own (base) decorator under the same Decoration key every time it is called
83
+ * — so importing core does not make core's implementation "stick" if anything also calls the base
84
+ * package's factory. Consumers that want core's `ContextLock`/per-adapter transaction-lock behavior
85
+ * MUST import `transactional` from `@decaf-ts/core` (this function), not from
86
+ * `@decaf-ts/transactional-decorators`. Whichever factory is called last determines the active
87
+ * implementation for the shared key/flavour going forward.
88
+ * @param {...any[]} data - Optional metadata available to the transaction-lock implementation
89
+ * @function transactional
90
+ * @category Decorators
91
+ */
92
+ export function transactional(...data) {
93
+ return Decoration.for(TransactionalKeys.TRANSACTIONAL)
94
+ .define({
95
+ decorator: innerTransactional,
96
+ args: data,
97
+ })
98
+ .apply();
99
+ }
67
100
  //# sourceMappingURL=transactions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transactions.js","sourceRoot":"","sources":["../../../src/persistence/transactions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transactions.js","sourceRoot":"","sources":["../../../src/persistence/transactions.ts"],"names":[],"mappings":"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"}
@@ -24,21 +24,21 @@ export * from "./persistence/index.d.cts";
24
24
  * @const VERSION
25
25
  * @memberOf module:core
26
26
  */
27
- export declare const VERSION = "0.26.4";
27
+ export declare const VERSION = "0.27.0";
28
28
  /**
29
29
  * @description Represents the current commit hash of the module build.
30
30
  * @summary Stores the current git commit hash for the package. The build replaces
31
31
  * the placeholder with the actual commit hash at publish time.
32
32
  * @const COMMIT
33
33
  */
34
- export declare const COMMIT = "698a38a";
34
+ export declare const COMMIT = "ad6f037";
35
35
  /**
36
36
  * @description Represents the full version string of the module.
37
37
  * @summary Stores the semver version and commit hash for the package.
38
38
  * The build replaces the placeholder with the actual `<version>-<commit>` value at publish time.
39
39
  * @const FULL_VERSION
40
40
  */
41
- export declare const FULL_VERSION = "0.26.4-698a38a";
41
+ export declare const FULL_VERSION = "0.27.0-ad6f037";
42
42
  /**
43
43
  * @description Stores the current package version
44
44
  * @summary A constant representing the version of the core package
@@ -24,21 +24,21 @@ export * from "./persistence/index.d.mts";
24
24
  * @const VERSION
25
25
  * @memberOf module:core
26
26
  */
27
- export declare const VERSION = "0.26.4";
27
+ export declare const VERSION = "0.27.0";
28
28
  /**
29
29
  * @description Represents the current commit hash of the module build.
30
30
  * @summary Stores the current git commit hash for the package. The build replaces
31
31
  * the placeholder with the actual commit hash at publish time.
32
32
  * @const COMMIT
33
33
  */
34
- export declare const COMMIT = "698a38a";
34
+ export declare const COMMIT = "ad6f037";
35
35
  /**
36
36
  * @description Represents the full version string of the module.
37
37
  * @summary Stores the semver version and commit hash for the package.
38
38
  * The build replaces the placeholder with the actual `<version>-<commit>` value at publish time.
39
39
  * @const FULL_VERSION
40
40
  */
41
- export declare const FULL_VERSION = "0.26.4-698a38a";
41
+ export declare const FULL_VERSION = "0.27.0-ad6f037";
42
42
  /**
43
43
  * @description Stores the current package version
44
44
  * @summary A constant representing the version of the core package
@@ -17,7 +17,7 @@ import { type Constructor } from "@decaf-ts/decoration";
17
17
  import { AbsContextual, ContextualArgs, ContextualizedArgs, MaybeContextualArg, MethodOrOperation } from "../utils/ContextualLoggedClass.d.cts";
18
18
  import { Paginator } from "../query/Paginator.d.cts";
19
19
  import { PreparedStatement } from "../query/types.d.cts";
20
- import { AdapterTransaction } from "./ContextLock.d.cts";
20
+ import { ContextLock } from "./ContextLock.d.cts";
21
21
  export declare function resolveBulkSequenceResult<T>(result: T[] | PromiseSettledResult<T>[], continueOnError: boolean, log: Logger, operation: string): T[];
22
22
  export type AdapterSubClass<A> = A extends Adapter<any, any, any, any> ? A : never;
23
23
  /**
@@ -150,7 +150,15 @@ export declare abstract class Adapter<CONF, CONN, QUERY, CONTEXT extends Context
150
150
  * @return {Constructor<Repository<any, Adapter<CONF, CONN, QUERY, CONTEXT>>>} The repository constructor
151
151
  */
152
152
  repository<R extends Repository<any, Adapter<CONF, CONN, QUERY, CONTEXT>>>(): Constructor<R>;
153
- transactionLock(...args: any[]): AdapterTransaction<this>;
153
+ /**
154
+ * @description Provides this adapter's transaction-lock implementation
155
+ * @summary Returns a fresh `ContextLock` instance used by `@transactional` to manage transaction
156
+ * boundaries. The base implementation is a no-op; adapters with native transaction support (e.g. a
157
+ * SQL adapter) should override this to return a `ContextLock` subclass that wraps the underlying
158
+ * driver's BEGIN/COMMIT/ROLLBACK. Nesting is handled by the `@transactional` proxy, not by this method
159
+ * or the returned lock.
160
+ */
161
+ transactionLock(...args: any[]): ContextLock<this>;
154
162
  protected shutdownProxies(...args: ContextualArgs<any>): Promise<void>;
155
163
  protected shutdownProxies(k: string, ...args: ContextualArgs<any>): Promise<void>;
156
164
  /**
@@ -17,7 +17,7 @@ import { type Constructor } from "@decaf-ts/decoration";
17
17
  import { AbsContextual, ContextualArgs, ContextualizedArgs, MaybeContextualArg, MethodOrOperation } from "../utils/ContextualLoggedClass.d.mts";
18
18
  import { Paginator } from "../query/Paginator.d.mts";
19
19
  import { PreparedStatement } from "../query/types.d.mts";
20
- import { AdapterTransaction } from "./ContextLock.d.mts";
20
+ import { ContextLock } from "./ContextLock.d.mts";
21
21
  export declare function resolveBulkSequenceResult<T>(result: T[] | PromiseSettledResult<T>[], continueOnError: boolean, log: Logger, operation: string): T[];
22
22
  export type AdapterSubClass<A> = A extends Adapter<any, any, any, any> ? A : never;
23
23
  /**
@@ -150,7 +150,15 @@ export declare abstract class Adapter<CONF, CONN, QUERY, CONTEXT extends Context
150
150
  * @return {Constructor<Repository<any, Adapter<CONF, CONN, QUERY, CONTEXT>>>} The repository constructor
151
151
  */
152
152
  repository<R extends Repository<any, Adapter<CONF, CONN, QUERY, CONTEXT>>>(): Constructor<R>;
153
- transactionLock(...args: any[]): AdapterTransaction<this>;
153
+ /**
154
+ * @description Provides this adapter's transaction-lock implementation
155
+ * @summary Returns a fresh `ContextLock` instance used by `@transactional` to manage transaction
156
+ * boundaries. The base implementation is a no-op; adapters with native transaction support (e.g. a
157
+ * SQL adapter) should override this to return a `ContextLock` subclass that wraps the underlying
158
+ * driver's BEGIN/COMMIT/ROLLBACK. Nesting is handled by the `@transactional` proxy, not by this method
159
+ * or the returned lock.
160
+ */
161
+ transactionLock(...args: any[]): ContextLock<this>;
154
162
  protected shutdownProxies(...args: ContextualArgs<any>): Promise<void>;
155
163
  protected shutdownProxies(k: string, ...args: ContextualArgs<any>): Promise<void>;
156
164
  /**
@@ -1,18 +1,76 @@
1
- import { Lock } from "@decaf-ts/transactional-decorators";
2
1
  import { type Adapter } from "./Adapter.d.cts";
3
- export declare class AdapterTransaction<A extends Adapter<any, any, any, any>> {
2
+ import { type Context } from "./Context.d.cts";
3
+ import { Lock } from "@decaf-ts/transactional-decorators";
4
+ /**
5
+ * @description Counting semaphore used by the default `ContextLock` to gate concurrent transactions
6
+ * @summary Simple FIFO semaphore: `acquire()` resolves immediately while permits remain, otherwise the
7
+ * caller is queued and resolved (without touching the permit count) the moment `release()` hands the
8
+ * permit directly to the next waiter. `SimpleConcurrencyLock.for(adapter, limit)` is the single,
9
+ * self-contained way to get the one gate shared by every transaction on that adapter - no extra state
10
+ * or methods live on `Adapter` itself for this.
11
+ * @class SimpleConcurrencyLock
12
+ */
13
+ export declare class SimpleConcurrencyLock extends Lock {
14
+ private static readonly registry;
15
+ /**
16
+ * @description Returns the one `SimpleConcurrencyLock` for this adapter, creating it on first use
17
+ * @summary `limit` only matters the first time it's called for a given adapter - the gate's capacity
18
+ * is fixed for the adapter's lifetime, the same way the adapter's own client/connection is.
19
+ */
20
+ static for(adapter: Adapter<any, any, any, any>, limit: number): SimpleConcurrencyLock;
21
+ private permits;
22
+ private readonly waiters;
23
+ private constructor();
24
+ acquire(ctx?: Context<any>): Promise<void>;
25
+ release(ctx?: Context<any>): void;
26
+ }
27
+ /**
28
+ * @description Per-adapter transaction lock
29
+ * @summary Default transaction boundary implementation stored on the Context by `@transactional`.
30
+ * Gated by the `maxConcurrentTransactions` flag (see `AdapterFlags`): `-1` (default) means no limit and
31
+ * `begin`/`commit`/`rollback` behave as a no-op; `0` disables transactions outright (every call throws);
32
+ * any positive number gates concurrent transactions through `SimpleConcurrencyLock.for(adapter, limit)`,
33
+ * the one counting semaphore shared by every transaction on that adapter, queuing callers until a slot
34
+ * frees up.
35
+ * Adapters with native transaction support (e.g. a SQL adapter wrapping BEGIN/COMMIT/ROLLBACK) override
36
+ * `Adapter.transactionLock()` to return a subclass with real `begin`/`commit`/`rollback` behavior - if that
37
+ * subclass does not call `super.begin()`/`super.commit()`/`super.rollback()`, `maxConcurrentTransactions`
38
+ * has no effect for it, since concurrency is then governed by the underlying database instead.
39
+ * `transactionLock()` always returns a *fresh* `ContextLock` per top-level transaction - it's the
40
+ * per-transaction handle (nesting `depth`, and for native adapters the actual exclusive connection/cursor),
41
+ * so it cannot be a singleton itself; only the concurrency gate it delegates to is shared.
42
+ * Nesting (reusing the same instance across nested `@transactional` calls, and deciding when to actually
43
+ * call `begin`/`commit`/`rollback`) is owned by the `@transactional` proxy via `depth`, not by this class.
44
+ * @class ContextLock
45
+ */
46
+ export declare class ContextLock<A extends Adapter<any, any, any, any> = Adapter<any, any, any, any>> {
4
47
  protected adapter: A;
48
+ /**
49
+ * @description Nesting depth, owned and mutated by the `@transactional` proxy
50
+ */
51
+ depth: number;
52
+ private semaphore?;
5
53
  constructor(adapter: A, ...args: any[]);
6
- begin(...args: any[]): Promise<void>;
7
- commit(...args: any[]): Promise<void>;
8
- rollback(...args: any[]): Promise<void>;
9
- }
10
- export declare class ContextLock extends Lock {
11
- protected adapterTransaction: AdapterTransaction<any>;
12
- private acquireCount;
13
- protected readonly lock: Lock;
14
- constructor(adapterTransaction: AdapterTransaction<any>);
15
- acquire(...args: any[]): Promise<void>;
16
- release(...args: any[]): Promise<void>;
17
- rollback(e: Error, ...args: any[]): Promise<void>;
54
+ /**
55
+ * @description Called once, by the outermost `@transactional` call
56
+ * @summary `context` already exists by the time this is called (the `@transactional` proxy always
57
+ * builds it before calling `begin`), so this routes it through `Adapter.logCtx()` with `allowCreate`
58
+ * left at its default `false` - there is nothing to create here, only the existing context (and its
59
+ * logger) to reuse. Passing `allowCreate: true` would be wrong: it skips the "reuse the context I was
60
+ * given" branch entirely and tries to build a new one through `Adapter.context()`, whose third
61
+ * positional parameter is reserved for a model constructor - the context would be misread as "model".
62
+ * @param {Context<any>} context - The context the transaction is starting under
63
+ */
64
+ begin(context: Context<any>): Promise<void>;
65
+ /**
66
+ * @description Called once, when the outermost `@transactional` call exits successfully
67
+ * @param {Context<any>} context - The context the transaction ran under
68
+ */
69
+ commit(context: Context<any>): Promise<void>;
70
+ /**
71
+ * @description Called once, by whichever call hits the error first. Ends the transaction outright
72
+ * @param {Error} err - The error that triggered the rollback
73
+ * @param {Context<any>} context - The context the transaction ran under
74
+ */
75
+ rollback(err: Error, context: Context<any>): Promise<void>;
18
76
  }
@@ -1,18 +1,76 @@
1
- import { Lock } from "@decaf-ts/transactional-decorators";
2
1
  import { type Adapter } from "./Adapter.d.mts";
3
- export declare class AdapterTransaction<A extends Adapter<any, any, any, any>> {
2
+ import { type Context } from "./Context.d.mts";
3
+ import { Lock } from "@decaf-ts/transactional-decorators";
4
+ /**
5
+ * @description Counting semaphore used by the default `ContextLock` to gate concurrent transactions
6
+ * @summary Simple FIFO semaphore: `acquire()` resolves immediately while permits remain, otherwise the
7
+ * caller is queued and resolved (without touching the permit count) the moment `release()` hands the
8
+ * permit directly to the next waiter. `SimpleConcurrencyLock.for(adapter, limit)` is the single,
9
+ * self-contained way to get the one gate shared by every transaction on that adapter - no extra state
10
+ * or methods live on `Adapter` itself for this.
11
+ * @class SimpleConcurrencyLock
12
+ */
13
+ export declare class SimpleConcurrencyLock extends Lock {
14
+ private static readonly registry;
15
+ /**
16
+ * @description Returns the one `SimpleConcurrencyLock` for this adapter, creating it on first use
17
+ * @summary `limit` only matters the first time it's called for a given adapter - the gate's capacity
18
+ * is fixed for the adapter's lifetime, the same way the adapter's own client/connection is.
19
+ */
20
+ static for(adapter: Adapter<any, any, any, any>, limit: number): SimpleConcurrencyLock;
21
+ private permits;
22
+ private readonly waiters;
23
+ private constructor();
24
+ acquire(ctx?: Context<any>): Promise<void>;
25
+ release(ctx?: Context<any>): void;
26
+ }
27
+ /**
28
+ * @description Per-adapter transaction lock
29
+ * @summary Default transaction boundary implementation stored on the Context by `@transactional`.
30
+ * Gated by the `maxConcurrentTransactions` flag (see `AdapterFlags`): `-1` (default) means no limit and
31
+ * `begin`/`commit`/`rollback` behave as a no-op; `0` disables transactions outright (every call throws);
32
+ * any positive number gates concurrent transactions through `SimpleConcurrencyLock.for(adapter, limit)`,
33
+ * the one counting semaphore shared by every transaction on that adapter, queuing callers until a slot
34
+ * frees up.
35
+ * Adapters with native transaction support (e.g. a SQL adapter wrapping BEGIN/COMMIT/ROLLBACK) override
36
+ * `Adapter.transactionLock()` to return a subclass with real `begin`/`commit`/`rollback` behavior - if that
37
+ * subclass does not call `super.begin()`/`super.commit()`/`super.rollback()`, `maxConcurrentTransactions`
38
+ * has no effect for it, since concurrency is then governed by the underlying database instead.
39
+ * `transactionLock()` always returns a *fresh* `ContextLock` per top-level transaction - it's the
40
+ * per-transaction handle (nesting `depth`, and for native adapters the actual exclusive connection/cursor),
41
+ * so it cannot be a singleton itself; only the concurrency gate it delegates to is shared.
42
+ * Nesting (reusing the same instance across nested `@transactional` calls, and deciding when to actually
43
+ * call `begin`/`commit`/`rollback`) is owned by the `@transactional` proxy via `depth`, not by this class.
44
+ * @class ContextLock
45
+ */
46
+ export declare class ContextLock<A extends Adapter<any, any, any, any> = Adapter<any, any, any, any>> {
4
47
  protected adapter: A;
48
+ /**
49
+ * @description Nesting depth, owned and mutated by the `@transactional` proxy
50
+ */
51
+ depth: number;
52
+ private semaphore?;
5
53
  constructor(adapter: A, ...args: any[]);
6
- begin(...args: any[]): Promise<void>;
7
- commit(...args: any[]): Promise<void>;
8
- rollback(...args: any[]): Promise<void>;
9
- }
10
- export declare class ContextLock extends Lock {
11
- protected adapterTransaction: AdapterTransaction<any>;
12
- private acquireCount;
13
- protected readonly lock: Lock;
14
- constructor(adapterTransaction: AdapterTransaction<any>);
15
- acquire(...args: any[]): Promise<void>;
16
- release(...args: any[]): Promise<void>;
17
- rollback(e: Error, ...args: any[]): Promise<void>;
54
+ /**
55
+ * @description Called once, by the outermost `@transactional` call
56
+ * @summary `context` already exists by the time this is called (the `@transactional` proxy always
57
+ * builds it before calling `begin`), so this routes it through `Adapter.logCtx()` with `allowCreate`
58
+ * left at its default `false` - there is nothing to create here, only the existing context (and its
59
+ * logger) to reuse. Passing `allowCreate: true` would be wrong: it skips the "reuse the context I was
60
+ * given" branch entirely and tries to build a new one through `Adapter.context()`, whose third
61
+ * positional parameter is reserved for a model constructor - the context would be misread as "model".
62
+ * @param {Context<any>} context - The context the transaction is starting under
63
+ */
64
+ begin(context: Context<any>): Promise<void>;
65
+ /**
66
+ * @description Called once, when the outermost `@transactional` call exits successfully
67
+ * @param {Context<any>} context - The context the transaction ran under
68
+ */
69
+ commit(context: Context<any>): Promise<void>;
70
+ /**
71
+ * @description Called once, by whichever call hits the error first. Ends the transaction outright
72
+ * @param {Error} err - The error that triggered the rollback
73
+ * @param {Context<any>} context - The context the transaction ran under
74
+ */
75
+ rollback(err: Error, context: Context<any>): Promise<void>;
18
76
  }
@@ -1,4 +1,21 @@
1
- import { Adapter } from "../persistence/Adapter.d.cts";
2
1
  import { ContextLock } from "../persistence/ContextLock.d.cts";
3
- export declare function getAdapterTransaction(obj: any, ...args: any[]): import(".").AdapterTransaction<Adapter<any, any, any, any>>;
4
- export declare function getContextLock(obj: any, ...args: any[]): ContextLock;
2
+ /**
3
+ * @description Resolves the transaction lock for a `@transactional`-decorated call
4
+ * @summary Finds the underlying adapter for the decorated object (Adapter, Repository, or
5
+ * ModelService) and asks it for a fresh `ContextLock` via `Adapter.transactionLock()`
6
+ */
7
+ export declare function resolveTransactionLock(obj: any, ...args: any[]): ContextLock;
8
+ /**
9
+ * @description Method decorator that wraps a method in core's transaction-lock mechanism
10
+ * @summary `@decaf-ts/transactional-decorators` exports its own `transactional()` factory, and that
11
+ * factory re-registers its own (base) decorator under the same Decoration key every time it is called
12
+ * — so importing core does not make core's implementation "stick" if anything also calls the base
13
+ * package's factory. Consumers that want core's `ContextLock`/per-adapter transaction-lock behavior
14
+ * MUST import `transactional` from `@decaf-ts/core` (this function), not from
15
+ * `@decaf-ts/transactional-decorators`. Whichever factory is called last determines the active
16
+ * implementation for the shared key/flavour going forward.
17
+ * @param {...any[]} data - Optional metadata available to the transaction-lock implementation
18
+ * @function transactional
19
+ * @category Decorators
20
+ */
21
+ export declare function transactional(...data: any[]): (target: any, propertyKey?: any, descriptor?: TypedPropertyDescriptor<any>) => any;
@@ -1,4 +1,21 @@
1
- import { Adapter } from "../persistence/Adapter.d.mts";
2
1
  import { ContextLock } from "../persistence/ContextLock.d.mts";
3
- export declare function getAdapterTransaction(obj: any, ...args: any[]): import(".").AdapterTransaction<Adapter<any, any, any, any>>;
4
- export declare function getContextLock(obj: any, ...args: any[]): ContextLock;
2
+ /**
3
+ * @description Resolves the transaction lock for a `@transactional`-decorated call
4
+ * @summary Finds the underlying adapter for the decorated object (Adapter, Repository, or
5
+ * ModelService) and asks it for a fresh `ContextLock` via `Adapter.transactionLock()`
6
+ */
7
+ export declare function resolveTransactionLock(obj: any, ...args: any[]): ContextLock;
8
+ /**
9
+ * @description Method decorator that wraps a method in core's transaction-lock mechanism
10
+ * @summary `@decaf-ts/transactional-decorators` exports its own `transactional()` factory, and that
11
+ * factory re-registers its own (base) decorator under the same Decoration key every time it is called
12
+ * — so importing core does not make core's implementation "stick" if anything also calls the base
13
+ * package's factory. Consumers that want core's `ContextLock`/per-adapter transaction-lock behavior
14
+ * MUST import `transactional` from `@decaf-ts/core` (this function), not from
15
+ * `@decaf-ts/transactional-decorators`. Whichever factory is called last determines the active
16
+ * implementation for the shared key/flavour going forward.
17
+ * @param {...any[]} data - Optional metadata available to the transaction-lock implementation
18
+ * @function transactional
19
+ * @category Decorators
20
+ */
21
+ export declare function transactional(...data: any[]): (target: any, propertyKey?: any, descriptor?: TypedPropertyDescriptor<any>) => any;
@@ -78,6 +78,15 @@ export type AdapterFlags<LOG extends Logger = Logger> = RepositoryFlags<LOG> & C
78
78
  paginateByBookmark: boolean;
79
79
  dryRun: boolean;
80
80
  lock?: ContextLock;
81
+ /**
82
+ * @description Maximum number of concurrent transactions the default `ContextLock` allows for this adapter
83
+ * @summary `-1` (default) means no limit - the default lock behaves as a no-op. `0` disables transactions
84
+ * entirely (every `@transactional()` call throws). Any positive number gates concurrent transactions through
85
+ * a counting semaphore, queuing callers until a slot frees up. Adapters with native transaction support
86
+ * (e.g. a SQL adapter) that fully override `ContextLock.begin()`/`commit()`/`rollback()` are not affected by
87
+ * this flag - concurrency there is governed by the underlying database instead.
88
+ */
89
+ maxConcurrentTransactions: number;
81
90
  };
82
91
  export type RawResult<R, D extends boolean> = D extends true ? R : {
83
92
  data: R;
@@ -78,6 +78,15 @@ export type AdapterFlags<LOG extends Logger = Logger> = RepositoryFlags<LOG> & C
78
78
  paginateByBookmark: boolean;
79
79
  dryRun: boolean;
80
80
  lock?: ContextLock;
81
+ /**
82
+ * @description Maximum number of concurrent transactions the default `ContextLock` allows for this adapter
83
+ * @summary `-1` (default) means no limit - the default lock behaves as a no-op. `0` disables transactions
84
+ * entirely (every `@transactional()` call throws). Any positive number gates concurrent transactions through
85
+ * a counting semaphore, queuing callers until a slot frees up. Adapters with native transaction support
86
+ * (e.g. a SQL adapter) that fully override `ContextLock.begin()`/`commit()`/`rollback()` are not affected by
87
+ * this flag - concurrency there is governed by the underlying database instead.
88
+ */
89
+ maxConcurrentTransactions: number;
81
90
  };
82
91
  export type RawResult<R, D extends boolean> = D extends true ? R : {
83
92
  data: R;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decaf-ts/core",
3
- "version": "0.26.5",
3
+ "version": "0.27.1",
4
4
  "description": "Core persistence module for the decaf framework",
5
5
  "type": "module",
6
6
  "exports": {