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
@@ -0,0 +1,7 @@
1
+ import { AnyProcedureRouter } from "./procedure.js";
2
+ import { AnyRouter } from "@orpc/server";
3
+
4
+ //#region src/shared/router.d.ts
5
+ declare function createOrpcRouter(router: AnyProcedureRouter): AnyRouter;
6
+ //#endregion
7
+ export { createOrpcRouter };
@@ -0,0 +1,26 @@
1
+ import { buildProcedure } from "./procedure.js";
2
+
3
+ //#region src/shared/router.ts
4
+ function createOrpcRouter(router) {
5
+ const cache = /* @__PURE__ */ new Map();
6
+ return new Proxy(router, { get: (target, p) => {
7
+ if (typeof p === "symbol") return target[p];
8
+ if (cache.has(p)) return cache.get(p);
9
+ const value = target[p];
10
+ if (value === void 0) return void 0;
11
+ let resolved;
12
+ if (isProcedure(value)) resolved = buildProcedure(value);
13
+ else if (typeof value === "object" && value !== null) resolved = createOrpcRouter(value);
14
+ else resolved = value;
15
+ cache.set(p, resolved);
16
+ return resolved;
17
+ } });
18
+ }
19
+ function isProcedure(value) {
20
+ if (typeof value !== "object" || value === null) return false;
21
+ const brand = value["~kizlo"];
22
+ return typeof brand === "object" && brand !== null && "options" in brand && "uses" in brand && "handler" in brand && typeof brand.handler === "function";
23
+ }
24
+
25
+ //#endregion
26
+ export { createOrpcRouter };
@@ -0,0 +1,55 @@
1
+ import z from "zod/v4";
2
+
3
+ //#region src/shared/schema.d.ts
4
+ declare const LIST_ORDER: readonly ["asc", "desc"];
5
+ declare const ListOrder: z.ZodEnum<{
6
+ asc: "asc";
7
+ desc: "desc";
8
+ }>;
9
+ type ListOrder = z.infer<typeof ListOrder>;
10
+ declare const ListMetadata: z.ZodObject<{
11
+ page: z.ZodNumber;
12
+ totalItems: z.ZodNumber;
13
+ totalPages: z.ZodNumber;
14
+ nextPage: z.ZodNullable<z.ZodNumber>;
15
+ prevPage: z.ZodNullable<z.ZodNumber>;
16
+ hasNextPage: z.ZodBoolean;
17
+ hasPrevPage: z.ZodBoolean;
18
+ }, z.core.$strip>;
19
+ type ListMetadata = z.infer<typeof ListMetadata>;
20
+ declare const CurrencyFormat: z.ZodObject<{
21
+ currencyCode: z.ZodString;
22
+ currencySymbol: z.ZodString;
23
+ currencyPrefix: z.ZodString;
24
+ currencySuffix: z.ZodString;
25
+ currencyMinorUnit: z.ZodNumber;
26
+ currencyDecimalSeparator: z.ZodString;
27
+ currencyThousandSeparator: z.ZodString;
28
+ }, z.core.$strip>;
29
+ type CurrencyFormat = z.infer<typeof CurrencyFormat>;
30
+ declare const Media: z.ZodObject<{
31
+ id: z.ZodNumber;
32
+ name: z.ZodString;
33
+ alt: z.ZodString;
34
+ src: z.ZodString;
35
+ }, z.core.$strip>;
36
+ type Media = z.infer<typeof Media>;
37
+ declare const IdentifierInput: z.ZodUnion<readonly [z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodCoercedNumber<string | number>>, z.ZodString]>;
38
+ type IdentifierInput = z.output<typeof IdentifierInput>;
39
+ declare const PreviewTokenPayload: z.ZodObject<{
40
+ id: z.ZodNumber;
41
+ parent: z.ZodNumber;
42
+ expires: z.ZodNumber;
43
+ }, z.core.$strip>;
44
+ type PreviewTokenPayload = z.infer<typeof PreviewTokenPayload>;
45
+ declare const PreviewTokenData: z.ZodObject<{
46
+ hash: z.ZodString;
47
+ payload: z.ZodObject<{
48
+ id: z.ZodNumber;
49
+ parent: z.ZodNumber;
50
+ expires: z.ZodNumber;
51
+ }, z.core.$strip>;
52
+ }, z.core.$strip>;
53
+ type PreviewTokenData = z.infer<typeof PreviewTokenData>;
54
+ //#endregion
55
+ export { CurrencyFormat, IdentifierInput, LIST_ORDER, ListMetadata, ListOrder, Media, PreviewTokenData, PreviewTokenPayload };
@@ -0,0 +1,43 @@
1
+ import { NumberLike } from "@kizlo/shared";
2
+ import z from "zod/v4";
3
+
4
+ //#region src/shared/schema.ts
5
+ const LIST_ORDER = ["asc", "desc"];
6
+ const ListOrder = z.enum(LIST_ORDER);
7
+ const ListMetadata = z.object({
8
+ page: z.number(),
9
+ totalItems: z.number(),
10
+ totalPages: z.number(),
11
+ nextPage: z.number().nullable(),
12
+ prevPage: z.number().nullable(),
13
+ hasNextPage: z.boolean(),
14
+ hasPrevPage: z.boolean()
15
+ });
16
+ const CurrencyFormat = z.object({
17
+ currencyCode: z.string(),
18
+ currencySymbol: z.string(),
19
+ currencyPrefix: z.string(),
20
+ currencySuffix: z.string(),
21
+ currencyMinorUnit: z.number(),
22
+ currencyDecimalSeparator: z.string(),
23
+ currencyThousandSeparator: z.string()
24
+ });
25
+ const Media = z.object({
26
+ id: z.number(),
27
+ name: z.string(),
28
+ alt: z.string(),
29
+ src: z.string()
30
+ });
31
+ const IdentifierInput = z.union([NumberLike, z.string()]);
32
+ const PreviewTokenPayload = z.object({
33
+ id: z.number(),
34
+ parent: z.number(),
35
+ expires: z.number()
36
+ });
37
+ const PreviewTokenData = z.object({
38
+ hash: z.string(),
39
+ payload: PreviewTokenPayload
40
+ });
41
+
42
+ //#endregion
43
+ export { CurrencyFormat, IdentifierInput, LIST_ORDER, ListMetadata, ListOrder, Media, PreviewTokenData, PreviewTokenPayload };
@@ -0,0 +1,12 @@
1
+ import { WP_CurrencyFormat, WP_ListMetadata } from "../wordpress/types.js";
2
+ import "../wordpress/index.js";
3
+ import { CurrencyFormat, ListMetadata } from "./schema.js";
4
+ import { List } from "./types.js";
5
+
6
+ //#region src/shared/serialize.d.ts
7
+ declare function emptyList<T>(): List<T>;
8
+ declare function deserializeListMetadata(data: WP_ListMetadata): ListMetadata;
9
+ declare function serializeCurrencyFormat(data: CurrencyFormat): WP_CurrencyFormat;
10
+ declare function deserializeCurrencyFormat(data: WP_CurrencyFormat): CurrencyFormat;
11
+ //#endregion
12
+ export { deserializeCurrencyFormat, deserializeListMetadata, emptyList, serializeCurrencyFormat };
@@ -0,0 +1,51 @@
1
+ //#region src/shared/serialize.ts
2
+ function emptyList() {
3
+ return {
4
+ items: [],
5
+ meta: {
6
+ hasNextPage: false,
7
+ hasPrevPage: false,
8
+ nextPage: 0,
9
+ page: 0,
10
+ prevPage: 0,
11
+ totalItems: 0,
12
+ totalPages: 0
13
+ }
14
+ };
15
+ }
16
+ function deserializeListMetadata(data) {
17
+ return {
18
+ hasNextPage: data.has_next_page,
19
+ hasPrevPage: data.has_prev_page,
20
+ nextPage: data.next_page,
21
+ page: data.page,
22
+ prevPage: data.prev_page,
23
+ totalItems: data.total_items,
24
+ totalPages: data.total_pages
25
+ };
26
+ }
27
+ function serializeCurrencyFormat(data) {
28
+ return {
29
+ currency_code: data.currencyCode,
30
+ currency_symbol: data.currencySymbol,
31
+ currency_prefix: data.currencyPrefix,
32
+ currency_suffix: data.currencySuffix,
33
+ currency_minor_unit: data.currencyMinorUnit,
34
+ currency_decimal_separator: data.currencyDecimalSeparator,
35
+ currency_thousand_separator: data.currencyThousandSeparator
36
+ };
37
+ }
38
+ function deserializeCurrencyFormat(data) {
39
+ return {
40
+ currencyCode: data.currency_code,
41
+ currencySymbol: data.currency_symbol,
42
+ currencyPrefix: data.currency_prefix,
43
+ currencySuffix: data.currency_suffix,
44
+ currencyMinorUnit: data.currency_minor_unit,
45
+ currencyDecimalSeparator: data.currency_decimal_separator,
46
+ currencyThousandSeparator: data.currency_thousand_separator
47
+ };
48
+ }
49
+
50
+ //#endregion
51
+ export { deserializeCurrencyFormat, deserializeListMetadata, emptyList, serializeCurrencyFormat };
@@ -0,0 +1,35 @@
1
+ import { ListMetadata } from "./schema.js";
2
+ import { NestedClient } from "@orpc/client";
3
+ import { CookieOptions, CookieWithOptions } from "@kizlo/shared";
4
+
5
+ //#region src/shared/types.d.ts
6
+ type AnyContext = Record<PropertyKey, any>;
7
+ type AnyNestedClient = NestedClient<any>;
8
+ type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD";
9
+ type List<T> = {
10
+ items: T[];
11
+ meta: ListMetadata;
12
+ };
13
+ type MaybeOptionalOptions<TOptions> = Record<never, never> extends TOptions ? [options?: TOptions] : [options: TOptions];
14
+ type RedirectStatus = 301 | 302 | 303 | 307 | 308;
15
+ interface RedirectInput {
16
+ to: string | URL;
17
+ status?: RedirectStatus;
18
+ searchParams?: Record<string, string>;
19
+ }
20
+ interface CookiesAdapter {
21
+ setAll(cookies: CookieWithOptions[]): Promise<void> | void;
22
+ getAll(): Promise<{
23
+ name: string;
24
+ value: string;
25
+ }[] | null> | {
26
+ name: string;
27
+ value: string;
28
+ }[] | null;
29
+ deleteAll(cookies: {
30
+ name: string;
31
+ options?: CookieOptions;
32
+ }[]): Promise<void> | void;
33
+ }
34
+ //#endregion
35
+ export { AnyContext, AnyNestedClient, CookiesAdapter, HTTPMethod, List, MaybeOptionalOptions, RedirectInput, RedirectStatus };
@@ -0,0 +1,17 @@
1
+ import "zod/v4";
2
+
3
+ //#region src/shared/utils.ts
4
+ function getObjectProperty(object, path) {
5
+ let current = object;
6
+ for (const key of path) {
7
+ if (!isTypescriptObject(current)) return;
8
+ current = current[key];
9
+ }
10
+ return current;
11
+ }
12
+ function isTypescriptObject(value) {
13
+ return !!value && (typeof value === "object" || typeof value === "function");
14
+ }
15
+
16
+ //#endregion
17
+ export { getObjectProperty, isTypescriptObject };
@@ -0,0 +1,7 @@
1
+ import { AuthAdapter } from "../adapters/auth.js";
2
+ import { TestAuthAdapterUser } from "./users.js";
3
+
4
+ //#region src/test/auth.d.ts
5
+ declare function testAuthAdapter(user: TestAuthAdapterUser): AuthAdapter;
6
+ //#endregion
7
+ export { testAuthAdapter };
@@ -0,0 +1,15 @@
1
+ //#region src/test/auth.ts
2
+ function testAuthAdapter(user) {
3
+ return { getUser() {
4
+ return {
5
+ id: user.wpUserId,
6
+ email: user.email,
7
+ phone: user.phone,
8
+ firstName: user.firstName,
9
+ lastName: user.lastName
10
+ };
11
+ } };
12
+ }
13
+
14
+ //#endregion
15
+ export { testAuthAdapter };
@@ -0,0 +1,7 @@
1
+ import { CaptchaAdapter } from "../adapters/captcha.js";
2
+
3
+ //#region src/test/captcha.d.ts
4
+ declare const CAPTCHA_TEST_TOKEN_PASS = "test-token-pass";
5
+ declare function captchaMock(): CaptchaAdapter;
6
+ //#endregion
7
+ export { CAPTCHA_TEST_TOKEN_PASS, captchaMock };
@@ -0,0 +1,8 @@
1
+ //#region src/test/captcha.ts
2
+ const CAPTCHA_TEST_TOKEN_PASS = "test-token-pass";
3
+ function captchaMock() {
4
+ return async ({ token }) => token === CAPTCHA_TEST_TOKEN_PASS;
5
+ }
6
+
7
+ //#endregion
8
+ export { CAPTCHA_TEST_TOKEN_PASS, captchaMock };
@@ -0,0 +1,11 @@
1
+ import { AnyExtension } from "../shared/extension.js";
2
+ import { RootRouter } from "../kizlo.js";
3
+ import { KizloClient } from "../client.js";
4
+ import "../index.js";
5
+ import { KizloTestInstance } from "./server.js";
6
+
7
+ //#region src/test/client.d.ts
8
+ declare function getKizloClientTestInstance(kizlo: KizloTestInstance): Promise<KizloClient<RootRouter<readonly AnyExtension[]>>>;
9
+ type KizloClientTestInstance = Awaited<ReturnType<typeof getKizloClientTestInstance>>;
10
+ //#endregion
11
+ export { KizloClientTestInstance, getKizloClientTestInstance };
@@ -0,0 +1,14 @@
1
+ import { generateContract } from "../shared/contract.js";
2
+ import { KizloClient } from "../client.js";
3
+
4
+ //#region src/test/client.ts
5
+ async function getKizloClientTestInstance(kizlo) {
6
+ return new KizloClient({
7
+ url: "http://test.local",
8
+ fetch: (req) => kizlo.handler(req),
9
+ contract: await generateContract(kizlo.router)
10
+ });
11
+ }
12
+
13
+ //#endregion
14
+ export { getKizloClientTestInstance };
@@ -0,0 +1,14 @@
1
+ import { Fixture } from "../cli/wp/types.js";
2
+ import { menuFixture } from "../menu/fixture.js";
3
+ import { postFixture } from "../post/fixture.js";
4
+
5
+ //#region src/test/fixtures.d.ts
6
+
7
+ /**
8
+ * The kizlo core content fixtures (posts/comments + menu). Mount these in
9
+ * `kizlo.config.ts` so the toolkit's own suites have content to read; consumers
10
+ * who only need a clean WP stack can leave them out.
11
+ */
12
+ declare const coreFixtures: Fixture[];
13
+ //#endregion
14
+ export { coreFixtures };
@@ -0,0 +1,13 @@
1
+ import { menuFixture } from "../menu/fixture.js";
2
+ import { postFixture } from "../post/fixture.js";
3
+
4
+ //#region src/test/fixtures.ts
5
+ /**
6
+ * The kizlo core content fixtures (posts/comments + menu). Mount these in
7
+ * `kizlo.config.ts` so the toolkit's own suites have content to read; consumers
8
+ * who only need a clean WP stack can leave them out.
9
+ */
10
+ const coreFixtures = [postFixture(), menuFixture()];
11
+
12
+ //#endregion
13
+ export { coreFixtures };
@@ -0,0 +1,10 @@
1
+ import { AnyExtension } from "../shared/extension.js";
2
+ import { Kizlo } from "../kizlo.js";
3
+
4
+ //#region src/test/server.d.ts
5
+ declare function getKizloTestInstance<TExts extends readonly AnyExtension[] = []>(options?: {
6
+ extensions?: TExts;
7
+ }): Kizlo<TExts>;
8
+ type KizloTestInstance = ReturnType<typeof getKizloTestInstance>;
9
+ //#endregion
10
+ export { KizloTestInstance, getKizloTestInstance };
@@ -0,0 +1,32 @@
1
+ import { geoMock } from "../adapters/geo.js";
2
+ import { consoleLog } from "../adapters/logger.js";
3
+ import { Kizlo } from "../kizlo.js";
4
+ import { getTestCredentials } from "../cli/wp/utils.js";
5
+ import { testAuthAdapter } from "./auth.js";
6
+ import { captchaMock } from "./captcha.js";
7
+ import { toTestUser } from "./users.js";
8
+
9
+ //#region src/test/server.ts
10
+ function getKizloTestInstance(options) {
11
+ const creds = getTestCredentials();
12
+ return new Kizlo({
13
+ baseUrl: "http://test.local",
14
+ siteSecret: "test-secret",
15
+ environment: "test",
16
+ credentials: {
17
+ url: creds.url,
18
+ username: creds.users.admin.username,
19
+ password: creds.users.admin.applicationPassword
20
+ },
21
+ adapters: {
22
+ geo: geoMock(),
23
+ auth: testAuthAdapter(toTestUser(creds.users.user)),
24
+ captcha: captchaMock(),
25
+ logger: consoleLog({ levels: ["warn", "error"] })
26
+ },
27
+ extensions: options?.extensions
28
+ });
29
+ }
30
+
31
+ //#endregion
32
+ export { getKizloTestInstance };
@@ -0,0 +1,14 @@
1
+ import { TestCredentials } from "../cli/wp/types.js";
2
+
3
+ //#region src/test/users.d.ts
4
+ interface TestAuthAdapterUser {
5
+ wpUserId: number;
6
+ username: string;
7
+ firstName: string;
8
+ lastName: string;
9
+ email: string;
10
+ phone: string;
11
+ }
12
+ declare function toTestUser(user: TestCredentials["users"]["user"]): TestAuthAdapterUser;
13
+ //#endregion
14
+ export { TestAuthAdapterUser, toTestUser };
@@ -0,0 +1,17 @@
1
+ //#region src/test/users.ts
2
+ const STATIC_FIELDS = {
3
+ firstName: "Test",
4
+ lastName: "Customer",
5
+ email: "customer@example.com",
6
+ phone: "+10000000002"
7
+ };
8
+ function toTestUser(user) {
9
+ return {
10
+ wpUserId: user.id,
11
+ username: user.username,
12
+ ...STATIC_FIELDS
13
+ };
14
+ }
15
+
16
+ //#endregion
17
+ export { toTestUser };
package/dist/test.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { compose, composeDown, composeStop, composeUp, wpCli } from "./cli/wp/docker.js";
2
+ import { Fixture, JsonValue, PluginSource, SeedContext, TestAdminUser, TestCredentials, TestUser, defineFixture } from "./cli/wp/types.js";
3
+ import { credentialsPath, ensurePlugin, findConfigDir, getTestCredentials, githubRelease, isSeeded, resolvePluginSource } from "./cli/wp/utils.js";
4
+ import { TestAuthAdapterUser, toTestUser } from "./test/users.js";
5
+ import { testAuthAdapter } from "./test/auth.js";
6
+ import { CAPTCHA_TEST_TOKEN_PASS, captchaMock } from "./test/captcha.js";
7
+ import { KizloTestInstance, getKizloTestInstance } from "./test/server.js";
8
+ import { KizloClientTestInstance, getKizloClientTestInstance } from "./test/client.js";
9
+ import { menuFixture } from "./menu/fixture.js";
10
+ import { postFixture } from "./post/fixture.js";
11
+ import { coreFixtures } from "./test/fixtures.js";
12
+ export { CAPTCHA_TEST_TOKEN_PASS, Fixture, JsonValue, KizloClientTestInstance, KizloTestInstance, PluginSource, SeedContext, TestAdminUser, TestAuthAdapterUser, TestCredentials, TestUser, captchaMock, compose, composeDown, composeStop, composeUp, coreFixtures, credentialsPath, defineFixture, ensurePlugin, findConfigDir, getKizloClientTestInstance, getKizloTestInstance, getTestCredentials, githubRelease, isSeeded, menuFixture, postFixture, resolvePluginSource, testAuthAdapter, toTestUser, wpCli };
package/dist/test.js ADDED
@@ -0,0 +1,13 @@
1
+ import { credentialsPath, ensurePlugin, findConfigDir, getTestCredentials, githubRelease, isSeeded, resolvePluginSource } from "./cli/wp/utils.js";
2
+ import { compose, composeDown, composeStop, composeUp, wpCli } from "./cli/wp/docker.js";
3
+ import { defineFixture } from "./cli/wp/types.js";
4
+ import { testAuthAdapter } from "./test/auth.js";
5
+ import { CAPTCHA_TEST_TOKEN_PASS, captchaMock } from "./test/captcha.js";
6
+ import { getKizloClientTestInstance } from "./test/client.js";
7
+ import { menuFixture } from "./menu/fixture.js";
8
+ import { postFixture } from "./post/fixture.js";
9
+ import { coreFixtures } from "./test/fixtures.js";
10
+ import { toTestUser } from "./test/users.js";
11
+ import { getKizloTestInstance } from "./test/server.js";
12
+
13
+ export { CAPTCHA_TEST_TOKEN_PASS, captchaMock, compose, composeDown, composeStop, composeUp, coreFixtures, credentialsPath, defineFixture, ensurePlugin, findConfigDir, getKizloClientTestInstance, getKizloTestInstance, getTestCredentials, githubRelease, isSeeded, menuFixture, postFixture, resolvePluginSource, testAuthAdapter, toTestUser, wpCli };
@@ -0,0 +1,38 @@
1
+ import { WebhookEvent } from "./schema.js";
2
+ import { DefinedErrorMapLike } from "../shared/error.js";
3
+ import { ServerContext } from "../context.js";
4
+ import { Procedure } from "../shared/procedure.js";
5
+ import "../index.js";
6
+ import { Pathname, Schema, SchemaOutput } from "@kizlo/shared";
7
+
8
+ //#region src/webhook/index.d.ts
9
+ type AnyWebhookEventSchema<TData = unknown> = Schema<unknown, TData>;
10
+ type AnyWebhookEvents = {
11
+ types: string[];
12
+ data: AnyWebhookEventSchema;
13
+ }[];
14
+ type InferWebhookEventUnion<T extends AnyWebhookEvents> = { [K in keyof T]: {
15
+ type: T[K]["types"][number];
16
+ data: SchemaOutput<T[K]["data"]>;
17
+ } }[number];
18
+ type WebhookHandlerFn<T extends AnyWebhookEvents> = (event: InferWebhookEventUnion<T> | WebhookEvent | null, context: ServerContext) => Promise<void> | void;
19
+ interface WebhookOptions {
20
+ path?: Pathname;
21
+ events?: EventHandler[];
22
+ }
23
+ interface EventHandler {
24
+ events?: AnyWebhookEvents;
25
+ handler: WebhookHandlerFn<AnyWebhookEvents>;
26
+ }
27
+ declare function createEventHandler<const T extends AnyWebhookEvents = never>(handler: WebhookHandlerFn<T>): EventHandler;
28
+ declare function createEventHandler<const T extends AnyWebhookEvents = never>(events: T, handler: WebhookHandlerFn<T>): EventHandler;
29
+ declare function createWebhookRouter(options?: WebhookOptions): {
30
+ webhooks: Procedure<"api", {
31
+ body: {
32
+ type: string;
33
+ data: unknown;
34
+ };
35
+ }, unknown, DefinedErrorMapLike>;
36
+ };
37
+ //#endregion
38
+ export { AnyWebhookEventSchema, AnyWebhookEvents, EventHandler, InferWebhookEventUnion, WebhookHandlerFn, WebhookOptions, createEventHandler, createWebhookRouter };
@@ -0,0 +1,44 @@
1
+ import { KizloError } from "../shared/error.js";
2
+ import { createProcedure } from "../shared/procedure.js";
3
+ import { AnyWebhookEvent } from "./schema.js";
4
+ import { validateWebhookEvent } from "./utils.js";
5
+ import { tryCatchSync, verifyWebhook } from "@kizlo/shared";
6
+ import z from "zod";
7
+
8
+ //#region src/webhook/index.ts
9
+ function createEventHandler(eventsOrHandler, maybeHandler) {
10
+ const events = Array.isArray(eventsOrHandler) ? eventsOrHandler : [];
11
+ const handler = Array.isArray(eventsOrHandler) ? maybeHandler : eventsOrHandler;
12
+ if (!handler) throw new Error("Event handler not defined.");
13
+ return {
14
+ events,
15
+ handler
16
+ };
17
+ }
18
+ function createWebhookRouter(options) {
19
+ return { webhooks: createProcedure({
20
+ scope: "api",
21
+ method: "POST",
22
+ body: AnyWebhookEvent,
23
+ path: options?.path ?? "/webhooks",
24
+ output: z.void()
25
+ }, async ({ context, input }) => {
26
+ const payload = await context.request?.text() ?? "";
27
+ const headers = Object.fromEntries(context.request?.headers.entries() ?? []);
28
+ const [err] = tryCatchSync(() => verifyWebhook({
29
+ secret: context.config.siteSecret,
30
+ payload,
31
+ headers
32
+ }));
33
+ if (err) throw new KizloError("FORBIDDEN", { message: "Signature verification failed." });
34
+ const results = await Promise.allSettled((options?.events ?? []).map(async ({ events, handler }) => {
35
+ const event = await validateWebhookEvent(events, input.body);
36
+ if (!event) return;
37
+ await handler(event, context);
38
+ }));
39
+ for (const result of results) if (result.status === "rejected") context.logger.error("Webhook handler failed", result.reason);
40
+ }) };
41
+ }
42
+
43
+ //#endregion
44
+ export { createEventHandler, createWebhookRouter };
@@ -0,0 +1,45 @@
1
+ import z from "zod/v4";
2
+
3
+ //#region src/webhook/schema.d.ts
4
+
5
+ declare const WebhookEvent: z.ZodUnion<readonly [z.ZodObject<{
6
+ type: z.ZodEnum<{
7
+ "post.created": "post.created";
8
+ "post.updated": "post.updated";
9
+ "post.trashed": "post.trashed";
10
+ "post.deleted": "post.deleted";
11
+ }>;
12
+ data: z.ZodObject<{
13
+ post_id: z.ZodNumber;
14
+ post_type: z.ZodString;
15
+ }, z.core.$strip>;
16
+ }, z.core.$strip>, z.ZodObject<{
17
+ type: z.ZodEnum<{
18
+ "term.created": "term.created";
19
+ "term.updated": "term.updated";
20
+ "term.deleted": "term.deleted";
21
+ }>;
22
+ data: z.ZodObject<{
23
+ term_id: z.ZodNumber;
24
+ taxonomy: z.ZodString;
25
+ post_types: z.ZodArray<z.ZodString>;
26
+ count: z.ZodNumber;
27
+ }, z.core.$strip>;
28
+ }, z.core.$strip>, z.ZodObject<{
29
+ type: z.ZodEnum<{
30
+ "payment.status_requested": "payment.status_requested";
31
+ }>;
32
+ data: z.ZodObject<{
33
+ transaction_id: z.ZodNullable<z.ZodString>;
34
+ payment_method_id: z.ZodString;
35
+ payment_session_id: z.ZodString;
36
+ }, z.core.$strip>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ type: z.ZodEnum<{
39
+ "settings.saved": "settings.saved";
40
+ }>;
41
+ data: z.ZodNull;
42
+ }, z.core.$strip>]>;
43
+ type WebhookEvent = z.infer<typeof WebhookEvent>;
44
+ //#endregion
45
+ export { WebhookEvent };
@@ -0,0 +1,72 @@
1
+ import z from "zod/v4";
2
+
3
+ //#region src/webhook/schema.ts
4
+ const TERM_WEBHOOK_EVENT_TYPES = [
5
+ "term.created",
6
+ "term.updated",
7
+ "term.deleted"
8
+ ];
9
+ const TermWebhookEventType = z.enum(TERM_WEBHOOK_EVENT_TYPES);
10
+ const POST_WEBHOOK_EVENT_TYPES = [
11
+ "post.created",
12
+ "post.updated",
13
+ "post.trashed",
14
+ "post.deleted"
15
+ ];
16
+ const PostWebhookEventType = z.enum(POST_WEBHOOK_EVENT_TYPES);
17
+ const PAYMENT_WEBHOOK_EVENT_TYPES = ["payment.status_requested"];
18
+ const PaymentWebhookEventType = z.enum(PAYMENT_WEBHOOK_EVENT_TYPES);
19
+ const SETTINGS_WEBHOOK_EVENT_TYPES = ["settings.saved"];
20
+ const SettingsWebhookEventType = z.enum(SETTINGS_WEBHOOK_EVENT_TYPES);
21
+ const WEBHOOK_EVENT_TYPES = [
22
+ ...TERM_WEBHOOK_EVENT_TYPES,
23
+ ...POST_WEBHOOK_EVENT_TYPES,
24
+ ...PAYMENT_WEBHOOK_EVENT_TYPES,
25
+ ...SETTINGS_WEBHOOK_EVENT_TYPES
26
+ ];
27
+ const WebhookEventType = z.enum(WEBHOOK_EVENT_TYPES);
28
+ const PostWebhookEventData = z.object({
29
+ post_id: z.number(),
30
+ post_type: z.string()
31
+ });
32
+ const PostWebhookEvent = z.object({
33
+ type: PostWebhookEventType,
34
+ data: PostWebhookEventData
35
+ });
36
+ const TermWebhookEventData = z.object({
37
+ term_id: z.number(),
38
+ taxonomy: z.string(),
39
+ post_types: z.array(z.string()),
40
+ count: z.number().nonnegative()
41
+ });
42
+ const TermWebhookEvent = z.object({
43
+ type: TermWebhookEventType,
44
+ data: TermWebhookEventData
45
+ });
46
+ const PaymentWebhookEventData = z.object({
47
+ transaction_id: z.nullable(z.string()),
48
+ payment_method_id: z.string(),
49
+ payment_session_id: z.string()
50
+ });
51
+ const PaymentWebhookEvent = z.object({
52
+ type: PaymentWebhookEventType,
53
+ data: PaymentWebhookEventData
54
+ });
55
+ const SettingsWebhookEventData = z.null();
56
+ const SettingsWebhookEvent = z.object({
57
+ type: SettingsWebhookEventType,
58
+ data: SettingsWebhookEventData
59
+ });
60
+ const WebhookEvent = z.union([
61
+ PostWebhookEvent,
62
+ TermWebhookEvent,
63
+ PaymentWebhookEvent,
64
+ SettingsWebhookEvent
65
+ ]);
66
+ const AnyWebhookEvent = z.object({
67
+ type: z.string(),
68
+ data: z.unknown()
69
+ });
70
+
71
+ //#endregion
72
+ export { AnyWebhookEvent, WebhookEvent };