attio 0.0.1-experimental.20241219 → 0.0.1-experimental.20250101
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/lib/api/create-version.js +2 -2
- package/lib/attio-logo.js +24 -0
- package/lib/attio.js +17 -8
- package/lib/commands/build.js +18 -35
- package/lib/commands/connection/add.js +51 -168
- package/lib/commands/connection/index.js +9 -1
- package/lib/commands/connection/list.js +17 -47
- package/lib/commands/connection/remove.js +17 -65
- package/lib/commands/create.js +27 -126
- package/lib/commands/dev.js +17 -106
- package/lib/commands/version/create.js +17 -68
- package/lib/commands/version/index.js +11 -1
- package/lib/commands/version/invite.js +40 -84
- package/lib/commands/version/list.js +18 -40
- package/lib/commands/version/publish.js +40 -64
- package/lib/machines/actions.js +7 -0
- package/lib/machines/actors.js +7 -1
- package/lib/machines/add-connection-machine.js +169 -201
- package/lib/machines/build-machine.js +35 -4
- package/lib/machines/create-machine.js +95 -70
- package/lib/machines/create-version-machine.js +121 -4
- package/lib/machines/dev-machine.js +173 -53
- package/lib/machines/generate-invite-machine.js +64 -10
- package/lib/machines/list-connections-machine.js +57 -2
- package/lib/machines/list-versions-machine.js +33 -0
- package/lib/machines/publish-version-machine.js +45 -16
- package/lib/machines/remove-connection-machine.js +64 -17
- package/lib/machines/ts-machine.js +4 -1
- package/lib/schema.js +2 -2
- package/lib/util/clear-terminal.js +4 -0
- package/lib/util/load-developer-config.js +2 -2
- package/lib/util/print-install-instructions.js +32 -0
- package/lib/util/print-message.js +9 -0
- package/lib/util/set-terminal-title.js +8 -0
- package/lib/util/text-gradient.js +28 -0
- package/lib/util/typescript.js +25 -0
- package/package.json +13 -12
- package/schema.graphql +8 -1
- package/lib/components/BuildError.js +0 -46
- package/lib/components/BuildLog.js +0 -6
- package/lib/components/CodeGenErrors.js +0 -22
- package/lib/components/Disclaimer.js +0 -9
- package/lib/components/InitialInstructions.js +0 -69
- package/lib/components/Log.js +0 -69
- package/lib/components/Logo.js +0 -10
- package/lib/components/MultiSelect.js +0 -65
- package/lib/components/ScrollBox.js +0 -87
- package/lib/components/ScrollBox.store.js +0 -36
- package/lib/components/ScrollBox.util.js +0 -27
- package/lib/components/Select.js +0 -6
- package/lib/components/Table.js +0 -33
- package/lib/components/TypeScriptErrors.js +0 -38
- package/lib/hooks/useFullScreen.js +0 -22
- package/lib/hooks/useTerminalTitle.js +0 -11
package/lib/commands/create.js
CHANGED
|
@@ -1,131 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import Link from "ink-link";
|
|
5
|
-
import Spinner from "ink-spinner";
|
|
6
|
-
import TextInput from "ink-text-input";
|
|
7
|
-
import { option, argument } from "pastel";
|
|
8
|
-
import React from "react";
|
|
1
|
+
import { Argument, Command, Option } from "commander";
|
|
2
|
+
import { createActor } from "xstate";
|
|
9
3
|
import { z } from "zod";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const description = "Create a new Attio extension";
|
|
17
|
-
export const args = z.tuple([
|
|
18
|
-
z
|
|
19
|
-
.string()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe(argument({ name: "name", description: "Name of the extension" })),
|
|
22
|
-
]);
|
|
23
|
-
export const options = z.object({
|
|
24
|
-
title: z
|
|
25
|
-
.string()
|
|
26
|
-
.optional()
|
|
27
|
-
.describe(option({ description: 'Title of the extension (in "Title Case")' })),
|
|
28
|
-
language: z
|
|
29
|
-
.enum(["javascript", "typescript"])
|
|
30
|
-
.optional()
|
|
31
|
-
.describe(option({ description: "Language" })),
|
|
32
|
-
tool: z
|
|
33
|
-
.boolean()
|
|
34
|
-
.optional()
|
|
35
|
-
.describe(option({ description: "If you want to build a workflow tool" })),
|
|
36
|
-
action: z
|
|
37
|
-
.boolean()
|
|
38
|
-
.optional()
|
|
39
|
-
.default(true)
|
|
40
|
-
.describe(option({ description: "If you want to build an action button" })),
|
|
41
|
-
dev: z
|
|
42
|
-
.boolean()
|
|
43
|
-
.default(false)
|
|
44
|
-
.describe(option({ description: "Run in development mode (additional debugging info)" })),
|
|
4
|
+
import { createMachine } from "../machines/create-machine.js";
|
|
5
|
+
export const argsSchema = z.string().optional().default("");
|
|
6
|
+
export const optionsSchema = z.object({
|
|
7
|
+
title: z.string().optional(),
|
|
8
|
+
language: z.enum(["javascript", "typescript"]).optional(),
|
|
9
|
+
dev: z.boolean().default(false),
|
|
45
10
|
});
|
|
46
|
-
export
|
|
47
|
-
|
|
11
|
+
export const create = new Command("create")
|
|
12
|
+
.description("Create a new Attio app")
|
|
13
|
+
.addArgument(new Argument("<title>", 'Title of the extension (in "Title Case")').argOptional())
|
|
14
|
+
.addOption(new Option("--title <title>", 'Title of the extension (in "Title Case")'))
|
|
15
|
+
.addOption(new Option("--language <language>", "Language").choices(["javascript", "typescript"]))
|
|
16
|
+
.addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
|
|
17
|
+
.action((unparsedArgs, unparsedOptions) => {
|
|
18
|
+
const args = argsSchema.parse(unparsedArgs);
|
|
19
|
+
const options = optionsSchema.parse(unparsedOptions);
|
|
20
|
+
const actor = createActor(createMachine, {
|
|
48
21
|
input: {
|
|
49
|
-
title: title ||
|
|
50
|
-
language,
|
|
51
|
-
outlets: [tool ? "tool" : null, action ? "action" : null].filter(Boolean),
|
|
22
|
+
title: options.title || args,
|
|
23
|
+
language: options.language,
|
|
52
24
|
},
|
|
53
25
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))),
|
|
62
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
63
|
-
React.createElement(Box, { marginRight: 1 },
|
|
64
|
-
React.createElement(Text, null, "What would you like to call your new app? (in \"Title Case\")")),
|
|
65
|
-
React.createElement(Box, null,
|
|
66
|
-
React.createElement(Text, null, "> "),
|
|
67
|
-
React.createElement(Text, { color: "yellow" },
|
|
68
|
-
React.createElement(TextInput, { value: snapshot.context.title, onChange: (title) => send({ type: "Update Title", title }), onSubmit: () => send({ type: "Submit" }) })))))),
|
|
69
|
-
snapshot.matches("Ask for slug") && (React.createElement(Box, { flexDirection: "column" },
|
|
70
|
-
snapshot.context.error && (React.createElement(Box, null,
|
|
71
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))),
|
|
72
|
-
React.createElement(Box, null,
|
|
73
|
-
React.createElement(Box, { marginRight: 1 },
|
|
74
|
-
React.createElement(Text, null, "Please provide a slug for your extension:")),
|
|
75
|
-
React.createElement(Box, null,
|
|
76
|
-
React.createElement(Text, { color: "yellow" },
|
|
77
|
-
React.createElement(TextInput, { value: snapshot.context.appSlug, onChange: (appSlug) => send({ type: "Update Slug", appSlug }), onSubmit: () => send({ type: "Submit" }) })))))),
|
|
78
|
-
snapshot.matches("Ask for language") && (React.createElement(Box, { flexDirection: "column" },
|
|
79
|
-
React.createElement(Box, null,
|
|
80
|
-
React.createElement(Text, null, "What language would you like to use?")),
|
|
81
|
-
React.createElement(Box, null,
|
|
82
|
-
React.createElement(Select, { items: languages, onSelect: (language) => send({ type: "Choose Language", language }) })))),
|
|
83
|
-
snapshot.matches("Ask for outlets") && (React.createElement(Box, { flexDirection: "column" },
|
|
84
|
-
React.createElement(Box, null,
|
|
85
|
-
React.createElement(Box, { marginRight: 2 },
|
|
86
|
-
React.createElement(Text, null, "Which Attio Outlets would you like to use?")),
|
|
87
|
-
React.createElement(Link, { url: "https://attio.dev/docs/outlets" },
|
|
88
|
-
figures.info,
|
|
89
|
-
" Learn More")),
|
|
90
|
-
React.createElement(Box, null,
|
|
91
|
-
React.createElement(MultiSelect, { items: outlets, onSubmit: (outlets) => send({ type: "Choose Outlets", outlets }), requiredMin: 1 })))),
|
|
92
|
-
snapshot.matches("Creating Project") && (React.createElement(Box, { flexDirection: "column" },
|
|
93
|
-
React.createElement(Box, null,
|
|
94
|
-
React.createElement(Text, null,
|
|
95
|
-
"Creating \"",
|
|
96
|
-
snapshot.context.title,
|
|
97
|
-
"\"... "),
|
|
98
|
-
React.createElement(Text, { color: "green" },
|
|
99
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
100
|
-
snapshot.matches("Success") && (React.createElement(Box, { flexDirection: "column" },
|
|
101
|
-
React.createElement(Box, null,
|
|
102
|
-
React.createElement(Text, { color: "green" },
|
|
103
|
-
"SUCCESS!! \uD83C\uDF89 Your extension \"",
|
|
104
|
-
snapshot.context.title,
|
|
105
|
-
"\" has been created.")),
|
|
106
|
-
React.createElement(Box, { marginY: 1 },
|
|
107
|
-
React.createElement(Text, null, "To get started, run:")),
|
|
108
|
-
React.createElement(Box, { flexDirection: "column", borderStyle: "round", width: Math.max(20, snapshot.context.appSlug.length + 8), paddingX: 1, marginBottom: 1 },
|
|
109
|
-
React.createElement(Box, null,
|
|
110
|
-
React.createElement(Text, null,
|
|
111
|
-
"cd ",
|
|
112
|
-
snapshot.context.appSlug)),
|
|
113
|
-
React.createElement(Box, null,
|
|
114
|
-
React.createElement(Text, null, "npm install")),
|
|
115
|
-
React.createElement(Box, null,
|
|
116
|
-
React.createElement(Text, null, "npm run dev"))),
|
|
117
|
-
React.createElement(Box, { marginBottom: 1 },
|
|
118
|
-
React.createElement(Text, null,
|
|
119
|
-
"(",
|
|
120
|
-
React.createElement(Text, { color: "yellowBright" }, "yarn"),
|
|
121
|
-
",",
|
|
122
|
-
" ",
|
|
123
|
-
React.createElement(Text, { color: "yellowBright" }, "pnpm"),
|
|
124
|
-
", and",
|
|
125
|
-
" ",
|
|
126
|
-
React.createElement(Text, { color: "yellowBright" }, "bun"),
|
|
127
|
-
" also work!)")))),
|
|
128
|
-
snapshot.matches("Error") && (React.createElement(Box, { flexDirection: "column" },
|
|
129
|
-
React.createElement(Box, null,
|
|
130
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))))));
|
|
131
|
-
}
|
|
26
|
+
if (options.dev) {
|
|
27
|
+
actor.subscribe((state) => {
|
|
28
|
+
console.log("state:", state.value);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
actor.start();
|
|
32
|
+
});
|
package/lib/commands/dev.js
CHANGED
|
@@ -1,109 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Box, Text, useApp, useInput } from "ink";
|
|
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 { renderBuildErrors } from "../components/BuildError.js";
|
|
8
|
-
import { CodeGenError } from "../components/CodeGenErrors.js";
|
|
9
|
-
import { InitialInstructions } from "../components/InitialInstructions.js";
|
|
10
|
-
import { ScrollBox } from "../components/ScrollBox.js";
|
|
11
|
-
import { renderTypeScriptErrors } from "../components/TypeScriptErrors.js";
|
|
12
|
-
import { useFullScreen } from "../hooks/useFullScreen.js";
|
|
13
|
-
import { useTerminalTitle } from "../hooks/useTerminalTitle.js";
|
|
14
4
|
import { devMachine } from "../machines/dev-machine.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
export const optionsSchema = z.object({
|
|
6
|
+
dev: z.boolean().default(false),
|
|
7
|
+
});
|
|
8
|
+
export const dev = new Command("dev")
|
|
9
|
+
.description("Develop 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(devMachine);
|
|
14
|
+
if (options.dev) {
|
|
15
|
+
actor.subscribe((state) => {
|
|
16
|
+
console.log("state:", state.value);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
actor.start();
|
|
22
20
|
});
|
|
23
|
-
export default function Dev({ options: { debug } }) {
|
|
24
|
-
const [snapshot] = useMachine(devMachine);
|
|
25
|
-
const { exit } = useApp();
|
|
26
|
-
const fullScreen = useFullScreen();
|
|
27
|
-
const appId = snapshot.context.devVersion?.app_id;
|
|
28
|
-
useTerminalTitle(appId ? `attio dev – ${appId}` : `attio dev`);
|
|
29
|
-
const jsError = snapshot.children.javascript?.getSnapshot().context.error;
|
|
30
|
-
const jsTime = snapshot.children.javascript?.getSnapshot().context.time;
|
|
31
|
-
const tsErrors = snapshot.children.typescript?.getSnapshot().context.errors;
|
|
32
|
-
const tsTime = snapshot.children.typescript?.getSnapshot().context.time;
|
|
33
|
-
const codeGenError = snapshot.children["code-gen"]?.getSnapshot().context.error;
|
|
34
|
-
const hasErrors = Boolean(jsError || tsErrors || codeGenError);
|
|
35
|
-
const isNoConfig = snapshot.matches("No Config");
|
|
36
|
-
React.useEffect(() => {
|
|
37
|
-
if (isNoConfig) {
|
|
38
|
-
setTimeout(() => {
|
|
39
|
-
exit(new Error("No config found"));
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}, [exit, isNoConfig]);
|
|
43
|
-
useInput((input) => {
|
|
44
|
-
if (input === "q") {
|
|
45
|
-
exit();
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
return (React.createElement(Box, { flexDirection: "column", ...fullScreen },
|
|
49
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
50
|
-
debug && (React.createElement(Box, { flexDirection: "column", paddingX: 1, borderStyle: "round" },
|
|
51
|
-
React.createElement(Box, null,
|
|
52
|
-
React.createElement(Text, null,
|
|
53
|
-
"State: ",
|
|
54
|
-
JSON.stringify(snapshot.value))),
|
|
55
|
-
React.createElement(Box, null,
|
|
56
|
-
React.createElement(Text, null,
|
|
57
|
-
"Env: ",
|
|
58
|
-
JSON.stringify(snapshot.children.env?.getSnapshot().value))),
|
|
59
|
-
React.createElement(Box, null,
|
|
60
|
-
React.createElement(Text, null,
|
|
61
|
-
"Code Gen:",
|
|
62
|
-
" ",
|
|
63
|
-
JSON.stringify(snapshot.children["code-gen"]?.getSnapshot()?.value))),
|
|
64
|
-
snapshot.context.devVersion?.app_id && (React.createElement(Box, null,
|
|
65
|
-
React.createElement(Text, null,
|
|
66
|
-
"App ID: ",
|
|
67
|
-
snapshot.context.devVersion?.app_id))),
|
|
68
|
-
snapshot.context.devVersion?.app_dev_version_id && (React.createElement(Box, null,
|
|
69
|
-
React.createElement(Text, null,
|
|
70
|
-
"App Dev Version ID:",
|
|
71
|
-
" ",
|
|
72
|
-
snapshot.context.devVersion?.app_dev_version_id))))),
|
|
73
|
-
snapshot.context.lastSuccessfulJavaScriptBuild && (React.createElement(Box, null,
|
|
74
|
-
React.createElement(Text, null,
|
|
75
|
-
"\u2705 Last successful build was at",
|
|
76
|
-
" ",
|
|
77
|
-
React.createElement(PrettyDate, { date: snapshot.context.lastSuccessfulJavaScriptBuild }),
|
|
78
|
-
"."))),
|
|
79
|
-
React.createElement(Log, null),
|
|
80
|
-
jsError && jsTime && (React.createElement(Box, null,
|
|
81
|
-
React.createElement(Text, null,
|
|
82
|
-
"\u274C Last failed build was at ",
|
|
83
|
-
React.createElement(PrettyDate, { date: jsTime }),
|
|
84
|
-
"."))),
|
|
85
|
-
tsErrors && tsTime && (React.createElement(Box, null,
|
|
86
|
-
React.createElement(Text, null,
|
|
87
|
-
"\u274C Last failed TypeScript check was at ",
|
|
88
|
-
React.createElement(PrettyDate, { date: tsTime }),
|
|
89
|
-
"."))),
|
|
90
|
-
snapshot.matches("No Config") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
|
|
91
|
-
snapshot.matches("Watching") && (React.createElement(Box, null,
|
|
92
|
-
React.createElement(Text, null, "\uD83D\uDC40 Watching for changes... "))),
|
|
93
|
-
snapshot.matches({ Watching: { JavaScript: "Uploading" } }) && (React.createElement(Box, null,
|
|
94
|
-
React.createElement(Text, null, "\u267B\uFE0F Uploading bundles... "))),
|
|
95
|
-
snapshot.matches({ Watching: { JavaScript: "Upload Error" } }) && (React.createElement(Box, { flexDirection: "column" },
|
|
96
|
-
React.createElement(Box, null,
|
|
97
|
-
React.createElement(Text, { color: "redBright" }, "\u274C Upload Error"),
|
|
98
|
-
React.createElement(Text, null,
|
|
99
|
-
"\u2013 ",
|
|
100
|
-
snapshot.context.uploadError?.message)))),
|
|
101
|
-
snapshot.matches({ Watching: { Graphql: "Started" } }) && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
102
|
-
React.createElement(Text, null, "Press \"o\" to open GraphQL Explorer"))),
|
|
103
|
-
snapshot.matches({ Watching: { Onboarding: "Prompt to Install" } }) && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
104
|
-
React.createElement(Text, null, "\uD83D\uDEA8 IMPORTANT: You will need to install your app in your workspace. Press \"i\" to open the app settings page, and then click \"Install\".")))),
|
|
105
|
-
hasErrors && (React.createElement(ScrollBox, { borderStyle: "round", padding: 1 },
|
|
106
|
-
jsError && renderBuildErrors(jsError),
|
|
107
|
-
tsErrors && renderTypeScriptErrors(tsErrors),
|
|
108
|
-
codeGenError && React.createElement(CodeGenError, { error: codeGenError })))));
|
|
109
|
-
}
|
|
@@ -1,71 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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 { renderBuildErrors } from "../../components/BuildError.js";
|
|
8
|
-
import { InitialInstructions } from "../../components/InitialInstructions.js";
|
|
9
|
-
import { Logo } from "../../components/Logo.js";
|
|
10
4
|
import { createVersionMachine } from "../../machines/create-version-machine.js";
|
|
11
|
-
export const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
export const optionsSchema = z.object({
|
|
6
|
+
dev: z.boolean().default(false),
|
|
7
|
+
});
|
|
8
|
+
export const versionCreate = new Command("create")
|
|
9
|
+
.description("Create a new unpublished 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(createVersionMachine);
|
|
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 CreateVersion({ options: { dev } }) {
|
|
19
|
-
const [snapshot] = useMachine(createVersionMachine);
|
|
20
|
-
const { exit } = useApp();
|
|
21
|
-
const jsError = snapshot.children.javascript?.getSnapshot().context.error;
|
|
22
|
-
const version = snapshot.context.version;
|
|
23
|
-
const isBuildError = snapshot.matches({ JavaScript: "Build Error" });
|
|
24
|
-
React.useEffect(() => {
|
|
25
|
-
if (isBuildError) {
|
|
26
|
-
exit();
|
|
27
|
-
}
|
|
28
|
-
}, [isBuildError, exit]);
|
|
29
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
30
|
-
dev && (React.createElement(Box, null,
|
|
31
|
-
React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
|
|
32
|
-
React.createElement(Logo, null),
|
|
33
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
34
|
-
snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
|
|
35
|
-
snapshot.matches({ JavaScript: "Building" }) && (React.createElement(Box, null,
|
|
36
|
-
React.createElement(Text, null,
|
|
37
|
-
"\uD83D\uDD28 Building...",
|
|
38
|
-
" ",
|
|
39
|
-
React.createElement(Text, { color: "green" },
|
|
40
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
41
|
-
isBuildError && (React.createElement(Box, { flexDirection: "column", gap: 1 },
|
|
42
|
-
jsError && renderBuildErrors(jsError),
|
|
43
|
-
!jsError && (React.createElement(Box, null,
|
|
44
|
-
React.createElement(Text, null, "Unknown error"))))),
|
|
45
|
-
snapshot.matches("Creating version") && (React.createElement(Box, null,
|
|
46
|
-
React.createElement(Text, null,
|
|
47
|
-
"\u231B\uFE0F Creating new version...",
|
|
48
|
-
" ",
|
|
49
|
-
React.createElement(Text, { color: "green" },
|
|
50
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
51
|
-
snapshot.matches("Uploading") && (React.createElement(Box, null,
|
|
52
|
-
React.createElement(Text, null,
|
|
53
|
-
"\u231B\uFE0F Uploading...",
|
|
54
|
-
" ",
|
|
55
|
-
React.createElement(Text, { color: "green" },
|
|
56
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
57
|
-
snapshot.matches("Success") && (React.createElement(React.Fragment, null,
|
|
58
|
-
React.createElement(Box, null,
|
|
59
|
-
React.createElement(Text, { color: "green" },
|
|
60
|
-
"SUCCESS!! \uD83C\uDF89 Version ",
|
|
61
|
-
version?.major,
|
|
62
|
-
".",
|
|
63
|
-
version?.minor,
|
|
64
|
-
" successfully created.")),
|
|
65
|
-
React.createElement(Box, null,
|
|
66
|
-
React.createElement(Text, null, "When you're ready, you can publish it with:")),
|
|
67
|
-
React.createElement(Box, { flexDirection: "column", borderStyle: "round", width: 27, paddingX: 1, marginBottom: 1 },
|
|
68
|
-
React.createElement(Text, null, "attio version publish")))),
|
|
69
|
-
snapshot.context.error && (React.createElement(Box, { marginTop: 1 },
|
|
70
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))))));
|
|
71
|
-
}
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { versionCreate } from "./create.js";
|
|
3
|
+
import { versionList } from "./list.js";
|
|
4
|
+
import { versionInvite } from "./invite.js";
|
|
5
|
+
import { versionPublish } from "./publish.js";
|
|
6
|
+
export const version = new Command("version")
|
|
7
|
+
.description("Manage app versions")
|
|
8
|
+
.addCommand(versionCreate)
|
|
9
|
+
.addCommand(versionList)
|
|
10
|
+
.addCommand(versionInvite)
|
|
11
|
+
.addCommand(versionPublish);
|
|
@@ -1,92 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import Spinner from "ink-spinner";
|
|
4
|
-
import { argument, option } from "pastel";
|
|
5
|
-
import React from "react";
|
|
1
|
+
import { Argument, 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 { generateInviteMachine } from "../../machines/generate-invite-machine.js";
|
|
11
|
-
export const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
name: "version",
|
|
19
|
-
description: `The version to invite someone to (e.g: "1.0"). If you don't specify a version, you will be prompted to choose.`,
|
|
20
|
-
})),
|
|
21
|
-
]);
|
|
22
|
-
export const options = z.object({
|
|
23
|
-
dev: z
|
|
24
|
-
.boolean()
|
|
25
|
-
.default(false)
|
|
26
|
-
.describe(option({ description: "Run in development mode (additional debugging info)" })),
|
|
5
|
+
export const argsSchema = z
|
|
6
|
+
.string()
|
|
7
|
+
.regex(/^\d+\.\d+$/, 'Version must be in the format "major.minor" (e.g., "1.0")')
|
|
8
|
+
.optional()
|
|
9
|
+
.describe(`The version to invite someone to (e.g: "1.0"). If you don't specify a version, you will be prompted to choose.`);
|
|
10
|
+
export const optionsSchema = z.object({
|
|
11
|
+
dev: z.boolean().default(false),
|
|
27
12
|
});
|
|
28
|
-
export
|
|
29
|
-
|
|
13
|
+
export const versionInvite = new Command("invite")
|
|
14
|
+
.description("Generates an invite link to an unpublished production version of your Attio app")
|
|
15
|
+
.addArgument(new Argument("<version>", `The version to invite someone to (e.g: "1.0"). If you don't specify a version, you will be prompted to choose.`).argOptional())
|
|
16
|
+
.addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
|
|
17
|
+
.action((unparsedArgs, unparsedOptions) => {
|
|
18
|
+
const versionResult = argsSchema.safeParse(unparsedArgs);
|
|
19
|
+
const optionsResult = optionsSchema.safeParse(unparsedOptions);
|
|
20
|
+
if (!versionResult.success) {
|
|
21
|
+
process.stderr.write("\nInvalid version argument:\n");
|
|
22
|
+
versionResult.error.errors.forEach((err) => {
|
|
23
|
+
process.stderr.write(`- ${err.message}\n`);
|
|
24
|
+
});
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
if (!optionsResult.success) {
|
|
28
|
+
process.stderr.write("\nInvalid options:\n");
|
|
29
|
+
optionsResult.error.errors.forEach((err) => {
|
|
30
|
+
process.stderr.write(`- ${err.path.map((p) => String(p).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)).join(".")}: ${err.message}\n`);
|
|
31
|
+
});
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const version = versionResult.data;
|
|
35
|
+
const options = optionsResult.data;
|
|
36
|
+
const actor = createActor(generateInviteMachine, {
|
|
30
37
|
input: {
|
|
31
38
|
major: version ? Number(version.split(".")[0]) : undefined,
|
|
32
39
|
minor: version ? Number(version.split(".")[1]) : undefined,
|
|
33
40
|
},
|
|
34
41
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
else if (snapshot.matches("No unpublished versions")) {
|
|
43
|
-
stdout.write("No unpublished versions found.");
|
|
44
|
-
}
|
|
45
|
-
else if (snapshot.matches("Display Invite Link") && snapshot.context.inviteLink) {
|
|
46
|
-
stdout.write(snapshot.context.inviteLink);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}, [version, snapshot, stdout]);
|
|
50
|
-
if (version)
|
|
51
|
-
return null;
|
|
52
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
53
|
-
dev && (React.createElement(Box, null,
|
|
54
|
-
React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
|
|
55
|
-
React.createElement(Logo, null),
|
|
56
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
57
|
-
snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
|
|
58
|
-
snapshot.matches("Ask for version") && (React.createElement(Box, { flexDirection: "column" },
|
|
59
|
-
React.createElement(Box, null,
|
|
60
|
-
React.createElement(Text, null, "Select an unpublished version to invite someone to:")),
|
|
61
|
-
React.createElement(Box, null,
|
|
62
|
-
React.createElement(Select, { items: snapshot.context.versions.map((version) => ({
|
|
63
|
-
label: `${version.major}.${version.minor}`,
|
|
64
|
-
value: version,
|
|
65
|
-
})), onSelect: (version) => send({ type: "Select Version", version }) })))),
|
|
66
|
-
snapshot.matches("No unpublished versions") && (React.createElement(Box, null,
|
|
67
|
-
React.createElement(Text, null, "No unpublished versions found."))),
|
|
68
|
-
snapshot.matches("Generating Invite Link") && (React.createElement(Box, null,
|
|
69
|
-
React.createElement(Text, null,
|
|
70
|
-
"\u231B\uFE0F Generating invite link for version ",
|
|
71
|
-
major,
|
|
72
|
-
".",
|
|
73
|
-
minor,
|
|
74
|
-
"...",
|
|
75
|
-
" ",
|
|
76
|
-
React.createElement(Text, { color: "green" },
|
|
77
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
78
|
-
snapshot.matches("Display Invite Link") && (React.createElement(React.Fragment, null,
|
|
79
|
-
React.createElement(Box, null,
|
|
80
|
-
React.createElement(Text, { color: "green" }, "SUCCESS!! \uD83C\uDF89"),
|
|
81
|
-
React.createElement(Text, null,
|
|
82
|
-
" ",
|
|
83
|
-
"Invite link for version ",
|
|
84
|
-
major,
|
|
85
|
-
".",
|
|
86
|
-
minor,
|
|
87
|
-
" successfully generated. It will expire in 24 hours.")),
|
|
88
|
-
React.createElement(Box, { marginTop: 1 },
|
|
89
|
-
React.createElement(Text, { color: "blue" }, snapshot.context.inviteLink)))),
|
|
90
|
-
snapshot.context.error && (React.createElement(Box, { marginTop: 1 },
|
|
91
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))))));
|
|
92
|
-
}
|
|
42
|
+
if (options.dev) {
|
|
43
|
+
actor.subscribe((state) => {
|
|
44
|
+
console.log("state:", state.value);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
actor.start();
|
|
48
|
+
});
|
|
@@ -1,43 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import Spinner from "ink-spinner";
|
|
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 { Table } from "../../components/Table.js";
|
|
11
4
|
import { listVersionsMachine } from "../../machines/list-versions-machine.js";
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
export const optionsSchema = z.object({
|
|
6
|
+
dev: z.boolean().default(false),
|
|
7
|
+
});
|
|
8
|
+
export const versionList = new Command("list")
|
|
9
|
+
.description("List all versions of your Attio app")
|
|
10
|
+
.addOption(new Option("--dev", "Run in development mode (additional debugging info)"))
|
|
11
|
+
.alias("ls")
|
|
12
|
+
.action((unparsedOptions) => {
|
|
13
|
+
const options = optionsSchema.parse(unparsedOptions);
|
|
14
|
+
const actor = createActor(listVersionsMachine);
|
|
15
|
+
if (options.dev) {
|
|
16
|
+
actor.subscribe((state) => {
|
|
17
|
+
console.log("state:", state.value);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
actor.start();
|
|
19
21
|
});
|
|
20
|
-
export default function ListVersions({ options: { dev } }) {
|
|
21
|
-
const [snapshot] = useMachine(listVersionsMachine);
|
|
22
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
23
|
-
dev && (React.createElement(Box, null,
|
|
24
|
-
React.createElement(Text, null, JSON.stringify(snapshot.value, null, 2)))),
|
|
25
|
-
React.createElement(Logo, null),
|
|
26
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
27
|
-
snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
|
|
28
|
-
snapshot.matches("Fetching Versions") && (React.createElement(Box, null,
|
|
29
|
-
React.createElement(Text, null,
|
|
30
|
-
"\u231B\uFE0F Fetching versions...",
|
|
31
|
-
" ",
|
|
32
|
-
React.createElement(Text, { color: "green" },
|
|
33
|
-
React.createElement(Spinner, { type: "dots" }))))),
|
|
34
|
-
snapshot.matches("Display Versions") &&
|
|
35
|
-
(snapshot.context.versions.length > 0 ? (React.createElement(Table, { rows: snapshot.context.versions.map((version) => ({
|
|
36
|
-
Version: `${version.major}.${version.minor}`,
|
|
37
|
-
Published: version.is_published ? "Yes" : "No",
|
|
38
|
-
Installations: version.num_installations.toLocaleString(),
|
|
39
|
-
Created: formatDate(new Date(version.created_at), "MMMM d, yyyy, HH:mm"),
|
|
40
|
-
})) })) : (React.createElement(Text, null, "No production versions."))),
|
|
41
|
-
snapshot.context.error && (React.createElement(Box, { marginTop: 1 },
|
|
42
|
-
React.createElement(Text, { color: "red" }, snapshot.context.error))))));
|
|
43
|
-
}
|