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,54 @@
1
+ import { createProcedure } from "../shared/procedure.js";
2
+ import { WP_KIZLO_BASE } from "../wordpress/constants.js";
3
+ import { ListSitemapUrlInput, Robots, SitemapList, SitemapUrlList } from "./schema.js";
4
+
5
+ //#region src/seo/index.ts
6
+ const SEO_ROUTER_MAP = {
7
+ sitemaps: createProcedure({
8
+ scope: "internal",
9
+ output: SitemapList
10
+ }, async ({ context, errors }) => {
11
+ const response = await context.service.wordpress.get("/seo/sitemaps", { base: WP_KIZLO_BASE });
12
+ if (response.error) {
13
+ context.logger.error("List sitemaps unhandled error", response.error);
14
+ throw errors.INTERNAL_SERVER_ERROR();
15
+ }
16
+ return response.data;
17
+ }),
18
+ robots: createProcedure({
19
+ scope: "internal",
20
+ output: Robots
21
+ }, async ({ context, errors }) => {
22
+ const response = await context.service.wordpress.get(`/seo/robots`, { base: WP_KIZLO_BASE });
23
+ if (response.error) {
24
+ context.logger.error("List robots unhandled error", response.error);
25
+ throw errors.INTERNAL_SERVER_ERROR();
26
+ }
27
+ return {
28
+ sitemaps: response.data.sitemaps ?? [],
29
+ rules: response.data.rules.map((item) => ({
30
+ allow: item.allow,
31
+ disallow: item.disallow,
32
+ userAgent: item.user_agent
33
+ }))
34
+ };
35
+ }),
36
+ urls: createProcedure({
37
+ scope: "internal",
38
+ output: SitemapUrlList,
39
+ input: ListSitemapUrlInput
40
+ }, async ({ context, input, errors }) => {
41
+ const response = await context.service.wordpress.get(`/seo/sitemaps/${input.type}/${input.type !== "author" ? input.key : ""}`, {
42
+ base: WP_KIZLO_BASE,
43
+ searchParams: { page: input.page ?? 1 }
44
+ });
45
+ if (response.error) {
46
+ context.logger.error("List sitemap urls unhandled error", response.error);
47
+ throw errors.INTERNAL_SERVER_ERROR();
48
+ }
49
+ return response.data;
50
+ })
51
+ };
52
+
53
+ //#endregion
54
+ export { SEO_ROUTER_MAP };
@@ -0,0 +1,196 @@
1
+ import z from "zod/v4";
2
+
3
+ //#region src/seo/schema.d.ts
4
+ declare const SeoHead: z.ZodObject<{
5
+ title: z.ZodString;
6
+ canonical: z.ZodString;
7
+ robots: z.ZodObject<{
8
+ index: z.ZodString;
9
+ follow: z.ZodString;
10
+ maxSnippet: z.ZodString;
11
+ maxImagePreview: z.ZodString;
12
+ maxVideoPreview: z.ZodString;
13
+ }, z.core.$strip>;
14
+ og: z.ZodObject<{
15
+ locale: z.ZodString;
16
+ type: z.ZodString;
17
+ title: z.ZodString;
18
+ url: z.ZodString;
19
+ siteName: z.ZodString;
20
+ description: z.ZodString;
21
+ image: z.ZodNullable<z.ZodObject<{
22
+ url: z.ZodString;
23
+ width: z.ZodString;
24
+ height: z.ZodString;
25
+ type: z.ZodString;
26
+ alt: z.ZodNullable<z.ZodString>;
27
+ }, z.core.$strip>>;
28
+ }, z.core.$strip>;
29
+ twitter: z.ZodObject<{
30
+ card: z.ZodEnum<{
31
+ summary: "summary";
32
+ summary_large_image: "summary_large_image";
33
+ }>;
34
+ title: z.ZodString;
35
+ site: z.ZodNullable<z.ZodString>;
36
+ creator: z.ZodNullable<z.ZodString>;
37
+ description: z.ZodString;
38
+ image: z.ZodNullable<z.ZodString>;
39
+ }, z.core.$strip>;
40
+ article: z.ZodNullable<z.ZodObject<{
41
+ publishedTime: z.ZodString;
42
+ modifiedTime: z.ZodString;
43
+ author: z.ZodString;
44
+ authorUrl: z.ZodString;
45
+ section: z.ZodString;
46
+ }, z.core.$strip>>;
47
+ }, z.core.$strip>;
48
+ type SeoHead = z.infer<typeof SeoHead>;
49
+ declare const SeoSchema: z.ZodObject<{
50
+ "@context": z.ZodLiteral<"https://schema.org">;
51
+ "@graph": z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
52
+ }, z.core.$strip>;
53
+ type SeoSchema = z.infer<typeof SeoSchema>;
54
+ declare const Seo: z.ZodObject<{
55
+ head: z.ZodObject<{
56
+ title: z.ZodString;
57
+ canonical: z.ZodString;
58
+ robots: z.ZodObject<{
59
+ index: z.ZodString;
60
+ follow: z.ZodString;
61
+ maxSnippet: z.ZodString;
62
+ maxImagePreview: z.ZodString;
63
+ maxVideoPreview: z.ZodString;
64
+ }, z.core.$strip>;
65
+ og: z.ZodObject<{
66
+ locale: z.ZodString;
67
+ type: z.ZodString;
68
+ title: z.ZodString;
69
+ url: z.ZodString;
70
+ siteName: z.ZodString;
71
+ description: z.ZodString;
72
+ image: z.ZodNullable<z.ZodObject<{
73
+ url: z.ZodString;
74
+ width: z.ZodString;
75
+ height: z.ZodString;
76
+ type: z.ZodString;
77
+ alt: z.ZodNullable<z.ZodString>;
78
+ }, z.core.$strip>>;
79
+ }, z.core.$strip>;
80
+ twitter: z.ZodObject<{
81
+ card: z.ZodEnum<{
82
+ summary: "summary";
83
+ summary_large_image: "summary_large_image";
84
+ }>;
85
+ title: z.ZodString;
86
+ site: z.ZodNullable<z.ZodString>;
87
+ creator: z.ZodNullable<z.ZodString>;
88
+ description: z.ZodString;
89
+ image: z.ZodNullable<z.ZodString>;
90
+ }, z.core.$strip>;
91
+ article: z.ZodNullable<z.ZodObject<{
92
+ publishedTime: z.ZodString;
93
+ modifiedTime: z.ZodString;
94
+ author: z.ZodString;
95
+ authorUrl: z.ZodString;
96
+ section: z.ZodString;
97
+ }, z.core.$strip>>;
98
+ }, z.core.$strip>;
99
+ schema: z.ZodObject<{
100
+ "@context": z.ZodLiteral<"https://schema.org">;
101
+ "@graph": z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
102
+ }, z.core.$strip>;
103
+ }, z.core.$strip>;
104
+ type Seo = z.infer<typeof Seo>;
105
+ declare const CONTENT_TYPES: readonly ["post_type", "taxonomy", "author"];
106
+ declare const ContentType: z.ZodEnum<{
107
+ author: "author";
108
+ post_type: "post_type";
109
+ taxonomy: "taxonomy";
110
+ }>;
111
+ type ContentType = z.infer<typeof ContentType>;
112
+ declare const Sitemap: z.ZodObject<{
113
+ key: z.ZodString;
114
+ type: z.ZodEnum<{
115
+ author: "author";
116
+ post_type: "post_type";
117
+ taxonomy: "taxonomy";
118
+ }>;
119
+ pages: z.ZodNumber;
120
+ lastmod: z.ZodString;
121
+ }, z.core.$strip>;
122
+ type Sitemap = z.infer<typeof Sitemap>;
123
+ declare const SitemapList: z.ZodArray<z.ZodObject<{
124
+ key: z.ZodString;
125
+ type: z.ZodEnum<{
126
+ author: "author";
127
+ post_type: "post_type";
128
+ taxonomy: "taxonomy";
129
+ }>;
130
+ pages: z.ZodNumber;
131
+ lastmod: z.ZodString;
132
+ }, z.core.$strip>>;
133
+ type SitemapList = z.infer<typeof SitemapList>;
134
+ declare const SitemapUrlImage: z.ZodObject<{
135
+ loc: z.ZodString;
136
+ title: z.ZodString;
137
+ }, z.core.$strip>;
138
+ type SitemapUrlImage = z.infer<typeof SitemapUrlImage>;
139
+ declare const SitemapUrl: z.ZodObject<{
140
+ loc: z.ZodString;
141
+ lastmod: z.ZodString;
142
+ images: z.ZodArray<z.ZodObject<{
143
+ loc: z.ZodString;
144
+ title: z.ZodString;
145
+ }, z.core.$strip>>;
146
+ }, z.core.$strip>;
147
+ type SitemapUrl = z.infer<typeof SitemapUrl>;
148
+ declare const SitemapUrlList: z.ZodArray<z.ZodObject<{
149
+ loc: z.ZodString;
150
+ lastmod: z.ZodString;
151
+ images: z.ZodArray<z.ZodObject<{
152
+ loc: z.ZodString;
153
+ title: z.ZodString;
154
+ }, z.core.$strip>>;
155
+ }, z.core.$strip>>;
156
+ type SitemapUrlList = z.infer<typeof SitemapUrlList>;
157
+ declare const ListSitemapUrlInputBase: z.ZodObject<{
158
+ type: z.ZodEnum<{
159
+ author: "author";
160
+ post_type: "post_type";
161
+ taxonomy: "taxonomy";
162
+ }>;
163
+ page: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodCoercedNumber<string | number>>>;
164
+ }, z.core.$strip>;
165
+ type ListSitemapUrlInputBase = z.input<typeof ListSitemapUrlInputBase>;
166
+ declare const ListSitemapUrlInput: z.ZodUnion<readonly [z.ZodObject<{
167
+ page: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodCoercedNumber<string | number>>>;
168
+ type: z.ZodEnum<{
169
+ post_type: "post_type";
170
+ taxonomy: "taxonomy";
171
+ }>;
172
+ key: z.ZodString;
173
+ }, z.core.$strip>, z.ZodObject<{
174
+ page: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodCoercedNumber<string | number>>>;
175
+ type: z.ZodEnum<{
176
+ author: "author";
177
+ }>;
178
+ }, z.core.$strip>]>;
179
+ type ListSitemapUrlInput = z.infer<typeof ListSitemapUrlInput>;
180
+ declare const RobotsRule: z.ZodObject<{
181
+ userAgent: z.ZodString;
182
+ allow: z.ZodArray<z.ZodString>;
183
+ disallow: z.ZodArray<z.ZodString>;
184
+ }, z.core.$strip>;
185
+ type RobotsRule = z.infer<typeof RobotsRule>;
186
+ declare const Robots: z.ZodObject<{
187
+ sitemaps: z.ZodArray<z.ZodString>;
188
+ rules: z.ZodArray<z.ZodObject<{
189
+ userAgent: z.ZodString;
190
+ allow: z.ZodArray<z.ZodString>;
191
+ disallow: z.ZodArray<z.ZodString>;
192
+ }, z.core.$strip>>;
193
+ }, z.core.$strip>;
194
+ type Robots = z.infer<typeof Robots>;
195
+ //#endregion
196
+ export { CONTENT_TYPES, ContentType, ListSitemapUrlInput, ListSitemapUrlInputBase, Robots, RobotsRule, Seo, SeoHead, SeoSchema, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList };
@@ -0,0 +1,96 @@
1
+ import { NumberLike } from "@kizlo/shared";
2
+ import z from "zod/v4";
3
+
4
+ //#region src/seo/schema.ts
5
+ const SeoHead = z.object({
6
+ title: z.string(),
7
+ canonical: z.string(),
8
+ robots: z.object({
9
+ index: z.string(),
10
+ follow: z.string(),
11
+ maxSnippet: z.string(),
12
+ maxImagePreview: z.string(),
13
+ maxVideoPreview: z.string()
14
+ }),
15
+ og: z.object({
16
+ locale: z.string(),
17
+ type: z.string(),
18
+ title: z.string(),
19
+ url: z.string(),
20
+ siteName: z.string(),
21
+ description: z.string(),
22
+ image: z.object({
23
+ url: z.string(),
24
+ width: z.string(),
25
+ height: z.string(),
26
+ type: z.string(),
27
+ alt: z.string().nullable()
28
+ }).nullable()
29
+ }),
30
+ twitter: z.object({
31
+ card: z.enum(["summary", "summary_large_image"]),
32
+ title: z.string(),
33
+ site: z.string().nullable(),
34
+ creator: z.string().nullable(),
35
+ description: z.string(),
36
+ image: z.string().nullable()
37
+ }),
38
+ article: z.object({
39
+ publishedTime: z.string(),
40
+ modifiedTime: z.string(),
41
+ author: z.string(),
42
+ authorUrl: z.string(),
43
+ section: z.string()
44
+ }).nullable()
45
+ });
46
+ const SeoSchema = z.object({
47
+ "@context": z.literal("https://schema.org"),
48
+ "@graph": z.array(z.record(z.string(), z.unknown()))
49
+ });
50
+ const Seo = z.object({
51
+ head: SeoHead,
52
+ schema: SeoSchema
53
+ });
54
+ const CONTENT_TYPES = [
55
+ "post_type",
56
+ "taxonomy",
57
+ "author"
58
+ ];
59
+ const ContentType = z.enum(CONTENT_TYPES);
60
+ const Sitemap = z.object({
61
+ key: z.string(),
62
+ type: ContentType,
63
+ pages: z.number(),
64
+ lastmod: z.string()
65
+ });
66
+ const SitemapList = z.array(Sitemap);
67
+ const SitemapUrlImage = z.object({
68
+ loc: z.string(),
69
+ title: z.string()
70
+ });
71
+ const SitemapUrl = z.object({
72
+ loc: z.string(),
73
+ lastmod: z.string(),
74
+ images: z.array(SitemapUrlImage)
75
+ });
76
+ const SitemapUrlList = z.array(SitemapUrl);
77
+ const ListSitemapUrlInputBase = z.object({
78
+ type: ContentType,
79
+ page: NumberLike.optional()
80
+ });
81
+ const ListSitemapUrlInput = z.union([ListSitemapUrlInputBase.extend({
82
+ type: ContentType.exclude(["author"]),
83
+ key: z.string()
84
+ }), ListSitemapUrlInputBase.extend({ type: ContentType.extract(["author"]) })]);
85
+ const RobotsRule = z.object({
86
+ userAgent: z.string(),
87
+ allow: z.array(z.string()),
88
+ disallow: z.array(z.string())
89
+ });
90
+ const Robots = z.object({
91
+ sitemaps: z.array(z.string()),
92
+ rules: z.array(RobotsRule)
93
+ });
94
+
95
+ //#endregion
96
+ export { CONTENT_TYPES, ContentType, ListSitemapUrlInput, ListSitemapUrlInputBase, Robots, RobotsRule, Seo, SeoHead, SeoSchema, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList };
@@ -0,0 +1,80 @@
1
+ //#region src/seo/types.d.ts
2
+ interface WPK_Seo {
3
+ head: {
4
+ title: string;
5
+ canonical: string;
6
+ robots: {
7
+ index: string;
8
+ follow: string;
9
+ "max-snippet": string;
10
+ "max-image-preview": string;
11
+ "max-video-preview": string;
12
+ };
13
+ og: {
14
+ locale: string;
15
+ type: string;
16
+ title: string;
17
+ url: string;
18
+ site_name: string;
19
+ description: string;
20
+ image: {
21
+ url: string;
22
+ width: string;
23
+ height: string;
24
+ type: string;
25
+ alt: string | null;
26
+ } | null;
27
+ };
28
+ twitter: {
29
+ card: "summary_large_image";
30
+ title: string;
31
+ site: string | null;
32
+ creator: string | null;
33
+ description: string;
34
+ image: string | null;
35
+ };
36
+ article: {
37
+ published_time: string;
38
+ modified_time: string;
39
+ author: string;
40
+ author_url: string;
41
+ section: string;
42
+ } | null;
43
+ };
44
+ schema: {
45
+ "@context": "https://schema.org";
46
+ "@graph": Record<string, unknown>[];
47
+ };
48
+ }
49
+ type WPK_SitemapContentType = "post_type" | "taxonomy" | "author";
50
+ interface WPK_RobotRule {
51
+ user_agent: string;
52
+ allow: string[];
53
+ disallow: string[];
54
+ }
55
+ interface WPK_Robots {
56
+ rules: WPK_RobotRule[];
57
+ sitemaps?: string[];
58
+ }
59
+ interface WPK_Sitemap {
60
+ key: string;
61
+ type: WPK_SitemapContentType;
62
+ pages: number;
63
+ lastmod: string;
64
+ }
65
+ interface WPK_SitemapUrlImage {
66
+ loc: string;
67
+ title: string;
68
+ }
69
+ interface WPK_SitemapUrl {
70
+ loc: string;
71
+ lastmod: string;
72
+ images: WPK_SitemapUrlImage[];
73
+ }
74
+ interface WPK_ListSitemapUrlInput {
75
+ type: WPK_SitemapContentType;
76
+ key?: string;
77
+ page?: number;
78
+ }
79
+ //#endregion
80
+ export { WPK_ListSitemapUrlInput, WPK_RobotRule, WPK_Robots, WPK_Seo, WPK_Sitemap, WPK_SitemapContentType, WPK_SitemapUrl, WPK_SitemapUrlImage };
@@ -0,0 +1,44 @@
1
+ //#region src/seo/utils.ts
2
+ function deserializeSeo(data) {
3
+ return {
4
+ head: {
5
+ article: data.head.article ? {
6
+ author: data.head.article.author,
7
+ authorUrl: data.head.article.author_url,
8
+ modifiedTime: data.head.article.modified_time,
9
+ publishedTime: data.head.article.published_time,
10
+ section: data.head.article.section
11
+ } : null,
12
+ canonical: data.head.canonical,
13
+ og: {
14
+ description: data.head.og.description,
15
+ image: data.head.og.image ?? null,
16
+ locale: data.head.og.locale,
17
+ siteName: data.head.og.site_name,
18
+ title: data.head.og.title,
19
+ type: data.head.og.type,
20
+ url: data.head.og.url
21
+ },
22
+ robots: {
23
+ index: data.head.robots.index,
24
+ follow: data.head.robots.follow,
25
+ maxSnippet: data.head.robots["max-snippet"],
26
+ maxImagePreview: data.head.robots["max-image-preview"],
27
+ maxVideoPreview: data.head.robots["max-video-preview"]
28
+ },
29
+ title: data.head.title,
30
+ twitter: {
31
+ card: data.head.twitter.card,
32
+ creator: data.head.twitter.creator,
33
+ description: data.head.twitter.description,
34
+ image: data.head.twitter.image ?? null,
35
+ site: data.head.twitter.site,
36
+ title: data.head.twitter.title
37
+ }
38
+ },
39
+ schema: data.schema
40
+ };
41
+ }
42
+
43
+ //#endregion
44
+ export { deserializeSeo };
@@ -0,0 +1,17 @@
1
+ import { WordPressCredentials } from "./wordpress/types.js";
2
+ import { WordPressService } from "./wordpress/service.js";
3
+ import "./wordpress/index.js";
4
+ import { EmailService } from "./email/service.js";
5
+
6
+ //#region src/service.d.ts
7
+ interface ServiceConfig {
8
+ credentials: WordPressCredentials;
9
+ }
10
+ declare class Service {
11
+ readonly email: EmailService;
12
+ readonly wordpress: WordPressService;
13
+ private readonly config;
14
+ constructor(config: ServiceConfig);
15
+ }
16
+ //#endregion
17
+ export { Service, ServiceConfig };
@@ -0,0 +1,17 @@
1
+ import { WordPressService } from "./wordpress/service.js";
2
+ import { EmailService } from "./email/service.js";
3
+
4
+ //#region src/service.ts
5
+ var Service = class {
6
+ email;
7
+ wordpress;
8
+ config;
9
+ constructor(config) {
10
+ this.config = config;
11
+ this.email = new EmailService(this);
12
+ this.wordpress = new WordPressService(this.config);
13
+ }
14
+ };
15
+
16
+ //#endregion
17
+ export { Service };
@@ -0,0 +1,10 @@
1
+ import { version } from "../package.js";
2
+ import { milliseconds } from "@kizlo/shared";
3
+
4
+ //#region src/shared/constants.ts
5
+ const VERSION = version;
6
+ const RPC_PROTOCOL_HEADER = "x-rpc-protocol";
7
+ const SESSION_EXPIRY_MARGIN_MS = milliseconds("5 minutes");
8
+
9
+ //#endregion
10
+ export { RPC_PROTOCOL_HEADER };
@@ -0,0 +1,21 @@
1
+ import { HTTPMethod } from "./types.js";
2
+ import { AnyProcedureRouter, InvocationScope } from "./procedure.js";
3
+ import { AnyContractRouter } from "@orpc/contract";
4
+ import { Pathname } from "@kizlo/shared";
5
+
6
+ //#region src/shared/contract.d.ts
7
+ type Contract = {
8
+ [key: string]: ContractProcedure | Contract;
9
+ };
10
+ type ContractProcedure = {
11
+ scope: InvocationScope;
12
+ route: {
13
+ method?: HTTPMethod;
14
+ path?: Pathname;
15
+ };
16
+ };
17
+ declare function isContractProcedure$1(node: unknown): node is ContractProcedure;
18
+ declare function generateContract<TRouter extends AnyProcedureRouter>(router: TRouter): Promise<Contract>;
19
+ declare function restoreContract(contract: Contract): AnyContractRouter;
20
+ //#endregion
21
+ export { Contract, ContractProcedure, generateContract, isContractProcedure$1 as isContractProcedure, restoreContract };
@@ -0,0 +1,43 @@
1
+ import { createOrpcRouter } from "./router.js";
2
+ import { isContractProcedure, minifyContractRouter } from "@orpc/contract";
3
+
4
+ //#region src/shared/contract.ts
5
+ function isContractProcedure$1(node) {
6
+ if (!node || typeof node !== "object") return false;
7
+ return "route" in node || "meta" in node;
8
+ }
9
+ async function generateContract(router) {
10
+ const contract = minifyContractRouter(createOrpcRouter(router));
11
+ const walk = (node) => {
12
+ const out = {};
13
+ for (const [key, value] of Object.entries(node)) if (isContractProcedure(value)) {
14
+ const { route, meta } = value["~orpc"];
15
+ const scope = meta?.scope ?? null;
16
+ if (!scope) throw new Error("Scope not defined in procedure metadata.");
17
+ out[key] = {
18
+ scope,
19
+ route: route ?? {}
20
+ };
21
+ } else out[key] = walk(value);
22
+ return out;
23
+ };
24
+ return walk(contract);
25
+ }
26
+ function restoreContract(contract) {
27
+ const walk = (node) => {
28
+ const out = {};
29
+ for (const [key, value] of Object.entries(node)) if (isContractProcedure$1(value)) {
30
+ const procedure = value;
31
+ out[key] = { "~orpc": {
32
+ meta: {},
33
+ errorMap: {},
34
+ route: procedure.route ?? {}
35
+ } };
36
+ } else out[key] = walk(value);
37
+ return out;
38
+ };
39
+ return walk(contract);
40
+ }
41
+
42
+ //#endregion
43
+ export { generateContract, isContractProcedure$1 as isContractProcedure, restoreContract };
@@ -0,0 +1,28 @@
1
+ import { BinaryLike } from "node:crypto";
2
+
3
+ //#region src/shared/crypto.d.ts
4
+
5
+ /**
6
+ * Compares two strings in a timing-safe manner to prevent timing attacks.
7
+ *
8
+ * @param a - The first string to compare.
9
+ * @param b - The second string to compare.
10
+ * @returns `true` if the strings match, `false` otherwise.
11
+ */
12
+ declare function compare(a: string, b: string): boolean;
13
+ /**
14
+ * Hashes a secret API key with SHA-256 for secure database storage.
15
+ * Safe to use in place of bcrypt/argon2 because API keys are high-entropy
16
+ * random strings, unlike user-chosen passwords.
17
+ * Only secret keys should be hashed — publishable keys are not sensitive.
18
+ *
19
+ * @param key - The raw secret API key to hash.
20
+ * @returns A SHA-256 hex string suitable for database storage.
21
+ */
22
+ declare function hash(key: string): string;
23
+ /**
24
+ * Create hmac using node crypto lib.
25
+ */
26
+ declare function hmac(key: string, value: BinaryLike): string;
27
+ //#endregion
28
+ export { compare, hash, hmac };
@@ -0,0 +1,34 @@
1
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
2
+
3
+ //#region src/shared/crypto.ts
4
+ /**
5
+ * Compares two strings in a timing-safe manner to prevent timing attacks.
6
+ *
7
+ * @param a - The first string to compare.
8
+ * @param b - The second string to compare.
9
+ * @returns `true` if the strings match, `false` otherwise.
10
+ */
11
+ function compare(a, b) {
12
+ return timingSafeEqual(Buffer.from(a), Buffer.from(b));
13
+ }
14
+ /**
15
+ * Hashes a secret API key with SHA-256 for secure database storage.
16
+ * Safe to use in place of bcrypt/argon2 because API keys are high-entropy
17
+ * random strings, unlike user-chosen passwords.
18
+ * Only secret keys should be hashed — publishable keys are not sensitive.
19
+ *
20
+ * @param key - The raw secret API key to hash.
21
+ * @returns A SHA-256 hex string suitable for database storage.
22
+ */
23
+ function hash(key) {
24
+ return createHash("sha256").update(key).digest("hex");
25
+ }
26
+ /**
27
+ * Create hmac using node crypto lib.
28
+ */
29
+ function hmac(key, value) {
30
+ return createHmac("sha256", key).update(value).digest("hex");
31
+ }
32
+
33
+ //#endregion
34
+ export { compare, hash, hmac };