@moku-labs/web 1.16.0 → 1.17.0

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.
@@ -871,7 +871,7 @@ type Api$1 = {
871
871
  composeTitle(head: HeadConfig | undefined): string;
872
872
  };
873
873
  declare namespace types_d_exports$4 {
874
- export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
874
+ export { AnyVNode, COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
875
875
  }
876
876
  /** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
877
877
  type SpaEvents = {
@@ -978,7 +978,13 @@ interface ResolvedSpaConfig {
978
978
  * - a `string` — set as the host's `innerHTML`;
979
979
  * - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
980
980
  */
981
- type RenderResult = import("preact").VNode | Node | string | void;
981
+ type RenderResult = AnyVNode | Node | string | void;
982
+ /**
983
+ * A Preact `VNode` of ANY props shape. A render returns `h(Component, props)`, i.e. a
984
+ * `VNode<SomeProps>`; the props generic is invariant under `exactOptionalPropertyTypes`,
985
+ * so the only supertype that accepts every concrete `VNode<P>` is `VNode<any>`.
986
+ */
987
+ type AnyVNode = import("preact").VNode<any>;
982
988
  /**
983
989
  * Factory that builds a component's typed per-instance state (mirrors a plugin's
984
990
  * `createState`). Called ONCE at mount; the returned object is stored on the
package/dist/browser.mjs CHANGED
@@ -2518,6 +2518,13 @@ const COMPONENT_HOOK_NAMES = [
2518
2518
  ];
2519
2519
  //#endregion
2520
2520
  //#region src/plugins/spa/components.ts
2521
+ /**
2522
+ * @file spa plugin — component lifecycle, mounting, the plugin-mirror authoring
2523
+ * surface (`createComponent` with a typed `{ state, render, events, api }` spec),
2524
+ * the per-instance state + microtask-batched render scheduler, declarative
2525
+ * delegated events, and the cross-island api registry.
2526
+ * @see README.md
2527
+ */
2521
2528
  /** Error prefix for spa fail-fast failures (spec/11 Part-3). */
2522
2529
  const ERROR_PREFIX$2 = "[web]";
2523
2530
  /** The set of legal hook names, frozen for O(1) membership checks. */
package/dist/index.cjs CHANGED
@@ -8039,17 +8039,22 @@ function createApi$1(ctx) {
8039
8039
  * @example
8040
8040
  * await api.update(["src/islands/board.ts"]);
8041
8041
  */
8042
- update(changes, options = {}) {
8042
+ async update(changes, options = {}) {
8043
8043
  const overrides = devBuildOverrides({
8044
8044
  og: options.og ?? false,
8045
8045
  sitemap: options.sitemap ?? false,
8046
8046
  feeds: options.feeds ?? false
8047
8047
  });
8048
- return ctx.require(buildPlugin).run({
8049
- skipClean: true,
8050
- overrides,
8051
- changed: changes
8052
- });
8048
+ ctx.state.render.setDriven(true);
8049
+ try {
8050
+ return await ctx.require(buildPlugin).run({
8051
+ skipClean: true,
8052
+ overrides,
8053
+ changed: changes
8054
+ });
8055
+ } finally {
8056
+ ctx.state.render.setDriven(false);
8057
+ }
8053
8058
  },
8054
8059
  /**
8055
8060
  * Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
@@ -8342,6 +8347,7 @@ function createPanelRenderer(options = {}) {
8342
8347
  let idle = false;
8343
8348
  let idleStartedAt = 0;
8344
8349
  let serveMode = false;
8350
+ let driven = false;
8345
8351
  let ticker;
8346
8352
  /**
8347
8353
  * Render one phase-tree row: a spinning cyan glyph + dim name while running, or a green
@@ -8503,7 +8509,7 @@ function createPanelRenderer(options = {}) {
8503
8509
  * render.phase({ phase: "pages", status: "done", durationMs: 12 });
8504
8510
  */
8505
8511
  phase(phase) {
8506
- if (rebuilding) return;
8512
+ if (rebuilding || driven) return;
8507
8513
  if (!color) {
8508
8514
  if (phase.status === "done") write(` ${palette.green("✓")} ${phase.phase}${durationSuffix(palette, phase.durationMs)}`);
8509
8515
  return;
@@ -8537,7 +8543,7 @@ function createPanelRenderer(options = {}) {
8537
8543
  * render.built({ outDir: "dist", pageCount: 12, durationMs: 840 });
8538
8544
  */
8539
8545
  built(summary) {
8540
- if (rebuilding) return;
8546
+ if (rebuilding || driven) return;
8541
8547
  if (color && phaseOpen) {
8542
8548
  let frame = (0, _moku_labs_common_cli.cursorUp)(phaseDrawn);
8543
8549
  for (const row of phaseRows) frame += `${_moku_labs_common_cli.CLEAR_LINE}${renderPhaseRow(row)}\n`;
@@ -8711,6 +8717,20 @@ function createPanelRenderer(options = {}) {
8711
8717
  if (detail !== void 0) for (const line of detail.split("\n")) write(` ${palette.dim(line)}`);
8712
8718
  },
8713
8719
  /**
8720
+ * Mark the build TUI as externally driven: when `on`, the per-phase build tree and the BUILD
8721
+ * summary are suppressed so an external dev driver (e.g. the worker's `dev({ onChange })` loop,
8722
+ * which calls `update()` and renders its own concise rebuild line) is the sole source of rebuild
8723
+ * output. Off by default; a standalone `build()` / `serve()` renders the full TUI as before.
8724
+ *
8725
+ * @param on - Whether an external driver owns the dev TUI.
8726
+ * @example
8727
+ * render.setDriven(true); // before an externally-driven update()
8728
+ * render.setDriven(false); // after it settles
8729
+ */
8730
+ setDriven(on) {
8731
+ driven = on;
8732
+ },
8733
+ /**
8714
8734
  * Stop every animation and release the interval timer (serve()'s teardown calls this).
8715
8735
  *
8716
8736
  * @example
@@ -9204,6 +9224,13 @@ const COMPONENT_HOOK_NAMES = [
9204
9224
  ];
9205
9225
  //#endregion
9206
9226
  //#region src/plugins/spa/components.ts
9227
+ /**
9228
+ * @file spa plugin — component lifecycle, mounting, the plugin-mirror authoring
9229
+ * surface (`createComponent` with a typed `{ state, render, events, api }` spec),
9230
+ * the per-instance state + microtask-batched render scheduler, declarative
9231
+ * delegated events, and the cross-island api registry.
9232
+ * @see README.md
9233
+ */
9207
9234
  /** Error prefix for spa fail-fast failures (spec/11 Part-3). */
9208
9235
  const ERROR_PREFIX$2 = "[web]";
9209
9236
  /** The set of legal hook names, frozen for O(1) membership checks. */
package/dist/index.d.cts CHANGED
@@ -872,7 +872,7 @@ type Api$4 = {
872
872
  composeTitle(head: HeadConfig | undefined): string;
873
873
  };
874
874
  declare namespace types_d_exports$7 {
875
- export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi$1 as ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
875
+ export { AnyVNode, COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi$1 as ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
876
876
  }
877
877
  /** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
878
878
  type SpaEvents = {
@@ -979,7 +979,13 @@ interface ResolvedSpaConfig {
979
979
  * - a `string` — set as the host's `innerHTML`;
980
980
  * - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
981
981
  */
982
- type RenderResult = import("preact").VNode | Node | string | void;
982
+ type RenderResult = AnyVNode | Node | string | void;
983
+ /**
984
+ * A Preact `VNode` of ANY props shape. A render returns `h(Component, props)`, i.e. a
985
+ * `VNode<SomeProps>`; the props generic is invariant under `exactOptionalPropertyTypes`,
986
+ * so the only supertype that accepts every concrete `VNode<P>` is `VNode<any>`.
987
+ */
988
+ type AnyVNode = import("preact").VNode<any>;
983
989
  /**
984
990
  * Factory that builds a component's typed per-instance state (mirrors a plugin's
985
991
  * `createState`). Called ONCE at mount; the returned object is stored on the
@@ -2213,6 +2219,19 @@ type CliRenderer = {
2213
2219
  * render.check(false, "CLOUDFLARE_API_TOKEN is set", "Create one at …");
2214
2220
  */
2215
2221
  check(ok: boolean, label: string, detail?: string): void;
2222
+ /**
2223
+ * Mark the build TUI as externally driven. When `on`, the per-phase build tree and the BUILD
2224
+ * summary block are suppressed, so an external dev driver (e.g. the worker's `dev({ onChange })`
2225
+ * loop, which calls `update()` and renders its own concise rebuild line) is the sole source of
2226
+ * rebuild output — no duplicate full TUI on each incremental rebuild. Off by default; a standalone
2227
+ * `build()` / `serve()` keeps the full TUI.
2228
+ *
2229
+ * @param on - Whether an external driver owns the dev TUI.
2230
+ * @returns Nothing.
2231
+ * @example
2232
+ * render.setDriven(true);
2233
+ */
2234
+ setDriven(on: boolean): void;
2216
2235
  /**
2217
2236
  * Stop any running animation (the live `serve()` idle pulse, a phase/rebuild spinner)
2218
2237
  * and release the renderer's interval timer. Called by `serve()`'s SIGINT/SIGTERM
package/dist/index.d.mts CHANGED
@@ -870,7 +870,7 @@ type Api$4 = {
870
870
  composeTitle(head: HeadConfig | undefined): string;
871
871
  };
872
872
  declare namespace types_d_exports$7 {
873
- export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi$1 as ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
873
+ export { AnyVNode, COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentEventHandler, ComponentEvents, ComponentHooks, ComponentInstance, ComponentRender, ComponentRouteSlice, ComponentSpec, ComponentSpecExtras, ComponentStateFactory, ExtractApi$1 as ExtractApi, PageData, RenderResult, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
874
874
  }
875
875
  /** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
876
876
  type SpaEvents = {
@@ -977,7 +977,13 @@ interface ResolvedSpaConfig {
977
977
  * - a `string` — set as the host's `innerHTML`;
978
978
  * - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
979
979
  */
980
- type RenderResult = import("preact").VNode | Node | string | void;
980
+ type RenderResult = AnyVNode | Node | string | void;
981
+ /**
982
+ * A Preact `VNode` of ANY props shape. A render returns `h(Component, props)`, i.e. a
983
+ * `VNode<SomeProps>`; the props generic is invariant under `exactOptionalPropertyTypes`,
984
+ * so the only supertype that accepts every concrete `VNode<P>` is `VNode<any>`.
985
+ */
986
+ type AnyVNode = import("preact").VNode<any>;
981
987
  /**
982
988
  * Factory that builds a component's typed per-instance state (mirrors a plugin's
983
989
  * `createState`). Called ONCE at mount; the returned object is stored on the
@@ -2211,6 +2217,19 @@ type CliRenderer = {
2211
2217
  * render.check(false, "CLOUDFLARE_API_TOKEN is set", "Create one at …");
2212
2218
  */
2213
2219
  check(ok: boolean, label: string, detail?: string): void;
2220
+ /**
2221
+ * Mark the build TUI as externally driven. When `on`, the per-phase build tree and the BUILD
2222
+ * summary block are suppressed, so an external dev driver (e.g. the worker's `dev({ onChange })`
2223
+ * loop, which calls `update()` and renders its own concise rebuild line) is the sole source of
2224
+ * rebuild output — no duplicate full TUI on each incremental rebuild. Off by default; a standalone
2225
+ * `build()` / `serve()` keeps the full TUI.
2226
+ *
2227
+ * @param on - Whether an external driver owns the dev TUI.
2228
+ * @returns Nothing.
2229
+ * @example
2230
+ * render.setDriven(true);
2231
+ */
2232
+ setDriven(on: boolean): void;
2214
2233
  /**
2215
2234
  * Stop any running animation (the live `serve()` idle pulse, a phase/rebuild spinner)
2216
2235
  * and release the renderer's interval timer. Called by `serve()`'s SIGINT/SIGTERM
package/dist/index.mjs CHANGED
@@ -8026,17 +8026,22 @@ function createApi$1(ctx) {
8026
8026
  * @example
8027
8027
  * await api.update(["src/islands/board.ts"]);
8028
8028
  */
8029
- update(changes, options = {}) {
8029
+ async update(changes, options = {}) {
8030
8030
  const overrides = devBuildOverrides({
8031
8031
  og: options.og ?? false,
8032
8032
  sitemap: options.sitemap ?? false,
8033
8033
  feeds: options.feeds ?? false
8034
8034
  });
8035
- return ctx.require(buildPlugin).run({
8036
- skipClean: true,
8037
- overrides,
8038
- changed: changes
8039
- });
8035
+ ctx.state.render.setDriven(true);
8036
+ try {
8037
+ return await ctx.require(buildPlugin).run({
8038
+ skipClean: true,
8039
+ overrides,
8040
+ changed: changes
8041
+ });
8042
+ } finally {
8043
+ ctx.state.render.setDriven(false);
8044
+ }
8040
8045
  },
8041
8046
  /**
8042
8047
  * Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
@@ -8329,6 +8334,7 @@ function createPanelRenderer(options = {}) {
8329
8334
  let idle = false;
8330
8335
  let idleStartedAt = 0;
8331
8336
  let serveMode = false;
8337
+ let driven = false;
8332
8338
  let ticker;
8333
8339
  /**
8334
8340
  * Render one phase-tree row: a spinning cyan glyph + dim name while running, or a green
@@ -8490,7 +8496,7 @@ function createPanelRenderer(options = {}) {
8490
8496
  * render.phase({ phase: "pages", status: "done", durationMs: 12 });
8491
8497
  */
8492
8498
  phase(phase) {
8493
- if (rebuilding) return;
8499
+ if (rebuilding || driven) return;
8494
8500
  if (!color) {
8495
8501
  if (phase.status === "done") write(` ${palette.green("✓")} ${phase.phase}${durationSuffix(palette, phase.durationMs)}`);
8496
8502
  return;
@@ -8524,7 +8530,7 @@ function createPanelRenderer(options = {}) {
8524
8530
  * render.built({ outDir: "dist", pageCount: 12, durationMs: 840 });
8525
8531
  */
8526
8532
  built(summary) {
8527
- if (rebuilding) return;
8533
+ if (rebuilding || driven) return;
8528
8534
  if (color && phaseOpen) {
8529
8535
  let frame = cursorUp(phaseDrawn);
8530
8536
  for (const row of phaseRows) frame += `${CLEAR_LINE}${renderPhaseRow(row)}\n`;
@@ -8698,6 +8704,20 @@ function createPanelRenderer(options = {}) {
8698
8704
  if (detail !== void 0) for (const line of detail.split("\n")) write(` ${palette.dim(line)}`);
8699
8705
  },
8700
8706
  /**
8707
+ * Mark the build TUI as externally driven: when `on`, the per-phase build tree and the BUILD
8708
+ * summary are suppressed so an external dev driver (e.g. the worker's `dev({ onChange })` loop,
8709
+ * which calls `update()` and renders its own concise rebuild line) is the sole source of rebuild
8710
+ * output. Off by default; a standalone `build()` / `serve()` renders the full TUI as before.
8711
+ *
8712
+ * @param on - Whether an external driver owns the dev TUI.
8713
+ * @example
8714
+ * render.setDriven(true); // before an externally-driven update()
8715
+ * render.setDriven(false); // after it settles
8716
+ */
8717
+ setDriven(on) {
8718
+ driven = on;
8719
+ },
8720
+ /**
8701
8721
  * Stop every animation and release the interval timer (serve()'s teardown calls this).
8702
8722
  *
8703
8723
  * @example
@@ -9191,6 +9211,13 @@ const COMPONENT_HOOK_NAMES = [
9191
9211
  ];
9192
9212
  //#endregion
9193
9213
  //#region src/plugins/spa/components.ts
9214
+ /**
9215
+ * @file spa plugin — component lifecycle, mounting, the plugin-mirror authoring
9216
+ * surface (`createComponent` with a typed `{ state, render, events, api }` spec),
9217
+ * the per-instance state + microtask-batched render scheduler, declarative
9218
+ * delegated events, and the cross-island api registry.
9219
+ * @see README.md
9220
+ */
9194
9221
  /** Error prefix for spa fail-fast failures (spec/11 Part-3). */
9195
9222
  const ERROR_PREFIX$2 = "[web]";
9196
9223
  /** The set of legal hook names, frozen for O(1) membership checks. */
@@ -6,7 +6,13 @@
6
6
  * - a `string` — set as the host's `innerHTML`;
7
7
  * - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
8
8
  */
9
- type RenderResult = import("preact").VNode | Node | string | void;
9
+ type RenderResult = AnyVNode | Node | string | void;
10
+ /**
11
+ * A Preact `VNode` of ANY props shape. A render returns `h(Component, props)`, i.e. a
12
+ * `VNode<SomeProps>`; the props generic is invariant under `exactOptionalPropertyTypes`,
13
+ * so the only supertype that accepts every concrete `VNode<P>` is `VNode<any>`.
14
+ */
15
+ type AnyVNode = import("preact").VNode<any>;
10
16
  /**
11
17
  * Factory that builds a component's typed per-instance state (mirrors a plugin's
12
18
  * `createState`). Called ONCE at mount; the returned object is stored on the
package/dist/testing.mjs CHANGED
@@ -12,6 +12,13 @@ const COMPONENT_HOOK_NAMES = [
12
12
  ];
13
13
  //#endregion
14
14
  //#region src/plugins/spa/components.ts
15
+ /**
16
+ * @file spa plugin — component lifecycle, mounting, the plugin-mirror authoring
17
+ * surface (`createComponent` with a typed `{ state, render, events, api }` spec),
18
+ * the per-instance state + microtask-batched render scheduler, declarative
19
+ * delegated events, and the cross-island api registry.
20
+ * @see README.md
21
+ */
15
22
  /** Error prefix for spa fail-fast failures (spec/11 Part-3). */
16
23
  const ERROR_PREFIX = "[web]";
17
24
  new Set(COMPONENT_HOOK_NAMES);
package/package.json CHANGED
@@ -132,5 +132,5 @@
132
132
  "test:build-e2e": "bun test src/plugins/build/__tests__/e2e/",
133
133
  "test:coverage": "vitest run --project unit --project integration --coverage"
134
134
  },
135
- "version": "1.16.0"
135
+ "version": "1.17.0"
136
136
  }