attio 0.0.1-experimental.20241226 → 0.0.1-experimental.20250108

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 (54) hide show
  1. package/lib/api/create-version.js +2 -2
  2. package/lib/attio-logo.js +24 -0
  3. package/lib/attio.js +17 -8
  4. package/lib/commands/build.js +18 -35
  5. package/lib/commands/connection/add.js +51 -168
  6. package/lib/commands/connection/index.js +9 -1
  7. package/lib/commands/connection/list.js +17 -47
  8. package/lib/commands/connection/remove.js +17 -65
  9. package/lib/commands/create.js +27 -126
  10. package/lib/commands/dev.js +17 -106
  11. package/lib/commands/version/create.js +17 -68
  12. package/lib/commands/version/index.js +11 -1
  13. package/lib/commands/version/invite.js +40 -84
  14. package/lib/commands/version/list.js +18 -40
  15. package/lib/commands/version/publish.js +40 -64
  16. package/lib/machines/actions.js +7 -0
  17. package/lib/machines/actors.js +26 -1
  18. package/lib/machines/add-connection-machine.js +169 -201
  19. package/lib/machines/build-machine.js +35 -4
  20. package/lib/machines/create-machine.js +95 -70
  21. package/lib/machines/create-version-machine.js +152 -7
  22. package/lib/machines/dev-machine.js +173 -53
  23. package/lib/machines/generate-invite-machine.js +64 -10
  24. package/lib/machines/list-connections-machine.js +57 -2
  25. package/lib/machines/list-versions-machine.js +47 -14
  26. package/lib/machines/publish-version-machine.js +45 -16
  27. package/lib/machines/remove-connection-machine.js +64 -17
  28. package/lib/machines/ts-machine.js +4 -1
  29. package/lib/server/attio-fetch.d.ts +3 -2
  30. package/lib/tsconfig.tsbuildinfo +1 -1
  31. package/lib/util/clear-terminal.js +4 -0
  32. package/lib/util/load-developer-config.js +2 -2
  33. package/lib/util/print-install-instructions.js +32 -0
  34. package/lib/util/print-message.js +9 -0
  35. package/lib/util/set-terminal-title.js +8 -0
  36. package/lib/util/text-gradient.js +28 -0
  37. package/lib/util/typescript.js +25 -0
  38. package/package.json +13 -12
  39. package/lib/components/BuildError.js +0 -46
  40. package/lib/components/BuildLog.js +0 -6
  41. package/lib/components/CodeGenErrors.js +0 -22
  42. package/lib/components/Disclaimer.js +0 -9
  43. package/lib/components/InitialInstructions.js +0 -69
  44. package/lib/components/Log.js +0 -69
  45. package/lib/components/Logo.js +0 -10
  46. package/lib/components/MultiSelect.js +0 -65
  47. package/lib/components/ScrollBox.js +0 -87
  48. package/lib/components/ScrollBox.store.js +0 -36
  49. package/lib/components/ScrollBox.util.js +0 -27
  50. package/lib/components/Select.js +0 -6
  51. package/lib/components/Table.js +0 -33
  52. package/lib/components/TypeScriptErrors.js +0 -38
  53. package/lib/hooks/useFullScreen.js +0 -22
  54. package/lib/hooks/useTerminalTitle.js +0 -11
@@ -10,12 +10,12 @@ const createVersionSchema = z.object({
10
10
  client_bundle_upload_url: z.string(),
11
11
  server_bundle_upload_url: z.string(),
12
12
  });
13
- export async function createVersion({ token, devSlug, appId, }) {
13
+ export async function createVersion({ token, devSlug, appId, major, }) {
14
14
  const response = await fetch(`${API}/developer-portal/accounts/${devSlug}/apps/${appId}/prod-versions`, {
15
15
  method: "POST",
16
16
  headers: makeHeaders(token),
17
17
  body: JSON.stringify({
18
- major: 1,
18
+ major,
19
19
  }),
20
20
  });
21
21
  await handleError(response);
@@ -0,0 +1,24 @@
1
+ export const attioLogo = `
2
+ ▟██▛╲
3
+ ▟██▛ ╲
4
+ ▟██▛ ╱
5
+ ▟██▛ ╱
6
+ ▟██▛ ╱ ▟█▛╲
7
+ 🬇██▛ ╱ ▟█▛ ╲
8
+ ▜█▙ ╱ 🬇██▙ ╱
9
+ ▜█▙╱ ▜█▙╱
10
+ `;
11
+ export const attioName = `
12
+
13
+
14
+ ▟ ▟ ██
15
+ ██ ██
16
+ ▟███▙▟ ████████████ ██ ▟███▙
17
+ ▟█ ██ ██ ██ ██ █ █
18
+ ██ ██ ██ ██ ██ █ █
19
+ ▜████▛█ ▜███ ▜███ ██ ▜███▛
20
+ `;
21
+ export const attioLogoAndName = `${attioLogo
22
+ .split("\n")
23
+ .map((line, i) => i < attioLogo.split("\n").length - 1 ? `${line} ${attioName.split("\n")[i] || ""}` : line)
24
+ .join("\n")}`;
package/lib/attio.js CHANGED
@@ -1,9 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import Pastel from "pastel";
3
- const app = new Pastel({
4
- name: "attio",
5
- description: "CLI for creating Attio extensions.",
6
- importMeta: import.meta,
7
- version: "0.0.1",
8
- });
9
- await app.run();
2
+ import { Command } from "commander";
3
+ import { create } from "./commands/create.js";
4
+ import { build } from "./commands/build.js";
5
+ import { dev } from "./commands/dev.js";
6
+ import { connection } from "./commands/connection/index.js";
7
+ import { version } from "./commands/version/index.js";
8
+ const program = new Command();
9
+ program
10
+ .name("attio")
11
+ .description("CLI tool to create Attio apps")
12
+ .version("0.0.1")
13
+ .addCommand(create, { isDefault: true })
14
+ .addCommand(build)
15
+ .addCommand(dev)
16
+ .addCommand(connection)
17
+ .addCommand(version)
18
+ .parse();
@@ -1,37 +1,20 @@
1
- import { useMachine } from "@xstate/react";
2
- import { Box, Text, useStdin } from "ink";
3
- import Spinner from "ink-spinner";
4
- import React from "react";
5
- import { renderBuildErrors } from "../components/BuildError.js";
6
- import { Logo } from "../components/Logo.js";
7
- import { renderTypeScriptErrors } from "../components/TypeScriptErrors.js";
1
+ import { Command, Option } from "commander";
2
+ import { createActor } from "xstate";
3
+ import { z } from "zod";
8
4
  import { buildMachine } from "../machines/build-machine.js";
9
- export const description = "Build your Attio extension locally";
10
- export default function Build() {
11
- const [snapshot] = useMachine(buildMachine);
12
- const jsError = snapshot.children.javascript?.getSnapshot().context.error;
13
- const tsErrors = snapshot.children.typescript?.getSnapshot().context.errors;
14
- const { isRawModeSupported } = useStdin();
15
- if (!isRawModeSupported) {
16
- return (React.createElement(React.Fragment, null,
17
- snapshot.matches("Building") && React.createElement(Text, null, "Building..."),
18
- snapshot.matches("Success") && React.createElement(Text, null, "Built!")));
5
+ export const optionsSchema = z.object({
6
+ dev: z.boolean().default(false),
7
+ });
8
+ export const build = new Command("build")
9
+ .description("Build your Attio extension locally")
10
+ .addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
11
+ .action((unparsedOptions) => {
12
+ const options = optionsSchema.parse(unparsedOptions);
13
+ const actor = createActor(buildMachine);
14
+ if (options.dev) {
15
+ actor.subscribe((state) => {
16
+ console.log("state:", state.value);
17
+ });
19
18
  }
20
- return (React.createElement(Box, { flexDirection: "column" },
21
- React.createElement(Logo, null),
22
- snapshot.matches("Building") && (React.createElement(Box, { flexDirection: "column" },
23
- React.createElement(Box, null,
24
- React.createElement(Text, null,
25
- "\uD83D\uDD28 Building...",
26
- " ",
27
- React.createElement(Text, { color: "green" },
28
- React.createElement(Spinner, { type: "dots" })))))),
29
- snapshot.matches("Success") && (React.createElement(Box, { flexDirection: "column" },
30
- React.createElement(Box, null,
31
- React.createElement(Text, null, "\u2705 Built!")))),
32
- snapshot.matches("Errored") && (React.createElement(Box, { flexDirection: "column", gap: 1 },
33
- jsError && renderBuildErrors(jsError),
34
- tsErrors && renderTypeScriptErrors(tsErrors),
35
- !jsError && !tsErrors && (React.createElement(Box, null,
36
- React.createElement(Text, null, "Unknown error")))))));
37
- }
19
+ actor.start();
20
+ });
@@ -1,184 +1,67 @@
1
- import { useMachine } from "@xstate/react";
2
- import { Box, Text } from "ink";
3
- import Spinner from "ink-spinner";
4
- import TextInput from "ink-text-input";
5
- import { option } from "pastel";
6
- import React from "react";
1
+ import { Command, Option } from "commander";
2
+ import { createActor } from "xstate";
7
3
  import { z } from "zod";
8
- import { InitialInstructions } from "../../components/InitialInstructions.js";
9
- import { Logo } from "../../components/Logo.js";
10
- import { Select } from "../../components/Select.js";
11
- import { addConnectionMachine, connectionTypes } from "../../machines/add-connection-machine.js";
12
- export const description = "Create a new connection for your Attio app";
13
- export const options = z.object({
14
- label: z
15
- .string()
16
- .optional()
17
- .describe(option({ description: "The label for your connection that will be displayed to users" })),
18
- description: z
19
- .string()
20
- .optional()
21
- .describe(option({
22
- description: "A more detailed description of your connection that will be displayed to users",
23
- })),
24
- type: z
25
- .enum(["secret", "oauth2-code"])
26
- .optional()
27
- .describe(option({ description: "The type of connection to create" })),
4
+ import { addConnectionMachine } from "../../machines/add-connection-machine.js";
5
+ export const optionsSchema = z.object({
6
+ label: z.string().optional(),
7
+ description: z.string().optional(),
8
+ type: z.enum(["secret", "oauth2-code"]).optional(),
28
9
  authorizeUrl: z
29
10
  .string()
30
11
  .url("Invalid URL, e.g. https://authorization-server.com/authorize")
31
12
  .startsWith("https://", { message: "Must provide secure authorize URL (https://...)" })
32
- .optional()
33
- .describe(option({ description: "The authorize URL for OAuth connection" })),
13
+ .optional(),
34
14
  accessTokenUrl: z
35
15
  .string()
36
16
  .url("Invalid URL, e.g. https://authorization-server.com/token")
37
17
  .startsWith("https://", { message: "Must provide secure access token URL (https://...)" })
38
- .optional()
39
- .describe(option({ description: "The access token URL for OAuth connection" })),
18
+ .optional(),
40
19
  scopes: z
41
20
  .string()
42
21
  .refine((value) => value.split(",").every((scope) => scope.trim().length > 0), {
43
22
  message: "Invalid OAuth scopes format. Must be a comma-delimited list of non-empty strings.",
44
23
  })
45
- .optional()
46
- .describe(option({ description: "A comma separated list of scopes for OAuth connection" })),
47
- clientId: z
48
- .string()
49
- .optional()
50
- .describe(option({ description: "The client ID for OAuth connection" })),
51
- clientSecret: z
52
- .string()
53
- .optional()
54
- .describe(option({ description: "The client secret for OAuth connection" })),
55
- dev: z
56
- .boolean()
57
- .default(false)
58
- .describe(option({ description: "Run in development mode (additional debugging info)" })),
24
+ .optional(),
25
+ clientId: z.string().optional(),
26
+ clientSecret: z.string().optional(),
27
+ dev: z.boolean().default(false),
59
28
  });
60
- export default function AddConnection({ options: { label, description, type: connectionType, authorizeUrl, accessTokenUrl, scopes, clientId, clientSecret, dev, }, }) {
61
- const [snapshot, send] = useMachine(addConnectionMachine, {
62
- input: {
63
- label,
64
- description,
65
- connectionType,
66
- authorizeUrl,
67
- accessTokenUrl,
68
- scopes,
69
- clientId,
70
- clientSecret,
71
- },
29
+ export const connectionAdd = new Command("add")
30
+ .description("Create a new connection for your Attio app")
31
+ .addOption(new Option("--label", "The label for your connection that will be displayed to users"))
32
+ .addOption(new Option("--description", "A more detailed description of your connection that will be displayed to users"))
33
+ .addOption(new Option("--type <type>", "The type of connection to create").choices([
34
+ "secret",
35
+ "oauth2-code",
36
+ ]))
37
+ .addOption(new Option("--authorize-url <url>", "The authorize URL for OAuth connection"))
38
+ .addOption(new Option("--access-token-url <url>", "The access token URL for OAuth connection"))
39
+ .addOption(new Option("--scopes <scopes>", "A comma separated list of scopes for OAuth connection"))
40
+ .addOption(new Option("--client-id <id>", "The client ID for OAuth connection"))
41
+ .addOption(new Option("--client-secret <secret>", "The client secret for OAuth connection"))
42
+ .addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
43
+ .action((unparsedOptions) => {
44
+ let options;
45
+ try {
46
+ options = optionsSchema.parse(unparsedOptions);
47
+ }
48
+ catch (error) {
49
+ if (error instanceof z.ZodError) {
50
+ process.stderr.write("\nInvalid options:\n");
51
+ error.errors.forEach((err) => {
52
+ process.stderr.write(`- ${err.path.map((p) => String(p).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)).join(".")}: ${err.message}\n`);
53
+ });
54
+ process.exit(1);
55
+ }
56
+ throw error;
57
+ }
58
+ const actor = createActor(addConnectionMachine, {
59
+ input: options,
72
60
  });
73
- return (React.createElement(Box, { flexDirection: "column" },
74
- dev && (React.createElement(Box, null,
75
- React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
76
- React.createElement(Logo, null),
77
- React.createElement(Box, { flexDirection: "column" },
78
- snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
79
- React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
80
- snapshot.context.connectionType && (React.createElement(Box, null,
81
- React.createElement(Text, null, "Connection Type: "),
82
- React.createElement(Text, { color: "green" }, snapshot.context.connectionType === "oauth2-code"
83
- ? "OAuth2 Code"
84
- : "Secret"))),
85
- snapshot.context.label && !snapshot.matches("Ask for label") && (React.createElement(Box, null,
86
- React.createElement(Text, null, "Label: "),
87
- React.createElement(Text, { color: "green" }, snapshot.context.label))),
88
- snapshot.context.description && !snapshot.matches("Ask for description") && (React.createElement(Box, null,
89
- React.createElement(Text, null, "Description: "),
90
- React.createElement(Text, { color: "green" }, snapshot.context.description))),
91
- snapshot.context.global !== undefined &&
92
- !snapshot.matches("Ask for global") && (React.createElement(Box, null,
93
- React.createElement(Text, null,
94
- snapshot.context.connectionType === "secret"
95
- ? "Secret"
96
- : "Token",
97
- " ",
98
- "will be created for:",
99
- " "),
100
- React.createElement(Text, { color: "green" }, snapshot.context.global
101
- ? "The entire workspace"
102
- : "An individual user"))),
103
- snapshot.context.connectionType === "oauth2-code" && (React.createElement(React.Fragment, null,
104
- snapshot.context.authorizeUrl &&
105
- !snapshot.matches("Ask for Authorize URL") && (React.createElement(Box, null,
106
- React.createElement(Text, null, "Authorize URL: "),
107
- React.createElement(Text, { color: "green" }, snapshot.context.authorizeUrl))),
108
- snapshot.context.accessTokenUrl &&
109
- !snapshot.matches("Ask for Access Token URL") && (React.createElement(Box, null,
110
- React.createElement(Text, null, "Access Token URL: "),
111
- React.createElement(Text, { color: "green" }, snapshot.context.accessTokenUrl))),
112
- snapshot.context.scopes && !snapshot.matches("Ask for Scopes") && (React.createElement(Box, null,
113
- React.createElement(Text, null, "Scopes: "),
114
- React.createElement(Text, { color: "green" }, snapshot.context.scopes))),
115
- snapshot.context.clientId &&
116
- !snapshot.matches("Ask for Client ID") && (React.createElement(Box, null,
117
- React.createElement(Text, null, "Client ID: "),
118
- React.createElement(Text, { color: "green" }, snapshot.context.clientId)))))),
119
- snapshot.matches("Ask for label") && (React.createElement(React.Fragment, null,
120
- React.createElement(Box, null,
121
- React.createElement(Text, null, "Provide a label for your connection. This is what your users will see.")),
122
- React.createElement(Box, { marginTop: 1 },
123
- React.createElement(Text, null, "> "),
124
- React.createElement(TextInput, { value: snapshot.context.label ?? "", onChange: (label) => send({ type: "Update Label", label }), onSubmit: () => send({ type: "Submit" }) })))),
125
- snapshot.matches("Ask for description") && (React.createElement(React.Fragment, null,
126
- React.createElement(Box, null,
127
- React.createElement(Text, null, "Provide an optional detailed description for your connection.")),
128
- React.createElement(Box, { marginTop: 1 },
129
- React.createElement(Text, null, "This will be displayed to users. (You can edit this later)")),
130
- React.createElement(Box, { marginTop: 1 },
131
- React.createElement(Text, null, "> "),
132
- React.createElement(TextInput, { value: snapshot.context.description ?? "", onChange: (description) => send({ type: "Update Description", description }), onSubmit: () => send({ type: "Submit" }) })))),
133
- snapshot.matches("Ask for connection type") && (React.createElement(React.Fragment, null,
134
- React.createElement(Box, null,
135
- React.createElement(Text, null, "What type of connection will this be?")),
136
- React.createElement(Box, null,
137
- React.createElement(Select, { items: connectionTypes, onSelect: (connectionType) => send({ type: "Choose Connection Type", connectionType }) })))),
138
- snapshot.matches("Ask for global") && (React.createElement(React.Fragment, null,
139
- React.createElement(Box, null,
140
- React.createElement(Text, null,
141
- "A",
142
- " ",
143
- snapshot.context.connectionType === "secret" ? "secret" : "token",
144
- " ",
145
- "will be created for:")),
146
- React.createElement(Box, null,
147
- React.createElement(Select, { items: [
148
- { value: false, label: "An individual user" },
149
- { value: true, label: "The entire workspace" },
150
- ], onSelect: (global) => send({ type: "Choose Global", global }) })))),
151
- snapshot.matches("Ask for Authorize URL") && (React.createElement(React.Fragment, null,
152
- React.createElement(Box, null,
153
- React.createElement(Text, null, "e.g. https://authorization-server.com/oauth/authorize")),
154
- React.createElement(Box, { marginTop: 1 },
155
- React.createElement(Text, null, "OAuth Authorize URL: "),
156
- React.createElement(TextInput, { value: snapshot.context.authorizeUrl ?? "", onChange: (authorizeUrl) => send({ type: "Update Authorize URL", authorizeUrl }), onSubmit: () => send({ type: "Submit" }) })))),
157
- snapshot.matches("Ask for Access Token URL") && (React.createElement(React.Fragment, null,
158
- React.createElement(Box, null,
159
- React.createElement(Text, null, "e.g. https://authorization-server.com/oauth/token")),
160
- React.createElement(Box, { marginTop: 1 },
161
- React.createElement(Text, null, "OAuth Access Token URL: "),
162
- React.createElement(TextInput, { value: snapshot.context.accessTokenUrl ?? "", onChange: (accessTokenUrl) => send({ type: "Update Access Token URL", accessTokenUrl }), onSubmit: () => send({ type: "Submit" }) })))),
163
- snapshot.matches("Ask for Scopes") && (React.createElement(React.Fragment, null,
164
- React.createElement(Box, null,
165
- React.createElement(Text, null, "e.g. profile,email,read,write")),
166
- React.createElement(Box, { marginTop: 1 },
167
- React.createElement(Text, null, "OAuth Scopes: (separated by commas) "),
168
- React.createElement(TextInput, { value: snapshot.context.scopes ?? "", onChange: (scopes) => send({ type: "Update Scopes", scopes }), onSubmit: () => send({ type: "Submit" }) })))),
169
- snapshot.matches("Ask for Client ID") && (React.createElement(React.Fragment, null,
170
- React.createElement(Box, null,
171
- React.createElement(Text, null, "OAuth Client ID: "),
172
- React.createElement(TextInput, { value: snapshot.context.clientId ?? "", onChange: (clientId) => send({ type: "Update Client ID", clientId }), onSubmit: () => send({ type: "Submit" }) })))),
173
- snapshot.matches("Ask for Client Secret") && (React.createElement(React.Fragment, null,
174
- React.createElement(Box, null,
175
- React.createElement(Text, null, "OAuth Client Secret: "),
176
- React.createElement(TextInput, { value: snapshot.context.clientSecret ?? "", mask: "*", onChange: (clientSecret) => send({ type: "Update Client Secret", clientSecret }), onSubmit: () => send({ type: "Submit" }) })))),
177
- snapshot.matches("Creating connection definition") && (React.createElement(Box, null,
178
- React.createElement(Text, null, "Creating connection definition..."),
179
- React.createElement(Text, { color: "green" },
180
- React.createElement(Spinner, { type: "dots" })))),
181
- snapshot.matches("Success") && (React.createElement(Text, { color: "green" }, "SUCCESS!! \uD83C\uDF89 Your connection has been created.")),
182
- snapshot.context.error && (React.createElement(Box, { marginTop: 1 },
183
- React.createElement(Text, { color: "red" }, snapshot.context.error))))));
184
- }
61
+ if (options.dev) {
62
+ actor.subscribe((state) => {
63
+ console.log("state:", state.value);
64
+ });
65
+ }
66
+ actor.start();
67
+ });
@@ -1 +1,9 @@
1
- export const description = "Manage app connections";
1
+ import { Command } from "commander";
2
+ import { connectionAdd } from "./add.js";
3
+ import { connectionList } from "./list.js";
4
+ import { connectionRemove } from "./remove.js";
5
+ export const connection = new Command("connection")
6
+ .description("Manage app connections")
7
+ .addCommand(connectionAdd)
8
+ .addCommand(connectionList)
9
+ .addCommand(connectionRemove);
@@ -1,50 +1,20 @@
1
- import { useMachine } from "@xstate/react";
2
- import { Box, Text } from "ink";
3
- import Spinner from "ink-spinner";
4
- import { option } from "pastel";
5
- import React from "react";
1
+ import { Command, Option } from "commander";
2
+ import { createActor } from "xstate";
6
3
  import { z } from "zod";
7
- import { InitialInstructions } from "../../components/InitialInstructions.js";
8
- import { Logo } from "../../components/Logo.js";
9
- import { Table } from "../../components/Table.js";
10
4
  import { listConnectionsMachine } from "../../machines/list-connections-machine.js";
11
- export const description = "List all connections for the current major version of your Attio app";
12
- export const options = z.object({
13
- dev: z
14
- .boolean()
15
- .default(false)
16
- .describe(option({ description: "Run in development mode (additional debugging info)" })),
5
+ export const optionsSchema = z.object({
6
+ dev: z.boolean().default(false),
7
+ });
8
+ export const connectionList = new Command("list")
9
+ .description("List all connections for the current major version of your Attio app")
10
+ .addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
11
+ .action((unparsedOptions) => {
12
+ const options = optionsSchema.parse(unparsedOptions);
13
+ const actor = createActor(listConnectionsMachine);
14
+ if (options.dev) {
15
+ actor.subscribe((state) => {
16
+ console.log("state:", state.value);
17
+ });
18
+ }
19
+ actor.start();
17
20
  });
18
- const connectionTypeNames = {
19
- "oauth2-code": "OAuth 2.0",
20
- "secret": "Secret",
21
- };
22
- export default function ListConnections({ options: { dev } }) {
23
- const [snapshot] = useMachine(listConnectionsMachine);
24
- return (React.createElement(Box, { flexDirection: "column" },
25
- dev && (React.createElement(Box, null,
26
- React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
27
- React.createElement(Logo, null),
28
- snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
29
- snapshot.matches("No Connections") && (React.createElement(Box, { flexDirection: "column" },
30
- React.createElement(Box, null,
31
- React.createElement(Text, { color: "redBright" }, "This app has no connections."),
32
- React.createElement(Text, null, " To add one, use:")),
33
- React.createElement(Box, { flexDirection: "column", borderStyle: "round", width: 27, paddingX: 1, marginBottom: 1 },
34
- React.createElement(Text, null, "attio connection add")))),
35
- snapshot.matches("Loading Connections") && (React.createElement(Box, { flexDirection: "column" },
36
- React.createElement(Box, null,
37
- React.createElement(Text, null, "Loading connections... "),
38
- React.createElement(Text, { color: "green" },
39
- React.createElement(Spinner, { type: "dots" }))))),
40
- snapshot.matches("Error") && (React.createElement(Box, null,
41
- React.createElement(Text, { color: "red" }, snapshot.context.error))),
42
- snapshot.matches("Display Connections") &&
43
- snapshot.context.connections &&
44
- snapshot.context.connections && (React.createElement(Box, null,
45
- React.createElement(Table, { rows: snapshot.context.connections.map((connection) => ({
46
- Label: connection.label,
47
- Global: connection.global ? "Yes" : "No",
48
- Type: connectionTypeNames[connection.connection_type],
49
- })) })))));
50
- }
@@ -1,68 +1,20 @@
1
- import { useMachine } from "@xstate/react";
2
- import { Box, Text } from "ink";
3
- import Spinner from "ink-spinner";
4
- import { option } from "pastel";
5
- import React from "react";
1
+ import { Command, Option } from "commander";
2
+ import { createActor } from "xstate";
6
3
  import { z } from "zod";
7
- import { InitialInstructions } from "../../components/InitialInstructions.js";
8
- import { Logo } from "../../components/Logo.js";
9
- import { Select } from "../../components/Select.js";
10
4
  import { removeConnectionMachine } from "../../machines/remove-connection-machine.js";
11
- export const description = "Remove a connection from your Attio app";
12
- export const options = z.object({
13
- dev: z
14
- .boolean()
15
- .default(false)
16
- .describe(option({ description: "Run in development mode (additional debugging info)" })),
5
+ export const optionsSchema = z.object({
6
+ dev: z.boolean().default(false),
7
+ });
8
+ export const connectionRemove = new Command("remove")
9
+ .description("Remove a connection from your Attio app")
10
+ .addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
11
+ .action((unparsedOptions) => {
12
+ const options = optionsSchema.parse(unparsedOptions);
13
+ const actor = createActor(removeConnectionMachine);
14
+ if (options.dev) {
15
+ actor.subscribe((state) => {
16
+ console.log("state:", state.value);
17
+ });
18
+ }
19
+ actor.start();
17
20
  });
18
- export default function RemoveConnection({ options: { dev } }) {
19
- const [snapshot, send] = useMachine(removeConnectionMachine);
20
- return (React.createElement(Box, { flexDirection: "column" },
21
- dev && (React.createElement(Box, null,
22
- React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
23
- React.createElement(Logo, null),
24
- snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
25
- snapshot.matches("No Connections") && (React.createElement(Box, { flexDirection: "column" },
26
- React.createElement(Box, null,
27
- React.createElement(Text, { color: "redBright" }, "This app has no connections to remove."),
28
- React.createElement(Text, null, " To add one, use:")),
29
- React.createElement(Box, { flexDirection: "column", borderStyle: "round", width: 27, paddingX: 1, marginBottom: 1 },
30
- React.createElement(Text, null, "attio connection add")))),
31
- snapshot.matches("Loading Connections") && (React.createElement(Box, { flexDirection: "column" },
32
- React.createElement(Box, null,
33
- React.createElement(Text, null, "Loading connections... "),
34
- React.createElement(Text, { color: "green" },
35
- React.createElement(Spinner, { type: "dots" }))))),
36
- snapshot.matches("Choosing a Connection") && snapshot.context.connections && (React.createElement(Box, { flexDirection: "column" },
37
- React.createElement(Box, null,
38
- React.createElement(Text, null, "Which connection would you like to remove?")),
39
- React.createElement(Box, null,
40
- React.createElement(Select, { items: snapshot.context.connections.map((connection) => ({
41
- value: connection.global,
42
- label: `${connection.label} (${connection.global ? "workspace" : "user"})`,
43
- })), onSelect: (global) => send({ type: "Connection Chosen", global }) })))),
44
- snapshot.matches("Confirm Removal") &&
45
- snapshot.context.global !== undefined &&
46
- snapshot.context.connections && (React.createElement(Box, { flexDirection: "column" },
47
- React.createElement(Box, null,
48
- React.createElement(Text, null,
49
- "Are you sure you want to remove \"",
50
- snapshot.context.connections.find(({ global }) => global === snapshot.context.global).label,
51
- "\"?")),
52
- React.createElement(Box, null,
53
- React.createElement(Select, { items: [
54
- { value: "Confirm", label: "Yes, remove it" },
55
- { value: "Cancel", label: "Cancel" },
56
- ], onSelect: (type) => send({ type }) })))),
57
- snapshot.matches("Removing connection definition") && (React.createElement(Box, { flexDirection: "column" },
58
- React.createElement(Box, null,
59
- React.createElement(Text, null, "Removing connection definition..."),
60
- React.createElement(Text, { color: "green" },
61
- React.createElement(Spinner, { type: "dots" }))))),
62
- snapshot.matches("Cancelled") && (React.createElement(Box, null,
63
- React.createElement(Text, null, "No connections have been removed."))),
64
- snapshot.matches("Success") && (React.createElement(Box, null,
65
- React.createElement(Text, { color: "green" }, "SUCCESS!! \uD83C\uDF89 Your connection has been removed."))),
66
- snapshot.matches("Error") && (React.createElement(Box, null,
67
- React.createElement(Text, { color: "red" }, snapshot.context.error)))));
68
- }