@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/index.mjs ADDED
@@ -0,0 +1,1236 @@
1
+ import { createBunTransport } from "./transports/bun-transport.mjs";
2
+ import { createDenoTransport } from "./transports/deno-transport.mjs";
3
+ import { ErrorResponse, ErrorResponseJsonSchema, NoResponse, isZetaSchema } from "./schema.mjs";
4
+ import { n as smartSerialize, t as smartDeserialize } from "./serialization-C8e7ECQ2.mjs";
5
+ import { addRoute, createRouter } from "rou3";
6
+ import { compileRouter } from "rou3/compiler";
7
+ import { titleCase } from "scule";
8
+ //#region src/status.ts
9
+ /**
10
+ * Enum containing all HTTP status codes.
11
+ */
12
+ let HttpStatus = /* @__PURE__ */ function(HttpStatus) {
13
+ HttpStatus[HttpStatus["Continue"] = 100] = "Continue";
14
+ HttpStatus[HttpStatus["SwitchingProtocols"] = 101] = "SwitchingProtocols";
15
+ HttpStatus[HttpStatus["ProcessingDeprecated"] = 102] = "ProcessingDeprecated";
16
+ HttpStatus[HttpStatus["EarlyHints"] = 103] = "EarlyHints";
17
+ HttpStatus[HttpStatus["Ok"] = 200] = "Ok";
18
+ HttpStatus[HttpStatus["Created"] = 201] = "Created";
19
+ HttpStatus[HttpStatus["Accepted"] = 202] = "Accepted";
20
+ HttpStatus[HttpStatus["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
21
+ HttpStatus[HttpStatus["NoContent"] = 204] = "NoContent";
22
+ HttpStatus[HttpStatus["ResetContent"] = 205] = "ResetContent";
23
+ HttpStatus[HttpStatus["PartialContent"] = 206] = "PartialContent";
24
+ HttpStatus[HttpStatus["MultiStatus"] = 207] = "MultiStatus";
25
+ HttpStatus[HttpStatus["AlreadyReported"] = 208] = "AlreadyReported";
26
+ HttpStatus[HttpStatus["ImUsed"] = 226] = "ImUsed";
27
+ HttpStatus[HttpStatus["MultipleChoices"] = 300] = "MultipleChoices";
28
+ HttpStatus[HttpStatus["MovedPermanently"] = 301] = "MovedPermanently";
29
+ HttpStatus[HttpStatus["Found"] = 302] = "Found";
30
+ HttpStatus[HttpStatus["SeeOther"] = 303] = "SeeOther";
31
+ HttpStatus[HttpStatus["NotModified"] = 304] = "NotModified";
32
+ HttpStatus[HttpStatus["UseProxyDeprecated"] = 305] = "UseProxyDeprecated";
33
+ HttpStatus[HttpStatus["Unused"] = 306] = "Unused";
34
+ HttpStatus[HttpStatus["TemporaryRedirect"] = 307] = "TemporaryRedirect";
35
+ HttpStatus[HttpStatus["PermanentRedirect"] = 308] = "PermanentRedirect";
36
+ HttpStatus[HttpStatus["BadRequest"] = 400] = "BadRequest";
37
+ HttpStatus[HttpStatus["Unauthorized"] = 401] = "Unauthorized";
38
+ HttpStatus[HttpStatus["PaymentRequired"] = 402] = "PaymentRequired";
39
+ HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";
40
+ HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";
41
+ HttpStatus[HttpStatus["MethodNotAllowed"] = 405] = "MethodNotAllowed";
42
+ HttpStatus[HttpStatus["NotAcceptable"] = 406] = "NotAcceptable";
43
+ HttpStatus[HttpStatus["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
44
+ HttpStatus[HttpStatus["RequestTimeout"] = 408] = "RequestTimeout";
45
+ HttpStatus[HttpStatus["Conflict"] = 409] = "Conflict";
46
+ HttpStatus[HttpStatus["Gone"] = 410] = "Gone";
47
+ HttpStatus[HttpStatus["LengthRequired"] = 411] = "LengthRequired";
48
+ HttpStatus[HttpStatus["PreconditionFailed"] = 412] = "PreconditionFailed";
49
+ HttpStatus[HttpStatus["ContentTooLarge"] = 413] = "ContentTooLarge";
50
+ HttpStatus[HttpStatus["UriTooLong"] = 414] = "UriTooLong";
51
+ HttpStatus[HttpStatus["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
52
+ HttpStatus[HttpStatus["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
53
+ HttpStatus[HttpStatus["ExpectationFailed"] = 417] = "ExpectationFailed";
54
+ HttpStatus[HttpStatus["ImATeapot"] = 418] = "ImATeapot";
55
+ HttpStatus[HttpStatus["MisdirectedRequest"] = 421] = "MisdirectedRequest";
56
+ HttpStatus[HttpStatus["UnprocessableEntity"] = 422] = "UnprocessableEntity";
57
+ HttpStatus[HttpStatus["Locked"] = 423] = "Locked";
58
+ HttpStatus[HttpStatus["FailedDependency"] = 424] = "FailedDependency";
59
+ HttpStatus[HttpStatus["TooEarly"] = 425] = "TooEarly";
60
+ HttpStatus[HttpStatus["UpgradeRequired"] = 426] = "UpgradeRequired";
61
+ HttpStatus[HttpStatus["PreconditionRequired"] = 428] = "PreconditionRequired";
62
+ HttpStatus[HttpStatus["TooManyRequests"] = 429] = "TooManyRequests";
63
+ HttpStatus[HttpStatus["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
64
+ HttpStatus[HttpStatus["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
65
+ HttpStatus[HttpStatus["InternalServerError"] = 500] = "InternalServerError";
66
+ HttpStatus[HttpStatus["NotImplemented"] = 501] = "NotImplemented";
67
+ HttpStatus[HttpStatus["BadGateway"] = 502] = "BadGateway";
68
+ HttpStatus[HttpStatus["ServiceUnavailable"] = 503] = "ServiceUnavailable";
69
+ HttpStatus[HttpStatus["GatewayTimeout"] = 504] = "GatewayTimeout";
70
+ HttpStatus[HttpStatus["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
71
+ HttpStatus[HttpStatus["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
72
+ HttpStatus[HttpStatus["InsufficientStorage"] = 507] = "InsufficientStorage";
73
+ HttpStatus[HttpStatus["LoopDetected"] = 508] = "LoopDetected";
74
+ HttpStatus[HttpStatus["NotExtended"] = 510] = "NotExtended";
75
+ HttpStatus[HttpStatus["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
76
+ return HttpStatus;
77
+ }({});
78
+ const STATUS_NAME_MAP = {
79
+ [HttpStatus.Continue]: "Continue",
80
+ [HttpStatus.SwitchingProtocols]: "Switching Protocols",
81
+ [HttpStatus.ProcessingDeprecated]: "Processing",
82
+ [HttpStatus.EarlyHints]: "Early Hints",
83
+ [HttpStatus.Ok]: "OK",
84
+ [HttpStatus.Created]: "Created",
85
+ [HttpStatus.Accepted]: "Accepted",
86
+ [HttpStatus.NonAuthoritativeInformation]: "Non-Authoritative Information",
87
+ [HttpStatus.NoContent]: "No Content",
88
+ [HttpStatus.ResetContent]: "Reset Content",
89
+ [HttpStatus.PartialContent]: "Partial Content",
90
+ [HttpStatus.MultiStatus]: "Multi-Status",
91
+ [HttpStatus.AlreadyReported]: "Already Reported",
92
+ [HttpStatus.ImUsed]: "IM Used",
93
+ [HttpStatus.MultipleChoices]: "Multiple Choices",
94
+ [HttpStatus.MovedPermanently]: "Moved Permanently",
95
+ [HttpStatus.Found]: "Found",
96
+ [HttpStatus.SeeOther]: "See Other",
97
+ [HttpStatus.NotModified]: "Not Modified",
98
+ [HttpStatus.UseProxyDeprecated]: "Use Proxy",
99
+ [HttpStatus.Unused]: "Unused",
100
+ [HttpStatus.TemporaryRedirect]: "Temporary Redirect",
101
+ [HttpStatus.PermanentRedirect]: "Permanent Redirect",
102
+ [HttpStatus.BadRequest]: "Bad Request",
103
+ [HttpStatus.Unauthorized]: "Unauthorized",
104
+ [HttpStatus.PaymentRequired]: "Payment Required",
105
+ [HttpStatus.Forbidden]: "Forbidden",
106
+ [HttpStatus.NotFound]: "Not Found",
107
+ [HttpStatus.MethodNotAllowed]: "Method Not Allowed",
108
+ [HttpStatus.NotAcceptable]: "Not Acceptable",
109
+ [HttpStatus.ProxyAuthenticationRequired]: "Proxy Authentication Required",
110
+ [HttpStatus.RequestTimeout]: "Request Timeout",
111
+ [HttpStatus.Conflict]: "Conflict",
112
+ [HttpStatus.Gone]: "Gone",
113
+ [HttpStatus.LengthRequired]: "Length Required",
114
+ [HttpStatus.PreconditionFailed]: "Precondition Failed",
115
+ [HttpStatus.ContentTooLarge]: "Content Too Large",
116
+ [HttpStatus.UriTooLong]: "URI Too Long",
117
+ [HttpStatus.UnsupportedMediaType]: "Unsupported Media Type",
118
+ [HttpStatus.RangeNotSatisfiable]: "Range Not Satisfiable",
119
+ [HttpStatus.ExpectationFailed]: "Expectation Failed",
120
+ [HttpStatus.ImATeapot]: "I'm a Teapot",
121
+ [HttpStatus.MisdirectedRequest]: "Misdirected Request",
122
+ [HttpStatus.UnprocessableEntity]: "Unprocessable Entity",
123
+ [HttpStatus.Locked]: "Locked",
124
+ [HttpStatus.FailedDependency]: "Failed Dependency",
125
+ [HttpStatus.TooEarly]: "Too Early",
126
+ [HttpStatus.UpgradeRequired]: "Upgrade Required",
127
+ [HttpStatus.PreconditionRequired]: "Precondition Required",
128
+ [HttpStatus.TooManyRequests]: "Too Many Requests",
129
+ [HttpStatus.RequestHeaderFieldsTooLarge]: "Request Header Fields Too Large",
130
+ [HttpStatus.UnavailableForLegalReasons]: "Unavailable For Legal Reasons",
131
+ [HttpStatus.InternalServerError]: "Internal Server Error",
132
+ [HttpStatus.NotImplemented]: "Not Implemented",
133
+ [HttpStatus.BadGateway]: "Bad Gateway",
134
+ [HttpStatus.ServiceUnavailable]: "Service Unavailable",
135
+ [HttpStatus.GatewayTimeout]: "Gateway Timeout",
136
+ [HttpStatus.HttpVersionNotSupported]: "HTTP Version Not Supported",
137
+ [HttpStatus.VariantAlsoNegotiates]: "Variant Also Negotiates",
138
+ [HttpStatus.InsufficientStorage]: "Insufficient Storage",
139
+ [HttpStatus.LoopDetected]: "Loop Detected",
140
+ [HttpStatus.NotExtended]: "Not Extended",
141
+ [HttpStatus.NetworkAuthenticationRequired]: "Network Authentication Required"
142
+ };
143
+ /**
144
+ * Returns the name of the HTTP status code (200 -> "OK").
145
+ * @param status The HTTP status code.
146
+ * @returns The name of the HTTP status code or `undefined` if the status code is not recognized.
147
+ */
148
+ function getHttpStatusName(status) {
149
+ return STATUS_NAME_MAP[status];
150
+ }
151
+ //#endregion
152
+ //#region src/errors.ts
153
+ /**
154
+ * Base class of all HTTP errors. You can throw this error or throw any of the
155
+ * subclasses. Zeta will automatically detect and handle these errors, setting
156
+ * the appropriate status code and message.
157
+ *
158
+ * Error responses will include the stacktrace during development. To hide the
159
+ * stacktrace in production, set the `NODE_ENV` environment variable to
160
+ * `production`.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * throw new HttpError(HttpStatus.BadRequest, "Bad request")
165
+ * // OR
166
+ * throw new BadRequestError()
167
+ * ```
168
+ */
169
+ var HttpError = class extends Error {
170
+ constructor(status, message, additionalInfo, options) {
171
+ super(message, options);
172
+ this.status = status;
173
+ this.additionalInfo = additionalInfo;
174
+ this.name = "HttpError";
175
+ }
176
+ };
177
+ /** Shorthand for `new HttpError(HttpStatus.BadRequest, "Bad Request", ...)` */
178
+ var BadRequestHttpError = class extends HttpError {
179
+ constructor(message = "Bad Request", additionalInfo, options) {
180
+ super(HttpStatus.BadRequest, message, additionalInfo, options);
181
+ this.name = "BadRequestError";
182
+ }
183
+ };
184
+ /** Shorthand for `new HttpError(HttpStatus.Unauthorized, "Unauthorized", ...)` */
185
+ var UnauthorizedHttpError = class extends HttpError {
186
+ constructor(message = "Unauthorized", additionalInfo, options) {
187
+ super(HttpStatus.Unauthorized, message, additionalInfo, options);
188
+ this.name = "UnauthorizedError";
189
+ }
190
+ };
191
+ /** Shorthand for `new HttpError(HttpStatus.PaymentRequired, "Payment Required", ...)` */
192
+ var PaymentRequiredHttpError = class extends HttpError {
193
+ constructor(message = "Payment Required", additionalInfo, options) {
194
+ super(HttpStatus.PaymentRequired, message, additionalInfo, options);
195
+ this.name = "PaymentRequiredError";
196
+ }
197
+ };
198
+ /** Shorthand for `new HttpError(HttpStatus.Forbidden, "Forbidden", ...)` */
199
+ var ForbiddenHttpError = class extends HttpError {
200
+ constructor(message = "Forbidden", additionalInfo, options) {
201
+ super(HttpStatus.Forbidden, message, additionalInfo, options);
202
+ this.name = "ForbiddenError";
203
+ }
204
+ };
205
+ /** Shorthand for `new HttpError(HttpStatus.NotFound, "Not Found", ...)` */
206
+ var NotFoundHttpError = class extends HttpError {
207
+ constructor(message = "Not Found", additionalInfo, options) {
208
+ super(HttpStatus.NotFound, message, additionalInfo, options);
209
+ this.name = "NotFoundHttpError";
210
+ }
211
+ };
212
+ /** Shorthand for `new HttpError(HttpStatus.MethodNotAllowed, "Method Not Allowed", ...)` */
213
+ var MethodNotAllowedHttpError = class extends HttpError {
214
+ constructor(message = "Method Not Allowed", additionalInfo, options) {
215
+ super(HttpStatus.MethodNotAllowed, message, additionalInfo, options);
216
+ this.name = "MethodNotAllowedError";
217
+ }
218
+ };
219
+ /** Shorthand for `new HttpError(HttpStatus.NotAcceptable, "Not Acceptable", ...)` */
220
+ var NotAcceptableHttpError = class extends HttpError {
221
+ constructor(message = "Not Acceptable", additionalInfo, options) {
222
+ super(HttpStatus.NotAcceptable, message, additionalInfo, options);
223
+ this.name = "NotAcceptableError";
224
+ }
225
+ };
226
+ /** Shorthand for `new HttpError(HttpStatus.ProxyAuthenticationRequired, "Proxy Authentication Required", ...)` */
227
+ var ProxyAuthenticationRequiredHttpError = class extends HttpError {
228
+ constructor(message = "Proxy Authentication Required", additionalInfo, options) {
229
+ super(HttpStatus.ProxyAuthenticationRequired, message, additionalInfo, options);
230
+ this.name = "ProxyAuthenticationRequiredError";
231
+ }
232
+ };
233
+ /** Shorthand for `new HttpError(HttpStatus.RequestTimeout, "Request Timeout", ...)` */
234
+ var RequestTimeoutHttpError = class extends HttpError {
235
+ constructor(message = "Request Timeout", additionalInfo, options) {
236
+ super(HttpStatus.RequestTimeout, message, additionalInfo, options);
237
+ this.name = "RequestTimeoutError";
238
+ }
239
+ };
240
+ /** Shorthand for `new HttpError(HttpStatus.Conflict, "Conflict", ...)` */
241
+ var ConflictHttpError = class extends HttpError {
242
+ constructor(message = "Conflict", additionalInfo, options) {
243
+ super(HttpStatus.Conflict, message, additionalInfo, options);
244
+ this.name = "ConflictError";
245
+ }
246
+ };
247
+ /** Shorthand for `new HttpError(HttpStatus.Gone, "Gone", ...)` */
248
+ var GoneHttpError = class extends HttpError {
249
+ constructor(message = "Gone", additionalInfo, options) {
250
+ super(HttpStatus.Gone, message, additionalInfo, options);
251
+ this.name = "GoneError";
252
+ }
253
+ };
254
+ /** Shorthand for `new HttpError(HttpStatus.LengthRequired, "Length Required", ...)` */
255
+ var LengthRequiredHttpError = class extends HttpError {
256
+ constructor(message = "Length Required", additionalInfo, options) {
257
+ super(HttpStatus.LengthRequired, message, additionalInfo, options);
258
+ this.name = "LengthRequiredError";
259
+ }
260
+ };
261
+ /** Shorthand for `new HttpError(HttpStatus.PreconditionFailed, "Precondition Failed", ...)` */
262
+ var PreconditionFailedHttpError = class extends HttpError {
263
+ constructor(message = "Precondition Failed", additionalInfo, options) {
264
+ super(HttpStatus.PreconditionFailed, message, additionalInfo, options);
265
+ this.name = "PreconditionFailedError";
266
+ }
267
+ };
268
+ /** Shorthand for `new HttpError(HttpStatus.ContentTooLarge, "Content Too Large", ...)` */
269
+ var ContentTooLargeHttpError = class extends HttpError {
270
+ constructor(message = "Content Too Large", additionalInfo, options) {
271
+ super(HttpStatus.ContentTooLarge, message, additionalInfo, options);
272
+ this.name = "ContentTooLargeError";
273
+ }
274
+ };
275
+ /** Shorthand for `new HttpError(HttpStatus.UriTooLong, "URI Too Long", ...)` */
276
+ var UriTooLongHttpError = class extends HttpError {
277
+ constructor(message = "URI Too Long", additionalInfo, options) {
278
+ super(HttpStatus.UriTooLong, message, additionalInfo, options);
279
+ this.name = "UriTooLongError";
280
+ }
281
+ };
282
+ /** Shorthand for `new HttpError(HttpStatus.UnsupportedMediaType, "Unsupported Media Type", ...)` */
283
+ var UnsupportedMediaTypeHttpError = class extends HttpError {
284
+ constructor(message = "Unsupported Media Type", additionalInfo, options) {
285
+ super(HttpStatus.UnsupportedMediaType, message, additionalInfo, options);
286
+ this.name = "UnsupportedMediaTypeError";
287
+ }
288
+ };
289
+ /** Shorthand for `new HttpError(HttpStatus.RangeNotSatisfiable, "Range Not Satisfiable", ...)` */
290
+ var RangeNotSatisfiableHttpError = class extends HttpError {
291
+ constructor(message = "Range Not Satisfiable", additionalInfo, options) {
292
+ super(HttpStatus.RangeNotSatisfiable, message, additionalInfo, options);
293
+ this.name = "RangeNotSatisfiableError";
294
+ }
295
+ };
296
+ /** Shorthand for `new HttpError(HttpStatus.ExpectationFailed, "Expectation Failed", ...)` */
297
+ var ExpectationFailedHttpError = class extends HttpError {
298
+ constructor(message = "Expectation Failed", additionalInfo, options) {
299
+ super(HttpStatus.ExpectationFailed, message, additionalInfo, options);
300
+ this.name = "ExpectationFailedError";
301
+ }
302
+ };
303
+ /** Shorthand for `new HttpError(HttpStatus.ImATeapot, "I'm a Teapot", ...)` */
304
+ var ImATeapotHttpError = class extends HttpError {
305
+ constructor(message = "I'm a Teapot", additionalInfo, options) {
306
+ super(HttpStatus.ImATeapot, message, additionalInfo, options);
307
+ this.name = "ImATeapotError";
308
+ }
309
+ };
310
+ /** Shorthand for `new HttpError(HttpStatus.MisdirectedRequest, "Misdirected Request", ...)` */
311
+ var MisdirectedRequestHttpError = class extends HttpError {
312
+ constructor(message = "Misdirected Request", additionalInfo, options) {
313
+ super(HttpStatus.MisdirectedRequest, message, additionalInfo, options);
314
+ this.name = "MisdirectedRequestError";
315
+ }
316
+ };
317
+ /** Shorthand for `new HttpError(HttpStatus.UnprocessableEntity, "Unprocessable Entity", ...)` */
318
+ var UnprocessableEntityHttpError = class extends HttpError {
319
+ constructor(message = "Unprocessable Entity", additionalInfo, options) {
320
+ super(HttpStatus.UnprocessableEntity, message, additionalInfo, options);
321
+ this.name = "UnprocessableEntityError";
322
+ }
323
+ };
324
+ /** Shorthand for `new HttpError(HttpStatus.Locked, "Locked", ...)` */
325
+ var LockedHttpError = class extends HttpError {
326
+ constructor(message = "Locked", additionalInfo, options) {
327
+ super(HttpStatus.Locked, message, additionalInfo, options);
328
+ this.name = "LockedError";
329
+ }
330
+ };
331
+ /** Shorthand for `new HttpError(HttpStatus.FailedDependency, "Failed Dependency", ...)` */
332
+ var FailedDependencyHttpError = class extends HttpError {
333
+ constructor(message = "Failed Dependency", additionalInfo, options) {
334
+ super(HttpStatus.FailedDependency, message, additionalInfo, options);
335
+ this.name = "FailedDependencyError";
336
+ }
337
+ };
338
+ /** Shorthand for `new HttpError(HttpStatus.TooEarly, "Too Early", ...)` */
339
+ var TooEarlyHttpError = class extends HttpError {
340
+ constructor(message = "Too Early", additionalInfo, options) {
341
+ super(HttpStatus.TooEarly, message, additionalInfo, options);
342
+ this.name = "TooEarlyError";
343
+ }
344
+ };
345
+ /** Shorthand for `new HttpError(HttpStatus.UpgradeRequired, "Upgrade Required", ...)` */
346
+ var UpgradeRequiredHttpError = class extends HttpError {
347
+ constructor(message = "Upgrade Required", additionalInfo, options) {
348
+ super(HttpStatus.UpgradeRequired, message, additionalInfo, options);
349
+ this.name = "UpgradeRequiredError";
350
+ }
351
+ };
352
+ /** Shorthand for `new HttpError(HttpStatus.PreconditionRequired, "Precondition Required", ...)` */
353
+ var PreconditionRequiredHttpError = class extends HttpError {
354
+ constructor(message = "Precondition Required", additionalInfo, options) {
355
+ super(HttpStatus.PreconditionRequired, message, additionalInfo, options);
356
+ this.name = "PreconditionRequiredError";
357
+ }
358
+ };
359
+ /** Shorthand for `new HttpError(HttpStatus.TooManyRequests, "Too Many Requests", ...)` */
360
+ var TooManyRequestsHttpError = class extends HttpError {
361
+ constructor(message = "Too Many Requests", additionalInfo, options) {
362
+ super(HttpStatus.TooManyRequests, message, additionalInfo, options);
363
+ this.name = "TooManyRequestsError";
364
+ }
365
+ };
366
+ /** Shorthand for `new HttpError(HttpStatus.RequestHeaderFieldsTooLarge, "Request Header Fields Too Large", ...)` */
367
+ var RequestHeaderFieldsTooLargeHttpError = class extends HttpError {
368
+ constructor(message = "Request Header Fields Too Large", additionalInfo, options) {
369
+ super(HttpStatus.RequestHeaderFieldsTooLarge, message, additionalInfo, options);
370
+ this.name = "RequestHeaderFieldsTooLargeError";
371
+ }
372
+ };
373
+ /** Shorthand for `new HttpError(HttpStatus.UnavailableForLegalReasons, "Unavailable For Legal Reasons", ...)` */
374
+ var UnavailableForLegalReasonsHttpError = class extends HttpError {
375
+ constructor(message = "Unavailable For Legal Reasons", additionalInfo, options) {
376
+ super(HttpStatus.UnavailableForLegalReasons, message, additionalInfo, options);
377
+ this.name = "UnavailableForLegalReasonsError";
378
+ }
379
+ };
380
+ /** Shorthand for `new HttpError(HttpStatus.InternalServerError, "Internal Server Error", ...)` */
381
+ var InternalServerErrorHttpError = class extends HttpError {
382
+ constructor(message = "Internal Server Error", additionalInfo, options) {
383
+ super(HttpStatus.InternalServerError, message, additionalInfo, options);
384
+ this.name = "InternalServerErrorError";
385
+ }
386
+ };
387
+ /** Shorthand for `new HttpError(HttpStatus.NotImplemented, "Not Implemented", ...)` */
388
+ var NotImplementedHttpError = class extends HttpError {
389
+ constructor(message = "Not Implemented", additionalInfo, options) {
390
+ super(HttpStatus.NotImplemented, message, additionalInfo, options);
391
+ this.name = "NotImplementedHttpError";
392
+ }
393
+ };
394
+ /** Shorthand for `new HttpError(HttpStatus.BadGateway, "Bad Gateway", ...)` */
395
+ var BadGatewayHttpError = class extends HttpError {
396
+ constructor(message = "Bad Gateway", additionalInfo, options) {
397
+ super(HttpStatus.BadGateway, message, additionalInfo, options);
398
+ this.name = "BadGatewayError";
399
+ }
400
+ };
401
+ /** Shorthand for `new HttpError(HttpStatus.ServiceUnavailable, "Service Unavailable", ...)` */
402
+ var ServiceUnavailableHttpError = class extends HttpError {
403
+ constructor(message = "Service Unavailable", additionalInfo, options) {
404
+ super(HttpStatus.ServiceUnavailable, message, additionalInfo, options);
405
+ this.name = "ServiceUnavailableError";
406
+ }
407
+ };
408
+ /** Shorthand for `new HttpError(HttpStatus.GatewayTimeout, "Gateway Timeout", ...)` */
409
+ var GatewayTimeoutHttpError = class extends HttpError {
410
+ constructor(message = "Gateway Timeout", additionalInfo, options) {
411
+ super(HttpStatus.GatewayTimeout, message, additionalInfo, options);
412
+ this.name = "GatewayTimeoutError";
413
+ }
414
+ };
415
+ /** Shorthand for `new HttpError(HttpStatus.HttpVersionNotSupported, "HTTP Version Not Supported", ...)` */
416
+ var HttpVersionNotSupportedHttpError = class extends HttpError {
417
+ constructor(message = "HTTP Version Not Supported", additionalInfo, options) {
418
+ super(HttpStatus.HttpVersionNotSupported, message, additionalInfo, options);
419
+ this.name = "HttpVersionNotSupportedError";
420
+ }
421
+ };
422
+ /** Shorthand for `new HttpError(HttpStatus.VariantAlsoNegotiates, "Variant Also Negotiates", ...)` */
423
+ var VariantAlsoNegotiatesHttpError = class extends HttpError {
424
+ constructor(message = "Variant Also Negotiates", additionalInfo, options) {
425
+ super(HttpStatus.VariantAlsoNegotiates, message, additionalInfo, options);
426
+ this.name = "VariantAlsoNegotiatesError";
427
+ }
428
+ };
429
+ /** Shorthand for `new HttpError(HttpStatus.InsufficientStorage, "Insufficient Storage", ...)` */
430
+ var InsufficientStorageHttpError = class extends HttpError {
431
+ constructor(message = "Insufficient Storage", additionalInfo, options) {
432
+ super(HttpStatus.InsufficientStorage, message, additionalInfo, options);
433
+ this.name = "InsufficientStorageError";
434
+ }
435
+ };
436
+ /** Shorthand for `new HttpError(HttpStatus.LoopDetected, "Loop Detected", ...)` */
437
+ var LoopDetectedHttpError = class extends HttpError {
438
+ constructor(message = "Loop Detected", additionalInfo, options) {
439
+ super(HttpStatus.LoopDetected, message, additionalInfo, options);
440
+ this.name = "LoopDetectedError";
441
+ }
442
+ };
443
+ /** Shorthand for `new HttpError(HttpStatus.NotExtended, "Not Extended", ...)` */
444
+ var NotExtendedHttpError = class extends HttpError {
445
+ constructor(message = "Not Extended", additionalInfo, options) {
446
+ super(HttpStatus.NotExtended, message, additionalInfo, options);
447
+ this.name = "NotExtendedError";
448
+ }
449
+ };
450
+ /** Shorthand for `new HttpError(HttpStatus.NetworkAuthenticationRequired, "Network Authentication Required", ...)` */
451
+ var NetworkAuthenticationRequiredHttpError = class extends HttpError {
452
+ constructor(message = "Network Authentication Required", additionalInfo, options) {
453
+ super(HttpStatus.NetworkAuthenticationRequired, message, additionalInfo, options);
454
+ this.name = "NetworkAuthenticationRequiredError";
455
+ }
456
+ };
457
+ //#endregion
458
+ //#region src/internal/utils.ts
459
+ function validateSchema(schema, input, status, message) {
460
+ const res = schema["~standard"].validate(input);
461
+ if (res instanceof Promise) throw Error("Async validation not supported");
462
+ if (res.issues) throw new HttpError(status, message, {
463
+ issues: res.issues,
464
+ input
465
+ });
466
+ return res.value;
467
+ }
468
+ function createHttpSchemaValidator(status, message) {
469
+ return (schema, input) => validateSchema(schema, input, status, message);
470
+ }
471
+ const validateInputSchema = createHttpSchemaValidator(HttpStatus.BadRequest, "Input validation failed");
472
+ const validateOutputSchema = createHttpSchemaValidator(HttpStatus.UnprocessableEntity, "Output validation failed");
473
+ function getRawPathname(request) {
474
+ const start = request.url.indexOf("/", 8);
475
+ if (start === -1) return "/";
476
+ for (let i = start + 1; i < request.url.length; i++) if (request.url[i] === "?" || request.url[i] === "#") return request.url.slice(start, i);
477
+ return request.url.slice(start);
478
+ }
479
+ function getRawQuery(request) {
480
+ let index = request.url.indexOf("?");
481
+ if (index === -1) return {};
482
+ const res = {};
483
+ const str = request.url;
484
+ const len = str.length;
485
+ let start = index + 1;
486
+ for (let i = start; i < len; i++) if (str[i] === "&" || i === len - 1) {
487
+ const end = i === len - 1 ? len : i;
488
+ const eqIndex = str.indexOf("=", start);
489
+ if (eqIndex !== -1 && eqIndex < end) res[str.slice(start, eqIndex)] = str.slice(eqIndex + 1, end);
490
+ start = i + 1;
491
+ }
492
+ return res;
493
+ }
494
+ function getRawParams(route) {
495
+ const params = route.params;
496
+ if (!params) return {};
497
+ const res = {};
498
+ for (const key in params) {
499
+ const outKey = key === "_" ? "**" : key;
500
+ res[outKey] = decodeURIComponent(params[key]);
501
+ }
502
+ return res;
503
+ }
504
+ function getErrorStack(err) {
505
+ if (process.env.NODE_ENV === "production") return;
506
+ return err.stack?.split("\n").map((line) => line.trim()).slice(1);
507
+ }
508
+ function serializeErrorResponse(err) {
509
+ if (err instanceof HttpError) return {
510
+ status: err.status,
511
+ name: err.name,
512
+ message: err.message,
513
+ ...err.additionalInfo,
514
+ stack: getErrorStack(err),
515
+ cause: err.cause != null ? serializeErrorResponse(err.cause) : void 0
516
+ };
517
+ if (err instanceof Error) return {
518
+ status: HttpStatus.InternalServerError,
519
+ name: err.name,
520
+ message: err.message,
521
+ stack: getErrorStack(err),
522
+ cause: err.cause != null ? serializeErrorResponse(err.cause) : void 0
523
+ };
524
+ return {
525
+ name: "Unknown Error",
526
+ message: "An unknown error occurred",
527
+ status: HttpStatus.InternalServerError,
528
+ stack: getErrorStack(err)
529
+ };
530
+ }
531
+ const IsStatusResult = Symbol("IsStatusResult");
532
+ function detectTransport() {
533
+ if (typeof Bun !== "undefined") return createBunTransport();
534
+ if (typeof Deno !== "undefined") return createDenoTransport();
535
+ throw Error(`Cannot automatically detect which transport to use. You must specify a transport in your top-level app:
536
+
537
+ ---
538
+ import { createBunTransport } from '@aklinker1/zeta/transports/bun-transport';
539
+
540
+ const app = createApp({
541
+ transport: createBunTransport(),
542
+ })
543
+
544
+ app.listen();
545
+ ---`);
546
+ }
547
+ function cleanupCompiledWhitespace(code) {
548
+ return code.replace(/^ +$/gm, "").replace(/\n\n+/gm, "\n\n").replaceAll("{\n\n", "{\n");
549
+ }
550
+ //#endregion
551
+ //#region src/internal/context.ts
552
+ var Context = class {
553
+ set = {
554
+ status: HttpStatus.Ok,
555
+ headers: {}
556
+ };
557
+ matchedRoute;
558
+ #params;
559
+ #query;
560
+ constructor(request, path, origin) {
561
+ this.request = request;
562
+ this.path = path;
563
+ this.origin = origin;
564
+ }
565
+ get url() {
566
+ return new URL(this.request.url, this.origin);
567
+ }
568
+ get params() {
569
+ if (this.#params !== void 0) return this.#params;
570
+ return this.matchedRoute?.params ? getRawParams(this.matchedRoute) : {};
571
+ }
572
+ set params(value) {
573
+ this.#params = value;
574
+ }
575
+ get query() {
576
+ if (this.#query !== void 0) return this.#query;
577
+ return this.request.url.includes("?") ? getRawQuery(this.request) : {};
578
+ }
579
+ set query(value) {
580
+ this.#query = value;
581
+ }
582
+ get route() {
583
+ return this.matchedRoute?.data.route;
584
+ }
585
+ get method() {
586
+ return this.request.method;
587
+ }
588
+ status(status, body) {
589
+ return {
590
+ [IsStatusResult]: true,
591
+ status,
592
+ body
593
+ };
594
+ }
595
+ };
596
+ //#endregion
597
+ //#region src/internal/compile-fetch-function.ts
598
+ function compileFetchFunction(options) {
599
+ const onGlobalRequestCount = options.hooks.onGlobalRequest?.length;
600
+ const onGlobalAfterResponseCount = options.hooks.onGlobalAfterResponse?.length;
601
+ const onGlobalErrorCount = options.hooks.onGlobalError?.length;
602
+ const js = `
603
+ return (request) => {
604
+ const path = utils.getRawPathname(request);
605
+ const ctx = new utils.Context(request, path, utils.origin);
606
+ ${onGlobalAfterResponseCount ? "let handlerReturnedPromise = false;" : ""}
607
+
608
+ try {
609
+ ${onGlobalRequestCount ? compileOnGlobalRequestHook(onGlobalRequestCount) : ""}
610
+
611
+ const matchedRoute = utils.getRoute(request.method, path);
612
+ if (matchedRoute == null) {
613
+ throw new utils.NotFoundHttpError(undefined, {
614
+ method: request.method,
615
+ path,
616
+ });
617
+ } else {
618
+ ctx.matchedRoute = matchedRoute;
619
+ }
620
+
621
+ ctx.response = matchedRoute.data.compiledHandler(request, ctx);
622
+ if (typeof ctx.response.then !== utils.FUNCTION) return ctx.response;
623
+
624
+ ${onGlobalAfterResponseCount ? "handlerReturnedPromise = true;" : ""}
625
+ return ctx.response.catch(error => {
626
+ ${onGlobalErrorCount ? compileOnGlobalErrorHook(onGlobalErrorCount, 3) : ""}
627
+
628
+ ${compileErrorResponse(3)}
629
+ })${onGlobalAfterResponseCount ? compileOnGlobalAfterResponsePromiseFinally(onGlobalAfterResponseCount, 2) : ""};
630
+ } catch (error) {
631
+ ${onGlobalErrorCount ? compileOnGlobalErrorHook(onGlobalErrorCount, 2) : ""}
632
+
633
+ ${compileErrorResponse(2)}
634
+ } ${onGlobalAfterResponseCount ? compileOnGlobalAfterResponseFinally(onGlobalAfterResponseCount, 1) : ""}
635
+ }
636
+ //#sourceURL=zeta-jit-generated://zeta-fetch-fn.js
637
+ `;
638
+ return new Function("utils", cleanupCompiledWhitespace(js))({
639
+ FUNCTION: "function",
640
+ getRawPathname,
641
+ hooks: options.hooks,
642
+ Context,
643
+ getRoute: options.getRoute,
644
+ NotFoundHttpError,
645
+ origin: options.origin,
646
+ HttpError,
647
+ HttpStatus,
648
+ serializeErrorResponse
649
+ });
650
+ }
651
+ function compileOnGlobalRequestHook(hookCount) {
652
+ const lines = [];
653
+ for (let i = 0; i < hookCount; i++) {
654
+ const resultVar = `onGlobalRequestRes${i}`;
655
+ lines.push(` const ${resultVar} = utils.hooks.onGlobalRequest[${i}].callback(ctx);`, ...process.env.NODE_ENV !== "production" ? [` if (${resultVar} instanceof Promise)`, ` console.warn("Warning: Promise returned from onGlobalRequest hook. Promises returned from onGlobalRequest are not awaited, ignoring the return value.");`] : [], ` if (${resultVar})`, ` if (typeof ${resultVar}.body?.bytes === utils.FUNCTION)`, ` return ${resultVar};`, ` else`, ` for (const key of Object.keys(${resultVar}))`, ` ctx[key] = ${resultVar}[key];`);
656
+ }
657
+ return lines.join("\n");
658
+ }
659
+ function compileOnGlobalErrorHook(hookCount, tabs) {
660
+ const indent = " ".repeat(tabs);
661
+ const lines = [`${indent}ctx.error = error;`];
662
+ for (let i = 0; i < hookCount; i++) lines.push(`${indent}utils.hooks.onGlobalError[${i}].callback(ctx);`);
663
+ return lines.join("\n");
664
+ }
665
+ function compileOnGlobalAfterResponseFinally(hookCount, tabs) {
666
+ const indent = " ".repeat(tabs);
667
+ return `finally {
668
+ ${indent} if (!handlerReturnedPromise) {
669
+ ${compileOnGlobalAfterResponseHook(hookCount, tabs + 2)}
670
+ ${indent} }
671
+ ${indent}}
672
+ `;
673
+ }
674
+ function compileOnGlobalAfterResponsePromiseFinally(hookCount, tabs) {
675
+ const indent = " ".repeat(tabs);
676
+ return `.finally(() => {
677
+ ${compileOnGlobalAfterResponseHook(hookCount, tabs + 1)}
678
+ ${indent}})`;
679
+ }
680
+ function compileOnGlobalAfterResponseHook(hookCount, tabs) {
681
+ const indent = " ".repeat(tabs);
682
+ const lines = [`${indent}setTimeout(() => {`];
683
+ for (let i = 0; i < hookCount; i++) lines.push(`${indent} utils.hooks.onGlobalAfterResponse[${i}].callback(ctx);`);
684
+ lines.push(`${indent}})`);
685
+ return lines.join("\n");
686
+ }
687
+ function compileErrorResponse(tabs) {
688
+ const indent = " ".repeat(tabs);
689
+ return `${indent}const status =
690
+ ${indent} error instanceof utils.HttpError
691
+ ${indent} ? error.status
692
+ ${indent} : utils.HttpStatus.InternalServerError;
693
+ ${indent}return (
694
+ ${indent} ctx.response = Response.json(
695
+ ${indent} utils.serializeErrorResponse(error),
696
+ ${indent} { status, headers: ctx.set.headers },
697
+ ${indent} )
698
+ ${indent});`;
699
+ }
700
+ //#endregion
701
+ //#region src/meta.ts
702
+ /** Get metadata for either a ZetaSchema or a StandardSchemaV1. */
703
+ function getMeta(adapter, schema) {
704
+ if (isZetaSchema(schema)) return schema["~zeta"].meta;
705
+ if (!adapter) return {};
706
+ return adapter.getMeta(schema) ?? {};
707
+ }
708
+ //#endregion
709
+ //#region src/internal/compile-route-handler.ts
710
+ function compileRouteHandler(options) {
711
+ if (options.fetch) return new Function(`
712
+ return (request, ctx) => ctx.matchedRoute.data.fetch(request)
713
+ //#sourceURL=${getSourceUrl(options)}
714
+ `)();
715
+ const responseContentTypeMap = getResponseContentTypeMap(options);
716
+ const js = `
717
+ return async (request, ctx) => {
718
+ ${options.method === "GET" ? "" : ADD_CTX_BODY}
719
+
720
+ ${options.hooks.onTransform?.length ? compileCtxModifierHookCall("onTransform", options.hooks.onTransform.length) : ""}
721
+
722
+ ${options.def?.body ? "ctx.body = utils.validateInputSchema(ctx.matchedRoute.data.def.body, ctx.body);" : ""}
723
+ ${options.def?.params ? "ctx.params = utils.validateInputSchema(ctx.matchedRoute.data.def.params, ctx.params);" : ""}
724
+ ${options.def?.query ? "ctx.query = utils.validateInputSchema(ctx.matchedRoute.data.def.query, ctx.query);" : ""}
725
+
726
+ ${options.hooks.onBeforeHandle?.length ? compileCtxModifierHookCall("onBeforeHandle", options.hooks.onBeforeHandle.length) : ""}
727
+
728
+ ctx.response = await ctx.matchedRoute.data.handler(ctx);
729
+ if (ctx.response) {
730
+ if (ctx.response[utils.IsStatusResult]) {
731
+ ctx.set.status = ctx.response.status;
732
+ ctx.response = ctx.response.body;
733
+ }
734
+ if (typeof ctx.response?.body?.bytes === utils.FUNCTION) return ctx.response;
735
+ }
736
+
737
+ ${compileValidateResponse(options)}
738
+
739
+ ${options.hooks.onAfterHandle?.length ? compileResponseModifierHookCall("onAfterHandle", options.hooks.onAfterHandle.length) : ""}
740
+
741
+ ${options.hooks.onMapResponse?.length ? compileResponseModifierHookCall("onMapResponse", options.hooks.onMapResponse.length) : ""}
742
+
743
+ if (ctx.response == null) {
744
+ return (
745
+ ctx.response = new Response(undefined, {
746
+ status: ctx.set.status,
747
+ headers: ctx.set.headers,
748
+ })
749
+ )
750
+ }
751
+
752
+ const serialized = utils.smartSerialize(ctx.response);
753
+ if (!ctx.set.headers["Content-Type"]) ctx.set.headers["Content-Type"] = ${responseContentTypeMap ? "responseContentTypeMap[ctx.set.status] ??" : ""} serialized.contentType
754
+ return (
755
+ ctx.response = new Response(serialized.value, {
756
+ status: ctx.set.status,
757
+ headers: ctx.set.headers,
758
+ })
759
+ )
760
+ }
761
+ //#sourceURL=${getSourceUrl(options)}
762
+ `;
763
+ return new Function("utils", "responseContentTypeMap", cleanupCompiledWhitespace(js))(UTILS, responseContentTypeMap);
764
+ }
765
+ const UTILS = {
766
+ smartDeserialize,
767
+ smartSerialize,
768
+ FUNCTION: "function",
769
+ IsStatusResult,
770
+ validateInputSchema,
771
+ validateOutputSchema
772
+ };
773
+ function getSourceUrl(options) {
774
+ return `zeta-jit-generated://${options.method.toLowerCase()}-${options.route.replace(/\s/gm, "").replaceAll("/", "-")}.js`;
775
+ }
776
+ const ADD_CTX_BODY = `
777
+ ctx.body = utils.smartDeserialize(request);
778
+ if (ctx.body) ctx.body = await ctx.body;
779
+ `;
780
+ function compileCtxModifierHookCall(hook, hookCount) {
781
+ const lines = [];
782
+ for (let i = 0; i < hookCount; i++) {
783
+ const resultVar = `${hook}Res${i}`;
784
+ lines.push(` const ${resultVar} = await ctx.matchedRoute.data.hooks.${hook}[${i}].callback(ctx);`, ` if (${resultVar})`, ` if (typeof ${resultVar}.body?.bytes === utils.FUNCTION)`, ` return ${resultVar};`, ` else`, ` for (const key of Object.keys(${resultVar}))`, ` ctx[key] = ${resultVar}[key];`);
785
+ }
786
+ return lines.join("\n");
787
+ }
788
+ function compileResponseModifierHookCall(hook, hookCount) {
789
+ const lines = [];
790
+ for (let i = 0; i < hookCount; i++) {
791
+ const resultVar = `${hook}Res${i}`;
792
+ lines.push(` const ${resultVar} = await ctx.matchedRoute.data.hooks.${hook}[${i}].callback(ctx);`, ` if (${resultVar}) ctx.response = ${resultVar};`, ` if (typeof ${resultVar}.body?.bytes === utils.FUNCTION)`, ` return ${resultVar};`);
793
+ }
794
+ return lines.join("\n");
795
+ }
796
+ function compileValidateResponse(options) {
797
+ if (!options.def?.responses) return "";
798
+ if ("~standard" in options.def.responses) return "ctx.response = utils.validateOutputSchema(ctx.matchedRoute.data.def.responses, ctx.response);";
799
+ return "ctx.response = utils.validateOutputSchema(ctx.matchedRoute.data.def.responses[ctx.set.status], ctx.response);";
800
+ }
801
+ function getResponseContentTypeMap(options) {
802
+ if (!options.def?.responses) return;
803
+ if ("~standard" in options.def.responses) {
804
+ const { contentType } = getMeta(options.schemaAdapter, options.def.responses);
805
+ if (!contentType) return;
806
+ return { [200]: contentType };
807
+ }
808
+ const map = {};
809
+ for (const [status, schema] of Object.entries(options.def.responses)) {
810
+ const { contentType } = getMeta(options.schemaAdapter, schema);
811
+ map[Number(status)] = contentType;
812
+ }
813
+ if (Object.keys(map).length === 0) return;
814
+ return map;
815
+ }
816
+ //#endregion
817
+ //#region src/open-api.ts
818
+ function buildOpenApiDocs(options, app) {
819
+ try {
820
+ if (!options?.schemaAdapter) return {
821
+ type: "error",
822
+ error: "OpenAPI docs require a schema adapter"
823
+ };
824
+ const adapter = options.schemaAdapter;
825
+ const userDoc = options.openApi ?? {};
826
+ const docs = {
827
+ openapi: "3.1.0",
828
+ ...userDoc,
829
+ info: {
830
+ title: "Zeta Application",
831
+ version: "1.0.0",
832
+ ...userDoc.info
833
+ },
834
+ paths: {},
835
+ components: {
836
+ ...userDoc.components,
837
+ schemas: {
838
+ ...userDoc.components?.schemas,
839
+ ErrorResponse: ErrorResponseJsonSchema
840
+ }
841
+ }
842
+ };
843
+ for (const [method, methodEntry] of Object.entries(app["~zeta"].routes)) for (const [path, routerData] of Object.entries(methodEntry)) {
844
+ const openApiPath = path.replace(/\/:([^/]+)/g, "/{$1}").replace(/\/$/, "") || "/";
845
+ const { headers, params, query, body, responses, ...openApiOperation } = routerData.def ?? {};
846
+ docs.paths ??= {};
847
+ docs.paths[openApiPath] ??= {};
848
+ docs.paths[openApiPath][method.toLowerCase()] = {
849
+ ...openApiOperation,
850
+ summary: openApiOperation.summary ?? (openApiOperation.operationId ? titleCase(openApiOperation.operationId) : void 0),
851
+ requestBody: body ? { content: { [getMeta(adapter, body)?.contentType ?? "application/json"]: { schema: isZetaSchema(body) ? body.toJsonSchema?.() : adapter.toJsonSchema(body) } } } : void 0,
852
+ parameters: [
853
+ ...mapParameters(adapter, params, "path"),
854
+ ...mapParameters(adapter, query, "query"),
855
+ ...mapParameters(adapter, headers, "header")
856
+ ],
857
+ responses: {
858
+ ...!responses ? {} : "~standard" in responses ? { 200: buildResponse(200, responses, adapter) } : Object.fromEntries(Object.entries(responses).map(([status, response]) => [status, buildResponse(Number(status), response, adapter)])),
859
+ ...(params || query || headers || body) && { 400: {
860
+ description: "Bad Request",
861
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
862
+ } }
863
+ }
864
+ };
865
+ }
866
+ return {
867
+ type: "success",
868
+ spec: optimizeSpec(docs)
869
+ };
870
+ } catch (error) {
871
+ return {
872
+ type: "error",
873
+ error
874
+ };
875
+ }
876
+ }
877
+ function buildScalarHtml(jsonRoute, options) {
878
+ const scalarConfig = {
879
+ defaultOpenAllTags: true,
880
+ ...options?.scalar,
881
+ url: jsonRoute
882
+ };
883
+ return `<!doctype html>
884
+ <html>
885
+ <head>
886
+ <title>API Reference</title>
887
+ <meta charset="utf-8" />
888
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
889
+ </head>
890
+ <body>
891
+ <div id="app"></div>
892
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"><\/script>
893
+ <script>
894
+ const config = ${JSON.stringify(scalarConfig)};
895
+ if (${process.env.NODE_ENV !== "production"}) {
896
+ config.servers ??= [];
897
+ config.servers.unshift({ url: location.origin })
898
+ }
899
+ Scalar.createApiReference('#app', config)
900
+ <\/script>
901
+ </body>
902
+ </html>
903
+ `;
904
+ }
905
+ function mapParameters(adapter, schema, in_) {
906
+ if (!schema) return [];
907
+ const openApiSchema = adapter.toJsonSchema(schema);
908
+ if (openApiSchema.type !== "object") throw Error(`Param in ${in_} must have { "type": "object", ... }, but got ${JSON.stringify(openApiSchema, null, 2)}`);
909
+ return Object.entries(openApiSchema.properties).map(([name, def]) => ({
910
+ name,
911
+ in: in_,
912
+ description: def.description,
913
+ schema: def,
914
+ required: !!openApiSchema.required?.includes(name)
915
+ }));
916
+ }
917
+ function buildResponse(status, schema, adapter) {
918
+ const meta = getMeta(adapter, schema);
919
+ if (isZetaSchema(schema)) {
920
+ const description = meta?.responseDescription ?? getHttpStatusName(status) ?? "";
921
+ if (schema["~zeta"].type === "NoResponse") return { description };
922
+ if (schema["~zeta"].type === "ErrorResponse") return {
923
+ description,
924
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
925
+ };
926
+ }
927
+ return {
928
+ description: meta?.responseDescription ?? getHttpStatusName(status),
929
+ content: { [meta?.contentType ?? "application/json"]: { schema: adapter.toJsonSchema(schema) } }
930
+ };
931
+ }
932
+ function optimizeSpec(spec) {
933
+ const optimized = structuredClone(spec);
934
+ addModelRefs(optimized);
935
+ sortComponentSchemas(optimized);
936
+ return optimized;
937
+ }
938
+ /**
939
+ * Look for `ref` properties from schema metadata and move those models to
940
+ * `components.schemas`.
941
+ */
942
+ function addModelRefs(spec) {
943
+ const recurse = (obj) => {
944
+ if (obj == null) return;
945
+ if (typeof obj !== "object") return;
946
+ if (Array.isArray(obj)) {
947
+ for (let i = 0, il = obj.length; i < il; i++) recurse(obj[i]);
948
+ return;
949
+ }
950
+ const values = Object.values(obj);
951
+ for (let i = 0, il = values.length; i < il; i++) recurse(values[i]);
952
+ if (typeof obj.ref === "string") {
953
+ const ref = obj.ref;
954
+ spec.components ??= {};
955
+ spec.components.schemas ??= {};
956
+ spec.components.schemas[ref] = {
957
+ ...structuredClone(obj),
958
+ ref: void 0
959
+ };
960
+ for (const key of Object.keys(obj)) delete obj[key];
961
+ obj.$ref = `#/components/schemas/${ref}`;
962
+ }
963
+ };
964
+ recurse(spec.paths);
965
+ }
966
+ function sortComponentSchemas(spec) {
967
+ if (!spec?.components?.schemas) return;
968
+ spec.components.schemas = Object.fromEntries(Object.entries(spec.components.schemas).sort((a, b) => a[0].toLowerCase().localeCompare(b[0].toLowerCase())));
969
+ }
970
+ //#endregion
971
+ //#region src/app.ts
972
+ let appIdInc = 0;
973
+ const nextAppId = () => `app-${appIdInc++}`;
974
+ let _hookIdInc = 0;
975
+ const nextHookId = (appId) => `${appId}/hook-${_hookIdInc++}`;
976
+ /**
977
+ * Create a server-side, Zeta application.
978
+ *
979
+ * Zeta provides simple support for serving applications using `Bun.serve` and
980
+ * `Deno.serve` by calling `app.listen(3000)`.
981
+ *
982
+ * If you need more customization, you can use the `build` method to create a
983
+ * `fetch` function and serve it however you like.
984
+ *
985
+ * @example
986
+ * ```ts
987
+ * import { createApp } from "@aklinker1/zeta";
988
+ *
989
+ * const app = createApp({ prefix: "/api" })
990
+ * .get("/health", () => "OK")
991
+ * .get("/users", () => ["user1", "user2"]);
992
+ *
993
+ * app.listen(3000);
994
+ *
995
+ * // Or serve the app yourself
996
+ * const fetch = app.build();
997
+ * Bun.serve({ fetch, ... });
998
+ * Deno.serve({ fetch, ... });
999
+ * ```
1000
+ *
1001
+ * @param options Configure application behavior.
1002
+ */
1003
+ function createApp(options) {
1004
+ const appId = nextAppId();
1005
+ const { origin = "http://localhost", prefix = "" } = options ?? {};
1006
+ const hooks = {};
1007
+ const routes = {};
1008
+ const addRoutesEntry = (method, route, data) => {
1009
+ routes[method] ??= {};
1010
+ if (routes[method][route]) console.warn(`Route ${route} already exists`);
1011
+ routes[method][route] = data;
1012
+ };
1013
+ const cloneHooks = () => {
1014
+ const cloned = {};
1015
+ for (const key of Object.keys(hooks)) if (hooks[key]) cloned[key] = [...hooks[key]];
1016
+ return cloned;
1017
+ };
1018
+ const app = {
1019
+ [Symbol.toStringTag]: "ZetaApp",
1020
+ "~zeta": {
1021
+ id: appId,
1022
+ prefix,
1023
+ routes,
1024
+ hooks
1025
+ },
1026
+ build: () => {
1027
+ const jsonRoute = options?.openApiRoute ?? "/openapi.json";
1028
+ const scalarRoute = options?.scalarRoute ?? "/scalar";
1029
+ const docs = buildOpenApiDocs(options, app);
1030
+ if (docs.type === "error") console.error("Failed to build OpenAPI docs:", docs.error);
1031
+ app.get(jsonRoute, () => {
1032
+ if (docs.type === "error") {
1033
+ console.error("Failed to build OpenAPI docs:", docs.error);
1034
+ throw docs.error;
1035
+ }
1036
+ return docs.spec;
1037
+ });
1038
+ if (docs.type === "success") {
1039
+ const scalarHtml = buildScalarHtml(jsonRoute, options);
1040
+ app.get(scalarRoute, () => new Response(scalarHtml, { headers: { "content-type": "text/html;charset=utf-8" } }));
1041
+ }
1042
+ const router = createRouter();
1043
+ for (const [method, methodValue] of Object.entries(routes)) for (const [path, data] of Object.entries(methodValue)) addRoute(router, method === Method.Any ? void 0 : method, path, data);
1044
+ return compileFetchFunction({
1045
+ getRoute: compileRouter(router),
1046
+ hooks,
1047
+ origin
1048
+ });
1049
+ },
1050
+ getOpenApiSpec: () => {
1051
+ const res = buildOpenApiDocs(options, app);
1052
+ if (res.type === "error") throw res.error;
1053
+ return res.spec;
1054
+ },
1055
+ export: () => {
1056
+ app["~zeta"].exported = true;
1057
+ return app;
1058
+ },
1059
+ listen: (port, cb) => {
1060
+ (options?.transport ?? detectTransport()).listen(port, app.build(), cb);
1061
+ return app;
1062
+ },
1063
+ decorate: (...args) => {
1064
+ const obj = args.length === 2 ? { [args[0]]: args[1] } : args[0];
1065
+ hooks.onTransform ??= [];
1066
+ hooks.onTransform.push({
1067
+ id: nextHookId(appId),
1068
+ applyTo: "local",
1069
+ callback: () => obj
1070
+ });
1071
+ return app;
1072
+ },
1073
+ onGlobalRequest(callback) {
1074
+ hooks.onGlobalRequest ??= [];
1075
+ hooks.onGlobalRequest.push({
1076
+ id: nextHookId(appId),
1077
+ applyTo: "global",
1078
+ callback
1079
+ });
1080
+ return app;
1081
+ },
1082
+ onTransform(callback) {
1083
+ hooks.onTransform ??= [];
1084
+ hooks.onTransform.push({
1085
+ id: nextHookId(appId),
1086
+ applyTo: "local",
1087
+ callback
1088
+ });
1089
+ return app;
1090
+ },
1091
+ onBeforeHandle(callback) {
1092
+ hooks.onBeforeHandle ??= [];
1093
+ hooks.onBeforeHandle.push({
1094
+ id: nextHookId(appId),
1095
+ applyTo: "local",
1096
+ callback
1097
+ });
1098
+ return app;
1099
+ },
1100
+ onAfterHandle(callback) {
1101
+ hooks.onAfterHandle ??= [];
1102
+ hooks.onAfterHandle.push({
1103
+ id: nextHookId(appId),
1104
+ applyTo: "local",
1105
+ callback
1106
+ });
1107
+ return app;
1108
+ },
1109
+ onMapResponse(callback) {
1110
+ hooks.onMapResponse ??= [];
1111
+ hooks.onMapResponse.push({
1112
+ id: nextHookId(appId),
1113
+ applyTo: "local",
1114
+ callback
1115
+ });
1116
+ return app;
1117
+ },
1118
+ onGlobalError(callback) {
1119
+ hooks.onGlobalError ??= [];
1120
+ hooks.onGlobalError.push({
1121
+ id: nextHookId(appId),
1122
+ applyTo: "global",
1123
+ callback
1124
+ });
1125
+ return app;
1126
+ },
1127
+ onGlobalAfterResponse(callback) {
1128
+ hooks.onGlobalAfterResponse ??= [];
1129
+ hooks.onGlobalAfterResponse.push({
1130
+ id: nextHookId(appId),
1131
+ applyTo: "global",
1132
+ callback
1133
+ });
1134
+ return app;
1135
+ },
1136
+ get: (...args) => app.method.apply(app, [Method.Get, ...args]),
1137
+ post: (...args) => app.method.apply(app, [Method.Post, ...args]),
1138
+ put: (...args) => app.method.apply(app, [Method.Put, ...args]),
1139
+ delete: (...args) => app.method.apply(app, [Method.Delete, ...args]),
1140
+ any: (...args) => app.method.apply(app, [Method.Any, ...args]),
1141
+ method(method, path, ...args) {
1142
+ const routeDef = args.length === 2 ? args[0] : void 0;
1143
+ const handler = args[1] ?? args[0];
1144
+ const route = `${prefix}${path}`;
1145
+ const hooks = cloneHooks();
1146
+ const def = mergeAppDefaults(routeDef, options);
1147
+ addRoutesEntry(method, route, {
1148
+ def,
1149
+ route,
1150
+ hooks,
1151
+ compiledHandler: compileRouteHandler({
1152
+ schemaAdapter: options?.schemaAdapter,
1153
+ def,
1154
+ hooks,
1155
+ method,
1156
+ route,
1157
+ handler
1158
+ }),
1159
+ handler
1160
+ });
1161
+ return app;
1162
+ },
1163
+ mount(...args) {
1164
+ let path = "";
1165
+ let routeDef = {};
1166
+ let fetch;
1167
+ if (args.length === 1) fetch = args[0];
1168
+ else if (args.length === 2) {
1169
+ path = args[0];
1170
+ fetch = args[1];
1171
+ } else {
1172
+ path = args[0];
1173
+ routeDef = args[1];
1174
+ fetch = args[2];
1175
+ }
1176
+ const route = `${prefix}${path}/**`;
1177
+ const hooks = cloneHooks();
1178
+ const def = mergeAppDefaults(routeDef, options);
1179
+ const compiledHandler = compileRouteHandler({
1180
+ schemaAdapter: options?.schemaAdapter,
1181
+ hooks,
1182
+ method: "ANY",
1183
+ route,
1184
+ fetch,
1185
+ def
1186
+ });
1187
+ addRoutesEntry(Method.Any, route, {
1188
+ def,
1189
+ fetch,
1190
+ route,
1191
+ hooks,
1192
+ compiledHandler
1193
+ });
1194
+ return app;
1195
+ },
1196
+ use: (childApp) => {
1197
+ for (const [method, methodValue] of Object.entries(childApp["~zeta"].routes)) for (const [subRoute, routeValue] of Object.entries(methodValue)) {
1198
+ const route = `${prefix}${subRoute}`;
1199
+ addRoutesEntry(method, route, {
1200
+ ...routeValue,
1201
+ route
1202
+ });
1203
+ }
1204
+ for (const hookName of Object.keys(childApp["~zeta"].hooks)) for (const hook of childApp["~zeta"].hooks[hookName]) {
1205
+ if (hook.applyTo !== "global" && !childApp["~zeta"].exported) continue;
1206
+ if (hooks[hookName]) {
1207
+ if (!hooks[hookName].includes(hook)) hooks[hookName].push(hook);
1208
+ } else hooks[hookName] = [hook];
1209
+ }
1210
+ return app;
1211
+ }
1212
+ };
1213
+ return app;
1214
+ }
1215
+ /**
1216
+ * Apply app-level defaults (tags, security) to a route definition.
1217
+ * Route-level values override app-level defaults.
1218
+ */
1219
+ function mergeAppDefaults(routeDef, options) {
1220
+ if (!options?.tags?.length && !options?.security?.length) return routeDef;
1221
+ return {
1222
+ tags: options.tags,
1223
+ security: options.security,
1224
+ ...routeDef
1225
+ };
1226
+ }
1227
+ var Method = /* @__PURE__ */ function(Method) {
1228
+ Method["Get"] = "GET";
1229
+ Method["Post"] = "POST";
1230
+ Method["Put"] = "PUT";
1231
+ Method["Delete"] = "DELETE";
1232
+ Method["Any"] = "ANY";
1233
+ return Method;
1234
+ }(Method || {});
1235
+ //#endregion
1236
+ export { BadGatewayHttpError, BadRequestHttpError, ConflictHttpError, ContentTooLargeHttpError, ErrorResponse, ExpectationFailedHttpError, FailedDependencyHttpError, ForbiddenHttpError, GatewayTimeoutHttpError, GoneHttpError, HttpError, HttpStatus, HttpVersionNotSupportedHttpError, ImATeapotHttpError, InsufficientStorageHttpError, InternalServerErrorHttpError, LengthRequiredHttpError, LockedHttpError, LoopDetectedHttpError, MethodNotAllowedHttpError, MisdirectedRequestHttpError, NetworkAuthenticationRequiredHttpError, NoResponse, NotAcceptableHttpError, NotExtendedHttpError, NotFoundHttpError, NotImplementedHttpError, PaymentRequiredHttpError, PreconditionFailedHttpError, PreconditionRequiredHttpError, ProxyAuthenticationRequiredHttpError, RangeNotSatisfiableHttpError, RequestHeaderFieldsTooLargeHttpError, RequestTimeoutHttpError, ServiceUnavailableHttpError, TooEarlyHttpError, TooManyRequestsHttpError, UnauthorizedHttpError, UnavailableForLegalReasonsHttpError, UnprocessableEntityHttpError, UnsupportedMediaTypeHttpError, UpgradeRequiredHttpError, UriTooLongHttpError, VariantAlsoNegotiatesHttpError, createApp, getHttpStatusName };