NewClientFromURL creates a client from a full base URL (e.g., "https://app.getpad.dev").
(baseURL string)
| 50 | |
| 51 | // NewClientFromURL creates a client from a full base URL (e.g., "https://app.getpad.dev"). |
| 52 | func NewClientFromURL(baseURL string) *Client { |
| 53 | baseURL = strings.TrimRight(baseURL, "/") |
| 54 | c := &Client{ |
| 55 | baseURL: baseURL + "/api/v1", |
| 56 | httpClient: &http.Client{ |
| 57 | Timeout: 10 * time.Second, |
| 58 | }, |
| 59 | // Long-running transfer client for streaming endpoints |
| 60 | // (workspace export bundles in/out, future S3 downloads). |
| 61 | // 10s on the default client is the right SLA for normal API |
| 62 | // calls but kills a multi-GiB bundle upload mid-stream over |
| 63 | // anything but a fast local link. 1 hour is generous enough |
| 64 | // for ~100 MB/s uplinks shipping a 350 GiB bundle and still |
| 65 | // caps a hung connection eventually. (Codex review on PR |
| 66 | // #306 round 2.) |
| 67 | streamClient: &http.Client{ |
| 68 | Timeout: 1 * time.Hour, |
| 69 | }, |
| 70 | } |
| 71 | |
| 72 | // Auth resolution order: PAD_TOKEN env override first (explicit, |
| 73 | // per-process — lets concurrent agents on one machine act as |
| 74 | // different users, issue #879), then the saved credential for THIS |
| 75 | // server URL. We use the original baseURL (without the /api/v1 |
| 76 | // suffix added below) so the lookup matches what login/save |
| 77 | // commands key on. Credentials for other servers are left untouched |
| 78 | // in the store — see TASK-1228 / IDEA-1226 for the per-server design. |
| 79 | if tok := EnvToken(); tok != "" { |
| 80 | c.authToken = tok |
| 81 | } else if store, err := LoadStore(); err == nil { |
| 82 | if creds := store.Get(baseURL); creds != nil { |
| 83 | c.authToken = creds.Token |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | // Resolve the agent identity that becomes X-Pad-Agent. Used to read |
| 88 | // .pad.toml's agent_name and nothing else, which meant any workspace that |
| 89 | // had not opted in recorded agent writes as human ones (BUG-2542). See |
| 90 | // ResolveAgentName for the precedence and for what this signal cannot do. |
| 91 | c.agentName = ResolveAgentName() |
| 92 | |
| 93 | return c |
| 94 | } |
| 95 | |
| 96 | // SetAuthToken sets the authorization token for API requests. |
| 97 | func (c *Client) SetAuthToken(token string) { |