@duraflows/kysely 3.1.0 → 4.0.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.
package/README.md CHANGED
@@ -51,7 +51,7 @@ import { KyselyTransactionContext } from "@duraflows/kysely";
51
51
 
52
52
  // Seed the transaction context so Duraflows participates in your transaction
53
53
  await db.transaction().execute(async (trx) => {
54
- await KyselyTransactionContext.run(trx, async () => {
54
+ await KyselyTransactionContext.run(db, trx, async () => {
55
55
  // Your own writes -- uses trx
56
56
  await trx.insertInto("orders").values({ id: "ORD-1", status: "paid" }).execute();
57
57
 
@@ -117,8 +117,10 @@ Convenience factory for short-lived runtimes pre-bound to an existing transactio
117
117
 
118
118
  ### `KyselyTransactionContext`
119
119
 
120
- - `getTransaction()` -- Returns the active `Transaction<WorkflowDatabase>` or `undefined`
121
- - `run(trx, callback)` -- Executes `callback` with `trx` as the active transaction context
120
+ The context is scoped per Kysely instance:
121
+
122
+ - `getTransaction(db)` -- Returns the active `Transaction<WorkflowDatabase>` for the given `db` instance, or `undefined`
123
+ - `run(db, trx, callback)` -- Executes `callback` with `trx` as the active transaction context for the given `db` instance
122
124
 
123
125
  ## Documentation
124
126
 
package/dist/cjs/index.js CHANGED
@@ -39,11 +39,12 @@ function kyselyWorkflowProvidersFromTransaction(trx) {
39
39
  const narrowed = trx;
40
40
  const transactionRunner = {
41
41
  async runInTransaction(callback) {
42
- const existing = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction();
43
- if (existing) {
42
+ // Nested calls reuse the bound transaction; an unrelated ambient
43
+ // transaction from another provider must never supersede it.
44
+ if (kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(narrowed)) {
44
45
  return callback();
45
46
  }
46
- return kysely_transaction_context_js_1.KyselyTransactionContext.run(trx, callback);
47
+ return kysely_transaction_context_js_1.KyselyTransactionContext.run(narrowed, trx, callback);
47
48
  },
48
49
  };
49
50
  const instanceStore = new kysely_instance_store_js_1.KyselyWorkflowInstanceStore(narrowed);
@@ -8,7 +8,7 @@ class KyselyWorkflowHistoryStore {
8
8
  this.db = db;
9
9
  }
10
10
  getExecutor() {
11
- return kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction() ?? this.db;
11
+ return kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db) ?? this.db;
12
12
  }
13
13
  async append(entry) {
14
14
  const executor = this.getExecutor();
@@ -9,7 +9,7 @@ class KyselyWorkflowInstanceStore {
9
9
  this.db = db;
10
10
  }
11
11
  getExecutor() {
12
- return kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction() ?? this.db;
12
+ return kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db) ?? this.db;
13
13
  }
14
14
  async create(instance) {
15
15
  const executor = this.getExecutor();
@@ -37,9 +37,9 @@ class KyselyWorkflowInstanceStore {
37
37
  return this.mapRow(row);
38
38
  }
39
39
  async lockByUuid(uuid) {
40
- const trx = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction();
40
+ const trx = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db);
41
41
  if (!trx) {
42
- throw new Error("lockByUuid requires an active transaction");
42
+ throw new core_1.WorkflowError("lockByUuid requires an active transaction");
43
43
  }
44
44
  const row = await trx
45
45
  .selectFrom("workflow_instances")
@@ -73,9 +73,9 @@ class KyselyWorkflowInstanceStore {
73
73
  }
74
74
  }
75
75
  async findExpired(limit, now) {
76
- const trx = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction();
76
+ const trx = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db);
77
77
  if (!trx) {
78
- throw new Error("findExpired requires an active transaction");
78
+ throw new core_1.WorkflowError("findExpired requires an active transaction");
79
79
  }
80
80
  const rows = await trx
81
81
  .selectFrom("workflow_instances")
@@ -1,9 +1,9 @@
1
- import type { Transaction } from "kysely";
1
+ import type { Kysely, Transaction } from "kysely";
2
2
  import type { WorkflowDatabase } from "./kysely-database.js";
3
3
  export declare const KyselyTransactionContext: {
4
- getTransaction(): Transaction<WorkflowDatabase> | undefined;
4
+ getTransaction(owner: Kysely<WorkflowDatabase>): Transaction<WorkflowDatabase> | undefined;
5
5
  /**
6
- * Executes callback with `trx` as the active transaction context.
6
+ * Executes callback with `trx` as the active transaction for `owner`.
7
7
  *
8
8
  * Generic so callers can pass `Transaction<MyDb & WorkflowDatabase>`
9
9
  * (Kysely is invariant in DB, so a non-generic signature would reject
@@ -11,6 +11,6 @@ export declare const KyselyTransactionContext: {
11
11
  * `Transaction<WorkflowDatabase>` which is safe — stores only access
12
12
  * workflow tables.
13
13
  */
14
- run<T, DB extends WorkflowDatabase = WorkflowDatabase>(trx: Transaction<DB>, callback: () => T): T;
14
+ run<T, DB extends WorkflowDatabase = WorkflowDatabase>(owner: Kysely<WorkflowDatabase>, trx: Transaction<DB>, callback: () => T): T;
15
15
  };
16
16
  //# sourceMappingURL=kysely-transaction-context.d.ts.map
@@ -2,13 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KyselyTransactionContext = void 0;
4
4
  const node_async_hooks_1 = require("node:async_hooks");
5
- const storage = new node_async_hooks_1.AsyncLocalStorage();
5
+ // One context per Kysely instance (or per pre-bound Transaction): a
6
+ // transaction on db A is invisible to stores and runners bound to db B.
7
+ const storages = new WeakMap();
8
+ function storageFor(owner) {
9
+ let storage = storages.get(owner);
10
+ if (!storage) {
11
+ storage = new node_async_hooks_1.AsyncLocalStorage();
12
+ storages.set(owner, storage);
13
+ }
14
+ return storage;
15
+ }
6
16
  exports.KyselyTransactionContext = {
7
- getTransaction() {
8
- return storage.getStore();
17
+ getTransaction(owner) {
18
+ return storages.get(owner)?.getStore();
9
19
  },
10
20
  /**
11
- * Executes callback with `trx` as the active transaction context.
21
+ * Executes callback with `trx` as the active transaction for `owner`.
12
22
  *
13
23
  * Generic so callers can pass `Transaction<MyDb & WorkflowDatabase>`
14
24
  * (Kysely is invariant in DB, so a non-generic signature would reject
@@ -16,8 +26,8 @@ exports.KyselyTransactionContext = {
16
26
  * `Transaction<WorkflowDatabase>` which is safe — stores only access
17
27
  * workflow tables.
18
28
  */
19
- run(trx, callback) {
20
- return storage.run(trx, callback);
29
+ run(owner, trx, callback) {
30
+ return storageFor(owner).run(trx, callback);
21
31
  },
22
32
  };
23
33
  //# sourceMappingURL=kysely-transaction-context.js.map
@@ -8,12 +8,12 @@ class KyselyTransactionRunner {
8
8
  this.db = db;
9
9
  }
10
10
  async runInTransaction(callback) {
11
- const existing = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction();
11
+ const existing = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db);
12
12
  if (existing) {
13
13
  return callback();
14
14
  }
15
15
  return this.db.transaction().execute(async (trx) => {
16
- return kysely_transaction_context_js_1.KyselyTransactionContext.run(trx, callback);
16
+ return kysely_transaction_context_js_1.KyselyTransactionContext.run(this.db, trx, callback);
17
17
  });
18
18
  }
19
19
  }
package/dist/index.js CHANGED
@@ -30,11 +30,12 @@ export function kyselyWorkflowProvidersFromTransaction(trx) {
30
30
  const narrowed = trx;
31
31
  const transactionRunner = {
32
32
  async runInTransaction(callback) {
33
- const existing = KyselyTransactionContext.getTransaction();
34
- if (existing) {
33
+ // Nested calls reuse the bound transaction; an unrelated ambient
34
+ // transaction from another provider must never supersede it.
35
+ if (KyselyTransactionContext.getTransaction(narrowed)) {
35
36
  return callback();
36
37
  }
37
- return KyselyTransactionContext.run(trx, callback);
38
+ return KyselyTransactionContext.run(narrowed, trx, callback);
38
39
  },
39
40
  };
40
41
  const instanceStore = new KyselyWorkflowInstanceStore(narrowed);
@@ -5,7 +5,7 @@ export class KyselyWorkflowHistoryStore {
5
5
  this.db = db;
6
6
  }
7
7
  getExecutor() {
8
- return KyselyTransactionContext.getTransaction() ?? this.db;
8
+ return KyselyTransactionContext.getTransaction(this.db) ?? this.db;
9
9
  }
10
10
  async append(entry) {
11
11
  const executor = this.getExecutor();
@@ -6,7 +6,7 @@ export class KyselyWorkflowInstanceStore {
6
6
  this.db = db;
7
7
  }
8
8
  getExecutor() {
9
- return KyselyTransactionContext.getTransaction() ?? this.db;
9
+ return KyselyTransactionContext.getTransaction(this.db) ?? this.db;
10
10
  }
11
11
  async create(instance) {
12
12
  const executor = this.getExecutor();
@@ -34,9 +34,9 @@ export class KyselyWorkflowInstanceStore {
34
34
  return this.mapRow(row);
35
35
  }
36
36
  async lockByUuid(uuid) {
37
- const trx = KyselyTransactionContext.getTransaction();
37
+ const trx = KyselyTransactionContext.getTransaction(this.db);
38
38
  if (!trx) {
39
- throw new Error("lockByUuid requires an active transaction");
39
+ throw new WorkflowError("lockByUuid requires an active transaction");
40
40
  }
41
41
  const row = await trx
42
42
  .selectFrom("workflow_instances")
@@ -70,9 +70,9 @@ export class KyselyWorkflowInstanceStore {
70
70
  }
71
71
  }
72
72
  async findExpired(limit, now) {
73
- const trx = KyselyTransactionContext.getTransaction();
73
+ const trx = KyselyTransactionContext.getTransaction(this.db);
74
74
  if (!trx) {
75
- throw new Error("findExpired requires an active transaction");
75
+ throw new WorkflowError("findExpired requires an active transaction");
76
76
  }
77
77
  const rows = await trx
78
78
  .selectFrom("workflow_instances")
@@ -1,9 +1,9 @@
1
- import type { Transaction } from "kysely";
1
+ import type { Kysely, Transaction } from "kysely";
2
2
  import type { WorkflowDatabase } from "./kysely-database.js";
3
3
  export declare const KyselyTransactionContext: {
4
- getTransaction(): Transaction<WorkflowDatabase> | undefined;
4
+ getTransaction(owner: Kysely<WorkflowDatabase>): Transaction<WorkflowDatabase> | undefined;
5
5
  /**
6
- * Executes callback with `trx` as the active transaction context.
6
+ * Executes callback with `trx` as the active transaction for `owner`.
7
7
  *
8
8
  * Generic so callers can pass `Transaction<MyDb & WorkflowDatabase>`
9
9
  * (Kysely is invariant in DB, so a non-generic signature would reject
@@ -11,6 +11,6 @@ export declare const KyselyTransactionContext: {
11
11
  * `Transaction<WorkflowDatabase>` which is safe — stores only access
12
12
  * workflow tables.
13
13
  */
14
- run<T, DB extends WorkflowDatabase = WorkflowDatabase>(trx: Transaction<DB>, callback: () => T): T;
14
+ run<T, DB extends WorkflowDatabase = WorkflowDatabase>(owner: Kysely<WorkflowDatabase>, trx: Transaction<DB>, callback: () => T): T;
15
15
  };
16
16
  //# sourceMappingURL=kysely-transaction-context.d.ts.map
@@ -1,11 +1,21 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
- const storage = new AsyncLocalStorage();
2
+ // One context per Kysely instance (or per pre-bound Transaction): a
3
+ // transaction on db A is invisible to stores and runners bound to db B.
4
+ const storages = new WeakMap();
5
+ function storageFor(owner) {
6
+ let storage = storages.get(owner);
7
+ if (!storage) {
8
+ storage = new AsyncLocalStorage();
9
+ storages.set(owner, storage);
10
+ }
11
+ return storage;
12
+ }
3
13
  export const KyselyTransactionContext = {
4
- getTransaction() {
5
- return storage.getStore();
14
+ getTransaction(owner) {
15
+ return storages.get(owner)?.getStore();
6
16
  },
7
17
  /**
8
- * Executes callback with `trx` as the active transaction context.
18
+ * Executes callback with `trx` as the active transaction for `owner`.
9
19
  *
10
20
  * Generic so callers can pass `Transaction<MyDb & WorkflowDatabase>`
11
21
  * (Kysely is invariant in DB, so a non-generic signature would reject
@@ -13,8 +23,8 @@ export const KyselyTransactionContext = {
13
23
  * `Transaction<WorkflowDatabase>` which is safe — stores only access
14
24
  * workflow tables.
15
25
  */
16
- run(trx, callback) {
17
- return storage.run(trx, callback);
26
+ run(owner, trx, callback) {
27
+ return storageFor(owner).run(trx, callback);
18
28
  },
19
29
  };
20
30
  //# sourceMappingURL=kysely-transaction-context.js.map
@@ -5,12 +5,12 @@ export class KyselyTransactionRunner {
5
5
  this.db = db;
6
6
  }
7
7
  async runInTransaction(callback) {
8
- const existing = KyselyTransactionContext.getTransaction();
8
+ const existing = KyselyTransactionContext.getTransaction(this.db);
9
9
  if (existing) {
10
10
  return callback();
11
11
  }
12
12
  return this.db.transaction().execute(async (trx) => {
13
- return KyselyTransactionContext.run(trx, callback);
13
+ return KyselyTransactionContext.run(this.db, trx, callback);
14
14
  });
15
15
  }
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duraflows/kysely",
3
- "version": "3.1.0",
3
+ "version": "4.0.1",
4
4
  "description": "PostgreSQL persistence adapter for duraflows using `kysely`. Integrates with kysely's type-safe query builder and AsyncLocalStorage-based transaction context.",
5
5
  "keywords": [
6
6
  "duraflows",
@@ -51,15 +51,15 @@
51
51
  "access": "public"
52
52
  },
53
53
  "peerDependencies": {
54
- "@duraflows/core": "^3.1.0",
55
- "kysely": "^0.29.2"
54
+ "@duraflows/core": "^4.0.1",
55
+ "kysely": "^0.29.4"
56
56
  },
57
57
  "devDependencies": {
58
- "@types/pg": "^8.11.0",
59
- "kysely": "^0.29.2",
60
- "pg": "^8.21.0",
61
- "@duraflows/core": "3.1.0",
62
- "@duraflows/pg": "3.1.0"
58
+ "@types/pg": "^8.20.4",
59
+ "kysely": "^0.29.4",
60
+ "pg": "^8.22.0",
61
+ "@duraflows/core": "4.0.1",
62
+ "@duraflows/pg": "4.0.1"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "tsc --build"