cloudflare / cloudflare/partykit

PartyServer: Phase 2 cleanup candidates (post ctx.id.name migration)

Open
#379 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.