feature: signup and login work
This commit is contained in:
parent
a4a750b35c
commit
3d42591ee5
18 changed files with 956 additions and 65 deletions
121
utils/api.ts
Normal file
121
utils/api.ts
Normal file
|
@ -0,0 +1,121 @@
|
|||
import { getSetCookies } from '@std/http/cookie';
|
||||
import { generateTotp } from '@stdext/crypto/totp';
|
||||
|
||||
export interface API_CLIENT {
|
||||
fetch: (url: string, options?: FETCH_OPTIONS, transform?: (obj: any) => any) => Promise<object>;
|
||||
}
|
||||
|
||||
export type API_CONFIG = {
|
||||
protocol: string;
|
||||
hostname: string;
|
||||
port: number;
|
||||
prefix: string;
|
||||
};
|
||||
|
||||
const DEFAULT_API_CONFIG: API_CONFIG = {
|
||||
protocol: 'http:',
|
||||
hostname: 'localhost',
|
||||
port: 80,
|
||||
prefix: ''
|
||||
};
|
||||
|
||||
export interface RETRY_OPTIONS {
|
||||
limit: number;
|
||||
methods: string[];
|
||||
status_codes: number[];
|
||||
}
|
||||
|
||||
export interface FETCH_OPTIONS extends RequestInit {
|
||||
retry?: RETRY_OPTIONS;
|
||||
json?: Record<string, any>;
|
||||
done?: (response: Response) => void;
|
||||
session?: Record<string, any>;
|
||||
totp_token?: string;
|
||||
}
|
||||
|
||||
const DEFAULT_TRANSFORM = (response_json: any) => {
|
||||
return response_json;
|
||||
};
|
||||
|
||||
export function api(api_config?: Record<string, any>): API_CLIENT {
|
||||
const config: API_CONFIG = {
|
||||
...DEFAULT_API_CONFIG,
|
||||
...(api_config ?? {})
|
||||
};
|
||||
|
||||
return {
|
||||
fetch: async (url: string, options?: FETCH_OPTIONS, transform?: (obj: any) => any) => {
|
||||
const prefix: string = `${config.protocol}//${config.hostname}:${config.port}${config.prefix}`;
|
||||
const retry: RETRY_OPTIONS = options?.retry ?? {
|
||||
limit: 0,
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
|
||||
status_codes: [500, 502, 503, 504, 521, 522, 524]
|
||||
};
|
||||
|
||||
const content_type = options?.json ? 'application/json' : 'text/plain';
|
||||
const headers = new Headers(options?.headers ?? {});
|
||||
headers.append('accept', 'application/json');
|
||||
if (options?.json || options?.body) {
|
||||
headers.append('content-type', content_type);
|
||||
}
|
||||
if (options?.session) {
|
||||
const cookies = getSetCookies(headers);
|
||||
|
||||
cookies.push({
|
||||
name: options.totp_token ?? 'totp',
|
||||
value: await generateTotp(options.session.secret),
|
||||
maxAge: 30,
|
||||
expires: Date.now() + 30_000,
|
||||
path: '/'
|
||||
});
|
||||
|
||||
for (const cookie of cookies) {
|
||||
headers.append(`x-${cookie.name}`, cookie.value);
|
||||
}
|
||||
headers.append('cookie', cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join('; '));
|
||||
}
|
||||
|
||||
const request_options: RequestInit = {
|
||||
body: options?.json ? JSON.stringify(options.json, null, 2) : options?.body,
|
||||
method: options?.method ?? 'GET',
|
||||
credentials: options?.credentials ?? 'include',
|
||||
redirect: options?.redirect ?? 'follow',
|
||||
headers
|
||||
};
|
||||
|
||||
const response_transform = transform ?? DEFAULT_TRANSFORM;
|
||||
|
||||
let retries = 0;
|
||||
let delay = 1000;
|
||||
const resolved_url = `${prefix}${url}`;
|
||||
do {
|
||||
const response: Response = await fetch(resolved_url, request_options);
|
||||
if (
|
||||
retries < retry.limit && retry.status_codes.includes(response.status) &&
|
||||
retry.methods.includes(request_options.method ?? 'GET')
|
||||
) {
|
||||
++retries;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
delay *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.status > 400) {
|
||||
const error_response = await response.json();
|
||||
throw new Error('Bad Request', {
|
||||
cause: error_response?.cause ?? JSON.stringify(error_response)
|
||||
});
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const transformed = await response_transform(data);
|
||||
|
||||
if (options?.done) {
|
||||
options.done(response);
|
||||
}
|
||||
|
||||
return transformed;
|
||||
} while (retries < retry.limit);
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue