conductor-node 8.6.1 → 8.6.3

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
@@ -48,7 +48,7 @@ const newAccount = await conductor.qbd.account.add(qbdConnections[0].id, {
48
48
 
49
49
  ### `createIntegrationConnection(input: CreateIntegrationConnectionInput)`
50
50
 
51
- Create a new integration-connection.
51
+ Creates a new integration-connection.
52
52
 
53
53
  ```ts
54
54
  const newQbdConnection = await conductor.createIntegrationConnection({
@@ -82,7 +82,7 @@ The response looks like the following:
82
82
 
83
83
  ### `qbd.*`
84
84
 
85
- Execute 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 full list of available APIs.
85
+ 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.
86
86
 
87
87
  ```ts
88
88
  const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
@@ -94,7 +94,7 @@ const newAccount = await conductor.qbd.account.add(qbdConnectionId, {
94
94
 
95
95
  ### `getIntegrationConnections()`
96
96
 
97
- Fetch all authorized integration-connections.
97
+ Fetches all authorized integration-connections.
98
98
 
99
99
  ```ts
100
100
  const qbdConnections = await conductor.getIntegrationConnections();
@@ -102,7 +102,7 @@ const qbdConnections = await conductor.getIntegrationConnections();
102
102
 
103
103
  ### `getIntegrationConnectionById(id: string)`
104
104
 
105
- Fetch a single integration-connection by id.
105
+ Fetches a single integration-connection by id.
106
106
 
107
107
  ```ts
108
108
  const qbdConnection = await conductor.getIntegrationConnectionById(
@@ -112,9 +112,9 @@ const qbdConnection = await conductor.getIntegrationConnectionById(
112
112
 
113
113
  ### `pingIntegrationConnection(id: string)`
114
114
 
115
- Check whether the specified integration-connection can connect and process requests end-to-end.
115
+ Checks whether the specified integration-connection can connect and process requests end-to-end.
116
116
 
117
- 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.
117
+ 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.
118
118
 
119
119
  In the form of a rejected promise:
120
120
 
@@ -142,7 +142,7 @@ try {
142
142
 
143
143
  ## TypeScript
144
144
 
145
- Access the full QuickBooks Desktop API through TypeScript. The `qbd.*` APIs are fully typed with inline documentation and will autocomplete in your editor.
145
+ Access the entire QuickBooks Desktop API through TypeScript. The `qbd.*` APIs are fully typed with inline documentation and will autocomplete in your editor.
146
146
 
147
147
  To manually access the QBD types, import them from `conductor-node` like so:
148
148
 
@@ -158,7 +158,7 @@ const accountAddInput: QbdTypes.AccountAdd = {
158
158
 
159
159
  ## Error Handling
160
160
 
161
- The `ConductorError` and its subclasses have the following properties:
161
+ Any error thrown by the Conductor API will be an instance of `ConductorError` or one of its subclasses, which all have the following properties:
162
162
 
163
163
  ```ts
164
164
  {
@@ -171,12 +171,12 @@ The `ConductorError` and its subclasses have the following properties:
171
171
  message: string;
172
172
  // The end-user-friendly error message to display in your app.
173
173
  endUserMessage: string;
174
- // The HTTP status code of the response that included the error.
175
- httpStatusCode: number | undefined;
176
174
  // The error code provided by the third-party integration when `type`
177
175
  // is `ConductorIntegrationError`. This is useful for adding special
178
176
  // handling for specific errors from the third-party integration.
179
177
  integrationCode: string | undefined;
178
+ // The HTTP status code of the response that included the error.
179
+ httpStatusCode: number | undefined;
180
180
  }
181
181
  ```
182
182
 
@@ -192,7 +192,9 @@ The error object you receive will have one of the following error types:
192
192
  | `ConductorConnectionError` | There was a network problem between the client (on your server) and Conductor's servers. |
193
193
  | `ConductorInternalError` | Something went wrong on Conductor's end. (These are rare.) |
194
194
 
195
- ### Example
195
+ ### Special Handling
196
+
197
+ If you need special handling for specific errors, you can wrap individual API calls, as shown below.
196
198
 
197
199
  In the form of a rejected promise:
198
200
 
@@ -208,7 +210,7 @@ conductor.qbd.account
208
210
  })
209
211
  .catch((error) => {
210
212
  if (error instanceof ConductorError) {
211
- // Update your app's UI to display `error.endUserMessage`.
213
+ // Check `error.code`, `error.integrationCode`, etc., for special handling.
212
214
  } else {
213
215
  // ...
214
216
  }
@@ -226,27 +228,28 @@ try {
226
228
  });
227
229
  } catch (error) {
228
230
  if (error instanceof ConductorError) {
229
- // Update your app's UI to display `error.endUserMessage`.
231
+ // Check `error.code`, `error.integrationCode`, etc., for special handling.
230
232
  } else {
231
233
  // ...
232
234
  }
233
235
  }
234
236
  ```
235
237
 
236
- ### Integration
237
-
238
- **NOTE:** We do not expect you to individually wrap every API call like the examples above. Instead, you should only need to wrap a specific Conductor API request when adding special handling for specific errors, such as checking the property `error.code`.
238
+ ### Global Error Handling
239
239
 
240
- Ideally, if your server does not already, we expect you to have a single global error handler, such as [`app.use((error, req, res, next) => { ... })` 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). In such a handler, you can do the following:
240
+ We do _not_ expect you to individually wrap every API call like the examples above. Instead, we recommend your server use a single global error handler, 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), where you do the following:
241
241
 
242
- 1. Ensure your app's UI shows your end-user the property `error.endUserMessage` of any `ConductorError` instance for any Conductor request while you log the rest.
243
- 2. Send the full error object to your error-tracking service (e.g., Sentry) for all `ConductorError` instances, for which we recommend:
244
- 1. Send a **warning** to your error-tracking service for instances of `ConductorIntegrationError`, which are your end-user's fault; e.g., cannot connect to QBD on your end-user's computer.
245
- 2. Send an **error** for all other `ConductorError` instances; e.g., invalid API key.
242
+ 1. Ensure your app's UI shows your end-user the property `error.endUserMessage` for any `ConductorError` instance for any Conductor request while you log the rest of the error object.
243
+ 2. Send the entire error object to your error-tracking service (e.g., Sentry) for all `ConductorError` instances:
244
+ - Send a **warning** for instances of `ConductorIntegrationError`, which are your end-user's fault; e.g., cannot connect to QBD on your end-user's computer.
245
+ - Send an **error** for all other `ConductorError` instances; e.g., invalid API key.
246
246
 
247
- For example, here is how you might do this in Express:
247
+ For example, using an Express error handler:
248
248
 
249
249
  ```ts
250
+ import * as Sentry from "@sentry/node";
251
+ import { ConductorError, ConductorIntegrationError } from "conductor-node";
252
+ // ...
250
253
  app.use((error, req, res, next) => {
251
254
  if (error instanceof ConductorError) {
252
255
  Sentry.captureException(error, {
@@ -260,14 +263,16 @@ app.use((error, req, res, next) => {
260
263
  });
261
264
  ```
262
265
 
263
- And here is how you might do this in Apollo Server:
266
+ Or using Apollo Server's error handler:
264
267
 
265
268
  ```ts
269
+ import { ApolloServer } from "@apollo/server";
266
270
  import { unwrapResolverError } from "@apollo/server/errors";
267
-
271
+ import * as Sentry from "@sentry/node";
272
+ import { ConductorError, ConductorIntegrationError } from "conductor-node";
273
+ // ...
268
274
  const server = new ApolloServer({
269
- typeDefs,
270
- resolvers,
275
+ // ...
271
276
  formatError: (formattedError, error) => {
272
277
  const origError = unwrapResolverError(error);
273
278
  if (origError instanceof ConductorError) {
@@ -275,17 +280,14 @@ const server = new ApolloServer({
275
280
  level:
276
281
  origError instanceof ConductorIntegrationError ? "warning" : "error",
277
282
  });
278
- // Return a different error message for your end-user to see in your app's UI.
279
283
  return {
280
284
  ...formattedError,
285
+ // Return a different error message for your end-user to see in
286
+ // your app's UI.
281
287
  message: origError.endUserMessage,
282
288
  };
283
- } else {
284
- // ...
285
289
  }
286
-
287
- // Otherwise return the formatted error. This error can also
288
- // be manipulated in other ways, as long as it's returned.
290
+ // ...
289
291
  return formattedError;
290
292
  },
291
293
  });
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-node",
3
- "version": "8.6.1",
3
+ "version": "8.6.3",
4
4
  "description": "Easily integrate with the entire QuickBooks Desktop API with fully-typed async TypeScript",
5
5
  "author": "Danny Nemer <hi@DannyNemer.com>",
6
6
  "license": "MIT",
@@ -2,7 +2,7 @@ import type { GraphqlCreateIntegrationConnectionInput, GraphqlCreateIntegrationC
2
2
  import QbdIntegration from "./integrations/qbd/QbdIntegration";
3
3
  import { getServerUrlForEnvironment } from "./utils";
4
4
  export interface ClientOptions {
5
- /** Log each request and response. */
5
+ /** Logs each request and response. */
6
6
  readonly verbose?: boolean;
7
7
  readonly serverEnvironment?: Parameters<typeof getServerUrlForEnvironment>[0];
8
8
  }
@@ -13,20 +13,20 @@ export default class Client {
13
13
  private readonly graphqlOperations;
14
14
  constructor(apiKey: string, { verbose, serverEnvironment }?: ClientOptions);
15
15
  /**
16
- * Fetch the specified integration-connection.
16
+ * Fetches the specified integration-connection.
17
17
  *
18
18
  * @param integrationConnectionId The integration-connection ID.
19
19
  * @returns The integration-connection.
20
20
  */
21
21
  getIntegrationConnection(integrationConnectionId: GraphqlGetIntegrationConnectionQueryVariables["integrationConnectionId"]): Promise<GraphqlGetIntegrationConnectionQuery["integrationConnection"]>;
22
22
  /**
23
- * Fetch all integration-connections associated with your Conductor account.
23
+ * Fetches all integration-connections associated with your Conductor account.
24
24
  *
25
25
  * @returns The integration-connections.
26
26
  */
27
27
  getIntegrationConnections(): Promise<GraphqlGetIntegrationConnectionsQuery["integrationConnections"]>;
28
28
  /**
29
- * Check whether we can successfully connect to the end-user's QBD instance.
29
+ * Checks whether we can successfully connect to the end-user's QBD instance.
30
30
  *
31
31
  * Unlike `lastHeartbeatAt`, which only checks if QBWC is running (i.e., is
32
32
  * the user's computer on), this check fails if the user's computer is on but
@@ -35,8 +35,8 @@ export default class Client {
35
35
  *
36
36
  * @param integrationConnectionId The ID of the integration-connection.
37
37
  * @returns The result object with the following properties:
38
- * - isConnected - Whether we can connect to the end-user's QBD.
39
- * - error - If `isConnected=false`, this will be an object with the following
38
+ * - isConnected: Whether we can connect to the end-user's QBD.
39
+ * - error: If `isConnected=false`, this will be an object with the following
40
40
  * properties:
41
41
  * - error.code - The unique error code.
42
42
  * - error.developerMessage - The technical error message for the developer.
@@ -45,7 +45,7 @@ export default class Client {
45
45
  */
46
46
  getConnectionStatus(integrationConnectionId: GraphqlGetConnectionStatusQueryVariables["integrationConnectionId"]): Promise<GraphqlGetConnectionStatusQuery["integrationConnection"]["connectionStatus"]>;
47
47
  /**
48
- * Create a new integration-connection.
48
+ * Creates a new integration-connection.
49
49
  *
50
50
  * @param input - The input object to create the integration-connection.
51
51
  * @param input.integrationKey The identifier of the third-party platform to
@@ -63,12 +63,13 @@ export default class Client {
63
63
  integrationKey: "quickbooks-desktop";
64
64
  }): Promise<GraphqlCreateIntegrationConnectionMutation["createIntegrationConnection"]["integrationConnection"]>;
65
65
  /**
66
- * Check whether the specified integration-connection can connect and process
66
+ * Checks whether the specified integration-connection can connect and process
67
67
  * requests end-to-end.
68
68
  *
69
69
  * If the connection fails, the error we encountered will be thrown as a
70
70
  * `ConductorError`. This information is useful for showing a "connection
71
- * status" indicator in your app.
71
+ * status" indicator in your app. If an error occurs, we recommend displaying
72
+ * the property `error.endUserMessage` to your end-user in your app's UI.
72
73
  */
73
74
  pingIntegrationConnection(integrationConnectionId: GraphqlPingIntegrationConnectionMutationVariables["input"]["integrationConnectionId"]): Promise<GraphqlPingIntegrationConnectionMutation["pingIntegrationConnection"]>;
74
75
  private createHeaders;
@@ -21,7 +21,7 @@ class Client {
21
21
  this.qbd = new QbdIntegration_1.default(this.graphqlOperations);
22
22
  }
23
23
  /**
24
- * Fetch the specified integration-connection.
24
+ * Fetches the specified integration-connection.
25
25
  *
26
26
  * @param integrationConnectionId The integration-connection ID.
27
27
  * @returns The integration-connection.
@@ -32,7 +32,7 @@ class Client {
32
32
  .then((result) => result.integrationConnection);
33
33
  }
34
34
  /**
35
- * Fetch all integration-connections associated with your Conductor account.
35
+ * Fetches all integration-connections associated with your Conductor account.
36
36
  *
37
37
  * @returns The integration-connections.
38
38
  */
@@ -42,7 +42,7 @@ class Client {
42
42
  .then((result) => result.integrationConnections);
43
43
  }
44
44
  /**
45
- * Check whether we can successfully connect to the end-user's QBD instance.
45
+ * Checks whether we can successfully connect to the end-user's QBD instance.
46
46
  *
47
47
  * Unlike `lastHeartbeatAt`, which only checks if QBWC is running (i.e., is
48
48
  * the user's computer on), this check fails if the user's computer is on but
@@ -51,8 +51,8 @@ class Client {
51
51
  *
52
52
  * @param integrationConnectionId The ID of the integration-connection.
53
53
  * @returns The result object with the following properties:
54
- * - isConnected - Whether we can connect to the end-user's QBD.
55
- * - error - If `isConnected=false`, this will be an object with the following
54
+ * - isConnected: Whether we can connect to the end-user's QBD.
55
+ * - error: If `isConnected=false`, this will be an object with the following
56
56
  * properties:
57
57
  * - error.code - The unique error code.
58
58
  * - error.developerMessage - The technical error message for the developer.
@@ -65,7 +65,7 @@ class Client {
65
65
  .then((result) => result.integrationConnection.connectionStatus);
66
66
  }
67
67
  /**
68
- * Create a new integration-connection.
68
+ * Creates a new integration-connection.
69
69
  *
70
70
  * @param input - The input object to create the integration-connection.
71
71
  * @param input.integrationKey The identifier of the third-party platform to
@@ -85,12 +85,13 @@ class Client {
85
85
  .then((result) => result.createIntegrationConnection.integrationConnection);
86
86
  }
87
87
  /**
88
- * Check whether the specified integration-connection can connect and process
88
+ * Checks whether the specified integration-connection can connect and process
89
89
  * requests end-to-end.
90
90
  *
91
91
  * If the connection fails, the error we encountered will be thrown as a
92
92
  * `ConductorError`. This information is useful for showing a "connection
93
- * status" indicator in your app.
93
+ * status" indicator in your app. If an error occurs, we recommend displaying
94
+ * the property `error.endUserMessage` to your end-user in your app's UI.
94
95
  */
95
96
  async pingIntegrationConnection(integrationConnectionId) {
96
97
  return this.graphqlOperations
@@ -4,8 +4,8 @@ export interface ConductorErrorOptions {
4
4
  readonly code: string;
5
5
  readonly message: string;
6
6
  readonly endUserMessage?: string;
7
- readonly httpStatusCode?: number;
8
7
  readonly integrationCode?: string;
8
+ readonly httpStatusCode?: number;
9
9
  }
10
10
  /**
11
11
  * The raw GraphQL error that Conductor's API returns.
@@ -41,10 +41,6 @@ export declare class ConductorError extends Error {
41
41
  * The end-user-friendly error message to display in your app.
42
42
  */
43
43
  readonly endUserMessage: string;
44
- /**
45
- * The HTTP status code of the response that included the error.
46
- */
47
- readonly httpStatusCode: number | undefined;
48
44
  /**
49
45
  * The error code provided by the third-party integration when `type` is
50
46
  * `ConductorIntegrationError`. This is useful for adding special handling for
@@ -54,6 +50,10 @@ export declare class ConductorError extends Error {
54
50
  * should not rely on this code to be the same across integrations.
55
51
  */
56
52
  readonly integrationCode: string | undefined;
53
+ /**
54
+ * The HTTP status code of the response that included the error.
55
+ */
56
+ readonly httpStatusCode: number | undefined;
57
57
  protected constructor(options: ConductorErrorOptions);
58
58
  }
59
59
  type ConductorErrorOptionsWithoutType = Omit<ConductorErrorOptions, "type">;
@@ -31,10 +31,6 @@ class ConductorError extends Error {
31
31
  * The end-user-friendly error message to display in your app.
32
32
  */
33
33
  endUserMessage;
34
- /**
35
- * The HTTP status code of the response that included the error.
36
- */
37
- httpStatusCode;
38
34
  /**
39
35
  * The error code provided by the third-party integration when `type` is
40
36
  * `ConductorIntegrationError`. This is useful for adding special handling for
@@ -44,6 +40,10 @@ class ConductorError extends Error {
44
40
  * should not rely on this code to be the same across integrations.
45
41
  */
46
42
  integrationCode;
43
+ /**
44
+ * The HTTP status code of the response that included the error.
45
+ */
46
+ httpStatusCode;
47
47
  constructor(options) {
48
48
  super(options.message);
49
49
  // Set `name` to the constructor name so that the error appears in logs as
@@ -59,8 +59,8 @@ class ConductorError extends Error {
59
59
  this.rawType = options.type;
60
60
  this.code = options.code;
61
61
  this.endUserMessage = options.endUserMessage ?? exports.DEFAULT_END_USER_MESSAGE;
62
- this.httpStatusCode = options.httpStatusCode;
63
62
  this.integrationCode = options.integrationCode;
63
+ this.httpStatusCode = options.httpStatusCode;
64
64
  }
65
65
  }
66
66
  exports.ConductorError = ConductorError;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-node",
3
- "version": "8.6.1",
3
+ "version": "8.6.3",
4
4
  "description": "Easily integrate with the entire QuickBooks Desktop API with fully-typed async TypeScript",
5
5
  "author": "Danny Nemer <hi@DannyNemer.com>",
6
6
  "license": "MIT",