cloudflare / cloudflare/partykit
PartyServer: Phase 2 cleanup candidates (post ctx.id.name migration)
- Dominant language
- TypeScript
- Stars
- 1.3k
- Forks
- 79
- PR merge metrics
- No merged PRs in 30d
Description
Tracking issue for cleanups that become possible once PartyServer users have all moved onto a runtime with `ctx.id.name`, and the pre-2026-03-15 legacy alarm fallback has drained in practice.
Context: #378 migrated `this.name` to read from `ctx.id.name` as the primary source, while keeping compatibility shims in place. Once we're confident those shims aren't load-bearing anymore, we can do the following in a single breaking-change release.
## API surface to remove
### 1. `Server.setName(name, props?)` (public, already `@deprecated`)
Callers no longer need it — `this.name` is derived from `ctx.id.name` automatically. Keep the behavior only if someone still uses it for props delivery, and even then it should migrate to a dedicated method or a props header.
- **Blockers**: any external code still calling `this.setName(...)` explicitly. Grep for this before removing.
### 2. `Server._initAndFetch(name, props, request)` (internal, already `@deprecated`)
Already reduced to a thin `setName()` + `fetch()` shim in #378. Delete once `setName` is gone.
### 3. `Server.__unsafe_ensureInitialized()` (internal, used by Agents SDK)
After `setName()` goes away, this is the remaining "please run `onStart()` now" primitive. Consider renaming to something less scary (e.g. `_runOnStart()`) and making it a supported, documented internal hook for framework authors.
### 4. `x-partykit-room` header fallback in `Server.fetch()`
Only reached when `ctx.id.name` is undefined *and* `#_name` is unset — i.e. for users calling `stub.fetch()` directly on a stub built via `idFromString()` or `newUniqueId()`. We don't support those paths; delete the fallback and throw directly.
### 5. `x-partykit-namespace` and `x-partykit-jurisdiction` request headers
Set by `routePartykitRequest()` on every DO fetch but **never read anywhere** in the codebase. Undocumented. Technically observable to user code through `onBeforeConnect`/`onBeforeRequest` hooks and `request.headers` inside `onRequest`/`onConnect`, which is the only reason they're a "breaking" change rather than trivially deleteable.
### 6. `Connection.server` (already `@deprecated` in `types.ts`)
Still populated in `webSocketMessage`/`webSocketClose`/`webSocketError` and the WebSocket upgrade path. Users should read `this.name` on the server instead.
## Internal cleanups
### 7. `#_name: string | undefined` field on `Server`
Only populated via three legacy paths now:
- `setName()` when `ctx.id.name` is undefined
- `x-partykit-room` header fallback in `fetch()`
- `__ps_name` storage read in `alarm()`
Once items 1 and 4 are gone, `#_name` only remains for the alarm legacy fallback (item 8). Once that's gone too, delete the field entirely and simplify `get name()` to `return this.ctx.id.name`.
### 8. `__ps_name` storage-backed legacy alarm fallback
PartyServer no longer writes this key (#378), but still reads it inside `alarm()` to handle pre-2026-03-15 alarm records where `ctx.id.name` is `undefined`. Per the [Durable Objects ID docs](https://developers.cloudflare.com/durable-objects/api/id/#name):
> Alarms created before 2026-03-15 do not have `name` stored. When such an alarm fires, `ctx.id.name` will be `undefined`, and any new alarm scheduled from that handler will also lack a `name`.
Important caveat: **a pre-2026-03-15 alarm that reschedules itself from inside `onAlarm()` inherits the nameless state indefinitely.** So the fallback never actually drains for long-lived scheduler DOs (e.g. `partywhen`). Deleting this requires either:
- Documenting that users should re-trigger their alarms via a fetch/RPC once after upgrade to escape the nameless chain, or
- Adding a migration step that reschedules nameless alarms via a trampoline fetch (more involved).
### 9. `#hydrateNameFromLegacyStorage()`
Paired with item 8. Delete together.
### 10. `#status` / `#ensureInitialized()` re-examination
Not obviously removable — `onStart()` is async and still needs to run before request handlers. But worth revisiting whether the state-machine approach is still the simplest way to express this, given that the rest of the machinery around it has simplified significantly.
## Dependency / metadata cleanups
### 11. `@cloudflare/workers-types` peer dep
Already bumped to `^4.20260424.1` in #378. Consider tracking a minimum workerd runtime version more explicitly, given we now hard-depend on `ctx.id.name`.
### 12. README + error messages audit
Post-cleanup, do another pass on `packages/partyserver/README.md` and the error messages in `Server.fetch()` to remove references to removed APIs.
## Suggested ordering
1. Deprecate the public `setName()` API more visibly (release notes, console.warn on use).
2. Deprecate `connection.server` more visibly.
3. Give it a release cycle or two for people to migrate.
4. Ship a major release that removes items 1, 2, 3, 4, 5, 6, 7.
5. Decide separately (based on operational experience) when to remove items 8, 9 — these are about draining legacy alarms, not breaking user APIs.
Contributor guide
Assessment
This issue has not been assessed yet.