nxus-qbd 0.7.2 → 1.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.
Files changed (231) hide show
  1. package/README.md +269 -91
  2. package/dist/client.d.ts +81 -77
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +77 -71
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts.d.ts +1 -1
  7. package/dist/contracts.d.ts.map +1 -1
  8. package/dist/generated/count-capabilities.d.ts +64 -0
  9. package/dist/generated/count-capabilities.d.ts.map +1 -0
  10. package/dist/generated/count-capabilities.js +64 -0
  11. package/dist/generated/count-capabilities.js.map +1 -0
  12. package/dist/generated/index.d.ts +1 -1
  13. package/dist/generated/index.d.ts.map +1 -1
  14. package/dist/generated/index.js +1 -1
  15. package/dist/generated/index.js.map +1 -1
  16. package/dist/generated/resource-capabilities.d.ts +506 -0
  17. package/dist/generated/resource-capabilities.d.ts.map +1 -0
  18. package/dist/generated/resource-capabilities.js +506 -0
  19. package/dist/generated/resource-capabilities.js.map +1 -0
  20. package/dist/generated/types.gen.d.ts +29531 -20897
  21. package/dist/generated/types.gen.d.ts.map +1 -1
  22. package/dist/generated/types.gen.js +80 -0
  23. package/dist/generated/types.gen.js.map +1 -1
  24. package/dist/helpers/enums.d.ts +29 -0
  25. package/dist/helpers/enums.d.ts.map +1 -0
  26. package/dist/helpers/enums.js +38 -0
  27. package/dist/helpers/enums.js.map +1 -0
  28. package/dist/helpers/errors.d.ts +14 -3
  29. package/dist/helpers/errors.d.ts.map +1 -1
  30. package/dist/helpers/errors.js +274 -23
  31. package/dist/helpers/errors.js.map +1 -1
  32. package/dist/helpers/index.d.ts +4 -2
  33. package/dist/helpers/index.d.ts.map +1 -1
  34. package/dist/helpers/index.js +4 -2
  35. package/dist/helpers/index.js.map +1 -1
  36. package/dist/helpers/pagination.d.ts +11 -1
  37. package/dist/helpers/pagination.d.ts.map +1 -1
  38. package/dist/helpers/pagination.js.map +1 -1
  39. package/dist/helpers/response.d.ts +93 -0
  40. package/dist/helpers/response.d.ts.map +1 -0
  41. package/dist/helpers/response.js +84 -0
  42. package/dist/helpers/response.js.map +1 -0
  43. package/dist/index.d.ts +10 -10
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +17 -8
  46. package/dist/index.js.map +1 -1
  47. package/dist/models/core/auth_session.d.ts +1 -1
  48. package/dist/models/core/auth_session.d.ts.map +1 -1
  49. package/dist/models/core/connections.d.ts +1 -1
  50. package/dist/models/core/connections.d.ts.map +1 -1
  51. package/dist/models/core/index.d.ts +3 -3
  52. package/dist/models/core/index.d.ts.map +1 -1
  53. package/dist/models/core/index.js +3 -3
  54. package/dist/models/core/index.js.map +1 -1
  55. package/dist/models/core/qwc_auth_setup.d.ts +1 -1
  56. package/dist/models/core/qwc_auth_setup.d.ts.map +1 -1
  57. package/dist/models/index.d.ts +6 -6
  58. package/dist/models/index.d.ts.map +1 -1
  59. package/dist/models/index.js +5 -5
  60. package/dist/models/index.js.map +1 -1
  61. package/dist/models/qbd/account.d.ts +2 -2
  62. package/dist/models/qbd/account.d.ts.map +1 -1
  63. package/dist/models/qbd/account.js +1 -1
  64. package/dist/models/qbd/account.js.map +1 -1
  65. package/dist/models/qbd/account_tax_line_info.d.ts +1 -1
  66. package/dist/models/qbd/account_tax_line_info.d.ts.map +1 -1
  67. package/dist/models/qbd/ar_refund_credit_card.d.ts +1 -1
  68. package/dist/models/qbd/ar_refund_credit_card.d.ts.map +1 -1
  69. package/dist/models/qbd/bar_code.d.ts +1 -1
  70. package/dist/models/qbd/bar_code.d.ts.map +1 -1
  71. package/dist/models/qbd/bill.d.ts +1 -1
  72. package/dist/models/qbd/bill.d.ts.map +1 -1
  73. package/dist/models/qbd/bill_payment_or_credit.d.ts +1 -1
  74. package/dist/models/qbd/bill_payment_or_credit.d.ts.map +1 -1
  75. package/dist/models/qbd/billing_rate.d.ts +1 -1
  76. package/dist/models/qbd/billing_rate.d.ts.map +1 -1
  77. package/dist/models/qbd/build_assembly.d.ts +1 -1
  78. package/dist/models/qbd/build_assembly.d.ts.map +1 -1
  79. package/dist/models/qbd/charge.d.ts +1 -1
  80. package/dist/models/qbd/charge.d.ts.map +1 -1
  81. package/dist/models/qbd/check.d.ts +1 -1
  82. package/dist/models/qbd/check.d.ts.map +1 -1
  83. package/dist/models/qbd/check_bill_payment.d.ts +1 -1
  84. package/dist/models/qbd/check_bill_payment.d.ts.map +1 -1
  85. package/dist/models/qbd/class_.d.ts +1 -1
  86. package/dist/models/qbd/class_.d.ts.map +1 -1
  87. package/dist/models/qbd/credit_card_bill_payment.d.ts +1 -1
  88. package/dist/models/qbd/credit_card_bill_payment.d.ts.map +1 -1
  89. package/dist/models/qbd/credit_card_charge.d.ts +1 -1
  90. package/dist/models/qbd/credit_card_charge.d.ts.map +1 -1
  91. package/dist/models/qbd/credit_card_credit.d.ts +1 -1
  92. package/dist/models/qbd/credit_card_credit.d.ts.map +1 -1
  93. package/dist/models/qbd/credit_memo.d.ts +1 -1
  94. package/dist/models/qbd/credit_memo.d.ts.map +1 -1
  95. package/dist/models/qbd/currency.d.ts +2 -1
  96. package/dist/models/qbd/currency.d.ts.map +1 -1
  97. package/dist/models/qbd/currency.js +2 -1
  98. package/dist/models/qbd/currency.js.map +1 -1
  99. package/dist/models/qbd/custom_field_definitions.d.ts +1 -1
  100. package/dist/models/qbd/custom_field_definitions.d.ts.map +1 -1
  101. package/dist/models/qbd/custom_fields.d.ts +2 -2
  102. package/dist/models/qbd/custom_fields.d.ts.map +1 -1
  103. package/dist/models/qbd/custom_fields.js +1 -1
  104. package/dist/models/qbd/custom_fields.js.map +1 -1
  105. package/dist/models/qbd/customer.d.ts +2 -2
  106. package/dist/models/qbd/customer.d.ts.map +1 -1
  107. package/dist/models/qbd/customer.js +1 -1
  108. package/dist/models/qbd/customer.js.map +1 -1
  109. package/dist/models/qbd/customer_type.d.ts +1 -1
  110. package/dist/models/qbd/customer_type.d.ts.map +1 -1
  111. package/dist/models/qbd/date_driven_term.d.ts +1 -1
  112. package/dist/models/qbd/date_driven_term.d.ts.map +1 -1
  113. package/dist/models/qbd/deposit.d.ts +1 -1
  114. package/dist/models/qbd/deposit.d.ts.map +1 -1
  115. package/dist/models/qbd/employee.d.ts +2 -2
  116. package/dist/models/qbd/employee.d.ts.map +1 -1
  117. package/dist/models/qbd/employee.js +1 -1
  118. package/dist/models/qbd/employee.js.map +1 -1
  119. package/dist/models/qbd/estimate.d.ts +1 -1
  120. package/dist/models/qbd/estimate.d.ts.map +1 -1
  121. package/dist/models/qbd/index.d.ts +66 -66
  122. package/dist/models/qbd/index.d.ts.map +1 -1
  123. package/dist/models/qbd/index.js +66 -66
  124. package/dist/models/qbd/index.js.map +1 -1
  125. package/dist/models/qbd/inventory_adjustment.d.ts +1 -1
  126. package/dist/models/qbd/inventory_adjustment.d.ts.map +1 -1
  127. package/dist/models/qbd/inventory_site.d.ts +1 -1
  128. package/dist/models/qbd/inventory_site.d.ts.map +1 -1
  129. package/dist/models/qbd/invoice.d.ts +2 -1
  130. package/dist/models/qbd/invoice.d.ts.map +1 -1
  131. package/dist/models/qbd/invoice.js +2 -1
  132. package/dist/models/qbd/invoice.js.map +1 -1
  133. package/dist/models/qbd/item.d.ts +2 -2
  134. package/dist/models/qbd/item.d.ts.map +1 -1
  135. package/dist/models/qbd/item.js +1 -1
  136. package/dist/models/qbd/item.js.map +1 -1
  137. package/dist/models/qbd/item_discount.d.ts +1 -1
  138. package/dist/models/qbd/item_discount.d.ts.map +1 -1
  139. package/dist/models/qbd/item_fixed_asset.d.ts +1 -1
  140. package/dist/models/qbd/item_fixed_asset.d.ts.map +1 -1
  141. package/dist/models/qbd/item_group.d.ts +1 -1
  142. package/dist/models/qbd/item_group.d.ts.map +1 -1
  143. package/dist/models/qbd/item_inventory.d.ts +1 -1
  144. package/dist/models/qbd/item_inventory.d.ts.map +1 -1
  145. package/dist/models/qbd/item_inventory_assembly.d.ts +1 -1
  146. package/dist/models/qbd/item_inventory_assembly.d.ts.map +1 -1
  147. package/dist/models/qbd/item_non_inventory.d.ts +1 -1
  148. package/dist/models/qbd/item_non_inventory.d.ts.map +1 -1
  149. package/dist/models/qbd/item_other_charge.d.ts +1 -1
  150. package/dist/models/qbd/item_other_charge.d.ts.map +1 -1
  151. package/dist/models/qbd/item_payment.d.ts +1 -1
  152. package/dist/models/qbd/item_payment.d.ts.map +1 -1
  153. package/dist/models/qbd/item_receipt.d.ts +1 -1
  154. package/dist/models/qbd/item_receipt.d.ts.map +1 -1
  155. package/dist/models/qbd/item_sales_tax.d.ts +1 -1
  156. package/dist/models/qbd/item_sales_tax.d.ts.map +1 -1
  157. package/dist/models/qbd/item_sales_tax_group.d.ts +1 -1
  158. package/dist/models/qbd/item_sales_tax_group.d.ts.map +1 -1
  159. package/dist/models/qbd/item_service.d.ts +1 -1
  160. package/dist/models/qbd/item_service.d.ts.map +1 -1
  161. package/dist/models/qbd/item_subtotal.d.ts +1 -1
  162. package/dist/models/qbd/item_subtotal.d.ts.map +1 -1
  163. package/dist/models/qbd/journal_entry.d.ts +1 -1
  164. package/dist/models/qbd/journal_entry.d.ts.map +1 -1
  165. package/dist/models/qbd/other_name.d.ts +1 -1
  166. package/dist/models/qbd/other_name.d.ts.map +1 -1
  167. package/dist/models/qbd/payment_method.d.ts +1 -1
  168. package/dist/models/qbd/payment_method.d.ts.map +1 -1
  169. package/dist/models/qbd/payroll_item_non_wage.d.ts +1 -1
  170. package/dist/models/qbd/payroll_item_non_wage.d.ts.map +1 -1
  171. package/dist/models/qbd/payroll_item_wage.d.ts +1 -1
  172. package/dist/models/qbd/payroll_item_wage.d.ts.map +1 -1
  173. package/dist/models/qbd/price_level.d.ts +1 -1
  174. package/dist/models/qbd/price_level.d.ts.map +1 -1
  175. package/dist/models/qbd/purchase_order.d.ts +1 -1
  176. package/dist/models/qbd/purchase_order.d.ts.map +1 -1
  177. package/dist/models/qbd/receive_payment.d.ts +1 -1
  178. package/dist/models/qbd/receive_payment.d.ts.map +1 -1
  179. package/dist/models/qbd/report.d.ts +1 -1
  180. package/dist/models/qbd/report.d.ts.map +1 -1
  181. package/dist/models/qbd/sales_order.d.ts +1 -1
  182. package/dist/models/qbd/sales_order.d.ts.map +1 -1
  183. package/dist/models/qbd/sales_receipt.d.ts +1 -1
  184. package/dist/models/qbd/sales_receipt.d.ts.map +1 -1
  185. package/dist/models/qbd/sales_tax_code.d.ts +1 -1
  186. package/dist/models/qbd/sales_tax_code.d.ts.map +1 -1
  187. package/dist/models/qbd/sales_tax_payment_check.d.ts +1 -1
  188. package/dist/models/qbd/sales_tax_payment_check.d.ts.map +1 -1
  189. package/dist/models/qbd/ship_method.d.ts +1 -1
  190. package/dist/models/qbd/ship_method.d.ts.map +1 -1
  191. package/dist/models/qbd/special_item.d.ts +1 -1
  192. package/dist/models/qbd/special_item.d.ts.map +1 -1
  193. package/dist/models/qbd/tenant_me.d.ts +1 -1
  194. package/dist/models/qbd/tenant_me.d.ts.map +1 -1
  195. package/dist/models/qbd/term.d.ts +1 -1
  196. package/dist/models/qbd/term.d.ts.map +1 -1
  197. package/dist/models/qbd/time_tracking_activity.d.ts +1 -1
  198. package/dist/models/qbd/time_tracking_activity.d.ts.map +1 -1
  199. package/dist/models/qbd/transaction.d.ts +1 -1
  200. package/dist/models/qbd/transaction.d.ts.map +1 -1
  201. package/dist/models/qbd/unit_of_measure_set.d.ts +1 -1
  202. package/dist/models/qbd/unit_of_measure_set.d.ts.map +1 -1
  203. package/dist/models/qbd/vendor.d.ts +1 -1
  204. package/dist/models/qbd/vendor.d.ts.map +1 -1
  205. package/dist/models/qbd/vendor_credit.d.ts +1 -1
  206. package/dist/models/qbd/vendor_credit.d.ts.map +1 -1
  207. package/dist/models/qbd/vendor_type.d.ts +1 -1
  208. package/dist/models/qbd/vendor_type.d.ts.map +1 -1
  209. package/dist/models/qbd/workers_comp_code.d.ts +1 -1
  210. package/dist/models/qbd/workers_comp_code.d.ts.map +1 -1
  211. package/dist/resources/base.d.ts +159 -29
  212. package/dist/resources/base.d.ts.map +1 -1
  213. package/dist/resources/base.js +417 -151
  214. package/dist/resources/base.js.map +1 -1
  215. package/dist/resources/connections.d.ts +17 -4
  216. package/dist/resources/connections.d.ts.map +1 -1
  217. package/dist/resources/connections.js +39 -13
  218. package/dist/resources/connections.js.map +1 -1
  219. package/dist/resources/custom-fields.d.ts +35 -32
  220. package/dist/resources/custom-fields.d.ts.map +1 -1
  221. package/dist/resources/custom-fields.js +121 -119
  222. package/dist/resources/custom-fields.js.map +1 -1
  223. package/dist/resources/reports.d.ts +23 -10
  224. package/dist/resources/reports.d.ts.map +1 -1
  225. package/dist/resources/reports.js +40 -29
  226. package/dist/resources/reports.js.map +1 -1
  227. package/dist/transport.d.ts +61 -10
  228. package/dist/transport.d.ts.map +1 -1
  229. package/dist/transport.js +522 -113
  230. package/dist/transport.js.map +1 -1
  231. package/package.json +8 -4
@@ -5,14 +5,111 @@
5
5
  * restricted variants that expose only the operations supported by each
6
6
  * QuickBooks Desktop endpoint.
7
7
  */
8
- import { PaginationError } from '../helpers/pagination';
9
- const LIST_TIMEOUT_HINT_HEADER = 'X-Nxus-Timeout-Seconds';
8
+ import { randomUUID } from "node:crypto";
9
+ import { enableIdempotentCreateTimeoutRetry, } from "../transport.js";
10
+ import { PaginationError } from "../helpers/pagination.js";
11
+ import { NxusResponse } from "../helpers/response.js";
12
+ const REQUEST_OPTION_KEYS = [
13
+ "connectionId",
14
+ "idempotencyKey",
15
+ "headers",
16
+ "timeout",
17
+ "serverTimeoutSeconds",
18
+ "maxRetries",
19
+ "verbose",
20
+ "fetchOptions",
21
+ "includeRawBody",
22
+ ];
23
+ const REQUEST_OPTION_KEY_SET = new Set(REQUEST_OPTION_KEYS);
24
+ const CURSOR_CLOSE_STRIPPED_HEADERS = new Set([
25
+ "x-connection-id",
26
+ "x-nxus-timeout-seconds",
27
+ ]);
28
+ function findRequestOptionKeys(value, allowedKeys = []) {
29
+ const allowedKeySet = new Set(allowedKeys);
30
+ return REQUEST_OPTION_KEYS.filter((key) => !allowedKeySet.has(key) && value[key] !== undefined);
31
+ }
32
+ export function assertNoRequestOptionKeys(value, allowedKeys = []) {
33
+ if (!value) {
34
+ return;
35
+ }
36
+ const conflictingKeys = findRequestOptionKeys(value, allowedKeys);
37
+ if (conflictingKeys.length === 0) {
38
+ return;
39
+ }
40
+ throw new Error(`Request options must be passed in the second argument only; found transport keys in the first argument: ${conflictingKeys.join(", ")}`);
41
+ }
42
+ export function withDefaultMaxRetries(options, maxRetries) {
43
+ if (options?.maxRetries !== undefined) {
44
+ return options;
45
+ }
46
+ return { ...(options ?? {}), maxRetries };
47
+ }
48
+ /**
49
+ * Attach one stable idempotency key to a logical generic Create operation.
50
+ *
51
+ * A raw Idempotency-Key header remains supported for backwards compatibility,
52
+ * but the first-class option wins when both forms are supplied. The returned
53
+ * options object is constructed once before the transport retry loop, so all
54
+ * attempts reuse the same header.
55
+ */
56
+ export function withCreateIdempotencyKey(options) {
57
+ const headers = { ...(options?.headers ?? {}) };
58
+ const headerEntry = Object.entries(headers).find(([name]) => name.toLowerCase() === "idempotency-key");
59
+ const idempotencyKey = options?.idempotencyKey ?? headerEntry?.[1] ?? randomUUID();
60
+ for (const name of Object.keys(headers)) {
61
+ if (name.toLowerCase() === "idempotency-key") {
62
+ delete headers[name];
63
+ }
64
+ }
65
+ return enableIdempotentCreateTimeoutRetry({
66
+ ...(options ?? {}),
67
+ idempotencyKey,
68
+ headers: {
69
+ ...headers,
70
+ "Idempotency-Key": idempotencyKey,
71
+ },
72
+ });
73
+ }
74
+ function splitListQueryAndOptions(query, options) {
75
+ if (!query) {
76
+ return {
77
+ query: {},
78
+ options,
79
+ };
80
+ }
81
+ assertNoRequestOptionKeys(query);
82
+ const nextQuery = { ...query };
83
+ const timeoutSeconds = nextQuery.timeoutSeconds;
84
+ delete nextQuery.timeoutSeconds;
85
+ let requestOptions = options;
86
+ if (requestOptions?.serverTimeoutSeconds === undefined &&
87
+ timeoutSeconds !== undefined) {
88
+ requestOptions = {
89
+ ...(options ?? {}),
90
+ serverTimeoutSeconds: timeoutSeconds,
91
+ };
92
+ }
93
+ return {
94
+ query: nextQuery,
95
+ options: requestOptions,
96
+ };
97
+ }
98
+ function extractCursorCloseOptions(options) {
99
+ const { connectionId: _connectionId, headers, serverTimeoutSeconds: _serverTimeoutSeconds, ...rest } = options ?? {};
100
+ const cursorCloseOptions = withDefaultMaxRetries(rest, 0);
101
+ const filteredHeaders = Object.fromEntries(Object.entries(headers ?? {}).filter(([name]) => !CURSOR_CLOSE_STRIPPED_HEADERS.has(name.toLowerCase())));
102
+ if (Object.keys(filteredHeaders).length > 0) {
103
+ cursorCloseOptions.headers = filteredHeaders;
104
+ }
105
+ return cursorCloseOptions;
106
+ }
10
107
  // ---------------------------------------------------------------------------
11
108
  // Pagination helpers (adapted for transport)
12
109
  // ---------------------------------------------------------------------------
13
110
  function normalizePage(value) {
14
- if (typeof value !== 'object' || value === null) {
15
- throw new PaginationError('Expected a paginated response object with data, hasMore, and nextCursor fields.', { causeData: value });
111
+ if (typeof value !== "object" || value === null) {
112
+ throw new PaginationError("Expected a paginated response object with data, hasMore, and nextCursor fields.", { causeData: value });
16
113
  }
17
114
  const obj = value;
18
115
  const data = Array.isArray(obj.data) ? obj.data : [];
@@ -20,14 +117,14 @@ function normalizePage(value) {
20
117
  ...obj,
21
118
  data,
22
119
  hasMore: Boolean(obj.hasMore),
23
- nextCursor: typeof obj.nextCursor === 'string' ? obj.nextCursor : null,
120
+ nextCursor: typeof obj.nextCursor === "string" ? obj.nextCursor : null,
24
121
  };
25
122
  }
26
123
  function wrapPage(page, fetchNextPage) {
27
124
  const hasNextPage = () => page.hasMore && Boolean(page.nextCursor);
28
125
  const getNextPage = async () => {
29
126
  if (!hasNextPage() || !page.nextCursor) {
30
- throw new PaginationError('No additional pages are available.');
127
+ throw new PaginationError("No additional pages are available.");
31
128
  }
32
129
  return fetchNextPage(page.nextCursor);
33
130
  };
@@ -82,27 +179,51 @@ class TransportPaginationPromise {
82
179
  }
83
180
  }
84
181
  }
85
- // ---------------------------------------------------------------------------
86
- // Utility: extract RequestOptions from a params bag
87
- // ---------------------------------------------------------------------------
88
- function extractOptions(params) {
89
- const { connectionId, headers, timeout, serverTimeoutSeconds, maxRetries, ...body } = params;
90
- const options = {};
91
- if (connectionId !== undefined)
92
- options.connectionId = connectionId;
93
- if (headers !== undefined)
94
- options.headers = headers;
95
- if (timeout !== undefined)
96
- options.timeout = timeout;
97
- if (serverTimeoutSeconds !== undefined)
98
- options.serverTimeoutSeconds = serverTimeoutSeconds;
99
- if (maxRetries !== undefined)
100
- options.maxRetries = maxRetries;
101
- return { body, options };
182
+ /**
183
+ * Build the wrapped method set once, for every resource shape.
184
+ *
185
+ * These call the same transport paths as the plain methods — the plain ones
186
+ * are wrappers that discard the snapshot — so parsing, retries and error
187
+ * translation cannot drift between the two forms.
188
+ */
189
+ function buildWithResponse(ctx) {
190
+ return {
191
+ async list(listQuery, options) {
192
+ const { query: requestQuery, options: requestOptions } = splitListQueryAndOptions(listQuery, options);
193
+ const wire = await ctx.transport.sendGet(ctx.basePath, requestQuery, requestOptions);
194
+ return NxusResponse.fromTransport(normalizePage(wire.body), wire);
195
+ },
196
+ async retrieve(id, options) {
197
+ const wire = await ctx.transport.sendGet(ctx.getSingularPath(id), undefined, options);
198
+ return NxusResponse.fromTransport(wire.body, wire);
199
+ },
200
+ async create(body, options) {
201
+ assertNoRequestOptionKeys(body);
202
+ const wire = await ctx.transport.sendPost(ctx.getCreatePath(), body, withCreateIdempotencyKey(options));
203
+ return NxusResponse.fromTransport(wire.body, wire);
204
+ },
205
+ async update(id, body, options) {
206
+ assertNoRequestOptionKeys(body);
207
+ const wire = await ctx.transport.sendPost(ctx.getSingularPath(id), body, options);
208
+ return NxusResponse.fromTransport(wire.body, wire);
209
+ },
210
+ async delete(id, options) {
211
+ const wire = await ctx.transport.sendDelete(ctx.getSingularPath(id), withDefaultMaxRetries(options, 0));
212
+ return NxusResponse.fromTransport(wire.body, wire);
213
+ },
214
+ async void(id, options) {
215
+ const wire = await ctx.transport.sendPost(`${ctx.getSingularPath(id)}/void`, undefined, withDefaultMaxRetries(options, 0));
216
+ return NxusResponse.fromTransport(wire.body, wire);
217
+ },
218
+ };
219
+ }
220
+ function pickWrappedResourceMethods(methods, keys) {
221
+ const picked = {};
222
+ for (const key of keys) {
223
+ picked[key] = methods[key];
224
+ }
225
+ return picked;
102
226
  }
103
- // ---------------------------------------------------------------------------
104
- // Resource<T> — full CRUD
105
- // ---------------------------------------------------------------------------
106
227
  export class Resource {
107
228
  transport;
108
229
  basePath;
@@ -119,7 +240,7 @@ export class Resource {
119
240
  getCreatePath() {
120
241
  if (this.createPath)
121
242
  return this.createPath;
122
- return this.basePath.replace(/s$/, '');
243
+ return this.basePath.replace(/s$/, "");
123
244
  }
124
245
  /**
125
246
  * Build the singular path for a specific resource by ID.
@@ -129,48 +250,22 @@ export class Resource {
129
250
  getSingularPath(id) {
130
251
  return `${this.getCreatePath()}/${id}`;
131
252
  }
132
- /**
133
- * List resources with auto-pagination support.
134
- *
135
- * ```ts
136
- * // Get the first page
137
- * const page = await resource.list({ limit: 50, connectionId: "..." });
138
- *
139
- * // Auto-paginate
140
- * for await (const item of resource.list({ limit: 50 })) { ... }
141
- * ```
142
- */
143
- list(params) {
144
- const { connectionId, headers, timeout, timeoutSeconds, serverTimeoutSeconds, maxRetries, ...query } = params ?? {};
145
- const reqOptions = {};
146
- if (connectionId !== undefined)
147
- reqOptions.connectionId = connectionId;
148
- if (timeout !== undefined)
149
- reqOptions.timeout = timeout;
150
- if (maxRetries !== undefined)
151
- reqOptions.maxRetries = maxRetries;
152
- const requestHeaders = headers
153
- ? { ...headers }
154
- : undefined;
155
- const backendTimeoutSeconds = serverTimeoutSeconds ?? timeoutSeconds;
156
- if (backendTimeoutSeconds !== undefined) {
157
- const mergedHeaders = requestHeaders ?? {};
158
- if (!(LIST_TIMEOUT_HINT_HEADER in mergedHeaders)) {
159
- mergedHeaders[LIST_TIMEOUT_HINT_HEADER] = String(backendTimeoutSeconds);
160
- }
161
- reqOptions.headers = mergedHeaders;
162
- }
163
- else if (requestHeaders) {
164
- reqOptions.headers = requestHeaders;
165
- }
253
+ list(query, options) {
254
+ const { query: requestQuery, options: requestOptions } = splitListQueryAndOptions(query, options);
255
+ const cursorCloseOptions = extractCursorCloseOptions(requestOptions);
166
256
  const fetchPage = async (cursor) => {
167
- const pageQuery = cursor ? { ...query, cursor } : { ...query };
168
- const raw = await this.transport.get(this.basePath, pageQuery, reqOptions);
257
+ const pageQuery = cursor
258
+ ? { ...requestQuery, cursor }
259
+ : { ...requestQuery };
260
+ const raw = await this.transport.get(this.basePath, pageQuery, requestOptions);
169
261
  const page = normalizePage(raw);
170
262
  return wrapPage(page, (nextCursor) => fetchPage(nextCursor));
171
263
  };
172
264
  const closeCursor = async (cursor) => {
173
- await this.transport.post(`/api/v1/cursors/${encodeURIComponent(cursor)}/close`);
265
+ // Cursor cleanup is transport-scoped, not connection-scoped. Reuse local
266
+ // transport controls and caller-provided headers, but intentionally drop
267
+ // connectionId and serverTimeoutSeconds.
268
+ await this.transport.post(`/api/v1/cursors/${encodeURIComponent(cursor)}/close`, undefined, cursorCloseOptions);
174
269
  };
175
270
  return new TransportPaginationPromise(fetchPage, closeCursor);
176
271
  }
@@ -184,40 +279,78 @@ export class Resource {
184
279
  async retrieve(id, options) {
185
280
  return this.transport.get(this.getSingularPath(id), undefined, options);
186
281
  }
187
- /**
188
- * Create a new resource. Fields are passed flat — `connectionId` and `headers`
189
- * are extracted and sent as request options.
190
- *
191
- * ```ts
192
- * const vendor = await resource.create({ name: "Acme", connectionId: "..." });
193
- * ```
194
- */
195
- async create(params) {
196
- const { body, options } = extractOptions(params);
197
- return this.transport.post(this.getCreatePath(), body, options);
282
+ async create(body, options) {
283
+ assertNoRequestOptionKeys(body);
284
+ return this.transport.post(this.getCreatePath(), body, withCreateIdempotencyKey(options));
285
+ }
286
+ async update(id, body, options) {
287
+ assertNoRequestOptionKeys(body);
288
+ return this.transport.post(this.getSingularPath(id), body, options);
198
289
  }
199
290
  /**
200
- * Update a resource. The Nxus API uses POST for updates.
291
+ * Delete a resource by ID.
201
292
  *
202
293
  * ```ts
203
- * const vendor = await resource.update("80000001-1234567890", { name: "Updated", connectionId: "..." });
294
+ * await resource.delete("80000001-1234567890", { connectionId: "..." });
204
295
  * ```
205
296
  */
206
- async update(id, params) {
207
- const { body, options } = extractOptions(params);
208
- return this.transport.post(this.getSingularPath(id), body, options);
297
+ async delete(id, options) {
298
+ return this.transport.delete(this.getSingularPath(id), withDefaultMaxRetries(options, 0));
209
299
  }
210
300
  /**
211
- * Delete a resource by ID.
301
+ * Call any method on this resource and get status/headers back too.
212
302
  *
213
303
  * ```ts
214
- * await resource.delete("80000001-1234567890", { connectionId: "..." });
304
+ * const check = await nxus.checks.create({ payeeId });
305
+ * // -> Check
306
+ *
307
+ * const wrapped = await nxus.checks.withResponse.create({ payeeId });
308
+ * // -> NxusResponse<Check>
309
+ * wrapped.data; // the same Check
310
+ * wrapped.requestId; // 'req_abc123'
215
311
  * ```
216
312
  */
217
- async delete(id, options) {
218
- await this.transport.delete(this.getSingularPath(id), options);
313
+ get withResponse() {
314
+ return pickWrappedResourceMethods(buildWithResponse({
315
+ transport: this.transport,
316
+ basePath: this.basePath,
317
+ getCreatePath: () => this.getCreatePath(),
318
+ getSingularPath: (id) => this.getSingularPath(id),
319
+ }), ["list", "retrieve", "create", "update", "delete"]);
219
320
  }
220
321
  }
322
+ /** Add the metadata-only count operation to a resource selected by the spec. */
323
+ export function withCount(resource, transport, countPath) {
324
+ const count = async (query, options) => {
325
+ if (query && (query.limit !== undefined || query.cursor !== undefined)) {
326
+ throw new Error("count() does not accept limit or cursor parameters.");
327
+ }
328
+ const { query: requestQuery, options: requestOptions } = splitListQueryAndOptions(query, options);
329
+ return transport.get(countPath, requestQuery, requestOptions);
330
+ };
331
+ const originalWithResponse = resource
332
+ .withResponse;
333
+ Object.defineProperty(resource, "count", {
334
+ configurable: true,
335
+ value: count,
336
+ });
337
+ Object.defineProperty(resource, "withResponse", {
338
+ configurable: true,
339
+ get: () => ({
340
+ ...(originalWithResponse ?? {}),
341
+ count: async (query, options) => {
342
+ if (query &&
343
+ (query.limit !== undefined || query.cursor !== undefined)) {
344
+ throw new Error("count() does not accept limit or cursor parameters.");
345
+ }
346
+ const { query: requestQuery, options: requestOptions } = splitListQueryAndOptions(query, options);
347
+ const wire = await transport.sendGet(countPath, requestQuery, requestOptions);
348
+ return NxusResponse.fromTransport(wire.body, wire);
349
+ },
350
+ }),
351
+ });
352
+ return resource;
353
+ }
221
354
  // ---------------------------------------------------------------------------
222
355
  // VoidableResource<T> — full CRUD plus void()
223
356
  // ---------------------------------------------------------------------------
@@ -235,7 +368,16 @@ export class VoidableResource extends Resource {
235
368
  * ```
236
369
  */
237
370
  async void(id, options) {
238
- return this.transport.post(`${this.getSingularPath(id)}/void`, undefined, options);
371
+ return this.transport.post(`${this.getSingularPath(id)}/void`, undefined, withDefaultMaxRetries(options, 0));
372
+ }
373
+ /** Adds `void` to the inherited wrapped method set. */
374
+ get withResponse() {
375
+ return pickWrappedResourceMethods(buildWithResponse({
376
+ transport: this.transport,
377
+ basePath: this.basePath,
378
+ getCreatePath: () => this.getCreatePath(),
379
+ getSingularPath: (id) => this.getSingularPath(id),
380
+ }), ["list", "retrieve", "create", "update", "delete", "void"]);
239
381
  }
240
382
  }
241
383
  // ---------------------------------------------------------------------------
@@ -251,30 +393,108 @@ export class ReadOnlyResource {
251
393
  this.singularPath = singularPath;
252
394
  }
253
395
  getSingularPath(id) {
254
- const path = this.singularPath ?? this.basePath.replace(/s$/, '');
396
+ const path = this.singularPath ?? this.basePath.replace(/s$/, "");
255
397
  return `${path}/${id}`;
256
398
  }
257
- list(params) {
399
+ list(query, options) {
258
400
  // Delegate to a full Resource instance for the pagination logic
259
- return new Resource(this.transport, this.basePath).list(params);
401
+ return new Resource(this.transport, this.basePath).list(query, options);
260
402
  }
261
403
  async retrieve(id, options) {
262
404
  return this.transport.get(this.getSingularPath(id), undefined, options);
263
405
  }
406
+ /** See {@link Resource.withResponse}. */
407
+ get withResponse() {
408
+ return pickWrappedResourceMethods(buildWithResponse({
409
+ transport: this.transport,
410
+ basePath: this.basePath,
411
+ getCreatePath: () => this.singularPath ?? this.basePath.replace(/s$/, ""),
412
+ getSingularPath: (id) => this.getSingularPath(id),
413
+ }), ["list", "retrieve"]);
414
+ }
264
415
  }
265
416
  // ---------------------------------------------------------------------------
266
417
  // Restricted variants
267
418
  // ---------------------------------------------------------------------------
268
419
  /** list + retrieve + create + delete (no update) */
269
- export class NoUpdateResource extends Resource {
270
- update(_id, _params) {
271
- throw new Error(`update() is not supported on ${this.basePath}`);
420
+ export class NoUpdateResource {
421
+ transport;
422
+ basePath;
423
+ createPath;
424
+ constructor(transport, basePath, createPath) {
425
+ this.transport = transport;
426
+ this.basePath = basePath;
427
+ this.createPath = createPath;
428
+ }
429
+ getCreatePath() {
430
+ if (this.createPath)
431
+ return this.createPath;
432
+ return this.basePath.replace(/s$/, "");
433
+ }
434
+ getSingularPath(id) {
435
+ return `${this.getCreatePath()}/${id}`;
436
+ }
437
+ list(query, options) {
438
+ return new Resource(this.transport, this.basePath, this.createPath).list(query, options);
439
+ }
440
+ async retrieve(id, options) {
441
+ return this.transport.get(this.getSingularPath(id), undefined, options);
442
+ }
443
+ async create(body, options) {
444
+ assertNoRequestOptionKeys(body);
445
+ return this.transport.post(this.getCreatePath(), body, withCreateIdempotencyKey(options));
446
+ }
447
+ async delete(id, options) {
448
+ return this.transport.delete(this.getSingularPath(id), withDefaultMaxRetries(options, 0));
449
+ }
450
+ get withResponse() {
451
+ return pickWrappedResourceMethods(buildWithResponse({
452
+ transport: this.transport,
453
+ basePath: this.basePath,
454
+ getCreatePath: () => this.getCreatePath(),
455
+ getSingularPath: (id) => this.getSingularPath(id),
456
+ }), ["list", "retrieve", "create", "delete"]);
272
457
  }
273
458
  }
274
459
  /** list + retrieve + create + update (no delete) */
275
- export class NoDeleteResource extends Resource {
276
- delete(_id, _options) {
277
- throw new Error(`delete() is not supported on ${this.basePath}`);
460
+ export class NoDeleteResource {
461
+ transport;
462
+ basePath;
463
+ createPath;
464
+ constructor(transport, basePath, createPath) {
465
+ this.transport = transport;
466
+ this.basePath = basePath;
467
+ this.createPath = createPath;
468
+ }
469
+ getCreatePath() {
470
+ if (this.createPath)
471
+ return this.createPath;
472
+ return this.basePath.replace(/s$/, "");
473
+ }
474
+ getSingularPath(id) {
475
+ return `${this.getCreatePath()}/${id}`;
476
+ }
477
+ list(query, options) {
478
+ return new Resource(this.transport, this.basePath, this.createPath).list(query, options);
479
+ }
480
+ async retrieve(id, options) {
481
+ return this.transport.get(this.getSingularPath(id), undefined, options);
482
+ }
483
+ async create(body, options) {
484
+ assertNoRequestOptionKeys(body);
485
+ return this.transport.post(this.getCreatePath(), body, withCreateIdempotencyKey(options));
486
+ }
487
+ async update(id, body, options) {
488
+ assertNoRequestOptionKeys(body);
489
+ return this.transport.post(this.getSingularPath(id), body, options);
490
+ }
491
+ get withResponse() {
492
+ return pickWrappedResourceMethods(buildWithResponse({
493
+ transport: this.transport,
494
+ basePath: this.basePath,
495
+ getCreatePath: () => this.getCreatePath(),
496
+ getSingularPath: (id) => this.getSingularPath(id),
497
+ }), ["list", "retrieve", "create", "update"]);
278
498
  }
279
499
  }
280
500
  /** list + retrieve + delete (no create, no update) */
@@ -286,16 +506,25 @@ export class ListRetrieveDeleteResource {
286
506
  this.basePath = basePath;
287
507
  }
288
508
  getSingularPath(id) {
289
- return `${this.basePath.replace(/s$/, '')}/${id}`;
509
+ return `${this.basePath.replace(/s$/, "")}/${id}`;
290
510
  }
291
- list(params) {
292
- return new Resource(this.transport, this.basePath).list(params);
511
+ list(query, options) {
512
+ return new Resource(this.transport, this.basePath).list(query, options);
293
513
  }
294
514
  async retrieve(id, options) {
295
515
  return this.transport.get(this.getSingularPath(id), undefined, options);
296
516
  }
297
517
  async delete(id, options) {
298
- await this.transport.delete(this.getSingularPath(id), options);
518
+ return this.transport.delete(this.getSingularPath(id), withDefaultMaxRetries(options, 0));
519
+ }
520
+ /** See {@link Resource.withResponse}. */
521
+ get withResponse() {
522
+ return pickWrappedResourceMethods(buildWithResponse({
523
+ transport: this.transport,
524
+ basePath: this.basePath,
525
+ getCreatePath: () => this.basePath.replace(/s$/, ""),
526
+ getSingularPath: (id) => this.getSingularPath(id),
527
+ }), ["list", "retrieve", "delete"]);
299
528
  }
300
529
  }
301
530
  /** list + delete (no retrieve, create, or update) */
@@ -309,14 +538,43 @@ export class ListDeleteResource {
309
538
  this.singularPath = singularPath;
310
539
  }
311
540
  getSingularPath(id) {
312
- const path = this.singularPath ?? this.basePath.replace(/s$/, '');
541
+ const path = this.singularPath ?? this.basePath.replace(/s$/, "");
313
542
  return `${path}/${id}`;
314
543
  }
315
- list(params) {
316
- return new Resource(this.transport, this.basePath).list(params);
544
+ list(query, options) {
545
+ return new Resource(this.transport, this.basePath).list(query, options);
317
546
  }
318
547
  async delete(id, options) {
319
- await this.transport.delete(this.getSingularPath(id), options);
548
+ return this.transport.delete(this.getSingularPath(id), withDefaultMaxRetries(options, 0));
549
+ }
550
+ /** See {@link Resource.withResponse}. */
551
+ get withResponse() {
552
+ return pickWrappedResourceMethods(buildWithResponse({
553
+ transport: this.transport,
554
+ basePath: this.basePath,
555
+ getCreatePath: () => this.singularPath ?? this.basePath.replace(/s$/, ""),
556
+ getSingularPath: (id) => this.getSingularPath(id),
557
+ }), ["list", "delete"]);
558
+ }
559
+ }
560
+ /** list only (no retrieve, create, update, or delete) */
561
+ export class ListOnlyResource {
562
+ transport;
563
+ basePath;
564
+ constructor(transport, basePath) {
565
+ this.transport = transport;
566
+ this.basePath = basePath;
567
+ }
568
+ list(query, options) {
569
+ return new Resource(this.transport, this.basePath).list(query, options);
570
+ }
571
+ get withResponse() {
572
+ return pickWrappedResourceMethods(buildWithResponse({
573
+ transport: this.transport,
574
+ basePath: this.basePath,
575
+ getCreatePath: () => this.basePath,
576
+ getSingularPath: () => this.basePath,
577
+ }), ["list"]);
320
578
  }
321
579
  }
322
580
  /** list + retrieve + create (no update, no delete) */
@@ -332,31 +590,29 @@ export class ListRetrieveCreateResource {
332
590
  getCreatePath() {
333
591
  if (this.createPath)
334
592
  return this.createPath;
335
- return this.basePath.replace(/s$/, '');
593
+ return this.basePath.replace(/s$/, "");
336
594
  }
337
595
  getSingularPath(id) {
338
596
  return `${this.getCreatePath()}/${id}`;
339
597
  }
340
- list(params) {
341
- return new Resource(this.transport, this.basePath).list(params);
598
+ list(query, options) {
599
+ return new Resource(this.transport, this.basePath).list(query, options);
342
600
  }
343
601
  async retrieve(id, options) {
344
602
  return this.transport.get(this.getSingularPath(id), undefined, options);
345
603
  }
346
- async create(params) {
347
- const { connectionId, headers, timeout, serverTimeoutSeconds, maxRetries, ...body } = params;
348
- const options = {};
349
- if (connectionId)
350
- options.connectionId = connectionId;
351
- if (headers)
352
- options.headers = headers;
353
- if (timeout)
354
- options.timeout = timeout;
355
- if (serverTimeoutSeconds)
356
- options.serverTimeoutSeconds = serverTimeoutSeconds;
357
- if (maxRetries !== undefined)
358
- options.maxRetries = maxRetries;
359
- return this.transport.post(this.getCreatePath(), body, options);
604
+ async create(body, options) {
605
+ assertNoRequestOptionKeys(body);
606
+ return this.transport.post(this.getCreatePath(), body, withCreateIdempotencyKey(options));
607
+ }
608
+ /** See {@link Resource.withResponse}. */
609
+ get withResponse() {
610
+ return pickWrappedResourceMethods(buildWithResponse({
611
+ transport: this.transport,
612
+ basePath: this.basePath,
613
+ getCreatePath: () => this.getCreatePath(),
614
+ getSingularPath: (id) => this.getSingularPath(id),
615
+ }), ["list", "retrieve", "create"]);
360
616
  }
361
617
  }
362
618
  /** list + retrieve + create + delete (no update) — same as NoUpdateResource but cleaner */
@@ -372,34 +628,46 @@ export class CrudNoUpdateResource {
372
628
  getCreatePath() {
373
629
  if (this.createPath)
374
630
  return this.createPath;
375
- return this.basePath.replace(/s$/, '');
631
+ return this.basePath.replace(/s$/, "");
376
632
  }
377
633
  getSingularPath(id) {
378
634
  return `${this.getCreatePath()}/${id}`;
379
635
  }
380
- list(params) {
381
- return new Resource(this.transport, this.basePath).list(params);
636
+ list(query, options) {
637
+ return new Resource(this.transport, this.basePath).list(query, options);
382
638
  }
383
639
  async retrieve(id, options) {
384
640
  return this.transport.get(this.getSingularPath(id), undefined, options);
385
641
  }
386
- async create(params) {
387
- const { connectionId, headers, timeout, serverTimeoutSeconds, maxRetries, ...body } = params;
388
- const options = {};
389
- if (connectionId)
390
- options.connectionId = connectionId;
391
- if (headers)
392
- options.headers = headers;
393
- if (timeout)
394
- options.timeout = timeout;
395
- if (serverTimeoutSeconds)
396
- options.serverTimeoutSeconds = serverTimeoutSeconds;
397
- if (maxRetries !== undefined)
398
- options.maxRetries = maxRetries;
399
- return this.transport.post(this.getCreatePath(), body, options);
642
+ async create(body, options) {
643
+ assertNoRequestOptionKeys(body);
644
+ return this.transport.post(this.getCreatePath(), body, withCreateIdempotencyKey(options));
400
645
  }
401
646
  async delete(id, options) {
402
- await this.transport.delete(this.getSingularPath(id), options);
647
+ return this.transport.delete(this.getSingularPath(id), withDefaultMaxRetries(options, 0));
648
+ }
649
+ /** See {@link Resource.withResponse}. */
650
+ get withResponse() {
651
+ return pickWrappedResourceMethods(buildWithResponse({
652
+ transport: this.transport,
653
+ basePath: this.basePath,
654
+ getCreatePath: () => this.getCreatePath(),
655
+ getSingularPath: (id) => this.getSingularPath(id),
656
+ }), ["list", "retrieve", "create", "delete"]);
657
+ }
658
+ }
659
+ /** list + retrieve + create + delete + void (no update) */
660
+ export class VoidableNoUpdateResource extends CrudNoUpdateResource {
661
+ async void(id, options) {
662
+ return this.transport.post(`${this.getSingularPath(id)}/void`, undefined, withDefaultMaxRetries(options, 0));
663
+ }
664
+ get withResponse() {
665
+ return pickWrappedResourceMethods(buildWithResponse({
666
+ transport: this.transport,
667
+ basePath: this.basePath,
668
+ getCreatePath: () => this.getCreatePath(),
669
+ getSingularPath: (id) => this.getSingularPath(id),
670
+ }), ["list", "retrieve", "create", "delete", "void"]);
403
671
  }
404
672
  }
405
673
  /** create-only (e.g. Special Items) */
@@ -410,20 +678,18 @@ export class CreateOnlyResource {
410
678
  this.transport = transport;
411
679
  this.createPath = createPath;
412
680
  }
413
- async create(params) {
414
- const { connectionId, headers, timeout, serverTimeoutSeconds, maxRetries, ...body } = params;
415
- const options = {};
416
- if (connectionId)
417
- options.connectionId = connectionId;
418
- if (headers)
419
- options.headers = headers;
420
- if (timeout)
421
- options.timeout = timeout;
422
- if (serverTimeoutSeconds)
423
- options.serverTimeoutSeconds = serverTimeoutSeconds;
424
- if (maxRetries !== undefined)
425
- options.maxRetries = maxRetries;
426
- return this.transport.post(this.createPath, body, options);
681
+ async create(body, options) {
682
+ assertNoRequestOptionKeys(body);
683
+ return this.transport.post(this.createPath, body, withCreateIdempotencyKey(options));
684
+ }
685
+ /** See {@link Resource.withResponse}. */
686
+ get withResponse() {
687
+ return pickWrappedResourceMethods(buildWithResponse({
688
+ transport: this.transport,
689
+ basePath: this.createPath,
690
+ getCreatePath: () => this.createPath,
691
+ getSingularPath: () => this.createPath,
692
+ }), ["create"]);
427
693
  }
428
694
  }
429
695
  //# sourceMappingURL=base.js.map