kayto_ts 0.1.1 → 0.1.3
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 +7 -13
- package/package.json +2 -6
- package/bin/kayto.mjs +0 -29
- package/scripts/postinstall.mjs +0 -541
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
🚀 Build robust API integrations faster with `kayto_ts`.
|
|
6
6
|
|
|
7
7
|
- 🔒 End-to-end type safety for `method + path + params + body + response`
|
|
8
|
-
- ⚡ Zero-boilerplate HTTP client
|
|
8
|
+
- ⚡ Zero-boilerplate HTTP client usage with generated schema types
|
|
9
9
|
- 🧩 Request/response hooks for auth, tracing, and custom logic
|
|
10
10
|
- ⏱️ Built-in timeout and cancellation support
|
|
11
11
|
- 🛡️ Predictable, unified error model for cleaner handling
|
|
@@ -20,23 +20,17 @@ bun add kayto_ts
|
|
|
20
20
|
# yarn add kayto_ts
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
No global `kayto` install is required.
|
|
23
|
+
## Generate schema (install kayto separately)
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
`kayto_ts` is a client library only.
|
|
26
|
+
To generate `schema.ts`, install `kayto` using the official guide:
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
[Install kayto from releases](https://github.com/vladislav-yemelyanov/kayto?tab=readme-ov-file#install-from-releases)
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
bunx kayto --lang ts --input "https://example.com/openapi.json" --output "generated/schema.ts"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Alternatives:
|
|
30
|
+
Example generation command after installing `kayto`:
|
|
35
31
|
|
|
36
32
|
```bash
|
|
37
|
-
|
|
38
|
-
pnpm exec kayto --help
|
|
39
|
-
yarn kayto --help
|
|
33
|
+
kayto --lang ts --input "https://example.com/openapi.json" --output "generated/schema.ts"
|
|
40
34
|
```
|
|
41
35
|
|
|
42
36
|
## Multiple Services
|
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kayto_ts",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Type-safe HTTP client
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Type-safe HTTP client for working with kayto-generated endpoint schemas.",
|
|
5
5
|
"repository": "https://github.com/vladislav-yemelyanov/kayto_ts",
|
|
6
6
|
"homepage": "https://www.npmjs.com/package/kayto_ts",
|
|
7
7
|
"module": "src/index.ts",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"bin": {
|
|
10
|
-
"kayto": "./bin/kayto.mjs"
|
|
11
|
-
},
|
|
12
9
|
"scripts": {
|
|
13
|
-
"postinstall": "bun ./scripts/postinstall.mjs || node ./scripts/postinstall.mjs",
|
|
14
10
|
"test": "bun test"
|
|
15
11
|
},
|
|
16
12
|
"devDependencies": {
|
package/bin/kayto.mjs
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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/scripts/postinstall.mjs
DELETED
|
@@ -1,541 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
chmodSync,
|
|
4
|
-
copyFileSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
readdirSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
rmSync,
|
|
10
|
-
writeFileSync,
|
|
11
|
-
} from "node:fs";
|
|
12
|
-
import { createHash } from "node:crypto";
|
|
13
|
-
import { arch, platform } from "node:os";
|
|
14
|
-
import { dirname, join } from "node:path";
|
|
15
|
-
import { fileURLToPath } from "node:url";
|
|
16
|
-
import { spawnSync } from "node:child_process";
|
|
17
|
-
|
|
18
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
-
const __dirname = dirname(__filename);
|
|
20
|
-
const rootDir = dirname(__dirname);
|
|
21
|
-
|
|
22
|
-
const repo = process.env.KAYTO_REPO ?? "vladislav-yemelyanov/kayto";
|
|
23
|
-
const versionInputRaw = process.env.KAYTO_VERSION?.trim();
|
|
24
|
-
|
|
25
|
-
const installDir = join(rootDir, ".kayto", "bin");
|
|
26
|
-
const metadataPath = join(rootDir, ".kayto", "metadata.json");
|
|
27
|
-
|
|
28
|
-
function userError(problem, actions = []) {
|
|
29
|
-
const lines = [problem];
|
|
30
|
-
if (actions.length > 0) {
|
|
31
|
-
lines.push("What to do:");
|
|
32
|
-
actions.forEach((action, index) => {
|
|
33
|
-
lines.push(`${index + 1}. ${action}`);
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const err = new Error(lines.join("\n"));
|
|
38
|
-
err.name = "KaytoInstallError";
|
|
39
|
-
return err;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function unique(values) {
|
|
43
|
-
return [...new Set(values)];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function getVersionCandidates(version) {
|
|
47
|
-
const trimmed = version.replace(/^v/, "");
|
|
48
|
-
return {
|
|
49
|
-
tags: unique([version, `v${trimmed}`, trimmed]),
|
|
50
|
-
assets: unique([version, `v${trimmed}`, trimmed]),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function validateInputs() {
|
|
55
|
-
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) {
|
|
56
|
-
throw userError(
|
|
57
|
-
`Invalid KAYTO_REPO: \"${repo}\". Expected format: <owner>/<repo>.`,
|
|
58
|
-
[
|
|
59
|
-
"Set KAYTO_REPO correctly, e.g. vladislav-yemelyanov/kayto.",
|
|
60
|
-
"Remove KAYTO_REPO to use the default repository.",
|
|
61
|
-
],
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const checksum = process.env.KAYTO_SHA256?.trim();
|
|
66
|
-
if (checksum && !/^[a-fA-F0-9]{64}$/.test(checksum)) {
|
|
67
|
-
throw userError(
|
|
68
|
-
"KAYTO_SHA256 must be a 64-character hex SHA-256 string.",
|
|
69
|
-
[
|
|
70
|
-
"Use checksum format like: e3b0c44298fc1c149afbf4c8996fb924...",
|
|
71
|
-
"Unset KAYTO_SHA256 to auto-resolve checksum from release files.",
|
|
72
|
-
],
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function getTarget() {
|
|
78
|
-
const p = platform();
|
|
79
|
-
const a = arch();
|
|
80
|
-
|
|
81
|
-
let targetOs;
|
|
82
|
-
let ext;
|
|
83
|
-
|
|
84
|
-
if (p === "darwin") {
|
|
85
|
-
targetOs = "apple-darwin";
|
|
86
|
-
ext = "tar.gz";
|
|
87
|
-
} else if (p === "linux") {
|
|
88
|
-
targetOs = "unknown-linux-gnu";
|
|
89
|
-
ext = "tar.gz";
|
|
90
|
-
} else if (p === "win32") {
|
|
91
|
-
targetOs = "pc-windows-gnu";
|
|
92
|
-
ext = "zip";
|
|
93
|
-
} else {
|
|
94
|
-
throw userError(`Unsupported platform: ${p}.`, [
|
|
95
|
-
"Use macOS, Linux, or Windows.",
|
|
96
|
-
"Or install kayto manually from GitHub release assets.",
|
|
97
|
-
]);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let targetArch;
|
|
101
|
-
if (a === "x64") {
|
|
102
|
-
targetArch = "x86_64";
|
|
103
|
-
} else if (a === "arm64") {
|
|
104
|
-
targetArch = "aarch64";
|
|
105
|
-
} else {
|
|
106
|
-
throw userError(`Unsupported architecture: ${a}.`, [
|
|
107
|
-
"Use x64 or arm64 machine.",
|
|
108
|
-
"Or install a compatible binary manually.",
|
|
109
|
-
]);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (p === "win32" && targetArch !== "x86_64") {
|
|
113
|
-
throw userError(`Windows build is available only for x86_64, got ${targetArch}.`, [
|
|
114
|
-
"Use x64 Windows environment.",
|
|
115
|
-
"Or build kayto from source on your machine.",
|
|
116
|
-
]);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
binaryName: p === "win32" ? "kayto.exe" : "kayto",
|
|
121
|
-
target: `${targetArch}-${targetOs}`,
|
|
122
|
-
ext,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function readMetadata() {
|
|
127
|
-
if (!existsSync(metadataPath)) {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
return JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
133
|
-
} catch {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function writeMetadata(next) {
|
|
139
|
-
try {
|
|
140
|
-
writeFileSync(metadataPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
|
|
141
|
-
} catch (error) {
|
|
142
|
-
throw userError("Failed to write installation metadata.", [
|
|
143
|
-
`Check write permissions for: ${metadataPath}`,
|
|
144
|
-
"Try reinstalling package with sufficient permissions.",
|
|
145
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
146
|
-
]);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function findBinaryRecursive(startDir, binaryName) {
|
|
151
|
-
const entries = readdirSync(startDir, { withFileTypes: true });
|
|
152
|
-
|
|
153
|
-
for (const entry of entries) {
|
|
154
|
-
const abs = join(startDir, entry.name);
|
|
155
|
-
|
|
156
|
-
if (entry.isFile() && entry.name === binaryName) {
|
|
157
|
-
return abs;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (entry.isDirectory()) {
|
|
161
|
-
const nested = findBinaryRecursive(abs, binaryName);
|
|
162
|
-
if (nested) {
|
|
163
|
-
return nested;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async function fetchText(url) {
|
|
172
|
-
let response;
|
|
173
|
-
try {
|
|
174
|
-
response = await fetch(url, {
|
|
175
|
-
headers: {
|
|
176
|
-
"User-Agent": "kayto_ts-postinstall",
|
|
177
|
-
Accept: "application/json, text/plain, application/octet-stream",
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
} catch (error) {
|
|
181
|
-
throw userError(`Network error while requesting ${url}.`, [
|
|
182
|
-
"Check internet access and DNS settings.",
|
|
183
|
-
"If you are behind proxy, configure proxy for Node.js/npm.",
|
|
184
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
185
|
-
]);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (!response.ok) {
|
|
189
|
-
throw userError(`Request failed (${response.status}) ${url}`, [
|
|
190
|
-
"Verify repository/tag/checksum file exists in GitHub release.",
|
|
191
|
-
"If GitHub is rate-limited, retry later or use authenticated network.",
|
|
192
|
-
]);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return response.text();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function resolveVersionInput() {
|
|
199
|
-
if (versionInputRaw) {
|
|
200
|
-
return versionInputRaw;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const url = `https://api.github.com/repos/${repo}/releases/latest`;
|
|
204
|
-
|
|
205
|
-
let response;
|
|
206
|
-
try {
|
|
207
|
-
response = await fetch(url, {
|
|
208
|
-
headers: {
|
|
209
|
-
"User-Agent": "kayto_ts-postinstall",
|
|
210
|
-
Accept: "application/vnd.github+json",
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
} catch (error) {
|
|
214
|
-
throw userError("Failed to resolve latest kayto release tag from GitHub.", [
|
|
215
|
-
"Check internet access and DNS settings.",
|
|
216
|
-
"Or set KAYTO_VERSION explicitly, e.g. KAYTO_VERSION=v0.1.32.",
|
|
217
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
218
|
-
]);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!response.ok) {
|
|
222
|
-
throw userError(`Failed to resolve latest release (${response.status}).`, [
|
|
223
|
-
`Open: ${url}`,
|
|
224
|
-
"Or set KAYTO_VERSION explicitly to a known tag.",
|
|
225
|
-
]);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const json = await response.json();
|
|
229
|
-
const tag = typeof json?.tag_name === "string" ? json.tag_name.trim() : "";
|
|
230
|
-
if (!tag) {
|
|
231
|
-
throw userError("GitHub response does not contain a valid latest tag_name.", [
|
|
232
|
-
"Set KAYTO_VERSION explicitly, e.g. KAYTO_VERSION=v0.1.32.",
|
|
233
|
-
"Verify releases exist in the target repository.",
|
|
234
|
-
]);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return tag;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async function downloadFile(url, outFile) {
|
|
241
|
-
let response;
|
|
242
|
-
try {
|
|
243
|
-
response = await fetch(url, {
|
|
244
|
-
headers: {
|
|
245
|
-
"User-Agent": "kayto_ts-postinstall",
|
|
246
|
-
Accept: "application/octet-stream",
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
} catch (error) {
|
|
250
|
-
throw userError(`Network error while downloading archive from ${url}.`, [
|
|
251
|
-
"Check internet/proxy configuration.",
|
|
252
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
253
|
-
]);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (!response.ok) {
|
|
257
|
-
throw userError(`Download failed (${response.status}) ${url}`, [
|
|
258
|
-
"Verify release/tag exists and contains the expected archive asset.",
|
|
259
|
-
"Try setting KAYTO_VERSION to an existing tag.",
|
|
260
|
-
]);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
264
|
-
writeFileSync(outFile, Buffer.from(arrayBuffer));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function sha256Hex(filePath) {
|
|
268
|
-
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function parseSha256Text(text, archiveName) {
|
|
272
|
-
const normalized = text.trim().toLowerCase();
|
|
273
|
-
const direct = normalized.match(/^[a-f0-9]{64}$/);
|
|
274
|
-
if (direct) {
|
|
275
|
-
return direct[0];
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const lines = text.split(/\r?\n/);
|
|
279
|
-
for (const line of lines) {
|
|
280
|
-
const match = line.trim().match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
|
|
281
|
-
if (!match) {
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const fileName = match[2].trim();
|
|
286
|
-
if (fileName === archiveName) {
|
|
287
|
-
return match[1].toLowerCase();
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
async function resolveExpectedSha256(repoName, tag, archiveName) {
|
|
295
|
-
const base = `https://github.com/${repoName}/releases/download/${tag}`;
|
|
296
|
-
const directCandidates = [
|
|
297
|
-
`${base}/${archiveName}.sha256`,
|
|
298
|
-
`${base}/${archiveName}.sha256.txt`,
|
|
299
|
-
];
|
|
300
|
-
|
|
301
|
-
for (const url of directCandidates) {
|
|
302
|
-
try {
|
|
303
|
-
const text = await fetchText(url);
|
|
304
|
-
const value = parseSha256Text(text, archiveName);
|
|
305
|
-
if (value) {
|
|
306
|
-
return { value, source: url };
|
|
307
|
-
}
|
|
308
|
-
} catch {
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const checksumFileCandidates = [
|
|
313
|
-
"checksums.txt",
|
|
314
|
-
"sha256sums.txt",
|
|
315
|
-
"SHA256SUMS",
|
|
316
|
-
"SHA256SUMS.txt",
|
|
317
|
-
];
|
|
318
|
-
|
|
319
|
-
for (const fileName of checksumFileCandidates) {
|
|
320
|
-
const url = `${base}/${fileName}`;
|
|
321
|
-
try {
|
|
322
|
-
const text = await fetchText(url);
|
|
323
|
-
const value = parseSha256Text(text, archiveName);
|
|
324
|
-
if (value) {
|
|
325
|
-
return { value, source: url };
|
|
326
|
-
}
|
|
327
|
-
} catch {
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async function verifyArchiveChecksum(archivePath, archiveName, resolvedTag) {
|
|
335
|
-
if (process.env.KAYTO_SKIP_CHECKSUM === "1") {
|
|
336
|
-
console.warn("[kayto_ts] checksum verification is disabled via KAYTO_SKIP_CHECKSUM=1");
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const expectedFromEnv = process.env.KAYTO_SHA256?.trim().toLowerCase();
|
|
341
|
-
let expected = expectedFromEnv;
|
|
342
|
-
let source = "KAYTO_SHA256";
|
|
343
|
-
|
|
344
|
-
if (!expected) {
|
|
345
|
-
const resolved = await resolveExpectedSha256(repo, resolvedTag, archiveName);
|
|
346
|
-
if (!resolved) {
|
|
347
|
-
throw userError(`Could not resolve SHA-256 for ${archiveName}.`, [
|
|
348
|
-
`Publish checksum files in release ${resolvedTag} (e.g. checksums.txt).`,
|
|
349
|
-
"Or provide checksum explicitly via KAYTO_SHA256.",
|
|
350
|
-
"Or set KAYTO_SKIP_CHECKSUM=1 to bypass verification (not recommended).",
|
|
351
|
-
]);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
expected = resolved.value;
|
|
355
|
-
source = resolved.source;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const actual = sha256Hex(archivePath);
|
|
359
|
-
if (actual !== expected) {
|
|
360
|
-
throw userError(`Checksum mismatch for ${archiveName}.`, [
|
|
361
|
-
`Expected: ${expected} (${source})`,
|
|
362
|
-
`Actual: ${actual}`,
|
|
363
|
-
"Re-run install with KAYTO_FORCE_INSTALL=1 to re-download archive.",
|
|
364
|
-
"If mismatch persists, verify release integrity and network/proxy behavior.",
|
|
365
|
-
]);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
console.log(`[kayto_ts] verified SHA-256 for ${archiveName} (${source})`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function extractArchive(archivePath, outDir, ext) {
|
|
372
|
-
if (ext === "tar.gz") {
|
|
373
|
-
const tar = spawnSync("tar", ["-xzf", archivePath, "-C", outDir], {
|
|
374
|
-
stdio: "inherit",
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
if (tar.error) {
|
|
378
|
-
throw userError("Failed to execute tar while extracting archive.", [
|
|
379
|
-
"Install tar and make sure it is available in PATH.",
|
|
380
|
-
`Original error: ${tar.error.message}`,
|
|
381
|
-
]);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (tar.status !== 0) {
|
|
385
|
-
throw userError("Failed to extract tar.gz archive.", [
|
|
386
|
-
"Archive may be corrupted. Re-run with KAYTO_FORCE_INSTALL=1.",
|
|
387
|
-
"Check tar output above for details.",
|
|
388
|
-
]);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const ps = spawnSync(
|
|
395
|
-
"powershell",
|
|
396
|
-
[
|
|
397
|
-
"-NoProfile",
|
|
398
|
-
"-ExecutionPolicy",
|
|
399
|
-
"Bypass",
|
|
400
|
-
"-Command",
|
|
401
|
-
`Expand-Archive -LiteralPath '${archivePath.replace(/'/g, "''")}' -DestinationPath '${outDir.replace(/'/g, "''")}' -Force`,
|
|
402
|
-
],
|
|
403
|
-
{ stdio: "inherit" },
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
if (ps.error) {
|
|
407
|
-
throw userError("Failed to execute PowerShell while extracting archive.", [
|
|
408
|
-
"Make sure PowerShell is installed and available in PATH.",
|
|
409
|
-
`Original error: ${ps.error.message}`,
|
|
410
|
-
]);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (ps.status !== 0) {
|
|
414
|
-
throw userError("Failed to extract zip archive.", [
|
|
415
|
-
"Archive may be corrupted. Re-run with KAYTO_FORCE_INSTALL=1.",
|
|
416
|
-
"Check PowerShell output above for details.",
|
|
417
|
-
]);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
async function resolveAndDownloadArchive(tmpDir, target, ext, versionInput) {
|
|
422
|
-
const candidates = getVersionCandidates(versionInput);
|
|
423
|
-
const attempted = [];
|
|
424
|
-
|
|
425
|
-
for (const tag of candidates.tags) {
|
|
426
|
-
for (const assetVersion of candidates.assets) {
|
|
427
|
-
const archive = `kayto-${assetVersion}-${target}.${ext}`;
|
|
428
|
-
const url = `https://github.com/${repo}/releases/download/${tag}/${archive}`;
|
|
429
|
-
const archivePath = join(tmpDir, archive);
|
|
430
|
-
attempted.push(url);
|
|
431
|
-
|
|
432
|
-
try {
|
|
433
|
-
await downloadFile(url, archivePath);
|
|
434
|
-
return {
|
|
435
|
-
archivePath,
|
|
436
|
-
archiveName: archive,
|
|
437
|
-
resolvedTag: tag,
|
|
438
|
-
resolvedAssetVersion: assetVersion,
|
|
439
|
-
};
|
|
440
|
-
} catch {
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
throw userError(`Could not download kayto archive for target ${target}.`, [
|
|
446
|
-
`Requested version input: ${versionInput}`,
|
|
447
|
-
`Tried tags: ${candidates.tags.join(", ")}`,
|
|
448
|
-
`Repository: ${repo}`,
|
|
449
|
-
"Check that release assets exist for your OS/arch target.",
|
|
450
|
-
"Set KAYTO_VERSION to a known existing tag.",
|
|
451
|
-
`Sample attempted URL: ${attempted[0] ?? "n/a"}`,
|
|
452
|
-
]);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
function installBinary(extractedBinary, binaryPath) {
|
|
456
|
-
try {
|
|
457
|
-
copyFileSync(extractedBinary, binaryPath);
|
|
458
|
-
if (platform() !== "win32") {
|
|
459
|
-
chmodSync(binaryPath, 0o755);
|
|
460
|
-
}
|
|
461
|
-
} catch (error) {
|
|
462
|
-
throw userError("Failed to install kayto binary into local package directory.", [
|
|
463
|
-
`Target path: ${binaryPath}`,
|
|
464
|
-
"Check directory write permissions.",
|
|
465
|
-
`Original error: ${error instanceof Error ? error.message : String(error)}`,
|
|
466
|
-
]);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
async function main() {
|
|
471
|
-
validateInputs();
|
|
472
|
-
|
|
473
|
-
const versionInput = await resolveVersionInput();
|
|
474
|
-
const { binaryName, target, ext } = getTarget();
|
|
475
|
-
const binaryPath = join(installDir, binaryName);
|
|
476
|
-
|
|
477
|
-
const current = readMetadata();
|
|
478
|
-
if (
|
|
479
|
-
process.env.KAYTO_FORCE_INSTALL !== "1"
|
|
480
|
-
&& existsSync(binaryPath)
|
|
481
|
-
&& current?.versionInput === versionInput
|
|
482
|
-
&& current?.target === target
|
|
483
|
-
&& current?.repo === repo
|
|
484
|
-
) {
|
|
485
|
-
console.log(`[kayto_ts] kayto already installed (${versionInput}, ${target})`);
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
mkdirSync(installDir, { recursive: true });
|
|
490
|
-
|
|
491
|
-
const tmpDir = join(rootDir, ".kayto", "tmp");
|
|
492
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
493
|
-
mkdirSync(tmpDir, { recursive: true });
|
|
494
|
-
|
|
495
|
-
try {
|
|
496
|
-
console.log(`[kayto_ts] resolving release for ${target}`);
|
|
497
|
-
const { archivePath, archiveName, resolvedTag, resolvedAssetVersion } = await resolveAndDownloadArchive(
|
|
498
|
-
tmpDir,
|
|
499
|
-
target,
|
|
500
|
-
ext,
|
|
501
|
-
versionInput,
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
console.log(
|
|
505
|
-
`[kayto_ts] downloaded kayto-${resolvedAssetVersion}-${target}.${ext} (tag ${resolvedTag})`,
|
|
506
|
-
);
|
|
507
|
-
|
|
508
|
-
await verifyArchiveChecksum(archivePath, archiveName, resolvedTag);
|
|
509
|
-
extractArchive(archivePath, tmpDir, ext);
|
|
510
|
-
|
|
511
|
-
const extractedBinary = findBinaryRecursive(tmpDir, binaryName);
|
|
512
|
-
if (!extractedBinary) {
|
|
513
|
-
throw userError(`Could not find ${binaryName} in downloaded archive.`, [
|
|
514
|
-
"Release asset structure may have changed.",
|
|
515
|
-
`Verify asset content for tag ${resolvedTag} in repository ${repo}.`,
|
|
516
|
-
"Try setting KAYTO_VERSION to another tag.",
|
|
517
|
-
]);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
installBinary(extractedBinary, binaryPath);
|
|
521
|
-
|
|
522
|
-
writeMetadata({
|
|
523
|
-
repo,
|
|
524
|
-
versionInput,
|
|
525
|
-
resolvedTag,
|
|
526
|
-
resolvedAssetVersion,
|
|
527
|
-
target,
|
|
528
|
-
installedAt: new Date().toISOString(),
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
console.log(`[kayto_ts] installed ${binaryName} (${resolvedAssetVersion}, ${target})`);
|
|
532
|
-
} finally {
|
|
533
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
main().catch((error) => {
|
|
538
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
539
|
-
console.error(`[kayto_ts] postinstall failed:\n${message}`);
|
|
540
|
-
process.exit(1);
|
|
541
|
-
});
|