katanakit-js 2.1.5

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 (153) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +22 -0
  3. package/README.md +446 -0
  4. package/dist/adapters/astro/astro.service.d.ts +18 -0
  5. package/dist/adapters/astro/astro.service.d.ts.map +1 -0
  6. package/dist/adapters/astro/astro.service.js +83 -0
  7. package/dist/adapters/astro/astro.service.js.map +1 -0
  8. package/dist/adapters/astro/index.d.ts +4 -0
  9. package/dist/adapters/astro/index.d.ts.map +1 -0
  10. package/dist/adapters/astro/index.js +4 -0
  11. package/dist/adapters/astro/index.js.map +1 -0
  12. package/dist/adapters/astro/rss.service.d.ts +115 -0
  13. package/dist/adapters/astro/rss.service.d.ts.map +1 -0
  14. package/dist/adapters/astro/rss.service.js +231 -0
  15. package/dist/adapters/astro/rss.service.js.map +1 -0
  16. package/dist/adapters/express/app.d.ts +4 -0
  17. package/dist/adapters/express/app.d.ts.map +1 -0
  18. package/dist/adapters/express/app.js +4 -0
  19. package/dist/adapters/express/app.js.map +1 -0
  20. package/dist/adapters/express/index.d.ts +5 -0
  21. package/dist/adapters/express/index.d.ts.map +1 -0
  22. package/dist/adapters/express/index.js +5 -0
  23. package/dist/adapters/express/index.js.map +1 -0
  24. package/dist/adapters/express/main.d.ts +2 -0
  25. package/dist/adapters/express/main.d.ts.map +1 -0
  26. package/dist/adapters/express/main.js +3 -0
  27. package/dist/adapters/express/main.js.map +1 -0
  28. package/dist/adapters/express/products.controller.d.ts +10 -0
  29. package/dist/adapters/express/products.controller.d.ts.map +1 -0
  30. package/dist/adapters/express/products.controller.js +53 -0
  31. package/dist/adapters/express/products.controller.js.map +1 -0
  32. package/dist/adapters/express/router.d.ts +3 -0
  33. package/dist/adapters/express/router.d.ts.map +1 -0
  34. package/dist/adapters/express/router.js +14 -0
  35. package/dist/adapters/express/router.js.map +1 -0
  36. package/dist/adapters/express/server.d.ts +15 -0
  37. package/dist/adapters/express/server.d.ts.map +1 -0
  38. package/dist/adapters/express/server.js +59 -0
  39. package/dist/adapters/express/server.js.map +1 -0
  40. package/dist/adapters/index.d.ts +2 -0
  41. package/dist/adapters/index.d.ts.map +1 -0
  42. package/dist/adapters/index.js +2 -0
  43. package/dist/adapters/index.js.map +1 -0
  44. package/dist/adapters/nuxt/index.d.ts +2 -0
  45. package/dist/adapters/nuxt/index.d.ts.map +1 -0
  46. package/dist/adapters/nuxt/index.js +2 -0
  47. package/dist/adapters/nuxt/index.js.map +1 -0
  48. package/dist/adapters/nuxt/nuxt.service.d.ts +83 -0
  49. package/dist/adapters/nuxt/nuxt.service.d.ts.map +1 -0
  50. package/dist/adapters/nuxt/nuxt.service.js +104 -0
  51. package/dist/adapters/nuxt/nuxt.service.js.map +1 -0
  52. package/dist/config/index.d.ts +3 -0
  53. package/dist/config/index.d.ts.map +1 -0
  54. package/dist/config/index.js +3 -0
  55. package/dist/config/index.js.map +1 -0
  56. package/dist/config/seo.service.d.ts +72 -0
  57. package/dist/config/seo.service.d.ts.map +1 -0
  58. package/dist/config/seo.service.js +190 -0
  59. package/dist/config/seo.service.js.map +1 -0
  60. package/dist/config/site.config.d.ts +89 -0
  61. package/dist/config/site.config.d.ts.map +1 -0
  62. package/dist/config/site.config.js +59 -0
  63. package/dist/config/site.config.js.map +1 -0
  64. package/dist/core/index.d.ts +13 -0
  65. package/dist/core/index.d.ts.map +1 -0
  66. package/dist/core/index.js +13 -0
  67. package/dist/core/index.js.map +1 -0
  68. package/dist/core/services/dates.service.d.ts +24 -0
  69. package/dist/core/services/dates.service.d.ts.map +1 -0
  70. package/dist/core/services/dates.service.js +64 -0
  71. package/dist/core/services/dates.service.js.map +1 -0
  72. package/dist/core/services/error.service.d.ts +25 -0
  73. package/dist/core/services/error.service.d.ts.map +1 -0
  74. package/dist/core/services/error.service.js +39 -0
  75. package/dist/core/services/error.service.js.map +1 -0
  76. package/dist/core/services/formatter.service.d.ts +36 -0
  77. package/dist/core/services/formatter.service.d.ts.map +1 -0
  78. package/dist/core/services/formatter.service.js +64 -0
  79. package/dist/core/services/formatter.service.js.map +1 -0
  80. package/dist/core/services/generator.service.d.ts +34 -0
  81. package/dist/core/services/generator.service.d.ts.map +1 -0
  82. package/dist/core/services/generator.service.js +83 -0
  83. package/dist/core/services/generator.service.js.map +1 -0
  84. package/dist/core/services/geometry.service.d.ts +45 -0
  85. package/dist/core/services/geometry.service.d.ts.map +1 -0
  86. package/dist/core/services/geometry.service.js +100 -0
  87. package/dist/core/services/geometry.service.js.map +1 -0
  88. package/dist/core/services/http.service.d.ts +22 -0
  89. package/dist/core/services/http.service.d.ts.map +1 -0
  90. package/dist/core/services/http.service.js +124 -0
  91. package/dist/core/services/http.service.js.map +1 -0
  92. package/dist/core/services/logger.service.d.ts +36 -0
  93. package/dist/core/services/logger.service.d.ts.map +1 -0
  94. package/dist/core/services/logger.service.js +60 -0
  95. package/dist/core/services/logger.service.js.map +1 -0
  96. package/dist/core/services/reactive.service.d.ts +22 -0
  97. package/dist/core/services/reactive.service.d.ts.map +1 -0
  98. package/dist/core/services/reactive.service.js +167 -0
  99. package/dist/core/services/reactive.service.js.map +1 -0
  100. package/dist/core/services/timing.service.d.ts +23 -0
  101. package/dist/core/services/timing.service.d.ts.map +1 -0
  102. package/dist/core/services/timing.service.js +217 -0
  103. package/dist/core/services/timing.service.js.map +1 -0
  104. package/dist/core/services/utils.service.d.ts +44 -0
  105. package/dist/core/services/utils.service.d.ts.map +1 -0
  106. package/dist/core/services/utils.service.js +143 -0
  107. package/dist/core/services/utils.service.js.map +1 -0
  108. package/dist/index.d.ts +6 -0
  109. package/dist/index.d.ts.map +1 -0
  110. package/dist/index.js +6 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/infrastructure/dom/dom.service.d.ts +49 -0
  113. package/dist/infrastructure/dom/dom.service.d.ts.map +1 -0
  114. package/dist/infrastructure/dom/dom.service.js +133 -0
  115. package/dist/infrastructure/dom/dom.service.js.map +1 -0
  116. package/dist/infrastructure/index.d.ts +11 -0
  117. package/dist/infrastructure/index.d.ts.map +1 -0
  118. package/dist/infrastructure/index.js +11 -0
  119. package/dist/infrastructure/index.js.map +1 -0
  120. package/dist/infrastructure/observer/observer.service.d.ts +34 -0
  121. package/dist/infrastructure/observer/observer.service.d.ts.map +1 -0
  122. package/dist/infrastructure/observer/observer.service.js +145 -0
  123. package/dist/infrastructure/observer/observer.service.js.map +1 -0
  124. package/dist/infrastructure/sensors/sensors.service.d.ts +25 -0
  125. package/dist/infrastructure/sensors/sensors.service.d.ts.map +1 -0
  126. package/dist/infrastructure/sensors/sensors.service.js +133 -0
  127. package/dist/infrastructure/sensors/sensors.service.js.map +1 -0
  128. package/dist/infrastructure/storage/storage.service.d.ts +48 -0
  129. package/dist/infrastructure/storage/storage.service.d.ts.map +1 -0
  130. package/dist/infrastructure/storage/storage.service.js +108 -0
  131. package/dist/infrastructure/storage/storage.service.js.map +1 -0
  132. package/dist/infrastructure/theme/theme.service.d.ts +30 -0
  133. package/dist/infrastructure/theme/theme.service.d.ts.map +1 -0
  134. package/dist/infrastructure/theme/theme.service.js +104 -0
  135. package/dist/infrastructure/theme/theme.service.js.map +1 -0
  136. package/dist/infrastructure/viewport/viewport.service.d.ts +38 -0
  137. package/dist/infrastructure/viewport/viewport.service.d.ts.map +1 -0
  138. package/dist/infrastructure/viewport/viewport.service.js +145 -0
  139. package/dist/infrastructure/viewport/viewport.service.js.map +1 -0
  140. package/dist/infrastructure/worker/worker.service.d.ts +42 -0
  141. package/dist/infrastructure/worker/worker.service.d.ts.map +1 -0
  142. package/dist/infrastructure/worker/worker.service.js +151 -0
  143. package/dist/infrastructure/worker/worker.service.js.map +1 -0
  144. package/dist/prisma/db.d.ts +4 -0
  145. package/dist/prisma/db.d.ts.map +1 -0
  146. package/dist/prisma/db.js +12 -0
  147. package/dist/prisma/db.js.map +1 -0
  148. package/dist/prisma/schema.json +411 -0
  149. package/dist/types/index.d.ts +436 -0
  150. package/dist/types/index.d.ts.map +1 -0
  151. package/dist/types/index.js +2 -0
  152. package/dist/types/index.js.map +1 -0
  153. package/package.json +117 -0
@@ -0,0 +1,4 @@
1
+ export * from "./astro.service.js";
2
+ export * from "./rss.service.js";
3
+ export { default as RssService } from "./rss.service.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/astro/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./astro.service.js";
2
+ export * from "./rss.service.js";
3
+ export { default as RssService } from "./rss.service.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/astro/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,115 @@
1
+ import type { SiteConfig } from "../../config/site.config.js";
2
+ import type { IRssService, RssConfig, RssItem, RssResult } from "../../types/index.js";
3
+ /**
4
+ * RSS service (Singleton + Facade). Generates RSS 2.0 feeds for Astro projects.
5
+ * Pure implementation — no external dependencies required.
6
+ *
7
+ * For projects using `@astrojs/rss`, use `useCreateRssEndpoint` which returns
8
+ * an Astro-compatible GET handler. For lighter setups, use `useGenerateRss`
9
+ * to get the raw XML string.
10
+ */
11
+ export default class RssService implements IRssService {
12
+ private static instance;
13
+ private constructor();
14
+ static getInstance(): RssService;
15
+ /**
16
+ * Generates the RSS XML string from a config.
17
+ * Returns a Safe Result (no throwing).
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const { useGenerateRss } = RssService.getInstance();
22
+ * const result = useGenerateRss({
23
+ * title: "My Blog",
24
+ * description: "Posts about TypeScript",
25
+ * site: "https://example.com",
26
+ * items: [{ title: "Hello", pubDate: new Date(), link: "/blog/hello/" }],
27
+ * });
28
+ * if (result.ok) console.log(result.data); // XML string
29
+ * ```
30
+ */
31
+ useGenerateRss: (config: RssConfig) => RssResult;
32
+ /**
33
+ * Generates an HTML `<link>` tag for the RSS feed.
34
+ * Paste this into your Astro layout's `<head>`.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const { useRssLinkTag } = RssService.getInstance();
39
+ * const tag = useRssLinkTag({ title: "My Blog" });
40
+ * // <link rel="alternate" type="application/rss+xml" title="My Blog" href="/rss.xml" />
41
+ * ```
42
+ */
43
+ useRssLinkTag: (config: Pick<RssConfig, "title" | "xmlPath">) => string;
44
+ /**
45
+ * Creates an Astro-compatible GET endpoint handler for the RSS feed.
46
+ * Use this in `src/pages/rss.xml.ts` to serve the feed.
47
+ *
48
+ * `items` can be a static array or a function (sync/async) that returns items.
49
+ * This allows using `getCollection` or any data source.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // src/pages/rss.xml.ts
54
+ * import { RssService } from "katanakit";
55
+ * import { getCollection } from "astro:content";
56
+ *
57
+ * const { useCreateRssEndpoint } = RssService.getInstance();
58
+ *
59
+ * export const GET = useCreateRssEndpoint({
60
+ * title: "My Blog",
61
+ * description: "Posts about TypeScript",
62
+ * site: "https://example.com",
63
+ * items: async () => {
64
+ * const posts = await getCollection("blog");
65
+ * return posts.map(post => ({
66
+ * title: post.data.title,
67
+ * pubDate: post.data.date,
68
+ * link: `/blog/${post.slug}/`,
69
+ * description: post.data.description,
70
+ * }));
71
+ * },
72
+ * });
73
+ * ```
74
+ */
75
+ useCreateRssEndpoint: (config: Omit<RssConfig, "items"> & {
76
+ items: RssItem[] | (() => RssItem[] | Promise<RssItem[]>);
77
+ }) => ((context: {
78
+ site?: URL | string;
79
+ }) => Promise<Response>);
80
+ /**
81
+ * Convenience method: creates an RSS endpoint from a SiteConfig.
82
+ * Reads title, description, site, and rss settings from the config.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // src/pages/rss.xml.ts
87
+ * import { RssService } from "katanakit";
88
+ * import { siteConfig } from "@/config/site.config";
89
+ * import { getCollection } from "astro:content";
90
+ *
91
+ * const { useCreateRssEndpointFromConfig } = RssService.getInstance();
92
+ *
93
+ * export const GET = useCreateRssEndpointFromConfig(siteConfig, async () => {
94
+ * const posts = await getCollection("blog");
95
+ * return posts.map(post => ({
96
+ * title: post.data.title,
97
+ * pubDate: post.data.date,
98
+ * link: `/blog/${post.slug}/`,
99
+ * description: post.data.description,
100
+ * }));
101
+ * });
102
+ * ```
103
+ */
104
+ useCreateRssEndpointFromConfig: (siteConfig: SiteConfig, items: RssItem[] | (() => RssItem[] | Promise<RssItem[]>)) => ((context: {
105
+ site?: URL | string;
106
+ }) => Promise<Response>);
107
+ }
108
+ export declare const useGenerateRss: (config: RssConfig) => RssResult, useRssLinkTag: (config: Pick<RssConfig, "title" | "xmlPath">) => string, useCreateRssEndpoint: (config: Omit<RssConfig, "items"> & {
109
+ items: RssItem[] | (() => RssItem[] | Promise<RssItem[]>);
110
+ }) => ((context: {
111
+ site?: URL | string;
112
+ }) => Promise<Response>), useCreateRssEndpointFromConfig: (siteConfig: SiteConfig, items: RssItem[] | (() => RssItem[] | Promise<RssItem[]>)) => ((context: {
113
+ site?: URL | string;
114
+ }) => Promise<Response>);
115
+ //# sourceMappingURL=rss.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.service.d.ts","sourceRoot":"","sources":["../../../src/adapters/astro/rss.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AA2EvF;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,YAAW,WAAW;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAa;IAEpC,OAAO,eAAiB;IAExB,OAAc,WAAW,IAAI,UAAU,CAKtC;IAED;;;;;;;;;;;;;;;OAeG;IACI,cAAc,WAAY,SAAS,KAAG,SAAS,CAsBpD;IAEF;;;;;;;;;;OAUG;IACI,aAAa,WAAY,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC,KAAG,MAAM,CAG3E;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACI,oBAAoB,WAClB,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG;QAClC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;KAC1D,KACC,CAAC,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,GAAG,GAAG,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAwC1D;IAEF;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACI,8BAA8B,eACxB,UAAU,SACf,OAAO,EAAE,GAAG,CAAC,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KACvD,CAAC,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,GAAG,GAAG,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAS1D;CACF;AAGD,eAAO,MACN,cAAc,WA9JmB,SAAS,KAAG,SAAS,EA+JtD,aAAa,WA5HmB,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC,KAAG,MAAM,EA6H7E,oBAAoB,WAxFX,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG;IAClC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;CAC1D,KACC,CAAC,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,GAAG,GAAG,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,EAsF5D,8BAA8B,eAnBjB,UAAU,SACf,OAAO,EAAE,GAAG,CAAC,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KACvD,CAAC,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,GAAG,GAAG,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAkBpB,CAAC"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Escapes special XML characters in a string.
3
+ */
4
+ function escapeXml(text) {
5
+ return text
6
+ .replace(/&/g, "&amp;")
7
+ .replace(/</g, "&lt;")
8
+ .replace(/>/g, "&gt;")
9
+ .replace(/"/g, "&quot;")
10
+ .replace(/'/g, "&apos;");
11
+ }
12
+ /**
13
+ * Formats a date as RFC-822 (required by RSS 2.0).
14
+ */
15
+ function toRfc822(date) {
16
+ const d = typeof date === "string" ? new Date(date) : date;
17
+ return d.toUTCString();
18
+ }
19
+ /**
20
+ * Builds the RSS 2.0 XML string from a config object.
21
+ * Pure function — no I/O, no dependencies.
22
+ */
23
+ function buildRssXml(config) {
24
+ const { title, description, site, items, language = "en", customData, xslUrl, lastBuildDate = true, } = config;
25
+ const siteUrl = site.endsWith("/") ? site.slice(0, -1) : site;
26
+ const xslProcessing = xslUrl
27
+ ? `<?xml-stylesheet type="text/xsl" href="${escapeXml(xslUrl)}" media="screen"?>\n`
28
+ : "";
29
+ const itemsXml = items
30
+ .map((item) => {
31
+ const link = item.link.startsWith("http") ? item.link : `${siteUrl}${item.link}`;
32
+ const categories = (item.categories ?? [])
33
+ .map((cat) => ` <category>${escapeXml(cat)}</category>`)
34
+ .join("\n");
35
+ return ` <item>
36
+ <title>${escapeXml(item.title)}</title>
37
+ <link>${escapeXml(link)}</link>
38
+ <guid isPermaLink="true">${escapeXml(link)}</guid>
39
+ <pubDate>${toRfc822(item.pubDate)}</pubDate>${item.description ? `\n <description>${escapeXml(item.description)}</description>` : ""}${item.content ? `\n <content:encoded><![CDATA[${item.content}]]></content:encoded>` : ""}${item.author ? `\n <author>${escapeXml(item.author)}</author>` : ""}${categories ? `\n${categories}` : ""}${item.customData ? `\n ${item.customData}` : ""}
40
+ </item>`;
41
+ })
42
+ .join("\n");
43
+ return `<?xml version="1.0" encoding="UTF-8"?>
44
+ ${xslProcessing}<rss version="2.0"
45
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
46
+ xmlns:atom="http://www.w3.org/2005/Atom">
47
+ <channel>
48
+ <title>${escapeXml(title)}</title>
49
+ <link>${escapeXml(siteUrl)}</link>
50
+ <description>${escapeXml(description)}</description>
51
+ <language>${escapeXml(language)}</language>
52
+ <atom:link href="${escapeXml(siteUrl)}${config.xmlPath ?? "/rss.xml"}" rel="self" type="application/rss+xml" />${lastBuildDate ? `\n <lastBuildDate>${toRfc822(new Date())}</lastBuildDate>` : ""}${customData ? `\n ${customData}` : ""}
53
+ ${itemsXml}
54
+ </channel>
55
+ </rss>`;
56
+ }
57
+ /**
58
+ * RSS service (Singleton + Facade). Generates RSS 2.0 feeds for Astro projects.
59
+ * Pure implementation — no external dependencies required.
60
+ *
61
+ * For projects using `@astrojs/rss`, use `useCreateRssEndpoint` which returns
62
+ * an Astro-compatible GET handler. For lighter setups, use `useGenerateRss`
63
+ * to get the raw XML string.
64
+ */
65
+ export default class RssService {
66
+ static instance;
67
+ constructor() { }
68
+ static getInstance() {
69
+ if (!RssService.instance) {
70
+ RssService.instance = new RssService();
71
+ }
72
+ return RssService.instance;
73
+ }
74
+ /**
75
+ * Generates the RSS XML string from a config.
76
+ * Returns a Safe Result (no throwing).
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * const { useGenerateRss } = RssService.getInstance();
81
+ * const result = useGenerateRss({
82
+ * title: "My Blog",
83
+ * description: "Posts about TypeScript",
84
+ * site: "https://example.com",
85
+ * items: [{ title: "Hello", pubDate: new Date(), link: "/blog/hello/" }],
86
+ * });
87
+ * if (result.ok) console.log(result.data); // XML string
88
+ * ```
89
+ */
90
+ useGenerateRss = (config) => {
91
+ try {
92
+ if (!config.title || !config.site) {
93
+ return {
94
+ data: null,
95
+ error: { message: "RSS config requires 'title' and 'site'." },
96
+ ok: false,
97
+ };
98
+ }
99
+ const xml = buildRssXml(config);
100
+ return { data: xml, error: null, ok: true };
101
+ }
102
+ catch (err) {
103
+ return {
104
+ data: null,
105
+ error: {
106
+ message: "Failed to generate RSS feed.",
107
+ details: err instanceof Error ? err.message : String(err),
108
+ },
109
+ ok: false,
110
+ };
111
+ }
112
+ };
113
+ /**
114
+ * Generates an HTML `<link>` tag for the RSS feed.
115
+ * Paste this into your Astro layout's `<head>`.
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * const { useRssLinkTag } = RssService.getInstance();
120
+ * const tag = useRssLinkTag({ title: "My Blog" });
121
+ * // <link rel="alternate" type="application/rss+xml" title="My Blog" href="/rss.xml" />
122
+ * ```
123
+ */
124
+ useRssLinkTag = (config) => {
125
+ const xmlPath = config.xmlPath ?? "/rss.xml";
126
+ return `<link rel="alternate" type="application/rss+xml" title="${escapeXml(config.title)}" href="${escapeXml(xmlPath)}" />`;
127
+ };
128
+ /**
129
+ * Creates an Astro-compatible GET endpoint handler for the RSS feed.
130
+ * Use this in `src/pages/rss.xml.ts` to serve the feed.
131
+ *
132
+ * `items` can be a static array or a function (sync/async) that returns items.
133
+ * This allows using `getCollection` or any data source.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * // src/pages/rss.xml.ts
138
+ * import { RssService } from "katanakit";
139
+ * import { getCollection } from "astro:content";
140
+ *
141
+ * const { useCreateRssEndpoint } = RssService.getInstance();
142
+ *
143
+ * export const GET = useCreateRssEndpoint({
144
+ * title: "My Blog",
145
+ * description: "Posts about TypeScript",
146
+ * site: "https://example.com",
147
+ * items: async () => {
148
+ * const posts = await getCollection("blog");
149
+ * return posts.map(post => ({
150
+ * title: post.data.title,
151
+ * pubDate: post.data.date,
152
+ * link: `/blog/${post.slug}/`,
153
+ * description: post.data.description,
154
+ * }));
155
+ * },
156
+ * });
157
+ * ```
158
+ */
159
+ useCreateRssEndpoint = (config) => {
160
+ return async (context) => {
161
+ try {
162
+ // Resolve items (static array or factory function).
163
+ const resolvedItems = typeof config.items === "function" ? await config.items() : config.items;
164
+ // Use context.site as fallback for the site URL.
165
+ const site = config.site || (context.site ? String(context.site) : "");
166
+ if (!site) {
167
+ return new Response(JSON.stringify({ error: "RSS feed requires a 'site' URL." }), {
168
+ status: 500,
169
+ headers: { "Content-Type": "application/json" },
170
+ });
171
+ }
172
+ const result = useGenerateRss({ ...config, site, items: resolvedItems });
173
+ if (!result.ok) {
174
+ return new Response(JSON.stringify({ error: result.error.message }), {
175
+ status: 500,
176
+ headers: { "Content-Type": "application/json" },
177
+ });
178
+ }
179
+ return new Response(result.data, {
180
+ status: 200,
181
+ headers: {
182
+ "Content-Type": "application/xml; charset=utf-8",
183
+ "Cache-Control": "public, max-age=3600",
184
+ },
185
+ });
186
+ }
187
+ catch (err) {
188
+ return new Response(JSON.stringify({
189
+ error: err instanceof Error ? err.message : "Unknown error generating RSS.",
190
+ }), { status: 500, headers: { "Content-Type": "application/json" } });
191
+ }
192
+ };
193
+ };
194
+ /**
195
+ * Convenience method: creates an RSS endpoint from a SiteConfig.
196
+ * Reads title, description, site, and rss settings from the config.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * // src/pages/rss.xml.ts
201
+ * import { RssService } from "katanakit";
202
+ * import { siteConfig } from "@/config/site.config";
203
+ * import { getCollection } from "astro:content";
204
+ *
205
+ * const { useCreateRssEndpointFromConfig } = RssService.getInstance();
206
+ *
207
+ * export const GET = useCreateRssEndpointFromConfig(siteConfig, async () => {
208
+ * const posts = await getCollection("blog");
209
+ * return posts.map(post => ({
210
+ * title: post.data.title,
211
+ * pubDate: post.data.date,
212
+ * link: `/blog/${post.slug}/`,
213
+ * description: post.data.description,
214
+ * }));
215
+ * });
216
+ * ```
217
+ */
218
+ useCreateRssEndpointFromConfig = (siteConfig, items) => {
219
+ return this.useCreateRssEndpoint({
220
+ title: siteConfig.rss.title ?? siteConfig.title,
221
+ description: siteConfig.rss.description ?? siteConfig.description,
222
+ site: siteConfig.site,
223
+ items,
224
+ xmlPath: siteConfig.rss.path,
225
+ language: siteConfig.lang,
226
+ });
227
+ };
228
+ }
229
+ // Singleton instance and destructured exports.
230
+ export const { useGenerateRss, useRssLinkTag, useCreateRssEndpoint, useCreateRssEndpointFromConfig, } = RssService.getInstance();
231
+ //# sourceMappingURL=rss.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.service.js","sourceRoot":"","sources":["../../../src/adapters/astro/rss.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Application } from "express";
2
+ export declare const useGetApp: () => Application, useStart: () => void;
3
+ export declare const app: Application;
4
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAI3C,eAAO,MAAQ,SAAS,qBAAE,QAAQ,YAA+C,CAAC;AAElF,eAAO,MAAM,GAAG,EAAE,WAAyB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import ServerExpress from "./server.js";
2
+ export const { useGetApp, useStart } = ServerExpress.getInstance();
3
+ export const app = useGetApp();
4
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/adapters/express/app.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,MAAM,aAAa,CAAC;AAExC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAkB,aAAa,CAAC,WAAW,EAAE,CAAC;AAElF,MAAM,CAAC,MAAM,GAAG,GAAgB,SAAS,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { app, useGetApp, useStart } from "./app.js";
2
+ export { ProductController } from "./products.controller.js";
3
+ export { default as router } from "./router.js";
4
+ export { default as ServerExpress } from "./server.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { app, useGetApp, useStart } from "./app.js";
2
+ export { ProductController } from "./products.controller.js";
3
+ export { default as router } from "./router.js";
4
+ export { default as ServerExpress } from "./server.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import ServerExpress from "./server.js";
2
+ ServerExpress.getInstance().useStart();
3
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/adapters/express/main.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,aAAa,CAAC;AAExC,aAAa,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Request, Response } from "express";
2
+ export declare class ProductController {
3
+ private products;
4
+ useGetAll(_request: Request, response: Response): void;
5
+ useGetProductById(request: Request, response: Response): void;
6
+ useCreateProduct(request: Request, response: Response): void;
7
+ useUpsertProduct(request: Request, response: Response): void;
8
+ useDeleteProductById(request: Request, response: Response): void;
9
+ }
10
+ //# sourceMappingURL=products.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.controller.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/products.controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjD,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAqB;IAGrC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAErD;IAGD,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAU5D;IAGD,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAc3D;IAGD,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAiB3D;IAGD,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAW/D;CACD"}
@@ -0,0 +1,53 @@
1
+ export class ProductController {
2
+ products = [];
3
+ // GET /products
4
+ useGetAll(_request, response) {
5
+ response.json(this.products);
6
+ }
7
+ // GET /products/:id
8
+ useGetProductById(request, response) {
9
+ const id = Number.parseInt(String(request.params.id), 10);
10
+ const product = this.products.find((item) => item.id === id);
11
+ if (!product) {
12
+ response.status(404).json({ error: "Product not found" });
13
+ return;
14
+ }
15
+ response.json({ productById: product });
16
+ }
17
+ // POST /products
18
+ useCreateProduct(request, response) {
19
+ const { name = "", price = 0 } = (request.body ?? {});
20
+ const product = {
21
+ id: this.products.length + 1,
22
+ name,
23
+ price: Number(price),
24
+ };
25
+ this.products.push(product);
26
+ response.status(201).json(product);
27
+ }
28
+ // PUT /products/:id
29
+ useUpsertProduct(request, response) {
30
+ const id = Number.parseInt(String(request.params.id), 10);
31
+ const product = this.products.find((item) => item.id === id);
32
+ if (!product) {
33
+ response.status(404).json({ error: "Product not found" });
34
+ return;
35
+ }
36
+ const { name, price } = (request.body ?? {});
37
+ product.name = name ?? product.name;
38
+ product.price = Number(price ?? product.price);
39
+ response.json(product);
40
+ }
41
+ // DELETE /products/:id
42
+ useDeleteProductById(request, response) {
43
+ const id = Number.parseInt(String(request.params.id), 10);
44
+ const index = this.products.findIndex((item) => item.id === id);
45
+ if (index === -1) {
46
+ response.status(404).json({ error: "Product not found" });
47
+ return;
48
+ }
49
+ this.products.splice(index, 1);
50
+ response.status(204).send();
51
+ }
52
+ }
53
+ //# sourceMappingURL=products.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.controller.js","sourceRoot":"","sources":["../../../src/adapters/express/products.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/router.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,MAAM,4CAAW,CAAC;eAeT,MAAM"}
@@ -0,0 +1,14 @@
1
+ import { Router } from "express";
2
+ const router = Router();
3
+ router.get("/", (_request, response) => {
4
+ response.json({ message: "Get all users" });
5
+ });
6
+ router.get("/:id", (request, response) => {
7
+ const { id = "" } = request.params;
8
+ response.json({ message: `Get user by ${id}` });
9
+ });
10
+ router.post("/", (_request, response) => {
11
+ response.json({ message: "Create a new user" });
12
+ });
13
+ export default router;
14
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/adapters/express/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAE9D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,QAAiB,EAAE,QAAkB,EAAE,EAAE;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,OAAgB,EAAE,QAAkB,EAAE,EAAE;IAC3D,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAiB,EAAE,QAAkB,EAAE,EAAE;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type Application } from "express";
2
+ export default class ServerExpress {
3
+ private static instance;
4
+ private readonly app;
5
+ private readonly port;
6
+ private readonly host;
7
+ private constructor();
8
+ static getInstance(): ServerExpress;
9
+ useStart: () => void;
10
+ useGetApp: () => Application;
11
+ private setupMiddlewares;
12
+ private setupRoutes;
13
+ private setupErrorHandling;
14
+ }
15
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/adapters/express/server.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,KAAK,WAAW,EAAkD,MAAM,SAAS,CAAC;AAKpG,MAAM,CAAC,OAAO,OAAO,aAAa;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,OAAO,eAIN;IAED,MAAM,CAAC,WAAW,IAAI,aAAa,CAKlC;IAED,QAAQ,QAAO,IAAI,CAQjB;IAEF,SAAS,QAAO,WAAW,CAAa;IAExC,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,kBAAkB;CAU1B"}
@@ -0,0 +1,59 @@
1
+ import cors from "cors";
2
+ import express from "express";
3
+ import { useLog } from "../../core/services/logger.service.js";
4
+ import router from "./router.js";
5
+ export default class ServerExpress {
6
+ static instance;
7
+ app;
8
+ port;
9
+ host;
10
+ constructor(port = 3000, host = "localhost") {
11
+ this.app = express();
12
+ this.port = port;
13
+ this.host = host;
14
+ }
15
+ static getInstance() {
16
+ if (!ServerExpress.instance) {
17
+ ServerExpress.instance = new ServerExpress();
18
+ }
19
+ return ServerExpress.instance;
20
+ }
21
+ useStart = () => {
22
+ this.setupMiddlewares();
23
+ this.setupRoutes();
24
+ this.setupErrorHandling();
25
+ this.app.listen(this.port, this.host, () => {
26
+ useLog(`Server running on http://${this.host}:${this.port}`);
27
+ });
28
+ };
29
+ useGetApp = () => this.app;
30
+ setupMiddlewares() {
31
+ // Restrict CORS to configured origins (defaults to localhost).
32
+ this.app.use(cors({
33
+ origin: process.env.CORS_ORIGINS?.split(",") ?? ["http://localhost:3000"],
34
+ methods: ["GET", "POST", "PUT", "DELETE"],
35
+ }));
36
+ this.app.disable("x-powered-by");
37
+ this.app.use(express.json({ limit: "100kb" }));
38
+ this.app.use(express.urlencoded({ extended: true, limit: "100kb" }));
39
+ }
40
+ setupRoutes() {
41
+ this.app.get("/health", (_request, response) => {
42
+ return response.json({
43
+ status: "ok",
44
+ timestamp: new Date().toISOString(),
45
+ });
46
+ });
47
+ this.app.use("/", router);
48
+ }
49
+ setupErrorHandling() {
50
+ this.app.use((err, _req, res, _next) => {
51
+ console.error("Unhandled error:", err);
52
+ res.status(500).json({ error: "Internal Server Error" });
53
+ });
54
+ this.app.use((_req, res) => {
55
+ res.status(404).json({ error: "Not Found" });
56
+ });
57
+ }
58
+ }
59
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/adapters/express/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from "./astro/index.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}