@riebeckite/core 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Plugins and themes are plain objects created by `definePlugin` and `defineTheme`
19
19
  ## Installation
20
20
 
21
21
  ```sh
22
- npm install @riebeckite/core
22
+ pnpm add @riebeckite/core
23
23
  ```
24
24
 
25
25
  Core is also installed transitively by `@riebeckite/honox` and by the
package/README_ja.md CHANGED
@@ -13,7 +13,7 @@ Riebeckite の移植可能なフレームワーク契約です。設定、コン
13
13
  ## インストール
14
14
 
15
15
  ```sh
16
- npm install @riebeckite/core
16
+ pnpm add @riebeckite/core
17
17
  ```
18
18
 
19
19
  `@riebeckite/honox`、`@riebeckite/plugin-*`、`@riebeckite/theme-*` をインストールすると、依存として一緒に入ります。
package/dist/index.d.ts CHANGED
@@ -4,61 +4,60 @@ export { ATTACHMENTS_BASE_PATH, attachmentUrl, getExtension, isAttachmentPath, i
4
4
  export type { ContentBuildState, FingerprintedContentEntry, } from "./src/content/content_build_state.js";
5
5
  export type { ContentBuildStateInvalidReason, ContentBuildStateStatus, } from "./src/content/content_build_state_store.js";
6
6
  export { loadContentBuildState, readContentBuildStateStatus, resolveContentBuildStatePath, } from "./src/content/content_build_state_store.js";
7
- export { fingerprintContentEntries } from "./src/content/content_fingerprint.js";
8
7
  export type { ContentCollection, ContentCollectionContext, ContentCollectionDefinition, ContentCollectionPage, } from "./src/content/content_collection.js";
9
8
  export { buildContentCollections } from "./src/content/content_collection.js";
10
- export type { ContentQueryDateFilter, ContentQueryDateGranularity, ContentQueryFilter, ContentQueryFrontmatterFilter, ContentQueryGroup, ContentQueryGroupBy, ContentQueryGroupOptions, ContentQueryPage, ContentQueryPagination, ContentQueryScalar, ContentQuerySort, ContentQuerySortOrder, ContentQuerySpec, ContentQueryTagFilter, } from "./src/content/content_query.js";
11
- export { groupContentEntries, queryContentEntries, queryContentPage, resolveContentQueryPagination, } from "./src/content/content_query.js";
9
+ export { fingerprintContentEntries } from "./src/content/content_fingerprint.js";
12
10
  export type { ContentGraph, ContentGraphNeighbors, } from "./src/content/content_graph.js";
13
11
  export { createContentGraph } from "./src/content/content_graph.js";
14
- export { buildGraphEdges, layoutRadialGraph, } from "./src/content/graph_layout.js";
15
- export type { GraphEdge, GraphLayoutNode, LinkableGraphNode, RadialGraphLayoutOptions, } from "./src/content/graph_layout.js";
16
12
  export { resolveDefaultContentLocation } from "./src/content/content_location.js";
17
13
  export type { ContentBuildOptions, ContentInspection, } from "./src/content/content_manager.js";
18
14
  export { ContentManager } from "./src/content/content_manager.js";
19
15
  export { extractFrontmatterAliases } from "./src/content/content_metadata.js";
16
+ export type { ContentQueryDateFilter, ContentQueryDateGranularity, ContentQueryFilter, ContentQueryFrontmatterFilter, ContentQueryGroup, ContentQueryGroupBy, ContentQueryGroupOptions, ContentQueryPage, ContentQueryPagination, ContentQueryScalar, ContentQuerySort, ContentQuerySortOrder, ContentQuerySpec, ContentQueryTagFilter, } from "./src/content/content_query.js";
17
+ export { groupContentEntries, queryContentEntries, queryContentPage, resolveContentQueryPagination, } from "./src/content/content_query.js";
20
18
  export type { ContentSource, ContentSourceContent, ContentSourceEntry, ContentSourceMetadata, } from "./src/content/content_source.js";
21
19
  export { getContentSourceEntry, readContentSourceEntry, } from "./src/content/content_source.js";
22
20
  export { resolveContentStableId } from "./src/content/content_stable_id.js";
23
21
  export { FileSystemContentSource } from "./src/content/file_system_content_source.js";
22
+ export type { GraphEdge, GraphLayoutNode, LinkableGraphNode, RadialGraphLayoutOptions, } from "./src/content/graph_layout.js";
23
+ export { buildGraphEdges, layoutRadialGraph, } from "./src/content/graph_layout.js";
24
24
  export { IMAGE_EXTENSIONS } from "./src/content/image_extensions.js";
25
25
  export { readOnlyContentGraph } from "./src/content/read_only_content_graph.js";
26
- export { uniqueStrings } from "./src/utils/collections.js";
27
- export { escapeHtml, escapeHtmlAttribute } from "./src/utils/html.js";
28
- export { normalizeTag } from "./src/utils/tags.js";
29
- export { calculateReadingTime, stripHtml } from "./src/utils/text.js";
30
26
  export type { LogContext, Logger, LogLevel, Observability, ObservabilityValue, TraceAttributes, TraceEvent, Tracer, TraceSink, TraceSpan, } from "./src/observability.js";
31
27
  export { CompositeTraceSink, ConsoleLogger, NoopLogger, NoopTracer, SinkTracer, } from "./src/observability.js";
32
28
  export type { PipelineOptions } from "./src/pipeline.js";
33
29
  export { Pipeline } from "./src/pipeline.js";
34
- export type { JsonValue } from "./src/types/json_value.js";
35
30
  export type { PluginCache } from "./src/plugin/plugin_cache.js";
31
+ export { PluginDependencyError, type PluginDependencyErrorKind, } from "./src/plugin/plugin_dependency_error.js";
36
32
  export type { CreatePluginMemoOptions, PluginMemo, } from "./src/plugin/plugin_memo.js";
37
33
  export { createPluginMemo, stableStringify, } from "./src/plugin/plugin_memo.js";
38
- export { PluginDependencyError, type PluginDependencyErrorKind, } from "./src/plugin/plugin_dependency_error.js";
39
34
  export type { ConfigValidationIssue, PluginOptionsValidator, } from "./src/types/config_validation.js";
40
35
  export type { ContentAsset, ContentBodySlot, ContentLink, ContentLinkKind, ContentLocationInput, ContentManifest, ContentManifestEntry, ContentManifestPluginClientEntry, ContentPublicLocation, ContentRedirect, } from "./src/types/content_manifest.js";
41
36
  export { appendContentBodySlot } from "./src/types/content_manifest.js";
42
37
  export type { Diagnostic, DiagnosticCode, DiagnosticSeverity, } from "./src/types/diagnostic.js";
43
38
  export type { GeneratedOutput, GeneratedOutputContent, GeneratedOutputInput, GeneratedOutputSink, } from "./src/types/generated_output.js";
44
39
  export { createUnavailableGeneratedOutputSink, normalizeGeneratedOutputPath, } from "./src/types/generated_output.js";
40
+ export type { JsonValue } from "./src/types/json_value.js";
45
41
  export type { PluginInput, ResolvedPluginMetadata, RiebeckitePlugin, } from "./src/types/plugin.js";
46
42
  export { definePlugin, getResolvedPluginMetadata, resolvePlugins, } from "./src/types/plugin.js";
47
43
  export type { PluginAsset, PluginAssetKind, PluginClientEntry, } from "./src/types/plugin_asset.js";
48
44
  export { createClientEntry, createStyleAsset, serializePublicClientConfig, } from "./src/types/plugin_asset.js";
49
45
  export type { PluginContentContext, PluginContentLocationAugmentContext, PluginContentLocationContext, PluginContentLocationResolver, PluginContentRenderer, PluginContext, PluginGeneratedHtml, PluginGeneratedHtmlInspector, PluginGraphContext, PluginLifecycleContext, PluginManifestContext, PluginPostContext, PluginRenderContext, PluginRenderInput, PluginRenderTarget, } from "./src/types/plugin_context.js";
50
46
  export type { PluginDiagnostic, PluginDiagnosticLevel, } from "./src/types/plugin_diagnostic.js";
51
- export type { PluginHeadTag } from "./src/types/plugin_head.js";
52
- export type { PluginEndpoint, PluginEndpointContext, PluginEndpointMethod, PluginEndpointResponse, PluginEndpointOptions, } from "./src/types/plugin_endpoint.js";
47
+ export type { PluginEndpoint, PluginEndpointContext, PluginEndpointMethod, PluginEndpointOptions, PluginEndpointRequest, PluginEndpointResponse, } from "./src/types/plugin_endpoint.js";
53
48
  export { defineEndpoint } from "./src/types/plugin_endpoint.js";
49
+ export type { PluginHeadTag } from "./src/types/plugin_head.js";
54
50
  export type { HtmlPipeline, MarkdownEmbedFragment, MarkdownPipeline, MarkdownPipelineContext, PipelinePlugin, } from "./src/types/plugin_pipeline.js";
55
51
  export type { PluginSeoExtension, RenderableFeedEntry, SeoMetadata, WebsiteSeoInput, } from "./src/types/plugin_seo.js";
56
52
  export type { PostContent, PostFrontmatter } from "./src/types/post_content.js";
57
- export type { PublishStrategy } from "./src/types/publish_strategy.js";
58
- export type { PublishFrontmatter } from "./src/types/publish_strategy.js";
53
+ export type { PublishFrontmatter, PublishStrategy, } from "./src/types/publish_strategy.js";
59
54
  export { isPublishable } from "./src/types/publish_strategy.js";
60
55
  export type { ResolvedRiebeckiteConfig } from "./src/types/resolved_riebeckite_config.js";
61
56
  export type { RiebeckiteConfig } from "./src/types/riebeckite_config.js";
62
57
  export type { SiteConfig } from "./src/types/site_config.js";
63
58
  export type { RiebeckiteTheme, ThemeArticleLayoutPreset, ThemeAttributes, ThemeColorMode, ThemeConfig, ThemeDesignTokens, ThemeInput, ThemeStyle, ThemeTypographyPreset, } from "./src/types/theme_config.js";
64
59
  export { defineTheme } from "./src/types/theme_config.js";
60
+ export { uniqueStrings } from "./src/utils/collections.js";
61
+ export { escapeHtml, escapeHtmlAttribute, escapeScriptJson, } from "./src/utils/html.js";
62
+ export { normalizeTag } from "./src/utils/tags.js";
63
+ export { calculateReadingTime, stripHtml } from "./src/utils/text.js";
package/dist/index.js CHANGED
@@ -382,16 +382,18 @@ function collectProviders(plugins) {
382
382
  function collectDependencies(plugins, providers) {
383
383
  const availableCapabilities = [...providers.keys()];
384
384
  return plugins.map((plugin, pluginIndex) => {
385
- const requiredDependencies = (plugin.requires ?? []).map((rawCapability) => {
386
- const capability = normalize(rawCapability);
387
- return resolveDependency({
388
- pluginIndex,
389
- pluginName: plugin.name,
390
- capability,
391
- availableCapabilities,
392
- providers
393
- });
394
- });
385
+ const requiredDependencies = (plugin.requires ?? []).map(
386
+ (rawCapability) => {
387
+ const capability = normalize(rawCapability);
388
+ return resolveDependency({
389
+ pluginIndex,
390
+ pluginName: plugin.name,
391
+ capability,
392
+ availableCapabilities,
393
+ providers
394
+ });
395
+ }
396
+ );
395
397
  const optionalDependencies = (plugin.optional ?? []).flatMap(
396
398
  (rawCapability) => {
397
399
  const capability = normalize(rawCapability);
@@ -824,23 +826,6 @@ function isNotFoundError(error) {
824
826
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
825
827
  }
826
828
 
827
- // src/content/content_fingerprint.ts
828
- import { createHash } from "node:crypto";
829
- async function fingerprintContentEntries(entries, read) {
830
- return await Promise.all(
831
- [...entries].sort((left, right) => left.path.localeCompare(right.path)).map(async (entry) => ({
832
- entry,
833
- fingerprint: await fingerprintContentEntry(entry, read)
834
- }))
835
- );
836
- }
837
- async function fingerprintContentEntry(entry, read) {
838
- if (entry.metadata?.hash) return `hash:${entry.metadata.hash}`;
839
- if (entry.metadata?.etag) return `etag:${entry.metadata.etag}`;
840
- const content = await read(entry);
841
- return `sha256:${createHash("sha256").update(typeof content === "string" ? content : content).digest("hex")}`;
842
- }
843
-
844
829
  // src/content/content_query.ts
845
830
  function queryContentEntries(entries, spec = {}) {
846
831
  const filter = spec.filter ?? {};
@@ -1172,6 +1157,23 @@ function normalizePath(value) {
1172
1157
  return absolute.replace(/\/{2,}/g, "/").replace(/\/+$/, "") || "/";
1173
1158
  }
1174
1159
 
1160
+ // src/content/content_fingerprint.ts
1161
+ import { createHash } from "node:crypto";
1162
+ async function fingerprintContentEntries(entries, read) {
1163
+ return await Promise.all(
1164
+ [...entries].sort((left, right) => left.path.localeCompare(right.path)).map(async (entry) => ({
1165
+ entry,
1166
+ fingerprint: await fingerprintContentEntry(entry, read)
1167
+ }))
1168
+ );
1169
+ }
1170
+ async function fingerprintContentEntry(entry, read) {
1171
+ if (entry.metadata?.hash) return `hash:${entry.metadata.hash}`;
1172
+ if (entry.metadata?.etag) return `etag:${entry.metadata.etag}`;
1173
+ const content = await read(entry);
1174
+ return `sha256:${createHash("sha256").update(typeof content === "string" ? content : content).digest("hex")}`;
1175
+ }
1176
+
1175
1177
  // src/utils/collections.ts
1176
1178
  function uniqueStrings(values) {
1177
1179
  return Array.from(new Set(values));
@@ -1220,46 +1222,6 @@ function isResolvedNoteLink(link) {
1220
1222
  return link.kind === "note" && link.slug !== null;
1221
1223
  }
1222
1224
 
1223
- // src/content/graph_layout.ts
1224
- function buildGraphEdges(nodes, visibleSlugs = new Set(nodes.map((node) => node.slug))) {
1225
- const edges = /* @__PURE__ */ new Map();
1226
- for (const node of nodes) {
1227
- for (const target of node.outgoing) {
1228
- if (!visibleSlugs.has(node.slug) || !visibleSlugs.has(target)) continue;
1229
- const key = `${node.slug}\0${target}`;
1230
- edges.set(key, { source: node.slug, target });
1231
- }
1232
- }
1233
- return Array.from(edges.values());
1234
- }
1235
- function layoutRadialGraph(nodes, options) {
1236
- const layout = /* @__PURE__ */ new Map();
1237
- const centerX = options.width / 2;
1238
- const centerY = options.height / 2;
1239
- const radius = Math.min(options.width, options.height) * (options.radiusRatio ?? 0.36);
1240
- const minNodeRadius = options.minNodeRadius ?? 8;
1241
- const maxNodeRadius = options.maxNodeRadius ?? 14;
1242
- const selectedIndex = Math.max(
1243
- nodes.findIndex((node) => node.slug === options.centerSlug),
1244
- 0
1245
- );
1246
- nodes.forEach((node, index) => {
1247
- const shiftedIndex = (index - selectedIndex + nodes.length) % nodes.length;
1248
- const angle = shiftedIndex / Math.max(nodes.length, 1) * Math.PI * 2;
1249
- const linkCount = node.outgoing.length + node.backlinks.length;
1250
- const isCenter = node.slug === options.centerSlug;
1251
- layout.set(node.slug, {
1252
- x: isCenter ? centerX : centerX + Math.cos(angle) * radius,
1253
- y: isCenter ? centerY : centerY + Math.sin(angle) * radius,
1254
- radius: clamp(7 + linkCount, minNodeRadius, maxNodeRadius)
1255
- });
1256
- });
1257
- return layout;
1258
- }
1259
- function clamp(value, min, max) {
1260
- return Math.min(Math.max(value, min), max);
1261
- }
1262
-
1263
1225
  // src/content/content_location.ts
1264
1226
  function resolveDefaultContentLocation(content) {
1265
1227
  return {
@@ -2360,12 +2322,12 @@ function extractFrontmatterAliases(markdown) {
2360
2322
  const lines = frontmatter[1].split(/\r?\n/);
2361
2323
  for (let i = 0; i < lines.length; i++) {
2362
2324
  const line = lines[i] ?? "";
2363
- const inlineMatch = line.match(/^aliases?:\s*(.+)$/i);
2325
+ const inlineMatch = line.match(/^alias(?:es)?:\s*(.+)$/i);
2364
2326
  if (inlineMatch?.[1]) {
2365
2327
  aliases.push(...parseYamlScalarOrList(inlineMatch[1]));
2366
2328
  continue;
2367
2329
  }
2368
- if (/^aliases?:\s*$/i.test(line)) {
2330
+ if (/^alias(?:es)?:\s*$/i.test(line)) {
2369
2331
  for (let j = i + 1; j < lines.length; j++) {
2370
2332
  const itemMatch = lines[j]?.match(/^\s*-\s*(.+)$/);
2371
2333
  if (!itemMatch?.[1]) break;
@@ -2960,6 +2922,46 @@ async function getContentSourceEntry(source, logicalPath) {
2960
2922
  return (await source.scan()).find((candidate) => candidate.path === logicalPath) ?? null;
2961
2923
  }
2962
2924
 
2925
+ // src/content/graph_layout.ts
2926
+ function buildGraphEdges(nodes, visibleSlugs = new Set(nodes.map((node) => node.slug))) {
2927
+ const edges = /* @__PURE__ */ new Map();
2928
+ for (const node of nodes) {
2929
+ for (const target of node.outgoing) {
2930
+ if (!visibleSlugs.has(node.slug) || !visibleSlugs.has(target)) continue;
2931
+ const key = `${node.slug}\0${target}`;
2932
+ edges.set(key, { source: node.slug, target });
2933
+ }
2934
+ }
2935
+ return Array.from(edges.values());
2936
+ }
2937
+ function layoutRadialGraph(nodes, options) {
2938
+ const layout = /* @__PURE__ */ new Map();
2939
+ const centerX = options.width / 2;
2940
+ const centerY = options.height / 2;
2941
+ const radius = Math.min(options.width, options.height) * (options.radiusRatio ?? 0.36);
2942
+ const minNodeRadius = options.minNodeRadius ?? 8;
2943
+ const maxNodeRadius = options.maxNodeRadius ?? 14;
2944
+ const selectedIndex = Math.max(
2945
+ nodes.findIndex((node) => node.slug === options.centerSlug),
2946
+ 0
2947
+ );
2948
+ nodes.forEach((node, index) => {
2949
+ const shiftedIndex = (index - selectedIndex + nodes.length) % nodes.length;
2950
+ const angle = shiftedIndex / Math.max(nodes.length, 1) * Math.PI * 2;
2951
+ const linkCount = node.outgoing.length + node.backlinks.length;
2952
+ const isCenter = node.slug === options.centerSlug;
2953
+ layout.set(node.slug, {
2954
+ x: isCenter ? centerX : centerX + Math.cos(angle) * radius,
2955
+ y: isCenter ? centerY : centerY + Math.sin(angle) * radius,
2956
+ radius: clamp(7 + linkCount, minNodeRadius, maxNodeRadius)
2957
+ });
2958
+ });
2959
+ return layout;
2960
+ }
2961
+ function clamp(value, min, max) {
2962
+ return Math.min(Math.max(value, min), max);
2963
+ }
2964
+
2963
2965
  // src/content/read_only_content_graph.ts
2964
2966
  async function readOnlyContentGraph(source, locations) {
2965
2967
  const entries = await source.scan();
@@ -3000,26 +3002,6 @@ async function readText2(source, entry) {
3000
3002
  return typeof content === "string" ? content : new TextDecoder().decode(content);
3001
3003
  }
3002
3004
 
3003
- // src/utils/html.ts
3004
- function escapeHtml(value) {
3005
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3006
- }
3007
- function escapeHtmlAttribute(value) {
3008
- return escapeHtml(value);
3009
- }
3010
-
3011
- // src/utils/text.ts
3012
- function stripHtml(html) {
3013
- return html.replace(/<script\b[\s\S]*?<\/script>/gi, " ").replace(/<style\b[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ");
3014
- }
3015
- function calculateReadingTime(html) {
3016
- const text = stripHtml(html).trim();
3017
- if (!text) return 1;
3018
- const cjkCharacters = text.match(/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}/gu)?.length ?? 0;
3019
- const latinWords = text.replace(/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}/gu, " ").match(/[\p{L}\p{N}]+/gu)?.length ?? 0;
3020
- return Math.max(1, Math.ceil(cjkCharacters / 500 + latinWords / 220));
3021
- }
3022
-
3023
3005
  // src/plugin/plugin_memo.ts
3024
3006
  import { createHash as createHash3 } from "node:crypto";
3025
3007
  function createPluginMemo(cache, options = {}) {
@@ -3030,13 +3012,23 @@ function createPluginMemo(cache, options = {}) {
3030
3012
  const cached = await cache.get(memoKey);
3031
3013
  if (cached !== void 0) return cached;
3032
3014
  } catch (error) {
3033
- warn(options.logger, "Plugin cache read failed; recomputing.", key, error);
3015
+ warn(
3016
+ options.logger,
3017
+ "Plugin cache read failed; recomputing.",
3018
+ key,
3019
+ error
3020
+ );
3034
3021
  }
3035
3022
  const value = await compute();
3036
3023
  try {
3037
3024
  await cache.set(memoKey, value);
3038
3025
  } catch (error) {
3039
- warn(options.logger, "Plugin cache write failed; result not cached.", key, error);
3026
+ warn(
3027
+ options.logger,
3028
+ "Plugin cache write failed; result not cached.",
3029
+ key,
3030
+ error
3031
+ );
3040
3032
  }
3041
3033
  return value;
3042
3034
  }
@@ -3079,16 +3071,37 @@ function defineEndpoint(path4, handler, options = {}) {
3079
3071
  path: path4,
3080
3072
  handler: async (context) => {
3081
3073
  const response = await handler(context);
3082
- return {
3083
- ...response,
3084
- headers: {
3085
- ...response.headers,
3086
- "Cache-Control": options.cacheControl
3087
- }
3088
- };
3074
+ const headers = { ...response.headers };
3075
+ if (options.cacheControl !== void 0) {
3076
+ headers["Cache-Control"] = options.cacheControl;
3077
+ }
3078
+ return { ...response, headers };
3089
3079
  }
3090
3080
  };
3091
3081
  }
3082
+
3083
+ // src/utils/html.ts
3084
+ function escapeHtml(value) {
3085
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3086
+ }
3087
+ function escapeHtmlAttribute(value) {
3088
+ return escapeHtml(value);
3089
+ }
3090
+ function escapeScriptJson(value) {
3091
+ return value.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
3092
+ }
3093
+
3094
+ // src/utils/text.ts
3095
+ function stripHtml(html) {
3096
+ return html.replace(/<script\b[\s\S]*?<\/script>/gi, " ").replace(/<style\b[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ");
3097
+ }
3098
+ function calculateReadingTime(html) {
3099
+ const text = stripHtml(html).trim();
3100
+ if (!text) return 1;
3101
+ const cjkCharacters = text.match(/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}/gu)?.length ?? 0;
3102
+ const latinWords = text.replace(/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}/gu, " ").match(/[\p{L}\p{N}]+/gu)?.length ?? 0;
3103
+ return Math.max(1, Math.ceil(cjkCharacters / 500 + latinWords / 220));
3104
+ }
3092
3105
  export {
3093
3106
  ATTACHMENTS_BASE_PATH,
3094
3107
  CompositeTraceSink,
@@ -3118,6 +3131,7 @@ export {
3118
3131
  defineTheme,
3119
3132
  escapeHtml,
3120
3133
  escapeHtmlAttribute,
3134
+ escapeScriptJson,
3121
3135
  extractFrontmatterAliases,
3122
3136
  fingerprintContentEntries,
3123
3137
  getContentSourceEntry,
@@ -1,9 +1,30 @@
1
1
  import type { ContentManifest } from "./content_manifest.js";
2
2
  import type { ResolvedRiebeckiteConfig } from "./resolved_riebeckite_config.js";
3
- export type PluginEndpointMethod = "GET";
3
+ export type PluginEndpointMethod = "GET" | "POST";
4
+ /**
5
+ * Framework-neutral snapshot of an incoming HTTP request.
6
+ *
7
+ * Integrations extract only these fields from their host router and pass them
8
+ * to endpoint handlers. Endpoints never receive a Hono, Vite, or Node request
9
+ * object, so a plugin stays usable across runtimes.
10
+ */
11
+ export type PluginEndpointRequest = {
12
+ method: PluginEndpointMethod;
13
+ /** Absolute request URL. */
14
+ url: string;
15
+ /** URL path, for example `/webmentions`. */
16
+ path: string;
17
+ /** First value of every query-string parameter. */
18
+ query: Readonly<Record<string, string>>;
19
+ /** Request headers keyed by lower-cased name. */
20
+ headers: Readonly<Record<string, string>>;
21
+ /** Raw request body text. Empty when the request has no body. */
22
+ body: string;
23
+ };
4
24
  export type PluginEndpointContext = {
5
25
  config: ResolvedRiebeckiteConfig;
6
26
  manifest: ContentManifest;
27
+ request: PluginEndpointRequest;
7
28
  };
8
29
  export type PluginEndpointResponse = {
9
30
  status?: number;
@@ -13,6 +34,7 @@ export type PluginEndpointResponse = {
13
34
  };
14
35
  export type PluginEndpoint = {
15
36
  path: string;
37
+ /** Defaults to `GET` when omitted. */
16
38
  method?: PluginEndpointMethod;
17
39
  handler(context: PluginEndpointContext): PluginEndpointResponse | Promise<PluginEndpointResponse>;
18
40
  };
@@ -1,8 +1,7 @@
1
1
  import type { Plugin } from "unified";
2
- import type { Node } from "unist";
3
2
  import type { ContentSource } from "../content/content_source.js";
4
3
  import type { PluginRenderInput } from "./plugin_context.js";
5
- export type PipelinePlugin = Plugin<[unknown?], Node, Node>;
4
+ export type PipelinePlugin = Plugin<any[], any, any>;
6
5
  export type MarkdownPipeline = {
7
6
  use(plugin: PipelinePlugin, options?: unknown): void;
8
7
  };
@@ -1,2 +1,11 @@
1
1
  export declare function escapeHtml(value: string): string;
2
2
  export declare function escapeHtmlAttribute(value: string): string;
3
+ /**
4
+ * Escapes JSON so it can be embedded inside a `<script>` element (e.g. as
5
+ * `application/ld+json` or `application/json`). `JSON.stringify` leaves `<`,
6
+ * `>`, `&`, U+2028 and U+2029 untouched; inside a script tag `<` terminates
7
+ * the element, which lets an attacker break out and inject markup or code.
8
+ * Replacing them with the equivalent `\uXXXX` escapes keeps the JSON valid
9
+ * while neutralizing the dangerous characters.
10
+ */
11
+ export declare function escapeScriptJson(value: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/core",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,7 +42,8 @@
42
42
  "vfile-matter": "^5.0.1"
43
43
  },
44
44
  "devDependencies": {
45
- "tsx": "^4.22.4"
45
+ "tsx": "^4.22.4",
46
+ "@riebeckite/test": "0.0.6"
46
47
  },
47
48
  "repository": {
48
49
  "type": "git",