@moku-labs/web 2.2.2 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +176 -6
- package/dist/browser.mjs +115 -6
- package/dist/convention-Bs8SrQS9.mjs +109 -0
- package/dist/{convention-BpDfzX7e.cjs → convention-CLIDd9k-.cjs} +0 -43
- package/dist/convention-CsJw7CML.cjs +120 -0
- package/dist/index.cjs +390 -37
- package/dist/index.d.cts +195 -6
- package/dist/index.d.mts +195 -6
- package/dist/index.mjs +328 -16
- package/dist/writer-BBtgz9wt.cjs +90 -0
- package/dist/{writer-JdhX1Wld.cjs → writer-BEM-Pbgb.cjs} +4 -3
- package/dist/writer-C9BfpPio.mjs +87 -0
- package/package.json +1 -1
package/dist/browser.d.mts
CHANGED
|
@@ -277,7 +277,7 @@ interface PathMatcher {
|
|
|
277
277
|
};
|
|
278
278
|
} | null;
|
|
279
279
|
}
|
|
280
|
-
declare namespace types_d_exports$
|
|
280
|
+
declare namespace types_d_exports$4 {
|
|
281
281
|
export { Api$2 as Api, ClientRoute, CompileInput, CompiledRoute, Config$2 as Config, ExtractApi$1 as ExtractApi, ExtractRouteParams, ExtractSegmentParameter, GenerateContext, HeadConfig$1 as HeadConfig, LayoutContext, LoadContext, MatcherTable, Prettify, RouteBuilder, RouteContext, RouteDefinition, RouteHandlers, RouteMap, RouteRequire, RouteState, RouterApi, RouterConfig, RouterState, ScrollMode, State$2 as State, TransitionMode, TypedRoute, Urls };
|
|
282
282
|
}
|
|
283
283
|
/**
|
|
@@ -738,7 +738,7 @@ type Config$2 = RouterConfig;
|
|
|
738
738
|
type State$2 = RouterState;
|
|
739
739
|
/** Re-export under the canonical `Api` name for the plugin-types barrel. */
|
|
740
740
|
type Api$2 = RouterApi;
|
|
741
|
-
declare namespace types_d_exports$
|
|
741
|
+
declare namespace types_d_exports$3 {
|
|
742
742
|
export { Api$1 as Api, ArticleMeta, Config$1 as Config, HeadConfig, HeadDefaults, HeadElement, ResolvedRoute, State$1 as State };
|
|
743
743
|
}
|
|
744
744
|
/**
|
|
@@ -913,7 +913,7 @@ type Api$1 = {
|
|
|
913
913
|
*/
|
|
914
914
|
composeTitle(head: HeadConfig | undefined): string;
|
|
915
915
|
};
|
|
916
|
-
declare namespace types_d_exports$
|
|
916
|
+
declare namespace types_d_exports$5 {
|
|
917
917
|
export { AnyVNode, ExtractApi, ISLAND_HOOK_NAMES, IslandContext, IslandDef, IslandEventHandler, IslandEvents, IslandHooks, IslandInstance, IslandRender, IslandRouteSlice, IslandSpec, IslandSpecExtras, IslandStateFactory, NavigateOptions, PageData, RenderResult, ResolvedSpaConfig, ScrollMode, SpaApi, SpaConfig, SpaContext, SpaDataReader, SpaEmitFunction, SpaEvents, SpaKernel, SpaKernelDeps, SpaRequire, SpaState, TransitionMode };
|
|
918
918
|
}
|
|
919
919
|
/** Per-navigation options for the programmatic navigators (`ctx.navigate` / `app.spa.navigate`). */
|
|
@@ -1925,7 +1925,7 @@ declare const spaPlugin: import("@moku-labs/core").PluginInstance<"spa", SpaConf
|
|
|
1925
1925
|
el: Element;
|
|
1926
1926
|
};
|
|
1927
1927
|
}> & Record<never, never>;
|
|
1928
|
-
declare namespace types_d_exports$
|
|
1928
|
+
declare namespace types_d_exports$2 {
|
|
1929
1929
|
export { DataConfig, DataEntry, DataProvider, DataState, DataWriteSummary };
|
|
1930
1930
|
}
|
|
1931
1931
|
/**
|
|
@@ -2072,7 +2072,43 @@ type DataProvider = {
|
|
|
2072
2072
|
* ```
|
|
2073
2073
|
*/
|
|
2074
2074
|
declare const dataPlugin: import("@moku-labs/core").PluginInstance<"data", DataConfig, DataState, DataProvider, {}> & Record<never, never>;
|
|
2075
|
-
|
|
2075
|
+
//#endregion
|
|
2076
|
+
//#region src/plugins/collection/convention.d.ts
|
|
2077
|
+
/**
|
|
2078
|
+
* Compute the browser fetch URL for a `(collection, shard)` key: the `baseUrl`
|
|
2079
|
+
* prefix joined with the {@link shardSuffix}. Exported so standalone consumers can
|
|
2080
|
+
* derive the same URL without composing the plugin.
|
|
2081
|
+
*
|
|
2082
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
2083
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
2084
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
2085
|
+
* @returns The site-root-relative shard URL (e.g. `/bank/en/animals.json`).
|
|
2086
|
+
* @example
|
|
2087
|
+
* ```ts
|
|
2088
|
+
* collectionUrl("/", "bank", "en/animals"); // "/bank/en/animals.json"
|
|
2089
|
+
* ```
|
|
2090
|
+
*/
|
|
2091
|
+
declare function collectionUrl(baseUrl: string, collection: string, shard: string): string;
|
|
2092
|
+
//#endregion
|
|
2093
|
+
//#region src/plugins/collection/read.d.ts
|
|
2094
|
+
/**
|
|
2095
|
+
* Fetch + parse a build-authored collection shard over HTTP. Builds the shard URL
|
|
2096
|
+
* via {@link collectionUrl}, fetches it, and throws on a non-OK response so the
|
|
2097
|
+
* caller (`collection.at`) can decide whether to fall back.
|
|
2098
|
+
*
|
|
2099
|
+
* @template T - The expected shape of the parsed shard JSON.
|
|
2100
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
2101
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
2102
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
2103
|
+
* @returns The parsed shard JSON, typed as `T`.
|
|
2104
|
+
* @throws {Error} If the fetch is not OK.
|
|
2105
|
+
* @example
|
|
2106
|
+
* ```ts
|
|
2107
|
+
* const animals = await loadCollectionShard<Animal[]>("/", "bank", "en/animals");
|
|
2108
|
+
* ```
|
|
2109
|
+
*/
|
|
2110
|
+
declare function loadCollectionShard<T>(baseUrl: string, collection: string, shard: string): Promise<T>;
|
|
2111
|
+
declare namespace types_d_exports$1 {
|
|
2076
2112
|
export { Api, Article, ArticleCard, ComputedFields, Config, ContentApiContext, ContentEvents, ContentProvider, ContentProviderState, EmbedFacade, EmbedFacadeProps, EmbedOptions, FileSystemContentOptions, Frontmatter, GalleryComponent, GalleryOptions, GalleryProps, GallerySlide, GalleryTransformOptions, LoadAllOptions, MermaidDiagramOptions, State };
|
|
2077
2113
|
}
|
|
2078
2114
|
/**
|
|
@@ -2571,6 +2607,140 @@ declare const contentPlugin: import("@moku-labs/core").PluginInstance<"content",
|
|
|
2571
2607
|
paths: readonly string[];
|
|
2572
2608
|
};
|
|
2573
2609
|
}> & Record<never, never>;
|
|
2610
|
+
declare namespace types_d_exports {
|
|
2611
|
+
export { CollectionConfig, CollectionProvider, CollectionShard, CollectionState, CollectionWriteSummary };
|
|
2612
|
+
}
|
|
2613
|
+
/**
|
|
2614
|
+
* @file collection plugin — type definitions (Standard tier).
|
|
2615
|
+
*
|
|
2616
|
+
* The `collection` plugin is the **static-data collection provider** — the
|
|
2617
|
+
* collection-keyed sibling of the page-path-keyed `data` plugin. It owns ONE
|
|
2618
|
+
* thing: the contract `(collection, shard) → persisted JSON file`. It knows
|
|
2619
|
+
* NOTHING about what the data *is* — no domain types appear here. A consumer
|
|
2620
|
+
* decides its own shard shape (`at`'s `T`).
|
|
2621
|
+
*
|
|
2622
|
+
* - **Node (build):** `write(entries)` persists one JSON file per shard, keyed by
|
|
2623
|
+
* `(collection, shard)` via {@link CollectionProvider.fileFor}. The build
|
|
2624
|
+
* supplies the entries (it already authored the shards), so there is no
|
|
2625
|
+
* expansion here.
|
|
2626
|
+
* - **Browser (runtime):** `at(collection, shard)` fetches + caches that file as
|
|
2627
|
+
* `unknown`, which the consumer reads on demand.
|
|
2628
|
+
*
|
|
2629
|
+
* The Node-only file-writing code (`node:fs`) is isolated behind a lazy `import()`
|
|
2630
|
+
* inside `write()`, so composing `collection` in a browser app keeps the bundle
|
|
2631
|
+
* free of `node:*`.
|
|
2632
|
+
*/
|
|
2633
|
+
/**
|
|
2634
|
+
* Configuration for {@link collectionPlugin}. All fields have defaults (see
|
|
2635
|
+
* `./config`).
|
|
2636
|
+
*
|
|
2637
|
+
* @example
|
|
2638
|
+
* ```ts
|
|
2639
|
+
* const cfg: CollectionConfig = { baseUrl: "/" };
|
|
2640
|
+
* ```
|
|
2641
|
+
*/
|
|
2642
|
+
type CollectionConfig = {
|
|
2643
|
+
/**
|
|
2644
|
+
* READ side (browser): site-root URL prefix the client fetches the per-shard
|
|
2645
|
+
* JSON from. The collection name is the top directory under it, so the fetched
|
|
2646
|
+
* URL is `baseUrl + collection + "/" + shard + ".json"`. Default `"/"`.
|
|
2647
|
+
*/
|
|
2648
|
+
baseUrl: string;
|
|
2649
|
+
};
|
|
2650
|
+
/** One build-authored shard to persist — the build produces these. */
|
|
2651
|
+
interface CollectionShard {
|
|
2652
|
+
/** The collection name — the top directory (e.g. `"bank"`). */
|
|
2653
|
+
collection: string;
|
|
2654
|
+
/**
|
|
2655
|
+
* The shard key WITHIN the collection (e.g. `"en/animals"`); may contain `/`,
|
|
2656
|
+
* which is preserved as a nested path. Maps to a file via
|
|
2657
|
+
* {@link CollectionProvider.fileFor}.
|
|
2658
|
+
*/
|
|
2659
|
+
shard: string;
|
|
2660
|
+
/** The serializable data for this shard. */
|
|
2661
|
+
data: unknown;
|
|
2662
|
+
}
|
|
2663
|
+
/** Summary returned by {@link CollectionProvider.write} and cached in state. */
|
|
2664
|
+
interface CollectionWriteSummary {
|
|
2665
|
+
/** Number of per-shard JSON files written. */
|
|
2666
|
+
fileCount: number;
|
|
2667
|
+
/** Total bytes written across all files. */
|
|
2668
|
+
bytes: number;
|
|
2669
|
+
/** The written file paths, relative to the build `outDir`. */
|
|
2670
|
+
files: string[];
|
|
2671
|
+
}
|
|
2672
|
+
/**
|
|
2673
|
+
* Internal collection state. `lastWrite` records the most recent `write()` (Node);
|
|
2674
|
+
* `cache` memoizes fetched per-`(collection, shard)` data (browser, lazy). Both
|
|
2675
|
+
* empty until their respective side first runs.
|
|
2676
|
+
*/
|
|
2677
|
+
interface CollectionState {
|
|
2678
|
+
/** Result of the last `write()`, or `null` if it has not run yet (Node). */
|
|
2679
|
+
lastWrite: CollectionWriteSummary | null;
|
|
2680
|
+
/** Per-`(collection, shard)` fetched data, cached after the first `at()` (browser). */
|
|
2681
|
+
cache: Map<string, unknown>;
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* Public API mounted at `app.collection` — the static-data collection provider.
|
|
2685
|
+
* `write()` is the Node persist side; `at()` is the browser read side;
|
|
2686
|
+
* `urlFor`/`fileFor` are the pure URL convention shared by both so the written
|
|
2687
|
+
* file and fetched URL can never drift.
|
|
2688
|
+
*
|
|
2689
|
+
* @example
|
|
2690
|
+
* ```ts
|
|
2691
|
+
* // Node build (build supplies the shards it already authored):
|
|
2692
|
+
* await app.collection.write([{ collection: "bank", shard: "en/animals", data }]);
|
|
2693
|
+
*
|
|
2694
|
+
* // Browser: fetch a shard on demand, read by the consumer:
|
|
2695
|
+
* const raw = await app.collection.at("bank", "en/animals"); // unknown | null (null on failure)
|
|
2696
|
+
* ```
|
|
2697
|
+
*/
|
|
2698
|
+
type CollectionProvider = {
|
|
2699
|
+
/**
|
|
2700
|
+
* READ (browser) — fetch (and cache) the persisted data for a `(collection,
|
|
2701
|
+
* shard)` key from `config.baseUrl`. Returns the raw parsed JSON as `unknown`;
|
|
2702
|
+
* returns `null` if the fetch or JSON parse fails.
|
|
2703
|
+
*
|
|
2704
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
2705
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
2706
|
+
* @returns The shard's raw data, or `null` on failure.
|
|
2707
|
+
*/
|
|
2708
|
+
at(collection: string, shard: string): Promise<unknown | null>;
|
|
2709
|
+
/**
|
|
2710
|
+
* WRITE (Node) — persist one JSON file per entry, keyed by `(collection, shard)`
|
|
2711
|
+
* via {@link CollectionProvider.fileFor}. Called by the build after it authors
|
|
2712
|
+
* the shards. Lazily loads its `node:fs` writer, so it never contaminates a
|
|
2713
|
+
* browser bundle.
|
|
2714
|
+
*
|
|
2715
|
+
* @param entries - The per-shard data to persist.
|
|
2716
|
+
* @param options - Optional overrides.
|
|
2717
|
+
* @param options.outDir - Build output directory to write under (default `./dist`).
|
|
2718
|
+
* @returns A summary of the written files.
|
|
2719
|
+
*/
|
|
2720
|
+
write(entries: readonly CollectionShard[], options?: {
|
|
2721
|
+
outDir?: string;
|
|
2722
|
+
}): Promise<CollectionWriteSummary>;
|
|
2723
|
+
/**
|
|
2724
|
+
* PURE — the browser fetch URL for a `(collection, shard)` key (e.g.
|
|
2725
|
+
* `("bank", "en/animals")` → `/bank/en/animals.json`). Shared with
|
|
2726
|
+
* {@link CollectionProvider.fileFor}.
|
|
2727
|
+
*
|
|
2728
|
+
* @param collection - The collection name.
|
|
2729
|
+
* @param shard - The shard key within the collection.
|
|
2730
|
+
* @returns The site-root-relative shard URL.
|
|
2731
|
+
*/
|
|
2732
|
+
urlFor(collection: string, shard: string): string;
|
|
2733
|
+
/**
|
|
2734
|
+
* PURE — the `outDir`-relative file path for a `(collection, shard)` key (e.g.
|
|
2735
|
+
* `("bank", "en/animals")` → `bank/en/animals.json`). Shared with
|
|
2736
|
+
* {@link CollectionProvider.urlFor}.
|
|
2737
|
+
*
|
|
2738
|
+
* @param collection - The collection name.
|
|
2739
|
+
* @param shard - The shard key within the collection.
|
|
2740
|
+
* @returns The output-relative file path.
|
|
2741
|
+
*/
|
|
2742
|
+
fileFor(collection: string, shard: string): string;
|
|
2743
|
+
};
|
|
2574
2744
|
//#endregion
|
|
2575
2745
|
//#region src/browser.d.ts
|
|
2576
2746
|
/**
|
|
@@ -2674,4 +2844,4 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
2674
2844
|
*/
|
|
2675
2845
|
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$5, Events, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", import("@moku-labs/common").LogConfig, import("@moku-labs/common").LogState, import("@moku-labs/common").LogApi>, import("@moku-labs/core").CorePluginInstance<"env", import("@moku-labs/common").EnvConfig, import("@moku-labs/common").EnvState, import("@moku-labs/common").EnvApi>]>>;
|
|
2676
2846
|
//#endregion
|
|
2677
|
-
export { type Channel, type ChannelKeepAlive, type ChannelOptions, type ChannelReconnect, types_d_exports as
|
|
2847
|
+
export { type Channel, type ChannelKeepAlive, type ChannelOptions, type ChannelReconnect, types_d_exports as Collection, types_d_exports$1 as Content, types_d_exports$2 as Data, type Env, types_d_exports$3 as Head, type Log, types_d_exports$4 as Router, types_d_exports$5 as Spa, browserEnv, buildArticleHead, canonical, collectionUrl, contentPlugin, createApp, createChannel, createIsland, createPlugin, createUrls, dataPlugin, defineRoutes, envPlugin, feedLink, hardNavigate, headPlugin, hreflang, i18nPlugin, jsonLd, lazyEmbed, loadCollectionShard, logPlugin, meta, navigate, og, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|
package/dist/browser.mjs
CHANGED
|
@@ -2640,7 +2640,7 @@ function syncHead(_head, doc) {
|
|
|
2640
2640
|
}
|
|
2641
2641
|
//#endregion
|
|
2642
2642
|
//#region src/plugins/spa/types.ts
|
|
2643
|
-
var types_exports$
|
|
2643
|
+
var types_exports$5 = /* @__PURE__ */ __exportAll({ ISLAND_HOOK_NAMES: () => ISLAND_HOOK_NAMES });
|
|
2644
2644
|
/** Allowed hook names — single source of truth for fail-fast validation. */
|
|
2645
2645
|
const ISLAND_HOOK_NAMES = [
|
|
2646
2646
|
"onCreate",
|
|
@@ -4772,6 +4772,112 @@ const spaPlugin = createPlugin$1("spa", {
|
|
|
4772
4772
|
onStop: disposeSpa
|
|
4773
4773
|
});
|
|
4774
4774
|
//#endregion
|
|
4775
|
+
//#region src/plugins/collection/convention.ts
|
|
4776
|
+
/**
|
|
4777
|
+
* @file collection plugin — the pure URL/file convention (no `node:*`, no DOM).
|
|
4778
|
+
*
|
|
4779
|
+
* ONE function maps a `(collection, shard)` key to its shard suffix, so the browser
|
|
4780
|
+
* fetch URL (`baseUrl + suffix`) and the on-disk file (`outDir + "/" + suffix`) are
|
|
4781
|
+
* derived from the same source and cannot drift. The collection name is the top
|
|
4782
|
+
* directory and the shard becomes a `.json` file beneath it (its INTERNAL slashes
|
|
4783
|
+
* are kept as nested dirs):
|
|
4784
|
+
* ("bank", "en/animals") → "bank/en/animals.json"
|
|
4785
|
+
* ("bank", "ru") → "bank/ru.json"
|
|
4786
|
+
* ("/bank/", "/en/") → "bank/en.json" (outer slashes trimmed)
|
|
4787
|
+
*
|
|
4788
|
+
* Encoding split: the FETCH suffix ({@link shardSuffix}) keeps the key's
|
|
4789
|
+
* percent-encoding (the browser requests the encoded path); the FILE path
|
|
4790
|
+
* ({@link relativeShardFile}) decodes it so the on-disk name is literal.
|
|
4791
|
+
*/
|
|
4792
|
+
/**
|
|
4793
|
+
* Strip leading/trailing slashes from `collection` and `shard` (keeping the
|
|
4794
|
+
* shard's INTERNAL slashes as nested path segments), then join them as
|
|
4795
|
+
* `` `${collection}/${shard}.json` `` — the suffix shared by the fetch URL and the
|
|
4796
|
+
* on-disk file.
|
|
4797
|
+
*
|
|
4798
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
4799
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
4800
|
+
* @returns The shard suffix (e.g. `"bank/en/animals.json"`).
|
|
4801
|
+
* @example
|
|
4802
|
+
* ```ts
|
|
4803
|
+
* shardSuffix("bank", "en/animals"); // "bank/en/animals.json"
|
|
4804
|
+
* shardSuffix("/bank/", "/ru/"); // "bank/ru.json"
|
|
4805
|
+
* ```
|
|
4806
|
+
*/
|
|
4807
|
+
function shardSuffix(collection, shard) {
|
|
4808
|
+
return `${trimSlashes(collection)}/${trimSlashes(shard)}.json`;
|
|
4809
|
+
}
|
|
4810
|
+
/**
|
|
4811
|
+
* Strip any leading and trailing slashes from a path segment, leaving its internal
|
|
4812
|
+
* slashes intact.
|
|
4813
|
+
*
|
|
4814
|
+
* @param segment - The raw `collection` or `shard` value.
|
|
4815
|
+
* @returns The segment without outer slashes.
|
|
4816
|
+
* @example
|
|
4817
|
+
* ```ts
|
|
4818
|
+
* trimSlashes("/en/animals/"); // "en/animals"
|
|
4819
|
+
* ```
|
|
4820
|
+
*/
|
|
4821
|
+
function trimSlashes(segment) {
|
|
4822
|
+
let trimmed = segment;
|
|
4823
|
+
while (trimmed.startsWith("/")) trimmed = trimmed.slice(1);
|
|
4824
|
+
while (trimmed.endsWith("/")) trimmed = trimmed.slice(0, -1);
|
|
4825
|
+
return trimmed;
|
|
4826
|
+
}
|
|
4827
|
+
/**
|
|
4828
|
+
* Compute the browser fetch URL for a `(collection, shard)` key: the `baseUrl`
|
|
4829
|
+
* prefix joined with the {@link shardSuffix}. Exported so standalone consumers can
|
|
4830
|
+
* derive the same URL without composing the plugin.
|
|
4831
|
+
*
|
|
4832
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
4833
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
4834
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
4835
|
+
* @returns The site-root-relative shard URL (e.g. `/bank/en/animals.json`).
|
|
4836
|
+
* @example
|
|
4837
|
+
* ```ts
|
|
4838
|
+
* collectionUrl("/", "bank", "en/animals"); // "/bank/en/animals.json"
|
|
4839
|
+
* ```
|
|
4840
|
+
*/
|
|
4841
|
+
function collectionUrl(baseUrl, collection, shard) {
|
|
4842
|
+
return `${baseUrl}${shardSuffix(collection, shard)}`;
|
|
4843
|
+
}
|
|
4844
|
+
//#endregion
|
|
4845
|
+
//#region src/plugins/collection/read.ts
|
|
4846
|
+
/**
|
|
4847
|
+
* @file `loadCollectionShard` — the collection plugin's standalone BROWSER read
|
|
4848
|
+
* primitive. Internal to the `collection` plugin AND exported for standalone
|
|
4849
|
+
* consumers: `collection.at(...)` wraps it, and a room-layer consumer can import it
|
|
4850
|
+
* directly from `@moku-labs/web/browser`.
|
|
4851
|
+
*
|
|
4852
|
+
* Unlike the `data` plugin's isomorphic `loadJson`, this uses the `fetch` global
|
|
4853
|
+
* DIRECTLY (no `node:fs` branch). Consumers — and tests — rely on `fetch` even
|
|
4854
|
+
* under Node test environments, so there is no document sniffing here: a shard is
|
|
4855
|
+
* always fetched over HTTP from the build-authored URL. This keeps the module
|
|
4856
|
+
* fully node-free.
|
|
4857
|
+
*/
|
|
4858
|
+
/**
|
|
4859
|
+
* Fetch + parse a build-authored collection shard over HTTP. Builds the shard URL
|
|
4860
|
+
* via {@link collectionUrl}, fetches it, and throws on a non-OK response so the
|
|
4861
|
+
* caller (`collection.at`) can decide whether to fall back.
|
|
4862
|
+
*
|
|
4863
|
+
* @template T - The expected shape of the parsed shard JSON.
|
|
4864
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
4865
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
4866
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
4867
|
+
* @returns The parsed shard JSON, typed as `T`.
|
|
4868
|
+
* @throws {Error} If the fetch is not OK.
|
|
4869
|
+
* @example
|
|
4870
|
+
* ```ts
|
|
4871
|
+
* const animals = await loadCollectionShard<Animal[]>("/", "bank", "en/animals");
|
|
4872
|
+
* ```
|
|
4873
|
+
*/
|
|
4874
|
+
async function loadCollectionShard(baseUrl, collection, shard) {
|
|
4875
|
+
const url = collectionUrl(baseUrl, collection, shard);
|
|
4876
|
+
const response = await fetch(url);
|
|
4877
|
+
if (!response.ok) throw new Error(`[web] collection: failed to fetch ${url} (${String(response.status)}).`);
|
|
4878
|
+
return response.json();
|
|
4879
|
+
}
|
|
4880
|
+
//#endregion
|
|
4775
4881
|
//#region src/plugins/content/api.ts
|
|
4776
4882
|
/** Actionable error when the content plugin is composed without any provider. */
|
|
4777
4883
|
const NO_PROVIDER = "[web] content: no provider composed.\n Add fileSystemContent(...) to pluginConfigs.content.providers.";
|
|
@@ -5325,18 +5431,21 @@ const contentPlugin = createPlugin$1("content", {
|
|
|
5325
5431
|
api: contentApi
|
|
5326
5432
|
});
|
|
5327
5433
|
//#endregion
|
|
5328
|
-
//#region src/plugins/
|
|
5434
|
+
//#region src/plugins/collection/types.ts
|
|
5329
5435
|
var types_exports = /* @__PURE__ */ __exportAll({});
|
|
5330
5436
|
//#endregion
|
|
5331
|
-
//#region src/plugins/
|
|
5437
|
+
//#region src/plugins/content/types.ts
|
|
5332
5438
|
var types_exports$1 = /* @__PURE__ */ __exportAll({});
|
|
5333
5439
|
//#endregion
|
|
5334
|
-
//#region src/plugins/
|
|
5440
|
+
//#region src/plugins/data/types.ts
|
|
5335
5441
|
var types_exports$2 = /* @__PURE__ */ __exportAll({});
|
|
5336
5442
|
//#endregion
|
|
5337
|
-
//#region src/plugins/
|
|
5443
|
+
//#region src/plugins/head/types.ts
|
|
5338
5444
|
var types_exports$3 = /* @__PURE__ */ __exportAll({});
|
|
5339
5445
|
//#endregion
|
|
5446
|
+
//#region src/plugins/router/types.ts
|
|
5447
|
+
var types_exports$4 = /* @__PURE__ */ __exportAll({});
|
|
5448
|
+
//#endregion
|
|
5340
5449
|
//#region src/browser.ts
|
|
5341
5450
|
/**
|
|
5342
5451
|
* @file `@moku-labs/web/browser` — the browser-safe entry point.
|
|
@@ -5411,4 +5520,4 @@ const createApp = core.createApp;
|
|
|
5411
5520
|
*/
|
|
5412
5521
|
const createPlugin = core.createPlugin;
|
|
5413
5522
|
//#endregion
|
|
5414
|
-
export { types_exports as
|
|
5523
|
+
export { types_exports as Collection, types_exports$1 as Content, types_exports$2 as Data, types_exports$3 as Head, types_exports$4 as Router, types_exports$5 as Spa, browserEnv, buildArticleHead, canonical, collectionUrl, contentPlugin, createApp, createChannel, createIsland, createPlugin, createUrls, dataPlugin, defineRoutes, envPlugin, feedLink, hardNavigate, headPlugin, hreflang, i18nPlugin, jsonLd, lazyEmbed, loadCollectionShard, logPlugin, meta, navigate, og, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
//#region src/plugins/collection/convention.ts
|
|
2
|
+
/**
|
|
3
|
+
* @file collection plugin — the pure URL/file convention (no `node:*`, no DOM).
|
|
4
|
+
*
|
|
5
|
+
* ONE function maps a `(collection, shard)` key to its shard suffix, so the browser
|
|
6
|
+
* fetch URL (`baseUrl + suffix`) and the on-disk file (`outDir + "/" + suffix`) are
|
|
7
|
+
* derived from the same source and cannot drift. The collection name is the top
|
|
8
|
+
* directory and the shard becomes a `.json` file beneath it (its INTERNAL slashes
|
|
9
|
+
* are kept as nested dirs):
|
|
10
|
+
* ("bank", "en/animals") → "bank/en/animals.json"
|
|
11
|
+
* ("bank", "ru") → "bank/ru.json"
|
|
12
|
+
* ("/bank/", "/en/") → "bank/en.json" (outer slashes trimmed)
|
|
13
|
+
*
|
|
14
|
+
* Encoding split: the FETCH suffix ({@link shardSuffix}) keeps the key's
|
|
15
|
+
* percent-encoding (the browser requests the encoded path); the FILE path
|
|
16
|
+
* ({@link relativeShardFile}) decodes it so the on-disk name is literal.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Strip leading/trailing slashes from `collection` and `shard` (keeping the
|
|
20
|
+
* shard's INTERNAL slashes as nested path segments), then join them as
|
|
21
|
+
* `` `${collection}/${shard}.json` `` — the suffix shared by the fetch URL and the
|
|
22
|
+
* on-disk file.
|
|
23
|
+
*
|
|
24
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
25
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
26
|
+
* @returns The shard suffix (e.g. `"bank/en/animals.json"`).
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* shardSuffix("bank", "en/animals"); // "bank/en/animals.json"
|
|
30
|
+
* shardSuffix("/bank/", "/ru/"); // "bank/ru.json"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function shardSuffix(collection, shard) {
|
|
34
|
+
return `${trimSlashes(collection)}/${trimSlashes(shard)}.json`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Strip any leading and trailing slashes from a path segment, leaving its internal
|
|
38
|
+
* slashes intact.
|
|
39
|
+
*
|
|
40
|
+
* @param segment - The raw `collection` or `shard` value.
|
|
41
|
+
* @returns The segment without outer slashes.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* trimSlashes("/en/animals/"); // "en/animals"
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function trimSlashes(segment) {
|
|
48
|
+
let trimmed = segment;
|
|
49
|
+
while (trimmed.startsWith("/")) trimmed = trimmed.slice(1);
|
|
50
|
+
while (trimmed.endsWith("/")) trimmed = trimmed.slice(0, -1);
|
|
51
|
+
return trimmed;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute the browser fetch URL for a `(collection, shard)` key: the `baseUrl`
|
|
55
|
+
* prefix joined with the {@link shardSuffix}. Exported so standalone consumers can
|
|
56
|
+
* derive the same URL without composing the plugin.
|
|
57
|
+
*
|
|
58
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
59
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
60
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
61
|
+
* @returns The site-root-relative shard URL (e.g. `/bank/en/animals.json`).
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* collectionUrl("/", "bank", "en/animals"); // "/bank/en/animals.json"
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function collectionUrl(baseUrl, collection, shard) {
|
|
68
|
+
return `${baseUrl}${shardSuffix(collection, shard)}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decode a shard suffix's percent-escapes so the on-disk file carries the literal
|
|
72
|
+
* name (servers decode the encoded fetch URL before filesystem lookup). Falls back
|
|
73
|
+
* to the raw suffix on malformed escapes.
|
|
74
|
+
*
|
|
75
|
+
* @param suffix - The computed shard suffix (possibly percent-encoded).
|
|
76
|
+
* @returns The decoded suffix, or the raw suffix on malformed escapes.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* decodeSuffix("bank/en/a%20%26%20b.json"); // "bank/en/a & b.json"
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function decodeSuffix(suffix) {
|
|
83
|
+
try {
|
|
84
|
+
return decodeURIComponent(suffix);
|
|
85
|
+
} catch {
|
|
86
|
+
return suffix;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Compute the `outDir`-relative shard file for a `(collection, shard)` key — the
|
|
91
|
+
* DECODED {@link shardSuffix} (servers resolve the decoded request path against
|
|
92
|
+
* literal file names). The collection name IS the top directory, so there is no
|
|
93
|
+
* extra output-dir wrapper. Shared by the Node writer and the pure `fileFor`
|
|
94
|
+
* accessor so the written file and the reported path never drift.
|
|
95
|
+
*
|
|
96
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
97
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
98
|
+
* @returns The `outDir`-relative file path (e.g. `bank/en/animals.json`).
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* relativeShardFile("bank", "en/animals"); // "bank/en/animals.json"
|
|
102
|
+
* relativeShardFile("bank", "a%20%26%20b"); // "bank/a & b.json"
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
function relativeShardFile(collection, shard) {
|
|
106
|
+
return decodeSuffix(shardSuffix(collection, shard));
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { relativeShardFile as n, collectionUrl as t };
|
|
@@ -1,34 +1,3 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __exportAll = (all, no_symbols) => {
|
|
9
|
-
let target = {};
|
|
10
|
-
for (var name in all) __defProp(target, name, {
|
|
11
|
-
get: all[name],
|
|
12
|
-
enumerable: true
|
|
13
|
-
});
|
|
14
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
15
|
-
return target;
|
|
16
|
-
};
|
|
17
|
-
var __copyProps = (to, from, except, desc) => {
|
|
18
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
19
|
-
key = keys[i];
|
|
20
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
21
|
-
get: ((k) => from[k]).bind(null, key),
|
|
22
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
return to;
|
|
26
|
-
};
|
|
27
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
28
|
-
value: mod,
|
|
29
|
-
enumerable: true
|
|
30
|
-
}) : target, mod));
|
|
31
|
-
//#endregion
|
|
32
1
|
//#region src/plugins/data/convention.ts
|
|
33
2
|
/**
|
|
34
3
|
* @file data plugin — the pure URL/file convention (no `node:*`, no DOM).
|
|
@@ -102,18 +71,6 @@ function relativeDataFile(outputDir, path) {
|
|
|
102
71
|
return `${outputDir.endsWith("/") ? outputDir.slice(0, -1) : outputDir}/${decodeSuffix(dataSuffix(path))}`;
|
|
103
72
|
}
|
|
104
73
|
//#endregion
|
|
105
|
-
Object.defineProperty(exports, "__exportAll", {
|
|
106
|
-
enumerable: true,
|
|
107
|
-
get: function() {
|
|
108
|
-
return __exportAll;
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
Object.defineProperty(exports, "__toESM", {
|
|
112
|
-
enumerable: true,
|
|
113
|
-
get: function() {
|
|
114
|
-
return __toESM;
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
74
|
Object.defineProperty(exports, "dataSuffix", {
|
|
118
75
|
enumerable: true,
|
|
119
76
|
get: function() {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//#region src/plugins/collection/convention.ts
|
|
2
|
+
/**
|
|
3
|
+
* @file collection plugin — the pure URL/file convention (no `node:*`, no DOM).
|
|
4
|
+
*
|
|
5
|
+
* ONE function maps a `(collection, shard)` key to its shard suffix, so the browser
|
|
6
|
+
* fetch URL (`baseUrl + suffix`) and the on-disk file (`outDir + "/" + suffix`) are
|
|
7
|
+
* derived from the same source and cannot drift. The collection name is the top
|
|
8
|
+
* directory and the shard becomes a `.json` file beneath it (its INTERNAL slashes
|
|
9
|
+
* are kept as nested dirs):
|
|
10
|
+
* ("bank", "en/animals") → "bank/en/animals.json"
|
|
11
|
+
* ("bank", "ru") → "bank/ru.json"
|
|
12
|
+
* ("/bank/", "/en/") → "bank/en.json" (outer slashes trimmed)
|
|
13
|
+
*
|
|
14
|
+
* Encoding split: the FETCH suffix ({@link shardSuffix}) keeps the key's
|
|
15
|
+
* percent-encoding (the browser requests the encoded path); the FILE path
|
|
16
|
+
* ({@link relativeShardFile}) decodes it so the on-disk name is literal.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Strip leading/trailing slashes from `collection` and `shard` (keeping the
|
|
20
|
+
* shard's INTERNAL slashes as nested path segments), then join them as
|
|
21
|
+
* `` `${collection}/${shard}.json` `` — the suffix shared by the fetch URL and the
|
|
22
|
+
* on-disk file.
|
|
23
|
+
*
|
|
24
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
25
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
26
|
+
* @returns The shard suffix (e.g. `"bank/en/animals.json"`).
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* shardSuffix("bank", "en/animals"); // "bank/en/animals.json"
|
|
30
|
+
* shardSuffix("/bank/", "/ru/"); // "bank/ru.json"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function shardSuffix(collection, shard) {
|
|
34
|
+
return `${trimSlashes(collection)}/${trimSlashes(shard)}.json`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Strip any leading and trailing slashes from a path segment, leaving its internal
|
|
38
|
+
* slashes intact.
|
|
39
|
+
*
|
|
40
|
+
* @param segment - The raw `collection` or `shard` value.
|
|
41
|
+
* @returns The segment without outer slashes.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* trimSlashes("/en/animals/"); // "en/animals"
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function trimSlashes(segment) {
|
|
48
|
+
let trimmed = segment;
|
|
49
|
+
while (trimmed.startsWith("/")) trimmed = trimmed.slice(1);
|
|
50
|
+
while (trimmed.endsWith("/")) trimmed = trimmed.slice(0, -1);
|
|
51
|
+
return trimmed;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute the browser fetch URL for a `(collection, shard)` key: the `baseUrl`
|
|
55
|
+
* prefix joined with the {@link shardSuffix}. Exported so standalone consumers can
|
|
56
|
+
* derive the same URL without composing the plugin.
|
|
57
|
+
*
|
|
58
|
+
* @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
|
|
59
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
60
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
61
|
+
* @returns The site-root-relative shard URL (e.g. `/bank/en/animals.json`).
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* collectionUrl("/", "bank", "en/animals"); // "/bank/en/animals.json"
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function collectionUrl(baseUrl, collection, shard) {
|
|
68
|
+
return `${baseUrl}${shardSuffix(collection, shard)}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decode a shard suffix's percent-escapes so the on-disk file carries the literal
|
|
72
|
+
* name (servers decode the encoded fetch URL before filesystem lookup). Falls back
|
|
73
|
+
* to the raw suffix on malformed escapes.
|
|
74
|
+
*
|
|
75
|
+
* @param suffix - The computed shard suffix (possibly percent-encoded).
|
|
76
|
+
* @returns The decoded suffix, or the raw suffix on malformed escapes.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* decodeSuffix("bank/en/a%20%26%20b.json"); // "bank/en/a & b.json"
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function decodeSuffix(suffix) {
|
|
83
|
+
try {
|
|
84
|
+
return decodeURIComponent(suffix);
|
|
85
|
+
} catch {
|
|
86
|
+
return suffix;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Compute the `outDir`-relative shard file for a `(collection, shard)` key — the
|
|
91
|
+
* DECODED {@link shardSuffix} (servers resolve the decoded request path against
|
|
92
|
+
* literal file names). The collection name IS the top directory, so there is no
|
|
93
|
+
* extra output-dir wrapper. Shared by the Node writer and the pure `fileFor`
|
|
94
|
+
* accessor so the written file and the reported path never drift.
|
|
95
|
+
*
|
|
96
|
+
* @param collection - The collection name (e.g. `"bank"`).
|
|
97
|
+
* @param shard - The shard key within the collection (e.g. `"en/animals"`).
|
|
98
|
+
* @returns The `outDir`-relative file path (e.g. `bank/en/animals.json`).
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* relativeShardFile("bank", "en/animals"); // "bank/en/animals.json"
|
|
102
|
+
* relativeShardFile("bank", "a%20%26%20b"); // "bank/a & b.json"
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
function relativeShardFile(collection, shard) {
|
|
106
|
+
return decodeSuffix(shardSuffix(collection, shard));
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
Object.defineProperty(exports, "collectionUrl", {
|
|
110
|
+
enumerable: true,
|
|
111
|
+
get: function() {
|
|
112
|
+
return collectionUrl;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
Object.defineProperty(exports, "relativeShardFile", {
|
|
116
|
+
enumerable: true,
|
|
117
|
+
get: function() {
|
|
118
|
+
return relativeShardFile;
|
|
119
|
+
}
|
|
120
|
+
});
|