diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-12-09 03:57:12 +0100 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-12-09 03:57:12 +0100 |
| commit | 4dbef3fcd7a14437d55c555cf10d50de8e50d7d1 (patch) | |
| tree | 632589ecfcfb4dfddeafb71d0077257584b5e7ec /code/app/src/api | |
| parent | 914c75e0ceeb3e11ddd55e94bb461c26b0db5b7a (diff) | |
| download | greatoffice-4dbef3fcd7a14437d55c555cf10d50de8e50d7d1.tar.xz greatoffice-4dbef3fcd7a14437d55c555cf10d50de8e50d7d1.zip | |
feat: Move everything out of $lib
Diffstat (limited to 'code/app/src/api')
| -rw-r--r-- | code/app/src/api/_fetch.ts | 94 | ||||
| -rw-r--r-- | code/app/src/api/account/index.ts | 39 | ||||
| -rw-r--r-- | code/app/src/api/api-tokens/index.ts | 23 | ||||
| -rw-r--r-- | code/app/src/api/projects/index.ts | 12 |
4 files changed, 168 insertions, 0 deletions
diff --git a/code/app/src/api/_fetch.ts b/code/app/src/api/_fetch.ts new file mode 100644 index 0000000..370b071 --- /dev/null +++ b/code/app/src/api/_fetch.ts @@ -0,0 +1,94 @@ +import {Temporal} from "temporal-polyfill"; +import {redirect} from "@sveltejs/kit"; +import {browser} from "$app/environment"; +import {goto} from "$app/navigation"; +import {SignInPageMessage, signInPageMessageQueryKey} from "$routes/(main)/(public)/sign-in"; +import {log_error} from "$help/logger"; + +export async function http_post_async(url: string, body?: object | string, timeout = -1, skip_401_check = false, abort_signal?: AbortSignal): Promise<Response> { + const init = make_request_init("post", body, abort_signal); + const response = await internal_fetch_async({url, init, timeout}); + if (!skip_401_check && await redirect_if_401_async(response)) throw new Error("Server returned 401"); + return response; +} + +export async function http_get_async(url: string, timeout = -1, skip_401_check = false, abort_signal?: AbortSignal): Promise<Response> { + const init = make_request_init("get", undefined, abort_signal); + const response = await internal_fetch_async({url, init, timeout}); + if (!skip_401_check && await redirect_if_401_async(response)) throw new Error("Server returned 401"); + return response; +} + +export async function http_delete_async(url: string, body?: object | string, timeout = -1, skip_401_check = false, abort_signal?: AbortSignal): Promise<Response> { + const init = make_request_init("delete", body, abort_signal); + const response = await internal_fetch_async({url, init, timeout}); + if (!skip_401_check && await redirect_if_401_async(response)) throw new Error("Server returned 401"); + return response; +} + +async function internal_fetch_async(request: InternalFetchRequest): Promise<Response> { + if (!request.init) throw new Error("request.init is required"); + const fetch_request = new Request(request.url, request.init); + let response: any; + + try { + if (request.timeout && request.timeout > 500) { + response = await Promise.race([ + fetch(fetch_request), + new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), request.timeout)), + ]); + } else { + response = await fetch(fetch_request); + } + } catch (error: any) { + log_error(error); + if (error.message === "Timeout") { + console.error("Request timed out"); + } else if (error.message === "Network request failed") { + console.error("No internet connection"); + } else { + throw error; + } + } + + return response; +} + +async function redirect_if_401_async(response: Response): Promise<boolean> { + if (response.status === 401) { + const redirectUrl = `/sign-in?${signInPageMessageQueryKey}=${SignInPageMessage.LOGGED_OUT}`; + clear_session_data(); + if (browser) { + await goto(redirectUrl); + } else { + throw redirect(307, redirectUrl); + } + } + return false; +} + +function make_request_init(method: string, body?: any, signal?: AbortSignal): RequestInit { + const init = { + method, + credentials: "include", + signal, + headers: { + "X-TimeZone": Temporal.Now.timeZone().id, + }, + } as RequestInit; + + if (body) { + init.body = JSON.stringify(body); + init.headers["Content-Type"] = "application/json;charset=UTF-8"; + } + + return init; +} + + +export type InternalFetchRequest = { + url: string, + init: RequestInit, + timeout?: number + retry_count?: number, +}
\ No newline at end of file diff --git a/code/app/src/api/account/index.ts b/code/app/src/api/account/index.ts new file mode 100644 index 0000000..7cbcefc --- /dev/null +++ b/code/app/src/api/account/index.ts @@ -0,0 +1,39 @@ +import {api_base} from "$configuration"; +import {http_delete_async, http_get_async, http_post_async} from "../_fetch"; + +export const http_account = { + login_async(payload: LoginPayload): Promise<Response> { + return http_post_async(api_base("_/account/login"), payload); + }, + logout_async(): Promise<Response> { + return http_get_async(api_base("_/account/logout")); + }, + delete_account_async(): Promise<Response> { + return http_delete_async(api_base("_/account/delete")); + }, + update_profile_async(payload: UpdateProfilePayload): Promise<Response> { + return http_post_async(api_base("_/account/update"), payload); + }, + create_account_async(payload: CreateAccountPayload): Promise<Response> { + return http_post_async(api_base("_/account/create"), payload); + }, + get_profile_async(suppress_401: boolean): Promise<Response> { + return http_get_async(api_base("_/account"), 0, suppress_401); + }, +}; + +export interface CreateAccountPayload { + username: string, + password: string +} + +export interface LoginPayload { + username: string, + password: string, + persist: boolean +} + +export interface UpdateProfilePayload { + username?: string, + password?: string, +} diff --git a/code/app/src/api/api-tokens/index.ts b/code/app/src/api/api-tokens/index.ts new file mode 100644 index 0000000..6c27a06 --- /dev/null +++ b/code/app/src/api/api-tokens/index.ts @@ -0,0 +1,23 @@ +import {http_delete_async, http_get_async, http_post_async} from "../_fetch"; +import {api_base} from "$configuration"; +import type {Temporal} from "temporal-polyfill"; + +export const http_api_tokens = { + create_token_async(payload: CreateTokenPayload): Promise<Response> { + return http_post_async(api_base("v1/api-tokens/create"), payload); + }, + delete_token_async(id: string): Promise<Response> { + return http_delete_async(api_base("v1/api-tokens/delete?id=" + id)); + }, + get_tokens_async(): Promise<Response> { + return http_get_async(api_base("v1/api-tokens")); + }, +}; + +export type CreateTokenPayload = { + expiryDate: Temporal.PlainDateTime, + allowRead: boolean, + allowCreate: boolean, + allowUpdate: boolean, + allowDelete: boolean +}
\ No newline at end of file diff --git a/code/app/src/api/projects/index.ts b/code/app/src/api/projects/index.ts new file mode 100644 index 0000000..316785f --- /dev/null +++ b/code/app/src/api/projects/index.ts @@ -0,0 +1,12 @@ +import {api_base} from "$configuration"; +import {http_post_async} from "../_fetch"; + +export const http_projects = { + create_async(payload: CreateProjectPayload): Promise<Response> { + return http_post_async(api_base("projects/create"), payload); + }, +}; + +export type CreateProjectPayload = { + name: "" +}
\ No newline at end of file |
