@porulle/core 0.34.0 → 0.35.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/dist/kernel/database/adapter.d.ts.map +1 -1
- package/dist/kernel/database/adapter.js +23 -1
- package/dist/kernel/hooks/deferred.d.ts +4 -0
- package/dist/kernel/hooks/deferred.d.ts.map +1 -0
- package/dist/kernel/hooks/deferred.js +44 -0
- package/dist/kernel/hooks/executor.d.ts +1 -1
- package/dist/kernel/hooks/executor.d.ts.map +1 -1
- package/dist/kernel/hooks/executor.js +50 -16
- package/dist/kernel/hooks/registry.d.ts +4 -0
- package/dist/kernel/hooks/registry.d.ts.map +1 -1
- package/dist/kernel/hooks/registry.js +12 -0
- package/dist/modules/catalog/entity-service.js +7 -7
- package/dist/modules/customers/service.js +4 -4
- package/dist/modules/fulfillment/service.js +2 -2
- package/dist/modules/inventory/service.d.ts.map +1 -1
- package/dist/modules/inventory/service.js +1 -1
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +3 -3
- package/dist/modules/promotions/service.js +3 -3
- package/dist/runtime/kernel-register-hooks.js +1 -1
- package/dist/test-utils/create-pglite-adapter.d.ts +5 -1
- package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
- package/dist/test-utils/create-pglite-adapter.js +15 -11
- package/package.json +1 -1
- package/src/kernel/database/adapter.ts +24 -1
- package/src/kernel/hooks/deferred.ts +53 -0
- package/src/kernel/hooks/executor.ts +48 -11
- package/src/kernel/hooks/registry.ts +15 -0
- package/src/modules/catalog/entity-service.ts +7 -7
- package/src/modules/customers/service.ts +4 -4
- package/src/modules/fulfillment/service.ts +2 -2
- package/src/modules/inventory/service.ts +1 -0
- package/src/modules/orders/service.ts +3 -1
- package/src/modules/promotions/service.ts +3 -3
- package/src/runtime/kernel-register-hooks.ts +1 -1
- package/src/test-utils/create-pglite-adapter.ts +20 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/database/adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/kernel/database/adapter.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAAC,SAAS,GAAG,OAAO,EAAE,YAAY,GAAG,OAAO;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjE;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,eAAe,CAAC;CAC1B;AASD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAMpC;AAwDD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,8BAA8B,GAAG,eAAe,CAY/F"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDeferredHooks } from "../hooks/deferred.js";
|
|
1
2
|
/**
|
|
2
3
|
* Marker used to retrieve the raw, un-normalized driver from a wrapped db.
|
|
3
4
|
* Tools that drive the driver directly (drizzle-kit's `pushSchema`, which
|
|
@@ -45,6 +46,24 @@ function normalizeExecuteShape(db) {
|
|
|
45
46
|
return result;
|
|
46
47
|
};
|
|
47
48
|
}
|
|
49
|
+
if (prop === "transaction") {
|
|
50
|
+
const orig = Reflect.get(target, prop, target);
|
|
51
|
+
if (typeof orig !== "function")
|
|
52
|
+
return orig;
|
|
53
|
+
// The OTHER half of the after-commit drain, and the one the card this shipped for
|
|
54
|
+
// actually needs. `createDatabaseConnection().transaction` covers core services and REST
|
|
55
|
+
// routes, but a plugin does not get the adapter — it is handed this db HANDLE as
|
|
56
|
+
// `ctx.db` (TaskContext.db is a DrizzleDatabase) and calls `ctx.db.transaction(...)`.
|
|
57
|
+
// `plugin-channel-connector` constructs its service with no transaction argument in
|
|
58
|
+
// production and therefore imports every product through exactly this path, so without
|
|
59
|
+
// the wrapper here the fix would be green in every suite (they inject the adapter's
|
|
60
|
+
// transaction explicitly) and inert on the deployed import.
|
|
61
|
+
//
|
|
62
|
+
// Double-wrapping is safe: `withDeferredHooks` joins an existing store and drains only at
|
|
63
|
+
// the outermost boundary, so adapter.transaction -> db.transaction nests without draining
|
|
64
|
+
// twice.
|
|
65
|
+
return (fn) => withDeferredHooks(() => orig.call(target, fn));
|
|
66
|
+
}
|
|
48
67
|
const value = Reflect.get(target, prop, target);
|
|
49
68
|
// Bind methods to the real instance so drizzle's internals (incl. any
|
|
50
69
|
// private fields) are never accessed through the proxy.
|
|
@@ -58,7 +77,10 @@ export function createDatabaseConnection(input) {
|
|
|
58
77
|
provider: adapter.provider,
|
|
59
78
|
db: normalizeExecuteShape(adapter.db),
|
|
60
79
|
transaction(fn) {
|
|
61
|
-
return
|
|
80
|
+
return withDeferredHooks(() =>
|
|
81
|
+
// adapter.transaction resolving IS the commit, so draining after it
|
|
82
|
+
// resolves is draining after commit.
|
|
83
|
+
adapter.transaction((tx) => fn(normalizeExecuteShape(tx))));
|
|
62
84
|
},
|
|
63
85
|
};
|
|
64
86
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../../src/kernel/hooks/deferred.ts"],"names":[],"mappings":"AAQA,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAKpE;AAcD,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAqB3E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const deferredStorage = new AsyncLocalStorage();
|
|
3
|
+
export function isInsideTransaction() {
|
|
4
|
+
return deferredStorage.getStore() != null;
|
|
5
|
+
}
|
|
6
|
+
export function deferAfterCommit(thunk) {
|
|
7
|
+
const pending = deferredStorage.getStore();
|
|
8
|
+
if (!pending)
|
|
9
|
+
return false;
|
|
10
|
+
pending.deferred.push(thunk);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
async function drainDeferred(pending) {
|
|
14
|
+
// `for...of` over a live array on purpose: a deferred hook that defers another one is drained
|
|
15
|
+
// in the same pass rather than being dropped.
|
|
16
|
+
for (const thunk of pending.deferred) {
|
|
17
|
+
try {
|
|
18
|
+
await thunk();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Each thunk logs its own hook failure (see runAfterHooks); swallow so siblings still run.
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function withDeferredHooks(fn) {
|
|
26
|
+
const existing = deferredStorage.getStore();
|
|
27
|
+
if (existing) {
|
|
28
|
+
return fn();
|
|
29
|
+
}
|
|
30
|
+
const pending = { deferred: [] };
|
|
31
|
+
// A throw propagates without reaching the drain: a rolled-back transaction discards its deferred
|
|
32
|
+
// hooks rather than announcing a write that never happened. Stated rather than implied.
|
|
33
|
+
const result = await deferredStorage.run(pending, fn);
|
|
34
|
+
// AWAITED, never `void`. `adapter.transaction` resolving IS the commit, so the hooks below run
|
|
35
|
+
// after commit — and they must still run INSIDE the invocation that started them. The Workers
|
|
36
|
+
// runtime discards a promise that is neither awaited nor handed to `waitUntil` once the
|
|
37
|
+
// invocation ends, which this codebase has already paid for once: a fire-and-forget queue nudge
|
|
38
|
+
// wrote 104 outbox rows and sent ZERO messages on the deployed Worker while every Node test
|
|
39
|
+
// passed. Detaching this drain would do the same to every webhook and search-index update in the
|
|
40
|
+
// product. "After commit" is the requirement; "after the service method returns" is not, and is
|
|
41
|
+
// what tempts you to detach it.
|
|
42
|
+
await drainDeferred(pending);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
@@ -9,5 +9,5 @@ export interface HookReport {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function mergeHookReports(a: HookReport, b: HookReport): HookReport;
|
|
11
11
|
export declare function runBeforeHooks<T>(hooks: BeforeHook<T>[], data: T, operation: HookOperation, context: HookContext): Promise<T>;
|
|
12
|
-
export declare function runAfterHooks<T>(hooks: AfterHook<T>[], originalData: T | null, committedResult: T, operation: HookOperation, context: HookContext): Promise<HookReport>;
|
|
12
|
+
export declare function runAfterHooks<T>(hooks: AfterHook<T>[], originalData: T | null, committedResult: T, operation: HookOperation, context: HookContext, runsInTransaction?: (hook: AfterHook<T>) => boolean): Promise<HookReport>;
|
|
13
13
|
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/kernel/hooks/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/kernel/hooks/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGpF,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAKzE;AAqCD,wBAAsB,cAAc,CAAC,CAAC,EACpC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,EACtB,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EACrB,YAAY,EAAE,CAAC,GAAG,IAAI,EACtB,eAAe,EAAE,CAAC,EAClB,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,EACpB,iBAAiB,GAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAqB,GAC/D,OAAO,CAAC,UAAU,CAAC,CA6DrB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { deferAfterCommit } from "./deferred.js";
|
|
1
2
|
export function mergeHookReports(a, b) {
|
|
2
3
|
return {
|
|
3
4
|
errors: [...a.errors, ...b.errors],
|
|
@@ -47,27 +48,60 @@ export async function runBeforeHooks(hooks, data, operation, context) {
|
|
|
47
48
|
}
|
|
48
49
|
return current;
|
|
49
50
|
}
|
|
50
|
-
export async function runAfterHooks(hooks, originalData, committedResult, operation, context) {
|
|
51
|
+
export async function runAfterHooks(hooks, originalData, committedResult, operation, context, runsInTransaction = () => false) {
|
|
51
52
|
const errors = [];
|
|
52
53
|
for (const hook of hooks) {
|
|
53
54
|
const hookName = hook.name || "(anonymous afterHook)";
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
context
|
|
60
|
-
|
|
55
|
+
const runHook = () => withTimeout(hook({
|
|
56
|
+
data: originalData,
|
|
57
|
+
result: committedResult,
|
|
58
|
+
operation,
|
|
59
|
+
context: runsInTransaction(hook)
|
|
60
|
+
? context
|
|
61
|
+
: { ...context, tx: null },
|
|
62
|
+
}), HOOK_TIMEOUT_MS, hookName);
|
|
63
|
+
if (runsInTransaction(hook)) {
|
|
64
|
+
try {
|
|
65
|
+
await runHook();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
errors.push({
|
|
69
|
+
hookName,
|
|
70
|
+
message: error instanceof Error ? error.message : String(error),
|
|
71
|
+
});
|
|
72
|
+
context.logger.error(`After-hook "${hookName}" failed`, {
|
|
73
|
+
error,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
61
77
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
const deferred = deferAfterCommit(async () => {
|
|
79
|
+
try {
|
|
80
|
+
await runHook();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
context.logger.error(`After-commit hook "${hookName}" failed`, {
|
|
84
|
+
error,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
if (!deferred) {
|
|
89
|
+
try {
|
|
90
|
+
await runHook();
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
errors.push({
|
|
94
|
+
hookName,
|
|
95
|
+
message: error instanceof Error ? error.message : String(error),
|
|
96
|
+
});
|
|
97
|
+
context.logger.error(`After-hook "${hookName}" failed`, {
|
|
98
|
+
error,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
70
101
|
}
|
|
71
102
|
}
|
|
103
|
+
// After-commit hook failures are logged when the transaction drains; they
|
|
104
|
+
// cannot appear here because deferred hooks run after commit, once the
|
|
105
|
+
// service method has already returned its Result.
|
|
72
106
|
return { errors, hasErrors: errors.length > 0 };
|
|
73
107
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export type HookHandler = (...args: never[]) => unknown;
|
|
2
2
|
export declare class HookRegistry {
|
|
3
3
|
private registry;
|
|
4
|
+
private inTransactionHandlers;
|
|
4
5
|
private logger?;
|
|
5
6
|
registerConfigHooks(hookName: string, handlers: HookHandler[]): void;
|
|
6
7
|
append(hookName: string, handler: HookHandler): void;
|
|
8
|
+
appendInTransaction(hookName: string, handler: HookHandler): void;
|
|
7
9
|
prepend(hookName: string, handler: HookHandler): void;
|
|
10
|
+
prependInTransaction(hookName: string, handler: HookHandler): void;
|
|
11
|
+
runsInTransaction(handler: HookHandler): boolean;
|
|
8
12
|
resolve(hookName: string): HookHandler[];
|
|
9
13
|
/**
|
|
10
14
|
* Emit a plugin event to all registered listeners.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/kernel/hooks/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAQxD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,MAAM,CAAC,CAAiE;IAEhF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI;IAKpE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKpD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKrD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE;IAMxC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAAG,IAAI;IAIjF,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,OAAO,CAAC,WAAW;CASpB"}
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/kernel/hooks/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAQxD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,MAAM,CAAC,CAAiE;IAEhF,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI;IAKpE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKpD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKrD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAKlE,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO;IAIhD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE;IAMxC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAAG,IAAI;IAIjF,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export class HookRegistry {
|
|
2
2
|
registry = new Map();
|
|
3
|
+
inTransactionHandlers = new WeakSet();
|
|
3
4
|
logger;
|
|
4
5
|
registerConfigHooks(hookName, handlers) {
|
|
5
6
|
this.ensureEntry(hookName);
|
|
@@ -9,10 +10,21 @@ export class HookRegistry {
|
|
|
9
10
|
this.ensureEntry(hookName);
|
|
10
11
|
this.registry.get(hookName).appended.push(handler);
|
|
11
12
|
}
|
|
13
|
+
appendInTransaction(hookName, handler) {
|
|
14
|
+
this.inTransactionHandlers.add(handler);
|
|
15
|
+
this.append(hookName, handler);
|
|
16
|
+
}
|
|
12
17
|
prepend(hookName, handler) {
|
|
13
18
|
this.ensureEntry(hookName);
|
|
14
19
|
this.registry.get(hookName).prepended.push(handler);
|
|
15
20
|
}
|
|
21
|
+
prependInTransaction(hookName, handler) {
|
|
22
|
+
this.inTransactionHandlers.add(handler);
|
|
23
|
+
this.prepend(hookName, handler);
|
|
24
|
+
}
|
|
25
|
+
runsInTransaction(handler) {
|
|
26
|
+
return this.inTransactionHandlers.has(handler);
|
|
27
|
+
}
|
|
16
28
|
resolve(hookName) {
|
|
17
29
|
const entry = this.registry.get(hookName);
|
|
18
30
|
if (!entry)
|
|
@@ -224,7 +224,7 @@ export class EntityService {
|
|
|
224
224
|
return Err(new CommerceConflictError(`Entity with slug ${input.slug} already exists.`));
|
|
225
225
|
const beforeHooks = this.deps.hooks.resolve("catalog.beforeCreate");
|
|
226
226
|
const afterHooks = this.deps.hooks.resolve("catalog.afterCreate");
|
|
227
|
-
const context =
|
|
227
|
+
const context = catalogHookContext(this.deps, actor, ctx, "create");
|
|
228
228
|
const processedInput = await runBeforeHooks(beforeHooks, input, "create", context);
|
|
229
229
|
if (processedInput.sourceStoreId != null)
|
|
230
230
|
assertPermission(actor, "catalog:sync");
|
|
@@ -238,7 +238,7 @@ export class EntityService {
|
|
|
238
238
|
await this.repo.createAttribute({ entityId: entity.id, locale: processedInput.attributes.locale ?? "en", title: processedInput.attributes.title, subtitle: processedInput.attributes.subtitle, description: processedInput.attributes.description, richDescription: processedInput.attributes.richDescription, seoTitle: processedInput.attributes.seoTitle, seoDescription: processedInput.attributes.seoDescription }, ctx);
|
|
239
239
|
}
|
|
240
240
|
await this.writeCustomFields(entity.id, customFieldsResult.value, ctx);
|
|
241
|
-
const hookReport = await runAfterHooks(afterHooks, null, entity, "create", context);
|
|
241
|
+
const hookReport = await runAfterHooks(afterHooks, null, entity, "create", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
242
242
|
const hydrated = await this.hydrateEntity(entity, undefined, ctx);
|
|
243
243
|
return Ok(hydrated, hookReport.hasErrors ? { hookErrors: hookReport.errors } : undefined);
|
|
244
244
|
}
|
|
@@ -266,7 +266,7 @@ export class EntityService {
|
|
|
266
266
|
if (!updated)
|
|
267
267
|
return Err(new CommerceNotFoundError("Entity not found."));
|
|
268
268
|
await this.writeCustomFields(existing.id, customFieldsResult.value, txCtx, true);
|
|
269
|
-
const hookReport = await runAfterHooks(afterHooks, existing, updated, "update", context);
|
|
269
|
+
const hookReport = await runAfterHooks(afterHooks, existing, updated, "update", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
270
270
|
const hydrated = await this.hydrateEntity(updated, undefined, txCtx);
|
|
271
271
|
return Ok(hydrated, hookReport.hasErrors ? { hookErrors: hookReport.errors } : undefined);
|
|
272
272
|
}
|
|
@@ -328,7 +328,7 @@ export class EntityService {
|
|
|
328
328
|
}
|
|
329
329
|
const result = await this.hydrateEntity(entity, processed.options ?? options, ctx);
|
|
330
330
|
const entityAfterHooks = this.deps.hooks.resolve(`catalog.${entity.type}.afterRead`);
|
|
331
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context), await runAfterHooks(entityAfterHooks, null, result, "read", context));
|
|
331
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
332
332
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
333
333
|
}
|
|
334
334
|
/**
|
|
@@ -380,7 +380,7 @@ export class EntityService {
|
|
|
380
380
|
}
|
|
381
381
|
const result = await this.hydrateEntity(entity, processed.options ?? options, ctx);
|
|
382
382
|
const entityAfterHooks = this.deps.hooks.resolve(`catalog.${entity.type}.afterRead`);
|
|
383
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context), await runAfterHooks(entityAfterHooks, null, result, "read", context));
|
|
383
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
384
384
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
385
385
|
}
|
|
386
386
|
async list(params, actor, ctx) {
|
|
@@ -457,7 +457,7 @@ export class EntityService {
|
|
|
457
457
|
const result = { items: hydratedItems, pagination: paged.pagination };
|
|
458
458
|
const listTypeFilter = processed.filter?.type;
|
|
459
459
|
const entityAfterHooks = listTypeFilter ? this.deps.hooks.resolve(`catalog.${listTypeFilter}.afterList`) : [];
|
|
460
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "list", context), await runAfterHooks(entityAfterHooks, null, result, "list", context));
|
|
460
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "list", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "list", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
461
461
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
462
462
|
}
|
|
463
463
|
async changeStatus(id, status, actor, ctx) {
|
|
@@ -530,7 +530,7 @@ export class EntityService {
|
|
|
530
530
|
const afterHooks = this.deps.hooks.resolve("catalog.afterUpdate");
|
|
531
531
|
const context = catalogHookContext(this.deps, actor, ctx, "update");
|
|
532
532
|
context.context.changedFieldPaths = changedFieldPaths;
|
|
533
|
-
await runAfterHooks(afterHooks, entity, entity, "update", context);
|
|
533
|
+
await runAfterHooks(afterHooks, entity, entity, "update", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
534
534
|
}
|
|
535
535
|
return Ok(undefined);
|
|
536
536
|
}
|
|
@@ -54,7 +54,7 @@ export class CustomerService {
|
|
|
54
54
|
}, ctx);
|
|
55
55
|
const afterHooks = this.deps.hooks.resolve("customers.afterCreate");
|
|
56
56
|
const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
57
|
-
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
57
|
+
await runAfterHooks(afterHooks, null, customer, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
58
58
|
return Ok(customer);
|
|
59
59
|
}
|
|
60
60
|
// ─── Customer interactions (clienteling notes / visits / calls) ──────────
|
|
@@ -138,7 +138,7 @@ export class CustomerService {
|
|
|
138
138
|
}, ctx);
|
|
139
139
|
const afterHooks = this.deps.hooks.resolve("customers.afterCreate");
|
|
140
140
|
const hctx = hookContext(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
141
|
-
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
141
|
+
await runAfterHooks(afterHooks, null, customer, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
142
142
|
return customer;
|
|
143
143
|
}
|
|
144
144
|
async list(actor, ctx) {
|
|
@@ -187,7 +187,7 @@ export class CustomerService {
|
|
|
187
187
|
return Err(new CommerceNotFoundError("Customer not found."));
|
|
188
188
|
const afterHooks = this.deps.hooks.resolve("customers.afterUpdate");
|
|
189
189
|
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
190
|
-
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
190
|
+
await runAfterHooks(afterHooks, existing, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
191
191
|
return Ok(updated);
|
|
192
192
|
}
|
|
193
193
|
async updateByUserId(userId, updates, actor, ctx) {
|
|
@@ -200,7 +200,7 @@ export class CustomerService {
|
|
|
200
200
|
}
|
|
201
201
|
const afterHooks = this.deps.hooks.resolve("customers.afterUpdate");
|
|
202
202
|
const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
203
|
-
await runAfterHooks(afterHooks, customer, updated, "update", hctx);
|
|
203
|
+
await runAfterHooks(afterHooks, customer, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
204
204
|
return Ok(updated);
|
|
205
205
|
}
|
|
206
206
|
async getAddresses(userId, actor, ctx) {
|
|
@@ -188,7 +188,7 @@ export class FulfillmentService {
|
|
|
188
188
|
database: { db: this.deps.database.db },
|
|
189
189
|
commerceConfig: this.deps.config,
|
|
190
190
|
});
|
|
191
|
-
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
191
|
+
await runAfterHooks(afterHooks, null, record, "create", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
192
192
|
// Create a fulfillment line item linking this fulfillment to the order line item
|
|
193
193
|
for (const li of record.lineItems) {
|
|
194
194
|
await this.deps.repository.createLineItem({
|
|
@@ -288,7 +288,7 @@ export class FulfillmentService {
|
|
|
288
288
|
database: { db: this.deps.database.db },
|
|
289
289
|
commerceConfig: this.deps.config,
|
|
290
290
|
});
|
|
291
|
-
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
291
|
+
await runAfterHooks(afterHooks, null, record, "create", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
292
292
|
return Ok(record);
|
|
293
293
|
}
|
|
294
294
|
async getByOrderId(orderId, ctx) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/inventory/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAW5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACtF,OAAO,EACL,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACvG,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAEvG,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,mBAAmB,CAAC;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,qBAAa,gBAAgB;IAGf,OAAO,CAAC,IAAI;IAFxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEvB,IAAI,EAAE,oBAAoB;YAIhC,eAAe;YAQf,aAAa;IA6BrB,eAAe,CACnB,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,EACzB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IA4BvB,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IASnF,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,EACf,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAcpB,UAAU,CACd,MAAM,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EACpD,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IAyB9B,aAAa,CACjB,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IASpC,mBAAmB,CACvB,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,SAAS,EACf,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GACnB,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IAS9B,OAAO,CACX,KAAK,EAAE,qBAAqB,EAC5B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAyDlB,OAAO,CACX,KAAK,EAAE,qBAAqB,EAC5B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAqDxB;;;;;;OAMG;IACG,cAAc,CAClB,KAAK,EAAE,oBAAoB,EAC3B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CACR,MAAM,CAAC;QACL,KAAK,EAAE,cAAc,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CACH;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/inventory/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -240,7 +240,7 @@ export class InventoryService {
|
|
|
240
240
|
commerceConfig: this.deps.config,
|
|
241
241
|
});
|
|
242
242
|
const afterHooks = this.deps.hooks.resolve("inventory.afterAdjust");
|
|
243
|
-
await runAfterHooks(afterHooks, null, level, "update", hookCtx);
|
|
243
|
+
await runAfterHooks(afterHooks, null, level, "update", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
244
244
|
return Ok({ level, before, after, delta, movementId: movement.id });
|
|
245
245
|
};
|
|
246
246
|
return this.withTransaction(ctx, async (tx) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/orders/service.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/orders/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -375,7 +375,7 @@ export class OrderService {
|
|
|
375
375
|
changedBy: actor?.userId ?? "system",
|
|
376
376
|
}, ctx);
|
|
377
377
|
const hydrated = await this.hydrateOrder(order, ctx);
|
|
378
|
-
const report = await runAfterHooks(afterHooks, null, hydrated, "create", hookCtx);
|
|
378
|
+
const report = await runAfterHooks(afterHooks, null, hydrated, "create", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
379
379
|
return Ok(hydrated, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
380
380
|
}
|
|
381
381
|
async getById(id, actor, ctx, guestCredential) {
|
|
@@ -405,7 +405,7 @@ export class OrderService {
|
|
|
405
405
|
const afterGetHooks = this.deps.hooks.resolve("orders.afterGet");
|
|
406
406
|
if (afterGetHooks.length > 0) {
|
|
407
407
|
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
408
|
-
await runAfterHooks(afterGetHooks, null, hydrated, "read", hookCtx);
|
|
408
|
+
await runAfterHooks(afterGetHooks, null, hydrated, "read", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
409
409
|
}
|
|
410
410
|
return Ok(hydrated);
|
|
411
411
|
}
|
|
@@ -675,7 +675,7 @@ export class OrderService {
|
|
|
675
675
|
// Audit logging is automatic via the audit hooks registered at kernel
|
|
676
676
|
// boot — no manual audit.record() call needed here.
|
|
677
677
|
const hydrated = await this.hydrateOrder(cas, ctx);
|
|
678
|
-
const report = await runAfterHooks(afterHooks, null, hydrated, "statusChange", hookCtx);
|
|
678
|
+
const report = await runAfterHooks(afterHooks, null, hydrated, "statusChange", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
679
679
|
return Ok(hydrated, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
680
680
|
}
|
|
681
681
|
async cancel(orderId, actor, reason = "cancelled_by_user", ctx) {
|
|
@@ -117,7 +117,7 @@ export class PromotionService {
|
|
|
117
117
|
}, ctx);
|
|
118
118
|
const afterHooks = this.deps.hooks.resolve("promotions.afterCreate");
|
|
119
119
|
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
120
|
-
await runAfterHooks(afterHooks, null, promotion, "create", hctx);
|
|
120
|
+
await runAfterHooks(afterHooks, null, promotion, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
121
121
|
return Ok(promotion);
|
|
122
122
|
}
|
|
123
123
|
async deactivate(orgId, id, ctx) {
|
|
@@ -132,7 +132,7 @@ export class PromotionService {
|
|
|
132
132
|
const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
|
|
133
133
|
// Actor-less by design; resolves to the deployment's declared organization.
|
|
134
134
|
const hctx = hookContext(null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
135
|
-
await runAfterHooks(afterHooks, promotion, updated, "update", hctx);
|
|
135
|
+
await runAfterHooks(afterHooks, promotion, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
136
136
|
return Ok(updated);
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
@@ -201,7 +201,7 @@ export class PromotionService {
|
|
|
201
201
|
}
|
|
202
202
|
const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
|
|
203
203
|
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
204
|
-
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
204
|
+
await runAfterHooks(afterHooks, existing, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
205
205
|
return Ok(updated);
|
|
206
206
|
}
|
|
207
207
|
async list(filter, actor, ctx) {
|
|
@@ -41,6 +41,6 @@ export function registerConfiguredKernelHooks(config, hooks) {
|
|
|
41
41
|
hooks.append("catalog.afterCreate", syncToSearchIndex);
|
|
42
42
|
hooks.append("catalog.afterUpdate", syncToSearchIndex);
|
|
43
43
|
for (const [key, handler] of Object.entries(auditHooks)) {
|
|
44
|
-
hooks.
|
|
44
|
+
hooks.appendInTransaction(key, handler);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -38,8 +38,12 @@ export interface QueryLog {
|
|
|
38
38
|
* - db: The Drizzle ORM instance for direct queries
|
|
39
39
|
* - cleanup: Function to truncate all tables (call between tests)
|
|
40
40
|
*/
|
|
41
|
+
/** The test adapter carries one thing a production adapter does not: see `inTransaction`. */
|
|
42
|
+
export type PGliteTestAdapter = DatabaseAdapter & {
|
|
43
|
+
inTransaction(): boolean;
|
|
44
|
+
};
|
|
41
45
|
export declare function createPGliteTestAdapter(): Promise<{
|
|
42
|
-
adapter:
|
|
46
|
+
adapter: PGliteTestAdapter;
|
|
43
47
|
db: DrizzleDatabase;
|
|
44
48
|
cleanup: () => Promise<void>;
|
|
45
49
|
queryLog: QueryLog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-pglite-adapter.d.ts","sourceRoot":"","sources":["../../src/test-utils/create-pglite-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAMrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAAC;IACd,mEAAmE;IACnE,IAAI,IAAI,MAAM,EAAE,CAAC;CAClB;AA0BD;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"create-pglite-adapter.d.ts","sourceRoot":"","sources":["../../src/test-utils/create-pglite-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAMrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAAC;IACd,mEAAmE;IACnE,IAAI,IAAI,MAAM,EAAE,CAAC;CAClB;AA0BD;;;;;;;;;;GAUG;AACH,6FAA6F;AAC7F,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG;IAAE,aAAa,IAAI,OAAO,CAAA;CAAE,CAAC;AAE/E,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,EAAE,EAAE,eAAe,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC,CA4HD"}
|
|
@@ -36,17 +36,6 @@ async function pushCoreSchema(db) {
|
|
|
36
36
|
const { apply } = await drizzleKit.pushSchema(coreSchema, db);
|
|
37
37
|
await apply();
|
|
38
38
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Creates a PGlite-backed database adapter for testing.
|
|
41
|
-
*
|
|
42
|
-
* Each call creates a new isolated PGlite instance with its own
|
|
43
|
-
* in-memory database. Core schema is pushed once during initialization.
|
|
44
|
-
*
|
|
45
|
-
* @returns A promise resolving to an object containing:
|
|
46
|
-
* - adapter: The DatabaseAdapter for use with createKernel
|
|
47
|
-
* - db: The Drizzle ORM instance for direct queries
|
|
48
|
-
* - cleanup: Function to truncate all tables (call between tests)
|
|
49
|
-
*/
|
|
50
39
|
export async function createPGliteTestAdapter() {
|
|
51
40
|
// Create in-memory PGlite instance
|
|
52
41
|
const pg = new PGlite();
|
|
@@ -128,6 +117,21 @@ export async function createPGliteTestAdapter() {
|
|
|
128
117
|
provider: "postgresql",
|
|
129
118
|
db,
|
|
130
119
|
transaction,
|
|
120
|
+
/**
|
|
121
|
+
* Whether a transaction body is executing RIGHT NOW on this adapter.
|
|
122
|
+
*
|
|
123
|
+
* Exposed for one reason: an after-hook that fires before its transaction commits is
|
|
124
|
+
* invisible to every assertion a PGlite suite can otherwise make. This adapter hands the
|
|
125
|
+
* transaction body the SAME `db` handle it hands everyone else, so a hook's query inside an
|
|
126
|
+
* open transaction succeeds and reads uncommitted rows exactly as if it had committed — the
|
|
127
|
+
* instrument is blind to the defect by construction. A recording jobs adapter stamping each
|
|
128
|
+
* enqueue with this flag is the only thing in a PGlite test that can tell "enqueued after
|
|
129
|
+
* commit" from "enqueued inside the transaction that may still roll back".
|
|
130
|
+
*
|
|
131
|
+
* Test-utils only. Production adapters do not carry it, and nothing outside a test may branch
|
|
132
|
+
* on it — a behaviour that depends on this flag would be a behaviour no production adapter has.
|
|
133
|
+
*/
|
|
134
|
+
inTransaction: () => inTransaction,
|
|
131
135
|
};
|
|
132
136
|
/**
|
|
133
137
|
* Cleanup function to reset data between tests.
|
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { withDeferredHooks } from "../hooks/deferred.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Database adapter interface for the commerce engine.
|
|
3
5
|
*
|
|
@@ -72,6 +74,24 @@ function normalizeExecuteShape<T extends object>(db: T): T {
|
|
|
72
74
|
return result;
|
|
73
75
|
};
|
|
74
76
|
}
|
|
77
|
+
if (prop === "transaction") {
|
|
78
|
+
const orig = Reflect.get(target, prop, target);
|
|
79
|
+
if (typeof orig !== "function") return orig;
|
|
80
|
+
// The OTHER half of the after-commit drain, and the one the card this shipped for
|
|
81
|
+
// actually needs. `createDatabaseConnection().transaction` covers core services and REST
|
|
82
|
+
// routes, but a plugin does not get the adapter — it is handed this db HANDLE as
|
|
83
|
+
// `ctx.db` (TaskContext.db is a DrizzleDatabase) and calls `ctx.db.transaction(...)`.
|
|
84
|
+
// `plugin-channel-connector` constructs its service with no transaction argument in
|
|
85
|
+
// production and therefore imports every product through exactly this path, so without
|
|
86
|
+
// the wrapper here the fix would be green in every suite (they inject the adapter's
|
|
87
|
+
// transaction explicitly) and inert on the deployed import.
|
|
88
|
+
//
|
|
89
|
+
// Double-wrapping is safe: `withDeferredHooks` joins an existing store and drains only at
|
|
90
|
+
// the outermost boundary, so adapter.transaction -> db.transaction nests without draining
|
|
91
|
+
// twice.
|
|
92
|
+
return (fn: (tx: unknown) => Promise<unknown>) =>
|
|
93
|
+
withDeferredHooks(() => (orig as (f: typeof fn) => Promise<unknown>).call(target, fn));
|
|
94
|
+
}
|
|
75
95
|
const value = Reflect.get(target, prop, target);
|
|
76
96
|
// Bind methods to the real instance so drizzle's internals (incl. any
|
|
77
97
|
// private fields) are never accessed through the proxy.
|
|
@@ -86,7 +106,10 @@ export function createDatabaseConnection(input: DatabaseConnectionFactoryInput):
|
|
|
86
106
|
provider: adapter.provider,
|
|
87
107
|
db: normalizeExecuteShape(adapter.db as object),
|
|
88
108
|
transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T> {
|
|
89
|
-
return
|
|
109
|
+
return withDeferredHooks(() =>
|
|
110
|
+
// adapter.transaction resolving IS the commit, so draining after it
|
|
111
|
+
// resolves is draining after commit.
|
|
112
|
+
adapter.transaction((tx) => fn(normalizeExecuteShape(tx as object))));
|
|
90
113
|
},
|
|
91
114
|
};
|
|
92
115
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
interface DeferredStore {
|
|
4
|
+
deferred: Array<() => Promise<void>>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const deferredStorage = new AsyncLocalStorage<DeferredStore>();
|
|
8
|
+
|
|
9
|
+
export function isInsideTransaction(): boolean {
|
|
10
|
+
return deferredStorage.getStore() != null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function deferAfterCommit(thunk: () => Promise<void>): boolean {
|
|
14
|
+
const pending = deferredStorage.getStore();
|
|
15
|
+
if (!pending) return false;
|
|
16
|
+
pending.deferred.push(thunk);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function drainDeferred(pending: DeferredStore): Promise<void> {
|
|
21
|
+
// `for...of` over a live array on purpose: a deferred hook that defers another one is drained
|
|
22
|
+
// in the same pass rather than being dropped.
|
|
23
|
+
for (const thunk of pending.deferred) {
|
|
24
|
+
try {
|
|
25
|
+
await thunk();
|
|
26
|
+
} catch {
|
|
27
|
+
// Each thunk logs its own hook failure (see runAfterHooks); swallow so siblings still run.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function withDeferredHooks<T>(fn: () => Promise<T>): Promise<T> {
|
|
33
|
+
const existing = deferredStorage.getStore();
|
|
34
|
+
if (existing) {
|
|
35
|
+
return fn();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const pending: DeferredStore = { deferred: [] };
|
|
39
|
+
// A throw propagates without reaching the drain: a rolled-back transaction discards its deferred
|
|
40
|
+
// hooks rather than announcing a write that never happened. Stated rather than implied.
|
|
41
|
+
const result = await deferredStorage.run(pending, fn);
|
|
42
|
+
|
|
43
|
+
// AWAITED, never `void`. `adapter.transaction` resolving IS the commit, so the hooks below run
|
|
44
|
+
// after commit — and they must still run INSIDE the invocation that started them. The Workers
|
|
45
|
+
// runtime discards a promise that is neither awaited nor handed to `waitUntil` once the
|
|
46
|
+
// invocation ends, which this codebase has already paid for once: a fire-and-forget queue nudge
|
|
47
|
+
// wrote 104 outbox rows and sent ZERO messages on the deployed Worker while every Node test
|
|
48
|
+
// passed. Detaching this drain would do the same to every webhook and search-index update in the
|
|
49
|
+
// product. "After commit" is the requirement; "after the service method returns" is not, and is
|
|
50
|
+
// what tempts you to detach it.
|
|
51
|
+
await drainDeferred(pending);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AfterHook, BeforeHook, HookContext, HookOperation } from "./types.js";
|
|
2
|
+
import { deferAfterCommit } from "./deferred.js";
|
|
2
3
|
|
|
3
4
|
export interface HookError {
|
|
4
5
|
hookName: string;
|
|
@@ -84,30 +85,66 @@ export async function runAfterHooks<T>(
|
|
|
84
85
|
committedResult: T,
|
|
85
86
|
operation: HookOperation,
|
|
86
87
|
context: HookContext,
|
|
88
|
+
runsInTransaction: (hook: AfterHook<T>) => boolean = () => false,
|
|
87
89
|
): Promise<HookReport> {
|
|
88
90
|
const errors: HookError[] = [];
|
|
89
91
|
for (const hook of hooks) {
|
|
90
92
|
const hookName = hook.name || "(anonymous afterHook)";
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
const runHook = () =>
|
|
94
|
+
withTimeout(
|
|
93
95
|
hook({
|
|
94
96
|
data: originalData,
|
|
95
97
|
result: committedResult,
|
|
96
98
|
operation,
|
|
97
|
-
context
|
|
99
|
+
context: runsInTransaction(hook)
|
|
100
|
+
? context
|
|
101
|
+
: { ...context, tx: null },
|
|
98
102
|
}),
|
|
99
103
|
HOOK_TIMEOUT_MS,
|
|
100
104
|
hookName,
|
|
101
105
|
);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
|
|
107
|
+
if (runsInTransaction(hook)) {
|
|
108
|
+
try {
|
|
109
|
+
await runHook();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
errors.push({
|
|
112
|
+
hookName,
|
|
113
|
+
message: error instanceof Error ? error.message : String(error),
|
|
114
|
+
});
|
|
115
|
+
context.logger.error(`After-hook "${hookName}" failed`, {
|
|
116
|
+
error,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const deferred = deferAfterCommit(async () => {
|
|
123
|
+
try {
|
|
124
|
+
await runHook();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
context.logger.error(`After-commit hook "${hookName}" failed`, {
|
|
127
|
+
error,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (!deferred) {
|
|
133
|
+
try {
|
|
134
|
+
await runHook();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
errors.push({
|
|
137
|
+
hookName,
|
|
138
|
+
message: error instanceof Error ? error.message : String(error),
|
|
139
|
+
});
|
|
140
|
+
context.logger.error(`After-hook "${hookName}" failed`, {
|
|
141
|
+
error,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
110
144
|
}
|
|
111
145
|
}
|
|
146
|
+
// After-commit hook failures are logged when the transaction drains; they
|
|
147
|
+
// cannot appear here because deferred hooks run after commit, once the
|
|
148
|
+
// service method has already returned its Result.
|
|
112
149
|
return { errors, hasErrors: errors.length > 0 };
|
|
113
150
|
}
|
|
@@ -8,6 +8,7 @@ type HookEntry = {
|
|
|
8
8
|
|
|
9
9
|
export class HookRegistry {
|
|
10
10
|
private registry = new Map<string, HookEntry>();
|
|
11
|
+
private inTransactionHandlers = new WeakSet<HookHandler>();
|
|
11
12
|
private logger?: { error: (obj: Record<string, unknown>, msg: string) => void };
|
|
12
13
|
|
|
13
14
|
registerConfigHooks(hookName: string, handlers: HookHandler[]): void {
|
|
@@ -20,11 +21,25 @@ export class HookRegistry {
|
|
|
20
21
|
this.registry.get(hookName)!.appended.push(handler);
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
appendInTransaction(hookName: string, handler: HookHandler): void {
|
|
25
|
+
this.inTransactionHandlers.add(handler);
|
|
26
|
+
this.append(hookName, handler);
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
prepend(hookName: string, handler: HookHandler): void {
|
|
24
30
|
this.ensureEntry(hookName);
|
|
25
31
|
this.registry.get(hookName)!.prepended.push(handler);
|
|
26
32
|
}
|
|
27
33
|
|
|
34
|
+
prependInTransaction(hookName: string, handler: HookHandler): void {
|
|
35
|
+
this.inTransactionHandlers.add(handler);
|
|
36
|
+
this.prepend(hookName, handler);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
runsInTransaction(handler: HookHandler): boolean {
|
|
40
|
+
return this.inTransactionHandlers.has(handler);
|
|
41
|
+
}
|
|
42
|
+
|
|
28
43
|
resolve(hookName: string): HookHandler[] {
|
|
29
44
|
const entry = this.registry.get(hookName);
|
|
30
45
|
if (!entry) return [];
|
|
@@ -285,7 +285,7 @@ export class EntityService {
|
|
|
285
285
|
if (existingBySlug) return Err(new CommerceConflictError(`Entity with slug ${input.slug} already exists.`));
|
|
286
286
|
const beforeHooks = this.deps.hooks.resolve("catalog.beforeCreate") as CatalogCreateBeforeHook[];
|
|
287
287
|
const afterHooks = this.deps.hooks.resolve("catalog.afterCreate") as CatalogCreateAfterHook[];
|
|
288
|
-
const context: HookContext =
|
|
288
|
+
const context: HookContext = catalogHookContext(this.deps, actor, ctx, "create");
|
|
289
289
|
const processedInput = await runBeforeHooks(beforeHooks, input, "create", context);
|
|
290
290
|
if (processedInput.sourceStoreId != null) assertPermission(actor, "catalog:sync");
|
|
291
291
|
const customFieldsResult = await this.validateCustomFields(processedInput.type, processedInput.customFields, actor, ctx);
|
|
@@ -297,7 +297,7 @@ export class EntityService {
|
|
|
297
297
|
await this.repo.createAttribute({ entityId: entity.id, locale: processedInput.attributes.locale ?? "en", title: processedInput.attributes.title, subtitle: processedInput.attributes.subtitle, description: processedInput.attributes.description, richDescription: processedInput.attributes.richDescription, seoTitle: processedInput.attributes.seoTitle, seoDescription: processedInput.attributes.seoDescription }, ctx);
|
|
298
298
|
}
|
|
299
299
|
await this.writeCustomFields(entity.id, customFieldsResult.value, ctx);
|
|
300
|
-
const hookReport = await runAfterHooks(afterHooks, null, entity, "create", context);
|
|
300
|
+
const hookReport = await runAfterHooks(afterHooks, null, entity, "create", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
301
301
|
const hydrated = await this.hydrateEntity(entity, undefined, ctx);
|
|
302
302
|
return Ok(hydrated, hookReport.hasErrors ? { hookErrors: hookReport.errors } : undefined);
|
|
303
303
|
} catch (error) { return Err(toCommerceError(error)); } }
|
|
@@ -318,7 +318,7 @@ export class EntityService {
|
|
|
318
318
|
const updated = await this.repo.updateEntity(id, { ...(processed.slug !== undefined ? { slug: processed.slug } : {}), ...(processed.status !== undefined ? { status: processed.status as SellableEntity["status"] } : {}), ...(processed.taxClass !== undefined ? { taxClass: processed.taxClass } : {}), ...(processed.metadata !== undefined ? { metadata: processed.metadata } : {}), ...(processed.isVisible !== undefined ? { isVisible: processed.isVisible } : {}) }, txCtx);
|
|
319
319
|
if (!updated) return Err(new CommerceNotFoundError("Entity not found."));
|
|
320
320
|
await this.writeCustomFields(existing.id, customFieldsResult.value, txCtx, true);
|
|
321
|
-
const hookReport = await runAfterHooks(afterHooks, existing, updated, "update", context);
|
|
321
|
+
const hookReport = await runAfterHooks(afterHooks, existing, updated, "update", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
322
322
|
const hydrated = await this.hydrateEntity(updated, undefined, txCtx);
|
|
323
323
|
return Ok(hydrated, hookReport.hasErrors ? { hookErrors: hookReport.errors } : undefined);
|
|
324
324
|
} catch (error) { return Err(toCommerceError(error)); } }
|
|
@@ -367,7 +367,7 @@ export class EntityService {
|
|
|
367
367
|
}
|
|
368
368
|
const result = await this.hydrateEntity(entity, processed.options ?? options, ctx);
|
|
369
369
|
const entityAfterHooks = this.deps.hooks.resolve(`catalog.${entity.type}.afterRead`) as CatalogReadAfterHook[];
|
|
370
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context), await runAfterHooks(entityAfterHooks, null, result, "read", context));
|
|
370
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
371
371
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
372
372
|
}
|
|
373
373
|
|
|
@@ -418,7 +418,7 @@ export class EntityService {
|
|
|
418
418
|
}
|
|
419
419
|
const result = await this.hydrateEntity(entity, processed.options ?? options, ctx);
|
|
420
420
|
const entityAfterHooks = this.deps.hooks.resolve(`catalog.${entity.type}.afterRead`) as CatalogReadAfterHook[];
|
|
421
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context), await runAfterHooks(entityAfterHooks, null, result, "read", context));
|
|
421
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "read", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
422
422
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
423
423
|
}
|
|
424
424
|
|
|
@@ -490,7 +490,7 @@ export class EntityService {
|
|
|
490
490
|
const result = { items: hydratedItems, pagination: paged.pagination };
|
|
491
491
|
const listTypeFilter = processed.filter?.type;
|
|
492
492
|
const entityAfterHooks = listTypeFilter ? (this.deps.hooks.resolve(`catalog.${listTypeFilter}.afterList`) as CatalogListAfterHook[]) : [];
|
|
493
|
-
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "list", context), await runAfterHooks(entityAfterHooks, null, result, "list", context));
|
|
493
|
+
const report = mergeHookReports(await runAfterHooks(globalAfterHooks, null, result, "list", context, (hook) => this.deps.hooks.runsInTransaction(hook)), await runAfterHooks(entityAfterHooks, null, result, "list", context, (hook) => this.deps.hooks.runsInTransaction(hook)));
|
|
494
494
|
return Ok(result, report.hasErrors ? { hookErrors: report.errors } : undefined);
|
|
495
495
|
}
|
|
496
496
|
|
|
@@ -533,7 +533,7 @@ export class EntityService {
|
|
|
533
533
|
const afterHooks = this.deps.hooks.resolve("catalog.afterUpdate") as CatalogUpdateAfterHook[];
|
|
534
534
|
const context = catalogHookContext(this.deps, actor, ctx, "update");
|
|
535
535
|
context.context.changedFieldPaths = changedFieldPaths;
|
|
536
|
-
await runAfterHooks(afterHooks, entity, entity, "update", context);
|
|
536
|
+
await runAfterHooks(afterHooks, entity, entity, "update", context, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
537
537
|
}
|
|
538
538
|
return Ok(undefined);
|
|
539
539
|
}
|
|
@@ -102,7 +102,7 @@ export class CustomerService {
|
|
|
102
102
|
"customers.afterCreate",
|
|
103
103
|
) as AfterHook<Customer>[];
|
|
104
104
|
const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
105
|
-
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
105
|
+
await runAfterHooks(afterHooks, null, customer, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
106
106
|
|
|
107
107
|
return Ok(customer);
|
|
108
108
|
}
|
|
@@ -195,7 +195,7 @@ export class CustomerService {
|
|
|
195
195
|
"customers.afterCreate",
|
|
196
196
|
) as AfterHook<Customer>[];
|
|
197
197
|
const hctx = hookContext(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
198
|
-
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
198
|
+
await runAfterHooks(afterHooks, null, customer, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
199
199
|
|
|
200
200
|
return customer;
|
|
201
201
|
}
|
|
@@ -277,7 +277,7 @@ export class CustomerService {
|
|
|
277
277
|
const hctx = hookContext(
|
|
278
278
|
actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null,
|
|
279
279
|
);
|
|
280
|
-
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
280
|
+
await runAfterHooks(afterHooks, existing, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
281
281
|
|
|
282
282
|
return Ok(updated);
|
|
283
283
|
}
|
|
@@ -308,7 +308,7 @@ export class CustomerService {
|
|
|
308
308
|
"customers.afterUpdate",
|
|
309
309
|
) as AfterHook<Customer>[];
|
|
310
310
|
const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
311
|
-
await runAfterHooks(afterHooks, customer, updated, "update", hctx);
|
|
311
|
+
await runAfterHooks(afterHooks, customer, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
312
312
|
|
|
313
313
|
return Ok(updated);
|
|
314
314
|
}
|
|
@@ -331,7 +331,7 @@ export class FulfillmentService {
|
|
|
331
331
|
database: { db: this.deps.database.db as PluginDb },
|
|
332
332
|
commerceConfig: this.deps.config,
|
|
333
333
|
});
|
|
334
|
-
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
334
|
+
await runAfterHooks(afterHooks, null, record, "create", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
335
335
|
|
|
336
336
|
// Create a fulfillment line item linking this fulfillment to the order line item
|
|
337
337
|
for (const li of record.lineItems) {
|
|
@@ -490,7 +490,7 @@ export class FulfillmentService {
|
|
|
490
490
|
database: { db: this.deps.database.db as PluginDb },
|
|
491
491
|
commerceConfig: this.deps.config,
|
|
492
492
|
});
|
|
493
|
-
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
493
|
+
await runAfterHooks(afterHooks, null, record, "create", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
494
494
|
|
|
495
495
|
return Ok(record);
|
|
496
496
|
}
|
|
@@ -749,6 +749,7 @@ export class OrderService {
|
|
|
749
749
|
hydrated,
|
|
750
750
|
"create",
|
|
751
751
|
hookCtx,
|
|
752
|
+
(hook) => this.deps.hooks.runsInTransaction(hook),
|
|
752
753
|
);
|
|
753
754
|
|
|
754
755
|
return Ok(
|
|
@@ -797,7 +798,7 @@ export class OrderService {
|
|
|
797
798
|
) as AfterHook<HydratedOrder>[];
|
|
798
799
|
if (afterGetHooks.length > 0) {
|
|
799
800
|
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
800
|
-
await runAfterHooks(afterGetHooks, null, hydrated, "read", hookCtx);
|
|
801
|
+
await runAfterHooks(afterGetHooks, null, hydrated, "read", hookCtx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
801
802
|
}
|
|
802
803
|
|
|
803
804
|
return Ok(hydrated);
|
|
@@ -1257,6 +1258,7 @@ export class OrderService {
|
|
|
1257
1258
|
hydrated,
|
|
1258
1259
|
"statusChange",
|
|
1259
1260
|
hookCtx,
|
|
1261
|
+
(hook) => this.deps.hooks.runsInTransaction(hook),
|
|
1260
1262
|
);
|
|
1261
1263
|
|
|
1262
1264
|
return Ok(
|
|
@@ -245,7 +245,7 @@ export class PromotionService {
|
|
|
245
245
|
const hctx = hookContext(
|
|
246
246
|
actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null,
|
|
247
247
|
);
|
|
248
|
-
await runAfterHooks(afterHooks, null, promotion, "create", hctx);
|
|
248
|
+
await runAfterHooks(afterHooks, null, promotion, "create", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
249
249
|
|
|
250
250
|
return Ok(promotion);
|
|
251
251
|
}
|
|
@@ -266,7 +266,7 @@ export class PromotionService {
|
|
|
266
266
|
) as AfterHook<Promotion>[];
|
|
267
267
|
// Actor-less by design; resolves to the deployment's declared organization.
|
|
268
268
|
const hctx = hookContext(null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
269
|
-
await runAfterHooks(afterHooks, promotion, updated, "update", hctx);
|
|
269
|
+
await runAfterHooks(afterHooks, promotion, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
270
270
|
|
|
271
271
|
return Ok(updated);
|
|
272
272
|
}
|
|
@@ -345,7 +345,7 @@ export class PromotionService {
|
|
|
345
345
|
const hctx = hookContext(
|
|
346
346
|
actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null,
|
|
347
347
|
);
|
|
348
|
-
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
348
|
+
await runAfterHooks(afterHooks, existing, updated, "update", hctx, (hook) => this.deps.hooks.runsInTransaction(hook));
|
|
349
349
|
|
|
350
350
|
return Ok(updated);
|
|
351
351
|
}
|
|
@@ -74,8 +74,11 @@ async function pushCoreSchema(db: DrizzleDatabase): Promise<void> {
|
|
|
74
74
|
* - db: The Drizzle ORM instance for direct queries
|
|
75
75
|
* - cleanup: Function to truncate all tables (call between tests)
|
|
76
76
|
*/
|
|
77
|
+
/** The test adapter carries one thing a production adapter does not: see `inTransaction`. */
|
|
78
|
+
export type PGliteTestAdapter = DatabaseAdapter & { inTransaction(): boolean };
|
|
79
|
+
|
|
77
80
|
export async function createPGliteTestAdapter(): Promise<{
|
|
78
|
-
adapter:
|
|
81
|
+
adapter: PGliteTestAdapter;
|
|
79
82
|
db: DrizzleDatabase;
|
|
80
83
|
cleanup: () => Promise<void>;
|
|
81
84
|
queryLog: QueryLog;
|
|
@@ -160,10 +163,25 @@ export async function createPGliteTestAdapter(): Promise<{
|
|
|
160
163
|
return run as Promise<T>;
|
|
161
164
|
}
|
|
162
165
|
|
|
163
|
-
const adapter: DatabaseAdapter = {
|
|
166
|
+
const adapter: DatabaseAdapter & { inTransaction(): boolean } = {
|
|
164
167
|
provider: "postgresql",
|
|
165
168
|
db,
|
|
166
169
|
transaction,
|
|
170
|
+
/**
|
|
171
|
+
* Whether a transaction body is executing RIGHT NOW on this adapter.
|
|
172
|
+
*
|
|
173
|
+
* Exposed for one reason: an after-hook that fires before its transaction commits is
|
|
174
|
+
* invisible to every assertion a PGlite suite can otherwise make. This adapter hands the
|
|
175
|
+
* transaction body the SAME `db` handle it hands everyone else, so a hook's query inside an
|
|
176
|
+
* open transaction succeeds and reads uncommitted rows exactly as if it had committed — the
|
|
177
|
+
* instrument is blind to the defect by construction. A recording jobs adapter stamping each
|
|
178
|
+
* enqueue with this flag is the only thing in a PGlite test that can tell "enqueued after
|
|
179
|
+
* commit" from "enqueued inside the transaction that may still roll back".
|
|
180
|
+
*
|
|
181
|
+
* Test-utils only. Production adapters do not carry it, and nothing outside a test may branch
|
|
182
|
+
* on it — a behaviour that depends on this flag would be a behaviour no production adapter has.
|
|
183
|
+
*/
|
|
184
|
+
inTransaction: () => inTransaction,
|
|
167
185
|
};
|
|
168
186
|
|
|
169
187
|
/**
|