| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Add a `realtime` module to the Base44 JS SDK that lets users subscribe to and send messages to Cloudflare Durable Object-backed RealtimeHandlers deployed by the Base44 platform. Uses PartySocket for WebSocket transport with automatic token refresh on reconnect. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/sdk@0.8.40-pr.212.6649074Prefer not to change any import paths? Install using npm alias so your code still imports @base44/sdk: npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.40-pr.212.6649074"Or add it to your package.json dependencies: {
"dependencies": {
"@base44/sdk": "npm:@base44-preview/sdk@0.8.40-pr.212.6649074"
}
}
Preview published to npm registry — try new features instantly! |
Sorry, something went wrong.
partysocket was added to package.json but lock file was never generated. Also fixes .npmrc: was using env-var syntax (npm_config_registry=...) instead of npmrc syntax (registry=...). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
- subscribe() now returns a sync unsubscribe function instead of Promise<RealtimeSubscription> - send() is typed via RealtimeHandlerRegistry (user-declared message types) - Add RealtimeHandlerNameRegistry for CLI codegen (no conflict with user augmentation) - Drop RealtimeSubscription in favor of the simpler sync cleanup pattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
…et URL
partysocket@0.0.23's updateProperties only falls back for host/room/path,
not party. Passing {query:{token}} dropped party, changing the URL from
/parties/ChatRoom/room to /party/room.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
Don't connect until we have a token — avoids initial tokenless connection being rejected and the updateProperties/reconnect timing race. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
Expose this.storage (DO KV) and onStart() lifecycle hook so handlers can persist and load state. Both are backed by the compiled shim at runtime; the stub implementations throw to surface misuse in local dev/test outside a deployed context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
… async token refresh
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
… by JWT script_name, not URL party name
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
partysocket only reconnects on a browser close/error event, so a silently
dead connection (TCP alive, no data — common behind proxies/LBs) hung until
the OS idle timeout (~60s), freezing the client. Add a ping/watchdog:
send {"type":"__ping"} every 5s and force ws.reconnect() if nothing arrives
for 12s, cutting detection from ~60s to seconds. __pong acks are swallowed.
Pairs with the handler shim answering __ping so idle handlers stay proven.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
12s was too long for interactive apps (a frozen game). Realtime handlers push frequently, so ~2-3s of total silence reliably means a dead socket. Recover in ≤3s instead of ≤12s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
subscribe() now returns { id, unsubscribe } instead of a bare unsubscribe fn,
and accepts options.id to control the connection id (stable across
reconnects/tabs if supplied, else auto-generated per connection). id matches
the handler's conn.id, so clients can identify themselves without a server
your_id message.
BREAKING: subscribe() now returns RealtimeSubscription ({ id, unsubscribe() })
instead of a bare () => void; call sub.unsubscribe() instead of the old sub().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
Add protected tickIntervalMs + optional shouldTick() so handlers get types for the platform-managed tick loop (implemented in the deployed shim). Opting in means no more startLoop/stopLoop bookkeeping in the handler. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Sorry, something went wrong.
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Clean, well-documented iteration. The room-handle API reads nicely, the type registry (ActorRegistry / ActorNameRegistry) is a great DX touch, and src/actor.ts is a tidy type-only base. Below are the remaining items — the top one is the same functional risk flagged in prior passes. 🟠 Design / lifecycle1. No cleanup wiring for actor rooms — the main functional risk — src/client.ts:231-236 // actors.ts
export function createActorsModule(config: ActorsConfig) {
const rooms = new Set<Room>();
const module = new Proxy(/* ... */ {
get(_, actorName: string) {
if (typeof actorName !== "string") return undefined; // see #4
return (instanceId: string) => {
const room = new Room(actorName, instanceId, config);
rooms.add(room); // and remove on close()
return room as unknown as ActorRoom;
};
},
});
// attach closeAll() for client.cleanup() to call
}2. send() can throw before the socket is OPEN — src/modules/actors.ts:113-118 3. Heartbeat is aggressive — src/modules/actors.ts:21-22 🟡 Minor4. Proxy get returns a factory for every key — src/modules/actors.ts:132-135 5. close() leaves connId stale — src/modules/actors.ts:120-128 6. crypto.randomUUID() vs uuidv4() — src/modules/actors.ts:47 🔒 SecurityNothing concerning. The token rides the WS query and is re-read on each (re)connect via the query() closure (actors.ts:56-64) so login/logout is picked up; anonymous connects correctly omit it (covered by test at actors.test.ts:110). Precedence token || getAccessToken() (client.ts:229) matches the functions module — good. 🧪 Test coverageSolid baseline in tests/unit/actors.test.ts — Proxy dispatch, idempotent connect, throw-before-connect, multi-listener + per-listener unsubscribe, __pong swallowing, send serialization, close teardown, anonymous connect, per-id independence. Gaps worth adding:
Blocker I'd flag: cleanup wiring (#1) — a forgotten close() leaks a 1s timer permanently. Everything else is polish/optional. Nice work overall. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Clean, well-documented feature. The room-handle API reads nicely, the type registry (ActorRegistry / ActorNameRegistry) is a great DX touch, and src/actor.ts is a tidy type-only base. Below are the remaining items — the top one is the same functional risk flagged across prior passes and is still unaddressed. 🟠 Design / lifecycle1. No cleanup wiring for actor rooms — the main functional risk — src/client.ts:231-236 + actors.ts:130-136 export function createActorsModule(config: ActorsConfig) {
const rooms = new Set<Room>();
const module = new Proxy({} as Record<string, (instanceId: string) => ActorRoom>, {
get(_, actorName: string) {
if (typeof actorName !== "string") return undefined; // see #4
return (instanceId: string) => {
const room = new Room(actorName, instanceId, config, () => rooms.delete(room));
rooms.add(room);
return room as unknown as ActorRoom;
};
},
});
return Object.assign(module, { closeAll: () => { for (const r of rooms) r.close(); rooms.clear(); } });
}…then call userModules.actors.closeAll() inside cleanup(). (serviceRoleModules has no actors module, so it's fine there.) 2. send() can throw before the socket is OPEN — src/modules/actors.ts:112-117 3. Heartbeat is aggressive — src/modules/actors.ts:21-22 🟡 Minor4. Proxy get returns a factory for every key — src/modules/actors.ts:132-134 5. close() leaves connId stale — src/modules/actors.ts:119-127 6. crypto.randomUUID() vs uuidv4() — src/modules/actors.ts:47 🔒 SecurityNothing concerning. The token rides the WS query and is re-read on each (re)connect via the query() closure (actors.ts:56-64) so login/logout is picked up; anonymous connects correctly omit it (covered by test at actors.test.ts:110). Precedence token || getAccessToken() (client.ts:229) matches the functions module — good. 🧪 Test coverageSolid baseline in tests/unit/actors.test.ts — Proxy dispatch, idempotent connect, throw-before-connect, multi-listener + per-listener unsubscribe, __pong swallowing, send serialization, close teardown, anonymous connect, per-id independence. Gaps worth adding:
Blocker I'd flag: cleanup wiring (#1) — a forgotten close() leaks a 1s timer permanently, and the module keeps no handle to reclaim it. Everything else is polish/optional. Nice work overall. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Clean, well-documented feature. The room-handle API reads nicely, the type registry (ActorRegistry / ActorNameRegistry) is a great DX touch, and src/actor.ts is a tidy type-only base. The code is unchanged since the last pass, so the same items remain — #1 is still the one functional risk worth resolving before merge. 🟠 Design / lifecycle1. No cleanup wiring for actor rooms — the main functional risk — src/client.ts:229-234 + actors.ts:130-136 export function createActorsModule(config: ActorsConfig) {
const rooms = new Set<Room>();
const module = new Proxy({} as Record<string, (instanceId: string) => ActorRoom>, {
get(_, actorName: string) {
if (typeof actorName !== "string") return undefined; // see #4
return (instanceId: string) => {
const room = new Room(actorName, instanceId, config, () => rooms.delete(room));
rooms.add(room);
return room as unknown as ActorRoom;
};
},
});
return Object.assign(module, {
closeAll: () => { for (const r of rooms) r.close(); rooms.clear(); },
});
}…then call userModules.actors.closeAll() inside cleanup(). (serviceRoleModules has no actors module, so it's fine there.) 2. send() can throw before the socket is OPEN — src/modules/actors.ts:112-117 3. Heartbeat is aggressive — src/modules/actors.ts:21-22 🟡 Minor4. Proxy get returns a factory for every key — src/modules/actors.ts:132-134 5. close() leaves connId stale — src/modules/actors.ts:119-127 6. crypto.randomUUID() vs uuidv4() — src/modules/actors.ts:47 🔒 SecurityNothing concerning. The token rides the WS query and is re-read on each (re)connect via the query() closure (actors.ts:56-64) so login/logout is picked up; anonymous connects correctly omit it (test at actors.test.ts:110). Precedence token || getAccessToken() (client.ts:227) matches the functions module — good. 🧪 Test coverageSolid baseline in tests/unit/actors.test.ts — Proxy dispatch, idempotent connect, throw-before-connect, multi-listener + per-listener unsubscribe, __pong swallowing, send serialization, close teardown, anonymous connect, per-id independence. Gaps worth adding:
Blocker I'd flag: cleanup wiring (#1) — a forgotten close() leaks a 1s timer permanently, and the module keeps no handle to reclaim it. Everything else is polish/optional. Nice work overall. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
createActorsModule now tracks live rooms per client and exposes closeAll(), which client.cleanup() invokes — a forgotten room.close() no longer leaks its 1s heartbeat timer (which also keeps the Node event loop alive). The Proxy get trap consults the target first so closeAll resolves instead of being read as an actor name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The get trap returned a room factory for `then`, so awaiting base44.actors (or passing it through a Promise chain) called the factory as a thenable and hung. Resolve `then` (and inherited/symbol keys) normally so the module isn't mistaken for a Promise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
close() left connId set, so room.id returned a stale id between close and the next connect(). Null it in close() — reading id after close now throws the same connect()-first guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks — walked all six:
Test coverage: closeAll now covered. Remaining gaps (heartbeat timing, functionsVersion -> fv, resolvedActorsWsUrl derivation) are noted — will add. |
Sorry, something went wrong.
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Thanks for walking all six — I re-read the current tree and can confirm the fixes landed cleanly. This is in good shape to merge. 🟢 Verified fixes since last pass
🟡 Minor (non-blocking, optional)1. closeAll() clears the Set only via each room's onClose — actors.ts:138-140 2. reconnect() after close() — actors.ts:85-98 🧪 Test coverageStrong baseline in tests/unit/actors.test.ts — Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, anonymous connect, per-id independence, not-thenable, and both closeAll paths. As you noted, the still-open gaps are:
None of these block merge. Verdict: the one functional blocker from prior passes (cleanup wiring) is now fixed and tested. Remaining items are optional polish. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
createActorsModule returns { module, closeAll } instead of bolting closeAll onto
the Proxy. The Proxy now only maps names to room factories (2-condition guard),
and closeAll is a plain internal function client.cleanup() calls — dropping the
api object, Object.assign, the intersection cast, and the key-in-target branch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. All prior blockers are resolved and the code reads cleanly. This is in good shape to merge — remaining notes are optional polish. 🟢 Verified fixes from prior passes
🟡 Minor (non-blocking, optional)1. send()/connect() doc vs. behavior — actors.types.ts:73 2. Heartbeat cost — actors.ts:21-22 3. crypto.randomUUID() vs uuidv4() — actors.ts:48 🔒 SecurityNothing concerning. The token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:57-64), so login/logout is picked up; anonymous connects omit it (test at actors.test.ts:120). Precedence token || getAccessToken() (client.ts:190) matches the functions module. 🧪 Test coverageStrong baseline in tests/unit/actors.test.ts — Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, not-thenable, and both closeAll paths. Gaps still worth adding (none block merge):
Verdict: No blockers. The one functional risk from earlier passes (cleanup leak) is fixed and tested. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
- Extract resolveActorsWsUrl into a pure exported helper (client.ts calls it) and unit-test its precedence + protocol/trailing-slash normalization. - Add heartbeat tests (fake timers): __ping every PING_MS, reconnect after DEAD_MS of silence; and functionsVersion -> fv present/omitted. - Soften the send() doc: buffered "once connecting" (matches PartySocket). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. This has come a long way — all prior blockers are resolved, and the new commits since the last pass (resolveActorsWsUrl now exported + tested, heartbeat timing test, fv present/absent test) close most of the outstanding gaps I flagged. This is in good shape to merge. Only optional polish remains. 🟢 Verified since last pass
🟡 Minor (non-blocking, optional)1. send() doc vs. immediate-send behavior — actors.types.ts:73 2. resolveActorsWsUrl protocol replace is anchored, appBaseUrl isn't validated — actors.ts:145-150 3. Heartbeat cost — actors.ts:21-22 4. crypto.randomUUID() vs uuidv4() — actors.ts:48 🔒 SecurityNothing concerning. The token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:57-65), so login/logout is picked up; anonymous connects omit it (test at actors.test.ts:120). Precedence token || getAccessToken() (client.ts:182) matches the functions module. Note the same subtle stale-token-closure applies here as elsewhere — after setToken(), the initial token const won't update, but getAccessToken() reads storage so the effective token stays correct. Consistent with the existing modules. 🧪 Test coverageStrong — tests/unit/actors.test.ts now covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsWsUrl derivation. Essentially all previously-noted gaps are closed. Only nice-to-have left: a close()→connect() re-open cycle mints a fresh socket (currently connect() is guarded by if (this.ws), and close() nulls ws, so a re-open path exists but isn't directly asserted). Verdict: No blockers. Every functional risk from prior passes is fixed and tested; the remaining items are polish/optional. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
…on code serverUrl is the app's own origin, and PartySocket already strips the scheme, strips a trailing slash, and picks wss (ws for localhost) from the host. So the resolveActorsWsUrl helper, the actorsWsUrl client option, and the browserOrigin/appBaseUrl derivation were all redundant — pass serverUrl straight through as PartySocket's host. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. The recent commits simplified things nicely: serverUrl is now passed straight through as PartySocket's host (PartySocket swaps the scheme itself), dropping the old resolveActorsWsUrl derivation and the actorsWsUrl client option entirely. All prior functional blockers remain resolved. No blockers here — only notes below. 🟢 State of prior items
🟠 Notes on the serverUrl refactor1. PR body is now stale. The description still mentions actorsWsUrl (defaulting to app origin → wss://) and dispatcherWsUrl, but the code now just forwards serverUrl as PartySocket's host. Worth updating the description so reviewers/future readers aren't misled. Also note resolveActorsWsUrl and its dedicated derivation tests are gone — the old actors.test.ts URL-derivation assertions no longer exist since the logic moved into PartySocket. 2. serverUrl semantics changed. Previously the socket was same-origin via an app-proxied /parties; now it connects to config.serverUrl (the Base44 backend, e.g. https://base44.app). Just confirming this is intentional and that the backend serves /parties directly for the SDK's use case (the doc comment at actors.ts:16-18 still says "the app proxies /parties", which reads slightly at odds with passing serverUrl rather than the app origin). Minor doc reconciliation. 🟡 Minor (non-blocking, optional — carried over)3. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. You validated the realistic path — phrasing is reasonable. 4. Heartbeat cost — actors.ts:23-24 (PING_MS=1s/DEAD_MS=3s, one ping/sec per room). Accepted per the server-side setWebSocketAutoResponse mitigation. Fine for interactive actors. 5. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:122). Precedence token || getAccessToken() (client.ts:171) matches the functions module. 🧪 Test coverageStrong — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, and both closeAll paths. One coverage change to flag: the previous resolveActorsWsUrl derivation tests were removed along with the function. Since host is now passed verbatim, that's reasonable — the one remaining assertion is opts.host === serverUrl (:56), which is sufficient given PartySocket owns the scheme swap. A close()→connect() re-open cycle is still the only untested path. Verdict: No blockers. The serverUrl simplification is clean and well-tested. Main ask is refreshing the PR description (and the actors.ts:16-18 comment) to match the new serverUrl-passthrough behavior. Nice work. 👍 |
Sorry, something went wrong.
Actors deployed by the bundler now expose an anonymous Base44 client as this.client. Mirror it on the type-only Actor base class (throw-stub like storage/instanceId) so actor authors get it typed as Base44Client; the runtime value is provided by the bundler shim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. The two new commits since the last pass — e75ce02 (pass serverUrl straight through as PartySocket's host, dropping the URL-derivation code) and 9717c67 (type-only this.client getter on Actor) — are clean. All prior functional blockers remain resolved. No blockers; notes below are polish/doc reconciliation. 🟢 State of prior items
🟠 Doc / naming reconciliation (from the serverUrl refactor)1. PR body is now stale. The description still mentions the actorsWsUrl client option (defaulting to app origin → wss://) and a dispatcherWsUrl, but the code now just forwards config.serverUrl as PartySocket's host — no such option or derivation exists anymore. Worth refreshing the description so future readers aren't misled. 2. serverUrl doc comment reads at odds with the passthrough. actors.ts:16-18 still says "The app's own origin … the socket is same-origin (the app proxies /parties)." But the value now passed is config.serverUrl (defaults to https://base44.app, i.e. the Base44 backend — client.ts:67,169), not the app origin. If the backend serves /parties directly this is fine, but the comment should be reconciled with the new source of the value. Minor. 🟡 Minor (non-blocking, optional — carried over)3. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. You validated the realistic buffering path — phrasing is reasonable. 4. Heartbeat cost — actors.ts:23-24 (PING_MS=1s/DEAD_MS=3s, one ping/sec per room). Accepted per the server-side setWebSocketAutoResponse mitigation (edge answers __ping→__pong without waking the DO, so idle rooms hibernate). Fine for interactive actors. 5. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. 6. Duplicate blank lines in actor.ts — :13-14, :39-40, :113-114. Trivial cosmetic; drop if your formatter flags it. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:122). Precedence token || getAccessToken() (client.ts:171) matches the functions module. createClientFromRequest continues to forward only the closed X-Data-Env set (client.ts:460) — good. 🧪 Test coverageStrong — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, and both closeAll paths. Coverage note tied to the refactor: the old resolveActorsWsUrl derivation tests were removed with the function (reasonable — host is now passed verbatim; the one assertion opts.host === serverUrl at :56 suffices since PartySocket owns the scheme swap). Only remaining untested path is a close()→connect() re-open cycle minting a fresh socket. Verdict: No blockers. The serverUrl simplification is clean and well-tested. Main ask is refreshing the PR description and the actors.ts:16-18 comment to match the new serverUrl-passthrough behavior. Nice work. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
…he socket serverUrl is often "" (same-origin apps use a relative /api), and PartySocket can't resolve a relative host — it builds a hostless wss:///parties/... So add resolveActorsHost: use serverUrl when absolute, else fall back to the browser origin. PartySocket still owns the scheme swap and trailing-slash strip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. The recent commits are clean: resolveActorsHost now resolves an empty/relative serverUrl to the page origin and hands it to PartySocket as host (PartySocket owns the scheme swap), and Actor gained a type-only client getter. All prior functional blockers remain resolved. No blockers — notes below are polish/doc reconciliation. 🟢 State of prior items
🟠 Small correctness note1. resolveActorsHost only treats a leading / as relative — actors.ts:141-143 🟠 Doc / naming reconciliation (carried over)2. PR body is stale. The description still mentions the actorsWsUrl option (defaulting to app origin → wss://) and a dispatcherWsUrl derivation — neither exists anymore; the code forwards a resolved host to PartySocket. Worth refreshing so future readers aren't misled. 3. Comment vs. value source — client.ts:169-170 / actors.ts:16-18. Comments read "same-origin app / the app proxies /parties," but the value now defaults to config.serverUrl (https://base44.app) unless it's empty/relative, in which case it falls back to the page origin. If the backend serves /parties directly, fine — just reconcile the wording with the actual resolveActorsHost precedence (serverUrl-wins-when-absolute). 🟡 Minor (non-blocking, optional — carried over)4. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. You validated the realistic buffering path — phrasing is reasonable. 5. Heartbeat cost — actors.ts:23-24 (PING_MS=1s / DEAD_MS=3s, one ping/sec per room). Accepted per the server-side setWebSocketAutoResponse mitigation (edge answers __ping→__pong without waking the DO, so idle rooms hibernate). Fine for interactive actors. 6. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. Keeping native is defensible. 7. Duplicate blank lines in actor.ts — :13-14, :39-40, :113-114. Trivial cosmetic; drop if your formatter flags them. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:122). Precedence token || getAccessToken() (client.ts:176) matches the functions module. Parsed inbound messages are JSON with a try/catch guard (actors.ts:77-81) and __pong frames are swallowed — no unsafe eval or trust of message shape. 🧪 Test coverageStrong — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsHost derivation. Only remaining untested path is a close()→connect() re-open cycle minting a fresh socket (the if (this.ws) guard + close() nulling ws makes this reachable but it isn't directly asserted). Verdict: No blockers. The serverUrl-resolution refactor is clean and well-tested. Main ask remains refreshing the PR description and the actors.ts:16-18 / client.ts:169-170 comments to match the resolveActorsHost behavior. Nice work. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. The code is clean and all prior functional blockers remain resolved. The recent commits (resolveActorsHost resolving empty/relative serverUrl to the page origin, the type-only this.client getter, and the blank-line cleanup in actor.ts) all landed cleanly. No blockers — notes below are polish/doc reconciliation. 🟢 State of prior items (all verified resolved)
🟠 Small correctness note (carried over)1. resolveActorsHost only treats a leading / as relative — actors.ts:141-143 🟠 Doc / naming reconciliation (carried over — still worth doing)2. PR body is stale. The description still mentions the actorsWsUrl option (defaulting to app origin → wss://) and a dispatcherWsUrl derivation — neither exists anymore; the code forwards a resolved host to PartySocket via resolveActorsHost. Worth refreshing so future readers aren't misled. 3. Comment vs. value source — client.ts:169-170 / actors.ts:16-18. The comments still read "same-origin app / the app proxies /parties," but the value now defaults to config.serverUrl (https://base44.app) when absolute, only falling back to the page origin when empty/relative. If the backend serves /parties directly this is fine — just reconcile the wording with the actual resolveActorsHost precedence. 🟡 Minor (non-blocking, optional — carried over)4. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. You validated the realistic buffering path — phrasing is reasonable. 5. Heartbeat cost — actors.ts:23-24 (PING_MS=1s / DEAD_MS=3s, one ping/sec per room). Accepted per the server-side setWebSocketAutoResponse mitigation (edge answers __ping→__pong without waking the DO, so idle rooms hibernate). Fine for interactive actors. 6. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. Keeping native is defensible. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:122). Precedence token || getAccessToken() (client.ts:176) matches the functions module. Inbound messages are JSON-parsed inside a try/catch (actors.ts:77-81) with __pong frames swallowed — no unsafe eval or trust of message shape. 🧪 Test coverageStrong — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsHost derivation. The only untested path is a close()→connect() re-open cycle minting a fresh socket (if (this.ws) guard + close() nulling ws makes it reachable but it isn't directly asserted). Not a blocker. Verdict: No blockers. Every functional risk from prior passes is fixed and tested; the remaining items are polish/optional. The main ask remains refreshing the PR description and the actors.ts:16-18 / client.ts:169-170 comments to match the resolveActorsHost behavior. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
Closes the last coverage note from review — the close()->connect() re-open path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. This is clean and ready to merge — every functional blocker from the prior passes is resolved and tested. Notes below are polish/doc reconciliation only. 🟢 State of prior items (all verified resolved)
🟠 Small correctness note (carried over)1. resolveActorsHost only treats a leading / as relative — actors.ts:141-142 🟠 Doc / naming reconciliation (carried over — still worth doing)2. PR body is stale. The description still mentions resolveActorsHost(serverUrl, window?.location?.origin) — that part matches, but earlier phrasing and prior descriptions referenced actorsWsUrl/dispatcherWsUrl which no longer exist. Worth a final skim of the description so it matches the resolveActorsHost passthrough exactly. 3. Comment vs. value source — client.ts:169-170 / actors.ts:16-18. The comments read "same-origin app / the app proxies /parties," but the resolved value is config.serverUrl when absolute (defaults to the Base44 backend), only falling back to the page origin when empty/relative. If the backend serves /parties directly this is fine — just reconcile the wording with the actual resolveActorsHost precedence. 🟡 Minor (non-blocking, optional — carried over)4. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. You validated the realistic buffering path — phrasing is reasonable. 5. Heartbeat cost — actors.ts:23-24 (PING_MS=1s / DEAD_MS=3s, one ping/sec per room). Accepted per the server-side setWebSocketAutoResponse mitigation (edge answers __ping→__pong without waking the DO, so idle rooms hibernate). Fine for interactive actors. 6. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. Keeping native is defensible. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:132). Precedence token || getAccessToken() (client.ts:176) matches the functions module. Inbound messages are JSON-parsed inside a try/catch (actors.ts:77-81) with __pong frames swallowed — no unsafe eval or trust of message shape. 🧪 Test coverageStrong and complete — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, close()→connect() re-open, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsHost derivation. No meaningful gaps remain. Verdict: No blockers. The one functional risk from earlier passes (cleanup leak) is fixed and tested, and the previously-open coverage gaps are now closed. Remaining items are optional polish — mainly reconciling the PR description and the actors.ts:16-18 / client.ts:169-170 comments with the resolveActorsHost behavior. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
An actor runs server-side with no per-connection identity, so a Test DB preview selected in the editor doesn't apply to this.client — it's an anonymous, prod-scoped client (logged-out-visitor semantics). Document the limitation for actor authors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (room-handle API)
Re-reviewed the current tree. The code is clean and every functional blocker from prior passes is resolved and tested. Below I address @netanelgilad's inline naming question, then the remaining polish items. 💬 Re: @netanelgilad's question — "shouldn't we call this Actor?" (actors.ts:26)I'd argue Room is the more accurate name here — and renaming it to Actor would actually be confusing given the rest of the codebase:
Suggestion: keep Room (or rename to ActorRoom to mirror the public interface), but not Actor — that name belongs to the server-side base class in actor.ts. 🟢 State of prior items (all verified resolved)
🟡 Minor (non-blocking, optional — carried over)1. resolveActorsHost only treats a leading / as relative — actors.ts:141-142. A scheme-less host ("api.example.com", protocol-relative "//host") is treated as absolute and passed verbatim to PartySocket. Fine given callers pass https://… or ""//api; just flagging the bare-host edge. 2. Doc/naming reconciliation — client.ts:169-170 / actors.ts:16-18 still describe "same-origin app / the app proxies /parties," but the resolved value is config.serverUrl when absolute, only falling back to the page origin when empty/relative. Worth reconciling the wording with the actual resolveActorsHost precedence. 3. send() doc vs. immediate-send — actors.types.ts:73 says a send is "buffered by the socket once connecting." Accurate once PartySocket's internal socket exists; a room.connect().send(...) in the same synchronous tick can still hit ws.send before construction. Realistic path is fine — phrasing is reasonable. 4. crypto.randomUUID() vs uuidv4() — actors.ts:50. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. Keeping native is defensible. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:59-67), so login/logout is picked up; anonymous connects omit it (actors.test.ts:132). Precedence token || getAccessToken() (client.ts:176) matches the functions module. Inbound messages are JSON-parsed inside a try/catch (actors.ts:77-81) with __pong frames swallowed — no unsafe eval or trust of message shape. 🧪 Test coverageStrong and complete — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, throw-before-connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, id-clearing, close()→connect() re-open, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsHost derivation. No meaningful gaps remain. Verdict: No blockers. On the inline question — I'd keep Room (or ActorRoom) rather than Actor, since Actor is the server-side base class in actor.ts and this class models a single room, not the actor type. Everything else is optional polish. Nice work. 👍 |
Sorry, something went wrong.
actors.X(id) now returns an ActorRef whose only method is connect(); connect()
returns a Connection with { id, subscribe, send, close }. subscribe/send are only
reachable from a live Connection, so the "connect() before subscribe/send" guards
are gone (invalid state is unrepresentable). Renames the Room handle away entirely
(ActorRoom -> Connection + ActorRef). Chained usage
(actors.X(id).connect().subscribe(...)) is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @ImriKochWix's task —— View job PR Review: Actors namespace (connect → Connection API)
Re-reviewed the current tree. The API has been refactored since the last pass into a cleaner two-step model: actors.MyActor(id) returns an ActorRef, and ref.connect() returns a Connection (subscribe/send/close). This directly answers @netanelgilad's inline question — see below. All prior functional blockers remain resolved. No blockers. 💬 Re: @netanelgilad — "shouldn't we call this Actor?" (actors.ts)The current naming already resolves this well, and I'd keep it as-is rather than rename to Actor:
So the trio ActorRef → Connection reads cleanly and avoids the Actor collision. I'd leave it. 🟢 State of prior items (all verified resolved)
🟡 Minor (non-blocking, optional)1. send() doc vs. immediate-send — actors.types.ts:70 says a send is "Buffered by the socket until it's open." Since a Connection is only obtainable after connect() constructs the PartySocket (:48), the internal socket always exists by the time you hold a Connection, so PartySocket's buffering does cover the realistic path here — the refactor actually made this doc more accurate than before. 👍 No change needed. 2. resolveActorsHost only treats a leading / as relative — actors.ts:148-150. A scheme-less host ("api.example.com", protocol-relative "//host") is treated as absolute and passed verbatim to PartySocket. Fine given callers pass https://… or ""//api; just flagging the bare-host edge. 3. Heartbeat cost — actors.ts:24-25 (PING_MS=1s / DEAD_MS=3s, one ping/sec per connection). Accepted per the server-side setWebSocketAutoResponse mitigation (edge answers __ping→__pong without waking the DO). Fine for interactive actors. 4. crypto.randomUUID() vs uuidv4() — actors.ts:46. Fine on the Node ≥22 baseline; purely a consistency nit with utils/axios-client.ts. Keeping native is defensible. 5. Duplicate blank lines in actor.ts — :13, :29, :37 regions. Trivial cosmetic; drop if your formatter flags them. 🔒 SecurityNothing concerning. Token rides the WS query and is re-read on every (re)connect via the query() closure (actors.ts:54-62), so login/logout is picked up; anonymous connects omit it (actors.test.ts:119). Precedence token || getAccessToken() (client.ts:176) matches the functions module. Inbound messages are JSON-parsed inside a try/catch (actors.ts:72-76) with __pong frames swallowed — no unsafe eval or trust of message shape. 🧪 Test coverageStrong and complete — tests/unit/actors.test.ts covers Proxy dispatch, idempotent connect, multi-listener/unsubscribe, __pong swallowing, send serialization, close teardown, close()→connect() re-open with fresh id, anonymous connect, per-id independence, fv present/absent, heartbeat ping+reconnect, not-thenable, both closeAll paths, and full resolveActorsHost derivation. No meaningful gaps remain. One small note: the docs elsewhere still describe the older subscribe-throws-before-connect model, but the code no longer has a pre-connect state (you only get a Connection post-connect()), so there's nothing to test there — the refactor removed that failure mode entirely. Clean. Verdict: No blockers. The ActorRef → Connection refactor is a nice simplification — it eliminates the pre-connect guard state and makes the naming question moot (Connection ≠ the server-side Actor base). Remaining items are optional polish. Nice work getting this over the line. 👍 View job • feat/realtime-handler |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
PR B of 3 for the Actor feature — the client SDK surface.
Depends on
PR A deployed to preview (the app-origin /parties proxy + Dispatcher WS handling must be live).
🤖 Generated with Claude Code