@moku-labs/web 0.5.6 → 1.0.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/README.md +227 -124
- package/dist/browser.d.mts +524 -111
- package/dist/browser.mjs +1565 -798
- package/dist/{convention-X3zLTlJ8.mjs → convention-CepUwWmT.mjs} +18 -1
- package/dist/{convention-Dr8jxG70.cjs → convention-krwh7Y6Q.cjs} +23 -0
- package/dist/index.cjs +4799 -2628
- package/dist/index.d.cts +1024 -419
- package/dist/index.d.mts +1023 -418
- package/dist/index.mjs +4840 -2678
- package/dist/{writer-DAF0pM25.cjs → writer-DV5hWB2i.cjs} +25 -27
- package/dist/{writer-BcWqa_7I.mjs → writer-Dc_lx22j.mjs} +25 -27
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { EmitFn } from "@moku-labs/core";
|
|
2
|
-
import { Pluggable, Processor } from "unified";
|
|
3
2
|
import { ComponentChildren, VNode } from "preact";
|
|
3
|
+
import { Pluggable, Processor } from "unified";
|
|
4
4
|
import { BundledTheme, ThemeRegistrationAny } from "shiki";
|
|
5
5
|
|
|
6
6
|
//#region src/plugins/log/types.d.ts
|
|
7
|
-
declare namespace types_d_exports$
|
|
7
|
+
declare namespace types_d_exports$7 {
|
|
8
8
|
export { ExpectChain, LogApi, LogConfig, LogEntry, LogLevel, LogSink, LogState };
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -144,7 +144,7 @@ type LogApi = {
|
|
|
144
144
|
addSink(sink: LogSink): void; /** Clear all recorded entries while keeping registered sinks. */
|
|
145
145
|
reset(): void;
|
|
146
146
|
};
|
|
147
|
-
declare namespace types_d_exports$
|
|
147
|
+
declare namespace types_d_exports$5 {
|
|
148
148
|
export { EnvApi, EnvConfig, EnvProvider, EnvState, EnvVarSpec };
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
@@ -155,8 +155,9 @@ declare namespace types_d_exports$4 {
|
|
|
155
155
|
*
|
|
156
156
|
* Providers are walked in array order during resolution; the first provider to
|
|
157
157
|
* return a non-`undefined` (and non-empty-string) value for a key wins. `load()`
|
|
158
|
-
* is called once per resolution at `onInit` time
|
|
159
|
-
*
|
|
158
|
+
* is called exactly once per resolution at `onInit` time, after which both env
|
|
159
|
+
* maps are frozen. A provider like {@link cloudflareBindings} reads `globalThis`
|
|
160
|
+
* at that single `onInit` call (not per request).
|
|
160
161
|
*
|
|
161
162
|
* @example
|
|
162
163
|
* ```ts
|
|
@@ -227,7 +228,8 @@ type EnvConfig = {
|
|
|
227
228
|
/**
|
|
228
229
|
* Ordered list of value sources. The first provider yielding a non-`undefined`
|
|
229
230
|
* (and non-empty-string) value for a key wins. The plugin's own spec default is
|
|
230
|
-
* `[]`; the
|
|
231
|
+
* `[]`; the consumer supplies the providers per target (`[dotenv(), processEnv()]`
|
|
232
|
+
* on Node) — only the `/browser` entry pre-wires `browserEnv()` out of the box.
|
|
231
233
|
*/
|
|
232
234
|
providers: EnvProvider[];
|
|
233
235
|
/**
|
|
@@ -336,12 +338,25 @@ declare function browserEnv(options?: {
|
|
|
336
338
|
declare const envPlugin: import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>;
|
|
337
339
|
//#endregion
|
|
338
340
|
//#region src/config.d.ts
|
|
341
|
+
/**
|
|
342
|
+
* Deployment stage. Drives content draft visibility — drafts are suppressed
|
|
343
|
+
* only in `"production"`; `"development"` and `"test"` both surface them.
|
|
344
|
+
*/
|
|
345
|
+
type Stage = "production" | "development" | "test";
|
|
339
346
|
/**
|
|
340
347
|
* Global framework configuration. Minimal by design — per-plugin config is
|
|
341
348
|
* resolved via `pluginConfigs`, not merged here.
|
|
342
349
|
*/
|
|
343
|
-
type Config$
|
|
344
|
-
/**
|
|
350
|
+
type Config$8 = {
|
|
351
|
+
/** Deployment stage. Drives content draft visibility (drafts hidden only in `"production"`). */stage: Stage;
|
|
352
|
+
/**
|
|
353
|
+
* Render mode — the single SSG/DATA/SPA switch, read by the router (`ctx.global`)
|
|
354
|
+
* and consumed by `build`/`spa` via `router.mode()`.
|
|
355
|
+
* - `"ssg"` static generation only (no client router emitted).
|
|
356
|
+
* - `"spa"` client-side routing only.
|
|
357
|
+
* - `"hybrid"` static HTML + client navigation overlay (default).
|
|
358
|
+
*/
|
|
359
|
+
mode: "ssg" | "spa" | "hybrid";
|
|
345
360
|
};
|
|
346
361
|
/**
|
|
347
362
|
* Framework event contract. Empty base — each plugin declares its own events
|
|
@@ -375,7 +390,7 @@ type Events = {};
|
|
|
375
390
|
* });
|
|
376
391
|
* ```
|
|
377
392
|
*/
|
|
378
|
-
type Config$
|
|
393
|
+
type Config$7 = {
|
|
379
394
|
/** Human-readable site name. Used in feeds, og:site_name, and titles. MUST be non-empty. */name: string; /** Absolute base URL of the site, e.g. "https://blog.dev". MUST be a valid absolute URL (http/https). */
|
|
380
395
|
url: string; /** Default author/byline for the site. Used in feeds and article author meta. */
|
|
381
396
|
author: string; /** Short site description. Used in feeds, the default meta description, and og:description fallbacks. */
|
|
@@ -385,7 +400,7 @@ type Config$6 = {
|
|
|
385
400
|
* Public API of the site plugin — read-only accessors over frozen global
|
|
386
401
|
* site metadata, plus canonical URL construction.
|
|
387
402
|
*/
|
|
388
|
-
type Api$
|
|
403
|
+
type Api$7 = {
|
|
389
404
|
/**
|
|
390
405
|
* Returns the configured site name.
|
|
391
406
|
*
|
|
@@ -446,7 +461,7 @@ type Api$6 = {
|
|
|
446
461
|
* @file i18n plugin — public type definitions (Config + Api).
|
|
447
462
|
*/
|
|
448
463
|
/**
|
|
449
|
-
* i18n plugin configuration.
|
|
464
|
+
* i18n plugin configuration.
|
|
450
465
|
*
|
|
451
466
|
* `locales` and `defaultLocale` are required and validated in `onInit`. The
|
|
452
467
|
* optional maps default to empty objects so every lookup method is total —
|
|
@@ -463,7 +478,7 @@ type Api$6 = {
|
|
|
463
478
|
* }
|
|
464
479
|
* ```
|
|
465
480
|
*/
|
|
466
|
-
type Config$
|
|
481
|
+
type Config$6 = {
|
|
467
482
|
readonly locales: readonly string[];
|
|
468
483
|
readonly defaultLocale: string;
|
|
469
484
|
readonly localeNames?: Record<string, string>;
|
|
@@ -474,7 +489,7 @@ type Config$5 = {
|
|
|
474
489
|
* Public API of the i18n plugin. Injected as `app.i18n` and reachable from
|
|
475
490
|
* other plugins via `ctx.require(i18nPlugin)`.
|
|
476
491
|
*/
|
|
477
|
-
type Api$
|
|
492
|
+
type Api$6 = {
|
|
478
493
|
/**
|
|
479
494
|
* Returns the configured supported locales in declared order.
|
|
480
495
|
*
|
|
@@ -542,8 +557,8 @@ type Api$5 = {
|
|
|
542
557
|
*/
|
|
543
558
|
t(locale: string, key: string): string;
|
|
544
559
|
};
|
|
545
|
-
declare namespace types_d_exports$
|
|
546
|
-
export { Api$
|
|
560
|
+
declare namespace types_d_exports$8 {
|
|
561
|
+
export { Api$5 as Api, ClientRoute, CompileInput, CompiledRoute, Config$5 as Config, ExtractApi$2 as ExtractApi, ExtractRouteParams, ExtractSegmentParameter, GenerateContext, HeadConfig$1 as HeadConfig, LayoutContext, LoadContext, MatcherTable, Prettify, RouteBuilder, RouteContext, RouteDefinition, RouteHandlers, RouteMap, RouteRequire, RouteState, RouterApi, RouterConfig, RouterState, State$5 as State, TypedRoute, Urls };
|
|
547
562
|
}
|
|
548
563
|
/**
|
|
549
564
|
* Param contribution of a single path segment. `{name:?}` / `:name?` → optional;
|
|
@@ -582,6 +597,84 @@ interface RouteContext<S extends RouteState> {
|
|
|
582
597
|
readonly data: S["data"];
|
|
583
598
|
/** Active locale for this render. */
|
|
584
599
|
readonly locale: string;
|
|
600
|
+
/**
|
|
601
|
+
* Build a link to a named route by pattern substitution — the framework delivers
|
|
602
|
+
* this on the context (same output as `app.router.toUrl`), so render/head build
|
|
603
|
+
* links with no `app`/`createUrls` reference. Works identically at build and on
|
|
604
|
+
* client navigation.
|
|
605
|
+
*/
|
|
606
|
+
readonly url: (name: string, params?: Record<string, string>) => string;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Structural extraction of a plugin instance's public API from its `_phantom`
|
|
610
|
+
* carrier (mirrors the kernel's `ExtractApi` / spec/09 §3). Lets the loader/generator
|
|
611
|
+
* `require` resolve a plugin instance to its typed public API.
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* type ContentApi = ExtractApi<typeof contentPlugin>;
|
|
615
|
+
*/
|
|
616
|
+
type ExtractApi$2<PluginCandidate> = PluginCandidate extends {
|
|
617
|
+
readonly _phantom: {
|
|
618
|
+
readonly api: infer PluginApi;
|
|
619
|
+
};
|
|
620
|
+
} ? PluginApi : never;
|
|
621
|
+
/**
|
|
622
|
+
* Generic, instance-only `require` handed to a route's `.load()` / `.generate()` —
|
|
623
|
+
* the SAME shape as the kernel's `RequireFunction` (spec/08 §7) and the build's
|
|
624
|
+
* `PhaseRequire`, so the build forwards its own `ctx.require` straight through.
|
|
625
|
+
* Resolves a plugin INSTANCE to its public API; the consumer supplies the instance
|
|
626
|
+
* (e.g. `ctx.require(contentPlugin)`), so the router never names a sibling plugin.
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* const content = ctx.require(contentPlugin); // ContentApi
|
|
630
|
+
*/
|
|
631
|
+
type RouteRequire = <PluginCandidate extends {
|
|
632
|
+
readonly name: string;
|
|
633
|
+
readonly spec: unknown;
|
|
634
|
+
readonly _phantom: {
|
|
635
|
+
readonly config: unknown;
|
|
636
|
+
readonly state: unknown;
|
|
637
|
+
readonly api: unknown;
|
|
638
|
+
readonly events: Record<string, unknown>;
|
|
639
|
+
};
|
|
640
|
+
}>(plugin: PluginCandidate) => ExtractApi$2<PluginCandidate>;
|
|
641
|
+
/**
|
|
642
|
+
* Build-time context handed to a route's `.load()`. Carries the resolved path
|
|
643
|
+
* `params` and active `locale`, plus the spec's `require`/`has` so a loader pulls
|
|
644
|
+
* sibling plugin APIs the canonical way — `ctx.require(contentPlugin)` — with no
|
|
645
|
+
* module global and no router→content coupling. Loaders run ONLY at build time
|
|
646
|
+
* (never on the client), inside the build plugin's context, so `require`/`has` are
|
|
647
|
+
* always live here.
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* route("/{slug}/").load((ctx) => ctx.require(contentPlugin).load(ctx.params.slug, ctx.locale));
|
|
651
|
+
*/
|
|
652
|
+
interface LoadContext<S extends RouteState> {
|
|
653
|
+
/** Resolved path params for this page instance. */
|
|
654
|
+
readonly params: S["params"];
|
|
655
|
+
/** Active locale this page instance is built for. */
|
|
656
|
+
readonly locale: string;
|
|
657
|
+
/** Resolve a sibling plugin instance to its public API (spec/08 §7). */
|
|
658
|
+
readonly require: RouteRequire;
|
|
659
|
+
/** Whether a plugin is registered (by name) — branch on OPTIONAL plugins. */
|
|
660
|
+
readonly has: (name: string) => boolean;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Build-time context handed to a route's `.generate()` — the static-param producer.
|
|
664
|
+
* Carries the active `locale` plus `require`/`has` (no `params` yet — `.generate()`
|
|
665
|
+
* PRODUCES the param sets). Same build-only guarantee as {@link LoadContext}.
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* route("/{slug}/").generate(async (ctx) =>
|
|
669
|
+
* [...(await ctx.require(contentPlugin).loadAll()).get(ctx.locale) ?? []].map((a) => ({ slug: a.computed.slug })));
|
|
670
|
+
*/
|
|
671
|
+
interface GenerateContext {
|
|
672
|
+
/** Active locale to enumerate param sets for. */
|
|
673
|
+
readonly locale: string;
|
|
674
|
+
/** Resolve a sibling plugin instance to its public API (spec/08 §7). */
|
|
675
|
+
readonly require: RouteRequire;
|
|
676
|
+
/** Whether a plugin is registered (by name). */
|
|
677
|
+
readonly has: (name: string) => boolean;
|
|
585
678
|
}
|
|
586
679
|
/**
|
|
587
680
|
* Context handed to a route's `.layout()` wrapper: the render-time
|
|
@@ -617,7 +710,7 @@ interface RouteBuilder<S extends RouteState> extends RouteDefinition {
|
|
|
617
710
|
* Attach a data loader; widens the data generic (and ONLY the data generic) so
|
|
618
711
|
* `.render()`/`.head()` see its return. Path params are preserved unchanged.
|
|
619
712
|
*/
|
|
620
|
-
load<D>(loader: (
|
|
713
|
+
load<D>(loader: (ctx: LoadContext<S>) => D | Promise<D>): RouteBuilder<{
|
|
621
714
|
readonly params: S["params"];
|
|
622
715
|
readonly data: Awaited<D>;
|
|
623
716
|
}>;
|
|
@@ -631,19 +724,10 @@ interface RouteBuilder<S extends RouteState> extends RouteDefinition {
|
|
|
631
724
|
layout(component: (ctx: LayoutContext<S>, children: ComponentChildren) => VNode): RouteBuilder<S>;
|
|
632
725
|
/** Attach the page render handler. */
|
|
633
726
|
render(handler: (ctx: RouteContext<S>) => VNode): RouteBuilder<S>;
|
|
634
|
-
/**
|
|
635
|
-
* Attach the client-side validation gate: parse the raw `unknown` fetched from
|
|
636
|
-
* the persisted data file back into this route's data type `S["data"]`. Runs at
|
|
637
|
-
* the trust boundary before `render` on the client (and MUST return `S["data"]`,
|
|
638
|
-
* so a mismatched schema is a compile error). Throw inside it to reject malformed
|
|
639
|
-
* data — `spa` then falls back to HTML-over-fetch. Use a hand guard or any
|
|
640
|
-
* Standard-Schema validator (zod/valibot/arktype).
|
|
641
|
-
*/
|
|
642
|
-
parse(handler: (raw: unknown) => S["data"]): RouteBuilder<S>;
|
|
643
727
|
/** Attach the head/SEO handler. */
|
|
644
728
|
head(handler: (ctx: RouteContext<S>) => HeadConfig$1): RouteBuilder<S>;
|
|
645
|
-
/** Attach a static-generation param producer. */
|
|
646
|
-
generate(handler: (
|
|
729
|
+
/** Attach a static-generation param producer (receives a {@link GenerateContext}). */
|
|
730
|
+
generate(handler: (ctx: GenerateContext) => S["params"][] | Promise<S["params"][]>): RouteBuilder<S>;
|
|
647
731
|
/**
|
|
648
732
|
* Attach an arbitrary metadata bag. The bag MUST be JSON-serializable: it is
|
|
649
733
|
* projected verbatim into `clientManifest()` and shipped to the browser.
|
|
@@ -656,18 +740,16 @@ interface RouteBuilder<S extends RouteState> extends RouteDefinition {
|
|
|
656
740
|
}
|
|
657
741
|
/** Build-only handler bag captured by a `RouteBuilder` (consumed by `build` via `manifest()`). */
|
|
658
742
|
interface RouteHandlers {
|
|
659
|
-
/** Data loader. */
|
|
660
|
-
readonly load?: (
|
|
743
|
+
/** Data loader (receives a {@link LoadContext}: params + locale + require/has). */
|
|
744
|
+
readonly load?: (ctx: LoadContext<RouteState>) => unknown;
|
|
661
745
|
/** Layout wrapper (ctx-aware): frames the page in persistent chrome. SSG-only. */
|
|
662
746
|
readonly layout?: (ctx: LayoutContext<RouteState>, children: ComponentChildren) => VNode;
|
|
663
747
|
/** Page renderer. */
|
|
664
748
|
readonly render?: (ctx: RouteContext<RouteState>) => VNode;
|
|
665
|
-
/** Client-side validation gate: `unknown` (fetched JSON) → the route's data type, or throw. */
|
|
666
|
-
readonly parse?: (raw: unknown) => unknown;
|
|
667
749
|
/** Head/SEO producer. */
|
|
668
750
|
readonly head?: (ctx: RouteContext<RouteState>) => HeadConfig$1;
|
|
669
|
-
/** Static-generation param producer. */
|
|
670
|
-
readonly generate?: (
|
|
751
|
+
/** Static-generation param producer (receives a {@link GenerateContext}). */
|
|
752
|
+
readonly generate?: (ctx: GenerateContext) => unknown[] | Promise<unknown[]>;
|
|
671
753
|
/** JSON serializer. */
|
|
672
754
|
readonly toJson?: (ctx: RouteContext<RouteState>) => unknown;
|
|
673
755
|
/** Output file-path producer. */
|
|
@@ -691,28 +773,45 @@ interface RouteDefinition {
|
|
|
691
773
|
* base (erased) `RouteDefinition`; this is the documented generic-erasure boundary.
|
|
692
774
|
*/
|
|
693
775
|
type RouteMap = Record<string, RouteDefinition>;
|
|
776
|
+
/**
|
|
777
|
+
* A pure, app-free URL builder over a route map (the return type of `createUrls`).
|
|
778
|
+
* `toUrl` builds a route's path by name + params via pattern substitution — it needs
|
|
779
|
+
* NO running app, router instance, base URL, or i18n: just the route map the consumer
|
|
780
|
+
* already holds at module scope. Works identically at build, on client navigation,
|
|
781
|
+
* and inside hydrated islands. Reuses the SAME `buildUrl` as the runtime `RouterApi`,
|
|
782
|
+
* so the helper and the API can never diverge.
|
|
783
|
+
*
|
|
784
|
+
* @example
|
|
785
|
+
* const url = createUrls(routes);
|
|
786
|
+
* url.toUrl("article", { lang: "en", slug: "hello" }); // "/en/hello/"
|
|
787
|
+
*/
|
|
788
|
+
interface Urls<T extends RouteMap> {
|
|
789
|
+
/**
|
|
790
|
+
* Build a route's URL path from its name and params. The name is typed to the
|
|
791
|
+
* route map's keys — only declared routes are accepted.
|
|
792
|
+
*
|
|
793
|
+
* @param name - Route name key from the map (e.g. `"home"`, `"article"`).
|
|
794
|
+
* @param params - Path params to substitute into the pattern. Defaults to `{}`.
|
|
795
|
+
* @returns The resolved relative URL path.
|
|
796
|
+
* @throws {Error} If `name` is not present in the route map.
|
|
797
|
+
* @example
|
|
798
|
+
* url.toUrl("home", { lang: "en" }); // "/en/"
|
|
799
|
+
*/
|
|
800
|
+
toUrl<K extends keyof T & string>(name: K, params?: Record<string, string>): string;
|
|
801
|
+
}
|
|
694
802
|
/**
|
|
695
803
|
* Configuration for the router plugin.
|
|
696
804
|
*
|
|
697
805
|
* @remarks
|
|
698
|
-
* `routes` is
|
|
699
|
-
*
|
|
700
|
-
*
|
|
806
|
+
* `routes` is the declarative route map — registered the normal config way via
|
|
807
|
+
* `createApp({ pluginConfigs: { router: { routes } } })` and compiled into the matcher
|
|
808
|
+
* table in the router's `onInit`. An `import * as routes` namespace is a valid value. It is
|
|
809
|
+
* the SOLE registration path: omitting it leaves the matcher table empty, so every read
|
|
810
|
+
* (`match`/`toUrl`/`entries`/…) throws. The render `mode` is NOT here — it is a GLOBAL
|
|
811
|
+
* framework option (`createApp({ config: { mode } })`), read by the router via `ctx.global`.
|
|
701
812
|
*/
|
|
702
813
|
type RouterConfig = {
|
|
703
|
-
/**
|
|
704
|
-
* Named route definitions. Element type erases to the base `RouteDefinition`
|
|
705
|
-
* at this config boundary; per-route call-site types are preserved only through
|
|
706
|
-
* `defineRoutes()` + `route()` at the consumer and re-exposed via `manifest()`.
|
|
707
|
-
*/
|
|
708
|
-
routes: RouteMap;
|
|
709
|
-
/**
|
|
710
|
-
* Render mode for URL/file resolution. Defaults to `"hybrid"`.
|
|
711
|
-
* - `"ssg"` static generation only (no client router emitted).
|
|
712
|
-
* - `"spa"` client-side routing only.
|
|
713
|
-
* - `"hybrid"` static HTML + client navigation overlay.
|
|
714
|
-
*/
|
|
715
|
-
mode?: "ssg" | "spa" | "hybrid";
|
|
814
|
+
/** Declarative route map (route name → `route(...)`); compiled at init. An `import * as` namespace works. */readonly routes?: RouteMap;
|
|
716
815
|
};
|
|
717
816
|
/** A resolved route exposing URL utilities with typed params (port of legacy TypedRoute). */
|
|
718
817
|
interface TypedRoute<TParams = Record<string, string>> {
|
|
@@ -761,15 +860,14 @@ interface MatcherTable {
|
|
|
761
860
|
readonly byName: ReadonlyMap<string, CompiledRoute>;
|
|
762
861
|
}
|
|
763
862
|
/**
|
|
764
|
-
* Router plugin state
|
|
765
|
-
*
|
|
766
|
-
*
|
|
863
|
+
* Router plugin state — a mutable holder whose `table` is `null` until the router's
|
|
864
|
+
* `onInit` compiles `config.routes`. The render `mode` is NOT stored here; it is read
|
|
865
|
+
* from the global framework config via the API context. Keeps all mutable state in
|
|
866
|
+
* `ctx.state` (no singletons).
|
|
767
867
|
*/
|
|
768
868
|
interface RouterState {
|
|
769
|
-
/** Compiled matcher table; `null` until `onInit`
|
|
869
|
+
/** Compiled matcher table; `null` until `onInit` compiles `config.routes`. */
|
|
770
870
|
table: MatcherTable | null;
|
|
771
|
-
/** Resolved render mode (single source of truth; set in `onInit`). Defaults `"hybrid"`. */
|
|
772
|
-
mode: "ssg" | "spa" | "hybrid";
|
|
773
871
|
}
|
|
774
872
|
/** Plain-data input to `compileRoutes` — resolved DATA only, never the plugin ctx. */
|
|
775
873
|
interface CompileInput {
|
|
@@ -802,7 +900,7 @@ interface ClientRoute {
|
|
|
802
900
|
/** Route metadata bag from `.meta()`. MUST be JSON-serializable. */
|
|
803
901
|
readonly meta: Record<string, unknown>;
|
|
804
902
|
}
|
|
805
|
-
/** Public API exposed via `ctx.require(routerPlugin)`. */
|
|
903
|
+
/** Public API exposed via `ctx.require(routerPlugin)` and `app.router`. */
|
|
806
904
|
type RouterApi = {
|
|
807
905
|
/**
|
|
808
906
|
* Match a pathname against the compiled route table (specificity-sorted).
|
|
@@ -841,7 +939,7 @@ type RouterApi = {
|
|
|
841
939
|
*
|
|
842
940
|
* @returns Read-only array of the typed route definitions, in declaration order.
|
|
843
941
|
* @example
|
|
844
|
-
* for (const def of ctx.require(routerPlugin).manifest())
|
|
942
|
+
* for (const def of ctx.require(routerPlugin).manifest()) def._handlers.render?.(routeContext);
|
|
845
943
|
*/
|
|
846
944
|
manifest(): readonly RouteDefinition[];
|
|
847
945
|
/**
|
|
@@ -867,13 +965,13 @@ type RouterApi = {
|
|
|
867
965
|
mode(): "ssg" | "spa" | "hybrid";
|
|
868
966
|
};
|
|
869
967
|
/** Re-export under the canonical `Config` name for the plugin-types barrel. */
|
|
870
|
-
type Config$
|
|
968
|
+
type Config$5 = RouterConfig;
|
|
871
969
|
/** Re-export under the canonical `State` name for the plugin-types barrel. */
|
|
872
|
-
type State$
|
|
970
|
+
type State$5 = RouterState;
|
|
873
971
|
/** Re-export under the canonical `Api` name for the plugin-types barrel. */
|
|
874
|
-
type Api$
|
|
875
|
-
declare namespace types_d_exports$
|
|
876
|
-
export { Api$
|
|
972
|
+
type Api$5 = RouterApi;
|
|
973
|
+
declare namespace types_d_exports$6 {
|
|
974
|
+
export { Api$4 as Api, ArticleMeta, Config$4 as Config, HeadConfig, HeadDefaults, HeadElement, ResolvedRoute, State$4 as State };
|
|
877
975
|
}
|
|
878
976
|
/**
|
|
879
977
|
* @file head plugin — type definitions skeleton
|
|
@@ -889,7 +987,7 @@ declare namespace types_d_exports$5 {
|
|
|
889
987
|
* const config: Config = { titleTemplate: "%s — Moku" };
|
|
890
988
|
* ```
|
|
891
989
|
*/
|
|
892
|
-
type Config$
|
|
990
|
+
type Config$4 = {
|
|
893
991
|
/** Title template applied to per-route titles. `%s` is replaced by the route title. */titleTemplate?: string; /** Default Open Graph image URL used when a route does not supply one. */
|
|
894
992
|
defaultOgImage?: string; /** Default Twitter card type emitted when og/twitter content is present. */
|
|
895
993
|
twitterCard?: "summary" | "summary_large_image"; /** Default Twitter site handle (e.g. `"@moku_labs"`) emitted as `twitter:site`. */
|
|
@@ -907,7 +1005,7 @@ type Config$3 = {
|
|
|
907
1005
|
* const state: State = { defaults: null };
|
|
908
1006
|
* ```
|
|
909
1007
|
*/
|
|
910
|
-
type State$
|
|
1008
|
+
type State$4 = {
|
|
911
1009
|
/** Normalized head defaults, assigned once in `onInit` (initially `null`). */defaults: HeadDefaults | null;
|
|
912
1010
|
};
|
|
913
1011
|
/**
|
|
@@ -1001,7 +1099,7 @@ type ResolvedRoute = {
|
|
|
1001
1099
|
* const html: string = api.render(route, data);
|
|
1002
1100
|
* ```
|
|
1003
1101
|
*/
|
|
1004
|
-
type Api$
|
|
1102
|
+
type Api$4 = {
|
|
1005
1103
|
/**
|
|
1006
1104
|
* Compose the final `<head>` inner HTML for a route. Pulled synchronously by `build`.
|
|
1007
1105
|
*
|
|
@@ -1015,7 +1113,7 @@ type Api$3 = {
|
|
|
1015
1113
|
*/
|
|
1016
1114
|
render(route: ResolvedRoute, data: unknown): string;
|
|
1017
1115
|
};
|
|
1018
|
-
declare namespace types_d_exports$
|
|
1116
|
+
declare namespace types_d_exports$9 {
|
|
1019
1117
|
export { COMPONENT_HOOK_NAMES, ComponentContext, ComponentDef, ComponentHooks, ComponentInstance, ExtractApi$1 as ExtractApi, PageData, ResolvedSpaConfig, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState };
|
|
1020
1118
|
}
|
|
1021
1119
|
/** Payload map for the events `spa` emits, used to type the kernel's `emit` closure. */
|
|
@@ -1216,11 +1314,11 @@ interface SpaKernelDeps {
|
|
|
1216
1314
|
/** Router plugin API — used for client-side route matching (`match`) + the resolved `mode`. */
|
|
1217
1315
|
router: RouterApi;
|
|
1218
1316
|
/** Head plugin API — its pure compose is reused for client head-sync. */
|
|
1219
|
-
head: Api$
|
|
1317
|
+
head: Api$4;
|
|
1220
1318
|
/**
|
|
1221
1319
|
* The OPTIONAL `data` reader. Present only when the `data` plugin is composed.
|
|
1222
1320
|
* When present (and `router.mode() !== "ssg"`), navigation first tries the client
|
|
1223
|
-
* DATA path (match → `dataAt(path)` → `route.
|
|
1321
|
+
* DATA path (match → `dataAt(path)` → `route.render`); otherwise
|
|
1224
1322
|
* it always uses HTML-over-fetch.
|
|
1225
1323
|
*/
|
|
1226
1324
|
dataAt?: SpaDataReader;
|
|
@@ -1323,7 +1421,7 @@ type SpaApi = {
|
|
|
1323
1421
|
current(): string;
|
|
1324
1422
|
};
|
|
1325
1423
|
declare namespace types_d_exports {
|
|
1326
|
-
export { Api$
|
|
1424
|
+
export { Api$3 as Api, BuildCacheEntry, BuildEvents, BuildResult, Config$3 as Config, ExtractApi, OgFont, OgImageConfig, PhaseContext, PhaseEmit, PhaseLog, PhaseName, PhaseRequire, RichOgInput, State$3 as State };
|
|
1327
1425
|
}
|
|
1328
1426
|
/**
|
|
1329
1427
|
* Structural extraction of a plugin instance's public API from its `_phantom`
|
|
@@ -1400,27 +1498,16 @@ type PhaseRequire = <PluginCandidate extends {
|
|
|
1400
1498
|
* ```
|
|
1401
1499
|
*/
|
|
1402
1500
|
type PhaseContext = {
|
|
1403
|
-
/** Mutable per-run build state (caches + runId). */state: State$
|
|
1404
|
-
readonly config: Readonly<Config$
|
|
1501
|
+
/** Mutable per-run build state (caches + runId). */state: State$3; /** Resolved, frozen build config. */
|
|
1502
|
+
readonly config: Readonly<Config$3>; /** Global framework config (deployment stage; render mode is read via `router.mode()`). */
|
|
1405
1503
|
readonly global: Readonly<{
|
|
1406
|
-
|
|
1504
|
+
stage: Stage;
|
|
1407
1505
|
}>; /** Resolve a depended-upon plugin instance to its public API. */
|
|
1408
1506
|
require: PhaseRequire; /** Whether a plugin is registered (by name) — used to detect the OPTIONAL `data` plugin. */
|
|
1409
1507
|
has: (name: string) => boolean; /** Emit a build event (notification-only). */
|
|
1410
1508
|
emit: PhaseEmit; /** Structured logger (core `log` API). */
|
|
1411
1509
|
readonly log: PhaseLog;
|
|
1412
1510
|
};
|
|
1413
|
-
/**
|
|
1414
|
-
* Injectable PNG renderer for the og-images phase. Defaults to the real
|
|
1415
|
-
* Satori → resvg pipeline; unit tests inject a fake to assert hash-cache skip
|
|
1416
|
-
* and the `p-limit` bound without rasterizing real images.
|
|
1417
|
-
*
|
|
1418
|
-
* @example
|
|
1419
|
-
* ```ts
|
|
1420
|
-
* const render: OgPngRenderer = async () => new Uint8Array();
|
|
1421
|
-
* ```
|
|
1422
|
-
*/
|
|
1423
|
-
type OgPngRenderer = (input: RichOgInput) => Promise<Uint8Array>;
|
|
1424
1511
|
/**
|
|
1425
1512
|
* Rich input handed to a custom OG `render` hook for a single article card. Carries
|
|
1426
1513
|
* the full article + site metadata so a consumer can compose any layout. Returned by
|
|
@@ -1510,7 +1597,7 @@ interface OgImageConfig {
|
|
|
1510
1597
|
* const config: Config = { outDir: "./dist", minify: true, feeds: true, sitemap: true, images: true, ogImage: false };
|
|
1511
1598
|
* ```
|
|
1512
1599
|
*/
|
|
1513
|
-
type Config$
|
|
1600
|
+
type Config$3 = {
|
|
1514
1601
|
/** Output directory for the built site. */outDir: string; /** Minify bundled CSS/JS. */
|
|
1515
1602
|
minify: boolean; /** Generate RSS/Atom/JSON feeds. */
|
|
1516
1603
|
feeds: boolean; /** Generate sitemap.xml + robots.txt. */
|
|
@@ -1521,11 +1608,11 @@ type Config$2 = {
|
|
|
1521
1608
|
publicDir?: string;
|
|
1522
1609
|
/**
|
|
1523
1610
|
* Emit `outDir/404.html`. `true` for the built-in default page, or
|
|
1524
|
-
* `{
|
|
1525
|
-
*
|
|
1611
|
+
* `{ body }` to supply the page's literal HTML body content (written into the
|
|
1612
|
+
* 404 page verbatim). Default `false`.
|
|
1526
1613
|
*/
|
|
1527
1614
|
notFound?: boolean | {
|
|
1528
|
-
|
|
1615
|
+
body?: string;
|
|
1529
1616
|
}; /** Emit per-path i18n bare-path redirect HTML pages. Default `false`. */
|
|
1530
1617
|
localeRedirects?: boolean; /** Authoritative client bundle entry path (overrides the conventional scan). */
|
|
1531
1618
|
clientEntry?: string; /** HTML shell template with `<!--moku:head-->`/`<!--moku:body-->`/`<!--moku:assets-->` placeholders. */
|
|
@@ -1551,9 +1638,9 @@ type BuildCacheEntry = Record<string, string>;
|
|
|
1551
1638
|
* const state: State = { config, manifest: null, buildCache: new Map(), runId: null, ogImageHashCache: new Map() };
|
|
1552
1639
|
* ```
|
|
1553
1640
|
*/
|
|
1554
|
-
interface State$
|
|
1641
|
+
interface State$3 {
|
|
1555
1642
|
/** Resolved, frozen config snapshot. */
|
|
1556
|
-
config: Config$
|
|
1643
|
+
config: Config$3;
|
|
1557
1644
|
/** Cached route manifest for the current run (populated in Phase 3 from router). */
|
|
1558
1645
|
manifest: RouteDefinition[] | null;
|
|
1559
1646
|
/** Per-run build artifacts (e.g. hashed CSS/JS asset paths from Phase 1). */
|
|
@@ -1600,7 +1687,7 @@ interface BuildResult {
|
|
|
1600
1687
|
* const result = await app.build.run();
|
|
1601
1688
|
* ```
|
|
1602
1689
|
*/
|
|
1603
|
-
type Api$
|
|
1690
|
+
type Api$3 = {
|
|
1604
1691
|
/**
|
|
1605
1692
|
* Run the full SSG pipeline and write the site to disk.
|
|
1606
1693
|
*
|
|
@@ -1649,7 +1736,7 @@ type Api$2 = {
|
|
|
1649
1736
|
* });
|
|
1650
1737
|
* ```
|
|
1651
1738
|
*/
|
|
1652
|
-
declare const buildPlugin: import("@moku-labs/core").PluginInstance<"build", Config$
|
|
1739
|
+
declare const buildPlugin: import("@moku-labs/core").PluginInstance<"build", Config$3, State$3, Api$3, {
|
|
1653
1740
|
"build:phase": {
|
|
1654
1741
|
phase: PhaseName;
|
|
1655
1742
|
status: "start" | "done";
|
|
@@ -1661,117 +1748,780 @@ declare const buildPlugin: import("@moku-labs/core").PluginInstance<"build", Con
|
|
|
1661
1748
|
durationMs: number;
|
|
1662
1749
|
};
|
|
1663
1750
|
}> & Record<never, never>;
|
|
1664
|
-
declare namespace types_d_exports$
|
|
1665
|
-
export { Api$
|
|
1751
|
+
declare namespace types_d_exports$4 {
|
|
1752
|
+
export { Api$2 as Api, Config$2 as Config, DeployErrorCode, DeployInitOptions, DeployResult, DeployRunOptions, InitResult, SpawnFunction, SpawnOptions, SpawnedProcess, State$2 as State, WranglerErrorKind };
|
|
1666
1753
|
}
|
|
1667
1754
|
/**
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1670
|
-
* @example
|
|
1671
|
-
* ```ts
|
|
1672
|
-
* { contentDir: "./src/content", trustedContent: false, shikiTheme: "github-dark" }
|
|
1673
|
-
* ```
|
|
1755
|
+
* @file deploy plugin — type definitions.
|
|
1674
1756
|
*/
|
|
1675
|
-
|
|
1676
|
-
|
|
1757
|
+
/**
|
|
1758
|
+
* Options passed to the injected spawner — the subset of Bun.spawn's options the
|
|
1759
|
+
* plugin uses (piped stdout/stderr plus an env carrying the API token).
|
|
1760
|
+
*/
|
|
1761
|
+
interface SpawnOptions {
|
|
1762
|
+
/** Capture stdout as a readable stream. */
|
|
1763
|
+
readonly stdout: "pipe";
|
|
1764
|
+
/** Capture stderr as a readable stream. */
|
|
1765
|
+
readonly stderr: "pipe";
|
|
1766
|
+
/** Subprocess environment — the API token is injected here, never via argv. */
|
|
1767
|
+
readonly env?: Record<string, string | undefined>;
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* The structural subprocess handle the plugin reads back: stdout/stderr streams
|
|
1771
|
+
* plus the exit-code promise. Streams are typed `unknown` and narrowed at the read
|
|
1772
|
+
* site so this carries no Bun namespace types.
|
|
1773
|
+
*/
|
|
1774
|
+
interface SpawnedProcess {
|
|
1775
|
+
/** Standard output stream (narrowed to a ReadableStream at the read site). */
|
|
1776
|
+
readonly stdout: unknown;
|
|
1777
|
+
/** Standard error stream (narrowed to a ReadableStream at the read site). */
|
|
1778
|
+
readonly stderr: unknown;
|
|
1779
|
+
/** Resolves with the subprocess exit code. */
|
|
1780
|
+
readonly exited: Promise<number>;
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* The subset of Bun.spawn's signature the plugin relies on (argv array + options).
|
|
1784
|
+
* Declared structurally — with NO `import("bun")` namespace types — so it survives
|
|
1785
|
+
* `.d.ts` bundling intact and tests can supply a fake spawn without importing Bun.
|
|
1786
|
+
*/
|
|
1787
|
+
type SpawnFunction = (cmd: string[], options: SpawnOptions) => SpawnedProcess;
|
|
1788
|
+
/**
|
|
1789
|
+
* A deploy error `code` from the wrangler error taxonomy and preflight validators.
|
|
1790
|
+
*/
|
|
1791
|
+
type DeployErrorCode = "ERR_DEPLOY_NO_WRANGLER_CONFIG" | "ERR_DEPLOY_EMPTY_OUTDIR" | "ERR_DEPLOY_TOO_MANY_FILES" | "ERR_DEPLOY_FILE_TOO_LARGE" | "ERR_DEPLOY_PATH_TRAVERSAL" | "ERR_DEPLOY_INVALID_BRANCH" | "ERR_DEPLOY_NO_TOKEN" | "ERR_DEPLOY_PROJECT_NOT_FOUND" | "ERR_DEPLOY_AUTH_EXPIRED" | "ERR_DEPLOY_AUTH" | "ERR_DEPLOY_NETWORK" | "ERR_DEPLOY_WRANGLER_FAILED" | "ERR_DEPLOY_CONFIG";
|
|
1792
|
+
/**
|
|
1793
|
+
* The subset of wrangler error `code`s classifyWranglerError can produce from a
|
|
1794
|
+
* non-zero wrangler exit.
|
|
1795
|
+
*/
|
|
1796
|
+
type WranglerErrorKind = Extract<DeployErrorCode, "ERR_DEPLOY_PROJECT_NOT_FOUND" | "ERR_DEPLOY_AUTH_EXPIRED" | "ERR_DEPLOY_AUTH" | "ERR_DEPLOY_NETWORK" | "ERR_DEPLOY_WRANGLER_FAILED">;
|
|
1797
|
+
/**
|
|
1798
|
+
* Configuration for the deploy plugin.
|
|
1799
|
+
*/
|
|
1800
|
+
type Config$2 = {
|
|
1677
1801
|
/**
|
|
1678
|
-
*
|
|
1679
|
-
*
|
|
1680
|
-
* disables sanitize and trusts all raw HTML.
|
|
1802
|
+
* Deploy target. Only Cloudflare Pages is supported in this version.
|
|
1803
|
+
* Defaults to `cloudflare-pages`.
|
|
1681
1804
|
*/
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1805
|
+
target: "cloudflare-pages";
|
|
1806
|
+
/**
|
|
1807
|
+
* Directory (relative to project root) containing the built site to deploy.
|
|
1808
|
+
* Re-validated against cwd at run() time to block path traversal.
|
|
1809
|
+
* Defaults to `dist`.
|
|
1810
|
+
*/
|
|
1811
|
+
outDir: string;
|
|
1685
1812
|
/**
|
|
1686
|
-
*
|
|
1687
|
-
*
|
|
1688
|
-
* "github-dark") — or a custom `ThemeRegistration` object. Passed straight through
|
|
1689
|
-
* to `@shikijs/rehype`'s `theme`. (Like Shiki's own theme type, an arbitrary string
|
|
1690
|
-
* still compiles via the object arm, so this is autocomplete, not typo-rejection.)
|
|
1813
|
+
* Branch treated as the Cloudflare Pages production branch.
|
|
1814
|
+
* Defaults to `main`.
|
|
1691
1815
|
*/
|
|
1692
|
-
|
|
1693
|
-
|
|
1816
|
+
productionBranch?: string;
|
|
1817
|
+
/**
|
|
1818
|
+
* Substrings exempt from entropy-gated secret scrubbing in logged output.
|
|
1819
|
+
* Defaults to `["CLOUDFLARE_ACCOUNT_ID"]`.
|
|
1820
|
+
*/
|
|
1821
|
+
scrubAllowlist: string[];
|
|
1822
|
+
/**
|
|
1823
|
+
* Cloudflare compatibility date written into generated wrangler.jsonc.
|
|
1824
|
+
* Defaults to `2024-01-01`.
|
|
1825
|
+
*/
|
|
1826
|
+
compatibilityDate?: string;
|
|
1827
|
+
/**
|
|
1828
|
+
* Whether init() also generates a GitHub Actions workflow.
|
|
1829
|
+
* Defaults to `false`.
|
|
1830
|
+
*/
|
|
1831
|
+
ci?: boolean;
|
|
1694
1832
|
};
|
|
1695
1833
|
/**
|
|
1696
|
-
*
|
|
1697
|
-
*
|
|
1698
|
-
* @example
|
|
1699
|
-
* ```ts
|
|
1700
|
-
* { processor: null, articles: new Map(), slugs: null, dirtyPaths: new Set() }
|
|
1701
|
-
* ```
|
|
1834
|
+
* Result of a successful deploy.
|
|
1702
1835
|
*/
|
|
1703
|
-
type
|
|
1704
|
-
/**
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1836
|
+
type DeployResult = {
|
|
1837
|
+
/** The public deployment URL (e.g. https://my-site.pages.dev). */url: string; /** Cloudflare deployment ID parsed from wrangler output. */
|
|
1838
|
+
deploymentId: string; /** The branch that was deployed. */
|
|
1839
|
+
branch: string; /** Wall-clock duration of the deploy in milliseconds. */
|
|
1840
|
+
durationMs: number;
|
|
1708
1841
|
};
|
|
1709
1842
|
/**
|
|
1710
|
-
*
|
|
1711
|
-
*
|
|
1712
|
-
* @example
|
|
1713
|
-
* ```ts
|
|
1714
|
-
* { title: "Hello", date: "2026-01-15", description: "Intro", tags: [], language: "en" }
|
|
1715
|
-
* ```
|
|
1843
|
+
* Runtime state for the deploy plugin. Created in createState() and accessed via
|
|
1844
|
+
* ctx.state. deploy declares no onStop because nothing here is a long-lived resource.
|
|
1716
1845
|
*/
|
|
1717
|
-
type
|
|
1718
|
-
/**
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
author?: string;
|
|
1846
|
+
type State$2 = {
|
|
1847
|
+
/** Result of the most recent successful deploy, or null before the first run. */lastDeployment: DeployResult | null;
|
|
1848
|
+
/**
|
|
1849
|
+
* Injectable subprocess spawner. Defaults to Bun.spawn. Swapped for a mock in
|
|
1850
|
+
* unit tests so wrangler is never actually invoked. Never reassigned at runtime.
|
|
1851
|
+
*/
|
|
1852
|
+
spawn: SpawnFunction;
|
|
1725
1853
|
};
|
|
1726
1854
|
/**
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
1729
|
-
* @example
|
|
1730
|
-
* ```ts
|
|
1731
|
-
* { slug: "hello", readingTime: 1, contentId: "hello", status: "published", wordCount: 42 }
|
|
1732
|
-
* ```
|
|
1855
|
+
* Options for DeployApi.run.
|
|
1733
1856
|
*/
|
|
1734
|
-
type
|
|
1735
|
-
/**
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1857
|
+
type DeployRunOptions = {
|
|
1858
|
+
/**
|
|
1859
|
+
* Branch to deploy. Defaults to config.productionBranch (or "main"). Must match
|
|
1860
|
+
* /^[a-zA-Z0-9/_.-]+$/ — otherwise rejected with ERR_DEPLOY_INVALID_BRANCH.
|
|
1861
|
+
*/
|
|
1862
|
+
branch?: string;
|
|
1740
1863
|
};
|
|
1741
1864
|
/**
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
* @example
|
|
1745
|
-
* ```ts
|
|
1746
|
-
* { frontmatter, computed, html: "<p>…</p>", locale: "en", isFallback: false, url: "/en/hello/" }
|
|
1747
|
-
* ```
|
|
1865
|
+
* Options for DeployApi.init.
|
|
1748
1866
|
*/
|
|
1749
|
-
type
|
|
1750
|
-
/**
|
|
1751
|
-
|
|
1752
|
-
html: string; /** Locale this Article instance represents (the requested locale, even on fallback). */
|
|
1753
|
-
locale: string; /** True when the default-locale file was used because the requested locale was missing. */
|
|
1754
|
-
isFallback: boolean; /** Canonical URL for this article in this locale. */
|
|
1755
|
-
url: string;
|
|
1867
|
+
type DeployInitOptions = {
|
|
1868
|
+
/** Also generate the GitHub Actions workflow. Defaults to config.ci. */ci?: boolean; /** Drift-only mode: report differences without writing any files. Defaults to `false`. */
|
|
1869
|
+
check?: boolean;
|
|
1756
1870
|
};
|
|
1757
1871
|
/**
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1760
|
-
* @example
|
|
1761
|
-
* ```ts
|
|
1762
|
-
* { contentId: "hello", status: "published", title: "Hello", date: "2026-01-15", description: "Intro", tags: [], readingTime: 1, url: "/en/hello/" }
|
|
1763
|
-
* ```
|
|
1872
|
+
* Result of an init/scaffold operation.
|
|
1764
1873
|
*/
|
|
1765
|
-
type
|
|
1766
|
-
/**
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1874
|
+
type InitResult = {
|
|
1875
|
+
/** Paths written this invocation. */written: string[]; /** Paths skipped because they already exist. */
|
|
1876
|
+
skipped: string[]; /** In check mode: paths whose on-disk content differs from what would be generated. */
|
|
1877
|
+
drifted: string[];
|
|
1878
|
+
};
|
|
1879
|
+
/**
|
|
1880
|
+
* Public API of the deploy plugin (returned from the api factory).
|
|
1881
|
+
*/
|
|
1882
|
+
type Api$2 = {
|
|
1883
|
+
/**
|
|
1884
|
+
* Deploy the built outDir to Cloudflare Pages via the wrangler subprocess.
|
|
1885
|
+
* Runs preflight validators, re-validates the resolved outdir against cwd, guards
|
|
1886
|
+
* the branch argument, spawns wrangler (no shell), scrubs all subprocess output
|
|
1887
|
+
* before logging, records lastDeployment, and emits deploy:complete.
|
|
1888
|
+
*
|
|
1889
|
+
* @param options - Optional branch override.
|
|
1890
|
+
* @returns The deploy result (url, deploymentId, branch, durationMs).
|
|
1891
|
+
* @throws {Error} With a `code` from the deploy error taxonomy on any failure.
|
|
1892
|
+
* @example
|
|
1893
|
+
* const result = await app.deploy.run();
|
|
1894
|
+
* console.log(result.url); // https://my-site.pages.dev
|
|
1895
|
+
* @example
|
|
1896
|
+
* await app.deploy.run({ branch: "preview/landing" });
|
|
1897
|
+
*/
|
|
1898
|
+
run(options?: DeployRunOptions): Promise<DeployResult>;
|
|
1899
|
+
/**
|
|
1900
|
+
* Return the most recent successful deploy result, or null if none has occurred.
|
|
1901
|
+
* The returned object is read-only (a defensive snapshot).
|
|
1902
|
+
*
|
|
1903
|
+
* @returns The last DeployResult, or null.
|
|
1904
|
+
* @example
|
|
1905
|
+
* const last = app.deploy.getLastDeployment();
|
|
1906
|
+
* if (last) console.log(`Last deployed to ${last.url}`);
|
|
1907
|
+
*/
|
|
1908
|
+
getLastDeployment(): Readonly<DeployResult> | null;
|
|
1909
|
+
/**
|
|
1910
|
+
* Generate deploy scaffolding: wrangler.jsonc (slug from site.name() + outDir +
|
|
1911
|
+
* compatibilityDate) and, when ci is enabled, .github/workflows/deploy.yml. Never
|
|
1912
|
+
* overwrites an existing wrangler.jsonc. In check mode, reports drift instead of writing.
|
|
1913
|
+
*
|
|
1914
|
+
* @param options - Optional ci toggle and check (drift-only) mode.
|
|
1915
|
+
* @returns Which files were written, skipped, or would drift.
|
|
1916
|
+
* @example
|
|
1917
|
+
* const out = await app.deploy.init({ ci: true });
|
|
1918
|
+
* // out.written -> ["wrangler.jsonc", ".github/workflows/deploy.yml"]
|
|
1919
|
+
* @example
|
|
1920
|
+
* const drift = await app.deploy.init({ check: true });
|
|
1921
|
+
* if (drift.drifted.length) process.exit(1);
|
|
1922
|
+
*/
|
|
1923
|
+
init(options?: DeployInitOptions): Promise<InitResult>;
|
|
1924
|
+
};
|
|
1925
|
+
declare namespace types_d_exports$1 {
|
|
1926
|
+
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 };
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* A cli error `code` from the config-validation and runtime taxonomy. Mirrors the
|
|
1930
|
+
* deploy plugin's coded-error pattern so every thrown value carries a stable `code`.
|
|
1931
|
+
*
|
|
1932
|
+
* @example
|
|
1933
|
+
* const code: CliErrorCode = "ERR_CLI_CONFIG";
|
|
1934
|
+
*/
|
|
1935
|
+
type CliErrorCode = "ERR_CLI_CONFIG" | "ERR_CLI_NOT_FOUND";
|
|
1936
|
+
/**
|
|
1937
|
+
* The four commands a single cli process can run. Each maps to one consumer script
|
|
1938
|
+
* (`scripts/{build,serve,preview,deploy}.ts`) and is rendered as the Panel header.
|
|
1939
|
+
*
|
|
1940
|
+
* @example
|
|
1941
|
+
* const command: Command = "build";
|
|
1942
|
+
*/
|
|
1943
|
+
type Command = "build" | "serve" | "preview" | "deploy";
|
|
1944
|
+
/**
|
|
1945
|
+
* Information rendered into the bordered server-ready panel by `serve()`/`preview()`.
|
|
1946
|
+
*
|
|
1947
|
+
* @example
|
|
1948
|
+
* const info: ServerInfo = { local: "http://localhost:4173", network: null };
|
|
1949
|
+
*/
|
|
1950
|
+
type ServerInfo = {
|
|
1951
|
+
/** The loopback URL the server is reachable at (e.g. `http://localhost:4173`). */local: string; /** The LAN URL derived from the first non-internal IPv4, or `null` when offline. */
|
|
1952
|
+
network: string | null; /** Directories `serve()` is watching for changes (omitted by `preview()`). */
|
|
1953
|
+
watching?: string[];
|
|
1954
|
+
};
|
|
1955
|
+
/**
|
|
1956
|
+
* Information rendered after a single `serve()` rebuild: the watched directory whose
|
|
1957
|
+
* subtree changed plus the fresh build summary used to print the "rebuilt N pages"
|
|
1958
|
+
* line.
|
|
1959
|
+
*
|
|
1960
|
+
* @example
|
|
1961
|
+
* const info: ReloadInfo = { file: "content", pageCount: 12, durationMs: 84 };
|
|
1962
|
+
*/
|
|
1963
|
+
type ReloadInfo = {
|
|
1964
|
+
/** The watched directory whose subtree changed (the rebuild is per-watchDir, not per-file). */file: string; /** Number of route pages rendered by the rebuild. */
|
|
1965
|
+
pageCount: number; /** Wall-clock duration of the rebuild in milliseconds. */
|
|
1966
|
+
durationMs: number;
|
|
1967
|
+
};
|
|
1968
|
+
/**
|
|
1969
|
+
* The Panel renderer surface — every line of terminal output flows through this so
|
|
1970
|
+
* tests can inject a line-capturing fake. Implemented by `createPanelRenderer` and
|
|
1971
|
+
* is TTY/`NO_COLOR`-aware (box-drawing + color on a TTY, plain lines otherwise).
|
|
1972
|
+
*
|
|
1973
|
+
* @example
|
|
1974
|
+
* const render: CliRenderer = createPanelRenderer();
|
|
1975
|
+
* render.header("build");
|
|
1976
|
+
*/
|
|
1977
|
+
type CliRenderer = {
|
|
1978
|
+
/**
|
|
1979
|
+
* Render the boxed `MOKU WEB` logo + command label. Called once per command (one
|
|
1980
|
+
* command = one process), so it never repeats within a run.
|
|
1981
|
+
*
|
|
1982
|
+
* @param command - The command being run, shown beside the logo.
|
|
1983
|
+
* @returns Nothing.
|
|
1984
|
+
* @example
|
|
1985
|
+
* render.header("serve");
|
|
1986
|
+
*/
|
|
1987
|
+
header(command: Command): void;
|
|
1988
|
+
/**
|
|
1989
|
+
* Render a live per-phase row from a `build:phase` event.
|
|
1990
|
+
*
|
|
1991
|
+
* @param phase - The `build:phase` payload (`{ phase, status, durationMs? }`).
|
|
1992
|
+
* @returns Nothing.
|
|
1993
|
+
* @example
|
|
1994
|
+
* render.phase({ phase: "pages", status: "done", durationMs: 12 });
|
|
1995
|
+
*/
|
|
1996
|
+
phase(phase: BuildEvents["build:phase"]): void;
|
|
1997
|
+
/**
|
|
1998
|
+
* Render the BUILD summary block from a `build:complete` event.
|
|
1999
|
+
*
|
|
2000
|
+
* @param summary - The `build:complete` payload (`{ outDir, pageCount, durationMs }`).
|
|
2001
|
+
* @returns Nothing.
|
|
2002
|
+
* @example
|
|
2003
|
+
* render.built({ outDir: "dist", pageCount: 12, durationMs: 840 });
|
|
2004
|
+
*/
|
|
2005
|
+
built(summary: BuildEvents["build:complete"]): void;
|
|
2006
|
+
/**
|
|
2007
|
+
* Render the bordered server-ready panel (Local / Network URLs + watched dirs).
|
|
2008
|
+
*
|
|
2009
|
+
* @param info - Local/Network URLs and optionally the watched directories.
|
|
2010
|
+
* @returns Nothing.
|
|
2011
|
+
* @example
|
|
2012
|
+
* render.serverReady({ local: "http://localhost:4173", network: null });
|
|
2013
|
+
*/
|
|
2014
|
+
serverReady(info: ServerInfo): void;
|
|
2015
|
+
/**
|
|
2016
|
+
* Render the post-rebuild line ("~ dir" + "✓ rebuilt N pages · Xms · reloaded"),
|
|
2017
|
+
* where the label is the watched directory whose subtree changed (see {@link ReloadInfo.file}).
|
|
2018
|
+
*
|
|
2019
|
+
* @param info - The changed watched directory plus the rebuild's page count and duration.
|
|
2020
|
+
* @returns Nothing.
|
|
2021
|
+
* @example
|
|
2022
|
+
* render.reload({ file: "content", pageCount: 12, durationMs: 84 });
|
|
2023
|
+
*/
|
|
2024
|
+
reload(info: ReloadInfo): void;
|
|
2025
|
+
/**
|
|
2026
|
+
* Render the deploy result panel from a `deploy:complete` event.
|
|
2027
|
+
*
|
|
2028
|
+
* @param result - The `deploy:complete` payload (`{ url, deploymentId, branch, durationMs }`).
|
|
2029
|
+
* @returns Nothing.
|
|
2030
|
+
* @example
|
|
2031
|
+
* render.deployed({ url: "https://x.pages.dev", deploymentId: "id", branch: "main", durationMs: 1200 });
|
|
2032
|
+
*/
|
|
2033
|
+
deployed(result: DeployResult): void;
|
|
2034
|
+
/**
|
|
2035
|
+
* Render a neutral informational line (e.g. the non-interactive deploy note, watch notice).
|
|
2036
|
+
*
|
|
2037
|
+
* @param message - The line to print.
|
|
2038
|
+
* @returns Nothing.
|
|
2039
|
+
* @example
|
|
2040
|
+
* render.info("watching for changes…");
|
|
2041
|
+
*/
|
|
2042
|
+
info(message: string): void;
|
|
2043
|
+
/**
|
|
2044
|
+
* Render a warning line (written to stderr).
|
|
2045
|
+
*
|
|
2046
|
+
* @param message - The warning to print.
|
|
2047
|
+
* @returns Nothing.
|
|
2048
|
+
* @example
|
|
2049
|
+
* render.warn("deploy skipped");
|
|
2050
|
+
*/
|
|
2051
|
+
warn(message: string): void;
|
|
2052
|
+
/**
|
|
2053
|
+
* Render an error line (written to stderr), optionally with a cause.
|
|
2054
|
+
*
|
|
2055
|
+
* @param message - The error summary to print.
|
|
2056
|
+
* @param cause - Optional underlying error/value to print beneath the summary.
|
|
2057
|
+
* @returns Nothing.
|
|
2058
|
+
* @example
|
|
2059
|
+
* render.error("build failed", err);
|
|
2060
|
+
*/
|
|
2061
|
+
error(message: string, cause?: unknown): void;
|
|
2062
|
+
};
|
|
2063
|
+
/**
|
|
2064
|
+
* A live directory watcher handle returned by the injectable `watch` seam. Closing
|
|
2065
|
+
* it detaches the underlying `node:fs.watch` listener.
|
|
2066
|
+
*
|
|
2067
|
+
* @example
|
|
2068
|
+
* const handle: WatchHandle = state.watch("content", onChange);
|
|
2069
|
+
* handle.close();
|
|
2070
|
+
*/
|
|
2071
|
+
type WatchHandle = {
|
|
2072
|
+
/**
|
|
2073
|
+
* Stop watching and release the underlying listener.
|
|
2074
|
+
*
|
|
2075
|
+
* @returns Nothing.
|
|
2076
|
+
* @example
|
|
2077
|
+
* handle.close();
|
|
2078
|
+
*/
|
|
2079
|
+
close(): void;
|
|
2080
|
+
};
|
|
2081
|
+
/**
|
|
2082
|
+
* A running static server handle the cli stops on teardown. Declared structurally
|
|
2083
|
+
* (no Bun namespace types) so it survives `.d.ts` bundling and tests can supply a
|
|
2084
|
+
* fake without importing Bun.
|
|
2085
|
+
*
|
|
2086
|
+
* @example
|
|
2087
|
+
* const handle: ServerHandle = state.serveStatic({ port, fetch });
|
|
2088
|
+
* handle.stop();
|
|
2089
|
+
*/
|
|
2090
|
+
type ServerHandle = {
|
|
2091
|
+
/**
|
|
2092
|
+
* Stop the server and release its socket.
|
|
2093
|
+
*
|
|
2094
|
+
* @returns Nothing.
|
|
2095
|
+
* @example
|
|
2096
|
+
* handle.stop();
|
|
2097
|
+
*/
|
|
2098
|
+
stop(): void;
|
|
2099
|
+
};
|
|
2100
|
+
/**
|
|
2101
|
+
* The subset of `Bun.serve`'s options the cli uses: a port plus a `fetch` handler.
|
|
2102
|
+
* Declared structurally so no Bun namespace type reaches the public surface.
|
|
2103
|
+
*
|
|
2104
|
+
* @example
|
|
2105
|
+
* const opts: ServeStaticOptions = { port: 4173, fetch: () => new Response("ok") };
|
|
2106
|
+
*/
|
|
2107
|
+
type ServeStaticOptions = {
|
|
2108
|
+
/** Port to bind the server to. */port: number;
|
|
2109
|
+
/**
|
|
2110
|
+
* Per-request handler returning the response (sync or async).
|
|
2111
|
+
*
|
|
2112
|
+
* @param request - The incoming request.
|
|
2113
|
+
* @returns The response (or a promise of it).
|
|
2114
|
+
* @example
|
|
2115
|
+
* fetch(req) { return new Response("ok"); }
|
|
2116
|
+
*/
|
|
2117
|
+
fetch(request: Request): Response | Promise<Response>;
|
|
2118
|
+
};
|
|
2119
|
+
/**
|
|
2120
|
+
* An injectable static-server factory (defaults to `Bun.serve`). Keeps the Bun
|
|
2121
|
+
* runtime dependency behind a structural seam so `serve()`/`preview()` never open a
|
|
2122
|
+
* real socket in tests.
|
|
2123
|
+
*
|
|
2124
|
+
* @example
|
|
2125
|
+
* const serveStatic: ServeStaticFunction = options => Bun.serve(options);
|
|
2126
|
+
*/
|
|
2127
|
+
type ServeStaticFunction = (options: ServeStaticOptions) => ServerHandle;
|
|
2128
|
+
/**
|
|
2129
|
+
* An injectable file-response factory (defaults to `new Response(Bun.file(path))`).
|
|
2130
|
+
* Maps a resolved on-disk path + status to the response body the server returns.
|
|
2131
|
+
*
|
|
2132
|
+
* @example
|
|
2133
|
+
* const fileResponse: FileResponseFunction = (path, status) => new Response(Bun.file(path), { status });
|
|
2134
|
+
*/
|
|
2135
|
+
type FileResponseFunction = (path: string, status: number) => Response;
|
|
2136
|
+
/**
|
|
2137
|
+
* Configuration for the cli plugin — the complete resolved `Config` (not a partial).
|
|
2138
|
+
* Consumers override individual fields via `pluginConfigs.cli`.
|
|
2139
|
+
*
|
|
2140
|
+
* @example
|
|
2141
|
+
* const config: Config = {
|
|
2142
|
+
* outDir: "dist", port: 4173, watchDirs: ["content", "src"],
|
|
2143
|
+
* debounceMs: 150, notFoundFile: "404.html", liveReload: true
|
|
2144
|
+
* };
|
|
2145
|
+
*/
|
|
2146
|
+
type Config$1 = {
|
|
2147
|
+
/** Build output directory; served by preview, asserted by build, rebuilt by serve. Default `"dist"`. */outDir: string; /** Default port for serve()/preview() (overridable per-call via options.port). Default `4173`. */
|
|
2148
|
+
port: number; /** Directories serve() watches for changes (recursive). Default `["content", "src"]`. */
|
|
2149
|
+
watchDirs: string[]; /** Debounce window (ms) coalescing FS-event bursts into one rebuild. Default `150`. */
|
|
2150
|
+
debounceMs: number; /** Filename build() asserts exists at outDir root (CF Pages flips to SPA mode without it). Default `"404.html"`. */
|
|
2151
|
+
notFoundFile: string; /** Inject the live-reload SSE client into HTML during serve() (never during preview()). Default `true`. */
|
|
2152
|
+
liveReload: boolean;
|
|
2153
|
+
};
|
|
2154
|
+
/**
|
|
2155
|
+
* Runtime state for the cli plugin — injectable seams so every command is testable
|
|
2156
|
+
* without real sockets/FS-watch/TTY (mirrors deploy's injectable `spawn`).
|
|
2157
|
+
*
|
|
2158
|
+
* @example
|
|
2159
|
+
* const state: State = createState();
|
|
2160
|
+
*/
|
|
2161
|
+
type State$1 = {
|
|
2162
|
+
/** Panel renderer — all terminal output flows through this. Tests inject a line-capturing fake. */render: CliRenderer;
|
|
2163
|
+
/**
|
|
2164
|
+
* Interactive y/N prompt used by deploy(). Default reads stdin (TTY); tests inject a canned answer.
|
|
2165
|
+
*
|
|
2166
|
+
* @param question - The yes/no question to display.
|
|
2167
|
+
* @returns Resolves `true` when the user answered yes.
|
|
2168
|
+
* @example
|
|
2169
|
+
* const ok = await state.confirm("Deploy dist/?");
|
|
2170
|
+
*/
|
|
2171
|
+
confirm: (question: string) => Promise<boolean>;
|
|
2172
|
+
/**
|
|
2173
|
+
* Monotonic clock for durations. Default `Date.now`; tests inject for deterministic timing.
|
|
2174
|
+
*
|
|
2175
|
+
* @returns The current time in milliseconds.
|
|
2176
|
+
* @example
|
|
2177
|
+
* const t = state.clock();
|
|
2178
|
+
*/
|
|
2179
|
+
clock: () => number;
|
|
2180
|
+
/**
|
|
2181
|
+
* Recursive directory watcher factory used by serve(). Default wraps `node:fs.watch`;
|
|
2182
|
+
* tests inject a fake emitter.
|
|
2183
|
+
*
|
|
2184
|
+
* @param dir - The directory to watch recursively.
|
|
2185
|
+
* @param onChange - Invoked on any change beneath `dir`.
|
|
2186
|
+
* @returns A handle whose `close()` detaches the watcher.
|
|
2187
|
+
* @example
|
|
2188
|
+
* const handle = state.watch("content", () => rebuild());
|
|
2189
|
+
*/
|
|
2190
|
+
watch: (dir: string, onChange: () => void) => WatchHandle; /** Static-server factory used by serve()/preview(). Default `Bun.serve`; tests inject a fake. */
|
|
2191
|
+
serveStatic: ServeStaticFunction; /** File-response factory mapping a resolved path + status to a `Response`. Default `Bun.file`. */
|
|
2192
|
+
fileResponse: FileResponseFunction;
|
|
2193
|
+
/**
|
|
2194
|
+
* LAN network-URL deriver for the server-ready panel. Default reads `node:os`
|
|
2195
|
+
* interfaces; tests inject a deterministic value.
|
|
2196
|
+
*
|
|
2197
|
+
* @param port - The port the server is bound to.
|
|
2198
|
+
* @returns The `http://<ip>:<port>` URL, or `null` when offline.
|
|
2199
|
+
* @example
|
|
2200
|
+
* const url = state.networkUrl(4173);
|
|
2201
|
+
*/
|
|
2202
|
+
networkUrl: (port: number) => string | null;
|
|
2203
|
+
};
|
|
2204
|
+
/**
|
|
2205
|
+
* Summary returned by `cli.build()` — the awaited `build.run()` result.
|
|
2206
|
+
*
|
|
2207
|
+
* @example
|
|
2208
|
+
* const summary: BuildSummary = { outDir: "dist", pageCount: 12, durationMs: 840 };
|
|
2209
|
+
*/
|
|
2210
|
+
type BuildSummary = {
|
|
2211
|
+
/** Resolved output directory the site was written to. */outDir: string; /** Number of route pages rendered. */
|
|
2212
|
+
pageCount: number; /** Total wall-clock duration of the run, in milliseconds. */
|
|
2213
|
+
durationMs: number;
|
|
2214
|
+
};
|
|
2215
|
+
/**
|
|
2216
|
+
* Outcome returned by `cli.deploy()` — either a completed deploy (with details) or a
|
|
2217
|
+
* skipped one. A skip happens only when an interactive TTY user answers "no" at the
|
|
2218
|
+
* confirm prompt (`reason: "declined"`). Non-interactive runs (CI / non-TTY) never
|
|
2219
|
+
* prompt and always proceed, so they never skip — the scripts are CI-safe.
|
|
2220
|
+
*
|
|
2221
|
+
* @example
|
|
2222
|
+
* const outcome: DeployOutcome = { deployed: false, reason: "declined" };
|
|
2223
|
+
*/
|
|
2224
|
+
type DeployOutcome = {
|
|
2225
|
+
deployed: true;
|
|
2226
|
+
url: string;
|
|
2227
|
+
deploymentId: string;
|
|
2228
|
+
branch: string;
|
|
2229
|
+
durationMs: number;
|
|
2230
|
+
} | {
|
|
2231
|
+
deployed: false;
|
|
2232
|
+
reason: "declined";
|
|
2233
|
+
};
|
|
2234
|
+
/**
|
|
2235
|
+
* Options for `cli.build()`.
|
|
2236
|
+
*
|
|
2237
|
+
* @example
|
|
2238
|
+
* await app.cli.build({ assertNotFound: false });
|
|
2239
|
+
*/
|
|
2240
|
+
type BuildOptions = {
|
|
2241
|
+
/** Assert `outDir/notFoundFile` exists after the build. Defaults to `true`. */assertNotFound?: boolean;
|
|
2242
|
+
};
|
|
2243
|
+
/**
|
|
2244
|
+
* Options for `cli.serve()`.
|
|
2245
|
+
*
|
|
2246
|
+
* @example
|
|
2247
|
+
* await app.cli.serve({ port: 3000 });
|
|
2248
|
+
*/
|
|
2249
|
+
type ServeOptions = {
|
|
2250
|
+
/** Port to bind the dev server to. Defaults to `config.port`. */port?: number; /** Reserved for opening the browser on start (not yet implemented). Defaults to `false`. */
|
|
2251
|
+
open?: boolean;
|
|
2252
|
+
};
|
|
2253
|
+
/**
|
|
2254
|
+
* Options for `cli.preview()`.
|
|
2255
|
+
*
|
|
2256
|
+
* @example
|
|
2257
|
+
* await app.cli.preview({ port: 8080 });
|
|
2258
|
+
*/
|
|
2259
|
+
type PreviewOptions = {
|
|
2260
|
+
/** Port to bind the preview server to. Defaults to `config.port`. */port?: number;
|
|
2261
|
+
};
|
|
2262
|
+
/**
|
|
2263
|
+
* Options for `cli.deploy()`.
|
|
2264
|
+
*
|
|
2265
|
+
* @example
|
|
2266
|
+
* await app.cli.deploy({ branch: "preview/x", yes: true });
|
|
2267
|
+
*/
|
|
2268
|
+
type DeployOptions = {
|
|
2269
|
+
/** Branch to deploy. Defaults to the deploy plugin's production branch. */branch?: string; /** Skip the y/N confirm and deploy immediately. Defaults to `false`. */
|
|
2270
|
+
yes?: boolean;
|
|
2271
|
+
};
|
|
2272
|
+
/**
|
|
2273
|
+
* Public API of the cli plugin (mounted at `app.cli`) — exactly four methods.
|
|
2274
|
+
*
|
|
2275
|
+
* @example
|
|
2276
|
+
* await app.cli.build();
|
|
2277
|
+
*/
|
|
2278
|
+
type Api$1 = {
|
|
2279
|
+
/**
|
|
2280
|
+
* Run the SSG build and assert the not-found page exists.
|
|
2281
|
+
*
|
|
2282
|
+
* @param options - Optional `assertNotFound` toggle (default `true`).
|
|
2283
|
+
* @returns The build summary (`outDir`, `pageCount`, `durationMs`).
|
|
2284
|
+
* @throws {Error} `ERR_CLI_NOT_FOUND` when the not-found page is missing and asserted.
|
|
2285
|
+
* @example
|
|
2286
|
+
* const summary = await app.cli.build();
|
|
2287
|
+
*/
|
|
2288
|
+
build(options?: BuildOptions): Promise<BuildSummary>;
|
|
2289
|
+
/**
|
|
2290
|
+
* Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
|
|
2291
|
+
* `watchDirs`, debounced rebuild + reload. Resolves when SIGINT/SIGTERM tears down.
|
|
2292
|
+
*
|
|
2293
|
+
* @param options - Optional port override.
|
|
2294
|
+
* @returns Resolves once the server has been torn down.
|
|
2295
|
+
* @example
|
|
2296
|
+
* await app.cli.serve({ port: 3000 });
|
|
2297
|
+
*/
|
|
2298
|
+
serve(options?: ServeOptions): Promise<void>;
|
|
2299
|
+
/**
|
|
2300
|
+
* Static preview of the built `dist/` with CF-Pages clean-URL resolution. No
|
|
2301
|
+
* reload injection (mirrors production). Resolves on SIGINT/SIGTERM.
|
|
2302
|
+
*
|
|
2303
|
+
* @param options - Optional port override.
|
|
2304
|
+
* @returns Resolves once the server has been torn down.
|
|
2305
|
+
* @example
|
|
2306
|
+
* await app.cli.preview();
|
|
2307
|
+
*/
|
|
2308
|
+
preview(options?: PreviewOptions): Promise<void>;
|
|
2309
|
+
/**
|
|
2310
|
+
* Scaffold, then deploy. A y/N confirm is shown only on an interactive TTY;
|
|
2311
|
+
* non-interactive runs (CI, or any non-TTY) skip the prompt and deploy, so the
|
|
2312
|
+
* consumer scripts never block a pipeline. `options.yes` forces the skip anywhere.
|
|
2313
|
+
*
|
|
2314
|
+
* @param options - Optional branch override and `yes` flag.
|
|
2315
|
+
* @returns The deploy outcome (completed details, or `declined` if a TTY user says no).
|
|
2316
|
+
* @example
|
|
2317
|
+
* await app.cli.deploy({ branch: "preview/x", yes: true });
|
|
2318
|
+
*/
|
|
2319
|
+
deploy(options?: DeployOptions): Promise<DeployOutcome>;
|
|
2320
|
+
};
|
|
2321
|
+
//#endregion
|
|
2322
|
+
//#region src/plugins/cli/index.d.ts
|
|
2323
|
+
/**
|
|
2324
|
+
* cli plugin — the node-only developer CLI for `@moku-labs/web`. Mounts exactly four
|
|
2325
|
+
* methods at `app.cli` (`build`/`serve`/`preview`/`deploy`), each rendering through
|
|
2326
|
+
* the boxed Panel UI. Live build/deploy progress rides on hooks over the `build` and
|
|
2327
|
+
* `deploy` plugins' events; there is no argv parser and no `run()` dispatcher — the
|
|
2328
|
+
* consumer drives it from one thin script per command.
|
|
2329
|
+
*
|
|
2330
|
+
* @example Compose the CLI in a consumer app (node-only)
|
|
2331
|
+
* ```ts
|
|
2332
|
+
* import { buildPlugin, cliPlugin, createApp, deployPlugin } from "@moku-labs/web";
|
|
2333
|
+
*
|
|
2334
|
+
* const app = createApp({
|
|
2335
|
+
* plugins: [buildPlugin, deployPlugin, cliPlugin],
|
|
2336
|
+
* pluginConfigs: { cli: { outDir: "dist", port: 4173, watchDirs: ["content", "src"] } }
|
|
2337
|
+
* });
|
|
2338
|
+
* await app.start();
|
|
2339
|
+
* await app.cli.build();
|
|
2340
|
+
* ```
|
|
2341
|
+
*/
|
|
2342
|
+
declare const cliPlugin: import("@moku-labs/core").PluginInstance<"cli", Config$1, State$1, Api$1, {}> & Record<never, never>;
|
|
2343
|
+
declare namespace types_d_exports$2 {
|
|
2344
|
+
export { Api, Article, ArticleCard, ComputedFields, Config, ContentApiContext, ContentEvents, ContentProvider, ContentProviderState, FileSystemContentOptions, Frontmatter, State };
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* YAML frontmatter parsed from each article file.
|
|
2348
|
+
*
|
|
2349
|
+
* @example
|
|
2350
|
+
* ```ts
|
|
2351
|
+
* { title: "Hello", date: "2026-01-15", description: "Intro", tags: [], language: "en" }
|
|
2352
|
+
* ```
|
|
2353
|
+
*/
|
|
2354
|
+
type Frontmatter = {
|
|
2355
|
+
/** Article title. Required. */title: string; /** ISO 8601 date string, e.g. "2026-01-15". Required. */
|
|
2356
|
+
date: string; /** Short summary used in cards, feeds, and meta description. Required. */
|
|
2357
|
+
description: string; /** Topic tags. Required (may be empty array). */
|
|
2358
|
+
tags: string[]; /** Source language code of this file. Required. */
|
|
2359
|
+
language: string; /** Draft flag. Excluded from output in production mode. Defaults to false. */
|
|
2360
|
+
draft?: boolean; /** Author name. Falls back to the provider's defaultAuthor when omitted. */
|
|
2361
|
+
author?: string;
|
|
2362
|
+
};
|
|
2363
|
+
/**
|
|
2364
|
+
* Fields computed by the pipeline (not authored in frontmatter).
|
|
2365
|
+
*
|
|
2366
|
+
* @example
|
|
2367
|
+
* ```ts
|
|
2368
|
+
* { slug: "hello", readingTime: 1, contentId: "hello", status: "published", wordCount: 42 }
|
|
2369
|
+
* ```
|
|
2370
|
+
*/
|
|
2371
|
+
type ComputedFields = {
|
|
2372
|
+
/** Article directory name. */slug: string; /** Reading time in minutes (ceiling, minimum 1). */
|
|
2373
|
+
readingTime: number; /** Stable content identifier (slug by default). */
|
|
2374
|
+
contentId: string; /** Derived publication status. */
|
|
2375
|
+
status: "published" | "draft"; /** Word count from the source body. */
|
|
2376
|
+
wordCount: number;
|
|
2377
|
+
};
|
|
2378
|
+
/**
|
|
2379
|
+
* A fully processed, render-ready article.
|
|
2380
|
+
*
|
|
2381
|
+
* @example
|
|
2382
|
+
* ```ts
|
|
2383
|
+
* { frontmatter, computed, html: "<p>…</p>", locale: "en", isFallback: false, url: "/en/hello/" }
|
|
2384
|
+
* ```
|
|
2385
|
+
*/
|
|
2386
|
+
type Article = {
|
|
2387
|
+
/** Parsed frontmatter. */frontmatter: Frontmatter; /** Pipeline-computed metadata. */
|
|
2388
|
+
computed: ComputedFields; /** Sanitized rendered HTML body. */
|
|
2389
|
+
html: string; /** Locale this Article instance represents (the requested locale, even on fallback). */
|
|
2390
|
+
locale: string; /** True when the default-locale file was used because the requested locale was missing. */
|
|
2391
|
+
isFallback: boolean; /** Canonical URL for this article in this locale. */
|
|
2392
|
+
url: string;
|
|
2393
|
+
};
|
|
2394
|
+
/**
|
|
2395
|
+
* Lightweight projection of Article for cards/lists.
|
|
2396
|
+
*
|
|
2397
|
+
* @example
|
|
2398
|
+
* ```ts
|
|
2399
|
+
* { contentId: "hello", status: "published", title: "Hello", date: "2026-01-15", description: "Intro", tags: [], readingTime: 1, url: "/en/hello/" }
|
|
2400
|
+
* ```
|
|
2401
|
+
*/
|
|
2402
|
+
type ArticleCard = {
|
|
2403
|
+
/** Stable content identifier. */contentId: string; /** Derived publication status. */
|
|
2404
|
+
status: "published" | "draft"; /** Article title. */
|
|
2405
|
+
title: string; /** ISO 8601 date string. */
|
|
2406
|
+
date: string; /** Short summary. */
|
|
1770
2407
|
description: string; /** Topic tags. */
|
|
1771
2408
|
tags: string[]; /** Reading time in minutes. */
|
|
1772
2409
|
readingTime: number; /** Canonical URL for this article in this locale. */
|
|
1773
2410
|
url: string;
|
|
1774
2411
|
};
|
|
2412
|
+
/**
|
|
2413
|
+
* A pluggable content SOURCE. The shell calls these to read articles; whether content
|
|
2414
|
+
* is read from the filesystem (Node) or some other source is chosen by which provider
|
|
2415
|
+
* you compose — exactly like `env` providers (`dotenv`/`processEnv` vs `browserEnv`).
|
|
2416
|
+
* The shell adds locale fallback, draft filtering, sorting, caching, and events on top.
|
|
2417
|
+
*
|
|
2418
|
+
* @example
|
|
2419
|
+
* ```ts
|
|
2420
|
+
* const provider = fileSystemContent({ contentDir: "./content" });
|
|
2421
|
+
* ```
|
|
2422
|
+
*/
|
|
2423
|
+
interface ContentProvider {
|
|
2424
|
+
/** Human-readable provider name, used in diagnostics. */
|
|
2425
|
+
readonly name: string;
|
|
2426
|
+
/** Source directory surfaced via `api.contentDir()` (filesystem providers; "" otherwise). */
|
|
2427
|
+
readonly contentDir: string;
|
|
2428
|
+
/**
|
|
2429
|
+
* Discover the article slugs this provider can supply.
|
|
2430
|
+
*
|
|
2431
|
+
* @returns The provider's slug list.
|
|
2432
|
+
*/
|
|
2433
|
+
slugs(): Promise<readonly string[]>;
|
|
2434
|
+
/**
|
|
2435
|
+
* Read + render ONE article for a file-locale; `null` if this provider has no such file.
|
|
2436
|
+
*
|
|
2437
|
+
* @param slug - Article directory name.
|
|
2438
|
+
* @param fileLocale - Locale whose source file is read.
|
|
2439
|
+
* @param outLocale - Locale the resulting Article represents (the requested locale).
|
|
2440
|
+
* @param isFallback - Whether this resolution used the default-locale fallback.
|
|
2441
|
+
* @returns The constructed Article, or `null` when absent.
|
|
2442
|
+
*/
|
|
2443
|
+
readArticle(slug: string, fileLocale: string, outLocale: string, isFallback: boolean): Promise<Article | null>;
|
|
2444
|
+
/**
|
|
2445
|
+
* Render a standalone Markdown string to HTML through the provider's pipeline.
|
|
2446
|
+
*
|
|
2447
|
+
* @param markdown - Raw Markdown source.
|
|
2448
|
+
* @returns The rendered HTML.
|
|
2449
|
+
*/
|
|
2450
|
+
render(markdown: string): Promise<string>;
|
|
2451
|
+
/**
|
|
2452
|
+
* Optional dev hook: drop cached discovery so stale paths are re-read next time.
|
|
2453
|
+
*
|
|
2454
|
+
* @param paths - Stale file paths.
|
|
2455
|
+
*/
|
|
2456
|
+
invalidate?(paths: readonly string[]): void;
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Options for the node filesystem provider {@link ContentProvider} `fileSystemContent`.
|
|
2460
|
+
* These are the markdown-pipeline + source concerns that used to live on the content
|
|
2461
|
+
* plugin config; they now belong to the provider you compose.
|
|
2462
|
+
*
|
|
2463
|
+
* @example
|
|
2464
|
+
* ```ts
|
|
2465
|
+
* fileSystemContent({ contentDir: "./content", shikiTheme: "github-dark", defaultAuthor: "Ada" });
|
|
2466
|
+
* ```
|
|
2467
|
+
*/
|
|
2468
|
+
type FileSystemContentOptions = {
|
|
2469
|
+
/** Absolute or project-relative path to the content directory. */contentDir: string;
|
|
2470
|
+
/**
|
|
2471
|
+
* SECURITY GATE. When false (the default), rehype-sanitize runs as the final
|
|
2472
|
+
* pipeline step. Set true ONLY for fully author-controlled Markdown.
|
|
2473
|
+
*/
|
|
2474
|
+
trustedContent?: boolean; /** Additional remark plugins, concatenated AFTER framework defaults. Defaults to []. */
|
|
2475
|
+
extraRemarkPlugins?: readonly Pluggable[]; /** Additional rehype plugins, concatenated after custom transforms, before Shiki + sanitize. Defaults to []. */
|
|
2476
|
+
extraRehypePlugins?: readonly Pluggable[];
|
|
2477
|
+
/**
|
|
2478
|
+
* Shiki theme for syntax highlighting: a bundled theme NAME (default "github-dark")
|
|
2479
|
+
* or a custom `ThemeRegistration` object. Passed straight through to `@shikijs/rehype`.
|
|
2480
|
+
*/
|
|
2481
|
+
shikiTheme?: BundledTheme | ThemeRegistrationAny; /** Author applied to articles whose frontmatter omits author. Defaults to undefined. */
|
|
2482
|
+
defaultAuthor?: string;
|
|
2483
|
+
};
|
|
2484
|
+
/**
|
|
2485
|
+
* Internal mutable state of the filesystem provider: the lazy unified processor and
|
|
2486
|
+
* the discovery caches. Owned by the provider closure, never by the plugin shell.
|
|
2487
|
+
*
|
|
2488
|
+
* @example
|
|
2489
|
+
* ```ts
|
|
2490
|
+
* { processor: null, slugs: null, dirtyPaths: new Set() }
|
|
2491
|
+
* ```
|
|
2492
|
+
*/
|
|
2493
|
+
type ContentProviderState = {
|
|
2494
|
+
/** Lazily-created unified processor singleton. null until first render()/readArticle(). */processor: Processor | null; /** Discovered, sorted slug list cached after first disk scan. null until first discovery. */
|
|
2495
|
+
slugs: string[] | null; /** Paths marked stale by invalidate(); next discovery re-reads only these. Starts empty. */
|
|
2496
|
+
dirtyPaths: Set<string>;
|
|
2497
|
+
};
|
|
2498
|
+
/**
|
|
2499
|
+
* Configuration for the content plugin (shell).
|
|
2500
|
+
*
|
|
2501
|
+
* @example
|
|
2502
|
+
* ```ts
|
|
2503
|
+
* { providers: [fileSystemContent({ contentDir: "./content" })] }
|
|
2504
|
+
* ```
|
|
2505
|
+
*/
|
|
2506
|
+
type Config = {
|
|
2507
|
+
/**
|
|
2508
|
+
* Ordered content sources. Compose at least one (e.g. `fileSystemContent(...)` on
|
|
2509
|
+
* Node). The first provider that supplies an article for a slug+locale wins;
|
|
2510
|
+
* `slugs()` are unioned. The plugin's own spec default is `[]` (a build must supply one).
|
|
2511
|
+
*/
|
|
2512
|
+
providers: ContentProvider[];
|
|
2513
|
+
};
|
|
2514
|
+
/**
|
|
2515
|
+
* Internal mutable state for the content plugin shell: the locale-keyed article cache.
|
|
2516
|
+
*
|
|
2517
|
+
* @example
|
|
2518
|
+
* ```ts
|
|
2519
|
+
* { articles: new Map() }
|
|
2520
|
+
* ```
|
|
2521
|
+
*/
|
|
2522
|
+
type State = {
|
|
2523
|
+
/** Article cache keyed locale -> (slug -> Article). Starts empty. */articles: Map<string, Map<string, Article>>;
|
|
2524
|
+
};
|
|
1775
2525
|
/**
|
|
1776
2526
|
* Notification-only events emitted by the content plugin.
|
|
1777
2527
|
*
|
|
@@ -1791,24 +2541,24 @@ type ContentEvents = {
|
|
|
1791
2541
|
};
|
|
1792
2542
|
/**
|
|
1793
2543
|
* Kernel-free domain context handed to createContentApi by the wiring harness.
|
|
1794
|
-
* Carries
|
|
1795
|
-
*
|
|
2544
|
+
* Carries the shell state (article cache), global flag, emit, the i18n-derived
|
|
2545
|
+
* locale helpers, and the resolved content {@link ContentProvider} — so api.ts stays
|
|
2546
|
+
* free of createPlugin/ctx AND of any node/pipeline import.
|
|
1796
2547
|
*
|
|
1797
2548
|
* @example
|
|
1798
2549
|
* ```ts
|
|
1799
|
-
* const apiContext: ContentApiContext = { state,
|
|
2550
|
+
* const apiContext: ContentApiContext = { state, global, emit, locales, defaultLocale, provider };
|
|
1800
2551
|
* ```
|
|
1801
2552
|
*/
|
|
1802
2553
|
type ContentApiContext = {
|
|
1803
|
-
/** Mutable
|
|
1804
|
-
config: Config$1; /** Global framework configuration (mode, etc.). */
|
|
2554
|
+
/** Mutable shell state (article cache). */state: State; /** Global framework configuration (deployment stage). */
|
|
1805
2555
|
global: {
|
|
1806
|
-
|
|
2556
|
+
stage: Stage;
|
|
1807
2557
|
}; /** Emit a registered content event. */
|
|
1808
2558
|
emit: <K extends keyof ContentEvents>(event: K, payload: ContentEvents[K]) => void; /** Active locale codes from i18n. */
|
|
1809
2559
|
locales: () => readonly string[]; /** Default locale code from i18n (fallback source). */
|
|
1810
|
-
defaultLocale: () => string; /**
|
|
1811
|
-
|
|
2560
|
+
defaultLocale: () => string; /** The resolved content source (merged from `config.providers`). */
|
|
2561
|
+
provider: ContentProvider;
|
|
1812
2562
|
};
|
|
1813
2563
|
/**
|
|
1814
2564
|
* Public API for the content plugin.
|
|
@@ -1818,7 +2568,7 @@ type ContentApiContext = {
|
|
|
1818
2568
|
* const map = await app.content.loadAll();
|
|
1819
2569
|
* ```
|
|
1820
2570
|
*/
|
|
1821
|
-
type Api
|
|
2571
|
+
type Api = {
|
|
1822
2572
|
/**
|
|
1823
2573
|
* Load every article across every active locale, returning a locale-keyed
|
|
1824
2574
|
* map of date-descending Article arrays. Emits content:ready.
|
|
@@ -1850,35 +2600,35 @@ type Api$1 = {
|
|
|
1850
2600
|
*/
|
|
1851
2601
|
articleToCard(article: Article): ArticleCard;
|
|
1852
2602
|
/**
|
|
1853
|
-
* The configured content source directory (e.g. `"./content"`)
|
|
1854
|
-
* article's co-located assets
|
|
1855
|
-
*
|
|
2603
|
+
* The configured content source directory (e.g. `"./content"`), from the first
|
|
2604
|
+
* provider. Lets the build copy each article's co-located assets
|
|
2605
|
+
* (`<contentDir>/<slug>/images/`) into the output.
|
|
1856
2606
|
*/
|
|
1857
2607
|
contentDir(): string;
|
|
1858
2608
|
};
|
|
1859
2609
|
//#endregion
|
|
1860
2610
|
//#region src/plugins/content/index.d.ts
|
|
1861
2611
|
/**
|
|
1862
|
-
* Content plugin —
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1865
|
-
* `
|
|
2612
|
+
* Content plugin (shell) — provider-driven locale-keyed Article model. Orchestration
|
|
2613
|
+
* (locale fallback, draft filtering, sort, caching, events) lives here; source I/O +
|
|
2614
|
+
* the Markdown pipeline live in a {@link ContentProvider} you compose (like `env`
|
|
2615
|
+
* providers). The shell imports zero node code, so `contentPlugin` is browser-safe.
|
|
2616
|
+
* Depends on i18n; emits `content:ready` and `content:invalidated`.
|
|
1866
2617
|
*
|
|
1867
|
-
* @example
|
|
2618
|
+
* @example Compose the node filesystem provider with a content dir + Shiki theme
|
|
1868
2619
|
* ```ts
|
|
2620
|
+
* import { contentPlugin, fileSystemContent } from "@moku-labs/web";
|
|
1869
2621
|
* const app = createApp({
|
|
2622
|
+
* plugins: [contentPlugin],
|
|
1870
2623
|
* pluginConfigs: {
|
|
1871
2624
|
* content: {
|
|
1872
|
-
* contentDir: "./content",
|
|
1873
|
-
* shikiTheme: "github-dark",
|
|
1874
|
-
* defaultAuthor: "Ada Lovelace"
|
|
1875
|
-
* // trustedContent: true // ONLY for fully author-controlled Markdown — disables sanitize
|
|
2625
|
+
* providers: [fileSystemContent({ contentDir: "./content", shikiTheme: "github-dark", defaultAuthor: "Ada" })]
|
|
1876
2626
|
* }
|
|
1877
2627
|
* }
|
|
1878
2628
|
* });
|
|
1879
2629
|
* ```
|
|
1880
2630
|
*/
|
|
1881
|
-
declare const contentPlugin: import("@moku-labs/core").PluginInstance<"content", Config
|
|
2631
|
+
declare const contentPlugin: import("@moku-labs/core").PluginInstance<"content", Config, State, Api, {
|
|
1882
2632
|
"content:ready": {
|
|
1883
2633
|
locales: readonly string[];
|
|
1884
2634
|
articleCount: number;
|
|
@@ -1887,7 +2637,7 @@ declare const contentPlugin: import("@moku-labs/core").PluginInstance<"content",
|
|
|
1887
2637
|
paths: readonly string[];
|
|
1888
2638
|
};
|
|
1889
2639
|
}> & Record<never, never>;
|
|
1890
|
-
declare namespace types_d_exports$
|
|
2640
|
+
declare namespace types_d_exports$3 {
|
|
1891
2641
|
export { DataConfig, DataEntry, DataProvider, DataState, DataWriteSummary };
|
|
1892
2642
|
}
|
|
1893
2643
|
/**
|
|
@@ -1896,13 +2646,13 @@ declare namespace types_d_exports$2 {
|
|
|
1896
2646
|
* The `data` plugin is the **agnostic data provider** for the SSG→DATA→SPA pattern.
|
|
1897
2647
|
* It owns ONE thing: the contract `page path → persisted JSON file`. It knows
|
|
1898
2648
|
* NOTHING about what the data *is* — no domain types appear here. A route decides
|
|
1899
|
-
* its own data shape (`load`'s return)
|
|
2649
|
+
* its own data shape (`load`'s return).
|
|
1900
2650
|
*
|
|
1901
2651
|
* - **Node (build):** `write(entries)` persists one JSON file per page, keyed by
|
|
1902
2652
|
* the page's URL via {@link DataProvider.fileFor}. `build` supplies the entries
|
|
1903
2653
|
* (it already expanded the routes), so there is no duplicate expansion here.
|
|
1904
|
-
* - **Browser (runtime):** `at(path)` fetches + caches that file as `unknown
|
|
1905
|
-
* route
|
|
2654
|
+
* - **Browser (runtime):** `at(path)` fetches + caches that file as `unknown`, which
|
|
2655
|
+
* the route uses directly as `ctx.data` in `render`.
|
|
1906
2656
|
*
|
|
1907
2657
|
* The Node-only file-writing code (`node:fs`) is isolated behind a lazy `import()`
|
|
1908
2658
|
* inside `write()`, so composing `data` in a browser app keeps the bundle free of
|
|
@@ -1924,8 +2674,8 @@ type DataConfig = {
|
|
|
1924
2674
|
outputDir: string;
|
|
1925
2675
|
/**
|
|
1926
2676
|
* READ side (browser): site-root-relative URL the client fetches the per-page
|
|
1927
|
-
* JSON from.
|
|
1928
|
-
* path); keep consistent (`"/" + trim(outputDir) + "/"`). Default `"/_data/"`.
|
|
2677
|
+
* JSON from. The URL-space mirror of {@link DataConfig.outputDir} (a filesystem
|
|
2678
|
+
* path); keep them consistent (`"/" + trim(outputDir) + "/"`). Default `"/_data/"`.
|
|
1929
2679
|
*/
|
|
1930
2680
|
baseUrl: string;
|
|
1931
2681
|
};
|
|
@@ -1967,15 +2717,15 @@ interface DataState {
|
|
|
1967
2717
|
* // Node build (build supplies the entries it already expanded):
|
|
1968
2718
|
* await app.data.write([{ path: "/en/hello/", data: article }]);
|
|
1969
2719
|
*
|
|
1970
|
-
* // Browser (inside spa nav): fetch the page's data,
|
|
1971
|
-
* const raw = await app.data.at("/en/hello/"); // unknown | null
|
|
2720
|
+
* // Browser (inside spa nav): fetch the page's data, used directly as ctx.data:
|
|
2721
|
+
* const raw = await app.data.at("/en/hello/"); // unknown | null (null on failure)
|
|
1972
2722
|
* ```
|
|
1973
2723
|
*/
|
|
1974
2724
|
type DataProvider = {
|
|
1975
2725
|
/**
|
|
1976
2726
|
* READ (browser) — fetch (and cache) the persisted data for a page path from
|
|
1977
|
-
* `config.baseUrl`. Returns the raw parsed JSON as `unknown
|
|
1978
|
-
* `
|
|
2727
|
+
* `config.baseUrl`. Returns the raw parsed JSON as `unknown`, used directly as
|
|
2728
|
+
* the route's `ctx.data`; returns `null` if the fetch or JSON parse fails.
|
|
1979
2729
|
*
|
|
1980
2730
|
* @param path - The page URL path (e.g. `/en/hello/`).
|
|
1981
2731
|
* @returns The page's raw data, or `null` on failure.
|
|
@@ -2021,197 +2771,19 @@ type DataProvider = {
|
|
|
2021
2771
|
* @example
|
|
2022
2772
|
* ```ts
|
|
2023
2773
|
* // Node build: `build` calls app.data.write(...) during its pages phase when
|
|
2024
|
-
* // router.mode !== "ssg".
|
|
2774
|
+
* // router.mode() !== "ssg". Compose the plugin + set the global render mode:
|
|
2775
|
+
* import * as routes from "./routes";
|
|
2025
2776
|
* const app = createApp({
|
|
2026
2777
|
* plugins: [dataPlugin, contentPlugin, buildPlugin],
|
|
2027
|
-
*
|
|
2778
|
+
* config: { mode: "hybrid" },
|
|
2779
|
+
* pluginConfigs: { content: { providers: [fileSystemContent({ contentDir: "./content" })] }, router: { routes } }
|
|
2028
2780
|
* });
|
|
2029
|
-
* await app.
|
|
2030
|
-
* await app.build.run(); // writes HTML + per-page data sidecars
|
|
2781
|
+
* await app.build.run(); // writes HTML + per-page data sidecars (routes compiled at init)
|
|
2031
2782
|
*
|
|
2032
2783
|
* // Browser app: compose `dataPlugin` too; spa fetches via app.data.at(path) on nav.
|
|
2033
2784
|
* ```
|
|
2034
2785
|
*/
|
|
2035
2786
|
declare const dataPlugin: import("@moku-labs/core").PluginInstance<"data", DataConfig, DataState, DataProvider, {}> & Record<never, never>;
|
|
2036
|
-
declare namespace types_d_exports$3 {
|
|
2037
|
-
export { Api, Config, DeployErrorCode, DeployInitOptions, DeployResult, DeployRunOptions, InitResult, SpawnFunction, SpawnOptions, SpawnedProcess, State, WranglerErrorKind };
|
|
2038
|
-
}
|
|
2039
|
-
/**
|
|
2040
|
-
* @file deploy plugin — type definitions.
|
|
2041
|
-
*/
|
|
2042
|
-
/**
|
|
2043
|
-
* Options passed to the injected spawner — the subset of Bun.spawn's options the
|
|
2044
|
-
* plugin uses (piped stdout/stderr plus an env carrying the API token).
|
|
2045
|
-
*/
|
|
2046
|
-
interface SpawnOptions {
|
|
2047
|
-
/** Capture stdout as a readable stream. */
|
|
2048
|
-
readonly stdout: "pipe";
|
|
2049
|
-
/** Capture stderr as a readable stream. */
|
|
2050
|
-
readonly stderr: "pipe";
|
|
2051
|
-
/** Subprocess environment — the API token is injected here, never via argv. */
|
|
2052
|
-
readonly env?: Record<string, string | undefined>;
|
|
2053
|
-
}
|
|
2054
|
-
/**
|
|
2055
|
-
* The structural subprocess handle the plugin reads back: stdout/stderr streams
|
|
2056
|
-
* plus the exit-code promise. Streams are typed `unknown` and narrowed at the read
|
|
2057
|
-
* site so this carries no Bun namespace types.
|
|
2058
|
-
*/
|
|
2059
|
-
interface SpawnedProcess {
|
|
2060
|
-
/** Standard output stream (narrowed to a ReadableStream at the read site). */
|
|
2061
|
-
readonly stdout: unknown;
|
|
2062
|
-
/** Standard error stream (narrowed to a ReadableStream at the read site). */
|
|
2063
|
-
readonly stderr: unknown;
|
|
2064
|
-
/** Resolves with the subprocess exit code. */
|
|
2065
|
-
readonly exited: Promise<number>;
|
|
2066
|
-
}
|
|
2067
|
-
/**
|
|
2068
|
-
* The subset of Bun.spawn's signature the plugin relies on (argv array + options).
|
|
2069
|
-
* Declared structurally — with NO `import("bun")` namespace types — so it survives
|
|
2070
|
-
* `.d.ts` bundling intact and tests can supply a fake spawn without importing Bun.
|
|
2071
|
-
*/
|
|
2072
|
-
type SpawnFunction = (cmd: string[], options: SpawnOptions) => SpawnedProcess;
|
|
2073
|
-
/**
|
|
2074
|
-
* A deploy error `code` from the wrangler error taxonomy and preflight validators.
|
|
2075
|
-
*/
|
|
2076
|
-
type DeployErrorCode = "ERR_DEPLOY_NO_WRANGLER_CONFIG" | "ERR_DEPLOY_EMPTY_OUTDIR" | "ERR_DEPLOY_TOO_MANY_FILES" | "ERR_DEPLOY_FILE_TOO_LARGE" | "ERR_DEPLOY_PATH_TRAVERSAL" | "ERR_DEPLOY_INVALID_BRANCH" | "ERR_DEPLOY_NO_TOKEN" | "ERR_DEPLOY_PROJECT_NOT_FOUND" | "ERR_DEPLOY_AUTH_EXPIRED" | "ERR_DEPLOY_AUTH" | "ERR_DEPLOY_NETWORK" | "ERR_DEPLOY_WRANGLER_FAILED" | "ERR_DEPLOY_CONFIG";
|
|
2077
|
-
/**
|
|
2078
|
-
* The subset of wrangler error `code`s classifyWranglerError can produce from a
|
|
2079
|
-
* non-zero wrangler exit.
|
|
2080
|
-
*/
|
|
2081
|
-
type WranglerErrorKind = Extract<DeployErrorCode, "ERR_DEPLOY_PROJECT_NOT_FOUND" | "ERR_DEPLOY_AUTH_EXPIRED" | "ERR_DEPLOY_AUTH" | "ERR_DEPLOY_NETWORK" | "ERR_DEPLOY_WRANGLER_FAILED">;
|
|
2082
|
-
/**
|
|
2083
|
-
* Configuration for the deploy plugin.
|
|
2084
|
-
*/
|
|
2085
|
-
type Config = {
|
|
2086
|
-
/**
|
|
2087
|
-
* Deploy target. Only Cloudflare Pages is supported in this version.
|
|
2088
|
-
* Defaults to `cloudflare-pages`.
|
|
2089
|
-
*/
|
|
2090
|
-
target: "cloudflare-pages";
|
|
2091
|
-
/**
|
|
2092
|
-
* Directory (relative to project root) containing the built site to deploy.
|
|
2093
|
-
* Re-validated against cwd at run() time to block path traversal.
|
|
2094
|
-
* Defaults to `dist`.
|
|
2095
|
-
*/
|
|
2096
|
-
outDir: string;
|
|
2097
|
-
/**
|
|
2098
|
-
* Branch treated as the Cloudflare Pages production branch.
|
|
2099
|
-
* Defaults to `main`.
|
|
2100
|
-
*/
|
|
2101
|
-
productionBranch?: string;
|
|
2102
|
-
/**
|
|
2103
|
-
* Substrings exempt from entropy-gated secret scrubbing in logged output.
|
|
2104
|
-
* Defaults to `["CLOUDFLARE_ACCOUNT_ID"]`.
|
|
2105
|
-
*/
|
|
2106
|
-
scrubAllowlist: string[];
|
|
2107
|
-
/**
|
|
2108
|
-
* Cloudflare compatibility date written into generated wrangler.jsonc.
|
|
2109
|
-
* Defaults to `2024-01-01`.
|
|
2110
|
-
*/
|
|
2111
|
-
compatibilityDate?: string;
|
|
2112
|
-
/**
|
|
2113
|
-
* Whether init() also generates a GitHub Actions workflow.
|
|
2114
|
-
* Defaults to `false`.
|
|
2115
|
-
*/
|
|
2116
|
-
ci?: boolean;
|
|
2117
|
-
};
|
|
2118
|
-
/**
|
|
2119
|
-
* Result of a successful deploy.
|
|
2120
|
-
*/
|
|
2121
|
-
type DeployResult = {
|
|
2122
|
-
/** The public deployment URL (e.g. https://my-site.pages.dev). */url: string; /** Cloudflare deployment ID parsed from wrangler output. */
|
|
2123
|
-
deploymentId: string; /** The branch that was deployed. */
|
|
2124
|
-
branch: string; /** Wall-clock duration of the deploy in milliseconds. */
|
|
2125
|
-
durationMs: number;
|
|
2126
|
-
};
|
|
2127
|
-
/**
|
|
2128
|
-
* Runtime state for the deploy plugin. Created in createState() and accessed via
|
|
2129
|
-
* ctx.state. deploy declares no onStop because nothing here is a long-lived resource.
|
|
2130
|
-
*/
|
|
2131
|
-
type State = {
|
|
2132
|
-
/** Result of the most recent successful deploy, or null before the first run. */lastDeployment: DeployResult | null;
|
|
2133
|
-
/**
|
|
2134
|
-
* Injectable subprocess spawner. Defaults to Bun.spawn. Swapped for a mock in
|
|
2135
|
-
* unit tests so wrangler is never actually invoked. Never reassigned at runtime.
|
|
2136
|
-
*/
|
|
2137
|
-
spawn: SpawnFunction;
|
|
2138
|
-
};
|
|
2139
|
-
/**
|
|
2140
|
-
* Options for DeployApi.run.
|
|
2141
|
-
*/
|
|
2142
|
-
type DeployRunOptions = {
|
|
2143
|
-
/**
|
|
2144
|
-
* Branch to deploy. Defaults to config.productionBranch (or "main"). Must match
|
|
2145
|
-
* /^[a-zA-Z0-9/_.-]+$/ — otherwise rejected with ERR_DEPLOY_INVALID_BRANCH.
|
|
2146
|
-
*/
|
|
2147
|
-
branch?: string;
|
|
2148
|
-
/**
|
|
2149
|
-
* Whether to run the build before deploying. When false, deploys the existing outDir.
|
|
2150
|
-
* Defaults to `true`.
|
|
2151
|
-
*/
|
|
2152
|
-
build?: boolean;
|
|
2153
|
-
};
|
|
2154
|
-
/**
|
|
2155
|
-
* Options for DeployApi.init.
|
|
2156
|
-
*/
|
|
2157
|
-
type DeployInitOptions = {
|
|
2158
|
-
/** Also generate the GitHub Actions workflow. Defaults to config.ci. */ci?: boolean; /** Drift-only mode: report differences without writing any files. Defaults to `false`. */
|
|
2159
|
-
check?: boolean;
|
|
2160
|
-
};
|
|
2161
|
-
/**
|
|
2162
|
-
* Result of an init/scaffold operation.
|
|
2163
|
-
*/
|
|
2164
|
-
type InitResult = {
|
|
2165
|
-
/** Paths written this invocation. */written: string[]; /** Paths skipped because they already exist. */
|
|
2166
|
-
skipped: string[]; /** In check mode: paths whose on-disk content differs from what would be generated. */
|
|
2167
|
-
drifted: string[];
|
|
2168
|
-
};
|
|
2169
|
-
/**
|
|
2170
|
-
* Public API of the deploy plugin (returned from the api factory).
|
|
2171
|
-
*/
|
|
2172
|
-
type Api = {
|
|
2173
|
-
/**
|
|
2174
|
-
* Deploy the built outDir to Cloudflare Pages via the wrangler subprocess.
|
|
2175
|
-
* Runs preflight validators, re-validates the resolved outdir against cwd, guards
|
|
2176
|
-
* the branch argument, spawns wrangler (no shell), scrubs all subprocess output
|
|
2177
|
-
* before logging, records lastDeployment, and emits deploy:complete.
|
|
2178
|
-
*
|
|
2179
|
-
* @param options - Optional branch override and build toggle.
|
|
2180
|
-
* @returns The deploy result (url, deploymentId, branch, durationMs).
|
|
2181
|
-
* @throws {Error} With a `code` from the deploy error taxonomy on any failure.
|
|
2182
|
-
* @example
|
|
2183
|
-
* const result = await app.deploy.run();
|
|
2184
|
-
* console.log(result.url); // https://my-site.pages.dev
|
|
2185
|
-
* @example
|
|
2186
|
-
* await app.deploy.run({ branch: "preview/landing", build: false });
|
|
2187
|
-
*/
|
|
2188
|
-
run(options?: DeployRunOptions): Promise<DeployResult>;
|
|
2189
|
-
/**
|
|
2190
|
-
* Return the most recent successful deploy result, or null if none has occurred.
|
|
2191
|
-
* The returned object is read-only (a defensive snapshot).
|
|
2192
|
-
*
|
|
2193
|
-
* @returns The last DeployResult, or null.
|
|
2194
|
-
* @example
|
|
2195
|
-
* const last = app.deploy.getLastDeployment();
|
|
2196
|
-
* if (last) console.log(`Last deployed to ${last.url}`);
|
|
2197
|
-
*/
|
|
2198
|
-
getLastDeployment(): Readonly<DeployResult> | null;
|
|
2199
|
-
/**
|
|
2200
|
-
* Generate deploy scaffolding: wrangler.jsonc (slug from site.name() + outDir +
|
|
2201
|
-
* compatibilityDate) and, when ci is enabled, .github/workflows/deploy.yml. Never
|
|
2202
|
-
* overwrites an existing wrangler.jsonc. In check mode, reports drift instead of writing.
|
|
2203
|
-
*
|
|
2204
|
-
* @param options - Optional ci toggle and check (drift-only) mode.
|
|
2205
|
-
* @returns Which files were written, skipped, or would drift.
|
|
2206
|
-
* @example
|
|
2207
|
-
* const out = await app.deploy.init({ ci: true });
|
|
2208
|
-
* // out.written -> ["wrangler.jsonc", ".github/workflows/deploy.yml"]
|
|
2209
|
-
* @example
|
|
2210
|
-
* const drift = await app.deploy.init({ check: true });
|
|
2211
|
-
* if (drift.drifted.length) process.exit(1);
|
|
2212
|
-
*/
|
|
2213
|
-
init(options?: DeployInitOptions): Promise<InitResult>;
|
|
2214
|
-
};
|
|
2215
2787
|
//#endregion
|
|
2216
2788
|
//#region src/plugins/deploy/index.d.ts
|
|
2217
2789
|
/**
|
|
@@ -2239,7 +2811,7 @@ type Api = {
|
|
|
2239
2811
|
* });
|
|
2240
2812
|
* ```
|
|
2241
2813
|
*/
|
|
2242
|
-
declare const deployPlugin: import("@moku-labs/core").PluginInstance<"deploy", Config, State, Api, {
|
|
2814
|
+
declare const deployPlugin: import("@moku-labs/core").PluginInstance<"deploy", Config$2, State$2, Api$2, {
|
|
2243
2815
|
"deploy:complete": {
|
|
2244
2816
|
url: string;
|
|
2245
2817
|
deploymentId: string;
|
|
@@ -2320,6 +2892,8 @@ declare function feedLink(title: string, url: string, type?: string): HeadElemen
|
|
|
2320
2892
|
* modified times, author, section, tags, plus a JSON-LD `Article` block and canonical.
|
|
2321
2893
|
*
|
|
2322
2894
|
* @param articleMeta - Article metadata (title, description, author, dates, tags, image…).
|
|
2895
|
+
* `image`, when present, is pushed to `og:image` verbatim and must therefore be
|
|
2896
|
+
* an absolute URL (this helper does not resolve relative paths against the site).
|
|
2323
2897
|
* @param canonicalUrl - The article's canonical absolute URL.
|
|
2324
2898
|
* @returns An ordered array of serializable head elements.
|
|
2325
2899
|
* @example buildArticleHead({ title: "Hi", author: "A", published: "2026-01-01" }, "https://x/p")
|
|
@@ -2346,7 +2920,7 @@ declare function buildArticleHead(articleMeta: ArticleMeta, canonicalUrl: string
|
|
|
2346
2920
|
* });
|
|
2347
2921
|
* ```
|
|
2348
2922
|
*/
|
|
2349
|
-
declare const headPlugin: import("@moku-labs/core").PluginInstance<"head", Config$
|
|
2923
|
+
declare const headPlugin: import("@moku-labs/core").PluginInstance<"head", Config$4, State$4, Api$4, {}> & {
|
|
2350
2924
|
meta: typeof meta;
|
|
2351
2925
|
og: typeof og;
|
|
2352
2926
|
twitter: typeof twitter;
|
|
@@ -2377,7 +2951,7 @@ declare const headPlugin: import("@moku-labs/core").PluginInstance<"head", Confi
|
|
|
2377
2951
|
* });
|
|
2378
2952
|
* ```
|
|
2379
2953
|
*/
|
|
2380
|
-
declare const i18nPlugin: import("@moku-labs/core").PluginInstance<"i18n", Config$
|
|
2954
|
+
declare const i18nPlugin: import("@moku-labs/core").PluginInstance<"i18n", Config$6, Record<string, never>, Api$6, {}> & Record<never, never>;
|
|
2381
2955
|
//#endregion
|
|
2382
2956
|
//#region src/plugins/log/index.d.ts
|
|
2383
2957
|
/**
|
|
@@ -2402,7 +2976,7 @@ declare const logPlugin: import("@moku-labs/core").CorePluginInstance<"log", Log
|
|
|
2402
2976
|
* @example
|
|
2403
2977
|
* ```ts
|
|
2404
2978
|
* route("/{lang:?}/{slug}/")
|
|
2405
|
-
* .load((
|
|
2979
|
+
* .load((ctx) => loadArticle(ctx.params.slug))
|
|
2406
2980
|
* .render((ctx) => <Article a={ctx.data} />)
|
|
2407
2981
|
* .head((ctx) => ({ title: ctx.data.title }));
|
|
2408
2982
|
* ```
|
|
@@ -2420,31 +2994,46 @@ declare function route<P extends string>(pattern: P): RouteBuilder<RouteState<P>
|
|
|
2420
2994
|
* ```
|
|
2421
2995
|
*/
|
|
2422
2996
|
declare function defineRoutes<T extends RouteMap>(routes: T): T;
|
|
2997
|
+
/**
|
|
2998
|
+
* Build a pure, app-free URL builder from a route map. `toUrl(name, params)` resolves
|
|
2999
|
+
* a route's path by pattern substitution using the SAME `buildUrl` as the runtime
|
|
3000
|
+
* `RouterApi.toUrl`, so the helper and the API can never diverge. It needs no running
|
|
3001
|
+
* app, router instance, base URL, or i18n — just the route map the consumer already
|
|
3002
|
+
* holds at module scope. So components, layouts, and hydrated islands import it
|
|
3003
|
+
* directly: no `app.router` reference, no manual "bind", no module global, no
|
|
3004
|
+
* "not bound" guard, and no createApp ↔ routes cycle.
|
|
3005
|
+
*
|
|
3006
|
+
* @param routes - The route map (typically the value returned by {@link defineRoutes}).
|
|
3007
|
+
* @returns A {@link Urls} builder whose `toUrl` accepts only this map's route names.
|
|
3008
|
+
* @example
|
|
3009
|
+
* ```ts
|
|
3010
|
+
* const url = createUrls(routes);
|
|
3011
|
+
* url.toUrl("article", { lang: "en", slug: "hello" }); // "/en/hello/"
|
|
3012
|
+
* ```
|
|
3013
|
+
*/
|
|
3014
|
+
declare function createUrls<T extends RouteMap>(routes: T): Urls<T>;
|
|
2423
3015
|
//#endregion
|
|
2424
3016
|
//#region src/plugins/router/index.d.ts
|
|
2425
3017
|
/**
|
|
2426
3018
|
* Router plugin — typed, named route definitions with locale-aware URL generation
|
|
2427
|
-
* and matching. Author routes with {@link route}
|
|
2428
|
-
*
|
|
3019
|
+
* and matching. Author routes with {@link route}, then register them the normal config
|
|
3020
|
+
* way via `pluginConfigs.router.routes` (compiled at init). Depends on site (base URL)
|
|
3021
|
+
* and i18n (locales).
|
|
2429
3022
|
*
|
|
2430
|
-
* @example
|
|
3023
|
+
* @example Register routes via config, then start/build
|
|
2431
3024
|
* ```ts
|
|
3025
|
+
* import * as routes from "./routes";
|
|
2432
3026
|
* const app = createApp({
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
2435
|
-
* routes: defineRoutes({
|
|
2436
|
-
* home: route("/"),
|
|
2437
|
-
* article: route("/blog/{slug}/")
|
|
2438
|
-
* }),
|
|
2439
|
-
* mode: "hybrid" // "ssg" | "spa" | "hybrid" (default)
|
|
2440
|
-
* }
|
|
2441
|
-
* }
|
|
3027
|
+
* config: { mode: "hybrid" }, // render mode is GLOBAL config
|
|
3028
|
+
* pluginConfigs: { router: { routes } } // declarative route map (a namespace works)
|
|
2442
3029
|
* });
|
|
3030
|
+
* await app.build.run(); // or: await app.start(); — routes compiled at init
|
|
2443
3031
|
* ```
|
|
2444
3032
|
*/
|
|
2445
3033
|
declare const routerPlugin: import("@moku-labs/core").PluginInstance<"router", RouterConfig, RouterState, RouterApi, {}> & {
|
|
2446
3034
|
route: typeof route;
|
|
2447
3035
|
defineRoutes: typeof defineRoutes;
|
|
3036
|
+
createUrls: typeof createUrls;
|
|
2448
3037
|
};
|
|
2449
3038
|
//#endregion
|
|
2450
3039
|
//#region src/plugins/site/index.d.ts
|
|
@@ -2467,7 +3056,7 @@ declare const routerPlugin: import("@moku-labs/core").PluginInstance<"router", R
|
|
|
2467
3056
|
* });
|
|
2468
3057
|
* ```
|
|
2469
3058
|
*/
|
|
2470
|
-
declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Config$
|
|
3059
|
+
declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Config$7, Record<string, never>, Api$7, {}> & Record<never, never>;
|
|
2471
3060
|
//#endregion
|
|
2472
3061
|
//#region src/plugins/spa/components.d.ts
|
|
2473
3062
|
/**
|
|
@@ -2568,6 +3157,20 @@ declare function processEnv(): EnvProvider;
|
|
|
2568
3157
|
*/
|
|
2569
3158
|
declare function cloudflareBindings(): EnvProvider;
|
|
2570
3159
|
//#endregion
|
|
3160
|
+
//#region src/plugins/content/providers.d.ts
|
|
3161
|
+
/**
|
|
3162
|
+
* The node filesystem content provider: reads + renders Markdown from `contentDir`
|
|
3163
|
+
* through the full pipeline. Caches discovery + the unified processor internally.
|
|
3164
|
+
*
|
|
3165
|
+
* @param options - Filesystem + pipeline options (`contentDir`, `shikiTheme`, `trustedContent`, …).
|
|
3166
|
+
* @returns A {@link ContentProvider} backed by the local filesystem.
|
|
3167
|
+
* @example
|
|
3168
|
+
* ```ts
|
|
3169
|
+
* createApp({ pluginConfigs: { content: { providers: [fileSystemContent({ contentDir: "./content" })] } } });
|
|
3170
|
+
* ```
|
|
3171
|
+
*/
|
|
3172
|
+
declare function fileSystemContent(options: FileSystemContentOptions): ContentProvider;
|
|
3173
|
+
//#endregion
|
|
2571
3174
|
//#region src/index.d.ts
|
|
2572
3175
|
/**
|
|
2573
3176
|
* Create and initialize a `@moku-labs/web` application — the Layer-3 entry point.
|
|
@@ -2580,28 +3183,29 @@ declare function cloudflareBindings(): EnvProvider;
|
|
|
2580
3183
|
*
|
|
2581
3184
|
* @param options - Optional configuration:
|
|
2582
3185
|
* - `pluginConfigs` — per-plugin overrides, keyed by plugin name.
|
|
2583
|
-
* - `config` — global framework config (e.g. `{ mode: "
|
|
3186
|
+
* - `config` — global framework config (e.g. `{ mode: "spa" }`).
|
|
2584
3187
|
* - `plugins` — extra plugins (Node-only built-ins or your own) merged into the app and its type.
|
|
2585
3188
|
* - `onReady` / `onError` / `onStart` / `onStop` — lifecycle callbacks.
|
|
2586
3189
|
* @returns The initialized app: `start()`, `stop()`, every plugin's API, and `log`.
|
|
2587
3190
|
* @example
|
|
2588
3191
|
* ```ts
|
|
2589
|
-
* // Node SSG build — add the node-only plugins:
|
|
3192
|
+
* // Node SSG build — add the node-only plugins, register routes via config, then build:
|
|
3193
|
+
* import * as routes from "./routes";
|
|
2590
3194
|
* const app = createApp({
|
|
2591
3195
|
* plugins: [contentPlugin, buildPlugin, deployPlugin],
|
|
2592
3196
|
* pluginConfigs: {
|
|
2593
3197
|
* site: { name: "My Blog", url: "https://blog.dev", author: "Ada", description: "Notes" },
|
|
2594
|
-
* router: { routes
|
|
3198
|
+
* router: { routes }
|
|
2595
3199
|
* }
|
|
2596
3200
|
* });
|
|
2597
|
-
* await app.
|
|
2598
|
-
* await app.build.run();
|
|
3201
|
+
* await app.build.run(); // routes compiled at init
|
|
2599
3202
|
* ```
|
|
2600
3203
|
*/
|
|
2601
|
-
declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$
|
|
3204
|
+
declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs/core").AnyPluginInstance[] = readonly []>(options?: import("@moku-labs/core").CreateAppOptions<Config$8, Events, (import("@moku-labs/core").PluginInstance<"site", Config$7, Record<string, never>, Api$7, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"i18n", Config$6, Record<string, never>, Api$6, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"router", RouterConfig, RouterState, RouterApi, {}> & {
|
|
2602
3205
|
route: typeof route;
|
|
2603
3206
|
defineRoutes: typeof defineRoutes;
|
|
2604
|
-
|
|
3207
|
+
createUrls: typeof createUrls;
|
|
3208
|
+
}) | (import("@moku-labs/core").PluginInstance<"head", Config$4, State$4, Api$4, {}> & {
|
|
2605
3209
|
meta: typeof meta;
|
|
2606
3210
|
og: typeof og;
|
|
2607
3211
|
twitter: typeof twitter;
|
|
@@ -2626,10 +3230,11 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
2626
3230
|
name: string;
|
|
2627
3231
|
el: Element;
|
|
2628
3232
|
};
|
|
2629
|
-
}> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", LogConfig, LogState, LogApi>, import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>]>> | undefined) => import("@moku-labs/core").App<Config$
|
|
3233
|
+
}> & Record<never, never>) | ExtraPlugins[number], [...ExtraPlugins], import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", LogConfig, LogState, LogApi>, import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>]>> | undefined) => import("@moku-labs/core").App<Config$8, Events, (import("@moku-labs/core").PluginInstance<"site", Config$7, Record<string, never>, Api$7, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"i18n", Config$6, Record<string, never>, Api$6, {}> & Record<never, never>) | (import("@moku-labs/core").PluginInstance<"router", RouterConfig, RouterState, RouterApi, {}> & {
|
|
2630
3234
|
route: typeof route;
|
|
2631
3235
|
defineRoutes: typeof defineRoutes;
|
|
2632
|
-
|
|
3236
|
+
createUrls: typeof createUrls;
|
|
3237
|
+
}) | (import("@moku-labs/core").PluginInstance<"head", Config$4, State$4, Api$4, {}> & {
|
|
2633
3238
|
meta: typeof meta;
|
|
2634
3239
|
og: typeof og;
|
|
2635
3240
|
twitter: typeof twitter;
|
|
@@ -2670,6 +3275,6 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
2670
3275
|
* const app = createApp({ plugins: [analytics] });
|
|
2671
3276
|
* ```
|
|
2672
3277
|
*/
|
|
2673
|
-
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$
|
|
3278
|
+
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$8, Events, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", LogConfig, LogState, LogApi>, import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>]>>;
|
|
2674
3279
|
//#endregion
|
|
2675
|
-
export { types_d_exports as Build, types_d_exports$1 as
|
|
3280
|
+
export { types_d_exports as Build, types_d_exports$1 as Cli, types_d_exports$2 as Content, types_d_exports$3 as Data, types_d_exports$4 as Deploy, types_d_exports$5 as Env, types_d_exports$6 as Head, types_d_exports$7 as Log, types_d_exports$8 as Router, types_d_exports$9 as Spa, browserEnv, buildArticleHead, buildPlugin, canonical, cliPlugin, cloudflareBindings, contentPlugin, createApp, createComponent, createPlugin, createUrls, dataPlugin, defineRoutes, deployPlugin, dotenv, envPlugin, feedLink, fileSystemContent, headPlugin, hreflang, i18nPlugin, jsonLd, logPlugin, meta, og, processEnv, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|