Skip to content

Conversation

@YasunariIguchi
Copy link
Contributor

@YasunariIguchi YasunariIguchi commented Nov 16, 2025

【当日ページ】FIX:終了後のイベントを開くと、エラーが表示される
#275

partykit/partykit->cloudflare/partykitへの移行
#279


主な変更

  1. パッケージとデプロイツールの変更
    パッケージ: partykit@0.0.115 → partyserver@0.0.75
    デプロイツール: PartyKit CLI → Wrangler (Cloudflare Workers)
    インフラ: PartyKitマネージドプラットフォーム → Cloudflare Workers
    デプロイURL: *.partykit.dev → *.workers.dev

  2. URLルーティングの変更
    変更理由: PartyServerのルーティング仕様変更により、Durable Object binding名(ForMokuServer)がkebab-caseに変換され、URL pathに反映されるようになりました。

旧: /parties/main/:room
新: /parties/for-moku-server/:room

  1. 環境変数の整理
    PartyKitサーバーの接続先を環境変数で管理するように変更:

ローカル: NEXT_PUBLIC_PARTYKIT_HOST=localhost:1999
本番: NEXT_PUBLIC_PARTYKIT_HOST=for-moku-partykit.y-iguchi.workers.dev
また、PartyKitサーバー側もAPIベースURLを環境変数化:

wrangler.tomlでAPI_BASE_URLを設定(本番ではコメントアウトを解除して使用)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request migrates the WebSocket infrastructure from the legacy partykit/partykit (which has deployment issues since October 2025) to the officially maintained cloudflare/partykit implementation using Cloudflare Workers and Durable Objects. Additionally, it fixes a bug where opening finished events would cause errors due to improper null checking.

Key changes:

  • Migration from partykit package to partyserver for the WebSocket server
  • Introduction of Cloudflare Workers deployment via Wrangler
  • Fix for null pointer exception when accessing finished event states

Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
partykit/wrangler.toml New Cloudflare Workers configuration defining Durable Objects bindings and migrations
partykit/src/server.ts Updated imports from partykit/server to partyserver, changed storage/broadcast API calls from this.room.* to this.ctx.*/this.*, fixed timezone handling
partykit/src/index.ts New entry point for Cloudflare Workers with fetch handler and PartyKit routing
partykit/package.json Updated scripts to use wrangler CLI, replaced partykit dependency with partyserver and wrangler
partykit/package-lock.json Updated dependency tree reflecting package changes
partykit/Dockerfile Updated base image to node:22-bookworm and changed CMD to use new dev script
partykit/.gitignore Added Wrangler-specific ignore patterns (.wrangler/, .dev.vars, etc.)
front/src/lib/db/finished_event_state.ts Added optional chaining (res[0]?.userIcons) to prevent null reference errors
front/src/lib/auth/auth.ts Updated party URL from /parties/main/ to /parties/for-moku-server/
front/src/components/templates/room/ActiveEventTemplate.tsx Added party: "for-moku-server" parameter to usePartySocket
front/src/app/room/[roomId]/page.tsx Updated all fetch URLs to use /parties/for-moku-server/ and removed unused import
front/src/app/env.ts Updated default host to localhost:1999 and added localhost check in protocol detection
docs/code/websocket/partyKit.md Comprehensive rewrite documenting the Cloudflare PartyKit setup, local development, and deployment
docs/code/websocket/cloudflare-partykit-migration.md New detailed migration guide with step-by-step instructions, troubleshooting, and FAQ
Files not reviewed (1)
  • partykit/package-lock.json: Language not supported

Comment on lines 119 to 128
const user = (await request.json()) as User;
const userIcon = userIcons.find((icon) => {
const userIcon = userIcons?.find((icon) => {
return icon.user.id === user.id;
})

if (!userIcon) {
this.room.broadcast(JSON.stringify({ type: "new", user }));
this.broadcast(JSON.stringify({ type: "new", user }));
this.userIcons!.push({ user: user, position: { x: 0, y: 0 }});
await this.room.storage.put("userIcons", this.userIcons);
await this.ctx.storage.put("userIcons", this.userIcons);
}
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing input validation for the user data received from POST request. The request.json() could fail or return malformed data. Add try-catch block around request.json() and validate the user object structure before processing to prevent potential crashes or data corruption.

Copilot uses AI. Check for mistakes.
Comment on lines 133 to 143
if (request.method === "DELETE") {
const userId = await request.json();

this.room.broadcast(JSON.stringify({ type: "delete", userId }))
this.broadcast(JSON.stringify({ type: "delete", userId }))
this.userIcons = userIcons!.filter((icon) => {
return icon.user.id !== userId;
});
await this.room.storage.put("userIcons", this.userIcons);
await this.ctx.storage.put("userIcons", this.userIcons);

return new Response(null, { status: 204 });
}
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing input validation for DELETE request. The userId from request.json() should be validated before use. Add error handling for request.json() and validate that userId is a non-empty string to prevent processing invalid delete requests.

Copilot uses AI. Check for mistakes.
return;
}

const message = JSON.parse(messageString);
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for JSON.parse(). If messageString contains invalid JSON, this will throw an error and crash the handler. Wrap JSON.parse() in a try-catch block and log/handle the error appropriately.

Suggested change
const message = JSON.parse(messageString);
let message;
try {
message = JSON.parse(messageString);
} catch (err) {
console.warn("Failed to parse incoming WebSocket message as JSON:", err, messageString);
return;
}

Copilot uses AI. Check for mistakes.
Comment on lines 40 to 46
if (!userIcons) {
console.log("record doesn't exist")
const url = `${PARTYKIT_URL}/parties/main/${roomId}`;
const url = `${PARTYKIT_URL}/parties/for-moku-server/${roomId}`;
console.log("Fetching from:", url);
const req = await fetch(url);
userIcons = await req.json();
}
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The console.log message 'record doesn't exist' is ambiguous and doesn't specify which record. Consider a more descriptive message such as 'No finished event state found in database, fetching from PartyKit' to improve debugging.

Copilot uses AI. Check for mistakes.
Comment on lines 44 to 45
const req = await fetch(url);
userIcons = await req.json();
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for the fetch request to PartyKit. If the fetch fails or returns a non-OK response, await req.json() could fail. Add response status check and error handling to prevent unhandled promise rejections.

Suggested change
const req = await fetch(url);
userIcons = await req.json();
try {
const req = await fetch(url);
if (!req.ok) {
console.error(`Failed to fetch user icons from PartyKit: ${req.status} ${req.statusText}`);
userIcons = [];
} else {
userIcons = await req.json();
}
} catch (err) {
console.error("Error fetching or parsing user icons from PartyKit:", err);
userIcons = [];
}

Copilot uses AI. Check for mistakes.
YasunariIguchi and others added 2 commits November 17, 2025 10:00
DurableObjectNamespaceをインポート

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants