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
package/CHANGELOG.md ADDED
@@ -0,0 +1,96 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.1.4] - Unreleased
9
+
10
+ Current development version. This is the first release published under the
11
+ **`katanakit-js`** npm name (previous development releases were published as
12
+ `katanakit-dev`).
13
+
14
+ ### Added
15
+
16
+ - **Nuxt adapter** — new `katanakit-js/adapters/nuxt` subpath exporting three
17
+ pure helpers that bridge KatanaKit Safe Results to Nuxt/Nitro server routes:
18
+ `useUnwrap(result, context?)`, `useSafeResponse(result)` and
19
+ `useEventResponse(event, result)`. They avoid a hard dependency on `h3`
20
+ (which ships with Nuxt).
21
+ - **Site config and SEO module** — new `src/config/` layer with
22
+ `siteConfig`/`SiteConfig` and pure SEO helpers (`useGenerateMetaTags`,
23
+ `useHeadTags`, `useTitle`, `useRssHeadLink`), re-exported from the main
24
+ barrel. Includes HTML/attribute escaping and JSON-LD breakout protection.
25
+ - **`publish:*` scripts** — `publish:patch`, `publish:minor`, `publish:major`
26
+ and `publish:beta` (tagged `beta`) with a `prepublishOnly` gate that runs
27
+ Biome, tests and the build before publishing.
28
+ - New Vitest suites for RSS, Nuxt and SEO services (57 tests across 7 files).
29
+
30
+ ### Changed
31
+
32
+ - **Renamed the npm package** from `katanakit-dev` to **`katanakit-js`**
33
+ (version bumped to 2.1.4). The `exports` map now exposes the root entry plus
34
+ two framework subpaths: `katanakit-js/adapters/express` and
35
+ `katanakit-js/adapters/nuxt`.
36
+ - **Restructured dependencies** — only `@js-temporal/polyfill` remains a
37
+ runtime dependency; `express`, `cors`, `dotenv` and `@prisma/orm-postgres`
38
+ are now **optional peer dependencies** installed only by consumers that use
39
+ the Express adapter or the Prisma layer.
40
+ - Upgraded the toolchain: Biome to v2 (migrated `biome.json` schema), Vitest to
41
+ v5, TypeScript to v7; Node engine floor raised to `>=22.18.0`.
42
+ - Hardened the Express reference adapter: CORS defaults to the comma-separated
43
+ `CORS_ORIGINS` allow-list (localhost fallback), `x-powered-by` is disabled
44
+ and JSON/urlencoded bodies are capped at 100 kb.
45
+
46
+ ### Fixed
47
+
48
+ - **Pure ESM `.js` exports** — all relative imports in `src/` now use explicit
49
+ `.js` extensions (`module: nodenext`), so Node's ESM loader and bundlers
50
+ resolve the emitted `dist/` correctly.
51
+ - **`WorkerService` pool correlation** — `useRunPool` now correlates responses
52
+ by echoing a `taskId` from the worker blob, fixing concurrent race
53
+ conditions.
54
+ - **`useEncrypt` salt** — generates a random 128-bit salt when none is provided
55
+ instead of relying on a fixed default.
56
+ - **SEO JSON-LD escaping** — `<`, `>` and `&` are escaped inside the
57
+ `application/ld+json` script to prevent `</script>` breakout.
58
+
59
+ ## [2.0.0] - 2026-09-03
60
+
61
+ Developed and published as `katanakit-dev`.
62
+
63
+ ### Changed
64
+
65
+ - **Reorganized the project with hexagonal architecture** into `types/`,
66
+ `core/services/` (ports + pure services), `infrastructure/` (browser/runtime
67
+ adapters), `adapters/` (Astro + Express) and `prisma/`, replacing the previous
68
+ flat `helpers/`/`api/` layout.
69
+ - Exposed the public API through barrel files (`src/index.ts` and per-layer
70
+ `index.ts`).
71
+
72
+ ### Added
73
+
74
+ - Added `biome.json` and `vitest.config.ts`; wired `typecheck`, `build`, `test`,
75
+ `lint`, `format` and `check` scripts.
76
+ - Added Vitest unit tests for the HTTP client, logger, storage, geometry, errors
77
+ and reactive signals.
78
+ - Added English documentation (`README.md`, `CONTRIBUTING.md`, `docs/`,
79
+ `SECURITY.md`).
80
+
81
+ ### Fixed
82
+
83
+ - Fixed TypeScript compile errors: broken imports, broken singleton guards
84
+ (`TimingService` and `ViewportService`), the `FIND_ENTRY` scope bug in
85
+ `AstroService`, and Express `Request`/`Response` typing.
86
+ - Removed all side effects on import (top-level `fetch` to dummyjson.com,
87
+ `console.log` calls, storage writes and timers).
88
+ - Fixed the Express server: `listen` now uses the configured port/host, the user
89
+ router is mounted, and handler `(req, res)` argument order is correct.
90
+ - Fixed the logger call sites (level is now the first argument of `useLog`).
91
+
92
+ ### Removed
93
+
94
+ - Removed duplicate type definitions (unified in `src/types/`), dead code, empty
95
+ files and the broken signals draft.
96
+ - Moved demos to `examples/` and dropped the obsolete `wiki/` documentation.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 senseikatana - Sergio Jurado
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,446 @@
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.
28
+
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.
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ npm install katanakit-js
64
+ # or
65
+ bun add katanakit-js
66
+ ```
67
+
68
+ Requirements: **Node.js >= 22.18.0** (pure ESM package). TypeScript consumers
69
+ should use `moduleResolution: "nodenext"` (or `"bundler"`).
70
+
71
+ ### Framework adapters
72
+
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";
82
+ ```
83
+
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
89
+
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
+ ```
96
+
97
+ ## Quick Start
98
+
99
+ Everything below is importable from the main barrel `katanakit-js`.
100
+
101
+ ### HTTP client
102
+
103
+ ```ts
104
+ import { useInit, useGet, usePost, useBuildUrl } from "katanakit-js";
105
+
106
+ // 1. Register your APIs once.
107
+ useInit({
108
+ pokeapi: {
109
+ baseUri: "https://pokeapi.co/api/v2",
110
+ endpoints: {
111
+ pokemonById: "/pokemon/:id/",
112
+ pokemons: "/pokemons/",
113
+ },
114
+ },
115
+ });
116
+
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", {
125
+ params: { id: 25 },
126
+ });
127
+
128
+ if (result.ok) {
129
+ console.log(result.data.name);
130
+ } else {
131
+ console.error(result.error.message, result.error.status);
132
+ }
133
+
134
+ // 4. POST JSON.
135
+ await usePost("pokeapi", "pokemons", { name: "charmander" });
136
+ ```
137
+
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).
186
+
187
+ ## RSS feeds for Astro
188
+
189
+ `RssService` generates pure RSS 2.0 XML with **no external dependencies**
190
+ (`@astrojs/rss` is not required).
191
+
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
+ ```
214
+
215
+ Add the feed `<link>` tag to your layout's `<head>`:
216
+
217
+ ```astro
218
+ ---
219
+ import { useRssLinkTag } from "katanakit-js";
220
+ ---
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
+ };
254
+ ```
255
+
256
+ Then inject complete meta tags (title, description, canonical, Open Graph,
257
+ Twitter Card and JSON-LD) in your layout:
258
+
259
+ ```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>
291
+ ```
292
+
293
+ The RSS endpoint consumes the same config:
294
+
295
+ ```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
+ });
312
+ ```
313
+
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
+ });
331
+ ```
332
+
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
+ ```
344
+
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).
349
+
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.
428
+
429
+ ## Documentation
430
+
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.
443
+
444
+ ## License
445
+
446
+ [MIT](LICENSE)
@@ -0,0 +1,18 @@
1
+ import type { AstroPath, AstroServiceResult, CollectionEntryLike, IAstroService, PaginationProps, PathsOptions } from "../../types/index.js";
2
+ /**
3
+ * Astro adapter (Facade + Adapter + Singleton). Converts arbitrary collections
4
+ * into the `getStaticPaths` format Astro expects, wrapped in a Safe Result.
5
+ */
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[];
18
+ //# sourceMappingURL=astro.service.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Astro adapter (Facade + Adapter + Singleton). Converts arbitrary collections
3
+ * into the `getStaticPaths` format Astro expects, wrapped in a Safe Result.
4
+ */
5
+ export class AstroService {
6
+ static instance;
7
+ constructor() { }
8
+ static getInstance() {
9
+ if (!AstroService.instance) {
10
+ AstroService.instance = new AstroService();
11
+ }
12
+ return AstroService.instance;
13
+ }
14
+ usePathsFrom = (items, options = {}) => {
15
+ const { param = "slug", valueFrom = (item) => {
16
+ const record = item;
17
+ return record?.slug ?? record?.id ?? "";
18
+ }, propsFrom = (item) => item, paramsFrom, } = options;
19
+ return items.map((item) => ({
20
+ params: (paramsFrom ? paramsFrom(item) : { [param]: String(valueFrom(item)) }),
21
+ props: propsFrom(item),
22
+ }));
23
+ };
24
+ useGetStaticPaths = async (getCollectionFn, collectionName, options = {}) => {
25
+ try {
26
+ const entries = await getCollectionFn(collectionName);
27
+ const paths = this.usePathsFrom(entries, options);
28
+ return {
29
+ data: paths,
30
+ error: null,
31
+ ok: true,
32
+ };
33
+ }
34
+ catch (error) {
35
+ return {
36
+ data: null,
37
+ error: {
38
+ message: `Error generating routes for collection "${collectionName}"`,
39
+ collectionName,
40
+ details: error instanceof Error ? error.message : String(error),
41
+ },
42
+ ok: false,
43
+ };
44
+ }
45
+ };
46
+ useFindEntry = (items, value, keyFrom) => {
47
+ const getKey = keyFrom ??
48
+ ((item) => {
49
+ const record = item;
50
+ return record?.slug ?? record?.id ?? "";
51
+ });
52
+ return items.find((item) => String(getKey(item)) === value) ?? null;
53
+ };
54
+ useGeneratePagination = (items, pageSize = 10, param = "page") => {
55
+ const totalPages = Math.max(1, Math.ceil(items.length / pageSize));
56
+ return Array.from({ length: totalPages }, (_, i) => {
57
+ const currentPage = i + 1;
58
+ return {
59
+ params: {
60
+ [param]: currentPage === 1 ? undefined : String(currentPage),
61
+ },
62
+ props: {
63
+ items: items.slice(i * pageSize, (i + 1) * pageSize),
64
+ currentPage,
65
+ totalPages,
66
+ },
67
+ };
68
+ });
69
+ };
70
+ usePathsFromValues = (values, param = "slug") => {
71
+ return values.map((value) => ({
72
+ params: { [param]: String(value) },
73
+ props: value,
74
+ }));
75
+ };
76
+ useExtractUniqueValues = (items, keyFrom) => {
77
+ const values = items.flatMap(keyFrom);
78
+ return [...new Set(values)];
79
+ };
80
+ }
81
+ // Singleton instance and destructured exports.
82
+ export const { usePathsFrom, useGetStaticPaths, useFindEntry, useGeneratePagination, usePathsFromValues, useExtractUniqueValues, } = AstroService.getInstance();
83
+ //# sourceMappingURL=astro.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astro.service.js","sourceRoot":"","sources":["../../../src/adapters/astro/astro.service.ts"],"names":[],"mappings":"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"}