@safercity/sdk 0.0.1
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.
- package/README.md +161 -0
- package/dist/index.cjs +275 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +463 -0
- package/dist/index.d.ts +463 -0
- package/dist/index.js +238 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @safercity/sdk
|
|
2
|
+
|
|
3
|
+
Official SaferCity API client for TypeScript/JavaScript.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @safercity/sdk
|
|
9
|
+
# or
|
|
10
|
+
bun add @safercity/sdk
|
|
11
|
+
# or
|
|
12
|
+
yarn add @safercity/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { createSaferCityClient } from '@safercity/sdk';
|
|
19
|
+
|
|
20
|
+
const client = createSaferCityClient({
|
|
21
|
+
baseUrl: 'https://api.safercity.com',
|
|
22
|
+
token: 'your-jwt-token',
|
|
23
|
+
tenantId: 'your-tenant-id',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Health check
|
|
27
|
+
const { data: health } = await client.health.check();
|
|
28
|
+
console.log('API Status:', health.status);
|
|
29
|
+
|
|
30
|
+
// Get user
|
|
31
|
+
const { data: user } = await client.users.get('user-123');
|
|
32
|
+
console.log('User:', user);
|
|
33
|
+
|
|
34
|
+
// Create panic
|
|
35
|
+
const { data: panic } = await client.panics.create({
|
|
36
|
+
userId: 'user-123',
|
|
37
|
+
latitude: -26.2041,
|
|
38
|
+
longitude: 28.0473,
|
|
39
|
+
});
|
|
40
|
+
console.log('Panic created:', panic.id);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Authentication
|
|
44
|
+
|
|
45
|
+
### JWT Token
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const client = createSaferCityClient({
|
|
49
|
+
baseUrl: 'https://api.safercity.com',
|
|
50
|
+
token: jwtToken, // Your JWT token
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Update token later
|
|
54
|
+
client.setToken(newToken);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### OAuth Token Flow
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const client = createSaferCityClient({
|
|
61
|
+
baseUrl: 'https://api.safercity.com',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Get access token
|
|
65
|
+
const { data: tokens } = await client.oauth.token({
|
|
66
|
+
grant_type: 'client_credentials',
|
|
67
|
+
tenantId: 'your-tenant-id',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Set token on client
|
|
71
|
+
client.setToken(tokens.access_token);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Streaming (SSE)
|
|
75
|
+
|
|
76
|
+
Stream real-time panic updates:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
for await (const event of client.panics.streamUpdates('panic-123')) {
|
|
80
|
+
console.log('Update:', JSON.parse(event.data));
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API Reference
|
|
85
|
+
|
|
86
|
+
### Health
|
|
87
|
+
- `client.health.check()` - Check API status
|
|
88
|
+
|
|
89
|
+
### Authentication
|
|
90
|
+
- `client.auth.whoami()` - Get current auth context
|
|
91
|
+
- `client.oauth.token(body)` - Get access token
|
|
92
|
+
- `client.oauth.refresh(body)` - Refresh token
|
|
93
|
+
- `client.oauth.introspect(body)` - Introspect token
|
|
94
|
+
- `client.oauth.revoke(body)` - Revoke token
|
|
95
|
+
|
|
96
|
+
### Users
|
|
97
|
+
- `client.users.create(body)` - Create user
|
|
98
|
+
- `client.users.list(query?)` - List users
|
|
99
|
+
- `client.users.get(userId)` - Get user by ID
|
|
100
|
+
- `client.users.update(userId, body)` - Update user
|
|
101
|
+
- `client.users.delete(userId)` - Delete user
|
|
102
|
+
|
|
103
|
+
### Panics
|
|
104
|
+
- `client.panics.create(body)` - Create panic
|
|
105
|
+
- `client.panics.get(panicId, query?)` - Get panic
|
|
106
|
+
- `client.panics.list(query?)` - List panics
|
|
107
|
+
- `client.panics.updateLocation(panicId, body)` - Update location
|
|
108
|
+
- `client.panics.cancel(panicId, body)` - Cancel panic
|
|
109
|
+
- `client.panics.streamUpdates(panicId)` - Stream updates (SSE)
|
|
110
|
+
|
|
111
|
+
### Subscriptions
|
|
112
|
+
- `client.subscriptions.listTypes()` - List subscription types
|
|
113
|
+
- `client.subscriptions.create(body)` - Create subscription
|
|
114
|
+
- `client.subscriptions.list(query?)` - List subscriptions
|
|
115
|
+
- `client.subscriptions.stats()` - Get stats
|
|
116
|
+
|
|
117
|
+
### Location Safety
|
|
118
|
+
- `client.locationSafety.check(query)` - Check location safety
|
|
119
|
+
|
|
120
|
+
### Crimes
|
|
121
|
+
- `client.crimes.list(query?)` - List crimes
|
|
122
|
+
- `client.crimes.categories()` - Get crime categories
|
|
123
|
+
- `client.crimes.types()` - Get crime types
|
|
124
|
+
|
|
125
|
+
## Error Handling
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { SaferCityApiError } from '@safercity/sdk';
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
await client.users.get('invalid-id');
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof SaferCityApiError) {
|
|
134
|
+
console.log('API Error:', error.error);
|
|
135
|
+
console.log('Message:', error.message);
|
|
136
|
+
console.log('Status:', error.status);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Custom Fetch
|
|
142
|
+
|
|
143
|
+
For environments with custom fetch requirements:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { createSaferCityClient } from '@safercity/sdk';
|
|
147
|
+
|
|
148
|
+
const client = createSaferCityClient({
|
|
149
|
+
baseUrl: 'https://api.safercity.com',
|
|
150
|
+
fetch: customFetchImplementation,
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Related Packages
|
|
155
|
+
|
|
156
|
+
- `@safercity/sdk-react` - React hooks with TanStack Query
|
|
157
|
+
- `@safercity/sdk-react-native` - React Native support with expo-fetch
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var sdkCore = require('@safercity/sdk-core');
|
|
4
|
+
|
|
5
|
+
function createSaferCityClient(options) {
|
|
6
|
+
const baseClient = new sdkCore.BaseClient(options);
|
|
7
|
+
const streamAdapter = options.streamAdapter ?? sdkCore.createStreamAdapter(options.fetch);
|
|
8
|
+
return {
|
|
9
|
+
/**
|
|
10
|
+
* Access the underlying base client for custom requests
|
|
11
|
+
*/
|
|
12
|
+
_client: baseClient,
|
|
13
|
+
/**
|
|
14
|
+
* Update authentication token
|
|
15
|
+
*/
|
|
16
|
+
setToken: (token) => baseClient.setToken(token),
|
|
17
|
+
/**
|
|
18
|
+
* Update tenant ID
|
|
19
|
+
*/
|
|
20
|
+
setTenantId: (tenantId) => baseClient.setTenantId(tenantId),
|
|
21
|
+
/**
|
|
22
|
+
* Get current configuration
|
|
23
|
+
*/
|
|
24
|
+
getConfig: () => baseClient.getConfig(),
|
|
25
|
+
// ==================
|
|
26
|
+
// Health & System
|
|
27
|
+
// ==================
|
|
28
|
+
health: {
|
|
29
|
+
/**
|
|
30
|
+
* Check API health status
|
|
31
|
+
*/
|
|
32
|
+
check: () => baseClient.get("/health")
|
|
33
|
+
},
|
|
34
|
+
// ==================
|
|
35
|
+
// Authentication
|
|
36
|
+
// ==================
|
|
37
|
+
auth: {
|
|
38
|
+
/**
|
|
39
|
+
* Get current authentication context
|
|
40
|
+
*/
|
|
41
|
+
whoami: () => baseClient.get("/auth/whoami"),
|
|
42
|
+
/**
|
|
43
|
+
* Check if authenticated (optional auth)
|
|
44
|
+
*/
|
|
45
|
+
check: () => baseClient.get("/auth/optional")
|
|
46
|
+
},
|
|
47
|
+
// ==================
|
|
48
|
+
// OAuth
|
|
49
|
+
// ==================
|
|
50
|
+
oauth: {
|
|
51
|
+
/**
|
|
52
|
+
* Get access token
|
|
53
|
+
*/
|
|
54
|
+
token: (body) => baseClient.post("/oauth/token", body),
|
|
55
|
+
/**
|
|
56
|
+
* Refresh access token
|
|
57
|
+
*/
|
|
58
|
+
refresh: (body) => baseClient.post("/oauth/refresh", body),
|
|
59
|
+
/**
|
|
60
|
+
* Introspect token
|
|
61
|
+
*/
|
|
62
|
+
introspect: (body) => baseClient.post("/oauth/introspect", body),
|
|
63
|
+
/**
|
|
64
|
+
* Revoke token
|
|
65
|
+
*/
|
|
66
|
+
revoke: (body) => baseClient.post("/oauth/revoke", body)
|
|
67
|
+
},
|
|
68
|
+
// ==================
|
|
69
|
+
// Tenants
|
|
70
|
+
// ==================
|
|
71
|
+
tenants: {
|
|
72
|
+
/**
|
|
73
|
+
* Create a new tenant
|
|
74
|
+
*/
|
|
75
|
+
create: (body) => baseClient.post("/v1/tenants", body),
|
|
76
|
+
/**
|
|
77
|
+
* List tenants (admin)
|
|
78
|
+
*/
|
|
79
|
+
list: (query) => baseClient.get("/v1/tenants", { query })
|
|
80
|
+
},
|
|
81
|
+
// ==================
|
|
82
|
+
// Credentials
|
|
83
|
+
// ==================
|
|
84
|
+
credentials: {
|
|
85
|
+
/**
|
|
86
|
+
* Exchange setup token for credentials
|
|
87
|
+
*/
|
|
88
|
+
setup: (body) => baseClient.post("/v1/credentials", body),
|
|
89
|
+
/**
|
|
90
|
+
* List credentials
|
|
91
|
+
*/
|
|
92
|
+
list: () => baseClient.get("/v1/credentials"),
|
|
93
|
+
/**
|
|
94
|
+
* Revoke credential
|
|
95
|
+
*/
|
|
96
|
+
revoke: (credentialId) => baseClient.delete(`/v1/credentials/${credentialId}`)
|
|
97
|
+
},
|
|
98
|
+
// ==================
|
|
99
|
+
// Users
|
|
100
|
+
// ==================
|
|
101
|
+
users: {
|
|
102
|
+
/**
|
|
103
|
+
* Create user
|
|
104
|
+
*/
|
|
105
|
+
create: (body) => baseClient.post("/v1/users", body),
|
|
106
|
+
/**
|
|
107
|
+
* List users
|
|
108
|
+
*/
|
|
109
|
+
list: (query) => baseClient.get("/v1/users", { query }),
|
|
110
|
+
/**
|
|
111
|
+
* Get user by ID
|
|
112
|
+
*/
|
|
113
|
+
get: (userId) => baseClient.get(`/v1/users/${userId}`),
|
|
114
|
+
/**
|
|
115
|
+
* Update user
|
|
116
|
+
*/
|
|
117
|
+
update: (userId, body) => baseClient.put(`/v1/users/${userId}`, body),
|
|
118
|
+
/**
|
|
119
|
+
* Update user status
|
|
120
|
+
*/
|
|
121
|
+
updateStatus: (userId, body) => baseClient.patch(`/v1/users/${userId}/status`, body),
|
|
122
|
+
/**
|
|
123
|
+
* Delete user
|
|
124
|
+
*/
|
|
125
|
+
delete: (userId) => baseClient.delete(`/v1/users/${userId}`)
|
|
126
|
+
},
|
|
127
|
+
// ==================
|
|
128
|
+
// Panics
|
|
129
|
+
// ==================
|
|
130
|
+
panics: {
|
|
131
|
+
/**
|
|
132
|
+
* Create panic
|
|
133
|
+
*/
|
|
134
|
+
create: (body) => baseClient.post("/v1/panics", body),
|
|
135
|
+
/**
|
|
136
|
+
* Get panic by ID
|
|
137
|
+
*/
|
|
138
|
+
get: (panicId, query) => baseClient.get(`/v1/panics/${panicId}`, { query }),
|
|
139
|
+
/**
|
|
140
|
+
* List panics
|
|
141
|
+
*/
|
|
142
|
+
list: (query) => baseClient.get("/v1/panics", { query }),
|
|
143
|
+
/**
|
|
144
|
+
* Update panic location
|
|
145
|
+
*/
|
|
146
|
+
updateLocation: (panicId, body) => baseClient.put(`/v1/panics/${panicId}/location`, body),
|
|
147
|
+
/**
|
|
148
|
+
* Cancel panic
|
|
149
|
+
*/
|
|
150
|
+
cancel: (panicId, body) => baseClient.put(`/v1/panics/${panicId}/cancel`, body),
|
|
151
|
+
/**
|
|
152
|
+
* Stream panic updates (SSE)
|
|
153
|
+
*/
|
|
154
|
+
streamUpdates: (panicId, options2) => {
|
|
155
|
+
const config = baseClient.getConfig();
|
|
156
|
+
const url = `${config.baseUrl}/v1/panics/${panicId}/stream`;
|
|
157
|
+
return streamAdapter.createEventSource(url, {
|
|
158
|
+
...options2,
|
|
159
|
+
headers: {
|
|
160
|
+
...options2?.headers,
|
|
161
|
+
...config.token ? { Authorization: `Bearer ${config.token}` } : {}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
// ==================
|
|
167
|
+
// Subscriptions
|
|
168
|
+
// ==================
|
|
169
|
+
subscriptions: {
|
|
170
|
+
/**
|
|
171
|
+
* List subscription types
|
|
172
|
+
*/
|
|
173
|
+
listTypes: () => baseClient.get("/v1/subscriptions/types"),
|
|
174
|
+
/**
|
|
175
|
+
* Create subscription
|
|
176
|
+
*/
|
|
177
|
+
create: (body) => baseClient.post("/v1/subscriptions", body),
|
|
178
|
+
/**
|
|
179
|
+
* List subscriptions
|
|
180
|
+
*/
|
|
181
|
+
list: (query) => baseClient.get("/v1/subscriptions", { query }),
|
|
182
|
+
/**
|
|
183
|
+
* Get subscription stats
|
|
184
|
+
*/
|
|
185
|
+
stats: () => baseClient.get("/v1/subscriptions/stats")
|
|
186
|
+
},
|
|
187
|
+
// ==================
|
|
188
|
+
// Notifications
|
|
189
|
+
// ==================
|
|
190
|
+
notifications: {
|
|
191
|
+
/**
|
|
192
|
+
* Create subscriber
|
|
193
|
+
*/
|
|
194
|
+
createSubscriber: (body) => baseClient.post("/v1/notifications/subscribers", body),
|
|
195
|
+
/**
|
|
196
|
+
* Trigger notification
|
|
197
|
+
*/
|
|
198
|
+
trigger: (body) => baseClient.post("/v1/notifications/trigger", body),
|
|
199
|
+
/**
|
|
200
|
+
* Get user preferences
|
|
201
|
+
*/
|
|
202
|
+
getPreferences: (userId) => baseClient.get(`/v1/notifications/preferences/${userId}`),
|
|
203
|
+
/**
|
|
204
|
+
* Update user preferences
|
|
205
|
+
*/
|
|
206
|
+
updatePreferences: (userId, body) => baseClient.put(`/v1/notifications/preferences/${userId}`, body)
|
|
207
|
+
},
|
|
208
|
+
// ==================
|
|
209
|
+
// Location Safety
|
|
210
|
+
// ==================
|
|
211
|
+
locationSafety: {
|
|
212
|
+
/**
|
|
213
|
+
* Check location safety
|
|
214
|
+
*/
|
|
215
|
+
check: (query) => baseClient.get("/v1/location-safety", { query })
|
|
216
|
+
},
|
|
217
|
+
// ==================
|
|
218
|
+
// Crimes
|
|
219
|
+
// ==================
|
|
220
|
+
crimes: {
|
|
221
|
+
/**
|
|
222
|
+
* List crimes
|
|
223
|
+
*/
|
|
224
|
+
list: (query) => baseClient.get("/v1/crimes", { query }),
|
|
225
|
+
/**
|
|
226
|
+
* Get crime categories
|
|
227
|
+
*/
|
|
228
|
+
categories: () => baseClient.get("/v1/crime-categories"),
|
|
229
|
+
/**
|
|
230
|
+
* Get crime types
|
|
231
|
+
*/
|
|
232
|
+
types: () => baseClient.get("/v1/crime-types")
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Object.defineProperty(exports, "FetchStreamAdapter", {
|
|
238
|
+
enumerable: true,
|
|
239
|
+
get: function () { return sdkCore.FetchStreamAdapter; }
|
|
240
|
+
});
|
|
241
|
+
Object.defineProperty(exports, "MemoryTokenStorage", {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function () { return sdkCore.MemoryTokenStorage; }
|
|
244
|
+
});
|
|
245
|
+
Object.defineProperty(exports, "SaferCityApiError", {
|
|
246
|
+
enumerable: true,
|
|
247
|
+
get: function () { return sdkCore.SaferCityApiError; }
|
|
248
|
+
});
|
|
249
|
+
Object.defineProperty(exports, "WebStreamAdapter", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
get: function () { return sdkCore.WebStreamAdapter; }
|
|
252
|
+
});
|
|
253
|
+
Object.defineProperty(exports, "createAuthHeader", {
|
|
254
|
+
enumerable: true,
|
|
255
|
+
get: function () { return sdkCore.createAuthHeader; }
|
|
256
|
+
});
|
|
257
|
+
Object.defineProperty(exports, "createStreamAdapter", {
|
|
258
|
+
enumerable: true,
|
|
259
|
+
get: function () { return sdkCore.createStreamAdapter; }
|
|
260
|
+
});
|
|
261
|
+
Object.defineProperty(exports, "getJwtExpiration", {
|
|
262
|
+
enumerable: true,
|
|
263
|
+
get: function () { return sdkCore.getJwtExpiration; }
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, "isTokenExpired", {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function () { return sdkCore.isTokenExpired; }
|
|
268
|
+
});
|
|
269
|
+
Object.defineProperty(exports, "parseJwtPayload", {
|
|
270
|
+
enumerable: true,
|
|
271
|
+
get: function () { return sdkCore.parseJwtPayload; }
|
|
272
|
+
});
|
|
273
|
+
exports.createSaferCityClient = createSaferCityClient;
|
|
274
|
+
//# sourceMappingURL=index.cjs.map
|
|
275
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":["BaseClient","createStreamAdapter","options"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SaferCity API Client\n * \n * Main client for interacting with the SaferCity multi-tenant API.\n * Provides typed methods for all API endpoints with streaming support.\n */\n\nimport {\n BaseClient,\n type SaferCityConfig,\n type StreamAdapter,\n createStreamAdapter,\n type ServerSentEvent,\n type EventSourceOptions,\n} from '@safercity/sdk-core';\n\nexport interface SaferCityClientOptions extends SaferCityConfig {\n /**\n * Custom stream adapter for SSE (auto-detected if not provided)\n */\n streamAdapter?: StreamAdapter;\n}\n\n/**\n * Create a SaferCity API client\n */\nexport function createSaferCityClient(options: SaferCityClientOptions) {\n const baseClient = new BaseClient(options);\n const streamAdapter = options.streamAdapter ?? createStreamAdapter(options.fetch);\n \n return {\n /**\n * Access the underlying base client for custom requests\n */\n _client: baseClient,\n \n /**\n * Update authentication token\n */\n setToken: (token: string | undefined) => baseClient.setToken(token),\n \n /**\n * Update tenant ID\n */\n setTenantId: (tenantId: string | undefined) => baseClient.setTenantId(tenantId),\n \n /**\n * Get current configuration\n */\n getConfig: () => baseClient.getConfig(),\n\n // ==================\n // Health & System\n // ==================\n \n health: {\n /**\n * Check API health status\n */\n check: () => baseClient.get<{\n status: string;\n timestamp: string;\n panicProviders?: {\n healthy: boolean;\n stats?: unknown;\n providers?: unknown;\n };\n }>('/health'),\n },\n\n // ==================\n // Authentication\n // ==================\n \n auth: {\n /**\n * Get current authentication context\n */\n whoami: () => baseClient.get<{\n tenantId: string | null;\n environment: string;\n scopes: string[];\n sessionId: string;\n }>('/auth/whoami'),\n \n /**\n * Check if authenticated (optional auth)\n */\n check: () => baseClient.get<{\n authenticated: boolean;\n tenantId: string | null;\n }>('/auth/optional'),\n },\n\n // ==================\n // OAuth\n // ==================\n \n oauth: {\n /**\n * Get access token\n */\n token: (body: {\n grant_type: 'client_credentials' | 'refresh_token';\n tenantId?: string;\n userId?: string;\n refresh_token?: string;\n }) => baseClient.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/oauth/token', body),\n \n /**\n * Refresh access token\n */\n refresh: (body: { refresh_token: string }) =>\n baseClient.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/oauth/refresh', body),\n \n /**\n * Introspect token\n */\n introspect: (body: { token: string }) =>\n baseClient.post<{\n active: boolean;\n tenantId?: string;\n sub?: string;\n scope?: string;\n exp?: number;\n }>('/oauth/introspect', body),\n \n /**\n * Revoke token\n */\n revoke: (body: { token: string }) =>\n baseClient.post<{ success: boolean }>('/oauth/revoke', body),\n },\n\n // ==================\n // Tenants\n // ==================\n \n tenants: {\n /**\n * Create a new tenant\n */\n create: (body: { name: string; domain?: string }) =>\n baseClient.post<{\n tenantId: string;\n name: string;\n setupToken: string;\n }>('/v1/tenants', body),\n \n /**\n * List tenants (admin)\n */\n list: (query?: { limit?: number; cursor?: string }) =>\n baseClient.get<{\n tenants: Array<{ id: string; name: string }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/tenants', { query }),\n },\n\n // ==================\n // Credentials\n // ==================\n \n credentials: {\n /**\n * Exchange setup token for credentials\n */\n setup: (body: { setupToken: string }) =>\n baseClient.post<{\n clientId: string;\n clientSecret: string;\n tenantId: string;\n }>('/v1/credentials', body),\n \n /**\n * List credentials\n */\n list: () =>\n baseClient.get<{\n credentials: Array<{\n id: string;\n clientId: string;\n createdAt: string;\n lastUsed?: string;\n }>;\n }>('/v1/credentials'),\n \n /**\n * Revoke credential\n */\n revoke: (credentialId: string) =>\n baseClient.delete<{ success: boolean }>(`/v1/credentials/${credentialId}`),\n },\n\n // ==================\n // Users\n // ==================\n \n users: {\n /**\n * Create user\n */\n create: (body: {\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n metadata?: Record<string, unknown>;\n }) => baseClient.post<{ id: string; email?: string; phone?: string }>('/v1/users', body),\n \n /**\n * List users\n */\n list: (query?: { limit?: number; cursor?: string; status?: string }) =>\n baseClient.get<{\n users: Array<{\n id: string;\n email?: string;\n phone?: string;\n status: string;\n }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/users', { query }),\n \n /**\n * Get user by ID\n */\n get: (userId: string) =>\n baseClient.get<{\n id: string;\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n status: string;\n metadata?: Record<string, unknown>;\n }>(`/v1/users/${userId}`),\n \n /**\n * Update user\n */\n update: (userId: string, body: {\n email?: string;\n phone?: string;\n firstName?: string;\n lastName?: string;\n metadata?: Record<string, unknown>;\n }) => baseClient.put<{ id: string }>(`/v1/users/${userId}`, body),\n \n /**\n * Update user status\n */\n updateStatus: (userId: string, body: { status: string }) =>\n baseClient.patch<{ id: string; status: string }>(`/v1/users/${userId}/status`, body),\n \n /**\n * Delete user\n */\n delete: (userId: string) =>\n baseClient.delete<{ success: boolean }>(`/v1/users/${userId}`),\n },\n\n // ==================\n // Panics\n // ==================\n \n panics: {\n /**\n * Create panic\n */\n create: (body: {\n userId: string;\n panicTypeId?: string;\n latitude: number;\n longitude: number;\n accuracy?: number;\n metadata?: Record<string, unknown>;\n }) => baseClient.post<{\n id: string;\n status: string;\n createdAt: string;\n }>('/v1/panics', body),\n \n /**\n * Get panic by ID\n */\n get: (panicId: string, query?: { userId?: string }) =>\n baseClient.get<{\n id: string;\n userId: string;\n status: string;\n latitude: number;\n longitude: number;\n createdAt: string;\n updatedAt?: string;\n }>(`/v1/panics/${panicId}`, { query }),\n \n /**\n * List panics\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n cursor?: string;\n }) => baseClient.get<{\n panics: Array<{\n id: string;\n userId: string;\n status: string;\n createdAt: string;\n }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/panics', { query }),\n \n /**\n * Update panic location\n */\n updateLocation: (panicId: string, body: {\n userId: string;\n latitude: number;\n longitude: number;\n accuracy?: number;\n }) => baseClient.put<{\n id: string;\n latitude: number;\n longitude: number;\n }>(`/v1/panics/${panicId}/location`, body),\n \n /**\n * Cancel panic\n */\n cancel: (panicId: string, body: { userId: string; reason?: string }) =>\n baseClient.put<{\n id: string;\n status: string;\n cancelledAt: string;\n }>(`/v1/panics/${panicId}/cancel`, body),\n \n /**\n * Stream panic updates (SSE)\n */\n streamUpdates: (\n panicId: string,\n options?: EventSourceOptions\n ): AsyncIterable<ServerSentEvent> => {\n const config = baseClient.getConfig();\n const url = `${config.baseUrl}/v1/panics/${panicId}/stream`;\n \n return streamAdapter.createEventSource(url, {\n ...options,\n headers: {\n ...options?.headers,\n ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),\n },\n });\n },\n },\n\n // ==================\n // Subscriptions\n // ==================\n \n subscriptions: {\n /**\n * List subscription types\n */\n listTypes: () =>\n baseClient.get<{\n types: Array<{\n id: string;\n name: string;\n description?: string;\n price?: number;\n }>;\n }>('/v1/subscriptions/types'),\n \n /**\n * Create subscription\n */\n create: (body: {\n userId: string;\n subscriptionTypeId: string;\n status?: string;\n }) => baseClient.post<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>('/v1/subscriptions', body),\n \n /**\n * List subscriptions\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n }) => baseClient.get<{\n subscriptions: Array<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>;\n }>('/v1/subscriptions', { query }),\n \n /**\n * Get subscription stats\n */\n stats: () =>\n baseClient.get<{\n total: number;\n active: number;\n byType: Record<string, number>;\n }>('/v1/subscriptions/stats'),\n },\n\n // ==================\n // Notifications\n // ==================\n \n notifications: {\n /**\n * Create subscriber\n */\n createSubscriber: (body: {\n userId: string;\n email?: string;\n phone?: string;\n data?: Record<string, unknown>;\n }) => baseClient.post<{ subscriberId: string }>('/v1/notifications/subscribers', body),\n \n /**\n * Trigger notification\n */\n trigger: (body: {\n userId: string;\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => baseClient.post<{\n transactionId: string;\n status: string;\n }>('/v1/notifications/trigger', body),\n \n /**\n * Get user preferences\n */\n getPreferences: (userId: string) =>\n baseClient.get<{\n preferences: Record<string, unknown>;\n }>(`/v1/notifications/preferences/${userId}`),\n \n /**\n * Update user preferences\n */\n updatePreferences: (userId: string, body: {\n preferences: Record<string, unknown>;\n }) => baseClient.put<{ success: boolean }>(`/v1/notifications/preferences/${userId}`, body),\n },\n\n // ==================\n // Location Safety\n // ==================\n \n locationSafety: {\n /**\n * Check location safety\n */\n check: (query: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.get<{\n safetyScore: number;\n riskLevel: string;\n factors: Array<{ type: string; impact: number }>;\n }>('/v1/location-safety', { query }),\n },\n\n // ==================\n // Crimes\n // ==================\n \n crimes: {\n /**\n * List crimes\n */\n list: (query?: {\n latitude?: number;\n longitude?: number;\n radius?: number;\n type?: string;\n from?: string;\n to?: string;\n limit?: number;\n }) => baseClient.get<{\n crimes: Array<{\n id: string;\n type: string;\n latitude: number;\n longitude: number;\n occurredAt: string;\n }>;\n }>('/v1/crimes', { query }),\n \n /**\n * Get crime categories\n */\n categories: () =>\n baseClient.get<{\n categories: Array<{ id: string; name: string }>;\n }>('/v1/crime-categories'),\n \n /**\n * Get crime types\n */\n types: () =>\n baseClient.get<{\n types: Array<{ id: string; name: string; categoryId: string }>;\n }>('/v1/crime-types'),\n },\n };\n}\n\nexport type SaferCityClient = ReturnType<typeof createSaferCityClient>;\n"]}
|