@endora-commerce/contracts 0.100.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/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/actor.d.ts +79 -0
- package/dist/actor.d.ts.map +1 -0
- package/dist/actor.js +41 -0
- package/dist/actor.js.map +1 -0
- package/dist/addresses.d.ts +134 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +16 -0
- package/dist/addresses.js.map +1 -0
- package/dist/admin-actions.d.ts +367 -0
- package/dist/admin-actions.d.ts.map +1 -0
- package/dist/admin-actions.js +287 -0
- package/dist/admin-actions.js.map +1 -0
- package/dist/admin-contributions.d.ts +518 -0
- package/dist/admin-contributions.d.ts.map +1 -0
- package/dist/admin-contributions.js +495 -0
- package/dist/admin-contributions.js.map +1 -0
- package/dist/admin-i18n.d.ts +135 -0
- package/dist/admin-i18n.d.ts.map +1 -0
- package/dist/admin-i18n.js +72 -0
- package/dist/admin-i18n.js.map +1 -0
- package/dist/admin-notifications.d.ts +55 -0
- package/dist/admin-notifications.d.ts.map +1 -0
- package/dist/admin-notifications.js +16 -0
- package/dist/admin-notifications.js.map +1 -0
- package/dist/admin-roles.d.ts +125 -0
- package/dist/admin-roles.d.ts.map +1 -0
- package/dist/admin-roles.js +2 -0
- package/dist/admin-roles.js.map +1 -0
- package/dist/admin-users.d.ts +178 -0
- package/dist/admin-users.d.ts.map +1 -0
- package/dist/admin-users.js +14 -0
- package/dist/admin-users.js.map +1 -0
- package/dist/admin.d.ts +243 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +246 -0
- package/dist/admin.js.map +1 -0
- package/dist/analytics.d.ts +123 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +68 -0
- package/dist/analytics.js.map +1 -0
- package/dist/api-keys.d.ts +97 -0
- package/dist/api-keys.d.ts.map +1 -0
- package/dist/api-keys.js +64 -0
- package/dist/api-keys.js.map +1 -0
- package/dist/assets-library.d.ts +684 -0
- package/dist/assets-library.d.ts.map +1 -0
- package/dist/assets-library.js +181 -0
- package/dist/assets-library.js.map +1 -0
- package/dist/audit-logs.d.ts +141 -0
- package/dist/audit-logs.d.ts.map +1 -0
- package/dist/audit-logs.js +31 -0
- package/dist/audit-logs.js.map +1 -0
- package/dist/auth.d.ts +174 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +27 -0
- package/dist/auth.js.map +1 -0
- package/dist/blog.d.ts +669 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +360 -0
- package/dist/blog.js.map +1 -0
- package/dist/capabilities.d.ts +40 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +38 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/carts.d.ts +1367 -0
- package/dist/carts.d.ts.map +1 -0
- package/dist/carts.js +405 -0
- package/dist/carts.js.map +1 -0
- package/dist/catalog.d.ts +2855 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +1543 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cms.d.ts +872 -0
- package/dist/cms.d.ts.map +1 -0
- package/dist/cms.js +468 -0
- package/dist/cms.js.map +1 -0
- package/dist/common.d.ts +82 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +72 -0
- package/dist/common.js.map +1 -0
- package/dist/comparisons.d.ts +487 -0
- package/dist/comparisons.d.ts.map +1 -0
- package/dist/comparisons.js +221 -0
- package/dist/comparisons.js.map +1 -0
- package/dist/credentials.d.ts +292 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +142 -0
- package/dist/credentials.js.map +1 -0
- package/dist/credit-limits.d.ts +111 -0
- package/dist/credit-limits.d.ts.map +1 -0
- package/dist/credit-limits.js +35 -0
- package/dist/credit-limits.js.map +1 -0
- package/dist/currencies.d.ts +127 -0
- package/dist/currencies.d.ts.map +1 -0
- package/dist/currencies.js +20 -0
- package/dist/currencies.js.map +1 -0
- package/dist/custom-fields.d.ts +345 -0
- package/dist/custom-fields.d.ts.map +1 -0
- package/dist/custom-fields.js +185 -0
- package/dist/custom-fields.js.map +1 -0
- package/dist/customer-accounts.d.ts +690 -0
- package/dist/customer-accounts.d.ts.map +1 -0
- package/dist/customer-accounts.js +41 -0
- package/dist/customer-accounts.js.map +1 -0
- package/dist/customers.d.ts +305 -0
- package/dist/customers.d.ts.map +1 -0
- package/dist/customers.js +158 -0
- package/dist/customers.js.map +1 -0
- package/dist/dictionary.d.ts +580 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +297 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/email-address.d.ts +62 -0
- package/dist/email-address.d.ts.map +1 -0
- package/dist/email-address.js +64 -0
- package/dist/email-address.js.map +1 -0
- package/dist/email.d.ts +175 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +45 -0
- package/dist/email.js.map +1 -0
- package/dist/envelopes.d.ts +15 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +16 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/environment-inputs.d.ts +306 -0
- package/dist/environment-inputs.d.ts.map +1 -0
- package/dist/environment-inputs.js +277 -0
- package/dist/environment-inputs.js.map +1 -0
- package/dist/erp-connector.d.ts +52 -0
- package/dist/erp-connector.d.ts.map +1 -0
- package/dist/erp-connector.js +34 -0
- package/dist/erp-connector.js.map +1 -0
- package/dist/errors.d.ts +455 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +532 -0
- package/dist/errors.js.map +1 -0
- package/dist/google-analytics.d.ts +181 -0
- package/dist/google-analytics.d.ts.map +1 -0
- package/dist/google-analytics.js +176 -0
- package/dist/google-analytics.js.map +1 -0
- package/dist/google-tag-manager.d.ts +111 -0
- package/dist/google-tag-manager.d.ts.map +1 -0
- package/dist/google-tag-manager.js +129 -0
- package/dist/google-tag-manager.js.map +1 -0
- package/dist/i18n.d.ts +69 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +59 -0
- package/dist/i18n.js.map +1 -0
- package/dist/import-export.d.ts +63 -0
- package/dist/import-export.d.ts.map +1 -0
- package/dist/import-export.js +37 -0
- package/dist/import-export.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.d.ts +673 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +412 -0
- package/dist/inventory.js.map +1 -0
- package/dist/invoice-ledger.d.ts +366 -0
- package/dist/invoice-ledger.d.ts.map +1 -0
- package/dist/invoice-ledger.js +114 -0
- package/dist/invoice-ledger.js.map +1 -0
- package/dist/invoices.d.ts +845 -0
- package/dist/invoices.d.ts.map +1 -0
- package/dist/invoices.js +314 -0
- package/dist/invoices.js.map +1 -0
- package/dist/kernel.d.ts +49 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +19 -0
- package/dist/kernel.js.map +1 -0
- package/dist/languages.d.ts +122 -0
- package/dist/languages.d.ts.map +1 -0
- package/dist/languages.js +24 -0
- package/dist/languages.js.map +1 -0
- package/dist/linkedin-ads.d.ts +167 -0
- package/dist/linkedin-ads.d.ts.map +1 -0
- package/dist/linkedin-ads.js +156 -0
- package/dist/linkedin-ads.js.map +1 -0
- package/dist/megamenu.d.ts +556 -0
- package/dist/megamenu.d.ts.map +1 -0
- package/dist/megamenu.js +186 -0
- package/dist/megamenu.js.map +1 -0
- package/dist/meta-ads.d.ts +126 -0
- package/dist/meta-ads.d.ts.map +1 -0
- package/dist/meta-ads.js +112 -0
- package/dist/meta-ads.js.map +1 -0
- package/dist/mfa.d.ts +274 -0
- package/dist/mfa.d.ts.map +1 -0
- package/dist/mfa.js +187 -0
- package/dist/mfa.js.map +1 -0
- package/dist/modules.d.ts +1706 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +1390 -0
- package/dist/modules.js.map +1 -0
- package/dist/newsletter.d.ts +611 -0
- package/dist/newsletter.d.ts.map +1 -0
- package/dist/newsletter.js +345 -0
- package/dist/newsletter.js.map +1 -0
- package/dist/orders.d.ts +1175 -0
- package/dist/orders.d.ts.map +1 -0
- package/dist/orders.js +630 -0
- package/dist/orders.js.map +1 -0
- package/dist/organizations.d.ts +938 -0
- package/dist/organizations.d.ts.map +1 -0
- package/dist/organizations.js +418 -0
- package/dist/organizations.js.map +1 -0
- package/dist/pagination.d.ts +21 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +22 -0
- package/dist/pagination.js.map +1 -0
- package/dist/payment-methods.d.ts +472 -0
- package/dist/payment-methods.d.ts.map +1 -0
- package/dist/payment-methods.js +175 -0
- package/dist/payment-methods.js.map +1 -0
- package/dist/payment-return-url.d.ts +53 -0
- package/dist/payment-return-url.d.ts.map +1 -0
- package/dist/payment-return-url.js +35 -0
- package/dist/payment-return-url.js.map +1 -0
- package/dist/payments.d.ts +386 -0
- package/dist/payments.d.ts.map +1 -0
- package/dist/payments.js +84 -0
- package/dist/payments.js.map +1 -0
- package/dist/pim-connector.d.ts +60 -0
- package/dist/pim-connector.d.ts.map +1 -0
- package/dist/pim-connector.js +43 -0
- package/dist/pim-connector.js.map +1 -0
- package/dist/pim-field-path.d.ts +6 -0
- package/dist/pim-field-path.d.ts.map +1 -0
- package/dist/pim-field-path.js +101 -0
- package/dist/pim-field-path.js.map +1 -0
- package/dist/platform-language.d.ts +20 -0
- package/dist/platform-language.d.ts.map +1 -0
- package/dist/platform-language.js +22 -0
- package/dist/platform-language.js.map +1 -0
- package/dist/price-lists.d.ts +685 -0
- package/dist/price-lists.d.ts.map +1 -0
- package/dist/price-lists.js +330 -0
- package/dist/price-lists.js.map +1 -0
- package/dist/product-feeds.d.ts +2837 -0
- package/dist/product-feeds.d.ts.map +1 -0
- package/dist/product-feeds.js +1504 -0
- package/dist/product-feeds.js.map +1 -0
- package/dist/product-scope-overrides.d.ts +134 -0
- package/dist/product-scope-overrides.d.ts.map +1 -0
- package/dist/product-scope-overrides.js +82 -0
- package/dist/product-scope-overrides.js.map +1 -0
- package/dist/product-value-resolver.d.ts +88 -0
- package/dist/product-value-resolver.d.ts.map +1 -0
- package/dist/product-value-resolver.js +128 -0
- package/dist/product-value-resolver.js.map +1 -0
- package/dist/promotions.d.ts +678 -0
- package/dist/promotions.d.ts.map +1 -0
- package/dist/promotions.js +479 -0
- package/dist/promotions.js.map +1 -0
- package/dist/prompt-actions.d.ts +582 -0
- package/dist/prompt-actions.d.ts.map +1 -0
- package/dist/prompt-actions.js +221 -0
- package/dist/prompt-actions.js.map +1 -0
- package/dist/pwa.d.ts +293 -0
- package/dist/pwa.d.ts.map +1 -0
- package/dist/pwa.js +204 -0
- package/dist/pwa.js.map +1 -0
- package/dist/quick-order.d.ts +340 -0
- package/dist/quick-order.d.ts.map +1 -0
- package/dist/quick-order.js +177 -0
- package/dist/quick-order.js.map +1 -0
- package/dist/quote-requests.d.ts +538 -0
- package/dist/quote-requests.d.ts.map +1 -0
- package/dist/quote-requests.js +308 -0
- package/dist/quote-requests.js.map +1 -0
- package/dist/returns.d.ts +774 -0
- package/dist/returns.d.ts.map +1 -0
- package/dist/returns.js +389 -0
- package/dist/returns.js.map +1 -0
- package/dist/sales-channels.d.ts +392 -0
- package/dist/sales-channels.d.ts.map +1 -0
- package/dist/sales-channels.js +285 -0
- package/dist/sales-channels.js.map +1 -0
- package/dist/scope-notice.d.ts +60 -0
- package/dist/scope-notice.d.ts.map +1 -0
- package/dist/scope-notice.js +56 -0
- package/dist/scope-notice.js.map +1 -0
- package/dist/search.d.ts +321 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +160 -0
- package/dist/search.js.map +1 -0
- package/dist/seo.d.ts +113 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +63 -0
- package/dist/seo.js.map +1 -0
- package/dist/settings.d.ts +453 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +337 -0
- package/dist/settings.js.map +1 -0
- package/dist/shipments.d.ts +140 -0
- package/dist/shipments.d.ts.map +1 -0
- package/dist/shipments.js +14 -0
- package/dist/shipments.js.map +1 -0
- package/dist/shipping-methods.d.ts +350 -0
- package/dist/shipping-methods.d.ts.map +1 -0
- package/dist/shipping-methods.js +99 -0
- package/dist/shipping-methods.js.map +1 -0
- package/dist/shopping-lists.d.ts +122 -0
- package/dist/shopping-lists.d.ts.map +1 -0
- package/dist/shopping-lists.js +92 -0
- package/dist/shopping-lists.js.map +1 -0
- package/dist/taxes.d.ts +106 -0
- package/dist/taxes.d.ts.map +1 -0
- package/dist/taxes.js +80 -0
- package/dist/taxes.js.map +1 -0
- package/dist/text-normalization.d.ts +199 -0
- package/dist/text-normalization.d.ts.map +1 -0
- package/dist/text-normalization.js +205 -0
- package/dist/text-normalization.js.map +1 -0
- package/dist/transactional-emails.d.ts +459 -0
- package/dist/transactional-emails.d.ts.map +1 -0
- package/dist/transactional-emails.js +212 -0
- package/dist/transactional-emails.js.map +1 -0
- package/dist/webhooks.d.ts +69 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +53 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Admin UI language versions (feature 019).
|
|
2
|
+
//
|
|
3
|
+
// Source-of-truth schemas for the Admin UI's i18n boundary. Distinct from
|
|
4
|
+
// `i18n.ts` (feature 017) which owns the storefront/customer-facing language
|
|
5
|
+
// pool — see specs/019-admin-i18n/research.md §R1 for the separation.
|
|
6
|
+
//
|
|
7
|
+
// At GA the supported set is `en` and `pl`; English is the platform-wide
|
|
8
|
+
// fallback (specs/019-admin-i18n/spec.md FR-013, FR-016).
|
|
9
|
+
//
|
|
10
|
+
// The set and the fallback themselves now live in `platform-language.ts`
|
|
11
|
+
// (feature 083, D-136): a buyer is answered out of the same enum, so naming it
|
|
12
|
+
// after the Admin UI was the thing that let `ADMIN_LANGUAGE_FALLBACK` sit on a
|
|
13
|
+
// buyer's code path for a year without anybody reading it as wrong (#234).
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { SupportedLanguageSchema } from './platform-language.js';
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use `SupportedLanguageSchema` from `platform-language.ts`. The set
|
|
18
|
+
* is the platform's, not the Admin UI's — a buyer is answered out of the same
|
|
19
|
+
* enum (feature 083, D-136). Draining task: `specs/083-buyer-language-resolution`
|
|
20
|
+
* T021.
|
|
21
|
+
*/
|
|
22
|
+
export const SupportedAdminLanguageSchema = SupportedLanguageSchema;
|
|
23
|
+
/**
|
|
24
|
+
* On-disk bundle JSON shape and the row payload persisted to
|
|
25
|
+
* `translation_bundles.entries`. Flat string→string only at v1; nested
|
|
26
|
+
* objects, arrays, and non-string values are rejected.
|
|
27
|
+
*/
|
|
28
|
+
export const TranslationBundleEntriesSchema = z.record(z.string().min(1), z.string());
|
|
29
|
+
/** Admin SPA boot fetch — `GET /api/v1/admin/i18n/bundles?language=…` response. */
|
|
30
|
+
export const GetBundlesResponseSchema = z.object({
|
|
31
|
+
language: SupportedAdminLanguageSchema,
|
|
32
|
+
// Monotonically-non-decreasing version vector. SPA refetches when its cached value is older.
|
|
33
|
+
version: z.number().int().nonnegative(),
|
|
34
|
+
// module_id → flat key/string map. The synthetic `core` namespace owns admin-chrome strings.
|
|
35
|
+
bundles: z.record(z.string(), TranslationBundleEntriesSchema),
|
|
36
|
+
});
|
|
37
|
+
/** `PATCH /api/v1/admin/me/preferred-language` body. `null` reverts to the platform default. */
|
|
38
|
+
export const PatchPreferredLanguageBodySchema = z.object({
|
|
39
|
+
preferredLanguage: SupportedAdminLanguageSchema.nullable(),
|
|
40
|
+
});
|
|
41
|
+
/** Standard 400 envelope when an unsupported language is requested. */
|
|
42
|
+
export const UnsupportedLanguageErrorSchema = z.object({
|
|
43
|
+
error: z.literal('unsupported-language'),
|
|
44
|
+
supported: z.array(SupportedAdminLanguageSchema),
|
|
45
|
+
});
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Coverage diagnostic — feature 021
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
export const I18nCoverageLanguageSchema = z.object({
|
|
50
|
+
languageCode: SupportedAdminLanguageSchema,
|
|
51
|
+
totalKeysSeen: z.number().int().nonnegative(),
|
|
52
|
+
missingCount: z.number().int().nonnegative(),
|
|
53
|
+
missingKeys: z.array(z.string()),
|
|
54
|
+
fellBackToEnCount: z.number().int().nonnegative(),
|
|
55
|
+
fellBackToEnKeys: z.array(z.string()),
|
|
56
|
+
});
|
|
57
|
+
export const I18nCoverageModuleSchema = z.object({
|
|
58
|
+
moduleId: z.string(),
|
|
59
|
+
languages: z.array(I18nCoverageLanguageSchema),
|
|
60
|
+
});
|
|
61
|
+
export const I18nCoverageResponseSchema = z.object({
|
|
62
|
+
capturedAt: z.iso.datetime(),
|
|
63
|
+
modules: z.array(I18nCoverageModuleSchema),
|
|
64
|
+
});
|
|
65
|
+
export const I18nCoverageQuerySchema = z.object({
|
|
66
|
+
module: z.union([z.string(), z.array(z.string())]).optional(),
|
|
67
|
+
language: z
|
|
68
|
+
.union([SupportedAdminLanguageSchema, z.array(SupportedAdminLanguageSchema)])
|
|
69
|
+
.optional(),
|
|
70
|
+
includeKeys: z.enum(['missing', 'all']).default('missing').optional(),
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=admin-i18n.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-i18n.js","sourceRoot":"","sources":["../src/admin-i18n.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,sEAAsE;AACtE,EAAE;AACF,yEAAyE;AACzE,0DAA0D;AAC1D,EAAE;AACF,yEAAyE;AACzE,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAE3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAA0B,MAAM,wBAAwB,CAAC;AAEzF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAOpE;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CACpD,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EACjB,CAAC,CAAC,MAAM,EAAE,CACX,CAAC;AAGF,mFAAmF;AACnF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,QAAQ,EAAE,4BAA4B;IACtC,6FAA6F;IAC7F,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACvC,6FAA6F;IAC7F,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,8BAA8B,CAAC;CAC9D,CAAC,CAAC;AAGH,gGAAgG;AAChG,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC,MAAM,CAAC;IACvD,iBAAiB,EAAE,4BAA4B,CAAC,QAAQ,EAAE;CAC3D,CAAC,CAAC;AAGH,uEAAuE;AACvE,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IACrD,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACxC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,4BAA4B,CAAC;CACjD,CAAC,CAAC;AAGH,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,YAAY,EAAE,4BAA4B;IAC1C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC7C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAChC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACjD,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACtC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC;CAC/C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC;CAC3C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC7D,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;SAC5E,QAAQ,EAAE;IACb,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;CACtE,CAAC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin_notifications` module contracts — the in-process port surface
|
|
3
|
+
* (feature 075, Phase P).
|
|
4
|
+
*
|
|
5
|
+
* The cross-module demand is one method wherever it comes from: something
|
|
6
|
+
* finished, and the administrator who asked for it should see a bell entry.
|
|
7
|
+
* `organizations` records one when a new organisation registers; `catalog`,
|
|
8
|
+
* `product_feeds` and `pim_ergonode` record one when a bulk operation, a feed
|
|
9
|
+
* generation or an import run ends. So the port is that one method, not the
|
|
10
|
+
* module's five — the other four are its own admin surface (listing, marking
|
|
11
|
+
* read, archiving, counting) and stay unpublished.
|
|
12
|
+
*
|
|
13
|
+
* Plain TypeScript rather than Zod: this describes an in-process call.
|
|
14
|
+
*/
|
|
15
|
+
export type AdminNotificationAudience = 'admin_user' | 'all_admins';
|
|
16
|
+
export interface RecordAdminNotificationInput {
|
|
17
|
+
audience: AdminNotificationAudience;
|
|
18
|
+
/** Required when `audience` is `admin_user`; rejected otherwise. */
|
|
19
|
+
targetAdminUserId?: string | null;
|
|
20
|
+
kind: string;
|
|
21
|
+
subjectType?: string | null;
|
|
22
|
+
subjectId?: string | null;
|
|
23
|
+
title: string;
|
|
24
|
+
body?: string | null;
|
|
25
|
+
linkPath?: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** What was recorded, for a caller that wants to correlate its own log. */
|
|
28
|
+
export interface AdminNotificationRecord {
|
|
29
|
+
id: string;
|
|
30
|
+
audience: AdminNotificationAudience;
|
|
31
|
+
targetAdminUserId: string | null;
|
|
32
|
+
kind: string;
|
|
33
|
+
subjectType: string | null;
|
|
34
|
+
subjectId: string | null;
|
|
35
|
+
title: string;
|
|
36
|
+
body: string | null;
|
|
37
|
+
linkPath: string | null;
|
|
38
|
+
createdAt: Date;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Container name: `adminNotificationRecordPort`. Owner: `admin_notifications`.
|
|
42
|
+
*
|
|
43
|
+
* When `admin_notifications` is off the call fails closed, and every caller
|
|
44
|
+
* decides absence in front of it rather than catching the refusal behind it
|
|
45
|
+
* (D-60). `organizations` records *after* the organisation has been created
|
|
46
|
+
* and committed, so a swallowed refusal there would be indistinguishable from
|
|
47
|
+
* a call that never happened; the three run-completion callers compose the
|
|
48
|
+
* presence question into their own return type — `'recorded' | 'not-present'`
|
|
49
|
+
* — so an operator reading "not notified" can tell their own choice from a
|
|
50
|
+
* defect.
|
|
51
|
+
*/
|
|
52
|
+
export interface AdminNotificationRecordPort {
|
|
53
|
+
record(input: RecordAdminNotificationInput): Promise<AdminNotificationRecord>;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=admin-notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-notifications.d.ts","sourceRoot":"","sources":["../src/admin-notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,yBAAyB,GAAG,YAAY,GAAG,YAAY,CAAC;AAEpE,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,yBAAyB,CAAC;IACpC,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,yBAAyB,CAAC;IACpC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/E"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin_notifications` module contracts — the in-process port surface
|
|
3
|
+
* (feature 075, Phase P).
|
|
4
|
+
*
|
|
5
|
+
* The cross-module demand is one method wherever it comes from: something
|
|
6
|
+
* finished, and the administrator who asked for it should see a bell entry.
|
|
7
|
+
* `organizations` records one when a new organisation registers; `catalog`,
|
|
8
|
+
* `product_feeds` and `pim_ergonode` record one when a bulk operation, a feed
|
|
9
|
+
* generation or an import run ends. So the port is that one method, not the
|
|
10
|
+
* module's five — the other four are its own admin surface (listing, marking
|
|
11
|
+
* read, archiving, counting) and stay unpublished.
|
|
12
|
+
*
|
|
13
|
+
* Plain TypeScript rather than Zod: this describes an in-process call.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=admin-notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-notifications.js","sourceRoot":"","sources":["../src/admin-notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { PermissionCatalogueEntry } from './admin.js';
|
|
2
|
+
/**
|
|
3
|
+
* `admin_roles` module contracts — the in-process port surface (feature 075,
|
|
4
|
+
* Phase P).
|
|
5
|
+
*
|
|
6
|
+
* The module's HTTP shapes and the shared `PERMISSION_CATALOGUE` live in
|
|
7
|
+
* `admin.ts`; what belongs here is behaviour — the fourteen inbound sites from
|
|
8
|
+
* `admin_users`, `admin_actions`, `blog` and the dev seed.
|
|
9
|
+
*
|
|
10
|
+
* **Not here on purpose:** `AdminPermissionChecker`. `auth`'s guard resolves
|
|
11
|
+
* `permissionService` for one method and the kernel already declares that
|
|
12
|
+
* narrow shape at `src/kernel/ports/require-admin.ts`, because the guard is
|
|
13
|
+
* the kernel's and every module's routes go through it. A second declaration
|
|
14
|
+
* of the same method would be two answers to one question.
|
|
15
|
+
*
|
|
16
|
+
* Plain TypeScript rather than Zod: these describe in-process calls.
|
|
17
|
+
*/
|
|
18
|
+
/** An admin role as it crosses a module boundary — never the ORM entity. */
|
|
19
|
+
export interface AdminRoleRecord {
|
|
20
|
+
id: string;
|
|
21
|
+
code: string;
|
|
22
|
+
name: string;
|
|
23
|
+
/** Permission codes granted by this role. */
|
|
24
|
+
permissions: string[];
|
|
25
|
+
requiresTwoFactor: boolean;
|
|
26
|
+
createdAt: Date;
|
|
27
|
+
updatedAt: Date;
|
|
28
|
+
}
|
|
29
|
+
export interface UpsertAdminRoleInput {
|
|
30
|
+
code: string;
|
|
31
|
+
name: string;
|
|
32
|
+
permissions: string[];
|
|
33
|
+
requiresTwoFactor?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Container name: `adminRolePort`. Owner: `admin_roles`.
|
|
37
|
+
*
|
|
38
|
+
* (It said `adminRoleService` until issue #192. That name is registered — it is
|
|
39
|
+
* the `AdminRoleService` **class**, a plain `di.register` with no presence gate,
|
|
40
|
+
* whose `list()` returns `AdminRole` **entities**. `AdminRole` is structurally
|
|
41
|
+
* assignable to `AdminRoleRecord`, so a consumer that copied the old name got an
|
|
42
|
+
* ungated registration and entities across the boundary, and `tsc` said nothing.
|
|
43
|
+
* Nothing in the tree ever did — `admin_users` resolves `adminRolePort` — but the
|
|
44
|
+
* comment was a standing invitation to.)
|
|
45
|
+
*
|
|
46
|
+
* `admin_users` reads a role to render it beside its user and to enforce the
|
|
47
|
+
* role's `requiresTwoFactor` at login. `remove` refuses a role whose code was
|
|
48
|
+
* registered as system-protected (feature 016 FR-025), and that refusal stays
|
|
49
|
+
* on this side of the port.
|
|
50
|
+
*
|
|
51
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
52
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
53
|
+
* half-executes. Whether `admin_roles` has an off state at all is its manifest's
|
|
54
|
+
* `activation` to say, not this line's: a module declaring
|
|
55
|
+
* `nonDeactivatable` never enters one.
|
|
56
|
+
*/
|
|
57
|
+
export interface AdminRolePort {
|
|
58
|
+
list(): Promise<AdminRoleRecord[]>;
|
|
59
|
+
getById(id: string): Promise<AdminRoleRecord>;
|
|
60
|
+
findByCode(code: string): Promise<AdminRoleRecord | null>;
|
|
61
|
+
upsertByCode(input: UpsertAdminRoleInput): Promise<AdminRoleRecord>;
|
|
62
|
+
remove(id: string): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Container name: `systemRoleCodePort`. Owner: `admin_roles`.
|
|
66
|
+
*
|
|
67
|
+
* A **contribution seam**: a module that seeds a role registers its code here
|
|
68
|
+
* so `remove` refuses to delete it. `blog` is the only contributor today, from
|
|
69
|
+
* its own boot hook.
|
|
70
|
+
*
|
|
71
|
+
* It is a contribution rather than a call, so an absent contributor's code is
|
|
72
|
+
* simply not protected — which is the correct answer, because a module that is
|
|
73
|
+
* not installed has no seeded role to protect. That classification must not
|
|
74
|
+
* change: gating the registration would let an operator delete a protected
|
|
75
|
+
* role by switching its owner off for a moment.
|
|
76
|
+
*/
|
|
77
|
+
export interface SystemRoleCodePort {
|
|
78
|
+
register(code: string): void;
|
|
79
|
+
/** Every protected code, in registration order. */
|
|
80
|
+
list(): readonly string[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Container name: `permissionCataloguePort`. Owner: `admin_roles`.
|
|
84
|
+
*
|
|
85
|
+
* (It said `permissionCatalogueService` until issue #192 — the same trap as
|
|
86
|
+
* {@link AdminRolePort}: that name is a plain `di.register` of the
|
|
87
|
+
* `PermissionCatalogueService` class, with no presence gate on it. The gated
|
|
88
|
+
* registration is this one.)
|
|
89
|
+
*
|
|
90
|
+
* The permission codes an operator may actually grant — core
|
|
91
|
+
* `PERMISSION_CATALOGUE` plus every registered module's manifest
|
|
92
|
+
* `permissions`. `admin_users` renders the role editor from it.
|
|
93
|
+
*
|
|
94
|
+
* Synchronous by contract: the catalogue is assembled from manifests at
|
|
95
|
+
* composition time and never queried.
|
|
96
|
+
*
|
|
97
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
98
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
99
|
+
* half-executes. Whether `admin_roles` has an off state at all is its manifest's
|
|
100
|
+
* `activation` to say, not this line's: a module declaring
|
|
101
|
+
* `nonDeactivatable` never enters one.
|
|
102
|
+
*/
|
|
103
|
+
export interface PermissionCataloguePort {
|
|
104
|
+
listAssignable(): PermissionCatalogueEntry[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Container name: `permissionService`. Owner: `admin_roles`.
|
|
108
|
+
*
|
|
109
|
+
* The effective permission codes of one admin user, resolved through their
|
|
110
|
+
* role. `admin_actions` reads it to filter the command palette, so an action
|
|
111
|
+
* is never advertised to somebody who would get a 403 opening it.
|
|
112
|
+
*
|
|
113
|
+
* The single-permission check `auth`'s guard makes is deliberately not here —
|
|
114
|
+
* see the file header.
|
|
115
|
+
*
|
|
116
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
117
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
118
|
+
* half-executes. Whether `admin_roles` has an off state at all is its manifest's
|
|
119
|
+
* `activation` to say, not this line's: a module declaring
|
|
120
|
+
* `nonDeactivatable` never enters one.
|
|
121
|
+
*/
|
|
122
|
+
export interface PermissionReadPort {
|
|
123
|
+
listPermissions(adminUserId: string): Promise<string[]>;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=admin-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-roles.d.ts","sourceRoot":"","sources":["../src/admin-roles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;;;;;;GAeG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC1D,YAAY,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mDAAmD;IACnD,IAAI,IAAI,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,uBAAuB;IACtC,cAAc,IAAI,wBAAwB,EAAE,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-roles.js","sourceRoot":"","sources":["../src/admin-roles.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin_users` module contracts — the in-process port surface (feature 075,
|
|
3
|
+
* Phase P).
|
|
4
|
+
*
|
|
5
|
+
* Eleven inbound sites, and they split cleanly in two: seven read the
|
|
6
|
+
* `AdminUser` entity to put a name beside an id — `admin_roles` resolving a
|
|
7
|
+
* user's role, `quote_requests` listing the admins a notification goes to,
|
|
8
|
+
* `catalog` attributing a bulk operation, `organizations` rendering the
|
|
9
|
+
* sales-rep picker — and the rest reach two services.
|
|
10
|
+
*
|
|
11
|
+
* Plain TypeScript rather than Zod: these describe in-process calls.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* An admin user as it crosses a module boundary — a plain shape, never the ORM
|
|
15
|
+
* entity (FR-011).
|
|
16
|
+
*
|
|
17
|
+
* `passwordHash` is absent, as it is from `CustomerAccountRecord` and for the
|
|
18
|
+
* same reason: exactly one module reads it, and a record that carried it would
|
|
19
|
+
* turn every consumer into a place a credential can leak from.
|
|
20
|
+
*/
|
|
21
|
+
export interface AdminUserRecord {
|
|
22
|
+
id: string;
|
|
23
|
+
email: string;
|
|
24
|
+
firstName: string;
|
|
25
|
+
lastName: string;
|
|
26
|
+
adminRoleId: string | null;
|
|
27
|
+
status: 'active' | 'inactive';
|
|
28
|
+
/** Whether a confirmed TOTP enrolment exists. The secret itself never travels. */
|
|
29
|
+
twoFactorEnabled: boolean;
|
|
30
|
+
lastLoginAt: Date | null;
|
|
31
|
+
/** Admin-UI language override, or `null` to follow the platform default. */
|
|
32
|
+
preferredLanguage: string | null;
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
updatedAt: Date;
|
|
35
|
+
deletedAt: Date | null;
|
|
36
|
+
}
|
|
37
|
+
/** Which admins a lookup should consider. */
|
|
38
|
+
export interface AdminUserLookupOptions {
|
|
39
|
+
/** Exclude soft-deleted admins. Defaults to `false` — the wider read. */
|
|
40
|
+
activeOnly?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Container name: `adminUserReadPort`. Owner: `admin_users`.
|
|
44
|
+
*
|
|
45
|
+
* `listAll` is the notification fan-out: when an organisation has no assigned
|
|
46
|
+
* sales rep, a quote request notifies every admin. It is the one read here
|
|
47
|
+
* that is not a lookup by id, and it stays because the alternative — a
|
|
48
|
+
* consumer paging the table itself — is the same query in a module that does
|
|
49
|
+
* not own it.
|
|
50
|
+
*
|
|
51
|
+
* When `admin_users` is off every method fails closed. The module is
|
|
52
|
+
* non-deactivatable in practice — a platform with no admin identity has no
|
|
53
|
+
* admin surface — but the gate is registered anyway, for the reason `auth`
|
|
54
|
+
* gives for its own.
|
|
55
|
+
*/
|
|
56
|
+
export interface AdminUserReadPort {
|
|
57
|
+
findById(id: string, options?: AdminUserLookupOptions): Promise<AdminUserRecord | null>;
|
|
58
|
+
findByIds(ids: readonly string[], options?: AdminUserLookupOptions): Promise<AdminUserRecord[]>;
|
|
59
|
+
findByEmail(email: string, options?: AdminUserLookupOptions): Promise<AdminUserRecord | null>;
|
|
60
|
+
/** Every admin, ordered by email. */
|
|
61
|
+
listAll(options?: AdminUserLookupOptions): Promise<AdminUserRecord[]>;
|
|
62
|
+
/** Admins holding a given role — the guard against deleting a role in use. */
|
|
63
|
+
listByRoleId(adminRoleId: string): Promise<AdminUserRecord[]>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Container name: `adminUserPreferencePort`. Owner: `admin_users`.
|
|
67
|
+
*
|
|
68
|
+
* `_i18n` writes the admin's language choice and reads nothing else off the
|
|
69
|
+
* row. One method, because that is the whole of the demand.
|
|
70
|
+
*/
|
|
71
|
+
export interface AdminUserPreferencePort {
|
|
72
|
+
setPreferredLanguage(id: string, preferredLanguage: string | null): Promise<AdminUserRecord>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Container name: `adminPasswordVerificationPort`. Owner: `admin_users`.
|
|
76
|
+
*
|
|
77
|
+
* Does the stored credential of this admin match the password presented? One
|
|
78
|
+
* method, because that is the whole of the demand: `mfa`'s step-up
|
|
79
|
+
* re-verification asks it before it disables a second factor, and a boolean is
|
|
80
|
+
* the entire answer.
|
|
81
|
+
*
|
|
82
|
+
* It is a port rather than a field on {@link AdminUserRecord} because the hash
|
|
83
|
+
* must not travel — the record says so, and this method is what makes that
|
|
84
|
+
* survivable. Until feature 080's T052 a composition root read
|
|
85
|
+
* `admin_users`' `passwordHash` off the entity and compared it with the
|
|
86
|
+
* platform hasher itself, so the one file in the tree that owns neither the
|
|
87
|
+
* column nor the hashing held both.
|
|
88
|
+
*
|
|
89
|
+
* `false` for an unknown id as well — an admin nobody can find has no password
|
|
90
|
+
* to match. It is a lookup by id and nothing else: whether the caller may
|
|
91
|
+
* authenticate as that admin at all is the session layer's question, asked
|
|
92
|
+
* before this one, and answering it twice in two places is how the two come to
|
|
93
|
+
* disagree.
|
|
94
|
+
*
|
|
95
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
96
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
97
|
+
* half-executes. Whether `admin_users` has an off state at all is its
|
|
98
|
+
* manifest's `activation` to say, not this line's: a module declaring
|
|
99
|
+
* `nonDeactivatable` never enters one.
|
|
100
|
+
*/
|
|
101
|
+
export interface AdminPasswordVerificationPort {
|
|
102
|
+
verifyPassword(adminUserId: string, password: string): Promise<boolean>;
|
|
103
|
+
}
|
|
104
|
+
export interface ImpersonationStartInput {
|
|
105
|
+
adminUserId: string;
|
|
106
|
+
/** Raw admin session cookie value — must be preserved as the shadow. */
|
|
107
|
+
adminSessionCookieValue: string;
|
|
108
|
+
customerAccountId: string;
|
|
109
|
+
/**
|
|
110
|
+
* Feature 040 — optional: standalone (org-less) customers have no
|
|
111
|
+
* organisation. When provided it scopes the target lookup; when omitted the
|
|
112
|
+
* target is found by id alone.
|
|
113
|
+
*/
|
|
114
|
+
organizationId?: string | null;
|
|
115
|
+
reason?: string;
|
|
116
|
+
ip?: string;
|
|
117
|
+
userAgent?: string;
|
|
118
|
+
requestId?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Who is being impersonated, as the one consumer renders them.
|
|
122
|
+
*
|
|
123
|
+
* Four fields, not a `CustomerAccountRecord`. `customers` reads exactly
|
|
124
|
+
* `id`, `email`, `firstName` and `lastName` off this and returns them in the
|
|
125
|
+
* response body; publishing the whole account here would have meant
|
|
126
|
+
* `admin_users` importing `customer_accounts`' mapper to build a shape nobody
|
|
127
|
+
* asked for — a new cross-module edge, added by the merge request whose job is
|
|
128
|
+
* to remove them.
|
|
129
|
+
*/
|
|
130
|
+
export interface ImpersonatedCustomerIdentity {
|
|
131
|
+
id: string;
|
|
132
|
+
email: string;
|
|
133
|
+
firstName: string;
|
|
134
|
+
lastName: string;
|
|
135
|
+
}
|
|
136
|
+
export interface ImpersonationStartResult {
|
|
137
|
+
impersonationSessionId: string;
|
|
138
|
+
impersonationCookieValue: string;
|
|
139
|
+
impersonationExpiresAt: Date;
|
|
140
|
+
adminShadowSessionCookieValue: string;
|
|
141
|
+
impersonatedCustomerAccount: ImpersonatedCustomerIdentity;
|
|
142
|
+
}
|
|
143
|
+
export interface ImpersonationEndInput {
|
|
144
|
+
impersonationSessionCookieValue: string;
|
|
145
|
+
adminShadowCookieValue: string;
|
|
146
|
+
ip?: string;
|
|
147
|
+
userAgent?: string;
|
|
148
|
+
requestId?: string;
|
|
149
|
+
}
|
|
150
|
+
export interface ImpersonationEndResult {
|
|
151
|
+
adminSessionCookieValue: string;
|
|
152
|
+
adminSessionExpiresAt: Date;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Container name: `impersonationPort`. Owner: `admin_users`.
|
|
156
|
+
*
|
|
157
|
+
* (It said `impersonationService` until issue #192. Nothing registers that
|
|
158
|
+
* name — a consumer copying it out of here got
|
|
159
|
+
* `[kernel] 'impersonationService' is not registered in this composition` on
|
|
160
|
+
* first call, and no `tsc` error before it.)
|
|
161
|
+
*
|
|
162
|
+
* `customers` hosts the "view as this customer" control, so the surface and
|
|
163
|
+
* the machinery sit in different modules by design.
|
|
164
|
+
*
|
|
165
|
+
* `impersonatedCustomerAccount` is the four-field identity the caller renders,
|
|
166
|
+
* not the account entity and not `CustomerAccountRecord` — see its own note.
|
|
167
|
+
*
|
|
168
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
169
|
+
* `ModuleDisabledError` and the call answers 503 `MODULE_DISABLED`, so nothing
|
|
170
|
+
* half-executes. Whether `admin_users` has an off state at all is its manifest's
|
|
171
|
+
* `activation` to say, not this line's: a module declaring
|
|
172
|
+
* `nonDeactivatable` never enters one.
|
|
173
|
+
*/
|
|
174
|
+
export interface ImpersonationPort {
|
|
175
|
+
start(input: ImpersonationStartInput): Promise<ImpersonationStartResult>;
|
|
176
|
+
end(input: ImpersonationEndInput): Promise<ImpersonationEndResult>;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=admin-users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-users.d.ts","sourceRoot":"","sources":["../src/admin-users.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin_users` module contracts — the in-process port surface (feature 075,
|
|
3
|
+
* Phase P).
|
|
4
|
+
*
|
|
5
|
+
* Eleven inbound sites, and they split cleanly in two: seven read the
|
|
6
|
+
* `AdminUser` entity to put a name beside an id — `admin_roles` resolving a
|
|
7
|
+
* user's role, `quote_requests` listing the admins a notification goes to,
|
|
8
|
+
* `catalog` attributing a bulk operation, `organizations` rendering the
|
|
9
|
+
* sales-rep picker — and the rest reach two services.
|
|
10
|
+
*
|
|
11
|
+
* Plain TypeScript rather than Zod: these describe in-process calls.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=admin-users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-users.js","sourceRoot":"","sources":["../src/admin-users.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|