@aklinker1/zeta 2.1.3 → 2.2.1

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