@mokup/server 0.0.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/LICENSE +21 -0
- package/dist/index.cjs +187 -0
- package/dist/index.d.cts +78 -0
- package/dist/index.d.mts +78 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.mjs +179 -0
- package/dist/shared/server.BdTl0qJd.cjs +264 -0
- package/dist/shared/server.C0FGI34s.d.cts +15 -0
- package/dist/shared/server.C0FGI34s.d.mts +15 -0
- package/dist/shared/server.C0FGI34s.d.ts +15 -0
- package/dist/shared/server.HVB7OYyI.mjs +258 -0
- package/dist/worker.cjs +43 -0
- package/dist/worker.d.cts +10 -0
- package/dist/worker.d.mts +10 -0
- package/dist/worker.d.ts +10 -0
- package/dist/worker.mjs +41 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ice breaker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const runtime = require('@mokup/runtime');
|
|
4
|
+
const fetch = require('./shared/server.BdTl0qJd.cjs');
|
|
5
|
+
|
|
6
|
+
function createConnectMiddleware(options) {
|
|
7
|
+
const runtime$1 = runtime.createRuntime(fetch.toRuntimeOptions(options));
|
|
8
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
9
|
+
return async (req, res, next) => {
|
|
10
|
+
const runtimeRequest = await fetch.toRuntimeRequestFromNode(req);
|
|
11
|
+
const result = await runtime$1.handle(runtimeRequest);
|
|
12
|
+
if (!result) {
|
|
13
|
+
if (onNotFound === "response") {
|
|
14
|
+
res.statusCode = 404;
|
|
15
|
+
res.end();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
next();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
fetch.applyRuntimeResultToNode(res, result);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createExpressMiddleware(options) {
|
|
26
|
+
return createConnectMiddleware(options);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createFastifyPlugin(options) {
|
|
30
|
+
const runtime$1 = runtime.createRuntime(fetch.toRuntimeOptions(options));
|
|
31
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
32
|
+
return async (instance) => {
|
|
33
|
+
instance.addHook("onRequest", async (request, reply) => {
|
|
34
|
+
const runtimeRequest = await fetch.toRuntimeRequestFromNode(
|
|
35
|
+
request.raw ?? request,
|
|
36
|
+
request.body
|
|
37
|
+
);
|
|
38
|
+
const result = await runtime$1.handle(runtimeRequest);
|
|
39
|
+
if (!result) {
|
|
40
|
+
if (onNotFound === "response") {
|
|
41
|
+
reply.status(404).send();
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
reply.status(result.status);
|
|
46
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
47
|
+
reply.header(key, value);
|
|
48
|
+
}
|
|
49
|
+
if (result.body === null) {
|
|
50
|
+
reply.send();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (typeof result.body === "string") {
|
|
54
|
+
reply.send(result.body);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
reply.send(fetch.toBinaryBody(result.body));
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createHonoMiddleware(options) {
|
|
63
|
+
const handler = fetch.createFetchHandler(options);
|
|
64
|
+
const middleware = async (context, next) => {
|
|
65
|
+
const response = await handler(context.req.raw);
|
|
66
|
+
if (!response) {
|
|
67
|
+
return await next();
|
|
68
|
+
}
|
|
69
|
+
return response;
|
|
70
|
+
};
|
|
71
|
+
const route = {
|
|
72
|
+
basePath: "",
|
|
73
|
+
path: "*",
|
|
74
|
+
method: "ALL",
|
|
75
|
+
handler: middleware
|
|
76
|
+
};
|
|
77
|
+
const bridge = middleware;
|
|
78
|
+
bridge.routes = [route];
|
|
79
|
+
return bridge;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function createKoaMiddleware(options) {
|
|
83
|
+
const runtime$1 = runtime.createRuntime(fetch.toRuntimeOptions(options));
|
|
84
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
85
|
+
return async (ctx, next) => {
|
|
86
|
+
const runtimeRequest = await fetch.toRuntimeRequestFromNode(
|
|
87
|
+
ctx.req,
|
|
88
|
+
ctx.request?.body
|
|
89
|
+
);
|
|
90
|
+
const result = await runtime$1.handle(runtimeRequest);
|
|
91
|
+
if (!result) {
|
|
92
|
+
if (onNotFound === "response") {
|
|
93
|
+
ctx.status = 404;
|
|
94
|
+
ctx.body = null;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await next();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
ctx.status = result.status;
|
|
101
|
+
ctx.set(result.headers);
|
|
102
|
+
if (result.body === null) {
|
|
103
|
+
ctx.body = null;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (typeof result.body === "string") {
|
|
107
|
+
ctx.body = result.body;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
ctx.body = fetch.toBinaryBody(result.body);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function isManifest(value) {
|
|
115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "version" in value && "routes" in value;
|
|
116
|
+
}
|
|
117
|
+
function normalizeWorkerOptions(bundle) {
|
|
118
|
+
const options = {
|
|
119
|
+
manifest: bundle.manifest,
|
|
120
|
+
onNotFound: bundle.onNotFound ?? "response"
|
|
121
|
+
};
|
|
122
|
+
if (typeof bundle.moduleBase !== "undefined") {
|
|
123
|
+
options.moduleBase = bundle.moduleBase;
|
|
124
|
+
}
|
|
125
|
+
if (typeof bundle.moduleMap !== "undefined") {
|
|
126
|
+
options.moduleMap = bundle.moduleMap;
|
|
127
|
+
}
|
|
128
|
+
return options;
|
|
129
|
+
}
|
|
130
|
+
async function loadBundleFromDir(dir) {
|
|
131
|
+
const nodeProcess = await import('node:process');
|
|
132
|
+
const isNode = typeof nodeProcess !== "undefined" && !!nodeProcess.versions?.node;
|
|
133
|
+
if (!isNode) {
|
|
134
|
+
throw new TypeError("createMokupWorker(dir) is only supported in Node runtimes.");
|
|
135
|
+
}
|
|
136
|
+
const { readFile, access } = await import('node:fs/promises');
|
|
137
|
+
const { resolve, join } = await import('node:path');
|
|
138
|
+
const { pathToFileURL } = await import('node:url');
|
|
139
|
+
const manifestPath = resolve(dir, "mokup.manifest.json");
|
|
140
|
+
const manifestRaw = await readFile(manifestPath, "utf8");
|
|
141
|
+
const manifest = JSON.parse(manifestRaw);
|
|
142
|
+
const handlersIndexPath = resolve(dir, "mokup-handlers", "index.mjs");
|
|
143
|
+
let moduleMap;
|
|
144
|
+
try {
|
|
145
|
+
await access(handlersIndexPath);
|
|
146
|
+
const module = await import(pathToFileURL(handlersIndexPath).href);
|
|
147
|
+
moduleMap = module.mokupModuleMap;
|
|
148
|
+
} catch {
|
|
149
|
+
moduleMap = void 0;
|
|
150
|
+
}
|
|
151
|
+
const bundle = {
|
|
152
|
+
manifest,
|
|
153
|
+
moduleBase: join(dir, "/")
|
|
154
|
+
};
|
|
155
|
+
if (typeof moduleMap !== "undefined") {
|
|
156
|
+
bundle.moduleMap = moduleMap;
|
|
157
|
+
}
|
|
158
|
+
return bundle;
|
|
159
|
+
}
|
|
160
|
+
function createWorker(handlerOptions) {
|
|
161
|
+
const handler = fetch.createFetchHandler(handlerOptions);
|
|
162
|
+
return {
|
|
163
|
+
fetch: async (request) => {
|
|
164
|
+
return await handler(request) ?? new Response("Not Found", { status: 404 });
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function createMokupWorker(input) {
|
|
169
|
+
if (typeof input === "string") {
|
|
170
|
+
return loadBundleFromDir(input).then((bundle) => createWorker(normalizeWorkerOptions(bundle)));
|
|
171
|
+
}
|
|
172
|
+
if (isManifest(input)) {
|
|
173
|
+
return createWorker({
|
|
174
|
+
manifest: input,
|
|
175
|
+
onNotFound: "response"
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return createWorker(normalizeWorkerOptions(input));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
exports.createFetchHandler = fetch.createFetchHandler;
|
|
182
|
+
exports.createConnectMiddleware = createConnectMiddleware;
|
|
183
|
+
exports.createExpressMiddleware = createExpressMiddleware;
|
|
184
|
+
exports.createFastifyPlugin = createFastifyPlugin;
|
|
185
|
+
exports.createHonoMiddleware = createHonoMiddleware;
|
|
186
|
+
exports.createKoaMiddleware = createKoaMiddleware;
|
|
187
|
+
exports.createMokupWorker = createMokupWorker;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { M as MokupServerOptions, F as FetchHandler, a as MokupWorkerInput } from './shared/server.C0FGI34s.cjs';
|
|
2
|
+
export { b as MokupWorkerBundle } from './shared/server.C0FGI34s.cjs';
|
|
3
|
+
export { Manifest, ManifestRoute, ModuleMap, RuntimeOptions } from '@mokup/runtime';
|
|
4
|
+
|
|
5
|
+
interface ReadableStreamLike {
|
|
6
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
7
|
+
}
|
|
8
|
+
interface NodeRequestLike extends ReadableStreamLike {
|
|
9
|
+
method?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
originalUrl?: string;
|
|
12
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
13
|
+
body?: unknown;
|
|
14
|
+
}
|
|
15
|
+
interface NodeResponseLike {
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
setHeader: (name: string, value: string) => void;
|
|
18
|
+
end: (data?: string | Uint8Array | ArrayBuffer | null) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type NextFunction = (error?: unknown) => void;
|
|
22
|
+
declare function createConnectMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: NextFunction) => Promise<void>;
|
|
23
|
+
|
|
24
|
+
declare function createExpressMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: (error?: unknown) => void) => Promise<void>;
|
|
25
|
+
|
|
26
|
+
interface FastifyRequestLike extends NodeRequestLike {
|
|
27
|
+
raw?: NodeRequestLike;
|
|
28
|
+
}
|
|
29
|
+
interface FastifyReplyLike {
|
|
30
|
+
status: (code: number) => FastifyReplyLike;
|
|
31
|
+
header: (name: string, value: string) => FastifyReplyLike;
|
|
32
|
+
send: (payload?: unknown) => void;
|
|
33
|
+
}
|
|
34
|
+
interface FastifyInstanceLike {
|
|
35
|
+
addHook: (name: 'onRequest' | 'preHandler', handler: (request: FastifyRequestLike, reply: FastifyReplyLike) => Promise<void> | void) => void;
|
|
36
|
+
}
|
|
37
|
+
declare function createFastifyPlugin(options: MokupServerOptions): (instance: FastifyInstanceLike) => Promise<void>;
|
|
38
|
+
|
|
39
|
+
declare function createFetchHandler(options: MokupServerOptions): FetchHandler;
|
|
40
|
+
|
|
41
|
+
interface HonoContextLike {
|
|
42
|
+
req: {
|
|
43
|
+
raw: Request;
|
|
44
|
+
};
|
|
45
|
+
notFound?: () => Response;
|
|
46
|
+
}
|
|
47
|
+
type HonoNext = () => Promise<unknown>;
|
|
48
|
+
type HonoMiddleware = (context: HonoContextLike, next: HonoNext) => Promise<unknown>;
|
|
49
|
+
interface HonoRouteLike {
|
|
50
|
+
basePath: string;
|
|
51
|
+
path: string;
|
|
52
|
+
method: string;
|
|
53
|
+
handler: HonoMiddleware;
|
|
54
|
+
}
|
|
55
|
+
declare function createHonoMiddleware(options: MokupServerOptions): HonoMiddleware & {
|
|
56
|
+
routes: HonoRouteLike[];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface KoaContextLike {
|
|
60
|
+
req: NodeRequestLike;
|
|
61
|
+
request?: {
|
|
62
|
+
body?: unknown;
|
|
63
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
64
|
+
};
|
|
65
|
+
status?: number;
|
|
66
|
+
body?: unknown;
|
|
67
|
+
set: (header: Record<string, string>) => void;
|
|
68
|
+
}
|
|
69
|
+
type KoaNext = () => Promise<unknown>;
|
|
70
|
+
declare function createKoaMiddleware(options: MokupServerOptions): (ctx: KoaContextLike, next: KoaNext) => Promise<void>;
|
|
71
|
+
|
|
72
|
+
interface MokupWorker {
|
|
73
|
+
fetch: (request: Request) => Promise<Response>;
|
|
74
|
+
}
|
|
75
|
+
declare function createMokupWorker(input: string): Promise<MokupWorker>;
|
|
76
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
77
|
+
|
|
78
|
+
export { FetchHandler, MokupServerOptions, MokupWorkerInput, createConnectMiddleware, createExpressMiddleware, createFastifyPlugin, createFetchHandler, createHonoMiddleware, createKoaMiddleware, createMokupWorker };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { M as MokupServerOptions, F as FetchHandler, a as MokupWorkerInput } from './shared/server.C0FGI34s.mjs';
|
|
2
|
+
export { b as MokupWorkerBundle } from './shared/server.C0FGI34s.mjs';
|
|
3
|
+
export { Manifest, ManifestRoute, ModuleMap, RuntimeOptions } from '@mokup/runtime';
|
|
4
|
+
|
|
5
|
+
interface ReadableStreamLike {
|
|
6
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
7
|
+
}
|
|
8
|
+
interface NodeRequestLike extends ReadableStreamLike {
|
|
9
|
+
method?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
originalUrl?: string;
|
|
12
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
13
|
+
body?: unknown;
|
|
14
|
+
}
|
|
15
|
+
interface NodeResponseLike {
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
setHeader: (name: string, value: string) => void;
|
|
18
|
+
end: (data?: string | Uint8Array | ArrayBuffer | null) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type NextFunction = (error?: unknown) => void;
|
|
22
|
+
declare function createConnectMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: NextFunction) => Promise<void>;
|
|
23
|
+
|
|
24
|
+
declare function createExpressMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: (error?: unknown) => void) => Promise<void>;
|
|
25
|
+
|
|
26
|
+
interface FastifyRequestLike extends NodeRequestLike {
|
|
27
|
+
raw?: NodeRequestLike;
|
|
28
|
+
}
|
|
29
|
+
interface FastifyReplyLike {
|
|
30
|
+
status: (code: number) => FastifyReplyLike;
|
|
31
|
+
header: (name: string, value: string) => FastifyReplyLike;
|
|
32
|
+
send: (payload?: unknown) => void;
|
|
33
|
+
}
|
|
34
|
+
interface FastifyInstanceLike {
|
|
35
|
+
addHook: (name: 'onRequest' | 'preHandler', handler: (request: FastifyRequestLike, reply: FastifyReplyLike) => Promise<void> | void) => void;
|
|
36
|
+
}
|
|
37
|
+
declare function createFastifyPlugin(options: MokupServerOptions): (instance: FastifyInstanceLike) => Promise<void>;
|
|
38
|
+
|
|
39
|
+
declare function createFetchHandler(options: MokupServerOptions): FetchHandler;
|
|
40
|
+
|
|
41
|
+
interface HonoContextLike {
|
|
42
|
+
req: {
|
|
43
|
+
raw: Request;
|
|
44
|
+
};
|
|
45
|
+
notFound?: () => Response;
|
|
46
|
+
}
|
|
47
|
+
type HonoNext = () => Promise<unknown>;
|
|
48
|
+
type HonoMiddleware = (context: HonoContextLike, next: HonoNext) => Promise<unknown>;
|
|
49
|
+
interface HonoRouteLike {
|
|
50
|
+
basePath: string;
|
|
51
|
+
path: string;
|
|
52
|
+
method: string;
|
|
53
|
+
handler: HonoMiddleware;
|
|
54
|
+
}
|
|
55
|
+
declare function createHonoMiddleware(options: MokupServerOptions): HonoMiddleware & {
|
|
56
|
+
routes: HonoRouteLike[];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface KoaContextLike {
|
|
60
|
+
req: NodeRequestLike;
|
|
61
|
+
request?: {
|
|
62
|
+
body?: unknown;
|
|
63
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
64
|
+
};
|
|
65
|
+
status?: number;
|
|
66
|
+
body?: unknown;
|
|
67
|
+
set: (header: Record<string, string>) => void;
|
|
68
|
+
}
|
|
69
|
+
type KoaNext = () => Promise<unknown>;
|
|
70
|
+
declare function createKoaMiddleware(options: MokupServerOptions): (ctx: KoaContextLike, next: KoaNext) => Promise<void>;
|
|
71
|
+
|
|
72
|
+
interface MokupWorker {
|
|
73
|
+
fetch: (request: Request) => Promise<Response>;
|
|
74
|
+
}
|
|
75
|
+
declare function createMokupWorker(input: string): Promise<MokupWorker>;
|
|
76
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
77
|
+
|
|
78
|
+
export { FetchHandler, MokupServerOptions, MokupWorkerInput, createConnectMiddleware, createExpressMiddleware, createFastifyPlugin, createFetchHandler, createHonoMiddleware, createKoaMiddleware, createMokupWorker };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { M as MokupServerOptions, F as FetchHandler, a as MokupWorkerInput } from './shared/server.C0FGI34s.js';
|
|
2
|
+
export { b as MokupWorkerBundle } from './shared/server.C0FGI34s.js';
|
|
3
|
+
export { Manifest, ManifestRoute, ModuleMap, RuntimeOptions } from '@mokup/runtime';
|
|
4
|
+
|
|
5
|
+
interface ReadableStreamLike {
|
|
6
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
7
|
+
}
|
|
8
|
+
interface NodeRequestLike extends ReadableStreamLike {
|
|
9
|
+
method?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
originalUrl?: string;
|
|
12
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
13
|
+
body?: unknown;
|
|
14
|
+
}
|
|
15
|
+
interface NodeResponseLike {
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
setHeader: (name: string, value: string) => void;
|
|
18
|
+
end: (data?: string | Uint8Array | ArrayBuffer | null) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type NextFunction = (error?: unknown) => void;
|
|
22
|
+
declare function createConnectMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: NextFunction) => Promise<void>;
|
|
23
|
+
|
|
24
|
+
declare function createExpressMiddleware(options: MokupServerOptions): (req: NodeRequestLike, res: NodeResponseLike, next: (error?: unknown) => void) => Promise<void>;
|
|
25
|
+
|
|
26
|
+
interface FastifyRequestLike extends NodeRequestLike {
|
|
27
|
+
raw?: NodeRequestLike;
|
|
28
|
+
}
|
|
29
|
+
interface FastifyReplyLike {
|
|
30
|
+
status: (code: number) => FastifyReplyLike;
|
|
31
|
+
header: (name: string, value: string) => FastifyReplyLike;
|
|
32
|
+
send: (payload?: unknown) => void;
|
|
33
|
+
}
|
|
34
|
+
interface FastifyInstanceLike {
|
|
35
|
+
addHook: (name: 'onRequest' | 'preHandler', handler: (request: FastifyRequestLike, reply: FastifyReplyLike) => Promise<void> | void) => void;
|
|
36
|
+
}
|
|
37
|
+
declare function createFastifyPlugin(options: MokupServerOptions): (instance: FastifyInstanceLike) => Promise<void>;
|
|
38
|
+
|
|
39
|
+
declare function createFetchHandler(options: MokupServerOptions): FetchHandler;
|
|
40
|
+
|
|
41
|
+
interface HonoContextLike {
|
|
42
|
+
req: {
|
|
43
|
+
raw: Request;
|
|
44
|
+
};
|
|
45
|
+
notFound?: () => Response;
|
|
46
|
+
}
|
|
47
|
+
type HonoNext = () => Promise<unknown>;
|
|
48
|
+
type HonoMiddleware = (context: HonoContextLike, next: HonoNext) => Promise<unknown>;
|
|
49
|
+
interface HonoRouteLike {
|
|
50
|
+
basePath: string;
|
|
51
|
+
path: string;
|
|
52
|
+
method: string;
|
|
53
|
+
handler: HonoMiddleware;
|
|
54
|
+
}
|
|
55
|
+
declare function createHonoMiddleware(options: MokupServerOptions): HonoMiddleware & {
|
|
56
|
+
routes: HonoRouteLike[];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface KoaContextLike {
|
|
60
|
+
req: NodeRequestLike;
|
|
61
|
+
request?: {
|
|
62
|
+
body?: unknown;
|
|
63
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
64
|
+
};
|
|
65
|
+
status?: number;
|
|
66
|
+
body?: unknown;
|
|
67
|
+
set: (header: Record<string, string>) => void;
|
|
68
|
+
}
|
|
69
|
+
type KoaNext = () => Promise<unknown>;
|
|
70
|
+
declare function createKoaMiddleware(options: MokupServerOptions): (ctx: KoaContextLike, next: KoaNext) => Promise<void>;
|
|
71
|
+
|
|
72
|
+
interface MokupWorker {
|
|
73
|
+
fetch: (request: Request) => Promise<Response>;
|
|
74
|
+
}
|
|
75
|
+
declare function createMokupWorker(input: string): Promise<MokupWorker>;
|
|
76
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
77
|
+
|
|
78
|
+
export { FetchHandler, MokupServerOptions, MokupWorkerInput, createConnectMiddleware, createExpressMiddleware, createFastifyPlugin, createFetchHandler, createHonoMiddleware, createKoaMiddleware, createMokupWorker };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { createRuntime } from '@mokup/runtime';
|
|
2
|
+
import { t as toRuntimeOptions, a as toRuntimeRequestFromNode, b as applyRuntimeResultToNode, c as toBinaryBody, d as createFetchHandler } from './shared/server.HVB7OYyI.mjs';
|
|
3
|
+
|
|
4
|
+
function createConnectMiddleware(options) {
|
|
5
|
+
const runtime = createRuntime(toRuntimeOptions(options));
|
|
6
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
7
|
+
return async (req, res, next) => {
|
|
8
|
+
const runtimeRequest = await toRuntimeRequestFromNode(req);
|
|
9
|
+
const result = await runtime.handle(runtimeRequest);
|
|
10
|
+
if (!result) {
|
|
11
|
+
if (onNotFound === "response") {
|
|
12
|
+
res.statusCode = 404;
|
|
13
|
+
res.end();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
next();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
applyRuntimeResultToNode(res, result);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createExpressMiddleware(options) {
|
|
24
|
+
return createConnectMiddleware(options);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createFastifyPlugin(options) {
|
|
28
|
+
const runtime = createRuntime(toRuntimeOptions(options));
|
|
29
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
30
|
+
return async (instance) => {
|
|
31
|
+
instance.addHook("onRequest", async (request, reply) => {
|
|
32
|
+
const runtimeRequest = await toRuntimeRequestFromNode(
|
|
33
|
+
request.raw ?? request,
|
|
34
|
+
request.body
|
|
35
|
+
);
|
|
36
|
+
const result = await runtime.handle(runtimeRequest);
|
|
37
|
+
if (!result) {
|
|
38
|
+
if (onNotFound === "response") {
|
|
39
|
+
reply.status(404).send();
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
reply.status(result.status);
|
|
44
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
45
|
+
reply.header(key, value);
|
|
46
|
+
}
|
|
47
|
+
if (result.body === null) {
|
|
48
|
+
reply.send();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (typeof result.body === "string") {
|
|
52
|
+
reply.send(result.body);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
reply.send(toBinaryBody(result.body));
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function createHonoMiddleware(options) {
|
|
61
|
+
const handler = createFetchHandler(options);
|
|
62
|
+
const middleware = async (context, next) => {
|
|
63
|
+
const response = await handler(context.req.raw);
|
|
64
|
+
if (!response) {
|
|
65
|
+
return await next();
|
|
66
|
+
}
|
|
67
|
+
return response;
|
|
68
|
+
};
|
|
69
|
+
const route = {
|
|
70
|
+
basePath: "",
|
|
71
|
+
path: "*",
|
|
72
|
+
method: "ALL",
|
|
73
|
+
handler: middleware
|
|
74
|
+
};
|
|
75
|
+
const bridge = middleware;
|
|
76
|
+
bridge.routes = [route];
|
|
77
|
+
return bridge;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createKoaMiddleware(options) {
|
|
81
|
+
const runtime = createRuntime(toRuntimeOptions(options));
|
|
82
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
83
|
+
return async (ctx, next) => {
|
|
84
|
+
const runtimeRequest = await toRuntimeRequestFromNode(
|
|
85
|
+
ctx.req,
|
|
86
|
+
ctx.request?.body
|
|
87
|
+
);
|
|
88
|
+
const result = await runtime.handle(runtimeRequest);
|
|
89
|
+
if (!result) {
|
|
90
|
+
if (onNotFound === "response") {
|
|
91
|
+
ctx.status = 404;
|
|
92
|
+
ctx.body = null;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
await next();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
ctx.status = result.status;
|
|
99
|
+
ctx.set(result.headers);
|
|
100
|
+
if (result.body === null) {
|
|
101
|
+
ctx.body = null;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (typeof result.body === "string") {
|
|
105
|
+
ctx.body = result.body;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
ctx.body = toBinaryBody(result.body);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isManifest(value) {
|
|
113
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "version" in value && "routes" in value;
|
|
114
|
+
}
|
|
115
|
+
function normalizeWorkerOptions(bundle) {
|
|
116
|
+
const options = {
|
|
117
|
+
manifest: bundle.manifest,
|
|
118
|
+
onNotFound: bundle.onNotFound ?? "response"
|
|
119
|
+
};
|
|
120
|
+
if (typeof bundle.moduleBase !== "undefined") {
|
|
121
|
+
options.moduleBase = bundle.moduleBase;
|
|
122
|
+
}
|
|
123
|
+
if (typeof bundle.moduleMap !== "undefined") {
|
|
124
|
+
options.moduleMap = bundle.moduleMap;
|
|
125
|
+
}
|
|
126
|
+
return options;
|
|
127
|
+
}
|
|
128
|
+
async function loadBundleFromDir(dir) {
|
|
129
|
+
const nodeProcess = await import('node:process');
|
|
130
|
+
const isNode = typeof nodeProcess !== "undefined" && !!nodeProcess.versions?.node;
|
|
131
|
+
if (!isNode) {
|
|
132
|
+
throw new TypeError("createMokupWorker(dir) is only supported in Node runtimes.");
|
|
133
|
+
}
|
|
134
|
+
const { readFile, access } = await import('node:fs/promises');
|
|
135
|
+
const { resolve, join } = await import('node:path');
|
|
136
|
+
const { pathToFileURL } = await import('node:url');
|
|
137
|
+
const manifestPath = resolve(dir, "mokup.manifest.json");
|
|
138
|
+
const manifestRaw = await readFile(manifestPath, "utf8");
|
|
139
|
+
const manifest = JSON.parse(manifestRaw);
|
|
140
|
+
const handlersIndexPath = resolve(dir, "mokup-handlers", "index.mjs");
|
|
141
|
+
let moduleMap;
|
|
142
|
+
try {
|
|
143
|
+
await access(handlersIndexPath);
|
|
144
|
+
const module = await import(pathToFileURL(handlersIndexPath).href);
|
|
145
|
+
moduleMap = module.mokupModuleMap;
|
|
146
|
+
} catch {
|
|
147
|
+
moduleMap = void 0;
|
|
148
|
+
}
|
|
149
|
+
const bundle = {
|
|
150
|
+
manifest,
|
|
151
|
+
moduleBase: join(dir, "/")
|
|
152
|
+
};
|
|
153
|
+
if (typeof moduleMap !== "undefined") {
|
|
154
|
+
bundle.moduleMap = moduleMap;
|
|
155
|
+
}
|
|
156
|
+
return bundle;
|
|
157
|
+
}
|
|
158
|
+
function createWorker(handlerOptions) {
|
|
159
|
+
const handler = createFetchHandler(handlerOptions);
|
|
160
|
+
return {
|
|
161
|
+
fetch: async (request) => {
|
|
162
|
+
return await handler(request) ?? new Response("Not Found", { status: 404 });
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function createMokupWorker(input) {
|
|
167
|
+
if (typeof input === "string") {
|
|
168
|
+
return loadBundleFromDir(input).then((bundle) => createWorker(normalizeWorkerOptions(bundle)));
|
|
169
|
+
}
|
|
170
|
+
if (isManifest(input)) {
|
|
171
|
+
return createWorker({
|
|
172
|
+
manifest: input,
|
|
173
|
+
onNotFound: "response"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return createWorker(normalizeWorkerOptions(input));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export { createConnectMiddleware, createExpressMiddleware, createFastifyPlugin, createFetchHandler, createHonoMiddleware, createKoaMiddleware, createMokupWorker };
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const runtime = require('@mokup/runtime');
|
|
4
|
+
|
|
5
|
+
const textDecoder = new TextDecoder();
|
|
6
|
+
const textEncoder = new TextEncoder();
|
|
7
|
+
function toRuntimeOptions(options) {
|
|
8
|
+
const runtimeOptions = {
|
|
9
|
+
manifest: options.manifest
|
|
10
|
+
};
|
|
11
|
+
if (typeof options.moduleBase !== "undefined") {
|
|
12
|
+
runtimeOptions.moduleBase = options.moduleBase;
|
|
13
|
+
}
|
|
14
|
+
if (typeof options.moduleMap !== "undefined") {
|
|
15
|
+
runtimeOptions.moduleMap = options.moduleMap;
|
|
16
|
+
}
|
|
17
|
+
return runtimeOptions;
|
|
18
|
+
}
|
|
19
|
+
function normalizeQuery(params) {
|
|
20
|
+
const query = {};
|
|
21
|
+
for (const [key, value] of params.entries()) {
|
|
22
|
+
const current = query[key];
|
|
23
|
+
if (typeof current === "undefined") {
|
|
24
|
+
query[key] = value;
|
|
25
|
+
} else if (Array.isArray(current)) {
|
|
26
|
+
current.push(value);
|
|
27
|
+
} else {
|
|
28
|
+
query[key] = [current, value];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return query;
|
|
32
|
+
}
|
|
33
|
+
function normalizeHeaders(headers) {
|
|
34
|
+
const record = {};
|
|
35
|
+
headers.forEach((value, key) => {
|
|
36
|
+
record[key.toLowerCase()] = value;
|
|
37
|
+
});
|
|
38
|
+
return record;
|
|
39
|
+
}
|
|
40
|
+
function normalizeNodeHeaders(headers) {
|
|
41
|
+
if (!headers) {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
const record = {};
|
|
45
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
46
|
+
if (typeof value === "undefined") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
record[key.toLowerCase()] = Array.isArray(value) ? value.join(",") : String(value);
|
|
50
|
+
}
|
|
51
|
+
return record;
|
|
52
|
+
}
|
|
53
|
+
function parseBody(rawText, contentType) {
|
|
54
|
+
if (!rawText) {
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
if (contentType === "application/json" || contentType.endsWith("+json")) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(rawText);
|
|
60
|
+
} catch {
|
|
61
|
+
return rawText;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
65
|
+
const params = new URLSearchParams(rawText);
|
|
66
|
+
return Object.fromEntries(params.entries());
|
|
67
|
+
}
|
|
68
|
+
return rawText;
|
|
69
|
+
}
|
|
70
|
+
function decodeText(data) {
|
|
71
|
+
return textDecoder.decode(data);
|
|
72
|
+
}
|
|
73
|
+
function toBinaryBody(body) {
|
|
74
|
+
return body;
|
|
75
|
+
}
|
|
76
|
+
function toArrayBuffer(body) {
|
|
77
|
+
const { buffer, byteOffset, byteLength } = body;
|
|
78
|
+
if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength) {
|
|
79
|
+
return buffer;
|
|
80
|
+
}
|
|
81
|
+
const copy = new Uint8Array(byteLength);
|
|
82
|
+
copy.set(body);
|
|
83
|
+
return copy.buffer;
|
|
84
|
+
}
|
|
85
|
+
function resolveUrl(input, headers) {
|
|
86
|
+
if (/^https?:\/\//.test(input)) {
|
|
87
|
+
return new URL(input);
|
|
88
|
+
}
|
|
89
|
+
const host = headers.host;
|
|
90
|
+
const base = host ? `http://${host}` : "http://localhost";
|
|
91
|
+
return new URL(input, base);
|
|
92
|
+
}
|
|
93
|
+
function concatChunks(chunks) {
|
|
94
|
+
if (chunks.length === 1) {
|
|
95
|
+
return chunks[0] ?? new Uint8Array();
|
|
96
|
+
}
|
|
97
|
+
let totalLength = 0;
|
|
98
|
+
for (const chunk of chunks) {
|
|
99
|
+
totalLength += chunk.length;
|
|
100
|
+
}
|
|
101
|
+
const merged = new Uint8Array(totalLength);
|
|
102
|
+
let offset = 0;
|
|
103
|
+
for (const chunk of chunks) {
|
|
104
|
+
merged.set(chunk, offset);
|
|
105
|
+
offset += chunk.length;
|
|
106
|
+
}
|
|
107
|
+
return merged;
|
|
108
|
+
}
|
|
109
|
+
async function readStreamBody(stream) {
|
|
110
|
+
return await new Promise((resolve, reject) => {
|
|
111
|
+
const chunks = [];
|
|
112
|
+
let hasData = false;
|
|
113
|
+
stream.on("data", (chunk) => {
|
|
114
|
+
hasData = true;
|
|
115
|
+
if (typeof chunk === "string") {
|
|
116
|
+
chunks.push(textEncoder.encode(chunk));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (chunk instanceof Uint8Array) {
|
|
120
|
+
chunks.push(chunk);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (chunk instanceof ArrayBuffer) {
|
|
124
|
+
chunks.push(new Uint8Array(chunk));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
chunks.push(textEncoder.encode(String(chunk)));
|
|
128
|
+
});
|
|
129
|
+
stream.on("end", () => {
|
|
130
|
+
if (!hasData) {
|
|
131
|
+
resolve(null);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
resolve(concatChunks(chunks));
|
|
135
|
+
});
|
|
136
|
+
stream.on("error", (error) => {
|
|
137
|
+
reject(error);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async function resolveBody(body, contentType, stream) {
|
|
142
|
+
if (typeof body !== "undefined") {
|
|
143
|
+
if (typeof body === "string") {
|
|
144
|
+
return {
|
|
145
|
+
body: parseBody(body, contentType),
|
|
146
|
+
rawBody: body
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (body instanceof Uint8Array) {
|
|
150
|
+
const rawText2 = decodeText(body);
|
|
151
|
+
return {
|
|
152
|
+
body: parseBody(rawText2, contentType),
|
|
153
|
+
rawBody: rawText2
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (body instanceof ArrayBuffer) {
|
|
157
|
+
const rawText2 = decodeText(new Uint8Array(body));
|
|
158
|
+
return {
|
|
159
|
+
body: parseBody(rawText2, contentType),
|
|
160
|
+
rawBody: rawText2
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
body
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (!stream) {
|
|
168
|
+
return { body: void 0 };
|
|
169
|
+
}
|
|
170
|
+
const rawBytes = await readStreamBody(stream);
|
|
171
|
+
if (!rawBytes || rawBytes.length === 0) {
|
|
172
|
+
return { body: void 0 };
|
|
173
|
+
}
|
|
174
|
+
const rawText = decodeText(rawBytes);
|
|
175
|
+
return {
|
|
176
|
+
body: parseBody(rawText, contentType),
|
|
177
|
+
rawBody: rawText
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function buildRuntimeRequest(url, method, headers, body, rawBody) {
|
|
181
|
+
const request = {
|
|
182
|
+
method,
|
|
183
|
+
path: url.pathname,
|
|
184
|
+
query: normalizeQuery(url.searchParams),
|
|
185
|
+
headers,
|
|
186
|
+
body
|
|
187
|
+
};
|
|
188
|
+
if (rawBody) {
|
|
189
|
+
request.rawBody = rawBody;
|
|
190
|
+
}
|
|
191
|
+
return request;
|
|
192
|
+
}
|
|
193
|
+
async function toRuntimeRequestFromFetch(request) {
|
|
194
|
+
const url = new URL(request.url);
|
|
195
|
+
const headers = normalizeHeaders(request.headers);
|
|
196
|
+
const contentType = (headers["content-type"] ?? "").split(";")[0]?.trim() ?? "";
|
|
197
|
+
const rawBody = await request.text();
|
|
198
|
+
const body = parseBody(rawBody, contentType);
|
|
199
|
+
return buildRuntimeRequest(
|
|
200
|
+
url,
|
|
201
|
+
request.method,
|
|
202
|
+
headers,
|
|
203
|
+
body,
|
|
204
|
+
rawBody || void 0
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
async function toRuntimeRequestFromNode(req, bodyOverride) {
|
|
208
|
+
const headers = normalizeNodeHeaders(req.headers);
|
|
209
|
+
const contentType = (headers["content-type"] ?? "").split(";")[0]?.trim() ?? "";
|
|
210
|
+
const url = resolveUrl(req.originalUrl ?? req.url ?? "/", headers);
|
|
211
|
+
const resolvedBody = await resolveBody(
|
|
212
|
+
typeof bodyOverride === "undefined" ? req.body : bodyOverride,
|
|
213
|
+
contentType,
|
|
214
|
+
req
|
|
215
|
+
);
|
|
216
|
+
return buildRuntimeRequest(
|
|
217
|
+
url,
|
|
218
|
+
req.method ?? "GET",
|
|
219
|
+
headers,
|
|
220
|
+
resolvedBody.body,
|
|
221
|
+
resolvedBody.rawBody
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function applyRuntimeResultToNode(res, result) {
|
|
225
|
+
res.statusCode = result.status;
|
|
226
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
227
|
+
res.setHeader(key, value);
|
|
228
|
+
}
|
|
229
|
+
if (result.body === null) {
|
|
230
|
+
res.end();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (typeof result.body === "string") {
|
|
234
|
+
res.end(result.body);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
res.end(toBinaryBody(result.body));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function createFetchHandler(options) {
|
|
241
|
+
const runtime$1 = runtime.createRuntime(toRuntimeOptions(options));
|
|
242
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
243
|
+
return async (request) => {
|
|
244
|
+
const runtimeRequest = await toRuntimeRequestFromFetch(request);
|
|
245
|
+
const result = await runtime$1.handle(runtimeRequest);
|
|
246
|
+
if (!result) {
|
|
247
|
+
if (onNotFound === "response") {
|
|
248
|
+
return new Response(null, { status: 404 });
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
const responseBody = result.body === null ? null : typeof result.body === "string" ? result.body : toArrayBuffer(result.body);
|
|
253
|
+
return new Response(responseBody, {
|
|
254
|
+
status: result.status,
|
|
255
|
+
headers: result.headers
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
exports.applyRuntimeResultToNode = applyRuntimeResultToNode;
|
|
261
|
+
exports.createFetchHandler = createFetchHandler;
|
|
262
|
+
exports.toBinaryBody = toBinaryBody;
|
|
263
|
+
exports.toRuntimeOptions = toRuntimeOptions;
|
|
264
|
+
exports.toRuntimeRequestFromNode = toRuntimeRequestFromNode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RuntimeOptions, Manifest, ModuleMap } from '@mokup/runtime';
|
|
2
|
+
|
|
3
|
+
interface MokupServerOptions extends RuntimeOptions {
|
|
4
|
+
onNotFound?: 'next' | 'response';
|
|
5
|
+
}
|
|
6
|
+
type FetchHandler = (request: Request) => Promise<Response | null>;
|
|
7
|
+
interface MokupWorkerBundle {
|
|
8
|
+
manifest: Manifest;
|
|
9
|
+
moduleMap?: ModuleMap;
|
|
10
|
+
moduleBase?: string | URL;
|
|
11
|
+
onNotFound?: 'next' | 'response';
|
|
12
|
+
}
|
|
13
|
+
type MokupWorkerInput = string | Manifest | MokupWorkerBundle;
|
|
14
|
+
|
|
15
|
+
export type { FetchHandler as F, MokupServerOptions as M, MokupWorkerInput as a, MokupWorkerBundle as b };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RuntimeOptions, Manifest, ModuleMap } from '@mokup/runtime';
|
|
2
|
+
|
|
3
|
+
interface MokupServerOptions extends RuntimeOptions {
|
|
4
|
+
onNotFound?: 'next' | 'response';
|
|
5
|
+
}
|
|
6
|
+
type FetchHandler = (request: Request) => Promise<Response | null>;
|
|
7
|
+
interface MokupWorkerBundle {
|
|
8
|
+
manifest: Manifest;
|
|
9
|
+
moduleMap?: ModuleMap;
|
|
10
|
+
moduleBase?: string | URL;
|
|
11
|
+
onNotFound?: 'next' | 'response';
|
|
12
|
+
}
|
|
13
|
+
type MokupWorkerInput = string | Manifest | MokupWorkerBundle;
|
|
14
|
+
|
|
15
|
+
export type { FetchHandler as F, MokupServerOptions as M, MokupWorkerInput as a, MokupWorkerBundle as b };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RuntimeOptions, Manifest, ModuleMap } from '@mokup/runtime';
|
|
2
|
+
|
|
3
|
+
interface MokupServerOptions extends RuntimeOptions {
|
|
4
|
+
onNotFound?: 'next' | 'response';
|
|
5
|
+
}
|
|
6
|
+
type FetchHandler = (request: Request) => Promise<Response | null>;
|
|
7
|
+
interface MokupWorkerBundle {
|
|
8
|
+
manifest: Manifest;
|
|
9
|
+
moduleMap?: ModuleMap;
|
|
10
|
+
moduleBase?: string | URL;
|
|
11
|
+
onNotFound?: 'next' | 'response';
|
|
12
|
+
}
|
|
13
|
+
type MokupWorkerInput = string | Manifest | MokupWorkerBundle;
|
|
14
|
+
|
|
15
|
+
export type { FetchHandler as F, MokupServerOptions as M, MokupWorkerInput as a, MokupWorkerBundle as b };
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { createRuntime } from '@mokup/runtime';
|
|
2
|
+
|
|
3
|
+
const textDecoder = new TextDecoder();
|
|
4
|
+
const textEncoder = new TextEncoder();
|
|
5
|
+
function toRuntimeOptions(options) {
|
|
6
|
+
const runtimeOptions = {
|
|
7
|
+
manifest: options.manifest
|
|
8
|
+
};
|
|
9
|
+
if (typeof options.moduleBase !== "undefined") {
|
|
10
|
+
runtimeOptions.moduleBase = options.moduleBase;
|
|
11
|
+
}
|
|
12
|
+
if (typeof options.moduleMap !== "undefined") {
|
|
13
|
+
runtimeOptions.moduleMap = options.moduleMap;
|
|
14
|
+
}
|
|
15
|
+
return runtimeOptions;
|
|
16
|
+
}
|
|
17
|
+
function normalizeQuery(params) {
|
|
18
|
+
const query = {};
|
|
19
|
+
for (const [key, value] of params.entries()) {
|
|
20
|
+
const current = query[key];
|
|
21
|
+
if (typeof current === "undefined") {
|
|
22
|
+
query[key] = value;
|
|
23
|
+
} else if (Array.isArray(current)) {
|
|
24
|
+
current.push(value);
|
|
25
|
+
} else {
|
|
26
|
+
query[key] = [current, value];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return query;
|
|
30
|
+
}
|
|
31
|
+
function normalizeHeaders(headers) {
|
|
32
|
+
const record = {};
|
|
33
|
+
headers.forEach((value, key) => {
|
|
34
|
+
record[key.toLowerCase()] = value;
|
|
35
|
+
});
|
|
36
|
+
return record;
|
|
37
|
+
}
|
|
38
|
+
function normalizeNodeHeaders(headers) {
|
|
39
|
+
if (!headers) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
const record = {};
|
|
43
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
44
|
+
if (typeof value === "undefined") {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
record[key.toLowerCase()] = Array.isArray(value) ? value.join(",") : String(value);
|
|
48
|
+
}
|
|
49
|
+
return record;
|
|
50
|
+
}
|
|
51
|
+
function parseBody(rawText, contentType) {
|
|
52
|
+
if (!rawText) {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
if (contentType === "application/json" || contentType.endsWith("+json")) {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(rawText);
|
|
58
|
+
} catch {
|
|
59
|
+
return rawText;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
63
|
+
const params = new URLSearchParams(rawText);
|
|
64
|
+
return Object.fromEntries(params.entries());
|
|
65
|
+
}
|
|
66
|
+
return rawText;
|
|
67
|
+
}
|
|
68
|
+
function decodeText(data) {
|
|
69
|
+
return textDecoder.decode(data);
|
|
70
|
+
}
|
|
71
|
+
function toBinaryBody(body) {
|
|
72
|
+
return body;
|
|
73
|
+
}
|
|
74
|
+
function toArrayBuffer(body) {
|
|
75
|
+
const { buffer, byteOffset, byteLength } = body;
|
|
76
|
+
if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength) {
|
|
77
|
+
return buffer;
|
|
78
|
+
}
|
|
79
|
+
const copy = new Uint8Array(byteLength);
|
|
80
|
+
copy.set(body);
|
|
81
|
+
return copy.buffer;
|
|
82
|
+
}
|
|
83
|
+
function resolveUrl(input, headers) {
|
|
84
|
+
if (/^https?:\/\//.test(input)) {
|
|
85
|
+
return new URL(input);
|
|
86
|
+
}
|
|
87
|
+
const host = headers.host;
|
|
88
|
+
const base = host ? `http://${host}` : "http://localhost";
|
|
89
|
+
return new URL(input, base);
|
|
90
|
+
}
|
|
91
|
+
function concatChunks(chunks) {
|
|
92
|
+
if (chunks.length === 1) {
|
|
93
|
+
return chunks[0] ?? new Uint8Array();
|
|
94
|
+
}
|
|
95
|
+
let totalLength = 0;
|
|
96
|
+
for (const chunk of chunks) {
|
|
97
|
+
totalLength += chunk.length;
|
|
98
|
+
}
|
|
99
|
+
const merged = new Uint8Array(totalLength);
|
|
100
|
+
let offset = 0;
|
|
101
|
+
for (const chunk of chunks) {
|
|
102
|
+
merged.set(chunk, offset);
|
|
103
|
+
offset += chunk.length;
|
|
104
|
+
}
|
|
105
|
+
return merged;
|
|
106
|
+
}
|
|
107
|
+
async function readStreamBody(stream) {
|
|
108
|
+
return await new Promise((resolve, reject) => {
|
|
109
|
+
const chunks = [];
|
|
110
|
+
let hasData = false;
|
|
111
|
+
stream.on("data", (chunk) => {
|
|
112
|
+
hasData = true;
|
|
113
|
+
if (typeof chunk === "string") {
|
|
114
|
+
chunks.push(textEncoder.encode(chunk));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (chunk instanceof Uint8Array) {
|
|
118
|
+
chunks.push(chunk);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (chunk instanceof ArrayBuffer) {
|
|
122
|
+
chunks.push(new Uint8Array(chunk));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
chunks.push(textEncoder.encode(String(chunk)));
|
|
126
|
+
});
|
|
127
|
+
stream.on("end", () => {
|
|
128
|
+
if (!hasData) {
|
|
129
|
+
resolve(null);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
resolve(concatChunks(chunks));
|
|
133
|
+
});
|
|
134
|
+
stream.on("error", (error) => {
|
|
135
|
+
reject(error);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async function resolveBody(body, contentType, stream) {
|
|
140
|
+
if (typeof body !== "undefined") {
|
|
141
|
+
if (typeof body === "string") {
|
|
142
|
+
return {
|
|
143
|
+
body: parseBody(body, contentType),
|
|
144
|
+
rawBody: body
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (body instanceof Uint8Array) {
|
|
148
|
+
const rawText2 = decodeText(body);
|
|
149
|
+
return {
|
|
150
|
+
body: parseBody(rawText2, contentType),
|
|
151
|
+
rawBody: rawText2
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (body instanceof ArrayBuffer) {
|
|
155
|
+
const rawText2 = decodeText(new Uint8Array(body));
|
|
156
|
+
return {
|
|
157
|
+
body: parseBody(rawText2, contentType),
|
|
158
|
+
rawBody: rawText2
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
body
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (!stream) {
|
|
166
|
+
return { body: void 0 };
|
|
167
|
+
}
|
|
168
|
+
const rawBytes = await readStreamBody(stream);
|
|
169
|
+
if (!rawBytes || rawBytes.length === 0) {
|
|
170
|
+
return { body: void 0 };
|
|
171
|
+
}
|
|
172
|
+
const rawText = decodeText(rawBytes);
|
|
173
|
+
return {
|
|
174
|
+
body: parseBody(rawText, contentType),
|
|
175
|
+
rawBody: rawText
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function buildRuntimeRequest(url, method, headers, body, rawBody) {
|
|
179
|
+
const request = {
|
|
180
|
+
method,
|
|
181
|
+
path: url.pathname,
|
|
182
|
+
query: normalizeQuery(url.searchParams),
|
|
183
|
+
headers,
|
|
184
|
+
body
|
|
185
|
+
};
|
|
186
|
+
if (rawBody) {
|
|
187
|
+
request.rawBody = rawBody;
|
|
188
|
+
}
|
|
189
|
+
return request;
|
|
190
|
+
}
|
|
191
|
+
async function toRuntimeRequestFromFetch(request) {
|
|
192
|
+
const url = new URL(request.url);
|
|
193
|
+
const headers = normalizeHeaders(request.headers);
|
|
194
|
+
const contentType = (headers["content-type"] ?? "").split(";")[0]?.trim() ?? "";
|
|
195
|
+
const rawBody = await request.text();
|
|
196
|
+
const body = parseBody(rawBody, contentType);
|
|
197
|
+
return buildRuntimeRequest(
|
|
198
|
+
url,
|
|
199
|
+
request.method,
|
|
200
|
+
headers,
|
|
201
|
+
body,
|
|
202
|
+
rawBody || void 0
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
async function toRuntimeRequestFromNode(req, bodyOverride) {
|
|
206
|
+
const headers = normalizeNodeHeaders(req.headers);
|
|
207
|
+
const contentType = (headers["content-type"] ?? "").split(";")[0]?.trim() ?? "";
|
|
208
|
+
const url = resolveUrl(req.originalUrl ?? req.url ?? "/", headers);
|
|
209
|
+
const resolvedBody = await resolveBody(
|
|
210
|
+
typeof bodyOverride === "undefined" ? req.body : bodyOverride,
|
|
211
|
+
contentType,
|
|
212
|
+
req
|
|
213
|
+
);
|
|
214
|
+
return buildRuntimeRequest(
|
|
215
|
+
url,
|
|
216
|
+
req.method ?? "GET",
|
|
217
|
+
headers,
|
|
218
|
+
resolvedBody.body,
|
|
219
|
+
resolvedBody.rawBody
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
function applyRuntimeResultToNode(res, result) {
|
|
223
|
+
res.statusCode = result.status;
|
|
224
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
225
|
+
res.setHeader(key, value);
|
|
226
|
+
}
|
|
227
|
+
if (result.body === null) {
|
|
228
|
+
res.end();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (typeof result.body === "string") {
|
|
232
|
+
res.end(result.body);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
res.end(toBinaryBody(result.body));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function createFetchHandler(options) {
|
|
239
|
+
const runtime = createRuntime(toRuntimeOptions(options));
|
|
240
|
+
const onNotFound = options.onNotFound ?? "next";
|
|
241
|
+
return async (request) => {
|
|
242
|
+
const runtimeRequest = await toRuntimeRequestFromFetch(request);
|
|
243
|
+
const result = await runtime.handle(runtimeRequest);
|
|
244
|
+
if (!result) {
|
|
245
|
+
if (onNotFound === "response") {
|
|
246
|
+
return new Response(null, { status: 404 });
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const responseBody = result.body === null ? null : typeof result.body === "string" ? result.body : toArrayBuffer(result.body);
|
|
251
|
+
return new Response(responseBody, {
|
|
252
|
+
status: result.status,
|
|
253
|
+
headers: result.headers
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { toRuntimeRequestFromNode as a, applyRuntimeResultToNode as b, toBinaryBody as c, createFetchHandler as d, toRuntimeOptions as t };
|
package/dist/worker.cjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fetch = require('./shared/server.BdTl0qJd.cjs');
|
|
4
|
+
require('@mokup/runtime');
|
|
5
|
+
|
|
6
|
+
function isManifest(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "version" in value && "routes" in value;
|
|
8
|
+
}
|
|
9
|
+
function normalizeWorkerOptions(bundle) {
|
|
10
|
+
const options = {
|
|
11
|
+
manifest: bundle.manifest,
|
|
12
|
+
onNotFound: bundle.onNotFound ?? "response"
|
|
13
|
+
};
|
|
14
|
+
if (typeof bundle.moduleBase !== "undefined") {
|
|
15
|
+
options.moduleBase = bundle.moduleBase;
|
|
16
|
+
}
|
|
17
|
+
if (typeof bundle.moduleMap !== "undefined") {
|
|
18
|
+
options.moduleMap = bundle.moduleMap;
|
|
19
|
+
}
|
|
20
|
+
return options;
|
|
21
|
+
}
|
|
22
|
+
function createWorker(handlerOptions) {
|
|
23
|
+
const handler = fetch.createFetchHandler(handlerOptions);
|
|
24
|
+
return {
|
|
25
|
+
fetch: async (request) => {
|
|
26
|
+
return await handler(request) ?? new Response("Not Found", { status: 404 });
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createMokupWorker(input) {
|
|
31
|
+
if (typeof input === "string") {
|
|
32
|
+
throw new TypeError("createMokupWorker(dir) is only supported in Node runtimes.");
|
|
33
|
+
}
|
|
34
|
+
if (isManifest(input)) {
|
|
35
|
+
return createWorker({
|
|
36
|
+
manifest: input,
|
|
37
|
+
onNotFound: "response"
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return createWorker(normalizeWorkerOptions(input));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.createMokupWorker = createMokupWorker;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { a as MokupWorkerInput } from './shared/server.C0FGI34s.cjs';
|
|
2
|
+
import '@mokup/runtime';
|
|
3
|
+
|
|
4
|
+
interface MokupWorker {
|
|
5
|
+
fetch: (request: Request) => Promise<Response>;
|
|
6
|
+
}
|
|
7
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
8
|
+
|
|
9
|
+
export { createMokupWorker };
|
|
10
|
+
export type { MokupWorker };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { a as MokupWorkerInput } from './shared/server.C0FGI34s.mjs';
|
|
2
|
+
import '@mokup/runtime';
|
|
3
|
+
|
|
4
|
+
interface MokupWorker {
|
|
5
|
+
fetch: (request: Request) => Promise<Response>;
|
|
6
|
+
}
|
|
7
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
8
|
+
|
|
9
|
+
export { createMokupWorker };
|
|
10
|
+
export type { MokupWorker };
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { a as MokupWorkerInput } from './shared/server.C0FGI34s.js';
|
|
2
|
+
import '@mokup/runtime';
|
|
3
|
+
|
|
4
|
+
interface MokupWorker {
|
|
5
|
+
fetch: (request: Request) => Promise<Response>;
|
|
6
|
+
}
|
|
7
|
+
declare function createMokupWorker(input: Exclude<MokupWorkerInput, string>): MokupWorker;
|
|
8
|
+
|
|
9
|
+
export { createMokupWorker };
|
|
10
|
+
export type { MokupWorker };
|
package/dist/worker.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { d as createFetchHandler } from './shared/server.HVB7OYyI.mjs';
|
|
2
|
+
import '@mokup/runtime';
|
|
3
|
+
|
|
4
|
+
function isManifest(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "version" in value && "routes" in value;
|
|
6
|
+
}
|
|
7
|
+
function normalizeWorkerOptions(bundle) {
|
|
8
|
+
const options = {
|
|
9
|
+
manifest: bundle.manifest,
|
|
10
|
+
onNotFound: bundle.onNotFound ?? "response"
|
|
11
|
+
};
|
|
12
|
+
if (typeof bundle.moduleBase !== "undefined") {
|
|
13
|
+
options.moduleBase = bundle.moduleBase;
|
|
14
|
+
}
|
|
15
|
+
if (typeof bundle.moduleMap !== "undefined") {
|
|
16
|
+
options.moduleMap = bundle.moduleMap;
|
|
17
|
+
}
|
|
18
|
+
return options;
|
|
19
|
+
}
|
|
20
|
+
function createWorker(handlerOptions) {
|
|
21
|
+
const handler = createFetchHandler(handlerOptions);
|
|
22
|
+
return {
|
|
23
|
+
fetch: async (request) => {
|
|
24
|
+
return await handler(request) ?? new Response("Not Found", { status: 404 });
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function createMokupWorker(input) {
|
|
29
|
+
if (typeof input === "string") {
|
|
30
|
+
throw new TypeError("createMokupWorker(dir) is only supported in Node runtimes.");
|
|
31
|
+
}
|
|
32
|
+
if (isManifest(input)) {
|
|
33
|
+
return createWorker({
|
|
34
|
+
manifest: input,
|
|
35
|
+
onNotFound: "response"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return createWorker(normalizeWorkerOptions(input));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { createMokupWorker };
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mokup/server",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"description": "Server adapters for @mokup/runtime.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/sonofmagic/mokup.git",
|
|
10
|
+
"directory": "packages/server"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.mjs",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./worker": {
|
|
19
|
+
"types": "./dist/worker.d.ts",
|
|
20
|
+
"import": "./dist/worker.mjs",
|
|
21
|
+
"require": "./dist/worker.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.mjs",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@mokup/runtime": "0.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^5.9.3",
|
|
38
|
+
"unbuild": "^3.6.1"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "unbuild",
|
|
42
|
+
"dev": "unbuild --stub",
|
|
43
|
+
"lint": "eslint .",
|
|
44
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
45
|
+
}
|
|
46
|
+
}
|