kizlo 0.2.0 → 0.2.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 +8 -12
- package/dist/cli/commands/dev.js +3 -0
- package/dist/cli/commands/init.js +9 -8
- package/dist/cli/commands/test.js +4 -1
- package/dist/cli/commands/watch.js +5 -23
- package/dist/cli/daemon/logger.js +1 -0
- package/dist/cli/daemon/watch.js +35 -2
- package/dist/cli/wp/phpunit.js +104 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/integrations/nextjs/kizlo.server.d.ts +5 -6
- package/dist/integrations/nextjs/kizlo.server.js +7 -5
- package/dist/integrations/nextjs/revalidate.d.ts +25 -0
- package/dist/integrations/nextjs/revalidate.js +46 -0
- package/dist/integrations/nextjs/seo.d.ts +7 -0
- package/dist/integrations/nextjs/seo.js +41 -0
- package/dist/integrations/nextjs/sitemap.d.ts +30 -0
- package/dist/integrations/nextjs/sitemap.js +28 -0
- package/dist/nextjs/server.d.ts +2 -1
- package/dist/nextjs/server.js +2 -1
- package/dist/nextjs.d.ts +2 -1
- package/dist/nextjs.js +2 -1
- package/dist/package.js +1 -1
- package/dist/router.d.ts +47 -0
- package/dist/seo/index.js +50 -1
- package/dist/seo/sitemap.d.ts +39 -0
- package/dist/seo/sitemap.js +64 -0
- package/dist/seo/utils.d.ts +6 -0
- package/dist/seo/utils.js +36 -1
- package/dist/settings/service.interface.d.ts +1 -0
- package/dist/shared/error.d.ts +3 -3
- package/dist/shared/procedure.d.ts +10 -10
- package/dist/webhook/schema.d.ts +2 -9
- package/dist/webhook/schema.js +4 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
|
-
<h3 align="center">Headless WordPress Toolkit</h3>
|
|
14
|
+
<h3 align="center">Headless WordPress Toolkit for TypeScript</h3>
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
|
-
|
|
17
|
+
Develop, test, and ship from your machine with a fully typed RPC layer and WordPress API client.
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
@@ -34,33 +34,29 @@
|
|
|
34
34
|
|
|
35
35
|
## What is Kizlo?
|
|
36
36
|
|
|
37
|
-
Kizlo is
|
|
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.
|
|
38
|
+
|
|
39
|
+
> 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).
|
|
38
40
|
|
|
39
41
|
## Quick start
|
|
40
42
|
|
|
41
43
|
Set up Kizlo in your project:
|
|
42
44
|
|
|
43
45
|
```bash
|
|
44
|
-
npx kizlo init
|
|
46
|
+
npx kizlo@latest init
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
Start the local WordPress stack and regenerate the contract as you work:
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
52
|
npx kizlo dev
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
Generate the contract once for production builds:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
npx kizlo generate
|
|
57
|
-
```
|
|
58
|
-
|
|
59
55
|
See the [docs](https://kizlo.io/docs) for the full guide.
|
|
60
56
|
|
|
61
57
|
## Contributing
|
|
62
58
|
|
|
63
|
-
Contributions are welcome
|
|
59
|
+
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/kizlo-io/kizlo/blob/main/CONTRIBUTING.md) for setup,
|
|
64
60
|
workflow, and PR guidelines.
|
|
65
61
|
|
|
66
62
|
## Security
|
package/dist/cli/commands/dev.js
CHANGED
|
@@ -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
|
-
|
|
495
|
-
|
|
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");
|
|
@@ -5,6 +5,7 @@ import { isFree } from "../wp/ports.js";
|
|
|
5
5
|
import { groupDefault, pickStackPort, withSpinner } from "../utils.js";
|
|
6
6
|
import { resolveTestConfig } from "../daemon/config.js";
|
|
7
7
|
import { testStack } from "../wp/stack.js";
|
|
8
|
+
import { runPluginPhpunit } from "../wp/phpunit.js";
|
|
8
9
|
import { runSeeds } from "../wp/setup.js";
|
|
9
10
|
import { spawn } from "node:child_process";
|
|
10
11
|
import { defineCommand } from "citty";
|
|
@@ -107,7 +108,9 @@ async function runSuite({ args }) {
|
|
|
107
108
|
log.info(cfg.command ? `Running: ${cfg.command}` : `Running: ${testCommand(cfg.packageManager).join(" ")}`);
|
|
108
109
|
let code = 1;
|
|
109
110
|
try {
|
|
110
|
-
|
|
111
|
+
const jsCode = await spawnTest(cfg.command, cfg.packageManager);
|
|
112
|
+
const phpCode = await runPluginPhpunit(cfg);
|
|
113
|
+
code = jsCode !== 0 ? jsCode : phpCode;
|
|
111
114
|
} finally {
|
|
112
115
|
if (args.teardown) await withSpinner("Tearing down WordPress test stack", () => stack.composeDown(), "WordPress test stack stopped");
|
|
113
116
|
else log.info("Stack left running for fast reruns — `kizlo test stop` to stop it, or rerun with --teardown.");
|
|
@@ -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 {
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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: {
|
package/dist/cli/daemon/watch.js
CHANGED
|
@@ -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 {
|
|
70
|
+
export { startWatcher };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isLocalPlugin } from "./types.js";
|
|
2
|
+
import { compose } from "./docker.js";
|
|
3
|
+
import { log } from "../daemon/logger.js";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { basename, isAbsolute, resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/wp/phpunit.ts
|
|
8
|
+
const PLUGINS_DIR = `/var/www/html/wp-content/plugins`;
|
|
9
|
+
/** Isolated database the PHP suite runs against — never the served site's DB. */
|
|
10
|
+
const TEST_DB = "wordpress_test";
|
|
11
|
+
/** Root creds from the compose file, used only to create the DB and grant access. */
|
|
12
|
+
const MYSQL_ROOT_PASSWORD = "rootpass";
|
|
13
|
+
/** The app user the served site already connects as; the suite reuses it. */
|
|
14
|
+
const MYSQL_USER = "wordpress";
|
|
15
|
+
/**
|
|
16
|
+
* The bind-mounted local plugins that carry a `phpunit.xml` (or `.dist`), resolved
|
|
17
|
+
* to their in-container plugin dir. Checked on the host (where the source lives),
|
|
18
|
+
* run in the container (where WordPress lives) — so this works identically for a
|
|
19
|
+
* consumer whose own plugin is mounted while kizlo comes from a release.
|
|
20
|
+
*/
|
|
21
|
+
function phpunitTargets(cfg) {
|
|
22
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23
|
+
const targets = [];
|
|
24
|
+
for (const plugin of cfg.fixtures.flatMap((fixture) => fixture.plugins ?? [])) {
|
|
25
|
+
if (!isLocalPlugin(plugin)) continue;
|
|
26
|
+
const hostDir = isAbsolute(plugin.path) ? plugin.path : resolve(cfg.configDir, plugin.path);
|
|
27
|
+
const slug = basename(hostDir);
|
|
28
|
+
if (seen.has(slug)) continue;
|
|
29
|
+
seen.add(slug);
|
|
30
|
+
if (!(existsSync(resolve(hostDir, "phpunit.xml")) || existsSync(resolve(hostDir, "phpunit.xml.dist")))) continue;
|
|
31
|
+
if (!existsSync(resolve(hostDir, "vendor/bin/phpunit"))) {
|
|
32
|
+
log.warn(`${slug} has a phpunit config but no vendor/bin/phpunit — run \`composer install\` with dev dependencies to run its PHP tests. Skipping.`);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
targets.push({
|
|
36
|
+
slug,
|
|
37
|
+
containerDir: `${PLUGINS_DIR}/${slug}`
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return targets;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create the isolated `wordpress_test` database in the `mysql` service and grant the
|
|
44
|
+
* app user full access to it. Idempotent (`IF NOT EXISTS` + a re-runnable grant), so
|
|
45
|
+
* it can run on every `kizlo test` next to seeding without a guard.
|
|
46
|
+
*/
|
|
47
|
+
async function provisionTestDb() {
|
|
48
|
+
const sql = [
|
|
49
|
+
`CREATE DATABASE IF NOT EXISTS ${TEST_DB};`,
|
|
50
|
+
`GRANT ALL PRIVILEGES ON ${TEST_DB}.* TO '${MYSQL_USER}'@'%';`,
|
|
51
|
+
"FLUSH PRIVILEGES;"
|
|
52
|
+
].join(" ");
|
|
53
|
+
const res = await compose([
|
|
54
|
+
"exec",
|
|
55
|
+
"-T",
|
|
56
|
+
"mysql",
|
|
57
|
+
"mysql",
|
|
58
|
+
`-uroot`,
|
|
59
|
+
`-p${MYSQL_ROOT_PASSWORD}`,
|
|
60
|
+
"-e",
|
|
61
|
+
sql
|
|
62
|
+
]);
|
|
63
|
+
if (res.code !== 0) throw new Error(`Failed to provision the ${TEST_DB} database:\n${res.stderr || res.stdout}`);
|
|
64
|
+
}
|
|
65
|
+
/** Run one plugin's phpunit suite inside the `wordpress` container; resolve its exit code. */
|
|
66
|
+
async function runTarget(target) {
|
|
67
|
+
const wpPhpunitDir = `${target.containerDir}/vendor/wp-phpunit/wp-phpunit`;
|
|
68
|
+
const res = await compose([
|
|
69
|
+
"exec",
|
|
70
|
+
"-T",
|
|
71
|
+
"-w",
|
|
72
|
+
target.containerDir,
|
|
73
|
+
"-e",
|
|
74
|
+
`WP_PHPUNIT__DIR=${wpPhpunitDir}`,
|
|
75
|
+
"wordpress",
|
|
76
|
+
"php",
|
|
77
|
+
"vendor/bin/phpunit",
|
|
78
|
+
"--colors=always"
|
|
79
|
+
]);
|
|
80
|
+
process.stdout.write(res.stdout);
|
|
81
|
+
if (res.stderr) process.stderr.write(res.stderr);
|
|
82
|
+
return res.code;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Provision the test DB, then run phpunit for every bind-mounted local plugin that
|
|
86
|
+
* ships a phpunit config. Returns the worst exit code (0 when nothing to run), so the
|
|
87
|
+
* caller can fold PHP results into the overall `kizlo test` outcome. Plugin-agnostic:
|
|
88
|
+
* it never hardcodes `plugins/kizlo`.
|
|
89
|
+
*/
|
|
90
|
+
async function runPluginPhpunit(cfg) {
|
|
91
|
+
const targets = phpunitTargets(cfg);
|
|
92
|
+
if (targets.length === 0) return 0;
|
|
93
|
+
await provisionTestDb();
|
|
94
|
+
let worst = 0;
|
|
95
|
+
for (const target of targets) {
|
|
96
|
+
log.info(`Running PHP tests for ${target.slug}…`);
|
|
97
|
+
const code = await runTarget(target);
|
|
98
|
+
if (code !== 0) worst = code;
|
|
99
|
+
}
|
|
100
|
+
return worst;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { runPluginPhpunit };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,9 @@ import "./wordpress/index.js";
|
|
|
17
17
|
import { DevPluginSource, Fixture, FixtureCleanupFn, FixtureSeedFn, JsonValue, LocalPlugin, PluginSource, SeedContext, TestAdminUser, TestCredentials, TestUser, defineFixture, isLocalPlugin } from "./cli/wp/types.js";
|
|
18
18
|
import { AuthAdapter, AuthGetUser, AuthUser, authMock, createAuthAdapter } from "./adapters/auth.js";
|
|
19
19
|
import { CaptchaAdapter, altcha, arkose, createCaptchaAdapter, friendlyCaptcha, hcaptcha, recaptcha, turnstile } from "./adapters/captcha.js";
|
|
20
|
+
import { CONTENT_TYPES, ContentType, ListSitemapUrlInput, ListSitemapUrlInputBase, Robots, RobotsRule, Seo, SeoHead, SeoSchema, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList } from "./seo/schema.js";
|
|
21
|
+
import { WPK_ListSitemapUrlInput, WPK_RobotRule, WPK_Robots, WPK_Seo, WPK_Sitemap, WPK_SitemapContentType, WPK_SitemapUrl, WPK_SitemapUrlImage } from "./seo/types.js";
|
|
22
|
+
import { SitemapIndexEntry } from "./seo/utils.js";
|
|
20
23
|
import { CurrencyFormat, IdentifierInput, LIST_ORDER, ListMetadata, ListOrder, Media, PreviewTokenData, PreviewTokenPayload } from "./shared/schema.js";
|
|
21
24
|
import { AnyContext, AnyNestedClient, CookiesAdapter, CookiesDeleteAll, CookiesGetAll, CookiesSetAll, HTTPMethod, List, MaybeOptionalOptions, RedirectInput, RedirectStatus } from "./shared/types.js";
|
|
22
25
|
import { createCookiesAdapter } from "./adapters/cookies.js";
|
|
@@ -34,11 +37,10 @@ import { AuthUserFn, ConnInfoFn, Context, ContextConfig, ServerContext, VerifyCa
|
|
|
34
37
|
import { AnyMiddleware, ExtractMiddlewareContextOutput, InferUses, Middleware, MiddlewareHandler, MiddlewareNextFn, MiddlewareOptions, MiddlewareResult, createMiddleware } from "./shared/middleware.js";
|
|
35
38
|
import { AnyProcedure, AnyProcedureRouter, BaseHandlerOptions, ExtractParams, ExtractProcedureByScope, InvocationScope, OpenapiPart, Procedure, ProcedureContext, ProcedureErrors, ProcedureHandler, ProcedureOptions, ResolveParamsPart, ResolvedSchemaInput, ResolvedSchemaOutput, RouterDepthTuple, SchemaIO, buildProcedure, combineDetailed, createProcedure, handleUnexpectedError, schemaType } from "./shared/procedure.js";
|
|
36
39
|
import { KizloClient, KizloClientConfig, createKizloClient } from "./client.js";
|
|
37
|
-
import {
|
|
38
|
-
import { WPK_ListSitemapUrlInput, WPK_RobotRule, WPK_Robots, WPK_Seo, WPK_Sitemap, WPK_SitemapContentType, WPK_SitemapUrl, WPK_SitemapUrlImage } from "./seo/types.js";
|
|
40
|
+
import { CreateSitemapRouteOptions, SITEMAP_BASE, SITEMAP_INDEX_SLUG, SitemapRouteExtra, createSitemapRoute } from "./seo/sitemap.js";
|
|
39
41
|
import { Contract, ContractProcedure, generateContract, isContractProcedure, restoreContract } from "./shared/contract.js";
|
|
40
42
|
import { compare, hash, hmac } from "./shared/crypto.js";
|
|
41
43
|
import { Identifier, parseIdentifier } from "./shared/identifier.js";
|
|
42
44
|
import { createOrpcRouter } from "./shared/router.js";
|
|
43
45
|
import { deserializeCurrencyFormat, deserializeListMetadata, emptyList, serializeCurrencyFormat } from "./shared/serialize.js";
|
|
44
|
-
export { AnyContext, AnyEventSchema, AnyEvents, AnyExtension, AnyKizloConfig, AnyMiddleware, AnyNestedClient, AnyProcedure, AnyProcedureRouter, AuthAdapter, AuthGetUser, AuthUser, AuthUserFn, BaseHandlerOptions, CART_HASH_HEADER_KEY, COMMON_ERRORS, CONTENT_TYPES, CaptchaAdapter, CommentService, CommonErrorCode, CommonErrorLiteral, CommonErrorMap, ConnInfo, ConnInfoFn, ConsoleLogAdapterOptions, ContentType, Context, ContextConfig, Contract, ContractProcedure, CookiesAdapter, CookiesDeleteAll, CookiesGetAll, CookiesSetAll, CreateKizloOptions, CurrencyFormat, DefinedErrorMapLike, DevPluginSource, Environment, ErrorDefinition, EventHandler, EventHandlerFn, Extension, ExtensionInitFn, ExtensionInitOptions, ExtensionInitResult, ExtractExtensionRouter, ExtractMiddlewareContextOutput, ExtractParams, ExtractProcedureByScope, Fixture, FixtureCleanupFn, FixtureSeedFn, GeoAdapter, GeoGetConnInfo, HTTPMethod, Identifier, IdentifierInput, InferEventUnion, InferExtensionRouter, InferUses, InvocationScope, JsonValue, Kizlo, KizloAuthorsSettings, KizloAuthorsSettingsInput, KizloClient, KizloClientConfig, KizloConfig, KizloCrawlingSettings, KizloCrawlingSettingsInput, KizloError, KizloErrorOptions, KizloIdentitySettings, KizloIdentitySettingsInput, KizloMedia, KizloOrganizationFounder, KizloOrganizationSettings, KizloOrganizationSettingsInput, KizloPersonSettings, KizloPersonSettingsInput, KizloPostStatus, KizloPostTypeSettings, KizloPostTypeSettingsInput, KizloSettings, KizloSettingsService, KizloSiteSettings, KizloSiteSettingsInput, KizloSocialProfile, KizloTarget, KizloTaxonomySettings, KizloTaxonomySettingsInput, KizloWebhookSettings, KizloWebhookSettingsInput, LIST_ORDER, List, ListMetadata, ListOrder, ListSitemapUrlInput, ListSitemapUrlInputBase, LocalPlugin, LogLevel, LogPayload, Logger, LoggerAdapter, MaybeOptionalOptions, Media, MenuItemService, MenuService, Middleware, MiddlewareHandler, MiddlewareNextFn, MiddlewareOptions, MiddlewareResult, OpenapiPart, PluginSource, PostService, PreviewTokenData, PreviewTokenPayload, Procedure, ProcedureContext, ProcedureErrors, ProcedureHandler, ProcedureOptions, RedirectInput, RedirectStatus, ResolveParamsPart, ResolvedSchemaInput, ResolvedSchemaOutput, Robots, RobotsRule, RootRouter, RouterDepthTuple, S2SClient, SAFE_REQUEST_TIMEOUT, SchemaIO, SeedContext, Seo, SeoHead, SeoSchema, ServerContext, Service, ServiceAdapters, ServiceConfig, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList, TestAdminUser, TestCredentials, TestUser, ThrowableErrorFn, ThrowableErrorMap, UNEXPECTED_BODY_SNIPPET_LENGTH, UserService, VerifyCaptchaFn, VerifyPreviewTokenFn, WC_CORE_BASE, WC_STORE_BASE, WPK_ListSitemapUrlInput, WPK_RobotRule, WPK_Robots, WPK_Seo, WPK_Sitemap, WPK_SitemapContentType, WPK_SitemapUrl, WPK_SitemapUrlImage, WP_AUTH_HEADER_KEY, WP_AUTH_TYPE, WP_CORE_BASE, WP_Comment, WP_CommentAvatarUrls, WP_CommentContent, WP_CommentContentInput, WP_CommentCreateErrorCode, WP_CommentCreateInput, WP_CommentDeleteErrorCode, WP_CommentDeleteInput, WP_CommentDeleteResponse, WP_CommentLinks, WP_CommentListErrorCode, WP_CommentListInput, WP_CommentOrderBy, WP_CommentRetrieveErrorCode, WP_CommentRetrieveInput, WP_CommentStatus, WP_CommentStatusFilter, WP_CommentStatusInput, WP_CommentType, WP_CommentUpdateErrorCode, WP_CommentUpdateInput, WP_CommonErrorCode, WP_Context, WP_CurrencyFormat, WP_Error, WP_ErrorData, WP_KIZLO_BASE, WP_Link, WP_List, WP_ListMetadata, WP_ListOrder, WP_Menu, WP_MenuCreateErrorCode, WP_MenuCreateInput, WP_MenuDeleteErrorCode, WP_MenuDeleteInput, WP_MenuDeleteResponse, WP_MenuItem, WP_MenuItemCreateErrorCode, WP_MenuItemCreateInput, WP_MenuItemDeleteErrorCode, WP_MenuItemDeleteInput, WP_MenuItemDeleteResponse, WP_MenuItemLinks, WP_MenuItemListErrorCode, WP_MenuItemListInput, WP_MenuItemOrderBy, WP_MenuItemRetrieveErrorCode, WP_MenuItemRetrieveInput, WP_MenuItemStatus, WP_MenuItemStatusFilter, WP_MenuItemTarget, WP_MenuItemTaxRelation, WP_MenuItemTitle, WP_MenuItemTitleInput, WP_MenuItemType, WP_MenuItemUpdateErrorCode, WP_MenuItemUpdateInput, WP_MenuLinks, WP_MenuListErrorCode, WP_MenuListInput, WP_MenuOrderBy, WP_MenuRetrieveErrorCode, WP_MenuRetrieveInput, WP_MenuUpdateErrorCode, WP_MenuUpdateInput, WP_Post, WP_PostCommentStatus, WP_PostContent, WP_PostContentInput, WP_PostCreateErrorCode, WP_PostCreateInput, WP_PostDeleteErrorCode, WP_PostDeleteInput, WP_PostDeleteResponse, WP_PostExcerpt, WP_PostExcerptInput, WP_PostFormat, WP_PostGuid, WP_PostLinks, WP_PostListErrorCode, WP_PostListInput, WP_PostOrderBy, WP_PostRetrieveErrorCode, WP_PostRetrieveInput, WP_PostStatus, WP_PostStatusFilter, WP_PostTaxRelation, WP_PostTitle, WP_PostTitleInput, WP_PostUpdateErrorCode, WP_PostUpdateInput, WP_RequestInput, WP_Result, WP_User, WP_UserAvatarUrls, WP_UserCapabilities, WP_UserCreateErrorCode, WP_UserCreateInput, WP_UserDeleteErrorCode, WP_UserDeleteInput, WP_UserDeleteMeErrorCode, WP_UserDeleteMeInput, WP_UserDeleteMeResponse, WP_UserDeleteResponse, WP_UserLinks, WP_UserListErrorCode, WP_UserListInput, WP_UserOrderBy, WP_UserRetrieveErrorCode, WP_UserRetrieveInput, WP_UserRetrieveMeErrorCode, WP_UserRetrieveMeInput, WP_UserUpdateErrorCode, WP_UserUpdateInput, WP_UserUpdateMeErrorCode, WP_UserUpdateMeInput, WP_UserWho, WebhookOptions, WithCommonErrorMap, WordPressCredentials, WordPressService, altcha, arkose, authMock, buildProcedure, combineDetailed, compare, consoleLog, createAuthAdapter, createCaptchaAdapter, createCookiesAdapter, createEventHandler, createExtension, createGeoAdapter, createKizlo, createKizloClient, createLoggerAdapter, createMiddleware, createOrpcRouter, createProcedure, createThrowableErrorMap, createWebhookRouter, defineErrorMap, defineFixture, deserializeCurrencyFormat, deserializeListMetadata, emptyList, friendlyCaptcha, generateContract, geoMock, geoVercelNext, handleUnexpectedError, hash, hcaptcha, hmac, isContractProcedure, isKizloError, isLocalPlugin, isWordPressResourceError, noopAdapter, parseIdentifier, recaptcha, resolveKizloConfig, restoreContract, schemaType, serializeCurrencyFormat, toKizloError, turnstile };
|
|
46
|
+
export { AnyContext, AnyEventSchema, AnyEvents, AnyExtension, AnyKizloConfig, AnyMiddleware, AnyNestedClient, AnyProcedure, AnyProcedureRouter, AuthAdapter, AuthGetUser, AuthUser, AuthUserFn, BaseHandlerOptions, CART_HASH_HEADER_KEY, COMMON_ERRORS, CONTENT_TYPES, CaptchaAdapter, CommentService, CommonErrorCode, CommonErrorLiteral, CommonErrorMap, ConnInfo, ConnInfoFn, ConsoleLogAdapterOptions, ContentType, Context, ContextConfig, Contract, ContractProcedure, CookiesAdapter, CookiesDeleteAll, CookiesGetAll, CookiesSetAll, CreateKizloOptions, CreateSitemapRouteOptions, CurrencyFormat, DefinedErrorMapLike, DevPluginSource, Environment, ErrorDefinition, EventHandler, EventHandlerFn, Extension, ExtensionInitFn, ExtensionInitOptions, ExtensionInitResult, ExtractExtensionRouter, ExtractMiddlewareContextOutput, ExtractParams, ExtractProcedureByScope, Fixture, FixtureCleanupFn, FixtureSeedFn, GeoAdapter, GeoGetConnInfo, HTTPMethod, Identifier, IdentifierInput, InferEventUnion, InferExtensionRouter, InferUses, InvocationScope, JsonValue, Kizlo, KizloAuthorsSettings, KizloAuthorsSettingsInput, KizloClient, KizloClientConfig, KizloConfig, KizloCrawlingSettings, KizloCrawlingSettingsInput, KizloError, KizloErrorOptions, KizloIdentitySettings, KizloIdentitySettingsInput, KizloMedia, KizloOrganizationFounder, KizloOrganizationSettings, KizloOrganizationSettingsInput, KizloPersonSettings, KizloPersonSettingsInput, KizloPostStatus, KizloPostTypeSettings, KizloPostTypeSettingsInput, KizloSettings, KizloSettingsService, KizloSiteSettings, KizloSiteSettingsInput, KizloSocialProfile, KizloTarget, KizloTaxonomySettings, KizloTaxonomySettingsInput, KizloWebhookSettings, KizloWebhookSettingsInput, LIST_ORDER, List, ListMetadata, ListOrder, ListSitemapUrlInput, ListSitemapUrlInputBase, LocalPlugin, LogLevel, LogPayload, Logger, LoggerAdapter, MaybeOptionalOptions, Media, MenuItemService, MenuService, Middleware, MiddlewareHandler, MiddlewareNextFn, MiddlewareOptions, MiddlewareResult, OpenapiPart, PluginSource, PostService, PreviewTokenData, PreviewTokenPayload, Procedure, ProcedureContext, ProcedureErrors, ProcedureHandler, ProcedureOptions, RedirectInput, RedirectStatus, ResolveParamsPart, ResolvedSchemaInput, ResolvedSchemaOutput, Robots, RobotsRule, RootRouter, RouterDepthTuple, S2SClient, SAFE_REQUEST_TIMEOUT, SITEMAP_BASE, SITEMAP_INDEX_SLUG, SchemaIO, SeedContext, Seo, SeoHead, SeoSchema, ServerContext, Service, ServiceAdapters, ServiceConfig, Sitemap, type SitemapIndexEntry, SitemapList, SitemapRouteExtra, SitemapUrl, SitemapUrlImage, SitemapUrlList, TestAdminUser, TestCredentials, TestUser, ThrowableErrorFn, ThrowableErrorMap, UNEXPECTED_BODY_SNIPPET_LENGTH, UserService, VerifyCaptchaFn, VerifyPreviewTokenFn, WC_CORE_BASE, WC_STORE_BASE, WPK_ListSitemapUrlInput, WPK_RobotRule, WPK_Robots, WPK_Seo, WPK_Sitemap, WPK_SitemapContentType, WPK_SitemapUrl, WPK_SitemapUrlImage, WP_AUTH_HEADER_KEY, WP_AUTH_TYPE, WP_CORE_BASE, WP_Comment, WP_CommentAvatarUrls, WP_CommentContent, WP_CommentContentInput, WP_CommentCreateErrorCode, WP_CommentCreateInput, WP_CommentDeleteErrorCode, WP_CommentDeleteInput, WP_CommentDeleteResponse, WP_CommentLinks, WP_CommentListErrorCode, WP_CommentListInput, WP_CommentOrderBy, WP_CommentRetrieveErrorCode, WP_CommentRetrieveInput, WP_CommentStatus, WP_CommentStatusFilter, WP_CommentStatusInput, WP_CommentType, WP_CommentUpdateErrorCode, WP_CommentUpdateInput, WP_CommonErrorCode, WP_Context, WP_CurrencyFormat, WP_Error, WP_ErrorData, WP_KIZLO_BASE, WP_Link, WP_List, WP_ListMetadata, WP_ListOrder, WP_Menu, WP_MenuCreateErrorCode, WP_MenuCreateInput, WP_MenuDeleteErrorCode, WP_MenuDeleteInput, WP_MenuDeleteResponse, WP_MenuItem, WP_MenuItemCreateErrorCode, WP_MenuItemCreateInput, WP_MenuItemDeleteErrorCode, WP_MenuItemDeleteInput, WP_MenuItemDeleteResponse, WP_MenuItemLinks, WP_MenuItemListErrorCode, WP_MenuItemListInput, WP_MenuItemOrderBy, WP_MenuItemRetrieveErrorCode, WP_MenuItemRetrieveInput, WP_MenuItemStatus, WP_MenuItemStatusFilter, WP_MenuItemTarget, WP_MenuItemTaxRelation, WP_MenuItemTitle, WP_MenuItemTitleInput, WP_MenuItemType, WP_MenuItemUpdateErrorCode, WP_MenuItemUpdateInput, WP_MenuLinks, WP_MenuListErrorCode, WP_MenuListInput, WP_MenuOrderBy, WP_MenuRetrieveErrorCode, WP_MenuRetrieveInput, WP_MenuUpdateErrorCode, WP_MenuUpdateInput, WP_Post, WP_PostCommentStatus, WP_PostContent, WP_PostContentInput, WP_PostCreateErrorCode, WP_PostCreateInput, WP_PostDeleteErrorCode, WP_PostDeleteInput, WP_PostDeleteResponse, WP_PostExcerpt, WP_PostExcerptInput, WP_PostFormat, WP_PostGuid, WP_PostLinks, WP_PostListErrorCode, WP_PostListInput, WP_PostOrderBy, WP_PostRetrieveErrorCode, WP_PostRetrieveInput, WP_PostStatus, WP_PostStatusFilter, WP_PostTaxRelation, WP_PostTitle, WP_PostTitleInput, WP_PostUpdateErrorCode, WP_PostUpdateInput, WP_RequestInput, WP_Result, WP_User, WP_UserAvatarUrls, WP_UserCapabilities, WP_UserCreateErrorCode, WP_UserCreateInput, WP_UserDeleteErrorCode, WP_UserDeleteInput, WP_UserDeleteMeErrorCode, WP_UserDeleteMeInput, WP_UserDeleteMeResponse, WP_UserDeleteResponse, WP_UserLinks, WP_UserListErrorCode, WP_UserListInput, WP_UserOrderBy, WP_UserRetrieveErrorCode, WP_UserRetrieveInput, WP_UserRetrieveMeErrorCode, WP_UserRetrieveMeInput, WP_UserUpdateErrorCode, WP_UserUpdateInput, WP_UserUpdateMeErrorCode, WP_UserUpdateMeInput, WP_UserWho, WebhookOptions, WithCommonErrorMap, WordPressCredentials, WordPressService, altcha, arkose, authMock, buildProcedure, combineDetailed, compare, consoleLog, createAuthAdapter, createCaptchaAdapter, createCookiesAdapter, createEventHandler, createExtension, createGeoAdapter, createKizlo, createKizloClient, createLoggerAdapter, createMiddleware, createOrpcRouter, createProcedure, createSitemapRoute, createThrowableErrorMap, createWebhookRouter, defineErrorMap, defineFixture, deserializeCurrencyFormat, deserializeListMetadata, emptyList, friendlyCaptcha, generateContract, geoMock, geoVercelNext, handleUnexpectedError, hash, hcaptcha, hmac, isContractProcedure, isKizloError, isLocalPlugin, isWordPressResourceError, noopAdapter, parseIdentifier, recaptcha, resolveKizloConfig, restoreContract, schemaType, serializeCurrencyFormat, toKizloError, turnstile };
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,8 @@ import { parseIdentifier } from "./shared/identifier.js";
|
|
|
29
29
|
import { CONTENT_TYPES, ContentType, ListSitemapUrlInput, ListSitemapUrlInputBase, Robots, RobotsRule, Seo, SeoHead, SeoSchema, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList } from "./seo/schema.js";
|
|
30
30
|
import { createEventHandler, createWebhookRouter } from "./webhook/index.js";
|
|
31
31
|
import { Kizlo, createKizlo, resolveKizloConfig } from "./kizlo.js";
|
|
32
|
+
import { SITEMAP_BASE, SITEMAP_INDEX_SLUG, createSitemapRoute } from "./seo/sitemap.js";
|
|
32
33
|
import { createExtension } from "./shared/extension.js";
|
|
33
34
|
import { createMiddleware } from "./shared/middleware.js";
|
|
34
35
|
|
|
35
|
-
export { CART_HASH_HEADER_KEY, COMMON_ERRORS, CONTENT_TYPES, CommentService, ContentType, Context, CurrencyFormat, IdentifierInput, Kizlo, KizloClient, KizloError, KizloSettingsService, LIST_ORDER, ListMetadata, ListOrder, ListSitemapUrlInput, ListSitemapUrlInputBase, Media, MenuItemService, MenuService, PostService, PreviewTokenData, PreviewTokenPayload, Robots, RobotsRule, SAFE_REQUEST_TIMEOUT, Seo, SeoHead, SeoSchema, Service, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList, UNEXPECTED_BODY_SNIPPET_LENGTH, UserService, WC_CORE_BASE, WC_STORE_BASE, WP_AUTH_HEADER_KEY, WP_AUTH_TYPE, WP_CORE_BASE, WP_Error, WP_KIZLO_BASE, WordPressService, altcha, arkose, authMock, buildProcedure, combineDetailed, compare, consoleLog, createAuthAdapter, createCaptchaAdapter, createCookiesAdapter, createEventHandler, createExtension, createGeoAdapter, createKizlo, createKizloClient, createLoggerAdapter, createMiddleware, createOrpcRouter, createProcedure, createThrowableErrorMap, createWebhookRouter, defineErrorMap, defineFixture, deserializeCurrencyFormat, deserializeListMetadata, emptyList, friendlyCaptcha, generateContract, geoMock, geoVercelNext, handleUnexpectedError, hash, hcaptcha, hmac, isContractProcedure, isKizloError, isLocalPlugin, isWordPressResourceError, noopAdapter, parseIdentifier, recaptcha, resolveKizloConfig, restoreContract, schemaType, serializeCurrencyFormat, toKizloError, turnstile };
|
|
36
|
+
export { CART_HASH_HEADER_KEY, COMMON_ERRORS, CONTENT_TYPES, CommentService, ContentType, Context, CurrencyFormat, IdentifierInput, Kizlo, KizloClient, KizloError, KizloSettingsService, LIST_ORDER, ListMetadata, ListOrder, ListSitemapUrlInput, ListSitemapUrlInputBase, Media, MenuItemService, MenuService, PostService, PreviewTokenData, PreviewTokenPayload, Robots, RobotsRule, SAFE_REQUEST_TIMEOUT, SITEMAP_BASE, SITEMAP_INDEX_SLUG, Seo, SeoHead, SeoSchema, Service, Sitemap, SitemapList, SitemapUrl, SitemapUrlImage, SitemapUrlList, UNEXPECTED_BODY_SNIPPET_LENGTH, UserService, WC_CORE_BASE, WC_STORE_BASE, WP_AUTH_HEADER_KEY, WP_AUTH_TYPE, WP_CORE_BASE, WP_Error, WP_KIZLO_BASE, WordPressService, altcha, arkose, authMock, buildProcedure, combineDetailed, compare, consoleLog, createAuthAdapter, createCaptchaAdapter, createCookiesAdapter, createEventHandler, createExtension, createGeoAdapter, createKizlo, createKizloClient, createLoggerAdapter, createMiddleware, createOrpcRouter, createProcedure, createSitemapRoute, createThrowableErrorMap, createWebhookRouter, defineErrorMap, defineFixture, deserializeCurrencyFormat, deserializeListMetadata, emptyList, friendlyCaptcha, generateContract, geoMock, geoVercelNext, handleUnexpectedError, hash, hcaptcha, hmac, isContractProcedure, isKizloError, isLocalPlugin, isWordPressResourceError, noopAdapter, parseIdentifier, recaptcha, resolveKizloConfig, restoreContract, schemaType, serializeCurrencyFormat, toKizloError, turnstile };
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { AnyExtension } from "../../shared/extension.js";
|
|
2
2
|
import { CreateKizloOptions, Kizlo } from "../../kizlo.js";
|
|
3
|
+
import { NextRevalidateOptions } from "./revalidate.js";
|
|
3
4
|
|
|
4
5
|
//#region src/integrations/nextjs/kizlo.server.d.ts
|
|
5
|
-
type KizloServerOptions<TExts extends readonly AnyExtension[] = []> = CreateKizloOptions<TExts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
declare function createKizlo<TExts extends readonly AnyExtension[] = []>(options?: CreateKizloOptions<TExts>): Kizlo<TExts>;
|
|
6
|
+
type KizloServerOptions<TExts extends readonly AnyExtension[] = []> = CreateKizloOptions<TExts> & {
|
|
7
|
+
revalidate?: boolean | NextRevalidateOptions;
|
|
8
|
+
};
|
|
9
|
+
declare function createKizlo<TExts extends readonly AnyExtension[] = []>(options?: KizloServerOptions<TExts>): Kizlo<TExts>;
|
|
11
10
|
//#endregion
|
|
12
11
|
export { KizloServerOptions, createKizlo };
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Kizlo, resolveKizloConfig } from "../../kizlo.js";
|
|
2
|
+
import { nextRevalidation } from "./revalidate.js";
|
|
2
3
|
|
|
3
4
|
//#region src/integrations/nextjs/kizlo.server.ts
|
|
4
|
-
/**
|
|
5
|
-
* Creates a Kizlo server for Next.js — same as the base `createKizlo`, but reads
|
|
6
|
-
* the public base URL from `NEXT_PUBLIC_KIZLO_BACKEND_URL`.
|
|
7
|
-
*/
|
|
8
5
|
function createKizlo(options) {
|
|
9
|
-
|
|
6
|
+
const revalidate = options?.revalidate;
|
|
7
|
+
const extensions = [...revalidate === false ? [] : [nextRevalidation(typeof revalidate === "object" ? revalidate : void 0)], ...options?.extensions ?? []];
|
|
8
|
+
return new Kizlo(resolveKizloConfig({
|
|
9
|
+
...options,
|
|
10
|
+
extensions
|
|
11
|
+
}, { baseUrlEnvKey: "NEXT_PUBLIC_KIZLO_BACKEND_URL" }));
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
//#endregion
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { KizloEvent } from "../../webhook/schema.js";
|
|
2
|
+
import "../../index.js";
|
|
3
|
+
import { Pathname } from "@kizlo/shared";
|
|
4
|
+
|
|
5
|
+
//#region src/integrations/nextjs/revalidate.d.ts
|
|
6
|
+
type RevalidatePathFn = (path: string, type?: "layout" | "page") => void;
|
|
7
|
+
/** A path to revalidate, optionally with the Next `type` a dynamic route needs (e.g. `"page"`). */
|
|
8
|
+
type RevalidateTarget = Pathname | {
|
|
9
|
+
path: Pathname;
|
|
10
|
+
type?: "layout" | "page";
|
|
11
|
+
};
|
|
12
|
+
interface NextRevalidateOptions {
|
|
13
|
+
revalidatePath?: RevalidatePathFn;
|
|
14
|
+
/** Return extra paths to revalidate for a given event, on top of the event's own URL. */
|
|
15
|
+
paths?: (event: KizloEvent) => Pathname[] | Promise<Pathname[]>;
|
|
16
|
+
/**
|
|
17
|
+
* How to revalidate the sitemap. Defaults to the route `createSitemapRoute` serves
|
|
18
|
+
* (`/sitemaps/[sitemap]`, revalidated as a dynamic page). Override this only if you
|
|
19
|
+
* serve sitemaps from your own route(s) instead of `createSitemapRoute`; pass `false`
|
|
20
|
+
* to skip sitemap revalidation.
|
|
21
|
+
*/
|
|
22
|
+
sitemap?: false | RevalidateTarget | RevalidateTarget[];
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { NextRevalidateOptions };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createEventHandler } from "../../webhook/index.js";
|
|
2
|
+
import { createExtension } from "../../shared/extension.js";
|
|
3
|
+
import { SITEMAP_ROUTE } from "./sitemap.js";
|
|
4
|
+
|
|
5
|
+
//#region src/integrations/nextjs/revalidate.ts
|
|
6
|
+
const ROBOTS_PATH = "/robots.txt";
|
|
7
|
+
const DEFAULT_SITEMAP_TARGET = {
|
|
8
|
+
path: SITEMAP_ROUTE,
|
|
9
|
+
type: "page"
|
|
10
|
+
};
|
|
11
|
+
function nextRevalidation(options) {
|
|
12
|
+
return createExtension({
|
|
13
|
+
id: "nextjs-revalidation",
|
|
14
|
+
init: () => ({ events: [createEventHandler(async (event) => {
|
|
15
|
+
if (!event) return;
|
|
16
|
+
if (event.type.startsWith("settings")) return;
|
|
17
|
+
const revalidatePath = options?.revalidatePath ?? (await import("next/cache")).revalidatePath;
|
|
18
|
+
const paths = [
|
|
19
|
+
...await Promise.resolve(options?.paths?.(event) ?? []),
|
|
20
|
+
...event.data?.url ? [event.data.url] : [],
|
|
21
|
+
ROBOTS_PATH
|
|
22
|
+
];
|
|
23
|
+
for (const path of normalizePaths(paths)) revalidatePath(path);
|
|
24
|
+
for (const target of resolveSitemapTargets(options?.sitemap)) revalidatePath(normalizePath(target.path), target.type);
|
|
25
|
+
})] })
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function resolveSitemapTargets(option) {
|
|
29
|
+
if (option === false) return [];
|
|
30
|
+
return (option === void 0 ? [DEFAULT_SITEMAP_TARGET] : Array.isArray(option) ? option : [option]).map((target) => typeof target === "string" ? { path: target } : target);
|
|
31
|
+
}
|
|
32
|
+
function normalizePaths(paths) {
|
|
33
|
+
return Array.from(new Set((Array.isArray(paths) ? paths : paths ? [paths] : []).map(normalizePath).filter(Boolean)));
|
|
34
|
+
}
|
|
35
|
+
function normalizePath(path) {
|
|
36
|
+
try {
|
|
37
|
+
return normalizePath(new URL(path).pathname);
|
|
38
|
+
} catch {
|
|
39
|
+
const trimmed = path.trim();
|
|
40
|
+
if (!trimmed) return "";
|
|
41
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { nextRevalidation };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/integrations/nextjs/seo.ts
|
|
2
|
+
function toMetadata(head) {
|
|
3
|
+
const robots = [
|
|
4
|
+
head.robots.index,
|
|
5
|
+
head.robots.follow,
|
|
6
|
+
head.robots.maxSnippet,
|
|
7
|
+
head.robots.maxImagePreview,
|
|
8
|
+
head.robots.maxVideoPreview
|
|
9
|
+
].join(", ");
|
|
10
|
+
return {
|
|
11
|
+
title: { absolute: head.title },
|
|
12
|
+
description: head.og.description || void 0,
|
|
13
|
+
alternates: { canonical: head.canonical },
|
|
14
|
+
robots,
|
|
15
|
+
openGraph: {
|
|
16
|
+
type: head.og.type,
|
|
17
|
+
title: head.og.title,
|
|
18
|
+
description: head.og.description || void 0,
|
|
19
|
+
url: head.og.url,
|
|
20
|
+
siteName: head.og.siteName,
|
|
21
|
+
locale: head.og.locale,
|
|
22
|
+
images: head.og.image ? [{
|
|
23
|
+
url: head.og.image.url,
|
|
24
|
+
width: head.og.image.width,
|
|
25
|
+
height: head.og.image.height,
|
|
26
|
+
alt: head.og.image.alt ?? void 0
|
|
27
|
+
}] : void 0
|
|
28
|
+
},
|
|
29
|
+
twitter: {
|
|
30
|
+
card: head.twitter.card,
|
|
31
|
+
title: head.twitter.title,
|
|
32
|
+
description: head.twitter.description || void 0,
|
|
33
|
+
site: head.twitter.site ?? void 0,
|
|
34
|
+
creator: head.twitter.creator ?? void 0,
|
|
35
|
+
images: head.twitter.image ? [head.twitter.image] : void 0
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { toMetadata };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { S2SClient } from "../../kizlo.js";
|
|
2
|
+
import { CreateSitemapRouteOptions } from "../../seo/sitemap.js";
|
|
3
|
+
|
|
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
|
+
* "page")` refreshes the index and every generated sitemap at once. `[sitemap]` is Next's
|
|
10
|
+
* file-routing convention, which is why it lives in this integration and not in core.
|
|
11
|
+
*/
|
|
12
|
+
declare const SITEMAP_ROUTE: "/sitemaps/[sitemap]";
|
|
13
|
+
/** Next's dynamic-route context. `params` is a promise in the App Router. */
|
|
14
|
+
interface NextRouteContext {
|
|
15
|
+
params?: {
|
|
16
|
+
sitemap?: string;
|
|
17
|
+
} | Promise<{
|
|
18
|
+
sitemap?: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Next wrapper around the framework-agnostic {@link createCoreSitemapRoute}. It serves the
|
|
23
|
+
* same sitemap index and collection pages, and additionally asserts the route is mounted at
|
|
24
|
+
* {@link SITEMAP_ROUTE}: if the dynamic segment is not named `[sitemap]`, `params.sitemap`
|
|
25
|
+
* is missing and a wrong mount would silently break `revalidatePath(SITEMAP_ROUTE, "page")`,
|
|
26
|
+
* so it throws loudly on the first request instead.
|
|
27
|
+
*/
|
|
28
|
+
declare function createSitemapRoute(client: S2SClient<[]>, options?: CreateSitemapRouteOptions): (request: Request, ctx?: NextRouteContext) => Promise<Response>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { SITEMAP_ROUTE, createSitemapRoute };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SITEMAP_BASE, createSitemapRoute } from "../../seo/sitemap.js";
|
|
2
|
+
|
|
3
|
+
//#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
|
+
* "page")` refreshes the index and every generated sitemap at once. `[sitemap]` is Next's
|
|
8
|
+
* file-routing convention, which is why it lives in this integration and not in core.
|
|
9
|
+
*/
|
|
10
|
+
const SITEMAP_ROUTE = `${SITEMAP_BASE}/[sitemap]`;
|
|
11
|
+
/**
|
|
12
|
+
* Next wrapper around the framework-agnostic {@link createCoreSitemapRoute}. It serves the
|
|
13
|
+
* same sitemap index and collection pages, and additionally asserts the route is mounted at
|
|
14
|
+
* {@link SITEMAP_ROUTE}: if the dynamic segment is not named `[sitemap]`, `params.sitemap`
|
|
15
|
+
* is missing and a wrong mount would silently break `revalidatePath(SITEMAP_ROUTE, "page")`,
|
|
16
|
+
* so it throws loudly on the first request instead.
|
|
17
|
+
*/
|
|
18
|
+
function createSitemapRoute$1(client, options) {
|
|
19
|
+
const handler = createSitemapRoute(client, options);
|
|
20
|
+
return async function GET(request, ctx) {
|
|
21
|
+
const params = ctx?.params ? await ctx.params : void 0;
|
|
22
|
+
if (params && params.sitemap === void 0) throw new Error(`createSitemapRoute must be mounted at "${SITEMAP_ROUTE}". The dynamic segment must be named [sitemap].`);
|
|
23
|
+
return handler(request);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { SITEMAP_ROUTE, createSitemapRoute$1 as createSitemapRoute };
|
package/dist/nextjs/server.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { KizloServerOptions, createKizlo } from "../integrations/nextjs/kizlo.server.js";
|
|
2
|
-
|
|
2
|
+
import { SITEMAP_ROUTE, createSitemapRoute } from "../integrations/nextjs/sitemap.js";
|
|
3
|
+
export { KizloServerOptions, SITEMAP_ROUTE, createKizlo, createSitemapRoute };
|
package/dist/nextjs/server.js
CHANGED
package/dist/nextjs.d.ts
CHANGED
package/dist/nextjs.js
CHANGED
package/dist/package.js
CHANGED
package/dist/router.d.ts
CHANGED
|
@@ -299,6 +299,53 @@ declare const ROUTER_MAP: {
|
|
|
299
299
|
}>;
|
|
300
300
|
};
|
|
301
301
|
seo: {
|
|
302
|
+
homepage: Procedure<"internal", {}, {
|
|
303
|
+
head: {
|
|
304
|
+
title: string;
|
|
305
|
+
canonical: string;
|
|
306
|
+
robots: {
|
|
307
|
+
index: string;
|
|
308
|
+
follow: string;
|
|
309
|
+
maxSnippet: string;
|
|
310
|
+
maxImagePreview: string;
|
|
311
|
+
maxVideoPreview: string;
|
|
312
|
+
};
|
|
313
|
+
og: {
|
|
314
|
+
locale: string;
|
|
315
|
+
type: string;
|
|
316
|
+
title: string;
|
|
317
|
+
url: string;
|
|
318
|
+
siteName: string;
|
|
319
|
+
description: string;
|
|
320
|
+
image: {
|
|
321
|
+
url: string;
|
|
322
|
+
width: string;
|
|
323
|
+
height: string;
|
|
324
|
+
type: string;
|
|
325
|
+
alt: string | null;
|
|
326
|
+
} | null;
|
|
327
|
+
};
|
|
328
|
+
twitter: {
|
|
329
|
+
card: "summary" | "summary_large_image";
|
|
330
|
+
title: string;
|
|
331
|
+
site: string | null;
|
|
332
|
+
creator: string | null;
|
|
333
|
+
description: string;
|
|
334
|
+
image: string | null;
|
|
335
|
+
};
|
|
336
|
+
article: {
|
|
337
|
+
publishedTime: string;
|
|
338
|
+
modifiedTime: string;
|
|
339
|
+
author: string;
|
|
340
|
+
authorUrl: string;
|
|
341
|
+
section: string;
|
|
342
|
+
} | null;
|
|
343
|
+
};
|
|
344
|
+
schema: {
|
|
345
|
+
"@context": "https://schema.org";
|
|
346
|
+
"@graph": Record<string, unknown>[];
|
|
347
|
+
};
|
|
348
|
+
}, DefinedErrorMapLike>;
|
|
302
349
|
sitemaps: Procedure<"internal", {}, {
|
|
303
350
|
key: string;
|
|
304
351
|
type: "author" | "post_type" | "taxonomy";
|
package/dist/seo/index.js
CHANGED
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
import { createProcedure } from "../shared/procedure.js";
|
|
2
2
|
import { WP_KIZLO_BASE } from "../wordpress/constants.js";
|
|
3
|
-
import { ListSitemapUrlInput, Robots, SitemapList, SitemapUrlList } from "./schema.js";
|
|
3
|
+
import { ListSitemapUrlInput, Robots, Seo, SitemapList, SitemapUrlList } from "./schema.js";
|
|
4
4
|
|
|
5
5
|
//#region src/seo/index.ts
|
|
6
6
|
const SEO_ROUTER_MAP = {
|
|
7
|
+
homepage: createProcedure({
|
|
8
|
+
scope: "internal",
|
|
9
|
+
output: Seo
|
|
10
|
+
}, async ({ context, errors }) => {
|
|
11
|
+
const response = await context.service.wordpress.get("/seo/homepage", { base: WP_KIZLO_BASE });
|
|
12
|
+
if (response.error) {
|
|
13
|
+
context.logger.error("Get homepage seo unhandled error", response.error);
|
|
14
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
15
|
+
}
|
|
16
|
+
const { head } = response.data;
|
|
17
|
+
return {
|
|
18
|
+
head: {
|
|
19
|
+
title: head.title,
|
|
20
|
+
canonical: head.canonical,
|
|
21
|
+
robots: {
|
|
22
|
+
index: head.robots.index,
|
|
23
|
+
follow: head.robots.follow,
|
|
24
|
+
maxSnippet: head.robots["max-snippet"],
|
|
25
|
+
maxImagePreview: head.robots["max-image-preview"],
|
|
26
|
+
maxVideoPreview: head.robots["max-video-preview"]
|
|
27
|
+
},
|
|
28
|
+
og: {
|
|
29
|
+
locale: head.og.locale,
|
|
30
|
+
type: head.og.type,
|
|
31
|
+
title: head.og.title,
|
|
32
|
+
url: head.og.url,
|
|
33
|
+
siteName: head.og.site_name,
|
|
34
|
+
description: head.og.description ?? "",
|
|
35
|
+
image: head.og.image
|
|
36
|
+
},
|
|
37
|
+
twitter: {
|
|
38
|
+
card: head.twitter.card,
|
|
39
|
+
title: head.twitter.title,
|
|
40
|
+
site: head.twitter.site,
|
|
41
|
+
creator: head.twitter.creator,
|
|
42
|
+
description: head.twitter.description ?? "",
|
|
43
|
+
image: head.twitter.image
|
|
44
|
+
},
|
|
45
|
+
article: head.article && {
|
|
46
|
+
publishedTime: head.article.published_time,
|
|
47
|
+
modifiedTime: head.article.modified_time,
|
|
48
|
+
author: head.article.author,
|
|
49
|
+
authorUrl: head.article.author_url,
|
|
50
|
+
section: head.article.section
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
schema: response.data.schema
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
7
56
|
sitemaps: createProcedure({
|
|
8
57
|
scope: "internal",
|
|
9
58
|
output: SitemapList
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SitemapUrl } from "./schema.js";
|
|
2
|
+
import { SitemapIndexEntry } from "./utils.js";
|
|
3
|
+
import { S2SClient } from "../kizlo.js";
|
|
4
|
+
|
|
5
|
+
//#region src/seo/sitemap.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Every generated sitemap is served from `/sitemaps`: the index at `/sitemaps/index.xml`
|
|
9
|
+
* and each collection page at `/sitemaps/{key}.xml` (later pages `-{n}`). The base is fixed
|
|
10
|
+
* because the index `<loc>` entries (built by `sitemapEntryPath`) point at it, so the route
|
|
11
|
+
* must be mounted there for the links to resolve. How the route is mounted is a
|
|
12
|
+
* framework concern; this handler only cares about the trailing slug.
|
|
13
|
+
*/
|
|
14
|
+
declare const SITEMAP_BASE = "/sitemaps";
|
|
15
|
+
/** Slug that serves the sitemap index (`/sitemaps/index.xml`) rather than a collection. */
|
|
16
|
+
declare const SITEMAP_INDEX_SLUG = "index.xml";
|
|
17
|
+
/**
|
|
18
|
+
* A sitemap not backed by WordPress (e.g. docs pages living in the app). It joins the
|
|
19
|
+
* same index/urlset pipeline: `entry` adds it to the index, `urls` serves its pages.
|
|
20
|
+
*/
|
|
21
|
+
interface SitemapRouteExtra {
|
|
22
|
+
entry: SitemapIndexEntry;
|
|
23
|
+
urls: (origin: string, page: number) => SitemapUrl[] | Promise<SitemapUrl[]>;
|
|
24
|
+
}
|
|
25
|
+
interface CreateSitemapRouteOptions {
|
|
26
|
+
/** Extra, non-WordPress sitemaps to fold into the index and serve. */
|
|
27
|
+
extra?: SitemapRouteExtra[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds a Web `Request` -> `Response` handler that serves the sitemap index
|
|
31
|
+
* (`/sitemaps/index.xml`) and every collection page, merging any `extra` sitemaps in.
|
|
32
|
+
* Framework-agnostic: the slug is the last path segment of the request URL, so this runs
|
|
33
|
+
* as-is on any web-standard server (Hono, a plain fetch handler, a Next route handler).
|
|
34
|
+
* Mounting it at the right path is the caller's job; framework wrappers (e.g. the Next
|
|
35
|
+
* integration) add mount assertions on top.
|
|
36
|
+
*/
|
|
37
|
+
declare function createSitemapRoute(client: S2SClient<[]>, options?: CreateSitemapRouteOptions): (request: Request) => Promise<Response>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { CreateSitemapRouteOptions, SITEMAP_BASE, SITEMAP_INDEX_SLUG, SitemapRouteExtra, createSitemapRoute };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { parseSitemapSlug, renderSitemapIndex, renderUrlSet, xmlResponse } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/seo/sitemap.ts
|
|
4
|
+
/**
|
|
5
|
+
* Every generated sitemap is served from `/sitemaps`: the index at `/sitemaps/index.xml`
|
|
6
|
+
* and each collection page at `/sitemaps/{key}.xml` (later pages `-{n}`). The base is fixed
|
|
7
|
+
* because the index `<loc>` entries (built by `sitemapEntryPath`) point at it, so the route
|
|
8
|
+
* must be mounted there for the links to resolve. How the route is mounted is a
|
|
9
|
+
* framework concern; this handler only cares about the trailing slug.
|
|
10
|
+
*/
|
|
11
|
+
const SITEMAP_BASE = "/sitemaps";
|
|
12
|
+
/** Slug that serves the sitemap index (`/sitemaps/index.xml`) rather than a collection. */
|
|
13
|
+
const SITEMAP_INDEX_SLUG = "index.xml";
|
|
14
|
+
/**
|
|
15
|
+
* Builds a Web `Request` -> `Response` handler that serves the sitemap index
|
|
16
|
+
* (`/sitemaps/index.xml`) and every collection page, merging any `extra` sitemaps in.
|
|
17
|
+
* Framework-agnostic: the slug is the last path segment of the request URL, so this runs
|
|
18
|
+
* as-is on any web-standard server (Hono, a plain fetch handler, a Next route handler).
|
|
19
|
+
* Mounting it at the right path is the caller's job; framework wrappers (e.g. the Next
|
|
20
|
+
* integration) add mount assertions on top.
|
|
21
|
+
*/
|
|
22
|
+
function createSitemapRoute(client, options) {
|
|
23
|
+
const extra = options?.extra ?? [];
|
|
24
|
+
return async function GET(request) {
|
|
25
|
+
const url = new URL(request.url);
|
|
26
|
+
const slug = lastPathSegment(url);
|
|
27
|
+
if (!slug) return notFound();
|
|
28
|
+
const { origin } = url;
|
|
29
|
+
if (slug === SITEMAP_INDEX_SLUG) {
|
|
30
|
+
const { data: data$1 } = await client.seo.sitemaps();
|
|
31
|
+
return xmlResponse(renderSitemapIndex([...data$1 ?? [], ...extra.map((item) => item.entry)], origin));
|
|
32
|
+
}
|
|
33
|
+
const parsed = parseSitemapSlug(slug);
|
|
34
|
+
if (!parsed) return notFound();
|
|
35
|
+
const custom = extra.find((item) => item.entry.key === parsed.key);
|
|
36
|
+
if (custom) {
|
|
37
|
+
if (parsed.page > custom.entry.pages) return notFound();
|
|
38
|
+
return xmlResponse(renderUrlSet(await custom.urls(origin, parsed.page)));
|
|
39
|
+
}
|
|
40
|
+
const { data: sitemaps } = await client.seo.sitemaps();
|
|
41
|
+
if (!sitemaps) return notFound();
|
|
42
|
+
const entry = sitemaps.find((item) => item.key === parsed.key);
|
|
43
|
+
if (!entry || parsed.page > entry.pages) return notFound();
|
|
44
|
+
const { data } = await client.seo.urls(entry.type === "author" ? {
|
|
45
|
+
type: "author",
|
|
46
|
+
page: parsed.page
|
|
47
|
+
} : {
|
|
48
|
+
type: entry.type,
|
|
49
|
+
key: entry.key,
|
|
50
|
+
page: parsed.page
|
|
51
|
+
});
|
|
52
|
+
if (!data) return notFound();
|
|
53
|
+
return xmlResponse(renderUrlSet(data));
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function lastPathSegment(url) {
|
|
57
|
+
return decodeURIComponent(url.pathname.split("/").filter(Boolean).pop() ?? "");
|
|
58
|
+
}
|
|
59
|
+
function notFound() {
|
|
60
|
+
return new Response("Not Found", { status: 404 });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { SITEMAP_BASE, SITEMAP_INDEX_SLUG, createSitemapRoute };
|
package/dist/seo/utils.js
CHANGED
|
@@ -39,6 +39,41 @@ function deserializeSeo(data) {
|
|
|
39
39
|
schema: data.schema
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
function sitemapEntryPath(key, page) {
|
|
43
|
+
return `/sitemaps/${key}${page > 1 ? `-${page}` : ""}.xml`;
|
|
44
|
+
}
|
|
45
|
+
function parseSitemapSlug(slug) {
|
|
46
|
+
const match = /^(.+?)(?:-(\d+))?\.xml$/.exec(slug);
|
|
47
|
+
if (!match) return null;
|
|
48
|
+
const [, key, rawPage] = match;
|
|
49
|
+
const page = rawPage ? Number(rawPage) : 1;
|
|
50
|
+
if (!key || !Number.isInteger(page) || page < 1) return null;
|
|
51
|
+
return {
|
|
52
|
+
key,
|
|
53
|
+
page
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function escapeXml(value) {
|
|
57
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
58
|
+
}
|
|
59
|
+
function renderSitemapIndex(sitemaps, origin) {
|
|
60
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${sitemaps.flatMap((sitemap) => Array.from({ length: sitemap.pages }, (_, index) => {
|
|
61
|
+
return `\t<sitemap>\n\t\t<loc>${escapeXml(`${origin}${sitemapEntryPath(sitemap.key, index + 1)}`)}</loc>\n\t\t<lastmod>${escapeXml(sitemap.lastmod)}</lastmod>\n\t</sitemap>`;
|
|
62
|
+
})).join("\n")}\n</sitemapindex>\n`;
|
|
63
|
+
}
|
|
64
|
+
function renderUrlSet(urls) {
|
|
65
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n${urls.map((url) => {
|
|
66
|
+
const images = url.images.map((image) => `\t\t<image:image>\n\t\t\t<image:loc>${escapeXml(image.loc)}</image:loc>\n\t\t</image:image>`).join("\n");
|
|
67
|
+
const imageBlock = images ? `\n${images}` : "";
|
|
68
|
+
return `\t<url>\n\t\t<loc>${escapeXml(url.loc)}</loc>\n\t\t<lastmod>${escapeXml(url.lastmod)}</lastmod>${imageBlock}\n\t</url>`;
|
|
69
|
+
}).join("\n")}\n</urlset>\n`;
|
|
70
|
+
}
|
|
71
|
+
function xmlResponse(body) {
|
|
72
|
+
return new Response(body, { headers: {
|
|
73
|
+
"Content-Type": "application/xml; charset=utf-8",
|
|
74
|
+
"Cache-Control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400"
|
|
75
|
+
} });
|
|
76
|
+
}
|
|
42
77
|
|
|
43
78
|
//#endregion
|
|
44
|
-
export { deserializeSeo };
|
|
79
|
+
export { deserializeSeo, parseSitemapSlug, renderSitemapIndex, renderUrlSet, xmlResponse };
|
package/dist/shared/error.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LiteralUnion, Metadata, Schema, SchemaInput, SchemaOutput } from "@kizlo/shared";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/error.d.ts
|
|
4
4
|
declare const COMMON_ERRORS: {
|
|
@@ -116,11 +116,11 @@ type ErrorDefinition = {
|
|
|
116
116
|
/** Human-readable message. Overridable per throw via `errors.CODE({ message })`. */
|
|
117
117
|
message?: string;
|
|
118
118
|
/** Standard Schema for the error's `data` payload — validated and typed when you throw `errors.CODE({ data })`. */
|
|
119
|
-
data?:
|
|
119
|
+
data?: Schema;
|
|
120
120
|
};
|
|
121
121
|
declare function defineErrorMap<const T extends Partial<Record<CommonErrorLiteral, ErrorDefinition>>>(map: T): T;
|
|
122
122
|
type DefinedErrorMapLike = Record<string, ErrorDefinition>;
|
|
123
|
-
type ThrowableErrorFn<TCode extends string, T extends ErrorDefinition> = T["data"] extends
|
|
123
|
+
type ThrowableErrorFn<TCode extends string, T extends ErrorDefinition> = T["data"] extends Schema ? undefined extends SchemaInput<T["data"]> ? (options?: {
|
|
124
124
|
status?: number;
|
|
125
125
|
message?: string;
|
|
126
126
|
data?: SchemaInput<T["data"]>;
|
|
@@ -2,7 +2,7 @@ import { DefinedErrorMapLike, ThrowableErrorMap, WithCommonErrorMap } from "./er
|
|
|
2
2
|
import { ServerContext } from "../context.js";
|
|
3
3
|
import { AnyMiddleware, InferUses, Middleware } from "./middleware.js";
|
|
4
4
|
import * as _orpc_contract0 from "@orpc/contract";
|
|
5
|
-
import {
|
|
5
|
+
import { DeepMerge, Pathname, Prettify, Promisify, Schema, SchemaInput, SchemaOutput } from "@kizlo/shared";
|
|
6
6
|
import * as _orpc_server0 from "@orpc/server";
|
|
7
7
|
import { HTTPMethod } from "@orpc/server";
|
|
8
8
|
import { JsonifiedValue } from "@orpc/openapi-client";
|
|
@@ -33,25 +33,25 @@ interface Procedure<TScope extends InvocationScope, TInput, TOutput, TError exte
|
|
|
33
33
|
options: {
|
|
34
34
|
scope: TScope;
|
|
35
35
|
errors?: TError;
|
|
36
|
-
output:
|
|
36
|
+
output: Schema;
|
|
37
37
|
inputValidation?: boolean;
|
|
38
38
|
outputValidation?: boolean;
|
|
39
39
|
middlewares?: AnyMiddleware[];
|
|
40
40
|
} & ({
|
|
41
41
|
scope: "internal";
|
|
42
|
-
input?:
|
|
42
|
+
input?: Schema;
|
|
43
43
|
} | {
|
|
44
44
|
scope: "remote";
|
|
45
|
-
input?:
|
|
45
|
+
input?: Schema;
|
|
46
46
|
method?: HTTPMethod;
|
|
47
47
|
} | {
|
|
48
48
|
scope: "api";
|
|
49
49
|
method?: HTTPMethod;
|
|
50
50
|
path?: Pathname;
|
|
51
|
-
body?:
|
|
52
|
-
query?:
|
|
53
|
-
params?:
|
|
54
|
-
headers?:
|
|
51
|
+
body?: Schema;
|
|
52
|
+
query?: Schema;
|
|
53
|
+
params?: Schema;
|
|
54
|
+
headers?: Schema;
|
|
55
55
|
});
|
|
56
56
|
};
|
|
57
57
|
}
|
|
@@ -112,9 +112,9 @@ type ProcedureOptions<TScope extends InvocationScope, TPathname extends Pathname
|
|
|
112
112
|
input?: TInput;
|
|
113
113
|
});
|
|
114
114
|
declare function createProcedure<TScope extends InvocationScope, TPathname extends Pathname, TInput extends Schema | undefined = undefined, TBody extends Schema | undefined = undefined, TParams extends Schema | undefined = undefined, TQuery extends Schema | undefined = undefined, THeaders extends Schema | undefined = undefined, TOutput extends Schema = Schema, TError extends DefinedErrorMapLike = DefinedErrorMapLike, TMiddlewares extends Middleware<ResolvedSchemaOutput<TScope, TPathname, TInput, TBody, TParams, TQuery, THeaders>, SchemaOutput<TOutput>, TError>[] = Middleware<ResolvedSchemaOutput<TScope, TPathname, TInput, TBody, TParams, TQuery, THeaders>, SchemaOutput<TOutput>, TError>[], TContext extends ProcedureContext<TMiddlewares> = ProcedureContext<TMiddlewares>>(options: ProcedureOptions<TScope, TPathname, TInput, TBody, TParams, TQuery, THeaders, TOutput, TError, TMiddlewares>, handler: ProcedureHandler<ResolvedSchemaOutput<TScope, TPathname, TInput, TBody, TParams, TQuery, THeaders>, SchemaOutput<TOutput>, TError, TContext>): Procedure<TScope, ResolvedSchemaInput<TScope, TPathname, TInput, TBody, TParams, TQuery, THeaders>, TScope extends "api" ? JsonifiedValue<SchemaOutput<TOutput>> : SchemaOutput<TOutput>, TError>;
|
|
115
|
-
declare function schemaType<TInput, TOutput = TInput>(schema?:
|
|
115
|
+
declare function schemaType<TInput, TOutput = TInput>(schema?: Schema): Schema<TInput, TOutput>;
|
|
116
116
|
declare function buildProcedure(procedure: AnyProcedure): _orpc_server0.DecoratedProcedure<_orpc_server0.Context & Record<never, never>, _orpc_server0.Context, _orpc_contract0.Schema<unknown, unknown>, _orpc_contract0.Schema<any, any>, Record<never, never>, Record<never, never>>;
|
|
117
117
|
declare function handleUnexpectedError(error: unknown, errors?: DefinedErrorMapLike): never;
|
|
118
|
-
declare function combineDetailed(parts: Record<string,
|
|
118
|
+
declare function combineDetailed(parts: Record<string, Schema>): Schema;
|
|
119
119
|
//#endregion
|
|
120
120
|
export { AnyProcedure, AnyProcedureRouter, BaseHandlerOptions, ExtractParams, ExtractProcedureByScope, InvocationScope, OpenapiPart, Procedure, ProcedureContext, ProcedureErrors, ProcedureHandler, ProcedureOptions, ResolveParamsPart, ResolvedSchemaInput, ResolvedSchemaOutput, RouterDepthTuple, SchemaIO, buildProcedure, combineDetailed, createProcedure, handleUnexpectedError, schemaType };
|
package/dist/webhook/schema.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
12
12
|
data: z.ZodObject<{
|
|
13
13
|
post_id: z.ZodNumber;
|
|
14
14
|
post_type: z.ZodString;
|
|
15
|
+
url: z.ZodOptional<z.ZodString>;
|
|
15
16
|
}, z.core.$strip>;
|
|
16
17
|
}, z.core.$strip>, z.ZodObject<{
|
|
17
18
|
type: z.ZodEnum<{
|
|
@@ -24,15 +25,7 @@ declare const KizloEvent: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
24
25
|
taxonomy: z.ZodString;
|
|
25
26
|
post_types: z.ZodArray<z.ZodString>;
|
|
26
27
|
count: z.ZodNumber;
|
|
27
|
-
|
|
28
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
29
|
-
type: z.ZodEnum<{
|
|
30
|
-
"payment.status_requested": "payment.status_requested";
|
|
31
|
-
}>;
|
|
32
|
-
data: z.ZodObject<{
|
|
33
|
-
transaction_id: z.ZodNullable<z.ZodString>;
|
|
34
|
-
payment_method_id: z.ZodString;
|
|
35
|
-
payment_session_id: z.ZodString;
|
|
28
|
+
url: z.ZodOptional<z.ZodString>;
|
|
36
29
|
}, z.core.$strip>;
|
|
37
30
|
}, z.core.$strip>, z.ZodObject<{
|
|
38
31
|
type: z.ZodEnum<{
|
package/dist/webhook/schema.js
CHANGED
|
@@ -27,7 +27,8 @@ const EVENT_TYPES = [
|
|
|
27
27
|
const EventType = z.enum(EVENT_TYPES);
|
|
28
28
|
const PostEventData = z.object({
|
|
29
29
|
post_id: z.number(),
|
|
30
|
-
post_type: z.string()
|
|
30
|
+
post_type: z.string(),
|
|
31
|
+
url: z.string().optional()
|
|
31
32
|
});
|
|
32
33
|
const PostEvent = z.object({
|
|
33
34
|
type: PostEventType,
|
|
@@ -37,21 +38,13 @@ const TermEventData = z.object({
|
|
|
37
38
|
term_id: z.number(),
|
|
38
39
|
taxonomy: z.string(),
|
|
39
40
|
post_types: z.array(z.string()),
|
|
40
|
-
count: z.number().nonnegative()
|
|
41
|
+
count: z.number().nonnegative(),
|
|
42
|
+
url: z.string().optional()
|
|
41
43
|
});
|
|
42
44
|
const TermEvent = z.object({
|
|
43
45
|
type: TermEventType,
|
|
44
46
|
data: TermEventData
|
|
45
47
|
});
|
|
46
|
-
const PaymentEventData = z.object({
|
|
47
|
-
transaction_id: z.nullable(z.string()),
|
|
48
|
-
payment_method_id: z.string(),
|
|
49
|
-
payment_session_id: z.string()
|
|
50
|
-
});
|
|
51
|
-
const PaymentEvent = z.object({
|
|
52
|
-
type: PaymentEventType,
|
|
53
|
-
data: PaymentEventData
|
|
54
|
-
});
|
|
55
48
|
const SettingsEventData = z.null();
|
|
56
49
|
const SettingsEvent = z.object({
|
|
57
50
|
type: SettingsEventType,
|
|
@@ -60,7 +53,6 @@ const SettingsEvent = z.object({
|
|
|
60
53
|
const KizloEvent = z.union([
|
|
61
54
|
PostEvent,
|
|
62
55
|
TermEvent,
|
|
63
|
-
PaymentEvent,
|
|
64
56
|
SettingsEvent
|
|
65
57
|
]);
|
|
66
58
|
const AnyEvent = z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kizlo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A headless WordPress toolkit for TypeScript.",
|
|
6
6
|
"keywords": [
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@clack/prompts": "^1.5.1",
|
|
79
|
-
"@kizlo/shared": "0.1.
|
|
79
|
+
"@kizlo/shared": "0.1.2",
|
|
80
80
|
"@orpc/client": "^1.14.3",
|
|
81
81
|
"@orpc/contract": "^1.14.3",
|
|
82
82
|
"@orpc/openapi": "^1.14.3",
|