@project-ajax/sdk 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/api/client.d.ts +2 -2
- package/dist/cli/api/client.d.ts.map +1 -1
- package/dist/cli/commands/auth.impl.d.ts.map +1 -1
- package/dist/cli/commands/auth.impl.js +13 -9
- package/dist/cli/commands/bundle.impl.js +2 -2
- package/dist/cli/commands/capabilities.impl.js +4 -4
- package/dist/cli/commands/connect.impl.js +13 -13
- package/dist/cli/commands/deploy.impl.d.ts.map +1 -1
- package/dist/cli/commands/deploy.impl.js +10 -16
- package/dist/cli/commands/env.impl.d.ts.map +1 -1
- package/dist/cli/commands/env.impl.js +7 -10
- package/dist/cli/commands/exec.impl.d.ts.map +1 -1
- package/dist/cli/commands/exec.impl.js +14 -16
- package/dist/cli/commands/runs.impl.js +7 -7
- package/dist/cli/commands/secrets.impl.js +12 -12
- package/dist/cli/commands/utils/testing.d.ts +2 -11
- package/dist/cli/commands/utils/testing.d.ts.map +1 -1
- package/dist/cli/commands/utils/testing.js +4 -4
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +3 -6
- package/dist/cli/context.d.ts +2 -2
- package/dist/cli/context.d.ts.map +1 -1
- package/dist/cli/context.js +3 -3
- package/dist/cli/deploy.js +11 -11
- package/dist/cli/handler.js +2 -2
- package/dist/cli/{writer.d.ts → io.d.ts} +10 -3
- package/dist/cli/io.d.ts.map +1 -0
- package/dist/cli/{writer.js → io.js} +24 -2
- package/package.json +3 -3
- package/src/cli/api/client.ts +3 -3
- package/src/cli/commands/auth.impl.test.ts +4 -2
- package/src/cli/commands/auth.impl.ts +17 -9
- package/src/cli/commands/bundle.impl.ts +2 -2
- package/src/cli/commands/capabilities.impl.ts +4 -4
- package/src/cli/commands/connect.impl.ts +13 -13
- package/src/cli/commands/deploy.impl.test.ts +9 -14
- package/src/cli/commands/deploy.impl.ts +11 -16
- package/src/cli/commands/env.impl.ts +7 -11
- package/src/cli/commands/exec.impl.ts +14 -16
- package/src/cli/commands/runs.impl.ts +7 -7
- package/src/cli/commands/secrets.impl.ts +12 -12
- package/src/cli/commands/utils/testing.ts +5 -4
- package/src/cli/config.ts +2 -5
- package/src/cli/context.ts +3 -3
- package/src/cli/deploy.ts +11 -11
- package/src/cli/handler.ts +2 -2
- package/src/cli/{writer.ts → io.ts} +34 -2
- package/dist/cli/writer.d.ts.map +0 -1
package/dist/cli/deploy.js
CHANGED
|
@@ -6,13 +6,13 @@ import { Result } from "./api/result.js";
|
|
|
6
6
|
async function deployWorker(context, options) {
|
|
7
7
|
const { workerPath } = options;
|
|
8
8
|
const absPath = path.resolve(process.cwd(), workerPath);
|
|
9
|
-
context.
|
|
9
|
+
context.io.debug(`Deploying worker from: ${absPath}`);
|
|
10
10
|
const client = context.apiClient;
|
|
11
11
|
let uploadUrl;
|
|
12
12
|
let uploadFields;
|
|
13
13
|
let workerId;
|
|
14
14
|
if ("workerId" in options) {
|
|
15
|
-
context.
|
|
15
|
+
context.io.writeErr(`Updating worker...`);
|
|
16
16
|
workerId = options.workerId;
|
|
17
17
|
const updateResult = await client.updateWorkerBundle(workerId);
|
|
18
18
|
if (Result.isSuccess(updateResult)) {
|
|
@@ -20,13 +20,13 @@ async function deployWorker(context, options) {
|
|
|
20
20
|
uploadUrl = res.url;
|
|
21
21
|
uploadFields = res.fields;
|
|
22
22
|
} else {
|
|
23
|
-
context.
|
|
23
|
+
context.io.writeErr(
|
|
24
24
|
"Failed to generate pre-signed upload URL for worker bundle:"
|
|
25
25
|
);
|
|
26
26
|
throw new Error(updateResult.error.message);
|
|
27
27
|
}
|
|
28
28
|
} else {
|
|
29
|
-
context.
|
|
29
|
+
context.io.writeErr(`Creating worker...`);
|
|
30
30
|
const createResult = await client.createWorker(options.name);
|
|
31
31
|
if (Result.isSuccess(createResult)) {
|
|
32
32
|
const res = Result.unwrap(createResult);
|
|
@@ -38,14 +38,14 @@ async function deployWorker(context, options) {
|
|
|
38
38
|
throw new Error(createResult.error.message);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
context.
|
|
42
|
-
context.
|
|
41
|
+
context.io.debug(`Generated upload URL: ${uploadUrl}`);
|
|
42
|
+
context.io.writeErr("Building worker bundle...");
|
|
43
43
|
const archivePath = await buildWorkerBundle(context, absPath);
|
|
44
|
-
context.
|
|
45
|
-
context.
|
|
44
|
+
context.io.debug(`Created bundle at: ${archivePath}`);
|
|
45
|
+
context.io.writeErr("Uploading bundle...");
|
|
46
46
|
await uploadBundle(uploadUrl, uploadFields, archivePath);
|
|
47
|
-
context.
|
|
48
|
-
context.
|
|
47
|
+
context.io.debug("Upload complete");
|
|
48
|
+
context.io.writeErr("Fetching and saving worker capabilities...");
|
|
49
49
|
const capabilitiesResult = await client.fetchAndSaveCapabilities(workerId);
|
|
50
50
|
if (Result.isSuccess(capabilitiesResult)) {
|
|
51
51
|
return Result.success({ workerId });
|
|
@@ -66,7 +66,7 @@ async function buildWorkerBundle(context, workerPath) {
|
|
|
66
66
|
outdir,
|
|
67
67
|
platform: "node"
|
|
68
68
|
});
|
|
69
|
-
context.
|
|
69
|
+
context.io.debug(`Built bundle to: ${outdir}`);
|
|
70
70
|
const archiveDir = fs.mkdtempSync("/tmp/workers-archive-");
|
|
71
71
|
const archivePath = path.join(archiveDir, "archive.tar.gz");
|
|
72
72
|
childProcess.execSync(`tar -czf ${archivePath} -C ${outdir} .`);
|
package/dist/cli/handler.js
CHANGED
|
@@ -8,7 +8,7 @@ function buildHandler(handler) {
|
|
|
8
8
|
processEnv: process.env,
|
|
9
9
|
flags
|
|
10
10
|
});
|
|
11
|
-
this.
|
|
11
|
+
this.io.debugEnabled = flags.debug;
|
|
12
12
|
await handler.call({ ...this, config }, flags, ...args);
|
|
13
13
|
};
|
|
14
14
|
}
|
|
@@ -21,7 +21,7 @@ function buildAuthedHandler(handler) {
|
|
|
21
21
|
environment,
|
|
22
22
|
baseUrl: this.config.baseUrl,
|
|
23
23
|
cellId,
|
|
24
|
-
writer: this.
|
|
24
|
+
writer: this.io
|
|
25
25
|
});
|
|
26
26
|
return handler.call({ ...this, apiClient: client }, flags, ...args);
|
|
27
27
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as prompts from "@inquirer/prompts";
|
|
1
2
|
import { type TableCell } from "@visulima/tabular";
|
|
2
3
|
export interface WriterOptions {
|
|
3
4
|
debugEnabled: boolean;
|
|
@@ -7,10 +8,13 @@ export interface TableOptions {
|
|
|
7
8
|
rows: TableCell[][];
|
|
8
9
|
plain: boolean;
|
|
9
10
|
}
|
|
11
|
+
type WithSafety<T> = T & {
|
|
12
|
+
noTTY: string;
|
|
13
|
+
};
|
|
10
14
|
/**
|
|
11
|
-
*
|
|
15
|
+
* IO manages safe, consistent, input and output patterns for the CLI.
|
|
12
16
|
*/
|
|
13
|
-
export declare class
|
|
17
|
+
export declare class IO {
|
|
14
18
|
#private;
|
|
15
19
|
debugEnabled: boolean;
|
|
16
20
|
constructor(options: WriterOptions);
|
|
@@ -44,5 +48,8 @@ export declare class Writer {
|
|
|
44
48
|
* @param tableConfig The table configuration.
|
|
45
49
|
*/
|
|
46
50
|
writeTableErr(tableConfig: TableOptions): void;
|
|
51
|
+
confirm(config: WithSafety<Parameters<typeof prompts.confirm>[0]>): Promise<boolean | void>;
|
|
52
|
+
input(config: WithSafety<Parameters<typeof prompts.input>[0]>): Promise<string | void>;
|
|
47
53
|
}
|
|
48
|
-
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/cli/io.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAe,KAAK,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAEhF,MAAM,WAAW,aAAa;IAC7B,YAAY,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,EAAE,CAAC;IACrC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CACf;AAED,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,qBAAa,EAAE;;IACd,YAAY,EAAE,OAAO,CAAC;gBAEV,OAAO,EAAE,aAAa;IAIlC;;;;OAIG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC;IAW7C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IASjE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;CAkC7D"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import * as prompts from "@inquirer/prompts";
|
|
1
2
|
import { createTable } from "@visulima/tabular";
|
|
2
|
-
class
|
|
3
|
+
class IO {
|
|
3
4
|
debugEnabled;
|
|
4
5
|
constructor(options) {
|
|
5
6
|
this.debugEnabled = options.debugEnabled;
|
|
@@ -52,6 +53,27 @@ class Writer {
|
|
|
52
53
|
const content = this.#buildTable(tableConfig);
|
|
53
54
|
this.writeErr(content);
|
|
54
55
|
}
|
|
56
|
+
confirm(config) {
|
|
57
|
+
if (!process.stdin.isTTY) {
|
|
58
|
+
this.writeErr(config.noTTY);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
return prompts.confirm(config).catch(this.#handlePromptExit.bind(this));
|
|
62
|
+
}
|
|
63
|
+
input(config) {
|
|
64
|
+
if (!process.stdin.isTTY) {
|
|
65
|
+
this.writeErr(config.noTTY);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
return prompts.input(config).catch(this.#handlePromptExit.bind(this));
|
|
69
|
+
}
|
|
70
|
+
#handlePromptExit(err) {
|
|
71
|
+
if (err instanceof Error && err.name === "ExitPromptError") {
|
|
72
|
+
this.writeErr("\u{1F44B} Prompt cancelled. Goodbye!");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
55
77
|
#buildTable(tableConfig) {
|
|
56
78
|
if (tableConfig.plain) {
|
|
57
79
|
return tableConfig.rows.map((row) => {
|
|
@@ -69,5 +91,5 @@ function isTableItem(cell) {
|
|
|
69
91
|
return typeof cell === "object";
|
|
70
92
|
}
|
|
71
93
|
export {
|
|
72
|
-
|
|
94
|
+
IO
|
|
73
95
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@project-ajax/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.57",
|
|
4
4
|
"description": "An SDK for building workers for the Project Ajax platform",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -70,11 +70,11 @@
|
|
|
70
70
|
"vitest": "^4.0.8"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
+
"@inquirer/prompts": "^8.0.1",
|
|
73
74
|
"@stricli/auto-complete": "^1.2.4",
|
|
74
75
|
"@stricli/core": "^1.2.4",
|
|
75
76
|
"@visulima/tabular": "^3.1.1",
|
|
76
77
|
"ajv": "^8.17.1",
|
|
77
|
-
"esbuild": "^0.25.12"
|
|
78
|
-
"prompts": "^2.4.2"
|
|
78
|
+
"esbuild": "^0.25.12"
|
|
79
79
|
}
|
|
80
80
|
}
|
package/src/cli/api/client.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* API client for making authenticated requests to the Workers API
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { IO } from "../io.js";
|
|
6
6
|
import { Result } from "./result.js";
|
|
7
7
|
|
|
8
8
|
export type Environment = "local" | "staging" | "dev" | "prod";
|
|
@@ -12,7 +12,7 @@ interface ApiClientConfig {
|
|
|
12
12
|
environment: Environment;
|
|
13
13
|
baseUrl?: string | undefined;
|
|
14
14
|
cellId: string;
|
|
15
|
-
writer:
|
|
15
|
+
writer: IO;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
type Endpoint = `/${string}`;
|
|
@@ -36,7 +36,7 @@ export class ApiClient {
|
|
|
36
36
|
readonly #token: string;
|
|
37
37
|
readonly #baseUrl: string | undefined;
|
|
38
38
|
readonly #cellId: string;
|
|
39
|
-
readonly #writer:
|
|
39
|
+
readonly #writer: IO;
|
|
40
40
|
|
|
41
41
|
constructor(config: ApiClientConfig) {
|
|
42
42
|
this.#token = config.token;
|
|
@@ -125,9 +125,11 @@ describe("login", () => {
|
|
|
125
125
|
configFile: {
|
|
126
126
|
token: null,
|
|
127
127
|
workerId: null,
|
|
128
|
-
environment: "prod",
|
|
129
128
|
baseUrl: "https://www.notion.so",
|
|
130
129
|
},
|
|
130
|
+
flags: {
|
|
131
|
+
env: "local",
|
|
132
|
+
},
|
|
131
133
|
});
|
|
132
134
|
|
|
133
135
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -142,9 +144,9 @@ describe("login", () => {
|
|
|
142
144
|
await login.call(context, baseFlags, testToken);
|
|
143
145
|
|
|
144
146
|
expect(updateSpy).toHaveBeenCalledWith({
|
|
145
|
-
environment: "prod",
|
|
146
147
|
token: testToken,
|
|
147
148
|
workerId: null,
|
|
149
|
+
environment: "local",
|
|
148
150
|
});
|
|
149
151
|
});
|
|
150
152
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConfigMap } from "../config.js";
|
|
1
2
|
import type { GlobalFlags } from "../flags.js";
|
|
2
3
|
import { buildHandler, type HandlerContext } from "../handler.js";
|
|
3
4
|
import { openNotionUrl } from "../utils/openUrl.js";
|
|
@@ -13,14 +14,14 @@ export const login = buildHandler(async function (
|
|
|
13
14
|
if (!token) {
|
|
14
15
|
const url = `${this.config.baseUrl}/__workers__?createToken=true`;
|
|
15
16
|
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
17
|
+
this.io.writeErr(`Opening browser to create a token...\n${url}\n`);
|
|
18
|
+
this.io.writeErr("After creating a token, run:");
|
|
19
|
+
this.io.writeErr("\tnpx workers auth login <token>");
|
|
19
20
|
|
|
20
21
|
try {
|
|
21
22
|
await openNotionUrl(environment, url);
|
|
22
23
|
} catch (_error) {
|
|
23
|
-
this.
|
|
24
|
+
this.io.writeErr(
|
|
24
25
|
`Failed to open browser automatically. Please visit:\n ${url}`,
|
|
25
26
|
);
|
|
26
27
|
}
|
|
@@ -28,17 +29,24 @@ export const login = buildHandler(async function (
|
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
environment,
|
|
32
|
+
const update: Partial<ConfigMap> = {
|
|
33
33
|
token,
|
|
34
34
|
workerId: null,
|
|
35
|
-
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
console.log("environment", environment);
|
|
38
|
+
|
|
39
|
+
if (environment !== "prod") {
|
|
40
|
+
update.environment = environment;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await this.config.update(update);
|
|
36
44
|
|
|
37
|
-
this.
|
|
45
|
+
this.io.writeErr("Successfully logged in!");
|
|
38
46
|
});
|
|
39
47
|
|
|
40
48
|
export const show = buildHandler(function (this: HandlerContext) {
|
|
41
|
-
this.
|
|
49
|
+
this.io.writeOut(`${this.config.token ?? ""}`);
|
|
42
50
|
});
|
|
43
51
|
|
|
44
52
|
export const logout = buildHandler(async function (this: HandlerContext) {
|
|
@@ -12,8 +12,8 @@ export const downloadBundle = buildAuthedHandler(async function () {
|
|
|
12
12
|
|
|
13
13
|
const result = await this.apiClient.downloadWorkerBundle(workerId);
|
|
14
14
|
if (Result.isFail(result)) {
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
15
|
+
this.io.writeErr(`✗ Failed to download bundle`);
|
|
16
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -21,9 +21,9 @@ export const listCapabilities = buildAuthedHandler(async function (
|
|
|
21
21
|
|
|
22
22
|
const data = Result.unwrap(result);
|
|
23
23
|
if (data.capabilities.length === 0) {
|
|
24
|
-
this.
|
|
24
|
+
this.io.writeErr("No capabilities found for this worker.");
|
|
25
25
|
} else {
|
|
26
|
-
this.
|
|
26
|
+
this.io.writeTableOut({
|
|
27
27
|
headers: ["Key", "Tag"],
|
|
28
28
|
rows: data.capabilities.map((capability) => [
|
|
29
29
|
capability.key,
|
|
@@ -37,10 +37,10 @@ export const listCapabilities = buildAuthedHandler(async function (
|
|
|
37
37
|
|
|
38
38
|
// If it's a validation error, show the clean debug message
|
|
39
39
|
if (result.error.validationError) {
|
|
40
|
-
this.
|
|
40
|
+
this.io.writeErr(`✗ ${result.error.validationError.debugMessage}`);
|
|
41
41
|
throw new Error(result.error.validationError.debugMessage);
|
|
42
42
|
} else {
|
|
43
|
-
this.
|
|
43
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
44
44
|
throw new Error(result.error.message);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -17,11 +17,11 @@ export const listProviders = buildAuthedHandler(async function (
|
|
|
17
17
|
this.process.stderr.write("OK\n\n");
|
|
18
18
|
const providers = providersResult.value.providers;
|
|
19
19
|
if (providers.length === 0) {
|
|
20
|
-
this.
|
|
20
|
+
this.io.writeErr("No OAuth providers are currently available.");
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
this.
|
|
24
|
+
this.io.writeTableOut({
|
|
25
25
|
headers: ["Provider", "Description"],
|
|
26
26
|
rows: providers.map((provider) => [provider.key, provider.displayName]),
|
|
27
27
|
plain: flags.plain,
|
|
@@ -50,22 +50,22 @@ export const addConnection = buildAuthedHandler(async function (
|
|
|
50
50
|
|
|
51
51
|
const { authorizationUrl } = startResult.value;
|
|
52
52
|
|
|
53
|
-
this.
|
|
53
|
+
this.io.writeErr("Opening your browser to continue the OAuth flow...");
|
|
54
54
|
try {
|
|
55
55
|
await openBrowserUrl(authorizationUrl);
|
|
56
56
|
} catch (error) {
|
|
57
|
-
this.
|
|
57
|
+
this.io.writeErr(
|
|
58
58
|
`Unable to open the browser automatically (${String(
|
|
59
59
|
error,
|
|
60
60
|
)}). Please open the link below manually.`,
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
64
|
+
this.io.writeErr("");
|
|
65
|
+
this.io.writeErr("If the browser did not open, visit:");
|
|
66
|
+
this.io.writeErr(` ${authorizationUrl}`);
|
|
67
|
+
this.io.writeErr("");
|
|
68
|
+
this.io.writeErr(
|
|
69
69
|
"After completing the flow in your browser, return to the CLI.",
|
|
70
70
|
);
|
|
71
71
|
});
|
|
@@ -91,11 +91,11 @@ export const listConnections = buildAuthedHandler(async function (
|
|
|
91
91
|
const secrets = secretsResult.value.secrets;
|
|
92
92
|
|
|
93
93
|
if (secrets.length === 0) {
|
|
94
|
-
this.
|
|
94
|
+
this.io.writeErr("No OAuth connections found for this worker.");
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
this.
|
|
98
|
+
this.io.writeTableOut({
|
|
99
99
|
headers: ["Env Var", "Created At"],
|
|
100
100
|
rows: secrets.map((secret) => [
|
|
101
101
|
`process.env.${secret.key}`,
|
|
@@ -143,7 +143,7 @@ function reportApiError(
|
|
|
143
143
|
error: ApiError,
|
|
144
144
|
action: string,
|
|
145
145
|
): never {
|
|
146
|
-
context.
|
|
147
|
-
context.
|
|
146
|
+
context.io.writeErr(`✗ Failed to ${action}`);
|
|
147
|
+
context.io.writeErr(`✗ ${error.message}`);
|
|
148
148
|
throw new Error(error.message);
|
|
149
149
|
}
|
|
@@ -21,11 +21,6 @@ vi.mock("../deploy.js", () => ({
|
|
|
21
21
|
deployWorker: vi.fn(),
|
|
22
22
|
}));
|
|
23
23
|
|
|
24
|
-
vi.mock("prompts", () => ({
|
|
25
|
-
default: vi.fn(),
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
import prompts from "prompts";
|
|
29
24
|
import { deployWorker } from "../deploy.js";
|
|
30
25
|
import { deploy } from "./deploy.impl.js";
|
|
31
26
|
|
|
@@ -96,6 +91,7 @@ describe("deploy", () => {
|
|
|
96
91
|
|
|
97
92
|
const updateSpy = vi.spyOn(mockConfig, "update");
|
|
98
93
|
const context = createBaseContext();
|
|
94
|
+
vi.spyOn(context.io, "input").mockResolvedValue("my-worker");
|
|
99
95
|
|
|
100
96
|
await deploy.call(context, { ...baseFlags, name: "my-worker" });
|
|
101
97
|
|
|
@@ -110,7 +106,7 @@ describe("deploy", () => {
|
|
|
110
106
|
expect(updateSpy).toHaveBeenCalledWith({
|
|
111
107
|
workerId: "worker-456",
|
|
112
108
|
});
|
|
113
|
-
expect(
|
|
109
|
+
expect(context.io.input).not.toHaveBeenCalled();
|
|
114
110
|
|
|
115
111
|
const allCalls = stderrSpy.mock.calls.map((call) => call[0]).join("");
|
|
116
112
|
expect(allCalls).toContain("✓ Successfully deployed worker");
|
|
@@ -128,21 +124,20 @@ describe("deploy", () => {
|
|
|
128
124
|
});
|
|
129
125
|
|
|
130
126
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
131
|
-
vi.mocked(prompts).mockResolvedValue({ name: "prompted-worker" });
|
|
132
127
|
vi.mocked(deployWorker).mockResolvedValue(
|
|
133
128
|
Result.success({ workerId: "worker-789" }),
|
|
134
129
|
);
|
|
135
130
|
|
|
136
131
|
const updateSpy = vi.spyOn(mockConfig, "update");
|
|
137
132
|
const context = createBaseContext();
|
|
133
|
+
vi.spyOn(context.io, "input").mockResolvedValue("prompted-worker");
|
|
138
134
|
|
|
139
135
|
await deploy.call(context, baseFlags);
|
|
140
136
|
|
|
141
|
-
expect(
|
|
142
|
-
type: "text",
|
|
143
|
-
name: "name",
|
|
137
|
+
expect(context.io.input).toHaveBeenCalledWith({
|
|
144
138
|
message: "Enter a name for the worker",
|
|
145
|
-
|
|
139
|
+
required: true,
|
|
140
|
+
noTTY: "Provide a name for the worker with --name",
|
|
146
141
|
});
|
|
147
142
|
|
|
148
143
|
expect(deployWorker).toHaveBeenCalledWith(expect.anything(), {
|
|
@@ -158,7 +153,7 @@ describe("deploy", () => {
|
|
|
158
153
|
});
|
|
159
154
|
});
|
|
160
155
|
|
|
161
|
-
it("throws error when
|
|
156
|
+
it("throws error when name is not provided", async () => {
|
|
162
157
|
const [mockConfig] = await createAndLoadConfig({
|
|
163
158
|
configFile: {
|
|
164
159
|
token:
|
|
@@ -170,9 +165,9 @@ describe("deploy", () => {
|
|
|
170
165
|
});
|
|
171
166
|
|
|
172
167
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
173
|
-
vi.mocked(prompts).mockResolvedValue({ name: undefined });
|
|
174
168
|
|
|
175
169
|
const context = createBaseContext();
|
|
170
|
+
vi.spyOn(context.io, "input").mockResolvedValue("");
|
|
176
171
|
|
|
177
172
|
await expect(deploy.call(context, baseFlags)).rejects.toThrow(
|
|
178
173
|
"Name is required",
|
|
@@ -240,12 +235,12 @@ describe("deploy", () => {
|
|
|
240
235
|
});
|
|
241
236
|
|
|
242
237
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
243
|
-
vi.mocked(prompts).mockResolvedValue({ name: " worker-name " });
|
|
244
238
|
vi.mocked(deployWorker).mockResolvedValue(
|
|
245
239
|
Result.success({ workerId: "worker-999" }),
|
|
246
240
|
);
|
|
247
241
|
|
|
248
242
|
const context = createBaseContext();
|
|
243
|
+
vi.spyOn(context.io, "input").mockResolvedValue(" worker-name ");
|
|
249
244
|
|
|
250
245
|
await deploy.call(context, baseFlags);
|
|
251
246
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import prompts from "prompts";
|
|
2
1
|
import type { ApiError } from "../api/client.js";
|
|
3
2
|
import { Result } from "../api/result.js";
|
|
4
3
|
import { deployWorker } from "../deploy.js";
|
|
@@ -19,7 +18,7 @@ export const deploy = buildAuthedHandler(async function (flags: DeployFlags) {
|
|
|
19
18
|
}
|
|
20
19
|
const workerPath = this.process.cwd();
|
|
21
20
|
|
|
22
|
-
this.
|
|
21
|
+
this.io.writeErr("Deploying worker...");
|
|
23
22
|
|
|
24
23
|
const name = flags.name;
|
|
25
24
|
if (workerId && name) {
|
|
@@ -39,23 +38,19 @@ export const deploy = buildAuthedHandler(async function (flags: DeployFlags) {
|
|
|
39
38
|
if (name) {
|
|
40
39
|
validatedName = name;
|
|
41
40
|
} else {
|
|
42
|
-
const
|
|
43
|
-
type: "text",
|
|
44
|
-
name: "name",
|
|
41
|
+
const nameInput = await this.io.input({
|
|
45
42
|
message: "Enter a name for the worker",
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return "Name is required";
|
|
49
|
-
}
|
|
50
|
-
return true;
|
|
51
|
-
},
|
|
43
|
+
required: true,
|
|
44
|
+
noTTY: "Provide a name for the worker with --name",
|
|
52
45
|
});
|
|
53
46
|
|
|
54
|
-
|
|
47
|
+
const trimmedName = nameInput?.trim();
|
|
48
|
+
|
|
49
|
+
if (!trimmedName) {
|
|
55
50
|
throw new Error("Name is required");
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
validatedName =
|
|
53
|
+
validatedName = trimmedName;
|
|
59
54
|
}
|
|
60
55
|
|
|
61
56
|
result = await deployWorker(this, {
|
|
@@ -69,10 +64,10 @@ export const deploy = buildAuthedHandler(async function (flags: DeployFlags) {
|
|
|
69
64
|
if (Result.isSuccess(result)) {
|
|
70
65
|
const { workerId } = Result.unwrap(result);
|
|
71
66
|
await this.config.update({ workerId });
|
|
72
|
-
this.
|
|
67
|
+
this.io.writeErr("✓ Successfully deployed worker");
|
|
73
68
|
} else {
|
|
74
|
-
this.
|
|
75
|
-
this.
|
|
69
|
+
this.io.writeErr("✗ Failed to deploy worker");
|
|
70
|
+
this.io.writeErr(result.error.message);
|
|
76
71
|
return;
|
|
77
72
|
}
|
|
78
73
|
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import prompts from "prompts";
|
|
2
|
-
|
|
3
1
|
import { Result } from "../api/result.js";
|
|
4
2
|
import { buildAuthedHandler } from "../handler.js";
|
|
5
3
|
import { pluralize } from "../utils/string.js";
|
|
@@ -28,25 +26,23 @@ export const pullEnv = buildAuthedHandler(async function (
|
|
|
28
26
|
);
|
|
29
27
|
|
|
30
28
|
if (this.fs.existsSync(absoluteDestination) && !flags.yes) {
|
|
31
|
-
const
|
|
32
|
-
type: "confirm",
|
|
33
|
-
name: "overwrite",
|
|
29
|
+
const overwrite = await this.io.confirm({
|
|
34
30
|
message: `File "${destination}" already exists. Overwrite it?`,
|
|
35
|
-
|
|
31
|
+
noTTY: `File "${destination}" already exists.`,
|
|
36
32
|
});
|
|
37
33
|
|
|
38
34
|
if (overwrite !== true) {
|
|
39
|
-
this.
|
|
35
|
+
this.io.writeErr("Aborted.");
|
|
40
36
|
return;
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
this.
|
|
40
|
+
this.io.writeErr("Fetching environment variables...");
|
|
45
41
|
const envResult = await this.apiClient.pullEnv(workerId);
|
|
46
42
|
|
|
47
43
|
if (Result.isFail(envResult)) {
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
44
|
+
this.io.writeErr("✗ Failed to fetch env vars");
|
|
45
|
+
this.io.writeErr(`✗ ${envResult.error.message}`);
|
|
50
46
|
throw new Error(envResult.error.message);
|
|
51
47
|
}
|
|
52
48
|
|
|
@@ -58,7 +54,7 @@ export const pullEnv = buildAuthedHandler(async function (
|
|
|
58
54
|
});
|
|
59
55
|
await this.fs.promises.writeFile(absoluteDestination, fileContents, "utf8");
|
|
60
56
|
|
|
61
|
-
this.
|
|
57
|
+
this.io.writeErr(
|
|
62
58
|
`Wrote ${pluralize(envEntries.length, "env var")} to "${destination}"`,
|
|
63
59
|
);
|
|
64
60
|
});
|
|
@@ -44,7 +44,7 @@ export const exec = buildAuthedHandler(async function (
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
// Execute the capability
|
|
47
|
-
this.
|
|
47
|
+
this.io.writeErr(`Executing capability "${capabilityName}"...`);
|
|
48
48
|
|
|
49
49
|
if (flags.stream) {
|
|
50
50
|
const result = await this.apiClient.runCapability(
|
|
@@ -94,21 +94,21 @@ export const exec = buildAuthedHandler(async function (
|
|
|
94
94
|
.trim()
|
|
95
95
|
.split("\n")
|
|
96
96
|
.forEach((dataLine) => {
|
|
97
|
-
this.
|
|
97
|
+
this.io.writeErr(
|
|
98
98
|
`[worker:${parsedLine.event.stream}] ${dataLine.trim()}`,
|
|
99
99
|
);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
break;
|
|
103
103
|
case "result":
|
|
104
|
-
this.
|
|
104
|
+
this.io.writeOut(JSON.stringify(parsedLine.result, null, 2));
|
|
105
105
|
break;
|
|
106
106
|
case "error":
|
|
107
|
-
this.
|
|
107
|
+
this.io.writeErr(`Error: ${parsedLine.error}`);
|
|
108
108
|
break;
|
|
109
109
|
}
|
|
110
110
|
} catch (error) {
|
|
111
|
-
this.
|
|
111
|
+
this.io.writeErr(`Error parsing log line: ${jsonLine}: ${error}`);
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
@@ -132,19 +132,17 @@ export const exec = buildAuthedHandler(async function (
|
|
|
132
132
|
}
|
|
133
133
|
return;
|
|
134
134
|
} else {
|
|
135
|
-
this.
|
|
135
|
+
this.io.writeErr(`\n✗ Failed to execute capability`);
|
|
136
136
|
|
|
137
137
|
// If it's a validation error, show the clean debug message
|
|
138
138
|
if (result.error.validationError) {
|
|
139
|
-
this.
|
|
140
|
-
this.
|
|
141
|
-
|
|
142
|
-
);
|
|
143
|
-
this.writer.writeErr(`\n${usageHint}`);
|
|
139
|
+
this.io.writeErr(`\t✗ HTTP Error: ${result.error.status}`);
|
|
140
|
+
this.io.writeErr(`\t✗ ${result.error.validationError.debugMessage}`);
|
|
141
|
+
this.io.writeErr(`\n${usageHint}`);
|
|
144
142
|
throw new Error(result.error.validationError.debugMessage);
|
|
145
143
|
} else {
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
144
|
+
this.io.writeErr(`\t✗ HTTP Error: ${result.error.status}`);
|
|
145
|
+
this.io.writeErr(`\t✗ ${result.error.message}`);
|
|
148
146
|
throw new Error(result.error.message);
|
|
149
147
|
}
|
|
150
148
|
}
|
|
@@ -159,10 +157,10 @@ export const exec = buildAuthedHandler(async function (
|
|
|
159
157
|
|
|
160
158
|
if (Result.isSuccess(result)) {
|
|
161
159
|
const data = Result.unwrap(result);
|
|
162
|
-
this.
|
|
160
|
+
this.io.writeOut(JSON.stringify(data.result, null, 2));
|
|
163
161
|
} else {
|
|
164
|
-
this.
|
|
165
|
-
this.
|
|
162
|
+
this.io.writeErr(`\n✗ Failed to execute capability`);
|
|
163
|
+
this.io.writeErr(`\t✗ ${result.error.message}`);
|
|
166
164
|
throw new Error(result.error.message);
|
|
167
165
|
}
|
|
168
166
|
}
|