@engjts/nexus 0.1.7 → 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/dist/advanced/playground/generatePlaygroundHTML.d.ts.map +1 -1
- package/dist/advanced/playground/generatePlaygroundHTML.js +107 -0
- package/dist/advanced/playground/generatePlaygroundHTML.js.map +1 -1
- package/dist/advanced/playground/playground.d.ts +19 -0
- package/dist/advanced/playground/playground.d.ts.map +1 -1
- package/dist/advanced/playground/playground.js +70 -0
- package/dist/advanced/playground/playground.js.map +1 -1
- package/dist/advanced/playground/types.d.ts +20 -0
- package/dist/advanced/playground/types.d.ts.map +1 -1
- package/dist/core/application.d.ts +14 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/application.js +173 -71
- package/dist/core/application.js.map +1 -1
- package/dist/core/context-pool.d.ts +2 -13
- package/dist/core/context-pool.d.ts.map +1 -1
- package/dist/core/context-pool.js +7 -45
- package/dist/core/context-pool.js.map +1 -1
- package/dist/core/context.d.ts +108 -5
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +449 -53
- package/dist/core/context.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/middleware.d.ts +6 -0
- package/dist/core/middleware.d.ts.map +1 -1
- package/dist/core/middleware.js +83 -84
- package/dist/core/middleware.js.map +1 -1
- package/dist/core/performance/fast-json.d.ts +149 -0
- package/dist/core/performance/fast-json.d.ts.map +1 -0
- package/dist/core/performance/fast-json.js +473 -0
- package/dist/core/performance/fast-json.js.map +1 -0
- package/dist/core/router/file-router.d.ts +20 -7
- package/dist/core/router/file-router.d.ts.map +1 -1
- package/dist/core/router/file-router.js +41 -13
- package/dist/core/router/file-router.js.map +1 -1
- package/dist/core/router/index.d.ts +6 -0
- package/dist/core/router/index.d.ts.map +1 -1
- package/dist/core/router/index.js +33 -6
- package/dist/core/router/index.js.map +1 -1
- package/dist/core/router/radix-tree.d.ts +4 -1
- package/dist/core/router/radix-tree.d.ts.map +1 -1
- package/dist/core/router/radix-tree.js +7 -3
- package/dist/core/router/radix-tree.js.map +1 -1
- package/dist/core/serializer.d.ts +251 -0
- package/dist/core/serializer.d.ts.map +1 -0
- package/dist/core/serializer.js +290 -0
- package/dist/core/serializer.js.map +1 -0
- package/dist/core/types.d.ts +39 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- 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 -1849
- 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 -170
- package/src/advanced/playground/types.ts +0 -20
- 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 -1335
- package/src/core/context-pool.ts +0 -127
- package/src/core/context.ts +0 -412
- package/src/core/index.ts +0 -80
- package/src/core/middleware.ts +0 -262
- 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 -594
- package/src/core/router/index.ts +0 -227
- package/src/core/router/radix-tree.ts +0 -226
- 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 -574
- 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 -264
- 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
package/src/cli/cli.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { CreateCommand } from './commands/create';
|
|
2
|
-
import { InitCommand } from './commands/init';
|
|
3
|
-
import { GenerateCommand } from './commands/generate';
|
|
4
|
-
import { AddCommand } from './commands/add';
|
|
5
|
-
import { DevCommand } from './commands/dev';
|
|
6
|
-
import { BuildCommand } from './commands/build';
|
|
7
|
-
import { HelpCommand } from './commands/help';
|
|
8
|
-
import { VersionCommand } from './commands/version';
|
|
9
|
-
import { Logger } from './utils/logger';
|
|
10
|
-
|
|
11
|
-
export interface Command {
|
|
12
|
-
name: string;
|
|
13
|
-
description: string;
|
|
14
|
-
usage: string;
|
|
15
|
-
options?: CommandOption[];
|
|
16
|
-
execute(args: string[], options: Record<string, string | boolean>): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface CommandOption {
|
|
20
|
-
name: string;
|
|
21
|
-
alias?: string;
|
|
22
|
-
description: string;
|
|
23
|
-
required?: boolean;
|
|
24
|
-
defaultValue?: string | boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class CLI {
|
|
28
|
-
private commands: Map<string, Command> = new Map();
|
|
29
|
-
private logger = new Logger();
|
|
30
|
-
|
|
31
|
-
constructor() {
|
|
32
|
-
this.registerCommands();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
private registerCommands(): void {
|
|
36
|
-
const commands: Command[] = [
|
|
37
|
-
new CreateCommand(),
|
|
38
|
-
new InitCommand(),
|
|
39
|
-
new GenerateCommand(),
|
|
40
|
-
new AddCommand(),
|
|
41
|
-
new DevCommand(),
|
|
42
|
-
new BuildCommand(),
|
|
43
|
-
new HelpCommand(() => this.commands),
|
|
44
|
-
new VersionCommand(),
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
for (const command of commands) {
|
|
48
|
-
this.commands.set(command.name, command);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async run(args: string[]): Promise<void> {
|
|
53
|
-
if (args.length === 0) {
|
|
54
|
-
this.showWelcome();
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const [commandName, ...rest] = args;
|
|
59
|
-
|
|
60
|
-
// Handle global flags
|
|
61
|
-
if (commandName === '--help' || commandName === '-h') {
|
|
62
|
-
const helpCommand = this.commands.get('help');
|
|
63
|
-
await helpCommand?.execute([], {});
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (commandName === '--version' || commandName === '-v') {
|
|
68
|
-
const versionCommand = this.commands.get('version');
|
|
69
|
-
await versionCommand?.execute([], {});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const command = this.commands.get(commandName);
|
|
74
|
-
if (!command) {
|
|
75
|
-
this.logger.error(`Unknown command: ${commandName}`);
|
|
76
|
-
this.logger.info('Run "nexus --help" for available commands');
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const { positionalArgs, options } = this.parseArgs(rest);
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
await command.execute(positionalArgs, options);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
if (error instanceof Error) {
|
|
86
|
-
this.logger.error(error.message);
|
|
87
|
-
}
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private parseArgs(args: string[]): {
|
|
93
|
-
positionalArgs: string[];
|
|
94
|
-
options: Record<string, string | boolean>;
|
|
95
|
-
} {
|
|
96
|
-
const positionalArgs: string[] = [];
|
|
97
|
-
const options: Record<string, string | boolean> = {};
|
|
98
|
-
|
|
99
|
-
for (let i = 0; i < args.length; i++) {
|
|
100
|
-
const arg = args[i];
|
|
101
|
-
|
|
102
|
-
if (arg.startsWith('--')) {
|
|
103
|
-
const [key, value] = arg.slice(2).split('=');
|
|
104
|
-
if (value !== undefined) {
|
|
105
|
-
options[key] = value;
|
|
106
|
-
} else if (args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
107
|
-
options[key] = args[++i];
|
|
108
|
-
} else {
|
|
109
|
-
options[key] = true;
|
|
110
|
-
}
|
|
111
|
-
} else if (arg.startsWith('-')) {
|
|
112
|
-
const key = arg.slice(1);
|
|
113
|
-
if (args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
114
|
-
options[key] = args[++i];
|
|
115
|
-
} else {
|
|
116
|
-
options[key] = true;
|
|
117
|
-
}
|
|
118
|
-
} else {
|
|
119
|
-
positionalArgs.push(arg);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return { positionalArgs, options };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private showWelcome(): void {
|
|
127
|
-
console.log(`
|
|
128
|
-
╔═══════════════════════════════════════════════════════════╗
|
|
129
|
-
║ ║
|
|
130
|
-
║ ███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗ ║
|
|
131
|
-
║ ████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝ ║
|
|
132
|
-
║ ██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗ ║
|
|
133
|
-
║ ██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║ ║
|
|
134
|
-
║ ██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║ ║
|
|
135
|
-
║ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ║
|
|
136
|
-
║ ║
|
|
137
|
-
║ Async-First Web Framework with Type-Safety ║
|
|
138
|
-
║ ║
|
|
139
|
-
╚═══════════════════════════════════════════════════════════╝
|
|
140
|
-
|
|
141
|
-
${this.logger.colors.cyan}Usage:${this.logger.colors.reset} nexus <command> [options]
|
|
142
|
-
|
|
143
|
-
${this.logger.colors.cyan}Commands:${this.logger.colors.reset}
|
|
144
|
-
create <name> Create a new Nexus project
|
|
145
|
-
init Initialize Nexus in current directory
|
|
146
|
-
generate <type> Generate components (route, middleware, etc.)
|
|
147
|
-
add <plugin> Add plugins (swagger, playground, postman)
|
|
148
|
-
dev Start development server
|
|
149
|
-
build Build for production
|
|
150
|
-
|
|
151
|
-
${this.logger.colors.cyan}Options:${this.logger.colors.reset}
|
|
152
|
-
--help, -h Show help
|
|
153
|
-
--version, -v Show version
|
|
154
|
-
|
|
155
|
-
Run ${this.logger.colors.green}nexus <command> --help${this.logger.colors.reset} for more information on a command.
|
|
156
|
-
`);
|
|
157
|
-
}
|
|
158
|
-
}
|
package/src/cli/commands/add.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { Command, CommandOption } from '../cli';
|
|
2
|
-
import { Logger } from '../utils/logger';
|
|
3
|
-
import { FileSystem } from '../utils/file-system';
|
|
4
|
-
|
|
5
|
-
type PluginType = 'playground' | 'postman' | 'swagger';
|
|
6
|
-
|
|
7
|
-
interface PluginConfig {
|
|
8
|
-
name: string;
|
|
9
|
-
import: string;
|
|
10
|
-
feature: string;
|
|
11
|
-
description: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class AddCommand implements Command {
|
|
15
|
-
name = 'add';
|
|
16
|
-
description = 'Add plugins to your Nexus project';
|
|
17
|
-
usage = 'nexus add <plugin> [options]';
|
|
18
|
-
options: CommandOption[] = [
|
|
19
|
-
{
|
|
20
|
-
name: 'path',
|
|
21
|
-
alias: 'p',
|
|
22
|
-
description: 'Path to the entry file (default: src/index.ts)',
|
|
23
|
-
defaultValue: 'src/index.ts',
|
|
24
|
-
},
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
private logger = new Logger();
|
|
28
|
-
private validPlugins: PluginType[] = ['playground', 'postman', 'swagger'];
|
|
29
|
-
|
|
30
|
-
private pluginConfigs: Record<PluginType, PluginConfig> = {
|
|
31
|
-
playground: {
|
|
32
|
-
name: 'playground',
|
|
33
|
-
import: 'playground',
|
|
34
|
-
feature: 'playground()',
|
|
35
|
-
description: 'Interactive API playground at /playground',
|
|
36
|
-
},
|
|
37
|
-
postman: {
|
|
38
|
-
name: 'postman',
|
|
39
|
-
import: 'postman',
|
|
40
|
-
feature: 'postman()',
|
|
41
|
-
description: 'Postman collection export at /postman',
|
|
42
|
-
},
|
|
43
|
-
swagger: {
|
|
44
|
-
name: 'swagger',
|
|
45
|
-
import: 'swagger',
|
|
46
|
-
feature: 'swagger()',
|
|
47
|
-
description: 'Swagger/OpenAPI documentation at /docs',
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
async execute(
|
|
52
|
-
args: string[],
|
|
53
|
-
options: Record<string, string | boolean>
|
|
54
|
-
): Promise<void> {
|
|
55
|
-
if (args.length < 1) {
|
|
56
|
-
this.showUsage();
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const [plugin] = args;
|
|
61
|
-
|
|
62
|
-
if (!this.validPlugins.includes(plugin as PluginType)) {
|
|
63
|
-
this.logger.error(`Invalid plugin: ${plugin}`);
|
|
64
|
-
this.logger.info(`Valid plugins: ${this.validPlugins.join(', ')}`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const entryPath = (options.path as string) || 'src/index.ts';
|
|
69
|
-
await this.addPlugin(plugin as PluginType, entryPath);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private async addPlugin(plugin: PluginType, entryPath: string): Promise<void> {
|
|
73
|
-
const fullPath = FileSystem.joinPath(process.cwd(), entryPath);
|
|
74
|
-
const config = this.pluginConfigs[plugin];
|
|
75
|
-
|
|
76
|
-
// Check if entry file exists
|
|
77
|
-
if (!(await FileSystem.exists(fullPath))) {
|
|
78
|
-
this.logger.error(`Entry file not found: ${fullPath}`);
|
|
79
|
-
this.logger.info('Use --path to specify your entry file');
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Read current file
|
|
84
|
-
let content = await FileSystem.readFile(fullPath);
|
|
85
|
-
|
|
86
|
-
// Check if plugin is already added
|
|
87
|
-
if (content.includes(`app.plugin(${config.feature})`)) {
|
|
88
|
-
this.logger.info(`Plugin "${plugin}" is already added to your project`);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Check if import already exists
|
|
93
|
-
const importRegex = new RegExp(`import\\s*{([^}]*)}\\s*from\\s*['"]@engjts/nexus['"]`);
|
|
94
|
-
const importMatch = content.match(importRegex);
|
|
95
|
-
|
|
96
|
-
if (importMatch) {
|
|
97
|
-
const currentImports = importMatch[1];
|
|
98
|
-
if (!currentImports.includes(config.import)) {
|
|
99
|
-
// Add to existing import
|
|
100
|
-
const newImports = currentImports.trim() + ', ' + config.import;
|
|
101
|
-
content = content.replace(importRegex, `import {${newImports}} from '@engjts/nexus'`);
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
// Add new import at the top
|
|
105
|
-
content = `import { ${config.import} } from '@engjts/nexus';\n${content}`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Find where to add app.plugin()
|
|
109
|
-
// Look for existing app.plugin() calls or app.use() calls
|
|
110
|
-
const pluginPattern = /app\.plugin\([^)]+\);?\n?/g;
|
|
111
|
-
const usePattern = /app\.use\([^)]+\);?\n?/;
|
|
112
|
-
const listenPattern = /app\.listen\(/;
|
|
113
|
-
|
|
114
|
-
let insertPosition = -1;
|
|
115
|
-
let insertText = `app.plugin(${config.feature});\n`;
|
|
116
|
-
|
|
117
|
-
// Find last app.plugin() call
|
|
118
|
-
let lastPluginMatch: RegExpExecArray | null = null;
|
|
119
|
-
let match;
|
|
120
|
-
while ((match = pluginPattern.exec(content)) !== null) {
|
|
121
|
-
lastPluginMatch = match;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (lastPluginMatch) {
|
|
125
|
-
// Insert after last plugin
|
|
126
|
-
insertPosition = lastPluginMatch.index + lastPluginMatch[0].length;
|
|
127
|
-
} else {
|
|
128
|
-
// Find app.use() or app.listen()
|
|
129
|
-
const useMatch = content.match(usePattern);
|
|
130
|
-
const listenMatch = content.match(listenPattern);
|
|
131
|
-
|
|
132
|
-
if (useMatch && useMatch.index !== undefined) {
|
|
133
|
-
// Insert before first app.use()
|
|
134
|
-
insertPosition = useMatch.index;
|
|
135
|
-
insertText = `// Plugins\napp.plugin(${config.feature});\n\n`;
|
|
136
|
-
} else if (listenMatch && listenMatch.index !== undefined) {
|
|
137
|
-
// Insert before app.listen()
|
|
138
|
-
insertPosition = listenMatch.index;
|
|
139
|
-
insertText = `// Plugins\napp.plugin(${config.feature});\n\n`;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (insertPosition === -1) {
|
|
144
|
-
this.logger.error('Could not find a suitable location to add the plugin');
|
|
145
|
-
this.logger.info('Please add manually: app.plugin(' + config.feature + ')');
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Insert the plugin call
|
|
150
|
-
content = content.slice(0, insertPosition) + insertText + content.slice(insertPosition);
|
|
151
|
-
|
|
152
|
-
// Write back
|
|
153
|
-
await FileSystem.writeFile(fullPath, content);
|
|
154
|
-
|
|
155
|
-
this.logger.success(`Added "${plugin}" plugin to your project`);
|
|
156
|
-
this.logger.info(` ${config.description}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private showUsage(): void {
|
|
160
|
-
console.log(`
|
|
161
|
-
${this.logger.colors.bright}Usage:${this.logger.colors.reset} nexus add <plugin> [options]
|
|
162
|
-
|
|
163
|
-
${this.logger.colors.bright}Plugins:${this.logger.colors.reset}
|
|
164
|
-
playground Add interactive API playground
|
|
165
|
-
postman Add Postman collection export
|
|
166
|
-
swagger Add Swagger/OpenAPI documentation
|
|
167
|
-
|
|
168
|
-
${this.logger.colors.bright}Examples:${this.logger.colors.reset}
|
|
169
|
-
nexus add swagger
|
|
170
|
-
nexus add playground
|
|
171
|
-
nexus add postman
|
|
172
|
-
nexus add swagger --path src/app.ts
|
|
173
|
-
|
|
174
|
-
${this.logger.colors.bright}Options:${this.logger.colors.reset}
|
|
175
|
-
--path, -p Path to entry file (default: src/index.ts)
|
|
176
|
-
`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { Command } from '../cli';
|
|
2
|
-
import { Logger } from '../utils/logger';
|
|
3
|
-
import { FileSystem } from '../utils/file-system';
|
|
4
|
-
import { spawnCommand } from '../utils/exec';
|
|
5
|
-
|
|
6
|
-
export class BuildCommand implements Command {
|
|
7
|
-
name = 'build';
|
|
8
|
-
description = 'Build the project for production';
|
|
9
|
-
usage = 'nexus build [options]';
|
|
10
|
-
options = [
|
|
11
|
-
{
|
|
12
|
-
name: 'outDir',
|
|
13
|
-
alias: 'o',
|
|
14
|
-
description: 'Output directory',
|
|
15
|
-
defaultValue: 'dist',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
name: 'minify',
|
|
19
|
-
description: 'Minify the output',
|
|
20
|
-
defaultValue: false,
|
|
21
|
-
},
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
private logger = new Logger();
|
|
25
|
-
|
|
26
|
-
async execute(
|
|
27
|
-
args: string[],
|
|
28
|
-
options: Record<string, string | boolean>
|
|
29
|
-
): Promise<void> {
|
|
30
|
-
const outDir = (options.outDir || options.o || 'dist') as string;
|
|
31
|
-
|
|
32
|
-
// Check if we're in a Nexus project
|
|
33
|
-
const packageJsonPath = FileSystem.joinPath(process.cwd(), 'package.json');
|
|
34
|
-
if (!(await FileSystem.exists(packageJsonPath))) {
|
|
35
|
-
this.logger.error('No package.json found. Are you in a Nexus project?');
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
this.logger.header('Building Nexus Project');
|
|
40
|
-
|
|
41
|
-
// Check for tsconfig.json
|
|
42
|
-
const tsconfigPath = FileSystem.joinPath(process.cwd(), 'tsconfig.json');
|
|
43
|
-
if (!(await FileSystem.exists(tsconfigPath))) {
|
|
44
|
-
this.logger.warning('No tsconfig.json found, using default configuration');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Clean output directory
|
|
48
|
-
this.logger.step(1, 3, 'Cleaning output directory...');
|
|
49
|
-
const outputPath = FileSystem.joinPath(process.cwd(), outDir);
|
|
50
|
-
await FileSystem.removeDirectory(outputPath);
|
|
51
|
-
this.logger.success(`Cleaned ${outDir}`);
|
|
52
|
-
|
|
53
|
-
// Run TypeScript compiler
|
|
54
|
-
this.logger.step(2, 3, 'Compiling TypeScript...');
|
|
55
|
-
const exitCode = await spawnCommand('npx', ['tsc', '--outDir', outDir], {
|
|
56
|
-
cwd: process.cwd(),
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
if (exitCode !== 0) {
|
|
60
|
-
this.logger.error('Build failed');
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
this.logger.success('TypeScript compiled');
|
|
64
|
-
|
|
65
|
-
// Done
|
|
66
|
-
this.logger.step(3, 3, 'Finalizing...');
|
|
67
|
-
this.logger.success('Build completed!');
|
|
68
|
-
|
|
69
|
-
this.logger.blank();
|
|
70
|
-
this.logger.info(`Output directory: ${outDir}`);
|
|
71
|
-
this.logger.info('Run "npm start" or "node dist/index.js" to start the server');
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { Command, CommandOption } from '../cli';
|
|
2
|
-
import { Logger } from '../utils/logger';
|
|
3
|
-
import { FileSystem } from '../utils/file-system';
|
|
4
|
-
import { spawnCommand, checkCommandExists } from '../utils/exec';
|
|
5
|
-
import { ProjectTemplates } from '../templates';
|
|
6
|
-
|
|
7
|
-
export class CreateCommand implements Command {
|
|
8
|
-
name = 'create';
|
|
9
|
-
description = 'Create a new Nexus project';
|
|
10
|
-
usage = 'nexus create <project-name> [options]';
|
|
11
|
-
options: CommandOption[] = [
|
|
12
|
-
{
|
|
13
|
-
name: 'template',
|
|
14
|
-
alias: 't',
|
|
15
|
-
description: 'Project template (basic, api, fullstack)',
|
|
16
|
-
defaultValue: 'basic',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: 'package-manager',
|
|
20
|
-
alias: 'pm',
|
|
21
|
-
description: 'Package manager to use (npm, yarn, pnpm, bun)',
|
|
22
|
-
defaultValue: 'npm',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: 'skip-install',
|
|
26
|
-
description: 'Skip dependency installation',
|
|
27
|
-
defaultValue: false,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'skip-git',
|
|
31
|
-
description: 'Skip git initialization',
|
|
32
|
-
defaultValue: false,
|
|
33
|
-
},
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
private logger = new Logger();
|
|
37
|
-
|
|
38
|
-
async execute(
|
|
39
|
-
args: string[],
|
|
40
|
-
options: Record<string, string | boolean>
|
|
41
|
-
): Promise<void> {
|
|
42
|
-
if (args.length === 0) {
|
|
43
|
-
this.logger.error('Project name is required');
|
|
44
|
-
this.logger.info('Usage: nexus create <project-name>');
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const projectName = args[0];
|
|
49
|
-
const template = (options.template || options.t || 'basic') as string;
|
|
50
|
-
const packageManager = (options['package-manager'] || options.pm || 'npm') as string;
|
|
51
|
-
const skipInstall = options['skip-install'] === true;
|
|
52
|
-
const skipGit = options['skip-git'] === true;
|
|
53
|
-
|
|
54
|
-
// Validate project name
|
|
55
|
-
if (!/^[a-z0-9-_]+$/i.test(projectName)) {
|
|
56
|
-
this.logger.error('Project name can only contain letters, numbers, hyphens, and underscores');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const projectPath = FileSystem.resolvePath(process.cwd(), projectName);
|
|
61
|
-
|
|
62
|
-
// Check if directory already exists
|
|
63
|
-
if (await FileSystem.exists(projectPath)) {
|
|
64
|
-
this.logger.error(`Directory "${projectName}" already exists`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
console.log(`
|
|
69
|
-
╔═══════════════════════════════════════════════════════════╗
|
|
70
|
-
║ ║
|
|
71
|
-
║ Creating new Nexus project: ${projectName.padEnd(25)} ║
|
|
72
|
-
║ ║
|
|
73
|
-
╚═══════════════════════════════════════════════════════════╝
|
|
74
|
-
`);
|
|
75
|
-
|
|
76
|
-
const totalSteps = skipInstall ? (skipGit ? 2 : 3) : (skipGit ? 3 : 4);
|
|
77
|
-
let currentStep = 0;
|
|
78
|
-
|
|
79
|
-
// Step 1: Create project structure
|
|
80
|
-
this.logger.step(++currentStep, totalSteps, 'Creating project structure...');
|
|
81
|
-
await this.createProjectStructure(projectPath, projectName, template);
|
|
82
|
-
this.logger.success('Project structure created');
|
|
83
|
-
|
|
84
|
-
// Step 2: Initialize git
|
|
85
|
-
if (!skipGit) {
|
|
86
|
-
this.logger.step(++currentStep, totalSteps, 'Initializing git repository...');
|
|
87
|
-
if (await checkCommandExists('git')) {
|
|
88
|
-
await spawnCommand('git', ['init'], { cwd: projectPath, stdio: 'pipe' });
|
|
89
|
-
this.logger.success('Git repository initialized');
|
|
90
|
-
} else {
|
|
91
|
-
this.logger.warning('Git not found, skipping git initialization');
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Step 3: Install dependencies
|
|
96
|
-
if (!skipInstall) {
|
|
97
|
-
this.logger.step(++currentStep, totalSteps, `Installing dependencies with ${packageManager}...`);
|
|
98
|
-
|
|
99
|
-
const installCommand = this.getInstallCommand(packageManager);
|
|
100
|
-
if (await checkCommandExists(packageManager)) {
|
|
101
|
-
await spawnCommand(installCommand.cmd, installCommand.args, { cwd: projectPath });
|
|
102
|
-
this.logger.success('Dependencies installed');
|
|
103
|
-
} else {
|
|
104
|
-
this.logger.warning(`${packageManager} not found, skipping dependency installation`);
|
|
105
|
-
this.logger.info(`Run "${packageManager} install" manually to install dependencies`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Step 4: Done!
|
|
110
|
-
this.logger.step(++currentStep, totalSteps, 'Finalizing...');
|
|
111
|
-
this.logger.success('Project created successfully!');
|
|
112
|
-
|
|
113
|
-
this.showNextSteps(projectName, packageManager);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private async createProjectStructure(
|
|
117
|
-
projectPath: string,
|
|
118
|
-
projectName: string,
|
|
119
|
-
template: string
|
|
120
|
-
): Promise<void> {
|
|
121
|
-
const templates = new ProjectTemplates(projectName);
|
|
122
|
-
const files = templates.getTemplate(template);
|
|
123
|
-
|
|
124
|
-
for (const [filePath, content] of Object.entries(files)) {
|
|
125
|
-
await FileSystem.writeFile(
|
|
126
|
-
FileSystem.joinPath(projectPath, filePath),
|
|
127
|
-
content
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private getInstallCommand(pm: string): { cmd: string; args: string[] } {
|
|
133
|
-
switch (pm) {
|
|
134
|
-
case 'yarn':
|
|
135
|
-
return { cmd: 'yarn', args: ['install'] };
|
|
136
|
-
case 'pnpm':
|
|
137
|
-
return { cmd: 'pnpm', args: ['install'] };
|
|
138
|
-
case 'bun':
|
|
139
|
-
return { cmd: 'bun', args: ['install'] };
|
|
140
|
-
default:
|
|
141
|
-
return { cmd: 'npm', args: ['install'] };
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private showNextSteps(projectName: string, pm: string): void {
|
|
146
|
-
const runCmd = pm === 'npm' ? 'npm run' : pm;
|
|
147
|
-
|
|
148
|
-
console.log(`
|
|
149
|
-
${this.logger.colors.green}✓ Success!${this.logger.colors.reset} Created ${this.logger.colors.cyan}${projectName}${this.logger.colors.reset}
|
|
150
|
-
|
|
151
|
-
${this.logger.colors.bright}Next steps:${this.logger.colors.reset}
|
|
152
|
-
|
|
153
|
-
${this.logger.colors.cyan}cd${this.logger.colors.reset} ${projectName}
|
|
154
|
-
${this.logger.colors.cyan}${runCmd}${this.logger.colors.reset} dev
|
|
155
|
-
|
|
156
|
-
${this.logger.colors.bright}Available commands:${this.logger.colors.reset}
|
|
157
|
-
|
|
158
|
-
${this.logger.colors.cyan}${runCmd} dev${this.logger.colors.reset} Start development server
|
|
159
|
-
${this.logger.colors.cyan}${runCmd} build${this.logger.colors.reset} Build for production
|
|
160
|
-
${this.logger.colors.cyan}${runCmd} start${this.logger.colors.reset} Start production server
|
|
161
|
-
${this.logger.colors.cyan}${runCmd} test${this.logger.colors.reset} Run tests
|
|
162
|
-
|
|
163
|
-
${this.logger.colors.dim}Happy coding with Nexus! 🚀${this.logger.colors.reset}
|
|
164
|
-
`);
|
|
165
|
-
}
|
|
166
|
-
}
|
package/src/cli/commands/dev.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { Command } from '../cli';
|
|
2
|
-
import { Logger } from '../utils/logger';
|
|
3
|
-
import { FileSystem } from '../utils/file-system';
|
|
4
|
-
import { spawnCommand } from '../utils/exec';
|
|
5
|
-
|
|
6
|
-
export class DevCommand implements Command {
|
|
7
|
-
name = 'dev';
|
|
8
|
-
description = 'Start development server with hot reload';
|
|
9
|
-
usage = 'nexus dev [options]';
|
|
10
|
-
options = [
|
|
11
|
-
{
|
|
12
|
-
name: 'port',
|
|
13
|
-
alias: 'p',
|
|
14
|
-
description: 'Port to run the server on',
|
|
15
|
-
defaultValue: '3000',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
name: 'host',
|
|
19
|
-
alias: 'H',
|
|
20
|
-
description: 'Host to bind the server to',
|
|
21
|
-
defaultValue: 'localhost',
|
|
22
|
-
},
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
private logger = new Logger();
|
|
26
|
-
|
|
27
|
-
async execute(
|
|
28
|
-
args: string[],
|
|
29
|
-
options: Record<string, string | boolean>
|
|
30
|
-
): Promise<void> {
|
|
31
|
-
const port = options.port || options.p || '3000';
|
|
32
|
-
const host = options.host || options.H || 'localhost';
|
|
33
|
-
|
|
34
|
-
// Check if we're in a Nexus project
|
|
35
|
-
const packageJsonPath = FileSystem.joinPath(process.cwd(), 'package.json');
|
|
36
|
-
if (!(await FileSystem.exists(packageJsonPath))) {
|
|
37
|
-
this.logger.error('No package.json found. Are you in a Nexus project?');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Check for main entry file
|
|
42
|
-
const possibleEntries = ['src/index.ts', 'src/main.ts', 'src/app.ts', 'index.ts'];
|
|
43
|
-
let entryFile: string | null = null;
|
|
44
|
-
|
|
45
|
-
for (const entry of possibleEntries) {
|
|
46
|
-
if (await FileSystem.exists(FileSystem.joinPath(process.cwd(), entry))) {
|
|
47
|
-
entryFile = entry;
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!entryFile) {
|
|
53
|
-
this.logger.error('No entry file found (src/index.ts, src/main.ts, etc.)');
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.logger.header('Starting Nexus Development Server');
|
|
58
|
-
this.logger.info(`Entry: ${entryFile}`);
|
|
59
|
-
this.logger.info(`Server: http://${host}:${port}`);
|
|
60
|
-
this.logger.blank();
|
|
61
|
-
|
|
62
|
-
// Try to use ts-node-dev, tsx, or ts-node
|
|
63
|
-
const runners = [
|
|
64
|
-
{ cmd: 'npx', args: ['tsx', 'watch', entryFile] },
|
|
65
|
-
{ cmd: 'npx', args: ['ts-node-dev', '--respawn', '--transpile-only', entryFile] },
|
|
66
|
-
{ cmd: 'npx', args: ['ts-node', entryFile] },
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
for (const runner of runners) {
|
|
70
|
-
try {
|
|
71
|
-
await spawnCommand(runner.cmd, runner.args, {
|
|
72
|
-
cwd: process.cwd(),
|
|
73
|
-
env: {
|
|
74
|
-
PORT: String(port),
|
|
75
|
-
HOST: String(host),
|
|
76
|
-
NODE_ENV: 'development',
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
break;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|