@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/index.cjs CHANGED
@@ -1,5 +1,37 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_convention = require("./convention-BpDfzX7e.cjs");
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __exportAll = (all, no_symbols) => {
10
+ let target = {};
11
+ for (var name in all) __defProp(target, name, {
12
+ get: all[name],
13
+ enumerable: true
14
+ });
15
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
16
+ return target;
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
20
+ key = keys[i];
21
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
22
+ get: ((k) => from[k]).bind(null, key),
23
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
24
+ });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
29
+ value: mod,
30
+ enumerable: true
31
+ }) : target, mod));
32
+ //#endregion
33
+ const require_convention = require("./convention-CLIDd9k-.cjs");
34
+ const require_convention$1 = require("./convention-CsJw7CML.cjs");
3
35
  let _moku_labs_common = require("@moku-labs/common");
4
36
  let _moku_labs_core = require("@moku-labs/core");
5
37
  let node_fs = require("node:fs");
@@ -7,8 +39,8 @@ let node_crypto = require("node:crypto");
7
39
  let node_fs_promises = require("node:fs/promises");
8
40
  let node_os = require("node:os");
9
41
  let node_path = require("node:path");
10
- let node_path$1 = require_convention.__toESM(node_path, 1);
11
- node_path = require_convention.__toESM(node_path);
42
+ let node_path$1 = __toESM(node_path, 1);
43
+ node_path = __toESM(node_path);
12
44
  let feed = require("feed");
13
45
  let preact = require("preact");
14
46
  let preact_render_to_string = require("preact-render-to-string");
@@ -17,31 +49,31 @@ let node_readline = require("node:readline");
17
49
  let node_url = require("node:url");
18
50
  let _moku_labs_common_cli = require("@moku-labs/common/cli");
19
51
  let gray_matter = require("gray-matter");
20
- gray_matter = require_convention.__toESM(gray_matter, 1);
52
+ gray_matter = __toESM(gray_matter, 1);
21
53
  let _shikijs_rehype = require("@shikijs/rehype");
22
- _shikijs_rehype = require_convention.__toESM(_shikijs_rehype, 1);
54
+ _shikijs_rehype = __toESM(_shikijs_rehype, 1);
23
55
  let rehype_sanitize = require("rehype-sanitize");
24
- rehype_sanitize = require_convention.__toESM(rehype_sanitize, 1);
56
+ rehype_sanitize = __toESM(rehype_sanitize, 1);
25
57
  let rehype_stringify = require("rehype-stringify");
26
- rehype_stringify = require_convention.__toESM(rehype_stringify, 1);
58
+ rehype_stringify = __toESM(rehype_stringify, 1);
27
59
  let unified = require("unified");
28
60
  let rehype_raw = require("rehype-raw");
29
- rehype_raw = require_convention.__toESM(rehype_raw, 1);
61
+ rehype_raw = __toESM(rehype_raw, 1);
30
62
  let remark_directive = require("remark-directive");
31
- remark_directive = require_convention.__toESM(remark_directive, 1);
63
+ remark_directive = __toESM(remark_directive, 1);
32
64
  let remark_frontmatter = require("remark-frontmatter");
33
- remark_frontmatter = require_convention.__toESM(remark_frontmatter, 1);
65
+ remark_frontmatter = __toESM(remark_frontmatter, 1);
34
66
  let remark_gfm = require("remark-gfm");
35
- remark_gfm = require_convention.__toESM(remark_gfm, 1);
67
+ remark_gfm = __toESM(remark_gfm, 1);
36
68
  let remark_parse = require("remark-parse");
37
- remark_parse = require_convention.__toESM(remark_parse, 1);
69
+ remark_parse = __toESM(remark_parse, 1);
38
70
  let remark_rehype = require("remark-rehype");
39
- remark_rehype = require_convention.__toESM(remark_rehype, 1);
71
+ remark_rehype = __toESM(remark_rehype, 1);
40
72
  let unist_util_visit = require("unist-util-visit");
41
73
  let preact_jsx_runtime = require("preact/jsx-runtime");
42
74
  let hast_util_sanitize = require("hast-util-sanitize");
43
75
  let reading_time = require("reading-time");
44
- reading_time = require_convention.__toESM(reading_time, 1);
76
+ reading_time = __toESM(reading_time, 1);
45
77
  let node_process = require("node:process");
46
78
  //#region src/config.ts
47
79
  /**
@@ -2571,9 +2603,70 @@ function substituteAssetPlaceholders(ctx, html) {
2571
2603
  return html.replaceAll(ASSETS_PLACEHOLDER, buildAssetTags(ctx)).replaceAll(CSS_ASSETS_PLACEHOLDER, buildAssetTags(ctx, "css")).replaceAll(JS_ASSETS_PLACEHOLDER, buildAssetTags(ctx, "js"));
2572
2604
  }
2573
2605
  /**
2574
- * Copies the configured `publicDir` (default `"public"`) verbatim into `outDir`,
2575
- * preserving the nested directory structure. Skips silently (returns `null`) when
2576
- * the source directory does not exist.
2606
+ * Test whether `destination` is already an up-to-date copy of the `src` file: same
2607
+ * size and at least as new (mtime). A missing destination — or any stat failure —
2608
+ * reports stale: when in doubt, copy.
2609
+ *
2610
+ * @param src - The source file path.
2611
+ * @param destination - The candidate destination file path.
2612
+ * @returns `true` when the destination can be skipped.
2613
+ * @example
2614
+ * ```ts
2615
+ * if (await isFreshCopy(src, destination)) return;
2616
+ * ```
2617
+ */
2618
+ async function isFreshCopy(src, destination) {
2619
+ try {
2620
+ const [srcStat, destinationStat] = await Promise.all([(0, node_fs_promises.stat)(src), (0, node_fs_promises.stat)(destination)]);
2621
+ return destinationStat.size === srcStat.size && destinationStat.mtimeMs >= srcStat.mtimeMs;
2622
+ } catch {
2623
+ return false;
2624
+ }
2625
+ }
2626
+ /**
2627
+ * Recursively copy `from` into `to`, skipping every file whose destination is already
2628
+ * fresh. Skipping matters in dev rebuilds (which keep the previous outDir): re-copying
2629
+ * unchanged assets makes asset-watching dev servers (wrangler) reload on src-only
2630
+ * edits, and on macOS/APFS under Bun a large-file re-copy goes through clonefile(2),
2631
+ * whose FSEvents "ItemCloned" echo on the SOURCE path re-triggers `public/**` watchers
2632
+ * — a self-sustaining rebuild loop. Serial on purpose: public dirs can hold thousands
2633
+ * of assets and the skip path is stat-only, while an unbounded parallel copy risks fd
2634
+ * exhaustion.
2635
+ *
2636
+ * @param from - The source directory.
2637
+ * @param to - The destination directory (created when missing).
2638
+ * @returns The number of entries actually copied.
2639
+ * @example
2640
+ * ```ts
2641
+ * const copied = await copyDirIncremental("public", "dist");
2642
+ * ```
2643
+ */
2644
+ async function copyDirIncremental(from, to) {
2645
+ await (0, node_fs_promises.mkdir)(to, { recursive: true });
2646
+ const entries = await (0, node_fs_promises.readdir)(from, { withFileTypes: true });
2647
+ let copied = 0;
2648
+ for (const entry of entries) {
2649
+ const src = node_path$1.default.join(from, entry.name);
2650
+ const destination = node_path$1.default.join(to, entry.name);
2651
+ if (entry.isDirectory()) copied += await copyDirIncremental(src, destination);
2652
+ else if (entry.isFile()) {
2653
+ if (await isFreshCopy(src, destination)) continue;
2654
+ await (0, node_fs_promises.copyFile)(src, destination);
2655
+ copied += 1;
2656
+ } else {
2657
+ await (0, node_fs_promises.cp)(src, destination, { recursive: true });
2658
+ copied += 1;
2659
+ }
2660
+ }
2661
+ return copied;
2662
+ }
2663
+ /**
2664
+ * Copies the configured `publicDir` (default `"public"`) into `outDir`, preserving the
2665
+ * nested directory structure. The copy is incremental: a file whose destination already
2666
+ * exists with the same size and an mtime at least as new as the source is skipped. A
2667
+ * full build cleans outDir first, so every file misses the compare and the output is
2668
+ * identical to a verbatim copy; a dev rebuild (`skipClean`) rewrites only what changed.
2669
+ * Skips silently (returns `null`) when the source directory does not exist.
2577
2670
  *
2578
2671
  * @param ctx - Plugin context (provides `config`, `log`).
2579
2672
  * @returns The copy result, or `null` when the public directory is absent.
@@ -2591,14 +2684,15 @@ async function copyPublic(ctx) {
2591
2684
  });
2592
2685
  return null;
2593
2686
  }
2594
- await (0, node_fs_promises.cp)(from, ctx.config.outDir, { recursive: true });
2687
+ const copied = await copyDirIncremental(from, ctx.config.outDir);
2595
2688
  ctx.log.debug("build:public", {
2596
2689
  from,
2597
- dest: ctx.config.outDir
2690
+ dest: ctx.config.outDir,
2691
+ copied
2598
2692
  });
2599
2693
  return {
2600
2694
  from: node_path$1.default.normalize(from),
2601
- copied: 1
2695
+ copied
2602
2696
  };
2603
2697
  }
2604
2698
  //#endregion
@@ -4460,7 +4554,7 @@ function dataApi(ctx) {
4460
4554
  * ```
4461
4555
  */
4462
4556
  async write(entries, options) {
4463
- const { writeData } = await Promise.resolve().then(() => require("./writer-JdhX1Wld.cjs"));
4557
+ const { writeData } = await Promise.resolve().then(() => require("./writer-BEM-Pbgb.cjs"));
4464
4558
  return writeData(ctx, entries, options);
4465
4559
  },
4466
4560
  /**
@@ -4544,7 +4638,7 @@ function createDataState(_ctx) {
4544
4638
  * isInvalidBaseUrl("_data"); // true
4545
4639
  * ```
4546
4640
  */
4547
- function isInvalidBaseUrl(baseUrl) {
4641
+ function isInvalidBaseUrl$1(baseUrl) {
4548
4642
  return typeof baseUrl !== "string" || !baseUrl.startsWith("/");
4549
4643
  }
4550
4644
  /**
@@ -4559,7 +4653,7 @@ function isInvalidBaseUrl(baseUrl) {
4559
4653
  * ```
4560
4654
  */
4561
4655
  function validateDataConfig(config) {
4562
- if (isInvalidBaseUrl(config.baseUrl)) throw new Error(`[web] data.baseUrl: must be a site-root-relative URL path starting with "/" (e.g. "/_data/").`);
4656
+ if (isInvalidBaseUrl$1(config.baseUrl)) throw new Error(`[web] data.baseUrl: must be a site-root-relative URL path starting with "/" (e.g. "/_data/").`);
4563
4657
  }
4564
4658
  //#endregion
4565
4659
  //#region src/plugins/data/index.ts
@@ -9181,6 +9275,252 @@ const cliPlugin = createPlugin$1("cli", {
9181
9275
  api: createApi$1
9182
9276
  });
9183
9277
  //#endregion
9278
+ //#region src/plugins/collection/read.ts
9279
+ /**
9280
+ * @file `loadCollectionShard` — the collection plugin's standalone BROWSER read
9281
+ * primitive. Internal to the `collection` plugin AND exported for standalone
9282
+ * consumers: `collection.at(...)` wraps it, and a room-layer consumer can import it
9283
+ * directly from `@moku-labs/web/browser`.
9284
+ *
9285
+ * Unlike the `data` plugin's isomorphic `loadJson`, this uses the `fetch` global
9286
+ * DIRECTLY (no `node:fs` branch). Consumers — and tests — rely on `fetch` even
9287
+ * under Node test environments, so there is no document sniffing here: a shard is
9288
+ * always fetched over HTTP from the build-authored URL. This keeps the module
9289
+ * fully node-free.
9290
+ */
9291
+ /**
9292
+ * Fetch + parse a build-authored collection shard over HTTP. Builds the shard URL
9293
+ * via {@link collectionUrl}, fetches it, and throws on a non-OK response so the
9294
+ * caller (`collection.at`) can decide whether to fall back.
9295
+ *
9296
+ * @template T - The expected shape of the parsed shard JSON.
9297
+ * @param baseUrl - The site-root URL prefix (ends with `/`, e.g. `"/"`).
9298
+ * @param collection - The collection name (e.g. `"bank"`).
9299
+ * @param shard - The shard key within the collection (e.g. `"en/animals"`).
9300
+ * @returns The parsed shard JSON, typed as `T`.
9301
+ * @throws {Error} If the fetch is not OK.
9302
+ * @example
9303
+ * ```ts
9304
+ * const animals = await loadCollectionShard<Animal[]>("/", "bank", "en/animals");
9305
+ * ```
9306
+ */
9307
+ async function loadCollectionShard(baseUrl, collection, shard) {
9308
+ const url = require_convention$1.collectionUrl(baseUrl, collection, shard);
9309
+ const response = await fetch(url);
9310
+ if (!response.ok) throw new Error(`[web] collection: failed to fetch ${url} (${String(response.status)}).`);
9311
+ return response.json();
9312
+ }
9313
+ //#endregion
9314
+ //#region src/plugins/collection/api.ts
9315
+ /**
9316
+ * @file collection plugin — API factory (the collection provider surface).
9317
+ *
9318
+ * Node-free by construction: this module statically imports only types + the pure
9319
+ * convention + the node-free `read` primitive. The Node write side (`write()`)
9320
+ * reaches its `node:fs` writer through a lazy `await import("./writer")` at call
9321
+ * time, so a browser bundle that composes `collection` for the read side never
9322
+ * pulls `node:*`. The read side (`at()`) uses only the `fetch`-based
9323
+ * `loadCollectionShard`.
9324
+ */
9325
+ /**
9326
+ * Builds the collection provider — the static-data bridge. `write()` is the Node
9327
+ * persist side; `at()` is the browser read side; `urlFor`/`fileFor` are the pure
9328
+ * convention. No `onStart`/`onStop` (holds no long-lived resource).
9329
+ *
9330
+ * @param ctx - The collection plugin context.
9331
+ * @returns The {@link CollectionProvider} mounted at `app.collection`.
9332
+ * @example
9333
+ * ```ts
9334
+ * const api = collectionApi(ctx);
9335
+ * await api.write([{ collection: "bank", shard: "en/animals", data }]); // Node build
9336
+ * await api.at("bank", "en/animals"); // browser
9337
+ * ```
9338
+ */
9339
+ function collectionApi(ctx) {
9340
+ return {
9341
+ /**
9342
+ * READ (browser) — fetch (and cache) the persisted data for a `(collection,
9343
+ * shard)` key. Returns the raw JSON as `unknown`; returns `null` if the fetch
9344
+ * or JSON parse fails (so the consumer can fall back). Wraps the throwing
9345
+ * {@link loadCollectionShard} reader into a soft null-returning app read.
9346
+ *
9347
+ * @param collection - The collection name (e.g. `"bank"`).
9348
+ * @param shard - The shard key within the collection (e.g. `"en/animals"`).
9349
+ * @returns The shard's raw data, or `null` on failure.
9350
+ * @example
9351
+ * ```ts
9352
+ * const raw = await api.at("bank", "en/animals");
9353
+ * ```
9354
+ */
9355
+ async at(collection, shard) {
9356
+ const key = `${collection}/${shard}`;
9357
+ if (ctx.state.cache.has(key)) return ctx.state.cache.get(key);
9358
+ try {
9359
+ const data = await loadCollectionShard(ctx.config.baseUrl, collection, shard);
9360
+ ctx.state.cache.set(key, data);
9361
+ return data;
9362
+ } catch {
9363
+ return null;
9364
+ }
9365
+ },
9366
+ /**
9367
+ * WRITE (Node) — persist one JSON file per entry, keyed by `(collection,
9368
+ * shard)`. Called by the build after it authors the shards. Lazily loads its
9369
+ * `node:fs` writer (keeping a browser bundle node-free).
9370
+ *
9371
+ * @param entries - The per-shard data to persist.
9372
+ * @param options - Optional `{ outDir }` override (defaults to `./dist`).
9373
+ * @param options.outDir - Build output directory the write happens under.
9374
+ * @returns A summary of the written files.
9375
+ * @example
9376
+ * ```ts
9377
+ * await api.write([{ collection: "bank", shard: "ru", data }], { outDir: "dist" });
9378
+ * ```
9379
+ */
9380
+ async write(entries, options) {
9381
+ const { writeCollection } = await Promise.resolve().then(() => require("./writer-BBtgz9wt.cjs"));
9382
+ return writeCollection(ctx, entries, options);
9383
+ },
9384
+ /**
9385
+ * PURE — the browser fetch URL for a `(collection, shard)` key.
9386
+ *
9387
+ * @param collection - The collection name.
9388
+ * @param shard - The shard key within the collection.
9389
+ * @returns The site-root-relative shard URL.
9390
+ * @example
9391
+ * ```ts
9392
+ * api.urlFor("bank", "en/animals"); // "/bank/en/animals.json"
9393
+ * ```
9394
+ */
9395
+ urlFor(collection, shard) {
9396
+ return require_convention$1.collectionUrl(ctx.config.baseUrl, collection, shard);
9397
+ },
9398
+ /**
9399
+ * PURE — the `outDir`-relative file path for a `(collection, shard)` key.
9400
+ *
9401
+ * @param collection - The collection name.
9402
+ * @param shard - The shard key within the collection.
9403
+ * @returns The output-relative file path.
9404
+ * @example
9405
+ * ```ts
9406
+ * api.fileFor("bank", "en/animals"); // "bank/en/animals.json"
9407
+ * ```
9408
+ */
9409
+ fileFor(collection, shard) {
9410
+ return require_convention$1.relativeShardFile(collection, shard);
9411
+ }
9412
+ };
9413
+ }
9414
+ //#endregion
9415
+ //#region src/plugins/collection/config.ts
9416
+ /**
9417
+ * Typed default collection config (R6: no inline `as`). `baseUrl` is the READ-side
9418
+ * site-root URL prefix the browser fetches shards from; the collection name is the
9419
+ * top directory under it. The default `"/"` serves shards straight from the site
9420
+ * root (e.g. `/bank/en/animals.json`).
9421
+ *
9422
+ * @example
9423
+ * ```ts
9424
+ * createPlugin("collection", { config: defaultCollectionConfig });
9425
+ * ```
9426
+ */
9427
+ const defaultCollectionConfig = { baseUrl: "/" };
9428
+ //#endregion
9429
+ //#region src/plugins/collection/state.ts
9430
+ /**
9431
+ * Creates initial collection state: a null `lastWrite` slot (populated by the Node
9432
+ * `write()` side) and an empty `cache` (populated lazily by the browser
9433
+ * `at(collection, shard)` side on first fetch).
9434
+ *
9435
+ * @param _ctx - Minimal context with global and config.
9436
+ * @param _ctx.global - Global framework configuration.
9437
+ * @param _ctx.config - Resolved plugin configuration.
9438
+ * @returns Fresh collection state with no recorded write and an empty per-shard cache.
9439
+ * @example
9440
+ * ```ts
9441
+ * const state = createCollectionState({ global: {}, config });
9442
+ * ```
9443
+ */
9444
+ function createCollectionState(_ctx) {
9445
+ return {
9446
+ lastWrite: null,
9447
+ cache: /* @__PURE__ */ new Map()
9448
+ };
9449
+ }
9450
+ //#endregion
9451
+ //#region src/plugins/collection/validate.ts
9452
+ /**
9453
+ * Reports whether a `baseUrl` value is invalid: it must be a string that ends with
9454
+ * a `"/"` so the collection name appends cleanly (`baseUrl + collection + "/" + …`).
9455
+ *
9456
+ * @param baseUrl - The candidate `baseUrl` value to check.
9457
+ * @returns `true` when `baseUrl` is not a string or does not end with "/".
9458
+ * @example
9459
+ * ```ts
9460
+ * isInvalidBaseUrl("/"); // false
9461
+ * isInvalidBaseUrl("/cdn"); // true
9462
+ * ```
9463
+ */
9464
+ function isInvalidBaseUrl(baseUrl) {
9465
+ return typeof baseUrl !== "string" || !baseUrl.endsWith("/");
9466
+ }
9467
+ /**
9468
+ * Validates the resolved collection config: the browser `baseUrl` must be a string
9469
+ * ending with `"/"` so the collection name appends cleanly.
9470
+ *
9471
+ * @param config - The resolved plugin configuration.
9472
+ * @throws {Error} If `baseUrl` is not a string ending with "/".
9473
+ * @example
9474
+ * ```ts
9475
+ * validateCollectionConfig({ baseUrl: "/" });
9476
+ * ```
9477
+ */
9478
+ function validateCollectionConfig(config) {
9479
+ if (isInvalidBaseUrl(config.baseUrl)) throw new Error(`[web] collection.baseUrl: must be a URL prefix ending with "/" (e.g. "/" or "/cdn/").`);
9480
+ }
9481
+ //#endregion
9482
+ //#region src/plugins/collection/index.ts
9483
+ /**
9484
+ * @file collection — Standard tier plugin (wiring-only). The static-data
9485
+ * COLLECTION provider — the collection-keyed sibling of the page-path-keyed `data`
9486
+ * plugin.
9487
+ *
9488
+ * Owns ONE contract — `(collection, shard) → persisted JSON file` — and nothing
9489
+ * about what the data is: `write(entries)` persists per-shard JSON on Node (the
9490
+ * build supplies the shards it already authored); `at(collection, shard)` fetches +
9491
+ * caches it in the browser as `unknown`, read on demand by the consumer. NOT a
9492
+ * framework default — the consumer composes it where needed (Node build AND/OR
9493
+ * browser app).
9494
+ *
9495
+ * **No hard `depends`** — fully browser-composable; the `node:fs` writer is behind
9496
+ * a lazy `import()` inside `write()`. Build ordering is a call-site contract: the
9497
+ * build writes shards during/after its pages phase, via `app.collection.write`.
9498
+ * No `onStart`/`onStop`.
9499
+ * @see README.md
9500
+ */
9501
+ /**
9502
+ * Collection plugin — the static-data collection provider. Mounts
9503
+ * `write(entries)` (Node persist), `at(collection, shard)` (browser read), and the
9504
+ * pure `urlFor`/`fileFor` convention at `app.collection`.
9505
+ *
9506
+ * @example
9507
+ * ```ts
9508
+ * // Node build: write build-authored shards during/after the build's pages phase.
9509
+ * const app = createApp({ plugins: [collectionPlugin, buildPlugin] });
9510
+ * await app.build.run();
9511
+ * await app.collection.write([{ collection: "bank", shard: "en/animals", data }]);
9512
+ *
9513
+ * // Browser app: compose `collectionPlugin` too; fetch a shard on demand.
9514
+ * const raw = await app.collection.at("bank", "en/animals"); // unknown | null
9515
+ * ```
9516
+ */
9517
+ const collectionPlugin = createPlugin$1("collection", {
9518
+ config: defaultCollectionConfig,
9519
+ createState: createCollectionState,
9520
+ onInit: (ctx) => validateCollectionConfig(ctx.config),
9521
+ api: collectionApi
9522
+ });
9523
+ //#endregion
9184
9524
  //#region src/plugins/spa/api.ts
9185
9525
  /**
9186
9526
  * Creates the spa plugin API surface (registration / control). All methods
@@ -9346,7 +9686,7 @@ function syncHead(_head, doc) {
9346
9686
  }
9347
9687
  //#endregion
9348
9688
  //#region src/plugins/spa/types.ts
9349
- var types_exports$7 = /* @__PURE__ */ require_convention.__exportAll({ ISLAND_HOOK_NAMES: () => ISLAND_HOOK_NAMES });
9689
+ var types_exports$8 = /* @__PURE__ */ __exportAll({ ISLAND_HOOK_NAMES: () => ISLAND_HOOK_NAMES });
9350
9690
  /** Allowed hook names — single source of truth for fail-fast validation. */
9351
9691
  const ISLAND_HOOK_NAMES = [
9352
9692
  "onCreate",
@@ -11479,25 +11819,28 @@ const spaPlugin = createPlugin$1("spa", {
11479
11819
  });
11480
11820
  //#endregion
11481
11821
  //#region src/plugins/build/types.ts
11482
- var types_exports = /* @__PURE__ */ require_convention.__exportAll({});
11822
+ var types_exports = /* @__PURE__ */ __exportAll({});
11483
11823
  //#endregion
11484
11824
  //#region src/plugins/cli/types.ts
11485
- var types_exports$1 = /* @__PURE__ */ require_convention.__exportAll({});
11825
+ var types_exports$1 = /* @__PURE__ */ __exportAll({});
11826
+ //#endregion
11827
+ //#region src/plugins/collection/types.ts
11828
+ var types_exports$2 = /* @__PURE__ */ __exportAll({});
11486
11829
  //#endregion
11487
11830
  //#region src/plugins/content/types.ts
11488
- var types_exports$2 = /* @__PURE__ */ require_convention.__exportAll({});
11831
+ var types_exports$3 = /* @__PURE__ */ __exportAll({});
11489
11832
  //#endregion
11490
11833
  //#region src/plugins/data/types.ts
11491
- var types_exports$3 = /* @__PURE__ */ require_convention.__exportAll({});
11834
+ var types_exports$4 = /* @__PURE__ */ __exportAll({});
11492
11835
  //#endregion
11493
11836
  //#region src/plugins/deploy/types.ts
11494
- var types_exports$4 = /* @__PURE__ */ require_convention.__exportAll({});
11837
+ var types_exports$5 = /* @__PURE__ */ __exportAll({});
11495
11838
  //#endregion
11496
11839
  //#region src/plugins/head/types.ts
11497
- var types_exports$5 = /* @__PURE__ */ require_convention.__exportAll({});
11840
+ var types_exports$6 = /* @__PURE__ */ __exportAll({});
11498
11841
  //#endregion
11499
11842
  //#region src/plugins/router/types.ts
11500
- var types_exports$6 = /* @__PURE__ */ require_convention.__exportAll({});
11843
+ var types_exports$7 = /* @__PURE__ */ __exportAll({});
11501
11844
  //#endregion
11502
11845
  //#region node_modules/unist-util-stringify-position/lib/index.js
11503
11846
  /**
@@ -13709,44 +14052,51 @@ Object.defineProperty(exports, "Cli", {
13709
14052
  return types_exports$1;
13710
14053
  }
13711
14054
  });
13712
- Object.defineProperty(exports, "Content", {
14055
+ Object.defineProperty(exports, "Collection", {
13713
14056
  enumerable: true,
13714
14057
  get: function() {
13715
14058
  return types_exports$2;
13716
14059
  }
13717
14060
  });
13718
- Object.defineProperty(exports, "Data", {
14061
+ Object.defineProperty(exports, "Content", {
13719
14062
  enumerable: true,
13720
14063
  get: function() {
13721
14064
  return types_exports$3;
13722
14065
  }
13723
14066
  });
13724
- Object.defineProperty(exports, "Deploy", {
14067
+ Object.defineProperty(exports, "Data", {
13725
14068
  enumerable: true,
13726
14069
  get: function() {
13727
14070
  return types_exports$4;
13728
14071
  }
13729
14072
  });
14073
+ Object.defineProperty(exports, "Deploy", {
14074
+ enumerable: true,
14075
+ get: function() {
14076
+ return types_exports$5;
14077
+ }
14078
+ });
13730
14079
  exports.EmbedFacadeButton = EmbedFacadeButton;
13731
14080
  exports.GalleryTrack = GalleryTrack;
13732
14081
  Object.defineProperty(exports, "Head", {
13733
14082
  enumerable: true,
13734
14083
  get: function() {
13735
- return types_exports$5;
14084
+ return types_exports$6;
13736
14085
  }
13737
14086
  });
13738
14087
  Object.defineProperty(exports, "Router", {
13739
14088
  enumerable: true,
13740
14089
  get: function() {
13741
- return types_exports$6;
14090
+ return types_exports$7;
13742
14091
  }
13743
14092
  });
13744
14093
  Object.defineProperty(exports, "Spa", {
13745
14094
  enumerable: true,
13746
14095
  get: function() {
13747
- return types_exports$7;
14096
+ return types_exports$8;
13748
14097
  }
13749
14098
  });
14099
+ exports.__toESM = __toESM;
13750
14100
  Object.defineProperty(exports, "browserEnv", {
13751
14101
  enumerable: true,
13752
14102
  get: function() {
@@ -13763,6 +14113,8 @@ Object.defineProperty(exports, "cloudflareBindings", {
13763
14113
  return _moku_labs_common.cloudflareBindings;
13764
14114
  }
13765
14115
  });
14116
+ exports.collectionPlugin = collectionPlugin;
14117
+ exports.collectionUrl = require_convention$1.collectionUrl;
13766
14118
  exports.contentPlugin = contentPlugin;
13767
14119
  exports.createApp = createApp;
13768
14120
  exports.createChannel = createChannel;
@@ -13792,6 +14144,7 @@ exports.hreflang = hreflang;
13792
14144
  exports.i18nPlugin = i18nPlugin;
13793
14145
  exports.jsonLd = jsonLd;
13794
14146
  exports.lazyEmbed = lazyEmbed;
14147
+ exports.loadCollectionShard = loadCollectionShard;
13795
14148
  Object.defineProperty(exports, "logPlugin", {
13796
14149
  enumerable: true,
13797
14150
  get: function() {