rpc4next 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +130 -0
  3. package/dist/cli/cache.d.ts +4 -0
  4. package/dist/cli/cache.js +24 -0
  5. package/dist/cli/cli.d.ts +2 -0
  6. package/dist/cli/cli.js +81 -0
  7. package/dist/cli/constants.d.ts +12 -0
  8. package/dist/cli/constants.js +20 -0
  9. package/dist/cli/debounce.d.ts +1 -0
  10. package/dist/cli/debounce.js +14 -0
  11. package/dist/cli/generate-path-structure.d.ts +7 -0
  12. package/dist/cli/generate-path-structure.js +37 -0
  13. package/dist/cli/path-utils.d.ts +1 -0
  14. package/dist/cli/path-utils.js +19 -0
  15. package/dist/cli/route-scanner.d.ts +21 -0
  16. package/dist/cli/route-scanner.js +167 -0
  17. package/dist/cli/scan-utils.d.ts +20 -0
  18. package/dist/cli/scan-utils.js +52 -0
  19. package/dist/cli/type-utils.d.ts +6 -0
  20. package/dist/cli/type-utils.js +26 -0
  21. package/dist/cli/types.d.ts +2 -0
  22. package/dist/cli/types.js +2 -0
  23. package/dist/helper/client/http-method.d.ts +2 -0
  24. package/dist/helper/client/http-method.js +68 -0
  25. package/dist/helper/client/index.d.ts +2 -0
  26. package/dist/helper/client/index.js +6 -0
  27. package/dist/helper/client/match.d.ts +1 -0
  28. package/dist/helper/client/match.js +33 -0
  29. package/dist/helper/client/rpc.d.ts +55 -0
  30. package/dist/helper/client/rpc.js +100 -0
  31. package/dist/helper/client/types.d.ts +119 -0
  32. package/dist/helper/client/types.js +2 -0
  33. package/dist/helper/client/url.d.ts +8 -0
  34. package/dist/helper/client/url.js +57 -0
  35. package/dist/helper/client/utils.d.ts +5 -0
  36. package/dist/helper/client/utils.js +31 -0
  37. package/dist/helper/server/create-handler.d.ts +2 -0
  38. package/dist/helper/server/create-handler.js +10 -0
  39. package/dist/helper/server/create-route-context.d.ts +5 -0
  40. package/dist/helper/server/create-route-context.js +27 -0
  41. package/dist/helper/server/index.d.ts +2 -0
  42. package/dist/helper/server/index.js +5 -0
  43. package/dist/helper/server/route-handler-factory.d.ts +53 -0
  44. package/dist/helper/server/route-handler-factory.js +67 -0
  45. package/dist/helper/server/search-params-to-object.d.ts +1 -0
  46. package/dist/helper/server/search-params-to-object.js +18 -0
  47. package/dist/helper/server/types.d.ts +250 -0
  48. package/dist/helper/server/types.js +4 -0
  49. package/dist/helper/server/validators/zod/index.d.ts +1 -0
  50. package/dist/helper/server/validators/zod/index.js +5 -0
  51. package/dist/helper/server/validators/zod/zod-validator.d.ts +6 -0
  52. package/dist/helper/server/validators/zod/zod-validator.js +44 -0
  53. package/dist/index.d.ts +2 -0
  54. package/dist/index.js +18 -0
  55. package/dist/lib/constants.d.ts +5 -0
  56. package/dist/lib/constants.js +9 -0
  57. package/dist/lib/types.d.ts +1 -0
  58. package/dist/lib/types.js +2 -0
  59. package/package.json +81 -0
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createImport = exports.createObjectType = exports.createRecodeType = void 0;
4
+ const constants_1 = require("./constants");
5
+ const createRecodeType = (key, value) => {
6
+ if (!key || !value)
7
+ return "";
8
+ return `Record<${key}, ${value}>`;
9
+ };
10
+ exports.createRecodeType = createRecodeType;
11
+ const createObjectType = (fields) => {
12
+ if (fields.length === 0 || fields.some(({ name, type }) => !name || !type))
13
+ return "";
14
+ return `{ ${fields
15
+ .map(({ name, type }) => `"${name}": ${type}`)
16
+ .join(`${constants_1.TYPE_SEPARATOR} `)}${fields.length > 1 ? constants_1.TYPE_SEPARATOR : ""} }`;
17
+ };
18
+ exports.createObjectType = createObjectType;
19
+ const createImport = (type, path, importAlias) => {
20
+ if (!type || !path)
21
+ return "";
22
+ return importAlias
23
+ ? `import type { ${type} as ${importAlias} } from "${path}"${constants_1.STATEMENT_TERMINATOR}`
24
+ : `import type { ${type} } from "${path}"${constants_1.STATEMENT_TERMINATOR}`;
25
+ };
26
+ exports.createImport = createImport;
@@ -0,0 +1,2 @@
1
+ import type { END_POINT_FILE_NAMES } from "./constants";
2
+ export type EndPointFileNames = (typeof END_POINT_FILE_NAMES)[number];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import type { FuncParams, UrlOptions, ClientOptions } from "./types";
2
+ export declare const httpMethod: (key: string, paths: string[], params: FuncParams, dynamicKeys: string[], defaultOptions: ClientOptions) => (url?: UrlOptions, options?: ClientOptions) => Promise<Response>;
@@ -0,0 +1,68 @@
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
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.httpMethod = void 0;
24
+ const url_1 = require("./url");
25
+ const utils_1 = require("./utils");
26
+ const normalizeHeaders = (headers) => {
27
+ const result = {};
28
+ if (!headers)
29
+ return result;
30
+ if (headers instanceof Headers) {
31
+ headers.forEach((value, key) => {
32
+ result[key.toLowerCase()] = value;
33
+ });
34
+ return result;
35
+ }
36
+ if (Array.isArray(headers)) {
37
+ headers.forEach(([key, value]) => {
38
+ result[key.toLowerCase()] = value;
39
+ });
40
+ return result;
41
+ }
42
+ Object.entries(headers).forEach(([key, value]) => {
43
+ result[key.toLowerCase()] = value;
44
+ });
45
+ return result;
46
+ };
47
+ const httpMethod = (key, paths, params, dynamicKeys, defaultOptions) => {
48
+ return (url, options) => __awaiter(void 0, void 0, void 0, function* () {
49
+ const urlObj = (0, url_1.createUrl)([...paths], params, dynamicKeys)(url);
50
+ const method = key.replace(/^\$/, "").toUpperCase();
51
+ const customFetch = (options === null || options === void 0 ? void 0 : options.fetch) || defaultOptions.fetch || fetch;
52
+ const defaultInit = defaultOptions.init || {};
53
+ const innerInit = (options === null || options === void 0 ? void 0 : options.init) || {};
54
+ const defaultHeaders = normalizeHeaders(defaultInit.headers);
55
+ const innerHeaders = normalizeHeaders(innerInit.headers);
56
+ const mergedHeaders = Object.assign(Object.assign({}, defaultHeaders), innerHeaders);
57
+ const { headers: _defaultHeaders } = defaultInit, defaultInitWithoutHeaders = __rest(defaultInit, ["headers"]);
58
+ const { headers: _innerHeaders } = innerInit, innerInitWithoutHeaders = __rest(innerInit, ["headers"]);
59
+ const mergedInit = (0, utils_1.deepMerge)(defaultInitWithoutHeaders, innerInitWithoutHeaders);
60
+ mergedInit.method = method;
61
+ if (Object.keys(mergedHeaders).length > 0) {
62
+ mergedInit.headers = mergedHeaders;
63
+ }
64
+ const response = yield customFetch(urlObj.path, mergedInit);
65
+ return response;
66
+ });
67
+ };
68
+ exports.httpMethod = httpMethod;
@@ -0,0 +1,2 @@
1
+ export { createRpcClient, createRpcHelper } from "./rpc";
2
+ export type { Endpoint, ParamsKey, QueryKey, OptionalQueryKey } from "./types";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRpcHelper = exports.createRpcClient = void 0;
4
+ var rpc_1 = require("./rpc");
5
+ Object.defineProperty(exports, "createRpcClient", { enumerable: true, get: function () { return rpc_1.createRpcClient; } });
6
+ Object.defineProperty(exports, "createRpcHelper", { enumerable: true, get: function () { return rpc_1.createRpcHelper; } });
@@ -0,0 +1 @@
1
+ export declare const matchPath: (paths: string[], dynamicKeys: string[]) => (path: string) => {} | null;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchPath = void 0;
4
+ const url_1 = require("./url");
5
+ const utils_1 = require("./utils");
6
+ const matchPath = (paths, dynamicKeys) => {
7
+ return (path) => {
8
+ const basePath = `/${paths.slice(1).join("/")}`;
9
+ const regexPattern = (0, url_1.replaceDynamicSegments)(basePath, {
10
+ optionalCatchAll: "(?:/(.*))?",
11
+ catchAll: "/([^/]+(?:/[^/]+)*)",
12
+ dynamic: "/([^/]+)",
13
+ });
14
+ // Append /? to match with or without a trailing slash.
15
+ const match = new RegExp(`^${regexPattern}/?$`).exec(path);
16
+ if (!match)
17
+ return null;
18
+ return dynamicKeys.reduce((acc, key, index) => {
19
+ const paramKey = key.replace(/^_+/, "");
20
+ const matchValue = match[index + 1];
21
+ const paramValue = (0, utils_1.isCatchAllOrOptional)(key)
22
+ ? matchValue === undefined || matchValue === ""
23
+ ? undefined
24
+ : matchValue
25
+ .split("/")
26
+ .filter((segment) => segment.length > 0)
27
+ .map((segment) => decodeURIComponent(segment))
28
+ : decodeURIComponent(matchValue);
29
+ return Object.assign(Object.assign({}, acc), { [paramKey]: paramValue });
30
+ }, {});
31
+ };
32
+ };
33
+ exports.matchPath = matchPath;
@@ -0,0 +1,55 @@
1
+ import type { FuncParams, DynamicPathProxyAsFunction, ClientOptions, DynamicPathProxyAsProperty } from "./types";
2
+ export declare const createRpcProxy: <T extends object>(options: ClientOptions, paths?: string[], params?: FuncParams, dynamicKeys?: string[]) => T;
3
+ /**
4
+ * Creates an RPC client proxy for making HTTP requests with a strongly typed API.
5
+ *
6
+ * @template T - The type defining the RPC endpoint structure.
7
+ * @param baseUrl - The base URL for the RPC client. This URL will be used as the root for all generated endpoint URLs.
8
+ * @param options - (Optional) Client options to customize the behavior of the RPC client. These options may include a custom fetch function and default request initialization options.
9
+ * @returns An object that enables you to dynamically build endpoint URLs and execute HTTP requests (such as GET, POST, DELETE, etc.) with full type support.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createRpcClient } from "./rpc";
14
+ * import type { PathStructure } from "./types";
15
+ *
16
+ * // Create an RPC client with a base URL
17
+ * const client = createRpcClient<PathStructure>("http://localhost:3000");
18
+ *
19
+ * // Generate a URL for a dynamic endpoint
20
+ * const urlResult = client.fuga._foo("test").$url();
21
+ * console.log(urlResult.path); // "http://localhost:3000/fuga/test"
22
+ * console.log(urlResult.relativePath); // "/fuga/test"
23
+ * console.log(urlResult.pathname); // "/fuga/[foo]"
24
+ * console.log(urlResult.params); // { foo: "test" }
25
+ *
26
+ * // Execute a GET request on an endpoint
27
+ * const response = await client.api.hoge._foo("test").$get();
28
+ * console.log(await response.json()); // Expected response: { method: "get" }
29
+ * ```
30
+ *
31
+ * The above example demonstrates how to generate URLs with dynamic segments and how to execute HTTP requests.
32
+ */
33
+ export declare const createRpcClient: <T extends object>(baseUrl: string, options?: ClientOptions) => DynamicPathProxyAsFunction<T>;
34
+ /**
35
+ * Creates an RPC helper proxy for dynamic path matching based on a given endpoint structure.
36
+ *
37
+ * @template T - The type defining the RPC endpoint structure.
38
+ *
39
+ * @returns An object that provides dynamic RPC helper methods for the defined endpoints.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // Create the RPC helper
44
+ * const rpcHelper = createRpcHelper<PathStructure>();
45
+ *
46
+ * // Use the $match method to extract dynamic parameters from a URL path
47
+ * const match = rpcHelper.fuga._foo.$match("/fuga/test");
48
+ * // Expected output: { foo: "test" }
49
+ *
50
+ * // If the path does not match, it returns null
51
+ * const noMatch = rpcHelper.fuga._foo.$match("/hoge/test");
52
+ * // Expected output: null
53
+ * ```
54
+ */
55
+ export declare const createRpcHelper: <T extends object>() => DynamicPathProxyAsProperty<T>;
@@ -0,0 +1,100 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.createRpcHelper = exports.createRpcClient = exports.createRpcProxy = void 0;
6
+ const http_method_1 = require("./http-method");
7
+ const match_1 = require("./match");
8
+ const url_1 = require("./url");
9
+ const utils_1 = require("./utils");
10
+ const createRpcProxy = (options, paths = [], params = {}, dynamicKeys = []) => {
11
+ const proxy = new Proxy((value) => {
12
+ var _a, _b;
13
+ if (value === undefined) {
14
+ return (0, exports.createRpcProxy)(options, [...paths], params, dynamicKeys);
15
+ }
16
+ const newKey = (_a = paths.at(-1)) !== null && _a !== void 0 ? _a : "";
17
+ if ((0, utils_1.isDynamic)(newKey)) {
18
+ // Treat as a dynamic parameter
19
+ return (0, exports.createRpcProxy)(options, [...paths], Object.assign(Object.assign({}, params), { [(_b = dynamicKeys.at(-1)) !== null && _b !== void 0 ? _b : ""]: value }), dynamicKeys);
20
+ }
21
+ return (0, exports.createRpcProxy)(options, [...paths], params, dynamicKeys);
22
+ }, {
23
+ get: (_, key) => {
24
+ if (key === "$url") {
25
+ return (0, url_1.createUrl)([...paths], params, dynamicKeys);
26
+ }
27
+ if (key === "$match") {
28
+ return (0, match_1.matchPath)([...paths], dynamicKeys);
29
+ }
30
+ if ((0, utils_1.isHttpMethod)(key)) {
31
+ return (0, http_method_1.httpMethod)(key, [...paths], params, dynamicKeys, Object.assign({}, options));
32
+ }
33
+ if ((0, utils_1.isDynamic)(key)) {
34
+ // Treat as a dynamic parameter
35
+ return (0, exports.createRpcProxy)(options, [...paths, key], params, [
36
+ ...dynamicKeys,
37
+ key,
38
+ ]);
39
+ }
40
+ return (0, exports.createRpcProxy)(options, [...paths, key], params, dynamicKeys);
41
+ },
42
+ });
43
+ return proxy;
44
+ };
45
+ exports.createRpcProxy = createRpcProxy;
46
+ /**
47
+ * Creates an RPC client proxy for making HTTP requests with a strongly typed API.
48
+ *
49
+ * @template T - The type defining the RPC endpoint structure.
50
+ * @param baseUrl - The base URL for the RPC client. This URL will be used as the root for all generated endpoint URLs.
51
+ * @param options - (Optional) Client options to customize the behavior of the RPC client. These options may include a custom fetch function and default request initialization options.
52
+ * @returns An object that enables you to dynamically build endpoint URLs and execute HTTP requests (such as GET, POST, DELETE, etc.) with full type support.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { createRpcClient } from "./rpc";
57
+ * import type { PathStructure } from "./types";
58
+ *
59
+ * // Create an RPC client with a base URL
60
+ * const client = createRpcClient<PathStructure>("http://localhost:3000");
61
+ *
62
+ * // Generate a URL for a dynamic endpoint
63
+ * const urlResult = client.fuga._foo("test").$url();
64
+ * console.log(urlResult.path); // "http://localhost:3000/fuga/test"
65
+ * console.log(urlResult.relativePath); // "/fuga/test"
66
+ * console.log(urlResult.pathname); // "/fuga/[foo]"
67
+ * console.log(urlResult.params); // { foo: "test" }
68
+ *
69
+ * // Execute a GET request on an endpoint
70
+ * const response = await client.api.hoge._foo("test").$get();
71
+ * console.log(await response.json()); // Expected response: { method: "get" }
72
+ * ```
73
+ *
74
+ * The above example demonstrates how to generate URLs with dynamic segments and how to execute HTTP requests.
75
+ */
76
+ const createRpcClient = (baseUrl, options = {}) => (0, exports.createRpcProxy)(options, [baseUrl]);
77
+ exports.createRpcClient = createRpcClient;
78
+ /**
79
+ * Creates an RPC helper proxy for dynamic path matching based on a given endpoint structure.
80
+ *
81
+ * @template T - The type defining the RPC endpoint structure.
82
+ *
83
+ * @returns An object that provides dynamic RPC helper methods for the defined endpoints.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * // Create the RPC helper
88
+ * const rpcHelper = createRpcHelper<PathStructure>();
89
+ *
90
+ * // Use the $match method to extract dynamic parameters from a URL path
91
+ * const match = rpcHelper.fuga._foo.$match("/fuga/test");
92
+ * // Expected output: { foo: "test" }
93
+ *
94
+ * // If the path does not match, it returns null
95
+ * const noMatch = rpcHelper.fuga._foo.$match("/hoge/test");
96
+ * // Expected output: null
97
+ * ```
98
+ */
99
+ const createRpcHelper = () => (0, exports.createRpcProxy)({}, ["/"]);
100
+ exports.createRpcHelper = createRpcHelper;
@@ -0,0 +1,119 @@
1
+ import type { OPTIONAL_CATCH_ALL_PREFIX, CATCH_ALL_PREFIX, DYNAMIC_PREFIX, HTTP_METHOD_FUNC_KEYS } from "../../lib/constants";
2
+ import type { TypedNextResponse, HttpStatusCode, ContentType } from "../server/types";
3
+ import type { NextResponse } from "next/server";
4
+ /**
5
+ * Represents HTTP request headers with optional fields.
6
+ * This type includes general request headers, CORS/security-related headers, and client-specific headers.
7
+ */
8
+ type HttpRequestHeaders = Partial<{
9
+ Accept: string;
10
+ "Accept-Charset": string;
11
+ "Accept-Encoding": string;
12
+ "Accept-Language": string;
13
+ Authorization: string;
14
+ "Cache-Control": string;
15
+ Connection: string;
16
+ "Content-Length": string;
17
+ "Content-Type": string;
18
+ Cookie: string;
19
+ Date: string;
20
+ Expect: string;
21
+ Forwarded: string;
22
+ From: string;
23
+ Host: string;
24
+ "If-Match": string;
25
+ "If-Modified-Since": string;
26
+ "If-None-Match": string;
27
+ "If-Range": string;
28
+ "If-Unmodified-Since": string;
29
+ "Max-Forwards": string;
30
+ Origin: string;
31
+ Pragma: string;
32
+ Range: string;
33
+ Referer: string;
34
+ TE: string;
35
+ Trailer: string;
36
+ "Transfer-Encoding": string;
37
+ Upgrade: string;
38
+ "User-Agent": string;
39
+ Via: string;
40
+ Warning: string;
41
+ "Access-Control-Request-Method": string;
42
+ "Access-Control-Request-Headers": string;
43
+ DNT: string;
44
+ "Sec-Fetch-Dest": string;
45
+ "Sec-Fetch-Mode": string;
46
+ "Sec-Fetch-Site": string;
47
+ "Sec-Fetch-User": string;
48
+ "Sec-CH-UA": string;
49
+ "Sec-CH-UA-Platform": string;
50
+ "Sec-CH-UA-Mobile": string;
51
+ }>;
52
+ /**
53
+ * Extension of the standard `RequestInit` interface with strongly typed headers.
54
+ */
55
+ export interface TypedRequestInit extends RequestInit {
56
+ headers?: HttpRequestHeaders | HeadersInit;
57
+ }
58
+ export type ClientOptions = {
59
+ fetch?: typeof fetch;
60
+ init?: TypedRequestInit;
61
+ };
62
+ declare const __proxy: unique symbol;
63
+ export type Endpoint = {
64
+ [__proxy]?: true;
65
+ };
66
+ export type ParamsKey = "__params";
67
+ type IsParams = Record<ParamsKey, unknown>;
68
+ export type QueryKey = "__query";
69
+ type IsQuery = Record<QueryKey, unknown>;
70
+ export type OptionalQueryKey = "__op_query";
71
+ type IsOptionalQuery = Record<OptionalQueryKey, unknown>;
72
+ export type HttpMethodFuncKey = (typeof HTTP_METHOD_FUNC_KEYS)[number];
73
+ type IsHttpMethod = {
74
+ [K in HttpMethodFuncKey]?: unknown;
75
+ };
76
+ type IsOptionalCatchAll = `${typeof OPTIONAL_CATCH_ALL_PREFIX}${string}`;
77
+ type IsCatchAll = `${typeof CATCH_ALL_PREFIX}${string}`;
78
+ type IsDynamic = `${typeof DYNAMIC_PREFIX}${string}`;
79
+ export type FuncParams<T = Record<string, string | number | string[] | undefined>> = T;
80
+ type QueryParams<T = Record<string, string | number>> = T;
81
+ type Params<T = unknown> = T extends IsParams ? T[ParamsKey] : Record<string, string>;
82
+ export type UrlOptions<T = unknown> = T extends IsQuery ? {
83
+ query: T[QueryKey];
84
+ hash?: string;
85
+ } : T extends IsOptionalQuery ? {
86
+ query?: T[OptionalQueryKey];
87
+ hash?: string;
88
+ } : {
89
+ query?: QueryParams;
90
+ hash?: string;
91
+ };
92
+ export type UrlResult<T = unknown> = {
93
+ pathname: string;
94
+ path: string;
95
+ relativePath: string;
96
+ params: Params<T>;
97
+ };
98
+ type UrlArg<T> = T extends IsQuery ? [url: UrlOptions<T>] : [url?: UrlOptions<T>];
99
+ type HttpMethodsArg<T> = [...UrlArg<T>, option?: ClientOptions];
100
+ type InferHttpMethods<T extends IsHttpMethod> = {
101
+ [K in keyof T as K extends HttpMethodFuncKey ? K : never]: (...args: HttpMethodsArg<T>) => Promise<InferTypedNextResponseType<T[K]>>;
102
+ };
103
+ type InferNextResponseType<T> = T extends (...args: any[]) => Promise<NextResponse<infer U>> ? U : never;
104
+ type InferTypedNextResponseType<T> = T extends (...args: any[]) => Promise<TypedNextResponse> ? Awaited<ReturnType<T>> : TypedNextResponse<InferNextResponseType<T>, HttpStatusCode, ContentType>;
105
+ type PathProxyAsProperty<T> = {
106
+ $match: (path: string) => Params<T> | null;
107
+ };
108
+ type PathProxyAsFunction<T> = {
109
+ $url: (...args: UrlArg<T>) => UrlResult<T>;
110
+ } & (T extends IsHttpMethod ? InferHttpMethods<T> : unknown);
111
+ type ParamFunction<T, TParamArgs extends unknown[]> = (...args: [...TParamArgs]) => DynamicPathProxyAsFunction<T>;
112
+ type NonEmptyArray<T> = [T, ...T[]];
113
+ export type DynamicPathProxyAsFunction<T> = Omit<(T extends Endpoint ? PathProxyAsFunction<T> : unknown) & {
114
+ [K in keyof T]: K extends IsOptionalCatchAll ? ParamFunction<T[K], [value?: string[]]> : K extends IsCatchAll ? ParamFunction<T[K], [value: NonEmptyArray<string>]> : K extends IsDynamic ? ParamFunction<T[K], [value: string | number]> : DynamicPathProxyAsFunction<T[K]>;
115
+ }, QueryKey | OptionalQueryKey | ParamsKey>;
116
+ export type DynamicPathProxyAsProperty<T> = Omit<(T extends Endpoint ? PathProxyAsProperty<T> : unknown) & {
117
+ [K in keyof T]: K extends unknown ? DynamicPathProxyAsProperty<T[K]> : DynamicPathProxyAsProperty<T[K]>;
118
+ }, QueryKey | OptionalQueryKey | ParamsKey>;
119
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import type { UrlOptions, UrlResult, FuncParams } from "./types";
2
+ export declare const buildUrlSuffix: (url?: UrlOptions) => string;
3
+ export declare const replaceDynamicSegments: (basePath: string, replacements: {
4
+ optionalCatchAll: string;
5
+ catchAll: string;
6
+ dynamic: string;
7
+ }) => string;
8
+ export declare const createUrl: (paths: string[], params: FuncParams, dynamicKeys: string[]) => (url?: UrlOptions) => UrlResult;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createUrl = exports.replaceDynamicSegments = exports.buildUrlSuffix = void 0;
4
+ const buildUrlSuffix = (url) => {
5
+ if (!url)
6
+ return "";
7
+ const query = url.query
8
+ ? "?" + new URLSearchParams(url.query).toString()
9
+ : "";
10
+ const hash = url.hash ? `#${url.hash}` : "";
11
+ return query + hash;
12
+ };
13
+ exports.buildUrlSuffix = buildUrlSuffix;
14
+ const replaceDynamicSegments = (basePath, replacements) => basePath
15
+ // optionalCatchAll
16
+ .replace(/\/_{5}(\w+)/g, replacements.optionalCatchAll)
17
+ // catchAll
18
+ .replace(/\/_{3}(\w+)/g, replacements.catchAll)
19
+ // dynamic
20
+ .replace(/\/_(\w+)/g, replacements.dynamic);
21
+ exports.replaceDynamicSegments = replaceDynamicSegments;
22
+ const createUrl = (paths, params, dynamicKeys) => {
23
+ const baseUrl = paths.shift();
24
+ const basePath = `/${paths.join("/")}`;
25
+ const dynamicPath = dynamicKeys.reduce((acc, key) => {
26
+ const param = params[key];
27
+ if (Array.isArray(param)) {
28
+ return acc.replace(`/${key}`, `/${param.map(encodeURIComponent).join("/")}`);
29
+ }
30
+ if (param === undefined) {
31
+ return acc.replace(`/${key}`, "");
32
+ }
33
+ return acc.replace(`/${key}`, `/${encodeURIComponent(param)}`);
34
+ }, basePath);
35
+ return (url) => {
36
+ const relativePath = `${dynamicPath}${(0, exports.buildUrlSuffix)(url)}`;
37
+ const pathname = (0, exports.replaceDynamicSegments)(basePath, {
38
+ optionalCatchAll: "/[[...$1]]",
39
+ catchAll: "/[...$1]",
40
+ dynamic: "/[$1]",
41
+ });
42
+ const cleanedParams = {};
43
+ for (const key in params) {
44
+ const cleanedKey = key.replace(/^_+/, "");
45
+ cleanedParams[cleanedKey] = params[key];
46
+ }
47
+ return {
48
+ pathname,
49
+ params: cleanedParams,
50
+ path: baseUrl
51
+ ? `${baseUrl.replace(/\/$/, "")}${relativePath}`
52
+ : relativePath,
53
+ relativePath,
54
+ };
55
+ };
56
+ };
57
+ exports.createUrl = createUrl;
@@ -0,0 +1,5 @@
1
+ import type { HttpMethodFuncKey } from "./types";
2
+ export declare const isDynamic: (key: string) => boolean;
3
+ export declare const isCatchAllOrOptional: (key: string) => boolean;
4
+ export declare const isHttpMethod: (value: string) => value is HttpMethodFuncKey;
5
+ export declare const deepMerge: <T extends object, U extends object>(target: T, source: U) => T;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepMerge = exports.isHttpMethod = exports.isCatchAllOrOptional = exports.isDynamic = void 0;
4
+ const constants_1 = require("../../lib/constants");
5
+ const isDynamic = (key) => key.startsWith(constants_1.DYNAMIC_PREFIX);
6
+ exports.isDynamic = isDynamic;
7
+ const isCatchAllOrOptional = (key) => key.startsWith(constants_1.CATCH_ALL_PREFIX) || key.startsWith(constants_1.OPTIONAL_CATCH_ALL_PREFIX);
8
+ exports.isCatchAllOrOptional = isCatchAllOrOptional;
9
+ const httpMethods = new Set(constants_1.HTTP_METHOD_FUNC_KEYS);
10
+ const isHttpMethod = (value) => httpMethods.has(value);
11
+ exports.isHttpMethod = isHttpMethod;
12
+ const isPlainObject = (value) => {
13
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14
+ };
15
+ const deepMerge = (target, source) => {
16
+ const result = Object.assign({}, target);
17
+ for (const key in source) {
18
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
19
+ const targetValue = target[key];
20
+ const sourceValue = source[key];
21
+ if (isPlainObject(targetValue) && isPlainObject(sourceValue)) {
22
+ result[key] = (0, exports.deepMerge)(targetValue, sourceValue);
23
+ }
24
+ else {
25
+ result[key] = sourceValue;
26
+ }
27
+ }
28
+ }
29
+ return result;
30
+ };
31
+ exports.deepMerge = deepMerge;
@@ -0,0 +1,2 @@
1
+ import type { Handler, Params, Query, RouteResponse, ValidationSchema } from "./types";
2
+ 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>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHandler = void 0;
4
+ // I want to use currying so that the return value can be inferred.
5
+ const createHandler = () => {
6
+ return (handler) => {
7
+ return handler;
8
+ };
9
+ };
10
+ exports.createHandler = createHandler;
@@ -0,0 +1,5 @@
1
+ import type { RouteContext, Query, ValidationSchema, Params } from "./types";
2
+ import type { NextRequest } from "next/server";
3
+ export declare const createRouteContext: <TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>(req: NextRequest, segmentData: {
4
+ params: Promise<TParams>;
5
+ }) => RouteContext<TParams, TQuery, TValidationSchema>;
@@ -0,0 +1,27 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.createRouteContext = void 0;
6
+ const server_1 = require("next/server");
7
+ const search_params_to_object_1 = require("./search-params-to-object");
8
+ const createRouteContext = (req, segmentData) => {
9
+ const validationResults = {};
10
+ return {
11
+ req: Object.assign(req, {
12
+ query: () => (0, search_params_to_object_1.searchParamsToObject)(req.nextUrl.searchParams),
13
+ params: () => segmentData.params,
14
+ valid: (target) => {
15
+ return validationResults[target];
16
+ },
17
+ addValidatedData: (target, value) => {
18
+ validationResults[target] = value;
19
+ },
20
+ }),
21
+ body: (data, init) => new server_1.NextResponse(data, init),
22
+ json: (data, init) => server_1.NextResponse.json(data, init),
23
+ text: (data, init) => new server_1.NextResponse(data, Object.assign(Object.assign({}, init), { headers: Object.assign({ "Content-Type": "text/plain" }, init === null || init === void 0 ? void 0 : init.headers) })),
24
+ redirect: (url, init) => server_1.NextResponse.redirect(url, init),
25
+ };
26
+ };
27
+ exports.createRouteContext = createRouteContext;
@@ -0,0 +1,2 @@
1
+ export { routeHandlerFactory } from "./route-handler-factory";
2
+ export type { ContentType, HttpStatusCode, TypedNextResponse } from "./types";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.routeHandlerFactory = void 0;
4
+ var route_handler_factory_1 = require("./route-handler-factory");
5
+ Object.defineProperty(exports, "routeHandlerFactory", { enumerable: true, get: function () { return route_handler_factory_1.routeHandlerFactory; } });