vector-bridge 0.0.1__py3-none-any.whl

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 (76) hide show
  1. vector_bridge/__init__.py +489 -0
  2. vector_bridge/async_io/__init__.py +0 -0
  3. vector_bridge/async_io/admin/__init__.py +20 -0
  4. vector_bridge/async_io/admin/api_keys.py +87 -0
  5. vector_bridge/async_io/admin/integrations.py +347 -0
  6. vector_bridge/async_io/admin/organization.py +26 -0
  7. vector_bridge/async_io/admin/security_groups.py +128 -0
  8. vector_bridge/async_io/admin/settings.py +21 -0
  9. vector_bridge/async_io/admin/vector_db/__init__.py +12 -0
  10. vector_bridge/async_io/admin/vector_db/changeset.py +372 -0
  11. vector_bridge/async_io/admin/vector_db/state.py +240 -0
  12. vector_bridge/async_io/client/__init__.py +0 -0
  13. vector_bridge/async_io/client/ai_knowledge/__init__.py +12 -0
  14. vector_bridge/async_io/client/ai_knowledge/file_storage.py +671 -0
  15. vector_bridge/async_io/client/logs.py +51 -0
  16. vector_bridge/async_io/client/query.py +118 -0
  17. vector_bridge/async_io/client/usage.py +49 -0
  18. vector_bridge/async_io/client/user.py +224 -0
  19. vector_bridge/async_io/client/workflows.py +650 -0
  20. vector_bridge/schema/__init__.py +0 -0
  21. vector_bridge/schema/ai_knowledge/__init__.py +37 -0
  22. vector_bridge/schema/ai_knowledge/filesystem.py +720 -0
  23. vector_bridge/schema/api_keys.py +38 -0
  24. vector_bridge/schema/error.py +13 -0
  25. vector_bridge/schema/errors/__init__.py +0 -0
  26. vector_bridge/schema/errors/ai_knowledge.py +151 -0
  27. vector_bridge/schema/errors/api_keys.py +43 -0
  28. vector_bridge/schema/errors/base.py +31 -0
  29. vector_bridge/schema/errors/integrations.py +109 -0
  30. vector_bridge/schema/errors/logs.py +49 -0
  31. vector_bridge/schema/errors/message.py +61 -0
  32. vector_bridge/schema/errors/organization.py +73 -0
  33. vector_bridge/schema/errors/queries.py +43 -0
  34. vector_bridge/schema/errors/security_groups.py +85 -0
  35. vector_bridge/schema/errors/settings.py +9 -0
  36. vector_bridge/schema/errors/usage.py +61 -0
  37. vector_bridge/schema/errors/user.py +57 -0
  38. vector_bridge/schema/errors/vectordb_state_changeset.py +195 -0
  39. vector_bridge/schema/errors/workflows.py +49 -0
  40. vector_bridge/schema/helpers/__init__.py +0 -0
  41. vector_bridge/schema/helpers/enums.py +318 -0
  42. vector_bridge/schema/helpers/weaviate_schema.py +158 -0
  43. vector_bridge/schema/integrations.py +54 -0
  44. vector_bridge/schema/logs.py +28 -0
  45. vector_bridge/schema/messages.py +53 -0
  46. vector_bridge/schema/organization.py +24 -0
  47. vector_bridge/schema/queries.py +43 -0
  48. vector_bridge/schema/security_group.py +188 -0
  49. vector_bridge/schema/settings.py +29 -0
  50. vector_bridge/schema/usage.py +29 -0
  51. vector_bridge/schema/user.py +154 -0
  52. vector_bridge/schema/user_integrations.py +44 -0
  53. vector_bridge/schema/weaviate_schema.py +60 -0
  54. vector_bridge/schema/workflows.py +177 -0
  55. vector_bridge/sync_io/__init__.py +0 -0
  56. vector_bridge/sync_io/admin/__init__.py +20 -0
  57. vector_bridge/sync_io/admin/integrations.py +305 -0
  58. vector_bridge/sync_io/admin/organization.py +23 -0
  59. vector_bridge/sync_io/admin/security_groups.py +105 -0
  60. vector_bridge/sync_io/admin/settings.py +19 -0
  61. vector_bridge/sync_io/admin/vector_db/__init__.py +12 -0
  62. vector_bridge/sync_io/admin/vector_db/changeset.py +336 -0
  63. vector_bridge/sync_io/admin/vector_db/state.py +200 -0
  64. vector_bridge/sync_io/client/__init__.py +0 -0
  65. vector_bridge/sync_io/client/ai_knowledge/__init__.py +10 -0
  66. vector_bridge/sync_io/client/ai_knowledge/file_storage.py +613 -0
  67. vector_bridge/sync_io/client/api_keys.py +75 -0
  68. vector_bridge/sync_io/client/logs.py +48 -0
  69. vector_bridge/sync_io/client/query.py +107 -0
  70. vector_bridge/sync_io/client/usage.py +46 -0
  71. vector_bridge/sync_io/client/user.py +191 -0
  72. vector_bridge/sync_io/client/workflows.py +573 -0
  73. vector_bridge/utils.py +35 -0
  74. vector_bridge-0.0.1.dist-info/METADATA +468 -0
  75. vector_bridge-0.0.1.dist-info/RECORD +76 -0
  76. vector_bridge-0.0.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,347 @@
1
+ from typing import Any
2
+
3
+ from vector_bridge import AsyncVectorBridgeClient
4
+ from vector_bridge.schema.errors.integrations import raise_for_integration_detail
5
+ from vector_bridge.schema.helpers.enums import WeaviateKey
6
+ from vector_bridge.schema.integrations import Integration, IntegrationCreate
7
+ from vector_bridge.schema.user_integrations import UserIntegrationList
8
+
9
+
10
+ class AsyncIntegrationsAdmin:
11
+ """Async admin client for integrations management endpoints."""
12
+
13
+ def __init__(self, client: AsyncVectorBridgeClient):
14
+ self.client = client
15
+
16
+ async def get_integrations_list(self) -> list[Integration]:
17
+ """
18
+ Get a list of all integrations.
19
+
20
+ Returns:
21
+ List of integration objects
22
+ """
23
+ await self.client._ensure_session()
24
+
25
+ url = f"{self.client.base_url}/v1/admin/integrations"
26
+ headers = self.client._get_auth_headers()
27
+
28
+ async with self.client.session.get(url, headers=headers) as response:
29
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
30
+ return [Integration.model_validate(item) for item in data]
31
+
32
+ async def get_integration_by_id(self, integration_id: str) -> Integration | None:
33
+ """
34
+ Get integration by ID.
35
+
36
+ Args:
37
+ integration_id: The integration ID
38
+
39
+ Returns:
40
+ Integration object
41
+ """
42
+ await self.client._ensure_session()
43
+
44
+ url = f"{self.client.base_url}/v1/admin/integration/id/{integration_id}"
45
+ headers = self.client._get_auth_headers()
46
+
47
+ async with self.client.session.get(url, headers=headers) as response:
48
+ if response.status in [403, 404]:
49
+ return None
50
+
51
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
52
+ return Integration.model_validate(data)
53
+
54
+ async def get_integration_by_name(self, integration_name: str | None = None) -> Integration | None:
55
+ """
56
+ Get integration by name.
57
+
58
+ Args:
59
+ integration_name: The integration name
60
+
61
+ Returns:
62
+ Integration object
63
+ """
64
+ if integration_name is None:
65
+ integration_name = self.client.integration_name
66
+
67
+ await self.client._ensure_session()
68
+
69
+ url = f"{self.client.base_url}/v1/admin/integration/name/{integration_name}"
70
+ headers = self.client._get_auth_headers()
71
+
72
+ async with self.client.session.get(url, headers=headers) as response:
73
+ if response.status in [403, 404]:
74
+ return None
75
+
76
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
77
+ return Integration.model_validate(data)
78
+
79
+ async def add_integration(self, integration_data: IntegrationCreate) -> Integration:
80
+ """
81
+ Add a new integration.
82
+
83
+ Args:
84
+ integration_data: Integration details
85
+
86
+ Returns:
87
+ Created integration object
88
+ """
89
+ await self.client._ensure_session()
90
+
91
+ url = f"{self.client.base_url}/v1/admin/integration/add"
92
+ headers = self.client._get_auth_headers()
93
+
94
+ async with self.client.session.post(url, headers=headers, json=integration_data.model_dump()) as response:
95
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
96
+ return Integration.model_validate(data)
97
+
98
+ async def delete_integration(self, integration_name: str | None = None) -> list[Integration]:
99
+ """
100
+ Delete an integration.
101
+
102
+ Args:
103
+ integration_name: The name of the integration to delete
104
+
105
+ Returns:
106
+ List of remaining integrations
107
+ """
108
+ if integration_name is None:
109
+ integration_name = self.client.integration_name
110
+
111
+ await self.client._ensure_session()
112
+
113
+ url = f"{self.client.base_url}/v1/admin/integration/delete"
114
+ params = {"integration_name": integration_name}
115
+ headers = self.client._get_auth_headers()
116
+
117
+ async with self.client.session.delete(url, headers=headers, params=params) as response:
118
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
119
+ return [Integration.model_validate(item) for item in data]
120
+
121
+ async def update_integration_weaviate(
122
+ self,
123
+ weaviate_key: WeaviateKey,
124
+ weaviate_value: str,
125
+ integration_name: str | None = None,
126
+ ) -> Integration:
127
+ """
128
+ Update Integration weaviate settings.
129
+
130
+ Args:
131
+ weaviate_key: The Weaviate key
132
+ weaviate_value: The Weaviate value
133
+ integration_name: The name of the Integration
134
+
135
+ Returns:
136
+ Updated integration object
137
+ """
138
+ if integration_name is None:
139
+ integration_name = self.client.integration_name
140
+
141
+ await self.client._ensure_session()
142
+
143
+ url = f"{self.client.base_url}/v1/admin/integration/edit/weaviate"
144
+ params = {
145
+ "integration_name": integration_name,
146
+ "weaviate_key": weaviate_key.value,
147
+ "weaviate_value": weaviate_value,
148
+ }
149
+ headers = self.client._get_auth_headers()
150
+
151
+ async with self.client.session.patch(url, headers=headers, params=params) as response:
152
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
153
+ return Integration.model_validate(data)
154
+
155
+ async def update_integration_published(self, published: bool, integration_name: str | None = None) -> Integration:
156
+ """
157
+ Update Integration published setting.
158
+
159
+ Args:
160
+ published: The published value
161
+ integration_name: The name of the Integration
162
+
163
+ Returns:
164
+ Updated integration object
165
+ """
166
+ if integration_name is None:
167
+ integration_name = self.client.integration_name
168
+
169
+ await self.client._ensure_session()
170
+
171
+ url = f"{self.client.base_url}/v1/admin/integration/edit/published"
172
+ params = {
173
+ "integration_name": integration_name,
174
+ "published": str(published).lower(),
175
+ }
176
+ headers = self.client._get_auth_headers()
177
+
178
+ async with self.client.session.patch(url, headers=headers, params=params) as response:
179
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
180
+ return Integration.model_validate(data)
181
+
182
+ async def update_environment_variables(
183
+ self, env_variables: dict[str, str], integration_name: str | None = None
184
+ ) -> Integration:
185
+ """
186
+ Update Integration environment variables.
187
+
188
+ Args:
189
+ env_variables: The Environment Variables
190
+ integration_name: The name of the Integration
191
+
192
+ Returns:
193
+ Updated integration object
194
+ """
195
+ if integration_name is None:
196
+ integration_name = self.client.integration_name
197
+
198
+ await self.client._ensure_session()
199
+
200
+ url = f"{self.client.base_url}/v1/admin/integration/edit/environment-variables"
201
+ params = {"integration_name": integration_name}
202
+ headers = self.client._get_auth_headers()
203
+
204
+ async with self.client.session.patch(url, headers=headers, params=params, json=env_variables) as response:
205
+ data = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
206
+ return Integration.model_validate(data)
207
+
208
+ async def add_user_to_integration(
209
+ self,
210
+ user_id: str,
211
+ security_group_id: str,
212
+ integration_name: str | None = None,
213
+ ) -> UserIntegrationList:
214
+ """
215
+ Add user to the Integration by id.
216
+
217
+ Args:
218
+ integration_name: The integration name
219
+ user_id: The user id
220
+ security_group_id: The Security Group
221
+
222
+ Returns:
223
+ Users list
224
+ """
225
+ if integration_name is None:
226
+ integration_name = self.client.integration_name
227
+
228
+ await self.client._ensure_session()
229
+
230
+ url = f"{self.client.base_url}/v1/admin/integration/name/{integration_name}/add-user/{user_id}"
231
+ params = {"security_group_id": security_group_id}
232
+ headers = self.client._get_auth_headers()
233
+
234
+ async with self.client.session.post(url, headers=headers, params=params) as response:
235
+ result = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
236
+ return UserIntegrationList.model_validate(result)
237
+
238
+ async def remove_user_from_integration(
239
+ self,
240
+ user_id: str,
241
+ integration_name: str | None = None,
242
+ ) -> UserIntegrationList:
243
+ """
244
+ Remove user from Integration.
245
+
246
+ Args:
247
+ integration_name: The integration name
248
+ user_id: The user id
249
+
250
+ Returns:
251
+ Users list
252
+ """
253
+ if integration_name is None:
254
+ integration_name = self.client.integration_name
255
+
256
+ await self.client._ensure_session()
257
+
258
+ url = f"{self.client.base_url}/v1/admin/integration/name/{integration_name}/remove-user/{user_id}"
259
+ headers = self.client._get_auth_headers()
260
+
261
+ async with self.client.session.post(url, headers=headers) as response:
262
+ result = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
263
+ return UserIntegrationList.model_validate(result)
264
+
265
+ async def update_users_security_group(
266
+ self,
267
+ user_id: str,
268
+ security_group_id: str,
269
+ integration_name: str | None = None,
270
+ ) -> UserIntegrationList:
271
+ """
272
+ Update user's security group in an integration.
273
+
274
+ Args:
275
+ integration_name: The integration name
276
+ user_id: The user id
277
+ security_group_id: The Security Group
278
+
279
+ Returns:
280
+ Users list
281
+ """
282
+ if integration_name is None:
283
+ integration_name = self.client.integration_name
284
+
285
+ await self.client._ensure_session()
286
+
287
+ url = (
288
+ f"{self.client.base_url}/v1/admin/integration/name/{integration_name}/update-users-security-group/{user_id}"
289
+ )
290
+ params = {"security_group_id": security_group_id}
291
+ headers = self.client._get_auth_headers()
292
+
293
+ async with self.client.session.post(url, headers=headers, params=params) as response:
294
+ result = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
295
+ return UserIntegrationList.model_validate(result)
296
+
297
+ async def get_users_from_integration(
298
+ self,
299
+ limit: int = 25,
300
+ integration_name: str | None = None,
301
+ last_evaluated_key: str | None = None,
302
+ ) -> UserIntegrationList:
303
+ """
304
+ Get users in an Integration by id.
305
+
306
+ Args:
307
+ integration_name: The integration name
308
+ limit: Number of users to return
309
+ last_evaluated_key: Last evaluated key for pagination
310
+
311
+ Returns:
312
+ Users list
313
+ """
314
+ if integration_name is None:
315
+ integration_name = self.client.integration_name
316
+
317
+ await self.client._ensure_session()
318
+
319
+ url = f"{self.client.base_url}/v1/admin/integration/name/{integration_name}/users"
320
+ params: dict[str, Any] = {"limit": limit}
321
+ if last_evaluated_key:
322
+ params["last_evaluated_key"] = last_evaluated_key
323
+
324
+ headers = self.client._get_auth_headers()
325
+
326
+ async with self.client.session.get(url, headers=headers, params=params) as response:
327
+ result = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
328
+ return UserIntegrationList.model_validate(result)
329
+
330
+ async def get_integration_names_of_a_user(self, user_id: str) -> list[str]:
331
+ """
332
+ Get integration names that a user belongs to.
333
+
334
+ Args:
335
+ user_id: The user id
336
+
337
+ Returns:
338
+ List of integration names
339
+ """
340
+ await self.client._ensure_session()
341
+
342
+ url = f"{self.client.base_url}/v1/admin/integration_names/user/id/{user_id}"
343
+ headers = self.client._get_auth_headers()
344
+
345
+ async with self.client.session.get(url, headers=headers) as response:
346
+ result = await self.client._handle_response(response=response, error_callable=raise_for_integration_detail)
347
+ return result
@@ -0,0 +1,26 @@
1
+ from vector_bridge import AsyncVectorBridgeClient
2
+ from vector_bridge.schema.errors.organization import raise_for_organization_detail
3
+ from vector_bridge.schema.organization import Organization
4
+
5
+
6
+ class AsyncOrganizationAdmin:
7
+ """Async admin client for organization management endpoints."""
8
+
9
+ def __init__(self, client: AsyncVectorBridgeClient):
10
+ self.client = client
11
+
12
+ async def get_my_organization(self) -> Organization:
13
+ """
14
+ Retrieve detailed information about the organization linked to the currently authenticated user's account.
15
+
16
+ Returns:
17
+ Organization details
18
+ """
19
+ await self.client._ensure_session()
20
+
21
+ url = f"{self.client.base_url}/v1/admin/organization/me"
22
+ headers = self.client._get_auth_headers()
23
+
24
+ async with self.client.session.get(url, headers=headers) as response:
25
+ data = await self.client._handle_response(response=response, error_callable=raise_for_organization_detail)
26
+ return Organization.model_validate(data)
@@ -0,0 +1,128 @@
1
+ from vector_bridge import AsyncVectorBridgeClient
2
+ from vector_bridge.schema.errors.security_groups import raise_for_security_group_detail
3
+ from vector_bridge.schema.security_group import (
4
+ PaginatedSecurityGroups,
5
+ SecurityGroup,
6
+ SecurityGroupCreate,
7
+ SecurityGroupUpdate,
8
+ )
9
+
10
+
11
+ class AsyncSecurityGroupsAdmin:
12
+ """Async admin client for security group management endpoints."""
13
+
14
+ def __init__(self, client: AsyncVectorBridgeClient):
15
+ self.client = client
16
+
17
+ async def create_security_group(self, security_group_data: SecurityGroupCreate) -> SecurityGroup:
18
+ """
19
+ Create a new security group.
20
+
21
+ Args:
22
+ organization_id: The ID of the organization
23
+ security_group_data: Details of the security group to create
24
+
25
+ Returns:
26
+ Created security group
27
+ """
28
+ await self.client._ensure_session()
29
+
30
+ url = f"{self.client.base_url}/v1/admin/security-group/create"
31
+ headers = self.client._get_auth_headers()
32
+
33
+ async with self.client.session.post(url, headers=headers, json=security_group_data.model_dump()) as response:
34
+ result = await self.client._handle_response(
35
+ response=response, error_callable=raise_for_security_group_detail
36
+ )
37
+ return SecurityGroup.model_validate(result)
38
+
39
+ async def update_security_group(self, group_id: str, security_group_data: SecurityGroupUpdate) -> SecurityGroup:
40
+ """
41
+ Update an existing security group by ID.
42
+
43
+ Args:
44
+ group_id: The Security Group ID
45
+ security_group_data: Updated details for the security group
46
+
47
+ Returns:
48
+ Updated security group
49
+ """
50
+ await self.client._ensure_session()
51
+
52
+ url = f"{self.client.base_url}/v1/admin/security-group/{group_id}/update"
53
+ headers = self.client._get_auth_headers()
54
+
55
+ async with self.client.session.put(url, headers=headers, json=security_group_data.model_dump()) as response:
56
+ result = await self.client._handle_response(
57
+ response=response, error_callable=raise_for_security_group_detail
58
+ )
59
+ return SecurityGroup.model_validate(result)
60
+
61
+ async def get_security_group(self, group_id: str) -> SecurityGroup | None:
62
+ """
63
+ Retrieve details of a specific security group by ID.
64
+
65
+ Args:
66
+ group_id: The Security Group ID
67
+
68
+ Returns:
69
+ Security group details
70
+ """
71
+ await self.client._ensure_session()
72
+
73
+ url = f"{self.client.base_url}/v1/admin/security-group/{group_id}"
74
+ headers = self.client._get_auth_headers()
75
+
76
+ async with self.client.session.get(url, headers=headers) as response:
77
+ result = await self.client._handle_response(
78
+ response=response, error_callable=raise_for_security_group_detail
79
+ )
80
+ return SecurityGroup.model_validate(result) if result else None
81
+
82
+ async def list_security_groups(
83
+ self,
84
+ limit: int = 10,
85
+ last_evaluated_key: str | None = None,
86
+ sort_by: str = "created_at",
87
+ ) -> PaginatedSecurityGroups:
88
+ """
89
+ Retrieve a paginated list of all security groups for the organization.
90
+
91
+ Args:
92
+ limit: Number of items per page
93
+ last_evaluated_key: Key to continue pagination from
94
+ sort_by: The sort field
95
+
96
+ Returns:
97
+ PaginatedSecurityGroups with security groups and pagination information
98
+ """
99
+ await self.client._ensure_session()
100
+
101
+ url = f"{self.client.base_url}/v1/admin/security-groups"
102
+ params = {"limit": limit, "sort_by": sort_by}
103
+ if last_evaluated_key:
104
+ params["last_evaluated_key"] = last_evaluated_key
105
+
106
+ headers = self.client._get_auth_headers()
107
+
108
+ async with self.client.session.get(url, headers=headers, params=params) as response:
109
+ result = await self.client._handle_response(
110
+ response=response, error_callable=raise_for_security_group_detail
111
+ )
112
+ return PaginatedSecurityGroups.model_validate(result)
113
+
114
+ async def delete_security_group(self, group_id: str) -> None:
115
+ """
116
+ Delete a specific security group by ID.
117
+
118
+ Args:
119
+ group_id: The Security Group ID
120
+ """
121
+ await self.client._ensure_session()
122
+
123
+ url = f"{self.client.base_url}/v1/admin/security-group/{group_id}/delete"
124
+ headers = self.client._get_auth_headers()
125
+
126
+ async with self.client.session.delete(url, headers=headers) as response:
127
+ if response.status != 204:
128
+ await self.client._handle_response(response=response, error_callable=raise_for_security_group_detail)
@@ -0,0 +1,21 @@
1
+ from vector_bridge import AsyncVectorBridgeClient
2
+ from vector_bridge.schema.errors.settings import raise_for_setting_detail
3
+ from vector_bridge.schema.settings import Settings
4
+
5
+
6
+ class AsyncSettingsAdmin:
7
+ """Async admin client for settings endpoints."""
8
+
9
+ def __init__(self, client: AsyncVectorBridgeClient):
10
+ self.client = client
11
+
12
+ async def get_settings(self) -> Settings:
13
+ """Get system settings."""
14
+ await self.client._ensure_session()
15
+
16
+ url = f"{self.client.base_url}/v1/settings"
17
+ headers = self.client._get_auth_headers()
18
+
19
+ async with self.client.session.get(url, headers=headers) as response:
20
+ result = await self.client._handle_response(response=response, error_callable=raise_for_setting_detail)
21
+ return Settings.model_validate(result)
@@ -0,0 +1,12 @@
1
+ from vector_bridge import AsyncVectorBridgeClient
2
+ from vector_bridge.async_io.admin.vector_db.changeset import AsyncVectorDBChangesetAdmin
3
+ from vector_bridge.async_io.admin.vector_db.state import AsyncVectorDBStateAdmin
4
+
5
+
6
+ class AsyncVectorDBAdmin:
7
+ """Async admin client for VectorDB management endpoints."""
8
+
9
+ def __init__(self, client: AsyncVectorBridgeClient):
10
+ self.client = client
11
+ self.changeset = AsyncVectorDBChangesetAdmin(client)
12
+ self.state = AsyncVectorDBStateAdmin(client)