( path: string, init?: JsonRequestInit )
| 156 | } |
| 157 | |
| 158 | async function jsonRequest<T>( |
| 159 | path: string, |
| 160 | init?: JsonRequestInit |
| 161 | ): Promise<T> { |
| 162 | const headers = new Headers(init?.headers) |
| 163 | const hasBody = init?.body !== undefined |
| 164 | if (hasBody && !headers.has('Content-Type')) { |
| 165 | headers.set('Content-Type', 'application/json') |
| 166 | } |
| 167 | const res = await fetch(`${API_BASE}${path}`, { |
| 168 | ...init, |
| 169 | headers, |
| 170 | body: hasBody ? JSON.stringify(init!.body) : undefined, |
| 171 | credentials: 'same-origin' |
| 172 | }) |
| 173 | if (!res.ok) { |
| 174 | if (res.status === 401) { |
| 175 | throw new HttpRequestError( |
| 176 | res.status, |
| 177 | path, |
| 178 | 'This ZenNotes server requires you to sign in with its auth token.' |
| 179 | ) |
| 180 | } |
| 181 | const text = await res.text().catch(() => '') |
| 182 | throw new HttpRequestError( |
| 183 | res.status, |
| 184 | path, |
| 185 | `HTTP ${res.status} ${res.statusText} for ${path}${text ? `: ${text}` : ''}` |
| 186 | ) |
| 187 | } |
| 188 | if (res.status === 204) return undefined as unknown as T |
| 189 | const ctype = res.headers.get('Content-Type') || '' |
| 190 | if (ctype.includes('application/json')) { |
| 191 | return (await res.json()) as T |
| 192 | } |
| 193 | return (await res.text()) as unknown as T |
| 194 | } |
| 195 | |
| 196 | function notImplemented(name: string): never { |
| 197 | throw new Error(`zen.${name} is not available in the web build`) |
no outgoing calls
no test coverage detected