katanakit-js 6.7.4 → 6.8.0

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 (50) hide show
  1. package/README.md +12 -8
  2. package/dist/adapters/hono/access.guard.d.ts +31 -0
  3. package/dist/adapters/hono/access.guard.d.ts.map +1 -0
  4. package/dist/adapters/hono/access.guard.js +53 -0
  5. package/dist/adapters/hono/access.guard.js.map +1 -0
  6. package/dist/adapters/hono/app.d.ts +42 -0
  7. package/dist/adapters/hono/app.d.ts.map +1 -0
  8. package/dist/adapters/hono/app.js +59 -0
  9. package/dist/adapters/hono/app.js.map +1 -0
  10. package/dist/adapters/hono/index.d.ts +4 -0
  11. package/dist/adapters/hono/index.d.ts.map +1 -0
  12. package/dist/adapters/hono/index.js +4 -0
  13. package/dist/adapters/hono/index.js.map +1 -0
  14. package/dist/adapters/hono/result.d.ts +32 -0
  15. package/dist/adapters/hono/result.d.ts.map +1 -0
  16. package/dist/adapters/hono/result.js +37 -0
  17. package/dist/adapters/hono/result.js.map +1 -0
  18. package/dist/adapters/nestjs/access.guard.d.ts +38 -0
  19. package/dist/adapters/nestjs/access.guard.d.ts.map +1 -0
  20. package/dist/adapters/nestjs/access.guard.js +69 -0
  21. package/dist/adapters/nestjs/access.guard.js.map +1 -0
  22. package/dist/adapters/nestjs/index.d.ts +6 -0
  23. package/dist/adapters/nestjs/index.d.ts.map +1 -0
  24. package/dist/adapters/nestjs/index.js +6 -0
  25. package/dist/adapters/nestjs/index.js.map +1 -0
  26. package/dist/adapters/nestjs/kit.module.d.ts +35 -0
  27. package/dist/adapters/nestjs/kit.module.d.ts.map +1 -0
  28. package/dist/adapters/nestjs/kit.module.js +54 -0
  29. package/dist/adapters/nestjs/kit.module.js.map +1 -0
  30. package/dist/adapters/nestjs/kit.service.d.ts +58 -0
  31. package/dist/adapters/nestjs/kit.service.d.ts.map +1 -0
  32. package/dist/adapters/nestjs/kit.service.js +102 -0
  33. package/dist/adapters/nestjs/kit.service.js.map +1 -0
  34. package/dist/adapters/nestjs/logger.service.d.ts +30 -0
  35. package/dist/adapters/nestjs/logger.service.d.ts.map +1 -0
  36. package/dist/adapters/nestjs/logger.service.js +66 -0
  37. package/dist/adapters/nestjs/logger.service.js.map +1 -0
  38. package/dist/adapters/nestjs/options.d.ts +17 -0
  39. package/dist/adapters/nestjs/options.d.ts.map +1 -0
  40. package/dist/adapters/nestjs/options.js +6 -0
  41. package/dist/adapters/nestjs/options.js.map +1 -0
  42. package/dist/config/index.d.ts +1 -1
  43. package/dist/config/index.d.ts.map +1 -1
  44. package/dist/config/index.js +1 -1
  45. package/dist/config/index.js.map +1 -1
  46. package/dist/config/seo.service.d.ts +39 -0
  47. package/dist/config/seo.service.d.ts.map +1 -1
  48. package/dist/config/seo.service.js +54 -1
  49. package/dist/config/seo.service.js.map +1 -1
  50. package/package.json +22 -1
package/README.md CHANGED
@@ -29,7 +29,7 @@ In the browser, use jsDelivr **`/+esm`** so named exports and dependencies resol
29
29
  | **esm.sh** | `https://esm.sh/katanakit-js` |
30
30
  | **Raw ESM file** | `https://cdn.jsdelivr.net/npm/katanakit-js/dist/index.js` (needs bundler or import map) |
31
31
 
32
- Pin a version in production (e.g. `@6.7.4/+esm`). There is no IIFE/UMD build.
32
+ Pin a version in production (e.g. `@6.8.0/+esm`). There is no IIFE/UMD build.
33
33
 
34
34
  ## Quick Start
35
35
 
@@ -871,6 +871,8 @@ See [Getting Started](https://docs.senseikatana.com/guides/getting-started) for
871
871
  | ----------- | ----------------------------------------------- | ------------------------------------------------------- |
872
872
  | **Express** | `katanakit-js/adapters/express` | Reference server with CORS and hardened headers |
873
873
  | **Bun** | `katanakit-js/adapters/bun` | `Bun.serve` route table + dummyjson.com demo |
874
+ | **NestJS** | `katanakit-js/adapters/nestjs` | `KatanaKitModule`, injectable facade, capability guard and logger bridge |
875
+ | **Hono** | `katanakit-js/adapters/hono` | Runtime-agnostic app factory, capability middleware and `useSafeJson` |
874
876
  | **Nuxt** | `katanakit-js/adapters/nuxt` | `useUnwrap`, `useSafeResponse`, `useEventResponse` |
875
877
  | **Astro** | `katanakit-js` or `katanakit-js/adapters/astro` | `AstroService`, `RssService` |
876
878
 
@@ -1548,13 +1550,15 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development contract.
1548
1550
 
1549
1551
  The docs site is built with **VitePress** from [`docs/`](./docs) and deployed with Cloudflare Pages at [docs.senseikatana.com](https://docs.senseikatana.com/). Run it locally with `bun run docs:dev`.
1550
1552
 
1551
- - [Getting Started](https://docs.senseikatana.com/guides/getting-started)
1552
- - [Error Handling](https://docs.senseikatana.com/guides/errors)
1553
- - [Architecture](https://docs.senseikatana.com/guides/architecture)
1554
- - [UI Kit (Katana UI)](https://docs.senseikatana.com/ui-kit/)
1555
- - [API Reference](https://docs.senseikatana.com/api/)
1556
- - [Roadmap](https://docs.senseikatana.com/guides/roadmap)
1557
- - [Changelog](https://docs.senseikatana.com/changelog)
1553
+ - **Introduction** — [Getting Started](https://docs.senseikatana.com/guides/getting-started) · [Error Handling](https://docs.senseikatana.com/guides/errors) · [Architecture](https://docs.senseikatana.com/guides/architecture) · [Roadmap](https://docs.senseikatana.com/guides/roadmap)
1554
+ - **Core Services** — [Overview](https://docs.senseikatana.com/guides/services/) · [HTTP Client](https://docs.senseikatana.com/guides/services/http-client) · [DOM](https://docs.senseikatana.com/guides/services/dom) · [Storage](https://docs.senseikatana.com/guides/services/storage) · [Dates](https://docs.senseikatana.com/guides/services/dates)
1555
+ - **Platform Services** — [Theme](https://docs.senseikatana.com/guides/services/theme) · [Astro Adapter](https://docs.senseikatana.com/guides/services/astro-adapter) · [RSS](https://docs.senseikatana.com/guides/services/rss) · [SEO](https://docs.senseikatana.com/guides/services/seo)
1556
+ - **Integrations** — [Nuxt Adapter](https://docs.senseikatana.com/guides/services/nuxt-adapter) · [Vue Adapter](https://docs.senseikatana.com/guides/services/vue-adapter) · [Express Server](https://docs.senseikatana.com/guides/services/express-server)
1557
+ - **HTTP & REST** — [Query Client](https://docs.senseikatana.com/guides/query-client) · [Framework Adapters](https://docs.senseikatana.com/guides/framework-adapters) · [Better Auth](https://docs.senseikatana.com/guides/better-auth)
1558
+ - **Runtime & Filesystem** — [Filesystem](https://docs.senseikatana.com/guides/filesystem) · [Bun Adapter](https://docs.senseikatana.com/guides/bun-adapter) · [Faker](https://docs.senseikatana.com/guides/faker)
1559
+ - **Browser & DOM** — [Watch](https://docs.senseikatana.com/guides/watch) · [PhotoSwipe](https://docs.senseikatana.com/guides/photoswipe)
1560
+ - **UI Kit (Katana UI)** — [Overview](https://docs.senseikatana.com/ui-kit/) · [SCSS framework](https://docs.senseikatana.com/ui-kit/css/)
1561
+ - **Reference** — [API Reference](https://docs.senseikatana.com/api/) · [Changelog](https://docs.senseikatana.com/changelog)
1558
1562
 
1559
1563
  ## License
1560
1564
 
@@ -0,0 +1,31 @@
1
+ import type { Context, MiddlewareHandler } from "hono";
2
+ import type { AccessCapability, AccessSubject } from "../../types/index.js";
3
+ /**
4
+ * Builds a Hono middleware that requires an access capability, mirroring the
5
+ * Express `useRequireCapability()` and Nest guard behavior.
6
+ *
7
+ * The project ships no auth provider, so the subject is resolved by the caller
8
+ * (JWT, session, API key…) from the request context. Return `null` for
9
+ * anonymous requests — they get a 401; authenticated but not allowed gets a
10
+ * 403. Both bodies use the toolkit's `{ ok, data, error }` shape.
11
+ *
12
+ * @param capability - The capability required to reach the route.
13
+ * @param resolveSubject - Resolves the access subject from the Hono context.
14
+ * @returns A Hono middleware handler for `app.use()` / `app.get(..., mw)`.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { Hono } from "hono";
19
+ * import { useRequireCapability } from "katanakit-js/adapters/hono";
20
+ *
21
+ * const app = new Hono();
22
+ * const canPublish = useRequireCapability("content:publish", (c) => {
23
+ * const header = c.req.header("authorization");
24
+ * return header ? { id: 1, roles: ["owner"] } : null; // your auth lookup
25
+ * });
26
+ *
27
+ * app.post("/articles/:id/publish", canPublish, (c) => c.json({ ok: true }));
28
+ * ```
29
+ */
30
+ export declare function useRequireCapability(capability: AccessCapability, resolveSubject: (context: Context) => AccessSubject | null): MiddlewareHandler;
31
+ //# sourceMappingURL=access.guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.guard.d.ts","sourceRoot":"","sources":["../../../src/adapters/hono/access.guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,gBAAgB,EAC5B,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,aAAa,GAAG,IAAI,GACxD,iBAAiB,CAgCnB"}
@@ -0,0 +1,53 @@
1
+ import { useCan } from "../../core/services/access.service.js";
2
+ /**
3
+ * Builds a Hono middleware that requires an access capability, mirroring the
4
+ * Express `useRequireCapability()` and Nest guard behavior.
5
+ *
6
+ * The project ships no auth provider, so the subject is resolved by the caller
7
+ * (JWT, session, API key…) from the request context. Return `null` for
8
+ * anonymous requests — they get a 401; authenticated but not allowed gets a
9
+ * 403. Both bodies use the toolkit's `{ ok, data, error }` shape.
10
+ *
11
+ * @param capability - The capability required to reach the route.
12
+ * @param resolveSubject - Resolves the access subject from the Hono context.
13
+ * @returns A Hono middleware handler for `app.use()` / `app.get(..., mw)`.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Hono } from "hono";
18
+ * import { useRequireCapability } from "katanakit-js/adapters/hono";
19
+ *
20
+ * const app = new Hono();
21
+ * const canPublish = useRequireCapability("content:publish", (c) => {
22
+ * const header = c.req.header("authorization");
23
+ * return header ? { id: 1, roles: ["owner"] } : null; // your auth lookup
24
+ * });
25
+ *
26
+ * app.post("/articles/:id/publish", canPublish, (c) => c.json({ ok: true }));
27
+ * ```
28
+ */
29
+ export function useRequireCapability(capability, resolveSubject) {
30
+ return async (context, next) => {
31
+ const subject = resolveSubject(context);
32
+ if (!subject) {
33
+ return context.json({ ok: false, data: null, error: { message: "Authentication required", status: 401 } }, 401);
34
+ }
35
+ let allowed;
36
+ try {
37
+ allowed = useCan(subject, capability);
38
+ }
39
+ catch {
40
+ // Malformed subject or unknown role: fail closed at the HTTP boundary.
41
+ allowed = false;
42
+ }
43
+ if (!allowed) {
44
+ return context.json({
45
+ ok: false,
46
+ data: null,
47
+ error: { message: `Missing capability: ${capability}`, status: 403 },
48
+ }, 403);
49
+ }
50
+ await next();
51
+ };
52
+ }
53
+ //# sourceMappingURL=access.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.guard.js","sourceRoot":"","sources":["../../../src/adapters/hono/access.guard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,oBAAoB,CACnC,UAA4B,EAC5B,cAA0D;IAE1D,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9B,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QAExC,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,OAAO,CAAC,IAAI,CAClB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,yBAAyB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EACrF,GAAG,CACH,CAAC;QACH,CAAC;QAED,IAAI,OAAgB,CAAC;QACrB,IAAI,CAAC;YACJ,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACR,uEAAuE;YACvE,OAAO,GAAG,KAAK,CAAC;QACjB,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,OAAO,CAAC,IAAI,CAClB;gBACC,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,IAAI;gBACV,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;aACpE,EACD,GAAG,CACH,CAAC;QACH,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACd,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { Hono } from "hono";
2
+ /** Options accepted by {@link useCreateApp}. */
3
+ export interface HonoAppOptions {
4
+ /**
5
+ * Allowed CORS origins. Defaults to the `CORS_ORIGINS` env variable
6
+ * (comma-separated) or `http://localhost:3000`.
7
+ */
8
+ corsOrigins?: string[];
9
+ /** Registers `GET /health` (default `true`). */
10
+ health?: boolean;
11
+ }
12
+ /**
13
+ * Creates a Hono app pre-configured for KatanaKit services.
14
+ *
15
+ * The factory is runtime-agnostic — the same app runs on Node
16
+ * (`@hono/node-server`), Bun (`Bun.serve`), Deno and Cloudflare Workers
17
+ * (`export default app`). It mounts `secureHeaders()`, CORS from the same
18
+ * `CORS_ORIGINS` convention as the Express adapter, an optional `/health`
19
+ * probe and JSON error bodies in the toolkit's `{ ok, data, error }` shape.
20
+ *
21
+ * @param options - CORS origins and health-check toggle.
22
+ * @returns A configured Hono application, ready to mount routes on.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { useCreateApp, useRequireCapability, useSafeJson } from "katanakit-js/adapters/hono";
27
+ * import { useGetApi } from "katanakit-js";
28
+ *
29
+ * const app = useCreateApp();
30
+ *
31
+ * app.get("/pokemon/:id", async (c) => {
32
+ * const result = await useGetApi("pokeapi", "pokemonById", {
33
+ * params: { id: c.req.param("id") },
34
+ * });
35
+ * return useSafeJson(c, result);
36
+ * });
37
+ *
38
+ * export default app; // Cloudflare Workers / Deno
39
+ * ```
40
+ */
41
+ export declare function useCreateApp(options?: HonoAppOptions): Hono;
42
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/adapters/hono/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gDAAgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,IAAI,CA+B/D"}
@@ -0,0 +1,59 @@
1
+ import { Hono } from "hono";
2
+ import { cors } from "hono/cors";
3
+ import { secureHeaders } from "hono/secure-headers";
4
+ import { useLogger } from "../../core/services/logger.service.js";
5
+ /** Resolves the CORS allow-list from options or the environment. */
6
+ function resolveCorsOrigins(options) {
7
+ if (options.corsOrigins)
8
+ return options.corsOrigins;
9
+ return (process.env.CORS_ORIGINS?.split(",") ?? ["http://localhost:3000"])
10
+ .map((origin) => origin.trim())
11
+ .filter(Boolean);
12
+ }
13
+ /**
14
+ * Creates a Hono app pre-configured for KatanaKit services.
15
+ *
16
+ * The factory is runtime-agnostic — the same app runs on Node
17
+ * (`@hono/node-server`), Bun (`Bun.serve`), Deno and Cloudflare Workers
18
+ * (`export default app`). It mounts `secureHeaders()`, CORS from the same
19
+ * `CORS_ORIGINS` convention as the Express adapter, an optional `/health`
20
+ * probe and JSON error bodies in the toolkit's `{ ok, data, error }` shape.
21
+ *
22
+ * @param options - CORS origins and health-check toggle.
23
+ * @returns A configured Hono application, ready to mount routes on.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { useCreateApp, useRequireCapability, useSafeJson } from "katanakit-js/adapters/hono";
28
+ * import { useGetApi } from "katanakit-js";
29
+ *
30
+ * const app = useCreateApp();
31
+ *
32
+ * app.get("/pokemon/:id", async (c) => {
33
+ * const result = await useGetApi("pokeapi", "pokemonById", {
34
+ * params: { id: c.req.param("id") },
35
+ * });
36
+ * return useSafeJson(c, result);
37
+ * });
38
+ *
39
+ * export default app; // Cloudflare Workers / Deno
40
+ * ```
41
+ */
42
+ export function useCreateApp(options = {}) {
43
+ const app = new Hono();
44
+ app.use("*", secureHeaders());
45
+ app.use("*", cors({
46
+ origin: resolveCorsOrigins(options),
47
+ allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE"],
48
+ }));
49
+ if (options.health ?? true) {
50
+ app.get("/health", (context) => context.json({ status: "ok", timestamp: new Date().toISOString() }));
51
+ }
52
+ app.notFound((context) => context.json({ ok: false, data: null, error: { message: "Not Found", status: 404 } }, 404));
53
+ app.onError((error, context) => {
54
+ useLogger("Unhandled error:", error, "error");
55
+ return context.json({ ok: false, data: null, error: { message: "Internal Server Error", status: 500 } }, 500);
56
+ });
57
+ return app;
58
+ }
59
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/adapters/hono/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAalE,oEAAoE;AACpE,SAAS,kBAAkB,CAAC,OAAuB;IAClD,IAAI,OAAO,CAAC,WAAW;QAAE,OAAO,OAAO,CAAC,WAAW,CAAC;IACpD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;SACxE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;SAC9B,MAAM,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,YAAY,CAAC,UAA0B,EAAE;IACxD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CACN,GAAG,EACH,IAAI,CAAC;QACJ,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC;QACnC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;KACvD,CAAC,CACF,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QAC5B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CACnE,CAAC;IACH,CAAC;IAED,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CACxB,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,CAC1F,CAAC;IAEF,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QAC9B,SAAS,CAAC,kBAAkB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,OAAO,CAAC,IAAI,CAClB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EACnF,GAAG,CACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACZ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { useRequireCapability } from "./access.guard.js";
2
+ export { type HonoAppOptions, useCreateApp } from "./app.js";
3
+ export { useSafeJson } from "./result.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/hono/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,KAAK,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { useRequireCapability } from "./access.guard.js";
2
+ export { useCreateApp } from "./app.js";
3
+ export { useSafeJson } from "./result.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/hono/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAuB,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { Context } from "hono";
2
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
3
+ import type { FetchResult } from "../../types/index.js";
4
+ /**
5
+ * Maps a KatanaKit Safe Result to a Hono JSON response.
6
+ *
7
+ * On success returns the whole Safe Result (`{ ok: true, data, error: null }`)
8
+ * with a 200. On failure it echoes the upstream HTTP status when the error
9
+ * carries one between 400 and 599 (proxy-style endpoints keep 404/429/503
10
+ * semantics); network and config errors (`status: 0`) fall back to
11
+ * `fallbackStatus` (500 by default).
12
+ *
13
+ * @param context - The Hono context.
14
+ * @param result - The Safe Result from any KatanaKit fetch method.
15
+ * @param fallbackStatus - Status used when the error has none (default 500).
16
+ * @returns A Hono JSON response.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { useSafeJson } from "katanakit-js/adapters/hono";
21
+ * import { useGetApi } from "katanakit-js";
22
+ *
23
+ * app.get("/products/:id", async (c) => {
24
+ * const result = await useGetApi("shop", "productById", {
25
+ * params: { id: c.req.param("id") },
26
+ * });
27
+ * return useSafeJson(c, result); // 200, upstream 4xx/5xx, or 500
28
+ * });
29
+ * ```
30
+ */
31
+ export declare function useSafeJson<T>(context: Context, result: FetchResult<T>, fallbackStatus?: ContentfulStatusCode): Response;
32
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../../src/adapters/hono/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC5B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,cAAc,GAAE,oBAA0B,GACxC,QAAQ,CAWV"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Maps a KatanaKit Safe Result to a Hono JSON response.
3
+ *
4
+ * On success returns the whole Safe Result (`{ ok: true, data, error: null }`)
5
+ * with a 200. On failure it echoes the upstream HTTP status when the error
6
+ * carries one between 400 and 599 (proxy-style endpoints keep 404/429/503
7
+ * semantics); network and config errors (`status: 0`) fall back to
8
+ * `fallbackStatus` (500 by default).
9
+ *
10
+ * @param context - The Hono context.
11
+ * @param result - The Safe Result from any KatanaKit fetch method.
12
+ * @param fallbackStatus - Status used when the error has none (default 500).
13
+ * @returns A Hono JSON response.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { useSafeJson } from "katanakit-js/adapters/hono";
18
+ * import { useGetApi } from "katanakit-js";
19
+ *
20
+ * app.get("/products/:id", async (c) => {
21
+ * const result = await useGetApi("shop", "productById", {
22
+ * params: { id: c.req.param("id") },
23
+ * });
24
+ * return useSafeJson(c, result); // 200, upstream 4xx/5xx, or 500
25
+ * });
26
+ * ```
27
+ */
28
+ export function useSafeJson(context, result, fallbackStatus = 500) {
29
+ if (result.ok) {
30
+ return context.json(result, 200);
31
+ }
32
+ const status = result.error.status >= 400 && result.error.status <= 599
33
+ ? result.error.status
34
+ : fallbackStatus;
35
+ return context.json(result, status);
36
+ }
37
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../../src/adapters/hono/result.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,WAAW,CAC1B,OAAgB,EAChB,MAAsB,EACtB,iBAAuC,GAAG;IAE1C,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,MAAM,GACX,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,GAAG;QACvD,CAAC,CAAE,MAAM,CAAC,KAAK,CAAC,MAA+B;QAC/C,CAAC,CAAC,cAAc,CAAC;IAEnB,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type CanActivate, type Type } from "@nestjs/common";
2
+ import type { AccessCapability, AccessSubject } from "../../types/index.js";
3
+ /**
4
+ * Builds a Nest guard that requires an access capability, mirroring the
5
+ * Express `useRequireCapability()` behavior on Nest's exception pipeline.
6
+ *
7
+ * The project ships no auth provider, so the subject is resolved by the caller
8
+ * (JWT, session, API key…). Return `null` for anonymous requests — they get a
9
+ * 401; authenticated but not allowed gets a 403. Both exceptions carry the
10
+ * same `{ ok, data, error }` body shape used across the toolkit.
11
+ *
12
+ * @typeParam TRequest - The platform request type (Express by default).
13
+ * @param capability - The capability required to activate the route.
14
+ * @param resolveSubject - Resolves the access subject from the request.
15
+ * @returns A guard class ready for `@UseGuards(...)`.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { Controller, Get, UseGuards } from "@nestjs/common";
20
+ * import { useRequireCapability } from "katanakit-js/adapters/nestjs";
21
+ *
22
+ * const CanPublish = useRequireCapability(
23
+ * "content:publish",
24
+ * (request: { account?: { id: number; roles: string[] } }) => request.account ?? null,
25
+ * );
26
+ *
27
+ * @Controller("articles")
28
+ * export class ArticlesController {
29
+ * @Get("drafts")
30
+ * @UseGuards(CanPublish)
31
+ * drafts() {
32
+ * return [];
33
+ * }
34
+ * }
35
+ * ```
36
+ */
37
+ export declare function useRequireCapability<TRequest = unknown>(capability: AccessCapability, resolveSubject: (request: TRequest) => AccessSubject | null): Type<CanActivate>;
38
+ //# sourceMappingURL=access.guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.guard.d.ts","sourceRoot":"","sources":["../../../src/adapters/nestjs/access.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,WAAW,EAGhB,KAAK,IAAI,EAET,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAG,OAAO,EACtD,UAAU,EAAE,gBAAgB,EAC5B,cAAc,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,GAAG,IAAI,GACzD,IAAI,CAAC,WAAW,CAAC,CAmCnB"}
@@ -0,0 +1,69 @@
1
+ import { ForbiddenException, UnauthorizedException, } from "@nestjs/common";
2
+ import { useCan } from "../../core/services/access.service.js";
3
+ /**
4
+ * Builds a Nest guard that requires an access capability, mirroring the
5
+ * Express `useRequireCapability()` behavior on Nest's exception pipeline.
6
+ *
7
+ * The project ships no auth provider, so the subject is resolved by the caller
8
+ * (JWT, session, API key…). Return `null` for anonymous requests — they get a
9
+ * 401; authenticated but not allowed gets a 403. Both exceptions carry the
10
+ * same `{ ok, data, error }` body shape used across the toolkit.
11
+ *
12
+ * @typeParam TRequest - The platform request type (Express by default).
13
+ * @param capability - The capability required to activate the route.
14
+ * @param resolveSubject - Resolves the access subject from the request.
15
+ * @returns A guard class ready for `@UseGuards(...)`.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { Controller, Get, UseGuards } from "@nestjs/common";
20
+ * import { useRequireCapability } from "katanakit-js/adapters/nestjs";
21
+ *
22
+ * const CanPublish = useRequireCapability(
23
+ * "content:publish",
24
+ * (request: { account?: { id: number; roles: string[] } }) => request.account ?? null,
25
+ * );
26
+ *
27
+ * @Controller("articles")
28
+ * export class ArticlesController {
29
+ * @Get("drafts")
30
+ * @UseGuards(CanPublish)
31
+ * drafts() {
32
+ * return [];
33
+ * }
34
+ * }
35
+ * ```
36
+ */
37
+ export function useRequireCapability(capability, resolveSubject) {
38
+ class KatanaCapabilityGuard {
39
+ canActivate(context) {
40
+ const request = context.switchToHttp().getRequest();
41
+ const subject = resolveSubject(request);
42
+ if (!subject) {
43
+ throw new UnauthorizedException({
44
+ ok: false,
45
+ data: null,
46
+ error: { message: "Authentication required", status: 401 },
47
+ });
48
+ }
49
+ let allowed;
50
+ try {
51
+ allowed = useCan(subject, capability);
52
+ }
53
+ catch {
54
+ // Malformed subject or unknown role: fail closed at the HTTP boundary.
55
+ allowed = false;
56
+ }
57
+ if (!allowed) {
58
+ throw new ForbiddenException({
59
+ ok: false,
60
+ data: null,
61
+ error: { message: `Missing capability: ${capability}`, status: 403 },
62
+ });
63
+ }
64
+ return true;
65
+ }
66
+ }
67
+ return KatanaCapabilityGuard;
68
+ }
69
+ //# sourceMappingURL=access.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.guard.js","sourceRoot":"","sources":["../../../src/adapters/nestjs/access.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,kBAAkB,EAElB,qBAAqB,GACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,oBAAoB,CACnC,UAA4B,EAC5B,cAA2D;IAE3D,MAAM,qBAAqB;QAC1B,WAAW,CAAC,OAAyB;YACpC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAY,CAAC;YAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YAExC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,qBAAqB,CAAC;oBAC/B,EAAE,EAAE,KAAK;oBACT,IAAI,EAAE,IAAI;oBACV,KAAK,EAAE,EAAE,OAAO,EAAE,yBAAyB,EAAE,MAAM,EAAE,GAAG,EAAE;iBAC1D,CAAC,CAAC;YACJ,CAAC;YAED,IAAI,OAAgB,CAAC;YACrB,IAAI,CAAC;gBACJ,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACR,uEAAuE;gBACvE,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;YAED,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,kBAAkB,CAAC;oBAC5B,EAAE,EAAE,KAAK;oBACT,IAAI,EAAE,IAAI;oBACV,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;iBACpE,CAAC,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;KACD;IAED,OAAO,qBAAqB,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { useRequireCapability } from "./access.guard.js";
2
+ export { KatanaKitModule } from "./kit.module.js";
3
+ export { KatanaKitService } from "./kit.service.js";
4
+ export { KatanaLogger } from "./logger.service.js";
5
+ export { KATANA_KIT_OPTIONS, type KatanaKitModuleOptions } from "./options.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { useRequireCapability } from "./access.guard.js";
2
+ export { KatanaKitModule } from "./kit.module.js";
3
+ export { KatanaKitService } from "./kit.service.js";
4
+ export { KatanaLogger } from "./logger.service.js";
5
+ export { KATANA_KIT_OPTIONS } from "./options.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAA+B,MAAM,cAAc,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { type DynamicModule } from "@nestjs/common";
2
+ import { type KatanaKitModuleOptions } from "./options.js";
3
+ /**
4
+ * Wires KatanaKit into a Nest application.
5
+ *
6
+ * `forRoot()` registers the APIs (and optionally the shared query client) at
7
+ * bootstrap and exposes an injectable {@link KatanaKitService}. The module is
8
+ * global by default so feature modules do not need to import it again; pass
9
+ * `global: false` to scope it explicitly.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Module } from "@nestjs/common";
14
+ * import { KatanaKitModule } from "katanakit-js/adapters/nestjs";
15
+ *
16
+ * @Module({
17
+ * imports: [
18
+ * KatanaKitModule.forRoot({
19
+ * apis: {
20
+ * pokeapi: {
21
+ * baseUri: "https://pokeapi.co/api/v2",
22
+ * endpoints: { pokemonById: "/pokemon/:id/" },
23
+ * },
24
+ * },
25
+ * }),
26
+ * ],
27
+ * })
28
+ * export class AppModule {}
29
+ * ```
30
+ */
31
+ export declare class KatanaKitModule {
32
+ /** Creates the dynamic module with the toolkit providers. */
33
+ static forRoot(options?: KatanaKitModuleOptions): DynamicModule;
34
+ }
35
+ //# sourceMappingURL=kit.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit.module.d.ts","sourceRoot":"","sources":["../../../src/adapters/nestjs/kit.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAG5D,OAAO,EAAsB,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBACa,eAAe;IAC3B,6DAA6D;IAC7D,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,sBAA2B,GAAG,aAAa;CAQnE"}
@@ -0,0 +1,54 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var KatanaKitModule_1;
8
+ import { Module } from "@nestjs/common";
9
+ import { KatanaKitService } from "./kit.service.js";
10
+ import { KATANA_KIT_OPTIONS } from "./options.js";
11
+ /**
12
+ * Wires KatanaKit into a Nest application.
13
+ *
14
+ * `forRoot()` registers the APIs (and optionally the shared query client) at
15
+ * bootstrap and exposes an injectable {@link KatanaKitService}. The module is
16
+ * global by default so feature modules do not need to import it again; pass
17
+ * `global: false` to scope it explicitly.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { Module } from "@nestjs/common";
22
+ * import { KatanaKitModule } from "katanakit-js/adapters/nestjs";
23
+ *
24
+ * @Module({
25
+ * imports: [
26
+ * KatanaKitModule.forRoot({
27
+ * apis: {
28
+ * pokeapi: {
29
+ * baseUri: "https://pokeapi.co/api/v2",
30
+ * endpoints: { pokemonById: "/pokemon/:id/" },
31
+ * },
32
+ * },
33
+ * }),
34
+ * ],
35
+ * })
36
+ * export class AppModule {}
37
+ * ```
38
+ */
39
+ let KatanaKitModule = KatanaKitModule_1 = class KatanaKitModule {
40
+ /** Creates the dynamic module with the toolkit providers. */
41
+ static forRoot(options = {}) {
42
+ return {
43
+ module: KatanaKitModule_1,
44
+ global: options.global ?? true,
45
+ providers: [KatanaKitService, { provide: KATANA_KIT_OPTIONS, useValue: options }],
46
+ exports: [KatanaKitService],
47
+ };
48
+ }
49
+ };
50
+ KatanaKitModule = KatanaKitModule_1 = __decorate([
51
+ Module({})
52
+ ], KatanaKitModule);
53
+ export { KatanaKitModule };
54
+ //# sourceMappingURL=kit.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit.module.js","sourceRoot":"","sources":["../../../src/adapters/nestjs/kit.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAsB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAA+B,MAAM,cAAc,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEI,IAAM,eAAe,uBAArB,MAAM,eAAe;IAC3B,6DAA6D;IAC7D,MAAM,CAAC,OAAO,CAAC,UAAkC,EAAE;QAClD,OAAO;YACN,MAAM,EAAE,iBAAe;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;YAC9B,SAAS,EAAE,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;YACjF,OAAO,EAAE,CAAC,gBAAgB,CAAC;SAC3B,CAAC;IACH,CAAC;CACD,CAAA;AAVY,eAAe;IAD3B,MAAM,CAAC,EAAE,CAAC;GACE,eAAe,CAU3B"}