Skip to content
This repository was archived by the owner on Nov 15, 2024. It is now read-only.

Commit 3f966e5

Browse files
authored
feat: Merge pull request #33 from seamapi/feat-login-flow
2 parents 97cf64d + 51e6bff commit 3f966e5

20 files changed

+348
-163
lines changed

docs/classes/Seam.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ ___
9595

9696
### client
9797

98-
`Private` **client**: `AxiosInstance`
98+
**client**: `AxiosInstance`
9999

100100
#### Defined in
101101

docs/classes/SeamWebhook.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Create a new instance of SeamWebhook.
5050

5151
### verify
5252

53-
**verify**(`payload`, `headers`): [`SeamEvent`](../modules.md#seamevent)
53+
**verify**(`payload`, `headers`): [`SeamWebhookEvent`](../modules.md#seamwebhookevent)
5454

5555
Verify a payload received from a webhook and return the typed event.
5656

@@ -63,7 +63,7 @@ Verify a payload received from a webhook and return the typed event.
6363

6464
#### Returns
6565

66-
[`SeamEvent`](../modules.md#seamevent)
66+
[`SeamWebhookEvent`](../modules.md#seamwebhookevent)
6767

6868
event
6969

docs/interfaces/CommonDeviceEvent.md

Lines changed: 0 additions & 37 deletions
This file was deleted.

docs/modules.md

Lines changed: 4 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
- [ActionAttemptGetResponse](interfaces/ActionAttemptGetResponse.md)
3333
- [ActionAttemptResultTypeMap](interfaces/ActionAttemptResultTypeMap.md)
3434
- [ActionAttemptWithError](interfaces/ActionAttemptWithError.md)
35-
- [CommonDeviceEvent](interfaces/CommonDeviceEvent.md)
3635
- [ConnectWebview](interfaces/ConnectWebview.md)
3736
- [ConnectWebviewCreateRequest](interfaces/ConnectWebviewCreateRequest.md)
3837
- [ConnectWebviewCreateResponse](interfaces/ConnectWebviewCreateResponse.md)
@@ -69,18 +68,12 @@
6968
- [ActionType](modules.md#actiontype)
7069
- [AnyDevice](modules.md#anydevice)
7170
- [CommonDeviceProperties](modules.md#commondeviceproperties)
72-
- [CreateAccessCodeEvent](modules.md#createaccesscodeevent)
73-
- [DeviceConnectedEvent](modules.md#deviceconnectedevent)
74-
- [DeviceDisconnectEvent](modules.md#devicedisconnectevent)
75-
- [DeviceLowBatteryEvent](modules.md#devicelowbatteryevent)
76-
- [DeviceTamperEvent](modules.md#devicetamperevent)
7771
- [DeviceType](modules.md#devicetype)
7872
- [DeviceUpdateRequest](modules.md#deviceupdaterequest)
7973
- [LockDevice](modules.md#lockdevice)
8074
- [LockDeviceType](modules.md#lockdevicetype)
81-
- [NoiseDetectedEvent](modules.md#noisedetectedevent)
8275
- [NoiseDetectionDeviceType](modules.md#noisedetectiondevicetype)
83-
- [SeamEvent](modules.md#seamevent)
76+
- [SeamWebhookEvent](modules.md#seamwebhookevent)
8477
- [SuccessfulAPIResponse](modules.md#successfulapiresponse)
8578

8679
### Functions
@@ -201,56 +194,6 @@ ___
201194

202195
___
203196

204-
### CreateAccessCodeEvent
205-
206-
Ƭ **CreateAccessCodeEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"access_codes.created"``, { `access_code_id`: `string` }\>
207-
208-
#### Defined in
209-
210-
[src/types/webhook-events.ts:21](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L21)
211-
212-
___
213-
214-
### DeviceConnectedEvent
215-
216-
Ƭ **DeviceConnectedEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"device.connected"``\>
217-
218-
#### Defined in
219-
220-
[src/types/webhook-events.ts:14](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L14)
221-
222-
___
223-
224-
### DeviceDisconnectEvent
225-
226-
Ƭ **DeviceDisconnectEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"devices.disconnected"``\>
227-
228-
#### Defined in
229-
230-
[src/types/webhook-events.ts:15](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L15)
231-
232-
___
233-
234-
### DeviceLowBatteryEvent
235-
236-
Ƭ **DeviceLowBatteryEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"devices.triggered_low_battery"``\>
237-
238-
#### Defined in
239-
240-
[src/types/webhook-events.ts:17](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L17)
241-
242-
___
243-
244-
### DeviceTamperEvent
245-
246-
Ƭ **DeviceTamperEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"devices.tampered"``\>
247-
248-
#### Defined in
249-
250-
[src/types/webhook-events.ts:16](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L16)
251-
252-
___
253-
254197
### DeviceType
255198

256199
Ƭ **DeviceType**: [`LockDeviceType`](modules.md#lockdevicetype) \| [`NoiseDetectionDeviceType`](modules.md#noisedetectiondevicetype)
@@ -300,16 +243,6 @@ ___
300243

301244
___
302245

303-
### NoiseDetectedEvent
304-
305-
Ƭ **NoiseDetectedEvent**: [`CommonDeviceEvent`](interfaces/CommonDeviceEvent.md)<``"noise_thresholds.detected_noise"``\>
306-
307-
#### Defined in
308-
309-
[src/types/webhook-events.ts:29](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L29)
310-
311-
___
312-
313246
### NoiseDetectionDeviceType
314247

315248
Ƭ **NoiseDetectionDeviceType**: ``"noiseaware_activity_zone"``
@@ -320,13 +253,13 @@ ___
320253

321254
___
322255

323-
### SeamEvent
256+
### SeamWebhookEvent
324257

325-
Ƭ **SeamEvent**: [`DeviceConnectedEvent`](modules.md#deviceconnectedevent) \| [`DeviceDisconnectEvent`](modules.md#devicedisconnectevent) \| [`DeviceTamperEvent`](modules.md#devicetamperevent) \| [`DeviceLowBatteryEvent`](modules.md#devicelowbatteryevent) \| [`CreateAccessCodeEvent`](modules.md#createaccesscodeevent) \| [`NoiseDetectedEvent`](modules.md#noisedetectedevent)
258+
Ƭ **SeamWebhookEvent**: `Distribute`<`SeamEvent`[``"event_type"``]\>
326259

327260
#### Defined in
328261

329-
[src/types/webhook-events.ts:32](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L32)
262+
[src/types/webhook-events.ts:10](https://github.com/seamapi/seamapi-javascript/blob/main/src/types/webhook-events.ts#L10)
330263

331264
___
332265

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"node-inspect-extracted": "1.1.0",
4343
"ora": "5.4.1",
4444
"p-retry": "4.6.1",
45+
"prompts": "2.4.2",
4546
"svix": "0.54.2",
4647
"typed-emitter": "2.1.0",
4748
"yargs": "17.3.1"
@@ -56,6 +57,7 @@
5657
"@types/lodash": "^4.14.179",
5758
"@types/ms": "0.7.31",
5859
"@types/node": "17.0.10",
60+
"@types/prompts": "2.0.14",
5961
"@types/uuid": "8.3.4",
6062
"@types/yargs": "17.0.8",
6163
"ajv": "8.9.0",
@@ -76,6 +78,7 @@
7678
"pkg": "5.5.2",
7779
"playwright": "1.19.2",
7880
"prettier": "2.5.1",
81+
"seamapi-types": "1.1.0",
7982
"testcontainers": "8.4.0",
8083
"ts-json-schema-generator": "0.98.0",
8184
"tsup": "5.11.11",

src/cli/commands/connect-webviews.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CommandModule } from "yargs"
22
import { Provider } from "../../types/models"
3+
import completeInteractiveLogin from "../lib/interactive-login/complete-interactive-login"
34
import executeCommand from "../lib/execute-command"
45
import { GlobalOptions } from "../lib/global-options"
56

@@ -32,6 +33,20 @@ const command: CommandModule<GlobalOptions> = {
3233
await executeCommand("connectWebviews.get", [argv.id], argv)
3334
}
3435
)
36+
.command(
37+
"login <id>",
38+
"login to a connect webview",
39+
(yargs) => {
40+
return yargs.positional("id", {
41+
describe: "the connect webview ID",
42+
demandOption: true,
43+
type: "string",
44+
})
45+
},
46+
async (argv) => {
47+
await completeInteractiveLogin(argv.id, argv)
48+
}
49+
)
3550
.command(
3651
"create",
3752
"create a connect webview",
@@ -44,6 +59,10 @@ const command: CommandModule<GlobalOptions> = {
4459
choices: Object.values(Provider),
4560
alias: "ap",
4661
})
62+
.option("login", {
63+
describe: "start interactive login flow after creating",
64+
type: "boolean",
65+
})
4766
.check((argv) => {
4867
if (argv["accepted-providers"].length === 0) {
4968
throw new Error(
@@ -54,7 +73,7 @@ const command: CommandModule<GlobalOptions> = {
5473
})
5574
},
5675
async (argv) => {
57-
await executeCommand(
76+
const { connect_webview_id } = await executeCommand(
5877
"connectWebviews.create",
5978
[
6079
{
@@ -63,6 +82,10 @@ const command: CommandModule<GlobalOptions> = {
6382
],
6483
argv
6584
)
85+
86+
if (argv.login) {
87+
await completeInteractiveLogin(connect_webview_id, argv)
88+
}
6689
}
6790
)
6891
},

src/cli/lib/execute-command.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { paramCase } from "change-case"
44
import Seam, { SeamAPIError } from "../.."
55
import { GlobalOptions } from "./global-options"
66
import _ from "lodash"
7+
import getClientFromArgs from "./get-client-from-args"
78

89
type ParametersByPath<Path extends string> = Parameters<
910
Exclude<Get<Seam, Path>, Seam>
@@ -33,16 +34,7 @@ const executeCommand = async <MethodPath extends string>(
3334
.start()
3435
}
3536

36-
const seam = new Seam(
37-
_.omitBy(
38-
{
39-
apiKey: executeArgs["api-key"],
40-
endpoint: executeArgs["endpoint"],
41-
workspaceId: executeArgs["workspace-id"],
42-
},
43-
_.isUndefined
44-
)
45-
)
37+
const seam = getClientFromArgs(executeArgs)
4638

4739
let method: any = seam
4840
for (const path of methodName.split(".")) {
@@ -62,6 +54,7 @@ const executeCommand = async <MethodPath extends string>(
6254
}
6355

6456
process.stdout.write("\n")
57+
return result
6558
} catch (error) {
6659
let message = "Unknown error"
6760
if (error instanceof SeamAPIError) {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import _ from "lodash"
2+
import { Seam } from "../.."
3+
import { GlobalOptions } from "./global-options"
4+
5+
const getClientFromArgs = (options: GlobalOptions) => {
6+
return new Seam(
7+
_.omitBy(
8+
{
9+
apiKey: options["api-key"],
10+
endpoint: options["endpoint"],
11+
workspaceId: options["workspace-id"],
12+
},
13+
_.isUndefined
14+
)
15+
)
16+
}
17+
18+
export default getClientFromArgs
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type ora from "ora"
2+
import getClientFromArgs from "../get-client-from-args"
3+
import { GlobalOptions } from "../global-options"
4+
import panes from "./panes"
5+
import { formatErrorMsg } from "./utils"
6+
7+
const completeInteractiveLogin = async (
8+
connectWebviewId: string,
9+
args: GlobalOptions
10+
) => {
11+
const { client } = getClientFromArgs(args)
12+
13+
const displaySpinner = typeof window === "undefined" && !args.quiet
14+
let spinner: ora.Ora | undefined
15+
if (displaySpinner) {
16+
// Dynamic import so we don't bundle this for the browser
17+
const ora = await import("ora")
18+
19+
spinner = ora.default("Logging in...")
20+
}
21+
22+
let submit_args: any
23+
while (true) {
24+
console.clear()
25+
26+
try {
27+
spinner?.start("Loading...")
28+
const { data } = await client.post(
29+
"/internal/connect_webviews/login/next",
30+
{
31+
connect_webview_id: connectWebviewId,
32+
submit_args,
33+
}
34+
)
35+
spinner?.stop()
36+
37+
const currentPane = data.pane
38+
39+
if (currentPane.name === "finished_pane") {
40+
if (currentPane.render_props.error_msg) {
41+
throw new Error(currentPane.render_props.error_msg)
42+
}
43+
44+
break
45+
}
46+
47+
const handler = panes.find((p) => p.name === currentPane.name)
48+
if (!handler) {
49+
throw new Error(`Unknown pane ${currentPane.name}`)
50+
}
51+
52+
if (currentPane.render_props.error_msg) {
53+
console.error(formatErrorMsg(currentPane.render_props.error_msg))
54+
}
55+
56+
submit_args = await handler.getInput(currentPane.render_props)
57+
} catch (error) {
58+
if (spinner) {
59+
spinner.fail((error as Error).message)
60+
} else {
61+
console.error(error)
62+
}
63+
64+
process.exit(1)
65+
}
66+
}
67+
68+
spinner?.succeed("🎉 login successful!")
69+
}
70+
71+
export default completeInteractiveLogin

0 commit comments

Comments
 (0)