katanakit-js 2.1.6 → 2.12.9

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 (152) hide show
  1. package/README.md +73 -385
  2. package/dist/adapters/astro/astro.service.d.ts +103 -15
  3. package/dist/adapters/astro/astro.service.d.ts.map +1 -1
  4. package/dist/adapters/astro/astro.service.js +145 -75
  5. package/dist/adapters/astro/astro.service.js.map +1 -1
  6. package/dist/adapters/astro/index.d.ts +1 -1
  7. package/dist/adapters/astro/index.d.ts.map +1 -1
  8. package/dist/adapters/astro/index.js +1 -1
  9. package/dist/adapters/astro/index.js.map +1 -1
  10. package/dist/adapters/astro/rss.service.d.ts +85 -105
  11. package/dist/adapters/astro/rss.service.d.ts.map +1 -1
  12. package/dist/adapters/astro/rss.service.js +172 -168
  13. package/dist/adapters/astro/rss.service.js.map +1 -1
  14. package/dist/adapters/astro/seo.service.d.ts +10 -0
  15. package/dist/adapters/astro/seo.service.d.ts.map +1 -0
  16. package/dist/adapters/astro/seo.service.js +3 -0
  17. package/dist/adapters/astro/seo.service.js.map +1 -0
  18. package/dist/adapters/express/app.d.ts +30 -1
  19. package/dist/adapters/express/app.d.ts.map +1 -1
  20. package/dist/adapters/express/app.js +31 -3
  21. package/dist/adapters/express/app.js.map +1 -1
  22. package/dist/adapters/express/index.d.ts +2 -2
  23. package/dist/adapters/express/index.d.ts.map +1 -1
  24. package/dist/adapters/express/index.js +2 -2
  25. package/dist/adapters/express/index.js.map +1 -1
  26. package/dist/adapters/express/main.js +2 -2
  27. package/dist/adapters/express/main.js.map +1 -1
  28. package/dist/adapters/express/products.controller.d.ts +67 -8
  29. package/dist/adapters/express/products.controller.d.ts.map +1 -1
  30. package/dist/adapters/express/products.controller.js +105 -49
  31. package/dist/adapters/express/products.controller.js.map +1 -1
  32. package/dist/adapters/express/server.d.ts +37 -13
  33. package/dist/adapters/express/server.d.ts.map +1 -1
  34. package/dist/adapters/express/server.js +118 -53
  35. package/dist/adapters/express/server.js.map +1 -1
  36. package/dist/adapters/nuxt/nuxt.service.d.ts +8 -6
  37. package/dist/adapters/nuxt/nuxt.service.d.ts.map +1 -1
  38. package/dist/adapters/nuxt/nuxt.service.js +34 -10
  39. package/dist/adapters/nuxt/nuxt.service.js.map +1 -1
  40. package/dist/adapters/vue/index.d.ts +2 -0
  41. package/dist/adapters/vue/index.d.ts.map +1 -0
  42. package/dist/adapters/vue/index.js +2 -0
  43. package/dist/adapters/vue/index.js.map +1 -0
  44. package/dist/adapters/vue/vue.service.d.ts +44 -0
  45. package/dist/adapters/vue/vue.service.d.ts.map +1 -0
  46. package/dist/adapters/vue/vue.service.js +85 -0
  47. package/dist/adapters/vue/vue.service.js.map +1 -0
  48. package/dist/config/index.d.ts +2 -1
  49. package/dist/config/index.d.ts.map +1 -1
  50. package/dist/config/index.js +1 -1
  51. package/dist/config/index.js.map +1 -1
  52. package/dist/config/seo-meta.types.d.ts +177 -0
  53. package/dist/config/seo-meta.types.d.ts.map +1 -0
  54. package/dist/config/seo-meta.types.js +11 -0
  55. package/dist/config/seo-meta.types.js.map +1 -0
  56. package/dist/config/seo.service.d.ts +41 -58
  57. package/dist/config/seo.service.d.ts.map +1 -1
  58. package/dist/config/seo.service.js +468 -136
  59. package/dist/config/seo.service.js.map +1 -1
  60. package/dist/config/site.config.d.ts +10 -50
  61. package/dist/config/site.config.d.ts.map +1 -1
  62. package/dist/config/site.config.js +8 -36
  63. package/dist/config/site.config.js.map +1 -1
  64. package/dist/core/index.d.ts +1 -3
  65. package/dist/core/index.d.ts.map +1 -1
  66. package/dist/core/index.js +1 -3
  67. package/dist/core/index.js.map +1 -1
  68. package/dist/core/services/dates.service.d.ts +149 -22
  69. package/dist/core/services/dates.service.d.ts.map +1 -1
  70. package/dist/core/services/dates.service.js +201 -54
  71. package/dist/core/services/dates.service.js.map +1 -1
  72. package/dist/core/services/error.service.d.ts +32 -20
  73. package/dist/core/services/error.service.d.ts.map +1 -1
  74. package/dist/core/services/error.service.js +44 -32
  75. package/dist/core/services/error.service.js.map +1 -1
  76. package/dist/core/services/formatter.service.d.ts +245 -35
  77. package/dist/core/services/formatter.service.d.ts.map +1 -1
  78. package/dist/core/services/formatter.service.js +281 -57
  79. package/dist/core/services/formatter.service.js.map +1 -1
  80. package/dist/core/services/generator.service.d.ts +115 -26
  81. package/dist/core/services/generator.service.d.ts.map +1 -1
  82. package/dist/core/services/generator.service.js +191 -56
  83. package/dist/core/services/generator.service.js.map +1 -1
  84. package/dist/core/services/geometry.service.d.ts +369 -39
  85. package/dist/core/services/geometry.service.d.ts.map +1 -1
  86. package/dist/core/services/geometry.service.js +424 -66
  87. package/dist/core/services/geometry.service.js.map +1 -1
  88. package/dist/core/services/http.service.d.ts +244 -21
  89. package/dist/core/services/http.service.d.ts.map +1 -1
  90. package/dist/core/services/http.service.js +419 -98
  91. package/dist/core/services/http.service.js.map +1 -1
  92. package/dist/core/services/logger.service.d.ts +95 -29
  93. package/dist/core/services/logger.service.d.ts.map +1 -1
  94. package/dist/core/services/logger.service.js +167 -41
  95. package/dist/core/services/logger.service.js.map +1 -1
  96. package/dist/core/services/reactive.service.d.ts +146 -19
  97. package/dist/core/services/reactive.service.d.ts.map +1 -1
  98. package/dist/core/services/reactive.service.js +278 -137
  99. package/dist/core/services/reactive.service.js.map +1 -1
  100. package/dist/core/services/timing.service.d.ts +142 -20
  101. package/dist/core/services/timing.service.d.ts.map +1 -1
  102. package/dist/core/services/timing.service.js +324 -185
  103. package/dist/core/services/timing.service.js.map +1 -1
  104. package/dist/core/services/utils.service.d.ts +228 -43
  105. package/dist/core/services/utils.service.d.ts.map +1 -1
  106. package/dist/core/services/utils.service.js +305 -125
  107. package/dist/core/services/utils.service.js.map +1 -1
  108. package/dist/infrastructure/dom/dom.service.d.ts +307 -44
  109. package/dist/infrastructure/dom/dom.service.d.ts.map +1 -1
  110. package/dist/infrastructure/dom/dom.service.js +408 -129
  111. package/dist/infrastructure/dom/dom.service.js.map +1 -1
  112. package/dist/infrastructure/index.d.ts +0 -3
  113. package/dist/infrastructure/index.d.ts.map +1 -1
  114. package/dist/infrastructure/index.js +0 -3
  115. package/dist/infrastructure/index.js.map +1 -1
  116. package/dist/infrastructure/observer/observer.service.d.ts +124 -31
  117. package/dist/infrastructure/observer/observer.service.d.ts.map +1 -1
  118. package/dist/infrastructure/observer/observer.service.js +227 -131
  119. package/dist/infrastructure/observer/observer.service.js.map +1 -1
  120. package/dist/infrastructure/sensors/sensors.service.d.ts +154 -22
  121. package/dist/infrastructure/sensors/sensors.service.d.ts.map +1 -1
  122. package/dist/infrastructure/sensors/sensors.service.js +264 -112
  123. package/dist/infrastructure/sensors/sensors.service.js.map +1 -1
  124. package/dist/infrastructure/storage/storage.service.d.ts +123 -45
  125. package/dist/infrastructure/storage/storage.service.d.ts.map +1 -1
  126. package/dist/infrastructure/storage/storage.service.js +236 -66
  127. package/dist/infrastructure/storage/storage.service.js.map +1 -1
  128. package/dist/infrastructure/theme/theme.service.d.ts +93 -29
  129. package/dist/infrastructure/theme/theme.service.d.ts.map +1 -1
  130. package/dist/infrastructure/theme/theme.service.js +198 -96
  131. package/dist/infrastructure/theme/theme.service.js.map +1 -1
  132. package/dist/infrastructure/viewport/viewport.service.d.ts +233 -35
  133. package/dist/infrastructure/viewport/viewport.service.d.ts.map +1 -1
  134. package/dist/infrastructure/viewport/viewport.service.js +358 -139
  135. package/dist/infrastructure/viewport/viewport.service.js.map +1 -1
  136. package/dist/infrastructure/worker/worker.service.d.ts +84 -38
  137. package/dist/infrastructure/worker/worker.service.d.ts.map +1 -1
  138. package/dist/infrastructure/worker/worker.service.js +234 -133
  139. package/dist/infrastructure/worker/worker.service.js.map +1 -1
  140. package/dist/prisma/index.d.ts +2 -0
  141. package/dist/prisma/index.d.ts.map +1 -0
  142. package/dist/prisma/index.js +2 -0
  143. package/dist/prisma/index.js.map +1 -0
  144. package/dist/prisma/schema.json +11 -33
  145. package/dist/prisma/use-prisma.d.ts +68 -0
  146. package/dist/prisma/use-prisma.d.ts.map +1 -0
  147. package/dist/prisma/use-prisma.js +82 -0
  148. package/dist/prisma/use-prisma.js.map +1 -0
  149. package/dist/types/index.d.ts +20 -12
  150. package/dist/types/index.d.ts.map +1 -1
  151. package/package.json +124 -115
  152. package/CHANGELOG.md +0 -96
package/README.md CHANGED
@@ -1,61 +1,6 @@
1
- # KatanaKit (`katanakit-js`)
2
-
3
- KatanaKit is a sharp, framework-agnostic **TypeScript service toolkit** organized
4
- with **hexagonal architecture** and built on proven design patterns (Singleton,
5
- Observer, Factory, Strategy, Facade and Adapter).
6
-
7
- It runs in the browser, in Node.js (>= 22.18) and in Bun, ships with an Astro
8
- `getStaticPaths` adapter, an RSS 2.0 generator, a site-config/SEO module, an
9
- optional Express server reference and a Nuxt (Nitro/H3) adapter. Importing a
10
- module never triggers side effects, and every async operation returns a **Safe
11
- Result** instead of throwing.
12
-
13
- - **Version:** 2.1.4
14
- - **npm package:** `katanakit-js`
15
- - **Repository:** [senseikatana/katanakit](https://github.com/senseikatana/katanakit)
16
- (development happens on the `dev` branch)
17
- - **License:** MIT
18
-
19
- ## Why
20
-
21
- Modern frontend and full-stack apps keep reimplementing the same plumbing:
22
- fetching an API safely, logging, persisting to storage, querying the DOM,
23
- reacting to state changes, generating slugs, formatting dates and money,
24
- building RSS/SEO output. KatanaKit provides all of that as a single, typed and
25
- tree-shakeable set of `use*` services with a consistent API: one `useInit` for
26
- your APIs, one `useFetch` that returns a Safe Result, one way to do logging,
27
- storage and DOM across every framework.
1
+ # `katanakit-js`
28
2
 
29
- ## Features
30
-
31
- - **Safe URL construction** — builds URLs from a JSON-defined API registry using
32
- the native `URL` API and `encodeURIComponent`; only `http:`/`https:` schemes
33
- are allowed (prevents `javascript:` URLs and SSRF).
34
- - **Safe Result** — every `useFetch` returns a discriminated union
35
- `{ data, error, url, status, ok }` (Astro Actions style) instead of throwing
36
- on HTTP errors.
37
- - **Hexagonal architecture** — a pure `core` layer (services), an
38
- `infrastructure` layer (browser/runtime adapters), an `adapters` layer
39
- (Astro, Express, Nuxt), a `config` layer (site config + SEO) and a single
40
- source of truth for contracts and types in `src/types/`.
41
- - **Design patterns** — Singleton facades, Strategy (logger, storage,
42
- crypto/UUID), Factory (errors, debounce/throttle), Observer (signals,
43
- IntersectionObserver, media queries), Facade and Adapter, all exposed as
44
- `use*` methods (like React hooks) with safe destructured exports.
45
- - **Consistent `use*` API** — every public method is prefixed with `use`
46
- (`useInit`, `useFetch`, `useLog`, `useCreateSignal`, ...); the only exception
47
- is `getInstance()`.
48
- - **Pure ESM** — relative imports use explicit `.js` extensions and
49
- `module: nodenext`; bundlers and Node resolve the package cleanly.
50
- - **Zero side effects on import** — importing a module never triggers network
51
- calls, timers, storage writes or DOM mutations.
52
- - **SSR-safe** — browser-only adapters guard or fall back gracefully
53
- (in-memory storage, main-thread worker execution) when `window` is
54
- unavailable.
55
- - **Optional heavy dependencies** — only `@js-temporal/polyfill` is a runtime
56
- dependency; `express`, `cors`, `dotenv` and `@prisma/orm-postgres` are
57
- optional peer dependencies.
58
- - **Fully typed** — strict TypeScript with generated `.d.ts` declarations.
3
+ A sharp, framework-agnostic TypeScript service toolkit organized with hexagonal architecture.
59
4
 
60
5
  ## Installation
61
6
 
@@ -63,384 +8,127 @@ storage and DOM across every framework.
63
8
  npm install katanakit-js
64
9
  # or
65
10
  bun add katanakit-js
11
+ # or
12
+ yarn add katanakit-js
66
13
  ```
67
14
 
68
- Requirements: **Node.js >= 22.18.0** (pure ESM package). TypeScript consumers
69
- should use `moduleResolution: "nodenext"` (or `"bundler"`).
15
+ ### CDN (ESM)
70
16
 
71
- ### Framework adapters
17
+ In the browser, use jsDelivr **`/+esm`** so named exports and dependencies resolve:
72
18
 
73
- The root import is framework-agnostic. Framework-specific entry points are
74
- published as package **subpaths** of the same `katanakit-js` package:
75
-
76
- ```ts
77
- // Nuxt / Nitro adapter helpers (no extra dependency; h3 ships with Nuxt)
78
- import { useUnwrap } from "katanakit-js/adapters/nuxt";
79
-
80
- // Express reference server (requires express as a peer dependency)
81
- import { ServerExpress } from "katanakit-js/adapters/express";
19
+ ```html
20
+ <script type="module">
21
+ import { useLogger, useGetApi, useInitApis } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
22
+ useLogger("ready");
23
+ </script>
82
24
  ```
83
25
 
84
- `express`, `cors`, `dotenv` and `@prisma/orm-postgres` are **optional peer
85
- dependencies** — install them only if you use the Express adapter or the Prisma
86
- layer.
87
-
88
- ### Building from source
26
+ | CDN | URL |
27
+ |-----|-----|
28
+ | **jsDelivr `/+esm`** (recommended) | `https://cdn.jsdelivr.net/npm/katanakit-js/+esm` |
29
+ | **esm.sh** | `https://esm.sh/katanakit-js` |
30
+ | **Raw ESM file** | `https://cdn.jsdelivr.net/npm/katanakit-js/dist/index.js` (needs bundler or import map) |
89
31
 
90
- ```bash
91
- git clone https://github.com/senseikatana/katanakit.git
92
- cd katanakit
93
- bun install
94
- bun run build # outputs to dist/
95
- ```
32
+ Pin a version in production (e.g. `@2.8.0/+esm`). There is no IIFE/UMD build.
96
33
 
97
34
  ## Quick Start
98
35
 
99
- Everything below is importable from the main barrel `katanakit-js`.
100
-
101
- ### HTTP client
102
-
103
36
  ```ts
104
- import { useInit, useGet, usePost, useBuildUrl } from "katanakit-js";
37
+ import { useInitApis, useGetApi, useLogger } from "katanakit-js";
38
+
39
+ useLogger("boot");
105
40
 
106
- // 1. Register your APIs once.
107
- useInit({
41
+ // Register your APIs once
42
+ useInitApis({
108
43
  pokeapi: {
109
44
  baseUri: "https://pokeapi.co/api/v2",
110
- endpoints: {
111
- pokemonById: "/pokemon/:id/",
112
- pokemons: "/pokemons/",
113
- },
45
+ endpoints: { pokemonById: "/pokemon/:id/" },
114
46
  },
115
47
  });
116
48
 
117
- // 2. Build a safe URL (path params encoded, query params merged).
118
- const url = useBuildUrl("pokeapi", "pokemonById", {
119
- params: { id: "pikachu" },
120
- });
121
- // => "https://pokeapi.co/api/v2/pokemon/pikachu/"
122
-
123
- // 3. Fetch with a Safe Result (no throwing on HTTP errors).
124
- const result = await useGet<{ name: string }>("pokeapi", "pokemonById", {
49
+ // Fetch with Safe Result no try/catch needed for HTTP failures
50
+ const result = await useGetApi<{ name: string }>("pokeapi", "pokemonById", {
125
51
  params: { id: 25 },
126
52
  });
127
53
 
128
54
  if (result.ok) {
129
- console.log(result.data.name);
55
+ console.log(result.data.name); // "pikachu"
130
56
  } else {
131
- console.error(result.error.message, result.error.status);
57
+ console.error(result.error.message);
132
58
  }
133
-
134
- // 4. POST JSON.
135
- await usePost("pokeapi", "pokemons", { name: "charmander" });
136
59
  ```
137
60
 
138
- ### Logger, storage and DOM
139
-
140
- ```ts
141
- import {
142
- useLog,
143
- useSetStorage,
144
- useGetStorage,
145
- useRemoveStorage,
146
- useAddClass,
147
- useGetRoot,
148
- } from "katanakit-js";
149
-
150
- useLog("Hello", { user: "John" }); // info level
151
- useLog("error", "Something failed", { code: 500 }); // error level
152
-
153
- useSetStorage("theme", "dark");
154
- const theme = useGetStorage<string>("theme"); // "dark"
155
- useRemoveStorage("theme");
156
-
157
- useAddClass(useGetRoot()!, "dark-mode");
158
- ```
159
-
160
- Storage is SSR-safe: when `window` is unavailable an in-memory fallback is used
161
- automatically, so imports never crash in Node/Bun.
162
-
163
- ## Astro adapter
164
-
165
- KatanaKit converts arbitrary collections into the payload Astro's
166
- `getStaticPaths` expects, wrapped in a Safe Result.
167
-
168
- ```ts
169
- // src/pages/blog/[slug].astro
170
- import { AstroService } from "katanakit-js";
171
-
172
- export async function getStaticPaths() {
173
- const { useGetStaticPaths } = AstroService.getInstance();
174
-
175
- return useGetStaticPaths(getCollection, "blog", {
176
- param: "slug",
177
- valueFrom: (entry) => entry.slug ?? entry.id,
178
- propsFrom: (entry) => entry.data,
179
- });
180
- }
181
- ```
182
-
183
- Also available: `usePathsFrom`, `useFindEntry`, `useGeneratePagination`,
184
- `usePathsFromValues` and `useExtractUniqueValues`. See the
185
- [API Reference](docs/API-Reference.md#astro--astroservice).
61
+ ## Features
186
62
 
187
- ## RSS feeds for Astro
63
+ - **Safe Results** HTTP (and other fallible) operations return `{ data, error, ok }` instead of throwing
64
+ - **Zero side effects** — importing any module is safe. No `fetch` calls, no `console.log`, no storage writes
65
+ - **Hexagonal architecture** — pure core, infrastructure adapters, framework adapters
66
+ - **Tree-shakeable** — destructured re-exports from Singleton facades
67
+ - **SSR-safe** — all infrastructure adapters guard or fall back gracefully in server environments
188
68
 
189
- `RssService` generates pure RSS 2.0 XML with **no external dependencies**
190
- (`@astrojs/rss` is not required).
69
+ ## Framework usage
191
70
 
192
- ```ts
193
- // src/pages/rss.xml.ts
194
- import { RssService } from "katanakit-js";
195
- import { getCollection } from "astro:content";
196
-
197
- const { useCreateRssEndpoint } = RssService.getInstance();
198
-
199
- export const GET = useCreateRssEndpoint({
200
- title: "My Blog",
201
- description: "Posts about TypeScript",
202
- site: "https://example.com",
203
- items: async () => {
204
- const posts = await getCollection("blog");
205
- return posts.map((post) => ({
206
- title: post.data.title,
207
- pubDate: post.data.date,
208
- link: `/blog/${post.slug}/`,
209
- description: post.data.description,
210
- }));
211
- },
212
- });
213
- ```
71
+ All common `use*` helpers (`useLogger`, `useInitApis`, `useGetApi`, formatter, dates, utils, theme, …) are on the **main barrel** `katanakit-js`.
214
72
 
215
- Add the feed `<link>` tag to your layout's `<head>`:
73
+ ### Astro (npm)
216
74
 
217
75
  ```astro
218
76
  ---
219
- import { useRssLinkTag } from "katanakit-js";
77
+ // Frontmatter = server
78
+ import { useLogger, useGetApi, useInitApis } from "katanakit-js";
79
+ useInitApis({ /* ... */ });
80
+ const result = await useGetApi("pokeapi", "pokemonById", { params: { id: 25 } });
220
81
  ---
221
- <head>
222
- <Fragment set:html={useRssLinkTag({ title: "My Blog" })} />
223
- </head>
224
- ```
225
-
226
- `useCreateRssEndpointFromConfig(siteConfig, items)` builds the same endpoint
227
- from your `SiteConfig`. See the [API Reference](docs/API-Reference.md#rss--rssservice).
228
-
229
- ## Site config and SEO
230
-
231
- Centralize your site metadata in a typed `SiteConfig` and derive every `<head>`
232
- tag from it.
233
-
234
- ```ts
235
- // src/config/site.config.ts
236
- import { type SiteConfig } from "katanakit-js";
237
-
238
- export const siteConfig: SiteConfig = {
239
- site: "https://myblog.com",
240
- title: "My Blog",
241
- description: "A blog about TypeScript and Astro",
242
- lang: "en",
243
- author: "John Doe",
244
- ogImage: "/og-default.png",
245
- twitter: "johndoe",
246
- rss: { enabled: true, path: "/rss.xml", limit: 20 },
247
- seo: { noindex: false, canonical: true, openGraph: true, twitterCard: true, jsonLd: true },
248
- nav: [
249
- { label: "Home", href: "/" },
250
- { label: "Blog", href: "/blog" },
251
- { label: "GitHub", href: "https://github.com/senseikatana/katanakit", external: true },
252
- ],
253
- };
82
+ <script>
83
+ // Client script Vite bundles the same package
84
+ import { useLogger } from "katanakit-js";
85
+ useLogger("client");
86
+ </script>
254
87
  ```
255
88
 
256
- Then inject complete meta tags (title, description, canonical, Open Graph,
257
- Twitter Card and JSON-LD) in your layout:
89
+ ### Astro (CDN client)
258
90
 
259
91
  ```astro
260
- ---
261
- // src/layouts/BaseLayout.astro
262
- import { siteConfig } from "@/config/site.config";
263
- import { useHeadTags } from "katanakit-js";
264
-
265
- interface Props {
266
- title: string;
267
- description?: string;
268
- ogType?: "website" | "article";
269
- publishedTime?: string;
270
- }
271
-
272
- const { title, description, ogType, publishedTime } = Astro.props;
273
- const headTags = useHeadTags(siteConfig, {
274
- title,
275
- description,
276
- url: new URL(Astro.url.pathname, siteConfig.site).href,
277
- ogType,
278
- publishedTime,
279
- });
280
- ---
281
- <html lang={siteConfig.lang}>
282
- <head>
283
- <meta charset="utf-8" />
284
- <meta name="viewport" content="width=device-width, initial-scale=1" />
285
- <Fragment set:html={headTags} />
286
- </head>
287
- <body>
288
- <slot />
289
- </body>
290
- </html>
92
+ <script is:inline type="module">
93
+ import { useLogger } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
94
+ useLogger("cdn");
95
+ </script>
291
96
  ```
292
97
 
293
- The RSS endpoint consumes the same config:
98
+ ### Vue / Nuxt / vanilla
294
99
 
295
100
  ```ts
296
- // src/pages/rss.xml.ts
297
- import { RssService } from "katanakit-js";
298
- import { siteConfig } from "@/config/site.config";
299
- import { getCollection } from "astro:content";
300
-
301
- const { useCreateRssEndpointFromConfig } = RssService.getInstance();
302
-
303
- export const GET = useCreateRssEndpointFromConfig(siteConfig, async () => {
304
- const posts = await getCollection("blog");
305
- return posts.map((post) => ({
306
- title: post.data.title,
307
- pubDate: post.data.date,
308
- link: `/blog/${post.slug}/`,
309
- description: post.data.description,
310
- }));
311
- });
101
+ import { useLogger, useInitApis, useGetApi } from "katanakit-js";
102
+ import { useKatanaFetch } from "katanakit-js/adapters/vue"; // Vue only
103
+ import { useUnwrap } from "katanakit-js/adapters/nuxt"; // Nuxt only
312
104
  ```
313
105
 
314
- ## Nuxt adapter
315
-
316
- New in 2.1.4. Three pure helper functions bridge KatanaKit's Safe Results to
317
- Nuxt/Nitro server routes. They are **not** singleton services — just exported
318
- functions — and they avoid a hard dependency on `h3` (it ships with Nuxt).
319
-
320
- ```ts
321
- import { useInit, useGet } from "katanakit-js";
322
- import { useUnwrap } from "katanakit-js/adapters/nuxt";
323
-
324
- // server/plugins/api.ts — register your APIs once
325
- useInit({
326
- pokeapi: {
327
- baseUri: "https://pokeapi.co/api/v2",
328
- endpoints: { pokemonById: "/pokemon/:id/" },
329
- },
330
- });
106
+ ```html
107
+ <!-- vanilla -->
108
+ <script type="module">
109
+ import { useLogger } from "https://cdn.jsdelivr.net/npm/katanakit-js/+esm";
110
+ </script>
331
111
  ```
332
112
 
333
- ```ts
334
- // server/api/pokemon/[id].ts
335
- import { useGet } from "katanakit-js";
336
- import { useUnwrap } from "katanakit-js/adapters/nuxt";
337
-
338
- export default defineEventHandler(async (event) => {
339
- const id = getRouterParam(event, "id");
340
- const result = await useGet("pokeapi", "pokemonById", { params: { id } });
341
- return useUnwrap(result, `Pokemon ${id}`); // returns data, or throws an H3-compatible error
342
- });
343
- ```
113
+ See [Getting Started](https://senseikatana.github.io/katanakit-js/docs/guides/getting-started) for full recipes.
344
114
 
345
- The other helpers are `useSafeResponse(result)` (shape the result as a clean
346
- JSON response object) and `useEventResponse(event, result)` (set the H3 event
347
- status code and return data/error). See the
348
- [API Reference](docs/API-Reference.md#nuxt-adapter--katanakit-jsadaptersnuxt).
115
+ ## Framework Adapters
349
116
 
350
- ## Express server (optional)
351
-
352
- The Express reference adapter is exposed only through its own subpath so it
353
- never bloats the main bundle:
354
-
355
- ```ts
356
- import { ServerExpress } from "katanakit-js/adapters/express";
357
-
358
- ServerExpress.getInstance().useStart(); // http://localhost:3000
359
- ```
360
-
361
- It expects `express` (and `cors`/`dotenv` if used) to be installed in your
362
- project. A `ProductController` and a demo `router` are also exported.
363
-
364
- ## Services at a glance
365
-
366
- | Area | Service / module | Highlights |
367
- | --------- | --------------------------- | ------------------------------------------------------------------- |
368
- | HTTP | `FetchApiManager` | `useInit`, `useGetApis`, `useBuildUrl`, `useFetch`, `useGet`, `usePost`, `usePut`, `useDelete` |
369
- | Logging | `LoggerService` | `useLog`, `useError`, `useClear`, `useTable`, pluggable `LogStrategy` |
370
- | Storage | `StorageService` | `useGetStorage`, `useSetStorage`, `useRemoveStorage`, `useClearStorage` (SSR-safe) |
371
- | DOM | `DomService` | `useQuerySelector`, `useAddClass`, `useOn`, `useSetText`, ... |
372
- | Reactive | `ReactiveService` | `useCreateSignal`, `useCreateEffect`, `useCreateMemo`, `useCreateToggle`, `useCreateStorageSignal`, `useCreateDebouncedSignal`, `useCreateBatch` |
373
- | Format | `FormatterService` | `useFormatNumber`, `useFormatCurrency`, `useJsonStringify`, `useUpperCase`, `useCapitalize`, ... |
374
- | Convert | `ConverterService` | `useToCelsius`, `useToFahrenheit`, `useToMiles`, `useToKilos`, ... |
375
- | Errors | `ErrorFactoryService` | `useBadRequest`, `useUnauthorized`, `useForbidden`, `useNotFound`, `useInternal`, `useCustom` |
376
- | Generate | `GeneratorService` | `useUuid`, `useSlugify`, `useNumericId`, `useToken`, `useEncrypt` |
377
- | Dates | `DatesService` | `useFormat`, `useNow`, `useAddDays`, `useIsBefore`, `useLastDayOfMonth`, ... (Temporal) |
378
- | Geometry | `GeometryUtils` | `area`, `perimeter`, `volume` static helpers (`useCircle`, `useSphere`, ...) |
379
- | Timing | `TimingService` | `useDelay`, `useSetTimeout`, `useInterval`, `useDebounce`, `useThrottle`, `useRepeat`, `useRace` |
380
- | Utils | `DataUtils` / `SystemUtils` | `useUnique`, `useGroupBy`, `useDeepClone`, `useSleep`, `useRetry`, `useRound`, ... |
381
- | Viewport | `ViewportService` | scroll, fullscreen, visibility, `usePrefersReducedMotion` |
382
- | Sensors | `SensorsUtils` | `useGetGeolocation`, `useGetMediaStream`, `useVibrate`, `useGetBattery`, ... |
383
- | Observer | `ObserverService` | `useCreate`, `useObserve`, `useObserveAll`, `useDisconnect` |
384
- | LazyLoad | `LazyLoaderService` | `useInit`, `useStop`, `useStopAll` for `img[data-src]` |
385
- | Worker | `WorkerService` | `useRun`, `useCreatePool`, `useRunPool`, `useTerminate` |
386
- | Theme | `ThemeService` | `useInitTheme`, `useSetThemeMode`, `useToggleTheme`, `useResetTheme` |
387
- | Astro | `AstroService` | `useGetStaticPaths`, `usePathsFrom`, `useGeneratePagination`, ... |
388
- | RSS | `RssService` | `useGenerateRss`, `useRssLinkTag`, `useCreateRssEndpoint`, `useCreateRssEndpointFromConfig` |
389
- | SEO | `useHeadTags` and friends | `useGenerateMetaTags`, `useTitle`, `useRssHeadLink` + typed `SiteConfig` |
390
- | Config | `siteConfig` / `SiteConfig` | single source for site metadata, RSS and SEO defaults |
391
- | Nuxt | `katanakit-js/adapters/nuxt`| `useUnwrap`, `useSafeResponse`, `useEventResponse` (pure functions) |
392
- | Server | `katanakit-js/adapters/express` | `ServerExpress`, `router`, `ProductController` (optional reference) |
393
-
394
- The Astro, RSS, SEO and config modules plus all core/infrastructure services
395
- are re-exported from the main barrel. The Nuxt and Express adapters are only
396
- available through their subpaths.
397
-
398
- ## Project structure (hexagonal)
399
-
400
- ```
401
- katanakit/
402
- ├── package.json # name: katanakit-js, ESM, exports map
403
- ├── prisma.config.ts # Prisma ORM config (contract + connection)
404
- ├── src/
405
- │ ├── index.ts # main barrel (public API)
406
- │ ├── types/ # single source of truth: contracts & types
407
- │ ├── core/
408
- │ │ └── services/ # pure services (no I/O): logger, http, ...
409
- │ ├── infrastructure/ # browser/runtime adapters
410
- │ │ ├── dom/ storage/ viewport/ sensors/
411
- │ │ └── observer/ worker/ theme/
412
- │ ├── adapters/ # framework adapters
413
- │ │ ├── astro/ # AstroService + RssService
414
- │ │ ├── express/ # ServerExpress reference (subpath export)
415
- │ │ └── nuxt/ # Nuxt helpers (subpath export)
416
- │ ├── config/ # siteConfig (SiteConfig) + SEO helpers
417
- │ └── prisma/ # Prisma schema, contract types and db client
418
- ├── tests/ # Vitest suite (57 tests across 7 files)
419
- ├── examples/ # runnable demos
420
- ├── docs/ # Getting Started, Architecture, API Reference, Roadmap
421
- ├── CONTRIBUTING.md
422
- └── SECURITY.md
423
- ```
424
-
425
- All internal source imports are relative and carry an explicit `.js` extension
426
- (pure ESM, `module: nodenext`). The `@/` alias (mapped to `src/`) is configured
427
- for the test suite and the examples.
117
+ | Adapter | Import | Description |
118
+ |---------|--------|-------------|
119
+ | **Express** | `katanakit-js/adapters/express` | Reference server with CORS and hardened headers |
120
+ | **Nuxt** | `katanakit-js/adapters/nuxt` | `useUnwrap`, `useSafeResponse`, `useEventResponse` |
121
+ | **Vue** | `katanakit-js/adapters/vue` | `useKatanaFetch` composable with reactivity |
122
+ | **Astro** | `katanakit-js` or `katanakit-js/adapters/astro` | `AstroService`, `RssService` |
428
123
 
429
124
  ## Documentation
430
125
 
431
- - [Getting Started](docs/Getting-Started.md)
432
- - [Architecture](docs/Architecture.md)
433
- - [API Reference](docs/API-Reference.md)
434
- - [Roadmap](docs/Roadmap.md)
435
- - [Security](SECURITY.md)
436
- - [Changelog](CHANGELOG.md)
437
-
438
- ## Contributing
439
-
440
- Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for
441
- the development contract (hexagonal layering, `use*` convention, `.js` ESM
442
- imports, tests, scripts) before opening a pull request.
126
+ - [Getting Started](https://senseikatana.github.io/katanakit-js/docs/guides/getting-started)
127
+ - [Architecture](https://senseikatana.github.io/katanakit-js/docs/guides/architecture)
128
+ - [API Reference](https://senseikatana.github.io/katanakit-js/docs/api)
129
+ - [Roadmap](https://senseikatana.github.io/katanakit-js/docs/guides/roadmap)
130
+ - [Changelog](https://senseikatana.github.io/katanakit-js/docs/changelog)
443
131
 
444
132
  ## License
445
133
 
446
- [MIT](LICENSE)
134
+ MIT
@@ -1,18 +1,106 @@
1
- import type { AstroPath, AstroServiceResult, CollectionEntryLike, IAstroService, PaginationProps, PathsOptions } from "../../types/index.js";
1
+ import type { AstroPath, AstroServiceResult, CollectionEntryLike, PaginationProps, PathsOptions } from "../../types/index.js";
2
2
  /**
3
- * Astro adapter (Facade + Adapter + Singleton). Converts arbitrary collections
4
- * into the `getStaticPaths` format Astro expects, wrapped in a Safe Result.
3
+ * Convert a collection into Astro-compatible static paths.
4
+ *
5
+ * @param items - Collection items to convert
6
+ * @param options - Configuration for param name, value extraction and props
7
+ * @returns Array of Astro paths with params and props
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // In Astro's getStaticPaths()
12
+ * const posts = await getCollection("blog");
13
+ * const paths = useAstroPathsFrom(posts, {
14
+ * param: "slug",
15
+ * valueFrom: (post) => post.slug,
16
+ * propsFrom: (post) => ({ title: post.data.title }),
17
+ * });
18
+ * // [{ params: { slug: "hello-world" }, props: { title: "Hello World" } }]
19
+ * ```
5
20
  */
6
- export declare class AstroService implements IAstroService {
7
- private static instance;
8
- private constructor();
9
- static getInstance(): AstroService;
10
- usePathsFrom: <T, TParam extends string = "slug", TProps = T>(items: T[], options?: PathsOptions<T, TParam, TProps>) => AstroPath<TParam, TProps>[];
11
- useGetStaticPaths: <TData = unknown, TParam extends string = "slug", TProps = CollectionEntryLike<TData>>(getCollectionFn: (collection: string) => Promise<CollectionEntryLike<TData>[]>, collectionName: string, options?: PathsOptions<CollectionEntryLike<TData>, TParam, TProps>) => Promise<AstroServiceResult<AstroPath<TParam, TProps>[]>>;
12
- useFindEntry: <T>(items: T[], value: string, keyFrom?: (item: T) => string | number) => T | null;
13
- useGeneratePagination: <T, TParam extends string = "page">(items: T[], pageSize?: number, param?: TParam) => AstroPath<TParam, PaginationProps<T>>[];
14
- usePathsFromValues: <TParam extends string = "slug">(values: (string | number)[], param?: TParam) => AstroPath<TParam, string | number>[];
15
- useExtractUniqueValues: <T, V>(items: T[], keyFrom: (item: T) => V | V[]) => V[];
16
- }
17
- export declare const usePathsFrom: <T, TParam extends string = "slug", TProps = T>(items: T[], options?: PathsOptions<T, TParam, TProps>) => AstroPath<TParam, TProps>[], useGetStaticPaths: <TData = unknown, TParam extends string = "slug", TProps = CollectionEntryLike<TData>>(getCollectionFn: (collection: string) => Promise<CollectionEntryLike<TData>[]>, collectionName: string, options?: PathsOptions<CollectionEntryLike<TData>, TParam, TProps>) => Promise<AstroServiceResult<AstroPath<TParam, TProps>[]>>, useFindEntry: <T>(items: T[], value: string, keyFrom?: ((item: T) => string | number) | undefined) => T | null, useGeneratePagination: <T, TParam extends string = "page">(items: T[], pageSize?: number, param?: TParam) => AstroPath<TParam, PaginationProps<T>>[], usePathsFromValues: <TParam extends string = "slug">(values: (string | number)[], param?: TParam) => AstroPath<TParam, string | number>[], useExtractUniqueValues: <T, V>(items: T[], keyFrom: (item: T) => V | V[]) => V[];
21
+ export declare function useAstroPathsFrom<T, TParam extends string = "slug", TProps = T>(items: T[], options?: PathsOptions<T, TParam, TProps>): AstroPath<TParam, TProps>[];
22
+ /**
23
+ * Fetch a collection and transform it into safe Astro paths.
24
+ * Returns a result object instead of throwing on error.
25
+ *
26
+ * @param getCollectionFn - Astro's getCollection function
27
+ * @param collectionName - Name of the collection to fetch
28
+ * @param options - Path generation options
29
+ * @returns Safe result with data or error
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * export async function getStaticPaths() {
34
+ * const result = await useAstroGetStaticPaths(getCollection, "blog");
35
+ * if (result.ok) return result.data;
36
+ * TODO: traer el useLogger('error', result.error)
37
+ * console.error(result.error);
38
+ * return [];
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function useAstroGetStaticPaths<TData = unknown, TParam extends string = "slug", TProps = CollectionEntryLike<TData>>(getCollectionFn: (collection: string) => Promise<CollectionEntryLike<TData>[]>, collectionName: string, options?: PathsOptions<CollectionEntryLike<TData>, TParam, TProps>): Promise<AstroServiceResult<AstroPath<TParam, TProps>[]>>;
43
+ /**
44
+ * Find a collection entry by slug or custom key.
45
+ *
46
+ * @param items - Collection items to search
47
+ * @param value - Value to match (slug, id, etc.)
48
+ * @param keyFrom - Optional function to extract the key from an item
49
+ * @returns Matched item or null
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const posts = await getCollection("blog");
54
+ * const post = useAstroFindEntry(posts, "hello-world");
55
+ * if (post) console.log(post.data.title);
56
+ * ```
57
+ */
58
+ export declare function useAstroFindEntry<T>(items: T[], value: string, keyFrom?: (item: T) => string | number): T | null;
59
+ /**
60
+ * Generate paginated Astro paths from a list of items.
61
+ *
62
+ * @param items - Items to paginate
63
+ * @param pageSize - Number of items per page
64
+ * @param param - URL param name for page number
65
+ * @returns Array of Astro paths with pagination props
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const posts = await getCollection("blog");
70
+ * const pages = useAstroGeneratePagination(posts, 10);
71
+ * // [{ params: { page: undefined }, props: { items: [...], currentPage: 1, totalPages: 3 } },
72
+ * // { params: { page: "2" }, props: { items: [...], currentPage: 2, totalPages: 3 } }, ...]
73
+ * ```
74
+ */
75
+ export declare function useAstroGeneratePagination<T, TParam extends string = "page">(items: T[], pageSize?: number, param?: TParam): AstroPath<TParam, PaginationProps<T>>[];
76
+ /**
77
+ * Convert simple values into Astro paths.
78
+ *
79
+ * @param values - Array of string or number values
80
+ * @param param - URL param name
81
+ * @returns Array of Astro paths
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * const categories = ["tech", "design", "business"];
86
+ * const paths = useAstroPathsFromValues(categories, "category");
87
+ * // [{ params: { category: "tech" }, props: "tech" }, ...]
88
+ * ```
89
+ */
90
+ export declare function useAstroPathsFromValues<TParam extends string = "slug">(values: (string | number)[], param?: TParam): AstroPath<TParam, string | number>[];
91
+ /**
92
+ * Extract unique values from a collection, supporting single values or arrays.
93
+ *
94
+ * @param items - Collection items
95
+ * @param keyFrom - Function to extract value(s) from each item
96
+ * @returns Array of unique values
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * const posts = [{ tags: ["ts", "react"] }, { tags: ["ts", "vue"] }];
101
+ * const tags = useAstroExtractUniqueValues(posts, (p) => p.tags);
102
+ * // ["ts", "react", "vue"]
103
+ * ```
104
+ */
105
+ export declare function useAstroExtractUniqueValues<T, V>(items: T[], keyFrom: (item: T) => V | V[]): V[];
18
106
  //# sourceMappingURL=astro.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"astro.service.d.ts","sourceRoot":"","sources":["../../../src/adapters/astro/astro.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;;GAGG;AACH,qBAAa,YAAa,YAAW,aAAa;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IAEtC,OAAO,eAAiB;IAExB,OAAc,WAAW,IAAI,YAAY,CAKxC;IAEM,YAAY,GAAI,CAAC,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,GAAG,CAAC,SAC5D,CAAC,EAAE,YACD,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KACtC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAkB5B;IAEK,iBAAiB,GACvB,KAAK,GAAG,OAAO,EACf,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,mBAElB,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC,kBAC9D,MAAM,YACb,YAAY,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAC/D,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAoBzD;IAEK,YAAY,GAAI,CAAC,SAChB,CAAC,EAAE,SACH,MAAM,YACH,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,KACpC,CAAC,GAAG,IAAI,CAQT;IAEK,qBAAqB,GAAI,CAAC,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,SACzD,CAAC,EAAE,6BAEH,MAAM,KACX,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAgBxC;IAEK,kBAAkB,GAAI,MAAM,SAAS,MAAM,GAAG,MAAM,UAClD,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,UACpB,MAAM,KACX,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,CAKrC;IAEK,sBAAsB,GAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAG,CAAC,EAAE,CAGpF;CACF;AAGD,eAAO,MACN,YAAY,GA3GW,CAAC,EAAE,MAAM,SAAS,MAAM,WAAW,MAAM,6FA4GhE,iBAAiB,GApFhB,KAAK,YACL,MAAM,SAAS,MAAM,WACrB,MAAM,6DAEwB,MAAM,4DACpB,MAAM,mIAgFvB,YAAY,GAxDW,CAAC,qBAEhB,MAAM,0BACU,MAAM,GAAG,MAAM,4BAsDvC,qBAAqB,GA3CW,CAAC,EAAE,MAAM,SAAS,MAAM,sGA4CxD,kBAAkB,GAtBW,MAAM,SAAS,MAAM,mBACzC,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,2DAsB5B,sBAAsB,GAbW,CAAC,EAAE,CAAC,mDAcM,CAAC"}
1
+ {"version":3,"file":"astro.service.d.ts","sourceRoot":"","sources":["../../../src/adapters/astro/astro.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,GAAG,CAAC,EAC9E,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,GAAE,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAM,GAC3C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAkB7B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,sBAAsB,CAC3C,KAAK,GAAG,OAAO,EACf,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,EAEnC,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC,EAC9E,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,YAAY,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAM,GACpE,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAe1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAClC,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GACpC,CAAC,GAAG,IAAI,CAQV;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,MAAM,SAAS,MAAM,GAAG,MAAM,EAC3E,KAAK,EAAE,CAAC,EAAE,EACV,QAAQ,SAAK,EACb,KAAK,GAAE,MAAyB,GAC9B,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAYzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EACrE,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAC3B,KAAK,GAAE,MAAyB,GAC9B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,CAKtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAEhG"}