webloom-framework 0.3.0 → 0.4.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 +70 -42
- package/dist/advanced.d.ts +168 -0
- package/dist/advanced.js +441 -0
- package/dist/advanced.js.map +1 -0
- package/dist/chunk-4DSINPZD.js +158 -0
- package/dist/chunk-4DSINPZD.js.map +1 -0
- package/dist/chunk-ANA6GBEI.js +1737 -0
- package/dist/chunk-ANA6GBEI.js.map +1 -0
- package/dist/chunk-HJKPKWI7.js +4024 -0
- package/dist/chunk-HJKPKWI7.js.map +1 -0
- package/dist/chunk-SX46RHDI.js +433 -0
- package/dist/chunk-SX46RHDI.js.map +1 -0
- package/dist/index.d.ts +39 -259
- package/dist/index.js +38 -1359
- package/dist/index.js.map +1 -1
- package/dist/messageBus-CtrwkjrO.d.ts +5 -0
- package/dist/messagePortServiceTransport-BYprNvQY.d.ts +264 -0
- package/dist/react.d.ts +41 -28
- package/dist/react.js +79 -88
- package/dist/react.js.map +1 -1
- package/dist/runtimeTypes-DquUCHz-.d.ts +1640 -0
- package/dist/sharedWorkerHost-KI7TIGdX.d.ts +192 -0
- package/dist/testing.d.ts +18 -17
- package/dist/testing.js +23 -15
- package/dist/testing.js.map +1 -1
- package/dist/windowRuntime-BKkLPsAS.d.ts +23 -0
- package/docs/api.md +148 -111
- package/docs/proposals/webloom-v4/implementation-plan.md +443 -0
- package/docs/proposals/webloom-v4/requirements.md +555 -0
- package/docs/proposals/webloom-v4/verification.md +115 -0
- package/package.json +11 -2
- package/dist/chunk-76BGPI6M.js +0 -4261
- package/dist/chunk-76BGPI6M.js.map +0 -1
- package/dist/createPluginHost-BVsUCDKN.d.ts +0 -1318
- package/dist/resourceRegistry-BFnjmeGE.d.ts +0 -267
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { T as PluginSetup, K as Capability, bj as RuntimeUnitImplementationRegistry, aH as PluginIntentSnapshot, aF as PluginIntentController, a$ as ResourceRegistry, aZ as ResourceDefinition, bd as RuntimeSnapshot, R as RuntimeKind, aN as PluginStateKind, Y as CapabilityBridge } from './runtimeTypes-DquUCHz-.js';
|
|
2
|
+
import { R as ReceivePortLedger, a as RuntimeLimitsInput, b as RuntimeBudget } from './sharedWorkerHost-KI7TIGdX.js';
|
|
3
|
+
|
|
4
|
+
interface RuntimeUnitImplementation {
|
|
5
|
+
/** 产品标识。 */
|
|
6
|
+
pluginId: string;
|
|
7
|
+
/** 稳定运行单元标识。 */
|
|
8
|
+
unitId: string;
|
|
9
|
+
/** 当前环境的可执行入口。 */
|
|
10
|
+
setup: PluginSetup;
|
|
11
|
+
/** 当前 realm 的 typed capability 定义。 */
|
|
12
|
+
capabilities?: readonly Capability[];
|
|
13
|
+
}
|
|
14
|
+
/** 创建一个拒绝重复注册、按产品和单元查找实现的运行时注册表。 */
|
|
15
|
+
declare function createRuntimeUnitImplementationRegistry(implementations?: readonly RuntimeUnitImplementation[]): RuntimeUnitImplementationRegistry & {
|
|
16
|
+
register(implementation: RuntimeUnitImplementation): void;
|
|
17
|
+
unregister(pluginId: string, unitId: string): void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
interface CreatePluginIntentControllerOptions {
|
|
21
|
+
/** 当前控制面启动身份;Worker 重启时应传入新值。 */
|
|
22
|
+
authorityInstanceId?: string;
|
|
23
|
+
/** Worker 恢复后读取的平台意图。 */
|
|
24
|
+
initial?: Partial<PluginIntentSnapshot>;
|
|
25
|
+
/** 将候选快照原子写入平台存储;缺省表示内存控制面(测试用)。 */
|
|
26
|
+
persist?: (snapshot: PluginIntentSnapshot) => Promise<void>;
|
|
27
|
+
/** 有界去重记录数量,避免 commandId 永久增长。 */
|
|
28
|
+
maxCommandRecords?: number;
|
|
29
|
+
}
|
|
30
|
+
/** 创建单一控制面上的插件意图控制器。 */
|
|
31
|
+
declare function createPluginIntentController(options?: CreatePluginIntentControllerOptions): PluginIntentController;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 资源注册表实现
|
|
35
|
+
*
|
|
36
|
+
* 设计缘由:管理资源定义的注册和查询,支持 owner-aware 生命周期。
|
|
37
|
+
* 重复 id 抛错,disable 时可回收。
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/** 资源注册表实现 */
|
|
41
|
+
declare function createResourceRegistry(): ResourceRegistry;
|
|
42
|
+
/** Internal runtime hook; deliberately absent from ResourceRegistry's public type. */
|
|
43
|
+
declare function registerOwnedResource(registry: ResourceRegistry, ownerId: string, definition: ResourceDefinition<any, any>): void;
|
|
44
|
+
|
|
45
|
+
declare const RUNTIME_PROTOCOL_VERSION: "webloom.runtime.v1";
|
|
46
|
+
declare const RUNTIME_SNAPSHOT_TYPE: "webloom.runtime.v1.snapshot";
|
|
47
|
+
declare const RUNTIME_ERROR_TYPE: "webloom.runtime.v1.runtime-error";
|
|
48
|
+
declare const RUNTIME_CALL_TYPE: "webloom.runtime.v1.call";
|
|
49
|
+
declare const RUNTIME_RESULT_TYPE: "webloom.runtime.v1.result";
|
|
50
|
+
declare const RUNTIME_ERROR_MESSAGE_TYPE: "webloom.runtime.v1.error";
|
|
51
|
+
declare const RUNTIME_CANCEL_TYPE: "webloom.runtime.v1.cancel";
|
|
52
|
+
declare const RUNTIME_NEXT_TYPE: "webloom.runtime.v1.next";
|
|
53
|
+
declare const RUNTIME_CREDIT_TYPE: "webloom.runtime.v1.credit";
|
|
54
|
+
interface RuntimeSnapshotUnit {
|
|
55
|
+
/** 插件标识。 */
|
|
56
|
+
readonly pluginId: string;
|
|
57
|
+
/** 单元标识。 */
|
|
58
|
+
readonly unitId: string;
|
|
59
|
+
/** Runtime。 */
|
|
60
|
+
readonly runtime: RuntimeKind;
|
|
61
|
+
/** 实例标识。 */
|
|
62
|
+
readonly instanceId?: string;
|
|
63
|
+
/** 状态。 */
|
|
64
|
+
readonly state: PluginStateKind;
|
|
65
|
+
}
|
|
66
|
+
type RuntimeSnapshotMessage = RuntimeSnapshot & {
|
|
67
|
+
readonly type: typeof RUNTIME_SNAPSHOT_TYPE;
|
|
68
|
+
};
|
|
69
|
+
interface RuntimeErrorMessage {
|
|
70
|
+
/** 消息类型。 */
|
|
71
|
+
readonly type: typeof RUNTIME_ERROR_TYPE;
|
|
72
|
+
/** 协议版本。 */
|
|
73
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
74
|
+
/** 结构化错误码。 */
|
|
75
|
+
readonly code: string;
|
|
76
|
+
/** 脱敏消息。 */
|
|
77
|
+
readonly message: string;
|
|
78
|
+
/** 失败阶段。 */
|
|
79
|
+
readonly phase: "validate" | "wait" | "dispatch" | "execute" | "receive" | "dispose";
|
|
80
|
+
/** 可选插件标识。 */
|
|
81
|
+
readonly pluginId?: string;
|
|
82
|
+
/** 可选单元标识。 */
|
|
83
|
+
readonly unitId?: string;
|
|
84
|
+
}
|
|
85
|
+
interface RuntimeCallMessage {
|
|
86
|
+
/** 消息类型。 */
|
|
87
|
+
readonly type: typeof RUNTIME_CALL_TYPE;
|
|
88
|
+
/** 协议版本。 */
|
|
89
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
90
|
+
/** 方向内唯一 call id。 */
|
|
91
|
+
readonly callId: string;
|
|
92
|
+
/** capability 标识。 */
|
|
93
|
+
readonly capabilityId: string;
|
|
94
|
+
/** 契约版本。 */
|
|
95
|
+
readonly contractVersion: string;
|
|
96
|
+
/** exposure 身份。 */
|
|
97
|
+
readonly serviceInstanceId: string;
|
|
98
|
+
/** 调用模式。 */
|
|
99
|
+
readonly mode: "unary" | "stream";
|
|
100
|
+
/** 本次派发的剩余预算。 */
|
|
101
|
+
readonly timeoutMs: number;
|
|
102
|
+
/** 已 parser 验证的请求。 */
|
|
103
|
+
readonly request: unknown;
|
|
104
|
+
/** 产品操作标识。 */
|
|
105
|
+
readonly operationId?: string;
|
|
106
|
+
/** 领域授权标识。 */
|
|
107
|
+
readonly grantId?: string;
|
|
108
|
+
/** stream 初始 credit。 */
|
|
109
|
+
readonly initialCredit?: number;
|
|
110
|
+
}
|
|
111
|
+
interface RuntimeUnaryResultMessage {
|
|
112
|
+
/** 消息类型。 */
|
|
113
|
+
readonly type: typeof RUNTIME_RESULT_TYPE;
|
|
114
|
+
/** 协议版本。 */
|
|
115
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
116
|
+
/** call id。 */
|
|
117
|
+
readonly callId: string;
|
|
118
|
+
/** exposure 身份。 */
|
|
119
|
+
readonly serviceInstanceId: string;
|
|
120
|
+
/** unary 结果。 */
|
|
121
|
+
readonly result: unknown;
|
|
122
|
+
}
|
|
123
|
+
interface RuntimeStreamReadyMessage {
|
|
124
|
+
/** 消息类型。 */
|
|
125
|
+
readonly type: typeof RUNTIME_RESULT_TYPE;
|
|
126
|
+
/** 协议版本。 */
|
|
127
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
128
|
+
/** call id。 */
|
|
129
|
+
readonly callId: string;
|
|
130
|
+
/** exposure 身份。 */
|
|
131
|
+
readonly serviceInstanceId: string;
|
|
132
|
+
/** stream 建立确认。 */
|
|
133
|
+
readonly streamReady: true;
|
|
134
|
+
}
|
|
135
|
+
interface RuntimeStreamDoneMessage {
|
|
136
|
+
/** 消息类型。 */
|
|
137
|
+
readonly type: typeof RUNTIME_RESULT_TYPE;
|
|
138
|
+
/** 协议版本。 */
|
|
139
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
140
|
+
/** call id。 */
|
|
141
|
+
readonly callId: string;
|
|
142
|
+
/** exposure 身份。 */
|
|
143
|
+
readonly serviceInstanceId: string;
|
|
144
|
+
/** stream 正常结束。 */
|
|
145
|
+
readonly done: true;
|
|
146
|
+
}
|
|
147
|
+
type RuntimeResultMessage = RuntimeUnaryResultMessage | RuntimeStreamReadyMessage | RuntimeStreamDoneMessage;
|
|
148
|
+
interface RuntimeErrorResponseMessage {
|
|
149
|
+
/** 消息类型。 */
|
|
150
|
+
readonly type: typeof RUNTIME_ERROR_MESSAGE_TYPE;
|
|
151
|
+
/** 协议版本。 */
|
|
152
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
153
|
+
/** call id。 */
|
|
154
|
+
readonly callId: string;
|
|
155
|
+
/** exposure 身份。 */
|
|
156
|
+
readonly serviceInstanceId: string;
|
|
157
|
+
/** 结构化错误。 */
|
|
158
|
+
readonly error: {
|
|
159
|
+
readonly code: string;
|
|
160
|
+
readonly message: string;
|
|
161
|
+
readonly phase: RuntimeErrorMessage["phase"];
|
|
162
|
+
readonly details?: Readonly<Record<string, unknown>>;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
interface RuntimeCancelMessage {
|
|
166
|
+
/** 消息类型。 */
|
|
167
|
+
readonly type: typeof RUNTIME_CANCEL_TYPE;
|
|
168
|
+
/** 协议版本。 */
|
|
169
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
170
|
+
/** call id。 */
|
|
171
|
+
readonly callId: string;
|
|
172
|
+
/** exposure 身份。 */
|
|
173
|
+
readonly serviceInstanceId: string;
|
|
174
|
+
}
|
|
175
|
+
interface RuntimeNextMessage {
|
|
176
|
+
/** 消息类型。 */
|
|
177
|
+
readonly type: typeof RUNTIME_NEXT_TYPE;
|
|
178
|
+
/** 协议版本。 */
|
|
179
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
180
|
+
/** call id。 */
|
|
181
|
+
readonly callId: string;
|
|
182
|
+
/** exposure 身份。 */
|
|
183
|
+
readonly serviceInstanceId: string;
|
|
184
|
+
/** 连续序号。 */
|
|
185
|
+
readonly sequence: number;
|
|
186
|
+
/** parser 验证的 item。 */
|
|
187
|
+
readonly item: unknown;
|
|
188
|
+
}
|
|
189
|
+
interface RuntimeCreditMessage {
|
|
190
|
+
/** 消息类型。 */
|
|
191
|
+
readonly type: typeof RUNTIME_CREDIT_TYPE;
|
|
192
|
+
/** 协议版本。 */
|
|
193
|
+
readonly protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
|
|
194
|
+
/** call id。 */
|
|
195
|
+
readonly callId: string;
|
|
196
|
+
/** exposure 身份。 */
|
|
197
|
+
readonly serviceInstanceId: string;
|
|
198
|
+
/** 新增 credit。 */
|
|
199
|
+
readonly count: number;
|
|
200
|
+
}
|
|
201
|
+
type RuntimeWireMessage = RuntimeSnapshotMessage | RuntimeErrorMessage | RuntimeCallMessage | RuntimeResultMessage | RuntimeErrorResponseMessage | RuntimeCancelMessage | RuntimeNextMessage | RuntimeCreditMessage;
|
|
202
|
+
interface RuntimeMessageCodec {
|
|
203
|
+
/** 严格验证并冻结 v4 message。 */
|
|
204
|
+
encode(message: RuntimeWireMessage): RuntimeWireMessage;
|
|
205
|
+
/** 严格解析 v4 message;旧协议直接拒绝。 */
|
|
206
|
+
decode(value: unknown): RuntimeWireMessage;
|
|
207
|
+
}
|
|
208
|
+
declare function createRuntimeMessageCodec(): RuntimeMessageCodec;
|
|
209
|
+
declare function isRuntimeSnapshot(value: RuntimeWireMessage): value is RuntimeSnapshotMessage;
|
|
210
|
+
|
|
211
|
+
interface RuntimeReceiveMetadata {
|
|
212
|
+
/** 本次 MessageEvent 实际携带的业务 MessagePort;仅 transport 本地使用。 */
|
|
213
|
+
readonly ports?: readonly MessagePort[];
|
|
214
|
+
/** 由物理 endpoint transport 创建的一次性接收资源账本。 */
|
|
215
|
+
readonly ledger?: ReceivePortLedger;
|
|
216
|
+
/** 物理 endpoint 已完成一次 codec decode。 */
|
|
217
|
+
readonly decoded?: boolean;
|
|
218
|
+
}
|
|
219
|
+
interface RuntimeTransport {
|
|
220
|
+
/** 发送已验证 v4 message;transfer 由契约 extractor 提供。 */
|
|
221
|
+
send(message: RuntimeWireMessage, transfer?: readonly Transferable[]): void;
|
|
222
|
+
/** 订阅接收 message 及本次事件的本地 transfer 元数据。 */
|
|
223
|
+
subscribe(listener: (message: RuntimeWireMessage, metadata?: RuntimeReceiveMetadata) => void): () => void;
|
|
224
|
+
/** 关闭本端传输。 */
|
|
225
|
+
close?(): void;
|
|
226
|
+
/** 物理 endpoint 对 decode/接收账本错误的统一通知。 */
|
|
227
|
+
subscribeError?(listener: (error: unknown, metadata?: RuntimeReceiveMetadata) => void): () => void;
|
|
228
|
+
}
|
|
229
|
+
interface CreateCapabilityBridgeOptions {
|
|
230
|
+
/** 底层双向 transport。 */
|
|
231
|
+
readonly transport: RuntimeTransport;
|
|
232
|
+
/** 预期的对端 Runtime 类型。 */
|
|
233
|
+
readonly remoteRuntimeKind?: RuntimeKind;
|
|
234
|
+
/** 预期的对端逻辑 Runtime id。 */
|
|
235
|
+
readonly remoteRuntimeId?: string;
|
|
236
|
+
/** 默认调用预算。 */
|
|
237
|
+
readonly defaultCallTimeoutMs?: number;
|
|
238
|
+
/** 可信 Runtime/advanced 装配提供的预算;只能收紧 v4 默认值。 */
|
|
239
|
+
readonly limits?: RuntimeLimitsInput;
|
|
240
|
+
/** 可选的 Runtime 方向共享计数器。 */
|
|
241
|
+
readonly budget?: RuntimeBudget;
|
|
242
|
+
}
|
|
243
|
+
/** 创建按 peer 绑定、可撤销且支持 typed stream 的 bridge。 */
|
|
244
|
+
declare function createCapabilityBridge(options: CreateCapabilityBridgeOptions): CapabilityBridge & {
|
|
245
|
+
readonly pendingCallCount: number;
|
|
246
|
+
readonly activeStreamCount: number;
|
|
247
|
+
readonly retainedPayloadBytes: number;
|
|
248
|
+
};
|
|
249
|
+
/** 内部 typed transfer 校验 helper;不接受 call 级临时 transfer 数组。 */
|
|
250
|
+
declare function validateTransferables(value: unknown, transfer: readonly Transferable[] | undefined, limits?: RuntimeLimitsInput): readonly Transferable[];
|
|
251
|
+
|
|
252
|
+
interface MessagePortLike {
|
|
253
|
+
addEventListener(type: "message" | "messageerror", listener: (event: MessageEvent) => void): void;
|
|
254
|
+
removeEventListener(type: "message" | "messageerror", listener: (event: MessageEvent) => void): void;
|
|
255
|
+
postMessage(message: unknown, transfer?: readonly Transferable[]): void;
|
|
256
|
+
start?(): void;
|
|
257
|
+
close?(): void;
|
|
258
|
+
}
|
|
259
|
+
/** 将一个真实 MessagePort 绑定为双向 v4 transport。 */
|
|
260
|
+
declare function createMessagePortRuntimeTransport(port: MessagePortLike, options?: {
|
|
261
|
+
readonly limits?: RuntimeLimitsInput;
|
|
262
|
+
}): RuntimeTransport;
|
|
263
|
+
|
|
264
|
+
export { createCapabilityBridge as A, createMessagePortRuntimeTransport as B, type CreateCapabilityBridgeOptions as C, createPluginIntentController as D, createResourceRegistry as E, createRuntimeMessageCodec as F, createRuntimeUnitImplementationRegistry as G, isRuntimeSnapshot as H, registerOwnedResource as I, validateTransferables as J, type MessagePortLike as M, type RuntimeCallMessage as R, type RuntimeTransport as a, type CreatePluginIntentControllerOptions as b, RUNTIME_CALL_TYPE as c, RUNTIME_CANCEL_TYPE as d, RUNTIME_CREDIT_TYPE as e, RUNTIME_ERROR_MESSAGE_TYPE as f, RUNTIME_ERROR_TYPE as g, RUNTIME_NEXT_TYPE as h, RUNTIME_PROTOCOL_VERSION as i, RUNTIME_RESULT_TYPE as j, RUNTIME_SNAPSHOT_TYPE as k, type RuntimeCancelMessage as l, type RuntimeCreditMessage as m, type RuntimeErrorMessage as n, type RuntimeErrorResponseMessage as o, type RuntimeMessageCodec as p, type RuntimeNextMessage as q, type RuntimeReceiveMetadata as r, type RuntimeResultMessage as s, type RuntimeSnapshotMessage as t, type RuntimeSnapshotUnit as u, type RuntimeStreamDoneMessage as v, type RuntimeStreamReadyMessage as w, type RuntimeUnaryResultMessage as x, type RuntimeUnitImplementation as y, type RuntimeWireMessage as z };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,57 +1,70 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { W as WindowApp, l as RuntimeHandle, K as Capability, Z as CapabilityClient, X as AppLike, aM as PluginState, a as PluginGraph, c as PluginReverseDep, aI as PluginIntentSubmissionResult, P as PluginManifest, C as CapabilityDescriptor, k as ResourceStoreApi, b0 as ResourceSnapshot } from './runtimeTypes-DquUCHz-.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
type WebLoomApp = WindowApp | RuntimeHandle;
|
|
7
|
+
declare const WebLoomContext: react.Context<WebLoomApp | undefined>;
|
|
8
|
+
interface WebLoomProviderProps {
|
|
9
|
+
/** 稳定的 WindowApp 或 RuntimeHandle。 */
|
|
10
|
+
readonly app: WebLoomApp;
|
|
11
|
+
/** React 子树。 */
|
|
12
|
+
readonly children: ReactNode;
|
|
10
13
|
}
|
|
11
|
-
declare function
|
|
12
|
-
declare function
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
* 订阅组件会重新渲染。这是"硬切换 001"让 React 层感知 host 变化的关键 hook。
|
|
16
|
-
*/
|
|
17
|
-
declare function useHostVersion(): number;
|
|
14
|
+
declare function WebLoomProvider({ app, children }: WebLoomProviderProps): react_jsx_runtime.JSX.Element;
|
|
15
|
+
declare function useWebLoomApp(): WebLoomApp;
|
|
16
|
+
/** app 状态的稳定外部订阅;hook 实现按 selector 再做引用保持。 */
|
|
17
|
+
declare function useAppSubscription(): WebLoomApp;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
declare function
|
|
19
|
+
/** 获取 typed capability;远程 proxy 的构造本身不等待 Worker。 */
|
|
20
|
+
declare function useCapability<C extends Capability>(capability: C): CapabilityClient<C>;
|
|
21
|
+
/** 当前目录没有 capability 时返回 undefined。 */
|
|
22
|
+
declare function useOptionalCapability<C extends Capability>(capability: C): CapabilityClient<C> | undefined;
|
|
23
|
+
/** 对 typed capability 做当前目录查询。 */
|
|
24
|
+
declare function useHasCapability<C extends Capability>(capability: C): boolean;
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
/** 从 App 诊断快照派生无领域 selector。 */
|
|
27
|
+
declare function useRegistry<T>(selector: (app: AppLike) => T): T;
|
|
25
28
|
|
|
26
29
|
interface UsePluginRuntime {
|
|
30
|
+
/** 读取插件状态。 */
|
|
27
31
|
state(id: string): PluginState;
|
|
32
|
+
/** 读取静态图。 */
|
|
28
33
|
graph(): PluginGraph;
|
|
29
|
-
|
|
34
|
+
/** 读取反向依赖。 */
|
|
35
|
+
reverseDeps(id: string): readonly PluginReverseDep[];
|
|
36
|
+
/** 启动插件。 */
|
|
30
37
|
enable(id: string): Promise<void>;
|
|
38
|
+
/** 停止插件。 */
|
|
31
39
|
disable(id: string): Promise<{
|
|
32
40
|
ok: true;
|
|
33
41
|
} | {
|
|
34
42
|
ok: false;
|
|
35
43
|
reason: string;
|
|
36
44
|
}>;
|
|
37
|
-
/**
|
|
45
|
+
/** 提交启停意图。 */
|
|
38
46
|
submitIntent(id: string, desiredEnabled: boolean): Promise<PluginIntentSubmissionResult>;
|
|
47
|
+
/** 删除插件。 */
|
|
39
48
|
unregister(id: string): Promise<void>;
|
|
49
|
+
/** Host/App 修订。 */
|
|
40
50
|
version(): number;
|
|
51
|
+
/** 插件 id。 */
|
|
41
52
|
manifests(): string[];
|
|
53
|
+
/** 插件 id。 */
|
|
42
54
|
installed(): string[];
|
|
55
|
+
/** 当前是否运行。 */
|
|
43
56
|
isEnabled(id: string): boolean;
|
|
44
|
-
/**
|
|
57
|
+
/** 清单。 */
|
|
45
58
|
getManifest(id: string): PluginManifest | undefined;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
* 依赖列表里写的是 capability key(如 "route.registry"),不是 plugin id。
|
|
49
|
-
*/
|
|
50
|
-
hasCapability(key: string): boolean;
|
|
59
|
+
/** typed descriptor 当前是否已暴露。 */
|
|
60
|
+
hasCapability(capability: CapabilityDescriptor): boolean;
|
|
51
61
|
}
|
|
62
|
+
/** 领域插件管理 hook;只能在 WindowApp 上使用。 */
|
|
52
63
|
declare function usePluginRuntime(): UsePluginRuntime;
|
|
53
|
-
/**
|
|
54
|
-
declare function
|
|
64
|
+
/** 精确订阅一个插件的状态。 */
|
|
65
|
+
declare function usePluginState(pluginId: string): PluginState | undefined;
|
|
66
|
+
/** 读取 App 状态的 selector;无关状态变化保持上一次选择结果。 */
|
|
67
|
+
declare function useRuntimeSelector<T>(selector: (snapshot: ReturnType<ReturnType<typeof useWebLoomApp>["state"]>) => T, equality?: (left: T, right: T) => boolean): T;
|
|
55
68
|
|
|
56
69
|
/**
|
|
57
70
|
* useResource React Hook
|
|
@@ -77,4 +90,4 @@ declare function countRender(name: string): void;
|
|
|
77
90
|
declare function getRenderCount(name: string): number;
|
|
78
91
|
declare function resetRenderCounters(): void;
|
|
79
92
|
|
|
80
|
-
export {
|
|
93
|
+
export { type UsePluginRuntime, type WebLoomApp, WebLoomContext, WebLoomProvider, type WebLoomProviderProps, countRender, getRenderCount, resetRenderCounters, useAppSubscription, useCapability, useHasCapability, useOptionalCapability, usePluginRuntime, usePluginState, useRegistry, useResource, useResourceSelector, useRuntimeSelector, useWebLoomApp };
|
package/dist/react.js
CHANGED
|
@@ -1,98 +1,89 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hostForWindowApp } from './chunk-HJKPKWI7.js';
|
|
2
|
+
import { createContext, useContext, useCallback, useSyncExternalStore, useMemo, useRef } from 'react';
|
|
2
3
|
import { jsx } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const [version, setVersion] = useState(host.version());
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
return host.subscribe((snap) => {
|
|
10
|
-
setVersion(snap.version);
|
|
11
|
-
});
|
|
12
|
-
}, [host]);
|
|
13
|
-
return /* @__PURE__ */ jsx(PluginHostContext.Provider, { value: host, children });
|
|
14
|
-
}
|
|
15
|
-
function usePluginHost() {
|
|
16
|
-
const host = useContext(PluginHostContext);
|
|
17
|
-
if (!host) throw new Error("PluginHostContext is missing");
|
|
18
|
-
return host;
|
|
19
|
-
}
|
|
20
|
-
function useHostVersion() {
|
|
21
|
-
const host = usePluginHost();
|
|
22
|
-
const [v, setV] = useState(host.version());
|
|
23
|
-
useEffect(() => host.subscribe((s) => setV(s.version)), [host]);
|
|
24
|
-
return v;
|
|
25
|
-
}
|
|
26
|
-
function useCapability(key) {
|
|
27
|
-
const host = usePluginHost();
|
|
28
|
-
const version = useHostVersion();
|
|
29
|
-
return useMemo(() => host.capabilities.get(key), [host, version, key]);
|
|
30
|
-
}
|
|
31
|
-
function useOptionalCapability(key) {
|
|
32
|
-
const host = usePluginHost();
|
|
33
|
-
const version = useHostVersion();
|
|
34
|
-
return useMemo(() => host.capabilities.has(key) ? host.capabilities.get(key) : void 0, [host, version, key]);
|
|
35
|
-
}
|
|
36
|
-
function useHasCapability(key) {
|
|
37
|
-
const host = usePluginHost();
|
|
38
|
-
const version = useHostVersion();
|
|
39
|
-
return useMemo(() => host.capabilities.has(key), [host, version, key]);
|
|
5
|
+
var WebLoomContext = createContext(void 0);
|
|
6
|
+
function WebLoomProvider({ app, children }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(WebLoomContext.Provider, { value: app, children });
|
|
40
8
|
}
|
|
41
|
-
function
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
return
|
|
9
|
+
function useWebLoomApp() {
|
|
10
|
+
const app = useContext(WebLoomContext);
|
|
11
|
+
if (!app) throw new Error("WebLoomProvider is missing");
|
|
12
|
+
return app;
|
|
13
|
+
}
|
|
14
|
+
function useAppSubscription() {
|
|
15
|
+
return useWebLoomApp();
|
|
16
|
+
}
|
|
17
|
+
function subscribeApp(app, listener) {
|
|
18
|
+
return app.subscribe(listener);
|
|
19
|
+
}
|
|
20
|
+
function useCapability(capability) {
|
|
21
|
+
const app = useWebLoomApp();
|
|
22
|
+
const subscribe = useCallback((listener) => subscribeApp(app, listener), [app]);
|
|
23
|
+
const getSnapshot = useCallback(() => app.capability(capability), [app, capability]);
|
|
24
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
25
|
+
}
|
|
26
|
+
function useOptionalCapability(capability) {
|
|
27
|
+
const app = useWebLoomApp();
|
|
28
|
+
const subscribe = useCallback((listener) => subscribeApp(app, listener), [app]);
|
|
29
|
+
const getSnapshot = useCallback(() => app.optionalCapability(capability), [app, capability]);
|
|
30
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
31
|
+
}
|
|
32
|
+
function useHasCapability(capability) {
|
|
33
|
+
return useOptionalCapability(capability) !== void 0;
|
|
34
|
+
}
|
|
35
|
+
function hostFor(app) {
|
|
36
|
+
return hostForWindowApp(app);
|
|
45
37
|
}
|
|
46
38
|
function usePluginRuntime() {
|
|
47
|
-
const
|
|
48
|
-
const
|
|
39
|
+
const app = useWebLoomApp();
|
|
40
|
+
const subscribe = useCallback((listener) => app.subscribe(listener), [app]);
|
|
41
|
+
const getSnapshot = useCallback(() => app.state(), [app]);
|
|
42
|
+
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
49
43
|
return useMemo(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
graph()
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
submitIntent(id, desiredEnabled) {
|
|
67
|
-
return host.submitIntent(id, desiredEnabled);
|
|
68
|
-
},
|
|
69
|
-
unregister(id) {
|
|
70
|
-
return host.unregister(id);
|
|
71
|
-
},
|
|
72
|
-
version() {
|
|
73
|
-
return host.version();
|
|
74
|
-
},
|
|
75
|
-
manifests() {
|
|
76
|
-
return host.manifests();
|
|
77
|
-
},
|
|
78
|
-
installed() {
|
|
79
|
-
return host.installed();
|
|
80
|
-
},
|
|
81
|
-
isEnabled(id) {
|
|
82
|
-
return host.state(id).kind === "enabled";
|
|
83
|
-
},
|
|
84
|
-
getManifest(id) {
|
|
85
|
-
return host.getManifest(id);
|
|
86
|
-
},
|
|
87
|
-
hasCapability(key) {
|
|
88
|
-
return host.capabilities.has(key);
|
|
89
|
-
}
|
|
44
|
+
if (app.runtimeKind !== "window-main") throw new Error("Plugin runtime controls require a WindowApp");
|
|
45
|
+
const host = hostFor(app);
|
|
46
|
+
return {
|
|
47
|
+
state: (id) => host.state(id),
|
|
48
|
+
graph: () => host.graph(),
|
|
49
|
+
reverseDeps: (id) => host.reverseDeps(id),
|
|
50
|
+
enable: (id) => host.enable(id),
|
|
51
|
+
disable: (id) => host.disable(id),
|
|
52
|
+
submitIntent: (id, desiredEnabled) => host.submitIntent(id, desiredEnabled),
|
|
53
|
+
unregister: (id) => host.unregister(id),
|
|
54
|
+
version: () => snapshot.revision,
|
|
55
|
+
manifests: () => host.manifests(),
|
|
56
|
+
installed: () => host.installed(),
|
|
57
|
+
isEnabled: (id) => host.state(id).kind === "enabled",
|
|
58
|
+
getManifest: (id) => host.getManifest(id),
|
|
59
|
+
hasCapability: (capability) => host.capabilities.has(capability)
|
|
90
60
|
};
|
|
91
|
-
|
|
92
|
-
|
|
61
|
+
}, [app, snapshot.revision]);
|
|
62
|
+
}
|
|
63
|
+
function usePluginState(pluginId) {
|
|
64
|
+
const app = useWebLoomApp();
|
|
65
|
+
const subscribe = useCallback((listener) => app.subscribe(listener), [app]);
|
|
66
|
+
const getSnapshot = useCallback(() => app.pluginState?.(pluginId), [app, pluginId]);
|
|
67
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
68
|
+
}
|
|
69
|
+
function useRuntimeSelector(selector, equality = Object.is) {
|
|
70
|
+
const app = useWebLoomApp();
|
|
71
|
+
const last = useMemo(() => ({ has: false, value: void 0 }), []);
|
|
72
|
+
const subscribe = useCallback((listener) => app.subscribe(listener), [app]);
|
|
73
|
+
const getSnapshot = useCallback(() => {
|
|
74
|
+
const next = selector(app.state());
|
|
75
|
+
if (last.has && equality(last.value, next)) return last.value;
|
|
76
|
+
last.has = true;
|
|
77
|
+
last.value = next;
|
|
78
|
+
return next;
|
|
79
|
+
}, [app, selector, equality, last]);
|
|
80
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
93
81
|
}
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
|
|
83
|
+
// src/react/useRegistry.ts
|
|
84
|
+
function useRegistry(selector) {
|
|
85
|
+
const app = useWebLoomApp();
|
|
86
|
+
return useRuntimeSelector(() => selector(app));
|
|
96
87
|
}
|
|
97
88
|
function useResource(store, definitionId, args) {
|
|
98
89
|
const subscribe = useCallback((callback) => {
|
|
@@ -172,6 +163,6 @@ function resetRenderCounters() {
|
|
|
172
163
|
counters.clear();
|
|
173
164
|
}
|
|
174
165
|
|
|
175
|
-
export {
|
|
166
|
+
export { WebLoomContext, WebLoomProvider, countRender, getRenderCount, resetRenderCounters, useAppSubscription, useCapability, useHasCapability, useOptionalCapability, usePluginRuntime, usePluginState, useRegistry, useResource, useResourceSelector, useRuntimeSelector, useWebLoomApp };
|
|
176
167
|
//# sourceMappingURL=react.js.map
|
|
177
168
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/PluginHostProvider.tsx","../src/react/useCapability.ts","../src/react/useRegistry.ts","../src/react/usePluginRuntime.ts","../src/react/useResource.ts","../src/react/useResourceSelector.ts","../src/react/renderCounter.ts"],"names":["useMemo","useCallback","useSyncExternalStore"],"mappings":"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","file":"react.js","sourcesContent":["// packages/runtime/src/react/PluginHostProvider.tsx\n// 把 PluginHost 注入 React 树。\n// 设计缘由:组件层只通过 hooks 访问能力,不要直接 import 内部模块。\n// 硬切换 001:host 进入运行期可卸载,host.version 变化要触发订阅者重渲染。\n\nimport { createContext, type ReactNode, useContext, useEffect, useState } from \"react\";\nimport type { PluginHost } from \"../host/createPluginHost.js\";\n\nexport const PluginHostContext = createContext<PluginHost | undefined>(undefined);\n\nexport interface PluginHostProviderProps {\n host: PluginHost;\n children: ReactNode;\n}\n\nexport function PluginHostProvider({ host, children }: PluginHostProviderProps) {\n // 订阅 host 变化:每次 enable / disable / unregister 后 bump version,\n // 我们把 version 透到 state 触发子树重渲染(hooks 自身也用 useHostVersion)。\n const [version, setVersion] = useState<number>(host.version());\n useEffect(() => {\n return host.subscribe((snap) => {\n setVersion(snap.version);\n });\n }, [host]);\n // version 仅作为\"key 变化\"挂在这里,不再通过 context 暴露(避免误用)。\n void version;\n return <PluginHostContext.Provider value={host}>{children}</PluginHostContext.Provider>;\n}\n\nexport function usePluginHost(): PluginHost {\n const host = useContext(PluginHostContext);\n if (!host) throw new Error(\"PluginHostContext is missing\");\n return host;\n}\n\n/**\n * 订阅 host.version:host 每次 enable / disable / unregister 后 version 递增,\n * 订阅组件会重新渲染。这是\"硬切换 001\"让 React 层感知 host 变化的关键 hook。\n */\nexport function useHostVersion(): number {\n const host = usePluginHost();\n const [v, setV] = useState<number>(host.version());\n useEffect(() => host.subscribe((s) => setV(s.version)), [host]);\n return v;\n}\n","// packages/runtime/src/react/useCapability.ts\n// 组件读取 capability 的唯一入口。\n// 设计缘由:业务组件不得直接调用 host.capabilities.get(),\n// 一律通过 hook 走,确保调用路径可观察。\n//\n// 硬切换 001:capability 在 plugin disable 时被 revoke。\n// 组件如果仍然用 has/capability 缓存结果,旧值会\"看起来还能用\"。\n// 改为基于 host.version 重新求值:disable 后 version 递增 -> 重渲染 ->\n// has/capability 走新值。\n\nimport { useMemo } from \"react\";\nimport { usePluginHost, useHostVersion } from \"./PluginHostProvider.js\";\n\nexport function useCapability<T>(key: string): T {\n const host = usePluginHost();\n const version = useHostVersion();\n return useMemo(() => host.capabilities.get<T>(key), [host, version, key]);\n}\n\n/** 读取可选兼容 capability;缺失时返回 undefined,不把页面渲染打崩。 */\nexport function useOptionalCapability<T>(key: string): T | undefined {\n const host = usePluginHost();\n const version = useHostVersion();\n return useMemo(() => host.capabilities.has(key) ? host.capabilities.get<T>(key) : undefined, [host, version, key]);\n}\n\nexport function useHasCapability(key: string): boolean {\n const host = usePluginHost();\n const version = useHostVersion();\n return useMemo(() => host.capabilities.has(key), [host, version, key]);\n}\n","// packages/runtime/src/react/useRegistry.ts\n// 通用 registry 读取 hook:基于 host.version 重新计算 selector 输出。\n//\n// 硬切换 001:runtime 进入热卸载模型后,host 可能在 React 挂载后变化。\n// 我们用 useHostVersion() 触发重新计算;selector 仍然纯同步(host 是稳定\n// 引用),不会出现 useSyncExternalStore 那种 snapshot 误判。\n//\n// 用法:\n// const routes = useRegistry(h => h.routes.list());\n// const route = useRegistry(h => h.routes.byPath('/poker'));\n// 不再假定\"host 挂载后不变\"。\n\nimport { useMemo } from \"react\";\nimport type { PluginHost } from \"../host/createPluginHost.js\";\nimport { usePluginHost, useHostVersion } from \"./PluginHostProvider.js\";\n\nexport function useRegistry<T>(selector: (host: PluginHost) => T): T {\n const host = usePluginHost();\n const version = useHostVersion();\n // version 变化时强制重算 selector;selector host 是稳定引用。\n return useMemo(() => selector(host), [version, host, selector]);\n}\n","// packages/runtime/src/react/usePluginRuntime.ts\n// 插件运行时操作 hook。\n// 设计缘由(硬切换 001):\n// - UI 层(plugin manager)需要 enable / disable 插件。\n// - 业务组件可能需要查 graph / state。\n// - 把这些操作收拢到 hook,调用方拿到的是一个稳定 API 对象。\n\nimport { useMemo } from \"react\";\nimport type { PluginGraph, PluginState, PluginReverseDep, PluginManifest } from \"../contracts/plugin.js\";\nimport type { PluginIntentSubmissionResult } from \"../contracts/lifecycle.js\";\nimport type { PluginHost } from \"../host/createPluginHost.js\";\nimport { usePluginHost, useHostVersion } from \"./PluginHostProvider.js\";\n\nexport interface UsePluginRuntime {\n state(id: string): PluginState;\n graph(): PluginGraph;\n reverseDeps(id: string): PluginReverseDep[];\n enable(id: string): Promise<void>;\n disable(id: string): Promise<{ ok: true } | { ok: false; reason: string }>;\n /** 提交产品级绝对启停意图;accepted 只表示意图已持久化。 */\n submitIntent(id: string, desiredEnabled: boolean): Promise<PluginIntentSubmissionResult>;\n unregister(id: string): Promise<void>;\n version(): number;\n manifests(): string[];\n installed(): string[];\n isEnabled(id: string): boolean;\n /** 拿单条 plugin 的 manifest。id 未知时返回 undefined。 */\n getManifest(id: string): PluginManifest | undefined;\n /**\n * 探测 capability 是否存在。供 UI 判断\"依赖的 capability 是否满足\",\n * 依赖列表里写的是 capability key(如 \"route.registry\"),不是 plugin id。\n */\n hasCapability(key: string): boolean;\n}\n\nexport function usePluginRuntime(): UsePluginRuntime {\n const host = usePluginHost();\n const version = useHostVersion();\n return useMemo<UsePluginRuntime>(() => {\n const api: UsePluginRuntime = {\n state(id) {\n return host.state(id);\n },\n graph() {\n return host.graph();\n },\n reverseDeps(id) {\n return host.reverseDeps(id);\n },\n enable(id) {\n return host.enable(id);\n },\n disable(id) {\n return host.disable(id);\n },\n submitIntent(id, desiredEnabled) {\n return host.submitIntent(id, desiredEnabled);\n },\n unregister(id) {\n return host.unregister(id);\n },\n version() {\n return host.version();\n },\n manifests() {\n return host.manifests();\n },\n installed() {\n return host.installed();\n },\n isEnabled(id) {\n return host.state(id).kind === \"enabled\";\n },\n getManifest(id) {\n return host.getManifest(id);\n },\n hasCapability(key) {\n return host.capabilities.has(key);\n }\n };\n return api;\n }, [host, version]);\n}\n\n/** 旧调用方兼容:单纯拿 host 引用。 */\nexport function useHost(): PluginHost {\n return usePluginHost();\n}\n","/**\n * useResource React Hook\n *\n * 设计缘由:负责 ensure + useSyncExternalStore 订阅并返回完整 snapshot。\n * 不暴露 store 内部可变对象。\n */\n\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport type { ResourceSnapshot } from \"../contracts/resource.js\";\nimport type { ResourceStoreApi } from \"../resources/resourceStore.js\";\n\n/** useResource hook:返回完整资源快照 */\nexport function useResource<T>(\n store: ResourceStoreApi,\n definitionId: string,\n args: readonly string[]\n): ResourceSnapshot<T> {\n const subscribe = useCallback((callback: () => void) => {\n return store.subscribe(definitionId, args, callback);\n }, [store, definitionId, ...args]);\n\n const getSnapshot = useCallback((): ResourceSnapshot<T> => {\n return store.ensure<T>(definitionId, args);\n }, [store, definitionId, ...args]);\n\n const getServerSnapshot = useCallback((): ResourceSnapshot<T> => {\n // SSR 稳定快照\n return {\n key: [definitionId, ...args],\n status: \"pending\",\n data: undefined,\n revision: 0,\n };\n }, [definitionId, ...args]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","/**\n * useResourceSelector React Hook\n *\n * 设计缘由:只在 selector 结果发生语义变化时重渲染。\n * selector 和 equality 必须为纯函数。\n */\n\nimport { useSyncExternalStore, useCallback, useRef } from \"react\";\nimport type { ResourceSnapshot } from \"../contracts/resource.js\";\nimport type { ResourceStoreApi } from \"../resources/resourceStore.js\";\n\n/** 默认相等判断:Object.is */\nfunction defaultEquality<T>(a: T, b: T): boolean {\n return Object.is(a, b);\n}\n\n/** useResourceSelector hook:只在 selector 结果变化时重渲染 */\nexport function useResourceSelector<T, TSelected>(\n store: ResourceStoreApi,\n definitionId: string,\n args: readonly string[],\n selector: (snapshot: ResourceSnapshot<T>) => TSelected,\n equality: (a: TSelected, b: TSelected) => boolean = defaultEquality\n): TSelected {\n const selectedRef = useRef<TSelected>();\n const hasSelectedRef = useRef(false);\n const sourceSnapshotRef = useRef<ResourceSnapshot<T>>();\n const selectorRef = useRef(selector);\n const equalityRef = useRef(equality);\n\n // 更新 refs\n selectorRef.current = selector;\n equalityRef.current = equality;\n\n const subscribe = useCallback(\n (callback: () => void) => {\n return store.subscribe(definitionId, args, callback);\n },\n [store, definitionId, ...args]\n );\n\n const getSnapshot = useCallback((): TSelected => {\n const snapshot = store.ensure<T>(definitionId, args);\n\n // React's useSyncExternalStore requires referentially stable results when\n // the backing store did not change. A selector may legitimately allocate\n // (for example `rows.slice().sort(...)`), so equality alone cannot uphold\n // that requirement when callers use reference equality.\n if (hasSelectedRef.current && sourceSnapshotRef.current === snapshot) {\n return selectedRef.current as TSelected;\n }\n\n const selected = selectorRef.current(snapshot);\n\n // 检查是否变化\n if (\n hasSelectedRef.current &&\n equalityRef.current(selectedRef.current as TSelected, selected)\n ) {\n sourceSnapshotRef.current = snapshot;\n return selectedRef.current as TSelected;\n }\n\n selectedRef.current = selected as TSelected;\n hasSelectedRef.current = true;\n sourceSnapshotRef.current = snapshot;\n return selected;\n }, [store, definitionId, ...args]);\n\n const getServerSnapshot = useCallback((): TSelected => {\n const snapshot: ResourceSnapshot<T> = {\n key: [definitionId, ...args],\n status: \"pending\",\n data: undefined,\n revision: 0,\n };\n return selectorRef.current(snapshot);\n }, [definitionId, ...args]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","// 仅用于开发/测试观察组件 render 次数;生产构建中保持 no-op。\n\nconst counters = new Map<string, number>();\n\nfunction enabled(): boolean {\n const env = (import.meta as ImportMeta & { env?: { DEV?: boolean } }).env;\n return env?.DEV !== false;\n}\n\nexport function countRender(name: string): void {\n if (!enabled()) return;\n counters.set(name, (counters.get(name) ?? 0) + 1);\n}\n\nexport function getRenderCount(name: string): number {\n return counters.get(name) ?? 0;\n}\n\nexport function resetRenderCounters(): void {\n counters.clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/PluginHostProvider.tsx","../src/react/useCapability.ts","../src/react/usePluginRuntime.ts","../src/react/useRegistry.ts","../src/react/useResource.ts","../src/react/useResourceSelector.ts","../src/react/renderCounter.ts"],"names":["useCallback","useSyncExternalStore"],"mappings":"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","file":"react.js","sourcesContent":["// React 绑定只保存 App,不复制一套 Host 状态。\n\nimport { createContext, type ReactNode, useContext } from \"react\";\nimport type { AppLike, RuntimeHandle, WindowApp } from \"../runtime/runtimeTypes.js\";\n\nexport type WebLoomApp = WindowApp | RuntimeHandle;\nexport const WebLoomContext = createContext<WebLoomApp | undefined>(undefined);\n\nexport interface WebLoomProviderProps {\n /** 稳定的 WindowApp 或 RuntimeHandle。 */\n readonly app: WebLoomApp;\n /** React 子树。 */\n readonly children: ReactNode;\n}\n\nexport function WebLoomProvider({ app, children }: WebLoomProviderProps) {\n return <WebLoomContext.Provider value={app}>{children}</WebLoomContext.Provider>;\n}\n\nexport function useWebLoomApp(): WebLoomApp {\n const app = useContext(WebLoomContext);\n if (!app) throw new Error(\"WebLoomProvider is missing\");\n return app;\n}\n\n/** app 状态的稳定外部订阅;hook 实现按 selector 再做引用保持。 */\nexport function useAppSubscription(): WebLoomApp {\n return useWebLoomApp();\n}\n","import { useCallback, useSyncExternalStore } from \"react\";\nimport type { Capability, CapabilityClient } from \"../contracts/capability.js\";\nimport { useWebLoomApp } from \"./PluginHostProvider.js\";\n\nfunction subscribeApp(app: { subscribe(listener: () => void): () => void }, listener: () => void): () => void {\n return app.subscribe(listener);\n}\n\n/** 获取 typed capability;远程 proxy 的构造本身不等待 Worker。 */\nexport function useCapability<C extends Capability>(capability: C): CapabilityClient<C> {\n const app = useWebLoomApp();\n const subscribe = useCallback((listener: () => void) => subscribeApp(app, listener), [app]);\n const getSnapshot = useCallback(() => (app as unknown as { capability<C extends Capability>(capability: C): CapabilityClient<C> }).capability(capability), [app, capability]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** 当前目录没有 capability 时返回 undefined。 */\nexport function useOptionalCapability<C extends Capability>(capability: C): CapabilityClient<C> | undefined {\n const app = useWebLoomApp();\n const subscribe = useCallback((listener: () => void) => subscribeApp(app, listener), [app]);\n const getSnapshot = useCallback(() => (app as unknown as { optionalCapability<C extends Capability>(capability: C): CapabilityClient<C> | undefined }).optionalCapability(capability), [app, capability]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** 对 typed capability 做当前目录查询。 */\nexport function useHasCapability<C extends Capability>(capability: C): boolean {\n return useOptionalCapability(capability) !== undefined;\n}\n","import { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport type { CapabilityDescriptor } from \"../contracts/capability.js\";\nimport type { PluginGraph, PluginManifest, PluginReverseDep, PluginState } from \"../contracts/plugin.js\";\nimport type { PluginIntentSubmissionResult } from \"../contracts/lifecycle.js\";\nimport { hostForWindowApp } from \"../runtime/windowRuntime.js\";\nimport type { WindowApp } from \"../runtime/runtimeTypes.js\";\nimport { useWebLoomApp } from \"./PluginHostProvider.js\";\n\nexport interface UsePluginRuntime {\n /** 读取插件状态。 */\n state(id: string): PluginState;\n /** 读取静态图。 */\n graph(): PluginGraph;\n /** 读取反向依赖。 */\n reverseDeps(id: string): readonly PluginReverseDep[];\n /** 启动插件。 */\n enable(id: string): Promise<void>;\n /** 停止插件。 */\n disable(id: string): Promise<{ ok: true } | { ok: false; reason: string }>;\n /** 提交启停意图。 */\n submitIntent(id: string, desiredEnabled: boolean): Promise<PluginIntentSubmissionResult>;\n /** 删除插件。 */\n unregister(id: string): Promise<void>;\n /** Host/App 修订。 */\n version(): number;\n /** 插件 id。 */\n manifests(): string[];\n /** 插件 id。 */\n installed(): string[];\n /** 当前是否运行。 */\n isEnabled(id: string): boolean;\n /** 清单。 */\n getManifest(id: string): PluginManifest | undefined;\n /** typed descriptor 当前是否已暴露。 */\n hasCapability(capability: CapabilityDescriptor): boolean;\n}\n\nfunction hostFor(app: WindowApp) {\n return hostForWindowApp(app);\n}\n\n/** 领域插件管理 hook;只能在 WindowApp 上使用。 */\nexport function usePluginRuntime(): UsePluginRuntime {\n const app = useWebLoomApp();\n const subscribe = useCallback((listener: () => void) => app.subscribe(listener), [app]);\n const getSnapshot = useCallback(() => app.state(), [app]);\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n return useMemo(() => {\n if (app.runtimeKind !== \"window-main\") throw new Error(\"Plugin runtime controls require a WindowApp\");\n const host = hostFor(app);\n return {\n state: (id: string) => host.state(id),\n graph: () => host.graph(),\n reverseDeps: (id: string) => host.reverseDeps(id),\n enable: (id: string) => host.enable(id),\n disable: (id: string) => host.disable(id),\n submitIntent: (id: string, desiredEnabled: boolean) => host.submitIntent(id, desiredEnabled),\n unregister: (id: string) => host.unregister(id),\n version: () => snapshot.revision,\n manifests: () => host.manifests(),\n installed: () => host.installed(),\n isEnabled: (id: string) => host.state(id).kind === \"enabled\",\n getManifest: (id: string) => host.getManifest(id),\n hasCapability: (capability: CapabilityDescriptor) => host.capabilities.has(capability),\n } satisfies UsePluginRuntime;\n }, [app, snapshot.revision]);\n}\n\n/** 精确订阅一个插件的状态。 */\nexport function usePluginState(pluginId: string): PluginState | undefined {\n const app = useWebLoomApp();\n const subscribe = useCallback((listener: () => void) => app.subscribe(listener), [app]);\n const getSnapshot = useCallback(() => app.pluginState?.(pluginId), [app, pluginId]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n/** 读取 App 状态的 selector;无关状态变化保持上一次选择结果。 */\nexport function useRuntimeSelector<T>(selector: (snapshot: ReturnType<ReturnType<typeof useWebLoomApp>[\"state\"]>) => T, equality: (left: T, right: T) => boolean = Object.is): T {\n const app = useWebLoomApp();\n const last = useMemo(() => ({ has: false, value: undefined as T }), []);\n const subscribe = useCallback((listener: () => void) => app.subscribe(listener), [app]);\n const getSnapshot = useCallback(() => {\n const next = selector(app.state());\n if (last.has && equality(last.value, next)) return last.value;\n last.has = true;\n last.value = next;\n return next;\n }, [app, selector, equality, last]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { useCallback } from \"react\";\nimport type { AppLike } from \"../runtime/runtimeTypes.js\";\nimport { useRuntimeSelector } from \"./usePluginRuntime.js\";\nimport { useWebLoomApp } from \"./PluginHostProvider.js\";\n\n/** 从 App 诊断快照派生无领域 selector。 */\nexport function useRegistry<T>(selector: (app: AppLike) => T): T {\n const app = useWebLoomApp();\n return useRuntimeSelector(() => selector(app));\n}\n","/**\n * useResource React Hook\n *\n * 设计缘由:负责 ensure + useSyncExternalStore 订阅并返回完整 snapshot。\n * 不暴露 store 内部可变对象。\n */\n\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport type { ResourceSnapshot } from \"../contracts/resource.js\";\nimport type { ResourceStoreApi } from \"../resources/resourceStore.js\";\n\n/** useResource hook:返回完整资源快照 */\nexport function useResource<T>(\n store: ResourceStoreApi,\n definitionId: string,\n args: readonly string[]\n): ResourceSnapshot<T> {\n const subscribe = useCallback((callback: () => void) => {\n return store.subscribe(definitionId, args, callback);\n }, [store, definitionId, ...args]);\n\n const getSnapshot = useCallback((): ResourceSnapshot<T> => {\n return store.ensure<T>(definitionId, args);\n }, [store, definitionId, ...args]);\n\n const getServerSnapshot = useCallback((): ResourceSnapshot<T> => {\n // SSR 稳定快照\n return {\n key: [definitionId, ...args],\n status: \"pending\",\n data: undefined,\n revision: 0,\n };\n }, [definitionId, ...args]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","/**\n * useResourceSelector React Hook\n *\n * 设计缘由:只在 selector 结果发生语义变化时重渲染。\n * selector 和 equality 必须为纯函数。\n */\n\nimport { useSyncExternalStore, useCallback, useRef } from \"react\";\nimport type { ResourceSnapshot } from \"../contracts/resource.js\";\nimport type { ResourceStoreApi } from \"../resources/resourceStore.js\";\n\n/** 默认相等判断:Object.is */\nfunction defaultEquality<T>(a: T, b: T): boolean {\n return Object.is(a, b);\n}\n\n/** useResourceSelector hook:只在 selector 结果变化时重渲染 */\nexport function useResourceSelector<T, TSelected>(\n store: ResourceStoreApi,\n definitionId: string,\n args: readonly string[],\n selector: (snapshot: ResourceSnapshot<T>) => TSelected,\n equality: (a: TSelected, b: TSelected) => boolean = defaultEquality\n): TSelected {\n const selectedRef = useRef<TSelected>();\n const hasSelectedRef = useRef(false);\n const sourceSnapshotRef = useRef<ResourceSnapshot<T>>();\n const selectorRef = useRef(selector);\n const equalityRef = useRef(equality);\n\n // 更新 refs\n selectorRef.current = selector;\n equalityRef.current = equality;\n\n const subscribe = useCallback(\n (callback: () => void) => {\n return store.subscribe(definitionId, args, callback);\n },\n [store, definitionId, ...args]\n );\n\n const getSnapshot = useCallback((): TSelected => {\n const snapshot = store.ensure<T>(definitionId, args);\n\n // React's useSyncExternalStore requires referentially stable results when\n // the backing store did not change. A selector may legitimately allocate\n // (for example `rows.slice().sort(...)`), so equality alone cannot uphold\n // that requirement when callers use reference equality.\n if (hasSelectedRef.current && sourceSnapshotRef.current === snapshot) {\n return selectedRef.current as TSelected;\n }\n\n const selected = selectorRef.current(snapshot);\n\n // 检查是否变化\n if (\n hasSelectedRef.current &&\n equalityRef.current(selectedRef.current as TSelected, selected)\n ) {\n sourceSnapshotRef.current = snapshot;\n return selectedRef.current as TSelected;\n }\n\n selectedRef.current = selected as TSelected;\n hasSelectedRef.current = true;\n sourceSnapshotRef.current = snapshot;\n return selected;\n }, [store, definitionId, ...args]);\n\n const getServerSnapshot = useCallback((): TSelected => {\n const snapshot: ResourceSnapshot<T> = {\n key: [definitionId, ...args],\n status: \"pending\",\n data: undefined,\n revision: 0,\n };\n return selectorRef.current(snapshot);\n }, [definitionId, ...args]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","// 仅用于开发/测试观察组件 render 次数;生产构建中保持 no-op。\n\nconst counters = new Map<string, number>();\n\nfunction enabled(): boolean {\n const env = (import.meta as ImportMeta & { env?: { DEV?: boolean } }).env;\n return env?.DEV !== false;\n}\n\nexport function countRender(name: string): void {\n if (!enabled()) return;\n counters.set(name, (counters.get(name) ?? 0) + 1);\n}\n\nexport function getRenderCount(name: string): number {\n return counters.get(name) ?? 0;\n}\n\nexport function resetRenderCounters(): void {\n counters.clear();\n}\n"]}
|