rpc4next 0.1.1 → 0.1.3

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 CHANGED
@@ -45,8 +45,7 @@ export async function GET(
45
45
  }
46
46
  ```
47
47
 
48
- - `GET`、`POST` などのハンドラを定義
49
- - **RPCとして利用するには、`NextResponse.json()` によるレスポンス返却が必須です**
48
+ - **RPCとしてresponseの戻り値の推論が機能するのは、対象となる `route.ts` の HTTPメソッドハンドラ内で`NextResponse.json()` をしている物のみになります**
50
49
 
51
50
  ---
52
51
 
@@ -0,0 +1,2 @@
1
+ import { CliOptions, Logger } from "./types";
2
+ export declare const handleCli: (baseDir: string, outputPath: string, options: CliOptions, logger: Logger) => number;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handleCli = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const generator_1 = require("./generator");
9
+ const watcher_1 = require("./watcher");
10
+ const handleCli = (baseDir, outputPath, options, logger) => {
11
+ const resolvedBaseDir = path_1.default.resolve(baseDir).replace(/\\/g, "/");
12
+ const resolvedOutputPath = path_1.default.resolve(outputPath).replace(/\\/g, "/");
13
+ const paramsFileName = typeof options.paramsFile === "string" ? options.paramsFile : null;
14
+ if (options.paramsFile !== undefined && !paramsFileName) {
15
+ logger.error("Error: --params-file requires a filename.");
16
+ return 1;
17
+ }
18
+ (0, generator_1.generate)({
19
+ baseDir: resolvedBaseDir,
20
+ outputPath: resolvedOutputPath,
21
+ paramsFileName: options.paramsFile || null,
22
+ logger,
23
+ });
24
+ if (options.watch) {
25
+ (0, watcher_1.setupWatcher)(resolvedBaseDir, () => {
26
+ (0, generator_1.generate)({
27
+ baseDir: resolvedBaseDir,
28
+ outputPath: resolvedOutputPath,
29
+ paramsFileName: options.paramsFile || null,
30
+ logger,
31
+ });
32
+ }, logger);
33
+ }
34
+ return 0;
35
+ };
36
+ exports.handleCli = handleCli;
package/dist/cli/cli.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ import { Logger } from "./types";
2
+ export declare const runCli: (argv: string[], logger?: Logger) => void;
package/dist/cli/cli.js CHANGED
@@ -1,81 +1,32 @@
1
- #!/usr/bin/env node
2
1
  "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
5
10
  };
6
11
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const chokidar_1 = __importDefault(require("chokidar"));
12
+ exports.runCli = void 0;
11
13
  const commander_1 = require("commander");
12
- const cache_1 = require("./cache");
13
- const debounce_1 = require("./debounce");
14
- const generate_path_structure_1 = require("./generate-path-structure");
15
- const program = new commander_1.Command();
16
- program
17
- .description("Generate RPC client type definitions based on the Next.js path structure.")
18
- .argument("<baseDir>", "Base directory containing Next.js paths for type generation")
19
- .argument("<outputPath>", "Output path for the generated type definitions")
20
- .option("-w, --watch", "Watch mode: regenerate on file changes")
21
- .option("--generate-params-types [filename]", "Generate params types file with specified filename")
22
- .action((baseDir, outputPath, options) => {
23
- const resolvedBaseDir = path_1.default.resolve(baseDir).replace(/\\/g, "/");
24
- const resolvedOutputPath = path_1.default.resolve(outputPath).replace(/\\/g, "/");
25
- const paramsFileName = typeof options.generateParamsTypes === "string"
26
- ? options.generateParamsTypes
27
- : null;
28
- if (options.generateParamsTypes !== undefined && !paramsFileName) {
29
- console.error(chalk_1.default.red("Error: --generate-params-types requires a filename (e.g., params.ts) when specified."));
30
- process.exit(1);
31
- }
32
- const log = (msg) => {
33
- const time = new Date().toLocaleTimeString();
34
- console.log(`${chalk_1.default.gray(`[${time}]`)} ${msg}`);
35
- };
36
- const generate = () => {
37
- log(chalk_1.default.cyan("Generating..."));
38
- const { pathStructure: outputContent, paramsTypes } = (0, generate_path_structure_1.generatePages)(resolvedOutputPath, resolvedBaseDir);
39
- fs_1.default.writeFileSync(resolvedOutputPath, outputContent);
40
- log(chalk_1.default.green(`RPC client type definitions generated at ${resolvedOutputPath}`));
41
- if (paramsFileName) {
42
- paramsTypes.forEach(({ paramsType, dirPath }) => {
43
- const filePath = `${dirPath}/${paramsFileName}`;
44
- fs_1.default.writeFileSync(filePath, paramsType);
45
- });
46
- log(chalk_1.default.green(`Params type files have been generated as '${paramsFileName}' alongside each route/page.`));
14
+ const cli_handler_1 = require("./cli-handler");
15
+ const logger_1 = require("./logger");
16
+ const runCli = (argv, logger = (0, logger_1.createLogger)()) => {
17
+ const program = new commander_1.Command();
18
+ program
19
+ .description("Generate RPC client type definitions based on the Next.js path structure.")
20
+ .argument("<baseDir>", "Base directory containing Next.js paths for type generation")
21
+ .argument("<outputPath>", "Output path for the generated type definitions")
22
+ .option("-w, --watch", "Watch mode: regenerate on file changes")
23
+ .option("-p, --params-file [filename]", "Generate params types file with specified filename")
24
+ .action((baseDir, outputPath, options) => __awaiter(void 0, void 0, void 0, function* () {
25
+ const exitCode = (0, cli_handler_1.handleCli)(baseDir, outputPath, options, logger);
26
+ if (!options.watch) {
27
+ process.exit(exitCode);
47
28
  }
48
- };
49
- generate();
50
- if (options.watch) {
51
- log(chalk_1.default.yellow(`Watching ${resolvedBaseDir} for changes...`));
52
- const isTargetFiles = (path) => path.endsWith("route.ts") || path.endsWith("page.tsx");
53
- const changedPaths = new Set();
54
- // Once the debounced function starts executing, no new watcher events will be processed until it completes.
55
- // This is due to JavaScript's single-threaded event loop: the current debounced function runs to completion,
56
- // and any new change events are queued until the execution finishes.
57
- const debouncedGenerate = (0, debounce_1.debounce)(() => {
58
- changedPaths.forEach((path) => {
59
- (0, cache_1.clearVisitedDirsCacheAbove)(path);
60
- });
61
- changedPaths.clear();
62
- (0, cache_1.clearCntCache)();
63
- generate();
64
- }, 300);
65
- const watcher = chokidar_1.default.watch(resolvedBaseDir, {
66
- ignoreInitial: true,
67
- // If we exclude everything except files using ignored, the watch mode will terminate, so we added "only files" to the exclusion condition.
68
- ignored: (path, stats) => !!(stats === null || stats === void 0 ? void 0 : stats.isFile()) && !isTargetFiles(path),
69
- });
70
- watcher.on("ready", () => {
71
- watcher.on("all", (event, path) => {
72
- if (isTargetFiles(path)) {
73
- log(`${chalk_1.default.magenta(`[${event}]`)} ${chalk_1.default.blue(path)}`);
74
- changedPaths.add(path);
75
- debouncedGenerate();
76
- }
77
- });
78
- });
79
- }
80
- });
81
- program.parse(process.argv);
29
+ }));
30
+ program.parse(argv);
31
+ };
32
+ exports.runCli = runCli;
@@ -0,0 +1,7 @@
1
+ import { Logger } from "./types";
2
+ export declare const generate: ({ baseDir, outputPath, paramsFileName, logger, }: {
3
+ baseDir: string;
4
+ outputPath: string;
5
+ paramsFileName: string | null;
6
+ logger: Logger;
7
+ }) => void;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generate = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const generate_path_structure_1 = require("./generate-path-structure");
9
+ const generate = ({ baseDir, outputPath, paramsFileName, logger, }) => {
10
+ logger.info("Generating...");
11
+ const { pathStructure, paramsTypes } = (0, generate_path_structure_1.generatePages)(outputPath, baseDir);
12
+ fs_1.default.writeFileSync(outputPath, pathStructure);
13
+ logger.success(`Generated types at ${outputPath}`);
14
+ if (paramsFileName) {
15
+ paramsTypes.forEach(({ paramsType, dirPath }) => {
16
+ const filePath = `${dirPath}/${paramsFileName}`;
17
+ fs_1.default.writeFileSync(filePath, paramsType);
18
+ });
19
+ logger.success(`Generated params type at ${paramsFileName}`);
20
+ }
21
+ };
22
+ exports.generate = generate;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("./cli");
5
+ (0, cli_1.runCli)(process.argv);
@@ -0,0 +1,2 @@
1
+ import { Logger } from "./types";
2
+ export declare const createLogger: () => Logger;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLogger = void 0;
4
+ const createLogger = () => {
5
+ return {
6
+ info: (msg) => console.log(msg),
7
+ success: (msg) => console.log(msg),
8
+ error: (msg) => console.error(msg),
9
+ };
10
+ };
11
+ exports.createLogger = createLogger;
@@ -1,2 +1,11 @@
1
1
  import type { END_POINT_FILE_NAMES } from "./constants";
2
2
  export type EndPointFileNames = (typeof END_POINT_FILE_NAMES)[number];
3
+ export interface Logger {
4
+ info: (msg: string) => void;
5
+ success: (msg: string) => void;
6
+ error: (msg: string) => void;
7
+ }
8
+ export interface CliOptions {
9
+ watch?: boolean;
10
+ paramsFile?: string;
11
+ }
@@ -0,0 +1,2 @@
1
+ import { Logger } from "./types";
2
+ export declare const setupWatcher: (baseDir: string, onGenerate: () => void, logger: Logger) => void;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setupWatcher = void 0;
7
+ const chokidar_1 = __importDefault(require("chokidar"));
8
+ const cache_1 = require("./cache");
9
+ const debounce_1 = require("./debounce");
10
+ const setupWatcher = (baseDir, onGenerate, logger) => {
11
+ logger.info(`Watching ${baseDir}...`);
12
+ const isTargetFiles = (path) => path.endsWith("route.ts") || path.endsWith("page.tsx");
13
+ const changedPaths = new Set();
14
+ // Once the debounced function starts executing, no new watcher events will be processed until it completes.
15
+ // This is due to JavaScript's single-threaded event loop: the current debounced function runs to completion,
16
+ // and any new change events are queued until the execution finishes.
17
+ const debouncedGenerate = (0, debounce_1.debounce)(() => {
18
+ changedPaths.forEach((path) => {
19
+ (0, cache_1.clearVisitedDirsCacheAbove)(path);
20
+ });
21
+ changedPaths.clear();
22
+ (0, cache_1.clearCntCache)();
23
+ onGenerate();
24
+ }, 300);
25
+ const watcher = chokidar_1.default.watch(baseDir, {
26
+ ignoreInitial: true,
27
+ // If we exclude everything except files using ignored, the watch mode will terminate, so we added "only files" to the exclusion condition.
28
+ ignored: (path, stats) => !!(stats === null || stats === void 0 ? void 0 : stats.isFile()) && !isTargetFiles(path),
29
+ });
30
+ watcher.on("ready", () => {
31
+ watcher.on("all", (event, path) => {
32
+ if (isTargetFiles(path)) {
33
+ logger.info(`[${event}] ${path}`);
34
+ changedPaths.add(path);
35
+ debouncedGenerate();
36
+ }
37
+ });
38
+ });
39
+ };
40
+ exports.setupWatcher = setupWatcher;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpc4next",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Inspired by Hono RPC and Pathpida, rpc4next brings a lightweight and intuitive RPC solution to Next.js, making server-client communication seamless",
5
5
  "author": "watanabe-1",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "dist"
25
25
  ],
26
26
  "bin": {
27
- "rpc4next": "dist/cli/cli.js"
27
+ "rpc4next": "dist/cli/index.js"
28
28
  },
29
29
  "exports": {
30
30
  "./client": {