attio 0.0.1-experimental.20250303 → 0.0.1-experimental.20250311
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.
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { APP } from "../env.js";
|
|
3
|
+
import { handleError } from "./handle-error.js";
|
|
4
|
+
import { makeHeaders } from "./make-headers.js";
|
|
5
|
+
const workspacesResponseSchema = z.array(z.object({
|
|
6
|
+
workspace: z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
name: z.string(),
|
|
9
|
+
slug: z.string(),
|
|
10
|
+
}),
|
|
11
|
+
membership: z.object({
|
|
12
|
+
access_level: z.enum(["admin", "member", "suspended"]),
|
|
13
|
+
}),
|
|
14
|
+
}));
|
|
15
|
+
export async function fetchWorkspaces({ token }) {
|
|
16
|
+
const response = await fetch(`${APP}/api/common/workspaces`, {
|
|
17
|
+
method: "GET",
|
|
18
|
+
headers: makeHeaders(token),
|
|
19
|
+
});
|
|
20
|
+
await handleError(response);
|
|
21
|
+
return workspacesResponseSchema
|
|
22
|
+
.parse(await response.json())
|
|
23
|
+
.map(({ workspace, membership }) => ({ ...workspace, ...membership }));
|
|
24
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import chokidar from "chokidar";
|
|
2
2
|
import open from "open";
|
|
3
|
-
import { assign, setup, enqueueActions } from "xstate";
|
|
3
|
+
import { assign, setup, enqueueActions, fromPromise } from "xstate";
|
|
4
4
|
import { APP } from "../env.js";
|
|
5
5
|
import { completeBundleUpload } from "../api/complete-bundle-upload.js";
|
|
6
6
|
import { createDevVersion } from "../api/create-dev-version.js";
|
|
7
7
|
import { startGraphqlServer } from "../api/start-graphql-server.js";
|
|
8
8
|
import { startUpload } from "../api/start-upload.js";
|
|
9
9
|
import { loadAppConfigFile } from "../util/app-config.js";
|
|
10
|
-
import { loadDeveloperConfig, loadInitialDeveloperConfig, } from "../util/load-developer-config.js";
|
|
10
|
+
import { loadDeveloperConfig, loadInitialDeveloperConfig, saveTargetWorkspaceToConfig, } from "../util/load-developer-config.js";
|
|
11
11
|
import notifier from "node-notifier";
|
|
12
12
|
import { loadEnv } from "../util/load-env.js";
|
|
13
13
|
import { loadAttioCliPackageJson } from "../util/load-attio-cli-package-json.js";
|
|
@@ -23,7 +23,8 @@ import { clearTerminal } from "../util/clear-terminal.js";
|
|
|
23
23
|
import { setTerminalTitle } from "../util/set-terminal-title.js";
|
|
24
24
|
import { printInstallInstructions } from "../util/print-install-instructions.js";
|
|
25
25
|
import { printLogo } from "./actions.js";
|
|
26
|
-
import { fromCallbackWithErrorHandling } from "./actors.js";
|
|
26
|
+
import { askWithTypedChoices, fromCallbackWithErrorHandling } from "./actors.js";
|
|
27
|
+
import { fetchWorkspaces } from "../api/fetch-workspaces.js";
|
|
27
28
|
process.on("SIGINT", () => {
|
|
28
29
|
process.stdout.write("\x1B[?25h");
|
|
29
30
|
process.exit();
|
|
@@ -40,12 +41,18 @@ export const devMachine = setup({
|
|
|
40
41
|
guards: {
|
|
41
42
|
"have dev version": ({ context }) => Boolean(context.devVersion),
|
|
42
43
|
"have typescript errors": (_, params) => Boolean(params.typeScriptErrors?.length),
|
|
44
|
+
"have target workspace": (_, params) => Boolean(params.config?.target_workspace_id),
|
|
45
|
+
"have workspaces": (_, params) => Boolean(params.output?.length),
|
|
46
|
+
"is workspace admin": (_, params) => params.output.access_level === "admin",
|
|
47
|
+
"only one workspace and admin": (_, params) => params.output.length === 1 && params.output[0].access_level === "admin",
|
|
48
|
+
"only one workspace and not admin": (_, params) => params.output.length === 1 && params.output[0].access_level !== "admin",
|
|
43
49
|
},
|
|
44
50
|
actors: {
|
|
45
51
|
"javascript": jsMachine,
|
|
46
52
|
"typescript": tsMachine,
|
|
47
53
|
"env": envMachine,
|
|
48
54
|
"code-gen": codeGenMachine,
|
|
55
|
+
"askForWorkspace": askWithTypedChoices(),
|
|
49
56
|
"loadConfig": fromCallbackWithErrorHandling(({ sendBack }) => {
|
|
50
57
|
const config = loadInitialDeveloperConfig();
|
|
51
58
|
if (typeof config === "string") {
|
|
@@ -98,6 +105,15 @@ export const devMachine = setup({
|
|
|
98
105
|
}
|
|
99
106
|
};
|
|
100
107
|
}),
|
|
108
|
+
"loadWorkspaces": fromPromise(async ({ input }) => await fetchWorkspaces({ token: input.token })),
|
|
109
|
+
"loadWorkspaceDetails": fromPromise(async ({ input }) => {
|
|
110
|
+
const workspaces = await fetchWorkspaces({ token: input.config.token });
|
|
111
|
+
const workspace = workspaces.find((workspace) => workspace.id === input.config.target_workspace_id);
|
|
112
|
+
if (!workspace) {
|
|
113
|
+
throw new Error(`Workspace not found: ${input.config.target_workspace_id}`);
|
|
114
|
+
}
|
|
115
|
+
return workspace;
|
|
116
|
+
}),
|
|
101
117
|
"prepareUpload": fromCallbackWithErrorHandling(({ sendBack }) => {
|
|
102
118
|
const prepareUpload = async () => {
|
|
103
119
|
const config = await loadDeveloperConfig();
|
|
@@ -248,8 +264,8 @@ export const devMachine = setup({
|
|
|
248
264
|
printUploadError: (_, params) => {
|
|
249
265
|
printMessage(params.uploadError.message);
|
|
250
266
|
},
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
printError: (_, params) => {
|
|
268
|
+
printMessage(params.error);
|
|
253
269
|
},
|
|
254
270
|
printLogo: (_) => {
|
|
255
271
|
process.stdout.write("\x1B[?25l");
|
|
@@ -289,7 +305,7 @@ export const devMachine = setup({
|
|
|
289
305
|
open(`http://localhost:${context.graphqlPort}/graphql`);
|
|
290
306
|
},
|
|
291
307
|
openInstallPage: ({ context }) => {
|
|
292
|
-
open(`${APP}/
|
|
308
|
+
open(`${APP}/${context.workspace.slug}/settings/apps/${context.devVersion?.app_slug}`);
|
|
293
309
|
},
|
|
294
310
|
saveTypeScriptErrors: assign({
|
|
295
311
|
typeScriptErrors: (_, params) => params.errors,
|
|
@@ -329,6 +345,21 @@ export const devMachine = setup({
|
|
|
329
345
|
? `attio dev – ${context.devVersion.app_id}`
|
|
330
346
|
: `attio dev`);
|
|
331
347
|
},
|
|
348
|
+
setTargetWorkspace: assign({
|
|
349
|
+
config: (_, params) => ({
|
|
350
|
+
...params.config,
|
|
351
|
+
target_workspace_id: params.workspace.id,
|
|
352
|
+
}),
|
|
353
|
+
}),
|
|
354
|
+
saveTargetWorkspaceToConfig: (_, params) => {
|
|
355
|
+
saveTargetWorkspaceToConfig(params.workspace.id);
|
|
356
|
+
},
|
|
357
|
+
setWorkspaces: assign({
|
|
358
|
+
workspaces: (_, params) => params.output,
|
|
359
|
+
}),
|
|
360
|
+
setWorkspace: assign({
|
|
361
|
+
workspace: (_, params) => params.output,
|
|
362
|
+
}),
|
|
332
363
|
setSuccess: assign({
|
|
333
364
|
jsContents: (_, params) => params.contents,
|
|
334
365
|
lastSuccessfulJavaScriptBuild: (_, params) => params.time,
|
|
@@ -610,8 +641,9 @@ export const devMachine = setup({
|
|
|
610
641
|
"Read Config": {
|
|
611
642
|
on: {
|
|
612
643
|
"Initialized": {
|
|
613
|
-
target: "
|
|
644
|
+
target: "Choose Target Workspace",
|
|
614
645
|
actions: { type: "setConfig", params: ({ event }) => event },
|
|
646
|
+
reenter: true,
|
|
615
647
|
},
|
|
616
648
|
"Initialization Error": {
|
|
617
649
|
target: "No Config",
|
|
@@ -632,15 +664,175 @@ export const devMachine = setup({
|
|
|
632
664
|
"Auth Error": {
|
|
633
665
|
type: "final",
|
|
634
666
|
},
|
|
635
|
-
"
|
|
667
|
+
"Choose Target Workspace": {
|
|
668
|
+
states: {
|
|
669
|
+
"Need Target Workspace?": {
|
|
670
|
+
always: [
|
|
671
|
+
{
|
|
672
|
+
target: "#Dev Machine.Loading Workspace Details",
|
|
673
|
+
guard: { type: "have target workspace", params: ({ context }) => context },
|
|
674
|
+
reenter: true,
|
|
675
|
+
},
|
|
676
|
+
"Loading Workspaces",
|
|
677
|
+
],
|
|
678
|
+
},
|
|
679
|
+
"Loading Workspaces": {
|
|
680
|
+
invoke: {
|
|
681
|
+
src: "loadWorkspaces",
|
|
682
|
+
input: ({ context }) => ({ token: context.config.token }),
|
|
683
|
+
onDone: [
|
|
684
|
+
{
|
|
685
|
+
target: "#Dev Machine.Loading Workspace Details",
|
|
686
|
+
guard: {
|
|
687
|
+
type: "only one workspace and admin",
|
|
688
|
+
params: ({ event }) => event,
|
|
689
|
+
},
|
|
690
|
+
reenter: true,
|
|
691
|
+
actions: [
|
|
692
|
+
{
|
|
693
|
+
type: "setTargetWorkspace",
|
|
694
|
+
params: ({ context, event }) => ({
|
|
695
|
+
config: context.config,
|
|
696
|
+
workspace: event.output[0],
|
|
697
|
+
}),
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
type: "saveTargetWorkspaceToConfig",
|
|
701
|
+
params: ({ event }) => ({ workspace: event.output[0] }),
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
target: "#Dev Machine.Not admin of only workspace",
|
|
707
|
+
guard: {
|
|
708
|
+
type: "only one workspace and not admin",
|
|
709
|
+
params: ({ event }) => event,
|
|
710
|
+
},
|
|
711
|
+
reenter: true,
|
|
712
|
+
actions: {
|
|
713
|
+
type: "printError",
|
|
714
|
+
params: ({ event }) => ({
|
|
715
|
+
error: `You are not the admin of the workspace ${event.output[0].name}. Please ask an admin to make you an admin of the workspace or create your own workspace.
|
|
716
|
+
|
|
717
|
+
${APP}/welcome/workspace-details
|
|
718
|
+
`,
|
|
719
|
+
}),
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
target: "Ask for Workspace",
|
|
724
|
+
guard: { type: "have workspaces", params: ({ event }) => event },
|
|
725
|
+
actions: { type: "setWorkspaces", params: ({ event }) => event },
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
target: "No Workspaces",
|
|
729
|
+
reenter: true,
|
|
730
|
+
actions: {
|
|
731
|
+
type: "printError",
|
|
732
|
+
params: () => ({
|
|
733
|
+
error: `You are not the admin of any workspaces. Either request permission from an existing workspace or create your own.
|
|
734
|
+
|
|
735
|
+
${APP}/welcome/workspace-details
|
|
736
|
+
`,
|
|
737
|
+
}),
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
],
|
|
741
|
+
onError: {
|
|
742
|
+
target: "Failed to load workspaces",
|
|
743
|
+
actions: {
|
|
744
|
+
type: "printError",
|
|
745
|
+
params: ({ event }) => ({
|
|
746
|
+
error: `Failed to load workspaces: ${event.error}`,
|
|
747
|
+
}),
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
"Ask for Workspace": {
|
|
753
|
+
invoke: {
|
|
754
|
+
src: "askForWorkspace",
|
|
755
|
+
input: ({ context }) => ({
|
|
756
|
+
message: "Choose a workspace",
|
|
757
|
+
choices: context.workspaces.map((workspace) => ({
|
|
758
|
+
name: workspace.name,
|
|
759
|
+
value: workspace,
|
|
760
|
+
})),
|
|
761
|
+
}),
|
|
762
|
+
onDone: [
|
|
763
|
+
{
|
|
764
|
+
target: "#Dev Machine.Loading Workspace Details",
|
|
765
|
+
actions: [
|
|
766
|
+
{
|
|
767
|
+
type: "setTargetWorkspace",
|
|
768
|
+
params: ({ context, event }) => ({
|
|
769
|
+
config: context.config,
|
|
770
|
+
workspace: event.output,
|
|
771
|
+
}),
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
type: "saveTargetWorkspaceToConfig",
|
|
775
|
+
params: ({ event }) => ({ workspace: event.output }),
|
|
776
|
+
},
|
|
777
|
+
],
|
|
778
|
+
guard: { type: "is workspace admin", params: ({ event }) => event },
|
|
779
|
+
reenter: true,
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
target: "#Dev Machine.Require Admin Workspace",
|
|
783
|
+
reenter: true,
|
|
784
|
+
actions: {
|
|
785
|
+
type: "printError",
|
|
786
|
+
params: ({ event }) => ({
|
|
787
|
+
error: `You are not the admin of the workspace ${event.output.name}. Please ask an admin to make you an admin of the workspace or create your own workspace.
|
|
788
|
+
|
|
789
|
+
${APP}/welcome/workspace-details
|
|
790
|
+
`,
|
|
791
|
+
}),
|
|
792
|
+
},
|
|
793
|
+
},
|
|
794
|
+
],
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
"No Workspaces": {
|
|
798
|
+
type: "final",
|
|
799
|
+
},
|
|
800
|
+
"Failed to load workspaces": {
|
|
801
|
+
type: "final",
|
|
802
|
+
},
|
|
803
|
+
},
|
|
804
|
+
initial: "Need Target Workspace?",
|
|
805
|
+
},
|
|
806
|
+
"Require Admin Workspace": {
|
|
807
|
+
type: "final",
|
|
808
|
+
},
|
|
809
|
+
"Not admin of only workspace": {
|
|
636
810
|
type: "final",
|
|
637
811
|
},
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
812
|
+
"Loading Workspace Details": {
|
|
813
|
+
invoke: {
|
|
814
|
+
src: "loadWorkspaceDetails",
|
|
815
|
+
input: ({ context }) => ({
|
|
816
|
+
config: context.config,
|
|
817
|
+
}),
|
|
818
|
+
onDone: {
|
|
819
|
+
target: "Watching",
|
|
820
|
+
actions: { type: "setWorkspace", params: ({ event }) => event },
|
|
821
|
+
},
|
|
822
|
+
onError: {
|
|
823
|
+
target: "Failed to load workspaces",
|
|
824
|
+
actions: {
|
|
825
|
+
type: "printError",
|
|
826
|
+
params: () => ({
|
|
827
|
+
error: "Failed to load workspace details",
|
|
828
|
+
}),
|
|
829
|
+
},
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
"Failed to load workspaces": {
|
|
834
|
+
type: "final",
|
|
644
835
|
},
|
|
645
836
|
},
|
|
837
|
+
entry: "printLogo",
|
|
646
838
|
});
|
|
@@ -7,7 +7,7 @@ import { isValidSlug } from "./validate-slug.js";
|
|
|
7
7
|
export const initialDeveloperConfigSchema = z.object({
|
|
8
8
|
token: z.string(),
|
|
9
9
|
developer_slug: z.string(),
|
|
10
|
-
target_workspace_id: z.string().uuid(),
|
|
10
|
+
target_workspace_id: z.string().uuid().optional().nullable(),
|
|
11
11
|
});
|
|
12
12
|
const developerConfigSchema = initialDeveloperConfigSchema.extend({
|
|
13
13
|
developer_account_id: z.string(),
|
|
@@ -76,8 +76,16 @@ export async function loadDeveloperConfig() {
|
|
|
76
76
|
developer_slug: developerSlug,
|
|
77
77
|
developer_account_id: devAccount.developer_account.developer_account_id,
|
|
78
78
|
developer_account_member_id: devAccount.developer_account_member.developer_account_member_id,
|
|
79
|
-
target_workspace_id: initialDeveloperConfig.target_workspace_id,
|
|
79
|
+
target_workspace_id: initialDeveloperConfig.target_workspace_id ?? null,
|
|
80
80
|
});
|
|
81
81
|
writeFileSync(configFile.path, stringify(config));
|
|
82
82
|
return config;
|
|
83
83
|
}
|
|
84
|
+
export async function saveTargetWorkspaceToConfig(workspaceId) {
|
|
85
|
+
const configFile = readDeveloperConfigFile();
|
|
86
|
+
if (configFile === "No config file" || configFile === "Invalid config file")
|
|
87
|
+
return;
|
|
88
|
+
const config = developerConfigSchema.parse(configFile.contents);
|
|
89
|
+
config.target_workspace_id = workspaceId;
|
|
90
|
+
writeFileSync(configFile.path, stringify(config));
|
|
91
|
+
}
|