@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 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;ACCA,kBAAgD;AAGhD,qBAA0B;AAWnB,IAAMA,SAAN,MAAMA;EAdb,OAcaA;;;;;EACDC,SAA4B,CAAA;EAC5BC,cAAc;EACdC,kBAAkC,CAAA;EAE1C,YAAoBC,OAAmBC,KAAkB;SAArCD,QAAAA;SAAmBC,MAAAA;EAAoB;;;;;;;;EASnDC,eAAgBC,SAAuBC,aAA+B,CAAA,GAAI;AAC9E,WAAO,OAAOC,UAAAA;AACV,YAAMC,SAAS,IAAIC,mBAAOH,UAAAA;AAC1B,aAAOE,OAAOE,OAAOH,OAAO,CAACI,QAAQC,QAAQC,QAAQR,QAAQM,GAAAA,CAAAA,CAAAA;IACjE;EACJ;;;;;;;;;;EAWQG,SACJC,QACAC,OACAX,SACAY,MACAX,aAA+B,CAAA,GACjC;AACE,UAAMY,WAAW,GAAG,KAAKlB,WAAW,GAAGgB,KAAAA,GAAOG,QAAQ,QAAQ,GAAA;AAC9D,SAAKpB,OAAOqB,KAAK;MAAEL;MAAQC,MAAME;MAAUD;MAAMZ;IAAQ,CAAA;AACzD,SAAKH,MAAMa,MAAAA,EAAiBG,UAAU,KAAKd,eAAeC,SAASC,UAAAA,CAAAA;EACvE;EAEQe,2BACJhB,SACAiB,YACY;AACZ,QAAI,OAAOjB,YAAY,cAAeA,QAAgBkB,qBAAqBC,wBAAY;AACnF,aAAO,CAACb,QAAAA;AACJ,cAAMc,aAAa,IAAKpB,QAA+C,KAAKF,GAAG;AAC/E,cAAMuB,SAAUJ,cAAc;AAE9B,YAAI,OAAOG,WAAWC,MAAAA,MAAY,YAAY;AAC1C,gBAAM,IAAIC,MAAM,WAAWD,MAAAA,6BAAmCrB,QAAQY,IAAI,EAAE;QAChF;AAEA,eAAOQ,WAAWC,MAAAA,EAAQf,GAAAA;MAC9B;IACJ;AAEA,WAAON;EACX;EAGAuB,IACIZ,OACAX,SACAiB,YAAqBL,MAAeX,aAA+B,CAAA,GACrE;AACE,SAAKQ,SAAS,OAAOE,OAAM,KAAKK,2BAA2BhB,SAASiB,UAAAA,GAAaL,MAAMX,UAAAA;EAC3F;EAEAuB,KACIb,OACAX,SACAiB,YAAqBL,MAAeX,aAA+B,CAAA,GACrE;AACE,SAAKQ,SAAS,QAAQE,OAAM,KAAKK,2BAA2BhB,SAASiB,UAAAA,GAAaL,MAAMX,UAAAA;EAC5F;EAEAwB,IACId,OACAX,SACAiB,YAAqBL,MAAeX,aAA+B,CAAA,GACrE;AACE,SAAKQ,SAAS,OAAOE,OAAM,KAAKK,2BAA2BhB,SAASiB,UAAAA,GAAaL,MAAMX,UAAAA;EAC3F;EAEAyB,OACIf,OACAX,SACAiB,YAAqBL,MAAeX,aAA+B,CAAA,GACrE;AACE,SAAKQ,SAAS,UAAUE,OAAM,KAAKK,2BAA2BhB,SAASiB,UAAAA,GAAaL,MAAMX,UAAAA;EAC9F;;;;;;;EAQA0B,YACIhB,OACAQ,aACAlB,aAA+B,CAAA,GACjC;AACEU,IAAAA,QAAOA,MAAKG,QAAQ,OAAO,GAAA;AAE3B,UAAMF,WAAOgB,0BAAUjB,OAAM,GAAA;AAC7B,UAAMkB,WAAW,IAAIlB,KAAAA,GAAOG,QAAQ,QAAQ,GAAA;AAE5C,UAAMM,aAAa,IAAID,YAAW,KAAKrB,GAAG;AAE1C,SAAKW,SAAS,OAAOoB,UAAUT,WAAWU,MAAMC,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,UAAcX,UAAAA;AACnF,SAAKQ,SAAS,QAAQoB,UAAUT,WAAWY,MAAMD,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,UAAcX,UAAAA;AACpF,SAAKQ,SAAS,OAAO,GAAGoB,QAAAA,QAAgBT,WAAWa,KAAKF,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,SAAaX,UAAAA;AAC1F,SAAKQ,SAAS,OAAO,GAAGoB,QAAAA,QAAgBT,WAAWc,OAAOH,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,WAAeX,UAAAA;AAC9F,SAAKQ,SAAS,SAAS,GAAGoB,QAAAA,QAAgBT,WAAWc,OAAOH,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,WAAeX,UAAAA;AAChG,SAAKQ,SAAS,UAAU,GAAGoB,QAAAA,QAAgBT,WAAWe,QAAQJ,KAAKX,UAAAA,GAAa,GAAGR,IAAAA,YAAgBX,UAAAA;EACvG;;;;;;;;EASAmC,MAAOxB,MAAcyB,SAAiC,CAAC,GAAuB;AAC1E,UAAMC,QAAQ,KAAK5C,OAAO6C,KAAKC,CAAAA,MAAKA,EAAE5B,SAASA,IAAAA;AAC/C,QAAI,CAAC0B,MAAO,QAAOG;AAEnB,QAAIC,MAAMJ,MAAM3B;AAChB,eAAW,CAACgC,KAAKC,KAAAA,KAAUC,OAAOC,QAAQT,MAAAA,GAAS;AAC/CK,YAAMA,IAAI5B,QAAQ,IAAI6B,GAAAA,IAAOC,KAAAA;IACjC;AACA,WAAOF;EACX;;;;;;;EAQAK,MAAOC,SAA2DC,UAAsB;AACpF,UAAMC,aAAa,KAAKvD;AACxB,UAAMwD,iBAAiB;SAAI,KAAKvD;;AAEhC,SAAKD,eAAeqD,QAAQI,UAAU;AACtC,SAAKxD,gBAAgBmB,KAAI,GAAKiC,QAAQ/C,cAAc,CAAA,CAAE;AAEtDgD,aAAAA;AAKA,SAAKtD,cAAcuD;AACnB,SAAKtD,kBAAkBuD;EAC3B;EAEAlD,WAAYU,OAAcX,SAAqBqD,MAA0B;AACrE,SAAKxD,MAAMyD,IAAI3C,OAAMX,SAASqD,IAAAA;EAClC;AACJ;;;ACnLA,sBAA+B;AAE/B,IAAAE,eAAgC;AAChC,IAAAC,kBAAuB;AACvB,uBAAqB;AACrB,gBAA4B;AAC5B,qBAAyB;AAOlB,IAAMC,wBAAN,cAAoCC,6BAAAA;EAb3C,OAa2CA;;;EACvCC,WAAY;AACR,UAAMC,MAAM,KAAKA,IAAIC,KAAK,QAAA;AAC1B,UAAMC,SAAS,KAAKF,IAAIC,KAAK,QAAA;AAC7B,UAAME,WAAWD,OAAOE,IAAI,YAAA;AAC5B,UAAMC,aAAa,KAAKL,IAAIM,QAAQ,QAAA;AAEpCN,QAAIO,WAAW,IAAIJ,SAASK,WAAW,OAAO,CAACC,UAAAA;AAC3C,iBAAOC,uBAAYD,OAAO;QACtBE,YAAY;UAAC;;QACbC,aAAa,wBAACC,OAAAA;AACV,gBAAMC,QAAQD,GAAGE,QAAQ,IAAIZ,SAASK,WAAW,KAAK,EAAA;AACtD,qBAAOQ,8BAASC,2BAAKC,wBAAOb,YAAYS,KAAAA,GAAQA,KAAAA,CAAAA;QACpD,GAHa;QAIbK,SAAS,8BAAON,OAAAA;AACZ,gBAAMC,QAAQD,GAAGE,QAAQ,IAAIZ,SAASK,WAAW,KAAK,EAAA;AACtD,gBAAMY,QAAQ,UAAMC,0BAAKJ,2BAAKC,wBAAOb,YAAYS,KAAAA,GAAQA,KAAAA,CAAAA,EAAQQ,MAAM,MAAA;UAAQ,CAAA;AAC/E,cAAIF,OAAOG,OAAAA,GAAU;AACjB,mBAAO;cACHC,MAAMJ,MAAMI;cACZC,OAAOL,MAAMM;YACjB;UACJ;QACJ,GATS;MAUb,CAAA;IACJ,CAAA;AAEA,SAAK1B,IAAI2B,UAAU,SAAS,MAAA;AACxB,aAAO,CAACC,KAAaC,MAAM,OAAE;AACzB,YAAI;AACAC,2CAASb,2BAAKC,wBAAOb,YAAYuB,GAAAA,GAAMA,GAAAA,CAAAA;QAC3C,QAAQ;AACJA,gBAAMC;QACV;AAEA,mBAAOZ,uBAAKd,SAASK,aAAaoB,GAAAA;MACtC;IACJ,CAAA;EACJ;AACJ;;;ACnDA,IAAAG,eAAgC;AAChC,IAAAC,oBAAiB;AACjB,IAAAC,mBAAwB;AAWjB,IAAMC,uBAAN,cAAmCC,6BAAAA;EAd1C,OAc0CA;;;EACtCC,WAAY;AACR,SAAKC,IAAIC,UAAU,UAAU,MAAA;AACzB,YAAMC,QAAQ,KAAKF,IAAIG,KAAK,UAAA;AAC5B,aAAO,IAAIC,OAAOF,OAAO,KAAKF,GAAG;IACrC,CAAA;EACJ;;;;EAKA,MAAMK,OAAQ;AACV,QAAI;AACA,YAAMC,YAAY,KAAKN,IAAIO,QAAQ,QAAA;AAEnC,YAAMC,QAAQ,UAAMC,0BAAQH,SAAAA;AAE5B,eAASI,IAAI,GAAGA,IAAIF,MAAMG,QAAQD,KAAK;AACnC,cAAME,eAAe,MAAM,OAAOC,kBAAAA,QAAKC,KAAKR,WAAWE,MAAME,CAAAA,CAAE;AAE/D,YAAI,OAAOE,aAAaG,YAAY,YAAY;AAC5C,gBAAMC,SAAS,KAAKhB,IAAIG,KAAK,QAAA;AAC7BS,uBAAaG,QAAQC,MAAAA;QACzB;MACJ;IACJ,SAASC,GAAG;AACRC,cAAQC,KAAK,0CAA0CF,CAAAA;IAC3D;EACJ;AACJ;","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"]}
@@ -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 };
@@ -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
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist"
5
+ },
6
+ "include": ["src"],
7
+ "exclude": ["dist", "node_modules"]
8
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm', 'cjs'],
6
+ dts: true,
7
+ sourcemap: true,
8
+ clean: true
9
+ })