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