@realnation/builder-shared-sdk 0.1.1 → 1.0.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/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # @realnation/builder-shared-sdk
2
+
3
+ 一个为Vite模块联邦微前端设计的轻量级SDK,旨在简化Host(宿主应用)与Remote(远程模块)之间的通信和流程控制。
4
+
5
+ ## ✨ 功能
6
+
7
+ - **HTTP客户端共享**: 提供统一的`axios`实例,自动处理鉴权Token,避免在每个Remote中重复配置。
8
+ - **全局事件总线**: 一个简单的发布/订阅系统,用于在Host和Remotes之间或Remotes彼此之间进行解耦的通信。
9
+ - **动态流程控制**: 一个极其灵活的事件驱动流程控制机制,允许Host动态注册回调,由任意Remote在特定时机触发。
10
+
11
+ ## 📦 安装
12
+
13
+ ```bash
14
+ npm install @realnation/builder-shared-sdk
15
+ # or
16
+ yarn add @realnation/builder-shared-sdk
17
+ # or
18
+ pnpm add @realnation/builder-shared-sdk
19
+ ```
20
+
21
+ ## 🚀 快速上手
22
+
23
+ ### 1. 初始化HTTP客户端 (在Host中)
24
+
25
+ 在您的Host应用启动时,配置共享的HTTP客户端。
26
+
27
+ ```typescript
28
+ import { configureHttpClient, setAuthToken } from '@realnation/builder-shared-sdk';
29
+
30
+ // 登录后,从您的用户会话中获取Token
31
+ const userToken = 'your-jwt-token-here';
32
+ setAuthToken(userToken);
33
+
34
+ // 配置API基础URL和超时
35
+ configureHttpClient({
36
+ baseURL: 'https://api.example.com',
37
+ timeout: 15000,
38
+ });
39
+ ```
40
+
41
+ ### 2. 在Remote中使用HTTP客户端
42
+
43
+ 在任何Remote模块中,直接获取已配置好的`axios`实例来发起请求。
44
+
45
+ ```typescript
46
+ import { getHttpClient } from '@realnation/builder-shared-sdk';
47
+
48
+ async function fetchSomeData() {
49
+ try {
50
+ const httpClient = getHttpClient();
51
+ const response = await httpClient.get('/data');
52
+ console.log(response.data);
53
+ } catch (error) {
54
+ console.error('Request failed:', error);
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### 3. 使用全局事件总线
60
+
61
+ `SdkEventBus`可用于在不同模块间传递消息,而无需直接依赖。
62
+
63
+ **在Host或某个Remote中监听事件:**
64
+
65
+ ```typescript
66
+ import { getGlobalEventBus } from '@realnation/builder-shared-sdk';
67
+
68
+ const eventBus = getGlobalEventBus();
69
+
70
+ // 监听模块导航事件
71
+ const unsubscribe = eventBus.on('module:navigate', (payload) => {
72
+ console.log('Navigating to:', payload.path);
73
+ // 在这里执行路由跳转逻辑...
74
+ });
75
+
76
+ // 在组件卸载或不再需要时取消监听
77
+ // unsubscribe();
78
+ ```
79
+
80
+ **在另一个Remote中触发事件:**
81
+
82
+ ```typescript
83
+ import { getGlobalEventBus } from '@realnation/builder-shared-sdk';
84
+
85
+ const eventBus = getGlobalEventBus();
86
+
87
+ function onButtonClick() {
88
+ eventBus.emit('module:navigate', { path: '/new-page' });
89
+ }
90
+ ```
91
+
92
+ ## 🔗 动态流程控制 (Flow Control)
93
+
94
+ 这是SDK的核心亮点之一,提供了一种比传统模块联邦更灵活的模块间协作方式。Host可以定义一组具名事件(例如 `success`, `failure`, `nextStep`),并将它们与具体的操作(例如加载下一个Remote模块)关联起来。Remote模块在完成其任务后,只需触发这些预定义的事件,而无需关心接下来会发生什么。
95
+
96
+ ### 系统事件与自定义事件
97
+
98
+ Flow Control区分两种事件类型:
99
+
100
+ 1. **系统事件 (System Events)**: 以`sys:`为前缀,由SDK或框架约定,用于处理通用的生命周期钩子。例如 `sys:ready`。这些事件**不会**被`clearEvents()`清除。
101
+ 2. **自定义事件 (Custom Events)**: 不带前缀,由业务逻辑定义,例如 `welcome:completed` 或 `profile:submitted`。这些事件会被`clearEvents()`清除。
102
+
103
+ ### 工作流程
104
+
105
+ 1. **Host注册事件**: Host应用使用`registerEvent`注册系统事件和自定义事件的回调。
106
+ * 注册`sys:ready`来处理Remote模块加载完成后的显示逻辑。
107
+ * 注册自定义事件来编排业务流程。
108
+ 2. **Remote触发事件**:
109
+ * Remote模块加载并初始化完成后,应立即触发`sys:ready`事件,通知Host可以将其UI插入DOM并显示。
110
+ * 在用户交互或内部状态改变后,触发相应的自定义事件。
111
+ 3. **执行与回退**:
112
+ * 如果Host注册了该事件,对应的回调函数将被执行。
113
+ * 如果Host**没有**注册该事件,`emitEvent`会执行一个可选的本地回退函数(最后一个函数类型的参数),确保Remote在独立运行时也能正常工作。
114
+ 4. **清理**: 在业务流程结束时,Host调用`clearEvents()`来清理所有**自定义事件**,而系统事件保持不变。
115
+
116
+ ### 代码示例
117
+
118
+ #### 在Host中编排流程
119
+
120
+ ```typescript
121
+ import { registerEvent, clearEvents } from '@realnation/builder-shared-sdk/flow';
122
+ import { loadRemoteModule, showRemote, hideRemote } from './remoteLoader'; // 假设的加载器
123
+
124
+ // 注册系统事件,用于显示已加载的模块
125
+ registerEvent('sys:ready', (remoteId) => {
126
+ console.log(`Remote module [${remoteId}] is ready to be displayed.`);
127
+ showRemote(remoteId);
128
+ });
129
+
130
+ // 注册自定义业务事件
131
+ registerEvent('welcome:completed', () => {
132
+ hideRemote('welcome'); // 隐藏旧模块
133
+ loadRemoteModule('user-profile'); // 加载新模块
134
+ });
135
+
136
+ registerEvent('profile:submitted', (userData) => {
137
+ hideRemote('user-profile');
138
+ loadRemoteModule('summary-view', { user: userData });
139
+ });
140
+
141
+ // 当整个业务流程结束时,清理自定义事件
142
+ function cleanupBusinessFlow() {
143
+ clearEvents();
144
+ }
145
+ ```
146
+
147
+ #### 在Remote中触发事件
148
+
149
+ **`welcome-module` (远程模块):**
150
+
151
+ ```typescript
152
+ import { emitEvent } from '@realnation/builder-shared-sdk/flow';
153
+ import React, { useEffect } from 'react';
154
+
155
+ function WelcomeComponent({ remoteId }) {
156
+ // 1. 组件挂载后,触发 sys:ready 事件
157
+ useEffect(() => {
158
+ emitEvent('sys:ready', remoteId, () => {
159
+ console.log(`Standalone mode: [${remoteId}] is ready.`);
160
+ });
161
+ }, [remoteId]);
162
+
163
+ const handleStartClick = () => {
164
+ // 2. 用户交互,触发自定义事件
165
+ emitEvent('welcome:completed', () => {
166
+ console.log('Standalone mode: Welcome journey would start here.');
167
+ });
168
+ };
169
+
170
+ return <button onClick={handleStartClick}>开始</button>;
171
+ }
172
+ ```
173
+
174
+ **`user-profile-module` (远程模块):**
175
+
176
+ ```typescript
177
+ import { emitEvent } from '@realnation/builder-shared-sdk/flow';
178
+
179
+ function UserProfileForm() {
180
+ const handleSubmit = (formData) => {
181
+ // 触发 'profile:submitted' 事件,并传递表单数据
182
+ emitEvent('profile:submitted', formData, () => {
183
+ console.log('In standalone mode: Form submitted locally.', formData);
184
+ // 在独立模式下可以导航到本地的下一页
185
+ });
186
+ };
187
+
188
+ // ... 表单逻辑
189
+ }
190
+ ```
191
+
192
+ 这种模式的优势在于:
193
+
194
+ - **高度解耦**: Remote模块不关心下一个模块是什么,只关心在何时完成了自己的任务。
195
+ - **灵活编排**: Host可以随时改变流程,例如在A/B测试中,通过注册不同的回调来加载不同的下一个模块,而无需修改任何Remote模块的代码。
196
+ - **易于测试**: Remote模块可以独立开发和测试,只需为其`emitEvent`提供本地回退函数即可。
197
+
198
+ ## 🛠️ API参考
199
+
200
+ ### HTTP
201
+
202
+ - `setAuthToken(token: string | null)`: 设置全局JWT Token。
203
+ - `setTokenResolver(resolver: () => string | null)`: (高级) 设置一个函数来动态解析Token,优先级高于`setAuthToken`。
204
+ - `configureHttpClient(options: HttpClientOptions)`: 配置共享的`axios`实例。
205
+ - `getHttpClient(): AxiosInstance`: 获取配置好的`axios`实例。
206
+
207
+ ### Events
208
+
209
+ - `getGlobalEventBus(): SdkEventBus`: 获取全局事件总线实例。
210
+ - `eventBus.on(name, handler)`: 监听一个事件。
211
+ - `eventBus.emit(name, payload)`: 触发一个事件。
212
+ - `eventBus.off(name, handler)`: 取消监听。
213
+
214
+ ### Flow
215
+
216
+ - `registerEvent(type: string, callback: Function)`: Host注册一个流程事件。以`sys:`为前缀的事件为系统事件,不会被`clearEvents`清除。
217
+ - `removeEvent(type: string)`: 移除一个已注册的事件。
218
+ - `clearEvents()`: 移除所有**非系统级**的自定义事件。
219
+ - `emitEvent(type: string, ...args: any[])`: Remote触发一个流程事件。参数会透传给回调,如果最后一个参数是函数,则被视作本地回退`callback`。
220
+
221
+ ## 🔧 构建
222
+
223
+ ```bash
224
+ npm run build
225
+ ```
226
+
227
+ 该命令会使用`tsc`将`src`目录下的TypeScript源文件编译到`dist`目录。
package/dist/flow.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Host 注册一个事件回调。
3
+ * @param type 事件名称。以 'sys:' 开头的为系统事件,不会被 clearEvents 清除。
4
+ * @param callback 事件触发时执行的回调函数。
5
+ */
6
+ export declare const registerEvent: (type: string, callback: Function) => void;
7
+ /**
8
+ * 移除一个已注册的事件。
9
+ * @param type 要移除的事件名称。
10
+ */
11
+ export declare const removeEvent: (type: string) => void;
12
+ /**
13
+ * 清除所有非系统级的自定义事件。
14
+ */
15
+ export declare const clearEvents: () => void;
16
+ /**
17
+ * Remote 触发一个事件。
18
+ * @param type 事件名称。
19
+ * @param args 传递给事件回调的参数。如果最后一个参数是函数,它将被当作本地回退使用。
20
+ */
21
+ export declare const emitEvent: (type: string, ...args: any[]) => void;
22
+ //# sourceMappingURL=flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,UAAU,QAAQ,SAM7D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,SAMvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,YAIvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,EAAE,SASrD,CAAC"}
package/dist/flow.js ADDED
@@ -0,0 +1,51 @@
1
+ const systemEvents = {};
2
+ const customEvents = {};
3
+ const isSystemEvent = (type) => type.startsWith('sys:');
4
+ /**
5
+ * Host 注册一个事件回调。
6
+ * @param type 事件名称。以 'sys:' 开头的为系统事件,不会被 clearEvents 清除。
7
+ * @param callback 事件触发时执行的回调函数。
8
+ */
9
+ export const registerEvent = (type, callback) => {
10
+ if (isSystemEvent(type)) {
11
+ systemEvents[type] = callback;
12
+ }
13
+ else {
14
+ customEvents[type] = callback;
15
+ }
16
+ };
17
+ /**
18
+ * 移除一个已注册的事件。
19
+ * @param type 要移除的事件名称。
20
+ */
21
+ export const removeEvent = (type) => {
22
+ if (isSystemEvent(type)) {
23
+ delete systemEvents[type];
24
+ }
25
+ else {
26
+ delete customEvents[type];
27
+ }
28
+ };
29
+ /**
30
+ * 清除所有非系统级的自定义事件。
31
+ */
32
+ export const clearEvents = () => {
33
+ for (const key in customEvents) {
34
+ delete customEvents[key];
35
+ }
36
+ };
37
+ /**
38
+ * Remote 触发一个事件。
39
+ * @param type 事件名称。
40
+ * @param args 传递给事件回调的参数。如果最后一个参数是函数,它将被当作本地回退使用。
41
+ */
42
+ export const emitEvent = (type, ...args) => {
43
+ const eventHandler = customEvents[type] ?? systemEvents[type];
44
+ const fallback = args.length > 0 && typeof args[args.length - 1] === 'function' ? args.pop() : null;
45
+ if (eventHandler) {
46
+ eventHandler(...args);
47
+ }
48
+ else if (fallback) {
49
+ fallback();
50
+ }
51
+ };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './types';
2
2
  export * from './http';
3
3
  export * from './events';
4
+ export * from './flow';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './types';
2
2
  export * from './http';
3
3
  export * from './events';
4
+ export * from './flow';
package/dist/types.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface RequestContext {
8
8
  headers?: Record<string, string>;
9
9
  }
10
10
  export type EventPayload = Record<string, unknown>;
11
- export type SdkEventName = 'sdk:ready' | 'sdk:error' | 'module:navigate' | 'module:metrics' | 'module:error' | 'module:open-surface' | 'module:close-surface' | 'host:refresh-token';
11
+ export type SdkEventName = 'sdk:ready' | 'sdk:error' | 'module:navigate' | 'module:metrics' | 'module:error' | 'module:open-surface' | 'module:close-surface' | 'module:load-component' | 'host:refresh-token';
12
12
  export interface ModuleSurfaceRequest extends EventPayload {
13
13
  surfaceId: string;
14
14
  title?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,GACtB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,yBAA0B,SAAQ,YAAY;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ,CAAC,QAAQ,SAAS,YAAY,GAAG,YAAY;IACpE,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,GACtB,uBAAuB,GACvB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,yBAA0B,SAAQ,YAAY;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ,CAAC,QAAQ,SAAS,YAAY,GAAG,YAAY;IACpE,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;CACnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realnation/builder-shared-sdk",
3
- "version": "0.1.1",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "exports": {