@duraflows/kysely 3.1.0 → 4.0.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.
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/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,7 +34,7 @@ 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
39
  throw new Error("lockByUuid requires an active transaction");
40
40
  }
@@ -70,7 +70,7 @@ 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
75
  throw new Error("findExpired requires an active transaction");
76
76
  }
@@ -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.0",
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",
54
+ "@duraflows/core": "^4.0.0",
55
55
  "kysely": "^0.29.2"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/pg": "^8.11.0",
59
59
  "kysely": "^0.29.2",
60
60
  "pg": "^8.21.0",
61
- "@duraflows/core": "3.1.0",
62
- "@duraflows/pg": "3.1.0"
61
+ "@duraflows/core": "4.0.0",
62
+ "@duraflows/pg": "4.0.0"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "tsc --build"