@veap/plugins 0.0.0-stage → 0.1.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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -2
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/actions/plugin.actions.d.ts +6 -0
  6. package/dist/actions/plugin.actions.js +60 -0
  7. package/dist/actions.d.ts +1 -0
  8. package/dist/actions.js +1 -0
  9. package/dist/cli/add.d.ts +4 -0
  10. package/dist/cli/add.js +191 -0
  11. package/dist/cli/eject.d.ts +2 -0
  12. package/dist/cli/eject.js +136 -0
  13. package/dist/cli/generate-plugin.d.ts +3 -0
  14. package/dist/cli/generate-plugin.js +48 -0
  15. package/dist/cli/index.d.ts +6 -0
  16. package/dist/cli/index.js +6 -0
  17. package/dist/cli/package-manager.d.ts +14 -0
  18. package/dist/cli/package-manager.js +62 -0
  19. package/dist/cli/stubs.d.ts +16 -0
  20. package/dist/cli/stubs.js +42 -0
  21. package/dist/cli/utils.d.ts +3 -0
  22. package/dist/cli/utils.js +164 -0
  23. package/dist/client.d.ts +6 -0
  24. package/dist/client.js +8 -0
  25. package/dist/common/context.d.ts +26 -0
  26. package/dist/common/context.js +26 -0
  27. package/dist/common/events.d.ts +19 -0
  28. package/dist/common/events.js +26 -0
  29. package/dist/common/index.d.ts +3 -0
  30. package/dist/common/index.js +3 -0
  31. package/dist/common/types.d.ts +195 -0
  32. package/dist/common/types.js +40 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.js +5 -0
  35. package/dist/migrations/0001_create_plugins_tables.d.ts +4 -0
  36. package/dist/migrations/0001_create_plugins_tables.js +29 -0
  37. package/dist/migrations/index.d.ts +4 -0
  38. package/dist/migrations/index.js +7 -0
  39. package/dist/models/SystemPlugin.d.ts +19 -0
  40. package/dist/models/SystemPlugin.js +14 -0
  41. package/dist/models/SystemUserWidget.d.ts +19 -0
  42. package/dist/models/SystemUserWidget.js +17 -0
  43. package/dist/models/index.d.ts +2 -0
  44. package/dist/models/index.js +2 -0
  45. package/dist/models.d.ts +1 -0
  46. package/dist/models.js +1 -0
  47. package/dist/navigation/breadcrumbs.d.ts +2 -0
  48. package/dist/navigation/breadcrumbs.js +84 -0
  49. package/dist/navigation/index.d.ts +2 -0
  50. package/dist/navigation/index.js +2 -0
  51. package/dist/navigation/navigation.service.d.ts +27 -0
  52. package/dist/navigation/navigation.service.js +183 -0
  53. package/dist/providers/index.d.ts +1 -0
  54. package/dist/providers/index.js +1 -0
  55. package/dist/providers/plugins.provider.d.ts +20 -0
  56. package/dist/providers/plugins.provider.js +142 -0
  57. package/dist/registry/contracts.d.ts +72 -0
  58. package/dist/registry/contracts.js +4 -0
  59. package/dist/registry/facade.d.ts +45 -0
  60. package/dist/registry/facade.js +49 -0
  61. package/dist/registry/index.d.ts +5 -0
  62. package/dist/registry/index.js +5 -0
  63. package/dist/registry/migration-runner.d.ts +8 -0
  64. package/dist/registry/migration-runner.js +12 -0
  65. package/dist/registry/plugin.repository.d.ts +19 -0
  66. package/dist/registry/plugin.repository.js +74 -0
  67. package/dist/registry/registry.service.d.ts +69 -0
  68. package/dist/registry/registry.service.js +535 -0
  69. package/dist/router/discovery.d.ts +27 -0
  70. package/dist/router/discovery.js +37 -0
  71. package/dist/router/handler.d.ts +6 -0
  72. package/dist/router/handler.js +40 -0
  73. package/dist/router/index.d.ts +13 -0
  74. package/dist/router/index.js +13 -0
  75. package/dist/router/matcher.d.ts +5 -0
  76. package/dist/router/matcher.js +32 -0
  77. package/dist/router/middlewares.d.ts +25 -0
  78. package/dist/router/middlewares.js +119 -0
  79. package/dist/router/react/error-boundary.d.ts +30 -0
  80. package/dist/router/react/error-boundary.js +68 -0
  81. package/dist/router/react/index.d.ts +4 -0
  82. package/dist/router/react/index.js +4 -0
  83. package/dist/router/react/renderer.d.ts +13 -0
  84. package/dist/router/react/renderer.js +159 -0
  85. package/dist/router/react/soft-navigation.d.ts +4 -0
  86. package/dist/router/react/soft-navigation.js +34 -0
  87. package/dist/router/react/with-router.d.ts +22 -0
  88. package/dist/router/react/with-router.js +19 -0
  89. package/dist/router/route-tree.d.ts +177 -0
  90. package/dist/router/route-tree.js +633 -0
  91. package/dist/router/router.service.d.ts +25 -0
  92. package/dist/router/router.service.js +127 -0
  93. package/dist/router/scanner.d.ts +4 -0
  94. package/dist/router/scanner.js +337 -0
  95. package/dist/router/utils.d.ts +10 -0
  96. package/dist/router/utils.js +48 -0
  97. package/dist/router.d.ts +6 -0
  98. package/dist/router.js +6 -0
  99. package/dist/server.d.ts +11 -0
  100. package/dist/server.js +17 -0
  101. package/dist/widgets/index.d.ts +8 -0
  102. package/dist/widgets/index.js +8 -0
  103. package/dist/widgets/path-prefix-context.d.ts +5 -0
  104. package/dist/widgets/path-prefix-context.js +9 -0
  105. package/dist/widgets/plugin-extension-point-client.d.ts +15 -0
  106. package/dist/widgets/plugin-extension-point-client.js +44 -0
  107. package/dist/widgets/plugin-extension-point.d.ts +14 -0
  108. package/dist/widgets/plugin-extension-point.js +51 -0
  109. package/dist/widgets/plugin-widget-area-client.d.ts +11 -0
  110. package/dist/widgets/plugin-widget-area-client.js +31 -0
  111. package/dist/widgets/plugin-widget-area.d.ts +10 -0
  112. package/dist/widgets/plugin-widget-area.js +19 -0
  113. package/dist/widgets/use-confirm-action.d.ts +19 -0
  114. package/dist/widgets/use-confirm-action.js +68 -0
  115. package/dist/widgets/widget-composer-client.d.ts +21 -0
  116. package/dist/widgets/widget-composer-client.js +281 -0
  117. package/dist/widgets/widget-composer.d.ts +8 -0
  118. package/dist/widgets/widget-composer.js +28 -0
  119. package/package.json +115 -4
@@ -0,0 +1,29 @@
1
+ export const name = "0001_create_plugins_tables";
2
+ export async function up(_db, schema) {
3
+ // 1. Plugins table
4
+ await schema.createTable("plugins", (table) => {
5
+ table.text("id").primaryKey();
6
+ table.boolean("enabled").notNull().default(false);
7
+ table.boolean("installed").notNull().default(false);
8
+ table.boolean("deleted").notNull().default(false);
9
+ table.boolean("system").notNull().default(false);
10
+ table.text("config");
11
+ table.text("last_step");
12
+ table.timestamp("updated_at").defaultNow();
13
+ });
14
+ // 2. System user widgets table
15
+ await schema.createTable("system_user_widgets", (table) => {
16
+ table
17
+ .text("user_id")
18
+ .references("users", "id")
19
+ .onDelete("CASCADE")
20
+ .notNull();
21
+ table.text("slot").notNull();
22
+ table.jsonb("state").notNull().default("[]");
23
+ table.primary(["user_id", "slot"]);
24
+ });
25
+ }
26
+ export async function down(_db, schema) {
27
+ await schema.dropTableIfExists("system_user_widgets");
28
+ await schema.dropTableIfExists("plugins");
29
+ }
@@ -0,0 +1,4 @@
1
+ import * as m0001 from "./0001_create_plugins_tables";
2
+ export declare const pluginMigrations: (typeof m0001)[];
3
+ export declare function runPluginMigrations(): Promise<void>;
4
+ export default pluginMigrations;
@@ -0,0 +1,7 @@
1
+ import { runMigrations } from "@veap/database";
2
+ import * as m0001 from "./0001_create_plugins_tables";
3
+ export const pluginMigrations = [m0001];
4
+ export async function runPluginMigrations() {
5
+ await runMigrations("plugins", pluginMigrations);
6
+ }
7
+ export default pluginMigrations;
@@ -0,0 +1,19 @@
1
+ import { type CastType, Model } from "@veap/database";
2
+ export interface SystemPluginAttributes {
3
+ id: string;
4
+ enabled: boolean;
5
+ installed: boolean;
6
+ deleted: boolean;
7
+ system: boolean;
8
+ config?: string | null;
9
+ lastStep?: string | null;
10
+ last_step?: string | null;
11
+ updatedAt?: Date | null;
12
+ updated_at?: Date | null;
13
+ }
14
+ export declare class SystemPlugin extends Model<SystemPluginAttributes> {
15
+ static table: string;
16
+ static autoUuid: boolean;
17
+ static timestamps: boolean | string[];
18
+ static casts: Record<string, CastType>;
19
+ }
@@ -0,0 +1,14 @@
1
+ import { Model } from "@veap/database";
2
+ export class SystemPlugin extends Model {
3
+ static table = "plugins";
4
+ static autoUuid = false;
5
+ static timestamps = ["updated_at"];
6
+ static casts = {
7
+ enabled: "boolean",
8
+ installed: "boolean",
9
+ deleted: "boolean",
10
+ system: "boolean",
11
+ updatedAt: "datetime",
12
+ updated_at: "datetime",
13
+ };
14
+ }
@@ -0,0 +1,19 @@
1
+ import { User } from "@veap/auth/models";
2
+ import { type CastType, Model } from "@veap/database";
3
+ export interface SystemUserWidgetAttributes {
4
+ userId: string;
5
+ user_id?: string;
6
+ slot: string;
7
+ state: any;
8
+ }
9
+ export declare class SystemUserWidget extends Model<SystemUserWidgetAttributes> {
10
+ static table: string;
11
+ static primaryKey: string;
12
+ static autoUuid: boolean;
13
+ static timestamps: boolean;
14
+ static casts: Record<string, CastType>;
15
+ /**
16
+ * Associated user relation.
17
+ */
18
+ user(): import("@veap/database").BelongsTo<this, User>;
19
+ }
@@ -0,0 +1,17 @@
1
+ import { User } from "@veap/auth/models";
2
+ import { Model } from "@veap/database";
3
+ export class SystemUserWidget extends Model {
4
+ static table = "system_user_widgets";
5
+ static primaryKey = "user_id";
6
+ static autoUuid = false;
7
+ static timestamps = false;
8
+ static casts = {
9
+ state: "json",
10
+ };
11
+ /**
12
+ * Associated user relation.
13
+ */
14
+ user() {
15
+ return this.belongsTo(User, "user_id");
16
+ }
17
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./SystemPlugin";
2
+ export * from "./SystemUserWidget";
@@ -0,0 +1,2 @@
1
+ export * from "./SystemPlugin";
2
+ export * from "./SystemUserWidget";
@@ -0,0 +1 @@
1
+ export * from "./models/index";
package/dist/models.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./models/index";
@@ -0,0 +1,2 @@
1
+ import type { BreadcrumbItem } from "../common/types";
2
+ export declare function getPluginBreadcrumbs(path: string, searchParams?: any): Promise<BreadcrumbItem[]>;
@@ -0,0 +1,84 @@
1
+ "use server";
2
+ import { buildRouteTree } from "../router/discovery";
3
+ import { getPluginNavigation, getVeapPluginNavigationGrouped, } from "./navigation.service";
4
+ async function resolveBreadcrumb(value, props) {
5
+ if (typeof value === "function") {
6
+ return await value(props);
7
+ }
8
+ return value;
9
+ }
10
+ async function findInNavigation(url) {
11
+ const adminNav = await getVeapPluginNavigationGrouped("admin");
12
+ const settingsNav = await getVeapPluginNavigationGrouped("settings");
13
+ const publicNav = await getPluginNavigation("public");
14
+ const allNavItems = [
15
+ ...Object.values(adminNav).flat(),
16
+ ...Object.values(settingsNav).flat(),
17
+ ...publicNav,
18
+ ];
19
+ const search = (items) => {
20
+ for (const item of items) {
21
+ if (item.url === url)
22
+ return item;
23
+ if (item.items) {
24
+ const found = search(item.items);
25
+ if (found)
26
+ return found;
27
+ }
28
+ }
29
+ return null;
30
+ };
31
+ return search(allNavItems);
32
+ }
33
+ export async function getPluginBreadcrumbs(path, searchParams = {}) {
34
+ const tree = await buildRouteTree(true);
35
+ const segments = path.split("/").filter(Boolean);
36
+ const breadcrumbs = [];
37
+ let currentPath = "";
38
+ for (const segment of segments) {
39
+ currentPath += `/${segment}`;
40
+ const match = tree.match(currentPath);
41
+ if (match?.isExact && match?.node?.breadcrumb) {
42
+ const resolved = await resolveBreadcrumb(match.node.breadcrumb, {
43
+ params: Promise.resolve(match.params || {}),
44
+ searchParams: Promise.resolve(searchParams || {}),
45
+ });
46
+ addResolvedToBreadcrumbs(resolved, currentPath, breadcrumbs);
47
+ }
48
+ else {
49
+ const navItem = await findInNavigation(currentPath);
50
+ if (navItem) {
51
+ breadcrumbs.push({
52
+ label: navItem.title,
53
+ href: currentPath,
54
+ id: navItem.id,
55
+ });
56
+ }
57
+ }
58
+ }
59
+ const result = [];
60
+ const seenHrefs = new Set();
61
+ for (const bc of breadcrumbs) {
62
+ if (bc.href && seenHrefs.has(bc.href)) {
63
+ const index = result.findIndex((r) => r.href === bc.href);
64
+ if (index !== -1)
65
+ result[index] = bc;
66
+ continue;
67
+ }
68
+ if (bc.href)
69
+ seenHrefs.add(bc.href);
70
+ result.push(bc);
71
+ }
72
+ return result.filter((bc) => bc.label);
73
+ }
74
+ function addResolvedToBreadcrumbs(resolved, href, breadcrumbs) {
75
+ if (Array.isArray(resolved)) {
76
+ breadcrumbs.push(...resolved);
77
+ }
78
+ else if (typeof resolved === "string") {
79
+ breadcrumbs.push({ label: resolved, href });
80
+ }
81
+ else {
82
+ breadcrumbs.push(resolved);
83
+ }
84
+ }
@@ -0,0 +1,2 @@
1
+ export { getPluginBreadcrumbs } from "./breadcrumbs";
2
+ export { getPathPrefix, getPluginNavigation, getPluginNavigationGrouped, getPluginPathPrefix, getVeapPluginNavigationGrouped, NavigationService, } from "./navigation.service";
@@ -0,0 +1,2 @@
1
+ export { getPluginBreadcrumbs } from "./breadcrumbs";
2
+ export { getPathPrefix, getPluginNavigation, getPluginNavigationGrouped, getPluginPathPrefix, getVeapPluginNavigationGrouped, NavigationService, } from "./navigation.service";
@@ -0,0 +1,27 @@
1
+ import { type IVeapConfigProvider } from "@veap/kernel";
2
+ import type { PluginNavElement } from "../common/types";
3
+ import { PluginRegistry } from "../registry";
4
+ /**
5
+ * Navigation use cases. Depends on the bound plugins context, the auth
6
+ * context and the config port - no container lookups.
7
+ */
8
+ export declare class NavigationService {
9
+ private readonly registry;
10
+ private readonly config;
11
+ constructor(registry: PluginRegistry, config: IVeapConfigProvider);
12
+ getPathPrefix(): Promise<string>;
13
+ getNavigationGrouped(type: "admin" | "settings"): Promise<{
14
+ groups: Record<string, PluginNavElement[]>;
15
+ groupPriorities: Record<string, number>;
16
+ }>;
17
+ getVeapNavigationGrouped(type: "admin" | "settings"): Promise<Record<string, PluginNavElement[]>>;
18
+ getPublicNavigation(): Promise<PluginNavElement[]>;
19
+ }
20
+ export declare function getPathPrefix(): Promise<string>;
21
+ export declare function getPluginPathPrefix(): Promise<string>;
22
+ export declare function getPluginNavigationGrouped(type: "admin" | "settings"): Promise<{
23
+ groups: Record<string, PluginNavElement[]>;
24
+ groupPriorities: Record<string, number>;
25
+ }>;
26
+ export declare function getVeapPluginNavigationGrouped(type: "admin" | "settings"): Promise<Record<string, PluginNavElement[]>>;
27
+ export declare function getPluginNavigation(type?: "public"): Promise<PluginNavElement[]>;
@@ -0,0 +1,183 @@
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
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { authContext } from "@veap/auth";
14
+ import { Inject, Injectable, VEAP_CONFIG, } from "@veap/kernel";
15
+ import { pluginsContext } from "../common/context";
16
+ import { PluginRegistry } from "../registry";
17
+ function filterNavItem(item, userRoles, userPermissions) {
18
+ if (item.roles && item.roles.length > 0) {
19
+ if (!item.roles.some((role) => userRoles.includes(role))) {
20
+ return null;
21
+ }
22
+ }
23
+ if (item.permissions && item.permissions.length > 0) {
24
+ if (!item.permissions.every((perm) => userPermissions.includes(perm))) {
25
+ return null;
26
+ }
27
+ }
28
+ if (item.items && item.items.length > 0) {
29
+ const filteredSubItems = item.items
30
+ .map((subItem) => filterNavItem(subItem, userRoles, userPermissions))
31
+ .filter((subItem) => subItem !== null);
32
+ return {
33
+ ...item,
34
+ items: filteredSubItems,
35
+ };
36
+ }
37
+ return item;
38
+ }
39
+ /**
40
+ * Navigation use cases. Depends on the bound plugins context, the auth
41
+ * context and the config port - no container lookups.
42
+ */
43
+ let NavigationService = class NavigationService {
44
+ registry;
45
+ config;
46
+ constructor(registry, config) {
47
+ this.registry = registry;
48
+ this.config = config;
49
+ }
50
+ async getPathPrefix() {
51
+ const config = await this.config.get();
52
+ return config.privatePath ?? "/app";
53
+ }
54
+ async getNavigationGrouped(type) {
55
+ const { user } = await authContext().session.getCurrentSession();
56
+ const userRoles = user?.roles || [];
57
+ const userPermissions = user?.permissions || [];
58
+ const plugins = this.registry.getEnabledPlugins();
59
+ const groups = {};
60
+ const groupPriorities = {};
61
+ for (const plugin of plugins) {
62
+ try {
63
+ const pluginNav = plugin.navigation?.[type];
64
+ if (pluginNav) {
65
+ for (const [groupName, groupData] of Object.entries(pluginNav)) {
66
+ if (!groups[groupName])
67
+ groups[groupName] = [];
68
+ let items = [];
69
+ if (Array.isArray(groupData)) {
70
+ items = groupData;
71
+ }
72
+ else {
73
+ items = groupData.items;
74
+ if (groupData.priority !== undefined &&
75
+ (groupPriorities[groupName] === undefined ||
76
+ groupData.priority < groupPriorities[groupName])) {
77
+ groupPriorities[groupName] = groupData.priority;
78
+ }
79
+ }
80
+ for (const rawItem of items) {
81
+ const item = filterNavItem(rawItem, userRoles, userPermissions);
82
+ if (item &&
83
+ !groups[groupName].some((existing) => existing.url === item.url)) {
84
+ groups[groupName].push(item);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ catch (_e) {
91
+ console.warn(`[Kernel:Navigation] Failed to load navigation for plugin ${plugin.manifest.id}:`, _e);
92
+ }
93
+ }
94
+ const sortNavItems = (items) => {
95
+ items.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
96
+ for (const item of items) {
97
+ if (item.items && item.items.length > 0) {
98
+ sortNavItems(item.items);
99
+ }
100
+ }
101
+ };
102
+ for (const groupName in groups) {
103
+ sortNavItems(groups[groupName]);
104
+ }
105
+ return { groups, groupPriorities };
106
+ }
107
+ async getVeapNavigationGrouped(type) {
108
+ const { groups, groupPriorities } = await this.getNavigationGrouped(type);
109
+ const prefix = await this.getPathPrefix();
110
+ const prefixUrl = (url) => {
111
+ if (url.startsWith(prefix))
112
+ return url;
113
+ return url === "/" ? prefix : `${prefix}${url}`;
114
+ };
115
+ const processItems = (items) => {
116
+ return items.map((item) => ({
117
+ ...item,
118
+ url: prefixUrl(item.url),
119
+ items: item.items
120
+ ? processItems(item.items)
121
+ : undefined,
122
+ }));
123
+ };
124
+ const transformedGroups = {};
125
+ const sortedGroupNames = Object.keys(groups).sort((a, b) => {
126
+ const prioA = groupPriorities[a] ?? 1000;
127
+ const prioB = groupPriorities[b] ?? 1000;
128
+ if (prioA !== prioB)
129
+ return prioA - prioB;
130
+ return a.localeCompare(b);
131
+ });
132
+ for (const groupName of sortedGroupNames) {
133
+ transformedGroups[groupName] = processItems(groups[groupName]);
134
+ }
135
+ return transformedGroups;
136
+ }
137
+ async getPublicNavigation() {
138
+ const { user } = await authContext().session.getCurrentSession();
139
+ const userRoles = user?.roles || [];
140
+ const userPermissions = user?.permissions || [];
141
+ const plugins = this.registry.getEnabledPlugins();
142
+ const all = [];
143
+ for (const plugin of plugins) {
144
+ try {
145
+ if (plugin.navigation?.["public"]) {
146
+ const items = plugin.navigation["public"];
147
+ for (const rawItem of items) {
148
+ const item = filterNavItem(rawItem, userRoles, userPermissions);
149
+ if (item)
150
+ all.push(item);
151
+ }
152
+ }
153
+ }
154
+ catch { }
155
+ }
156
+ all.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
157
+ all.sort((a, b) => a.title.localeCompare(b.title));
158
+ return all;
159
+ }
160
+ };
161
+ NavigationService = __decorate([
162
+ Injectable(),
163
+ __param(0, Inject(PluginRegistry)),
164
+ __param(1, Inject(VEAP_CONFIG)),
165
+ __metadata("design:paramtypes", [PluginRegistry, Object])
166
+ ], NavigationService);
167
+ export { NavigationService };
168
+ // ─── Module-level API (composition-bound) ───────────────────────────
169
+ export async function getPathPrefix() {
170
+ return pluginsContext().navigation.getPathPrefix();
171
+ }
172
+ export async function getPluginPathPrefix() {
173
+ return pluginsContext().navigation.getPathPrefix();
174
+ }
175
+ export async function getPluginNavigationGrouped(type) {
176
+ return pluginsContext().navigation.getNavigationGrouped(type);
177
+ }
178
+ export async function getVeapPluginNavigationGrouped(type) {
179
+ return pluginsContext().navigation.getVeapNavigationGrouped(type);
180
+ }
181
+ export async function getPluginNavigation(type = "public") {
182
+ return pluginsContext().navigation.getPublicNavigation();
183
+ }
@@ -0,0 +1 @@
1
+ export { PluginServiceProvider, type PluginsConfig, PluginsServiceProvider, type RouterConfig, RouterServiceProvider, } from "./plugins.provider";
@@ -0,0 +1 @@
1
+ export { PluginServiceProvider, PluginsServiceProvider, RouterServiceProvider, } from "./plugins.provider";
@@ -0,0 +1,20 @@
1
+ import { ServiceProvider } from "@veap/kernel";
2
+ import type * as React from "react";
3
+ export interface PluginsConfig {
4
+ plugins?: any[];
5
+ rewrites?: Record<string, string>;
6
+ siteLayout?: React.ComponentType<any>;
7
+ /**
8
+ * Whether to automatically run plugin database migrations during boot().
9
+ * Defaults to `true` when database connection is initialized.
10
+ */
11
+ autoMigrate?: boolean;
12
+ }
13
+ export declare class PluginsServiceProvider extends ServiceProvider {
14
+ private config?;
15
+ constructor(container: any, config?: PluginsConfig);
16
+ register(): void;
17
+ boot(): Promise<void>;
18
+ }
19
+ export type { PluginsConfig as RouterConfig };
20
+ export { PluginsServiceProvider as PluginServiceProvider, PluginsServiceProvider as RouterServiceProvider, };
@@ -0,0 +1,142 @@
1
+ import { isDatabaseInitialized } from "@veap/database";
2
+ import { IntlService } from "@veap/intl/server";
3
+ import { APP_PLUGINS, eventBus, ROUTER_SERVICE, ServiceProvider, SITE_LAYOUT, } from "@veap/kernel";
4
+ import { bindPluginsContext } from "../common/context";
5
+ import { runPluginMigrations } from "../migrations";
6
+ import { NavigationService } from "../navigation/navigation.service";
7
+ import { MIGRATION_RUNNER, PLUGIN_REPOSITORY } from "../registry/contracts";
8
+ import { ensurePluginsInitialized, registerPlugins } from "../registry/facade";
9
+ import { KnexMigrationRunner } from "../registry/migration-runner";
10
+ import { ActiveRecordPluginRepository } from "../registry/plugin.repository";
11
+ import { PluginRegistry } from "../registry/registry.service";
12
+ import { RouterService } from "../router/router.service";
13
+ export class PluginsServiceProvider extends ServiceProvider {
14
+ config;
15
+ constructor(container, config) {
16
+ super(container);
17
+ this.config = config;
18
+ }
19
+ register() {
20
+ this.container.register({
21
+ token: PLUGIN_REPOSITORY,
22
+ useClass: ActiveRecordPluginRepository,
23
+ singleton: true,
24
+ });
25
+ this.container.register({
26
+ token: MIGRATION_RUNNER,
27
+ useClass: KnexMigrationRunner,
28
+ singleton: true,
29
+ });
30
+ this.container.register({
31
+ token: PluginRegistry,
32
+ useClass: PluginRegistry,
33
+ singleton: true,
34
+ });
35
+ this.container.register({
36
+ token: NavigationService,
37
+ useClass: NavigationService,
38
+ singleton: true,
39
+ });
40
+ this.container.register({
41
+ token: RouterService,
42
+ useClass: RouterService,
43
+ singleton: true,
44
+ });
45
+ this.container.register({
46
+ token: ROUTER_SERVICE,
47
+ useClass: RouterService,
48
+ singleton: true,
49
+ });
50
+ if (this.config?.siteLayout) {
51
+ this.container.register({
52
+ token: SITE_LAYOUT,
53
+ useValue: this.config.siteLayout,
54
+ singleton: true,
55
+ });
56
+ }
57
+ }
58
+ async boot() {
59
+ const registry = await this.container.resolve(PluginRegistry);
60
+ const navigation = await this.container.resolve(NavigationService);
61
+ const routerService = await this.container.resolve(RouterService);
62
+ bindPluginsContext({
63
+ registry,
64
+ navigation,
65
+ router: routerService,
66
+ });
67
+ if (this.config?.rewrites) {
68
+ for (const [from, to] of Object.entries(this.config.rewrites)) {
69
+ routerService.addRewrite(from, to);
70
+ }
71
+ }
72
+ if (this.config?.siteLayout) {
73
+ routerService.setSiteLayout(this.config.siteLayout);
74
+ }
75
+ // Register Intl loader for plugins if IntlService is available
76
+ if (this.container.has(IntlService)) {
77
+ try {
78
+ const intlService = await this.container.resolve(IntlService);
79
+ intlService.registerLoader({
80
+ id: "veap:plugins",
81
+ priority: 100,
82
+ load: async (locale) => {
83
+ let combined = {};
84
+ const plugins = registry.getPlugins();
85
+ for (const plugin of plugins) {
86
+ if (plugin.locales && plugin.locales[locale]) {
87
+ try {
88
+ const pluginDict = await plugin.locales[locale]();
89
+ const data = pluginDict.default || pluginDict;
90
+ combined = { ...combined, ...data };
91
+ }
92
+ catch (e) {
93
+ console.error(`[veap:Intl] Error loading locale ${locale} for plugin ${plugin.manifest.id}`, e);
94
+ }
95
+ }
96
+ }
97
+ return combined;
98
+ },
99
+ });
100
+ }
101
+ catch (err) {
102
+ console.warn("[veap:plugins] Intl loader registration deferred:", err?.message || err);
103
+ }
104
+ }
105
+ // Clear cache when plugins are enabled/disabled
106
+ eventBus.subscribe("system:plugin:toggle", "route-tree-cache", async () => {
107
+ await routerService.clearCache();
108
+ });
109
+ // Clear cache after plugin initialization finishes
110
+ eventBus.subscribe("system:plugins:init:end", "route-tree-cache-init", async () => {
111
+ await routerService.clearCache();
112
+ });
113
+ // Register plugins from config or container
114
+ const pluginsToRegister = this.config?.plugins ||
115
+ (this.container.has(APP_PLUGINS)
116
+ ? await this.container.resolve(APP_PLUGINS)
117
+ : this.container.has("AppPlugins")
118
+ ? await this.container.resolve("AppPlugins")
119
+ : []);
120
+ if (pluginsToRegister?.length) {
121
+ await registerPlugins(pluginsToRegister);
122
+ }
123
+ // Automatically run plugin migrations if database is initialized and autoMigrate is not disabled
124
+ if (this.config?.autoMigrate !== false && isDatabaseInitialized()) {
125
+ try {
126
+ await runPluginMigrations();
127
+ }
128
+ catch (err) {
129
+ console.warn("[veap:plugins] Plugin migration deferred:", err?.message || err);
130
+ }
131
+ }
132
+ // Auto-bootstrap and synchronize database state
133
+ try {
134
+ await ensurePluginsInitialized();
135
+ }
136
+ catch (e) {
137
+ console.warn("[veap:plugins] Plugin initialization deferred:", e?.message || e);
138
+ }
139
+ }
140
+ }
141
+ // Backwards compatibility aliases
142
+ export { PluginsServiceProvider as PluginServiceProvider, PluginsServiceProvider as RouterServiceProvider, };