@aklinker1/zeta 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/zod-schema-adapter.d.mts +17 -0
- package/dist/adapters/zod-schema-adapter.mjs +726 -0
- package/dist/client.d.mts +71 -0
- package/dist/client.mjs +73 -0
- package/dist/index.d.mts +316 -0
- package/dist/index.mjs +1236 -0
- package/dist/schema-IKHh0I39.d.mts +168 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +151 -0
- package/dist/serialization-C8e7ECQ2.mjs +56 -0
- package/dist/testing.d.mts +26 -0
- package/dist/testing.mjs +52 -0
- package/dist/transports/bun-transport.d.mts +7 -0
- package/dist/transports/bun-transport.mjs +14 -0
- package/dist/transports/deno-transport.d.mts +6 -0
- package/dist/transports/deno-transport.mjs +13 -0
- package/dist/types-D9oRVe1E.d.mts +698 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +1 -0
- package/package.json +38 -16
- package/src/adapters/zod-schema-adapter.ts +0 -29
- package/src/app.ts +0 -479
- package/src/client.ts +0 -184
- package/src/errors.ts +0 -529
- package/src/index.ts +0 -5
- package/src/internal/compile-fetch-function.ts +0 -166
- package/src/internal/compile-route-handler.ts +0 -194
- package/src/internal/context.ts +0 -65
- package/src/internal/serialization.ts +0 -91
- package/src/internal/utils.ts +0 -191
- package/src/meta.ts +0 -14
- package/src/open-api.ts +0 -273
- package/src/schema.ts +0 -271
- package/src/status.ts +0 -143
- package/src/testing.ts +0 -62
- package/src/transports/bun-transport.ts +0 -17
- package/src/transports/deno-transport.ts +0 -13
- package/src/types.ts +0 -1102
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { $ as SchemaAdapter, A as LifeCycleHookName, B as OnGlobalAfterResponseHook, C as GetResponseInputFromDef, D as GetRouteHandler, E as GetResponseStatusMap, F as MergeAppData, G as OnMapResponseContext, H as OnGlobalErrorHook, I as MergeRoutes, J as OnTransformHook, K as OnMapResponseHook, L as OnAfterHandleHook, M as MaybePromise, N as Merge, O as GetRouteHandlerReturnType, P as MergeApp, Q as RouterData, R as OnBeforeHandleContext, S as GetResponseInput, T as GetResponseOutputFromDef, U as OnGlobalRequestContext, V as OnGlobalErrorContext, W as OnGlobalRequestHook, X as RouteDef, Y as PrefixObjectKeys, Z as RouteHandler, _ as GetAppRoutes, a as AppData, at as Transport, b as GetRequestParamsOutput, c as BaseCtx, d as BaseRoutes, et as ServerSideFetch, f as BuildHandlerContext, g as GetAppDataCtx, h as GetAppData, i as App, it as StatusResult, j as LifeCycleHooks, k as LifeCycleHook, l as BasePath, m as DefaultAppData, n as AfterResponseContext, nt as Simplify, o as ApplyAppDataPrefix, ot as UseApp, p as CompiledRouteHandler, q as OnTransformContext, r as AnyDef, rt as StatusFn, s as ApplyAppPrefix, st as UseAppData, t as AfterHandleContext, tt as Setter, u as BasePrefix, v as GetRequestParamsInput, w as GetResponseOutput, x as GetRequestParamsOutputFromDef, y as GetRequestParamsInputFromDef, z as OnBeforeHandleHook } from "./types-D9oRVe1E.mjs";
|
|
2
|
+
export { AfterHandleContext, AfterResponseContext, AnyDef, App, AppData, ApplyAppDataPrefix, ApplyAppPrefix, BaseCtx, BasePath, BasePrefix, BaseRoutes, BuildHandlerContext, CompiledRouteHandler, DefaultAppData, GetAppData, GetAppDataCtx, GetAppRoutes, GetRequestParamsInput, GetRequestParamsInputFromDef, GetRequestParamsOutput, GetRequestParamsOutputFromDef, GetResponseInput, GetResponseInputFromDef, GetResponseOutput, GetResponseOutputFromDef, GetResponseStatusMap, GetRouteHandler, GetRouteHandlerReturnType, LifeCycleHook, LifeCycleHookName, LifeCycleHooks, MaybePromise, Merge, MergeApp, MergeAppData, MergeRoutes, OnAfterHandleHook, OnBeforeHandleContext, OnBeforeHandleHook, OnGlobalAfterResponseHook, OnGlobalErrorContext, OnGlobalErrorHook, OnGlobalRequestContext, OnGlobalRequestHook, OnMapResponseContext, OnMapResponseHook, OnTransformContext, OnTransformHook, PrefixObjectKeys, RouteDef, RouteHandler, RouterData, SchemaAdapter, ServerSideFetch, Setter, Simplify, StatusFn, StatusResult, Transport, UseApp, UseAppData };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aklinker1/zeta",
|
|
3
3
|
"description": "Composable, testable, OpenAPI-first backend framework with validation built-in",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"packageManager": "bun@1.3.5",
|
|
8
|
-
"module": "
|
|
9
|
-
"types": "
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"types": "dist/index.d.mts",
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"./
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"./types": {
|
|
16
|
+
"types": "./dist/types.d.mts",
|
|
17
|
+
"default": "./dist/types.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./client": {
|
|
20
|
+
"types": "./dist/client.d.mts",
|
|
21
|
+
"default": "./dist/client.mjs"
|
|
22
|
+
},
|
|
23
|
+
"./testing": {
|
|
24
|
+
"types": "./dist/testing.d.mts",
|
|
25
|
+
"default": "./dist/testing.mjs"
|
|
26
|
+
},
|
|
27
|
+
"./schema": {
|
|
28
|
+
"types": "./dist/schema.d.mts",
|
|
29
|
+
"default": "./dist/schema.mjs"
|
|
30
|
+
},
|
|
31
|
+
"./adapters/zod-schema-adapter": {
|
|
32
|
+
"types": "./dist/adapters/zod-schema-adapter.d.mts",
|
|
33
|
+
"default": "./dist/adapters/zod-schema-adapter.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./transports/bun-transport": {
|
|
36
|
+
"types": "./dist/transports/bun-transport.d.mts",
|
|
37
|
+
"default": "./dist/transports/bun-transport.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./transports/deno-transport": {
|
|
40
|
+
"types": "./dist/transports/deno-transport.d.mts",
|
|
41
|
+
"default": "./dist/transports/deno-transport.mjs"
|
|
42
|
+
}
|
|
19
43
|
},
|
|
20
44
|
"files": [
|
|
21
|
-
"
|
|
22
|
-
"src/adapters/*.ts",
|
|
23
|
-
"src/internal/*.ts",
|
|
24
|
-
"src/transports/*.ts"
|
|
45
|
+
"dist/*"
|
|
25
46
|
],
|
|
26
47
|
"publishConfig": {
|
|
27
48
|
"access": "public"
|
|
@@ -37,7 +58,7 @@
|
|
|
37
58
|
],
|
|
38
59
|
"scripts": {
|
|
39
60
|
"dev": "bun test --watch",
|
|
40
|
-
"build": "
|
|
61
|
+
"build": "tsdown src/{index,types,client,testing,schema,adapters/zod-schema-adapter,transports/bun-transport,transports/deno-transport}.ts",
|
|
41
62
|
"bench": "bun run src/__tests__/bench.ts",
|
|
42
63
|
"example": "bun --watch run example.ts",
|
|
43
64
|
"example:prod": "NODE_ENV=production bun run example",
|
|
@@ -72,6 +93,7 @@
|
|
|
72
93
|
"prettier": "^3.5.3",
|
|
73
94
|
"publint": "^0.3.12",
|
|
74
95
|
"tinybench": "^4.0.1",
|
|
96
|
+
"tsdown": "^0.21.2",
|
|
75
97
|
"vitepress": "^2.0.0-alpha.12",
|
|
76
98
|
"vitepress-plugin-mermaid": "^2.0.17",
|
|
77
99
|
"zod": "^4.1.11"
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contains a schema adapter for app's using [`zod`](https://npmjs.com/package/zod).
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import type { SchemaAdapter } from "../types";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Usage:
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { zodSchemaAdapter } from "@aklinker1/zeta/adapters/zod-schema-adapter";
|
|
13
|
-
*
|
|
14
|
-
* const app = createApp({
|
|
15
|
-
* schemaAdapter: zodSchemaAdapter,
|
|
16
|
-
* });
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export const zodSchemaAdapter: SchemaAdapter = {
|
|
20
|
-
toJsonSchema: (schema) => {
|
|
21
|
-
if (!("_zod" in schema)) throw Error("input schema is not a Zod schema");
|
|
22
|
-
const res = z.toJSONSchema(schema, { target: "openapi-3.0" });
|
|
23
|
-
delete res.$schema;
|
|
24
|
-
return res;
|
|
25
|
-
},
|
|
26
|
-
getMeta: (schema: any) => {
|
|
27
|
-
return z.globalRegistry.get(schema);
|
|
28
|
-
},
|
|
29
|
-
};
|
package/src/app.ts
DELETED
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
import type { OpenAPI, OpenAPIV3_1 } from "openapi-types";
|
|
2
|
-
import { addRoute, createRouter } from "rou3";
|
|
3
|
-
import { compileRouter } from "rou3/compiler";
|
|
4
|
-
import { compileFetchFunction } from "./internal/compile-fetch-function";
|
|
5
|
-
import { compileRouteHandler } from "./internal/compile-route-handler";
|
|
6
|
-
import { detectTransport } from "./internal/utils";
|
|
7
|
-
import { buildOpenApiDocs, buildScalarHtml } from "./open-api";
|
|
8
|
-
import type {
|
|
9
|
-
App,
|
|
10
|
-
BasePath,
|
|
11
|
-
BasePrefix,
|
|
12
|
-
DefaultAppData,
|
|
13
|
-
LifeCycleHook,
|
|
14
|
-
LifeCycleHookName,
|
|
15
|
-
RouteDef,
|
|
16
|
-
RouterData,
|
|
17
|
-
SchemaAdapter,
|
|
18
|
-
ServerSideFetch,
|
|
19
|
-
Transport,
|
|
20
|
-
} from "./types";
|
|
21
|
-
|
|
22
|
-
let appIdInc = 0;
|
|
23
|
-
const nextAppId = () => `app-${appIdInc++}`;
|
|
24
|
-
|
|
25
|
-
let _hookIdInc = 0;
|
|
26
|
-
const nextHookId = (appId: string) => `${appId}/hook-${_hookIdInc++}`;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Create a server-side, Zeta application.
|
|
30
|
-
*
|
|
31
|
-
* Zeta provides simple support for serving applications using `Bun.serve` and
|
|
32
|
-
* `Deno.serve` by calling `app.listen(3000)`.
|
|
33
|
-
*
|
|
34
|
-
* If you need more customization, you can use the `build` method to create a
|
|
35
|
-
* `fetch` function and serve it however you like.
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* ```ts
|
|
39
|
-
* import { createApp } from "@aklinker1/zeta";
|
|
40
|
-
*
|
|
41
|
-
* const app = createApp({ prefix: "/api" })
|
|
42
|
-
* .get("/health", () => "OK")
|
|
43
|
-
* .get("/users", () => ["user1", "user2"]);
|
|
44
|
-
*
|
|
45
|
-
* app.listen(3000);
|
|
46
|
-
*
|
|
47
|
-
* // Or serve the app yourself
|
|
48
|
-
* const fetch = app.build();
|
|
49
|
-
* Bun.serve({ fetch, ... });
|
|
50
|
-
* Deno.serve({ fetch, ... });
|
|
51
|
-
* ```
|
|
52
|
-
*
|
|
53
|
-
* @param options Configure application behavior.
|
|
54
|
-
*/
|
|
55
|
-
export function createApp<TPrefix extends BasePrefix = "">(
|
|
56
|
-
options?: CreateAppOptions<TPrefix>,
|
|
57
|
-
): App<{
|
|
58
|
-
ctx: {};
|
|
59
|
-
exported: false;
|
|
60
|
-
prefix: TPrefix;
|
|
61
|
-
routes: {};
|
|
62
|
-
}> {
|
|
63
|
-
const appId = nextAppId();
|
|
64
|
-
|
|
65
|
-
const { origin = "http://localhost", prefix = "" } = options ?? {};
|
|
66
|
-
const hooks: App["~zeta"]["hooks"] = {};
|
|
67
|
-
const routes: App["~zeta"]["routes"] = {};
|
|
68
|
-
|
|
69
|
-
const addRoutesEntry = (method: string, route: string, data: RouterData) => {
|
|
70
|
-
routes[method] ??= {};
|
|
71
|
-
if (routes[method][route]) {
|
|
72
|
-
console.warn(`Route ${route} already exists`);
|
|
73
|
-
}
|
|
74
|
-
routes[method][route] = data;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const cloneHooks = (): App["~zeta"]["hooks"] => {
|
|
78
|
-
const cloned: App["~zeta"]["hooks"] = {};
|
|
79
|
-
for (const key of Object.keys(hooks) as LifeCycleHookName[]) {
|
|
80
|
-
if (hooks[key]) cloned[key] = [...hooks[key]] as any;
|
|
81
|
-
}
|
|
82
|
-
return cloned;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const app: App<DefaultAppData> = {
|
|
86
|
-
// @ts-expect-error
|
|
87
|
-
[Symbol.toStringTag]: "ZetaApp",
|
|
88
|
-
|
|
89
|
-
"~zeta": {
|
|
90
|
-
id: appId,
|
|
91
|
-
prefix,
|
|
92
|
-
routes,
|
|
93
|
-
hooks,
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
build: () => {
|
|
97
|
-
const jsonRoute = options?.openApiRoute ?? "/openapi.json";
|
|
98
|
-
const scalarRoute = options?.scalarRoute ?? "/scalar";
|
|
99
|
-
const docs = buildOpenApiDocs(options, app);
|
|
100
|
-
if (docs.type === "error") {
|
|
101
|
-
console.error("Failed to build OpenAPI docs:", docs.error);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
app.get(jsonRoute, () => {
|
|
105
|
-
if (docs.type === "error") {
|
|
106
|
-
console.error("Failed to build OpenAPI docs:", docs.error);
|
|
107
|
-
throw docs.error;
|
|
108
|
-
}
|
|
109
|
-
return docs.spec;
|
|
110
|
-
});
|
|
111
|
-
if (docs.type === "success") {
|
|
112
|
-
const scalarHtml = buildScalarHtml(jsonRoute, options);
|
|
113
|
-
app.get(
|
|
114
|
-
scalarRoute,
|
|
115
|
-
() =>
|
|
116
|
-
new Response(scalarHtml, {
|
|
117
|
-
headers: { "content-type": "text/html;charset=utf-8" },
|
|
118
|
-
}),
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const router = createRouter<RouterData>();
|
|
123
|
-
for (const [method, methodValue] of Object.entries(routes)) {
|
|
124
|
-
for (const [path, data] of Object.entries(methodValue)) {
|
|
125
|
-
addRoute(
|
|
126
|
-
router,
|
|
127
|
-
method === Method.Any ? undefined : method,
|
|
128
|
-
path,
|
|
129
|
-
data,
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const getRoute = compileRouter(router);
|
|
135
|
-
return compileFetchFunction({ getRoute, hooks, origin });
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
getOpenApiSpec: () => {
|
|
139
|
-
const res = buildOpenApiDocs(options, app);
|
|
140
|
-
if (res.type === "error") throw res.error;
|
|
141
|
-
|
|
142
|
-
return res.spec;
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
export: () => {
|
|
146
|
-
app["~zeta"].exported = true;
|
|
147
|
-
return app as any;
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
listen: (port, cb) => {
|
|
151
|
-
const transport = options?.transport ?? detectTransport();
|
|
152
|
-
transport.listen(port, app.build(), cb);
|
|
153
|
-
return app;
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
decorate: (...args: any[]) => {
|
|
157
|
-
const obj: Record<string, any> =
|
|
158
|
-
args.length === 2 ? { [args[0]]: args[1] } : args[0];
|
|
159
|
-
|
|
160
|
-
hooks.onTransform ??= [];
|
|
161
|
-
hooks.onTransform.push({
|
|
162
|
-
id: nextHookId(appId),
|
|
163
|
-
applyTo: "local",
|
|
164
|
-
callback: () => obj,
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return app;
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
onGlobalRequest(callback: any) {
|
|
171
|
-
hooks.onGlobalRequest ??= [];
|
|
172
|
-
hooks.onGlobalRequest.push({
|
|
173
|
-
id: nextHookId(appId),
|
|
174
|
-
applyTo: "global",
|
|
175
|
-
callback,
|
|
176
|
-
});
|
|
177
|
-
return app;
|
|
178
|
-
},
|
|
179
|
-
onTransform(callback: any) {
|
|
180
|
-
hooks.onTransform ??= [];
|
|
181
|
-
hooks.onTransform.push({
|
|
182
|
-
id: nextHookId(appId),
|
|
183
|
-
applyTo: "local",
|
|
184
|
-
callback,
|
|
185
|
-
});
|
|
186
|
-
return app;
|
|
187
|
-
},
|
|
188
|
-
onBeforeHandle(callback: any) {
|
|
189
|
-
hooks.onBeforeHandle ??= [];
|
|
190
|
-
hooks.onBeforeHandle.push({
|
|
191
|
-
id: nextHookId(appId),
|
|
192
|
-
applyTo: "local",
|
|
193
|
-
callback,
|
|
194
|
-
});
|
|
195
|
-
return app;
|
|
196
|
-
},
|
|
197
|
-
onAfterHandle(callback: any) {
|
|
198
|
-
hooks.onAfterHandle ??= [];
|
|
199
|
-
hooks.onAfterHandle.push({
|
|
200
|
-
id: nextHookId(appId),
|
|
201
|
-
applyTo: "local",
|
|
202
|
-
callback,
|
|
203
|
-
});
|
|
204
|
-
return app;
|
|
205
|
-
},
|
|
206
|
-
onMapResponse(callback: any) {
|
|
207
|
-
hooks.onMapResponse ??= [];
|
|
208
|
-
hooks.onMapResponse.push({
|
|
209
|
-
id: nextHookId(appId),
|
|
210
|
-
applyTo: "local",
|
|
211
|
-
callback,
|
|
212
|
-
});
|
|
213
|
-
return app;
|
|
214
|
-
},
|
|
215
|
-
onGlobalError(callback: any) {
|
|
216
|
-
hooks.onGlobalError ??= [];
|
|
217
|
-
hooks.onGlobalError.push({
|
|
218
|
-
id: nextHookId(appId),
|
|
219
|
-
applyTo: "global",
|
|
220
|
-
callback,
|
|
221
|
-
});
|
|
222
|
-
return app;
|
|
223
|
-
},
|
|
224
|
-
onGlobalAfterResponse(callback: any) {
|
|
225
|
-
hooks.onGlobalAfterResponse ??= [];
|
|
226
|
-
hooks.onGlobalAfterResponse.push({
|
|
227
|
-
id: nextHookId(appId),
|
|
228
|
-
applyTo: "global",
|
|
229
|
-
callback,
|
|
230
|
-
});
|
|
231
|
-
return app;
|
|
232
|
-
},
|
|
233
|
-
|
|
234
|
-
get: (...args: any[]) =>
|
|
235
|
-
app.method.apply(app, [Method.Get, ...args] as any) as any,
|
|
236
|
-
post: (...args: any[]) =>
|
|
237
|
-
app.method.apply(app, [Method.Post, ...args] as any) as any,
|
|
238
|
-
put: (...args: any[]) =>
|
|
239
|
-
app.method.apply(app, [Method.Put, ...args] as any) as any,
|
|
240
|
-
delete: (...args: any[]) =>
|
|
241
|
-
app.method.apply(app, [Method.Delete, ...args] as any) as any,
|
|
242
|
-
any: (...args: any[]) =>
|
|
243
|
-
app.method.apply(app, [Method.Any, ...args] as any) as any,
|
|
244
|
-
|
|
245
|
-
method(method: string, path: BasePath, ...args: any[]) {
|
|
246
|
-
const routeDef: RouteDef | undefined =
|
|
247
|
-
args.length === 2 ? args[0] : undefined;
|
|
248
|
-
const handler = args[1] ?? args[0];
|
|
249
|
-
const route = `${prefix}${path}`;
|
|
250
|
-
const hooks = cloneHooks();
|
|
251
|
-
|
|
252
|
-
// Merge app-level tags and security into route definition
|
|
253
|
-
const def: RouteDef | undefined = mergeAppDefaults(routeDef, options);
|
|
254
|
-
|
|
255
|
-
const compiledHandler = compileRouteHandler({
|
|
256
|
-
schemaAdapter: options?.schemaAdapter,
|
|
257
|
-
def,
|
|
258
|
-
hooks,
|
|
259
|
-
method,
|
|
260
|
-
route,
|
|
261
|
-
handler,
|
|
262
|
-
});
|
|
263
|
-
addRoutesEntry(method, route, {
|
|
264
|
-
def,
|
|
265
|
-
route,
|
|
266
|
-
hooks,
|
|
267
|
-
compiledHandler,
|
|
268
|
-
handler,
|
|
269
|
-
});
|
|
270
|
-
return app;
|
|
271
|
-
},
|
|
272
|
-
|
|
273
|
-
mount(...args: any[]) {
|
|
274
|
-
let path = "";
|
|
275
|
-
let routeDef: RouteDef = {};
|
|
276
|
-
let fetch: ServerSideFetch;
|
|
277
|
-
|
|
278
|
-
if (args.length === 1) {
|
|
279
|
-
fetch = args[0];
|
|
280
|
-
} else if (args.length === 2) {
|
|
281
|
-
path = args[0];
|
|
282
|
-
fetch = args[1];
|
|
283
|
-
} else {
|
|
284
|
-
path = args[0];
|
|
285
|
-
routeDef = args[1];
|
|
286
|
-
fetch = args[2];
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const route = `${prefix}${path}/**`;
|
|
290
|
-
const hooks = cloneHooks();
|
|
291
|
-
|
|
292
|
-
// Merge app-level tags and security into route definition
|
|
293
|
-
const def = mergeAppDefaults(routeDef, options);
|
|
294
|
-
|
|
295
|
-
const compiledHandler = compileRouteHandler({
|
|
296
|
-
schemaAdapter: options?.schemaAdapter,
|
|
297
|
-
hooks,
|
|
298
|
-
method: "ANY",
|
|
299
|
-
route,
|
|
300
|
-
fetch,
|
|
301
|
-
def,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
addRoutesEntry(Method.Any, route, {
|
|
305
|
-
def,
|
|
306
|
-
fetch,
|
|
307
|
-
route,
|
|
308
|
-
hooks,
|
|
309
|
-
compiledHandler,
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
return app as any;
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
use: (childApp) => {
|
|
316
|
-
// Bring in routes
|
|
317
|
-
for (const [method, methodValue] of Object.entries(
|
|
318
|
-
childApp["~zeta"].routes,
|
|
319
|
-
)) {
|
|
320
|
-
for (const [subRoute, routeValue] of Object.entries(methodValue)) {
|
|
321
|
-
const route = `${prefix}${subRoute}`;
|
|
322
|
-
addRoutesEntry(method, route, { ...routeValue, route });
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Add the child's global hooks to parent
|
|
327
|
-
for (const hookName of Object.keys(
|
|
328
|
-
childApp["~zeta"].hooks,
|
|
329
|
-
) as LifeCycleHookName[]) {
|
|
330
|
-
for (const hook of childApp["~zeta"].hooks[
|
|
331
|
-
hookName
|
|
332
|
-
]! as LifeCycleHook<any>[]) {
|
|
333
|
-
if (hook.applyTo !== "global" && !childApp["~zeta"].exported)
|
|
334
|
-
continue;
|
|
335
|
-
|
|
336
|
-
if (hooks[hookName]) {
|
|
337
|
-
// Don't add a hook if it's already there
|
|
338
|
-
if (!hooks[hookName].includes(hook)) hooks[hookName].push(hook);
|
|
339
|
-
} else {
|
|
340
|
-
hooks[hookName] = [hook];
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return app as any;
|
|
346
|
-
},
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
return app as any;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Configure how the app is created.
|
|
354
|
-
*/
|
|
355
|
-
export type CreateAppOptions<TPrefix extends BasePrefix = ""> = {
|
|
356
|
-
/**
|
|
357
|
-
* The origin to use when constructing URLs.
|
|
358
|
-
* @default "http://localhost"
|
|
359
|
-
*/
|
|
360
|
-
origin?: string;
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Add a prefix to the beginning of all routes in the app.
|
|
364
|
-
*/
|
|
365
|
-
prefix?: TPrefix;
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Tell Zeta which library you're using for validation. OpenAPI docs cannot
|
|
369
|
-
* be served without a schema adapter.
|
|
370
|
-
*
|
|
371
|
-
* @example
|
|
372
|
-
* ```ts
|
|
373
|
-
* import { zodSchemaAdapter } from "@aklinker1/zeta/adapters/zod-schema-adapter"
|
|
374
|
-
*
|
|
375
|
-
* const app = createApp({
|
|
376
|
-
* openApi: {
|
|
377
|
-
* schemaAdapter: zodSchemaAdapter,
|
|
378
|
-
* },
|
|
379
|
-
* });
|
|
380
|
-
* ```
|
|
381
|
-
*/
|
|
382
|
-
schemaAdapter?: SchemaAdapter;
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Tell Zeta how to serve your app over a port. By default, Zeta will detect
|
|
386
|
-
* if you're runtime is Bun or Deno, and use the appropriate transport.
|
|
387
|
-
*
|
|
388
|
-
* If you need to customize the transport, like adding an `idleTimeout` to
|
|
389
|
-
* bun, you can do so by passing options into the transport's factory function.
|
|
390
|
-
*
|
|
391
|
-
* @example
|
|
392
|
-
* ```ts
|
|
393
|
-
* import { createBunTransport } from "@aklinker1/zeta/transports/bun-transport"
|
|
394
|
-
*
|
|
395
|
-
* const app = createApp({
|
|
396
|
-
* transport: createBunTransport(),
|
|
397
|
-
* });
|
|
398
|
-
* ```
|
|
399
|
-
*/
|
|
400
|
-
transport?: Transport;
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Where the OpenAPI JSON docs is hosted.
|
|
404
|
-
* @default "/openapi.json"
|
|
405
|
-
*/
|
|
406
|
-
openApiRoute?: BasePath;
|
|
407
|
-
/**
|
|
408
|
-
* Where the Scalar UI is hosted.
|
|
409
|
-
* @default "/scalar"
|
|
410
|
-
*/
|
|
411
|
-
scalarRoute?: BasePath;
|
|
412
|
-
|
|
413
|
-
/** Configure how your application's OpenAPI docs are generated. */
|
|
414
|
-
openApi?: Partial<OpenAPIV3_1.Document> & {};
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* OpenAPI tags to apply to all routes in this app. Route-level tags will
|
|
418
|
-
* override these app-level tags.
|
|
419
|
-
*
|
|
420
|
-
* @example
|
|
421
|
-
* ```ts
|
|
422
|
-
* const usersApp = createApp({
|
|
423
|
-
* prefix: "/users",
|
|
424
|
-
* tags: ["Users"],
|
|
425
|
-
* })
|
|
426
|
-
* .get("/", {}, () => [...]) // Will have ["Users"] tag
|
|
427
|
-
* .get("/:id", { tags: ["Admin"] }, () => {...}) // Will have ["Admin"] tag (overrides app-level)
|
|
428
|
-
* ```
|
|
429
|
-
*/
|
|
430
|
-
tags?: string[];
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* OpenAPI security requirements to apply to all routes in this app.
|
|
434
|
-
* Route-level security will override these app-level security requirements.
|
|
435
|
-
*
|
|
436
|
-
* @example
|
|
437
|
-
* ```ts
|
|
438
|
-
* const authApp = createApp({
|
|
439
|
-
* prefix: "/auth",
|
|
440
|
-
* security: [{ bearerAuth: [] }],
|
|
441
|
-
* })
|
|
442
|
-
* .get("/profile", {}, () => {...}) // Will require bearerAuth
|
|
443
|
-
* .get("/admin", { security: [{ adminKey: [] }] }, () => {...}) // Will require adminKey (overrides app-level)
|
|
444
|
-
* ```
|
|
445
|
-
*/
|
|
446
|
-
security?: OpenAPI.Document["security"];
|
|
447
|
-
/**
|
|
448
|
-
* Configure [Scalar](https://scalar.com/) UI docs.
|
|
449
|
-
* @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md#list-of-all-attributes
|
|
450
|
-
*/
|
|
451
|
-
scalar?: any;
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Apply app-level defaults (tags, security) to a route definition.
|
|
456
|
-
* Route-level values override app-level defaults.
|
|
457
|
-
*/
|
|
458
|
-
function mergeAppDefaults(
|
|
459
|
-
routeDef: RouteDef | undefined,
|
|
460
|
-
options: CreateAppOptions<any> | undefined,
|
|
461
|
-
): RouteDef | undefined {
|
|
462
|
-
if (!options?.tags?.length && !options?.security?.length) {
|
|
463
|
-
return routeDef;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
return {
|
|
467
|
-
tags: options.tags,
|
|
468
|
-
security: options.security,
|
|
469
|
-
...routeDef,
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
enum Method {
|
|
474
|
-
Get = "GET",
|
|
475
|
-
Post = "POST",
|
|
476
|
-
Put = "PUT",
|
|
477
|
-
Delete = "DELETE",
|
|
478
|
-
Any = "ANY",
|
|
479
|
-
}
|