kizlo 0.1.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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/dist/adapters/auth.d.ts +18 -0
  4. package/dist/adapters/auth.js +15 -0
  5. package/dist/adapters/captcha.d.ts +28 -0
  6. package/dist/adapters/captcha.js +86 -0
  7. package/dist/adapters/geo.d.ts +18 -0
  8. package/dist/adapters/geo.js +18 -0
  9. package/dist/adapters/geo.vercel.d.ts +6 -0
  10. package/dist/adapters/geo.vercel.js +41 -0
  11. package/dist/adapters/logger.d.ts +31 -0
  12. package/dist/adapters/logger.js +30 -0
  13. package/dist/cli/banner.js +26 -0
  14. package/dist/cli/commands/generate.js +34 -0
  15. package/dist/cli/commands/init.js +313 -0
  16. package/dist/cli/commands/test.js +68 -0
  17. package/dist/cli/commands/watch.js +53 -0
  18. package/dist/cli/commands/wp.js +66 -0
  19. package/dist/cli/daemon/config.js +87 -0
  20. package/dist/cli/daemon/generate.js +40 -0
  21. package/dist/cli/daemon/lock.js +31 -0
  22. package/dist/cli/daemon/logger.js +8 -0
  23. package/dist/cli/daemon/watch.js +37 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +22 -0
  26. package/dist/cli/presets/base.js +23 -0
  27. package/dist/cli/presets/index.js +16 -0
  28. package/dist/cli/presets/nextjs.js +39 -0
  29. package/dist/cli/utils.js +182 -0
  30. package/dist/cli/wp/bootstrap.js +114 -0
  31. package/dist/cli/wp/compose/docker-compose.yml +73 -0
  32. package/dist/cli/wp/constants.js +52 -0
  33. package/dist/cli/wp/docker.d.ts +24 -0
  34. package/dist/cli/wp/docker.js +69 -0
  35. package/dist/cli/wp/setup.js +39 -0
  36. package/dist/cli/wp/types.d.ts +72 -0
  37. package/dist/cli/wp/types.js +8 -0
  38. package/dist/cli/wp/utils.d.ts +39 -0
  39. package/dist/cli/wp/utils.js +105 -0
  40. package/dist/client.d.ts +24 -0
  41. package/dist/client.js +55 -0
  42. package/dist/comment/errors.js +47 -0
  43. package/dist/comment/index.js +138 -0
  44. package/dist/comment/schema.js +72 -0
  45. package/dist/comment/utils.js +35 -0
  46. package/dist/config.d.ts +39 -0
  47. package/dist/config.js +7 -0
  48. package/dist/context.d.ts +73 -0
  49. package/dist/context.js +145 -0
  50. package/dist/cookie.d.ts +19 -0
  51. package/dist/cookie.js +25 -0
  52. package/dist/email/service.d.ts +11 -0
  53. package/dist/email/service.interface.d.ts +8 -0
  54. package/dist/email/service.js +20 -0
  55. package/dist/index.d.ts +39 -0
  56. package/dist/index.js +31 -0
  57. package/dist/integrations/nextjs/kizlo.client.d.ts +10 -0
  58. package/dist/integrations/nextjs/kizlo.client.js +13 -0
  59. package/dist/integrations/nextjs/kizlo.server.d.ts +12 -0
  60. package/dist/integrations/nextjs/kizlo.server.js +13 -0
  61. package/dist/integrations/nextjs/utils.js +11 -0
  62. package/dist/kizlo.d.ts +73 -0
  63. package/dist/kizlo.js +144 -0
  64. package/dist/menu/errors.js +16 -0
  65. package/dist/menu/fixture.d.ts +8 -0
  66. package/dist/menu/fixture.js +62 -0
  67. package/dist/menu/index.js +70 -0
  68. package/dist/menu/schema.js +70 -0
  69. package/dist/menu/utils.js +57 -0
  70. package/dist/nextjs/server.d.ts +2 -0
  71. package/dist/nextjs/server.js +3 -0
  72. package/dist/nextjs.d.ts +2 -0
  73. package/dist/nextjs.js +3 -0
  74. package/dist/package.js +5 -0
  75. package/dist/post/error.js +30 -0
  76. package/dist/post/fixture.d.ts +8 -0
  77. package/dist/post/fixture.js +71 -0
  78. package/dist/post/index.js +123 -0
  79. package/dist/post/schema.js +120 -0
  80. package/dist/post/utils.js +42 -0
  81. package/dist/post-type/service.js +48 -0
  82. package/dist/router.d.ts +624 -0
  83. package/dist/router.js +15 -0
  84. package/dist/seo/index.js +54 -0
  85. package/dist/seo/schema.d.ts +196 -0
  86. package/dist/seo/schema.js +96 -0
  87. package/dist/seo/types.d.ts +80 -0
  88. package/dist/seo/utils.js +44 -0
  89. package/dist/service.d.ts +17 -0
  90. package/dist/service.js +17 -0
  91. package/dist/shared/constants.js +10 -0
  92. package/dist/shared/contract.d.ts +21 -0
  93. package/dist/shared/contract.js +43 -0
  94. package/dist/shared/crypto.d.ts +28 -0
  95. package/dist/shared/crypto.js +34 -0
  96. package/dist/shared/error.d.ts +128 -0
  97. package/dist/shared/error.js +147 -0
  98. package/dist/shared/extension.d.ts +25 -0
  99. package/dist/shared/extension.js +7 -0
  100. package/dist/shared/identifier.d.ts +11 -0
  101. package/dist/shared/identifier.js +26 -0
  102. package/dist/shared/middleware.d.ts +29 -0
  103. package/dist/shared/procedure.d.ts +114 -0
  104. package/dist/shared/procedure.js +114 -0
  105. package/dist/shared/result.d.ts +24 -0
  106. package/dist/shared/result.js +49 -0
  107. package/dist/shared/router.d.ts +7 -0
  108. package/dist/shared/router.js +26 -0
  109. package/dist/shared/schema.d.ts +55 -0
  110. package/dist/shared/schema.js +43 -0
  111. package/dist/shared/serialize.d.ts +12 -0
  112. package/dist/shared/serialize.js +51 -0
  113. package/dist/shared/types.d.ts +35 -0
  114. package/dist/shared/utils.js +17 -0
  115. package/dist/test/auth.d.ts +7 -0
  116. package/dist/test/auth.js +15 -0
  117. package/dist/test/captcha.d.ts +7 -0
  118. package/dist/test/captcha.js +8 -0
  119. package/dist/test/client.d.ts +11 -0
  120. package/dist/test/client.js +14 -0
  121. package/dist/test/fixtures.d.ts +14 -0
  122. package/dist/test/fixtures.js +13 -0
  123. package/dist/test/server.d.ts +10 -0
  124. package/dist/test/server.js +32 -0
  125. package/dist/test/users.d.ts +14 -0
  126. package/dist/test/users.js +17 -0
  127. package/dist/test.d.ts +12 -0
  128. package/dist/test.js +13 -0
  129. package/dist/webhook/index.d.ts +38 -0
  130. package/dist/webhook/index.js +44 -0
  131. package/dist/webhook/schema.d.ts +45 -0
  132. package/dist/webhook/schema.js +72 -0
  133. package/dist/webhook/utils.js +21 -0
  134. package/dist/wordpress/comment/service.d.ts +28 -0
  135. package/dist/wordpress/comment/service.js +55 -0
  136. package/dist/wordpress/comment/types.d.ts +206 -0
  137. package/dist/wordpress/constants.d.ts +14 -0
  138. package/dist/wordpress/constants.js +13 -0
  139. package/dist/wordpress/error.d.ts +9 -0
  140. package/dist/wordpress/error.js +12 -0
  141. package/dist/wordpress/index.d.ts +15 -0
  142. package/dist/wordpress/menu/items/service.d.ts +28 -0
  143. package/dist/wordpress/menu/items/service.js +55 -0
  144. package/dist/wordpress/menu/items/types.d.ts +214 -0
  145. package/dist/wordpress/menu/service.d.ts +30 -0
  146. package/dist/wordpress/menu/service.js +58 -0
  147. package/dist/wordpress/menu/types.d.ts +115 -0
  148. package/dist/wordpress/post/service.d.ts +28 -0
  149. package/dist/wordpress/post/service.js +55 -0
  150. package/dist/wordpress/post/types.d.ts +290 -0
  151. package/dist/wordpress/service.d.ts +77 -0
  152. package/dist/wordpress/service.js +180 -0
  153. package/dist/wordpress/types.d.ts +67 -0
  154. package/dist/wordpress/user/service.d.ts +28 -0
  155. package/dist/wordpress/user/service.js +55 -0
  156. package/dist/wordpress/user/types.d.ts +221 -0
  157. package/dist/wordpress/utils.d.ts +7 -0
  158. package/dist/wordpress/utils.js +9 -0
  159. package/package.json +109 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kizlo
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.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ <br>
2
+
3
+ <p align="center">
4
+ <a name="readme-top"></a>
5
+ <a href="https://kizlo.io">
6
+ <picture>
7
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.kizlo.io/logo/icon-light.svg">
8
+ <source media="(prefers-color-scheme: light)" srcset="https://cdn.kizlo.io/logo/icon-dark.svg">
9
+ <img alt="Kizlo" src="https://cdn.kizlo.io/logo/icon-dark.svg" height="100">
10
+ </picture>
11
+ </a>
12
+ </p>
13
+
14
+ <h3 align="center">Headless WordPress Toolkit</h3>
15
+
16
+ <p align="center">
17
+ Your backend, your frontend — Kizlo handles the plumbing.
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://www.npmjs.com/package/kizlo"><img src="https://img.shields.io/npm/v/kizlo?style=flat-square&color=333" alt="npm version"></a>
22
+ <a href="./LICENSE"><img src="https://img.shields.io/github/license/kizlo-io/kizlo?style=flat-square&color=333" alt="License"></a>
23
+ <a href="https://www.npmjs.com/package/kizlo"><img src="https://img.shields.io/npm/dt/kizlo?style=flat-square&color=333" alt="npm downloads"></a>
24
+ </p>
25
+
26
+ <p align="center">
27
+ <a href="https://kizlo.io"><strong>Website</strong></a> ·
28
+ <a href="https://kizlo.io/docs"><strong>Docs</strong></a> ·
29
+ <a href="https://discord.com/invite/MjAUZamx5g"><strong>Discord</strong></a> ·
30
+ <a href="https://x.com/kizlo_io"><strong>Twitter</strong></a>
31
+ </p>
32
+
33
+ ---
34
+
35
+ ## What is Kizlo?
36
+
37
+ Kizlo is a framework-agnostic toolkit for headless WordPress, built for a stack you host and own from top to bottom. Use it to build websites, mobile apps, agentic applications, and more — Kizlo takes care of the plumbing so you can focus on the design.
38
+
39
+ ## Quick start
40
+
41
+ Set up Kizlo in your project:
42
+
43
+ ```bash
44
+ npx kizlo init
45
+ ```
46
+
47
+ Watch your extensions and regenerate the contract during development:
48
+
49
+ ```bash
50
+ npx kizlo dev
51
+ ```
52
+
53
+ Generate the contract once for production builds:
54
+
55
+ ```bash
56
+ npx kizlo generate
57
+ ```
58
+
59
+ See the [docs](https://kizlo.io/docs) for the full guide.
60
+
61
+ ## Contributing
62
+
63
+ Contributions are welcome — see [CONTRIBUTING.md](https://github.com/kizlo-io/kizlo/blob/main/CONTRIBUTING.md) for setup,
64
+ workflow, and PR guidelines.
65
+
66
+ ## Security
67
+
68
+ If you discover a security vulnerability within Kizlo, please send an e-mail to security@kizlo.io.
69
+
70
+ All reports will be promptly addressed, and you'll be credited accordingly.
71
+
72
+ ## Disclaimer
73
+
74
+ Kizlo is an independent project and is not endorsed by, sponsored by, or affiliated with the WordPress Foundation or WooCommerce, Inc. The WordPress® trademarks are the intellectual property of the WordPress Foundation, and the Woo® and WooCommerce® trademarks are the intellectual property of WooCommerce, Inc. Uses of the WordPress®, Woo®, and WooCommerce® names in this organization are for identification purposes only and do not imply endorsement.
@@ -0,0 +1,18 @@
1
+ import { Promisify } from "@kizlo/shared";
2
+
3
+ //#region src/adapters/auth.d.ts
4
+ interface AuthUser {
5
+ id: number;
6
+ email?: string;
7
+ phone?: string;
8
+ firstName: string;
9
+ lastName: string;
10
+ }
11
+ interface AuthAdapter {
12
+ getUser(request: Request | null): Promisify<AuthUser | null>;
13
+ }
14
+ declare function authMock(options?: {
15
+ mockUserId?: number;
16
+ }): AuthAdapter;
17
+ //#endregion
18
+ export { AuthAdapter, AuthUser, authMock };
@@ -0,0 +1,15 @@
1
+ //#region src/adapters/auth.ts
2
+ function authMock(options) {
3
+ return { getUser() {
4
+ return {
5
+ id: options?.mockUserId ?? 0,
6
+ firstName: "Karan",
7
+ lastName: "Gill",
8
+ email: "karan@gmail.con",
9
+ phone: "12345678901"
10
+ };
11
+ } };
12
+ }
13
+
14
+ //#endregion
15
+ export { authMock };
@@ -0,0 +1,28 @@
1
+ //#region src/adapters/captcha.d.ts
2
+ type CaptchaAdapter = (input: {
3
+ token: string;
4
+ ip: string;
5
+ }) => Promise<boolean>;
6
+ declare function recaptcha(opts: {
7
+ secret: string;
8
+ minScore?: number;
9
+ }): CaptchaAdapter;
10
+ declare function turnstile(opts: {
11
+ secret: string;
12
+ }): CaptchaAdapter;
13
+ declare function hcaptcha(opts: {
14
+ secret: string;
15
+ sitekey?: string;
16
+ }): CaptchaAdapter;
17
+ declare function friendlyCaptcha(opts: {
18
+ secret: string;
19
+ sitekey?: string;
20
+ }): CaptchaAdapter;
21
+ declare function arkose(opts: {
22
+ privateKey: string;
23
+ }): CaptchaAdapter;
24
+ declare function altcha(opts: {
25
+ hmacKey: string;
26
+ }): CaptchaAdapter;
27
+ //#endregion
28
+ export { CaptchaAdapter, altcha, arkose, friendlyCaptcha, hcaptcha, recaptcha, turnstile };
@@ -0,0 +1,86 @@
1
+ //#region src/adapters/captcha.ts
2
+ function recaptcha(opts) {
3
+ return async ({ token, ip }) => {
4
+ const data = await (await fetch("https://www.google.com/recaptcha/api/siteverify", {
5
+ method: "POST",
6
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
7
+ body: new URLSearchParams({
8
+ secret: opts.secret,
9
+ response: token,
10
+ ...ip && { remoteip: ip }
11
+ })
12
+ })).json();
13
+ if (!data.success) return false;
14
+ if (opts.minScore !== void 0 && data.score !== void 0) return data.score >= opts.minScore;
15
+ return true;
16
+ };
17
+ }
18
+ function turnstile(opts) {
19
+ return async ({ token, ip }) => {
20
+ return (await (await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
23
+ body: new URLSearchParams({
24
+ secret: opts.secret,
25
+ response: token,
26
+ ...ip && { remoteip: ip }
27
+ })
28
+ })).json()).success === true;
29
+ };
30
+ }
31
+ function hcaptcha(opts) {
32
+ return async ({ token, ip }) => {
33
+ return (await (await fetch("https://api.hcaptcha.com/siteverify", {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
36
+ body: new URLSearchParams({
37
+ secret: opts.secret,
38
+ response: token,
39
+ ...ip && { remoteip: ip },
40
+ ...opts.sitekey && { sitekey: opts.sitekey }
41
+ })
42
+ })).json()).success === true;
43
+ };
44
+ }
45
+ function friendlyCaptcha(opts) {
46
+ return async ({ token }) => {
47
+ return (await (await fetch("https://api.friendlycaptcha.com/api/v1/siteverify", {
48
+ method: "POST",
49
+ headers: { "Content-Type": "application/json" },
50
+ body: JSON.stringify({
51
+ solution: token,
52
+ secret: opts.secret,
53
+ ...opts.sitekey && { sitekey: opts.sitekey }
54
+ })
55
+ })).json()).success === true;
56
+ };
57
+ }
58
+ function arkose(opts) {
59
+ return async ({ token, ip }) => {
60
+ return (await (await fetch("https://verify-api.arkoselabs.com/api/v4/verify/", {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
63
+ body: new URLSearchParams({
64
+ private_key: opts.privateKey,
65
+ session_token: token,
66
+ ...ip && { log_data: ip }
67
+ })
68
+ })).json()).session_details?.solved === true;
69
+ };
70
+ }
71
+ function altcha(opts) {
72
+ return async ({ token }) => {
73
+ try {
74
+ const payload = JSON.parse(Buffer.from(token, "base64").toString("utf-8"));
75
+ const { createHmac, createHash } = await import("node:crypto");
76
+ const algo = payload.algorithm.toLowerCase().replace("-", "");
77
+ if (createHash(algo).update(`${payload.salt}${payload.number}`).digest("hex") !== payload.challenge) return false;
78
+ return createHmac(algo, opts.hmacKey).update(payload.challenge).digest("hex") === payload.signature;
79
+ } catch {
80
+ return false;
81
+ }
82
+ };
83
+ }
84
+
85
+ //#endregion
86
+ export { altcha, arkose, friendlyCaptcha, hcaptcha, recaptcha, turnstile };
@@ -0,0 +1,18 @@
1
+ import { Promisify } from "@kizlo/shared";
2
+
3
+ //#region src/adapters/geo.d.ts
4
+ interface ConnInfo {
5
+ ip: string | null;
6
+ country: string | null;
7
+ city: string | null;
8
+ state: string | null;
9
+ postcode: string | null;
10
+ timezone: string | null;
11
+ userAgent: string | null;
12
+ }
13
+ interface GeoAdapter {
14
+ getConnInfo(request: Request | null): Promisify<ConnInfo>;
15
+ }
16
+ declare function geoMock(values?: Partial<ConnInfo>): GeoAdapter;
17
+ //#endregion
18
+ export { ConnInfo, GeoAdapter, geoMock };
@@ -0,0 +1,18 @@
1
+ //#region src/adapters/geo.ts
2
+ function geoMock(values) {
3
+ return { getConnInfo(request) {
4
+ return {
5
+ ip: "49.205.46.133",
6
+ city: "DL",
7
+ state: "HR",
8
+ country: "IN",
9
+ postcode: "110058",
10
+ userAgent: request?.headers.get("User-Agent") ?? null,
11
+ timezone: null,
12
+ ...values
13
+ };
14
+ } };
15
+ }
16
+
17
+ //#endregion
18
+ export { geoMock };
@@ -0,0 +1,6 @@
1
+ import { GeoAdapter } from "./geo.js";
2
+
3
+ //#region src/adapters/geo.vercel.d.ts
4
+ declare function geoVercelNext(): GeoAdapter;
5
+ //#endregion
6
+ export { geoVercelNext };
@@ -0,0 +1,41 @@
1
+ //#region src/adapters/geo.vercel.ts
2
+ function geoVercelNext() {
3
+ return { getConnInfo: async (request) => {
4
+ if (request) return readVercelHeaders(request.headers);
5
+ let nextHeaders;
6
+ try {
7
+ nextHeaders = await (await import("next/headers")).headers();
8
+ } catch (err) {
9
+ throw new Error("geoVercelNext: no Request was provided and `next/headers` could not be loaded. Install `next` as a peer dependency, or pass a Request to the SDK.", { cause: err });
10
+ }
11
+ return readVercelHeaders(nextHeaders);
12
+ } };
13
+ }
14
+ function readVercelHeaders(headers) {
15
+ const xRealIp = headers.get("x-real-ip");
16
+ const xff = headers.get("x-forwarded-for");
17
+ const ip = xRealIp || xff?.split(",")[0]?.trim() || null;
18
+ const country = headers.get("x-vercel-ip-country") || null;
19
+ const cityRaw = headers.get("x-vercel-ip-city");
20
+ const tzRaw = headers.get("x-vercel-ip-timezone");
21
+ const userAgent = headers.get("User-Agent");
22
+ return {
23
+ ip,
24
+ country,
25
+ city: cityRaw ? safeDecode(cityRaw) : null,
26
+ timezone: tzRaw ? safeDecode(tzRaw) : null,
27
+ postcode: null,
28
+ state: null,
29
+ userAgent
30
+ };
31
+ }
32
+ function safeDecode(value) {
33
+ try {
34
+ return decodeURIComponent(value);
35
+ } catch {
36
+ return value || null;
37
+ }
38
+ }
39
+
40
+ //#endregion
41
+ export { geoVercelNext };
@@ -0,0 +1,31 @@
1
+ import { LiteralUnion } from "@kizlo/shared";
2
+
3
+ //#region src/adapters/logger.d.ts
4
+ type LogLevel = "debug" | "info" | "warn" | "error";
5
+ type Environment = LiteralUnion<"development" | "production" | "test", string>;
6
+ interface LogPayload {
7
+ level: LogLevel;
8
+ message: string;
9
+ timestamp: Date;
10
+ context?: Record<string, unknown>;
11
+ error?: Error;
12
+ }
13
+ type LoggerAdapter = (payload: LogPayload) => void | Promise<void>;
14
+ interface Logger {
15
+ debug(message: string, context?: Record<string, unknown>): void;
16
+ info(message: string, context?: Record<string, unknown>): void;
17
+ warn(message: string, context?: Record<string, unknown>): void;
18
+ error(message: string, error?: Error, context?: Record<string, unknown>): void;
19
+ child(context: Record<string, unknown>): Logger;
20
+ }
21
+ interface ConsoleLogAdapterOptions {
22
+ /**
23
+ * Which levels to log. `true` means all, an array means only those.
24
+ * Default: all levels.
25
+ */
26
+ levels?: boolean | LogLevel[];
27
+ }
28
+ declare function consoleLog(opts?: ConsoleLogAdapterOptions): LoggerAdapter;
29
+ declare const noopAdapter: LoggerAdapter;
30
+ //#endregion
31
+ export { ConsoleLogAdapterOptions, Environment, LogLevel, LogPayload, Logger, LoggerAdapter, consoleLog, noopAdapter };
@@ -0,0 +1,30 @@
1
+ //#region src/adapters/logger.ts
2
+ function consoleLog(opts = {}) {
3
+ const levelsOpt = opts.levels ?? true;
4
+ const allowed = levelsOpt === true ? null : new Set(levelsOpt === false ? [] : levelsOpt);
5
+ return (payload) => {
6
+ if (allowed && !allowed.has(payload.level)) return;
7
+ const { level, message, timestamp, context, error } = payload;
8
+ const args = [`[${timestamp.toISOString()}] [${level.toUpperCase()}]`, message];
9
+ if (context) args.push(context);
10
+ if (error) args.push(error);
11
+ switch (level) {
12
+ case "debug":
13
+ console.debug(...args);
14
+ break;
15
+ case "info":
16
+ console.info(...args);
17
+ break;
18
+ case "warn":
19
+ console.warn(...args);
20
+ break;
21
+ case "error":
22
+ console.error(...args);
23
+ break;
24
+ }
25
+ };
26
+ }
27
+ const noopAdapter = () => {};
28
+
29
+ //#endregion
30
+ export { consoleLog, noopAdapter };
@@ -0,0 +1,26 @@
1
+ //#region src/cli/banner.ts
2
+ const KIZLO_CLI_WORD_MARK = [
3
+ "██╗ ██╗██╗███████╗██╗ ██████╗ ",
4
+ "██║ ██╔╝██║╚══███╔╝██║ ██╔═══██╗",
5
+ "█████╔╝ ██║ ███╔╝ ██║ ██║ ██║",
6
+ "██╔═██╗ ██║ ███╔╝ ██║ ██║ ██║",
7
+ "██║ ██╗██║███████╗███████╗╚██████╔╝",
8
+ "╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚═════╝ "
9
+ ];
10
+ const KIZLO_TAGLINE = "Headless WordPress toolkit for TypeScript";
11
+ function colorSupported() {
12
+ return Boolean(process.stdout.isTTY) && process.env.NO_COLOR === void 0 && process.env.TERM !== "dumb";
13
+ }
14
+ function printBanner(version) {
15
+ const color = colorSupported();
16
+ const cyan = color ? "\x1B[38;5;44m" : "";
17
+ const bold = color ? "\x1B[1m" : "";
18
+ const dim = color ? "\x1B[2m" : "";
19
+ const reset = color ? "\x1B[0m" : "";
20
+ const art = KIZLO_CLI_WORD_MARK.map((line) => `${cyan}${line}${reset}`).join("\n");
21
+ process.stdout.write(`\n${art}\n\n`);
22
+ process.stdout.write(`${dim}${KIZLO_TAGLINE}${reset} ${bold}v${version}${reset}\n\n`);
23
+ }
24
+
25
+ //#endregion
26
+ export { printBanner };
@@ -0,0 +1,34 @@
1
+ import { log } from "../daemon/logger.js";
2
+ import { resolveConfig } from "../daemon/config.js";
3
+ import { generateOnce } from "../daemon/generate.js";
4
+ import { defineCommand } from "citty";
5
+
6
+ //#region src/cli/commands/generate.ts
7
+ const generate = defineCommand({
8
+ meta: {
9
+ name: "generate",
10
+ description: "Generate the Kizlo contract once (for builds and CI)"
11
+ },
12
+ args: { dir: {
13
+ type: "string",
14
+ description: "Override the Kizlo directory (defaults to kizlo.config.ts)"
15
+ } },
16
+ async run({ args }) {
17
+ const cfg = await resolveConfig(process.cwd(), { dir: args.dir });
18
+ let ok;
19
+ try {
20
+ ok = await generateOnce(cfg);
21
+ } catch (error) {
22
+ log.error("Failed to generate the Kizlo contract:", error);
23
+ process.exit(1);
24
+ }
25
+ if (!ok) {
26
+ log.error(`No Kizlo server found in ${cfg.serverEntry}`);
27
+ process.exit(1);
28
+ }
29
+ log.success("Contract generated");
30
+ }
31
+ });
32
+
33
+ //#endregion
34
+ export { generate };