@easyai-canvas/canvas-plugin-sdk 0.1.0 → 0.1.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 +2 -0
- package/dist/protocol/index.d.ts +2 -0
- package/dist/protocol/index.js +12 -3
- package/dist/runtime/package-runtime.js +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,3 +20,5 @@ npm start
|
|
|
20
20
|
托管节点暂不支持文件和画布宿主能力。管理员导入 ZIP 后默认停用,审核插件代码、声明能力和版本摘要后启用。版本切换不会改变已提交任务使用的包摘要。
|
|
21
21
|
|
|
22
22
|
公开导入路径:`@easyai-canvas/canvas-plugin-sdk`、`@easyai-canvas/canvas-plugin-sdk/protocol`、`@easyai-canvas/canvas-plugin-sdk/ui`。客户项目不需访问 EasyAI 画布源码。
|
|
23
|
+
|
|
24
|
+
后台节点从 `request.parameters` 读取用户在画布上设置的参数,从 `request.inputsByPort` 读取上游数据,从 `request.context.runtime` 读取平台生成的默认上下文。查询处理器的第三个参数也是默认上下文,其中 `user.ssoId` 仅在用户已绑定 SSO 时提供。默认上下文不包含用户登录 Token;插件不得把参数或查询输入中的身份字段当作平台身份。
|
package/dist/protocol/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export type PluginMenuContribution = {
|
|
|
50
50
|
order?: number;
|
|
51
51
|
icon?: string;
|
|
52
52
|
};
|
|
53
|
+
/** Platform-derived identity and location, shared by backend node handlers and queries. Never accepts a login token. */
|
|
53
54
|
export type PluginRuntimeContext = {
|
|
54
55
|
user: {
|
|
55
56
|
id: string;
|
|
@@ -182,6 +183,7 @@ export type ExecutionRequest = {
|
|
|
182
183
|
executionId: string;
|
|
183
184
|
pluginId: string;
|
|
184
185
|
nodeType: string;
|
|
186
|
+
/** User-edited node settings. Neither these nor inputsByPort can override context.runtime. */
|
|
185
187
|
parameters: Record<string, unknown>;
|
|
186
188
|
inputsByPort: Record<string, DataPacket[]>;
|
|
187
189
|
document?: {
|
package/dist/protocol/index.js
CHANGED
|
@@ -325,12 +325,21 @@ export function validateExecution(value, node) {
|
|
|
325
325
|
if (request.nodeType !== node.type)
|
|
326
326
|
throw new ContractError('节点类型不匹配');
|
|
327
327
|
object(request.parameters, 'parameters');
|
|
328
|
-
const context =
|
|
328
|
+
const context = keys(request.context, ['nodeId', 'taskId', 'userId', 'projectId', 'runtime'], 'execution.context');
|
|
329
329
|
identifier(context.nodeId, 'nodeId');
|
|
330
330
|
if (typeof context.userId !== 'string' || !context.userId)
|
|
331
331
|
throw new ContractError('调用身份缺失');
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
optionalString(context.taskId, 'context.taskId');
|
|
333
|
+
optionalString(context.projectId, 'context.projectId');
|
|
334
|
+
if (context.runtime !== undefined) {
|
|
335
|
+
const runtime = validatePluginRuntimeContext(context.runtime);
|
|
336
|
+
if (runtime.user.id !== context.userId)
|
|
337
|
+
throw new ContractError('运行上下文身份不匹配');
|
|
338
|
+
if (runtime.projectId !== undefined && runtime.projectId !== context.projectId)
|
|
339
|
+
throw new ContractError('运行上下文项目不匹配');
|
|
340
|
+
if (runtime.nodeId !== undefined && runtime.nodeId !== context.nodeId)
|
|
341
|
+
throw new ContractError('运行上下文节点不匹配');
|
|
342
|
+
}
|
|
334
343
|
if (request.host !== undefined) {
|
|
335
344
|
const host = keys(request.host, ['files'], 'execution.host');
|
|
336
345
|
if (host.files !== undefined) {
|
|
@@ -4,7 +4,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
4
4
|
import { mkdir, readFile, writeFile, rename, rm, lstat, } from 'node:fs/promises';
|
|
5
5
|
import { join, dirname } from 'node:path';
|
|
6
6
|
import { fork } from 'node:child_process';
|
|
7
|
-
import { ContractError, validateManifest, validateExecution, object, } from '../protocol/index.js';
|
|
7
|
+
import { ContractError, validateManifest, validateExecution, validatePluginRuntimeContext, object, } from '../protocol/index.js';
|
|
8
8
|
export const PLUGIN_PACKAGE_MAX_BYTES = 16 * 1024 * 1024;
|
|
9
9
|
const MAX_EXPANDED_BYTES = 64 * 1024 * 1024;
|
|
10
10
|
const MAX_FILES = 128;
|
|
@@ -278,6 +278,10 @@ export async function invokePluginPackage(pkg, call, options = {}) {
|
|
|
278
278
|
throw new ContractError('插件节点处理器与安装包声明不匹配', 400, 'INVALID_PACKAGE');
|
|
279
279
|
call = { ...call, request: validateExecution(request, node) };
|
|
280
280
|
}
|
|
281
|
+
if (call.operation === 'query' && call.context !== undefined) {
|
|
282
|
+
// Platform queries always carry a context; keep direct legacy package calls compatible.
|
|
283
|
+
call = { ...call, context: validatePluginRuntimeContext(call.context) };
|
|
284
|
+
}
|
|
281
285
|
if (Number(process.versions.node.split('.')[0]) !==
|
|
282
286
|
pkg.descriptor.runtime.nodeMajor)
|
|
283
287
|
throw new ContractError('平台 Node 运行版本不兼容', 400, 'INVALID_PACKAGE');
|