Skip to content

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

Merged
yurynix merged 2 commits into
mainfrom
feat/dev3-versions-declare-actors
Oct 19, 2026
Merged

yurynix merged 2 commits into
mainfrom
feat/dev3-versions-declare-actors

Conversation

@yurynix

@yurynix yurynix commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Note

Description

Extends the versions lane so that publishing an app records its actors alongside its frontend assets, backend bundles, entities and agents. A new compileActors step compiles every actor under base44/actors/<Name>/entry.ts into its own Durable Object Worker module via the functions-compiler's single-function bundle(), declares it in the create-version call, and stages its bytes at actors/<name>.mjs. Until now a version described an app with actors as if it had none, so the platform would drop them.

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, compiles each one separately (concurrency 4), and returns an ActorArtifact per actor with its name, entry, source as written, module bytes, size, sha256 digest and the STATIC_EGRESS_ARTIFACT_MARKER contract. Actors are sorted by name so declared order — and therefore each upload slot — never follows a filesystem walk.
  • Compiler input scoping — an actor's bundle sees only the files its entry reaches within its own folder plus base44/shared/**, keyed where the compiler looks; a reach into another actor or a backend function stays unresolved and fails the compile. An entry.js is keyed as entry.ts, since that path is how the compiler recognizes an actor (hence bundle() directly rather than cfwBundleInput, which would flatten a no-import entry to main.ts).
  • Failure handling — one actor that fails to compile fails the whole publish at step build, before anything is declared; more than 50 actors is refused up front with InvalidInputError to match the server ceiling. The module is also sanity-checked against do_class_name so a plain Worker is never deployed under an actor's identity.
  • core/version/api.ts — declares actors in the create-version body (always sent, [] when the app has none), appends actor upload slots after the asset, site-worker and bundle slots so adding actors moves no existing slot, verifies each signed slot path matches actors/<name>.mjs, and uploads each module with putPresignedBody.
  • core/version/schema.ts — adds the ActorArtifact interface and actors to ArtifactSet.
  • core/version/functions.ts — exports requireCompilerRuntime (now parameterized so the message reads "Actors…" or "Backend functions…"), describeFailure and sha256 for reuse.
  • core/project/target.ts — BuildTarget resolves actorsDir (default actors).
  • core/version/artifacts.ts — collects actors during the build step.
  • Docs — new "Actors are compiled here too" section in docs/versions.md, updated declare/slot-order description and keywords.
  • Tests — new tests/core/version-actors.spec.ts (entry keying, shared-module reach, scope isolation, deterministic digests, set-wide failure, the 50-actor cap) and a new publish suite covering declaration shape, per-actor upload slots, slot ordering alongside bundles, the empty-actors case, compile failure, and the standalone binary refusing an app with actors. TestAPIServer signs actor slots; the with-actors fixture gained a base44/shared/limits.ts import so the shared path is exercised end to end, and the actor publish specs pin DENO_DIR for the npm cache (Windows @deno/loader compatibility).

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

The whole lane stays behind the BASE44_VERSIONS_API env gate. 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 at step build rather than silently publishing without them — both the npm-mode and binary-mode specs assert nothing is declared in that case.


🤖 Generated by Claude | 2026-10-19 06:48 UTC | 9dd49bd

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

github-actions Bot commented Oct 15, 2026 •

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.9dd49bd

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.9dd49bd"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.1.32-pr.665.9dd49bd"
  }
}

Preview published to npm registry — try new features instantly!

On Windows @deno/loader caches npm packages under USERPROFILE while the
compiler allows file reads only under LOCALAPPDATA. The testkit moves
USERPROFILE to a temp dir for auth isolation, so every actor compile on
windows-latest/npm failed with "filesystem imports are not allowed".
DENO_DIR is honoured by both, as in production.

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

carmelc commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

One thing I did not understand is how is the cli supposed to work in a fullstack app given that it looks for the backend functions in the base44/functions folder

@yurynix
yurynix merged commit 30e2bad into main Oct 19, 2026
15 checks passed
@yurynix
yurynix deleted the feat/dev3-versions-declare-actors branch October 19, 2026 08:31
@yurynix

yurynix commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Backend functions can exist also on fullstack app 🙃

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.

2 participants