attio 0.0.1-experimental.20250408 → 0.0.1-experimental.20250414
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/api.js +99 -31
- package/lib/api/fetcher.js +31 -27
- package/lib/api/schemas.js +6 -0
- package/lib/auth/auth.js +135 -97
- package/lib/auth/keychain.js +86 -43
- package/lib/build/server/generate-server-entry.js +6 -6
- package/lib/build.js +2 -2
- package/lib/commands/build/build-javascript.js +1 -1
- package/lib/commands/build/validate-typescript.js +1 -1
- package/lib/commands/build.js +2 -2
- package/lib/commands/dev/boot.js +9 -9
- package/lib/commands/dev/bundle-javascript.js +1 -1
- package/lib/commands/dev/onboarding.js +3 -3
- package/lib/commands/dev/prepare-build-contexts.js +1 -1
- package/lib/commands/dev/upload.js +4 -21
- package/lib/commands/dev.js +5 -4
- package/lib/commands/init/create-project.js +7 -39
- package/lib/commands/init.js +6 -14
- package/lib/commands/login.js +8 -2
- package/lib/commands/logout.js +8 -2
- package/lib/commands/version/create/bundle-javascript.js +3 -3
- package/lib/commands/version/create.js +14 -14
- package/lib/commands/version/list.js +4 -4
- package/lib/commands/whoami.js +7 -8
- package/lib/errors.js +1 -0
- package/lib/print-errors.js +165 -0
- package/lib/spinners/determine-workspace.spinner.js +3 -26
- package/lib/spinners/get-app-info.spinner.js +2 -2
- package/lib/spinners/get-app-slug-from-package-json.js +1 -20
- package/lib/spinners/get-versions.spinner.js +2 -2
- package/lib/util/copy-with-replace.js +2 -2
- package/lib/util/create-directory.js +1 -1
- package/lib/util/load-attio-cli-version.js +1 -26
- package/lib/util/upload-bundle.js +1 -1
- package/package.json +1 -1
- package/lib/auth/ensure-authed.js +0 -14
- package/lib/commands/dev/start-graphql-server.js +0 -32
- package/lib/commands/init/ask-language.js +0 -11
- package/lib/templates/javascript/.env +0 -12
- package/lib/templates/javascript/eslint.config.js +0 -48
- package/lib/templates/javascript/package.json +0 -26
- package/lib/templates/javascript/src/assets/icon.png +0 -0
- package/lib/templates/javascript/src/cat-fact.jsx +0 -16
- package/lib/templates/javascript/src/get-cat-fact.server.js +0 -6
- package/lib/templates/javascript/src/hello-world-action.jsx +0 -17
- package/lib/templates/javascript/src/hello-world-dialog.jsx +0 -26
- package/lib/templates/typescript/.eslintignore +0 -3
- package/lib/templates/typescript/src/assets/icon.png +0 -0
- /package/lib/{templates/typescript → template}/.env +0 -0
- /package/lib/{templates/javascript → template}/.eslintignore +0 -0
- /package/lib/{templates/common → template}/README.md +0 -0
- /package/lib/{templates/typescript → template}/eslint.config.js +0 -0
- /package/lib/{templates/typescript → template}/package.json +0 -0
- /package/lib/{templates/common → template}/src/assets/icon.png +0 -0
- /package/lib/{templates/typescript → template}/src/cat-fact.tsx +0 -0
- /package/lib/{templates/typescript → template}/src/get-cat-fact.server.ts +0 -0
- /package/lib/{templates/typescript → template}/src/hello-world-action.tsx +0 -0
- /package/lib/{templates/typescript → template}/src/hello-world-dialog.tsx +0 -0
- /package/lib/{templates/typescript → template}/tsconfig.json +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { spinnerify } from "../../util/spinner.js";
|
|
4
|
-
import { loadAttioCliVersion
|
|
4
|
+
import { loadAttioCliVersion } from "../../util/load-attio-cli-version.js";
|
|
5
5
|
import { uploadBundle } from "../../util/upload-bundle.js";
|
|
6
6
|
import { getVersions } from "../../spinners/get-versions.spinner.js";
|
|
7
7
|
import { getAppInfo } from "../../spinners/get-app-info.spinner.js";
|
|
8
|
-
import { printFetcherError } from "../../
|
|
8
|
+
import { printCliVersionError, printFetcherError, printPackageJsonError } from "../../print-errors.js";
|
|
9
9
|
import { combineAsync, isErrored } from "@attio/fetchable";
|
|
10
|
-
import { getAppSlugFromPackageJson
|
|
10
|
+
import { getAppSlugFromPackageJson } from "../../spinners/get-app-slug-from-package-json.js";
|
|
11
11
|
import { bundleJavaScript } from "./create/bundle-javascript.js";
|
|
12
12
|
import { printBuildContextError } from "../dev/prepare-build-contexts.js";
|
|
13
|
-
import {
|
|
13
|
+
import { api } from "../../api/api.js";
|
|
14
14
|
import { printJsError } from "../../util/typescript.js";
|
|
15
15
|
export const versionCreate = new Command("create")
|
|
16
16
|
.description("Create a new unpublished version of your Attio app")
|
|
@@ -23,7 +23,7 @@ export const versionCreate = new Command("create")
|
|
|
23
23
|
const appSlug = appSlugResult.value;
|
|
24
24
|
const appInfoResult = await getAppInfo(appSlug);
|
|
25
25
|
if (isErrored(appInfoResult)) {
|
|
26
|
-
printFetcherError("Error loading app info", appInfoResult.error
|
|
26
|
+
printFetcherError("Error loading app info", appInfoResult.error);
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
29
|
const appInfo = appInfoResult.value;
|
|
@@ -33,22 +33,22 @@ export const versionCreate = new Command("create")
|
|
|
33
33
|
const { error } = bundleResult.error;
|
|
34
34
|
if (error.code === "BUILD_JAVASCRIPT_ERROR") {
|
|
35
35
|
const { errors, warnings } = error;
|
|
36
|
-
errors
|
|
37
|
-
warnings
|
|
36
|
+
errors?.forEach((error) => printJsError(error, "error"));
|
|
37
|
+
warnings?.forEach((warning) => printJsError(warning, "warning"));
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
40
40
|
printBuildContextError(error);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
|
-
printBuildContextError(bundleResult.error.
|
|
44
|
+
printBuildContextError(bundleResult.error.error);
|
|
45
45
|
}
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
const [clientBundle, serverBundle] = bundleResult.value;
|
|
49
49
|
const versionsResult = await getVersions(appInfo);
|
|
50
50
|
if (isErrored(versionsResult)) {
|
|
51
|
-
printFetcherError("Error fetching versions", versionsResult.error
|
|
51
|
+
printFetcherError("Error fetching versions", versionsResult.error);
|
|
52
52
|
process.exit(1);
|
|
53
53
|
}
|
|
54
54
|
const versions = versionsResult.value;
|
|
@@ -59,7 +59,7 @@ export const versionCreate = new Command("create")
|
|
|
59
59
|
process.exit(1);
|
|
60
60
|
}
|
|
61
61
|
const cliVersion = cliVersionResult.value;
|
|
62
|
-
const versionResult = await
|
|
62
|
+
const versionResult = await api.createVersion({
|
|
63
63
|
appId: appInfo.app_id,
|
|
64
64
|
major: versions.length === 0
|
|
65
65
|
? 1
|
|
@@ -67,7 +67,7 @@ export const versionCreate = new Command("create")
|
|
|
67
67
|
cliVersion,
|
|
68
68
|
});
|
|
69
69
|
if (isErrored(versionResult)) {
|
|
70
|
-
printFetcherError("Error creating version", versionResult.error
|
|
70
|
+
printFetcherError("Error creating version", versionResult.error);
|
|
71
71
|
process.exit(1);
|
|
72
72
|
}
|
|
73
73
|
const { client_bundle_upload_url, server_bundle_upload_url } = versionResult.value;
|
|
@@ -76,7 +76,7 @@ export const versionCreate = new Command("create")
|
|
|
76
76
|
uploadBundle(serverBundle, server_bundle_upload_url),
|
|
77
77
|
]);
|
|
78
78
|
if (isErrored(uploadResult)) {
|
|
79
|
-
process.stderr.write(`${chalk.red("✖ ")}Failed to upload bundle to: ${uploadResult.error.
|
|
79
|
+
process.stderr.write(`${chalk.red("✖ ")}Failed to upload bundle to: ${uploadResult.error.upload_url}\n`);
|
|
80
80
|
process.exit(1);
|
|
81
81
|
}
|
|
82
82
|
return versionResult;
|
|
@@ -86,14 +86,14 @@ export const versionCreate = new Command("create")
|
|
|
86
86
|
process.exit(1);
|
|
87
87
|
}
|
|
88
88
|
const version = versionResult.value;
|
|
89
|
-
const signingResult = await spinnerify("Signing bundles...", "Bundles signed", async () => await
|
|
89
|
+
const signingResult = await spinnerify("Signing bundles...", "Bundles signed", async () => await api.completeProdBundleUpload({
|
|
90
90
|
appId: appInfo.app_id,
|
|
91
91
|
major: version.major,
|
|
92
92
|
minor: version.minor,
|
|
93
93
|
bundleId: version.app_prod_version_bundle_id,
|
|
94
94
|
}));
|
|
95
95
|
if (isErrored(signingResult)) {
|
|
96
|
-
printFetcherError("Error signing bundles", signingResult.error
|
|
96
|
+
printFetcherError("Error signing bundles", signingResult.error);
|
|
97
97
|
process.exit(1);
|
|
98
98
|
}
|
|
99
99
|
process.stdout.write(`\nVersion ${chalk.green(`${version.major}.${version.minor}`)} created!\n\n`);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { getAppInfo } from "../../spinners/get-app-info.spinner.js";
|
|
3
|
-
import { getAppSlugFromPackageJson
|
|
3
|
+
import { getAppSlugFromPackageJson } from "../../spinners/get-app-slug-from-package-json.js";
|
|
4
4
|
import { getVersions } from "../../spinners/get-versions.spinner.js";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import Table from "cli-table3";
|
|
7
7
|
import { format as formatDate } from "date-fns";
|
|
8
8
|
import { isErrored } from "@attio/fetchable";
|
|
9
|
-
import { printFetcherError } from "../../
|
|
9
|
+
import { printFetcherError, printPackageJsonError } from "../../print-errors.js";
|
|
10
10
|
export const versionList = new Command()
|
|
11
11
|
.name("list")
|
|
12
12
|
.description("List all versions of your app")
|
|
@@ -19,13 +19,13 @@ export const versionList = new Command()
|
|
|
19
19
|
const appSlug = appSlugResult.value;
|
|
20
20
|
const appInfoResult = await getAppInfo(appSlug);
|
|
21
21
|
if (isErrored(appInfoResult)) {
|
|
22
|
-
printFetcherError("Error loading app info", appInfoResult.error
|
|
22
|
+
printFetcherError("Error loading app info", appInfoResult.error);
|
|
23
23
|
process.exit(1);
|
|
24
24
|
}
|
|
25
25
|
const appInfo = appInfoResult.value;
|
|
26
26
|
const versionsResult = await getVersions(appInfo);
|
|
27
27
|
if (isErrored(versionsResult)) {
|
|
28
|
-
printFetcherError("Error loading versions", versionsResult.error
|
|
28
|
+
printFetcherError("Error loading versions", versionsResult.error);
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
31
|
const versions = versionsResult.value;
|
package/lib/commands/whoami.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { keychain } from "../auth/keychain.js";
|
|
3
|
+
import { api } from "../api/api.js";
|
|
4
4
|
import { isErrored } from "@attio/fetchable";
|
|
5
|
-
import { printFetcherError } from "../
|
|
5
|
+
import { printFetcherError } from "../print-errors.js";
|
|
6
6
|
export const whoami = new Command()
|
|
7
7
|
.name("whoami")
|
|
8
8
|
.description("Identify the current user")
|
|
9
9
|
.action(async () => {
|
|
10
|
-
const tokenResult = await
|
|
11
|
-
if (
|
|
10
|
+
const tokenResult = await keychain.load();
|
|
11
|
+
if (isErrored(tokenResult) || tokenResult.value === null) {
|
|
12
12
|
process.stdout.write("🔒 Not logged in.\n");
|
|
13
13
|
process.exit(0);
|
|
14
14
|
}
|
|
15
|
-
const result = await
|
|
15
|
+
const result = await api.whoami();
|
|
16
16
|
if (isErrored(result)) {
|
|
17
|
-
|
|
18
|
-
printFetcherError("Error fetching user", fetcherError);
|
|
17
|
+
printFetcherError("Error fetching user", result.error);
|
|
19
18
|
process.exit(1);
|
|
20
19
|
}
|
|
21
20
|
const { name, email_address } = result.value;
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { APP } from "./env.js";
|
|
3
|
+
export function printFetcherError(message, { error }) {
|
|
4
|
+
process.stderr.write(`${chalk.red("✖ ")}${message}\n`);
|
|
5
|
+
switch (error.code) {
|
|
6
|
+
case "HTTP_ERROR":
|
|
7
|
+
process.stderr.write(`HTTP Error (${error.status}): ${error.message}\n`);
|
|
8
|
+
break;
|
|
9
|
+
case "INVALID_RESPONSE":
|
|
10
|
+
process.stderr.write(`Invalid response: ${error.message}\n`);
|
|
11
|
+
break;
|
|
12
|
+
case "NETWORK_ERROR":
|
|
13
|
+
process.stderr.write(`Network error: ${error.message}\n`);
|
|
14
|
+
break;
|
|
15
|
+
case "UNAUTHORIZED":
|
|
16
|
+
process.stderr.write(`Unauthorized. You must log in with "attio login"\n`);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function printUploadError(error) {
|
|
21
|
+
switch (error.code) {
|
|
22
|
+
case "BUNDLE_UPLOAD_ERROR":
|
|
23
|
+
process.stderr.write(chalk.red(`Error uploading bundle: ${error.upload_url}\n`));
|
|
24
|
+
break;
|
|
25
|
+
case "START_UPLOAD_ERROR":
|
|
26
|
+
printFetcherError("Error starting upload", error);
|
|
27
|
+
break;
|
|
28
|
+
case "COMPLETE_BUNDLE_UPLOAD_ERROR":
|
|
29
|
+
printFetcherError("Error completing bundle upload", error);
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
return error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function printCreateProjectError(error) {
|
|
36
|
+
switch (error.code) {
|
|
37
|
+
case "DIRECTORY_ALREADY_EXISTS":
|
|
38
|
+
process.stderr.write(chalk.red(`Directory ${error.path} already exists`));
|
|
39
|
+
break;
|
|
40
|
+
case "WRITE_ACCESS_DENIED":
|
|
41
|
+
process.stderr.write(chalk.red(`Write access denied to ${error.path}`));
|
|
42
|
+
break;
|
|
43
|
+
case "FAILED_TO_CREATE_DIRECTORY":
|
|
44
|
+
process.stderr.write(chalk.red(`Failed to create directory ${error.path}`));
|
|
45
|
+
break;
|
|
46
|
+
case "FAILED_TO_COPY_FILE":
|
|
47
|
+
process.stderr.write(chalk.red(`Failed to copy file ${error.src} to ${error.dest}`));
|
|
48
|
+
break;
|
|
49
|
+
case "FAILED_TO_LIST_FILES":
|
|
50
|
+
process.stderr.write(chalk.red(`Failed to list files in ${error.path}`));
|
|
51
|
+
break;
|
|
52
|
+
case "FAILED_TO_READ_FILE":
|
|
53
|
+
process.stderr.write(chalk.red(`Failed to read file ${error.path}`));
|
|
54
|
+
break;
|
|
55
|
+
case "FAILED_TO_WRITE_FILE":
|
|
56
|
+
process.stderr.write(chalk.red(`Failed to write file ${error.path}`));
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
return error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function printPackageJsonError({ code, error }) {
|
|
63
|
+
switch (code) {
|
|
64
|
+
case "MALFORMED_PACKAGE_JSON":
|
|
65
|
+
if (error.issues.length > 0) {
|
|
66
|
+
process.stderr.write(`${chalk.red("✖ ")}Malformed package.json: ${error.issues[0].message}\n`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
process.stderr.write(`${chalk.red("✖ ")}Malformed package.json: ${error.message}\n`);
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case "FILE_SYSTEM_ERROR":
|
|
73
|
+
process.stderr.write(`${chalk.red("✖ ")}Failed to read package.json\n`);
|
|
74
|
+
break;
|
|
75
|
+
case "INVALID_JSON":
|
|
76
|
+
process.stderr.write(`${chalk.red("✖ ")}Invalid JSON in package.json: ${error}\n`);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function printCliVersionError({ error }) {
|
|
81
|
+
switch (error.code) {
|
|
82
|
+
case "UNABLE_TO_FIND_PACKAGE_JSON":
|
|
83
|
+
process.stderr.write(`${chalk.red("✖ ")}Failed to find package.json in ${error.path}\n`);
|
|
84
|
+
break;
|
|
85
|
+
case "UNABLE_TO_READ_PACKAGE_JSON":
|
|
86
|
+
process.stderr.write(`${chalk.red("✖ ")}Failed to read package.json: ${error.error}\n`);
|
|
87
|
+
break;
|
|
88
|
+
case "UNABLE_TO_PARSE_PACKAGE_JSON":
|
|
89
|
+
process.stderr.write(`${chalk.red("✖ ")}Failed to parse package.json: ${error.error}\n`);
|
|
90
|
+
break;
|
|
91
|
+
case "INVALID_PACKAGE_JSON":
|
|
92
|
+
process.stderr.write(`${chalk.red("✖ ")}Invalid package.json: ${error.error}\n`);
|
|
93
|
+
break;
|
|
94
|
+
case "ERROR_LOADING_PACKAGE_JSON":
|
|
95
|
+
process.stderr.write(`${chalk.red("✖ ")}Error loading package.json: ${error.error}\n`);
|
|
96
|
+
break;
|
|
97
|
+
case "NO_CLI_VERSION_FOUND":
|
|
98
|
+
process.stderr.write(`${chalk.red("✖ ")}No CLI version found in attio's package.json\n`);
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
return error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function printDetermineWorkspaceError(error) {
|
|
105
|
+
switch (error.code) {
|
|
106
|
+
case "FETCH_WORKSPACES_ERROR":
|
|
107
|
+
process.stderr.write(`Error fetching workspaces: ${error.error}
|
|
108
|
+
|
|
109
|
+
${APP}/welcome/workspace-details
|
|
110
|
+
`);
|
|
111
|
+
break;
|
|
112
|
+
case "NO_WORKSPACE_FOUND":
|
|
113
|
+
process.stderr.write(`You are not the admin any workspace with the slug "${error.workspace_slug}". Either request permission from "${error.workspace_slug}" or create your own.
|
|
114
|
+
|
|
115
|
+
${APP}/welcome/workspace-details
|
|
116
|
+
`);
|
|
117
|
+
break;
|
|
118
|
+
case "NO_WORKSPACES_FOUND":
|
|
119
|
+
process.stderr.write(`You are not the admin of any workspaces. Either request permission from an existing workspace or create your own.
|
|
120
|
+
|
|
121
|
+
${APP}/welcome/workspace-details
|
|
122
|
+
`);
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
return error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function printKeychainError(error) {
|
|
129
|
+
switch (error.code) {
|
|
130
|
+
case "SAVE_KEYCHAIN_ERROR":
|
|
131
|
+
process.stderr.write(chalk.red(`Error saving token to keychain: ${error.error}`));
|
|
132
|
+
break;
|
|
133
|
+
case "LOAD_KEYCHAIN_ERROR":
|
|
134
|
+
process.stderr.write(chalk.red(`Error loading token from keychain: ${error.error}`));
|
|
135
|
+
break;
|
|
136
|
+
case "DELETE_KEYCHAIN_ERROR":
|
|
137
|
+
process.stderr.write(chalk.red(`Error deleting token from keychain: ${error.error}`));
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
return error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export function printAuthenticationError(error) {
|
|
144
|
+
switch (error.code) {
|
|
145
|
+
case "GET_TOKEN_ERROR":
|
|
146
|
+
printFetcherError("Error getting token", error);
|
|
147
|
+
break;
|
|
148
|
+
case "REFRESH_TOKEN_ERROR":
|
|
149
|
+
printFetcherError("Error refreshing token", error);
|
|
150
|
+
break;
|
|
151
|
+
case "NO_AUTHORIZATION_CODE":
|
|
152
|
+
process.stderr.write(chalk.red(`No authorization code received`));
|
|
153
|
+
break;
|
|
154
|
+
case "OAUTH_STATE_MISMATCH":
|
|
155
|
+
process.stderr.write(chalk.red(`OAuth state mismatch, possible CSRF attack`));
|
|
156
|
+
break;
|
|
157
|
+
case "SAVE_KEYCHAIN_ERROR":
|
|
158
|
+
case "LOAD_KEYCHAIN_ERROR":
|
|
159
|
+
case "DELETE_KEYCHAIN_ERROR":
|
|
160
|
+
printKeychainError(error);
|
|
161
|
+
break;
|
|
162
|
+
default:
|
|
163
|
+
return error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { select } from "@inquirer/prompts";
|
|
2
|
-
import { APP } from "../env.js";
|
|
3
2
|
import { spinnerify } from "../util/spinner.js";
|
|
4
|
-
import {
|
|
3
|
+
import { api } from "../api/api.js";
|
|
5
4
|
import { isErrored, complete, errored } from "@attio/fetchable";
|
|
6
|
-
import { printFetcherError } from "../api/fetcher.js";
|
|
7
5
|
export async function determineWorkspace(workspaceSlug) {
|
|
8
|
-
const workspacesResult = await spinnerify("Loading workspaces...", "Workspaces loaded", async () => await
|
|
6
|
+
const workspacesResult = await spinnerify("Loading workspaces...", "Workspaces loaded", async () => await api.fetchWorkspaces());
|
|
9
7
|
if (isErrored(workspacesResult)) {
|
|
10
8
|
return workspacesResult;
|
|
11
9
|
}
|
|
@@ -16,7 +14,7 @@ export async function determineWorkspace(workspaceSlug) {
|
|
|
16
14
|
return complete(workspace);
|
|
17
15
|
}
|
|
18
16
|
if (workspaceSlug) {
|
|
19
|
-
return errored({ code: "NO_WORKSPACE_FOUND", workspaceSlug });
|
|
17
|
+
return errored({ code: "NO_WORKSPACE_FOUND", workspace_slug: workspaceSlug });
|
|
20
18
|
}
|
|
21
19
|
if (workspaces.length === 0) {
|
|
22
20
|
return errored({ code: "NO_WORKSPACES_FOUND" });
|
|
@@ -35,24 +33,3 @@ export async function determineWorkspace(workspaceSlug) {
|
|
|
35
33
|
process.stdout.write(`Using workspace: ${choice.name}`);
|
|
36
34
|
return complete(choice);
|
|
37
35
|
}
|
|
38
|
-
export function printDetermineWorkspaceError(error) {
|
|
39
|
-
switch (error.code) {
|
|
40
|
-
case "FETCH_WORKSPACES_ERROR":
|
|
41
|
-
printFetcherError("Error fetching workspaces", error.fetcherError);
|
|
42
|
-
break;
|
|
43
|
-
case "NO_WORKSPACE_FOUND":
|
|
44
|
-
process.stderr.write(`You are not the admin any workspace with the slug "${error.workspaceSlug}". Either request permission from "${error.workspaceSlug}" or create your own.
|
|
45
|
-
|
|
46
|
-
${APP}/welcome/workspace-details
|
|
47
|
-
`);
|
|
48
|
-
break;
|
|
49
|
-
case "NO_WORKSPACES_FOUND":
|
|
50
|
-
process.stderr.write(`You are not the admin of any workspaces. Either request permission from an existing workspace or create your own.
|
|
51
|
-
|
|
52
|
-
${APP}/welcome/workspace-details
|
|
53
|
-
`);
|
|
54
|
-
break;
|
|
55
|
-
default:
|
|
56
|
-
return error;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { api } from "../api/api.js";
|
|
2
2
|
import { spinnerify } from "../util/spinner.js";
|
|
3
3
|
export async function getAppInfo(appSlug) {
|
|
4
4
|
return await spinnerify("Loading app information...", (app) => `App found: ${app.title}`, async () => {
|
|
5
|
-
return await
|
|
5
|
+
return await api.fetchAppInfo(appSlug);
|
|
6
6
|
});
|
|
7
7
|
}
|
|
@@ -2,7 +2,6 @@ import { readFileSync } from "fs";
|
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { complete, errored } from "@attio/fetchable";
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
const packageJsonSchema = z.object({
|
|
7
6
|
name: z.string({
|
|
8
7
|
required_error: "No name field found in package.json",
|
|
@@ -15,7 +14,7 @@ export async function getAppSlugFromPackageJson() {
|
|
|
15
14
|
const packageJsonRaw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
16
15
|
const result = packageJsonSchema.safeParse(packageJsonRaw);
|
|
17
16
|
if (!result.success) {
|
|
18
|
-
return errored({ code: "MALFORMED_PACKAGE_JSON", error: result.error
|
|
17
|
+
return errored({ code: "MALFORMED_PACKAGE_JSON", error: result.error });
|
|
19
18
|
}
|
|
20
19
|
return complete(result.data.name);
|
|
21
20
|
}
|
|
@@ -26,21 +25,3 @@ export async function getAppSlugFromPackageJson() {
|
|
|
26
25
|
return errored({ code: "FILE_SYSTEM_ERROR", error });
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
|
-
export function printPackageJsonError({ code, error }) {
|
|
30
|
-
switch (code) {
|
|
31
|
-
case "MALFORMED_PACKAGE_JSON":
|
|
32
|
-
if (error) {
|
|
33
|
-
process.stderr.write(`${chalk.red("✖ ")}Malformed package.json: ${error}\n`);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
process.stderr.write(`${chalk.red("✖ ")}Malformed package.json\n`);
|
|
37
|
-
}
|
|
38
|
-
break;
|
|
39
|
-
case "FILE_SYSTEM_ERROR":
|
|
40
|
-
process.stderr.write(`${chalk.red("✖ ")}Failed to read package.json\n`);
|
|
41
|
-
break;
|
|
42
|
-
case "INVALID_JSON":
|
|
43
|
-
process.stderr.write(`${chalk.red("✖ ")}Invalid JSON in package.json: ${error}\n`);
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spinnerify } from "../util/spinner.js";
|
|
2
|
-
import {
|
|
2
|
+
import { api } from "../api/api.js";
|
|
3
3
|
export async function getVersions(appInfo) {
|
|
4
|
-
return await spinnerify("Loading versions...", "Versions loaded", async () => await
|
|
4
|
+
return await spinnerify("Loading versions...", "Versions loaded", async () => await api.fetchVersions(appInfo.app_id));
|
|
5
5
|
}
|
|
@@ -6,14 +6,14 @@ export async function copyWithTransform(srcDir, destDir, transform) {
|
|
|
6
6
|
await fs.mkdir(destDir, { recursive: true });
|
|
7
7
|
}
|
|
8
8
|
catch {
|
|
9
|
-
return errored({ code: "FAILED_TO_CREATE_DIRECTORY",
|
|
9
|
+
return errored({ code: "FAILED_TO_CREATE_DIRECTORY", path: destDir });
|
|
10
10
|
}
|
|
11
11
|
let entries;
|
|
12
12
|
try {
|
|
13
13
|
entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
14
14
|
}
|
|
15
15
|
catch {
|
|
16
|
-
return errored({ code: "FAILED_TO_LIST_FILES",
|
|
16
|
+
return errored({ code: "FAILED_TO_LIST_FILES", path: srcDir });
|
|
17
17
|
}
|
|
18
18
|
const results = await combineAsync(entries.map(async (entry) => {
|
|
19
19
|
const srcPath = path.join(srcDir, entry.name);
|
|
@@ -3,7 +3,6 @@ import { findUpSync } from "find-up-simple";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { errored, complete } from "@attio/fetchable";
|
|
6
|
-
import chalk from "chalk";
|
|
7
6
|
const FILE_NAME = "package.json";
|
|
8
7
|
const packageJsonSchema = z.object({
|
|
9
8
|
name: z.literal("attio"),
|
|
@@ -20,7 +19,7 @@ export function loadAttioCliVersion() {
|
|
|
20
19
|
if (packageJsonPath === undefined) {
|
|
21
20
|
return errored({
|
|
22
21
|
code: "UNABLE_TO_FIND_PACKAGE_JSON",
|
|
23
|
-
|
|
22
|
+
path: cwd,
|
|
24
23
|
});
|
|
25
24
|
}
|
|
26
25
|
let contents;
|
|
@@ -60,27 +59,3 @@ export function loadAttioCliVersion() {
|
|
|
60
59
|
}
|
|
61
60
|
return complete(version);
|
|
62
61
|
}
|
|
63
|
-
export function printCliVersionError({ error }) {
|
|
64
|
-
switch (error.code) {
|
|
65
|
-
case "UNABLE_TO_FIND_PACKAGE_JSON":
|
|
66
|
-
process.stderr.write(`${chalk.red("✖ ")}Failed to find package.json in ${error.directory}\n`);
|
|
67
|
-
break;
|
|
68
|
-
case "UNABLE_TO_READ_PACKAGE_JSON":
|
|
69
|
-
process.stderr.write(`${chalk.red("✖ ")}Failed to read package.json: ${error.error}\n`);
|
|
70
|
-
break;
|
|
71
|
-
case "UNABLE_TO_PARSE_PACKAGE_JSON":
|
|
72
|
-
process.stderr.write(`${chalk.red("✖ ")}Failed to parse package.json: ${error.error}\n`);
|
|
73
|
-
break;
|
|
74
|
-
case "INVALID_PACKAGE_JSON":
|
|
75
|
-
process.stderr.write(`${chalk.red("✖ ")}Invalid package.json: ${error.error}\n`);
|
|
76
|
-
break;
|
|
77
|
-
case "ERROR_LOADING_PACKAGE_JSON":
|
|
78
|
-
process.stderr.write(`${chalk.red("✖ ")}Error loading package.json: ${error.error}\n`);
|
|
79
|
-
break;
|
|
80
|
-
case "NO_CLI_VERSION_FOUND":
|
|
81
|
-
process.stderr.write(`${chalk.red("✖ ")}No CLI version found in attio's package.json\n`);
|
|
82
|
-
break;
|
|
83
|
-
default:
|
|
84
|
-
return error;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
@@ -12,6 +12,6 @@ export async function uploadBundle(bundle, uploadUrl) {
|
|
|
12
12
|
return complete(undefined);
|
|
13
13
|
}
|
|
14
14
|
catch (error) {
|
|
15
|
-
return errored({ code: "BUNDLE_UPLOAD_ERROR",
|
|
15
|
+
return errored({ code: "BUNDLE_UPLOAD_ERROR", upload_url: uploadUrl });
|
|
16
16
|
}
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { auth as authApi } from "./auth.js";
|
|
2
|
-
import { deleteAuthToken, loadAuthToken } from "./keychain.js";
|
|
3
|
-
async function auth() {
|
|
4
|
-
await deleteAuthToken();
|
|
5
|
-
if (process.env.NODE_ENV !== "test") {
|
|
6
|
-
process.stdout.write("You need to log in with Attio. Press Enter to continue...\n\n");
|
|
7
|
-
await new Promise((resolve) => process.stdin.once("data", resolve));
|
|
8
|
-
}
|
|
9
|
-
return await authApi();
|
|
10
|
-
}
|
|
11
|
-
export async function ensureAuthed() {
|
|
12
|
-
const token = await loadAuthToken();
|
|
13
|
-
return token ?? (await auth());
|
|
14
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { graphqlServer } from "@hono/graphql-server";
|
|
2
|
-
import { serve } from "@hono/node-server";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import { buildSchema } from "graphql";
|
|
5
|
-
import { Hono } from "hono";
|
|
6
|
-
import path, { dirname } from "path";
|
|
7
|
-
import { fileURLToPath } from "url";
|
|
8
|
-
import { findAvailablePort } from "../../util/find-available-port.js";
|
|
9
|
-
export function startGraphqlServer(sendBack) {
|
|
10
|
-
let server = null;
|
|
11
|
-
const startServer = async () => {
|
|
12
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
13
|
-
const currentDirPath = dirname(currentFilePath);
|
|
14
|
-
const schemaPath = path.resolve(currentDirPath, "..", "..", "schema.graphql");
|
|
15
|
-
const schemaString = fs.readFileSync(schemaPath, "utf8");
|
|
16
|
-
const port = await findAvailablePort(8700);
|
|
17
|
-
const schema = buildSchema(schemaString);
|
|
18
|
-
const app = new Hono();
|
|
19
|
-
const rootResolver = () => {
|
|
20
|
-
return {};
|
|
21
|
-
};
|
|
22
|
-
app.use("/graphql", graphqlServer({ schema, rootResolver, graphiql: true }));
|
|
23
|
-
server = serve({ fetch: app.fetch, port });
|
|
24
|
-
sendBack({ code: "GraphQL Server Started", port });
|
|
25
|
-
};
|
|
26
|
-
startServer();
|
|
27
|
-
return () => {
|
|
28
|
-
if (!server)
|
|
29
|
-
return;
|
|
30
|
-
server.close();
|
|
31
|
-
};
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { select } from "@inquirer/prompts";
|
|
2
|
-
export const LANGUAGES = [
|
|
3
|
-
{ name: "TypeScript (recommended)", value: "typescript" },
|
|
4
|
-
{ name: "JavaScript", value: "javascript" },
|
|
5
|
-
];
|
|
6
|
-
export async function askLanguage() {
|
|
7
|
-
return select({
|
|
8
|
-
message: "What language would you like to use?",
|
|
9
|
-
choices: LANGUAGES,
|
|
10
|
-
});
|
|
11
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Add secrets that you want available in your .server.js files
|
|
2
|
-
# IN DEV MODE ONLY here. In production, secrets should be managed
|
|
3
|
-
# using the `attio secret` command.
|
|
4
|
-
#
|
|
5
|
-
# Example: SECRET_KEY=super-secret-value
|
|
6
|
-
#
|
|
7
|
-
# You will then be able to reference them in your code like so:
|
|
8
|
-
# ```
|
|
9
|
-
# import { env } from '@attio/extension-sdk';
|
|
10
|
-
#
|
|
11
|
-
# const secretValue = env('SECRET_KEY');
|
|
12
|
-
# ```
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const {FlatCompat} = require("@eslint/eslintrc")
|
|
2
|
-
const js = require("@eslint/js")
|
|
3
|
-
const reactPlugin = require("eslint-plugin-react")
|
|
4
|
-
const reactHooksPlugin = require("eslint-plugin-react-hooks")
|
|
5
|
-
const attio = require("attio/lint")
|
|
6
|
-
|
|
7
|
-
const compat = new FlatCompat({
|
|
8
|
-
baseDirectory: __dirname,
|
|
9
|
-
recommendedConfig: js.configs.recommended,
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
module.exports = [
|
|
13
|
-
...compat.extends("eslint:recommended"),
|
|
14
|
-
...compat.extends("plugin:react/recommended"),
|
|
15
|
-
{
|
|
16
|
-
files: ["src/**/*.{js,jsx}"],
|
|
17
|
-
languageOptions: {
|
|
18
|
-
parserOptions: {
|
|
19
|
-
ecmaFeatures: {
|
|
20
|
-
jsx: true,
|
|
21
|
-
},
|
|
22
|
-
ecmaVersion: 12,
|
|
23
|
-
sourceType: "module",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
plugins: {
|
|
27
|
-
"react": reactPlugin,
|
|
28
|
-
"react-hooks": reactHooksPlugin,
|
|
29
|
-
attio,
|
|
30
|
-
},
|
|
31
|
-
rules: {
|
|
32
|
-
"react/jsx-key": "error",
|
|
33
|
-
"react-hooks/rules-of-hooks": "error",
|
|
34
|
-
"react-hooks/exhaustive-deps": "error",
|
|
35
|
-
"attio/attio-client-import": "error",
|
|
36
|
-
"attio/server-default-export": "error",
|
|
37
|
-
"attio/form-submit-button": "error",
|
|
38
|
-
},
|
|
39
|
-
settings: {
|
|
40
|
-
react: {
|
|
41
|
-
version: "detect",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
ignores: ["node_modules/", "dist/"],
|
|
47
|
-
},
|
|
48
|
-
]
|