kizlo 0.15.2 → 0.17.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 (98) hide show
  1. package/dist/adapters/logger.d.ts +2 -5
  2. package/dist/adapters/logger.js +1 -1
  3. package/dist/adapters/types.d.ts +19 -0
  4. package/dist/adapters/types.js +17 -0
  5. package/dist/astro/server.d.ts +2 -2
  6. package/dist/astro/server.js +2 -2
  7. package/dist/category/index.js +2 -2
  8. package/dist/category/schema.js +2 -1
  9. package/dist/category/utils.js +1 -0
  10. package/dist/cli/commands/_setup.js +10 -10
  11. package/dist/cli/commands/dev.js +7 -7
  12. package/dist/cli/daemon/generate.js +19 -9
  13. package/dist/cli/daemon/jiti.js +4 -5
  14. package/dist/cli/daemon/watch.js +3 -2
  15. package/dist/cli/presets/template.js +1 -1
  16. package/dist/cli/utils.js +6 -6
  17. package/dist/cli/wp/bootstrap.js +15 -11
  18. package/dist/cli/wp/constants.js +1 -1
  19. package/dist/cli/wp/dev.js +6 -23
  20. package/dist/cli/wp/types.d.ts +2 -2
  21. package/dist/cli/wp/utils.d.ts +1 -1
  22. package/dist/cli/wp/utils.js +1 -1
  23. package/dist/client.d.ts +7 -7
  24. package/dist/client.js +1 -1
  25. package/dist/comment/index.js +2 -2
  26. package/dist/comment/schema.js +3 -3
  27. package/dist/comment/utils.js +4 -14
  28. package/dist/config.d.ts +8 -8
  29. package/dist/context.d.ts +5 -5
  30. package/dist/context.js +5 -5
  31. package/dist/index.d.ts +8 -7
  32. package/dist/index.js +6 -5
  33. package/dist/integrations/astro/integration.d.ts +12 -0
  34. package/dist/integrations/astro/integration.js +14 -0
  35. package/dist/integrations/astro/kizlo.client.d.ts +4 -4
  36. package/dist/integrations/astro/utils.d.ts +4 -5
  37. package/dist/integrations/astro/utils.js +5 -6
  38. package/dist/integrations/nextjs/integration.d.ts +15 -0
  39. package/dist/integrations/nextjs/integration.js +18 -0
  40. package/dist/integrations/nextjs/kizlo.client.d.ts +2 -2
  41. package/dist/integrations/nextjs/revalidate.d.ts +2 -3
  42. package/dist/integrations/nextjs/revalidate.js +4 -4
  43. package/dist/integrations/nextjs/utils.js +2 -2
  44. package/dist/integrations/node/integration.d.ts +12 -0
  45. package/dist/integrations/node/integration.js +14 -0
  46. package/dist/integrations/runtime-env.js +25 -0
  47. package/dist/integrations/tanstack-start/api.d.ts +1 -1
  48. package/dist/integrations/tanstack-start/integration.d.ts +12 -0
  49. package/dist/integrations/tanstack-start/integration.js +14 -0
  50. package/dist/integrations/tanstack-start/kizlo.client.d.ts +4 -4
  51. package/dist/integrations/tanstack-start/utils.d.ts +1 -1
  52. package/dist/integrations/tanstack-start/utils.js +3 -3
  53. package/dist/kizlo.d.ts +33 -70
  54. package/dist/kizlo.js +91 -75
  55. package/dist/menu/index.js +2 -2
  56. package/dist/nextjs/server.d.ts +2 -2
  57. package/dist/nextjs/server.js +2 -2
  58. package/dist/node.d.ts +2 -0
  59. package/dist/node.js +3 -0
  60. package/dist/package.js +1 -1
  61. package/dist/page/index.js +2 -2
  62. package/dist/page/schema.js +5 -4
  63. package/dist/page/utils.js +5 -9
  64. package/dist/post/index.js +2 -2
  65. package/dist/post/schema.js +5 -4
  66. package/dist/post/utils.js +5 -9
  67. package/dist/{router.d.ts → procedures.d.ts} +42 -125
  68. package/dist/procedures.js +23 -0
  69. package/dist/seo/index.js +2 -2
  70. package/dist/seo/schema.d.ts +5 -5
  71. package/dist/settings/index.js +2 -2
  72. package/dist/shared/constants.js +1 -9
  73. package/dist/shared/contract-generation.js +14 -0
  74. package/dist/shared/contract.d.ts +2 -2
  75. package/dist/shared/contract.js +2 -2
  76. package/dist/shared/integration.d.ts +91 -0
  77. package/dist/shared/integration.js +59 -0
  78. package/dist/shared/procedure.d.ts +8 -8
  79. package/dist/shared/result.d.ts +2 -2
  80. package/dist/shared/router.d.ts +2 -2
  81. package/dist/shared/router.js +2 -2
  82. package/dist/shared/schema.d.ts +3 -1
  83. package/dist/shared/schema.js +3 -1
  84. package/dist/tag/index.js +2 -2
  85. package/dist/tag/schema.js +2 -1
  86. package/dist/tag/utils.js +1 -0
  87. package/dist/tanstack-start/server.d.ts +2 -2
  88. package/dist/tanstack-start/server.js +2 -2
  89. package/package.json +8 -2
  90. package/dist/integrations/astro/kizlo.server.d.ts +0 -10
  91. package/dist/integrations/astro/kizlo.server.js +0 -12
  92. package/dist/integrations/nextjs/kizlo.server.d.ts +0 -11
  93. package/dist/integrations/nextjs/kizlo.server.js +0 -15
  94. package/dist/integrations/tanstack-start/kizlo.server.d.ts +0 -14
  95. package/dist/integrations/tanstack-start/kizlo.server.js +0 -15
  96. package/dist/router.js +0 -23
  97. package/dist/shared/extension.d.ts +0 -58
  98. package/dist/shared/extension.js +0 -37
@@ -3,13 +3,13 @@ import { KizloError } from "../../shared/error.js";
3
3
  //#region src/integrations/tanstack-start/utils.ts
4
4
  /**
5
5
  * The public Kizlo API base URL, read from `process.env` as a last-resort fallback for a client built
6
- * without an explicit `url`. Client-side code passes `import.meta.env.VITE_KIZLO_API_URL` at the call
6
+ * without an explicit `url`. Client-side code passes `import.meta.env.VITE_KIZLO_BASE_URL` at the call
7
7
  * site (see the template's `client.ts`) so Vite inlines it into the browser bundle; this fallback only
8
8
  * matters when neither is supplied.
9
9
  */
10
10
  function getServerBaseUrl() {
11
- const baseUrl = process.env.VITE_KIZLO_API_URL?.trim();
12
- if (!baseUrl) throw new KizloError("MISSING_ENV_VARIABLE", { message: "Please define VITE_KIZLO_API_URL in your .env file." });
11
+ const baseUrl = process.env.VITE_KIZLO_BASE_URL?.trim();
12
+ if (!baseUrl) throw new KizloError("MISSING_ENV_VARIABLE", { message: "Please define VITE_KIZLO_BASE_URL in your .env file." });
13
13
  return baseUrl;
14
14
  }
15
15
 
package/dist/kizlo.d.ts CHANGED
@@ -1,77 +1,49 @@
1
1
  import { WordPressCredentials } from "./wordpress/types.js";
2
2
  import "./wordpress/index.js";
3
- import { AuthAdapter } from "./adapters/auth.js";
4
- import { CaptchaAdapter } from "./adapters/captcha.js";
5
- import { CookiesAdapter } from "./shared/types.js";
6
- import { GeoAdapter } from "./adapters/geo.js";
7
- import { Environment, LoggerAdapter } from "./adapters/logger.js";
3
+ import { LogLevel } from "./adapters/logger.js";
8
4
  import { Context } from "./context.js";
9
- import { RouterMap } from "./router.js";
10
- import { AnyExtension, InferExtensionRouter } from "./shared/extension.js";
5
+ import { CoreProcedures } from "./procedures.js";
6
+ import { AnyIntegration, EnvReader, InferIntegrationProcedures } from "./shared/integration.js";
11
7
  import { ResultClient } from "./shared/result.js";
12
8
 
13
9
  //#region src/kizlo.d.ts
14
10
  type AnyKizloConfig = KizloConfig<any>;
15
- /**
16
- * Which credential set to read from the environment. Independent of `environment`
17
- * (which carries logging semantics off `NODE_ENV`): `"local"` reads the `KIZLO_LOCAL_WP_*`
18
- * / `KIZLO_LOCAL_WP_SECRET` keys local WordPress manages, `"remote"` reads `KIZLO_WP_*` / `KIZLO_WP_SECRET`.
19
- */
20
- type KizloConnect = "local" | "remote";
21
- interface KizloConfig<TExts extends readonly AnyExtension[]> {
11
+ interface KizloConfig<TIntegrations extends readonly AnyIntegration[]> {
22
12
  baseUrl: string;
23
13
  siteSecret: string;
24
- extensions?: TExts;
25
- environment: Environment;
26
- connect: KizloConnect;
27
- adapters?: ServiceAdapters;
14
+ integrations?: TIntegrations;
15
+ logging?: false | LogLevel;
28
16
  credentials: WordPressCredentials;
29
17
  wordpressEndpoints?: object;
30
18
  }
31
- interface ServiceAdapters {
32
- geo?: GeoAdapter;
33
- auth?: AuthAdapter;
34
- logger?: LoggerAdapter;
35
- captcha?: CaptchaAdapter;
36
- cookies?: CookiesAdapter;
37
- }
38
- type RootRouter<TExts extends readonly AnyExtension[]> = InferExtensionRouter<TExts> & RouterMap;
39
- type S2SClient<TExts extends readonly AnyExtension[]> = ResultClient<RootRouter<TExts>>;
40
- declare class Kizlo<TExts extends readonly AnyExtension[] = []> {
19
+ type RootProcedures<TIntegrations extends readonly AnyIntegration[]> = InferIntegrationProcedures<TIntegrations> & CoreProcedures;
20
+ type S2SClient<TIntegrations extends readonly AnyIntegration[]> = ResultClient<RootProcedures<TIntegrations>>;
21
+ declare class Kizlo<TIntegrations extends readonly AnyIntegration[] = []> {
41
22
  readonly context: Context;
42
- readonly client: S2SClient<TExts>;
43
- readonly router: RootRouter<TExts>;
23
+ readonly client: S2SClient<TIntegrations>;
24
+ readonly procedures: RootProcedures<TIntegrations>;
44
25
  private readonly remoteHandler;
45
26
  private readonly openapiHandler;
46
27
  private readonly config;
47
- constructor(config: KizloConfig<TExts>);
28
+ constructor(config: KizloConfig<TIntegrations>);
48
29
  handler(request: Request): Promise<Response>;
49
30
  private errorInterceptor;
50
31
  private checkInvocationScope;
51
- private registerExtensions;
32
+ private registerIntegrations;
52
33
  }
53
- interface CreateKizloOptions<TExts extends readonly AnyExtension[] = []> {
54
- /** Public base URL of your Kizlo server, used to route requests. Falls back to the `KIZLO_API_URL` env var. */
34
+ interface CreateKizloOptions<TIntegrations extends readonly AnyIntegration[] = []> {
35
+ /** Public base URL of your Kizlo server. Falls back to the `baseUrl` value contributed by an integration. */
55
36
  baseUrl?: string;
56
- /** Secret shared with the WordPress plugin to sign and verify webhooks. Falls back to the `KIZLO_WP_SECRET` env var (connect-selected). */
37
+ /** Secret shared with WordPress. Falls back to the `siteSecret` value contributed by an integration. */
57
38
  siteSecret?: string;
58
- /** Extensions to register, built with `createExtension` — mounts their namespaces on the client and their routes and event handlers on the handler. */
59
- extensions?: TExts;
60
- /** Runtime environment. Falls back to `NODE_ENV`, then `"development"`. */
61
- environment?: Environment;
62
- /**
63
- * Which credential set to use. Falls back to the `KIZLO_CONNECT` env var, then `"remote"`.
64
- * Independent of `environment`: `"local"` reads `KIZLO_LOCAL_WP_*` / `KIZLO_LOCAL_WP_SECRET` (the keys
65
- * local WordPress manages), `"remote"` reads `KIZLO_WP_*` / `KIZLO_WP_SECRET`.
66
- */
67
- connect?: KizloConnect;
68
- /** Service adapters: auth, captcha, geo, logger, and cookies. */
69
- adapters?: ServiceAdapters;
39
+ /** Integrations to compose, built with `createIntegration`. */
40
+ integrations?: TIntegrations;
41
+ /** Enable Kizlo's built-in console logger at this level. */
42
+ logging?: false | LogLevel;
70
43
  /**
71
- * The generated endpoints to run against WordPress, plus the connection to run them on. Pass the
72
- * `endpoints` export of your generated barrel. Each credential falls back to a connect-selected
73
- * env var: with the default `"remote"` connect to `KIZLO_WP_URL` / `KIZLO_WP_USERNAME` /
74
- * `KIZLO_WP_APP_PASSWORD`, and with the `"local"` connect to their `KIZLO_LOCAL_WP_*` counterparts.
44
+ * The generated endpoints to run against WordPress, plus optional explicit credentials. Pass the
45
+ * `endpoints` export of your generated barrel. Missing credentials fall back to the `wordpressUrl`,
46
+ * `wordpressUsername`, and `wordpressPassword` values contributed by integrations.
75
47
  */
76
48
  wordpress?: {
77
49
  endpoints?: object;
@@ -79,30 +51,21 @@ interface CreateKizloOptions<TExts extends readonly AnyExtension[] = []> {
79
51
  };
80
52
  }
81
53
  /**
82
- * Reads a single environment variable by name. Defaults to `process.env`, but framework factories can
83
- * pass their own source: the Astro factory hands in `getSecret` from `astro:env/server`, so `.env` is
84
- * resolved the Astro-native way (through the dev server / adapter) rather than through `process.env`.
54
+ * Compose environment sources without letting `undefined` erase an earlier value, then resolve
55
+ * Kizlo's active WordPress connection from the canonical `mode` value.
85
56
  */
86
- type EnvReader = (name: string) => string | undefined;
87
- declare function resolveWordPressConnection(options: Pick<CreateKizloOptions, "connect" | "wordpress"> | undefined, env?: EnvReader): {
88
- connect: KizloConnect;
57
+ declare function integrationEnv(integrations: readonly AnyIntegration[]): EnvReader;
58
+ declare function resolveWordPressConnection(options: Pick<CreateKizloOptions, "wordpress"> | undefined, env: EnvReader): {
89
59
  credentials: WordPressCredentials;
90
60
  };
91
61
  /**
92
- * Resolves a full `KizloConfig` from options and the environment. Shared by the
93
- * base `createKizlo` and each framework factory — the single place env values
94
- * and credentials are read. `baseUrlEnvKey` is the only framework-varying part.
62
+ * Resolves a full `KizloConfig` from explicit options and the composed integration environment.
95
63
  */
96
- declare function resolveKizloConfig<TExts extends readonly AnyExtension[]>(options: CreateKizloOptions<TExts> | undefined, defaults: {
97
- baseUrlEnvKey: string;
98
- adapters?: ServiceAdapters;
99
- env?: EnvReader;
100
- }): KizloConfig<TExts>;
64
+ declare function resolveKizloConfig<TIntegrations extends readonly AnyIntegration[]>(options: CreateKizloOptions<TIntegrations> | undefined): KizloConfig<TIntegrations>;
101
65
  /**
102
- * Creates a Kizlo server from the environment (`KIZLO_API_URL`, `KIZLO_WP_SECRET`,
103
- * `KIZLO_WP_*`), with options taking precedence. Framework packages wrap this
104
- * with their own URL convention and adapters.
66
+ * Creates a Kizlo server from integration-contributed environment values, with explicit options
67
+ * taking precedence.
105
68
  */
106
- declare function createKizlo<TExts extends readonly AnyExtension[] = []>(options?: CreateKizloOptions<TExts>): Kizlo<TExts>;
69
+ declare function createKizlo<TIntegrations extends readonly AnyIntegration[] = []>(options?: CreateKizloOptions<TIntegrations>): Kizlo<TIntegrations>;
107
70
  //#endregion
108
- export { AnyKizloConfig, CreateKizloOptions, EnvReader, Kizlo, KizloConfig, KizloConnect, RootRouter, S2SClient, ServiceAdapters, createKizlo, resolveKizloConfig, resolveWordPressConnection };
71
+ export { AnyKizloConfig, CreateKizloOptions, Kizlo, KizloConfig, RootProcedures, S2SClient, createKizlo, integrationEnv, resolveKizloConfig, resolveWordPressConnection };
package/dist/kizlo.js CHANGED
@@ -1,11 +1,14 @@
1
- import { CONTRACT_GENERATION_ENV, RPC_PROTOCOL_HEADER } from "./shared/constants.js";
1
+ import { consoleLog } from "./adapters/logger.js";
2
+ import { mergeServiceAdapters } from "./adapters/types.js";
3
+ import { RPC_PROTOCOL_HEADER } from "./shared/constants.js";
2
4
  import { KizloError } from "./shared/error.js";
3
5
  import { createOrpcRouter } from "./shared/router.js";
4
6
  import { createResultClient } from "./shared/result.js";
5
7
  import { isTypescriptObject } from "./shared/utils.js";
6
8
  import { Context } from "./context.js";
7
- import { ROUTER_MAP } from "./router.js";
8
- import { assertExtensionEndpoints } from "./shared/extension.js";
9
+ import { CORE_PROCEDURES } from "./procedures.js";
10
+ import { isContractGeneration } from "./shared/contract-generation.js";
11
+ import { assertIntegrationEndpoints, assertIntegrationEnv, readEnv } from "./shared/integration.js";
9
12
  import { createWebhookRouter } from "./webhook/index.js";
10
13
  import { tryCatch } from "@kizlo/shared";
11
14
  import { ORPCError, createRouterClient } from "@orpc/server";
@@ -16,25 +19,25 @@ import { RPCHandler } from "@orpc/server/fetch";
16
19
  var Kizlo = class {
17
20
  context;
18
21
  client;
19
- router;
22
+ procedures;
20
23
  remoteHandler;
21
24
  openapiHandler;
22
25
  config;
23
26
  constructor(config) {
24
27
  this.config = config;
25
- const extensions = this.registerExtensions();
28
+ const integrations = this.registerIntegrations();
26
29
  this.context = new Context({
27
- adapters: config.adapters,
30
+ adapters: integrations.adapters,
28
31
  siteSecret: config.siteSecret,
29
32
  credentials: config.credentials,
30
33
  wordpressEndpoints: config.wordpressEndpoints,
31
- extensionPlugins: extensions.plugins
34
+ integrationPlugins: integrations.plugins
32
35
  });
33
- this.router = Object.assign(Object.assign({}, {
34
- ...extensions.router,
35
- ...ROUTER_MAP
36
- }), { webhooks: createWebhookRouter({ events: extensions.events }) });
37
- const orpcRouter = createOrpcRouter(this.router);
36
+ this.procedures = Object.assign(Object.assign({}, {
37
+ ...integrations.procedures,
38
+ ...CORE_PROCEDURES
39
+ }), { webhooks: createWebhookRouter({ events: integrations.events }) });
40
+ const orpcRouter = createOrpcRouter(this.procedures);
38
41
  this.client = createResultClient(createRouterClient(orpcRouter, { context: () => this.context.createServerContext() }));
39
42
  this.remoteHandler = new RPCHandler(orpcRouter, {
40
43
  filter: (options) => {
@@ -90,93 +93,106 @@ var Kizlo = class {
90
93
  checkInvocationScope(value, scope) {
91
94
  return isTypescriptObject(value) && "scope" in value && value.scope === scope;
92
95
  }
93
- registerExtensions() {
94
- const router = {};
96
+ registerIntegrations() {
97
+ const procedures = {};
95
98
  const events = [];
96
99
  const plugins = [];
97
- const generating = Boolean(process.env[CONTRACT_GENERATION_ENV]);
98
- for (const extension of this.config.extensions ?? []) {
99
- if (!generating) assertExtensionEndpoints(extension, this.config.wordpressEndpoints ?? {});
100
- if (extension.requires?.plugin) plugins.push(extension.requires.plugin);
101
- const data = extension.init({ context: { something: "" } });
102
- if (data.router) router[extension.id] = data.router;
103
- for (const handler of data.events ?? []) events.push(handler);
100
+ let adapters = mergeServiceAdapters(this.config.logging ? { logger: consoleLog({ levels: levelsFrom(this.config.logging) }) } : void 0);
101
+ const reservedIds = new Set([...Object.keys(CORE_PROCEDURES), "webhooks"]);
102
+ const integrationIds = /* @__PURE__ */ new Set();
103
+ const generating = isContractGeneration();
104
+ for (const integration of this.config.integrations ?? []) {
105
+ if (reservedIds.has(integration.id)) throw new KizloError("INTEGRATION_ID_CONFLICT", { message: `The integration id "${integration.id}" is reserved by Kizlo. Choose a different integration id.` });
106
+ if (integrationIds.has(integration.id)) throw new KizloError("INTEGRATION_ID_CONFLICT", { message: `The integration id "${integration.id}" is registered more than once. Give every integration a unique id.` });
107
+ integrationIds.add(integration.id);
108
+ if (!generating) assertIntegrationEndpoints(integration, this.config.wordpressEndpoints ?? {});
109
+ plugins.push(...integration.requires?.plugins ?? []);
110
+ if (integration.procedures && Object.keys(integration.procedures).length > 0) procedures[integration.id] = integration.procedures;
111
+ for (const handler of integration.events ?? []) events.push(handler);
112
+ adapters = mergeServiceAdapters(adapters, integration.adapters);
104
113
  }
105
114
  return {
115
+ adapters,
106
116
  events,
107
117
  plugins,
108
- router
118
+ procedures
109
119
  };
110
120
  }
111
121
  };
112
- const processEnvReader = (name) => process.env[name];
113
- function requireEnv(name, env) {
114
- const value = env(name)?.trim();
115
- if (value) return value;
116
- if (process.env[CONTRACT_GENERATION_ENV]) return "";
117
- throw new KizloError("MISSING_ENV_VARIABLE", { message: `Please define ${name} in your .env file.` });
122
+ const WORDPRESS_ENV_VALUES = new Set([
123
+ "siteSecret",
124
+ "wordpressUrl",
125
+ "wordpressUsername",
126
+ "wordpressPassword"
127
+ ]);
128
+ /**
129
+ * Compose environment sources without letting `undefined` erase an earlier value, then resolve
130
+ * Kizlo's active WordPress connection from the canonical `mode` value.
131
+ */
132
+ function integrationEnv(integrations) {
133
+ const composed = (name) => {
134
+ let value;
135
+ for (const integration of integrations) {
136
+ if (!integration.env) continue;
137
+ const contribution = readEnv(integration.env, name);
138
+ if (contribution !== void 0) value = contribution;
139
+ }
140
+ return value;
141
+ };
142
+ const mode = composed("mode")?.trim();
143
+ if (mode && mode !== "local" && mode !== "remote") throw new KizloError("INVALID_ENV_VALUE", { message: `The "mode" environment value must be "local" or "remote", got "${mode}".` });
144
+ const profile = mode === "local" ? "local" : "remote";
145
+ return (name) => {
146
+ return WORDPRESS_ENV_VALUES.has(name) ? composed(`${profile}.${name}`) : composed(name);
147
+ };
118
148
  }
119
- function resolveConnect(option, env) {
120
- if (option) return option;
121
- const value = env("KIZLO_CONNECT")?.trim();
122
- if (!value) return "remote";
123
- if (value !== "local" && value !== "remote") throw new KizloError("INVALID_ENV_VARIABLE", { message: `KIZLO_CONNECT must be "local" or "remote", got "${value}".` });
124
- return value;
149
+ function levelsFrom(level) {
150
+ const levels = [
151
+ "debug",
152
+ "info",
153
+ "warn",
154
+ "error"
155
+ ];
156
+ return levels.slice(levels.indexOf(level));
125
157
  }
126
- /** Env var names for a credential set: `KIZLO_LOCAL_WP_URL` / `KIZLO_LOCAL_WP_SECRET` for local, `KIZLO_WP_URL` / `KIZLO_WP_SECRET` for remote. */
127
- function connectEnvKeys(connect) {
128
- const prefix = connect === "local" ? "KIZLO_LOCAL_" : "KIZLO_";
129
- return {
130
- siteSecret: `${prefix}WP_SECRET`,
131
- url: `${prefix}WP_URL`,
132
- username: `${prefix}WP_USERNAME`,
133
- password: `${prefix}WP_APP_PASSWORD`
134
- };
158
+ function requireEnvValue(name, env) {
159
+ const value = env(name)?.trim();
160
+ if (value) return value;
161
+ if (isContractGeneration()) return "";
162
+ throw new KizloError("MISSING_ENV_VALUE", { message: `Kizlo requires the "${name}" environment value. Provide it through an integration or an explicit createKizlo option.` });
135
163
  }
136
- function resolveWordPressConnection(options, env = processEnvReader) {
164
+ function resolveWordPressConnection(options, env) {
137
165
  const credentials = options?.wordpress?.credentials;
138
- const connect = resolveConnect(options?.connect, env);
139
- const keys = connectEnvKeys(connect);
140
- return {
141
- connect,
142
- credentials: {
143
- url: credentials?.url ?? requireEnv(keys.url, env),
144
- username: credentials?.username ?? requireEnv(keys.username, env),
145
- password: credentials?.password ?? requireEnv(keys.password, env)
146
- }
147
- };
166
+ return { credentials: {
167
+ url: credentials?.url ?? requireEnvValue("wordpressUrl", env),
168
+ username: credentials?.username ?? requireEnvValue("wordpressUsername", env),
169
+ password: credentials?.password ?? requireEnvValue("wordpressPassword", env)
170
+ } };
148
171
  }
149
172
  /**
150
- * Resolves a full `KizloConfig` from options and the environment. Shared by the
151
- * base `createKizlo` and each framework factory — the single place env values
152
- * and credentials are read. `baseUrlEnvKey` is the only framework-varying part.
173
+ * Resolves a full `KizloConfig` from explicit options and the composed integration environment.
153
174
  */
154
- function resolveKizloConfig(options, defaults) {
155
- const env = defaults.env ?? processEnvReader;
156
- const { connect, credentials } = resolveWordPressConnection(options, env);
157
- const keys = connectEnvKeys(connect);
175
+ function resolveKizloConfig(options) {
176
+ const integrations = options?.integrations ?? [];
177
+ const env = integrationEnv(integrations);
178
+ if (!isContractGeneration()) for (const integration of integrations) assertIntegrationEnv(integration, env);
179
+ const { credentials } = resolveWordPressConnection(options, env);
158
180
  return {
159
- baseUrl: options?.baseUrl ?? requireEnv(defaults.baseUrlEnvKey, env),
160
- siteSecret: options?.siteSecret ?? requireEnv(keys.siteSecret, env),
161
- environment: options?.environment ?? process.env.NODE_ENV ?? "development",
162
- connect,
163
- extensions: options?.extensions,
164
- adapters: {
165
- ...defaults.adapters,
166
- ...options?.adapters
167
- },
181
+ baseUrl: options?.baseUrl ?? requireEnvValue("baseUrl", env),
182
+ siteSecret: options?.siteSecret ?? requireEnvValue("siteSecret", env),
183
+ integrations,
184
+ logging: options?.logging,
168
185
  credentials,
169
186
  wordpressEndpoints: options?.wordpress?.endpoints
170
187
  };
171
188
  }
172
189
  /**
173
- * Creates a Kizlo server from the environment (`KIZLO_API_URL`, `KIZLO_WP_SECRET`,
174
- * `KIZLO_WP_*`), with options taking precedence. Framework packages wrap this
175
- * with their own URL convention and adapters.
190
+ * Creates a Kizlo server from integration-contributed environment values, with explicit options
191
+ * taking precedence.
176
192
  */
177
193
  function createKizlo(options) {
178
- return new Kizlo(resolveKizloConfig(options, { baseUrlEnvKey: "KIZLO_API_URL" }));
194
+ return new Kizlo(resolveKizloConfig(options));
179
195
  }
180
196
 
181
197
  //#endregion
182
- export { Kizlo, createKizlo, resolveKizloConfig, resolveWordPressConnection };
198
+ export { Kizlo, createKizlo, integrationEnv, resolveKizloConfig, resolveWordPressConnection };
@@ -6,7 +6,7 @@ import { buildMenuGroupItem, deserializeListMenuInput, extractPath } from "./uti
6
6
  import { stringifiedMetaRecord } from "@kizlo/shared";
7
7
 
8
8
  //#region src/menu/index.ts
9
- const MENU_ROUTER_MAP = { items: {
9
+ const MENU_PROCEDURES = { items: {
10
10
  list: createProcedure({
11
11
  scope: "api",
12
12
  method: "GET",
@@ -86,4 +86,4 @@ const MENU_ROUTER_MAP = { items: {
86
86
  } };
87
87
 
88
88
  //#endregion
89
- export { MENU_ROUTER_MAP };
89
+ export { MENU_PROCEDURES };
@@ -2,10 +2,10 @@ 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 { NextRevalidateOptions, RevalidatePathFn, RevalidateTagFn, RevalidateTarget, nextRevalidation } from "../integrations/nextjs/revalidate.js";
5
- import { KizloServerOptions, createKizlo } from "../integrations/nextjs/kizlo.server.js";
5
+ import { NextjsOptions, nextjs } from "../integrations/nextjs/integration.js";
6
6
  import { MANIFEST_CACHE_TAG, createManifestRoute } from "../integrations/nextjs/manifest.js";
7
7
  import { createHomeMetadata, createPageMetadata, createRootMetadata, createRootViewport } from "../integrations/nextjs/metadata.js";
8
8
  import { ROBOTS_CACHE_TAG, createRobotsRoute } from "../integrations/nextjs/robots.js";
9
9
  import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
10
10
  import { createCachedTextRoute, createNextCookiesInterface, getServerBaseUrl } from "../integrations/nextjs/utils.js";
11
- export { KizloServerOptions, MANIFEST_CACHE_TAG, NextRevalidateOptions, ROBOTS_CACHE_TAG, RevalidatePathFn, RevalidateTagFn, RevalidateTarget, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createKizlo, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, renderJsonLd };
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 };
@@ -5,8 +5,8 @@ import { createCachedTextRoute, createNextCookiesInterface, getServerBaseUrl } f
5
5
  import { ROBOTS_CACHE_TAG, createRobotsRoute } from "../integrations/nextjs/robots.js";
6
6
  import { SITEMAP_CACHE_TAG, SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
7
7
  import { nextRevalidation } from "../integrations/nextjs/revalidate.js";
8
- import { createKizlo } from "../integrations/nextjs/kizlo.server.js";
8
+ import { nextjs } from "../integrations/nextjs/integration.js";
9
9
  import { MANIFEST_CACHE_TAG, createManifestRoute } from "../integrations/nextjs/manifest.js";
10
10
  import { createHomeMetadata, createPageMetadata, createRootMetadata, createRootViewport } from "../integrations/nextjs/metadata.js";
11
11
 
12
- export { MANIFEST_CACHE_TAG, ROBOTS_CACHE_TAG, SITEMAP_CACHE_TAG, SITEMAP_ROUTE, WEB_MANIFEST_ROUTE, createCachedTextRoute, createHomeMetadata, createKizlo, createManifestRoute, createNextCookiesInterface, createPageMetadata, createRobotsRoute, createRootMetadata, createRootViewport, createSitemapRedirectRoute, createSitemapRoute, getServerBaseUrl, nextRevalidation, renderJsonLd };
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 };
package/dist/node.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { NodeOptions, node } from "./integrations/node/integration.js";
2
+ export { NodeOptions, node };
package/dist/node.js ADDED
@@ -0,0 +1,3 @@
1
+ import { node } from "./integrations/node/integration.js";
2
+
3
+ export { node };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.15.2";
2
+ var version = "0.17.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -8,7 +8,7 @@ import { deserializePage } from "./utils.js";
8
8
  import { normalizeArrayableValue } from "@kizlo/shared";
9
9
 
10
10
  //#region src/page/index.ts
11
- const PAGE_ROUTER_MAP = {
11
+ const PAGE_PROCEDURES = {
12
12
  get: createProcedure({
13
13
  scope: "api",
14
14
  method: "GET",
@@ -120,4 +120,4 @@ const PAGE_ROUTER_MAP = {
120
120
  };
121
121
 
122
122
  //#endregion
123
- export { PAGE_ROUTER_MAP };
123
+ export { PAGE_PROCEDURES };
@@ -1,6 +1,6 @@
1
- import { IdentifierInput, ListMetadata, ListOrder } from "../shared/schema.js";
1
+ import { IdentifierInput, ListMetadata, ListOrder, customFieldsSchema } from "../shared/schema.js";
2
2
  import { Seo } from "../seo/schema.js";
3
- import { Media, Metadata, NumberLike, arrayable, lenient } from "@kizlo/shared";
3
+ import { MediaImage, Metadata, NumberLike, arrayable, lenient } from "@kizlo/shared";
4
4
  import z from "zod/v4";
5
5
 
6
6
  //#region src/page/schema.ts
@@ -30,7 +30,7 @@ const PageAuthorRef = z.object({
30
30
  id: z.number(),
31
31
  name: z.string(),
32
32
  slug: z.string(),
33
- avatar: Media.nullable()
33
+ avatarUrl: z.string().nullable()
34
34
  });
35
35
  const Page = z.object({
36
36
  id: z.number(),
@@ -47,8 +47,9 @@ const Page = z.object({
47
47
  preview: z.boolean(),
48
48
  status: PageStatus,
49
49
  author: PageAuthorRef.nullable(),
50
- featuredMedia: Media.nullable(),
50
+ featuredMedia: MediaImage.nullable(),
51
51
  seo: Seo.nullable(),
52
+ custom: customFieldsSchema(),
52
53
  createdAt: z.number(),
53
54
  updatedAt: z.number(),
54
55
  meta: Metadata
@@ -1,6 +1,6 @@
1
1
  import { deserializeSeo } from "../seo/utils.js";
2
2
  import { publicPostStatus } from "../post-type/status.js";
3
- import { resolveWpTimestamp, stringifiedMetaRecord } from "@kizlo/shared";
3
+ import { stringifiedMetaRecord, timestampFromWpGmt } from "@kizlo/shared";
4
4
 
5
5
  //#region src/page/utils.ts
6
6
  function deserializePage(data, options) {
@@ -26,16 +26,12 @@ function deserializePage(data, options) {
26
26
  id: kizlo.author.id,
27
27
  name: kizlo.author.name,
28
28
  slug: kizlo.author.slug,
29
- avatar: kizlo.author.avatar_url ? {
30
- id: 0,
31
- alt: kizlo.author.name,
32
- name: kizlo.author.name,
33
- src: kizlo.author.avatar_url
34
- } : null
29
+ avatarUrl: kizlo.author.avatar_url || null
35
30
  } : null,
36
31
  seo: "seo" in kizlo ? deserializeSeo(kizlo.seo) : null,
37
- createdAt: resolveWpTimestamp(data.date_gmt) ?? resolveWpTimestamp(data.modified_gmt) ?? 0,
38
- updatedAt: resolveWpTimestamp(data.modified_gmt) ?? 0,
32
+ custom: kizlo.custom,
33
+ createdAt: timestampFromWpGmt(data.date_gmt) ?? timestampFromWpGmt(data.modified_gmt) ?? 0,
34
+ updatedAt: timestampFromWpGmt(data.modified_gmt) ?? 0,
39
35
  meta: stringifiedMetaRecord(data.meta)
40
36
  };
41
37
  }
@@ -8,7 +8,7 @@ import { deserializePost } from "./utils.js";
8
8
  import { normalizeArrayableValue } from "@kizlo/shared";
9
9
 
10
10
  //#region src/post/index.ts
11
- const POST_ROUTER_MAP = {
11
+ const POST_PROCEDURES = {
12
12
  get: createProcedure({
13
13
  scope: "api",
14
14
  method: "GET",
@@ -123,4 +123,4 @@ const POST_ROUTER_MAP = {
123
123
  };
124
124
 
125
125
  //#endregion
126
- export { POST_ROUTER_MAP };
126
+ export { POST_PROCEDURES };
@@ -1,6 +1,6 @@
1
- import { IdentifierInput, ListMetadata, ListOrder } from "../shared/schema.js";
1
+ import { IdentifierInput, ListMetadata, ListOrder, customFieldsSchema } from "../shared/schema.js";
2
2
  import { Seo } from "../seo/schema.js";
3
- import { BooleanLike, Media, Metadata, NumberLike, arrayable, lenient } from "@kizlo/shared";
3
+ import { BooleanLike, MediaImage, Metadata, NumberLike, arrayable, lenient } from "@kizlo/shared";
4
4
  import z from "zod/v4";
5
5
 
6
6
  //#region src/post/schema.ts
@@ -43,7 +43,7 @@ const PostAuthorRef = z.object({
43
43
  id: z.number(),
44
44
  name: z.string(),
45
45
  slug: z.string(),
46
- avatar: Media.nullable()
46
+ avatarUrl: z.string().nullable()
47
47
  });
48
48
  const PostCategoryRef = z.object({
49
49
  id: z.number(),
@@ -70,10 +70,11 @@ const Post = z.object({
70
70
  format: PostTypeFormat,
71
71
  sticky: z.boolean(),
72
72
  author: PostAuthorRef.nullable(),
73
- featuredMedia: Media.nullable(),
73
+ featuredMedia: MediaImage.nullable(),
74
74
  categories: z.array(PostCategoryRef),
75
75
  tags: z.array(PostTagRef),
76
76
  seo: Seo.nullable(),
77
+ custom: customFieldsSchema(),
77
78
  createdAt: z.number(),
78
79
  updatedAt: z.number(),
79
80
  meta: Metadata
@@ -1,6 +1,6 @@
1
1
  import { deserializeSeo } from "../seo/utils.js";
2
2
  import { publicPostStatus } from "../post-type/status.js";
3
- import { resolveWpTimestamp, stringifiedMetaRecord } from "@kizlo/shared";
3
+ import { stringifiedMetaRecord, timestampFromWpGmt } from "@kizlo/shared";
4
4
 
5
5
  //#region src/post/utils.ts
6
6
  function deserializePost(data, options) {
@@ -27,17 +27,13 @@ function deserializePost(data, options) {
27
27
  id: kizlo.author.id,
28
28
  name: kizlo.author.name,
29
29
  slug: kizlo.author.slug,
30
- avatar: kizlo.author.avatar_url ? {
31
- id: 0,
32
- alt: kizlo.author.name,
33
- name: kizlo.author.name,
34
- src: kizlo.author.avatar_url
35
- } : null
30
+ avatarUrl: kizlo.author.avatar_url || null
36
31
  } : null,
37
32
  format: data.format,
38
33
  seo: "seo" in kizlo ? deserializeSeo(kizlo.seo) : null,
39
- createdAt: resolveWpTimestamp(data.date_gmt) ?? resolveWpTimestamp(data.modified_gmt) ?? 0,
40
- updatedAt: resolveWpTimestamp(data.modified_gmt) ?? 0,
34
+ custom: kizlo.custom,
35
+ createdAt: timestampFromWpGmt(data.date_gmt) ?? timestampFromWpGmt(data.modified_gmt) ?? 0,
36
+ updatedAt: timestampFromWpGmt(data.modified_gmt) ?? 0,
41
37
  meta: stringifiedMetaRecord(data.meta)
42
38
  };
43
39
  }