Skip to content

Commit cef0ce0

Browse files
several updates
1 parent edfad0b commit cef0ce0

File tree

15 files changed

+266
-255
lines changed

15 files changed

+266
-255
lines changed

src/PreviewTokens.ts renamed to src/Hosts.ts

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,69 @@ import {
88
previewTokenUpdate,
99
} from "./api-clients/client";
1010

11-
interface BasePreviewTokenInfo {
11+
interface BaseHostTokenInfo {
1212
expiresAt: Date | null;
1313
tokenId: string;
1414
lastUsedAt: Date | null;
1515
}
1616

17-
export interface PreviewTokenInfo extends BasePreviewTokenInfo {
17+
export interface HostTokenInfo extends BaseHostTokenInfo {
1818
tokenPrefix: string;
1919
}
2020

21-
export interface PreviewToken extends BasePreviewTokenInfo {
21+
export interface HostToken extends BaseHostTokenInfo {
2222
token: string;
2323
sandboxId: string;
2424
}
2525

2626
/**
27-
* Provider for generating preview tokens that can be used to access
28-
* private sandbox previews. This provider is only available in environments
27+
* Provider for generating host tokens that can be used to access
28+
* private sandbox hosts. This provider is only available in environments
2929
* with an authenticated API client (like Node.js).
3030
*/
31-
export class PreviewTokens extends Disposable {
31+
export class HostTokens extends Disposable {
3232
constructor(private apiClient: Client) {
3333
super();
3434
}
3535

3636
/**
37-
* Get a signed preview URL for a port using a preview token.
37+
* Get url to access a private host using a host token.
38+
* The PORT argument is needed as all hosts are exposed with
39+
* a port.
3840
*/
39-
getSignedPreviewUrl(
41+
getUrl(
4042
token: { sandboxId: string; token: string },
41-
port: number
43+
port: number,
44+
protocol: string = "https"
4245
): string {
43-
return `https://${token.sandboxId}-${port}.csb.app?preview_token=${token.token}`;
46+
return `${protocol}://${token.sandboxId}-${port}.csb.app?preview_token=${token.token}`;
4447
}
4548

4649
/**
47-
* Generate a new preview token that can be used to access private sandbox previews. By default the token never expires.
50+
* Get headers to access a private host using a host token.
4851
*/
49-
async create(
52+
getHeaders(token: { sandboxId: string; token: string }) {
53+
return {
54+
"csb-preview-token": token.token,
55+
};
56+
}
57+
58+
/**
59+
* Get cookies to access a private host using a host token.
60+
*/
61+
getCookies(token: { sandboxId: string; token: string }) {
62+
return {
63+
csb_preview_token: token.token,
64+
};
65+
}
66+
67+
/**
68+
* Generate a new host token that can be used to access private sandbox hosts. By default the token never expires.
69+
*/
70+
async createToken(
5071
sandboxId: string,
5172
opts: { expiresAt?: Date } = {}
52-
): Promise<PreviewToken> {
73+
): Promise<HostToken> {
5374
const response = handleResponse(
5475
await previewTokenCreate({
5576
client: this.apiClient,
@@ -81,17 +102,17 @@ export class PreviewTokens extends Disposable {
81102
}
82103

83104
/**
84-
* List all active preview tokens for this sandbox.
105+
* List all active host tokens for this sandbox.
85106
*/
86-
async list(sandboxId: string): Promise<PreviewTokenInfo[]> {
107+
async listTokens(sandboxId: string): Promise<HostTokenInfo[]> {
87108
const response = handleResponse(
88109
await previewTokenList({
89110
client: this.apiClient,
90111
path: {
91112
id: sandboxId,
92113
},
93114
}),
94-
"Failed to list preview tokens"
115+
"Failed to list host tokens"
95116
);
96117

97118
if (!response.tokens) {
@@ -107,9 +128,9 @@ export class PreviewTokens extends Disposable {
107128
}
108129

109130
/**
110-
* Revoke a single preview token for this sandbox.
131+
* Revoke a single host token for this sandbox.
111132
*/
112-
async revoke(sandboxId: string, tokenId: string): Promise<void> {
133+
async revokeToken(sandboxId: string, tokenId: string): Promise<void> {
113134
handleResponse(
114135
await previewTokenUpdate({
115136
client: this.apiClient,
@@ -121,35 +142,35 @@ export class PreviewTokens extends Disposable {
121142
expires_at: new Date().toISOString(),
122143
},
123144
}),
124-
"Failed to revoke preview token"
145+
"Failed to revoke host token"
125146
);
126147
}
127148

128149
/**
129-
* Revoke all active preview tokens for this sandbox.
150+
* Revoke all active host tokens for this sandbox.
130151
* This will immediately invalidate all tokens, and they can no longer be used
131-
* to access the sandbox preview.
152+
* to access the sandbox host.
132153
*/
133-
async revokeAll(sandboxId: string): Promise<void> {
154+
async revokeAllTokens(sandboxId: string): Promise<void> {
134155
handleResponse(
135156
await previewTokenRevokeAll({
136157
client: this.apiClient,
137158
path: {
138159
id: sandboxId,
139160
},
140161
}),
141-
"Failed to revoke preview tokens"
162+
"Failed to revoke host tokens"
142163
);
143164
}
144165

145166
/**
146-
* Update a preview token's expiration date.
167+
* Update a host token's expiration date.
147168
*/
148-
async update(
169+
async updateToken(
149170
sandboxId: string,
150171
tokenId: string,
151172
expiresAt: Date | null
152-
): Promise<PreviewTokenInfo> {
173+
): Promise<HostTokenInfo> {
153174
const response = handleResponse(
154175
await previewTokenUpdate({
155176
client: this.apiClient,
@@ -161,7 +182,7 @@ export class PreviewTokens extends Disposable {
161182
expires_at: expiresAt?.toISOString(),
162183
},
163184
}),
164-
"Failed to update preview token"
185+
"Failed to update host token"
165186
);
166187

167188
if (!response.token) {

src/bin/commands/host-tokens.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import type { CommandModule } from "yargs";
2+
import {
3+
listPreviewTokens,
4+
createPreviewToken,
5+
revokeAllPreviewTokens,
6+
revokePreviewToken,
7+
updatePreviewToken,
8+
} from "./sandbox/host-tokens";
9+
10+
export const hostTokensCommand: CommandModule = {
11+
command: "host-tokens",
12+
describe: "Manage host tokens",
13+
builder: (yargs) => {
14+
return yargs
15+
.command({
16+
command: "list <sandbox-id>",
17+
describe: "List host tokens for a sandbox",
18+
builder: (yargs) => {
19+
return yargs.positional("sandbox-id", {
20+
describe: "ID of the sandbox",
21+
type: "string",
22+
demandOption: true,
23+
});
24+
},
25+
handler: async (argv) => {
26+
await listPreviewTokens(argv.sandboxId as string);
27+
},
28+
})
29+
.command({
30+
command: "create <sandbox-id>",
31+
describe: "Create a host token for a sandbox",
32+
builder: (yargs) => {
33+
return yargs
34+
.positional("sandbox-id", {
35+
describe: "ID of the sandbox",
36+
type: "string",
37+
demandOption: true,
38+
})
39+
.option("expires-at", {
40+
alias: "e",
41+
describe:
42+
"Expiration date (ISO 8601 format, e.g. 2024-12-31T23:59:59Z). Can be omitted to create a token that never expires.",
43+
type: "string",
44+
});
45+
},
46+
handler: async (argv) => {
47+
await createPreviewToken(
48+
argv.sandboxId as string,
49+
argv["expires-at"] as string | undefined
50+
);
51+
},
52+
})
53+
.command({
54+
command: "update <sandbox-id> <host-token-id>",
55+
describe: "Update the expiration date of a host token",
56+
builder: (yargs) => {
57+
return yargs
58+
.positional("sandbox-id", {
59+
describe: "ID of the sandbox",
60+
type: "string",
61+
demandOption: true,
62+
})
63+
.positional("host-token-id", {
64+
describe: "ID of the host token",
65+
type: "string",
66+
demandOption: true,
67+
})
68+
.option("expires-at", {
69+
alias: "e",
70+
describe:
71+
"Expiration date (ISO 8601 format, e.g. 2024-12-31T23:59:59Z). Can be omitted to remove the expiration date.",
72+
type: "string",
73+
});
74+
},
75+
handler: async (argv) => {
76+
await updatePreviewToken(
77+
argv["sandbox-id"] as string,
78+
argv["host-token-id"] as string,
79+
argv["expires-at"] as string | undefined
80+
);
81+
},
82+
})
83+
.command({
84+
command: "revoke <sandbox-id> [host-token-id]",
85+
describe: "Revoke host token(s)",
86+
builder: (yargs) => {
87+
return yargs
88+
.positional("sandbox-id", {
89+
describe: "ID of the sandbox",
90+
type: "string",
91+
demandOption: true,
92+
})
93+
.positional("host-token-id", {
94+
describe: "ID of the host token",
95+
type: "string",
96+
})
97+
.option("all", {
98+
alias: "a",
99+
describe: "Revoke all preview tokens",
100+
type: "boolean",
101+
conflicts: "host-token-id",
102+
});
103+
},
104+
handler: async (argv) => {
105+
if (argv.all) {
106+
await revokeAllPreviewTokens(argv["sandbox-id"] as string);
107+
} else if (argv["host-token-id"]) {
108+
await revokePreviewToken(
109+
argv["sandbox-id"] as string,
110+
argv["host-token-id"] as string
111+
);
112+
} else {
113+
console.error(
114+
"Error: Either specify a host token ID or use --all to revoke all tokens"
115+
);
116+
process.exit(1);
117+
}
118+
},
119+
});
120+
},
121+
handler: () => {},
122+
};

src/bin/commands/previewHosts.ts

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,6 @@ export type PreviewHostsCommandArgs = {
1919
clear?: boolean;
2020
};
2121

22-
function createSpinnerFactory() {
23-
let currentLineIndex = 0;
24-
let currentSpinnerIndex = 0;
25-
26-
return () => {
27-
const spinner = ora({ stream: process.stdout });
28-
const spinnerIndex = currentSpinnerIndex++;
29-
let lastMethod: string;
30-
31-
function updateCursor(method: string) {
32-
readline.moveCursor(
33-
process.stdout,
34-
0,
35-
spinnerIndex - currentLineIndex + (lastMethod !== "start" ? -1 : 0)
36-
);
37-
currentLineIndex = spinnerIndex;
38-
lastMethod = method;
39-
}
40-
41-
return {
42-
start(message: string) {
43-
updateCursor("start");
44-
spinner.start(message);
45-
},
46-
succeed(message: string) {
47-
updateCursor("succeed");
48-
spinner.succeed(message);
49-
},
50-
fail(message: string) {
51-
updateCursor("fail");
52-
spinner.fail(message);
53-
},
54-
info(message: string) {
55-
updateCursor("info");
56-
spinner.info(message);
57-
},
58-
};
59-
};
60-
}
61-
6222
export const previewHostsCommand: yargs.CommandModule<
6323
Record<string, never>,
6424
PreviewHostsCommandArgs

0 commit comments

Comments
 (0)