@hartl-services/medusa-base 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/admin-components/features/plugin-features/components/PluginSettingsForm.js +12 -9
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +20 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +5 -1
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +20 -4
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.d.ts +0 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/plugin-view.js +0 -5
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.d.ts +4 -0
- package/.medusa/server/src/admin/admin-components/features/plugin-features/lib/settings-layout.js +4 -0
- package/.medusa/server/src/admin/admin-components/i18n/texts.d.ts +1 -2
- package/.medusa/server/src/admin/admin-components/i18n/texts.js +1 -2
- package/.medusa/server/src/admin/index.js +142 -87
- package/.medusa/server/src/admin/index.mjs +144 -89
- package/.medusa/server/src/api/admin/email/templates/[kind]/send-test/route.js +7 -1
- package/.medusa/server/src/customer-auth/plugin-features.js +10 -10
- package/.medusa/server/src/email/application/warn-credential-expiry.js +77 -0
- package/.medusa/server/src/email/config/index.js +8 -2
- package/.medusa/server/src/email/config/notification-module.js +28 -2
- package/.medusa/server/src/email/domain/business-keys.js +5 -2
- package/.medusa/server/src/email/domain/failure-classification.js +9 -1
- package/.medusa/server/src/email/plugin-features.js +123 -1
- package/.medusa/server/src/email/rendering/default-templates.js +16 -1
- package/.medusa/server/src/email/rendering/render-email.js +2 -1
- package/.medusa/server/src/email/types/email-kinds.js +2 -1
- package/.medusa/server/src/email/types/template-data.js +8 -1
- package/.medusa/server/src/jobs/email-credential-expiry.js +27 -0
- package/.medusa/server/src/modules/email/domain/message-state.js +3 -1
- package/.medusa/server/src/modules/email/migrations/Migration20261011120000.js +20 -0
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +27 -6
- package/.medusa/server/src/modules/plugin-features/service.js +4 -3
- package/.medusa/server/src/providers/smtp/delivery-settings.js +75 -0
- package/.medusa/server/src/providers/smtp/graph-transport.js +150 -0
- package/.medusa/server/src/providers/smtp/service.js +105 -37
- package/.medusa/server/src/providers/smtp/types.js +7 -1
- package/.medusa/server/src/public/descriptor.js +24 -3
- package/.medusa/server/src/shared/lib/dates.js +8 -2
- package/.medusa/server/src/shop-config/build-food-shop-config.js +3 -5
- package/README.md +100 -65
- package/dist/customer-auth/plugin-features.js +9 -9
- package/dist/email/config/index.d.ts +6 -1
- package/dist/email/config/index.js +7 -1
- package/dist/email/config/notification-module.d.ts +25 -0
- package/dist/email/config/notification-module.js +27 -1
- package/dist/email/types/email-kinds.d.ts +2 -1
- package/dist/email/types/email-kinds.js +1 -0
- package/dist/email/types/template-data.d.ts +10 -0
- package/dist/email/types/template-data.js +7 -0
- package/dist/public/descriptor.js +23 -2
- package/dist/public/types.d.ts +14 -4
- package/dist/shared/lib/dates.d.ts +2 -0
- package/dist/shared/lib/dates.js +7 -1
- package/dist/shop-config/build-food-shop-config.d.ts +1 -1
- package/dist/shop-config/build-food-shop-config.js +2 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ packing lists) and S3 file storage, and the turnkey `medusa-config.ts` preset
|
|
|
50
50
|
`@hartl-services/medusa-base/config` and Sentry's `register()` from
|
|
51
51
|
`@hartl-services/medusa-base/instrumentation` (see "Config helpers" and
|
|
52
52
|
"Sentry instrumentation").
|
|
53
|
-
- Sends the shop's transactional e-mails over SMTP (module `email`, see
|
|
53
|
+
- Sends the shop's transactional e-mails over SMTP or Microsoft 365, chosen in the Admin (module `email`, see
|
|
54
54
|
"E-Mail"), issues invoices, cancellation documents and packing lists as
|
|
55
55
|
private PDFs (module `documents`, see "Dokumente") and stores files in
|
|
56
56
|
S3-compatible storage behind the `/files` gateway (see "Dateispeicher (S3)").
|
|
@@ -234,13 +234,18 @@ All optional; the Admin response always carries them (`null`, `[]` or
|
|
|
234
234
|
unchanged, e.g. by the plugin switch of a switchable plugin). The Admin locks
|
|
235
235
|
the switch of the last enabled top-level feature with a hint. The Admin DTO
|
|
236
236
|
field is `require_enabled_feature: boolean` (`false` when not declared).
|
|
237
|
-
- `setting_groups`: `{ name, description?, note?, requires_feature? }` per
|
|
237
|
+
- `setting_groups`: `{ name, description?, note?, requires_feature?, visible_when? }` per
|
|
238
238
|
settings group. `name` equals the `group` of at least one setting and is
|
|
239
239
|
unique; `requires_feature` is a declared feature key, the Admin dims the group
|
|
240
240
|
(still editable) while that feature is not effectively enabled.
|
|
241
|
+
`visible_when: { setting, equals }` names a `select` or `boolean` setting
|
|
242
|
+
outside the group and one of its values: the group applies only while that
|
|
243
|
+
setting has the value. The Admin hides it otherwise (by the form's current
|
|
244
|
+
value), and its required settings do not count as `missing`; stored values
|
|
245
|
+
are kept. The Admin DTO carries `visible_when` or `null`.
|
|
241
246
|
- Per setting: `hint` (short text under the field, shown instead of
|
|
242
247
|
`description`), `placeholder` (not for `boolean`, `select`, `image`,
|
|
243
|
-
`color`), `width` (`"full"` default or `"half"`: consecutive half settings
|
|
248
|
+
`color`, `date`), `width` (`"full"` default or `"half"`: consecutive half settings
|
|
244
249
|
share a two-column row; not for `boolean`) and `section` (sub-heading inside
|
|
245
250
|
the group, shared by consecutive settings with the same value).
|
|
246
251
|
|
|
@@ -338,7 +343,7 @@ in-memory copy of the toggle (see "Kontobestätigung per E-Mail").
|
|
|
338
343
|
|
|
339
344
|
Configuration a plugin reads at RUN time (for example an external system's
|
|
340
345
|
URL and API key) is declared in the descriptor and edited on the plugin's
|
|
341
|
-
Admin page. Boot-time provider configuration (
|
|
346
|
+
Admin page. Boot-time provider configuration (S3, Sentry, Redis) and
|
|
342
347
|
function-valued options stay in `medusa-config.ts`.
|
|
343
348
|
|
|
344
349
|
```ts
|
|
@@ -383,7 +388,8 @@ class DemoModuleService extends MedusaService({ /* models */ }) {
|
|
|
383
388
|
through Medusa's `/admin/uploads` into the public File Module storage and
|
|
384
389
|
previews; replacing or removing it leaves the old file in storage), `color`
|
|
385
390
|
(a hex color `#rrggbb`, stored lowercase; the Admin shows a hex field with a
|
|
386
|
-
color picker and checks the format before saving)
|
|
391
|
+
color picker and checks the format before saving), `date` (a calendar day
|
|
392
|
+
`YYYY-MM-DD`; the Admin shows `AdminDatePicker`). An optional `group`
|
|
387
393
|
(non-empty text) is a section heading: the Admin starts a new section with
|
|
388
394
|
that heading whenever the group changes from one setting to the next. Keys
|
|
389
395
|
follow the feature key format and are unique. A `secret` has no default;
|
|
@@ -394,8 +400,8 @@ class DemoModuleService extends MedusaService({ /* models */ }) {
|
|
|
394
400
|
`api_url` so a stored key is never sent to a new host. `definePluginFeatures`
|
|
395
401
|
throws at import time otherwise (also for an `invalidates` entry that is not
|
|
396
402
|
a secret of the plugin). The Admin renders a `select` as a dropdown, gives
|
|
397
|
-
number inputs their bounds and shows "
|
|
398
|
-
|
|
403
|
+
number inputs their bounds and shows "Wird gelöscht, wenn … sich ändert"
|
|
404
|
+
under each secret named in an `invalidates`.
|
|
399
405
|
- Precedence per key: stored in the Admin > `pluginSettingsFallback`
|
|
400
406
|
(medusa-config) > declared default > not set. A value that does not fit the
|
|
401
407
|
declared type is skipped. A plugin is `configured` when every required
|
|
@@ -1326,7 +1332,7 @@ have no dependency on Medusa; the subpath does not load `@sentry/node`.
|
|
|
1326
1332
|
| `resolvePublicOrigin(value, name, allowHttp)`, `shopUrl(origin, path)` | Validate a bare HTTP(S) origin; build an absolute URL that cannot leave the origin |
|
|
1327
1333
|
| `resolveStripe(values)` | Checks the `sk_` key and the `whsec_` webhook secret |
|
|
1328
1334
|
| `resolveRedisEventBus(environment, phase)` | `{ url } \| undefined`: optional in development, required at runtime elsewhere, never used in a build, authenticated `rediss://` in production |
|
|
1329
|
-
| `createSmtpNotificationModuleConfig`, `resolveSmtp`, `SMTP_ENVIRONMENT_VARIABLES`, `SMTP_BUILD_PLACEHOLDERS
|
|
1335
|
+
| `createEmailNotificationModuleConfig`, `defineShopEmailConfiguration` (deprecated: `createSmtpNotificationModuleConfig`, `resolveSmtp`, `SMTP_ENVIRONMENT_VARIABLES`, `SMTP_BUILD_PLACEHOLDERS`) | Mail notification provider and E-Mail configuration (see "E-Mail") |
|
|
1330
1336
|
| `createS3CacheStorageConfig`, `createS3CacheFileModuleConfig`, `resolveS3Credentials`, `resolveExpirationStrategy`, `S3_BUILD_PLACEHOLDERS` | S3 file storage (see "Dateispeicher (S3)") |
|
|
1331
1337
|
| `createDefaultDocumentHtmlFactory`, `DOCUMENTS_BUILD_PLACEHOLDERS` | Documents markup and build placeholder (see "Dokumente") |
|
|
1332
1338
|
|
|
@@ -1373,36 +1379,32 @@ this export (or `sentry-logger`) lists `@sentry/node` in its own
|
|
|
1373
1379
|
## E-Mail
|
|
1374
1380
|
|
|
1375
1381
|
The base owns transactional e-mail for the shop: logical email messages,
|
|
1376
|
-
attempts, rendering, the Medusa Notification integration, SMTP
|
|
1377
|
-
retries and e-mail-specific Admin operations. It is
|
|
1378
|
-
|
|
1382
|
+
attempts, rendering, the Medusa Notification integration, the SMTP and
|
|
1383
|
+
Microsoft 365 transports, retries and e-mail-specific Admin operations. It is
|
|
1384
|
+
the `email` module, its notification provider (`providers/smtp`, id `smtp`),
|
|
1385
|
+
its subscribers, jobs and
|
|
1379
1386
|
workflows, and the Admin page `/settings/hartl-services/email`. There is no
|
|
1380
1387
|
separate e-mail package since 1.0.0.
|
|
1381
1388
|
|
|
1382
1389
|
### Configuration
|
|
1383
1390
|
|
|
1384
|
-
The
|
|
1385
|
-
`
|
|
1386
|
-
`@hartl-services/medusa-base/config`);
|
|
1391
|
+
The notification provider is a `modules` entry built by
|
|
1392
|
+
`createEmailNotificationModuleConfig` (from
|
|
1393
|
+
`@hartl-services/medusa-base/config`); which service it sends through and the
|
|
1394
|
+
credentials are set in the Admin (see "Versand"). The branding and rendering
|
|
1387
1395
|
configuration goes into the `email` namespace of the base options:
|
|
1388
1396
|
|
|
1389
1397
|
```ts
|
|
1390
|
-
import {
|
|
1391
|
-
createSmtpNotificationModuleConfig,
|
|
1392
|
-
resolveSmtp,
|
|
1393
|
-
SMTP_ENVIRONMENT_VARIABLES,
|
|
1394
|
-
} from "@hartl-services/medusa-base/config";
|
|
1395
|
-
|
|
1396
|
-
// Validates the seven SMTP_* variables (see "SMTP environment helpers").
|
|
1397
|
-
const smtp = resolveSmtp(
|
|
1398
|
-
Object.fromEntries(
|
|
1399
|
-
SMTP_ENVIRONMENT_VARIABLES.map((name) => [name, process.env[name] ?? ""]),
|
|
1400
|
-
) as Record<(typeof SMTP_ENVIRONMENT_VARIABLES)[number], string>,
|
|
1401
|
-
process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test",
|
|
1402
|
-
);
|
|
1398
|
+
import { createEmailNotificationModuleConfig } from "@hartl-services/medusa-base/config";
|
|
1403
1399
|
|
|
1404
1400
|
export default defineConfig({
|
|
1405
|
-
modules: [
|
|
1401
|
+
modules: [
|
|
1402
|
+
createEmailNotificationModuleConfig({
|
|
1403
|
+
// Permits "Verschlüsselung: Keine" (a local SMTP server); never in production.
|
|
1404
|
+
allowInsecure:
|
|
1405
|
+
process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test",
|
|
1406
|
+
}),
|
|
1407
|
+
],
|
|
1406
1408
|
plugins: [
|
|
1407
1409
|
{
|
|
1408
1410
|
resolve: "@hartl-services/medusa-base",
|
|
@@ -1456,24 +1458,73 @@ affiliate-reminder and partner-application e-mails come from
|
|
|
1456
1458
|
`@hartl-services/medusa-food-supplements-contracts/events/documents` and
|
|
1457
1459
|
`/events/affiliate`, so installing the base does not pull in Affiliate.
|
|
1458
1460
|
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
development/test):
|
|
1462
|
-
|
|
1463
|
-
```text
|
|
1464
|
-
SMTP_HOST=
|
|
1465
|
-
SMTP_PORT=
|
|
1466
|
-
SMTP_SECURE=
|
|
1467
|
-
SMTP_REQUIRE_TLS=
|
|
1468
|
-
SMTP_USER=
|
|
1469
|
-
SMTP_PASSWORD=
|
|
1470
|
-
SMTP_FROM=
|
|
1471
|
-
```
|
|
1461
|
+
The provider reads no environment variables (since 2.9.0; the former
|
|
1462
|
+
`SMTP_*` variables are ignored).
|
|
1472
1463
|
|
|
1473
1464
|
Set `REDIS_URL` to use `@medusajs/event-bus-redis` instead of Medusa's local
|
|
1474
1465
|
Event Bus; production requires an authenticated `rediss://` URL. See "Event
|
|
1475
1466
|
Bus" below for retry/backoff behavior.
|
|
1476
1467
|
|
|
1468
|
+
### Versand
|
|
1469
|
+
|
|
1470
|
+
The page E-Mail → "Versand" (`/settings/hartl-services/email/delivery`, linked
|
|
1471
|
+
under "Verwaltung") edits the plugin's settings. It stays reachable while the
|
|
1472
|
+
E-Mail plugin is off, because the login-code mail is still sent then.
|
|
1473
|
+
|
|
1474
|
+
| Key | Type | Required |
|
|
1475
|
+
|---|---|---|
|
|
1476
|
+
| `provider` (Versand über, group "Anbieter") | select `smtp` \| `microsoft365` | yes |
|
|
1477
|
+
| `smtp_host`, `smtp_port` (default 587), `smtp_security` (`starttls` default, `tls`, `none`), `smtp_from` (Absender, `Name <address>` allowed) | string / number / select / string | yes, while SMTP |
|
|
1478
|
+
| `smtp_user`, `smtp_password` (secret) | string / secret | no (no login without a user) |
|
|
1479
|
+
| `microsoft_tenant_id`, `microsoft_client_id`, `microsoft_client_secret` (secret), `microsoft_client_secret_expires_on` (date), `microsoft_mailbox` (Postfach) | string / secret / date | yes, while Microsoft 365 |
|
|
1480
|
+
|
|
1481
|
+
The groups "SMTP" and "Microsoft 365" are shown and required only for the
|
|
1482
|
+
selected provider (`visible_when`). Changing the host deletes the SMTP
|
|
1483
|
+
password; changing tenant or client id deletes the client secret.
|
|
1484
|
+
|
|
1485
|
+
The provider reads the settings on every send, never at boot; a shop without
|
|
1486
|
+
them boots and its mails fail as `not_configured` (retried like a connection
|
|
1487
|
+
failure, then `failed`; a log warning names the missing keys). `none`
|
|
1488
|
+
encryption is accepted only with `allowInsecure`. A rejected login (SMTP
|
|
1489
|
+
`EAUTH`, a Graph token or 401/403 error) is `auth_failed` and not retried.
|
|
1490
|
+
The test mail of the template editor shows both as their own message.
|
|
1491
|
+
|
|
1492
|
+
**Microsoft 365** sends with Microsoft Graph `POST /users/{mailbox}/sendMail`
|
|
1493
|
+
and an app-only token (client credentials, cached in memory per tenant,
|
|
1494
|
+
client and secret). Graph has one body, so the mail goes out as HTML; it is
|
|
1495
|
+
saved to the mailbox's Sent Items. A request above 4 MB (large PDF
|
|
1496
|
+
attachments) fails as `invalid_content`. 429 and 5xx are temporary, other 4xx
|
|
1497
|
+
permanent. Setup:
|
|
1498
|
+
|
|
1499
|
+
1. Microsoft Entra admin center → App registrations → New registration
|
|
1500
|
+
(single tenant, no redirect URI). Note the Application (client) ID and
|
|
1501
|
+
Directory (tenant) ID.
|
|
1502
|
+
2. Certificates & secrets → New client secret (at most 24 months); copy the
|
|
1503
|
+
value and its expiry date.
|
|
1504
|
+
3. Do **not** grant the Graph application permission `Mail.Send` in Entra: it
|
|
1505
|
+
would allow sending as every mailbox. Grant it in Exchange Online, limited
|
|
1506
|
+
to the shop's mailbox (RBAC for Applications), in Exchange Online
|
|
1507
|
+
PowerShell:
|
|
1508
|
+
|
|
1509
|
+
```powershell
|
|
1510
|
+
New-ServicePrincipal -AppId <client-id> -ObjectId <enterprise-app-object-id> -DisplayName "Shop Mail"
|
|
1511
|
+
New-ManagementScope -Name "Shop Mailbox" -RecipientRestrictionFilter "PrimarySmtpAddress -eq 'shop@example.com'"
|
|
1512
|
+
New-ManagementRoleAssignment -App <client-id> -Role "Application Mail.Send" -CustomResourceScope "Shop Mailbox"
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
(`<enterprise-app-object-id>` is the object id under Enterprise
|
|
1516
|
+
applications, not the one of the app registration.)
|
|
1517
|
+
4. In the Admin: E-Mail → Versand → Anbieter "Microsoft 365", enter tenant
|
|
1518
|
+
id, client id, secret, its expiry date and the mailbox; send a test mail
|
|
1519
|
+
from a template.
|
|
1520
|
+
|
|
1521
|
+
Seven days before "Secret gültig bis" (shop time zone) the daily job
|
|
1522
|
+
`email-credential-expiry` (07:00 server time, while the E-Mail plugin is on
|
|
1523
|
+
and Microsoft 365 is selected) sends the mail `system.credential_expiry.admin`
|
|
1524
|
+
to the e-mail of the Shop-Stammdaten, once per client id and expiry date (a
|
|
1525
|
+
log warning when the Shop-Stammdaten have no e-mail). A new secret with a new
|
|
1526
|
+
date warns again.
|
|
1527
|
+
|
|
1477
1528
|
### Feature toggles
|
|
1478
1529
|
|
|
1479
1530
|
The E-Mail module declares its toggles to `@hartl-services/medusa-base` under the
|
|
@@ -1996,30 +2047,14 @@ configuration (blank `displayName`, a non-function `layout` or renderer, an
|
|
|
1996
2047
|
unknown renderer kind) fails at startup and not at the first send. Custom
|
|
1997
2048
|
renderers must escape dynamic values in `bodyHtml` themselves.
|
|
1998
2049
|
|
|
1999
|
-
### SMTP
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
them only while building.
|
|
2008
|
-
- `resolveSmtp(values, allowInsecure)` — validates the values and returns the
|
|
2009
|
-
`ResolvedSmtpConfiguration` for `createSmtpNotificationModuleConfig`. It
|
|
2010
|
-
rejects a port outside 1–65535, a non-`"true"`/`"false"` boolean and an
|
|
2011
|
-
invalid `SMTP_FROM`. `allowInsecure` permits plain SMTP (development, test,
|
|
2012
|
-
build); otherwise `SMTP_SECURE` or `SMTP_REQUIRE_TLS` must be `true`.
|
|
2013
|
-
|
|
2014
|
-
Runtime requires `SMTP_HOST`, `SMTP_PORT`, `SMTP_SECURE`, `SMTP_REQUIRE_TLS`,
|
|
2015
|
-
`SMTP_USER`, `SMTP_PASSWORD`, and `SMTP_FROM`. `SMTP_FROM` is a bare address
|
|
2016
|
-
or carries the sender's display name: `Example GmbH <info@example.com>` (quote
|
|
2017
|
-
the value in a `.env` file). `SMTP_SECURE=true` selects
|
|
2018
|
-
implicit TLS; `SMTP_REQUIRE_TLS=true` requires STARTTLS. Outside development
|
|
2019
|
-
and test, at least one must be true. Certificate verification is never
|
|
2020
|
-
disabled. Development and test may set both to `false` for an isolated local
|
|
2021
|
-
SMTP server. SMTP endpoints and credentials never belong in the shop
|
|
2022
|
-
configuration.
|
|
2050
|
+
### Deprecated SMTP helpers
|
|
2051
|
+
|
|
2052
|
+
`createSmtpNotificationModuleConfig(smtp)`, `resolveSmtp`,
|
|
2053
|
+
`SMTP_ENVIRONMENT_VARIABLES` and `SMTP_BUILD_PLACEHOLDERS` remain exported
|
|
2054
|
+
for shops that still read `SMTP_*` in their `medusa-config.ts`. The values
|
|
2055
|
+
given to `createSmtpNotificationModuleConfig` only fill SMTP settings that are
|
|
2056
|
+
not stored in the Admin (the Admin status does not count them as configured).
|
|
2057
|
+
Use `createEmailNotificationModuleConfig` and the "Versand" page instead.
|
|
2023
2058
|
|
|
2024
2059
|
### Delivery Semantics
|
|
2025
2060
|
|
|
@@ -7,32 +7,32 @@ const PASSWORD_RULES = "Passwort-Regeln";
|
|
|
7
7
|
exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
8
8
|
plugin_key: customer_auth_1.CUSTOMER_AUTH_PLUGIN_KEY,
|
|
9
9
|
label: "Kunden-Login",
|
|
10
|
-
description: "
|
|
10
|
+
description: "Wie sich Kunden anmelden. Mindestens eine Methode bleibt eingeschaltet; Admin-Benutzer melden sich immer mit E-Mail und Passwort an.",
|
|
11
11
|
summary: "Anmeldemethoden und Passwort-Regeln für Kunden.",
|
|
12
12
|
icon: "ShieldCheck",
|
|
13
13
|
switchable: false,
|
|
14
14
|
features_heading: "Anmeldemethoden",
|
|
15
|
-
features_note: "Wirkt nach ca.
|
|
15
|
+
features_note: "Wirkt nach ca. 1 Minute.",
|
|
16
16
|
all_off_warning: "Keine Methode eingeschaltet: Kunden können sich nicht mehr anmelden.",
|
|
17
17
|
require_enabled_feature: true,
|
|
18
18
|
features: [
|
|
19
19
|
{
|
|
20
20
|
key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
|
|
21
21
|
label: "E-Mail + Passwort",
|
|
22
|
-
description: "Anmeldung, Registrierung und Passwort
|
|
22
|
+
description: "Anmeldung, Registrierung und Passwort zurücksetzen.",
|
|
23
23
|
default_enabled: true,
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
key: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailOtp,
|
|
27
27
|
label: "Anmeldecode per E-Mail",
|
|
28
|
-
description: "
|
|
28
|
+
description: "Anmeldung mit einem 6-stelligen Code per E-Mail; für neue Adressen entsteht ein Konto.",
|
|
29
29
|
default_enabled: false,
|
|
30
30
|
},
|
|
31
31
|
],
|
|
32
32
|
setting_groups: [
|
|
33
33
|
{
|
|
34
34
|
name: PASSWORD_RULES,
|
|
35
|
-
description: "
|
|
35
|
+
description: "Für Kunden mit „E-Mail + Passwort“. Admin-Benutzer: mindestens 15 Zeichen.",
|
|
36
36
|
requires_feature: customer_auth_1.CUSTOMER_AUTH_FEATURES.emailPassword,
|
|
37
37
|
},
|
|
38
38
|
],
|
|
@@ -40,8 +40,8 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
40
40
|
{
|
|
41
41
|
key: "password_min_length",
|
|
42
42
|
label: "Mindestlänge",
|
|
43
|
-
description: "
|
|
44
|
-
hint: "8 bis 128 Zeichen. Empfohlen:
|
|
43
|
+
description: "Gilt bei Registrierung und Passwort-Zurücksetzen; bestehende Passwörter bleiben gültig.",
|
|
44
|
+
hint: "8 bis 128 Zeichen. Empfohlen: 15 (NIST SP 800-63B).",
|
|
45
45
|
group: PASSWORD_RULES,
|
|
46
46
|
width: "half",
|
|
47
47
|
type: "number",
|
|
@@ -54,7 +54,7 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
54
54
|
key: "password_require_mixed_case",
|
|
55
55
|
label: "Groß- und Kleinbuchstaben verlangen",
|
|
56
56
|
description: "Mindestens ein Groß- und ein Kleinbuchstabe.",
|
|
57
|
-
hint: "NIST rät von
|
|
57
|
+
hint: "NIST rät von Zeichenregeln ab, Länge schützt besser.",
|
|
58
58
|
group: PASSWORD_RULES,
|
|
59
59
|
type: "boolean",
|
|
60
60
|
default: false,
|
|
@@ -70,7 +70,7 @@ exports.customerAuthPluginFeatures = (0, descriptor_1.definePluginFeatures)({
|
|
|
70
70
|
{
|
|
71
71
|
key: "password_require_symbol",
|
|
72
72
|
label: "Sonderzeichen verlangen",
|
|
73
|
-
description: "Mindestens ein Sonderzeichen
|
|
73
|
+
description: "Mindestens ein Sonderzeichen.",
|
|
74
74
|
group: PASSWORD_RULES,
|
|
75
75
|
type: "boolean",
|
|
76
76
|
default: false,
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import type { ResolvedSmtpConfiguration, ShopEmailConfiguration } from "../types";
|
|
2
|
-
export { createSmtpNotificationModuleConfig } from "./notification-module";
|
|
2
|
+
export { createEmailNotificationModuleConfig, createSmtpNotificationModuleConfig, } from "./notification-module";
|
|
3
3
|
export declare const defineShopEmailConfiguration: <Configuration extends ShopEmailConfiguration>(configuration: Configuration) => Configuration;
|
|
4
4
|
export type { ResolvedSmtpConfiguration, ShopEmailConfiguration, } from "../types";
|
|
5
|
+
/** @deprecated The provider is set in the Admin (E-Mail > Versand). */
|
|
5
6
|
export declare const SMTP_ENVIRONMENT_VARIABLES: readonly ["SMTP_HOST", "SMTP_PORT", "SMTP_SECURE", "SMTP_USER", "SMTP_PASSWORD", "SMTP_FROM", "SMTP_REQUIRE_TLS"];
|
|
6
7
|
/**
|
|
8
|
+
* @deprecated The provider is set in the Admin (E-Mail > Versand).
|
|
9
|
+
*
|
|
7
10
|
* `medusa build` loads the configuration without deployment secrets. These
|
|
8
11
|
* placeholders only satisfy the required-variable checks of a build; they
|
|
9
12
|
* never reach a running server.
|
|
10
13
|
*/
|
|
11
14
|
export declare const SMTP_BUILD_PLACEHOLDERS: Readonly<Record<string, string>>;
|
|
12
15
|
/**
|
|
16
|
+
* @deprecated The provider is set in the Admin (E-Mail > Versand).
|
|
17
|
+
*
|
|
13
18
|
* Validates the SMTP environment values and returns the transport
|
|
14
19
|
* configuration. `allowInsecure` permits plain SMTP for development, tests
|
|
15
20
|
* and builds; otherwise `SMTP_SECURE` or `SMTP_REQUIRE_TLS` must be `true`.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveSmtp = exports.SMTP_BUILD_PLACEHOLDERS = exports.SMTP_ENVIRONMENT_VARIABLES = exports.defineShopEmailConfiguration = exports.createSmtpNotificationModuleConfig = void 0;
|
|
3
|
+
exports.resolveSmtp = exports.SMTP_BUILD_PLACEHOLDERS = exports.SMTP_ENVIRONMENT_VARIABLES = exports.defineShopEmailConfiguration = exports.createSmtpNotificationModuleConfig = exports.createEmailNotificationModuleConfig = void 0;
|
|
4
4
|
const config_1 = require("../../public/config");
|
|
5
5
|
const sender_1 = require("../domain/sender");
|
|
6
6
|
var notification_module_1 = require("./notification-module");
|
|
7
|
+
Object.defineProperty(exports, "createEmailNotificationModuleConfig", { enumerable: true, get: function () { return notification_module_1.createEmailNotificationModuleConfig; } });
|
|
7
8
|
Object.defineProperty(exports, "createSmtpNotificationModuleConfig", { enumerable: true, get: function () { return notification_module_1.createSmtpNotificationModuleConfig; } });
|
|
8
9
|
const defineShopEmailConfiguration = (configuration) => configuration;
|
|
9
10
|
exports.defineShopEmailConfiguration = defineShopEmailConfiguration;
|
|
11
|
+
/** @deprecated The provider is set in the Admin (E-Mail > Versand). */
|
|
10
12
|
exports.SMTP_ENVIRONMENT_VARIABLES = [
|
|
11
13
|
"SMTP_HOST",
|
|
12
14
|
"SMTP_PORT",
|
|
@@ -17,6 +19,8 @@ exports.SMTP_ENVIRONMENT_VARIABLES = [
|
|
|
17
19
|
"SMTP_REQUIRE_TLS",
|
|
18
20
|
];
|
|
19
21
|
/**
|
|
22
|
+
* @deprecated The provider is set in the Admin (E-Mail > Versand).
|
|
23
|
+
*
|
|
20
24
|
* `medusa build` loads the configuration without deployment secrets. These
|
|
21
25
|
* placeholders only satisfy the required-variable checks of a build; they
|
|
22
26
|
* never reach a running server.
|
|
@@ -31,6 +35,8 @@ exports.SMTP_BUILD_PLACEHOLDERS = {
|
|
|
31
35
|
SMTP_USER: "build-user",
|
|
32
36
|
};
|
|
33
37
|
/**
|
|
38
|
+
* @deprecated The provider is set in the Admin (E-Mail > Versand).
|
|
39
|
+
*
|
|
34
40
|
* Validates the SMTP environment values and returns the transport
|
|
35
41
|
* configuration. `allowInsecure` permits plain SMTP for development, tests
|
|
36
42
|
* and builds; otherwise `SMTP_SECURE` or `SMTP_REQUIRE_TLS` must be `true`.
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import type { ResolvedSmtpConfiguration } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* The Notification Module with the shop's mail provider. Provider and
|
|
4
|
+
* credentials are set in the Admin (E-Mail > Versand); `allowInsecure`
|
|
5
|
+
* (development and tests only) permits SMTP without encryption there.
|
|
6
|
+
*/
|
|
7
|
+
export declare const createEmailNotificationModuleConfig: (options?: Readonly<{
|
|
8
|
+
allowInsecure?: boolean;
|
|
9
|
+
}>) => {
|
|
10
|
+
resolve: string;
|
|
11
|
+
options: {
|
|
12
|
+
providers: {
|
|
13
|
+
id: string;
|
|
14
|
+
options: {
|
|
15
|
+
allowInsecure: boolean;
|
|
16
|
+
channels: string[];
|
|
17
|
+
};
|
|
18
|
+
resolve: string;
|
|
19
|
+
}[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated Use `createEmailNotificationModuleConfig` and set the provider
|
|
24
|
+
* in the Admin (E-Mail > Versand). The SMTP values given here only fill the
|
|
25
|
+
* SMTP settings that are not stored in the Admin.
|
|
26
|
+
*/
|
|
2
27
|
export declare const createSmtpNotificationModuleConfig: (smtp: ResolvedSmtpConfiguration) => {
|
|
3
28
|
resolve: string;
|
|
4
29
|
options: {
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createSmtpNotificationModuleConfig = void 0;
|
|
3
|
+
exports.createSmtpNotificationModuleConfig = exports.createEmailNotificationModuleConfig = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The Notification Module with the shop's mail provider. Provider and
|
|
6
|
+
* credentials are set in the Admin (E-Mail > Versand); `allowInsecure`
|
|
7
|
+
* (development and tests only) permits SMTP without encryption there.
|
|
8
|
+
*/
|
|
9
|
+
const createEmailNotificationModuleConfig = (options = {}) => ({
|
|
10
|
+
resolve: "@medusajs/medusa/notification",
|
|
11
|
+
options: {
|
|
12
|
+
providers: [
|
|
13
|
+
{
|
|
14
|
+
id: "smtp",
|
|
15
|
+
options: {
|
|
16
|
+
allowInsecure: options.allowInsecure === true,
|
|
17
|
+
channels: ["email"],
|
|
18
|
+
},
|
|
19
|
+
resolve: "@hartl-services/medusa-base/providers/smtp",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
exports.createEmailNotificationModuleConfig = createEmailNotificationModuleConfig;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use `createEmailNotificationModuleConfig` and set the provider
|
|
27
|
+
* in the Admin (E-Mail > Versand). The SMTP values given here only fill the
|
|
28
|
+
* SMTP settings that are not stored in the Admin.
|
|
29
|
+
*/
|
|
4
30
|
const createSmtpNotificationModuleConfig = (smtp) => ({
|
|
5
31
|
resolve: "@medusajs/medusa/notification",
|
|
6
32
|
options: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "@medusajs/framework/zod";
|
|
2
|
-
export declare const EMAIL_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "affiliate.consignment_report_due", "affiliate.application_submitted.admin", "user.invite", "auth.verification", "auth.login_code"];
|
|
2
|
+
export declare const EMAIL_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "affiliate.consignment_report_due", "affiliate.application_submitted.admin", "user.invite", "auth.verification", "auth.login_code", "system.credential_expiry.admin"];
|
|
3
3
|
export declare const EmailKindSchema: z.ZodEnum<{
|
|
4
4
|
"order.received": "order.received";
|
|
5
5
|
"order.received.admin": "order.received.admin";
|
|
@@ -14,6 +14,7 @@ export declare const EmailKindSchema: z.ZodEnum<{
|
|
|
14
14
|
"user.invite": "user.invite";
|
|
15
15
|
"auth.verification": "auth.verification";
|
|
16
16
|
"auth.login_code": "auth.login_code";
|
|
17
|
+
"system.credential_expiry.admin": "system.credential_expiry.admin";
|
|
17
18
|
}>;
|
|
18
19
|
export type EmailKind = (typeof EMAIL_KINDS)[number];
|
|
19
20
|
/**
|
|
@@ -376,6 +376,11 @@ export declare const EmailPersistedDataSchemas: {
|
|
|
376
376
|
locale: z.ZodNullable<z.ZodString>;
|
|
377
377
|
}, z.core.$strict>;
|
|
378
378
|
readonly "auth.login_code": z.ZodObject<{}, z.core.$strict>;
|
|
379
|
+
readonly "system.credential_expiry.admin": z.ZodObject<{
|
|
380
|
+
provider: z.ZodLiteral<"microsoft365">;
|
|
381
|
+
client_id: z.ZodString;
|
|
382
|
+
expires_on: z.ZodString;
|
|
383
|
+
}, z.core.$strict>;
|
|
379
384
|
};
|
|
380
385
|
export declare const EmailRenderDataSchemas: {
|
|
381
386
|
readonly "auth.password_reset": z.ZodObject<{
|
|
@@ -619,6 +624,11 @@ export declare const EmailRenderDataSchemas: {
|
|
|
619
624
|
company_name: z.ZodNullable<z.ZodString>;
|
|
620
625
|
message: z.ZodNullable<z.ZodString>;
|
|
621
626
|
}, z.core.$strict>;
|
|
627
|
+
readonly "system.credential_expiry.admin": z.ZodObject<{
|
|
628
|
+
provider: z.ZodLiteral<"microsoft365">;
|
|
629
|
+
client_id: z.ZodString;
|
|
630
|
+
expires_on: z.ZodString;
|
|
631
|
+
}, z.core.$strict>;
|
|
622
632
|
};
|
|
623
633
|
export type EmailPersistedDataMap = {
|
|
624
634
|
readonly [Kind in EmailKind]: Readonly<z.infer<(typeof EmailPersistedDataSchemas)[Kind]>>;
|
|
@@ -233,6 +233,13 @@ exports.EmailPersistedDataSchemas = {
|
|
|
233
233
|
.strict(),
|
|
234
234
|
// The code itself is never stored: it only exists in the render context.
|
|
235
235
|
"auth.login_code": zod_1.z.object({}).strict(),
|
|
236
|
+
"system.credential_expiry.admin": zod_1.z
|
|
237
|
+
.object({
|
|
238
|
+
provider: zod_1.z.literal("microsoft365"),
|
|
239
|
+
client_id: NonEmptyStringSchema,
|
|
240
|
+
expires_on: affiliate_1.CalendarDateSchema,
|
|
241
|
+
})
|
|
242
|
+
.strict(),
|
|
236
243
|
};
|
|
237
244
|
exports.EmailRenderDataSchemas = {
|
|
238
245
|
...exports.EmailPersistedDataSchemas,
|
|
@@ -15,6 +15,7 @@ const SETTING_TYPES = new Set([
|
|
|
15
15
|
"select",
|
|
16
16
|
"image",
|
|
17
17
|
"color",
|
|
18
|
+
"date",
|
|
18
19
|
]);
|
|
19
20
|
const HEX_COLOR_PATTERN = /^#[0-9a-f]{6}$/;
|
|
20
21
|
const ACTION_MODES = new Set(["sync", "background"]);
|
|
@@ -24,7 +25,7 @@ const ADMIN_PAGE_PATTERN = /^\/settings\/hartl-services(\/[a-z0-9][a-z0-9_-]*)+$
|
|
|
24
25
|
const ICON_NAMES = new Set(plugin_icons_1.PLUGIN_ICON_NAMES);
|
|
25
26
|
const SETTING_WIDTHS = new Set(["full", "half"]);
|
|
26
27
|
/** Types an input placeholder makes no sense for. */
|
|
27
|
-
const NO_PLACEHOLDER_TYPES = new Set(["boolean", "select", "image", "color"]);
|
|
28
|
+
const NO_PLACEHOLDER_TYPES = new Set(["boolean", "select", "image", "color", "date"]);
|
|
28
29
|
const invalid = (pluginKey, message) => new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Ungültige Funktionsschalter für Plugin "${pluginKey}": ${message}`);
|
|
29
30
|
const defaultMatchesType = (setting) => {
|
|
30
31
|
const value = setting.default;
|
|
@@ -36,6 +37,8 @@ const defaultMatchesType = (setting) => {
|
|
|
36
37
|
return typeof value === "string" && (0, lib_1.isHttpUrl)(value);
|
|
37
38
|
case "color":
|
|
38
39
|
return typeof value === "string" && HEX_COLOR_PATTERN.test(value);
|
|
40
|
+
case "date":
|
|
41
|
+
return typeof value === "string" && (0, lib_1.isCalendarDate)(value);
|
|
39
42
|
case "number":
|
|
40
43
|
return (typeof value === "number" &&
|
|
41
44
|
Number.isFinite(value) &&
|
|
@@ -222,9 +225,26 @@ const validateAdminPage = (pluginKey, path) => {
|
|
|
222
225
|
throw invalid(pluginKey, `admin_page "${String(path)}" muss unter "${ADMIN_PAGE_PREFIX}<plugin>" liegen und darf nicht mit "${BASE_PAGE_PREFIX}" beginnen.`);
|
|
223
226
|
}
|
|
224
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* `visible_when` points at a select or boolean setting outside the group and
|
|
230
|
+
* `equals` is one of its possible values.
|
|
231
|
+
*/
|
|
232
|
+
const validateVisibleWhen = (pluginKey, groupName, condition, settings) => {
|
|
233
|
+
if (condition === undefined) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const { setting: key, equals } = (condition ?? {});
|
|
237
|
+
const target = settings.find((setting) => setting.key === key);
|
|
238
|
+
const fits = target?.type === "select"
|
|
239
|
+
? (target.options ?? []).some((option) => option.value === equals)
|
|
240
|
+
: target?.type === "boolean" && typeof equals === "boolean";
|
|
241
|
+
if (!target || target.group === groupName || !fits) {
|
|
242
|
+
throw invalid(pluginKey, `Einstellungsgruppe "${groupName}": visible_when muss auf eine Auswahl oder einen Schalter außerhalb der Gruppe mit einem ihrer Werte zeigen.`);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
225
245
|
/**
|
|
226
246
|
* Metadata per settings group: unique names, each used by a setting's
|
|
227
|
-
* `group`, `requires_feature` a declared feature key.
|
|
247
|
+
* `group`, `requires_feature` a declared feature key, `visible_when` valid.
|
|
228
248
|
*/
|
|
229
249
|
const validateSettingGroups = (pluginKey, groups, settings, featureKeys) => {
|
|
230
250
|
if (groups === undefined) {
|
|
@@ -255,6 +275,7 @@ const validateSettingGroups = (pluginKey, groups, settings, featureKeys) => {
|
|
|
255
275
|
!featureKeys.has(group.requires_feature)) {
|
|
256
276
|
throw invalid(pluginKey, `Einstellungsgruppe "${group.name}": requires_feature "${String(group.requires_feature)}" ist kein Feature dieses Plugins.`);
|
|
257
277
|
}
|
|
278
|
+
validateVisibleWhen(pluginKey, group.name, group.visible_when, settings);
|
|
258
279
|
}
|
|
259
280
|
};
|
|
260
281
|
/** Optional texts and icon of the plugin's Admin page. */
|
package/dist/public/types.d.ts
CHANGED
|
@@ -36,8 +36,9 @@ export type PluginFeatureDefinition<K extends string = string> = {
|
|
|
36
36
|
/**
|
|
37
37
|
* `image`: public http(s) URL of an image the Admin uploads (PNG/JPEG).
|
|
38
38
|
* `color`: lowercase hex color `#rrggbb`.
|
|
39
|
+
* `date`: calendar day `YYYY-MM-DD`.
|
|
39
40
|
*/
|
|
40
|
-
export type PluginSettingType = "string" | "url" | "number" | "boolean" | "secret" | "select" | "image" | "color";
|
|
41
|
+
export type PluginSettingType = "string" | "url" | "number" | "boolean" | "secret" | "select" | "image" | "color" | "date";
|
|
41
42
|
/** One allowed value of a `"select"` setting. */
|
|
42
43
|
export type PluginSettingOption = {
|
|
43
44
|
readonly value: string;
|
|
@@ -76,7 +77,7 @@ export type PluginSettingDefinition<S extends string = string> = {
|
|
|
76
77
|
* Short text under the field; the Admin shows `hint ?? description`.
|
|
77
78
|
*/
|
|
78
79
|
readonly hint?: string;
|
|
79
|
-
/** Input placeholder; not for boolean, select, image and
|
|
80
|
+
/** Input placeholder; not for boolean, select, image, color and date. */
|
|
80
81
|
readonly placeholder?: string;
|
|
81
82
|
/**
|
|
82
83
|
* `"half"`: consecutive half-width settings share one two-column row.
|
|
@@ -90,7 +91,7 @@ export type PluginSettingDefinition<S extends string = string> = {
|
|
|
90
91
|
readonly section?: string;
|
|
91
92
|
};
|
|
92
93
|
/** Metadata of one settings group, keyed by the `group` name of its settings. */
|
|
93
|
-
export type PluginSettingGroupDefinition<K extends string = string> = {
|
|
94
|
+
export type PluginSettingGroupDefinition<K extends string = string, S extends string = string> = {
|
|
94
95
|
/** Equals the `group` of at least one setting; unique per plugin. */
|
|
95
96
|
readonly name: string;
|
|
96
97
|
/** Explanatory text under the group heading. */
|
|
@@ -102,6 +103,15 @@ export type PluginSettingGroupDefinition<K extends string = string> = {
|
|
|
102
103
|
* (still editable) while the feature is not effectively enabled.
|
|
103
104
|
*/
|
|
104
105
|
readonly requires_feature?: K;
|
|
106
|
+
/**
|
|
107
|
+
* The group applies only while the select or boolean setting `setting`
|
|
108
|
+
* (of another group) resolves to `equals`. Otherwise the Admin hides it and
|
|
109
|
+
* its required settings do not count as missing; stored values are kept.
|
|
110
|
+
*/
|
|
111
|
+
readonly visible_when?: {
|
|
112
|
+
readonly setting: S;
|
|
113
|
+
readonly equals: string | boolean;
|
|
114
|
+
};
|
|
105
115
|
};
|
|
106
116
|
export type PluginActionMode = "sync" | "background";
|
|
107
117
|
export type PluginActionDefinition<A extends string = string> = {
|
|
@@ -161,7 +171,7 @@ export type PluginFeatureDescriptor<K extends string = string, S extends string
|
|
|
161
171
|
*/
|
|
162
172
|
readonly require_enabled_feature?: true;
|
|
163
173
|
/** Metadata for the groups used in `settings[].group`. */
|
|
164
|
-
readonly setting_groups?: readonly PluginSettingGroupDefinition<K>[];
|
|
174
|
+
readonly setting_groups?: readonly PluginSettingGroupDefinition<K, S>[];
|
|
165
175
|
};
|
|
166
176
|
/** Values a plugin received from medusa-config; the base shows them as source "config". */
|
|
167
177
|
export type PluginSettingsFallback<S extends string = string> = Partial<Record<S, PluginSettingValue | null | undefined>>;
|
|
@@ -10,3 +10,5 @@ export declare const toWireDate: (value: Date | string) => string;
|
|
|
10
10
|
export declare const toOptionalWireDate: (value: Date | string | null | undefined) => string | null;
|
|
11
11
|
/** Whether the value is an IANA time zone this runtime knows ("Europe/Vienna"). */
|
|
12
12
|
export declare const isValidTimeZone: (value: unknown) => value is string;
|
|
13
|
+
/** Whether the value is an existing calendar day written `yyyy-mm-dd`. */
|
|
14
|
+
export declare const isCalendarDate: (value: unknown) => value is string;
|
package/dist/shared/lib/dates.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isValidTimeZone = exports.toOptionalWireDate = exports.toWireDate = exports.toIsoDate = exports.startOfUtcDate = exports.toValidDate = void 0;
|
|
3
|
+
exports.isCalendarDate = exports.isValidTimeZone = exports.toOptionalWireDate = exports.toWireDate = exports.toIsoDate = exports.startOfUtcDate = exports.toValidDate = void 0;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
5
|
/** A valid `Date`; throws `INVALID_DATA` for an unparsable value. */
|
|
6
6
|
const toValidDate = (value, message = "Invalid date.") => {
|
|
@@ -40,3 +40,9 @@ const isValidTimeZone = (value) => {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
exports.isValidTimeZone = isValidTimeZone;
|
|
43
|
+
/** Whether the value is an existing calendar day written `yyyy-mm-dd`. */
|
|
44
|
+
const isCalendarDate = (value) => typeof value === "string" &&
|
|
45
|
+
/^\d{4}-\d{2}-\d{2}$/.test(value) &&
|
|
46
|
+
!Number.isNaN(Date.parse(`${value}T00:00:00Z`)) &&
|
|
47
|
+
new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) === value;
|
|
48
|
+
exports.isCalendarDate = isCalendarDate;
|