Skip to content

Commit 25353e7

Browse files
mikewuuseambotrazor-x
authored
feat: add bridge_connected_systems/list (#248)
* feat: add bridge_connected_systems/list * ci: Format code * fix noise threshold flaky test * add test * fix noise threshold flaky test * fix: Use Node 20.18 for build (#249) * 1.80.1 * Use Node 20.18 in development * Update Dockerfile to use Node 20.18 * Fix Dockerfile case * Use alpine in Dockerfile * revert from third_party_account_id -> connected_account_id * ci: Generate code * fix missing third_party_account_id --------- Co-authored-by: Seam Bot <[email protected]> Co-authored-by: Evan Sosenko <[email protected]>
1 parent 4e7927f commit 25353e7

File tree

14 files changed

+216
-26
lines changed

14 files changed

+216
-26
lines changed

src/lib/database/schema.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
AcsUser,
99
ActionAttempt,
1010
ApiKey,
11+
Bridge,
1112
BridgeClientSession,
1213
ClientSession,
1314
ConnectedAccount,
@@ -51,6 +52,7 @@ export interface DatabaseState {
5152
connect_webviews: ConnectWebview[]
5253
client_sessions: ClientSession[]
5354
bridge_client_sessions: BridgeClientSession[]
55+
bridges: Bridge[]
5456
connected_accounts: ConnectedAccount[]
5557
devices: Device[]
5658
events: Event[]
@@ -115,6 +117,9 @@ export interface DatabaseMethods {
115117
pairing_code?: string
116118
pairing_code_expires_at?: string
117119
}) => void
120+
addBridge: (
121+
params: Pick<Bridge, "workspace_id" | "bridge_client_session_id">,
122+
) => Bridge
118123
addUserIdentity: (params: {
119124
workspace_id: WorkspaceId
120125
user_identity_id?: string
@@ -167,6 +172,7 @@ export interface DatabaseMethods {
167172
account_type?: string
168173
automatically_manage_new_devices?: boolean
169174
custom_metadata?: ConnectedAccount["custom_metadata"]
175+
bridge_id?: string
170176
}) => ConnectedAccount
171177
updateConnectedAccount: (params: {
172178
connected_account_id: string
@@ -298,7 +304,7 @@ export interface DatabaseMethods {
298304
addAcsSystem: (
299305
params: Pick<
300306
AcsSystem,
301-
"external_type" | "name" | "workspace_id" | "connected_account_ids"
307+
"external_type" | "name" | "workspace_id" | "connected_account_id"
302308
> &
303309
Partial<Pick<AcsSystem, "created_at" | "acs_system_id">>,
304310
) => AcsSystem

src/lib/database/seed.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const seedDatabase = (db: Database): Seed => {
183183
noise_threshold_decibels: 60,
184184
name: "builtin_normal_hours",
185185
starts_daily_at: "00:00:00[America/Los_Angeles]",
186-
ends_daily_at: "23:00:00[America/Los_Angeles]",
186+
ends_daily_at: "23:59:59[America/Los_Angeles]",
187187
})
188188

189189
db.addDevice({
@@ -273,7 +273,7 @@ export const seedDatabase = (db: Database): Seed => {
273273
external_type: "visionline_system",
274274
name: "Fake Visionline System",
275275
workspace_id: seed.seed_workspace_1,
276-
connected_account_ids: [seed.john_connected_account_id],
276+
connected_account_id: seed.john_connected_account_id,
277277
})
278278

279279
const [, short_token = "", long_token = ""] = seed.seam_at1_token.split("_")

src/lib/database/store.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { immer } from "zustand/middleware/immer"
77
import { createStore, type StoreApi } from "zustand/vanilla"
88
import { hoist } from "zustand-hoist"
99

10-
import type { BridgeClientSession, UserSession } from "lib/zod/index.ts"
10+
import type { Bridge, BridgeClientSession, UserSession } from "lib/zod/index.ts"
1111

1212
import {
1313
ACS_ACCESS_GROUP_EXTERNAL_TYPE_TO_DISPLAY_NAME,
@@ -72,6 +72,7 @@ const initializer = immer<Database>((set, get) => ({
7272
simulatedEvents: {},
7373
client_sessions: [],
7474
bridge_client_sessions: [],
75+
bridges: [],
7576
assa_abloy_credential_services: [],
7677
assa_abloy_cards: [],
7778
endpoints: [],
@@ -342,6 +343,24 @@ const initializer = immer<Database>((set, get) => ({
342343
})
343344
},
344345

346+
addBridge(params) {
347+
const bridge_id = get()._getNextId("bid")
348+
349+
const new_bridge: Bridge = {
350+
...params,
351+
bridge_id,
352+
created_at: new Date().toISOString(),
353+
workspace_id: params.workspace_id,
354+
bridge_client_session_id: params.bridge_client_session_id,
355+
}
356+
357+
set({
358+
bridges: [...get().bridges, new_bridge],
359+
})
360+
361+
return new_bridge
362+
},
363+
345364
addUserIdentity(params) {
346365
const user_identity_id = params.user_identity_id ?? get()._getNextId("uid")
347366
const new_user_identity: UserIdentity = {
@@ -557,6 +576,7 @@ const initializer = immer<Database>((set, get) => ({
557576
automatically_manage_new_devices:
558577
params?.automatically_manage_new_devices ?? true,
559578
custom_metadata: params.custom_metadata ?? {},
579+
bridge_id: params.bridge_id ?? null,
560580
}
561581

562582
if (params.provider === "assa_abloy_credential_service") {
@@ -1237,7 +1257,7 @@ const initializer = immer<Database>((set, get) => ({
12371257
name,
12381258
workspace_id,
12391259
created_at,
1240-
connected_account_ids,
1260+
connected_account_id,
12411261
acs_system_id,
12421262
}) {
12431263
const new_acs_system: AcsSystem = {
@@ -1250,7 +1270,7 @@ const initializer = immer<Database>((set, get) => ({
12501270
external_type,
12511271
external_type_display_name:
12521272
ACS_SYSTEM_TYPE_TO_DISPLAY_NAME[external_type],
1253-
connected_account_ids: connected_account_ids ?? [],
1273+
connected_account_id,
12541274
}
12551275

12561276
set({

src/lib/zod/acs/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const acs_system = z.object({
2525
name: z.string(),
2626
created_at: z.string().datetime(),
2727
workspace_id: z.string(),
28-
connected_account_ids: z.array(z.string()),
28+
connected_account_id: z.string(),
2929
})
3030

3131
export type AcsSystem = z.output<typeof acs_system>

src/lib/zod/bridge.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { z } from "zod"
2+
3+
export const bridge = z.object({
4+
bridge_id: z.string().uuid(),
5+
created_at: z.string().datetime(),
6+
workspace_id: z.string().uuid(),
7+
bridge_client_session_id: z.string().uuid(),
8+
})
9+
10+
export type Bridge = z.infer<typeof bridge>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { z } from "zod"
2+
3+
export const bridge_connected_system = z.object({
4+
bridge_id: z.string().uuid(),
5+
bridge_created_at: z.string().datetime(),
6+
connected_account_id: z.string().uuid(),
7+
connected_account_created_at: z.string().datetime(),
8+
acs_system_id: z.string().uuid(),
9+
acs_system_display_name: z.string(),
10+
workspace_id: z.string().uuid(),
11+
workspace_display_name: z.string(),
12+
}).describe(`
13+
---
14+
route_path: /seam/bridge/v1/bridge_connected_systems
15+
undocumented: Seam Bridge Client only.
16+
---
17+
`)
18+
19+
export type BridgeConnectedSystem = z.infer<typeof bridge_connected_system>

src/lib/zod/connected_account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export const connected_account = z.object({
1515
account_type_display_name: z.string(),
1616
automatically_manage_new_devices: z.boolean(),
1717
custom_metadata: custom_metadata.optional(),
18-
1918
assa_abloy_credential_service_id: z.string().optional(),
19+
bridge_id: z.string().nullable(),
2020
})
2121

2222
export type ConnectedAccount = z.infer<typeof connected_account>

src/lib/zod/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ export * from "./access_token.ts"
33
export * from "./acs/index.ts"
44
export * from "./action_attempt.ts"
55
export * from "./api_key.ts"
6+
export * from "./bridge.ts"
67
export * from "./bridge_client_session.ts"
8+
export * from "./bridge_connected_system.ts"
79
export * from "./client_session.ts"
810
export * from "./common.ts"
911
export * from "./connect_webview.ts"

src/pages/api/acs/systems/list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default withRouteSpec({
2424
(acs_system) =>
2525
acs_system.workspace_id === req.auth.workspace_id &&
2626
(connected_account_id == null ||
27-
acs_system.connected_account_ids.includes(connected_account_id)),
27+
acs_system.connected_account_id === connected_account_id),
2828
)
2929

3030
res.status(200).json({
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { z } from "zod"
2+
3+
import { withRouteSpec } from "lib/middleware/index.ts"
4+
5+
import {
6+
bridge_connected_system,
7+
type BridgeConnectedSystem,
8+
} from "lib/zod/bridge_connected_system.ts"
9+
10+
export default withRouteSpec({
11+
description: `
12+
---
13+
title: List Bridge Connected Systems
14+
response_key: bridge_connected_systems
15+
undocumented: Seam Bridge Client only.
16+
---
17+
Returns the bridge connected systems associated with the session token used.
18+
`,
19+
auth: ["bridge_client_session"],
20+
methods: ["GET", "POST"],
21+
jsonResponse: z.object({
22+
bridge_connected_systems: z.array(bridge_connected_system),
23+
}),
24+
} as const)(async (req, res) => {
25+
const { db, auth } = req
26+
27+
const bridges = db.bridges.filter(
28+
(bridge) =>
29+
bridge.bridge_client_session_id ===
30+
auth.bridge_client_session.bridge_client_session_id,
31+
)
32+
33+
const bridge_connected_systems: BridgeConnectedSystem[] = bridges.map(
34+
(bridge) => {
35+
const connected_account = db.connected_accounts.find(
36+
(connected_account) => connected_account.bridge_id === bridge.bridge_id,
37+
)
38+
39+
if (connected_account == null) {
40+
throw new Error("Could not find connected_account for bridge.")
41+
}
42+
43+
const acs_system = db.acs_systems.find(
44+
(acs_system) =>
45+
acs_system.connected_account_id ===
46+
connected_account.connected_account_id,
47+
)
48+
49+
if (acs_system == null) {
50+
throw new Error("Could not find acs_system for third_party_account.")
51+
}
52+
53+
const workspace = db.workspaces.find(
54+
(workspace) => workspace.workspace_id === bridge.workspace_id,
55+
)
56+
57+
if (workspace == null) {
58+
throw new Error("Could not find workspace for bridge.")
59+
}
60+
61+
return {
62+
bridge_id: bridge.bridge_id,
63+
bridge_created_at: bridge.created_at,
64+
connected_account_id: connected_account.connected_account_id,
65+
connected_account_created_at: connected_account.created_at,
66+
acs_system_id: acs_system.acs_system_id,
67+
acs_system_display_name: acs_system.name,
68+
workspace_id: bridge.workspace_id,
69+
workspace_display_name: workspace.name,
70+
}
71+
},
72+
)
73+
74+
res.status(200).json({
75+
bridge_connected_systems,
76+
})
77+
})

0 commit comments

Comments
 (0)