Create a typescript client library for the server

This commit is contained in:
Savanni D'Gerinel 2025-02-14 09:53:08 -05:00
parent 79af050f53
commit 182020e136
11 changed files with 3942 additions and 29 deletions

2
visions/client/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
gen/
dist/

View File

@ -0,0 +1,12 @@
version: '3'
tasks:
fmt:
cmds:
- npx prettier -w package.json src
build:
cmds:
- npm install typescript
- typeshare --lang typescript --output-file gen/types.ts ../server/src
- npx tsc

View File

@ -0,0 +1,29 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended, eslintConfigPrettier],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
},
);

3813
visions/client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
{
"name": "visions-client",
"version": "0.0.1",
"description": "Shared data types for Visions",
"main": "visions.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"prettier": {
"singleQuote": true,
"semi": false,
"tabWidth": 4
},
"devDependencies": {
"prettier": "^3.5.1",
"ts-jest": "^29.2.5",
"typescript": "^5.7.3"
}
}

View File

@ -0,0 +1,42 @@
import { VResponse, SessionId } from '../gen/types'
export interface Client {
auth: (
username: string,
password: string,
) => Promise<ClientResponse<SessionId>>
}
export type ClientResponse<A> =
| { status: 'ok'; content: VResponse<A> }
| { status: 'unauthorized' }
| { status: 'unexpected'; code: number }
export class Connection implements Client {
private base: URL
// private sessionId: string | undefined;
constructor(baseUrl: URL) {
this.base = baseUrl
}
async auth(
username: string,
password: string,
): Promise<ClientResponse<SessionId>> {
const url = new URL(this.base)
url.pathname = `/api/v1/auth`
const response = await fetch(url, {
method: 'POST',
headers: [['Content-Type', 'application/json']],
body: JSON.stringify({ username: username, password: password }),
})
if (response.ok) {
return await response.json()
} else if (response.status == 401) {
return { status: 'unauthorized' }
} else {
return { status: 'unexpected', code: response.status }
}
}
}

View File

@ -11,5 +11,5 @@
"strict": true,
"skipLibCheck": true
},
"include": ["./visions.ts"]
"include": ["gen", "src"]
}

15
visions/client/visions.ts Normal file
View File

@ -0,0 +1,15 @@
/*
Generated by typeshare 1.13.0
*/
export type SessionId = string;
export interface AuthRequest {
username: string;
password: string;
}
export type AuthResponse =
| { type: "Success", content: SessionId }
| { type: "PasswordReset", content: SessionId };

View File

@ -38,19 +38,20 @@ impl From<String> for SessionId {
}
#[derive(Deserialize, Serialize)]
#[serde(tag = "type", content = "content")]
#[typeshare]
enum AuthResponse {
Success(SessionId),
PasswordReset(SessionId),
enum VResponse<A> {
Success(A),
PasswordReset(A),
}
#[axum::debug_handler]
async fn check_password(request: Json<AuthRequest>) -> (StatusCode, Json<Option<AuthResponse>>) {
async fn check_password(request: Json<AuthRequest>) -> (StatusCode, Json<Option<VResponse<SessionId>>>) {
let Json(request) = request;
if request.username == "vakarian" && request.password == "aoeu" {
(StatusCode::OK, Json(Some(AuthResponse::Success("vakarian-session-id".into()))))
(StatusCode::OK, Json(Some(VResponse::Success("vakarian-session-id".into()))))
} else if request.username == "shephard" && request.password == "aoeu" {
(StatusCode::OK, Json(Some(AuthResponse::PasswordReset("shephard-session-id".into()))))
(StatusCode::OK, Json(Some(VResponse::PasswordReset("shephard-session-id".into()))))
} else {
(StatusCode::UNAUTHORIZED, Json(None))
}

View File

@ -1,8 +0,0 @@
version: '3'
tasks:
build:
cmds:
- npm install typescript
- typeshare --lang typescript --output-file visions.ts ../server/src
- npx tsc

View File

@ -1,14 +0,0 @@
{
"name": "visions-types",
"version": "0.0.1",
"description": "Shared data types for Visions",
"main": "visions.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"typescript": "^5.7.3"
}
}