@moku-labs/web 1.3.0 → 1.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 +21 -9
- package/dist/browser.mjs +18 -8
- package/dist/index.cjs +30 -20
- package/dist/index.d.cts +22 -11
- package/dist/index.d.mts +22 -11
- package/dist/index.mjs +30 -20
- package/package.json +2 -2
package/dist/browser.d.mts
CHANGED
|
@@ -2028,11 +2028,18 @@ type Config = {
|
|
|
2028
2028
|
*
|
|
2029
2029
|
* @example
|
|
2030
2030
|
* ```ts
|
|
2031
|
-
* { articles: new Map() }
|
|
2031
|
+
* { articles: new Map(), loadedAll: null }
|
|
2032
2032
|
* ```
|
|
2033
2033
|
*/
|
|
2034
2034
|
type State = {
|
|
2035
2035
|
/** Article cache keyed locale -> (slug -> Article). Starts empty. */articles: Map<string, Map<string, Article>>;
|
|
2036
|
+
/**
|
|
2037
|
+
* Memoized full `loadAll()` result, or `null` when not yet loaded / invalidated. List-route
|
|
2038
|
+
* loaders call `loadAll()` once PER PAGE, so without this every page re-reads + re-renders
|
|
2039
|
+
* every article (the dev-loop killer). The memo makes repeated calls O(1); `invalidate()`
|
|
2040
|
+
* clears it so a dev rebuild reloads (re-resolving only the changed slugs). Starts `null`.
|
|
2041
|
+
*/
|
|
2042
|
+
loadedAll: Map<string, Article[]> | null;
|
|
2036
2043
|
};
|
|
2037
2044
|
/**
|
|
2038
2045
|
* Notification-only events emitted by the content plugin.
|
|
@@ -2082,11 +2089,13 @@ type ContentApiContext = {
|
|
|
2082
2089
|
*/
|
|
2083
2090
|
type LoadAllOptions = {
|
|
2084
2091
|
/**
|
|
2085
|
-
* Reuse
|
|
2086
|
-
*
|
|
2087
|
-
*
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2092
|
+
* Reuse the per-build memo + per-slug cache (re-resolving only slugs a preceding
|
|
2093
|
+
* `invalidate()` dropped). Default `true` — this is what keeps repeated `loadAll()` calls
|
|
2094
|
+
* (a list route's loader runs once per page) cheap, and makes a dev rebuild re-render only
|
|
2095
|
+
* changed articles. Set `false` to force a FRESH full reload (cold build / an
|
|
2096
|
+
* unclassifiable change), which re-reads + re-renders every article and rebuilds the memo.
|
|
2097
|
+
* The post-sort `contentId` ordinals are always recomputed across the full set, so order +
|
|
2098
|
+
* ids match a full load either way.
|
|
2090
2099
|
*/
|
|
2091
2100
|
reuse?: boolean;
|
|
2092
2101
|
};
|
|
@@ -2100,10 +2109,13 @@ type LoadAllOptions = {
|
|
|
2100
2109
|
*/
|
|
2101
2110
|
type Api = {
|
|
2102
2111
|
/**
|
|
2103
|
-
* Load every article across every active locale, returning a locale-keyed
|
|
2104
|
-
*
|
|
2112
|
+
* Load every article across every active locale, returning a locale-keyed map of
|
|
2113
|
+
* date-descending Article arrays. Emits content:ready (once per actual load). Cache-first
|
|
2114
|
+
* + memoized: repeated calls (e.g. a list route's loader on every page) return the SAME
|
|
2115
|
+
* cached result with no re-read — so treat the result as READ-ONLY (do not sort/mutate it
|
|
2116
|
+
* in place; slice/copy first). Pass `{ reuse: false }` to force a fresh full reload.
|
|
2105
2117
|
*
|
|
2106
|
-
* @param options - Optional load behaviour ({@link LoadAllOptions});
|
|
2118
|
+
* @param options - Optional load behaviour ({@link LoadAllOptions}); default reuses the cache.
|
|
2107
2119
|
*/
|
|
2108
2120
|
loadAll(options?: LoadAllOptions): Promise<Map<string, Article[]>>;
|
|
2109
2121
|
/**
|
package/dist/browser.mjs
CHANGED
|
@@ -4409,12 +4409,15 @@ function createContentApi(ctx) {
|
|
|
4409
4409
|
* Load every article across every active locale (locale fallback, production
|
|
4410
4410
|
* draft exclusion, date sort, `contentId` after sort), cache them, emit `content:ready`.
|
|
4411
4411
|
*
|
|
4412
|
-
*
|
|
4413
|
-
*
|
|
4414
|
-
*
|
|
4415
|
-
*
|
|
4412
|
+
* Cache-first by default: repeated calls return the per-build memo (list-route loaders
|
|
4413
|
+
* call this once PER PAGE — without the memo every page would re-read + re-render every
|
|
4414
|
+
* article, the dev-loop killer), and a rebuild after `invalidate()` re-resolves only the
|
|
4415
|
+
* dropped slugs while reusing the cached articles for the rest (`contentId` ordinals are
|
|
4416
|
+
* still recomputed across the FULL sorted set, so ids + order match a full load). Pass
|
|
4417
|
+
* `{ reuse: false }` to force a FRESH full reload (cold build / an unclassifiable change
|
|
4418
|
+
* where the caller cannot pinpoint what changed) — this bypasses the memo + per-slug cache.
|
|
4416
4419
|
*
|
|
4417
|
-
* @param options - Optional load behaviour (`reuse`)
|
|
4420
|
+
* @param options - Optional load behaviour (`reuse`, default `true`).
|
|
4418
4421
|
* @returns A locale-keyed map of date-descending articles.
|
|
4419
4422
|
* @example
|
|
4420
4423
|
* ```ts
|
|
@@ -4422,7 +4425,9 @@ function createContentApi(ctx) {
|
|
|
4422
4425
|
* ```
|
|
4423
4426
|
*/
|
|
4424
4427
|
async loadAll(options) {
|
|
4425
|
-
const reuse = options?.reuse
|
|
4428
|
+
const reuse = options?.reuse !== false;
|
|
4429
|
+
const memo = ctx.state.loadedAll;
|
|
4430
|
+
if (reuse && memo !== null) return memo;
|
|
4426
4431
|
const slugs = await ctx.provider.slugs();
|
|
4427
4432
|
const locales = ctx.locales();
|
|
4428
4433
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -4440,6 +4445,7 @@ function createContentApi(ctx) {
|
|
|
4440
4445
|
result.set(locale, present);
|
|
4441
4446
|
total += present.length;
|
|
4442
4447
|
}
|
|
4448
|
+
ctx.state.loadedAll = result;
|
|
4443
4449
|
ctx.emit("content:ready", {
|
|
4444
4450
|
locales,
|
|
4445
4451
|
articleCount: total
|
|
@@ -4503,6 +4509,7 @@ function createContentApi(ctx) {
|
|
|
4503
4509
|
if (slug === void 0) continue;
|
|
4504
4510
|
for (const cache of ctx.state.articles.values()) cache.delete(slug);
|
|
4505
4511
|
}
|
|
4512
|
+
if (accepted.length > 0) ctx.state.loadedAll = null;
|
|
4506
4513
|
ctx.emit("content:invalidated", { paths: accepted });
|
|
4507
4514
|
},
|
|
4508
4515
|
/**
|
|
@@ -4572,14 +4579,17 @@ const contentEvents = (register) => ({
|
|
|
4572
4579
|
* @param _ctx - Minimal context with global and config.
|
|
4573
4580
|
* @param _ctx.global - Global plugin registry.
|
|
4574
4581
|
* @param _ctx.config - Resolved plugin configuration.
|
|
4575
|
-
* @returns Fresh content shell state: an empty article cache.
|
|
4582
|
+
* @returns Fresh content shell state: an empty article cache + an empty loadAll memo.
|
|
4576
4583
|
* @example
|
|
4577
4584
|
* ```ts
|
|
4578
4585
|
* const state = createContentState({ global: {}, config: { providers: [] } });
|
|
4579
4586
|
* ```
|
|
4580
4587
|
*/
|
|
4581
4588
|
function createContentState(_ctx) {
|
|
4582
|
-
return {
|
|
4589
|
+
return {
|
|
4590
|
+
articles: /* @__PURE__ */ new Map(),
|
|
4591
|
+
loadedAll: null
|
|
4592
|
+
};
|
|
4583
4593
|
}
|
|
4584
4594
|
//#endregion
|
|
4585
4595
|
//#region src/plugins/content/validate.ts
|
package/dist/index.cjs
CHANGED
|
@@ -1349,12 +1349,15 @@ function createContentApi(ctx) {
|
|
|
1349
1349
|
* Load every article across every active locale (locale fallback, production
|
|
1350
1350
|
* draft exclusion, date sort, `contentId` after sort), cache them, emit `content:ready`.
|
|
1351
1351
|
*
|
|
1352
|
-
*
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1352
|
+
* Cache-first by default: repeated calls return the per-build memo (list-route loaders
|
|
1353
|
+
* call this once PER PAGE — without the memo every page would re-read + re-render every
|
|
1354
|
+
* article, the dev-loop killer), and a rebuild after `invalidate()` re-resolves only the
|
|
1355
|
+
* dropped slugs while reusing the cached articles for the rest (`contentId` ordinals are
|
|
1356
|
+
* still recomputed across the FULL sorted set, so ids + order match a full load). Pass
|
|
1357
|
+
* `{ reuse: false }` to force a FRESH full reload (cold build / an unclassifiable change
|
|
1358
|
+
* where the caller cannot pinpoint what changed) — this bypasses the memo + per-slug cache.
|
|
1356
1359
|
*
|
|
1357
|
-
* @param options - Optional load behaviour (`reuse`)
|
|
1360
|
+
* @param options - Optional load behaviour (`reuse`, default `true`).
|
|
1358
1361
|
* @returns A locale-keyed map of date-descending articles.
|
|
1359
1362
|
* @example
|
|
1360
1363
|
* ```ts
|
|
@@ -1362,7 +1365,9 @@ function createContentApi(ctx) {
|
|
|
1362
1365
|
* ```
|
|
1363
1366
|
*/
|
|
1364
1367
|
async loadAll(options) {
|
|
1365
|
-
const reuse = options?.reuse
|
|
1368
|
+
const reuse = options?.reuse !== false;
|
|
1369
|
+
const memo = ctx.state.loadedAll;
|
|
1370
|
+
if (reuse && memo !== null) return memo;
|
|
1366
1371
|
const slugs = await ctx.provider.slugs();
|
|
1367
1372
|
const locales = ctx.locales();
|
|
1368
1373
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -1380,6 +1385,7 @@ function createContentApi(ctx) {
|
|
|
1380
1385
|
result.set(locale, present);
|
|
1381
1386
|
total += present.length;
|
|
1382
1387
|
}
|
|
1388
|
+
ctx.state.loadedAll = result;
|
|
1383
1389
|
ctx.emit("content:ready", {
|
|
1384
1390
|
locales,
|
|
1385
1391
|
articleCount: total
|
|
@@ -1443,6 +1449,7 @@ function createContentApi(ctx) {
|
|
|
1443
1449
|
if (slug === void 0) continue;
|
|
1444
1450
|
for (const cache of ctx.state.articles.values()) cache.delete(slug);
|
|
1445
1451
|
}
|
|
1452
|
+
if (accepted.length > 0) ctx.state.loadedAll = null;
|
|
1446
1453
|
ctx.emit("content:invalidated", { paths: accepted });
|
|
1447
1454
|
},
|
|
1448
1455
|
/**
|
|
@@ -1512,14 +1519,17 @@ const contentEvents = (register) => ({
|
|
|
1512
1519
|
* @param _ctx - Minimal context with global and config.
|
|
1513
1520
|
* @param _ctx.global - Global plugin registry.
|
|
1514
1521
|
* @param _ctx.config - Resolved plugin configuration.
|
|
1515
|
-
* @returns Fresh content shell state: an empty article cache.
|
|
1522
|
+
* @returns Fresh content shell state: an empty article cache + an empty loadAll memo.
|
|
1516
1523
|
* @example
|
|
1517
1524
|
* ```ts
|
|
1518
1525
|
* const state = createContentState({ global: {}, config: { providers: [] } });
|
|
1519
1526
|
* ```
|
|
1520
1527
|
*/
|
|
1521
1528
|
function createContentState(_ctx) {
|
|
1522
|
-
return {
|
|
1529
|
+
return {
|
|
1530
|
+
articles: /* @__PURE__ */ new Map(),
|
|
1531
|
+
loadedAll: null
|
|
1532
|
+
};
|
|
1523
1533
|
}
|
|
1524
1534
|
//#endregion
|
|
1525
1535
|
//#region src/plugins/content/validate.ts
|
|
@@ -7515,23 +7525,23 @@ function createDevHandler(ctx, hub) {
|
|
|
7515
7525
|
}
|
|
7516
7526
|
/**
|
|
7517
7527
|
* Build the per-run {@link BuildRunOverrides} for a dev build from the session feature
|
|
7518
|
-
* opt-ins: minification is always off in dev (no benefit, slower), and each expensive
|
|
7519
|
-
* output stays off unless its flag re-enables it (`ogImage: false`
|
|
7520
|
-
* regardless of the persisted config).
|
|
7521
|
-
*
|
|
7528
|
+
* opt-ins: minification is always off in dev (no benefit, slower), and each expensive,
|
|
7529
|
+
* NON-navigational output stays off unless its flag re-enables it (`ogImage: false`
|
|
7530
|
+
* disables OG generation regardless of the persisted config). Locale-redirects are NOT
|
|
7531
|
+
* overridden — they produce navigable pages (the bare `/` → `/{defaultLocale}/` redirect),
|
|
7532
|
+
* so they follow the app's own config. The persisted plugin config is never mutated.
|
|
7522
7533
|
*
|
|
7523
7534
|
* @param features - The resolved per-session dev feature opt-ins.
|
|
7524
7535
|
* @returns The config overrides merged into the dev build run.
|
|
7525
7536
|
* @example
|
|
7526
|
-
* devBuildOverrides({ og: false, sitemap: false, feeds: false
|
|
7537
|
+
* devBuildOverrides({ og: false, sitemap: false, feeds: false });
|
|
7527
7538
|
*/
|
|
7528
7539
|
function devBuildOverrides(features) {
|
|
7529
7540
|
return {
|
|
7530
7541
|
minify: false,
|
|
7531
7542
|
...features.feeds ? {} : { feeds: false },
|
|
7532
7543
|
...features.sitemap ? {} : { sitemap: false },
|
|
7533
|
-
...features.og ? {} : { ogImage: false }
|
|
7534
|
-
...features.localeRedirects ? {} : { localeRedirects: false }
|
|
7544
|
+
...features.og ? {} : { ogImage: false }
|
|
7535
7545
|
};
|
|
7536
7546
|
}
|
|
7537
7547
|
/**
|
|
@@ -7891,9 +7901,10 @@ function createApi$1(ctx) {
|
|
|
7891
7901
|
/**
|
|
7892
7902
|
* Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
|
|
7893
7903
|
* `watchDirs`, debounced + incremental rebuild + reload. For a fast rebuild the dev
|
|
7894
|
-
* build disables minification + expensive,
|
|
7895
|
-
*
|
|
7896
|
-
*
|
|
7904
|
+
* build disables minification + expensive, NON-navigational outputs (feeds / sitemap /
|
|
7905
|
+
* og-images); pass `og`/`sitemap`/`feeds` to re-enable any of them for the session.
|
|
7906
|
+
* Locale-redirects are always built per the app config (they emit the navigable bare-path
|
|
7907
|
+
* `/` → `/{defaultLocale}/` redirect). Resolves on SIGINT/SIGTERM.
|
|
7897
7908
|
*
|
|
7898
7909
|
* @param options - Optional port override + per-session dev feature opt-ins.
|
|
7899
7910
|
* @returns Resolves once the server has been torn down.
|
|
@@ -7906,8 +7917,7 @@ function createApi$1(ctx) {
|
|
|
7906
7917
|
return runDevServer(ctx, port, {
|
|
7907
7918
|
og: options.og ?? false,
|
|
7908
7919
|
sitemap: options.sitemap ?? false,
|
|
7909
|
-
feeds: options.feeds ?? false
|
|
7910
|
-
localeRedirects: options.localeRedirects ?? false
|
|
7920
|
+
feeds: options.feeds ?? false
|
|
7911
7921
|
});
|
|
7912
7922
|
},
|
|
7913
7923
|
/**
|
package/dist/index.d.cts
CHANGED
|
@@ -2460,8 +2460,7 @@ type ServeOptions = {
|
|
|
2460
2460
|
*/
|
|
2461
2461
|
og?: boolean; /** Re-enable `sitemap.xml` + `robots.txt` for this dev session (maps to `--sitemap`). Defaults to `false`. */
|
|
2462
2462
|
sitemap?: boolean; /** Re-enable RSS/Atom/JSON feeds for this dev session (maps to `--feeds`). Defaults to `false`. */
|
|
2463
|
-
feeds?: boolean;
|
|
2464
|
-
localeRedirects?: boolean;
|
|
2463
|
+
feeds?: boolean;
|
|
2465
2464
|
};
|
|
2466
2465
|
/**
|
|
2467
2466
|
* Options for `cli.preview()`.
|
|
@@ -2736,11 +2735,18 @@ type Config = {
|
|
|
2736
2735
|
*
|
|
2737
2736
|
* @example
|
|
2738
2737
|
* ```ts
|
|
2739
|
-
* { articles: new Map() }
|
|
2738
|
+
* { articles: new Map(), loadedAll: null }
|
|
2740
2739
|
* ```
|
|
2741
2740
|
*/
|
|
2742
2741
|
type State = {
|
|
2743
2742
|
/** Article cache keyed locale -> (slug -> Article). Starts empty. */articles: Map<string, Map<string, Article>>;
|
|
2743
|
+
/**
|
|
2744
|
+
* Memoized full `loadAll()` result, or `null` when not yet loaded / invalidated. List-route
|
|
2745
|
+
* loaders call `loadAll()` once PER PAGE, so without this every page re-reads + re-renders
|
|
2746
|
+
* every article (the dev-loop killer). The memo makes repeated calls O(1); `invalidate()`
|
|
2747
|
+
* clears it so a dev rebuild reloads (re-resolving only the changed slugs). Starts `null`.
|
|
2748
|
+
*/
|
|
2749
|
+
loadedAll: Map<string, Article[]> | null;
|
|
2744
2750
|
};
|
|
2745
2751
|
/**
|
|
2746
2752
|
* Notification-only events emitted by the content plugin.
|
|
@@ -2790,11 +2796,13 @@ type ContentApiContext = {
|
|
|
2790
2796
|
*/
|
|
2791
2797
|
type LoadAllOptions = {
|
|
2792
2798
|
/**
|
|
2793
|
-
* Reuse
|
|
2794
|
-
*
|
|
2795
|
-
*
|
|
2796
|
-
*
|
|
2797
|
-
*
|
|
2799
|
+
* Reuse the per-build memo + per-slug cache (re-resolving only slugs a preceding
|
|
2800
|
+
* `invalidate()` dropped). Default `true` — this is what keeps repeated `loadAll()` calls
|
|
2801
|
+
* (a list route's loader runs once per page) cheap, and makes a dev rebuild re-render only
|
|
2802
|
+
* changed articles. Set `false` to force a FRESH full reload (cold build / an
|
|
2803
|
+
* unclassifiable change), which re-reads + re-renders every article and rebuilds the memo.
|
|
2804
|
+
* The post-sort `contentId` ordinals are always recomputed across the full set, so order +
|
|
2805
|
+
* ids match a full load either way.
|
|
2798
2806
|
*/
|
|
2799
2807
|
reuse?: boolean;
|
|
2800
2808
|
};
|
|
@@ -2808,10 +2816,13 @@ type LoadAllOptions = {
|
|
|
2808
2816
|
*/
|
|
2809
2817
|
type Api = {
|
|
2810
2818
|
/**
|
|
2811
|
-
* Load every article across every active locale, returning a locale-keyed
|
|
2812
|
-
*
|
|
2819
|
+
* Load every article across every active locale, returning a locale-keyed map of
|
|
2820
|
+
* date-descending Article arrays. Emits content:ready (once per actual load). Cache-first
|
|
2821
|
+
* + memoized: repeated calls (e.g. a list route's loader on every page) return the SAME
|
|
2822
|
+
* cached result with no re-read — so treat the result as READ-ONLY (do not sort/mutate it
|
|
2823
|
+
* in place; slice/copy first). Pass `{ reuse: false }` to force a fresh full reload.
|
|
2813
2824
|
*
|
|
2814
|
-
* @param options - Optional load behaviour ({@link LoadAllOptions});
|
|
2825
|
+
* @param options - Optional load behaviour ({@link LoadAllOptions}); default reuses the cache.
|
|
2815
2826
|
*/
|
|
2816
2827
|
loadAll(options?: LoadAllOptions): Promise<Map<string, Article[]>>;
|
|
2817
2828
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -2460,8 +2460,7 @@ type ServeOptions = {
|
|
|
2460
2460
|
*/
|
|
2461
2461
|
og?: boolean; /** Re-enable `sitemap.xml` + `robots.txt` for this dev session (maps to `--sitemap`). Defaults to `false`. */
|
|
2462
2462
|
sitemap?: boolean; /** Re-enable RSS/Atom/JSON feeds for this dev session (maps to `--feeds`). Defaults to `false`. */
|
|
2463
|
-
feeds?: boolean;
|
|
2464
|
-
localeRedirects?: boolean;
|
|
2463
|
+
feeds?: boolean;
|
|
2465
2464
|
};
|
|
2466
2465
|
/**
|
|
2467
2466
|
* Options for `cli.preview()`.
|
|
@@ -2736,11 +2735,18 @@ type Config = {
|
|
|
2736
2735
|
*
|
|
2737
2736
|
* @example
|
|
2738
2737
|
* ```ts
|
|
2739
|
-
* { articles: new Map() }
|
|
2738
|
+
* { articles: new Map(), loadedAll: null }
|
|
2740
2739
|
* ```
|
|
2741
2740
|
*/
|
|
2742
2741
|
type State = {
|
|
2743
2742
|
/** Article cache keyed locale -> (slug -> Article). Starts empty. */articles: Map<string, Map<string, Article>>;
|
|
2743
|
+
/**
|
|
2744
|
+
* Memoized full `loadAll()` result, or `null` when not yet loaded / invalidated. List-route
|
|
2745
|
+
* loaders call `loadAll()` once PER PAGE, so without this every page re-reads + re-renders
|
|
2746
|
+
* every article (the dev-loop killer). The memo makes repeated calls O(1); `invalidate()`
|
|
2747
|
+
* clears it so a dev rebuild reloads (re-resolving only the changed slugs). Starts `null`.
|
|
2748
|
+
*/
|
|
2749
|
+
loadedAll: Map<string, Article[]> | null;
|
|
2744
2750
|
};
|
|
2745
2751
|
/**
|
|
2746
2752
|
* Notification-only events emitted by the content plugin.
|
|
@@ -2790,11 +2796,13 @@ type ContentApiContext = {
|
|
|
2790
2796
|
*/
|
|
2791
2797
|
type LoadAllOptions = {
|
|
2792
2798
|
/**
|
|
2793
|
-
* Reuse
|
|
2794
|
-
*
|
|
2795
|
-
*
|
|
2796
|
-
*
|
|
2797
|
-
*
|
|
2799
|
+
* Reuse the per-build memo + per-slug cache (re-resolving only slugs a preceding
|
|
2800
|
+
* `invalidate()` dropped). Default `true` — this is what keeps repeated `loadAll()` calls
|
|
2801
|
+
* (a list route's loader runs once per page) cheap, and makes a dev rebuild re-render only
|
|
2802
|
+
* changed articles. Set `false` to force a FRESH full reload (cold build / an
|
|
2803
|
+
* unclassifiable change), which re-reads + re-renders every article and rebuilds the memo.
|
|
2804
|
+
* The post-sort `contentId` ordinals are always recomputed across the full set, so order +
|
|
2805
|
+
* ids match a full load either way.
|
|
2798
2806
|
*/
|
|
2799
2807
|
reuse?: boolean;
|
|
2800
2808
|
};
|
|
@@ -2808,10 +2816,13 @@ type LoadAllOptions = {
|
|
|
2808
2816
|
*/
|
|
2809
2817
|
type Api = {
|
|
2810
2818
|
/**
|
|
2811
|
-
* Load every article across every active locale, returning a locale-keyed
|
|
2812
|
-
*
|
|
2819
|
+
* Load every article across every active locale, returning a locale-keyed map of
|
|
2820
|
+
* date-descending Article arrays. Emits content:ready (once per actual load). Cache-first
|
|
2821
|
+
* + memoized: repeated calls (e.g. a list route's loader on every page) return the SAME
|
|
2822
|
+
* cached result with no re-read — so treat the result as READ-ONLY (do not sort/mutate it
|
|
2823
|
+
* in place; slice/copy first). Pass `{ reuse: false }` to force a fresh full reload.
|
|
2813
2824
|
*
|
|
2814
|
-
* @param options - Optional load behaviour ({@link LoadAllOptions});
|
|
2825
|
+
* @param options - Optional load behaviour ({@link LoadAllOptions}); default reuses the cache.
|
|
2815
2826
|
*/
|
|
2816
2827
|
loadAll(options?: LoadAllOptions): Promise<Map<string, Article[]>>;
|
|
2817
2828
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1336,12 +1336,15 @@ function createContentApi(ctx) {
|
|
|
1336
1336
|
* Load every article across every active locale (locale fallback, production
|
|
1337
1337
|
* draft exclusion, date sort, `contentId` after sort), cache them, emit `content:ready`.
|
|
1338
1338
|
*
|
|
1339
|
-
*
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
1339
|
+
* Cache-first by default: repeated calls return the per-build memo (list-route loaders
|
|
1340
|
+
* call this once PER PAGE — without the memo every page would re-read + re-render every
|
|
1341
|
+
* article, the dev-loop killer), and a rebuild after `invalidate()` re-resolves only the
|
|
1342
|
+
* dropped slugs while reusing the cached articles for the rest (`contentId` ordinals are
|
|
1343
|
+
* still recomputed across the FULL sorted set, so ids + order match a full load). Pass
|
|
1344
|
+
* `{ reuse: false }` to force a FRESH full reload (cold build / an unclassifiable change
|
|
1345
|
+
* where the caller cannot pinpoint what changed) — this bypasses the memo + per-slug cache.
|
|
1343
1346
|
*
|
|
1344
|
-
* @param options - Optional load behaviour (`reuse`)
|
|
1347
|
+
* @param options - Optional load behaviour (`reuse`, default `true`).
|
|
1345
1348
|
* @returns A locale-keyed map of date-descending articles.
|
|
1346
1349
|
* @example
|
|
1347
1350
|
* ```ts
|
|
@@ -1349,7 +1352,9 @@ function createContentApi(ctx) {
|
|
|
1349
1352
|
* ```
|
|
1350
1353
|
*/
|
|
1351
1354
|
async loadAll(options) {
|
|
1352
|
-
const reuse = options?.reuse
|
|
1355
|
+
const reuse = options?.reuse !== false;
|
|
1356
|
+
const memo = ctx.state.loadedAll;
|
|
1357
|
+
if (reuse && memo !== null) return memo;
|
|
1353
1358
|
const slugs = await ctx.provider.slugs();
|
|
1354
1359
|
const locales = ctx.locales();
|
|
1355
1360
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -1367,6 +1372,7 @@ function createContentApi(ctx) {
|
|
|
1367
1372
|
result.set(locale, present);
|
|
1368
1373
|
total += present.length;
|
|
1369
1374
|
}
|
|
1375
|
+
ctx.state.loadedAll = result;
|
|
1370
1376
|
ctx.emit("content:ready", {
|
|
1371
1377
|
locales,
|
|
1372
1378
|
articleCount: total
|
|
@@ -1430,6 +1436,7 @@ function createContentApi(ctx) {
|
|
|
1430
1436
|
if (slug === void 0) continue;
|
|
1431
1437
|
for (const cache of ctx.state.articles.values()) cache.delete(slug);
|
|
1432
1438
|
}
|
|
1439
|
+
if (accepted.length > 0) ctx.state.loadedAll = null;
|
|
1433
1440
|
ctx.emit("content:invalidated", { paths: accepted });
|
|
1434
1441
|
},
|
|
1435
1442
|
/**
|
|
@@ -1499,14 +1506,17 @@ const contentEvents = (register) => ({
|
|
|
1499
1506
|
* @param _ctx - Minimal context with global and config.
|
|
1500
1507
|
* @param _ctx.global - Global plugin registry.
|
|
1501
1508
|
* @param _ctx.config - Resolved plugin configuration.
|
|
1502
|
-
* @returns Fresh content shell state: an empty article cache.
|
|
1509
|
+
* @returns Fresh content shell state: an empty article cache + an empty loadAll memo.
|
|
1503
1510
|
* @example
|
|
1504
1511
|
* ```ts
|
|
1505
1512
|
* const state = createContentState({ global: {}, config: { providers: [] } });
|
|
1506
1513
|
* ```
|
|
1507
1514
|
*/
|
|
1508
1515
|
function createContentState(_ctx) {
|
|
1509
|
-
return {
|
|
1516
|
+
return {
|
|
1517
|
+
articles: /* @__PURE__ */ new Map(),
|
|
1518
|
+
loadedAll: null
|
|
1519
|
+
};
|
|
1510
1520
|
}
|
|
1511
1521
|
//#endregion
|
|
1512
1522
|
//#region src/plugins/content/validate.ts
|
|
@@ -7502,23 +7512,23 @@ function createDevHandler(ctx, hub) {
|
|
|
7502
7512
|
}
|
|
7503
7513
|
/**
|
|
7504
7514
|
* Build the per-run {@link BuildRunOverrides} for a dev build from the session feature
|
|
7505
|
-
* opt-ins: minification is always off in dev (no benefit, slower), and each expensive
|
|
7506
|
-
* output stays off unless its flag re-enables it (`ogImage: false`
|
|
7507
|
-
* regardless of the persisted config).
|
|
7508
|
-
*
|
|
7515
|
+
* opt-ins: minification is always off in dev (no benefit, slower), and each expensive,
|
|
7516
|
+
* NON-navigational output stays off unless its flag re-enables it (`ogImage: false`
|
|
7517
|
+
* disables OG generation regardless of the persisted config). Locale-redirects are NOT
|
|
7518
|
+
* overridden — they produce navigable pages (the bare `/` → `/{defaultLocale}/` redirect),
|
|
7519
|
+
* so they follow the app's own config. The persisted plugin config is never mutated.
|
|
7509
7520
|
*
|
|
7510
7521
|
* @param features - The resolved per-session dev feature opt-ins.
|
|
7511
7522
|
* @returns The config overrides merged into the dev build run.
|
|
7512
7523
|
* @example
|
|
7513
|
-
* devBuildOverrides({ og: false, sitemap: false, feeds: false
|
|
7524
|
+
* devBuildOverrides({ og: false, sitemap: false, feeds: false });
|
|
7514
7525
|
*/
|
|
7515
7526
|
function devBuildOverrides(features) {
|
|
7516
7527
|
return {
|
|
7517
7528
|
minify: false,
|
|
7518
7529
|
...features.feeds ? {} : { feeds: false },
|
|
7519
7530
|
...features.sitemap ? {} : { sitemap: false },
|
|
7520
|
-
...features.og ? {} : { ogImage: false }
|
|
7521
|
-
...features.localeRedirects ? {} : { localeRedirects: false }
|
|
7531
|
+
...features.og ? {} : { ogImage: false }
|
|
7522
7532
|
};
|
|
7523
7533
|
}
|
|
7524
7534
|
/**
|
|
@@ -7878,9 +7888,10 @@ function createApi$1(ctx) {
|
|
|
7878
7888
|
/**
|
|
7879
7889
|
* Dev loop: build once, serve `dist/` in-process (live-reload injected), watch
|
|
7880
7890
|
* `watchDirs`, debounced + incremental rebuild + reload. For a fast rebuild the dev
|
|
7881
|
-
* build disables minification + expensive,
|
|
7882
|
-
*
|
|
7883
|
-
*
|
|
7891
|
+
* build disables minification + expensive, NON-navigational outputs (feeds / sitemap /
|
|
7892
|
+
* og-images); pass `og`/`sitemap`/`feeds` to re-enable any of them for the session.
|
|
7893
|
+
* Locale-redirects are always built per the app config (they emit the navigable bare-path
|
|
7894
|
+
* `/` → `/{defaultLocale}/` redirect). Resolves on SIGINT/SIGTERM.
|
|
7884
7895
|
*
|
|
7885
7896
|
* @param options - Optional port override + per-session dev feature opt-ins.
|
|
7886
7897
|
* @returns Resolves once the server has been torn down.
|
|
@@ -7893,8 +7904,7 @@ function createApi$1(ctx) {
|
|
|
7893
7904
|
return runDevServer(ctx, port, {
|
|
7894
7905
|
og: options.og ?? false,
|
|
7895
7906
|
sitemap: options.sitemap ?? false,
|
|
7896
|
-
feeds: options.feeds ?? false
|
|
7897
|
-
localeRedirects: options.localeRedirects ?? false
|
|
7907
|
+
feeds: options.feeds ?? false
|
|
7898
7908
|
});
|
|
7899
7909
|
},
|
|
7900
7910
|
/**
|
package/package.json
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"bun": ">=1.3.14"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@moku-labs/core": "0.1.
|
|
61
|
+
"@moku-labs/core": "0.1.1",
|
|
62
62
|
"@resvg/resvg-js": "2.6.2",
|
|
63
63
|
"@shikijs/rehype": "3.22.0",
|
|
64
64
|
"feed": "5.2.0",
|
|
@@ -113,5 +113,5 @@
|
|
|
113
113
|
"test:cli-e2e": "bun test src/plugins/cli/__tests__/e2e/",
|
|
114
114
|
"test:coverage": "vitest run --project unit --project integration --coverage"
|
|
115
115
|
},
|
|
116
|
-
"version": "1.3.
|
|
116
|
+
"version": "1.3.1"
|
|
117
117
|
}
|