kizlo 0.17.0 → 0.19.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.
- package/dist/adapters/auth.d.ts +17 -16
- package/dist/adapters/auth.js +4 -5
- package/dist/category/index.js +4 -4
- package/dist/category/schema.d.ts +153 -0
- package/dist/category/schema.js +4 -3
- package/dist/cli/commands/_wiring.js +9 -8
- package/dist/cli/commands/check.js +11 -15
- package/dist/cli/commands/dev.js +3 -3
- package/dist/cli/commands/generate.js +15 -17
- package/dist/cli/commands/test.js +3 -3
- package/dist/cli/daemon/config.js +148 -82
- package/dist/cli/daemon/generate.js +54 -54
- package/dist/cli/daemon/watch.js +41 -54
- package/dist/cli/wp/constants.d.ts +2 -4
- package/dist/cli/wp/constants.js +2 -4
- package/dist/cli/wp/types.d.ts +6 -3
- package/dist/cli/wp/utils.d.ts +3 -3
- package/dist/cli/wp/utils.js +9 -3
- package/dist/comment/errors.js +0 -1
- package/dist/comment/index.js +6 -6
- package/dist/config.d.ts +61 -47
- package/dist/context.d.ts +7 -7
- package/dist/context.js +4 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +8 -3
- package/dist/package.js +1 -1
- package/dist/page/index.js +3 -3
- package/dist/page/schema.d.ts +226 -0
- package/dist/page/schema.js +4 -3
- package/dist/post/index.js +3 -3
- package/dist/post/schema.d.ts +268 -0
- package/dist/post/schema.js +4 -3
- package/dist/procedures.d.ts +35 -902
- package/dist/seo/index.js +1 -1
- package/dist/seo/schema.d.ts +5 -5
- package/dist/shared/contract.d.ts +1 -1
- package/dist/shared/procedure.d.ts +12 -3
- package/dist/shared/procedure.js +4 -0
- package/dist/shared/result.d.ts +16 -7
- package/dist/shared/types.d.ts +1 -1
- package/dist/tag/index.js +3 -3
- package/dist/tag/schema.d.ts +151 -0
- package/dist/tag/schema.js +4 -3
- package/dist/test/auth.js +2 -3
- package/dist/test/users.d.ts +2 -4
- package/dist/test/users.js +4 -9
- package/dist/test.d.ts +2 -2
- package/dist/test.js +2 -2
- package/dist/wordpress/endpoint.js +2 -1
- package/dist/wordpress/error.d.ts +1 -0
- package/dist/wordpress/error.js +2 -0
- package/dist/wordpress/fetch-introspection.js +1 -1
- package/dist/wordpress/generate.js +51 -7
- package/dist/wordpress/index.d.ts +1 -1
- package/dist/wordpress/transport.js +5 -3
- package/dist/wordpress/types.d.ts +38 -12
- package/dist/wordpress/utils.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_WORDPRESS_TAG,
|
|
1
|
+
import { DEFAULT_WORDPRESS_TAG, INTROSPECTION_META_REL, LOCAL_DIR_REL } from "../wp/constants.js";
|
|
2
2
|
import { credentialsPath, findConfigDir } from "../wp/utils.js";
|
|
3
3
|
import { log } from "./logger.js";
|
|
4
4
|
import { detectPackageManager } from "../utils.js";
|
|
@@ -11,39 +11,82 @@ import fs from "node:fs";
|
|
|
11
11
|
//#region src/cli/daemon/config.ts
|
|
12
12
|
const fixtureSchema = z.custom((value) => typeof value === "object" && value !== null && typeof value.name === "string", { message: "must be a fixture object with a string `name` (use defineFixture)" });
|
|
13
13
|
/**
|
|
14
|
-
* `dev.version` / `test.version`. Validated against Docker's tag grammar here rather than
|
|
15
|
-
* so `"wordpress:7.1.0"`, which would resolve to `wordpress:wordpress:7.1.0`, is named as a
|
|
16
|
-
* mistake instead of surfacing as a pull failure seconds into starting a stack.
|
|
14
|
+
* `local.dev.version` / `local.test.version`. Validated against Docker's tag grammar here rather than
|
|
15
|
+
* at boot, so `"wordpress:7.1.0"`, which would resolve to `wordpress:wordpress:7.1.0`, is named as a
|
|
16
|
+
* config mistake instead of surfacing as a pull failure seconds into starting a stack.
|
|
17
17
|
*/
|
|
18
18
|
const versionSchema = z.string().regex(WORDPRESS_TAG_PATTERN, "must be a WordPress image tag, like \"7.1.0\" or \"7.1.0-php8.3-apache\" (no \"wordpress:\" prefix)");
|
|
19
|
+
/**
|
|
20
|
+
* A key that moved in the config redesign. It accepts only `undefined`, so an absent key passes and a
|
|
21
|
+
* present one fails validation with a message naming where it went: a hard cutover with no silent
|
|
22
|
+
* fallback. {@link loadConfigFile} surfaces the message through `z.prettifyError`.
|
|
23
|
+
*/
|
|
24
|
+
const removedKey = (message) => z.undefined({ error: message }).optional();
|
|
25
|
+
const dirSchema = z.union([z.string(), z.object({
|
|
26
|
+
server: z.string().optional(),
|
|
27
|
+
contract: z.string().optional(),
|
|
28
|
+
introspection: z.string().optional()
|
|
29
|
+
})]);
|
|
30
|
+
const devStackSchema = z.object({
|
|
31
|
+
enable: z.boolean().optional(),
|
|
32
|
+
port: z.number().int().positive().optional(),
|
|
33
|
+
version: versionSchema.optional(),
|
|
34
|
+
dbPort: z.number().int().positive().optional(),
|
|
35
|
+
fixtures: z.array(fixtureSchema).optional()
|
|
36
|
+
});
|
|
37
|
+
const testStackSchema = z.object({
|
|
38
|
+
enable: z.boolean().optional(),
|
|
39
|
+
inherit: z.boolean().optional(),
|
|
40
|
+
port: z.number().int().positive().optional(),
|
|
41
|
+
version: versionSchema.optional(),
|
|
42
|
+
fixtures: z.array(fixtureSchema).optional(),
|
|
43
|
+
packageManager: z.enum([
|
|
44
|
+
"npm",
|
|
45
|
+
"pnpm",
|
|
46
|
+
"yarn",
|
|
47
|
+
"bun"
|
|
48
|
+
]).optional(),
|
|
49
|
+
command: z.string().optional()
|
|
50
|
+
});
|
|
51
|
+
const localSchema = z.union([z.boolean(), z.object({
|
|
52
|
+
enable: z.boolean().optional(),
|
|
53
|
+
name: z.string().optional(),
|
|
54
|
+
worktrees: z.boolean().optional(),
|
|
55
|
+
dev: devStackSchema.optional(),
|
|
56
|
+
test: testStackSchema.optional()
|
|
57
|
+
})]);
|
|
19
58
|
/** Runtime shape of `kizlo.config.*` — mirrors {@link KizloGlobalConfig}. */
|
|
20
59
|
const configSchema = z.object({
|
|
21
|
-
dir:
|
|
60
|
+
dir: dirSchema.optional(),
|
|
22
61
|
alias: z.string().optional(),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
version: versionSchema.optional(),
|
|
30
|
-
dbPort: z.number().int().positive().optional(),
|
|
31
|
-
fixtures: z.array(fixtureSchema).optional()
|
|
32
|
-
}).optional(),
|
|
33
|
-
test: z.object({
|
|
34
|
-
local: z.boolean().optional(),
|
|
35
|
-
port: z.number().int().positive().optional(),
|
|
36
|
-
version: versionSchema.optional(),
|
|
37
|
-
fixtures: z.array(fixtureSchema).optional(),
|
|
38
|
-
packageManager: z.enum([
|
|
39
|
-
"npm",
|
|
40
|
-
"pnpm",
|
|
41
|
-
"yarn",
|
|
42
|
-
"bun"
|
|
43
|
-
]).optional(),
|
|
44
|
-
command: z.string().optional()
|
|
45
|
-
}).optional()
|
|
62
|
+
local: localSchema.optional(),
|
|
63
|
+
wordpressClientDir: removedKey("`wordpressClientDir` has been removed. Use `dir: { introspection }` instead."),
|
|
64
|
+
name: removedKey("`name` is no longer a config root key. Move it under `local.name`."),
|
|
65
|
+
worktrees: removedKey("`worktrees` is no longer a config root key. Move it under `local.worktrees`."),
|
|
66
|
+
dev: removedKey("`dev` is no longer a config root key. Move it under `local.dev`."),
|
|
67
|
+
test: removedKey("`test` is no longer a config root key. Move it under `local.test`.")
|
|
46
68
|
});
|
|
69
|
+
/** Normalize `local` (absent, `true`, `false`, or the object form) into one shape the resolvers read. */
|
|
70
|
+
function resolveLocal(fileConfig) {
|
|
71
|
+
const local = fileConfig?.local;
|
|
72
|
+
if (local === true) return {
|
|
73
|
+
enabled: true,
|
|
74
|
+
dev: {},
|
|
75
|
+
test: {}
|
|
76
|
+
};
|
|
77
|
+
if (!local) return {
|
|
78
|
+
enabled: false,
|
|
79
|
+
dev: {},
|
|
80
|
+
test: {}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
enabled: local.enable !== false,
|
|
84
|
+
name: local.name,
|
|
85
|
+
worktrees: local.worktrees,
|
|
86
|
+
dev: local.dev ?? {},
|
|
87
|
+
test: local.test ?? {}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
47
90
|
const CONFIG_FILES = [
|
|
48
91
|
"kizlo.config.ts",
|
|
49
92
|
"kizlo.config.js",
|
|
@@ -52,6 +95,12 @@ const CONFIG_FILES = [
|
|
|
52
95
|
const DEFAULT_DEV_PORT = 8080;
|
|
53
96
|
const DEFAULT_DEV_DB_PORT = 3307;
|
|
54
97
|
const DEFAULT_TEST_PORT = 8889;
|
|
98
|
+
/** The generated introspection artifact's filename, written under its resolved directory. */
|
|
99
|
+
const INTROSPECTION_FILE = "introspection.ts";
|
|
100
|
+
/** Strip a leading `./` and trailing slashes so a config path joins cleanly. */
|
|
101
|
+
function normalizeDir(value) {
|
|
102
|
+
return value.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
103
|
+
}
|
|
55
104
|
async function loadConfigFile(cwd) {
|
|
56
105
|
const file = CONFIG_FILES.map((name) => path.join(cwd, name)).find((p) => fs.existsSync(p));
|
|
57
106
|
if (!file) return void 0;
|
|
@@ -71,40 +120,56 @@ async function loadConfigFile(cwd) {
|
|
|
71
120
|
return result.data;
|
|
72
121
|
}
|
|
73
122
|
/**
|
|
74
|
-
* Resolve
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
123
|
+
* Resolve what Kizlo generates and watches from `dir`: the `--dir` flag or `dir` in `kizlo.config.*`.
|
|
124
|
+
* A string is the home Kizlo owns the layout under (sources in `<dir>/server`, generated files under
|
|
125
|
+
* `<dir>/server/generated`); the object form sets `server` / `contract` / `introspection` independently.
|
|
126
|
+
*
|
|
127
|
+
* The introspection is always generated at its resolved path, so a project with no server still gets it.
|
|
128
|
+
* `server` is present only when `dir` resolves a server path (the string form always does, the object
|
|
129
|
+
* form only when `server` is set), and its absence means there is nothing to watch and no contract to
|
|
130
|
+
* build. Returns `undefined` only when nothing at all is configured (no `dir`, or an object naming
|
|
131
|
+
* neither a server nor an introspection path): there is then nothing to generate.
|
|
79
132
|
*/
|
|
80
133
|
async function resolveConfig(cwd, flags) {
|
|
81
134
|
const fileConfig = await loadConfigFile(cwd);
|
|
82
135
|
const raw = flags?.dir ?? fileConfig?.dir;
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
136
|
+
if (raw === void 0) return void 0;
|
|
137
|
+
if (typeof raw === "string") {
|
|
138
|
+
const home = normalizeDir(raw);
|
|
139
|
+
const serverDir$1 = path.join(home, "server");
|
|
140
|
+
const contractDir$1 = path.join(serverDir$1, "generated");
|
|
141
|
+
return {
|
|
142
|
+
cwd,
|
|
143
|
+
server: {
|
|
144
|
+
dir: serverDir$1,
|
|
145
|
+
entry: path.join(serverDir$1, "index.ts"),
|
|
146
|
+
contractDir: contractDir$1,
|
|
147
|
+
contractPath: path.join(contractDir$1, "contract.json"),
|
|
148
|
+
barrelPath: path.join(contractDir$1, "index.ts")
|
|
149
|
+
},
|
|
150
|
+
introspectionPath: path.join(contractDir$1, INTROSPECTION_FILE),
|
|
151
|
+
introspectionMetaPath: INTROSPECTION_META_REL
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const serverDir = raw.server ? normalizeDir(raw.server) : void 0;
|
|
155
|
+
const contractDir = serverDir ? raw.contract ? normalizeDir(raw.contract) : path.join(serverDir, "generated") : void 0;
|
|
156
|
+
const server = serverDir && contractDir ? {
|
|
157
|
+
dir: serverDir,
|
|
158
|
+
entry: path.join(serverDir, "index.ts"),
|
|
159
|
+
contractDir,
|
|
160
|
+
contractPath: path.join(contractDir, "contract.json"),
|
|
161
|
+
barrelPath: path.join(contractDir, "index.ts")
|
|
162
|
+
} : void 0;
|
|
163
|
+
const introspectionDir = raw.introspection ? normalizeDir(raw.introspection) : contractDir;
|
|
164
|
+
if (!introspectionDir) return void 0;
|
|
87
165
|
return {
|
|
88
166
|
cwd,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
generatedDir,
|
|
93
|
-
contractPath: path.join(generatedDir, "contract.json"),
|
|
94
|
-
barrelPath: path.join(generatedDir, "index.ts"),
|
|
95
|
-
wordpressPath: path.join(generatedDir, "wordpress.ts"),
|
|
96
|
-
wordpressMetaPath: WORDPRESS_META_REL
|
|
167
|
+
server,
|
|
168
|
+
introspectionPath: path.join(introspectionDir, INTROSPECTION_FILE),
|
|
169
|
+
introspectionMetaPath: INTROSPECTION_META_REL
|
|
97
170
|
};
|
|
98
171
|
}
|
|
99
172
|
/**
|
|
100
|
-
* The directory `wordpress.ts` is written to for a workspace with no Kizlo server, from `wordpressClientDir`
|
|
101
|
-
* in `kizlo.config.*`. Resolved on its own rather than through {@link resolveConfig}, which describes a
|
|
102
|
-
* server layout and returns nothing without `dir` — the two are independent.
|
|
103
|
-
*/
|
|
104
|
-
async function resolveWordPressClientDir(cwd) {
|
|
105
|
-
return (await loadConfigFile(cwd))?.wordpressClientDir;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
173
|
* Sanitize an arbitrary package/dir name into a valid Docker compose project id:
|
|
109
174
|
* lowercase, `@scope/pkg` → `scope-pkg`, dropping anything outside `[a-z0-9_-]`.
|
|
110
175
|
*/
|
|
@@ -164,61 +229,62 @@ function stackProject(baseName, kind) {
|
|
|
164
229
|
return `kizlo-${baseName}-${kind}`;
|
|
165
230
|
}
|
|
166
231
|
/**
|
|
167
|
-
* Resolve the
|
|
168
|
-
*
|
|
169
|
-
* and
|
|
232
|
+
* Resolve the test stack (`local.test`) into concrete values for the `test` command, applying defaults
|
|
233
|
+
* (port 8889, auto-detected package manager) and anchoring the credentials artifact to the config
|
|
234
|
+
* directory. `version` and `fixtures` fall back to the dev stack unless `test.inherit` is `false`;
|
|
235
|
+
* `port`, `packageManager`, and `command` are never inherited.
|
|
170
236
|
*/
|
|
171
237
|
async function resolveTestConfig(cwd) {
|
|
172
238
|
const configDir = findConfigDir(cwd);
|
|
173
|
-
const
|
|
174
|
-
const
|
|
239
|
+
const local = resolveLocal(await loadConfigFile(configDir));
|
|
240
|
+
const { dev, test } = local;
|
|
241
|
+
const inherit = test.inherit !== false;
|
|
175
242
|
return {
|
|
176
243
|
configDir,
|
|
177
|
-
local:
|
|
244
|
+
local: local.enabled && test.enable !== false,
|
|
178
245
|
project: stackProject(resolveStackName(configDir, {
|
|
179
|
-
name:
|
|
180
|
-
worktrees:
|
|
246
|
+
name: local.name,
|
|
247
|
+
worktrees: local.worktrees
|
|
181
248
|
}), "test"),
|
|
182
249
|
command: test.command,
|
|
183
250
|
port: test.port ?? DEFAULT_TEST_PORT,
|
|
184
|
-
portExplicit: test.port !== void 0 && !
|
|
185
|
-
wordpressTag: test.version ?? DEFAULT_WORDPRESS_TAG,
|
|
186
|
-
fixtures: test.fixtures ?? [],
|
|
251
|
+
portExplicit: test.port !== void 0 && !local.worktrees,
|
|
252
|
+
wordpressTag: test.version ?? (inherit ? dev.version : void 0) ?? DEFAULT_WORDPRESS_TAG,
|
|
253
|
+
fixtures: test.fixtures ?? (inherit ? dev.fixtures : void 0) ?? [],
|
|
187
254
|
credentialsPath: credentialsPath(cwd),
|
|
188
255
|
packageManager: test.packageManager ?? await detectPackageManager(configDir) ?? "npm"
|
|
189
256
|
};
|
|
190
257
|
}
|
|
191
258
|
/**
|
|
192
|
-
* Whether this project runs local WordPress under `kizlo dev
|
|
193
|
-
* `kizlo.config.*`. When false, `kizlo dev` has nothing to boot and
|
|
194
|
-
* the path a project pointing at its own WordPress takes.
|
|
195
|
-
* local WordPress is chosen,
|
|
196
|
-
* survives `kizlo dev reset`.
|
|
259
|
+
* Whether this project runs local WordPress under `kizlo dev`: local is enabled and the dev stack is
|
|
260
|
+
* on (`local.dev.enable !== false`) in `kizlo.config.*`. When false, `kizlo dev` has nothing to boot and
|
|
261
|
+
* runs the contract watcher alone, the path a project pointing at its own WordPress takes. Written by
|
|
262
|
+
* `create`/`init` when local WordPress is chosen, so it's committed and survives `kizlo dev reset`.
|
|
197
263
|
*/
|
|
198
264
|
async function usesLocalWordPress(cwd) {
|
|
199
|
-
const
|
|
200
|
-
return
|
|
265
|
+
const local = resolveLocal(await loadConfigFile(findConfigDir(cwd)));
|
|
266
|
+
return local.enabled && local.dev.enable !== false;
|
|
201
267
|
}
|
|
202
268
|
/**
|
|
203
|
-
* Resolve the
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
269
|
+
* Resolve the dev stack (`local.dev`) into concrete values for the `dev` command, applying defaults
|
|
270
|
+
* (port 8080). The install folder is fixed at `.kizlo/local` (no longer a config choice), so there's
|
|
271
|
+
* nothing required here. Callers gate on {@link usesLocalWordPress} first, since a project without
|
|
272
|
+
* local WordPress runs the watcher alone rather than reaching here.
|
|
207
273
|
*/
|
|
208
274
|
async function resolveDevConfig(cwd) {
|
|
209
275
|
const configDir = findConfigDir(cwd);
|
|
210
|
-
const
|
|
211
|
-
const dev =
|
|
276
|
+
const local = resolveLocal(await loadConfigFile(configDir));
|
|
277
|
+
const { dev } = local;
|
|
212
278
|
return {
|
|
213
279
|
configDir,
|
|
214
280
|
project: stackProject(resolveStackName(configDir, {
|
|
215
|
-
name:
|
|
216
|
-
worktrees:
|
|
281
|
+
name: local.name,
|
|
282
|
+
worktrees: local.worktrees
|
|
217
283
|
}), "dev"),
|
|
218
284
|
port: dev.port ?? DEFAULT_DEV_PORT,
|
|
219
|
-
portExplicit: dev.port !== void 0 && !
|
|
285
|
+
portExplicit: dev.port !== void 0 && !local.worktrees,
|
|
220
286
|
dbPort: dev.dbPort ?? DEFAULT_DEV_DB_PORT,
|
|
221
|
-
dbPortExplicit: dev.dbPort !== void 0 && !
|
|
287
|
+
dbPortExplicit: dev.dbPort !== void 0 && !local.worktrees,
|
|
222
288
|
wordpressTag: dev.version ?? DEFAULT_WORDPRESS_TAG,
|
|
223
289
|
fixtures: dev.fixtures ?? [],
|
|
224
290
|
wordpressPath: LOCAL_DIR_REL,
|
|
@@ -227,4 +293,4 @@ async function resolveDevConfig(cwd) {
|
|
|
227
293
|
}
|
|
228
294
|
|
|
229
295
|
//#endregion
|
|
230
|
-
export { CONFIG_FILES, DEFAULT_DEV_DB_PORT, DEFAULT_DEV_PORT, resolveConfig, resolveDevConfig, resolveStackName, resolveTestConfig,
|
|
296
|
+
export { CONFIG_FILES, DEFAULT_DEV_DB_PORT, DEFAULT_DEV_PORT, resolveConfig, resolveDevConfig, resolveStackName, resolveTestConfig, stackProject, usesLocalWordPress };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { generateContract } from "../../shared/contract.js";
|
|
2
2
|
import { integrationEnv, resolveWordPressConnection } from "../../kizlo.js";
|
|
3
|
-
import { WORDPRESS_CLIENT_META_REL } from "../wp/constants.js";
|
|
4
3
|
import { node } from "../../integrations/node/integration.js";
|
|
5
4
|
import { log } from "./logger.js";
|
|
6
5
|
import { loadEnvFiles } from "../utils.js";
|
|
@@ -24,7 +23,7 @@ const CONTRACT_BARREL = [
|
|
|
24
23
|
`import contractJson from "./contract.json"`,
|
|
25
24
|
``,
|
|
26
25
|
`export const contract = contractJson as unknown as typeof procedures`,
|
|
27
|
-
`export { endpoints, type WordPressClient } from "./
|
|
26
|
+
`export { endpoints, type WordPressClient } from "./introspection"`,
|
|
28
27
|
``
|
|
29
28
|
].join("\n");
|
|
30
29
|
var LegacyRouterExportError = class extends Error {
|
|
@@ -34,13 +33,13 @@ var LegacyRouterExportError = class extends Error {
|
|
|
34
33
|
}
|
|
35
34
|
};
|
|
36
35
|
/**
|
|
37
|
-
* `
|
|
36
|
+
* `introspection.ts` before the first generation. WordPress is reachable but untyped until then, so a
|
|
38
37
|
* freshly scaffolded project compiles, including Kizlo's own procedures, before it has ever
|
|
39
|
-
* connected. `kizlo dev` / `kizlo generate` replaces this with the real
|
|
40
|
-
* empty tree on purpose: every endpoint a procedure names has to resolve to something until the
|
|
38
|
+
* connected. `kizlo dev` / `kizlo generate` replaces this with the real introspection. `any` rather than
|
|
39
|
+
* an empty tree on purpose: every endpoint a procedure names has to resolve to something until the
|
|
41
40
|
* real shapes arrive, which `WP_Client` preserves by passing `any` through.
|
|
42
41
|
*/
|
|
43
|
-
const
|
|
42
|
+
const INTROSPECTION_STUB = [
|
|
44
43
|
`import type { WP_Client } from "kizlo"`,
|
|
45
44
|
``,
|
|
46
45
|
`export const endpoints = {} as any`,
|
|
@@ -51,6 +50,12 @@ const WORDPRESS_STUB = [
|
|
|
51
50
|
`\tinterface WordPressClientRegistry {`,
|
|
52
51
|
`\t\tendpoints: typeof endpoints`,
|
|
53
52
|
`\t}`,
|
|
53
|
+
`\tinterface WordPressEndpointRegistry {`,
|
|
54
|
+
`\t\t[path: string]: any`,
|
|
55
|
+
`\t}`,
|
|
56
|
+
`\tinterface WordPressCustomFieldsRegistry {`,
|
|
57
|
+
`\t\t[path: string]: Record<string, unknown>`,
|
|
58
|
+
`\t}`,
|
|
54
59
|
`}`,
|
|
55
60
|
``
|
|
56
61
|
].join("\n");
|
|
@@ -117,8 +122,8 @@ function formatDiagnostic(diagnostic) {
|
|
|
117
122
|
* partial contract is worth is the generator's call rather than the transport's. Taking it is the
|
|
118
123
|
* default: a third-party plugin's broken declaration then costs its own routes and nothing else,
|
|
119
124
|
* where refusing the document costs the project every route that still works, for a mistake in code
|
|
120
|
-
* it does not own. Strict generation makes the opposite trade for CI, where
|
|
121
|
-
* of routes typechecks clean and ships the gap.
|
|
125
|
+
* it does not own. Strict generation makes the opposite trade for CI, where an introspection silently
|
|
126
|
+
* short of routes typechecks clean and ships the gap.
|
|
122
127
|
*/
|
|
123
128
|
var PartialContractError = class extends Error {
|
|
124
129
|
excluded;
|
|
@@ -149,7 +154,7 @@ function reportDiagnostics(document, strict) {
|
|
|
149
154
|
const excluded = new Set(document.diagnostics.filter((diagnostic) => diagnostic.type === "error").map(diagnosticLocation));
|
|
150
155
|
if (!excluded.size) return;
|
|
151
156
|
if (strict) throw new PartialContractError(excluded.size);
|
|
152
|
-
log.warn(`Generating without the ${excluded.size} excluded ${excluded.size === 1 ? "contribution" : "contributions"} above. Their routes and types are missing from the
|
|
157
|
+
log.warn(`Generating without the ${excluded.size} excluded ${excluded.size === 1 ? "contribution" : "contributions"} above. Their routes and types are missing from the introspection; \`kizlo generate --strict\` refuses the contract instead.`);
|
|
153
158
|
}
|
|
154
159
|
/**
|
|
155
160
|
* Plugin versions already named as outdated. `kizlo dev` refetches every few seconds, and the answer
|
|
@@ -183,74 +188,69 @@ async function fetchDocument(cwd, options, etag) {
|
|
|
183
188
|
return result;
|
|
184
189
|
}
|
|
185
190
|
/**
|
|
186
|
-
* Produce the
|
|
191
|
+
* Produce the introspection source without writing it or its ETag cache. Health checks use this to ask
|
|
187
192
|
* the same generator as `kizlo generate` what should be on disk, while leaving a contributor's
|
|
188
193
|
* checkout untouched. Callers choose strictness just as generation does.
|
|
189
194
|
*/
|
|
190
|
-
async function
|
|
195
|
+
async function generateIntrospectionSource(cwd, options = {}) {
|
|
191
196
|
const result = await fetchDocument(cwd, options);
|
|
192
197
|
if (!result?.document) throw new Error("WordPress introspection returned no document.");
|
|
193
198
|
const generated = generateWordPressModule(result.document);
|
|
194
199
|
await assertGeneratedClientCompiles(generated);
|
|
195
200
|
return generated.source;
|
|
196
201
|
}
|
|
197
|
-
async function generateWordPressOnce(cfg, options = {}) {
|
|
198
|
-
const etag = readWordPressMeta(path.resolve(cfg.cwd, cfg.wordpressMetaPath), path.resolve(cfg.cwd, cfg.wordpressPath))?.etag;
|
|
199
|
-
const result = await fetchDocument(cfg.cwd, options, etag);
|
|
200
|
-
if (!result?.document) return "unchanged";
|
|
201
|
-
const generated = generateWordPressModule(result.document);
|
|
202
|
-
await assertGeneratedClientCompiles(generated);
|
|
203
|
-
writeGeneratedWordPress(cfg, generated.source, wordPressMeta(result.etag, result.document.hash));
|
|
204
|
-
return "generated";
|
|
205
|
-
}
|
|
206
202
|
/**
|
|
207
|
-
* Write
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* class, so reaching for the runtime later needs no regeneration.
|
|
203
|
+
* Write `introspection.ts` at its resolved path, revalidating against the ETag cache. The one place
|
|
204
|
+
* the introspection reaches disk, whether or not the project has a server: a server-backed app writes
|
|
205
|
+
* it under `generated/`, and a package that only ships procedures writes it at its own `dir.introspection`.
|
|
211
206
|
*/
|
|
212
|
-
async function
|
|
213
|
-
const file = path.resolve(cwd,
|
|
214
|
-
const metaPath = path.resolve(cwd,
|
|
215
|
-
const result = await fetchDocument(cwd, options, readWordPressMeta(metaPath, file)?.etag);
|
|
207
|
+
async function generateIntrospectionOnce(cfg, options = {}) {
|
|
208
|
+
const file = path.resolve(cfg.cwd, cfg.introspectionPath);
|
|
209
|
+
const metaPath = path.resolve(cfg.cwd, cfg.introspectionMetaPath);
|
|
210
|
+
const result = await fetchDocument(cfg.cwd, options, readWordPressMeta(metaPath, file)?.etag);
|
|
216
211
|
if (!result?.document) return "unchanged";
|
|
217
212
|
const generated = generateWordPressModule(result.document);
|
|
218
213
|
await assertGeneratedClientCompiles(generated);
|
|
219
|
-
|
|
214
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
220
215
|
fs.mkdirSync(path.dirname(metaPath), { recursive: true });
|
|
216
|
+
atomicWrite(file, generated.source);
|
|
221
217
|
atomicWrite(metaPath, wordPressMeta(result.etag, result.document.hash));
|
|
222
|
-
if (fs.existsSync(file) && fs.readFileSync(file, "utf8") === contents) return "unchanged";
|
|
223
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
224
|
-
atomicWrite(file, contents);
|
|
225
218
|
return "generated";
|
|
226
219
|
}
|
|
227
|
-
function writeGeneratedWordPress(cfg, client, meta) {
|
|
228
|
-
const metaPath = path.resolve(cfg.cwd, cfg.wordpressMetaPath);
|
|
229
|
-
fs.mkdirSync(path.resolve(cfg.cwd, cfg.generatedDir), { recursive: true });
|
|
230
|
-
fs.mkdirSync(path.dirname(metaPath), { recursive: true });
|
|
231
|
-
atomicWrite(path.resolve(cfg.cwd, cfg.wordpressPath), client);
|
|
232
|
-
atomicWrite(metaPath, meta);
|
|
233
|
-
}
|
|
234
220
|
/**
|
|
235
|
-
*
|
|
236
|
-
*
|
|
221
|
+
* Generate everything `dir` resolves: the introspection always, plus the contract and barrel when a
|
|
222
|
+
* server is present. The server is loaded before the introspection is fetched, so a legacy `router`
|
|
223
|
+
* export is named as a migration error even with WordPress unreachable; a server whose entry exports no
|
|
224
|
+
* `procedures` still gets its introspection, and reports `contract: "empty"`.
|
|
237
225
|
*/
|
|
238
226
|
async function generateOnce(cfg, options = {}) {
|
|
239
227
|
loadEnvFiles(cfg.cwd);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
228
|
+
let procedures;
|
|
229
|
+
if (cfg.server) {
|
|
230
|
+
const entry = path.resolve(cfg.cwd, cfg.server.entry);
|
|
231
|
+
const server = await importIgnoringVirtualModules(cfg.cwd, entry);
|
|
232
|
+
if (!server.procedures && server.router) throw new LegacyRouterExportError(cfg.server.entry);
|
|
233
|
+
procedures = server.procedures;
|
|
245
234
|
}
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (
|
|
252
|
-
|
|
235
|
+
const introspection = await generateIntrospectionOnce(cfg, options);
|
|
236
|
+
if (!cfg.server) return {
|
|
237
|
+
introspection,
|
|
238
|
+
contract: "none"
|
|
239
|
+
};
|
|
240
|
+
if (!procedures) return {
|
|
241
|
+
introspection,
|
|
242
|
+
contract: "empty"
|
|
243
|
+
};
|
|
244
|
+
const contract = JSON.stringify(await generateContract(procedures));
|
|
245
|
+
fs.mkdirSync(path.resolve(cfg.cwd, cfg.server.contractDir), { recursive: true });
|
|
246
|
+
atomicWrite(path.resolve(cfg.cwd, cfg.server.contractPath), contract);
|
|
247
|
+
atomicWrite(path.resolve(cfg.cwd, cfg.server.barrelPath), CONTRACT_BARREL);
|
|
248
|
+
if (introspection === "generated") log.success("WordPress introspection generated");
|
|
249
|
+
return {
|
|
250
|
+
introspection,
|
|
251
|
+
contract: "built"
|
|
252
|
+
};
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
//#endregion
|
|
256
|
-
export { CONTRACT_BARREL,
|
|
256
|
+
export { CONTRACT_BARREL, INTROSPECTION_STUB, PartialContractError, generateIntrospectionOnce, generateIntrospectionSource, generateOnce, reportGenerationError };
|