kizlo 0.29.0 → 0.31.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 (45) hide show
  1. package/dist/adapters/geo.cloudflare.d.ts +1 -1
  2. package/dist/adapters/geo.cloudflare.js +1 -1
  3. package/dist/adapters/request-context.d.ts +12 -0
  4. package/dist/adapters/types.d.ts +2 -0
  5. package/dist/adapters/types.js +1 -0
  6. package/dist/context.d.ts +13 -30
  7. package/dist/context.js +15 -6
  8. package/dist/index.d.ts +4 -4
  9. package/dist/integrations/nextjs/api.d.ts +13 -0
  10. package/dist/integrations/nextjs/api.js +17 -0
  11. package/dist/integrations/tanstack-start/cloudflare/cache-policy.js +14 -0
  12. package/dist/integrations/tanstack-start/cloudflare/cache.d.ts +40 -0
  13. package/dist/integrations/tanstack-start/cloudflare/cache.js +112 -0
  14. package/dist/integrations/tanstack-start/cloudflare/revalidator.d.ts +35 -0
  15. package/dist/integrations/tanstack-start/cloudflare/revalidator.js +130 -0
  16. package/dist/integrations/tanstack-start/react/cookies.js +20 -0
  17. package/dist/integrations/tanstack-start/react/integration.d.ts +25 -0
  18. package/dist/integrations/tanstack-start/react/integration.js +18 -0
  19. package/dist/integrations/tanstack-start/react/middleware.d.ts +9 -0
  20. package/dist/integrations/tanstack-start/react/middleware.js +32 -0
  21. package/dist/integrations/tanstack-start/request-context.d.ts +8 -0
  22. package/dist/integrations/tanstack-start/request-context.js +24 -0
  23. package/dist/kizlo.d.ts +2 -1
  24. package/dist/kizlo.js +24 -16
  25. package/dist/nextjs/server.d.ts +2 -1
  26. package/dist/nextjs/server.js +2 -1
  27. package/dist/package.js +1 -1
  28. package/dist/tanstack-start/cloudflare.d.ts +28 -0
  29. package/dist/tanstack-start/cloudflare.js +34 -0
  30. package/dist/tanstack-start/react/server.d.ts +14 -0
  31. package/dist/tanstack-start/react/server.js +13 -0
  32. package/dist/webhook/index.d.ts +2 -0
  33. package/dist/webhook/index.js +9 -2
  34. package/dist/webhook/schema.d.ts +36 -1
  35. package/dist/webhook/schema.js +7 -3
  36. package/dist/webhook/utils.js +11 -1
  37. package/package.json +24 -20
  38. package/dist/cloudflare/vinext.d.ts +0 -7
  39. package/dist/cloudflare/vinext.js +0 -44
  40. package/dist/cloudflare.d.ts +0 -3
  41. package/dist/cloudflare.js +0 -4
  42. package/dist/integrations/cloudflare/integration.d.ts +0 -8
  43. package/dist/integrations/cloudflare/integration.js +0 -16
  44. package/dist/integrations/cloudflare/request-context.d.ts +0 -9
  45. package/dist/integrations/cloudflare/request-context.js +0 -58
@@ -0,0 +1,18 @@
1
+ import { tanstackStart } from "../integration.js";
2
+ import { startCookies } from "./cookies.js";
3
+ import { getStartRequestContext } from "../request-context.js";
4
+
5
+ //#region src/integrations/tanstack-start/react/integration.ts
6
+ /** Add React Start's native request context and cookies to the shared environment mapping. */
7
+ function tanstackStart$1(options = {}) {
8
+ return {
9
+ ...tanstackStart(options),
10
+ adapters: {
11
+ cookies: startCookies(),
12
+ requestContext: { get: getStartRequestContext }
13
+ }
14
+ };
15
+ }
16
+
17
+ //#endregion
18
+ export { tanstackStart$1 as tanstackStart };
@@ -0,0 +1,9 @@
1
+ import * as _tanstack_start_client_core0 from "@tanstack/start-client-core";
2
+ import { AnyRequestMiddleware } from "@tanstack/react-start";
3
+
4
+ //#region src/integrations/tanstack-start/react/middleware.d.ts
5
+ type MiddlewareMatcher = string | readonly string[] | ((request: Request) => boolean);
6
+ /** Wrap native request middleware with a path-to-regexp pattern or synchronous request predicate. */
7
+ declare function matchMiddleware<Middleware extends AnyRequestMiddleware>(middleware: Middleware, matcher: MiddlewareMatcher): Pick<_tanstack_start_client_core0.RequestMiddlewareAfterServer<{}, readonly [Middleware], undefined>, "options" | "~types">;
8
+ //#endregion
9
+ export { MiddlewareMatcher, matchMiddleware };
@@ -0,0 +1,32 @@
1
+ import { createPathMatcher } from "@kizlo/shared";
2
+ import { getRequest } from "@tanstack/react-start/server";
3
+ import { createIsomorphicFn, createMiddleware } from "@tanstack/react-start";
4
+
5
+ //#region src/integrations/tanstack-start/react/middleware.ts
6
+ const currentRequest = createIsomorphicFn().client(() => void 0).server(() => getRequest());
7
+ /** Wrap native request middleware with a path-to-regexp pattern or synchronous request predicate. */
8
+ function matchMiddleware(middleware, matcher) {
9
+ const patterns = typeof matcher === "function" ? [] : typeof matcher === "string" ? [matcher] : matcher;
10
+ if (patterns.some((pattern) => !pattern.startsWith("/"))) throw new TypeError("Middleware patterns must start with /.");
11
+ const [first, ...rest] = patterns;
12
+ const matches = typeof matcher === "function" ? matcher : first === void 0 ? () => false : createPathMatcher([first, ...rest]);
13
+ const wrapped = createMiddleware().middleware([middleware]).server(({ next }) => next());
14
+ const options = wrapped.options;
15
+ const skipped = { server: options.server };
16
+ const decisions = /* @__PURE__ */ new WeakMap();
17
+ Object.defineProperty(wrapped, "options", { get() {
18
+ const request = currentRequest();
19
+ if (!request) return {};
20
+ let selected = decisions.get(request);
21
+ if (selected === void 0) {
22
+ selected = matches(request);
23
+ if (typeof selected !== "boolean") throw new TypeError("Middleware predicates must return a boolean synchronously.");
24
+ decisions.set(request, selected);
25
+ }
26
+ return selected ? options : skipped;
27
+ } });
28
+ return wrapped;
29
+ }
30
+
31
+ //#endregion
32
+ export { matchMiddleware };
@@ -0,0 +1,8 @@
1
+ //#region src/integrations/tanstack-start/request-context.d.ts
2
+ /** Read Start's native request scope; no application-owned async storage is needed. */
3
+ declare function getStartRequestContext(): {
4
+ request: Request;
5
+ values: object;
6
+ } | undefined;
7
+ //#endregion
8
+ export { getStartRequestContext };
@@ -0,0 +1,24 @@
1
+ import { getGlobalStartContext } from "@tanstack/start-client-core";
2
+ import { getRequest } from "@tanstack/start-server-core/request-response";
3
+
4
+ //#region src/integrations/tanstack-start/request-context.ts
5
+ /** Read Start's native request scope; no application-owned async storage is needed. */
6
+ function getStartRequestContext() {
7
+ let request;
8
+ try {
9
+ request = getRequest();
10
+ } catch {
11
+ return;
12
+ }
13
+ let values = {};
14
+ try {
15
+ values = getGlobalStartContext() ?? {};
16
+ } catch {}
17
+ return {
18
+ request,
19
+ values
20
+ };
21
+ }
22
+
23
+ //#endregion
24
+ export { getStartRequestContext };
package/dist/kizlo.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ActiveWordPressClient, WordPressCredentials } from "./wordpress/types.js";
2
2
  import "./wordpress/index.js";
3
3
  import { LogLevel } from "./adapters/logger.js";
4
+ import { PlatformRequestCtx } from "./context.js";
4
5
  import { CoreProcedures } from "./procedures.js";
5
6
  import { AnyIntegration, EnvReader, InferIntegrationProcedures } from "./shared/integration.js";
6
7
  import { ResultClient } from "./shared/result.js";
@@ -26,7 +27,7 @@ declare class Kizlo<TIntegrations extends readonly AnyIntegration[] = []> {
26
27
  private readonly config;
27
28
  constructor(config: KizloConfig<TIntegrations>);
28
29
  get wordpress(): ActiveWordPressClient;
29
- handler(request: Request): Promise<Response>;
30
+ handler(request: Request, values?: PlatformRequestCtx): Promise<Response>;
30
31
  private errorInterceptor;
31
32
  private checkInvocationScope;
32
33
  private registerIntegrations;
package/dist/kizlo.js CHANGED
@@ -61,23 +61,31 @@ var Kizlo = class {
61
61
  get wordpress() {
62
62
  return this.context.createServerContext().wordpress;
63
63
  }
64
- async handler(request) {
65
- const serverUrl = new URL(this.config.baseUrl);
66
- const context = this.context.createRestContext(request);
67
- const result = !(request.headers.get(RPC_PROTOCOL_HEADER) !== null) ? await this.openapiHandler.handle(request, {
68
- context,
69
- prefix: serverUrl.pathname
70
- }) : await this.remoteHandler.handle(request, {
71
- context,
72
- prefix: serverUrl.pathname
64
+ async handler(request, values) {
65
+ return this.context.withRequestContext(request, values, async () => {
66
+ const serverUrl = new URL(this.config.baseUrl);
67
+ const context = this.context.createRestContext(request, values);
68
+ const result = !(request.headers.get(RPC_PROTOCOL_HEADER) !== null) ? await this.openapiHandler.handle(request, {
69
+ context,
70
+ prefix: serverUrl.pathname
71
+ }) : await this.remoteHandler.handle(request, {
72
+ context,
73
+ prefix: serverUrl.pathname
74
+ });
75
+ const response = result.matched ? result.response : new Response("Not Found", { status: 404 });
76
+ for (const [key, value] of context.headers.entries()) {
77
+ if (key.toLowerCase() === "set-cookie") continue;
78
+ response.headers.set(key, value);
79
+ }
80
+ for (const cookie of context.headers.getSetCookie()) response.headers.append("Set-Cookie", cookie);
81
+ response.headers.set("Cache-Control", "private, no-store");
82
+ for (const name of [
83
+ "Cloudflare-CDN-Cache-Control",
84
+ "CDN-Cache-Control",
85
+ "Cache-Tag"
86
+ ]) response.headers.delete(name);
87
+ return response;
73
88
  });
74
- if (!result.matched) return new Response("Not Found", { status: 404 });
75
- for (const [key, value] of context.headers.entries()) {
76
- if (key.toLowerCase() === "set-cookie") continue;
77
- result.response.headers.set(key, value);
78
- }
79
- for (const cookie of context.headers.getSetCookie()) result.response.headers.append("Set-Cookie", cookie);
80
- return result.response;
81
89
  }
82
90
  errorInterceptor() {
83
91
  return async ({ context, next }) => {
@@ -1,6 +1,7 @@
1
1
  import { WEB_MANIFEST_ROUTE } from "../brand/manifest.js";
2
2
  import { renderJsonLd } from "../seo/utils.js";
3
3
  import { createSitemapRedirectRoute } from "../seo/sitemap.js";
4
+ import { toNextJsHandler } from "../integrations/nextjs/api.js";
4
5
  import { NextRevalidateOptions, RevalidatePathFn, RevalidateTagFn, RevalidateTarget, nextRevalidation } from "../integrations/nextjs/revalidate.js";
5
6
  import { NextjsOptions, nextjs } from "../integrations/nextjs/integration.js";
6
7
  import { MANIFEST_CACHE_TAG, createManifestRoute } from "../integrations/nextjs/manifest.js";
@@ -8,4 +9,4 @@ import { createHomeMetadata, createPageMetadata, createRootMetadata, createRootV
8
9
  import { ROBOTS_CACHE_TAG, createRobotsRoute } from "../integrations/nextjs/robots.js";
9
10
  import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
10
11
  import { createCachedTextRoute, createNextCookiesInterface, getServerBaseUrl } from "../integrations/nextjs/utils.js";
11
- export { MANIFEST_CACHE_TAG, NextRevalidateOptions, NextjsOptions, ROBOTS_CACHE_TAG, RevalidatePathFn, RevalidateTagFn, RevalidateTarget, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, nextjs, renderJsonLd };
12
+ export { MANIFEST_CACHE_TAG, NextRevalidateOptions, NextjsOptions, ROBOTS_CACHE_TAG, RevalidatePathFn, RevalidateTagFn, RevalidateTarget, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, nextjs, renderJsonLd, toNextJsHandler };
@@ -2,6 +2,7 @@ import { WEB_MANIFEST_ROUTE } from "../brand/manifest.js";
2
2
  import { renderJsonLd } from "../seo/utils.js";
3
3
  import { createSitemapRedirectRoute } from "../seo/sitemap.js";
4
4
  import { createCachedTextRoute, createNextCookiesInterface, getServerBaseUrl } from "../integrations/nextjs/utils.js";
5
+ import { toNextJsHandler } from "../integrations/nextjs/api.js";
5
6
  import { ROBOTS_CACHE_TAG, createRobotsRoute } from "../integrations/nextjs/robots.js";
6
7
  import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
7
8
  import { nextRevalidation } from "../integrations/nextjs/revalidate.js";
@@ -9,4 +10,4 @@ import { nextjs } from "../integrations/nextjs/integration.js";
9
10
  import { MANIFEST_CACHE_TAG, createManifestRoute } from "../integrations/nextjs/manifest.js";
10
11
  import { createHomeMetadata, createPageMetadata, createRootMetadata, createRootViewport } from "../integrations/nextjs/metadata.js";
11
12
 
12
- export { MANIFEST_CACHE_TAG, ROBOTS_CACHE_TAG, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, nextjs, renderJsonLd };
13
+ export { MANIFEST_CACHE_TAG, ROBOTS_CACHE_TAG, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, nextjs, renderJsonLd, toNextJsHandler };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.29.0";
2
+ var version = "0.31.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -0,0 +1,28 @@
1
+ import { GeoAdapter } from "../adapters/geo.js";
2
+ import { Integration } from "../shared/integration.js";
3
+ import "../index.js";
4
+ import { CdnHeadersOptions, CloudflareCacheBinding, CloudflareCacheResult, createCdnHeaders, purgeCache, revalidateTag, revalidateUrl } from "../integrations/tanstack-start/cloudflare/cache.js";
5
+ import { RevalidationPostData, RevalidationPostRule, RevalidationSettingsEvent, RevalidationTaxonomyRule, RevalidationTermData, RevalidatorOptions, revalidator } from "../integrations/tanstack-start/cloudflare/revalidator.js";
6
+
7
+ //#region src/integrations/tanstack-start/cloudflare.d.ts
8
+ interface ExecutionContext {
9
+ cache?: CloudflareCacheBinding;
10
+ waitUntil(promise: Promise<unknown>): void;
11
+ }
12
+ /** Cloudflare connection metadata, using TanStack Start's existing request scope. */
13
+ declare function geoCloudflare(): GeoAdapter;
14
+ /** Add Cloudflare connection metadata; caching remains an explicit response policy. */
15
+ declare function cloudflare(): Integration<"cloudflare", Record<never, never>>;
16
+ /** Forward native Worker values to Start, default to no caching and encode explicit cache tags. */
17
+ declare function withCloudflare<Env, Context extends ExecutionContext = ExecutionContext>(handler: {
18
+ fetch(request: Request, options: {
19
+ context: {
20
+ env: Env;
21
+ executionCtx: Context;
22
+ };
23
+ }): Response | Promise<Response>;
24
+ }): {
25
+ fetch(request: Request, env: Env, executionCtx: Context): Promise<Response>;
26
+ };
27
+ //#endregion
28
+ export { type CdnHeadersOptions, type CloudflareCacheBinding, type CloudflareCacheResult, type RevalidationPostData, type RevalidationPostRule, type RevalidationSettingsEvent, type RevalidationTaxonomyRule, type RevalidationTermData, type RevalidatorOptions, cloudflare, createCdnHeaders, geoCloudflare, purgeCache, revalidateTag, revalidateUrl, revalidator, withCloudflare };
@@ -0,0 +1,34 @@
1
+ import { cloudflareConnInfo } from "../adapters/cloudflare-connection.js";
2
+ import { FRAMEWORK_INTEGRATION_ORDER } from "../shared/constants.js";
3
+ import { createIntegration } from "../shared/integration.js";
4
+ import { getStartRequestContext } from "../integrations/tanstack-start/request-context.js";
5
+ import { applyCloudflareHeaders, createCdnHeaders, purgeCache, revalidateTag, revalidateUrl } from "../integrations/tanstack-start/cloudflare/cache.js";
6
+ import { revalidator } from "../integrations/tanstack-start/cloudflare/revalidator.js";
7
+
8
+ //#region src/integrations/tanstack-start/cloudflare.ts
9
+ /** Cloudflare connection metadata, using TanStack Start's existing request scope. */
10
+ function geoCloudflare() {
11
+ return { getConnInfo(request) {
12
+ return cloudflareConnInfo((request ?? getStartRequestContext()?.request)?.headers);
13
+ } };
14
+ }
15
+ /** Add Cloudflare connection metadata; caching remains an explicit response policy. */
16
+ function cloudflare() {
17
+ return createIntegration({
18
+ id: "cloudflare",
19
+ order: FRAMEWORK_INTEGRATION_ORDER,
20
+ adapters: { geo: geoCloudflare() }
21
+ });
22
+ }
23
+ /** Forward native Worker values to Start, default to no caching and encode explicit cache tags. */
24
+ function withCloudflare(handler) {
25
+ return { async fetch(request, env, executionCtx) {
26
+ return applyCloudflareHeaders(request, await handler.fetch(request, { context: {
27
+ env,
28
+ executionCtx
29
+ } }));
30
+ } };
31
+ }
32
+
33
+ //#endregion
34
+ export { cloudflare, createCdnHeaders, geoCloudflare, purgeCache, revalidateTag, revalidateUrl, revalidator, withCloudflare };
@@ -0,0 +1,14 @@
1
+ import { WEB_MANIFEST_ROUTE } from "../../brand/manifest.js";
2
+ import { renderJsonLd } from "../../seo/utils.js";
3
+ import { LinkDescriptor, MetaDescriptor, RouteHead, ScriptDescriptor, resolvePageHead } from "../../integrations/tanstack-start/metadata.js";
4
+ import { ServerRoute, ServerRouteContext, getServerBaseUrl } from "../../integrations/tanstack-start/utils.js";
5
+ import { ApiHandlers, KizloHandler, createApiHandlers } from "../../integrations/tanstack-start/api.js";
6
+ import { TanstackStartOptions } from "../../integrations/tanstack-start/integration.js";
7
+ import { createManifestRoute } from "../../integrations/tanstack-start/manifest.js";
8
+ import { createRobotsRoute } from "../../integrations/tanstack-start/robots.js";
9
+ import { resolveRootHead } from "../../integrations/tanstack-start/root-head.js";
10
+ import { createSitemapRedirectRoute, createSitemapRoute } from "../../integrations/tanstack-start/sitemap.js";
11
+ import "../server.js";
12
+ import { tanstackStart } from "../../integrations/tanstack-start/react/integration.js";
13
+ import { MiddlewareMatcher, matchMiddleware } from "../../integrations/tanstack-start/react/middleware.js";
14
+ export { ApiHandlers, KizloHandler, LinkDescriptor, MetaDescriptor, MiddlewareMatcher, RouteHead, ScriptDescriptor, ServerRoute, ServerRouteContext, TanstackStartOptions, WEB_MANIFEST_ROUTE, createApiHandlers, createManifestRoute, createRobotsRoute, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, matchMiddleware, renderJsonLd, resolvePageHead, resolveRootHead, tanstackStart };
@@ -0,0 +1,13 @@
1
+ import { WEB_MANIFEST_ROUTE } from "../../brand/manifest.js";
2
+ import { renderJsonLd } from "../../seo/utils.js";
3
+ import { getServerBaseUrl } from "../../integrations/tanstack-start/utils.js";
4
+ import { resolvePageHead } from "../../integrations/tanstack-start/metadata.js";
5
+ import { createApiHandlers } from "../../integrations/tanstack-start/api.js";
6
+ import { createManifestRoute } from "../../integrations/tanstack-start/manifest.js";
7
+ import { createRobotsRoute } from "../../integrations/tanstack-start/robots.js";
8
+ import { resolveRootHead } from "../../integrations/tanstack-start/root-head.js";
9
+ import { createSitemapRedirectRoute, createSitemapRoute } from "../../integrations/tanstack-start/sitemap.js";
10
+ import { tanstackStart } from "../../integrations/tanstack-start/react/integration.js";
11
+ import { matchMiddleware } from "../../integrations/tanstack-start/react/middleware.js";
12
+
13
+ export { WEB_MANIFEST_ROUTE, createApiHandlers, createManifestRoute, createRobotsRoute, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, matchMiddleware, renderJsonLd, resolvePageHead, resolveRootHead, tanstackStart };
@@ -22,6 +22,8 @@ interface WebhookOptions {
22
22
  events?: EventHandler[];
23
23
  }
24
24
  interface EventHandler {
25
+ /** Required handlers fail acknowledgement so the sender can retry. Defaults to log-only. */
26
+ failureMode?: "log" | "retry";
25
27
  events?: AnyEvents;
26
28
  handler: EventHandlerFn<AnyEvents>;
27
29
  }
@@ -31,12 +31,19 @@ function createWebhookRouter(options) {
31
31
  headers
32
32
  }));
33
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 validateEvent(events, input.body);
34
+ const results = await Promise.allSettled((options?.events ?? []).map(async ({ events, handler, failureMode }) => {
35
+ const event = await validateEvent(events, input.body, failureMode);
36
36
  if (!event) return;
37
37
  await handler(event, context);
38
38
  }));
39
39
  for (const result of results) if (result.status === "rejected") context.logger.error("Webhook handler failed", result.reason);
40
+ const required = results.find((result, index) => result.status === "rejected" && options?.events?.[index]?.failureMode === "retry");
41
+ if (required?.status === "rejected") {
42
+ if (required.reason instanceof KizloError && required.reason.status === 422) throw required.reason;
43
+ const limited = required.reason instanceof KizloError && required.reason.status === 429;
44
+ if (limited) context.headers?.set("Retry-After", "60");
45
+ throw new KizloError(limited ? "TOO_MANY_REQUESTS" : "SERVICE_UNAVAILABLE", { message: "Required webhook work failed. Retry delivery." });
46
+ }
40
47
  }) };
41
48
  }
42
49
 
@@ -2,6 +2,38 @@ import z from "zod/v4";
2
2
 
3
3
  //#region src/webhook/schema.d.ts
4
4
 
5
+ declare const SETTINGS_INDEXED_EVENT_TYPES: readonly ["settings.post_type.updated", "settings.taxonomy.updated"];
6
+ declare const SettingsEventType: z.ZodEnum<{
7
+ "settings.site.updated": "settings.site.updated";
8
+ "settings.brand.updated": "settings.brand.updated";
9
+ "settings.identity.updated": "settings.identity.updated";
10
+ "settings.authors.updated": "settings.authors.updated";
11
+ "settings.crawling.updated": "settings.crawling.updated";
12
+ "settings.headless.updated": "settings.headless.updated";
13
+ "settings.integration.updated": "settings.integration.updated";
14
+ "settings.woocommerce.updated": "settings.woocommerce.updated";
15
+ "settings.post_type.updated": "settings.post_type.updated";
16
+ "settings.taxonomy.updated": "settings.taxonomy.updated";
17
+ }>;
18
+ type SettingsEventType = z.infer<typeof SettingsEventType>;
19
+ declare const TermDependencies: z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodArray<z.ZodNumber>, z.ZodTransform<number[], number[]>>>;
20
+ type TermDependencies = z.infer<typeof TermDependencies>;
21
+ declare const PostEventData: z.ZodObject<{
22
+ post_id: z.ZodNumber;
23
+ affected_terms: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodArray<z.ZodNumber>, z.ZodTransform<number[], number[]>>>>>;
24
+ post_type: z.ZodString;
25
+ url: z.ZodOptional<z.ZodString>;
26
+ }, z.core.$strip>;
27
+ type PostEventData = z.infer<typeof PostEventData>;
28
+ declare const TermEventData: z.ZodObject<{
29
+ term_id: z.ZodNumber;
30
+ affected_terms: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodArray<z.ZodNumber>, z.ZodTransform<number[], number[]>>>>>;
31
+ taxonomy: z.ZodString;
32
+ post_types: z.ZodArray<z.ZodString>;
33
+ count: z.ZodNumber;
34
+ url: z.ZodOptional<z.ZodString>;
35
+ }, z.core.$strip>;
36
+ type TermEventData = z.infer<typeof TermEventData>;
5
37
  declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
6
38
  type: z.ZodEnum<{
7
39
  "post.created": "post.created";
@@ -11,6 +43,7 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
11
43
  }>;
12
44
  data: z.ZodObject<{
13
45
  post_id: z.ZodNumber;
46
+ affected_terms: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodArray<z.ZodNumber>, z.ZodTransform<number[], number[]>>>>>;
14
47
  post_type: z.ZodString;
15
48
  url: z.ZodOptional<z.ZodString>;
16
49
  }, z.core.$strip>;
@@ -22,6 +55,7 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
22
55
  }>;
23
56
  data: z.ZodObject<{
24
57
  term_id: z.ZodNumber;
58
+ affected_terms: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodArray<z.ZodNumber>, z.ZodTransform<number[], number[]>>>>>;
25
59
  taxonomy: z.ZodString;
26
60
  post_types: z.ZodArray<z.ZodString>;
27
61
  count: z.ZodNumber;
@@ -34,6 +68,7 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
34
68
  "settings.identity.updated": "settings.identity.updated";
35
69
  "settings.authors.updated": "settings.authors.updated";
36
70
  "settings.crawling.updated": "settings.crawling.updated";
71
+ "settings.headless.updated": "settings.headless.updated";
37
72
  "settings.integration.updated": "settings.integration.updated";
38
73
  "settings.woocommerce.updated": "settings.woocommerce.updated";
39
74
  }>;
@@ -49,4 +84,4 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
49
84
  }, z.core.$strip>]>;
50
85
  type KizloEvent = z.infer<typeof KizloEvent>;
51
86
  //#endregion
52
- export { KizloEvent };
87
+ export { KizloEvent, PostEventData, SETTINGS_INDEXED_EVENT_TYPES, SettingsEventType, TermDependencies, TermEventData };
@@ -20,6 +20,7 @@ const SETTINGS_SIMPLE_EVENT_TYPES = [
20
20
  "settings.identity.updated",
21
21
  "settings.authors.updated",
22
22
  "settings.crawling.updated",
23
+ "settings.headless.updated",
23
24
  "settings.integration.updated",
24
25
  "settings.woocommerce.updated"
25
26
  ];
@@ -34,8 +35,10 @@ const EVENT_TYPES = [
34
35
  ...SETTINGS_EVENT_TYPES
35
36
  ];
36
37
  const EventType = z.enum(EVENT_TYPES);
38
+ const TermDependencies = z.record(z.string().min(1), z.array(z.number().int().positive().max(Number.MAX_SAFE_INTEGER)).transform((ids) => [...new Set(ids)]));
37
39
  const PostEventData = z.object({
38
- post_id: z.number(),
40
+ post_id: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
41
+ affected_terms: TermDependencies.nullable().optional(),
39
42
  post_type: z.string(),
40
43
  url: z.string().optional()
41
44
  });
@@ -44,7 +47,8 @@ const PostEvent = z.object({
44
47
  data: PostEventData
45
48
  });
46
49
  const TermEventData = z.object({
47
- term_id: z.number(),
50
+ term_id: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
51
+ affected_terms: TermDependencies.nullable().optional(),
48
52
  taxonomy: z.string(),
49
53
  post_types: z.array(z.string()),
50
54
  count: z.number().nonnegative(),
@@ -77,4 +81,4 @@ const AnyEvent = z.object({
77
81
  });
78
82
 
79
83
  //#endregion
80
- export { AnyEvent, KizloEvent, POST_EVENT_TYPES, SETTINGS_EVENT_TYPES, TERM_EVENT_TYPES };
84
+ export { AnyEvent, KizloEvent, POST_EVENT_TYPES, PostEventData, SETTINGS_EVENT_TYPES, SETTINGS_INDEXED_EVENT_TYPES, SettingsIndexedEventData, SettingsSimpleEventData, TERM_EVENT_TYPES, TermDependencies, TermEventData };
@@ -1,8 +1,18 @@
1
+ import { KizloError } from "../shared/error.js";
1
2
  import { KizloEvent } from "./schema.js";
2
3
  import { safeValidateSchema } from "@kizlo/shared";
3
4
 
4
5
  //#region src/webhook/utils.ts
5
- async function validateEvent(events, data) {
6
+ async function validateEvent(events, data, failureMode = "log") {
7
+ const explicit = events?.find((entry) => entry.types.includes(data.type))?.data;
8
+ if (failureMode === "retry" && explicit) {
9
+ const result = await safeValidateSchema(explicit, data.data);
10
+ if (!result.success) throw new KizloError("UNPROCESSABLE_CONTENT", { message: "Invalid webhook dependencies. Update the event-producing plugin and check affected_terms." });
11
+ return {
12
+ type: data.type,
13
+ data: result.value
14
+ };
15
+ }
6
16
  const internal = await safeValidateSchema(KizloEvent, data);
7
17
  if (internal.success) return internal.value;
8
18
  const external = events?.find((a) => a.types.includes(data.type))?.data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kizlo",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "type": "module",
5
5
  "description": "A headless WordPress framework for TypeScript.",
6
6
  "keywords": [
@@ -58,18 +58,6 @@
58
58
  "default": "./dist/test.js"
59
59
  }
60
60
  },
61
- "./cloudflare": {
62
- "import": {
63
- "types": "./dist/cloudflare.d.ts",
64
- "default": "./dist/cloudflare.js"
65
- }
66
- },
67
- "./cloudflare/vinext": {
68
- "import": {
69
- "types": "./dist/cloudflare/vinext.d.ts",
70
- "default": "./dist/cloudflare/vinext.js"
71
- }
72
- },
73
61
  "./node": {
74
62
  "import": {
75
63
  "types": "./dist/node.d.ts",
@@ -111,6 +99,18 @@
111
99
  "types": "./dist/tanstack-start/server.d.ts",
112
100
  "default": "./dist/tanstack-start/server.js"
113
101
  }
102
+ },
103
+ "./tanstack-start/react/server": {
104
+ "import": {
105
+ "types": "./dist/tanstack-start/react/server.d.ts",
106
+ "default": "./dist/tanstack-start/react/server.js"
107
+ }
108
+ },
109
+ "./tanstack-start/cloudflare": {
110
+ "import": {
111
+ "types": "./dist/tanstack-start/cloudflare.d.ts",
112
+ "default": "./dist/tanstack-start/cloudflare.js"
113
+ }
114
114
  }
115
115
  },
116
116
  "files": [
@@ -145,14 +145,15 @@
145
145
  "zod": "^4.3.6"
146
146
  },
147
147
  "peerDependencies": {
148
- "@tanstack/react-router": "^1.130.0",
149
- "@tanstack/react-start": "^1.130.0",
148
+ "@tanstack/react-router": "^1.170.41",
149
+ "@tanstack/react-start": "^1.168.60",
150
+ "@tanstack/start-client-core": "^1.170.34",
151
+ "@tanstack/start-server-core": "^1.169.39",
150
152
  "astro": "^7.0.0",
151
153
  "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
152
154
  "react": "^18.0.0 || ^19.0.0",
153
155
  "react-dom": "^18.0.0 || ^19.0.0",
154
- "typescript": "^5.0.0",
155
- "vite": "^8.0.0"
156
+ "typescript": "^5.0.0"
156
157
  },
157
158
  "peerDependenciesMeta": {
158
159
  "@tanstack/react-router": {
@@ -161,6 +162,12 @@
161
162
  "@tanstack/react-start": {
162
163
  "optional": true
163
164
  },
165
+ "@tanstack/start-client-core": {
166
+ "optional": true
167
+ },
168
+ "@tanstack/start-server-core": {
169
+ "optional": true
170
+ },
164
171
  "astro": {
165
172
  "optional": true
166
173
  },
@@ -175,9 +182,6 @@
175
182
  },
176
183
  "typescript": {
177
184
  "optional": true
178
- },
179
- "vite": {
180
- "optional": true
181
185
  }
182
186
  }
183
187
  }
@@ -1,7 +0,0 @@
1
- import { Plugin } from "vite";
2
-
3
- //#region src/integrations/cloudflare/vinext.d.ts
4
- /** Capture Cloudflare context inside each Vinext stage, including cache misses and regeneration. */
5
- declare function cloudflareVinext(): Plugin;
6
- //#endregion
7
- export { cloudflareVinext };
@@ -1,44 +0,0 @@
1
- //#region src/integrations/cloudflare/vinext.ts
2
- const stages = new Map([["vinext/server/request-stage", ["loadVinextRequestStage", "handleRequestStage"]], ["vinext/server/response-stage", ["loadVinextResponseStage", "handleResponseStage"]]]);
3
- /** Capture Cloudflare context inside each Vinext stage, including cache misses and regeneration. */
4
- function cloudflareVinext() {
5
- const modules = /* @__PURE__ */ new Map();
6
- return {
7
- name: "kizlo:cloudflare-vinext",
8
- enforce: "pre",
9
- async resolveId(source, importer) {
10
- const stage = stages.get(source);
11
- if (!stage) return null;
12
- const resolved = await this.resolve(source, importer, { skipSelf: true });
13
- if (!resolved) return this.error(`Cannot resolve ${source}. Use a Vinext release exposing the public stage loaders.`);
14
- const id = `\0kizlo:cloudflare:${resolved.id}`;
15
- modules.set(id, {
16
- original: resolved.id,
17
- loader: stage[0],
18
- handler: stage[1]
19
- });
20
- return id;
21
- },
22
- load(id) {
23
- const stage = modules.get(id);
24
- if (!stage) return null;
25
- return `
26
- import { withCloudflareRequest } from "kizlo/cloudflare";
27
- import { ${stage.loader} as loadStage } from ${JSON.stringify(stage.original)};
28
- export * from ${JSON.stringify(stage.original)};
29
- export async function ${stage.loader}(...args) {
30
- const stage = await loadStage(...args);
31
- return {
32
- ...stage,
33
- ${stage.handler}(request, ...args) {
34
- return withCloudflareRequest(request, () => stage.${stage.handler}(request, ...args));
35
- }
36
- };
37
- }
38
- `;
39
- }
40
- };
41
- }
42
-
43
- //#endregion
44
- export { cloudflareVinext };
@@ -1,3 +0,0 @@
1
- import { cloudflare } from "./integrations/cloudflare/integration.js";
2
- import { geoCloudflare, withCloudflareRequest } from "./integrations/cloudflare/request-context.js";
3
- export { cloudflare, geoCloudflare, withCloudflareRequest };
@@ -1,4 +0,0 @@
1
- import { geoCloudflare, withCloudflareRequest } from "./integrations/cloudflare/request-context.js";
2
- import { cloudflare } from "./integrations/cloudflare/integration.js";
3
-
4
- export { cloudflare, geoCloudflare, withCloudflareRequest };
@@ -1,8 +0,0 @@
1
- import { Integration } from "../../shared/integration.js";
2
- import "../../index.js";
3
-
4
- //#region src/integrations/cloudflare/integration.d.ts
5
- /** Supply Cloudflare connection info independently of the frontend framework or WordPress host. */
6
- declare function cloudflare(): Integration<"cloudflare", Record<never, never>>;
7
- //#endregion
8
- export { cloudflare };
@@ -1,16 +0,0 @@
1
- import { FRAMEWORK_INTEGRATION_ORDER } from "../../shared/constants.js";
2
- import { createIntegration } from "../../shared/integration.js";
3
- import { geoCloudflare } from "./request-context.js";
4
-
5
- //#region src/integrations/cloudflare/integration.ts
6
- /** Supply Cloudflare connection info independently of the frontend framework or WordPress host. */
7
- function cloudflare() {
8
- return createIntegration({
9
- id: "cloudflare",
10
- order: FRAMEWORK_INTEGRATION_ORDER,
11
- adapters: { geo: geoCloudflare() }
12
- });
13
- }
14
-
15
- //#endregion
16
- export { cloudflare };