@project-ajax/sdk 0.0.49 → 0.0.51

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.
Files changed (47) hide show
  1. package/dist/capabilities/sync.d.ts +5 -0
  2. package/dist/capabilities/sync.d.ts.map +1 -1
  3. package/dist/cli/api/client.d.ts +0 -8
  4. package/dist/cli/api/client.d.ts.map +1 -1
  5. package/dist/cli/api/client.js +4 -31
  6. package/dist/cli/commands/auth.d.ts.map +1 -1
  7. package/dist/cli/commands/auth.impl.d.ts +4 -9
  8. package/dist/cli/commands/auth.impl.d.ts.map +1 -1
  9. package/dist/cli/commands/auth.impl.js +4 -10
  10. package/dist/cli/commands/auth.impl.test.d.ts +2 -0
  11. package/dist/cli/commands/auth.impl.test.d.ts.map +1 -0
  12. package/dist/cli/commands/auth.js +1 -15
  13. package/dist/cli/commands/bundle.impl.test.d.ts +2 -0
  14. package/dist/cli/commands/bundle.impl.test.d.ts.map +1 -0
  15. package/dist/cli/commands/deploy.impl.test.d.ts +2 -0
  16. package/dist/cli/commands/deploy.impl.test.d.ts.map +1 -0
  17. package/dist/cli/commands/exec.impl.d.ts.map +1 -1
  18. package/dist/cli/commands/exec.impl.js +3 -0
  19. package/dist/cli/commands/utils/testing.d.ts +25 -0
  20. package/dist/cli/commands/utils/testing.d.ts.map +1 -0
  21. package/dist/cli/commands/utils/testing.js +51 -0
  22. package/dist/cli/config.d.ts +8 -8
  23. package/dist/cli/config.d.ts.map +1 -1
  24. package/dist/cli/config.js +55 -19
  25. package/dist/cli/config.test.d.ts +2 -0
  26. package/dist/cli/config.test.d.ts.map +1 -0
  27. package/dist/cli/flags.d.ts +5 -0
  28. package/dist/cli/flags.d.ts.map +1 -1
  29. package/dist/cli/flags.js +25 -0
  30. package/dist/cli/handler.d.ts.map +1 -1
  31. package/dist/cli/handler.js +3 -5
  32. package/package.json +2 -2
  33. package/src/capabilities/sync.ts +5 -0
  34. package/src/capabilities/tool.test.ts +51 -1
  35. package/src/cli/api/client.ts +3 -44
  36. package/src/cli/commands/.cursor/rules/testing-commands.mdc +212 -0
  37. package/src/cli/commands/auth.impl.test.ts +206 -0
  38. package/src/cli/commands/auth.impl.ts +5 -17
  39. package/src/cli/commands/auth.ts +2 -15
  40. package/src/cli/commands/bundle.impl.test.ts +137 -0
  41. package/src/cli/commands/deploy.impl.test.ts +239 -0
  42. package/src/cli/commands/exec.impl.ts +4 -0
  43. package/src/cli/commands/utils/testing.ts +60 -0
  44. package/src/cli/config.test.ts +114 -0
  45. package/src/cli/config.ts +68 -28
  46. package/src/cli/flags.ts +29 -0
  47. package/src/cli/handler.ts +2 -5
@@ -1,4 +1,12 @@
1
- import { describe, expect, it } from "vitest";
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ it,
7
+ type Mock,
8
+ vi,
9
+ } from "vitest";
2
10
  import {
3
11
  InvalidToolInputError,
4
12
  InvalidToolOutputError,
@@ -7,6 +15,18 @@ import {
7
15
  } from "./tool.js";
8
16
 
9
17
  describe("tool", () => {
18
+ let stdoutSpy: Mock<typeof process.stdout.write>;
19
+
20
+ beforeEach(() => {
21
+ stdoutSpy = vi
22
+ .spyOn(process.stdout, "write")
23
+ .mockImplementation(() => true);
24
+ });
25
+
26
+ afterEach(() => {
27
+ vi.restoreAllMocks();
28
+ });
29
+
10
30
  it("sync execution", async () => {
11
31
  const myTool = tool<{ name: string }, string>({
12
32
  title: "Say Hello",
@@ -30,6 +50,10 @@ describe("tool", () => {
30
50
  if (result._tag === "success") {
31
51
  expect(result.value).toBe("Hello, Alice!");
32
52
  }
53
+
54
+ expect(stdoutSpy).toHaveBeenCalledWith(
55
+ `\n<output>"Hello, Alice!"</output>\n`,
56
+ );
33
57
  });
34
58
 
35
59
  it("async execution", async () => {
@@ -57,6 +81,10 @@ describe("tool", () => {
57
81
  if (result._tag === "success") {
58
82
  expect(result.value).toEqual({ data: "Data for ID 42" });
59
83
  }
84
+
85
+ expect(stdoutSpy).toHaveBeenCalledWith(
86
+ `\n<output>{"data":"Data for ID 42"}</output>\n`,
87
+ );
60
88
  });
61
89
 
62
90
  it("execution error", async () => {
@@ -81,6 +109,10 @@ describe("tool", () => {
81
109
  expect(result.error).toBeInstanceOf(ToolExecutionError);
82
110
  expect(result.error.message).toBe("Something went wrong");
83
111
  }
112
+
113
+ expect(stdoutSpy).toHaveBeenCalledWith(
114
+ `\n<output>{"_tag":"error","error":{"name":"ToolExecutionError","message":"Something went wrong"}}</output>\n`,
115
+ );
84
116
  });
85
117
 
86
118
  it("invalid input", async () => {
@@ -107,6 +139,12 @@ describe("tool", () => {
107
139
  expect(result.error).toBeInstanceOf(InvalidToolInputError);
108
140
  expect(result.error.message).toContain("name");
109
141
  }
142
+
143
+ expect(stdoutSpy).toHaveBeenCalledWith(
144
+ expect.stringContaining(
145
+ `\n<output>{"_tag":"error","error":{"name":"InvalidToolInputError"`,
146
+ ),
147
+ );
110
148
  });
111
149
 
112
150
  it("invalid output", async () => {
@@ -140,6 +178,12 @@ describe("tool", () => {
140
178
  expect(result.error).toBeInstanceOf(InvalidToolOutputError);
141
179
  expect(result.error.message).toContain("result");
142
180
  }
181
+
182
+ expect(stdoutSpy).toHaveBeenCalledWith(
183
+ expect.stringContaining(
184
+ `\n<output>{"_tag":"error","error":{"name":"InvalidToolOutputError"`,
185
+ ),
186
+ );
143
187
  });
144
188
 
145
189
  it("invalid output with custom output schema", async () => {
@@ -181,5 +225,11 @@ describe("tool", () => {
181
225
  expect(result.error).toBeInstanceOf(InvalidToolOutputError);
182
226
  expect(result.error.message).toContain("message");
183
227
  }
228
+
229
+ expect(stdoutSpy).toHaveBeenCalledWith(
230
+ expect.stringContaining(
231
+ `\n<output>{"_tag":"error","error":{"name":"InvalidToolOutputError"`,
232
+ ),
233
+ );
184
234
  });
185
235
  });
@@ -29,65 +29,24 @@ export interface ApiError {
29
29
  };
30
30
  }
31
31
 
32
- /**
33
- * Get the base URL for the given environment
34
- */
35
- export function baseUrl({
36
- environment,
37
- override,
38
- }: {
39
- environment: Environment;
40
- override?: string | undefined;
41
- }): string {
42
- if (override) {
43
- return override;
44
- }
45
-
46
- switch (environment) {
47
- case "local":
48
- return "http://localhost:3000";
49
- case "staging":
50
- return "https://staging.notion.so";
51
- case "dev":
52
- return "https://dev.notion.so";
53
- case "prod":
54
- return "https://www.notion.so";
55
- }
56
- }
57
-
58
- /**
59
- * Get the base API URL for the given environment
60
- */
61
- function baseApiUrl({
62
- environment,
63
- override,
64
- }: {
65
- environment: Environment;
66
- override?: string | undefined;
67
- }): string {
68
- return `${baseUrl({ environment, override })}/api/v3`;
69
- }
70
-
71
32
  /**
72
33
  * API client for making authenticated requests to Workers endpoints
73
34
  */
74
35
  export class ApiClient {
75
36
  readonly #token: string;
76
- readonly #env: Environment;
77
37
  readonly #baseUrl: string | undefined;
78
38
  readonly #cellId: string;
79
39
  readonly #writer: Writer;
80
40
 
81
41
  constructor(config: ApiClientConfig) {
82
42
  this.#token = config.token;
83
- this.#env = config.environment;
84
43
  this.#baseUrl = config.baseUrl;
85
44
  this.#cellId = config.cellId;
86
45
  this.#writer = config.writer;
87
46
  }
88
47
 
89
- private baseApiUrl() {
90
- return baseApiUrl({ environment: this.#env, override: this.#baseUrl });
48
+ #baseApiUrl() {
49
+ return `${this.#baseUrl}/api/v3`;
91
50
  }
92
51
 
93
52
  /**
@@ -113,7 +72,7 @@ export class ApiClient {
113
72
  throw new Error("Endpoint must start with a slash (/)");
114
73
  }
115
74
 
116
- const url = `${this.baseApiUrl()}${endpoint}`;
75
+ const url = `${this.#baseApiUrl()}${endpoint}`;
117
76
 
118
77
  this.#writer.debug(`Fetching ${url}`);
119
78
  this.#writer.debug(
@@ -0,0 +1,212 @@
1
+ ---
2
+ description: Testing patterns for CLI command implementations
3
+ globs:
4
+ - "**/*.impl.test.ts"
5
+ alwaysApply: false
6
+ ---
7
+
8
+ # Testing CLI Commands
9
+
10
+ ## Understanding buildHandler
11
+
12
+ Commands are wrapped with `buildHandler` which:
13
+ 1. Returns a function that accepts `(flags, ...args)`
14
+ 2. Internally loads config using `Config.load()`
15
+ 3. Requires a `this` context with `process`, `fs`, `os`, `path`, and `writer`
16
+
17
+ ## Test Structure Pattern
18
+
19
+ ```typescript
20
+ describe("commandName", () => {
21
+ let stderrSpy: Mock<typeof process.stderr.write>; // or stdoutSpy
22
+
23
+ beforeEach(() => {
24
+ stderrSpy = vi
25
+ .spyOn(process.stderr, "write")
26
+ .mockImplementation(() => true);
27
+ });
28
+
29
+ it("does something", async () => {
30
+ // 1. Create a mock config with the desired state
31
+ const mockConfig = await createTestConfig({
32
+ token: "test-token",
33
+ workerId: null,
34
+ environment: "local",
35
+ baseUrl: "http://localhost:3000",
36
+ });
37
+
38
+ // 2. Spy on Config.load to return your mock config
39
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
40
+
41
+ // 3. Spy on config methods to verify they're called
42
+ const setTokenSpy = vi.spyOn(mockConfig, "setToken");
43
+
44
+ // 4. Create a base context
45
+ const context = createBaseContext();
46
+
47
+ // 5. Call the handler with .call(context, flags, ...args)
48
+ await commandHandler.call(context, baseFlags, "arg1", "arg2");
49
+
50
+ // 6. Assert on spies and output
51
+ expect(setTokenSpy).toHaveBeenCalledWith("expected-value");
52
+ expect(stderrSpy).toHaveBeenCalledWith(
53
+ expect.stringContaining("Expected message"),
54
+ );
55
+ });
56
+ });
57
+ ```
58
+
59
+ ## Key Testing Patterns
60
+
61
+ ### 1. Mocking Config.load
62
+
63
+ Always mock `Config.load` to return your test config. The handler loads config internally, so you can't pass it directly.
64
+
65
+ ```typescript
66
+ const mockConfig = await createTestConfig({
67
+ token: null,
68
+ workerId: null,
69
+ environment: "local",
70
+ baseUrl: "http://localhost:3000",
71
+ });
72
+
73
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
74
+ ```
75
+
76
+ ### 2. Creating Context
77
+
78
+ Handlers expect a context with specific properties:
79
+
80
+ ```typescript
81
+ function createBaseContext() {
82
+ return {
83
+ writer: new Writer({ debugEnabled: false }),
84
+ process,
85
+ fs,
86
+ os,
87
+ path,
88
+ };
89
+ }
90
+ ```
91
+
92
+ ### 3. Calling Handlers
93
+
94
+ Use `.call()` to provide the context:
95
+
96
+ ```typescript
97
+ await handler.call(context, flags, ...args);
98
+ ```
99
+
100
+ **Don't** call the handler directly without context - it will fail because `this.process` will be undefined.
101
+
102
+ ### 4. Verifying Config Updates
103
+
104
+ Spy on config methods to verify they were called, rather than checking state directly:
105
+
106
+ ```typescript
107
+ const setTokenSpy = vi.spyOn(mockConfig, "setToken");
108
+ await handler.call(context, flags);
109
+ expect(setTokenSpy).toHaveBeenCalledWith(expectedValue);
110
+ ```
111
+
112
+ Config methods like `setToken()`, `setEnvironment()`, and `setWorkerId()` write to the file asynchronously, so checking the config state immediately won't work.
113
+
114
+ ### 5. Mocking External Dependencies
115
+
116
+ Mock external modules before importing the implementation:
117
+
118
+ ```typescript
119
+ vi.mock("../utils/openUrl.js", () => ({
120
+ openNotionUrl: vi.fn().mockResolvedValue(undefined),
121
+ }));
122
+
123
+ import { commandHandler } from "./command.impl.js";
124
+ import { openNotionUrl } from "../utils/openUrl.js";
125
+
126
+ // In your test:
127
+ expect(openNotionUrl).toHaveBeenCalledWith("local", "http://...");
128
+
129
+ // For one-time failures:
130
+ vi.mocked(openNotionUrl).mockRejectedValueOnce(new Error("Failed"));
131
+ ```
132
+
133
+ ### 6. Capturing stdout/stderr
134
+
135
+ When testing output, spy on the write methods and check the content:
136
+
137
+ ```typescript
138
+ let stderrSpy: Mock<typeof process.stderr.write>;
139
+
140
+ beforeEach(() => {
141
+ stderrSpy = vi
142
+ .spyOn(process.stderr, "write")
143
+ .mockImplementation(() => true);
144
+ });
145
+
146
+ // For single messages:
147
+ expect(stderrSpy).toHaveBeenCalledWith(
148
+ expect.stringContaining("Expected message"),
149
+ );
150
+
151
+ // For multiple messages (concatenate all calls):
152
+ const allCalls = stderrSpy.mock.calls.map((call) => call[0]).join("");
153
+ expect(allCalls).toContain("Expected message");
154
+ ```
155
+
156
+ ## Helper Functions
157
+
158
+ Place helper functions at the bottom of test files:
159
+
160
+ ```typescript
161
+ // Test helpers
162
+
163
+ type ConfigFileContents = {
164
+ token: string | null;
165
+ workerId: string | null;
166
+ environment: Environment;
167
+ baseUrl: string;
168
+ };
169
+
170
+ const tmpDirectories: string[] = [];
171
+
172
+ const baseFlags: GlobalFlags = {
173
+ debug: false,
174
+ };
175
+
176
+ async function createConfigFile(contents: ConfigFileContents) {
177
+ const dir = await mkdtemp(path.join(tmpdir(), "test-prefix-"));
178
+ tmpDirectories.push(dir);
179
+ const configFilePath = path.join(dir, "config.json");
180
+ await writeFile(configFilePath, JSON.stringify(contents, null, 2), "utf-8");
181
+ return configFilePath;
182
+ }
183
+
184
+ async function createTestConfig(
185
+ configFileContents: ConfigFileContents,
186
+ ): Promise<Config> {
187
+ const configFilePath = await createConfigFile(configFileContents);
188
+ return Config.load({
189
+ configFilePath,
190
+ processEnv: {} as NodeJS.ProcessEnv,
191
+ flags: { debug: false },
192
+ });
193
+ }
194
+
195
+ function createBaseContext() {
196
+ return {
197
+ writer: new Writer({ debugEnabled: false }),
198
+ process,
199
+ fs,
200
+ os,
201
+ path,
202
+ };
203
+ }
204
+ ```
205
+
206
+ ## Common Mistakes to Avoid
207
+
208
+ 1. **Don't call handlers directly without context**: Always use `.call(context, ...)`
209
+ 2. **Don't check config state directly**: Spy on the setter methods instead
210
+ 3. **Don't forget to mock Config.load**: The handler loads config internally
211
+ 4. **Don't forget to create unique temp directories**: Use `mkdtemp` with unique prefixes
212
+ 5. **Don't forget to clean up temp files**: Use `afterEach` to remove temp directories
@@ -0,0 +1,206 @@
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ it,
7
+ type Mock,
8
+ vi,
9
+ } from "vitest";
10
+ import { Config } from "../config.js";
11
+ import {
12
+ baseFlags,
13
+ cleanupTmpDirectories,
14
+ createBaseContext,
15
+ createTestConfig,
16
+ } from "./utils/testing.js";
17
+
18
+ // Mock the openUrl module before importing the implementation
19
+ vi.mock("../utils/openUrl.js", () => ({
20
+ openNotionUrl: vi.fn().mockResolvedValue(undefined),
21
+ }));
22
+
23
+ import { openNotionUrl } from "../utils/openUrl.js";
24
+ import { login, logout, show } from "./auth.impl.js";
25
+
26
+ afterEach(cleanupTmpDirectories);
27
+
28
+ describe("login", () => {
29
+ let stderrSpy: Mock<typeof process.stderr.write>;
30
+
31
+ beforeEach(() => {
32
+ stderrSpy = vi
33
+ .spyOn(process.stderr, "write")
34
+ .mockImplementation(() => true);
35
+ });
36
+
37
+ it("opens browser and displays instructions when no token provided", async () => {
38
+ const mockConfig = await createTestConfig({
39
+ token: null,
40
+ workerId: null,
41
+ environment: "local",
42
+ baseUrl: "http://localhost:3000",
43
+ });
44
+
45
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
46
+
47
+ const context = createBaseContext();
48
+
49
+ await login.call(context, baseFlags);
50
+
51
+ expect(openNotionUrl).toHaveBeenCalledWith(
52
+ "local",
53
+ "http://localhost:3000/__workers__?createToken=true",
54
+ );
55
+
56
+ const allCalls = stderrSpy.mock.calls.map((call) => call[0]).join("");
57
+ expect(allCalls).toContain("Opening browser to create a token...");
58
+ expect(allCalls).toContain(
59
+ "http://localhost:3000/__workers__?createToken=true",
60
+ );
61
+ expect(allCalls).toContain("After creating a token, run:");
62
+ expect(allCalls).toContain("npx workers auth login <token>");
63
+ });
64
+
65
+ it("shows error message when browser fails to open", async () => {
66
+ const mockConfig = await createTestConfig({
67
+ token: null,
68
+ workerId: null,
69
+ environment: "local",
70
+ baseUrl: "http://localhost:3000",
71
+ });
72
+
73
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
74
+ vi.mocked(openNotionUrl).mockRejectedValueOnce(new Error("Failed to open"));
75
+
76
+ const context = createBaseContext();
77
+
78
+ await login.call(context, baseFlags);
79
+
80
+ const allCalls = stderrSpy.mock.calls.map((call) => call[0]).join("");
81
+ expect(allCalls).toContain("Failed to open browser automatically");
82
+ expect(allCalls).toContain(
83
+ "http://localhost:3000/__workers__?createToken=true",
84
+ );
85
+ });
86
+
87
+ it("saves token and clears workerId when token is provided", async () => {
88
+ const mockConfig = await createTestConfig({
89
+ token: null,
90
+ workerId: null,
91
+ environment: "local",
92
+ baseUrl: "http://localhost:3000",
93
+ });
94
+
95
+ // Spy on Config.load to return our mock config
96
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
97
+
98
+ const testToken =
99
+ "1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
100
+
101
+ const setEnvironmentSpy = vi.spyOn(mockConfig, "setEnvironment");
102
+ const setTokenSpy = vi.spyOn(mockConfig, "setToken");
103
+ const setWorkerIdSpy = vi.spyOn(mockConfig, "setWorkerId");
104
+
105
+ const context = createBaseContext();
106
+
107
+ await login.call(context, baseFlags, testToken);
108
+
109
+ expect(setEnvironmentSpy).toHaveBeenCalledWith("local");
110
+ expect(setTokenSpy).toHaveBeenCalledWith(testToken);
111
+ expect(setWorkerIdSpy).toHaveBeenCalledWith(null);
112
+ expect(stderrSpy).toHaveBeenCalledWith(
113
+ expect.stringContaining("Successfully logged in!"),
114
+ );
115
+ });
116
+
117
+ it("saves environment from config when logging in", async () => {
118
+ const mockConfig = await createTestConfig({
119
+ token: null,
120
+ workerId: null,
121
+ environment: "prod",
122
+ baseUrl: "https://www.notion.so",
123
+ });
124
+
125
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
126
+
127
+ const testToken =
128
+ "1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
129
+
130
+ const setEnvironmentSpy = vi.spyOn(mockConfig, "setEnvironment");
131
+
132
+ const context = createBaseContext();
133
+
134
+ await login.call(context, baseFlags, testToken);
135
+
136
+ expect(setEnvironmentSpy).toHaveBeenCalledWith("prod");
137
+ });
138
+ });
139
+
140
+ describe("show", () => {
141
+ let stdoutSpy: Mock<typeof process.stdout.write>;
142
+
143
+ beforeEach(() => {
144
+ stdoutSpy = vi
145
+ .spyOn(process.stdout, "write")
146
+ .mockImplementation(() => true);
147
+ });
148
+
149
+ it("writes token to stdout when token exists", async () => {
150
+ const testToken =
151
+ "1.2.eyJzcGFjZUlkIjoic3BhY2UxIiwidXNlcklkIjoidXNlcjEiLCJjZWxsSWQiOiJjZWxsMSJ9.sig";
152
+
153
+ const mockConfig = await createTestConfig({
154
+ token: testToken,
155
+ workerId: "worker-1",
156
+ environment: "local",
157
+ baseUrl: "http://localhost:3000",
158
+ });
159
+
160
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
161
+
162
+ const context = createBaseContext();
163
+
164
+ await show.call(context, baseFlags);
165
+
166
+ expect(stdoutSpy).toHaveBeenCalledWith(`${testToken}\n`);
167
+ });
168
+
169
+ it("writes empty string to stdout when no token exists", async () => {
170
+ const mockConfig = await createTestConfig({
171
+ token: null,
172
+ workerId: null,
173
+ environment: "local",
174
+ baseUrl: "http://localhost:3000",
175
+ });
176
+
177
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
178
+
179
+ const context = createBaseContext();
180
+
181
+ await show.call(context, baseFlags);
182
+
183
+ expect(stdoutSpy).toHaveBeenCalledWith("\n");
184
+ });
185
+ });
186
+
187
+ describe("logout", () => {
188
+ it("calls setToken with null", async () => {
189
+ const mockConfig = await createTestConfig({
190
+ token: "existing-token",
191
+ workerId: "worker-1",
192
+ environment: "local",
193
+ baseUrl: "http://localhost:3000",
194
+ });
195
+
196
+ vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
197
+
198
+ const setTokenSpy = vi.spyOn(mockConfig, "setToken");
199
+
200
+ const context = createBaseContext();
201
+
202
+ await logout.call(context, baseFlags);
203
+
204
+ expect(setTokenSpy).toHaveBeenCalledWith(null);
205
+ });
206
+ });
@@ -1,30 +1,17 @@
1
- import { baseUrl } from "../api/client.js";
2
- import type { Environment } from "../config.js";
1
+ import type { GlobalFlags } from "../flags.js";
3
2
  import { buildHandler, type HandlerContext } from "../handler.js";
4
3
  import { openNotionUrl } from "../utils/openUrl.js";
5
4
 
6
- interface LoginFlags {
7
- env?: Environment;
8
- "base-url"?: string;
9
- }
10
-
11
5
  export const login = buildHandler(async function (
12
6
  this: HandlerContext,
13
- flags: LoginFlags,
7
+ _: GlobalFlags,
14
8
  token?: string,
15
9
  ) {
16
- const environment = flags.env ?? "prod";
17
-
18
- if (flags["base-url"]) {
19
- await this.config.setBaseUrl(flags["base-url"]);
20
- }
10
+ const environment = this.config.environment;
21
11
 
22
12
  // If no token provided, open the browser to get one
23
13
  if (!token) {
24
- const url = `${baseUrl({
25
- environment,
26
- override: this.config.baseUrl,
27
- })}/__workers__?createToken=true`;
14
+ const url = `${this.config.baseUrl}/__workers__?createToken=true`;
28
15
 
29
16
  this.writer.writeErr(`Opening browser to create a token...\n${url}\n`);
30
17
  this.writer.writeErr("After creating a token, run:");
@@ -43,6 +30,7 @@ export const login = buildHandler(async function (
43
30
 
44
31
  await this.config.setEnvironment(environment);
45
32
  await this.config.setToken(token);
33
+ await this.config.setWorkerId(null);
46
34
 
47
35
  this.writer.writeErr("Successfully logged in!");
48
36
  });
@@ -1,5 +1,4 @@
1
1
  import { buildCommand, buildRouteMap } from "@stricli/core";
2
- import { Environments } from "../config.js";
3
2
  import { globalFlags } from "../flags.js";
4
3
 
5
4
  export const authCommands = buildRouteMap({
@@ -9,7 +8,8 @@ export const authCommands = buildRouteMap({
9
8
  routes: {
10
9
  login: buildCommand({
11
10
  docs: {
12
- brief: "Login to the Project Ajax platform using a Workers API token",
11
+ brief:
12
+ "Login to the Project Ajax platform using a Workers API token; will clear existing token, environment, and worker ID",
13
13
  },
14
14
 
15
15
  parameters: {
@@ -26,19 +26,6 @@ export const authCommands = buildRouteMap({
26
26
  },
27
27
 
28
28
  flags: {
29
- env: {
30
- kind: "enum",
31
- values: Environments,
32
- brief: "The environment to use for the command",
33
- optional: true,
34
- },
35
- "base-url": {
36
- kind: "parsed",
37
- parse: String,
38
- brief: "The base URL to use for all API requests",
39
- optional: true,
40
- hidden: true,
41
- },
42
29
  ...globalFlags,
43
30
  },
44
31
  },