 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			428 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			428 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package schemadmt
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/ipld/go-ipld-prime/datamodel"
 | |
| 	"github.com/ipld/go-ipld-prime/schema"
 | |
| )
 | |
| 
 | |
| // Compile transforms a description of a schema in raw data model ("dmt") form
 | |
| // into a compiled schema.TypeSystem, which is the ready-to-use form.
 | |
| //
 | |
| // The first parameter is mutated by this process,
 | |
| // and the second parameter is the data source.
 | |
| //
 | |
| // The compilation process includes first inserting the "prelude" types into the
 | |
| // schema.TypeSystem -- that is, the "type Bool bool" and "type String string", etc,
 | |
| // which are generally presumed to be present in any type system.
 | |
| //
 | |
| // The compilation process attempts to check the validity of the schema at a logical level as it goes.
 | |
| // For example, references to type names not present elsewhere in the same schema are now an error
 | |
| // (even though that has been easily representable in the dmt.Schema form up until this point).
 | |
| //
 | |
| // Note that this API is EXPERIMENTAL and will likely change.
 | |
| // It supports many features of IPLD Schemas,
 | |
| // but it may yet not support all of them.
 | |
| // It supports several validations for logical coherency of schemas,
 | |
| // but may not yet successfully reject all invalid schemas.
 | |
| func Compile(ts *schema.TypeSystem, node *Schema) error {
 | |
| 	// Prelude; probably belongs elsewhere.
 | |
| 	{
 | |
| 		ts.Accumulate(schema.SpawnBool("Bool"))
 | |
| 		ts.Accumulate(schema.SpawnInt("Int"))
 | |
| 		ts.Accumulate(schema.SpawnFloat("Float"))
 | |
| 		ts.Accumulate(schema.SpawnString("String"))
 | |
| 		ts.Accumulate(schema.SpawnBytes("Bytes"))
 | |
| 
 | |
| 		ts.Accumulate(schema.SpawnAny("Any"))
 | |
| 
 | |
| 		ts.Accumulate(schema.SpawnMap("Map", "String", "Any", false))
 | |
| 		ts.Accumulate(schema.SpawnList("List", "Any", false))
 | |
| 
 | |
| 		// Should be &Any, really.
 | |
| 		ts.Accumulate(schema.SpawnLink("Link"))
 | |
| 
 | |
| 		// TODO: schema package lacks support?
 | |
| 		// ts.Accumulate(schema.SpawnUnit("Null", NullRepr))
 | |
| 	}
 | |
| 
 | |
| 	for _, name := range node.Types.Keys {
 | |
| 		defn := node.Types.Values[name]
 | |
| 
 | |
| 		// TODO: once ./schema supports anonymous/inline types, remove the ts argument.
 | |
| 		typ, err := spawnType(ts, name, defn)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		ts.Accumulate(typ)
 | |
| 	}
 | |
| 
 | |
| 	// TODO: if this fails and the user forgot to check Compile's returned error,
 | |
| 	// we can leave the TypeSystem in an unfortunate broken state:
 | |
| 	// they can obtain types out of the TypeSystem and they are non-nil,
 | |
| 	// but trying to use them in any way may result in panics.
 | |
| 	// Consider making that less prone to misuse, such as making it illegal to
 | |
| 	// call TypeByName until ValidateGraph is happy.
 | |
| 	if errs := ts.ValidateGraph(); errs != nil {
 | |
| 		// Return the first error.
 | |
| 		for _, err := range errs {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Note that the parser and compiler support defaults. We're lacking support in bindnode.
 | |
| func todoFromImplicitlyFalseBool(b *bool) bool {
 | |
| 	if b == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	return *b
 | |
| }
 | |
| 
 | |
| func anonTypeName(nameOrDefn TypeNameOrInlineDefn) string {
 | |
| 	if nameOrDefn.TypeName != nil {
 | |
| 		return *nameOrDefn.TypeName
 | |
| 	}
 | |
| 	defn := *nameOrDefn.InlineDefn
 | |
| 	switch {
 | |
| 	case defn.TypeDefnMap != nil:
 | |
| 		defn := defn.TypeDefnMap
 | |
| 		return fmt.Sprintf("Map__%s__%s", defn.KeyType, anonTypeName(defn.ValueType))
 | |
| 	case defn.TypeDefnList != nil:
 | |
| 		defn := defn.TypeDefnList
 | |
| 		return fmt.Sprintf("List__%s", anonTypeName(defn.ValueType))
 | |
| 	case defn.TypeDefnLink != nil:
 | |
| 		return anonLinkName(*defn.TypeDefnLink)
 | |
| 	default:
 | |
| 		panic(fmt.Errorf("%#v", defn))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func anonLinkName(defn TypeDefnLink) string {
 | |
| 	if defn.ExpectedType != nil {
 | |
| 		return fmt.Sprintf("Link__%s", *defn.ExpectedType)
 | |
| 	}
 | |
| 	return "Link__Link"
 | |
| }
 | |
| 
 | |
| func parseKind(s string) datamodel.Kind {
 | |
| 	switch s {
 | |
| 	case "map":
 | |
| 		return datamodel.Kind_Map
 | |
| 	case "list":
 | |
| 		return datamodel.Kind_List
 | |
| 	case "null":
 | |
| 		return datamodel.Kind_Null
 | |
| 	case "bool":
 | |
| 		return datamodel.Kind_Bool
 | |
| 	case "int":
 | |
| 		return datamodel.Kind_Int
 | |
| 	case "float":
 | |
| 		return datamodel.Kind_Float
 | |
| 	case "string":
 | |
| 		return datamodel.Kind_String
 | |
| 	case "bytes":
 | |
| 		return datamodel.Kind_Bytes
 | |
| 	case "link":
 | |
| 		return datamodel.Kind_Link
 | |
| 	default:
 | |
| 		return datamodel.Kind_Invalid
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func spawnType(ts *schema.TypeSystem, name schema.TypeName, defn TypeDefn) (schema.Type, error) {
 | |
| 	switch {
 | |
| 	// Scalar types without parameters.
 | |
| 	case defn.TypeDefnBool != nil:
 | |
| 		return schema.SpawnBool(name), nil
 | |
| 	case defn.TypeDefnString != nil:
 | |
| 		return schema.SpawnString(name), nil
 | |
| 	case defn.TypeDefnBytes != nil:
 | |
| 		return schema.SpawnBytes(name), nil
 | |
| 	case defn.TypeDefnInt != nil:
 | |
| 		return schema.SpawnInt(name), nil
 | |
| 	case defn.TypeDefnFloat != nil:
 | |
| 		return schema.SpawnFloat(name), nil
 | |
| 
 | |
| 	case defn.TypeDefnList != nil:
 | |
| 		typ := defn.TypeDefnList
 | |
| 		tname := ""
 | |
| 		if typ.ValueType.TypeName != nil {
 | |
| 			tname = *typ.ValueType.TypeName
 | |
| 		} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
 | |
| 			anonDefn := TypeDefn{
 | |
| 				TypeDefnMap:  typ.ValueType.InlineDefn.TypeDefnMap,
 | |
| 				TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
 | |
| 				TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
 | |
| 			}
 | |
| 			anonType, err := spawnType(ts, tname, anonDefn)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			ts.Accumulate(anonType)
 | |
| 		}
 | |
| 		switch {
 | |
| 		case typ.Representation == nil ||
 | |
| 			typ.Representation.ListRepresentation_List != nil:
 | |
| 			// default behavior
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("TODO: support other list repr in schema package")
 | |
| 		}
 | |
| 		return schema.SpawnList(name,
 | |
| 			tname,
 | |
| 			todoFromImplicitlyFalseBool(typ.ValueNullable),
 | |
| 		), nil
 | |
| 	case defn.TypeDefnMap != nil:
 | |
| 		typ := defn.TypeDefnMap
 | |
| 		tname := ""
 | |
| 		if typ.ValueType.TypeName != nil {
 | |
| 			tname = *typ.ValueType.TypeName
 | |
| 		} else if tname = anonTypeName(typ.ValueType); ts.TypeByName(tname) == nil {
 | |
| 			anonDefn := TypeDefn{
 | |
| 				TypeDefnMap:  typ.ValueType.InlineDefn.TypeDefnMap,
 | |
| 				TypeDefnList: typ.ValueType.InlineDefn.TypeDefnList,
 | |
| 				TypeDefnLink: typ.ValueType.InlineDefn.TypeDefnLink,
 | |
| 			}
 | |
| 			anonType, err := spawnType(ts, tname, anonDefn)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			ts.Accumulate(anonType)
 | |
| 		}
 | |
| 		switch {
 | |
| 		case typ.Representation == nil ||
 | |
| 			typ.Representation.MapRepresentation_Map != nil:
 | |
| 			// default behavior
 | |
| 		case typ.Representation.MapRepresentation_Stringpairs != nil:
 | |
| 			return nil, fmt.Errorf("TODO: support stringpairs map repr in schema package")
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("TODO: support other map repr in schema package")
 | |
| 		}
 | |
| 		return schema.SpawnMap(name,
 | |
| 			typ.KeyType,
 | |
| 			tname,
 | |
| 			todoFromImplicitlyFalseBool(typ.ValueNullable),
 | |
| 		), nil
 | |
| 	case defn.TypeDefnStruct != nil:
 | |
| 		typ := defn.TypeDefnStruct
 | |
| 		var fields []schema.StructField
 | |
| 		for _, fname := range typ.Fields.Keys {
 | |
| 			field := typ.Fields.Values[fname]
 | |
| 			tname := ""
 | |
| 			if field.Type.TypeName != nil {
 | |
| 				tname = *field.Type.TypeName
 | |
| 			} else if tname = anonTypeName(field.Type); ts.TypeByName(tname) == nil {
 | |
| 				// Note that TypeDefn and InlineDefn aren't the same enum.
 | |
| 				anonDefn := TypeDefn{
 | |
| 					TypeDefnMap:  field.Type.InlineDefn.TypeDefnMap,
 | |
| 					TypeDefnList: field.Type.InlineDefn.TypeDefnList,
 | |
| 					TypeDefnLink: field.Type.InlineDefn.TypeDefnLink,
 | |
| 				}
 | |
| 				anonType, err := spawnType(ts, tname, anonDefn)
 | |
| 				if err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 				ts.Accumulate(anonType)
 | |
| 			}
 | |
| 			fields = append(fields, schema.SpawnStructField(fname,
 | |
| 				tname,
 | |
| 				todoFromImplicitlyFalseBool(field.Optional),
 | |
| 				todoFromImplicitlyFalseBool(field.Nullable),
 | |
| 			))
 | |
| 		}
 | |
| 		var repr schema.StructRepresentation
 | |
| 		switch {
 | |
| 		case typ.Representation.StructRepresentation_Map != nil:
 | |
| 			rp := typ.Representation.StructRepresentation_Map
 | |
| 			if rp.Fields == nil {
 | |
| 				repr = schema.SpawnStructRepresentationMap2(nil, nil)
 | |
| 				break
 | |
| 			}
 | |
| 			renames := make(map[string]string, len(rp.Fields.Keys))
 | |
| 			implicits := make(map[string]schema.ImplicitValue, len(rp.Fields.Keys))
 | |
| 			for _, name := range rp.Fields.Keys {
 | |
| 				details := rp.Fields.Values[name]
 | |
| 				if details.Rename != nil {
 | |
| 					renames[name] = *details.Rename
 | |
| 				}
 | |
| 				if imp := details.Implicit; imp != nil {
 | |
| 					var sumVal schema.ImplicitValue
 | |
| 					switch {
 | |
| 					case imp.Bool != nil:
 | |
| 						sumVal = schema.ImplicitValue_Bool(*imp.Bool)
 | |
| 					case imp.String != nil:
 | |
| 						sumVal = schema.ImplicitValue_String(*imp.String)
 | |
| 					case imp.Int != nil:
 | |
| 						sumVal = schema.ImplicitValue_Int(*imp.Int)
 | |
| 					default:
 | |
| 						panic("TODO: implicit value kind")
 | |
| 					}
 | |
| 					implicits[name] = sumVal
 | |
| 				}
 | |
| 
 | |
| 			}
 | |
| 			repr = schema.SpawnStructRepresentationMap2(renames, implicits)
 | |
| 		case typ.Representation.StructRepresentation_Tuple != nil:
 | |
| 			rp := typ.Representation.StructRepresentation_Tuple
 | |
| 			if rp.FieldOrder == nil {
 | |
| 				repr = schema.SpawnStructRepresentationTuple()
 | |
| 				break
 | |
| 			}
 | |
| 			return nil, fmt.Errorf("TODO: support for tuples with field orders in the schema package")
 | |
| 		case typ.Representation.StructRepresentation_Stringjoin != nil:
 | |
| 			join := typ.Representation.StructRepresentation_Stringjoin.Join
 | |
| 			if join == "" {
 | |
| 				return nil, fmt.Errorf("stringjoin has empty join value")
 | |
| 			}
 | |
| 			repr = schema.SpawnStructRepresentationStringjoin(join)
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("TODO: support other struct repr in schema package")
 | |
| 		}
 | |
| 		return schema.SpawnStruct(name,
 | |
| 			fields,
 | |
| 			repr,
 | |
| 		), nil
 | |
| 	case defn.TypeDefnUnion != nil:
 | |
| 		typ := defn.TypeDefnUnion
 | |
| 		var members []schema.TypeName
 | |
| 		for _, member := range typ.Members {
 | |
| 			if member.TypeName != nil {
 | |
| 				members = append(members, *member.TypeName)
 | |
| 			} else {
 | |
| 				tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
 | |
| 				members = append(members, tname)
 | |
| 				if ts.TypeByName(tname) == nil {
 | |
| 					anonDefn := TypeDefn{
 | |
| 						TypeDefnLink: member.UnionMemberInlineDefn.TypeDefnLink,
 | |
| 					}
 | |
| 					anonType, err := spawnType(ts, tname, anonDefn)
 | |
| 					if err != nil {
 | |
| 						return nil, err
 | |
| 					}
 | |
| 					ts.Accumulate(anonType)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		remainingMembers := make(map[string]bool)
 | |
| 		for _, memberName := range members {
 | |
| 			remainingMembers[memberName] = true
 | |
| 		}
 | |
| 		validMember := func(memberName string) error {
 | |
| 			switch remaining, known := remainingMembers[memberName]; {
 | |
| 			case remaining:
 | |
| 				remainingMembers[memberName] = false
 | |
| 				return nil
 | |
| 			case !known:
 | |
| 				return fmt.Errorf("%q is not a valid member of union %q", memberName, name)
 | |
| 			default:
 | |
| 				return fmt.Errorf("%q is duplicate in the union repr of %q", memberName, name)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		var repr schema.UnionRepresentation
 | |
| 		switch {
 | |
| 		case typ.Representation.UnionRepresentation_Kinded != nil:
 | |
| 			rp := typ.Representation.UnionRepresentation_Kinded
 | |
| 			table := make(map[datamodel.Kind]schema.TypeName, len(rp.Keys))
 | |
| 			for _, kindStr := range rp.Keys {
 | |
| 				kind := parseKind(kindStr)
 | |
| 				member := rp.Values[kindStr]
 | |
| 				switch {
 | |
| 				case member.TypeName != nil:
 | |
| 					memberName := *member.TypeName
 | |
| 					validMember(memberName)
 | |
| 					table[kind] = memberName
 | |
| 				case member.UnionMemberInlineDefn != nil:
 | |
| 					tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
 | |
| 					validMember(tname)
 | |
| 					table[kind] = tname
 | |
| 				}
 | |
| 			}
 | |
| 			repr = schema.SpawnUnionRepresentationKinded(table)
 | |
| 		case typ.Representation.UnionRepresentation_Keyed != nil:
 | |
| 			rp := typ.Representation.UnionRepresentation_Keyed
 | |
| 			table := make(map[string]schema.TypeName, len(rp.Keys))
 | |
| 			for _, key := range rp.Keys {
 | |
| 				member := rp.Values[key]
 | |
| 				switch {
 | |
| 				case member.TypeName != nil:
 | |
| 					memberName := *member.TypeName
 | |
| 					validMember(memberName)
 | |
| 					table[key] = memberName
 | |
| 				case member.UnionMemberInlineDefn != nil:
 | |
| 					tname := anonLinkName(*member.UnionMemberInlineDefn.TypeDefnLink)
 | |
| 					validMember(tname)
 | |
| 					table[key] = tname
 | |
| 				}
 | |
| 			}
 | |
| 			repr = schema.SpawnUnionRepresentationKeyed(table)
 | |
| 		case typ.Representation.UnionRepresentation_StringPrefix != nil:
 | |
| 			prefixes := typ.Representation.UnionRepresentation_StringPrefix.Prefixes
 | |
| 			for _, key := range prefixes.Keys {
 | |
| 				validMember(prefixes.Values[key])
 | |
| 			}
 | |
| 			repr = schema.SpawnUnionRepresentationStringprefix("", prefixes.Values)
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("TODO: support other union repr in schema package")
 | |
| 		}
 | |
| 		for memberName, remaining := range remainingMembers {
 | |
| 			if remaining {
 | |
| 				return nil, fmt.Errorf("%q is not present in the union repr of %q", memberName, name)
 | |
| 			}
 | |
| 		}
 | |
| 		return schema.SpawnUnion(name,
 | |
| 			members,
 | |
| 			repr,
 | |
| 		), nil
 | |
| 	case defn.TypeDefnEnum != nil:
 | |
| 		typ := defn.TypeDefnEnum
 | |
| 		var repr schema.EnumRepresentation
 | |
| 
 | |
| 		// TODO: we should probably also reject duplicates.
 | |
| 		validMember := func(name string) bool {
 | |
| 			for _, memberName := range typ.Members {
 | |
| 				if memberName == name {
 | |
| 					return true
 | |
| 				}
 | |
| 			}
 | |
| 			return false
 | |
| 		}
 | |
| 		switch {
 | |
| 		case typ.Representation.EnumRepresentation_String != nil:
 | |
| 			rp := typ.Representation.EnumRepresentation_String
 | |
| 			for memberName := range rp.Values {
 | |
| 				if !validMember(memberName) {
 | |
| 					return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
 | |
| 				}
 | |
| 			}
 | |
| 			repr = schema.EnumRepresentation_String(rp.Values)
 | |
| 		case typ.Representation.EnumRepresentation_Int != nil:
 | |
| 			rp := typ.Representation.EnumRepresentation_Int
 | |
| 			for memberName := range rp.Values {
 | |
| 				if !validMember(memberName) {
 | |
| 					return nil, fmt.Errorf("%q is not a valid member of enum %q", memberName, name)
 | |
| 				}
 | |
| 			}
 | |
| 			repr = schema.EnumRepresentation_Int(rp.Values)
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("TODO: support other enum repr in schema package")
 | |
| 		}
 | |
| 		return schema.SpawnEnum(name,
 | |
| 			typ.Members,
 | |
| 			repr,
 | |
| 		), nil
 | |
| 	case defn.TypeDefnLink != nil:
 | |
| 		typ := defn.TypeDefnLink
 | |
| 		if typ.ExpectedType == nil {
 | |
| 			return schema.SpawnLink(name), nil
 | |
| 		}
 | |
| 		return schema.SpawnLinkReference(name, *typ.ExpectedType), nil
 | |
| 	case defn.TypeDefnAny != nil:
 | |
| 		return schema.SpawnAny(name), nil
 | |
| 	default:
 | |
| 		panic(fmt.Errorf("%#v", defn))
 | |
| 	}
 | |
| }
 |