// Package fromruntime is compose/frombus's StatesReader over a bundle's runtime (the lead, 2026-10-29): the states a // module's manifest names in `reads` (frombus.StatesReads), read through stdio.State, and a templates archive fetched // over HTTP. Apart from frombus so that frombus stays pure for the mesh-compose command. package fromruntime import ( "context" "fmt" "io" "net/http" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/compose/frombus" ) // States are a bundle's read states through its runtime. type States struct{} // Get is a key's value, false when it has none. func (States) Get(state, key string) ([]byte, bool, error) { e, err := stdio.State(state).Get(key) if err != nil || e == nil { return nil, false, err } return e.Value, true, nil } // Keys are a state's keys. func (States) Keys(state string) ([]string, error) { return stdio.State(state).Keys() } // Reader is frombus's Reader over this bundle's read states, fetching archives over HTTP. func Reader() frombus.Reader { return frombus.StatesReader(States{}, HTTPFetch) } // HTTPFetch reads an archive over HTTP, at most 256 MiB. func HTTPFetch(ctx context.Context, url string) ([]byte, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%s answered %s", url, resp.Status) } return io.ReadAll(io.LimitReader(resp.Body, 256<<20)) }