attio 0.0.1-experimental.20240925 → 0.0.1-experimental.20240926.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.
@@ -7,14 +7,18 @@ const addConnectionSchema = z.object({
7
7
  app_id: z.string(),
8
8
  connection_definition_id: z.string(),
9
9
  });
10
- export async function addConnectionDefinition({ token, devSlug, appId, connection, clientId, clientSecret, authorizeUrl, accessTokenUrl, scopes, }) {
10
+ export async function addConnectionDefinition({ token, devSlug, appId, slug, label, description, allowMultiple, global, connectionType, clientId, clientSecret, authorizeUrl, accessTokenUrl, major, scopes, }) {
11
11
  const connectionDefinitionId = uuid();
12
12
  const body = {
13
- connection_type: connection.connection_type,
14
- audience: connection.audience,
15
- major: 1,
13
+ connection_type: connectionType,
14
+ slug,
15
+ label,
16
+ description,
17
+ allow_multiple: allowMultiple,
18
+ global,
19
+ major,
16
20
  };
17
- if (connection.connection_type === "oauth2-code") {
21
+ if (connectionType === "oauth2-code") {
18
22
  body.authorize_url = authorizeUrl;
19
23
  body.access_token_url = accessTokenUrl;
20
24
  body.client_id = clientId;
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ import { API } from "../env.js";
3
+ import { handleError } from "./handle-error.js";
4
+ import { makeHeaders } from "./make-headers.js";
5
+ const connectionDefinitionsResponseSchema = z.object({
6
+ connection_definitions: z.record(z.string(), z.object({
7
+ label: z.string(),
8
+ connection_type: z.enum(["oauth2-code", "secret"]),
9
+ description: z.string().nullable(),
10
+ global: z.boolean(),
11
+ allow_multiple: z.boolean(),
12
+ })),
13
+ });
14
+ export async function fetchConnections({ token, devSlug, appId, major, }) {
15
+ const response = await fetch(`${API}/developer-portal/accounts/${devSlug}/apps/${appId}/versions/${major}/connection-definitions`, {
16
+ method: "GET",
17
+ headers: makeHeaders(token),
18
+ });
19
+ await handleError(response);
20
+ return connectionDefinitionsResponseSchema.parse(await response.json()).connection_definitions;
21
+ }
@@ -0,0 +1,32 @@
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({ type: "GraphQL Server Started", port });
25
+ };
26
+ startServer();
27
+ return () => {
28
+ if (!server)
29
+ return;
30
+ server.close();
31
+ };
32
+ }
@@ -14,7 +14,7 @@ export interface Form<TSchema> {
14
14
  }) => JSX.Element;
15
15
  Input: React.FC<{
16
16
  label: string;
17
- data: PathTo<TSchema, "string" | "number">;
17
+ data: PathTo<TSchema, "string" | "number" | "connection">;
18
18
  placeholder?: string;
19
19
  disabled?: boolean;
20
20
  }>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A connection form value.
3
+ */
4
+ export interface FormConnection {
5
+ type: "connection";
6
+ isOptional: boolean;
7
+ optional(): FormConnection;
8
+ }
9
+ export interface Connection {
10
+ connectionId: string;
11
+ }
12
+ /**
13
+ * Create a new connection form value.
14
+ */
15
+ export declare function connection({ connectionSlug }: {
16
+ connectionSlug: string;
17
+ }): FormConnection;
@@ -2,3 +2,4 @@ export { build } from "./build";
2
2
  export { array } from "./array";
3
3
  export { number } from "./number";
4
4
  export { string } from "./string";
5
+ export { connection } from "./connection";
@@ -1,11 +1,12 @@
1
1
  import { Prettify } from "../util/prettify";
2
2
  import { FormArray } from "./array";
3
+ import { FormConnection, Connection } from "./connection";
3
4
  import { FormNumber } from "./number";
4
5
  import { FormString } from "./string";
5
6
  type Assert<TCat, TAnimal> = TCat extends TAnimal ? TCat : never;
6
7
  type Join<A extends string | number | null, B extends string | number> = A extends null ? B : `${A}.${B}`;
7
- export type ValueType = "string" | "number" | "array";
8
- export type SchemaNode = FormString | FormNumber | FormArray<any> | {
8
+ export type ValueType = "string" | "number" | "array" | "connection";
9
+ export type SchemaNode = FormString | FormNumber | FormConnection | FormArray<any> | {
9
10
  type: "object";
10
11
  };
11
12
  type PathWithTypeRecursive<TState, TRoot extends string | number | null> = TState extends FormString ? {
@@ -14,6 +15,9 @@ type PathWithTypeRecursive<TState, TRoot extends string | number | null> = TStat
14
15
  } : TState extends FormNumber ? {
15
16
  path: TRoot;
16
17
  type: "number";
18
+ } : TState extends FormConnection ? {
19
+ path: TRoot;
20
+ type: "connection";
17
21
  } : TState extends FormArray<infer TElement> ? {
18
22
  path: TRoot;
19
23
  type: "array";
@@ -28,7 +32,7 @@ export type Path<TState> = PathWithType<TState>["path"];
28
32
  export type PathTo<TState, TType extends ValueType> = Extract<PathWithType<TState>, {
29
33
  type: TType;
30
34
  }>["path"];
31
- export type ValueOf<TState> = TState extends FormString ? string : TState extends FormNumber ? number : TState extends FormArray<infer TElement> ? Array<ValueOf<TElement>> : {
35
+ export type ValueOf<TState> = TState extends FormString ? string : TState extends FormNumber ? number : TState extends FormConnection ? Connection : TState extends FormArray<infer TElement> ? Array<ValueOf<TElement>> : {
32
36
  [K in keyof TState]: K extends string ? ValueOf<TState[K]> : never;
33
37
  };
34
38
  export {};
@@ -4,5 +4,6 @@ export * as Forms from "./forms/index.js";
4
4
  export { FormArray } from "./forms/array.js";
5
5
  export { FormNumber } from "./forms/number.js";
6
6
  export { FormString } from "./forms/string.js";
7
+ export { FormConnection, Connection } from "./forms/connection.js";
7
8
  export * from "./forms/path.js";
8
9
  export { Form } from "./forms/build.js";
@@ -8,17 +8,27 @@ import { z } from "zod";
8
8
  import { InitialInstructions } from "../../components/InitialInstructions.js";
9
9
  import { Logo } from "../../components/Logo.js";
10
10
  import { Select } from "../../components/Select.js";
11
- import { addConnectionMachine, audiences, connectionTypes, } from "../../machines/add-connection-machine.js";
11
+ import { addConnectionMachine, connectionTypes } from "../../machines/add-connection-machine.js";
12
12
  export const description = "Create a new connection for your Attio app";
13
13
  export const options = z.object({
14
+ slug: z
15
+ .string()
16
+ .optional()
17
+ .describe(option({ description: "A unique slug for your connection" })),
18
+ label: z
19
+ .string()
20
+ .optional()
21
+ .describe(option({ description: "The label for your connection that will be displayed to users" })),
22
+ description: z
23
+ .string()
24
+ .optional()
25
+ .describe(option({
26
+ description: "A more detailed description of your connection that will be displayed to users",
27
+ })),
14
28
  type: z
15
29
  .enum(["secret", "oauth2-code"])
16
30
  .optional()
17
31
  .describe(option({ description: "The type of connection to create" })),
18
- audience: z
19
- .enum(["workspace", "workspace-member"])
20
- .optional()
21
- .describe(option({ description: "The audience for the connection" })),
22
32
  authorizeUrl: z
23
33
  .string()
24
34
  .url("Invalid URL, e.g. https://authorization-server.com/authorize")
@@ -51,11 +61,13 @@ export const options = z.object({
51
61
  .default(false)
52
62
  .describe(option({ description: "Run in development mode (additional debugging info)" })),
53
63
  });
54
- export default function AddConnection({ options: { type: connectionType, audience, authorizeUrl, accessTokenUrl, scopes, clientId, clientSecret, dev, }, }) {
64
+ export default function AddConnection({ options: { slug, label, description, type: connectionType, authorizeUrl, accessTokenUrl, scopes, clientId, clientSecret, dev, }, }) {
55
65
  const [snapshot, send] = useMachine(addConnectionMachine, {
56
66
  input: {
67
+ slug,
68
+ label,
69
+ description,
57
70
  connectionType,
58
- audience,
59
71
  authorizeUrl,
60
72
  accessTokenUrl,
61
73
  scopes,
@@ -69,22 +81,41 @@ export default function AddConnection({ options: { type: connectionType, audienc
69
81
  React.createElement(Logo, null),
70
82
  React.createElement(Box, { flexDirection: "column" },
71
83
  snapshot.matches("Show config instructions") && (React.createElement(InitialInstructions, { reason: snapshot.context.configError })),
72
- snapshot.matches("Already have a connection") && (React.createElement(React.Fragment, null,
84
+ snapshot.matches("Ask for slug") && (React.createElement(React.Fragment, null,
73
85
  React.createElement(Box, null,
74
- React.createElement(Text, { color: "redBright" }, "This app already has a connection."),
75
- React.createElement(Text, null, " To change it, you first must remove it with:")),
76
- React.createElement(Box, { flexDirection: "column", borderStyle: "round", width: 27, paddingX: 1, marginBottom: 1 },
77
- React.createElement(Text, null, "attio connection remove")))),
86
+ React.createElement(Text, null, "Unique Slug: "),
87
+ React.createElement(TextInput, { value: snapshot.context.slug ?? "", placeholder: "my-access-token", onChange: (slug) => send({ type: "Update Slug", slug }), onSubmit: () => send({ type: "Submit" }) })))),
88
+ snapshot.matches("Ask for label") && (React.createElement(React.Fragment, null,
89
+ React.createElement(Box, null,
90
+ React.createElement(Text, null, "Provide a label for your connection. This will be displayed to users. (You can edit this later)")),
91
+ React.createElement(Box, null,
92
+ React.createElement(TextInput, { value: snapshot.context.label ?? "", placeholder: "My Awesome Connection", onChange: (label) => send({ type: "Update Label", label }), onSubmit: () => send({ type: "Submit" }) })))),
93
+ snapshot.matches("Ask for description") && (React.createElement(React.Fragment, null,
94
+ React.createElement(Box, null,
95
+ React.createElement(Text, null, "Provide an optional detailed description for your connection. This will be displayed to users. (You can edit this later)")),
96
+ React.createElement(Box, null,
97
+ React.createElement(TextInput, { value: snapshot.context.description ?? "", onChange: (description) => send({ type: "Update Description", description }), onSubmit: () => send({ type: "Submit" }) })))),
78
98
  snapshot.matches("Ask for connection type") && (React.createElement(React.Fragment, null,
79
99
  React.createElement(Box, null,
80
100
  React.createElement(Text, null, "What type of connection will this be?")),
81
101
  React.createElement(Box, null,
82
102
  React.createElement(Select, { items: connectionTypes, onSelect: (connectionType) => send({ type: "Choose Connection Type", connectionType }) })))),
83
- snapshot.matches("Ask for audience") && (React.createElement(React.Fragment, null,
103
+ snapshot.matches("Ask for global") && (React.createElement(React.Fragment, null,
104
+ React.createElement(Box, null,
105
+ React.createElement(Text, null, "Should users of your app be allowed to add multiple connections?")),
106
+ React.createElement(Box, null,
107
+ React.createElement(Select, { items: [
108
+ { value: true, label: "Yes" },
109
+ { value: false, label: "No" },
110
+ ], onSelect: (global) => send({ type: "Choose Global", global }) })))),
111
+ snapshot.matches("Ask for allow multiple") && (React.createElement(React.Fragment, null,
84
112
  React.createElement(Box, null,
85
- React.createElement(Text, null, "What is the audience of this connection?")),
113
+ React.createElement(Text, null, "Should this connection be allowed to be used multiple times?")),
86
114
  React.createElement(Box, null,
87
- React.createElement(Select, { items: audiences, onSelect: (audience) => send({ type: "Choose Audience", audience }) })))),
115
+ React.createElement(Select, { items: [
116
+ { value: true, label: "Yes" },
117
+ { value: false, label: "No" },
118
+ ], onSelect: (allowMultiple) => send({ type: "Choose Allow Multiple", allowMultiple }) })))),
88
119
  snapshot.matches("Ask for Authorize URL") && (React.createElement(React.Fragment, null,
89
120
  React.createElement(Box, null,
90
121
  React.createElement(Text, null, "OAuth Authorize URL: "),
@@ -88,7 +88,9 @@ export default function Dev({ options: { debug } }) {
88
88
  React.createElement(Text, { color: "redBright" }, "\u274C Upload Error"),
89
89
  React.createElement(Text, null,
90
90
  "\u2013 ",
91
- snapshot.context.uploadError?.message))))),
91
+ snapshot.context.uploadError?.message)))),
92
+ snapshot.matches({ Watching: { Graphql: "Started" } }) && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
93
+ React.createElement(Text, null, "Press \"o\" to open GraphQL Explorer")))),
92
94
  hasErrors && (React.createElement(ScrollBox, { borderStyle: "round", padding: 1 },
93
95
  jsError && renderBuildErrors(jsError),
94
96
  tsErrors && renderTypeScriptErrors(tsErrors)))));