@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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/admin/api/megamenu-client.d.ts +28 -0
  4. package/dist/admin/api/megamenu-client.d.ts.map +1 -0
  5. package/dist/admin/api/megamenu-client.js +43 -0
  6. package/dist/admin/api/megamenu-client.js.map +1 -0
  7. package/dist/admin/components/BindingsPanel.d.ts +10 -0
  8. package/dist/admin/components/BindingsPanel.d.ts.map +1 -0
  9. package/dist/admin/components/BindingsPanel.js +120 -0
  10. package/dist/admin/components/BindingsPanel.js.map +1 -0
  11. package/dist/admin/components/MenuItemConfigPanel.d.ts +22 -0
  12. package/dist/admin/components/MenuItemConfigPanel.d.ts.map +1 -0
  13. package/dist/admin/components/MenuItemConfigPanel.js +77 -0
  14. package/dist/admin/components/MenuItemConfigPanel.js.map +1 -0
  15. package/dist/admin/components/MenuItemTree.d.ts +13 -0
  16. package/dist/admin/components/MenuItemTree.d.ts.map +1 -0
  17. package/dist/admin/components/MenuItemTree.js +46 -0
  18. package/dist/admin/components/MenuItemTree.js.map +1 -0
  19. package/dist/admin/index.d.ts +31 -0
  20. package/dist/admin/index.d.ts.map +1 -0
  21. package/dist/admin/index.js +47 -0
  22. package/dist/admin/index.js.map +1 -0
  23. package/dist/admin/pages/MegamenuEditor.d.ts +4 -0
  24. package/dist/admin/pages/MegamenuEditor.d.ts.map +1 -0
  25. package/dist/admin/pages/MegamenuEditor.js +151 -0
  26. package/dist/admin/pages/MegamenuEditor.js.map +1 -0
  27. package/dist/admin/pages/MegamenuListPage.d.ts +4 -0
  28. package/dist/admin/pages/MegamenuListPage.d.ts.map +1 -0
  29. package/dist/admin/pages/MegamenuListPage.js +51 -0
  30. package/dist/admin/pages/MegamenuListPage.js.map +1 -0
  31. package/dist/backend/entities/megamenu-binding.entity.d.ts +18 -0
  32. package/dist/backend/entities/megamenu-binding.entity.d.ts.map +1 -0
  33. package/dist/backend/entities/megamenu-binding.entity.js +61 -0
  34. package/dist/backend/entities/megamenu-binding.entity.js.map +1 -0
  35. package/dist/backend/entities/megamenu-item.entity.d.ts +27 -0
  36. package/dist/backend/entities/megamenu-item.entity.d.ts.map +1 -0
  37. package/dist/backend/entities/megamenu-item.entity.js +83 -0
  38. package/dist/backend/entities/megamenu-item.entity.js.map +1 -0
  39. package/dist/backend/entities/megamenu.entity.d.ts +17 -0
  40. package/dist/backend/entities/megamenu.entity.d.ts.map +1 -0
  41. package/dist/backend/entities/megamenu.entity.js +57 -0
  42. package/dist/backend/entities/megamenu.entity.js.map +1 -0
  43. package/dist/backend/index.d.ts +116 -0
  44. package/dist/backend/index.d.ts.map +1 -0
  45. package/dist/backend/index.js +147 -0
  46. package/dist/backend/index.js.map +1 -0
  47. package/dist/backend/routes.admin.d.ts +10 -0
  48. package/dist/backend/routes.admin.d.ts.map +1 -0
  49. package/dist/backend/routes.admin.js +50 -0
  50. package/dist/backend/routes.admin.js.map +1 -0
  51. package/dist/backend/routes.storefront.d.ts +6 -0
  52. package/dist/backend/routes.storefront.d.ts.map +1 -0
  53. package/dist/backend/routes.storefront.js +26 -0
  54. package/dist/backend/routes.storefront.js.map +1 -0
  55. package/dist/backend/services/asset-references.d.ts +4 -0
  56. package/dist/backend/services/asset-references.d.ts.map +1 -0
  57. package/dist/backend/services/asset-references.js +36 -0
  58. package/dist/backend/services/asset-references.js.map +1 -0
  59. package/dist/backend/services/cms-references.d.ts +6 -0
  60. package/dist/backend/services/cms-references.d.ts.map +1 -0
  61. package/dist/backend/services/cms-references.js +39 -0
  62. package/dist/backend/services/cms-references.js.map +1 -0
  63. package/dist/backend/services/cross-module-ports.d.ts +112 -0
  64. package/dist/backend/services/cross-module-ports.d.ts.map +1 -0
  65. package/dist/backend/services/cross-module-ports.js +88 -0
  66. package/dist/backend/services/cross-module-ports.js.map +1 -0
  67. package/dist/backend/services/megamenu-cache.d.ts +36 -0
  68. package/dist/backend/services/megamenu-cache.d.ts.map +1 -0
  69. package/dist/backend/services/megamenu-cache.js +70 -0
  70. package/dist/backend/services/megamenu-cache.js.map +1 -0
  71. package/dist/backend/services/megamenu-item-service.d.ts +39 -0
  72. package/dist/backend/services/megamenu-item-service.d.ts.map +1 -0
  73. package/dist/backend/services/megamenu-item-service.js +151 -0
  74. package/dist/backend/services/megamenu-item-service.js.map +1 -0
  75. package/dist/backend/services/megamenu-language-reference.d.ts +12 -0
  76. package/dist/backend/services/megamenu-language-reference.d.ts.map +1 -0
  77. package/dist/backend/services/megamenu-language-reference.js +24 -0
  78. package/dist/backend/services/megamenu-language-reference.js.map +1 -0
  79. package/dist/backend/services/megamenu-reference-registry.d.ts +24 -0
  80. package/dist/backend/services/megamenu-reference-registry.d.ts.map +1 -0
  81. package/dist/backend/services/megamenu-reference-registry.js +69 -0
  82. package/dist/backend/services/megamenu-reference-registry.js.map +1 -0
  83. package/dist/backend/services/megamenu-service.d.ts +70 -0
  84. package/dist/backend/services/megamenu-service.d.ts.map +1 -0
  85. package/dist/backend/services/megamenu-service.js +299 -0
  86. package/dist/backend/services/megamenu-service.js.map +1 -0
  87. package/dist/backend/services/storefront-resolver.d.ts +46 -0
  88. package/dist/backend/services/storefront-resolver.d.ts.map +1 -0
  89. package/dist/backend/services/storefront-resolver.js +162 -0
  90. package/dist/backend/services/storefront-resolver.js.map +1 -0
  91. package/dist/backend/services/target-validator.d.ts +24 -0
  92. package/dist/backend/services/target-validator.d.ts.map +1 -0
  93. package/dist/backend/services/target-validator.js +105 -0
  94. package/dist/backend/services/target-validator.js.map +1 -0
  95. package/dist/manifest.d.ts +167 -0
  96. package/dist/manifest.d.ts.map +1 -0
  97. package/dist/manifest.js +170 -0
  98. package/dist/manifest.js.map +1 -0
  99. package/dist/migrations/20260505T193836_megamenu_init.d.ts +23 -0
  100. package/dist/migrations/20260505T193836_megamenu_init.d.ts.map +1 -0
  101. package/dist/migrations/20260505T193836_megamenu_init.js +91 -0
  102. package/dist/migrations/20260505T193836_megamenu_init.js.map +1 -0
  103. package/dist/migrations/index.d.ts +27 -0
  104. package/dist/migrations/index.d.ts.map +1 -0
  105. package/dist/migrations/index.js +29 -0
  106. package/dist/migrations/index.js.map +1 -0
  107. package/docs/megamenu/index.md +159 -0
  108. package/i18n/en.json +96 -0
  109. package/i18n/pl.json +96 -0
  110. package/package.json +99 -0
  111. package/tailwind.css +14 -0
@@ -0,0 +1,105 @@
1
+ // Per-kind target validation for Megamenu items — feature 015 / T012.
2
+ //
3
+ // The Zod boundary in `packages/contracts/src/megamenu.ts` enforces the
4
+ // shape rules (URL schemes, button variants, asset kinds). Cross-module
5
+ // existence + scope checks (Category exists, CMS Page / Block exists in
6
+ // scope, Asset matches an expected kind) live here so the unit test can
7
+ // stub them without booting a server.
8
+ import { ERROR_CODES } from '@endora-commerce/contracts';
9
+ import { HttpError } from '@endora-commerce/platform/http';
10
+ const externalUrlRe = /^(?:https?:\/\/|tel:|mailto:)/i;
11
+ /**
12
+ * Validates a single MegamenuItem against the cross-module ports. Throws
13
+ * `HttpError` on the first failure so callers (`MegamenuItemService.setTree`)
14
+ * can re-raise unchanged.
15
+ *
16
+ * The four checks used to arrive as `TargetValidatorDeps`, an interface this
17
+ * module exported for a composition root to build closures against
18
+ * (`specs/110-instance-repository/` T118c). They are their owners' published read
19
+ * ports now, resolved by `backend/index.ts` and declared in this module's
20
+ * manifest.
21
+ *
22
+ * **`_channelIds` is threaded and read by nothing, which is what the roots' SQL
23
+ * did.** `setTree` computes the union of the menu's bound channels and passes it
24
+ * here; neither root's closure ever looked at it, so `MEGAMENU_TARGET_OUT_OF_SCOPE`
25
+ * has only ever meant *the target does not exist*. That is a documented v1
26
+ * narrowing — `megamenu-item-service.ts` says so at the call site, and the scope
27
+ * refusal is US3's — and the parameter is kept so US3 lands inside this function
28
+ * rather than re-plumbing its caller. Naming it `_` is the only change: the
29
+ * ignoring used to happen two files away in a root nobody reads.
30
+ */
31
+ export async function validateTarget(item, _channelIds, ports) {
32
+ // Defence in depth — Zod has already filtered URL schemes at the
33
+ // boundary, but the validator double-checks any free URL on a kind
34
+ // where we expect one.
35
+ if (item.kind === 'external-link') {
36
+ if (!externalUrlRe.test(item.target.url)) {
37
+ throw new HttpError(400, ERROR_CODES.VALIDATION_FAILED, `External link URL "${item.target.url}" must use http://, https://, tel:, or mailto:.`);
38
+ }
39
+ }
40
+ // Optional icon on link kinds: must reference an image asset.
41
+ if (item.kind === 'category-link' ||
42
+ item.kind === 'cms-page-link' ||
43
+ item.kind === 'external-link') {
44
+ const iconAssetId = item.target.iconAssetId;
45
+ if (iconAssetId) {
46
+ const icon = await ports.assets.findById(iconAssetId);
47
+ if (icon?.kind !== 'image') {
48
+ throw new HttpError(400, ERROR_CODES.MEGAMENU_ASSET_KIND_MISMATCH, `Icon asset ${iconAssetId} is not an image.`);
49
+ }
50
+ }
51
+ }
52
+ switch (item.kind) {
53
+ case 'category-link': {
54
+ // No `liveOnly` and no `isActive` test: the roots' `select 1 from
55
+ // categories where id = ?` accepted a deactivated or soft-deleted
56
+ // category, and an admin pointing a menu item at one is not making an
57
+ // error the storefront cannot answer — `resolveCategoryUrl` drops the
58
+ // item at render time.
59
+ const ok = (await ports.categories.findById(item.target.categoryId)) !== null;
60
+ if (!ok) {
61
+ throw new HttpError(400, ERROR_CODES.MEGAMENU_TARGET_OUT_OF_SCOPE, `Category ${item.target.categoryId} is not in scope of the megamenu's bindings.`);
62
+ }
63
+ return;
64
+ }
65
+ case 'cms-page-link': {
66
+ const ok = (await ports.pages.findById(item.target.pageId)) !== null;
67
+ if (!ok) {
68
+ throw new HttpError(400, ERROR_CODES.MEGAMENU_TARGET_OUT_OF_SCOPE, `CMS Page ${item.target.pageId} is not in scope of the megamenu's bindings.`);
69
+ }
70
+ return;
71
+ }
72
+ case 'cms-block-embed': {
73
+ // `findById` and not `findLocalizedById`: existence, `active` included,
74
+ // is the question — an operator may be pointing a menu item at a block
75
+ // they have deactivated while they edit it, and the roots' SQL accepted
76
+ // one. The storefront refuses it later, where a shopper is the one asking.
77
+ const ok = (await ports.blocks.findById(item.target.blockId)) !== null;
78
+ if (!ok) {
79
+ throw new HttpError(400, ERROR_CODES.MEGAMENU_TARGET_OUT_OF_SCOPE, `CMS Block ${item.target.blockId} is not in scope of the megamenu's bindings.`);
80
+ }
81
+ return;
82
+ }
83
+ case 'asset': {
84
+ if ('assetId' in item.target) {
85
+ const asset = await ports.assets.findById(item.target.assetId);
86
+ if (asset?.kind !== item.target.kind) {
87
+ throw new HttpError(400, ERROR_CODES.MEGAMENU_ASSET_KIND_MISMATCH, `Asset ${item.target.assetId} is not a ${item.target.kind}.`);
88
+ }
89
+ }
90
+ else {
91
+ // Free-URL asset items require a server-side import into the
92
+ // Assets Library (T068). The Library does not yet expose
93
+ // `importFromUrl`; until it does, refuse free URLs at the
94
+ // validator with a clear error so admins know to upload first.
95
+ throw new HttpError(400, ERROR_CODES.VALIDATION_FAILED, 'Free-URL asset items are not yet supported. Upload the asset to the Assets Library first and reference it by id.');
96
+ }
97
+ return;
98
+ }
99
+ case 'external-link':
100
+ case 'button':
101
+ // No cross-module check beyond the icon already covered above.
102
+ return;
103
+ }
104
+ }
105
+ //# sourceMappingURL=target-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"target-validator.js","sourceRoot":"","sources":["../../../src/backend/services/target-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Megamenu module — feature 015.
3
+ *
4
+ * Owns the megamenu (multi-column dropdown navigation) configuration.
5
+ * Manifest backfilled alongside feature 020.
6
+ */
7
+ export declare const manifest: {
8
+ id: string;
9
+ name: string;
10
+ version: string;
11
+ dependencies: string[];
12
+ description?: string | undefined;
13
+ acknowledgedDependencies?: {
14
+ moduleId: string;
15
+ port: string;
16
+ reason: string;
17
+ }[] | undefined;
18
+ nonBindingDependencies?: {
19
+ moduleId: string;
20
+ name: string;
21
+ kind: "contributes-to" | "degrades-without" | "refuses-without";
22
+ reason: string;
23
+ whenAbsent?: string | undefined;
24
+ }[] | undefined;
25
+ activation?: {
26
+ settingCode: string;
27
+ default: boolean;
28
+ } | {
29
+ nonDeactivatable: true;
30
+ reason: string;
31
+ } | undefined;
32
+ settings?: {
33
+ moduleCode: string;
34
+ groups: {
35
+ code: string;
36
+ name: string;
37
+ salesChannelCodes?: string[] | undefined;
38
+ isSystemProtected?: boolean | undefined;
39
+ }[];
40
+ settings: {
41
+ code: string;
42
+ name: string;
43
+ valueType: "string" | "number" | "boolean" | "json" | "string_list" | "secret" | "credential_ref";
44
+ defaultValue: unknown;
45
+ description?: string | undefined;
46
+ groupCode?: string | undefined;
47
+ previousDefaultValues?: unknown[] | undefined;
48
+ salesChannelCodes?: string[] | undefined;
49
+ enumOptions?: string[] | undefined;
50
+ configurationType?: string | undefined;
51
+ hidden?: boolean | undefined;
52
+ }[];
53
+ } | undefined;
54
+ i18n?: {
55
+ bundlesDir: string;
56
+ } | undefined;
57
+ docs?: false | {
58
+ dir: string;
59
+ } | undefined;
60
+ demo?: false | {
61
+ summary: string;
62
+ seed: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoSeedResult>;
63
+ reset: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoResetResult>;
64
+ after?: readonly string[] | undefined;
65
+ package?: string | undefined;
66
+ } | undefined;
67
+ actions?: {
68
+ id: string;
69
+ labelKey: string;
70
+ icon: "Plus" | "Sparkles" | "Settings" | "Search" | "Boxes" | "Layers" | "Menu" | "PlusCircle" | "PlusSquare" | "FilePlus" | "FolderPlus" | "Upload" | "FileUp" | "CloudUpload" | "Download" | "FileDown" | "FileText" | "BookOpen" | "Rss" | "Package" | "Tag" | "ShoppingCart" | "Receipt" | "CreditCard" | "Users" | "UserPlus" | "Inbox" | "ListChecks" | "ClipboardList" | "Image" | "Video" | "LayoutDashboard" | "PanelLeft" | "KeyRound" | "ShieldCheck" | "Edit" | "Archive" | "Box" | "Truck" | "CircleDollarSign" | "Activity" | "LineChart" | "Smartphone" | "Webhook" | "Scale" | "PlugZap" | "PercentDiamond" | "Newspaper" | "Languages" | "Eraser" | "Warehouse" | "TrendingDown" | "Bell" | "PackageOpen" | "Building2" | "Store" | "ClipboardCheck";
71
+ targetRoute: string;
72
+ keywords: string[];
73
+ weight: number;
74
+ descriptionKey?: string | undefined;
75
+ requiredPermission?: string | undefined;
76
+ }[] | undefined;
77
+ permissions?: {
78
+ code: string;
79
+ label: string;
80
+ module?: string | undefined;
81
+ description?: string | undefined;
82
+ requires?: string[] | undefined;
83
+ }[] | undefined;
84
+ transactionalEmails?: {
85
+ code: string;
86
+ name: string;
87
+ variables: {
88
+ key: string;
89
+ label: string;
90
+ sampleValue?: string | undefined;
91
+ description?: string | undefined;
92
+ }[];
93
+ description?: string | undefined;
94
+ group?: string | undefined;
95
+ }[] | undefined;
96
+ capabilities?: string[] | undefined;
97
+ exclusiveCapabilities?: {
98
+ key: string;
99
+ errorCode: string;
100
+ }[] | undefined;
101
+ errorCodes?: {
102
+ code: string;
103
+ tokens?: string[] | undefined;
104
+ }[] | undefined;
105
+ blocks?: {
106
+ name: string;
107
+ labelKey: string;
108
+ category: string;
109
+ contexts: ("cms" | "invoice" | "email" | "newsletter")[];
110
+ fields: Record<string, {
111
+ type: "number" | "object" | "array" | "text" | "textarea" | "select" | "radio" | "external" | "uuid" | "richtext";
112
+ label?: string | undefined;
113
+ required?: boolean | undefined;
114
+ options?: {
115
+ label: string;
116
+ value: string | number;
117
+ }[] | undefined;
118
+ refKind?: string | undefined;
119
+ }>;
120
+ descriptionKey?: string | undefined;
121
+ defaultProps?: Record<string, unknown> | undefined;
122
+ responsiveFields?: string[] | undefined;
123
+ previewIcon?: string | undefined;
124
+ weight?: number | undefined;
125
+ }[] | undefined;
126
+ blockCategories?: {
127
+ key: string;
128
+ titleKey: string;
129
+ contexts: ("cms" | "invoice" | "email" | "newsletter")[];
130
+ weight?: number | undefined;
131
+ visible?: boolean | undefined;
132
+ }[] | undefined;
133
+ env?: {
134
+ name: string;
135
+ describes: {
136
+ en: string;
137
+ pl: string;
138
+ };
139
+ requirement: {
140
+ kind: "required";
141
+ } | {
142
+ kind: "requiredWhen";
143
+ input: string;
144
+ equals: string;
145
+ } | {
146
+ kind: "optional";
147
+ without: {
148
+ en: string;
149
+ pl: string;
150
+ };
151
+ };
152
+ secret: boolean;
153
+ generable: boolean;
154
+ owner: {
155
+ kind: "platform";
156
+ } | {
157
+ kind: "application";
158
+ application: "admin" | "backend" | "storefront";
159
+ } | {
160
+ kind: "module";
161
+ moduleId: string;
162
+ };
163
+ consumers: ("admin" | "backend" | "storefront")[];
164
+ addressOf: "admin" | "backend" | "storefront" | null;
165
+ }[] | undefined;
166
+ };
167
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkKnB,CAAC"}
@@ -0,0 +1,170 @@
1
+ import { defineModuleManifest } from '@endora-commerce/contracts';
2
+ /**
3
+ * Megamenu module — feature 015.
4
+ *
5
+ * Owns the megamenu (multi-column dropdown navigation) configuration.
6
+ * Manifest backfilled alongside feature 020.
7
+ */
8
+ export const manifest = defineModuleManifest({
9
+ id: 'megamenu',
10
+ name: 'Megamenu',
11
+ description: 'Multi-column dropdown navigation builder.',
12
+ version: '1.0.0',
13
+ // `auth` owns the `requireAdmin` port the admin routes are gated by — feature
14
+ // 072 made it required rather than defaulting to a permissive no-op.
15
+ // `dictionaries` owns the validator the menu service checks languages with.
16
+ // `assets_library` owns the reference registry this module contributes its
17
+ // asset-and-icon scan to (T143a); `cms` owns the one it contributes the
18
+ // page/block scan to. Both edges existed as composition-root
19
+ // cross-registrations, which is to say nowhere an operator could see them.
20
+ // `languages` owns `languageReferenceRegistry`, the registry this module
21
+ // contributes its "which languages do bindings carry" descriptor to (feature
22
+ // 077, D-87). `languages` used to ask the question itself, with a
23
+ // `count(*) from "megamenu_bindings"` naming this module's table.
24
+ //
25
+ // `catalog` is new with `specs/110-instance-repository/` T118c, and it is the
26
+ // one edge this module did not already have. A menu item may target a
27
+ // category, so validating it and resolving its storefront URL are reads of
28
+ // `catalog`'s table — issued by a composition root in raw SQL until T118c, in
29
+ // a file that is nobody's declared dependency, so the edge existed nowhere an
30
+ // operator or a check could see it. It is `catalogCategoryReadPort` now, and
31
+ // the `demo` block below records what that changes about its own argument.
32
+ //
33
+ // The bind costs no operator a control, and that is derived rather than
34
+ // waived: `catalog` declares itself non-deactivatable, so this is not an edge
35
+ // into a switchable module and it owes no `nonBindingDependencies` entry. The
36
+ // other two owners T118c's ports belong to — `cms` and `assets_library` — were
37
+ // both already declared here, for the reference registries above, so the drain
38
+ // adds one line to this array and no judgement beyond it.
39
+ dependencies: [
40
+ 'assets_library',
41
+ 'catalog',
42
+ 'cms',
43
+ 'languages',
44
+ 'sales_channels',
45
+ 'auth',
46
+ 'dictionaries',
47
+ ],
48
+ settings: {
49
+ moduleCode: 'megamenu',
50
+ groups: [{ code: 'megamenu', name: 'Megamenu' }],
51
+ settings: [
52
+ {
53
+ // Feature 073 — the operator's activation control. Platform-wide.
54
+ code: 'megamenu.enabled',
55
+ name: 'Megamenu enabled',
56
+ description: 'Switches the megamenu admin screens, their API and the storefront navigation they drive on or off. Nothing is dropped: menus, items and channel bindings stay in the database and reappear exactly as configured when you switch it back on.',
57
+ groupCode: 'megamenu',
58
+ valueType: 'boolean',
59
+ defaultValue: true,
60
+ },
61
+ ],
62
+ },
63
+ /**
64
+ * The ten error codes this module owns — feature 090, Phase 3.
65
+ *
66
+ * **This list is the incumbent prefix chain's answer, copied from
67
+ * `backend/test/fixtures/error-code-routing/chain-answers.ts`, not a
68
+ * judgement.** The migration is answer-preserving over all 289 codes with no
69
+ * exception list (`specs/090-module-owned-error-codes/contracts/error-code-declaration.md`
70
+ * §6.2), so nothing here was added or dropped because it looked misplaced;
71
+ * re-routing is §6.5's and out of scope.
72
+ *
73
+ * **Two codes a reader would attribute elsewhere, in both directions.**
74
+ * `MEGAMENU_LANGUAGE_NOT_IN_CHANNEL_SCOPE` reads as `sales_channels`' — it
75
+ * is raised while checking a language against a Sales Channel's configured
76
+ * language set — and is ours: the chain routes it on the `MEGAMENU_` prefix
77
+ * and `megamenu-service.ts` is what raises it. Going the other way, the three
78
+ * codes this module raises and does **not** own are `NOT_FOUND`,
79
+ * `VALIDATION_FAILED` and `VERSION_CONFLICT`, all the platform's; the first
80
+ * of those is raised for a *Sales Channel* that does not exist, so a reader
81
+ * tracing that refusal would look in `sales_channels` and find it in `core`.
82
+ *
83
+ * **Two of the ten are raised by nothing, and neither is a missing rule.**
84
+ * Both spellings were searched over `packages` and `backend/src` —
85
+ * `ERROR_CODES.<CODE>` and the bare quoted literal — because a module need
86
+ * not spell its codes the first way (runbook step 2, T12).
87
+ * `MEGAMENU_DEPTH_EXCEEDED` is built, enforced and covered by
88
+ * `test/contract/megamenu/admin-items-depth.contract.test.ts`, and it reaches
89
+ * the client — as a `meta.warnings` entry on a **200**, because FR-011 makes
90
+ * depth a non-blocking soft warning. It is never thrown, so the envelope can
91
+ * never render the `errors.MEGAMENU_DEPTH_EXCEEDED` sentence written for it
92
+ * in both languages. `MEGAMENU_REFERENCED` is built too: this module
93
+ * contributes reference descriptors to `assets_library`'s and `cms`' delete
94
+ * scans (`asset-references.ts`, `cms-references.ts`), the delete *is* refused
95
+ * and the holder list *does* name the menu — but the refusal is answered
96
+ * under the deleting module's code, `ASSET_REFERENCED` or `CMS_REFERENCED`,
97
+ * so this one never travels either.
98
+ * `specs/015-megamenu/contracts/megamenu-reference-scan.contract.md`
99
+ * still specifies `409 MEGAMENU_REFERENCED`; the contract and the
100
+ * implementation disagree, and that is a product finding rather than this
101
+ * merge request's to repair.
102
+ *
103
+ * **No `tokens`, derived rather than assumed.** The envelope's `refusalToken`
104
+ * (`packages/platform/src/http/error-envelope.ts`) reads exactly one member
105
+ * of `details` — `code`, and only when `details` is an object. Every raise of
106
+ * one of these codes was enumerated over `packages` and `backend/src` rather
107
+ * than over this package alone (runbook §5): all sixteen pass three
108
+ * arguments to `HttpError` and no fourth at all, so none can carry a token.
109
+ * The bundle agrees from the other direction — ten `errors.<CODE>` keys and
110
+ * not one `errors.<CODE>.<token>`.
111
+ */
112
+ errorCodes: [
113
+ { code: 'MEGAMENU_ASSET_KIND_MISMATCH' },
114
+ { code: 'MEGAMENU_BINDING_ALREADY_EXISTS' },
115
+ { code: 'MEGAMENU_BINDING_NOT_FOUND' },
116
+ { code: 'MEGAMENU_DEPTH_EXCEEDED' },
117
+ { code: 'MEGAMENU_EMPTY_TREE' },
118
+ { code: 'MEGAMENU_HAS_ACTIVE_BINDINGS' },
119
+ { code: 'MEGAMENU_LANGUAGE_NOT_IN_CHANNEL_SCOPE' },
120
+ { code: 'MEGAMENU_NOT_FOUND' },
121
+ { code: 'MEGAMENU_REFERENCED' },
122
+ { code: 'MEGAMENU_TARGET_OUT_OF_SCOPE' },
123
+ ],
124
+ i18n: { bundlesDir: 'i18n' },
125
+ docs: { dir: 'docs' },
126
+ permissions: [
127
+ { code: 'megamenu.read', label: 'View megamenu configuration' },
128
+ { code: 'megamenu.write', label: 'Edit megamenu configuration' },
129
+ ],
130
+ actions: [
131
+ {
132
+ id: 'edit-megamenu',
133
+ labelKey: 'actions.editMegamenu.label',
134
+ descriptionKey: 'actions.editMegamenu.description',
135
+ icon: 'Menu',
136
+ targetRoute: '/megamenu',
137
+ requiredPermission: 'megamenu.write',
138
+ keywords: ['menu', 'edit', 'navigation', 'edytuj', 'nawigacja'],
139
+ weight: 240,
140
+ },
141
+ ],
142
+ // Feature 073 — the operator's activation control. Platform-wide. A platform
143
+ // without a megamenu is a smaller platform, not a broken one: the menus,
144
+ // their items and their channel bindings stay in the database and reappear
145
+ // exactly as configured when it is switched back on.
146
+ /**
147
+ * Nothing to demonstrate of its own (feature 113, T225 — contract §1.2).
148
+ *
149
+ * The demo shop does have a megamenu, and it is not this module's demo data:
150
+ * it mirrors `catalog`'s demo category tree and binds to the demo sales
151
+ * channels, so it is three modules' rows in one step and belongs to whoever
152
+ * owns the instance (§5.1). It is step 1 of `backend/src/seeds/
153
+ * demo-composition.ts`.
154
+ *
155
+ * **This block used to add *"and this module does not declare `catalog`"* as
156
+ * §2.3's measured case.** It declares it since
157
+ * `specs/110-instance-repository/` T118c, for a reason that has nothing to do
158
+ * with demo data: a menu item may target a category, so validating one is a
159
+ * read of `catalogCategoryReadPort`. The clause is retired rather than
160
+ * updated because it was the weaker half of the argument all along — the rule
161
+ * is that `demo` may not become a way of *acquiring* a dependency, and it
162
+ * holds identically now that the dependency is here on its own merits.
163
+ *
164
+ * `false` rather than absent, because the two are different states: this is
165
+ * a decision that the module owes nothing, not a module nobody has looked at.
166
+ */
167
+ demo: false,
168
+ activation: { settingCode: 'megamenu.enabled', default: true },
169
+ });
170
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC;IAC3C,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,2CAA2C;IACxD,OAAO,EAAE,OAAO;IAChB,8EAA8E;IAC9E,qEAAqE;IACrE,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,6DAA6D;IAC7D,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,kEAAkE;IAClE,kEAAkE;IAClE,EAAE;IACF,8EAA8E;IAC9E,sEAAsE;IACtE,2EAA2E;IAC3E,8EAA8E;IAC9E,8EAA8E;IAC9E,6EAA6E;IAC7E,2EAA2E;IAC3E,EAAE;IACF,wEAAwE;IACxE,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,+EAA+E;IAC/E,0DAA0D;IAC1D,YAAY,EAAE;QACZ,gBAAgB;QAChB,SAAS;QACT,KAAK;QACL,WAAW;QACX,gBAAgB;QAChB,MAAM;QACN,cAAc;KACf;IACD,QAAQ,EAAE;QACR,UAAU,EAAE,UAAU;QACtB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAChD,QAAQ,EAAE;YACR;gBACE,kEAAkE;gBAClE,IAAI,EAAE,kBAAkB;gBACxB,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EACT,8OAA8O;gBAChP,SAAS,EAAE,UAAU;gBACrB,SAAS,EAAE,SAAS;gBACpB,YAAY,EAAE,IAAI;aACnB;SACF;KACF;IACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACH,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,8BAA8B,EAAE;QACxC,EAAE,IAAI,EAAE,iCAAiC,EAAE;QAC3C,EAAE,IAAI,EAAE,4BAA4B,EAAE;QACtC,EAAE,IAAI,EAAE,yBAAyB,EAAE;QACnC,EAAE,IAAI,EAAE,qBAAqB,EAAE;QAC/B,EAAE,IAAI,EAAE,8BAA8B,EAAE;QACxC,EAAE,IAAI,EAAE,wCAAwC,EAAE;QAClD,EAAE,IAAI,EAAE,oBAAoB,EAAE;QAC9B,EAAE,IAAI,EAAE,qBAAqB,EAAE;QAC/B,EAAE,IAAI,EAAE,8BAA8B,EAAE;KACzC;IACD,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;IAC5B,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;IACrB,WAAW,EAAE;QACX,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,6BAA6B,EAAE;QAC/D,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,6BAA6B,EAAE;KACjE;IACD,OAAO,EAAE;QACP;YACE,EAAE,EAAE,eAAe;YACnB,QAAQ,EAAE,4BAA4B;YACtC,cAAc,EAAE,kCAAkC;YAClD,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,WAAW;YACxB,kBAAkB,EAAE,gBAAgB;YACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC;YAC/D,MAAM,EAAE,GAAG;SACZ;KACF;IACD,6EAA6E;IAC7E,yEAAyE;IACzE,2EAA2E;IAC3E,qDAAqD;IACrD;;;;;;;;;;;;;;;;;;;;QAoBI;IACJ,IAAI,EAAE,KAAK;IACX,UAAU,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,IAAI,EAAE;CAC/D,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Megamenu module — feature 015 / data-model.md.
4
+ *
5
+ * Schema changes (one atomic migration):
6
+ * - new tables: `megamenus`, `megamenu_items`, `megamenu_bindings`.
7
+ * - GIN index on `megamenu_items.target` (jsonb_path_ops) so the
8
+ * cross-module reference scan stays fast.
9
+ * - btree index on `megamenu_items(megamenu_id, parent_id, position)`
10
+ * drives the per-tree fetch.
11
+ * - **partial unique index** on
12
+ * `megamenu_bindings(sales_channel_id, language) WHERE active = true`
13
+ * enforces "exactly one active megamenu per (channel, language)"
14
+ * (FR-008 + research § R3) at the DB level.
15
+ *
16
+ * No seed rows; no data backfill — first-time admins create the first
17
+ * configuration through the admin UI.
18
+ */
19
+ export declare class Migration20260505T193836MegamenuInit extends Migration {
20
+ up(): Promise<void>;
21
+ down(): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=20260505T193836_megamenu_init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260505T193836_megamenu_init.d.ts","sourceRoot":"","sources":["../../src/migrations/20260505T193836_megamenu_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oCAAqC,SAAQ,SAAS;IAClD,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IA4EnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAKrC"}
@@ -0,0 +1,91 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Megamenu module — feature 015 / data-model.md.
4
+ *
5
+ * Schema changes (one atomic migration):
6
+ * - new tables: `megamenus`, `megamenu_items`, `megamenu_bindings`.
7
+ * - GIN index on `megamenu_items.target` (jsonb_path_ops) so the
8
+ * cross-module reference scan stays fast.
9
+ * - btree index on `megamenu_items(megamenu_id, parent_id, position)`
10
+ * drives the per-tree fetch.
11
+ * - **partial unique index** on
12
+ * `megamenu_bindings(sales_channel_id, language) WHERE active = true`
13
+ * enforces "exactly one active megamenu per (channel, language)"
14
+ * (FR-008 + research § R3) at the DB level.
15
+ *
16
+ * No seed rows; no data backfill — first-time admins create the first
17
+ * configuration through the admin UI.
18
+ */
19
+ export class Migration20260505T193836MegamenuInit extends Migration {
20
+ async up() {
21
+ // ────────────────────────────────────────────────────────────────────
22
+ // 1) megamenus
23
+ // ────────────────────────────────────────────────────────────────────
24
+ this.addSql(`
25
+ create table "megamenus" (
26
+ "id" uuid not null,
27
+ "name" varchar(200) not null,
28
+ "description" text null,
29
+ "version" int not null default 1,
30
+ "created_at" timestamptz not null,
31
+ "updated_at" timestamptz not null,
32
+ constraint "megamenus_pkey" primary key ("id")
33
+ );
34
+ `);
35
+ // ────────────────────────────────────────────────────────────────────
36
+ // 2) megamenu_items — adjacency-list tree
37
+ // ────────────────────────────────────────────────────────────────────
38
+ this.addSql(`
39
+ create table "megamenu_items" (
40
+ "id" uuid not null,
41
+ "megamenu_id" uuid not null,
42
+ "parent_id" uuid null,
43
+ "position" int not null default 0,
44
+ "kind" varchar(32) not null,
45
+ "labels" jsonb not null default '{}'::jsonb,
46
+ "descriptions" jsonb null,
47
+ "target" jsonb not null default '{}'::jsonb,
48
+ "created_at" timestamptz not null,
49
+ "updated_at" timestamptz not null,
50
+ constraint "megamenu_items_pkey" primary key ("id"),
51
+ constraint "megamenu_items_megamenu_fk" foreign key ("megamenu_id")
52
+ references "megamenus" ("id") on delete cascade,
53
+ constraint "megamenu_items_parent_fk" foreign key ("parent_id")
54
+ references "megamenu_items" ("id") on delete cascade
55
+ );
56
+ `);
57
+ this.addSql('create index "idx_megamenu_items_tree" on "megamenu_items" ("megamenu_id", "parent_id", "position");');
58
+ this.addSql('create index "idx_megamenu_items_target_refs" on "megamenu_items" using gin ("target" jsonb_path_ops);');
59
+ // ────────────────────────────────────────────────────────────────────
60
+ // 3) megamenu_bindings
61
+ // ────────────────────────────────────────────────────────────────────
62
+ this.addSql(`
63
+ create table "megamenu_bindings" (
64
+ "megamenu_id" uuid not null,
65
+ "sales_channel_id" uuid not null,
66
+ "language" varchar(8) not null,
67
+ "active" boolean not null default false,
68
+ "version" int not null default 1,
69
+ "created_at" timestamptz not null,
70
+ "updated_at" timestamptz not null,
71
+ constraint "megamenu_bindings_pkey"
72
+ primary key ("megamenu_id", "sales_channel_id", "language"),
73
+ constraint "megamenu_bindings_megamenu_fk" foreign key ("megamenu_id")
74
+ references "megamenus" ("id") on delete cascade,
75
+ constraint "megamenu_bindings_channel_fk" foreign key ("sales_channel_id")
76
+ references "sales_channels" ("id") on delete cascade
77
+ );
78
+ `);
79
+ // Partial unique index (FR-008 / R3) — exactly one active megamenu
80
+ // per (sales_channel_id, language).
81
+ this.addSql('create unique index "idx_megamenu_bindings_active_uniq" on "megamenu_bindings" ("sales_channel_id", "language") where "active" = true;');
82
+ // Lookup index for the storefront resolver.
83
+ this.addSql('create index "idx_megamenu_bindings_channel_lang" on "megamenu_bindings" ("sales_channel_id", "language");');
84
+ }
85
+ async down() {
86
+ this.addSql('drop table if exists "megamenu_bindings" cascade;');
87
+ this.addSql('drop table if exists "megamenu_items" cascade;');
88
+ this.addSql('drop table if exists "megamenus" cascade;');
89
+ }
90
+ }
91
+ //# sourceMappingURL=20260505T193836_megamenu_init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260505T193836_megamenu_init.js","sourceRoot":"","sources":["../../src/migrations/20260505T193836_megamenu_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,oCAAqC,SAAQ,SAAS;IACxD,KAAK,CAAC,EAAE;QACf,uEAAuE;QACvE,eAAe;QACf,uEAAuE;QACvE,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;KAUX,CAAC,CAAC;QAEH,uEAAuE;QACvE,0CAA0C;QAC1C,uEAAuE;QACvE,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;KAkBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,sGAAsG,CACvG,CAAC;QACF,IAAI,CAAC,MAAM,CACT,wGAAwG,CACzG,CAAC;QAEF,uEAAuE;QACvE,uBAAuB;QACvB,uEAAuE;QACvE,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;KAgBX,CAAC,CAAC;QACH,mEAAmE;QACnE,oCAAoC;QACpC,IAAI,CAAC,MAAM,CACT,wIAAwI,CACzI,CAAC;QACF,4CAA4C;QAC5C,IAAI,CAAC,MAAM,CACT,4GAA4G,CAC7G,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,mDAAmD,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,gDAAgD,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC;IAC3D,CAAC;CACF"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which orders **this module's own** migrations
10
+ * and nothing else (feature 081). Where the block sits relative to every other
11
+ * module's is decided by the manifest `dependencies` graph.
12
+ *
13
+ * The **named** exports stay, and the asymmetry with `./backend` — which
14
+ * publishes an array and no entity class by name (D-168) — is deliberate.
15
+ * `db/migrations-registry.generated.ts` imports each class by name from this
16
+ * specifier, and a migration class name is contract in a way an entity class
17
+ * name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom
22
+ * is a query against a table nobody created.
23
+ */
24
+ import { Migration20260505T193836MegamenuInit } from './20260505T193836_megamenu_init.js';
25
+ export declare const migrations: (typeof Migration20260505T193836MegamenuInit)[];
26
+ export { Migration20260505T193836MegamenuInit, };
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,oCAAoC,EAAE,MAAM,oCAAoC,CAAC;AAE1F,eAAO,MAAM,UAAU,iDAEtB,CAAC;AAEF,OAAO,EACL,oCAAoC,GACrC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which orders **this module's own** migrations
10
+ * and nothing else (feature 081). Where the block sits relative to every other
11
+ * module's is decided by the manifest `dependencies` graph.
12
+ *
13
+ * The **named** exports stay, and the asymmetry with `./backend` — which
14
+ * publishes an array and no entity class by name (D-168) — is deliberate.
15
+ * `db/migrations-registry.generated.ts` imports each class by name from this
16
+ * specifier, and a migration class name is contract in a way an entity class
17
+ * name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom
22
+ * is a query against a table nobody created.
23
+ */
24
+ import { Migration20260505T193836MegamenuInit } from './20260505T193836_megamenu_init.js';
25
+ export const migrations = [
26
+ Migration20260505T193836MegamenuInit,
27
+ ];
28
+ export { Migration20260505T193836MegamenuInit, };
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,oCAAoC,EAAE,MAAM,oCAAoC,CAAC;AAE1F,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,oCAAoC;CACrC,CAAC;AAEF,OAAO,EACL,oCAAoC,GACrC,CAAC"}