@h3ravel/router 0.1.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.
- package/LICENSE +21 -0
- package/dist/index.cjs +259 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +162 -0
- package/dist/index.d.ts +162 -0
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -0
- package/package.json +27 -0
- package/src/Contracts/.gitkeep +0 -0
- package/src/Controller.ts +1 -0
- package/src/Decorators/ApiResource.ts +1 -0
- package/src/Decorators/Controller.ts +1 -0
- package/src/Decorators/Get.ts +1 -0
- package/src/Decorators/Middleware.ts +1 -0
- package/src/Decorators/Post.ts +1 -0
- package/src/Middleware/.gitkeep +0 -0
- package/src/Providers/AssetsServiceProvider.ts +53 -0
- package/src/Providers/RouteServiceProvider.ts +44 -0
- package/src/Route.ts +1 -0
- package/src/Router.ts +180 -0
- package/src/index.ts +14 -0
- package/tests/.gitkeep +0 -0
- package/tsconfig.json +8 -0
- package/vite.config.ts +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 h3ravel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
AssetsServiceProvider: () => AssetsServiceProvider,
|
|
35
|
+
RouteServiceProvider: () => RouteServiceProvider,
|
|
36
|
+
Router: () => Router
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// src/Router.ts
|
|
41
|
+
var import_core = require("@h3ravel/core");
|
|
42
|
+
var import_support = require("@h3ravel/support");
|
|
43
|
+
var Router = class {
|
|
44
|
+
static {
|
|
45
|
+
__name(this, "Router");
|
|
46
|
+
}
|
|
47
|
+
h3App;
|
|
48
|
+
app;
|
|
49
|
+
routes = [];
|
|
50
|
+
groupPrefix = "";
|
|
51
|
+
groupMiddleware = [];
|
|
52
|
+
constructor(h3App, app) {
|
|
53
|
+
this.h3App = h3App;
|
|
54
|
+
this.app = app;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Route Resolver
|
|
58
|
+
*
|
|
59
|
+
* @param handler
|
|
60
|
+
* @param middleware
|
|
61
|
+
* @returns
|
|
62
|
+
*/
|
|
63
|
+
resolveHandler(handler, middleware = []) {
|
|
64
|
+
return async (event) => {
|
|
65
|
+
const kernel = new import_core.Kernel(middleware);
|
|
66
|
+
return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)));
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Add a route to the stack
|
|
71
|
+
*
|
|
72
|
+
* @param method
|
|
73
|
+
* @param path
|
|
74
|
+
* @param handler
|
|
75
|
+
* @param name
|
|
76
|
+
* @param middleware
|
|
77
|
+
*/
|
|
78
|
+
addRoute(method, path2, handler, name, middleware = []) {
|
|
79
|
+
const fullPath = `${this.groupPrefix}${path2}`.replace(/\/+/g, "/");
|
|
80
|
+
this.routes.push({
|
|
81
|
+
method,
|
|
82
|
+
path: fullPath,
|
|
83
|
+
name,
|
|
84
|
+
handler
|
|
85
|
+
});
|
|
86
|
+
this.h3App[method](fullPath, this.resolveHandler(handler, middleware));
|
|
87
|
+
}
|
|
88
|
+
resolveControllerOrHandler(handler, methodName) {
|
|
89
|
+
if (typeof handler === "function" && handler.prototype instanceof import_core.Controller) {
|
|
90
|
+
return (ctx) => {
|
|
91
|
+
const controller = new handler(this.app);
|
|
92
|
+
const action = methodName || "index";
|
|
93
|
+
if (typeof controller[action] !== "function") {
|
|
94
|
+
throw new Error(`Method "${action}" not found on controller ${handler.name}`);
|
|
95
|
+
}
|
|
96
|
+
return controller[action](ctx);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return handler;
|
|
100
|
+
}
|
|
101
|
+
get(path2, handler, methodName, name, middleware = []) {
|
|
102
|
+
this.addRoute("get", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
103
|
+
}
|
|
104
|
+
post(path2, handler, methodName, name, middleware = []) {
|
|
105
|
+
this.addRoute("post", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
106
|
+
}
|
|
107
|
+
put(path2, handler, methodName, name, middleware = []) {
|
|
108
|
+
this.addRoute("put", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
109
|
+
}
|
|
110
|
+
delete(path2, handler, methodName, name, middleware = []) {
|
|
111
|
+
this.addRoute("delete", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* API Resource support
|
|
115
|
+
*
|
|
116
|
+
* @param path
|
|
117
|
+
* @param controller
|
|
118
|
+
*/
|
|
119
|
+
apiResource(path2, Controller2, middleware = []) {
|
|
120
|
+
path2 = path2.replace(/\//g, "/");
|
|
121
|
+
const name = (0, import_support.afterLast)(path2, "/");
|
|
122
|
+
const basePath = `/${path2}`.replace(/\/+/g, "/");
|
|
123
|
+
const controller = new Controller2(this.app);
|
|
124
|
+
this.addRoute("get", basePath, controller.index.bind(controller), `${name}.index`, middleware);
|
|
125
|
+
this.addRoute("post", basePath, controller.store.bind(controller), `${name}.store`, middleware);
|
|
126
|
+
this.addRoute("get", `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware);
|
|
127
|
+
this.addRoute("put", `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware);
|
|
128
|
+
this.addRoute("patch", `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware);
|
|
129
|
+
this.addRoute("delete", `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Named route URL generator
|
|
133
|
+
*
|
|
134
|
+
* @param name
|
|
135
|
+
* @param params
|
|
136
|
+
* @returns
|
|
137
|
+
*/
|
|
138
|
+
route(name, params = {}) {
|
|
139
|
+
const found = this.routes.find((r) => r.name === name);
|
|
140
|
+
if (!found) return void 0;
|
|
141
|
+
let url = found.path;
|
|
142
|
+
for (const [key, value] of Object.entries(params)) {
|
|
143
|
+
url = url.replace(`:${key}`, value);
|
|
144
|
+
}
|
|
145
|
+
return url;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Grouping
|
|
149
|
+
*
|
|
150
|
+
* @param options
|
|
151
|
+
* @param callback
|
|
152
|
+
*/
|
|
153
|
+
group(options, callback) {
|
|
154
|
+
const prevPrefix = this.groupPrefix;
|
|
155
|
+
const prevMiddleware = [
|
|
156
|
+
...this.groupMiddleware
|
|
157
|
+
];
|
|
158
|
+
this.groupPrefix += options.prefix || "";
|
|
159
|
+
this.groupMiddleware.push(...options.middleware || []);
|
|
160
|
+
callback();
|
|
161
|
+
this.groupPrefix = prevPrefix;
|
|
162
|
+
this.groupMiddleware = prevMiddleware;
|
|
163
|
+
}
|
|
164
|
+
middleware(path2, handler, opts) {
|
|
165
|
+
this.h3App.use(path2, handler, opts);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/Providers/AssetsServiceProvider.ts
|
|
170
|
+
var import_promises = require("fs/promises");
|
|
171
|
+
var import_core2 = require("@h3ravel/core");
|
|
172
|
+
var import_support2 = require("@h3ravel/support");
|
|
173
|
+
var import_node_path = require("path");
|
|
174
|
+
var import_h3 = require("h3");
|
|
175
|
+
var import_node_fs = require("fs");
|
|
176
|
+
var AssetsServiceProvider = class extends import_core2.ServiceProvider {
|
|
177
|
+
static {
|
|
178
|
+
__name(this, "AssetsServiceProvider");
|
|
179
|
+
}
|
|
180
|
+
register() {
|
|
181
|
+
const app = this.app.make("router");
|
|
182
|
+
const config = this.app.make("config");
|
|
183
|
+
const fsconfig = config.get("filesystem");
|
|
184
|
+
const publicPath = this.app.getPath("public");
|
|
185
|
+
app.middleware(`/${fsconfig.public_mask}/**`, (event) => {
|
|
186
|
+
return (0, import_h3.serveStatic)(event, {
|
|
187
|
+
indexNames: [
|
|
188
|
+
"/index.html"
|
|
189
|
+
],
|
|
190
|
+
getContents: /* @__PURE__ */ __name((id) => {
|
|
191
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, "");
|
|
192
|
+
return (0, import_promises.readFile)((0, import_node_path.join)((0, import_support2.before)(publicPath, newId), newId));
|
|
193
|
+
}, "getContents"),
|
|
194
|
+
getMeta: /* @__PURE__ */ __name(async (id) => {
|
|
195
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, "");
|
|
196
|
+
const stats = await (0, import_promises.stat)((0, import_node_path.join)((0, import_support2.before)(publicPath, newId), newId)).catch(() => {
|
|
197
|
+
});
|
|
198
|
+
if (stats?.isFile()) {
|
|
199
|
+
return {
|
|
200
|
+
size: stats.size,
|
|
201
|
+
mtime: stats.mtimeMs
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}, "getMeta")
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
this.app.singleton("asset", () => {
|
|
208
|
+
return (key, def = "") => {
|
|
209
|
+
try {
|
|
210
|
+
(0, import_node_fs.statSync)((0, import_node_path.join)((0, import_support2.before)(publicPath, key), key));
|
|
211
|
+
} catch {
|
|
212
|
+
key = def;
|
|
213
|
+
}
|
|
214
|
+
return (0, import_node_path.join)(fsconfig.public_mask, key);
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/Providers/RouteServiceProvider.ts
|
|
221
|
+
var import_core3 = require("@h3ravel/core");
|
|
222
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
223
|
+
var import_promises2 = require("fs/promises");
|
|
224
|
+
var RouteServiceProvider = class extends import_core3.ServiceProvider {
|
|
225
|
+
static {
|
|
226
|
+
__name(this, "RouteServiceProvider");
|
|
227
|
+
}
|
|
228
|
+
register() {
|
|
229
|
+
this.app.singleton("router", () => {
|
|
230
|
+
const h3App = this.app.make("http.app");
|
|
231
|
+
return new Router(h3App, this.app);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Load routes from src/routes
|
|
236
|
+
*/
|
|
237
|
+
async boot() {
|
|
238
|
+
try {
|
|
239
|
+
const routePath = this.app.getPath("routes");
|
|
240
|
+
const files = await (0, import_promises2.readdir)(routePath);
|
|
241
|
+
for (let i = 0; i < files.length; i++) {
|
|
242
|
+
const routesModule = await import(import_node_path2.default.join(routePath, files[i]));
|
|
243
|
+
if (typeof routesModule.default === "function") {
|
|
244
|
+
const router = this.app.make("router");
|
|
245
|
+
routesModule.default(router);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
console.warn("No web routes found or failed to load:", e);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
254
|
+
0 && (module.exports = {
|
|
255
|
+
AssetsServiceProvider,
|
|
256
|
+
RouteServiceProvider,
|
|
257
|
+
Router
|
|
258
|
+
});
|
|
259
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Router.ts","../src/Providers/AssetsServiceProvider.ts","../src/Providers/RouteServiceProvider.ts"],"sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from './Controller';\nexport * from './Route';\nexport * from './Router';\nexport * from './Decorators/ApiResource';\nexport * from './Decorators/Controller';\nexport * from './Decorators/Get';\nexport * from './Decorators/Middleware';\nexport * from './Decorators/Post';\nexport * from './Providers/AssetsServiceProvider';\nexport * from './Providers/RouteServiceProvider';\n","import { H3Event, Middleware, MiddlewareOptions, type H3 } from 'h3'\nimport { Application, Controller, Kernel } from '@h3ravel/core'\nimport { Middleware as HttpMiddleware } from '@h3ravel/http'\nimport { HttpContext } from '@h3ravel/http'\nimport { afterLast } from '@h3ravel/support'\n\ntype EventHandler = (ctx: HttpContext) => unknown\n\ninterface RouteDefinition {\n method: string\n path: string\n name?: string\n handler: EventHandler\n}\n\nexport class Router {\n private routes: RouteDefinition[] = []\n private groupPrefix = ''\n private groupMiddleware: EventHandler[] = []\n\n constructor(private h3App: H3, private app: Application) { }\n\n /**\n * Route Resolver\n * \n * @param handler \n * @param middleware \n * @returns \n */\n private resolveHandler (handler: EventHandler, middleware: HttpMiddleware[] = []) {\n return async (event: H3Event) => {\n const kernel = new Kernel(middleware)\n return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)))\n }\n }\n\n /**\n * Add a route to the stack\n * \n * @param method \n * @param path \n * @param handler \n * @param name \n * @param middleware \n */\n private addRoute (\n method: string,\n path: string,\n handler: EventHandler,\n name?: string,\n middleware: HttpMiddleware[] = []\n ) {\n const fullPath = `${this.groupPrefix}${path}`.replace(/\\/+/g, '/')\n this.routes.push({ method, path: fullPath, name, handler })\n this.h3App[method as 'get'](fullPath, this.resolveHandler(handler, middleware))\n }\n\n private resolveControllerOrHandler (\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string\n ): EventHandler {\n if (typeof handler === 'function' && (handler as any).prototype instanceof Controller) {\n return (ctx) => {\n const controller = new (handler as new (...args: any[]) => Controller)(this.app)\n const action = (methodName || 'index') as keyof Controller\n\n if (typeof controller[action] !== 'function') {\n throw new Error(`Method \"${action}\" not found on controller ${handler.name}`)\n }\n\n return controller[action](ctx)\n }\n }\n\n return handler as EventHandler\n }\n\n\n get (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('get', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n post (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('post', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n put (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('put', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n delete (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('delete', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n /**\n * API Resource support \n * \n * @param path \n * @param controller \n */\n apiResource (\n path: string,\n Controller: new (app: Application) => Controller,\n middleware: HttpMiddleware[] = []\n ) {\n path = path.replace(/\\//g, '/')\n\n const name = afterLast(path, '/')\n const basePath = `/${path}`.replace(/\\/+/g, '/')\n\n const controller = new Controller(this.app)\n\n this.addRoute('get', basePath, controller.index.bind(controller), `${name}.index`, middleware)\n this.addRoute('post', basePath, controller.store.bind(controller), `${name}.store`, middleware)\n this.addRoute('get', `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware)\n this.addRoute('put', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)\n this.addRoute('patch', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)\n this.addRoute('delete', `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware)\n }\n\n /**\n * Named route URL generator\n * \n * @param name \n * @param params \n * @returns \n */\n route (name: string, params: Record<string, string> = {}): string | undefined {\n const found = this.routes.find(r => r.name === name)\n if (!found) return undefined\n\n let url = found.path\n for (const [key, value] of Object.entries(params)) {\n url = url.replace(`:${key}`, value)\n }\n return url\n }\n\n /**\n * Grouping\n * \n * @param options \n * @param callback \n */\n group (options: { prefix?: string; middleware?: EventHandler[] }, callback: () => void) {\n const prevPrefix = this.groupPrefix\n const prevMiddleware = [...this.groupMiddleware]\n\n this.groupPrefix += options.prefix || ''\n this.groupMiddleware.push(...(options.middleware || []))\n\n callback()\n\n /**\n * Restore state after group\n */\n this.groupPrefix = prevPrefix\n this.groupMiddleware = prevMiddleware\n }\n\n middleware (path: string, handler: Middleware, opts?: MiddlewareOptions) {\n this.h3App.use(path, handler, opts)\n }\n}\n","import { readFile, stat } from \"node:fs/promises\";\n\nimport { ServiceProvider } from '@h3ravel/core'\nimport { before } from \"@h3ravel/support\";\nimport { join } from \"node:path\";\nimport { serveStatic } from 'h3'\nimport { statSync } from \"node:fs\";\n\n/**\n * Handles public assets loading\n * \n * Auto-Registered\n */\nexport class AssetsServiceProvider extends ServiceProvider {\n register () {\n const app = this.app.make('router')\n const config = this.app.make('config')\n const fsconfig = config.get('filesystem')\n const publicPath = this.app.getPath('public')\n\n app.middleware(`/${fsconfig.public_mask}/**`, (event) => {\n return serveStatic(event, {\n indexNames: [\"/index.html\"],\n getContents: (id) => {\n const newId = id.replace(`/${fsconfig.public_mask}/`, '')\n return readFile(join(before(publicPath, newId), newId))\n },\n getMeta: async (id) => {\n const newId = id.replace(`/${fsconfig.public_mask}/`, '')\n const stats = await stat(join(before(publicPath, newId), newId)).catch(() => { });\n if (stats?.isFile()) {\n return {\n size: stats.size,\n mtime: stats.mtimeMs,\n };\n }\n },\n });\n })\n\n this.app.singleton('asset', () => {\n return (key: string, def = '') => {\n try {\n statSync(join(before(publicPath, key), key))\n } catch {\n key = def\n }\n\n return join(fsconfig.public_mask, key)\n }\n })\n }\n}\n","import { Router } from '../Router'\nimport { ServiceProvider } from '@h3ravel/core'\nimport path from 'node:path'\nimport { readdir } from 'node:fs/promises'\n\n/**\n * Handles routing registration\n * \n * Load route files (web.ts, api.ts).\n * Map controllers to routes.\n * Register route-related middleware.\n * \n * Auto-Registered\n */\nexport class RouteServiceProvider extends ServiceProvider {\n register () {\n this.app.singleton('router', () => {\n const h3App = this.app.make('http.app')\n return new Router(h3App, this.app)\n })\n }\n\n /**\n * Load routes from src/routes\n */\n async boot () {\n try {\n const routePath = this.app.getPath('routes')\n\n const files = await readdir(routePath);\n\n for (let i = 0; i < files.length; i++) {\n const routesModule = await import(path.join(routePath, files[i]))\n\n if (typeof routesModule.default === 'function') {\n const router = this.app.make('router')\n routesModule.default(router)\n }\n }\n } catch (e) {\n console.warn('No web routes found or failed to load:', e)\n }\n }\n}\n"],"mappings":"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","names":["Router","routes","groupPrefix","groupMiddleware","h3App","app","resolveHandler","handler","middleware","event","kernel","Kernel","handle","ctx","Promise","resolve","addRoute","method","path","name","fullPath","replace","push","resolveControllerOrHandler","methodName","prototype","Controller","controller","action","Error","get","post","put","delete","apiResource","afterLast","basePath","index","bind","store","show","update","destroy","route","params","found","find","r","undefined","url","key","value","Object","entries","group","options","callback","prevPrefix","prevMiddleware","prefix","opts","use","import_core","import_support","AssetsServiceProvider","ServiceProvider","register","app","make","config","fsconfig","get","publicPath","getPath","middleware","public_mask","event","serveStatic","indexNames","getContents","id","newId","replace","readFile","join","before","getMeta","stats","stat","catch","isFile","size","mtime","mtimeMs","singleton","key","def","statSync","import_core","import_node_path","import_promises","RouteServiceProvider","ServiceProvider","register","app","singleton","h3App","make","Router","boot","routePath","getPath","files","readdir","i","length","routesModule","path","join","default","router","e","console","warn"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { H3Event, H3, Middleware as Middleware$1, MiddlewareOptions } from 'h3';
|
|
2
|
+
import { Application, Controller, ServiceProvider } from '@h3ravel/core';
|
|
3
|
+
import { DotNestedKeys, DotNestedValue } from '@h3ravel/support';
|
|
4
|
+
|
|
5
|
+
declare class Request {
|
|
6
|
+
private readonly event;
|
|
7
|
+
constructor(event: H3Event);
|
|
8
|
+
/**
|
|
9
|
+
* Get all input data (query + body).
|
|
10
|
+
*/
|
|
11
|
+
all<T = Record<string, unknown>>(): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Get a single input field from query or body.
|
|
14
|
+
*/
|
|
15
|
+
input<T = unknown>(key: string, defaultValue?: T): Promise<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Get route parameters.
|
|
18
|
+
*/
|
|
19
|
+
params<T = Record<string, string>>(): T;
|
|
20
|
+
/**
|
|
21
|
+
* Get query parameters.
|
|
22
|
+
*/
|
|
23
|
+
query<T = Record<string, string>>(): T;
|
|
24
|
+
/**
|
|
25
|
+
* Get the base event
|
|
26
|
+
*/
|
|
27
|
+
getEvent(): H3Event;
|
|
28
|
+
getEvent<K extends DotNestedKeys<H3Event>>(key: K): DotNestedValue<H3Event, K>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare class Response {
|
|
32
|
+
private readonly event;
|
|
33
|
+
private statusCode;
|
|
34
|
+
private headers;
|
|
35
|
+
constructor(event: H3Event);
|
|
36
|
+
/**
|
|
37
|
+
* Set HTTP status code.
|
|
38
|
+
*/
|
|
39
|
+
setStatusCode(code: number): this;
|
|
40
|
+
/**
|
|
41
|
+
* Set a header.
|
|
42
|
+
*/
|
|
43
|
+
setHeader(name: string, value: string): this;
|
|
44
|
+
html(content: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Send a JSON response.
|
|
47
|
+
*/
|
|
48
|
+
json<T = unknown>(data: T): T;
|
|
49
|
+
/**
|
|
50
|
+
* Send plain text.
|
|
51
|
+
*/
|
|
52
|
+
text(data: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Redirect to another URL.
|
|
55
|
+
*/
|
|
56
|
+
redirect(url: string, status?: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Apply headers before sending response.
|
|
59
|
+
*/
|
|
60
|
+
private applyHeaders;
|
|
61
|
+
/**
|
|
62
|
+
* Get the base event
|
|
63
|
+
*/
|
|
64
|
+
getEvent(): H3Event;
|
|
65
|
+
getEvent<K extends DotNestedKeys<H3Event>>(key: K): DotNestedValue<H3Event, K>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface HttpContext {
|
|
69
|
+
request: Request;
|
|
70
|
+
response: Response;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare abstract class Middleware {
|
|
74
|
+
abstract handle(context: HttpContext, next: () => Promise<unknown>): Promise<unknown>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type EventHandler = (ctx: HttpContext) => unknown;
|
|
78
|
+
declare class Router {
|
|
79
|
+
private h3App;
|
|
80
|
+
private app;
|
|
81
|
+
private routes;
|
|
82
|
+
private groupPrefix;
|
|
83
|
+
private groupMiddleware;
|
|
84
|
+
constructor(h3App: H3, app: Application);
|
|
85
|
+
/**
|
|
86
|
+
* Route Resolver
|
|
87
|
+
*
|
|
88
|
+
* @param handler
|
|
89
|
+
* @param middleware
|
|
90
|
+
* @returns
|
|
91
|
+
*/
|
|
92
|
+
private resolveHandler;
|
|
93
|
+
/**
|
|
94
|
+
* Add a route to the stack
|
|
95
|
+
*
|
|
96
|
+
* @param method
|
|
97
|
+
* @param path
|
|
98
|
+
* @param handler
|
|
99
|
+
* @param name
|
|
100
|
+
* @param middleware
|
|
101
|
+
*/
|
|
102
|
+
private addRoute;
|
|
103
|
+
private resolveControllerOrHandler;
|
|
104
|
+
get(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
105
|
+
post(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
106
|
+
put(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
107
|
+
delete(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
108
|
+
/**
|
|
109
|
+
* API Resource support
|
|
110
|
+
*
|
|
111
|
+
* @param path
|
|
112
|
+
* @param controller
|
|
113
|
+
*/
|
|
114
|
+
apiResource(path: string, Controller: new (app: Application) => Controller, middleware?: Middleware[]): void;
|
|
115
|
+
/**
|
|
116
|
+
* Named route URL generator
|
|
117
|
+
*
|
|
118
|
+
* @param name
|
|
119
|
+
* @param params
|
|
120
|
+
* @returns
|
|
121
|
+
*/
|
|
122
|
+
route(name: string, params?: Record<string, string>): string | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Grouping
|
|
125
|
+
*
|
|
126
|
+
* @param options
|
|
127
|
+
* @param callback
|
|
128
|
+
*/
|
|
129
|
+
group(options: {
|
|
130
|
+
prefix?: string;
|
|
131
|
+
middleware?: EventHandler[];
|
|
132
|
+
}, callback: () => void): void;
|
|
133
|
+
middleware(path: string, handler: Middleware$1, opts?: MiddlewareOptions): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Handles public assets loading
|
|
138
|
+
*
|
|
139
|
+
* Auto-Registered
|
|
140
|
+
*/
|
|
141
|
+
declare class AssetsServiceProvider extends ServiceProvider {
|
|
142
|
+
register(): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Handles routing registration
|
|
147
|
+
*
|
|
148
|
+
* Load route files (web.ts, api.ts).
|
|
149
|
+
* Map controllers to routes.
|
|
150
|
+
* Register route-related middleware.
|
|
151
|
+
*
|
|
152
|
+
* Auto-Registered
|
|
153
|
+
*/
|
|
154
|
+
declare class RouteServiceProvider extends ServiceProvider {
|
|
155
|
+
register(): void;
|
|
156
|
+
/**
|
|
157
|
+
* Load routes from src/routes
|
|
158
|
+
*/
|
|
159
|
+
boot(): Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export { AssetsServiceProvider, RouteServiceProvider, Router };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { H3Event, H3, Middleware as Middleware$1, MiddlewareOptions } from 'h3';
|
|
2
|
+
import { Application, Controller, ServiceProvider } from '@h3ravel/core';
|
|
3
|
+
import { DotNestedKeys, DotNestedValue } from '@h3ravel/support';
|
|
4
|
+
|
|
5
|
+
declare class Request {
|
|
6
|
+
private readonly event;
|
|
7
|
+
constructor(event: H3Event);
|
|
8
|
+
/**
|
|
9
|
+
* Get all input data (query + body).
|
|
10
|
+
*/
|
|
11
|
+
all<T = Record<string, unknown>>(): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Get a single input field from query or body.
|
|
14
|
+
*/
|
|
15
|
+
input<T = unknown>(key: string, defaultValue?: T): Promise<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Get route parameters.
|
|
18
|
+
*/
|
|
19
|
+
params<T = Record<string, string>>(): T;
|
|
20
|
+
/**
|
|
21
|
+
* Get query parameters.
|
|
22
|
+
*/
|
|
23
|
+
query<T = Record<string, string>>(): T;
|
|
24
|
+
/**
|
|
25
|
+
* Get the base event
|
|
26
|
+
*/
|
|
27
|
+
getEvent(): H3Event;
|
|
28
|
+
getEvent<K extends DotNestedKeys<H3Event>>(key: K): DotNestedValue<H3Event, K>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare class Response {
|
|
32
|
+
private readonly event;
|
|
33
|
+
private statusCode;
|
|
34
|
+
private headers;
|
|
35
|
+
constructor(event: H3Event);
|
|
36
|
+
/**
|
|
37
|
+
* Set HTTP status code.
|
|
38
|
+
*/
|
|
39
|
+
setStatusCode(code: number): this;
|
|
40
|
+
/**
|
|
41
|
+
* Set a header.
|
|
42
|
+
*/
|
|
43
|
+
setHeader(name: string, value: string): this;
|
|
44
|
+
html(content: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Send a JSON response.
|
|
47
|
+
*/
|
|
48
|
+
json<T = unknown>(data: T): T;
|
|
49
|
+
/**
|
|
50
|
+
* Send plain text.
|
|
51
|
+
*/
|
|
52
|
+
text(data: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Redirect to another URL.
|
|
55
|
+
*/
|
|
56
|
+
redirect(url: string, status?: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Apply headers before sending response.
|
|
59
|
+
*/
|
|
60
|
+
private applyHeaders;
|
|
61
|
+
/**
|
|
62
|
+
* Get the base event
|
|
63
|
+
*/
|
|
64
|
+
getEvent(): H3Event;
|
|
65
|
+
getEvent<K extends DotNestedKeys<H3Event>>(key: K): DotNestedValue<H3Event, K>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface HttpContext {
|
|
69
|
+
request: Request;
|
|
70
|
+
response: Response;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare abstract class Middleware {
|
|
74
|
+
abstract handle(context: HttpContext, next: () => Promise<unknown>): Promise<unknown>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type EventHandler = (ctx: HttpContext) => unknown;
|
|
78
|
+
declare class Router {
|
|
79
|
+
private h3App;
|
|
80
|
+
private app;
|
|
81
|
+
private routes;
|
|
82
|
+
private groupPrefix;
|
|
83
|
+
private groupMiddleware;
|
|
84
|
+
constructor(h3App: H3, app: Application);
|
|
85
|
+
/**
|
|
86
|
+
* Route Resolver
|
|
87
|
+
*
|
|
88
|
+
* @param handler
|
|
89
|
+
* @param middleware
|
|
90
|
+
* @returns
|
|
91
|
+
*/
|
|
92
|
+
private resolveHandler;
|
|
93
|
+
/**
|
|
94
|
+
* Add a route to the stack
|
|
95
|
+
*
|
|
96
|
+
* @param method
|
|
97
|
+
* @param path
|
|
98
|
+
* @param handler
|
|
99
|
+
* @param name
|
|
100
|
+
* @param middleware
|
|
101
|
+
*/
|
|
102
|
+
private addRoute;
|
|
103
|
+
private resolveControllerOrHandler;
|
|
104
|
+
get(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
105
|
+
post(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
106
|
+
put(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
107
|
+
delete(path: string, handler: EventHandler | (new (...args: any[]) => Controller), methodName?: string, name?: string, middleware?: Middleware[]): void;
|
|
108
|
+
/**
|
|
109
|
+
* API Resource support
|
|
110
|
+
*
|
|
111
|
+
* @param path
|
|
112
|
+
* @param controller
|
|
113
|
+
*/
|
|
114
|
+
apiResource(path: string, Controller: new (app: Application) => Controller, middleware?: Middleware[]): void;
|
|
115
|
+
/**
|
|
116
|
+
* Named route URL generator
|
|
117
|
+
*
|
|
118
|
+
* @param name
|
|
119
|
+
* @param params
|
|
120
|
+
* @returns
|
|
121
|
+
*/
|
|
122
|
+
route(name: string, params?: Record<string, string>): string | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Grouping
|
|
125
|
+
*
|
|
126
|
+
* @param options
|
|
127
|
+
* @param callback
|
|
128
|
+
*/
|
|
129
|
+
group(options: {
|
|
130
|
+
prefix?: string;
|
|
131
|
+
middleware?: EventHandler[];
|
|
132
|
+
}, callback: () => void): void;
|
|
133
|
+
middleware(path: string, handler: Middleware$1, opts?: MiddlewareOptions): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Handles public assets loading
|
|
138
|
+
*
|
|
139
|
+
* Auto-Registered
|
|
140
|
+
*/
|
|
141
|
+
declare class AssetsServiceProvider extends ServiceProvider {
|
|
142
|
+
register(): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Handles routing registration
|
|
147
|
+
*
|
|
148
|
+
* Load route files (web.ts, api.ts).
|
|
149
|
+
* Map controllers to routes.
|
|
150
|
+
* Register route-related middleware.
|
|
151
|
+
*
|
|
152
|
+
* Auto-Registered
|
|
153
|
+
*/
|
|
154
|
+
declare class RouteServiceProvider extends ServiceProvider {
|
|
155
|
+
register(): void;
|
|
156
|
+
/**
|
|
157
|
+
* Load routes from src/routes
|
|
158
|
+
*/
|
|
159
|
+
boot(): Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export { AssetsServiceProvider, RouteServiceProvider, Router };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/Router.ts
|
|
5
|
+
import { Controller, Kernel } from "@h3ravel/core";
|
|
6
|
+
import { afterLast } from "@h3ravel/support";
|
|
7
|
+
var Router = class {
|
|
8
|
+
static {
|
|
9
|
+
__name(this, "Router");
|
|
10
|
+
}
|
|
11
|
+
h3App;
|
|
12
|
+
app;
|
|
13
|
+
routes = [];
|
|
14
|
+
groupPrefix = "";
|
|
15
|
+
groupMiddleware = [];
|
|
16
|
+
constructor(h3App, app) {
|
|
17
|
+
this.h3App = h3App;
|
|
18
|
+
this.app = app;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Route Resolver
|
|
22
|
+
*
|
|
23
|
+
* @param handler
|
|
24
|
+
* @param middleware
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
resolveHandler(handler, middleware = []) {
|
|
28
|
+
return async (event) => {
|
|
29
|
+
const kernel = new Kernel(middleware);
|
|
30
|
+
return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)));
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Add a route to the stack
|
|
35
|
+
*
|
|
36
|
+
* @param method
|
|
37
|
+
* @param path
|
|
38
|
+
* @param handler
|
|
39
|
+
* @param name
|
|
40
|
+
* @param middleware
|
|
41
|
+
*/
|
|
42
|
+
addRoute(method, path2, handler, name, middleware = []) {
|
|
43
|
+
const fullPath = `${this.groupPrefix}${path2}`.replace(/\/+/g, "/");
|
|
44
|
+
this.routes.push({
|
|
45
|
+
method,
|
|
46
|
+
path: fullPath,
|
|
47
|
+
name,
|
|
48
|
+
handler
|
|
49
|
+
});
|
|
50
|
+
this.h3App[method](fullPath, this.resolveHandler(handler, middleware));
|
|
51
|
+
}
|
|
52
|
+
resolveControllerOrHandler(handler, methodName) {
|
|
53
|
+
if (typeof handler === "function" && handler.prototype instanceof Controller) {
|
|
54
|
+
return (ctx) => {
|
|
55
|
+
const controller = new handler(this.app);
|
|
56
|
+
const action = methodName || "index";
|
|
57
|
+
if (typeof controller[action] !== "function") {
|
|
58
|
+
throw new Error(`Method "${action}" not found on controller ${handler.name}`);
|
|
59
|
+
}
|
|
60
|
+
return controller[action](ctx);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return handler;
|
|
64
|
+
}
|
|
65
|
+
get(path2, handler, methodName, name, middleware = []) {
|
|
66
|
+
this.addRoute("get", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
67
|
+
}
|
|
68
|
+
post(path2, handler, methodName, name, middleware = []) {
|
|
69
|
+
this.addRoute("post", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
70
|
+
}
|
|
71
|
+
put(path2, handler, methodName, name, middleware = []) {
|
|
72
|
+
this.addRoute("put", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
73
|
+
}
|
|
74
|
+
delete(path2, handler, methodName, name, middleware = []) {
|
|
75
|
+
this.addRoute("delete", path2, this.resolveControllerOrHandler(handler, methodName), name, middleware);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* API Resource support
|
|
79
|
+
*
|
|
80
|
+
* @param path
|
|
81
|
+
* @param controller
|
|
82
|
+
*/
|
|
83
|
+
apiResource(path2, Controller2, middleware = []) {
|
|
84
|
+
path2 = path2.replace(/\//g, "/");
|
|
85
|
+
const name = afterLast(path2, "/");
|
|
86
|
+
const basePath = `/${path2}`.replace(/\/+/g, "/");
|
|
87
|
+
const controller = new Controller2(this.app);
|
|
88
|
+
this.addRoute("get", basePath, controller.index.bind(controller), `${name}.index`, middleware);
|
|
89
|
+
this.addRoute("post", basePath, controller.store.bind(controller), `${name}.store`, middleware);
|
|
90
|
+
this.addRoute("get", `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware);
|
|
91
|
+
this.addRoute("put", `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware);
|
|
92
|
+
this.addRoute("patch", `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware);
|
|
93
|
+
this.addRoute("delete", `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Named route URL generator
|
|
97
|
+
*
|
|
98
|
+
* @param name
|
|
99
|
+
* @param params
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
102
|
+
route(name, params = {}) {
|
|
103
|
+
const found = this.routes.find((r) => r.name === name);
|
|
104
|
+
if (!found) return void 0;
|
|
105
|
+
let url = found.path;
|
|
106
|
+
for (const [key, value] of Object.entries(params)) {
|
|
107
|
+
url = url.replace(`:${key}`, value);
|
|
108
|
+
}
|
|
109
|
+
return url;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Grouping
|
|
113
|
+
*
|
|
114
|
+
* @param options
|
|
115
|
+
* @param callback
|
|
116
|
+
*/
|
|
117
|
+
group(options, callback) {
|
|
118
|
+
const prevPrefix = this.groupPrefix;
|
|
119
|
+
const prevMiddleware = [
|
|
120
|
+
...this.groupMiddleware
|
|
121
|
+
];
|
|
122
|
+
this.groupPrefix += options.prefix || "";
|
|
123
|
+
this.groupMiddleware.push(...options.middleware || []);
|
|
124
|
+
callback();
|
|
125
|
+
this.groupPrefix = prevPrefix;
|
|
126
|
+
this.groupMiddleware = prevMiddleware;
|
|
127
|
+
}
|
|
128
|
+
middleware(path2, handler, opts) {
|
|
129
|
+
this.h3App.use(path2, handler, opts);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// src/Providers/AssetsServiceProvider.ts
|
|
134
|
+
import { readFile, stat } from "fs/promises";
|
|
135
|
+
import { ServiceProvider } from "@h3ravel/core";
|
|
136
|
+
import { before } from "@h3ravel/support";
|
|
137
|
+
import { join } from "path";
|
|
138
|
+
import { serveStatic } from "h3";
|
|
139
|
+
import { statSync } from "fs";
|
|
140
|
+
var AssetsServiceProvider = class extends ServiceProvider {
|
|
141
|
+
static {
|
|
142
|
+
__name(this, "AssetsServiceProvider");
|
|
143
|
+
}
|
|
144
|
+
register() {
|
|
145
|
+
const app = this.app.make("router");
|
|
146
|
+
const config = this.app.make("config");
|
|
147
|
+
const fsconfig = config.get("filesystem");
|
|
148
|
+
const publicPath = this.app.getPath("public");
|
|
149
|
+
app.middleware(`/${fsconfig.public_mask}/**`, (event) => {
|
|
150
|
+
return serveStatic(event, {
|
|
151
|
+
indexNames: [
|
|
152
|
+
"/index.html"
|
|
153
|
+
],
|
|
154
|
+
getContents: /* @__PURE__ */ __name((id) => {
|
|
155
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, "");
|
|
156
|
+
return readFile(join(before(publicPath, newId), newId));
|
|
157
|
+
}, "getContents"),
|
|
158
|
+
getMeta: /* @__PURE__ */ __name(async (id) => {
|
|
159
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, "");
|
|
160
|
+
const stats = await stat(join(before(publicPath, newId), newId)).catch(() => {
|
|
161
|
+
});
|
|
162
|
+
if (stats?.isFile()) {
|
|
163
|
+
return {
|
|
164
|
+
size: stats.size,
|
|
165
|
+
mtime: stats.mtimeMs
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}, "getMeta")
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
this.app.singleton("asset", () => {
|
|
172
|
+
return (key, def = "") => {
|
|
173
|
+
try {
|
|
174
|
+
statSync(join(before(publicPath, key), key));
|
|
175
|
+
} catch {
|
|
176
|
+
key = def;
|
|
177
|
+
}
|
|
178
|
+
return join(fsconfig.public_mask, key);
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/Providers/RouteServiceProvider.ts
|
|
185
|
+
import { ServiceProvider as ServiceProvider2 } from "@h3ravel/core";
|
|
186
|
+
import path from "path";
|
|
187
|
+
import { readdir } from "fs/promises";
|
|
188
|
+
var RouteServiceProvider = class extends ServiceProvider2 {
|
|
189
|
+
static {
|
|
190
|
+
__name(this, "RouteServiceProvider");
|
|
191
|
+
}
|
|
192
|
+
register() {
|
|
193
|
+
this.app.singleton("router", () => {
|
|
194
|
+
const h3App = this.app.make("http.app");
|
|
195
|
+
return new Router(h3App, this.app);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Load routes from src/routes
|
|
200
|
+
*/
|
|
201
|
+
async boot() {
|
|
202
|
+
try {
|
|
203
|
+
const routePath = this.app.getPath("routes");
|
|
204
|
+
const files = await readdir(routePath);
|
|
205
|
+
for (let i = 0; i < files.length; i++) {
|
|
206
|
+
const routesModule = await import(path.join(routePath, files[i]));
|
|
207
|
+
if (typeof routesModule.default === "function") {
|
|
208
|
+
const router = this.app.make("router");
|
|
209
|
+
routesModule.default(router);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
console.warn("No web routes found or failed to load:", e);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
export {
|
|
218
|
+
AssetsServiceProvider,
|
|
219
|
+
RouteServiceProvider,
|
|
220
|
+
Router
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Router.ts","../src/Providers/AssetsServiceProvider.ts","../src/Providers/RouteServiceProvider.ts"],"sourcesContent":["import { H3Event, Middleware, MiddlewareOptions, type H3 } from 'h3'\nimport { Application, Controller, Kernel } from '@h3ravel/core'\nimport { Middleware as HttpMiddleware } from '@h3ravel/http'\nimport { HttpContext } from '@h3ravel/http'\nimport { afterLast } from '@h3ravel/support'\n\ntype EventHandler = (ctx: HttpContext) => unknown\n\ninterface RouteDefinition {\n method: string\n path: string\n name?: string\n handler: EventHandler\n}\n\nexport class Router {\n private routes: RouteDefinition[] = []\n private groupPrefix = ''\n private groupMiddleware: EventHandler[] = []\n\n constructor(private h3App: H3, private app: Application) { }\n\n /**\n * Route Resolver\n * \n * @param handler \n * @param middleware \n * @returns \n */\n private resolveHandler (handler: EventHandler, middleware: HttpMiddleware[] = []) {\n return async (event: H3Event) => {\n const kernel = new Kernel(middleware)\n return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)))\n }\n }\n\n /**\n * Add a route to the stack\n * \n * @param method \n * @param path \n * @param handler \n * @param name \n * @param middleware \n */\n private addRoute (\n method: string,\n path: string,\n handler: EventHandler,\n name?: string,\n middleware: HttpMiddleware[] = []\n ) {\n const fullPath = `${this.groupPrefix}${path}`.replace(/\\/+/g, '/')\n this.routes.push({ method, path: fullPath, name, handler })\n this.h3App[method as 'get'](fullPath, this.resolveHandler(handler, middleware))\n }\n\n private resolveControllerOrHandler (\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string\n ): EventHandler {\n if (typeof handler === 'function' && (handler as any).prototype instanceof Controller) {\n return (ctx) => {\n const controller = new (handler as new (...args: any[]) => Controller)(this.app)\n const action = (methodName || 'index') as keyof Controller\n\n if (typeof controller[action] !== 'function') {\n throw new Error(`Method \"${action}\" not found on controller ${handler.name}`)\n }\n\n return controller[action](ctx)\n }\n }\n\n return handler as EventHandler\n }\n\n\n get (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('get', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n post (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('post', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n put (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('put', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n delete (\n path: string,\n handler: EventHandler | (new (...args: any[]) => Controller),\n methodName?: string, name?: string, middleware: HttpMiddleware[] = []\n ) {\n this.addRoute('delete', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)\n }\n\n /**\n * API Resource support \n * \n * @param path \n * @param controller \n */\n apiResource (\n path: string,\n Controller: new (app: Application) => Controller,\n middleware: HttpMiddleware[] = []\n ) {\n path = path.replace(/\\//g, '/')\n\n const name = afterLast(path, '/')\n const basePath = `/${path}`.replace(/\\/+/g, '/')\n\n const controller = new Controller(this.app)\n\n this.addRoute('get', basePath, controller.index.bind(controller), `${name}.index`, middleware)\n this.addRoute('post', basePath, controller.store.bind(controller), `${name}.store`, middleware)\n this.addRoute('get', `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware)\n this.addRoute('put', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)\n this.addRoute('patch', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)\n this.addRoute('delete', `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware)\n }\n\n /**\n * Named route URL generator\n * \n * @param name \n * @param params \n * @returns \n */\n route (name: string, params: Record<string, string> = {}): string | undefined {\n const found = this.routes.find(r => r.name === name)\n if (!found) return undefined\n\n let url = found.path\n for (const [key, value] of Object.entries(params)) {\n url = url.replace(`:${key}`, value)\n }\n return url\n }\n\n /**\n * Grouping\n * \n * @param options \n * @param callback \n */\n group (options: { prefix?: string; middleware?: EventHandler[] }, callback: () => void) {\n const prevPrefix = this.groupPrefix\n const prevMiddleware = [...this.groupMiddleware]\n\n this.groupPrefix += options.prefix || ''\n this.groupMiddleware.push(...(options.middleware || []))\n\n callback()\n\n /**\n * Restore state after group\n */\n this.groupPrefix = prevPrefix\n this.groupMiddleware = prevMiddleware\n }\n\n middleware (path: string, handler: Middleware, opts?: MiddlewareOptions) {\n this.h3App.use(path, handler, opts)\n }\n}\n","import { readFile, stat } from \"node:fs/promises\";\n\nimport { ServiceProvider } from '@h3ravel/core'\nimport { before } from \"@h3ravel/support\";\nimport { join } from \"node:path\";\nimport { serveStatic } from 'h3'\nimport { statSync } from \"node:fs\";\n\n/**\n * Handles public assets loading\n * \n * Auto-Registered\n */\nexport class AssetsServiceProvider extends ServiceProvider {\n register () {\n const app = this.app.make('router')\n const config = this.app.make('config')\n const fsconfig = config.get('filesystem')\n const publicPath = this.app.getPath('public')\n\n app.middleware(`/${fsconfig.public_mask}/**`, (event) => {\n return serveStatic(event, {\n indexNames: [\"/index.html\"],\n getContents: (id) => {\n const newId = id.replace(`/${fsconfig.public_mask}/`, '')\n return readFile(join(before(publicPath, newId), newId))\n },\n getMeta: async (id) => {\n const newId = id.replace(`/${fsconfig.public_mask}/`, '')\n const stats = await stat(join(before(publicPath, newId), newId)).catch(() => { });\n if (stats?.isFile()) {\n return {\n size: stats.size,\n mtime: stats.mtimeMs,\n };\n }\n },\n });\n })\n\n this.app.singleton('asset', () => {\n return (key: string, def = '') => {\n try {\n statSync(join(before(publicPath, key), key))\n } catch {\n key = def\n }\n\n return join(fsconfig.public_mask, key)\n }\n })\n }\n}\n","import { Router } from '../Router'\nimport { ServiceProvider } from '@h3ravel/core'\nimport path from 'node:path'\nimport { readdir } from 'node:fs/promises'\n\n/**\n * Handles routing registration\n * \n * Load route files (web.ts, api.ts).\n * Map controllers to routes.\n * Register route-related middleware.\n * \n * Auto-Registered\n */\nexport class RouteServiceProvider extends ServiceProvider {\n register () {\n this.app.singleton('router', () => {\n const h3App = this.app.make('http.app')\n return new Router(h3App, this.app)\n })\n }\n\n /**\n * Load routes from src/routes\n */\n async boot () {\n try {\n const routePath = this.app.getPath('routes')\n\n const files = await readdir(routePath);\n\n for (let i = 0; i < files.length; i++) {\n const routesModule = await import(path.join(routePath, files[i]))\n\n if (typeof routesModule.default === 'function') {\n const router = this.app.make('router')\n routesModule.default(router)\n }\n }\n } catch (e) {\n console.warn('No web routes found or failed to load:', e)\n }\n }\n}\n"],"mappings":"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","names":["Controller","Kernel","afterLast","Router","routes","groupPrefix","groupMiddleware","h3App","app","resolveHandler","handler","middleware","event","kernel","Kernel","handle","ctx","Promise","resolve","addRoute","method","path","name","fullPath","replace","push","resolveControllerOrHandler","methodName","prototype","Controller","controller","action","Error","get","post","put","delete","apiResource","afterLast","basePath","index","bind","store","show","update","destroy","route","params","found","find","r","undefined","url","key","value","Object","entries","group","options","callback","prevPrefix","prevMiddleware","prefix","opts","use","readFile","stat","ServiceProvider","before","join","serveStatic","statSync","AssetsServiceProvider","ServiceProvider","register","app","make","config","fsconfig","get","publicPath","getPath","middleware","public_mask","event","serveStatic","indexNames","getContents","id","newId","replace","readFile","join","before","getMeta","stats","stat","catch","isFile","size","mtime","mtimeMs","singleton","key","def","statSync","ServiceProvider","path","readdir","RouteServiceProvider","ServiceProvider","register","app","singleton","h3App","make","Router","boot","routePath","getPath","files","readdir","i","length","routesModule","path","join","default","router","e","console","warn"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@h3ravel/router",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Route facade, decorators and controller system for H3ravel.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"h3": "^2.0.0-beta.1",
|
|
13
|
+
"@h3ravel/core": "0.1.0",
|
|
14
|
+
"@h3ravel/support": "0.1.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"typescript": "^5.4.0"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"barrel": "barrelsby --directory src --delete --singleQuotes",
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsx watch src/index.ts",
|
|
23
|
+
"start": "node dist/index.js",
|
|
24
|
+
"lint": "eslint . --ext .ts",
|
|
25
|
+
"test": "vitest"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
import { ServiceProvider } from '@h3ravel/core'
|
|
4
|
+
import { before } from "@h3ravel/support";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { serveStatic } from 'h3'
|
|
7
|
+
import { statSync } from "node:fs";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handles public assets loading
|
|
11
|
+
*
|
|
12
|
+
* Auto-Registered
|
|
13
|
+
*/
|
|
14
|
+
export class AssetsServiceProvider extends ServiceProvider {
|
|
15
|
+
register () {
|
|
16
|
+
const app = this.app.make('router')
|
|
17
|
+
const config = this.app.make('config')
|
|
18
|
+
const fsconfig = config.get('filesystem')
|
|
19
|
+
const publicPath = this.app.getPath('public')
|
|
20
|
+
|
|
21
|
+
app.middleware(`/${fsconfig.public_mask}/**`, (event) => {
|
|
22
|
+
return serveStatic(event, {
|
|
23
|
+
indexNames: ["/index.html"],
|
|
24
|
+
getContents: (id) => {
|
|
25
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, '')
|
|
26
|
+
return readFile(join(before(publicPath, newId), newId))
|
|
27
|
+
},
|
|
28
|
+
getMeta: async (id) => {
|
|
29
|
+
const newId = id.replace(`/${fsconfig.public_mask}/`, '')
|
|
30
|
+
const stats = await stat(join(before(publicPath, newId), newId)).catch(() => { });
|
|
31
|
+
if (stats?.isFile()) {
|
|
32
|
+
return {
|
|
33
|
+
size: stats.size,
|
|
34
|
+
mtime: stats.mtimeMs,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
this.app.singleton('asset', () => {
|
|
42
|
+
return (key: string, def = '') => {
|
|
43
|
+
try {
|
|
44
|
+
statSync(join(before(publicPath, key), key))
|
|
45
|
+
} catch {
|
|
46
|
+
key = def
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return join(fsconfig.public_mask, key)
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Router } from '../Router'
|
|
2
|
+
import { ServiceProvider } from '@h3ravel/core'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { readdir } from 'node:fs/promises'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles routing registration
|
|
8
|
+
*
|
|
9
|
+
* Load route files (web.ts, api.ts).
|
|
10
|
+
* Map controllers to routes.
|
|
11
|
+
* Register route-related middleware.
|
|
12
|
+
*
|
|
13
|
+
* Auto-Registered
|
|
14
|
+
*/
|
|
15
|
+
export class RouteServiceProvider extends ServiceProvider {
|
|
16
|
+
register () {
|
|
17
|
+
this.app.singleton('router', () => {
|
|
18
|
+
const h3App = this.app.make('http.app')
|
|
19
|
+
return new Router(h3App, this.app)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Load routes from src/routes
|
|
25
|
+
*/
|
|
26
|
+
async boot () {
|
|
27
|
+
try {
|
|
28
|
+
const routePath = this.app.getPath('routes')
|
|
29
|
+
|
|
30
|
+
const files = await readdir(routePath);
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < files.length; i++) {
|
|
33
|
+
const routesModule = await import(path.join(routePath, files[i]))
|
|
34
|
+
|
|
35
|
+
if (typeof routesModule.default === 'function') {
|
|
36
|
+
const router = this.app.make('router')
|
|
37
|
+
routesModule.default(router)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.warn('No web routes found or failed to load:', e)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/Route.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class { }
|
package/src/Router.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { H3Event, Middleware, MiddlewareOptions, type H3 } from 'h3'
|
|
2
|
+
import { Application, Controller, Kernel } from '@h3ravel/core'
|
|
3
|
+
import { Middleware as HttpMiddleware } from '@h3ravel/http'
|
|
4
|
+
import { HttpContext } from '@h3ravel/http'
|
|
5
|
+
import { afterLast } from '@h3ravel/support'
|
|
6
|
+
|
|
7
|
+
type EventHandler = (ctx: HttpContext) => unknown
|
|
8
|
+
|
|
9
|
+
interface RouteDefinition {
|
|
10
|
+
method: string
|
|
11
|
+
path: string
|
|
12
|
+
name?: string
|
|
13
|
+
handler: EventHandler
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Router {
|
|
17
|
+
private routes: RouteDefinition[] = []
|
|
18
|
+
private groupPrefix = ''
|
|
19
|
+
private groupMiddleware: EventHandler[] = []
|
|
20
|
+
|
|
21
|
+
constructor(private h3App: H3, private app: Application) { }
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Route Resolver
|
|
25
|
+
*
|
|
26
|
+
* @param handler
|
|
27
|
+
* @param middleware
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
private resolveHandler (handler: EventHandler, middleware: HttpMiddleware[] = []) {
|
|
31
|
+
return async (event: H3Event) => {
|
|
32
|
+
const kernel = new Kernel(middleware)
|
|
33
|
+
return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Add a route to the stack
|
|
39
|
+
*
|
|
40
|
+
* @param method
|
|
41
|
+
* @param path
|
|
42
|
+
* @param handler
|
|
43
|
+
* @param name
|
|
44
|
+
* @param middleware
|
|
45
|
+
*/
|
|
46
|
+
private addRoute (
|
|
47
|
+
method: string,
|
|
48
|
+
path: string,
|
|
49
|
+
handler: EventHandler,
|
|
50
|
+
name?: string,
|
|
51
|
+
middleware: HttpMiddleware[] = []
|
|
52
|
+
) {
|
|
53
|
+
const fullPath = `${this.groupPrefix}${path}`.replace(/\/+/g, '/')
|
|
54
|
+
this.routes.push({ method, path: fullPath, name, handler })
|
|
55
|
+
this.h3App[method as 'get'](fullPath, this.resolveHandler(handler, middleware))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private resolveControllerOrHandler (
|
|
59
|
+
handler: EventHandler | (new (...args: any[]) => Controller),
|
|
60
|
+
methodName?: string
|
|
61
|
+
): EventHandler {
|
|
62
|
+
if (typeof handler === 'function' && (handler as any).prototype instanceof Controller) {
|
|
63
|
+
return (ctx) => {
|
|
64
|
+
const controller = new (handler as new (...args: any[]) => Controller)(this.app)
|
|
65
|
+
const action = (methodName || 'index') as keyof Controller
|
|
66
|
+
|
|
67
|
+
if (typeof controller[action] !== 'function') {
|
|
68
|
+
throw new Error(`Method "${action}" not found on controller ${handler.name}`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return controller[action](ctx)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return handler as EventHandler
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
get (
|
|
80
|
+
path: string,
|
|
81
|
+
handler: EventHandler | (new (...args: any[]) => Controller),
|
|
82
|
+
methodName?: string, name?: string, middleware: HttpMiddleware[] = []
|
|
83
|
+
) {
|
|
84
|
+
this.addRoute('get', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
post (
|
|
88
|
+
path: string,
|
|
89
|
+
handler: EventHandler | (new (...args: any[]) => Controller),
|
|
90
|
+
methodName?: string, name?: string, middleware: HttpMiddleware[] = []
|
|
91
|
+
) {
|
|
92
|
+
this.addRoute('post', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
put (
|
|
96
|
+
path: string,
|
|
97
|
+
handler: EventHandler | (new (...args: any[]) => Controller),
|
|
98
|
+
methodName?: string, name?: string, middleware: HttpMiddleware[] = []
|
|
99
|
+
) {
|
|
100
|
+
this.addRoute('put', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
delete (
|
|
104
|
+
path: string,
|
|
105
|
+
handler: EventHandler | (new (...args: any[]) => Controller),
|
|
106
|
+
methodName?: string, name?: string, middleware: HttpMiddleware[] = []
|
|
107
|
+
) {
|
|
108
|
+
this.addRoute('delete', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* API Resource support
|
|
113
|
+
*
|
|
114
|
+
* @param path
|
|
115
|
+
* @param controller
|
|
116
|
+
*/
|
|
117
|
+
apiResource (
|
|
118
|
+
path: string,
|
|
119
|
+
Controller: new (app: Application) => Controller,
|
|
120
|
+
middleware: HttpMiddleware[] = []
|
|
121
|
+
) {
|
|
122
|
+
path = path.replace(/\//g, '/')
|
|
123
|
+
|
|
124
|
+
const name = afterLast(path, '/')
|
|
125
|
+
const basePath = `/${path}`.replace(/\/+/g, '/')
|
|
126
|
+
|
|
127
|
+
const controller = new Controller(this.app)
|
|
128
|
+
|
|
129
|
+
this.addRoute('get', basePath, controller.index.bind(controller), `${name}.index`, middleware)
|
|
130
|
+
this.addRoute('post', basePath, controller.store.bind(controller), `${name}.store`, middleware)
|
|
131
|
+
this.addRoute('get', `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware)
|
|
132
|
+
this.addRoute('put', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)
|
|
133
|
+
this.addRoute('patch', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)
|
|
134
|
+
this.addRoute('delete', `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Named route URL generator
|
|
139
|
+
*
|
|
140
|
+
* @param name
|
|
141
|
+
* @param params
|
|
142
|
+
* @returns
|
|
143
|
+
*/
|
|
144
|
+
route (name: string, params: Record<string, string> = {}): string | undefined {
|
|
145
|
+
const found = this.routes.find(r => r.name === name)
|
|
146
|
+
if (!found) return undefined
|
|
147
|
+
|
|
148
|
+
let url = found.path
|
|
149
|
+
for (const [key, value] of Object.entries(params)) {
|
|
150
|
+
url = url.replace(`:${key}`, value)
|
|
151
|
+
}
|
|
152
|
+
return url
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Grouping
|
|
157
|
+
*
|
|
158
|
+
* @param options
|
|
159
|
+
* @param callback
|
|
160
|
+
*/
|
|
161
|
+
group (options: { prefix?: string; middleware?: EventHandler[] }, callback: () => void) {
|
|
162
|
+
const prevPrefix = this.groupPrefix
|
|
163
|
+
const prevMiddleware = [...this.groupMiddleware]
|
|
164
|
+
|
|
165
|
+
this.groupPrefix += options.prefix || ''
|
|
166
|
+
this.groupMiddleware.push(...(options.middleware || []))
|
|
167
|
+
|
|
168
|
+
callback()
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Restore state after group
|
|
172
|
+
*/
|
|
173
|
+
this.groupPrefix = prevPrefix
|
|
174
|
+
this.groupMiddleware = prevMiddleware
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
middleware (path: string, handler: Middleware, opts?: MiddlewareOptions) {
|
|
178
|
+
this.h3App.use(path, handler, opts)
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by barrelsby.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export * from './Controller';
|
|
6
|
+
export * from './Route';
|
|
7
|
+
export * from './Router';
|
|
8
|
+
export * from './Decorators/ApiResource';
|
|
9
|
+
export * from './Decorators/Controller';
|
|
10
|
+
export * from './Decorators/Get';
|
|
11
|
+
export * from './Decorators/Middleware';
|
|
12
|
+
export * from './Decorators/Post';
|
|
13
|
+
export * from './Providers/AssetsServiceProvider';
|
|
14
|
+
export * from './Providers/RouteServiceProvider';
|
package/tests/.gitkeep
ADDED
|
File without changes
|
package/tsconfig.json
ADDED