package standard import ( "fmt" "io" "net/http" "strings" "github.com/dop251/goja" "reichard.io/poiesis/internal/runtime/pkg/builtin" ) type FetchResult struct { OK bool Status int Body string Headers map[string]string } func Fetch(url string, options map[string]any) (*FetchResult, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("failed to fetch: %w", err) } defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read body: %w", err) } headers := make(map[string]string) for key, values := range resp.Header { if len(values) > 0 { val := values[0] headers[key] = val headers[strings.ToLower(key)] = val } } return &FetchResult{ OK: resp.StatusCode >= 200 && resp.StatusCode < 300, Status: resp.StatusCode, Body: string(body), Headers: headers, }, nil } func convertFetchResult(vm *goja.Runtime, result *FetchResult) goja.Value { if result == nil { return goja.Null() } obj := vm.NewObject() _ = obj.Set("ok", result.OK) _ = obj.Set("status", result.Status) _ = obj.Set("text", func() string { return result.Body }) headersObj := vm.NewObject() headers := result.Headers _ = headersObj.Set("get", func(c goja.FunctionCall) goja.Value { if len(c.Arguments) < 1 { return goja.Undefined() } key := c.Arguments[0].String() return vm.ToValue(headers[key]) }) _ = obj.Set("headers", headersObj) return obj } func init() { builtin.RegisterCustomConverter(convertFetchResult) builtin.RegisterBuiltin("fetch", Fetch) builtin.RegisterBuiltin("add", func(a, b int) int { return a + b }) builtin.RegisterBuiltin("greet", func(name string) string { return fmt.Sprintf("Hello, %s!", name) }) }