@h3ravel/core 1.7.3 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,438 +1,560 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
1
+ import "reflect-metadata";
2
+ import { Logger, PathLoader } from "@h3ravel/shared";
3
+ import { dd, dump } from "@h3ravel/support";
4
+ import path from "node:path";
5
+ import chalk from "chalk";
6
+ import { detect } from "detect-port";
7
+ import dotenv from "dotenv";
8
+ import dotenvExpand from "dotenv-expand";
9
+ import { Edge } from "edge.js";
3
10
 
4
- // src/Container.ts
11
+ //#region src/Container.ts
5
12
  var Container = class {
6
- static {
7
- __name(this, "Container");
8
- }
9
- bindings = /* @__PURE__ */ new Map();
10
- singletons = /* @__PURE__ */ new Map();
11
- /**
12
- * Check if the target has any decorators
13
- *
14
- * @param target
15
- * @returns
16
- */
17
- static hasAnyDecorator(target) {
18
- if (Reflect.getMetadataKeys(target).length > 0) return true;
19
- const paramLength = target.length;
20
- for (let i = 0; i < paramLength; i++) {
21
- if (Reflect.getMetadataKeys(target, `__param_${i}`).length > 0) {
22
- return true;
23
- }
24
- }
25
- return false;
26
- }
27
- bind(key, factory) {
28
- this.bindings.set(key, factory);
29
- }
30
- /**
31
- * Bind a singleton service to the container
32
- */
33
- singleton(key, factory) {
34
- this.bindings.set(key, () => {
35
- if (!this.singletons.has(key)) {
36
- this.singletons.set(key, factory());
37
- }
38
- return this.singletons.get(key);
39
- });
40
- }
41
- /**
42
- * Resolve a service from the container
43
- */
44
- make(key) {
45
- if (this.bindings.has(key)) {
46
- return this.bindings.get(key)();
47
- }
48
- if (typeof key === "function") {
49
- return this.build(key);
50
- }
51
- throw new Error(`No binding found for key: ${typeof key === "string" ? key : key?.name}`);
52
- }
53
- /**
54
- * Automatically build a class with constructor dependency injection
55
- */
56
- build(ClassType) {
57
- let dependencies = [];
58
- if (Array.isArray(ClassType.__inject__)) {
59
- dependencies = ClassType.__inject__.map((alias) => {
60
- return this.make(alias);
61
- });
62
- } else {
63
- const paramTypes = Reflect.getMetadata("design:paramtypes", ClassType) || [];
64
- dependencies = paramTypes.map((dep) => this.make(dep));
65
- }
66
- return new ClassType(...dependencies);
67
- }
68
- /**
69
- * Check if a service is registered
70
- */
71
- has(key) {
72
- return this.bindings.has(key);
73
- }
13
+ bindings = /* @__PURE__ */ new Map();
14
+ singletons = /* @__PURE__ */ new Map();
15
+ /**
16
+ * Check if the target has any decorators
17
+ *
18
+ * @param target
19
+ * @returns
20
+ */
21
+ static hasAnyDecorator(target) {
22
+ if (Reflect.getMetadataKeys(target).length > 0) return true;
23
+ const paramLength = target.length;
24
+ for (let i = 0; i < paramLength; i++) if (Reflect.getMetadataKeys(target, `__param_${i}`).length > 0) return true;
25
+ return false;
26
+ }
27
+ bind(key, factory) {
28
+ this.bindings.set(key, factory);
29
+ }
30
+ /**
31
+ * Bind a singleton service to the container
32
+ */
33
+ singleton(key, factory) {
34
+ this.bindings.set(key, () => {
35
+ if (!this.singletons.has(key)) this.singletons.set(key, factory());
36
+ return this.singletons.get(key);
37
+ });
38
+ }
39
+ /**
40
+ * Resolve a service from the container
41
+ */
42
+ make(key) {
43
+ /**
44
+ * Direct factory binding
45
+ */
46
+ if (this.bindings.has(key)) return this.bindings.get(key)();
47
+ /**
48
+ * If this is a class constructor, auto-resolve via reflection
49
+ */
50
+ if (typeof key === "function") return this.build(key);
51
+ throw new Error(`No binding found for key: ${typeof key === "string" ? key : key?.name}`);
52
+ }
53
+ /**
54
+ * Automatically build a class with constructor dependency injection
55
+ */
56
+ build(ClassType) {
57
+ let dependencies = [];
58
+ if (Array.isArray(ClassType.__inject__)) dependencies = ClassType.__inject__.map((alias) => {
59
+ return this.make(alias);
60
+ });
61
+ else dependencies = (Reflect.getMetadata("design:paramtypes", ClassType) || []).map((dep) => this.make(dep));
62
+ return new ClassType(...dependencies);
63
+ }
64
+ /**
65
+ * Check if a service is registered
66
+ */
67
+ has(key) {
68
+ return this.bindings.has(key);
69
+ }
74
70
  };
75
71
 
76
- // src/Application.ts
77
- import { PathLoader } from "@h3ravel/shared";
72
+ //#endregion
73
+ //#region src/Di/ContainerResolver.ts
74
+ var ContainerResolver = class ContainerResolver {
75
+ constructor(app) {
76
+ this.app = app;
77
+ }
78
+ async resolveMethodParams(instance, method, _default) {
79
+ /**
80
+ * Get param types for instance method
81
+ */
82
+ let params = Reflect.getMetadata("design:paramtypes", instance, String(method)) || [];
83
+ /**
84
+ * Ensure that the Application class is always available
85
+ */
86
+ if (params.length < 1 && _default) params = [_default];
87
+ /**
88
+ * Resolve the bound dependencies
89
+ */
90
+ let args = params.filter((e) => ContainerResolver.isClass(e)).map((type) => {
91
+ return this.app.make(type);
92
+ });
93
+ return new Promise((resolve) => {
94
+ resolve(instance[method](...args));
95
+ });
96
+ }
97
+ static isClass(C) {
98
+ return typeof C === "function" && C.prototype !== void 0 && Object.toString.call(C).substring(0, 5) === "class";
99
+ }
100
+ };
78
101
 
79
- // src/Registerer.ts
80
- import { dd, dump } from "@h3ravel/support";
81
- var Registerer = class {
82
- static {
83
- __name(this, "Registerer");
84
- }
85
- static register() {
86
- globalThis.dd = dd;
87
- globalThis.dump = dump;
88
- }
102
+ //#endregion
103
+ //#region src/Registerer.ts
104
+ var Registerer = class Registerer {
105
+ constructor(app) {
106
+ this.app = app;
107
+ }
108
+ static register(app) {
109
+ new Registerer(app).bootRegister();
110
+ }
111
+ bootRegister() {
112
+ globalThis.dd = dd;
113
+ globalThis.dump = dump;
114
+ globalThis.app_path = (path$1) => this.appPath(path$1);
115
+ globalThis.base_path = (path$1) => this.basePath(path$1);
116
+ globalThis.public_path = (path$1) => this.publicPath(path$1);
117
+ globalThis.storage_path = (path$1) => this.storagePath(path$1);
118
+ globalThis.database_path = (path$1) => this.databasePath(path$1);
119
+ }
120
+ appPath(path$1) {
121
+ return this.app.getPath("base", path.join(`/${process.env.SRC_PATH ?? "src"}/`.replace(/([^:]\/)\/+/g, "$1"), "app", path$1 ?? ""));
122
+ }
123
+ basePath(path$1) {
124
+ return this.app.getPath("base", path$1);
125
+ }
126
+ publicPath(path$1) {
127
+ return this.app.getPath("public", path$1);
128
+ }
129
+ storagePath(path$1) {
130
+ return this.app.getPath("base", path.join("storage", path$1 ?? ""));
131
+ }
132
+ databasePath(path$1) {
133
+ return this.app.getPath("database", path$1);
134
+ }
89
135
  };
90
136
 
91
- // src/Application.ts
92
- import dotenv from "dotenv";
93
- import path from "path";
94
- var Application = class _Application extends Container {
95
- static {
96
- __name(this, "Application");
97
- }
98
- paths = new PathLoader();
99
- booted = false;
100
- versions = {
101
- app: "0",
102
- ts: "0"
103
- };
104
- basePath;
105
- providers = [];
106
- externalProviders = [];
107
- constructor(basePath) {
108
- super();
109
- this.basePath = basePath;
110
- this.setPath("base", basePath);
111
- this.loadOptions();
112
- this.registerBaseBindings();
113
- Registerer.register();
114
- dotenv.config({
115
- quiet: true
116
- });
117
- }
118
- /**
119
- * Register core bindings into the container
120
- */
121
- registerBaseBindings() {
122
- this.bind(_Application, () => this);
123
- this.bind("path.base", () => this.basePath);
124
- this.bind("load.paths", () => this.paths);
125
- }
126
- /**
127
- * Dynamically register all configured providers
128
- */
129
- async registerConfiguredProviders() {
130
- const providers = await this.getAllProviders();
131
- for (const ProviderClass of providers) {
132
- if (!ProviderClass) continue;
133
- const provider = new ProviderClass(this);
134
- await this.register(provider);
135
- }
136
- }
137
- async loadOptions() {
138
- const app = await this.safeImport(this.getPath("base", "package.json"));
139
- const core = await this.safeImport("../package.json");
140
- if (app && app.dependencies) {
141
- this.versions.app = app.dependencies["@h3ravel/core"];
142
- }
143
- if (core && core.devDependencies) {
144
- this.versions.ts = app.devDependencies.typescript;
145
- }
146
- }
147
- /**
148
- * Load default and optional providers dynamically
149
- *
150
- * Auto-Registration Behavior
151
- *
152
- * Minimal App: Loads only core, config, http, router by default.
153
- * Full-Stack App: Installs database, mail, queue, cache they self-register via their providers.
154
- */
155
- async getConfiguredProviders() {
156
- return [
157
- (await import("./index.js")).CoreServiceProvider,
158
- (await import("./index.js")).ViewServiceProvider
159
- ];
160
- }
161
- async getAllProviders() {
162
- const coreProviders = await this.getConfiguredProviders();
163
- const allProviders = [
164
- ...coreProviders,
165
- ...this.externalProviders
166
- ];
167
- const uniqueProviders = Array.from(new Set(allProviders));
168
- return this.sortProviders(uniqueProviders);
169
- }
170
- sortProviders(providers) {
171
- const priorityMap = /* @__PURE__ */ new Map();
172
- providers.forEach((Provider) => {
173
- priorityMap.set(Provider.name, Provider.priority ?? 0);
174
- });
175
- providers.forEach((Provider) => {
176
- const order = Provider.order;
177
- if (!order) return;
178
- const [direction, target] = order.split(":");
179
- const targetPriority = priorityMap.get(target) ?? 0;
180
- if (direction === "before") {
181
- priorityMap.set(Provider.name, targetPriority - 1);
182
- } else if (direction === "after") {
183
- priorityMap.set(Provider.name, targetPriority + 1);
184
- }
185
- });
186
- const sorted = providers.sort((A, B) => (priorityMap.get(B.name) ?? 0) - (priorityMap.get(A.name) ?? 0));
187
- if (process.env.APP_DEBUG === "true") {
188
- console.table(sorted.map((P) => ({
189
- Provider: P.name,
190
- Priority: priorityMap.get(P.name),
191
- Order: P.order || "N/A"
192
- })));
193
- }
194
- return sorted;
195
- }
196
- registerProviders(providers) {
197
- this.externalProviders.push(...providers);
198
- }
199
- /**
200
- * Register a provider
201
- */
202
- async register(provider) {
203
- await provider.register();
204
- this.providers.push(provider);
205
- }
206
- /**
207
- * Boot all providers after registration
208
- */
209
- async boot() {
210
- if (this.booted) return;
211
- for (const provider of this.providers) {
212
- if (provider.boot) {
213
- await provider.boot();
214
- }
215
- }
216
- this.booted = true;
217
- }
218
- /**
219
- * Attempt to dynamically import an optional module
220
- */
221
- async safeImport(moduleName) {
222
- try {
223
- const mod = await import(moduleName);
224
- return mod.default ?? mod ?? {};
225
- } catch {
226
- return null;
227
- }
228
- }
229
- /**
230
- * Get the base path of the app
231
- *
232
- * @returns
233
- */
234
- getBasePath() {
235
- return this.basePath;
236
- }
237
- /**
238
- * Dynamically retrieves a path property from the class.
239
- * Any property ending with "Path" is accessible automatically.
240
- *
241
- * @param name - The base name of the path property
242
- * @returns
243
- */
244
- getPath(name, pth) {
245
- return path.join(this.paths.getPath(name, this.basePath), pth ?? "");
246
- }
247
- /**
248
- * Programatically set the paths.
249
- *
250
- * @param name - The base name of the path property
251
- * @param path - The new path
252
- * @returns
253
- */
254
- setPath(name, path2) {
255
- return this.paths.setPath(name, path2, this.basePath);
256
- }
257
- /**
258
- * Returns the installed version of the system core and typescript.
259
- *
260
- * @returns
261
- */
262
- getVersion(key) {
263
- return this.versions[key]?.replaceAll(/\^|~/g, "");
264
- }
137
+ //#endregion
138
+ //#region src/Application.ts
139
+ var Application = class Application extends Container {
140
+ paths = new PathLoader();
141
+ tries = 0;
142
+ booted = false;
143
+ versions = {
144
+ app: "0",
145
+ ts: "0"
146
+ };
147
+ basePath;
148
+ providers = [];
149
+ externalProviders = [];
150
+ /**
151
+ * List of registered console commands
152
+ */
153
+ registeredCommands = [];
154
+ constructor(basePath) {
155
+ super();
156
+ dotenvExpand.expand(dotenv.config({ quiet: true }));
157
+ this.basePath = basePath;
158
+ this.setPath("base", basePath);
159
+ this.loadOptions();
160
+ this.registerBaseBindings();
161
+ Registerer.register(this);
162
+ }
163
+ /**
164
+ * Register core bindings into the container
165
+ */
166
+ registerBaseBindings() {
167
+ this.bind(Application, () => this);
168
+ this.bind("path.base", () => this.basePath);
169
+ this.bind("load.paths", () => this.paths);
170
+ }
171
+ /**
172
+ * Dynamically register all configured providers
173
+ */
174
+ async registerConfiguredProviders() {
175
+ const providers = await this.getAllProviders();
176
+ for (const ProviderClass of providers) {
177
+ if (!ProviderClass) continue;
178
+ const provider = new ProviderClass(this);
179
+ await this.register(provider);
180
+ }
181
+ }
182
+ async loadOptions() {
183
+ const app = await this.safeImport(this.getPath("base", "package.json"));
184
+ const core = await this.safeImport("../package.json");
185
+ if (app && app.dependencies) this.versions.app = app.dependencies["@h3ravel/core"];
186
+ if (core && core.devDependencies) this.versions.ts = app.devDependencies.typescript;
187
+ }
188
+ /**
189
+ * Get all registered providers
190
+ */
191
+ getRegisteredProviders() {
192
+ return this.providers;
193
+ }
194
+ /**
195
+ * Load default and optional providers dynamically
196
+ *
197
+ * Auto-Registration Behavior
198
+ *
199
+ * Minimal App: Loads only core, config, http, router by default.
200
+ * Full-Stack App: Installs database, mail, queue, cache → they self-register via their providers.
201
+ */
202
+ async getConfiguredProviders() {
203
+ return [(await import("./index.js")).CoreServiceProvider, (await import("./index.js")).ViewServiceProvider];
204
+ }
205
+ async getAllProviders() {
206
+ const allProviders = [...await this.getConfiguredProviders(), ...this.externalProviders];
207
+ /**
208
+ * Deduplicate by class reference
209
+ */
210
+ const uniqueProviders = Array.from(new Set(allProviders));
211
+ return this.sortProviders(uniqueProviders);
212
+ }
213
+ sortProviders(providers) {
214
+ const priorityMap = /* @__PURE__ */ new Map();
215
+ /**
216
+ * Base priority (default 0)
217
+ */
218
+ providers.forEach((Provider) => {
219
+ priorityMap.set(Provider.name, Provider.priority ?? 0);
220
+ });
221
+ /**
222
+ * Handle before/after adjustments
223
+ */
224
+ providers.forEach((Provider) => {
225
+ const order = Provider.order;
226
+ if (!order) return;
227
+ const [direction, target] = order.split(":");
228
+ const targetPriority = priorityMap.get(target) ?? 0;
229
+ if (direction === "before") priorityMap.set(Provider.name, targetPriority - 1);
230
+ else if (direction === "after") priorityMap.set(Provider.name, targetPriority + 1);
231
+ });
232
+ /**
233
+ * Service providers sorted based on thier name and priority
234
+ */
235
+ const sorted = providers.sort((A, B) => (priorityMap.get(B.name) ?? 0) - (priorityMap.get(A.name) ?? 0));
236
+ /**
237
+ * If debug is enabled, let's show the loaded service provider info
238
+ */
239
+ if (process.env.APP_DEBUG === "true" && process.env.EXTENDED_DEBUG !== "false" && !sorted.some((e) => e.console)) {
240
+ console.table(sorted.map((P) => ({
241
+ Provider: P.name,
242
+ Priority: priorityMap.get(P.name),
243
+ Order: P.order || "N/A"
244
+ })));
245
+ console.info(`Set ${chalk.bgCyan(" APP_DEBUG = false ")} in your .env file to hide this information`, "\n");
246
+ }
247
+ return sorted;
248
+ }
249
+ registerProviders(providers) {
250
+ this.externalProviders.push(...providers);
251
+ }
252
+ /**
253
+ * Register a provider
254
+ */
255
+ async register(provider) {
256
+ await new ContainerResolver(this).resolveMethodParams(provider, "register", this);
257
+ if (provider.registeredCommands && provider.registeredCommands.length > 0) this.registeredCommands.push(...provider.registeredCommands);
258
+ this.providers.push(provider);
259
+ }
260
+ /**
261
+ * checks if the application is running in CLI
262
+ */
263
+ runningInConsole() {
264
+ return typeof process !== "undefined" && !!process.stdout && !!process.stdin;
265
+ }
266
+ getRuntimeEnv() {
267
+ if (typeof window !== "undefined" && typeof document !== "undefined") return "browser";
268
+ if (typeof process !== "undefined" && process.versions?.node) return "node";
269
+ return "unknown";
270
+ }
271
+ /**
272
+ * Boot all service providers after registration
273
+ */
274
+ async boot() {
275
+ if (this.booted) return;
276
+ for (const provider of this.providers) if (provider.boot) if (Container.hasAnyDecorator(provider.boot))
277
+ /**
278
+ * If the service provider is decorated use the IoC container
279
+ */
280
+ await this.make(provider.boot);
281
+ else
282
+ /**
283
+ * Otherwise instantiate manually so that we can at least
284
+ * pass the app instance
285
+ */
286
+ await provider.boot(this);
287
+ this.booted = true;
288
+ }
289
+ /**
290
+ * Fire up the developement server using the user provided arguments
291
+ *
292
+ * Port will be auto assigned if provided one is not available
293
+ *
294
+ * @param h3App The current H3 app instance
295
+ * @param preferedPort If provided, this will overide the port set in the evironment
296
+ */
297
+ async fire(h3App, preferedPort) {
298
+ const serve = this.make("http.serve");
299
+ const port = preferedPort ?? env("PORT", 3e3);
300
+ const tries = env("RETRIES", 1);
301
+ const hostname = env("HOSTNAME", "localhost");
302
+ try {
303
+ const realPort = await detect(port);
304
+ if (port == realPort) {
305
+ const server = serve(h3App, {
306
+ port,
307
+ hostname,
308
+ silent: true
309
+ });
310
+ Logger.parse([[`🚀 H3ravel running at:`, "green"], [`${server.options.protocol ?? "http"}://${server.options.hostname}:${server.options.port}`, "cyan"]]);
311
+ } else if (this.tries <= tries) {
312
+ await this.fire(h3App, realPort);
313
+ this.tries++;
314
+ } else Logger.parse([["ERROR:", "bgRed"], ["No free port available", "red"]]);
315
+ } catch (e) {
316
+ Logger.parse([
317
+ ["An error occured", "bgRed"],
318
+ [e.message, "red"],
319
+ [e.stack, "red"]
320
+ ], "\n");
321
+ }
322
+ }
323
+ /**
324
+ * Attempt to dynamically import an optional module
325
+ */
326
+ async safeImport(moduleName) {
327
+ try {
328
+ const mod = await import(moduleName);
329
+ return mod.default ?? mod ?? {};
330
+ } catch {
331
+ return null;
332
+ }
333
+ }
334
+ /**
335
+ * Get the base path of the app
336
+ *
337
+ * @returns
338
+ */
339
+ getBasePath() {
340
+ return this.basePath;
341
+ }
342
+ /**
343
+ * Dynamically retrieves a path property from the class.
344
+ * Any property ending with "Path" is accessible automatically.
345
+ *
346
+ * @param name - The base name of the path property
347
+ * @returns
348
+ */
349
+ getPath(name, suffix) {
350
+ return path.join(this.paths.getPath(name, this.basePath), suffix ?? "");
351
+ }
352
+ /**
353
+ * Programatically set the paths.
354
+ *
355
+ * @param name - The base name of the path property
356
+ * @param path - The new path
357
+ * @returns
358
+ */
359
+ setPath(name, path$1) {
360
+ return this.paths.setPath(name, path$1, this.basePath);
361
+ }
362
+ /**
363
+ * Returns the installed version of the system core and typescript.
364
+ *
365
+ * @returns
366
+ */
367
+ getVersion(key) {
368
+ return this.versions[key]?.replaceAll(/\^|~/g, "");
369
+ }
265
370
  };
266
371
 
267
- // src/Controller.ts
372
+ //#endregion
373
+ //#region src/Controller.ts
374
+ /**
375
+ * Base controller class
376
+ */
268
377
  var Controller = class {
269
- static {
270
- __name(this, "Controller");
271
- }
272
- app;
273
- constructor(app) {
274
- this.app = app;
275
- }
276
- show(..._ctx) {
277
- return;
278
- }
279
- index(..._ctx) {
280
- return;
281
- }
282
- store(..._ctx) {
283
- return;
284
- }
285
- update(..._ctx) {
286
- return;
287
- }
288
- destroy(..._ctx) {
289
- return;
290
- }
378
+ app;
379
+ constructor(app) {
380
+ this.app = app;
381
+ }
382
+ show(..._ctx) {}
383
+ index(..._ctx) {}
384
+ store(..._ctx) {}
385
+ update(..._ctx) {}
386
+ destroy(..._ctx) {}
291
387
  };
292
388
 
293
- // src/Di/Inject.ts
389
+ //#endregion
390
+ //#region src/Di/Inject.ts
294
391
  function Inject(...dependencies) {
295
- return function(target) {
296
- target.__inject__ = dependencies;
297
- };
392
+ return function(target) {
393
+ target.__inject__ = dependencies;
394
+ };
298
395
  }
299
- __name(Inject, "Inject");
396
+ /**
397
+ * Allows binding dependencies to both class and class methods
398
+ *
399
+ * @returns
400
+ */
300
401
  function Injectable() {
301
- return (...args) => {
302
- if (args.length === 1) {
303
- void args[0];
304
- }
305
- if (args.length === 3) {
306
- void args[0];
307
- void args[1];
308
- void args[2];
309
- }
310
- };
402
+ return (...args) => {
403
+ if (args.length === 1) args[0];
404
+ if (args.length === 3) {
405
+ args[0];
406
+ args[1];
407
+ args[2];
408
+ }
409
+ };
311
410
  }
312
- __name(Injectable, "Injectable");
313
411
 
314
- // src/Http/Kernel.ts
412
+ //#endregion
413
+ //#region src/Http/Kernel.ts
414
+ /**
415
+ * Kernel class handles middleware execution and response transformations.
416
+ * It acts as the core middleware pipeline for HTTP requests.
417
+ */
315
418
  var Kernel = class {
316
- static {
317
- __name(this, "Kernel");
318
- }
319
- context;
320
- middleware;
321
- /**
322
- * @param context - A factory function that converts an H3Event into an HttpContext.
323
- * @param middleware - An array of middleware classes that will be executed in sequence.
324
- */
325
- constructor(context, middleware = []) {
326
- this.context = context;
327
- this.middleware = middleware;
328
- }
329
- /**
330
- * Handles an incoming request and passes it through middleware before invoking the next handler.
331
- *
332
- * @param event - The raw H3 event object.
333
- * @param next - A callback function that represents the next layer (usually the controller or final handler).
334
- * @returns A promise resolving to the result of the request pipeline.
335
- */
336
- async handle(event, next) {
337
- const ctx = this.context(event);
338
- const { app } = ctx.request;
339
- app.bind("view", () => async (template, params) => {
340
- const edge = app.make("edge");
341
- return ctx.response.html(await edge.render(template, params));
342
- });
343
- const result = await this.runMiddleware(ctx, () => next(ctx));
344
- if (result !== void 0 && this.isPlainObject(result)) {
345
- event.res.headers.set("Content-Type", "application/json; charset=UTF-8");
346
- }
347
- return result;
348
- }
349
- /**
350
- * Sequentially runs middleware in the order they were registered.
351
- *
352
- * @param context - The standardized HttpContext.
353
- * @param next - Callback to execute when middleware completes.
354
- * @returns A promise resolving to the final handler's result.
355
- */
356
- async runMiddleware(context, next) {
357
- let index = -1;
358
- const runner = /* @__PURE__ */ __name(async (i) => {
359
- if (i <= index) throw new Error("next() called multiple times");
360
- index = i;
361
- const middleware = this.middleware[i];
362
- if (middleware) {
363
- return middleware.handle(context, () => runner(i + 1));
364
- } else {
365
- return next(context);
366
- }
367
- }, "runner");
368
- return runner(0);
369
- }
370
- /**
371
- * Utility function to determine if a value is a plain object or array.
372
- *
373
- * @param value - The value to check.
374
- * @returns True if the value is a plain object or array, otherwise false.
375
- */
376
- isPlainObject(value) {
377
- return typeof value === "object" && value !== null && (value.constructor === Object || value.constructor === Array);
378
- }
419
+ /**
420
+ * @param context - A factory function that converts an H3Event into an HttpContext.
421
+ * @param middleware - An array of middleware classes that will be executed in sequence.
422
+ */
423
+ constructor(context, middleware = []) {
424
+ this.context = context;
425
+ this.middleware = middleware;
426
+ }
427
+ /**
428
+ * Handles an incoming request and passes it through middleware before invoking the next handler.
429
+ *
430
+ * @param event - The raw H3 event object.
431
+ * @param next - A callback function that represents the next layer (usually the controller or final handler).
432
+ * @returns A promise resolving to the result of the request pipeline.
433
+ */
434
+ async handle(event, next) {
435
+ /**
436
+ * Convert the raw event into a standardized HttpContext
437
+ */
438
+ const ctx = this.context(event);
439
+ const { app } = ctx.request;
440
+ /**
441
+ * Dynamically bind the view renderer to the service container.
442
+ * This allows any part of the request lifecycle to render templates using Edge.
443
+ */
444
+ app.bind("view", () => async (template, params) => {
445
+ const edge = app.make("edge");
446
+ return ctx.response.html(await edge.render(template, params));
447
+ });
448
+ /**
449
+ * Run middleware stack and obtain result
450
+ */
451
+ const result = await this.runMiddleware(ctx, () => next(ctx));
452
+ /**
453
+ * If a plain object is returned from a controller or middleware,
454
+ * automatically set the JSON Content-Type header for the response.
455
+ */
456
+ if (result !== void 0 && this.isPlainObject(result)) event.res.headers.set("Content-Type", "application/json; charset=UTF-8");
457
+ return result;
458
+ }
459
+ /**
460
+ * Sequentially runs middleware in the order they were registered.
461
+ *
462
+ * @param context - The standardized HttpContext.
463
+ * @param next - Callback to execute when middleware completes.
464
+ * @returns A promise resolving to the final handler's result.
465
+ */
466
+ async runMiddleware(context, next) {
467
+ let index = -1;
468
+ const runner = async (i) => {
469
+ if (i <= index) throw new Error("next() called multiple times");
470
+ index = i;
471
+ const middleware = this.middleware[i];
472
+ if (middleware)
473
+ /**
474
+ * Execute the current middleware and proceed to the next one
475
+ */
476
+ return middleware.handle(context, () => runner(i + 1));
477
+ else
478
+ /**
479
+ * If no more middleware, call the final handler
480
+ */
481
+ return next(context);
482
+ };
483
+ return runner(0);
484
+ }
485
+ /**
486
+ * Utility function to determine if a value is a plain object or array.
487
+ *
488
+ * @param value - The value to check.
489
+ * @returns True if the value is a plain object or array, otherwise false.
490
+ */
491
+ isPlainObject(value) {
492
+ return typeof value === "object" && value !== null && (value.constructor === Object || value.constructor === Array);
493
+ }
379
494
  };
380
495
 
381
- // src/Providers/CoreServiceProvider.ts
382
- import "reflect-metadata";
383
-
384
- // src/ServiceProvider.ts
496
+ //#endregion
497
+ //#region src/ServiceProvider.ts
385
498
  var ServiceProvider = class {
386
- static {
387
- __name(this, "ServiceProvider");
388
- }
389
- static order;
390
- static priority = 0;
391
- app;
392
- constructor(app) {
393
- this.app = app;
394
- }
499
+ /**
500
+ * Sort order
501
+ */
502
+ static order;
503
+ /**
504
+ * Sort priority
505
+ */
506
+ static priority = 0;
507
+ /**
508
+ * Indicate that this service provider only runs in console
509
+ */
510
+ static console = false;
511
+ /**
512
+ * List of registered console commands
513
+ */
514
+ registeredCommands;
515
+ app;
516
+ constructor(app) {
517
+ this.app = app;
518
+ }
519
+ /**
520
+ * An array of console commands to register.
521
+ */
522
+ commands(commands) {
523
+ this.registeredCommands = commands;
524
+ }
395
525
  };
396
526
 
397
- // src/Providers/CoreServiceProvider.ts
527
+ //#endregion
528
+ //#region src/Providers/CoreServiceProvider.ts
529
+ /**
530
+ * Bootstraps core services and bindings.
531
+ *
532
+ * Bind essential services to the container (logger, config repository).
533
+ * Register app-level singletons.
534
+ * Set up exception handling.
535
+ *
536
+ * Auto-Registered
537
+ */
398
538
  var CoreServiceProvider = class extends ServiceProvider {
399
- static {
400
- __name(this, "CoreServiceProvider");
401
- }
402
- static priority = 999;
403
- register() {
404
- }
539
+ static priority = 999;
540
+ register() {}
405
541
  };
406
542
 
407
- // src/Providers/ViewServiceProvider.ts
408
- import { Edge } from "edge.js";
543
+ //#endregion
544
+ //#region src/Providers/ViewServiceProvider.ts
409
545
  var ViewServiceProvider = class extends ServiceProvider {
410
- static {
411
- __name(this, "ViewServiceProvider");
412
- }
413
- static priority = 995;
414
- register() {
415
- const config = this.app.make("config");
416
- const edge = Edge.create({
417
- cache: process.env.NODE_ENV === "production"
418
- });
419
- edge.mount(this.app.getPath("views"));
420
- edge.global("asset", this.app.make("asset"));
421
- edge.global("config", config.get);
422
- edge.global("app", this.app);
423
- this.app.bind("edge", () => edge);
424
- }
425
- };
426
- export {
427
- Application,
428
- Container,
429
- Controller,
430
- CoreServiceProvider,
431
- Inject,
432
- Injectable,
433
- Kernel,
434
- Registerer,
435
- ServiceProvider,
436
- ViewServiceProvider
546
+ static priority = 995;
547
+ register() {
548
+ const config = this.app.make("config");
549
+ const edge = Edge.create({ cache: process.env.NODE_ENV === "production" });
550
+ edge.mount(this.app.getPath("views"));
551
+ edge.global("asset", this.app.make("asset"));
552
+ edge.global("config", config.get);
553
+ edge.global("app", this.app);
554
+ this.app.bind("edge", () => edge);
555
+ }
437
556
  };
557
+
558
+ //#endregion
559
+ export { Application, Container, ContainerResolver, Controller, CoreServiceProvider, Inject, Injectable, Kernel, Registerer, ServiceProvider, ViewServiceProvider };
438
560
  //# sourceMappingURL=index.js.map