Skip to content

Commit 08a40ef

Browse files
joshi4ampcode-com
andauthored
refactor: migrate from nodes-sdk-alpha to raw fetch calls (#261)
Co-authored-by: Amp <amp@ampcode.com>
1 parent 66afae4 commit 08a40ef

4 files changed

Lines changed: 112 additions & 56 deletions

File tree

src/lib/contracts/ContractDisplay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export function ContractDisplay(props: { contract: Contract }) {
140140
{intervalData.map((data, index) => {
141141
return (
142142
<Box
143-
key={`${index}-${data.quantity}`}
143+
key={`${props.contract.id}-${data.start.toISOString()}`}
144144
paddingLeft={index === 0 ? 0 : COLUMN_WIDTH}
145145
>
146146
{index === 0 && (

src/lib/images/get.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function ImageDisplay({
2626
upload_status: string;
2727
sha256_hash: string | null;
2828
};
29-
download: { download_url: string; expires_at: number } | null;
29+
download: { url: string; expires_at: number } | null;
3030
}) {
3131
const expiresAt = download?.expires_at
3232
? new Date(download.expires_at * 1000)
@@ -51,8 +51,8 @@ function ImageDisplay({
5151
value={
5252
<Box flexDirection="column" paddingRight={1}>
5353
<Text color="cyan">Use curl or wget to download.</Text>
54-
<Link url={download.download_url} fallback={false}>
55-
{download.download_url}
54+
<Link url={download.url} fallback={false}>
55+
{download.url}
5656
</Link>
5757
</Box>
5858
}
@@ -116,11 +116,11 @@ const get = new Command("get")
116116
// Fetch download URL if image is completed
117117
let download = null;
118118
if (image.upload_status === "completed") {
119-
const { data: downloadData } = await client.GET(
120-
"/v2/images/{id}/download",
121-
{ params: { path: { id } } },
122-
);
123-
if (downloadData) {
119+
const { data: downloadData, response: downloadResponse } =
120+
await client.GET("/v2/images/{id}/download", {
121+
params: { path: { id } },
122+
});
123+
if (downloadResponse.ok && downloadData) {
124124
download = downloadData;
125125
}
126126
}

src/lib/nodes/image/show.tsx

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import console from "node:console";
22
import { Command } from "@commander-js/extra-typings";
3-
import type SFCNodes from "@sfcompute/nodes-sdk-alpha";
43
import chalk from "chalk";
54
import dayjs from "dayjs";
65
import advanced from "dayjs/plugin/advancedFormat";
76
import timezone from "dayjs/plugin/timezone";
87
import utc from "dayjs/plugin/utc";
98
import { Box, render, Text } from "ink";
109
import Link from "ink-link";
10+
import { apiClient } from "../../../apiClient.ts";
11+
import { logAndQuit } from "../../../helpers/errors.ts";
1112
import { formatDate } from "../../../helpers/format-time.ts";
12-
import { handleNodesError, nodesClient } from "../../../nodesClient.ts";
1313
import { Row } from "../../Row.tsx";
1414

1515
dayjs.extend(utc);
@@ -18,20 +18,25 @@ dayjs.extend(timezone);
1818

1919
export function ImageDisplay({
2020
image,
21+
download,
2122
}: {
22-
image: SFCNodes.VMs.ImageGetResponse;
23+
image: {
24+
name: string;
25+
id: string;
26+
upload_status: string;
27+
};
28+
download: { url: string; expires_at: number } | null;
2329
}) {
24-
const expiresAt = image.expires_at ? new Date(image.expires_at) : null;
30+
const expiresAt = download?.expires_at
31+
? new Date(download.expires_at * 1000)
32+
: null;
2533
const isExpired = expiresAt ? expiresAt < new Date() : false;
2634

27-
const statusColor = isExpired ? "red" : "green";
28-
const statusText = isExpired ? "Expired" : "Ready";
29-
3035
return (
3136
<Box flexDirection="column" padding={0} width={80}>
3237
<Box borderStyle="single" borderColor="cyan" paddingX={1}>
3338
<Text color="cyan" bold>
34-
Image: {image.name} ({image.image_id})
39+
Image: {image.name} ({image.id})
3540
</Text>
3641
</Box>
3742

@@ -40,62 +45,113 @@ export function ImageDisplay({
4045
head="Status: "
4146
value={
4247
<Box gap={1}>
43-
<Text color={statusColor}>{statusText}</Text>
48+
<Text color={formatStatusColor(image.upload_status)}>
49+
{formatStatusText(image.upload_status)}
50+
</Text>
4451
</Box>
4552
}
4653
/>
47-
<Row
48-
head="URL: "
49-
value={
50-
<Box flexDirection="column" paddingRight={1}>
51-
<Text color="cyan">Use curl or wget to download.</Text>
52-
<Link url={image.download_url} fallback={false}>
53-
{image.download_url}
54-
</Link>
55-
</Box>
56-
}
57-
/>
58-
{expiresAt && (
59-
<Row
60-
head="URL Expiry: "
61-
value={
62-
<Box gap={1}>
63-
<Text color={isExpired ? "red" : undefined}>
64-
{expiresAt.toISOString()}{" "}
65-
{chalk.blackBright(
66-
`(${formatDate(dayjs(expiresAt).toDate())} ${dayjs(
67-
expiresAt,
68-
).format("z")})`,
69-
)}
70-
</Text>
71-
{isExpired && <Text dimColor>(Expired)</Text>}
72-
</Box>
73-
}
74-
/>
54+
{download && (
55+
<>
56+
<Row
57+
head="URL: "
58+
value={
59+
<Box flexDirection="column" paddingRight={1}>
60+
<Text color="cyan">Use curl or wget to download.</Text>
61+
<Link url={download.url} fallback={false}>
62+
{download.url}
63+
</Link>
64+
</Box>
65+
}
66+
/>
67+
{expiresAt && (
68+
<Row
69+
head="URL Expiry: "
70+
value={
71+
<Box gap={1}>
72+
<Text color={isExpired ? "red" : undefined}>
73+
{expiresAt.toISOString()}{" "}
74+
{chalk.blackBright(
75+
`(${formatDate(dayjs(expiresAt).toDate())} ${dayjs(
76+
expiresAt,
77+
).format("z")})`,
78+
)}
79+
</Text>
80+
{isExpired && <Text dimColor>(Expired)</Text>}
81+
</Box>
82+
}
83+
/>
84+
)}
85+
</>
7586
)}
7687
</Box>
7788
</Box>
7889
);
7990
}
8091

92+
function formatStatusColor(status: string): string {
93+
switch (status) {
94+
case "started":
95+
return "green";
96+
case "uploading":
97+
return "yellow";
98+
case "completed":
99+
return "cyan";
100+
case "failed":
101+
return "red";
102+
default:
103+
return "gray";
104+
}
105+
}
106+
107+
function formatStatusText(status: string): string {
108+
switch (status) {
109+
case "started":
110+
return "Started";
111+
case "uploading":
112+
return "Uploading";
113+
case "completed":
114+
return "Completed";
115+
case "failed":
116+
return "Failed";
117+
default:
118+
return "Unknown";
119+
}
120+
}
121+
81122
const show = new Command("show")
82123
.description("Show VM image details and download URL")
83124
.argument("<image-id>", "ID of the image")
84125
.option("--json", "Output JSON")
85126
.action(async (imageId, opts) => {
86-
try {
87-
const client = await nodesClient();
88-
const data = await client.vms.images.get(imageId);
127+
const client = await apiClient();
89128

90-
if (opts.json) {
91-
console.log(JSON.stringify(data, null, 2));
92-
return;
129+
const { data: image, response } = await client.GET("/v2/images/{id}", {
130+
params: { path: { id: imageId } },
131+
});
132+
if (!response.ok || !image) {
133+
logAndQuit(
134+
`Failed to get image: ${response.status} ${response.statusText}`,
135+
);
136+
}
137+
138+
let download = null;
139+
if (image.upload_status === "completed") {
140+
const { data: downloadData, response: downloadResponse } =
141+
await client.GET("/v2/images/{id}/download", {
142+
params: { path: { id: imageId } },
143+
});
144+
if (downloadResponse.ok && downloadData) {
145+
download = downloadData;
93146
}
147+
}
94148

95-
render(<ImageDisplay image={data} />);
96-
} catch (err) {
97-
handleNodesError(err);
149+
if (opts.json) {
150+
console.log(JSON.stringify({ ...image, download }, null, 2));
151+
return;
98152
}
153+
154+
render(<ImageDisplay image={image} download={download} />);
99155
});
100156

101157
export default show;

src/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2204,7 +2204,7 @@ export interface components {
22042204
*/
22052205
vmorch_ImageDiscriminator: "image";
22062206
vmorch_ImageDownloadResponse: {
2207-
download_url: string;
2207+
url: string;
22082208
expires_at: components["schemas"]["vmorch_UnixEpoch"];
22092209
sha256_hash: string;
22102210
/** Format: u-int64 */

0 commit comments

Comments
 (0)