rpc4next 0.1.5 → 0.1.7
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 +3 -11
- package/dist/cli/cli-handler.js +8 -6
- package/dist/cli/core/alias.d.ts +1 -0
- package/dist/cli/core/alias.js +16 -0
- package/dist/cli/core/cache.d.ts +12 -2
- package/dist/cli/core/cache.js +16 -10
- package/dist/cli/core/route-scanner.d.ts +4 -0
- package/dist/cli/core/route-scanner.js +13 -5
- package/dist/cli/core/scan-utils.d.ts +0 -1
- package/dist/cli/core/scan-utils.js +3 -11
- package/dist/cli/debounce.d.ts +1 -1
- package/dist/cli/debounce.js +36 -7
- package/dist/cli/watcher.js +4 -2
- package/dist/helper/client/http-method.d.ts +6 -2
- package/dist/helper/client/http-method.js +23 -3
- package/dist/helper/client/rpc.d.ts +5 -0
- package/dist/helper/client/rpc.js +5 -2
- package/dist/helper/client/types.d.ts +39 -10
- package/dist/helper/server/create-handler.d.ts +2 -1
- package/dist/helper/server/create-route-context.d.ts +2 -1
- package/dist/helper/server/create-route-context.js +0 -2
- package/dist/helper/server/route-handler-factory.d.ts +6 -1
- package/dist/helper/server/route-handler-factory.js +4 -0
- package/dist/helper/server/route-types.d.ts +39 -0
- package/dist/helper/server/route-types.js +10 -0
- package/dist/helper/server/types.d.ts +3 -28
- package/dist/helper/server/types.js +0 -2
- package/dist/helper/server/validators/validator-utils.d.ts +2 -0
- package/dist/helper/server/validators/validator-utils.js +31 -0
- package/dist/helper/server/validators/zod/zod-validator.d.ts +11 -2
- package/dist/helper/server/validators/zod/zod-validator.js +18 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,15 +8,12 @@ Inspired by Hono RPC and Pathpida, **rpc4next** automatically generates a type-s
|
|
|
8
8
|
|
|
9
9
|
## ✨ Features
|
|
10
10
|
|
|
11
|
-
- ✅ 既存の `app/**/route.ts` および `app/**/page.tsx` を活用するため、新たなハンドラファイルの作成は不要
|
|
12
11
|
- ✅ ルート、パラメータ、クエリパラメータ、 リクエストボディ、レスポンスの型安全なクライアント生成
|
|
12
|
+
- ✅ 既存の `app/**/route.ts` および `app/**/page.tsx` を活用するため、新たなハンドラファイルの作成は不要
|
|
13
13
|
- ✅ 最小限のセットアップで、カスタムサーバー不要
|
|
14
14
|
- ✅ 動的ルート(`[id]`、`[...slug]` など)に対応
|
|
15
15
|
- ✅ CLI による自動クライアント用型定義生成
|
|
16
16
|
|
|
17
|
-
> **注意**
|
|
18
|
-
> RPCとしてresponseの戻り値の推論が機能するのは、対象となる `route.ts` の HTTPメソッドハンドラ内で`NextResponse.json()` をしている物のみになります。
|
|
19
|
-
|
|
20
17
|
---
|
|
21
18
|
|
|
22
19
|
## 🚀 Getting Started
|
|
@@ -54,7 +51,7 @@ export async function GET(
|
|
|
54
51
|
|
|
55
52
|
🚩 Query or OptionalQuery 型を export することで、searchParams の型も自動的にクライアントに反映されます。
|
|
56
53
|
|
|
57
|
-
- **RPCとしてresponseの戻り値の推論が機能するのは、対象となる `route.ts` の HTTPメソッドハンドラ内で`NextResponse.json()`
|
|
54
|
+
- **RPCとしてresponseの戻り値の推論が機能するのは、対象となる `route.ts` の HTTPメソッドハンドラ内で`NextResponse.json()` をしている関数のみになります**
|
|
58
55
|
|
|
59
56
|
---
|
|
60
57
|
|
|
@@ -85,8 +82,6 @@ npx rpc4next <baseDir> <outputPath>
|
|
|
85
82
|
npx rpc4next <baseDir> <outputPath> --generate-params-types <paramsFileName>
|
|
86
83
|
```
|
|
87
84
|
|
|
88
|
-
※ このオプションを指定する際は、必ずファイル名をセットしてください。ファイル名が指定されない場合、エラーが発生します。
|
|
89
|
-
|
|
90
85
|
---
|
|
91
86
|
|
|
92
87
|
### 4. Create Your RPC Client
|
|
@@ -152,10 +147,7 @@ const createRouteHandler = routeHandlerFactory((err, rc) =>
|
|
|
152
147
|
rc.text("error", { status: 400 })
|
|
153
148
|
);
|
|
154
149
|
|
|
155
|
-
const { POST } = createRouteHandler().post(
|
|
156
|
-
async (rc) => rc.json("json response"),
|
|
157
|
-
async (rc) => rc.text("plain text")
|
|
158
|
-
);
|
|
150
|
+
const { POST } = createRouteHandler().post(async (rc) => rc.text("plain text"));
|
|
159
151
|
```
|
|
160
152
|
|
|
161
153
|
これだけで、POST リクエストの返り値が、responseの内容(json,textなど)、status,contenttypeが型付けされるようになります。
|
package/dist/cli/cli-handler.js
CHANGED
|
@@ -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;
|
package/dist/cli/core/cache.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export declare const visitedDirsCache: Map<string, boolean>;
|
|
2
|
-
export declare const
|
|
3
|
-
|
|
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
|
+
}>;
|
|
4
13
|
export declare const clearVisitedDirsCacheAbove: (targetPath: string) => void;
|
|
14
|
+
export declare const clearScanAppDirCacheAbove: (targetPath: string) => void;
|
package/dist/cli/core/cache.js
CHANGED
|
@@ -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.
|
|
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.
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
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
|
};
|
|
@@ -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
|
|
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,
|
|
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
|
-
|
|
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
1
|
import { HttpMethod } from "../../lib/types";
|
|
2
|
-
export declare const createImportAlias: (type: string, key: string) => string;
|
|
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 =
|
|
6
|
+
exports.scanRoute = exports.scanQuery = exports.scanFile = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const
|
|
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,
|
|
18
|
+
const importAlias = (0, alias_1.createImportAlias)(relativeImportPath, type);
|
|
27
19
|
return {
|
|
28
20
|
importName: importAlias,
|
|
29
21
|
importPath: relativeImportPath,
|
package/dist/cli/debounce.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const debounceOnceRunningWithTrailing: <T extends (...args: any[]) => Promise<void> | void>(func: T, delay: number) => (...args: Parameters<T>) => void;
|
package/dist/cli/debounce.js
CHANGED
|
@@ -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.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let
|
|
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
|
-
|
|
32
|
+
if (timer)
|
|
33
|
+
clearTimeout(timer);
|
|
9
34
|
timer = setTimeout(() => {
|
|
10
|
-
|
|
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.
|
|
43
|
+
exports.debounceOnceRunningWithTrailing = debounceOnceRunningWithTrailing;
|
package/dist/cli/watcher.js
CHANGED
|
@@ -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.
|
|
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) => (
|
|
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 (
|
|
49
|
-
|
|
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
|
-
|
|
3
|
-
|
|
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 {
|
|
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":
|
|
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
|
|
99
|
-
type
|
|
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:
|
|
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:
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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 {};
|
|
@@ -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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
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.
|
|
3
|
+
"version": "0.1.7",
|
|
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",
|