package api_gen import ( "os" "path/filepath" "text/template" ) func generateJSClient(outputDir string, pkg *APIPackage) error { tmpl := `// Code generated by api_gen. DO NOT EDIT. /** * Auto-generated API Client * Generated from: {{ .PkgPath }} */ class APIClient { constructor(baseURL = '', options = {}) { this.baseURL = baseURL; this.timeout = options.timeout || 30000; this.headers = options.headers || {}; this.onUnauthorized = options.onUnauthorized || null; } async request(method, path, body = null) { const url = this.baseURL + path; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const options = { method, headers: { 'Content-Type': 'application/json', ...this.headers }, credentials: 'same-origin', signal: controller.signal }; if (body !== null) { options.body = JSON.stringify(body); } const response = await fetch(url, options); clearTimeout(timeoutId); if (!response.ok) { let parsed = null; try { parsed = await response.json(); } catch (_) {} const err = new Error(` + "`Request failed with status ${response.status}`" + `); err.status = response.status; err.response = parsed; if (response.status === 401 && this.onUnauthorized) { this.onUnauthorized(err); } throw err; } const text = await response.text(); return text ? JSON.parse(text) : null; } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error('Request timeout'); } throw error; } } {{ range .Endpoints }} async {{.Name}}(req) { return this.request('{{.Method}}', '{{.Path}}', req); } {{ end }} } if (typeof module !== 'undefined' && module.exports) { module.exports = APIClient; } if (typeof window !== 'undefined') { window.APIClient = APIClient; } ` tmplObj := template.Must(template.New("jsclient").Parse(tmpl)) f, err := os.Create(filepath.Join(outputDir, "client.js")) if err != nil { return err } defer f.Close() return tmplObj.Execute(f, pkg) }