mirror of
https://github.com/versia-pub/versia-go.git
synced 2026-03-13 20:49:15 +01:00
chore: init
This commit is contained in:
commit
320715f3e7
174 changed files with 42083 additions and 0 deletions
51
web/src/api/auth.ts
Normal file
51
web/src/api/auth.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import {HttpClient, HttpClientRequest, HttpClientResponse,} from "@effect/platform";
|
||||
import * as Schema from "@effect/schema/Schema";
|
||||
import {Effect, Schedule} from "effect";
|
||||
import {OTLP_TRACE_PROPAGATION} from "../env.ts";
|
||||
import {APIResponse, BASE_URL, FailedAPIResponse} from "./response.ts";
|
||||
|
||||
export const UserId = Schema.UUID.pipe(Schema.brand("UserId"));
|
||||
export type UserId = Schema.Schema.Type<typeof UserId>;
|
||||
|
||||
export class UserInfo extends Schema.Class<UserInfo>("UserInfo")({
|
||||
id: UserId,
|
||||
username: Schema.String,
|
||||
}) {
|
||||
}
|
||||
|
||||
export const fetchUserInfo = HttpClientRequest.get(
|
||||
`${BASE_URL}/api/auth/authn/@me`,
|
||||
).pipe(
|
||||
HttpClient.fetch,
|
||||
HttpClientResponse.schemaBodyJsonScoped(APIResponse(UserInfo)),
|
||||
Effect.filterOrFail(
|
||||
(res) => res.ok,
|
||||
(res) => (res as FailedAPIResponse).error,
|
||||
),
|
||||
Effect.retry({times: 3, schedule: Schedule.exponential(250, 2)}),
|
||||
Effect.map((d) => d.data),
|
||||
Effect.either,
|
||||
Effect.withSpan("fetchUserInfo"),
|
||||
HttpClient.withTracerPropagation(OTLP_TRACE_PROPAGATION),
|
||||
);
|
||||
|
||||
export class UserCreation extends Schema.Class<UserCreation>("UserCreation")({
|
||||
username: Schema.String,
|
||||
}) {
|
||||
}
|
||||
|
||||
const createUserBody = HttpClientRequest.schemaBody(UserCreation);
|
||||
export const createUser = (data: UserCreation) =>
|
||||
HttpClientRequest.post(`${BASE_URL}/api/app/users/`).pipe(
|
||||
createUserBody(data),
|
||||
Effect.andThen(HttpClient.fetch),
|
||||
HttpClientResponse.schemaBodyJsonScoped(APIResponse(UserInfo)),
|
||||
Effect.filterOrFail(
|
||||
(res) => res.ok,
|
||||
(res) => (res as FailedAPIResponse).error,
|
||||
),
|
||||
Effect.map((d) => d.data),
|
||||
Effect.either,
|
||||
Effect.withSpan("createUser", {attributes: {data: data}}),
|
||||
HttpClient.withTracerPropagation(OTLP_TRACE_PROPAGATION),
|
||||
);
|
||||
28
web/src/api/index.ts
Normal file
28
web/src/api/index.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import {layer} from "@effect/opentelemetry/WebSdk";
|
||||
import {OTLPTraceExporter} from "@opentelemetry/exporter-trace-otlp-http";
|
||||
import {BatchSpanProcessor} from "@opentelemetry/sdk-trace-base";
|
||||
import {Layer, ManagedRuntime} from "effect";
|
||||
import {OTLP_ENDPOINT, OTLP_TRACE_PROPAGATION} from "../env.ts";
|
||||
|
||||
export const WebSdkLive = OTLP_TRACE_PROPAGATION
|
||||
? layer(() => ({
|
||||
resource: {serviceName: "Web UI"},
|
||||
spanProcessor: new BatchSpanProcessor(
|
||||
new OTLPTraceExporter({url: OTLP_ENDPOINT}),
|
||||
),
|
||||
}))
|
||||
: Layer.empty;
|
||||
|
||||
if (OTLP_ENDPOINT) {
|
||||
console.log("OpenTelemetry initialized with OTLP endpoint", OTLP_ENDPOINT);
|
||||
|
||||
if (OTLP_TRACE_PROPAGATION) {
|
||||
console.log("OpenTelemetry initialized with trace propagation");
|
||||
} else {
|
||||
console.warn("OpenTelemetry initialized without trace propagation");
|
||||
}
|
||||
} else {
|
||||
console.warn("OpenTelemetry not initialized because no OTLP endpoint is set");
|
||||
}
|
||||
|
||||
export const runtime = ManagedRuntime.make(WebSdkLive);
|
||||
40
web/src/api/notes.ts
Normal file
40
web/src/api/notes.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import {HttpClient, HttpClientRequest, HttpClientResponse,} from "@effect/platform";
|
||||
import * as Schema from "@effect/schema/Schema";
|
||||
import {Effect} from "effect";
|
||||
import {OTLP_TRACE_PROPAGATION} from "../env.ts";
|
||||
import {APIResponse, BASE_URL, FailedAPIResponse} from "./response.ts";
|
||||
|
||||
export const NoteId = Schema.UUID.pipe(Schema.brand("UserId"));
|
||||
export type NoteId = Schema.Schema.Type<typeof NoteId>;
|
||||
|
||||
export const NoteVisibility = Schema.Literal("public", "private", "direct");
|
||||
export type NoteVisibility = Schema.Schema.Type<typeof NoteVisibility>;
|
||||
|
||||
export class Note extends Schema.Class<Note>("Note")({
|
||||
id: NoteId,
|
||||
visibility: NoteVisibility,
|
||||
}) {
|
||||
}
|
||||
|
||||
export class NoteCreation extends Schema.Class<NoteCreation>("NoteCreation")({
|
||||
content: Schema.String,
|
||||
visibility: Schema.optionalWith(NoteVisibility, {default: () => "public"}),
|
||||
mentions: Schema.optional(Schema.Array(Schema.String)),
|
||||
}) {
|
||||
}
|
||||
|
||||
const createNoteBody = HttpClientRequest.schemaBody(NoteCreation);
|
||||
export const createNote = (data: NoteCreation) =>
|
||||
HttpClientRequest.post(`${BASE_URL}/api/app/notes/`).pipe(
|
||||
createNoteBody(data),
|
||||
Effect.andThen(HttpClient.fetch),
|
||||
HttpClientResponse.schemaBodyJsonScoped(APIResponse(Note)),
|
||||
Effect.filterOrFail(
|
||||
(res) => res.ok,
|
||||
(res) => (res as FailedAPIResponse).error,
|
||||
),
|
||||
Effect.map((d) => d.data),
|
||||
Effect.either,
|
||||
Effect.withSpan("createNote", {attributes: {data: data}}),
|
||||
HttpClient.withTracerPropagation(OTLP_TRACE_PROPAGATION),
|
||||
);
|
||||
42
web/src/api/response.ts
Normal file
42
web/src/api/response.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import * as Schema from "@effect/schema/Schema";
|
||||
|
||||
export const BASE_URL = import.meta.env.VITE_BASE_URL ?? "INVALID";
|
||||
|
||||
export class APIError extends Schema.Class<APIError>("APIError")({
|
||||
status_code: Schema.Number,
|
||||
description: Schema.String,
|
||||
metadata: Schema.optional(
|
||||
Schema.Record({key: Schema.String, value: Schema.Any}),
|
||||
),
|
||||
}) {
|
||||
_tag = "APIError" as const;
|
||||
|
||||
static toString(error: APIError) {
|
||||
return `${error.status_code}: ${error.description}${error.metadata ? JSON.stringify(error.metadata) : ""}`;
|
||||
}
|
||||
|
||||
override toString() {
|
||||
return APIError.toString(this);
|
||||
}
|
||||
|
||||
get message() {
|
||||
return this.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export const FailedAPIResponse = Schema.Struct({
|
||||
ok: Schema.Literal(false),
|
||||
error: APIError,
|
||||
data: Schema.Null,
|
||||
});
|
||||
export type FailedAPIResponse = Schema.Schema.Type<typeof FailedAPIResponse>;
|
||||
|
||||
export const APIResponse = <A, I>(data: Schema.Schema<A, I>) =>
|
||||
Schema.Union(
|
||||
Schema.Struct({
|
||||
ok: Schema.Literal(true),
|
||||
data: data,
|
||||
error: Schema.Null,
|
||||
}),
|
||||
FailedAPIResponse,
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue