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.
- package/README.md +18 -6
- 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 +14 -0
- package/dist/cli/{cache.js → core/cache.js} +16 -10
- package/dist/cli/{route-scanner.d.ts → core/route-scanner.d.ts} +4 -0
- package/dist/cli/{route-scanner.js → core/route-scanner.js} +14 -6
- package/dist/cli/{scan-utils.d.ts → core/scan-utils.d.ts} +1 -2
- package/dist/cli/{scan-utils.js → core/scan-utils.js} +3 -11
- package/dist/cli/core/types.d.ts +2 -0
- package/dist/cli/core/types.js +2 -0
- package/dist/cli/debounce.d.ts +1 -1
- package/dist/cli/debounce.js +36 -7
- package/dist/cli/generator.js +1 -1
- package/dist/cli/types.d.ts +0 -2
- package/dist/cli/watcher.js +5 -3
- 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/dist/cli/cache.d.ts +0 -4
- /package/dist/cli/{constants.d.ts → core/constants.d.ts} +0 -0
- /package/dist/cli/{constants.js → core/constants.js} +0 -0
- /package/dist/cli/{generate-path-structure.d.ts → core/generate-path-structure.d.ts} +0 -0
- /package/dist/cli/{generate-path-structure.js → core/generate-path-structure.js} +0 -0
- /package/dist/cli/{path-utils.d.ts → core/path-utils.d.ts} +0 -0
- /package/dist/cli/{path-utils.js → core/path-utils.js} +0 -0
- /package/dist/cli/{type-utils.d.ts → core/type-utils.d.ts} +0 -0
- /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
|
-
|
|
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.
|
|
119
|
+
return <div>{json.q}</div>;
|
|
108
120
|
}
|
|
109
121
|
```
|
|
110
122
|
|
|
111
123
|
- エディタの補完機能により、利用可能なエンドポイントが自動的に表示されます。
|
|
112
|
-
- リクエストの構造(params,
|
|
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` も型推論可能
|
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;
|
|
@@ -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.
|
|
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
|
};
|
|
@@ -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("
|
|
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
|
|
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
|
-
import { HttpMethod } from "
|
|
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 =
|
|
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/generator.js
CHANGED
|
@@ -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);
|
package/dist/cli/types.d.ts
CHANGED
package/dist/cli/watcher.js
CHANGED
|
@@ -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.
|
|
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.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",
|
package/dist/cli/cache.d.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|