wexts 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-342VRT25.mjs +504 -0
- package/dist/chunk-342VRT25.mjs.map +1 -0
- package/dist/chunk-7HNQWJWV.js +504 -0
- package/dist/chunk-7HNQWJWV.js.map +1 -0
- package/dist/chunk-7SSCNCTW.mjs +137 -0
- package/dist/chunk-7SSCNCTW.mjs.map +1 -0
- package/dist/chunk-7TLSPR65.mjs +95 -0
- package/dist/chunk-7TLSPR65.mjs.map +1 -0
- package/dist/chunk-AVMQJWYD.js +95 -0
- package/dist/chunk-AVMQJWYD.js.map +1 -0
- package/dist/chunk-O4II6N34.js +137 -0
- package/dist/chunk-O4II6N34.js.map +1 -0
- package/dist/cli/index.d.mts +13 -1
- package/dist/cli/index.d.ts +13 -1
- package/dist/cli/index.js +438 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +438 -54
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.js +3 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +2 -1
- package/dist/codegen/index.js +3 -2
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/index.mjs +2 -1
- package/dist/index.d.mts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +22 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -4
- package/dist/index.mjs.map +1 -1
- package/dist/next/index.js +68 -5
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +68 -5
- package/dist/next/index.mjs.map +1 -1
- package/dist/runtime/index.js +9 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/index.mjs +9 -1
- package/dist/runtime/index.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/nestjs-api/package-lock.json +0 -5623
- package/templates/nextjs-web/package-lock.json +0 -3254
package/dist/cli/index.mjs
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
logger
|
|
4
4
|
} from "../chunk-JHOVXH3X.mjs";
|
|
5
|
+
import {
|
|
6
|
+
WextsError,
|
|
7
|
+
formatWextsError
|
|
8
|
+
} from "../chunk-7TLSPR65.mjs";
|
|
5
9
|
import {
|
|
6
10
|
__dirname,
|
|
7
11
|
__filename,
|
|
@@ -16,8 +20,8 @@ import { spawnSync } from "child_process";
|
|
|
16
20
|
import { createRequire } from "module";
|
|
17
21
|
function createCliProgram() {
|
|
18
22
|
const program = new Command();
|
|
19
|
-
program.name("wexts").description("Wexts - production-focused single-runtime Next.js + NestJS toolkit").version(
|
|
20
|
-
program.command("create <project-name>").description("Create a
|
|
23
|
+
program.name("wexts").description("Wexts - production-focused single-runtime Next.js + NestJS toolkit").version(readPackageVersion());
|
|
24
|
+
program.command("create <project-name>").description("Create a verified Wexts starter").option("-t, --template <template>", "Template to use (starter|legacy)", "starter").option("--skip-install", "Skip dependency installation", false).action(async (projectName, options) => {
|
|
21
25
|
await createProject(projectName, options.template, {
|
|
22
26
|
skipInstall: options.skipInstall
|
|
23
27
|
});
|
|
@@ -33,8 +37,8 @@ function createCliProgram() {
|
|
|
33
37
|
useProxy: options.proxy
|
|
34
38
|
});
|
|
35
39
|
});
|
|
36
|
-
program.command("generate [type] [name]").alias("g").description("Generate RPC manifest/client, or scaffold a minimal RPC service").option("-p, --project <path>", "Path to NestJS project", "./apps/api").option("-o, --output <path>", "Output directory for generated RPC client", "./apps/web/lib/wexts").action(async (type, name, options) => {
|
|
37
|
-
if (!type || type === "rpc") {
|
|
40
|
+
program.command("generate [type] [name]").alias("g").description("Generate RPC manifest/client, or scaffold a minimal RPC service").option("-p, --project <path>", "Path to NestJS project", "./apps/api").option("-o, --output <path>", "Output directory for generated RPC client", "./apps/web/lib/wexts").option("--force", "Overwrite generated files if they already exist", false).action(async (type, name, options) => {
|
|
41
|
+
if (!type || type === "rpc" && !name) {
|
|
38
42
|
const { generateRpcClient } = await import("../codegen/index.mjs");
|
|
39
43
|
const manifest = await generateRpcClient({
|
|
40
44
|
projectPath: path.resolve(options.project),
|
|
@@ -43,13 +47,19 @@ function createCliProgram() {
|
|
|
43
47
|
logger.success(`Generated Wexts RPC client for ${manifest.services.length} service(s).`);
|
|
44
48
|
return;
|
|
45
49
|
}
|
|
46
|
-
if (type
|
|
47
|
-
|
|
48
|
-
await
|
|
49
|
-
|
|
50
|
+
if (isScaffoldGenerator(type)) {
|
|
51
|
+
const targetRoot = type === "config" ? process.cwd() : path.resolve(options.project);
|
|
52
|
+
const changedFiles = await scaffoldGenerator({
|
|
53
|
+
type,
|
|
54
|
+
name,
|
|
55
|
+
targetRoot,
|
|
56
|
+
force: options.force
|
|
57
|
+
});
|
|
58
|
+
for (const file of changedFiles) logger.info(`created ${path.relative(process.cwd(), file)}`);
|
|
59
|
+
logger.success(`Generated ${type}${name ? ` ${name}` : ""}.`);
|
|
50
60
|
return;
|
|
51
61
|
}
|
|
52
|
-
throw new Error(`Unknown generator "${type}". Supported generators: rpc, service.`);
|
|
62
|
+
throw new Error(`Unknown generator "${type}". Supported generators: rpc, service, module, entity, guard, config.`);
|
|
53
63
|
});
|
|
54
64
|
program.command("codegen").description("Alias for wexts generate rpc").option("-p, --project <path>", "Path to NestJS project", "./apps/api").option("-o, --output <path>", "Output directory for generated RPC client", "./apps/web/lib/wexts").action(async (options) => {
|
|
55
65
|
const { generateRpcClient } = await import("../codegen/index.mjs");
|
|
@@ -157,78 +167,438 @@ async function createProject(projectName, template, options) {
|
|
|
157
167
|
if (fs.existsSync(projectPath)) {
|
|
158
168
|
throw new Error(`Directory already exists: ${projectName}`);
|
|
159
169
|
}
|
|
160
|
-
const templatePath = findTemplatePath();
|
|
161
|
-
if (!templatePath) {
|
|
162
|
-
throw new Error("Template directory not found in package.");
|
|
163
|
-
}
|
|
164
170
|
fs.mkdirSync(projectPath, {
|
|
165
171
|
recursive: true
|
|
166
172
|
});
|
|
167
|
-
if (template === "
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
if (template === "starter") {
|
|
174
|
+
await createVerifiedStarter(projectPath, projectName, options.wextsDependency ?? resolveCreateWextsDependency(projectPath));
|
|
175
|
+
} else if (template === "legacy") {
|
|
176
|
+
createLegacyProject(projectPath, projectName);
|
|
177
|
+
} else {
|
|
178
|
+
throw new Error(`Unknown template "${template}". Supported templates: starter, legacy.`);
|
|
179
|
+
}
|
|
180
|
+
if (!options.skipInstall) {
|
|
181
|
+
runCommand(detectPackageManager(projectPath), [
|
|
182
|
+
"install"
|
|
183
|
+
], projectPath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
__name(createProject, "createProject");
|
|
187
|
+
async function createVerifiedStarter(projectPath, projectName, wextsDependency) {
|
|
188
|
+
const files = {
|
|
189
|
+
"pnpm-workspace.yaml": "packages:\n - 'apps/*'\n",
|
|
190
|
+
"package.json": JSON.stringify({
|
|
179
191
|
name: projectName,
|
|
192
|
+
version: "0.1.0",
|
|
180
193
|
private: true,
|
|
181
194
|
packageManager: "pnpm@10.22.0",
|
|
182
195
|
scripts: {
|
|
183
196
|
dev: "wexts dev",
|
|
184
|
-
generate: "wexts generate",
|
|
185
|
-
build: "
|
|
186
|
-
start: "wexts start",
|
|
187
|
-
|
|
197
|
+
generate: "wexts generate -p apps/api -o apps/web/lib/wexts",
|
|
198
|
+
build: "pnpm run generate && tsc -p apps/api/tsconfig.json && next build apps/web",
|
|
199
|
+
start: "wexts start -c ./wexts.runtime.js",
|
|
200
|
+
"vercel-build": "wexts vercel-build -p apps/api -o apps/web/lib/wexts -c ./wexts.runtime.js",
|
|
201
|
+
doctor: "wexts doctor",
|
|
202
|
+
"doctor:security": "wexts doctor --security"
|
|
203
|
+
},
|
|
204
|
+
dependencies: {
|
|
205
|
+
"@nestjs/common": "^11.1.19",
|
|
206
|
+
"@nestjs/core": "^11.1.19",
|
|
207
|
+
"@nestjs/platform-fastify": "^11.1.19",
|
|
208
|
+
next: "16.2.4",
|
|
209
|
+
react: "^19.2.5",
|
|
210
|
+
"react-dom": "^19.2.5",
|
|
211
|
+
"reflect-metadata": "^0.2.2",
|
|
212
|
+
rxjs: "^7.8.1",
|
|
213
|
+
wexts: wextsDependency
|
|
188
214
|
},
|
|
189
215
|
devDependencies: {
|
|
190
|
-
|
|
216
|
+
"@types/node": "^22.19.1",
|
|
217
|
+
"@types/react": "^19.2.14",
|
|
218
|
+
"@types/react-dom": "^19.2.3",
|
|
219
|
+
typescript: "^5.9.3"
|
|
191
220
|
}
|
|
192
|
-
}, null, 2)
|
|
193
|
-
|
|
194
|
-
|
|
221
|
+
}, null, 2),
|
|
222
|
+
"apps/api/package.json": JSON.stringify({
|
|
223
|
+
name: `${projectName}-api`,
|
|
224
|
+
private: true,
|
|
225
|
+
scripts: {
|
|
226
|
+
"start:dev": "tsc -w -p tsconfig.json"
|
|
227
|
+
}
|
|
228
|
+
}, null, 2),
|
|
229
|
+
"apps/api/tsconfig.json": JSON.stringify({
|
|
230
|
+
compilerOptions: {
|
|
231
|
+
target: "ES2023",
|
|
232
|
+
module: "NodeNext",
|
|
233
|
+
moduleResolution: "NodeNext",
|
|
234
|
+
experimentalDecorators: true,
|
|
235
|
+
emitDecoratorMetadata: true,
|
|
236
|
+
strict: true,
|
|
237
|
+
esModuleInterop: true,
|
|
238
|
+
skipLibCheck: true,
|
|
239
|
+
outDir: "dist",
|
|
240
|
+
rootDir: "src"
|
|
241
|
+
},
|
|
242
|
+
include: [
|
|
243
|
+
"src/**/*.ts"
|
|
244
|
+
]
|
|
245
|
+
}, null, 2),
|
|
246
|
+
"apps/api/src/hello.service.ts": `import { Injectable } from '@nestjs/common';
|
|
247
|
+
import { RpcMethod, RpcService } from 'wexts/nest';
|
|
248
|
+
|
|
249
|
+
@Injectable()
|
|
250
|
+
@RpcService({ name: 'hello', requireAuth: false })
|
|
251
|
+
export class HelloService {
|
|
252
|
+
@RpcMethod()
|
|
253
|
+
async sayHello(name: string): Promise<string> {
|
|
254
|
+
return \`Hello, \${name}!\`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
`,
|
|
258
|
+
"apps/web/package.json": JSON.stringify({
|
|
259
|
+
name: `${projectName}-web`,
|
|
260
|
+
private: true,
|
|
261
|
+
scripts: {
|
|
262
|
+
dev: "next dev -p 3000"
|
|
263
|
+
}
|
|
264
|
+
}, null, 2),
|
|
265
|
+
"apps/web/tsconfig.json": JSON.stringify({
|
|
266
|
+
compilerOptions: {
|
|
267
|
+
target: "ES2022",
|
|
268
|
+
lib: [
|
|
269
|
+
"dom",
|
|
270
|
+
"dom.iterable",
|
|
271
|
+
"es2022"
|
|
272
|
+
],
|
|
273
|
+
allowJs: false,
|
|
274
|
+
skipLibCheck: true,
|
|
275
|
+
strict: true,
|
|
276
|
+
noEmit: true,
|
|
277
|
+
esModuleInterop: true,
|
|
278
|
+
module: "esnext",
|
|
279
|
+
moduleResolution: "bundler",
|
|
280
|
+
resolveJsonModule: true,
|
|
281
|
+
isolatedModules: true,
|
|
282
|
+
jsx: "react-jsx",
|
|
283
|
+
incremental: true,
|
|
284
|
+
plugins: [
|
|
285
|
+
{
|
|
286
|
+
name: "next"
|
|
287
|
+
}
|
|
288
|
+
]
|
|
289
|
+
},
|
|
290
|
+
include: [
|
|
291
|
+
"next-env.d.ts",
|
|
292
|
+
"**/*.ts",
|
|
293
|
+
"**/*.tsx",
|
|
294
|
+
".next/types/**/*.ts",
|
|
295
|
+
".next/dev/types/**/*.ts"
|
|
296
|
+
],
|
|
297
|
+
exclude: [
|
|
298
|
+
"node_modules"
|
|
299
|
+
]
|
|
300
|
+
}, null, 2),
|
|
301
|
+
"apps/web/next-env.d.ts": `/// <reference types="next" />
|
|
302
|
+
/// <reference types="next/image-types/global" />
|
|
303
|
+
|
|
304
|
+
// This file is generated by Next.js. Do not edit.
|
|
305
|
+
`,
|
|
306
|
+
"apps/web/next.config.ts": `import type { NextConfig } from 'next';
|
|
307
|
+
|
|
308
|
+
const nextConfig: NextConfig = {
|
|
309
|
+
output: 'standalone',
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export default nextConfig;
|
|
313
|
+
`,
|
|
314
|
+
"apps/web/app/layout.tsx": `import type { ReactNode } from 'react';
|
|
315
|
+
import { WextsProvider } from '../lib/wexts-provider';
|
|
316
|
+
|
|
317
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
318
|
+
return (
|
|
319
|
+
<html lang="en">
|
|
320
|
+
<body>
|
|
321
|
+
<WextsProvider>{children}</WextsProvider>
|
|
322
|
+
</body>
|
|
323
|
+
</html>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
`,
|
|
327
|
+
"apps/web/app/page.tsx": `'use client';
|
|
328
|
+
|
|
329
|
+
import { useState } from 'react';
|
|
330
|
+
import { useWexts } from '../lib/wexts-provider';
|
|
331
|
+
|
|
332
|
+
export default function Page() {
|
|
333
|
+
const wexts = useWexts();
|
|
334
|
+
const [message, setMessage] = useState('Not called yet');
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<main>
|
|
338
|
+
<h1>Wexts Hello RPC</h1>
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
onClick={async () => {
|
|
342
|
+
setMessage(await wexts.hello.sayHello('Bob'));
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
345
|
+
Call RPC
|
|
346
|
+
</button>
|
|
347
|
+
<p>{message}</p>
|
|
348
|
+
</main>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
`,
|
|
352
|
+
"apps/web/lib/wexts-provider.tsx": `'use client';
|
|
353
|
+
|
|
354
|
+
import { FusionProvider, useWexts as useGeneratedWexts } from 'wexts/next';
|
|
355
|
+
import { createWextsClient, type WextsClient } from './wexts/client';
|
|
356
|
+
|
|
357
|
+
export function WextsProvider({ children }: { children: React.ReactNode }) {
|
|
358
|
+
return (
|
|
359
|
+
<FusionProvider rpcClient={createWextsClient({ baseUrl: '/rpc' })}>
|
|
360
|
+
{children}
|
|
361
|
+
</FusionProvider>
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function useWexts(): WextsClient {
|
|
366
|
+
return useGeneratedWexts<WextsClient>();
|
|
367
|
+
}
|
|
368
|
+
`,
|
|
369
|
+
"wexts.runtime.js": `const { HelloService } = require('./apps/api/dist/hello.service.js');
|
|
370
|
+
|
|
371
|
+
module.exports = {
|
|
372
|
+
nextDir: './apps/web',
|
|
373
|
+
rpcManifestPath: './apps/web/lib/wexts/wexts.rpc.manifest.json',
|
|
374
|
+
rpcServices: {
|
|
375
|
+
hello: new HelloService(),
|
|
376
|
+
},
|
|
377
|
+
security: {
|
|
378
|
+
allowedOrigins: ['http://localhost:3000'],
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
`,
|
|
382
|
+
"README.md": `# ${projectName}
|
|
383
|
+
|
|
384
|
+
Verified Wexts starter with a generated Hello RPC client.
|
|
385
|
+
|
|
386
|
+
\`\`\`bash
|
|
387
|
+
pnpm install
|
|
388
|
+
pnpm run generate
|
|
389
|
+
pnpm run build
|
|
390
|
+
pnpm run doctor
|
|
391
|
+
pnpm run doctor:security
|
|
392
|
+
pnpm run start
|
|
393
|
+
\`\`\`
|
|
394
|
+
`
|
|
395
|
+
};
|
|
396
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
397
|
+
const absolutePath = path.join(projectPath, relativePath);
|
|
398
|
+
fs.mkdirSync(path.dirname(absolutePath), {
|
|
195
399
|
recursive: true
|
|
196
400
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
401
|
+
fs.writeFileSync(absolutePath, content);
|
|
402
|
+
}
|
|
403
|
+
const { generateRpcClient } = await import("../codegen/index.mjs");
|
|
404
|
+
await generateRpcClient({
|
|
405
|
+
projectPath: path.join(projectPath, "apps/api"),
|
|
406
|
+
outputPath: path.join(projectPath, "apps/web/lib/wexts")
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
__name(createVerifiedStarter, "createVerifiedStarter");
|
|
410
|
+
function createLegacyProject(projectPath, projectName) {
|
|
411
|
+
const templatePath = findTemplatePath();
|
|
412
|
+
if (!templatePath) {
|
|
413
|
+
throw new Error("Template directory not found in package.");
|
|
414
|
+
}
|
|
415
|
+
fs.mkdirSync(path.join(projectPath, "apps"), {
|
|
416
|
+
recursive: true
|
|
417
|
+
});
|
|
418
|
+
fs.cpSync(path.join(templatePath, "nestjs-api"), path.join(projectPath, "apps/api"), {
|
|
419
|
+
recursive: true
|
|
420
|
+
});
|
|
421
|
+
fs.cpSync(path.join(templatePath, "nextjs-web"), path.join(projectPath, "apps/web"), {
|
|
422
|
+
recursive: true
|
|
423
|
+
});
|
|
424
|
+
fs.rmSync(path.join(projectPath, "apps/web/package-lock.json"), {
|
|
425
|
+
force: true
|
|
426
|
+
});
|
|
427
|
+
fs.rmSync(path.join(projectPath, "apps/api/package-lock.json"), {
|
|
428
|
+
force: true
|
|
429
|
+
});
|
|
430
|
+
fs.writeFileSync(path.join(projectPath, "pnpm-workspace.yaml"), "packages:\n - 'apps/*'\n");
|
|
431
|
+
fs.writeFileSync(path.join(projectPath, "package.json"), JSON.stringify({
|
|
432
|
+
name: projectName,
|
|
433
|
+
private: true,
|
|
434
|
+
packageManager: "pnpm@10.22.0",
|
|
435
|
+
scripts: {
|
|
436
|
+
dev: "wexts dev",
|
|
437
|
+
generate: "wexts generate",
|
|
438
|
+
build: "wexts build",
|
|
439
|
+
start: "wexts start",
|
|
440
|
+
doctor: "wexts doctor"
|
|
441
|
+
},
|
|
442
|
+
devDependencies: {
|
|
443
|
+
wexts: `^${readPackageVersion()}`
|
|
444
|
+
}
|
|
445
|
+
}, null, 2));
|
|
446
|
+
}
|
|
447
|
+
__name(createLegacyProject, "createLegacyProject");
|
|
448
|
+
function resolveCreateWextsDependency(projectPath) {
|
|
449
|
+
const packageRoot = path.resolve(__dirname, "../..");
|
|
450
|
+
const cwdLocalPackage = path.join(process.cwd(), "node_modules/wexts");
|
|
451
|
+
try {
|
|
452
|
+
if (fs.existsSync(cwdLocalPackage) && fs.realpathSync(cwdLocalPackage) === fs.realpathSync(packageRoot)) {
|
|
453
|
+
return `file:${path.relative(projectPath, cwdLocalPackage)}`;
|
|
454
|
+
}
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
return `^${readPackageVersion()}`;
|
|
458
|
+
}
|
|
459
|
+
__name(resolveCreateWextsDependency, "resolveCreateWextsDependency");
|
|
460
|
+
async function scaffoldGenerator(options) {
|
|
461
|
+
if (options.type !== "config" && !options.name) {
|
|
462
|
+
throw new WextsError({
|
|
463
|
+
code: "WEXTS_CLI_GENERATOR_NAME_REQUIRED",
|
|
464
|
+
message: `Generator "${options.type}" requires a name.`,
|
|
465
|
+
suggestedFix: `Run \`wexts generate ${options.type} hello\` or use \`wexts generate config\`.`,
|
|
466
|
+
docsSlug: "cli"
|
|
200
467
|
});
|
|
201
|
-
} else {
|
|
202
|
-
throw new Error(`Unknown template "${template}".`);
|
|
203
468
|
}
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
469
|
+
if (options.type === "config") {
|
|
470
|
+
return writeGeneratedFiles(options.targetRoot, [
|
|
471
|
+
{
|
|
472
|
+
relativePath: "wexts.runtime.js",
|
|
473
|
+
content: `/** @type {import('wexts/runtime').WextsRuntimeConfig} */
|
|
474
|
+
module.exports = {
|
|
475
|
+
rootDir: __dirname,
|
|
476
|
+
port: Number(process.env.PORT || 3000),
|
|
477
|
+
rpcManifestPath: 'apps/web/lib/wexts/wexts.rpc.manifest.json',
|
|
478
|
+
security: {
|
|
479
|
+
enabled: true,
|
|
480
|
+
production: process.env.NODE_ENV === 'production',
|
|
481
|
+
allowedOrigins: process.env.WEXTS_ALLOWED_ORIGINS?.split(',').filter(Boolean) || [],
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
`
|
|
485
|
+
}
|
|
486
|
+
], Boolean(options.force));
|
|
487
|
+
}
|
|
488
|
+
const rawName = options.name;
|
|
489
|
+
const name = toKebabCase(rawName);
|
|
490
|
+
const classBase = toPascalCase(name);
|
|
491
|
+
const srcRoot = path.join(options.targetRoot, "src");
|
|
492
|
+
const filesByType = {
|
|
493
|
+
rpc: rpcServiceFiles(name, classBase),
|
|
494
|
+
service: [
|
|
495
|
+
{
|
|
496
|
+
relativePath: path.join("src", name, `${name}.service.ts`),
|
|
497
|
+
content: `import { Injectable } from '@nestjs/common';
|
|
498
|
+
|
|
499
|
+
@Injectable()
|
|
500
|
+
export class ${classBase}Service {
|
|
501
|
+
async execute(): Promise<string> {
|
|
502
|
+
return '${toCamelCase(name)}';
|
|
208
503
|
}
|
|
209
504
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
505
|
+
`
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
module: [
|
|
509
|
+
{
|
|
510
|
+
relativePath: path.join("src", name, `${name}.module.ts`),
|
|
511
|
+
content: `import { Module } from '@nestjs/common';
|
|
512
|
+
|
|
513
|
+
@Module({})
|
|
514
|
+
export class ${classBase}Module {}
|
|
515
|
+
`
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
entity: [
|
|
519
|
+
{
|
|
520
|
+
relativePath: path.join("src", name, `${name}.entity.ts`),
|
|
521
|
+
content: `export interface ${classBase}Entity {
|
|
522
|
+
id: string;
|
|
523
|
+
createdAt: Date;
|
|
524
|
+
updatedAt: Date;
|
|
525
|
+
}
|
|
526
|
+
`
|
|
527
|
+
}
|
|
528
|
+
],
|
|
529
|
+
guard: [
|
|
530
|
+
{
|
|
531
|
+
relativePath: path.join("src", name, `${name}.guard.ts`),
|
|
532
|
+
content: `import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
|
533
|
+
|
|
534
|
+
@Injectable()
|
|
535
|
+
export class ${classBase}Guard implements CanActivate {
|
|
536
|
+
canActivate(_context: ExecutionContext): boolean {
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
`
|
|
541
|
+
}
|
|
542
|
+
]
|
|
543
|
+
};
|
|
544
|
+
fs.mkdirSync(srcRoot, {
|
|
216
545
|
recursive: true
|
|
217
546
|
});
|
|
218
|
-
|
|
547
|
+
return writeGeneratedFiles(options.targetRoot, filesByType[options.type], Boolean(options.force));
|
|
548
|
+
}
|
|
549
|
+
__name(scaffoldGenerator, "scaffoldGenerator");
|
|
550
|
+
function isScaffoldGenerator(type) {
|
|
551
|
+
return [
|
|
552
|
+
"rpc",
|
|
553
|
+
"service",
|
|
554
|
+
"module",
|
|
555
|
+
"entity",
|
|
556
|
+
"guard",
|
|
557
|
+
"config"
|
|
558
|
+
].includes(type);
|
|
559
|
+
}
|
|
560
|
+
__name(isScaffoldGenerator, "isScaffoldGenerator");
|
|
561
|
+
function rpcServiceFiles(serviceName, classBase) {
|
|
562
|
+
return [
|
|
563
|
+
{
|
|
564
|
+
relativePath: path.join("src", serviceName, `${serviceName}.service.ts`),
|
|
565
|
+
content: `import { Injectable } from '@nestjs/common';
|
|
219
566
|
import { RpcMethod, RpcService } from 'wexts/nest';
|
|
220
567
|
|
|
221
568
|
@Injectable()
|
|
222
569
|
@RpcService({ name: '${toCamelCase(serviceName)}', requireAuth: false })
|
|
223
|
-
export class ${
|
|
570
|
+
export class ${classBase}Service {
|
|
224
571
|
@RpcMethod()
|
|
225
572
|
async sayHello(name: string): Promise<string> {
|
|
226
573
|
return \`Hello, \${name}!\`;
|
|
227
574
|
}
|
|
228
575
|
}
|
|
229
|
-
`
|
|
576
|
+
`
|
|
577
|
+
}
|
|
578
|
+
];
|
|
579
|
+
}
|
|
580
|
+
__name(rpcServiceFiles, "rpcServiceFiles");
|
|
581
|
+
function writeGeneratedFiles(root, files, force) {
|
|
582
|
+
const changedFiles = [];
|
|
583
|
+
for (const file of files) {
|
|
584
|
+
const absolutePath = path.join(root, file.relativePath);
|
|
585
|
+
if (fs.existsSync(absolutePath) && !force) {
|
|
586
|
+
throw new WextsError({
|
|
587
|
+
code: "WEXTS_CLI_GENERATOR_FILE_EXISTS",
|
|
588
|
+
message: `Refusing to overwrite existing file: ${absolutePath}`,
|
|
589
|
+
suggestedFix: "Review the file, then rerun with --force if overwriting is intentional.",
|
|
590
|
+
docsSlug: "cli"
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
fs.mkdirSync(path.dirname(absolutePath), {
|
|
594
|
+
recursive: true
|
|
595
|
+
});
|
|
596
|
+
fs.writeFileSync(absolutePath, file.content);
|
|
597
|
+
changedFiles.push(absolutePath);
|
|
598
|
+
}
|
|
599
|
+
return changedFiles;
|
|
230
600
|
}
|
|
231
|
-
__name(
|
|
601
|
+
__name(writeGeneratedFiles, "writeGeneratedFiles");
|
|
232
602
|
function runScript(script, options) {
|
|
233
603
|
const cwd = options.cwd ?? process.cwd();
|
|
234
604
|
const packageManager = detectPackageManager(cwd);
|
|
@@ -254,7 +624,13 @@ function runCommand(command, args, cwd) {
|
|
|
254
624
|
}
|
|
255
625
|
__name(runCommand, "runCommand");
|
|
256
626
|
function detectPackageManager(cwd) {
|
|
627
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
628
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
629
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
630
|
+
if (pkg.packageManager?.startsWith("pnpm@")) return "pnpm";
|
|
631
|
+
}
|
|
257
632
|
if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
633
|
+
if (fs.existsSync(path.join(cwd, "pnpm-workspace.yaml"))) return "pnpm";
|
|
258
634
|
return "npm";
|
|
259
635
|
}
|
|
260
636
|
__name(detectPackageManager, "detectPackageManager");
|
|
@@ -267,6 +643,12 @@ function findTemplatePath() {
|
|
|
267
643
|
return candidates.find((candidate) => fs.existsSync(candidate));
|
|
268
644
|
}
|
|
269
645
|
__name(findTemplatePath, "findTemplatePath");
|
|
646
|
+
function readPackageVersion() {
|
|
647
|
+
const packageJsonPath = path.resolve(__dirname, "../../package.json");
|
|
648
|
+
if (!fs.existsSync(packageJsonPath)) return "0.0.0";
|
|
649
|
+
return JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).version;
|
|
650
|
+
}
|
|
651
|
+
__name(readPackageVersion, "readPackageVersion");
|
|
270
652
|
function readAllText(cwd, dirs) {
|
|
271
653
|
let text = "";
|
|
272
654
|
for (const dir of dirs) {
|
|
@@ -323,12 +705,14 @@ __name(loadRuntimeConfig, "loadRuntimeConfig");
|
|
|
323
705
|
var invokedAsCli = process.argv[1] && (path.basename(process.argv[1]) === "wexts" || path.basename(process.argv[1]) === "wexts.cjs" || path.resolve(process.argv[1]).includes(`${path.sep}dist${path.sep}cli${path.sep}index`));
|
|
324
706
|
if (invokedAsCli && !process.env.VITEST) {
|
|
325
707
|
createCliProgram().parseAsync(process.argv).catch((error) => {
|
|
326
|
-
logger.error(
|
|
708
|
+
logger.error(formatWextsError(error));
|
|
327
709
|
process.exit(1);
|
|
328
710
|
});
|
|
329
711
|
}
|
|
330
712
|
export {
|
|
331
713
|
createCliProgram,
|
|
332
|
-
|
|
714
|
+
createProject,
|
|
715
|
+
runDoctor,
|
|
716
|
+
scaffoldGenerator
|
|
333
717
|
};
|
|
334
718
|
//# sourceMappingURL=index.mjs.map
|