@hartl-services/medusa-payload-sync 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/.medusa/server/src/lib/payload-connection.js +53 -0
  2. package/.medusa/server/src/lib/payload-sync-guard.js +51 -0
  3. package/.medusa/server/src/modules/payload-sync/domain/errors.js +96 -2
  4. package/.medusa/server/src/modules/payload-sync/domain/options.js +28 -5
  5. package/.medusa/server/src/modules/payload-sync/domain/settings.js +44 -0
  6. package/.medusa/server/src/modules/payload-sync/loaders/register-payload-client.js +17 -12
  7. package/.medusa/server/src/modules/payload-sync/service.js +116 -55
  8. package/.medusa/server/src/modules/payload-sync/services/payload-rest-client.js +1 -1
  9. package/.medusa/server/src/plugin-actions.js +10 -0
  10. package/.medusa/server/src/plugin-features.js +49 -0
  11. package/.medusa/server/src/scripts/reconcile-payload-catalog.js +93 -13
  12. package/.medusa/server/src/subscribers/payload-sync-product-deleted.js +7 -4
  13. package/.medusa/server/src/subscribers/payload-sync-product-upserted.js +7 -4
  14. package/.medusa/server/src/subscribers/payload-sync-variant-deleted.js +7 -4
  15. package/.medusa/server/src/subscribers/payload-sync-variant-upserted.js +7 -4
  16. package/.medusa/server/src/workflows/payload-sync/authoritative-reconciliation.js +19 -14
  17. package/.medusa/server/src/workflows/payload-sync/external-step-failure.js +18 -1
  18. package/.medusa/server/src/workflows/payload-sync/reconcile-catalog.js +13 -10
  19. package/.medusa/server/src/workflows/payload-sync/reconcile-full-catalog.js +30 -0
  20. package/.medusa/server/src/workflows/payload-sync/sync-product.js +3 -11
  21. package/.medusa/server/src/workflows/payload-sync/sync-variant.js +4 -2
  22. package/README.md +197 -55
  23. package/package.json +7 -4
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reconcilePayloadCatalogWorkflow = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const payload_sync_guard_1 = require("../../lib/payload-sync-guard");
6
+ const plugin_actions_1 = require("../../plugin-actions");
7
+ const reconcile_payload_catalog_1 = require("../../scripts/reconcile-payload-catalog");
8
+ const reconcilePayloadCatalogStep = (0, workflows_sdk_1.createStep)({
9
+ name: "payload-sync-reconcile-catalog-step",
10
+ // No step retry: it would rerun the whole catalog. The nested product and
11
+ // page workflows retry on their own.
12
+ maxRetries: 0,
13
+ noCompensation: true,
14
+ }, async (input, { container }) => {
15
+ // The script returns quietly while not configured; the action fails, so
16
+ // the Admin sees why nothing was synchronized.
17
+ await (0, payload_sync_guard_1.requirePayloadSyncConfigured)(container);
18
+ // Per-product failures are collected and then thrown by the shared
19
+ // function, so a partial failure ends the action as "failed".
20
+ return new workflows_sdk_1.StepResponse(await (0, reconcile_payload_catalog_1.reconcilePayloadCatalog)({ container, runId: input.run_id }));
21
+ });
22
+ /**
23
+ * Whole-catalog reconciliation as a workflow, run by the base plugin for the
24
+ * Admin action `sync_now`. Same code path as the reconcile-payload-catalog
25
+ * script.
26
+ */
27
+ exports.reconcilePayloadCatalogWorkflow = (0, workflows_sdk_1.createWorkflow)(plugin_actions_1.PAYLOAD_SYNC_RECONCILE_CATALOG_WORKFLOW_ID, function (input) {
28
+ return new workflows_sdk_1.WorkflowResponse(reconcilePayloadCatalogStep(input));
29
+ });
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb25jaWxlLWZ1bGwtY2F0YWxvZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3MvcGF5bG9hZC1zeW5jL3JlY29uY2lsZS1mdWxsLWNhdGFsb2cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBSzJDO0FBRTNDLHFFQUE0RTtBQUU1RSx5REFBa0Y7QUFDbEYsdUZBQWtGO0FBYWxGLE1BQU0sMkJBQTJCLEdBQUcsSUFBQSwwQkFBVSxFQUM1QztJQUNFLElBQUksRUFBRSxxQ0FBcUM7SUFDM0MsMEVBQTBFO0lBQzFFLHFDQUFxQztJQUNyQyxVQUFVLEVBQUUsQ0FBQztJQUNiLGNBQWMsRUFBRSxJQUFJO0NBQ3JCLEVBQ0QsS0FBSyxFQUFFLEtBQTJDLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQ25FLHdFQUF3RTtJQUN4RSwrQ0FBK0M7SUFDL0MsTUFBTSxJQUFBLGlEQUE0QixFQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzlDLG1FQUFtRTtJQUNuRSw4REFBOEQ7SUFDOUQsT0FBTyxJQUFJLDRCQUFZLENBQ3JCLE1BQU0sSUFBQSxtREFBdUIsRUFBQyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQ2xFLENBQUM7QUFDSixDQUFDLENBQ0YsQ0FBQztBQUVGOzs7O0dBSUc7QUFDVSxRQUFBLCtCQUErQixHQUFHLElBQUEsOEJBQWMsRUFJM0QsMkRBQTBDLEVBQUUsVUFBVSxLQUFLO0lBQzNELE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQywyQkFBMkIsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ2xFLENBQUMsQ0FBQyxDQUFDIn0=
@@ -4,8 +4,8 @@ exports.syncProductToPayloadWorkflow = void 0;
4
4
  const core_flows_1 = require("@medusajs/medusa/core-flows");
5
5
  const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
6
6
  const utils_1 = require("@medusajs/framework/utils");
7
- const errors_1 = require("../../modules/payload-sync/domain/errors");
8
7
  const authoritative_reconciliation_1 = require("./authoritative-reconciliation");
8
+ const external_step_failure_1 = require("./external-step-failure");
9
9
  const syncProductMirrorStep = (0, workflows_sdk_1.createStep)({
10
10
  name: "payload-sync-sync-product-mirror",
11
11
  maxRetries: 1,
@@ -20,7 +20,7 @@ const syncProductMirrorStep = (0, workflows_sdk_1.createStep)({
20
20
  }));
21
21
  }
22
22
  catch (error) {
23
- const safeLog = (0, errors_1.formatPayloadSyncLog)(error, {
23
+ (0, external_step_failure_1.handlePayloadSyncExternalStepFailure)(error, logger, {
24
24
  operation: "sync-product",
25
25
  entityType: "product",
26
26
  medusaId: input.snapshot.id,
@@ -30,11 +30,6 @@ const syncProductMirrorStep = (0, workflows_sdk_1.createStep)({
30
30
  attempt,
31
31
  idempotencyKey,
32
32
  });
33
- logger.error(safeLog);
34
- if (isPermanentPayloadSyncError(error)) {
35
- return workflows_sdk_1.StepResponse.permanentFailure(safeLog);
36
- }
37
- throw error;
38
33
  }
39
34
  });
40
35
  exports.syncProductToPayloadWorkflow = (0, workflows_sdk_1.createWorkflow)("payload-sync-sync-product", function (input) {
@@ -72,7 +67,4 @@ exports.syncProductToPayloadWorkflow = (0, workflows_sdk_1.createWorkflow)("payl
72
67
  });
73
68
  return new workflows_sdk_1.WorkflowResponse(result);
74
69
  });
75
- function isPermanentPayloadSyncError(error) {
76
- return error instanceof errors_1.PayloadSyncError && !error.retryable;
77
- }
78
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wcm9kdWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9wYXlsb2FkLXN5bmMvc3luYy1wcm9kdWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDREQUFnRTtBQUNoRSxxRUFNMkM7QUFDM0MscURBQXNFO0FBTXRFLHFFQUdrRDtBQUNsRCxpRkFBK0U7QUF1Qi9FLE1BQU0scUJBQXFCLEdBQUcsSUFBQSwwQkFBVSxFQUN0QztJQUNFLElBQUksRUFBRSxrQ0FBa0M7SUFDeEMsVUFBVSxFQUFFLENBQUM7SUFDYixhQUFhLEVBQUUsQ0FBQztJQUNoQixjQUFjLEVBQUUsSUFBSTtDQUNyQixFQUNELEtBQUssRUFDSCxLQUFpQyxFQUNqQyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxFQUNsRCxFQUFFO0lBQ0YsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUVuRSxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksNEJBQVksQ0FDckIsTUFBTSxJQUFBLDREQUE2QixFQUFDLFNBQVMsRUFBRTtZQUM3QyxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQzNCLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxRQUFRO1NBQ2pDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixNQUFNLE9BQU8sR0FBRyxJQUFBLDZCQUFvQixFQUFDLEtBQUssRUFBRTtZQUMxQyxTQUFTLEVBQUUsY0FBYztZQUN6QixVQUFVLEVBQUUsU0FBUztZQUNyQixRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQzNCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztZQUMxQixZQUFZLEVBQUUsMkJBQTJCO1lBQ3pDLFVBQVU7WUFDVixPQUFPO1lBQ1AsY0FBYztTQUNmLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFdEIsSUFBSSwyQkFBMkIsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZDLE9BQU8sNEJBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoRCxDQUFDO1FBRUQsTUFBTSxLQUFLLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQyxDQUNGLENBQUM7QUFFVyxRQUFBLDRCQUE0QixHQUFHLElBQUEsOEJBQWMsRUFJeEQsMkJBQTJCLEVBQUUsVUFBVSxLQUFLO0lBQzVDLE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBQSw4QkFBaUIsRUFBQztRQUMzQyxNQUFNLEVBQUUsU0FBUztRQUNqQixNQUFNLEVBQUU7WUFDTixJQUFJO1lBQ0osT0FBTztZQUNQLFFBQVE7WUFDUixRQUFRO1lBQ1IsYUFBYTtZQUNiLGdCQUFnQjtTQUNqQjtRQUNELE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFO0tBQzFCLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsc0NBQXNDLEVBQUUsQ0FBQyxDQUFDO0lBRTVELE1BQU0sUUFBUSxHQUFHLElBQUEseUJBQVMsRUFPeEIsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFDakMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsRUFBeUIsRUFBRTtRQUNqRCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFNUIsSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDMUIsT0FBTyw0QkFBWSxDQUFDLGdCQUFnQixDQUNsQywwQ0FBMEMsU0FBUyxHQUFHLENBQ3ZELENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTztZQUNMLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRTtZQUNkLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSztZQUNwQixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07WUFDdEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQ3RCLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDM0MsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFO2dCQUNkLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSzthQUNyQixDQUFDLENBQUM7U0FDSixDQUFDO0lBQ0osQ0FBQyxDQUNGLENBQUM7SUFFRixNQUFNLE1BQU0sR0FBRyxxQkFBcUIsQ0FBQztRQUNuQyxRQUFRO1FBQ1IsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO0tBQzNCLENBQUMsQ0FBQztJQUVILE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0QyxDQUFDLENBQUMsQ0FBQztBQUVILFNBQVMsMkJBQTJCLENBQUMsS0FBYztJQUNqRCxPQUFPLEtBQUssWUFBWSx5QkFBZ0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUM7QUFDL0QsQ0FBQyJ9
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wcm9kdWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9wYXlsb2FkLXN5bmMvc3luYy1wcm9kdWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDREQUFnRTtBQUNoRSxxRUFNMkM7QUFDM0MscURBQXNFO0FBTXRFLGlGQUErRTtBQUMvRSxtRUFBK0U7QUF1Qi9FLE1BQU0scUJBQXFCLEdBQUcsSUFBQSwwQkFBVSxFQUN0QztJQUNFLElBQUksRUFBRSxrQ0FBa0M7SUFDeEMsVUFBVSxFQUFFLENBQUM7SUFDYixhQUFhLEVBQUUsQ0FBQztJQUNoQixjQUFjLEVBQUUsSUFBSTtDQUNyQixFQUNELEtBQUssRUFDSCxLQUFpQyxFQUNqQyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxFQUNsRCxFQUFFO0lBQ0YsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUVuRSxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksNEJBQVksQ0FDckIsTUFBTSxJQUFBLDREQUE2QixFQUFDLFNBQVMsRUFBRTtZQUM3QyxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQzNCLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxRQUFRO1NBQ2pDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixJQUFBLDREQUFvQyxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUU7WUFDbEQsU0FBUyxFQUFFLGNBQWM7WUFDekIsVUFBVSxFQUFFLFNBQVM7WUFDckIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUMzQixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7WUFDMUIsWUFBWSxFQUFFLDJCQUEyQjtZQUN6QyxVQUFVO1lBQ1YsT0FBTztZQUNQLGNBQWM7U0FDZixDQUFDLENBQUM7SUFDTCxDQUFDO0FBQ0gsQ0FBQyxDQUNGLENBQUM7QUFFVyxRQUFBLDRCQUE0QixHQUFHLElBQUEsOEJBQWMsRUFJeEQsMkJBQTJCLEVBQUUsVUFBVSxLQUFLO0lBQzVDLE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBQSw4QkFBaUIsRUFBQztRQUMzQyxNQUFNLEVBQUUsU0FBUztRQUNqQixNQUFNLEVBQUU7WUFDTixJQUFJO1lBQ0osT0FBTztZQUNQLFFBQVE7WUFDUixRQUFRO1lBQ1IsYUFBYTtZQUNiLGdCQUFnQjtTQUNqQjtRQUNELE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFO0tBQzFCLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsc0NBQXNDLEVBQUUsQ0FBQyxDQUFDO0lBRTVELE1BQU0sUUFBUSxHQUFHLElBQUEseUJBQVMsRUFPeEIsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFDakMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsRUFBeUIsRUFBRTtRQUNqRCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFNUIsSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDMUIsT0FBTyw0QkFBWSxDQUFDLGdCQUFnQixDQUNsQywwQ0FBMEMsU0FBUyxHQUFHLENBQ3ZELENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTztZQUNMLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRTtZQUNkLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSztZQUNwQixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07WUFDdEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQ3RCLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDM0MsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFO2dCQUNkLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSzthQUNyQixDQUFDLENBQUM7U0FDSixDQUFDO0lBQ0osQ0FBQyxDQUNGLENBQUM7SUFFRixNQUFNLE1BQU0sR0FBRyxxQkFBcUIsQ0FBQztRQUNuQyxRQUFRO1FBQ1IsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO0tBQzNCLENBQUMsQ0FBQztJQUVILE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0QyxDQUFDLENBQUMsQ0FBQyJ9
@@ -5,6 +5,7 @@ const core_flows_1 = require("@medusajs/medusa/core-flows");
5
5
  const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
6
6
  const utils_1 = require("@medusajs/framework/utils");
7
7
  const errors_1 = require("../../modules/payload-sync/domain/errors");
8
+ const payload_connection_1 = require("../../lib/payload-connection");
8
9
  const payload_sync_1 = require("../../modules/payload-sync");
9
10
  const authoritative_reconciliation_1 = require("./authoritative-reconciliation");
10
11
  const sync_product_1 = require("./sync-product");
@@ -16,7 +17,8 @@ const findParentMirrorStep = (0, workflows_sdk_1.createStep)({
16
17
  const service = container.resolve(payload_sync_1.PAYLOAD_SYNC_MODULE);
17
18
  const logger = container.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
18
19
  try {
19
- return new workflows_sdk_1.StepResponse(await service.findProductMirror(input.productMedusaId));
20
+ const connection = await (0, payload_connection_1.resolvePayloadConnection)(container);
21
+ return new workflows_sdk_1.StepResponse(await service.findProductMirror(connection, input.productMedusaId));
20
22
  }
21
23
  catch (error) {
22
24
  const safeLog = (0, errors_1.formatPayloadSyncLog)(error, {
@@ -126,4 +128,4 @@ exports.syncVariantToPayloadWorkflow = (0, workflows_sdk_1.createWorkflow)("payl
126
128
  function isPermanentPayloadSyncError(error) {
127
129
  return error instanceof errors_1.PayloadSyncError && !error.retryable;
128
130
  }
129
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy12YXJpYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9wYXlsb2FkLXN5bmMvc3luYy12YXJpYW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDREQUFnRTtBQUNoRSxxRUFPMkM7QUFDM0MscURBQXNFO0FBT3RFLHFFQUdrRDtBQUNsRCw2REFBaUU7QUFFakUsaUZBQStFO0FBQy9FLGlEQUE4RDtBQW1DOUQsTUFBTSxvQkFBb0IsR0FBRyxJQUFBLDBCQUFVLEVBQ3JDO0lBQ0UsSUFBSSxFQUFFLGlDQUFpQztJQUN2QyxVQUFVLEVBQUUsQ0FBQztJQUNiLGFBQWEsRUFBRSxDQUFDO0NBQ2pCLEVBQ0QsS0FBSyxFQUNILEtBQWdDLEVBQ2hDLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLEVBQ2xELEVBQUU7SUFDRixNQUFNLE9BQU8sR0FDWCxTQUFTLENBQUMsT0FBTyxDQUEyQixrQ0FBbUIsQ0FBQyxDQUFDO0lBQ25FLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFbkUsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFJLDRCQUFZLENBQ3JCLE1BQU0sT0FBTyxDQUFDLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FDdkQsQ0FBQztJQUNKLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsTUFBTSxPQUFPLEdBQUcsSUFBQSw2QkFBb0IsRUFBQyxLQUFLLEVBQUU7WUFDMUMsU0FBUyxFQUFFLHFCQUFxQjtZQUNoQyxVQUFVLEVBQUUsU0FBUztZQUNyQixRQUFRLEVBQUUsS0FBSyxDQUFDLGVBQWU7WUFDL0IsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1lBQzFCLFlBQVksRUFBRSwyQkFBMkI7WUFDekMsVUFBVTtZQUNWLE9BQU87WUFDUCxj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
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy12YXJpYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9wYXlsb2FkLXN5bmMvc3luYy12YXJpYW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDREQUFnRTtBQUNoRSxxRUFPMkM7QUFDM0MscURBQXNFO0FBT3RFLHFFQUdrRDtBQUNsRCxxRUFBd0U7QUFDeEUsNkRBQWlFO0FBRWpFLGlGQUErRTtBQUMvRSxpREFBOEQ7QUFtQzlELE1BQU0sb0JBQW9CLEdBQUcsSUFBQSwwQkFBVSxFQUNyQztJQUNFLElBQUksRUFBRSxpQ0FBaUM7SUFDdkMsVUFBVSxFQUFFLENBQUM7SUFDYixhQUFhLEVBQUUsQ0FBQztDQUNqQixFQUNELEtBQUssRUFDSCxLQUFnQyxFQUNoQyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxFQUNsRCxFQUFFO0lBQ0YsTUFBTSxPQUFPLEdBQ1gsU0FBUyxDQUFDLE9BQU8sQ0FBMkIsa0NBQW1CLENBQUMsQ0FBQztJQUNuRSxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRW5FLElBQUksQ0FBQztRQUNILE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBQSw2Q0FBd0IsRUFBQyxTQUFTLENBQUMsQ0FBQztRQUU3RCxPQUFPLElBQUksNEJBQVksQ0FDckIsTUFBTSxPQUFPLENBQUMsaUJBQWlCLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FDbkUsQ0FBQztJQUNKLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsTUFBTSxPQUFPLEdBQUcsSUFBQSw2QkFBb0IsRUFBQyxLQUFLLEVBQUU7WUFDMUMsU0FBUyxFQUFFLHFCQUFxQjtZQUNoQyxVQUFVLEVBQUUsU0FBUztZQUNyQixRQUFRLEVBQUUsS0FBSyxDQUFDLGVBQWU7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
package/README.md CHANGED
@@ -22,40 +22,180 @@ remain pinned to `2.19.0`.
22
22
  ## Installation in a shop
23
23
 
24
24
  ```sh
25
- pnpm add @hartl-services/medusa-payload-sync
25
+ pnpm add @hartl-services/medusa-payload-sync @hartl-services/medusa-base
26
26
  ```
27
27
 
28
+ `@hartl-services/medusa-base` (>= 1.0.0) is a required peer: it stores the
29
+ plugin switch (see [Feature toggles](#feature-toggles)), the connection
30
+ settings (see [Settings in the Admin](#settings-in-the-admin)) and runs the
31
+ [`sync_now` action](#admin-action-jetzt-synchronisieren). Register it as a
32
+ plugin as well, before Payload Sync.
33
+
28
34
  ```ts
29
35
  // medusa-config.ts
30
36
  const plugins = [
37
+ { resolve: "@hartl-services/medusa-base", options: {} },
31
38
  {
32
39
  resolve: "@hartl-services/medusa-payload-sync",
33
- options: {
34
- payloadUrl: process.env.PAYLOAD_URL,
35
- payloadApiKey: process.env.PAYLOAD_SERVICE_API_KEY,
36
- // optional, defaults to "users"
37
- payloadAuthCollection: process.env.PAYLOAD_AUTH_COLLECTION,
38
- },
40
+ // No connection options: URL, API key and auth collection are Admin
41
+ // settings. Only the config-only options below may be passed here.
42
+ options: {},
39
43
  },
40
44
  // ...other plugins
41
45
  ];
42
46
  ```
43
47
 
44
- Required options and environment variables:
45
-
46
- - `payloadUrl` — Payload origin, `http`/`https` (`PAYLOAD_URL`).
47
- - `payloadApiKey` — API key of the dedicated Payload service user
48
- (`PAYLOAD_SERVICE_API_KEY`).
49
-
50
- Everything else (`payloadAuthCollection`, `collections.product`,
51
- `collections.variant`, `requestTimeoutMs`, `backfillBatchSize`,
52
- `backfillBatchDelayMs`) is optional; see
53
- [Options and exact defaults](#options-and-exact-defaults) below. Keep
54
- `payloadApiKey` out of any public/browser environment-variable prefix and
55
- never forward it to a Storefront or Admin client. Also complete
48
+ No option is required. The Payload URL, API key and auth collection are
49
+ runtime settings maintained only in the Admin (see
50
+ [Settings in the Admin](#settings-in-the-admin)); there is no
51
+ `medusa-config.ts` or environment fallback. The former options `payloadUrl`,
52
+ `payloadApiKey` and `payloadAuthCollection` are rejected at boot with an
53
+ error that points to the Admin settings. The config-only options
54
+ (`collections.product`, `collections.variant`, `requestTimeoutMs`,
55
+ `backfillBatchSize`, `backfillBatchDelayMs`) are described in
56
+ [Options and exact defaults](#options-and-exact-defaults) below. Also complete
56
57
  [Configure Payload authentication](#configure-payload-authentication) below,
57
58
  which the plugin itself does not automate.
58
59
 
60
+ ## Settings in the Admin
61
+
62
+ The plugin declares three settings to `@hartl-services/medusa-base`. An Admin
63
+ maintains them under Settings → "Hartl Services Plugins" → Payload-CMS-Sync
64
+ ("Öffnen"):
65
+
66
+ | Key | Label | Type | Required | Default |
67
+ | ------------------------- | --------------- | ------ | -------- | ------- |
68
+ | `payload_url` | Payload-URL | url | yes | none |
69
+ | `payload_api_key` | API-Key | secret | yes | none |
70
+ | `payload_auth_collection` | Auth-Collection | string | no | `users` |
71
+
72
+ Precedence per key: value stored in the Admin > default. The page shows each
73
+ value's source; the API key is stored encrypted by the base plugin and never
74
+ displayed ("gesetzt" only). "Löschen" removes a stored value: the URL or API
75
+ key is then missing (the plugin is "nicht konfiguriert"), the auth collection
76
+ returns to `users`. Saving a changed URL or auth collection also clears the
77
+ stored API key (the settings declare `invalidates: ["payload_api_key"]`), so
78
+ the key is never sent to a host it was not entered for; the plugin is "nicht
79
+ konfiguriert" until the key is entered again. Rotating the backend's `COOKIE_SECRET` makes a stored API key unreadable; it
80
+ then counts as not set until it is saved again (see the base plugin's README).
81
+
82
+ Every sync resolves the settings anew, so a change applies to the next event
83
+ without a restart. The settings are read at app level, never by the module
84
+ service (a module does not reach into other modules):
85
+
86
+ - `resolvePayloadConnection(container)` (`src/lib/payload-connection.ts`)
87
+ reads them through the base plugin with the caller's application container
88
+ (workflow step, subscriber, script), validates them and returns the
89
+ connection; while incomplete it throws the permanent
90
+ `PayloadSyncNotConfiguredError`.
91
+ - `describePayloadSyncConfiguration(container)` answers the same check
92
+ without throwing (subscriber guard, reconciliation script, `sync_now`).
93
+ - Every Payload-facing method of the module service takes that connection
94
+ as its first parameter, for example
95
+ `service.syncProductSnapshot(connection, snapshot)` or
96
+ `service.findProductMirror(connection, medusaId)`. The service builds its
97
+ REST client from it lazily and reuses it while URL, key and auth collection
98
+ stay the same. An injected `payloadSyncRestClient` (test seam) is used
99
+ as-is and the connection is ignored.
100
+ Resolved values are validated like the former options (`http`/`https` URL
101
+ with one trailing slash removed, non-empty key, lowercase auth-collection
102
+ slug); an invalid value counts as missing. The collections, timeout and
103
+ backfill options stay config-only.
104
+
105
+ ### Not configured
106
+
107
+ While URL or API key is missing or invalid, the plugin is "nicht
108
+ konfiguriert". That is also the state of every fresh installation until the
109
+ settings are saved:
110
+
111
+ - the backend boots normally and does not contact Payload at startup;
112
+ - the settings page and the plugin hub show "nicht konfiguriert" with the
113
+ missing keys;
114
+ - the subscribers check the plugin switch first, then the settings, and
115
+ return without mirroring; product and variant changes made meanwhile are
116
+ not caught up automatically (run the reconciliation afterwards);
117
+ - the reconciliation script returns an empty summary without touching
118
+ Payload; the `sync_now` action ends `failed` with the not-configured
119
+ message;
120
+ - one warning per process names the missing or invalid keys (never values),
121
+ for example `Payload-CMS-Sync ist nicht konfiguriert (fehlend:
122
+ payload_url).`; after a successful resolution the warning is re-armed for
123
+ the next outage.
124
+
125
+ ### Migrating an existing shop
126
+
127
+ Earlier versions read the connection from `medusa-config.ts`
128
+ (`PAYLOAD_URL`, `PAYLOAD_SERVICE_API_KEY`, `PAYLOAD_AUTH_COLLECTION`). The
129
+ settings only exist from this version on, so upgrade in this order:
130
+
131
+ 1. Remove the three options from the plugin entry (the boot fails while they
132
+ are still passed) and drop the environment variables.
133
+ 2. Deploy. The plugin reports "nicht konfiguriert"; product and variant
134
+ events in the meantime are not mirrored.
135
+ 3. Enter URL, API key and auth collection in the Admin (Settings → "Hartl
136
+ Services Plugins" → Payload-CMS-Sync).
137
+ 4. Run "Jetzt synchronisieren" to catch up on the changes missed meanwhile.
138
+
139
+ Unlike the Documents module of `@hartl-services/medusa-base`, which
140
+ deliberately keeps its `merchant` option as a config fallback for the shop
141
+ master data, this plugin has no config or environment fallback for its
142
+ connection settings.
143
+
144
+ ### Admin action "Jetzt synchronisieren"
145
+
146
+ The descriptor declares the action `sync_now` ("Jetzt synchronisieren", mode
147
+ `background`, with a confirmation prompt). It runs the workflow
148
+ `payload-sync-reconcile-catalog`, which calls the same full
149
+ [reconciliation](#initial-and-repeat-reconciliation) as the script. The base
150
+ answers `202` right after starting it and emits `plugin-action.finished.v1`
151
+ with `completed` or `failed` when it ends; any failed product or a failed
152
+ orphan scan makes the run `failed`. The base records every run and refuses a
153
+ second start while one is running (`409`).
154
+
155
+ A failed run's message names the counts and the classified cause, redacted,
156
+ e.g. `Payload-Abgleich fehlgeschlagen: 4 von 4 Produkt(en) nicht gespiegelt
157
+ (Payload nicht erreichbar, Netzwerkfehler [PAYLOAD_NETWORK_ERROR]); verwaiste
158
+ Spiegel nicht geprüft (…)`. A retryable error (network, timeout, HTTP
159
+ 408/429/5xx) makes Medusa schedule the step's retry (`retryInterval`) instead
160
+ of retrying inline; the reconciliation does not wait for it and counts that
161
+ product or orphan page as failed right away. Rerun once Payload is back.
162
+
163
+ The workflow reports its progress to that run through the base's
164
+ `reportPluginActionProgress` after every page, and the Admin shows it while
165
+ the run is active:
166
+
167
+ - product pages: `current` = products scanned, `total` = products in Medusa,
168
+ label e.g. `Produkte: Seite 3, 140 gespiegelt`;
169
+ - orphan scans: `Verwaiste Produkt-Spiegel: Seite 1`,
170
+ `Verwaiste Varianten-Spiegel: Seite 1`;
171
+ - at the end: `Fertig: 140 Produkte und 312 Varianten gespiegelt, 2 verwaiste
172
+ Spiegel auf Entwurf gesetzt` (plus `, N fehlgeschlagen` for failed
173
+ products).
174
+
175
+ The reconciliation script reports nothing (it has no run). While the plugin
176
+ is "nicht konfiguriert" the action ends `failed` with the not-configured
177
+ message (for example `Payload-CMS-Sync ist nicht konfiguriert (fehlend:
178
+ payload_url).`) and no progress.
179
+
180
+ ## Feature toggles
181
+
182
+ The plugin declares a plugin switch without features to
183
+ `@hartl-services/medusa-base` under the plugin key `payload_sync`. An Admin
184
+ switches it under Settings → "Hartl Services Plugins"; its effective value is
185
+ readable from `GET /store/plugin-features/payload_sync`. The plugin has no
186
+ HTTP routes.
187
+
188
+ | Key | Label | Default | Gates | Keeps running when off |
189
+ | --------------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
190
+ | (plugin switch) | Payload-CMS-Sync | on | subscribers `payload-sync-product-upserted`, `payload-sync-product-deleted`, `payload-sync-variant-upserted`, `payload-sync-variant-deleted` | the module, existing Payload mirror documents (unchanged), the manual reconciliation script and the `sync_now` action |
191
+
192
+ While the switch is off, product and variant events are consumed without
193
+ effect: nothing is mirrored and nothing is caught up when the switch is
194
+ turned on again. Run the [reconciliation](#initial-and-repeat-reconciliation)
195
+ afterwards to bring Payload back in line; neither the script nor the
196
+ `sync_now` action reads the switch. A toggle or settings read failure fails
197
+ the subscriber, so the Event Bus retries it.
198
+
59
199
  ## Configure Medusa
60
200
 
61
201
  This repository's demo/test host, `apps/backend`, configures Payload
@@ -64,16 +204,13 @@ following the same direct `medusa-config.ts` entry shown above; it does not
64
204
  ship a Payload runtime package.
65
205
 
66
206
  Feature selection and non-secret defaults belong directly in the plugin's
67
- options in `apps/backend/medusa-config.ts`. It is enabled by being listed
68
- there, not by a separate runtime feature flag. `medusa-config.ts` selects the
69
- default Payload auth collection `users`, overridable via
70
- `PAYLOAD_AUTH_COLLECTION`.
207
+ options in `apps/backend/medusa-config.ts`. It is installed by being listed
208
+ there; the Admin plugin switch (see [Feature toggles](#feature-toggles)) only
209
+ pauses the mirroring.
71
210
 
72
- Dokploy must provide the server-only runtime values `PAYLOAD_URL` and
73
- `PAYLOAD_SERVICE_API_KEY`; `PAYLOAD_AUTH_COLLECTION` can override the
74
- default. `apps/backend/medusa-config.ts` validates and passes those values to
75
- the local plugin. Never use a public/browser environment-variable prefix for
76
- the API key or forward it to a Storefront or Admin client.
211
+ The demo shop passes no Payload connection: it boots with the plugin "nicht
212
+ konfiguriert" until URL and API key are saved in the Admin. Never forward
213
+ the API key to a Storefront or Admin client.
77
214
 
78
215
  The backend configuration owns these server-only options directly; Payload
79
216
  Sync exports no consumer-facing option or HTTP contract.
@@ -82,19 +219,18 @@ Sync exports no consumer-facing option or HTTP contract.
82
219
 
83
220
  | Option | Required | Implemented default | Purpose |
84
221
  | ----------------------- | -------- | ------------------------- | ---------------------------------------------------------------------------------------------- |
85
- | `payloadUrl` | yes | none | Payload origin using `http` or `https`; one trailing slash is removed. The client adds `/api`. |
86
- | `payloadApiKey` | yes | none | API key of the dedicated Payload service user. |
87
- | `payloadAuthCollection` | no | `users` | Payload auth collection slug used in the API-key Authorization header. |
88
222
  | `collections.product` | no | `medusa-products` | Product mirror collection slug. |
89
223
  | `collections.variant` | no | `medusa-product-variants` | Variant mirror collection slug. |
90
224
  | `requestTimeoutMs` | no | `10000` | Timeout for one Payload REST request; accepted range `100`–`120000`. |
91
225
  | `backfillBatchSize` | no | `50` | Medusa/Payload page size for reconciliation; accepted range `1`–`500`. |
92
226
  | `backfillBatchDelayMs` | no | `250` | Delay between non-final Medusa product pages; accepted range `0`–`60000`. |
93
227
 
94
- Collection and auth slugs must be lowercase Payload-style slugs.
95
- `apps/backend/medusa-config.ts` currently forwards only the resolved URL,
96
- API key, and auth collection; changes to non-secret shop defaults must be
97
- modeled directly in the plugin's options there.
228
+ Collection slugs must be lowercase Payload-style slugs. Invalid options and
229
+ the removed connection options fail the boot. The connection settings are
230
+ validated when they are used (an invalid one makes the plugin "nicht
231
+ konfiguriert"). `apps/backend/medusa-config.ts` passes no options; changes to
232
+ non-secret shop defaults must be modeled directly in the plugin's options
233
+ there.
98
234
 
99
235
  The REST client rejects any successful JSON response larger than 8 MiB with
100
236
  `PAYLOAD_RESPONSE_TOO_LARGE` and cancels the response stream. This fixed bound
@@ -134,11 +270,11 @@ After restarting Payload with `useAPIKey: true`:
134
270
  Keep the resulting values server-side:
135
271
 
136
272
  - its document ID as `PAYLOAD_SYNC_SERVICE_USER_ID` in the Payload process;
137
- - its API key as `PAYLOAD_SERVICE_API_KEY` in the Medusa process.
273
+ - its API key in the Admin setting "API-Key" (`payload_api_key`).
138
274
 
139
- Set `payloadAuthCollection` to the auth collection's actual slug. The plugin
140
- sends the standard header
141
- `Authorization: <payloadAuthCollection> API-Key <payloadApiKey>` on every
275
+ Set the Admin setting "Auth-Collection" (`payload_auth_collection`) to the
276
+ auth collection's actual slug. The plugin sends the standard header
277
+ `Authorization: <auth collection> API-Key <API key>` on every
142
278
  Payload request. It never logs this header or the key. Do not put either secret
143
279
  in a public environment variable, client bundle, URL, or checked-in `.env`
144
280
  file.
@@ -384,29 +520,29 @@ not satisfy this plugin's process-death recovery contract. Reconciliation must
384
520
  use the same compatible provider and lock domain as event workers. Otherwise
385
521
  the ordering guarantee is only process-local or does not apply.
386
522
 
387
- ## Reduced startup capability check
523
+ ## Capability check
524
+
525
+ The plugin does not contact Payload at startup: the connection is a runtime
526
+ setting, so there is nothing to check at boot. A wrong URL, key or missing
527
+ permission surfaces on the first sync (structured, redacted error log) or as
528
+ a failed `sync_now` run.
388
529
 
389
- At normal startup, the plugin calls Payload's standard authenticated
390
- `/api/access` endpoint. It validates:
530
+ `runPayloadPreflight` (used by the Payload REST contract suite against a real
531
+ Payload) calls Payload's standard authenticated `/api/access` endpoint and
532
+ validates:
391
533
 
392
534
  - reachable authentication;
393
535
  - both configured collection slugs;
394
536
  - collection-level `read`, `create`, and `update` capabilities;
395
537
  - required field capabilities only when Payload exposes those field shapes.
396
538
 
397
- This is intentionally a reduced preflight. With no custom Payload code, the
539
+ This is intentionally a reduced check. With no custom Payload code, the
398
540
  standard endpoint cannot prove every field type, `unique`/index rule,
399
541
  relationship `relationTo`, drafts/version setting, delete ACL, or omitted field
400
542
  shape. The copyable schema above is the authoritative configuration contract;
401
543
  runtime writes and the real Payload contract test are the authoritative
402
544
  protocol gate.
403
545
 
404
- Recognizable auth, schema, permission, and other non-retryable contract errors
405
- fail startup with the affected collection or capability. Temporary network
406
- failures, timeouts, HTTP 408, 429, and 5xx responses produce a structured,
407
- redacted warning and allow startup in degraded mode; later workflows retry.
408
- Remote preflight I/O is skipped in Medusa's data-loader-only/migration context.
409
-
410
546
  ## Initial and repeat reconciliation
411
547
 
412
548
  Reconciliation is the initial backfill and the repair tool after missed or
@@ -421,8 +557,11 @@ pnpm exec medusa exec \
421
557
  node_modules/@hartl-services/medusa-payload-sync/.medusa/server/src/scripts/reconcile-payload-catalog.js
422
558
  ```
423
559
 
424
- The command uses the shop's configured database and server-only Payload
425
- credentials.
560
+ The command uses the shop's configured database and resolves the Payload
561
+ connection exactly like the subscribers (Admin settings > default). While the plugin is "nicht konfiguriert" it logs that
562
+ once and exits without touching Payload (the Admin action fails instead). The Admin action
563
+ [`sync_now`](#admin-action-jetzt-synchronisieren) runs the same function as
564
+ the workflow `payload-sync-reconcile-catalog`.
426
565
 
427
566
  Every run:
428
567
 
@@ -450,7 +589,8 @@ metrics-only limitation.
450
589
  The runner is restartable and idempotent: safe repeat runs converge on the
451
590
  current Medusa state without duplicate mirror documents. Pagination is not a
452
591
  database snapshot, so rerun after concurrent catalog changes. V1 deliberately
453
- has no automatic schedule; operators decide when to rerun it.
592
+ has no automatic schedule; operators decide when to rerun it (script or
593
+ `sync_now`).
454
594
 
455
595
  ## Retries, logs, and incident recovery
456
596
 
@@ -488,7 +628,8 @@ missed delete events without deleting Payload history.
488
628
  - Medusa categories, collections, prices, inventory, Sales Channels, or other
489
629
  commerce facts
490
630
  - Medusa Module Links or `defineLink`
491
- - Medusa Admin UI, an Admin reconciliation route, or an automatic schedule
631
+ - a plugin-owned Admin UI or HTTP route (settings and the `sync_now` action
632
+ are served by `@hartl-services/medusa-base`), or an automatic schedule
492
633
  - Payload hard delete or a configurable delete mode
493
634
  - a plugin-owned dead-letter database/table
494
635
 
@@ -498,8 +639,9 @@ needed for their editorial model; those remain outside this plugin's contract.
498
639
  ## Plugin development contract
499
640
 
500
641
  Payload Sync is server-to-server integration code and intentionally exposes no
501
- Store or Admin HTTP routes. It has no public DTO, schema, path, Storefront
502
- client, or runtime Payload-credential contract.
642
+ Store or Admin HTTP routes of its own; its settings and action go through the
643
+ base plugin's `/admin/plugin-features` routes. It has no public DTO, schema,
644
+ path, Storefront client, or runtime Payload-credential contract.
503
645
 
504
646
  If this component gains a Medusa HTTP route, define its request/query/response
505
647
  DTOs with `@medusajs/framework/zod`, derive public types from those schemas,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hartl-services/medusa-payload-sync",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Mirrors Medusa product and variant facts into Payload CMS.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -27,7 +27,8 @@
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@medusajs/framework": "^2.19.0",
30
- "@medusajs/medusa": "^2.19.0"
30
+ "@medusajs/medusa": "^2.19.0",
31
+ "@hartl-services/medusa-base": "^1.0.0"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@medusajs/cli": "2.19.0",
@@ -38,7 +39,8 @@
38
39
  "@types/jest": "^29.5.14",
39
40
  "@types/node": "^20.12.11",
40
41
  "jest": "^29.7.0",
41
- "typescript": "^5.6.2"
42
+ "typescript": "^5.6.2",
43
+ "@hartl-services/medusa-base": "1.0.0"
42
44
  },
43
45
  "engines": {
44
46
  "node": ">=20"
@@ -47,6 +49,7 @@
47
49
  "build": "medusa plugin:build",
48
50
  "typecheck": "tsc --noEmit",
49
51
  "test:unit": "jest --config jest.config.js",
50
- "test:contract": "jest --config jest.contract.config.js --runInBand"
52
+ "test:contract": "jest --config jest.contract.config.js --runInBand",
53
+ "pretest:unit": "pnpm --filter @hartl-services/medusa-food-supplements-contracts build && pnpm --filter @hartl-services/medusa-base build"
51
54
  }
52
55
  }