@easyai-canvas/canvas-plugin-sdk 0.1.5 → 0.1.6
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/dist/customer-main.js
CHANGED
|
@@ -80,7 +80,8 @@ async function studioCatalog() {
|
|
|
80
80
|
nodes: entry.manifest.contributes.nodes?.length ?? 0,
|
|
81
81
|
actions: entry.manifest.contributes.actions?.length ?? 0,
|
|
82
82
|
package: packaged.downloads[entry.manifest.id] ? { mode: 'download' } : null,
|
|
83
|
-
buildKey: createHash('sha256').update(JSON.stringify({
|
|
83
|
+
buildKey: createHash('sha256').update(JSON.stringify({ instanceId: catalog.instanceId,
|
|
84
|
+
entry, bundleDigest: bundle?.digest, cssDigest: bundle?.cssDigest })).digest('hex'),
|
|
84
85
|
};
|
|
85
86
|
}),
|
|
86
87
|
};
|
|
@@ -249,7 +250,7 @@ const server = createServer(async (request, response) => {
|
|
|
249
250
|
}
|
|
250
251
|
if (method === 'POST' && path === '/studio/open') {
|
|
251
252
|
const input = await body(request);
|
|
252
|
-
send(response, 200, await studio.openDebugSession(
|
|
253
|
+
send(response, 200, await studio.openDebugSession(typeof input.pluginId === 'string' && input.pluginId ? input.pluginId : undefined));
|
|
253
254
|
return;
|
|
254
255
|
}
|
|
255
256
|
if (method === 'POST' && path === '/studio/embed-ticket') {
|
package/dist/studio/index.html
CHANGED
|
@@ -316,14 +316,14 @@ dialog::backdrop { background: #30384266; }
|
|
|
316
316
|
</div>
|
|
317
317
|
<div id="notice" class="notice" role="status" hidden></div>
|
|
318
318
|
<dialog id="panel" aria-labelledby="panel-title">
|
|
319
|
-
<div class="dialog-head"><div><h2 id="panel-title">插件管理</h2><p
|
|
319
|
+
<div class="dialog-head"><div><h2 id="panel-title">插件管理</h2><p>已启用插件会同时出现在调试画布,选择插件可查看配置</p></div><button id="close" type="button" aria-label="关闭管理面板"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4.5 4.5 15.5 15.5M15.5 4.5 4.5 15.5"/></svg></button></div>
|
|
320
320
|
<div class="dialog-body">
|
|
321
321
|
<aside class="plugin-sidebar" aria-labelledby="target-title"><div class="section-heading"><h3 id="target-title">本地插件</h3><span id="plugin-count" class="activity-count">0 个</span></div><p>选择插件后在右侧管理</p><div id="plugin-list" class="plugin-list" role="radiogroup" aria-labelledby="target-title"></div></aside>
|
|
322
322
|
<div class="plugin-detail"><p id="detail-empty" class="detail-empty" hidden>暂无插件。请在本地服务中注册插件。</p><div id="plugin-detail-content" class="plugin-detail-content">
|
|
323
323
|
<div class="detail-head"><div><h3 id="detail-name">插件</h3><code id="detail-id"></code></div><span id="detail-status" class="status-badge" role="status">检查中</span></div>
|
|
324
324
|
<div class="detail-meta"><span id="detail-nodes">0 个节点</span><span id="detail-actions">0 个操作</span><span id="detail-package">插件包不可用</span></div>
|
|
325
|
-
<div class="plugin-actions"><button id="open-plugin" type="button"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 10h11m-4-4 4 4-4 4M16 4h2v12h-2"/></svg><span
|
|
326
|
-
<div class="configuration-section" aria-labelledby="configuration-title"><h4 id="configuration-title">插件配置</h4><p>配置仅保存在本地开发服务中。</p><div id="no-config" class="no-config" hidden
|
|
325
|
+
<div class="plugin-actions"><button id="open-plugin" type="button"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 10h11m-4-4 4 4-4 4M16 4h2v12h-2"/></svg><span>返回调试画布</span></button><button id="download-package" type="button" disabled><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2.5v10m-3.5-3.5L10 12.5 13.5 9M3.5 14v2.5h13V14"/></svg><span id="download-label">下载插件包</span></button></div><p id="package-note" class="package-note" role="status" aria-live="polite"></p>
|
|
326
|
+
<div class="configuration-section" aria-labelledby="configuration-title"><h4 id="configuration-title">插件配置</h4><p>配置仅保存在本地开发服务中。</p><div id="no-config" class="no-config" hidden>此插件无需配置,可以在画布中使用或下载插件包。</div><form id="plugin-config" class="plugin-config" hidden><p id="config-status" role="status" aria-live="polite"></p><div id="config-fields"></div><div class="config-actions"><button type="submit">保存并启用</button><button id="config-check" type="button">检查配置</button></div></form></div>
|
|
327
327
|
<div class="secondary-panels"><details><summary>连接与构建 <span id="panel-status" class="status-badge" role="status">正在连接</span></summary><div class="panel-content"><dl class="session-summary"><div><dt>开发服务</dt><dd id="connection">—</dd></div><div><dt>当前构建</dt><dd id="build">—</dd></div><div><dt>调试画布</dt><dd id="project">—</dd></div></dl><span id="active-plugin" class="section-context" hidden></span><div class="sdk-card" hidden><strong>画布插件 SDK</strong><p class="sdk-message" role="status" aria-live="polite"></p><button class="sdk-action" type="button" hidden>升级 SDK</button></div><details class="technical-details"><summary>查看连接详情</summary><dl><dt>连接 ID</dt><dd id="connection-id">—</dd><dt>构建摘要</dt><dd id="build-full">—</dd><dt>项目 ID</dt><dd id="project-id">—</dd></dl></details></div></details><details><summary>最近活动 <span id="activity-count" class="activity-count">0 条</span></summary><div class="panel-content"><div id="log" class="activity-list" role="log" aria-label="调试活动" aria-live="polite"></div></div></details></div>
|
|
328
328
|
</div></div>
|
|
329
329
|
</div>
|
|
@@ -535,6 +535,10 @@ dialog::backdrop { background: #30384266; }
|
|
|
535
535
|
$('dock-expand').addEventListener('click', () => { manuallyCollapsed = false; expandedOverDialog = canvasDialogOpen; renderDock(); });
|
|
536
536
|
const chosen = () => catalog?.plugins.find(item => item.id === selected);
|
|
537
537
|
const panelPlugin = () => catalog?.plugins.find(item => item.id === panelSelected);
|
|
538
|
+
const activePluginId = () => session?.pluginId || preparedSession?.pluginId || selected;
|
|
539
|
+
const hasNewBuild = () => (session?.plugins || (session ? [{ pluginId: session.pluginId, fingerprint: session.fingerprint }] : []))
|
|
540
|
+
.some(item => item.active !== false && catalog?.plugins.find(plugin => plugin.id === item.pluginId)?.buildKey !== item.fingerprint) ||
|
|
541
|
+
Boolean(session && catalog?.plugins.some(plugin => plugin.enabled && !session.plugins?.some(item => item.pluginId === plugin.id && item.active)));
|
|
538
542
|
let configFormKey = '', configFeedback = null;
|
|
539
543
|
function renderConfig() {
|
|
540
544
|
const plugin = panelPlugin();
|
|
@@ -599,27 +603,27 @@ dialog::backdrop { background: #30384266; }
|
|
|
599
603
|
}
|
|
600
604
|
const url = () => {
|
|
601
605
|
const address = new URL('/developer/plugin-debug', catalog.platformOrigin);
|
|
602
|
-
address.searchParams.set('pluginId',
|
|
606
|
+
address.searchParams.set('pluginId', activePluginId());
|
|
603
607
|
address.searchParams.set('connectionId', catalog.connectionId);
|
|
604
608
|
if (preparedSession?.sessionId) address.searchParams.set('sessionId', preparedSession.sessionId);
|
|
605
609
|
return address.toString();
|
|
606
610
|
};
|
|
607
611
|
function render() {
|
|
608
612
|
const plugin = chosen();
|
|
609
|
-
$('plugin-name').textContent =
|
|
613
|
+
$('plugin-name').textContent = catalog?.plugins?.length ? `${catalog.plugins.filter(item => item.enabled).length} 个插件 · 调试画布` : '插件调试画布';
|
|
610
614
|
const building = catalog?.devBuild?.state;
|
|
611
|
-
$('state').textContent = building === 'error' ? '构建失败' : building === 'building' ? '正在构建' :
|
|
612
|
-
$('dot').className = `dot ${building === 'error' || frameFailed ? 'error' : building === 'building'
|
|
615
|
+
$('state').textContent = building === 'error' ? '构建失败' : building === 'building' ? '正在构建' : frameFailed ? '画布加载失败' : busy ? (session ? '正在刷新' : '正在打开画布') : session ? (!session.active ? '会话已失效' : hasNewBuild() ? '发现新构建' : '已连接') : '等待画布';
|
|
616
|
+
$('dot').className = `dot ${building === 'error' || frameFailed ? 'error' : building === 'building' ? 'warning' : session ? !session.active ? 'error' : hasNewBuild() ? 'warning' : 'ready' : ''}`;
|
|
613
617
|
$('refresh').disabled = !session?.active || busy || frameFailed || Boolean(building && building !== 'ready');
|
|
614
618
|
const stateText = $('state').textContent;
|
|
615
619
|
$('panel-status').textContent = stateText;
|
|
616
620
|
$('panel-status').className = `status-badge ${$('dot').classList.contains('error') ? 'error' : $('dot').classList.contains('ready') ? 'ready' : ''}`;
|
|
617
621
|
$('connection').textContent = connectorStatus?.phase === 'connected' ? '已连接 · 本机' : '未连接';
|
|
618
|
-
$('active-plugin').textContent =
|
|
619
|
-
$('build').textContent = building === 'error' ? '构建失败' : building === 'building' ? '构建中' :
|
|
622
|
+
$('active-plugin').textContent = catalog?.plugins.filter(item => item.enabled).map(item => item.name).join('、') || '';
|
|
623
|
+
$('build').textContent = building === 'error' ? '构建失败' : building === 'building' ? '构建中' : `${catalog?.plugins.filter(item => item.enabled).length || 0} 个插件`;
|
|
620
624
|
$('project').textContent = session?.active ? '私人调试画布' : session ? '会话已失效' : '等待打开';
|
|
621
625
|
$('connection-id').textContent = catalog?.connectionId || '—';
|
|
622
|
-
$('build-full').textContent =
|
|
626
|
+
$('build-full').textContent = catalog?.plugins.filter(item => item.enabled).map(item => `${item.name}: ${item.buildKey}`).join('\n') || '—';
|
|
623
627
|
$('project-id').textContent = session?.projectId || '—';
|
|
624
628
|
renderPluginList();
|
|
625
629
|
renderConfig();
|
|
@@ -633,7 +637,7 @@ dialog::backdrop { background: #30384266; }
|
|
|
633
637
|
$('detail-package').textContent = inspected?.package ? '插件包可下载' : '插件包不可用';
|
|
634
638
|
$('detail-status').textContent = inspected?.configurationRequired ? '待配置' : inspected?.enabled ? '已启用' : '已停用';
|
|
635
639
|
$('detail-status').className = `status-badge ${inspected?.configurationRequired ? '' : inspected?.enabled ? 'ready' : 'error'}`;
|
|
636
|
-
$('open-plugin').disabled =
|
|
640
|
+
$('open-plugin').disabled = busy || packageDownloading;
|
|
637
641
|
$('download-package').disabled = !inspected?.package || packageDownloading;
|
|
638
642
|
$('download-package').setAttribute('aria-busy', String(packageDownloading));
|
|
639
643
|
$('download-label').textContent = packageDownloading ? '正在准备…' : inspected?.package?.mode === 'build' ? '打包并下载' : '下载插件包';
|
|
@@ -649,13 +653,13 @@ dialog::backdrop { background: #30384266; }
|
|
|
649
653
|
$('empty-text').textContent = '正在打开调试画布…';
|
|
650
654
|
canvasDialogOpen = false; expandedOverDialog = false; renderDock(); render();
|
|
651
655
|
try {
|
|
652
|
-
const response = await fetch('/studio/open', { method: 'POST', headers: { 'content-type': 'application/json' }, body:
|
|
656
|
+
const response = await fetch('/studio/open', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' });
|
|
653
657
|
const next = await response.json();
|
|
654
658
|
if (!response.ok) throw new Error(next.message || next.error || '调试画布创建失败');
|
|
655
659
|
preparedSession = next;
|
|
656
660
|
} catch (error) { busy = false; frameLoading = false; frameFailed = true; $('empty-text').textContent = error.message; $('retry').hidden = false; show(error.message); log(error.message); render(); return; }
|
|
657
661
|
frame.src = url();
|
|
658
|
-
log(
|
|
662
|
+
log('打开全部插件的调试画布');
|
|
659
663
|
readyTimer = setTimeout(() => {
|
|
660
664
|
if (!session) {
|
|
661
665
|
busy = false; frameLoading = false; frameFailed = true; $('retry').hidden = false;
|
|
@@ -695,7 +699,7 @@ dialog::backdrop { background: #30384266; }
|
|
|
695
699
|
if (event.origin === window.location.origin && event.data?.type === 'plugin-debug-auth-complete') { void loadConnectionStatus(); return; }
|
|
696
700
|
if (!catalog || event.origin !== catalog.platformOrigin || event.source !== frame.contentWindow) return;
|
|
697
701
|
const data = event.data;
|
|
698
|
-
if (!data || typeof data !== 'object' || data.protocol !== protocol || data.pluginId !==
|
|
702
|
+
if (!data || typeof data !== 'object' || data.protocol !== protocol || data.pluginId !== activePluginId()) return;
|
|
699
703
|
if (data.type === 'bootstrap.request' && preparedSession?.sessionId === data.sessionId &&
|
|
700
704
|
typeof data.codeChallenge === 'string' && /^[A-Za-z0-9_-]{43,128}$/.test(data.codeChallenge)) {
|
|
701
705
|
void (async () => {
|
|
@@ -704,7 +708,7 @@ dialog::backdrop { background: #30384266; }
|
|
|
704
708
|
body: JSON.stringify({ debugSessionId: data.sessionId, codeChallenge: data.codeChallenge }) });
|
|
705
709
|
const issued = await response.json();
|
|
706
710
|
if (!response.ok) throw new Error(issued.message || issued.error || '画布登录失败');
|
|
707
|
-
frame.contentWindow.postMessage({ protocol, type: 'bootstrap.ticket', pluginId:
|
|
711
|
+
frame.contentWindow.postMessage({ protocol, type: 'bootstrap.ticket', pluginId: activePluginId(),
|
|
708
712
|
sessionId: data.sessionId, ticket: issued.ticket }, catalog.platformOrigin);
|
|
709
713
|
} catch (error) { show(error.message); log(error.message); }
|
|
710
714
|
})();
|
|
@@ -726,6 +730,10 @@ dialog::backdrop { background: #30384266; }
|
|
|
726
730
|
if (data.type === 'status' && data.status?.sessionId === session.sessionId) { session = data.status; if (!session.active) show('调试会话已失效,请在管理菜单中重新连接。'); render(); return; }
|
|
727
731
|
if (data.type === 'refreshing' && data.requestId === waiting) { busy = true; log('正在保存画布并检查新构建'); render(); }
|
|
728
732
|
if (data.type === 'refreshResult' && data.requestId === waiting) {
|
|
733
|
+
if (data.status?.sessionId !== session.sessionId) {
|
|
734
|
+
waiting = null; show('插件列表已更新,正在重新打开调试画布。', false);
|
|
735
|
+
void connect(); return;
|
|
736
|
+
}
|
|
729
737
|
session = data.status; waiting = null; busy = Boolean(data.changed); frameLoading = Boolean(data.changed); show(data.changed ? '新构建已启用,正在重新加载画布…' : '当前已经是最新构建。', false); log(data.changed ? '构建已更新,画布正在重载' : '当前构建没有变化');
|
|
730
738
|
if (data.changed) $('empty-text').textContent = '正在加载新构建…';
|
|
731
739
|
if (data.changed) readyTimer = setTimeout(() => {
|
|
@@ -740,7 +748,7 @@ dialog::backdrop { background: #30384266; }
|
|
|
740
748
|
$('refresh').addEventListener('click', () => {
|
|
741
749
|
if (!session || busy) return;
|
|
742
750
|
waiting = crypto.randomUUID(); busy = true;
|
|
743
|
-
frame.contentWindow.postMessage({ protocol, type: 'refresh', sessionId: session.sessionId, pluginId:
|
|
751
|
+
frame.contentWindow.postMessage({ protocol, type: 'refresh', sessionId: session.sessionId, pluginId: activePluginId(), requestId: waiting }, catalog.platformOrigin);
|
|
744
752
|
render();
|
|
745
753
|
});
|
|
746
754
|
function openPanel(forConfiguration = false) {
|
|
@@ -789,8 +797,7 @@ dialog::backdrop { background: #30384266; }
|
|
|
789
797
|
} catch (error) { configFeedback = { pluginId: plugin.id, message: error.message || '配置检查失败' }; $('config-status').textContent = configFeedback.message; }
|
|
790
798
|
});
|
|
791
799
|
$('open-plugin').addEventListener('click', () => {
|
|
792
|
-
|
|
793
|
-
selected = panelSelected; show(''); panel.close(); connect();
|
|
800
|
+
panel.close();
|
|
794
801
|
});
|
|
795
802
|
$('download-package').addEventListener('click', async () => {
|
|
796
803
|
const plugin = panelPlugin();
|
|
@@ -42,7 +42,7 @@ export declare class RemoteStudioConnector {
|
|
|
42
42
|
}>;
|
|
43
43
|
private post;
|
|
44
44
|
private renewAccessToken;
|
|
45
|
-
openDebugSession(pluginId
|
|
45
|
+
openDebugSession(pluginId?: string): Promise<{
|
|
46
46
|
sessionId: string;
|
|
47
47
|
projectId: string;
|
|
48
48
|
connectionId: string;
|
|
@@ -119,7 +119,7 @@ export class RemoteStudioConnector {
|
|
|
119
119
|
if (!this.ticket || this.phase !== 'connected')
|
|
120
120
|
throw new Error('请先连接画布平台');
|
|
121
121
|
await this.renewAccessToken();
|
|
122
|
-
return this.post(`/canvas-workflow/plugin-debug-connectors/${this.ticket.connectionId}/open`, { pluginId }, true);
|
|
122
|
+
return this.post(`/canvas-workflow/plugin-debug-connectors/${this.ticket.connectionId}/open`, pluginId ? { pluginId } : {}, true);
|
|
123
123
|
}
|
|
124
124
|
async createEmbedTicket(debugSessionId, codeChallenge) {
|
|
125
125
|
if (!this.ticket || this.phase !== 'connected')
|
package/package.json
CHANGED
|
@@ -27,9 +27,11 @@ export async function buildPluginPackage({
|
|
|
27
27
|
},
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
).
|
|
30
|
+
const serverModule = resolve(directory, 'server/plugin.mjs');
|
|
31
|
+
const serverBytes = await readFile(serverModule);
|
|
32
|
+
const moduleUrl = new URL(pathToFileURL(serverModule).href);
|
|
33
|
+
moduleUrl.searchParams.set('build', createHash('sha256').update(serverBytes).digest('hex'));
|
|
34
|
+
const plugin = (await import(moduleUrl.href)).default;
|
|
33
35
|
if (!plugin?.manifest) throw new Error(`插件入口 ${serverEntry} 必须默认导出 definePlugin(...)`);
|
|
34
36
|
await build({
|
|
35
37
|
configFile: false,
|