UNPKG

alinea

Version:
198 lines (196 loc) 6.16 kB
import "../chunks/chunk-NZLE2WMY.js"; // src/core/Client.ts import { AbortController, fetch } from "@alinea/iso"; import { HandleAction } from "alinea/backend/HandleAction"; import { AuthResultType } from "alinea/cloud/AuthResult"; import { HttpError } from "./HttpError.js"; import { getScope } from "./Scope.js"; import { ReadonlyTree } from "./source/Tree.js"; import { base64 } from "./util/Encoding.js"; var Client = class _Client { #options; constructor(options) { this.#options = options; } get url() { return this.#options.url; } authStatus() { return this.#requestJson({ action: HandleAction.Auth, auth: "status" }).then(this.#failOnHttpError); } logout = async () => { const endSession = this.#options.unauthorized; await this.#request({ action: HandleAction.Auth, auth: "logout" }).then((res) => this.#failOnHttpError(res, false)).then(endSession); }; previewToken(request) { return this.#requestJson( { action: HandleAction.PreviewToken }, { method: "POST", body: JSON.stringify(request) } ).then(this.#failOnHttpError); } prepareUpload(file) { return this.#requestJson( { action: HandleAction.Upload }, { method: "POST", body: JSON.stringify({ filename: file }) } ).then(this.#failOnHttpError); } user() { return this.#requestJson({ action: HandleAction.User }).then(this.#failOnHttpError).then((user) => user ?? void 0); } resolve(query) { const scope = getScope(this.#options.config); const body = scope.stringify(query); return this.#requestJson( { action: HandleAction.Resolve }, { method: "POST", body } ).then(this.#failOnHttpError); } mutate(mutations) { return this.#requestJson( { action: HandleAction.Mutate }, { method: "POST", body: JSON.stringify(mutations) } ).then(this.#failOnHttpError); } authenticate(applyAuth, unauthorized) { return new _Client({ ...this.#options, applyAuth, unauthorized }); } // History revisions(file) { return this.#requestJson({ action: HandleAction.History, file }).then(this.#failOnHttpError); } revisionData(file, revisionId) { return this.#requestJson({ action: HandleAction.History, file, revisionId }).then(this.#failOnHttpError).then((res) => res ?? void 0); } // Source getTreeIfDifferent(sha) { return this.#requestJson({ action: HandleAction.Tree, sha }).then(this.#failOnHttpError).then((tree) => tree ? new ReadonlyTree(tree) : void 0); } async *getBlobs(shas) { if (shas.length === 0) return; const response = await this.#request( { action: HandleAction.Blob }, { method: "POST", body: JSON.stringify({ shas }), headers: { "content-type": "application/json", accept: "multipart/form-data" } } ).then((response2) => this.#failOnHttpError(response2, false)); const form = await response.formData(); for (const [key, value] of form.entries()) { if (value instanceof Blob) { const sha = key.slice(0, 40); const blob = new Uint8Array(await value.arrayBuffer()); yield [sha, blob]; } } } // Commit write(request) { return this.#requestJson( { action: HandleAction.Commit }, { method: "POST", body: JSON.stringify(request) } ).then(this.#failOnHttpError); } // Drafts getDraft(key) { return this.#requestJson({ action: HandleAction.Draft, key }).then(this.#failOnHttpError).then( (draft) => draft ? { ...draft, draft: base64.parse(draft.draft) } : void 0 ); } storeDraft(draft) { return this.#requestJson( { action: HandleAction.Draft }, { method: "POST", body: JSON.stringify({ ...draft, draft: base64.stringify(draft.draft) }) } ).then((res) => this.#failOnHttpError(res, false)); } #request(params, init = {}, retry = false) { const { url, applyAuth = (v) => v, unauthorized } = this.#options; const controller = new AbortController(); const signal = controller.signal; const location = `${url}?${new URLSearchParams(params).toString()}`; const promise = fetch(location, { ...applyAuth(init), signal }).catch((err) => { throw new HttpError( 500, `${err} @ ${init?.method || "GET"} action ${params.action}` ); }).then(async (res) => { if (res.ok) return res; const isJson = res.headers.get("content-type")?.includes("application/json"); let errorMessage; if (isJson) { const body = await res.json(); if (res.status === 401 && body.type === AuthResultType.NeedsRefresh) { if (!retry) return this.#request(params, init, true); } if ("error" in body && typeof body.error === "string") errorMessage = body.error; else errorMessage = JSON.stringify(body, null, 2); } else { errorMessage = await res.text(); } errorMessage = errorMessage.replace(/\s+/g, " ").slice(0, 1024); if (res.status === 401) unauthorized?.(); throw new HttpError( res.status, `${errorMessage} @ ${init?.method || "GET"} action ${params.action}` ); }); const cancel = () => controller.abort(); function cancelify(promise2) { const t = promise2.then.bind(promise2); const c = promise2.catch.bind(promise2); return Object.assign(promise2, { cancel, then: (...args) => cancelify(t(...args)), catch: (...args) => cancelify(c(...args)) }); } return cancelify(promise); } #requestJson(params, init) { return this.#request(params, { ...init, headers: { ...init?.headers, "content-type": "application/json", accept: "application/json" } }); } async #failOnHttpError(res, expectJson = true) { if (res.ok) return expectJson ? res.json() : res; const text = await res.text(); throw new HttpError(res.status, text || res.statusText); } }; export { Client };