@moku-labs/web 1.15.0 → 1.16.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.
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, ComponentHooks, ComponentInstance, ExtractApi$1 as ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
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 };
874
874
  }
875
875
  /** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
876
876
  type SpaEvents = {
@@ -971,12 +971,77 @@ interface ResolvedSpaConfig {
971
971
  components: ComponentDef[];
972
972
  }
973
973
  /**
974
- * Context handed to every component lifecycle hook — the bound element + page data,
975
- * plus the matched route's `params`/`meta`/`locale` and a link builder, so an island
976
- * can read its route context (e.g. a `card` route's `ctx.meta.focus` + `ctx.params.id`)
977
- * directly, without the page bridging it through `data-*` attributes.
974
+ * What a component's `render` may return:
975
+ * - a Preact `VNode` committed into the host through the lazy Preact gate (`commitVNode`);
976
+ * - a `Node` replaces the host's children;
977
+ * - a `string` set as the host's `innerHTML`;
978
+ * - `void`/`undefined` — the render mutated the DOM itself (DOM-only islands → no Preact loaded).
978
979
  */
979
- interface ComponentContext {
980
+ type RenderResult = import("preact").VNode | Node | string | void;
981
+ /**
982
+ * Factory that builds a component's typed per-instance state (mirrors a plugin's
983
+ * `createState`). Called ONCE at mount; the returned object is stored on the
984
+ * {@link ComponentInstance} and exposed read-only as `ctx.state`.
985
+ *
986
+ * @param ctx - The component context for this instance (state is not yet set).
987
+ * @returns The initial per-instance state.
988
+ * @example
989
+ * state: (ctx): BoardState => ({ boardId: ctx.params.id ?? "", cards: [] })
990
+ */
991
+ type ComponentStateFactory<S extends object> = (ctx: ComponentContext<S>) => S;
992
+ /**
993
+ * Pure render of `(state, ctx)` → {@link RenderResult}. Called after mount-state-init
994
+ * and again (microtask-batched) after every `ctx.set`. Must be free of side effects
995
+ * beyond producing its result.
996
+ *
997
+ * @param state - The current per-instance state (read-only).
998
+ * @param ctx - The component context for this instance.
999
+ * @returns The render result to commit into the host.
1000
+ * @example
1001
+ * render: (state) => h(BoardView, { snapshot: state.snapshot })
1002
+ */
1003
+ type ComponentRender<S extends object> = (state: Readonly<S>, ctx: ComponentContext<S>) => RenderResult;
1004
+ /**
1005
+ * A delegated DOM event handler. `target` is the element matched by the key's selector
1006
+ * (already resolved via `closest` — no `instanceof`/`closest` ceremony in the body).
1007
+ *
1008
+ * Typed `void` for ergonomics (the void-return rule accepts async handlers returning
1009
+ * `Promise<void>` too); the kernel ignores any returned value.
1010
+ *
1011
+ * @param ctx - The component context (carries the live per-instance `state`).
1012
+ * @param event - The raw DOM event.
1013
+ * @param target - The element matched by the selector (the host when no selector).
1014
+ * @returns void (a returned promise is ignored by the kernel).
1015
+ * @example
1016
+ * (ctx, event, button) => { event.preventDefault(); ctx.set({ open: true }); }
1017
+ */
1018
+ type ComponentEventHandler<S extends object> = (ctx: ComponentContext<S>, event: Event, target: Element) => void;
1019
+ /**
1020
+ * Declarative delegated event map. Each key is `"<type> <selector>"` (the selector is
1021
+ * optional → a host-level listener). ONE real listener per event TYPE is attached to
1022
+ * the host; dispatch walks `event.target.closest(selector)` within the host. All
1023
+ * listeners are auto-removed on destroy.
1024
+ *
1025
+ * @example
1026
+ * events: {
1027
+ * "click [data-action='delete']": (ctx, _e, btn) => ctx.set(removeCard(ctx.state, btn)),
1028
+ * "submit [data-add]": (ctx, e) => { e.preventDefault(); add(ctx); }
1029
+ * }
1030
+ */
1031
+ type ComponentEvents<S extends object> = Record<string, ComponentEventHandler<S>>;
1032
+ /**
1033
+ * Context handed to every component lifecycle hook, render, and event handler — the
1034
+ * bound element + page data, plus the matched route's `params`/`meta`/`locale` and a
1035
+ * link builder, so an island can read its route context (e.g. a `card` route's
1036
+ * `ctx.meta.focus` + `ctx.params.id`) directly, without the page bridging it through
1037
+ * `data-*` attributes.
1038
+ *
1039
+ * Generic over the per-instance state `S` (default `undefined` so every existing
1040
+ * hooks-only island still type-checks). The additive members (`state`/`set`/`flush`/
1041
+ * `cleanup`/`component`) are ALWAYS-PRESENT functions — never optional keys — so they
1042
+ * never trip `exactOptionalPropertyTypes`.
1043
+ */
1044
+ interface ComponentContext<S = undefined> {
980
1045
  /** The element the component instance is bound to. */
981
1046
  el: Element;
982
1047
  /** Page data extracted from the `script#__DATA__` payload. */
@@ -989,9 +1054,52 @@ interface ComponentContext {
989
1054
  readonly locale: string;
990
1055
  /** Build a link to a named route by pattern substitution (same output as `app.router.toUrl`). */
991
1056
  readonly url: (name: string, params?: Record<string, string>) => string;
1057
+ /** The live per-instance state (the object returned by `spec.state`). `undefined` for legacy hooks-only islands. */
1058
+ readonly state: S;
1059
+ /**
1060
+ * Merge a patch into the per-instance state, then schedule ONE batched render.
1061
+ * Accepts a partial object or an updater `(prev) => partial`. A no-op for legacy
1062
+ * islands with no `state`/`render`.
1063
+ *
1064
+ * @param patch - A partial state object, or an updater returning one.
1065
+ * @returns void
1066
+ * @example
1067
+ * ctx.set({ open: true });
1068
+ * ctx.set(prev => ({ count: prev.count + 1 }));
1069
+ */
1070
+ set(patch: Partial<S> | ((prev: Readonly<S>) => Partial<S>)): void;
1071
+ /**
1072
+ * Force a synchronous render now (drains any pending scheduled render). Rarely
1073
+ * needed in app code — `ctx.set` already schedules one; mainly a test seam.
1074
+ *
1075
+ * @returns void
1076
+ * @example
1077
+ * ctx.flush();
1078
+ */
1079
+ flush(): void;
1080
+ /**
1081
+ * Register a disposer run on `onDestroy` (subscriptions, timers, manual/global
1082
+ * listeners the declarative `events` map cannot cover). Disposers run LIFO.
1083
+ *
1084
+ * @param dispose - The teardown function.
1085
+ * @returns void
1086
+ * @example
1087
+ * ctx.cleanup(onPatch(p => applyPatch(ctx, p)));
1088
+ */
1089
+ cleanup(dispose: () => void): void;
1090
+ /**
1091
+ * Resolve another island's registered `api` by name. Returns `undefined` when no
1092
+ * provider is registered (optional-dependency semantics, mirroring `ctx.has`).
1093
+ *
1094
+ * @param name - The provider island's component name.
1095
+ * @returns The provider's api, or `undefined`.
1096
+ * @example
1097
+ * ctx.component<LightboxApi>("lightbox")?.open(slides, index);
1098
+ */
1099
+ component<T = unknown>(name: string): T | undefined;
992
1100
  }
993
- /** Lifecycle hooks a component may implement. */
994
- interface ComponentHooks {
1101
+ /** Lifecycle hooks a component may implement. Generic over the per-instance state `S`. */
1102
+ interface ComponentHooks<S = undefined> {
995
1103
  /**
996
1104
  * Called once when the instance is created (before DOM attach).
997
1105
  *
@@ -1000,7 +1108,7 @@ interface ComponentHooks {
1000
1108
  * @example
1001
1109
  * onCreate({ el }) { el.dataset.ready = "1"; }
1002
1110
  */
1003
- onCreate?(ctx: ComponentContext): void;
1111
+ onCreate?(ctx: ComponentContext<S>): void;
1004
1112
  /**
1005
1113
  * Called after the instance is attached to its element.
1006
1114
  *
@@ -1008,8 +1116,10 @@ interface ComponentHooks {
1008
1116
  * @returns void
1009
1117
  * @example
1010
1118
  * onMount({ el }) { el.textContent = "0"; }
1119
+ * @example
1120
+ * async onMount(ctx) { ctx.set({ items: await load() }); } // async is allowed; the harness awaits it via settle()
1011
1121
  */
1012
- onMount?(ctx: ComponentContext): void;
1122
+ onMount?(ctx: ComponentContext<S>): void;
1013
1123
  /**
1014
1124
  * Called when a navigation begins while this instance is mounted.
1015
1125
  *
@@ -1018,7 +1128,7 @@ interface ComponentHooks {
1018
1128
  * @example
1019
1129
  * onNavStart({ el }) { el.dataset.loading = ""; }
1020
1130
  */
1021
- onNavStart?(ctx: ComponentContext): void;
1131
+ onNavStart?(ctx: ComponentContext<S>): void;
1022
1132
  /**
1023
1133
  * Called when a navigation completes while this instance is mounted.
1024
1134
  *
@@ -1027,7 +1137,7 @@ interface ComponentHooks {
1027
1137
  * @example
1028
1138
  * onNavEnd({ el }) { delete el.dataset.loading; }
1029
1139
  */
1030
- onNavEnd?(ctx: ComponentContext): void;
1140
+ onNavEnd?(ctx: ComponentContext<S>): void;
1031
1141
  /**
1032
1142
  * Called before the instance is detached from its element.
1033
1143
  *
@@ -1036,7 +1146,7 @@ interface ComponentHooks {
1036
1146
  * @example
1037
1147
  * onUnMount({ el }) { el.replaceChildren(); }
1038
1148
  */
1039
- onUnMount?(ctx: ComponentContext): void;
1149
+ onUnMount?(ctx: ComponentContext<S>): void;
1040
1150
  /**
1041
1151
  * Called once when the instance is destroyed (after detach).
1042
1152
  *
@@ -1045,17 +1155,60 @@ interface ComponentHooks {
1045
1155
  * @example
1046
1156
  * onDestroy({ el }) { delete el.dataset.ready; }
1047
1157
  */
1048
- onDestroy?(ctx: ComponentContext): void;
1158
+ onDestroy?(ctx: ComponentContext<S>): void;
1049
1159
  }
1050
1160
  /** Allowed hook names — single source of truth for fail-fast validation. */
1051
1161
  declare const COMPONENT_HOOK_NAMES: readonly ["onCreate", "onMount", "onNavStart", "onNavEnd", "onUnMount", "onDestroy"];
1052
- /** A registered component definition. */
1162
+ /**
1163
+ * The plugin-mirror authoring form for {@link createComponent}: typed per-instance
1164
+ * `state`, `render`, declarative `events`, and a cross-island `api` on top of the
1165
+ * lifecycle hooks. All keys optional + additive; the presence of any spec-only key
1166
+ * (`state`/`render`/`events`/`api`) selects the spec overload of `createComponent`.
1167
+ *
1168
+ * @example
1169
+ * createComponent<{ boards: Board[] }>("board-list", {
1170
+ * state: () => ({ boards: [] }),
1171
+ * async onMount(ctx) { ctx.set({ boards: await ctx.component<Api>("api")!.list() }); },
1172
+ * render: (s) => h(BoardList, { boards: s.boards }),
1173
+ * events: { "submit [data-create]": (ctx, e) => { e.preventDefault(); create(ctx); } }
1174
+ * });
1175
+ */
1176
+ interface ComponentSpec<S extends object = object, A = unknown> extends ComponentHooks<S> {
1177
+ /** Build typed per-instance state at mount (stored on the instance, not a module WeakMap). */
1178
+ state?: ComponentStateFactory<S>;
1179
+ /** Pure render re-invoked (microtask-batched) on every `ctx.set`. */
1180
+ render?: ComponentRender<S>;
1181
+ /** Declarative delegated DOM events with auto-teardown. */
1182
+ events?: ComponentEvents<S>;
1183
+ /** Public api factory — registered under the component name; reached via `app.spa.component(name)`. */
1184
+ api?: (ctx: ComponentContext<S>) => A;
1185
+ }
1186
+ /**
1187
+ * The spec extras carried on a {@link ComponentDef}, type-erased to `object` state
1188
+ * (authors keep full `S` inference at the `createComponent` call site; the registry
1189
+ * stores the runtime-only erased form). Absent for legacy `(name, hooks)` defs.
1190
+ */
1191
+ interface ComponentSpecExtras {
1192
+ /** Per-instance state factory. */
1193
+ state?: ComponentStateFactory<object>;
1194
+ /** Render called on mount + after every `ctx.set`. */
1195
+ render?: ComponentRender<object>;
1196
+ /** Declarative delegated events. */
1197
+ events?: ComponentEvents<object>;
1198
+ /** Public api factory registered under the component name. */
1199
+ api?: (ctx: ComponentContext<object>) => unknown;
1200
+ }
1201
+ /** A registered component definition (an opaque token; author inference lives on `createComponent`). */
1053
1202
  interface ComponentDef {
1054
1203
  /** Unique component name (matched against `data-component`). */
1055
1204
  name: string;
1056
- /** Lifecycle hooks. */
1057
- hooks: ComponentHooks;
1205
+ /** Lifecycle hooks (the subset shared with the legacy form). */
1206
+ hooks: ComponentHooks<object>;
1207
+ /** Plugin-mirror extras (state/render/events/api). Absent for legacy `(name, hooks)` defs. */
1208
+ spec?: ComponentSpecExtras;
1058
1209
  }
1210
+ /** The matched-route slice carried on a live instance (params/meta/locale + link builder). */
1211
+ type ComponentRouteSlice = Pick<ComponentContext, "params" | "meta" | "locale" | "url">;
1059
1212
  /** A live, mounted component instance. */
1060
1213
  interface ComponentInstance {
1061
1214
  /** The definition this instance was created from. */
@@ -1068,6 +1221,26 @@ interface ComponentInstance {
1068
1221
  * page-specific: full unmount/destroy on every navigation.
1069
1222
  */
1070
1223
  persistent: boolean;
1224
+ /** The single per-instance context reused by every hook, event handler, and render. */
1225
+ ctx: ComponentContext<object>;
1226
+ /** Live per-instance state (the object returned by `spec.state`), or undefined for hooks-only islands. */
1227
+ state: object | undefined;
1228
+ /** This instance's public api (the object returned by `spec.api`), or undefined when none declared. */
1229
+ api: unknown;
1230
+ /** Current matched-route slice (updated on navigation; read by `ctx.params/meta/locale/url`). */
1231
+ route: ComponentRouteSlice;
1232
+ /** Current page data payload (updated on navigation; read by `ctx.data`). */
1233
+ data: PageData;
1234
+ /** Disposers from `ctx.cleanup` + the declarative `events` listeners — run LIFO on destroy. */
1235
+ cleanups: Array<() => void>;
1236
+ /** Synchronously drain a pending render (the `ctx.flush` implementation). */
1237
+ flush: () => void;
1238
+ /** True while a render is queued for the next microtask — coalesces multiple `set` calls. */
1239
+ renderScheduled: boolean;
1240
+ /** Re-entrancy depth guard for the render scheduler (a render that calls `ctx.set`). */
1241
+ renderDepth: number;
1242
+ /** onMount's returned promise (+ render-module load) — awaited by the test harness's `settle()`. */
1243
+ mountPromise: Promise<void> | undefined;
1071
1244
  }
1072
1245
  /** Page data payload parsed from the inline `script#__DATA__` element. */
1073
1246
  type PageData = Record<string, unknown>;
@@ -1151,6 +1324,8 @@ interface SpaState {
1151
1324
  registeredComponents: Map<string, ComponentDef>;
1152
1325
  /** Live component instances keyed by their bound element. */
1153
1326
  instances: Map<Element, ComponentInstance>;
1327
+ /** Registered island apis by component name (the cross-island `ctx.component`/`app.spa.component` seam). */
1328
+ componentApis: Map<string, unknown>;
1154
1329
  /** The current resolved URL (pathname + search). */
1155
1330
  currentUrl: string;
1156
1331
  /** Teardown handle for the attached router listeners (null when detached). */
@@ -1188,6 +1363,16 @@ type SpaApi = {
1188
1363
  * const url = app.spa.current(); // "/about"
1189
1364
  */
1190
1365
  current(): string;
1366
+ /**
1367
+ * Resolve a registered island's api by name (the cross-island seam). Returns
1368
+ * `undefined` when no provider with that name is currently registered.
1369
+ *
1370
+ * @param name - The provider island's component name.
1371
+ * @returns The provider's api, or `undefined`.
1372
+ * @example
1373
+ * app.spa.component<LightboxApi>("lightbox")?.open(slides, 0);
1374
+ */
1375
+ component<T = unknown>(name: string): T | undefined;
1191
1376
  };
1192
1377
  declare namespace types_d_exports {
1193
1378
  export { Api$3 as Api, BuildCacheEntry, BuildEvents, BuildResult, BuildRunOverrides, Config$3 as Config, ExtractApi, OgFont, OgImageConfig, PhaseContext, PhaseEmit, PhaseLog, PhaseName, PhaseRequire, RenderCacheEntry, RichOgInput, RunOptions, State$3 as State };
@@ -1854,7 +2039,7 @@ type Api$2 = {
1854
2039
  createProject(): Promise<CreateProjectResult>;
1855
2040
  };
1856
2041
  declare namespace types_d_exports$1 {
1857
- export { Api$1 as Api, BuildOptions, BuildSummary, CliErrorCode, CliRenderer, Command, Config$1 as Config, DeployOptions, DeployOutcome, FileResponseFunction, PreviewOptions, ReloadInfo, ServeOptions, ServeStaticFunction, ServeStaticOptions, ServerHandle, ServerInfo, State$1 as State, WatchHandle };
2042
+ export { Api$1 as Api, BuildOptions, BuildSummary, CliErrorCode, CliRenderer, Command, Config$1 as Config, DeployOptions, DeployOutcome, FileResponseFunction, PreviewOptions, ReloadInfo, ServeOptions, ServeStaticFunction, ServeStaticOptions, ServerHandle, ServerInfo, State$1 as State, UpdateOptions, WatchHandle };
1858
2043
  }
1859
2044
  /**
1860
2045
  * A cli error `code` from the config-validation and runtime taxonomy. Mirrors the
@@ -2267,6 +2452,20 @@ type DeployOutcome = {
2267
2452
  type BuildOptions = {
2268
2453
  /** Assert `outDir/notFoundFile` exists after the build. Defaults to `true`. */assertNotFound?: boolean;
2269
2454
  };
2455
+ /**
2456
+ * Options for `cli.update()` — the per-session dev-output opt-ins, mirroring the
2457
+ * relevant subset of {@link ServeOptions}. Each defaults to `false`: an incremental
2458
+ * rebuild skips expensive, preview-irrelevant outputs (OG images / sitemap / feeds)
2459
+ * for speed, and a flag re-enables that one output for the rebuild.
2460
+ *
2461
+ * @example
2462
+ * await app.cli.update(["src/styles.css"], { feeds: true });
2463
+ */
2464
+ type UpdateOptions = {
2465
+ /** Re-enable OG-image generation for this rebuild. Defaults to `false`. */og?: boolean; /** Re-enable `sitemap.xml` + `robots.txt` for this rebuild. Defaults to `false`. */
2466
+ sitemap?: boolean; /** Re-enable RSS/Atom/JSON feeds for this rebuild. Defaults to `false`. */
2467
+ feeds?: boolean;
2468
+ };
2270
2469
  /**
2271
2470
  * Options for `cli.serve()`.
2272
2471
  *
@@ -2328,6 +2527,24 @@ type Api$1 = {
2328
2527
  * const summary = await app.cli.build();
2329
2528
  */
2330
2529
  build(options?: BuildOptions): Promise<BuildSummary>;
2530
+ /**
2531
+ * Incremental dev rebuild from a set of changed paths — the fast counterpart to
2532
+ * {@link build} for a long-lived EXTERNAL dev loop (e.g. an `@moku-labs/worker` dev
2533
+ * session driving the composed web client via `dev({ onChange })`). Reuses the build
2534
+ * plugin's incremental engine: skips the destructive clean, scopes the rebuild to
2535
+ * `changes` (re-reads only changed Markdown, reuses cached page renders whose data is
2536
+ * unchanged), and applies the dev overrides (minify off; OG/sitemap/feeds off unless
2537
+ * re-enabled per {@link UpdateOptions}). An unclassifiable path forces a full rebuild.
2538
+ * Unlike {@link build} it renders no command header and skips the not-found assertion
2539
+ * (it's a per-change dev rebuild, not a release build).
2540
+ *
2541
+ * @param changes - The paths changed since the last build (the incremental hint).
2542
+ * @param options - Optional per-session dev-output opt-ins.
2543
+ * @returns The rebuild summary (`outDir`, `pageCount`, `durationMs`).
2544
+ * @example
2545
+ * await app.cli.update(["src/islands/board.ts"]);
2546
+ */
2547
+ update(changes: readonly string[], options?: UpdateOptions): Promise<BuildSummary>;
2331
2548
  /**
2332
2549
  * Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
2333
2550
  * `watchDirs`, debounced rebuild + reload. Resolves when SIGINT/SIGTERM tears down.
@@ -3281,21 +3498,26 @@ declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Confi
3281
3498
  //#endregion
3282
3499
  //#region src/plugins/spa/components.d.ts
3283
3500
  /**
3284
- * Create a validated component definition. Validates hook names at registration
3285
- * for fail-fast typo detection (e.g. `onMout` throws immediately) and asserts
3286
- * each provided hook is a function.
3501
+ * Create a validated component definition. Accepts either the legacy hooks-only form
3502
+ * (`createComponent("counter", { onMount() {} })`) or the plugin-mirror spec form
3503
+ * (`createComponent("board", { state, render, events, api, ...hooks })`). Spec-only
3504
+ * keys (`state`/`render`/`events`/`api`) are partitioned out before hook-name
3505
+ * validation, so a real typo (e.g. `onMout`) still throws immediately while the spec
3506
+ * keys are accepted.
3287
3507
  *
3288
3508
  * @param name - Unique component name.
3289
- * @param hooks - Lifecycle hook implementations.
3509
+ * @param spec - Lifecycle hooks, or the `{ state, render, events, api, ...hooks }` spec.
3290
3510
  * @returns A `ComponentDef` ready to `register`.
3291
- * @throws {Error} If `name` is empty, any hook key is not in
3292
- * `COMPONENT_HOOK_NAMES`, or any provided hook value is not a function.
3511
+ * @throws {Error} If `name` is empty, a hook key is unknown, or an extra/hook value has the wrong shape.
3512
+ * @example
3513
+ * const counter = createComponent("counter", { onMount({ el }) { el.textContent = "0"; } });
3293
3514
  * @example
3294
- * const counter = createComponent("counter", {
3295
- * onMount({ el }) { el.textContent = "0"; }
3515
+ * const list = createComponent<{ items: string[] }>("list", {
3516
+ * state: () => ({ items: [] }),
3517
+ * render: (s) => h(List, { items: s.items })
3296
3518
  * });
3297
3519
  */
3298
- declare function createComponent(name: string, hooks: ComponentHooks): ComponentDef;
3520
+ declare function createComponent<S extends object = object, A = unknown>(name: string, spec: ComponentSpec<S, A>): ComponentDef;
3299
3521
  //#endregion
3300
3522
  //#region src/plugins/spa/lazy-embed.d.ts
3301
3523
  /**