@hartl-services/medusa-base 0.1.1 → 0.3.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/.medusa/server/src/public/complete-cart.js +3 -0
- package/.medusa/server/src/public/sentry-logger.js +82 -0
- package/.medusa/server/src/utils/discover-complete-cart-participants.js +90 -0
- package/.medusa/server/src/utils/discover-plugin-features.js +14 -6
- package/.medusa/server/src/workflows/hooks/complete-cart-participants.js +163 -0
- package/.medusa/server/src/workflows/hooks/complete-cart.js +17 -0
- package/README.md +89 -0
- package/dist/public/complete-cart.d.ts +21 -0
- package/dist/public/complete-cart.js +2 -0
- package/dist/public/index.d.ts +1 -0
- package/dist/public/sentry-logger.d.ts +11 -0
- package/dist/public/sentry-logger.js +81 -0
- package/package.json +15 -3
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGUtY2FydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9wdWJsaWMvY29tcGxldGUtY2FydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.withSentryErrorReporting = withSentryErrorReporting;
|
|
37
|
+
const Sentry = __importStar(require("@sentry/node"));
|
|
38
|
+
/**
|
|
39
|
+
* Medusa's own HTTP error-handler middleware fully "handles" every thrown
|
|
40
|
+
* route/workflow error via logger.error(...) before it can ever reach an
|
|
41
|
+
* uncaught-exception process hook, so Sentry's default Node integrations
|
|
42
|
+
* never see it. Bridging logger.error(...) itself is the only place that
|
|
43
|
+
* reliably captures every error Medusa's framework already logs internally.
|
|
44
|
+
* Errors that Medusa logs through logger.warn(err) (failing event
|
|
45
|
+
* subscribers) are reported too, at warning level.
|
|
46
|
+
*/
|
|
47
|
+
function withSentryErrorReporting(logger) {
|
|
48
|
+
const originalError = logger.error.bind(logger);
|
|
49
|
+
const originalWarn = logger.warn.bind(logger);
|
|
50
|
+
return {
|
|
51
|
+
panic: logger.panic.bind(logger),
|
|
52
|
+
shouldLog: logger.shouldLog.bind(logger),
|
|
53
|
+
setLogLevel: logger.setLogLevel.bind(logger),
|
|
54
|
+
unsetLogLevel: logger.unsetLogLevel.bind(logger),
|
|
55
|
+
activity: logger.activity.bind(logger),
|
|
56
|
+
progress: logger.progress.bind(logger),
|
|
57
|
+
failure: logger.failure.bind(logger),
|
|
58
|
+
success: logger.success.bind(logger),
|
|
59
|
+
silly: logger.silly.bind(logger),
|
|
60
|
+
debug: logger.debug.bind(logger),
|
|
61
|
+
verbose: logger.verbose.bind(logger),
|
|
62
|
+
http: logger.http.bind(logger),
|
|
63
|
+
info: logger.info.bind(logger),
|
|
64
|
+
// Medusa's Redis Event Bus logs a failing subscriber's exception with
|
|
65
|
+
// warn(err), even on the final retry, so an Error passed to warn is a real
|
|
66
|
+
// failure too. Plain warning messages stay out of Sentry.
|
|
67
|
+
warn: (message) => {
|
|
68
|
+
if (message instanceof Error) {
|
|
69
|
+
Sentry.captureException(message, { level: "warning" });
|
|
70
|
+
}
|
|
71
|
+
return originalWarn(message);
|
|
72
|
+
},
|
|
73
|
+
log: logger.log.bind(logger),
|
|
74
|
+
error: (messageOrError, error) => {
|
|
75
|
+
const exception = error ?? (messageOrError instanceof Error ? messageOrError : new Error(messageOrError));
|
|
76
|
+
const loggerMessage = error && typeof messageOrError === "string" ? messageOrError : undefined;
|
|
77
|
+
Sentry.captureException(exception, loggerMessage ? { extra: { loggerMessage } } : undefined);
|
|
78
|
+
return originalError(messageOrError, error);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VudHJ5LWxvZ2dlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9wdWJsaWMvc2VudHJ5LWxvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQVlBLDREQTBDQztBQXRERCxxREFBc0M7QUFHdEM7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQix3QkFBd0IsQ0FBQyxNQUFjO0lBQ3JELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQy9DLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBRTdDLE9BQU87UUFDTCxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ2hDLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDeEMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUM1QyxhQUFhLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ2hELFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDdEMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUN0QyxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3BDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDcEMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNoQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ2hDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDcEMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUM5QixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQzlCLHNFQUFzRTtRQUN0RSwyRUFBMkU7UUFDM0UsMERBQTBEO1FBQzFELElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ2hCLElBQUssT0FBbUIsWUFBWSxLQUFLLEVBQUUsQ0FBQztnQkFDMUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFBO1lBQ3hELENBQUM7WUFDRCxPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUM5QixDQUFDO1FBQ0QsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUM1QixLQUFLLEVBQUUsQ0FBQyxjQUFjLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDL0IsTUFBTSxTQUFTLEdBQ2IsS0FBSyxJQUFJLENBQUMsY0FBYyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFBO1lBQ3pGLE1BQU0sYUFBYSxHQUNqQixLQUFLLElBQUksT0FBTyxjQUFjLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtZQUUxRSxNQUFNLENBQUMsZ0JBQWdCLENBQ3JCLFNBQVMsRUFDVCxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsYUFBYSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUN6RCxDQUFBO1lBRUQsT0FBTyxhQUFhLENBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQzdDLENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyJ9
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectCompleteCartParticipants = selectCompleteCartParticipants;
|
|
4
|
+
exports.listCompleteCartParticipants = listCompleteCartParticipants;
|
|
5
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
+
const discover_plugin_features_1 = require("./discover-plugin-features");
|
|
7
|
+
const HOOK_NAMES = [
|
|
8
|
+
"validate",
|
|
9
|
+
"orderCreated",
|
|
10
|
+
];
|
|
11
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
12
|
+
const invalid = (moduleKey, reason) => new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Modul "${moduleKey}" deklariert ungültige Complete-Cart-Hooks: ${reason}`);
|
|
13
|
+
const readDeclarations = (moduleKey, service) => {
|
|
14
|
+
if (service === null || typeof service !== "object") {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const declare = service
|
|
18
|
+
.completeCartHooks;
|
|
19
|
+
if (typeof declare !== "function") {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
let declarations;
|
|
23
|
+
try {
|
|
24
|
+
declarations = declare.call(service);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw invalid(moduleKey, error instanceof Error ? error.message : String(error));
|
|
28
|
+
}
|
|
29
|
+
if (declarations === null ||
|
|
30
|
+
typeof declarations !== "object" ||
|
|
31
|
+
Array.isArray(declarations)) {
|
|
32
|
+
throw invalid(moduleKey, "completeCartHooks() liefert kein Objekt.");
|
|
33
|
+
}
|
|
34
|
+
return declarations;
|
|
35
|
+
};
|
|
36
|
+
const validateStep = (moduleKey, hook, step) => {
|
|
37
|
+
if (!HOOK_NAMES.includes(hook)) {
|
|
38
|
+
throw invalid(moduleKey, `unbekannter Hook "${hook}".`);
|
|
39
|
+
}
|
|
40
|
+
const candidate = step;
|
|
41
|
+
if (candidate === null ||
|
|
42
|
+
typeof candidate !== "object" ||
|
|
43
|
+
typeof candidate.workflow_id !== "string" ||
|
|
44
|
+
!candidate.workflow_id.trim() ||
|
|
45
|
+
typeof candidate.order !== "number" ||
|
|
46
|
+
!Number.isFinite(candidate.order)) {
|
|
47
|
+
throw invalid(moduleKey, `"${hook}" braucht eine workflow_id (String) und eine endliche order (Zahl).`);
|
|
48
|
+
}
|
|
49
|
+
return { workflow_id: candidate.workflow_id, order: candidate.order };
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Selects the participants of one hook from the given modules: every service
|
|
53
|
+
* with a `completeCartHooks()` function. Fails closed: an invalid declaration
|
|
54
|
+
* (for any hook) is `UNEXPECTED_STATE`, never skipped. Sorted by `order`,
|
|
55
|
+
* then module key, then workflow id.
|
|
56
|
+
*/
|
|
57
|
+
function selectCompleteCartParticipants(modules, hook) {
|
|
58
|
+
const participants = [];
|
|
59
|
+
for (const { key, service } of modules) {
|
|
60
|
+
const declarations = readDeclarations(key, service);
|
|
61
|
+
if (!declarations) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
for (const [declaredHook, step] of Object.entries(declarations)) {
|
|
65
|
+
if (step === undefined) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const valid = validateStep(key, declaredHook, step);
|
|
69
|
+
if (declaredHook === hook) {
|
|
70
|
+
participants.push({ module_key: key, ...valid });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
participants.sort((left, right) => left.order - right.order ||
|
|
75
|
+
compare(left.module_key, right.module_key) ||
|
|
76
|
+
compare(left.workflow_id, right.workflow_id));
|
|
77
|
+
const workflowIds = new Set();
|
|
78
|
+
for (const participant of participants) {
|
|
79
|
+
if (workflowIds.has(participant.workflow_id)) {
|
|
80
|
+
throw invalid(participant.module_key, `Workflow "${participant.workflow_id}" ist für "${hook}" mehrfach deklariert.`);
|
|
81
|
+
}
|
|
82
|
+
workflowIds.add(participant.workflow_id);
|
|
83
|
+
}
|
|
84
|
+
return participants;
|
|
85
|
+
}
|
|
86
|
+
/** The participants of one hook among the modules registered in the app. */
|
|
87
|
+
function listCompleteCartParticipants(container, hook) {
|
|
88
|
+
return selectCompleteCartParticipants((0, discover_plugin_features_1.listRegisteredModules)(container), hook);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXItY29tcGxldGUtY2FydC1wYXJ0aWNpcGFudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvZGlzY292ZXItY29tcGxldGUtY2FydC1wYXJ0aWNpcGFudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE0RkEsd0VBc0NDO0FBR0Qsb0VBS0M7QUF6SUQscURBQXVEO0FBR3ZELHlFQUdtQztBQVFuQyxNQUFNLFVBQVUsR0FBc0I7SUFDcEMsVUFBVTtJQUNWLGNBQWM7Q0FDa0IsQ0FBQTtBQUVsQyxNQUFNLE9BQU8sR0FBRyxDQUFDLElBQVksRUFBRSxLQUFhLEVBQVUsRUFBRSxDQUN0RCxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFFMUMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxTQUFpQixFQUFFLE1BQWMsRUFBZSxFQUFFLENBQ2pFLElBQUksbUJBQVcsQ0FDYixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsVUFBVSxTQUFTLCtDQUErQyxNQUFNLEVBQUUsQ0FDM0UsQ0FBQTtBQUVILE1BQU0sZ0JBQWdCLEdBQUcsQ0FDdkIsU0FBaUIsRUFDakIsT0FBZ0IsRUFDcUIsRUFBRTtJQUN2QyxJQUFJLE9BQU8sS0FBSyxJQUFJLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDcEQsT0FBTyxTQUFTLENBQUE7SUFDbEIsQ0FBQztJQUNELE1BQU0sT0FBTyxHQUFJLE9BQTJDO1NBQ3pELGlCQUFpQixDQUFBO0lBQ3BCLElBQUksT0FBTyxPQUFPLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDbEMsT0FBTyxTQUFTLENBQUE7SUFDbEIsQ0FBQztJQUVELElBQUksWUFBcUIsQ0FBQTtJQUN6QixJQUFJLENB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
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listRegisteredModules = listRegisteredModules;
|
|
3
4
|
exports.discoverPluginFeatureDescriptors = discoverPluginFeatureDescriptors;
|
|
4
5
|
exports.findPluginFeatureDescriptor = findPluginFeatureDescriptor;
|
|
5
6
|
const utils_1 = require("@medusajs/framework/utils");
|
|
@@ -7,6 +8,16 @@ const descriptor_1 = require("../public/descriptor");
|
|
|
7
8
|
// Keyed by the app's config object: stable for the process lifetime, unlike
|
|
8
9
|
// `req.scope`, which is a new scope per request.
|
|
9
10
|
const discovered = new WeakMap();
|
|
11
|
+
const registeredModules = (container, configModule) => Object.keys(configModule.modules ?? {})
|
|
12
|
+
.filter((moduleKey) => container.hasRegistration(moduleKey))
|
|
13
|
+
.map((moduleKey) => ({
|
|
14
|
+
key: moduleKey,
|
|
15
|
+
service: container.resolve(moduleKey),
|
|
16
|
+
}));
|
|
17
|
+
/** Every module listed in medusa-config that is registered in the container. */
|
|
18
|
+
function listRegisteredModules(container) {
|
|
19
|
+
return registeredModules(container, container.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE));
|
|
20
|
+
}
|
|
10
21
|
const readDescriptor = (service) => service !== null && typeof service === "object" && "pluginFeatures" in service
|
|
11
22
|
? service.pluginFeatures
|
|
12
23
|
: undefined;
|
|
@@ -21,11 +32,8 @@ function discoverPluginFeatureDescriptors(container) {
|
|
|
21
32
|
return memo;
|
|
22
33
|
}
|
|
23
34
|
const byPluginKey = new Map();
|
|
24
|
-
for (const moduleKey of
|
|
25
|
-
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
const candidate = readDescriptor(container.resolve(moduleKey));
|
|
35
|
+
for (const { key: moduleKey, service } of registeredModules(container, configModule)) {
|
|
36
|
+
const candidate = readDescriptor(service);
|
|
29
37
|
if (candidate === undefined) {
|
|
30
38
|
continue;
|
|
31
39
|
}
|
|
@@ -48,4 +56,4 @@ function discoverPluginFeatureDescriptors(container) {
|
|
|
48
56
|
function findPluginFeatureDescriptor(container, pluginKey) {
|
|
49
57
|
return discoverPluginFeatureDescriptors(container).find((descriptor) => descriptor.plugin_key === pluginKey);
|
|
50
58
|
}
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXItcGx1Z2luLWZlYXR1cmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2Rpc2NvdmVyLXBsdWdpbi1mZWF0dXJlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTRCQSxzREFPQztBQVdELDRFQStDQztBQUVELGtFQU9DO0FBckdELHFEQUFrRjtBQUVsRixxREFBc0U7QUFTdEUsNEVBQTRFO0FBQzVFLGlEQUFpRDtBQUNqRCxNQUFNLFVBQVUsR0FBRyxJQUFJLE9BQU8sRUFBcUMsQ0FBQTtBQUVuRSxNQUFNLGlCQUFpQixHQUFHLENBQ3hCLFNBQTBCLEVBQzFCLFlBQThCLEVBQ1YsRUFBRSxDQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO0tBQ3BDLE1BQU0sQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQztLQUMzRCxHQUFHLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbkIsR0FBRyxFQUFFLFNBQVM7SUFDZCxPQUFPLEVBQUUsU0FBUyxDQUFDLE9BQU8sQ0FBVSxTQUFTLENBQUM7Q0FDL0MsQ0FBQyxDQUFDLENBQUE7QUFFUCxnRkFBZ0Y7QUFDaEYsU0FBZ0IscUJBQXFCLENBQ25DLFNBQTBCO0lBRTFCLE9BQU8saUJBQWlCLENBQ3RCLFNBQVMsRUFDVCxTQUFTLENBQUMsT0FBTyxDQUFtQixpQ0FBeUIsQ0FBQyxhQUFhLENBQUMsQ0FDN0UsQ0FBQTtBQUNILENBQUM7QUFFRCxNQUFNLGNBQWMsR0FBRyxDQUFDLE9BQWdCLEVBQVcsRUFBRSxDQUNuRCxPQUFPLEtBQUssSUFBSSxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxnQkFBZ0IsSUFBSSxPQUFPO0lBQzVFLENBQUMsQ0FBRSxPQUF1QyxDQUFDLGNBQWM7SUFDekQsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtBQUVmOzs7R0FHRztBQUNILFNBQWdCLGdDQUFnQyxDQUM5QyxTQUEwQjtJQUUxQixNQUFNLFlBQVksR0FBRyxTQUFTLENBQUMsT0FBTyxDQUNwQyxpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFDRCxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3pDLElBQUksSUFBSSxFQUFFLENBQUM7UUFDVCxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsRUFBbUMsQ0FBQTtJQUM5RCxLQUFLLE1BQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxJQUFJLGlCQUFpQixDQUN6RCxTQUFTLEVBQ1QsWUFBWSxDQUNiLEVBQUUsQ0FBQztRQUNGLE1BQU0sU0FBUyxHQUFHLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxJQUFJLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM1QixTQUFRO1FBQ1YsQ0FBQztRQUVELE1BQU0sVUFBVSxHQUFHLFNBQW9DLENBQUE7UUFDdkQsSUFBSSxDQUFDO1lBQ0gsSUFBQSw0Q0FBK0IsRUFBQyxVQUFVLENBQUMsQ0FBQTtRQUM3QyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsVUFBVSxTQUFTLDZDQUNqQixLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUN2RCxFQUFFLENBQ0gsQ0FBQTtRQUNILENBQUM7UUFFRCxJQUFJLFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDM0MsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyxlQUFlLFVBQVUsQ0FBQyxVQUFVLHlDQUF5QyxDQUM5RSxDQUFBO1FBQ0gsQ0FBQztRQUNELFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQTtJQUNwRCxDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUM1RCxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQ2hELENBQUE7SUFDRCxVQUFVLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUNwQyxPQUFPLE1BQU0sQ0FBQTtBQUNmLENBQUM7QUFFRCxTQUFnQiwyQkFBMkIsQ0FDekMsU0FBMEIsRUFDMUIsU0FBaUI7SUFFakIsT0FBTyxnQ0FBZ0MsQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQ3JELENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsVUFBVSxLQUFLLFNBQVMsQ0FDcEQsQ0FBQTtBQUNILENBQUMifQ==
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compensateCompleteCartOrderCreatedParticipants = exports.runCompleteCartOrderCreatedParticipants = exports.runCompleteCartValidateParticipants = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
6
|
+
const discover_complete_cart_participants_1 = require("../../utils/discover-complete-cart-participants");
|
|
7
|
+
const participantsFor = (hook, container, modules) => modules
|
|
8
|
+
? (0, discover_complete_cart_participants_1.selectCompleteCartParticipants)(modules, hook)
|
|
9
|
+
: (0, discover_complete_cart_participants_1.listCompleteCartParticipants)(container, hook);
|
|
10
|
+
const logError = (container, message) => {
|
|
11
|
+
try {
|
|
12
|
+
container
|
|
13
|
+
.resolve(utils_1.ContainerRegistrationKeys.LOGGER)
|
|
14
|
+
.error(message);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Logging must not replace the original workflow outcome.
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Cancels (compensates) one participant run by transaction id, also after it
|
|
22
|
+
* finished; the participant workflow must be stored with a retention time.
|
|
23
|
+
* Not `engine.cancel()`: in Medusa 2.19.0 it loads the transaction through a
|
|
24
|
+
* workflow runner without the container, so the participant's compensation
|
|
25
|
+
* cannot resolve its module. Built with the container like `runAsStep` does.
|
|
26
|
+
* Throws the participant's own compensation error, not "Unknown error".
|
|
27
|
+
*/
|
|
28
|
+
const cancelParticipant = async (workflowId, transactionId, container, sharedContext) => {
|
|
29
|
+
const workflow = workflows_sdk_1.MedusaWorkflow.getWorkflow(workflowId);
|
|
30
|
+
if (!workflow) {
|
|
31
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `Workflow "${workflowId}" is not registered.`);
|
|
32
|
+
}
|
|
33
|
+
const { transaction } = await workflow(container).cancel({
|
|
34
|
+
transactionId,
|
|
35
|
+
container,
|
|
36
|
+
context: { ...sharedContext },
|
|
37
|
+
throwOnError: false,
|
|
38
|
+
});
|
|
39
|
+
if (transaction.getState() !== utils_1.TransactionState.REVERTED) {
|
|
40
|
+
const [first] = transaction.getErrors();
|
|
41
|
+
throw (first?.error ??
|
|
42
|
+
new Error(`Workflow "${workflowId}" ended in state "${transaction.getState()}" instead of reverted.`));
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const describeError = (error) => error instanceof Error
|
|
46
|
+
? error.message
|
|
47
|
+
: typeof error?.message === "string"
|
|
48
|
+
? error.message
|
|
49
|
+
: String(error);
|
|
50
|
+
/**
|
|
51
|
+
* Runs every `validate` participant in order. No transaction id: validation
|
|
52
|
+
* writes nothing, so there is nothing to compensate. The first error is
|
|
53
|
+
* rethrown unchanged, keeping its MedusaError type for the HTTP status.
|
|
54
|
+
*/
|
|
55
|
+
const runCompleteCartValidateParticipants = async (input, context, modules) => {
|
|
56
|
+
const { container, ...sharedContext } = context;
|
|
57
|
+
const participants = participantsFor("validate", container, modules);
|
|
58
|
+
if (!participants.length) {
|
|
59
|
+
return new workflows_sdk_1.StepResponse(undefined);
|
|
60
|
+
}
|
|
61
|
+
const workflowEngine = container.resolve(utils_1.Modules.WORKFLOW_ENGINE);
|
|
62
|
+
for (const participant of participants) {
|
|
63
|
+
// The engine JSON-clones its options, so the container is never passed
|
|
64
|
+
// to run(); the engine uses the shared app container.
|
|
65
|
+
await workflowEngine.run(participant.workflow_id, {
|
|
66
|
+
input,
|
|
67
|
+
context: {
|
|
68
|
+
...sharedContext,
|
|
69
|
+
preventReleaseEvents: true,
|
|
70
|
+
},
|
|
71
|
+
throwOnError: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return new workflows_sdk_1.StepResponse(undefined);
|
|
75
|
+
};
|
|
76
|
+
exports.runCompleteCartValidateParticipants = runCompleteCartValidateParticipants;
|
|
77
|
+
/**
|
|
78
|
+
* Runs every `orderCreated` participant in order under the complete-cart
|
|
79
|
+
* transaction id. If participant k fails, participants 0..k-1 are cancelled
|
|
80
|
+
* in reverse order; a rollback failure is logged, and the ORIGINAL error is
|
|
81
|
+
* rethrown either way.
|
|
82
|
+
*/
|
|
83
|
+
const runCompleteCartOrderCreatedParticipants = async (input, context, modules) => {
|
|
84
|
+
const { container, ...sharedContext } = context;
|
|
85
|
+
const transactionId = context.transactionId;
|
|
86
|
+
if (!transactionId) {
|
|
87
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Complete-cart orderCreated hook ran without a transaction id.");
|
|
88
|
+
}
|
|
89
|
+
const participants = participantsFor("orderCreated", container, modules);
|
|
90
|
+
const workflowIds = participants.map(({ workflow_id }) => workflow_id);
|
|
91
|
+
if (!participants.length) {
|
|
92
|
+
return new workflows_sdk_1.StepResponse(undefined, {
|
|
93
|
+
transaction_id: transactionId,
|
|
94
|
+
workflow_ids: workflowIds,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const workflowEngine = container.resolve(utils_1.Modules.WORKFLOW_ENGINE);
|
|
98
|
+
const completed = [];
|
|
99
|
+
for (const participant of participants) {
|
|
100
|
+
try {
|
|
101
|
+
await workflowEngine.run(participant.workflow_id, {
|
|
102
|
+
input,
|
|
103
|
+
transactionId,
|
|
104
|
+
context: {
|
|
105
|
+
...sharedContext,
|
|
106
|
+
preventReleaseEvents: true,
|
|
107
|
+
},
|
|
108
|
+
throwOnError: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
for (const done of [...completed].reverse()) {
|
|
113
|
+
try {
|
|
114
|
+
await cancelParticipant(done.workflow_id, transactionId, container, sharedContext);
|
|
115
|
+
}
|
|
116
|
+
catch (rollbackError) {
|
|
117
|
+
logError(container, `Complete-cart orderCreated rollback failed for module "${done.module_key}", workflow "${done.workflow_id}" (cart ${input.cart_id}, order ${input.order_id}, transaction ${transactionId}) after "${participant.workflow_id}" failed: ${describeError(rollbackError)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
completed.push(participant);
|
|
123
|
+
}
|
|
124
|
+
return new workflows_sdk_1.StepResponse(undefined, {
|
|
125
|
+
transaction_id: transactionId,
|
|
126
|
+
workflow_ids: workflowIds,
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
exports.runCompleteCartOrderCreatedParticipants = runCompleteCartOrderCreatedParticipants;
|
|
130
|
+
/**
|
|
131
|
+
* Cancels the participants in reverse order. Every participant is attempted;
|
|
132
|
+
* failures are logged and the first one is thrown so the parent compensation
|
|
133
|
+
* stays failed. `undefined` means the invoke already rolled back.
|
|
134
|
+
*/
|
|
135
|
+
const compensateCompleteCartOrderCreatedParticipants = async (compensation, context) => {
|
|
136
|
+
if (!compensation) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const { container, ...sharedContext } = context;
|
|
140
|
+
const workflowIds = [...compensation.workflow_ids].reverse();
|
|
141
|
+
if (!workflowIds.length) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
let failed = false;
|
|
145
|
+
let firstFailure;
|
|
146
|
+
for (const workflowId of workflowIds) {
|
|
147
|
+
try {
|
|
148
|
+
await cancelParticipant(workflowId, compensation.transaction_id, container, sharedContext);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
logError(container, `Complete-cart orderCreated compensation failed for workflow "${workflowId}" (transaction ${compensation.transaction_id}): ${describeError(error)}`);
|
|
152
|
+
if (!failed) {
|
|
153
|
+
failed = true;
|
|
154
|
+
firstFailure = error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (failed) {
|
|
159
|
+
throw firstFailure;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
exports.compensateCompleteCartOrderCreatedParticipants = compensateCompleteCartOrderCreatedParticipants;
|
|
163
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGUtY2FydC1wYXJ0aWNpcGFudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2hvb2tzL2NvbXBsZXRlLWNhcnQtcGFydGljaXBhbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLHFEQUtrQztBQUNsQyxxRUFBZ0Y7QUFRaEYseUdBSXdEO0FBbUJ4RCxNQUFNLGVBQWUsR0FBRyxDQUN0QixJQUEwQixFQUMxQixTQUEwQixFQUMxQixPQUFnRCxFQUNoQixFQUFFLENBQ2xDLE9BQU87SUFDTCxDQUFDLENBQUMsSUFBQSxvRUFBOEIsRUFBQyxPQUFPLEVBQUUsSUFBSSxDQUFDO0lBQy9DLENBQUMsQ0FBQyxJQUFBLGtFQUE0QixFQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQTtBQUVuRCxNQUFNLFFBQVEsR0FBRyxDQUFDLFNBQTBCLEVBQUUsT0FBZSxFQUFRLEVBQUU7SUFDckUsSUFBSSxDQUFDO1FBQ0gsU0FBUzthQUNOLE9BQU8sQ0FDTixpQ0FBeUIsQ0FBQyxNQUFNLENBQ2pDO2FBQ0EsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ25CLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCwwREFBMEQ7SUFDNUQsQ0FBQztBQUNILENBQUMsQ0FBQTtBQWdCRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLEVBQzdCLFVBQWtCLEVBQ2xCLGFBQXFCLEVBQ3JCLFNBQTBCLEVBQzFCLGFBQXNDLEVBQ3ZCLEVBQUU7SUFDakIsTUFBTSxRQUFRLEdBQ1osOEJBR0QsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDekIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2QsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFDM0IsYUFBYSxVQUFVLHNCQUFzQixDQUM5QyxDQUFBO0lBQ0gsQ0FBQztJ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
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
4
|
+
const complete_cart_participants_1 = require("./complete-cart-participants");
|
|
5
|
+
/**
|
|
6
|
+
* The ONLY registrations of these two hooks in the whole shop. Medusa 2.19.0
|
|
7
|
+
* throws "Cannot define multiple hook handlers" for a second handler
|
|
8
|
+
* (workflows-sdk dist/utils/composer/create-hook.js), so plugins declare
|
|
9
|
+
* `completeCartHooks()` on their module service instead and the base runs
|
|
10
|
+
* their workflows. The cart path never reads feature toggles.
|
|
11
|
+
*/
|
|
12
|
+
core_flows_1.completeCartWorkflow.hooks.validate((input, context) => (0, complete_cart_participants_1.runCompleteCartValidateParticipants)(input, context));
|
|
13
|
+
// Medusa 2.19.0 creates this hook internally but omits it from complete cart's
|
|
14
|
+
// public declaration. Keep the cast isolated to this version-specific edge.
|
|
15
|
+
const { orderCreated } = core_flows_1.completeCartWorkflow.hooks;
|
|
16
|
+
orderCreated((input, context) => (0, complete_cart_participants_1.runCompleteCartOrderCreatedParticipants)(input, context), complete_cart_participants_1.compensateCompleteCartOrderCreatedParticipants);
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGUtY2FydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3MvaG9va3MvY29tcGxldGUtY2FydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLDREQUFrRTtBQUdsRSw2RUFNcUM7QUFFckM7Ozs7OztHQU1HO0FBRUgsaUNBQW9CLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUNyRCxJQUFBLGdFQUFtQyxFQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FDcEQsQ0FBQTtBQWFELCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLGlDQUFvQixDQUFDLEtBRTdDLENBQUE7QUFFRCxZQUFZLENBQ1YsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUUsQ0FBQyxJQUFBLG9FQUF1QyxFQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsRUFDM0UsMkVBQThDLENBQy9DLENBQUEifQ==
|
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ helpers that plugins use to enforce their toggles.
|
|
|
16
16
|
values to the Admin.
|
|
17
17
|
- Exports `definePluginFeatures`, `requirePluginFeature` and
|
|
18
18
|
`isPluginFeatureEnabled` from `@hartl-services/medusa-base` for plugins.
|
|
19
|
+
- Owns the `completeCartWorkflow` hooks `validate` and `orderCreated` and runs
|
|
20
|
+
the workflows that plugins declare for them (see "Complete-cart hook
|
|
21
|
+
composition").
|
|
19
22
|
|
|
20
23
|
## Installation in a shop
|
|
21
24
|
|
|
@@ -164,3 +167,89 @@ existing data.
|
|
|
164
167
|
- Updates are optimistic: `expected_version` 0 creates the row, any other
|
|
165
168
|
value updates exactly that version. A concurrent change answers 409; the
|
|
166
169
|
Admin page reloads and shows a notice.
|
|
170
|
+
|
|
171
|
+
## Complete-cart hook composition
|
|
172
|
+
|
|
173
|
+
**Why.** Medusa 2.19.0 allows exactly one handler per workflow hook; a second
|
|
174
|
+
registration throws "Cannot define multiple hook handlers" at boot. Several
|
|
175
|
+
plugins need `completeCartWorkflow.hooks.validate` and the (undeclared, but
|
|
176
|
+
existing) `orderCreated` hook, so the base registers both, once
|
|
177
|
+
(`src/workflows/hooks/complete-cart.ts`), and runs the plugins' workflows.
|
|
178
|
+
**A plugin must never register these two hooks itself.**
|
|
179
|
+
|
|
180
|
+
**How a plugin participates.** Its module service implements
|
|
181
|
+
`CompleteCartParticipant` (plain data, `import type` only):
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import type { CompleteCartHookDeclarations } from "@hartl-services/medusa-base"
|
|
185
|
+
|
|
186
|
+
class MyModuleService extends MedusaService({ /* … */ }) {
|
|
187
|
+
completeCartHooks(): CompleteCartHookDeclarations {
|
|
188
|
+
return {
|
|
189
|
+
validate: { workflow_id: "my-validate-complete-cart", order: 150 },
|
|
190
|
+
orderCreated: { workflow_id: "my-order-created", order: 150 },
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- A `validate` workflow receives `CompleteCartValidateInput` (`{ input, cart }`)
|
|
197
|
+
and fails the checkout by throwing (a `MedusaError` keeps its type, so
|
|
198
|
+
`NOT_ALLOWED`/`INVALID_DATA` answer 400). It must not write.
|
|
199
|
+
- An `orderCreated` workflow receives `CompleteCartOrderCreatedInput`
|
|
200
|
+
(`{ order_id, cart_id }`) and must be compensable. Create it with
|
|
201
|
+
`store: true` and a `retentionTime` of at least three days (Medusa's own
|
|
202
|
+
`completeCartWorkflow` retention): the base cancels it by transaction id also
|
|
203
|
+
after it finished, and the in-memory workflow engine deletes an unstored
|
|
204
|
+
finished transaction.
|
|
205
|
+
- The base discovers participants like feature descriptors (every module in
|
|
206
|
+
`medusa-config` that is registered in the container). Fail closed: an
|
|
207
|
+
invalid declaration (non-string or blank `workflow_id`, non-finite `order`,
|
|
208
|
+
unknown hook name, the same workflow twice for one hook) is
|
|
209
|
+
`UNEXPECTED_STATE` and blocks checkout, naming the module key.
|
|
210
|
+
|
|
211
|
+
**Ordering.** Ascending `order`, then module key, then workflow id. In use:
|
|
212
|
+
Affiliate 100 (`affiliate-validate-complete-cart`,
|
|
213
|
+
`finalize-affiliate-order-attribution`), tax compliance 200
|
|
214
|
+
(`freeze-tax-compliance-order-evidence`, `orderCreated` only).
|
|
215
|
+
|
|
216
|
+
**Rollback semantics.**
|
|
217
|
+
|
|
218
|
+
- `validate` participants run one after another without their own transaction
|
|
219
|
+
id (they write nothing). The first error stops the chain and is rethrown
|
|
220
|
+
unchanged.
|
|
221
|
+
- `orderCreated` participants run one after another through the workflow
|
|
222
|
+
engine under the complete-cart transaction id, with the parent's event group
|
|
223
|
+
(`preventReleaseEvents`). If participant *k* fails, the base cancels
|
|
224
|
+
participants *k-1 … 0* in reverse order, logs every failed cancellation
|
|
225
|
+
(module key, workflow id, cart, order, transaction), and rethrows the
|
|
226
|
+
original error.
|
|
227
|
+
- When a later complete-cart step fails, the hook's compensation cancels every
|
|
228
|
+
participant in reverse order, attempts all of them, logs each failure and
|
|
229
|
+
then throws the first one, so the complete-cart compensation stays failed
|
|
230
|
+
instead of silently leaving partial state.
|
|
231
|
+
- The base never swallows a participant error and never reads toggles here.
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
## Sentry logger wrapper
|
|
235
|
+
|
|
236
|
+
`@hartl-services/medusa-base/sentry-logger` exports `withSentryErrorReporting(logger)`,
|
|
237
|
+
formerly published as `@hartl-services/medusa-sentry-logger`. Medusa's HTTP
|
|
238
|
+
error handler catches thrown route and workflow errors and only logs them, so
|
|
239
|
+
Sentry's default Node integrations never see them; wrapping the logger reports
|
|
240
|
+
every `logger.error(...)` and every `Error` passed to `logger.warn(...)` (at
|
|
241
|
+
level `warning`). It is a plain library import for `medusa-config.ts`, not a
|
|
242
|
+
Medusa plugin feature, and needs `@sentry/node` (an optional peer dependency):
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import { logger } from "@medusajs/framework/logger";
|
|
246
|
+
import { withSentryErrorReporting } from "@hartl-services/medusa-base/sentry-logger";
|
|
247
|
+
|
|
248
|
+
module.exports = defineConfig({
|
|
249
|
+
logger: withSentryErrorReporting(logger),
|
|
250
|
+
// ...
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Initialize Sentry in `instrumentation.ts` as usual; without a `SENTRY_DSN` the
|
|
255
|
+
wrapper is inert.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { completeCartWorkflow } from "@medusajs/medusa/core-flows";
|
|
2
|
+
/** The two complete-cart hooks the base composes (see README). */
|
|
3
|
+
export type CompleteCartHookName = "validate" | "orderCreated";
|
|
4
|
+
/** One participant workflow, run by id through the workflow engine. */
|
|
5
|
+
export type CompleteCartParticipantStep = {
|
|
6
|
+
readonly workflow_id: string;
|
|
7
|
+
/** Lower runs first; ties sort by module key, then workflow id. */
|
|
8
|
+
readonly order: number;
|
|
9
|
+
};
|
|
10
|
+
export type CompleteCartHookDeclarations = Partial<Record<CompleteCartHookName, CompleteCartParticipantStep>>;
|
|
11
|
+
/** Implemented by a plugin's module service. Plain data only: the base runs the workflows by id. */
|
|
12
|
+
export interface CompleteCartParticipant {
|
|
13
|
+
completeCartHooks(): CompleteCartHookDeclarations;
|
|
14
|
+
}
|
|
15
|
+
/** Input of a `validate` participant workflow: `{ input, cart }`. */
|
|
16
|
+
export type CompleteCartValidateInput = Parameters<Parameters<typeof completeCartWorkflow.hooks.validate>[0]>[0];
|
|
17
|
+
/** Input of an `orderCreated` participant workflow. */
|
|
18
|
+
export type CompleteCartOrderCreatedInput = {
|
|
19
|
+
order_id: string;
|
|
20
|
+
cart_id: string;
|
|
21
|
+
};
|
package/dist/public/index.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { definePluginFeatures } from "./descriptor";
|
|
|
3
3
|
export { resolveEffectivePluginFeatures } from "./effective-features";
|
|
4
4
|
export { isPluginFeatureEnabled, requirePluginFeature } from "./enforcement";
|
|
5
5
|
export type { EffectivePluginFeatures, PluginFeatureDefinition, PluginFeatureDescriptor, PluginFeatureProvider, } from "./types";
|
|
6
|
+
export type { CompleteCartHookDeclarations, CompleteCartHookName, CompleteCartOrderCreatedInput, CompleteCartParticipant, CompleteCartParticipantStep, CompleteCartValidateInput, } from "./complete-cart";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Logger } from "@medusajs/framework/types";
|
|
2
|
+
/**
|
|
3
|
+
* Medusa's own HTTP error-handler middleware fully "handles" every thrown
|
|
4
|
+
* route/workflow error via logger.error(...) before it can ever reach an
|
|
5
|
+
* uncaught-exception process hook, so Sentry's default Node integrations
|
|
6
|
+
* never see it. Bridging logger.error(...) itself is the only place that
|
|
7
|
+
* reliably captures every error Medusa's framework already logs internally.
|
|
8
|
+
* Errors that Medusa logs through logger.warn(err) (failing event
|
|
9
|
+
* subscribers) are reported too, at warning level.
|
|
10
|
+
*/
|
|
11
|
+
export declare function withSentryErrorReporting(logger: Logger): Logger;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.withSentryErrorReporting = withSentryErrorReporting;
|
|
37
|
+
const Sentry = __importStar(require("@sentry/node"));
|
|
38
|
+
/**
|
|
39
|
+
* Medusa's own HTTP error-handler middleware fully "handles" every thrown
|
|
40
|
+
* route/workflow error via logger.error(...) before it can ever reach an
|
|
41
|
+
* uncaught-exception process hook, so Sentry's default Node integrations
|
|
42
|
+
* never see it. Bridging logger.error(...) itself is the only place that
|
|
43
|
+
* reliably captures every error Medusa's framework already logs internally.
|
|
44
|
+
* Errors that Medusa logs through logger.warn(err) (failing event
|
|
45
|
+
* subscribers) are reported too, at warning level.
|
|
46
|
+
*/
|
|
47
|
+
function withSentryErrorReporting(logger) {
|
|
48
|
+
const originalError = logger.error.bind(logger);
|
|
49
|
+
const originalWarn = logger.warn.bind(logger);
|
|
50
|
+
return {
|
|
51
|
+
panic: logger.panic.bind(logger),
|
|
52
|
+
shouldLog: logger.shouldLog.bind(logger),
|
|
53
|
+
setLogLevel: logger.setLogLevel.bind(logger),
|
|
54
|
+
unsetLogLevel: logger.unsetLogLevel.bind(logger),
|
|
55
|
+
activity: logger.activity.bind(logger),
|
|
56
|
+
progress: logger.progress.bind(logger),
|
|
57
|
+
failure: logger.failure.bind(logger),
|
|
58
|
+
success: logger.success.bind(logger),
|
|
59
|
+
silly: logger.silly.bind(logger),
|
|
60
|
+
debug: logger.debug.bind(logger),
|
|
61
|
+
verbose: logger.verbose.bind(logger),
|
|
62
|
+
http: logger.http.bind(logger),
|
|
63
|
+
info: logger.info.bind(logger),
|
|
64
|
+
// Medusa's Redis Event Bus logs a failing subscriber's exception with
|
|
65
|
+
// warn(err), even on the final retry, so an Error passed to warn is a real
|
|
66
|
+
// failure too. Plain warning messages stay out of Sentry.
|
|
67
|
+
warn: (message) => {
|
|
68
|
+
if (message instanceof Error) {
|
|
69
|
+
Sentry.captureException(message, { level: "warning" });
|
|
70
|
+
}
|
|
71
|
+
return originalWarn(message);
|
|
72
|
+
},
|
|
73
|
+
log: logger.log.bind(logger),
|
|
74
|
+
error: (messageOrError, error) => {
|
|
75
|
+
const exception = error ?? (messageOrError instanceof Error ? messageOrError : new Error(messageOrError));
|
|
76
|
+
const loggerMessage = error && typeof messageOrError === "string" ? messageOrError : undefined;
|
|
77
|
+
Sentry.captureException(exception, loggerMessage ? { extra: { loggerMessage } } : undefined);
|
|
78
|
+
return originalError(messageOrError, error);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hartl-services/medusa-base",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Base plugin for Hartl Services Medusa shops: per-plugin feature toggles with a generic Admin settings page, a Store endpoint for storefronts,
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Base plugin for Hartl Services Medusa shops: per-plugin feature toggles with a generic Admin settings page, a Store endpoint for storefronts, enforcement helpers, the complete-cart hook composition, and the Sentry logger wrapper.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
7
7
|
".medusa/server",
|
|
@@ -28,6 +28,11 @@
|
|
|
28
28
|
"import": "./dist/public/index.js",
|
|
29
29
|
"require": "./dist/public/index.js"
|
|
30
30
|
},
|
|
31
|
+
"./sentry-logger": {
|
|
32
|
+
"types": "./dist/public/sentry-logger.d.ts",
|
|
33
|
+
"import": "./dist/public/sentry-logger.js",
|
|
34
|
+
"require": "./dist/public/sentry-logger.js"
|
|
35
|
+
},
|
|
31
36
|
"./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
|
|
32
37
|
"./.medusa/server/src/*": "./.medusa/server/src/*",
|
|
33
38
|
"./admin": {
|
|
@@ -41,12 +46,13 @@
|
|
|
41
46
|
"@medusajs/js-sdk": "^2.19.0",
|
|
42
47
|
"@medusajs/medusa": "^2.19.0",
|
|
43
48
|
"@medusajs/ui": "^4.2.1",
|
|
49
|
+
"@sentry/node": "^10.74.0",
|
|
44
50
|
"@tanstack/react-query": "^5.64.2",
|
|
45
51
|
"react": "^18.3.1",
|
|
46
52
|
"react-router-dom": "^7.18.2"
|
|
47
53
|
},
|
|
48
54
|
"dependencies": {
|
|
49
|
-
"@hartl-services/medusa-food-supplements-contracts": "^0.
|
|
55
|
+
"@hartl-services/medusa-food-supplements-contracts": "^0.11.0"
|
|
50
56
|
},
|
|
51
57
|
"devDependencies": {
|
|
52
58
|
"@medusajs/admin-sdk": "2.19.0",
|
|
@@ -55,6 +61,7 @@
|
|
|
55
61
|
"@medusajs/js-sdk": "2.19.0",
|
|
56
62
|
"@medusajs/medusa": "2.19.0",
|
|
57
63
|
"@medusajs/ui": "4.2.1",
|
|
64
|
+
"@sentry/node": "^10.74.0",
|
|
58
65
|
"@swc/core": "^1.7.28",
|
|
59
66
|
"@swc/jest": "^0.2.39",
|
|
60
67
|
"@tanstack/react-query": "5.64.2",
|
|
@@ -72,6 +79,11 @@
|
|
|
72
79
|
"engines": {
|
|
73
80
|
"node": ">=20"
|
|
74
81
|
},
|
|
82
|
+
"peerDependenciesMeta": {
|
|
83
|
+
"@sentry/node": {
|
|
84
|
+
"optional": true
|
|
85
|
+
}
|
|
86
|
+
},
|
|
75
87
|
"scripts": {
|
|
76
88
|
"build": "medusa plugin:build && tsc -p tsconfig.public.json",
|
|
77
89
|
"dev": "medusa plugin:develop",
|