feat: publish immutable workflow definitions with typed SDK

This commit is contained in:
2026-09-18 00:28:00 +08:00
parent a664ec9370
commit 520e98d9d1
33 changed files with 2603 additions and 11 deletions

75
weave/definition/data.go Normal file
View File

@@ -0,0 +1,75 @@
package definition
import (
"bytes"
"encoding/json"
"git.yuntuo.hk/k2safe/orbit/internal/jsonvalue"
)
// ValidateData 在实例输入、任务成功结果、信号和块输出边界复用同一类型契约。
// 使用精确JSON数值文本;大小、重复字段、Unicode和嵌套限制先于类型检查。
func ValidateData(schema Type, raw json.RawMessage) error {
if err := checkType(schema, 0); err != nil {
return err
}
if len(raw) == 0 || len(raw) > 256<<10 {
return invalid("data", "JSON value required, maximum 256 KiB")
}
if _, err := jsonvalue.Canonical(raw); err != nil {
return invalid("data", "invalid JSON, duplicate fields or unsupported value limits")
}
var value any
d := json.NewDecoder(bytes.NewReader(raw))
d.UseNumber()
if err := d.Decode(&value); err != nil {
return invalid("data", "invalid JSON value")
}
return matchData(schema, value)
}
func matchData(schema Type, value any) error {
valid := false
switch schema.Kind {
case "JSON":
return nil
case "NULL":
valid = value == nil
case "STRING":
v, ok := value.(string)
valid = ok && (len(schema.Enum) == 0 || contains(schema.Enum, v))
case "NUMBER":
_, valid = value.(json.Number)
case "BOOLEAN":
_, valid = value.(bool)
case "OBJECT":
v, ok := value.(map[string]any)
if !ok || len(v) != len(schema.Fields) {
return invalid("data", "object fields do not match declared type")
}
for key, t := range schema.Fields {
child, ok := v[key]
if !ok {
return invalid("data", "required object field missing")
}
if err := matchData(t, child); err != nil {
return err
}
}
return nil
case "ARRAY":
v, ok := value.([]any)
if !ok || len(v) > 4096 {
return invalid("data", "array required, maximum 4096 elements")
}
for _, child := range v {
if err := matchData(*schema.Items, child); err != nil {
return err
}
}
return nil
}
if !valid {
return invalid("data", "value does not match declared type")
}
return nil
}