@safercity/sdk 0.1.2 → 0.1.3
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 +17 -3
- package/dist/index.cjs +252 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +456 -48
- package/dist/index.d.ts +456 -48
- package/dist/index.js +252 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Official SaferCity API client for TypeScript/JavaScript.
|
|
4
4
|
|
|
5
|
+
## What's New in v0.1.3
|
|
6
|
+
|
|
7
|
+
- **OAuth endpoint path fix** - Fixed paths (`/oauth/*` → `/v1/oauth/*`)
|
|
8
|
+
- **ServerClient domain helpers** - Added typed domain helpers to `ServerClient`
|
|
9
|
+
- **Security hardening** - Removed `panics.list()` and `subscriptions.stats()` from client-side SDK (available on `ServerClient` only)
|
|
10
|
+
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
7
13
|
```bash
|
|
@@ -104,7 +110,15 @@ const client = createServerClient({
|
|
|
104
110
|
|
|
105
111
|
// All requests are automatically authenticated with OAuth tokens
|
|
106
112
|
// Tokens are refreshed automatically before expiration
|
|
107
|
-
const users = await client.
|
|
113
|
+
const { data: users } = await client.users.list();
|
|
114
|
+
const { data: panic } = await client.panics.create({
|
|
115
|
+
userId: 'user-123',
|
|
116
|
+
latitude: -26.2041,
|
|
117
|
+
longitude: 28.0473,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Low-level requests still work too
|
|
121
|
+
const response = await client.get('/v1/custom-endpoint');
|
|
108
122
|
|
|
109
123
|
// Manual token control
|
|
110
124
|
const token = await client.getAccessToken();
|
|
@@ -112,6 +126,8 @@ await client.refreshToken();
|
|
|
112
126
|
client.clearTokens();
|
|
113
127
|
```
|
|
114
128
|
|
|
129
|
+
> **Note**: The `ServerClient` includes `panics.list()` and `subscriptions.stats()` which are not available on the client-side SDK for security reasons.
|
|
130
|
+
|
|
115
131
|
### ServerClientConfig
|
|
116
132
|
|
|
117
133
|
```typescript
|
|
@@ -256,7 +272,6 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
|
|
|
256
272
|
### Panics
|
|
257
273
|
- `client.panics.create(body)` - Create panic
|
|
258
274
|
- `client.panics.get(panicId, query?)` - Get panic
|
|
259
|
-
- `client.panics.list(query?)` - List panics
|
|
260
275
|
- `client.panics.updateLocation(panicId, body)` - Update location
|
|
261
276
|
- `client.panics.cancel(panicId, body)` - Cancel panic
|
|
262
277
|
- `client.panics.streamUpdates(panicId, options?)` - Stream updates (SSE)
|
|
@@ -265,7 +280,6 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
|
|
|
265
280
|
- `client.subscriptions.listTypes()` - List subscription types
|
|
266
281
|
- `client.subscriptions.create(body)` - Create subscription
|
|
267
282
|
- `client.subscriptions.list(query?)` - List subscriptions
|
|
268
|
-
- `client.subscriptions.stats()` - Get stats
|
|
269
283
|
|
|
270
284
|
### Notifications
|
|
271
285
|
- `client.notifications.createSubscriber(body)` - Create subscriber
|
package/dist/index.cjs
CHANGED
|
@@ -51,19 +51,19 @@ function createSaferCityClient(options) {
|
|
|
51
51
|
/**
|
|
52
52
|
* Get access token
|
|
53
53
|
*/
|
|
54
|
-
token: (body) => baseClient.post("/oauth/token", body),
|
|
54
|
+
token: (body) => baseClient.post("/v1/oauth/token", body),
|
|
55
55
|
/**
|
|
56
56
|
* Refresh access token
|
|
57
57
|
*/
|
|
58
|
-
refresh: (body) => baseClient.post("/oauth/refresh", body),
|
|
58
|
+
refresh: (body) => baseClient.post("/v1/oauth/refresh", body),
|
|
59
59
|
/**
|
|
60
60
|
* Introspect token
|
|
61
61
|
*/
|
|
62
|
-
introspect: (body) => baseClient.post("/oauth/introspect", body),
|
|
62
|
+
introspect: (body) => baseClient.post("/v1/oauth/introspect", body),
|
|
63
63
|
/**
|
|
64
64
|
* Revoke token
|
|
65
65
|
*/
|
|
66
|
-
revoke: (body) => baseClient.post("/oauth/revoke", body)
|
|
66
|
+
revoke: (body) => baseClient.post("/v1/oauth/revoke", body)
|
|
67
67
|
},
|
|
68
68
|
// ==================
|
|
69
69
|
// Tenants
|
|
@@ -136,10 +136,6 @@ function createSaferCityClient(options) {
|
|
|
136
136
|
* Get panic by ID
|
|
137
137
|
*/
|
|
138
138
|
get: (panicId, query) => baseClient.get(`/v1/panics/${panicId}`, { query }),
|
|
139
|
-
/**
|
|
140
|
-
* List panics
|
|
141
|
-
*/
|
|
142
|
-
list: (query) => baseClient.get("/v1/panics", { query }),
|
|
143
139
|
/**
|
|
144
140
|
* Update panic location
|
|
145
141
|
*/
|
|
@@ -178,11 +174,7 @@ function createSaferCityClient(options) {
|
|
|
178
174
|
/**
|
|
179
175
|
* List subscriptions
|
|
180
176
|
*/
|
|
181
|
-
list: (query) => baseClient.get("/v1/subscriptions", { query })
|
|
182
|
-
/**
|
|
183
|
-
* Get subscription stats
|
|
184
|
-
*/
|
|
185
|
-
stats: () => baseClient.get("/v1/subscriptions/stats")
|
|
177
|
+
list: (query) => baseClient.get("/v1/subscriptions", { query })
|
|
186
178
|
},
|
|
187
179
|
// ==================
|
|
188
180
|
// Notifications
|
|
@@ -282,6 +274,253 @@ var ServerClient = class extends sdkCore.BaseClient {
|
|
|
282
274
|
headers: authHeaders
|
|
283
275
|
});
|
|
284
276
|
}
|
|
277
|
+
// ==================
|
|
278
|
+
// Health & System
|
|
279
|
+
// ==================
|
|
280
|
+
/**
|
|
281
|
+
* Check API health status
|
|
282
|
+
*/
|
|
283
|
+
get health() {
|
|
284
|
+
return {
|
|
285
|
+
check: () => this.get("/health")
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// ==================
|
|
289
|
+
// Authentication
|
|
290
|
+
// ==================
|
|
291
|
+
/**
|
|
292
|
+
* Authentication helpers
|
|
293
|
+
*/
|
|
294
|
+
get auth() {
|
|
295
|
+
return {
|
|
296
|
+
/**
|
|
297
|
+
* Get current authentication context
|
|
298
|
+
*/
|
|
299
|
+
whoami: () => this.get("/auth/whoami"),
|
|
300
|
+
/**
|
|
301
|
+
* Check if authenticated (optional auth)
|
|
302
|
+
*/
|
|
303
|
+
check: () => this.get("/auth/optional")
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
// ==================
|
|
307
|
+
// OAuth
|
|
308
|
+
// ==================
|
|
309
|
+
/**
|
|
310
|
+
* OAuth helpers
|
|
311
|
+
*/
|
|
312
|
+
get oauth() {
|
|
313
|
+
return {
|
|
314
|
+
/**
|
|
315
|
+
* Get access token
|
|
316
|
+
*/
|
|
317
|
+
token: (body) => this.post("/v1/oauth/token", body),
|
|
318
|
+
/**
|
|
319
|
+
* Refresh access token
|
|
320
|
+
*/
|
|
321
|
+
refresh: (body) => this.post("/v1/oauth/refresh", body),
|
|
322
|
+
/**
|
|
323
|
+
* Introspect token
|
|
324
|
+
*/
|
|
325
|
+
introspect: (body) => this.post("/v1/oauth/introspect", body),
|
|
326
|
+
/**
|
|
327
|
+
* Revoke token
|
|
328
|
+
*/
|
|
329
|
+
revoke: (body) => this.post("/v1/oauth/revoke", body)
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// ==================
|
|
333
|
+
// Tenants
|
|
334
|
+
// ==================
|
|
335
|
+
/**
|
|
336
|
+
* Tenant helpers
|
|
337
|
+
*/
|
|
338
|
+
get tenants() {
|
|
339
|
+
return {
|
|
340
|
+
/**
|
|
341
|
+
* Create a new tenant
|
|
342
|
+
*/
|
|
343
|
+
create: (body) => this.post("/v1/tenants", body),
|
|
344
|
+
/**
|
|
345
|
+
* List tenants (admin)
|
|
346
|
+
*/
|
|
347
|
+
list: (query) => this.get("/v1/tenants", { query })
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
// ==================
|
|
351
|
+
// Credentials
|
|
352
|
+
// ==================
|
|
353
|
+
/**
|
|
354
|
+
* Credential helpers
|
|
355
|
+
*/
|
|
356
|
+
get credentials() {
|
|
357
|
+
return {
|
|
358
|
+
/**
|
|
359
|
+
* Exchange setup token for credentials
|
|
360
|
+
*/
|
|
361
|
+
setup: (body) => this.post("/v1/credentials", body),
|
|
362
|
+
/**
|
|
363
|
+
* List credentials
|
|
364
|
+
*/
|
|
365
|
+
list: () => this.get("/v1/credentials"),
|
|
366
|
+
/**
|
|
367
|
+
* Revoke credential
|
|
368
|
+
*/
|
|
369
|
+
revoke: (credentialId) => this.delete(`/v1/credentials/${credentialId}`)
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
// ==================
|
|
373
|
+
// Users
|
|
374
|
+
// ==================
|
|
375
|
+
/**
|
|
376
|
+
* User helpers
|
|
377
|
+
*/
|
|
378
|
+
get users() {
|
|
379
|
+
return {
|
|
380
|
+
/**
|
|
381
|
+
* Create user
|
|
382
|
+
*/
|
|
383
|
+
create: (body) => this.post("/v1/users", body),
|
|
384
|
+
/**
|
|
385
|
+
* List users
|
|
386
|
+
*/
|
|
387
|
+
list: (query) => this.get("/v1/users", { query }),
|
|
388
|
+
/**
|
|
389
|
+
* Get user by ID
|
|
390
|
+
*/
|
|
391
|
+
get: (userId) => this.get(`/v1/users/${userId}`),
|
|
392
|
+
/**
|
|
393
|
+
* Update user
|
|
394
|
+
*/
|
|
395
|
+
update: (userId, body) => this.put(`/v1/users/${userId}`, body),
|
|
396
|
+
/**
|
|
397
|
+
* Update user status
|
|
398
|
+
*/
|
|
399
|
+
updateStatus: (userId, body) => this.patch(`/v1/users/${userId}/status`, body),
|
|
400
|
+
/**
|
|
401
|
+
* Delete user
|
|
402
|
+
*/
|
|
403
|
+
delete: (userId) => this.delete(`/v1/users/${userId}`)
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
// ==================
|
|
407
|
+
// Panics
|
|
408
|
+
// ==================
|
|
409
|
+
/**
|
|
410
|
+
* Panic helpers (streaming not available in server client)
|
|
411
|
+
*/
|
|
412
|
+
get panics() {
|
|
413
|
+
return {
|
|
414
|
+
/**
|
|
415
|
+
* Create panic
|
|
416
|
+
*/
|
|
417
|
+
create: (body) => this.post("/v1/panics", body),
|
|
418
|
+
/**
|
|
419
|
+
* Get panic by ID
|
|
420
|
+
*/
|
|
421
|
+
get: (panicId, query) => this.get(`/v1/panics/${panicId}`, { query }),
|
|
422
|
+
/**
|
|
423
|
+
* List panics
|
|
424
|
+
*/
|
|
425
|
+
list: (query) => this.get("/v1/panics", { query }),
|
|
426
|
+
/**
|
|
427
|
+
* Update panic location
|
|
428
|
+
*/
|
|
429
|
+
updateLocation: (panicId, body) => this.put(`/v1/panics/${panicId}/location`, body),
|
|
430
|
+
/**
|
|
431
|
+
* Cancel panic
|
|
432
|
+
*/
|
|
433
|
+
cancel: (panicId, body) => this.put(`/v1/panics/${panicId}/cancel`, body)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
// ==================
|
|
437
|
+
// Subscriptions
|
|
438
|
+
// ==================
|
|
439
|
+
/**
|
|
440
|
+
* Subscription helpers
|
|
441
|
+
*/
|
|
442
|
+
get subscriptions() {
|
|
443
|
+
return {
|
|
444
|
+
/**
|
|
445
|
+
* List subscription types
|
|
446
|
+
*/
|
|
447
|
+
listTypes: () => this.get("/v1/subscriptions/types"),
|
|
448
|
+
/**
|
|
449
|
+
* Create subscription
|
|
450
|
+
*/
|
|
451
|
+
create: (body) => this.post("/v1/subscriptions", body),
|
|
452
|
+
/**
|
|
453
|
+
* List subscriptions
|
|
454
|
+
*/
|
|
455
|
+
list: (query) => this.get("/v1/subscriptions", { query }),
|
|
456
|
+
/**
|
|
457
|
+
* Get subscription stats
|
|
458
|
+
*/
|
|
459
|
+
stats: () => this.get("/v1/subscriptions/stats")
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
// ==================
|
|
463
|
+
// Notifications
|
|
464
|
+
// ==================
|
|
465
|
+
/**
|
|
466
|
+
* Notification helpers
|
|
467
|
+
*/
|
|
468
|
+
get notifications() {
|
|
469
|
+
return {
|
|
470
|
+
/**
|
|
471
|
+
* Create subscriber
|
|
472
|
+
*/
|
|
473
|
+
createSubscriber: (body) => this.post("/v1/notifications/subscribers", body),
|
|
474
|
+
/**
|
|
475
|
+
* Trigger notification
|
|
476
|
+
*/
|
|
477
|
+
trigger: (body) => this.post("/v1/notifications/trigger", body),
|
|
478
|
+
/**
|
|
479
|
+
* Get user preferences
|
|
480
|
+
*/
|
|
481
|
+
getPreferences: (userId) => this.get(`/v1/notifications/preferences/${userId}`),
|
|
482
|
+
/**
|
|
483
|
+
* Update user preferences
|
|
484
|
+
*/
|
|
485
|
+
updatePreferences: (userId, body) => this.put(`/v1/notifications/preferences/${userId}`, body)
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
// ==================
|
|
489
|
+
// Location Safety
|
|
490
|
+
// ==================
|
|
491
|
+
/**
|
|
492
|
+
* Location safety helpers
|
|
493
|
+
*/
|
|
494
|
+
get locationSafety() {
|
|
495
|
+
return {
|
|
496
|
+
/**
|
|
497
|
+
* Check location safety
|
|
498
|
+
*/
|
|
499
|
+
check: (query) => this.get("/v1/location-safety", { query })
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
// ==================
|
|
503
|
+
// Crimes
|
|
504
|
+
// ==================
|
|
505
|
+
/**
|
|
506
|
+
* Crime helpers
|
|
507
|
+
*/
|
|
508
|
+
get crimes() {
|
|
509
|
+
return {
|
|
510
|
+
/**
|
|
511
|
+
* List crimes
|
|
512
|
+
*/
|
|
513
|
+
list: (query) => this.get("/v1/crimes", { query }),
|
|
514
|
+
/**
|
|
515
|
+
* Get crime categories
|
|
516
|
+
*/
|
|
517
|
+
categories: () => this.get("/v1/crime-categories"),
|
|
518
|
+
/**
|
|
519
|
+
* Get crime types
|
|
520
|
+
*/
|
|
521
|
+
types: () => this.get("/v1/crime-types")
|
|
522
|
+
};
|
|
523
|
+
}
|
|
285
524
|
};
|
|
286
525
|
function createServerClient(config) {
|
|
287
526
|
return new ServerClient(config);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/server.ts","../src/proxy.ts"],"names":["BaseClient","createStreamAdapter","options","TokenManager"],"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","/**\n * Server-side SaferCity Client\n * \n * For backend applications that need to authenticate with OAuth client credentials.\n * Handles automatic token management and refresh.\n */\n\nimport {\n TokenManager,\n type OAuthCredentials,\n type TokenStorage,\n BaseClient,\n type SaferCityConfig,\n} from '@safercity/sdk-core';\n\nexport interface ServerClientConfig {\n /**\n * SaferCity API base URL\n * @default \"https://api.safercity.com\"\n */\n baseUrl?: string;\n \n /**\n * OAuth credentials for authentication\n */\n auth: OAuthCredentials;\n \n /**\n * Custom token storage (defaults to in-memory)\n */\n tokenStore?: TokenStorage;\n \n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeout?: number;\n \n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\n/**\n * Server client that wraps the base client with automatic OAuth token management\n */\nexport class ServerClient extends BaseClient {\n private tokenManager: TokenManager;\n\n constructor(config: ServerClientConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n \n super({\n baseUrl,\n timeout: config.timeout,\n fetch: config.fetch,\n });\n\n this.tokenManager = new TokenManager({\n credentials: config.auth,\n baseUrl,\n storage: config.tokenStore,\n fetch: config.fetch,\n });\n }\n\n /**\n * Get a valid access token\n */\n async getAccessToken(): Promise<string> {\n return this.tokenManager.getToken();\n }\n\n /**\n * Force refresh the token\n */\n async refreshToken(): Promise<string> {\n return this.tokenManager.forceRefresh();\n }\n\n /**\n * Clear stored tokens\n */\n clearTokens(): void {\n this.tokenManager.clear();\n }\n\n /**\n * Make an authenticated request\n * Automatically adds the Authorization header with a valid token\n */\n protected override async request<T>(\n method: string,\n path: string,\n options?: Parameters<BaseClient['request']>[2]\n ): Promise<{ data: T; status: number; headers: Headers }> {\n // Get token and add to headers\n const token = await this.getAccessToken();\n \n const authHeaders = {\n ...options?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return super.request<T>(method, path, {\n ...options,\n headers: authHeaders,\n });\n }\n}\n\n/**\n * Create a server-side SaferCity client with automatic OAuth token management\n * \n * @example\n * ```typescript\n * const client = createServerClient({\n * auth: {\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * },\n * });\n * \n * // All requests are automatically authenticated\n * const users = await client.get('/v1/users');\n * ```\n */\nexport function createServerClient(config: ServerClientConfig): ServerClient {\n return new ServerClient(config);\n}\n\nexport type { OAuthCredentials, TokenStorage };\n","/**\n * Proxy Middleware Helpers\n * \n * Helpers for creating proxy endpoints that forward requests to SaferCity API\n * with automatic tenant authentication.\n */\n\nimport { TokenManager, type TokenStorage } from '@safercity/sdk-core';\n\nexport interface ProxyConfig {\n /**\n * OAuth client ID\n */\n clientId: string;\n \n /**\n * OAuth client secret\n */\n clientSecret: string;\n \n /**\n * SaferCity API base URL\n * @default \"https://api.safercity.com\"\n */\n baseUrl?: string;\n \n /**\n * Tenant ID (optional, can be extracted from request)\n */\n tenantId?: string;\n \n /**\n * Custom token storage\n */\n tokenStore?: TokenStorage;\n \n /**\n * Path prefix to strip from incoming requests\n * @default \"/api/safercity\"\n */\n pathPrefix?: string;\n \n /**\n * Headers to forward from the original request\n * @default [\"content-type\", \"accept\", \"x-request-id\"]\n */\n forwardHeaders?: string[];\n \n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\n// Singleton token manager to share across requests\nconst tokenManagers = new Map<string, TokenManager>();\n\nfunction getTokenManager(config: ProxyConfig): TokenManager {\n const key = `${config.clientId}:${config.baseUrl ?? \"default\"}`;\n \n let manager = tokenManagers.get(key);\n if (!manager) {\n manager = new TokenManager({\n credentials: {\n clientId: config.clientId,\n clientSecret: config.clientSecret,\n tenantId: config.tenantId,\n },\n baseUrl: config.baseUrl ?? \"https://api.safercity.com\",\n storage: config.tokenStore,\n fetch: config.fetch,\n });\n tokenManagers.set(key, manager);\n }\n \n return manager;\n}\n\n/**\n * Create a Next.js App Router handler for proxying SaferCity API requests\n * \n * @example\n * ```typescript\n * // app/api/safercity/[...path]/route.ts\n * import { createNextHandler } from \"@safercity/sdk\";\n * \n * const handler = createNextHandler({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * });\n * \n * export { handler as GET, handler as POST, handler as PUT, handler as DELETE, handler as PATCH };\n * ```\n */\nexport function createNextHandler(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const pathPrefix = config.pathPrefix ?? \"/api/safercity\";\n const forwardHeaders = config.forwardHeaders ?? [\"content-type\", \"accept\", \"x-request-id\"];\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function handler(request: Request): Promise<Response> {\n const tokenManager = getTokenManager(config);\n \n try {\n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n const url = new URL(request.url);\n const path = url.pathname.replace(new RegExp(`^${pathPrefix}`), \"\");\n const targetUrl = `${baseUrl}${path}${url.search}`;\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n \n // Forward specified headers\n for (const header of forwardHeaders) {\n const value = request.headers.get(header);\n if (value) {\n headers[header] = value;\n }\n }\n \n // Forward tenant ID header if present\n const tenantIdHeader = request.headers.get(\"x-tenant-id\");\n if (tenantIdHeader) {\n headers[\"X-Tenant-ID\"] = tenantIdHeader;\n } else if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Forward request body for non-GET requests\n let body: BodyInit | undefined;\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n body = await request.text();\n }\n \n // Make proxied request\n const response = await fetchFn(targetUrl, {\n method: request.method,\n headers,\n body,\n });\n \n // Return response with CORS headers\n const responseHeaders = new Headers(response.headers);\n responseHeaders.set(\"Access-Control-Allow-Origin\", \"*\");\n responseHeaders.set(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, PATCH, OPTIONS\");\n responseHeaders.set(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, X-Tenant-ID\");\n \n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n } catch (error) {\n console.error(\"[SaferCity Proxy] Error:\", error);\n \n return new Response(\n JSON.stringify({\n error: \"proxy_error\",\n message: error instanceof Error ? error.message : \"Proxy request failed\",\n }),\n {\n status: 502,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }\n );\n }\n };\n}\n\n/**\n * Express/Node.js compatible request type\n */\ninterface ExpressRequest {\n method: string;\n path: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n query?: Record<string, string>;\n}\n\n/**\n * Express/Node.js compatible response type\n */\ninterface ExpressResponse {\n status(code: number): ExpressResponse;\n set(headers: Record<string, string>): ExpressResponse;\n json(data: unknown): void;\n send(data: string | ArrayBuffer | Uint8Array): void;\n}\n\n/**\n * Express next function type\n */\ntype NextFunction = (error?: unknown) => void;\n\n/**\n * Create an Express middleware for proxying SaferCity API requests\n * \n * @example\n * ```typescript\n * // Express middleware\n * import express from \"express\";\n * import { createExpressMiddleware } from \"@safercity/sdk\";\n * \n * const app = express();\n * \n * app.use(\n * \"/api/safercity\",\n * createExpressMiddleware({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * })\n * );\n * ```\n */\nexport function createExpressMiddleware(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const forwardHeaders = config.forwardHeaders ?? [\"content-type\", \"accept\", \"x-request-id\"];\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function middleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ): Promise<void> {\n const tokenManager = getTokenManager(config);\n \n try {\n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n const targetUrl = `${baseUrl}${req.path}${req.url.includes(\"?\") ? req.url.slice(req.url.indexOf(\"?\")) : \"\"}`;\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n \n // Forward specified headers\n for (const header of forwardHeaders) {\n const value = req.headers[header.toLowerCase()];\n if (value) {\n headers[header] = Array.isArray(value) ? value[0] : value;\n }\n }\n \n // Forward tenant ID header if present\n const tenantIdHeader = req.headers[\"x-tenant-id\"];\n if (tenantIdHeader) {\n headers[\"X-Tenant-ID\"] = Array.isArray(tenantIdHeader) ? tenantIdHeader[0] : tenantIdHeader;\n } else if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Prepare body\n let body: string | undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\" && req.body) {\n body = typeof req.body === \"string\" ? req.body : JSON.stringify(req.body);\n }\n \n // Make proxied request\n const response = await fetchFn(targetUrl, {\n method: req.method,\n headers,\n body,\n });\n \n // Get response body\n const contentType = response.headers.get(\"content-type\");\n const responseBody = contentType?.includes(\"application/json\")\n ? await response.json()\n : await response.text();\n \n // Set response headers\n res.status(response.status);\n res.set({\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Tenant-ID\",\n \"Content-Type\": contentType ?? \"application/json\",\n });\n \n // Send response\n if (typeof responseBody === \"string\") {\n res.send(responseBody);\n } else {\n res.json(responseBody);\n }\n } catch (error) {\n console.error(\"[SaferCity Proxy] Error:\", error);\n next(error);\n }\n };\n}\n\n/**\n * Create a generic proxy handler that works with any framework\n * Returns a function that takes a request and returns a response\n * \n * @example\n * ```typescript\n * const proxy = createProxyHandler({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * });\n * \n * // Use with any framework\n * const response = await proxy({\n * method: \"GET\",\n * path: \"/v1/users\",\n * headers: {},\n * });\n * ```\n */\nexport function createProxyHandler(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function proxy(request: {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n query?: Record<string, string>;\n }): Promise<{\n status: number;\n headers: Record<string, string>;\n body: unknown;\n }> {\n const tokenManager = getTokenManager(config);\n \n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n let targetUrl = `${baseUrl}${request.path}`;\n if (request.query && Object.keys(request.query).length > 0) {\n const params = new URLSearchParams(request.query);\n targetUrl += `?${params.toString()}`;\n }\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n ...request.headers,\n };\n \n // Add tenant ID if configured\n if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Make request\n const response = await fetchFn(targetUrl, {\n method: request.method,\n headers,\n body: request.body ? JSON.stringify(request.body) : undefined,\n });\n \n // Parse response\n const contentType = response.headers.get(\"content-type\");\n const body = contentType?.includes(\"application/json\")\n ? await response.json()\n : await response.text();\n \n // Extract response headers\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n \n return {\n status: response.status,\n headers: responseHeaders,\n body,\n };\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/server.ts","../src/proxy.ts"],"names":["BaseClient","createStreamAdapter","options","TokenManager"],"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 }>('/v1/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 }>('/v1/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 }>('/v1/oauth/introspect', body),\n \n /**\n * Revoke token\n */\n revoke: (body: { token: string }) =>\n baseClient.post<{ success: boolean }>('/v1/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 * 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 // ==================\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","/**\n * Server-side SaferCity Client\n * \n * For backend applications that need to authenticate with OAuth client credentials.\n * Handles automatic token management and refresh.\n */\n\nimport {\n TokenManager,\n type OAuthCredentials,\n type TokenStorage,\n BaseClient,\n type SaferCityConfig,\n} from '@safercity/sdk-core';\n\nexport interface ServerClientConfig\n extends Pick<SaferCityConfig, 'baseUrl' | 'timeout' | 'fetch'> {\n /**\n * OAuth credentials for authentication\n */\n auth: OAuthCredentials;\n\n /**\n * Custom token storage (defaults to in-memory)\n */\n tokenStore?: TokenStorage;\n}\n\n/**\n * Server client that wraps the base client with automatic OAuth token management\n */\nexport class ServerClient extends BaseClient {\n private tokenManager: TokenManager;\n\n constructor(config: ServerClientConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n \n super({\n baseUrl,\n timeout: config.timeout,\n fetch: config.fetch,\n });\n\n this.tokenManager = new TokenManager({\n credentials: config.auth,\n baseUrl,\n storage: config.tokenStore,\n fetch: config.fetch,\n });\n }\n\n /**\n * Get a valid access token\n */\n async getAccessToken(): Promise<string> {\n return this.tokenManager.getToken();\n }\n\n /**\n * Force refresh the token\n */\n async refreshToken(): Promise<string> {\n return this.tokenManager.forceRefresh();\n }\n\n /**\n * Clear stored tokens\n */\n clearTokens(): void {\n this.tokenManager.clear();\n }\n\n /**\n * Make an authenticated request\n * Automatically adds the Authorization header with a valid token\n */\n protected override async request<T>(\n method: string,\n path: string,\n options?: Parameters<BaseClient['request']>[2]\n ): Promise<{ data: T; status: number; headers: Headers }> {\n // Get token and add to headers\n const token = await this.getAccessToken();\n \n const authHeaders = {\n ...options?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return super.request<T>(method, path, {\n ...options,\n headers: authHeaders,\n });\n }\n\n // ==================\n // Health & System\n // ==================\n\n /**\n * Check API health status\n */\n get health() {\n return {\n check: () => this.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 // ==================\n // Authentication\n // ==================\n\n /**\n * Authentication helpers\n */\n get auth() {\n return {\n /**\n * Get current authentication context\n */\n whoami: () => this.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: () => this.get<{\n authenticated: boolean;\n tenantId: string | null;\n }>('/auth/optional'),\n };\n }\n\n // ==================\n // OAuth\n // ==================\n\n /**\n * OAuth helpers\n */\n get oauth() {\n return {\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 }) => this.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/v1/oauth/token', body),\n\n /**\n * Refresh access token\n */\n refresh: (body: { refresh_token: string }) =>\n this.post<{\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n }>('/v1/oauth/refresh', body),\n\n /**\n * Introspect token\n */\n introspect: (body: { token: string }) =>\n this.post<{\n active: boolean;\n tenantId?: string;\n sub?: string;\n scope?: string;\n exp?: number;\n }>('/v1/oauth/introspect', body),\n\n /**\n * Revoke token\n */\n revoke: (body: { token: string }) =>\n this.post<{ success: boolean }>('/v1/oauth/revoke', body),\n };\n }\n\n // ==================\n // Tenants\n // ==================\n\n /**\n * Tenant helpers\n */\n get tenants() {\n return {\n /**\n * Create a new tenant\n */\n create: (body: { name: string; domain?: string }) =>\n this.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 this.get<{\n tenants: Array<{ id: string; name: string }>;\n hasNext: boolean;\n cursor?: string;\n }>('/v1/tenants', { query }),\n };\n }\n\n // ==================\n // Credentials\n // ==================\n\n /**\n * Credential helpers\n */\n get credentials() {\n return {\n /**\n * Exchange setup token for credentials\n */\n setup: (body: { setupToken: string }) =>\n this.post<{\n clientId: string;\n clientSecret: string;\n tenantId: string;\n }>('/v1/credentials', body),\n\n /**\n * List credentials\n */\n list: () =>\n this.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 this.delete<{ success: boolean }>(`/v1/credentials/${credentialId}`),\n };\n }\n\n // ==================\n // Users\n // ==================\n\n /**\n * User helpers\n */\n get users() {\n return {\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 }) => this.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 this.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 this.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 }) => this.put<{ id: string }>(`/v1/users/${userId}`, body),\n\n /**\n * Update user status\n */\n updateStatus: (userId: string, body: { status: string }) =>\n this.patch<{ id: string; status: string }>(`/v1/users/${userId}/status`, body),\n\n /**\n * Delete user\n */\n delete: (userId: string) =>\n this.delete<{ success: boolean }>(`/v1/users/${userId}`),\n };\n }\n\n // ==================\n // Panics\n // ==================\n\n /**\n * Panic helpers (streaming not available in server client)\n */\n get panics() {\n return {\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 }) => this.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 this.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 }) => this.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 }) => this.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 this.put<{\n id: string;\n status: string;\n cancelledAt: string;\n }>(`/v1/panics/${panicId}/cancel`, body),\n };\n }\n\n // ==================\n // Subscriptions\n // ==================\n\n /**\n * Subscription helpers\n */\n get subscriptions() {\n return {\n /**\n * List subscription types\n */\n listTypes: () =>\n this.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 }) => this.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 }) => this.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 this.get<{\n total: number;\n active: number;\n byType: Record<string, number>;\n }>('/v1/subscriptions/stats'),\n };\n }\n\n // ==================\n // Notifications\n // ==================\n\n /**\n * Notification helpers\n */\n get notifications() {\n return {\n /**\n * Create subscriber\n */\n createSubscriber: (body: {\n userId: string;\n email?: string;\n phone?: string;\n data?: Record<string, unknown>;\n }) => this.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 }) => this.post<{\n transactionId: string;\n status: string;\n }>('/v1/notifications/trigger', body),\n\n /**\n * Get user preferences\n */\n getPreferences: (userId: string) =>\n this.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 }) => this.put<{ success: boolean }>(`/v1/notifications/preferences/${userId}`, body),\n };\n }\n\n // ==================\n // Location Safety\n // ==================\n\n /**\n * Location safety helpers\n */\n get locationSafety() {\n return {\n /**\n * Check location safety\n */\n check: (query: { latitude: number; longitude: number; radius?: number }) =>\n this.get<{\n safetyScore: number;\n riskLevel: string;\n factors: Array<{ type: string; impact: number }>;\n }>('/v1/location-safety', { query }),\n };\n }\n\n // ==================\n // Crimes\n // ==================\n\n /**\n * Crime helpers\n */\n get crimes() {\n return {\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 }) => this.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 this.get<{\n categories: Array<{ id: string; name: string }>;\n }>('/v1/crime-categories'),\n\n /**\n * Get crime types\n */\n types: () =>\n this.get<{\n types: Array<{ id: string; name: string; categoryId: string }>;\n }>('/v1/crime-types'),\n };\n }\n}\n\n/**\n * Create a server-side SaferCity client with automatic OAuth token management\n * \n * @example\n * ```typescript\n * const client = createServerClient({\n * auth: {\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * },\n * });\n * \n * // All requests are automatically authenticated\n * const users = await client.get('/v1/users');\n * ```\n */\nexport function createServerClient(config: ServerClientConfig): ServerClient {\n return new ServerClient(config);\n}\n\nexport type { OAuthCredentials, TokenStorage };\n","/**\n * Proxy Middleware Helpers\n * \n * Helpers for creating proxy endpoints that forward requests to SaferCity API\n * with automatic tenant authentication.\n */\n\nimport { TokenManager, type TokenStorage } from '@safercity/sdk-core';\n\nexport interface ProxyConfig {\n /**\n * OAuth client ID\n */\n clientId: string;\n \n /**\n * OAuth client secret\n */\n clientSecret: string;\n \n /**\n * SaferCity API base URL\n * @default \"https://api.safercity.com\"\n */\n baseUrl?: string;\n \n /**\n * Tenant ID (optional, can be extracted from request)\n */\n tenantId?: string;\n \n /**\n * Custom token storage\n */\n tokenStore?: TokenStorage;\n \n /**\n * Path prefix to strip from incoming requests\n * @default \"/api/safercity\"\n */\n pathPrefix?: string;\n \n /**\n * Headers to forward from the original request\n * @default [\"content-type\", \"accept\", \"x-request-id\"]\n */\n forwardHeaders?: string[];\n \n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\n// Singleton token manager to share across requests\nconst tokenManagers = new Map<string, TokenManager>();\n\nfunction getTokenManager(config: ProxyConfig): TokenManager {\n const key = `${config.clientId}:${config.baseUrl ?? \"default\"}`;\n \n let manager = tokenManagers.get(key);\n if (!manager) {\n manager = new TokenManager({\n credentials: {\n clientId: config.clientId,\n clientSecret: config.clientSecret,\n tenantId: config.tenantId,\n },\n baseUrl: config.baseUrl ?? \"https://api.safercity.com\",\n storage: config.tokenStore,\n fetch: config.fetch,\n });\n tokenManagers.set(key, manager);\n }\n \n return manager;\n}\n\n/**\n * Create a Next.js App Router handler for proxying SaferCity API requests\n * \n * @example\n * ```typescript\n * // app/api/safercity/[...path]/route.ts\n * import { createNextHandler } from \"@safercity/sdk\";\n * \n * const handler = createNextHandler({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * });\n * \n * export { handler as GET, handler as POST, handler as PUT, handler as DELETE, handler as PATCH };\n * ```\n */\nexport function createNextHandler(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const pathPrefix = config.pathPrefix ?? \"/api/safercity\";\n const forwardHeaders = config.forwardHeaders ?? [\"content-type\", \"accept\", \"x-request-id\"];\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function handler(request: Request): Promise<Response> {\n const tokenManager = getTokenManager(config);\n \n try {\n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n const url = new URL(request.url);\n const path = url.pathname.replace(new RegExp(`^${pathPrefix}`), \"\");\n const targetUrl = `${baseUrl}${path}${url.search}`;\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n \n // Forward specified headers\n for (const header of forwardHeaders) {\n const value = request.headers.get(header);\n if (value) {\n headers[header] = value;\n }\n }\n \n // Forward tenant ID header if present\n const tenantIdHeader = request.headers.get(\"x-tenant-id\");\n if (tenantIdHeader) {\n headers[\"X-Tenant-ID\"] = tenantIdHeader;\n } else if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Forward request body for non-GET requests\n let body: BodyInit | undefined;\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n body = await request.text();\n }\n \n // Make proxied request\n const response = await fetchFn(targetUrl, {\n method: request.method,\n headers,\n body,\n });\n \n // Return response with CORS headers\n const responseHeaders = new Headers(response.headers);\n responseHeaders.set(\"Access-Control-Allow-Origin\", \"*\");\n responseHeaders.set(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, PATCH, OPTIONS\");\n responseHeaders.set(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, X-Tenant-ID\");\n \n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n } catch (error) {\n console.error(\"[SaferCity Proxy] Error:\", error);\n \n return new Response(\n JSON.stringify({\n error: \"proxy_error\",\n message: error instanceof Error ? error.message : \"Proxy request failed\",\n }),\n {\n status: 502,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }\n );\n }\n };\n}\n\n/**\n * Express/Node.js compatible request type\n */\ninterface ExpressRequest {\n method: string;\n path: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n query?: Record<string, string>;\n}\n\n/**\n * Express/Node.js compatible response type\n */\ninterface ExpressResponse {\n status(code: number): ExpressResponse;\n set(headers: Record<string, string>): ExpressResponse;\n json(data: unknown): void;\n send(data: string | ArrayBuffer | Uint8Array): void;\n}\n\n/**\n * Express next function type\n */\ntype NextFunction = (error?: unknown) => void;\n\n/**\n * Create an Express middleware for proxying SaferCity API requests\n * \n * @example\n * ```typescript\n * // Express middleware\n * import express from \"express\";\n * import { createExpressMiddleware } from \"@safercity/sdk\";\n * \n * const app = express();\n * \n * app.use(\n * \"/api/safercity\",\n * createExpressMiddleware({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * })\n * );\n * ```\n */\nexport function createExpressMiddleware(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const forwardHeaders = config.forwardHeaders ?? [\"content-type\", \"accept\", \"x-request-id\"];\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function middleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction\n ): Promise<void> {\n const tokenManager = getTokenManager(config);\n \n try {\n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n const targetUrl = `${baseUrl}${req.path}${req.url.includes(\"?\") ? req.url.slice(req.url.indexOf(\"?\")) : \"\"}`;\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n \n // Forward specified headers\n for (const header of forwardHeaders) {\n const value = req.headers[header.toLowerCase()];\n if (value) {\n headers[header] = Array.isArray(value) ? value[0] : value;\n }\n }\n \n // Forward tenant ID header if present\n const tenantIdHeader = req.headers[\"x-tenant-id\"];\n if (tenantIdHeader) {\n headers[\"X-Tenant-ID\"] = Array.isArray(tenantIdHeader) ? tenantIdHeader[0] : tenantIdHeader;\n } else if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Prepare body\n let body: string | undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\" && req.body) {\n body = typeof req.body === \"string\" ? req.body : JSON.stringify(req.body);\n }\n \n // Make proxied request\n const response = await fetchFn(targetUrl, {\n method: req.method,\n headers,\n body,\n });\n \n // Get response body\n const contentType = response.headers.get(\"content-type\");\n const responseBody = contentType?.includes(\"application/json\")\n ? await response.json()\n : await response.text();\n \n // Set response headers\n res.status(response.status);\n res.set({\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type, Authorization, X-Tenant-ID\",\n \"Content-Type\": contentType ?? \"application/json\",\n });\n \n // Send response\n if (typeof responseBody === \"string\") {\n res.send(responseBody);\n } else {\n res.json(responseBody);\n }\n } catch (error) {\n console.error(\"[SaferCity Proxy] Error:\", error);\n next(error);\n }\n };\n}\n\n/**\n * Create a generic proxy handler that works with any framework\n * Returns a function that takes a request and returns a response\n * \n * @example\n * ```typescript\n * const proxy = createProxyHandler({\n * clientId: process.env.SAFERCITY_CLIENT_ID!,\n * clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,\n * });\n * \n * // Use with any framework\n * const response = await proxy({\n * method: \"GET\",\n * path: \"/v1/users\",\n * headers: {},\n * });\n * ```\n */\nexport function createProxyHandler(config: ProxyConfig) {\n const baseUrl = config.baseUrl ?? \"https://api.safercity.com\";\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n \n return async function proxy(request: {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n query?: Record<string, string>;\n }): Promise<{\n status: number;\n headers: Record<string, string>;\n body: unknown;\n }> {\n const tokenManager = getTokenManager(config);\n \n // Get access token\n const token = await tokenManager.getToken();\n \n // Build target URL\n let targetUrl = `${baseUrl}${request.path}`;\n if (request.query && Object.keys(request.query).length > 0) {\n const params = new URLSearchParams(request.query);\n targetUrl += `?${params.toString()}`;\n }\n \n // Build headers\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n ...request.headers,\n };\n \n // Add tenant ID if configured\n if (config.tenantId) {\n headers[\"X-Tenant-ID\"] = config.tenantId;\n }\n \n // Make request\n const response = await fetchFn(targetUrl, {\n method: request.method,\n headers,\n body: request.body ? JSON.stringify(request.body) : undefined,\n });\n \n // Parse response\n const contentType = response.headers.get(\"content-type\");\n const body = contentType?.includes(\"application/json\")\n ? await response.json()\n : await response.text();\n \n // Extract response headers\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n \n return {\n status: response.status,\n headers: responseHeaders,\n body,\n };\n };\n}\n"]}
|