@project-ajax/sdk 0.0.54 → 0.0.56
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 +14 -10
- 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 +11 -17
- 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 +8 -20
- package/dist/cli/commands/utils/testing.d.ts.map +1 -1
- package/dist/cli/commands/utils/testing.js +25 -18
- package/dist/cli/config.d.ts +13 -6
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +60 -35
- 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 +66 -46
- package/src/cli/commands/auth.impl.ts +14 -10
- package/src/cli/commands/bundle.impl.test.ts +25 -19
- 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 +78 -63
- package/src/cli/commands/deploy.impl.ts +12 -17
- 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 +33 -27
- package/src/cli/config.test.ts +45 -95
- package/src/cli/config.ts +69 -42
- 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
|
@@ -19,9 +19,9 @@ export const listRuns = buildAuthedHandler(async function (flags: FormatFlags) {
|
|
|
19
19
|
|
|
20
20
|
const data = Result.unwrap(result);
|
|
21
21
|
if (data.runs.length === 0) {
|
|
22
|
-
this.
|
|
22
|
+
this.io.writeErr("No runs found for this worker.");
|
|
23
23
|
} else {
|
|
24
|
-
this.
|
|
24
|
+
this.io.writeTableOut({
|
|
25
25
|
headers: ["Run ID", "Name", "Started At", "Ended At", "Exit Code"],
|
|
26
26
|
rows: data.runs.map((run) => [
|
|
27
27
|
run.runId,
|
|
@@ -38,10 +38,10 @@ export const listRuns = buildAuthedHandler(async function (flags: FormatFlags) {
|
|
|
38
38
|
|
|
39
39
|
// If it's a validation error, show the clean debug message
|
|
40
40
|
if (result.error.validationError) {
|
|
41
|
-
this.
|
|
41
|
+
this.io.writeErr(`✗ ${result.error.validationError.debugMessage}`);
|
|
42
42
|
throw new Error(result.error.validationError.debugMessage);
|
|
43
43
|
} else {
|
|
44
|
-
this.
|
|
44
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
45
45
|
throw new Error(result.error.message);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -71,16 +71,16 @@ export const getRunLogs = buildAuthedHandler(async function (
|
|
|
71
71
|
|
|
72
72
|
const data = Result.unwrap(result);
|
|
73
73
|
// Output logs directly to stdout (primary output)
|
|
74
|
-
this.
|
|
74
|
+
this.io.writeOut(data.logs);
|
|
75
75
|
} else {
|
|
76
76
|
this.process.stderr.write("ERROR\n\n");
|
|
77
77
|
|
|
78
78
|
// If it's a validation error, show the clean debug message
|
|
79
79
|
if (result.error.validationError) {
|
|
80
|
-
this.
|
|
80
|
+
this.io.writeErr(`✗ ${result.error.validationError.debugMessage}`);
|
|
81
81
|
throw new Error(result.error.validationError.debugMessage);
|
|
82
82
|
} else {
|
|
83
|
-
this.
|
|
83
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
84
84
|
throw new Error(result.error.message);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -17,17 +17,17 @@ export const setSecrets = buildAuthedHandler(async function (
|
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
this.
|
|
20
|
+
this.io.writeErr(`Setting ${pluralize(secrets.length, "secret")}...`);
|
|
21
21
|
|
|
22
22
|
const result = await this.apiClient.upsertSecrets(workerId, secrets);
|
|
23
23
|
|
|
24
24
|
if (Result.isSuccess(result)) {
|
|
25
25
|
for (const secret of Result.unwrap(result).secrets) {
|
|
26
|
-
this.
|
|
26
|
+
this.io.writeErr(`Set secret "${secret.key}"`);
|
|
27
27
|
}
|
|
28
28
|
} else {
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
29
|
+
this.io.writeErr(`✗ Failed to set secrets`);
|
|
30
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
31
31
|
throw new Error(result.error.message);
|
|
32
32
|
}
|
|
33
33
|
});
|
|
@@ -51,25 +51,25 @@ export const listSecrets = buildAuthedHandler(async function (
|
|
|
51
51
|
|
|
52
52
|
const data = Result.unwrap(result);
|
|
53
53
|
if (data.secrets.length === 0) {
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
54
|
+
this.io.writeErr("No secrets for this worker.");
|
|
55
|
+
this.io.writeErr(
|
|
56
56
|
"To list OAuth connect secrets, use `npx workers connect list`",
|
|
57
57
|
);
|
|
58
58
|
} else {
|
|
59
|
-
this.
|
|
59
|
+
this.io.writeTableOut({
|
|
60
60
|
headers: ["Key", "Created At"],
|
|
61
61
|
rows: data.secrets.map((secret) => [secret.key, secret.createdAt]),
|
|
62
62
|
plain: flags.plain,
|
|
63
63
|
});
|
|
64
|
-
this.
|
|
64
|
+
this.io.writeErr(
|
|
65
65
|
"To list OAuth connect secrets, use `npx workers connect list`",
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
} else {
|
|
69
69
|
this.process.stderr.write("ERROR\n\n");
|
|
70
70
|
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
71
|
+
this.io.writeErr(`✗ Failed to list secrets`);
|
|
72
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
73
73
|
throw new Error(result.error.message);
|
|
74
74
|
}
|
|
75
75
|
});
|
|
@@ -94,8 +94,8 @@ export const removeSecret = buildAuthedHandler(async function (
|
|
|
94
94
|
} else {
|
|
95
95
|
this.process.stderr.write("ERROR\n\n");
|
|
96
96
|
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
97
|
+
this.io.writeErr(`✗ Failed to remove secret "${key}"`);
|
|
98
|
+
this.io.writeErr(`✗ ${result.error.message}`);
|
|
99
99
|
throw new Error(result.error.message);
|
|
100
100
|
}
|
|
101
101
|
});
|
|
@@ -3,16 +3,10 @@ import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import { Config, type
|
|
6
|
+
import { Config, type ConfigMap } from "../../config.js";
|
|
7
|
+
import type { LocalContext } from "../../context.js";
|
|
7
8
|
import type { GlobalFlags } from "../../flags.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
export type ConfigFileContents = {
|
|
11
|
-
token: string | null;
|
|
12
|
-
workerId: string | null;
|
|
13
|
-
environment: Environment;
|
|
14
|
-
baseUrl: string;
|
|
15
|
-
};
|
|
9
|
+
import { IO } from "../../io.js";
|
|
16
10
|
|
|
17
11
|
export const tmpDirectories: string[] = [];
|
|
18
12
|
|
|
@@ -20,33 +14,36 @@ export const baseFlags: GlobalFlags = {
|
|
|
20
14
|
debug: false,
|
|
21
15
|
};
|
|
22
16
|
|
|
23
|
-
export async function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
export async function createAndLoadConfig({
|
|
18
|
+
configFile,
|
|
19
|
+
env,
|
|
20
|
+
flags,
|
|
21
|
+
}: {
|
|
22
|
+
configFile: Partial<ConfigMap>;
|
|
23
|
+
env?: Partial<NodeJS.ProcessEnv>;
|
|
24
|
+
flags?: Partial<GlobalFlags>;
|
|
25
|
+
}): Promise<[config: Config, path: string]> {
|
|
26
|
+
const configFilePath = await createConfigFile(configFile);
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
configFileContents: ConfigFileContents,
|
|
34
|
-
): Promise<Config> {
|
|
35
|
-
const configFilePath = await createConfigFile(configFileContents);
|
|
36
|
-
return Config.load({
|
|
28
|
+
const map = await Config.load({
|
|
37
29
|
configFilePath,
|
|
38
|
-
processEnv: {}
|
|
39
|
-
flags: {
|
|
30
|
+
processEnv: env ?? {},
|
|
31
|
+
flags: {
|
|
32
|
+
...baseFlags,
|
|
33
|
+
...(flags ?? {}),
|
|
34
|
+
},
|
|
40
35
|
});
|
|
36
|
+
|
|
37
|
+
return [map, configFilePath];
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
export function createBaseContext() {
|
|
40
|
+
export function createBaseContext(): LocalContext {
|
|
44
41
|
return {
|
|
45
|
-
writer: new Writer({ debugEnabled: false }),
|
|
46
|
-
process,
|
|
47
42
|
fs,
|
|
43
|
+
io: new IO({ debugEnabled: false }),
|
|
48
44
|
os,
|
|
49
45
|
path,
|
|
46
|
+
process,
|
|
50
47
|
};
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -58,3 +55,12 @@ export async function cleanupTmpDirectories() {
|
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
57
|
}
|
|
58
|
+
|
|
59
|
+
async function createConfigFile(contents: Partial<ConfigMap>) {
|
|
60
|
+
const dir = await mkdtemp(path.join(tmpdir(), "cmd-test-"));
|
|
61
|
+
tmpDirectories.push(dir);
|
|
62
|
+
const configFilePath = path.join(dir, "config.json");
|
|
63
|
+
|
|
64
|
+
await writeFile(configFilePath, JSON.stringify(contents, null, 2), "utf-8");
|
|
65
|
+
return configFilePath;
|
|
66
|
+
}
|
package/src/cli/config.test.ts
CHANGED
|
@@ -1,74 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import * as path from "node:path";
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
4
2
|
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
workerId: string | null;
|
|
11
|
-
environment: Environment;
|
|
12
|
-
baseUrl: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const tmpDirectories: string[] = [];
|
|
16
|
-
|
|
17
|
-
async function createConfigFile(contents: ConfigFileContents) {
|
|
18
|
-
const dir = await mkdtemp(path.join(tmpdir(), "config-test-"));
|
|
19
|
-
tmpDirectories.push(dir);
|
|
20
|
-
const configFilePath = path.join(dir, "config.json");
|
|
3
|
+
import {
|
|
4
|
+
cleanupTmpDirectories,
|
|
5
|
+
createAndLoadConfig,
|
|
6
|
+
} from "./commands/utils/testing.js";
|
|
7
|
+
import { Config, type ConfigMap } from "./config.js";
|
|
21
8
|
|
|
22
|
-
|
|
23
|
-
return configFilePath;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
afterEach(async () => {
|
|
27
|
-
while (tmpDirectories.length > 0) {
|
|
28
|
-
const dir = tmpDirectories.pop();
|
|
29
|
-
if (dir) {
|
|
30
|
-
await rm(dir, { recursive: true, force: true });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
async function loadTestConfig({
|
|
36
|
-
configFile,
|
|
37
|
-
env,
|
|
38
|
-
flags,
|
|
39
|
-
}: {
|
|
40
|
-
configFile: ConfigFileContents;
|
|
41
|
-
env?: Partial<NodeJS.ProcessEnv>;
|
|
42
|
-
flags?: Partial<GlobalFlags>;
|
|
43
|
-
}) {
|
|
44
|
-
const configFilePath = await createConfigFile(configFile);
|
|
45
|
-
return Config.load({
|
|
46
|
-
configFilePath,
|
|
47
|
-
processEnv: { ...(env ?? {}) } as NodeJS.ProcessEnv,
|
|
48
|
-
flags: {
|
|
49
|
-
debug: false,
|
|
50
|
-
...(flags ?? {}),
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const baseConfigFile: ConfigFileContents = {
|
|
9
|
+
const baseConfigMap: ConfigMap = {
|
|
56
10
|
token: "file-token",
|
|
57
11
|
workerId: "file-worker",
|
|
58
12
|
environment: "local",
|
|
59
13
|
baseUrl: "https://config.example.com",
|
|
60
14
|
};
|
|
61
15
|
|
|
16
|
+
afterEach(cleanupTmpDirectories);
|
|
17
|
+
|
|
62
18
|
describe("Config.load precedence", () => {
|
|
63
19
|
it("uses values from the config file when no overrides are present", async () => {
|
|
64
|
-
const config = await
|
|
65
|
-
configFile:
|
|
20
|
+
const [config] = await createAndLoadConfig({
|
|
21
|
+
configFile: baseConfigMap,
|
|
66
22
|
});
|
|
67
23
|
|
|
68
|
-
expect(config.token).toBe(
|
|
69
|
-
expect(config.workerId).toBe(
|
|
70
|
-
expect(config.environment).toBe(
|
|
71
|
-
expect(config.baseUrl).toBe(
|
|
24
|
+
expect(config.token).toBe(baseConfigMap.token);
|
|
25
|
+
expect(config.workerId).toBe(baseConfigMap.workerId);
|
|
26
|
+
expect(config.environment).toBe(baseConfigMap.environment);
|
|
27
|
+
expect(config.baseUrl).toBe(baseConfigMap.baseUrl);
|
|
72
28
|
});
|
|
73
29
|
|
|
74
30
|
it("prefers environment variables over the config file", async () => {
|
|
@@ -77,15 +33,15 @@ describe("Config.load precedence", () => {
|
|
|
77
33
|
WORKERS_WORKER_ID: "env-worker",
|
|
78
34
|
WORKERS_ENVIRONMENT: "staging",
|
|
79
35
|
};
|
|
80
|
-
const config = await
|
|
81
|
-
configFile:
|
|
36
|
+
const [config] = await createAndLoadConfig({
|
|
37
|
+
configFile: baseConfigMap,
|
|
82
38
|
env: envVars,
|
|
83
39
|
});
|
|
84
40
|
|
|
85
41
|
expect(config.token).toBe(envVars.WORKERS_TOKEN);
|
|
86
42
|
expect(config.workerId).toBe(envVars.WORKERS_WORKER_ID);
|
|
87
43
|
expect(config.environment).toBe(envVars.WORKERS_ENVIRONMENT);
|
|
88
|
-
expect(config.baseUrl).toBe(
|
|
44
|
+
expect(config.baseUrl).toBe(baseConfigMap.baseUrl);
|
|
89
45
|
});
|
|
90
46
|
|
|
91
47
|
it("prefers flags over environment variables and config file values", async () => {
|
|
@@ -100,59 +56,53 @@ describe("Config.load precedence", () => {
|
|
|
100
56
|
"base-url": "https://flag.example.com",
|
|
101
57
|
};
|
|
102
58
|
|
|
103
|
-
const config = await
|
|
104
|
-
configFile:
|
|
59
|
+
const [config] = await createAndLoadConfig({
|
|
60
|
+
configFile: baseConfigMap,
|
|
105
61
|
env: envVars,
|
|
106
62
|
flags,
|
|
107
63
|
});
|
|
108
64
|
|
|
109
|
-
expect(config.token).toBe(
|
|
65
|
+
expect(config.token).toBe(baseConfigMap.token);
|
|
110
66
|
expect(config.workerId).toBe(envVars.WORKERS_WORKER_ID);
|
|
111
67
|
expect(config.environment).toBe(flags.env);
|
|
112
68
|
expect(config.baseUrl).toBe(flags["base-url"]);
|
|
113
69
|
});
|
|
114
70
|
});
|
|
115
71
|
|
|
116
|
-
describe("Config.
|
|
117
|
-
it("
|
|
118
|
-
const
|
|
72
|
+
describe("Config.update", () => {
|
|
73
|
+
it("persists only provided keys to disk", async () => {
|
|
74
|
+
const [, configFilePath] = await createAndLoadConfig({
|
|
119
75
|
configFile: {
|
|
120
|
-
token: "
|
|
121
|
-
workerId:
|
|
76
|
+
token: "file-token",
|
|
77
|
+
workerId: "file-worker",
|
|
122
78
|
environment: "prod",
|
|
123
|
-
baseUrl: "https://
|
|
79
|
+
baseUrl: "https://config.example.com",
|
|
124
80
|
},
|
|
125
81
|
});
|
|
126
82
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
83
|
+
const config = await Config.load({
|
|
84
|
+
configFilePath,
|
|
85
|
+
processEnv: {
|
|
86
|
+
WORKERS_BASE_URL: "https://env.example.com",
|
|
87
|
+
} as NodeJS.ProcessEnv,
|
|
88
|
+
flags: { debug: false },
|
|
89
|
+
});
|
|
131
90
|
|
|
132
|
-
expect(config.
|
|
133
|
-
expect(config.baseUrl).toBe("http://localhost:3000");
|
|
134
|
-
});
|
|
91
|
+
expect(config.baseUrl).toBe("https://env.example.com");
|
|
135
92
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
configFile: {
|
|
139
|
-
token: "test-token",
|
|
140
|
-
workerId: null,
|
|
141
|
-
environment: "prod",
|
|
142
|
-
baseUrl: "https://www.notion.so",
|
|
143
|
-
},
|
|
93
|
+
await config.update({
|
|
94
|
+
token: "updated-token",
|
|
144
95
|
});
|
|
145
96
|
|
|
146
|
-
|
|
147
|
-
expect(config.baseUrl).toBe("https://staging.notion.so");
|
|
97
|
+
expect(config.token).toBe("updated-token");
|
|
148
98
|
|
|
149
|
-
|
|
150
|
-
expect(config.baseUrl).toBe("https://dev.notion.so");
|
|
99
|
+
const persisted = JSON.parse(await readFile(configFilePath, "utf-8"));
|
|
151
100
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
101
|
+
expect(persisted).toEqual({
|
|
102
|
+
token: "updated-token",
|
|
103
|
+
workerId: "file-worker",
|
|
104
|
+
environment: "prod",
|
|
105
|
+
baseUrl: "https://config.example.com",
|
|
106
|
+
});
|
|
157
107
|
});
|
|
158
108
|
});
|
package/src/cli/config.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { GlobalFlags } from "./flags.js";
|
|
|
5
5
|
export const Environments = ["local", "staging", "dev", "prod"] as const;
|
|
6
6
|
export type Environment = (typeof Environments)[number];
|
|
7
7
|
|
|
8
|
-
interface ConfigMap {
|
|
8
|
+
export interface ConfigMap {
|
|
9
9
|
environment: Environment;
|
|
10
10
|
baseUrl: string;
|
|
11
11
|
token: string | null;
|
|
@@ -46,11 +46,11 @@ export class Config {
|
|
|
46
46
|
readonly #configFilePath: string;
|
|
47
47
|
|
|
48
48
|
constructor(opts: {
|
|
49
|
+
configMap: ConfigMap;
|
|
49
50
|
configFilePath: string;
|
|
50
|
-
configFile: ConfigMap;
|
|
51
51
|
}) {
|
|
52
|
+
this.#configMap = opts.configMap;
|
|
52
53
|
this.#configFilePath = opts.configFilePath;
|
|
53
|
-
this.#configMap = opts.configFile;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Getters read from the environment variables, and then the config file.
|
|
@@ -71,32 +71,6 @@ export class Config {
|
|
|
71
71
|
return this.#configMap.workerId;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// Setters update the config file, and then write it to disk.
|
|
75
|
-
|
|
76
|
-
async setEnvironment(environment: Environment) {
|
|
77
|
-
this.#configMap.environment = environment;
|
|
78
|
-
this.#configMap.baseUrl = baseUrl(environment);
|
|
79
|
-
await this.#writeConfigFile();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async setToken(token: string | null) {
|
|
83
|
-
this.#configMap.token = token;
|
|
84
|
-
await this.#writeConfigFile();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async setWorkerId(workerId: string | null) {
|
|
88
|
-
this.#configMap.workerId = workerId;
|
|
89
|
-
await this.#writeConfigFile();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async #writeConfigFile() {
|
|
93
|
-
await fs.promises.writeFile(
|
|
94
|
-
this.#configFilePath,
|
|
95
|
-
JSON.stringify(this.#configMap, null, 2),
|
|
96
|
-
"utf-8",
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
74
|
get tokenInfo(): { token: string; spaceId: string; cellId: string } {
|
|
101
75
|
const token = this.token;
|
|
102
76
|
if (!token) {
|
|
@@ -107,47 +81,100 @@ export class Config {
|
|
|
107
81
|
return { token, spaceId, cellId };
|
|
108
82
|
}
|
|
109
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Update the config with a partial config map.
|
|
86
|
+
*
|
|
87
|
+
* This will write only the updated keys in the config file on disk. Not all
|
|
88
|
+
* keys are written, since some current keys in the Config object may have
|
|
89
|
+
* come from e.g. environment variables, rather than the original config
|
|
90
|
+
* file.
|
|
91
|
+
*
|
|
92
|
+
* @param config The config update.
|
|
93
|
+
*/
|
|
94
|
+
async update(config: Partial<ConfigMap>) {
|
|
95
|
+
Object.assign(this.#configMap, config);
|
|
96
|
+
|
|
97
|
+
const currentConfigFile = await Config.#readConfigFile(
|
|
98
|
+
this.#configFilePath,
|
|
99
|
+
);
|
|
100
|
+
Object.assign(currentConfigFile, config);
|
|
101
|
+
await fs.promises.writeFile(
|
|
102
|
+
this.#configFilePath,
|
|
103
|
+
JSON.stringify(currentConfigFile, null, 2),
|
|
104
|
+
"utf-8",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
110
108
|
static async load(opts: {
|
|
111
109
|
configFilePath: string;
|
|
112
110
|
processEnv: NodeJS.ProcessEnv;
|
|
113
111
|
flags: GlobalFlags;
|
|
114
112
|
}) {
|
|
115
113
|
const absConfigFilePath = path.resolve(process.cwd(), opts.configFilePath);
|
|
116
|
-
const
|
|
114
|
+
const partialConfig = await Config.#readConfigFile(absConfigFilePath);
|
|
117
115
|
|
|
118
116
|
if (opts.processEnv.WORKERS_TOKEN) {
|
|
119
|
-
|
|
117
|
+
partialConfig.token = opts.processEnv.WORKERS_TOKEN;
|
|
120
118
|
}
|
|
121
119
|
if (opts.processEnv.WORKERS_ENVIRONMENT) {
|
|
122
|
-
|
|
120
|
+
partialConfig.environment = parseEnvironment(
|
|
123
121
|
opts.processEnv.WORKERS_ENVIRONMENT,
|
|
124
122
|
);
|
|
125
123
|
}
|
|
126
124
|
if (opts.processEnv.WORKERS_WORKER_ID) {
|
|
127
|
-
|
|
125
|
+
partialConfig.workerId = opts.processEnv.WORKERS_WORKER_ID;
|
|
128
126
|
}
|
|
129
127
|
if (opts.processEnv.WORKERS_BASE_URL) {
|
|
130
|
-
|
|
128
|
+
partialConfig.baseUrl = opts.processEnv.WORKERS_BASE_URL;
|
|
131
129
|
}
|
|
132
130
|
|
|
133
131
|
if (opts.flags.token) {
|
|
134
|
-
|
|
132
|
+
partialConfig.token = opts.flags.token;
|
|
135
133
|
}
|
|
136
134
|
if (opts.flags.env) {
|
|
137
|
-
|
|
135
|
+
partialConfig.environment = parseEnvironment(opts.flags.env);
|
|
138
136
|
}
|
|
139
137
|
if (opts.flags["base-url"]) {
|
|
140
|
-
|
|
138
|
+
partialConfig.baseUrl = opts.flags["base-url"];
|
|
141
139
|
}
|
|
142
140
|
if (opts.flags["worker-id"]) {
|
|
143
|
-
|
|
141
|
+
partialConfig.workerId = opts.flags["worker-id"];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
partialConfig.baseUrl ??= baseUrlForEnvironment(
|
|
145
|
+
partialConfig.environment ?? "prod",
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const environment = partialConfig.environment;
|
|
149
|
+
if (!environment) {
|
|
150
|
+
throw new Error("Environment is required");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const baseUrl = partialConfig.baseUrl;
|
|
154
|
+
if (!baseUrl) {
|
|
155
|
+
throw new Error("Base URL is required");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const token = partialConfig.token;
|
|
159
|
+
if (token === undefined) {
|
|
160
|
+
throw new Error("Token is required");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const workerId = partialConfig.workerId;
|
|
164
|
+
if (workerId === undefined) {
|
|
165
|
+
throw new Error("Worker ID is required");
|
|
144
166
|
}
|
|
145
167
|
|
|
146
|
-
|
|
168
|
+
const configMap: ConfigMap = {
|
|
169
|
+
environment,
|
|
170
|
+
baseUrl,
|
|
171
|
+
token,
|
|
172
|
+
workerId,
|
|
173
|
+
};
|
|
147
174
|
|
|
148
175
|
return new Config({
|
|
149
176
|
configFilePath: absConfigFilePath,
|
|
150
|
-
|
|
177
|
+
configMap,
|
|
151
178
|
});
|
|
152
179
|
}
|
|
153
180
|
|
|
@@ -168,7 +195,7 @@ export class Config {
|
|
|
168
195
|
token: null,
|
|
169
196
|
workerId: null,
|
|
170
197
|
environment: "prod",
|
|
171
|
-
baseUrl:
|
|
198
|
+
baseUrl: baseUrlForEnvironment("prod"),
|
|
172
199
|
};
|
|
173
200
|
} else {
|
|
174
201
|
throw error;
|
|
@@ -227,7 +254,7 @@ export function extractPayloadFromToken(token: string): {
|
|
|
227
254
|
}
|
|
228
255
|
}
|
|
229
256
|
|
|
230
|
-
function
|
|
257
|
+
function baseUrlForEnvironment(environment: Environment): string {
|
|
231
258
|
switch (environment) {
|
|
232
259
|
case "local":
|
|
233
260
|
return "http://localhost:3000";
|
package/src/cli/context.ts
CHANGED
|
@@ -3,24 +3,24 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { StricliAutoCompleteContext } from "@stricli/auto-complete";
|
|
5
5
|
import type { CommandContext } from "@stricli/core";
|
|
6
|
-
import {
|
|
6
|
+
import { IO } from "./io.js";
|
|
7
7
|
|
|
8
8
|
export interface LocalContext
|
|
9
9
|
extends CommandContext,
|
|
10
10
|
StricliAutoCompleteContext {
|
|
11
11
|
readonly fs: typeof fs;
|
|
12
|
+
readonly io: IO;
|
|
12
13
|
readonly os: typeof os;
|
|
13
14
|
readonly path: typeof path;
|
|
14
15
|
readonly process: NodeJS.Process;
|
|
15
|
-
readonly writer: Writer;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function buildContext(process: NodeJS.Process): LocalContext {
|
|
19
19
|
return {
|
|
20
20
|
fs,
|
|
21
|
+
io: new IO({ debugEnabled: false }),
|
|
21
22
|
os,
|
|
22
23
|
path,
|
|
23
24
|
process,
|
|
24
|
-
writer: new Writer({ debugEnabled: false }),
|
|
25
25
|
};
|
|
26
26
|
}
|
package/src/cli/deploy.ts
CHANGED
|
@@ -53,7 +53,7 @@ export async function deployWorker(
|
|
|
53
53
|
|
|
54
54
|
// Resolve absolute path
|
|
55
55
|
const absPath = path.resolve(process.cwd(), workerPath);
|
|
56
|
-
context.
|
|
56
|
+
context.io.debug(`Deploying worker from: ${absPath}`);
|
|
57
57
|
|
|
58
58
|
// Create API client
|
|
59
59
|
const client = context.apiClient;
|
|
@@ -63,7 +63,7 @@ export async function deployWorker(
|
|
|
63
63
|
let workerId: string;
|
|
64
64
|
|
|
65
65
|
if ("workerId" in options) {
|
|
66
|
-
context.
|
|
66
|
+
context.io.writeErr(`Updating worker...`);
|
|
67
67
|
|
|
68
68
|
workerId = options.workerId;
|
|
69
69
|
|
|
@@ -73,13 +73,13 @@ export async function deployWorker(
|
|
|
73
73
|
uploadUrl = res.url;
|
|
74
74
|
uploadFields = res.fields;
|
|
75
75
|
} else {
|
|
76
|
-
context.
|
|
76
|
+
context.io.writeErr(
|
|
77
77
|
"Failed to generate pre-signed upload URL for worker bundle:",
|
|
78
78
|
);
|
|
79
79
|
throw new Error(updateResult.error.message);
|
|
80
80
|
}
|
|
81
81
|
} else {
|
|
82
|
-
context.
|
|
82
|
+
context.io.writeErr(`Creating worker...`);
|
|
83
83
|
|
|
84
84
|
const createResult = await client.createWorker(options.name);
|
|
85
85
|
if (Result.isSuccess(createResult)) {
|
|
@@ -93,20 +93,20 @@ export async function deployWorker(
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
context.
|
|
96
|
+
context.io.debug(`Generated upload URL: ${uploadUrl}`);
|
|
97
97
|
|
|
98
98
|
// Build the worker bundle
|
|
99
|
-
context.
|
|
99
|
+
context.io.writeErr("Building worker bundle...");
|
|
100
100
|
const archivePath = await buildWorkerBundle(context, absPath);
|
|
101
|
-
context.
|
|
101
|
+
context.io.debug(`Created bundle at: ${archivePath}`);
|
|
102
102
|
|
|
103
103
|
// Upload the bundle
|
|
104
|
-
context.
|
|
104
|
+
context.io.writeErr("Uploading bundle...");
|
|
105
105
|
await uploadBundle(uploadUrl, uploadFields, archivePath);
|
|
106
|
-
context.
|
|
106
|
+
context.io.debug("Upload complete");
|
|
107
107
|
|
|
108
108
|
// Fetch and save capabilities
|
|
109
|
-
context.
|
|
109
|
+
context.io.writeErr("Fetching and saving worker capabilities...");
|
|
110
110
|
const capabilitiesResult = await client.fetchAndSaveCapabilities(workerId);
|
|
111
111
|
|
|
112
112
|
if (Result.isSuccess(capabilitiesResult)) {
|
|
@@ -141,7 +141,7 @@ async function buildWorkerBundle(
|
|
|
141
141
|
platform: "node",
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
context.
|
|
144
|
+
context.io.debug(`Built bundle to: ${outdir}`);
|
|
145
145
|
|
|
146
146
|
// Create tar.gz archive
|
|
147
147
|
const archiveDir = fs.mkdtempSync("/tmp/workers-archive-");
|