mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 16:55:37 +02:00
⭐ feat: New account system with improved team management (#273)
Description <!-- Briefly describe the purpose and scope of your changes --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced comprehensive account management with combined user and team info. - Added advanced, context-aware logging utilities. - Implemented invite code generation for teams with uniqueness guarantees. - Expanded example data for users, teams, subscriptions, sessions, and games. - **Enhancements** - Refined user, team, member, and Steam account schemas for richer data and validation. - Streamlined user creation, login acknowledgment, and error handling. - Improved API authentication and unified actor context management. - Added persistent shared temporary volume support to API and auth services. - Enhanced Steam account management with create, update, and event notifications. - Refined team listing and serialization integrating Steam accounts as members. - Simplified event, context, and logging systems. - Updated API and auth middleware for better token handling and actor provisioning. - **Bug Fixes** - Fixed multiline log output to prefix each line with log level. - **Removals** - Removed machine and subscription management features, including schemas and DB tables. - Disabled machine-based authentication and removed related subject schemas. - Removed deprecated fields and legacy logic from member and team management. - Removed legacy event and error handling related to teams and members. - **Chores** - Reorganized and cleaned exports across utility and API modules. - Updated database schemas for users, teams, members, and Steam accounts. - Improved internal code structure, imports, and error messaging. - Moved logger patching to earlier initialization for consistent logging. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
import { z } from "zod";
|
||||
import { Hono } from "hono";
|
||||
import { notPublic } from "./utils/auth";
|
||||
import { notPublic } from "./utils";
|
||||
import { describeRoute } from "hono-openapi";
|
||||
import { User } from "@nestri/core/user/index";
|
||||
import { Team } from "@nestri/core/team/index";
|
||||
import { assertActor } from "@nestri/core/actor";
|
||||
import { Examples } from "@nestri/core/examples";
|
||||
import { ErrorResponses, Result } from "./utils";
|
||||
import { ErrorCodes, VisibleError } from "@nestri/core/error";
|
||||
import { Account } from "@nestri/core/account/index";
|
||||
|
||||
export namespace AccountApi {
|
||||
export const route = new Hono()
|
||||
@@ -22,10 +18,7 @@ export namespace AccountApi {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: Result(
|
||||
z.object({
|
||||
...User.Info.shape,
|
||||
teams: Team.Info.array(),
|
||||
}).openapi({
|
||||
Account.Info.openapi({
|
||||
description: "User account information",
|
||||
example: { ...Examples.User, teams: [Examples.Team] }
|
||||
})
|
||||
@@ -34,27 +27,14 @@ export namespace AccountApi {
|
||||
},
|
||||
description: "User account details"
|
||||
},
|
||||
400: ErrorResponses[400],
|
||||
404: ErrorResponses[404],
|
||||
429: ErrorResponses[429]
|
||||
429: ErrorResponses[429],
|
||||
}
|
||||
}),
|
||||
async (c) => {
|
||||
const actor = assertActor("user");
|
||||
const [currentUser, teams] = await Promise.all([User.fromID(actor.properties.userID), User.teams()])
|
||||
|
||||
if (!currentUser)
|
||||
throw new VisibleError(
|
||||
"not_found",
|
||||
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
|
||||
"User not found",
|
||||
);
|
||||
|
||||
return c.json({
|
||||
data: {
|
||||
...currentUser,
|
||||
teams,
|
||||
}
|
||||
}, 200);
|
||||
},
|
||||
async (c) =>
|
||||
c.json({
|
||||
data: await Account.list()
|
||||
}, 200)
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import { patchLogger } from "../utils/patch-logger";
|
||||
import { HTTPException } from "hono/http-exception";
|
||||
import { ErrorCodes, VisibleError } from "@nestri/core/error";
|
||||
|
||||
patchLogger();
|
||||
|
||||
export const app = new Hono();
|
||||
app
|
||||
.use(logger())
|
||||
@@ -85,8 +87,6 @@ app.get(
|
||||
}),
|
||||
);
|
||||
|
||||
patchLogger();
|
||||
|
||||
export default {
|
||||
port: 3001,
|
||||
idleTimeout: 255,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Resource } from "sst";
|
||||
import { subjects } from "../../subjects";
|
||||
import { Actor } from "@nestri/core/actor";
|
||||
import { type MiddlewareHandler } from "hono";
|
||||
import { useActor, withActor } from "@nestri/core/actor";
|
||||
import { createClient } from "@openauthjs/openauth/client";
|
||||
import { ErrorCodes, VisibleError } from "@nestri/core/error";
|
||||
|
||||
@@ -11,7 +11,7 @@ const client = createClient({
|
||||
});
|
||||
|
||||
export const notPublic: MiddlewareHandler = async (c, next) => {
|
||||
const actor = useActor();
|
||||
const actor = Actor.use();
|
||||
if (actor.type === "public")
|
||||
throw new VisibleError(
|
||||
"authentication",
|
||||
@@ -22,9 +22,8 @@ export const notPublic: MiddlewareHandler = async (c, next) => {
|
||||
};
|
||||
|
||||
export const auth: MiddlewareHandler = async (c, next) => {
|
||||
const authHeader =
|
||||
c.req.query("authorization") ?? c.req.header("authorization");
|
||||
if (!authHeader) return withActor({ type: "public", properties: {} }, next);
|
||||
const authHeader = c.req.header("authorization");
|
||||
if (!authHeader) return Actor.provide("public", {}, next);
|
||||
const match = authHeader.match(/^Bearer (.+)$/);
|
||||
if (!match) {
|
||||
throw new VisibleError(
|
||||
@@ -44,20 +43,24 @@ export const auth: MiddlewareHandler = async (c, next) => {
|
||||
}
|
||||
|
||||
if (result.subject.type === "user") {
|
||||
const user = { ...result.subject.properties }
|
||||
const teamID = c.req.header("x-nestri-team");
|
||||
if (!teamID) return withActor(result.subject, next);
|
||||
return withActor(
|
||||
if (!teamID) {
|
||||
return Actor.provide("user", {
|
||||
...user
|
||||
}, next);
|
||||
}
|
||||
return Actor.provide(
|
||||
"system",
|
||||
{
|
||||
type: "system",
|
||||
properties: {
|
||||
teamID,
|
||||
},
|
||||
teamID
|
||||
},
|
||||
async () =>
|
||||
withActor(
|
||||
result.subject,
|
||||
next,
|
||||
)
|
||||
Actor.provide("user", {
|
||||
...user
|
||||
}, next)
|
||||
);
|
||||
}
|
||||
|
||||
return Actor.provide("public", {}, next);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./validator";
|
||||
export * from "./auth";
|
||||
export * from "./error";
|
||||
export * from "./result";
|
||||
export * from "./error";
|
||||
export * from "./validator";
|
||||
Reference in New Issue
Block a user