svedocs 0.1.0-beta.10

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.
Files changed (286) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +85 -0
  3. package/dist/ai/openai-compatible.d.ts +13 -0
  4. package/dist/ai/openai-compatible.d.ts.map +1 -0
  5. package/dist/ai/openai-compatible.js +92 -0
  6. package/dist/ai/providers.d.ts +20 -0
  7. package/dist/ai/providers.d.ts.map +1 -0
  8. package/dist/ai/providers.js +185 -0
  9. package/dist/ai/rate-limit.d.ts +18 -0
  10. package/dist/ai/rate-limit.d.ts.map +1 -0
  11. package/dist/ai/rate-limit.js +52 -0
  12. package/dist/ai/response.d.ts +4 -0
  13. package/dist/ai/response.d.ts.map +1 -0
  14. package/dist/ai/response.js +151 -0
  15. package/dist/ai/runtime.d.ts +32 -0
  16. package/dist/ai/runtime.d.ts.map +1 -0
  17. package/dist/ai/runtime.js +111 -0
  18. package/dist/ai/types.d.ts +93 -0
  19. package/dist/ai/types.d.ts.map +1 -0
  20. package/dist/ai/types.js +1 -0
  21. package/dist/ai.d.ts +7 -0
  22. package/dist/ai.d.ts.map +1 -0
  23. package/dist/ai.js +6 -0
  24. package/dist/ambient.d.ts +5 -0
  25. package/dist/cloudflare.d.ts +29 -0
  26. package/dist/cloudflare.d.ts.map +1 -0
  27. package/dist/cloudflare.js +149 -0
  28. package/dist/config.d.ts +373 -0
  29. package/dist/config.d.ts.map +1 -0
  30. package/dist/config.js +299 -0
  31. package/dist/core/checks.d.ts +4 -0
  32. package/dist/core/checks.d.ts.map +1 -0
  33. package/dist/core/checks.js +267 -0
  34. package/dist/core/config.d.ts +6 -0
  35. package/dist/core/config.d.ts.map +1 -0
  36. package/dist/core/config.js +178 -0
  37. package/dist/core/content.d.ts +7 -0
  38. package/dist/core/content.d.ts.map +1 -0
  39. package/dist/core/content.js +340 -0
  40. package/dist/core/i18n.d.ts +5 -0
  41. package/dist/core/i18n.d.ts.map +1 -0
  42. package/dist/core/i18n.js +117 -0
  43. package/dist/core/links.d.ts +5 -0
  44. package/dist/core/links.d.ts.map +1 -0
  45. package/dist/core/links.js +60 -0
  46. package/dist/core/messages.d.ts +149 -0
  47. package/dist/core/messages.d.ts.map +1 -0
  48. package/dist/core/messages.js +163 -0
  49. package/dist/core/navigation.d.ts +5 -0
  50. package/dist/core/navigation.d.ts.map +1 -0
  51. package/dist/core/navigation.js +144 -0
  52. package/dist/core/routes.d.ts +36 -0
  53. package/dist/core/routes.d.ts.map +1 -0
  54. package/dist/core/routes.js +152 -0
  55. package/dist/core/search.d.ts +5 -0
  56. package/dist/core/search.d.ts.map +1 -0
  57. package/dist/core/search.js +41 -0
  58. package/dist/core/types.d.ts +468 -0
  59. package/dist/core/types.d.ts.map +1 -0
  60. package/dist/core/types.js +4 -0
  61. package/dist/core/utils.d.ts +13 -0
  62. package/dist/core/utils.d.ts.map +1 -0
  63. package/dist/core/utils.js +60 -0
  64. package/dist/core.d.ts +9 -0
  65. package/dist/core.d.ts.map +1 -0
  66. package/dist/core.js +8 -0
  67. package/dist/index.d.ts +6 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +3 -0
  70. package/dist/mdx/ast.d.ts +32 -0
  71. package/dist/mdx/ast.d.ts.map +1 -0
  72. package/dist/mdx/ast.js +148 -0
  73. package/dist/mdx/code.d.ts +17 -0
  74. package/dist/mdx/code.d.ts.map +1 -0
  75. package/dist/mdx/code.js +327 -0
  76. package/dist/mdx/compile.d.ts +29 -0
  77. package/dist/mdx/compile.d.ts.map +1 -0
  78. package/dist/mdx/compile.js +59 -0
  79. package/dist/mdx/diff.d.ts +9 -0
  80. package/dist/mdx/diff.d.ts.map +1 -0
  81. package/dist/mdx/diff.js +171 -0
  82. package/dist/mdx/headings.d.ts +4 -0
  83. package/dist/mdx/headings.d.ts.map +1 -0
  84. package/dist/mdx/headings.js +42 -0
  85. package/dist/mdx/links.d.ts +4 -0
  86. package/dist/mdx/links.d.ts.map +1 -0
  87. package/dist/mdx/links.js +144 -0
  88. package/dist/mdx/utils.d.ts +10 -0
  89. package/dist/mdx/utils.d.ts.map +1 -0
  90. package/dist/mdx/utils.js +64 -0
  91. package/dist/og/image.d.ts +25 -0
  92. package/dist/og/image.d.ts.map +1 -0
  93. package/dist/og/image.js +224 -0
  94. package/dist/og/metadata.d.ts +7 -0
  95. package/dist/og/metadata.d.ts.map +1 -0
  96. package/dist/og/metadata.js +198 -0
  97. package/dist/og/response.d.ts +4 -0
  98. package/dist/og/response.d.ts.map +1 -0
  99. package/dist/og/response.js +49 -0
  100. package/dist/og/rss.d.ts +4 -0
  101. package/dist/og/rss.d.ts.map +1 -0
  102. package/dist/og/rss.js +96 -0
  103. package/dist/og/sitemap.d.ts +7 -0
  104. package/dist/og/sitemap.d.ts.map +1 -0
  105. package/dist/og/sitemap.js +90 -0
  106. package/dist/og/types.d.ts +65 -0
  107. package/dist/og/types.d.ts.map +1 -0
  108. package/dist/og/types.js +1 -0
  109. package/dist/og.d.ts +6 -0
  110. package/dist/og.d.ts.map +1 -0
  111. package/dist/og.js +5 -0
  112. package/dist/routes.d.ts +2 -0
  113. package/dist/routes.d.ts.map +1 -0
  114. package/dist/routes.js +1 -0
  115. package/dist/search/algolia.d.ts +10 -0
  116. package/dist/search/algolia.d.ts.map +1 -0
  117. package/dist/search/algolia.js +82 -0
  118. package/dist/search/cloudflare-sync.d.ts +5 -0
  119. package/dist/search/cloudflare-sync.d.ts.map +1 -0
  120. package/dist/search/cloudflare-sync.js +169 -0
  121. package/dist/search/cloudflare.d.ts +11 -0
  122. package/dist/search/cloudflare.d.ts.map +1 -0
  123. package/dist/search/cloudflare.js +126 -0
  124. package/dist/search/local.d.ts +9 -0
  125. package/dist/search/local.d.ts.map +1 -0
  126. package/dist/search/local.js +165 -0
  127. package/dist/search/runtime.d.ts +41 -0
  128. package/dist/search/runtime.d.ts.map +1 -0
  129. package/dist/search/runtime.js +152 -0
  130. package/dist/search/types.d.ts +172 -0
  131. package/dist/search/types.d.ts.map +1 -0
  132. package/dist/search/types.js +1 -0
  133. package/dist/search/typesense.d.ts +11 -0
  134. package/dist/search/typesense.d.ts.map +1 -0
  135. package/dist/search/typesense.js +91 -0
  136. package/dist/search/utils.d.ts +11 -0
  137. package/dist/search/utils.d.ts.map +1 -0
  138. package/dist/search/utils.js +93 -0
  139. package/dist/search.d.ts +8 -0
  140. package/dist/search.d.ts.map +1 -0
  141. package/dist/search.js +7 -0
  142. package/dist/svelte.d.ts +27 -0
  143. package/dist/svelte.d.ts.map +1 -0
  144. package/dist/svelte.js +45 -0
  145. package/dist/testing.d.ts +3 -0
  146. package/dist/testing.d.ts.map +1 -0
  147. package/dist/testing.js +23 -0
  148. package/dist/theme/Article.svelte +145 -0
  149. package/dist/theme/Article.svelte.d.ts +36 -0
  150. package/dist/theme/Article.svelte.d.ts.map +1 -0
  151. package/dist/theme/AskAiPanel.svelte +241 -0
  152. package/dist/theme/AskAiPanel.svelte.d.ts +31 -0
  153. package/dist/theme/AskAiPanel.svelte.d.ts.map +1 -0
  154. package/dist/theme/Brand.svelte +19 -0
  155. package/dist/theme/Brand.svelte.d.ts +22 -0
  156. package/dist/theme/Brand.svelte.d.ts.map +1 -0
  157. package/dist/theme/Button.svelte +34 -0
  158. package/dist/theme/Button.svelte.d.ts +41 -0
  159. package/dist/theme/Button.svelte.d.ts.map +1 -0
  160. package/dist/theme/Checkbox.svelte +63 -0
  161. package/dist/theme/Checkbox.svelte.d.ts +45 -0
  162. package/dist/theme/Checkbox.svelte.d.ts.map +1 -0
  163. package/dist/theme/CodeBlock.svelte +6 -0
  164. package/dist/theme/CodeBlock.svelte.d.ts +22 -0
  165. package/dist/theme/CodeBlock.svelte.d.ts.map +1 -0
  166. package/dist/theme/DocPage.svelte +15 -0
  167. package/dist/theme/DocPage.svelte.d.ts +33 -0
  168. package/dist/theme/DocPage.svelte.d.ts.map +1 -0
  169. package/dist/theme/DocsApp.svelte +194 -0
  170. package/dist/theme/DocsApp.svelte.d.ts +60 -0
  171. package/dist/theme/DocsApp.svelte.d.ts.map +1 -0
  172. package/dist/theme/DocsLayout.svelte +99 -0
  173. package/dist/theme/DocsLayout.svelte.d.ts +39 -0
  174. package/dist/theme/DocsLayout.svelte.d.ts.map +1 -0
  175. package/dist/theme/DocsShell.svelte +91 -0
  176. package/dist/theme/DocsShell.svelte.d.ts +34 -0
  177. package/dist/theme/DocsShell.svelte.d.ts.map +1 -0
  178. package/dist/theme/ErrorPage.svelte +113 -0
  179. package/dist/theme/ErrorPage.svelte.d.ts +34 -0
  180. package/dist/theme/ErrorPage.svelte.d.ts.map +1 -0
  181. package/dist/theme/FloatingToolbar.svelte +8 -0
  182. package/dist/theme/FloatingToolbar.svelte.d.ts +22 -0
  183. package/dist/theme/FloatingToolbar.svelte.d.ts.map +1 -0
  184. package/dist/theme/Footer.svelte +18 -0
  185. package/dist/theme/Footer.svelte.d.ts +24 -0
  186. package/dist/theme/Footer.svelte.d.ts.map +1 -0
  187. package/dist/theme/FooterLinks.svelte +37 -0
  188. package/dist/theme/FooterLinks.svelte.d.ts +22 -0
  189. package/dist/theme/FooterLinks.svelte.d.ts.map +1 -0
  190. package/dist/theme/FormField.svelte +41 -0
  191. package/dist/theme/FormField.svelte.d.ts +35 -0
  192. package/dist/theme/FormField.svelte.d.ts.map +1 -0
  193. package/dist/theme/HomePage.svelte +284 -0
  194. package/dist/theme/HomePage.svelte.d.ts +65 -0
  195. package/dist/theme/HomePage.svelte.d.ts.map +1 -0
  196. package/dist/theme/Input.svelte +36 -0
  197. package/dist/theme/Input.svelte.d.ts +34 -0
  198. package/dist/theme/Input.svelte.d.ts.map +1 -0
  199. package/dist/theme/LayoutShell.svelte +120 -0
  200. package/dist/theme/LayoutShell.svelte.d.ts +43 -0
  201. package/dist/theme/LayoutShell.svelte.d.ts.map +1 -0
  202. package/dist/theme/LocalizedLink.svelte +21 -0
  203. package/dist/theme/LocalizedLink.svelte.d.ts +38 -0
  204. package/dist/theme/LocalizedLink.svelte.d.ts.map +1 -0
  205. package/dist/theme/MobileNav.svelte +20 -0
  206. package/dist/theme/MobileNav.svelte.d.ts +26 -0
  207. package/dist/theme/MobileNav.svelte.d.ts.map +1 -0
  208. package/dist/theme/Navbar.svelte +69 -0
  209. package/dist/theme/Navbar.svelte.d.ts +29 -0
  210. package/dist/theme/Navbar.svelte.d.ts.map +1 -0
  211. package/dist/theme/PageLayout.svelte +49 -0
  212. package/dist/theme/PageLayout.svelte.d.ts +34 -0
  213. package/dist/theme/PageLayout.svelte.d.ts.map +1 -0
  214. package/dist/theme/PageShell.svelte +98 -0
  215. package/dist/theme/PageShell.svelte.d.ts +35 -0
  216. package/dist/theme/PageShell.svelte.d.ts.map +1 -0
  217. package/dist/theme/PageTools.svelte +87 -0
  218. package/dist/theme/PageTools.svelte.d.ts +25 -0
  219. package/dist/theme/PageTools.svelte.d.ts.map +1 -0
  220. package/dist/theme/RenderError.svelte +62 -0
  221. package/dist/theme/RenderError.svelte.d.ts +31 -0
  222. package/dist/theme/RenderError.svelte.d.ts.map +1 -0
  223. package/dist/theme/RootLayout.svelte +274 -0
  224. package/dist/theme/RootLayout.svelte.d.ts +47 -0
  225. package/dist/theme/RootLayout.svelte.d.ts.map +1 -0
  226. package/dist/theme/RouteRenderError.svelte +53 -0
  227. package/dist/theme/RouteRenderError.svelte.d.ts +34 -0
  228. package/dist/theme/RouteRenderError.svelte.d.ts.map +1 -0
  229. package/dist/theme/SafeRenderError.svelte +49 -0
  230. package/dist/theme/SafeRenderError.svelte.d.ts +33 -0
  231. package/dist/theme/SafeRenderError.svelte.d.ts.map +1 -0
  232. package/dist/theme/ScopeSwitcher.svelte +107 -0
  233. package/dist/theme/ScopeSwitcher.svelte.d.ts +26 -0
  234. package/dist/theme/ScopeSwitcher.svelte.d.ts.map +1 -0
  235. package/dist/theme/SearchDialog.svelte +200 -0
  236. package/dist/theme/SearchDialog.svelte.d.ts +31 -0
  237. package/dist/theme/SearchDialog.svelte.d.ts.map +1 -0
  238. package/dist/theme/Select.svelte +37 -0
  239. package/dist/theme/Select.svelte.d.ts +42 -0
  240. package/dist/theme/Select.svelte.d.ts.map +1 -0
  241. package/dist/theme/SidebarTree.svelte +148 -0
  242. package/dist/theme/SidebarTree.svelte.d.ts +24 -0
  243. package/dist/theme/SidebarTree.svelte.d.ts.map +1 -0
  244. package/dist/theme/SocialNav.svelte +17 -0
  245. package/dist/theme/SocialNav.svelte.d.ts +22 -0
  246. package/dist/theme/SocialNav.svelte.d.ts.map +1 -0
  247. package/dist/theme/TableOfContents.svelte +73 -0
  248. package/dist/theme/TableOfContents.svelte.d.ts +25 -0
  249. package/dist/theme/TableOfContents.svelte.d.ts.map +1 -0
  250. package/dist/theme/Textarea.svelte +33 -0
  251. package/dist/theme/Textarea.svelte.d.ts +33 -0
  252. package/dist/theme/Textarea.svelte.d.ts.map +1 -0
  253. package/dist/theme/ThemeInit.svelte +16 -0
  254. package/dist/theme/ThemeInit.svelte.d.ts +23 -0
  255. package/dist/theme/ThemeInit.svelte.d.ts.map +1 -0
  256. package/dist/theme/ThemeToggle.svelte +37 -0
  257. package/dist/theme/ThemeToggle.svelte.d.ts +23 -0
  258. package/dist/theme/ThemeToggle.svelte.d.ts.map +1 -0
  259. package/dist/theme/TopNav.svelte +23 -0
  260. package/dist/theme/TopNav.svelte.d.ts +22 -0
  261. package/dist/theme/TopNav.svelte.d.ts.map +1 -0
  262. package/dist/theme/base.css +240 -0
  263. package/dist/theme/defaults.d.ts +4 -0
  264. package/dist/theme/defaults.d.ts.map +1 -0
  265. package/dist/theme/defaults.js +55 -0
  266. package/dist/theme/forms.d.ts +4 -0
  267. package/dist/theme/forms.d.ts.map +1 -0
  268. package/dist/theme/forms.js +3 -0
  269. package/dist/theme/headless.d.ts +62 -0
  270. package/dist/theme/headless.d.ts.map +1 -0
  271. package/dist/theme/headless.js +1064 -0
  272. package/dist/theme/index.d.ts +41 -0
  273. package/dist/theme/index.d.ts.map +1 -0
  274. package/dist/theme/index.js +38 -0
  275. package/dist/theme/portal.d.ts +6 -0
  276. package/dist/theme/portal.d.ts.map +1 -0
  277. package/dist/theme/portal.js +59 -0
  278. package/dist/theme/styles.css +4232 -0
  279. package/dist/theme/types.d.ts +363 -0
  280. package/dist/theme/types.d.ts.map +1 -0
  281. package/dist/theme/types.js +1 -0
  282. package/dist/virtual.d.ts +65 -0
  283. package/dist/vite.d.ts +16 -0
  284. package/dist/vite.d.ts.map +1 -0
  285. package/dist/vite.js +386 -0
  286. package/package.json +132 -0
@@ -0,0 +1,90 @@
1
+ import { formatRoutePathForBuildMode } from '../core/utils.js';
2
+ import { createPageAlternates } from './metadata.js';
3
+ import { createDisabledDiscoveryResponse, createDiscoveryResponse, escapeXml } from './response.js';
4
+ export function createSitemapXml(config, pages) {
5
+ if (!config.seo.sitemap)
6
+ return '';
7
+ const discoverablePages = pages.filter(isDiscoverablePage);
8
+ const alternateIndex = createAlternateIndex(config, discoverablePages);
9
+ const urls = discoverablePages
10
+ .map((page) => {
11
+ const loc = createSitemapLocation(config, page);
12
+ if (!loc)
13
+ return '';
14
+ const lastmod = page.seo.updatedTime ?? page.lastUpdated;
15
+ const alternates = alternateIndex.get(createAlternateKey(page)) ?? [];
16
+ return [
17
+ ' <url>',
18
+ ` <loc>${escapeXml(loc)}</loc>`,
19
+ ...(lastmod ? [` <lastmod>${escapeXml(lastmod)}</lastmod>`] : []),
20
+ ...alternates.map((alternate) => ` <xhtml:link rel="alternate" hreflang="${escapeXml(alternate.lang)}" href="${escapeXml(alternate.href)}" />`),
21
+ ' </url>'
22
+ ].join('\n');
23
+ })
24
+ .filter(Boolean)
25
+ .join('\n');
26
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">\n${urls}\n</urlset>\n`;
27
+ }
28
+ export function createRobotsTxt(config) {
29
+ if (!config.seo.robots)
30
+ return '';
31
+ const sitemap = config.seo.sitemap ? createAbsoluteUrl(config, '/sitemap.xml') : undefined;
32
+ return [
33
+ 'User-agent: *',
34
+ 'Allow: /',
35
+ ...(sitemap ? [`Sitemap: ${sitemap}`] : [])
36
+ ].join('\n') + '\n';
37
+ }
38
+ export function createSitemapResponse(config, pages, request) {
39
+ if (!config.seo.sitemap)
40
+ return createDisabledDiscoveryResponse('Sitemap');
41
+ return createDiscoveryResponse(createSitemapXml(config, pages), 'application/xml; charset=utf-8', request);
42
+ }
43
+ export function createRobotsResponse(config, request) {
44
+ if (!config.seo.robots)
45
+ return createDisabledDiscoveryResponse('Robots');
46
+ return createDiscoveryResponse(createRobotsTxt(config), 'text/plain; charset=utf-8', request);
47
+ }
48
+ export function isDiscoverablePage(page) {
49
+ return !page.hidden && !/(?:^|[\s,])(?:noindex|none)(?:$|[\s,])/i.test(page.seo.robots ?? '');
50
+ }
51
+ function createAlternateIndex(config, pages) {
52
+ const groups = new Map();
53
+ for (const page of pages) {
54
+ const key = createAlternateKey(page);
55
+ const group = groups.get(key) ?? [];
56
+ group.push(page);
57
+ groups.set(key, group);
58
+ }
59
+ const alternates = new Map();
60
+ for (const [key, group] of groups) {
61
+ const reference = group[0];
62
+ if (reference)
63
+ alternates.set(key, createPageAlternates(config, reference, group));
64
+ }
65
+ return alternates;
66
+ }
67
+ function createAlternateKey(page) {
68
+ return `${page.kind}:${page.scopePath}`;
69
+ }
70
+ function createSitemapLocation(config, page) {
71
+ const routePath = formatRoutePathForBuildMode(page.routePath, config.build.mode);
72
+ const location = page.seo.canonical
73
+ ? createAbsoluteUrl(config, page.seo.canonical) ?? page.seo.canonical
74
+ : createAbsoluteUrl(config, routePath) ?? routePath;
75
+ if (!config.site.url || !/^https?:\/\//.test(location))
76
+ return location;
77
+ try {
78
+ return new URL(location).origin === new URL(config.site.url).origin ? location : undefined;
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ }
84
+ function createAbsoluteUrl(config, value) {
85
+ if (/^https?:\/\//.test(value))
86
+ return value;
87
+ if (!config.site.url)
88
+ return undefined;
89
+ return new URL(value, config.site.url).href;
90
+ }
@@ -0,0 +1,65 @@
1
+ import type { SvedocsResolvedSeoHead } from '../core/types.js';
2
+ export interface OgImageInput {
3
+ title: string;
4
+ description?: string;
5
+ siteName?: string;
6
+ }
7
+ export type OgRenderer = 'svg' | 'satori';
8
+ export interface OgFont {
9
+ name: string;
10
+ data: ArrayBuffer | Uint8Array;
11
+ weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
12
+ style?: 'normal' | 'italic';
13
+ }
14
+ export interface OgTemplateNode {
15
+ type: string;
16
+ props: {
17
+ style?: Record<string, string | number>;
18
+ children?: string | OgTemplateNode | OgTemplateNode[];
19
+ [key: string]: unknown;
20
+ };
21
+ }
22
+ export type OgTemplate = (input: OgImageInput) => OgTemplateNode;
23
+ export interface OgRenderOptions {
24
+ renderer?: OgRenderer;
25
+ fonts?: OgFont[];
26
+ template?: OgTemplate;
27
+ }
28
+ export interface OgImageOptions extends OgRenderOptions {
29
+ format?: 'svg' | 'png';
30
+ }
31
+ export interface SvedocsPageMetadata {
32
+ title: string;
33
+ description: string;
34
+ canonical?: string;
35
+ image?: string;
36
+ keywords: string[];
37
+ robots?: string;
38
+ head: SvedocsResolvedSeoHead;
39
+ openGraph: {
40
+ title: string;
41
+ description: string;
42
+ type: string;
43
+ url?: string;
44
+ image?: string;
45
+ siteName: string;
46
+ locale?: string;
47
+ alternateLocales?: string[];
48
+ author?: string;
49
+ publishedTime?: string;
50
+ updatedTime?: string;
51
+ };
52
+ twitter: {
53
+ card: 'summary' | 'summary_large_image';
54
+ title: string;
55
+ description: string;
56
+ image?: string;
57
+ };
58
+ jsonLd: Record<string, unknown>;
59
+ }
60
+ export interface SvedocsPageAlternate {
61
+ lang: string;
62
+ href: string;
63
+ locale?: string;
64
+ }
65
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/og/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC;IAC/B,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC7D,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;QACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;QACtD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,cAAc,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,cAAe,SAAQ,eAAe;IACrD,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,SAAS,GAAG,qBAAqB,CAAC;QACxC,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/og.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './og/types.js';
2
+ export * from './og/metadata.js';
3
+ export * from './og/sitemap.js';
4
+ export * from './og/rss.js';
5
+ export * from './og/image.js';
6
+ //# sourceMappingURL=og.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"og.d.ts","sourceRoot":"","sources":["../src/og.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
package/dist/og.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './og/types.js';
2
+ export * from './og/metadata.js';
3
+ export * from './og/sitemap.js';
4
+ export * from './og/rss.js';
5
+ export * from './og/image.js';
@@ -0,0 +1,2 @@
1
+ export * from './core/routes.js';
2
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
package/dist/routes.js ADDED
@@ -0,0 +1 @@
1
+ export * from './core/routes.js';
@@ -0,0 +1,10 @@
1
+ import type { SearchProvider, SearchQuery } from './types.js';
2
+ export interface AlgoliaSearchProviderOptions {
3
+ appId: string;
4
+ apiKey: string;
5
+ indexName: string;
6
+ filters?: string | ((query: SearchQuery) => string | undefined);
7
+ fetch?: typeof fetch;
8
+ }
9
+ export declare function createAlgoliaSearchProvider(options: AlgoliaSearchProviderOptions): SearchProvider;
10
+ //# sourceMappingURL=algolia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algolia.d.ts","sourceRoot":"","sources":["../../src/search/algolia.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAG5E,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;IAChE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAyBD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,4BAA4B,GAAG,cAAc,CAgCjG"}
@@ -0,0 +1,82 @@
1
+ import { matchesSearchScope } from './local.js';
2
+ import { createExcerpt, stringMetadata, stringifyMetadata } from './utils.js';
3
+ export function createAlgoliaSearchProvider(options) {
4
+ return {
5
+ name: 'algolia',
6
+ index() {
7
+ // Algolia indexing is usually handled by DocSearch crawlers or user CI.
8
+ },
9
+ async search(query) {
10
+ const requestFetch = options.fetch ?? fetch;
11
+ const filters = createAlgoliaFilters(options, query);
12
+ const response = await requestFetch(createAlgoliaQueryEndpoint(options), {
13
+ method: 'POST',
14
+ headers: {
15
+ 'content-type': 'application/json',
16
+ 'x-algolia-application-id': options.appId,
17
+ 'x-algolia-api-key': options.apiKey
18
+ },
19
+ body: JSON.stringify({
20
+ query: query.query,
21
+ hitsPerPage: query.limit ?? 10,
22
+ ...(filters ? { filters } : {}),
23
+ attributesToSnippet: ['content:30']
24
+ })
25
+ });
26
+ if (!response.ok) {
27
+ throw new Error(`Algolia search returned ${response.status}: ${(await response.text()).slice(0, 500)}`);
28
+ }
29
+ const payload = await response.json();
30
+ return (payload.hits ?? [])
31
+ .map((hit, index) => createAlgoliaResult(hit, index, query.query))
32
+ .filter((result) => matchesSearchScope({ metadata: result.metadata }, query));
33
+ }
34
+ };
35
+ }
36
+ function createAlgoliaQueryEndpoint(options) {
37
+ return `https://${encodeURIComponent(options.appId)}-dsn.algolia.net/1/indexes/${encodeURIComponent(options.indexName)}/query`;
38
+ }
39
+ function createAlgoliaFilters(options, query) {
40
+ return typeof options.filters === 'function' ? options.filters(query) : options.filters;
41
+ }
42
+ function createAlgoliaResult(hit, index, query) {
43
+ const metadata = stringifyMetadata({
44
+ ...(hit.metadata ?? {}),
45
+ locale: hit.locale ?? hit.metadata?.locale,
46
+ kind: hit.kind ?? hit.metadata?.kind
47
+ });
48
+ const hierarchyTitle = readHierarchy(hit.hierarchy, ['lvl0', 'lvl1', 'lvl2']);
49
+ const title = hit.title ?? hierarchyTitle ?? 'Result';
50
+ const section = hit.section ?? readHierarchy(hit.hierarchy, ['lvl6', 'lvl5', 'lvl4', 'lvl3', 'lvl2', 'lvl1']);
51
+ const content = stripHtml(readSnippet(hit) ?? hit.content ?? title);
52
+ return {
53
+ id: hit.objectID ?? `algolia:${index}`,
54
+ title,
55
+ url: createAlgoliaUrl(hit),
56
+ ...(section && section !== title ? { section } : {}),
57
+ excerpt: createExcerpt(content, query),
58
+ score: 1 / (index + 1),
59
+ metadata
60
+ };
61
+ }
62
+ function createAlgoliaUrl(hit) {
63
+ const url = hit.url ?? '#';
64
+ if (!hit.anchor || url.includes('#'))
65
+ return url;
66
+ return `${url}#${hit.anchor}`;
67
+ }
68
+ function readSnippet(hit) {
69
+ return stringMetadata(hit._snippetResult?.content?.value)
70
+ ?? stringMetadata(hit._highlightResult?.content?.value);
71
+ }
72
+ function readHierarchy(hierarchy, keys) {
73
+ for (const key of keys) {
74
+ const value = stringMetadata(hierarchy?.[key]);
75
+ if (value)
76
+ return stripHtml(value);
77
+ }
78
+ return undefined;
79
+ }
80
+ function stripHtml(value) {
81
+ return value.replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').trim();
82
+ }
@@ -0,0 +1,5 @@
1
+ import type { SvedocsSearchRecord } from '../core.js';
2
+ import type { CloudflareAiSearchSyncDocument, CloudflareAiSearchSyncOptions, CloudflareAiSearchSyncResult } from './types.js';
3
+ export declare function createCloudflareAiSearchDocuments(records: SvedocsSearchRecord[]): CloudflareAiSearchSyncDocument[];
4
+ export declare function syncCloudflareAiSearchIndex(options: CloudflareAiSearchSyncOptions): Promise<CloudflareAiSearchSyncResult>;
5
+ //# sourceMappingURL=cloudflare-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-sync.d.ts","sourceRoot":"","sources":["../../src/search/cloudflare-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AAGpB,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,8BAA8B,EAAE,CAwBlH;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,4BAA4B,CAAC,CAgEvC"}
@@ -0,0 +1,169 @@
1
+ import { chunkArray, stringifyMetadata, uniqueStrings, wait } from './utils.js';
2
+ export function createCloudflareAiSearchDocuments(records) {
3
+ return records.map((record) => ({
4
+ id: record.id,
5
+ title: record.section ? `${record.title}: ${record.section}` : record.title,
6
+ url: record.url,
7
+ content: [
8
+ `# ${record.section ? `${record.title}: ${record.section}` : record.title}`,
9
+ '',
10
+ `URL: ${record.url}`,
11
+ '',
12
+ record.content
13
+ ].join('\n'),
14
+ metadata: stringifyMetadata({
15
+ svedocs: JSON.stringify({
16
+ id: record.id,
17
+ pageId: record.pageId,
18
+ title: record.title,
19
+ section: record.section ?? '',
20
+ url: record.url
21
+ }),
22
+ locale: record.metadata.locale,
23
+ kind: record.metadata.kind
24
+ })
25
+ }));
26
+ }
27
+ export async function syncCloudflareAiSearchIndex(options) {
28
+ const endpoint = options.endpoint ?? createCloudflareAiSearchItemsEndpoint(options);
29
+ const dryRun = options.dryRun ?? (!options.accountId || !options.apiToken);
30
+ const documents = createCloudflareAiSearchDocuments(options.records);
31
+ const uploadIds = documents.map((document) => document.id);
32
+ const deleteIds = createCloudflareDeletePlan(options, uploadIds);
33
+ const result = {
34
+ provider: 'cloudflare-ai-search',
35
+ instanceName: options.instanceName,
36
+ endpoint,
37
+ dryRun,
38
+ indexed: dryRun ? documents.length : 0,
39
+ deleted: dryRun ? deleteIds.length : 0,
40
+ failed: 0,
41
+ planned: {
42
+ uploadIds,
43
+ deleteIds
44
+ },
45
+ errors: []
46
+ };
47
+ if (dryRun)
48
+ return result;
49
+ if (!options.apiToken) {
50
+ throw new Error('CLOUDFLARE_API_TOKEN is required to index Cloudflare AI Search.');
51
+ }
52
+ const requestFetch = options.fetch ?? fetch;
53
+ const batchSize = options.batchSize ?? 10;
54
+ const maxRetries = options.maxRetries ?? 2;
55
+ const retryDelayMs = options.retryDelayMs ?? 250;
56
+ await processBatches(deleteIds, batchSize, async (itemId) => {
57
+ try {
58
+ await withRetry(() => deleteCloudflareAiSearchItem(endpoint, itemId, options.apiToken, requestFetch), {
59
+ maxRetries,
60
+ retryDelayMs
61
+ });
62
+ result.deleted += 1;
63
+ }
64
+ catch (error) {
65
+ result.failed += 1;
66
+ result.errors.push({
67
+ id: itemId,
68
+ message: error instanceof Error ? error.message : 'Cloudflare AI Search delete failed.'
69
+ });
70
+ }
71
+ });
72
+ await processBatches(documents, batchSize, async (document) => {
73
+ try {
74
+ await withRetry(() => uploadCloudflareAiSearchDocument(endpoint, document, options, requestFetch), {
75
+ maxRetries,
76
+ retryDelayMs
77
+ });
78
+ result.indexed += 1;
79
+ }
80
+ catch (error) {
81
+ result.failed += 1;
82
+ result.errors.push({
83
+ id: document.id,
84
+ message: error instanceof Error ? error.message : 'Cloudflare AI Search upload failed.'
85
+ });
86
+ }
87
+ });
88
+ return result;
89
+ }
90
+ function createCloudflareAiSearchItemsEndpoint(options) {
91
+ if (!options.accountId)
92
+ return 'https://api.cloudflare.com/client/v4/accounts/<account_id>/ai-search/instances/<instance_name>/items';
93
+ const account = encodeURIComponent(options.accountId);
94
+ const instance = encodeURIComponent(options.instanceName);
95
+ if (options.namespace) {
96
+ return `https://api.cloudflare.com/client/v4/accounts/${account}/ai-search/namespaces/${encodeURIComponent(options.namespace)}/instances/${instance}/items`;
97
+ }
98
+ return `https://api.cloudflare.com/client/v4/accounts/${account}/ai-search/instances/${instance}/items`;
99
+ }
100
+ function createCloudflareAiSearchItemEndpoint(itemsEndpoint, itemId) {
101
+ return `${itemsEndpoint.replace(/\/$/, '')}/${encodeURIComponent(itemId)}`;
102
+ }
103
+ function createCloudflareDeletePlan(options, uploadIds) {
104
+ const explicitDeletes = options.deleteIds ?? [];
105
+ if (options.strategy !== 'replace')
106
+ return uniqueStrings(explicitDeletes);
107
+ const uploadSet = new Set(uploadIds);
108
+ return uniqueStrings([
109
+ ...explicitDeletes,
110
+ ...(options.existingIds ?? []).filter((itemId) => !uploadSet.has(itemId))
111
+ ]);
112
+ }
113
+ function createCloudflareItemFilename(document) {
114
+ const safe = document.id.replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/^-|-$/g, '') || 'svedocs-page';
115
+ return `${safe.slice(0, 124)}.md`;
116
+ }
117
+ async function deleteCloudflareAiSearchItem(endpoint, itemId, apiToken, requestFetch) {
118
+ const response = await requestFetch(createCloudflareAiSearchItemEndpoint(endpoint, itemId), {
119
+ method: 'DELETE',
120
+ headers: {
121
+ authorization: `Bearer ${apiToken}`
122
+ }
123
+ });
124
+ if (!response.ok) {
125
+ throw new Error(await createCloudflareApiErrorMessage(response, 'delete'));
126
+ }
127
+ }
128
+ async function uploadCloudflareAiSearchDocument(endpoint, document, options, requestFetch) {
129
+ const form = new FormData();
130
+ form.append('file', new Blob([document.content], { type: 'text/markdown' }), createCloudflareItemFilename(document));
131
+ form.append('metadata', JSON.stringify(document.metadata));
132
+ if (typeof options.waitForCompletion === 'boolean') {
133
+ form.append('wait_for_completion', String(options.waitForCompletion));
134
+ }
135
+ const response = await requestFetch(endpoint, {
136
+ method: 'POST',
137
+ headers: {
138
+ authorization: `Bearer ${options.apiToken}`
139
+ },
140
+ body: form
141
+ });
142
+ if (!response.ok) {
143
+ throw new Error(await createCloudflareApiErrorMessage(response, 'upload'));
144
+ }
145
+ }
146
+ async function createCloudflareApiErrorMessage(response, action) {
147
+ const body = await response.text().catch(() => '');
148
+ return `Cloudflare AI Search ${action} returned ${response.status}${body ? `: ${body.slice(0, 500)}` : ''}`;
149
+ }
150
+ async function processBatches(items, batchSize, handler) {
151
+ for (const batch of chunkArray(items, batchSize)) {
152
+ await Promise.all(batch.map((item) => handler(item)));
153
+ }
154
+ }
155
+ async function withRetry(action, options) {
156
+ let attempt = 0;
157
+ while (true) {
158
+ try {
159
+ await action();
160
+ return;
161
+ }
162
+ catch (error) {
163
+ if (attempt >= options.maxRetries)
164
+ throw error;
165
+ attempt += 1;
166
+ await wait(options.retryDelayMs * attempt);
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,11 @@
1
+ import type { CloudflareAiSearchInput, CloudflareAiSearchInstance, CloudflareAiSearchOutput, CloudflareAiSearchNamespace, SearchResult, SearchScope, SearchProvider } from './types.js';
2
+ export declare function createCloudflareAiSearchProvider(input: {
3
+ binding: CloudflareAiSearchInstance | CloudflareAiSearchNamespace;
4
+ instanceName?: string;
5
+ namespace?: boolean;
6
+ }): SearchProvider;
7
+ export declare function runCloudflareAiSearch(binding: CloudflareAiSearchInstance | CloudflareAiSearchNamespace, instanceName: string | undefined, input: CloudflareAiSearchInput, namespace?: boolean): Promise<CloudflareAiSearchOutput>;
8
+ export declare function normalizeCloudflareAiSearchResults(result: CloudflareAiSearchOutput, query: string): SearchResult[];
9
+ export declare function resolveAiSearchInstance(binding: CloudflareAiSearchInstance | CloudflareAiSearchNamespace, instanceName?: string, namespace?: boolean): CloudflareAiSearchInstance;
10
+ export declare function createCloudflareAiSearchScopeFilters(scope?: SearchScope): Record<string, unknown> | undefined;
11
+ //# sourceMappingURL=cloudflare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/search/cloudflare.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EACvB,0BAA0B,EAE1B,wBAAwB,EACxB,2BAA2B,EAC3B,YAAY,EACZ,WAAW,EACX,cAAc,EACf,MAAM,YAAY,CAAC;AAIpB,wBAAgB,gCAAgC,CAAC,KAAK,EAAE;IACtD,OAAO,EAAE,0BAA0B,GAAG,2BAA2B,CAAC;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,cAAc,CA4BjB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,0BAA0B,GAAG,2BAA2B,EACjE,YAAY,oBAAY,EACxB,KAAK,EAAE,uBAAuB,EAC9B,SAAS,UAAQ,GAChB,OAAO,CAAC,wBAAwB,CAAC,CASnC;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAKlH;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,0BAA0B,GAAG,2BAA2B,EACjE,YAAY,SAAY,EACxB,SAAS,UAAQ,GAChB,0BAA0B,CAI5B;AAED,wBAAgB,oCAAoC,CAAC,KAAK,GAAE,WAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAMjH"}
@@ -0,0 +1,126 @@
1
+ import { matchesSearchScope } from './local.js';
2
+ import { createExcerpt, stringMetadata, stringifyMetadata } from './utils.js';
3
+ export function createCloudflareAiSearchProvider(input) {
4
+ return {
5
+ name: 'cloudflare-ai-search',
6
+ index() {
7
+ // Cloudflare AI Search indexing is intentionally handled by CLI/provider sync.
8
+ },
9
+ async search(query) {
10
+ const maxResults = query.limit ?? 10;
11
+ const filters = createCloudflareAiSearchScopeFilters(query);
12
+ const result = await runCloudflareAiSearch(input.binding, input.instanceName, {
13
+ messages: [
14
+ {
15
+ role: 'user',
16
+ content: query.query
17
+ }
18
+ ],
19
+ ai_search_options: {
20
+ retrieval: {
21
+ retrieval_type: 'hybrid',
22
+ max_num_results: maxResults,
23
+ ...(filters ? { filters } : {})
24
+ }
25
+ }
26
+ }, input.namespace);
27
+ return normalizeCloudflareAiSearchResults(result, query.query)
28
+ .filter((record) => matchesSearchScope({ metadata: record.metadata }, query));
29
+ }
30
+ };
31
+ }
32
+ export async function runCloudflareAiSearch(binding, instanceName = 'svedocs', input, namespace = false) {
33
+ const instance = resolveAiSearchInstance(binding, instanceName, namespace);
34
+ const aiSearchOptions = createAiSearchOptions(input);
35
+ const messages = input.messages;
36
+ return instance.search({
37
+ ...(messages ? { messages } : {}),
38
+ ...(!messages && input.query ? { query: input.query } : {}),
39
+ ...(aiSearchOptions ? { ai_search_options: aiSearchOptions } : {})
40
+ });
41
+ }
42
+ export function normalizeCloudflareAiSearchResults(result, query) {
43
+ if (result.data?.length) {
44
+ return result.data.map((item, index) => createResultFromItem(item, index, query, result.response ?? result.answer));
45
+ }
46
+ return (result.chunks ?? []).map((chunk, index) => createResultFromChunk(chunk, index, query, result.response ?? result.answer));
47
+ }
48
+ export function resolveAiSearchInstance(binding, instanceName = 'svedocs', namespace = false) {
49
+ return namespace
50
+ ? binding.get(instanceName)
51
+ : binding;
52
+ }
53
+ export function createCloudflareAiSearchScopeFilters(scope = {}) {
54
+ const filters = {
55
+ ...(scope.locale ? { locale: scope.locale } : {}),
56
+ ...(scope.kind ? { kind: scope.kind } : {})
57
+ };
58
+ return Object.keys(filters).length > 0 ? filters : undefined;
59
+ }
60
+ function mergeRetrieval(options, retrieval) {
61
+ return {
62
+ ...(options ?? {}),
63
+ retrieval: {
64
+ ...(options?.retrieval ?? {}),
65
+ ...retrieval
66
+ }
67
+ };
68
+ }
69
+ function createAiSearchOptions(input) {
70
+ const retrieval = typeof input.max_num_results === 'number' ? { max_num_results: input.max_num_results } : {};
71
+ return input.ai_search_options || Object.keys(retrieval).length > 0
72
+ ? mergeRetrieval(input.ai_search_options, retrieval)
73
+ : undefined;
74
+ }
75
+ function createResultFromItem(item, index, query, fallbackContent = '') {
76
+ const metadata = normalizeCloudflareMetadata(item.metadata ?? {});
77
+ const section = stringMetadata(metadata.section);
78
+ return {
79
+ id: item.id ?? `cloudflare:${index}`,
80
+ title: item.title ?? stringMetadata(metadata.title) ?? 'Result',
81
+ url: item.url ?? stringMetadata(metadata.url) ?? '#',
82
+ ...(section ? { section } : {}),
83
+ excerpt: createExcerpt(item.content ?? item.text ?? fallbackContent, query),
84
+ score: typeof item.score === 'number' ? item.score : 1 / (index + 1),
85
+ metadata
86
+ };
87
+ }
88
+ function createResultFromChunk(chunk, index, query, fallbackContent = '') {
89
+ const metadata = normalizeCloudflareMetadata({
90
+ ...(chunk.attributes ?? {}),
91
+ ...(chunk.metadata ?? {}),
92
+ ...(chunk.item?.metadata ?? {})
93
+ });
94
+ const section = stringMetadata(metadata.section);
95
+ return {
96
+ id: chunk.id ?? stringMetadata(chunk.item?.id) ?? stringMetadata(chunk.item?.key) ?? `cloudflare:${index}`,
97
+ title: stringMetadata(metadata.title) ??
98
+ stringMetadata(chunk.item?.title) ??
99
+ stringMetadata(chunk.item?.filename) ??
100
+ stringMetadata(chunk.item?.key) ??
101
+ 'Result',
102
+ url: stringMetadata(metadata.url) ?? stringMetadata(metadata.source_url) ?? '#',
103
+ ...(section ? { section } : {}),
104
+ excerpt: createExcerpt(chunk.text ?? chunk.content ?? stringMetadata(metadata.content) ?? fallbackContent, query),
105
+ score: typeof chunk.score === 'number' ? chunk.score : 1 / (index + 1),
106
+ metadata
107
+ };
108
+ }
109
+ function normalizeCloudflareMetadata(metadata) {
110
+ const stringified = stringifyMetadata(metadata);
111
+ const embedded = stringMetadata(metadata.svedocs);
112
+ if (!embedded)
113
+ return stringified;
114
+ try {
115
+ const parsed = JSON.parse(embedded);
116
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
117
+ return stringified;
118
+ return {
119
+ ...stringified,
120
+ ...stringifyMetadata(parsed)
121
+ };
122
+ }
123
+ catch {
124
+ return stringified;
125
+ }
126
+ }
@@ -0,0 +1,9 @@
1
+ import type { SvedocsSearchRecord } from '../core.js';
2
+ import type { SearchProvider, SearchQuery, SearchResult, SearchScope } from './types.js';
3
+ export declare function createLocalSearchProvider(records?: SvedocsSearchRecord[]): SearchProvider;
4
+ export declare const localSearchProvider: SearchProvider;
5
+ export declare function searchRecords(records: SvedocsSearchRecord[], input: SearchQuery): SearchResult[];
6
+ export declare function filterSearchRecords(records: SvedocsSearchRecord[], scope?: SearchScope): SvedocsSearchRecord[];
7
+ export declare function matchesSearchScope(record: SvedocsSearchRecord, scope?: SearchScope): boolean;
8
+ export declare function createSearchResponse(records: SvedocsSearchRecord[], request: Request): Promise<Response>;
9
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/search/local.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgCzF,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,mBAAmB,EAAO,GAAG,cAAc,CAW7F;AAED,eAAO,MAAM,mBAAmB,gBAA8B,CAAC;AAE/D,wBAAgB,aAAa,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE,CA8BhG;AAyBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,mBAAmB,EAAE,EAC9B,KAAK,GAAE,WAAgB,GACtB,mBAAmB,EAAE,CAEvB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAGhG;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAa9G"}