feat(global) compatibility milestone

This commit is contained in:
lumither committed 2025-06-03 03:19:49 +08:00
1 parent 06a4ab8cf7
commit 45010f030c
19 files changed
+347 -119

No files matched your search

View File
Whitespace-only changes.
+96
View File
@@ -0,0 +1,96 @@
import { fetchNocturneJson } from '@/src/api/endpoint';
const DEFAULT_PAGE_SIZE = 6;
export interface PostListResponse {
data: {
posts: {
id: string,
identifier: string,
title: string,
subtitle: string,
tags: string[]
category: string,
date_created: Date,
date_updated: Date | null,
header_img: string | null
}[],
pagination: {
page: number,
page_count: number,
page_size: number
}
},
status: string
}
export async function fetchPostList(page: number, page_size: number = DEFAULT_PAGE_SIZE): Promise<PostListResponse> {
const url = `/blog/posts?page=${ page }&page_size=${ page_size }`;
return await fetchNocturneJson(url);
}
export interface PostListPaginationResponseData {
page_count: number,
post_count: number,
}
export interface PostListPaginationResponse {
data: PostListPaginationResponseData;
status: string;
}
export async function fetchPostListPagination(): Promise<PostListPaginationResponse> {
const url = `/blog/posts/pagination`;
return await fetchNocturneJson(url);
}
export interface FetchPostResponseData {
post: {
id: string,
identifier: string,
title: string,
subtitle: string,
status: string,
date_created: string,
date_updated: string | null,
category: string,
tags: string[],
content: string,
metadata: any | null,
},
adjacent: {
prev: {
id: string,
identifier: string,
title: string,
subtitle: string,
date_created: string,
category: string,
tags: string[],
header_img: string | null,
} | null,
next: {
id: string,
identifier: string,
title: string,
subtitle: string,
date_created: string,
category: string,
tags: string[],
header_img: string | null,
} | null,
}
}
export interface FetchPostResponse {
data: FetchPostResponseData;
status: string;
}
export async function fetchPost(id: string): Promise<FetchPostResponse> {
const url = `/blog/posts/${ id }`;
return await fetchNocturneJson(url);
}
+40
View File
@@ -0,0 +1,40 @@
const LOCAL_ENDPOINT = process.env.API_LOCAL_URL;
const REMOTE_ENDPOINT = process.env.API_REMOTE_URL;
const FALLBACK_ENDPOINT = 'http://localhost:3001';
const NOCTURNE_ENDPOINT = ((isServerSide = true) => {
const get_endpoint = () => {
if (process.env.NODE_ENV === 'production') {
if (isServerSide) {
return LOCAL_ENDPOINT;
} else {
return REMOTE_ENDPOINT;
}
} else {
return LOCAL_ENDPOINT;
}
};
return get_endpoint() ?? FALLBACK_ENDPOINT;
});
export async function fetchNocturneJson<T>(
path: string,
isServerSideRequest = true,
method: string = 'GET'
): Promise<T> {
const url = `${ NOCTURNE_ENDPOINT(isServerSideRequest) }${ path }`;
const future = fetch(url, {
cache: 'no-cache',
method: method
});
const res = (await future);
if (!res.ok) {
throw new Error(`Failed to fetch "${ url }" [${ res.status }]: ${ res.statusText }`);
}
return (await res.json()) as T;
}
+89
View File
@@ -0,0 +1,89 @@
export type Result<T, E> = Ok<T, E> | Err<T, E>;
class Ok<T, E> {
readonly value: T;
constructor(value: T) {
this.value = value;
}
isOk(): this is Ok<T, E> {
return true;
}
isErr(): this is Err<T, E> {
return false;
}
map<U>(fn: (val: T) => U): Result<U, E> {
return new Ok(fn(this.value));
}
mapErr<F>(_fn: (err: E) => F): Result<T, F> {
return new Ok(this.value);
}
unwrap(): T {
return this.value;
}
unwrapOr(_default: T): T {
return this.value;
}
match<U>(handlers: { ok: (val: T) => U, err: (err: E) => U }): U {
return handlers.ok(this.value);
}
andThen<U>(fn: (val: T) => Result<U, E>): Result<U, E> {
return fn(this.value);
}
}
class Err<T, E> {
readonly error: E;
constructor(error: E) {
this.error = error;
}
isOk(): this is Ok<T, E> {
return false;
}
isErr(): this is Err<T, E> {
return true;
}
map<U>(_fn: (val: T) => U): Result<U, E> {
return new Err(this.error);
}
mapErr<F>(fn: (err: E) => F): Result<T, F> {
return new Err(fn(this.error));
}
unwrap(): T {
throw new Error('Tried to unwrap Err: ' + this.error);
}
unwrapOr(defaultValue: T): T {
return defaultValue;
}
match<U>(handlers: { ok: (val: T) => U, err: (err: E) => U }): U {
return handlers.err(this.error);
}
andThen<U>(_fn: (val: T) => Result<U, E>): Result<U, E> {
return new Err(this.error);
}
}
export function ok<T, E = never>(value: T): Result<T, E> {
return new Ok(value);
}
export function err<T = never, E = unknown>(error: E): Result<T, E> {
return new Err(error);
}
+3
View File
@@ -0,0 +1,3 @@
export function todo(message: string = 'Not yet implemented'): never {
throw new Error(`TODO: ${ message }`);
}