conductor-node 9.8.1 → 10.0.0

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/README.md CHANGED
@@ -16,7 +16,7 @@ Execute _any_ read or write [QuickBooks Desktop API](https://developer.intuit.co
16
16
 
17
17
  ## Requirements
18
18
 
19
- 1. A Conductor API key from Danny.
19
+ 1. A Conductor API key.
20
20
  2. A running version of QuickBooks Desktop connected to Conductor. See our [guide to connecting QuickBooks Desktop to Conductor](https://conductor-io.notion.site/QuickBooks-Desktop-integration-setup-86f6325f747d4447b95d27b59ad89ef5).
21
21
 
22
22
  ## Installation
@@ -34,7 +34,7 @@ import Conductor from "conductor-node";
34
34
  const conductor = new Conductor("sk_test_...");
35
35
 
36
36
  // Fetch all authorized integration-connections.
37
- const qbdConnections = await conductor.getIntegrationConnections();
37
+ const qbdConnections = await conductor.integrationConnection.list();
38
38
 
39
39
  // Execute any QBD API against your QBD connection id.
40
40
  const newAccount = await conductor.qbd.account.add(qbdConnections[0].id, {
@@ -46,12 +46,20 @@ const newAccount = await conductor.qbd.account.add(qbdConnections[0].id, {
46
46
 
47
47
  ## APIs
48
48
 
49
- ### `createIntegrationConnection(input: CreateIntegrationConnectionInput)`
49
+ ### `integrationConnections.list()`
50
+
51
+ Returns a of list all integration-connections associated with your Conductor account.
52
+
53
+ ```ts
54
+ const qbdConnections = await conductor.integrationConnections.list();
55
+ ```
56
+
57
+ ### `integrationConnections.create(input: CreateIntegrationConnectionInput)`
50
58
 
51
59
  Creates a new integration-connection.
52
60
 
53
61
  ```ts
54
- const newQbdConnection = await conductor.createIntegrationConnection({
62
+ const newQbdConnection = await conductor.integrationConnections.create({
55
63
  // The identifier of the third-party platform to integrate.
56
64
  integrationKey: "quickbooks-desktop",
57
65
  // Your end-user's unique ID in your product's database. Must be
@@ -79,45 +87,27 @@ The response looks like the following:
79
87
  }
80
88
  ```
81
89
 
82
- ### `qbd.*`
83
-
84
- Executes any QuickBooks Desktop (QBD) API against a specific integration-connection id. See the official [QuickBooks Desktop API Reference](https://developer.intuit.com/app/developer/qbdesktop/docs/api-reference/qbdesktop) for a complete list of available APIs.
85
-
86
- ```ts
87
- const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
88
- Name: "Test Account",
89
- AccountType: "Bank",
90
- OpenBalance: "100",
91
- });
92
- ```
93
-
94
- ### `getIntegrationConnections()`
95
-
96
- Fetches all authorized integration-connections.
97
-
98
- ```ts
99
- const qbdConnections = await conductor.getIntegrationConnections();
100
- ```
101
-
102
- ### `getIntegrationConnection(id: string)`
90
+ ### `integrationConnections.retrieve(id: string)`
103
91
 
104
- Fetches a single integration-connection by id.
92
+ Retrieves the specified integration-connection.
105
93
 
106
94
  ```ts
107
- const qbdConnection = await conductor.getIntegrationConnection(qbdConnectionId);
95
+ const qbdConnection = await conductor.integrationConnections.retrieve(
96
+ qbdConnectionId
97
+ );
108
98
  ```
109
99
 
110
- ### `pingIntegrationConnection(id: string)`
100
+ ### `integrationConnections.ping(id: string)`
111
101
 
112
102
  Checks whether the specified integration-connection can connect and process requests end-to-end.
113
103
 
114
- If the connection fails, the error we encountered will be thrown as a [`ConductorError`](#error-handling). This information is useful for showing a "connection status" indicator in your app. If an error occurs, we recommend displaying the property `error.endUserMessage` to your end-user in your app's UI.
104
+ If the connection fails, the error we encountered will be thrown as a [`ConductorError`](#error-handling) (like any request). This information is useful for showing a "connection status" indicator in your app. If an error occurs, we recommend displaying the property `error.endUserMessage` to your end-user in your app's UI.
115
105
 
116
106
  Using `async`/`await`:
117
107
 
118
108
  ```ts
119
109
  try {
120
- await conductor.pingIntegrationConnection(qbdConnectionId);
110
+ await conductor.integrationConnections.ping(qbdConnectionId);
121
111
  } catch (error) {
122
112
  if (error instanceof ConductorError) {
123
113
  // Update your app's UI to display `error.endUserMessage`.
@@ -129,7 +119,7 @@ try {
129
119
  Or in the form of a rejected promise:
130
120
 
131
121
  ```ts
132
- conductor.pingIntegrationConnection(qbdConnectionId).catch((error) => {
122
+ conductor.integrationConnections.ping(qbdConnectionId).catch((error) => {
133
123
  if (error instanceof ConductorError) {
134
124
  // Update your app's UI to display `error.endUserMessage`.
135
125
  }
@@ -137,6 +127,18 @@ conductor.pingIntegrationConnection(qbdConnectionId).catch((error) => {
137
127
  });
138
128
  ```
139
129
 
130
+ ### `qbd.*`
131
+
132
+ Executes any QuickBooks Desktop (QBD) API against a specific integration-connection id. See the official [QuickBooks Desktop API Reference](https://developer.intuit.com/app/developer/qbdesktop/docs/api-reference/qbdesktop) for a complete list of available APIs.
133
+
134
+ ```ts
135
+ const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
136
+ Name: "Test Account",
137
+ AccountType: "Bank",
138
+ OpenBalance: "100",
139
+ });
140
+ ```
141
+
140
142
  ## TypeScript
141
143
 
142
144
  Access the entire QuickBooks Desktop API through TypeScript. The `qbd.*` APIs are fully typed with inline documentation and will autocomplete in your editor.
@@ -162,11 +164,11 @@ All errors thrown by the Conductor API are instances of `ConductorError` or its
162
164
  | Property | Type | Description |
163
165
  | ----------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
164
166
  | `type` | `string` | Categorizes the error. See [Error Types](#error-types) below.<br><br>This value is the same as the subclass name. E.g., `"ConductorIntegrationError"` or `"ConductorInvalidRequestError"`. |
165
- | `code` | `string` | The unique error code from Conductor, which is useful for adding special handling for specific errors. E.g., `"INTEGRATION_CONNECTION_MISSING"`, `"API_KEY_INVALID"`, or `"QBD_REQUEST_ERROR"`.<br><br>In contrast, `type` is more general and categorizes the error. |
167
+ | `code` | `string` | The unique error code from Conductor, which is useful for adding special handling for specific errors. E.g., `"RESOURCE_MISSING"`, `"API_KEY_INVALID"`, or `"QBD_REQUEST_ERROR"`.<br><br>In contrast, `type` is more general and categorizes the error. |
168
+ | `httpStatusCode` | `number` or `undefined` | The HTTP status code of the response that included the error. You probably won't need this. |
166
169
  | `message` | `string` | The developer-friendly error message for your logs. |
167
170
  | `endUserMessage` | `string` | The end-user-friendly error message to display in your app's UI to your end-users.<br><br>This value exists for _every_ error. E.g., for a QBD connection error, it might recommend the end-user to check that their QuickBooks Desktop is open and that they're logged in. But if a Conductor API key is expired, e.g., this message will just say "An internal server error occurred. Please try again later.". |
168
171
  | `integrationCode` | `string` or `undefined` | The unique error code supplied by the third-party integration for errors returned by the integration (i.e., `ConductorIntegrationError`) or integration connector (i.e., `ConductorIntegrationConnectorError`). This is useful for adding special handling for specific errors from the third-party integration or connector.<br><br>The integration's corresponding error message for this code is in `error.message`.<br><br>The third-party integrations' error codes are not standardized, so you should not rely on this code to be the same across integrations. |
169
- | `httpStatusCode` | `number` or `undefined` | The HTTP status code of the response that included the error. You probably won't need this. |
170
172
 
171
173
  ### Error Types
172
174
 
@@ -224,16 +226,16 @@ conductor.qbd.account
224
226
  });
225
227
  ```
226
228
 
227
- ### Centralized Error Handling
229
+ ### Global Error Handling
228
230
 
229
- It is unnecessary to wrap each API call individually, as demonstrated in the examples above. Instead, we suggest implementing a centralized error handler for your server, such as [`app.use((error, ...) => { ... })` in Express](https://expressjs.com/en/guide/error-handling.html#writing-error-handlers) or [`formatError` in Apollo Server](https://apollographql.com/docs/apollo-server/data/errors/#for-client-responses). Within this handler, perform the following actions:
231
+ It is unnecessary to wrap each API call individually, as demonstrated in the examples above. Instead, we suggest implementing a Global error handler for your server, such as [`app.use((error, ...) => { ... })` in Express](https://expressjs.com/en/guide/error-handling.html#writing-error-handlers) or [`formatError` in Apollo Server](https://apollographql.com/docs/apollo-server/data/errors/#for-client-responses). Within this handler, perform the following actions:
230
232
 
231
233
  1. For any `ConductorError` instance, display the `error.endUserMessage` property to the end-user in your app's UI while logging the complete error object.
232
234
  2. For all `ConductorError` instances, transmit the full error object to your error-tracking service (e.g., Sentry):
233
235
  - Send a **warning** for instances of `ConductorIntegrationConnectionError`, which are not actionable by you and can only be resolved by the end-user; for example, failure to connect to QuickBooks Desktop on the end-user's computer.
234
236
  - Send an **error** for all other `ConductorError` instances, such as an invalid API key.
235
237
 
236
- For example, using an Express error handler:
238
+ For example, using an [Express error handler](https://expressjs.com/en/guide/error-handling.html#writing-error-handlers):
237
239
 
238
240
  ```ts
239
241
  import * as Sentry from "@sentry/node";
@@ -259,7 +261,7 @@ app.use((error, req, res, next) => {
259
261
  });
260
262
  ```
261
263
 
262
- Or using Apollo Server's error handler:
264
+ Or using [Apollo Server's error handler](https://apollographql.com/docs/apollo-server/data/errors/#for-client-responses):
263
265
 
264
266
  ```ts
265
267
  import { ApolloServer } from "@apollo/server";
package/dist/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "conductor-node",
3
- "version": "9.8.1",
4
- "description": "Easily integrate with the entire QuickBooks Desktop API with fully-typed async TypeScript",
5
- "author": "Danny Nemer <hi@DannyNemer.com>",
3
+ "version": "10.0.0",
4
+ "description": "Easily integrate the entire QuickBooks Desktop API using fully-typed async TypeScript",
6
5
  "license": "MIT",
7
6
  "type": "commonjs",
8
7
  "main": "dist/src/index.js",
@@ -13,10 +12,9 @@
13
12
  ],
14
13
  "scripts": {
15
14
  "prepack": "yarn --silent tsc && yarn --silent delete-compiled-dev-files && yarn --silent tsc-alias",
16
- "delete-compiled-dev-files": "rm -rf `find ./dist -type d -name __tests__` ./dist/src/utils/testing.* ./dist/src/graphql/codegenConfig.*",
15
+ "delete-compiled-dev-files": "rm -rf `find ./dist -type d -name __tests__` ./dist/src/utils/test/*",
17
16
  "postpack": "rm -rf dist",
18
17
  "clean": "rm -rf dist package conductor-node-*.tgz tsconfig.tsbuildinfo",
19
- "gen:graphql": "yarn graphql-codegen --config=./src/graphql/codegenConfig.ts",
20
18
  "diff": "yarn pack && npm diff --diff=conductor-node@latest --diff=conductor-node-v$(node -p \"require('./package.json').version\").tgz && yarn clean",
21
19
  "prepublishOnly": "yarn test",
22
20
  "test": "yarn --cwd=../../ test ./packages/client",
@@ -26,25 +24,17 @@
26
24
  "node": ">=16"
27
25
  },
28
26
  "dependencies": {
29
- "graphql": "^16.6.0",
30
- "graphql-request": "~5.1.0"
27
+ "axios": "^1.4.0"
31
28
  },
32
29
  "devDependencies": {
33
- "@graphql-codegen/add": "^4.0.1",
34
- "@graphql-codegen/cli": "^3.2.1",
35
- "@graphql-codegen/typescript-graphql-request": "^4.5.8",
36
- "@graphql-codegen/typescript-operations": "^3.0.1",
30
+ "axios-mock-adapter": "^1.21.4",
37
31
  "tsc-alias": "^1.7.0"
38
32
  },
39
33
  "keywords": [
40
- "accounting",
41
- "api",
42
34
  "conductor",
43
35
  "qbd",
44
36
  "qbwc",
45
37
  "qbxml",
46
- "quickbooks desktop",
47
- "sdk",
48
- "typescript"
38
+ "quickbooks desktop"
49
39
  ]
50
40
  }
@@ -1,57 +1,17 @@
1
- import type { GraphqlCreateIntegrationConnectionInput, GraphqlCreateIntegrationConnectionMutation, GraphqlGetIntegrationConnectionQuery, GraphqlGetIntegrationConnectionQueryVariables, GraphqlGetIntegrationConnectionsQuery, GraphqlPingIntegrationConnectionMutation, GraphqlPingIntegrationConnectionMutationVariables } from "./graphql/__generated__/operationTypes";
2
1
  import QbdIntegration from "./integrations/qbd/QbdIntegration";
3
- import { getServerUrlForEnvironment } from "./utils/misc";
2
+ import IntegrationConnectionsResource from "./resources/IntegrationConnectionsResource";
3
+ import { getServerUrlForEnvironment } from "./utils/http";
4
4
  export interface ClientOptions {
5
- /** Logs each request and response. */
5
+ /** Logs each request, response, and error. */
6
6
  readonly verbose?: boolean;
7
7
  readonly serverEnvironment?: Parameters<typeof getServerUrlForEnvironment>[0];
8
8
  }
9
9
  export default class Client {
10
+ readonly integrationConnections: IntegrationConnectionsResource;
10
11
  /** QuickBooks Desktop integration. */
11
12
  readonly qbd: QbdIntegration;
12
- private readonly graphqlClient;
13
- private readonly graphqlOperations;
13
+ private readonly httpClient;
14
14
  constructor(apiKey: string, { verbose, serverEnvironment }?: ClientOptions);
15
- /**
16
- * Fetches all integration-connections associated with your Conductor account.
17
- *
18
- * @returns The integration-connections.
19
- */
20
- getIntegrationConnections(): Promise<GraphqlGetIntegrationConnectionsQuery["integrationConnections"]>;
21
- /**
22
- * Fetches the specified integration-connection.
23
- *
24
- * @param integrationConnectionId The integration-connection ID.
25
- * @returns The integration-connection.
26
- */
27
- getIntegrationConnection(integrationConnectionId: GraphqlGetIntegrationConnectionQueryVariables["integrationConnectionId"]): Promise<GraphqlGetIntegrationConnectionQuery["integrationConnection"]>;
28
- /**
29
- * Creates a new integration-connection.
30
- *
31
- * @param input - The input object to create the integration-connection.
32
- * @param input.integrationKey The identifier of the third-party platform to
33
- * integrate.
34
- * @param input.endUserSourceId Your end-user's unique ID in your product's
35
- * database. Must be distinct from your other connections for the same
36
- * integration.
37
- * @param input.endUserEmail Your end-user's email address for identification
38
- * only. No emails will be sent.
39
- * @param input.endUserCompanyName Your end-user's company name that will be
40
- * shown elsewhere in Conductor.
41
- * @returns The newly created integration-connection.
42
- */
43
- createIntegrationConnection(input: GraphqlCreateIntegrationConnectionInput & {
44
- integrationKey: "quickbooks-desktop";
45
- }): Promise<GraphqlCreateIntegrationConnectionMutation["createIntegrationConnection"]["integrationConnection"]>;
46
- /**
47
- * Checks whether the specified integration-connection can connect and process
48
- * requests end-to-end.
49
- *
50
- * If the connection fails, the error we encountered will be thrown as a
51
- * `ConductorError`. This information is useful for showing a "connection
52
- * status" indicator in your app. If an error occurs, we recommend displaying
53
- * the property `error.endUserMessage` to your end-user in your app's UI.
54
- */
55
- pingIntegrationConnection(integrationConnectionId: GraphqlPingIntegrationConnectionMutationVariables["input"]["integrationConnectionId"]): Promise<GraphqlPingIntegrationConnectionMutation["pingIntegrationConnection"]>;
15
+ private createHttpClient;
56
16
  private createHeaders;
57
17
  }
@@ -4,76 +4,35 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const package_json_1 = __importDefault(require("./../package.json"));
7
- const operationTypes_1 = require("./graphql/__generated__/operationTypes");
8
- const graphqlOperationWrapper_1 = require("./graphql/graphqlOperationWrapper");
9
7
  const QbdIntegration_1 = __importDefault(require("./integrations/qbd/QbdIntegration"));
10
- const misc_1 = require("./utils/misc");
11
- const graphql_request_1 = require("graphql-request");
8
+ const errorHandling_1 = require("./interceptors/errorHandling");
9
+ const logging_1 = require("./interceptors/logging");
10
+ const IntegrationConnectionsResource_1 = __importDefault(require("./resources/IntegrationConnectionsResource"));
11
+ const checkForUpdates_1 = require("./utils/checkForUpdates");
12
+ const http_1 = require("./utils/http");
13
+ const axios_1 = __importDefault(require("axios"));
12
14
  class Client {
15
+ integrationConnections;
13
16
  /** QuickBooks Desktop integration. */
14
17
  qbd;
15
- graphqlClient;
16
- graphqlOperations;
18
+ httpClient;
17
19
  constructor(apiKey, { verbose = false, serverEnvironment = "production" } = {}) {
18
- (0, misc_1.checkForUpdates)();
19
- this.graphqlClient = new graphql_request_1.GraphQLClient(`${(0, misc_1.getServerUrlForEnvironment)(serverEnvironment)}/graphql`, { headers: this.createHeaders(apiKey) });
20
- this.graphqlOperations = (0, graphqlOperationWrapper_1.wrapGraphqlOperations)((0, operationTypes_1.getSdk)(this.graphqlClient), verbose);
21
- this.qbd = new QbdIntegration_1.default(this.graphqlOperations);
20
+ (0, checkForUpdates_1.checkForUpdates)();
21
+ this.httpClient = this.createHttpClient(apiKey, verbose, serverEnvironment);
22
+ this.integrationConnections = new IntegrationConnectionsResource_1.default(this.httpClient);
23
+ this.qbd = new QbdIntegration_1.default(this.httpClient);
22
24
  }
23
- /**
24
- * Fetches all integration-connections associated with your Conductor account.
25
- *
26
- * @returns The integration-connections.
27
- */
28
- async getIntegrationConnections() {
29
- return this.graphqlOperations
30
- .getIntegrationConnections()
31
- .then((result) => result.integrationConnections);
32
- }
33
- /**
34
- * Fetches the specified integration-connection.
35
- *
36
- * @param integrationConnectionId The integration-connection ID.
37
- * @returns The integration-connection.
38
- */
39
- async getIntegrationConnection(integrationConnectionId) {
40
- return this.graphqlOperations
41
- .getIntegrationConnection({ integrationConnectionId })
42
- .then((result) => result.integrationConnection);
43
- }
44
- /**
45
- * Creates a new integration-connection.
46
- *
47
- * @param input - The input object to create the integration-connection.
48
- * @param input.integrationKey The identifier of the third-party platform to
49
- * integrate.
50
- * @param input.endUserSourceId Your end-user's unique ID in your product's
51
- * database. Must be distinct from your other connections for the same
52
- * integration.
53
- * @param input.endUserEmail Your end-user's email address for identification
54
- * only. No emails will be sent.
55
- * @param input.endUserCompanyName Your end-user's company name that will be
56
- * shown elsewhere in Conductor.
57
- * @returns The newly created integration-connection.
58
- */
59
- async createIntegrationConnection(input) {
60
- return this.graphqlOperations
61
- .createIntegrationConnection({ input })
62
- .then((result) => result.createIntegrationConnection.integrationConnection);
63
- }
64
- /**
65
- * Checks whether the specified integration-connection can connect and process
66
- * requests end-to-end.
67
- *
68
- * If the connection fails, the error we encountered will be thrown as a
69
- * `ConductorError`. This information is useful for showing a "connection
70
- * status" indicator in your app. If an error occurs, we recommend displaying
71
- * the property `error.endUserMessage` to your end-user in your app's UI.
72
- */
73
- async pingIntegrationConnection(integrationConnectionId) {
74
- return this.graphqlOperations
75
- .pingIntegrationConnection({ input: { integrationConnectionId } })
76
- .then((result) => result.pingIntegrationConnection);
25
+ createHttpClient(apiKey, verbose, serverEnvironment) {
26
+ const httpClient = axios_1.default.create({
27
+ baseURL: `${(0, http_1.getServerUrlForEnvironment)(serverEnvironment)}/v1`,
28
+ headers: this.createHeaders(apiKey),
29
+ timeout: 0, // No timeout (default).
30
+ });
31
+ // Wrap errors in `ConductorError`.
32
+ (0, errorHandling_1.addErrorHandlingInterceptors)(httpClient);
33
+ // Must be the last interceptor for error logging to use the wrapped error.
34
+ (0, logging_1.addLoggingInterceptors)(httpClient, verbose);
35
+ return httpClient;
77
36
  }
78
37
  createHeaders(apiKey) {
79
38
  return {
@@ -1,8 +1,8 @@
1
- import type Client from "../Client";
2
- import type { GraphqlSendIntegrationRequestInput, GraphqlSendIntegrationRequestMutation } from "../graphql/__generated__/operationTypes";
3
- export default class BaseIntegration {
4
- private readonly graphqlOperations;
5
- constructor(graphqlOperations: Client["graphqlOperations"]);
1
+ import type { IntegrationConnection } from "../resources/IntegrationConnectionsResource";
2
+ import type { AxiosInstance } from "axios";
3
+ export default abstract class BaseIntegration {
4
+ protected readonly httpClient: AxiosInstance;
5
+ constructor(httpClient: AxiosInstance);
6
6
  /** Not intended for public use. */
7
- protected sendIntegrationRequest(input: GraphqlSendIntegrationRequestInput): Promise<GraphqlSendIntegrationRequestMutation["sendIntegrationRequest"]["response"]>;
7
+ protected sendRequest(id: IntegrationConnection["id"], payload: Record<string, unknown>): Promise<object>;
8
8
  }
@@ -1,15 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class BaseIntegration {
4
- graphqlOperations;
5
- constructor(graphqlOperations) {
6
- this.graphqlOperations = graphqlOperations;
4
+ httpClient;
5
+ constructor(httpClient) {
6
+ this.httpClient = httpClient;
7
7
  }
8
8
  /** Not intended for public use. */
9
- async sendIntegrationRequest(input) {
10
- return this.graphqlOperations
11
- .sendIntegrationRequest({ input })
12
- .then((result) => result.sendIntegrationRequest.response);
9
+ async sendRequest(id, payload) {
10
+ const { data } = await this.httpClient.post(`/integration-connections/${id}/send-request`, payload);
11
+ return data;
13
12
  }
14
13
  }
15
14
  exports.default = BaseIntegration;
@@ -2404,10 +2404,7 @@ class QbdIntegration extends BaseIntegration_1.default {
2404
2404
  query: async (integrationConnectionId, params) => this.sendRequestWrapper(integrationConnectionId, { WorkersCompCodeQueryRq: params }, "WorkersCompCodeQueryRs", "WorkersCompCodeRet"),
2405
2405
  };
2406
2406
  async sendRequestWrapper(integrationConnectionId, params, responseWrapperKey, responseBodyKey) {
2407
- const response = (await this.sendIntegrationRequest({
2408
- integrationConnectionId,
2409
- requestObject: params,
2410
- }));
2407
+ const response = (await this.sendRequest(integrationConnectionId, params));
2411
2408
  const responseBody = response[responseWrapperKey]?.[responseBodyKey];
2412
2409
  if (responseBody === undefined) {
2413
2410
  throw new error_1.ConductorIntegrationError({
@@ -0,0 +1,2 @@
1
+ import type { AxiosInstance } from "axios";
2
+ export declare function addErrorHandlingInterceptors(httpClient: AxiosInstance): void;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addErrorHandlingInterceptors = void 0;
4
+ const error_1 = require("../utils/error");
5
+ const axios_1 = require("axios");
6
+ function addErrorHandlingInterceptors(httpClient) {
7
+ httpClient.interceptors.response.use((response) => response, (error) => {
8
+ // The request was made and the server responded with a status code that
9
+ // falls out of the range of 2xx.
10
+ if (error.response) {
11
+ const errorData = error.response.data;
12
+ if (!(0, error_1.isWellFormedConductorServerError)(errorData)) {
13
+ throw new error_1.ConductorInternalError({
14
+ code: "INVALID_JSON_RESPONSE",
15
+ message: "Invalid JSON received from the Conductor API.",
16
+ httpStatusCode: error.status ?? axios_1.HttpStatusCode.InternalServerError,
17
+ });
18
+ }
19
+ throw (0, error_1.generateConductorErrorFromType)({
20
+ ...errorData.error,
21
+ httpStatusCode: error.response.status,
22
+ });
23
+ }
24
+ if (error.code === axios_1.AxiosError.ECONNABORTED) {
25
+ let message = "Request aborted due to timeout being reached";
26
+ if (error.config?.timeout !== undefined) {
27
+ message += ` (${error.config.timeout}ms)`;
28
+ }
29
+ throw new error_1.ConductorConnectionError({
30
+ code: error.code,
31
+ message,
32
+ httpStatusCode: error.status ?? axios_1.HttpStatusCode.RequestTimeout,
33
+ });
34
+ }
35
+ // Either the request was made but no response was received (e.g.,
36
+ // Conductor API is offline) or an error ocurred when setting up the
37
+ // request (e.g., no network connection).
38
+ throw new error_1.ConductorConnectionError({
39
+ code: error.code ?? "NETWORK_ERROR",
40
+ message: "An error occurred with our connection to Conductor.",
41
+ httpStatusCode: error.status,
42
+ });
43
+ });
44
+ }
45
+ exports.addErrorHandlingInterceptors = addErrorHandlingInterceptors;
@@ -0,0 +1,7 @@
1
+ import type { AxiosInstance, AxiosRequestConfig } from "axios";
2
+ export interface RequestConfigWithStartTime extends AxiosRequestConfig {
3
+ startTime: number;
4
+ }
5
+ export declare function addLoggingInterceptors(httpClient: AxiosInstance, verbose: boolean): void;
6
+ export declare function getDurationStringFromConfig(config: RequestConfigWithStartTime): string;
7
+ export declare function stringifyForLogs(object: unknown): string;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stringifyForLogs = exports.getDurationStringFromConfig = exports.addLoggingInterceptors = void 0;
7
+ const node_util_1 = __importDefault(require("node:util"));
8
+ function addLoggingInterceptors(httpClient, verbose) {
9
+ httpClient.interceptors.request.use((config) => {
10
+ if (verbose) {
11
+ config.startTime = Date.now();
12
+ console.log("Conductor request:", stringifyForLogs(createRequestLogObject(config)));
13
+ }
14
+ return config;
15
+ });
16
+ httpClient.interceptors.response.use((response) => {
17
+ if (verbose) {
18
+ console.log("Conductor response:", stringifyForLogs(createResponseLogObject(response)));
19
+ }
20
+ return response;
21
+ }, (error) => {
22
+ // Log after the other interceptor wraps the response error in a
23
+ // `ConductorError`.
24
+ // NOTE: We cannot include duration because we lack access to
25
+ // `AxiosError.config` because we already wrapped the error.
26
+ if (verbose) {
27
+ console.log("Conductor error:", stringifyForLogs(error));
28
+ }
29
+ throw error;
30
+ });
31
+ }
32
+ exports.addLoggingInterceptors = addLoggingInterceptors;
33
+ function createRequestLogObject(config) {
34
+ return {
35
+ method: config.method?.toUpperCase(),
36
+ endpoint: config.url,
37
+ body: config.data,
38
+ };
39
+ }
40
+ function createResponseLogObject(response) {
41
+ return {
42
+ duration: getDurationStringFromConfig(response.config),
43
+ status: response.status,
44
+ data: response.data,
45
+ request: createRequestLogObject(response.config),
46
+ };
47
+ }
48
+ function getDurationStringFromConfig(config) {
49
+ const duration = Date.now() - config.startTime;
50
+ return `${Math.round(duration / 10) / 100}s`;
51
+ }
52
+ exports.getDurationStringFromConfig = getDurationStringFromConfig;
53
+ function stringifyForLogs(object) {
54
+ return node_util_1.default.inspect(object, {
55
+ depth: 5,
56
+ // Omit color codes to keep logs clean when sent to a log management
57
+ // service.
58
+ colors: false,
59
+ });
60
+ }
61
+ exports.stringifyForLogs = stringifyForLogs;
@@ -0,0 +1,6 @@
1
+ import type { AxiosInstance } from "axios";
2
+ export default abstract class BaseResource {
3
+ protected readonly httpClient: AxiosInstance;
4
+ protected abstract readonly ROUTE: string;
5
+ constructor(httpClient: AxiosInstance);
6
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class BaseResource {
4
+ httpClient;
5
+ constructor(httpClient) {
6
+ this.httpClient = httpClient;
7
+ }
8
+ }
9
+ exports.default = BaseResource;
@@ -0,0 +1,59 @@
1
+ import BaseResource from "../resources/BaseResource";
2
+ export interface IntegrationConnection {
3
+ id: string;
4
+ integrationKey: string;
5
+ endUserSourceId: string;
6
+ endUserEmail: string;
7
+ endUserCompanyName: string;
8
+ }
9
+ export type CreateIntegrationConnectionInput = Pick<IntegrationConnection, "endUserCompanyName" | "endUserEmail" | "endUserSourceId" | "integrationKey">;
10
+ export interface PingIntegrationConnectionOutput {
11
+ duration: number;
12
+ }
13
+ export default class IntegrationConnectionsResource extends BaseResource {
14
+ protected readonly ROUTE = "/integration-connections";
15
+ /**
16
+ * Returns a list of all integration-connections associated with your
17
+ * Conductor account.
18
+ *
19
+ * @returns Your integration-connections.
20
+ */
21
+ list(): Promise<IntegrationConnection[]>;
22
+ /**
23
+ * Creates a new integration-connection.
24
+ *
25
+ * @param input The input object to create the integration-connection.
26
+ * @param input.integrationKey The identifier of the third-party platform to
27
+ * integrate (e.g., "quickbooks-desktop").
28
+ * @param input.endUserSourceId Your end-user's unique ID in your product's
29
+ * database. Must be distinct from your other connections for the same
30
+ * integration.
31
+ * @param input.endUserEmail Your end-user's email address for identification
32
+ * only. No emails will be sent.
33
+ * @param input.endUserCompanyName Your end-user's company name that will be
34
+ * shown elsewhere in Conductor.
35
+ * @returns The newly created integration-connection.
36
+ */
37
+ create(input: CreateIntegrationConnectionInput): Promise<IntegrationConnection>;
38
+ /**
39
+ * Retrieves the specified integration-connection.
40
+ *
41
+ * @param id The integration-connection ID.
42
+ * @returns The integration-connection.
43
+ */
44
+ retrieve(id: IntegrationConnection["id"]): Promise<IntegrationConnection>;
45
+ /**
46
+ * Checks whether the specified integration-connection can connect and process
47
+ * requests end-to-end.
48
+ *
49
+ * If the connection fails, the error we encountered will be thrown as a
50
+ * `ConductorError` (like any request). This information is useful for showing
51
+ * a "connection status" indicator in your app. If an error occurs, we
52
+ * recommend displaying the property `error.endUserMessage` to your end-user
53
+ * in your app's UI.
54
+ *
55
+ * @param id The integration-connection ID.
56
+ * @returns The ping result with the duration in milliseconds.
57
+ */
58
+ ping(id: IntegrationConnection["id"]): Promise<PingIntegrationConnectionOutput>;
59
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const BaseResource_1 = __importDefault(require("../resources/BaseResource"));
7
+ class IntegrationConnectionsResource extends BaseResource_1.default {
8
+ ROUTE = "/integration-connections";
9
+ /**
10
+ * Returns a list of all integration-connections associated with your
11
+ * Conductor account.
12
+ *
13
+ * @returns Your integration-connections.
14
+ */
15
+ async list() {
16
+ const { data } = await this.httpClient.get(this.ROUTE);
17
+ return data;
18
+ }
19
+ /**
20
+ * Creates a new integration-connection.
21
+ *
22
+ * @param input The input object to create the integration-connection.
23
+ * @param input.integrationKey The identifier of the third-party platform to
24
+ * integrate (e.g., "quickbooks-desktop").
25
+ * @param input.endUserSourceId Your end-user's unique ID in your product's
26
+ * database. Must be distinct from your other connections for the same
27
+ * integration.
28
+ * @param input.endUserEmail Your end-user's email address for identification
29
+ * only. No emails will be sent.
30
+ * @param input.endUserCompanyName Your end-user's company name that will be
31
+ * shown elsewhere in Conductor.
32
+ * @returns The newly created integration-connection.
33
+ */
34
+ async create(input) {
35
+ const { data } = await this.httpClient.post(this.ROUTE, input);
36
+ return data;
37
+ }
38
+ /**
39
+ * Retrieves the specified integration-connection.
40
+ *
41
+ * @param id The integration-connection ID.
42
+ * @returns The integration-connection.
43
+ */
44
+ async retrieve(id) {
45
+ const { data } = await this.httpClient.get(`${this.ROUTE}/${id}`);
46
+ return data;
47
+ }
48
+ /**
49
+ * Checks whether the specified integration-connection can connect and process
50
+ * requests end-to-end.
51
+ *
52
+ * If the connection fails, the error we encountered will be thrown as a
53
+ * `ConductorError` (like any request). This information is useful for showing
54
+ * a "connection status" indicator in your app. If an error occurs, we
55
+ * recommend displaying the property `error.endUserMessage` to your end-user
56
+ * in your app's UI.
57
+ *
58
+ * @param id The integration-connection ID.
59
+ * @returns The ping result with the duration in milliseconds.
60
+ */
61
+ async ping(id) {
62
+ const { data } = await this.httpClient.get(`${this.ROUTE}/${id}/ping`);
63
+ return data;
64
+ }
65
+ }
66
+ exports.default = IntegrationConnectionsResource;
@@ -0,0 +1 @@
1
+ export declare function checkForUpdates(): void;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getServerUrlForEnvironment = exports.checkForUpdates = void 0;
6
+ exports.checkForUpdates = void 0;
7
7
  const package_json_1 = __importDefault(require("../../package.json"));
8
8
  const node_child_process_1 = require("node:child_process");
9
9
  function checkForUpdates() {
@@ -16,10 +16,3 @@ function checkForUpdates() {
16
16
  }
17
17
  }
18
18
  exports.checkForUpdates = checkForUpdates;
19
- function getServerUrlForEnvironment(environment) {
20
- if (environment === "production") {
21
- return "https://api.conductor.is";
22
- }
23
- return "http://localhost:4000";
24
- }
25
- exports.getServerUrlForEnvironment = getServerUrlForEnvironment;
@@ -2,23 +2,30 @@ export declare const DEFAULT_END_USER_MESSAGE = "An internal server error occurr
2
2
  export interface ConductorErrorOptions {
3
3
  readonly type: string;
4
4
  readonly code: string;
5
+ readonly httpStatusCode?: number | undefined;
5
6
  readonly message: string;
6
7
  readonly endUserMessage?: string;
7
- readonly integrationCode?: string;
8
- readonly httpStatusCode?: number;
8
+ readonly integrationCode?: string | undefined;
9
9
  }
10
10
  /**
11
- * The raw GraphQL error that Conductor's API returns.
11
+ * The raw REST error response that Conductor's API returns.
12
12
  */
13
- export interface ConductorGraphqlError {
14
- readonly message: string;
15
- readonly extensions: Omit<ConductorErrorOptions, "httpStatusCode" | "message">;
13
+ export interface ConductorServerError {
14
+ readonly error: {
15
+ readonly type: string;
16
+ readonly code: string;
17
+ readonly httpStatusCode: number;
18
+ readonly message: string;
19
+ readonly endUserMessage: string;
20
+ readonly integrationCode?: string;
21
+ };
16
22
  }
23
+ export declare function isWellFormedConductorServerError(error: unknown): error is ConductorServerError;
17
24
  /**
18
25
  * The base error from which all other more specific Conductor errors derive.
19
26
  * Specifically for errors that Conductor's API returned.
20
27
  */
21
- export declare class ConductorError extends Error {
28
+ export declare abstract class ConductorError extends Error {
22
29
  /**
23
30
  * Categorizes the error.
24
31
  *
@@ -28,12 +35,17 @@ export declare class ConductorError extends Error {
28
35
  readonly type: string;
29
36
  /**
30
37
  * The unique error code from Conductor, which is useful for adding special
31
- * handling for specific errors. E.g., `"INTEGRATION_CONNECTION_MISSING"`,
38
+ * handling for specific errors. E.g., `"RESOURCE_MISSING"`,
32
39
  * `"API_KEY_INVALID"`, or `"QBD_REQUEST_ERROR"`.
33
40
  *
34
41
  * In contrast, `type` is more general and categorizes the error.
35
42
  */
36
43
  readonly code: string;
44
+ /**
45
+ * The HTTP status code of the response that included the error. You probably
46
+ * won't need this.
47
+ */
48
+ readonly httpStatusCode: number | undefined;
37
49
  /**
38
50
  * The developer-friendly error message for your logs.
39
51
  */
@@ -63,16 +75,11 @@ export declare class ConductorError extends Error {
63
75
  * should not rely on this code to be the same across integrations.
64
76
  */
65
77
  readonly integrationCode: string | undefined;
66
- /**
67
- * The HTTP status code of the response that included the error. You probably
68
- * won't need this.
69
- */
70
- readonly httpStatusCode: number | undefined;
71
78
  /**
72
79
  * The internal representation of `type` for debugging.
73
80
  */
74
81
  protected readonly rawType: string;
75
- protected constructor(options: ConductorErrorOptions);
82
+ constructor(options: ConductorErrorOptions);
76
83
  }
77
84
  type ConductorErrorOptionsWithoutType = Omit<ConductorErrorOptions, "type">;
78
85
  /**
@@ -1,9 +1,19 @@
1
1
  "use strict";
2
2
  /* eslint-disable max-classes-per-file -- Use one module for all error classes. */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.generateConductorErrorFromType = exports.ConductorUnknownError = exports.ConductorInternalError = exports.ConductorConnectionError = exports.ConductorAuthenticationError = exports.ConductorInvalidRequestError = exports.ConductorIntegrationConnectionError = exports.ConductorIntegrationError = exports.ConductorError = exports.DEFAULT_END_USER_MESSAGE = void 0;
4
+ exports.generateConductorErrorFromType = exports.ConductorUnknownError = exports.ConductorInternalError = exports.ConductorConnectionError = exports.ConductorAuthenticationError = exports.ConductorInvalidRequestError = exports.ConductorIntegrationConnectionError = exports.ConductorIntegrationError = exports.ConductorError = exports.isWellFormedConductorServerError = exports.DEFAULT_END_USER_MESSAGE = void 0;
5
5
  // Matches server-side value.
6
6
  exports.DEFAULT_END_USER_MESSAGE = "An internal server error occurred. Please try again later.";
7
+ function isWellFormedConductorServerError(error) {
8
+ return (error instanceof Object &&
9
+ typeof error.error === "object" &&
10
+ typeof error.error.type === "string" &&
11
+ typeof error.error.code === "string" &&
12
+ typeof error.error.httpStatusCode === "number" &&
13
+ typeof error.error.message === "string" &&
14
+ typeof error.error.endUserMessage === "string");
15
+ }
16
+ exports.isWellFormedConductorServerError = isWellFormedConductorServerError;
7
17
  /**
8
18
  * The base error from which all other more specific Conductor errors derive.
9
19
  * Specifically for errors that Conductor's API returned.
@@ -18,12 +28,17 @@ class ConductorError extends Error {
18
28
  type;
19
29
  /**
20
30
  * The unique error code from Conductor, which is useful for adding special
21
- * handling for specific errors. E.g., `"INTEGRATION_CONNECTION_MISSING"`,
31
+ * handling for specific errors. E.g., `"RESOURCE_MISSING"`,
22
32
  * `"API_KEY_INVALID"`, or `"QBD_REQUEST_ERROR"`.
23
33
  *
24
34
  * In contrast, `type` is more general and categorizes the error.
25
35
  */
26
36
  code;
37
+ /**
38
+ * The HTTP status code of the response that included the error. You probably
39
+ * won't need this.
40
+ */
41
+ httpStatusCode;
27
42
  /**
28
43
  * The developer-friendly error message for your logs.
29
44
  */
@@ -53,11 +68,6 @@ class ConductorError extends Error {
53
68
  * should not rely on this code to be the same across integrations.
54
69
  */
55
70
  integrationCode;
56
- /**
57
- * The HTTP status code of the response that included the error. You probably
58
- * won't need this.
59
- */
60
- httpStatusCode;
61
71
  /**
62
72
  * The internal representation of `type` for debugging.
63
73
  */
@@ -78,10 +88,10 @@ class ConductorError extends Error {
78
88
  this.type = this.constructor.name;
79
89
  this.rawType = options.type;
80
90
  this.code = options.code;
91
+ this.httpStatusCode = options.httpStatusCode;
81
92
  this.message = options.message;
82
93
  this.endUserMessage = options.endUserMessage ?? exports.DEFAULT_END_USER_MESSAGE;
83
94
  this.integrationCode = options.integrationCode;
84
- this.httpStatusCode = options.httpStatusCode;
85
95
  }
86
96
  }
87
97
  exports.ConductorError = ConductorError;
@@ -1,2 +1 @@
1
- export declare function checkForUpdates(): void;
2
1
  export declare function getServerUrlForEnvironment(environment: "development" | "production" | "test"): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServerUrlForEnvironment = void 0;
4
+ function getServerUrlForEnvironment(environment) {
5
+ if (environment === "production") {
6
+ return "https://api.conductor.is";
7
+ }
8
+ return "http://localhost:4000";
9
+ }
10
+ exports.getServerUrlForEnvironment = getServerUrlForEnvironment;
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "conductor-node",
3
- "version": "9.8.1",
4
- "description": "Easily integrate with the entire QuickBooks Desktop API with fully-typed async TypeScript",
5
- "author": "Danny Nemer <hi@DannyNemer.com>",
3
+ "version": "10.0.0",
4
+ "description": "Easily integrate the entire QuickBooks Desktop API using fully-typed async TypeScript",
6
5
  "license": "MIT",
7
6
  "type": "commonjs",
8
7
  "main": "dist/src/index.js",
@@ -13,10 +12,9 @@
13
12
  ],
14
13
  "scripts": {
15
14
  "prepack": "yarn --silent tsc && yarn --silent delete-compiled-dev-files && yarn --silent tsc-alias",
16
- "delete-compiled-dev-files": "rm -rf `find ./dist -type d -name __tests__` ./dist/src/utils/testing.* ./dist/src/graphql/codegenConfig.*",
15
+ "delete-compiled-dev-files": "rm -rf `find ./dist -type d -name __tests__` ./dist/src/utils/test/*",
17
16
  "postpack": "rm -rf dist",
18
17
  "clean": "rm -rf dist package conductor-node-*.tgz tsconfig.tsbuildinfo",
19
- "gen:graphql": "yarn graphql-codegen --config=./src/graphql/codegenConfig.ts",
20
18
  "diff": "yarn pack && npm diff --diff=conductor-node@latest --diff=conductor-node-v$(node -p \"require('./package.json').version\").tgz && yarn clean",
21
19
  "prepublishOnly": "yarn test",
22
20
  "test": "yarn --cwd=../../ test ./packages/client",
@@ -26,25 +24,17 @@
26
24
  "node": ">=16"
27
25
  },
28
26
  "dependencies": {
29
- "graphql": "^16.6.0",
30
- "graphql-request": "~5.1.0"
27
+ "axios": "^1.4.0"
31
28
  },
32
29
  "devDependencies": {
33
- "@graphql-codegen/add": "^4.0.1",
34
- "@graphql-codegen/cli": "^3.2.1",
35
- "@graphql-codegen/typescript-graphql-request": "^4.5.8",
36
- "@graphql-codegen/typescript-operations": "^3.0.1",
30
+ "axios-mock-adapter": "^1.21.4",
37
31
  "tsc-alias": "^1.7.0"
38
32
  },
39
33
  "keywords": [
40
- "accounting",
41
- "api",
42
34
  "conductor",
43
35
  "qbd",
44
36
  "qbwc",
45
37
  "qbxml",
46
- "quickbooks desktop",
47
- "sdk",
48
- "typescript"
38
+ "quickbooks desktop"
49
39
  ]
50
40
  }
@@ -1,114 +0,0 @@
1
- import type { GraphQLClient } from "graphql-request";
2
- import type * as Dom from "graphql-request/dist/types.dom";
3
- export type Maybe<T> = T | null;
4
- export type InputMaybe<T> = Maybe<T>;
5
- export type Exact<T extends {
6
- [key: string]: unknown;
7
- }> = {
8
- [K in keyof T]: T[K];
9
- };
10
- export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
11
- [SubKey in K]?: Maybe<T[SubKey]>;
12
- };
13
- export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
14
- [SubKey in K]: Maybe<T[SubKey]>;
15
- };
16
- /** All built-in and custom scalars, mapped to their actual values */
17
- export type Scalars = {
18
- ID: string;
19
- String: string;
20
- Boolean: boolean;
21
- Int: number;
22
- Float: number;
23
- DateTime: Date;
24
- JSONObject: object;
25
- };
26
- export type GraphqlCreateIntegrationConnectionInput = {
27
- endUserCompanyName: Scalars["String"];
28
- endUserEmail: Scalars["String"];
29
- endUserSourceId: Scalars["String"];
30
- integrationKey: Scalars["String"];
31
- };
32
- export type GraphqlPingIntegrationConnectionInput = {
33
- integrationConnectionId: Scalars["ID"];
34
- };
35
- export type GraphqlSendIntegrationRequestInput = {
36
- integrationConnectionId: Scalars["ID"];
37
- requestObject: Scalars["JSONObject"];
38
- };
39
- export type GraphqlIntegrationConnectionFragment = {
40
- id: string;
41
- integrationKey: string;
42
- endUserSourceId: string;
43
- endUserEmail: string;
44
- endUserCompanyName: string;
45
- };
46
- export type GraphqlGetIntegrationConnectionQueryVariables = Exact<{
47
- integrationConnectionId: Scalars["ID"];
48
- }>;
49
- export type GraphqlGetIntegrationConnectionQuery = {
50
- integrationConnection: {
51
- id: string;
52
- integrationKey: string;
53
- endUserSourceId: string;
54
- endUserEmail: string;
55
- endUserCompanyName: string;
56
- };
57
- };
58
- export type GraphqlGetIntegrationConnectionsQueryVariables = Exact<{
59
- [key: string]: never;
60
- }>;
61
- export type GraphqlGetIntegrationConnectionsQuery = {
62
- integrationConnections: Array<{
63
- id: string;
64
- integrationKey: string;
65
- endUserSourceId: string;
66
- endUserEmail: string;
67
- endUserCompanyName: string;
68
- }>;
69
- };
70
- export type GraphqlCreateIntegrationConnectionMutationVariables = Exact<{
71
- input: GraphqlCreateIntegrationConnectionInput;
72
- }>;
73
- export type GraphqlCreateIntegrationConnectionMutation = {
74
- createIntegrationConnection: {
75
- integrationConnection: {
76
- id: string;
77
- integrationKey: string;
78
- endUserSourceId: string;
79
- endUserEmail: string;
80
- endUserCompanyName: string;
81
- };
82
- };
83
- };
84
- export type GraphqlPingIntegrationConnectionMutationVariables = Exact<{
85
- input: GraphqlPingIntegrationConnectionInput;
86
- }>;
87
- export type GraphqlPingIntegrationConnectionMutation = {
88
- pingIntegrationConnection: {
89
- duration: number;
90
- };
91
- };
92
- export type GraphqlSendIntegrationRequestMutationVariables = Exact<{
93
- input: GraphqlSendIntegrationRequestInput;
94
- }>;
95
- export type GraphqlSendIntegrationRequestMutation = {
96
- sendIntegrationRequest: {
97
- response: object;
98
- };
99
- };
100
- export declare const IntegrationConnectionFragmentDoc = "\n fragment IntegrationConnection on IntegrationConnection {\n id\n integrationKey\n endUserSourceId\n endUserEmail\n endUserCompanyName\n}\n ";
101
- export declare const GetIntegrationConnectionDocument: string;
102
- export declare const GetIntegrationConnectionsDocument: string;
103
- export declare const CreateIntegrationConnectionDocument: string;
104
- export declare const PingIntegrationConnectionDocument = "\n mutation pingIntegrationConnection($input: PingIntegrationConnectionInput!) {\n pingIntegrationConnection(input: $input) {\n duration\n }\n}\n ";
105
- export declare const SendIntegrationRequestDocument = "\n mutation sendIntegrationRequest($input: SendIntegrationRequestInput!) {\n sendIntegrationRequest(input: $input) {\n response\n }\n}\n ";
106
- export type SdkFunctionWrapper = <T>(action: (requestHeaders?: Record<string, string>) => Promise<T>, operationName: string, operationType?: string) => Promise<T>;
107
- export declare function getSdk(client: GraphQLClient, withWrapper?: SdkFunctionWrapper): {
108
- getIntegrationConnection(variables: GraphqlGetIntegrationConnectionQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<GraphqlGetIntegrationConnectionQuery>;
109
- getIntegrationConnections(variables?: GraphqlGetIntegrationConnectionsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<GraphqlGetIntegrationConnectionsQuery>;
110
- createIntegrationConnection(variables: GraphqlCreateIntegrationConnectionMutationVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<GraphqlCreateIntegrationConnectionMutation>;
111
- pingIntegrationConnection(variables: GraphqlPingIntegrationConnectionMutationVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<GraphqlPingIntegrationConnectionMutation>;
112
- sendIntegrationRequest(variables: GraphqlSendIntegrationRequestMutationVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<GraphqlSendIntegrationRequestMutation>;
113
- };
114
- export type Sdk = ReturnType<typeof getSdk>;
@@ -1,70 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSdk = exports.SendIntegrationRequestDocument = exports.PingIntegrationConnectionDocument = exports.CreateIntegrationConnectionDocument = exports.GetIntegrationConnectionsDocument = exports.GetIntegrationConnectionDocument = exports.IntegrationConnectionFragmentDoc = void 0;
4
- exports.IntegrationConnectionFragmentDoc = `
5
- fragment IntegrationConnection on IntegrationConnection {
6
- id
7
- integrationKey
8
- endUserSourceId
9
- endUserEmail
10
- endUserCompanyName
11
- }
12
- `;
13
- exports.GetIntegrationConnectionDocument = `
14
- query getIntegrationConnection($integrationConnectionId: ID!) {
15
- integrationConnection(id: $integrationConnectionId) {
16
- ...IntegrationConnection
17
- }
18
- }
19
- ${exports.IntegrationConnectionFragmentDoc}`;
20
- exports.GetIntegrationConnectionsDocument = `
21
- query getIntegrationConnections {
22
- integrationConnections {
23
- ...IntegrationConnection
24
- }
25
- }
26
- ${exports.IntegrationConnectionFragmentDoc}`;
27
- exports.CreateIntegrationConnectionDocument = `
28
- mutation createIntegrationConnection($input: CreateIntegrationConnectionInput!) {
29
- createIntegrationConnection(input: $input) {
30
- integrationConnection {
31
- ...IntegrationConnection
32
- }
33
- }
34
- }
35
- ${exports.IntegrationConnectionFragmentDoc}`;
36
- exports.PingIntegrationConnectionDocument = `
37
- mutation pingIntegrationConnection($input: PingIntegrationConnectionInput!) {
38
- pingIntegrationConnection(input: $input) {
39
- duration
40
- }
41
- }
42
- `;
43
- exports.SendIntegrationRequestDocument = `
44
- mutation sendIntegrationRequest($input: SendIntegrationRequestInput!) {
45
- sendIntegrationRequest(input: $input) {
46
- response
47
- }
48
- }
49
- `;
50
- const defaultWrapper = (action, _operationName, _operationType) => action();
51
- function getSdk(client, withWrapper = defaultWrapper) {
52
- return {
53
- getIntegrationConnection(variables, requestHeaders) {
54
- return withWrapper((wrappedRequestHeaders) => client.request(exports.GetIntegrationConnectionDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getIntegrationConnection", "query");
55
- },
56
- getIntegrationConnections(variables, requestHeaders) {
57
- return withWrapper((wrappedRequestHeaders) => client.request(exports.GetIntegrationConnectionsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getIntegrationConnections", "query");
58
- },
59
- createIntegrationConnection(variables, requestHeaders) {
60
- return withWrapper((wrappedRequestHeaders) => client.request(exports.CreateIntegrationConnectionDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "createIntegrationConnection", "mutation");
61
- },
62
- pingIntegrationConnection(variables, requestHeaders) {
63
- return withWrapper((wrappedRequestHeaders) => client.request(exports.PingIntegrationConnectionDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "pingIntegrationConnection", "mutation");
64
- },
65
- sendIntegrationRequest(variables, requestHeaders) {
66
- return withWrapper((wrappedRequestHeaders) => client.request(exports.SendIntegrationRequestDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "sendIntegrationRequest", "mutation");
67
- },
68
- };
69
- }
70
- exports.getSdk = getSdk;
@@ -1,8 +0,0 @@
1
- import type { getSdk } from "../graphql/__generated__/operationTypes";
2
- import type { ConductorError } from "../utils/error";
3
- export declare function wrapGraphqlOperations<T extends ReturnType<typeof getSdk>>(graphqlOperations: T, verbose: boolean): T;
4
- export declare function graphqlOperationWrapper<V extends {
5
- [key: string]: unknown;
6
- }, R>(operationName: string, variables: V | undefined, operation: (variables: V | undefined) => Promise<R>, verbose: boolean): Promise<R>;
7
- export declare function getDurationString(startTime: number): string;
8
- export declare function wrapError(error: Error): ConductorError;
@@ -1,108 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.wrapError = exports.getDurationString = exports.graphqlOperationWrapper = exports.wrapGraphqlOperations = void 0;
7
- const error_1 = require("../utils/error");
8
- const graphql_request_1 = require("graphql-request");
9
- const node_util_1 = __importDefault(require("node:util"));
10
- function wrapGraphqlOperations(graphqlOperations, verbose) {
11
- return Object.fromEntries(Object.entries(graphqlOperations).map(([operationName, operation]) => [
12
- operationName,
13
- async (variables) => graphqlOperationWrapper(operationName,
14
- // @ts-expect-error -- It is safe to call `operation` with `variables`.
15
- variables, operation, verbose),
16
- ]));
17
- }
18
- exports.wrapGraphqlOperations = wrapGraphqlOperations;
19
- async function graphqlOperationWrapper(operationName, variables, operation, verbose) {
20
- const graphqlInfo = {
21
- operationName,
22
- input: variables
23
- ? Object.keys(variables).length === 1 && "input" in variables
24
- ? variables["input"] // Flatten the input if it only has one key called "input".
25
- : variables
26
- : {},
27
- };
28
- if (verbose) {
29
- console.log(`Conductor request start: ${node_util_1.default.inspect(graphqlInfo, {
30
- depth: undefined,
31
- })}`);
32
- }
33
- const startTime = Date.now();
34
- try {
35
- const result = await operation(variables);
36
- if (verbose) {
37
- const responseLog = {
38
- duration: getDurationString(startTime),
39
- ...graphqlInfo,
40
- };
41
- const responseString = node_util_1.default.inspect(responseLog, { depth: undefined });
42
- console.log(`Conductor request complete: ${responseString}`);
43
- }
44
- return result;
45
- }
46
- catch (error) {
47
- const conductorError = wrapError(error);
48
- if (verbose) {
49
- const errorLog = {
50
- duration: getDurationString(startTime),
51
- error: String(conductorError),
52
- ...graphqlInfo,
53
- };
54
- const errorString = node_util_1.default.inspect(errorLog, { depth: undefined });
55
- console.log(`Conductor error: ${errorString}`);
56
- }
57
- throw conductorError;
58
- }
59
- }
60
- exports.graphqlOperationWrapper = graphqlOperationWrapper;
61
- function getDurationString(startTime) {
62
- const duration = Date.now() - startTime;
63
- return `${Math.round(duration / 10) / 100}s`;
64
- }
65
- exports.getDurationString = getDurationString;
66
- function wrapError(error) {
67
- if (error instanceof graphql_request_1.ClientError) {
68
- const { response } = error;
69
- if ([404, 502, 503].includes(response.status)) {
70
- return createConnectionError(String(response.status), response.status);
71
- }
72
- const nestedError = response.errors?.[0];
73
- const errorExtensions = nestedError?.extensions;
74
- if (errorExtensions) {
75
- // Do *not* bother validating if this error is a Conductor error:
76
- // 1. We know this is a `ClientError`, so `message` and `httpStatusCode`
77
- // exist.
78
- // 2. We know this is a GraphQL error, so `code` likely exists either from
79
- // Conductor or Apollo.
80
- // 3. If `type` is absent, then `generateConductorErrorFromType` will
81
- // default to `ConductorUnknownError`.
82
- // 4. If `endUserMessage` is absent, then `ConductorError` will use a
83
- // default value.
84
- return (0, error_1.generateConductorErrorFromType)({
85
- message: nestedError.message,
86
- httpStatusCode: response.status,
87
- ...errorExtensions,
88
- });
89
- }
90
- // Ideally, we would check for instances of `FetchError` but we don't have
91
- // that type available.
92
- }
93
- else if (error.name === "FetchError") {
94
- return createConnectionError(error.message, 502);
95
- }
96
- return new error_1.ConductorInternalError({
97
- code: "INVALID_JSON_RESPONSE",
98
- message: "Invalid JSON received from the Conductor API.",
99
- });
100
- }
101
- exports.wrapError = wrapError;
102
- function createConnectionError(originalMessage, httpStatusCode) {
103
- return new error_1.ConductorConnectionError({
104
- code: "SERVER_UNAVAILABLE",
105
- message: `Conductor failed to connect to the server: ${originalMessage}. Please alert the Conductor team if this error persists.`,
106
- httpStatusCode,
107
- });
108
- }