@engjts/nexus 0.1.8 → 0.1.9
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/package.json +1 -1
- package/BENCHMARK_REPORT.md +0 -343
- package/documentation/01-getting-started.md +0 -240
- package/documentation/02-context.md +0 -335
- package/documentation/03-routing.md +0 -397
- package/documentation/04-middleware.md +0 -483
- package/documentation/05-validation.md +0 -514
- package/documentation/06-error-handling.md +0 -465
- package/documentation/07-performance.md +0 -364
- package/documentation/08-adapters.md +0 -470
- package/documentation/09-api-reference.md +0 -548
- package/documentation/10-examples.md +0 -582
- package/documentation/11-deployment.md +0 -477
- package/documentation/12-sentry.md +0 -620
- package/documentation/13-sentry-data-storage.md +0 -996
- package/documentation/14-sentry-data-reference.md +0 -457
- package/documentation/15-sentry-summary.md +0 -409
- package/documentation/16-alerts-system.md +0 -745
- package/documentation/17-alert-adapters.md +0 -696
- package/documentation/18-alerts-implementation-summary.md +0 -385
- package/documentation/19-class-based-routing.md +0 -840
- package/documentation/20-websocket-realtime.md +0 -813
- package/documentation/21-cache-system.md +0 -510
- package/documentation/22-job-queue.md +0 -772
- package/documentation/23-sentry-plugin.md +0 -551
- package/documentation/24-testing-utilities.md +0 -1287
- package/documentation/25-api-versioning.md +0 -533
- package/documentation/26-context-store.md +0 -607
- package/documentation/27-dependency-injection.md +0 -329
- package/documentation/28-lifecycle-hooks.md +0 -521
- package/documentation/29-package-structure.md +0 -196
- package/documentation/30-plugin-system.md +0 -414
- package/documentation/31-jwt-authentication.md +0 -597
- package/documentation/32-cli.md +0 -268
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
- package/documentation/ALERTS-INDEX.md +0 -330
- package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
- package/documentation/README.md +0 -178
- package/documentation/index.html +0 -34
- package/modern_framework_paper.md +0 -1870
- package/public/css/style.css +0 -87
- package/public/index.html +0 -34
- package/public/js/app.js +0 -27
- package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
- package/src/advanced/cache/MultiTierCache.ts +0 -194
- package/src/advanced/cache/RedisCacheStore.ts +0 -341
- package/src/advanced/cache/index.ts +0 -5
- package/src/advanced/cache/types.ts +0 -40
- package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
- package/src/advanced/graphql/index.ts +0 -22
- package/src/advanced/graphql/server.ts +0 -252
- package/src/advanced/graphql/types.ts +0 -42
- package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
- package/src/advanced/jobs/JobQueue.ts +0 -556
- package/src/advanced/jobs/RedisQueueStore.ts +0 -367
- package/src/advanced/jobs/index.ts +0 -5
- package/src/advanced/jobs/types.ts +0 -70
- package/src/advanced/observability/APMManager.ts +0 -163
- package/src/advanced/observability/AlertManager.ts +0 -109
- package/src/advanced/observability/MetricRegistry.ts +0 -151
- package/src/advanced/observability/ObservabilityCenter.ts +0 -304
- package/src/advanced/observability/StructuredLogger.ts +0 -154
- package/src/advanced/observability/TracingManager.ts +0 -117
- package/src/advanced/observability/adapters.ts +0 -304
- package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
- package/src/advanced/observability/index.ts +0 -11
- package/src/advanced/observability/types.ts +0 -174
- package/src/advanced/playground/extractPathParams.ts +0 -6
- package/src/advanced/playground/generateFieldExample.ts +0 -31
- package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
- package/src/advanced/playground/generateSummary.ts +0 -19
- package/src/advanced/playground/getTagFromPath.ts +0 -9
- package/src/advanced/playground/index.ts +0 -8
- package/src/advanced/playground/playground.ts +0 -250
- package/src/advanced/playground/types.ts +0 -49
- package/src/advanced/playground/zodToExample.ts +0 -16
- package/src/advanced/playground/zodToParams.ts +0 -15
- package/src/advanced/postman/buildAuth.ts +0 -31
- package/src/advanced/postman/buildBody.ts +0 -15
- package/src/advanced/postman/buildQueryParams.ts +0 -27
- package/src/advanced/postman/buildRequestItem.ts +0 -36
- package/src/advanced/postman/buildResponses.ts +0 -11
- package/src/advanced/postman/buildUrl.ts +0 -33
- package/src/advanced/postman/capitalize.ts +0 -4
- package/src/advanced/postman/generateCollection.ts +0 -59
- package/src/advanced/postman/generateEnvironment.ts +0 -34
- package/src/advanced/postman/generateExampleFromZod.ts +0 -21
- package/src/advanced/postman/generateFieldExample.ts +0 -45
- package/src/advanced/postman/generateName.ts +0 -20
- package/src/advanced/postman/generateUUID.ts +0 -11
- package/src/advanced/postman/getTagFromPath.ts +0 -10
- package/src/advanced/postman/index.ts +0 -28
- package/src/advanced/postman/postman.ts +0 -156
- package/src/advanced/postman/slugify.ts +0 -7
- package/src/advanced/postman/types.ts +0 -140
- package/src/advanced/realtime/index.ts +0 -18
- package/src/advanced/realtime/websocket.ts +0 -231
- package/src/advanced/sentry/index.ts +0 -1236
- package/src/advanced/sentry/types.ts +0 -355
- package/src/advanced/static/generateDirectoryListing.ts +0 -47
- package/src/advanced/static/generateETag.ts +0 -7
- package/src/advanced/static/getMimeType.ts +0 -9
- package/src/advanced/static/index.ts +0 -32
- package/src/advanced/static/isSafePath.ts +0 -13
- package/src/advanced/static/publicDir.ts +0 -21
- package/src/advanced/static/serveStatic.ts +0 -225
- package/src/advanced/static/spa.ts +0 -24
- package/src/advanced/static/types.ts +0 -159
- package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
- package/src/advanced/swagger/buildOperation.ts +0 -61
- package/src/advanced/swagger/buildParameters.ts +0 -61
- package/src/advanced/swagger/buildRequestBody.ts +0 -21
- package/src/advanced/swagger/buildResponses.ts +0 -54
- package/src/advanced/swagger/capitalize.ts +0 -5
- package/src/advanced/swagger/convertPath.ts +0 -9
- package/src/advanced/swagger/createSwagger.ts +0 -12
- package/src/advanced/swagger/generateOperationId.ts +0 -21
- package/src/advanced/swagger/generateSpec.ts +0 -105
- package/src/advanced/swagger/generateSummary.ts +0 -24
- package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
- package/src/advanced/swagger/generateThemeCss.ts +0 -53
- package/src/advanced/swagger/index.ts +0 -25
- package/src/advanced/swagger/swagger.ts +0 -237
- package/src/advanced/swagger/types.ts +0 -206
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
- package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
- package/src/advanced/testing/factory.ts +0 -509
- package/src/advanced/testing/harness.ts +0 -612
- package/src/advanced/testing/index.ts +0 -430
- package/src/advanced/testing/load-test.ts +0 -618
- package/src/advanced/testing/mock-server.ts +0 -498
- package/src/advanced/testing/mock.ts +0 -670
- package/src/cli/bin.ts +0 -9
- package/src/cli/cli.ts +0 -158
- package/src/cli/commands/add.ts +0 -178
- package/src/cli/commands/build.ts +0 -73
- package/src/cli/commands/create.ts +0 -166
- package/src/cli/commands/dev.ts +0 -85
- package/src/cli/commands/generate.ts +0 -99
- package/src/cli/commands/help.ts +0 -95
- package/src/cli/commands/init.ts +0 -91
- package/src/cli/commands/version.ts +0 -38
- package/src/cli/index.ts +0 -6
- package/src/cli/templates/generators.ts +0 -359
- package/src/cli/templates/index.ts +0 -680
- package/src/cli/utils/exec.ts +0 -52
- package/src/cli/utils/file-system.ts +0 -78
- package/src/cli/utils/logger.ts +0 -111
- package/src/core/adapter.ts +0 -88
- package/src/core/application.ts +0 -1453
- package/src/core/context-pool.ts +0 -79
- package/src/core/context.ts +0 -856
- package/src/core/index.ts +0 -94
- package/src/core/middleware.ts +0 -272
- package/src/core/performance/buffer-pool.ts +0 -108
- package/src/core/performance/middleware-optimizer.ts +0 -162
- package/src/core/plugin/PluginManager.ts +0 -435
- package/src/core/plugin/builder.ts +0 -358
- package/src/core/plugin/index.ts +0 -50
- package/src/core/plugin/types.ts +0 -214
- package/src/core/router/file-router.ts +0 -623
- package/src/core/router/index.ts +0 -260
- package/src/core/router/radix-tree.ts +0 -242
- package/src/core/serializer.ts +0 -397
- package/src/core/store/index.ts +0 -30
- package/src/core/store/registry.ts +0 -178
- package/src/core/store/request-store.ts +0 -240
- package/src/core/store/types.ts +0 -233
- package/src/core/types.ts +0 -616
- package/src/database/adapter.ts +0 -35
- package/src/database/adapters/index.ts +0 -1
- package/src/database/adapters/mysql.ts +0 -669
- package/src/database/database.ts +0 -70
- package/src/database/dialect.ts +0 -388
- package/src/database/index.ts +0 -12
- package/src/database/migrations.ts +0 -86
- package/src/database/optimizer.ts +0 -125
- package/src/database/query-builder.ts +0 -404
- package/src/database/realtime.ts +0 -53
- package/src/database/schema.ts +0 -71
- package/src/database/transactions.ts +0 -56
- package/src/database/types.ts +0 -87
- package/src/deployment/cluster.ts +0 -471
- package/src/deployment/config.ts +0 -454
- package/src/deployment/docker.ts +0 -599
- package/src/deployment/graceful-shutdown.ts +0 -373
- package/src/deployment/index.ts +0 -56
- package/src/index.ts +0 -281
- package/src/security/adapter.ts +0 -318
- package/src/security/auth/JWTPlugin.ts +0 -234
- package/src/security/auth/JWTProvider.ts +0 -316
- package/src/security/auth/adapter.ts +0 -12
- package/src/security/auth/jwt.ts +0 -234
- package/src/security/auth/middleware.ts +0 -188
- package/src/security/csrf.ts +0 -220
- package/src/security/headers.ts +0 -108
- package/src/security/index.ts +0 -60
- package/src/security/rate-limit/adapter.ts +0 -7
- package/src/security/rate-limit/memory.ts +0 -108
- package/src/security/rate-limit/middleware.ts +0 -181
- package/src/security/sanitization.ts +0 -75
- package/src/security/types.ts +0 -240
- package/src/security/utils.ts +0 -52
- package/tsconfig.json +0 -39
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Manager
|
|
3
|
-
* Handles plugin lifecycle, dependency resolution, and execution
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Application } from '../application';
|
|
7
|
-
import { Context, Middleware } from '../types';
|
|
8
|
-
import {
|
|
9
|
-
NexusPlugin,
|
|
10
|
-
SimplePlugin,
|
|
11
|
-
RegisteredPlugin,
|
|
12
|
-
PluginContext,
|
|
13
|
-
PluginLogger,
|
|
14
|
-
PluginPhase,
|
|
15
|
-
PluginMeta,
|
|
16
|
-
PluginManagerEvents,
|
|
17
|
-
PRIORITY_WEIGHTS
|
|
18
|
-
} from './types';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Type-safe event emitter for plugin manager
|
|
22
|
-
*/
|
|
23
|
-
class PluginEventEmitter {
|
|
24
|
-
private listeners: Map<string, Set<Function>> = new Map();
|
|
25
|
-
|
|
26
|
-
on<K extends keyof PluginManagerEvents>(
|
|
27
|
-
event: K,
|
|
28
|
-
listener: PluginManagerEvents[K]
|
|
29
|
-
): this {
|
|
30
|
-
if (!this.listeners.has(event)) {
|
|
31
|
-
this.listeners.set(event, new Set());
|
|
32
|
-
}
|
|
33
|
-
this.listeners.get(event)!.add(listener);
|
|
34
|
-
return this;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
off<K extends keyof PluginManagerEvents>(
|
|
38
|
-
event: K,
|
|
39
|
-
listener: PluginManagerEvents[K]
|
|
40
|
-
): this {
|
|
41
|
-
this.listeners.get(event)?.delete(listener);
|
|
42
|
-
return this;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
emit<K extends keyof PluginManagerEvents>(
|
|
46
|
-
event: K,
|
|
47
|
-
...args: Parameters<PluginManagerEvents[K]>
|
|
48
|
-
): void {
|
|
49
|
-
const handlers = this.listeners.get(event);
|
|
50
|
-
if (handlers) {
|
|
51
|
-
const handlerArray = Array.from(handlers);
|
|
52
|
-
for (const handler of handlerArray) {
|
|
53
|
-
try {
|
|
54
|
-
(handler as any)(...args);
|
|
55
|
-
} catch (e) {
|
|
56
|
-
console.error(`Error in plugin event handler for ${event}:`, e);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Plugin Manager - orchestrates all plugin operations
|
|
65
|
-
*/
|
|
66
|
-
export class PluginManager {
|
|
67
|
-
private plugins: Map<string, RegisteredPlugin> = new Map();
|
|
68
|
-
private app: Application<any>;
|
|
69
|
-
private events: PluginEventEmitter = new PluginEventEmitter();
|
|
70
|
-
private debug: boolean;
|
|
71
|
-
private currentPhase: PluginPhase = 'configure';
|
|
72
|
-
private contextDecorators: Array<(ctx: Context) => void> = [];
|
|
73
|
-
|
|
74
|
-
constructor(app: Application<any>, options: { debug?: boolean } = {}) {
|
|
75
|
-
this.app = app;
|
|
76
|
-
this.debug = options.debug ?? false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Create a scoped logger for a plugin
|
|
81
|
-
*/
|
|
82
|
-
private createLogger(pluginName: string): PluginLogger {
|
|
83
|
-
const prefix = `[plugin:${pluginName}]`;
|
|
84
|
-
return {
|
|
85
|
-
debug: (msg, ...args) => this.debug && console.log(prefix, msg, ...args),
|
|
86
|
-
info: (msg, ...args) => console.log(prefix, msg, ...args),
|
|
87
|
-
warn: (msg, ...args) => console.warn(prefix, msg, ...args),
|
|
88
|
-
error: (msg, ...args) => console.error(prefix, msg, ...args)
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Create plugin context for lifecycle hooks
|
|
94
|
-
*/
|
|
95
|
-
private createContext(entry: RegisteredPlugin): PluginContext {
|
|
96
|
-
return {
|
|
97
|
-
app: this.app,
|
|
98
|
-
config: entry.config,
|
|
99
|
-
getPlugin: <T>(name: string) => this.getExports<T>(name),
|
|
100
|
-
hasPlugin: (name: string) => this.has(name),
|
|
101
|
-
log: this.createLogger(entry.meta.name),
|
|
102
|
-
storage: entry.storage
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Normalize a plugin (handle legacy SimplePlugin format)
|
|
108
|
-
*/
|
|
109
|
-
private normalizePlugin(plugin: NexusPlugin | SimplePlugin): NexusPlugin {
|
|
110
|
-
// Check if it's a legacy SimplePlugin
|
|
111
|
-
if ('install' in plugin && !('meta' in plugin)) {
|
|
112
|
-
const simple = plugin as SimplePlugin;
|
|
113
|
-
return {
|
|
114
|
-
meta: {
|
|
115
|
-
name: simple.name,
|
|
116
|
-
version: simple.version
|
|
117
|
-
},
|
|
118
|
-
register: async (ctx) => {
|
|
119
|
-
await simple.install(ctx.app);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
return plugin as NexusPlugin;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Add a plugin to the manager
|
|
128
|
-
*/
|
|
129
|
-
add<TConfig = any>(
|
|
130
|
-
plugin: NexusPlugin<TConfig> | SimplePlugin,
|
|
131
|
-
config?: TConfig
|
|
132
|
-
): this {
|
|
133
|
-
const normalized = this.normalizePlugin(plugin);
|
|
134
|
-
const { meta } = normalized;
|
|
135
|
-
|
|
136
|
-
// Check for duplicate
|
|
137
|
-
if (this.plugins.has(meta.name)) {
|
|
138
|
-
throw new Error(`Plugin "${meta.name}" is already registered`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Check for conflicts
|
|
142
|
-
const pluginEntries = Array.from(this.plugins.entries());
|
|
143
|
-
for (const [name, entry] of pluginEntries) {
|
|
144
|
-
if (entry.meta.conflicts?.includes(meta.name)) {
|
|
145
|
-
throw new Error(`Plugin "${meta.name}" conflicts with "${name}"`);
|
|
146
|
-
}
|
|
147
|
-
if (meta.conflicts?.includes(name)) {
|
|
148
|
-
throw new Error(`Plugin "${meta.name}" conflicts with "${name}"`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Merge config with defaults
|
|
153
|
-
const finalConfig = { ...normalized.defaults, ...config };
|
|
154
|
-
|
|
155
|
-
// Validate config if validator provided
|
|
156
|
-
if (normalized.validateConfig) {
|
|
157
|
-
const result = normalized.validateConfig(finalConfig);
|
|
158
|
-
if (result !== true) {
|
|
159
|
-
throw new Error(
|
|
160
|
-
typeof result === 'string'
|
|
161
|
-
? result
|
|
162
|
-
: `Invalid configuration for plugin "${meta.name}"`
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Register the plugin
|
|
168
|
-
const entry: RegisteredPlugin = {
|
|
169
|
-
meta,
|
|
170
|
-
plugin: normalized,
|
|
171
|
-
config: finalConfig,
|
|
172
|
-
storage: new Map(),
|
|
173
|
-
state: 'pending'
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
this.plugins.set(meta.name, entry);
|
|
177
|
-
this.events.emit('plugin:added', meta);
|
|
178
|
-
|
|
179
|
-
if (this.debug) {
|
|
180
|
-
console.log(`[PluginManager] Added plugin: ${meta.name}@${meta.version}`);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return this;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Check if a plugin is registered
|
|
188
|
-
*/
|
|
189
|
-
has(name: string): boolean {
|
|
190
|
-
return this.plugins.has(name);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Get a plugin's exports
|
|
195
|
-
*/
|
|
196
|
-
getExports<T = any>(name: string): T | undefined {
|
|
197
|
-
return this.plugins.get(name)?.exports as T;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Get plugin metadata
|
|
202
|
-
*/
|
|
203
|
-
getMeta(name: string): PluginMeta | undefined {
|
|
204
|
-
return this.plugins.get(name)?.meta;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Get all registered plugins
|
|
209
|
-
*/
|
|
210
|
-
getAll(): RegisteredPlugin[] {
|
|
211
|
-
return Array.from(this.plugins.values());
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Resolve plugin order based on dependencies
|
|
216
|
-
*/
|
|
217
|
-
private resolveDependencyOrder(): RegisteredPlugin[] {
|
|
218
|
-
const resolved: RegisteredPlugin[] = [];
|
|
219
|
-
const resolving = new Set<string>();
|
|
220
|
-
const visited = new Set<string>();
|
|
221
|
-
|
|
222
|
-
const resolve = (name: string): void => {
|
|
223
|
-
if (visited.has(name)) return;
|
|
224
|
-
if (resolving.has(name)) {
|
|
225
|
-
throw new Error(`Circular dependency detected involving plugin "${name}"`);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const entry = this.plugins.get(name);
|
|
229
|
-
if (!entry) {
|
|
230
|
-
throw new Error(`Plugin "${name}" not found (required as dependency)`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
resolving.add(name);
|
|
234
|
-
|
|
235
|
-
// Resolve required dependencies first
|
|
236
|
-
for (const dep of entry.meta.dependencies ?? []) {
|
|
237
|
-
if (!this.plugins.has(dep)) {
|
|
238
|
-
throw new Error(
|
|
239
|
-
`Plugin "${name}" requires "${dep}" but it's not installed`
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
resolve(dep);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Optional dependencies (don't fail if missing)
|
|
246
|
-
for (const dep of entry.meta.optionalDependencies ?? []) {
|
|
247
|
-
if (this.plugins.has(dep)) {
|
|
248
|
-
resolve(dep);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
resolving.delete(name);
|
|
253
|
-
visited.add(name);
|
|
254
|
-
resolved.push(entry);
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
// Sort by priority first, then resolve
|
|
258
|
-
const sortedNames = Array.from(this.plugins.keys()).sort((a, b) => {
|
|
259
|
-
const pa = this.plugins.get(a)!.meta.priority ?? 'normal';
|
|
260
|
-
const pb = this.plugins.get(b)!.meta.priority ?? 'normal';
|
|
261
|
-
return PRIORITY_WEIGHTS[pa] - PRIORITY_WEIGHTS[pb];
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
for (const name of sortedNames) {
|
|
265
|
-
resolve(name);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return resolved;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Run a lifecycle phase for all plugins
|
|
273
|
-
*/
|
|
274
|
-
private async runPhase(phase: PluginPhase): Promise<void> {
|
|
275
|
-
this.currentPhase = phase;
|
|
276
|
-
this.events.emit('lifecycle:start', phase);
|
|
277
|
-
|
|
278
|
-
const ordered = phase === 'shutdown'
|
|
279
|
-
? this.resolveDependencyOrder().reverse()
|
|
280
|
-
: this.resolveDependencyOrder();
|
|
281
|
-
|
|
282
|
-
for (const entry of ordered) {
|
|
283
|
-
try {
|
|
284
|
-
const ctx = this.createContext(entry);
|
|
285
|
-
const plugin = entry.plugin;
|
|
286
|
-
|
|
287
|
-
switch (phase) {
|
|
288
|
-
case 'configure':
|
|
289
|
-
await plugin.configure?.(ctx);
|
|
290
|
-
entry.state = 'configured';
|
|
291
|
-
this.events.emit('plugin:configured', entry.meta);
|
|
292
|
-
break;
|
|
293
|
-
|
|
294
|
-
case 'register':
|
|
295
|
-
// Register middlewares
|
|
296
|
-
if (plugin.middlewares) {
|
|
297
|
-
const middlewares = typeof plugin.middlewares === 'function'
|
|
298
|
-
? plugin.middlewares(ctx)
|
|
299
|
-
: plugin.middlewares;
|
|
300
|
-
for (const mw of middlewares) {
|
|
301
|
-
this.app.use(mw);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Register routes
|
|
306
|
-
if (plugin.routes) {
|
|
307
|
-
const routes = typeof plugin.routes === 'function'
|
|
308
|
-
? plugin.routes(ctx)
|
|
309
|
-
: plugin.routes;
|
|
310
|
-
for (const route of routes) {
|
|
311
|
-
(this.app as any)[route.method.toLowerCase()](
|
|
312
|
-
route.path,
|
|
313
|
-
{
|
|
314
|
-
handler: route.handler,
|
|
315
|
-
middlewares: route.middlewares,
|
|
316
|
-
meta: route.meta
|
|
317
|
-
}
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Context decorator
|
|
323
|
-
if (plugin.decorateContext) {
|
|
324
|
-
this.contextDecorators.push(plugin.decorateContext);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// App decorator
|
|
328
|
-
if (plugin.decorateApp) {
|
|
329
|
-
plugin.decorateApp(this.app);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Main register hook
|
|
333
|
-
await plugin.register?.(ctx);
|
|
334
|
-
|
|
335
|
-
// Collect exports
|
|
336
|
-
if (plugin.exports) {
|
|
337
|
-
entry.exports = plugin.exports(ctx);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
entry.state = 'registered';
|
|
341
|
-
this.events.emit('plugin:registered', entry.meta);
|
|
342
|
-
break;
|
|
343
|
-
|
|
344
|
-
case 'boot':
|
|
345
|
-
await plugin.boot?.(ctx);
|
|
346
|
-
entry.state = 'booted';
|
|
347
|
-
this.events.emit('plugin:booted', entry.meta);
|
|
348
|
-
break;
|
|
349
|
-
|
|
350
|
-
case 'ready':
|
|
351
|
-
await plugin.ready?.(ctx);
|
|
352
|
-
entry.state = 'ready';
|
|
353
|
-
this.events.emit('plugin:ready', entry.meta);
|
|
354
|
-
break;
|
|
355
|
-
|
|
356
|
-
case 'shutdown':
|
|
357
|
-
await plugin.shutdown?.(ctx);
|
|
358
|
-
entry.state = 'shutdown';
|
|
359
|
-
this.events.emit('plugin:shutdown', entry.meta);
|
|
360
|
-
break;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (this.debug) {
|
|
364
|
-
console.log(`[PluginManager] ${phase}: ${entry.meta.name} ✓`);
|
|
365
|
-
}
|
|
366
|
-
} catch (error) {
|
|
367
|
-
entry.state = 'error';
|
|
368
|
-
entry.error = error as Error;
|
|
369
|
-
this.events.emit('plugin:error', entry.meta, error as Error);
|
|
370
|
-
throw new Error(
|
|
371
|
-
`Plugin "${entry.meta.name}" failed during ${phase}: ${(error as Error).message}`
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
this.events.emit('lifecycle:complete', phase);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Initialize all plugins (configure → register → boot)
|
|
381
|
-
*/
|
|
382
|
-
async initialize(): Promise<void> {
|
|
383
|
-
await this.runPhase('configure');
|
|
384
|
-
await this.runPhase('register');
|
|
385
|
-
await this.runPhase('boot');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Notify plugins that server is ready
|
|
390
|
-
*/
|
|
391
|
-
async notifyReady(): Promise<void> {
|
|
392
|
-
await this.runPhase('ready');
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Shutdown all plugins
|
|
397
|
-
*/
|
|
398
|
-
async shutdown(): Promise<void> {
|
|
399
|
-
await this.runPhase('shutdown');
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Get context decorators (for Context to apply)
|
|
404
|
-
*/
|
|
405
|
-
getContextDecorators(): Array<(ctx: Context) => void> {
|
|
406
|
-
return this.contextDecorators;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Subscribe to plugin manager events
|
|
411
|
-
*/
|
|
412
|
-
on<K extends keyof PluginManagerEvents>(
|
|
413
|
-
event: K,
|
|
414
|
-
listener: PluginManagerEvents[K]
|
|
415
|
-
): this {
|
|
416
|
-
this.events.on(event, listener);
|
|
417
|
-
return this;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Get current lifecycle phase
|
|
422
|
-
*/
|
|
423
|
-
getCurrentPhase(): PluginPhase {
|
|
424
|
-
return this.currentPhase;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Get plugins in error state
|
|
429
|
-
*/
|
|
430
|
-
getErrors(): Array<{ meta: PluginMeta; error: Error }> {
|
|
431
|
-
return Array.from(this.plugins.values())
|
|
432
|
-
.filter(e => e.state === 'error')
|
|
433
|
-
.map(e => ({ meta: e.meta, error: e.error! }));
|
|
434
|
-
}
|
|
435
|
-
}
|