feat: initial app

This commit is contained in:
2026-05-10 03:06:54 +07:00
parent 23be44dbe0
commit d5b92cc9a4
95 changed files with 8104 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
{
"name": "@pien-studio/api",
"private": true,
"scripts": {
"dev": "bun --watch src/index.ts",
"build": "bun build src/index.ts --outdir dist",
"start": "bun run dist/index.js",
"test": "vitest run",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@pien-studio/types": "workspace:*",
"elysia": "^1.1.25",
"zod": "^4.4.3"
},
"devDependencies": {
"bun-types": "latest",
"typescript": "^6.0.3",
"vitest": "^4.1.5"
}
}
+34
View File
@@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import { createApp } from "./index";
describe("api endpoints", () => {
it("returns root route info", async () => {
const app = createApp();
const response = await app.handle(new Request("http://localhost/"));
const body = await response.json();
expect(response.status).toBe(200);
expect(body.name).toBe("pien-api");
});
it("returns healthy status", async () => {
const app = createApp();
const response = await app.handle(new Request("http://localhost/health"));
const body = await response.json();
expect(response.status).toBe(200);
expect(body.ok).toBe(true);
});
it("returns token for valid device payload", async () => {
const app = createApp();
const response = await app.handle(
new Request("http://localhost/auth/device", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ deviceId: "dev1234", locale: "en" }),
}),
);
const body = await response.json();
expect(response.status).toBe(200);
expect(body.token).toBe("dev_dev1234");
});
});
+35
View File
@@ -0,0 +1,35 @@
import { Elysia } from "elysia";
import { DeviceSessionSchema } from "@pien-studio/types";
export function createApp() {
return new Elysia()
.get("/", () => ({
name: "pien-api",
status: "ok",
}))
.get("/health", () => ({ ok: true, service: "pien-api" }))
.post("/auth/device", ({ body }) => {
const parsed = DeviceSessionSchema.safeParse(body);
if (!parsed.success) {
return new Response(JSON.stringify({ error: "invalid_device_payload" }), {
status: 400,
});
}
return {
token: `dev_${parsed.data.deviceId}`,
scope: "local-sync",
};
})
.get("/sync/bootstrap", () => ({
replication: {
pull: "/sync/pull",
push: "/sync/push",
strategy: "couch-compatible",
},
}));
}
if (import.meta.main) {
createApp().listen(4000);
console.log("pien api listening on http://localhost:4000");
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"types": ["bun-types"]
},
"include": ["src/**/*.ts"]
}
+8
View File
@@ -0,0 +1,8 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "node",
include: ["**/*.test.ts"],
},
});