@buenojs/bueno 0.8.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 (120) hide show
  1. package/.env.example +109 -0
  2. package/.github/workflows/ci.yml +31 -0
  3. package/LICENSE +21 -0
  4. package/README.md +892 -0
  5. package/architecture.md +652 -0
  6. package/bun.lock +70 -0
  7. package/dist/cli/index.js +3233 -0
  8. package/dist/index.js +9014 -0
  9. package/package.json +77 -0
  10. package/src/cache/index.ts +795 -0
  11. package/src/cli/ARCHITECTURE.md +837 -0
  12. package/src/cli/bin.ts +10 -0
  13. package/src/cli/commands/build.ts +425 -0
  14. package/src/cli/commands/dev.ts +248 -0
  15. package/src/cli/commands/generate.ts +541 -0
  16. package/src/cli/commands/help.ts +55 -0
  17. package/src/cli/commands/index.ts +112 -0
  18. package/src/cli/commands/migration.ts +355 -0
  19. package/src/cli/commands/new.ts +804 -0
  20. package/src/cli/commands/start.ts +208 -0
  21. package/src/cli/core/args.ts +283 -0
  22. package/src/cli/core/console.ts +349 -0
  23. package/src/cli/core/index.ts +60 -0
  24. package/src/cli/core/prompt.ts +424 -0
  25. package/src/cli/core/spinner.ts +265 -0
  26. package/src/cli/index.ts +135 -0
  27. package/src/cli/templates/deploy.ts +295 -0
  28. package/src/cli/templates/docker.ts +307 -0
  29. package/src/cli/templates/index.ts +24 -0
  30. package/src/cli/utils/fs.ts +428 -0
  31. package/src/cli/utils/index.ts +8 -0
  32. package/src/cli/utils/strings.ts +197 -0
  33. package/src/config/env.ts +408 -0
  34. package/src/config/index.ts +506 -0
  35. package/src/config/loader.ts +329 -0
  36. package/src/config/merge.ts +285 -0
  37. package/src/config/types.ts +320 -0
  38. package/src/config/validation.ts +441 -0
  39. package/src/container/forward-ref.ts +143 -0
  40. package/src/container/index.ts +386 -0
  41. package/src/context/index.ts +360 -0
  42. package/src/database/index.ts +1142 -0
  43. package/src/database/migrations/index.ts +371 -0
  44. package/src/database/schema/index.ts +619 -0
  45. package/src/frontend/api-routes.ts +640 -0
  46. package/src/frontend/bundler.ts +643 -0
  47. package/src/frontend/console-client.ts +419 -0
  48. package/src/frontend/console-stream.ts +587 -0
  49. package/src/frontend/dev-server.ts +846 -0
  50. package/src/frontend/file-router.ts +611 -0
  51. package/src/frontend/frameworks/index.ts +106 -0
  52. package/src/frontend/frameworks/react.ts +85 -0
  53. package/src/frontend/frameworks/solid.ts +104 -0
  54. package/src/frontend/frameworks/svelte.ts +110 -0
  55. package/src/frontend/frameworks/vue.ts +92 -0
  56. package/src/frontend/hmr-client.ts +663 -0
  57. package/src/frontend/hmr.ts +728 -0
  58. package/src/frontend/index.ts +342 -0
  59. package/src/frontend/islands.ts +552 -0
  60. package/src/frontend/isr.ts +555 -0
  61. package/src/frontend/layout.ts +475 -0
  62. package/src/frontend/ssr/react.ts +446 -0
  63. package/src/frontend/ssr/solid.ts +523 -0
  64. package/src/frontend/ssr/svelte.ts +546 -0
  65. package/src/frontend/ssr/vue.ts +504 -0
  66. package/src/frontend/ssr.ts +699 -0
  67. package/src/frontend/types.ts +2274 -0
  68. package/src/health/index.ts +604 -0
  69. package/src/index.ts +410 -0
  70. package/src/lock/index.ts +587 -0
  71. package/src/logger/index.ts +444 -0
  72. package/src/logger/transports/index.ts +969 -0
  73. package/src/metrics/index.ts +494 -0
  74. package/src/middleware/built-in.ts +360 -0
  75. package/src/middleware/index.ts +94 -0
  76. package/src/modules/filters.ts +458 -0
  77. package/src/modules/guards.ts +405 -0
  78. package/src/modules/index.ts +1256 -0
  79. package/src/modules/interceptors.ts +574 -0
  80. package/src/modules/lazy.ts +418 -0
  81. package/src/modules/lifecycle.ts +478 -0
  82. package/src/modules/metadata.ts +90 -0
  83. package/src/modules/pipes.ts +626 -0
  84. package/src/router/index.ts +339 -0
  85. package/src/router/linear.ts +371 -0
  86. package/src/router/regex.ts +292 -0
  87. package/src/router/tree.ts +562 -0
  88. package/src/rpc/index.ts +1263 -0
  89. package/src/security/index.ts +436 -0
  90. package/src/ssg/index.ts +631 -0
  91. package/src/storage/index.ts +456 -0
  92. package/src/telemetry/index.ts +1097 -0
  93. package/src/testing/index.ts +1586 -0
  94. package/src/types/index.ts +236 -0
  95. package/src/types/optional-deps.d.ts +219 -0
  96. package/src/validation/index.ts +276 -0
  97. package/src/websocket/index.ts +1004 -0
  98. package/tests/integration/cli.test.ts +1016 -0
  99. package/tests/integration/fullstack.test.ts +234 -0
  100. package/tests/unit/cache.test.ts +174 -0
  101. package/tests/unit/cli-commands.test.ts +892 -0
  102. package/tests/unit/cli.test.ts +1258 -0
  103. package/tests/unit/container.test.ts +279 -0
  104. package/tests/unit/context.test.ts +221 -0
  105. package/tests/unit/database.test.ts +183 -0
  106. package/tests/unit/linear-router.test.ts +280 -0
  107. package/tests/unit/lock.test.ts +336 -0
  108. package/tests/unit/middleware.test.ts +184 -0
  109. package/tests/unit/modules.test.ts +142 -0
  110. package/tests/unit/pubsub.test.ts +257 -0
  111. package/tests/unit/regex-router.test.ts +265 -0
  112. package/tests/unit/router.test.ts +373 -0
  113. package/tests/unit/rpc.test.ts +1248 -0
  114. package/tests/unit/security.test.ts +174 -0
  115. package/tests/unit/telemetry.test.ts +371 -0
  116. package/tests/unit/test-cache.test.ts +110 -0
  117. package/tests/unit/test-database.test.ts +282 -0
  118. package/tests/unit/tree-router.test.ts +325 -0
  119. package/tests/unit/validation.test.ts +794 -0
  120. package/tsconfig.json +27 -0
@@ -0,0 +1,292 @@
1
+ /**
2
+ * RegexRouter
3
+ *
4
+ * Balanced performance for applications with 10-100 routes.
5
+ * - Compiled regex patterns for fast matching
6
+ * - Priority-based sorting for correct route resolution
7
+ * - Full feature support: params, wildcards, optional params, custom regex
8
+ *
9
+ * Best for: Medium-sized APIs, general purpose routing
10
+ */
11
+
12
+ import type {
13
+ HTTPMethod,
14
+ MiddlewareHandler,
15
+ PathParams,
16
+ RouteHandler,
17
+ } from "../types";
18
+
19
+ // ============= Types =============
20
+
21
+ export interface RouteMatch {
22
+ handler: RouteHandler;
23
+ params: PathParams;
24
+ middleware?: MiddlewareHandler[];
25
+ name?: string;
26
+ }
27
+
28
+ interface RouteEntry {
29
+ method: HTTPMethod | "ALL";
30
+ pattern: string;
31
+ handler: RouteHandler;
32
+ middleware?: MiddlewareHandler[];
33
+ name?: string;
34
+ regex: RegExp;
35
+ paramNames: string[];
36
+ isStatic: boolean;
37
+ priority: number;
38
+ }
39
+
40
+ export interface RouteOptions {
41
+ name?: string;
42
+ middleware?: MiddlewareHandler | MiddlewareHandler[];
43
+ }
44
+
45
+ // ============= Pattern Utilities =============
46
+
47
+ function patternToRegex(pattern: string): {
48
+ regex: RegExp;
49
+ paramNames: string[];
50
+ isStatic: boolean;
51
+ hasWildcard: boolean;
52
+ } {
53
+ const paramNames: string[] = [];
54
+ let isStatic = true;
55
+ let hasWildcard = false;
56
+
57
+ const segments: string[] = [];
58
+ let i = 0;
59
+
60
+ while (i < pattern.length) {
61
+ if (pattern[i] === ":") {
62
+ i++;
63
+
64
+ let name = "";
65
+ while (i < pattern.length && /[a-zA-Z0-9_]/.test(pattern[i])) {
66
+ name += pattern[i];
67
+ i++;
68
+ }
69
+
70
+ let optional = false;
71
+ if (i < pattern.length && pattern[i] === "?") {
72
+ optional = true;
73
+ i++;
74
+ }
75
+
76
+ let customRegex = "";
77
+ if (i < pattern.length && pattern[i] === "<") {
78
+ i++;
79
+ while (i < pattern.length && pattern[i] !== ">") {
80
+ customRegex += pattern[i];
81
+ i++;
82
+ }
83
+ i++;
84
+ }
85
+
86
+ paramNames.push(name);
87
+ isStatic = false;
88
+
89
+ if (optional) {
90
+ if (segments.length > 0 && segments[segments.length - 1] === "/") {
91
+ segments.pop();
92
+ }
93
+ segments.push("(?:/([^/]*))?");
94
+ } else if (customRegex) {
95
+ segments.push(`(${customRegex})`);
96
+ } else {
97
+ segments.push("([^/]+)");
98
+ }
99
+ } else if (pattern[i] === "*") {
100
+ hasWildcard = true;
101
+ isStatic = false;
102
+ paramNames.push("*");
103
+ segments.push("(.*)");
104
+ i++;
105
+ } else {
106
+ const char = pattern[i];
107
+ if (/[.+^${}()|[\]\\]/.test(char)) {
108
+ segments.push(`\\${char}`);
109
+ } else {
110
+ segments.push(char);
111
+ }
112
+ i++;
113
+ }
114
+ }
115
+
116
+ const regexStr = `^${segments.join("")}/?$`;
117
+
118
+ return {
119
+ regex: new RegExp(regexStr, "i"),
120
+ paramNames,
121
+ isStatic,
122
+ hasWildcard,
123
+ };
124
+ }
125
+
126
+ function extractParams(
127
+ regex: RegExp,
128
+ paramNames: string[],
129
+ pathname: string,
130
+ ): PathParams {
131
+ const params: PathParams = {};
132
+ const match = pathname.match(regex);
133
+
134
+ if (match) {
135
+ paramNames.forEach((name, index) => {
136
+ if (match[index + 1] !== undefined) {
137
+ params[name] = match[index + 1];
138
+ }
139
+ });
140
+ }
141
+
142
+ return params;
143
+ }
144
+
145
+ // ============= RegexRouter Class =============
146
+
147
+ export class RegexRouter {
148
+ private routes: RouteEntry[] = [];
149
+ private groupPrefix = "";
150
+ private groupMiddleware: MiddlewareHandler[] = [];
151
+ private routeCounter = 0;
152
+
153
+ private addRoute(
154
+ method: HTTPMethod | "ALL",
155
+ pattern: string,
156
+ handler: RouteHandler,
157
+ options?: RouteOptions,
158
+ ): void {
159
+ const fullPattern = this.groupPrefix + pattern;
160
+ const { regex, paramNames, isStatic } = patternToRegex(fullPattern);
161
+
162
+ const optsMiddleware = options?.middleware;
163
+ const routeMiddleware: MiddlewareHandler[] = optsMiddleware
164
+ ? Array.isArray(optsMiddleware)
165
+ ? optsMiddleware
166
+ : [optsMiddleware]
167
+ : [];
168
+
169
+ this.routes.push({
170
+ method,
171
+ pattern: fullPattern,
172
+ handler,
173
+ middleware: [...this.groupMiddleware, ...routeMiddleware],
174
+ name: options?.name,
175
+ regex,
176
+ paramNames,
177
+ isStatic,
178
+ priority: this.routeCounter++,
179
+ });
180
+
181
+ this.sortRoutes();
182
+ }
183
+
184
+ private sortRoutes(): void {
185
+ this.routes.sort((a, b) => {
186
+ if (a.isStatic !== b.isStatic) {
187
+ return a.isStatic ? -1 : 1;
188
+ }
189
+ if (a.paramNames.length !== b.paramNames.length) {
190
+ return a.paramNames.length - b.paramNames.length;
191
+ }
192
+ return a.priority - b.priority;
193
+ });
194
+ }
195
+
196
+ match(method: HTTPMethod | "ALL", pathname: string): RouteMatch | undefined {
197
+ for (const route of this.routes) {
198
+ if (route.method !== "ALL" && route.method !== method) {
199
+ continue;
200
+ }
201
+
202
+ if (route.regex.test(pathname)) {
203
+ const params = extractParams(route.regex, route.paramNames, pathname);
204
+ return {
205
+ handler: route.handler,
206
+ params,
207
+ middleware: route.middleware,
208
+ name: route.name,
209
+ };
210
+ }
211
+ }
212
+
213
+ return undefined;
214
+ }
215
+
216
+ group(
217
+ prefix: string,
218
+ options?: { middleware?: MiddlewareHandler | MiddlewareHandler[] },
219
+ ): RegexRouter {
220
+ const childRouter = new RegexRouter();
221
+ childRouter.routes = this.routes;
222
+ childRouter.groupPrefix = this.groupPrefix + prefix;
223
+
224
+ const optsMiddleware = options?.middleware;
225
+ const middlewareArray: MiddlewareHandler[] = optsMiddleware
226
+ ? Array.isArray(optsMiddleware)
227
+ ? optsMiddleware
228
+ : [optsMiddleware]
229
+ : [];
230
+
231
+ childRouter.groupMiddleware = [...this.groupMiddleware, ...middlewareArray];
232
+ childRouter.routeCounter = this.routeCounter;
233
+
234
+ return childRouter;
235
+ }
236
+
237
+ getRoutes(): Array<{
238
+ method: HTTPMethod | "ALL";
239
+ pattern: string;
240
+ name?: string;
241
+ }> {
242
+ return this.routes.map((r) => ({
243
+ method: r.method,
244
+ pattern: r.pattern,
245
+ name: r.name,
246
+ }));
247
+ }
248
+
249
+ getRouterType(): "regex" {
250
+ return "regex";
251
+ }
252
+
253
+ getRouteCount(): number {
254
+ return this.routes.length;
255
+ }
256
+
257
+ get(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
258
+ this.addRoute("GET", pattern, handler, options);
259
+ }
260
+
261
+ post(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
262
+ this.addRoute("POST", pattern, handler, options);
263
+ }
264
+
265
+ put(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
266
+ this.addRoute("PUT", pattern, handler, options);
267
+ }
268
+
269
+ patch(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
270
+ this.addRoute("PATCH", pattern, handler, options);
271
+ }
272
+
273
+ delete(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
274
+ this.addRoute("DELETE", pattern, handler, options);
275
+ }
276
+
277
+ head(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
278
+ this.addRoute("HEAD", pattern, handler, options);
279
+ }
280
+
281
+ options(
282
+ pattern: string,
283
+ handler: RouteHandler,
284
+ options?: RouteOptions,
285
+ ): void {
286
+ this.addRoute("OPTIONS", pattern, handler, options);
287
+ }
288
+
289
+ all(pattern: string, handler: RouteHandler, options?: RouteOptions): void {
290
+ this.addRoute("ALL", pattern, handler, options);
291
+ }
292
+ }