void 0.7.2 → 0.7.4

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/index.mjs CHANGED
@@ -4,10 +4,10 @@ import { u as require_picocolors } from "./output-BwlcIYSR.mjs";
4
4
  import { n as loadVoidAuthConfig, t as findVoidAuthConfig } from "./config-CvHtTM0q.mjs";
5
5
  import { r as readProjectConfig } from "./project-TqORyHn8.mjs";
6
6
  import { c as getToken, u as isStagingMode } from "./client-DCqnMpDt.mjs";
7
- import { _ as resolveSandboxConfig, a as prerenderPagesNode, c as filterLoadedEnv, d as ensureWranglerCompatibilityDate, f as ensureWranglerNodejsAlsFlag, g as isSandboxEnabled, h as SANDBOX_MIGRATION_TAG, i as prerenderPages, l as resolveRemoteMode, m as syncWranglerBindings, n as resolveDistDir, o as DEFAULT_PROXY_URL, p as readWranglerCompat, r as resolveWorkerDirName, s as STAGING_PROXY_URL, u as stripInternalEnvKeys } from "./deploy-BkjqNk9U.mjs";
7
+ import { C as resolveSandboxConfig, S as isSandboxEnabled, _ as readExistingLiveBindingConfig, a as prerenderPagesNode, b as syncWranglerBindings, c as filterLoadedEnv, d as LIVE_MIGRATION_TAG, f as ensureWranglerCompatibilityDate, g as normalizeWranglerCompatibilityFlags, h as nextDurableObjectMigrationTag, i as prerenderPages, l as resolveRemoteMode, m as hasDurableObjectSqliteMigration, n as resolveDistDir, o as DEFAULT_PROXY_URL, p as ensureWranglerNodejsAlsFlag, r as resolveWorkerDirName, s as STAGING_PROXY_URL, u as stripInternalEnvKeys, v as readWranglerCompat, x as SANDBOX_MIGRATION_TAG, y as resolveLiveBindingConfig } from "./deploy-CRIz77mw.mjs";
8
8
  import { c as getDatabaseDialect, f as readConfig, l as isNodeTarget, p as resolveBindingNames } from "./config-BIa9HwVX.mjs";
9
- import { i as scanJobsSync, n as scanWebSocketRoutesSync, r as scanQueuesSync, t as scanRoutes } from "./scan-C6HMEIdW.mjs";
10
- import { a as SSR_SERVER_ENTRY_RELATIVE_PATHS, c as validateSsrEntry, d as isIdentifier, f as isLiteral, h as walk, i as SSR_CLIENT_ENTRY_RELATIVE_PATHS, l as inferBindingsFromSource, n as detectFramework, p as isMemberExpression, r as inferProjectBindings, s as validateSsrEntries, t as FRAMEWORK_SCAN_DIRS } from "./plugin-inference-oZ6Ybu2_.mjs";
9
+ import { i as scanJobsSync, n as scanWebSocketRoutesSync, r as scanQueuesSync, t as scanRoutes } from "./scan-QtRTdh94.mjs";
10
+ import { a as SSR_CLIENT_ENTRY_RELATIVE_PATHS, c as validateSsrEntries, f as isIdentifier, g as walk, i as inferProjectBindings, l as validateSsrEntry, m as isMemberExpression, n as FRAMEWORK_SCAN_DIRS, o as SSR_SERVER_ENTRY_RELATIVE_PATHS, p as isLiteral, r as detectFramework, t as DEFAULT_SCAN_DIRS, u as inferBindingsFromSource } from "./plugin-inference-CCtRkt9O.mjs";
11
11
  import { i as voidWarn, n as voidError, r as voidLog, t as setShowTimestamp } from "./log-DXdqnmhF.mjs";
12
12
  import { r as parseDotenvFile } from "./dotenv-DwO4ti0Z.mjs";
13
13
  import { i as generateDbDts, n as generateQueueTypes, r as DRIZZLE_OPERATORS, t as generateRouteTypes } from "./route-types-DReF1gUY.mjs";
@@ -2062,6 +2062,7 @@ function compileRouteTable(scan, routesDir, middlewareDir, jobsDir, queuesDir, s
2062
2062
  if (auth.authConfigPath) lines.push(`import __voidAuthConfig from ${JSON.stringify(auth.authConfigPath)};`);
2063
2063
  }
2064
2064
  if (webSockets.length > 0 && options.webSocketRuntimePath) lines.push(`import { createWebSocketDurableObject as __createWebSocketDurableObject, handleWebSocketUpgrade as __handleWebSocketUpgrade, forwardWebSocketRequest as __forwardWebSocketRequest } from ${JSON.stringify(options.webSocketRuntimePath)};`);
2065
+ if (options.hasLive && options.liveRuntimePath) lines.push(`import { createLiveDurableObject as __createLiveDurableObject } from ${JSON.stringify(options.liveRuntimePath)};`);
2065
2066
  lines.push("");
2066
2067
  for (let i = 0; i < scan.middleware.length; i++) {
2067
2068
  const mw = scan.middleware[i];
@@ -2278,6 +2279,10 @@ function compileRouteTable(scan, routesDir, middlewareDir, jobsDir, queuesDir, s
2278
2279
  lines.push("export async function __voidHandleWebSocket() { return null; }");
2279
2280
  lines.push("");
2280
2281
  }
2282
+ if (options.hasLive) {
2283
+ lines.push("export const VoidLiveStreamDurableObject = __createLiveDurableObject();");
2284
+ lines.push("");
2285
+ }
2281
2286
  if (pages && scan.pages.pages.length > 0) compilePageRoutes(lines, scan, pages, options);
2282
2287
  compilePrerenderCollector(lines, scan, ssr, options);
2283
2288
  if (ssr) {
@@ -2954,7 +2959,7 @@ function compilePageRoutes(lines, scan, pages, options) {
2954
2959
  * remote mode (`__VOID_REMOTE`) and replace local bindings with
2955
2960
  * proxy-backed versions.
2956
2961
  */
2957
- function compileWorkerEntry(hasQueues = false, remote, assetsDir = "assets", webSocketClasses = [], runtimeEnvPath = "void/_env", envSchemaModule, sandbox, serveSpaFallback = false) {
2962
+ function compileWorkerEntry(hasQueues = false, remote, assetsDir = "assets", webSocketClasses = [], runtimeEnvPath = "void/_env", envSchemaModule, sandbox, serveSpaFallback = false, live) {
2958
2963
  const remotePath = remote?.remotePath;
2959
2964
  const hasSandbox = sandbox === true || typeof sandbox === "object";
2960
2965
  const sandboxClassName = typeof sandbox === "object" ? sandbox.className ?? "Sandbox" : "Sandbox";
@@ -2962,6 +2967,12 @@ function compileWorkerEntry(hasQueues = false, remote, assetsDir = "assets", web
2962
2967
  const sandboxRuntimePath = typeof sandbox === "object" ? sandbox.runtimePath ?? "void/sandbox" : "void/sandbox";
2963
2968
  const sandboxImport = hasSandbox ? `import { Sandbox as __VoidSandbox } from "@cloudflare/sandbox";\nimport { __setSandboxBindingName } from ${JSON.stringify(sandboxRuntimePath)};\n` : "";
2964
2969
  const sandboxExport = hasSandbox ? sandboxClassName === "Sandbox" ? `export { __VoidSandbox as Sandbox };\n__setSandboxBindingName(${JSON.stringify(sandboxBindingName)});\n` : `export class ${sandboxClassName} extends __VoidSandbox {}\n__setSandboxBindingName(${JSON.stringify(sandboxBindingName)});\n` : "";
2970
+ const hasLive = live === true || typeof live === "object";
2971
+ const liveBindingName = typeof live === "object" ? live.bindingName ?? "VOID_LIVE" : "VOID_LIVE";
2972
+ const liveClassName = typeof live === "object" ? live.className ?? "VoidLiveStreamDurableObject" : "VoidLiveStreamDurableObject";
2973
+ const liveRouteImport = hasLive ? ", VoidLiveStreamDurableObject" : "";
2974
+ const liveRuntimeImport = hasLive ? `import { __setLiveBindingName } from "void/live";\n` : "";
2975
+ const liveExport = hasLive ? liveClassName === "VoidLiveStreamDurableObject" ? `export { VoidLiveStreamDurableObject };\n__setLiveBindingName(${JSON.stringify(liveBindingName)});\n` : `export { VoidLiveStreamDurableObject as ${liveClassName} };\n__setLiveBindingName(${JSON.stringify(liveBindingName)});\n` : "";
2965
2976
  const runtimeEnvImport = `import { withRuntimeEnv } from ${JSON.stringify(runtimeEnvPath)};\n`;
2966
2977
  const remoteImport = remote ? `import { createRemoteEnv } from ${JSON.stringify(remote.remotePath)};\n` : "";
2967
2978
  const envSchemaImport = envSchemaModule ? `import ${JSON.stringify(envSchemaModule.importPath)};\nimport { _validateEnvOnce } from ${JSON.stringify(envSchemaModule.helperPath)};\n` : "";
@@ -3076,7 +3087,7 @@ ${envValidateCall} if (env.__VOID_REMOTE === "1") env = createRemoteEnv(env);
3076
3087
  ${envValidateCall} const userEnv = __filterInternalBindings(env);
3077
3088
  return withRuntimeEnv(env, () => scheduled(controller, userEnv, ctx));
3078
3089
  }`;
3079
- if (hasQueues) return `${sandboxImport}import app, { scheduled, __voidCollectPrerenderPaths, __voidHandleWebSocket, __withRawEnv, __processQueue${webSocketClasses.length > 0 ? `, ${webSocketClasses.join(", ")}` : ""} } from 'virtual:void-routes';
3090
+ if (hasQueues) return `${sandboxImport}${liveRuntimeImport}import app, { scheduled, __voidCollectPrerenderPaths, __voidHandleWebSocket, __withRawEnv, __processQueue${webSocketClasses.length > 0 ? `, ${webSocketClasses.join(", ")}` : ""}${liveRouteImport} } from 'virtual:void-routes';
3080
3091
  ${runtimeEnvImport}${envSchemaImport}${remoteImport}${filterBindingsHelper}${assetHelper}
3081
3092
  ${internalRouteHelper}
3082
3093
  ${scheduledHandler}
@@ -3102,13 +3113,15 @@ ${envValidateCall}${remotePath ? ` if (env.__VOID_REMOTE === "1") env = createR
3102
3113
  }
3103
3114
 
3104
3115
  ${webSocketClasses.map((name) => `export { ${name} };`).join("\n")}
3116
+ ${liveExport}
3105
3117
  ${sandboxExport}
3106
3118
  export default { fetch: ${fetchHandler}, scheduled: handleScheduled, queue };`;
3107
- return `${sandboxImport}import app, { scheduled, __voidCollectPrerenderPaths, __voidHandleWebSocket, __withRawEnv${webSocketClasses.length > 0 ? `, ${webSocketClasses.join(", ")}` : ""} } from 'virtual:void-routes';
3119
+ return `${sandboxImport}${liveRuntimeImport}import app, { scheduled, __voidCollectPrerenderPaths, __voidHandleWebSocket, __withRawEnv${webSocketClasses.length > 0 ? `, ${webSocketClasses.join(", ")}` : ""}${liveRouteImport} } from 'virtual:void-routes';
3108
3120
  ${runtimeEnvImport}${envSchemaImport}${remoteImport}${filterBindingsHelper}${assetHelper}
3109
3121
  ${internalRouteHelper}
3110
3122
  ${scheduledHandler}
3111
3123
  ${webSocketClasses.map((name) => `export { ${name} };`).join("\n")}
3124
+ ${liveExport}
3112
3125
  ${sandboxExport}
3113
3126
  export default { fetch: ${fetchHandler}, scheduled: handleScheduled };`;
3114
3127
  }
@@ -3628,6 +3641,8 @@ function routingPlugin(root, options) {
3628
3641
  projectRoot: root,
3629
3642
  homeDir: homedir(),
3630
3643
  webSocketRuntimePath: resolveFile("#self/runtime/ws-server"),
3644
+ liveRuntimePath: resolveFile("#self/runtime/live-server"),
3645
+ hasLive: options.live !== void 0,
3631
3646
  reactRefresh: false,
3632
3647
  dev: false,
3633
3648
  devTriggerToken: options.devTriggerToken,
@@ -3727,7 +3742,7 @@ function routingPlugin(root, options) {
3727
3742
  bindingName: options.sandboxBindingName,
3728
3743
  className: options.sandboxClassName,
3729
3744
  runtimePath: sandboxRuntimePath
3730
- } : false));
3745
+ } : false, void 0, options.live));
3731
3746
  return {
3732
3747
  name: "void:routing",
3733
3748
  enforce: "pre",
@@ -3791,7 +3806,7 @@ function routingPlugin(root, options) {
3791
3806
  bindingName: options.sandboxBindingName,
3792
3807
  className: options.sandboxClassName,
3793
3808
  runtimePath: sandboxRuntimePath
3794
- } : false, shouldServeSpaFallback()));
3809
+ } : false, shouldServeSpaFallback(), options.live));
3795
3810
  },
3796
3811
  resolveId: {
3797
3812
  filter: { id: RESOLVE_ID_FILTER },
@@ -3834,7 +3849,7 @@ function routingPlugin(root, options) {
3834
3849
  bindingName: options.sandboxBindingName,
3835
3850
  className: options.sandboxClassName,
3836
3851
  runtimePath: sandboxRuntimePath
3837
- } : false, shouldServeSpaFallback()));
3852
+ } : false, shouldServeSpaFallback(), options.live));
3838
3853
  const structural = event !== "change";
3839
3854
  for (const env of Object.values(devServer.environments)) {
3840
3855
  const mod = env.moduleGraph.getModuleById(VIRTUAL_ROUTES_ID);
@@ -4250,6 +4265,7 @@ function voidPlugin(options) {
4250
4265
  const authEnabled = bindings.needsAuth || authConfigPath !== null || config.auth !== void 0;
4251
4266
  if (detected && authEnabled) throw new Error("auth: Void-managed Better Auth is only supported in Void apps. Use Better Auth's official integration for this framework instead.");
4252
4267
  if (detected && bindings.needsSandbox) throw new Error("sandbox: Cloudflare Sandboxes are currently supported in Void apps only.");
4268
+ if (detected && bindings.needsLive) throw new Error("live: void/live is currently supported in Void apps only.");
4253
4269
  const STUB_PREFIX = "\0void-client-stub:";
4254
4270
  const SERVER_ONLY_STUBS = {
4255
4271
  "void/db": "export const db = {}; export const createDb = () => ({});",
@@ -4258,7 +4274,8 @@ function voidPlugin(options) {
4258
4274
  "void/queues": "export const queues = {};",
4259
4275
  "void/storage": "export const storage = {}; export const createStorage = () => ({});",
4260
4276
  "void/isr": "export const revalidate = async () => {};",
4261
- "void/sandbox": "export const sandbox = {}; export const getSandbox = () => ({});"
4277
+ "void/sandbox": "export const sandbox = {}; export const getSandbox = () => ({});",
4278
+ "void/live": ""
4262
4279
  };
4263
4280
  const STUB_RESOLVE_FILTER = new RegExp(`^(${Object.keys(SERVER_ONLY_STUBS).join("|").replaceAll("/", "\\/")})$`);
4264
4281
  const STUB_LOAD_FILTER = new RegExp(`^\\0void-client-stub:`);
@@ -4268,7 +4285,10 @@ function voidPlugin(options) {
4268
4285
  resolveId: {
4269
4286
  filter: { id: STUB_RESOLVE_FILTER },
4270
4287
  handler(id) {
4271
- if (this.environment?.name === "client") return STUB_PREFIX + id;
4288
+ if (this.environment?.name === "client") {
4289
+ if (id === "void/live") this.error("void/live is server-only and cannot be imported by browser code. Import void/live/client instead.");
4290
+ return STUB_PREFIX + id;
4291
+ }
4272
4292
  }
4273
4293
  },
4274
4294
  load: {
@@ -4280,6 +4300,10 @@ function voidPlugin(options) {
4280
4300
  };
4281
4301
  const queues = framework ? [] : scanQueuesSync(root);
4282
4302
  const websocketRoutes = framework ? [] : scanWebSocketRoutesSync(root);
4303
+ const liveConfig = !isNodeTarget(config.target) ? bindings.needsLive ? resolveLiveBindingConfig(root, {
4304
+ reservedBindings: websocketRoutes.map((route) => route.bindingName),
4305
+ reservedClasses: [...websocketRoutes.map((route) => route.className), sandboxConfig?.className]
4306
+ }) : readExistingLiveBindingConfig(root) : void 0;
4283
4307
  if (detected && (detected.class === "b" || detected.class === "c")) {
4284
4308
  const bindingNames = resolveBindingNames(config.inference?.bindings);
4285
4309
  const frameworkPersistRoot = join(root, ".wrangler", "state");
@@ -4305,7 +4329,8 @@ function voidPlugin(options) {
4305
4329
  if (syncWranglerBindings(root, bindings, {
4306
4330
  bindingNames,
4307
4331
  websockets: websocketRoutes,
4308
- sandbox: sandboxConfig
4332
+ sandbox: sandboxConfig,
4333
+ live: liveConfig
4309
4334
  })) voidLog("Synced bindings to wrangler.jsonc");
4310
4335
  }
4311
4336
  },
@@ -4417,6 +4442,19 @@ function voidPlugin(options) {
4417
4442
  new_sqlite_classes: [sandboxConfig.className]
4418
4443
  }];
4419
4444
  }
4445
+ if (liveConfig) {
4446
+ const existingDurableObjectBindings = (result.durable_objects ?? resolved.durable_objects)?.bindings ?? [];
4447
+ if (!existingDurableObjectBindings.some((binding) => binding.name === liveConfig.bindingName)) result.durable_objects = { bindings: [...existingDurableObjectBindings, {
4448
+ name: liveConfig.bindingName,
4449
+ class_name: liveConfig.className
4450
+ }] };
4451
+ const currentMigrations = result.migrations ?? resolved.migrations;
4452
+ const existingMigrations = Array.isArray(currentMigrations) ? currentMigrations : [];
4453
+ if (!hasDurableObjectSqliteMigration(existingMigrations, liveConfig.className)) result.migrations = [...existingMigrations, {
4454
+ tag: nextDurableObjectMigrationTag(existingMigrations, LIVE_MIGRATION_TAG),
4455
+ new_sqlite_classes: [liveConfig.className]
4456
+ }];
4457
+ }
4420
4458
  if (viteCommand === "serve" && bindings.needsAI) {
4421
4459
  const credentials = readVoidDevCredentials(root);
4422
4460
  if (credentials.status === "ok") {
@@ -4519,13 +4557,7 @@ function voidPlugin(options) {
4519
4557
  apply: "serve",
4520
4558
  configureServer(server) {
4521
4559
  if (!autoDetectBindings && !autoDetectAuth) return;
4522
- const watchDirs = [...new Set([...scanDirs ?? [
4523
- "routes",
4524
- "middleware",
4525
- "queues",
4526
- "pages",
4527
- "crons"
4528
- ], "src"])].map((d) => join(root, d));
4560
+ const watchDirs = [...new Set([...scanDirs ?? DEFAULT_SCAN_DIRS, "src"])].map((d) => join(root, d));
4529
4561
  let hintShown = false;
4530
4562
  const check = (path) => {
4531
4563
  if (hintShown) return;
@@ -4618,6 +4650,7 @@ function voidPlugin(options) {
4618
4650
  if (config.worker) voidWarn("\"worker\" in void.json is ignored with target: \"" + config.target + "\"");
4619
4651
  if (config.remote) voidWarn("\"remote\" in void.json is ignored with target: \"" + config.target + "\"");
4620
4652
  if (bindings.needsSandbox) throw new Error(`sandbox: Cloudflare Sandboxes require target: "cloudflare". They are not available with target: '${config.target}'.`);
4653
+ if (bindings.needsLive) throw new Error(`live: void/live requires target: "cloudflare". It is not available with target: '${config.target}'.`);
4621
4654
  if (config.routing?.revalidate) voidWarn("\"routing.revalidate\" in void.json is ignored with target: \"" + config.target + "\" (edge caching is CF-only)");
4622
4655
  return [
4623
4656
  restartPlugin(),
@@ -4638,8 +4671,8 @@ function voidPlugin(options) {
4638
4671
  ];
4639
4672
  }
4640
4673
  const existingFlags = workerConfig.compatibility_flags ?? [];
4641
- if ((dialect === "postgresql" || bindings.needsSandbox) && !existingFlags.includes("nodejs_compat")) workerConfig.compatibility_flags = [...existingFlags.filter((f) => f !== "nodejs_als"), "nodejs_compat"];
4642
- else if (!existingFlags.includes("nodejs_als") && !existingFlags.includes("nodejs_compat")) workerConfig.compatibility_flags = [...existingFlags, "nodejs_als"];
4674
+ const normalizedFlags = normalizeWranglerCompatibilityFlags(existingFlags, { needsNodejsCompat: authEnabled || dialect === "postgresql" || bindings.needsSandbox });
4675
+ if (normalizedFlags && normalizedFlags !== existingFlags) workerConfig.compatibility_flags = normalizedFlags;
4643
4676
  const jobs = scanJobsSync(root);
4644
4677
  const ssrEntry = validateSsrEntry(root);
4645
4678
  const hasPages = existsSync(join(root, "pages"));
@@ -4671,7 +4704,8 @@ function voidPlugin(options) {
4671
4704
  routing: config.routing,
4672
4705
  hasSandbox: bindings.needsSandbox,
4673
4706
  sandboxBindingName: sandboxConfig?.binding,
4674
- sandboxClassName: sandboxConfig?.className
4707
+ sandboxClassName: sandboxConfig?.className,
4708
+ live: liveConfig
4675
4709
  }),
4676
4710
  drizzlePlugin(root, true, dialect, { forceVirtualDb: authEnabled }),
4677
4711
  migrationPlugin(root, dialect, "local", join(root, ".void"), {
@@ -4,7 +4,7 @@ import { _ as me, c as R, g as ge, i as Ee, u as Se, v as ue, x as q, y as ye }
4
4
  import { a as writeProjectConfig, r as readProjectConfig } from "./project-TqORyHn8.mjs";
5
5
  import { c as getToken, n as PlatformClient, u as isStagingMode } from "./client-DCqnMpDt.mjs";
6
6
  import { c as getDatabaseDialect, f as readConfig } from "./config-BIa9HwVX.mjs";
7
- import { n as detectFramework } from "./plugin-inference-oZ6Ybu2_.mjs";
7
+ import { r as detectFramework } from "./plugin-inference-CCtRkt9O.mjs";
8
8
  import { r as parseDotenvFile, t as expandDotenv } from "./dotenv-DwO4ti0Z.mjs";
9
9
  import { n as ensureProjectTsconfig, t as createProjectTsconfig } from "./project-tsconfig-DfkESbDL.mjs";
10
10
  import { t as MagicString } from "./magic-string.es-D6g9UnIy.mjs";
@@ -12,7 +12,7 @@ import { n as writeDrizzleConfig } from "./config-BzM9Dy7T.mjs";
12
12
  import { n as getAgentById, r as getPackageDir, t as detectAgents } from "./agents-DqkFfc2c.mjs";
13
13
  import { n as promptProjectSelection, t as promptAndCreateProject } from "./create-project-Bg88Kq_I.mjs";
14
14
  import { t as promptForLoginToken } from "./login-B5HHT32i.mjs";
15
- import { r as formatProjectCommand } from "./preset-DFvePt0l.mjs";
15
+ import { r as formatProjectCommand } from "./preset-jKn1hQwP.mjs";
16
16
  import { n as findInstalledYarnPnpRuntime, r as hasLocalLockfile, t as buildDrizzleKitSpawnEnv } from "./yarn-pnp-6LD6_3Ej.mjs";
17
17
  import { createRequire } from "node:module";
18
18
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmdirSync, unlinkSync, writeFileSync } from "node:fs";
@@ -2120,7 +2120,8 @@ function inferBindingsFromSource(code, filename) {
2120
2120
  needsAuth: false,
2121
2121
  needsQueues: false,
2122
2122
  needsAI: false,
2123
- needsSandbox: false
2123
+ needsSandbox: false,
2124
+ needsLive: false
2124
2125
  };
2125
2126
  try {
2126
2127
  const [imports] = parse(code);
@@ -2149,6 +2150,9 @@ function inferBindingsFromSource(code, filename) {
2149
2150
  case "void/sandbox":
2150
2151
  result.needsSandbox = true;
2151
2152
  break;
2153
+ case "void/live":
2154
+ if (!isTypeOnlyImportStatement(code.slice(imp.ss, imp.se + 1))) result.needsLive = true;
2155
+ break;
2152
2156
  case "void/client": {
2153
2157
  const stmt = code.slice(imp.ss, imp.se + 1);
2154
2158
  if (/\bauth\b/.test(stmt)) result.needsAuth = true;
@@ -2164,9 +2168,10 @@ function inferBindingsFromSource(code, filename) {
2164
2168
  if (/\bfrom\s+["']void\/queue["']/.test(code)) result.needsQueues = true;
2165
2169
  if (/\bfrom\s+["']void\/ai["']/.test(code)) result.needsAI = true;
2166
2170
  if (/\bfrom\s+["']void\/sandbox["']/.test(code)) result.needsSandbox = true;
2171
+ if (hasRuntimeImportFrom(code, "void/live")) result.needsLive = true;
2167
2172
  if (/\bfrom\s+["']void\/client["']/.test(code) && /\bauth\b/.test(code)) result.needsAuth = true;
2168
2173
  }
2169
- if (result.needsD1 && result.needsKV && result.needsR2 && result.needsAI && result.needsSandbox) return result;
2174
+ if (result.needsD1 && result.needsKV && result.needsR2 && result.needsAI && result.needsSandbox && result.needsLive) return result;
2170
2175
  if (!ENV_BINDING_RE.test(code)) return result;
2171
2176
  let parsed;
2172
2177
  try {
@@ -2208,6 +2213,25 @@ function inferBindingsFromSource(code, filename) {
2208
2213
  } });
2209
2214
  return result;
2210
2215
  }
2216
+ function isTypeOnlyImportStatement(statement) {
2217
+ if (/^\s*import\s+type\b/.test(statement)) return true;
2218
+ const specifierStart = statement.indexOf("{");
2219
+ const specifierEnd = statement.lastIndexOf("}");
2220
+ if (specifierStart === -1 || specifierEnd === -1 || specifierEnd < specifierStart) return false;
2221
+ const beforeSpecifiers = statement.slice(0, specifierStart);
2222
+ if (!/^\s*import\s*$/.test(beforeSpecifiers)) return false;
2223
+ const specifiers = statement.slice(specifierStart + 1, specifierEnd).split(",").map((specifier) => specifier.trim()).filter(Boolean);
2224
+ return specifiers.length > 0 && specifiers.every((specifier) => specifier.startsWith("type "));
2225
+ }
2226
+ function hasRuntimeImportFrom(code, source) {
2227
+ const escapedSource = source.replaceAll("/", "\\/");
2228
+ const importRe = new RegExp(`\\bimport\\s+(?:[\\s\\S]*?\\bfrom\\s+)?["']${escapedSource}["']\\s*;?`, "g");
2229
+ for (const match of code.matchAll(importRe)) {
2230
+ const statement = match[0];
2231
+ if (!isTypeOnlyImportStatement(statement)) return true;
2232
+ }
2233
+ return false;
2234
+ }
2211
2235
  /**
2212
2236
  * Merge multiple InferredBindings into a single result (union).
2213
2237
  */
@@ -2219,7 +2243,8 @@ function mergeBindings(bindings) {
2219
2243
  needsAuth: bindings.some((b) => b.needsAuth),
2220
2244
  needsQueues: bindings.some((b) => b.needsQueues),
2221
2245
  needsAI: bindings.some((b) => b.needsAI),
2222
- needsSandbox: bindings.some((b) => b.needsSandbox)
2246
+ needsSandbox: bindings.some((b) => b.needsSandbox),
2247
+ needsLive: bindings.some((b) => b.needsLive)
2223
2248
  };
2224
2249
  }
2225
2250
  //#endregion
@@ -2309,6 +2334,15 @@ const FRAMEWORK_SCAN_DIRS = [
2309
2334
  "crons",
2310
2335
  "queues"
2311
2336
  ];
2337
+ /** Directories to scan for binding inference in Void app mode. */
2338
+ const DEFAULT_SCAN_DIRS = [
2339
+ "routes",
2340
+ "middleware",
2341
+ "queues",
2342
+ "pages",
2343
+ "crons",
2344
+ "src"
2345
+ ];
2312
2346
  /**
2313
2347
  * Map from npm package name to framework identifier.
2314
2348
  * Only packages that unambiguously indicate framework mode are listed.
@@ -2393,15 +2427,10 @@ function inferProjectBindings(root, options, scanDirs) {
2393
2427
  needsAuth: false,
2394
2428
  needsQueues: false,
2395
2429
  needsAI: Boolean(options.bindings.ai),
2396
- needsSandbox: false
2430
+ needsSandbox: false,
2431
+ needsLive: false
2397
2432
  };
2398
- const dirs = scanDirs ?? [
2399
- "routes",
2400
- "middleware",
2401
- "queues",
2402
- "pages",
2403
- "crons"
2404
- ];
2433
+ const dirs = scanDirs ?? DEFAULT_SCAN_DIRS;
2405
2434
  const allBindings = [];
2406
2435
  for (const dir of dirs) {
2407
2436
  const dirPath = join(root, dir);
@@ -2444,4 +2473,4 @@ function inferProjectBindings(root, options, scanDirs) {
2444
2473
  return mergeBindings(allBindings);
2445
2474
  }
2446
2475
  //#endregion
2447
- export { SSR_SERVER_ENTRY_RELATIVE_PATHS as a, validateSsrEntry as c, isIdentifier as d, isLiteral as f, walk as h, SSR_CLIENT_ENTRY_RELATIVE_PATHS as i, inferBindingsFromSource as l, isObjectExpression as m, detectFramework as n, hasSsrEntry as o, isMemberExpression as p, inferProjectBindings as r, validateSsrEntries as s, FRAMEWORK_SCAN_DIRS as t, isCallExpression as u };
2476
+ export { SSR_CLIENT_ENTRY_RELATIVE_PATHS as a, validateSsrEntries as c, isCallExpression as d, isIdentifier as f, walk as g, isObjectExpression as h, inferProjectBindings as i, validateSsrEntry as l, isMemberExpression as m, FRAMEWORK_SCAN_DIRS as n, SSR_SERVER_ENTRY_RELATIVE_PATHS as o, isLiteral as p, detectFramework as r, hasSsrEntry as s, DEFAULT_SCAN_DIRS as t, inferBindingsFromSource as u };
@@ -3,8 +3,8 @@ import { n as cliTitle } from "./output-BwlcIYSR.mjs";
3
3
  import { n as loadVoidAuthConfig, t as findVoidAuthConfig } from "./config-CvHtTM0q.mjs";
4
4
  import { c as R, g as ge, u as Se, y as ye } from "./dist-Dayj3gCK.mjs";
5
5
  import { c as getDatabaseDialect, f as readConfig } from "./config-BIa9HwVX.mjs";
6
- import { t as scanRoutes } from "./scan-C6HMEIdW.mjs";
7
- import { n as detectFramework, r as inferProjectBindings, t as FRAMEWORK_SCAN_DIRS } from "./plugin-inference-oZ6Ybu2_.mjs";
6
+ import { t as scanRoutes } from "./scan-QtRTdh94.mjs";
7
+ import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework } from "./plugin-inference-CCtRkt9O.mjs";
8
8
  import { i as generateDbDts, n as generateQueueTypes, t as generateRouteTypes } from "./route-types-DReF1gUY.mjs";
9
9
  import { n as ensureProjectTsconfig } from "./project-tsconfig-DfkESbDL.mjs";
10
10
  import { t as discoverSchema } from "./discover-B7FkXBLB.mjs";
@@ -1,5 +1,5 @@
1
1
  import { a as join, s as resolve } from "./pathe.M-eThtNZ-D-kmWkCS.mjs";
2
- import { o as hasSsrEntry } from "./plugin-inference-oZ6Ybu2_.mjs";
2
+ import { s as hasSsrEntry } from "./plugin-inference-CCtRkt9O.mjs";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  //#region src/cli/preset.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { t as applyPgAuthMigrations } from "../auth-migrations-BwLPwRgH.mjs";
2
- import { t as createVoidAuthRuntime } from "../better-auth-shared-APuDaPqW.mjs";
2
+ import { t as createVoidAuthRuntime } from "../better-auth-shared-BrfZ78iY.mjs";
3
3
  //#region src/runtime/better-auth-pg.ts
4
4
  function resolveConnectionString(env) {
5
5
  const connectionString = typeof env.DATABASE_URL === "string" && env.DATABASE_URL.length > 0 ? env.DATABASE_URL : typeof env.HYPERDRIVE?.connectionString === "string" && env.HYPERDRIVE.connectionString.length > 0 ? env.HYPERDRIVE.connectionString : void 0;
@@ -1,5 +1,5 @@
1
1
  import { n as applySqliteAuthMigrations } from "../auth-migrations-BwLPwRgH.mjs";
2
- import { t as createVoidAuthRuntime } from "../better-auth-shared-APuDaPqW.mjs";
2
+ import { t as createVoidAuthRuntime } from "../better-auth-shared-BrfZ78iY.mjs";
3
3
  //#region src/runtime/better-auth.ts
4
4
  async function resolveDatabase(env) {
5
5
  if (!env.DB) throw new Error("auth: Better Auth requires the \"DB\" D1 binding for sqlite apps.");
@@ -0,0 +1,34 @@
1
+ import { LiveClientEvent } from "./live.mjs";
2
+
3
+ //#region src/runtime/live-client.d.ts
4
+ type LiveSubscribeOptions<Data = unknown> = {
5
+ id: string;
6
+ topic: string;
7
+ lastEventId?: string;
8
+ onEvent?: (event: LiveClientEvent<Data>) => void;
9
+ };
10
+ type ConnectLiveStreamOptions = {
11
+ withCredentials?: boolean;
12
+ fetch?: typeof fetch;
13
+ headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
14
+ eventSource?: EventSourceConstructor;
15
+ keepOpen?: boolean;
16
+ retryDelay?: number;
17
+ onError?: (error: Event | Error) => void;
18
+ };
19
+ type LiveClient = {
20
+ readonly connectionId: string;
21
+ subscribe<Data = unknown>(options: LiveSubscribeOptions<Data>): Promise<() => Promise<void>>;
22
+ close(): void;
23
+ };
24
+ type EventSourceLike = {
25
+ addEventListener(type: string, listener: (event: Event) => void): void;
26
+ removeEventListener(type: string, listener: (event: Event) => void): void;
27
+ close(): void;
28
+ };
29
+ type EventSourceConstructor = new (url: string, options?: {
30
+ withCredentials?: boolean;
31
+ }) => EventSourceLike;
32
+ declare function connectLiveStream(url: string | URL, options?: ConnectLiveStreamOptions): LiveClient;
33
+ //#endregion
34
+ export { ConnectLiveStreamOptions, LiveClient, LiveSubscribeOptions, connectLiveStream };