rpc4next 0.1.4 → 0.1.6

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.
Files changed (45) hide show
  1. package/README.md +18 -6
  2. package/dist/cli/cli-handler.js +8 -6
  3. package/dist/cli/core/alias.d.ts +1 -0
  4. package/dist/cli/core/alias.js +16 -0
  5. package/dist/cli/core/cache.d.ts +14 -0
  6. package/dist/cli/{cache.js → core/cache.js} +16 -10
  7. package/dist/cli/{route-scanner.d.ts → core/route-scanner.d.ts} +4 -0
  8. package/dist/cli/{route-scanner.js → core/route-scanner.js} +14 -6
  9. package/dist/cli/{scan-utils.d.ts → core/scan-utils.d.ts} +1 -2
  10. package/dist/cli/{scan-utils.js → core/scan-utils.js} +3 -11
  11. package/dist/cli/core/types.d.ts +2 -0
  12. package/dist/cli/core/types.js +2 -0
  13. package/dist/cli/debounce.d.ts +1 -1
  14. package/dist/cli/debounce.js +36 -7
  15. package/dist/cli/generator.js +1 -1
  16. package/dist/cli/types.d.ts +0 -2
  17. package/dist/cli/watcher.js +5 -3
  18. package/dist/helper/client/http-method.d.ts +6 -2
  19. package/dist/helper/client/http-method.js +23 -3
  20. package/dist/helper/client/rpc.d.ts +5 -0
  21. package/dist/helper/client/rpc.js +5 -2
  22. package/dist/helper/client/types.d.ts +39 -10
  23. package/dist/helper/server/create-handler.d.ts +2 -1
  24. package/dist/helper/server/create-route-context.d.ts +2 -1
  25. package/dist/helper/server/create-route-context.js +0 -2
  26. package/dist/helper/server/route-handler-factory.d.ts +6 -1
  27. package/dist/helper/server/route-handler-factory.js +4 -0
  28. package/dist/helper/server/route-types.d.ts +39 -0
  29. package/dist/helper/server/route-types.js +10 -0
  30. package/dist/helper/server/types.d.ts +3 -28
  31. package/dist/helper/server/types.js +0 -2
  32. package/dist/helper/server/validators/validator-utils.d.ts +2 -0
  33. package/dist/helper/server/validators/validator-utils.js +31 -0
  34. package/dist/helper/server/validators/zod/zod-validator.d.ts +11 -2
  35. package/dist/helper/server/validators/zod/zod-validator.js +18 -2
  36. package/package.json +1 -1
  37. package/dist/cli/cache.d.ts +0 -4
  38. /package/dist/cli/{constants.d.ts → core/constants.d.ts} +0 -0
  39. /package/dist/cli/{constants.js → core/constants.js} +0 -0
  40. /package/dist/cli/{generate-path-structure.d.ts → core/generate-path-structure.d.ts} +0 -0
  41. /package/dist/cli/{generate-path-structure.js → core/generate-path-structure.js} +0 -0
  42. /package/dist/cli/{path-utils.d.ts → core/path-utils.d.ts} +0 -0
  43. /package/dist/cli/{path-utils.js → core/path-utils.js} +0 -0
  44. /package/dist/cli/{type-utils.d.ts → core/type-utils.d.ts} +0 -0
  45. /package/dist/cli/{type-utils.js → core/type-utils.js} +0 -0
package/README.md CHANGED
@@ -9,7 +9,7 @@ Inspired by Hono RPC and Pathpida, **rpc4next** automatically generates a type-s
9
9
  ## ✨ Features
10
10
 
11
11
  - ✅ 既存の `app/**/route.ts` および `app/**/page.tsx` を活用するため、新たなハンドラファイルの作成は不要
12
- - ✅ ルート、パラメータ、リクエストボディ、レスポンスの型安全なクライアント生成
12
+ - ✅ ルート、パラメータ、クエリパラメータ、 リクエストボディ、レスポンスの型安全なクライアント生成
13
13
  - ✅ 最小限のセットアップで、カスタムサーバー不要
14
14
  - ✅ 動的ルート(`[id]`、`[...slug]` など)に対応
15
15
  - ✅ CLI による自動クライアント用型定義生成
@@ -30,20 +30,30 @@ npm install rpc4next
30
30
  ### 2. Define API Routes in Next.js
31
31
 
32
32
  Next.js プロジェクト内の既存の `app/**/route.ts` と `app/**/page.tsx` ファイルをそのまま利用できます。
33
+ さらに、クエリパラメータ(searchParams)の型安全性を有効にするには、対象のファイル内で `Query` または `OptionalQuery` 型を定義し、`export` してください。
33
34
 
34
35
  ```ts
35
36
  // app/api/user/[id]/route.ts
36
37
  import { NextRequest, NextResponse } from "next/server";
37
38
 
39
+ // searchParams用の型定義
40
+ export type Query = {
41
+ q: string; // 必須
42
+ page?: number; // 任意
43
+ };
44
+
38
45
  export async function GET(
39
46
  req: NextRequest,
40
47
  segmentData: { params: Promise<{ id: string }> }
41
48
  ) {
42
49
  const { id } = await segmentData.params;
43
- return NextResponse.json({ name: `User ${id}` });
50
+ const q = req.nextUrl.searchParams.get("q");
51
+ return NextResponse.json({ id, q });
44
52
  }
45
53
  ```
46
54
 
55
+ 🚩 Query or OptionalQuery 型を export することで、searchParams の型も自動的にクライアントに反映されます。
56
+
47
57
  - **RPCとしてresponseの戻り値の推論が機能するのは、対象となる `route.ts` の HTTPメソッドハンドラ内で`NextResponse.json()` をしている物のみになります**
48
58
 
49
59
  ---
@@ -102,14 +112,16 @@ export const rpc = createClient<PathStructure>();
102
112
  import { rpc } from "@/lib/rpcClient";
103
113
 
104
114
  export default async function Page() {
105
- const res = await rpc.api.user._id("123").$get();
115
+ const res = await rpc.api.user._id("123").$get({
116
+ query: { q: "hello", page: 1 },
117
+ });
106
118
  const json = await res.json();
107
- return <div>{json.name}</div>;
119
+ return <div>{json.q}</div>;
108
120
  }
109
121
  ```
110
122
 
111
123
  - エディタの補完機能により、利用可能なエンドポイントが自動的に表示されます。
112
- - リクエストの構造(params, searchParams)はサーバーコードから推論され、レスポンスも型安全に扱えます。
124
+ - リクエストの構造(params, query)はサーバーコードから推論され、レスポンスも型安全に扱えます。
113
125
 
114
126
  ---
115
127
 
@@ -126,7 +138,7 @@ export default async function Page() {
126
138
 
127
139
  2. **クライアント側補完強化**
128
140
 
129
- - `status`, `content-type`, `json()`, `text()` などがステータスに応じて適切に補完される
141
+ - `status`, `content-type`, `json()`, `text()` などが適切に補完される
130
142
 
131
143
  3. **サーバー側 params / query も型安全**
132
144
  - `routeHandlerFactory()` を使えば、`params`, `query` も型推論可能
@@ -15,12 +15,6 @@ const handleCli = (baseDir, outputPath, options, logger) => {
15
15
  logger.error("Error: --params-file requires a filename.");
16
16
  return 1;
17
17
  }
18
- (0, generator_1.generate)({
19
- baseDir: resolvedBaseDir,
20
- outputPath: resolvedOutputPath,
21
- paramsFileName: options.paramsFile || null,
22
- logger,
23
- });
24
18
  if (options.watch) {
25
19
  (0, watcher_1.setupWatcher)(resolvedBaseDir, () => {
26
20
  (0, generator_1.generate)({
@@ -31,6 +25,14 @@ const handleCli = (baseDir, outputPath, options, logger) => {
31
25
  });
32
26
  }, logger);
33
27
  }
28
+ else {
29
+ (0, generator_1.generate)({
30
+ baseDir: resolvedBaseDir,
31
+ outputPath: resolvedOutputPath,
32
+ paramsFileName: options.paramsFile || null,
33
+ logger,
34
+ });
35
+ }
34
36
  return 0;
35
37
  };
36
38
  exports.handleCli = handleCli;
@@ -0,0 +1 @@
1
+ export declare const createImportAlias: (path: string, name: string) => string;
@@ -0,0 +1,16 @@
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.createImportAlias = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const createImportAlias = (path, name) => {
9
+ const hash = crypto_1.default
10
+ .createHash("md5")
11
+ .update(`${path}::${name}`)
12
+ .digest("hex")
13
+ .slice(0, 16);
14
+ return `${name}_${hash}`;
15
+ };
16
+ exports.createImportAlias = createImportAlias;
@@ -0,0 +1,14 @@
1
+ export declare const visitedDirsCache: Map<string, boolean>;
2
+ export declare const scanAppDirCache: Map<string, {
3
+ pathStructure: string;
4
+ imports: {
5
+ statement: string;
6
+ path: string;
7
+ }[];
8
+ paramsTypes: {
9
+ paramsType: string;
10
+ path: string;
11
+ }[];
12
+ }>;
13
+ export declare const clearVisitedDirsCacheAbove: (targetPath: string) => void;
14
+ export declare const clearScanAppDirCacheAbove: (targetPath: string) => void;
@@ -3,22 +3,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.clearVisitedDirsCacheAbove = exports.clearCntCache = exports.cntCache = exports.visitedDirsCache = void 0;
6
+ exports.clearScanAppDirCacheAbove = exports.clearVisitedDirsCacheAbove = exports.scanAppDirCache = exports.visitedDirsCache = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
+ // Caches
8
9
  exports.visitedDirsCache = new Map();
9
- exports.cntCache = {};
10
- const clearCntCache = () => {
11
- Object.keys(exports.cntCache).forEach((key) => delete exports.cntCache[key]);
12
- };
13
- exports.clearCntCache = clearCntCache;
14
- const clearVisitedDirsCacheAbove = (targetPath) => {
10
+ exports.scanAppDirCache = new Map();
11
+ // Generic function to clear cache entries above a target path
12
+ const clearCacheAbove = (cache, targetPath) => {
15
13
  const basePath = path_1.default.resolve(targetPath);
16
- for (const key of exports.visitedDirsCache.keys()) {
14
+ [...cache.keys()].forEach((key) => {
17
15
  const normalizedKey = path_1.default.resolve(key);
18
16
  if (normalizedKey === basePath ||
19
17
  basePath.startsWith(normalizedKey + path_1.default.sep)) {
20
- exports.visitedDirsCache.delete(key);
18
+ cache.delete(key);
21
19
  }
22
- }
20
+ });
21
+ };
22
+ // Specific clear functions using the generic one
23
+ const clearVisitedDirsCacheAbove = (targetPath) => {
24
+ clearCacheAbove(exports.visitedDirsCache, targetPath);
23
25
  };
24
26
  exports.clearVisitedDirsCacheAbove = clearVisitedDirsCacheAbove;
27
+ const clearScanAppDirCacheAbove = (targetPath) => {
28
+ clearCacheAbove(exports.scanAppDirCache, targetPath);
29
+ };
30
+ exports.clearScanAppDirCacheAbove = clearScanAppDirCacheAbove;
@@ -1,3 +1,7 @@
1
+ /*!
2
+ * Inspired by pathpida (https://github.com/aspida/pathpida),
3
+ * especially the design and UX of its CLI.
4
+ */
1
5
  export declare const hasTargetFiles: (dirPath: string) => boolean;
2
6
  export declare const scanAppDir: (output: string, input: string, indent?: string, parentParams?: {
3
7
  paramName: string;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
- // Inspired by pathpida (https://github.com/aspida/pathpida)
3
- // Some parts of this code are based on or adapted from the pathpida project
2
+ /*!
3
+ * Inspired by pathpida (https://github.com/aspida/pathpida),
4
+ * especially the design and UX of its CLI.
5
+ */
4
6
  var __importDefault = (this && this.__importDefault) || function (mod) {
5
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
6
8
  };
@@ -12,7 +14,7 @@ const cache_1 = require("./cache");
12
14
  const constants_1 = require("./constants");
13
15
  const scan_utils_1 = require("./scan-utils");
14
16
  const type_utils_1 = require("./type-utils");
15
- const constants_2 = require("../lib/constants");
17
+ const constants_2 = require("../../lib/constants");
16
18
  const endPointFileNames = new Set(constants_1.END_POINT_FILE_NAMES);
17
19
  const hasTargetFiles = (dirPath) => {
18
20
  // Return cached result if available
@@ -48,6 +50,9 @@ const hasTargetFiles = (dirPath) => {
48
50
  };
49
51
  exports.hasTargetFiles = hasTargetFiles;
50
52
  const scanAppDir = (output, input, indent = "", parentParams = []) => {
53
+ if (cache_1.scanAppDirCache.has(input)) {
54
+ return cache_1.scanAppDirCache.get(input);
55
+ }
51
56
  indent += constants_1.INDENT;
52
57
  const pathStructures = [];
53
58
  const imports = [];
@@ -95,6 +100,7 @@ const scanAppDir = (output, input, indent = "", parentParams = []) => {
95
100
  : "";
96
101
  return { paramName: param, keyName: `${prefix}${param}` };
97
102
  })();
103
+ let nextParams = params;
98
104
  if (isDynamic || isCatchAll || isOptionalCatchAll) {
99
105
  const routeType = {
100
106
  isGroup,
@@ -103,10 +109,10 @@ const scanAppDir = (output, input, indent = "", parentParams = []) => {
103
109
  isCatchAll,
104
110
  isDynamic,
105
111
  };
106
- params.push({ paramName, routeType });
112
+ nextParams = [...params, { paramName, routeType }];
107
113
  }
108
114
  const isSkipDir = isGroup || isParallel;
109
- const { pathStructure: childPathStructure, imports: childImports, paramsTypes: childParamsTypes, } = (0, exports.scanAppDir)(output, fullPath, isSkipDir ? indent.replace(constants_1.INDENT, "") : indent, [...params]);
115
+ const { pathStructure: childPathStructure, imports: childImports, paramsTypes: childParamsTypes, } = (0, exports.scanAppDir)(output, fullPath, isSkipDir ? indent.replace(constants_1.INDENT, "") : indent, nextParams);
110
116
  imports.push(...childImports);
111
117
  paramsTypes.push(...childParamsTypes);
112
118
  if (isSkipDir) {
@@ -158,10 +164,12 @@ const scanAppDir = (output, input, indent = "", parentParams = []) => {
158
164
  const pathStructure = pathStructures.length > 0
159
165
  ? `${typeString}${typeString ? " & " : ""}{${constants_1.NEWLINE}${pathStructures.join(`,${constants_1.NEWLINE}`)}${constants_1.NEWLINE}${indent.replace(constants_1.INDENT, "")}}`
160
166
  : typeString;
161
- return {
167
+ const result = {
162
168
  pathStructure,
163
169
  imports,
164
170
  paramsTypes,
165
171
  };
172
+ cache_1.scanAppDirCache.set(input, result);
173
+ return result;
166
174
  };
167
175
  exports.scanAppDir = scanAppDir;
@@ -1,5 +1,4 @@
1
- import { HttpMethod } from "../lib/types";
2
- export declare const createImportAlias: (type: string, key: string) => string;
1
+ import { HttpMethod } from "../../lib/types";
3
2
  export declare const scanFile: <T extends string | undefined>(outputFile: string, inputFile: string, findCallBack: (fileContents: string) => T, typeCallBack: (type: NonNullable<T>, importAlias: string) => string) => {
4
3
  importName: string;
5
4
  importPath: string;
@@ -3,27 +3,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.scanRoute = exports.scanQuery = exports.scanFile = exports.createImportAlias = void 0;
6
+ exports.scanRoute = exports.scanQuery = exports.scanFile = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
- const cache_1 = require("./cache");
8
+ const alias_1 = require("./alias");
9
9
  const constants_1 = require("./constants");
10
10
  const path_utils_1 = require("./path-utils");
11
11
  const type_utils_1 = require("./type-utils");
12
- // 連番付与
13
- const createImportAlias = (type, key) => {
14
- if (!cache_1.cntCache[key]) {
15
- cache_1.cntCache[key] = 0;
16
- }
17
- return `${type}_${cache_1.cntCache[key]++}`;
18
- };
19
- exports.createImportAlias = createImportAlias;
20
12
  const scanFile = (outputFile, inputFile, findCallBack, typeCallBack) => {
21
13
  const fileContents = fs_1.default.readFileSync(inputFile, "utf8");
22
14
  const type = findCallBack(fileContents);
23
15
  if (!type)
24
16
  return;
25
17
  const relativeImportPath = (0, path_utils_1.createRelativeImportPath)(outputFile, inputFile);
26
- const importAlias = (0, exports.createImportAlias)(type, type);
18
+ const importAlias = (0, alias_1.createImportAlias)(relativeImportPath, type);
27
19
  return {
28
20
  importName: importAlias,
29
21
  importPath: relativeImportPath,
@@ -0,0 +1,2 @@
1
+ import type { END_POINT_FILE_NAMES } from "./constants";
2
+ export type EndPointFileNames = (typeof END_POINT_FILE_NAMES)[number];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1 @@
1
- export declare const debounce: <T extends (...args: any[]) => void>(func: T, delay: number) => (...args: Parameters<T>) => void;
1
+ export declare const debounceOnceRunningWithTrailing: <T extends (...args: any[]) => Promise<void> | void>(func: T, delay: number) => (...args: Parameters<T>) => void;
@@ -1,14 +1,43 @@
1
1
  "use strict";
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
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.debounce = void 0;
4
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- const debounce = (func, delay) => {
6
- let timer;
12
+ exports.debounceOnceRunningWithTrailing = void 0;
13
+ const debounceOnceRunningWithTrailing = (func, delay) => {
14
+ let timer = null;
15
+ let isRunning = false;
16
+ let pendingArgs = null;
17
+ const execute = (...args) => __awaiter(void 0, void 0, void 0, function* () {
18
+ isRunning = true;
19
+ try {
20
+ yield func(...args);
21
+ }
22
+ finally {
23
+ isRunning = false;
24
+ if (pendingArgs) {
25
+ const nextArgs = pendingArgs;
26
+ pendingArgs = null;
27
+ execute(...nextArgs);
28
+ }
29
+ }
30
+ });
7
31
  return (...args) => {
8
- clearTimeout(timer);
32
+ if (timer)
33
+ clearTimeout(timer);
9
34
  timer = setTimeout(() => {
10
- func(...args);
35
+ if (isRunning) {
36
+ pendingArgs = args !== null && args !== void 0 ? args : [];
37
+ return;
38
+ }
39
+ execute(...(args !== null && args !== void 0 ? args : []));
11
40
  }, delay);
12
41
  };
13
42
  };
14
- exports.debounce = debounce;
43
+ exports.debounceOnceRunningWithTrailing = debounceOnceRunningWithTrailing;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.generate = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
- const generate_path_structure_1 = require("./generate-path-structure");
8
+ const generate_path_structure_1 = require("./core/generate-path-structure");
9
9
  const generate = ({ baseDir, outputPath, paramsFileName, logger, }) => {
10
10
  logger.info("Generating...");
11
11
  const { pathStructure, paramsTypes } = (0, generate_path_structure_1.generatePages)(outputPath, baseDir);
@@ -1,5 +1,3 @@
1
- import type { END_POINT_FILE_NAMES } from "./constants";
2
- export type EndPointFileNames = (typeof END_POINT_FILE_NAMES)[number];
3
1
  export interface Logger {
4
2
  info: (msg: string) => void;
5
3
  success: (msg: string) => void;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.setupWatcher = void 0;
7
7
  const chokidar_1 = __importDefault(require("chokidar"));
8
- const cache_1 = require("./cache");
8
+ const cache_1 = require("./core/cache");
9
9
  const debounce_1 = require("./debounce");
10
10
  const setupWatcher = (baseDir, onGenerate, logger) => {
11
11
  logger.info(`Watching ${baseDir}...`);
@@ -14,12 +14,12 @@ const setupWatcher = (baseDir, onGenerate, logger) => {
14
14
  // Once the debounced function starts executing, no new watcher events will be processed until it completes.
15
15
  // This is due to JavaScript's single-threaded event loop: the current debounced function runs to completion,
16
16
  // and any new change events are queued until the execution finishes.
17
- const debouncedGenerate = (0, debounce_1.debounce)(() => {
17
+ const debouncedGenerate = (0, debounce_1.debounceOnceRunningWithTrailing)(() => {
18
18
  changedPaths.forEach((path) => {
19
19
  (0, cache_1.clearVisitedDirsCacheAbove)(path);
20
+ (0, cache_1.clearScanAppDirCacheAbove)(path);
20
21
  });
21
22
  changedPaths.clear();
22
- (0, cache_1.clearCntCache)();
23
23
  onGenerate();
24
24
  }, 300);
25
25
  const watcher = chokidar_1.default.watch(baseDir, {
@@ -28,6 +28,8 @@ const setupWatcher = (baseDir, onGenerate, logger) => {
28
28
  ignored: (path, stats) => !!(stats === null || stats === void 0 ? void 0 : stats.isFile()) && !isTargetFiles(path),
29
29
  });
30
30
  watcher.on("ready", () => {
31
+ // First execution
32
+ debouncedGenerate();
31
33
  watcher.on("all", (event, path) => {
32
34
  if (isTargetFiles(path)) {
33
35
  logger.info(`[${event}] ${path}`);
@@ -1,2 +1,6 @@
1
- import type { FuncParams, UrlOptions, ClientOptions } from "./types";
2
- export declare const httpMethod: (key: string, paths: string[], params: FuncParams, dynamicKeys: string[], defaultOptions: ClientOptions) => (url?: UrlOptions, options?: ClientOptions) => Promise<Response>;
1
+ import type { FuncParams, UrlOptions, ClientOptions, BodyOptions, HeadersOptions } from "./types";
2
+ export declare const httpMethod: (key: string, paths: string[], params: FuncParams, dynamicKeys: string[], defaultOptions: ClientOptions) => (methodParam?: {
3
+ url?: UrlOptions;
4
+ body?: BodyOptions;
5
+ requestHeaders?: HeadersOptions;
6
+ }, options?: ClientOptions) => Promise<Response>;
@@ -45,15 +45,32 @@ const normalizeHeaders = (headers) => {
45
45
  return result;
46
46
  };
47
47
  const httpMethod = (key, paths, params, dynamicKeys, defaultOptions) => {
48
- return (url, options) => __awaiter(void 0, void 0, void 0, function* () {
49
- const urlObj = (0, url_1.createUrl)([...paths], params, dynamicKeys)(url);
48
+ return (methodParam, options) => __awaiter(void 0, void 0, void 0, function* () {
49
+ var _a, _b, _c;
50
+ let methodParamBody = undefined;
51
+ let methodParamContentType = undefined;
52
+ if ((_a = methodParam === null || methodParam === void 0 ? void 0 : methodParam.body) === null || _a === void 0 ? void 0 : _a.json) {
53
+ methodParamContentType = "application/json";
54
+ methodParamBody = JSON.stringify(methodParam.body.json);
55
+ }
56
+ const methodParamHeaders = (_b = methodParam === null || methodParam === void 0 ? void 0 : methodParam.requestHeaders) === null || _b === void 0 ? void 0 : _b.headers;
57
+ const methodParamCookies = (_c = methodParam === null || methodParam === void 0 ? void 0 : methodParam.requestHeaders) === null || _c === void 0 ? void 0 : _c.cookies;
58
+ const urlObj = (0, url_1.createUrl)([...paths], params, dynamicKeys)(methodParam === null || methodParam === void 0 ? void 0 : methodParam.url);
50
59
  const method = key.replace(/^\$/, "").toUpperCase();
51
60
  const customFetch = (options === null || options === void 0 ? void 0 : options.fetch) || defaultOptions.fetch || fetch;
52
61
  const defaultInit = defaultOptions.init || {};
53
62
  const innerInit = (options === null || options === void 0 ? void 0 : options.init) || {};
54
63
  const defaultHeaders = normalizeHeaders(defaultInit.headers);
55
- const innerHeaders = normalizeHeaders(innerInit.headers);
64
+ const innerHeaders = normalizeHeaders(methodParamHeaders ? methodParamHeaders : innerInit.headers);
56
65
  const mergedHeaders = Object.assign(Object.assign({}, defaultHeaders), innerHeaders);
66
+ if (methodParamContentType) {
67
+ mergedHeaders["content-type"] = methodParamContentType;
68
+ }
69
+ if (methodParamCookies) {
70
+ mergedHeaders["cookie"] = Object.entries(methodParamCookies)
71
+ .map(([key, value]) => `${key}=${value}`)
72
+ .join("; ");
73
+ }
57
74
  const { headers: _defaultHeaders } = defaultInit, defaultInitWithoutHeaders = __rest(defaultInit, ["headers"]);
58
75
  const { headers: _innerHeaders } = innerInit, innerInitWithoutHeaders = __rest(innerInit, ["headers"]);
59
76
  const mergedInit = (0, utils_1.deepMerge)(defaultInitWithoutHeaders, innerInitWithoutHeaders);
@@ -61,6 +78,9 @@ const httpMethod = (key, paths, params, dynamicKeys, defaultOptions) => {
61
78
  if (Object.keys(mergedHeaders).length > 0) {
62
79
  mergedInit.headers = mergedHeaders;
63
80
  }
81
+ if (methodParamBody) {
82
+ mergedInit.body = methodParamBody;
83
+ }
64
84
  const response = yield customFetch(urlObj.path, mergedInit);
65
85
  return response;
66
86
  });
@@ -1,3 +1,8 @@
1
+ /*!
2
+ * Inspired by the design of Hono (https://github.com/honojs/hono)
3
+ * and pathpida (https://github.com/aspida/pathpida)
4
+ * particularly their routing structures and developer experience.
5
+ */
1
6
  import type { FuncParams, DynamicPathProxyAsFunction, ClientOptions, DynamicPathProxyAsProperty } from "./types";
2
7
  export declare const createRpcProxy: <T extends object>(options: ClientOptions, paths?: string[], params?: FuncParams, dynamicKeys?: string[]) => T;
3
8
  /**
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
- // Inspired by Hono (https://github.com/honojs/hono)
3
- // Some parts of this code are based on or adapted from the Hono project
2
+ /*!
3
+ * Inspired by the design of Hono (https://github.com/honojs/hono)
4
+ * and pathpida (https://github.com/aspida/pathpida)
5
+ * particularly their routing structures and developer experience.
6
+ */
4
7
  Object.defineProperty(exports, "__esModule", { value: true });
5
8
  exports.createRpcHelper = exports.createRpcClient = exports.createRpcProxy = void 0;
6
9
  const http_method_1 = require("./http-method");
@@ -1,5 +1,6 @@
1
1
  import type { OPTIONAL_CATCH_ALL_PREFIX, CATCH_ALL_PREFIX, DYNAMIC_PREFIX, HTTP_METHOD_FUNC_KEYS } from "../../lib/constants";
2
- import type { TypedNextResponse, HttpStatusCode, ContentType } from "../server/types";
2
+ import type { RouteHandlerResponse, RouteResponse, ValidationSchema } from "../server/route-types";
3
+ import type { TypedNextResponse, HttpStatusCode, ContentType, ValidationInputFor } from "../server/types";
3
4
  import type { NextResponse } from "next/server";
4
5
  /**
5
6
  * Represents HTTP request headers with optional fields.
@@ -14,7 +15,7 @@ type HttpRequestHeaders = Partial<{
14
15
  "Cache-Control": string;
15
16
  Connection: string;
16
17
  "Content-Length": string;
17
- "Content-Type": string;
18
+ "Content-Type": ContentType;
18
19
  Cookie: string;
19
20
  Date: string;
20
21
  Expect: string;
@@ -52,12 +53,12 @@ type HttpRequestHeaders = Partial<{
52
53
  /**
53
54
  * Extension of the standard `RequestInit` interface with strongly typed headers.
54
55
  */
55
- export interface TypedRequestInit extends RequestInit {
56
- headers?: HttpRequestHeaders | HeadersInit;
56
+ export interface TypedRequestInit<TWithoutHeaders extends "Content-Type" | "Cookie" = never> extends RequestInit {
57
+ headers?: (Omit<HttpRequestHeaders, TWithoutHeaders> & Record<string, string>) | HeadersInit;
57
58
  }
58
- export type ClientOptions = {
59
+ export type ClientOptions<TWithoutHeaders extends "Content-Type" | "Cookie" = never, TWithoutInit extends "body" | "headers" = never> = {
59
60
  fetch?: typeof fetch;
60
- init?: TypedRequestInit;
61
+ init?: Omit<TypedRequestInit<TWithoutHeaders>, TWithoutInit>;
61
62
  };
62
63
  declare const __proxy: unique symbol;
63
64
  export type Endpoint = {
@@ -95,18 +96,46 @@ export type UrlResult<T = unknown> = {
95
96
  relativePath: string;
96
97
  params: Params<T>;
97
98
  };
98
- type UrlArg<T> = T extends IsQuery ? [url: UrlOptions<T>] : [url?: UrlOptions<T>];
99
- type HttpMethodsArg<T> = [...UrlArg<T>, option?: ClientOptions];
99
+ type IsNever<T> = [T] extends [never] ? true : false;
100
+ type AllOptional<T> = Partial<T> extends T ? true : false;
101
+ type UrlArgs<T> = T extends IsQuery ? [url: UrlOptions<T>] : [url?: UrlOptions<T>];
102
+ type UrlArgsObj<T> = T extends IsQuery ? {
103
+ url: UrlOptions<T>;
104
+ } : {
105
+ url?: UrlOptions<T>;
106
+ };
107
+ export type BodyOptions<TJson = unknown> = {
108
+ json: TJson;
109
+ };
110
+ type BodyArgsObj<TJson> = IsNever<TJson> extends true ? unknown : {
111
+ body: BodyOptions<TJson>;
112
+ };
113
+ export type HeadersOptions<THeaders = unknown, TCookies = unknown> = {
114
+ headers: THeaders;
115
+ cookies: TCookies;
116
+ };
117
+ type HeadersArgsObj<THeaders = unknown, TCookies = unknown> = IsNever<THeaders> extends true ? IsNever<TCookies> extends true ? unknown : {
118
+ requestHeaders: Pick<HeadersOptions<THeaders, TCookies>, "cookies">;
119
+ } : IsNever<TCookies> extends true ? {
120
+ requestHeaders: Pick<HeadersOptions<THeaders, TCookies>, "headers">;
121
+ } : {
122
+ requestHeaders: HeadersOptions<THeaders, TCookies>;
123
+ };
124
+ type HttpMethodsArgs<T, TValidationSchema extends ValidationSchema, TJson = ValidationInputFor<"json", TValidationSchema>, THeaders = ValidationInputFor<"headers", TValidationSchema>, TCookies = ValidationInputFor<"cookies", TValidationSchema>, TBaseArgs = UrlArgsObj<T> & BodyArgsObj<TJson> & HeadersArgsObj<THeaders, TCookies>> = [
125
+ ...(AllOptional<TBaseArgs> extends true ? [methodParam?: TBaseArgs] : [methodParam: TBaseArgs]),
126
+ option?: ClientOptions<(IsNever<TJson> extends true ? never : "Content-Type") | (IsNever<TCookies> extends true ? never : "Cookie"), (IsNever<TJson> extends true ? never : "body") | (IsNever<THeaders> extends true ? never : "headers")>
127
+ ];
100
128
  type InferHttpMethods<T extends IsHttpMethod> = {
101
- [K in keyof T as K extends HttpMethodFuncKey ? K : never]: (...args: HttpMethodsArg<T>) => Promise<InferTypedNextResponseType<T[K]>>;
129
+ [K in keyof T as K extends HttpMethodFuncKey ? K : never]: (...args: HttpMethodsArgs<T, InferValidationSchema<T[K]>>) => Promise<InferTypedNextResponseType<T[K]>>;
102
130
  };
131
+ type InferValidationSchema<T> = T extends (...args: any[]) => RouteHandlerResponse<RouteResponse, infer TValidationSchema> ? TValidationSchema : ValidationSchema;
103
132
  type InferNextResponseType<T> = T extends (...args: any[]) => Promise<NextResponse<infer U>> ? U : never;
104
133
  type InferTypedNextResponseType<T> = T extends (...args: any[]) => Promise<TypedNextResponse> ? Awaited<ReturnType<T>> : TypedNextResponse<InferNextResponseType<T>, HttpStatusCode, ContentType>;
105
134
  type PathProxyAsProperty<T> = {
106
135
  $match: (path: string) => Params<T> | null;
107
136
  };
108
137
  type PathProxyAsFunction<T> = {
109
- $url: (...args: UrlArg<T>) => UrlResult<T>;
138
+ $url: (...args: UrlArgs<T>) => UrlResult<T>;
110
139
  } & (T extends IsHttpMethod ? InferHttpMethods<T> : unknown);
111
140
  type ParamFunction<T, TParamArgs extends unknown[]> = (...args: [...TParamArgs]) => DynamicPathProxyAsFunction<T>;
112
141
  type NonEmptyArray<T> = [T, ...T[]];
@@ -1,2 +1,3 @@
1
- import type { Handler, Params, Query, RouteResponse, ValidationSchema } from "./types";
1
+ import type { ValidationSchema, RouteResponse, Handler } from "./route-types";
2
+ import type { Params, Query } from "./types";
2
3
  export declare const createHandler: <TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>() => <TRouteResponse extends RouteResponse>(handler: Handler<TParams, TQuery, TValidationSchema, TRouteResponse>) => Handler<TParams, TQuery, TValidationSchema, TRouteResponse>;
@@ -1,4 +1,5 @@
1
- import type { RouteContext, Query, ValidationSchema, Params } from "./types";
1
+ import type { ValidationSchema } from "./route-types";
2
+ import type { RouteContext, Query, Params } from "./types";
2
3
  import type { NextRequest } from "next/server";
3
4
  export declare const createRouteContext: <TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>(req: NextRequest, segmentData: {
4
5
  params: Promise<TParams>;
@@ -1,6 +1,4 @@
1
1
  "use strict";
2
- // Inspired by Hono (https://github.com/honojs/hono)
3
- // Some parts of this code are based on or adapted from the Hono project
4
2
  Object.defineProperty(exports, "__esModule", { value: true });
5
3
  exports.createRouteContext = void 0;
6
4
  const server_1 = require("next/server");
@@ -1,4 +1,9 @@
1
- import type { Query, Params, RouteBindings, MethodRouteDefinition, RequiredRouteResponse, ErrorHandler } from "./types";
1
+ /*!
2
+ * Inspired by Hono (https://github.com/honojs/hono),
3
+ * particularly its routing design and handler interface.
4
+ */
5
+ import type { RequiredRouteResponse, ErrorHandler, RouteBindings, MethodRouteDefinition } from "./route-types";
6
+ import type { Query, Params } from "./types";
2
7
  /**
3
8
  * A factory function that creates route handlers for various HTTP methods (GET, POST, etc.).
4
9
  *
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /*!
3
+ * Inspired by Hono (https://github.com/honojs/hono),
4
+ * particularly its routing design and handler interface.
5
+ */
2
6
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
7
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
8
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -0,0 +1,39 @@
1
+ /*!
2
+ * Portions of this code are based on the Hono project (https://github.com/honojs/hono),
3
+ * originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
4
+ * contributions from the Hono community.
5
+ * This code has been adapted and modified for this project.
6
+ * Original copyright belongs to Yusuke Wada and the Hono project contributors.
7
+ * Hono is licensed under the MIT License.
8
+ */
9
+ import type { TypedNextResponse, Query, RouteContext, Params } from "./types";
10
+ import type { HttpMethod } from "../../lib/types";
11
+ import type { NextRequest } from "next/server";
12
+ export type RouteResponse = TypedNextResponse | Promise<TypedNextResponse | void>;
13
+ export type RequiredRouteResponse = TypedNextResponse | Promise<TypedNextResponse>;
14
+ export interface RouteBindings {
15
+ params?: Params | Promise<Params>;
16
+ query?: Query;
17
+ }
18
+ export interface ValidationSchema {
19
+ input: {};
20
+ output: {};
21
+ }
22
+ export type Handler<TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema, TRouteResponse extends RouteResponse = RouteResponse> = (routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
23
+ export type ErrorHandler<TRouteResponse extends RequiredRouteResponse, TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema> = (error: unknown, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
24
+ export type RouteHandlerResponse<TRouteResponse extends RouteResponse, _TValidationSchema extends ValidationSchema> = Promise<Exclude<Awaited<TRouteResponse>, void | undefined>>;
25
+ export type RouteHandler<TParams extends RouteBindings["params"], TRouteResponse extends RouteResponse, TValidationSchema extends ValidationSchema> = (req: NextRequest, segmentData: {
26
+ params: Promise<TParams>;
27
+ }) => RouteHandlerResponse<TRouteResponse, TValidationSchema>;
28
+ type HttpMethodMapping<THttpMethod extends HttpMethod, TParams extends RouteBindings["params"], TRouteResponse extends RouteResponse, TValidationSchema extends ValidationSchema> = Record<THttpMethod, RouteHandler<TParams, TRouteResponse, TValidationSchema>>;
29
+ export interface MethodRouteDefinition<THttpMethod extends HttpMethod, TBindings extends RouteBindings, TOnErrorResponse extends RequiredRouteResponse, TParams extends TBindings["params"] = TBindings extends {
30
+ params: infer TValue;
31
+ } ? Awaited<TValue> : Params, TQuery extends TBindings["query"] = TBindings extends {
32
+ query: infer TValue;
33
+ } ? TValue : Query> {
34
+ <TV1 extends ValidationSchema = ValidationSchema, TR1 extends RequiredRouteResponse = RequiredRouteResponse>(handler: Handler<TParams, TQuery, TV1, TR1>): HttpMethodMapping<THttpMethod, TParams, TR1 | TOnErrorResponse, TV1>;
35
+ <TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TR1 extends RouteResponse = RouteResponse, TR2 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TOnErrorResponse, TV2>;
36
+ <TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TOnErrorResponse, TV3>;
37
+ <TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>, handler4: Handler<TParams, TQuery, TV4, TR4>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TOnErrorResponse, TV4>;
38
+ }
39
+ export {};
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /*!
3
+ * Portions of this code are based on the Hono project (https://github.com/honojs/hono),
4
+ * originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
5
+ * contributions from the Hono community.
6
+ * This code has been adapted and modified for this project.
7
+ * Original copyright belongs to Yusuke Wada and the Hono project contributors.
8
+ * Hono is licensed under the MIT License.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,4 @@
1
- import { HttpMethod } from "../../lib/types";
1
+ import type { ValidationSchema } from "./route-types";
2
2
  import type { NextResponse, NextRequest } from "next/server";
3
3
  type KnownContentType = "application/json" | "text/html" | "text/plain" | "application/javascript" | "text/css" | "image/png" | "image/jpeg" | "image/svg+xml" | "application/pdf" | "application/octet-stream" | "multipart/form-data" | "application/x-www-form-urlencoded";
4
4
  /**
@@ -217,34 +217,9 @@ export interface RouteContext<TParams = Params, TQuery = Query, TValidationSchem
217
217
  */
218
218
  redirect: <TStatus extends RedirectionHttpStatusCode = 302>(url: string, init?: TStatus | TypedResponseInit<TStatus, "">) => TypedNextResponse<undefined, TStatus, "">;
219
219
  }
220
- export type RouteResponse = TypedNextResponse | Promise<TypedNextResponse | void>;
221
- export type RequiredRouteResponse = TypedNextResponse | Promise<TypedNextResponse>;
222
- export interface RouteBindings {
223
- params?: Params | Promise<Params>;
224
- query?: Query;
225
- }
226
- export type ValidationTarget = "params" | "query";
227
- export interface ValidationSchema {
228
- input: {};
229
- output: {};
230
- }
220
+ export type ValidationTarget = "params" | "query" | "json" | "headers" | "cookies";
231
221
  type ValidationFor<TDirection extends keyof ValidationSchema, TTarget extends ValidationTarget, TSchema extends ValidationSchema> = TTarget extends keyof TSchema[TDirection] ? TSchema[TDirection][TTarget] : never;
232
- type ValidationInputFor<TTarget extends ValidationTarget, TSchema extends ValidationSchema> = ValidationFor<"input", TTarget, TSchema>;
222
+ export type ValidationInputFor<TTarget extends ValidationTarget, TSchema extends ValidationSchema> = ValidationFor<"input", TTarget, TSchema>;
233
223
  type ValidationOutputFor<TTarget extends ValidationTarget, TSchema extends ValidationSchema> = ValidationFor<"output", TTarget, TSchema>;
234
224
  export type ConditionalValidationInput<TTarget extends ValidationTarget, TExpected extends ValidationTarget, TSchema extends ValidationSchema, TFallback> = TTarget extends TExpected ? ValidationInputFor<TTarget, TSchema> : TFallback;
235
- export type Handler<TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema, TRouteResponse extends RouteResponse = RouteResponse> = (routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
236
- export type ErrorHandler<TRouteResponse extends RequiredRouteResponse, TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema> = (error: unknown, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
237
- type RouteHandler<TParams extends RouteBindings["params"], TRouteResponse extends RouteResponse> = (req: NextRequest, segmentData: {
238
- params: Promise<TParams>;
239
- }) => Promise<Exclude<Awaited<TRouteResponse>, void | undefined>>;
240
- type HttpMethodMapping<THttpMethod extends HttpMethod, TParams extends RouteBindings["params"], TRouteResponse extends RouteResponse> = Record<THttpMethod, RouteHandler<TParams, TRouteResponse>>;
241
- export interface MethodRouteDefinition<THttpMethod extends HttpMethod, TBindings extends RouteBindings, TOnErrorResponse extends RequiredRouteResponse, TParams extends TBindings["params"] = TBindings extends {
242
- params: infer TValue;
243
- } ? Awaited<TValue> : Params, TQuery extends TBindings["query"] = TBindings extends {
244
- query: infer TValue;
245
- } ? TValue : Query> {
246
- <TV1 extends ValidationSchema = ValidationSchema, TR1 extends RequiredRouteResponse = RequiredRouteResponse>(handler: Handler<TParams, TQuery, TV1, TR1>): HttpMethodMapping<THttpMethod, TParams, TR1 | TOnErrorResponse>;
247
- <TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TR1 extends RouteResponse = RouteResponse, TR2 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TOnErrorResponse>;
248
- <TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TOnErrorResponse>;
249
- }
250
225
  export {};
@@ -1,4 +1,2 @@
1
1
  "use strict";
2
- // Inspired by Hono (https://github.com/honojs/hono)
3
- // Some parts of this code are based on or adapted from the Hono project
4
2
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export declare const getHeadersObject: () => Promise<Record<string, string>>;
2
+ export declare const getCookiesObject: () => Promise<Record<string, string>>;
@@ -0,0 +1,31 @@
1
+ "use strict";
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
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getCookiesObject = exports.getHeadersObject = void 0;
13
+ const headers_1 = require("next/headers");
14
+ const getHeadersObject = () => __awaiter(void 0, void 0, void 0, function* () {
15
+ const headersList = yield (0, headers_1.headers)();
16
+ const headersObj = {};
17
+ for (const [key, value] of headersList.entries()) {
18
+ headersObj[key] = value;
19
+ }
20
+ return headersObj;
21
+ });
22
+ exports.getHeadersObject = getHeadersObject;
23
+ const getCookiesObject = () => __awaiter(void 0, void 0, void 0, function* () {
24
+ const cookiesList = yield (0, headers_1.cookies)();
25
+ const cookiesObj = {};
26
+ for (const cookie of cookiesList.getAll()) {
27
+ cookiesObj[cookie.name] = cookie.value;
28
+ }
29
+ return cookiesObj;
30
+ });
31
+ exports.getCookiesObject = getCookiesObject;
@@ -1,6 +1,15 @@
1
- import type { RouteContext, Params, Query, TypedNextResponse, ValidationSchema, ConditionalValidationInput, ValidationTarget } from "../../types";
1
+ /*!
2
+ * Portions of this code are based on the Hono project (https://github.com/honojs/middleware/tree/main/packages/zod-validator),
3
+ * originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
4
+ * contributions from the Hono community.
5
+ * This code has been adapted and modified for this project.
6
+ * Original copyright belongs to Yusuke Wada and the Hono project contributors.
7
+ * Hono is licensed under the MIT License.
8
+ */
9
+ import type { ValidationSchema } from "../../route-types";
10
+ import type { RouteContext, Params, Query, TypedNextResponse, ConditionalValidationInput, ValidationTarget } from "../../types";
2
11
  import type { z, ZodSchema } from "zod";
3
12
  export declare const zodValidator: <TValidationTarget extends ValidationTarget, TSchema extends ZodSchema<any>, TParams extends ConditionalValidationInput<TValidationTarget, "params", TValidationSchema, Params> & Params, TQuery extends ConditionalValidationInput<TValidationTarget, "query", TValidationSchema, Query> & Query, TInput = z.input<TSchema>, TOutput = z.output<TSchema>, TValidationSchema extends ValidationSchema = {
4
13
  input: Record<TValidationTarget, TInput>;
5
14
  output: Record<TValidationTarget, TOutput>;
6
- }, THookReturn extends TypedNextResponse | void = TypedNextResponse<z.SafeParseError<TInput>, 400, "application/json"> | void>(target: TValidationTarget, schema: TSchema, hook?: (result: z.SafeParseReturnType<TInput, TOutput>, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => THookReturn) => import("../../types").Handler<TParams, TQuery, TValidationSchema, Promise<Exclude<THookReturn, void> | undefined>>;
15
+ }, THookReturn extends TypedNextResponse | void = TypedNextResponse<z.SafeParseError<TInput>, 400, "application/json"> | void>(target: TValidationTarget, schema: TSchema, hook?: (result: z.SafeParseReturnType<TInput, TOutput>, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => THookReturn) => import("../../route-types").Handler<TParams, TQuery, TValidationSchema, Promise<Exclude<THookReturn, void> | undefined>>;
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
- // Inspired by Hono (https://github.com/honojs/middleware/tree/main/packages/zod-validator)
3
- // Some parts of this code are based on or adapted from the Hono project
2
+ /*!
3
+ * Portions of this code are based on the Hono project (https://github.com/honojs/middleware/tree/main/packages/zod-validator),
4
+ * originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
5
+ * contributions from the Hono community.
6
+ * This code has been adapted and modified for this project.
7
+ * Original copyright belongs to Yusuke Wada and the Hono project contributors.
8
+ * Hono is licensed under the MIT License.
9
+ */
4
10
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
11
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
12
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -13,6 +19,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
13
19
  Object.defineProperty(exports, "__esModule", { value: true });
14
20
  exports.zodValidator = void 0;
15
21
  const create_handler_1 = require("../../create-handler");
22
+ const validator_utils_1 = require("../validator-utils");
16
23
  const zodValidator = (target, schema, hook) => {
17
24
  const resolvedHook = hook !== null && hook !== void 0 ? hook : ((result, rc) => {
18
25
  if (!result.success) {
@@ -27,6 +34,15 @@ const zodValidator = (target, schema, hook) => {
27
34
  if (target === "query") {
28
35
  return rc.req.query();
29
36
  }
37
+ if (target === "json") {
38
+ return rc.req.json();
39
+ }
40
+ if (target === "headers") {
41
+ return yield (0, validator_utils_1.getHeadersObject)();
42
+ }
43
+ if (target === "cookies") {
44
+ return yield (0, validator_utils_1.getCookiesObject)();
45
+ }
30
46
  }))();
31
47
  const result = yield schema.safeParseAsync(value);
32
48
  const hookResult = resolvedHook(result, rc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpc4next",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",
@@ -1,4 +0,0 @@
1
- export declare const visitedDirsCache: Map<string, boolean>;
2
- export declare const cntCache: Record<string, number>;
3
- export declare const clearCntCache: () => void;
4
- export declare const clearVisitedDirsCacheAbove: (targetPath: string) => void;
File without changes
File without changes
File without changes