@warlock.js/cascade 5.19.0 → 5.20.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 (39) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/cjs/index.cjs +78 -7
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/context/database-transaction-context.d.mts +10 -0
  5. package/esm/context/database-transaction-context.d.mts.map +1 -1
  6. package/esm/context/database-transaction-context.mjs +17 -0
  7. package/esm/context/database-transaction-context.mjs.map +1 -1
  8. package/esm/drivers/mongodb/mongodb-driver.d.mts.map +1 -1
  9. package/esm/drivers/mongodb/mongodb-driver.mjs +13 -5
  10. package/esm/drivers/mongodb/mongodb-driver.mjs.map +1 -1
  11. package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
  12. package/esm/drivers/postgres/postgres-driver.mjs +8 -3
  13. package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
  14. package/esm/index.d.mts +2 -1
  15. package/esm/index.mjs +2 -1
  16. package/esm/migration/migration-runner.mjs +1 -1
  17. package/esm/transactions/after-commit.d.mts +24 -0
  18. package/esm/transactions/after-commit.d.mts.map +1 -0
  19. package/esm/transactions/after-commit.mjs +47 -0
  20. package/esm/transactions/after-commit.mjs.map +1 -0
  21. package/llms-full.txt +2783 -2766
  22. package/llms.txt +15 -15
  23. package/package.json +6 -6
  24. package/skills/aggregate-data/SKILL.md +165 -165
  25. package/skills/alter-migration/SKILL.md +531 -531
  26. package/skills/configure-delete-strategy/SKILL.md +130 -130
  27. package/skills/define-model/SKILL.md +205 -205
  28. package/skills/define-relations/SKILL.md +171 -171
  29. package/skills/index.md +23 -0
  30. package/skills/manage-data-sources/SKILL.md +140 -140
  31. package/skills/manage-transactions/SKILL.md +208 -191
  32. package/skills/paginate-results/SKILL.md +122 -122
  33. package/skills/perform-atomic-ops/SKILL.md +156 -156
  34. package/skills/query-data/SKILL.md +213 -213
  35. package/skills/run-cascade-cli/SKILL.md +125 -125
  36. package/skills/search-by-vector/SKILL.md +127 -127
  37. package/skills/subscribe-to-model-events/SKILL.md +148 -148
  38. package/skills/track-changes/SKILL.md +127 -127
  39. package/skills/write-migration/SKILL.md +206 -206
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to `@warlock.js/cascade` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.20.0 - 2026-09-24
8
+
9
+ ### Added
10
+
11
+ - `afterCommit(fn)` — run a side effect only once the transaction has committed. Inside a transaction, `fn` is queued and runs after the outermost COMMIT (in order, awaited one by one); it is discarded on rollback or a failed COMMIT. Outside a transaction, it runs on the next microtask. Errors are logged and never change the transaction result. Use it in model event listeners (`saved`, `created`, ...) for cache clears, sitemap regeneration and emails.
12
+
7
13
  ## 5.19.0 - 2026-09-23
8
14
 
9
15
  ### Changed
package/cjs/index.cjs CHANGED
@@ -27,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
 
28
28
  //#endregion
29
29
  let _warlock_js_context = require("@warlock.js/context");
30
+ let _warlock_js_logger = require("@warlock.js/logger");
30
31
  let node_events = require("node:events");
31
32
  let _mongez_reinforcements = require("@mongez/reinforcements");
32
33
  let _mongez_supportive_is = require("@mongez/supportive-is");
@@ -34,7 +35,6 @@ let _mongez_events = require("@mongez/events");
34
35
  _mongez_events = __toESM(_mongez_events, 1);
35
36
  let _warlock_js_seal = require("@warlock.js/seal");
36
37
  let _mongez_copper = require("@mongez/copper");
37
- let _warlock_js_logger = require("@warlock.js/logger");
38
38
  let fs = require("fs");
39
39
  fs = __toESM(fs, 1);
40
40
  let path = require("path");
@@ -98,6 +98,23 @@ var DatabaseTransactionContext = class extends _warlock_js_context.Context {
98
98
  this.set("session", session);
99
99
  }
100
100
  /**
101
+ * Queue a callback to run once the active transaction commits
102
+ */
103
+ addAfterCommit(fn) {
104
+ const queue = this.get("afterCommit") ?? [];
105
+ queue.push(fn);
106
+ this.set("afterCommit", queue);
107
+ }
108
+ /**
109
+ * Take (and empty) the queued after-commit callbacks.
110
+ * Must be called before `exit()`, which clears the store.
111
+ */
112
+ takeAfterCommit() {
113
+ const queue = this.get("afterCommit") ?? [];
114
+ this.set("afterCommit", []);
115
+ return queue;
116
+ }
117
+ /**
101
118
  * Exit the transaction context
102
119
  */
103
120
  exit() {
@@ -113,6 +130,48 @@ var DatabaseTransactionContext = class extends _warlock_js_context.Context {
113
130
  const databaseTransactionContext = new DatabaseTransactionContext();
114
131
  _warlock_js_context.contextManager.register("db.transaction", databaseTransactionContext);
115
132
 
133
+ //#endregion
134
+ //#region ../cascade/src/transactions/after-commit.ts
135
+ function reportFailure(error) {
136
+ _warlock_js_logger.log.error("database", "afterCommit", `[cascade] afterCommit callback failed: ${error}`);
137
+ }
138
+ /**
139
+ * Run a callback only once the current transaction has COMMITTED.
140
+ *
141
+ * Model events (`saved`, `created`, `updated`, `deleted`) fire INSIDE the
142
+ * transaction, before COMMIT. Anything that must observe committed data
143
+ * (cache invalidation, sitemap regeneration, webhooks) belongs here.
144
+ *
145
+ * - Inside a transaction: queued, run after the outermost COMMIT, in order,
146
+ * awaited one by one. Discarded on rollback or a failed COMMIT.
147
+ * - Outside a transaction: run on the next microtask (not awaited by the caller).
148
+ * - A callback that throws is logged; it never affects the transaction result
149
+ * or the remaining callbacks.
150
+ * - Callbacks run after the transaction context has exited, so any DB work
151
+ * they do is outside the finished transaction.
152
+ *
153
+ * @example
154
+ * Product.events().onSaved(() => afterCommit(() => regenerateSitemap()));
155
+ */
156
+ function afterCommit(fn) {
157
+ if (databaseTransactionContext.hasActiveTransaction()) {
158
+ databaseTransactionContext.addAfterCommit(fn);
159
+ return;
160
+ }
161
+ Promise.resolve().then(fn).catch(reportFailure);
162
+ }
163
+ /**
164
+ * Run committed callbacks sequentially. Never throws.
165
+ * Drivers call this after a successful COMMIT and after the context exited.
166
+ */
167
+ async function flushAfterCommit(callbacks) {
168
+ for (const callback of callbacks) try {
169
+ await callback();
170
+ } catch (error) {
171
+ reportFailure(error);
172
+ }
173
+ }
174
+
116
175
  //#endregion
117
176
  //#region ../cascade/src/data-source/data-source.ts
118
177
  /**
@@ -13979,15 +14038,18 @@ var MongoDbDriver = class {
13979
14038
  await session.startTransaction(this.transactionOptions);
13980
14039
  databaseTransactionContext.enter({ session });
13981
14040
  let finished = false;
13982
- const finalize = async (operation) => {
14041
+ const finalize = async (operation, committing = false) => {
13983
14042
  if (finished) return;
14043
+ let committedCallbacks = [];
13984
14044
  try {
13985
14045
  await operation();
14046
+ if (committing) committedCallbacks = databaseTransactionContext.takeAfterCommit();
13986
14047
  } finally {
13987
14048
  finished = true;
13988
14049
  databaseTransactionContext.exit();
13989
14050
  await session.endSession().catch(() => void 0);
13990
14051
  }
14052
+ await flushAfterCommit(committedCallbacks);
13991
14053
  };
13992
14054
  return {
13993
14055
  context: session,
@@ -13999,7 +14061,7 @@ var MongoDbDriver = class {
13999
14061
  await session.abortTransaction().catch(() => void 0);
14000
14062
  throw error;
14001
14063
  }
14002
- });
14064
+ }, true);
14003
14065
  },
14004
14066
  rollback: async () => {
14005
14067
  await finalize(async () => {
@@ -14030,6 +14092,8 @@ var MongoDbDriver = class {
14030
14092
  if (databaseTransactionContext.hasActiveTransaction()) return fn(ctx);
14031
14093
  await this.ensureReplicaSetAvailable();
14032
14094
  const session = this.getClientInstance().startSession();
14095
+ let committedCallbacks = [];
14096
+ let result;
14033
14097
  try {
14034
14098
  await session.startTransaction({
14035
14099
  ...this.transactionOptions,
@@ -14037,9 +14101,9 @@ var MongoDbDriver = class {
14037
14101
  });
14038
14102
  databaseTransactionContext.enter({ session });
14039
14103
  try {
14040
- const result = await fn(ctx);
14104
+ result = await fn(ctx);
14041
14105
  await session.commitTransaction();
14042
- return result;
14106
+ committedCallbacks = databaseTransactionContext.takeAfterCommit();
14043
14107
  } catch (error) {
14044
14108
  await session.abortTransaction().catch(() => void 0);
14045
14109
  throw error;
@@ -14049,6 +14113,8 @@ var MongoDbDriver = class {
14049
14113
  } finally {
14050
14114
  await session.endSession().catch(() => void 0);
14051
14115
  }
14116
+ await flushAfterCommit(committedCallbacks);
14117
+ return result;
14052
14118
  }
14053
14119
  /**
14054
14120
  * Execute atomic operations (typically $inc/$set style updates) against documents.
@@ -18723,11 +18789,13 @@ var PostgresDriver = class {
18723
18789
  const tx = await this.beginTransaction(options);
18724
18790
  databaseTransactionContext.enter({ session: tx.context });
18725
18791
  let commitStarted = false;
18792
+ let committedCallbacks = [];
18793
+ let result;
18726
18794
  try {
18727
- const result = await fn(ctx);
18795
+ result = await fn(ctx);
18728
18796
  commitStarted = true;
18729
18797
  await tx.commit();
18730
- return result;
18798
+ committedCallbacks = databaseTransactionContext.takeAfterCommit();
18731
18799
  } catch (error) {
18732
18800
  if (commitStarted) _warlock_js_logger.log.error(`database.postgress`, "transaction", "Transaction COMMIT failed; client discarded, no rollback issued");
18733
18801
  else try {
@@ -18740,6 +18808,8 @@ var PostgresDriver = class {
18740
18808
  } finally {
18741
18809
  databaseTransactionContext.exit();
18742
18810
  }
18811
+ await flushAfterCommit(committedCallbacks);
18812
+ return result;
18743
18813
  }
18744
18814
  /**
18745
18815
  * Perform an atomic update operation.
@@ -23758,6 +23828,7 @@ exports.UnsafeRawExpressionError = UnsafeRawExpressionError;
23758
23828
  exports.UnsupportedLeanOperationError = UnsupportedLeanOperationError;
23759
23829
  exports.UnsupportedQueryOperationError = UnsupportedQueryOperationError;
23760
23830
  exports.UnsupportedUpdateOperationError = UnsupportedUpdateOperationError;
23831
+ exports.afterCommit = afterCommit;
23761
23832
  exports.arrayBigInt = arrayBigInt;
23762
23833
  exports.arrayBoolean = arrayBoolean;
23763
23834
  exports.arrayDate = arrayDate;