@lunora/vite 1.0.0-alpha.5 → 1.0.0-alpha.50

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.d.mts CHANGED
@@ -14,6 +14,15 @@ type CloudflarePluginOptions = Record<string, unknown>;
14
14
  */
15
15
  type OverlayPluginOptions = NonNullable<Parameters<typeof errorOverlayPlugin>[0]>;
16
16
  interface LunoraPluginOptions {
17
+ /**
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
+ */
25
+ allowUnauthenticatedShardAccess?: boolean;
17
26
  /**
18
27
  * Which machine-readable API spec(s) codegen emits into `_generated/`.
19
28
  * `"openapi"` (default) writes `openapi.json` (OpenAPI 3.1; RPC + REST),
@@ -43,6 +52,7 @@ interface LunoraPluginOptions {
43
52
  }
44
53
  /** Resolved options after merging defaults. */
45
54
  interface ResolvedLunoraPluginOptions {
55
+ allowUnauthenticatedShardAccess: boolean;
46
56
  apiSpec: NonNullable<CodegenOptions["apiSpec"]>;
47
57
  cloudflare: false | CloudflarePluginOptions;
48
58
  generatedDir: string;
@@ -63,6 +73,23 @@ type LunoraPlugins = Plugin[];
63
73
  * inside the lunora schema directory.
64
74
  */
65
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;
66
93
  interface ReconcileResult {
67
94
  /** `true` when `wrangler.jsonc` was rewritten. */
68
95
  changed: boolean;
@@ -86,14 +113,23 @@ interface ReconcileResult {
86
113
  * the generated value.
87
114
  */
88
115
  declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
116
+ /** Vite plugin (serve-only) that writes the dev-server state record on listen and clears it on close. */
117
+ declare const devStatePlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
89
118
  /**
90
- * Dev-only Vite plugin that offers to scaffold `.dev.vars` before the worker
91
- * boots. `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`,
92
- * but the file is gitignored — so a fresh clone has none and the worker throws
93
- * on the first required secret (e.g. `AUTH_SECRET is required`). When a
94
- * `.dev.vars.example` exists, we prompt to generate `.dev.vars` from it with
95
- * secrets auto-filled. Identical behaviour to `lunora dev` — both call
96
- * `ensureDevVariables` from `@lunora/config`.
119
+ * Dev-only Vite plugin that prepares `.dev.vars` before the worker boots.
120
+ * `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`, but the
121
+ * file is gitignored — so a fresh clone has none and the worker throws on the
122
+ * first required secret (e.g. `AUTH_SECRET is required`). Two steps, both shared
123
+ * with `lunora dev` via `@lunora/config`.
124
+ *
125
+ * First, {@link ensureDevVariables}: when a `.dev.vars.example` exists, prompt
126
+ * to generate `.dev.vars` from it with secrets auto-filled. Second,
127
+ * {@link fillDevSecrets}: fill any empty/placeholder secret already in
128
+ * `.dev.vars` (a `lunora add`-scaffolded project writes secrets blank) and
129
+ * ensure `LUNORA_ADMIN_TOKEN` is present + generated — so the worker boots with
130
+ * working secrets and the Studio authenticates without its login gate. No
131
+ * prompt: it only generates locally-derivable values and never overwrites a real
132
+ * one.
97
133
  *
98
134
  * Runs in `configResolved` (awaited by Vite) so it completes before the
99
135
  * Cloudflare plugin reads the file. Non-interactive runs decline silently.
@@ -198,7 +234,7 @@ declare const isAutoComposable: (context: LunoraPluginContext) => boolean;
198
234
  * virtual module id. Absolute paths are resolved correctly in all environments
199
235
  * (Vite 8 + rolldown 1.x confirmed).
200
236
  */
201
- declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, hasContainers?: boolean, useUmbrella?: boolean) => string;
237
+ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, hasContainers?: boolean, useUmbrella?: boolean, allowUnauthenticatedShardAccess?: boolean) => string;
202
238
  /**
203
239
  * Vite plugin that auto-composes a detected class-A meta-framework's SSR
204
240
  * handler with Lunora into one Cloudflare Worker (PLAN4 §2.4 / §3 class-A row).
@@ -221,6 +257,27 @@ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedIm
221
257
  */
222
258
  declare const frameworkComposePlugin: (options: ResolvedLunoraPluginOptions, context: LunoraPluginContext) => Plugin;
223
259
  /**
260
+ * The custom HMR event the Lunora Vite plugin sends on the client environment's
261
+ * hot channel after a successful codegen run, in place of the old blanket
262
+ * browser `full-reload`. The generated `api`/`server` modules are just
263
+ * `FunctionReference` metadata, so Vite's granular module HMR re-imports the
264
+ * changed `_generated/*` in place; this event is a non-destructive nudge that
265
+ * lets open WebSocket subscriptions, optimistic state, the offline queue, and
266
+ * form state survive a schema save.
267
+ *
268
+ * Kept in its own module (a single source of truth) so the codegen plugin —
269
+ * whose sole export is the plugin factory — can reference it without becoming a
270
+ * mixed default+named module, and so any future client-side listener can agree
271
+ * on the exact string.
272
+ *
273
+ * There is no first-party client listener yet: `@lunora/client` / `@lunora/react`
274
+ * ship as pre-bundled, side-effect-free dependencies where `import.meta.hot` is
275
+ * `undefined` at runtime (Vite's dep optimizer), so a listener there would be
276
+ * dead (and tree-shaken) code. A future app-local or codegen-emitted listener
277
+ * can import this constant to re-validate active queries over the live socket.
278
+ */
279
+ declare const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
280
+ /**
224
281
  * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
225
282
  * Patches `process.stdout`/`process.stderr` once the dev server is configured
226
283
  * and restores them when it closes.
@@ -281,6 +338,35 @@ declare const withRemoteBindings: (options: CloudflarePluginOptions, isServe: ()
281
338
  * the build/close path). Idempotent cleanup means firing on both is safe.
282
339
  */
283
340
  declare const remoteBindingsCleanupPlugin: (cleanup: () => void) => Plugin;
341
+ /**
342
+ * A `@visulima/vite-overlay` solution finder. Derived from the overlay's own
343
+ * options type so the shape can't drift from the installed package. The overlay
344
+ * runs every finder it's given (custom finders first, then its built-ins),
345
+ * sorted by `priority` descending, and shows the first non-`undefined` result.
346
+ *
347
+ * Note: this type (and {@link Solution}) is re-exported from `@lunora/vite` and
348
+ * intentionally tracks the installed `@visulima/vite-overlay` — if a future
349
+ * overlay release changes the finder contract, that surfaces here as a compile
350
+ * error rather than a silent drift.
351
+ */
352
+ type SolutionFinder = NonNullable<OverlayPluginOptions["solutionFinders"]>[number];
353
+ /** What a finder may return: a Markdown-rendered `{ header?, body }`, or `undefined` to defer. */
354
+ type Solution = NonNullable<Awaited<ReturnType<SolutionFinder["handle"]>>>;
355
+ /**
356
+ * Lunora's solution finder for the dev error overlay. A single finder that
357
+ * delegates to `@lunora/codegen`'s shared rule table (the same table the
358
+ * standalone `lunora dev` CLI prints to the terminal) and returns the first
359
+ * match — so one `priority` slot covers every Lunora rule and the overlay's
360
+ * built-in finders still run for anything we don't recognize (we return
361
+ * `undefined`).
362
+ *
363
+ * Priority is high so a Lunora-specific hint wins over the overlay's generic
364
+ * finder for the same error; a user's own finder can still outrank it with a
365
+ * higher `priority`.
366
+ */
367
+ declare const lunoraSolutionFinder: SolutionFinder;
368
+ /** The finders Lunora injects into the overlay by default. */
369
+ declare const lunoraSolutionFinders: ReadonlyArray<SolutionFinder>;
284
370
  /** Dev-server path the studio SPA is served from. */
285
371
  declare const STUDIO_PATH = "/__lunora";
286
372
  /** Static asset routes the studio document references. */
@@ -358,6 +444,17 @@ declare const withWorkerStartupHint: (plugins: ReadonlyArray<Plugin>) => Plugin[
358
444
  */
359
445
  declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
360
446
  /**
447
+ * Resolve the `overlay` toggle into the overlay plugin's options — or `false` to
448
+ * skip it. Lunora's solution finders are **prepended** so they run before the
449
+ * overlay's built-ins; a user's own finders are appended and can still win per
450
+ * error via a strictly higher `priority` (equal priority keeps Lunora first,
451
+ * since the overlay sorts stably). Lunora also forwards both `error` AND `warn`
452
+ * console calls by default (the overlay's own default is `["error"]` only) so
453
+ * Lunora's branded `warn` advisories surface in the browser too — the user can
454
+ * override `forwardedConsoleMethods`.
455
+ */
456
+ declare const resolveOverlayOption: (overlay: LunoraPluginOptions["overlay"]) => false | OverlayPluginOptions;
457
+ /**
361
458
  * Lunora Vite plugin. Returns a flat array of Vite plugins that:
362
459
  *
363
460
  * 1. Run `@lunora/codegen` on startup + on schema file changes.
@@ -371,4 +468,4 @@ declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions) =>
371
468
  */
372
469
  declare const lunora: (options?: LunoraPluginOptions) => LunoraPlugins;
373
470
  declare const VERSION = "0.0.0";
374
- 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, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, createCommandProbe, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
471
+ export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_API_UPDATED_EVENT, 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, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
package/dist/index.d.ts CHANGED
@@ -14,6 +14,15 @@ type CloudflarePluginOptions = Record<string, unknown>;
14
14
  */
15
15
  type OverlayPluginOptions = NonNullable<Parameters<typeof errorOverlayPlugin>[0]>;
16
16
  interface LunoraPluginOptions {
17
+ /**
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
+ */
25
+ allowUnauthenticatedShardAccess?: boolean;
17
26
  /**
18
27
  * Which machine-readable API spec(s) codegen emits into `_generated/`.
19
28
  * `"openapi"` (default) writes `openapi.json` (OpenAPI 3.1; RPC + REST),
@@ -43,6 +52,7 @@ interface LunoraPluginOptions {
43
52
  }
44
53
  /** Resolved options after merging defaults. */
45
54
  interface ResolvedLunoraPluginOptions {
55
+ allowUnauthenticatedShardAccess: boolean;
46
56
  apiSpec: NonNullable<CodegenOptions["apiSpec"]>;
47
57
  cloudflare: false | CloudflarePluginOptions;
48
58
  generatedDir: string;
@@ -63,6 +73,23 @@ type LunoraPlugins = Plugin[];
63
73
  * inside the lunora schema directory.
64
74
  */
65
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;
66
93
  interface ReconcileResult {
67
94
  /** `true` when `wrangler.jsonc` was rewritten. */
68
95
  changed: boolean;
@@ -86,14 +113,23 @@ interface ReconcileResult {
86
113
  * the generated value.
87
114
  */
88
115
  declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
116
+ /** Vite plugin (serve-only) that writes the dev-server state record on listen and clears it on close. */
117
+ declare const devStatePlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
89
118
  /**
90
- * Dev-only Vite plugin that offers to scaffold `.dev.vars` before the worker
91
- * boots. `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`,
92
- * but the file is gitignored — so a fresh clone has none and the worker throws
93
- * on the first required secret (e.g. `AUTH_SECRET is required`). When a
94
- * `.dev.vars.example` exists, we prompt to generate `.dev.vars` from it with
95
- * secrets auto-filled. Identical behaviour to `lunora dev` — both call
96
- * `ensureDevVariables` from `@lunora/config`.
119
+ * Dev-only Vite plugin that prepares `.dev.vars` before the worker boots.
120
+ * `@cloudflare/vite-plugin` loads `.dev.vars` into the worker's `env`, but the
121
+ * file is gitignored — so a fresh clone has none and the worker throws on the
122
+ * first required secret (e.g. `AUTH_SECRET is required`). Two steps, both shared
123
+ * with `lunora dev` via `@lunora/config`.
124
+ *
125
+ * First, {@link ensureDevVariables}: when a `.dev.vars.example` exists, prompt
126
+ * to generate `.dev.vars` from it with secrets auto-filled. Second,
127
+ * {@link fillDevSecrets}: fill any empty/placeholder secret already in
128
+ * `.dev.vars` (a `lunora add`-scaffolded project writes secrets blank) and
129
+ * ensure `LUNORA_ADMIN_TOKEN` is present + generated — so the worker boots with
130
+ * working secrets and the Studio authenticates without its login gate. No
131
+ * prompt: it only generates locally-derivable values and never overwrites a real
132
+ * one.
97
133
  *
98
134
  * Runs in `configResolved` (awaited by Vite) so it completes before the
99
135
  * Cloudflare plugin reads the file. Non-interactive runs decline silently.
@@ -198,7 +234,7 @@ declare const isAutoComposable: (context: LunoraPluginContext) => boolean;
198
234
  * virtual module id. Absolute paths are resolved correctly in all environments
199
235
  * (Vite 8 + rolldown 1.x confirmed).
200
236
  */
201
- declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, hasContainers?: boolean, useUmbrella?: boolean) => string;
237
+ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedImportBase: string, hasContainers?: boolean, useUmbrella?: boolean, allowUnauthenticatedShardAccess?: boolean) => string;
202
238
  /**
203
239
  * Vite plugin that auto-composes a detected class-A meta-framework's SSR
204
240
  * handler with Lunora into one Cloudflare Worker (PLAN4 §2.4 / §3 class-A row).
@@ -221,6 +257,27 @@ declare const buildWorkerEntrySource: (framework: DetectedFramework, generatedIm
221
257
  */
222
258
  declare const frameworkComposePlugin: (options: ResolvedLunoraPluginOptions, context: LunoraPluginContext) => Plugin;
223
259
  /**
260
+ * The custom HMR event the Lunora Vite plugin sends on the client environment's
261
+ * hot channel after a successful codegen run, in place of the old blanket
262
+ * browser `full-reload`. The generated `api`/`server` modules are just
263
+ * `FunctionReference` metadata, so Vite's granular module HMR re-imports the
264
+ * changed `_generated/*` in place; this event is a non-destructive nudge that
265
+ * lets open WebSocket subscriptions, optimistic state, the offline queue, and
266
+ * form state survive a schema save.
267
+ *
268
+ * Kept in its own module (a single source of truth) so the codegen plugin —
269
+ * whose sole export is the plugin factory — can reference it without becoming a
270
+ * mixed default+named module, and so any future client-side listener can agree
271
+ * on the exact string.
272
+ *
273
+ * There is no first-party client listener yet: `@lunora/client` / `@lunora/react`
274
+ * ship as pre-bundled, side-effect-free dependencies where `import.meta.hot` is
275
+ * `undefined` at runtime (Vite's dep optimizer), so a listener there would be
276
+ * dead (and tree-shaken) code. A future app-local or codegen-emitted listener
277
+ * can import this constant to re-validate active queries over the live socket.
278
+ */
279
+ declare const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
280
+ /**
224
281
  * Vite plugin (serve-only) that formats Lunora worker logs in the terminal.
225
282
  * Patches `process.stdout`/`process.stderr` once the dev server is configured
226
283
  * and restores them when it closes.
@@ -281,6 +338,35 @@ declare const withRemoteBindings: (options: CloudflarePluginOptions, isServe: ()
281
338
  * the build/close path). Idempotent cleanup means firing on both is safe.
282
339
  */
283
340
  declare const remoteBindingsCleanupPlugin: (cleanup: () => void) => Plugin;
341
+ /**
342
+ * A `@visulima/vite-overlay` solution finder. Derived from the overlay's own
343
+ * options type so the shape can't drift from the installed package. The overlay
344
+ * runs every finder it's given (custom finders first, then its built-ins),
345
+ * sorted by `priority` descending, and shows the first non-`undefined` result.
346
+ *
347
+ * Note: this type (and {@link Solution}) is re-exported from `@lunora/vite` and
348
+ * intentionally tracks the installed `@visulima/vite-overlay` — if a future
349
+ * overlay release changes the finder contract, that surfaces here as a compile
350
+ * error rather than a silent drift.
351
+ */
352
+ type SolutionFinder = NonNullable<OverlayPluginOptions["solutionFinders"]>[number];
353
+ /** What a finder may return: a Markdown-rendered `{ header?, body }`, or `undefined` to defer. */
354
+ type Solution = NonNullable<Awaited<ReturnType<SolutionFinder["handle"]>>>;
355
+ /**
356
+ * Lunora's solution finder for the dev error overlay. A single finder that
357
+ * delegates to `@lunora/codegen`'s shared rule table (the same table the
358
+ * standalone `lunora dev` CLI prints to the terminal) and returns the first
359
+ * match — so one `priority` slot covers every Lunora rule and the overlay's
360
+ * built-in finders still run for anything we don't recognize (we return
361
+ * `undefined`).
362
+ *
363
+ * Priority is high so a Lunora-specific hint wins over the overlay's generic
364
+ * finder for the same error; a user's own finder can still outrank it with a
365
+ * higher `priority`.
366
+ */
367
+ declare const lunoraSolutionFinder: SolutionFinder;
368
+ /** The finders Lunora injects into the overlay by default. */
369
+ declare const lunoraSolutionFinders: ReadonlyArray<SolutionFinder>;
284
370
  /** Dev-server path the studio SPA is served from. */
285
371
  declare const STUDIO_PATH = "/__lunora";
286
372
  /** Static asset routes the studio document references. */
@@ -358,6 +444,17 @@ declare const withWorkerStartupHint: (plugins: ReadonlyArray<Plugin>) => Plugin[
358
444
  */
359
445
  declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions) => Plugin;
360
446
  /**
447
+ * Resolve the `overlay` toggle into the overlay plugin's options — or `false` to
448
+ * skip it. Lunora's solution finders are **prepended** so they run before the
449
+ * overlay's built-ins; a user's own finders are appended and can still win per
450
+ * error via a strictly higher `priority` (equal priority keeps Lunora first,
451
+ * since the overlay sorts stably). Lunora also forwards both `error` AND `warn`
452
+ * console calls by default (the overlay's own default is `["error"]` only) so
453
+ * Lunora's branded `warn` advisories surface in the browser too — the user can
454
+ * override `forwardedConsoleMethods`.
455
+ */
456
+ declare const resolveOverlayOption: (overlay: LunoraPluginOptions["overlay"]) => false | OverlayPluginOptions;
457
+ /**
361
458
  * Lunora Vite plugin. Returns a flat array of Vite plugins that:
362
459
  *
363
460
  * 1. Run `@lunora/codegen` on startup + on schema file changes.
@@ -371,4 +468,4 @@ declare const wranglerValidatorPlugin: (options: ResolvedLunoraPluginOptions) =>
371
468
  */
372
469
  declare const lunora: (options?: LunoraPluginOptions) => LunoraPlugins;
373
470
  declare const VERSION = "0.0.0";
374
- 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, VERSION, type ViteRemotePlan, WORKER_STARTUP_HINT, augmentWorkerStartupError, buildStudioUrl, buildWorkerEntrySource, codegenPlugin, createCommandProbe, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
471
+ export { CLASS_A_WIRING, type ClassAWiring, type CloudflarePluginOptions, DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR, LUNORA_API_UPDATED_EVENT, 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, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, isAutoComposable, isWorkerEntryEvalError, logStreamPlugin, lunora, lunoraSolutionFinder, lunoraSolutionFinders, planViteRemoteBindings, reconcileWranglerCrons, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
package/dist/index.mjs CHANGED
@@ -2,21 +2,26 @@ import { cloudflare } from '@cloudflare/vite-plugin';
2
2
  import errorOverlayPlugin from '@visulima/vite-overlay';
3
3
  import { detectAgentRules, claimAgentRulesHint, AGENT_RULES_HINT, detectFramework } from '@lunora/config';
4
4
  export { detectFramework } from '@lunora/config';
5
- import { l as lunoraLine } from './packem_shared/log-Bgkv6QhO.mjs';
6
- import codegenPlugin from './packem_shared/codegenPlugin-CHzvXqK6.mjs';
7
- import devVariablesPlugin from './packem_shared/devVariablesPlugin-DbDf7tmi.mjs';
5
+ import { l as lunoraLine } from './packem_shared/log-BjO9EWah.mjs';
6
+ import codegenPlugin from './packem_shared/codegenPlugin-3AqQzOq0.mjs';
7
+ import containerLogsPlugin from './packem_shared/containerLogsPlugin-DMssU3wb.mjs';
8
+ import devStatePlugin from './packem_shared/devStatePlugin-D7Qc2gKr.mjs';
9
+ import devVariablesPlugin from './packem_shared/devVariablesPlugin-CDNSnvOP.mjs';
8
10
  import { createCommandProbe, withDevWorkerEnv } from './packem_shared/DEV_WORKER_ENV_VALUE-Coo6bgVz.mjs';
9
11
  export { DEV_WORKER_ENV_VALUE, DEV_WORKER_ENV_VAR } from './packem_shared/DEV_WORKER_ENV_VALUE-Coo6bgVz.mjs';
10
- import { frameworkComposePlugin } from './packem_shared/CLASS_A_WIRING-CZVcjgKo.mjs';
11
- export { CLASS_A_WIRING, LUNORA_WORKER_VIRTUAL_ID, buildWorkerEntrySource, isAutoComposable } from './packem_shared/CLASS_A_WIRING-CZVcjgKo.mjs';
12
- import logStreamPlugin from './packem_shared/logStreamPlugin-CqvZ17kd.mjs';
12
+ import { frameworkComposePlugin } from './packem_shared/CLASS_A_WIRING-DEw5sPHs.mjs';
13
+ export { CLASS_A_WIRING, LUNORA_WORKER_VIRTUAL_ID, buildWorkerEntrySource, isAutoComposable } from './packem_shared/CLASS_A_WIRING-DEw5sPHs.mjs';
14
+ import logStreamPlugin from './packem_shared/logStreamPlugin-CVrcDAZ1.mjs';
13
15
  import { planViteRemoteBindings, remoteBindingsCleanupPlugin, withRemoteBindings } from './packem_shared/planViteRemoteBindings-QN5ncUS1.mjs';
14
- import { studioPlugin } from './packem_shared/STUDIO_PATH-5ppCdBHa.mjs';
15
- export { STUDIO_PATH, buildStudioUrl } from './packem_shared/STUDIO_PATH-5ppCdBHa.mjs';
16
+ import { lunoraSolutionFinders } from './packem_shared/lunoraSolutionFinder-BKEAiUJP.mjs';
17
+ export { lunoraSolutionFinder } from './packem_shared/lunoraSolutionFinder-BKEAiUJP.mjs';
18
+ import { studioPlugin } from './packem_shared/STUDIO_PATH-DYspAN3z.mjs';
19
+ export { STUDIO_PATH, buildStudioUrl } from './packem_shared/STUDIO_PATH-DYspAN3z.mjs';
16
20
  import { withWorkerStartupHint } from './packem_shared/WORKER_STARTUP_HINT-DhsXUW8k.mjs';
17
21
  export { WORKER_STARTUP_HINT, augmentWorkerStartupError, isWorkerEntryEvalError } from './packem_shared/WORKER_STARTUP_HINT-DhsXUW8k.mjs';
18
- import { wranglerValidatorPlugin } from './packem_shared/wranglerValidatorPlugin-DggqUjxL.mjs';
22
+ import { wranglerValidatorPlugin } from './packem_shared/wranglerValidatorPlugin-C5VWOD7N.mjs';
19
23
  export { reconcileWranglerCrons } from './packem_shared/reconcileWranglerCrons-PxGwfCp_.mjs';
24
+ export { default as LUNORA_API_UPDATED_EVENT } from './packem_shared/LUNORA_API_UPDATED_EVENT-BrkWk3rr.mjs';
20
25
 
21
26
  const agentRulesHintPlugin = (options) => {
22
27
  return {
@@ -81,6 +86,19 @@ const frameworkDetectPlugin = (options, context) => {
81
86
  };
82
87
  };
83
88
 
89
+ const resolveOverlayOption = (overlay) => {
90
+ if (overlay === false) {
91
+ return false;
92
+ }
93
+ const userOverlay = overlay === true || overlay === void 0 ? {} : overlay;
94
+ return {
95
+ ...userOverlay,
96
+ // After the spread + nullish-coalesce so an explicit `undefined` from the
97
+ // user doesn't erase Lunora's default (the spread would otherwise win).
98
+ forwardedConsoleMethods: userOverlay.forwardedConsoleMethods ?? ["error", "warn"],
99
+ solutionFinders: [...lunoraSolutionFinders, ...userOverlay.solutionFinders ?? []]
100
+ };
101
+ };
84
102
  const resolveOptions = (options) => {
85
103
  const input = options ?? {};
86
104
  const schemaDirectory = input.schemaDir ?? "lunora";
@@ -92,20 +110,13 @@ const resolveOptions = (options) => {
92
110
  } else {
93
111
  cloudflareOption = input.cloudflare;
94
112
  }
95
- let overlayOption;
96
- if (input.overlay === false) {
97
- overlayOption = false;
98
- } else if (input.overlay === true || input.overlay === void 0) {
99
- overlayOption = {};
100
- } else {
101
- overlayOption = input.overlay;
102
- }
103
113
  return {
114
+ allowUnauthenticatedShardAccess: input.allowUnauthenticatedShardAccess ?? false,
104
115
  apiSpec: input.apiSpec ?? "openapi",
105
116
  cloudflare: cloudflareOption,
106
117
  studio: input.studio ?? true,
107
118
  generatedDir: input.generatedDir ?? `${schemaDirectory}/_generated`,
108
- overlay: overlayOption,
119
+ overlay: resolveOverlayOption(input.overlay),
109
120
  projectRoot: input.projectRoot ?? process.cwd(),
110
121
  schemaDir: schemaDirectory,
111
122
  validateWrangler: input.validateWrangler ?? true
@@ -128,6 +139,9 @@ const lunora = (options) => {
128
139
  devVariablesPlugin(resolved),
129
140
  codegenPlugin(resolved),
130
141
  logStreamPlugin(),
142
+ // Registers the running dev server in `.lunora/dev.json` so
143
+ // `lunora dev --background|stop|status|logs` manage Vite projects too.
144
+ devStatePlugin(resolved),
131
145
  agentRulesHintPlugin(resolved)
132
146
  ];
133
147
  if (resolved.studio) {
@@ -140,6 +154,7 @@ const lunora = (options) => {
140
154
  plugins.push(errorOverlayPlugin(resolved.overlay));
141
155
  }
142
156
  if (resolved.cloudflare !== false) {
157
+ plugins.push(containerLogsPlugin(resolved));
143
158
  const remotePlan = planViteRemoteBindings({ projectRoot: resolved.projectRoot });
144
159
  if (remotePlan.enabled && remotePlan.configPath !== void 0) {
145
160
  plugins.push(remoteBindingsCleanupPlugin(remotePlan.cleanup));
@@ -151,4 +166,4 @@ const lunora = (options) => {
151
166
  };
152
167
  const VERSION = "0.0.0";
153
168
 
154
- export { VERSION, codegenPlugin, createCommandProbe, devVariablesPlugin, frameworkComposePlugin, logStreamPlugin, lunora, planViteRemoteBindings, remoteBindingsCleanupPlugin, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
169
+ export { VERSION, codegenPlugin, containerLogsPlugin, createCommandProbe, devStatePlugin, devVariablesPlugin, frameworkComposePlugin, logStreamPlugin, lunora, lunoraSolutionFinders, planViteRemoteBindings, remoteBindingsCleanupPlugin, resolveOverlayOption, studioPlugin, withDevWorkerEnv, withRemoteBindings, withWorkerStartupHint, wranglerValidatorPlugin };
@@ -1,9 +1,13 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { resolve, join } from 'node:path';
3
+ import { LunoraError } from '@lunora/errors';
3
4
 
4
5
  const LUNORA_WORKER_VIRTUAL_ID = "virtual:lunora/worker";
5
6
  const RESOLVED_VIRTUAL_PREFIX = "\0";
6
7
  const RESOLVED_LUNORA_WORKER_ID = `${RESOLVED_VIRTUAL_PREFIX}${LUNORA_WORKER_VIRTUAL_ID}`;
8
+ const CLIENT_WORKER_STUB = `// @lunora/vite — the composed worker entry is worker-only and unavailable in the client environment.
9
+ export default {};
10
+ `;
7
11
  const TRAILING_SLASH = /\/$/;
8
12
  const CLASS_A_WIRING = {
9
13
  "react-router": {
@@ -44,10 +48,10 @@ const projectUsesUmbrella = (projectRoot) => {
44
48
  return false;
45
49
  }
46
50
  };
47
- const buildWorkerEntrySource = (framework, generatedImportBase, hasContainers = false, useUmbrella = false) => {
51
+ const buildWorkerEntrySource = (framework, generatedImportBase, hasContainers = false, useUmbrella = false, allowUnauthenticatedShardAccess = false) => {
48
52
  const wiring = CLASS_A_WIRING[framework];
49
53
  if (wiring === void 0) {
50
- throw new Error(`[lunora] no class-A worker wiring for framework "${framework}"`);
54
+ throw new LunoraError("INTERNAL", `[lunora] no class-A worker wiring for framework "${framework}"`);
51
55
  }
52
56
  const runtimeModule = useUmbrella ? "lunorash/runtime" : "@lunora/runtime";
53
57
  const containersReexport = hasContainers ? `
@@ -69,7 +73,7 @@ let worker;
69
73
 
70
74
  export default {
71
75
  async fetch(request, env, context) {
72
- worker ??= composeWorker({
76
+ worker ??= composeWorker({${allowUnauthenticatedShardAccess ? "\n allowUnauthenticatedShardAccess: true," : ""}
73
77
  functions: LUNORA_FUNCTIONS,
74
78
  httpRouter: ${wiring.handler},
75
79
  openApiSpec,
@@ -88,8 +92,17 @@ const frameworkComposePlugin = (options, context) => {
88
92
  return {
89
93
  load(id) {
90
94
  if (id === RESOLVED_LUNORA_WORKER_ID && isWorkerVirtualActive(context) && context.framework !== void 0) {
95
+ if (this.environment.name === "client") {
96
+ return CLIENT_WORKER_STUB;
97
+ }
91
98
  const hasContainers = existsSync(join(generatedImportBase, "containers.ts"));
92
- return buildWorkerEntrySource(context.framework.framework, generatedImportBase, hasContainers, useUmbrella);
99
+ return buildWorkerEntrySource(
100
+ context.framework.framework,
101
+ generatedImportBase,
102
+ hasContainers,
103
+ useUmbrella,
104
+ options.allowUnauthenticatedShardAccess
105
+ );
93
106
  }
94
107
  return void 0;
95
108
  },
@@ -0,0 +1,3 @@
1
+ const LUNORA_API_UPDATED_EVENT = "lunora:api-updated";
2
+
3
+ export { LUNORA_API_UPDATED_EVENT as default };
@@ -1,5 +1,5 @@
1
1
  import { detectAgentRules } from '@lunora/config';
2
- import { handleSeedRequest, handleSchemaEditRequest, handlePolicyScaffoldRequest, SEED_ENDPOINT, SCHEMA_EDIT_ENDPOINT, POLICY_SCAFFOLD_ENDPOINT, serveJsonHandler, renderStudioHtml, resolveAdminToken, studioAssetsStamp, loadStudioAssets } from '@lunora/config/studio-host';
2
+ import { handleSeedRequest, handleSchemaEditRequest, handlePolicyScaffoldRequest, SEED_ENDPOINT, SCHEMA_EDIT_ENDPOINT, POLICY_SCAFFOLD_ENDPOINT, serveJsonHandler, isStandaloneModulePath, renderStudioHtml, resolveAdminToken, studioAssetsStamp, loadStudioAssets, readStandaloneAsset, assetContentType } from '@lunora/config/studio-host';
3
3
 
4
4
  const STUDIO_PATH = "/__lunora";
5
5
  const STUDIO_SCRIPT_PATH = `${STUDIO_PATH}/studio.js`;
@@ -113,7 +113,7 @@ const createStudioHandler = (server, isNonLoopbackBind) => {
113
113
  let assetsStamp;
114
114
  let html;
115
115
  const projectRoot = server.config.root ?? process.cwd();
116
- const serveStaticAsset = (pathname, response) => {
116
+ const serveStaticAsset = (pathname, request, response) => {
117
117
  const stamp = studioAssetsStamp();
118
118
  if (assets === void 0 || stamp !== assetsStamp) {
119
119
  assets = loadStudioAssets(server.config.logger);
@@ -125,8 +125,30 @@ const createStudioHandler = (server, isNonLoopbackBind) => {
125
125
  response.end("Lunora studio assets not found — install and build @lunora/studio.");
126
126
  return;
127
127
  }
128
- const isScript = pathname === STUDIO_SCRIPT_PATH;
129
- sendOk(response, isScript ? assets.script : assets.styles, isScript ? "text/javascript; charset=utf-8" : "text/css; charset=utf-8");
128
+ const isStyle = pathname === STUDIO_STYLE_PATH;
129
+ const fileName = pathname.slice(pathname.lastIndexOf("/") + 1);
130
+ const etag = stamp === void 0 ? void 0 : `W/"${fileName}-${String(stamp)}"`;
131
+ response.setHeader("Cache-Control", "no-cache");
132
+ if (etag !== void 0) {
133
+ response.setHeader("ETag", etag);
134
+ if (headerValue(request.headers?.["if-none-match"]) === etag.toLowerCase()) {
135
+ response.statusCode = 304;
136
+ response.end();
137
+ return;
138
+ }
139
+ }
140
+ if (isStyle) {
141
+ sendOk(response, assets.styles, "text/css; charset=utf-8");
142
+ return;
143
+ }
144
+ const bytes = readStandaloneAsset(fileName);
145
+ if (bytes === void 0) {
146
+ response.statusCode = 404;
147
+ response.setHeader("Content-Type", "text/plain");
148
+ response.end("Not found");
149
+ return;
150
+ }
151
+ sendOk(response, bytes, assetContentType(fileName));
130
152
  };
131
153
  return (request, response, next) => {
132
154
  const pathname = pathnameOf(request.url ?? "");
@@ -154,8 +176,8 @@ const createStudioHandler = (server, isNonLoopbackBind) => {
154
176
  serveJsonHandler(request, response, jsonHandler, projectRoot);
155
177
  return;
156
178
  }
157
- if (pathname === STUDIO_SCRIPT_PATH || pathname === STUDIO_STYLE_PATH) {
158
- serveStaticAsset(pathname, response);
179
+ if (pathname === STUDIO_STYLE_PATH || isStandaloneModulePath(pathname)) {
180
+ serveStaticAsset(pathname, request, response);
159
181
  return;
160
182
  }
161
183
  html ??= renderStudioHtml({