Skip to content

Commit 1fa9682

Browse files
authored
feat: Add default client request options (#23)
1 parent b5e1bdb commit 1fa9682

30 files changed

+518
-156
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ Some asynchronous operations, e.g., unlocking a door, return an [action attempt]
151151
Seam tracks the progress of requested operation and updates the action attempt.
152152

153153
To make working with action attempts more convenient for applications,
154-
this library provides the `waitForActionAttempt` option:
154+
this library provides the `waitForActionAttempt` option.
155+
156+
Pass the option per-request,
155157

156158
```ts
157159
await seam.locks.unlockDoor(
@@ -162,6 +164,17 @@ await seam.locks.unlockDoor(
162164
)
163165
```
164166

167+
or set the default option for the client:
168+
169+
```ts
170+
const seam = new SeamHttp({
171+
apiKey: 'your-api-key',
172+
waitForActionAttempt: true,
173+
})
174+
175+
await seam.locks.unlockDoor({ device_id })
176+
```
177+
165178
Using the `waitForActionAttempt` option:
166179

167180
- Polls the action attempt up to the `timeout`

generate-routes.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,14 @@ import {
254254
type SeamHttpOptionsWithClientSessionToken,
255255
type SeamHttpOptionsWithConsoleSessionToken,
256256
type SeamHttpOptionsWithPersonalAccessToken,
257+
type SeamHttpRequestOptions,
257258
} from 'lib/seam/connect/options.js'
258-
import { parseOptions } from 'lib/seam/connect/parse-options.js'
259+
import {
260+
limitToSeamHttpRequestOptions,
261+
parseOptions
262+
} from 'lib/seam/connect/parse-options.js'
259263
import {
260264
resolveActionAttempt,
261-
type ResolveActionAttemptOptions,
262265
} from 'lib/seam/connect/resolve-action-attempt.js'
263266
264267
${
@@ -291,6 +294,7 @@ const renderClass = (
291294
`
292295
export class SeamHttp${pascalCase(namespace)} {
293296
client: Client
297+
readonly defaults: Required<SeamHttpRequestOptions>
294298
295299
${constructors
296300
.replaceAll(': SeamHttp ', `: SeamHttp${pascalCase(namespace)} `)
@@ -342,10 +346,11 @@ const renderClassMethod = ({
342346
})
343347
${
344348
resource === 'action_attempt'
345-
? `if (waitForActionAttempt != null && waitForActionAttempt !== false) {
349+
? `const waitForActionAttempt = options.waitForActionAttempt ?? this.defaults.waitForActionAttempt
350+
if (waitForActionAttempt !== false) {
346351
return resolveActionAttempt(
347352
data.${resource},
348-
SeamHttpActionAttempts.fromClient(this.client),
353+
SeamHttpActionAttempts.fromClient(this.client, { ...this.defaults, waitForActionAttempt: false }),
349354
typeof waitForActionAttempt === 'boolean' ? {} : waitForActionAttempt,
350355
)
351356
}`
@@ -359,9 +364,9 @@ const renderClassMethodOptions = ({
359364
resource,
360365
}: Pick<Endpoint, 'resource'>): string => {
361366
if (resource === 'action_attempt') {
362-
return `{ waitForActionAttempt = false }: ${renderClassMethodOptionsTypeDef(
363-
{ resource },
364-
)} = {},`
367+
return `options: ${renderClassMethodOptionsTypeDef({
368+
resource,
369+
})} = {},`
365370
}
366371
return ''
367372
}
@@ -376,11 +381,7 @@ const renderClassMethodOptionsTypeDef = ({
376381
resource,
377382
}: Pick<Endpoint, 'resource'>): string => {
378383
if (resource === 'action_attempt') {
379-
return `
380-
{
381-
waitForActionAttempt?: boolean | Partial<ResolveActionAttemptOptions>
382-
}
383-
`
384+
return "Pick<SeamHttpRequestOptions, 'waitForActionAttempt'>"
384385
}
385386
return 'never'
386387
}
@@ -394,7 +395,7 @@ const renderSubresourceMethod = (
394395
)}${pascalCase(subresource)} {
395396
return SeamHttp${pascalCase(namespace)}${pascalCase(
396397
subresource,
397-
)}.fromClient(this.client)
398+
)}.fromClient(this.client, this.defaults)
398399
}
399400
`
400401

src/lib/seam/connect/client.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ export type Client = AxiosInstance
1212
export interface ClientOptions {
1313
axiosOptions?: AxiosRequestConfig
1414
axiosRetryOptions?: AxiosRetryConfig
15-
client?: Client
1615
}
1716

1817
type AxiosRetryConfig = Parameters<AxiosRetry>[1]
1918

2019
export const createClient = (options: ClientOptions): AxiosInstance => {
21-
if (options.client != null) return options.client
22-
2320
const client = axios.create({
2421
paramsSerializer,
2522
...options.axiosOptions,

src/lib/seam/connect/options.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type { Client, ClientOptions } from './client.js'
2+
import { isSeamHttpRequestOption } from './parse-options.js'
3+
import type { ResolveActionAttemptOptions } from './resolve-action-attempt.js'
24

35
export type SeamHttpMultiWorkspaceOptions =
46
| SeamHttpMultiWorkspaceOptionsWithClient
@@ -13,16 +15,21 @@ export type SeamHttpOptions =
1315
| SeamHttpOptionsWithConsoleSessionToken
1416
| SeamHttpOptionsWithPersonalAccessToken
1517

16-
interface SeamHttpCommonOptions extends ClientOptions {
18+
interface SeamHttpCommonOptions extends ClientOptions, SeamHttpRequestOptions {
1719
endpoint?: string
1820
}
1921

22+
export interface SeamHttpRequestOptions {
23+
waitForActionAttempt?: boolean | ResolveActionAttemptOptions
24+
}
25+
2026
export interface SeamHttpFromPublishableKeyOptions
2127
extends SeamHttpCommonOptions {}
2228

2329
export interface SeamHttpOptionsFromEnv extends SeamHttpCommonOptions {}
2430

25-
export interface SeamHttpMultiWorkspaceOptionsWithClient {
31+
export interface SeamHttpMultiWorkspaceOptionsWithClient
32+
extends SeamHttpRequestOptions {
2633
client: Client
2734
}
2835

@@ -31,7 +38,7 @@ export const isSeamHttpMultiWorkspaceOptionsWithClient = (
3138
): options is SeamHttpMultiWorkspaceOptionsWithClient =>
3239
isSeamHttpOptionsWithClient(options)
3340

34-
export interface SeamHttpOptionsWithClient {
41+
export interface SeamHttpOptionsWithClient extends SeamHttpRequestOptions {
3542
client: Client
3643
}
3744

@@ -42,7 +49,7 @@ export const isSeamHttpOptionsWithClient = (
4249
if (options.client == null) return false
4350

4451
const keys = Object.keys(options).filter((k) => k !== 'client')
45-
if (keys.length > 0) {
52+
if (keys.filter((k) => !isSeamHttpRequestOption(k)).length > 0) {
4653
throw new SeamHttpInvalidOptionsError(
4754
`The client option cannot be used with any other option, but received: ${keys.join(
4855
', ',

src/lib/seam/connect/parse-options.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import version from 'lib/version.js'
22

33
import { getAuthHeaders } from './auth.js'
4-
import type { ClientOptions } from './client.js'
4+
import type { Client, ClientOptions } from './client.js'
55
import {
66
isSeamHttpMultiWorkspaceOptionsWithClient,
77
isSeamHttpOptionsWithClient,
88
isSeamHttpOptionsWithClientSessionToken,
99
type SeamHttpMultiWorkspaceOptions,
1010
type SeamHttpOptions,
11+
type SeamHttpRequestOptions,
1112
} from './options.js'
1213

1314
const defaultEndpoint = 'https://connect.getseam.com'
@@ -21,15 +22,20 @@ export type Options =
2122
| SeamHttpMultiWorkspaceOptions
2223
| (SeamHttpOptions & { publishableKey?: string })
2324

25+
type ParsedOptions = Required<
26+
(ClientOptions | { client: Client }) & SeamHttpRequestOptions
27+
>
28+
2429
export const parseOptions = (
2530
apiKeyOrOptions: string | Options,
26-
): ClientOptions => {
31+
): ParsedOptions => {
2732
const options = getNormalizedOptions(apiKeyOrOptions)
2833

2934
if (isSeamHttpOptionsWithClient(options)) return options
3035
if (isSeamHttpMultiWorkspaceOptionsWithClient(options)) return options
3136

3237
return {
38+
...options,
3339
axiosOptions: {
3440
baseURL: options.endpoint ?? getEndpointFromEnv() ?? defaultEndpoint,
3541
withCredentials: isSeamHttpOptionsWithClientSessionToken(options),
@@ -48,20 +54,30 @@ export const parseOptions = (
4854

4955
const getNormalizedOptions = (
5056
apiKeyOrOptions: string | Options,
51-
): SeamHttpOptions => {
57+
): SeamHttpOptions & Required<SeamHttpRequestOptions> => {
5258
const options =
5359
typeof apiKeyOrOptions === 'string'
5460
? { apiKey: apiKeyOrOptions }
5561
: apiKeyOrOptions
5662

57-
if (isSeamHttpOptionsWithClient(options)) return options
63+
const requestOptions = {
64+
waitForActionAttempt: options.waitForActionAttempt ?? false,
65+
}
66+
67+
if (isSeamHttpOptionsWithClient(options)) {
68+
return {
69+
...options,
70+
...requestOptions,
71+
}
72+
}
5873

5974
const apiKey =
6075
'apiKey' in options ? options.apiKey : getApiKeyFromEnv(options)
6176

6277
return {
6378
...options,
6479
...(apiKey != null ? { apiKey } : {}),
80+
...requestOptions,
6581
}
6682
}
6783

@@ -80,3 +96,26 @@ const getEndpointFromEnv = (): string | null | undefined => {
8096
globalThis.process?.env?.SEAM_API_URL
8197
)
8298
}
99+
100+
export const limitToSeamHttpRequestOptions = (
101+
options: Required<SeamHttpRequestOptions>,
102+
): Required<SeamHttpRequestOptions> => {
103+
return Object.keys(options)
104+
.filter(isSeamHttpRequestOption)
105+
.reduce(
106+
(obj, key) => ({
107+
...obj,
108+
[key]: options[key],
109+
}),
110+
{},
111+
) as Required<SeamHttpRequestOptions>
112+
}
113+
114+
export const isSeamHttpRequestOption = (
115+
key: string,
116+
): key is keyof SeamHttpRequestOptions => {
117+
const keys: Record<keyof SeamHttpRequestOptions, true> = {
118+
waitForActionAttempt: true,
119+
}
120+
return Object.keys(keys).includes(key)
121+
}

src/lib/seam/connect/routes/access-codes-unmanaged.ts

Lines changed: 14 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/seam/connect/routes/access-codes.ts

Lines changed: 15 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/seam/connect/routes/acs-access-groups.ts

Lines changed: 14 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)