@decaf-ts/transactional-decorators 0.1.4 → 0.2.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.
Files changed (82) hide show
  1. package/README.md +1 -1
  2. package/dist/transactional-decorators.cjs +1 -1
  3. package/dist/transactional-decorators.cjs.map +1 -1
  4. package/dist/transactional-decorators.js +1 -1
  5. package/dist/transactional-decorators.js.map +1 -1
  6. package/lib/Transaction.cjs +254 -56
  7. package/lib/Transaction.d.ts +44 -18
  8. package/lib/Transaction.js.map +1 -1
  9. package/lib/constants.cjs +0 -1
  10. package/lib/constants.js.map +1 -1
  11. package/lib/decorators.cjs +60 -146
  12. package/lib/decorators.d.ts +1 -11
  13. package/lib/decorators.js.map +1 -1
  14. package/lib/errors.cjs +11 -0
  15. package/lib/errors.d.ts +4 -0
  16. package/lib/errors.js.map +1 -0
  17. package/lib/esm/Transaction.d.ts +44 -18
  18. package/lib/esm/Transaction.js +254 -56
  19. package/lib/esm/Transaction.js.map +1 -1
  20. package/lib/esm/constants.js +0 -1
  21. package/lib/esm/constants.js.map +1 -1
  22. package/lib/esm/decorators.d.ts +1 -11
  23. package/lib/esm/decorators.js +60 -145
  24. package/lib/esm/decorators.js.map +1 -1
  25. package/lib/esm/errors.d.ts +4 -0
  26. package/lib/esm/errors.js +7 -0
  27. package/lib/esm/errors.js.map +1 -0
  28. package/lib/esm/index.d.ts +4 -1
  29. package/lib/esm/index.js +6 -1
  30. package/lib/esm/index.js.map +1 -1
  31. package/lib/esm/interfaces/TransactionLock.d.ts +2 -2
  32. package/lib/esm/locks/{SyncronousLock.d.ts → SynchronousLock.d.ts} +10 -6
  33. package/lib/esm/locks/SynchronousLock.js +131 -0
  34. package/lib/esm/locks/SynchronousLock.js.map +1 -0
  35. package/lib/esm/locks/index.d.ts +1 -1
  36. package/lib/esm/locks/index.js +1 -1
  37. package/lib/esm/locks/index.js.map +1 -1
  38. package/lib/esm/overrides/Metadata.d.ts +8 -0
  39. package/lib/esm/overrides/Metadata.js +2 -0
  40. package/lib/esm/overrides/Metadata.js.map +1 -0
  41. package/lib/esm/overrides/index.d.ts +2 -0
  42. package/lib/esm/overrides/index.js +3 -0
  43. package/lib/esm/overrides/index.js.map +1 -0
  44. package/lib/esm/overrides/overrides.d.ts +1 -0
  45. package/lib/esm/overrides/overrides.js +12 -0
  46. package/lib/esm/overrides/overrides.js.map +1 -0
  47. package/lib/esm/types.d.ts +0 -10
  48. package/lib/esm/types.js +11 -0
  49. package/lib/esm/types.js.map +1 -1
  50. package/lib/index.cjs +7 -2
  51. package/lib/index.d.ts +4 -1
  52. package/lib/index.js.map +1 -1
  53. package/lib/interfaces/TransactionLock.d.ts +2 -2
  54. package/lib/locks/SynchronousLock.cjs +135 -0
  55. package/lib/locks/{SyncronousLock.d.ts → SynchronousLock.d.ts} +10 -6
  56. package/lib/locks/SynchronousLock.js.map +1 -0
  57. package/lib/locks/index.cjs +1 -1
  58. package/lib/locks/index.d.ts +1 -1
  59. package/lib/locks/index.js.map +1 -1
  60. package/lib/overrides/Metadata.cjs +4 -0
  61. package/lib/overrides/Metadata.d.ts +8 -0
  62. package/lib/overrides/Metadata.js.map +1 -0
  63. package/lib/overrides/index.cjs +19 -0
  64. package/lib/overrides/index.d.ts +2 -0
  65. package/lib/overrides/index.js.map +1 -0
  66. package/lib/overrides/overrides.cjs +14 -0
  67. package/lib/overrides/overrides.d.ts +1 -0
  68. package/lib/overrides/overrides.js.map +1 -0
  69. package/lib/types.cjs +11 -0
  70. package/lib/types.d.ts +0 -10
  71. package/lib/types.js.map +1 -1
  72. package/package.json +7 -32
  73. package/lib/esm/locks/SyncronousLock.js +0 -128
  74. package/lib/esm/locks/SyncronousLock.js.map +0 -1
  75. package/lib/esm/utils.d.ts +0 -1
  76. package/lib/esm/utils.js +0 -14
  77. package/lib/esm/utils.js.map +0 -1
  78. package/lib/locks/SyncronousLock.cjs +0 -132
  79. package/lib/locks/SyncronousLock.js.map +0 -1
  80. package/lib/utils.cjs +0 -17
  81. package/lib/utils.d.ts +0 -1
  82. package/lib/utils.js.map +0 -1
package/lib/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./interfaces";
2
2
  export * from "./locks";
3
+ export * from "./overrides";
3
4
  export * from "./constants";
5
+ export * from "./errors";
4
6
  export * from "./decorators";
5
7
  export * from "./Transaction";
6
8
  export * from "./types";
@@ -15,4 +17,5 @@ export * from "./types";
15
17
  * @const VERSION
16
18
  * @memberOf module:transactions
17
19
  */
18
- export declare const VERSION = "0.1.3";
20
+ export declare const VERSION = "0.1.5";
21
+ export declare const PACKAGE_NAME = "@decaf-ts/transactional-decorators";
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yDAA6B;AAC7B,oDAAwB;AACxB,kDAA4B;AAC5B,mDAA6B;AAC7B,oDAA8B;AAC9B,8CAAwB;AAExB;;;;GAIG;AAEH;;;;;GAKG;AACU,QAAA,OAAO,GAAG,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qDAAgD;AAEhD,yDAA6B;AAC7B,oDAAwB;AACxB,wDAA4B;AAC5B,kDAA4B;AAC5B,+CAAyB;AACzB,mDAA6B;AAC7B,oDAA8B;AAC9B,8CAAwB;AAExB;;;;GAIG;AAEH;;;;;GAKG;AACU,QAAA,OAAO,GAAG,aAAa,CAAC;AAExB,QAAA,YAAY,GAAG,aAAa,CAAC;AAE1C,qBAAQ,CAAC,eAAe,CAAC,oBAAY,EAAE,eAAO,CAAC,CAAC"}
@@ -10,14 +10,14 @@ export interface TransactionLock {
10
10
  * @description Current active transaction reference
11
11
  * @summary Stores a reference to the currently executing transaction, allowing access to the active transaction context
12
12
  */
13
- currentTransaction?: Transaction;
13
+ currentTransaction?: Transaction<any>;
14
14
  /**
15
15
  * @description Submits a transaction for processing
16
16
  * @summary Adds a transaction to the processing queue and handles its execution according to the lock's concurrency rules
17
17
  * @param {Transaction} transaction - The transaction to be processed
18
18
  * @return {void}
19
19
  */
20
- submit(transaction: Transaction): void;
20
+ submit<R>(transaction: Transaction<R>): Promise<R>;
21
21
  /**
22
22
  * @description Releases the transaction lock
23
23
  * @summary Releases the lock after the conclusion of a transaction, allowing the next transaction to proceed, and handles any errors that occurred
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SynchronousLock = void 0;
4
+ const Transaction_1 = require("./../Transaction.cjs");
5
+ const Lock_1 = require("./Lock.cjs");
6
+ const logging_1 = require("@decaf-ts/logging");
7
+ /**
8
+ * @summary Simple Synchronous Lock implementation
9
+ * @description for transaction management
10
+ * adapted from {@link https://www.talkinghightech.com/en/creating-a-js-lock-for-a-resource/}
11
+ *
12
+ * @param {number} [counter] the number of simultaneous transactions allowed. defaults to 1
13
+ * @param {Function} [onBegin] to be called at the start of the transaction
14
+ * @param {Function} [onEnd] to be called at the conclusion of the transaction
15
+ *
16
+ * @class SynchronousLock
17
+ * @implements TransactionLock
18
+ */
19
+ class SynchronousLock extends logging_1.LoggedClass {
20
+ get log() {
21
+ if (!this["_log"]) {
22
+ this["_log"] = Transaction_1.Transaction["log"].for(this);
23
+ }
24
+ return this["_log"];
25
+ }
26
+ logger(method) {
27
+ if (!this.loggerCache.has(method)) {
28
+ this.loggerCache.set(method, this.log.for(this[method]));
29
+ }
30
+ return this.loggerCache.get(method);
31
+ }
32
+ constructor(counter = 1, onBegin, onEnd) {
33
+ super();
34
+ this.counter = counter;
35
+ this.onBegin = onBegin;
36
+ this.onEnd = onEnd;
37
+ this.pendingTransactions = [];
38
+ this.currentTransaction = undefined;
39
+ this.loggerCache = new Map();
40
+ this.lock = new Lock_1.Lock();
41
+ }
42
+ /**
43
+ * @summary Submits a transaction to be processed
44
+ * @param {Transaction} transaction
45
+ */
46
+ async submit(transaction) {
47
+ const log = this.logger("submit");
48
+ await this.lock.acquire();
49
+ log.silly(`Lock acquired to submit transaction ${transaction.id}`);
50
+ if (this.currentTransaction &&
51
+ this.currentTransaction.id === transaction.id) {
52
+ this.lock.release();
53
+ log.silly(`Released lock for re-entrant transaction ${transaction.id}`);
54
+ return transaction.fire();
55
+ }
56
+ let resultPromise;
57
+ if (this.counter > 0) {
58
+ this.counter--;
59
+ this.lock.release();
60
+ log.silly(`Released lock for transaction ${transaction.id}`);
61
+ resultPromise = this.fireTransaction(transaction);
62
+ }
63
+ else {
64
+ log.debug(`Pushing transaction ${transaction.id} to the queue`);
65
+ this.pendingTransactions.push(transaction);
66
+ resultPromise = transaction.wait();
67
+ this.lock.release();
68
+ log.silly(`Released lock after queuing transaction ${transaction.id}`);
69
+ }
70
+ return resultPromise;
71
+ }
72
+ /**
73
+ * @summary Executes a transaction
74
+ *
75
+ * @param {Transaction} transaction
76
+ * @private
77
+ */
78
+ async fireTransaction(transaction) {
79
+ const log = this.logger("fireTransaction");
80
+ await this.lock.acquire();
81
+ log.silly(`Lock acquired obtain transaction ${transaction.id}`);
82
+ this.currentTransaction = transaction;
83
+ this.lock.release();
84
+ log.silly(`Released lock after obtaining ${transaction.id}`);
85
+ if (this.onBegin) {
86
+ log.verbose(`Calling onBegin for transaction ${transaction.id}`);
87
+ await this.onBegin();
88
+ }
89
+ log.info(`Starting transaction ${transaction.id}. ${this.pendingTransactions.length} remaining...`);
90
+ return transaction.fire();
91
+ }
92
+ /**
93
+ * @summary Releases The lock after the conclusion of a transaction
94
+ */
95
+ async release(err) {
96
+ const log = this.logger("release");
97
+ await this.lock.acquire();
98
+ if (!this.currentTransaction)
99
+ log.warn("Trying to release an unexisting transaction. should never happen...");
100
+ log.verbose(`Releasing transaction ${this.currentTransaction?.toString(true, true)}`);
101
+ const id = this.currentTransaction?.id;
102
+ this.currentTransaction = undefined;
103
+ this.lock.release();
104
+ log.silly(`Released lock after clearing transaction ${id}`);
105
+ if (this.onEnd) {
106
+ log.verbose(`Calling onEnd for transaction ${id}`);
107
+ await this.onEnd(err);
108
+ }
109
+ await this.lock.acquire();
110
+ log.silly(`Acquired lock after completing transaction ${id} for pending transaction verification`);
111
+ if (this.pendingTransactions.length > 0) {
112
+ const transaction = this.pendingTransactions.shift();
113
+ const cb = () => {
114
+ return this.fireTransaction.call(this, transaction).catch((err) => {
115
+ this.log.for(this.fireTransaction).error(err);
116
+ });
117
+ };
118
+ log.silly(`Marking ${transaction.id} for execution`);
119
+ if (!(0, logging_1.isBrowser)()) {
120
+ globalThis.process.nextTick(cb); // if you are on node
121
+ }
122
+ else {
123
+ setTimeout(cb, 0);
124
+ } // if you are in the browser
125
+ }
126
+ else {
127
+ log.debug(`No pending transactions. Incrementing counter.`);
128
+ this.counter++;
129
+ }
130
+ this.lock.release();
131
+ log.silly(`Released lock after completing transaction ${id}`);
132
+ }
133
+ }
134
+ exports.SynchronousLock = SynchronousLock;
135
+ //# sourceMappingURL=SynchronousLock.js.map
@@ -1,5 +1,6 @@
1
1
  import { Transaction } from "../Transaction";
2
2
  import { TransactionLock } from "../interfaces/TransactionLock";
3
+ import { LoggedClass } from "@decaf-ts/logging";
3
4
  /**
4
5
  * @summary Simple Synchronous Lock implementation
5
6
  * @description for transaction management
@@ -9,22 +10,25 @@ import { TransactionLock } from "../interfaces/TransactionLock";
9
10
  * @param {Function} [onBegin] to be called at the start of the transaction
10
11
  * @param {Function} [onEnd] to be called at the conclusion of the transaction
11
12
  *
12
- * @class SyncronousLock
13
+ * @class SynchronousLock
13
14
  * @implements TransactionLock
14
15
  */
15
- export declare class SyncronousLock implements TransactionLock {
16
+ export declare class SynchronousLock extends LoggedClass implements TransactionLock {
16
17
  private counter;
17
- private pendingTransactions;
18
- currentTransaction?: Transaction;
19
18
  private readonly onBegin?;
20
19
  private readonly onEnd?;
20
+ private pendingTransactions;
21
+ currentTransaction?: Transaction<any>;
22
+ private readonly loggerCache;
23
+ get log(): any;
24
+ private logger;
21
25
  private readonly lock;
22
- constructor(counter?: number, onBegin?: () => Promise<void>, onEnd?: (err?: Error) => Promise<void>);
26
+ constructor(counter?: number, onBegin?: (() => Promise<void>) | undefined, onEnd?: ((err?: Error) => Promise<void>) | undefined);
23
27
  /**
24
28
  * @summary Submits a transaction to be processed
25
29
  * @param {Transaction} transaction
26
30
  */
27
- submit(transaction: Transaction): void;
31
+ submit<R>(transaction: Transaction<R>): Promise<R>;
28
32
  /**
29
33
  * @summary Executes a transaction
30
34
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynchronousLock.js","sourceRoot":"","sources":["../../src/locks/SynchronousLock.ts"],"names":[],"mappings":"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"}
@@ -20,5 +20,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  __exportStar(require("./Lock.cjs"), exports);
23
- __exportStar(require("./SyncronousLock.cjs"), exports);
23
+ __exportStar(require("./SynchronousLock.cjs"), exports);
24
24
  //# sourceMappingURL=index.js.map
@@ -4,4 +4,4 @@
4
4
  * @module transactions/locks
5
5
  */
6
6
  export * from "./Lock";
7
- export * from "./SyncronousLock";
7
+ export * from "./SynchronousLock";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/locks/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;AAEH,6CAAuB;AACvB,uDAAiC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/locks/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;AAEH,6CAAuB;AACvB,wDAAkC"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("@decaf-ts/decoration");
4
+ //# sourceMappingURL=Metadata.js.map
@@ -0,0 +1,8 @@
1
+ import "@decaf-ts/decoration";
2
+ import { Constructor } from "@decaf-ts/decorator-validation";
3
+ declare module "@decaf-ts/decoration" {
4
+ namespace Metadata {
5
+ function transactionals<T>(obj: Constructor<T>): (keyof T)[];
6
+ function isTransactional<T>(obj: Constructor<T>): boolean;
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Metadata.js","sourceRoot":"","sources":["../../src/overrides/Metadata.ts"],"names":[],"mappings":";;AAAA,gCAA8B"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Metadata.cjs"), exports);
18
+ __exportStar(require("./overrides.cjs"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ export * from "./Metadata";
2
+ export * from "./overrides";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/overrides/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA2B;AAC3B,kDAA4B"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const decoration_1 = require("@decaf-ts/decoration");
4
+ const constants_1 = require("./../constants.cjs");
5
+ decoration_1.Metadata.transactionals = function (obj) {
6
+ const meta = decoration_1.Metadata.get(obj, constants_1.TransactionalKeys.TRANSACTIONAL);
7
+ if (!meta)
8
+ return [];
9
+ return Object.keys(meta);
10
+ };
11
+ decoration_1.Metadata.isTransactional = function (obj) {
12
+ return !!decoration_1.Metadata.get(obj, constants_1.TransactionalKeys.TRANSACTIONAL);
13
+ };
14
+ //# sourceMappingURL=overrides.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overrides.js","sourceRoot":"","sources":["../../src/overrides/overrides.ts"],"names":[],"mappings":";;AAAA,qDAAgD;AAChD,kDAAiD;AAGhD,qBAAgB,CAAC,cAAc,GAAG,UACjC,GAAmB;IAEnB,MAAM,IAAI,GAAG,qBAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,6BAAiB,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAgB,CAAC;AAC1C,CAAC,CAAC;AAED,qBAAgB,CAAC,eAAe,GAAG,UAAa,GAAmB;IAClE,OAAO,CAAC,CAAC,qBAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,6BAAiB,CAAC,aAAa,CAAC,CAAC;AAC9D,CAAC,CAAC"}
package/lib/types.cjs CHANGED
@@ -1,3 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ //
4
+ // /**
5
+ // * @description Standard callback function type for asynchronous operations
6
+ // * @summary Defines a Node.js-style callback function that receives an optional error as the first parameter and optional result and additional arguments
7
+ // * @typedef {Function} Callback
8
+ // * @param {Error} [err] - Optional error object if the operation failed
9
+ // * @param {any} [result] - Optional result of the operation if successful
10
+ // * @param {...any} [args] - Additional arguments that may be passed to the callback
11
+ // * @memberOf module:transactions
12
+ // */
13
+ // export type Callback = (err?: Error, result?: any, ...args: any[]) => void;
3
14
  //# sourceMappingURL=types.js.map
package/lib/types.d.ts CHANGED
@@ -5,13 +5,3 @@
5
5
  * @memberOf module:transactions
6
6
  */
7
7
  export type LockCallable = (value?: void | PromiseLike<void>) => void;
8
- /**
9
- * @description Standard callback function type for asynchronous operations
10
- * @summary Defines a Node.js-style callback function that receives an optional error as the first parameter and optional result and additional arguments
11
- * @typedef {Function} Callback
12
- * @param {Error} [err] - Optional error object if the operation failed
13
- * @param {any} [result] - Optional result of the operation if successful
14
- * @param {...any} [args] - Additional arguments that may be passed to the callback
15
- * @memberOf module:transactions
16
- */
17
- export type Callback = (err?: Error, result?: any, ...args: any[]) => void;
package/lib/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":";;AAOA,EAAE;AACF,MAAM;AACN,8EAA8E;AAC9E,4JAA4J;AAC5J,kCAAkC;AAClC,0EAA0E;AAC1E,4EAA4E;AAC5E,sFAAsF;AACtF,mCAAmC;AACnC,MAAM;AACN,8EAA8E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decaf-ts/transactional-decorators",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Locking and transactions",
5
5
  "type": "module",
6
6
  "exports": {
@@ -23,7 +23,7 @@
23
23
  "test:integration": "jest --testPathPattern=\"/tests/(integration)\" --passWithNoTests --detectOpenHandles",
24
24
  "test:all": "jest --testPathPattern=\"/tests\" --passWithNoTests --detectOpenHandles",
25
25
  "test:circular": "dpdm -T --no-warning --no-tree ./src/index.ts",
26
- "coverage": "rimraf ./workdocs/reports/data/*.json && npm run test:all -- --coverage --config=./workdocs/reports/jest.coverage.config.ts",
26
+ "coverage": "rimraf ./workdocs/reports/data/*.json && npm run test:all -- --runInBand --coverage --config=./workdocs/reports/jest.coverage.config.ts",
27
27
  "lint": "eslint .",
28
28
  "lint-fix": "eslint --fix .",
29
29
  "prepare-pr": "npm run lint-fix && npm run build:prod && npm run coverage && npm run docs",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "repository": {
46
46
  "type": "git",
47
- "url": "git+https://github.com/decaf-ts/ts-workspace.git"
47
+ "url": "git+https://github.com/decaf-ts/transactional-decorators.git"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=20.0.0",
@@ -69,43 +69,18 @@
69
69
  "author": "Tiago Venceslau and Contributors",
70
70
  "license": "MIT",
71
71
  "bugs": {
72
- "url": "https://github.com/decaf-ts/ts-workspace/issues"
72
+ "url": "https://github.com/decaf-ts/transactional-decorators/issues"
73
73
  },
74
- "homepage": "https://github.com/decaf-ts/ts-workspace#readme",
74
+ "homepage": "https://github.com/decaf-ts/transactional-decorators#readme",
75
75
  "devDependencies": {
76
76
  "@decaf-ts/logging": "latest",
77
- "@decaf-ts/utils": "latest",
78
- "@eslint/js": "^9.25.1",
79
- "@stylistic/eslint-plugin": "^4.2.0",
80
- "@types/jest": "^29.5.14",
81
- "clean-publish": "^5.1.0",
82
- "dpdm": "^3.14.0",
83
- "eslint": "^9.25.1",
84
- "eslint-config-prettier": "^10.1.2",
85
- "eslint-plugin-prettier": "^5.2.6",
86
- "globals": "^16.0.0",
87
- "jest": "^29.7.0",
88
- "jest-html-reporters": "^3.1.7",
89
- "jest-junit": "^16.0.0",
90
- "jsdoc": "^4.0.4",
91
- "jsdoc-mermaid": "^1.0.0",
92
- "markdown-include": "^0.4.3",
93
- "minimist": "^1.2.8",
94
- "nodemon": "^3.1.9",
95
- "npm-check-updates": "^18.0.0",
96
- "prettier": "3.5.3",
97
- "rimraf": "^6.0.1",
98
- "ts-jest": "^29.3.2",
99
- "ts-loader": "^9.5.2",
100
- "ts-node": "^10.9.2",
101
- "typescript": "^5.8.3",
102
- "typescript-eslint": "^8.31.0"
77
+ "@decaf-ts/utils": "latest"
103
78
  },
104
79
  "peerDependencies": {
105
80
  "@decaf-ts/db-decorators": "latest",
106
81
  "@decaf-ts/decoration": "latest",
107
82
  "@decaf-ts/decorator-validation": "latest",
108
- "@decaf-ts/reflection": "latest",
83
+ "@decaf-ts/injectable-decorators": "latest",
109
84
  "reflect-metadata": "^0.2.1"
110
85
  }
111
86
  }
@@ -1,128 +0,0 @@
1
- import { Lock } from "./Lock.js";
2
- /**
3
- * @summary Simple Synchronous Lock implementation
4
- * @description for transaction management
5
- * adapted from {@link https://www.talkinghightech.com/en/creating-a-js-lock-for-a-resource/}
6
- *
7
- * @param {number} [counter] the number of simultaneous transactions allowed. defaults to 1
8
- * @param {Function} [onBegin] to be called at the start of the transaction
9
- * @param {Function} [onEnd] to be called at the conclusion of the transaction
10
- *
11
- * @class SyncronousLock
12
- * @implements TransactionLock
13
- */
14
- export class SyncronousLock {
15
- constructor(counter = 1, onBegin, onEnd) {
16
- this.currentTransaction = undefined;
17
- this.lock = new Lock();
18
- this.counter = counter;
19
- this.pendingTransactions = [];
20
- this.onBegin = onBegin;
21
- this.onEnd = onEnd;
22
- }
23
- /**
24
- * @summary Submits a transaction to be processed
25
- * @param {Transaction} transaction
26
- */
27
- submit(transaction) {
28
- // eslint-disable-next-line @typescript-eslint/no-this-alias
29
- const self = this;
30
- self.lock.acquire().then(() => {
31
- if (self.currentTransaction &&
32
- self.currentTransaction.id === transaction.id) {
33
- self.lock.release();
34
- return transaction.fire();
35
- }
36
- if (self.counter > 0) {
37
- self.counter--;
38
- self.lock.release();
39
- return self.fireTransaction(transaction);
40
- }
41
- else {
42
- self.pendingTransactions.push(transaction);
43
- self.lock.release();
44
- }
45
- });
46
- }
47
- /**
48
- * @summary Executes a transaction
49
- *
50
- * @param {Transaction} transaction
51
- * @private
52
- */
53
- fireTransaction(transaction) {
54
- // eslint-disable-next-line @typescript-eslint/no-this-alias
55
- const self = this;
56
- self.lock.acquire().then(() => {
57
- self.currentTransaction = transaction;
58
- self.lock.release();
59
- if (self.onBegin)
60
- self.onBegin().then(() => {
61
- // all.call(
62
- // self,
63
- // `Firing transaction {0}. {1} remaining...`,
64
- // transaction.id,
65
- // this.pendingTransactions.length,
66
- // );
67
- transaction.fire();
68
- });
69
- else {
70
- // all.call(
71
- // self,
72
- // `Firing transaction {0}. {1} remaining...`,
73
- // transaction.id,
74
- // this.pendingTransactions.length,
75
- // );
76
- transaction.fire();
77
- }
78
- });
79
- }
80
- /**
81
- * @summary Releases The lock after the conclusion of a transaction
82
- */
83
- async release(err) {
84
- // eslint-disable-next-line @typescript-eslint/no-this-alias
85
- const self = this;
86
- return new Promise((resolve) => {
87
- self.lock.acquire().then(() => {
88
- if (!self.currentTransaction)
89
- console.warn("Trying to release an unexisting transaction. should never happen...");
90
- // debug.call(
91
- // self,
92
- // "Releasing transaction: {0}",
93
- // self.currentTransaction?.toString(true, true),
94
- // );
95
- self.currentTransaction = undefined;
96
- self.lock.release();
97
- const afterConclusionCB = () => {
98
- self.lock.acquire().then(() => {
99
- if (self.pendingTransactions.length > 0) {
100
- const transaction = self.pendingTransactions.shift();
101
- const cb = () => self.fireTransaction(transaction);
102
- //
103
- // all(
104
- // `Releasing Transaction Lock on transaction {0}`,
105
- // transaction.id,
106
- // );
107
- if (typeof globalThis.window ===
108
- "undefined")
109
- globalThis.process.nextTick(cb); // if you are on node
110
- else
111
- setTimeout(cb, 0); // if you are in the browser
112
- }
113
- else {
114
- self.counter++;
115
- }
116
- self.lock.release();
117
- resolve();
118
- });
119
- };
120
- if (self.onEnd)
121
- self.onEnd(err).then(() => afterConclusionCB());
122
- else
123
- afterConclusionCB();
124
- });
125
- });
126
- }
127
- }
128
- //# sourceMappingURL=SyncronousLock.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SyncronousLock.js","sourceRoot":"","sources":["../../../src/locks/SyncronousLock.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export declare function getObjectName(obj: any): string | undefined;
package/lib/esm/utils.js DELETED
@@ -1,14 +0,0 @@
1
- export function getObjectName(obj) {
2
- if (!obj)
3
- return;
4
- if (typeof obj === "string")
5
- return obj;
6
- if (obj.constructor &&
7
- obj.constructor.name &&
8
- ["Function", "Object"].indexOf(obj.constructor.name) === -1)
9
- return obj.constructor.name;
10
- if (typeof obj === "function" && obj.name)
11
- return obj.name;
12
- return obj.toString();
13
- }
14
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IACE,GAAG,CAAC,WAAW;QACf,GAAG,CAAC,WAAW,CAAC,IAAI;QACpB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE3D,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC;IAC9B,IAAI,OAAO,GAAG,KAAK,UAAU,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAC3D,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC"}