You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix: restore __ps_name storage hydrate for Agents facets (0.5.1)
0.5.0 moved the legacy __ps_name storage hydrate into `alarm()` only,
which broke Cloudflare Agents facets and any other framework that
writes __ps_name directly before calling __unsafe_ensureInitialized().
Facet DOs are spawned via `ctx.facets.get(...)` rather than
`idFromName()`, so their `ctx.id.name` is `undefined`. They were
relying on PartyServer's `#ensureInitialized()` calling
`#hydrateNameFromStorage()` to populate `this.name` before `onStart()`.
This PR:
- Moves the hydrate from `alarm()` into `#ensureInitialized()`, gated on
`!ctx.id.name && !#_name` so the happy path (normal idFromName DOs)
still pays zero storage reads.
- Simplifies `Server.fetch()` to delegate the hydrate to
`#ensureInitialized()`. The x-partykit-room header remains as a
last-resort fallback when neither ctx.id.name nor storage has a value.
- Simplifies `Server.alarm()` — no separate hydrate call needed.
- Softens `@deprecated` on `setName()` to clarify it's still the right
primitive for framework bootstrap of non-idFromName DOs (e.g. facets).
- Adds FacetLikeBootstrapServer + tests covering the fetch-time and
RPC-time hydrate paths.
Made-with: Cursor
Fix: restore legacy `__ps_name` storage fallback for framework bootstrap patterns.
6
+
7
+
0.5.0 moved the legacy storage hydrate into `alarm()` only, breaking Cloudflare Agents facets and any other framework that writes `__ps_name` directly before calling `__unsafe_ensureInitialized()`. Facet DOs are spawned via `ctx.facets.get(...)` rather than `idFromName()` and therefore have `ctx.id.name === undefined`; they relied on PartyServer reading the storage record back to populate `this.name` before `onStart()`.
8
+
9
+
Changes:
10
+
11
+
- Move the legacy `__ps_name` hydrate from `alarm()` into `#ensureInitialized()`, still gated on `!ctx.id.name && !#_name` so it costs nothing on the happy path (normal `idFromName()`/`getByName()` DOs skip the storage read entirely).
12
+
-`Server.fetch()` now delegates to `#ensureInitialized()` for the hydrate instead of doing its own. The `x-partykit-room` header fallback remains as a last resort when neither `ctx.id.name` nor a legacy storage record is available.
13
+
-`Server.alarm()` is simplified — it no longer needs its own hydrate call since `#ensureInitialized()` handles it.
14
+
-`setName()`'s `@deprecated` docblock is softened to clarify that it remains appropriate for framework-level bootstrap of non-`idFromName` DOs (e.g. Agents facets), not just a deprecated compatibility shim.
Copy file name to clipboardExpand all lines: packages/partyserver/src/index.ts
+49-24Lines changed: 49 additions & 24 deletions
Original file line number
Diff line number
Diff line change
@@ -389,24 +389,26 @@ export class Server<
389
389
this.#_props =JSON.parse(props);
390
390
}
391
391
392
-
// Legacy fallback for callers that bypass `routePartykitRequest`/
393
-
// `getServerByName` and invoke `stub.fetch()` directly with the
394
-
// `x-partykit-room` header. When the DO was addressed via
395
-
// `idFromName()`/`getByName()`, `ctx.id.name` provides the name and
396
-
// this branch is a no-op.
392
+
// Name resolution in `#ensureInitialized()` consults
393
+
// `ctx.id.name`, then a legacy storage record, so by the time it
394
+
// returns `this.name` is populated for any properly-addressed
395
+
// DO or any DO bootstrapped via the legacy `__ps_name` storage
396
+
// record (e.g. Cloudflare Agents facets). The only remaining
397
+
// case is a caller that bypasses both — then we fall back to
398
+
// the `x-partykit-room` request header.
399
+
awaitthis.#ensureInitialized();
400
+
397
401
if(!this.ctx.id.name&&!this.#_name){
398
402
constroom=request.headers.get("x-partykit-room");
399
403
if(!room){
400
-
thrownewError(`Cannot determine the name for ${this.#ParentClass.name}: this.ctx.id.name is undefinedand no x-partykit-room header is present. Likely causes:
404
+
thrownewError(`Cannot determine the name for ${this.#ParentClass.name}: this.ctx.id.name is undefined, no legacy __ps_name storage record is present, and no x-partykit-room header was supplied. Likely causes:
401
405
1. The stub was built via idFromString()/newUniqueId(). PartyServer requires name-based addressing (idFromName/getByName).
402
406
2. The workerd/wrangler runtime is too old to expose ctx.id.name — update to a recent wrangler release.
403
407
3. You called stub.fetch() directly without going through routePartykitRequest()/getServerByName(). Prefer those, or set the x-partykit-room header.`);
0 commit comments