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
@@ -1,7 +1,12 @@
1
- import { assign, setup, fromCallback } from "xstate";
2
- import { fetchVersions } from "../api/fetch-versions.js";
1
+ import { assign, setup } from "xstate";
3
2
  import { emptyConfig } from "../schema.js";
4
- import { loadAppConfig, loadDeveloperConfig } from "./actors.js";
3
+ import { loadAppConfig, loadDeveloperConfig, fetchVersions } from "./actors.js";
4
+ import formatDate from "date-fns/format/index.js";
5
+ import { showError, printLogo } from "./actions.js";
6
+ import { printInstallInstructions } from "../util/print-install-instructions.js";
7
+ import Table from "cli-table3";
8
+ import chalk from "chalk";
9
+ import boxen from "boxen";
5
10
  export const connectionTypes = [
6
11
  { value: "secret", label: "Secret" },
7
12
  { value: "oauth2-code", label: "OAuth2" },
@@ -16,21 +21,41 @@ export const listVersionsMachine = setup({
16
21
  events: {},
17
22
  },
18
23
  actors: {
19
- fetchVersions: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, }, }) => {
20
- const getVersions = async () => {
21
- const versions = await fetchVersions({
22
- token,
23
- devSlug,
24
- appId: config.id,
25
- });
26
- sendBack({ type: "Versions Fetched", versions });
27
- };
28
- getVersions();
29
- }),
24
+ fetchVersions,
30
25
  loadDeveloperConfig,
31
26
  loadAppConfig,
32
27
  },
33
28
  actions: {
29
+ printLogo,
30
+ showError,
31
+ showConfigInstructions: ({ context }) => printInstallInstructions(context.configError),
32
+ showVersions: ({ context }) => {
33
+ if (context.versions.length === 0) {
34
+ process.stdout.write(chalk.red("\nNo versions found.\n\n"));
35
+ process.stdout.write("You can create a new version by running:\n");
36
+ process.stdout.write(boxen("attio version create", {
37
+ padding: 1,
38
+ margin: 1,
39
+ borderStyle: "round",
40
+ }));
41
+ return;
42
+ }
43
+ const table = new Table({
44
+ head: ["Version", "Published", "Installations", "Created"].map((h) => chalk.bold(h)),
45
+ style: {
46
+ head: [],
47
+ border: [],
48
+ },
49
+ colAligns: ["center", "center", "right", "left"],
50
+ });
51
+ table.push(...context.versions.map((version) => [
52
+ `${version.major}.${version.minor}`,
53
+ version.is_published ? "Yes" : "No",
54
+ version.num_installations.toLocaleString(),
55
+ formatDate(new Date(version.created_at), "MMMM d, yyyy, HH:mm"),
56
+ ]));
57
+ process.stdout.write(table.toString());
58
+ },
34
59
  clearError: assign({
35
60
  error: () => undefined,
36
61
  }),
@@ -75,6 +100,7 @@ export const listVersionsMachine = setup({
75
100
  },
76
101
  "Show config instructions": {
77
102
  type: "final",
103
+ entry: "showConfigInstructions",
78
104
  },
79
105
  "Loading App Config": {
80
106
  invoke: {
@@ -94,6 +120,7 @@ export const listVersionsMachine = setup({
94
120
  },
95
121
  "Error": {
96
122
  type: "final",
123
+ entry: { type: "showError", params: ({ context }) => ({ error: context.error }) },
97
124
  },
98
125
  "Fetching Versions": {
99
126
  on: {
@@ -101,6 +128,10 @@ export const listVersionsMachine = setup({
101
128
  target: "Display Versions",
102
129
  actions: { type: "setVersions", params: ({ event }) => event },
103
130
  },
131
+ "Error": {
132
+ target: "Error",
133
+ actions: { type: "setError", params: ({ event }) => event },
134
+ },
104
135
  },
105
136
  invoke: {
106
137
  src: "fetchVersions",
@@ -112,7 +143,9 @@ export const listVersionsMachine = setup({
112
143
  },
113
144
  "Display Versions": {
114
145
  type: "final",
146
+ entry: "showVersions",
115
147
  },
116
148
  },
117
149
  initial: "Loading Developer Config",
150
+ entry: "printLogo",
118
151
  });
@@ -2,7 +2,10 @@ import { assign, setup, fromCallback } from "xstate";
2
2
  import { fetchPublishableVersions } from "../api/fetch-versions.js";
3
3
  import { publishVersion } from "../api/publish-version.js";
4
4
  import { emptyConfig } from "../schema.js";
5
- import { loadAppConfig, loadDeveloperConfig } from "./actors.js";
5
+ import { askWithTypedChoices, loadAppConfig, loadDeveloperConfig } from "./actors.js";
6
+ import { printInstallInstructions } from "../util/print-install-instructions.js";
7
+ import { printLogo, showError } from "./actions.js";
8
+ import Spinner from "tiny-spinner";
6
9
  export const connectionTypes = [
7
10
  { value: "secret", label: "Secret" },
8
11
  { value: "oauth2-code", label: "OAuth2" },
@@ -18,30 +21,41 @@ export const publishVersionMachine = setup({
18
21
  input: {},
19
22
  },
20
23
  actors: {
24
+ askForVersion: askWithTypedChoices(),
21
25
  fetchVersions: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, }, }) => {
22
26
  const getVersions = async () => {
27
+ const spinner = new Spinner();
28
+ spinner.start("Loading versions...");
23
29
  const versions = await fetchPublishableVersions({
24
30
  token,
25
31
  devSlug,
26
32
  appId: config.id,
27
33
  });
34
+ spinner.success("Versions loaded");
28
35
  sendBack({ type: "Versions Fetched", versions });
29
36
  };
30
37
  getVersions();
31
38
  }),
32
- publishVersion: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, }, }) => {
39
+ publishVersion: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, major, minor, }, }) => {
33
40
  const add = async () => {
41
+ const spinner = new Spinner();
34
42
  try {
43
+ spinner.start(`Publishing version ${major}.${minor}...`);
44
+ if (major === undefined || minor === undefined) {
45
+ throw new Error("Major and minor must be provided");
46
+ }
35
47
  await publishVersion({
36
48
  token,
37
49
  devSlug,
38
50
  appId: config.id,
39
- major: config.major,
40
- minor: config.minor,
51
+ major,
52
+ minor,
41
53
  });
54
+ spinner.success(`Version ${major}.${minor} published successfully!`);
42
55
  sendBack({ type: "Success" });
43
56
  }
44
57
  catch (error) {
58
+ spinner.error("Error publishing version");
45
59
  sendBack({ type: "Error", error: error.message });
46
60
  }
47
61
  };
@@ -51,6 +65,12 @@ export const publishVersionMachine = setup({
51
65
  loadAppConfig,
52
66
  },
53
67
  actions: {
68
+ printLogo,
69
+ showError,
70
+ showConfigInstructions: ({ context }) => printInstallInstructions(context.configError),
71
+ showNoUnpublishedVersions: () => {
72
+ process.stdout.write("No unpublished versions found.\n");
73
+ },
54
74
  clearError: assign({
55
75
  error: () => undefined,
56
76
  }),
@@ -67,8 +87,8 @@ export const publishVersionMachine = setup({
67
87
  config: (_, params) => params.config,
68
88
  }),
69
89
  setVersion: assign({
70
- major: (_, params) => params.version.major,
71
- minor: (_, params) => params.version.minor,
90
+ major: (_, params) => params.output.major,
91
+ minor: (_, params) => params.output.minor,
72
92
  }),
73
93
  setVersions: assign({
74
94
  versions: (_, params) => params.versions,
@@ -105,6 +125,7 @@ export const publishVersionMachine = setup({
105
125
  },
106
126
  "Show config instructions": {
107
127
  type: "final",
128
+ entry: "showConfigInstructions",
108
129
  },
109
130
  "Loading App Config": {
110
131
  invoke: {
@@ -124,6 +145,7 @@ export const publishVersionMachine = setup({
124
145
  },
125
146
  "Error": {
126
147
  type: "final",
148
+ entry: { type: "showError", params: ({ context }) => ({ error: context.error }) },
127
149
  },
128
150
  "Success": {
129
151
  type: "final",
@@ -161,10 +183,7 @@ export const publishVersionMachine = setup({
161
183
  "Publishing": {
162
184
  invoke: {
163
185
  src: "publishVersion",
164
- input: ({ context }) => ({
165
- developer: context.developer,
166
- config: context.config,
167
- }),
186
+ input: ({ context }) => context,
168
187
  },
169
188
  on: {
170
189
  Success: {
@@ -179,12 +198,6 @@ export const publishVersionMachine = setup({
179
198
  },
180
199
  },
181
200
  "Ask for version": {
182
- on: {
183
- "Select Version": {
184
- target: "Publishing",
185
- actions: { type: "setVersion", params: ({ event }) => event },
186
- },
187
- },
188
201
  always: {
189
202
  target: "No unpublished versions",
190
203
  guard: {
@@ -192,10 +205,26 @@ export const publishVersionMachine = setup({
192
205
  params: ({ context }) => context,
193
206
  },
194
207
  },
208
+ invoke: {
209
+ src: "askForVersion",
210
+ input: ({ context }) => ({
211
+ message: "Select a version to publish:",
212
+ choices: context.versions.map((version) => ({
213
+ name: `${version.major}.${version.minor}`,
214
+ value: version,
215
+ })),
216
+ }),
217
+ onDone: {
218
+ target: "Publishing",
219
+ actions: { type: "setVersion", params: ({ event }) => event },
220
+ },
221
+ },
195
222
  },
196
223
  "No unpublished versions": {
197
224
  type: "final",
225
+ entry: "showNoUnpublishedVersions",
198
226
  },
199
227
  },
200
228
  initial: "Loading Developer Config",
229
+ entry: "printLogo",
201
230
  });
@@ -2,16 +2,23 @@ import { assign, setup, fromCallback } from "xstate";
2
2
  import { fetchConnections } from "../api/fetch-connections.js";
3
3
  import { removeConnectionDefinition } from "../api/remove-connection-definition.js";
4
4
  import { emptyConfig } from "../schema.js";
5
- import { loadAppConfig, loadDeveloperConfig } from "./actors.js";
5
+ import { askWithChoices, loadAppConfig, loadDeveloperConfig, confirm } from "./actors.js";
6
+ import { printInstallInstructions } from "../util/print-install-instructions.js";
7
+ import { showError, printLogo } from "./actions.js";
8
+ import Spinner from "tiny-spinner";
6
9
  export const removeConnectionMachine = setup({
7
10
  types: {
8
11
  context: {},
9
12
  events: {},
10
13
  },
11
14
  actors: {
15
+ askWithChoices,
16
+ confirm,
12
17
  removeConnectionDefinition: fromCallback(({ sendBack, input }) => {
13
18
  const add = async () => {
19
+ const spinner = new Spinner();
14
20
  try {
21
+ spinner.start("Removing connection...");
15
22
  await removeConnectionDefinition({
16
23
  token: input.developer.token,
17
24
  devSlug: input.developer.slug,
@@ -19,9 +26,11 @@ export const removeConnectionMachine = setup({
19
26
  global: input.global,
20
27
  major: input.config.major,
21
28
  });
29
+ spinner.success("Connection removed");
22
30
  sendBack({ type: "Success" });
23
31
  }
24
32
  catch (error) {
33
+ spinner.error("Error removing connection");
25
34
  sendBack({ type: "Error", error: error.message });
26
35
  }
27
36
  };
@@ -30,17 +39,34 @@ export const removeConnectionMachine = setup({
30
39
  loadDeveloperConfig,
31
40
  loadAppConfig,
32
41
  loadConnections: fromCallback(({ sendBack, input }) => {
42
+ const spinner = new Spinner();
43
+ spinner.start("Loading connections...");
33
44
  fetchConnections({
34
45
  token: input.developer.token,
35
46
  devSlug: input.developer.slug,
36
47
  appId: input.config.id,
37
48
  major: input.config.major,
38
49
  })
39
- .then((connections) => sendBack({ type: "Connections Loaded", connections }))
40
- .catch((error) => sendBack({ type: "Error", error: error.message }));
50
+ .then((connections) => {
51
+ spinner.success("Connections loaded");
52
+ sendBack({ type: "Connections Loaded", connections });
53
+ })
54
+ .catch((error) => {
55
+ spinner.error("Error loading connections");
56
+ sendBack({ type: "Error", error: error.message });
57
+ });
41
58
  }),
42
59
  },
43
60
  actions: {
61
+ printLogo,
62
+ showError,
63
+ showConfigInstructions: ({ context }) => printInstallInstructions(context.configError),
64
+ showCanceled: () => {
65
+ process.stdout.write("No connection removed.\n\n");
66
+ },
67
+ showNoConnections: () => {
68
+ process.stdout.write("This app has no connections to remove.\n\n");
69
+ },
44
70
  clearError: assign({
45
71
  error: () => undefined,
46
72
  }),
@@ -60,7 +86,7 @@ export const removeConnectionMachine = setup({
60
86
  connections: (_, params) => params.connections,
61
87
  }),
62
88
  setGlobal: assign({
63
- global: (_, params) => params.global,
89
+ global: (_, params) => params.output === "true",
64
90
  }),
65
91
  setOnlyConnection: assign({
66
92
  global: (_, params) => params.connections[0].global,
@@ -69,6 +95,7 @@ export const removeConnectionMachine = setup({
69
95
  guards: {
70
96
  "have more than one connection": (_, params) => Boolean(params.connections && params.connections.length > 1),
71
97
  "have only one connection": (_, params) => Boolean(params.connections && params.connections.length === 1),
98
+ "confirmed": (_, params) => params.output,
72
99
  },
73
100
  }).createMachine({
74
101
  context: ({ input }) => ({
@@ -95,6 +122,7 @@ export const removeConnectionMachine = setup({
95
122
  },
96
123
  "Show config instructions": {
97
124
  type: "final",
125
+ entry: "showConfigInstructions",
98
126
  },
99
127
  "Loading App Config": {
100
128
  invoke: {
@@ -113,6 +141,7 @@ export const removeConnectionMachine = setup({
113
141
  },
114
142
  "Error": {
115
143
  type: "final",
144
+ entry: { type: "showError", params: ({ context }) => ({ error: context.error }) },
116
145
  },
117
146
  "Removing connection definition": {
118
147
  invoke: {
@@ -177,30 +206,48 @@ export const removeConnectionMachine = setup({
177
206
  },
178
207
  "No Connections": {
179
208
  type: "final",
209
+ entry: "showNoConnections",
180
210
  },
181
211
  "Choosing a Connection": {
182
- on: {
183
- "Connection Chosen": {
212
+ invoke: {
213
+ src: "askWithChoices",
214
+ input: ({ context }) => ({
215
+ message: "Which connection would you like to remove?",
216
+ choices: context.connections.map((connection) => ({
217
+ name: `${connection.label} (${connection.global ? "workspace" : "user"})`,
218
+ value: connection.global ? "true" : "false",
219
+ })),
220
+ required: true,
221
+ }),
222
+ onDone: {
184
223
  target: "Confirm Removal",
185
- actions: {
186
- type: "setGlobal",
187
- params: ({ event }) => ({
188
- global: event.global,
189
- }),
190
- },
191
- reenter: true,
224
+ actions: { type: "setGlobal", params: ({ event }) => event },
192
225
  },
193
226
  },
194
227
  },
195
228
  "Confirm Removal": {
196
- on: {
197
- Confirm: "Removing connection definition",
198
- Cancel: "Cancelled",
229
+ invoke: {
230
+ src: "confirm",
231
+ input: ({ context }) => ({
232
+ message: `Are you sure you want to remove "${context.connections[0].label}"?`,
233
+ }),
234
+ onDone: [
235
+ {
236
+ target: "Removing connection definition",
237
+ guard: { type: "confirmed", params: ({ event }) => event },
238
+ },
239
+ {
240
+ target: "Canceled",
241
+ reenter: true,
242
+ },
243
+ ],
199
244
  },
200
245
  },
201
- "Cancelled": {
246
+ "Canceled": {
202
247
  type: "final",
248
+ entry: "showCanceled",
203
249
  },
204
250
  },
205
251
  initial: "Loading Developer Config",
252
+ entry: "printLogo",
206
253
  });
@@ -47,7 +47,10 @@ export const tsMachine = setup({
47
47
  clearTime: assign({
48
48
  time: () => undefined,
49
49
  }),
50
- raiseErrored: sendTo(({ context }) => context.parentRef, { type: "TypeScript Error" }),
50
+ raiseErrored: sendTo(({ context }) => context.parentRef, ({ context }) => ({
51
+ type: "TypeScript Error",
52
+ errors: context.errors,
53
+ })),
51
54
  raiseSuccess: sendTo(({ context }) => context.parentRef, { type: "TypeScript Success" }),
52
55
  setErrors: assign({
53
56
  errors: (_, params) => params.errors,
@@ -21,10 +21,11 @@ interface FetchAttioOptions {
21
21
  /**
22
22
  * The body to use in the request.
23
23
  *
24
- * In the Attio API, this is always an object with the single key "data".
24
+ * In the Attio API, this is always an object with key "data" or "filter".
25
25
  */
26
26
  body?: {
27
- data: Record<string, unknown>;
27
+ data?: Record<string, unknown>;
28
+ filter?: Record<string, unknown>;
28
29
  };
29
30
  }
30
31
  /**