@bbki.ng/site 5.7.0 → 5.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/index.html +0 -11
- package/package.json +1 -1
- package/src/app/app.tsx +1 -2
- package/src/core/components/SlotComp.tsx +2 -3
- package/src/core/hooks/useMiddlewareTransData.ts +12 -7
- package/src/core/hooks/useSlotComp.ts +8 -7
- package/src/core/hooks/use_plugins.ts +27 -14
- package/src/core/plugin-system/pluginManager.ts +129 -0
- package/src/core/{pluginManifestService.ts → plugin-system/pluginManifestService.ts} +2 -3
- package/src/core/plugin-system/pluginStore.ts +190 -0
- package/src/core/{registry.ts → plugin-system/registry.ts} +1 -3
- package/src/core/plugin-system/services/coreService.ts +56 -0
- package/src/core/plugin-system/services/systemUIService.ts +159 -0
- package/src/core/shared-service/contract/ICoreService.ts +23 -0
- package/src/core/shared-service/contract/IUIService.ts +49 -0
- package/src/core/shared-service/service-proxy.ts +26 -0
- package/src/core/shared-service/service-registry.ts +52 -0
- package/src/plugins/blog/components/BlogSlotCom.tsx +27 -0
- package/src/plugins/blog/components/article/index.tsx +2 -2
- package/src/plugins/blog/context/index.ts +0 -4
- package/src/plugins/blog/hooks/useMiddlewareTransData.ts +79 -0
- package/src/plugins/blog/hooks/use_blog_scroll_pos_restoration.ts +2 -2
- package/src/plugins/blog/hooks/use_blog_slot_com.ts +27 -0
- package/src/plugins/blog/hooks/use_posts.ts +3 -2
- package/src/plugins/blog/index.ts +32 -5
- package/src/plugins/blog/pages/extensions/txt/article.tsx +2 -2
- package/src/plugins/blog/services/BlogUIService.ts +120 -0
- package/src/plugins/blog/services/IBlogUIService.ts +31 -0
- package/src/plugins/extra-cd/index.ts +13 -2
- package/src/plugins/extra-entry/index.ts +8 -4
- package/src/plugins/fx/index.ts +18 -5
- package/src/plugins/manifest.ts +2 -6
- package/src/plugins/now/hooks/use_streaming.ts +3 -1
- package/src/plugins/now/index.ts +17 -6
- package/src/plugins/sticker/const.ts +2 -2
- package/src/plugins/sticker/index.ts +18 -3
- package/src/plugins/store/components/storePage.tsx +13 -2
- package/src/plugins/store/context/index.ts +1 -0
- package/src/plugins/store/index.ts +18 -7
- package/src/plugins/xwy/index.ts +24 -19
- package/src/plugins/xwy/types/index.ts +0 -18
- package/src/types/hostApi.ts +3 -34
- package/src/types/plugin.ts +1 -0
- package/src/utils/index.tsx +1 -48
- package/vite.config.js +1 -1
- package/src/core/pluginManager.ts +0 -191
- package/src/core/pluginStore.ts +0 -70
- /package/src/core/{bbplugin.ts → plugin-system/bbplugin.ts} +0 -0
package/src/utils/index.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PathRouteProps } from 'react-router-dom';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
import { IHostContext } from '#/types/hostApi';
|
|
5
4
|
import { IPluginEntry } from '#/types/plugin';
|
|
6
5
|
import { IComPropsRegisteredToSlot } from '#/types/slots';
|
|
7
6
|
|
|
@@ -19,49 +18,3 @@ export const buildEntrySlotCom = (entry: IPluginEntry) => {
|
|
|
19
18
|
|
|
20
19
|
return Component;
|
|
21
20
|
};
|
|
22
|
-
|
|
23
|
-
export const buildEntryCreator = (ctx: IHostContext) => (entry: IPluginEntry, id: string) => {
|
|
24
|
-
ctx.api.registerMiddleware(
|
|
25
|
-
'extendedRoutes',
|
|
26
|
-
(routes: Array<Omit<PathRouteProps, 'element'>>) => {
|
|
27
|
-
return [
|
|
28
|
-
...routes,
|
|
29
|
-
{
|
|
30
|
-
path: entry.path,
|
|
31
|
-
},
|
|
32
|
-
];
|
|
33
|
-
},
|
|
34
|
-
id,
|
|
35
|
-
10
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
ctx.api.registerSlot(
|
|
39
|
-
'route',
|
|
40
|
-
(props: IComPropsRegisteredToSlot) => {
|
|
41
|
-
const route = props.data as Omit<PathRouteProps, 'element'>;
|
|
42
|
-
if (route.path === entry.path) {
|
|
43
|
-
const Com = entry.pageComponent;
|
|
44
|
-
return <Com data={props.data} />;
|
|
45
|
-
}
|
|
46
|
-
return null;
|
|
47
|
-
},
|
|
48
|
-
id
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
if (!entry.label) return;
|
|
52
|
-
|
|
53
|
-
ctx.api.registerMiddleware(
|
|
54
|
-
'transformCoverEntry',
|
|
55
|
-
(entries: Array<LinkProps>) => {
|
|
56
|
-
return [
|
|
57
|
-
...entries,
|
|
58
|
-
{
|
|
59
|
-
to: entry.path,
|
|
60
|
-
children: entry.label,
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
},
|
|
64
|
-
id,
|
|
65
|
-
10
|
|
66
|
-
);
|
|
67
|
-
};
|
package/vite.config.js
CHANGED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { PathRouteProps } from 'react-router-dom';
|
|
3
|
-
import { LinkProps } from '@bbki.ng/ui';
|
|
4
|
-
|
|
5
|
-
import { IHostContext } from '#/types/hostApi';
|
|
6
|
-
import type { SlotName, HookPoint, IComPropsRegisteredToSlot } from '#/types/slots';
|
|
7
|
-
import { IPlugin, IPluginEntry, PluginEvents, PluginID, PluginPerm } from '#/types/plugin';
|
|
8
|
-
import { getStableDeviceId } from '#/app/utils/fingerprints';
|
|
9
|
-
import { cfApiFetcher } from '#/app/utils';
|
|
10
|
-
import { buildEntrySlotCom } from '#/utils';
|
|
11
|
-
|
|
12
|
-
import { registry } from './registry';
|
|
13
|
-
import { createEventBus } from './utils/eventBus';
|
|
14
|
-
import { AdminPluginIDSet } from './const';
|
|
15
|
-
import { PluginStore } from './pluginStore';
|
|
16
|
-
|
|
17
|
-
const pluginModules = import.meta.glob('../plugins/*/index.ts');
|
|
18
|
-
|
|
19
|
-
class PluginManager {
|
|
20
|
-
private activePlugins: Map<string, IPlugin> = new Map();
|
|
21
|
-
|
|
22
|
-
private bus = createEventBus<PluginEvents>();
|
|
23
|
-
|
|
24
|
-
private registryEntry = (entry: IPluginEntry, id: string) => {
|
|
25
|
-
this.registerMiddleware(
|
|
26
|
-
'extendedRoutes',
|
|
27
|
-
(routes: Array<Omit<PathRouteProps, 'element'>>) => {
|
|
28
|
-
return [
|
|
29
|
-
...routes,
|
|
30
|
-
{
|
|
31
|
-
path: entry.path,
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
},
|
|
35
|
-
id,
|
|
36
|
-
10
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
this.registerSlot('route', buildEntrySlotCom(entry), id);
|
|
40
|
-
|
|
41
|
-
if (!entry.label) return;
|
|
42
|
-
|
|
43
|
-
this.registerMiddleware(
|
|
44
|
-
'transformCoverEntry',
|
|
45
|
-
(entries: Array<LinkProps>) => {
|
|
46
|
-
return [
|
|
47
|
-
...entries,
|
|
48
|
-
{
|
|
49
|
-
to: entry.path,
|
|
50
|
-
children: entry.label,
|
|
51
|
-
},
|
|
52
|
-
];
|
|
53
|
-
},
|
|
54
|
-
id,
|
|
55
|
-
10
|
|
56
|
-
);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
private registerMiddleware = <T>(
|
|
60
|
-
point: HookPoint,
|
|
61
|
-
fn: (data: T) => Promise<T> | T,
|
|
62
|
-
pluginId: string,
|
|
63
|
-
weight = 0
|
|
64
|
-
) => {
|
|
65
|
-
registry.registerMiddleware(point, fn, pluginId, weight);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
private registerSlot = (
|
|
69
|
-
slotName: SlotName,
|
|
70
|
-
component: React.ComponentType<IComPropsRegisteredToSlot>,
|
|
71
|
-
pluginId: string,
|
|
72
|
-
weight = 0
|
|
73
|
-
) => {
|
|
74
|
-
registry.registerComponent(slotName, component, pluginId, weight);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
private createHostContext(perm: PluginPerm = 'guest'): IHostContext {
|
|
78
|
-
const adminCtx =
|
|
79
|
-
perm === 'admin'
|
|
80
|
-
? {
|
|
81
|
-
store: PluginStore.getInstance(),
|
|
82
|
-
}
|
|
83
|
-
: {};
|
|
84
|
-
return {
|
|
85
|
-
...adminCtx,
|
|
86
|
-
api: {
|
|
87
|
-
fetch: cfApiFetcher,
|
|
88
|
-
setLoading: (id: PluginID, loading: boolean) => {
|
|
89
|
-
this.bus.emit('plugin:loading:changed', { id, loading });
|
|
90
|
-
},
|
|
91
|
-
onLoadingChanged: (listener: (payload: PluginEvents['site:loading:changed']) => void) => {
|
|
92
|
-
return this.bus.on('site:loading:changed', listener);
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
getDeviceId: getStableDeviceId,
|
|
96
|
-
getVersionHash: () => {
|
|
97
|
-
const hashStr: string =
|
|
98
|
-
typeof GLOBAL_COMMIT_HASH === 'string' ? GLOBAL_COMMIT_HASH : '0000000';
|
|
99
|
-
return hashStr;
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
registerSlot: this.registerSlot,
|
|
103
|
-
registerMiddleware: this.registerMiddleware,
|
|
104
|
-
registerEntry: this.registryEntry,
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private loading = new Set<string>();
|
|
110
|
-
|
|
111
|
-
notifySiteLoadingChanged(loading: boolean) {
|
|
112
|
-
this.bus.emit('site:loading:changed', loading);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
subscribePluginLoading(listener: (payload: PluginEvents['plugin:loading:changed']) => void) {
|
|
116
|
-
return this.bus.on('plugin:loading:changed', listener);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// enable abort ctrl
|
|
120
|
-
async loadPlugin(pluginId: PluginID) {
|
|
121
|
-
if (this.activePlugins.has(pluginId)) {
|
|
122
|
-
console.warn(`Plugin ${pluginId} is already loaded.`);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (this.loading.has(pluginId)) {
|
|
127
|
-
console.warn(`Plugin ${pluginId} is loading...`);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// try load plugin
|
|
132
|
-
this.loading.add(pluginId);
|
|
133
|
-
this.bus.emit('plugin:loading:changed', { id: pluginId, loading: true });
|
|
134
|
-
|
|
135
|
-
const modulePath = `../plugins/${pluginId}/index.ts`;
|
|
136
|
-
const moduleLoader = pluginModules[modulePath];
|
|
137
|
-
if (!moduleLoader) {
|
|
138
|
-
console.error(`Plugin ${pluginId} not found in registry`);
|
|
139
|
-
|
|
140
|
-
this.loading.delete(pluginId);
|
|
141
|
-
this.bus.emit('plugin:loading:changed', { id: pluginId, loading: false });
|
|
142
|
-
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
const module = (await moduleLoader()) as {
|
|
148
|
-
default: IPlugin;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const p: IPlugin = module.default;
|
|
152
|
-
|
|
153
|
-
const perm = p.getMeta().perm || 'guest';
|
|
154
|
-
if (perm === 'admin' && !AdminPluginIDSet.has(pluginId)) {
|
|
155
|
-
console.error(`Plugin ${pluginId} requires admin permission, but it's not trusted.`);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const ctx = this.createHostContext(perm);
|
|
160
|
-
|
|
161
|
-
if (p.onInstall) {
|
|
162
|
-
await p.onInstall(ctx);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
this.activePlugins.set(pluginId, p);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.error(`Failed to load plugin ${pluginId}:`, error);
|
|
168
|
-
} finally {
|
|
169
|
-
this.loading.delete(pluginId);
|
|
170
|
-
this.bus.emit('plugin:loading:changed', { id: pluginId, loading: false });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async disablePlugin(pluginId: PluginID) {
|
|
175
|
-
const plugin = this.activePlugins.get(pluginId);
|
|
176
|
-
if (!plugin) {
|
|
177
|
-
console.warn(`Plugin ${pluginId} is not loaded.`);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (plugin.onDisable) {
|
|
182
|
-
await plugin.onDisable();
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
this.activePlugins.delete(pluginId);
|
|
186
|
-
|
|
187
|
-
registry.unregisterAllByPluginId(plugin.id);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export const pluginManager = new PluginManager();
|
package/src/core/pluginStore.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { IPluginStoreEntry, PluginID } from '#/types/plugin';
|
|
2
|
-
|
|
3
|
-
import { pluginManager } from './pluginManager';
|
|
4
|
-
import { PluginManifestService } from './pluginManifestService';
|
|
5
|
-
|
|
6
|
-
export class PluginStore {
|
|
7
|
-
private static instance: PluginStore;
|
|
8
|
-
|
|
9
|
-
private installedSet: Set<PluginID> = new Set();
|
|
10
|
-
|
|
11
|
-
private constructor() {
|
|
12
|
-
this.parse();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
private parse = () => {
|
|
16
|
-
this.installedSet.clear();
|
|
17
|
-
const installedPluginsStr = localStorage.getItem('installed_plugins');
|
|
18
|
-
if (installedPluginsStr) {
|
|
19
|
-
try {
|
|
20
|
-
const entries = JSON.parse(installedPluginsStr) as Array<PluginID>;
|
|
21
|
-
entries.forEach(id => this.installedSet.add(id));
|
|
22
|
-
} catch (e) {
|
|
23
|
-
console.error('Failed to parse installed plugins from localStorage', e);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return this.installedSet;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
private stringify = () => {
|
|
31
|
-
localStorage.setItem('installed_plugins', JSON.stringify(Array.from(this.installedSet)));
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
getInstalledPlugins: () => Set<PluginID> = () => {
|
|
35
|
-
return this.parse();
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
async getAllPlugins(): Promise<Array<IPluginStoreEntry>> {
|
|
39
|
-
const installedPlugins = this.getInstalledPlugins();
|
|
40
|
-
await PluginManifestService.getInstance().fetch();
|
|
41
|
-
const manifest = PluginManifestService.getInstance().getAllPlugins();
|
|
42
|
-
return manifest.map(plugin => ({
|
|
43
|
-
...plugin,
|
|
44
|
-
enabled: installedPlugins.has(plugin.id),
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
isPluginInstalled: (id: PluginID) => boolean = id => {
|
|
49
|
-
return this.getInstalledPlugins().has(id);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
installPlugin: (id: PluginID) => Promise<void> = async id => {
|
|
53
|
-
await pluginManager.loadPlugin(id);
|
|
54
|
-
this.installedSet.add(id);
|
|
55
|
-
this.stringify();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
disablePlugin: (id: PluginID) => Promise<void> = async id => {
|
|
59
|
-
await pluginManager.disablePlugin(id);
|
|
60
|
-
this.installedSet.delete(id);
|
|
61
|
-
this.stringify();
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
static getInstance() {
|
|
65
|
-
if (!PluginStore.instance) {
|
|
66
|
-
PluginStore.instance = new PluginStore();
|
|
67
|
-
}
|
|
68
|
-
return PluginStore.instance;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
File without changes
|