package contract import ( "bytes" "fmt" "path" "strings" "sync" "git.ipao.vip/rogee/go-sip/contracts" "github.com/santhosh-tekuri/jsonschema/v6" ) var compiledSchemas sync.Map type bundleLoader struct{ version string } func (l bundleLoader) base() string { return "https://go-sip.local/contracts/" + l.version + "/" } // Load never accesses the network or resolves references against another bundle. func (l bundleLoader) Load(address string) (any, error) { if !strings.HasPrefix(address, l.base()) { return nil, fmt.Errorf("schema reference outside pinned bundle: %s", address) } name := strings.TrimPrefix(address, l.base()) if name == "" || path.Base(name) != name || !strings.HasSuffix(name, ".schema.json") { return nil, fmt.Errorf("invalid schema resource name %q", name) } raw, err := contracts.Files.ReadFile("upstream/" + l.version + "/" + name) if err != nil { return nil, fmt.Errorf("read pinned schema %s: %w", name, err) } return jsonschema.UnmarshalJSON(bytes.NewReader(raw)) } const projectLocalSchemaBase = "https://go-sip.local/contracts/proposals/" type projectBundleLoader struct{} func (projectBundleLoader) Load(address string) (any, error) { upstream := bundleLoader{version: contracts.SourceCommit} if strings.HasPrefix(address, upstream.base()) { return upstream.Load(address) } if !strings.HasPrefix(address, projectLocalSchemaBase) { return nil, fmt.Errorf("schema reference outside pinned project bundles: %s", address) } name := strings.TrimPrefix(address, projectLocalSchemaBase) if name == "" || path.Base(name) != name || !strings.HasSuffix(name, ".schema.json") { return nil, fmt.Errorf("invalid project-local schema resource %q", name) } raw, err := contracts.ReadLocal(localSchemaVersion(name), name) if err != nil { return nil, fmt.Errorf("read project-local schema %s: %w", name, err) } return jsonschema.UnmarshalJSON(bytes.NewReader(raw)) } func localSchemaVersion(name string) string { switch name { case "config-read-v0.1.schema.json", "command-next-v0.1-proposal.schema.json", "call-result-v0.1-proposal.schema.json", "local-mock-recording-failure-v0.1.schema.json": return "v0.1" case "config-read-v0.2.schema.json": return "v0.2" case "config-read-v0.3.schema.json", "ai-authorization-v0.2.schema.json", "static-cell-artifact-v0.2.schema.json", "task-discovery-v0.3-proposal.schema.json": return "v0.3" case "task-discovery-v0.4-proposal.schema.json", "task-control-v0.4-proposal.schema.json", "call-execute-v0.4-proposal.schema.json": return "v0.4" default: return "" } } func localSchemaFromBundle(name string) (*jsonschema.Schema, error) { version := localSchemaVersion(name) if version == "" { return nil, fmt.Errorf("unknown project-local schema %q", name) } key := "local/" + version + "/" + name if cached, ok := compiledSchemas.Load(key); ok { return cached.(*jsonschema.Schema), nil } raw, err := contracts.ReadLocal(version, name) if err != nil { return nil, err } doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(raw)) if err != nil { return nil, fmt.Errorf("decode project-local schema %s: %w", name, err) } resource := projectLocalSchemaBase + name compiler := jsonschema.NewCompiler() compiler.UseLoader(projectBundleLoader{}) compiler.AssertFormat() if err := compiler.AddResource(resource, doc); err != nil { return nil, fmt.Errorf("register project-local schema %s: %w", name, err) } schema, err := compiler.Compile(resource) if err != nil { return nil, fmt.Errorf("compile project-local schema %s: %w", name, err) } actual, _ := compiledSchemas.LoadOrStore(key, schema) return actual.(*jsonschema.Schema), nil } func schemaFromBundle(version, name string) (*jsonschema.Schema, error) { key := version + "/" + name if cached, ok := compiledSchemas.Load(key); ok { return cached.(*jsonschema.Schema), nil } loader := bundleLoader{version: version} resource := loader.base() + name doc, err := loader.Load(resource) if err != nil { return nil, err } compiler := jsonschema.NewCompiler() compiler.UseLoader(loader) compiler.AssertFormat() if err := compiler.AddResource(resource, doc); err != nil { return nil, fmt.Errorf("register %s: %w", name, err) } schema, err := compiler.Compile(resource) if err != nil { return nil, fmt.Errorf("compile %s: %w", name, err) } actual, _ := compiledSchemas.LoadOrStore(key, schema) return actual.(*jsonschema.Schema), nil }