clear-router 2.9.0 → 2.9.2
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/README.md +15 -1
- package/dist/core/CoreRouter.cjs +47 -34
- package/dist/core/CoreRouter.d.cts +7 -4
- package/dist/core/CoreRouter.d.mts +7 -4
- package/dist/core/CoreRouter.mjs +47 -34
- package/dist/core/bindings.cjs +197 -38
- package/dist/core/bindings.d.cts +82 -11
- package/dist/core/bindings.d.mts +82 -11
- package/dist/core/bindings.mjs +191 -38
- package/dist/core/index.cjs +16 -0
- package/dist/core/index.d.cts +3 -1
- package/dist/core/index.d.mts +3 -1
- package/dist/core/index.mjs +3 -1
- package/dist/core/plugins.d.cts +4 -4
- package/dist/core/plugins.d.mts +4 -4
- package/dist/decorators/index.cjs +6 -1
- package/dist/decorators/index.d.cts +3 -2
- package/dist/decorators/index.d.mts +3 -2
- package/dist/decorators/index.mjs +3 -2
- package/dist/decorators/middleware.cjs +100 -0
- package/dist/decorators/middleware.d.cts +51 -0
- package/dist/decorators/middleware.d.mts +51 -0
- package/dist/decorators/middleware.mjs +98 -0
- package/dist/decorators/setup.cjs +6 -1
- package/dist/decorators/setup.d.cts +3 -2
- package/dist/decorators/setup.d.mts +3 -2
- package/dist/decorators/setup.mjs +3 -2
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +3 -1
- package/dist/types/basic.d.cts +5 -0
- package/dist/types/basic.d.mts +5 -0
- package/package.json +1 -1
package/dist/core/bindings.mjs
CHANGED
|
@@ -1,54 +1,189 @@
|
|
|
1
1
|
import { Request } from "./Request.mjs";
|
|
2
2
|
import { Response } from "./Response.mjs";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
|
|
4
5
|
//#region src/core/bindings.ts
|
|
5
6
|
const metadataKey = Symbol.for("clear-router:binding-metadata");
|
|
6
7
|
const bindings = /* @__PURE__ */ new WeakMap();
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.
|
|
8
|
+
var InjectionToken = class {
|
|
9
|
+
key;
|
|
10
|
+
constructor(description) {
|
|
11
|
+
this.description = description;
|
|
12
|
+
this.key = Symbol(description);
|
|
13
|
+
}
|
|
14
|
+
toString() {
|
|
15
|
+
return `InjectionToken(${this.description})`;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var ContainerResolutionError = class extends Error {
|
|
19
|
+
constructor(message, path) {
|
|
20
|
+
super(`${message}\nResolution path: ${path.map(describeToken).join(" -> ")}`);
|
|
21
|
+
this.path = path;
|
|
22
|
+
this.name = "ContainerResolutionError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var Container = class Container {
|
|
26
|
+
static activeScope = new AsyncLocalStorage();
|
|
27
|
+
static containers = /* @__PURE__ */ new Set();
|
|
28
|
+
static globalContainer = new Container();
|
|
29
|
+
registry = /* @__PURE__ */ new Map();
|
|
30
|
+
instances = /* @__PURE__ */ new Map();
|
|
31
|
+
pending = /* @__PURE__ */ new Map();
|
|
32
|
+
constructor(parent, context, requestScope = false) {
|
|
33
|
+
this.parent = parent;
|
|
34
|
+
this.context = context;
|
|
35
|
+
this.requestScope = requestScope;
|
|
36
|
+
}
|
|
37
|
+
static get global() {
|
|
38
|
+
return this.globalContainer;
|
|
39
|
+
}
|
|
40
|
+
static current() {
|
|
41
|
+
return this.activeScope.getStore() ?? this.globalContainer;
|
|
42
|
+
}
|
|
43
|
+
static run(container, callback) {
|
|
44
|
+
return this.activeScope.run(container, callback);
|
|
45
|
+
}
|
|
46
|
+
static create(parent = this.globalContainer) {
|
|
47
|
+
const container = new Container(parent);
|
|
48
|
+
this.containers.add(container);
|
|
49
|
+
return container;
|
|
50
|
+
}
|
|
51
|
+
createRequestScope(ctx) {
|
|
52
|
+
return new Container(this, ctx, true);
|
|
53
|
+
}
|
|
54
|
+
static bind(token, value, options) {
|
|
55
|
+
this.globalContainer.bind(token, value, options);
|
|
11
56
|
}
|
|
12
57
|
static unbind(token) {
|
|
13
|
-
this.
|
|
58
|
+
this.globalContainer.unbind(token);
|
|
14
59
|
}
|
|
15
60
|
static clear() {
|
|
16
|
-
this.
|
|
61
|
+
this.globalContainer.clear();
|
|
62
|
+
for (const container of this.containers) container.clear();
|
|
17
63
|
}
|
|
18
64
|
static has(token) {
|
|
19
|
-
return this.
|
|
65
|
+
return this.current().has(token);
|
|
20
66
|
}
|
|
21
67
|
static bindings() {
|
|
22
|
-
return
|
|
68
|
+
return this.current().bindings();
|
|
23
69
|
}
|
|
24
70
|
static async resolve(token, ctx, autoDiscover = false) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
71
|
+
return this.current().resolve(token, ctx, autoDiscover);
|
|
72
|
+
}
|
|
73
|
+
bind(token, value, options) {
|
|
74
|
+
this.registry.set(token, normalizeProvider(value, options));
|
|
75
|
+
this.instances.delete(token);
|
|
76
|
+
}
|
|
77
|
+
unbind(token) {
|
|
78
|
+
this.registry.delete(token);
|
|
79
|
+
this.instances.delete(token);
|
|
80
|
+
}
|
|
81
|
+
clear() {
|
|
82
|
+
this.registry.clear();
|
|
83
|
+
this.instances.clear();
|
|
84
|
+
this.pending.clear();
|
|
85
|
+
}
|
|
86
|
+
has(token) {
|
|
87
|
+
return Boolean(this.findProvider(token));
|
|
88
|
+
}
|
|
89
|
+
entries() {
|
|
90
|
+
const entries = /* @__PURE__ */ new Map();
|
|
91
|
+
for (const container of this.lineage().reverse()) for (const [token, provider] of container.registry) entries.set(token, provider);
|
|
92
|
+
return entries;
|
|
93
|
+
}
|
|
94
|
+
bindings() {
|
|
95
|
+
return Object.fromEntries(Array.from(this.entries(), ([token, provider]) => [describeToken(token), provider]));
|
|
96
|
+
}
|
|
97
|
+
async resolve(token, ctx = this.context, autoDiscover = false) {
|
|
98
|
+
return this.resolveToken(token, ctx, {
|
|
99
|
+
autoDiscover,
|
|
100
|
+
stack: []
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async resolveOrFail(token, ctx = this.context, autoDiscover = false) {
|
|
104
|
+
const resolved = await this.resolve(token, ctx, autoDiscover);
|
|
105
|
+
if (typeof resolved === "undefined") throw new ContainerResolutionError(`Cannot resolve ${describeToken(token)}`, [token]);
|
|
106
|
+
return resolved;
|
|
107
|
+
}
|
|
108
|
+
async resolveToken(token, ctx, state) {
|
|
109
|
+
if (token === Request) return ctx?.clearRequest;
|
|
110
|
+
if (token === Response) return ctx?.clearResponse;
|
|
111
|
+
if (state.stack.includes(token)) throw new ContainerResolutionError(`Circular dependency detected while resolving ${describeToken(token)}`, [...state.stack, token]);
|
|
112
|
+
const nextState = {
|
|
113
|
+
...state,
|
|
114
|
+
stack: [...state.stack, token]
|
|
115
|
+
};
|
|
116
|
+
const found = this.findProvider(token);
|
|
117
|
+
if (found) return this.resolveProvider(found.token, found.provider, found.owner, ctx, nextState);
|
|
118
|
+
if (state.autoDiscover && typeof token === "function") return this.instantiate(token, void 0, ctx, nextState);
|
|
119
|
+
}
|
|
120
|
+
findProvider(token) {
|
|
121
|
+
if (this.registry.has(token)) return {
|
|
122
|
+
token,
|
|
123
|
+
provider: this.registry.get(token),
|
|
124
|
+
owner: this
|
|
125
|
+
};
|
|
33
126
|
const equivalent = this.findEquivalentToken(token);
|
|
34
|
-
|
|
127
|
+
if (equivalent) return {
|
|
128
|
+
token: equivalent,
|
|
129
|
+
provider: this.registry.get(equivalent),
|
|
130
|
+
owner: this
|
|
131
|
+
};
|
|
132
|
+
return this.parent?.findProvider(token);
|
|
133
|
+
}
|
|
134
|
+
async resolveProvider(token, provider, owner, ctx, state) {
|
|
135
|
+
if ("useExisting" in provider) return this.resolveToken(provider.useExisting, ctx, state);
|
|
136
|
+
const cache = provider.scope === "singleton" ? owner : provider.scope === "request" ? this.findRequestScope() : void 0;
|
|
137
|
+
if (cache?.instances.has(token)) return cache.instances.get(token);
|
|
138
|
+
if (cache?.pending.has(token)) return cache.pending.get(token);
|
|
139
|
+
const create = async () => {
|
|
140
|
+
if ("useValue" in provider) return provider.useValue;
|
|
141
|
+
if ("useClass" in provider) return this.instantiate(provider.useClass, provider.dependencies, ctx, state);
|
|
142
|
+
return provider.useFactory(ctx);
|
|
143
|
+
};
|
|
144
|
+
if (!cache) return create();
|
|
145
|
+
const promise = create();
|
|
146
|
+
cache.pending.set(token, promise);
|
|
147
|
+
try {
|
|
148
|
+
const resolved = await promise;
|
|
149
|
+
if (typeof resolved !== "undefined") cache.instances.set(token, resolved);
|
|
150
|
+
return resolved;
|
|
151
|
+
} finally {
|
|
152
|
+
cache.pending.delete(token);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async instantiate(Type, dependencies, ctx, state) {
|
|
156
|
+
const tokens = dependencies ?? getInjectTokens(Type);
|
|
157
|
+
const args = [];
|
|
158
|
+
for (const dependency of tokens) {
|
|
159
|
+
const resolved = await this.resolveToken(dependency, ctx, state);
|
|
160
|
+
if (typeof resolved === "undefined") throw new ContainerResolutionError(`Cannot resolve ${describeToken(dependency)} required by ${describeToken(Type)}`, [...state.stack, dependency]);
|
|
161
|
+
args.push(resolved);
|
|
162
|
+
}
|
|
163
|
+
return new Type(...args);
|
|
35
164
|
}
|
|
36
|
-
|
|
165
|
+
findRequestScope() {
|
|
166
|
+
if (this.requestScope) return this;
|
|
167
|
+
return this.parent?.findRequestScope();
|
|
168
|
+
}
|
|
169
|
+
lineage() {
|
|
170
|
+
return [this, ...this.parent?.lineage() ?? []];
|
|
171
|
+
}
|
|
172
|
+
findEquivalentToken(token) {
|
|
173
|
+
if (typeof token !== "function") return void 0;
|
|
37
174
|
const name = token.name;
|
|
38
|
-
if (!name) return;
|
|
175
|
+
if (!name) return void 0;
|
|
39
176
|
const tokenParent = Object.getPrototypeOf(token);
|
|
40
177
|
const tokenProps = this.getComparableStaticProps(token);
|
|
41
178
|
for (const registered of this.registry.keys()) {
|
|
42
|
-
if (registered === token) continue;
|
|
43
|
-
if (registered.name !== name) continue;
|
|
179
|
+
if (typeof registered !== "function" || registered === token || registered.name !== name) continue;
|
|
44
180
|
const registeredParent = Object.getPrototypeOf(registered);
|
|
45
181
|
if (tokenParent && registeredParent && tokenParent.name !== registeredParent.name) continue;
|
|
46
182
|
const registeredProps = this.getComparableStaticProps(registered);
|
|
47
|
-
if (
|
|
48
|
-
return registered;
|
|
183
|
+
if (this.staticPropsMatch(token, registered, tokenProps, registeredProps)) return registered;
|
|
49
184
|
}
|
|
50
185
|
}
|
|
51
|
-
|
|
186
|
+
getComparableStaticProps(token) {
|
|
52
187
|
return Object.getOwnPropertyNames(token).filter((prop) => {
|
|
53
188
|
return ![
|
|
54
189
|
"length",
|
|
@@ -59,23 +194,38 @@ var Container = class {
|
|
|
59
194
|
].includes(prop);
|
|
60
195
|
});
|
|
61
196
|
}
|
|
62
|
-
|
|
197
|
+
staticPropsMatch(token, registered, tokenProps, registeredProps) {
|
|
63
198
|
if (tokenProps.length !== registeredProps.length) return false;
|
|
64
|
-
for (const prop of tokenProps)
|
|
65
|
-
if (!registeredProps.includes(prop)) return false;
|
|
66
|
-
if (Reflect.get(token, prop) !== Reflect.get(registered, prop)) return false;
|
|
67
|
-
}
|
|
199
|
+
for (const prop of tokenProps) if (!registeredProps.includes(prop) || Reflect.get(token, prop) !== Reflect.get(registered, prop)) return false;
|
|
68
200
|
return true;
|
|
69
201
|
}
|
|
70
|
-
static async resolveBinding(binding, ctx, autoDiscover) {
|
|
71
|
-
if (!binding) return void 0;
|
|
72
|
-
if (typeof binding !== "function") return binding;
|
|
73
|
-
if (isClass(binding)) return new binding();
|
|
74
|
-
const resolved = await binding(ctx);
|
|
75
|
-
if (typeof resolved === "function" && autoDiscover && isClass(resolved)) return new resolved();
|
|
76
|
-
return resolved;
|
|
77
|
-
}
|
|
78
202
|
};
|
|
203
|
+
function normalizeProvider(value, options) {
|
|
204
|
+
if (isProvider(value)) return {
|
|
205
|
+
scope: "transient",
|
|
206
|
+
...value
|
|
207
|
+
};
|
|
208
|
+
if (isClass(value)) return {
|
|
209
|
+
useClass: value,
|
|
210
|
+
scope: options?.scope ?? "transient"
|
|
211
|
+
};
|
|
212
|
+
if (typeof value === "function") return {
|
|
213
|
+
useFactory: value,
|
|
214
|
+
scope: options?.scope ?? "transient"
|
|
215
|
+
};
|
|
216
|
+
return { useValue: value };
|
|
217
|
+
}
|
|
218
|
+
function isProvider(value) {
|
|
219
|
+
return Boolean(value && typeof value === "object" && ("useValue" in value || "useClass" in value || "useFactory" in value || "useExisting" in value));
|
|
220
|
+
}
|
|
221
|
+
function getInjectTokens(Type) {
|
|
222
|
+
return Type.inject ?? getDesignParamTypes(Type);
|
|
223
|
+
}
|
|
224
|
+
function describeToken(token) {
|
|
225
|
+
if (token instanceof InjectionToken) return token.toString();
|
|
226
|
+
if (typeof token === "symbol") return token.description ?? token.toString();
|
|
227
|
+
return token.name || "<anonymous class>";
|
|
228
|
+
}
|
|
79
229
|
function Bind(...tokens) {
|
|
80
230
|
return ((target, propertyKeyOrContext) => {
|
|
81
231
|
if (isStandardClassContext(propertyKeyOrContext)) {
|
|
@@ -103,6 +253,9 @@ function Bind(...tokens) {
|
|
|
103
253
|
});
|
|
104
254
|
});
|
|
105
255
|
}
|
|
256
|
+
function getMetadataKey() {
|
|
257
|
+
return metadataKey;
|
|
258
|
+
}
|
|
106
259
|
function getStandardMetadata(metadata, propertyKey) {
|
|
107
260
|
const store = metadata && metadata[metadataKey];
|
|
108
261
|
if (!store) return void 0;
|
|
@@ -151,4 +304,4 @@ function isClass(value) {
|
|
|
151
304
|
}
|
|
152
305
|
|
|
153
306
|
//#endregion
|
|
154
|
-
export { Bind, Container, getBindingMetadataFromTargets, getDesignParamTypes, getStandardMetadata, isClass };
|
|
307
|
+
export { Bind, Container, ContainerResolutionError, InjectionToken, getBindingMetadata, getBindingMetadataFromTargets, getDesignParamTypes, getMetadataKey, getStandardMetadata, isClass, setBindingMetadata, setStandardMetadata };
|
package/dist/core/index.cjs
CHANGED
|
@@ -3,13 +3,29 @@ const require_helpers = require('./helpers.cjs');
|
|
|
3
3
|
const require_RouteGroup = require('../RouteGroup.cjs');
|
|
4
4
|
const require_Request = require('./Request.cjs');
|
|
5
5
|
const require_Response = require('./Response.cjs');
|
|
6
|
+
const require_bindings = require('./bindings.cjs');
|
|
6
7
|
const require_plugins = require('./plugins.cjs');
|
|
8
|
+
const require_middleware = require('../decorators/middleware.cjs');
|
|
7
9
|
const require_CoreRouter = require('./CoreRouter.cjs');
|
|
8
10
|
|
|
11
|
+
exports.Bind = require_bindings.Bind;
|
|
12
|
+
exports.Container = require_bindings.Container;
|
|
13
|
+
exports.ContainerResolutionError = require_bindings.ContainerResolutionError;
|
|
9
14
|
exports.CoreRouter = require_CoreRouter.CoreRouter;
|
|
15
|
+
exports.InjectionToken = require_bindings.InjectionToken;
|
|
10
16
|
exports.Request = require_Request.Request;
|
|
11
17
|
exports.Response = require_Response.Response;
|
|
12
18
|
exports.RouteGroup = require_RouteGroup.RouteGroup;
|
|
13
19
|
exports.definePlugin = require_plugins.definePlugin;
|
|
20
|
+
exports.getBindingMetadata = require_bindings.getBindingMetadata;
|
|
21
|
+
exports.getBindingMetadataFromTargets = require_bindings.getBindingMetadataFromTargets;
|
|
22
|
+
exports.getControllerMiddlewares = require_middleware.getControllerMiddlewares;
|
|
23
|
+
exports.getDesignParamTypes = require_bindings.getDesignParamTypes;
|
|
24
|
+
exports.getMetadataKey = require_bindings.getMetadataKey;
|
|
25
|
+
exports.getStandardMetadata = require_bindings.getStandardMetadata;
|
|
14
26
|
exports.importFile = require_helpers.importFile;
|
|
27
|
+
exports.isClass = require_bindings.isClass;
|
|
28
|
+
exports.middleware = require_middleware.middleware;
|
|
29
|
+
exports.setBindingMetadata = require_bindings.setBindingMetadata;
|
|
30
|
+
exports.setStandardMetadata = require_bindings.setStandardMetadata;
|
|
15
31
|
exports.wrap = require_helpers.wrap;
|
package/dist/core/index.d.cts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Response } from "./Response.cjs";
|
|
2
2
|
import { Request } from "./Request.cjs";
|
|
3
|
+
import { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, Container, ContainerResolutionError, ExistingProvider, FactoryProvider, InjectionToken, ValueProvider, getBindingMetadata, getBindingMetadataFromTargets, getDesignParamTypes, getMetadataKey, getStandardMetadata, isClass, setBindingMetadata, setStandardMetadata } from "./bindings.cjs";
|
|
3
4
|
import { ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, definePlugin } from "./plugins.cjs";
|
|
5
|
+
import { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware } from "../decorators/middleware.cjs";
|
|
4
6
|
import { RouteGroup } from "../RouteGroup.cjs";
|
|
5
7
|
import { CoreRouter } from "./CoreRouter.cjs";
|
|
6
8
|
import { importFile, wrap } from "./helpers.cjs";
|
|
7
|
-
export { ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, CoreRouter, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, Request, Response, RouteGroup, definePlugin, importFile, wrap };
|
|
9
|
+
export { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, Container, ContainerResolutionError, CoreRouter, ExistingProvider, FactoryProvider, InjectionToken, MiddlewareDecorator, MiddlewareInput, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, Request, Response, RouteGroup, ValueProvider, definePlugin, getBindingMetadata, getBindingMetadataFromTargets, getControllerMiddlewares, getDesignParamTypes, getMetadataKey, getStandardMetadata, importFile, isClass, middleware, setBindingMetadata, setStandardMetadata, wrap };
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Response } from "./Response.mjs";
|
|
2
2
|
import { Request } from "./Request.mjs";
|
|
3
|
+
import { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, Container, ContainerResolutionError, ExistingProvider, FactoryProvider, InjectionToken, ValueProvider, getBindingMetadata, getBindingMetadataFromTargets, getDesignParamTypes, getMetadataKey, getStandardMetadata, isClass, setBindingMetadata, setStandardMetadata } from "./bindings.mjs";
|
|
3
4
|
import { ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, definePlugin } from "./plugins.mjs";
|
|
5
|
+
import { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware } from "../decorators/middleware.mjs";
|
|
4
6
|
import { RouteGroup } from "../RouteGroup.mjs";
|
|
5
7
|
import { CoreRouter } from "./CoreRouter.mjs";
|
|
6
8
|
import { importFile, wrap } from "./helpers.mjs";
|
|
7
|
-
export { ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, CoreRouter, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, Request, Response, RouteGroup, definePlugin, importFile, wrap };
|
|
9
|
+
export { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, ClearRouterPlugin, ClearRouterPluginArgumentsContext, ClearRouterPluginContext, ClearRouterPluginInput, ClearRouterPluginRequestContext, Container, ContainerResolutionError, CoreRouter, ExistingProvider, FactoryProvider, InjectionToken, MiddlewareDecorator, MiddlewareInput, PluginArgumentsResolver, PluginBind, PluginBindFactory, PluginBindValue, PluginSetupResult, Request, Response, RouteGroup, ValueProvider, definePlugin, getBindingMetadata, getBindingMetadataFromTargets, getControllerMiddlewares, getDesignParamTypes, getMetadataKey, getStandardMetadata, importFile, isClass, middleware, setBindingMetadata, setStandardMetadata, wrap };
|
package/dist/core/index.mjs
CHANGED
|
@@ -2,7 +2,9 @@ import { importFile, wrap } from "./helpers.mjs";
|
|
|
2
2
|
import { RouteGroup } from "../RouteGroup.mjs";
|
|
3
3
|
import { Request } from "./Request.mjs";
|
|
4
4
|
import { Response } from "./Response.mjs";
|
|
5
|
+
import { Bind, Container, ContainerResolutionError, InjectionToken, getBindingMetadata, getBindingMetadataFromTargets, getDesignParamTypes, getMetadataKey, getStandardMetadata, isClass, setBindingMetadata, setStandardMetadata } from "./bindings.mjs";
|
|
5
6
|
import { definePlugin } from "./plugins.mjs";
|
|
7
|
+
import { getControllerMiddlewares, middleware } from "../decorators/middleware.mjs";
|
|
6
8
|
import { CoreRouter } from "./CoreRouter.mjs";
|
|
7
9
|
|
|
8
|
-
export { CoreRouter, Request, Response, RouteGroup, definePlugin, importFile, wrap };
|
|
10
|
+
export { Bind, Container, ContainerResolutionError, CoreRouter, InjectionToken, Request, Response, RouteGroup, definePlugin, getBindingMetadata, getBindingMetadataFromTargets, getControllerMiddlewares, getDesignParamTypes, getMetadataKey, getStandardMetadata, importFile, isClass, middleware, setBindingMetadata, setStandardMetadata, wrap };
|
package/dist/core/plugins.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Response } from "./Response.cjs";
|
|
2
2
|
import { RouterConfig } from "../types/basic.cjs";
|
|
3
3
|
import { Request } from "./Request.cjs";
|
|
4
|
-
import { BindToken, BindValue, Container } from "./bindings.cjs";
|
|
4
|
+
import { BindToken, BindValue, BindingOptions, Container } from "./bindings.cjs";
|
|
5
5
|
|
|
6
6
|
//#region src/core/plugins.d.ts
|
|
7
7
|
type PluginSetupResult = void | Promise<void>;
|
|
@@ -22,13 +22,13 @@ interface ClearRouterPluginArgumentsContext<X = any> extends ClearRouterPluginRe
|
|
|
22
22
|
}
|
|
23
23
|
type PluginBindFactory<T = any, X = any> = (ctx: ClearRouterPluginRequestContext<X>) => T | Promise<T>;
|
|
24
24
|
type PluginBindValue<T = any, X = any> = BindValue<T> | PluginBindFactory<T, X>;
|
|
25
|
-
type PluginBind<X = any> = <T>(token: BindToken<T>, value: PluginBindValue<T, X
|
|
25
|
+
type PluginBind<X = any> = <T>(token: BindToken<T>, value: PluginBindValue<T, X>, options?: BindingOptions) => void;
|
|
26
26
|
type PluginArgumentsResolver<HttpContext = any> = (ctx: ClearRouterPluginArgumentsContext<HttpContext>) => any[] | undefined | Promise<any[] | undefined>;
|
|
27
27
|
interface ClearRouterPluginContext<Options = any, HttpContext = any> {
|
|
28
28
|
/**
|
|
29
29
|
* The service container
|
|
30
30
|
*/
|
|
31
|
-
container:
|
|
31
|
+
container: Container;
|
|
32
32
|
/**
|
|
33
33
|
* Register service container bindings
|
|
34
34
|
*/
|
|
@@ -97,7 +97,7 @@ interface ClearRouterPlugin<Options = any, HttpContext = any> {
|
|
|
97
97
|
*/
|
|
98
98
|
setup: (ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult;
|
|
99
99
|
}
|
|
100
|
-
type ClearRouterPluginInput<Options = any, HttpContext = any> = ClearRouterPlugin<Options> | ((ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult);
|
|
100
|
+
type ClearRouterPluginInput<Options = any, HttpContext = any> = ClearRouterPlugin<Options, HttpContext> | ((ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult);
|
|
101
101
|
/**
|
|
102
102
|
* Creates a new plugin
|
|
103
103
|
*
|
package/dist/core/plugins.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Response } from "./Response.mjs";
|
|
2
2
|
import { RouterConfig } from "../types/basic.mjs";
|
|
3
3
|
import { Request } from "./Request.mjs";
|
|
4
|
-
import { BindToken, BindValue, Container } from "./bindings.mjs";
|
|
4
|
+
import { BindToken, BindValue, BindingOptions, Container } from "./bindings.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/core/plugins.d.ts
|
|
7
7
|
type PluginSetupResult = void | Promise<void>;
|
|
@@ -22,13 +22,13 @@ interface ClearRouterPluginArgumentsContext<X = any> extends ClearRouterPluginRe
|
|
|
22
22
|
}
|
|
23
23
|
type PluginBindFactory<T = any, X = any> = (ctx: ClearRouterPluginRequestContext<X>) => T | Promise<T>;
|
|
24
24
|
type PluginBindValue<T = any, X = any> = BindValue<T> | PluginBindFactory<T, X>;
|
|
25
|
-
type PluginBind<X = any> = <T>(token: BindToken<T>, value: PluginBindValue<T, X
|
|
25
|
+
type PluginBind<X = any> = <T>(token: BindToken<T>, value: PluginBindValue<T, X>, options?: BindingOptions) => void;
|
|
26
26
|
type PluginArgumentsResolver<HttpContext = any> = (ctx: ClearRouterPluginArgumentsContext<HttpContext>) => any[] | undefined | Promise<any[] | undefined>;
|
|
27
27
|
interface ClearRouterPluginContext<Options = any, HttpContext = any> {
|
|
28
28
|
/**
|
|
29
29
|
* The service container
|
|
30
30
|
*/
|
|
31
|
-
container:
|
|
31
|
+
container: Container;
|
|
32
32
|
/**
|
|
33
33
|
* Register service container bindings
|
|
34
34
|
*/
|
|
@@ -97,7 +97,7 @@ interface ClearRouterPlugin<Options = any, HttpContext = any> {
|
|
|
97
97
|
*/
|
|
98
98
|
setup: (ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult;
|
|
99
99
|
}
|
|
100
|
-
type ClearRouterPluginInput<Options = any, HttpContext = any> = ClearRouterPlugin<Options> | ((ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult);
|
|
100
|
+
type ClearRouterPluginInput<Options = any, HttpContext = any> = ClearRouterPlugin<Options, HttpContext> | ((ctx: ClearRouterPluginContext<Options, HttpContext>) => PluginSetupResult);
|
|
101
101
|
/**
|
|
102
102
|
* Creates a new plugin
|
|
103
103
|
*
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_bindings = require('../core/bindings.cjs');
|
|
3
|
+
const require_middleware = require('./middleware.cjs');
|
|
3
4
|
|
|
4
5
|
exports.Bind = require_bindings.Bind;
|
|
5
|
-
exports.Container = require_bindings.Container;
|
|
6
|
+
exports.Container = require_bindings.Container;
|
|
7
|
+
exports.ContainerResolutionError = require_bindings.ContainerResolutionError;
|
|
8
|
+
exports.InjectionToken = require_bindings.InjectionToken;
|
|
9
|
+
exports.getControllerMiddlewares = require_middleware.getControllerMiddlewares;
|
|
10
|
+
exports.middleware = require_middleware.middleware;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { Bind, BindDecorator, BindFactory, BindToken, BindValue, Container } from "../core/bindings.cjs";
|
|
2
|
-
|
|
1
|
+
import { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, Container, ContainerResolutionError, ExistingProvider, FactoryProvider, InjectionToken, ValueProvider } from "../core/bindings.cjs";
|
|
2
|
+
import { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware } from "./middleware.cjs";
|
|
3
|
+
export { Bind, type BindClass, type BindDecorator, type BindFactory, type BindProvider, type BindToken, type BindValue, type BindingOptions, type BindingScope, type ClassProvider, Container, ContainerResolutionError, type ExistingProvider, type FactoryProvider, InjectionToken, type MiddlewareDecorator, type MiddlewareInput, type ValueProvider, getControllerMiddlewares, middleware };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { Bind, BindDecorator, BindFactory, BindToken, BindValue, Container } from "../core/bindings.mjs";
|
|
2
|
-
|
|
1
|
+
import { Bind, BindClass, BindDecorator, BindFactory, BindProvider, BindToken, BindValue, BindingOptions, BindingScope, ClassProvider, Container, ContainerResolutionError, ExistingProvider, FactoryProvider, InjectionToken, ValueProvider } from "../core/bindings.mjs";
|
|
2
|
+
import { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware } from "./middleware.mjs";
|
|
3
|
+
export { Bind, type BindClass, type BindDecorator, type BindFactory, type BindProvider, type BindToken, type BindValue, type BindingOptions, type BindingScope, type ClassProvider, Container, ContainerResolutionError, type ExistingProvider, type FactoryProvider, InjectionToken, type MiddlewareDecorator, type MiddlewareInput, type ValueProvider, getControllerMiddlewares, middleware };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { Bind, Container } from "../core/bindings.mjs";
|
|
1
|
+
import { Bind, Container, ContainerResolutionError, InjectionToken } from "../core/bindings.mjs";
|
|
2
|
+
import { getControllerMiddlewares, middleware } from "./middleware.mjs";
|
|
2
3
|
|
|
3
|
-
export { Bind, Container };
|
|
4
|
+
export { Bind, Container, ContainerResolutionError, InjectionToken, getControllerMiddlewares, middleware };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/decorators/middleware.ts
|
|
3
|
+
const CLASS_KEY = "__class__";
|
|
4
|
+
const metadataKey = Symbol.for("clear-router:middleware-metadata");
|
|
5
|
+
const store = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
/**
|
|
7
|
+
* Attach one or more middleware to a controller class or a controller method.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* @Middleware([auth])
|
|
12
|
+
* class AccountController {}
|
|
13
|
+
*
|
|
14
|
+
* class LoginController {
|
|
15
|
+
* @Middleware(GuestMiddleware)
|
|
16
|
+
* create () {}
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Accepts the middleware variadically or as arrays, and every supported
|
|
21
|
+
* middleware shape: callbacks, middleware classes, or instances exposing a
|
|
22
|
+
* `handle` method.
|
|
23
|
+
*
|
|
24
|
+
* @param middlewares
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
function middleware(...middlewares) {
|
|
28
|
+
const flattened = middlewares.flat();
|
|
29
|
+
return ((target, propertyKeyOrContext) => {
|
|
30
|
+
if (isStandardClassContext(propertyKeyOrContext)) {
|
|
31
|
+
setClassMiddlewareMetadata(target, flattened);
|
|
32
|
+
setStandardMetadata(propertyKeyOrContext.metadata, CLASS_KEY, flattened);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (isStandardMethodContext(propertyKeyOrContext)) {
|
|
36
|
+
setStandardMetadata(propertyKeyOrContext.metadata, propertyKeyOrContext.name, flattened);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (typeof propertyKeyOrContext === "undefined") {
|
|
40
|
+
setClassMiddlewareMetadata(target, flattened);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setMiddlewareMetadata(target, propertyKeyOrContext, flattened);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Collect the decorator-declared middleware for a controller route handler,
|
|
48
|
+
* ordered class-level first then method-level. Returns an empty array for
|
|
49
|
+
* non-controller (callback) handlers or handlers without any decorators.
|
|
50
|
+
*
|
|
51
|
+
* @param handler
|
|
52
|
+
* @returns
|
|
53
|
+
*/
|
|
54
|
+
function getControllerMiddlewares(handler) {
|
|
55
|
+
if (!Array.isArray(handler) || handler.length !== 2) return [];
|
|
56
|
+
const [controller, method] = handler;
|
|
57
|
+
if (!controller) return [];
|
|
58
|
+
const constructor = typeof controller === "function" ? controller : controller.constructor;
|
|
59
|
+
const prototype = typeof controller === "function" ? controller.prototype : Object.getPrototypeOf(controller);
|
|
60
|
+
const standardMetadata = constructor?.[Symbol.metadata];
|
|
61
|
+
const classMiddlewares = getMiddlewareMetadata(constructor, CLASS_KEY) ?? getMiddlewareMetadata(prototype, CLASS_KEY) ?? getStandardMetadata(standardMetadata, CLASS_KEY) ?? [];
|
|
62
|
+
const methodMiddlewares = getMiddlewareMetadata(prototype, method) ?? getMiddlewareMetadata(constructor, method) ?? getStandardMetadata(standardMetadata, method) ?? [];
|
|
63
|
+
return [...classMiddlewares, ...methodMiddlewares];
|
|
64
|
+
}
|
|
65
|
+
function setClassMiddlewareMetadata(target, middlewares) {
|
|
66
|
+
setMiddlewareMetadata(target, CLASS_KEY, middlewares);
|
|
67
|
+
const prototype = target.prototype;
|
|
68
|
+
if (prototype) setMiddlewareMetadata(prototype, CLASS_KEY, middlewares);
|
|
69
|
+
}
|
|
70
|
+
function setMiddlewareMetadata(target, propertyKey, middlewares) {
|
|
71
|
+
const map = store.get(target) ?? /* @__PURE__ */ new Map();
|
|
72
|
+
const existing = map.get(propertyKey);
|
|
73
|
+
map.set(propertyKey, existing ? [...existing, ...middlewares] : middlewares);
|
|
74
|
+
store.set(target, map);
|
|
75
|
+
}
|
|
76
|
+
function getMiddlewareMetadata(target, propertyKey) {
|
|
77
|
+
if (!target) return void 0;
|
|
78
|
+
return store.get(target)?.get(propertyKey);
|
|
79
|
+
}
|
|
80
|
+
function setStandardMetadata(metadata, propertyKey, middlewares) {
|
|
81
|
+
if (!metadata) return;
|
|
82
|
+
const record = metadata;
|
|
83
|
+
record[metadataKey] = record[metadataKey] ?? {};
|
|
84
|
+
const existing = record[metadataKey][propertyKey];
|
|
85
|
+
record[metadataKey][propertyKey] = existing ? [...existing, ...middlewares] : middlewares;
|
|
86
|
+
}
|
|
87
|
+
function getStandardMetadata(metadata, propertyKey) {
|
|
88
|
+
const record = metadata && metadata[metadataKey];
|
|
89
|
+
return record ? record[propertyKey] : void 0;
|
|
90
|
+
}
|
|
91
|
+
function isStandardMethodContext(value) {
|
|
92
|
+
return Boolean(value && typeof value === "object" && value.kind === "method" && typeof value.name !== "undefined");
|
|
93
|
+
}
|
|
94
|
+
function isStandardClassContext(value) {
|
|
95
|
+
return Boolean(value && typeof value === "object" && value.kind === "class" && typeof value.name !== "undefined");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
exports.getControllerMiddlewares = getControllerMiddlewares;
|
|
100
|
+
exports.middleware = middleware;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ClassMiddleware, MiddlewareHandle } from "../types/basic.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/decorators/middleware.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Any value accepted as a middleware by the router: a plain callback, a class
|
|
6
|
+
* exposing a `handle` method, or an already-instantiated object exposing one.
|
|
7
|
+
*/
|
|
8
|
+
type MiddlewareInput = MiddlewareHandle | ClassMiddleware;
|
|
9
|
+
/**
|
|
10
|
+
* Decorator produced by {@link Middleware}. Works both as a class decorator (to
|
|
11
|
+
* apply the middleware to every action of a controller) and as a method
|
|
12
|
+
* decorator (to apply it to a single action). Supports the legacy
|
|
13
|
+
* (`experimentalDecorators`) and TC39 standard decorator signatures.
|
|
14
|
+
*/
|
|
15
|
+
type MiddlewareDecorator = MethodDecorator & ClassDecorator & {
|
|
16
|
+
<This, Value extends (this: This, ...args: any[]) => any>(value: Value, context: ClassMethodDecoratorContext<This, Value>): void | Value;
|
|
17
|
+
<Value extends abstract new (...args: any[]) => any>(value: Value, context: ClassDecoratorContext<Value>): void | Value;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Attach one or more middleware to a controller class or a controller method.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* @Middleware([auth])
|
|
25
|
+
* class AccountController {}
|
|
26
|
+
*
|
|
27
|
+
* class LoginController {
|
|
28
|
+
* @Middleware(GuestMiddleware)
|
|
29
|
+
* create () {}
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Accepts the middleware variadically or as arrays, and every supported
|
|
34
|
+
* middleware shape: callbacks, middleware classes, or instances exposing a
|
|
35
|
+
* `handle` method.
|
|
36
|
+
*
|
|
37
|
+
* @param middlewares
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
declare function middleware(...middlewares: Array<MiddlewareInput | MiddlewareInput[]>): MiddlewareDecorator;
|
|
41
|
+
/**
|
|
42
|
+
* Collect the decorator-declared middleware for a controller route handler,
|
|
43
|
+
* ordered class-level first then method-level. Returns an empty array for
|
|
44
|
+
* non-controller (callback) handlers or handlers without any decorators.
|
|
45
|
+
*
|
|
46
|
+
* @param handler
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
declare function getControllerMiddlewares(handler: any): MiddlewareInput[];
|
|
50
|
+
//#endregion
|
|
51
|
+
export { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ClassMiddleware, MiddlewareHandle } from "../types/basic.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/decorators/middleware.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Any value accepted as a middleware by the router: a plain callback, a class
|
|
6
|
+
* exposing a `handle` method, or an already-instantiated object exposing one.
|
|
7
|
+
*/
|
|
8
|
+
type MiddlewareInput = MiddlewareHandle | ClassMiddleware;
|
|
9
|
+
/**
|
|
10
|
+
* Decorator produced by {@link Middleware}. Works both as a class decorator (to
|
|
11
|
+
* apply the middleware to every action of a controller) and as a method
|
|
12
|
+
* decorator (to apply it to a single action). Supports the legacy
|
|
13
|
+
* (`experimentalDecorators`) and TC39 standard decorator signatures.
|
|
14
|
+
*/
|
|
15
|
+
type MiddlewareDecorator = MethodDecorator & ClassDecorator & {
|
|
16
|
+
<This, Value extends (this: This, ...args: any[]) => any>(value: Value, context: ClassMethodDecoratorContext<This, Value>): void | Value;
|
|
17
|
+
<Value extends abstract new (...args: any[]) => any>(value: Value, context: ClassDecoratorContext<Value>): void | Value;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Attach one or more middleware to a controller class or a controller method.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* @Middleware([auth])
|
|
25
|
+
* class AccountController {}
|
|
26
|
+
*
|
|
27
|
+
* class LoginController {
|
|
28
|
+
* @Middleware(GuestMiddleware)
|
|
29
|
+
* create () {}
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Accepts the middleware variadically or as arrays, and every supported
|
|
34
|
+
* middleware shape: callbacks, middleware classes, or instances exposing a
|
|
35
|
+
* `handle` method.
|
|
36
|
+
*
|
|
37
|
+
* @param middlewares
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
declare function middleware(...middlewares: Array<MiddlewareInput | MiddlewareInput[]>): MiddlewareDecorator;
|
|
41
|
+
/**
|
|
42
|
+
* Collect the decorator-declared middleware for a controller route handler,
|
|
43
|
+
* ordered class-level first then method-level. Returns an empty array for
|
|
44
|
+
* non-controller (callback) handlers or handlers without any decorators.
|
|
45
|
+
*
|
|
46
|
+
* @param handler
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
declare function getControllerMiddlewares(handler: any): MiddlewareInput[];
|
|
50
|
+
//#endregion
|
|
51
|
+
export { MiddlewareDecorator, MiddlewareInput, getControllerMiddlewares, middleware };
|