attio 0.0.1-experimental.20250414 → 0.0.1-experimental.20250425.1
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/auth/auth.js +6 -6
- package/lib/auth/keychain.js +14 -1
- package/lib/commands/build.js +6 -0
- package/lib/commands/dev/graphql-code-gen.js +46 -20
- package/lib/commands/dev.js +12 -2
- package/lib/commands/logout.js +2 -2
- package/lib/commands/whoami.js +2 -2
- package/package.json +1 -1
package/lib/auth/auth.js
CHANGED
|
@@ -4,7 +4,7 @@ import { randomBytes, createHash } from "crypto";
|
|
|
4
4
|
import open from "open";
|
|
5
5
|
import { APP } from "../env.js";
|
|
6
6
|
import { findAvailablePort } from "../util/find-available-port.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getKeychain } from "./keychain.js";
|
|
8
8
|
import { api } from "../api/api.js";
|
|
9
9
|
import { isErrored, complete, errored } from "@attio/fetchable";
|
|
10
10
|
import { printFetcherError, printKeychainError } from "../print-errors.js";
|
|
@@ -12,7 +12,7 @@ class AuthenticatorImpl {
|
|
|
12
12
|
clientId = "f881c6f1-82d7-48a5-a581-649596167845";
|
|
13
13
|
refreshTimeout = null;
|
|
14
14
|
async ensureAuthed() {
|
|
15
|
-
const existingTokenResult = await
|
|
15
|
+
const existingTokenResult = await getKeychain().load();
|
|
16
16
|
if (isErrored(existingTokenResult)) {
|
|
17
17
|
return this.promptToAuthenticate();
|
|
18
18
|
}
|
|
@@ -31,7 +31,7 @@ class AuthenticatorImpl {
|
|
|
31
31
|
return this.authenticate();
|
|
32
32
|
}
|
|
33
33
|
async authenticate() {
|
|
34
|
-
const existingTokenResult = await
|
|
34
|
+
const existingTokenResult = await getKeychain().load();
|
|
35
35
|
if (isErrored(existingTokenResult)) {
|
|
36
36
|
return existingTokenResult;
|
|
37
37
|
}
|
|
@@ -108,7 +108,7 @@ class AuthenticatorImpl {
|
|
|
108
108
|
token_type: token.token_type,
|
|
109
109
|
expires_at: Date.now() + token.expires_in * 1000,
|
|
110
110
|
};
|
|
111
|
-
const saveResult = await
|
|
111
|
+
const saveResult = await getKeychain().save(keychainToken);
|
|
112
112
|
if (isErrored(saveResult)) {
|
|
113
113
|
return saveResult;
|
|
114
114
|
}
|
|
@@ -141,7 +141,7 @@ class AuthenticatorImpl {
|
|
|
141
141
|
token_type: refreshedToken.token_type,
|
|
142
142
|
expires_at: Date.now() + refreshedToken.expires_in * 1000,
|
|
143
143
|
};
|
|
144
|
-
const saveResult = await
|
|
144
|
+
const saveResult = await getKeychain().save(keychainToken);
|
|
145
145
|
if (isErrored(saveResult)) {
|
|
146
146
|
printKeychainError(saveResult.error);
|
|
147
147
|
return;
|
|
@@ -153,7 +153,7 @@ class AuthenticatorImpl {
|
|
|
153
153
|
clearTimeout(this.refreshTimeout);
|
|
154
154
|
this.refreshTimeout = null;
|
|
155
155
|
}
|
|
156
|
-
await
|
|
156
|
+
await getKeychain().delete();
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
export const authenticator = new AuthenticatorImpl();
|
package/lib/auth/keychain.js
CHANGED
|
@@ -59,6 +59,13 @@ class KeytarKeychain {
|
|
|
59
59
|
console.debug("Wiped keychain entry due to schema mismatch");
|
|
60
60
|
return complete(null);
|
|
61
61
|
}
|
|
62
|
+
if (parsedToken.data.expires_at < Date.now() + 60_000 * 5) {
|
|
63
|
+
const deleteResult = await this.delete();
|
|
64
|
+
if (isErrored(deleteResult)) {
|
|
65
|
+
return errored({ code: "LOAD_KEYCHAIN_ERROR", error: deleteResult.error });
|
|
66
|
+
}
|
|
67
|
+
return complete(null);
|
|
68
|
+
}
|
|
62
69
|
return complete(parsedToken.data);
|
|
63
70
|
}
|
|
64
71
|
async delete() {
|
|
@@ -92,4 +99,10 @@ class TestKeychain {
|
|
|
92
99
|
return complete(undefined);
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
|
-
|
|
102
|
+
let keychain = null;
|
|
103
|
+
export const getKeychain = () => {
|
|
104
|
+
if (keychain === null) {
|
|
105
|
+
keychain = process.env.NODE_ENV === "test" ? new TestKeychain() : new KeytarKeychain();
|
|
106
|
+
}
|
|
107
|
+
return keychain;
|
|
108
|
+
};
|
package/lib/commands/build.js
CHANGED
|
@@ -5,9 +5,15 @@ import { spinnerify } from "../util/spinner.js";
|
|
|
5
5
|
import { isErrored } from "@attio/fetchable";
|
|
6
6
|
import { printJsError, printTsError } from "../util/typescript.js";
|
|
7
7
|
import { printBuildContextError } from "./dev/prepare-build-contexts.js";
|
|
8
|
+
import { graphqlCodeGen } from "./dev/graphql-code-gen.js";
|
|
9
|
+
import { hardExit } from "../util/hard-exit.js";
|
|
8
10
|
export const build = new Command("build")
|
|
9
11
|
.description("Build your Attio extension locally")
|
|
10
12
|
.action(async () => {
|
|
13
|
+
const generateGraphqlOperationsResult = await spinnerify("Generating GraphQL types...", "GraphQL types generated successfully", graphqlCodeGen);
|
|
14
|
+
if (isErrored(generateGraphqlOperationsResult)) {
|
|
15
|
+
hardExit(generateGraphqlOperationsResult.error.error.toString());
|
|
16
|
+
}
|
|
11
17
|
const tsResult = await spinnerify("Validating TypeScript...", "TypeScript validation passed", validateTypeScript);
|
|
12
18
|
if (isErrored(tsResult)) {
|
|
13
19
|
switch (tsResult.error.code) {
|
|
@@ -1,39 +1,65 @@
|
|
|
1
1
|
import chokidar from "chokidar";
|
|
2
2
|
import { readFileSync } from "fs";
|
|
3
3
|
import { parse } from "graphql";
|
|
4
|
+
import { complete, errored, isErrored } from "@attio/fetchable";
|
|
4
5
|
import { findNodeModulesPath } from "../../util/find-node-modules-path.js";
|
|
5
6
|
import { generateOperations } from "../../graphql/generate-operations.js";
|
|
6
7
|
import { GraphQLError } from "../../graphql/graphql-error.js";
|
|
7
8
|
import { hardExit } from "../../util/hard-exit.js";
|
|
8
|
-
export function graphqlCodeGen(
|
|
9
|
+
export async function graphqlCodeGen() {
|
|
10
|
+
try {
|
|
11
|
+
const schemaPath = await findNodeModulesPath(["schema.graphql"]);
|
|
12
|
+
if (!schemaPath) {
|
|
13
|
+
hardExit("No schema.graphql found in node_modules");
|
|
14
|
+
}
|
|
15
|
+
const schema = parse(readFileSync(schemaPath, "utf8"));
|
|
16
|
+
await generateOperations(".", schema);
|
|
17
|
+
return complete(true);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof GraphQLError) {
|
|
21
|
+
return errored({ code: "GRAPHQL_ERROR", error: error });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return errored({
|
|
25
|
+
code: "GRAPHQL_CODEGEN_ERROR",
|
|
26
|
+
error: error instanceof Error ? error.message : "GraphQL code generation failed",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function watchGraphqlCodegen(onSuccess, onError) {
|
|
9
32
|
const watcher = chokidar.watch(["**/*.graphql", "**/*.gql"], {
|
|
10
33
|
ignored: ["**/node_modules/**", "**/dist/**"],
|
|
11
34
|
cwd: ".",
|
|
12
35
|
});
|
|
13
|
-
async
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
const schema = parse(readFileSync(schemaPath, "utf8"));
|
|
20
|
-
await generateOperations(".", schema);
|
|
21
|
-
onSuccess?.();
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
if (error instanceof GraphQLError) {
|
|
25
|
-
process.stderr.write(error.toString());
|
|
36
|
+
watcher.on("ready", async () => {
|
|
37
|
+
const result = await graphqlCodeGen();
|
|
38
|
+
if (isErrored(result)) {
|
|
39
|
+
if (result.error.code === "GRAPHQL_ERROR") {
|
|
40
|
+
onError?.(result.error.error.toString());
|
|
26
41
|
}
|
|
27
42
|
else {
|
|
28
|
-
hardExit(error
|
|
43
|
+
hardExit(result.error.error.toString());
|
|
29
44
|
}
|
|
30
45
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
watcher.on("all", (event, path) => {
|
|
46
|
+
else {
|
|
47
|
+
onSuccess?.();
|
|
48
|
+
}
|
|
49
|
+
watcher.on("all", async (event, path) => {
|
|
35
50
|
if (event === "add" || event === "change" || event === "unlink") {
|
|
36
|
-
|
|
51
|
+
const result = await graphqlCodeGen();
|
|
52
|
+
if (isErrored(result)) {
|
|
53
|
+
if (result.error.code === "GRAPHQL_ERROR") {
|
|
54
|
+
onError?.(result.error.error.toString());
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
hardExit(result.error.error.toString());
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
onSuccess?.();
|
|
62
|
+
}
|
|
37
63
|
}
|
|
38
64
|
});
|
|
39
65
|
});
|
package/lib/commands/dev.js
CHANGED
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { printMessage } from "../util/print-message.js";
|
|
5
5
|
import { validateTypeScript } from "./dev/validate-typescript.js";
|
|
6
|
-
import {
|
|
6
|
+
import { watchGraphqlCodegen } from "./dev/graphql-code-gen.js";
|
|
7
7
|
import { bundleJavaScript } from "./dev/bundle-javascript.js";
|
|
8
8
|
import { boot } from "./dev/boot.js";
|
|
9
9
|
import { onboarding } from "./dev/onboarding.js";
|
|
@@ -76,7 +76,17 @@ export const dev = new Command("dev")
|
|
|
76
76
|
notifyTsErrors(errors);
|
|
77
77
|
});
|
|
78
78
|
cleanupFunctions.push(cleanupTs);
|
|
79
|
-
|
|
79
|
+
let hasGraphqlCodeGenError = false;
|
|
80
|
+
const cleanupGraphqlCodeGen = watchGraphqlCodegen(() => {
|
|
81
|
+
if (hasGraphqlCodeGenError) {
|
|
82
|
+
process.stdout.write(`${chalk.green("✓")} GraphQL errors fixed\n`);
|
|
83
|
+
hasGraphqlCodeGenError = false;
|
|
84
|
+
}
|
|
85
|
+
triggerTs();
|
|
86
|
+
}, (error) => {
|
|
87
|
+
hasGraphqlCodeGenError = true;
|
|
88
|
+
process.stderr.write(error);
|
|
89
|
+
});
|
|
80
90
|
cleanupFunctions.push(cleanupGraphqlCodeGen);
|
|
81
91
|
let haveJsErrors = false;
|
|
82
92
|
const cleanupJs = bundleJavaScript(async (contents) => {
|
package/lib/commands/logout.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { getKeychain } from "../auth/keychain.js";
|
|
3
3
|
import { printKeychainError } from "../print-errors.js";
|
|
4
4
|
import { isErrored } from "@attio/fetchable";
|
|
5
5
|
export const logout = new Command("logout").description("Log out from Attio").action(async () => {
|
|
6
|
-
const result = await
|
|
6
|
+
const result = await getKeychain().delete();
|
|
7
7
|
if (isErrored(result)) {
|
|
8
8
|
printKeychainError(result.error);
|
|
9
9
|
process.exit(1);
|
package/lib/commands/whoami.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { getKeychain } from "../auth/keychain.js";
|
|
3
3
|
import { api } from "../api/api.js";
|
|
4
4
|
import { isErrored } from "@attio/fetchable";
|
|
5
5
|
import { printFetcherError } from "../print-errors.js";
|
|
@@ -7,7 +7,7 @@ export const whoami = new Command()
|
|
|
7
7
|
.name("whoami")
|
|
8
8
|
.description("Identify the current user")
|
|
9
9
|
.action(async () => {
|
|
10
|
-
const tokenResult = await
|
|
10
|
+
const tokenResult = await getKeychain().load();
|
|
11
11
|
if (isErrored(tokenResult) || tokenResult.value === null) {
|
|
12
12
|
process.stdout.write("🔒 Not logged in.\n");
|
|
13
13
|
process.exit(0);
|