kayto_ts 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vladislav Yemelyanov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,299 @@
1
+ # kayto_ts
2
+
3
+ 🚀 Build robust API integrations faster with `kayto_ts`.
4
+
5
+ - 🔒 End-to-end type safety for `method + path + params + body + response`
6
+ - ⚡ Zero-boilerplate HTTP client generation from schema
7
+ - 🧩 Request/response hooks for auth, tracing, and custom logic
8
+ - ⏱️ Built-in timeout and cancellation support
9
+ - 🛡️ Predictable, unified error model for cleaner handling
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ bun add kayto_ts
15
+ # alternatives:
16
+ # npm i kayto_ts
17
+ # pnpm add kayto_ts
18
+ # yarn add kayto_ts
19
+ ```
20
+
21
+ During install, `kayto_ts` automatically downloads `kayto` binary into local package directory: `.kayto/bin`.
22
+ No global `kayto` install is required.
23
+
24
+ ## Using CLI
25
+
26
+ Generate TypeScript schema from OpenAPI in one command:
27
+
28
+ ```bash
29
+ bunx kayto --lang ts --input "https://example.com/openapi.json" --output "generated/schema.ts"
30
+ ```
31
+
32
+ Alternatives:
33
+
34
+ ```bash
35
+ npx kayto --help
36
+ pnpm exec kayto --help
37
+ yarn kayto --help
38
+ ```
39
+
40
+ ## Multiple Services
41
+
42
+ If you generate one schema file per microservice, keep clients centralized in one place.
43
+
44
+ ```ts
45
+ import { clientApi, type EndpointsMap } from "kayto_ts";
46
+ import type { Endpoints as AccountsEndpoints } from "./schemas/accounts";
47
+ import type { Endpoints as BillingEndpoints } from "./schemas/billing";
48
+ import type { Endpoints as NotificationsEndpoints } from "./schemas/notifications";
49
+
50
+ const SERVICE_URLS = {
51
+ accounts: "https://accounts.example.com",
52
+ billing: "https://billing.example.com",
53
+ notifications: "https://notifications.example.com",
54
+ } as const;
55
+
56
+ function createServiceClient<TEndpoints extends EndpointsMap>(baseUrl: string) {
57
+ return clientApi<TEndpoints>({
58
+ baseUrl,
59
+ onRequest: ({ init }) => {
60
+ const headers = new Headers(init.headers);
61
+ headers.set("authorization", `Bearer ${getAccessToken()}`);
62
+ init.headers = headers;
63
+ },
64
+ });
65
+ }
66
+
67
+ export const clients = {
68
+ accounts: createServiceClient<AccountsEndpoints>(SERVICE_URLS.accounts),
69
+ billing: createServiceClient<BillingEndpoints>(SERVICE_URLS.billing),
70
+ notifications: createServiceClient<NotificationsEndpoints>(SERVICE_URLS.notifications),
71
+ };
72
+
73
+ function getAccessToken(): string {
74
+ return "token";
75
+ }
76
+
77
+ // usage
78
+ const me = await clients.accounts.get("/v1/me");
79
+ const invoices = await clients.billing.get("/v1/invoices");
80
+ ```
81
+
82
+ Suggested structure:
83
+ - `schemas/accounts.ts`, `schemas/billing.ts`, `schemas/notifications.ts`
84
+ - one shared `clients.ts` that exports preconfigured clients
85
+ - app code imports only `clients` and never constructs clients ad-hoc
86
+
87
+ ## Quick Start (Cats API)
88
+
89
+ ### With `baseUrl`
90
+
91
+ ```ts
92
+ import { clientApi } from "kayto_ts";
93
+ import type { Endpoints as CatsEndpoints } from "./schemas/cats";
94
+
95
+ const clientWithBaseUrl = clientApi<CatsEndpoints>({
96
+ baseUrl: "https://api.example.com",
97
+ });
98
+ ```
99
+
100
+ `baseUrl` applies only to relative paths.
101
+ If you pass an absolute URL (`https://...`), it is used as-is and `baseUrl` is ignored.
102
+
103
+ ```ts
104
+ import { clientApi } from "kayto_ts";
105
+ import type { Endpoints as CatsEndpoints } from "./schemas/cats";
106
+
107
+ const client = clientApi<CatsEndpoints>({
108
+ baseUrl: "https://api.example.com",
109
+ });
110
+
111
+ await client.get("/api/cats");
112
+ // -> https://api.example.com/api/cats
113
+
114
+ await client.get("https://other.example.com/api/cats" as "/api/cats");
115
+ // -> https://other.example.com/api/cats
116
+ ```
117
+
118
+ ## Basic Requests
119
+
120
+ ### GET with query params
121
+
122
+ ```ts
123
+ const listResult = await client.get("/api/cats", {
124
+ params: {
125
+ query: {
126
+ page: 1,
127
+ search: "british",
128
+ },
129
+ },
130
+ });
131
+ ```
132
+
133
+ ### GET with path params
134
+
135
+ ```ts
136
+ const oneResult = await client.get("/api/cats/{id}", {
137
+ params: {
138
+ path: {
139
+ id: "cat_42",
140
+ },
141
+ },
142
+ });
143
+ ```
144
+
145
+ ### POST with body
146
+
147
+ ```ts
148
+ const createResult = await client.post("/api/cats", {
149
+ body: {
150
+ name: "Milo",
151
+ age: 2,
152
+ },
153
+ });
154
+ ```
155
+
156
+ ### Request headers
157
+
158
+ ```ts
159
+ const authorizedResult = await client.get("/api/cats", {
160
+ headers: {
161
+ Authorization: "Bearer <token>",
162
+ "x-cats-trace-id": "trace_123",
163
+ },
164
+ });
165
+ ```
166
+
167
+ ### DELETE with path params
168
+
169
+ ```ts
170
+ const deleteResult = await client.delete("/api/cats/{id}", {
171
+ params: {
172
+ path: {
173
+ id: "cat_42",
174
+ },
175
+ },
176
+ });
177
+ ```
178
+
179
+ ## Timeout and Cancellation
180
+
181
+ ### Timeout
182
+
183
+ ```ts
184
+ const result = await client.get("/api/cats", {
185
+ timeoutMs: 5_000,
186
+ });
187
+ ```
188
+
189
+ ### AbortController
190
+
191
+ ```ts
192
+ const controller = new AbortController();
193
+
194
+ const promise = client.get("/api/cats", {
195
+ signal: controller.signal,
196
+ });
197
+
198
+ controller.abort();
199
+
200
+ const result = await promise;
201
+ ```
202
+
203
+ ## Hooks and Interceptor
204
+
205
+ ```ts
206
+ import { clientApi } from "kayto_ts";
207
+ import type { Endpoints as CatsEndpoints } from "./schemas/cats";
208
+
209
+ const clientWithHooks = clientApi<CatsEndpoints>({
210
+ baseUrl: "https://api.example.com",
211
+
212
+ onRequest: ({ method, path, init }) => {
213
+ const headers = new Headers(init.headers);
214
+ headers.set("x-cats-trace-id", "trace_123");
215
+ init.headers = headers;
216
+
217
+ console.log("request", method, path);
218
+ },
219
+
220
+ responseInterceptor: async ({ response }) => {
221
+ // Example: could refresh token and retry in your own wrapper logic.
222
+ return response;
223
+ },
224
+
225
+ onResponse: ({ method, path, response, durationMs }) => {
226
+ console.log("response", method, path, response.status, `${durationMs}ms`);
227
+ },
228
+ });
229
+ ```
230
+
231
+ ## Error Handling
232
+
233
+ All requests return a discriminated union:
234
+
235
+ - success: `{ ok: true, result, response }`
236
+ - failure: `{ ok: false, error, response? }`
237
+
238
+ `error.kind` values:
239
+
240
+ - `network`
241
+ - `timeout`
242
+ - `aborted`
243
+ - `http`
244
+ - `parse`
245
+ - `hook`
246
+
247
+ You can handle errors by `kind`, but it is optional.
248
+ You can also handle them generically via `message` / `status` / `cause` without branching by `kind`.
249
+
250
+ ```ts
251
+ const result = await client.get("/api/cats");
252
+
253
+ if (!result.ok) {
254
+ console.error("Request failed:", result.error.message);
255
+
256
+ if (result.error.status != null) {
257
+ console.error("HTTP status:", result.error.status);
258
+ }
259
+
260
+ if (result.error.cause) {
261
+ console.error("Cause:", result.error.cause);
262
+ }
263
+ }
264
+ ```
265
+
266
+ ```ts
267
+ const result = await client.get("/api/cats");
268
+
269
+ if (!result.ok) {
270
+ switch (result.error.kind) {
271
+ case "timeout":
272
+ console.error("Cats API timeout");
273
+ break;
274
+ case "aborted":
275
+ console.error("Request was cancelled");
276
+ break;
277
+ case "http":
278
+ console.error("HTTP error", result.error.status);
279
+ break;
280
+ default:
281
+ console.error(result.error.message, result.error.cause);
282
+ }
283
+ }
284
+ ```
285
+
286
+ ## Response Parsing Rules
287
+
288
+ Client parses response body automatically by `content-type`:
289
+
290
+ - JSON: `application/json`, `application/problem+json`, `*+json`
291
+ - Text: `text/*`
292
+ - Other content-types: `Blob`
293
+ - Empty body statuses (`204`, `205`, `304`): `null`
294
+
295
+ ## Notes
296
+
297
+ - Runtime shape validation is not built in yet (current typing is compile-time only).
298
+ - If you need runtime validation, validate `result.result` in consumer code (ArkType/Zod/etc.).
299
+ - Current entrypoint is `src/index.ts`.
package/bin/kayto.mjs ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { spawnSync } from "node:child_process";
6
+ import { platform } from "node:os";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const rootDir = dirname(__dirname);
11
+
12
+ const binary = platform() === "win32" ? "kayto.exe" : "kayto";
13
+ const binaryPath = join(rootDir, ".kayto", "bin", binary);
14
+
15
+ if (!existsSync(binaryPath)) {
16
+ console.error("[kayto_ts] kayto binary is missing. Reinstall package: npm i kayto_ts (or bun/pnpm/yarn install)");
17
+ process.exit(1);
18
+ }
19
+
20
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
21
+ stdio: "inherit",
22
+ });
23
+
24
+ if (result.error) {
25
+ console.error("[kayto_ts] failed to execute kayto:", result.error.message);
26
+ process.exit(1);
27
+ }
28
+
29
+ process.exit(result.status ?? 1);
package/bun.lock ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "kayto_ts",
7
+ "devDependencies": {
8
+ "@types/bun": "latest",
9
+ },
10
+ "peerDependencies": {
11
+ "typescript": "^5",
12
+ },
13
+ },
14
+ },
15
+ "packages": {
16
+ "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
17
+
18
+ "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
19
+
20
+ "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
21
+
22
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
23
+
24
+ "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
25
+ }
26
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "kayto_ts",
3
+ "version": "0.1.0",
4
+ "description": "Type-safe HTTP client and CLI wrapper for generating and using schemas with kayto.",
5
+ "module": "src/index.ts",
6
+ "type": "module",
7
+ "bin": {
8
+ "kayto": "./bin/kayto.mjs"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "bun ./scripts/postinstall.mjs || node ./scripts/postinstall.mjs",
12
+ "test": "bun test"
13
+ },
14
+ "devDependencies": {
15
+ "@types/bun": "latest"
16
+ },
17
+ "peerDependencies": {
18
+ "typescript": "^5"
19
+ }
20
+ }