@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
package/dist/cli/config.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GlobalFlags } from "./flags.js";
|
|
2
2
|
export declare const Environments: readonly ["local", "staging", "dev", "prod"];
|
|
3
3
|
export type Environment = (typeof Environments)[number];
|
|
4
|
-
interface ConfigMap {
|
|
4
|
+
export interface ConfigMap {
|
|
5
5
|
environment: Environment;
|
|
6
6
|
baseUrl: string;
|
|
7
7
|
token: string | null;
|
|
@@ -26,21 +26,29 @@ export declare class TokenNotSetError extends Error {
|
|
|
26
26
|
export declare class Config {
|
|
27
27
|
#private;
|
|
28
28
|
constructor(opts: {
|
|
29
|
+
configMap: ConfigMap;
|
|
29
30
|
configFilePath: string;
|
|
30
|
-
configFile: ConfigMap;
|
|
31
31
|
});
|
|
32
32
|
get baseUrl(): string;
|
|
33
33
|
get token(): string | null;
|
|
34
34
|
get environment(): "local" | "staging" | "dev" | "prod";
|
|
35
35
|
get workerId(): string | null;
|
|
36
|
-
setEnvironment(environment: Environment): Promise<void>;
|
|
37
|
-
setToken(token: string | null): Promise<void>;
|
|
38
|
-
setWorkerId(workerId: string | null): Promise<void>;
|
|
39
36
|
get tokenInfo(): {
|
|
40
37
|
token: string;
|
|
41
38
|
spaceId: string;
|
|
42
39
|
cellId: string;
|
|
43
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Update the config with a partial config map.
|
|
43
|
+
*
|
|
44
|
+
* This will write only the updated keys in the config file on disk. Not all
|
|
45
|
+
* keys are written, since some current keys in the Config object may have
|
|
46
|
+
* come from e.g. environment variables, rather than the original config
|
|
47
|
+
* file.
|
|
48
|
+
*
|
|
49
|
+
* @param config The config update.
|
|
50
|
+
*/
|
|
51
|
+
update(config: Partial<ConfigMap>): Promise<void>;
|
|
44
52
|
static load(opts: {
|
|
45
53
|
configFilePath: string;
|
|
46
54
|
processEnv: NodeJS.ProcessEnv;
|
|
@@ -52,5 +60,4 @@ export declare function extractPayloadFromToken(token: string): {
|
|
|
52
60
|
userId: string;
|
|
53
61
|
cellId: string;
|
|
54
62
|
};
|
|
55
|
-
export {};
|
|
56
63
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/cli/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,SAAS;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAM1D;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAEzC,OAAO,GAAE,MAA6D;CAKvE;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;;gBAIN,IAAI,EAAE;QACjB,SAAS,EAAE,SAAS,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;KACvB;IAOD,IAAI,OAAO,WAEV;IAED,IAAI,KAAK,kBAER;IAED,IAAI,WAAW,yCAEd;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,SAAS,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAQlE;IAED;;;;;;;;;OASG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;WAc1B,IAAI,CAAC,IAAI,EAAE;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;QAC9B,KAAK,EAAE,WAAW,CAAC;KACnB;CA+FD;AAQD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf,CAoCA"}
|
package/dist/cli/config.js
CHANGED
|
@@ -17,8 +17,8 @@ class Config {
|
|
|
17
17
|
#configMap;
|
|
18
18
|
#configFilePath;
|
|
19
19
|
constructor(opts) {
|
|
20
|
+
this.#configMap = opts.configMap;
|
|
20
21
|
this.#configFilePath = opts.configFilePath;
|
|
21
|
-
this.#configMap = opts.configFile;
|
|
22
22
|
}
|
|
23
23
|
// Getters read from the environment variables, and then the config file.
|
|
24
24
|
get baseUrl() {
|
|
@@ -33,27 +33,6 @@ class Config {
|
|
|
33
33
|
get workerId() {
|
|
34
34
|
return this.#configMap.workerId;
|
|
35
35
|
}
|
|
36
|
-
// Setters update the config file, and then write it to disk.
|
|
37
|
-
async setEnvironment(environment) {
|
|
38
|
-
this.#configMap.environment = environment;
|
|
39
|
-
this.#configMap.baseUrl = baseUrl(environment);
|
|
40
|
-
await this.#writeConfigFile();
|
|
41
|
-
}
|
|
42
|
-
async setToken(token) {
|
|
43
|
-
this.#configMap.token = token;
|
|
44
|
-
await this.#writeConfigFile();
|
|
45
|
-
}
|
|
46
|
-
async setWorkerId(workerId) {
|
|
47
|
-
this.#configMap.workerId = workerId;
|
|
48
|
-
await this.#writeConfigFile();
|
|
49
|
-
}
|
|
50
|
-
async #writeConfigFile() {
|
|
51
|
-
await fs.promises.writeFile(
|
|
52
|
-
this.#configFilePath,
|
|
53
|
-
JSON.stringify(this.#configMap, null, 2),
|
|
54
|
-
"utf-8"
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
36
|
get tokenInfo() {
|
|
58
37
|
const token = this.token;
|
|
59
38
|
if (!token) {
|
|
@@ -62,39 +41,85 @@ class Config {
|
|
|
62
41
|
const { spaceId, cellId } = extractPayloadFromToken(token);
|
|
63
42
|
return { token, spaceId, cellId };
|
|
64
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Update the config with a partial config map.
|
|
46
|
+
*
|
|
47
|
+
* This will write only the updated keys in the config file on disk. Not all
|
|
48
|
+
* keys are written, since some current keys in the Config object may have
|
|
49
|
+
* come from e.g. environment variables, rather than the original config
|
|
50
|
+
* file.
|
|
51
|
+
*
|
|
52
|
+
* @param config The config update.
|
|
53
|
+
*/
|
|
54
|
+
async update(config) {
|
|
55
|
+
Object.assign(this.#configMap, config);
|
|
56
|
+
const currentConfigFile = await Config.#readConfigFile(
|
|
57
|
+
this.#configFilePath
|
|
58
|
+
);
|
|
59
|
+
Object.assign(currentConfigFile, config);
|
|
60
|
+
await fs.promises.writeFile(
|
|
61
|
+
this.#configFilePath,
|
|
62
|
+
JSON.stringify(currentConfigFile, null, 2),
|
|
63
|
+
"utf-8"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
65
66
|
static async load(opts) {
|
|
66
67
|
const absConfigFilePath = path.resolve(process.cwd(), opts.configFilePath);
|
|
67
|
-
const
|
|
68
|
+
const partialConfig = await Config.#readConfigFile(absConfigFilePath);
|
|
68
69
|
if (opts.processEnv.WORKERS_TOKEN) {
|
|
69
|
-
|
|
70
|
+
partialConfig.token = opts.processEnv.WORKERS_TOKEN;
|
|
70
71
|
}
|
|
71
72
|
if (opts.processEnv.WORKERS_ENVIRONMENT) {
|
|
72
|
-
|
|
73
|
+
partialConfig.environment = parseEnvironment(
|
|
73
74
|
opts.processEnv.WORKERS_ENVIRONMENT
|
|
74
75
|
);
|
|
75
76
|
}
|
|
76
77
|
if (opts.processEnv.WORKERS_WORKER_ID) {
|
|
77
|
-
|
|
78
|
+
partialConfig.workerId = opts.processEnv.WORKERS_WORKER_ID;
|
|
78
79
|
}
|
|
79
80
|
if (opts.processEnv.WORKERS_BASE_URL) {
|
|
80
|
-
|
|
81
|
+
partialConfig.baseUrl = opts.processEnv.WORKERS_BASE_URL;
|
|
81
82
|
}
|
|
82
83
|
if (opts.flags.token) {
|
|
83
|
-
|
|
84
|
+
partialConfig.token = opts.flags.token;
|
|
84
85
|
}
|
|
85
86
|
if (opts.flags.env) {
|
|
86
|
-
|
|
87
|
+
partialConfig.environment = parseEnvironment(opts.flags.env);
|
|
87
88
|
}
|
|
88
89
|
if (opts.flags["base-url"]) {
|
|
89
|
-
|
|
90
|
+
partialConfig.baseUrl = opts.flags["base-url"];
|
|
90
91
|
}
|
|
91
92
|
if (opts.flags["worker-id"]) {
|
|
92
|
-
|
|
93
|
+
partialConfig.workerId = opts.flags["worker-id"];
|
|
94
|
+
}
|
|
95
|
+
partialConfig.baseUrl ??= baseUrlForEnvironment(
|
|
96
|
+
partialConfig.environment ?? "prod"
|
|
97
|
+
);
|
|
98
|
+
const environment = partialConfig.environment;
|
|
99
|
+
if (!environment) {
|
|
100
|
+
throw new Error("Environment is required");
|
|
101
|
+
}
|
|
102
|
+
const baseUrl = partialConfig.baseUrl;
|
|
103
|
+
if (!baseUrl) {
|
|
104
|
+
throw new Error("Base URL is required");
|
|
105
|
+
}
|
|
106
|
+
const token = partialConfig.token;
|
|
107
|
+
if (token === void 0) {
|
|
108
|
+
throw new Error("Token is required");
|
|
93
109
|
}
|
|
94
|
-
|
|
110
|
+
const workerId = partialConfig.workerId;
|
|
111
|
+
if (workerId === void 0) {
|
|
112
|
+
throw new Error("Worker ID is required");
|
|
113
|
+
}
|
|
114
|
+
const configMap = {
|
|
115
|
+
environment,
|
|
116
|
+
baseUrl,
|
|
117
|
+
token,
|
|
118
|
+
workerId
|
|
119
|
+
};
|
|
95
120
|
return new Config({
|
|
96
121
|
configFilePath: absConfigFilePath,
|
|
97
|
-
|
|
122
|
+
configMap
|
|
98
123
|
});
|
|
99
124
|
}
|
|
100
125
|
static async #readConfigFile(configFilePath) {
|
|
@@ -111,7 +136,7 @@ class Config {
|
|
|
111
136
|
token: null,
|
|
112
137
|
workerId: null,
|
|
113
138
|
environment: "prod",
|
|
114
|
-
baseUrl:
|
|
139
|
+
baseUrl: baseUrlForEnvironment("prod")
|
|
115
140
|
};
|
|
116
141
|
} else {
|
|
117
142
|
throw error;
|
|
@@ -151,7 +176,7 @@ function extractPayloadFromToken(token) {
|
|
|
151
176
|
throw new Error("Failed to parse token payload.");
|
|
152
177
|
}
|
|
153
178
|
}
|
|
154
|
-
function
|
|
179
|
+
function baseUrlForEnvironment(environment) {
|
|
155
180
|
switch (environment) {
|
|
156
181
|
case "local":
|
|
157
182
|
return "http://localhost:3000";
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ 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
|
export interface LocalContext extends CommandContext, StricliAutoCompleteContext {
|
|
8
8
|
readonly fs: typeof fs;
|
|
9
|
+
readonly io: IO;
|
|
9
10
|
readonly os: typeof os;
|
|
10
11
|
readonly path: typeof path;
|
|
11
12
|
readonly process: NodeJS.Process;
|
|
12
|
-
readonly writer: Writer;
|
|
13
13
|
}
|
|
14
14
|
export declare function buildContext(process: NodeJS.Process): LocalContext;
|
|
15
15
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/cli/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/cli/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,WAAW,YAChB,SAAQ,cAAc,EACrB,0BAA0B;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,YAAY,CAQlE"}
|
package/dist/cli/context.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { IO } from "./io.js";
|
|
5
5
|
function buildContext(process) {
|
|
6
6
|
return {
|
|
7
7
|
fs,
|
|
8
|
+
io: new IO({ debugEnabled: false }),
|
|
8
9
|
os,
|
|
9
10
|
path,
|
|
10
|
-
process
|
|
11
|
-
writer: new Writer({ debugEnabled: false })
|
|
11
|
+
process
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
export {
|
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.56",
|
|
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;
|
|
@@ -11,8 +11,8 @@ import { Config } from "../config.js";
|
|
|
11
11
|
import {
|
|
12
12
|
baseFlags,
|
|
13
13
|
cleanupTmpDirectories,
|
|
14
|
+
createAndLoadConfig,
|
|
14
15
|
createBaseContext,
|
|
15
|
-
createTestConfig,
|
|
16
16
|
} from "./utils/testing.js";
|
|
17
17
|
|
|
18
18
|
// Mock the openUrl module before importing the implementation
|
|
@@ -35,11 +35,13 @@ describe("login", () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it("opens browser and displays instructions when no token provided", async () => {
|
|
38
|
-
const mockConfig = await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
39
|
+
configFile: {
|
|
40
|
+
token: null,
|
|
41
|
+
workerId: null,
|
|
42
|
+
environment: "local",
|
|
43
|
+
baseUrl: "http://localhost:3000",
|
|
44
|
+
},
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -63,11 +65,13 @@ describe("login", () => {
|
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
it("shows error message when browser fails to open", async () => {
|
|
66
|
-
const mockConfig = await
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
69
|
+
configFile: {
|
|
70
|
+
token: null,
|
|
71
|
+
workerId: null,
|
|
72
|
+
environment: "local",
|
|
73
|
+
baseUrl: "http://localhost:3000",
|
|
74
|
+
},
|
|
71
75
|
});
|
|
72
76
|
|
|
73
77
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -85,11 +89,13 @@ describe("login", () => {
|
|
|
85
89
|
});
|
|
86
90
|
|
|
87
91
|
it("saves token and clears workerId when token is provided", async () => {
|
|
88
|
-
const mockConfig = await
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
93
|
+
configFile: {
|
|
94
|
+
token: null,
|
|
95
|
+
workerId: null,
|
|
96
|
+
environment: "local",
|
|
97
|
+
baseUrl: "http://localhost:3000",
|
|
98
|
+
},
|
|
93
99
|
});
|
|
94
100
|
|
|
95
101
|
// Spy on Config.load to return our mock config
|
|
@@ -98,28 +104,30 @@ describe("login", () => {
|
|
|
98
104
|
const testToken =
|
|
99
105
|
"1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
|
|
100
106
|
|
|
101
|
-
const
|
|
102
|
-
const setTokenSpy = vi.spyOn(mockConfig, "setToken");
|
|
103
|
-
const setWorkerIdSpy = vi.spyOn(mockConfig, "setWorkerId");
|
|
107
|
+
const updateSpy = vi.spyOn(mockConfig, "update");
|
|
104
108
|
|
|
105
109
|
const context = createBaseContext();
|
|
106
110
|
|
|
107
111
|
await login.call(context, baseFlags, testToken);
|
|
108
112
|
|
|
109
|
-
expect(
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
expect(updateSpy).toHaveBeenCalledWith({
|
|
114
|
+
environment: "local",
|
|
115
|
+
token: testToken,
|
|
116
|
+
workerId: null,
|
|
117
|
+
});
|
|
112
118
|
expect(stderrSpy).toHaveBeenCalledWith(
|
|
113
119
|
expect.stringContaining("Successfully logged in!"),
|
|
114
120
|
);
|
|
115
121
|
});
|
|
116
122
|
|
|
117
123
|
it("saves environment from config when logging in", async () => {
|
|
118
|
-
const mockConfig = await
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
125
|
+
configFile: {
|
|
126
|
+
token: null,
|
|
127
|
+
workerId: null,
|
|
128
|
+
environment: "prod",
|
|
129
|
+
baseUrl: "https://www.notion.so",
|
|
130
|
+
},
|
|
123
131
|
});
|
|
124
132
|
|
|
125
133
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -127,13 +135,17 @@ describe("login", () => {
|
|
|
127
135
|
const testToken =
|
|
128
136
|
"1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
|
|
129
137
|
|
|
130
|
-
const
|
|
138
|
+
const updateSpy = vi.spyOn(mockConfig, "update");
|
|
131
139
|
|
|
132
140
|
const context = createBaseContext();
|
|
133
141
|
|
|
134
142
|
await login.call(context, baseFlags, testToken);
|
|
135
143
|
|
|
136
|
-
expect(
|
|
144
|
+
expect(updateSpy).toHaveBeenCalledWith({
|
|
145
|
+
environment: "prod",
|
|
146
|
+
token: testToken,
|
|
147
|
+
workerId: null,
|
|
148
|
+
});
|
|
137
149
|
});
|
|
138
150
|
});
|
|
139
151
|
|
|
@@ -150,11 +162,13 @@ describe("show", () => {
|
|
|
150
162
|
const testToken =
|
|
151
163
|
"1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
|
|
152
164
|
|
|
153
|
-
const mockConfig = await
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
165
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
166
|
+
configFile: {
|
|
167
|
+
token: testToken,
|
|
168
|
+
workerId: "worker-1",
|
|
169
|
+
environment: "local",
|
|
170
|
+
baseUrl: "http://localhost:3000",
|
|
171
|
+
},
|
|
158
172
|
});
|
|
159
173
|
|
|
160
174
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -167,11 +181,13 @@ describe("show", () => {
|
|
|
167
181
|
});
|
|
168
182
|
|
|
169
183
|
it("writes empty string to stdout when no token exists", async () => {
|
|
170
|
-
const mockConfig = await
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
184
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
185
|
+
configFile: {
|
|
186
|
+
token: null,
|
|
187
|
+
workerId: null,
|
|
188
|
+
environment: "local",
|
|
189
|
+
baseUrl: "http://localhost:3000",
|
|
190
|
+
},
|
|
175
191
|
});
|
|
176
192
|
|
|
177
193
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
@@ -186,21 +202,25 @@ describe("show", () => {
|
|
|
186
202
|
|
|
187
203
|
describe("logout", () => {
|
|
188
204
|
it("calls setToken with null", async () => {
|
|
189
|
-
const mockConfig = await
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
205
|
+
const [mockConfig] = await createAndLoadConfig({
|
|
206
|
+
configFile: {
|
|
207
|
+
token: "existing-token",
|
|
208
|
+
workerId: "worker-1",
|
|
209
|
+
environment: "local",
|
|
210
|
+
baseUrl: "http://localhost:3000",
|
|
211
|
+
},
|
|
194
212
|
});
|
|
195
213
|
|
|
196
214
|
vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
|
|
197
215
|
|
|
198
|
-
const
|
|
216
|
+
const updateSpy = vi.spyOn(mockConfig, "update");
|
|
199
217
|
|
|
200
218
|
const context = createBaseContext();
|
|
201
219
|
|
|
202
220
|
await logout.call(context, baseFlags);
|
|
203
221
|
|
|
204
|
-
expect(
|
|
222
|
+
expect(updateSpy).toHaveBeenCalledWith({
|
|
223
|
+
token: null,
|
|
224
|
+
});
|
|
205
225
|
});
|
|
206
226
|
});
|