Skip to content

Use ctx.id.name for PartyServer name#378

Merged
threepointone merged 3 commits into
mainfrom
this-name
Apr 24, 2026
Merged

Use ctx.id.name for PartyServer name#378
threepointone merged 3 commits into
mainfrom
this-name

Conversation

@threepointone
Copy link
Copy Markdown
Collaborator

@threepointone threepointone commented Apr 24, 2026

Summary

Durable Objects now expose ctx.id.name on every entry point (constructor, fetch, alarm, hibernating websocket handlers) when the DO is addressed via idFromName() / getByName(). This PR makes that the primary source of this.name in PartyServer and retires the scaffolding we built to paper over its absence.

  • this.name resolves from this.ctx.id.name. It is now available inside the constructor, which was never possible before. The apologetic workerd#2240 error message is gone.
  • routePartykitRequest no longer issues a setName() / _initAndFetch() RPC before fetch(). The WebSocket path goes from 2 RPCs to 1; HTTP stays at 1. Props (when supplied) are delivered via the x-partykit-props request header, set after onBeforeConnect / onBeforeRequest hooks run so they aren't visible to user hook code.
  • getServerByName continues to perform a single RPC that awaits onStart() before returning, so user-defined RPC methods on the stub can rely on initialization being done (native DO RPCs don't pass through Server.fetch() and thus don't trigger #ensureInitialized() themselves). That RPC is now cheaper internally — no storage write.
  • Server no longer writes the __ps_name record to storage. Existing records remain on disk and are only read inside alarm() as a fallback for alarms scheduled before 2026-03-15 (where ctx.id.name is not carried into the alarm handler — see the Durable Objects ID docs).
  • setName() and _initAndFetch() are marked @deprecated. They continue to work for backward compatibility. setName(name) now throws if name does not match ctx.id.name. _initAndFetch() is simplified to setName() + fetch().
  • x-partykit-room header is still accepted as a fallback when ctx.id.name is unavailable.

Call-count delta

Call path Before After
getServerByName(ns, name) 1 RPC 1 RPC (cheaper; no storage write)
getServerByName(ns, name, { props }) 1 RPC 1 RPC (cheaper; no storage write)
routePartykitRequest HTTP 1 RPC 1 RPC
routePartykitRequest WS 2 RPCs 1 RPC
__ps_name storage writes per setName never
__ps_name storage reads every cold wake alarm() only (legacy)

Not supported

Addressing PartyServer DOs via idFromString() or newUniqueId(). These paths have ctx.id.name === undefined inside the DO and will surface as a clear error from this.name. PartyServer has always assumed name-based addressing via getServerByName / routePartykitRequest; this release makes that assumption explicit.

Test plan

  • All tests across the monorepo pass (npm run check:test)
  • Types clean across every package (npm run check:type)
  • Lint + format clean (npm run check:lint, npm run check:format)
  • New test: this.name resolves from ctx.id.name on first fetch without any header or setName RPC
  • New test: setName() throws when called with a name different from ctx.id.name
  • New test (regression guard): getServerByName awaits onStart before returning so user-defined RPC methods see initialized state
  • Updated test: legacy __ps_name storage fallback exercised via newUniqueId() to simulate pre-2026-03-15 alarms where ctx.id.name is actually undefined
  • Updated test: x-partykit-room header fallback still works for direct stub.fetch() callers
  • Follow-up: release Agents SDK with confirmation that __unsafe_ensureInitialized() still works as expected in their native-RPC path

PartyServer now uses native ctx.id.name as the primary source for this.name (minor release). This makes this.name available in the constructor and onStart for cold wakes, removes the prior storage write of __ps_name, and eliminates several setName/_initAndFetch RPCs (WS path reduced from 2 RPCs to 1; HTTP path unchanged). setName() and _initAndFetch() are deprecated (setName will throw if the provided name differs from ctx.id.name). Props are delivered via x-partykit-props; x-partykit-room remains a fallback when ctx.id.name is unavailable. Alarms still fall back to stored __ps_name for pre-2026-03-15 scheduled alarms. Tests and worker helpers were updated accordingly. Also includes dependency bumps across fixtures and updated package-lock entries.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

🦋 Changeset detected

Latest commit: 9beaec8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
partyserver Minor
partywhen Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 24, 2026

Open in StackBlitz

hono-party

npm i https://pkg.pr.new/cloudflare/partykit/hono-party@378

partyfn

npm i https://pkg.pr.new/cloudflare/partykit/partyfn@378

partyserver

npm i https://pkg.pr.new/cloudflare/partykit/partyserver@378

partysocket

npm i https://pkg.pr.new/cloudflare/partykit/partysocket@378

partysub

npm i https://pkg.pr.new/cloudflare/partykit/partysub@378

partysync

npm i https://pkg.pr.new/cloudflare/partykit/partysync@378

partytracks

npm i https://pkg.pr.new/cloudflare/partykit/partytracks@378

partywhen

npm i https://pkg.pr.new/cloudflare/partykit/partywhen@378

y-partyserver

npm i https://pkg.pr.new/cloudflare/partykit/y-partyserver@378

commit: 9beaec8

Regression fix: with no props, `getServerByName` was returning a stub
with 0 RPCs, meaning `onStart()` had not run by the time user-defined
RPC methods on the stub were invoked (user RPCs don't pass through
`Server.fetch()` and therefore don't trigger `#ensureInitialized()`).

Restore the unconditional `setName()` call so `onStart()` is guaranteed
to have completed before `getServerByName()` resolves. The call is now
cheap internally (no storage write; name is read from `ctx.id.name`),
so this only costs the RPC round-trip.

Also:
- Simplify `_initAndFetch` (now a thin shim: setName + fetch).
- Add regression test covering `getServerByName` + user RPC method.
- Update README `.name` docs to reflect constructor availability.
- Update changeset to drop the "0 RPC" claim for getServerByName.

Made-with: Cursor
- Bump @cloudflare/workers-types peer dep to ^4.20260424.1 across
  partyserver, partysub, partysync, y-partyserver, hono-party. The old
  ^4.20240729.0 range predates `ctx.id.name` in the type surface.
- Improve the "cannot determine name" error in Server.fetch() to list
  the three real causes (idFromString/newUniqueId, old workerd runtime,
  direct stub.fetch without a helper) so users on old runtimes get an
  actionable hint instead of a misleading "missing header" message.
- Add NameInConstructorServer + test guarding the headline Phase 1
  capability: `this.name` must be readable from class field
  initializers and the constructor body.

Made-with: Cursor
@threepointone threepointone merged commit b99c1da into main Apr 24, 2026
6 checks passed
@threepointone threepointone deleted the this-name branch April 24, 2026 20:00
@github-actions github-actions Bot mentioned this pull request Apr 24, 2026
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.

1 participant