@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 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.get('/v1/users');
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);
@@ -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"]}