@tryfinch/finch-api 6.5.0 → 6.6.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 (123) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/_shims/node-types.d.ts +1 -1
  3. package/core.d.ts +5 -2
  4. package/core.d.ts.map +1 -1
  5. package/core.js +28 -8
  6. package/core.js.map +1 -1
  7. package/core.mjs +25 -6
  8. package/core.mjs.map +1 -1
  9. package/error.d.ts +1 -1
  10. package/error.d.ts.map +1 -1
  11. package/error.js +1 -1
  12. package/error.js.map +1 -1
  13. package/error.mjs +1 -1
  14. package/error.mjs.map +1 -1
  15. package/index.d.mts +3 -13
  16. package/index.d.ts +3 -13
  17. package/index.d.ts.map +1 -1
  18. package/index.js +9 -13
  19. package/index.js.map +1 -1
  20. package/index.mjs +9 -13
  21. package/index.mjs.map +1 -1
  22. package/internal/qs/formats.d.ts +6 -0
  23. package/internal/qs/formats.d.ts.map +1 -0
  24. package/internal/qs/formats.js +11 -0
  25. package/internal/qs/formats.js.map +1 -0
  26. package/internal/qs/formats.mjs +8 -0
  27. package/internal/qs/formats.mjs.map +1 -0
  28. package/internal/qs/index.d.ts +10 -0
  29. package/internal/qs/index.d.ts.map +1 -0
  30. package/internal/qs/index.js +14 -0
  31. package/internal/qs/index.js.map +1 -0
  32. package/internal/qs/index.mjs +10 -0
  33. package/internal/qs/index.mjs.map +1 -0
  34. package/internal/qs/stringify.d.ts +3 -0
  35. package/internal/qs/stringify.d.ts.map +1 -0
  36. package/internal/qs/stringify.js +280 -0
  37. package/internal/qs/stringify.js.map +1 -0
  38. package/internal/qs/stringify.mjs +276 -0
  39. package/internal/qs/stringify.mjs.map +1 -0
  40. package/internal/qs/types.d.ts +57 -0
  41. package/internal/qs/types.d.ts.map +1 -0
  42. package/internal/qs/types.js +3 -0
  43. package/internal/qs/types.js.map +1 -0
  44. package/internal/qs/types.mjs +2 -0
  45. package/internal/qs/types.mjs.map +1 -0
  46. package/internal/qs/utils.d.ts +14 -0
  47. package/internal/qs/utils.d.ts.map +1 -0
  48. package/internal/qs/utils.js +229 -0
  49. package/internal/qs/utils.js.map +1 -0
  50. package/internal/qs/utils.mjs +217 -0
  51. package/internal/qs/utils.mjs.map +1 -0
  52. package/package.json +2 -4
  53. package/resources/access-tokens.d.ts +5 -0
  54. package/resources/access-tokens.d.ts.map +1 -1
  55. package/resources/access-tokens.js.map +1 -1
  56. package/resources/access-tokens.mjs.map +1 -1
  57. package/resources/account.d.ts +15 -0
  58. package/resources/account.d.ts.map +1 -1
  59. package/resources/account.js.map +1 -1
  60. package/resources/account.mjs.map +1 -1
  61. package/resources/connect/connect.d.ts +13 -0
  62. package/resources/connect/connect.d.ts.map +1 -0
  63. package/resources/connect/connect.js +40 -0
  64. package/resources/connect/connect.js.map +1 -0
  65. package/resources/connect/connect.mjs +13 -0
  66. package/resources/connect/connect.mjs.map +1 -0
  67. package/resources/connect/index.d.ts +3 -0
  68. package/resources/connect/index.d.ts.map +1 -0
  69. package/resources/connect/index.js +9 -0
  70. package/resources/connect/index.js.map +1 -0
  71. package/resources/connect/index.mjs +4 -0
  72. package/resources/connect/index.mjs.map +1 -0
  73. package/resources/connect/sessions.d.ts +80 -0
  74. package/resources/connect/sessions.d.ts.map +1 -0
  75. package/resources/connect/sessions.js +23 -0
  76. package/resources/connect/sessions.js.map +1 -0
  77. package/resources/connect/sessions.mjs +19 -0
  78. package/resources/connect/sessions.mjs.map +1 -0
  79. package/resources/index.d.ts +1 -0
  80. package/resources/index.d.ts.map +1 -1
  81. package/resources/index.js +3 -1
  82. package/resources/index.js.map +1 -1
  83. package/resources/index.mjs +1 -0
  84. package/resources/index.mjs.map +1 -1
  85. package/resources/sandbox/directory.d.ts +1 -0
  86. package/resources/sandbox/directory.d.ts.map +1 -1
  87. package/resources/sandbox/directory.js.map +1 -1
  88. package/resources/sandbox/directory.mjs.map +1 -1
  89. package/resources/sandbox/employment.d.ts +2 -0
  90. package/resources/sandbox/employment.d.ts.map +1 -1
  91. package/resources/sandbox/employment.js.map +1 -1
  92. package/resources/sandbox/employment.mjs.map +1 -1
  93. package/shims/node.d.ts +1 -0
  94. package/shims/node.d.ts.map +1 -1
  95. package/src/_shims/node-types.d.ts +1 -1
  96. package/src/core.ts +31 -6
  97. package/src/error.ts +2 -2
  98. package/src/index.ts +9 -26
  99. package/src/internal/qs/LICENSE.md +13 -0
  100. package/src/internal/qs/README.md +3 -0
  101. package/src/internal/qs/formats.ts +9 -0
  102. package/src/internal/qs/index.ts +13 -0
  103. package/src/internal/qs/stringify.ts +388 -0
  104. package/src/internal/qs/types.ts +71 -0
  105. package/src/internal/qs/utils.ts +265 -0
  106. package/src/resources/access-tokens.ts +6 -0
  107. package/src/resources/account.ts +18 -0
  108. package/src/resources/connect/connect.ts +16 -0
  109. package/src/resources/connect/index.ts +10 -0
  110. package/src/resources/connect/sessions.ts +114 -0
  111. package/src/resources/index.ts +1 -0
  112. package/src/resources/sandbox/directory.ts +2 -0
  113. package/src/resources/sandbox/employment.ts +4 -0
  114. package/src/uploads.ts +5 -3
  115. package/src/version.ts +1 -1
  116. package/uploads.d.ts.map +1 -1
  117. package/uploads.js +5 -3
  118. package/uploads.js.map +1 -1
  119. package/uploads.mjs +5 -3
  120. package/uploads.mjs.map +1 -1
  121. package/version.d.ts +1 -1
  122. package/version.js +1 -1
  123. package/version.mjs +1 -1
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  import * as Errors from './error';
4
4
  import * as Uploads from './uploads';
5
5
  import { type Agent } from './_shims/index';
6
- import * as qs from 'qs';
6
+ import * as qs from './internal/qs';
7
7
  import * as Core from './core';
8
8
  import * as Pagination from './pagination';
9
9
  import * as API from './resources/index';
@@ -21,16 +21,6 @@ export interface ClientOptions {
21
21
  */
22
22
  clientSecret?: string | null | undefined;
23
23
 
24
- /**
25
- * Defaults to process.env['FINCH_SANDBOX_CLIENT_ID'].
26
- */
27
- sandboxClientId?: string | null | undefined;
28
-
29
- /**
30
- * Defaults to process.env['FINCH_SANDBOX_CLIENT_SECRET'].
31
- */
32
- sandboxClientSecret?: string | null | undefined;
33
-
34
24
  /**
35
25
  * Defaults to process.env['FINCH_WEBHOOK_SECRET'].
36
26
  */
@@ -100,8 +90,6 @@ export class Finch extends Core.APIClient {
100
90
  accessToken: string | null;
101
91
  clientId: string | null;
102
92
  clientSecret: string | null;
103
- sandboxClientId: string | null;
104
- sandboxClientSecret: string | null;
105
93
  webhookSecret: string | null;
106
94
 
107
95
  private _options: ClientOptions;
@@ -112,8 +100,6 @@ export class Finch extends Core.APIClient {
112
100
  * @param {string | null | undefined} [opts.accessToken]
113
101
  * @param {string | null | undefined} [opts.clientId=process.env['FINCH_CLIENT_ID'] ?? null]
114
102
  * @param {string | null | undefined} [opts.clientSecret=process.env['FINCH_CLIENT_SECRET'] ?? null]
115
- * @param {string | null | undefined} [opts.sandboxClientId=process.env['FINCH_SANDBOX_CLIENT_ID'] ?? null]
116
- * @param {string | null | undefined} [opts.sandboxClientSecret=process.env['FINCH_SANDBOX_CLIENT_SECRET'] ?? null]
117
103
  * @param {string | null | undefined} [opts.webhookSecret=process.env['FINCH_WEBHOOK_SECRET'] ?? null]
118
104
  * @param {string} [opts.baseURL=process.env['FINCH_BASE_URL'] ?? https://api.tryfinch.com] - Override the default base URL for the API.
119
105
  * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
@@ -128,8 +114,6 @@ export class Finch extends Core.APIClient {
128
114
  accessToken = null,
129
115
  clientId = Core.readEnv('FINCH_CLIENT_ID') ?? null,
130
116
  clientSecret = Core.readEnv('FINCH_CLIENT_SECRET') ?? null,
131
- sandboxClientId = Core.readEnv('FINCH_SANDBOX_CLIENT_ID') ?? null,
132
- sandboxClientSecret = Core.readEnv('FINCH_SANDBOX_CLIENT_SECRET') ?? null,
133
117
  webhookSecret = Core.readEnv('FINCH_WEBHOOK_SECRET') ?? null,
134
118
  ...opts
135
119
  }: ClientOptions = {}) {
@@ -137,8 +121,6 @@ export class Finch extends Core.APIClient {
137
121
  accessToken,
138
122
  clientId,
139
123
  clientSecret,
140
- sandboxClientId,
141
- sandboxClientSecret,
142
124
  webhookSecret,
143
125
  ...opts,
144
126
  baseURL: baseURL || `https://api.tryfinch.com`,
@@ -157,8 +139,6 @@ export class Finch extends Core.APIClient {
157
139
  this.accessToken = accessToken;
158
140
  this.clientId = clientId;
159
141
  this.clientSecret = clientSecret;
160
- this.sandboxClientId = sandboxClientId;
161
- this.sandboxClientSecret = sandboxClientSecret;
162
142
  this.webhookSecret = webhookSecret;
163
143
  }
164
144
 
@@ -171,6 +151,7 @@ export class Finch extends Core.APIClient {
171
151
  jobs: API.Jobs = new API.Jobs(this);
172
152
  sandbox: API.Sandbox = new API.Sandbox(this);
173
153
  payroll: API.Payroll = new API.Payroll(this);
154
+ connect: API.Connect = new API.Connect(this);
174
155
 
175
156
  /**
176
157
  * DEPRECATED: use client.accessTokens.create instead.
@@ -250,7 +231,7 @@ export class Finch extends Core.APIClient {
250
231
  return;
251
232
  }
252
233
 
253
- if (this.sandboxClientId && this.sandboxClientSecret && headers['authorization']) {
234
+ if (this.clientId && this.clientSecret && headers['authorization']) {
254
235
  return;
255
236
  }
256
237
  if (customHeaders['authorization'] === null) {
@@ -258,7 +239,7 @@ export class Finch extends Core.APIClient {
258
239
  }
259
240
 
260
241
  throw new Error(
261
- 'Could not resolve authentication method. Expected either accessToken, sandboxClientId or sandboxClientSecret to be set. Or for one of the "Authorization" or "Authorization" headers to be explicitly omitted',
242
+ 'Could not resolve authentication method. Expected either accessToken, clientId or clientSecret to be set. Or for one of the "Authorization" or "Authorization" headers to be explicitly omitted',
262
243
  );
263
244
  }
264
245
 
@@ -280,15 +261,15 @@ export class Finch extends Core.APIClient {
280
261
  }
281
262
 
282
263
  protected basicAuth(opts: Core.FinalRequestOptions): Core.Headers {
283
- if (!this.sandboxClientId) {
264
+ if (!this.clientId) {
284
265
  return {};
285
266
  }
286
267
 
287
- if (!this.sandboxClientSecret) {
268
+ if (!this.clientSecret) {
288
269
  return {};
289
270
  }
290
271
 
291
- const credentials = `${this.sandboxClientId}:${this.sandboxClientSecret}`;
272
+ const credentials = `${this.clientId}:${this.clientSecret}`;
292
273
  const Authorization = `Basic ${Core.toBase64(credentials)}`;
293
274
  return { Authorization };
294
275
  }
@@ -393,6 +374,8 @@ export namespace Finch {
393
374
 
394
375
  export import Payroll = API.Payroll;
395
376
 
377
+ export import Connect = API.Connect;
378
+
396
379
  export import ConnectionStatusType = API.ConnectionStatusType;
397
380
  export import OperationSupport = API.OperationSupport;
398
381
  export import OperationSupportMatrix = API.OperationSupportMatrix;
@@ -0,0 +1,13 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/puruvj/neoqs/graphs/contributors) All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10
+
11
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,3 @@
1
+ # qs
2
+
3
+ This is a vendored version of [neoqs](https://github.com/PuruVJ/neoqs) which is a TypeScript rewrite of [qs](https://github.com/ljharb/qs), a query string library.
@@ -0,0 +1,9 @@
1
+ import type { Format } from './types';
2
+
3
+ export const default_format: Format = 'RFC3986';
4
+ export const formatters: Record<Format, (str: PropertyKey) => string> = {
5
+ RFC1738: (v: PropertyKey) => String(v).replace(/%20/g, '+'),
6
+ RFC3986: (v: PropertyKey) => String(v),
7
+ };
8
+ export const RFC1738 = 'RFC1738';
9
+ export const RFC3986 = 'RFC3986';
@@ -0,0 +1,13 @@
1
+ import { default_format, formatters, RFC1738, RFC3986 } from './formats';
2
+
3
+ const formats = {
4
+ formatters,
5
+ RFC1738,
6
+ RFC3986,
7
+ default: default_format,
8
+ };
9
+
10
+ export { stringify } from './stringify';
11
+ export { formats };
12
+
13
+ export type { DefaultDecoder, DefaultEncoder, Format, ParseOptions, StringifyOptions } from './types';
@@ -0,0 +1,388 @@
1
+ import { encode, is_buffer, maybe_map } from './utils';
2
+ import { default_format, formatters } from './formats';
3
+ import type { NonNullableProperties, StringifyOptions } from './types';
4
+
5
+ const has = Object.prototype.hasOwnProperty;
6
+
7
+ const array_prefix_generators = {
8
+ brackets(prefix: PropertyKey) {
9
+ return String(prefix) + '[]';
10
+ },
11
+ comma: 'comma',
12
+ indices(prefix: PropertyKey, key: string) {
13
+ return String(prefix) + '[' + key + ']';
14
+ },
15
+ repeat(prefix: PropertyKey) {
16
+ return String(prefix);
17
+ },
18
+ };
19
+
20
+ const is_array = Array.isArray;
21
+ const push = Array.prototype.push;
22
+ const push_to_array = function (arr: any[], value_or_array: any) {
23
+ push.apply(arr, is_array(value_or_array) ? value_or_array : [value_or_array]);
24
+ };
25
+
26
+ const to_ISO = Date.prototype.toISOString;
27
+
28
+ const defaults = {
29
+ addQueryPrefix: false,
30
+ allowDots: false,
31
+ allowEmptyArrays: false,
32
+ arrayFormat: 'indices',
33
+ charset: 'utf-8',
34
+ charsetSentinel: false,
35
+ delimiter: '&',
36
+ encode: true,
37
+ encodeDotInKeys: false,
38
+ encoder: encode,
39
+ encodeValuesOnly: false,
40
+ format: default_format,
41
+ formatter: formatters[default_format],
42
+ /** @deprecated */
43
+ indices: false,
44
+ serializeDate(date) {
45
+ return to_ISO.call(date);
46
+ },
47
+ skipNulls: false,
48
+ strictNullHandling: false,
49
+ } as NonNullableProperties<StringifyOptions & { formatter: (typeof formatters)['RFC1738'] }>;
50
+
51
+ function is_non_nullish_primitive(v: unknown): v is string | number | boolean | symbol | bigint {
52
+ return (
53
+ typeof v === 'string' ||
54
+ typeof v === 'number' ||
55
+ typeof v === 'boolean' ||
56
+ typeof v === 'symbol' ||
57
+ typeof v === 'bigint'
58
+ );
59
+ }
60
+
61
+ const sentinel = {};
62
+
63
+ function inner_stringify(
64
+ object: any,
65
+ prefix: PropertyKey,
66
+ generateArrayPrefix: StringifyOptions['arrayFormat'] | ((prefix: string, key: string) => string),
67
+ commaRoundTrip: boolean,
68
+ allowEmptyArrays: boolean,
69
+ strictNullHandling: boolean,
70
+ skipNulls: boolean,
71
+ encodeDotInKeys: boolean,
72
+ encoder: StringifyOptions['encoder'],
73
+ filter: StringifyOptions['filter'],
74
+ sort: StringifyOptions['sort'],
75
+ allowDots: StringifyOptions['allowDots'],
76
+ serializeDate: StringifyOptions['serializeDate'],
77
+ format: StringifyOptions['format'],
78
+ formatter: StringifyOptions['formatter'],
79
+ encodeValuesOnly: boolean,
80
+ charset: StringifyOptions['charset'],
81
+ sideChannel: WeakMap<any, any>,
82
+ ) {
83
+ let obj = object;
84
+
85
+ let tmp_sc = sideChannel;
86
+ let step = 0;
87
+ let find_flag = false;
88
+ while ((tmp_sc = tmp_sc.get(sentinel)) !== void undefined && !find_flag) {
89
+ // Where object last appeared in the ref tree
90
+ const pos = tmp_sc.get(object);
91
+ step += 1;
92
+ if (typeof pos !== 'undefined') {
93
+ if (pos === step) {
94
+ throw new RangeError('Cyclic object value');
95
+ } else {
96
+ find_flag = true; // Break while
97
+ }
98
+ }
99
+ if (typeof tmp_sc.get(sentinel) === 'undefined') {
100
+ step = 0;
101
+ }
102
+ }
103
+
104
+ if (typeof filter === 'function') {
105
+ obj = filter(prefix, obj);
106
+ } else if (obj instanceof Date) {
107
+ obj = serializeDate?.(obj);
108
+ } else if (generateArrayPrefix === 'comma' && is_array(obj)) {
109
+ obj = maybe_map(obj, function (value) {
110
+ if (value instanceof Date) {
111
+ return serializeDate?.(value);
112
+ }
113
+ return value;
114
+ });
115
+ }
116
+
117
+ if (obj === null) {
118
+ if (strictNullHandling) {
119
+ return encoder && !encodeValuesOnly ?
120
+ // @ts-expect-error
121
+ encoder(prefix, defaults.encoder, charset, 'key', format)
122
+ : prefix;
123
+ }
124
+
125
+ obj = '';
126
+ }
127
+
128
+ if (is_non_nullish_primitive(obj) || is_buffer(obj)) {
129
+ if (encoder) {
130
+ const key_value =
131
+ encodeValuesOnly ? prefix
132
+ // @ts-expect-error
133
+ : encoder(prefix, defaults.encoder, charset, 'key', format);
134
+ return [
135
+ formatter?.(key_value) +
136
+ '=' +
137
+ // @ts-expect-error
138
+ formatter?.(encoder(obj, defaults.encoder, charset, 'value', format)),
139
+ ];
140
+ }
141
+ return [formatter?.(prefix) + '=' + formatter?.(String(obj))];
142
+ }
143
+
144
+ const values: string[] = [];
145
+
146
+ if (typeof obj === 'undefined') {
147
+ return values;
148
+ }
149
+
150
+ let obj_keys;
151
+ if (generateArrayPrefix === 'comma' && is_array(obj)) {
152
+ // we need to join elements in
153
+ if (encodeValuesOnly && encoder) {
154
+ // @ts-expect-error values only
155
+ obj = maybe_map(obj, encoder);
156
+ }
157
+ obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
158
+ } else if (is_array(filter)) {
159
+ obj_keys = filter;
160
+ } else {
161
+ const keys = Object.keys(obj);
162
+ obj_keys = sort ? keys.sort(sort) : keys;
163
+ }
164
+
165
+ const encoded_prefix = encodeDotInKeys ? String(prefix).replace(/\./g, '%2E') : String(prefix);
166
+
167
+ const adjusted_prefix =
168
+ commaRoundTrip && is_array(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix;
169
+
170
+ if (allowEmptyArrays && is_array(obj) && obj.length === 0) {
171
+ return adjusted_prefix + '[]';
172
+ }
173
+
174
+ for (let j = 0; j < obj_keys.length; ++j) {
175
+ const key = obj_keys[j];
176
+ const value =
177
+ // @ts-ignore
178
+ typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key as any];
179
+
180
+ if (skipNulls && value === null) {
181
+ continue;
182
+ }
183
+
184
+ // @ts-ignore
185
+ const encoded_key = allowDots && encodeDotInKeys ? (key as any).replace(/\./g, '%2E') : key;
186
+ const key_prefix =
187
+ is_array(obj) ?
188
+ typeof generateArrayPrefix === 'function' ?
189
+ generateArrayPrefix(adjusted_prefix, encoded_key)
190
+ : adjusted_prefix
191
+ : adjusted_prefix + (allowDots ? '.' + encoded_key : '[' + encoded_key + ']');
192
+
193
+ sideChannel.set(object, step);
194
+ const valueSideChannel = new WeakMap();
195
+ valueSideChannel.set(sentinel, sideChannel);
196
+ push_to_array(
197
+ values,
198
+ inner_stringify(
199
+ value,
200
+ key_prefix,
201
+ generateArrayPrefix,
202
+ commaRoundTrip,
203
+ allowEmptyArrays,
204
+ strictNullHandling,
205
+ skipNulls,
206
+ encodeDotInKeys,
207
+ // @ts-ignore
208
+ generateArrayPrefix === 'comma' && encodeValuesOnly && is_array(obj) ? null : encoder,
209
+ filter,
210
+ sort,
211
+ allowDots,
212
+ serializeDate,
213
+ format,
214
+ formatter,
215
+ encodeValuesOnly,
216
+ charset,
217
+ valueSideChannel,
218
+ ),
219
+ );
220
+ }
221
+
222
+ return values;
223
+ }
224
+
225
+ function normalize_stringify_options(
226
+ opts: StringifyOptions = defaults,
227
+ ): NonNullableProperties<Omit<StringifyOptions, 'indices'>> & { indices?: boolean } {
228
+ if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
229
+ throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
230
+ }
231
+
232
+ if (typeof opts.encodeDotInKeys !== 'undefined' && typeof opts.encodeDotInKeys !== 'boolean') {
233
+ throw new TypeError('`encodeDotInKeys` option can only be `true` or `false`, when provided');
234
+ }
235
+
236
+ if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
237
+ throw new TypeError('Encoder has to be a function.');
238
+ }
239
+
240
+ const charset = opts.charset || defaults.charset;
241
+ if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
242
+ throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
243
+ }
244
+
245
+ let format = default_format;
246
+ if (typeof opts.format !== 'undefined') {
247
+ if (!has.call(formatters, opts.format)) {
248
+ throw new TypeError('Unknown format option provided.');
249
+ }
250
+ format = opts.format;
251
+ }
252
+ const formatter = formatters[format];
253
+
254
+ let filter = defaults.filter;
255
+ if (typeof opts.filter === 'function' || is_array(opts.filter)) {
256
+ filter = opts.filter;
257
+ }
258
+
259
+ let arrayFormat: StringifyOptions['arrayFormat'];
260
+ if (opts.arrayFormat && opts.arrayFormat in array_prefix_generators) {
261
+ arrayFormat = opts.arrayFormat;
262
+ } else if ('indices' in opts) {
263
+ arrayFormat = opts.indices ? 'indices' : 'repeat';
264
+ } else {
265
+ arrayFormat = defaults.arrayFormat;
266
+ }
267
+
268
+ if ('commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
269
+ throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
270
+ }
271
+
272
+ const allowDots =
273
+ typeof opts.allowDots === 'undefined' ?
274
+ !!opts.encodeDotInKeys === true ?
275
+ true
276
+ : defaults.allowDots
277
+ : !!opts.allowDots;
278
+
279
+ return {
280
+ addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
281
+ // @ts-ignore
282
+ allowDots: allowDots,
283
+ allowEmptyArrays:
284
+ typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
285
+ arrayFormat: arrayFormat,
286
+ charset: charset,
287
+ charsetSentinel:
288
+ typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
289
+ commaRoundTrip: !!opts.commaRoundTrip,
290
+ delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
291
+ encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
292
+ encodeDotInKeys:
293
+ typeof opts.encodeDotInKeys === 'boolean' ? opts.encodeDotInKeys : defaults.encodeDotInKeys,
294
+ encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
295
+ encodeValuesOnly:
296
+ typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
297
+ filter: filter,
298
+ format: format,
299
+ formatter: formatter,
300
+ serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,
301
+ skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,
302
+ // @ts-ignore
303
+ sort: typeof opts.sort === 'function' ? opts.sort : null,
304
+ strictNullHandling:
305
+ typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling,
306
+ };
307
+ }
308
+
309
+ export function stringify(object: any, opts: StringifyOptions = {}) {
310
+ let obj = object;
311
+ const options = normalize_stringify_options(opts);
312
+
313
+ let obj_keys: PropertyKey[] | undefined;
314
+ let filter;
315
+
316
+ if (typeof options.filter === 'function') {
317
+ filter = options.filter;
318
+ obj = filter('', obj);
319
+ } else if (is_array(options.filter)) {
320
+ filter = options.filter;
321
+ obj_keys = filter;
322
+ }
323
+
324
+ const keys: string[] = [];
325
+
326
+ if (typeof obj !== 'object' || obj === null) {
327
+ return '';
328
+ }
329
+
330
+ const generateArrayPrefix = array_prefix_generators[options.arrayFormat];
331
+ const commaRoundTrip = generateArrayPrefix === 'comma' && options.commaRoundTrip;
332
+
333
+ if (!obj_keys) {
334
+ obj_keys = Object.keys(obj);
335
+ }
336
+
337
+ if (options.sort) {
338
+ obj_keys.sort(options.sort);
339
+ }
340
+
341
+ const sideChannel = new WeakMap();
342
+ for (let i = 0; i < obj_keys.length; ++i) {
343
+ const key = obj_keys[i]!;
344
+
345
+ if (options.skipNulls && obj[key] === null) {
346
+ continue;
347
+ }
348
+ push_to_array(
349
+ keys,
350
+ inner_stringify(
351
+ obj[key],
352
+ key,
353
+ // @ts-expect-error
354
+ generateArrayPrefix,
355
+ commaRoundTrip,
356
+ options.allowEmptyArrays,
357
+ options.strictNullHandling,
358
+ options.skipNulls,
359
+ options.encodeDotInKeys,
360
+ options.encode ? options.encoder : null,
361
+ options.filter,
362
+ options.sort,
363
+ options.allowDots,
364
+ options.serializeDate,
365
+ options.format,
366
+ options.formatter,
367
+ options.encodeValuesOnly,
368
+ options.charset,
369
+ sideChannel,
370
+ ),
371
+ );
372
+ }
373
+
374
+ const joined = keys.join(options.delimiter);
375
+ let prefix = options.addQueryPrefix === true ? '?' : '';
376
+
377
+ if (options.charsetSentinel) {
378
+ if (options.charset === 'iso-8859-1') {
379
+ // encodeURIComponent('&#10003;'), the "numeric entity" representation of a checkmark
380
+ prefix += 'utf8=%26%2310003%3B&';
381
+ } else {
382
+ // encodeURIComponent('✓')
383
+ prefix += 'utf8=%E2%9C%93&';
384
+ }
385
+ }
386
+
387
+ return joined.length > 0 ? prefix + joined : '';
388
+ }
@@ -0,0 +1,71 @@
1
+ export type Format = 'RFC1738' | 'RFC3986';
2
+
3
+ export type DefaultEncoder = (str: any, defaultEncoder?: any, charset?: string) => string;
4
+ export type DefaultDecoder = (str: string, decoder?: any, charset?: string) => string;
5
+
6
+ export type BooleanOptional = boolean | undefined;
7
+
8
+ export type StringifyBaseOptions = {
9
+ delimiter?: string;
10
+ allowDots?: boolean;
11
+ encodeDotInKeys?: boolean;
12
+ strictNullHandling?: boolean;
13
+ skipNulls?: boolean;
14
+ encode?: boolean;
15
+ encoder?: (
16
+ str: any,
17
+ defaultEncoder: DefaultEncoder,
18
+ charset: string,
19
+ type: 'key' | 'value',
20
+ format?: Format,
21
+ ) => string;
22
+ filter?: Array<PropertyKey> | ((prefix: PropertyKey, value: any) => any);
23
+ arrayFormat?: 'indices' | 'brackets' | 'repeat' | 'comma';
24
+ indices?: boolean;
25
+ sort?: ((a: PropertyKey, b: PropertyKey) => number) | null;
26
+ serializeDate?: (d: Date) => string;
27
+ format?: 'RFC1738' | 'RFC3986';
28
+ formatter?: (str: PropertyKey) => string;
29
+ encodeValuesOnly?: boolean;
30
+ addQueryPrefix?: boolean;
31
+ charset?: 'utf-8' | 'iso-8859-1';
32
+ charsetSentinel?: boolean;
33
+ allowEmptyArrays?: boolean;
34
+ commaRoundTrip?: boolean;
35
+ };
36
+
37
+ export type StringifyOptions = StringifyBaseOptions;
38
+
39
+ export type ParseBaseOptions = {
40
+ comma?: boolean;
41
+ delimiter?: string | RegExp;
42
+ depth?: number | false;
43
+ decoder?: (str: string, defaultDecoder: DefaultDecoder, charset: string, type: 'key' | 'value') => any;
44
+ arrayLimit?: number;
45
+ parseArrays?: boolean;
46
+ plainObjects?: boolean;
47
+ allowPrototypes?: boolean;
48
+ allowSparse?: boolean;
49
+ parameterLimit?: number;
50
+ strictDepth?: boolean;
51
+ strictNullHandling?: boolean;
52
+ ignoreQueryPrefix?: boolean;
53
+ charset?: 'utf-8' | 'iso-8859-1';
54
+ charsetSentinel?: boolean;
55
+ interpretNumericEntities?: boolean;
56
+ allowEmptyArrays?: boolean;
57
+ duplicates?: 'combine' | 'first' | 'last';
58
+ allowDots?: boolean;
59
+ decodeDotInKeys?: boolean;
60
+ };
61
+
62
+ export type ParseOptions = ParseBaseOptions;
63
+
64
+ export type ParsedQs = {
65
+ [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[];
66
+ };
67
+
68
+ // Type to remove null or undefined union from each property
69
+ export type NonNullableProperties<T> = {
70
+ [K in keyof T]-?: Exclude<T[K], undefined | null>;
71
+ };