Skip to content

Commit

Permalink
fix: fully type safe network requests
Browse files Browse the repository at this point in the history
This should hopefully fix the undefined error
  • Loading branch information
aarondill committed Feb 9, 2024
1 parent 760bbd6 commit a98a8bf
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 136 deletions.
3 changes: 3 additions & 0 deletions src/commands/Deployments/openDeploymentsLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export class OpenDeploymentsLink implements Command {
constructor(private readonly vercel: VercelManager) {}
async execute() {
const projectInfo = await this.vercel.project.getInfo();
if (!projectInfo) return;
const user = await this.vercel.user.getInfo();
if (!user)
return void vscode.window.showErrorMessage("Could not get user info!");
const url = `https://vercel.com/${user.username}/${projectInfo.name}`;
await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(url));
}
Expand Down
22 changes: 7 additions & 15 deletions src/commands/Environment/createEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Blob } from "node-fetch";
import { window } from "vscode";
import type { Command } from "../../CommandManager";
import type { VercelManager } from "../../features/VercelManager";
import { vercelTargets } from "../../features/models";

export class CreateEnvironment implements Command {
public readonly id = "vercel.createEnvironment";
Expand Down Expand Up @@ -51,19 +52,11 @@ export class CreateEnvironment implements Command {
if (value === undefined) return;

//> Get targets from user
const options = [
{
label: "Development",
alwaysShow: true,
picked: true,
},
{ label: "Preview", alwaysShow: true, picked: true },
{
label: "Production",
alwaysShow: true,
picked: true,
},
];
const options = vercelTargets.map(t => ({
label: t,
alwaysShow: true,
picked: true,
}));

/** User's choice of targets as a list of options*/
const targetsChoices = await window.showQuickPick(options, {
Expand All @@ -72,8 +65,7 @@ export class CreateEnvironment implements Command {
title: `Creating ${key}`,
});
if (!targetsChoices || targetsChoices.length === 0) return;
const targets = targetsChoices.map(x => x.label.toLowerCase());

const targets = targetsChoices.map(x => x.label);
await this.vercel.env.create(key, value, targets);
}
}
3 changes: 3 additions & 0 deletions src/commands/Environment/openEnvironmentLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export class OpenEnvironmentLink implements Command {
constructor(private readonly vercel: VercelManager) {}
async execute() {
const projectInfo = await this.vercel.project.getInfo();
if (!projectInfo) return;
const user = await this.vercel.user.getInfo();
if (!user)
return void vscode.window.showErrorMessage("Could not get user info!");
const url = `https://vercel.com/${user.username}/${projectInfo.name}/settings/environment-variables`;
await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(url));
}
Expand Down
53 changes: 19 additions & 34 deletions src/commands/Environment/setEnvironment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { window } from "vscode";
import type { Command } from "../../CommandManager";
import type { VercelEnvironmentInformation } from "../../features/models";
import {
vercelTargets,
type VercelEnvironmentInformation,
} from "../../features/models";
import type { VercelManager } from "../../features/VercelManager";

export class SetEnvironment implements Command {
Expand Down Expand Up @@ -43,9 +46,9 @@ export class SetEnvironment implements Command {
if (!id || !key) return;

//> Find variable being changed
const env = envList.find(
env => env.id === id
) as VercelEnvironmentInformation;
const env = envList.find(env => env.id === id);
if (!env)
return void window.showErrorMessage("Could not find environment!");

//> get user input for value(placeholder = original value)
const currValue = env.value;
Expand All @@ -61,51 +64,33 @@ export class SetEnvironment implements Command {

//> Get user options of targets to apply to
/** list of initial targets */
const initialTargets: string[] =
typeof env.target === "string" ? [env.target] : env.target!;
const initialTargets =
typeof env.target === "string" ? [env.target] : env.target ?? [];

let targets: string[] | undefined;
let targets = initialTargets;
/** Check if Arguments say only to edit values */
if (!command?.editing || command.editing === "TARGETS") {
/** Function to check if the original contained the target */
const getPicked = (target: string) => initialTargets?.includes(target);

/** List of options available for user choice */
const options = [
{
label: "Development",
alwaysShow: true,
picked: getPicked("development"),
},
{ label: "Preview", alwaysShow: true, picked: getPicked("preview") },
{
label: "Production",
alwaysShow: true,
picked: getPicked("production"),
},
];
const options = vercelTargets.map(l => ({
label: l,
alwaysShow: true,
picked: initialTargets.includes(l),
}));

/** User's choice of targets as a list of options*/
const chosen = await window.showQuickPick(options, {
canPickMany: true,
placeHolder: "Select environments to apply to (None or esc to cancel)",
placeHolder: "Select environments to apply to (esc to cancel)",
title: `Editing ${key}`,
});
if (!chosen) return;
/** List of choices as strings */
targets = chosen?.map(t => t.label);
} else {
/** Editing Values Through Arguments */
targets = initialTargets;
}
//> Return if canceled
if (targets === undefined || targets === null || targets.length === 0)
return;
if (targets.length === 0) return;

//> edit the env by **ID**, new value and targets
await this.vercel.env.edit(
id,
newValue,
targets.map(t => t.toLowerCase())
);
await this.vercel.env.edit(id, newValue, targets);
}
}
62 changes: 28 additions & 34 deletions src/features/VercelManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/naming-convention */
// 👆 because vercel API requires snake_case keys
import { workspace } from "vscode";
import { window, workspace } from "vscode";
import { Api } from "../utils/Api";
import type { TokenManager } from "./TokenManager";
import type {
Deployment,
VercelEnvironmentInformation,
VercelResponse,
VercelTargets,
} from "./models";
import { getTokenOauth } from "../utils/oauth";

Expand Down Expand Up @@ -84,13 +85,14 @@ export class VercelManager {
project = {
getInfo: async (refresh: boolean = false) => {
if (this.projectInfo !== null && !refresh) return this.projectInfo;
const selectedProject = this.selectedProject;
if (!selectedProject)
return void window.showErrorMessage("No project selected!");
const result = await Api.projectInfo(
{
projectId: this.selectedProject,
},
{ projectId: selectedProject },
await this.authHeader()
);
if (result.ok) return;
if (!result.ok) return;
return (this.projectInfo = result);
},
};
Expand Down Expand Up @@ -126,22 +128,15 @@ export class VercelManager {
*
* @param key Name of var to create
* @param value Value to store in variable
* @param {("development" | "preview" | "production")[]} targets Deployment targets to set to
* @param target Deployment targets to set to
*/
create: async (key: string, value: string, targets: string[]) => {
create: async (key: string, value: string, target: VercelTargets[]) => {
const projectId = this.selectedProject;
if (!projectId)
return void window.showErrorMessage("No project selected!");
await Api.environment.create(
{
projectId: this.selectedProject,
},
{
headers: (await this.authHeader()).headers,
body: JSON.stringify({
key,
value,
target: targets,
type: "encrypted",
}),
}
{ projectId, body: { key, value, target, type: "encrypted" } },
await this.authHeader()
);
this.onDidEnvironmentsUpdated();
},
Expand All @@ -151,34 +146,33 @@ export class VercelManager {
* @param id A string corresponding to the Vercel ID of the env variable
*/
remove: async (id: string) => {
await Api.environment.remove(
{
projectId: this.selectedProject,
id,
},
await this.authHeader()
);
const projectId = this.selectedProject;
if (!projectId)
return void window.showErrorMessage("No project selected!");
await Api.environment.remove({ projectId, id }, await this.authHeader());
this.onDidEnvironmentsUpdated();
},
/**
*
* @param id A string corresponding the ID of the Environment Variable
* @param value The value to set the Variable to
* @param {("development" | "preview" | "production")[]} targets Deployment targets to set to
* @param targets Deployment targets to set to
*/
edit: async (id: string, value: string, targets: string[]) => {
edit: async (id: string, value: string, targets: VercelTargets[]) => {
const selectedProject = this.selectedProject;
if (!selectedProject)
return void window.showErrorMessage("No project selected!");
await Api.environment.edit(
{
projectId: this.selectedProject,
projectId: selectedProject,
id,
body: {
value,
target: targets,
},
},
{
headers: (await this.authHeader()).headers,

body: JSON.stringify({
value,
target: targets,
}),
}
);
this.onDidEnvironmentsUpdated();
Expand Down
7 changes: 3 additions & 4 deletions src/features/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,11 @@ type Pagination = {
next: number; //Timestamp that must be used to request the next page.
prev: number; //Timestamp that must be used to request the previous page.
};
type targets =
| ("production" | "preview" | "development" | "preview" | "development")[]
| ("production" | "preview" | "development" | "preview" | "development");
export const vercelTargets = ["production", "preview", "development"] as const;
export type VercelTargets = (typeof vercelTargets)[number];

export type VercelEnvironmentInformation = {
target?: targets;
target?: VercelTargets | VercelTargets[];
type?: "secret" | "system" | "encrypted" | "plain";
id?: string;
key?: string;
Expand Down
Loading

0 comments on commit a98a8bf

Please sign in to comment.