@mokup/cli 1.0.4 → 1.0.6
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 +115 -24
- package/dist/index.d.cts +241 -2
- package/dist/index.d.mts +241 -2
- package/dist/index.d.ts +241 -2
- package/dist/index.mjs +112 -22
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -9,8 +9,8 @@ const node_url = require('node:url');
|
|
|
9
9
|
const esbuild = require('@mokup/shared/esbuild');
|
|
10
10
|
const runtime = require('@mokup/runtime');
|
|
11
11
|
const jsoncParser = require('@mokup/shared/jsonc-parser');
|
|
12
|
-
const server = require('@mokup/server');
|
|
13
12
|
const node = require('@mokup/server/node');
|
|
13
|
+
const logger$1 = require('@mokup/shared/logger');
|
|
14
14
|
const commander = require('commander');
|
|
15
15
|
|
|
16
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -75,6 +75,7 @@ async function writeManifestModule(outDir, manifest) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
78
|
+
const middlewareSymbol$1 = Symbol.for("mokup.config.middlewares");
|
|
78
79
|
async function loadModule$1(file) {
|
|
79
80
|
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
80
81
|
if (ext === ".cjs") {
|
|
@@ -135,7 +136,7 @@ async function loadConfig(file) {
|
|
|
135
136
|
}
|
|
136
137
|
return value;
|
|
137
138
|
}
|
|
138
|
-
function normalizeMiddlewares(value, source, log) {
|
|
139
|
+
function normalizeMiddlewares(value, source, log, position) {
|
|
139
140
|
if (!value) {
|
|
140
141
|
return [];
|
|
141
142
|
}
|
|
@@ -146,10 +147,22 @@ function normalizeMiddlewares(value, source, log) {
|
|
|
146
147
|
log?.(`Invalid middleware in ${source}`);
|
|
147
148
|
return;
|
|
148
149
|
}
|
|
149
|
-
middlewares.push({ file: source, index });
|
|
150
|
+
middlewares.push({ file: source, index, position });
|
|
150
151
|
});
|
|
151
152
|
return middlewares;
|
|
152
153
|
}
|
|
154
|
+
function readMiddlewareMeta(config) {
|
|
155
|
+
const value = config[middlewareSymbol$1];
|
|
156
|
+
if (!value || typeof value !== "object") {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const meta = value;
|
|
160
|
+
return {
|
|
161
|
+
pre: Array.isArray(meta.pre) ? meta.pre : [],
|
|
162
|
+
normal: Array.isArray(meta.normal) ? meta.normal : [],
|
|
163
|
+
post: Array.isArray(meta.post) ? meta.post : []
|
|
164
|
+
};
|
|
165
|
+
}
|
|
153
166
|
async function resolveDirectoryConfig(params) {
|
|
154
167
|
const { file, rootDir, log, configCache, fileCache } = params;
|
|
155
168
|
const resolvedRoot = pathe.normalize(rootDir);
|
|
@@ -168,7 +181,10 @@ async function resolveDirectoryConfig(params) {
|
|
|
168
181
|
current = parent;
|
|
169
182
|
}
|
|
170
183
|
chain.reverse();
|
|
171
|
-
const merged = {
|
|
184
|
+
const merged = {};
|
|
185
|
+
const preMiddlewares = [];
|
|
186
|
+
const normalMiddlewares = [];
|
|
187
|
+
const postMiddlewares = [];
|
|
172
188
|
for (const dir of chain) {
|
|
173
189
|
const configPath = await findConfigFile(dir, fileCache);
|
|
174
190
|
if (!configPath) {
|
|
@@ -204,12 +220,48 @@ async function resolveDirectoryConfig(params) {
|
|
|
204
220
|
if (typeof config.exclude !== "undefined") {
|
|
205
221
|
merged.exclude = config.exclude;
|
|
206
222
|
}
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
223
|
+
const meta = readMiddlewareMeta(config);
|
|
224
|
+
const normalizedPre = normalizeMiddlewares(
|
|
225
|
+
meta?.pre,
|
|
226
|
+
configPath,
|
|
227
|
+
log,
|
|
228
|
+
"pre"
|
|
229
|
+
);
|
|
230
|
+
const normalizedNormal = normalizeMiddlewares(
|
|
231
|
+
meta?.normal,
|
|
232
|
+
configPath,
|
|
233
|
+
log,
|
|
234
|
+
"normal"
|
|
235
|
+
);
|
|
236
|
+
const normalizedLegacy = normalizeMiddlewares(
|
|
237
|
+
config.middleware,
|
|
238
|
+
configPath,
|
|
239
|
+
log,
|
|
240
|
+
"normal"
|
|
241
|
+
);
|
|
242
|
+
const normalizedPost = normalizeMiddlewares(
|
|
243
|
+
meta?.post,
|
|
244
|
+
configPath,
|
|
245
|
+
log,
|
|
246
|
+
"post"
|
|
247
|
+
);
|
|
248
|
+
if (normalizedPre.length > 0) {
|
|
249
|
+
preMiddlewares.push(...normalizedPre);
|
|
250
|
+
}
|
|
251
|
+
if (normalizedNormal.length > 0) {
|
|
252
|
+
normalMiddlewares.push(...normalizedNormal);
|
|
253
|
+
}
|
|
254
|
+
if (normalizedLegacy.length > 0) {
|
|
255
|
+
normalMiddlewares.push(...normalizedLegacy);
|
|
256
|
+
}
|
|
257
|
+
if (normalizedPost.length > 0) {
|
|
258
|
+
postMiddlewares.push(...normalizedPost);
|
|
210
259
|
}
|
|
211
260
|
}
|
|
212
|
-
return
|
|
261
|
+
return {
|
|
262
|
+
...merged,
|
|
263
|
+
middlewares: [...preMiddlewares, ...normalMiddlewares, ...postMiddlewares]
|
|
264
|
+
};
|
|
213
265
|
}
|
|
214
266
|
|
|
215
267
|
function toPosix(value) {
|
|
@@ -764,6 +816,40 @@ async function buildManifest(options = {}) {
|
|
|
764
816
|
};
|
|
765
817
|
}
|
|
766
818
|
|
|
819
|
+
const middlewareSymbol = Symbol.for("mokup.config.middlewares");
|
|
820
|
+
function createRegistry(list) {
|
|
821
|
+
return {
|
|
822
|
+
use: (...handlers) => {
|
|
823
|
+
list.push(...handlers);
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
function attachMetadata(config, meta) {
|
|
828
|
+
Object.defineProperty(config, middlewareSymbol, {
|
|
829
|
+
value: meta,
|
|
830
|
+
enumerable: false
|
|
831
|
+
});
|
|
832
|
+
return config;
|
|
833
|
+
}
|
|
834
|
+
function defineConfig(input) {
|
|
835
|
+
if (typeof input === "function") {
|
|
836
|
+
const pre = [];
|
|
837
|
+
const normal = [];
|
|
838
|
+
const post = [];
|
|
839
|
+
const context = {
|
|
840
|
+
pre: createRegistry(pre),
|
|
841
|
+
normal: createRegistry(normal),
|
|
842
|
+
post: createRegistry(post)
|
|
843
|
+
};
|
|
844
|
+
const result = input(context);
|
|
845
|
+
const config2 = result && typeof result === "object" ? result : {};
|
|
846
|
+
return attachMetadata(config2, { pre, normal, post });
|
|
847
|
+
}
|
|
848
|
+
const config = input && typeof input === "object" ? input : {};
|
|
849
|
+
return attachMetadata(config, { pre: [], normal: [], post: [] });
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const logger = logger$1.createLogger();
|
|
767
853
|
function collectValues(value, previous) {
|
|
768
854
|
return [...previous ?? [], value];
|
|
769
855
|
}
|
|
@@ -776,7 +862,7 @@ function toBuildOptions(options) {
|
|
|
776
862
|
const buildOptions = {
|
|
777
863
|
handlers: options.handlers !== false,
|
|
778
864
|
log: (message) => {
|
|
779
|
-
|
|
865
|
+
logger.info(message);
|
|
780
866
|
}
|
|
781
867
|
};
|
|
782
868
|
if (options.dir && options.dir.length > 0) {
|
|
@@ -829,10 +915,10 @@ function toServeOptions(options) {
|
|
|
829
915
|
}
|
|
830
916
|
serveOptions.port = parsed;
|
|
831
917
|
}
|
|
832
|
-
|
|
833
|
-
serveOptions
|
|
834
|
-
|
|
835
|
-
|
|
918
|
+
return {
|
|
919
|
+
entry: serveOptions,
|
|
920
|
+
playground: options.playground
|
|
921
|
+
};
|
|
836
922
|
}
|
|
837
923
|
function createCli() {
|
|
838
924
|
const program = new commander.Command();
|
|
@@ -843,31 +929,35 @@ function createCli() {
|
|
|
843
929
|
});
|
|
844
930
|
program.command("serve").description("Start a Node.js mock server").option("-d, --dir <dir>", "Mock directory (repeatable)", collectValues).option("--prefix <prefix>", "URL prefix").option("--include <pattern>", "Include regex (repeatable)", collectRegex).option("--exclude <pattern>", "Exclude regex (repeatable)", collectRegex).option("--ignore-prefix <prefix>", "Ignore path segment prefix (repeatable)", collectValues).option("--host <host>", "Hostname (default: localhost)").option("--port <port>", "Port (default: 8080)").option("--no-watch", "Disable file watching").option("--no-playground", "Disable Playground").option("--no-log", "Disable logging").action(async (options) => {
|
|
845
931
|
const serveOptions = toServeOptions(options);
|
|
846
|
-
const
|
|
847
|
-
const
|
|
848
|
-
const
|
|
849
|
-
const
|
|
850
|
-
const
|
|
932
|
+
const { entry, playground } = serveOptions;
|
|
933
|
+
const host = entry.host ?? "localhost";
|
|
934
|
+
const port = entry.port ?? 8080;
|
|
935
|
+
const playgroundEnabled = playground !== false;
|
|
936
|
+
const playgroundPath = "/__mokup";
|
|
937
|
+
const server = await node.createFetchServer({
|
|
938
|
+
entries: entry,
|
|
939
|
+
playground
|
|
940
|
+
});
|
|
851
941
|
const nodeServer = node.serve(
|
|
852
942
|
{
|
|
853
|
-
fetch: server
|
|
943
|
+
fetch: server.fetch,
|
|
854
944
|
hostname: host,
|
|
855
945
|
port
|
|
856
946
|
},
|
|
857
947
|
(info) => {
|
|
858
948
|
const resolvedHost = typeof info === "string" ? host : info?.address ?? host;
|
|
859
949
|
const resolvedPort = typeof info === "string" ? port : info?.port ?? port;
|
|
860
|
-
|
|
950
|
+
logger.info(`Mock server ready at http://${resolvedHost}:${resolvedPort}`);
|
|
861
951
|
if (playgroundEnabled) {
|
|
862
|
-
|
|
952
|
+
logger.info(`Playground at http://${resolvedHost}:${resolvedPort}${playgroundPath}`);
|
|
863
953
|
}
|
|
864
954
|
}
|
|
865
955
|
);
|
|
866
|
-
server
|
|
956
|
+
server.injectWebSocket?.(nodeServer);
|
|
867
957
|
const shutdown = async () => {
|
|
868
958
|
try {
|
|
869
|
-
if (server
|
|
870
|
-
await server
|
|
959
|
+
if (server.close) {
|
|
960
|
+
await server.close();
|
|
871
961
|
}
|
|
872
962
|
await new Promise((resolve, reject) => {
|
|
873
963
|
nodeServer.close((error) => {
|
|
@@ -901,4 +991,5 @@ async function runCli(argv = process__default.argv) {
|
|
|
901
991
|
|
|
902
992
|
exports.buildManifest = buildManifest;
|
|
903
993
|
exports.createCli = createCli;
|
|
994
|
+
exports.defineConfig = defineConfig;
|
|
904
995
|
exports.runCli = runCli;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,25 +1,264 @@
|
|
|
1
1
|
import { Manifest } from '@mokup/runtime';
|
|
2
|
+
import { MiddlewareHandler } from '@mokup/shared/hono';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options for building a mokup manifest.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import type { BuildOptions } from '@mokup/cli'
|
|
10
|
+
*
|
|
11
|
+
* const options: BuildOptions = {
|
|
12
|
+
* dir: 'mock',
|
|
13
|
+
* outDir: '.mokup',
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
4
16
|
interface BuildOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Directory or directories to scan for mock files.
|
|
19
|
+
*
|
|
20
|
+
* @default "mock"
|
|
21
|
+
*/
|
|
5
22
|
dir?: string | string[];
|
|
23
|
+
/**
|
|
24
|
+
* Output directory for manifest artifacts.
|
|
25
|
+
*
|
|
26
|
+
* @default ".mokup"
|
|
27
|
+
*/
|
|
6
28
|
outDir?: string;
|
|
29
|
+
/**
|
|
30
|
+
* URL prefix to apply to generated routes.
|
|
31
|
+
*
|
|
32
|
+
* @default ""
|
|
33
|
+
*/
|
|
7
34
|
prefix?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Include filter for files.
|
|
37
|
+
*
|
|
38
|
+
* @default undefined
|
|
39
|
+
*/
|
|
8
40
|
include?: RegExp | RegExp[];
|
|
41
|
+
/**
|
|
42
|
+
* Exclude filter for files.
|
|
43
|
+
*
|
|
44
|
+
* @default undefined
|
|
45
|
+
*/
|
|
9
46
|
exclude?: RegExp | RegExp[];
|
|
47
|
+
/**
|
|
48
|
+
* Ignore file or folder prefixes.
|
|
49
|
+
*
|
|
50
|
+
* @default ["."]
|
|
51
|
+
*/
|
|
10
52
|
ignorePrefix?: string | string[];
|
|
53
|
+
/**
|
|
54
|
+
* Emit handler bundles for module-based responses.
|
|
55
|
+
*
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
11
58
|
handlers?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Project root used to resolve paths.
|
|
61
|
+
*
|
|
62
|
+
* @default process.cwd()
|
|
63
|
+
*/
|
|
12
64
|
root?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Optional logger for build messages.
|
|
67
|
+
*
|
|
68
|
+
* @default undefined
|
|
69
|
+
*/
|
|
13
70
|
log?: (message: string) => void;
|
|
14
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Route rule shape used in build-time resolution.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* import type { RouteRule } from '@mokup/cli'
|
|
77
|
+
*
|
|
78
|
+
* const rule: RouteRule = { handler: { ok: true } }
|
|
79
|
+
*/
|
|
80
|
+
interface RouteRule {
|
|
81
|
+
/** Route handler or static value. */
|
|
82
|
+
handler: unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Enable or disable this rule.
|
|
85
|
+
*
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
enabled?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Override response status code.
|
|
91
|
+
*
|
|
92
|
+
* @default 200
|
|
93
|
+
*/
|
|
94
|
+
status?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Additional response headers.
|
|
97
|
+
*
|
|
98
|
+
* @default {}
|
|
99
|
+
*/
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
/**
|
|
102
|
+
* Delay in milliseconds before responding.
|
|
103
|
+
*
|
|
104
|
+
* @default 0
|
|
105
|
+
*/
|
|
106
|
+
delay?: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Directory-level config used during manifest build.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* import type { RouteDirectoryConfig } from '@mokup/cli'
|
|
113
|
+
*
|
|
114
|
+
* const config: RouteDirectoryConfig = {
|
|
115
|
+
* headers: { 'x-mokup': 'dir' },
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
interface RouteDirectoryConfig {
|
|
119
|
+
/**
|
|
120
|
+
* Headers applied to routes in this directory.
|
|
121
|
+
*
|
|
122
|
+
* @default {}
|
|
123
|
+
*/
|
|
124
|
+
headers?: Record<string, string>;
|
|
125
|
+
/**
|
|
126
|
+
* Default status code override.
|
|
127
|
+
*
|
|
128
|
+
* @default 200
|
|
129
|
+
*/
|
|
130
|
+
status?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Default delay in milliseconds.
|
|
133
|
+
*
|
|
134
|
+
* @default 0
|
|
135
|
+
*/
|
|
136
|
+
delay?: number;
|
|
137
|
+
/**
|
|
138
|
+
* Enable or disable this directory.
|
|
139
|
+
*
|
|
140
|
+
* @default true
|
|
141
|
+
*/
|
|
142
|
+
enabled?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Ignore prefixes applied to files in this directory.
|
|
145
|
+
*
|
|
146
|
+
* @default ["."]
|
|
147
|
+
*/
|
|
148
|
+
ignorePrefix?: string | string[];
|
|
149
|
+
/**
|
|
150
|
+
* Include filter for files.
|
|
151
|
+
*
|
|
152
|
+
* @default undefined
|
|
153
|
+
*/
|
|
154
|
+
include?: RegExp | RegExp[];
|
|
155
|
+
/**
|
|
156
|
+
* Exclude filter for files.
|
|
157
|
+
*
|
|
158
|
+
* @default undefined
|
|
159
|
+
*/
|
|
160
|
+
exclude?: RegExp | RegExp[];
|
|
161
|
+
/**
|
|
162
|
+
* Middleware for the directory.
|
|
163
|
+
*
|
|
164
|
+
* @default undefined
|
|
165
|
+
*/
|
|
166
|
+
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Middleware execution position.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* import type { MiddlewarePosition } from '@mokup/cli'
|
|
173
|
+
*
|
|
174
|
+
* const position: MiddlewarePosition = 'pre'
|
|
175
|
+
*/
|
|
176
|
+
type MiddlewarePosition = 'pre' | 'normal' | 'post';
|
|
177
|
+
/**
|
|
178
|
+
* Middleware registry used by defineConfig.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* import type { MiddlewareRegistry } from '@mokup/cli'
|
|
182
|
+
*
|
|
183
|
+
* const registry: MiddlewareRegistry = { use: () => {} }
|
|
184
|
+
*/
|
|
185
|
+
interface MiddlewareRegistry {
|
|
186
|
+
use: (...handlers: MiddlewareHandler[]) => void;
|
|
187
|
+
}
|
|
15
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Build and write a mokup manifest to disk.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Build options.
|
|
193
|
+
* @returns Build output metadata.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* import { buildManifest } from '@mokup/cli'
|
|
197
|
+
*
|
|
198
|
+
* const result = await buildManifest({ dir: 'mock', outDir: '.mokup' })
|
|
199
|
+
*/
|
|
16
200
|
declare function buildManifest(options?: BuildOptions): Promise<{
|
|
17
201
|
manifest: Manifest;
|
|
18
202
|
manifestPath: string;
|
|
19
203
|
}>;
|
|
20
204
|
|
|
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;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create the mokup CLI program instance.
|
|
241
|
+
*
|
|
242
|
+
* @returns A configured CLI program.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* import { createCli } from '@mokup/cli'
|
|
246
|
+
*
|
|
247
|
+
* const cli = createCli()
|
|
248
|
+
*/
|
|
21
249
|
declare function createCli(): Command;
|
|
250
|
+
/**
|
|
251
|
+
* Run the mokup CLI with the provided argv.
|
|
252
|
+
*
|
|
253
|
+
* @param argv - CLI arguments.
|
|
254
|
+
* @returns Exit code or void.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* import { runCli } from '@mokup/cli'
|
|
258
|
+
*
|
|
259
|
+
* await runCli(['node', 'mokup', 'build', '--dir', 'mock'])
|
|
260
|
+
*/
|
|
22
261
|
declare function runCli(argv?: string[]): Promise<void>;
|
|
23
262
|
|
|
24
|
-
export { buildManifest, createCli, runCli };
|
|
25
|
-
export type { BuildOptions };
|
|
263
|
+
export { buildManifest, createCli, defineConfig, runCli };
|
|
264
|
+
export type { BuildOptions, MiddlewarePosition, MiddlewareRegistry, RouteDirectoryConfig, RouteRule };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,25 +1,264 @@
|
|
|
1
1
|
import { Manifest } from '@mokup/runtime';
|
|
2
|
+
import { MiddlewareHandler } from '@mokup/shared/hono';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options for building a mokup manifest.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import type { BuildOptions } from '@mokup/cli'
|
|
10
|
+
*
|
|
11
|
+
* const options: BuildOptions = {
|
|
12
|
+
* dir: 'mock',
|
|
13
|
+
* outDir: '.mokup',
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
4
16
|
interface BuildOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Directory or directories to scan for mock files.
|
|
19
|
+
*
|
|
20
|
+
* @default "mock"
|
|
21
|
+
*/
|
|
5
22
|
dir?: string | string[];
|
|
23
|
+
/**
|
|
24
|
+
* Output directory for manifest artifacts.
|
|
25
|
+
*
|
|
26
|
+
* @default ".mokup"
|
|
27
|
+
*/
|
|
6
28
|
outDir?: string;
|
|
29
|
+
/**
|
|
30
|
+
* URL prefix to apply to generated routes.
|
|
31
|
+
*
|
|
32
|
+
* @default ""
|
|
33
|
+
*/
|
|
7
34
|
prefix?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Include filter for files.
|
|
37
|
+
*
|
|
38
|
+
* @default undefined
|
|
39
|
+
*/
|
|
8
40
|
include?: RegExp | RegExp[];
|
|
41
|
+
/**
|
|
42
|
+
* Exclude filter for files.
|
|
43
|
+
*
|
|
44
|
+
* @default undefined
|
|
45
|
+
*/
|
|
9
46
|
exclude?: RegExp | RegExp[];
|
|
47
|
+
/**
|
|
48
|
+
* Ignore file or folder prefixes.
|
|
49
|
+
*
|
|
50
|
+
* @default ["."]
|
|
51
|
+
*/
|
|
10
52
|
ignorePrefix?: string | string[];
|
|
53
|
+
/**
|
|
54
|
+
* Emit handler bundles for module-based responses.
|
|
55
|
+
*
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
11
58
|
handlers?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Project root used to resolve paths.
|
|
61
|
+
*
|
|
62
|
+
* @default process.cwd()
|
|
63
|
+
*/
|
|
12
64
|
root?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Optional logger for build messages.
|
|
67
|
+
*
|
|
68
|
+
* @default undefined
|
|
69
|
+
*/
|
|
13
70
|
log?: (message: string) => void;
|
|
14
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Route rule shape used in build-time resolution.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* import type { RouteRule } from '@mokup/cli'
|
|
77
|
+
*
|
|
78
|
+
* const rule: RouteRule = { handler: { ok: true } }
|
|
79
|
+
*/
|
|
80
|
+
interface RouteRule {
|
|
81
|
+
/** Route handler or static value. */
|
|
82
|
+
handler: unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Enable or disable this rule.
|
|
85
|
+
*
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
enabled?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Override response status code.
|
|
91
|
+
*
|
|
92
|
+
* @default 200
|
|
93
|
+
*/
|
|
94
|
+
status?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Additional response headers.
|
|
97
|
+
*
|
|
98
|
+
* @default {}
|
|
99
|
+
*/
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
/**
|
|
102
|
+
* Delay in milliseconds before responding.
|
|
103
|
+
*
|
|
104
|
+
* @default 0
|
|
105
|
+
*/
|
|
106
|
+
delay?: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Directory-level config used during manifest build.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* import type { RouteDirectoryConfig } from '@mokup/cli'
|
|
113
|
+
*
|
|
114
|
+
* const config: RouteDirectoryConfig = {
|
|
115
|
+
* headers: { 'x-mokup': 'dir' },
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
interface RouteDirectoryConfig {
|
|
119
|
+
/**
|
|
120
|
+
* Headers applied to routes in this directory.
|
|
121
|
+
*
|
|
122
|
+
* @default {}
|
|
123
|
+
*/
|
|
124
|
+
headers?: Record<string, string>;
|
|
125
|
+
/**
|
|
126
|
+
* Default status code override.
|
|
127
|
+
*
|
|
128
|
+
* @default 200
|
|
129
|
+
*/
|
|
130
|
+
status?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Default delay in milliseconds.
|
|
133
|
+
*
|
|
134
|
+
* @default 0
|
|
135
|
+
*/
|
|
136
|
+
delay?: number;
|
|
137
|
+
/**
|
|
138
|
+
* Enable or disable this directory.
|
|
139
|
+
*
|
|
140
|
+
* @default true
|
|
141
|
+
*/
|
|
142
|
+
enabled?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Ignore prefixes applied to files in this directory.
|
|
145
|
+
*
|
|
146
|
+
* @default ["."]
|
|
147
|
+
*/
|
|
148
|
+
ignorePrefix?: string | string[];
|
|
149
|
+
/**
|
|
150
|
+
* Include filter for files.
|
|
151
|
+
*
|
|
152
|
+
* @default undefined
|
|
153
|
+
*/
|
|
154
|
+
include?: RegExp | RegExp[];
|
|
155
|
+
/**
|
|
156
|
+
* Exclude filter for files.
|
|
157
|
+
*
|
|
158
|
+
* @default undefined
|
|
159
|
+
*/
|
|
160
|
+
exclude?: RegExp | RegExp[];
|
|
161
|
+
/**
|
|
162
|
+
* Middleware for the directory.
|
|
163
|
+
*
|
|
164
|
+
* @default undefined
|
|
165
|
+
*/
|
|
166
|
+
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Middleware execution position.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* import type { MiddlewarePosition } from '@mokup/cli'
|
|
173
|
+
*
|
|
174
|
+
* const position: MiddlewarePosition = 'pre'
|
|
175
|
+
*/
|
|
176
|
+
type MiddlewarePosition = 'pre' | 'normal' | 'post';
|
|
177
|
+
/**
|
|
178
|
+
* Middleware registry used by defineConfig.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* import type { MiddlewareRegistry } from '@mokup/cli'
|
|
182
|
+
*
|
|
183
|
+
* const registry: MiddlewareRegistry = { use: () => {} }
|
|
184
|
+
*/
|
|
185
|
+
interface MiddlewareRegistry {
|
|
186
|
+
use: (...handlers: MiddlewareHandler[]) => void;
|
|
187
|
+
}
|
|
15
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Build and write a mokup manifest to disk.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Build options.
|
|
193
|
+
* @returns Build output metadata.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* import { buildManifest } from '@mokup/cli'
|
|
197
|
+
*
|
|
198
|
+
* const result = await buildManifest({ dir: 'mock', outDir: '.mokup' })
|
|
199
|
+
*/
|
|
16
200
|
declare function buildManifest(options?: BuildOptions): Promise<{
|
|
17
201
|
manifest: Manifest;
|
|
18
202
|
manifestPath: string;
|
|
19
203
|
}>;
|
|
20
204
|
|
|
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;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create the mokup CLI program instance.
|
|
241
|
+
*
|
|
242
|
+
* @returns A configured CLI program.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* import { createCli } from '@mokup/cli'
|
|
246
|
+
*
|
|
247
|
+
* const cli = createCli()
|
|
248
|
+
*/
|
|
21
249
|
declare function createCli(): Command;
|
|
250
|
+
/**
|
|
251
|
+
* Run the mokup CLI with the provided argv.
|
|
252
|
+
*
|
|
253
|
+
* @param argv - CLI arguments.
|
|
254
|
+
* @returns Exit code or void.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* import { runCli } from '@mokup/cli'
|
|
258
|
+
*
|
|
259
|
+
* await runCli(['node', 'mokup', 'build', '--dir', 'mock'])
|
|
260
|
+
*/
|
|
22
261
|
declare function runCli(argv?: string[]): Promise<void>;
|
|
23
262
|
|
|
24
|
-
export { buildManifest, createCli, runCli };
|
|
25
|
-
export type { BuildOptions };
|
|
263
|
+
export { buildManifest, createCli, defineConfig, runCli };
|
|
264
|
+
export type { BuildOptions, MiddlewarePosition, MiddlewareRegistry, RouteDirectoryConfig, RouteRule };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,264 @@
|
|
|
1
1
|
import { Manifest } from '@mokup/runtime';
|
|
2
|
+
import { MiddlewareHandler } from '@mokup/shared/hono';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options for building a mokup manifest.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import type { BuildOptions } from '@mokup/cli'
|
|
10
|
+
*
|
|
11
|
+
* const options: BuildOptions = {
|
|
12
|
+
* dir: 'mock',
|
|
13
|
+
* outDir: '.mokup',
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
4
16
|
interface BuildOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Directory or directories to scan for mock files.
|
|
19
|
+
*
|
|
20
|
+
* @default "mock"
|
|
21
|
+
*/
|
|
5
22
|
dir?: string | string[];
|
|
23
|
+
/**
|
|
24
|
+
* Output directory for manifest artifacts.
|
|
25
|
+
*
|
|
26
|
+
* @default ".mokup"
|
|
27
|
+
*/
|
|
6
28
|
outDir?: string;
|
|
29
|
+
/**
|
|
30
|
+
* URL prefix to apply to generated routes.
|
|
31
|
+
*
|
|
32
|
+
* @default ""
|
|
33
|
+
*/
|
|
7
34
|
prefix?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Include filter for files.
|
|
37
|
+
*
|
|
38
|
+
* @default undefined
|
|
39
|
+
*/
|
|
8
40
|
include?: RegExp | RegExp[];
|
|
41
|
+
/**
|
|
42
|
+
* Exclude filter for files.
|
|
43
|
+
*
|
|
44
|
+
* @default undefined
|
|
45
|
+
*/
|
|
9
46
|
exclude?: RegExp | RegExp[];
|
|
47
|
+
/**
|
|
48
|
+
* Ignore file or folder prefixes.
|
|
49
|
+
*
|
|
50
|
+
* @default ["."]
|
|
51
|
+
*/
|
|
10
52
|
ignorePrefix?: string | string[];
|
|
53
|
+
/**
|
|
54
|
+
* Emit handler bundles for module-based responses.
|
|
55
|
+
*
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
11
58
|
handlers?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Project root used to resolve paths.
|
|
61
|
+
*
|
|
62
|
+
* @default process.cwd()
|
|
63
|
+
*/
|
|
12
64
|
root?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Optional logger for build messages.
|
|
67
|
+
*
|
|
68
|
+
* @default undefined
|
|
69
|
+
*/
|
|
13
70
|
log?: (message: string) => void;
|
|
14
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Route rule shape used in build-time resolution.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* import type { RouteRule } from '@mokup/cli'
|
|
77
|
+
*
|
|
78
|
+
* const rule: RouteRule = { handler: { ok: true } }
|
|
79
|
+
*/
|
|
80
|
+
interface RouteRule {
|
|
81
|
+
/** Route handler or static value. */
|
|
82
|
+
handler: unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Enable or disable this rule.
|
|
85
|
+
*
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
enabled?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Override response status code.
|
|
91
|
+
*
|
|
92
|
+
* @default 200
|
|
93
|
+
*/
|
|
94
|
+
status?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Additional response headers.
|
|
97
|
+
*
|
|
98
|
+
* @default {}
|
|
99
|
+
*/
|
|
100
|
+
headers?: Record<string, string>;
|
|
101
|
+
/**
|
|
102
|
+
* Delay in milliseconds before responding.
|
|
103
|
+
*
|
|
104
|
+
* @default 0
|
|
105
|
+
*/
|
|
106
|
+
delay?: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Directory-level config used during manifest build.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* import type { RouteDirectoryConfig } from '@mokup/cli'
|
|
113
|
+
*
|
|
114
|
+
* const config: RouteDirectoryConfig = {
|
|
115
|
+
* headers: { 'x-mokup': 'dir' },
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
interface RouteDirectoryConfig {
|
|
119
|
+
/**
|
|
120
|
+
* Headers applied to routes in this directory.
|
|
121
|
+
*
|
|
122
|
+
* @default {}
|
|
123
|
+
*/
|
|
124
|
+
headers?: Record<string, string>;
|
|
125
|
+
/**
|
|
126
|
+
* Default status code override.
|
|
127
|
+
*
|
|
128
|
+
* @default 200
|
|
129
|
+
*/
|
|
130
|
+
status?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Default delay in milliseconds.
|
|
133
|
+
*
|
|
134
|
+
* @default 0
|
|
135
|
+
*/
|
|
136
|
+
delay?: number;
|
|
137
|
+
/**
|
|
138
|
+
* Enable or disable this directory.
|
|
139
|
+
*
|
|
140
|
+
* @default true
|
|
141
|
+
*/
|
|
142
|
+
enabled?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Ignore prefixes applied to files in this directory.
|
|
145
|
+
*
|
|
146
|
+
* @default ["."]
|
|
147
|
+
*/
|
|
148
|
+
ignorePrefix?: string | string[];
|
|
149
|
+
/**
|
|
150
|
+
* Include filter for files.
|
|
151
|
+
*
|
|
152
|
+
* @default undefined
|
|
153
|
+
*/
|
|
154
|
+
include?: RegExp | RegExp[];
|
|
155
|
+
/**
|
|
156
|
+
* Exclude filter for files.
|
|
157
|
+
*
|
|
158
|
+
* @default undefined
|
|
159
|
+
*/
|
|
160
|
+
exclude?: RegExp | RegExp[];
|
|
161
|
+
/**
|
|
162
|
+
* Middleware for the directory.
|
|
163
|
+
*
|
|
164
|
+
* @default undefined
|
|
165
|
+
*/
|
|
166
|
+
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Middleware execution position.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* import type { MiddlewarePosition } from '@mokup/cli'
|
|
173
|
+
*
|
|
174
|
+
* const position: MiddlewarePosition = 'pre'
|
|
175
|
+
*/
|
|
176
|
+
type MiddlewarePosition = 'pre' | 'normal' | 'post';
|
|
177
|
+
/**
|
|
178
|
+
* Middleware registry used by defineConfig.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* import type { MiddlewareRegistry } from '@mokup/cli'
|
|
182
|
+
*
|
|
183
|
+
* const registry: MiddlewareRegistry = { use: () => {} }
|
|
184
|
+
*/
|
|
185
|
+
interface MiddlewareRegistry {
|
|
186
|
+
use: (...handlers: MiddlewareHandler[]) => void;
|
|
187
|
+
}
|
|
15
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Build and write a mokup manifest to disk.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Build options.
|
|
193
|
+
* @returns Build output metadata.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* import { buildManifest } from '@mokup/cli'
|
|
197
|
+
*
|
|
198
|
+
* const result = await buildManifest({ dir: 'mock', outDir: '.mokup' })
|
|
199
|
+
*/
|
|
16
200
|
declare function buildManifest(options?: BuildOptions): Promise<{
|
|
17
201
|
manifest: Manifest;
|
|
18
202
|
manifestPath: string;
|
|
19
203
|
}>;
|
|
20
204
|
|
|
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;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create the mokup CLI program instance.
|
|
241
|
+
*
|
|
242
|
+
* @returns A configured CLI program.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* import { createCli } from '@mokup/cli'
|
|
246
|
+
*
|
|
247
|
+
* const cli = createCli()
|
|
248
|
+
*/
|
|
21
249
|
declare function createCli(): Command;
|
|
250
|
+
/**
|
|
251
|
+
* Run the mokup CLI with the provided argv.
|
|
252
|
+
*
|
|
253
|
+
* @param argv - CLI arguments.
|
|
254
|
+
* @returns Exit code or void.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* import { runCli } from '@mokup/cli'
|
|
258
|
+
*
|
|
259
|
+
* await runCli(['node', 'mokup', 'build', '--dir', 'mock'])
|
|
260
|
+
*/
|
|
22
261
|
declare function runCli(argv?: string[]): Promise<void>;
|
|
23
262
|
|
|
24
|
-
export { buildManifest, createCli, runCli };
|
|
25
|
-
export type { BuildOptions };
|
|
263
|
+
export { buildManifest, createCli, defineConfig, runCli };
|
|
264
|
+
export type { BuildOptions, MiddlewarePosition, MiddlewareRegistry, RouteDirectoryConfig, RouteRule };
|
package/dist/index.mjs
CHANGED
|
@@ -7,8 +7,8 @@ import { pathToFileURL } from 'node:url';
|
|
|
7
7
|
import { build } from '@mokup/shared/esbuild';
|
|
8
8
|
import { parseRouteTemplate, compareRouteScore } from '@mokup/runtime';
|
|
9
9
|
import { parse } from '@mokup/shared/jsonc-parser';
|
|
10
|
-
import { createFetchServer } from '@mokup/server';
|
|
11
|
-
import {
|
|
10
|
+
import { createFetchServer, serve } from '@mokup/server/node';
|
|
11
|
+
import { createLogger } from '@mokup/shared/logger';
|
|
12
12
|
import { Command } from 'commander';
|
|
13
13
|
|
|
14
14
|
async function writeBundle(outDir, hasHandlers) {
|
|
@@ -68,6 +68,7 @@ async function writeManifestModule(outDir, manifest) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
71
|
+
const middlewareSymbol$1 = Symbol.for("mokup.config.middlewares");
|
|
71
72
|
async function loadModule$1(file) {
|
|
72
73
|
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
73
74
|
if (ext === ".cjs") {
|
|
@@ -128,7 +129,7 @@ async function loadConfig(file) {
|
|
|
128
129
|
}
|
|
129
130
|
return value;
|
|
130
131
|
}
|
|
131
|
-
function normalizeMiddlewares(value, source, log) {
|
|
132
|
+
function normalizeMiddlewares(value, source, log, position) {
|
|
132
133
|
if (!value) {
|
|
133
134
|
return [];
|
|
134
135
|
}
|
|
@@ -139,10 +140,22 @@ function normalizeMiddlewares(value, source, log) {
|
|
|
139
140
|
log?.(`Invalid middleware in ${source}`);
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
|
-
middlewares.push({ file: source, index });
|
|
143
|
+
middlewares.push({ file: source, index, position });
|
|
143
144
|
});
|
|
144
145
|
return middlewares;
|
|
145
146
|
}
|
|
147
|
+
function readMiddlewareMeta(config) {
|
|
148
|
+
const value = config[middlewareSymbol$1];
|
|
149
|
+
if (!value || typeof value !== "object") {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const meta = value;
|
|
153
|
+
return {
|
|
154
|
+
pre: Array.isArray(meta.pre) ? meta.pre : [],
|
|
155
|
+
normal: Array.isArray(meta.normal) ? meta.normal : [],
|
|
156
|
+
post: Array.isArray(meta.post) ? meta.post : []
|
|
157
|
+
};
|
|
158
|
+
}
|
|
146
159
|
async function resolveDirectoryConfig(params) {
|
|
147
160
|
const { file, rootDir, log, configCache, fileCache } = params;
|
|
148
161
|
const resolvedRoot = normalize(rootDir);
|
|
@@ -161,7 +174,10 @@ async function resolveDirectoryConfig(params) {
|
|
|
161
174
|
current = parent;
|
|
162
175
|
}
|
|
163
176
|
chain.reverse();
|
|
164
|
-
const merged = {
|
|
177
|
+
const merged = {};
|
|
178
|
+
const preMiddlewares = [];
|
|
179
|
+
const normalMiddlewares = [];
|
|
180
|
+
const postMiddlewares = [];
|
|
165
181
|
for (const dir of chain) {
|
|
166
182
|
const configPath = await findConfigFile(dir, fileCache);
|
|
167
183
|
if (!configPath) {
|
|
@@ -197,12 +213,48 @@ async function resolveDirectoryConfig(params) {
|
|
|
197
213
|
if (typeof config.exclude !== "undefined") {
|
|
198
214
|
merged.exclude = config.exclude;
|
|
199
215
|
}
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
216
|
+
const meta = readMiddlewareMeta(config);
|
|
217
|
+
const normalizedPre = normalizeMiddlewares(
|
|
218
|
+
meta?.pre,
|
|
219
|
+
configPath,
|
|
220
|
+
log,
|
|
221
|
+
"pre"
|
|
222
|
+
);
|
|
223
|
+
const normalizedNormal = normalizeMiddlewares(
|
|
224
|
+
meta?.normal,
|
|
225
|
+
configPath,
|
|
226
|
+
log,
|
|
227
|
+
"normal"
|
|
228
|
+
);
|
|
229
|
+
const normalizedLegacy = normalizeMiddlewares(
|
|
230
|
+
config.middleware,
|
|
231
|
+
configPath,
|
|
232
|
+
log,
|
|
233
|
+
"normal"
|
|
234
|
+
);
|
|
235
|
+
const normalizedPost = normalizeMiddlewares(
|
|
236
|
+
meta?.post,
|
|
237
|
+
configPath,
|
|
238
|
+
log,
|
|
239
|
+
"post"
|
|
240
|
+
);
|
|
241
|
+
if (normalizedPre.length > 0) {
|
|
242
|
+
preMiddlewares.push(...normalizedPre);
|
|
243
|
+
}
|
|
244
|
+
if (normalizedNormal.length > 0) {
|
|
245
|
+
normalMiddlewares.push(...normalizedNormal);
|
|
246
|
+
}
|
|
247
|
+
if (normalizedLegacy.length > 0) {
|
|
248
|
+
normalMiddlewares.push(...normalizedLegacy);
|
|
249
|
+
}
|
|
250
|
+
if (normalizedPost.length > 0) {
|
|
251
|
+
postMiddlewares.push(...normalizedPost);
|
|
203
252
|
}
|
|
204
253
|
}
|
|
205
|
-
return
|
|
254
|
+
return {
|
|
255
|
+
...merged,
|
|
256
|
+
middlewares: [...preMiddlewares, ...normalMiddlewares, ...postMiddlewares]
|
|
257
|
+
};
|
|
206
258
|
}
|
|
207
259
|
|
|
208
260
|
function toPosix(value) {
|
|
@@ -757,6 +809,40 @@ async function buildManifest(options = {}) {
|
|
|
757
809
|
};
|
|
758
810
|
}
|
|
759
811
|
|
|
812
|
+
const middlewareSymbol = Symbol.for("mokup.config.middlewares");
|
|
813
|
+
function createRegistry(list) {
|
|
814
|
+
return {
|
|
815
|
+
use: (...handlers) => {
|
|
816
|
+
list.push(...handlers);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
function attachMetadata(config, meta) {
|
|
821
|
+
Object.defineProperty(config, middlewareSymbol, {
|
|
822
|
+
value: meta,
|
|
823
|
+
enumerable: false
|
|
824
|
+
});
|
|
825
|
+
return config;
|
|
826
|
+
}
|
|
827
|
+
function defineConfig(input) {
|
|
828
|
+
if (typeof input === "function") {
|
|
829
|
+
const pre = [];
|
|
830
|
+
const normal = [];
|
|
831
|
+
const post = [];
|
|
832
|
+
const context = {
|
|
833
|
+
pre: createRegistry(pre),
|
|
834
|
+
normal: createRegistry(normal),
|
|
835
|
+
post: createRegistry(post)
|
|
836
|
+
};
|
|
837
|
+
const result = input(context);
|
|
838
|
+
const config2 = result && typeof result === "object" ? result : {};
|
|
839
|
+
return attachMetadata(config2, { pre, normal, post });
|
|
840
|
+
}
|
|
841
|
+
const config = input && typeof input === "object" ? input : {};
|
|
842
|
+
return attachMetadata(config, { pre: [], normal: [], post: [] });
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const logger = createLogger();
|
|
760
846
|
function collectValues(value, previous) {
|
|
761
847
|
return [...previous ?? [], value];
|
|
762
848
|
}
|
|
@@ -769,7 +855,7 @@ function toBuildOptions(options) {
|
|
|
769
855
|
const buildOptions = {
|
|
770
856
|
handlers: options.handlers !== false,
|
|
771
857
|
log: (message) => {
|
|
772
|
-
|
|
858
|
+
logger.info(message);
|
|
773
859
|
}
|
|
774
860
|
};
|
|
775
861
|
if (options.dir && options.dir.length > 0) {
|
|
@@ -822,10 +908,10 @@ function toServeOptions(options) {
|
|
|
822
908
|
}
|
|
823
909
|
serveOptions.port = parsed;
|
|
824
910
|
}
|
|
825
|
-
|
|
826
|
-
serveOptions
|
|
827
|
-
|
|
828
|
-
|
|
911
|
+
return {
|
|
912
|
+
entry: serveOptions,
|
|
913
|
+
playground: options.playground
|
|
914
|
+
};
|
|
829
915
|
}
|
|
830
916
|
function createCli() {
|
|
831
917
|
const program = new Command();
|
|
@@ -836,11 +922,15 @@ function createCli() {
|
|
|
836
922
|
});
|
|
837
923
|
program.command("serve").description("Start a Node.js mock server").option("-d, --dir <dir>", "Mock directory (repeatable)", collectValues).option("--prefix <prefix>", "URL prefix").option("--include <pattern>", "Include regex (repeatable)", collectRegex).option("--exclude <pattern>", "Exclude regex (repeatable)", collectRegex).option("--ignore-prefix <prefix>", "Ignore path segment prefix (repeatable)", collectValues).option("--host <host>", "Hostname (default: localhost)").option("--port <port>", "Port (default: 8080)").option("--no-watch", "Disable file watching").option("--no-playground", "Disable Playground").option("--no-log", "Disable logging").action(async (options) => {
|
|
838
924
|
const serveOptions = toServeOptions(options);
|
|
839
|
-
const
|
|
840
|
-
const
|
|
841
|
-
const
|
|
842
|
-
const
|
|
843
|
-
const
|
|
925
|
+
const { entry, playground } = serveOptions;
|
|
926
|
+
const host = entry.host ?? "localhost";
|
|
927
|
+
const port = entry.port ?? 8080;
|
|
928
|
+
const playgroundEnabled = playground !== false;
|
|
929
|
+
const playgroundPath = "/__mokup";
|
|
930
|
+
const server = await createFetchServer({
|
|
931
|
+
entries: entry,
|
|
932
|
+
playground
|
|
933
|
+
});
|
|
844
934
|
const nodeServer = serve(
|
|
845
935
|
{
|
|
846
936
|
fetch: server.fetch,
|
|
@@ -850,9 +940,9 @@ function createCli() {
|
|
|
850
940
|
(info) => {
|
|
851
941
|
const resolvedHost = typeof info === "string" ? host : info?.address ?? host;
|
|
852
942
|
const resolvedPort = typeof info === "string" ? port : info?.port ?? port;
|
|
853
|
-
|
|
943
|
+
logger.info(`Mock server ready at http://${resolvedHost}:${resolvedPort}`);
|
|
854
944
|
if (playgroundEnabled) {
|
|
855
|
-
|
|
945
|
+
logger.info(`Playground at http://${resolvedHost}:${resolvedPort}${playgroundPath}`);
|
|
856
946
|
}
|
|
857
947
|
}
|
|
858
948
|
);
|
|
@@ -892,4 +982,4 @@ async function runCli(argv = process.argv) {
|
|
|
892
982
|
await program.parseAsync(argv);
|
|
893
983
|
}
|
|
894
984
|
|
|
895
|
-
export { buildManifest, createCli, runCli };
|
|
985
|
+
export { buildManifest, createCli, defineConfig, runCli };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mokup/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"description": "CLI for building mokup manifests and handlers.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://mokup.icebreaker.top",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"commander": "^14.0.0",
|
|
31
|
-
"@mokup/runtime": "1.0.
|
|
32
|
-
"@mokup/server": "1.1.
|
|
33
|
-
"@mokup/shared": "1.0.
|
|
31
|
+
"@mokup/runtime": "1.0.3",
|
|
32
|
+
"@mokup/server": "1.1.3",
|
|
33
|
+
"@mokup/shared": "1.0.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^25.0.10",
|