sc-dev-deploy/lib/context.js
2026-06-01 16:43:43 -05:00

65 lines
1.8 KiB
JavaScript

// Per-async-flow context for the mutation wraps.
//
// AsyncLocalStorage gives every wrap a stack of in-flight op_ids so that ops
// triggered while another op is running (e.g. cascading field deletes inside
// a table delete) can attach themselves to the outer op as parent_op_id, and
// share its correlation_id.
const { AsyncLocalStorage } = require("async_hooks");
const { randomUuid } = require("./ids");
const storage = new AsyncLocalStorage();
const enterOp = async (opId, fn) => {
const current = storage.getStore();
const correlationId = current ? current.correlationId : randomUuid();
const parentStack = current ? current.stack : [];
const newStore = {
stack: [...parentStack, opId],
correlationId: correlationId
};
return await storage.run(newStore, fn);
};
const currentParentOpId = () => {
const store = storage.getStore();
if (!store || store.stack.length < 2) {
return null;
}
return store.stack[store.stack.length - 2];
};
const currentCorrelationId = () => {
const store = storage.getStore();
return store ? store.correlationId : null;
};
// Suppression mode: when applying ingested ops we run the underlying Saltcorn
// model methods but want the CRUD wraps to pass through silently — no journal
// writes, no entity_id assignment. The apply handler manages those side effects
// itself with the source-env's UUID.
const runSuppressed = async (fn) => {
const current = storage.getStore() || { stack: [], correlationId: null };
return await storage.run({ ...current, suppressed: true }, fn);
};
const isSuppressed = () => {
const s = storage.getStore();
return !!(s && s.suppressed);
};
module.exports = {
enterOp,
currentParentOpId,
currentCorrelationId,
runSuppressed,
isSuppressed
};