@lunora/vite 1.0.0-alpha.42 → 1.0.0-alpha.421

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.
Files changed (34) hide show
  1. package/LICENSE.md +6 -0
  2. package/README.md +12 -2
  3. package/dist/index.d.mts +446 -332
  4. package/dist/index.d.ts +446 -332
  5. package/dist/index.mjs +4 -164
  6. package/dist/packem_shared/CLASS_A_WIRING-CDSSmDqw.mjs +29 -0
  7. package/dist/packem_shared/LUNORA_API_UPDATED_EVENT-CO2Rv2re.mjs +1 -0
  8. package/dist/packem_shared/WORKER_STARTUP_HINT-COlRTY32.mjs +5 -0
  9. package/dist/packem_shared/build-session-D75JzvIT.mjs +1 -0
  10. package/dist/packem_shared/buildStudioUrl-B9K0wAjC.mjs +1 -0
  11. package/dist/packem_shared/checkLunoraProxy-BNPgNWtV.mjs +1 -0
  12. package/dist/packem_shared/codegenPlugin-2ycHgwJC.mjs +3 -0
  13. package/dist/packem_shared/containerLogsPlugin-CWF3LHN3.mjs +1 -0
  14. package/dist/packem_shared/devStatePlugin-CF4GDvBn.mjs +1 -0
  15. package/dist/packem_shared/devVariablesPlugin-Bm5X49VR.mjs +1 -0
  16. package/dist/packem_shared/logStreamPlugin-EMXiy6pI.mjs +3 -0
  17. package/dist/packem_shared/lunoraSolutionFinder--J0x2mAM.mjs +1 -0
  18. package/dist/packem_shared/planViteRemoteBindings-DYUUW67d.mjs +1 -0
  19. package/dist/packem_shared/server-close-DWiO4Vxb.mjs +1 -0
  20. package/dist/packem_shared/wranglerValidatorPlugin-CPPKubFC.mjs +1 -0
  21. package/package.json +8 -9
  22. package/dist/packem_shared/CLASS_A_WIRING-DWYL4g1x.mjs +0 -118
  23. package/dist/packem_shared/DEV_WORKER_ENV_VALUE-Coo6bgVz.mjs +0 -36
  24. package/dist/packem_shared/STUDIO_PATH-yREc3Bbm.mjs +0 -221
  25. package/dist/packem_shared/WORKER_STARTUP_HINT-DhsXUW8k.mjs +0 -81
  26. package/dist/packem_shared/codegenPlugin-B_ayaObq.mjs +0 -207
  27. package/dist/packem_shared/containerLogsPlugin-DMssU3wb.mjs +0 -50
  28. package/dist/packem_shared/devVariablesPlugin-CDNSnvOP.mjs +0 -19
  29. package/dist/packem_shared/log-BjO9EWah.mjs +0 -8
  30. package/dist/packem_shared/logStreamPlugin-CqvZ17kd.mjs +0 -61
  31. package/dist/packem_shared/lunoraSolutionFinder-BKEAiUJP.mjs +0 -17
  32. package/dist/packem_shared/planViteRemoteBindings-QN5ncUS1.mjs +0 -50
  33. package/dist/packem_shared/reconcileWranglerCrons-PxGwfCp_.mjs +0 -29
  34. package/dist/packem_shared/wranglerValidatorPlugin-CEoJEghS.mjs +0 -66
package/dist/index.d.mts CHANGED
@@ -1,52 +1,112 @@
1
1
  import { CodegenOptions } from '@lunora/codegen';
2
2
  import errorOverlayPlugin from '@visulima/vite-overlay';
3
3
  import { Plugin } from 'vite';
4
- import { FrameworkDetection, DetectedFramework, materializeRemoteWranglerConfig, readProjectRemotePreference } from '@lunora/config';
5
- export { type DetectedFramework, type FrameworkClass, type FrameworkDetection, detectFramework } from '@lunora/config';
4
+ import { DiscoveryCache, FrameworkDetection, DetectedFramework, GeneratedClassModule, readProjectRemotePreference } from '@lunora/config';
5
+ export { type DetectedFramework, type FrameworkClass, type FrameworkDetection, GENERATED_CLASS_MODULES, type GeneratedClassModule, detectFramework } from '@lunora/config';
6
+ import { materializeDevWranglerConfig, WithheldBinding } from '@lunora/config/cloudflare';
7
+ export { type ReconcileCronsResult as ReconcileResult, reconcileWranglerCrons } from '@lunora/config/cloudflare';
6
8
  import { AddressInfo } from 'node:net';
9
+ export { STUDIO_PATH } from '@lunora/config/studio-host';
7
10
  /** Options forwarded to `@cloudflare/vite-plugin`'s cloudflare plugin. */
8
11
  type CloudflarePluginOptions = Record<string, unknown>;
9
12
  /**
10
- * Options forwarded to `@visulima/vite-overlay`'s error-overlay plugin. Derived
11
- * from the plugin's own factory signature so it tracks the real shape
12
- * (`forwardConsole`, `forwardedConsoleMethods`, `reactPluginName`,
13
- * `solutionFinders`, `showBallonButton`, `vuePluginName`, …).
14
- */
13
+ * Options forwarded to `@visulima/vite-overlay`'s error-overlay plugin. Derived
14
+ * from the plugin's own factory signature so it tracks the real shape
15
+ * (`forwardConsole`, `forwardedConsoleMethods`, `reactPluginName`,
16
+ * `solutionFinders`, `showBallonButton`, `vuePluginName`, …).
17
+ */
15
18
  type OverlayPluginOptions = NonNullable<Parameters<typeof errorOverlayPlugin>[0]>;
19
+ /**
20
+ * Shard Durable Object configuration for the AUTO-COMPOSED class-A worker.
21
+ *
22
+ * A class-A app (TanStack Start, vinext, React Router, SolidStart) has no
23
+ * hand-written worker entry — that is what makes it class A — so it never calls
24
+ * the generated `defineApp()` builder and never reaches `createShardDO(config)`.
25
+ * The composed entry emitted `createShardDO()` bare, which left `cdc` and the
26
+ * whole reactive query cache unreachable for every class-A template no matter
27
+ * what the app wanted. `vite.config.ts` is the one place such an app configures
28
+ * Lunora, so it is where these land — the same route
29
+ * {@link LunoraPluginOptions.allowUnauthenticatedShardAccess} already takes into
30
+ * the same emitted entry.
31
+ *
32
+ * Deliberately only the PLAIN-DATA half of the generated `ShardDOConfig`. The
33
+ * rest of that type is `(env) => …` factories (`scheduler`, `storage`,
34
+ * `vectors`, …) which cannot be written in a config object and which a class-A
35
+ * app reaches by writing its own entry instead.
36
+ *
37
+ * Ignored for class B/C: those pass their config to `createShardDO` directly (or
38
+ * through `defineApp`), and an explicit argument there is unaffected by this.
39
+ */
40
+ interface LunoraShardConfig {
41
+ /** Opt into change-data-capture: every write records a post-image to `__cdc_log`. Backs streaming export, replay-PITR, and shard-local `defineShape` replication. Off by default. */
42
+ cdc?: boolean;
43
+ /** Ceiling on the join keys one relation-crossing `where` predicate may pre-resolve via semijoin before failing closed. Omit for the engine default. */
44
+ maxRelationKeys?: number;
45
+ /**
46
+ * Enable the per-shard reactive query cache: `true` for the defaults, or an
47
+ * options object to tune the caps. Query results are memoized by
48
+ * `(functionPath, args, identity)` and invalidated by the ctx-db write hooks
49
+ * before the subscription broadcast, so a subscriber never observes a
50
+ * pre-write value. Omitted (or `false`) keeps every dispatch re-running its
51
+ * handler.
52
+ */
53
+ reactiveCache?: boolean | {
54
+ maxBytes?: number;
55
+ maxEntries?: number;
56
+ };
57
+ /** Resolution policy for a relation-crossing `where` whose child is co-located in this shard: `"auto"` (cost-based, the engine default), `"always"` (inline correlated EXISTS) or `"never"` (universal semijoin). All three return identical rows. */
58
+ relationExistsPushDown?: "always" | "auto" | "never";
59
+ }
16
60
  interface LunoraPluginOptions {
17
61
  /**
18
- * Allow a client-named NON-default shard / cross-shard fan-out WITHOUT an
19
- * `authorizeShard`/`authorizeFanOut` callback. The auto-composed class-A worker
20
- * (`virtual:lunora/worker`) default-denies such access (403 `FORBIDDEN_SHARD`);
21
- * set this `true` to opt into open access — only safe when every table is
22
- * protected by per-row RLS. A production sharded app should configure
23
- * `authorizeShard` instead (via a hand-written class-B worker). Defaults to `false`.
24
- */
62
+ * Allow a client-named NON-default shard / cross-shard fan-out WITHOUT an
63
+ * `authorizeShard`/`authorizeFanOut` callback. The auto-composed class-A worker
64
+ * (`virtual:lunora/worker`) default-denies such access (403 `FORBIDDEN_SHARD`);
65
+ * set this `true` to opt into open access — only safe when every table is
66
+ * protected by per-row RLS. A production sharded app should configure
67
+ * `authorizeShard` instead (via a hand-written class-B worker). Defaults to `false`.
68
+ */
25
69
  allowUnauthenticatedShardAccess?: boolean;
26
70
  /**
27
- * Which machine-readable API spec(s) codegen emits into `_generated/`.
28
- * `"openapi"` (default) writes `openapi.json` (OpenAPI 3.1; RPC + REST),
29
- * `"openrpc"` writes `openrpc.json` (OpenRPC 1.x; RPC-only), `"both"` writes
30
- * both, and `"none"` writes neither. Forwarded to `runCodegen({ apiSpec })`;
31
- * the value set is derived from `CodegenOptions` so it can't drift.
32
- */
71
+ * Which machine-readable API spec(s) codegen emits into `_generated/`.
72
+ * `"openapi"` (default) writes `openapi.json` (OpenAPI 3.1; RPC + REST),
73
+ * `"openrpc"` writes `openrpc.json` (OpenRPC 1.x; RPC-only), `"both"` writes
74
+ * both, and `"none"` writes neither. Forwarded to `runCodegen({ apiSpec })`;
75
+ * the value set is derived from `CodegenOptions` so it can't drift.
76
+ */
33
77
  apiSpec?: CodegenOptions["apiSpec"];
34
78
  /** Pass through to `@cloudflare/vite-plugin`. Pass `false` to opt out. Defaults to `true`. */
35
79
  cloudflare?: boolean | CloudflarePluginOptions;
36
- /** Directory name (relative to `projectRoot`) where generated files are written. Defaults to `"lunora/_generated"`. */
37
- generatedDir?: string;
38
80
  /**
39
- * Inject `@visulima/vite-overlay` for runtime errors (dev only). Pass
40
- * `false` to opt out, or an options object to forward to the overlay.
41
- * Defaults to `true`.
42
- */
81
+ * Inject `@visulima/vite-overlay` for runtime errors (dev only). Pass
82
+ * `false` to opt out, or an options object to forward to the overlay.
83
+ * Defaults to `true`.
84
+ */
43
85
  overlay?: boolean | OverlayPluginOptions;
44
86
  /** Project root containing the `lunora/` directory. Defaults to `process.cwd()`. */
45
87
  projectRoot?: string;
46
88
  /** Directory name (relative to `projectRoot`) containing `schema.ts` and function files. Defaults to `"lunora"`. */
47
89
  schemaDir?: string;
90
+ /**
91
+ * Shard DO configuration baked into the auto-composed class-A worker entry —
92
+ * see {@link LunoraShardConfig}. The ONLY way a class-A app can set `cdc` or
93
+ * enable the reactive query cache, since it has no worker entry to call
94
+ * `createShardDO(config)` from. Ignored for class B/C. Defaults to `{}`
95
+ * (byte-identical composed output).
96
+ */
97
+ shard?: LunoraShardConfig;
48
98
  /** Serve the Lunora studio at `/__lunora` during dev. Pass `false` to opt out. Defaults to `true`. */
49
99
  studio?: boolean;
100
+ /**
101
+ * Deploy target the emitted `ctx.*` surface is tailored to. Defaults to
102
+ * `"target"` in `lunora.config.*`, then `"cloudflare"` — so an existing project
103
+ * emits byte-identical output.
104
+ *
105
+ * Set it here only to override the project config for one build — keeping
106
+ * this and `lunora deploy` on the same target is what the shared resolution
107
+ * in `@lunora/config` exists to guarantee.
108
+ */
109
+ target?: string;
50
110
  /** Validate that `wrangler.jsonc` declares the bindings the schema implies. Defaults to `true`. */
51
111
  validateWrangler?: boolean;
52
112
  }
@@ -55,156 +115,126 @@ interface ResolvedLunoraPluginOptions {
55
115
  allowUnauthenticatedShardAccess: boolean;
56
116
  apiSpec: NonNullable<CodegenOptions["apiSpec"]>;
57
117
  cloudflare: false | CloudflarePluginOptions;
118
+ /**
119
+ * Where codegen writes `_generated/*`, always `<schemaDir>/_generated`.
120
+ *
121
+ * NOT a user option: codegen hardcodes that path (`run-codegen` joins
122
+ * `lunoraDirectory` with `"_generated"`), so a settable override was a no-op
123
+ * everywhere except `frameworkComposePlugin`, which uses it as the composed
124
+ * class-A worker's import base — where a non-default value pointed the
125
+ * emitted imports at a directory nothing writes and broke class-A dev and
126
+ * build. Derived, so the import base cannot disagree with the emitter.
127
+ */
58
128
  generatedDir: string;
129
+ /** `LUNORA_LAZY_FUNCTIONS`, which `lunora dev`/`build` set for this process; `codegen.lazyFunctions` in `lunora.config.*` is read by codegen itself. */
130
+ lazyFunctions: boolean;
59
131
  overlay: false | OverlayPluginOptions;
60
132
  projectRoot: string;
61
133
  schemaDir: string;
134
+ shard: LunoraShardConfig;
62
135
  studio: boolean;
136
+ target: string;
63
137
  validateWrangler: boolean;
64
138
  }
65
139
  /**
66
- * The plugins `lunora()` returns. A mutable `Plugin[]` (not `ReadonlyArray`) so
67
- * it slots directly into Vite's `plugins` — which recursively flattens nested
68
- * plugin arrays — without a spread: `plugins: [lunora()]`.
69
- */
140
+ * The plugins `lunora()` returns. A mutable `Plugin[]` (not `ReadonlyArray`) so
141
+ * it slots directly into Vite's `plugins` — which recursively flattens nested
142
+ * plugin arrays — without a spread: `plugins: [lunora()]`.
143
+ */
70
144
  type LunoraPlugins = Plugin[];
71
145
  /**
72
- * Vite plugin that runs `@lunora/codegen` on startup and on file changes
73
- * inside the lunora schema directory.
74
- */
75
- declare const codegenPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
76
- /**
77
- * Dev-only plugin that tails the local dev containers' own stdout/stderr in the
78
- * Vite terminal.
79
- *
80
- * `@cloudflare/vite-plugin` builds and runs each declared container locally via
81
- * Docker (image `cloudflare-dev/&lt;class>:&lt;id>`) but only forwards the *worker's*
82
- * console — the container process's own output is otherwise invisible. This
83
- * plugin attaches to those Docker log streams (via `@lunora/config`'s
84
- * `streamContainerLogs`, which lazy-loads `dockerode`) and prints each line
85
- * through Vite's logger, branded and tagged `container:&lt;name>`.
86
- *
87
- * A no-op when the project declares no containers (the common case): discovery
88
- * returns an empty list, so `dockerode` is never imported and no Docker work
89
- * starts. Set `LUNORA_CONTAINER_LOGS=0` to opt out. A missing/stopped Docker
90
- * engine degrades to a single warning rather than breaking dev.
91
- */
92
- declare const containerLogsPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
93
- interface ReconcileResult {
94
- /** `true` when `wrangler.jsonc` was rewritten. */
95
- changed: boolean;
96
- /** Human-readable reason when reconciliation was skipped (for logging). */
97
- reason?: string;
98
- /** Resolved wrangler path, or `undefined` when none was found. */
99
- wranglerPath?: string;
100
- }
146
+ * Vite plugin that runs `@lunora/codegen` on startup and on file changes
147
+ * inside the lunora schema directory.
148
+ *
149
+ * `discovery` is the startup's shared source-scan memo (see
150
+ * `bindingsProvisionPlugin`); `buildStart`'s binding reconcile reads it and then
151
+ * ends it, so nothing after startup sees a scan from before an edit.
152
+ */
153
+ declare const codegenPlugin: (options: ResolvedLunoraPluginOptions, discovery?: DiscoveryCache) => Plugin;
101
154
  /**
102
- * Reconcile the codegen-derived cron schedules into the project's
103
- * `wrangler.jsonc` `triggers.crons` array, preserving comments and formatting
104
- * via `jsonc-parser`'s structural edits.
105
- *
106
- * When `triggers.crons` already matches `cronTriggers`, nothing is written (so
107
- * we don't churn the file or trip the dev server's file watcher). When the
108
- * project declares no crons, a stale non-empty array is cleared so removed
109
- * crons stop firing.
110
- *
111
- * This intentionally writes the SAME `triggers.crons` shape the
112
- * `@lunora/config` validator accepts, so the wrangler validator never fights
113
- * the generated value.
114
- */
115
- declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
155
+ * Dev-only plugin that tails the local dev containers' own stdout/stderr in the
156
+ * Vite terminal.
157
+ *
158
+ * `@cloudflare/vite-plugin` builds and runs each declared container locally via
159
+ * Docker (image `cloudflare-dev/<class>:<id>`) but only forwards the *worker's*
160
+ * console — the container process's own output is otherwise invisible. This
161
+ * plugin attaches to those Docker log streams (via `@lunora/config`'s
162
+ * `streamContainerLogs`, which lazy-loads `dockerode`) and prints each line
163
+ * through Vite's logger, branded and tagged `container:<name>`.
164
+ *
165
+ * A no-op when the project declares no containers (the common case): discovery
166
+ * returns an empty list, so `dockerode` is never imported and no Docker work
167
+ * starts. Set `LUNORA_CONTAINER_LOGS=0` to opt out. A missing/stopped Docker
168
+ * engine degrades to a single warning rather than breaking dev.
169
+ *
170
+ * `discovery` is the startup's shared source-scan memo, so the container
171
+ * discovery binding inference already ran is not parsed again here.
172
+ */
173
+ declare const containerLogsPlugin: (options: ResolvedLunoraPluginOptions, discovery?: DiscoveryCache) => Plugin;
174
+ /** Vite plugin (serve-only) that writes the dev-server state record on listen and clears it on close. */
175
+ declare const devStatePlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
116
176
  /**
117
- * Dev-only Vite plugin that prepares `.dev.vars` before the worker boots.
118
- * `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`, but the
119
- * file is gitignored — so a fresh clone has none and the worker throws on the
120
- * first required secret (e.g. `AUTH_SECRET is required`). Two steps, both shared
121
- * with `lunora dev` via `@lunora/config`.
122
- *
123
- * First, {@link ensureDevVariables}: when a `.dev.vars.example` exists, prompt
124
- * to generate `.dev.vars` from it with secrets auto-filled. Second,
125
- * {@link fillDevSecrets}: fill any empty/placeholder secret already in
126
- * `.dev.vars` (a `lunora add`-scaffolded project writes secrets blank) and
127
- * ensure `LUNORA_ADMIN_TOKEN` is present + generated — so the worker boots with
128
- * working secrets and the Studio authenticates without its login gate. No
129
- * prompt: it only generates locally-derivable values and never overwrites a real
130
- * one.
131
- *
132
- * Runs in `configResolved` (awaited by Vite) so it completes before the
133
- * Cloudflare plugin reads the file. Non-interactive runs decline silently.
134
- */
177
+ * Dev-only Vite plugin that prepares `.dev.vars` before the worker boots.
178
+ * `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`, but the
179
+ * file is gitignored — so a fresh clone has none and the worker throws on the
180
+ * first required secret (e.g. `AUTH_SECRET is required`). All three steps live in
181
+ * `@lunora/config`, shared with `lunora dev` and `@lunora/rspack`.
182
+ *
183
+ * First, {@link ensureDevVariables}: when a `.dev.vars.example` exists, prompt
184
+ * to generate `.dev.vars` from it with secrets auto-filled. Second,
185
+ * {@link fillDevSecrets}: fill any empty/placeholder secret already in
186
+ * `.dev.vars` that Lunora can mint locally (a `lunora add`-scaffolded project
187
+ * writes secrets blank) and ensure `LUNORA_ADMIN_TOKEN` is present + generated —
188
+ * so the worker boots with working secrets and the Studio authenticates without
189
+ * its login gate. No prompt: it only generates locally-derivable values and
190
+ * never overwrites a real one. Third, {@link ensureDevWorkerEnv}.
191
+ *
192
+ * Runs in `configResolved` (awaited by Vite) so it completes before the
193
+ * Cloudflare plugin reads the file. Non-interactive runs decline silently.
194
+ * Skipped under `vite preview`, which resolves with `command: "serve"` and so
195
+ * runs `apply: "serve"` plugins too — previewing a built app must not prompt to
196
+ * scaffold, or write, a dev secrets file.
197
+ */
135
198
  declare const devVariablesPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
136
199
  /**
137
- * Worker env var the dev tooling sets so the Lunora runtime recognises a
138
- * development deployment (`@lunora/do`'s `isDevEnvironment`) and therefore
139
- * streams every RPC dispatch summary to the terminal by default — the
140
- * `lunora dev` CLI sets the same var via `wrangler dev --var`.
141
- *
142
- * It is injected ONLY during `vite` serve, never a production `vite build`, so
143
- * it can never leak into a deployed worker. A `WORKER_ENV` the user already
144
- * declares (in `wrangler.jsonc` `[vars]` or `.dev.vars`) takes precedence, so
145
- * this only fills the gap when none is set.
146
- */
147
- declare const DEV_WORKER_ENV_VAR = "WORKER_ENV";
148
- declare const DEV_WORKER_ENV_VALUE = "development";
149
- /** The structural slice of `@cloudflare/vite-plugin`'s worker config we read/write. */
150
- /**
151
- * Wrap the cloudflare-plugin options so the dev worker's `vars` gain a
152
- * `WORKER_ENV` of `development` when — and only when — `isServe()` reports a
153
- * `vite` serve. Any `config` customizer the caller already supplied is
154
- * preserved and applied first; an existing `WORKER_ENV` wins, so a user
155
- * override is never clobbered.
156
- */
157
- declare const withDevWorkerEnv: (options: CloudflarePluginOptions, isServe: () => boolean) => CloudflarePluginOptions;
158
- /**
159
- * A Vite plugin that captures the resolved command (`serve` vs `build`) so
160
- * {@link withDevWorkerEnv} injects the dev var only during `vite`, plus an
161
- * `isServe` probe sharing the same closure. `enforce: "pre"` so the command is
162
- * captured before the cloudflare plugin resolves its worker config.
163
- */
164
- declare const createCommandProbe: () => {
165
- isServe: () => boolean;
166
- plugin: Plugin;
167
- };
168
- /**
169
- * Mutable, plugin-shared context. The `lunora()` factory creates one instance
170
- * and threads it through every Lunora sub-plugin, so detection runs once and
171
- * downstream plugins (codegen, composition, the dev hint) read the same result
172
- * without re-scanning `package.json`. PLAN4 §2.4.
173
- */
200
+ * Mutable, plugin-shared context. The `lunora()` factory creates one instance
201
+ * and threads it through every Lunora sub-plugin, so detection runs once and
202
+ * downstream plugins (codegen, composition, the dev hint) read the same result
203
+ * without re-scanning `package.json`. PLAN4 §2.4.
204
+ */
174
205
  interface LunoraPluginContext {
175
206
  /** The detected framework + class, populated during `config` / `configResolved`. `undefined` until detection runs. */
176
207
  framework?: FrameworkDetection;
177
208
  }
178
- /** Create an empty shared context object for one `lunora()` invocation. */
179
209
  /**
180
- * The virtual module id the Lunora plugin resolves to a generated, class-A
181
- * worker entry. A class-A template points its wrangler `main` at this id (or
182
- * re-exports it from a one-line `src/server.ts`) and never hand-writes
183
- * `createWorker({ httpRouter })` — the plugin composes the framework's SSR
184
- * handler under `composeWorker`'s `httpRouter` seam for it.
185
- *
186
- * Exposed publicly so `@lunora/cli`'s build/deploy path and the templates can
187
- * reference the same constant rather than re-typing the literal.
188
- */
210
+ * The virtual module id the Lunora plugin resolves to a generated, class-A
211
+ * worker entry. A class-A template points its wrangler `main` at this id (or
212
+ * re-exports it from a one-line `src/server.ts`) and never hand-writes
213
+ * `createWorker({ httpRouter })` — the plugin composes the framework's SSR
214
+ * handler under `composeWorker`'s `httpRouter` seam for it.
215
+ *
216
+ * Exposed publicly so `@lunora/cli`'s build/deploy path and the templates can
217
+ * reference the same constant rather than re-typing the literal.
218
+ */
189
219
  declare const LUNORA_WORKER_VIRTUAL_ID: string;
190
220
  /**
191
- * Per-class-A-framework wiring the generated worker entry needs: how to obtain
192
- * the framework's SSR handler as a `composeWorker`-compatible `httpRouter`.
193
- *
194
- * `imports` is the full import statement(s) the generated entry needs (each
195
- * framework controls its own import shape — a namespace import, or a named one);
196
- * `handler` is a JS expression (evaluated in the generated module's scope, where
197
- * `imports`' symbols are in scope) that yields an `HttpRouterLike`
198
- * (`{ fetch(request, env?, ctx?) }`). Both are data — not codegen branches — so
199
- * the set of supported class-A frameworks is one readable table and adding a
200
- * framework is a pure data edit.
201
- *
202
- * Honesty note: these handler expressions encode each framework's *documented*
203
- * Cloudflare SSR-handler shape — the same expressions the hand-wired template
204
- * entries use today (React Router's `createRequestHandler` over its virtual
205
- * server build; SolidStart's `cloudflare-module` handler; TanStack Start's
206
- * server entry). The plugin just emits them so the developer doesn't.
207
- */
221
+ * Per-class-A-framework wiring the generated worker entry needs: how to obtain
222
+ * the framework's SSR handler as a `composeWorker`-compatible `httpRouter`.
223
+ *
224
+ * `imports` is the full import statement(s) the generated entry needs (each
225
+ * framework controls its own import shape — a namespace import, or a named one);
226
+ * `handler` is a JS expression (evaluated in the generated module's scope, where
227
+ * `imports`' symbols are in scope) that yields an `HttpRouterLike`
228
+ * (`{ fetch(request, env?, ctx?) }`). Both are data — not codegen branches — so
229
+ * the set of supported class-A frameworks is one readable table and adding a
230
+ * framework is a pure data edit.
231
+ *
232
+ * Honesty note: these handler expressions encode each framework's *documented*
233
+ * Cloudflare SSR-handler shape — the same expressions the hand-wired template
234
+ * entries use today (React Router's `createRequestHandler` over its virtual
235
+ * server build; SolidStart's `cloudflare-module` handler; TanStack Start's
236
+ * server entry). The plugin just emits them so the developer doesn't.
237
+ */
208
238
  interface ClassAWiring {
209
239
  /** JS expression yielding the `httpRouter` ({ fetch }), referencing symbols brought in by `imports`. */
210
240
  handler: string;
@@ -213,236 +243,320 @@ interface ClassAWiring {
213
243
  }
214
244
  declare const CLASS_A_WIRING: Readonly<Partial<Record<DetectedFramework, ClassAWiring>>>;
215
245
  /**
216
- * Whether the detected framework is one the plugin can auto-compose. Only
217
- * class-A frameworks with a known SSR-handler wiring qualify; everything else
218
- * (class B/C, `none`) falls back to the existing flow.
219
- */
246
+ * Whether the detected framework is one the plugin can auto-compose. Only
247
+ * class-A frameworks with a known SSR-handler wiring qualify; everything else
248
+ * (class B/C, `none`) falls back to the existing flow.
249
+ */
220
250
  declare const isAutoComposable: (context: LunoraPluginContext) => boolean;
251
+ /** Trailing `.ts` on the app-config path — the bundler resolves the extension, so the emitted specifier drops it. */
221
252
  /**
222
- * Build the source of the virtual class-A worker entry. Pure (no fs / no Vite),
223
- * so the emitted composition is unit-testable in isolation.
224
- *
225
- * The emitted module imports the framework SSR handler + the project's
226
- * generated artifacts (functions registry, OpenAPI doc, `createShardDO`) and
227
- * composes them through `composeWorker` — reserved `/_lunora/*` paths route to
228
- * Lunora, everything else falls through to the framework SSR handler. The
229
- * `generatedImportBase` MUST be an absolute filesystem path to the `_generated`
230
- * directory. Virtual modules have no real filesystem path, so relative specifiers
231
- * like `./lunora/_generated/functions` cannot be resolved by Vite/rolldown from a
232
- * virtual module id. Absolute paths are resolved correctly in all environments
233
- * (Vite 8 + rolldown 1.x confirmed).
234
- */
235
- declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, hasContainers?: boolean, useUmbrella?: boolean, allowUnauthenticatedShardAccess?: boolean) => string;
253
+ * Build the source of the virtual class-A worker entry. Pure (no fs / no Vite),
254
+ * so the emitted composition is unit-testable in isolation.
255
+ *
256
+ * The emitted module imports the framework SSR handler and the project's
257
+ * generated `defineApp()` builder, and mounts the handler as the app's
258
+ * `httpRouter` — reserved `/_lunora/*` paths route to Lunora, everything else
259
+ * falls through to the framework SSR handler. `.build()` yields the whole
260
+ * module worker (`fetch` / `scheduled` / `queue` / `email`) plus `ShardDO`. The
261
+ * `generatedImportBase` MUST be an absolute filesystem path to the `_generated`
262
+ * directory. Virtual modules have no real filesystem path, so relative specifiers
263
+ * like `./lunora/_generated/functions` cannot be resolved by Vite/rolldown from a
264
+ * virtual module id. Absolute paths are resolved correctly in all environments
265
+ * (Vite 8 + rolldown 1.x confirmed).
266
+ */
267
+ interface WorkerEntryComposition {
268
+ /** Whether to allow unauthenticated shard access — `.extend(...)` on the builder. */
269
+ allowUnauthenticatedShardAccess?: boolean;
270
+ /** Finished specifier for the project's `lunora.config.*`, when it declares an `app` hook. */
271
+ appConfigModule?: string;
272
+ /** The `_generated/` class modules that exist, each star-re-exported. */
273
+ classModules?: ReadonlyArray<GeneratedClassModule>;
274
+ /** Codegen wrote the merge module: export one `LunoraDO` hosting the shard, scheduler and registry (plan 462). */
275
+ mergeDurableObjects?: boolean;
276
+ /** Per-shard knobs, each key named after the builder method that sets it. */
277
+ shard?: LunoraShardConfig;
278
+ }
279
+ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, composition?: WorkerEntryComposition) => string;
236
280
  /**
237
- * Vite plugin that auto-composes a detected class-A meta-framework's SSR
238
- * handler with Lunora into one Cloudflare Worker (PLAN4 §2.4 / §3 class-A row).
239
- *
240
- * Mechanism: it resolves the {@link LUNORA_WORKER_VIRTUAL_ID} virtual module to
241
- * a generated worker entry that wires the framework SSR handler under
242
- * `composeWorker`'s `httpRouter` seam — so the developer never writes
243
- * `createWorker({ httpRouter })`. The composed worker is an ordinary module
244
- * entry, so it HMRs under `@cloudflare/vite-plugin` exactly like a hand-written
245
- * one (PLAN4 M5 risk #5): the virtual entry only imports the framework handler
246
- * and the generated artifacts, both of which the framework's plugin + codegen
247
- * already make HMR-aware.
248
- *
249
- * Safety: it is a strict no-op unless `context.framework.class === "A"` with a
250
- * known wiring. For class-C (SPA) projects and undetected frameworks it
251
- * resolves/loads nothing. `cloudflare: false` does NOT disable the virtual
252
- * entry — it only means "don't add the Cloudflare Vite plugin a second time"
253
- * (the user supplied it themselves); the composed worker must still be
254
- * resolvable so the user-supplied CF plugin can find the wrangler `main`.
255
- */
281
+ * Vite plugin that auto-composes a detected class-A meta-framework's SSR
282
+ * handler with Lunora into one Cloudflare Worker (PLAN4 §2.4 / §3 class-A row).
283
+ *
284
+ * Mechanism: it resolves the {@link LUNORA_WORKER_VIRTUAL_ID} virtual module to
285
+ * a generated worker entry that wires the framework SSR handler under
286
+ * `composeWorker`'s `httpRouter` seam — so the developer never writes
287
+ * `createWorker({ httpRouter })`. The composed worker is an ordinary module
288
+ * entry, so it HMRs under `@cloudflare/vite-plugin` exactly like a hand-written
289
+ * one (PLAN4 M5 risk #5): the virtual entry only imports the framework handler
290
+ * and the generated artifacts, both of which the framework's plugin + codegen
291
+ * already make HMR-aware.
292
+ *
293
+ * Safety: it is a strict no-op unless `context.framework.class === "A"` with a
294
+ * known wiring. For class-C (SPA) projects and undetected frameworks it
295
+ * resolves/loads nothing. `cloudflare: false` does NOT disable the virtual
296
+ * entry — it only means "don't add the Cloudflare Vite plugin a second time"
297
+ * (the user supplied it themselves); the composed worker must still be
298
+ * resolvable so the user-supplied CF plugin can find the wrangler `main`. The
299
+ * vinext template depends on exactly that, so making this plugin honour the
300
+ * option would break it.
301
+ */
256
302
  declare const frameworkComposePlugin: (options: ResolvedLunoraPluginOptions, context: LunoraPluginContext) => Plugin;
257
303
  /**
258
- * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
259
- * Patches `process.stdout`/`process.stderr` once the dev server is configured
260
- * and restores them when it closes.
261
- */
304
+ * The custom HMR event the Lunora Vite plugin sends on the client environment's
305
+ * hot channel after a successful codegen run, in place of the old blanket
306
+ * browser `full-reload`. The generated `api`/`server` modules are just
307
+ * `FunctionReference` metadata, so Vite's granular module HMR re-imports the
308
+ * changed `_generated/*` in place; this event is a non-destructive nudge that
309
+ * lets open WebSocket subscriptions, optimistic state, the offline queue, and
310
+ * form state survive a schema save.
311
+ *
312
+ * Kept in its own module (a single source of truth) so the codegen plugin —
313
+ * whose sole export is the plugin factory — can reference it without becoming a
314
+ * mixed default+named module, and so any future client-side listener can agree
315
+ * on the exact string.
316
+ *
317
+ * There is no first-party client listener yet: `@lunora/client` / `@lunora/react`
318
+ * ship as pre-bundled, side-effect-free dependencies where `import.meta.hot` is
319
+ * `undefined` at runtime (Vite's dep optimizer), so a listener there would be
320
+ * dead (and tree-shaken) code. A future app-local or codegen-emitted listener
321
+ * can import this constant to re-validate active queries over the live socket.
322
+ */
323
+ declare const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
324
+ /**
325
+ * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
326
+ * Patches `process.stdout`/`process.stderr` fresh for each dev-server generation
327
+ * and restores them when that server closes.
328
+ */
262
329
  declare const logStreamPlugin: () => Plugin;
330
+ /**
331
+ * Warnings for one proxy table. Pure + exported so the behavior is unit-testable
332
+ * without booting a dev server.
333
+ */
334
+ declare const checkLunoraProxy: (proxy: Record<string, unknown> | undefined, label: string) => string[];
335
+ /**
336
+ * Warn when a dev/preview proxy routes `/_lunora/*` without `ws: true` (or with an
337
+ * origin-rewriting `changeOrigin`). See the module docs.
338
+ */
339
+ declare const proxyCheckPlugin: () => Plugin;
263
340
  /** The decision a {@link planViteRemoteBindings} call returns. */
264
341
  interface ViteRemotePlan {
265
342
  /** Idempotent disposer for the temp config; always present + safe to call. */
266
343
  cleanup: () => void;
267
344
  /**
268
- * Absolute path to the materialized temp wrangler config to hand the
269
- * cloudflare plugin's `configPath`, or `undefined` when remote mode is off
270
- * or nothing was materialized (no eligible binding, no wrangler file, …).
271
- */
345
+ * Absolute path to the materialized temp wrangler config to hand the
346
+ * cloudflare plugin's `configPath`, or `undefined` when remote mode is off
347
+ * or nothing was materialized (no eligible binding, no wrangler file, …).
348
+ */
272
349
  configPath?: string;
273
350
  /** Whether remote mode was requested for this dev session. */
274
351
  enabled: boolean;
275
352
  /** Why remote mode didn't take effect despite being requested, for logging. */
276
353
  reason?: string;
354
+ /** Remote-only bindings (`ai`, `artifacts`) left out for lack of Cloudflare credentials, for the dev warning. */
355
+ withheld: WithheldBinding[];
277
356
  }
278
357
  /** Inputs to the Vite remote-binding decision — injectable so tests don't touch the env/fs. */
279
358
  interface PlanViteRemoteOptions {
280
359
  /** Injection seam — defaults to the real materializer. */
281
- materialize?: typeof materializeRemoteWranglerConfig;
282
- /** Project root containing `wrangler.jsonc` + the optional `lunora.json`. */
360
+ materialize?: typeof materializeDevWranglerConfig;
361
+ /** Project root containing `wrangler.jsonc` + the optional `lunora.config.*`. */
283
362
  projectRoot: string;
284
- /** Injection seam — defaults to the real `lunora.json` reader. */
363
+ /** Injection seam — defaults to the real `lunora.config.*` reader. */
285
364
  readPreference?: typeof readProjectRemotePreference;
286
365
  /** The raw `LUNORA_REMOTE` env value; defaults to `process.env.LUNORA_REMOTE`. */
287
366
  remoteEnv?: string;
288
367
  }
289
368
  /**
290
- * Decide whether the Vite dev worker uses remote bindings and, if so,
291
- * materialize the temp config. Pure decision + a single fs write via the
292
- * injected materializer; returns a `cleanup` for the dev server's close hook.
293
- *
294
- * There is no `--remote` flag on the Vite path (Vite has no Lunora CLI flags),
295
- * so the precedence reduces to `LUNORA_REMOTE` env > `lunora.json` `remote`.
296
- */
369
+ * Decide whether the Vite dev worker uses remote bindings and, if so,
370
+ * materialize the temp config. Pure decision + a single fs write via the
371
+ * injected materializer; returns a `cleanup` for the dev server's close hook.
372
+ *
373
+ * There is no `--remote` flag on the Vite path (Vite has no Lunora CLI flags),
374
+ * so the precedence reduces to `LUNORA_REMOTE` env > `lunora.config.*` `remote`.
375
+ *
376
+ * Call this from a `config` hook, never at plugin-factory time — see
377
+ * {@link remoteBindingsPlugin} for the two defects that timing caused.
378
+ */
297
379
  declare const planViteRemoteBindings: (options: PlanViteRemoteOptions) => ViteRemotePlan;
298
380
  /**
299
- * Wrap the cloudflare-plugin options so the dev worker loads the materialized
300
- * remote temp config (via `configPath`) when — and only when — remote mode is
301
- * on AND it's a `vite` serve. A `configPath` the caller already set wins (their
302
- * explicit choice), and during a production build nothing is injected, so the
303
- * deployed worker is never affected.
304
- *
305
- * Returns the wrapped options plus the plan, so `index.ts` can register the
306
- * cleanup on a close hook. Materialization happens lazily inside the `configPath`
307
- * resolution path: it's only meaningful during serve, but computing it eagerly
308
- * is harmless (the materializer is a no-op when disabled) and keeps the wiring
309
- * simple — the plan is computed once here.
310
- */
311
- declare const withRemoteBindings: (options: CloudflarePluginOptions, isServe: () => boolean, plan: ViteRemotePlan) => CloudflarePluginOptions;
381
+ * Wrap the cloudflare-plugin options so the dev worker loads the materialized
382
+ * remote temp config (via `configPath`) when — and only when — remote mode is
383
+ * on and a temp config was materialized. A `configPath` the caller already set
384
+ * wins (their explicit choice).
385
+ *
386
+ * Pure decision only — the serve-vs-build gate lives in
387
+ * {@link remoteBindingsPlugin}'s `config` hook, because the resolved Vite
388
+ * `command` is unknown at plugin-factory time. An eager serve check there would
389
+ * always read `command` as undefined and strip `configPath`.
390
+ */
391
+ declare const withRemoteBindings: (options: CloudflarePluginOptions, plan: ViteRemotePlan) => CloudflarePluginOptions;
312
392
  /**
313
- * A tiny Vite plugin that runs the remote temp-config disposer when the dev
314
- * server tears down (`buildEnd` fires on close in serve; `closeBundle` covers
315
- * the build/close path). Idempotent cleanup means firing on both is safe.
316
- */
317
- declare const remoteBindingsCleanupPlugin: (cleanup: () => void) => Plugin;
393
+ * A `enforce: "pre"` plugin that materializes the remote temp wrangler config
394
+ * and injects it into the cloudflare plugin's `configPath` — but only on a
395
+ * `vite` serve, never a production build (so the deployed worker is never
396
+ * affected) — then disposes the temp file when the dev server tears down.
397
+ *
398
+ * Both halves are deferred into the `config` hook, and each deferral closes a
399
+ * defect of its own.
400
+ *
401
+ * The command check: at plugin-factory time Vite has not yet resolved `serve`
402
+ * vs `build`, so it has to run here. An eager factory-time check always read
403
+ * `command` as undefined and stripped `configPath`, so remote bindings never
404
+ * activated on `vite dev` at all.
405
+ *
406
+ * The materialization: the temp config is a COPY of `wrangler.jsonc`, and
407
+ * Lunora provisions the bindings the project's code implies from
408
+ * `bindingsProvisionPlugin`'s own `config` hook — earlier in this same phase,
409
+ * since both are `enforce: "pre"` and that plugin is registered first. (It is a
410
+ * plugin of its own, registered unconditionally, precisely so this copy is not a
411
+ * binding short whenever `validateWrangler` is off — `wranglerValidatorPlugin`
412
+ * only validates, and is registered after this one.) Copying
413
+ * the file at factory time therefore snapshotted it BEFORE that write, and the
414
+ * dev worker booted against a config missing the binding Lunora had just added:
415
+ * a `vite dev` that logged `inferred bindings → AI (Workers AI)`, passed
416
+ * validation, and served a worker with no `env.AI`. That is the remote twin of
417
+ * the local defect the reconcile's move into `config` fixed.
418
+ *
419
+ * The injection mutates the SAME options object handed to `cloudflare()` in
420
+ * place — the cloudflare plugin reads `pluginConfig.configPath` lazily inside
421
+ * its own `config` hook, which runs after this `enforce: "pre"` one, so the
422
+ * injection takes effect.
423
+ *
424
+ * The disposer reads the CURRENT plan rather than a factory-time capture,
425
+ * because no plan exists until `config` has run.
426
+ *
427
+ * When remote mode was requested but nothing materialized (no eligible binding,
428
+ * no wrangler file, …), the plan's `reason` is logged so the degradation isn't
429
+ * silent.
430
+ *
431
+ * `options` is `undefined` on the BYO path (`cloudflare: false`), where the
432
+ * project constructs `cloudflare()` itself and Lunora has no options object to
433
+ * inject into: the materialized path is printed with what to do with it, rather
434
+ * than leaving `LUNORA_REMOTE` looking like it took effect.
435
+ */
436
+ declare const remoteBindingsPlugin: (options: CloudflarePluginOptions | undefined, planOptions: PlanViteRemoteOptions) => Plugin;
318
437
  /**
319
- * A `@visulima/vite-overlay` solution finder. Derived from the overlay's own
320
- * options type so the shape can't drift from the installed package. The overlay
321
- * runs every finder it's given (custom finders first, then its built-ins),
322
- * sorted by `priority` descending, and shows the first non-`undefined` result.
323
- *
324
- * Note: this type (and {@link Solution}) is re-exported from `@lunora/vite` and
325
- * intentionally tracks the installed `@visulima/vite-overlay` — if a future
326
- * overlay release changes the finder contract, that surfaces here as a compile
327
- * error rather than a silent drift.
328
- */
438
+ * A `@visulima/vite-overlay` solution finder. Derived from the overlay's own
439
+ * options type so the shape can't drift from the installed package. The overlay
440
+ * runs every finder it's given (custom finders first, then its built-ins),
441
+ * sorted by `priority` descending, and shows the first non-`undefined` result.
442
+ *
443
+ * Note: this type (and {@link Solution}) is re-exported from `@lunora/vite` and
444
+ * intentionally tracks the installed `@visulima/vite-overlay` — if a future
445
+ * overlay release changes the finder contract, that surfaces here as a compile
446
+ * error rather than a silent drift.
447
+ */
329
448
  type SolutionFinder = NonNullable<OverlayPluginOptions["solutionFinders"]>[number];
330
449
  /** What a finder may return: a Markdown-rendered `{ header?, body }`, or `undefined` to defer. */
331
450
  type Solution = NonNullable<Awaited<ReturnType<SolutionFinder["handle"]>>>;
332
451
  /**
333
- * Lunora's solution finder for the dev error overlay. A single finder that
334
- * delegates to `@lunora/codegen`'s shared rule table (the same table the
335
- * standalone `lunora dev` CLI prints to the terminal) and returns the first
336
- * match — so one `priority` slot covers every Lunora rule and the overlay's
337
- * built-in finders still run for anything we don't recognize (we return
338
- * `undefined`).
339
- *
340
- * Priority is high so a Lunora-specific hint wins over the overlay's generic
341
- * finder for the same error; a user's own finder can still outrank it with a
342
- * higher `priority`.
343
- */
452
+ * Lunora's solution finder for the dev error overlay. A single finder that
453
+ * delegates to `@lunora/codegen`'s shared rule table (the same table the
454
+ * standalone `lunora dev` CLI prints to the terminal) and returns the first
455
+ * match — so one `priority` slot covers every Lunora rule and the overlay's
456
+ * built-in finders still run for anything we don't recognize (we return
457
+ * `undefined`).
458
+ *
459
+ * Priority is high so a Lunora-specific hint wins over the overlay's generic
460
+ * finder for the same error; a user's own finder can still outrank it with a
461
+ * higher `priority`.
462
+ */
344
463
  declare const lunoraSolutionFinder: SolutionFinder;
345
464
  /** The finders Lunora injects into the overlay by default. */
346
465
  declare const lunoraSolutionFinders: ReadonlyArray<SolutionFinder>;
347
- /** Dev-server path the studio SPA is served from. */
348
- declare const STUDIO_PATH = "/__lunora";
349
- /** Static asset routes the studio document references. */
350
-
351
466
  /**
352
- * Build the user-facing studio URL from the dev server's resolved address.
353
- * Pure so it can be unit-tested without a live server. Prefers Vite's own
354
- * `resolvedUrls.local` (honours `host` / `base` / https); falls back to the raw
355
- * socket address, bracketing IPv6 and normalising the wildcard host.
356
- */
467
+ * Build the user-facing studio URL from the dev server's resolved address.
468
+ * Pure so it can be unit-tested without a live server. Prefers Vite's own
469
+ * `resolvedUrls.local` (honours `host` / `base` / https); falls back to the raw
470
+ * socket address, bracketing IPv6 and normalising the wildcard host.
471
+ */
357
472
  declare const buildStudioUrl: (input: {
358
473
  address?: AddressInfo | string;
359
474
  base?: string;
360
475
  resolvedLocal?: string;
361
476
  }) => string;
362
477
  /**
363
- * Vite plugin that serves the composed Lunora studio at
364
- * {@link STUDIO_PATH} during dev and prints its URL once the server is
365
- * listening. Dev-only (`apply: "serve"`); it adds nothing to production builds.
366
- *
367
- * Because `lunora dev` spawns Vite, this makes the studio available on
368
- * `lunora dev` and on a plain `vite` with no per-project files. The studio
369
- * is served as a prebuilt static bundle, independent of the host app.
370
- */
371
- declare const studioPlugin: () => Plugin;
478
+ * Vite plugin that serves the composed Lunora studio at
479
+ * {@link STUDIO_PATH} during dev and prints its URL once the server is
480
+ * listening. Dev-only (`apply: "serve"`); it adds nothing to production builds.
481
+ *
482
+ * Because `lunora dev` spawns Vite, this makes the studio available on
483
+ * `lunora dev` and on a plain `vite` with no per-project files. The studio
484
+ * is served as a prebuilt static bundle, independent of the host app.
485
+ */
486
+ declare const studioPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
372
487
  /**
373
- * When a module under `lunora/` throws while the Worker entry is first
374
- * evaluated, `@cloudflare/vite-plugin` surfaces the failure from deep inside
375
- * its `runner-worker` running in `workerd`. The real error crosses a workerd
376
- * RPC boundary on the way out, which drops the user-code stack frames — so all
377
- * the dev server sees is a bare, file-less message like:
378
- *
379
- * ```
380
- * TypeError: Cannot read properties of undefined (reading 'string')
381
- * at runInRunnerObject (workers/runner-worker/index.js:107:3)
382
- * at getWorkerEntryExportTypes (workers/runner-worker/index.js:246:24)
383
- * ```
384
- *
385
- * The classic cause is a **circular import**: a `lunora/` query/mutation/action
386
- * module runs `mutation({ args: { x: v.string() } })` at the top level while the
387
- * module it imported `v`/`query`/`mutation` from is still mid-initialization, so
388
- * those bindings read as `undefined`. The message names a validator method
389
- * (`'string'`, `'id'`, …) but never the file.
390
- *
391
- * We can't recover the dropped frames at this layer, but we can recognise the
392
- * shape of the failure and append an actionable hint pointing at the likely
393
- * cause — turning a dead-end stack into something a user can act on.
394
- */
488
+ * When a module under `lunora/` throws while the Worker entry is first
489
+ * evaluated, `@cloudflare/vite-plugin` surfaces the failure from deep inside
490
+ * its `runner-worker` running in `workerd`. The real error crosses a workerd
491
+ * RPC boundary on the way out, which drops the user-code stack frames — so all
492
+ * the dev server sees is a bare, file-less message like:
493
+ *
494
+ * ```
495
+ * TypeError: Cannot read properties of undefined (reading 'string')
496
+ * at runInRunnerObject (workers/runner-worker/index.js:107:3)
497
+ * at getWorkerEntryExportTypes (workers/runner-worker/index.js:246:24)
498
+ * ```
499
+ *
500
+ * The classic cause is a **circular import**: a `lunora/` query/mutation/action
501
+ * module runs `mutation({ args: { x: v.string() } })` at the top level while the
502
+ * module it imported `v`/`query`/`mutation` from is still mid-initialization, so
503
+ * those bindings read as `undefined`. The message names a validator method
504
+ * (`'string'`, `'id'`, …) but never the file.
505
+ *
506
+ * We can't recover the dropped frames at this layer, but we can recognise the
507
+ * shape of the failure and append an actionable hint pointing at the likely
508
+ * cause — turning a dead-end stack into something a user can act on.
509
+ */
395
510
  declare const WORKER_STARTUP_HINT: string;
396
511
  /**
397
- * True when `error` looks like a Worker-entry evaluation failure routed through
398
- * `@cloudflare/vite-plugin`'s runner worker (the stack references the runner
399
- * worker / export-types probe). Kept narrow so we only annotate this specific
400
- * class of dev-startup error.
401
- */
512
+ * True when `error` looks like a Worker-entry evaluation failure routed through
513
+ * `@cloudflare/vite-plugin`'s runner worker (the stack references the runner
514
+ * worker / export-types probe). Kept narrow so we only annotate this specific
515
+ * class of dev-startup error.
516
+ */
402
517
  declare const isWorkerEntryEvalError: (error: unknown) => boolean;
403
518
  /**
404
- * Append {@link WORKER_STARTUP_HINT} to a recognised Worker-entry eval error
405
- * (idempotently). Any other value is returned untouched.
406
- */
519
+ * Append {@link WORKER_STARTUP_HINT} to a recognised Worker-entry eval error
520
+ * (idempotently). Any other value is returned untouched.
521
+ */
407
522
  declare const augmentWorkerStartupError: (error: unknown) => unknown;
408
523
  /**
409
- * Wrap the startup hooks of `@cloudflare/vite-plugin`'s plugins so a Worker-entry
410
- * evaluation failure carries the Lunora hint. Returns a new array; the input
411
- * plugins are shallow-cloned (never mutated in place) so re-using the cloudflare
412
- * plugin instances elsewhere stays safe.
413
- */
524
+ * Wrap the startup hooks of `@cloudflare/vite-plugin`'s plugins so a Worker-entry
525
+ * evaluation failure carries the Lunora hint. Returns a new array; the input
526
+ * plugins are shallow-cloned (never mutated in place) so re-using the cloudflare
527
+ * plugin instances elsewhere stays safe.
528
+ */
414
529
  declare const withWorkerStartupHint: (plugins: ReadonlyArray<Plugin>) => Plugin[];
415
530
  /**
416
- * Vite plugin that validates the project's `wrangler.jsonc` against the
417
- * bindings implied by `lunora/schema.ts`. Throws (Vite renders nicely) on
418
- * missing requirements during `configResolved`. Delegates the parsing /
419
- * validation logic to `@lunora/config` so the rules stay in lockstep with
420
- * the CLI (`lunora deploy`).
421
- */
422
- declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
531
+ * Vite plugin that validates the project's `wrangler.jsonc` against the
532
+ * bindings implied by `lunora/schema.ts`. Throws (Vite renders nicely) on
533
+ * missing requirements during `configResolved`. Delegates the parsing /
534
+ * validation logic to `@lunora/config` so the rules stay in lockstep with
535
+ * the CLI (`lunora deploy`).
536
+ *
537
+ * Provisioning runs BEFORE this, in `bindingsProvisionPlugin`'s `config` hook,
538
+ * which is the order `lunora dev` uses (infer → reconcile, no validation pass):
539
+ * the bindings this check requires are the ones Lunora writes itself, so
540
+ * validating first killed the dev server the first time a project declared a
541
+ * `.global()` table or a container. That plugin is registered unconditionally and
542
+ * ahead of this one — the write is not optional the way the check is, and it must
543
+ * land in `config` to reach the worker at all (see its docblock).
544
+ *
545
+ * Skipped under `vite preview`, which resolves with `command: "serve"` and so
546
+ * runs `apply: "serve"` plugins: previewing a built app must not probe Docker.
547
+ */
548
+ declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions, discovery?: DiscoveryCache) => Plugin;
423
549
  /**
424
- * Resolve the `overlay` toggle into the overlay plugin's options — or `false` to
425
- * skip it. Lunora's solution finders are **prepended** so they run before the
426
- * overlay's built-ins; a user's own finders are appended and can still win per
427
- * error via a strictly higher `priority` (equal priority keeps Lunora first,
428
- * since the overlay sorts stably). Lunora also forwards both `error` AND `warn`
429
- * console calls by default (the overlay's own default is `["error"]` only) so
430
- * Lunora's branded `warn` advisories surface in the browser too — the user can
431
- * override `forwardedConsoleMethods`.
432
- */
550
+ * Resolve the `overlay` toggle into the overlay plugin's options — or `false` to
551
+ * skip it. Lunora's solution finders are **prepended** so they run before the
552
+ * overlay's built-ins; a user's own finders are appended and can still win per
553
+ * error via a strictly higher `priority` (equal priority keeps Lunora first,
554
+ * since the overlay sorts stably). Lunora also forwards both `error` AND `warn`
555
+ * console calls by default (the overlay's own default is `["error"]` only) so
556
+ * Lunora's branded `warn` advisories surface in the browser too — the user can
557
+ * override `forwardedConsoleMethods`.
558
+ */
433
559
  declare const resolveOverlayOption: (overlay: LunoraPluginOptions["overlay"]) => false | OverlayPluginOptions;
434
- /**
435
- * Lunora Vite plugin. Returns a flat array of Vite plugins that:
436
- *
437
- * 1. Run `@lunora/codegen` on startup + on schema file changes.
438
- * 2. Validate the project's `wrangler.jsonc` against the schema's implied bindings.
439
- * 3. Inject `@visulima/vite-overlay` for runtime error overlays (unless `overlay: false`).
440
- * 4. Include `@cloudflare/vite-plugin` so users get one-import setup (unless `cloudflare: false`).
441
- *
442
- * `@cloudflare/vite-plugin` and `@visulima/vite-overlay` are direct dependencies,
443
- * so they're imported statically — opt out per-feature via the options rather
444
- * than relying on whether they're installed.
445
- */
446
560
  declare const lunora: (options?: LunoraPluginOptions) => LunoraPlugins;
447
- declare const VERSION = "0.0.0";
448
- export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type OverlayPluginOptions, type PlanViteRemoteOptions, type ReconcileResult, type ResolvedLunoraPluginOptions, STUDIO_PATH, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, containerLogsPlugin, createCommandProbe, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
561
+ declare const VERSION: string;
562
+ export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, LUNORA_API_UPDATED_EVENT, LUNORA_WORKER_VIRTUAL_ID, type LunoraPluginOptions, type LunoraPlugins, type LunoraShardConfig, type OverlayPluginOptions, type PlanViteRemoteOptions, type ResolvedLunoraPluginOptions, type Solution, type SolutionFinder, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, type WorkerEntryComposition, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, checkLunoraProxy, codegenPlugin, containerLogsPlugin, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, proxyCheckPlugin, remoteBindingsPlugin, resolveOverlayOption, studioPlugin, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };