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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +196 -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,179 @@ 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` (>= 0.4.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 `@hartl-services/medusa-documents`, which deliberately keeps its
140
+ `merchant` option as a config fallback for the shop master data, this plugin
141
+ has no config or environment fallback for its connection settings.
142
+
143
+ ### Admin action "Jetzt synchronisieren"
144
+
145
+ The descriptor declares the action `sync_now` ("Jetzt synchronisieren", mode
146
+ `background`, with a confirmation prompt). It runs the workflow
147
+ `payload-sync-reconcile-catalog`, which calls the same full
148
+ [reconciliation](#initial-and-repeat-reconciliation) as the script. The base
149
+ answers `202` right after starting it and emits `plugin-action.finished.v1`
150
+ with `completed` or `failed` when it ends; any failed product or a failed
151
+ orphan scan makes the run `failed`. The base records every run and refuses a
152
+ second start while one is running (`409`).
153
+
154
+ A failed run's message names the counts and the classified cause, redacted,
155
+ e.g. `Payload-Abgleich fehlgeschlagen: 4 von 4 Produkt(en) nicht gespiegelt
156
+ (Payload nicht erreichbar, Netzwerkfehler [PAYLOAD_NETWORK_ERROR]); verwaiste
157
+ Spiegel nicht geprüft (…)`. A retryable error (network, timeout, HTTP
158
+ 408/429/5xx) makes Medusa schedule the step's retry (`retryInterval`) instead
159
+ of retrying inline; the reconciliation does not wait for it and counts that
160
+ product or orphan page as failed right away. Rerun once Payload is back.
161
+
162
+ The workflow reports its progress to that run through the base's
163
+ `reportPluginActionProgress` after every page, and the Admin shows it while
164
+ the run is active:
165
+
166
+ - product pages: `current` = products scanned, `total` = products in Medusa,
167
+ label e.g. `Produkte: Seite 3, 140 gespiegelt`;
168
+ - orphan scans: `Verwaiste Produkt-Spiegel: Seite 1`,
169
+ `Verwaiste Varianten-Spiegel: Seite 1`;
170
+ - at the end: `Fertig: 140 Produkte und 312 Varianten gespiegelt, 2 verwaiste
171
+ Spiegel auf Entwurf gesetzt` (plus `, N fehlgeschlagen` for failed
172
+ products).
173
+
174
+ The reconciliation script reports nothing (it has no run). While the plugin
175
+ is "nicht konfiguriert" the action ends `failed` with the not-configured
176
+ message (for example `Payload-CMS-Sync ist nicht konfiguriert (fehlend:
177
+ payload_url).`) and no progress.
178
+
179
+ ## Feature toggles
180
+
181
+ The plugin declares a plugin switch without features to
182
+ `@hartl-services/medusa-base` under the plugin key `payload_sync`. An Admin
183
+ switches it under Settings → "Hartl Services Plugins"; its effective value is
184
+ readable from `GET /store/plugin-features/payload_sync`. The plugin has no
185
+ HTTP routes.
186
+
187
+ | Key | Label | Default | Gates | Keeps running when off |
188
+ | --------------- | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
189
+ | (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 |
190
+
191
+ While the switch is off, product and variant events are consumed without
192
+ effect: nothing is mirrored and nothing is caught up when the switch is
193
+ turned on again. Run the [reconciliation](#initial-and-repeat-reconciliation)
194
+ afterwards to bring Payload back in line; neither the script nor the
195
+ `sync_now` action reads the switch. A toggle or settings read failure fails
196
+ the subscriber, so the Event Bus retries it.
197
+
59
198
  ## Configure Medusa
60
199
 
61
200
  This repository's demo/test host, `apps/backend`, configures Payload
@@ -64,16 +203,13 @@ following the same direct `medusa-config.ts` entry shown above; it does not
64
203
  ship a Payload runtime package.
65
204
 
66
205
  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`.
206
+ options in `apps/backend/medusa-config.ts`. It is installed by being listed
207
+ there; the Admin plugin switch (see [Feature toggles](#feature-toggles)) only
208
+ pauses the mirroring.
71
209
 
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.
210
+ The demo shop passes no Payload connection: it boots with the plugin "nicht
211
+ konfiguriert" until URL and API key are saved in the Admin. Never forward
212
+ the API key to a Storefront or Admin client.
77
213
 
78
214
  The backend configuration owns these server-only options directly; Payload
79
215
  Sync exports no consumer-facing option or HTTP contract.
@@ -82,19 +218,18 @@ Sync exports no consumer-facing option or HTTP contract.
82
218
 
83
219
  | Option | Required | Implemented default | Purpose |
84
220
  | ----------------------- | -------- | ------------------------- | ---------------------------------------------------------------------------------------------- |
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
221
  | `collections.product` | no | `medusa-products` | Product mirror collection slug. |
89
222
  | `collections.variant` | no | `medusa-product-variants` | Variant mirror collection slug. |
90
223
  | `requestTimeoutMs` | no | `10000` | Timeout for one Payload REST request; accepted range `100`–`120000`. |
91
224
  | `backfillBatchSize` | no | `50` | Medusa/Payload page size for reconciliation; accepted range `1`–`500`. |
92
225
  | `backfillBatchDelayMs` | no | `250` | Delay between non-final Medusa product pages; accepted range `0`–`60000`. |
93
226
 
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.
227
+ Collection slugs must be lowercase Payload-style slugs. Invalid options and
228
+ the removed connection options fail the boot. The connection settings are
229
+ validated when they are used (an invalid one makes the plugin "nicht
230
+ konfiguriert"). `apps/backend/medusa-config.ts` passes no options; changes to
231
+ non-secret shop defaults must be modeled directly in the plugin's options
232
+ there.
98
233
 
99
234
  The REST client rejects any successful JSON response larger than 8 MiB with
100
235
  `PAYLOAD_RESPONSE_TOO_LARGE` and cancels the response stream. This fixed bound
@@ -134,11 +269,11 @@ After restarting Payload with `useAPIKey: true`:
134
269
  Keep the resulting values server-side:
135
270
 
136
271
  - 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.
272
+ - its API key in the Admin setting "API-Key" (`payload_api_key`).
138
273
 
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
274
+ Set the Admin setting "Auth-Collection" (`payload_auth_collection`) to the
275
+ auth collection's actual slug. The plugin sends the standard header
276
+ `Authorization: <auth collection> API-Key <API key>` on every
142
277
  Payload request. It never logs this header or the key. Do not put either secret
143
278
  in a public environment variable, client bundle, URL, or checked-in `.env`
144
279
  file.
@@ -384,29 +519,29 @@ not satisfy this plugin's process-death recovery contract. Reconciliation must
384
519
  use the same compatible provider and lock domain as event workers. Otherwise
385
520
  the ordering guarantee is only process-local or does not apply.
386
521
 
387
- ## Reduced startup capability check
522
+ ## Capability check
523
+
524
+ The plugin does not contact Payload at startup: the connection is a runtime
525
+ setting, so there is nothing to check at boot. A wrong URL, key or missing
526
+ permission surfaces on the first sync (structured, redacted error log) or as
527
+ a failed `sync_now` run.
388
528
 
389
- At normal startup, the plugin calls Payload's standard authenticated
390
- `/api/access` endpoint. It validates:
529
+ `runPayloadPreflight` (used by the Payload REST contract suite against a real
530
+ Payload) calls Payload's standard authenticated `/api/access` endpoint and
531
+ validates:
391
532
 
392
533
  - reachable authentication;
393
534
  - both configured collection slugs;
394
535
  - collection-level `read`, `create`, and `update` capabilities;
395
536
  - required field capabilities only when Payload exposes those field shapes.
396
537
 
397
- This is intentionally a reduced preflight. With no custom Payload code, the
538
+ This is intentionally a reduced check. With no custom Payload code, the
398
539
  standard endpoint cannot prove every field type, `unique`/index rule,
399
540
  relationship `relationTo`, drafts/version setting, delete ACL, or omitted field
400
541
  shape. The copyable schema above is the authoritative configuration contract;
401
542
  runtime writes and the real Payload contract test are the authoritative
402
543
  protocol gate.
403
544
 
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
545
  ## Initial and repeat reconciliation
411
546
 
412
547
  Reconciliation is the initial backfill and the repair tool after missed or
@@ -421,8 +556,11 @@ pnpm exec medusa exec \
421
556
  node_modules/@hartl-services/medusa-payload-sync/.medusa/server/src/scripts/reconcile-payload-catalog.js
422
557
  ```
423
558
 
424
- The command uses the shop's configured database and server-only Payload
425
- credentials.
559
+ The command uses the shop's configured database and resolves the Payload
560
+ connection exactly like the subscribers (Admin settings > default). While the plugin is "nicht konfiguriert" it logs that
561
+ once and exits without touching Payload (the Admin action fails instead). The Admin action
562
+ [`sync_now`](#admin-action-jetzt-synchronisieren) runs the same function as
563
+ the workflow `payload-sync-reconcile-catalog`.
426
564
 
427
565
  Every run:
428
566
 
@@ -450,7 +588,8 @@ metrics-only limitation.
450
588
  The runner is restartable and idempotent: safe repeat runs converge on the
451
589
  current Medusa state without duplicate mirror documents. Pagination is not a
452
590
  database snapshot, so rerun after concurrent catalog changes. V1 deliberately
453
- has no automatic schedule; operators decide when to rerun it.
591
+ has no automatic schedule; operators decide when to rerun it (script or
592
+ `sync_now`).
454
593
 
455
594
  ## Retries, logs, and incident recovery
456
595
 
@@ -488,7 +627,8 @@ missed delete events without deleting Payload history.
488
627
  - Medusa categories, collections, prices, inventory, Sales Channels, or other
489
628
  commerce facts
490
629
  - Medusa Module Links or `defineLink`
491
- - Medusa Admin UI, an Admin reconciliation route, or an automatic schedule
630
+ - a plugin-owned Admin UI or HTTP route (settings and the `sync_now` action
631
+ are served by `@hartl-services/medusa-base`), or an automatic schedule
492
632
  - Payload hard delete or a configurable delete mode
493
633
  - a plugin-owned dead-letter database/table
494
634
 
@@ -498,8 +638,9 @@ needed for their editorial model; those remain outside this plugin's contract.
498
638
  ## Plugin development contract
499
639
 
500
640
  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.
641
+ Store or Admin HTTP routes of its own; its settings and action go through the
642
+ base plugin's `/admin/plugin-features` routes. It has no public DTO, schema,
643
+ path, Storefront client, or runtime Payload-credential contract.
503
644
 
504
645
  If this component gains a Medusa HTTP route, define its request/query/response
505
646
  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.0",
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": "^0.4.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": "0.4.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
  }