kizlo 0.3.0 → 0.3.2

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.
package/README.md CHANGED
@@ -1,27 +1,5 @@
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 for TypeScript</h3>
15
-
16
- <p align="center">
17
- Develop, test, and ship from your machine with a fully typed RPC layer and WordPress API client.
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>
1
+ <a href="https://www.kizlo.io"><img width="100%" src="https://cdn.kizlo.io/images/github-kizlo-banner.png" alt="Kizlo headless CMS Admin panel built with React" /></a>
2
+ <br />
25
3
 
26
4
  <p align="center">
27
5
  <a href="https://kizlo.io"><strong>Website</strong></a> ·
@@ -30,11 +8,16 @@
30
8
  <a href="https://x.com/kizlo_io"><strong>Twitter</strong></a>
31
9
  </p>
32
10
 
33
- ---
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/kizlo"><img src="https://img.shields.io/npm/v/kizlo?style=flat-square" alt="npm version"></a>
13
+ <a href="./LICENSE"><img src="https://img.shields.io/github/license/kizlo-io/kizlo?style=flat-square" alt="License"></a>
14
+ <a href="https://www.npmjs.com/package/kizlo"><img src="https://img.shields.io/npm/dt/kizlo?style=flat-square" alt="npm downloads"></a>
15
+ <a href="https://twitter.com/kizlo_io"><img src="https://img.shields.io/badge/follow-kizlo-1DA1F2?logo=twitter&style=flat-square" alt="Kizlo Twitter" /></a>
16
+ </p>
34
17
 
35
- ## What is Kizlo?
18
+ ---
36
19
 
37
- Kizlo is an open-source, typesafe toolkit for headless WordPress, built to sit behind any JavaScript framework as your backend or CMS. Its CLI spins up a local, Docker-based environment scoped to your project, giving you a fully typed RPC layer and WordPress API client to develop, test, and ship from your machine.
20
+ Kizlo is an open-source framework for building content-driven applications with WordPress as a headless CMS. Fully typed end-to-end, built for the AI era.
38
21
 
39
22
  > Kizlo extends through integrations, whether that's a WordPress plugin like WooCommerce or an external service for auth, analytics, and more. Browse all available [integrations](https://kizlo.io/integrations).
40
23
 
@@ -46,7 +29,7 @@ Set up Kizlo in your project:
46
29
  npx kizlo@latest init
47
30
  ```
48
31
 
49
- Start the local WordPress stack and regenerate the contract as you work:
32
+ Start the local WordPress stack:
50
33
 
51
34
  ```bash
52
35
  npx kizlo dev
@@ -71,9 +71,17 @@ export const GET = createRobotsRoute(client)
71
71
  contents: `import { createSitemapRoute } from "kizlo/nextjs/server"
72
72
  import { client } from "${ctx.serverImport(sitemapDir)}"
73
73
 
74
- // Unlike robots.txt, Vercel revalidates this route on demand, so it can stay static. It's
75
- // served from the CDN at no per-request cost and still refreshes when content changes.
76
- export const dynamic = "force-static"
74
+ // Run on the edge: cheaper and faster than Node for a response this small.
75
+ export const runtime = "edge"
76
+
77
+ // Like robots.txt, Vercel bakes sitemap routes into immutable Edge CDN assets at build time,
78
+ // bypassing ISR and on-demand revalidatePath. The index gets frozen with whatever WordPress
79
+ // returned at build (often nothing, since the self-referential backend isn't reachable yet),
80
+ // and revalidation can't purge that CDN copy.
81
+ //
82
+ // force-dynamic opts out of that static treatment. createSitemapRoute caches the WordPress calls
83
+ // per sitemap and refreshes them on content changes (via revalidateTag), so requests stay cheap.
84
+ export const dynamic = "force-dynamic"
77
85
 
78
86
  export const GET = createSitemapRoute(client)
79
87
  `
@@ -2,7 +2,7 @@ import { POST_EVENT_TYPES, TERM_EVENT_TYPES } from "../../webhook/schema.js";
2
2
  import { createEventHandler } from "../../webhook/index.js";
3
3
  import { createExtension } from "../../shared/extension.js";
4
4
  import { ROBOTS_CACHE_TAG } from "./robots.js";
5
- import { SITEMAP_ROUTE } from "./sitemap.js";
5
+ import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE } from "./sitemap.js";
6
6
 
7
7
  //#region src/integrations/nextjs/revalidate.ts
8
8
  const DEFAULT_SITEMAP_TARGET = {
@@ -24,7 +24,10 @@ function nextRevalidation(options) {
24
24
  ];
25
25
  for (const path of normalizePaths(paths)) revalidatePath(path);
26
26
  if (event.type === "settings.saved") revalidateTag(ROBOTS_CACHE_TAG, { expire: 0 });
27
- if (CONTENT_EVENT_TYPES.has(event.type)) for (const target of resolveSitemapTargets(options?.sitemap)) revalidatePath(normalizePath(target.path), target.type);
27
+ if (CONTENT_EVENT_TYPES.has(event.type)) {
28
+ revalidateTag(SITEMAP_CACHE_TAG, { expire: 0 });
29
+ for (const target of resolveSitemapTargets(options?.sitemap)) revalidatePath(normalizePath(target.path), target.type);
30
+ }
28
31
  })] })
29
32
  });
30
33
  }
@@ -1,7 +1,6 @@
1
1
  import { S2SClient } from "../../kizlo.js";
2
2
 
3
3
  //#region src/integrations/nextjs/robots.d.ts
4
-
5
4
  declare function createRobotsRoute(client: S2SClient<[]>): (request: Request) => Promise<Response>;
6
5
  //#endregion
7
6
  export { createRobotsRoute };
@@ -1,11 +1,6 @@
1
1
  import { createRobotsRoute } from "../../seo/robots.js";
2
2
 
3
3
  //#region src/integrations/nextjs/robots.ts
4
- /**
5
- * Cache tag for the cached robots.txt body. The Next revalidation extension calls
6
- * `revalidateTag(ROBOTS_CACHE_TAG)` on every webhook event so the route refreshes
7
- * on-demand instead of on every request.
8
- */
9
4
  const ROBOTS_CACHE_TAG = "kizlo:robots";
10
5
  function createRobotsRoute$1(client) {
11
6
  const handler = createRobotsRoute(client);
@@ -2,17 +2,8 @@ import { S2SClient } from "../../kizlo.js";
2
2
  import { CreateSitemapRouteOptions } from "../../seo/sitemap.js";
3
3
 
4
4
  //#region src/integrations/nextjs/sitemap.d.ts
5
-
6
- /**
7
- * The Next route the sitemap handler is mounted at: a single dynamic segment named
8
- * `[sitemap]`. It is fixed (not configurable) so that one `revalidatePath(SITEMAP_ROUTE,
9
- * "layout")` refreshes the index and every generated sitemap at once. A `layout`
10
- * revalidation (not `page`) is required because the route has no `generateStaticParams`,
11
- * so its slugs are generated on-demand and only a subtree invalidation reaches them.
12
- * `[sitemap]` is Next's file-routing convention, which is why it lives in this integration
13
- * and not in core.
14
- */
15
5
  declare const SITEMAP_ROUTE: "/sitemaps/[sitemap]";
6
+ declare const SITEMAP_CACHE_TAG = "kizlo:sitemap";
16
7
  /** Next's dynamic-route context. `params` is a promise in the App Router. */
17
8
  interface NextRouteContext {
18
9
  params?: {
@@ -21,13 +12,6 @@ interface NextRouteContext {
21
12
  sitemap?: string;
22
13
  }>;
23
14
  }
24
- /**
25
- * Next wrapper around the framework-agnostic {@link createCoreSitemapRoute}. It serves the
26
- * same sitemap index and collection pages, and additionally asserts the route is mounted at
27
- * {@link SITEMAP_ROUTE}: if the dynamic segment is not named `[sitemap]`, `params.sitemap`
28
- * is missing and a wrong mount would silently break `revalidatePath(SITEMAP_ROUTE, "layout")`,
29
- * so it throws loudly on the first request instead.
30
- */
31
15
  declare function createSitemapRoute(client: S2SClient<[]>, options?: CreateSitemapRouteOptions): (request: Request, ctx?: NextRouteContext) => Promise<Response>;
32
16
  //#endregion
33
- export { SITEMAP_ROUTE, createSitemapRoute };
17
+ export { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute };
@@ -1,31 +1,29 @@
1
+ import { xmlResponse } from "../../seo/utils.js";
1
2
  import { SITEMAP_BASE, createSitemapRoute } from "../../seo/sitemap.js";
2
3
 
3
4
  //#region src/integrations/nextjs/sitemap.ts
4
- /**
5
- * The Next route the sitemap handler is mounted at: a single dynamic segment named
6
- * `[sitemap]`. It is fixed (not configurable) so that one `revalidatePath(SITEMAP_ROUTE,
7
- * "layout")` refreshes the index and every generated sitemap at once. A `layout`
8
- * revalidation (not `page`) is required because the route has no `generateStaticParams`,
9
- * so its slugs are generated on-demand and only a subtree invalidation reaches them.
10
- * `[sitemap]` is Next's file-routing convention, which is why it lives in this integration
11
- * and not in core.
12
- */
13
5
  const SITEMAP_ROUTE = `${SITEMAP_BASE}/[sitemap]`;
14
- /**
15
- * Next wrapper around the framework-agnostic {@link createCoreSitemapRoute}. It serves the
16
- * same sitemap index and collection pages, and additionally asserts the route is mounted at
17
- * {@link SITEMAP_ROUTE}: if the dynamic segment is not named `[sitemap]`, `params.sitemap`
18
- * is missing and a wrong mount would silently break `revalidatePath(SITEMAP_ROUTE, "layout")`,
19
- * so it throws loudly on the first request instead.
20
- */
6
+ const SITEMAP_CACHE_TAG = "kizlo:sitemap";
21
7
  function createSitemapRoute$1(client, options) {
22
8
  const handler = createSitemapRoute(client, options);
9
+ let getCached;
23
10
  return async function GET(request, ctx) {
24
11
  const params = ctx?.params ? await ctx.params : void 0;
25
12
  if (params && params.sitemap === void 0) throw new Error(`createSitemapRoute must be mounted at "${SITEMAP_ROUTE}". The dynamic segment must be named [sitemap].`);
26
- return handler(request);
13
+ if (!getCached) {
14
+ const { unstable_cache } = await import("next/cache");
15
+ getCached = unstable_cache(async (url) => {
16
+ const response = await handler(new Request(url));
17
+ return {
18
+ status: response.status,
19
+ body: await response.text()
20
+ };
21
+ }, [SITEMAP_CACHE_TAG], { tags: [SITEMAP_CACHE_TAG] });
22
+ }
23
+ const { status, body } = await getCached(request.url);
24
+ return status === 200 ? xmlResponse(body) : new Response(body, { status });
27
25
  };
28
26
  }
29
27
 
30
28
  //#endregion
31
- export { SITEMAP_ROUTE, createSitemapRoute$1 as createSitemapRoute };
29
+ export { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute$1 as createSitemapRoute };
@@ -1,4 +1,4 @@
1
1
  import { KizloServerOptions, createKizlo } from "../integrations/nextjs/kizlo.server.js";
2
2
  import { createRobotsRoute } from "../integrations/nextjs/robots.js";
3
- import { SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
4
- export { KizloServerOptions, SITEMAP_ROUTE, createKizlo, createRobotsRoute, createSitemapRoute };
3
+ import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
4
+ export { KizloServerOptions, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createKizlo, createRobotsRoute, createSitemapRoute };
@@ -1,5 +1,5 @@
1
1
  import { createRobotsRoute } from "../integrations/nextjs/robots.js";
2
- import { SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
2
+ import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
3
3
  import { createKizlo } from "../integrations/nextjs/kizlo.server.js";
4
4
 
5
- export { SITEMAP_ROUTE, createKizlo, createRobotsRoute, createSitemapRoute };
5
+ export { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createKizlo, createRobotsRoute, createSitemapRoute };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.3.0";
2
+ var version = "0.3.2";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kizlo",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "description": "A headless WordPress toolkit for TypeScript.",
6
6
  "keywords": [