feat(actor): add actor command and scaffolding - #555
Draft
ImriKochWix wants to merge 17 commits into
Draft
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/cli@0.1.6-pr.555.eaa386dPrefer not to change any import paths? Install using npm alias so your code still imports npm i "base44@npm:@base44-preview/cli@0.1.6-pr.555.eaa386d"Or add it to your {
"dependencies": {
"base44": "npm:@base44-preview/cli@0.1.6-pr.555.eaa386d"
}
}
Preview published to npm registry — try new features instantly! |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
new.ts used project.root but readAllRealtimeHandlers uses dirname(configPath), causing handlers to be created at realtime/ instead of base44/realtime/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'base44' is the CLI package name and has no exported types. @base44/sdk now exports RealtimeHandler and Conn for type-checking, and the bundler rewrites the import to the CF shim at deploy time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- base44 types generate now includes realtime handlers in types.d.ts - RealtimeHandlerNameRegistry: auto-registers handler names (no manual declare needed) - RealtimeHandlerRegistry: compiled from schema.jsonc inbound/outbound JSON schemas - Add schema.jsonc support to realtime-handler resource reader - Update test fixture with ChatRoom schema and assertions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Detect @base44/sdk vs @base44-preview/sdk from project's package.json
so declare module targets the correct package name
- Add export {} to generated types.d.ts to ensure module context,
preventing ambient module from shadowing the SDK package types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused RealtimeHandlerConfig type alias - Replace [^]* regex with [\s\S]* (Biome noEmptyCharacterClassInRegex) - Auto-format long lines per Biome formatter rules Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The dedicated endpoint calls ensure_cfw_backend and uses force_per_function so the bundler runs applyRealtimeCompat instead of the per-app path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
schema.jsonc is now a catalog of named messages (inbound/outbound maps of
message-name -> full JSON Schema, like entities) plus optional shared `types`.
compileRealtimeHandler emits one named interface per message (direction- and
handler-prefixed to avoid collisions) + shared types, and composes the
inbound/outbound unions in the registry.
Removes the /\{([\s\S]*)\}/ body-scrape, which produced invalid TS whenever
json-schema-to-typescript emitted more than one declaration (unions with
$defs). Because every message is a single flat object, that multi-declaration
case can no longer arise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lient/toServer The old names were written from the client's perspective, so handler code read backwards (InMsg = Reg["outbound"]) and every reader had to do the double-negative. toClient/toServer read correctly from both sides: Reg["toServer"] is what the handler receives, Reg["toClient"] is what it sends. Generated interface prefixes follow (GameRoomToClientInit). Breaking for schema.jsonc files and the generated registry shape; done now while there are zero external users. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename the Durable-Object abstraction and its CLI surface to the actor model:
- command group `base44 realtime <cmd>` -> `base44 actor <cmd>`
- resource dir src/core/resources/realtime-handler/ -> resources/actor/;
commands/realtime/ -> commands/actor/
- project config key realtimeDir("realtime") -> actorsDir("actors");
ProjectData.realtimeHandlers -> actors
- project directory convention base44/realtime/<Name>/ -> base44/actors/<Name>/
(resource discovery + generated actor message types)
- builder deploy route PUT realtime-handlers/<name> -> PUT actors/<name>
- scaffold template emits `import { Actor } ... extends Actor`
The entity live-update Socket.IO dev-server (dev-server/realtime.ts,
createRealtimeServer) is intentionally left as "realtime" — it's the
entity-change feature, not the Actor DO.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Biome organizeImports across the files touched by the actor rename (import order shifted when realtime-handler paths became actor paths). - preview-publish + manual-publish: pin npm@11; npm@latest is now 12.x which requires node >=22 and fails EBADENGINE on the node-20 runner (.node-version). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Actors now import their base class from the bundler-served virtual module `base44:runtime/actors` instead of `@base44/sdk`. Emit a matching ambient declaration into the generated types.d.ts (when the app has actors) that re-exports Actor / Conn / ActorRegistry from the SDK package, so the import typechecks in the editor and ActorRegistry keeps its app-specific augmentation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pure types (Conn, ActorRegistry) have no runtime and ActorRegistry is
augmented onto the SDK, so they belong in @base44/sdk, not the bundler-served
runtime virtual module. The declare module now re-exports only Actor — the one
value whose runtime the bundler swaps. Authoring: `import { Actor } from
"base44:runtime/actors"` + `import type { Conn, ActorRegistry } from "@base44/sdk"`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Actor base class is the one value the bundler swaps at deploy/dev, so it comes from the base44:runtime/actors virtual module; pure types (Conn) come from the SDK. Matches the taught authoring shape and the type-gen declare module. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e44:runtime/actors import resolves Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Description
Adds actors as a first-class Base44 resource: stateful, long-lived server objects (prototyped earlier in this branch as "realtime handlers") that live in
base44/actors/<ActorName>/entry.ts. The PR introduces a newbase44 actorcommand group (new,deploy), wires actors into project config reading, unifiedbase44 deploy, and TypeScript type generation. Actors can declare aschema.jsoncmessage catalog (types/toClient/toServer), which is compiled into a discriminated-unionActorRegistryso client and server message handling is fully typed.Related Issue
None
Type of Change
npm@11in the publish workflowsChanges Made
New actor resource (
src/core/resources/actor/)schema.ts— Zod schemas for the actor config, theschema.jsoncmessage catalog (types/toClient/toServer), and the deploy response (deployed|unchanged)config.ts— discovers**/entry.{js,ts}under the actors dir, derives the actor name from its subfolder, loads the optionalschema.jsonc, and rejects duplicate names or anentry.tsplaced directly in the actors rootapi.ts—PUT actors/:namewith the entry file plus all sibling.tsfiles, Zod-validated response,ApiError.fromHttpError()on failuredeploy.ts— sequential per-actor deploy withonStart/onResultcallbacks and per-actor timing; failures are captured per actor rather than aborting the runresource.ts— standardResource<Actor>(readAll/push) so actors join the unified resource pipelineCLI commands (
src/cli/commands/actor/)base44 actor new <ActorName>— scaffoldsbase44/actors/<ActorName>/entry.tswith a typedActor<State, Message>subclass that importsActorfrom the virtualbase44:runtime/actorsmodule andConnas a pure type from the SDK, then re-reads the project and regeneratesbase44/.types/types.d.ts(plusupdateProjectConfig) so that import resolves in the editor immediatelybase44 actor deploy [names...]— deploys all actors or a comma/space-separated subset, prints per-actor status plus a summary, and exits1viaCLIExitErrorif any actor failsactorcommand group inprogram.tsProject integration
actorsDir(default"actors") toProjectConfigSchema, andactorstoProjectData/ProjectResourcesreadProjectConfig()now reads actors in parallel with the other resources; plugin projects get an empty actor listhasResourcesToDeploy(), thebase44 deploysummary, anddeployAll()all account for actorsbase44 types generatepasses actors through to the generatorType generation (
src/core/types/generator.ts)ActorNameRegistryandActorRegistryaugmentations; each actor's message catalog compiles in a singlejson-schema-to-typescriptpass into one named interface per message (direction-prefixed) plus sharedtypes, with thetypediscriminant injected from the message key and#/types/Xrefs rewritten to prefixed$defsTypeGenerationErroron generated-name collisions instead of silently clobberingdeclare module 'base44:runtime/actors're-exporting only theActorbase class (pure types keep coming from the SDK)@base44/sdkvs@base44-preview/sdkfrom the projectpackage.json, and addsexport {};so the generated file is a module anddeclare moduleaugments rather than replaces the SDK typesCI
npm@11inmanual-publish.ymlandpreview-publish.yml—npm@latestis now 12.x, which requires Node >= 22 and failsEBADENGINEon the Node 20 runnerTesting
npm test)Checklist
docs/(AGENTS.md) if I made architectural changesAdditional Notes
tests/core/types-actor.spec.tscover catalog compilation (discriminant injection, shared-type reuse, registry union assembly, thebase44:runtime/actorsdeclaration) and the name-collision error.tests/cli/types_generate.spec.tswas extended with actor registry assertions plus a newChatRoomfixture (entry.ts+schema.jsonc). The suite was not run while generating this description, so the "tested locally" / "all tests pass" boxes are left unchecked.docs/resources.md,docs/commands.md, and the README don't mention the new resource or thebase44 actorcommands — worth adding before merge, per rule 9 ("Keep docs updated").actor newreads the project config twice (once for paths, once after writing the scaffold) so type generation picks up the new actor.realtime-handler/RealtimeHandler; it was renamed toactor/Actorlater in the branch, andtoClient/toServerreplaced an earlierinbound/outboundpair. Only the final naming ships.🤖 Generated by Claude | 2026-07-28 11:16 UTC | eaa386d