@mokup/cli 1.0.11 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,18 +3,22 @@
3
3
  const node_fs = require('node:fs');
4
4
  const process = require('node:process');
5
5
  const pathe = require('@mokup/shared/pathe');
6
+ const configUtils = require('@mokup/shared/config-utils');
7
+ const moduleLoader = require('@mokup/shared/module-loader');
8
+ const routeConstants = require('@mokup/shared/route-constants');
9
+ const mockFiles = require('@mokup/shared/mock-files');
10
+ const scanUtils = require('@mokup/shared/scan-utils');
11
+ const pathUtils = require('@mokup/shared/path-utils');
6
12
  const node_buffer = require('node:buffer');
7
- const node_module = require('node:module');
8
- const node_url = require('node:url');
9
13
  const esbuild = require('@mokup/shared/esbuild');
10
- const pathUtils = require('@mokup/shared/path-utils');
11
14
  const runtime = require('@mokup/runtime');
12
- const jsoncParser = require('@mokup/shared/jsonc-parser');
15
+ const routeUtils$1 = require('@mokup/shared/route-utils');
16
+ const loadRules$1 = require('@mokup/shared/load-rules');
17
+ const defineConfig$1 = require('@mokup/shared/define-config');
13
18
  const node = require('@mokup/server/node');
14
19
  const logger$1 = require('@mokup/shared/logger');
15
20
  const commander = require('commander');
16
21
 
17
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18
22
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
19
23
 
20
24
  const process__default = /*#__PURE__*/_interopDefaultCompat(process);
@@ -75,259 +79,48 @@ async function writeManifestModule(outDir, manifest) {
75
79
  await node_fs.promises.writeFile(pathe.join(outDir, "mokup.manifest.d.mts"), dts.join("\n"), "utf8");
76
80
  }
77
81
 
78
- const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
79
- const middlewareSymbol$1 = Symbol.for("mokup.config.middlewares");
80
- async function loadModule$1(file) {
81
- const ext = configExtensions.find((extension) => file.endsWith(extension));
82
- if (ext === ".cjs") {
83
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
84
- delete require$1.cache[file];
85
- return require$1(file);
86
- }
87
- if (ext === ".js" || ext === ".mjs") {
88
- return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
89
- }
90
- if (ext === ".ts") {
91
- const result = await esbuild.build({
92
- entryPoints: [file],
93
- bundle: true,
94
- format: "esm",
95
- platform: "node",
96
- sourcemap: "inline",
97
- target: "es2020",
98
- write: false
99
- });
100
- const output = result.outputFiles[0];
101
- const code = output?.text ?? "";
102
- const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
103
- "base64"
104
- )}`;
105
- return import(`${dataUrl}#${Date.now()}`);
106
- }
107
- return null;
108
- }
109
- function getConfigFileCandidates(dir) {
110
- return configExtensions.map((extension) => pathe.join(dir, `index.config${extension}`));
111
- }
112
- async function findConfigFile(dir, cache) {
113
- const cached = cache.get(dir);
114
- if (cached !== void 0) {
115
- return cached;
116
- }
117
- for (const candidate of getConfigFileCandidates(dir)) {
118
- try {
119
- await node_fs.promises.stat(candidate);
120
- cache.set(dir, candidate);
121
- return candidate;
122
- } catch {
123
- continue;
124
- }
125
- }
126
- cache.set(dir, null);
127
- return null;
128
- }
129
82
  async function loadConfig(file) {
130
- const mod = await loadModule$1(file);
83
+ const mod = await moduleLoader.loadModule(file);
131
84
  if (!mod) {
132
85
  return null;
133
86
  }
134
- const value = mod?.default ?? mod;
87
+ const raw = mod?.default ?? mod;
88
+ const value = configUtils.isPromise(raw) ? await raw : raw;
135
89
  if (!value || typeof value !== "object") {
136
90
  return null;
137
91
  }
138
92
  return value;
139
93
  }
140
- function normalizeMiddlewares(value, source, log, position) {
141
- if (!value) {
142
- return [];
143
- }
144
- const list = Array.isArray(value) ? value : [value];
145
- const middlewares = [];
146
- list.forEach((entry, index) => {
147
- if (typeof entry !== "function") {
148
- log?.(`Invalid middleware in ${source}`);
149
- return;
150
- }
151
- middlewares.push({ file: source, index, position });
152
- });
153
- return middlewares;
154
- }
155
- function readMiddlewareMeta(config) {
156
- const value = config[middlewareSymbol$1];
157
- if (!value || typeof value !== "object") {
158
- return null;
159
- }
160
- const meta = value;
161
- return {
162
- pre: Array.isArray(meta.pre) ? meta.pre : [],
163
- normal: Array.isArray(meta.normal) ? meta.normal : [],
164
- post: Array.isArray(meta.post) ? meta.post : []
165
- };
166
- }
167
94
  async function resolveDirectoryConfig(params) {
168
95
  const { file, rootDir, log, configCache, fileCache } = params;
169
- const resolvedRoot = pathe.normalize(rootDir);
170
- const resolvedFileDir = pathe.normalize(pathe.dirname(file));
171
- const chain = [];
172
- let current = resolvedFileDir;
173
- while (true) {
174
- chain.push(current);
175
- if (current === resolvedRoot) {
176
- break;
177
- }
178
- const parent = pathe.dirname(current);
179
- if (parent === current) {
180
- break;
181
- }
182
- current = parent;
183
- }
184
- chain.reverse();
185
- const merged = {};
186
- const preMiddlewares = [];
187
- const normalMiddlewares = [];
188
- const postMiddlewares = [];
189
- for (const dir of chain) {
190
- const configPath = await findConfigFile(dir, fileCache);
191
- if (!configPath) {
192
- continue;
193
- }
194
- let config = configCache.get(configPath);
195
- if (config === void 0) {
196
- config = await loadConfig(configPath);
197
- configCache.set(configPath, config);
198
- }
199
- if (!config) {
200
- log?.(`Invalid config in ${configPath}`);
201
- continue;
202
- }
203
- if (config.headers) {
204
- merged.headers = { ...merged.headers ?? {}, ...config.headers };
205
- }
206
- if (typeof config.status === "number") {
207
- merged.status = config.status;
208
- }
209
- if (typeof config.delay === "number") {
210
- merged.delay = config.delay;
211
- }
212
- if (typeof config.enabled === "boolean") {
213
- merged.enabled = config.enabled;
214
- }
215
- if (typeof config.ignorePrefix !== "undefined") {
216
- merged.ignorePrefix = config.ignorePrefix;
217
- }
218
- if (typeof config.include !== "undefined") {
219
- merged.include = config.include;
220
- }
221
- if (typeof config.exclude !== "undefined") {
222
- merged.exclude = config.exclude;
223
- }
224
- const meta = readMiddlewareMeta(config);
225
- const normalizedPre = normalizeMiddlewares(
226
- meta?.pre,
227
- configPath,
228
- log,
229
- "pre"
230
- );
231
- const normalizedNormal = normalizeMiddlewares(
232
- meta?.normal,
233
- configPath,
234
- log,
235
- "normal"
236
- );
237
- const normalizedLegacy = normalizeMiddlewares(
238
- config.middleware,
239
- configPath,
240
- log,
241
- "normal"
242
- );
243
- const normalizedPost = normalizeMiddlewares(
244
- meta?.post,
245
- configPath,
246
- log,
247
- "post"
248
- );
249
- if (normalizedPre.length > 0) {
250
- preMiddlewares.push(...normalizedPre);
251
- }
252
- if (normalizedNormal.length > 0) {
253
- normalMiddlewares.push(...normalizedNormal);
254
- }
255
- if (normalizedLegacy.length > 0) {
256
- normalMiddlewares.push(...normalizedLegacy);
257
- }
258
- if (normalizedPost.length > 0) {
259
- postMiddlewares.push(...normalizedPost);
260
- }
261
- }
96
+ const resolved = await configUtils.resolveDirectoryConfig({
97
+ file,
98
+ rootDir,
99
+ configExtensions: routeConstants.configExtensions,
100
+ configCache,
101
+ fileCache,
102
+ loadConfig,
103
+ warn: log,
104
+ mapMiddleware: (_handler, index, position, source) => ({
105
+ file: source,
106
+ index,
107
+ position
108
+ })
109
+ });
262
110
  return {
263
- ...merged,
264
- middlewares: [...preMiddlewares, ...normalMiddlewares, ...postMiddlewares]
111
+ headers: resolved.headers,
112
+ status: resolved.status,
113
+ delay: resolved.delay,
114
+ enabled: resolved.enabled,
115
+ ignorePrefix: resolved.ignorePrefix,
116
+ include: resolved.include,
117
+ exclude: resolved.exclude,
118
+ middlewares: resolved.middlewares
265
119
  };
266
120
  }
267
121
 
268
- const supportedExtensions = /* @__PURE__ */ new Set([
269
- ".json",
270
- ".jsonc",
271
- ".ts",
272
- ".js",
273
- ".mjs",
274
- ".cjs"
275
- ]);
276
- async function exists(path) {
277
- try {
278
- await node_fs.promises.stat(path);
279
- return true;
280
- } catch {
281
- return false;
282
- }
283
- }
284
- async function walkDir(dir, rootDir, files) {
285
- const entries = await node_fs.promises.readdir(dir, { withFileTypes: true });
286
- for (const entry of entries) {
287
- if (entry.name === "node_modules" || entry.name === ".git") {
288
- continue;
289
- }
290
- const fullPath = pathe.join(dir, entry.name);
291
- if (entry.isDirectory()) {
292
- await walkDir(fullPath, rootDir, files);
293
- continue;
294
- }
295
- if (entry.isFile()) {
296
- files.push({ file: fullPath, rootDir });
297
- }
298
- }
299
- }
300
- async function collectFiles(dirs) {
301
- const files = [];
302
- for (const dir of dirs) {
303
- if (!await exists(dir)) {
304
- continue;
305
- }
306
- await walkDir(dir, dir, files);
307
- }
308
- return files;
309
- }
310
122
  function resolveDirs(dir, root) {
311
- const raw = dir;
312
- const resolved = Array.isArray(raw) ? raw : raw ? [raw] : ["mock"];
313
- const normalized = resolved.map(
314
- (entry) => pathe.isAbsolute(entry) ? entry : pathe.resolve(root, entry)
315
- );
316
- return Array.from(new Set(normalized));
317
- }
318
- function normalizeIgnorePrefix(value, fallback = ["."]) {
319
- const list = typeof value === "undefined" ? fallback : Array.isArray(value) ? value : [value];
320
- return list.filter((entry) => typeof entry === "string" && entry.length > 0);
321
- }
322
- function isSupportedFile(file) {
323
- if (file.endsWith(".d.ts")) {
324
- return false;
325
- }
326
- if (pathe.basename(file).startsWith("index.config.")) {
327
- return false;
328
- }
329
- const ext = pathe.extname(file).toLowerCase();
330
- return supportedExtensions.has(ext);
123
+ return scanUtils.resolveDirs(dir, root);
331
124
  }
332
125
 
333
126
  function getHandlerModulePath(file, handlersDir, root) {
@@ -429,119 +222,28 @@ async function bundleHandlers(files, root, handlersDir) {
429
222
  });
430
223
  }
431
224
 
432
- const methodSet = /* @__PURE__ */ new Set([
433
- "GET",
434
- "POST",
435
- "PUT",
436
- "PATCH",
437
- "DELETE",
438
- "OPTIONS",
439
- "HEAD"
440
- ]);
441
- const methodSuffixSet = new Set(
442
- Array.from(methodSet, (method) => method.toLowerCase())
443
- );
444
- const jsonExtensions = /* @__PURE__ */ new Set([".json", ".jsonc"]);
445
- function normalizePrefix(prefix) {
446
- if (!prefix) {
447
- return "";
448
- }
449
- const normalized = prefix.startsWith("/") ? prefix : `/${prefix}`;
450
- return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
451
- }
452
- function resolveTemplate(template, prefix) {
453
- const normalized = template.startsWith("/") ? template : `/${template}`;
454
- if (!prefix) {
455
- return normalized;
456
- }
457
- const normalizedPrefix = normalizePrefix(prefix);
458
- if (!normalizedPrefix) {
459
- return normalized;
460
- }
461
- if (normalized === normalizedPrefix || normalized.startsWith(`${normalizedPrefix}/`)) {
462
- return normalized;
463
- }
464
- if (normalized === "/") {
465
- return `${normalizedPrefix}/`;
466
- }
467
- return `${normalizedPrefix}${normalized}`;
468
- }
469
- function stripMethodSuffix(base) {
470
- const segments = base.split(".");
471
- const last = segments.at(-1);
472
- if (last && methodSuffixSet.has(last.toLowerCase())) {
473
- segments.pop();
474
- return {
475
- name: segments.join("."),
476
- method: last.toUpperCase()
477
- };
478
- }
479
- return {
480
- name: base,
481
- method: void 0
482
- };
483
- }
225
+ const routeUtils = routeUtils$1.createRouteUtils({
226
+ parseRouteTemplate: runtime.parseRouteTemplate,
227
+ compareRouteScore: runtime.compareRouteScore
228
+ });
484
229
  function deriveRouteFromFile(file, rootDir, log) {
485
- const rel = pathUtils.toPosix(pathe.relative(rootDir, file));
486
- const ext = pathe.extname(rel);
487
- const withoutExt = rel.slice(0, rel.length - ext.length);
488
- const dir = pathe.dirname(withoutExt);
489
- const base = pathe.basename(withoutExt);
490
- const { name, method } = stripMethodSuffix(base);
491
- const resolvedMethod = method ?? (jsonExtensions.has(ext) ? "GET" : void 0);
492
- if (!resolvedMethod) {
493
- log?.(`Skip mock without method suffix: ${file}`);
494
- return null;
495
- }
496
- if (!name) {
497
- log?.(`Skip mock with empty route name: ${file}`);
498
- return null;
499
- }
500
- const joined = dir === "." ? name : pathe.join(dir, name);
501
- const segments = pathUtils.toPosix(joined).split("/");
502
- if (segments.at(-1) === "index") {
503
- segments.pop();
504
- }
505
- const template = segments.length === 0 ? "/" : `/${segments.join("/")}`;
506
- const parsed = runtime.parseRouteTemplate(template);
507
- if (parsed.errors.length > 0) {
508
- for (const error of parsed.errors) {
509
- log?.(`${error} in ${file}`);
510
- }
511
- return null;
512
- }
513
- for (const warning of parsed.warnings) {
514
- log?.(`${warning} in ${file}`);
515
- }
516
- return {
517
- template: parsed.template,
518
- method: resolvedMethod,
519
- tokens: parsed.tokens,
520
- score: parsed.score
521
- };
230
+ return routeUtils.deriveRouteFromFile(file, rootDir, log);
522
231
  }
523
232
  function resolveRule(params) {
524
- const method = params.derivedMethod;
525
- if (!method) {
526
- return null;
527
- }
528
- const template = resolveTemplate(params.derivedTemplate, params.prefix);
529
- const parsed = runtime.parseRouteTemplate(template);
530
- if (parsed.errors.length > 0) {
531
- for (const error of parsed.errors) {
532
- params.log?.(`${error} in ${params.file}`);
533
- }
534
- return null;
535
- }
536
- for (const warning of parsed.warnings) {
537
- params.log?.(`${warning} in ${params.file}`);
538
- }
539
- return {
540
- method,
541
- template: parsed.template,
542
- tokens: parsed.tokens,
543
- score: parsed.score
544
- };
233
+ return routeUtils.resolveRule({
234
+ rule: params.rule,
235
+ derivedTemplate: params.derivedTemplate,
236
+ derivedMethod: params.derivedMethod,
237
+ prefix: params.prefix,
238
+ file: params.file,
239
+ warn: params.log,
240
+ build: (base) => ({
241
+ method: base.method,
242
+ template: base.template,
243
+ tokens: base.tokens,
244
+ score: base.score
245
+ })
246
+ });
545
247
  }
546
248
  function sortRoutes(routes) {
547
249
  return routes.sort((a, b) => {
@@ -552,80 +254,8 @@ function sortRoutes(routes) {
552
254
  });
553
255
  }
554
256
 
555
- async function readJsonFile(file) {
556
- try {
557
- const content = await node_fs.promises.readFile(file, "utf8");
558
- const errors = [];
559
- const data = jsoncParser.parse(content, errors, {
560
- allowTrailingComma: true,
561
- disallowComments: false
562
- });
563
- if (errors.length > 0) {
564
- return void 0;
565
- }
566
- return data;
567
- } catch {
568
- return void 0;
569
- }
570
- }
571
- async function loadModule(file) {
572
- const ext = pathe.extname(file).toLowerCase();
573
- if (ext === ".cjs") {
574
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
575
- delete require$1.cache[file];
576
- return require$1(file);
577
- }
578
- if (ext === ".js" || ext === ".mjs") {
579
- return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
580
- }
581
- if (ext === ".ts") {
582
- const result = await esbuild.build({
583
- entryPoints: [file],
584
- bundle: true,
585
- format: "esm",
586
- platform: "node",
587
- sourcemap: "inline",
588
- target: "es2020",
589
- write: false
590
- });
591
- const output = result.outputFiles[0];
592
- const code = output?.text ?? "";
593
- const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
594
- "base64"
595
- )}`;
596
- return import(`${dataUrl}#${Date.now()}`);
597
- }
598
- return null;
599
- }
600
257
  async function loadRules(file) {
601
- const ext = pathe.extname(file).toLowerCase();
602
- if (ext === ".json" || ext === ".jsonc") {
603
- const json = await readJsonFile(file);
604
- if (typeof json === "undefined") {
605
- return [];
606
- }
607
- return [
608
- {
609
- handler: json
610
- }
611
- ];
612
- }
613
- const mod = await loadModule(file);
614
- const value = mod?.default ?? mod;
615
- if (!value) {
616
- return [];
617
- }
618
- if (Array.isArray(value)) {
619
- return value;
620
- }
621
- if (typeof value === "function") {
622
- return [
623
- {
624
- handler: value
625
- }
626
- ];
627
- }
628
- return [value];
258
+ return loadRules$1.loadRules(file, { loadModule: moduleLoader.loadModule });
629
259
  }
630
260
 
631
261
  async function buildManifest(options = {}) {
@@ -633,14 +263,14 @@ async function buildManifest(options = {}) {
633
263
  const outDir = pathe.resolve(root, options.outDir ?? ".mokup");
634
264
  const handlersDir = pathe.join(outDir, "mokup-handlers");
635
265
  const dirs = resolveDirs(options.dir, root);
636
- const files = await collectFiles(dirs);
266
+ const files = await mockFiles.collectFiles(dirs);
637
267
  const routes = [];
638
268
  const seen = /* @__PURE__ */ new Set();
639
269
  const handlerSources = /* @__PURE__ */ new Set();
640
270
  const handlerModuleMap = /* @__PURE__ */ new Map();
641
271
  const configCache = /* @__PURE__ */ new Map();
642
272
  const configFileCache = /* @__PURE__ */ new Map();
643
- const globalIgnorePrefix = normalizeIgnorePrefix(options.ignorePrefix);
273
+ const globalIgnorePrefix = scanUtils.normalizeIgnorePrefix(options.ignorePrefix);
644
274
  for (const fileInfo of files) {
645
275
  const configParams = {
646
276
  file: fileInfo.file,
@@ -655,11 +285,11 @@ async function buildManifest(options = {}) {
655
285
  if (config.enabled === false) {
656
286
  continue;
657
287
  }
658
- const effectiveIgnorePrefix = typeof config.ignorePrefix !== "undefined" ? normalizeIgnorePrefix(config.ignorePrefix, []) : globalIgnorePrefix;
288
+ const effectiveIgnorePrefix = typeof config.ignorePrefix !== "undefined" ? scanUtils.normalizeIgnorePrefix(config.ignorePrefix, []) : globalIgnorePrefix;
659
289
  if (pathUtils.hasIgnoredPrefix(fileInfo.file, fileInfo.rootDir, effectiveIgnorePrefix)) {
660
290
  continue;
661
291
  }
662
- if (!isSupportedFile(fileInfo.file)) {
292
+ if (!mockFiles.isSupportedFile(fileInfo.file)) {
663
293
  continue;
664
294
  }
665
295
  const effectiveInclude = typeof config.include !== "undefined" ? config.include : options.include;
@@ -789,38 +419,12 @@ async function buildManifest(options = {}) {
789
419
  };
790
420
  }
791
421
 
792
- const middlewareSymbol = Symbol.for("mokup.config.middlewares");
793
- function createRegistry(list) {
794
- return {
795
- use: (...handlers) => {
796
- list.push(...handlers);
797
- }
798
- };
799
- }
800
- function attachMetadata(config, meta) {
801
- Object.defineProperty(config, middlewareSymbol, {
802
- value: meta,
803
- enumerable: false
804
- });
805
- return config;
806
- }
807
- function defineConfig(input) {
808
- if (typeof input === "function") {
809
- const pre = [];
810
- const normal = [];
811
- const post = [];
812
- const context = {
813
- pre: createRegistry(pre),
814
- normal: createRegistry(normal),
815
- post: createRegistry(post)
816
- };
817
- const result = input(context);
818
- const config2 = result && typeof result === "object" ? result : {};
819
- return attachMetadata(config2, { pre, normal, post });
820
- }
821
- const config = input && typeof input === "object" ? input : {};
822
- return attachMetadata(config, { pre: [], normal: [], post: [] });
823
- }
422
+ const shared = defineConfig$1.createDefineConfig({
423
+ logPrefix: "[@mokup/cli]"
424
+ });
425
+ const defineConfig = shared.defineConfig;
426
+ const onBeforeAll = shared.onBeforeAll;
427
+ const onAfterAll = shared.onAfterAll;
824
428
 
825
429
  const logger = logger$1.createLogger();
826
430
  function collectValues(value, previous) {
@@ -965,4 +569,6 @@ async function runCli(argv = process__default.argv) {
965
569
  exports.buildManifest = buildManifest;
966
570
  exports.createCli = createCli;
967
571
  exports.defineConfig = defineConfig;
572
+ exports.onAfterAll = onAfterAll;
573
+ exports.onBeforeAll = onBeforeAll;
968
574
  exports.runCli = runCli;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Manifest } from '@mokup/runtime';
2
2
  import { MiddlewareHandler } from '@mokup/shared/hono';
3
+ import * as _mokup_shared_define_config from '@mokup/shared/define-config';
3
4
  import { Command } from 'commander';
4
5
 
5
6
  /**
@@ -164,6 +165,12 @@ interface RouteDirectoryConfig {
164
165
  * @default undefined
165
166
  */
166
167
  middleware?: MiddlewareHandler | MiddlewareHandler[];
168
+ /**
169
+ * Error handling policy for defineConfig hooks.
170
+ *
171
+ * @default "warn"
172
+ */
173
+ hookError?: HookErrorPolicy;
167
174
  }
168
175
  /**
169
176
  * Middleware execution position.
@@ -174,6 +181,10 @@ interface RouteDirectoryConfig {
174
181
  * const position: MiddlewarePosition = 'pre'
175
182
  */
176
183
  type MiddlewarePosition = 'pre' | 'normal' | 'post';
184
+ /**
185
+ * Error handling policy for config hooks.
186
+ */
187
+ type HookErrorPolicy = 'throw' | 'warn' | 'silent';
177
188
  /**
178
189
  * Middleware registry used by defineConfig.
179
190
  *
@@ -202,39 +213,9 @@ declare function buildManifest(options?: BuildOptions): Promise<{
202
213
  manifestPath: string;
203
214
  }>;
204
215
 
205
- type DefineConfigFactory = (context: {
206
- pre: MiddlewareRegistry;
207
- normal: MiddlewareRegistry;
208
- post: MiddlewareRegistry;
209
- }) => RouteDirectoryConfig | void;
210
- /**
211
- * Define a directory config with Hono-style middleware registration.
212
- *
213
- * @param input - Config object or factory callback.
214
- * @returns Route directory config with middleware metadata.
215
- *
216
- * @example
217
- * import { defineConfig } from '@mokup/cli'
218
- *
219
- * export default defineConfig(({ pre, normal, post }) => {
220
- * pre.use(async (c, next) => {
221
- * c.header('x-before', '1')
222
- * await next()
223
- * })
224
- *
225
- * normal.use(async (_c, next) => {
226
- * await next()
227
- * })
228
- *
229
- * post.use(async (c, next) => {
230
- * await next()
231
- * c.header('x-after', '1')
232
- * })
233
- *
234
- * return { delay: 120 }
235
- * })
236
- */
237
- declare function defineConfig(input: RouteDirectoryConfig | DefineConfigFactory): RouteDirectoryConfig;
216
+ declare const defineConfig: (input: RouteDirectoryConfig | _mokup_shared_define_config.DefineConfigFactory<RouteDirectoryConfig, MiddlewareHandler>) => RouteDirectoryConfig | Promise<RouteDirectoryConfig>;
217
+ declare const onBeforeAll: (handler: _mokup_shared_define_config.HookHandler) => void;
218
+ declare const onAfterAll: (handler: _mokup_shared_define_config.HookHandler) => void;
238
219
 
239
220
  /**
240
221
  * Create the mokup CLI program instance.
@@ -260,5 +241,5 @@ declare function createCli(): Command;
260
241
  */
261
242
  declare function runCli(argv?: string[]): Promise<void>;
262
243
 
263
- export { buildManifest, createCli, defineConfig, runCli };
264
- export type { BuildOptions, MiddlewarePosition, MiddlewareRegistry, RouteDirectoryConfig, RouteRule };
244
+ export { buildManifest, createCli, defineConfig, onAfterAll, onBeforeAll, runCli };
245
+ export type { BuildOptions, HookErrorPolicy, MiddlewarePosition, MiddlewareRegistry, RouteDirectoryConfig, RouteRule };