@cniot/mdd-editor 0.3.1 → 0.3.4
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 +24 -0
- package/build/index.cjs.js +35 -19
- package/build/index.es.js +289 -32
- package/build/style.css +1 -1
- package/package.json +1 -1
- package/src/ai/LocalAIDrawer.jsx +265 -30
- package/src/ai/bridgeClient.js +67 -15
package/src/ai/bridgeClient.js
CHANGED
|
@@ -2,9 +2,19 @@ export const DEFAULT_BRIDGE_URL = 'http://127.0.0.1:17678';
|
|
|
2
2
|
|
|
3
3
|
const trimEndSlash = (value = '') => value.replace(/\/+$/, '');
|
|
4
4
|
const RELAY_CHANNEL = 'mdd-ai-bridge';
|
|
5
|
+
const relayCacheMap = new Map();
|
|
5
6
|
|
|
6
7
|
const isLoopbackURL = (value = '') => /^http:\/\/(127(?:\.\d{1,3}){3}|localhost)(?::\d+)?/i.test(value);
|
|
7
8
|
|
|
9
|
+
export class BridgeRequestError extends Error {
|
|
10
|
+
constructor(message, options = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'BridgeRequestError';
|
|
13
|
+
this.status = options.status || 0;
|
|
14
|
+
this.data = options.data || null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
export function shouldUseBridgeRelay(baseURL) {
|
|
9
19
|
return typeof window !== 'undefined' && !window.isSecureContext && isLoopbackURL(baseURL);
|
|
10
20
|
}
|
|
@@ -35,14 +45,22 @@ async function request(baseURL, path, options = {}) {
|
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
if (!res.ok) {
|
|
38
|
-
throw new
|
|
48
|
+
throw new BridgeRequestError(data?.message || `请求本地 AI Bridge 失败: ${res.status}`, {
|
|
49
|
+
status: res.status,
|
|
50
|
+
data,
|
|
51
|
+
});
|
|
39
52
|
}
|
|
40
53
|
return data;
|
|
41
54
|
}
|
|
42
55
|
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
const
|
|
56
|
+
function getRelayCache(baseURL) {
|
|
57
|
+
const relayOrigin = trimEndSlash(baseURL);
|
|
58
|
+
const relayURL = `${relayOrigin}/relay`;
|
|
59
|
+
const cached = relayCacheMap.get(relayOrigin);
|
|
60
|
+
if (cached?.window && !cached.window.closed) {
|
|
61
|
+
return cached;
|
|
62
|
+
}
|
|
63
|
+
|
|
46
64
|
const relayWindow = window.open(
|
|
47
65
|
relayURL,
|
|
48
66
|
'mdd-ai-bridge-relay',
|
|
@@ -53,9 +71,23 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
53
71
|
throw new Error('浏览器拦截了本地 Bridge 窗口,请允许弹窗后重试');
|
|
54
72
|
}
|
|
55
73
|
|
|
74
|
+
const next = {
|
|
75
|
+
origin: relayOrigin,
|
|
76
|
+
window: relayWindow,
|
|
77
|
+
ready: false,
|
|
78
|
+
};
|
|
79
|
+
relayCacheMap.set(relayOrigin, next);
|
|
80
|
+
return next;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function requestViaRelay(baseURL, path, options = {}) {
|
|
84
|
+
const relayCache = getRelayCache(baseURL);
|
|
85
|
+
const requestId = createRequestId();
|
|
86
|
+
|
|
56
87
|
return new Promise((resolve, reject) => {
|
|
57
88
|
let settled = false;
|
|
58
|
-
let
|
|
89
|
+
let fallbackPosted = false;
|
|
90
|
+
let readyPosted = false;
|
|
59
91
|
|
|
60
92
|
const cleanup = () => {
|
|
61
93
|
window.removeEventListener('message', handleMessage);
|
|
@@ -63,8 +95,19 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
63
95
|
clearTimeout(fallbackTimer);
|
|
64
96
|
};
|
|
65
97
|
|
|
66
|
-
const postRequest = () => {
|
|
67
|
-
|
|
98
|
+
const postRequest = (source = 'ready') => {
|
|
99
|
+
if (source === 'ready') {
|
|
100
|
+
if (readyPosted) return;
|
|
101
|
+
readyPosted = true;
|
|
102
|
+
} else {
|
|
103
|
+
if (fallbackPosted) return;
|
|
104
|
+
fallbackPosted = true;
|
|
105
|
+
}
|
|
106
|
+
if (!relayCache.window || relayCache.window.closed) {
|
|
107
|
+
finish(reject, new Error('本地 Bridge relay 窗口已关闭,请重试'));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
relayCache.window.postMessage(
|
|
68
111
|
{
|
|
69
112
|
channel: RELAY_CHANNEL,
|
|
70
113
|
type: 'request',
|
|
@@ -72,7 +115,7 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
72
115
|
path,
|
|
73
116
|
options,
|
|
74
117
|
},
|
|
75
|
-
|
|
118
|
+
relayCache.origin,
|
|
76
119
|
);
|
|
77
120
|
};
|
|
78
121
|
|
|
@@ -84,14 +127,14 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
84
127
|
};
|
|
85
128
|
|
|
86
129
|
const handleMessage = (event) => {
|
|
87
|
-
if (event.origin !==
|
|
88
|
-
if (event.source !==
|
|
130
|
+
if (event.origin !== relayCache.origin) return;
|
|
131
|
+
if (event.source !== relayCache.window) return;
|
|
89
132
|
const message = event.data || {};
|
|
90
133
|
if (message.channel !== RELAY_CHANNEL) return;
|
|
91
134
|
|
|
92
|
-
if (message.type === 'ready'
|
|
93
|
-
ready = true;
|
|
94
|
-
postRequest();
|
|
135
|
+
if (message.type === 'ready') {
|
|
136
|
+
relayCache.ready = true;
|
|
137
|
+
postRequest('ready');
|
|
95
138
|
return;
|
|
96
139
|
}
|
|
97
140
|
|
|
@@ -99,7 +142,13 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
99
142
|
if (!message.ok) {
|
|
100
143
|
finish(
|
|
101
144
|
reject,
|
|
102
|
-
new
|
|
145
|
+
new BridgeRequestError(
|
|
146
|
+
message.data?.message || `请求本地 AI Bridge 失败: ${message.status || 0}`,
|
|
147
|
+
{
|
|
148
|
+
status: message.status || 0,
|
|
149
|
+
data: message.data,
|
|
150
|
+
},
|
|
151
|
+
),
|
|
103
152
|
);
|
|
104
153
|
return;
|
|
105
154
|
}
|
|
@@ -110,10 +159,13 @@ function requestViaRelay(baseURL, path, options = {}) {
|
|
|
110
159
|
finish(reject, new Error('本地 AI Bridge relay 响应超时,请确认服务已启动'));
|
|
111
160
|
}, 30000);
|
|
112
161
|
const fallbackTimer = setTimeout(() => {
|
|
113
|
-
if (!ready) postRequest();
|
|
162
|
+
if (!relayCache.ready) postRequest('fallback');
|
|
114
163
|
}, 500);
|
|
115
164
|
|
|
116
165
|
window.addEventListener('message', handleMessage);
|
|
166
|
+
if (relayCache.ready) {
|
|
167
|
+
setTimeout(() => postRequest('ready'), 0);
|
|
168
|
+
}
|
|
117
169
|
});
|
|
118
170
|
}
|
|
119
171
|
|