add docs for bun publish (#14327)

This commit is contained in:
Dylan Conway
2024-10-03 03:41:11 -07:00
committed by GitHub
parent eda608d629
commit 39b1c0111e
12 changed files with 341 additions and 91 deletions

View File

@@ -1996,7 +1996,7 @@ pub const Example = struct {
var is_expected_content_type = false;
var content_type: string = "";
for (response.headers) |header| {
for (response.headers.list) |header| {
if (strings.eqlCaseInsensitiveASCII(header.name, "content-type", true)) {
content_type = header.value;

View File

@@ -561,14 +561,7 @@ pub const PublishCommand = struct {
const prompt_for_otp = prompt_for_otp: {
if (res.status_code != 401) break :prompt_for_otp false;
if (authenticate: {
for (res.headers) |header| {
if (strings.eqlCaseInsensitiveASCII(header.name, "www-authenticate", true)) {
break :authenticate header.value;
}
}
break :authenticate null;
}) |@"www-authenticate"| {
if (res.headers.get("www-authenticate")) |@"www-authenticate"| {
var iter = strings.split(@"www-authenticate", ",");
while (iter.next()) |part| {
const trimmed = strings.trim(part, &strings.whitespace_chars);
@@ -583,7 +576,7 @@ pub const PublishCommand = struct {
Output.errGeneric("unable to authenticate, need: {s}", .{@"www-authenticate"});
Global.crash();
} else if (strings.containsComptime(response_buf.list.items, "one-time pass")) {
// missing www-authenticate header but one-time pass is still included
// missing www-authenicate header but one-time pass is still included
break :prompt_for_otp true;
}
@@ -592,7 +585,14 @@ pub const PublishCommand = struct {
if (!prompt_for_otp) {
// general error
return handleResponseErrors(directory_publish, ctx, &req, &res, &response_buf, true);
const otp_response = false;
return handleResponseErrors(directory_publish, ctx, &req, &res, &response_buf, otp_response);
}
if (res.headers.get("npm-notice")) |notice| {
Output.printError("\n", .{});
Output.note("{s}", .{notice});
Output.flush();
}
const otp = try getOTP(directory_publish, ctx, registry, &response_buf, &print_buf);
@@ -634,9 +634,16 @@ pub const PublishCommand = struct {
switch (otp_res.status_code) {
400...std.math.maxInt(@TypeOf(otp_res.status_code)) => {
return handleResponseErrors(directory_publish, ctx, &otp_req, &otp_res, &response_buf, true);
const otp_response = true;
return handleResponseErrors(directory_publish, ctx, &otp_req, &otp_res, &response_buf, otp_response);
},
else => {
if (otp_res.headers.get("npm-notice")) |notice| {
Output.printError("\n", .{});
Output.note("{s}", .{notice});
Output.flush();
}
},
else => {},
}
},
else => {},
@@ -649,7 +656,7 @@ pub const PublishCommand = struct {
req: *const http.AsyncHTTP,
res: *const bun.picohttp.Response,
response_body: *MutableString,
comptime check_for_success: bool,
comptime otp_response: bool,
) OOM!void {
const message = message: {
const source = logger.Source.initPathString("???", response_body.list.items);
@@ -660,29 +667,40 @@ pub const PublishCommand = struct {
}
};
if (comptime check_for_success) {
if (json.get("success")) |success_expr| {
if (success_expr.asBool()) |successful| {
if (successful) {
// possible to hit this with otp responses
return;
}
}
}
}
// I don't think we should make this check, I cannot find code in npm
// that does this
// if (comptime otp_response) {
// if (json.get("success")) |success_expr| {
// if (success_expr.asBool()) |successful| {
// if (successful) {
// // possible to hit this with otp responses
// return;
// }
// }
// }
// }
const @"error", _ = try json.getString(ctx.allocator, "error") orelse break :message null;
break :message @"error";
};
Output.prettyErrorln("\n<red>{d}<r>{s}{s}: {s}\n{s}{s}", .{
Output.prettyErrorln("\n<red>{d}<r>{s}{s}: {s}\n", .{
res.status_code,
if (res.status.len > 0) " " else "",
res.status,
bun.fmt.redactedNpmUrl(req.url.href),
if (message != null) "\n - " else "",
message orelse "",
});
if (message) |msg| {
if (comptime otp_response) {
if (res.status_code == 401 and strings.containsComptime(msg, "You must provide a one-time pass. Upgrade your client to npm@latest in order to use 2FA.")) {
Output.prettyErrorln("\n - Received invalid OTP", .{});
Global.crash();
}
}
Output.prettyErrorln("\n - {s}", .{msg});
}
Global.crash();
}
@@ -810,12 +828,10 @@ pub const PublishCommand = struct {
202 => {
// retry
const nanoseconds = nanoseconds: {
default: for (res.headers) |header| {
if (strings.eqlCaseInsensitiveASCII(header.name, "retry-after", true)) {
const trimmed = strings.trim(header.value, &strings.whitespace_chars);
const seconds = bun.fmt.parseInt(u32, trimmed, 10) catch break :default;
break :nanoseconds seconds * std.time.ns_per_s;
}
if (res.headers.get("retry-after")) |retry| default: {
const trimmed = strings.trim(retry, &strings.whitespace_chars);
const seconds = bun.fmt.parseInt(u32, trimmed, 10) catch break :default;
break :nanoseconds seconds * std.time.ns_per_s;
}
break :nanoseconds 500 * std.time.ns_per_ms;
@@ -837,13 +853,22 @@ pub const PublishCommand = struct {
}
};
return try otp_done_json.getStringCloned(ctx.allocator, "token") orelse {
const token = try otp_done_json.getStringCloned(ctx.allocator, "token") orelse {
Output.err("WebLogin", "missing `token` field in reponse json", .{});
Global.crash();
};
if (res.headers.get("npm-notice")) |notice| {
Output.printError("\n", .{});
Output.note("{s}", .{notice});
Output.flush();
}
return token;
},
else => {
try handleResponseErrors(directory_publish, ctx, &req, &res, response_buf, false);
const otp_response = false;
try handleResponseErrors(directory_publish, ctx, &req, &res, response_buf, otp_response);
},
}
}