vercel
Version:
The command-line interface for Vercel
421 lines (419 loc) • 12.3 kB
JavaScript
import { createRequire as __createRequire } from 'node:module';
import { fileURLToPath as __fileURLToPath } from 'node:url';
import { dirname as __dirname_ } from 'node:path';
const require = __createRequire(import.meta.url);
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __dirname_(__filename);
import {
handleValidationError,
normalizeRepeatableStringFilters,
outputError,
validateAllProjectMutualExclusivity,
validateIntegerRangeWithDefault,
validateTimeBound,
validateTimeOrder
} from "./chunk-HTOH3MSD.js";
import {
getCommandFlags
} from "./chunk-EOZFDJSY.js";
import {
validateJsonOutput
} from "./chunk-XPKWKPWA.js";
import {
activityCommand
} from "./chunk-CQANJIEC.js";
import {
getScope
} from "./chunk-KWDV5FZH.js";
import {
getLinkedProject,
getProjectByNameOrId
} from "./chunk-X775BOSL.js";
import "./chunk-4OEA5ILS.js";
import "./chunk-ULXHXZCZ.js";
import "./chunk-CO5D46AG.js";
import "./chunk-N2T234LO.js";
import {
getFlagsSpecification,
parseArguments,
printError
} from "./chunk-4GQQJY5Y.js";
import {
ProjectNotFound,
getCommandName,
isAPIError
} from "./chunk-UGXBNJMO.js";
import "./chunk-P4QNYOFB.js";
import {
output_manager_default
} from "./chunk-ZQKJVHXY.js";
import {
require_source
} from "./chunk-S7KYDPEM.js";
import {
__toESM
} from "./chunk-TZ2YI2VH.js";
// src/commands/activity/list.ts
var import_chalk = __toESM(require_source(), 1);
function validateNext(next) {
if (next === void 0) {
return { valid: true, value: void 0 };
}
if (Number.isNaN(next)) {
return {
valid: false,
code: "INVALID_NEXT",
message: "Please provide a number for flag `--next`."
};
}
const date = new Date(next);
if (Number.isNaN(date.getTime())) {
return {
valid: false,
code: "INVALID_NEXT",
message: "Please provide a valid unix timestamp in milliseconds for `--next`."
};
}
return { valid: true, value: date };
}
function handleApiError(err, jsonOutput, client) {
if (err.status === 403) {
return outputError(
client,
jsonOutput,
"FORBIDDEN",
"You do not have permission to list activity events. Required permissions: Event: List or OwnEvent: List."
);
}
return outputError(
client,
jsonOutput,
err.code || "API_ERROR",
err.serverMessage || `API error (${err.status}).`
);
}
function formatActor(event) {
const principal = event.principal;
if (!principal) {
return event.principalId || "-";
}
if (principal.type === "system") {
return "system";
}
if (principal.username) {
return principal.username;
}
if (principal.name) {
return principal.name;
}
if (principal.slug) {
return principal.slug;
}
if (principal.email) {
return principal.email;
}
return event.principalId || "-";
}
function formatTimestamp(createdAt) {
if (!Number.isFinite(createdAt) || createdAt <= 0) {
return "-";
}
const date = new Date(createdAt);
if (Number.isNaN(date.getTime())) {
return "-";
}
return date.toISOString();
}
function formatEventText(text) {
return text.replace(/\s+/g, " ").trim();
}
function printExpandedEvents(events) {
const lines = [""];
events.forEach((event) => {
lines.push(`${import_chalk.default.gray("-")} ${formatEventText(event.text)}`);
lines.push(` ${import_chalk.default.cyan("Type".padEnd(14))}${event.type ?? "-"}`);
lines.push(` ${import_chalk.default.cyan("Actor".padEnd(14))}${formatActor(event)}`);
lines.push(
` ${import_chalk.default.cyan("Timestamp".padEnd(14))}${formatTimestamp(event.createdAt)}`
);
lines.push(` ${import_chalk.default.cyan("ID".padEnd(14))}${event.id}`);
lines.push("");
});
output_manager_default.print(`${lines.join("\n")}
`);
}
function trackTelemetry(flags, types, telemetry) {
telemetry.trackCliOptionType(types.length > 0 ? types : void 0);
telemetry.trackCliOptionSince(flags["--since"]);
telemetry.trackCliOptionUntil(flags["--until"]);
telemetry.trackCliOptionProject(flags["--project"]);
telemetry.trackCliFlagAll(flags["--all"]);
telemetry.trackCliOptionLimit(flags["--limit"]);
telemetry.trackCliOptionNext(flags["--next"]);
telemetry.trackCliOptionFormat(flags["--format"]);
}
function parseFlags(client) {
const flagsSpecification = getFlagsSpecification(activityCommand.options);
try {
const parsedArgs = parseArguments(client.argv.slice(2), flagsSpecification);
return parsedArgs.flags;
} catch (err) {
printError(err);
return 1;
}
}
function resolveValidatedInputs(flags, jsonOutput, client, normalizedTypes) {
const limitResult = validateIntegerRangeWithDefault(flags["--limit"], {
flag: "--limit",
min: 1,
max: 100,
defaultValue: 20
});
if (!limitResult.valid) {
return handleValidationError(limitResult, jsonOutput, client);
}
const mutualResult = validateAllProjectMutualExclusivity(
flags["--all"],
flags["--project"]
);
if (!mutualResult.valid) {
return handleValidationError(mutualResult, jsonOutput, client);
}
const sinceResult = validateTimeBound(flags["--since"]);
if (!sinceResult.valid) {
return handleValidationError(sinceResult, jsonOutput, client);
}
const nextResult = validateNext(flags["--next"]);
if (!nextResult.valid) {
return handleValidationError(nextResult, jsonOutput, client);
}
let until = nextResult.value;
if (!until) {
const untilResult = validateTimeBound(flags["--until"]);
if (!untilResult.valid) {
return handleValidationError(untilResult, jsonOutput, client);
}
until = untilResult.value;
}
const since = sinceResult.value;
const timeOrderResult = validateTimeOrder(since, until);
if (!timeOrderResult.valid) {
return handleValidationError(timeOrderResult, jsonOutput, client);
}
return {
limit: limitResult.value,
types: normalizedTypes,
since,
until
};
}
async function resolveScope(client, opts) {
if (opts.all || opts.project) {
const { team } = await getScope(client);
if (!team) {
return outputError(
client,
opts.jsonOutput,
"NO_TEAM",
"No team context found. Run `vercel switch` to select a team, or use `vercel link` in a project directory."
);
}
if (opts.all) {
return {
teamId: team.id,
teamSlug: team.slug
};
}
let projectResult;
try {
projectResult = await getProjectByNameOrId(
client,
opts.project,
team.id
);
} catch (err) {
if (isAPIError(err)) {
return outputError(
client,
opts.jsonOutput,
err.code || "API_ERROR",
err.serverMessage || (err.status === 403 ? `You do not have permission to access project "${opts.project}" in team "${team.slug}".` : `API error (${err.status}).`)
);
}
throw err;
}
if (projectResult instanceof ProjectNotFound) {
return outputError(
client,
opts.jsonOutput,
"PROJECT_NOT_FOUND",
`Project "${opts.project}" was not found in team "${team.slug}".`
);
}
return {
teamId: team.id,
teamSlug: team.slug,
projectIds: [projectResult.id],
projectName: projectResult.name
};
}
const linkedProject = await getLinkedProject(client);
if (linkedProject.status === "error") {
return linkedProject.exitCode;
}
if (linkedProject.status === "not_linked") {
return outputError(
client,
opts.jsonOutput,
"NOT_LINKED",
"No linked project found. Run `vercel link` to link a project, or use --project <name> or --all."
);
}
const isTeamProject = linkedProject.org.type === "team";
return {
projectIds: [linkedProject.project.id],
projectName: linkedProject.project.name,
teamId: isTeamProject ? linkedProject.org.id : void 0,
teamSlug: isTeamProject ? linkedProject.org.slug : void 0
};
}
function buildEventsQuery(params) {
const query = new URLSearchParams({
limit: String(params.limit + 1)
});
if (params.types.length > 0) {
query.set("types", params.types.join(","));
}
if (params.since) {
query.set("since", params.since.toISOString());
}
if (params.until) {
query.set("until", params.until.toISOString());
}
if (params.scope.projectIds && params.scope.projectIds.length > 0) {
query.set("projectIds", params.scope.projectIds.join(","));
}
if (params.scope.teamId) {
query.set("teamId", params.scope.teamId);
}
if (params.scope.teamSlug) {
query.set("slug", params.scope.teamSlug);
}
if (params.jsonOutput) {
query.set("withPayload", "true");
}
return query;
}
function paginateEvents(allEvents, limit) {
const events = allEvents.slice(0, limit);
const hasMore = allEvents.length > limit;
const lastVisibleEvent = events[events.length - 1];
const next = hasMore && typeof lastVisibleEvent?.createdAt === "number" ? lastVisibleEvent.createdAt - 1 : null;
return { events, next };
}
function printScopeHeader(scope) {
if (!scope.projectName && scope.teamSlug) {
output_manager_default.log(`Showing all activity for team ${import_chalk.default.bold(scope.teamSlug)}`);
} else if (scope.projectName && scope.teamSlug) {
output_manager_default.log(
`Showing activity for project ${import_chalk.default.bold(scope.projectName)} in team ${import_chalk.default.bold(scope.teamSlug)}`
);
} else if (scope.projectName) {
output_manager_default.log(`Showing activity for project ${import_chalk.default.bold(scope.projectName)}`);
}
}
function printNextPageHint(flags, next) {
const commandFlags = getCommandFlags(flags, ["--next"]);
output_manager_default.log(
`To display the next page, run ${getCommandName(
`activity${commandFlags} --next ${next}`
)}`
);
}
async function list(client, telemetry) {
const flags = parseFlags(client);
if (typeof flags === "number") {
return flags;
}
const formatResult = validateJsonOutput(flags);
if (!formatResult.valid) {
output_manager_default.error(formatResult.error);
return 1;
}
const jsonOutput = formatResult.jsonOutput;
const normalizedTypes = normalizeRepeatableStringFilters(flags["--type"]);
trackTelemetry(flags, normalizedTypes, telemetry);
const validatedInputs = resolveValidatedInputs(
flags,
jsonOutput,
client,
normalizedTypes
);
if (typeof validatedInputs === "number") {
return validatedInputs;
}
const scope = await resolveScope(client, {
project: flags["--project"],
all: flags["--all"],
jsonOutput
});
if (typeof scope === "number") {
return scope;
}
const query = buildEventsQuery({
limit: validatedInputs.limit,
types: validatedInputs.types,
since: validatedInputs.since,
until: validatedInputs.until,
scope,
jsonOutput
});
output_manager_default.spinner("Fetching activity...");
try {
const response = await client.fetch(
`/v3/events?${query.toString()}`,
{
useCurrentTeam: false
}
);
const allEvents = Array.isArray(response.events) ? response.events : [];
const { events, next } = paginateEvents(allEvents, validatedInputs.limit);
if (jsonOutput) {
const hasScope = scope.teamSlug || scope.projectName;
const jsonResponse = {
...hasScope && {
scope: {
...scope.teamSlug && { teamSlug: scope.teamSlug },
...scope.projectName && { projectName: scope.projectName },
...scope.projectIds && { projectIds: scope.projectIds }
}
},
events,
pagination: { next }
};
client.stdout.write(`${JSON.stringify(jsonResponse, null, 2)}
`);
return 0;
}
printScopeHeader(scope);
if (events.length === 0) {
output_manager_default.log("No activity events found.");
return 0;
}
printExpandedEvents(events);
if (next !== null) {
printNextPageHint(flags, next);
}
return 0;
} catch (err) {
if (isAPIError(err)) {
return handleApiError(err, jsonOutput, client);
}
throw err;
} finally {
output_manager_default.stopSpinner();
}
}
export {
list as default
};