@endora-commerce/mod-admin-actions 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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -0
  3. package/dist/backend/entities/module-action.entity.d.ts +30 -0
  4. package/dist/backend/entities/module-action.entity.d.ts.map +1 -0
  5. package/dist/backend/entities/module-action.entity.js +100 -0
  6. package/dist/backend/entities/module-action.entity.js.map +1 -0
  7. package/dist/backend/index.d.ts +85 -0
  8. package/dist/backend/index.d.ts.map +1 -0
  9. package/dist/backend/index.js +57 -0
  10. package/dist/backend/index.js.map +1 -0
  11. package/dist/backend/plugin.d.ts +110 -0
  12. package/dist/backend/plugin.d.ts.map +1 -0
  13. package/dist/backend/plugin.js +77 -0
  14. package/dist/backend/plugin.js.map +1 -0
  15. package/dist/backend/routes.admin.d.ts +19 -0
  16. package/dist/backend/routes.admin.d.ts.map +1 -0
  17. package/dist/backend/routes.admin.js +32 -0
  18. package/dist/backend/routes.admin.js.map +1 -0
  19. package/dist/backend/services/admin-actions-reconciler.d.ts +49 -0
  20. package/dist/backend/services/admin-actions-reconciler.d.ts.map +1 -0
  21. package/dist/backend/services/admin-actions-reconciler.js +78 -0
  22. package/dist/backend/services/admin-actions-reconciler.js.map +1 -0
  23. package/dist/backend/services/admin-actions-service.d.ts +136 -0
  24. package/dist/backend/services/admin-actions-service.d.ts.map +1 -0
  25. package/dist/backend/services/admin-actions-service.js +168 -0
  26. package/dist/backend/services/admin-actions-service.js.map +1 -0
  27. package/dist/manifest.d.ts +196 -0
  28. package/dist/manifest.d.ts.map +1 -0
  29. package/dist/manifest.js +85 -0
  30. package/dist/manifest.js.map +1 -0
  31. package/dist/migrations/20260507T142354_admin_actions_init.d.ts +31 -0
  32. package/dist/migrations/20260507T142354_admin_actions_init.d.ts.map +1 -0
  33. package/dist/migrations/20260507T142354_admin_actions_init.js +55 -0
  34. package/dist/migrations/20260507T142354_admin_actions_init.js.map +1 -0
  35. package/dist/migrations/index.d.ts +27 -0
  36. package/dist/migrations/index.d.ts.map +1 -0
  37. package/dist/migrations/index.js +29 -0
  38. package/dist/migrations/index.js.map +1 -0
  39. package/docs/admin-actions.md +164 -0
  40. package/i18n/en.json +5 -0
  41. package/i18n/pl.json +5 -0
  42. package/package.json +68 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ <!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
2
+
3
+ # @endora-commerce/mod-admin-actions
4
+
5
+ Module-contributed action registry that surfaces declared actions in the admin command palette.
6
+
7
+ ## What this is
8
+
9
+ An **Endora Commerce module package**. Its module id is `admin_actions` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
10
+
11
+ A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
12
+
13
+ ## Entry points
14
+
15
+ | Import | Contents |
16
+ | --- | --- |
17
+ | `@endora-commerce/mod-admin-actions` | the module manifest — its id, version, dependencies, settings and activation |
18
+ | `@endora-commerce/mod-admin-actions/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
19
+ | `@endora-commerce/mod-admin-actions/migrations` | the module’s own schema migrations, in the order the platform runs them |
20
+
21
+ ## Depends on
22
+
23
+ Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
24
+
25
+ **Endora packages**
26
+
27
+ - `@endora-commerce/contracts`
28
+ - `@endora-commerce/platform`
29
+
30
+ **Third-party**
31
+
32
+ - `@mikro-orm/core` ^6
33
+ - `@mikro-orm/migrations` ^6
34
+ - `@mikro-orm/postgresql` ^6
35
+ - `fastify` ^5
36
+
37
+ ## What the tarball carries
38
+
39
+ - `dist/` — the compiled JavaScript and its type declarations
40
+ - `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
41
+ - `docs/` — the package’s own pages in the Endora Commerce documentation site
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ pnpm add @endora-commerce/mod-admin-actions
47
+ ```
48
+
49
+ ## Licence
50
+
51
+ MIT — the text is in `LICENSE`, beside this file.
@@ -0,0 +1,30 @@
1
+ import { OptionalProps } from '@mikro-orm/core';
2
+ import type { KnownIconName } from '@endora-commerce/contracts';
3
+ /**
4
+ * Module Action — feature 020 / data-model.md.
5
+ *
6
+ * One row per `(module_id, action_id)`. Written by the lifecycle install
7
+ * hook from each module's manifest `actions` array; never edited by
8
+ * hand. The `version` column defaults to `nextval(module_actions_version_seq)`
9
+ * so every UPSERT bumps the vector — useful for cache diagnostics.
10
+ *
11
+ * No FK on `module_id` for the same reason as `translation_bundles`
12
+ * (feature 019): modules are filesystem-driven and lifecycle ordering
13
+ * already owns cleanup on hard-uninstall.
14
+ */
15
+ export declare class ModuleAction {
16
+ [OptionalProps]?: 'descriptionKey' | 'requiredPermission' | 'keywords' | 'weight' | 'version' | 'installedAt' | 'updatedAt';
17
+ moduleId: string;
18
+ actionId: string;
19
+ labelKey: string;
20
+ descriptionKey: string | null;
21
+ icon: KnownIconName;
22
+ targetRoute: string;
23
+ requiredPermission: string | null;
24
+ keywords: string[];
25
+ weight: number;
26
+ version: number;
27
+ installedAt: Date;
28
+ updatedAt: Date;
29
+ }
30
+ //# sourceMappingURL=module-action.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-action.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/module-action.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAErF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,qBAMa,YAAY;IACvB,CAAC,aAAa,CAAC,CAAC,EACZ,gBAAgB,GAChB,oBAAoB,GACpB,UAAU,GACV,QAAQ,GACR,SAAS,GACT,aAAa,GACb,WAAW,CAAC;IAGhB,QAAQ,EAAG,MAAM,CAAC;IAGlB,QAAQ,EAAG,MAAM,CAAC;IAGlB,QAAQ,EAAG,MAAM,CAAC;IAGlB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGrC,IAAI,EAAG,aAAa,CAAC;IAGrB,WAAW,EAAG,MAAM,CAAC;IAGrB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGzC,QAAQ,EAAE,MAAM,EAAE,CAAM;IAGxB,MAAM,EAAE,MAAM,CAAO;IAOrB,OAAO,EAAG,MAAM,CAAC;IAGjB,WAAW,EAAE,IAAI,CAAc;IAG/B,SAAS,EAAE,IAAI,CAAc;CAC9B"}
@@ -0,0 +1,100 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, Index, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core';
11
+ import { GlobalEntity } from '@endora-commerce/platform/tenancy';
12
+ /**
13
+ * Module Action — feature 020 / data-model.md.
14
+ *
15
+ * One row per `(module_id, action_id)`. Written by the lifecycle install
16
+ * hook from each module's manifest `actions` array; never edited by
17
+ * hand. The `version` column defaults to `nextval(module_actions_version_seq)`
18
+ * so every UPSERT bumps the vector — useful for cache diagnostics.
19
+ *
20
+ * No FK on `module_id` for the same reason as `translation_bundles`
21
+ * (feature 019): modules are filesystem-driven and lifecycle ordering
22
+ * already owns cleanup on hard-uninstall.
23
+ */
24
+ let ModuleAction = class ModuleAction {
25
+ [OptionalProps];
26
+ moduleId;
27
+ actionId;
28
+ labelKey;
29
+ descriptionKey = null;
30
+ icon;
31
+ targetRoute;
32
+ requiredPermission = null;
33
+ keywords = [];
34
+ weight = 100;
35
+ version;
36
+ installedAt = new Date();
37
+ updatedAt = new Date();
38
+ };
39
+ __decorate([
40
+ PrimaryKey({ type: 'string', length: 64 }),
41
+ __metadata("design:type", String)
42
+ ], ModuleAction.prototype, "moduleId", void 0);
43
+ __decorate([
44
+ PrimaryKey({ type: 'string', length: 64 }),
45
+ __metadata("design:type", String)
46
+ ], ModuleAction.prototype, "actionId", void 0);
47
+ __decorate([
48
+ Property({ type: 'string', length: 255 }),
49
+ __metadata("design:type", String)
50
+ ], ModuleAction.prototype, "labelKey", void 0);
51
+ __decorate([
52
+ Property({ type: 'string', length: 255, nullable: true }),
53
+ __metadata("design:type", Object)
54
+ ], ModuleAction.prototype, "descriptionKey", void 0);
55
+ __decorate([
56
+ Property({ type: 'string', length: 64 }),
57
+ __metadata("design:type", String)
58
+ ], ModuleAction.prototype, "icon", void 0);
59
+ __decorate([
60
+ Property({ type: 'string', length: 255 }),
61
+ __metadata("design:type", String)
62
+ ], ModuleAction.prototype, "targetRoute", void 0);
63
+ __decorate([
64
+ Property({ type: 'string', length: 64, nullable: true }),
65
+ __metadata("design:type", Object)
66
+ ], ModuleAction.prototype, "requiredPermission", void 0);
67
+ __decorate([
68
+ Property({ type: 'json', columnType: 'jsonb' }),
69
+ __metadata("design:type", Array)
70
+ ], ModuleAction.prototype, "keywords", void 0);
71
+ __decorate([
72
+ Property({ type: 'integer' }),
73
+ __metadata("design:type", Number)
74
+ ], ModuleAction.prototype, "weight", void 0);
75
+ __decorate([
76
+ Property({
77
+ type: 'bigint',
78
+ columnType: 'bigint',
79
+ defaultRaw: "nextval('module_actions_version_seq')",
80
+ }),
81
+ __metadata("design:type", Number)
82
+ ], ModuleAction.prototype, "version", void 0);
83
+ __decorate([
84
+ Property({ type: 'Date' }),
85
+ __metadata("design:type", Date)
86
+ ], ModuleAction.prototype, "installedAt", void 0);
87
+ __decorate([
88
+ Property({ type: 'Date', onUpdate: () => new Date() }),
89
+ __metadata("design:type", Date)
90
+ ], ModuleAction.prototype, "updatedAt", void 0);
91
+ ModuleAction = __decorate([
92
+ GlobalEntity(),
93
+ Entity({ tableName: 'module_actions' }),
94
+ Index({
95
+ properties: ['weight', 'labelKey'],
96
+ name: 'idx_module_actions_weight_label_key',
97
+ })
98
+ ], ModuleAction);
99
+ export { ModuleAction };
100
+ //# sourceMappingURL=module-action.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-action.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/module-action.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAGjE;;;;;;;;;;;GAWG;AAOI,IAAM,YAAY,GAAlB,MAAM,YAAY;IACvB,CAAC,aAAa,CAAC,CAOC;IAGhB,QAAQ,CAAU;IAGlB,QAAQ,CAAU;IAGlB,QAAQ,CAAU;IAGlB,cAAc,GAAkB,IAAI,CAAC;IAGrC,IAAI,CAAiB;IAGrB,WAAW,CAAU;IAGrB,kBAAkB,GAAkB,IAAI,CAAC;IAGzC,QAAQ,GAAa,EAAE,CAAC;IAGxB,MAAM,GAAW,GAAG,CAAC;IAOrB,OAAO,CAAU;IAGjB,WAAW,GAAS,IAAI,IAAI,EAAE,CAAC;IAG/B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AAtCC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;8CACzB;AAGlB;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;8CACzB;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;8CACxB;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACrB;AAGrC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;0CACpB;AAGrB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;iDACrB;AAGrB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;wDAChB;AAGzC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;;8CACxB;AAGxB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;4CACT;AAOrB;IALC,QAAQ,CAAC;QACR,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,QAAQ;QACpB,UAAU,EAAE,uCAAuC;KACpD,CAAC;;6CACe;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;8BACd,IAAI;iDAAc;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAC5C,IAAI;+CAAc;AAhDlB,YAAY;IANxB,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;IACvC,KAAK,CAAC;QACL,UAAU,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;QAClC,IAAI,EAAE,qCAAqC;KAC5C,CAAC;GACW,YAAY,CAiDxB"}
@@ -0,0 +1,85 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { FastifyRequest } from 'fastify';
3
+ import type { AdminI18nTranslatePort, PermissionReadPort } from '@endora-commerce/contracts';
4
+ import type { ModuleContext } from '@endora-commerce/platform/kernel';
5
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
6
+ import type { ModulePresenceProbe } from './services/admin-actions-service.js';
7
+ import { ModuleAction } from './entities/module-action.entity.js';
8
+ import { type AdminActionsManifestRegistryView, type AdminActionsModuleHandle } from './plugin.js';
9
+ /**
10
+ * `admin_actions` — the second module whose reconcile must not move (feature
11
+ * 072, wave 2, T099).
12
+ *
13
+ * This is `_i18n`'s shape repeated, and it is worth naming rather than
14
+ * rediscovering. The module walks the lifecycle manifest registry to refresh
15
+ * every module's palette actions, and reaches that registry through the same
16
+ * lazy accessor, for the same chicken-and-egg reason — `_lifecycle`'s
17
+ * orchestrator is constructed after it. The reconcile therefore runs at
18
+ * **plugin attach**, the point at which every root has finished composing and
19
+ * the accessor is guaranteed to answer, and it stays there.
20
+ *
21
+ * It stays there for `_i18n`'s reason too: neither reconciler treats an absent
22
+ * registry as an error — this one simply walks nothing — so an accessor that
23
+ * answers `undefined` fails silently. Every module's palette actions would stop
24
+ * being refreshed at boot and the first symptom would be a stale ⌘K entry
25
+ * pointing at a route that moved. Moving the reconcile is a change that has to
26
+ * carry its own evidence; uniformity with the other conversions is not it.
27
+ *
28
+ * **The presence probe stops being optional**, and its absent form is the
29
+ * permissive one. The option's own comment says what that costs: *"Without it
30
+ * the palette keeps offering a deactivated module's actions, which lead to a
31
+ * 503."* An operator switches a module off, its entries stay in ⌘K, and the
32
+ * admin who picks one gets an error rather than an absence. Both roots pass it,
33
+ * so nothing is live; eleventh removal of this shape.
34
+ *
35
+ * Issue #225 — it carries the presence **version** alongside the reading, in
36
+ * one value, because the service memoises what the reading produced and needs
37
+ * to know when the reading moved. A root that supplied one without the other
38
+ * would give the palette a snapshot it can never drop.
39
+ *
40
+ * `adminActionsReconciler` is a **port**, and since feature 080's T036a it is
41
+ * one with no consumer here: the lifecycle orchestrator reaches this module's
42
+ * reconcile through the `lifecycleParticipant` declared in `manifest.ts`. See
43
+ * the note on `AdminActionsModuleHandle.reconciler` in `plugin.ts`.
44
+ */
45
+ export interface AdminActionsCradle {
46
+ readonly emFactory: () => EntityManager;
47
+ readonly orm: import('@mikro-orm/postgresql').MikroORM;
48
+ readonly requireAdmin: RequireAdminFactory;
49
+ readonly adminContextResolver: (req: FastifyRequest) => {
50
+ adminUserId: string;
51
+ };
52
+ readonly adminI18nService: AdminI18nTranslatePort;
53
+ readonly permissionService: PermissionReadPort;
54
+ /** Reads the lifecycle registry lazily; `undefined` until `_lifecycle` exists. */
55
+ readonly lifecycleManifestRegistry: () => AdminActionsManifestRegistryView | undefined;
56
+ /**
57
+ * Both presence axes and their generation, so the palette hides an absent
58
+ * module — uninstalled or deactivated — and stops serving a snapshot built
59
+ * before it became one.
60
+ */
61
+ readonly modulePresenceProbe: ModulePresenceProbe;
62
+ readonly adminActions: {
63
+ handle: AdminActionsModuleHandle;
64
+ plugin: unknown;
65
+ };
66
+ readonly adminActionsReconciler: AdminActionsModuleHandle['reconciler'];
67
+ }
68
+ export declare function registerModule(ctx: ModuleContext): void;
69
+ /**
70
+ * The module's persisted entity classes, on the `./backend` subpath, as one
71
+ * array and **no named class export** (D-168).
72
+ *
73
+ * This is the shape the platform reads when the package is *installed*: the
74
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
75
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
76
+ * which is the third source of `check:module-boundary`'s `table->owner` map and
77
+ * the package pass of `check-entity-tenant-classification`. A missing array is
78
+ * answered with `[]` — zero entities registered, no error anywhere.
79
+ *
80
+ * The order is the one `db/entities-registry.generated.ts` declared before this
81
+ * module became a package, so the registered set is the same list in the same
82
+ * sequence.
83
+ */
84
+ export declare const entities: (typeof ModuleAction)[];
85
+ //# 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,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAEL,KAAK,gCAAgC,EACrC,KAAK,wBAAwB,EAC9B,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,aAAa,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,OAAO,uBAAuB,EAAE,QAAQ,CAAC;IACvD,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,oBAAoB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;IAClD,QAAQ,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IAC/C,kFAAkF;IAClF,QAAQ,CAAC,yBAAyB,EAAE,MAAM,gCAAgC,GAAG,SAAS,CAAC;IACvF;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,QAAQ,CAAC,YAAY,EAAE;QAAE,MAAM,EAAE,wBAAwB,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7E,QAAQ,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,YAAY,CAAC,CAAC;CACzE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA+CvD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,yBAEpB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { lazyPort } from '@endora-commerce/platform/kernel';
2
+ import { ModuleAction } from './entities/module-action.entity.js';
3
+ import { adminActionsModule, } from './plugin.js';
4
+ export function registerModule(ctx) {
5
+ ctx.di.register({
6
+ adminActions: ctx
7
+ .asFunction(({ orm, emFactory }) => adminActionsModule({
8
+ orm,
9
+ emFactory,
10
+ // Feature 075, Phase C — `admin_roles`' published permission read,
11
+ // resolved per call so a switched-off `admin_roles` answers 503 at
12
+ // the call rather than through a gate frozen at composition time.
13
+ permissionService: lazyPort(ctx, 'permissionService'),
14
+ // The registry accessor, threaded straight through: the module's own
15
+ // reconcile reads it at plugin attach, which is the whole point.
16
+ registry: () => ctx.cradle().lifecycleManifestRegistry(),
17
+ // Feature 075, Phase C — `_i18n`'s published resolver. One method of
18
+ // it: the palette renders a label and a description per action.
19
+ i18nService: lazyPort(ctx, 'adminI18nService'),
20
+ requireAdmin: (permission) => async (req, reply) => ctx.cradle().requireAdmin(permission)(req, reply),
21
+ resolveAdminContext: (req) => ctx.cradle().adminContextResolver(req),
22
+ presence: {
23
+ isPlatformAvailable: (moduleId) => ctx.cradle().modulePresenceProbe.isPlatformAvailable(moduleId),
24
+ isActivated: (moduleId) => ctx.cradle().modulePresenceProbe.isActivated(moduleId),
25
+ version: () => ctx.cradle().modulePresenceProbe.version(),
26
+ },
27
+ }))
28
+ .singleton(),
29
+ });
30
+ ctx.di.providePort('adminActionsReconciler', ctx
31
+ .asFunction(({ adminActions }) => adminActions.handle.reconciler)
32
+ .singleton());
33
+ ctx.routes(async (app) => {
34
+ const plugin = ctx.cradle().adminActions.plugin;
35
+ // Plugin attach, not `onBoot` — see the note at the top of this file.
36
+ await plugin(app);
37
+ });
38
+ }
39
+ /**
40
+ * The module's persisted entity classes, on the `./backend` subpath, as one
41
+ * array and **no named class export** (D-168).
42
+ *
43
+ * This is the shape the platform reads when the package is *installed*: the
44
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
45
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
46
+ * which is the third source of `check:module-boundary`'s `table->owner` map and
47
+ * the package pass of `check-entity-tenant-classification`. A missing array is
48
+ * answered with `[]` — zero entities registered, no error anywhere.
49
+ *
50
+ * The order is the one `db/entities-registry.generated.ts` declared before this
51
+ * module became a package, so the registered set is the same list in the same
52
+ * sequence.
53
+ */
54
+ export const entities = [
55
+ ModuleAction,
56
+ ];
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EACL,kBAAkB,GAGnB,MAAM,aAAa,CAAC;AA0DrB,MAAM,UAAU,cAAc,CAAC,GAAkB;IAC/C,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC;QACd,YAAY,EAAE,GAAG;aACd,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAsB,EAAE,EAAE,CACrD,kBAAkB,CAAC;YACjB,GAAG;YACH,SAAS;YACT,mEAAmE;YACnE,mEAAmE;YACnE,kEAAkE;YAClE,iBAAiB,EAAE,QAAQ,CAAqB,GAAG,EAAE,mBAAmB,CAAC;YACzE,qEAAqE;YACrE,iEAAiE;YACjE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAsB,CAAC,yBAAyB,EAAE;YAC5E,qEAAqE;YACrE,gEAAgE;YAChE,WAAW,EAAE,QAAQ,CAAyB,GAAG,EAAE,kBAAkB,CAAC;YACtE,YAAY,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CACjD,GAAG,CAAC,MAAM,EAAsB,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC;YACvE,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE,CAC3B,GAAG,CAAC,MAAM,EAAsB,CAAC,oBAAoB,CAAC,GAAG,CAAC;YAC5D,QAAQ,EAAE;gBACR,mBAAmB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAChC,GAAG,CAAC,MAAM,EAAsB,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,QAAQ,CAAC;gBACpF,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CACxB,GAAG,CAAC,MAAM,EAAsB,CAAC,mBAAmB,CAAC,WAAW,CAAC,QAAQ,CAAC;gBAC5E,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAsB,CAAC,mBAAmB,CAAC,OAAO,EAAE;aAC9E;SACF,CAAC,CACH;aACA,SAAS,EAAE;KACf,CAAC,CAAC;IAEH,GAAG,CAAC,EAAE,CAAC,WAAW,CAChB,wBAAwB,EACxB,GAAG;SACA,UAAU,CAAC,CAAC,EAAE,YAAY,EAAsB,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC;SACpF,SAAS,EAAE,CACf,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAsB,CAAC,YAAY,CAAC,MAE3C,CAAC;QACnB,sEAAsE;QACtE,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,YAAY;CACb,CAAC"}
@@ -0,0 +1,110 @@
1
+ import type { EntityManager, MikroORM } from '@mikro-orm/postgresql';
2
+ import type { AdminI18nTranslatePort, ModuleAction, PermissionReadPort } from '@endora-commerce/contracts';
3
+ import { AdminActionsService, type ModulePresenceProbe } from './services/admin-actions-service.js';
4
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
5
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
6
+ /**
7
+ * The attach function this module hands its composition root.
8
+ *
9
+ * Typed on `fastify`'s own `FastifyInstance` rather than on the platform's
10
+ * `ModulePlugin`, which `contracts/host-package.md` §1.4g classifies **A**: the
11
+ * host does not publish it, so a packaged module cannot name it. The
12
+ * already-packaged `quote_requests` types its attach function the same way.
13
+ */
14
+ type ModuleAttach = (app: FastifyInstance) => Promise<void>;
15
+ /**
16
+ * Admin Actions module composition root — feature 020.
17
+ *
18
+ * Boot-time responsibilities:
19
+ *
20
+ * 1. Build the `AdminActionsService` (visibility + cache + pubsub).
21
+ * 2. Build the `AdminActionsReconciler` (UPSERT + prune at install,
22
+ * DELETE at hard-uninstall).
23
+ * 3. Run an idempotent reconcile pass — for every module whose
24
+ * manifest declares `actions`, refresh the `module_actions` rows
25
+ * from the manifest. Mirrors feature 019's i18n boot reconciler so
26
+ * the registry catches up after a redeploy without requiring a
27
+ * module:install of every module.
28
+ * 4. Register the admin HTTP route.
29
+ */
30
+ /**
31
+ * One module's manifest, as the palette reconcile reads it: the id the
32
+ * `module_actions` rows are keyed by, and the actions the manifest declares.
33
+ *
34
+ * Stated here rather than imported from `_lifecycle` (feature 075, Phase C),
35
+ * for the reason `_i18n`'s `I18nManifestRegistryView` records. Which modules a
36
+ * deployment ships is a **composition root's** input — `lifecycleManifestRegistry`
37
+ * is a name a root supplies, not a port a module resolves — and `_lifecycle`'s
38
+ * own `LoadedManifestRegistry` additionally carries a dependency graph and each
39
+ * module's install hooks, none of which a palette reconcile has any business
40
+ * seeing. Stating the demand is what keeps the two apart.
41
+ */
42
+ export interface AdminActionsReconcileEntry {
43
+ manifest: {
44
+ id: string;
45
+ actions?: readonly ModuleAction[] | undefined;
46
+ };
47
+ }
48
+ /** The slice of the lifecycle registry the palette reconcile walks. */
49
+ export interface AdminActionsManifestRegistryView {
50
+ modules: {
51
+ values(): Iterable<AdminActionsReconcileEntry>;
52
+ };
53
+ }
54
+ export interface AdminActionsModuleDeps {
55
+ orm: MikroORM;
56
+ emFactory: () => EntityManager;
57
+ /** Lazy accessor — same chicken-and-egg pattern feature 019 uses. */
58
+ registry?: AdminActionsManifestRegistryView | (() => AdminActionsManifestRegistryView | undefined);
59
+ i18nService: AdminI18nTranslatePort;
60
+ permissionService: PermissionReadPort;
61
+ requireAdmin: RequireAdminFactory;
62
+ resolveAdminContext: (req: FastifyRequest) => {
63
+ adminUserId: string;
64
+ };
65
+ log?: {
66
+ info(msg: string): void;
67
+ warn(msg: string): void;
68
+ };
69
+ /**
70
+ * Feature 073 / issue #225 — the operator presence axis and its generation,
71
+ * passed straight through to the service. See
72
+ * `AdminActionsServiceDeps.presence` for why it is injected rather than read
73
+ * from the lifecycle singleton, and why the two halves are one value.
74
+ */
75
+ presence: ModulePresenceProbe;
76
+ }
77
+ export interface AdminActionsModuleHandle {
78
+ service: AdminActionsService;
79
+ /**
80
+ * Lifecycle-orchestrator-shaped reconciler, published as the
81
+ * `adminActionsReconciler` port.
82
+ *
83
+ * It no longer has a consumer in this repository (feature 080, T036a): the
84
+ * lifecycle orchestrator used to resolve it on every module's install, and
85
+ * now collects this module's `lifecycleParticipant` from the manifest
86
+ * registry instead — the one shape that also reaches a `module:*` command,
87
+ * which composes no container to resolve a port from. The port stays
88
+ * published because it is a legitimate seam for a caller that has a
89
+ * container; withdrawing it is a contract decision of its own.
90
+ */
91
+ reconciler: {
92
+ install(args: {
93
+ moduleId: string;
94
+ actions: readonly ModuleAction[];
95
+ }): Promise<{
96
+ upserted: number;
97
+ pruned: number;
98
+ }>;
99
+ remove(moduleId: string): Promise<{
100
+ removed: number;
101
+ }>;
102
+ };
103
+ }
104
+ export interface AdminActionsModule {
105
+ handle: AdminActionsModuleHandle;
106
+ plugin: ModuleAttach;
107
+ }
108
+ export declare function adminActionsModule(deps: AdminActionsModuleDeps): AdminActionsModule;
109
+ export {};
110
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,mBAAmB,EACnB,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAC;AAI7C,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE5E;;;;;;;GAOG;AACH,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5D;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAA;KAAE,CAAC;CACzE;AAED,uEAAuE;AACvE,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE;QAAE,MAAM,IAAI,QAAQ,CAAC,0BAA0B,CAAC,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,QAAQ,CAAC;IACd,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,EACL,gCAAgC,GAChC,CAAC,MAAM,gCAAgC,GAAG,SAAS,CAAC,CAAC;IACzD,WAAW,EAAE,sBAAsB,CAAC;IACpC,iBAAiB,EAAE,kBAAkB,CAAC;IACtC,YAAY,EAAE,mBAAmB,CAAC;IAClC,mBAAmB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,GAAG,CAAC,EAAE;QAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3D;;;;;OAKG;IACH,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,mBAAmB,CAAC;IAC7B;;;;;;;;;;;OAWG;IACH,UAAU,EAAE;QACV,OAAO,CAAC,IAAI,EAAE;YACZ,QAAQ,EAAE,MAAM,CAAC;YACjB,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;SAClC,GAAG,OAAO,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACxD,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,kBAAkB,CAmCnF"}
@@ -0,0 +1,77 @@
1
+ import { AdminActionsReconciler } from './services/admin-actions-reconciler.js';
2
+ import { AdminActionsService, } from './services/admin-actions-service.js';
3
+ import { registerAdminActionsRoutes, } from './routes.admin.js';
4
+ export function adminActionsModule(deps) {
5
+ const log = deps.log ?? { info: () => { }, warn: (m) => console.warn(m) };
6
+ const reconciler = new AdminActionsReconciler({ em: deps.emFactory });
7
+ const service = new AdminActionsService({
8
+ em: deps.emFactory,
9
+ i18nService: deps.i18nService,
10
+ permissionService: deps.permissionService,
11
+ ...(deps.presence ? { presence: deps.presence } : {}),
12
+ log,
13
+ });
14
+ const plugin = async (app) => {
15
+ const registry = typeof deps.registry === 'function' ? deps.registry() : deps.registry;
16
+ if (registry) {
17
+ await reconcileActions(registry, reconciler, log);
18
+ }
19
+ await registerAdminActionsRoutes(app, {
20
+ adminActionsService: service,
21
+ requireAdmin: deps.requireAdmin,
22
+ resolveAdminContext: deps.resolveAdminContext,
23
+ });
24
+ };
25
+ return {
26
+ handle: {
27
+ service,
28
+ reconciler: {
29
+ install: async ({ moduleId, actions }) => reconciler.installForModule({ moduleId, actions }),
30
+ remove: async (moduleId) => reconciler.removeForModule({ moduleId }),
31
+ },
32
+ },
33
+ plugin,
34
+ };
35
+ }
36
+ /**
37
+ * Idempotent reconciler — for every manifest with declared actions,
38
+ * UPSERT them and prune any rows the manifest no longer declares.
39
+ * Errors on a single module are logged but do NOT abort boot.
40
+ */
41
+ async function reconcileActions(registry, reconciler, log) {
42
+ let installed = 0;
43
+ let skipped = 0;
44
+ let failed = 0;
45
+ for (const entry of registry.modules.values()) {
46
+ const actions = entry.manifest.actions;
47
+ if (!actions || actions.length === 0) {
48
+ skipped += 1;
49
+ // Even when no actions are declared, prune any rows that may
50
+ // remain from a previous version that did declare them. This is
51
+ // the cheapest way to keep the table aligned with the current
52
+ // manifest set.
53
+ try {
54
+ await reconciler.installForModule({ moduleId: entry.manifest.id, actions: [] });
55
+ }
56
+ catch (err) {
57
+ // Pruning a non-existent row is a no-op; failure here means a
58
+ // larger DB problem worth surfacing.
59
+ log.warn(`[admin_actions] prune for "${entry.manifest.id}" failed: ${err.message}`);
60
+ }
61
+ continue;
62
+ }
63
+ try {
64
+ await reconciler.installForModule({
65
+ moduleId: entry.manifest.id,
66
+ actions,
67
+ });
68
+ installed += 1;
69
+ }
70
+ catch (err) {
71
+ failed += 1;
72
+ log.warn(`[admin_actions] reconcile: module "${entry.manifest.id}" failed: ${err.message}`);
73
+ }
74
+ }
75
+ log.info(`[admin_actions] reconcile complete — installed=${installed} skipped=${skipped} failed=${failed}`);
76
+ }
77
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import type { AdminActionsService } from './services/admin-actions-service.js';
3
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
4
+ export interface AdminActionsRouteDeps {
5
+ adminActionsService: AdminActionsService;
6
+ requireAdmin: RequireAdminFactory;
7
+ resolveAdminContext: (req: FastifyRequest) => {
8
+ adminUserId: string;
9
+ };
10
+ }
11
+ /**
12
+ * GET /api/v1/admin/admin-actions?language=…
13
+ *
14
+ * Returns the operator-visible action list for the requested language
15
+ * — already filtered by enabled-module + permission, already resolved
16
+ * to localized labels, already sorted by `(weight, label)`.
17
+ */
18
+ export declare function registerAdminActionsRoutes(app: FastifyInstance, deps: AdminActionsRouteDeps): Promise<void>;
19
+ //# 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,cAAc,EAAE,MAAM,SAAS,CAAC;AAM/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,YAAY,EAAE,mBAAmB,CAAC;IAClC,mBAAmB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CACvE;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -0,0 +1,32 @@
1
+ import { GetAdminActionsQuerySchema, GetAdminActionsResponseSchema, } from '@endora-commerce/contracts';
2
+ /**
3
+ * GET /api/v1/admin/admin-actions?language=…
4
+ *
5
+ * Returns the operator-visible action list for the requested language
6
+ * — already filtered by enabled-module + permission, already resolved
7
+ * to localized labels, already sorted by `(weight, label)`.
8
+ */
9
+ export async function registerAdminActionsRoutes(app, deps) {
10
+ app.get('/api/v1/admin/admin-actions', {
11
+ preHandler: deps.requireAdmin(),
12
+ schema: { querystring: GetAdminActionsQuerySchema },
13
+ }, async (request, reply) => {
14
+ const { language } = GetAdminActionsQuerySchema.parse(request.query);
15
+ const ctx = deps.resolveAdminContext(request);
16
+ const result = await deps.adminActionsService.listVisibleForOperator({
17
+ language,
18
+ adminUserId: ctx.adminUserId,
19
+ });
20
+ const payload = {
21
+ data: result.actions,
22
+ meta: {
23
+ language,
24
+ total: result.actions.length,
25
+ registryVersion: result.registryVersion,
26
+ },
27
+ };
28
+ reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
29
+ return { data: GetAdminActionsResponseSchema.parse(payload) };
30
+ });
31
+ }
32
+ //# sourceMappingURL=routes.admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.admin.js","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,GAE9B,MAAM,4BAA4B,CAAC;AAUpC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAoB,EACpB,IAA2B;IAE3B,GAAG,CAAC,GAAG,CACL,6BAA6B,EAC7B;QACE,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE;QAC/B,MAAM,EAAE,EAAE,WAAW,EAAE,0BAA0B,EAAE;KACpD,EACD,KAAK,EAAE,OAAO,EAAE,KAAK,EAA8C,EAAE;QACnE,MAAM,EAAE,QAAQ,EAAE,GAAG,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,sBAAsB,CAAC;YACnE,QAAQ;YACR,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC,CAAC;QACH,MAAM,OAAO,GAA4B;YACvC,IAAI,EAAE,MAAM,CAAC,OAAO;YACpB,IAAI,EAAE;gBACJ,QAAQ;gBACR,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;gBAC5B,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC;SACF,CAAC;QACF,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,qCAAqC,CAAC,CAAC;QACrE,OAAO,EAAE,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;IAChE,CAAC,CACF,CAAC;AACJ,CAAC"}