@hartl-services/medusa-base 2.6.1 → 2.7.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 (148) hide show
  1. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.d.ts +3 -2
  2. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ImageSettingInput.js +4 -4
  3. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginActionsSection.js +4 -4
  4. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.d.ts +16 -0
  5. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginBreadcrumb.js +25 -0
  6. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginDetailPage.js +1 -1
  7. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.d.ts +5 -4
  8. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeatureSections.js +8 -5
  9. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.d.ts +4 -4
  10. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesCard.js +24 -27
  11. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.d.ts +2 -2
  12. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginFeaturesSettingsPage.js +9 -9
  13. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.d.ts +5 -1
  14. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginHubCard.js +11 -15
  15. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.d.ts +10 -4
  16. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginPageShell.js +10 -5
  17. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.d.ts +0 -1
  18. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +73 -26
  19. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.d.ts +5 -1
  20. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginStatusChips.js +8 -6
  21. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.d.ts +11 -0
  22. package/.medusa/server/src/admin/admin-components/features/plugin-features/components/ShopMasterDataBanner.js +15 -0
  23. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +36 -5
  24. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +144 -20
  25. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +36 -5
  26. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.d.ts +15 -0
  27. package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSwitch.js +66 -0
  28. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +144 -20
  29. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +49 -0
  30. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +72 -0
  31. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.d.ts +1 -12
  32. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-draft.js +4 -20
  33. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +43 -0
  34. package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +66 -0
  35. package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +22 -2
  36. package/.medusa/server/src/admin/admin-components/i18n/texts.js +29 -7
  37. package/.medusa/server/src/admin/admin-components/index.d.ts +12 -0
  38. package/.medusa/server/src/admin/admin-components/index.js +11 -0
  39. package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.d.ts +22 -0
  40. package/.medusa/server/src/admin/admin-components/shared/ui/AdminPageHeader.js +8 -0
  41. package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.d.ts +26 -0
  42. package/.medusa/server/src/admin/admin-components/shared/ui/AdminSection.js +12 -0
  43. package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.d.ts +23 -0
  44. package/.medusa/server/src/admin/admin-components/shared/ui/BreadcrumbTrail.js +20 -0
  45. package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.d.ts +21 -0
  46. package/.medusa/server/src/admin/admin-components/shared/ui/FileDropField.js +33 -0
  47. package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.d.ts +27 -0
  48. package/.medusa/server/src/admin/admin-components/shared/ui/FocusModalShell.js +13 -0
  49. package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.d.ts +13 -0
  50. package/.medusa/server/src/admin/admin-components/shared/ui/InfoTooltip.js +8 -0
  51. package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.d.ts +22 -0
  52. package/.medusa/server/src/admin/admin-components/shared/ui/MultiSelectDropdown.js +14 -0
  53. package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.d.ts +10 -0
  54. package/.medusa/server/src/admin/admin-components/shared/ui/PluginIcon.js +10 -0
  55. package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.d.ts +27 -0
  56. package/.medusa/server/src/admin/admin-components/shared/ui/SwitchRow.js +15 -0
  57. package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.d.ts +15 -0
  58. package/.medusa/server/src/admin/admin-components/shared/ui/WidgetHeader.js +8 -0
  59. package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.d.ts +13 -0
  60. package/.medusa/server/src/admin/admin-components/shared/ui/file-drop.js +16 -0
  61. package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.d.ts +13 -0
  62. package/.medusa/server/src/admin/admin-components/shared/ui/multi-select.js +11 -0
  63. package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.d.ts +12 -0
  64. package/.medusa/server/src/admin/admin-components/shared/ui/plugin-icon.js +29 -0
  65. package/.medusa/server/src/admin/index.js +3118 -2020
  66. package/.medusa/server/src/admin/index.mjs +3121 -2023
  67. package/.medusa/server/src/api/admin-first-login-password-policy.js +56 -0
  68. package/.medusa/server/src/api/answer-actor-type-casing-not-found.js +26 -0
  69. package/.medusa/server/src/api/answer-code-provider-route-not-found.js +34 -0
  70. package/.medusa/server/src/api/code-account-password-routes.js +92 -0
  71. package/.medusa/server/src/api/middlewares.js +82 -17
  72. package/.medusa/server/src/api/password-policy.js +55 -10
  73. package/.medusa/server/src/api/require-login-code-customer-email.js +40 -0
  74. package/.medusa/server/src/api/store/customer-auth/login-code/route.js +17 -0
  75. package/.medusa/server/src/api/store/customer-auth/password-policy/route.js +19 -0
  76. package/.medusa/server/src/customer-auth/application/prepare-code-account-password-reset.js +111 -0
  77. package/.medusa/server/src/customer-auth/application/request-login-code.js +145 -0
  78. package/.medusa/server/src/customer-auth/customer-auth-methods-snapshot.js +55 -0
  79. package/.medusa/server/src/customer-auth/customer-password-policy.js +40 -0
  80. package/.medusa/server/src/customer-auth/domain/account-linking.js +53 -0
  81. package/.medusa/server/src/customer-auth/domain/auth-methods.js +32 -0
  82. package/.medusa/server/src/customer-auth/domain/login-code.js +39 -0
  83. package/.medusa/server/src/customer-auth/login-code-accounts.js +146 -0
  84. package/.medusa/server/src/customer-auth/login-code-state.js +139 -0
  85. package/.medusa/server/src/customer-auth/plugin-features.js +80 -0
  86. package/.medusa/server/src/customer-auth/remove-provider-identity.js +18 -0
  87. package/.medusa/server/src/customer-auth/start-customer-auth-methods.js +20 -0
  88. package/.medusa/server/src/documents/plugin-features.js +8 -2
  89. package/.medusa/server/src/email/application/deliver-ephemeral-auth-mail.js +186 -0
  90. package/.medusa/server/src/email/application/deliver-login-code.js +89 -0
  91. package/.medusa/server/src/email/application/handle-customer-verification-event.js +29 -168
  92. package/.medusa/server/src/email/application/handle-password-reset-event.js +27 -166
  93. package/.medusa/server/src/email/customer-verification-snapshot.js +20 -108
  94. package/.medusa/server/src/email/domain/business-keys.js +15 -2
  95. package/.medusa/server/src/email/plugin-features.js +8 -3
  96. package/.medusa/server/src/email/rendering/default-templates.js +2 -1
  97. package/.medusa/server/src/email/templates/blocks/dynamic-blocks.js +19 -1
  98. package/.medusa/server/src/email/templates/defaults/documents.js +7 -1
  99. package/.medusa/server/src/email/templates/defaults/subjects.js +3 -1
  100. package/.medusa/server/src/email/templates/defaults/texts.js +5 -2
  101. package/.medusa/server/src/email/templates/render.js +2 -1
  102. package/.medusa/server/src/email/templates/sample-data.js +2 -1
  103. package/.medusa/server/src/email/templates/validate.js +8 -3
  104. package/.medusa/server/src/email/types/email-kinds.js +4 -2
  105. package/.medusa/server/src/email/types/template-data.js +9 -1
  106. package/.medusa/server/src/modules/customer-auth/index.js +14 -0
  107. package/.medusa/server/src/modules/customer-auth/service.js +35 -0
  108. package/.medusa/server/src/modules/email/migrations/Migration20261010090000.js +20 -0
  109. package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +4 -1
  110. package/.medusa/server/src/modules/plugin-features/service.js +26 -1
  111. package/.medusa/server/src/providers/email-otp/index.js +8 -0
  112. package/.medusa/server/src/providers/email-otp/service.js +96 -0
  113. package/.medusa/server/src/public/descriptor.js +117 -5
  114. package/.medusa/server/src/public/effective-features.js +22 -1
  115. package/.medusa/server/src/public/index.js +4 -2
  116. package/.medusa/server/src/public/plugin-icons.js +28 -0
  117. package/.medusa/server/src/public/shop-master-data.js +33 -14
  118. package/.medusa/server/src/shared/lib/index.js +2 -1
  119. package/.medusa/server/src/shared/lib/refreshing-snapshot.js +122 -0
  120. package/.medusa/server/src/shop-config/build-food-shop-config.js +38 -1
  121. package/README.md +436 -87
  122. package/dist/customer-auth/customer-auth-methods-snapshot.d.ts +25 -0
  123. package/dist/customer-auth/customer-auth-methods-snapshot.js +54 -0
  124. package/dist/customer-auth/domain/auth-methods.d.ts +16 -0
  125. package/dist/customer-auth/domain/auth-methods.js +31 -0
  126. package/dist/customer-auth/plugin-features.d.ts +2 -0
  127. package/dist/customer-auth/plugin-features.js +79 -0
  128. package/dist/email/customer-verification-snapshot.d.ts +3 -15
  129. package/dist/email/customer-verification-snapshot.js +19 -107
  130. package/dist/email/types/email-kinds.d.ts +4 -3
  131. package/dist/email/types/email-kinds.js +3 -1
  132. package/dist/email/types/template-data.d.ts +8 -0
  133. package/dist/email/types/template-data.js +8 -0
  134. package/dist/public/descriptor.js +116 -4
  135. package/dist/public/effective-features.d.ts +10 -0
  136. package/dist/public/effective-features.js +21 -0
  137. package/dist/public/index.d.ts +2 -1
  138. package/dist/public/index.js +3 -1
  139. package/dist/public/plugin-icons.d.ts +7 -0
  140. package/dist/public/plugin-icons.js +27 -0
  141. package/dist/public/shop-master-data.js +32 -13
  142. package/dist/public/types.d.ts +63 -1
  143. package/dist/shared/lib/index.d.ts +1 -0
  144. package/dist/shared/lib/index.js +1 -0
  145. package/dist/shared/lib/refreshing-snapshot.d.ts +52 -0
  146. package/dist/shared/lib/refreshing-snapshot.js +121 -0
  147. package/dist/shop-config/build-food-shop-config.js +37 -0
  148. package/package.json +8 -3
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRefreshingSnapshot = exports.SNAPSHOT_REFRESH_MS = void 0;
4
+ /**
5
+ * In-memory copy of one value for the places that cannot await it: Medusa
6
+ * reads some `projectConfig.http` settings synchronously on every login, and
7
+ * the shop preset puts a getter backed by such a copy there, so a change in
8
+ * the Admin takes effect without a restart.
9
+ *
10
+ * - Boot: `start` loads the value once.
11
+ * - Afterwards an unref'd timer refreshes every 30 s, so a change reaches an
12
+ * idle instance too. A read that finds the copy older than 30 s (a blocked
13
+ * timer, say) also starts one refresh in the background
14
+ * (stale-while-revalidate) and still answers from the copy. A change thus
15
+ * reaches a running instance within about 30 s plus the duration of the
16
+ * read.
17
+ * - A failed read keeps the last value (initially `initial`) and is logged;
18
+ * the next attempt waits another 30 s. Neither a throwing reader nor a
19
+ * throwing logger escapes.
20
+ *
21
+ * The state lives on `globalThis` under a `Symbol.for(key)`: the preset
22
+ * (`dist`) and the Medusa-loaded plugin code (`.medusa/server`) are compiled
23
+ * separately and would otherwise each hold their own copy.
24
+ */
25
+ exports.SNAPSHOT_REFRESH_MS = 30_000;
26
+ const createRefreshingSnapshot = (options) => {
27
+ const { key, initial } = options;
28
+ const symbol = Symbol.for(key);
29
+ const state = () => {
30
+ const holder = globalThis;
31
+ holder[symbol] ??= {
32
+ value: initial,
33
+ refreshedAt: null,
34
+ refreshing: null,
35
+ timer: null,
36
+ read: null,
37
+ warn: null,
38
+ };
39
+ return holder[symbol];
40
+ };
41
+ const logFailure = (current, error) => {
42
+ try {
43
+ current.warn?.(`${options.describe(current.value)}: ${error instanceof Error ? error.message : "unknown error"}`);
44
+ }
45
+ catch {
46
+ // A broken logger must not turn a failed refresh into a throw.
47
+ }
48
+ };
49
+ const refresh = () => {
50
+ const current = state();
51
+ if (!current.read) {
52
+ return Promise.resolve();
53
+ }
54
+ if (current.refreshing) {
55
+ return current.refreshing;
56
+ }
57
+ const read = current.read;
58
+ // Started from a microtask so the assignment below always precedes `finally`.
59
+ const refreshing = Promise.resolve().then(async () => {
60
+ try {
61
+ current.value = await read();
62
+ }
63
+ catch (error) {
64
+ logFailure(current, error);
65
+ }
66
+ finally {
67
+ current.refreshedAt = Date.now();
68
+ current.refreshing = null;
69
+ }
70
+ });
71
+ current.refreshing = refreshing;
72
+ return refreshing;
73
+ };
74
+ const stopTimer = (current) => {
75
+ if (current.timer) {
76
+ clearInterval(current.timer);
77
+ current.timer = null;
78
+ }
79
+ };
80
+ return {
81
+ refresh,
82
+ start: (input) => {
83
+ const current = state();
84
+ current.read = input.read;
85
+ current.warn = input.warn;
86
+ stopTimer(current);
87
+ current.timer = setInterval(() => {
88
+ void refresh();
89
+ }, exports.SNAPSHOT_REFRESH_MS);
90
+ // An idle timer must not keep the process (or a test run) alive.
91
+ current.timer.unref();
92
+ return refresh();
93
+ },
94
+ stop: () => stopTimer(state()),
95
+ current: () => {
96
+ const current = state();
97
+ if (current.read &&
98
+ !current.refreshing &&
99
+ (current.refreshedAt === null ||
100
+ Date.now() - current.refreshedAt >= exports.SNAPSHOT_REFRESH_MS)) {
101
+ void refresh();
102
+ }
103
+ return current.value;
104
+ },
105
+ setForTests: (value) => {
106
+ const current = state();
107
+ if (value === null) {
108
+ stopTimer(current);
109
+ current.value = initial;
110
+ current.refreshedAt = null;
111
+ current.refreshing = null;
112
+ current.read = null;
113
+ current.warn = null;
114
+ return;
115
+ }
116
+ current.value = value;
117
+ current.refreshedAt = Date.now();
118
+ },
119
+ };
120
+ };
121
+ exports.createRefreshingSnapshot = createRefreshingSnapshot;
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildFoodShopConfig = buildFoodShopConfig;
4
4
  exports.defineFoodShopConfig = defineFoodShopConfig;
5
5
  const logger_1 = require("@medusajs/framework/logger");
6
+ const customer_auth_1 = require("@hartl-services/medusa-food-supplements-contracts/schemas/customer-auth");
6
7
  const utils_1 = require("@medusajs/framework/utils");
7
8
  const config_1 = require("../public/config");
9
+ const customer_auth_methods_snapshot_1 = require("../customer-auth/customer-auth-methods-snapshot");
8
10
  const customer_verification_snapshot_1 = require("../email/customer-verification-snapshot");
9
11
  const sentry_logger_1 = require("../public/sentry-logger");
10
12
  const options_1 = require("./options");
@@ -101,6 +103,30 @@ function buildFoodShopConfig(options, environment = process.env) {
101
103
  : []),
102
104
  (0, config_1.createSmtpNotificationModuleConfig)((0, config_1.resolveSmtp)(env, allowInsecure)),
103
105
  s3CacheStorage.fileModule,
106
+ {
107
+ // Replaces Medusa's default auth entry (same module key): the same
108
+ // `emailpass` provider as the default plus the code login. defineConfig
109
+ // merges its MFA defaults back into this entry. Which of the two a
110
+ // customer may use is decided at run time by `authMethodsPerActor`
111
+ // (customer_auth switches), not by this list.
112
+ resolve: "@medusajs/medusa/auth",
113
+ options: {
114
+ providers: [
115
+ {
116
+ resolve: "@medusajs/medusa/auth-emailpass",
117
+ id: "emailpass",
118
+ },
119
+ {
120
+ resolve: "@hartl-services/medusa-base/providers/email-otp",
121
+ id: customer_auth_1.EMAIL_OTP_AUTH_PROVIDER,
122
+ // Must equal projectConfig.http.jwtSecret (below): the code
123
+ // request reads its key material from there, the provider from
124
+ // this option; both derive the same HMAC key.
125
+ options: { hmacSecret: env.JWT_SECRET },
126
+ },
127
+ ],
128
+ },
129
+ },
104
130
  {
105
131
  resolve: "@medusajs/medusa/tax",
106
132
  options: {
@@ -244,6 +270,17 @@ function buildFoodShopConfig(options, environment = process.env) {
244
270
  return (0, customer_verification_snapshot_1.customerVerificationActors)();
245
271
  },
246
272
  },
273
+ // The same technique for the login methods (customer_auth switches,
274
+ // see customer-auth-methods-snapshot.ts). Customers: emailpass, the
275
+ // code login, both, or none when both switches are off. Admin users
276
+ // are pinned to emailpass: without an allowlist Medusa would let
277
+ // them use every registered provider, the code login included.
278
+ authMethodsPerActor: {
279
+ get customer() {
280
+ return (0, customer_auth_methods_snapshot_1.customerAuthMethods)();
281
+ },
282
+ user: ["emailpass"],
283
+ },
247
284
  },
248
285
  // The storefront turns its customer JWT into a Medusa browser session
249
286
  // at login, so its browser-side cart and payment calls carry the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hartl-services/medusa-base",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
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, the root redirect, cart-promotion link repair, the built-in E-Mail, Documents and S3 file storage modules, config helpers with the turnkey food-shop preset, and the Sentry logger wrapper and instrumentation.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -101,7 +101,7 @@
101
101
  "mime-types": "3.0.1",
102
102
  "nodemailer": "6.10.1",
103
103
  "ulid": "^2.4.0",
104
- "@hartl-services/medusa-food-supplements-contracts": "^0.26.0"
104
+ "@hartl-services/medusa-food-supplements-contracts": "^0.27.0"
105
105
  },
106
106
  "devDependencies": {
107
107
  "@medusajs/admin-sdk": "2.19.0",
@@ -116,6 +116,10 @@
116
116
  "@swc/core": "^1.7.28",
117
117
  "@swc/jest": "^0.2.39",
118
118
  "@tanstack/react-query": "5.64.2",
119
+ "@testing-library/dom": "10.4.2",
120
+ "@testing-library/jest-dom": "6.9.1",
121
+ "@testing-library/react": "16.3.3",
122
+ "@testing-library/user-event": "14.6.7",
119
123
  "@types/jest": "^29.5.14",
120
124
  "@types/jsonwebtoken": "^9.0.10",
121
125
  "@types/mailparser": "3.4.6",
@@ -126,6 +130,7 @@
126
130
  "@types/react-dom": "^18.2.25",
127
131
  "@types/smtp-server": "3.5.10",
128
132
  "jest": "^29.7.0",
133
+ "jest-environment-jsdom": "29.7.0",
129
134
  "mailparser": "3.7.2",
130
135
  "react": "^18.3.1",
131
136
  "react-dom": "^18.3.1",
@@ -146,7 +151,7 @@
146
151
  "scripts": {
147
152
  "build": "medusa plugin:build && tsc -p tsconfig.public.json && tsc -p tsconfig.admin-components.json",
148
153
  "dev": "medusa plugin:develop",
149
- "typecheck": "tsc --noEmit && tsc -p tsconfig.type-tests.json --noEmit",
154
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.type-tests.json --noEmit && tsc -p tsconfig.component-tests.json",
150
155
  "pretest:unit": "pnpm --filter @hartl-services/medusa-food-supplements-contracts build",
151
156
  "test:unit": "jest",
152
157
  "pretest:contract": "pnpm --filter @hartl-services/medusa-food-supplements-contracts build",