12.x → 13.0.0, entry by entry
Two breaking entries, and both are compile errors the moment you upgrade. Nothing changes at runtime, no data migrates, no cursor or protocol moves. This major is wide in what it ADDS — notifications, full-text search, webhooks, exports, state machines, form binding — and narrow in what it breaks.
No app.config.ts key moves. No codemod: each entry names its own manual edit.
| # | Surface | Costs you an edit if |
|---|---|---|
| 1 | ServiceFactory receives CtxFacts, not Ctx | your defineService factory annotates its parameter (ctx: Ctx), or reads a sibling service off it |
| 2 | PageLike.content() is deleted | you called it in an e2e test, or implement PageLike yourself |
1. ServiceFactory receives CtxFacts
defineService's factory is handed the framework's own facts — actor, now(), clock, tz,
locale, requestId — and not the app's augmented services. It always worked this way; the
type said otherwise.
// before — compiles, and is circular: the factory that BUILDS ctx.posts
// declares that ctx.posts must already exist
export const posts = defineService('posts', (ctx: Ctx) => ({ … }));
// after — the documented form, which cannot drift from the signature
export const posts = defineService('posts', (ctx) => ({ … }));Drop the annotation. If you genuinely need to name the type, CtxFacts is now exported from
@ultimat3/core — it was the parameter type all along and the barrel never re-exported it, so no
app could name what its own factory was handed.
Reading a sibling service inside a factory no longer typechecks. That was already documented as
unsupported — factories run in registration order and a sibling may not exist yet — but the type
permitted it. Move the read into the method that needs it, where useService() resolves at call
time.
2. PageLike.content() is deleted
PageLike's comment claimed "every member is one the reference app's e2e suite already calls".
An audit found that false for three of eleven: content() had zero call sites anywhere in the
repository, and title() / reload() are named only by x g route's generated template, which
nothing executes.
content() is gone. title() and reload() stay, with the caveat recorded on each. If you drive
a browser yourself, delete content from your PageLike implementation; if you called it, read the
DOM through evaluate() instead.