@riebeckite/core 0.0.17 → 0.0.19

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.js CHANGED
@@ -119,41 +119,41 @@ function validateTheme(value, issues) {
119
119
  }
120
120
  }
121
121
  }
122
- function validateThemeConfig(value, path5, issues) {
123
- validateOptionalString(value.name, `${path5}.name`, issues);
122
+ function validateThemeConfig(value, path6, issues) {
123
+ validateOptionalString(value.name, `${path6}.name`, issues);
124
124
  validateOneOf(
125
125
  value.colorMode,
126
- `${path5}.colorMode`,
126
+ `${path6}.colorMode`,
127
127
  ["light", "dark", "system"],
128
128
  issues
129
129
  );
130
130
  validateOneOf(
131
131
  value.typography,
132
- `${path5}.typography`,
132
+ `${path6}.typography`,
133
133
  ["system", "serif", "sans"],
134
134
  issues
135
135
  );
136
136
  validateOneOf(
137
137
  value.articleLayout,
138
- `${path5}.articleLayout`,
138
+ `${path6}.articleLayout`,
139
139
  ["article", "sidebar", "full-width"],
140
140
  issues
141
141
  );
142
- validateStringArray(value.userCss, `${path5}.userCss`, issues);
142
+ validateStringArray(value.userCss, `${path6}.userCss`, issues);
143
143
  if (value.attributes !== void 0 && !isRecord(value.attributes)) {
144
- issues.push({ path: `${path5}.attributes`, message: "Expected an object." });
144
+ issues.push({ path: `${path6}.attributes`, message: "Expected an object." });
145
145
  }
146
146
  }
147
- function validateThemeStyles(value, path5, issues) {
147
+ function validateThemeStyles(value, path6, issues) {
148
148
  if (value === void 0) return;
149
149
  if (!Array.isArray(value)) {
150
- issues.push({ path: path5, message: "Expected an array." });
150
+ issues.push({ path: path6, message: "Expected an array." });
151
151
  return;
152
152
  }
153
153
  for (const [index, style] of value.entries()) {
154
154
  if (!isRecord(style) || !isNonEmptyString(style.moduleSpecifier)) {
155
155
  issues.push({
156
- path: `${path5}[${index}].moduleSpecifier`,
156
+ path: `${path6}[${index}].moduleSpecifier`,
157
157
  message: "Expected a non-empty string."
158
158
  });
159
159
  }
@@ -173,69 +173,69 @@ function validatePlugins(value, issues) {
173
173
  continue;
174
174
  }
175
175
  const plugin = input;
176
- const path5 = `plugins[${index}]`;
176
+ const path6 = `plugins[${index}]`;
177
177
  if (!isNonEmptyString(plugin.name)) {
178
178
  issues.push({
179
- path: `${path5}.name`,
179
+ path: `${path6}.name`,
180
180
  message: "Expected a non-empty string."
181
181
  });
182
182
  } else if (plugin.enabled !== false) {
183
183
  const duplicateIndex = names.get(plugin.name);
184
184
  if (duplicateIndex !== void 0) {
185
185
  issues.push({
186
- path: `${path5}.name`,
186
+ path: `${path6}.name`,
187
187
  message: `Duplicate plugin name "${plugin.name}" (also plugins[${duplicateIndex}]).`
188
188
  });
189
189
  } else {
190
190
  names.set(plugin.name, index);
191
191
  }
192
192
  }
193
- validateOptionalBoolean(plugin.enabled, `${path5}.enabled`, issues);
194
- validateCapabilityMetadata(plugin, path5, issues);
195
- if (plugin.enabled !== false) validatePluginOptions(plugin, path5, issues);
193
+ validateOptionalBoolean(plugin.enabled, `${path6}.enabled`, issues);
194
+ validateCapabilityMetadata(plugin, path6, issues);
195
+ if (plugin.enabled !== false) validatePluginOptions(plugin, path6, issues);
196
196
  }
197
197
  }
198
- function validateCapabilityMetadata(plugin, path5, issues) {
199
- validateStringArray(plugin.provides, `${path5}.provides`, issues, true);
200
- validateStringArray(plugin.requires, `${path5}.requires`, issues, true);
201
- validateStringArray(plugin.optional, `${path5}.optional`, issues, true);
198
+ function validateCapabilityMetadata(plugin, path6, issues) {
199
+ validateStringArray(plugin.provides, `${path6}.provides`, issues, true);
200
+ validateStringArray(plugin.requires, `${path6}.requires`, issues, true);
201
+ validateStringArray(plugin.optional, `${path6}.optional`, issues, true);
202
202
  }
203
- function validatePluginOptions(plugin, path5, issues) {
203
+ function validatePluginOptions(plugin, path6, issues) {
204
204
  if (!plugin.validateOptions) return;
205
205
  try {
206
206
  const optionIssues = plugin.validateOptions(plugin.options) ?? [];
207
207
  for (const issue of optionIssues) {
208
208
  issues.push({
209
- path: issue.path ? `${path5}.options.${issue.path}` : `${path5}.options`,
209
+ path: issue.path ? `${path6}.options.${issue.path}` : `${path6}.options`,
210
210
  message: issue.message
211
211
  });
212
212
  }
213
213
  } catch (error) {
214
214
  issues.push({
215
- path: `${path5}.options`,
215
+ path: `${path6}.options`,
216
216
  message: `Validator failed: ${toErrorMessage(error)}`
217
217
  });
218
218
  }
219
219
  }
220
- function validateRequiredString(value, path5, issues) {
220
+ function validateRequiredString(value, path6, issues) {
221
221
  if (!isNonEmptyString(value)) {
222
- issues.push({ path: path5, message: "Expected a non-empty string." });
222
+ issues.push({ path: path6, message: "Expected a non-empty string." });
223
223
  }
224
224
  }
225
- function validateOptionalString(value, path5, issues) {
225
+ function validateOptionalString(value, path6, issues) {
226
226
  if (value !== void 0 && typeof value !== "string") {
227
- issues.push({ path: path5, message: "Expected a string." });
227
+ issues.push({ path: path6, message: "Expected a string." });
228
228
  }
229
229
  }
230
- function validateOptionalBoolean(value, path5, issues) {
230
+ function validateOptionalBoolean(value, path6, issues) {
231
231
  if (value !== void 0 && typeof value !== "boolean") {
232
- issues.push({ path: path5, message: "Expected a boolean." });
232
+ issues.push({ path: path6, message: "Expected a boolean." });
233
233
  }
234
234
  }
235
- function validateAbsoluteUrl(value, path5, issues) {
235
+ function validateAbsoluteUrl(value, path6, issues) {
236
236
  if (value === void 0 || value === "") return;
237
237
  if (typeof value !== "string") {
238
- issues.push({ path: path5, message: "Expected an absolute URL." });
238
+ issues.push({ path: path6, message: "Expected an absolute URL." });
239
239
  return;
240
240
  }
241
241
  try {
@@ -243,27 +243,27 @@ function validateAbsoluteUrl(value, path5, issues) {
243
243
  if (url.protocol !== "http:" && url.protocol !== "https:")
244
244
  throw new Error();
245
245
  } catch {
246
- issues.push({ path: path5, message: "Expected an absolute HTTP(S) URL." });
246
+ issues.push({ path: path6, message: "Expected an absolute HTTP(S) URL." });
247
247
  }
248
248
  }
249
- function validateStringArray(value, path5, issues, nonEmpty = false) {
249
+ function validateStringArray(value, path6, issues, nonEmpty = false) {
250
250
  if (value === void 0) return;
251
251
  if (!Array.isArray(value)) {
252
- issues.push({ path: path5, message: "Expected an array." });
252
+ issues.push({ path: path6, message: "Expected an array." });
253
253
  return;
254
254
  }
255
255
  for (const [index, item] of value.entries()) {
256
256
  if (typeof item !== "string" || nonEmpty && !item.trim()) {
257
257
  issues.push({
258
- path: `${path5}[${index}]`,
258
+ path: `${path6}[${index}]`,
259
259
  message: nonEmpty ? "Expected a non-empty string." : "Expected a string."
260
260
  });
261
261
  }
262
262
  }
263
263
  }
264
- function validateOneOf(value, path5, choices, issues) {
264
+ function validateOneOf(value, path6, choices, issues) {
265
265
  if (value !== void 0 && (typeof value !== "string" || !choices.includes(value))) {
266
- issues.push({ path: path5, message: `Expected one of: ${choices.join(", ")}.` });
266
+ issues.push({ path: path6, message: `Expected one of: ${choices.join(", ")}.` });
267
267
  }
268
268
  }
269
269
  function formatValidationIssues(issues) {
@@ -284,6 +284,74 @@ function toErrorMessage(error) {
284
284
  return error instanceof Error ? error.message : String(error);
285
285
  }
286
286
 
287
+ // src/types/publish_strategy.ts
288
+ function isPublishable(strategy, frontmatter) {
289
+ if (strategy === "explicit") {
290
+ return frontmatter?.publish === true;
291
+ }
292
+ return !(frontmatter?.private === true || frontmatter?.draft === true);
293
+ }
294
+
295
+ // src/content/publishing.ts
296
+ function resolvePublishingState(frontmatter, options) {
297
+ const explicitVisibility = resolveExplicitVisibility(frontmatter?.visibility);
298
+ const publishAt = resolvePublishAt(frontmatter?.publishAt);
299
+ if (explicitVisibility === "draft")
300
+ return state("draft", false, false, publishAt);
301
+ if (publishAt && publishAt.getTime() > options.buildTime.getTime()) {
302
+ return state("scheduled", false, false, publishAt);
303
+ }
304
+ if (explicitVisibility === "unlisted") {
305
+ return state("unlisted", true, false, publishAt);
306
+ }
307
+ if (explicitVisibility === "public" || publishAt) {
308
+ return state("public", true, true, publishAt);
309
+ }
310
+ const routable = isPublishable(options.strategy, frontmatter);
311
+ return state(routable ? "public" : "draft", routable, routable, publishAt);
312
+ }
313
+ function resolvePublishingBuildTime(input) {
314
+ if (input === void 0) return /* @__PURE__ */ new Date();
315
+ if (input instanceof Date) {
316
+ if (Number.isNaN(input.getTime()))
317
+ throw new Error("Invalid publishing build time.");
318
+ return new Date(input.getTime());
319
+ }
320
+ const parsed = new Date(input);
321
+ if (Number.isNaN(parsed.getTime()))
322
+ throw new Error("Invalid publishing build time.");
323
+ return parsed;
324
+ }
325
+ function resolveExplicitVisibility(value) {
326
+ if (value === void 0) return void 0;
327
+ if (value === "public" || value === "unlisted" || value === "draft")
328
+ return value;
329
+ throw new Error(
330
+ `Invalid content visibility "${String(value)}". Expected public, unlisted, or draft.`
331
+ );
332
+ }
333
+ function resolvePublishAt(value) {
334
+ if (value === void 0) return void 0;
335
+ if (!(typeof value === "string" || value instanceof Date)) {
336
+ throw new Error("Invalid publishAt. Expected an ISO 8601 date string.");
337
+ }
338
+ const parsed = value instanceof Date ? value : new Date(value);
339
+ if (Number.isNaN(parsed.getTime())) {
340
+ throw new Error(
341
+ `Invalid publishAt "${String(value)}". Expected an ISO 8601 date string.`
342
+ );
343
+ }
344
+ return new Date(parsed.getTime());
345
+ }
346
+ function state(visibility, routable, discoverable, publishAt) {
347
+ return {
348
+ visibility,
349
+ routable,
350
+ discoverable,
351
+ ...publishAt ? { publishAt } : {}
352
+ };
353
+ }
354
+
287
355
  // src/plugin/plugin_dependency_error.ts
288
356
  var PluginDependencyError = class extends Error {
289
357
  kind;
@@ -573,14 +641,6 @@ function getResolvedPluginMetadata(plugins) {
573
641
  }));
574
642
  }
575
643
 
576
- // src/types/publish_strategy.ts
577
- function isPublishable(strategy, frontmatter) {
578
- if (strategy === "explicit") {
579
- return frontmatter?.publish === true;
580
- }
581
- return !(frontmatter?.private === true || frontmatter?.draft === true);
582
- }
583
-
584
644
  // src/types/theme_config.ts
585
645
  function defineTheme(theme) {
586
646
  return theme;
@@ -680,10 +740,11 @@ function sanitizeThemeAttributes(attributes) {
680
740
  ).filter(([name]) => !reservedAttributes.has(name))
681
741
  );
682
742
  }
683
- function isPublished(config, frontmatter) {
684
- if (frontmatter?.visibility === "unlisted") return true;
685
- if (frontmatter?.visibility === "draft") return false;
686
- return isPublishable(config.content.filters.publishStrategy, frontmatter);
743
+ function isPublished(config, frontmatter, options = {}) {
744
+ return resolvePublishingState(frontmatter, {
745
+ strategy: config.content.filters.publishStrategy,
746
+ buildTime: resolvePublishingBuildTime(options.buildTime)
747
+ }).routable;
687
748
  }
688
749
  function isExcluded(patterns, relativePath) {
689
750
  const normalized = relativePath.replace(/\\/g, "/");
@@ -745,9 +806,9 @@ var configDeprecations = [];
745
806
  function collectConfigDeprecationDiagnostics(config, notices = configDeprecations) {
746
807
  return notices.filter((notice) => hasConfigPath(config, notice.path)).map(createDeprecationDiagnostic);
747
808
  }
748
- function hasConfigPath(config, path5) {
809
+ function hasConfigPath(config, path6) {
749
810
  let value = config;
750
- for (const segment of path5.split(".")) {
811
+ for (const segment of path6.split(".")) {
751
812
  if (!isRecord2(value) || !(segment in value)) return false;
752
813
  value = value[segment];
753
814
  }
@@ -810,7 +871,7 @@ import fs from "node:fs/promises";
810
871
  import path from "node:path";
811
872
 
812
873
  // src/content/content_build_state.ts
813
- var CONTENT_BUILD_STATE_VERSION = 7;
874
+ var CONTENT_BUILD_STATE_VERSION = 8;
814
875
  var CONTENT_BUILD_STATE_DIRECTORY = ".riebeckite";
815
876
  var CONTENT_BUILD_STATE_EXCLUDE = `${CONTENT_BUILD_STATE_DIRECTORY}/**`;
816
877
 
@@ -1215,9 +1276,9 @@ function buildContentCollections(entries, definitions) {
1215
1276
  function normalizePageSize(value) {
1216
1277
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
1217
1278
  }
1218
- function withPage(path5, index) {
1219
- if (index === 0) return path5;
1220
- const base = path5 === "/" ? "" : path5;
1279
+ function withPage(path6, index) {
1280
+ if (index === 0) return path6;
1281
+ const base = path6 === "/" ? "" : path6;
1221
1282
  return normalizePath(`${base}/page/${index + 1}`);
1222
1283
  }
1223
1284
  function defaultPath(context) {
@@ -1705,7 +1766,14 @@ function createPersistentContentCache(options) {
1705
1766
  );
1706
1767
  return void 0;
1707
1768
  }
1708
- throw error;
1769
+ logger?.warn(
1770
+ "Persistent content cache entry could not be read and will be ignored.",
1771
+ {
1772
+ key,
1773
+ error: error instanceof Error ? error.message : String(error)
1774
+ }
1775
+ );
1776
+ return void 0;
1709
1777
  }
1710
1778
  },
1711
1779
  async set(key, value) {
@@ -1717,8 +1785,18 @@ function createPersistentContentCache(options) {
1717
1785
  "Persistent content cache values must be JSON serializable."
1718
1786
  );
1719
1787
  }
1720
- await writeAtomically(filePath, versionDir, serialized);
1721
- tracer?.event("persistentContentCache.write", { key });
1788
+ try {
1789
+ await writeAtomically(filePath, versionDir, serialized);
1790
+ tracer?.event("persistentContentCache.write", { key });
1791
+ } catch (error) {
1792
+ logger?.warn(
1793
+ "Persistent content cache entry could not be written and will be ignored.",
1794
+ {
1795
+ key,
1796
+ error: error instanceof Error ? error.message : String(error)
1797
+ }
1798
+ );
1799
+ }
1722
1800
  },
1723
1801
  async clear() {
1724
1802
  try {
@@ -2463,9 +2541,9 @@ function resolveRelativeMarkdownSlug(sourceSlug, targetPath) {
2463
2541
  }
2464
2542
  return normalizedParts.join("/").replace(/\.md$/i, "");
2465
2543
  }
2466
- function decodeUriPath(path5) {
2544
+ function decodeUriPath(path6) {
2467
2545
  try {
2468
- return decodeURI(path5);
2546
+ return decodeURI(path6);
2469
2547
  } catch {
2470
2548
  return null;
2471
2549
  }
@@ -2553,16 +2631,16 @@ var GeneratedOutputRegistry = class {
2553
2631
  outputs = [];
2554
2632
  owners = /* @__PURE__ */ new Map();
2555
2633
  sinkFor(pluginName) {
2556
- const register = (path5, output) => {
2557
- const owner = this.owners.get(path5);
2634
+ const register = (path6, output) => {
2635
+ const owner = this.owners.get(path6);
2558
2636
  if (owner) {
2559
2637
  throw new Error(
2560
- `Duplicate generated output path "${path5}" declared by "${owner}" and "${pluginName}".`
2638
+ `Duplicate generated output path "${path6}" declared by "${owner}" and "${pluginName}".`
2561
2639
  );
2562
2640
  }
2563
- this.owners.set(path5, pluginName);
2641
+ this.owners.set(path6, pluginName);
2564
2642
  this.outputs.push({
2565
- path: path5,
2643
+ path: path6,
2566
2644
  content: output.content,
2567
2645
  dependencies: output.dependencies,
2568
2646
  owner: pluginName
@@ -2586,9 +2664,12 @@ var GeneratedOutputRegistry = class {
2586
2664
 
2587
2665
  // src/plugin/plugin_lifecycle.ts
2588
2666
  var PluginHookError = class extends Error {
2667
+ path;
2589
2668
  constructor(pluginName, hookName, cause) {
2590
2669
  super(`Plugin "${pluginName}" failed during "${hookName}"`, { cause });
2591
2670
  this.name = "PluginHookError";
2671
+ const path6 = cause?.path;
2672
+ if (typeof path6 === "string") this.path = path6;
2592
2673
  }
2593
2674
  };
2594
2675
  async function runPluginHook(plugin, hookName, context, hook) {
@@ -3073,12 +3154,12 @@ function normalizePageTypePath(pathname, pageType) {
3073
3154
  return pageType.directoryIndex ? normalizeDirectoryPagePath(pathname) : normalizePagePath(pathname);
3074
3155
  }
3075
3156
  function normalizeDirectoryPagePath(pathname) {
3076
- const path5 = normalizePagePath(pathname);
3077
- return path5 === "/" ? path5 : `${path5}/`;
3157
+ const path6 = normalizePagePath(pathname);
3158
+ return path6 === "/" ? path6 : `${path6}/`;
3078
3159
  }
3079
3160
  function normalizePagePath(pathname) {
3080
- const path5 = `/${pathname.split("/").filter(Boolean).join("/")}`;
3081
- return path5 === "/" ? path5 : path5.replace(/\/$/, "");
3161
+ const path6 = `/${pathname.split("/").filter(Boolean).join("/")}`;
3162
+ return path6 === "/" ? path6 : path6.replace(/\/$/, "");
3082
3163
  }
3083
3164
  function countSeverity(diagnostics, severity) {
3084
3165
  return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
@@ -3101,6 +3182,14 @@ function uniqueOutputs(outputs) {
3101
3182
  return [...byPath.values()].map(({ output }) => output).sort((left, right) => left.path.localeCompare(right.path));
3102
3183
  }
3103
3184
 
3185
+ // src/utils/error.ts
3186
+ function attachErrorPath(error, path6) {
3187
+ if (error instanceof Error && error.path === void 0) {
3188
+ error.path = path6;
3189
+ }
3190
+ return error;
3191
+ }
3192
+
3104
3193
  // src/content/affected_content.ts
3105
3194
  function determineAffectedContent(changeSet, previousState, currentPaths, currentContentIndex) {
3106
3195
  const changedPaths = [
@@ -3121,9 +3210,9 @@ function determineAffectedContent(changeSet, previousState, currentPaths, curren
3121
3210
  previousState.contentIndex,
3122
3211
  currentContentIndex
3123
3212
  );
3124
- for (const [path5, entry] of Object.entries(previousState.entries)) {
3125
- if (!isMarkdownPath2(path5)) continue;
3126
- const slug = toDependencyId(path5);
3213
+ for (const [path6, entry] of Object.entries(previousState.entries)) {
3214
+ if (!isMarkdownPath2(path6)) continue;
3215
+ const slug = toDependencyId(path6);
3127
3216
  if (direct.has(slug) || dependent.has(slug)) continue;
3128
3217
  if (!entry.linkTargets?.some((target) => changedIndexKeys.has(target))) {
3129
3218
  continue;
@@ -3160,27 +3249,27 @@ function findChangedIndexKeys(previousIndex, currentIndex) {
3160
3249
  return changed;
3161
3250
  }
3162
3251
  function addAllNotes(target, currentPaths, exclude) {
3163
- for (const path5 of currentPaths) {
3164
- if (!isMarkdownPath2(path5)) continue;
3165
- const slug = toDependencyId(path5);
3252
+ for (const path6 of currentPaths) {
3253
+ if (!isMarkdownPath2(path6)) continue;
3254
+ const slug = toDependencyId(path6);
3166
3255
  if (exclude?.has(slug)) continue;
3167
3256
  target.add(slug);
3168
3257
  }
3169
3258
  }
3170
- function isMarkdownPath2(path5) {
3171
- return path5.endsWith(".md");
3259
+ function isMarkdownPath2(path6) {
3260
+ return path6.endsWith(".md");
3172
3261
  }
3173
- function toDependencyId(path5) {
3174
- return path5.replace(/\.md$/, "");
3262
+ function toDependencyId(path6) {
3263
+ return path6.replace(/\.md$/, "");
3175
3264
  }
3176
- function toDependency(path5) {
3177
- return isMarkdownPath2(path5) ? { kind: "content", id: toDependencyId(path5) } : { kind: "file", id: path5.replace(/\\/g, "/") };
3265
+ function toDependency(path6) {
3266
+ return isMarkdownPath2(path6) ? { kind: "content", id: toDependencyId(path6) } : { kind: "file", id: path6.replace(/\\/g, "/") };
3178
3267
  }
3179
3268
  function buildDependentsByDependency(state2) {
3180
3269
  const dependents = /* @__PURE__ */ new Map();
3181
- for (const [path5, entry] of Object.entries(state2.entries)) {
3182
- if (!isMarkdownPath2(path5)) continue;
3183
- const slug = toDependencyId(path5);
3270
+ for (const [path6, entry] of Object.entries(state2.entries)) {
3271
+ if (!isMarkdownPath2(path6)) continue;
3272
+ const slug = toDependencyId(path6);
3184
3273
  for (const dependency of entry.dependencies) {
3185
3274
  const key = dependencyKey2(dependency);
3186
3275
  const values = dependents.get(key) ?? /* @__PURE__ */ new Set();
@@ -3202,18 +3291,18 @@ function diffContentEntries(previous, current) {
3202
3291
  const added = [];
3203
3292
  const changed = [];
3204
3293
  const unchanged = [];
3205
- for (const [path5, fingerprint] of currentFingerprints) {
3206
- const previousEntry = previous.entries[path5];
3294
+ for (const [path6, fingerprint] of currentFingerprints) {
3295
+ const previousEntry = previous.entries[path6];
3207
3296
  if (!previousEntry) {
3208
- added.push(path5);
3297
+ added.push(path6);
3209
3298
  } else if (previousEntry.fingerprint !== fingerprint) {
3210
- changed.push(path5);
3299
+ changed.push(path6);
3211
3300
  } else {
3212
- unchanged.push(path5);
3301
+ unchanged.push(path6);
3213
3302
  }
3214
3303
  }
3215
3304
  const removed = Object.keys(previous.entries).filter(
3216
- (path5) => !currentFingerprints.has(path5)
3305
+ (path6) => !currentFingerprints.has(path6)
3217
3306
  );
3218
3307
  return sortChangeSet({ added, changed, removed, unchanged });
3219
3308
  }
@@ -3225,9 +3314,6 @@ function allContentChanged(entries) {
3225
3314
  unchanged: []
3226
3315
  });
3227
3316
  }
3228
- function hasContentChanges(changeSet) {
3229
- return changeSet.added.length > 0 || changeSet.changed.length > 0 || changeSet.removed.length > 0;
3230
- }
3231
3317
  function sortChangeSet(changeSet) {
3232
3318
  return {
3233
3319
  added: [...changeSet.added].sort(),
@@ -3303,54 +3389,73 @@ var ContentIndexBuilder = class _ContentIndexBuilder {
3303
3389
  }
3304
3390
  source;
3305
3391
  async build(contentEntries, read = (entry) => this.source.read(entry)) {
3306
- const index = /* @__PURE__ */ new Map();
3392
+ const candidates = /* @__PURE__ */ new Map();
3307
3393
  for (const contentEntry of contentEntries) {
3308
- await this.indexContentEntry(index, contentEntry, read);
3394
+ await this.indexContentEntry(candidates, contentEntry, read);
3309
3395
  }
3310
- return index;
3396
+ return resolveContentIndex(candidates);
3311
3397
  }
3312
3398
  static buildFromAliases(contentEntries, aliasesByPath) {
3313
- const index = /* @__PURE__ */ new Map();
3399
+ const candidates = /* @__PURE__ */ new Map();
3314
3400
  for (const contentEntry of contentEntries) {
3315
3401
  _ContentIndexBuilder.indexContentEntryFromAliases(
3316
- index,
3402
+ candidates,
3317
3403
  contentEntry,
3318
3404
  aliasesByPath.get(contentEntry.path) ?? []
3319
3405
  );
3320
3406
  }
3321
- return index;
3407
+ return resolveContentIndex(candidates);
3322
3408
  }
3323
- async indexContentEntry(index, contentEntry, read) {
3409
+ async indexContentEntry(candidates, contentEntry, read) {
3324
3410
  const aliases = contentEntry.path.toLowerCase().endsWith(".md") ? extractFrontmatterAliases(readText(await read(contentEntry))) : [];
3325
3411
  _ContentIndexBuilder.indexContentEntryFromAliases(
3326
- index,
3412
+ candidates,
3327
3413
  contentEntry,
3328
3414
  aliases
3329
3415
  );
3330
3416
  }
3331
- static indexContentEntryFromAliases(index, contentEntry, aliases) {
3417
+ static indexContentEntryFromAliases(candidates, contentEntry, aliases) {
3332
3418
  const contentPath = contentEntry.path;
3333
3419
  const ext = contentPath.split(".").pop()?.toLowerCase() ?? "";
3334
3420
  const value = ext === "md" ? contentPath.replace(/\.md$/, "") : contentPath;
3335
3421
  const parts = value.split("/");
3336
3422
  for (let i = parts.length - 1; i >= 0; i--) {
3337
3423
  const rawSuffix = parts.slice(i).join("/");
3338
- addIndexEntry(index, rawSuffix, value);
3424
+ addCandidate(candidates, rawSuffix, value);
3339
3425
  if (ext !== "md") {
3340
- addIndexEntry(index, rawSuffix.replace(/\.[^/.]+$/, ""), value);
3426
+ addCandidate(candidates, rawSuffix.replace(/\.[^/.]+$/, ""), value);
3341
3427
  }
3342
3428
  }
3343
3429
  if (ext === "md") {
3344
- for (const alias of aliases) addIndexEntry(index, alias, value);
3430
+ for (const alias of aliases) addCandidate(candidates, alias, value);
3345
3431
  }
3346
3432
  }
3347
3433
  };
3434
+ function resolveContentIndex(candidates) {
3435
+ const index = /* @__PURE__ */ new Map();
3436
+ const ambiguities = /* @__PURE__ */ new Map();
3437
+ for (const [key, values] of candidates) {
3438
+ const list = [...values].sort(compareCandidates);
3439
+ const [only] = list;
3440
+ if (list.length === 1 && only !== void 0) {
3441
+ index.set(key, only);
3442
+ continue;
3443
+ }
3444
+ ambiguities.set(key, list);
3445
+ }
3446
+ return { index, ambiguities };
3447
+ }
3448
+ function compareCandidates(left, right) {
3449
+ return left < right ? -1 : left > right ? 1 : 0;
3450
+ }
3348
3451
  function readText(content) {
3349
3452
  return typeof content === "string" ? content : new TextDecoder().decode(content);
3350
3453
  }
3351
- function addIndexEntry(index, key, value) {
3454
+ function addCandidate(candidates, key, value) {
3352
3455
  const normalizedKey = key.toLowerCase();
3353
- if (!index.has(normalizedKey)) index.set(normalizedKey, value);
3456
+ const values = candidates.get(normalizedKey) ?? /* @__PURE__ */ new Set();
3457
+ values.add(value);
3458
+ candidates.set(normalizedKey, values);
3354
3459
  }
3355
3460
 
3356
3461
  // src/content/content_build_coordinator.ts
@@ -3433,7 +3538,10 @@ var ContentBuildCoordinator = class {
3433
3538
  previousState,
3434
3539
  changeSet
3435
3540
  );
3436
- const currentContentIndex = await this.dependencies.observability.tracer.span(
3541
+ const {
3542
+ index: currentContentIndex,
3543
+ ambiguities: currentContentIndexAmbiguities
3544
+ } = await this.dependencies.observability.tracer.span(
3437
3545
  "content.index",
3438
3546
  {},
3439
3547
  () => ContentIndexBuilder.buildFromAliases(
@@ -3471,6 +3579,7 @@ var ContentBuildCoordinator = class {
3471
3579
  currentEntries,
3472
3580
  currentContentAliases,
3473
3581
  currentContentIndex,
3582
+ currentContentIndexAmbiguities,
3474
3583
  changeSet,
3475
3584
  affectedContent: affected
3476
3585
  };
@@ -3498,8 +3607,8 @@ var ContentBuildCoordinator = class {
3498
3607
  function readText2(content) {
3499
3608
  return typeof content === "string" ? content : new TextDecoder().decode(content);
3500
3609
  }
3501
- function toSlug(path5) {
3502
- return path5.replace(/\.md$/, "");
3610
+ function toSlug(path6) {
3611
+ return path6.replace(/\.md$/, "");
3503
3612
  }
3504
3613
  function collectDependencies2(manifestEntry, trackedDependencies) {
3505
3614
  if (!manifestEntry) return [];
@@ -3588,9 +3697,14 @@ var ContentEntryReader = class {
3588
3697
  if (cached) return cached;
3589
3698
  const content = this.source.read(entry).then(
3590
3699
  (value) => typeof value === "string" ? value : new TextDecoder().decode(value)
3591
- ).finally(() => this.texts.delete(entry.path));
3592
- this.texts.set(entry.path, content);
3593
- return content;
3700
+ );
3701
+ const retain = entry.path.endsWith(".md");
3702
+ const tracked = retain ? content : content.finally(() => this.texts.delete(entry.path));
3703
+ this.texts.set(entry.path, tracked);
3704
+ return tracked;
3705
+ }
3706
+ clearReadCache() {
3707
+ this.texts.clear();
3594
3708
  }
3595
3709
  };
3596
3710
 
@@ -3682,8 +3796,8 @@ var ContentLocationResolver = class {
3682
3796
  }
3683
3797
  }
3684
3798
  };
3685
- function toSlug2(path5) {
3686
- return path5.replace(/\.md$/, "");
3799
+ function toSlug2(path6) {
3800
+ return path6.replace(/\.md$/, "");
3687
3801
  }
3688
3802
  async function mapConcurrent2(values, concurrency, map) {
3689
3803
  const results = new Array(values.length);
@@ -3881,7 +3995,7 @@ var ManifestBuilder = class {
3881
3995
  assets: uniqueAssets(assets)
3882
3996
  };
3883
3997
  }
3884
- build(entries, contentIndex) {
3998
+ build(entries, contentIndex, contentIndexAmbiguities = /* @__PURE__ */ new Map()) {
3885
3999
  const bySlug = new Map(entries.map((entry) => [entry.slug, entry]));
3886
4000
  const byContentId = createContentIdIndex(entries);
3887
4001
  const byAlias = createAliasIndex(entries);
@@ -3922,6 +4036,7 @@ var ManifestBuilder = class {
3922
4036
  outgoingLinks,
3923
4037
  incomingLinks,
3924
4038
  contentIndex,
4039
+ contentIndexAmbiguities,
3925
4040
  assets: [],
3926
4041
  clientEntries: [],
3927
4042
  diagnostics: [],
@@ -4038,10 +4153,10 @@ function buildOutputInventory(manifest, pluginPageOutputs = [], contentOutputDep
4038
4153
  for (const entry of manifest.publicEntries) {
4039
4154
  addOutput(outputs, contentOutput(entry, contentOutputDependencies));
4040
4155
  }
4041
- for (const [path5, redirect] of manifest.publicRedirects) {
4156
+ for (const [path6, redirect] of manifest.publicRedirects) {
4042
4157
  addOutput(outputs, {
4043
4158
  kind: "redirect",
4044
- path: htmlOutputPath(path5),
4159
+ path: htmlOutputPath(path6),
4045
4160
  producer: `content:${redirect.slug}:redirect`,
4046
4161
  dependencies: [{ type: "content", slug: redirect.slug }]
4047
4162
  });
@@ -4170,79 +4285,19 @@ function assertNoGeneratedOutputCollision(existing, incoming) {
4170
4285
  );
4171
4286
  }
4172
4287
  function normalizePublicPath(pathname) {
4173
- const path5 = `/${pathname.split("/").filter(Boolean).join("/")}`;
4174
- return path5 === "/" ? path5 : path5.replace(/\/$/, "");
4288
+ const path6 = `/${pathname.split("/").filter(Boolean).join("/")}`;
4289
+ return path6 === "/" ? path6 : path6.replace(/\/$/, "");
4175
4290
  }
4176
- function isMarkdownPath3(path5) {
4177
- return path5.endsWith(".md");
4291
+ function isMarkdownPath3(path6) {
4292
+ return path6.endsWith(".md");
4178
4293
  }
4179
- function toSlug3(path5) {
4180
- return path5.replace(/\.md$/, "");
4294
+ function toSlug3(path6) {
4295
+ return path6.replace(/\.md$/, "");
4181
4296
  }
4182
4297
  function compareOutput(left, right) {
4183
4298
  return left.path.localeCompare(right.path) || left.kind.localeCompare(right.kind);
4184
4299
  }
4185
4300
 
4186
- // src/content/publishing.ts
4187
- function resolvePublishingState(frontmatter, options) {
4188
- const explicitVisibility = resolveExplicitVisibility(frontmatter?.visibility);
4189
- const publishAt = resolvePublishAt(frontmatter?.publishAt);
4190
- if (explicitVisibility === "draft")
4191
- return state("draft", false, false, publishAt);
4192
- if (publishAt && publishAt.getTime() > options.buildTime.getTime()) {
4193
- return state("scheduled", false, false, publishAt);
4194
- }
4195
- if (explicitVisibility === "unlisted") {
4196
- return state("unlisted", true, false, publishAt);
4197
- }
4198
- if (explicitVisibility === "public" || publishAt) {
4199
- return state("public", true, true, publishAt);
4200
- }
4201
- const routable = isPublishable(options.strategy, frontmatter);
4202
- return state(routable ? "public" : "draft", routable, routable, publishAt);
4203
- }
4204
- function resolvePublishingBuildTime(input) {
4205
- if (input === void 0) return /* @__PURE__ */ new Date();
4206
- if (input instanceof Date) {
4207
- if (Number.isNaN(input.getTime()))
4208
- throw new Error("Invalid publishing build time.");
4209
- return new Date(input.getTime());
4210
- }
4211
- const parsed = new Date(input);
4212
- if (Number.isNaN(parsed.getTime()))
4213
- throw new Error("Invalid publishing build time.");
4214
- return parsed;
4215
- }
4216
- function resolveExplicitVisibility(value) {
4217
- if (value === void 0) return void 0;
4218
- if (value === "public" || value === "unlisted" || value === "draft")
4219
- return value;
4220
- throw new Error(
4221
- `Invalid content visibility "${String(value)}". Expected public, unlisted, or draft.`
4222
- );
4223
- }
4224
- function resolvePublishAt(value) {
4225
- if (value === void 0) return void 0;
4226
- if (!(typeof value === "string" || value instanceof Date)) {
4227
- throw new Error("Invalid publishAt. Expected an ISO 8601 date string.");
4228
- }
4229
- const parsed = value instanceof Date ? value : new Date(value);
4230
- if (Number.isNaN(parsed.getTime())) {
4231
- throw new Error(
4232
- `Invalid publishAt "${String(value)}". Expected an ISO 8601 date string.`
4233
- );
4234
- }
4235
- return new Date(parsed.getTime());
4236
- }
4237
- function state(visibility, routable, discoverable, publishAt) {
4238
- return {
4239
- visibility,
4240
- routable,
4241
- discoverable,
4242
- ...publishAt ? { publishAt } : {}
4243
- };
4244
- }
4245
-
4246
4301
  // src/content/content_manager.ts
4247
4302
  var CONTENT_PROCESSING_CONCURRENCY = 16;
4248
4303
  var ContentManager = class {
@@ -4300,6 +4355,7 @@ var ContentManager = class {
4300
4355
  manifestBuilder = new ManifestBuilder();
4301
4356
  pluginRuntime;
4302
4357
  contentIndex = null;
4358
+ contentIndexAmbiguities = /* @__PURE__ */ new Map();
4303
4359
  contentIndexPromise = null;
4304
4360
  contentCache = /* @__PURE__ */ new Map();
4305
4361
  manifest = null;
@@ -4328,15 +4384,10 @@ var ContentManager = class {
4328
4384
  async getContentIndex(preparation) {
4329
4385
  if (this.contentIndex) return this.contentIndex;
4330
4386
  if (!preparation && this.contentIndexPromise)
4331
- return await this.contentIndexPromise;
4332
- if (preparation?.previousState && !hasContentChanges(preparation.changeSet)) {
4333
- this.contentIndex = new Map(
4334
- Object.entries(preparation.previousState.contentIndex)
4335
- );
4336
- return this.contentIndex;
4337
- }
4387
+ return (await this.contentIndexPromise).index;
4338
4388
  if (preparation) {
4339
4389
  this.contentIndex = preparation.currentContentIndex;
4390
+ this.contentIndexAmbiguities = preparation.currentContentIndexAmbiguities;
4340
4391
  return this.contentIndex;
4341
4392
  }
4342
4393
  const promise = this.observability().tracer.span(
@@ -4349,7 +4400,9 @@ var ContentManager = class {
4349
4400
  );
4350
4401
  if (!preparation) this.contentIndexPromise = promise;
4351
4402
  try {
4352
- this.contentIndex = await promise;
4403
+ const built = await promise;
4404
+ this.contentIndex = built.index;
4405
+ this.contentIndexAmbiguities = built.ambiguities;
4353
4406
  return this.contentIndex;
4354
4407
  } finally {
4355
4408
  if (!preparation) this.contentIndexPromise = null;
@@ -4364,48 +4417,55 @@ var ContentManager = class {
4364
4417
  contentPath: `${slug}.md`
4365
4418
  },
4366
4419
  async () => {
4367
- const [contentIndex, rawPost] = await Promise.all([
4368
- this.getContentIndex(),
4369
- this.getPost(slug)
4370
- ]);
4371
- await this.pluginRuntime.startBuild(contentIndex);
4372
- await this.pluginRuntime.runContentLoaded(slug, rawPost, contentIndex);
4373
- await this.ensureRoutableSlugs();
4374
- this.pipeline ??= new Pipeline(
4375
- contentIndex,
4376
- await this.locationResolver.getPermalinks(),
4377
- (postSlug) => this.getPost(postSlug),
4378
- this.pipelineOptions,
4379
- this.isBuildTime
4380
- );
4381
- const content = await this.pipeline.execute(rawPost, {
4382
- sourceSlug: slug
4383
- });
4384
- this.processedContentCount += 1;
4385
- if (this.processedContentCount % 100 === 0) {
4386
- this.observability().tracer.event("content.process.sample", {
4387
- processed: this.processedContentCount
4388
- });
4420
+ try {
4421
+ return await this.processContent(slug);
4422
+ } catch (error) {
4423
+ throw attachErrorPath(error, `${slug}.md`);
4389
4424
  }
4390
- await this.pluginRuntime.runPostHook(
4391
- "onPostParsed",
4392
- slug,
4393
- rawPost,
4394
- content,
4395
- contentIndex
4396
- );
4397
- await this.pluginRuntime.runPostHook(
4398
- "onPostProcessed",
4399
- slug,
4400
- rawPost,
4401
- content,
4402
- contentIndex
4403
- );
4404
- this.contentCache.set(slug, content);
4405
- return content;
4406
4425
  }
4407
4426
  );
4408
4427
  }
4428
+ async processContent(slug) {
4429
+ const [contentIndex, rawPost] = await Promise.all([
4430
+ this.getContentIndex(),
4431
+ this.getPost(slug)
4432
+ ]);
4433
+ await this.pluginRuntime.startBuild(contentIndex);
4434
+ await this.pluginRuntime.runContentLoaded(slug, rawPost, contentIndex);
4435
+ await this.ensureRoutableSlugs();
4436
+ this.pipeline ??= new Pipeline(
4437
+ contentIndex,
4438
+ await this.locationResolver.getPermalinks(),
4439
+ (postSlug) => this.getPost(postSlug),
4440
+ this.pipelineOptions,
4441
+ this.isBuildTime
4442
+ );
4443
+ const content = await this.pipeline.execute(rawPost, {
4444
+ sourceSlug: slug
4445
+ });
4446
+ this.processedContentCount += 1;
4447
+ if (this.processedContentCount % 100 === 0) {
4448
+ this.observability().tracer.event("content.process.sample", {
4449
+ processed: this.processedContentCount
4450
+ });
4451
+ }
4452
+ await this.pluginRuntime.runPostHook(
4453
+ "onPostParsed",
4454
+ slug,
4455
+ rawPost,
4456
+ content,
4457
+ contentIndex
4458
+ );
4459
+ await this.pluginRuntime.runPostHook(
4460
+ "onPostProcessed",
4461
+ slug,
4462
+ rawPost,
4463
+ content,
4464
+ contentIndex
4465
+ );
4466
+ this.contentCache.set(slug, content);
4467
+ return content;
4468
+ }
4409
4469
  async getManifest(options) {
4410
4470
  if (this.manifest) return this.manifest;
4411
4471
  if (this.manifestPromise) return await this.manifestPromise;
@@ -4471,7 +4531,11 @@ var ContentManager = class {
4471
4531
  const manifest = await this.observability().tracer.span(
4472
4532
  "content.graph",
4473
4533
  {},
4474
- () => this.manifestBuilder.build(entries, contentIndex)
4534
+ () => this.manifestBuilder.build(
4535
+ entries,
4536
+ contentIndex,
4537
+ this.contentIndexAmbiguities
4538
+ )
4475
4539
  );
4476
4540
  const cacheManifestEntries = structuredClone(manifest.entries);
4477
4541
  this.locationResolver.populateRedirects(manifest, locations);
@@ -4608,6 +4672,7 @@ var ContentManager = class {
4608
4672
  return { entries, contentIndex, diagnostics };
4609
4673
  }
4610
4674
  async dispose() {
4675
+ this.entryReader.clearReadCache();
4611
4676
  if (!this.contentIndex) return;
4612
4677
  await this.pluginRuntime.dispose(this.contentIndex);
4613
4678
  }
@@ -4707,7 +4772,13 @@ var ContentManager = class {
4707
4772
  const routableSlugs = /* @__PURE__ */ new Set();
4708
4773
  await mapConcurrent3(posts, CONTENT_PROCESSING_CONCURRENCY, async (post) => {
4709
4774
  const markdown = await this.getPost(post.slug);
4710
- const publishing = resolvePublishingState(readFrontmatter(markdown), {
4775
+ let frontmatter;
4776
+ try {
4777
+ frontmatter = readFrontmatter(markdown);
4778
+ } catch (error) {
4779
+ throw attachErrorPath(error, `${post.slug}.md`);
4780
+ }
4781
+ const publishing = resolvePublishingState(frontmatter, {
4711
4782
  strategy,
4712
4783
  buildTime: this.publishingBuildTime
4713
4784
  });
@@ -4797,7 +4868,12 @@ function resolveFolderLocation(manifest, folder) {
4797
4868
  if (candidate) return { type: "content", entry: candidate.entry };
4798
4869
  }
4799
4870
  if (candidates.length > 1) return { type: "ambiguous", candidates };
4800
- const location = manifest.folderLocations.get(normalizeFolder2(folder));
4871
+ const normalizedFolder = normalizeFolder2(folder);
4872
+ const direct = manifest.folderLocations.get(normalizedFolder);
4873
+ if (direct) return { type: "generated", pathname: direct.pathname };
4874
+ const location = [...manifest.folderLocations.values()].find(
4875
+ (candidate) => candidate.folder === normalizedFolder
4876
+ );
4801
4877
  return location ? { type: "generated", pathname: location.pathname } : { type: "none" };
4802
4878
  }
4803
4879
  function resolvePublicFolderLocation(manifest, pathname) {
@@ -4811,12 +4887,15 @@ function resolvePublicFolderLocation(manifest, pathname) {
4811
4887
  );
4812
4888
  return location ? { type: "generated", pathname: location.pathname } : { type: "none" };
4813
4889
  }
4814
- function resolveGeneratedFolderLocation(manifest, folder) {
4890
+ function resolveGeneratedFolderLocation(manifest, folder, language) {
4815
4891
  const normalizedFolder = normalizeFolder2(folder);
4816
4892
  if (!normalizedFolder) return null;
4817
4893
  const candidates = /* @__PURE__ */ new Set();
4818
4894
  const prefix = `${normalizedFolder}/`;
4819
4895
  for (const entry of manifest.publicEntries) {
4896
+ if (language !== void 0 && entry.publicLocation.language !== language) {
4897
+ continue;
4898
+ }
4820
4899
  if (!entry.slug.startsWith(prefix)) continue;
4821
4900
  const remainder = entry.slug.slice(prefix.length).split("/").filter(Boolean);
4822
4901
  const pathname = parentPath(
@@ -5031,7 +5110,7 @@ function clampFinite(value, min, max) {
5031
5110
  // src/content/read_only_content_graph.ts
5032
5111
  async function readOnlyContentGraph(source, locations) {
5033
5112
  const entries = await source.scan();
5034
- const contentIndex = await new ContentIndexBuilder(source).build(entries);
5113
+ const { index: contentIndex, ambiguities: contentIndexAmbiguities } = await new ContentIndexBuilder(source).build(entries);
5035
5114
  const markdownEntries = entries.filter((entry) => entry.path.endsWith(".md")).toSorted((left, right) => left.path.localeCompare(right.path));
5036
5115
  const markdownContents = await Promise.all(
5037
5116
  markdownEntries.map(async (entry) => ({
@@ -5042,7 +5121,11 @@ async function readOnlyContentGraph(source, locations) {
5042
5121
  const graphEntries = markdownContents.map(
5043
5122
  ({ entry, markdown }) => createGraphEntry(entry, markdown, contentIndex, locations)
5044
5123
  );
5045
- return new ManifestBuilder().build(graphEntries, contentIndex).graph;
5124
+ return new ManifestBuilder().build(
5125
+ graphEntries,
5126
+ contentIndex,
5127
+ contentIndexAmbiguities
5128
+ ).graph;
5046
5129
  }
5047
5130
  function createGraphEntry(entry, markdown, contentIndex, locations) {
5048
5131
  const slug = entry.path.replace(/\.md$/, "");
@@ -5076,7 +5159,26 @@ async function readText3(source, entry) {
5076
5159
  return typeof content === "string" ? content : new TextDecoder().decode(content);
5077
5160
  }
5078
5161
 
5162
+ // src/project/project_layout.ts
5163
+ import path5 from "node:path";
5164
+ function resolveManagedStateRoot(config) {
5165
+ const directory = config?.buildDirectory;
5166
+ return directory ? path5.resolve(directory) : void 0;
5167
+ }
5168
+ function resolveBuildOutputDirectory(config) {
5169
+ const directory = config?.outputDirectory;
5170
+ return directory ? path5.resolve(directory) : void 0;
5171
+ }
5172
+
5079
5173
  // src/types/content_manifest.ts
5174
+ var ARTICLE_SLOT = {
5175
+ header: "article.header",
5176
+ metadata: "article.metadata",
5177
+ aside: "article.aside",
5178
+ beforeContent: "article.before-content",
5179
+ afterContent: "article.after-content",
5180
+ footer: "article.footer"
5181
+ };
5080
5182
  function appendContentBodySlot(entry, slot, html) {
5081
5183
  if (!html.trim()) return;
5082
5184
  const previous = entry.bodySlots?.[slot];
@@ -5088,12 +5190,12 @@ ${html}` : html
5088
5190
  }
5089
5191
 
5090
5192
  // src/types/plugin_endpoint.ts
5091
- function defineEndpoint(path5, handler, options = {}) {
5193
+ function defineEndpoint(path6, handler, options = {}) {
5092
5194
  if (options.cacheControl === void 0) {
5093
- return { path: path5, handler };
5195
+ return { path: path6, handler };
5094
5196
  }
5095
5197
  return {
5096
- path: path5,
5198
+ path: path6,
5097
5199
  handler: async (context) => {
5098
5200
  const response = await handler(context);
5099
5201
  const headers = { ...response.headers };
@@ -5128,6 +5230,7 @@ function calculateReadingTime(html) {
5128
5230
  return Math.max(1, Math.ceil(cjkCharacters / 500 + latinWords / 220));
5129
5231
  }
5130
5232
  export {
5233
+ ARTICLE_SLOT,
5131
5234
  ATTACHMENTS_BASE_PATH,
5132
5235
  CompositeTraceSink,
5133
5236
  ConfigValidationError,
@@ -5142,6 +5245,7 @@ export {
5142
5245
  PluginDependencyError,
5143
5246
  SinkTracer,
5144
5247
  appendContentBodySlot,
5248
+ attachErrorPath,
5145
5249
  attachmentUrl,
5146
5250
  buildContentCollections,
5147
5251
  buildGraphEdges,
@@ -5193,6 +5297,7 @@ export {
5193
5297
  readContentBuildStateStatus,
5194
5298
  readContentSourceEntry,
5195
5299
  readOnlyContentGraph,
5300
+ resolveBuildOutputDirectory,
5196
5301
  resolveConfig,
5197
5302
  resolveConfigModule,
5198
5303
  resolveContentBuildStatePath,
@@ -5202,6 +5307,7 @@ export {
5202
5307
  resolveFolderEntry,
5203
5308
  resolveFolderLocation,
5204
5309
  resolveGeneratedFolderLocation,
5310
+ resolveManagedStateRoot,
5205
5311
  resolvePlugins,
5206
5312
  resolvePublicFolderLocation,
5207
5313
  resolvePublishingBuildTime,