@hono/cli 0.1.9 → 0.1.10
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 +5 -0
- package/dist/cli.js +166 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,6 +157,11 @@ hono request [file] [options]
|
|
|
157
157
|
- `-d, --data <data>` - Request body data
|
|
158
158
|
- `-H, --header <header>` - Custom headers (can be used multiple times)
|
|
159
159
|
- `-w, --watch` - Watch for changes and resend request
|
|
160
|
+
- `-J, --json` - Output response as JSON
|
|
161
|
+
- `-o, --output <file>` - Write to file instead of stdout
|
|
162
|
+
- `-O, --remote-name` - Write output to file named as remote file
|
|
163
|
+
- `-i, --include` - Include protocol and headers in the output
|
|
164
|
+
- `-I, --head` - Show only protocol and headers in the output
|
|
160
165
|
- `-e, --external <package>` - Mark package as external (can be used multiple times)
|
|
161
166
|
|
|
162
167
|
**Examples:**
|
package/dist/cli.js
CHANGED
|
@@ -14665,7 +14665,7 @@ var require_lib = __commonJS({
|
|
|
14665
14665
|
// src/cli.ts
|
|
14666
14666
|
import { Command } from "commander";
|
|
14667
14667
|
import { readFileSync as readFileSync2 } from "fs";
|
|
14668
|
-
import { dirname as
|
|
14668
|
+
import { dirname as dirname3, join as join2 } from "path";
|
|
14669
14669
|
import { fileURLToPath } from "url";
|
|
14670
14670
|
|
|
14671
14671
|
// src/commands/docs/index.ts
|
|
@@ -16206,18 +16206,82 @@ var isIdentifier = (key) => key.type === "Identifier";
|
|
|
16206
16206
|
var isPrivateIdentifier = (key) => key.type === "PrivateName";
|
|
16207
16207
|
|
|
16208
16208
|
// src/commands/request/index.ts
|
|
16209
|
-
import { existsSync as
|
|
16209
|
+
import { existsSync as existsSync3, realpathSync as realpathSync2 } from "fs";
|
|
16210
16210
|
import { resolve as resolve2 } from "path";
|
|
16211
|
+
|
|
16212
|
+
// src/utils/file.ts
|
|
16213
|
+
import { getExtension } from "hono/utils/mime";
|
|
16214
|
+
import { existsSync as existsSync2, createWriteStream } from "fs";
|
|
16215
|
+
import { dirname as dirname2, basename } from "path";
|
|
16216
|
+
var getFilenameFromPath = (path, contentType) => {
|
|
16217
|
+
const url = new URL(path, "http://localhost");
|
|
16218
|
+
const pathname = url.pathname;
|
|
16219
|
+
if (pathname === "/") {
|
|
16220
|
+
if (contentType) {
|
|
16221
|
+
const parts = contentType.split(";");
|
|
16222
|
+
for (const part of parts) {
|
|
16223
|
+
const mimeType = part.trim().toLowerCase();
|
|
16224
|
+
const extension = getExtension(mimeType);
|
|
16225
|
+
if (extension) {
|
|
16226
|
+
return `index.${extension}`;
|
|
16227
|
+
}
|
|
16228
|
+
}
|
|
16229
|
+
}
|
|
16230
|
+
return "index";
|
|
16231
|
+
}
|
|
16232
|
+
const name = basename(pathname);
|
|
16233
|
+
return name;
|
|
16234
|
+
};
|
|
16235
|
+
var saveFile = async (buffer, filepath) => {
|
|
16236
|
+
if (existsSync2(filepath)) {
|
|
16237
|
+
throw new Error(`File ${filepath} already exists.`);
|
|
16238
|
+
}
|
|
16239
|
+
const dir = dirname2(filepath);
|
|
16240
|
+
if (!existsSync2(dir)) {
|
|
16241
|
+
throw new Error(`Directory ${dir} does not exist.`);
|
|
16242
|
+
}
|
|
16243
|
+
const totalBytes = buffer.byteLength;
|
|
16244
|
+
const view = new Uint8Array(buffer);
|
|
16245
|
+
const chunkSize = 1024 * 64;
|
|
16246
|
+
let savedBytes = 0;
|
|
16247
|
+
const stream = createWriteStream(filepath);
|
|
16248
|
+
return new Promise((resolve4, reject) => {
|
|
16249
|
+
stream.on("error", (err) => reject(err));
|
|
16250
|
+
const writeChunk = (index) => {
|
|
16251
|
+
if (index >= totalBytes) {
|
|
16252
|
+
stream.end(() => {
|
|
16253
|
+
resolve4();
|
|
16254
|
+
});
|
|
16255
|
+
return;
|
|
16256
|
+
}
|
|
16257
|
+
const end = Math.min(index + chunkSize, totalBytes);
|
|
16258
|
+
const chunk = view.slice(index, end);
|
|
16259
|
+
stream.write(chunk, (err) => {
|
|
16260
|
+
if (err) {
|
|
16261
|
+
stream.destroy(err);
|
|
16262
|
+
reject(err);
|
|
16263
|
+
return;
|
|
16264
|
+
}
|
|
16265
|
+
savedBytes += chunk.length;
|
|
16266
|
+
console.log(`Saved ${savedBytes} of ${totalBytes} bytes`);
|
|
16267
|
+
writeChunk(end);
|
|
16268
|
+
});
|
|
16269
|
+
};
|
|
16270
|
+
writeChunk(0);
|
|
16271
|
+
});
|
|
16272
|
+
};
|
|
16273
|
+
|
|
16274
|
+
// src/commands/request/index.ts
|
|
16211
16275
|
var DEFAULT_ENTRY_CANDIDATES2 = ["src/index.ts", "src/index.tsx", "src/index.js", "src/index.jsx"];
|
|
16212
16276
|
function requestCommand(program2) {
|
|
16213
|
-
program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option("-w, --watch", "Watch for changes and resend request", false).option(
|
|
16277
|
+
program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option("-w, --watch", "Watch for changes and resend request", false).option("-J, --json", "Output response as JSON", false).option(
|
|
16214
16278
|
"-H, --header <header>",
|
|
16215
16279
|
"Custom headers",
|
|
16216
16280
|
(value, previous) => {
|
|
16217
16281
|
return previous ? [...previous, value] : [value];
|
|
16218
16282
|
},
|
|
16219
16283
|
[]
|
|
16220
|
-
).option(
|
|
16284
|
+
).option("-o, --output <file>", "Write to file instead of stdout").option("-O, --remote-name", "Write output to file named as remote file", false).option("-i, --include", "Include protocol and headers in the output", false).option("-I, --head", "Show only protocol and headers in the output", false).option(
|
|
16221
16285
|
"-e, --external <package>",
|
|
16222
16286
|
"Mark package as external (can be used multiple times)",
|
|
16223
16287
|
(value, previous) => {
|
|
@@ -16225,16 +16289,80 @@ function requestCommand(program2) {
|
|
|
16225
16289
|
},
|
|
16226
16290
|
[]
|
|
16227
16291
|
).action(async (file, options) => {
|
|
16292
|
+
const doSaveFile = options.output || options.remoteName;
|
|
16228
16293
|
const path = options.path || "/";
|
|
16229
16294
|
const watch = options.watch;
|
|
16230
16295
|
const external = options.external || [];
|
|
16231
16296
|
const buildIterator = getBuildIterator(file, watch, external);
|
|
16232
16297
|
for await (const app of buildIterator) {
|
|
16233
16298
|
const result = await executeRequest(app, path, options);
|
|
16234
|
-
|
|
16299
|
+
const contentType = result.headers["content-type"];
|
|
16300
|
+
const outputBody = formatResponseBody(
|
|
16301
|
+
result.body,
|
|
16302
|
+
contentType,
|
|
16303
|
+
options.json && !options.include
|
|
16304
|
+
);
|
|
16305
|
+
const buffer = await result.response.clone().arrayBuffer();
|
|
16306
|
+
const isBinaryData = isBinaryResponse(buffer);
|
|
16307
|
+
if (isBinaryData && !doSaveFile) {
|
|
16308
|
+
console.warn("Binary output can mess up your terminal.");
|
|
16309
|
+
continue;
|
|
16310
|
+
}
|
|
16311
|
+
const outputData = getOutputData(
|
|
16312
|
+
buffer,
|
|
16313
|
+
outputBody,
|
|
16314
|
+
isBinaryData,
|
|
16315
|
+
options,
|
|
16316
|
+
result.status,
|
|
16317
|
+
result.headers
|
|
16318
|
+
);
|
|
16319
|
+
if (!isBinaryData) {
|
|
16320
|
+
console.log(outputData);
|
|
16321
|
+
}
|
|
16322
|
+
if (doSaveFile) {
|
|
16323
|
+
await handleSaveOutput(outputData, path, options, contentType);
|
|
16324
|
+
}
|
|
16235
16325
|
}
|
|
16236
16326
|
});
|
|
16237
16327
|
}
|
|
16328
|
+
function getOutputData(buffer, outputBody, isBinaryData, options, status, headers) {
|
|
16329
|
+
if (isBinaryData) {
|
|
16330
|
+
return buffer;
|
|
16331
|
+
}
|
|
16332
|
+
const headerLines = [];
|
|
16333
|
+
headerLines.push(`${status}`);
|
|
16334
|
+
for (const key in headers) {
|
|
16335
|
+
headerLines.push(`\x1B[1m${key}\x1B[0m: ${headers[key]}`);
|
|
16336
|
+
}
|
|
16337
|
+
const headerOutput = headerLines.join("\n");
|
|
16338
|
+
if (options.head) {
|
|
16339
|
+
return headerOutput + "\n";
|
|
16340
|
+
}
|
|
16341
|
+
if (options.include) {
|
|
16342
|
+
return headerOutput + "\n\n" + outputBody;
|
|
16343
|
+
}
|
|
16344
|
+
if (options.json) {
|
|
16345
|
+
return JSON.stringify({ status, body: outputBody, headers }, null, 2);
|
|
16346
|
+
}
|
|
16347
|
+
return outputBody;
|
|
16348
|
+
}
|
|
16349
|
+
async function handleSaveOutput(saveData, requestPath, options, contentType) {
|
|
16350
|
+
let filepath;
|
|
16351
|
+
if (options.output) {
|
|
16352
|
+
filepath = options.output;
|
|
16353
|
+
} else {
|
|
16354
|
+
filepath = getFilenameFromPath(requestPath, contentType);
|
|
16355
|
+
}
|
|
16356
|
+
try {
|
|
16357
|
+
await saveFile(
|
|
16358
|
+
typeof saveData === "string" ? new TextEncoder().encode(saveData).buffer : saveData instanceof ArrayBuffer ? saveData : new TextEncoder().encode(JSON.stringify(saveData)).buffer,
|
|
16359
|
+
filepath
|
|
16360
|
+
);
|
|
16361
|
+
console.log(`Saved response to ${filepath}`);
|
|
16362
|
+
} catch (error) {
|
|
16363
|
+
console.error(`Error saving file: ${error.message}`);
|
|
16364
|
+
}
|
|
16365
|
+
}
|
|
16238
16366
|
function getBuildIterator(appPath, watch, external = []) {
|
|
16239
16367
|
let entry;
|
|
16240
16368
|
let resolvedAppPath;
|
|
@@ -16242,10 +16370,10 @@ function getBuildIterator(appPath, watch, external = []) {
|
|
|
16242
16370
|
entry = appPath;
|
|
16243
16371
|
resolvedAppPath = resolve2(process.cwd(), entry);
|
|
16244
16372
|
} else {
|
|
16245
|
-
entry = DEFAULT_ENTRY_CANDIDATES2.find((candidate) =>
|
|
16373
|
+
entry = DEFAULT_ENTRY_CANDIDATES2.find((candidate) => existsSync3(resolve2(process.cwd(), candidate))) ?? DEFAULT_ENTRY_CANDIDATES2[0];
|
|
16246
16374
|
resolvedAppPath = resolve2(process.cwd(), entry);
|
|
16247
16375
|
}
|
|
16248
|
-
if (!
|
|
16376
|
+
if (!existsSync3(resolvedAppPath)) {
|
|
16249
16377
|
throw new Error(`Entry file ${entry} does not exist`);
|
|
16250
16378
|
}
|
|
16251
16379
|
const appFilePath = realpathSync2(resolvedAppPath);
|
|
@@ -16279,13 +16407,39 @@ async function executeRequest(app, requestPath, options) {
|
|
|
16279
16407
|
response.headers.forEach((value, key) => {
|
|
16280
16408
|
responseHeaders[key] = value;
|
|
16281
16409
|
});
|
|
16282
|
-
const body = await response.text();
|
|
16410
|
+
const body = await response.clone().text();
|
|
16283
16411
|
return {
|
|
16284
16412
|
status: response.status,
|
|
16285
16413
|
body,
|
|
16286
|
-
headers: responseHeaders
|
|
16414
|
+
headers: responseHeaders,
|
|
16415
|
+
response
|
|
16287
16416
|
};
|
|
16288
16417
|
}
|
|
16418
|
+
var formatResponseBody = (responseBody, contentType, jsonOption) => {
|
|
16419
|
+
if (contentType && /^application\/(json|[^;\s]+\+json)($|;)/i.test(contentType)) {
|
|
16420
|
+
try {
|
|
16421
|
+
const parsedJSON = JSON.parse(responseBody);
|
|
16422
|
+
if (jsonOption) {
|
|
16423
|
+
return parsedJSON;
|
|
16424
|
+
}
|
|
16425
|
+
return JSON.stringify(parsedJSON, null, 2);
|
|
16426
|
+
} catch {
|
|
16427
|
+
console.error("Response indicated JSON content type but failed to parse JSON.");
|
|
16428
|
+
return responseBody;
|
|
16429
|
+
}
|
|
16430
|
+
}
|
|
16431
|
+
return responseBody;
|
|
16432
|
+
};
|
|
16433
|
+
var isBinaryResponse = (buffer) => {
|
|
16434
|
+
const view = new Uint8Array(buffer);
|
|
16435
|
+
const len = Math.min(view.length, 2e3);
|
|
16436
|
+
for (let i = 0; i < len; i++) {
|
|
16437
|
+
if (view[i] === 0) {
|
|
16438
|
+
return true;
|
|
16439
|
+
}
|
|
16440
|
+
}
|
|
16441
|
+
return false;
|
|
16442
|
+
};
|
|
16289
16443
|
|
|
16290
16444
|
// src/commands/search/index.ts
|
|
16291
16445
|
function searchCommand(program2) {
|
|
@@ -16411,7 +16565,7 @@ import { serve } from "@hono/node-server";
|
|
|
16411
16565
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
16412
16566
|
import { Hono } from "hono";
|
|
16413
16567
|
import { showRoutes } from "hono/dev";
|
|
16414
|
-
import { existsSync as
|
|
16568
|
+
import { existsSync as existsSync4, realpathSync as realpathSync3 } from "fs";
|
|
16415
16569
|
import { resolve as resolve3 } from "path";
|
|
16416
16570
|
|
|
16417
16571
|
// src/commands/serve/builtin-map.ts
|
|
@@ -16517,7 +16671,7 @@ function serveCommand(program2) {
|
|
|
16517
16671
|
app = new Hono();
|
|
16518
16672
|
} else {
|
|
16519
16673
|
const appPath = resolve3(process.cwd(), entry);
|
|
16520
|
-
if (!
|
|
16674
|
+
if (!existsSync4(appPath)) {
|
|
16521
16675
|
app = new Hono();
|
|
16522
16676
|
} else {
|
|
16523
16677
|
const appFilePath = realpathSync3(appPath);
|
|
@@ -16569,7 +16723,7 @@ function serveCommand(program2) {
|
|
|
16569
16723
|
|
|
16570
16724
|
// src/cli.ts
|
|
16571
16725
|
var __filename = fileURLToPath(import.meta.url);
|
|
16572
|
-
var __dirname =
|
|
16726
|
+
var __dirname = dirname3(__filename);
|
|
16573
16727
|
var packageJson = JSON.parse(readFileSync2(join2(__dirname, "../package.json"), "utf-8"));
|
|
16574
16728
|
var program = new Command();
|
|
16575
16729
|
program.name("hono").description("CLI for Hono").version(packageJson.version, "-v, --version", "display version number");
|