Skip to content

feat(version): compile and declare actors on every version - #665

Open
yurynix wants to merge 1 commit into
mainfrom
feat/dev3-versions-declare-actors
Open

yurynix wants to merge 1 commit into
mainfrom
feat/dev3-versions-declare-actors

Conversation

@yurynix

@yurynix yurynix commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Note

Description

Teaches the version lane to compile and declare an app's actors alongside its backend functions, so a recorded version describes the Durable Object side of the app too. A new core/version/actors.ts compiles each actor into a module of its own with the functions-compiler, declares it with its name, entry, source and digest, and stages its module at actors/<name>.mjs after every other upload slot. The actors field is always sent — [] for an app with none — because an absent field is what a pre-actors CLI sends and the platform rejects that for an app that has actors.

Related Issue

None

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

  • core/version/actors.ts (new) — compileActors() reads every actor under the actors dir, compiles each one separately via the compiler's single-function bundle() (concurrency 4), and returns an ActorArtifact per actor: name, entry, source as written, module bytes, size, sha256 digest, and the STATIC_EGRESS_ARTIFACT_MARKER contract. Actors are sorted by name so upload slots never follow a filesystem walk.
  • Compiler input shaped like apper's — the entry is always keyed base44/actors/<Name>/entry.ts (an entry.js included, since that path is what marks an entry as an actor), with the actor's own folder plus base44/shared/** as the reachable set. Deliberately bypasses cfwBundleInput, which would flatten a leaf entry to main.ts. A reach into another actor or a function stays unresolved and fails the compile.
  • Guards — refuses more than 50 actors (the server ceiling) before compiling any; one actor that fails to compile fails the whole publish at step build; InternalError if the compiler does not report a Durable Object class matching the actor's name.
  • core/version/api.ts — declares actors in the create-version POST, computes the actor slot offset after assets + Worker modules + backend bundles, verifies the server signed each actor slot at the expected actors/<name>.mjs path, and uploads each module with putPresignedBody.
  • core/version/schema.ts — new ActorArtifact interface and a required actors field on ArtifactSet.
  • core/version/artifacts.ts — collects actors under the existing build step tag.
  • core/version/functions.ts — exports requireCompilerRuntime() (now parameterized with what is being compiled, for the DEPENDENCY_NOT_FOUND message), describeFailure() and sha256() for reuse.
  • core/project/target.ts — BuildTarget gains actorsDir, defaulting to actors.
  • Docs — new "Actors are compiled here too" section in docs/versions.md, plus updated declare/upload ordering and keywords.
  • Tests — new tests/core/version-actors.spec.ts (8 cases: empty set without loading the compiler, per-actor modules, entry.js keyed as entry.ts, shared-module reach, no cross-actor reach, deterministic bytes, whole-set failure, the 50-actor cap) and 6 new publish integration cases (declaration shape, per-slot uploads, actors staged after bundles, actors: [] for an app with none, build-step compile failure, and the standalone binary refusing an app with actors). TestAPIServer now signs actor slots; the with-actors fixture gains a base44/shared/limits.ts the ChatRoom entry imports.

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

Actors are appended last in the declared-slot order (assets → Worker modules → backend bundles → actors), so an app gaining actors moves no slot the other kinds already had. Like backend functions, actor compilation needs the external esbuild / @deno/loader runtime packages, so the standalone binary refuses an app with actors with DEPENDENCY_NOT_FOUND before declaring anything. The whole lane stays behind the BASE44_VERSIONS_API env gate.


🤖 Generated by Claude | 2026-10-15 10:41 UTC | 1a74073

The versions lane now compiles each actor into a module of its own and
declares `actors` on every version, `[]` for an app with none. An absent
field is what a CLI from before actors sends, and the platform refuses it
(409 actors_undeclared) for an app that has them.

- Each actor compiles with the compiler's single-function bundle(), keyed
  base44/actors/<Name>/entry.ts (an entry.js too), over the files its
  entry reaches among its own folder and base44/shared — as apper
  assembles one. Not cfwBundleInput: its flat main.ts loses the path that
  makes the entry an actor.
- Declared as name, entry, source, module {size, digest} and static_egress
  (the compiler's STATIC_EGRESS_ARTIFACT_MARKER, installed by the actor
  prelude). Sorted by name.
- Upload slots come after the bundles', each at actors/<Name>.mjs, which
  the client checks the server signed.
- BuildTarget.actorsDir; at most 50 actors, refused before compiling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.1.32-pr.665.1a74073

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.1.32-pr.665.1a74073"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.1.32-pr.665.1a74073"
  }
}

Preview published to npm registry — try new features instantly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant