@graphvideo/backend-sdk 1.0.0
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/index.d.ts +39 -0
- package/dist/index.mjs +99 -0
- package/dist/plugin-manifest.d.mts +19 -0
- package/package.json +27 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Info, Node } from '@graphvideo/kernel';
|
|
2
|
+
export type AnyNode = Node<any, any>;
|
|
3
|
+
/** Creates exactly one ordinary Node and never creates or owns a Runtime. */
|
|
4
|
+
export type NodeFactory<Input = void, Output extends AnyNode = AnyNode> = (input: Input) => Output;
|
|
5
|
+
/** Creates a flat batch of ordinary Nodes and never creates or owns a Runtime. */
|
|
6
|
+
export type GraphFactory<Input = void, Output extends AnyNode = AnyNode> = (input: Input) => readonly Output[];
|
|
7
|
+
export declare function defineNodeFactory<Input, Output extends AnyNode>(factory: NodeFactory<Input, Output>): NodeFactory<Input, Output>;
|
|
8
|
+
export declare function defineGraphFactory<Input, Output extends AnyNode>(factory: GraphFactory<Input, Output>): GraphFactory<Input, Output>;
|
|
9
|
+
export interface BackendPluginContext<Dependencies> {
|
|
10
|
+
readonly pluginId: string;
|
|
11
|
+
readonly dependencies: Readonly<Dependencies>;
|
|
12
|
+
}
|
|
13
|
+
export interface BackendPlugin<Dependencies = Record<string, never>> {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
createNodes(context: BackendPluginContext<Dependencies>): readonly AnyNode[];
|
|
16
|
+
/** Explicit user commands only. Internal observations and WorldNode effects
|
|
17
|
+
* must not be public roots. Backend code is trusted, not sandboxed. */
|
|
18
|
+
readonly rendererRoots?: readonly RendererRoot[];
|
|
19
|
+
}
|
|
20
|
+
export interface RendererRoot {
|
|
21
|
+
readonly targetNodeId: string;
|
|
22
|
+
readonly infoType: string;
|
|
23
|
+
readonly validate: (info: Info) => boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function assertRendererRoot<Dependencies>(plugins: readonly BackendPlugin<Dependencies>[], input: {
|
|
26
|
+
targetNodeId: string;
|
|
27
|
+
info: Info;
|
|
28
|
+
}): void;
|
|
29
|
+
export interface BackendPluginModule<Dependencies = Record<string, never>> {
|
|
30
|
+
readonly default?: BackendPlugin<Dependencies>;
|
|
31
|
+
readonly plugin?: BackendPlugin<Dependencies>;
|
|
32
|
+
}
|
|
33
|
+
export declare function defineBackendPlugin<Dependencies>(plugin: BackendPlugin<Dependencies>): BackendPlugin<Dependencies>;
|
|
34
|
+
export declare function createPluginNodes<Dependencies>(plugins: readonly BackendPlugin<Dependencies>[], dependencies: Dependencies): readonly AnyNode[];
|
|
35
|
+
export type { EffectAdapter, EffectContext } from '@graphvideo/kernel';
|
|
36
|
+
export { Node, WorldNode } from '@graphvideo/kernel';
|
|
37
|
+
export type { ChangeContext, DomainChangeContext, Info, WorldChangeContext, } from '@graphvideo/kernel';
|
|
38
|
+
export type { StudioPluginManifest } from './plugin-manifest.mjs';
|
|
39
|
+
export { defineStudioPluginManifest, parseStudioPluginManifest, } from './plugin-manifest.mjs';
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Node as e, WorldNode as t } from "@graphvideo/kernel";
|
|
2
|
+
//#region sdk/backend/plugin-manifest.mjs
|
|
3
|
+
var n = /^[a-z0-9][a-z0-9.-]*$/, r = /^(?![\\/])(?!.*(?:^|[\\/])\.\.(?:[\\/]|$)).+$/;
|
|
4
|
+
function i(e, t) {
|
|
5
|
+
if (e === void 0) return [];
|
|
6
|
+
if (!Array.isArray(e) || e.some((e) => typeof e != "string" || !n.test(e))) throw Error(`Plugin ${t} 必须是合法 ID 数组`);
|
|
7
|
+
if (new Set(e).size !== e.length) throw Error(`Plugin ${t} 存在重复 ID`);
|
|
8
|
+
return [...e];
|
|
9
|
+
}
|
|
10
|
+
function a(e, t) {
|
|
11
|
+
if (e !== void 0) {
|
|
12
|
+
if (typeof e != "string" || !r.test(e.replace(/\\/g, "/"))) throw Error(`Plugin ${t} 必须是包内相对路径`);
|
|
13
|
+
return e.replace(/\\/g, "/");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function o(e) {
|
|
17
|
+
let t = e;
|
|
18
|
+
if (typeof e == "string") try {
|
|
19
|
+
t = JSON.parse(e);
|
|
20
|
+
} catch {
|
|
21
|
+
throw Error("graphvideo.plugin.json 不是有效 JSON");
|
|
22
|
+
}
|
|
23
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw Error("graphvideo.plugin.json 必须是对象");
|
|
24
|
+
let r = t;
|
|
25
|
+
if (r.apiVersion !== 1) throw Error("Plugin apiVersion 必须是 1");
|
|
26
|
+
if (typeof r.id != "string" || !n.test(r.id)) throw Error("Plugin id 只能包含小写字母、数字、点和短横线");
|
|
27
|
+
if (typeof r.name != "string" || !r.name.trim()) throw Error("Plugin name 不能为空");
|
|
28
|
+
if (typeof r.version != "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(r.version)) throw Error("Plugin version 必须是 SemVer");
|
|
29
|
+
let o = r.contributes === void 0 ? {} : r.contributes;
|
|
30
|
+
if (!o || typeof o != "object" || Array.isArray(o)) throw Error("Plugin contributes 必须是对象");
|
|
31
|
+
return Object.freeze({
|
|
32
|
+
id: r.id,
|
|
33
|
+
name: r.name.trim(),
|
|
34
|
+
version: r.version,
|
|
35
|
+
apiVersion: 1,
|
|
36
|
+
contributes: Object.freeze({
|
|
37
|
+
backend: a(o.backend, "contributes.backend"),
|
|
38
|
+
elements: Object.freeze(i(o.elements, "contributes.elements")),
|
|
39
|
+
workspaces: Object.freeze(i(o.workspaces, "contributes.workspaces"))
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function s(e) {
|
|
44
|
+
return o(e);
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region sdk/backend/index.ts
|
|
48
|
+
function c(e) {
|
|
49
|
+
return (t) => {
|
|
50
|
+
let n = e(t);
|
|
51
|
+
if (!n.id) throw Error("NodeFactory 必须产出具有非空 id 的 Node");
|
|
52
|
+
return n;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function l(e) {
|
|
56
|
+
return (t) => {
|
|
57
|
+
let n = e(t), r = /* @__PURE__ */ new Set();
|
|
58
|
+
for (let e of n) {
|
|
59
|
+
if (!e.id) throw Error("GraphFactory 必须产出具有非空 id 的 Node");
|
|
60
|
+
if (r.has(e.id)) throw Error(`GraphFactory 产出了重复 Node ID: ${e.id}`);
|
|
61
|
+
r.add(e.id);
|
|
62
|
+
}
|
|
63
|
+
return n;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function u(e, t) {
|
|
67
|
+
let n = e.flatMap((e) => e.rendererRoots ?? []).find((e) => e.targetNodeId === t?.targetNodeId && e.infoType === t?.info?.type);
|
|
68
|
+
if (!n || !n.validate(t.info)) throw Error("Renderer root Info 未授权或参数无效");
|
|
69
|
+
}
|
|
70
|
+
function d(e) {
|
|
71
|
+
if (!e.id.trim()) throw Error("Backend Plugin id 不能为空");
|
|
72
|
+
if (typeof e.createNodes != "function") throw Error(`Backend Plugin ${e.id} 缺少 createNodes`);
|
|
73
|
+
return Object.freeze(e);
|
|
74
|
+
}
|
|
75
|
+
function f(e, t) {
|
|
76
|
+
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Map(), i = [];
|
|
77
|
+
for (let a of [...e].sort((e, t) => e.id.localeCompare(t.id))) {
|
|
78
|
+
if (n.has(a.id)) throw Error(`Backend Plugin ID 重复: ${a.id}`);
|
|
79
|
+
n.add(a.id);
|
|
80
|
+
let e = a.createNodes({
|
|
81
|
+
pluginId: a.id,
|
|
82
|
+
dependencies: t
|
|
83
|
+
}), o = new Set(e.map((e) => e.id)), s = /* @__PURE__ */ new Set();
|
|
84
|
+
for (let e of a.rendererRoots ?? []) {
|
|
85
|
+
let t = `${e.targetNodeId}\0${e.infoType}`;
|
|
86
|
+
if (!o.has(e.targetNodeId) || !e.infoType || typeof e.validate != "function" || s.has(t)) throw Error(`Plugin ${a.id} renderer root 无效: ${t}`);
|
|
87
|
+
s.add(t);
|
|
88
|
+
}
|
|
89
|
+
for (let t of e) {
|
|
90
|
+
if (!t.id) throw Error(`Backend Plugin ${a.id} 产出了空 Node ID`);
|
|
91
|
+
let e = r.get(t.id);
|
|
92
|
+
if (e) throw Error(`Node ID 冲突: ${t.id} (${e} / ${a.id})`);
|
|
93
|
+
r.set(t.id, a.id), i.push(t);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return i;
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { e as Node, t as WorldNode, u as assertRendererRoot, f as createPluginNodes, d as defineBackendPlugin, l as defineGraphFactory, c as defineNodeFactory, s as defineStudioPluginManifest, o as parseStudioPluginManifest };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface StudioPluginManifest {
|
|
2
|
+
readonly id: string
|
|
3
|
+
readonly name: string
|
|
4
|
+
readonly version: string
|
|
5
|
+
readonly apiVersion: 1
|
|
6
|
+
readonly contributes: {
|
|
7
|
+
readonly backend?: string
|
|
8
|
+
readonly elements: readonly string[]
|
|
9
|
+
readonly workspaces: readonly string[]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function parseStudioPluginManifest(textOrValue: string | unknown): StudioPluginManifest
|
|
14
|
+
export function defineStudioPluginManifest(
|
|
15
|
+
manifest: StudioPluginManifest | (Omit<StudioPluginManifest, 'contributes'> & {
|
|
16
|
+
contributes?: Partial<StudioPluginManifest['contributes']>
|
|
17
|
+
}),
|
|
18
|
+
): StudioPluginManifest
|
|
19
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@graphvideo/backend-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Backend plugin SDK for GraphFramework: Node factories, plugin contract, kernel re-exports",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git@github.com:vd249175-cpu/GSDK.git",
|
|
13
|
+
"directory": "sdk/backend"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.mjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@graphvideo/kernel": "^1.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|