@h3ravel/core 1.21.6 → 1.22.0-alpha.1
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/env.d.ts +1 -0
- package/dist/index.cjs +771 -320
- package/dist/index.d.ts +493 -148
- package/dist/index.js +746 -313
- package/package.json +6 -5
- package/dist/app.globals.d.ts +0 -84
package/dist/index.cjs
CHANGED
|
@@ -6,12 +6,16 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
15
19
|
}
|
|
16
20
|
return to;
|
|
17
21
|
};
|
|
@@ -23,7 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
27
|
//#endregion
|
|
24
28
|
require("reflect-metadata");
|
|
25
29
|
let __h3ravel_shared = require("@h3ravel/shared");
|
|
30
|
+
let h3 = require("h3");
|
|
31
|
+
let __h3ravel_contracts = require("@h3ravel/contracts");
|
|
26
32
|
let __h3ravel_support = require("@h3ravel/support");
|
|
33
|
+
let __h3ravel_foundation = require("@h3ravel/foundation");
|
|
34
|
+
let module$1 = require("module");
|
|
27
35
|
let fast_glob = require("fast-glob");
|
|
28
36
|
fast_glob = __toESM(fast_glob);
|
|
29
37
|
let node_path = require("node:path");
|
|
@@ -36,12 +44,91 @@ dotenv_expand = __toESM(dotenv_expand);
|
|
|
36
44
|
let node_fs_promises = require("node:fs/promises");
|
|
37
45
|
let semver = require("semver");
|
|
38
46
|
semver = __toESM(semver);
|
|
39
|
-
let
|
|
47
|
+
let node_module = require("node:module");
|
|
48
|
+
let __h3ravel_support_facades = require("@h3ravel/support/facades");
|
|
40
49
|
|
|
50
|
+
//#region src/Manager/ContainerResolver.ts
|
|
51
|
+
var ContainerResolver = class ContainerResolver {
|
|
52
|
+
constructor(app) {
|
|
53
|
+
this.app = app;
|
|
54
|
+
}
|
|
55
|
+
async resolveMethodParams(instance, method, ..._default) {
|
|
56
|
+
/**
|
|
57
|
+
* Get param types for instance method
|
|
58
|
+
*/
|
|
59
|
+
let params = Reflect.getMetadata("design:paramtypes", instance, String(method)) || [];
|
|
60
|
+
/**
|
|
61
|
+
* Ensure that the Application class is always available
|
|
62
|
+
*/
|
|
63
|
+
if (params.length < 1 && _default.length > 0) params = _default;
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the bound dependencies
|
|
66
|
+
*/
|
|
67
|
+
const args = params.filter((e) => ContainerResolver.isClass(e) || e instanceof Application).map((type) => {
|
|
68
|
+
if (type instanceof Application) return type;
|
|
69
|
+
return this.app.make(type);
|
|
70
|
+
});
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
resolve(instance[method](...args));
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
static isClass(C) {
|
|
76
|
+
return typeof C === "function" && C.prototype !== void 0 && Object.toString.call(C).substring(0, 5) === "class";
|
|
77
|
+
}
|
|
78
|
+
static isAbstract(C) {
|
|
79
|
+
return this.isClass(C) && C.name.startsWith("I");
|
|
80
|
+
}
|
|
81
|
+
static isCallable(C) {
|
|
82
|
+
return typeof C === "function" && !ContainerResolver.isClass(C);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
41
87
|
//#region src/Container.ts
|
|
42
|
-
var Container = class {
|
|
88
|
+
var Container = class Container extends __h3ravel_contracts.IContainer {
|
|
43
89
|
bindings = /* @__PURE__ */ new Map();
|
|
44
90
|
singletons = /* @__PURE__ */ new Map();
|
|
91
|
+
middlewareHandler;
|
|
92
|
+
/**
|
|
93
|
+
* The current globally available container (if any).
|
|
94
|
+
*/
|
|
95
|
+
static instance;
|
|
96
|
+
/**
|
|
97
|
+
* All of the before resolving callbacks by class type.
|
|
98
|
+
*/
|
|
99
|
+
beforeResolvingCallbacks = /* @__PURE__ */ new Map();
|
|
100
|
+
/**
|
|
101
|
+
* All of the after resolving callbacks by class type.
|
|
102
|
+
*/
|
|
103
|
+
afterResolvingCallbacks = /* @__PURE__ */ new Map();
|
|
104
|
+
/**
|
|
105
|
+
* All of the registered rebound callbacks.
|
|
106
|
+
*/
|
|
107
|
+
reboundCallbacks = /* @__PURE__ */ new Map();
|
|
108
|
+
/**
|
|
109
|
+
* The container's shared instances.
|
|
110
|
+
*/
|
|
111
|
+
instances = /* @__PURE__ */ new Map();
|
|
112
|
+
/**
|
|
113
|
+
* The container's resolved instances.
|
|
114
|
+
*/
|
|
115
|
+
resolvedInstances = /* @__PURE__ */ new Map();
|
|
116
|
+
/**
|
|
117
|
+
* The registered type alias.
|
|
118
|
+
*/
|
|
119
|
+
aliases = /* @__PURE__ */ new Map();
|
|
120
|
+
/**
|
|
121
|
+
* The registered aliases keyed by the abstract name.
|
|
122
|
+
*/
|
|
123
|
+
abstractAliases = /* @__PURE__ */ new Map();
|
|
124
|
+
/**
|
|
125
|
+
* The registered aliases keyed by the abstract name.
|
|
126
|
+
*/
|
|
127
|
+
middlewares = /* @__PURE__ */ new Map();
|
|
128
|
+
/**
|
|
129
|
+
* The extension closures for services.
|
|
130
|
+
*/
|
|
131
|
+
extenders = /* @__PURE__ */ new Map();
|
|
45
132
|
static hasAnyDecorator(target) {
|
|
46
133
|
if (Reflect.getMetadataKeys(target).length > 0) return true;
|
|
47
134
|
const paramLength = target.length;
|
|
@@ -52,7 +139,22 @@ var Container = class {
|
|
|
52
139
|
this.bindings.set(key, factory);
|
|
53
140
|
}
|
|
54
141
|
/**
|
|
142
|
+
* Bind unregistered middlewares to the service container so we can use them later
|
|
143
|
+
*
|
|
144
|
+
* @param key
|
|
145
|
+
* @param middleware
|
|
146
|
+
*/
|
|
147
|
+
bindMiddleware(key, middleware) {
|
|
148
|
+
this.middlewares.set(key, middleware);
|
|
149
|
+
}
|
|
150
|
+
boundMiddlewares(key) {
|
|
151
|
+
if (key) return this.middlewares.get(key);
|
|
152
|
+
return this.middlewares.entries();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
55
155
|
* Remove one or more transient services from the container
|
|
156
|
+
*
|
|
157
|
+
* @param key
|
|
56
158
|
*/
|
|
57
159
|
unbind(key) {
|
|
58
160
|
if (Array.isArray(key)) for (let i = 0; i < key.length; i++) {
|
|
@@ -64,28 +166,127 @@ var Container = class {
|
|
|
64
166
|
this.singletons.delete(key);
|
|
65
167
|
}
|
|
66
168
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Bind a singleton service to the container
|
|
69
|
-
*/
|
|
70
169
|
singleton(key, factory) {
|
|
71
170
|
this.bindings.set(key, () => {
|
|
72
|
-
if (!this.singletons.has(key)) this.singletons.set(key, factory
|
|
171
|
+
if (!this.singletons.has(key)) this.singletons.set(key, this.call(factory));
|
|
73
172
|
return this.singletons.get(key);
|
|
74
173
|
});
|
|
75
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Read reflected param types, resolve dependencies from the container and
|
|
177
|
+
* optionally transform them, finally invoke the specified method on a class instance
|
|
178
|
+
*
|
|
179
|
+
* @param instance
|
|
180
|
+
* @param method
|
|
181
|
+
* @param defaultArgs
|
|
182
|
+
* @param handler
|
|
183
|
+
* @returns
|
|
184
|
+
*/
|
|
185
|
+
async invoke(instance, method, defaultArgs, handler) {
|
|
186
|
+
/**
|
|
187
|
+
* Get param types for the instance method
|
|
188
|
+
*/
|
|
189
|
+
const paramTypes = Reflect.getMetadata("design:paramtypes", instance, method) || [];
|
|
190
|
+
/**
|
|
191
|
+
* Resolve the bound dependencies
|
|
192
|
+
*/
|
|
193
|
+
let args = await Promise.all(paramTypes.map(async (paramType) => {
|
|
194
|
+
const inst = this.make(paramType);
|
|
195
|
+
if (handler) return await handler(inst);
|
|
196
|
+
return inst;
|
|
197
|
+
}));
|
|
198
|
+
/**
|
|
199
|
+
* Ensure that the args is always filled
|
|
200
|
+
*/
|
|
201
|
+
if (args.length < 1) args = defaultArgs ?? [];
|
|
202
|
+
const fn = instance[method];
|
|
203
|
+
return Reflect.apply(fn, instance, args);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Read reflected param types, resolve dependencies from the container and return the result
|
|
207
|
+
*
|
|
208
|
+
* @param instance
|
|
209
|
+
* @param method
|
|
210
|
+
*/
|
|
211
|
+
resolveParams(instance, method) {
|
|
212
|
+
/**
|
|
213
|
+
* Resolve and return the bound dependencies
|
|
214
|
+
*/
|
|
215
|
+
return (Reflect.getMetadata("design:paramtypes", instance, method) || []).filter((e) => !!e).map((abstract) => {
|
|
216
|
+
if (typeof abstract === "function" && abstract.toString().startsWith("function Function")) return abstract;
|
|
217
|
+
return this.make(abstract);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
76
220
|
make(key) {
|
|
221
|
+
return this.resolve(key);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resolve the gevein service from the container
|
|
225
|
+
*
|
|
226
|
+
* @param abstract
|
|
227
|
+
* @param raiseEvents
|
|
228
|
+
*/
|
|
229
|
+
resolve(abstract, raiseEvents = true) {
|
|
230
|
+
abstract = this.getAlias(abstract);
|
|
77
231
|
/**
|
|
78
232
|
* Direct factory binding
|
|
79
233
|
*/
|
|
80
|
-
|
|
81
|
-
|
|
234
|
+
let resolved;
|
|
235
|
+
if (this.resolvedInstances.has(abstract)) return this.resolvedInstances.get(abstract);
|
|
236
|
+
if (raiseEvents) this.runBeforeResolvingCallbacks(abstract);
|
|
237
|
+
if (this.bindings.has(abstract)) resolved = this.bindings.get(abstract)();
|
|
238
|
+
else if (this.instances.has(abstract)) resolved = this.instances.get(abstract);
|
|
239
|
+
else if (typeof abstract === "function")
|
|
240
|
+
/**
|
|
82
241
|
* If this is a class constructor, auto-resolve via reflection
|
|
83
242
|
*/
|
|
84
|
-
|
|
85
|
-
throw new Error(`No binding found for key: ${typeof
|
|
243
|
+
resolved = this.build(abstract);
|
|
244
|
+
else throw new Error(`No binding found for key: ${typeof abstract === "string" ? abstract : abstract?.name}`);
|
|
245
|
+
/**
|
|
246
|
+
* If we defined any extenders for this type, we'll need to spin through them
|
|
247
|
+
* and apply them to the object being built. This allows for the extension
|
|
248
|
+
* of services, such as changing configuration or decorating the object.
|
|
249
|
+
*/
|
|
250
|
+
for (const extender of this.getExtenders(abstract)) resolved = extender(resolved, this);
|
|
251
|
+
if (raiseEvents) this.runAfterResolvingCallbacks(abstract, resolved);
|
|
252
|
+
this.resolvedInstances.set(abstract, resolved);
|
|
253
|
+
return resolved;
|
|
254
|
+
}
|
|
255
|
+
afterResolving(key, callback) {
|
|
256
|
+
const existing = this.afterResolvingCallbacks.get(key) || [];
|
|
257
|
+
existing.push(callback);
|
|
258
|
+
this.afterResolvingCallbacks.set(key, existing);
|
|
259
|
+
}
|
|
260
|
+
beforeResolving(key, callback) {
|
|
261
|
+
const existing = this.beforeResolvingCallbacks.get(key) || [];
|
|
262
|
+
existing.push(callback);
|
|
263
|
+
this.beforeResolvingCallbacks.set(key, existing);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Execute all registered beforeResolving callbacks for a given key
|
|
267
|
+
*
|
|
268
|
+
* @param key
|
|
269
|
+
* @param resolved
|
|
270
|
+
*/
|
|
271
|
+
runBeforeResolvingCallbacks(key) {
|
|
272
|
+
const callbacks = this.beforeResolvingCallbacks.get(key) || [];
|
|
273
|
+
for (let i = 0; i < callbacks.length; i++) callbacks[i](this);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Execute all registered afterResolving callbacks for a given key
|
|
277
|
+
*
|
|
278
|
+
* @param key
|
|
279
|
+
* @param resolved
|
|
280
|
+
*/
|
|
281
|
+
runAfterResolvingCallbacks(key, resolved) {
|
|
282
|
+
const callbacks = this.afterResolvingCallbacks.get(key) || [];
|
|
283
|
+
for (let i = 0; i < callbacks.length; i++) callbacks[i](resolved, this);
|
|
86
284
|
}
|
|
87
285
|
/**
|
|
88
286
|
* Automatically build a class with constructor dependency injection
|
|
287
|
+
*
|
|
288
|
+
* @param ClassType
|
|
289
|
+
* @returns
|
|
89
290
|
*/
|
|
90
291
|
build(ClassType) {
|
|
91
292
|
let dependencies = [];
|
|
@@ -93,44 +294,135 @@ var Container = class {
|
|
|
93
294
|
return this.make(alias);
|
|
94
295
|
});
|
|
95
296
|
else dependencies = (Reflect.getMetadata("design:paramtypes", ClassType) || []).map((dep) => this.make(dep));
|
|
297
|
+
if (dependencies.length === 0) dependencies = [this];
|
|
96
298
|
return new ClassType(...dependencies);
|
|
97
299
|
}
|
|
98
300
|
/**
|
|
99
|
-
*
|
|
301
|
+
* Determine if a given string is an alias.
|
|
302
|
+
*
|
|
303
|
+
* @param name
|
|
304
|
+
*/
|
|
305
|
+
isAlias(name) {
|
|
306
|
+
return this.aliases.has(name) && typeof this.aliases.get(name) !== "undefined";
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get the alias for an abstract if available.
|
|
310
|
+
*
|
|
311
|
+
* @param abstract
|
|
100
312
|
*/
|
|
313
|
+
getAlias(abstract) {
|
|
314
|
+
if (typeof abstract === "string" && this.aliases.has(abstract)) return this.getAlias(this.aliases.get(abstract));
|
|
315
|
+
if (abstract == null) return abstract;
|
|
316
|
+
return this.aliases.get(abstract) ?? abstract;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get the extender callbacks for a given type.
|
|
320
|
+
*
|
|
321
|
+
* @param abstract
|
|
322
|
+
*/
|
|
323
|
+
getExtenders(abstract) {
|
|
324
|
+
return this.extenders.get(this.getAlias(abstract)) ?? [];
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Remove all of the extender callbacks for a given type.
|
|
328
|
+
*
|
|
329
|
+
* @param abstract
|
|
330
|
+
*/
|
|
331
|
+
forgetExtenders(abstract) {
|
|
332
|
+
this.extenders.delete(this.getAlias(abstract));
|
|
333
|
+
}
|
|
334
|
+
alias(key, target) {
|
|
335
|
+
if (Array.isArray(key)) for (const [tokn, targ] of key) this.aliases.set(tokn, targ);
|
|
336
|
+
else this.aliases.set(key, target);
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
rebinding(abstract, callback) {
|
|
340
|
+
abstract = this.getAlias(abstract);
|
|
341
|
+
this.reboundCallbacks.set(abstract, this.reboundCallbacks.get(abstract)?.concat(callback) ?? [callback]);
|
|
342
|
+
if (this.bound(abstract)) return this.make(abstract);
|
|
343
|
+
}
|
|
344
|
+
bound(abstract) {
|
|
345
|
+
return this.bindings.has(abstract) || !!this.instances.get(abstract) || this.isAlias(abstract);
|
|
346
|
+
}
|
|
101
347
|
has(key) {
|
|
102
|
-
return this.
|
|
348
|
+
return this.bound(key);
|
|
103
349
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.
|
|
350
|
+
/**
|
|
351
|
+
* Determine if the given abstract type has been resolved.
|
|
352
|
+
*
|
|
353
|
+
* @param abstract
|
|
354
|
+
*/
|
|
355
|
+
resolved(abstract) {
|
|
356
|
+
if (this.isAlias(abstract)) abstract = this.getAlias(abstract);
|
|
357
|
+
return this.resolvedInstances.has(abstract) || this.instances.has(abstract);
|
|
358
|
+
}
|
|
359
|
+
extend(abstract, closure) {
|
|
360
|
+
abstract = this.getAlias(abstract);
|
|
361
|
+
if (this.instances.has(abstract)) {
|
|
362
|
+
this.instances.set(abstract, closure(this.instances.get(abstract), this));
|
|
363
|
+
this.rebound(abstract);
|
|
364
|
+
} else {
|
|
365
|
+
this.extenders.set(abstract, this.extenders.get(abstract)?.concat(closure) ?? [closure]);
|
|
366
|
+
if (this.resolved(abstract)) this.rebound(abstract);
|
|
367
|
+
}
|
|
111
368
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*/
|
|
120
|
-
if (params.length < 1 && _default.length > 0) params = _default;
|
|
121
|
-
/**
|
|
122
|
-
* Resolve the bound dependencies
|
|
123
|
-
*/
|
|
124
|
-
const args = params.filter((e) => ContainerResolver.isClass(e) || e instanceof Application).map((type) => {
|
|
125
|
-
if (type instanceof Application) return type;
|
|
126
|
-
return this.app.make(type);
|
|
127
|
-
});
|
|
128
|
-
return new Promise((resolve) => {
|
|
129
|
-
resolve(instance[method](...args));
|
|
130
|
-
});
|
|
369
|
+
instance(abstract, instance) {
|
|
370
|
+
this.removeAbstractAlias(abstract);
|
|
371
|
+
const isBound = this.bound(abstract);
|
|
372
|
+
this.aliases.delete(abstract);
|
|
373
|
+
this.instances.set(abstract, instance);
|
|
374
|
+
if (isBound) this.rebound(abstract);
|
|
375
|
+
return instance;
|
|
131
376
|
}
|
|
132
|
-
|
|
133
|
-
|
|
377
|
+
call(callback) {
|
|
378
|
+
if (ContainerResolver.isClass(callback)) return this.make(callback);
|
|
379
|
+
return callback(this);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Fire the "rebound" callbacks for the given abstract type.
|
|
383
|
+
*
|
|
384
|
+
* @param abstract
|
|
385
|
+
*/
|
|
386
|
+
rebound(abstract) {
|
|
387
|
+
const callbacks = this.getReboundCallbacks(abstract);
|
|
388
|
+
if (!callbacks) return;
|
|
389
|
+
const instance = this.make(abstract);
|
|
390
|
+
for (const callback of callbacks) callback(this, instance);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get the rebound callbacks for a given type.
|
|
394
|
+
*
|
|
395
|
+
* @param abstract
|
|
396
|
+
*/
|
|
397
|
+
getReboundCallbacks(abstract) {
|
|
398
|
+
return this.reboundCallbacks.get(abstract) ?? [];
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Remove an alias from the contextual binding alias cache.
|
|
402
|
+
*
|
|
403
|
+
* @param searched
|
|
404
|
+
*/
|
|
405
|
+
removeAbstractAlias(searched) {
|
|
406
|
+
if (!this.aliases.has(searched)) return;
|
|
407
|
+
for (const [abstract, aliases] of this.abstractAliases.entries()) {
|
|
408
|
+
const filtered = aliases.filter((alias) => alias !== searched);
|
|
409
|
+
if (filtered.length > 0) this.abstractAliases.set(abstract, filtered);
|
|
410
|
+
else this.abstractAliases.delete(abstract);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Get the globally available instance of the container.
|
|
415
|
+
*/
|
|
416
|
+
static getInstance() {
|
|
417
|
+
return this.instance ??= new Application(process.cwd(), "h3ravel");
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Set the shared instance of the container.
|
|
421
|
+
*
|
|
422
|
+
* @param container
|
|
423
|
+
*/
|
|
424
|
+
static setInstance(container) {
|
|
425
|
+
return Container.instance = container;
|
|
134
426
|
}
|
|
135
427
|
};
|
|
136
428
|
|
|
@@ -220,33 +512,25 @@ var ProviderRegistry = class {
|
|
|
220
512
|
* @returns
|
|
221
513
|
*/
|
|
222
514
|
static sort(providers) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
});
|
|
230
|
-
/**
|
|
231
|
-
* Handle before/after adjustments
|
|
232
|
-
*/
|
|
515
|
+
const makeKey = (Provider) => `${Provider.name}::${this.getKey(Provider)}`;
|
|
516
|
+
providers.sort((A, B) => (B.priority ?? 0) - (A.priority ?? 0));
|
|
517
|
+
const findIndex = (target) => {
|
|
518
|
+
if (target.includes("::")) return providers.findIndex((p) => makeKey(p) === target);
|
|
519
|
+
return providers.findIndex((p) => p.name === target);
|
|
520
|
+
};
|
|
233
521
|
providers.forEach((Provider) => {
|
|
234
522
|
const order = Provider.order;
|
|
235
523
|
if (!order) return;
|
|
236
|
-
const [direction,
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
*/
|
|
245
|
-
return providers.sort((A, B) => {
|
|
246
|
-
const keyA = this.getKey(A);
|
|
247
|
-
const keyB = this.getKey(B);
|
|
248
|
-
return (this.priorityMap.get(`${B.name}::${keyB}`) ?? 0) - (this.priorityMap.get(`${A.name}::${keyA}`) ?? 0);
|
|
524
|
+
const [direction, rawTarget] = order.split(":");
|
|
525
|
+
const targetIndex = findIndex(rawTarget);
|
|
526
|
+
if (targetIndex === -1) return;
|
|
527
|
+
const currentIndex = providers.indexOf(Provider);
|
|
528
|
+
if (currentIndex === -1) return;
|
|
529
|
+
providers.splice(currentIndex, 1);
|
|
530
|
+
const insertIndex = direction === "before" ? targetIndex : targetIndex + 1;
|
|
531
|
+
providers.splice(insertIndex, 0, Provider);
|
|
249
532
|
});
|
|
533
|
+
return providers;
|
|
250
534
|
}
|
|
251
535
|
/**
|
|
252
536
|
* Sort service providers
|
|
@@ -265,7 +549,8 @@ var ProviderRegistry = class {
|
|
|
265
549
|
*
|
|
266
550
|
* @param priorityMap
|
|
267
551
|
*/
|
|
268
|
-
static log(providers) {
|
|
552
|
+
static log(providers, enabled = true) {
|
|
553
|
+
if (!enabled) return;
|
|
269
554
|
const sorted = Array.from((providers ?? this.providers).values());
|
|
270
555
|
console.table(sorted.map((P) => ({
|
|
271
556
|
Name: P.constructor.name,
|
|
@@ -306,10 +591,10 @@ var ProviderRegistry = class {
|
|
|
306
591
|
const providers = [];
|
|
307
592
|
if (autoRegister) {
|
|
308
593
|
for (const manifestPath of manifests) {
|
|
309
|
-
const pkg =
|
|
594
|
+
const pkg = this.getManifest(node_path.default.resolve(manifestPath));
|
|
310
595
|
if (pkg.h3ravel?.providers) providers.push(...await Promise.all(pkg.h3ravel.providers.map(async (name) => (await import(node_path.default.resolve(node_path.default.dirname(manifestPath), "dist/index.js")))[name])));
|
|
311
596
|
}
|
|
312
|
-
for (const provider of providers) {
|
|
597
|
+
for (const provider of providers.filter((e) => typeof e !== "undefined")) {
|
|
313
598
|
const key = this.getKey(provider);
|
|
314
599
|
this.providers.set(key, provider);
|
|
315
600
|
}
|
|
@@ -322,22 +607,16 @@ var ProviderRegistry = class {
|
|
|
322
607
|
* @param manifestPath
|
|
323
608
|
* @returns
|
|
324
609
|
*/
|
|
325
|
-
static
|
|
326
|
-
|
|
327
|
-
try {
|
|
328
|
-
pkg = (await import(manifestPath)).default;
|
|
329
|
-
} catch {
|
|
330
|
-
const { createRequire } = await import("module");
|
|
331
|
-
pkg = createRequire(require("url").pathToFileURL(__filename).href)(manifestPath);
|
|
332
|
-
}
|
|
333
|
-
return pkg;
|
|
610
|
+
static getManifest(manifestPath) {
|
|
611
|
+
return (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href)(manifestPath);
|
|
334
612
|
}
|
|
335
613
|
};
|
|
336
614
|
|
|
337
615
|
//#endregion
|
|
338
616
|
//#region src/Registerer.ts
|
|
339
|
-
var Registerer = class Registerer {
|
|
617
|
+
var Registerer = class Registerer extends __h3ravel_contracts.IRegisterer {
|
|
340
618
|
constructor(app) {
|
|
619
|
+
super();
|
|
341
620
|
this.app = app;
|
|
342
621
|
}
|
|
343
622
|
static register(app) {
|
|
@@ -369,31 +648,87 @@ var Registerer = class Registerer {
|
|
|
369
648
|
}
|
|
370
649
|
};
|
|
371
650
|
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/Providers/CoreServiceProvider.ts
|
|
653
|
+
/**
|
|
654
|
+
* Bootstraps core services and bindings.
|
|
655
|
+
*
|
|
656
|
+
* Bind essential services to the container (logger, config repository).
|
|
657
|
+
* Register app-level singletons.
|
|
658
|
+
* Set up exception handling.
|
|
659
|
+
*
|
|
660
|
+
* Auto-Registered
|
|
661
|
+
*/
|
|
662
|
+
var CoreServiceProvider = class extends __h3ravel_support.ServiceProvider {
|
|
663
|
+
static priority = 999;
|
|
664
|
+
register() {
|
|
665
|
+
Object.assign(globalThis, { str: __h3ravel_support.str });
|
|
666
|
+
this.app.alias(__h3ravel_contracts.IApplication, Application);
|
|
667
|
+
}
|
|
668
|
+
boot() {}
|
|
669
|
+
};
|
|
670
|
+
|
|
372
671
|
//#endregion
|
|
373
672
|
//#region src/Application.ts
|
|
374
673
|
var Application = class Application extends Container {
|
|
674
|
+
/**
|
|
675
|
+
* Indicates if the application has "booted".
|
|
676
|
+
*/
|
|
677
|
+
#booted = false;
|
|
375
678
|
paths = new __h3ravel_shared.PathLoader();
|
|
376
679
|
context;
|
|
680
|
+
h3Event;
|
|
377
681
|
tries = 0;
|
|
378
|
-
booted = false;
|
|
379
682
|
basePath;
|
|
380
683
|
versions = {
|
|
381
684
|
app: "0.0.0",
|
|
382
685
|
ts: "0.0.0"
|
|
383
686
|
};
|
|
687
|
+
namespace;
|
|
384
688
|
static versions = {
|
|
385
689
|
app: "0.0.0",
|
|
386
690
|
ts: "0.0.0"
|
|
387
691
|
};
|
|
692
|
+
h3App;
|
|
388
693
|
providers = [];
|
|
389
694
|
externalProviders = [];
|
|
390
695
|
filteredProviders = [];
|
|
696
|
+
autoRegisterProviders = false;
|
|
697
|
+
/**
|
|
698
|
+
* The route resolver callback.
|
|
699
|
+
*/
|
|
700
|
+
uriResolver;
|
|
391
701
|
/**
|
|
392
702
|
* List of registered console commands
|
|
393
703
|
*/
|
|
394
704
|
registeredCommands = [];
|
|
395
|
-
|
|
705
|
+
/**
|
|
706
|
+
* The array of booted callbacks.
|
|
707
|
+
*/
|
|
708
|
+
bootedCallbacks = [];
|
|
709
|
+
/**
|
|
710
|
+
* The array of booting callbacks.
|
|
711
|
+
*/
|
|
712
|
+
bootingCallbacks = [];
|
|
713
|
+
/**
|
|
714
|
+
* The array of terminating callbacks.
|
|
715
|
+
*/
|
|
716
|
+
terminatingCallbacks = [];
|
|
717
|
+
/**
|
|
718
|
+
* Indicates if the application has been bootstrapped before.
|
|
719
|
+
*/
|
|
720
|
+
bootstrapped = false;
|
|
721
|
+
/**
|
|
722
|
+
* Controls logging
|
|
723
|
+
*/
|
|
724
|
+
logsDisabled = false;
|
|
725
|
+
/**
|
|
726
|
+
* The conrrent HttpContext
|
|
727
|
+
*/
|
|
728
|
+
httpContext;
|
|
729
|
+
constructor(basePath, initializer) {
|
|
396
730
|
super();
|
|
731
|
+
this.initializer = initializer;
|
|
397
732
|
dotenv_expand.default.expand(dotenv.default.config({ quiet: true }));
|
|
398
733
|
this.basePath = basePath;
|
|
399
734
|
this.setPath("base", basePath);
|
|
@@ -405,6 +740,7 @@ var Application = class Application extends Container {
|
|
|
405
740
|
* Register core bindings into the container
|
|
406
741
|
*/
|
|
407
742
|
registerBaseBindings() {
|
|
743
|
+
Application.setInstance(this);
|
|
408
744
|
this.bind(Application, () => this);
|
|
409
745
|
this.bind("path.base", () => this.basePath);
|
|
410
746
|
this.bind("load.paths", () => this.paths);
|
|
@@ -444,7 +780,7 @@ var Application = class Application extends Container {
|
|
|
444
780
|
* Full-Stack App: Installs database, mail, queue, cache → they self-register via their providers.
|
|
445
781
|
*/
|
|
446
782
|
async getConfiguredProviders() {
|
|
447
|
-
return [
|
|
783
|
+
return [CoreServiceProvider];
|
|
448
784
|
}
|
|
449
785
|
async getAllProviders() {
|
|
450
786
|
return [...await this.getConfiguredProviders(), ...this.externalProviders];
|
|
@@ -458,22 +794,30 @@ var Application = class Application extends Container {
|
|
|
458
794
|
*
|
|
459
795
|
* @returns
|
|
460
796
|
*/
|
|
461
|
-
|
|
797
|
+
initialize(providers, filtered = [], autoRegisterProviders = true) {
|
|
798
|
+
/**
|
|
799
|
+
* Bind HTTP APP to the service container
|
|
800
|
+
*/
|
|
801
|
+
this.singleton("http.app", () => {
|
|
802
|
+
return new h3.H3();
|
|
803
|
+
});
|
|
804
|
+
/**
|
|
805
|
+
* Bind the HTTP server to the service container
|
|
806
|
+
*/
|
|
807
|
+
this.singleton("http.serve", () => h3.serve);
|
|
462
808
|
this.registerProviders(providers, filtered);
|
|
463
|
-
|
|
464
|
-
return this
|
|
809
|
+
this.autoRegisterProviders = autoRegisterProviders;
|
|
810
|
+
return this;
|
|
465
811
|
}
|
|
466
812
|
/**
|
|
467
813
|
* Dynamically register all configured providers
|
|
468
|
-
*
|
|
469
|
-
* @param autoRegister If set to false, service providers will not be auto discovered and registered.
|
|
470
814
|
*/
|
|
471
|
-
async registerConfiguredProviders(
|
|
815
|
+
async registerConfiguredProviders() {
|
|
472
816
|
const providers = await this.getAllProviders();
|
|
473
817
|
ProviderRegistry.setSortable(false);
|
|
474
818
|
ProviderRegistry.setFiltered(this.filteredProviders);
|
|
475
819
|
ProviderRegistry.registerMany(providers);
|
|
476
|
-
if (
|
|
820
|
+
if (this.autoRegisterProviders) await ProviderRegistry.discoverProviders(this.autoRegisterProviders);
|
|
477
821
|
ProviderRegistry.doSort();
|
|
478
822
|
for (const ProviderClass of ProviderRegistry.all()) {
|
|
479
823
|
if (!ProviderClass) continue;
|
|
@@ -489,7 +833,7 @@ var Application = class Application extends Container {
|
|
|
489
833
|
*/
|
|
490
834
|
registerProviders(providers, filtered = []) {
|
|
491
835
|
this.externalProviders.push(...providers);
|
|
492
|
-
this.filteredProviders = filtered;
|
|
836
|
+
this.filteredProviders = Array.from(new Set(this.filteredProviders.concat(filtered)));
|
|
493
837
|
}
|
|
494
838
|
/**
|
|
495
839
|
* Register a provider
|
|
@@ -514,44 +858,237 @@ var Application = class Application extends Container {
|
|
|
514
858
|
runningInConsole() {
|
|
515
859
|
return typeof process !== "undefined" && !!process.stdout && !!process.stdin;
|
|
516
860
|
}
|
|
861
|
+
/**
|
|
862
|
+
* checks if the application is running in Unit Test
|
|
863
|
+
*/
|
|
864
|
+
runningUnitTests() {
|
|
865
|
+
return process.env.VITEST === "true";
|
|
866
|
+
}
|
|
517
867
|
getRuntimeEnv() {
|
|
518
868
|
if (typeof window !== "undefined" && typeof document !== "undefined") return "browser";
|
|
519
869
|
if (typeof process !== "undefined" && process.versions?.node) return "node";
|
|
520
870
|
return "unknown";
|
|
521
871
|
}
|
|
522
872
|
/**
|
|
873
|
+
* Determine if the application has booted.
|
|
874
|
+
*/
|
|
875
|
+
isBooted() {
|
|
876
|
+
return this.#booted;
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Determine if the application has booted.
|
|
880
|
+
*/
|
|
881
|
+
logging(logging = true) {
|
|
882
|
+
this.logsDisabled = !logging;
|
|
883
|
+
return this;
|
|
884
|
+
}
|
|
885
|
+
logsEnabled() {
|
|
886
|
+
if (this.logsDisabled) return false;
|
|
887
|
+
return (process.env.APP_DEBUG === "true" && process.env.EXTENDED_DEBUG !== "false" || Number(process.env.VERBOSE) > 1) && !this.providers.some((e) => e.runsInConsole);
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
523
890
|
* Boot all service providers after registration
|
|
524
891
|
*/
|
|
525
892
|
async boot() {
|
|
526
|
-
if (this
|
|
893
|
+
if (this.#booted) return this;
|
|
894
|
+
this.fireAppCallbacks(this.bootingCallbacks);
|
|
895
|
+
/**
|
|
896
|
+
* Register all the configured service providers
|
|
897
|
+
*/
|
|
898
|
+
await this.registerConfiguredProviders();
|
|
527
899
|
/**
|
|
528
900
|
* If debug is enabled, let's show the loaded service provider info
|
|
529
901
|
*/
|
|
530
|
-
|
|
531
|
-
for (const provider of this.providers) if (provider.boot)
|
|
902
|
+
ProviderRegistry.log(this.providers, this.logsEnabled());
|
|
903
|
+
for (const provider of this.providers) if (provider.boot) {
|
|
904
|
+
if (Container.hasAnyDecorator(provider.boot))
|
|
532
905
|
/**
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
906
|
+
* If the service provider is decorated use the IoC container
|
|
907
|
+
*/
|
|
908
|
+
await this.make(provider.boot);
|
|
909
|
+
else
|
|
537
910
|
/**
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
911
|
+
* Otherwise instantiate manually so that we can at least
|
|
912
|
+
* pass the app instance
|
|
913
|
+
*/
|
|
914
|
+
await provider.boot(this);
|
|
915
|
+
if (provider.callBootedCallbacks) await provider.callBootedCallbacks();
|
|
916
|
+
}
|
|
917
|
+
this.#booted = true;
|
|
918
|
+
this.fireAppCallbacks(this.bootedCallbacks);
|
|
543
919
|
return this;
|
|
544
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* Register a new boot listener.
|
|
923
|
+
*
|
|
924
|
+
* @param callable $callback
|
|
925
|
+
*/
|
|
926
|
+
booting(callback) {
|
|
927
|
+
this.bootingCallbacks.push(callback);
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Register a new "booted" listener.
|
|
931
|
+
*
|
|
932
|
+
* @param callback
|
|
933
|
+
*/
|
|
934
|
+
booted(callback) {
|
|
935
|
+
this.bootedCallbacks.push(callback);
|
|
936
|
+
if (this.isBooted()) callback(this);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Throw an HttpException with the given data.
|
|
940
|
+
*
|
|
941
|
+
* @param code
|
|
942
|
+
* @param message
|
|
943
|
+
* @param headers
|
|
944
|
+
*
|
|
945
|
+
* @throws {HttpException}
|
|
946
|
+
* @throws {NotFoundHttpException}
|
|
947
|
+
*/
|
|
948
|
+
abort(code, message = "", headers = {}) {
|
|
949
|
+
if (code == 404) throw new __h3ravel_foundation.NotFoundHttpException(message, void 0, 0, headers);
|
|
950
|
+
throw new __h3ravel_foundation.HttpException(code, message, void 0, headers);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Register a terminating callback with the application.
|
|
954
|
+
*
|
|
955
|
+
* @param callback
|
|
956
|
+
*/
|
|
957
|
+
terminating(callback) {
|
|
958
|
+
this.terminatingCallbacks.push(callback);
|
|
959
|
+
return this;
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Terminate the application.
|
|
963
|
+
*/
|
|
964
|
+
terminate() {
|
|
965
|
+
let index = 0;
|
|
966
|
+
while (index < this.terminatingCallbacks.length) {
|
|
967
|
+
this.call(this.terminatingCallbacks[index]);
|
|
968
|
+
index++;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Call the booting callbacks for the application.
|
|
973
|
+
*
|
|
974
|
+
* @param callbacks
|
|
975
|
+
*/
|
|
976
|
+
fireAppCallbacks(callbacks) {
|
|
977
|
+
let index = 0;
|
|
978
|
+
while (index < callbacks.length) {
|
|
979
|
+
callbacks[index](this);
|
|
980
|
+
index++;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Handle the incoming HTTP request and send the response to the browser.
|
|
985
|
+
*
|
|
986
|
+
* @param config Configuration option to pass to the initializer
|
|
987
|
+
*/
|
|
988
|
+
async handleRequest(config) {
|
|
989
|
+
this.h3App?.all("/**", async (event) => {
|
|
990
|
+
this.context = (event$1) => this.buildContext(event$1, config);
|
|
991
|
+
this.h3Event = event;
|
|
992
|
+
const context = await this.context(event);
|
|
993
|
+
const kernel = this.make(__h3ravel_contracts.IKernel);
|
|
994
|
+
this.bind("http.context", () => context);
|
|
995
|
+
this.bind("http.request", () => context.request);
|
|
996
|
+
this.bind("http.response", () => context.response);
|
|
997
|
+
const response = await kernel.handle(context.request);
|
|
998
|
+
if (response) this.bind("http.response", () => response);
|
|
999
|
+
kernel.terminate(context.request, response);
|
|
1000
|
+
let finalResponse;
|
|
1001
|
+
if (response && ["Response", "JsonResponse"].includes(response.constructor.name)) finalResponse = response.prepare(context.request).send();
|
|
1002
|
+
else finalResponse = response;
|
|
1003
|
+
return finalResponse;
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Build the http context
|
|
1008
|
+
*
|
|
1009
|
+
* @param event
|
|
1010
|
+
* @param config
|
|
1011
|
+
* @returns
|
|
1012
|
+
*/
|
|
1013
|
+
async buildContext(event, config, fresh = false) {
|
|
1014
|
+
const { HttpContext, Request, Response } = await import("@h3ravel/http");
|
|
1015
|
+
event = config?.h3Event ?? event;
|
|
1016
|
+
if (!fresh && event._h3ravelContext) return event._h3ravelContext;
|
|
1017
|
+
Request.enableHttpMethodParameterOverride();
|
|
1018
|
+
const ctx = HttpContext.init({
|
|
1019
|
+
app: this,
|
|
1020
|
+
request: await Request.create(event, this),
|
|
1021
|
+
response: new Response(this, event)
|
|
1022
|
+
}, event);
|
|
1023
|
+
event._h3ravelContext = ctx;
|
|
1024
|
+
return ctx;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Handle the incoming Artisan command.
|
|
1028
|
+
*/
|
|
1029
|
+
async handleCommand() {
|
|
1030
|
+
const kernel = this.make(__h3ravel_contracts.CKernel);
|
|
1031
|
+
const status = await kernel.handle();
|
|
1032
|
+
kernel.terminate(status);
|
|
1033
|
+
return status;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Get the URI resolver callback.
|
|
1037
|
+
*/
|
|
1038
|
+
getUriResolver() {
|
|
1039
|
+
return this.uriResolver ?? (() => void 0);
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Set the URI resolver callback.
|
|
1043
|
+
*
|
|
1044
|
+
* @param callback
|
|
1045
|
+
*/
|
|
1046
|
+
setUriResolver(callback) {
|
|
1047
|
+
this.uriResolver = callback;
|
|
1048
|
+
return this;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Determine if middleware has been disabled for the application.
|
|
1052
|
+
*/
|
|
1053
|
+
shouldSkipMiddleware() {
|
|
1054
|
+
return this.bound("middleware.disable") && this.make("middleware.disable") === true;
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Provide safe overides for the app
|
|
1058
|
+
*/
|
|
1059
|
+
configure() {
|
|
1060
|
+
return new __h3ravel_foundation.AppBuilder(this).withKernels().withCommands();
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Check if the current application environment matches the one provided
|
|
1064
|
+
*/
|
|
1065
|
+
environment(env$1) {
|
|
1066
|
+
return this.make("config").get("app.env") === env$1;
|
|
1067
|
+
}
|
|
545
1068
|
async fire(h3App, preferredPort) {
|
|
1069
|
+
if (h3App) this.h3App = h3App;
|
|
1070
|
+
if (!this?.h3App) throw new __h3ravel_foundation.ConfigException("[Provide a H3 app instance in the config or install @h3ravel/http]");
|
|
1071
|
+
return await this.serve(this.h3App, preferredPort);
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Fire up the developement server using the user provided arguments
|
|
1075
|
+
*
|
|
1076
|
+
* Port will be auto assigned if provided one is not available
|
|
1077
|
+
*
|
|
1078
|
+
* @param h3App The current H3 app instance
|
|
1079
|
+
* @param preferedPort If provided, this will overide the port set in the evironment
|
|
1080
|
+
*/
|
|
1081
|
+
async serve(h3App, preferredPort) {
|
|
546
1082
|
if (!h3App) throw new __h3ravel_support.InvalidArgumentException("No valid H3 app instance was provided.");
|
|
547
|
-
|
|
1083
|
+
await this.boot();
|
|
1084
|
+
const serve$1 = this.make("http.serve");
|
|
548
1085
|
const port = preferredPort ?? env("PORT", 3e3);
|
|
549
1086
|
const tries = env("RETRIES", 1);
|
|
550
1087
|
const hostname = env("HOSTNAME", "localhost");
|
|
551
1088
|
try {
|
|
552
1089
|
const realPort = await (0, detect_port.detect)(port);
|
|
553
1090
|
if (port == realPort) {
|
|
554
|
-
const server = serve(h3App, {
|
|
1091
|
+
const server = serve$1(h3App, {
|
|
555
1092
|
port,
|
|
556
1093
|
hostname,
|
|
557
1094
|
silent: true
|
|
@@ -571,6 +1108,66 @@ var Application = class Application extends Container {
|
|
|
571
1108
|
return this;
|
|
572
1109
|
}
|
|
573
1110
|
/**
|
|
1111
|
+
* Run the given array of bootstrap classes.
|
|
1112
|
+
*
|
|
1113
|
+
* @param bootstrappers
|
|
1114
|
+
*/
|
|
1115
|
+
async bootstrapWith(bootstrappers) {
|
|
1116
|
+
for (const bootstrapper of bootstrappers) {
|
|
1117
|
+
if (this.has("app.events")) this.make("app.events").dispatch("bootstrapping: " + bootstrapper.name, [this]);
|
|
1118
|
+
await this.make(bootstrapper).bootstrap(this);
|
|
1119
|
+
if (this.has("app.events")) this.make("app.events").dispatch("bootstrapped: " + bootstrapper.name, [this]);
|
|
1120
|
+
}
|
|
1121
|
+
this.bootstrapped = true;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Determine if the application has been bootstrapped before.
|
|
1125
|
+
*/
|
|
1126
|
+
hasBeenBootstrapped() {
|
|
1127
|
+
return this.bootstrapped;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Save the curretn H3 instance for possible future use.
|
|
1131
|
+
*
|
|
1132
|
+
* @param h3App The current H3 app instance
|
|
1133
|
+
* @returns
|
|
1134
|
+
*/
|
|
1135
|
+
setH3App(h3App) {
|
|
1136
|
+
this.h3App = h3App;
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Set the HttpContext.
|
|
1141
|
+
*
|
|
1142
|
+
* @param ctx
|
|
1143
|
+
*/
|
|
1144
|
+
setHttpContext(ctx) {
|
|
1145
|
+
this.httpContext = ctx;
|
|
1146
|
+
return this;
|
|
1147
|
+
}
|
|
1148
|
+
getHttpContext(key) {
|
|
1149
|
+
return key ? this.httpContext?.[key] : this.httpContext;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Get the application namespace.
|
|
1153
|
+
*
|
|
1154
|
+
* @throws {RuntimeException}
|
|
1155
|
+
*/
|
|
1156
|
+
getNamespace() {
|
|
1157
|
+
if (this.namespace != null) return this.namespace;
|
|
1158
|
+
const pkg = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)(node_path.default.join(process.cwd(), "package.json"));
|
|
1159
|
+
for (const [namespace, pathChoice] of Object.entries((0, __h3ravel_support.data_get)(pkg, "autoload.namespaces"))) if (this.getPath("app", "/") === this.getPath("src", pathChoice)) return this.namespace = namespace;
|
|
1160
|
+
throw new __h3ravel_support.RuntimeException("Unable to detect application namespace.");
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Get the path of the app dir
|
|
1164
|
+
*
|
|
1165
|
+
* @returns
|
|
1166
|
+
*/
|
|
1167
|
+
path() {
|
|
1168
|
+
return this.getPath("app");
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
574
1171
|
* Get the base path of the app
|
|
575
1172
|
*
|
|
576
1173
|
* @returns
|
|
@@ -621,52 +1218,14 @@ var Application = class Application extends Container {
|
|
|
621
1218
|
/**
|
|
622
1219
|
* Base controller class
|
|
623
1220
|
*/
|
|
624
|
-
var Controller = class {
|
|
1221
|
+
var Controller = class extends __h3ravel_contracts.IController {
|
|
625
1222
|
app;
|
|
626
1223
|
constructor(app) {
|
|
1224
|
+
super();
|
|
627
1225
|
this.app = app;
|
|
628
1226
|
}
|
|
629
1227
|
};
|
|
630
1228
|
|
|
631
|
-
//#endregion
|
|
632
|
-
//#region src/Di/Inject.ts
|
|
633
|
-
function Inject(...dependencies) {
|
|
634
|
-
return function(target) {
|
|
635
|
-
target.__inject__ = dependencies;
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Allows binding dependencies to both class and class methods
|
|
640
|
-
*
|
|
641
|
-
* @returns
|
|
642
|
-
*/
|
|
643
|
-
function Injectable() {
|
|
644
|
-
return (...args) => {
|
|
645
|
-
if (args.length === 1) args[0];
|
|
646
|
-
if (args.length === 3) {
|
|
647
|
-
args[0];
|
|
648
|
-
args[1];
|
|
649
|
-
args[2];
|
|
650
|
-
}
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
//#endregion
|
|
655
|
-
//#region src/Exceptions/ConfigException.ts
|
|
656
|
-
var ConfigException = class extends Error {
|
|
657
|
-
key;
|
|
658
|
-
constructor(key, type = "config", cause) {
|
|
659
|
-
const info = {
|
|
660
|
-
any: `${key} not configured`,
|
|
661
|
-
env: `${key} environment variable not configured`,
|
|
662
|
-
config: `${key} config not set`
|
|
663
|
-
};
|
|
664
|
-
const message = __h3ravel_shared.Logger.log([["ERROR:", "bgRed"], [info[type], "white"]], " ", false);
|
|
665
|
-
super(message, { cause });
|
|
666
|
-
this.key = key;
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
|
|
670
1229
|
//#endregion
|
|
671
1230
|
//#region src/H3ravel.ts
|
|
672
1231
|
/**
|
|
@@ -680,56 +1239,23 @@ const h3ravel = async (providers = [], basePath = process.cwd(), config = {
|
|
|
680
1239
|
initialize: false,
|
|
681
1240
|
autoload: false,
|
|
682
1241
|
filteredProviders: []
|
|
683
|
-
}
|
|
1242
|
+
}) => {
|
|
684
1243
|
let h3App;
|
|
685
|
-
const app = new Application(basePath);
|
|
686
|
-
|
|
1244
|
+
const app = new Application(basePath, "h3ravel");
|
|
1245
|
+
if (config.customPaths) for (const [name, path$2] of Object.entries(config.customPaths)) app.setPath(name, path$2);
|
|
1246
|
+
app.initialize(providers, config.filteredProviders, config.autoload);
|
|
687
1247
|
try {
|
|
688
1248
|
h3App = app.make("http.app");
|
|
689
|
-
app.
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
request: await __h3ravel_http.Request.create(event, app),
|
|
695
|
-
response: new __h3ravel_http.Response(event, app)
|
|
696
|
-
});
|
|
697
|
-
event._h3ravelContext = ctx;
|
|
698
|
-
return ctx;
|
|
699
|
-
};
|
|
700
|
-
const kernel = new Kernel(async (event) => app.context(event), [new __h3ravel_http.LogRequests()]);
|
|
701
|
-
h3App.use((event) => kernel.handle(event, middleware));
|
|
1249
|
+
app.setH3App(h3App);
|
|
1250
|
+
app.singleton(__h3ravel_contracts.IApplication, () => app);
|
|
1251
|
+
if (!__h3ravel_support_facades.Facades.getApplication()) __h3ravel_support_facades.Facades.setApplication(app);
|
|
1252
|
+
if (!__h3ravel_foundation.Helpers.isLoaded()) __h3ravel_foundation.Helpers.load(app);
|
|
1253
|
+
await app.handleRequest(config);
|
|
702
1254
|
} catch {
|
|
703
1255
|
if (!h3App && config.h3) h3App = config.h3;
|
|
704
1256
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
return new Proxy(appRef, {
|
|
708
|
-
get(target, prop, receiver) {
|
|
709
|
-
if (prop === "fire") return orig;
|
|
710
|
-
return Reflect.get(target, prop, receiver);
|
|
711
|
-
},
|
|
712
|
-
has(target, prop) {
|
|
713
|
-
if (prop === "fire") return true;
|
|
714
|
-
return Reflect.has(target, prop);
|
|
715
|
-
},
|
|
716
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
717
|
-
if (prop === "fire") return {
|
|
718
|
-
configurable: true,
|
|
719
|
-
enumerable: false,
|
|
720
|
-
writable: true,
|
|
721
|
-
value: orig
|
|
722
|
-
};
|
|
723
|
-
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
724
|
-
}
|
|
725
|
-
});
|
|
726
|
-
})(app, originalFire);
|
|
727
|
-
if (config.initialize && h3App) return await Reflect.apply(originalFire, app, [h3App]);
|
|
728
|
-
app.fire = async function() {
|
|
729
|
-
if (!h3App) throw new ConfigException("Provide a H3 app instance in the config or install @h3ravel/http");
|
|
730
|
-
return await Reflect.apply(originalFire, proxyThis, [h3App]);
|
|
731
|
-
};
|
|
732
|
-
return app;
|
|
1257
|
+
if (config.initialize && h3App) return await app.fire(h3App);
|
|
1258
|
+
return app.setH3App(h3App);
|
|
733
1259
|
};
|
|
734
1260
|
|
|
735
1261
|
//#endregion
|
|
@@ -740,12 +1266,23 @@ const h3ravel = async (providers = [], basePath = process.cwd(), config = {
|
|
|
740
1266
|
*/
|
|
741
1267
|
var Kernel = class {
|
|
742
1268
|
/**
|
|
743
|
-
*
|
|
1269
|
+
* The router instance.
|
|
1270
|
+
*/
|
|
1271
|
+
router;
|
|
1272
|
+
/**
|
|
1273
|
+
* A factory function that converts an H3Event into an HttpContext.
|
|
1274
|
+
*/
|
|
1275
|
+
context;
|
|
1276
|
+
applicationContext;
|
|
1277
|
+
/**
|
|
1278
|
+
* @param app - The current application instance
|
|
744
1279
|
* @param middleware - An array of middleware classes that will be executed in sequence.
|
|
745
1280
|
*/
|
|
746
|
-
constructor(
|
|
747
|
-
this.
|
|
1281
|
+
constructor(app, middleware = []) {
|
|
1282
|
+
this.app = app;
|
|
748
1283
|
this.middleware = middleware;
|
|
1284
|
+
this.router = app.make("router");
|
|
1285
|
+
this.context = async (event) => app.context(event);
|
|
749
1286
|
}
|
|
750
1287
|
/**
|
|
751
1288
|
* Handles an incoming request and passes it through middleware before invoking the next handler.
|
|
@@ -755,157 +1292,71 @@ var Kernel = class {
|
|
|
755
1292
|
* @returns A promise resolving to the result of the request pipeline.
|
|
756
1293
|
*/
|
|
757
1294
|
async handle(event, next) {
|
|
1295
|
+
const { request } = await this.app.context(event);
|
|
758
1296
|
/**
|
|
759
1297
|
* Convert the raw event into a standardized HttpContext
|
|
760
1298
|
*/
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
* Bind HTTP Response instance to the service container
|
|
765
|
-
*/
|
|
766
|
-
app.bind("http.response", () => {
|
|
767
|
-
return ctx.response;
|
|
768
|
-
});
|
|
769
|
-
/**
|
|
770
|
-
* Bind HTTP Request instance to the service container
|
|
1299
|
+
this.applicationContext = await this.context(event);
|
|
1300
|
+
/**
|
|
1301
|
+
* Bind HttpContext, request, and response to the container
|
|
771
1302
|
*/
|
|
772
|
-
app.bind("http.
|
|
773
|
-
|
|
774
|
-
|
|
1303
|
+
this.app.bind("http.context", () => this.applicationContext);
|
|
1304
|
+
this.app.bind("http.request", () => this.applicationContext.request);
|
|
1305
|
+
this.app.bind("http.response", () => this.applicationContext.response);
|
|
1306
|
+
this.app.middlewareHandler = this.app.has(__h3ravel_foundation.MiddlewareHandler) ? this.app.make(__h3ravel_foundation.MiddlewareHandler) : new __h3ravel_foundation.MiddlewareHandler([], this.app);
|
|
1307
|
+
request.constructor.enableHttpMethodParameterOverride();
|
|
775
1308
|
/**
|
|
776
1309
|
* Run middleware stack and obtain result
|
|
777
1310
|
*/
|
|
778
|
-
const result = await this.
|
|
1311
|
+
const result = await this.app.middlewareHandler.register(this.middleware).run(this.applicationContext, next);
|
|
779
1312
|
/**
|
|
780
1313
|
* If a plain object is returned from a controller or middleware,
|
|
781
1314
|
* automatically set the JSON Content-Type header for the response.
|
|
782
1315
|
*/
|
|
783
|
-
if (result !== void 0 &&
|
|
1316
|
+
if (result !== void 0 && __h3ravel_support.Obj.isPlainObject(result, true) && !result?.headers) event.res.headers.set("Content-Type", "application/json; charset=UTF-8");
|
|
784
1317
|
return result;
|
|
785
1318
|
}
|
|
786
1319
|
/**
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
* @param context - The standardized HttpContext.
|
|
790
|
-
* @param next - Callback to execute when middleware completes.
|
|
791
|
-
* @returns A promise resolving to the final handler's result.
|
|
792
|
-
*/
|
|
793
|
-
async runMiddleware(context, next) {
|
|
794
|
-
let index = -1;
|
|
795
|
-
const runner = async (i) => {
|
|
796
|
-
if (i <= index) throw new Error("next() called multiple times");
|
|
797
|
-
index = i;
|
|
798
|
-
const middleware = this.middleware[i];
|
|
799
|
-
if (middleware)
|
|
800
|
-
/**
|
|
801
|
-
* Execute the current middleware and proceed to the next one
|
|
802
|
-
*/
|
|
803
|
-
return middleware.handle(context, () => runner(i + 1));
|
|
804
|
-
else
|
|
805
|
-
/**
|
|
806
|
-
* If no more middleware, call the final handler
|
|
807
|
-
*/
|
|
808
|
-
return next(context);
|
|
809
|
-
};
|
|
810
|
-
return runner(0);
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Utility function to determine if a value is a plain object or array.
|
|
814
|
-
*
|
|
815
|
-
* @param value - The value to check.
|
|
816
|
-
* @returns True if the value is a plain object or array, otherwise false.
|
|
817
|
-
*/
|
|
818
|
-
isPlainObject(value) {
|
|
819
|
-
return typeof value === "object" && value !== null && (value.constructor === Object || value.constructor === Array);
|
|
820
|
-
}
|
|
821
|
-
};
|
|
822
|
-
|
|
823
|
-
//#endregion
|
|
824
|
-
//#region src/ServiceProvider.ts
|
|
825
|
-
const Inference = class {};
|
|
826
|
-
var ServiceProvider = class extends Inference {
|
|
827
|
-
/**
|
|
828
|
-
* The current app instance
|
|
829
|
-
*/
|
|
830
|
-
app;
|
|
831
|
-
/**
|
|
832
|
-
* Unique Identifier for the service providers
|
|
833
|
-
*/
|
|
834
|
-
static uid;
|
|
835
|
-
/**
|
|
836
|
-
* Sort order
|
|
837
|
-
*/
|
|
838
|
-
static order;
|
|
839
|
-
/**
|
|
840
|
-
* Sort priority
|
|
841
|
-
*/
|
|
842
|
-
static priority = 0;
|
|
843
|
-
/**
|
|
844
|
-
* Indicate that this service provider only runs in console
|
|
845
|
-
*/
|
|
846
|
-
static console = false;
|
|
847
|
-
/**
|
|
848
|
-
* List of registered console commands
|
|
849
|
-
*/
|
|
850
|
-
registeredCommands;
|
|
851
|
-
constructor(app) {
|
|
852
|
-
super();
|
|
853
|
-
this.app = app;
|
|
854
|
-
}
|
|
855
|
-
/**
|
|
856
|
-
* Register the listed service providers.
|
|
857
|
-
*
|
|
858
|
-
* @param commands An array of console commands to register.
|
|
859
|
-
*
|
|
860
|
-
* @deprecated since version 1.16.0. Will be removed in future versions, use `registerCommands` instead
|
|
861
|
-
*/
|
|
862
|
-
commands(commands) {
|
|
863
|
-
this.registerCommands(commands);
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Register the listed service providers.
|
|
867
|
-
*
|
|
868
|
-
* @param commands An array of console commands to register.
|
|
1320
|
+
* Resolve the provided callback using the current H3 event instance
|
|
869
1321
|
*/
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
* Bind essential services to the container (logger, config repository).
|
|
881
|
-
* Register app-level singletons.
|
|
882
|
-
* Set up exception handling.
|
|
883
|
-
*
|
|
884
|
-
* Auto-Registered
|
|
885
|
-
*/
|
|
886
|
-
var CoreServiceProvider = class extends ServiceProvider {
|
|
887
|
-
static priority = 999;
|
|
888
|
-
register() {
|
|
889
|
-
Object.assign(globalThis, { str: __h3ravel_support.str });
|
|
890
|
-
}
|
|
891
|
-
boot() {
|
|
892
|
-
try {
|
|
893
|
-
Object.assign(globalThis, { asset: this.app.make("asset") });
|
|
894
|
-
} catch {}
|
|
1322
|
+
async resolve(event, middleware, handler) {
|
|
1323
|
+
const { Response } = await import("@h3ravel/http");
|
|
1324
|
+
this.middleware = Array.from(new Set([...this.middleware, ...__h3ravel_support.Arr.wrap(middleware)]));
|
|
1325
|
+
return this.handle(event, (ctx) => new Promise((resolve) => {
|
|
1326
|
+
if (__h3ravel_shared.Resolver.isAsyncFunction(handler)) handler(ctx).then((response) => {
|
|
1327
|
+
if (response instanceof Response) resolve(response.prepare(ctx.request).send());
|
|
1328
|
+
else resolve(response);
|
|
1329
|
+
});
|
|
1330
|
+
else resolve(handler(ctx));
|
|
1331
|
+
}));
|
|
895
1332
|
}
|
|
896
1333
|
};
|
|
897
1334
|
|
|
898
1335
|
//#endregion
|
|
899
1336
|
exports.Application = Application;
|
|
900
|
-
exports.ConfigException = ConfigException;
|
|
901
1337
|
exports.Container = Container;
|
|
902
1338
|
exports.ContainerResolver = ContainerResolver;
|
|
903
1339
|
exports.Controller = Controller;
|
|
904
1340
|
exports.CoreServiceProvider = CoreServiceProvider;
|
|
905
|
-
exports
|
|
906
|
-
|
|
1341
|
+
Object.defineProperty(exports, 'Inject', {
|
|
1342
|
+
enumerable: true,
|
|
1343
|
+
get: function () {
|
|
1344
|
+
return __h3ravel_foundation.Inject;
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
Object.defineProperty(exports, 'Injectable', {
|
|
1348
|
+
enumerable: true,
|
|
1349
|
+
get: function () {
|
|
1350
|
+
return __h3ravel_foundation.Injectable;
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
907
1353
|
exports.Kernel = Kernel;
|
|
908
1354
|
exports.ProviderRegistry = ProviderRegistry;
|
|
909
1355
|
exports.Registerer = Registerer;
|
|
910
|
-
exports
|
|
1356
|
+
Object.defineProperty(exports, 'ServiceProvider', {
|
|
1357
|
+
enumerable: true,
|
|
1358
|
+
get: function () {
|
|
1359
|
+
return __h3ravel_support.ServiceProvider;
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
911
1362
|
exports.h3ravel = h3ravel;
|