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 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 { keychain } from "./keychain.js";
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 keychain.load();
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 keychain.load();
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 keychain.save(keychainToken);
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 keychain.save(keychainToken);
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 keychain.delete();
156
+ await getKeychain().delete();
157
157
  }
158
158
  }
159
159
  export const authenticator = new AuthenticatorImpl();
@@ -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
- export const keychain = process.env.NODE_ENV === "test" ? new TestKeychain() : new KeytarKeychain();
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
+ };
@@ -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(onSuccess) {
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 function handleSchemaAndGenerate() {
14
- try {
15
- const schemaPath = await findNodeModulesPath(["schema.graphql"]);
16
- if (!schemaPath) {
17
- hardExit("No schema.graphql found in node_modules");
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 instanceof Error ? error.message : "GraphQL code generation failed");
43
+ hardExit(result.error.error.toString());
29
44
  }
30
45
  }
31
- }
32
- watcher.on("ready", () => {
33
- handleSchemaAndGenerate();
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
- handleSchemaAndGenerate();
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
  });
@@ -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 { graphqlCodeGen } from "./dev/graphql-code-gen.js";
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
- const cleanupGraphqlCodeGen = graphqlCodeGen(triggerTs);
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) => {
@@ -1,9 +1,9 @@
1
1
  import { Command } from "commander";
2
- import { keychain } from "../auth/keychain.js";
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 keychain.delete();
6
+ const result = await getKeychain().delete();
7
7
  if (isErrored(result)) {
8
8
  printKeychainError(result.error);
9
9
  process.exit(1);
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import { keychain } from "../auth/keychain.js";
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 keychain.load();
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "attio",
3
- "version": "0.0.1-experimental.20250414",
3
+ "version": "0.0.1-experimental.20250425.1",
4
4
  "bin": "lib/attio.js",
5
5
  "type": "module",
6
6
  "files": [