kizlo 0.2.0 → 0.2.1

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
@@ -41,7 +41,7 @@ Kizlo is a framework-agnostic toolkit for headless WordPress, built for a stack
41
41
  Set up Kizlo in your project:
42
42
 
43
43
  ```bash
44
- npx kizlo init
44
+ npx kizlo@latest init
45
45
  ```
46
46
 
47
47
  Watch your extensions and regenerate the contract during development:
@@ -2,6 +2,7 @@ import { createStack } from "../wp/docker.js";
2
2
  import { ensureGitignored, envGroups, getVersion, groupDefault, mergeEnv, pickStackPort, withSpinner } from "../utils.js";
3
3
  import { palette, printBanner } from "../banner.js";
4
4
  import { resolveDevConfig } from "../daemon/config.js";
5
+ import { startWatcher } from "../daemon/watch.js";
5
6
  import { bootstrapDev } from "../wp/dev.js";
6
7
  import { reapOrphans, registerSession, removeProjectContainers, spawnWatchdog, unregisterSession } from "../wp/session.js";
7
8
  import { syncSiteSettings } from "../wp/settings.js";
@@ -195,6 +196,8 @@ async function startForeground(cfg) {
195
196
  const took = ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
196
197
  process.stdout.write(`\n ${dim}Press ${reset}${bold}Ctrl+C${reset}${dim} (or close the terminal) to stop the development stack${reset}\n`);
197
198
  process.stdout.write(`\n ${green}✓${reset} Ready in ${took}\n\n`);
199
+ const stopWatcher = await startWatcher(ready.configDir);
200
+ if (stopWatcher) process.on("exit", stopWatcher);
198
201
  setInterval(() => {}, 1 << 30);
199
202
  await new Promise(() => {});
200
203
  }
@@ -2,12 +2,12 @@ import { composeStop, createStack, dockerAvailable } from "../wp/docker.js";
2
2
  import { addDependencyArgs, detectImportAlias, detectPackageManager, ensureGitignored, envGroups, envKeysPresent, getVersion, loadEnvFiles, mergeEnv, pickStackPort, resolveModuleImport, runCommand, writeFileIfAbsent } from "../utils.js";
3
3
  import { printBanner } from "../banner.js";
4
4
  import { DEFAULT_DEV_DB_PORT, DEFAULT_DEV_PORT, resolveStackName } from "../daemon/config.js";
5
+ import { CONTRACT_BARREL } from "../daemon/generate.js";
5
6
  import { createAdminAppPassword } from "../wp/bootstrap.js";
6
7
  import { bootstrapDev } from "../wp/dev.js";
7
8
  import { removeProjectContainers } from "../wp/session.js";
8
9
  import { syncSiteSettings } from "../wp/settings.js";
9
10
  import { devStack } from "../wp/stack.js";
10
- import { CONTRACT_BARREL } from "../daemon/generate.js";
11
11
  import { PRESETS, detectPreset, getPreset } from "../presets/index.js";
12
12
  import z from "zod/v4";
13
13
  import { randomBytes } from "node:crypto";
@@ -375,9 +375,9 @@ const init = defineCommand({
375
375
  if (!hasKizlo) {
376
376
  const s = p.spinner();
377
377
  s.start(`Installing kizlo with ${pm}`);
378
- const ok = runCommand(addDependencyArgs(pm, "kizlo"), cwd, "ignore");
378
+ const ok = runCommand(addDependencyArgs(pm, "kizlo@latest"), cwd, "ignore");
379
379
  s.stop(ok ? "Installed kizlo" : "Could not install kizlo automatically");
380
- if (!ok) p.log.warn(`Install it yourself: ${addDependencyArgs(pm, "kizlo").join(" ")}`);
380
+ if (!ok) p.log.warn(`Install it yourself: ${addDependencyArgs(pm, "kizlo@latest").join(" ")}`);
381
381
  }
382
382
  if (preset.apiPath && setup.baseUrl) setup.baseUrl = withApiPath(setup.baseUrl, preset.apiPath);
383
383
  let adminPassword;
@@ -487,13 +487,14 @@ const init = defineCommand({
487
487
  }
488
488
  p.note([
489
489
  ...setup.mode === "local" ? [
490
- `Start your local WordPress dev stack:`,
490
+ `Start your local WordPress dev stack (also watches your extensions):`,
491
491
  ` npx kizlo dev`,
492
492
  ``
493
- ] : [],
494
- `Watch your extensions and regenerate the contract during development:`,
495
- ` npx kizlo watch`,
496
- ``,
493
+ ] : [
494
+ `Watch your extensions and regenerate the contract during development:`,
495
+ ` npx kizlo watch`,
496
+ ``
497
+ ],
497
498
  `Generate the contract once for production builds:`,
498
499
  ` npx kizlo generate`
499
500
  ].join("\n"), "Next steps");
@@ -1,10 +1,6 @@
1
- import { log } from "../daemon/logger.js";
2
1
  import { getVersion } from "../utils.js";
3
2
  import { printBanner } from "../banner.js";
4
- import { resolveConfig } from "../daemon/config.js";
5
- import { generateOnce } from "../daemon/generate.js";
6
- import { acquire, isLocked, lockPath, release } from "../daemon/lock.js";
7
- import { watch as watch$1 } from "../daemon/watch.js";
3
+ import { startWatcher } from "../daemon/watch.js";
8
4
  import { defineCommand } from "citty";
9
5
 
10
6
  //#region src/cli/commands/watch.ts
@@ -13,32 +9,18 @@ const args = { dir: {
13
9
  description: "Override the Kizlo directory (defaults to kizlo.config.ts)"
14
10
  } };
15
11
  async function run({ args: args$1 }) {
16
- const cwd = process.cwd();
17
- const lock = lockPath(cwd);
18
- if (isLocked(lock)) {
19
- log.info("Watcher already running — nothing to do.");
20
- return;
21
- }
22
12
  printBanner(getVersion());
23
- const cfg = await resolveConfig(cwd, { dir: args$1.dir });
24
- acquire(lock);
25
- const cleanup = () => release(lock);
26
- process.on("exit", cleanup);
13
+ const stop = await startWatcher(process.cwd(), { dir: args$1.dir });
14
+ if (!stop) return;
15
+ process.on("exit", stop);
27
16
  for (const signal of [
28
17
  "SIGINT",
29
18
  "SIGTERM",
30
19
  "SIGHUP"
31
20
  ]) process.on(signal, () => {
32
- cleanup();
21
+ stop();
33
22
  process.exit(0);
34
23
  });
35
- try {
36
- if (await generateOnce(cfg)) log.success("Contract generated");
37
- else log.warn(`No Kizlo server found in ${cfg.serverEntry}`);
38
- } catch (error) {
39
- log.error("Failed to generate the Kizlo contract:", error);
40
- }
41
- await watch$1(cfg);
42
24
  }
43
25
  const watch = defineCommand({
44
26
  meta: {
@@ -3,6 +3,7 @@ import { consola } from "consola";
3
3
  //#region src/cli/daemon/logger.ts
4
4
  /** Tagged logger for the daemon — every line is prefixed with `kizlo`. */
5
5
  const log = consola.withTag("kizlo");
6
+ log.options.formatOptions.date = false;
6
7
 
7
8
  //#endregion
8
9
  export { log };
@@ -1,5 +1,7 @@
1
1
  import { log } from "./logger.js";
2
+ import { resolveConfig } from "./config.js";
2
3
  import { generateOnce } from "./generate.js";
4
+ import { acquire, isLocked, lockPath, release } from "./lock.js";
3
5
  import path from "node:path";
4
6
  import { FSWatcher } from "chokidar";
5
7
 
@@ -28,10 +30,41 @@ async function watch(cfg) {
28
30
  });
29
31
  const onChange = debounce(() => regenerate(cfg), 300);
30
32
  watcher.add(path.resolve(cfg.cwd, cfg.serverDir));
31
- watcher.on("ready", () => log.start("Watching for changes..."));
33
+ watcher.on("ready", () => log.start("Watching for contract changes..."));
32
34
  watcher.on("all", () => void onChange());
33
35
  return watcher;
34
36
  }
37
+ /**
38
+ * Acquire the single-instance lock, generate the contract once, and start the file
39
+ * watcher. Returns a synchronous `stop()` that closes the watcher and releases the
40
+ * lock — or `undefined` when another watcher already holds the lock (a standalone
41
+ * `kizlo watch`, or a framework dev script), in which case the caller carries on
42
+ * without watching. Shared by the standalone `kizlo watch` command and the
43
+ * folded-in watcher of `kizlo dev`, so a single terminal covers both.
44
+ */
45
+ async function startWatcher(cwd, opts) {
46
+ const lock = lockPath(cwd);
47
+ if (isLocked(lock)) {
48
+ log.info("Watcher already running — skipping the contract watcher.");
49
+ return;
50
+ }
51
+ const cfg = await resolveConfig(cwd, { dir: opts?.dir });
52
+ acquire(lock);
53
+ try {
54
+ if (await generateOnce(cfg)) log.success("Contract generated");
55
+ else log.warn(`No Kizlo server found in ${cfg.serverEntry}`);
56
+ } catch (error) {
57
+ log.error("Failed to generate the Kizlo contract:", error);
58
+ }
59
+ const watcher = await watch(cfg);
60
+ let stopped = false;
61
+ return () => {
62
+ if (stopped) return;
63
+ stopped = true;
64
+ release(lock);
65
+ watcher.close();
66
+ };
67
+ }
35
68
 
36
69
  //#endregion
37
- export { watch };
70
+ export { startWatcher };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.2.0";
2
+ var version = "0.2.1";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/dist/router.d.ts CHANGED
@@ -21,7 +21,7 @@ declare const ROUTER_MAP: {
21
21
  excerpt: string | null;
22
22
  commentsEnabled: boolean;
23
23
  protected: boolean;
24
- format: "standard" | "aside" | "chat" | "gallery" | "link" | "image" | "quote" | "status" | "video" | "audio";
24
+ format: "image" | "link" | "standard" | "aside" | "chat" | "gallery" | "quote" | "status" | "video" | "audio";
25
25
  sticky: boolean;
26
26
  author: {
27
27
  id: number;
@@ -150,7 +150,7 @@ declare const ROUTER_MAP: {
150
150
  include?: string | number | (string | number)[] | undefined;
151
151
  offset?: string | number | undefined;
152
152
  order?: "asc" | "desc" | undefined;
153
- orderby?: "date" | "id" | "slug" | "title" | "author" | "include" | "parent" | "relevance" | "include_slugs" | undefined;
153
+ orderby?: "title" | "author" | "date" | "id" | "parent" | "slug" | "include" | "relevance" | "include_slugs" | undefined;
154
154
  searchColumns?: string[] | undefined;
155
155
  slug?: string | string[] | undefined;
156
156
  taxRelation?: "AND" | "OR" | undefined;
@@ -169,7 +169,7 @@ declare const ROUTER_MAP: {
169
169
  excerpt: string | null;
170
170
  commentsEnabled: boolean;
171
171
  protected: boolean;
172
- format: "standard" | "aside" | "chat" | "gallery" | "link" | "image" | "quote" | "status" | "video" | "audio";
172
+ format: "image" | "link" | "standard" | "aside" | "chat" | "gallery" | "quote" | "status" | "video" | "audio";
173
173
  sticky: boolean;
174
174
  author: {
175
175
  id: number;
@@ -342,7 +342,7 @@ declare const ROUTER_MAP: {
342
342
  include?: string | number | (string | number)[] | undefined;
343
343
  offset?: string | number | undefined;
344
344
  order?: "asc" | "desc" | undefined;
345
- orderby?: "date" | "id" | "slug" | "title" | "author" | "include" | "parent" | "relevance" | "include_slugs" | "menu_order" | undefined;
345
+ orderby?: "title" | "author" | "date" | "id" | "parent" | "slug" | "include" | "relevance" | "include_slugs" | "menu_order" | undefined;
346
346
  searchColumns?: string[] | undefined;
347
347
  slug?: string | string[] | undefined;
348
348
  taxRelation?: "AND" | "OR" | undefined;
@@ -355,7 +355,7 @@ declare const ROUTER_MAP: {
355
355
  id: number;
356
356
  href: string;
357
357
  name: string;
358
- type: "custom" | "post" | "page" | "category" | "product" | "product_cat" | "product_tag";
358
+ type: "custom" | "page" | "post" | "category" | "product" | "product_cat" | "product_tag";
359
359
  description: string;
360
360
  meta: {
361
361
  [x: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
@@ -413,7 +413,7 @@ declare const ROUTER_MAP: {
413
413
  include?: string | number | (string | number)[] | undefined;
414
414
  offset?: string | number | undefined;
415
415
  order?: "asc" | "desc" | undefined;
416
- orderby?: "date" | "id" | "slug" | "title" | "author" | "include" | "parent" | "relevance" | "include_slugs" | "menu_order" | undefined;
416
+ orderby?: "title" | "author" | "date" | "id" | "parent" | "slug" | "include" | "relevance" | "include_slugs" | "menu_order" | undefined;
417
417
  searchColumns?: string[] | undefined;
418
418
  slug?: string | string[] | undefined;
419
419
  taxRelation?: "AND" | "OR" | undefined;
@@ -503,7 +503,7 @@ declare const ROUTER_MAP: {
503
503
  include?: string | number | (string | number)[] | undefined;
504
504
  offset?: string | number | undefined;
505
505
  order?: "asc" | "desc" | undefined;
506
- orderby?: "date" | "id" | "post" | "include" | "parent" | undefined;
506
+ orderby?: "date" | "id" | "parent" | "post" | "include" | undefined;
507
507
  parent?: string | number | (string | number)[] | undefined;
508
508
  parentExclude?: string | number | (string | number)[] | undefined;
509
509
  post?: string | number | (string | number)[] | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kizlo",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "A headless WordPress toolkit for TypeScript.",
6
6
  "keywords": [