@base44-preview/cli 0.1.32-pr.664.89779c9 → 0.1.32-pr.665.1a74073

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -228838,7 +228838,7 @@ function normalizeBase44Env() {
228838
228838
  loadProjectEnvFiles();
228839
228839
 
228840
228840
  // src/cli/index.ts
228841
- import { dirname as dirname29, join as join40 } from "node:path";
228841
+ import { dirname as dirname30, join as join40 } from "node:path";
228842
228842
  import { fileURLToPath as fileURLToPath7 } from "node:url";
228843
228843
 
228844
228844
  // ../../node_modules/@clack/core/dist/index.mjs
@@ -246963,7 +246963,8 @@ async function resolveBuildTarget(projectRoot, overrides = {}) {
246963
246963
  outputDir: resolve6(root, overrides.outputDir ?? site.outputDirectory ?? DEFAULT_SITE.outputDirectory),
246964
246964
  entitiesDir: project?.entitiesDir ?? "entities",
246965
246965
  agentsDir: project?.agentsDir ?? "agents",
246966
- functionsDir: project?.functionsDir ?? "functions"
246966
+ functionsDir: project?.functionsDir ?? "functions",
246967
+ actorsDir: project?.actorsDir ?? "actors"
246967
246968
  };
246968
246969
  }
246969
246970
  async function readSettingsIfPresent(projectRoot) {
@@ -250792,6 +250793,25 @@ function declaredBundle({
250792
250793
  }
250793
250794
  };
250794
250795
  }
250796
+ function declaredActor({
250797
+ name,
250798
+ entry,
250799
+ source,
250800
+ size,
250801
+ digest,
250802
+ staticEgress
250803
+ }) {
250804
+ return {
250805
+ name,
250806
+ entry,
250807
+ source,
250808
+ module: { size, digest },
250809
+ static_egress: staticEgress
250810
+ };
250811
+ }
250812
+ function actorUploadPath(actor) {
250813
+ return `actors/${actor.name}.mjs`;
250814
+ }
250795
250815
  function declaredServingConfig(config) {
250796
250816
  const stated = {
250797
250817
  html_handling: config?.htmlHandling ?? null,
@@ -250846,6 +250866,7 @@ async function createVersion(artifacts, options = {}) {
250846
250866
  }
250847
250867
  } : {},
250848
250868
  backend_bundles: artifacts.backendBundles.map(declaredBundle),
250869
+ actors: artifacts.actors.map(declaredActor),
250849
250870
  entities: artifacts.entities,
250850
250871
  agents: artifacts.agents,
250851
250872
  source_commit: options.sourceCommit
@@ -250854,7 +250875,8 @@ async function createVersion(artifacts, options = {}) {
250854
250875
  ...artifacts.assets,
250855
250876
  ...artifacts.siteWorker?.modules ?? []
250856
250877
  ];
250857
- const slotCount = declaredFiles.length + artifacts.backendBundles.length;
250878
+ const actorsAt = declaredFiles.length + artifacts.backendBundles.length;
250879
+ const slotCount = actorsAt + artifacts.actors.length;
250858
250880
  options.progress?.onDeclared?.({ fileCount: slotCount });
250859
250881
  if (declared.uploads.length !== slotCount) {
250860
250882
  throw new InternalError(`Declared ${slotCount} files but the server signed ${declared.uploads.length} upload URLs.`);
@@ -250863,12 +250885,18 @@ async function createVersion(artifacts, options = {}) {
250863
250885
  if (drifted !== -1) {
250864
250886
  throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
250865
250887
  }
250888
+ const actorDrifted = artifacts.actors.findIndex((actor, index) => declared.uploads[actorsAt + index].path !== actorUploadPath(actor));
250889
+ if (actorDrifted !== -1) {
250890
+ throw new InternalError(`Upload ${actorsAt + actorDrifted} is signed for ${declared.uploads[actorsAt + actorDrifted].path}, but that slot declared the actor ${artifacts.actors[actorDrifted].name}.`);
250891
+ }
250866
250892
  let uploadedFiles = 0;
250867
250893
  await pMap(declared.uploads, async (upload, index) => {
250868
250894
  if (index < declaredFiles.length) {
250869
250895
  await putPresigned(upload, declaredFiles[index].absolutePath);
250870
- } else {
250896
+ } else if (index < actorsAt) {
250871
250897
  await putPresignedBody(upload, artifacts.backendBundles[index - declaredFiles.length].module);
250898
+ } else {
250899
+ await putPresignedBody(upload, artifacts.actors[index - actorsAt].module);
250872
250900
  }
250873
250901
  uploadedFiles++;
250874
250902
  options.progress?.onUpload?.({
@@ -250886,11 +250914,10 @@ async function setEnvironmentVersion(environment, versionId, options = {}) {
250886
250914
  }
250887
250915
  // src/core/version/artifacts.ts
250888
250916
  import { createHash as createHash3 } from "node:crypto";
250889
- import { join as join29, resolve as resolve13 } from "node:path";
250917
+ import { join as join29, resolve as resolve14 } from "node:path";
250890
250918
 
250891
- // src/core/version/functions.ts
250892
- import { createHash as createHash2 } from "node:crypto";
250893
- import { relative as relative6 } from "node:path";
250919
+ // src/core/version/actors.ts
250920
+ import { dirname as dirname22, relative as relative7, resolve as resolve13 } from "node:path";
250894
250921
 
250895
250922
  // ../functions-compiler/src/assembly.ts
250896
250923
  import path17 from "node:path";
@@ -256424,6 +256451,18 @@ function consolePatch(runtimeSecrets) {
256424
256451
  return runtimeSecrets ? `${CONSOLE_PATCH}
256425
256452
  ${RUNTIME_SECRETS_RESERVED_PATCH}` : CONSOLE_PATCH;
256426
256453
  }
256454
+ async function prepareFunction(entry, files, postResponseTelemetry = false, runtimeSecrets = false) {
256455
+ assertNoReservedFilenames(files);
256456
+ return {
256457
+ entry: ENTRY_FILENAME,
256458
+ files: {
256459
+ ...userFiles(files),
256460
+ ...workerRuntimeFiles(),
256461
+ ...runtimeSecrets ? { [ACTIVATION_FILENAME]: activationShimSource() } : {},
256462
+ [ENTRY_FILENAME]: buildEntrySource(entry, postResponseTelemetry, runtimeSecrets)
256463
+ }
256464
+ };
256465
+ }
256427
256466
  var BANNER_FORMAT = 1;
256428
256467
  function buildBanner(entries, telemetry, runtimeSecrets) {
256429
256468
  return `//!b44:${BANNER_FORMAT} ${JSON.stringify({
@@ -256467,6 +256506,50 @@ function activationImport(runtimeSecrets) {
256467
256506
  return runtimeSecrets ? `
256468
256507
  import { ensureActivation, takeActivationChallenge, withoutActivationHeaders } from "./${ACTIVATION_FILENAME}";` : "";
256469
256508
  }
256509
+ function buildEntrySource(userEntry, telemetry, runtimeSecrets = false) {
256510
+ const userImport = `./${userEntry.replace(/^\.\//, "")}`;
256511
+ const handlerExpr = telemetry ? "_b44AttachTelemetry(await handler(request, info))" : runtimeSecrets ? "await handler(request, info)" : "handler(request, info)";
256512
+ const guard = activationGuard(runtimeSecrets);
256513
+ const returnExpr = guard(handlerExpr);
256514
+ return `// Auto-generated by the base44 bundler. Do not edit.
256515
+
256516
+ import { currentWorkerRuntimeContext as _b44Context, runWithWorkerEnvironment as _b44Run } from ${JSON.stringify(RUNTIME_CONTEXT_SPECIFIER)};
256517
+ import { getRegisteredHandler, installStaticEgressFetch } from "./${SHIM_FILENAME}";${activationImport(runtimeSecrets)}
256518
+
256519
+ ${consolePatch(runtimeSecrets)}
256520
+ // Static egress reads workerEnv from the active request store. Install it
256521
+ // before telemetry so telemetry remains the outermost fetch wrapper.
256522
+ installStaticEgressFetch();
256523
+ ${telemetry ? TELEMETRY_PATCH : ""}
256524
+
256525
+ let _b44Init = null;
256526
+ export default {
256527
+ async fetch(request, env, ctx) {
256528
+ ${runtimeSecrets ? ACTIVATION_TAKE : ""} const _b44Env = (request.headers.get('base44-functions-version') ?? '') === 'prod' ? 'prod' : 'preview';
256529
+ return _b44Run({ env: _b44Env, secrets: ${runtimeSecrets ? "process.env" : "env"}, workerEnv: env, waitUntil: (p) => ctx.waitUntil(p)${telemetry ? `, ${TELEMETRY_STORE_FIELDS}` : ""} }, async () => {
256530
+ ${runtimeSecrets ? ACTIVATION_GATE : ""} if (!_b44Init) _b44Init = import(${JSON.stringify(userImport)}).catch(e => { _b44Init = null; throw e; });
256531
+ const _b44Mod = await _b44Init;
256532
+ // Deno.serve capture wins (legacy contract, zero behavior change);
256533
+ // a default-exported handler is the new-contract fallback.
256534
+ const handler = getRegisteredHandler() ?? (typeof _b44Mod?.default === 'function' ? _b44Mod.default : null);
256535
+ if (!handler) {
256536
+ return ${guard(`new Response(
256537
+ "The function must export default a request handler or call Deno.serve()",
256538
+ { status: 503 },
256539
+ )`)};
256540
+ }
256541
+ // Deno's handler signature is (request, info). Cloudflare doesn't expose a
256542
+ // connection address the same way; pass a best-effort placeholder. Real
256543
+ // client IP is available via the "cf-connecting-ip" request header.
256544
+ const info = {
256545
+ remoteAddr: { transport: "tcp", hostname: "0.0.0.0", port: 0 },
256546
+ };
256547
+ return ${returnExpr};
256548
+ });
256549
+ },
256550
+ };
256551
+ `;
256552
+ }
256470
256553
  function buildFunctionModuleSource(functionName, userEntry) {
256471
256554
  const userImport = `./${userEntry.replace(/^\.\//, "")}`;
256472
256555
  return `// Auto-generated by the base44 bundler. Do not edit.
@@ -256769,6 +256852,284 @@ function runtimeContextVirtualPlugin() {
256769
256852
  };
256770
256853
  }
256771
256854
 
256855
+ // ../functions-compiler/src/actor-compat.ts
256856
+ var ACTOR_ENTRY_FILENAME2 = "__base44_actor_entry.mjs";
256857
+ var ACTOR_PRELUDE_FILENAME = "__base44_actor_prelude.mjs";
256858
+ var ACTOR_AUTH_FILENAME = "__base44_actor_auth.mjs";
256859
+ var ACTORS_PREFIX = "base44/actors/";
256860
+ var ENTRY_SUFFIX = "/entry.ts";
256861
+ function actorNameFromEntry(entry) {
256862
+ if (!entry.startsWith(ACTORS_PREFIX) || !entry.endsWith(ENTRY_SUFFIX))
256863
+ return null;
256864
+ const name = entry.slice(ACTORS_PREFIX.length, -ENTRY_SUFFIX.length);
256865
+ return name && !name.includes("/") ? name : null;
256866
+ }
256867
+ function applyActorCompat(entry, files) {
256868
+ const actorName = actorNameFromEntry(entry);
256869
+ if (!actorName || files[entry] === undefined)
256870
+ return null;
256871
+ assertNoReservedFilenames(files);
256872
+ if (ACTOR_PRELUDE_FILENAME in files) {
256873
+ throw new Error(`Reserved filename "${ACTOR_PRELUDE_FILENAME}" in actor bundle — ` + "it is generated by the bundler. Rename the file.");
256874
+ }
256875
+ if (ACTOR_AUTH_FILENAME in files) {
256876
+ throw new Error(`Reserved filename "${ACTOR_AUTH_FILENAME}" in actor bundle — ` + "it is generated by the bundler. Rename the file.");
256877
+ }
256878
+ const handlerName = actorName;
256879
+ const doClassName = handlerName;
256880
+ const prelude = buildPrelude();
256881
+ const entryWrapper = buildEntryWrapper(doClassName, entry);
256882
+ return {
256883
+ entry: ACTOR_ENTRY_FILENAME2,
256884
+ files: {
256885
+ ...files,
256886
+ ...workerRuntimeFiles(),
256887
+ [ACTOR_AUTH_FILENAME]: buildActorAuth(),
256888
+ [ACTOR_PRELUDE_FILENAME]: prelude,
256889
+ [ACTOR_ENTRY_FILENAME2]: entryWrapper
256890
+ },
256891
+ handlerName,
256892
+ doClassName
256893
+ };
256894
+ }
256895
+ function buildActorAuth() {
256896
+ return `// Auto-generated by the base44 bundler. Do not edit.
256897
+ const TOKEN_HEADER = "X-Base44-Actor-Token";
256898
+ const IDENTITY_HEADER = "X-Base44-Actor-Identity";
256899
+ const CLOCK_SKEW_SECONDS = 30;
256900
+ const TOKEN_TTL_SECONDS = 300;
256901
+
256902
+ const decodeSegment = (segment) => {
256903
+ const normalized = segment.replace(/-/g, "+").replace(/_/g, "/");
256904
+ const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
256905
+ const binary = atob(padded);
256906
+ return new Uint8Array([...binary].map((character) => character.charCodeAt(0)));
256907
+ };
256908
+
256909
+ const decodeJsonSegment = (segment) =>
256910
+ JSON.parse(new TextDecoder().decode(decodeSegment(segment)));
256911
+
256912
+ const unauthorized = () => ({
256913
+ ok: false,
256914
+ response: new Response("Unauthorized", { status: 401 }),
256915
+ });
256916
+
256917
+ const validPrincipal = (principal) => {
256918
+ if (principal === null || typeof principal !== "object" || Array.isArray(principal)) return false;
256919
+ if (principal.type === "authenticated") {
256920
+ return typeof principal.userId === "string" && principal.userId.length > 0 && principal.userId.length <= 128;
256921
+ }
256922
+ if (principal.type === "anonymous") {
256923
+ return typeof principal.anonymousId === "string" && principal.anonymousId.length > 0 && principal.anonymousId.length <= 128;
256924
+ }
256925
+ return false;
256926
+ };
256927
+
256928
+ export async function verifyActorConnection(request, env, actorName, room) {
256929
+ const publicKey = env.BASE44_ACTOR_PUBLIC_KEY;
256930
+ const scriptId = env.BASE44_ACTOR_SCRIPT_ID;
256931
+ const token = request.headers.get(TOKEN_HEADER) ?? new URL(request.url).searchParams.get("token");
256932
+ if (
256933
+ typeof publicKey !== "string" || !publicKey ||
256934
+ typeof scriptId !== "string" || !scriptId ||
256935
+ typeof token !== "string" || token.length > 4096
256936
+ ) return unauthorized();
256937
+
256938
+ const parts = token.split(".");
256939
+ if (parts.length !== 3) return unauthorized();
256940
+ try {
256941
+ const header = decodeJsonSegment(parts[0]);
256942
+ const claims = decodeJsonSegment(parts[1]);
256943
+ if (header?.alg !== "EdDSA" || (header.typ !== undefined && header.typ !== "JWT")) {
256944
+ return unauthorized();
256945
+ }
256946
+ const key = await crypto.subtle.importKey(
256947
+ "raw",
256948
+ decodeSegment(publicKey),
256949
+ { name: "Ed25519" },
256950
+ false,
256951
+ ["verify"],
256952
+ );
256953
+ const validSignature = await crypto.subtle.verify(
256954
+ { name: "Ed25519" },
256955
+ key,
256956
+ decodeSegment(parts[2]),
256957
+ new TextEncoder().encode(parts[0] + "." + parts[1]),
256958
+ );
256959
+ if (!validSignature) return unauthorized();
256960
+
256961
+ const now = Math.floor(Date.now() / 1000);
256962
+ const times = [claims.iat, claims.nbf, claims.exp];
256963
+ if (!times.every(Number.isInteger)) return unauthorized();
256964
+ if (
256965
+ claims.iss !== "base44" ||
256966
+ claims.aud !== "base44-actor-connect" ||
256967
+ claims.purpose !== "actor-connect" ||
256968
+ claims.v !== 1 ||
256969
+ typeof claims.jti !== "string" || !claims.jti || claims.jti.length > 64 ||
256970
+ claims.iat > now + CLOCK_SKEW_SECONDS ||
256971
+ claims.nbf > now + CLOCK_SKEW_SECONDS ||
256972
+ claims.exp < now - CLOCK_SKEW_SECONDS ||
256973
+ claims.exp <= claims.iat || claims.exp - claims.iat > TOKEN_TTL_SECONDS ||
256974
+ claims.app_id !== env.BASE44_APP_ID ||
256975
+ claims.actor_name !== actorName ||
256976
+ claims.actor_script_id !== scriptId ||
256977
+ claims.room !== room ||
256978
+ claims.connection_id !== new URL(request.url).searchParams.get("_pk") ||
256979
+ claims.runtime_mode !== (env.BASE44_FUNCTIONS_VERSION === "prod" ? "prod" : "preview") ||
256980
+ !validPrincipal(claims.principal)
256981
+ ) return unauthorized();
256982
+
256983
+ return {
256984
+ ok: true,
256985
+ identity: Object.freeze({ ...claims.principal }),
256986
+ runtimeMode: claims.runtime_mode,
256987
+ };
256988
+ } catch {
256989
+ return unauthorized();
256990
+ }
256991
+ }
256992
+
256993
+ export function authorizedActorRequest(request, identity, actorName, room, runtimeMode) {
256994
+ const url = new URL(request.url);
256995
+ url.searchParams.delete("token");
256996
+ url.pathname = "/parties/" + encodeURIComponent(actorName) + "/" + encodeURIComponent(room);
256997
+ const headers = new Headers(request.headers);
256998
+ headers.delete(TOKEN_HEADER);
256999
+ headers.set(IDENTITY_HEADER, JSON.stringify(identity));
257000
+ headers.set("base44-functions-version", runtimeMode === "prod" ? "prod" : "preview");
257001
+ return new Request(new Request(url.toString(), request), { headers });
257002
+ }
257003
+ `;
257004
+ }
257005
+ function buildPrelude() {
257006
+ return `// Auto-generated by the base44 bundler. Do not edit.
257007
+ import { currentWorkerRuntimeContext as _b44Context } from ${JSON.stringify(RUNTIME_CONTEXT_SPECIFIER)};
257008
+ import { installStaticEgressFetch } from "./${SHIM_FILENAME}";
257009
+
257010
+ ${CONSOLE_PATCH}
257011
+ installStaticEgressFetch();
257012
+ `;
257013
+ }
257014
+ function buildEntryWrapper(doClassName, userEntry) {
257015
+ const userImport = `./${userEntry.replace(/^\.\//, "")}`;
257016
+ return `// Auto-generated by the base44 bundler. Do not edit.
257017
+ // The prelude is intentionally the first dependency: it installs the fetch
257018
+ // shim before the user module evaluates while this static default import keeps
257019
+ // missing-default actors as bundle-time errors.
257020
+ import "./${ACTOR_PRELUDE_FILENAME}";
257021
+ import Base44UserActor from ${JSON.stringify(userImport)};
257022
+ import { runWithWorkerEnvironment as _b44Run } from ${JSON.stringify(RUNTIME_CONTEXT_SPECIFIER)};
257023
+ import { authorizedActorRequest as _b44AuthorizedActorRequest, verifyActorConnection as _b44VerifyActorConnection } from "./${ACTOR_AUTH_FILENAME}";
257024
+
257025
+ const _b44ActorState = new WeakMap();
257026
+ const _b44RunWithActorEnvironment = (ctx, env, runtimeEnv, callback) => _b44Run({
257027
+ env: runtimeEnv,
257028
+ secrets: env,
257029
+ workerEnv: env,
257030
+ waitUntil: (promise) => ctx.waitUntil(promise),
257031
+ }, callback);
257032
+ const _b44ConstructActor = (ctx, env, newTarget) => _b44RunWithActorEnvironment(
257033
+ ctx,
257034
+ env,
257035
+ "prod",
257036
+ () => {
257037
+ // A derived constructor may return an explicitly constructed instance.
257038
+ // This keeps the user's constructor and class-field initializers inside the
257039
+ // request-scoped Worker environment without changing the exported subclass.
257040
+ const actor = Reflect.construct(Base44UserActor, [ctx, env], newTarget);
257041
+ _b44ActorState.set(actor, { ctx, env, runtimeEnv: null });
257042
+ return actor;
257043
+ },
257044
+ );
257045
+ const _b44RunActor = (actor, request, callback) => {
257046
+ const state = _b44ActorState.get(actor);
257047
+ const runtimeEnv = request
257048
+ ? ((request.headers.get("base44-functions-version") ?? "") === "prod" ? "prod" : "preview")
257049
+ : (state.runtimeEnv ?? "prod");
257050
+ state.runtimeEnv = runtimeEnv;
257051
+ return _b44RunWithActorEnvironment(state.ctx, state.env, runtimeEnv, callback);
257052
+ };
257053
+
257054
+ export class ${doClassName} extends Base44UserActor {
257055
+ // Read by the shim's service-token exchange: the assertion's actor_name claim
257056
+ // selects the verification key on the platform side. A static (not .name) so
257057
+ // minification can't change it.
257058
+ static _b44ActorName = ${JSON.stringify(doClassName)};
257059
+
257060
+ constructor(ctx, env) {
257061
+ return _b44ConstructActor(ctx, env, new.target);
257062
+ }
257063
+
257064
+ fetch(request) {
257065
+ return _b44RunActor(this, request, () => super.fetch(request));
257066
+ }
257067
+
257068
+ onConnect(...args) {
257069
+ return _b44RunActor(this, null, () => super.onConnect(...args));
257070
+ }
257071
+
257072
+ onMessage(...args) {
257073
+ return _b44RunActor(this, null, () => super.onMessage(...args));
257074
+ }
257075
+
257076
+ onClose(...args) {
257077
+ return _b44RunActor(this, null, () => super.onClose(...args));
257078
+ }
257079
+
257080
+ onAlarm(...args) {
257081
+ return _b44RunActor(this, null, () => super.onAlarm(...args));
257082
+ }
257083
+
257084
+ onStart(...args) {
257085
+ return _b44RunActor(this, null, () => super.onStart(...args));
257086
+ }
257087
+
257088
+ onError(...args) {
257089
+ return _b44RunActor(this, null, () => super.onError(...args));
257090
+ }
257091
+ }
257092
+ export default {
257093
+ async fetch(request, env, ctx) {
257094
+ const url = new URL(request.url);
257095
+ const parts = url.pathname.split("/");
257096
+ const direct = parts[1] === "rooms" && parts.length === 3;
257097
+ const legacy = parts[1] === "parties" && parts.length === 4;
257098
+ if (direct || legacy) {
257099
+ // Decode the room: the token was verified against the decoded instance id,
257100
+ // so an escaped room must map to the same Durable Object.
257101
+ const namespace = direct ? "${doClassName}" : parts[2];
257102
+ const encodedRoom = direct ? parts[2] : parts[3];
257103
+ let room;
257104
+ try { room = decodeURIComponent(encodedRoom); } catch { return new Response("Invalid room", { status: 400 }); }
257105
+ let actorRequest = request;
257106
+ if (direct || typeof env.BASE44_ACTOR_PUBLIC_KEY === "string") {
257107
+ const verification = await _b44VerifyActorConnection(request, env, "${doClassName}", room);
257108
+ if (!verification.ok) return verification.response;
257109
+ actorRequest = _b44AuthorizedActorRequest(
257110
+ request,
257111
+ verification.identity,
257112
+ "${doClassName}",
257113
+ room,
257114
+ verification.runtimeMode,
257115
+ );
257116
+ }
257117
+ const doNs = env["${doClassName}"];
257118
+ if (doNs && typeof doNs.idFromName === "function") {
257119
+ const stub = doNs.get(doNs.idFromName(room));
257120
+ const req = new Request(actorRequest);
257121
+ req.headers.set("x-partykit-room", room);
257122
+ req.headers.set("x-partykit-namespace", namespace);
257123
+ return stub.fetch(req);
257124
+ }
257125
+ return new Response("DO binding not found", { status: 503 });
257126
+ }
257127
+ return new Response("Not found", { status: 404 });
257128
+ },
257129
+ };
257130
+ `;
257131
+ }
257132
+
256772
257133
  // ../../node_modules/zod/v3/helpers/util.js
256773
257134
  var util;
256774
257135
  (function(util) {
@@ -261003,6 +261364,7 @@ var WS_SPECIFIER = /^(npm:)?ws(@[^/]+)?$/;
261003
261364
  var ADAPTER = `"use strict";
261004
261365
  const toBuffer = (value) => (globalThis.Buffer ? globalThis.Buffer.from(value) : value);
261005
261366
  const READY_STATES = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
261367
+ const later = (fn, ...args) => queueMicrotask(() => fn(...args));
261006
261368
  const upgradeHeaders = (options) => {
261007
261369
  const headers = new Headers(options?.headers);
261008
261370
  for (const name of headers.keys()) if (name !== "user-agent") return headers;
@@ -261017,6 +261379,7 @@ class WebSocket {
261017
261379
  #state = 0;
261018
261380
  #url;
261019
261381
  #closeRequested = null;
261382
+ #terminated = false;
261020
261383
  #listeners = new Map();
261021
261384
  constructor(address, protocols, options) {
261022
261385
  if (protocols && typeof protocols === "object" && !Array.isArray(protocols)) {
@@ -261031,7 +261394,10 @@ class WebSocket {
261031
261394
  this.#attach(new globalThis.WebSocket(this.#url, protocols));
261032
261395
  }
261033
261396
  }
261034
- get readyState() { return this.#socket ? this.#socket.readyState : this.#state; }
261397
+ get readyState() {
261398
+ if (this.#terminated) return 3;
261399
+ return this.#socket ? this.#socket.readyState : this.#state;
261400
+ }
261035
261401
  get url() { return this.#url; }
261036
261402
  get protocol() { return this.#socket ? this.#socket.protocol ?? "" : ""; }
261037
261403
  on(name, listener) { return this.#add(name, listener, false); }
@@ -261075,7 +261441,20 @@ class WebSocket {
261075
261441
  this.#state = 2;
261076
261442
  }
261077
261443
  }
261078
- terminate() { this.close(); }
261444
+ // \`ws\` tears the connection down at once. workerd has no abrupt close, so the
261445
+ // socket is closed normally and "close" is reported now, not on the reply.
261446
+ terminate() {
261447
+ if (this.#terminated || this.readyState === 3) return;
261448
+ this.#terminated = true;
261449
+ if (this.#socket) {
261450
+ try { this.#socket.close(); } catch {}
261451
+ } else {
261452
+ // Upgrade still in flight: close it on arrival, without an "open".
261453
+ this.#closeRequested = [];
261454
+ this.#state = 3;
261455
+ }
261456
+ later(() => this.emit("close", 1006, toBuffer("")));
261457
+ }
261079
261458
  #attach(socket) {
261080
261459
  this.#socket = socket;
261081
261460
  try { socket.binaryType = "arraybuffer"; } catch {}
@@ -261085,7 +261464,9 @@ class WebSocket {
261085
261464
  this.emit("message", toBuffer(isBinary ? new Uint8Array(event.data) : event.data), isBinary);
261086
261465
  });
261087
261466
  socket.addEventListener("error", (event) => this.emit("error", event.error ?? new Error(event.message || "WebSocket error")));
261088
- socket.addEventListener("close", (event) => this.emit("close", event.code, toBuffer(event.reason ?? "")));
261467
+ socket.addEventListener("close", (event) => {
261468
+ if (!this.#terminated) this.emit("close", event.code, toBuffer(event.reason ?? ""));
261469
+ });
261089
261470
  }
261090
261471
  #upgrade(headers, protocols) {
261091
261472
  headers.set("Upgrade", "websocket");
@@ -261093,6 +261474,7 @@ class WebSocket {
261093
261474
  const httpUrl = this.#url.replace(/^ws(s?):/i, "http$1:");
261094
261475
  const fail = (error) => {
261095
261476
  this.#state = 3;
261477
+ if (this.#terminated) return;
261096
261478
  this.emit("error", error);
261097
261479
  this.emit("close", 1006, toBuffer(""));
261098
261480
  };
@@ -261252,6 +261634,51 @@ function setSpanTags(tags) {
261252
261634
  // ../functions-compiler/src/bundler.ts
261253
261635
  var NORMALIZED_MAIN_MODULE = "_bundled.mjs";
261254
261636
  var MAX_PARALLEL_COMPILES = 4;
261637
+ async function bundle(req) {
261638
+ let actor;
261639
+ try {
261640
+ actor = applyActorCompat(req.entry, req.files);
261641
+ } catch (e) {
261642
+ return denoCompatErrorOrThrow(e);
261643
+ }
261644
+ if (actor) {
261645
+ if (req.runtimeSecrets) {
261646
+ return denoCompatErrorOrThrow(new DenoCompatError("runtimeSecrets is not supported for Actor entries: an Actor reads secrets " + "from its Durable Object env, so it must be deployed in binding mode."));
261647
+ }
261648
+ const outcome = await installAndCompile({
261649
+ entry: actor.entry,
261650
+ files: actor.files
261651
+ });
261652
+ if (outcome.ok) {
261653
+ return {
261654
+ ok: true,
261655
+ module: outcome.module,
261656
+ main_module: NORMALIZED_MAIN_MODULE,
261657
+ warnings: outcome.warnings,
261658
+ handler_name: actor.handlerName,
261659
+ do_class_name: actor.doClassName
261660
+ };
261661
+ }
261662
+ return { ok: false, stage: outcome.stage, errors: outcome.errors };
261663
+ }
261664
+ let prepared;
261665
+ try {
261666
+ prepared = await prepareFunction(req.entry, req.files, req.postResponseTelemetry, req.runtimeSecrets);
261667
+ } catch (e) {
261668
+ return denoCompatErrorOrThrow(e);
261669
+ }
261670
+ const outcome = await installAndCompile(prepared);
261671
+ if (outcome.ok) {
261672
+ return {
261673
+ ok: true,
261674
+ module: outcome.module,
261675
+ main_module: NORMALIZED_MAIN_MODULE,
261676
+ warnings: outcome.warnings,
261677
+ ...activationField(req.runtimeSecrets ?? false)
261678
+ };
261679
+ }
261680
+ return { ok: false, stage: outcome.stage, errors: outcome.errors };
261681
+ }
261255
261682
  function activationField(runtimeSecrets) {
261256
261683
  return runtimeSecrets ? { activation: ACTIVATION_MODE } : {};
261257
261684
  }
@@ -261439,6 +261866,16 @@ async function installAndCompile(prepared) {
261439
261866
  return { ok: false, stage: "esbuild", errors: result.errors };
261440
261867
  });
261441
261868
  }
261869
+ function denoCompatErrorOrThrow(e) {
261870
+ if (e instanceof DenoCompatError) {
261871
+ return {
261872
+ ok: false,
261873
+ stage: "deno_compat",
261874
+ errors: [denoCompatErrorItem(e)]
261875
+ };
261876
+ }
261877
+ throw e;
261878
+ }
261442
261879
  function denoCompatErrorItem(e) {
261443
261880
  return { message: e.message, file: e.file };
261444
261881
  }
@@ -261641,6 +262078,8 @@ async function mapWithConcurrency2(items, limit, fn) {
261641
262078
  return results;
261642
262079
  }
261643
262080
  // src/core/version/functions.ts
262081
+ import { createHash as createHash2 } from "node:crypto";
262082
+ import { relative as relative6 } from "node:path";
261644
262083
  var SHARD_POLICY = {
261645
262084
  shardSize: 100,
261646
262085
  globalShardSize: 100,
@@ -261648,11 +262087,11 @@ var SHARD_POLICY = {
261648
262087
  gzipCapBytes: 9500000
261649
262088
  };
261650
262089
  var COMPILE_MODES = { runtimeSecrets: false, postResponseTelemetry: false };
261651
- async function requireCompilerRuntime() {
262090
+ async function requireCompilerRuntime(what = "Backend functions") {
261652
262091
  try {
261653
262092
  await Promise.all([import("esbuild"), import("@deno/loader")]);
261654
262093
  } catch (error) {
261655
- throw new DependencyNotFoundError("Backend functions cannot be compiled by this installation of the CLI.", {
262094
+ throw new DependencyNotFoundError(`${what} cannot be compiled by this installation of the CLI.`, {
261656
262095
  hints: [{ message: "Install the CLI from npm: npm install -g base44" }],
261657
262096
  cause: error instanceof Error ? error : undefined
261658
262097
  });
@@ -261709,6 +262148,97 @@ async function compileBackendBundles(root, functionsDir) {
261709
262148
  });
261710
262149
  }
261711
262150
 
262151
+ // src/core/version/actors.ts
262152
+ var MAX_ACTORS = 50;
262153
+ var COMPILE_CONCURRENCY = 4;
262154
+ var ACTORS_ROOT = "base44/actors";
262155
+ var SHARED_ROOT = "base44/shared";
262156
+ function forwardSlashed(from, to) {
262157
+ return relative7(from, to).split(/[/\\]/).join("/");
262158
+ }
262159
+ async function readSharedFiles2(actorsDir) {
262160
+ const sharedDir = resolve13(actorsDir, "..", "shared");
262161
+ if (!await pathExists(sharedDir)) {
262162
+ return {};
262163
+ }
262164
+ const paths = await globby(BACKEND_FILE_GLOB, {
262165
+ cwd: sharedDir,
262166
+ absolute: true
262167
+ });
262168
+ const files = {};
262169
+ for (const path of paths.sort()) {
262170
+ files[`${SHARED_ROOT}/${forwardSlashed(sharedDir, path)}`] = await readTextFile(path);
262171
+ }
262172
+ return files;
262173
+ }
262174
+ async function compilerInput2(actor, shared) {
262175
+ const actorDir = dirname22(actor.entryPath);
262176
+ const entry = `${ACTORS_ROOT}/${actor.name}/entry.ts`;
262177
+ const source = await readTextFile(actor.entryPath);
262178
+ const candidates = { ...shared };
262179
+ for (const filePath of actor.filePaths) {
262180
+ if (filePath !== actor.entryPath) {
262181
+ candidates[`${ACTORS_ROOT}/${actor.name}/${forwardSlashed(actorDir, filePath)}`] = await readTextFile(filePath);
262182
+ }
262183
+ }
262184
+ candidates[entry] = source;
262185
+ return {
262186
+ entry,
262187
+ files: await collectReachableFiles(entry, candidates),
262188
+ source
262189
+ };
262190
+ }
262191
+ async function compileActors(actorsDir) {
262192
+ const actors = await readAllActors(actorsDir);
262193
+ if (actors.length === 0) {
262194
+ return [];
262195
+ }
262196
+ if (actors.length > MAX_ACTORS) {
262197
+ throw new InvalidInputError(`Too many actors: found ${actors.length}, the limit is ${MAX_ACTORS}.`);
262198
+ }
262199
+ await requireCompilerRuntime("Actors");
262200
+ const shared = await readSharedFiles2(actorsDir);
262201
+ const sorted = [...actors].sort((a, b) => a.name < b.name ? -1 : 1);
262202
+ const compiled = await pMap(sorted, async (actor) => {
262203
+ const input = await compilerInput2(actor, shared);
262204
+ const result = await bundle({ entry: input.entry, files: input.files });
262205
+ return {
262206
+ name: actor.name,
262207
+ entry: input.entry,
262208
+ source: input.source,
262209
+ result
262210
+ };
262211
+ }, { concurrency: COMPILE_CONCURRENCY });
262212
+ const failures = compiled.flatMap(({ name, result }) => result.ok ? [] : [
262213
+ {
262214
+ function: name,
262215
+ message: `Actor "${name}" failed to compile.`,
262216
+ errors: result.errors
262217
+ }
262218
+ ]);
262219
+ if (failures.length > 0) {
262220
+ throw new InvalidInputError(`Actors failed to compile (${failures.length} error${failures.length === 1 ? "" : "s"}).`, { details: failures.map(describeFailure) });
262221
+ }
262222
+ return compiled.map(({ name, entry, source, result }) => {
262223
+ const module = new TextEncoder().encode(compiledModule(name, result));
262224
+ return {
262225
+ name,
262226
+ entry,
262227
+ source,
262228
+ module,
262229
+ size: module.byteLength,
262230
+ digest: sha256(module),
262231
+ staticEgress: STATIC_EGRESS_ARTIFACT_MARKER
262232
+ };
262233
+ });
262234
+ }
262235
+ function compiledModule(name, result) {
262236
+ if (!result.ok || result.do_class_name !== name) {
262237
+ throw new InternalError(`Actor "${name}" did not compile as an actor of that name.`);
262238
+ }
262239
+ return result.module;
262240
+ }
262241
+
261712
262242
  // src/core/version/publish.ts
261713
262243
  import { randomUUID as randomUUID4 } from "node:crypto";
261714
262244
  var DEFAULT_ENVIRONMENT = "production";
@@ -261761,7 +262291,7 @@ async function collectBuildOutput(outputDir, options = {}) {
261761
262291
  }
261762
262292
  async function describeSiteWorker(built) {
261763
262293
  const { config, modules } = built;
261764
- const entry = resolve13(config.configDir, config.main);
262294
+ const entry = resolve14(config.configDir, config.main);
261765
262295
  const main = modules.find((m) => m.absolutePath === entry)?.name;
261766
262296
  if (!main) {
261767
262297
  throw new InvalidInputError(`The Worker's entry module ${config.main} is not among the ${modules.length} modules collected from ${config.configDir}.`);
@@ -261812,6 +262342,7 @@ async function collectArtifacts(target) {
261812
262342
  }),
261813
262343
  ...siteWorker ? { siteWorker } : {},
261814
262344
  backendBundles: await tagStep2("build", () => compileBackendBundles(target.root, join29(target.configDir, target.functionsDir))),
262345
+ actors: await tagStep2("build", () => compileActors(join29(target.configDir, target.actorsDir))),
261815
262346
  ...await collectResources(target.configDir, target)
261816
262347
  };
261817
262348
  }
@@ -262269,7 +262800,7 @@ function getSecretsListCommand() {
262269
262800
  }
262270
262801
 
262271
262802
  // src/cli/commands/secrets/set.ts
262272
- import { resolve as resolve14 } from "node:path";
262803
+ import { resolve as resolve15 } from "node:path";
262273
262804
  function parseEntries(entries) {
262274
262805
  const secrets = {};
262275
262806
  for (const entry of entries) {
@@ -262300,7 +262831,7 @@ async function setSecretsAction({ log, runTask }, entries, options) {
262300
262831
  validateInput(entries, options);
262301
262832
  let secrets;
262302
262833
  if (options.envFile) {
262303
- secrets = await parseEnvFile(resolve14(options.envFile));
262834
+ secrets = await parseEnvFile(resolve15(options.envFile));
262304
262835
  if (Object.keys(secrets).length === 0) {
262305
262836
  throw new InvalidInputError("The env file contains no valid KEY=VALUE entries.");
262306
262837
  }
@@ -262329,7 +262860,7 @@ function getSecretsCommand() {
262329
262860
  }
262330
262861
 
262331
262862
  // src/cli/commands/site/deploy.ts
262332
- import { resolve as resolve15 } from "node:path";
262863
+ import { resolve as resolve16 } from "node:path";
262333
262864
  async function deployAction2(ctx, options) {
262334
262865
  const { isNonInteractive } = ctx;
262335
262866
  if (isNonInteractive && !options.yes) {
@@ -262398,7 +262929,7 @@ async function deployTarball({ runTask }, project) {
262398
262929
  }
262399
262930
  function siteOutputDir(project) {
262400
262931
  const { outputDirectory = DEFAULT_SITE.outputDirectory } = siteOrDefault(project);
262401
- return resolve15(project.root, outputDirectory);
262932
+ return resolve16(project.root, outputDirectory);
262402
262933
  }
262403
262934
  function getSiteDeployCommand() {
262404
262935
  const command = new Base44Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").option("--build", "Build the site before deploying (skips the prompt)").option("--no-build", "Deploy without building (skips the prompt)");
@@ -263226,7 +263757,7 @@ function getWorkspaceCommand() {
263226
263757
  // src/cli/dev/dev-server/main.ts
263227
263758
  var import_cors = __toESM(require_lib4(), 1);
263228
263759
  var import_express6 = __toESM(require_express(), 1);
263229
- import { dirname as dirname27, join as join38 } from "node:path";
263760
+ import { dirname as dirname28, join as join38 } from "node:path";
263230
263761
 
263231
263762
  // ../../node_modules/get-port/index.js
263232
263763
  import net from "node:net";
@@ -263356,7 +263887,7 @@ var $tmpName = promisify12(tmp.tmpName);
263356
263887
 
263357
263888
  // src/cli/dev/dev-server/function-manager.ts
263358
263889
  import { spawn as spawn3 } from "node:child_process";
263359
- import { dirname as dirname24, join as join34 } from "node:path";
263890
+ import { dirname as dirname25, join as join34 } from "node:path";
263360
263891
  import { pathToFileURL as pathToFileURL6 } from "node:url";
263361
263892
 
263362
263893
  // src/cli/dev/dev-server/base-function-manager.ts
@@ -263461,7 +263992,7 @@ class FunctionManager extends BaseFunctionManager {
263461
263992
  }
263462
263993
  spawnFunction(func, port) {
263463
263994
  this.logger.log(`Spawning function "${func.name}" on port ${port}`);
263464
- const importMapPath = join34(dirname24(this.wrapperPath), "import-map.json");
263995
+ const importMapPath = join34(dirname25(this.wrapperPath), "import-map.json");
263465
263996
  const process2 = spawn3("deno", ["run", "--allow-all", "--import-map", importMapPath, this.wrapperPath], {
263466
263997
  env: {
263467
263998
  ...globalThis.process.env,
@@ -265190,7 +265721,7 @@ function createCustomIntegrationRoutes(remoteProxy, logger) {
265190
265721
 
265191
265722
  // src/cli/dev/dev-server/watcher.ts
265192
265723
  import { EventEmitter as EventEmitter4 } from "node:events";
265193
- import { relative as relative10 } from "node:path";
265724
+ import { relative as relative11 } from "node:path";
265194
265725
 
265195
265726
  // ../../node_modules/chokidar/index.js
265196
265727
  import { EventEmitter as EventEmitter3 } from "node:events";
@@ -266875,7 +267406,7 @@ class WatchBase44 extends EventEmitter4 {
266875
267406
  ignoreInitial: true
266876
267407
  });
266877
267408
  watcher.on("all", import_debounce.default(async (_event, path) => {
266878
- this.emit("change", name, relative10(targetPath, path));
267409
+ this.emit("change", name, relative11(targetPath, path));
266879
267410
  }, WATCH_DEBOUNCE_MS));
266880
267411
  watcher.on("error", (err) => {
266881
267412
  this.logger.error(`Watch handler failed for ${targetPath}`, err);
@@ -266987,8 +267518,8 @@ async function createDevServer(options) {
266987
267518
  broadcastEntityEvent(io, appId, entityName, event);
266988
267519
  };
266989
267520
  const base44ConfigWatcher = new WatchBase44({
266990
- functions: join38(dirname27(project.configPath), project.functionsDir),
266991
- entities: join38(dirname27(project.configPath), project.entitiesDir)
267521
+ functions: join38(dirname28(project.configPath), project.functionsDir),
267522
+ entities: join38(dirname28(project.configPath), project.entitiesDir)
266992
267523
  }, devLogger);
266993
267524
  base44ConfigWatcher.on("change", async (name) => {
266994
267525
  try {
@@ -267348,7 +267879,7 @@ Examples:
267348
267879
  }
267349
267880
 
267350
267881
  // src/cli/commands/project/eject.ts
267351
- import { resolve as resolve19 } from "node:path";
267882
+ import { resolve as resolve20 } from "node:path";
267352
267883
  var import_kebabCase2 = __toESM(require_kebabCase(), 1);
267353
267884
  async function eject(ctx, options, command) {
267354
267885
  const { log, runTask, isNonInteractive } = ctx;
@@ -267412,7 +267943,7 @@ async function eject(ctx, options, command) {
267412
267943
  Ne("Operation cancelled.");
267413
267944
  throw new CLIExitError(0);
267414
267945
  }
267415
- const resolvedPath = resolve19(selectedPath);
267946
+ const resolvedPath = resolve20(selectedPath);
267416
267947
  await runTask("Downloading your project's code...", async (updateMessage) => {
267417
267948
  await createProjectFilesForExistingProject({
267418
267949
  projectId,
@@ -267517,7 +268048,7 @@ var import_detect_agent = __toESM(require_dist5(), 1);
267517
268048
  import { release, type } from "node:os";
267518
268049
 
267519
268050
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
267520
- import { dirname as dirname28, posix, sep as sep2 } from "path";
268051
+ import { dirname as dirname29, posix, sep as sep2 } from "path";
267521
268052
  function createModulerModifier() {
267522
268053
  const getModuleFromFileName = createGetModuleFromFilename();
267523
268054
  return async (frames) => {
@@ -267526,7 +268057,7 @@ function createModulerModifier() {
267526
268057
  return frames;
267527
268058
  };
267528
268059
  }
267529
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname28(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
268060
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname29(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
267530
268061
  const normalizedBase = isWindows ? normalizeWindowsPath2(basePath) : basePath;
267531
268062
  return (filename) => {
267532
268063
  if (!filename)
@@ -271515,7 +272046,7 @@ function addCommandInfoToErrorReporter(program, errorReporter) {
271515
272046
  });
271516
272047
  }
271517
272048
  // src/cli/index.ts
271518
- var __dirname4 = dirname29(fileURLToPath7(import.meta.url));
272049
+ var __dirname4 = dirname30(fileURLToPath7(import.meta.url));
271519
272050
  async function runCLI(options) {
271520
272051
  ensureNpmAssets(join40(__dirname4, "../assets"));
271521
272052
  const errorReporter = new ErrorReporter;
@@ -271556,4 +272087,4 @@ export {
271556
272087
  runCLI
271557
272088
  };
271558
272089
 
271559
- //# debugId=B28345EB77F07FBF64756E2164756E21
272090
+ //# debugId=02073B02CE22EAE264756E2164756E21