@alphatique/hono-fetch 0.0.0-stage → 1.0.5
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/LICENSE +15 -0
- package/dist/index.d.mts +33 -0
- package/dist/index.mjs +107 -0
- package/package.json +36 -5
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alphatique
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Schema } from "hono";
|
|
2
|
+
import { HonoBase } from "hono/hono-base";
|
|
3
|
+
import { Endpoint, ExtractSchema } from "hono/types";
|
|
4
|
+
import "hono/utils/headers";
|
|
5
|
+
//#region src/config.d.ts
|
|
6
|
+
interface HonoFetchConfig {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
onError?: (err: unknown) => any;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/types.d.ts
|
|
12
|
+
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
|
13
|
+
type ExtractPath<S extends Schema, M extends Method> = { [P in keyof S]: P extends string ? InferEndpoint<S, M, P> extends Endpoint ? P : never : never; }[keyof S];
|
|
14
|
+
type InferEndpoint<S extends Schema, M extends Method, P extends keyof S> = S[P][`$${M}`];
|
|
15
|
+
type InferInput<S extends Schema, M extends Method, P extends keyof S> = InferEndpoint<S, M, P>['input'];
|
|
16
|
+
type InferOutput<S extends Schema, M extends Method, P extends keyof S> = InferEndpoint<S, M, P>['output'];
|
|
17
|
+
type InferError<C extends HonoFetchConfig> = C['onError'] extends ((err: unknown) => infer E) ? Awaited<E> : never;
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/index.d.ts
|
|
20
|
+
export declare class HonoFetch<S extends Schema, C extends HonoFetchConfig> {
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: C);
|
|
23
|
+
private fetch;
|
|
24
|
+
get<P extends ExtractPath<S, 'get'>>(path: P, args: InferInput<S, 'get', P>): Promise<InferOutput<S, "get", P> | InferError<C>>;
|
|
25
|
+
post<P extends ExtractPath<S, 'post'>>(path: P, args: InferInput<S, 'post', P>): Promise<InferError<C> | InferOutput<S, "post", P>>;
|
|
26
|
+
put<P extends ExtractPath<S, 'put'>>(path: P, args: InferInput<S, 'put', P>): Promise<InferError<C> | InferOutput<S, "put", P>>;
|
|
27
|
+
delete<P extends ExtractPath<S, 'delete'>>(path: P, args: InferInput<S, 'delete', P>): Promise<InferError<C> | InferOutput<S, "delete", P>>;
|
|
28
|
+
patch<P extends ExtractPath<S, 'patch'>>(path: P, args: InferInput<S, 'patch', P>): Promise<InferError<C> | InferOutput<S, "patch", P>>;
|
|
29
|
+
}
|
|
30
|
+
type InferSchema<T extends HonoBase<any, any, any>> = T extends HonoBase<any, any, any> ? ExtractSchema<T> : never;
|
|
31
|
+
export declare function honoFetch<T extends HonoBase<any, any, any>, C extends HonoFetchConfig = HonoFetchConfig>(config: C): HonoFetch<InferSchema<T>, C>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export {};
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region src/url.ts
|
|
2
|
+
const PARAM_SEGMENT = /\/:([^/{}?]+)(\{[^/]*\})?(\?)?(?=\/|$)/g;
|
|
3
|
+
/**
|
|
4
|
+
* baseUrl、hono の route(schema の key)、param、query から送信先の URL を作る。
|
|
5
|
+
* package の entry からは export しない。
|
|
6
|
+
*
|
|
7
|
+
* 不変条件:
|
|
8
|
+
* - 戻り値の origin は、常に new URL(baseUrl).origin と一致する。
|
|
9
|
+
* - 1 つの param は、encodeURIComponent した 1 つの path segment にだけ入る。
|
|
10
|
+
* - `:name` は名前が完全に一致した場合にだけ置換する。`:id` は `:idx` に一致しない。
|
|
11
|
+
* - `:name?` の値が undefined か空文字なら、その segment を取り除く。
|
|
12
|
+
* - query は、undefined の値と配列内の undefined を送らない。配列は同じ key で append する。
|
|
13
|
+
* - baseUrl の path は、これまでどおり使わない(route は baseUrl の origin からの絶対 path として解決する)。
|
|
14
|
+
*
|
|
15
|
+
* エラー(同期の TypeError):
|
|
16
|
+
* - baseUrl が URL として不正
|
|
17
|
+
* - 必須の param が無い、または空文字
|
|
18
|
+
* - param の値が "." または ".."(encode しても dot segment として正規化されるため)
|
|
19
|
+
* - param の値が対になっていない surrogate を含む(encodeURIComponent が URIError を投げるため)
|
|
20
|
+
* - 組み立てた URL の origin が baseUrl と異なる(多重の防御。上の規則が正しければ起きない)
|
|
21
|
+
*
|
|
22
|
+
* 対象外: route 中の `*` ワイルドカード
|
|
23
|
+
*/
|
|
24
|
+
function buildUrl(baseUrl, route, input = {}) {
|
|
25
|
+
const base = new URL(baseUrl);
|
|
26
|
+
const param = input.param ?? {};
|
|
27
|
+
const path = route.replace(PARAM_SEGMENT, (_match, name, _pattern, optional) => {
|
|
28
|
+
const value = Object.hasOwn(param, name) ? param[name] : void 0;
|
|
29
|
+
if (value === void 0 || value === "") {
|
|
30
|
+
if (optional) return "";
|
|
31
|
+
throw new TypeError(`hono-fetch: path param "${name}" is required for ${route}`);
|
|
32
|
+
}
|
|
33
|
+
if (value === "." || value === "..") throw new TypeError(`hono-fetch: path param "${name}" must not be "." or ".."`);
|
|
34
|
+
try {
|
|
35
|
+
return "/" + encodeURIComponent(value);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
throw new TypeError(`hono-fetch: path param "${name}" is not a well-formed string`, { cause: err });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const url = new URL(path === "" ? "/" : path, base);
|
|
41
|
+
for (const [k, v] of Object.entries(input.query ?? {})) {
|
|
42
|
+
if (v === void 0) continue;
|
|
43
|
+
if (Array.isArray(v)) {
|
|
44
|
+
for (const v2 of v) if (v2 !== void 0) url.searchParams.append(k, v2);
|
|
45
|
+
} else url.searchParams.set(k, v);
|
|
46
|
+
}
|
|
47
|
+
if (url.origin !== base.origin) throw new TypeError(`hono-fetch: built URL left the origin of baseUrl: ${url.href}`);
|
|
48
|
+
return url;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/index.ts
|
|
52
|
+
var HonoFetch = class {
|
|
53
|
+
config;
|
|
54
|
+
constructor(config) {
|
|
55
|
+
this.config = config;
|
|
56
|
+
}
|
|
57
|
+
async fetch(method, path, args) {
|
|
58
|
+
const url = buildUrl(this.config.baseUrl, path, args);
|
|
59
|
+
let contentType = null;
|
|
60
|
+
let body = null;
|
|
61
|
+
if (args.json) {
|
|
62
|
+
contentType = "application/json";
|
|
63
|
+
body = JSON.stringify(args.json);
|
|
64
|
+
}
|
|
65
|
+
if (args.form) {
|
|
66
|
+
const form = new FormData();
|
|
67
|
+
for (const [k, v] of Object.entries(args.form)) {
|
|
68
|
+
if (v === void 0) continue;
|
|
69
|
+
if (Array.isArray(v)) for (const v2 of v) form.append(k, v2);
|
|
70
|
+
else form.set(k, v);
|
|
71
|
+
}
|
|
72
|
+
body = form;
|
|
73
|
+
}
|
|
74
|
+
const headers = new Headers(args.header);
|
|
75
|
+
if (contentType) headers.set("Content-Type", contentType);
|
|
76
|
+
try {
|
|
77
|
+
return await (await fetch(url, {
|
|
78
|
+
method: method.toUpperCase(),
|
|
79
|
+
headers,
|
|
80
|
+
body
|
|
81
|
+
})).json();
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (this.config.onError) return this.config.onError(err);
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
get(path, args) {
|
|
88
|
+
return this.fetch("get", path, args);
|
|
89
|
+
}
|
|
90
|
+
post(path, args) {
|
|
91
|
+
return this.fetch("post", path, args);
|
|
92
|
+
}
|
|
93
|
+
put(path, args) {
|
|
94
|
+
return this.fetch("put", path, args);
|
|
95
|
+
}
|
|
96
|
+
delete(path, args) {
|
|
97
|
+
return this.fetch("delete", path, args);
|
|
98
|
+
}
|
|
99
|
+
patch(path, args) {
|
|
100
|
+
return this.fetch("patch", path, args);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
function honoFetch(config) {
|
|
104
|
+
return new HonoFetch(config);
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { HonoFetch, honoFetch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@alphatique/hono-fetch",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/alphatique/hono-fetch.git"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
16
|
+
"default": "./dist/index.mjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"prepare": "vp config --no-agent",
|
|
24
|
+
"build": "vp pack",
|
|
25
|
+
"test": "vp test"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"hono": "^4.12.10",
|
|
29
|
+
"typescript": "^5.9.3",
|
|
30
|
+
"vite": "catalog:",
|
|
31
|
+
"vite-plus": "catalog:"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"hono": "^4.12.10"
|
|
35
|
+
},
|
|
36
|
+
"packageManager": "pnpm@12.11.2"
|
|
37
|
+
}
|
package/README.md
DELETED