@endora-commerce/mod-megamenu 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 +59 -0
- package/dist/admin/api/megamenu-client.d.ts +28 -0
- package/dist/admin/api/megamenu-client.d.ts.map +1 -0
- package/dist/admin/api/megamenu-client.js +43 -0
- package/dist/admin/api/megamenu-client.js.map +1 -0
- package/dist/admin/components/BindingsPanel.d.ts +10 -0
- package/dist/admin/components/BindingsPanel.d.ts.map +1 -0
- package/dist/admin/components/BindingsPanel.js +120 -0
- package/dist/admin/components/BindingsPanel.js.map +1 -0
- package/dist/admin/components/MenuItemConfigPanel.d.ts +22 -0
- package/dist/admin/components/MenuItemConfigPanel.d.ts.map +1 -0
- package/dist/admin/components/MenuItemConfigPanel.js +77 -0
- package/dist/admin/components/MenuItemConfigPanel.js.map +1 -0
- package/dist/admin/components/MenuItemTree.d.ts +13 -0
- package/dist/admin/components/MenuItemTree.d.ts.map +1 -0
- package/dist/admin/components/MenuItemTree.js +46 -0
- package/dist/admin/components/MenuItemTree.js.map +1 -0
- package/dist/admin/index.d.ts +31 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +47 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/MegamenuEditor.d.ts +4 -0
- package/dist/admin/pages/MegamenuEditor.d.ts.map +1 -0
- package/dist/admin/pages/MegamenuEditor.js +151 -0
- package/dist/admin/pages/MegamenuEditor.js.map +1 -0
- package/dist/admin/pages/MegamenuListPage.d.ts +4 -0
- package/dist/admin/pages/MegamenuListPage.d.ts.map +1 -0
- package/dist/admin/pages/MegamenuListPage.js +51 -0
- package/dist/admin/pages/MegamenuListPage.js.map +1 -0
- package/dist/backend/entities/megamenu-binding.entity.d.ts +18 -0
- package/dist/backend/entities/megamenu-binding.entity.d.ts.map +1 -0
- package/dist/backend/entities/megamenu-binding.entity.js +61 -0
- package/dist/backend/entities/megamenu-binding.entity.js.map +1 -0
- package/dist/backend/entities/megamenu-item.entity.d.ts +27 -0
- package/dist/backend/entities/megamenu-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/megamenu-item.entity.js +83 -0
- package/dist/backend/entities/megamenu-item.entity.js.map +1 -0
- package/dist/backend/entities/megamenu.entity.d.ts +17 -0
- package/dist/backend/entities/megamenu.entity.d.ts.map +1 -0
- package/dist/backend/entities/megamenu.entity.js +57 -0
- package/dist/backend/entities/megamenu.entity.js.map +1 -0
- package/dist/backend/index.d.ts +116 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +147 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +10 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +50 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +6 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +26 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/asset-references.d.ts +4 -0
- package/dist/backend/services/asset-references.d.ts.map +1 -0
- package/dist/backend/services/asset-references.js +36 -0
- package/dist/backend/services/asset-references.js.map +1 -0
- package/dist/backend/services/cms-references.d.ts +6 -0
- package/dist/backend/services/cms-references.d.ts.map +1 -0
- package/dist/backend/services/cms-references.js +39 -0
- package/dist/backend/services/cms-references.js.map +1 -0
- package/dist/backend/services/cross-module-ports.d.ts +112 -0
- package/dist/backend/services/cross-module-ports.d.ts.map +1 -0
- package/dist/backend/services/cross-module-ports.js +88 -0
- package/dist/backend/services/cross-module-ports.js.map +1 -0
- package/dist/backend/services/megamenu-cache.d.ts +36 -0
- package/dist/backend/services/megamenu-cache.d.ts.map +1 -0
- package/dist/backend/services/megamenu-cache.js +70 -0
- package/dist/backend/services/megamenu-cache.js.map +1 -0
- package/dist/backend/services/megamenu-item-service.d.ts +39 -0
- package/dist/backend/services/megamenu-item-service.d.ts.map +1 -0
- package/dist/backend/services/megamenu-item-service.js +151 -0
- package/dist/backend/services/megamenu-item-service.js.map +1 -0
- package/dist/backend/services/megamenu-language-reference.d.ts +12 -0
- package/dist/backend/services/megamenu-language-reference.d.ts.map +1 -0
- package/dist/backend/services/megamenu-language-reference.js +24 -0
- package/dist/backend/services/megamenu-language-reference.js.map +1 -0
- package/dist/backend/services/megamenu-reference-registry.d.ts +24 -0
- package/dist/backend/services/megamenu-reference-registry.d.ts.map +1 -0
- package/dist/backend/services/megamenu-reference-registry.js +69 -0
- package/dist/backend/services/megamenu-reference-registry.js.map +1 -0
- package/dist/backend/services/megamenu-service.d.ts +70 -0
- package/dist/backend/services/megamenu-service.d.ts.map +1 -0
- package/dist/backend/services/megamenu-service.js +299 -0
- package/dist/backend/services/megamenu-service.js.map +1 -0
- package/dist/backend/services/storefront-resolver.d.ts +46 -0
- package/dist/backend/services/storefront-resolver.d.ts.map +1 -0
- package/dist/backend/services/storefront-resolver.js +162 -0
- package/dist/backend/services/storefront-resolver.js.map +1 -0
- package/dist/backend/services/target-validator.d.ts +24 -0
- package/dist/backend/services/target-validator.d.ts.map +1 -0
- package/dist/backend/services/target-validator.js +105 -0
- package/dist/backend/services/target-validator.js.map +1 -0
- package/dist/manifest.d.ts +167 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +170 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260505T193836_megamenu_init.d.ts +23 -0
- package/dist/migrations/20260505T193836_megamenu_init.d.ts.map +1 -0
- package/dist/migrations/20260505T193836_megamenu_init.js +91 -0
- package/dist/migrations/20260505T193836_megamenu_init.js.map +1 -0
- package/dist/migrations/index.d.ts +27 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +29 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/megamenu/index.md +159 -0
- package/i18n/en.json +96 -0
- package/i18n/pl.json +96 -0
- package/package.json +99 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { Redis } from 'ioredis';
|
|
3
|
+
import type { AssetReferenceRegistryPort, CmsExternalReferenceScanner, DictionaryValidator } from '@endora-commerce/contracts';
|
|
4
|
+
import type { ModuleContext } from '@endora-commerce/platform/kernel';
|
|
5
|
+
import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
|
|
6
|
+
import { MegamenuCache, type MegamenuCacheOptions } from './services/megamenu-cache.js';
|
|
7
|
+
import { MegamenuReferenceRegistry } from './services/megamenu-reference-registry.js';
|
|
8
|
+
import { MegamenuService } from './services/megamenu-service.js';
|
|
9
|
+
import { MegamenuItemService } from './services/megamenu-item-service.js';
|
|
10
|
+
import { StorefrontResolver } from './services/storefront-resolver.js';
|
|
11
|
+
import { MegamenuBinding } from './entities/megamenu-binding.entity.js';
|
|
12
|
+
import { MegamenuItem } from './entities/megamenu-item.entity.js';
|
|
13
|
+
import { Megamenu } from './entities/megamenu.entity.js';
|
|
14
|
+
/**
|
|
15
|
+
* `megamenu` — the module reads its own cross-module targets
|
|
16
|
+
* (`specs/110-instance-repository/` T118c).
|
|
17
|
+
*
|
|
18
|
+
* Until T118c this block said the opposite, and said it firmly: two dependency
|
|
19
|
+
* bundles stayed in the composition roots because both were raw SQL against
|
|
20
|
+
* `categories`, `cms_pages`, `cms_blocks` and `assets`, and moving *that* into
|
|
21
|
+
* the module would have given it direct reads of three other modules' storage.
|
|
22
|
+
* The reasoning was right and the conclusion had an expiry date the block wrote
|
|
23
|
+
* down itself: *"it belongs to whichever of `catalog`, `cms` and
|
|
24
|
+
* `assets_library` grows the existence-check port first."* All three have.
|
|
25
|
+
* `catalogCategoryReadPort`, `cmsPageReadPort` and `assetReadPort` came out of
|
|
26
|
+
* `specs/075-cross-module-decoupling-sweep/` Phase C, and `cmsBlockReadPort` is
|
|
27
|
+
* this merge request's — the one port the drain still needed and the reason
|
|
28
|
+
* T118c's row picks this target.
|
|
29
|
+
*
|
|
30
|
+
* So the eight closures are gone from both roots and their two interfaces with
|
|
31
|
+
* them. What replaces them is `MegamenuCrossModulePorts`: five published ports,
|
|
32
|
+
* resolved per call by `lazyPort`, with the four judgements that used to sit
|
|
33
|
+
* inside the closures — a storefront URL's shape, which category counts as live,
|
|
34
|
+
* which asset kinds a menu may embed, what an absent language means — in
|
|
35
|
+
* `services/cross-module-ports.ts`, where they have a test.
|
|
36
|
+
*
|
|
37
|
+
* **What the roots were getting wrong, which is the argument for the drain
|
|
38
|
+
* rather than a bonus.** A root's contribution is nobody's declared dependency,
|
|
39
|
+
* so none of these edges appeared in a manifest: an operator switching `cms` off
|
|
40
|
+
* was told nothing about the menu embeds that stop. And the two roots did not
|
|
41
|
+
* agree — production dropped a deactivated or soft-deleted category from the
|
|
42
|
+
* menu where the harness kept it, and production built `/c/<slug>` where the
|
|
43
|
+
* harness built `/catalog/<slug>`, which the storefront serves from nowhere. No
|
|
44
|
+
* test in the tree read either value, so both divergences were invisible.
|
|
45
|
+
*
|
|
46
|
+
* `requireAdmin` stops being optional — `routes.admin.ts` defaulted an absent
|
|
47
|
+
* gate to `?? (async () => {})`, the permissive form, which both roots happened
|
|
48
|
+
* to pass.
|
|
49
|
+
*
|
|
50
|
+
* `megamenuCacheOptions` is a contribution point that **neither** composition
|
|
51
|
+
* currently overrides, and that is deliberate rather than an oversight. Unlike
|
|
52
|
+
* `seo`'s sitemap options, the harness wants this module's cache *on*:
|
|
53
|
+
* `test/integration/megamenu/storefront-cache.test.ts` exists to prove the
|
|
54
|
+
* payload is cached and dropped on write, so a zero TTL there would make the
|
|
55
|
+
* suite assert nothing. The seam stays for a deployment that wants to tune the
|
|
56
|
+
* TTL; the default is the behaviour both compositions actually want.
|
|
57
|
+
*/
|
|
58
|
+
interface MegamenuServices {
|
|
59
|
+
readonly menuService: MegamenuService;
|
|
60
|
+
readonly itemService: MegamenuItemService;
|
|
61
|
+
readonly storefrontResolver: StorefrontResolver;
|
|
62
|
+
readonly cache: MegamenuCache | undefined;
|
|
63
|
+
}
|
|
64
|
+
export interface MegamenuCradle {
|
|
65
|
+
readonly emFactory: () => EntityManager;
|
|
66
|
+
readonly redis: Redis | undefined;
|
|
67
|
+
readonly requireAdmin: RequireAdminFactory;
|
|
68
|
+
readonly dictionaryValidator: DictionaryValidator;
|
|
69
|
+
/** Composition-specific cache tuning; `{}` in production. */
|
|
70
|
+
readonly megamenuCacheOptions: MegamenuCacheOptions;
|
|
71
|
+
/**
|
|
72
|
+
* Owned by `assets_library`: the registry that refuses to delete an asset a
|
|
73
|
+
* menu item points at, whether as the item's target or as its icon. Named by
|
|
74
|
+
* its published contract since Phase C, not by that module's class.
|
|
75
|
+
*/
|
|
76
|
+
readonly assetReferenceRegistry: AssetReferenceRegistryPort;
|
|
77
|
+
/**
|
|
78
|
+
* Owned by `cms`: the registry that refuses to delete a page or a block a
|
|
79
|
+
* menu item links to. This module contributes the scanner; `cms` calls it.
|
|
80
|
+
*/
|
|
81
|
+
readonly cmsReferenceRegistry: {
|
|
82
|
+
register: (scanner: CmsExternalReferenceScanner) => void;
|
|
83
|
+
};
|
|
84
|
+
readonly megamenuServices: MegamenuServices;
|
|
85
|
+
readonly megamenuReferenceRegistry: MegamenuReferenceRegistry;
|
|
86
|
+
}
|
|
87
|
+
export declare function registerModule(ctx: ModuleContext): void;
|
|
88
|
+
/**
|
|
89
|
+
* The module's persisted entity classes, on the `./backend` subpath, as one
|
|
90
|
+
* array and **no named class export** (D-168).
|
|
91
|
+
*
|
|
92
|
+
* This is the shape the platform reads when the package is *installed*: the
|
|
93
|
+
* boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
|
|
94
|
+
* and the static declaration reader (`scripts/lib/package-declarations.ts`),
|
|
95
|
+
* which is the third source of `check:module-boundary`'s `table->owner` map and
|
|
96
|
+
* the package pass of `check-entity-tenant-classification`. A missing array is
|
|
97
|
+
* answered with `[]` — zero entities registered, no error anywhere.
|
|
98
|
+
*
|
|
99
|
+
* The order is the one `db/entities-registry.generated.ts` declared before this
|
|
100
|
+
* module became a package, so the registered set is the same list in the same
|
|
101
|
+
* sequence.
|
|
102
|
+
*/
|
|
103
|
+
export declare const entities: (typeof MegamenuBinding | typeof MegamenuItem | typeof Megamenu)[];
|
|
104
|
+
export {};
|
|
105
|
+
/**
|
|
106
|
+
* **Nothing is published for a composition root any more**
|
|
107
|
+
* (`specs/110-instance-repository/` T118c).
|
|
108
|
+
*
|
|
109
|
+
* `TargetValidatorDeps` and `StorefrontDeps` were exported here so
|
|
110
|
+
* `backend/src/composition.ts` and `backend/test/helpers/test-server.ts` could
|
|
111
|
+
* write objects that `satisfies` them. Both roots have stopped, both interfaces
|
|
112
|
+
* are deleted rather than relocated, and this module's outward reach is
|
|
113
|
+
* `MegamenuCrossModulePorts` — module-private, and a bundle of five published
|
|
114
|
+
* ports with no closure in it, so there is nothing left for a root to build.
|
|
115
|
+
*/
|
|
116
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAEV,0BAA0B,EAI1B,2BAA2B,EAE3B,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAMvE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,UAAU,gBAAgB;IACxB,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,aAAa,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,6DAA6D;IAC7D,QAAQ,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,sBAAsB,EAAE,0BAA0B,CAAC;IAC5D;;;OAGG;IACH,QAAQ,CAAC,oBAAoB,EAAE;QAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAA;KAAE,CAAC;IAC5F,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,yBAAyB,EAAE,yBAAyB,CAAC;CAC/D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmHvD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,oEAIpB,CAAC;;AAEF;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { lazyPort } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { MegamenuCache } from './services/megamenu-cache.js';
|
|
3
|
+
import { MegamenuReferenceRegistry } from './services/megamenu-reference-registry.js';
|
|
4
|
+
import { MegamenuService } from './services/megamenu-service.js';
|
|
5
|
+
import { MegamenuItemService } from './services/megamenu-item-service.js';
|
|
6
|
+
import { StorefrontResolver } from './services/storefront-resolver.js';
|
|
7
|
+
import { registerMegamenuAdminRoutes } from './routes.admin.js';
|
|
8
|
+
import { registerMegamenuStorefrontRoutes } from './routes.storefront.js';
|
|
9
|
+
import { registerMegamenuAssetReferences } from './services/asset-references.js';
|
|
10
|
+
import { registerMegamenuCmsReferences } from './services/cms-references.js';
|
|
11
|
+
import { registerMegamenuLanguageReferences } from './services/megamenu-language-reference.js';
|
|
12
|
+
import { MegamenuBinding } from './entities/megamenu-binding.entity.js';
|
|
13
|
+
import { MegamenuItem } from './entities/megamenu-item.entity.js';
|
|
14
|
+
import { Megamenu } from './entities/megamenu.entity.js';
|
|
15
|
+
export function registerModule(ctx) {
|
|
16
|
+
ctx.di.register({
|
|
17
|
+
megamenuCacheOptions: ctx.asFunction(() => ({})).singleton(),
|
|
18
|
+
megamenuServices: ctx
|
|
19
|
+
.asFunction(({ emFactory, redis, megamenuCacheOptions }) => {
|
|
20
|
+
const cache = redis ? new MegamenuCache(redis, megamenuCacheOptions) : undefined;
|
|
21
|
+
const menuService = new MegamenuService(emFactory, cache, lazyPort(ctx, 'dictionaryValidator'));
|
|
22
|
+
/**
|
|
23
|
+
* The five published ports this module reads outside itself
|
|
24
|
+
* (`specs/110-instance-repository/` T118c). Every one is a `lazyPort`
|
|
25
|
+
* proxy that resolves on the call rather than here, so nothing
|
|
26
|
+
* captures a gated registration — a captured gate keeps answering
|
|
27
|
+
* after its owner is switched off.
|
|
28
|
+
*
|
|
29
|
+
* Two of them are `assets_library`'s, because neither answers the
|
|
30
|
+
* whole question: `AssetRecord` carries the stored `kind` and no
|
|
31
|
+
* resolved URL, `AssetDetail` carries the URL and no `kind`, and
|
|
32
|
+
* `resolveUrl` is published on no port (D-223).
|
|
33
|
+
*/
|
|
34
|
+
const ports = {
|
|
35
|
+
categories: lazyPort(ctx, 'catalogCategoryReadPort'),
|
|
36
|
+
pages: lazyPort(ctx, 'cmsPageReadPort'),
|
|
37
|
+
blocks: lazyPort(ctx, 'cmsBlockReadPort'),
|
|
38
|
+
assets: lazyPort(ctx, 'assetReadPort'),
|
|
39
|
+
assetLibrary: lazyPort(ctx, 'assetsLibraryPort'),
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
menuService,
|
|
43
|
+
cache,
|
|
44
|
+
itemService: new MegamenuItemService(emFactory, menuService, ports, cache),
|
|
45
|
+
storefrontResolver: new StorefrontResolver(emFactory, ports, cache),
|
|
46
|
+
};
|
|
47
|
+
})
|
|
48
|
+
.singleton(),
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* The lookup behind this module's own CMS scanner, deliberately **ungated**
|
|
52
|
+
* (feature 072, D-39).
|
|
53
|
+
*
|
|
54
|
+
* It was a `providePort`, and the only thing that resolves it is this
|
|
55
|
+
* module's own boot hook, twenty lines down — so switching `megamenu` off
|
|
56
|
+
* made `megamenu` throw `MODULE_DISABLED` at its own registration and the
|
|
57
|
+
* backend stopped starting. The gate protected nothing: the sole consumer is
|
|
58
|
+
* the module the gate was about.
|
|
59
|
+
*
|
|
60
|
+
* It stays ungated rather than merely moving: what it feeds is a scanner
|
|
61
|
+
* `cms` walks on delete, and `cms` honours that edge while `megamenu` is off
|
|
62
|
+
* on purpose — the menu items still hold the reference. A gate here would be
|
|
63
|
+
* a second, contradictory answer to a question `cms` has already answered.
|
|
64
|
+
*/
|
|
65
|
+
ctx.di.register({
|
|
66
|
+
megamenuReferenceRegistry: ctx
|
|
67
|
+
.asFunction(({ emFactory }) => new MegamenuReferenceRegistry(emFactory))
|
|
68
|
+
.singleton(),
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* The two reference edges this module holds against other modules' entities
|
|
72
|
+
* (T143a): an asset a menu item targets or uses as an icon, and a CMS page or
|
|
73
|
+
* block a menu item links to. Both refuse the upstream delete with a 409 that
|
|
74
|
+
* names the menu.
|
|
75
|
+
*
|
|
76
|
+
* Both roots used to cross-register these, which had the failure this cluster
|
|
77
|
+
* exists to remove: a root's push survives `megamenu` being switched off, so
|
|
78
|
+
* an operator who had disabled the module still could not delete a page a
|
|
79
|
+
* megamenu item referenced, and the 409 named a menu the platform was no
|
|
80
|
+
* longer serving.
|
|
81
|
+
*
|
|
82
|
+
* `ctx.onBoot` rather than a registration: both registries are *read* by
|
|
83
|
+
* their owners on delete, and a registration declares without resolving.
|
|
84
|
+
*/
|
|
85
|
+
ctx.onBoot(() => {
|
|
86
|
+
const { assetReferenceRegistry, cmsReferenceRegistry, megamenuReferenceRegistry, emFactory } = ctx.cradle();
|
|
87
|
+
registerMegamenuAssetReferences(assetReferenceRegistry, emFactory);
|
|
88
|
+
registerMegamenuCmsReferences(cmsReferenceRegistry, megamenuReferenceRegistry);
|
|
89
|
+
});
|
|
90
|
+
ctx.routes(async (app) => {
|
|
91
|
+
const { megamenuServices, requireAdmin } = ctx.cradle();
|
|
92
|
+
await registerMegamenuAdminRoutes(app, {
|
|
93
|
+
menuService: megamenuServices.menuService,
|
|
94
|
+
itemService: megamenuServices.itemService,
|
|
95
|
+
requireAdmin,
|
|
96
|
+
});
|
|
97
|
+
await registerMegamenuStorefrontRoutes(app, {
|
|
98
|
+
storefrontResolver: megamenuServices.storefrontResolver,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* This module's rows carry a language code, so it answers "who still points at
|
|
103
|
+
* this language?" about its own tables (feature 077, D-87), where the owner used
|
|
104
|
+
* to count them with SQL naming this module's tables.
|
|
105
|
+
*
|
|
106
|
+
* A **contribution** hook: it pushes an inert descriptor into `languageReferenceRegistry`,
|
|
107
|
+
* an ungated registry, and carries no presence probe (D-62/D-68). Probing
|
|
108
|
+
* would be wrong in the dangerous direction — a switched-off module still owns
|
|
109
|
+
* the rows, so its language must still refuse the delete, which is the
|
|
110
|
+
* enumeration policy the registry states.
|
|
111
|
+
*/
|
|
112
|
+
ctx.onBoot(() => {
|
|
113
|
+
registerMegamenuLanguageReferences(lazyPort(ctx, 'languageReferenceRegistry'), ctx.cradle().emFactory);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The module's persisted entity classes, on the `./backend` subpath, as one
|
|
118
|
+
* array and **no named class export** (D-168).
|
|
119
|
+
*
|
|
120
|
+
* This is the shape the platform reads when the package is *installed*: the
|
|
121
|
+
* boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
|
|
122
|
+
* and the static declaration reader (`scripts/lib/package-declarations.ts`),
|
|
123
|
+
* which is the third source of `check:module-boundary`'s `table->owner` map and
|
|
124
|
+
* the package pass of `check-entity-tenant-classification`. A missing array is
|
|
125
|
+
* answered with `[]` — zero entities registered, no error anywhere.
|
|
126
|
+
*
|
|
127
|
+
* The order is the one `db/entities-registry.generated.ts` declared before this
|
|
128
|
+
* module became a package, so the registered set is the same list in the same
|
|
129
|
+
* sequence.
|
|
130
|
+
*/
|
|
131
|
+
export const entities = [
|
|
132
|
+
MegamenuBinding,
|
|
133
|
+
MegamenuItem,
|
|
134
|
+
Megamenu,
|
|
135
|
+
];
|
|
136
|
+
/**
|
|
137
|
+
* **Nothing is published for a composition root any more**
|
|
138
|
+
* (`specs/110-instance-repository/` T118c).
|
|
139
|
+
*
|
|
140
|
+
* `TargetValidatorDeps` and `StorefrontDeps` were exported here so
|
|
141
|
+
* `backend/src/composition.ts` and `backend/test/helpers/test-server.ts` could
|
|
142
|
+
* write objects that `satisfies` them. Both roots have stopped, both interfaces
|
|
143
|
+
* are deleted rather than relocated, and this module's outward reach is
|
|
144
|
+
* `MegamenuCrossModulePorts` — module-private, and a bundle of five published
|
|
145
|
+
* ports with no closure in it, so there is nothing left for a root to build.
|
|
146
|
+
*/
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { MegamenuService } from './services/megamenu-service.js';
|
|
3
|
+
import type { MegamenuItemService } from './services/megamenu-item-service.js';
|
|
4
|
+
import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
|
|
5
|
+
export declare function registerMegamenuAdminRoutes(app: FastifyInstance, deps: {
|
|
6
|
+
menuService: MegamenuService;
|
|
7
|
+
itemService: MegamenuItemService;
|
|
8
|
+
requireAdmin: RequireAdminFactory;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=routes.admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.d.ts","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAQ/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IACJ,WAAW,EAAE,eAAe,CAAC;IAC7B,WAAW,EAAE,mBAAmB,CAAC;IACjC,YAAY,EAAE,mBAAmB,CAAC;CACnC,GACA,OAAO,CAAC,IAAI,CAAC,CAoHf"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { activateBindingRequestSchema, addBindingRequestSchema, createMegamenuRequestSchema, patchMegamenuRequestSchema, putItemsRequestSchema, } from '@endora-commerce/contracts';
|
|
2
|
+
export async function registerMegamenuAdminRoutes(app, deps) {
|
|
3
|
+
const requireRead = deps.requireAdmin('megamenu.read');
|
|
4
|
+
const requireWrite = deps.requireAdmin('megamenu.write');
|
|
5
|
+
app.get('/api/v1/admin/megamenu/menus', { preHandler: requireRead }, async () => deps.menuService.list());
|
|
6
|
+
app.post('/api/v1/admin/megamenu/menus', { preHandler: requireWrite }, async (request, reply) => {
|
|
7
|
+
const body = createMegamenuRequestSchema.parse(request.body);
|
|
8
|
+
const created = await deps.menuService.create(body);
|
|
9
|
+
return reply.code(201).send({ data: created });
|
|
10
|
+
});
|
|
11
|
+
app.get('/api/v1/admin/megamenu/menus/:id', { preHandler: requireRead }, async (request) => ({ data: await deps.menuService.get(request.params.id) }));
|
|
12
|
+
app.patch('/api/v1/admin/megamenu/menus/:id', { preHandler: requireWrite }, async (request) => {
|
|
13
|
+
const body = patchMegamenuRequestSchema.parse(request.body);
|
|
14
|
+
return { data: await deps.menuService.patch(request.params.id, body) };
|
|
15
|
+
});
|
|
16
|
+
app.delete('/api/v1/admin/megamenu/menus/:id', { preHandler: requireWrite }, async (request, reply) => {
|
|
17
|
+
await deps.menuService.delete(request.params.id);
|
|
18
|
+
return reply.code(204).send();
|
|
19
|
+
});
|
|
20
|
+
app.put('/api/v1/admin/megamenu/menus/:id/items', { preHandler: requireWrite }, async (request) => {
|
|
21
|
+
const body = putItemsRequestSchema.parse(request.body);
|
|
22
|
+
const result = await deps.itemService.setTree(request.params.id, body);
|
|
23
|
+
return {
|
|
24
|
+
data: result.detail,
|
|
25
|
+
...(result.warnings.length > 0 ? { meta: { warnings: result.warnings } } : {}),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
// ── Bindings ──────────────────────────────────────────────────────
|
|
29
|
+
app.get('/api/v1/admin/megamenu/menus/:id/bindings', { preHandler: requireRead }, async (request) => ({ data: await deps.menuService.listBindings(request.params.id) }));
|
|
30
|
+
app.post('/api/v1/admin/megamenu/menus/:id/bindings', { preHandler: requireWrite }, async (request, reply) => {
|
|
31
|
+
const body = addBindingRequestSchema.parse(request.body);
|
|
32
|
+
const created = await deps.menuService.addBinding(request.params.id, body.salesChannelId, body.language);
|
|
33
|
+
return reply.code(201).send({ data: created });
|
|
34
|
+
});
|
|
35
|
+
app.delete('/api/v1/admin/megamenu/menus/:id/bindings/:salesChannelId/:language', { preHandler: requireWrite }, async (request, reply) => {
|
|
36
|
+
await deps.menuService.removeBinding(request.params.id, request.params.salesChannelId, request.params.language);
|
|
37
|
+
return reply.code(204).send();
|
|
38
|
+
});
|
|
39
|
+
app.post('/api/v1/admin/megamenu/menus/:id/activate', { preHandler: requireWrite }, async (request) => {
|
|
40
|
+
const body = activateBindingRequestSchema.parse(request.body);
|
|
41
|
+
const result = await deps.menuService.activate(request.params.id, body.salesChannelId, body.language);
|
|
42
|
+
return { data: result };
|
|
43
|
+
});
|
|
44
|
+
app.post('/api/v1/admin/megamenu/menus/:id/deactivate', { preHandler: requireWrite }, async (request, reply) => {
|
|
45
|
+
const body = activateBindingRequestSchema.parse(request.body);
|
|
46
|
+
await deps.menuService.deactivate(request.params.id, body.salesChannelId, body.language);
|
|
47
|
+
return reply.code(200).send({ data: { deactivated: body } });
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=routes.admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.admin.js","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { StorefrontResolver } from './services/storefront-resolver.js';
|
|
3
|
+
export declare function registerMegamenuStorefrontRoutes(app: FastifyInstance, deps: {
|
|
4
|
+
storefrontResolver: StorefrontResolver;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=routes.storefront.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.storefront.d.ts","sourceRoot":"","sources":["../../src/backend/routes.storefront.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAI/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAE5E,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IAAE,kBAAkB,EAAE,kBAAkB,CAAA;CAAE,GAC/C,OAAO,CAAC,IAAI,CAAC,CAcf"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ERROR_CODES } from '@endora-commerce/contracts';
|
|
2
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
3
|
+
import { getResolvedChannel } from '@endora-commerce/platform/kernel';
|
|
4
|
+
export async function registerMegamenuStorefrontRoutes(app, deps) {
|
|
5
|
+
app.get('/api/v1/megamenu/by-channel', async (request) => {
|
|
6
|
+
const query = (request.query ?? {});
|
|
7
|
+
const language = query['language'] ?? readHeader(request.headers['accept-language'])?.split(',')[0];
|
|
8
|
+
const resolved = await deps.storefrontResolver.resolveByChannelAndLanguage({
|
|
9
|
+
resolvedChannel: resolvedChannel(request),
|
|
10
|
+
...(language !== undefined ? { language } : {}),
|
|
11
|
+
});
|
|
12
|
+
if (!resolved) {
|
|
13
|
+
throw new HttpError(404, ERROR_CODES.MEGAMENU_NOT_FOUND, 'No active Megamenu for the requested scope.');
|
|
14
|
+
}
|
|
15
|
+
return { data: resolved };
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** Reads the request's already-resolved sales channel (set by the resolver middleware). */
|
|
19
|
+
function resolvedChannel(request) {
|
|
20
|
+
const ch = getResolvedChannel(request);
|
|
21
|
+
return { id: ch.id, code: ch.code, defaultLanguage: ch.defaultLanguage };
|
|
22
|
+
}
|
|
23
|
+
function readHeader(value) {
|
|
24
|
+
return Array.isArray(value) ? value[0] : value;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=routes.storefront.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.storefront.js","sourceRoot":"","sources":["../../src/backend/routes.storefront.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAGtE,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,GAAoB,EACpB,IAAgD;IAEhD,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACvD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAuC,CAAC;QAC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpG,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,2BAA2B,CAAC;YACzE,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC;YACzC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChD,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,kBAAkB,EAAE,6CAA6C,CAAC,CAAC;QAC1G,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,2FAA2F;AAC3F,SAAS,eAAe,CAAC,OAAuB;IAC9C,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC;AAC3E,CAAC;AAED,SAAS,UAAU,CAAC,KAAoC;IACtD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { AssetReferenceRegistryPort } from '@endora-commerce/contracts';
|
|
3
|
+
export declare function registerMegamenuAssetReferences(registry: AssetReferenceRegistryPort, emFactory: () => EntityManager): void;
|
|
4
|
+
//# sourceMappingURL=asset-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-references.d.ts","sourceRoot":"","sources":["../../../src/backend/services/asset-references.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAGV,0BAA0B,EAC3B,MAAM,4BAA4B,CAAC;AAEpC,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,0BAA0B,EACpC,SAAS,EAAE,MAAM,aAAa,GAC7B,IAAI,CAEN"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Megamenu → AssetReferenceRegistry descriptor — feature 015 / T015.
|
|
2
|
+
//
|
|
3
|
+
// Scans `megamenu_items.target` for both `assetId` (asset items) and
|
|
4
|
+
// `iconAssetId` (link items with an icon). Both edges block deletion of
|
|
5
|
+
// the upstream Library Asset with a 409.
|
|
6
|
+
//
|
|
7
|
+
// The registry and the descriptor are named by their `@endora-commerce/contracts` shapes
|
|
8
|
+
// since feature 075's Phase C: this file describes what it contributes, and
|
|
9
|
+
// `assets_library` decides what enumerating it means — including the policy
|
|
10
|
+
// that honours this scanner while `megamenu` is switched off, which is why the
|
|
11
|
+
// seam stays an ungated registration rather than becoming a port.
|
|
12
|
+
export function registerMegamenuAssetReferences(registry, emFactory) {
|
|
13
|
+
registry.register(megamenuAssetReferenceDescriptor(emFactory));
|
|
14
|
+
}
|
|
15
|
+
function megamenuAssetReferenceDescriptor(emFactory) {
|
|
16
|
+
return {
|
|
17
|
+
ownerModuleId: 'megamenu',
|
|
18
|
+
async findReferences(assetIds) {
|
|
19
|
+
if (assetIds.length === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const em = emFactory();
|
|
22
|
+
const placeholders = assetIds.map(() => '?').join(', ');
|
|
23
|
+
const rows = (await em.execute(`select mi.id::text as item_id, m.name as menu_name
|
|
24
|
+
from megamenu_items mi
|
|
25
|
+
join megamenus m on m.id = mi.megamenu_id
|
|
26
|
+
where mi.target->>'assetId' in (${placeholders})
|
|
27
|
+
or mi.target->>'iconAssetId' in (${placeholders})`, [...assetIds, ...assetIds]));
|
|
28
|
+
return rows.map((r) => ({
|
|
29
|
+
kind: 'megamenu_item_target',
|
|
30
|
+
entityId: r.item_id,
|
|
31
|
+
label: `Megamenu "${r.menu_name}"`,
|
|
32
|
+
}));
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=asset-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-references.js","sourceRoot":"","sources":["../../../src/backend/services/asset-references.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,yCAAyC;AACzC,EAAE;AACF,yFAAyF;AACzF,4EAA4E;AAC5E,4EAA4E;AAC5E,+EAA+E;AAC/E,kEAAkE;AASlE,MAAM,UAAU,+BAA+B,CAC7C,QAAoC,EACpC,SAA8B;IAE9B,QAAQ,CAAC,QAAQ,CAAC,gCAAgC,CAAC,SAAS,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,gCAAgC,CACvC,SAA8B;IAE9B,OAAO;QACL,aAAa,EAAE,UAAU;QACzB,KAAK,CAAC,cAAc,CAAC,QAAkB;YACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;YACvB,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAC5B;;;gDAGwC,YAAY;gDACZ,YAAY,GAAG,EACvD,CAAC,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC,CAC3B,CAAkD,CAAC;YACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtB,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,CAAC,CAAC,OAAO;gBACnB,KAAK,EAAE,aAAa,CAAC,CAAC,SAAS,GAAG;aACnC,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CmsExternalReferenceScanner } from '@endora-commerce/contracts';
|
|
2
|
+
import type { MegamenuReferenceRegistry } from './megamenu-reference-registry.js';
|
|
3
|
+
export declare function registerMegamenuCmsReferences(cmsRegistry: {
|
|
4
|
+
register: (scanner: CmsExternalReferenceScanner) => void;
|
|
5
|
+
}, megamenuRegistry: MegamenuReferenceRegistry): void;
|
|
6
|
+
//# sourceMappingURL=cms-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-references.d.ts","sourceRoot":"","sources":["../../../src/backend/services/cms-references.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,2BAA2B,EAAgB,MAAM,4BAA4B,CAAC;AAC5F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAElF,wBAAgB,6BAA6B,CAK3C,WAAW,EAAE;IAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAA;CAAE,EACzE,gBAAgB,EAAE,yBAAyB,GAC1C,IAAI,CAoBN"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Megamenu → CmsReferenceRegistry external scanner — feature 015 / T047.
|
|
2
|
+
//
|
|
3
|
+
// Adapts the in-process `MegamenuReferenceRegistry` into the shape the
|
|
4
|
+
// CMS module's `CmsReferenceRegistry` registers. When the CMS module's
|
|
5
|
+
// page or block delete endpoints consult their registry, our scanner
|
|
6
|
+
// surfaces megamenu items that hold the reference, so the delete is
|
|
7
|
+
// refused with the merged-holder list.
|
|
8
|
+
//
|
|
9
|
+
// Both shapes are read from `@endora-commerce/contracts` since feature 075's Phase C, so
|
|
10
|
+
// this module no longer names a file in `cms`. The seam itself is unchanged:
|
|
11
|
+
// an ungated registration `cms` enumerates on delete, honoured while `megamenu`
|
|
12
|
+
// is off because the items still hold the reference.
|
|
13
|
+
export function registerMegamenuCmsReferences(
|
|
14
|
+
// `CmsReferenceRegistryPort` is the whole seam; a contributor calls one
|
|
15
|
+
// method of it, and `cms`' registry spells the other one `externalOwners`.
|
|
16
|
+
// Naming just `register` keeps this signature what it has always been while
|
|
17
|
+
// the scanner shape comes from the contract.
|
|
18
|
+
cmsRegistry, megamenuRegistry) {
|
|
19
|
+
cmsRegistry.register({
|
|
20
|
+
ownerModuleId: 'megamenu',
|
|
21
|
+
async findPageReferences(pageId) {
|
|
22
|
+
const refs = await megamenuRegistry.findCmsPageReferences(pageId);
|
|
23
|
+
return refs.map((ref) => ({
|
|
24
|
+
kind: 'megamenu',
|
|
25
|
+
entityId: ref.menuId,
|
|
26
|
+
label: `Megamenu "${ref.menuName}"`,
|
|
27
|
+
}));
|
|
28
|
+
},
|
|
29
|
+
async findBlockReferences(blockId) {
|
|
30
|
+
const refs = await megamenuRegistry.findCmsBlockReferences(blockId);
|
|
31
|
+
return refs.map((ref) => ({
|
|
32
|
+
kind: 'megamenu',
|
|
33
|
+
entityId: ref.menuId,
|
|
34
|
+
label: `Megamenu "${ref.menuName}"`,
|
|
35
|
+
}));
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cms-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-references.js","sourceRoot":"","sources":["../../../src/backend/services/cms-references.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,uEAAuE;AACvE,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,uCAAuC;AACvC,EAAE;AACF,yFAAyF;AACzF,6EAA6E;AAC7E,gFAAgF;AAChF,qDAAqD;AAKrD,MAAM,UAAU,6BAA6B;AAC3C,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAC5E,6CAA6C;AAC7C,WAAyE,EACzE,gBAA2C;IAE3C,WAAW,CAAC,QAAQ,CAAC;QACnB,aAAa,EAAE,UAAU;QACzB,KAAK,CAAC,kBAAkB,CAAC,MAAc;YACrC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACxB,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,GAAG,CAAC,MAAM;gBACpB,KAAK,EAAE,aAAa,GAAG,CAAC,QAAQ,GAAG;aACpC,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,CAAC,mBAAmB,CAAC,OAAe;YACvC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YACpE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACxB,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,GAAG,CAAC,MAAM;gBACpB,KAAK,EAAE,aAAa,GAAG,CAAC,QAAQ,GAAG;aACpC,CAAC,CAAC,CAAC;QACN,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { AssetReadPort, AssetsLibraryPort, CatalogCategoryReadPort, CmsBlockReadPort, CmsPageReadPort, MegamenuAssetKind, MegamenuResolvedBlock } from '@endora-commerce/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* Everything this module reads outside itself, in one declaration
|
|
4
|
+
* (`specs/110-instance-repository/` T118c).
|
|
5
|
+
*
|
|
6
|
+
* Until T118c this was two objects a composition root built —
|
|
7
|
+
* `megamenuValidatorDeps` and `megamenuStorefrontDeps`, eight closures written
|
|
8
|
+
* twice, once in `backend/src/composition.ts` and once in
|
|
9
|
+
* `backend/test/helpers/test-server.ts`. Every one of them was a
|
|
10
|
+
* `select … from categories | cms_pages | cms_blocks | assets` issued from a file
|
|
11
|
+
* this module does not own, by a root that is nobody's declared dependency: an
|
|
12
|
+
* operator switching `cms` off was told nothing about what stops, because the
|
|
13
|
+
* edge existed nowhere a manifest could see it. The two roots also disagreed —
|
|
14
|
+
* production dropped a deactivated category from the menu and the harness did
|
|
15
|
+
* not, and production built `/c/<slug>` where the harness built `/catalog/<slug>`,
|
|
16
|
+
* a path the storefront serves from nowhere.
|
|
17
|
+
*
|
|
18
|
+
* Every member is now its owner's **published** port, resolved per call by
|
|
19
|
+
* `lazyPort` in `backend/index.ts`, so the gate is the registration's and the
|
|
20
|
+
* edges are in this module's manifest `dependencies`.
|
|
21
|
+
*
|
|
22
|
+
* The four functions below are the judgements that used to live inside those
|
|
23
|
+
* closures — a storefront URL's shape, which category counts as live, which
|
|
24
|
+
* asset kinds a menu may embed, and what an absent language means. They are
|
|
25
|
+
* functions of their ports rather than of a `ModuleContext`, so each is testable
|
|
26
|
+
* over a stub with nothing composed.
|
|
27
|
+
*/
|
|
28
|
+
export interface MegamenuCrossModulePorts {
|
|
29
|
+
/** `catalog` — a menu item's category target and its storefront URL. */
|
|
30
|
+
readonly categories: Pick<CatalogCategoryReadPort, 'findById'>;
|
|
31
|
+
/** `cms` — a menu item's page target and its storefront URL. */
|
|
32
|
+
readonly pages: Pick<CmsPageReadPort, 'findById'>;
|
|
33
|
+
/** `cms` — a menu item's block target, and the tree a panel inlines. */
|
|
34
|
+
readonly blocks: Pick<CmsBlockReadPort, 'findById' | 'findLocalizedById'>;
|
|
35
|
+
/** `assets_library` — the stored kind, which is what an item's target declares. */
|
|
36
|
+
readonly assets: Pick<AssetReadPort, 'findById'>;
|
|
37
|
+
/**
|
|
38
|
+
* `assets_library` again, for the URL alone.
|
|
39
|
+
*
|
|
40
|
+
* Two ports for one asset because neither answers the whole question:
|
|
41
|
+
* `AssetRecord` carries the stored `kind` and no resolved URL, and
|
|
42
|
+
* `AssetDetail` carries the URL and no `kind`. `resolveUrl`, which is what
|
|
43
|
+
* both roots called, **is published on no port** — D-223, in as many words —
|
|
44
|
+
* so `getAsset` is the sanctioned way to turn an asset id into a URL and this
|
|
45
|
+
* is the same two reads the roots issued.
|
|
46
|
+
*/
|
|
47
|
+
readonly assetLibrary: Pick<AssetsLibraryPort, 'getAsset'>;
|
|
48
|
+
}
|
|
49
|
+
/** What a menu item renders an asset target or an icon as. */
|
|
50
|
+
export interface MegamenuAssetTarget {
|
|
51
|
+
url: string;
|
|
52
|
+
label: string | null;
|
|
53
|
+
kind: MegamenuAssetKind;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A category target's public storefront URL, or `null` for one a shopper may not
|
|
57
|
+
* reach — which drops the item, and its children with it.
|
|
58
|
+
*
|
|
59
|
+
* `/c/<slug>` is the storefront's category route
|
|
60
|
+
* (`storefront/app/(catalog)/c/[slug]`), and a module naming it is the tree's
|
|
61
|
+
* established shape: `seo`'s sitemap builds `/c/`, `/p/` and `/<slug>` in its own
|
|
62
|
+
* sources for the same three things. The composition roots disagreed about it —
|
|
63
|
+
* the harness built `/catalog/<slug>`, which no route serves — and no test in the
|
|
64
|
+
* tree read the value, so the harness's answer was wrong for as long as it
|
|
65
|
+
* existed.
|
|
66
|
+
*
|
|
67
|
+
* **Deactivated and soft-deleted are both refusals**, which is production's
|
|
68
|
+
* `is_active = true and deleted_at is null`. `liveOnly` is the port's word for
|
|
69
|
+
* the second; `isActive` rides on the record because it is the caller's
|
|
70
|
+
* judgement, and the admin-side existence check below deliberately makes the
|
|
71
|
+
* opposite one.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveCategoryUrl(categories: MegamenuCrossModulePorts['categories'], categoryId: string): Promise<string | null>;
|
|
74
|
+
/**
|
|
75
|
+
* A CMS page target's public storefront URL, or `null` when the page is gone.
|
|
76
|
+
*
|
|
77
|
+
* **No status or `active` narrowing**, which is what both roots did and is an
|
|
78
|
+
* asymmetry with the category case above rather than an oversight of this drain:
|
|
79
|
+
* a draft or deactivated page keeps its menu item and answers for itself when the
|
|
80
|
+
* shopper follows the link. Changing it is a product decision, and T118c moves a
|
|
81
|
+
* value rather than redesigning it.
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveCmsPageUrl(pages: MegamenuCrossModulePorts['pages'], pageId: string): Promise<string | null>;
|
|
84
|
+
/**
|
|
85
|
+
* An asset target or icon, resolved to the three fields a menu payload carries.
|
|
86
|
+
*
|
|
87
|
+
* `null` for an asset that is gone, and for one whose stored kind a menu cannot
|
|
88
|
+
* render: the library holds `pdf`, `certificate` and `other` as well, and
|
|
89
|
+
* `MegamenuAssetKind` is the narrower pair. The narrowing is the roots' own
|
|
90
|
+
* (`if (row.kind !== 'image' && row.kind !== 'video') return null`) and it is what
|
|
91
|
+
* keeps the wire shape's union honest.
|
|
92
|
+
*
|
|
93
|
+
* **No `catch` around `getAsset`, deliberately.** It throws 404 for a row that is
|
|
94
|
+
* gone, which the read above has already answered `null` for, so the only way to
|
|
95
|
+
* reach it is an asset deleted between the two reads — and swallowing it would
|
|
96
|
+
* also swallow `ModuleDisabledError`, which is the fail-open composition
|
|
97
|
+
* checklist item 7 refuses. Neither root caught here either.
|
|
98
|
+
*/
|
|
99
|
+
export declare function resolveMenuAsset(ports: Pick<MegamenuCrossModulePorts, 'assets' | 'assetLibrary'>, assetId: string): Promise<MegamenuAssetTarget | null>;
|
|
100
|
+
/**
|
|
101
|
+
* The block a panel inlines, in the language the menu is being resolved for, or
|
|
102
|
+
* `null` when there is nothing to inline — which drops the item.
|
|
103
|
+
*
|
|
104
|
+
* `schemaVersion: 1` is **this module's wire contract**
|
|
105
|
+
* (`megamenuResolvedBlockSchema`) and not the CMS envelope's deprecated
|
|
106
|
+
* `schema_version`, which is normalized away on read. It is a constant here for
|
|
107
|
+
* the same reason it was a constant in the root closures: nothing produces a
|
|
108
|
+
* second version of this payload shape, and the field belongs to whoever owns the
|
|
109
|
+
* response.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveMenuBlock(blocks: MegamenuCrossModulePorts['blocks'], blockId: string, language: string): Promise<MegamenuResolvedBlock | null>;
|
|
112
|
+
//# sourceMappingURL=cross-module-ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-module-ports.d.ts","sourceRoot":"","sources":["../../../src/backend/services/cross-module-ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAC;IAC/D,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAClD,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,mBAAmB,CAAC,CAAC;IAC1E,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACjD;;;;;;;;;OASG;IACH,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;CAC5D;AAED,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC,EAClD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,EACxC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,IAAI,CAAC,wBAAwB,EAAE,QAAQ,GAAG,cAAc,CAAC,EAChE,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CASrC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CASvC"}
|