Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/auto-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
Expand All @@ -79,15 +79,15 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Setup Node.js (for native module compatibility)
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: "20"

Expand All @@ -110,7 +110,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down
55 changes: 17 additions & 38 deletions bun.lock

Large diffs are not rendered by default.

11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rox",
"version": "2026.4.0",
"version": "2026.4.1",
"license": "AGPL-3.0-only",
"devDependencies": {
"@playwright/test": "^1.59.1",
Expand All @@ -11,10 +11,6 @@
"typescript": "^5.9.3",
"vite-plus": "^0.1.15"
},
"overrides": {
"vite": "^8.0.0",
"@vitejs/plugin-react": "^6.0.0"
},
"description": "Lightweight ActivityPub server & client with Misskey API compatibility",
"engines": {
"bun": ">=1.0.0"
Expand Down Expand Up @@ -55,5 +51,8 @@
},
"workspaces": [
"packages/*"
]
],
"dependencies": {
"waku": "^1.0.0-alpha.7"
}
}
2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hono_rox",
"version": "1.5.0",
"version": "1.5.1",
"private": true,
"license": "AGPL-3.0-only",
"type": "module",
Expand Down
44 changes: 31 additions & 13 deletions packages/backend/src/interfaces/IFileStorage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/**
* Metadata for a user-uploaded file.
*/
export interface FileMetadata {
/** Original file name */
name: string;
/** MIME type of the file */
type: string;
/** File size in bytes */
size: number;
/** ID of the user who uploaded the file */
userId: string;
}

Expand All @@ -14,34 +21,45 @@ export interface EmojiFileMetadata {
size: number;
}

/**
* Abstract file storage interface.
*
* Implementations handle saving, deleting, and resolving URLs for uploaded files.
* Supports both user-uploaded files and instance-owned emoji files.
*/
export interface IFileStorage {
/**
* ファイルを保存
* @param file ファイルのBuffer
* @param metadata ファイルメタデータ
* @returns 保存されたファイルのパス(相対パスまたはキー)
* Save a file to storage.
*
* @param file - File contents as a Buffer
* @param metadata - File metadata including name, type, size, and owner
* @returns Relative path or key of the saved file
*/
save(file: Buffer, metadata: FileMetadata): Promise<string>;

/**
* Save emoji file to dedicated emoji directory
* Not associated with any user - instance-owned resource
* @param file File buffer
* @param metadata Emoji file metadata
* Save emoji file to dedicated emoji directory.
*
* Not associated with any user - instance-owned resource.
*
* @param file - File buffer
* @param metadata - Emoji file metadata
* @returns Relative path of the saved file
*/
saveEmoji(file: Buffer, metadata: EmojiFileMetadata): Promise<string>;

/**
* ファイルを削除
* @param filePath ファイルパス
* Delete a file from storage.
*
* @param filePath - Relative path or key of the file to delete
*/
delete(filePath: string): Promise<void>;

/**
* ファイルの公開URLを取得
* @param filePath ファイルパス
* @returns 公開アクセス可能なURL
* Get the publicly accessible URL for a stored file.
*
* @param filePath - Relative path or key of the file
* @returns Publicly accessible URL
*/
getUrl(filePath: string): string;
}
43 changes: 32 additions & 11 deletions packages/backend/src/interfaces/repositories/IUserRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ export interface SearchUsersOptions {

export interface IUserRepository {
/**
* ユーザーを作成
* Create a new user.
*
* @param user - User data excluding auto-generated timestamps
* @returns Created user record
*/
create(user: Omit<User, "createdAt" | "updatedAt">): Promise<User>;

/**
* IDでユーザーを取得
* Find a user by their ID.
*
* @param id - User ID
* @returns User if found, null otherwise
*/
findById(id: string): Promise<User | null>;

Expand All @@ -52,14 +58,19 @@ export interface IUserRepository {
findAll(options?: ListUsersOptions): Promise<User[]>;

/**
* ユーザー名でユーザーを取得
* @param username ユーザー名
* @param host ホスト名(nullの場合はローカルユーザー)
* Find a user by username and host.
*
* @param username - Username to search for
* @param host - Host domain (null for local users)
* @returns User if found, null otherwise
*/
findByUsername(username: string, host?: string | null): Promise<User | null>;

/**
* メールアドレスでユーザーを取得
* Find a user by email address.
*
* @param email - Email address to search for
* @returns User if found, null otherwise
*/
findByEmail(email: string): Promise<User | null>;

Expand All @@ -75,23 +86,33 @@ export interface IUserRepository {
findByUri(uri: string): Promise<User | null>;

/**
* ユーザー情報を更新
* Update a user's data.
*
* @param id - User ID
* @param data - Partial user data to update
* @returns Updated user record
*/
update(id: string, data: Partial<Omit<User, "id" | "createdAt">>): Promise<User>;

/**
* ユーザーを削除
* Delete a user by ID.
*
* @param id - User ID
*/
delete(id: string): Promise<void>;

/**
* ユーザー数を取得
* @param localOnly ローカルユーザーのみをカウントする場合はtrue
* Get the total number of users.
*
* @param localOnly - If true, count only local users
* @returns Total user count
*/
count(localOnly?: boolean): Promise<number>;

/**
* リモートユーザー数を取得
* Get the total number of remote users.
*
* @returns Remote user count
*/
countRemote(): Promise<number>;

Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/lib/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ function createLoggerConfig(config: LoggerConfig = {}): pino.LoggerOptions {
*/
function createTransport(config: LoggerConfig = {}): pino.TransportSingleOptions | undefined {
const isProduction = process.env.NODE_ENV === "production";
const pretty = config.pretty ?? !isProduction;
const pretty = config.pretty ?? true;

if (pretty) {
return {
target: "pino-pretty",
options: {
colorize: true,
colorize: !isProduction,
translateTime: "SYS:standard",
ignore: "pid,hostname,env",
},
Expand Down
12 changes: 8 additions & 4 deletions packages/backend/src/middleware/di.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import { getContainer, type AppContainer } from "../di/container.js";
import type { PluginLoader } from "../plugins/loader.js";

/**
* DIミドルウェア
* コンテナの内容をHonoのContextに注入
* Dependency injection middleware.
*
* Injects all DI container bindings into the Hono request context,
* making repositories, services, and adapters available to route handlers.
*
* @returns Hono middleware function
*/
export function diMiddleware() {
const container = getContainer();

return async (c: Context, next: Next) => {
// コンテナの各プロパティをContextに設定
// Set each container property on the Hono context
c.set("userRepository", container.userRepository);
c.set("noteRepository", container.noteRepository);
c.set("driveFileRepository", container.driveFileRepository);
Expand Down Expand Up @@ -61,7 +65,7 @@ export function diMiddleware() {
};
}

// Hono Context型の拡張
// Extend Hono's ContextVariableMap with DI container types
declare module "hono" {
interface ContextVariableMap extends AppContainer {
container: AppContainer;
Expand Down
3 changes: 1 addition & 2 deletions packages/backend/src/plugins/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ export class PluginLoader {
}
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
logger.error({ error: message }, "Failed to discover plugins directory");
// If plugins dir doesn't exist, that's okay - just no plugins
logger.debug({ error: message }, "Plugins directory not found, skipping");
}

return results;
Expand Down
10 changes: 8 additions & 2 deletions packages/backend/src/routes/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ const STATE_COOKIE_NAME = "oauth_state";
const STATE_COOKIE_MAX_AGE = 600; // 10 minutes

/**
* Get OAuth service instance
* Get OAuth service instance from the Hono context's DI container.
*
* @param c - Hono request context
* @returns Configured OAuthService instance
*/
const getOAuthService = (c: Context): OAuthService => {
const oauthAccountRepository = c.get("oauthAccountRepository");
Expand All @@ -34,7 +37,10 @@ const getOAuthService = (c: Context): OAuthService => {
};

/**
* Validate OAuth provider parameter
* Validate that a string is a supported OAuth provider.
*
* @param provider - Provider name to validate
* @returns True if the provider is supported
*/
const isValidProvider = (provider: string): provider is OAuthProvider => {
return ["github", "google", "discord", "mastodon"].includes(provider);
Expand Down
10 changes: 9 additions & 1 deletion packages/backend/src/services/NotificationStreamService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export class NotificationStreamService {

/**
* Get singleton instance
*
* @returns The shared NotificationStreamService instance
*/
static getInstance(): NotificationStreamService {
if (!NotificationStreamService.instance) {
Expand Down Expand Up @@ -151,6 +153,8 @@ export class NotificationStreamService {

/**
* Get total number of active connections
*
* @returns Sum of all user connection counts
*/
getTotalConnections(): number {
let total = 0;
Expand Down Expand Up @@ -212,7 +216,11 @@ export class NotificationStreamService {
}
}

// Export singleton getter
/**
* Get the singleton NotificationStreamService instance.
*
* @returns The shared NotificationStreamService instance
*/
export function getNotificationStreamService(): NotificationStreamService {
return NotificationStreamService.getInstance();
}
Loading