@moku-labs/web 0.5.3 → 0.5.5

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/browser.mjs CHANGED
@@ -633,18 +633,28 @@ function createLogApi(ctx) {
633
633
  }
634
634
  //#endregion
635
635
  //#region src/plugins/log/sinks.ts
636
+ /** Severity rank for threshold comparison (higher = more severe). */
637
+ const LEVEL_RANK = {
638
+ debug: 10,
639
+ info: 20,
640
+ warn: 30,
641
+ error: 40
642
+ };
636
643
  /**
637
644
  * Build the console sink: routes entries by channel — `error` → `console.error`,
638
645
  * `warn` → `console.warn`, and `debug`/`info` → `console.log`. The full entry
639
- * object is forwarded so the console serializes its `event` and `data`.
646
+ * object is forwarded so the console serializes its `event` and `data`. Entries
647
+ * below `minLevel` are dropped (the in-memory trace still records everything).
640
648
  *
649
+ * @param minLevel - Lowest severity to print. Defaults to `"debug"` (print all).
641
650
  * @returns A {@link LogSink} that writes to the matching `console` channel.
642
651
  * @example
643
652
  * ```ts
644
- * state.sinks.push(consoleSink());
653
+ * state.sinks.push(consoleSink("info")); // suppress debug spam
645
654
  * ```
646
655
  */
647
- function consoleSink() {
656
+ function consoleSink(minLevel = "debug") {
657
+ const threshold = LEVEL_RANK[minLevel];
648
658
  return {
649
659
  /**
650
660
  * Route a single entry to the console channel matching its level.
@@ -656,6 +666,7 @@ function consoleSink() {
656
666
  * ```
657
667
  */
658
668
  write(entry) {
669
+ if (LEVEL_RANK[entry.level] < threshold) return;
659
670
  if (entry.level === "error") console.error(entry);
660
671
  else if (entry.level === "warn") console.warn(entry);
661
672
  else console.log(entry);
@@ -663,18 +674,22 @@ write(entry) {
663
674
  }
664
675
  /**
665
676
  * Install mode-selected default sinks at onInit. The in-memory trace is always
666
- * on (`state.entries`); the console sink is added only in dev/production.
677
+ * on (`state.entries`); the console sink is added only in dev/production. `dev`
678
+ * prints everything (debug+); `production` prints `info`+ only, so the per-phase
679
+ * `debug` events (build:bundle, build:pages, …) don't spam a prod build. Both
680
+ * modes still record all levels in the in-memory trace.
667
681
  *
668
682
  * @param ctx - Core plugin context (`{ config, state }`).
669
683
  * @param ctx.config - Resolved log config (`{ mode }`).
670
684
  * @param ctx.state - Mutable log state (`{ entries, sinks }`).
671
685
  * @example
672
686
  * ```ts
673
- * // mode "dev" -> state.sinks === [consoleSink()]; mode "test" -> state.sinks === []
687
+ * // "dev" -> [consoleSink("debug")]; "production" -> [consoleSink("info")]; "test"/"silent" -> []
674
688
  * ```
675
689
  */
676
690
  function installDefaultSinks(ctx) {
677
- if (ctx.config.mode === "dev" || ctx.config.mode === "production") ctx.state.sinks.push(consoleSink());
691
+ if (ctx.config.mode === "dev") ctx.state.sinks.push(consoleSink("debug"));
692
+ else if (ctx.config.mode === "production") ctx.state.sinks.push(consoleSink("info"));
678
693
  }
679
694
  //#endregion
680
695
  //#region src/plugins/log/state.ts
@@ -3288,11 +3303,10 @@ function createSpaKernel(state, config, emit, deps) {
3288
3303
  const region = document.querySelector(resolved.swapSelector);
3289
3304
  if (!region) return false;
3290
3305
  handleStart(pathname);
3291
- const { renderVNode } = await import("./render-BL9Fv6G6.mjs");
3306
+ const { renderVNode } = await import("./render-BNe0s7fr.mjs");
3292
3307
  syncDataHead(hit.route, routeContext);
3293
3308
  unmountPageSpecific(state, emit);
3294
3309
  runSwap(() => {
3295
- region.replaceChildren();
3296
3310
  renderVNode(vnode, region);
3297
3311
  scanAndMount(state, emit, resolved.swapSelector);
3298
3312
  notifyNavEnd(state);
package/dist/index.cjs CHANGED
@@ -667,18 +667,28 @@ function createLogApi(ctx) {
667
667
  }
668
668
  //#endregion
669
669
  //#region src/plugins/log/sinks.ts
670
+ /** Severity rank for threshold comparison (higher = more severe). */
671
+ const LEVEL_RANK = {
672
+ debug: 10,
673
+ info: 20,
674
+ warn: 30,
675
+ error: 40
676
+ };
670
677
  /**
671
678
  * Build the console sink: routes entries by channel — `error` → `console.error`,
672
679
  * `warn` → `console.warn`, and `debug`/`info` → `console.log`. The full entry
673
- * object is forwarded so the console serializes its `event` and `data`.
680
+ * object is forwarded so the console serializes its `event` and `data`. Entries
681
+ * below `minLevel` are dropped (the in-memory trace still records everything).
674
682
  *
683
+ * @param minLevel - Lowest severity to print. Defaults to `"debug"` (print all).
675
684
  * @returns A {@link LogSink} that writes to the matching `console` channel.
676
685
  * @example
677
686
  * ```ts
678
- * state.sinks.push(consoleSink());
687
+ * state.sinks.push(consoleSink("info")); // suppress debug spam
679
688
  * ```
680
689
  */
681
- function consoleSink() {
690
+ function consoleSink(minLevel = "debug") {
691
+ const threshold = LEVEL_RANK[minLevel];
682
692
  return {
683
693
  /**
684
694
  * Route a single entry to the console channel matching its level.
@@ -690,6 +700,7 @@ function consoleSink() {
690
700
  * ```
691
701
  */
692
702
  write(entry) {
703
+ if (LEVEL_RANK[entry.level] < threshold) return;
693
704
  if (entry.level === "error") console.error(entry);
694
705
  else if (entry.level === "warn") console.warn(entry);
695
706
  else console.log(entry);
@@ -697,18 +708,22 @@ write(entry) {
697
708
  }
698
709
  /**
699
710
  * Install mode-selected default sinks at onInit. The in-memory trace is always
700
- * on (`state.entries`); the console sink is added only in dev/production.
711
+ * on (`state.entries`); the console sink is added only in dev/production. `dev`
712
+ * prints everything (debug+); `production` prints `info`+ only, so the per-phase
713
+ * `debug` events (build:bundle, build:pages, …) don't spam a prod build. Both
714
+ * modes still record all levels in the in-memory trace.
701
715
  *
702
716
  * @param ctx - Core plugin context (`{ config, state }`).
703
717
  * @param ctx.config - Resolved log config (`{ mode }`).
704
718
  * @param ctx.state - Mutable log state (`{ entries, sinks }`).
705
719
  * @example
706
720
  * ```ts
707
- * // mode "dev" -> state.sinks === [consoleSink()]; mode "test" -> state.sinks === []
721
+ * // "dev" -> [consoleSink("debug")]; "production" -> [consoleSink("info")]; "test"/"silent" -> []
708
722
  * ```
709
723
  */
710
724
  function installDefaultSinks(ctx) {
711
- if (ctx.config.mode === "dev" || ctx.config.mode === "production") ctx.state.sinks.push(consoleSink());
725
+ if (ctx.config.mode === "dev") ctx.state.sinks.push(consoleSink("debug"));
726
+ else if (ctx.config.mode === "production") ctx.state.sinks.push(consoleSink("info"));
712
727
  }
713
728
  //#endregion
714
729
  //#region src/plugins/log/state.ts
@@ -6686,11 +6701,10 @@ function createSpaKernel(state, config, emit, deps) {
6686
6701
  const region = document.querySelector(resolved.swapSelector);
6687
6702
  if (!region) return false;
6688
6703
  handleStart(pathname);
6689
- const { renderVNode } = await Promise.resolve().then(() => require("./render-BSTM0Akv.cjs"));
6704
+ const { renderVNode } = await Promise.resolve().then(() => require("./render-DLZEOe4M.cjs"));
6690
6705
  syncDataHead(hit.route, routeContext);
6691
6706
  unmountPageSpecific(state, emit);
6692
6707
  runSwap(() => {
6693
- region.replaceChildren();
6694
6708
  renderVNode(vnode, region);
6695
6709
  scanAndMount(state, emit, resolved.swapSelector);
6696
6710
  notifyNavEnd(state);
package/dist/index.mjs CHANGED
@@ -654,18 +654,28 @@ function createLogApi(ctx) {
654
654
  }
655
655
  //#endregion
656
656
  //#region src/plugins/log/sinks.ts
657
+ /** Severity rank for threshold comparison (higher = more severe). */
658
+ const LEVEL_RANK = {
659
+ debug: 10,
660
+ info: 20,
661
+ warn: 30,
662
+ error: 40
663
+ };
657
664
  /**
658
665
  * Build the console sink: routes entries by channel — `error` → `console.error`,
659
666
  * `warn` → `console.warn`, and `debug`/`info` → `console.log`. The full entry
660
- * object is forwarded so the console serializes its `event` and `data`.
667
+ * object is forwarded so the console serializes its `event` and `data`. Entries
668
+ * below `minLevel` are dropped (the in-memory trace still records everything).
661
669
  *
670
+ * @param minLevel - Lowest severity to print. Defaults to `"debug"` (print all).
662
671
  * @returns A {@link LogSink} that writes to the matching `console` channel.
663
672
  * @example
664
673
  * ```ts
665
- * state.sinks.push(consoleSink());
674
+ * state.sinks.push(consoleSink("info")); // suppress debug spam
666
675
  * ```
667
676
  */
668
- function consoleSink() {
677
+ function consoleSink(minLevel = "debug") {
678
+ const threshold = LEVEL_RANK[minLevel];
669
679
  return {
670
680
  /**
671
681
  * Route a single entry to the console channel matching its level.
@@ -677,6 +687,7 @@ function consoleSink() {
677
687
  * ```
678
688
  */
679
689
  write(entry) {
690
+ if (LEVEL_RANK[entry.level] < threshold) return;
680
691
  if (entry.level === "error") console.error(entry);
681
692
  else if (entry.level === "warn") console.warn(entry);
682
693
  else console.log(entry);
@@ -684,18 +695,22 @@ write(entry) {
684
695
  }
685
696
  /**
686
697
  * Install mode-selected default sinks at onInit. The in-memory trace is always
687
- * on (`state.entries`); the console sink is added only in dev/production.
698
+ * on (`state.entries`); the console sink is added only in dev/production. `dev`
699
+ * prints everything (debug+); `production` prints `info`+ only, so the per-phase
700
+ * `debug` events (build:bundle, build:pages, …) don't spam a prod build. Both
701
+ * modes still record all levels in the in-memory trace.
688
702
  *
689
703
  * @param ctx - Core plugin context (`{ config, state }`).
690
704
  * @param ctx.config - Resolved log config (`{ mode }`).
691
705
  * @param ctx.state - Mutable log state (`{ entries, sinks }`).
692
706
  * @example
693
707
  * ```ts
694
- * // mode "dev" -> state.sinks === [consoleSink()]; mode "test" -> state.sinks === []
708
+ * // "dev" -> [consoleSink("debug")]; "production" -> [consoleSink("info")]; "test"/"silent" -> []
695
709
  * ```
696
710
  */
697
711
  function installDefaultSinks(ctx) {
698
- if (ctx.config.mode === "dev" || ctx.config.mode === "production") ctx.state.sinks.push(consoleSink());
712
+ if (ctx.config.mode === "dev") ctx.state.sinks.push(consoleSink("debug"));
713
+ else if (ctx.config.mode === "production") ctx.state.sinks.push(consoleSink("info"));
699
714
  }
700
715
  //#endregion
701
716
  //#region src/plugins/log/state.ts
@@ -6673,11 +6688,10 @@ function createSpaKernel(state, config, emit, deps) {
6673
6688
  const region = document.querySelector(resolved.swapSelector);
6674
6689
  if (!region) return false;
6675
6690
  handleStart(pathname);
6676
- const { renderVNode } = await import("./render-BL9Fv6G6.mjs");
6691
+ const { renderVNode } = await import("./render-BNe0s7fr.mjs");
6677
6692
  syncDataHead(hit.route, routeContext);
6678
6693
  unmountPageSpecific(state, emit);
6679
6694
  runSwap(() => {
6680
- region.replaceChildren();
6681
6695
  renderVNode(vnode, region);
6682
6696
  scanAndMount(state, emit, resolved.swapSelector);
6683
6697
  notifyNavEnd(state);
@@ -0,0 +1,32 @@
1
+ import { render } from "preact";
2
+ //#region src/plugins/spa/render.ts
3
+ /**
4
+ * Render a route's `VNode` into the live swap region, starting from a clean slate
5
+ * each time. Preact keeps the previous vdom tree on the container and diffs the
6
+ * next render against it — but the kernel clears the region between navs to drop
7
+ * the static SSR markup. A raw `replaceChildren()` would delete the live DOM out
8
+ * from under Preact's retained vdom, so the next diff patches detached nodes → an
9
+ * empty region (the bug where a SECOND consecutive client nav went blank).
10
+ *
11
+ * To stay correct without tracking element identity, first `render(null, region)`
12
+ * — this unmounts any Preact tree Preact owns AND resets its retained vdom pointer
13
+ * (a no-op the first time, when the region still holds raw SSR/HTML). Then clear
14
+ * whatever static children remain, then mount the new VNode fresh. Reuses the
15
+ * build's component output verbatim (same `route.render`), so the client paint
16
+ * matches the SSG paint.
17
+ *
18
+ * @param vnode - The VNode produced by the matched route's `.render(ctx)`.
19
+ * @param region - The swap-region element to render into.
20
+ * @example
21
+ * ```ts
22
+ * const { renderVNode } = await import("./render");
23
+ * renderVNode(route._handlers.render(ctx), document.querySelector("main > section"));
24
+ * ```
25
+ */
26
+ function renderVNode(vnode, region) {
27
+ render(null, region);
28
+ region.replaceChildren();
29
+ render(vnode, region);
30
+ }
31
+ //#endregion
32
+ export { renderVNode };
@@ -0,0 +1,32 @@
1
+ let preact = require("preact");
2
+ //#region src/plugins/spa/render.ts
3
+ /**
4
+ * Render a route's `VNode` into the live swap region, starting from a clean slate
5
+ * each time. Preact keeps the previous vdom tree on the container and diffs the
6
+ * next render against it — but the kernel clears the region between navs to drop
7
+ * the static SSR markup. A raw `replaceChildren()` would delete the live DOM out
8
+ * from under Preact's retained vdom, so the next diff patches detached nodes → an
9
+ * empty region (the bug where a SECOND consecutive client nav went blank).
10
+ *
11
+ * To stay correct without tracking element identity, first `render(null, region)`
12
+ * — this unmounts any Preact tree Preact owns AND resets its retained vdom pointer
13
+ * (a no-op the first time, when the region still holds raw SSR/HTML). Then clear
14
+ * whatever static children remain, then mount the new VNode fresh. Reuses the
15
+ * build's component output verbatim (same `route.render`), so the client paint
16
+ * matches the SSG paint.
17
+ *
18
+ * @param vnode - The VNode produced by the matched route's `.render(ctx)`.
19
+ * @param region - The swap-region element to render into.
20
+ * @example
21
+ * ```ts
22
+ * const { renderVNode } = await import("./render");
23
+ * renderVNode(route._handlers.render(ctx), document.querySelector("main > section"));
24
+ * ```
25
+ */
26
+ function renderVNode(vnode, region) {
27
+ (0, preact.render)(null, region);
28
+ region.replaceChildren();
29
+ (0, preact.render)(vnode, region);
30
+ }
31
+ //#endregion
32
+ exports.renderVNode = renderVNode;
package/package.json CHANGED
@@ -112,5 +112,5 @@
112
112
  "test:integration": "vitest run --project integration",
113
113
  "test:coverage": "vitest run --project unit --project integration --coverage"
114
114
  },
115
- "version": "0.5.3"
115
+ "version": "0.5.5"
116
116
  }
@@ -1,20 +0,0 @@
1
- import { render } from "preact";
2
- //#region src/plugins/spa/render.ts
3
- /**
4
- * Render a route's `VNode` into the live swap region, replacing its contents.
5
- * Reuses the build's component output verbatim (same `route.render`), so the
6
- * client paint matches the SSG paint.
7
- *
8
- * @param vnode - The VNode produced by the matched route's `.render(ctx)`.
9
- * @param region - The swap-region element to render into.
10
- * @example
11
- * ```ts
12
- * const { renderVNode } = await import("./render");
13
- * renderVNode(route._handlers.render(ctx), document.querySelector("main > section"));
14
- * ```
15
- */
16
- function renderVNode(vnode, region) {
17
- render(vnode, region);
18
- }
19
- //#endregion
20
- export { renderVNode };
@@ -1,20 +0,0 @@
1
- let preact = require("preact");
2
- //#region src/plugins/spa/render.ts
3
- /**
4
- * Render a route's `VNode` into the live swap region, replacing its contents.
5
- * Reuses the build's component output verbatim (same `route.render`), so the
6
- * client paint matches the SSG paint.
7
- *
8
- * @param vnode - The VNode produced by the matched route's `.render(ctx)`.
9
- * @param region - The swap-region element to render into.
10
- * @example
11
- * ```ts
12
- * const { renderVNode } = await import("./render");
13
- * renderVNode(route._handlers.render(ctx), document.querySelector("main > section"));
14
- * ```
15
- */
16
- function renderVNode(vnode, region) {
17
- (0, preact.render)(vnode, region);
18
- }
19
- //#endregion
20
- exports.renderVNode = renderVNode;