@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 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"]}