@veap/plugins 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/plugin.actions.d.ts +6 -0
- package/dist/actions/plugin.actions.js +60 -0
- package/dist/actions.d.ts +1 -0
- package/dist/actions.js +1 -0
- package/dist/cli/add.d.ts +4 -0
- package/dist/cli/add.js +191 -0
- package/dist/cli/eject.d.ts +2 -0
- package/dist/cli/eject.js +136 -0
- package/dist/cli/generate-plugin.d.ts +3 -0
- package/dist/cli/generate-plugin.js +48 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli/package-manager.d.ts +14 -0
- package/dist/cli/package-manager.js +62 -0
- package/dist/cli/stubs.d.ts +16 -0
- package/dist/cli/stubs.js +42 -0
- package/dist/cli/utils.d.ts +3 -0
- package/dist/cli/utils.js +164 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +8 -0
- package/dist/common/context.d.ts +26 -0
- package/dist/common/context.js +26 -0
- package/dist/common/events.d.ts +19 -0
- package/dist/common/events.js +26 -0
- package/dist/common/index.d.ts +4 -0
- package/dist/common/index.js +4 -0
- package/dist/common/tokens.d.ts +14 -0
- package/dist/common/tokens.js +12 -0
- package/dist/common/types.d.ts +202 -0
- package/dist/common/types.js +39 -0
- package/dist/composition.d.ts +15 -0
- package/dist/composition.js +20 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/migrations/0001_create_plugins_tables.d.ts +4 -0
- package/dist/migrations/0001_create_plugins_tables.js +29 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.js +7 -0
- package/dist/models/SystemPlugin.d.ts +19 -0
- package/dist/models/SystemPlugin.js +14 -0
- package/dist/models/SystemUserWidget.d.ts +19 -0
- package/dist/models/SystemUserWidget.js +17 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.js +2 -0
- package/dist/models.d.ts +1 -0
- package/dist/models.js +1 -0
- package/dist/navigation/breadcrumbs.d.ts +2 -0
- package/dist/navigation/breadcrumbs.js +84 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/navigation.service.d.ts +27 -0
- package/dist/navigation/navigation.service.js +183 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/plugins.provider.d.ts +20 -0
- package/dist/providers/plugins.provider.js +143 -0
- package/dist/registry/contracts.d.ts +72 -0
- package/dist/registry/contracts.js +4 -0
- package/dist/registry/facade.d.ts +45 -0
- package/dist/registry/facade.js +49 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +5 -0
- package/dist/registry/migration-runner.d.ts +8 -0
- package/dist/registry/migration-runner.js +12 -0
- package/dist/registry/plugin.repository.d.ts +19 -0
- package/dist/registry/plugin.repository.js +74 -0
- package/dist/registry/registry.service.d.ts +69 -0
- package/dist/registry/registry.service.js +535 -0
- package/dist/router/discovery.d.ts +27 -0
- package/dist/router/discovery.js +37 -0
- package/dist/router/handler.d.ts +6 -0
- package/dist/router/handler.js +40 -0
- package/dist/router/index.d.ts +14 -0
- package/dist/router/index.js +14 -0
- package/dist/router/matcher.d.ts +5 -0
- package/dist/router/matcher.js +32 -0
- package/dist/router/middlewares.d.ts +25 -0
- package/dist/router/middlewares.js +119 -0
- package/dist/router/react/error-boundary.d.ts +30 -0
- package/dist/router/react/error-boundary.js +68 -0
- package/dist/router/react/index.d.ts +4 -0
- package/dist/router/react/index.js +4 -0
- package/dist/router/react/renderer.d.ts +13 -0
- package/dist/router/react/renderer.js +159 -0
- package/dist/router/react/soft-navigation.d.ts +4 -0
- package/dist/router/react/soft-navigation.js +34 -0
- package/dist/router/react/with-router.d.ts +22 -0
- package/dist/router/react/with-router.js +19 -0
- package/dist/router/route-tree.d.ts +177 -0
- package/dist/router/route-tree.js +639 -0
- package/dist/router/router.service.d.ts +25 -0
- package/dist/router/router.service.js +127 -0
- package/dist/router/scanner.d.ts +4 -0
- package/dist/router/scanner.js +337 -0
- package/dist/router/utils.d.ts +10 -0
- package/dist/router/utils.js +48 -0
- package/dist/router.d.ts +6 -0
- package/dist/router.js +6 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +17 -0
- package/dist/widgets/index.d.ts +8 -0
- package/dist/widgets/index.js +8 -0
- package/dist/widgets/path-prefix-context.d.ts +5 -0
- package/dist/widgets/path-prefix-context.js +9 -0
- package/dist/widgets/plugin-extension-point-client.d.ts +15 -0
- package/dist/widgets/plugin-extension-point-client.js +44 -0
- package/dist/widgets/plugin-extension-point.d.ts +14 -0
- package/dist/widgets/plugin-extension-point.js +51 -0
- package/dist/widgets/plugin-widget-area-client.d.ts +11 -0
- package/dist/widgets/plugin-widget-area-client.js +31 -0
- package/dist/widgets/plugin-widget-area.d.ts +10 -0
- package/dist/widgets/plugin-widget-area.js +19 -0
- package/dist/widgets/use-confirm-action.d.ts +19 -0
- package/dist/widgets/use-confirm-action.js +68 -0
- package/dist/widgets/widget-composer-client.d.ts +21 -0
- package/dist/widgets/widget-composer-client.js +281 -0
- package/dist/widgets/widget-composer.d.ts +8 -0
- package/dist/widgets/widget-composer.js +28 -0
- package/package.json +115 -4
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const PluginManifestSchema = z.object({
|
|
3
|
+
id: z.string(),
|
|
4
|
+
name: z.string(),
|
|
5
|
+
version: z.string(),
|
|
6
|
+
description: z.string().optional(),
|
|
7
|
+
dependencies: z.array(z.string()).default([]),
|
|
8
|
+
extends: z.array(z.string()).default([]),
|
|
9
|
+
enabled: z.boolean().default(true),
|
|
10
|
+
system: z.boolean().default(false),
|
|
11
|
+
hasSetup: z.boolean().default(false),
|
|
12
|
+
author: z.string().optional(),
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Helper to build a `PluginManifest` from a `package.json` import.\n * Eliminates the need for a standalone `manifest.json` file.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import pkg from "../package.json" with { type: "json" };
|
|
20
|
+
* import { createManifestFromPackageJson } from "@veap/framework/plugins";
|
|
21
|
+
* const manifest = createManifestFromPackageJson(pkg);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function createManifestFromPackageJson(pkg) {
|
|
25
|
+
const meta = pkg.veap || {};
|
|
26
|
+
return {
|
|
27
|
+
id: meta.id || pkg.name.replace(/^@[^/]+\//, ""),
|
|
28
|
+
name: meta.name || pkg.name,
|
|
29
|
+
version: pkg.version,
|
|
30
|
+
description: meta.description || pkg.description,
|
|
31
|
+
enabled: meta.enabled ?? true,
|
|
32
|
+
system: meta.system ?? false,
|
|
33
|
+
hasSetup: meta.hasSetup ?? false,
|
|
34
|
+
dependencies: meta.dependencies || [],
|
|
35
|
+
extends: meta.extends || [],
|
|
36
|
+
isNpm: meta.isNpm ?? true,
|
|
37
|
+
author: meta.author,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ServiceProvider } from "@veap/kernel";
|
|
2
|
+
declare module "@veap/kernel" {
|
|
3
|
+
interface ApplicationBuilder {
|
|
4
|
+
/**
|
|
5
|
+
* Registers plugins with the application IoC container and configures PluginsServiceProvider.
|
|
6
|
+
*/
|
|
7
|
+
withPlugins(plugins: any[]): this;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
declare class PluginsConfigProvider extends ServiceProvider {
|
|
11
|
+
private plugins;
|
|
12
|
+
constructor(container: any, plugins?: any[]);
|
|
13
|
+
register(): void;
|
|
14
|
+
}
|
|
15
|
+
export { PluginsConfigProvider };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ApplicationBuilder, ServiceProvider } from "@veap/kernel";
|
|
2
|
+
import { APP_PLUGINS } from "./common/tokens.js";
|
|
3
|
+
import { PluginsServiceProvider } from "./providers/plugins.provider.js";
|
|
4
|
+
class PluginsConfigProvider extends ServiceProvider {
|
|
5
|
+
plugins;
|
|
6
|
+
constructor(container, plugins = []) {
|
|
7
|
+
super(container);
|
|
8
|
+
this.plugins = plugins;
|
|
9
|
+
}
|
|
10
|
+
register() {
|
|
11
|
+
this.container.register({ token: APP_PLUGINS, useValue: this.plugins });
|
|
12
|
+
this.container.register({ token: "AppPlugins", useValue: this.plugins });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (!ApplicationBuilder.prototype.withPlugins) {
|
|
16
|
+
ApplicationBuilder.prototype.withPlugins = function (plugins) {
|
|
17
|
+
return this.use((c) => new PluginsConfigProvider(c, plugins)).use(PluginsServiceProvider);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export { PluginsConfigProvider };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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,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
|
+
}
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./models/index";
|
package/dist/models.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./models/index";
|
|
@@ -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,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, };
|