@raiyyan/brisk 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/AGENTS.md +535 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1745 -2
  4. package/dist/bin/brisk.d.ts +3 -0
  5. package/dist/bin/brisk.d.ts.map +1 -0
  6. package/dist/bin/brisk.js +13 -0
  7. package/dist/bin/brisk.js.map +1 -0
  8. package/dist/src/cli/agents.d.ts +7 -0
  9. package/dist/src/cli/agents.d.ts.map +1 -0
  10. package/dist/src/cli/agents.js +55 -0
  11. package/dist/src/cli/agents.js.map +1 -0
  12. package/dist/src/cli/cli.d.ts +5 -0
  13. package/dist/src/cli/cli.d.ts.map +1 -0
  14. package/dist/src/cli/cli.js +113 -0
  15. package/dist/src/cli/cli.js.map +1 -0
  16. package/dist/src/cli/client.d.ts +12 -0
  17. package/dist/src/cli/client.d.ts.map +1 -0
  18. package/dist/src/cli/client.js +76 -0
  19. package/dist/src/cli/client.js.map +1 -0
  20. package/dist/src/cli/init.d.ts +16 -0
  21. package/dist/src/cli/init.d.ts.map +1 -0
  22. package/dist/src/cli/init.js +149 -0
  23. package/dist/src/cli/init.js.map +1 -0
  24. package/dist/src/cli/names.d.ts +14 -0
  25. package/dist/src/cli/names.d.ts.map +1 -0
  26. package/dist/src/cli/names.js +25 -0
  27. package/dist/src/cli/names.js.map +1 -0
  28. package/dist/src/cli/render.d.ts +30 -0
  29. package/dist/src/cli/render.d.ts.map +1 -0
  30. package/dist/src/cli/render.js +101 -0
  31. package/dist/src/cli/render.js.map +1 -0
  32. package/dist/src/cli/system.d.ts +35 -0
  33. package/dist/src/cli/system.d.ts.map +1 -0
  34. package/dist/src/cli/system.js +81 -0
  35. package/dist/src/cli/system.js.map +1 -0
  36. package/dist/src/client/client.d.ts +64 -0
  37. package/dist/src/client/client.d.ts.map +1 -0
  38. package/dist/src/client/client.js +170 -0
  39. package/dist/src/client/client.js.map +1 -0
  40. package/dist/src/client/index.d.ts +8 -0
  41. package/dist/src/client/index.d.ts.map +1 -0
  42. package/dist/src/client/index.js +7 -0
  43. package/dist/src/client/index.js.map +1 -0
  44. package/dist/src/config/env.d.ts +28 -0
  45. package/dist/src/config/env.d.ts.map +1 -0
  46. package/dist/src/config/env.js +35 -0
  47. package/dist/src/config/env.js.map +1 -0
  48. package/dist/src/config/logger.d.ts +32 -0
  49. package/dist/src/config/logger.d.ts.map +1 -0
  50. package/dist/src/config/logger.js +31 -0
  51. package/dist/src/config/logger.js.map +1 -0
  52. package/dist/src/di/container.d.ts +194 -0
  53. package/dist/src/di/container.d.ts.map +1 -0
  54. package/dist/src/di/container.js +225 -0
  55. package/dist/src/di/container.js.map +1 -0
  56. package/dist/src/di/index.d.ts +8 -0
  57. package/dist/src/di/index.d.ts.map +1 -0
  58. package/dist/src/di/index.js +8 -0
  59. package/dist/src/di/index.js.map +1 -0
  60. package/dist/src/errors/http-errors.d.ts +295 -0
  61. package/dist/src/errors/http-errors.d.ts.map +1 -0
  62. package/dist/src/errors/http-errors.js +311 -0
  63. package/dist/src/errors/http-errors.js.map +1 -0
  64. package/dist/src/errors/index.d.ts +8 -0
  65. package/dist/src/errors/index.d.ts.map +1 -0
  66. package/dist/src/errors/index.js +8 -0
  67. package/dist/src/errors/index.js.map +1 -0
  68. package/dist/src/http/app.d.ts +229 -0
  69. package/dist/src/http/app.d.ts.map +1 -0
  70. package/dist/src/http/app.js +45 -0
  71. package/dist/src/http/app.js.map +1 -0
  72. package/dist/src/http/context.d.ts +66 -0
  73. package/dist/src/http/context.d.ts.map +1 -0
  74. package/dist/src/http/context.js +96 -0
  75. package/dist/src/http/context.js.map +1 -0
  76. package/dist/src/http/controller.d.ts +195 -0
  77. package/dist/src/http/controller.d.ts.map +1 -0
  78. package/dist/src/http/controller.js +290 -0
  79. package/dist/src/http/controller.js.map +1 -0
  80. package/dist/src/http/error-handler.d.ts +86 -0
  81. package/dist/src/http/error-handler.d.ts.map +1 -0
  82. package/dist/src/http/error-handler.js +147 -0
  83. package/dist/src/http/error-handler.js.map +1 -0
  84. package/dist/src/http/instance.d.ts +14 -0
  85. package/dist/src/http/instance.d.ts.map +1 -0
  86. package/dist/src/http/instance.js +377 -0
  87. package/dist/src/http/instance.js.map +1 -0
  88. package/dist/src/http/middleware.d.ts +141 -0
  89. package/dist/src/http/middleware.d.ts.map +1 -0
  90. package/dist/src/http/middleware.js +160 -0
  91. package/dist/src/http/middleware.js.map +1 -0
  92. package/dist/src/http/openapi.d.ts +34 -0
  93. package/dist/src/http/openapi.d.ts.map +1 -0
  94. package/dist/src/http/openapi.js +151 -0
  95. package/dist/src/http/openapi.js.map +1 -0
  96. package/dist/src/http/path-params.d.ts +24 -0
  97. package/dist/src/http/path-params.d.ts.map +1 -0
  98. package/dist/src/http/path-params.js +2 -0
  99. package/dist/src/http/path-params.js.map +1 -0
  100. package/dist/src/http/routes.d.ts +141 -0
  101. package/dist/src/http/routes.d.ts.map +1 -0
  102. package/dist/src/http/routes.js +2 -0
  103. package/dist/src/http/routes.js.map +1 -0
  104. package/dist/src/http/server.d.ts +23 -0
  105. package/dist/src/http/server.d.ts.map +1 -0
  106. package/dist/src/http/server.js +22 -0
  107. package/dist/src/http/server.js.map +1 -0
  108. package/dist/src/http/validation.d.ts +16 -0
  109. package/dist/src/http/validation.d.ts.map +1 -0
  110. package/dist/src/http/validation.js +51 -0
  111. package/dist/src/http/validation.js.map +1 -0
  112. package/dist/src/index.d.ts +22 -0
  113. package/dist/src/index.d.ts.map +1 -0
  114. package/dist/src/index.js +19 -0
  115. package/dist/src/index.js.map +1 -0
  116. package/dist/src/testing/index.d.ts +7 -0
  117. package/dist/src/testing/index.d.ts.map +1 -0
  118. package/dist/src/testing/index.js +7 -0
  119. package/dist/src/testing/index.js.map +1 -0
  120. package/dist/src/testing/test-client.d.ts +67 -0
  121. package/dist/src/testing/test-client.d.ts.map +1 -0
  122. package/dist/src/testing/test-client.js +78 -0
  123. package/dist/src/testing/test-client.js.map +1 -0
  124. package/package.json +89 -3
  125. package/starters/minimal/.env.example +3 -0
  126. package/starters/minimal/.oxfmtrc.json +5 -0
  127. package/starters/minimal/.oxlintrc.json +14 -0
  128. package/starters/minimal/AGENTS.md +23 -0
  129. package/starters/minimal/CLAUDE.md +2 -0
  130. package/starters/minimal/README.md +53 -0
  131. package/starters/minimal/_gitignore +3 -0
  132. package/starters/minimal/package.json +29 -0
  133. package/starters/minimal/src/app.ts +14 -0
  134. package/starters/minimal/src/env.ts +7 -0
  135. package/starters/minimal/src/features/index.ts +8 -0
  136. package/starters/minimal/src/features/notes/notes.controller.ts +38 -0
  137. package/starters/minimal/src/features/notes/notes.repository.ts +36 -0
  138. package/starters/minimal/src/features/notes/notes.schema.ts +24 -0
  139. package/starters/minimal/src/features/notes/notes.service.ts +33 -0
  140. package/starters/minimal/src/main.ts +4 -0
  141. package/starters/minimal/src/schemas.ts +26 -0
  142. package/starters/minimal/templates/feature/src/features/index.ts.controllers.insert +1 -0
  143. package/starters/minimal/templates/feature/src/features/index.ts.imports.insert +1 -0
  144. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +38 -0
  145. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +36 -0
  146. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
  147. package/starters/minimal/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
  148. package/starters/minimal/templates/feature/test/{{kebab}}.service.test.ts +20 -0
  149. package/starters/minimal/templates/feature/test/{{kebab}}.test.ts +35 -0
  150. package/starters/minimal/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
  151. package/starters/minimal/test/notes.service.test.ts +20 -0
  152. package/starters/minimal/test/notes.test.ts +35 -0
  153. package/starters/minimal/tsconfig.json +17 -0
  154. package/starters/minimal/vitest.config.ts +9 -0
  155. package/starters/sqlite-auth/.dockerignore +8 -0
  156. package/starters/sqlite-auth/.env.example +9 -0
  157. package/starters/sqlite-auth/.oxfmtrc.json +5 -0
  158. package/starters/sqlite-auth/.oxlintrc.json +14 -0
  159. package/starters/sqlite-auth/AGENTS.md +23 -0
  160. package/starters/sqlite-auth/CLAUDE.md +2 -0
  161. package/starters/sqlite-auth/Dockerfile +23 -0
  162. package/starters/sqlite-auth/README.md +93 -0
  163. package/starters/sqlite-auth/_gitignore +5 -0
  164. package/starters/sqlite-auth/compose.yaml +14 -0
  165. package/starters/sqlite-auth/package.json +35 -0
  166. package/starters/sqlite-auth/public/.gitkeep +0 -0
  167. package/starters/sqlite-auth/src/app.ts +39 -0
  168. package/starters/sqlite-auth/src/auth/tokens.ts +41 -0
  169. package/starters/sqlite-auth/src/database/clock.ts +4 -0
  170. package/starters/sqlite-auth/src/database/database.ts +29 -0
  171. package/starters/sqlite-auth/src/database/errors.ts +11 -0
  172. package/starters/sqlite-auth/src/database/migrations.ts +29 -0
  173. package/starters/sqlite-auth/src/env.ts +17 -0
  174. package/starters/sqlite-auth/src/features/auth/auth.controller.ts +28 -0
  175. package/starters/sqlite-auth/src/features/index.ts +12 -0
  176. package/starters/sqlite-auth/src/features/notes/notes.controller.ts +39 -0
  177. package/starters/sqlite-auth/src/features/notes/notes.repository.ts +47 -0
  178. package/starters/sqlite-auth/src/features/notes/notes.schema.ts +24 -0
  179. package/starters/sqlite-auth/src/features/notes/notes.service.ts +33 -0
  180. package/starters/sqlite-auth/src/features/users/admin-seed.ts +21 -0
  181. package/starters/sqlite-auth/src/features/users/users.controller.ts +42 -0
  182. package/starters/sqlite-auth/src/features/users/users.errors.ts +13 -0
  183. package/starters/sqlite-auth/src/features/users/users.repository.ts +77 -0
  184. package/starters/sqlite-auth/src/features/users/users.schema.ts +35 -0
  185. package/starters/sqlite-auth/src/features/users/users.service.ts +80 -0
  186. package/starters/sqlite-auth/src/main.ts +4 -0
  187. package/starters/sqlite-auth/src/middlewares/authenticate.ts +29 -0
  188. package/starters/sqlite-auth/src/schemas.ts +26 -0
  189. package/starters/sqlite-auth/templates/feature/src/database/migrations.ts.migrations.insert +5 -0
  190. package/starters/sqlite-auth/templates/feature/src/features/index.ts.controllers.insert +1 -0
  191. package/starters/sqlite-auth/templates/feature/src/features/index.ts.imports.insert +1 -0
  192. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.controller.ts +39 -0
  193. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.repository.ts +47 -0
  194. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.schema.ts +24 -0
  195. package/starters/sqlite-auth/templates/feature/src/features/{{kebab}}/{{kebab}}.service.ts +33 -0
  196. package/starters/sqlite-auth/templates/feature/test/{{kebab}}.service.test.ts +20 -0
  197. package/starters/sqlite-auth/templates/feature/test/{{kebab}}.test.ts +41 -0
  198. package/starters/sqlite-auth/templates/middleware/src/middlewares/{{kebab}}.ts +12 -0
  199. package/starters/sqlite-auth/test/auth.test.ts +18 -0
  200. package/starters/sqlite-auth/test/helpers.ts +13 -0
  201. package/starters/sqlite-auth/test/notes.service.test.ts +20 -0
  202. package/starters/sqlite-auth/test/notes.test.ts +41 -0
  203. package/starters/sqlite-auth/test/users.service.test.ts +25 -0
  204. package/starters/sqlite-auth/test/users.test.ts +164 -0
  205. package/starters/sqlite-auth/tsconfig.json +17 -0
  206. package/starters/sqlite-auth/vitest.config.ts +15 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/http/controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,290 @@
1
+ import { Readable } from "node:stream";
2
+ import { pipeline } from "node:stream/promises";
3
+ import { Router } from "express";
4
+ import { getContext, HandlerContext } from "./context.js";
5
+ import { MethodNotAllowedError, UnsupportedMediaTypeError } from "../errors/http-errors.js";
6
+ import { applyMiddlewares, securityOf, } from "./middleware.js";
7
+ import { parseInput, Pending, serializeOutput, settle } from "./validation.js";
8
+ /**
9
+ * Declares a feature's HTTP routes. `setup` runs once per app instance, inside its container, so it can
10
+ * `inject()` services. It declares routes and returns them by name; the names form the typed client, so
11
+ * `usersController` mounted as `users` gives `api.users.get(...)`.
12
+ *
13
+ * A handler's return value is the response: nothing sends 204, a `Readable` is streamed, a `Buffer` is sent
14
+ * as bytes, and anything else is JSON, parsed through `response` when given. Throw an error class to fail;
15
+ * never call `next()`.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * export const usersController = defineController({ prefix: "/users", use: [authenticate] }, (route) => {
20
+ * const users = inject(UsersService);
21
+ * return {
22
+ * me: route.get("/me", ({ user }) => user),
23
+ * get: route.get("/:id", { params: UserIdParams, response: UserResponse }, ({ params }) => users.get(params.id)),
24
+ * create: route.post("/", { body: CreateUserBody, response: UserResponse }, ({ body }) => users.create(body)),
25
+ * };
26
+ * });
27
+ * ```
28
+ */
29
+ export function defineController(options, setup) {
30
+ return {
31
+ prefix: options.prefix,
32
+ providers: options.providers ?? [],
33
+ mount: (target) => mount(target, options.use ?? [], (builder) =>
34
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the loose builder implements every typed overload at runtime
35
+ setup(builder)),
36
+ };
37
+ }
38
+ /**
39
+ * Registers a controller's routes inside the container, with full paths on the app's one router: no nested
40
+ * router per controller, so a request pays no prefix trimming or parameter merging on its way to a route.
41
+ */
42
+ function mount({ container, router, basePath, parseBody }, use, register) {
43
+ const declared = [];
44
+ const returned = container.run(() => register(createBuilder({ router, container, parseBody, declared, prefix: basePath, use })));
45
+ const named = new Map();
46
+ const manifest = returned === undefined ? undefined : toManifest(returned, named, basePath, "");
47
+ const missing = manifest ? declared.find((ref) => !named.has(ref)) : undefined;
48
+ if (missing) {
49
+ throw new TypeError(`Controller ${basePath} declares ${missing.method.toUpperCase()} ${missing.path} but does not return it: add it to the object setup returns`);
50
+ }
51
+ const endpoints = declared.map((ref) => ({
52
+ method: ref.method,
53
+ path: ref.path,
54
+ name: named.get(ref),
55
+ schemas: ref.schemas,
56
+ status: ref.status,
57
+ security: ref.security,
58
+ }));
59
+ return { endpoints, manifest };
60
+ }
61
+ /** A route as `route.get(...)` returns it: method and full path for the manifest, schemas for documentation. */
62
+ class RouteRef {
63
+ method;
64
+ path;
65
+ schemas;
66
+ status;
67
+ security;
68
+ constructor(method, path, options, middlewares) {
69
+ this.method = method;
70
+ this.path = path;
71
+ this.status = options.status;
72
+ this.security = securityOf(middlewares);
73
+ const schemas = {};
74
+ for (const key of ["params", "query", "body", "headers", "response"]) {
75
+ const schema = options[key];
76
+ if (schema)
77
+ schemas[key] = schema;
78
+ }
79
+ this.schemas = schemas;
80
+ }
81
+ }
82
+ /** Turns the object a setup returned into a manifest, recording every route's dotted name. */
83
+ function toManifest(value, named, where, scope) {
84
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
85
+ throw new TypeError(`Controller ${where} must return an object of named routes, or nothing`);
86
+ }
87
+ const manifest = {};
88
+ for (const [name, entry] of Object.entries(value)) {
89
+ const dotted = scope === "" ? name : `${scope}.${name}`;
90
+ if (entry instanceof RouteRef) {
91
+ named.set(entry, dotted);
92
+ manifest[name] = [entry.method.toUpperCase(), entry.path];
93
+ }
94
+ else if (isController(entry)) {
95
+ throw new TypeError(`"${dotted}" in controller ${where} is a controller, not a route: add it to defineApp({ controllers }) instead`);
96
+ }
97
+ else {
98
+ manifest[name] = toManifest(entry, named, `${where} (${dotted})`, dotted);
99
+ }
100
+ }
101
+ return manifest;
102
+ }
103
+ /**
104
+ * Answers requests no controller handled on a known path: `OPTIONS` gets 204, other methods 405, both with an
105
+ * `Allow` header that lists what every controller accepts there.
106
+ *
107
+ * The app mounts it twice. Before the controllers, for `OPTIONS` only, because an Express router would
108
+ * otherwise answer `OPTIONS` itself with just its own methods. After them, where only unmatched requests
109
+ * arrive. A request that matches a route never runs it.
110
+ */
111
+ export function methodGuard(routes) {
112
+ const router = Router();
113
+ const allowedByRequest = new WeakMap();
114
+ const allowed = new Map();
115
+ for (const { method, path } of routes) {
116
+ const methods = allowed.get(path) ?? new Set(["OPTIONS"]);
117
+ methods.add(method.toUpperCase());
118
+ if (method === "get")
119
+ methods.add("HEAD");
120
+ allowed.set(path, methods);
121
+ }
122
+ for (const [path, methods] of allowed) {
123
+ router.all(path, (req, _res, next) => {
124
+ const seen = allowedByRequest.get(req);
125
+ if (seen)
126
+ for (const method of methods)
127
+ seen.add(method);
128
+ else
129
+ allowedByRequest.set(req, new Set(methods));
130
+ next();
131
+ });
132
+ }
133
+ router.use((req, res, next) => {
134
+ const methods = allowedByRequest.get(req);
135
+ if (!methods) {
136
+ next();
137
+ return;
138
+ }
139
+ const allow = [...methods].toSorted();
140
+ if (req.method !== "OPTIONS")
141
+ throw new MethodNotAllowedError(allow);
142
+ res.set("allow", allow.join(", ")).status(204).end();
143
+ });
144
+ return router;
145
+ }
146
+ function createBuilder(state) {
147
+ const route = (method) => (path, optionsOrHandler, maybeHandler) => {
148
+ const [options, handler] = isFunction(optionsOrHandler)
149
+ ? [{}, optionsOrHandler]
150
+ : [optionsOrHandler, maybeHandler];
151
+ if (!isOptions(options) || !isFunction(handler)) {
152
+ throw new TypeError(`Invalid route ${method.toUpperCase()} ${path}: use (path, handler) or (path, options, handler)`);
153
+ }
154
+ if (options.status !== undefined && !isSuccessStatus(options.status)) {
155
+ throw new TypeError(`Invalid status ${String(options.status)} on ${method.toUpperCase()} ${path}: use a 2xx or 3xx status; throw an error class for failures`);
156
+ }
157
+ const fullPath = joinPath(state.prefix, path);
158
+ const middlewares = [...state.use, ...(options.use ?? [])];
159
+ const ref = new RouteRef(method, fullPath, options, middlewares);
160
+ state.declared.push(ref);
161
+ const run = (req, res) => state.container.run(handle, req, res, method, middlewares, options, handler);
162
+ // GET requests rarely carry a body, so they skip the parser unless the route declares one.
163
+ if (method === "get" && !options.body)
164
+ state.router.get(fullPath, run);
165
+ else
166
+ state.router[method](fullPath, state.parseBody, run);
167
+ return ref;
168
+ };
169
+ return {
170
+ get: route("get"),
171
+ post: route("post"),
172
+ put: route("put"),
173
+ patch: route("patch"),
174
+ delete: route("delete"),
175
+ group(path, optionsOrSetup, maybeSetup) {
176
+ const [options, setup] = isFunction(optionsOrSetup)
177
+ ? [{}, optionsOrSetup]
178
+ : [optionsOrSetup, maybeSetup];
179
+ if (!isOptions(options) || !isFunction(setup)) {
180
+ throw new TypeError(`Invalid group ${path}: use (path, setup) or (path, options, setup)`);
181
+ }
182
+ return setup(createBuilder({
183
+ ...state,
184
+ prefix: joinPath(state.prefix, path),
185
+ use: [...state.use, ...(options.use ?? [])],
186
+ }));
187
+ },
188
+ };
189
+ }
190
+ /**
191
+ * One request: middlewares, input validation, handler, then the response the handler's result calls for.
192
+ * Awaits only what is really a promise, so synchronous middlewares and handlers stay synchronous.
193
+ */
194
+ async function handle(req, res, method, middlewares, options, handler) {
195
+ const base = getContext(req);
196
+ const ctx = new HandlerContext(base);
197
+ if (middlewares.length > 0) {
198
+ const pending = applyMiddlewares(base, ctx, middlewares);
199
+ if (pending)
200
+ await pending;
201
+ if (res.headersSent)
202
+ return;
203
+ }
204
+ if (options.body && req.body === undefined && hasBody(req) && req.get("content-type") !== undefined) {
205
+ throw new UnsupportedMediaTypeError(`No parser accepted a ${req.get("content-type")} body`);
206
+ }
207
+ const parsing = parseInto(ctx, req, options);
208
+ if (parsing)
209
+ await parsing;
210
+ const returned = handler(ctx);
211
+ const result = returned instanceof Promise ? await returned : returned;
212
+ if (res.headersSent)
213
+ return;
214
+ const chosen = options.status ?? (res.statusCode === 200 ? undefined : res.statusCode);
215
+ if (result === undefined) {
216
+ res.status(chosen ?? 204).end();
217
+ return;
218
+ }
219
+ const status = chosen ?? (method === "post" ? 201 : 200);
220
+ if (result instanceof Readable) {
221
+ res.status(status);
222
+ await stream(result, res);
223
+ return;
224
+ }
225
+ if (result instanceof Uint8Array) {
226
+ res.status(status).send(Buffer.from(result.buffer, result.byteOffset, result.byteLength));
227
+ return;
228
+ }
229
+ const output = serializeOutput(options.response, result);
230
+ res.status(status).json(output instanceof Promise ? await output : output);
231
+ }
232
+ /** Whether the request carries a body at all, as body parsers decide it; a bodiless POST is not a 415. */
233
+ function hasBody(req) {
234
+ return req.get("transfer-encoding") !== undefined || req.get("content-length") !== undefined;
235
+ }
236
+ /** Pipes with backpressure. A client that disconnects mid-stream is normal, not a server error. */
237
+ async function stream(source, res) {
238
+ try {
239
+ await pipeline(source, res);
240
+ }
241
+ catch (error) {
242
+ if (!(error instanceof Error && "code" in error && error.code === "ERR_STREAM_PREMATURE_CLOSE"))
243
+ throw error;
244
+ }
245
+ }
246
+ /**
247
+ * Validates every input location onto the handler's context. Synchronous, which is the fast path; only when a
248
+ * schema has async refinements does validation switch to `safeParseAsync` and return a promise.
249
+ */
250
+ function parseInto(ctx, req, options) {
251
+ const params = parseInput(options.params, req.params, "params");
252
+ const query = parseInput(options.query, req.query, "query");
253
+ const body = parseInput(options.body, req.body, "body");
254
+ const headers = parseInput(options.headers, req.headers, "headers");
255
+ if (params instanceof Pending ||
256
+ query instanceof Pending ||
257
+ body instanceof Pending ||
258
+ headers instanceof Pending) {
259
+ return settleInto(ctx, params, query, body, headers);
260
+ }
261
+ ctx.params = params;
262
+ ctx.query = query;
263
+ ctx.body = body;
264
+ ctx.headers = headers;
265
+ return undefined;
266
+ }
267
+ async function settleInto(ctx, ...inputs) {
268
+ const [params, query, body, headers] = await Promise.all(inputs.map(settle));
269
+ ctx.params = params;
270
+ ctx.query = query;
271
+ ctx.body = body;
272
+ ctx.headers = headers;
273
+ }
274
+ function isController(value) {
275
+ return typeof value === "object" && value !== null && "mount" in value && typeof value.mount === "function";
276
+ }
277
+ function isSuccessStatus(status) {
278
+ return Number.isInteger(status) && status >= 200 && status <= 399;
279
+ }
280
+ function isFunction(value) {
281
+ return typeof value === "function";
282
+ }
283
+ function isOptions(value) {
284
+ return typeof value === "object" && value !== null;
285
+ }
286
+ /** Joins URL segments into one normalized path: `("/api", "/users/", ":id")` gives `/api/users/:id`. */
287
+ export function joinPath(...parts) {
288
+ return `/${parts.join("/").split("/").filter(Boolean).join("/")}`;
289
+ }
290
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/http/controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import type { ErrorRequestHandler } from "express";
2
+ import type { Logger } from "../config/logger.ts";
3
+ import { type RequestContext } from "./context.ts";
4
+ import { HttpError } from "../errors/http-errors.ts";
5
+ /**
6
+ * The app's error translation, injectable: turns any error into the status, code, message and details a route
7
+ * would answer with, `errors.mappers` applied and internal messages hidden. For code outside brisk's routes,
8
+ * such as GraphQL's `maskError` or WebSocket close codes. Inside a request `inject()` it directly; in a
9
+ * callback a library fires on its own, resolve it in a class field.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * maskError: (error) => {
14
+ * const { status, code, message } = inject(ErrorTranslator)(unwrap(error));
15
+ * return new GraphQLError(message, { extensions: { code, status } });
16
+ * },
17
+ * ```
18
+ */
19
+ export declare const ErrorTranslator: import("../di/container.ts").InjectionToken<(error: unknown) => {
20
+ status: number;
21
+ code: string;
22
+ message: string;
23
+ details: unknown;
24
+ }>;
25
+ /**
26
+ * Turns an error from a library (a database, an SDK) into an HTTP error, or returns `undefined` to leave it.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const uniqueViolation: ErrorMapper = (error) =>
31
+ * error instanceof DatabaseError && error.code === "23505" ? new ConflictError("Already exists") : undefined;
32
+ *
33
+ * defineApp({ controllers, errors: { mappers: [uniqueViolation] } });
34
+ * ```
35
+ */
36
+ export type ErrorMapper = (error: unknown) => HttpError | undefined;
37
+ /**
38
+ * Builds the body of an error response. The default builds an {@link ErrorResponse}.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const problemJson: ErrorFormatter = (error, ctx) => ({
43
+ * type: `https://errors.example.com/${error.code}`,
44
+ * title: error.message,
45
+ * status: error.status,
46
+ * instance: ctx.req.originalUrl,
47
+ * });
48
+ *
49
+ * defineApp({ controllers, errors: { format: problemJson } });
50
+ * ```
51
+ */
52
+ export type ErrorFormatter = (error: HttpError, ctx: RequestContext) => unknown;
53
+ export interface ErrorHandlingOptions {
54
+ mappers: readonly ErrorMapper[];
55
+ format: ErrorFormatter;
56
+ exposeInternalErrors: boolean;
57
+ onError: ((error: unknown, ctx: RequestContext) => void) | undefined;
58
+ }
59
+ /**
60
+ * The default error body: `{ error: { code, message, details, requestId } }`. Call it from your own formatter
61
+ * to add fields to the default shape.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const withDocs: ErrorFormatter = (error, ctx) => ({
66
+ * ...defaultErrorFormatter(error, ctx),
67
+ * docs: `https://docs.example.com/errors/${error.code}`,
68
+ * });
69
+ * ```
70
+ */
71
+ export declare const defaultErrorFormatter: ErrorFormatter;
72
+ /**
73
+ * Turns every error into a response: classify it, log it by severity, report it to `onError`, then send the
74
+ * status, headers and body. A mapper, formatter or `onError` hook that throws is logged, never fatal.
75
+ *
76
+ * When the response has already started (a handler wrote part of a stream, then threw), the connection is
77
+ * destroyed instead: ending it normally would hand the client a truncated body that looks complete.
78
+ */
79
+ export declare function errorHandler(options: ErrorHandlingOptions): ErrorRequestHandler;
80
+ /**
81
+ * Classifies any error as the HTTP error a client should see: an HttpError as it is, then the mappers, a
82
+ * ZodError as 400, body-parser and http-errors failures by their status, and anything else as a 500 whose
83
+ * message is hidden unless `exposeInternalErrors` is on.
84
+ */
85
+ export declare function toHttpError(error: unknown, options: Omit<ErrorHandlingOptions, "format" | "onError">, log: Logger): HttpError;
86
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/http/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAEL,SAAS,EAMV,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe,sDAClB,OAAO,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAGvF,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,GAAG,SAAS,CAAC;AAEpE;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC;AAEhF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACtE;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAElC,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAsB/E;AAWD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,SAAS,CAAC,EACzD,GAAG,EAAE,MAAM,GACV,SAAS,CAgBX"}
@@ -0,0 +1,147 @@
1
+ import { STATUS_CODES } from "node:http";
2
+ import { z } from "zod";
3
+ import { defineToken } from "../di/container.js";
4
+ import { getContext } from "./context.js";
5
+ import { BadRequestError, HttpError, InternalServerError, PayloadTooLargeError, UnsupportedMediaTypeError, ValidationError, } from "../errors/http-errors.js";
6
+ /**
7
+ * The app's error translation, injectable: turns any error into the status, code, message and details a route
8
+ * would answer with, `errors.mappers` applied and internal messages hidden. For code outside brisk's routes,
9
+ * such as GraphQL's `maskError` or WebSocket close codes. Inside a request `inject()` it directly; in a
10
+ * callback a library fires on its own, resolve it in a class field.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * maskError: (error) => {
15
+ * const { status, code, message } = inject(ErrorTranslator)(unwrap(error));
16
+ * return new GraphQLError(message, { extensions: { code, status } });
17
+ * },
18
+ * ```
19
+ */
20
+ export const ErrorTranslator = /* @__PURE__ */ defineToken("ErrorTranslator", () => {
21
+ throw new Error("ErrorTranslator is provided by an app made with defineApp()");
22
+ });
23
+ /**
24
+ * The default error body: `{ error: { code, message, details, requestId } }`. Call it from your own formatter
25
+ * to add fields to the default shape.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const withDocs: ErrorFormatter = (error, ctx) => ({
30
+ * ...defaultErrorFormatter(error, ctx),
31
+ * docs: `https://docs.example.com/errors/${error.code}`,
32
+ * });
33
+ * ```
34
+ */
35
+ export const defaultErrorFormatter = (error, ctx) => ({
36
+ error: { code: error.code, message: error.message, details: error.details, requestId: ctx.requestId },
37
+ });
38
+ /**
39
+ * Turns every error into a response: classify it, log it by severity, report it to `onError`, then send the
40
+ * status, headers and body. A mapper, formatter or `onError` hook that throws is logged, never fatal.
41
+ *
42
+ * When the response has already started (a handler wrote part of a stream, then threw), the connection is
43
+ * destroyed instead: ending it normally would hand the client a truncated body that looks complete.
44
+ */
45
+ export function errorHandler(options) {
46
+ return (error, req, res, _next) => {
47
+ const ctx = getContext(req);
48
+ const http = toHttpError(error, options, ctx.log);
49
+ if (http.status >= 500)
50
+ ctx.log.error({ err: error, code: http.code }, http.message);
51
+ else
52
+ ctx.log.debug({ code: http.code, status: http.status }, http.message);
53
+ try {
54
+ options.onError?.(error, ctx);
55
+ }
56
+ catch (hookError) {
57
+ ctx.log.error({ err: hookError }, "onError hook failed");
58
+ }
59
+ if (res.headersSent) {
60
+ if (!res.writableEnded)
61
+ res.destroy();
62
+ return;
63
+ }
64
+ res
65
+ .status(http.status)
66
+ .set(http.headers)
67
+ .json(formatBody(http, ctx, options.format));
68
+ };
69
+ }
70
+ function formatBody(error, ctx, format) {
71
+ try {
72
+ return format(error, ctx);
73
+ }
74
+ catch (formatError) {
75
+ ctx.log.error({ err: formatError }, "formatError failed, sending the default error body");
76
+ return defaultErrorFormatter(error, ctx);
77
+ }
78
+ }
79
+ /**
80
+ * Classifies any error as the HTTP error a client should see: an HttpError as it is, then the mappers, a
81
+ * ZodError as 400, body-parser and http-errors failures by their status, and anything else as a 500 whose
82
+ * message is hidden unless `exposeInternalErrors` is on.
83
+ */
84
+ export function toHttpError(error, options, log) {
85
+ if (error instanceof HttpError)
86
+ return error;
87
+ for (const mapper of options.mappers) {
88
+ try {
89
+ const mapped = mapper(error);
90
+ if (mapped)
91
+ return mapped;
92
+ }
93
+ catch (mapperError) {
94
+ log.error({ err: mapperError }, "error mapper failed");
95
+ }
96
+ }
97
+ if (error instanceof z.ZodError)
98
+ return ValidationError.fromZod(error, "input");
99
+ const parserError = fromBodyParser(error) ?? fromHttpErrors(error);
100
+ if (parserError)
101
+ return parserError;
102
+ const message = options.exposeInternalErrors && error instanceof Error ? error.message : "Internal server error";
103
+ return new InternalServerError(message, { cause: error });
104
+ }
105
+ /** Errors raised while reading the request body, rewritten so parser internals never reach the client. */
106
+ function fromBodyParser(error) {
107
+ if (!(error instanceof Error) || !("type" in error) || typeof error.type !== "string")
108
+ return undefined;
109
+ switch (error.type) {
110
+ case "entity.parse.failed":
111
+ return new BadRequestError("Body must be a valid JSON object or array", {
112
+ code: "INVALID_JSON",
113
+ cause: error,
114
+ });
115
+ case "entity.too.large":
116
+ return new PayloadTooLargeError("Request body is too large", { cause: error });
117
+ case "encoding.unsupported":
118
+ case "charset.unsupported":
119
+ return new UnsupportedMediaTypeError(error.message, { cause: error });
120
+ default:
121
+ return undefined;
122
+ }
123
+ }
124
+ /**
125
+ * Errors from Express middleware that follow the `http-errors` convention: a numeric `status` and a boolean
126
+ * `expose` (body parsers, `express.static`, many community packages). The status is kept, and the message is
127
+ * sent only when `expose` is true.
128
+ *
129
+ * Errors without `expose` are not trusted: an upstream SDK's `{ status: 404 }` means a call to another
130
+ * service failed, which is this server's 500, not the client's 404. The one exception is Express's own
131
+ * `URIError` for an undecodable path parameter, which it marks 400.
132
+ */
133
+ function fromHttpErrors(error) {
134
+ if (error instanceof URIError && "status" in error && error.status === 400) {
135
+ return new BadRequestError("Malformed percent-encoding in the URL", {
136
+ code: "INVALID_URL",
137
+ cause: error,
138
+ });
139
+ }
140
+ if (!(error instanceof Error) || !("status" in error) || !("expose" in error))
141
+ return undefined;
142
+ const { status, expose } = error;
143
+ if (typeof status !== "number" || typeof expose !== "boolean" || status < 400 || status > 599)
144
+ return undefined;
145
+ return new HttpError(status, expose ? error.message : (STATUS_CODES[status] ?? "Error"), { cause: error });
146
+ }
147
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/http/error-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type ProviderEntry } from "../di/container.ts";
2
+ import type { AppInstance, AppOptions, ControllerMap, ListenOptions, StartOptions } from "./app.ts";
3
+ /** An instance with the controls only `defineApp` uses: each instance listens or starts once. */
4
+ export interface Runner<C extends ControllerMap> extends AppInstance<C> {
5
+ listen(port: number, options: Omit<ListenOptions, "providers">): Promise<void>;
6
+ start(options: Omit<StartOptions, "providers">): Promise<void>;
7
+ }
8
+ /**
9
+ * Builds one instance of an app: security headers, request ids and logging, health check and OpenAPI routes,
10
+ * the app's `use`, controllers (each parsing its own JSON bodies), mounts, 404 and error handling, and the container that runs every
11
+ * lifecycle hook. `overrides` come after the app's own providers, so they win.
12
+ */
13
+ export declare function createInstance<C extends ControllerMap>(options: AppOptions<C>, overrides?: readonly ProviderEntry[]): Runner<C>;
14
+ //# sourceMappingURL=instance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../src/http/instance.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE9F,OAAO,KAAK,EAEV,WAAW,EACX,UAAU,EACV,aAAa,EAEb,aAAa,EACb,YAAY,EACb,MAAM,UAAU,CAAC;AAoBlB,iGAAiG;AACjG,MAAM,WAAW,MAAM,CAAC,CAAC,SAAS,aAAa,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,aAAa,EACpD,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EACtB,SAAS,GAAE,SAAS,aAAa,EAAO,GACvC,MAAM,CAAC,CAAC,CAAC,CAoPX"}