@safercity/sdk 0.2.0 → 0.3.0

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,13 @@
2
2
 
3
3
  Official SaferCity API client for TypeScript/JavaScript.
4
4
 
5
+ ## What's New in v0.3.0
6
+
7
+ - **Typed SDK via OpenAPI Codegen** - All request/response types are now auto-generated from the API's OpenAPI spec using `@hey-api/openapi-ts`. This guarantees 1:1 type alignment between the SDK and API — no more manual type mismatches.
8
+ - **Re-exported Generated Types** - All generated API types (request bodies, response shapes, error types) are re-exported from `@safercity/sdk` for direct use in your application.
9
+ - **Correct Field Names** - Request bodies now use the exact API field names (`emailAddress` not `email`, `panicType` not `panicTypeId`, `phoneNumber` not `phone`).
10
+ - **Richer Response Types** - Response types now include the full API response structure (e.g., `{ success: boolean; data: {...}; message?: string }`).
11
+
5
12
  ## What's New in v0.2.0
6
13
 
7
14
  - **User-Scoped Client** - The main client is now user-scoped (Stripe publishable key pattern). Admin operations moved to `ServerClient`.
@@ -95,9 +102,12 @@ console.log('User:', user);
95
102
 
96
103
  // Create panic (userId is optional if set on client)
97
104
  const { data: panic } = await client.panics.create({
105
+ userId: 'user-123',
106
+ panicType: 'emergency',
98
107
  latitude: -26.2041,
99
108
  longitude: 28.0473,
100
109
  });
110
+
101
111
  console.log('Panic created:', panic.id);
102
112
  ```
103
113
 
@@ -123,10 +133,12 @@ const client = createServerClient({
123
133
  const { data: users } = await client.users.list(); // Admin only
124
134
  const { data: panic } = await client.panics.create({
125
135
  userId: 'user-123',
136
+ panicType: 'emergency',
126
137
  latitude: -26.2041,
127
138
  longitude: 28.0473,
128
139
  });
129
140
 
141
+
130
142
  // ServerClient has ALL endpoints including admin-only ones:
131
143
  // - client.oauth.*
132
144
  // - client.tenants.*
@@ -257,9 +269,9 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
257
269
  - `client.auth.check()` - Check if authenticated (optional auth)
258
270
 
259
271
  ### Users (User-Scoped)
260
- - `client.users.create(body)` - Create user
272
+ - `client.users.create(body)` - Create user (`emailAddress`, `firstName`, `lastName`, `phoneNumber?`, `password?`)
261
273
  - `client.users.get(userId?)` - Get user by ID (defaults to client's `userId`)
262
- - `client.users.update(userId?, body)` - Update user (defaults to client's `userId`)
274
+ - `client.users.update(userId?, body)` - Update user (`emailAddress?`, `firstName?`, `lastName?`, `phoneNumber?`, `password?`)
263
275
 
264
276
  ### Panics
265
277
  - `client.panics.create(body)` - Create panic
@@ -270,7 +282,7 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
270
282
  - `client.panics.streamUpdates(panicId, options?)` - Stream updates (SSE)
271
283
 
272
284
  ### Panic Information
273
- - `client.panicInformation.create(body)` - Create panic profile
285
+ - `client.panicInformation.create(body)` - Create panic profile (`userId`, `phoneNumber`, `firstName`, `lastName`, `idNumber`, `duressCode`, `emergencyContacts?`)
274
286
  - `client.panicInformation.get(id)` - Get profile by ID
275
287
  - `client.panicInformation.getByUser(userId?)` - Get profile by user ID
276
288
  - `client.panicInformation.update(id, body)` - Update profile
@@ -281,7 +293,7 @@ for await (const event of client.panics.streamUpdates('panic-123')) {
281
293
  - `client.subscriptions.listTypes()` - List subscription types
282
294
  - `client.subscriptions.create(body)` - Create subscription
283
295
  - `client.subscriptions.list(query?)` - List subscriptions for a user
284
- - `client.subscriptions.subscribeUser(body)` - Shorthand to subscribe a user
296
+ - `client.subscriptions.subscribeUser(body)` - Shorthand to subscribe a user (`userId`, `isPremium`, `startDate?`, `endDate?`, `notes?`)
285
297
 
286
298
  ### Notifications
287
299
  - `client.notifications.createSubscriber(body)` - Create subscriber
@@ -331,6 +343,40 @@ const client = createSaferCityClient({
331
343
  });
332
344
  ```
333
345
 
346
+ ## Type Generation
347
+
348
+ The SDK types are auto-generated from the API's OpenAPI specification using `@hey-api/openapi-ts`.
349
+
350
+ ### Regenerating Types
351
+
352
+ If the API schema changes, regenerate the types:
353
+
354
+ ```bash
355
+ # Start the API server locally first
356
+ bun run dev
357
+
358
+ # Fetch the latest OpenAPI spec and regenerate types
359
+ bun run -C packages/sdk/client generate:all
360
+
361
+ # Or step by step:
362
+ bun run -C packages/sdk/client fetch:openapi # Fetches from http://localhost:3000/openapi
363
+ bun run -C packages/sdk/client generate # Generates types from openapi.json
364
+ ```
365
+
366
+ ### Using Generated Types
367
+
368
+ All generated types are re-exported from `@safercity/sdk`:
369
+
370
+ ```typescript
371
+ import type {
372
+ UserCreateBody,
373
+ PanicCreatedResponse,
374
+ CreatePanicBody,
375
+ GetV1UsersByUserIdResponse,
376
+ PanicInformationResponse,
377
+ } from '@safercity/sdk';
378
+ ```
379
+
334
380
  ## Related Packages
335
381
 
336
382
  - `@safercity/sdk-react` - React hooks with TanStack Query
package/dist/index.cjs CHANGED
@@ -164,7 +164,9 @@ function createSaferCityClient(options) {
164
164
  /**
165
165
  * Validate user eligibility for panic services
166
166
  */
167
- validateEligibility: (userId2) => baseClient.get(`/v1/panic-information/validation/${resolveUserId(userId2)}`)
167
+ validateEligibility: (userId2) => baseClient.get(
168
+ `/v1/panic-information/validation/${resolveUserId(userId2)}`
169
+ )
168
170
  },
169
171
  // ==================
170
172
  // Subscriptions
@@ -198,7 +200,10 @@ function createSaferCityClient(options) {
198
200
  */
199
201
  subscribeUser: (body) => {
200
202
  const resolvedUserId = resolveUserId(body.userId);
201
- return baseClient.post("/v1/subscriptions/subscribe-user", { ...body, userId: resolvedUserId });
203
+ return baseClient.post(
204
+ "/v1/subscriptions/subscribe-user",
205
+ { ...body, userId: resolvedUserId }
206
+ );
202
207
  }
203
208
  },
204
209
  // ==================
@@ -220,16 +225,24 @@ function createSaferCityClient(options) {
220
225
  */
221
226
  trigger: (body) => {
222
227
  const resolvedUserId = resolveUserId(body.userId);
223
- return baseClient.post("/v1/notifications/trigger", { ...body, userId: resolvedUserId });
228
+ return baseClient.post("/v1/notifications/trigger", {
229
+ ...body,
230
+ userId: resolvedUserId
231
+ });
224
232
  },
225
233
  /**
226
234
  * Bulk trigger notifications
227
235
  */
228
- bulkTrigger: (body) => baseClient.post("/v1/notifications/bulk-trigger", body),
236
+ bulkTrigger: (body) => baseClient.post(
237
+ "/v1/notifications/bulk-trigger",
238
+ body
239
+ ),
229
240
  /**
230
241
  * Get user preferences
231
242
  */
232
- getPreferences: (userId2) => baseClient.get(`/v1/notifications/preferences/${resolveUserId(userId2)}`),
243
+ getPreferences: (userId2) => baseClient.get(
244
+ `/v1/notifications/preferences/${resolveUserId(userId2)}`
245
+ ),
233
246
  /**
234
247
  * Update user preferences
235
248
  */
@@ -285,8 +298,8 @@ var ServerClient = class extends sdkCore.BaseClient {
285
298
  const baseUrl = config.baseUrl ?? "https://api.safercity.com";
286
299
  super({
287
300
  baseUrl,
288
- timeout: config.timeout,
289
- fetch: config.fetch
301
+ ...config.timeout != null && { timeout: config.timeout },
302
+ ...config.fetch != null && { fetch: config.fetch }
290
303
  });
291
304
  this.tokenManager = new sdkCore.TokenManager({
292
305
  credentials: config.auth,
@@ -544,11 +557,16 @@ var ServerClient = class extends sdkCore.BaseClient {
544
557
  /**
545
558
  * Get user preferences
546
559
  */
547
- getPreferences: (userId) => this.get(`/v1/notifications/preferences/${userId}`),
560
+ getPreferences: (userId) => this.get(
561
+ `/v1/notifications/preferences/${userId}`
562
+ ),
548
563
  /**
549
564
  * Update user preferences
550
565
  */
551
- updatePreferences: (userId, body) => this.put(`/v1/notifications/preferences/${userId}`, body)
566
+ updatePreferences: (userId, body) => this.put(
567
+ `/v1/notifications/preferences/${userId}`,
568
+ body
569
+ )
552
570
  };
553
571
  }
554
572
  // ==================
@@ -586,7 +604,9 @@ var ServerClient = class extends sdkCore.BaseClient {
586
604
  /**
587
605
  * Validate user eligibility for panic services
588
606
  */
589
- validateEligibility: (userId) => this.get(`/v1/panic-information/validation/${userId}`)
607
+ validateEligibility: (userId) => this.get(
608
+ `/v1/panic-information/validation/${userId}`
609
+ )
590
610
  };
591
611
  }
592
612
  // ==================
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/server.ts","../src/proxy.ts"],"names":["BaseClient","createStreamAdapter","userId","options","TokenManager"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SaferCity API Client\n * \n * Client SDK for interacting with the SaferCity multi-tenant API.\n * Provides typed methods for user-scoped endpoints with streaming support.\n * \n * Admin-only operations (tenants, credentials, oauth, user management)\n * are available exclusively through the ServerClient.\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\n// ==================\n// Types\n// ==================\n\nexport interface PanicInformationRecord {\n id: string;\n tenantId: string;\n userId: string;\n phoneNumber: string;\n firstName: string;\n lastName: string;\n idNumber: string;\n duressCode?: string;\n emergencyContacts: Array<{\n name: string;\n phoneNumber: string;\n relationship?: string;\n }> | null;\n scaExternalId?: string | null;\n scbExternalId?: string | null;\n sccExternalId?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SaferCityClientOptions extends SaferCityConfig {\n /**\n * User ID for user-scoped operations\n */\n userId?: string;\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 * \n * This client exposes user-scoped endpoints only.\n * For admin/server operations, use `createServerClient` instead.\n */\nexport function createSaferCityClient(options: SaferCityClientOptions) {\n const baseClient = new BaseClient(options);\n const streamAdapter = options.streamAdapter ?? createStreamAdapter(options.fetch);\n let userId = options.userId;\n\n const resolveUserId = (explicit?: string): string => {\n const resolved = explicit ?? userId;\n if (!resolved) {\n throw new Error(\n 'userId is required. Either pass it as a parameter or set it on the client via setUserId() or in the provider config.'\n );\n }\n return resolved;\n };\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 * Update user ID\n */\n setUserId: (nextUserId: string | undefined) => {\n userId = nextUserId;\n },\n\n /**\n * Get current user ID\n */\n getUserId: () => userId,\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 // Users (user-scoped)\n // ==================\n \n users: {\n /**\n * Create user (used by tenant apps to register users)\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 * 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/${resolveUserId(userId)}`),\n \n /**\n * Update user (user can update self)\n */\n update: (userId: string | undefined, 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/${resolveUserId(userId)}`, body),\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{\n id: string;\n status: string;\n createdAt: string;\n }>('/v1/panic', { ...body, userId: resolvedUserId });\n },\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/panic/${panicId}`, {\n query: {\n ...query,\n userId: resolveUserId(query?.userId),\n },\n }),\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.put<{\n id: string;\n latitude: number;\n longitude: number;\n }>(`/v1/panic/${panicId}/location`, { ...body, userId: resolvedUserId });\n },\n \n /**\n * Cancel panic\n */\n cancel: (panicId: string, body: { userId?: string; reason?: string }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.put<{\n id: string;\n status: string;\n cancelledAt: string;\n }>(`/v1/panic/${panicId}/cancel`, { ...body, userId: resolvedUserId });\n },\n \n /**\n * Get available panic types for a user\n */\n types: (userId?: string) =>\n baseClient.get<{\n types: Array<{ id: string; name: string; description?: string }>;\n }>(`/v1/panic/types/${resolveUserId(userId)}`),\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/panic/${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 // Panic Information\n // ==================\n \n panicInformation: {\n /**\n * Create panic information profile\n */\n create: (body: {\n userId?: string;\n phoneNumber: string;\n firstName: string;\n lastName: string;\n idNumber: string;\n duressCode?: string;\n emergencyContacts?: Array<{\n name: string;\n phoneNumber: string;\n relationship?: string;\n }>;\n }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{\n success: boolean;\n data: PanicInformationRecord;\n message: string;\n }>('/v1/panic-information', { ...body, userId: resolvedUserId });\n },\n\n /**\n * Get panic information by ID\n */\n get: (id: string) => baseClient.get<{\n success: boolean;\n data: PanicInformationRecord;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Get panic information by user ID\n */\n getByUser: (userId?: string) => baseClient.get<{\n success: boolean;\n data: PanicInformationRecord;\n }>(`/v1/panic-information/user/${resolveUserId(userId)}`),\n\n /**\n * Update panic information\n */\n update: (id: string, body: {\n phoneNumber?: string;\n firstName?: string;\n lastName?: string;\n idNumber?: string;\n duressCode?: string;\n emergencyContacts?: Array<{\n name: string;\n phoneNumber: string;\n relationship?: string;\n }>;\n }) => baseClient.put<{\n success: boolean;\n data: PanicInformationRecord;\n message: string;\n }>(`/v1/panic-information/${id}`, body),\n\n /**\n * Delete panic information\n */\n delete: (id: string) => baseClient.delete<{\n success: boolean;\n message: string;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Validate user eligibility for panic services\n */\n validateEligibility: (userId?: string) => baseClient.get<{\n success: boolean;\n data: {\n eligible: boolean;\n subscriptionActive: boolean;\n profileComplete: boolean;\n reasons: string[];\n panicInformation: PanicInformationRecord | null;\n subscriptionDetails: {\n usedSeats: number;\n userHasActiveSubscription: boolean;\n } | null;\n };\n }>(`/v1/panic-information/validation/${resolveUserId(userId)}`),\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>('/v1/subscriptions', { ...body, userId: resolvedUserId });\n },\n \n /**\n * List subscriptions\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n }) => {\n const resolvedUserId = resolveUserId(query?.userId);\n return baseClient.get<{\n subscriptions: Array<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>;\n }>('/v1/subscriptions', {\n query: {\n ...query,\n userId: resolvedUserId,\n },\n });\n },\n\n /**\n * Subscribe a user to a subscription type\n */\n subscribeUser: (body: {\n userId?: string;\n subscriptionTypeId: string;\n }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>('/v1/subscriptions/subscribe-user', { ...body, userId: resolvedUserId });\n },\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{ subscriberId: string }>('/v1/notifications/subscribers', {\n ...body,\n userId: resolvedUserId,\n });\n },\n \n /**\n * Trigger notification\n */\n trigger: (body: {\n userId?: string;\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<{\n transactionId: string;\n status: string;\n }>('/v1/notifications/trigger', { ...body, userId: resolvedUserId });\n },\n \n /**\n * Bulk trigger notifications\n */\n bulkTrigger: (body: {\n userIds: string[];\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => baseClient.post<{\n transactionIds: string[];\n status: string;\n }>('/v1/notifications/bulk-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/${resolveUserId(userId)}`),\n \n /**\n * Update user preferences\n */\n updatePreferences: (userId: string | undefined, body: {\n preferences: Record<string, unknown>;\n }) => baseClient.put<{ success: boolean }>(\n `/v1/notifications/preferences/${resolveUserId(userId)}`,\n body\n ),\n },\n\n // ==================\n // Location Safety\n // ==================\n \n locationSafety: {\n /**\n * Check location safety\n */\n check: (body: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.post<{\n safetyScore: number;\n riskLevel: string;\n factors: Array<{ type: string; impact: number }>;\n }>('/v1/locations/safety-check', body),\n },\n\n // ==================\n // Banner\n // ==================\n \n banner: {\n /**\n * Get crime banner data for a location\n */\n get: (body: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.post<{\n success: boolean;\n data: {\n totalCrimes: number;\n categories: Array<{ name: string; count: number }>;\n period: string;\n };\n }>('/v1/banner', body),\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/list', { 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 * Get crime categories with their types\n */\n categoriesWithTypes: () =>\n baseClient.get<{\n categories: Array<{\n id: string;\n name: string;\n types: Array<{ id: string; name: string }>;\n }>;\n }>('/v1/crime-categories/withTypes'),\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\nimport type { PanicInformationRecord } from './client';\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/panic', 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/panic/${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/panic', { 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/panic/${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/panic/${panicId}/cancel`, body),\n\n /**\n * Get available panic types for a user\n */\n types: (userId: string) =>\n this.get<{\n types: Array<{ id: string; name: string; description?: string }>;\n }>(`/v1/panic/types/${userId}`),\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 * Subscribe a user to a subscription type\n */\n subscribeUser: (body: {\n userId: string;\n subscriptionTypeId: string;\n }) => this.post<{\n id: string;\n userId: string;\n subscriptionTypeId: string;\n status: string;\n }>('/v1/subscriptions/subscribe-user', body),\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 * Bulk trigger notifications\n */\n bulkTrigger: (body: {\n userIds: string[];\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => this.post<{\n transactionIds: string[];\n status: string;\n }>('/v1/notifications/bulk-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 // Panic Information\n // ==================\n\n /**\n * Panic information helpers\n */\n get panicInformation() {\n return {\n /**\n * Create panic information profile\n */\n create: (body: {\n userId: string;\n phoneNumber: string;\n firstName: string;\n lastName: string;\n idNumber: string;\n duressCode?: string;\n emergencyContacts?: Array<{\n name: string;\n phoneNumber: string;\n relationship?: string;\n }>;\n }) => this.post<{\n success: boolean;\n data: PanicInformationRecord;\n message: string;\n }>('/v1/panic-information', body),\n\n /**\n * List panic information records\n */\n list: (query?: { limit?: number; offset?: number; userId?: string; idNumber?: string }) =>\n this.get<{\n success: boolean;\n data: PanicInformationRecord[];\n pagination: { limit: number; offset: number; hasMore: boolean };\n }>('/v1/panic-information', { query }),\n\n /**\n * Get panic information by ID\n */\n get: (id: string) => this.get<{\n success: boolean;\n data: PanicInformationRecord;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Get panic information by user ID\n */\n getByUser: (userId: string) => this.get<{\n success: boolean;\n data: PanicInformationRecord;\n }>(`/v1/panic-information/user/${userId}`),\n\n /**\n * Update panic information\n */\n update: (id: string, body: {\n phoneNumber?: string;\n firstName?: string;\n lastName?: string;\n idNumber?: string;\n duressCode?: string;\n emergencyContacts?: Array<{\n name: string;\n phoneNumber: string;\n relationship?: string;\n }>;\n }) => this.put<{\n success: boolean;\n data: PanicInformationRecord;\n message: string;\n }>(`/v1/panic-information/${id}`, body),\n\n /**\n * Delete panic information\n */\n delete: (id: string) => this.delete<{\n success: boolean;\n message: string;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Validate user eligibility for panic services\n */\n validateEligibility: (userId: string) => this.get<{\n success: boolean;\n data: {\n eligible: boolean;\n subscriptionActive: boolean;\n profileComplete: boolean;\n reasons: string[];\n panicInformation: PanicInformationRecord | null;\n subscriptionDetails: {\n usedSeats: number;\n userHasActiveSubscription: boolean;\n } | null;\n };\n }>(`/v1/panic-information/validation/${userId}`),\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: (body: { latitude: number; longitude: number; radius?: number }) =>\n this.post<{\n safetyScore: number;\n riskLevel: string;\n factors: Array<{ type: string; impact: number }>;\n }>('/v1/locations/safety-check', body),\n };\n }\n\n // ==================\n // Banner\n // ==================\n\n /**\n * Banner helpers\n */\n get banner() {\n return {\n /**\n * Get crime banner data for a location\n */\n get: (body: { latitude: number; longitude: number; radius?: number }) =>\n this.post<{\n success: boolean;\n data: {\n totalCrimes: number;\n categories: Array<{ name: string; count: number }>;\n period: string;\n };\n }>('/v1/banner', body),\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/list', { 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 * Get crime categories with their types\n */\n categoriesWithTypes: () =>\n this.get<{\n categories: Array<{\n id: string;\n name: string;\n types: Array<{ id: string; name: string }>;\n }>;\n }>('/v1/crime-categories/withTypes'),\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 type EndpointPattern = string | { method?: string; path: string };\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 * Explicitly allowed endpoints for proxy forwarding\n */\n allowedEndpoints?: EndpointPattern[];\n\n /**\n * Explicitly blocked endpoints for proxy forwarding\n */\n blockedEndpoints?: EndpointPattern[];\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\nfunction isPathPrefixMatch(path: string, pattern: string): boolean {\n const normalizedPath = path.toLowerCase();\n const normalizedPattern = pattern.toLowerCase();\n\n if (normalizedPattern.length === 0) {\n return normalizedPath.length === 0;\n }\n\n return normalizedPath.startsWith(normalizedPattern);\n}\n\nfunction matchesEndpointPattern(method: string, path: string, pattern: EndpointPattern): boolean {\n if (typeof pattern === \"string\") {\n return isPathPrefixMatch(path, pattern);\n }\n\n const methodMatches = pattern.method\n ? pattern.method.toUpperCase() === method.toUpperCase()\n : true;\n\n return methodMatches && isPathPrefixMatch(path, pattern.path);\n}\n\nexport function isEndpointAllowed(method: string, path: string, config: ProxyConfig): boolean {\n const hasAllowlist = Array.isArray(config.allowedEndpoints);\n const hasBlocklist = Array.isArray(config.blockedEndpoints);\n\n if (!hasAllowlist && !hasBlocklist) {\n return true;\n }\n\n if (hasAllowlist) {\n return (config.allowedEndpoints ?? []).some((pattern) =>\n matchesEndpointPattern(method, path, pattern)\n );\n }\n\n return !(config.blockedEndpoints ?? []).some((pattern) =>\n matchesEndpointPattern(method, path, pattern)\n );\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 if (!isEndpointAllowed(request.method, path, config)) {\n return new Response(\n JSON.stringify({\n error: \"endpoint_blocked\",\n message: `Endpoint ${request.method} ${path} is not allowed through this proxy`,\n }),\n {\n status: 403,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }\n );\n }\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 if (!isEndpointAllowed(req.method, req.path, config)) {\n res.status(403).json({\n error: \"endpoint_blocked\",\n message: `Endpoint ${req.method} ${req.path} is not allowed through this proxy`,\n });\n return;\n }\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 if (!isEndpointAllowed(request.method, request.path, config)) {\n return {\n status: 403,\n headers: {},\n body: {\n error: \"endpoint_blocked\",\n message: `Endpoint ${request.method} ${request.path} is not allowed through this proxy`,\n },\n };\n }\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","userId","options","TokenManager"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SaferCity API Client\n * \n * Client SDK for interacting with the SaferCity multi-tenant API.\n * Provides typed methods for user-scoped endpoints with streaming support.\n * \n * Admin-only operations (tenants, credentials, oauth, user management)\n * are available exclusively through the ServerClient.\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\nimport type {\n CreatePanicBody,\n CreatePanicInformationBody,\n GetAuthOptionalResponse,\n GetAuthWhoamiResponse,\n GetHealthResponse,\n GetV1CrimeCategoriesResponse,\n GetV1CrimeTypesResponse,\n GetV1CrimesListResponse,\n GetV1NotificationsPreferencesByUserIdResponse,\n GetV1PanicInformationValidationByUserIdResponse,\n GetV1SubscriptionsResponse,\n GetV1SubscriptionsTypesResponse,\n GetV1UsersByUserIdResponse,\n LocationUpdateResponse,\n PanicCancelledResponse,\n PanicCreatedResponse,\n PanicInformationCreatedResponse,\n PanicInformationResponse,\n PanicResponse,\n PostV1BannerResponse,\n PostV1LocationsSafetyCheckResponse,\n PostV1NotificationsBulkTriggerResponse,\n PostV1NotificationsSubscribersResponse,\n PostV1NotificationsTriggerResponse,\n PostV1SubscriptionsSubscribeUserData,\n PostV1SubscriptionsSubscribeUserResponse,\n PostV1SubscriptionsResponse,\n PostV1UsersResponse,\n PutV1NotificationsPreferencesByUserIdResponse,\n PutV1UsersByUserIdResponse,\n UpdatePanicInformationBody,\n UserCreateBody,\n UserUpdateBody,\n} from './generated/types.gen';\n\n// ==================\n// Types\n// ==================\n\nexport type PanicInformationRecord = PanicInformationResponse['data'];\n\nexport interface SaferCityClientOptions extends SaferCityConfig {\n /**\n * User ID for user-scoped operations\n */\n userId?: string;\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 * \n * This client exposes user-scoped endpoints only.\n * For admin/server operations, use `createServerClient` instead.\n */\nexport function createSaferCityClient(options: SaferCityClientOptions) {\n const baseClient = new BaseClient(options);\n const streamAdapter = options.streamAdapter ?? createStreamAdapter(options.fetch);\n let userId = options.userId;\n\n const resolveUserId = (explicit?: string): string => {\n const resolved = explicit ?? userId;\n if (!resolved) {\n throw new Error(\n 'userId is required. Either pass it as a parameter or set it on the client via setUserId() or in the provider config.'\n );\n }\n return resolved;\n };\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 * Update user ID\n */\n setUserId: (nextUserId: string | undefined) => {\n userId = nextUserId;\n },\n\n /**\n * Get current user ID\n */\n getUserId: () => userId,\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<GetHealthResponse>('/health'),\n },\n\n // ==================\n // Authentication\n // ==================\n \n auth: {\n /**\n * Get current authentication context\n */\n whoami: () => baseClient.get<GetAuthWhoamiResponse>('/auth/whoami'),\n \n /**\n * Check if authenticated (optional auth)\n */\n check: () => baseClient.get<GetAuthOptionalResponse>('/auth/optional'),\n },\n\n // ==================\n // Users (user-scoped)\n // ==================\n \n users: {\n /**\n * Create user (used by tenant apps to register users)\n */\n create: (body: UserCreateBody) =>\n baseClient.post<PostV1UsersResponse>('/v1/users', body),\n \n /**\n * Get user by ID\n */\n get: (userId?: string) =>\n baseClient.get<GetV1UsersByUserIdResponse>(`/v1/users/${resolveUserId(userId)}`),\n \n /**\n * Update user (user can update self)\n */\n update: (userId: string | undefined, body: UserUpdateBody) =>\n baseClient.put<PutV1UsersByUserIdResponse>(`/v1/users/${resolveUserId(userId)}`, body),\n },\n\n // ==================\n // Panics\n // ==================\n \n panics: {\n /**\n * Create panic\n */\n create: (body: Omit<CreatePanicBody, 'userId'> & { userId?: string }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PanicCreatedResponse>('/v1/panic', { ...body, userId: resolvedUserId });\n },\n \n /**\n * Get panic by ID\n */\n get: (panicId: string, query?: { userId?: string }) =>\n baseClient.get<PanicResponse>(`/v1/panic/${panicId}`, {\n query: {\n ...query,\n userId: resolveUserId(query?.userId),\n },\n }),\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.put<LocationUpdateResponse>(`/v1/panic/${panicId}/location`, { ...body, userId: resolvedUserId });\n },\n \n /**\n * Cancel panic\n */\n cancel: (panicId: string, body: { userId?: string; reason?: string }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.put<PanicCancelledResponse>(`/v1/panic/${panicId}/cancel`, { ...body, userId: resolvedUserId });\n },\n \n /**\n * Get available panic types for a user\n */\n types: (userId?: string) =>\n baseClient.get<{\n types: Array<{ id: string; name: string; description?: string }>;\n }>(`/v1/panic/types/${resolveUserId(userId)}`),\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/panic/${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 // Panic Information\n // ==================\n \n panicInformation: {\n /**\n * Create panic information profile\n */\n create: (body: Omit<CreatePanicInformationBody, 'userId'> & { userId?: string }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PanicInformationCreatedResponse>('/v1/panic-information', { ...body, userId: resolvedUserId });\n },\n\n /**\n * Get panic information by ID\n */\n get: (id: string) => baseClient.get<PanicInformationResponse>(`/v1/panic-information/${id}`),\n\n /**\n * Get panic information by user ID\n */\n getByUser: (userId?: string) => baseClient.get<PanicInformationResponse>(`/v1/panic-information/user/${resolveUserId(userId)}`),\n\n /**\n * Update panic information\n */\n update: (id: string, body: UpdatePanicInformationBody) =>\n baseClient.put<PanicInformationCreatedResponse>(`/v1/panic-information/${id}`, body),\n\n /**\n * Delete panic information\n */\n delete: (id: string) => baseClient.delete<{\n success: boolean;\n message: string;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Validate user eligibility for panic services\n */\n validateEligibility: (userId?: string) => baseClient.get<GetV1PanicInformationValidationByUserIdResponse>(\n `/v1/panic-information/validation/${resolveUserId(userId)}`\n ),\n },\n\n // ==================\n // Subscriptions\n // ==================\n \n subscriptions: {\n /**\n * List subscription types\n */\n listTypes: () =>\n baseClient.get<GetV1SubscriptionsTypesResponse>('/v1/subscriptions/types'),\n \n /**\n * Create subscription\n */\n create: (body: {\n userId?: string;\n subscriptionTypeId: string;\n status?: string;\n }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PostV1SubscriptionsResponse>('/v1/subscriptions', { ...body, userId: resolvedUserId });\n },\n \n /**\n * List subscriptions\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n }) => {\n const resolvedUserId = resolveUserId(query?.userId);\n return baseClient.get<GetV1SubscriptionsResponse>('/v1/subscriptions', {\n query: {\n ...query,\n userId: resolvedUserId,\n },\n });\n },\n\n /**\n * Subscribe a user to a subscription type\n */\n subscribeUser: (body: Omit<PostV1SubscriptionsSubscribeUserData['body'], 'userId'> & { userId?: string }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PostV1SubscriptionsSubscribeUserResponse>(\n '/v1/subscriptions/subscribe-user',\n { ...body, userId: resolvedUserId }\n );\n },\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 }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PostV1NotificationsSubscribersResponse>('/v1/notifications/subscribers', {\n ...body,\n userId: resolvedUserId,\n });\n },\n \n /**\n * Trigger notification\n */\n trigger: (body: {\n userId?: string;\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => {\n const resolvedUserId = resolveUserId(body.userId);\n return baseClient.post<PostV1NotificationsTriggerResponse>('/v1/notifications/trigger', {\n ...body,\n userId: resolvedUserId,\n });\n },\n \n /**\n * Bulk trigger notifications\n */\n bulkTrigger: (body: {\n userIds: string[];\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => baseClient.post<PostV1NotificationsBulkTriggerResponse>(\n '/v1/notifications/bulk-trigger',\n body\n ),\n \n /**\n * Get user preferences\n */\n getPreferences: (userId?: string) =>\n baseClient.get<GetV1NotificationsPreferencesByUserIdResponse>(\n `/v1/notifications/preferences/${resolveUserId(userId)}`\n ),\n \n /**\n * Update user preferences\n */\n updatePreferences: (userId: string | undefined, body: {\n preferences: Record<string, unknown>;\n }) => baseClient.put<PutV1NotificationsPreferencesByUserIdResponse>(\n `/v1/notifications/preferences/${resolveUserId(userId)}`,\n body\n ),\n },\n\n // ==================\n // Location Safety\n // ==================\n \n locationSafety: {\n /**\n * Check location safety\n */\n check: (body: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.post<PostV1LocationsSafetyCheckResponse>('/v1/locations/safety-check', body),\n },\n\n // ==================\n // Banner\n // ==================\n \n banner: {\n /**\n * Get crime banner data for a location\n */\n get: (body: { latitude: number; longitude: number; radius?: number }) =>\n baseClient.post<PostV1BannerResponse>('/v1/banner', body),\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<GetV1CrimesListResponse>('/v1/crimes/list', { query }),\n \n /**\n * Get crime categories\n */\n categories: () =>\n baseClient.get<GetV1CrimeCategoriesResponse>('/v1/crime-categories'),\n \n /**\n * Get crime types\n */\n types: () =>\n baseClient.get<GetV1CrimeTypesResponse>('/v1/crime-types'),\n\n /**\n * Get crime categories with their types\n */\n categoriesWithTypes: () =>\n baseClient.get<{\n categories: Array<{\n id: string;\n name: string;\n types: Array<{ id: string; name: string }>;\n }>;\n }>('/v1/crime-categories/withTypes'),\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\nimport type {\n CreatePanicBody,\n CreatePanicInformationBody,\n GetAuthOptionalResponse,\n GetAuthWhoamiResponse,\n GetHealthResponse,\n GetV1CrimeCategoriesResponse,\n GetV1CrimeTypesResponse,\n GetV1CrimesListResponse,\n GetV1NotificationsPreferencesByUserIdResponse,\n GetV1PanicInformationValidationByUserIdResponse,\n GetV1SubscriptionsResponse,\n GetV1SubscriptionsTypesResponse,\n GetV1UsersByUserIdResponse,\n GetV1UsersResponse,\n LocationUpdateResponse,\n PanicCancelledResponse,\n PanicCreatedResponse,\n PanicInformationCreatedResponse,\n PanicInformationListResponse,\n PanicInformationResponse,\n PanicListResponse,\n PanicResponse,\n PostV1BannerResponse,\n PostV1LocationsSafetyCheckResponse,\n PostV1NotificationsBulkTriggerResponse,\n PostV1NotificationsSubscribersResponse,\n PostV1NotificationsTriggerResponse,\n PostV1OauthIntrospectResponse,\n PostV1OauthRevokeResponse,\n PostV1OauthTokenResponse,\n PostV1SubscriptionsResponse,\n PostV1SubscriptionsSubscribeUserData,\n PostV1SubscriptionsSubscribeUserResponse,\n PostV1TenantsResponse,\n PostV1UsersResponse,\n PutV1NotificationsPreferencesByUserIdResponse,\n PutV1UsersByUserIdResponse,\n TenantCreateBody,\n UpdatePanicInformationBody,\n UserCreateBody,\n UserUpdateBody,\n} from './generated/types.gen';\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 ...(config.timeout != null && { timeout: config.timeout }),\n ...(config.fetch != null && { 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<GetHealthResponse>('/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<GetAuthWhoamiResponse>('/auth/whoami'),\n\n /**\n * Check if authenticated (optional auth)\n */\n check: () => this.get<GetAuthOptionalResponse>('/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<PostV1OauthTokenResponse>('/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<PostV1OauthIntrospectResponse>('/v1/oauth/introspect', body),\n\n /**\n * Revoke token\n */\n revoke: (body: { token: string }) =>\n this.post<PostV1OauthRevokeResponse>('/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: TenantCreateBody) =>\n this.post<PostV1TenantsResponse>('/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: UserCreateBody) =>\n this.post<PostV1UsersResponse>('/v1/users', body),\n\n /**\n * List users\n */\n list: (query?: { limit?: number; cursor?: string; status?: string }) =>\n this.get<GetV1UsersResponse>('/v1/users', { query }),\n\n /**\n * Get user by ID\n */\n get: (userId: string) =>\n this.get<GetV1UsersByUserIdResponse>(`/v1/users/${userId}`),\n\n /**\n * Update user\n */\n update: (userId: string, body: UserUpdateBody) =>\n this.put<PutV1UsersByUserIdResponse>(`/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: CreatePanicBody) =>\n this.post<PanicCreatedResponse>('/v1/panic', body),\n\n /**\n * Get panic by ID\n */\n get: (panicId: string, query?: { userId?: string }) =>\n this.get<PanicResponse>(`/v1/panic/${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<PanicListResponse>('/v1/panic', { 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<LocationUpdateResponse>(`/v1/panic/${panicId}/location`, body),\n\n /**\n * Cancel panic\n */\n cancel: (panicId: string, body: { userId: string; reason?: string }) =>\n this.put<PanicCancelledResponse>(`/v1/panic/${panicId}/cancel`, body),\n\n /**\n * Get available panic types for a user\n */\n types: (userId: string) =>\n this.get<{\n types: Array<{ id: string; name: string; description?: string }>;\n }>(`/v1/panic/types/${userId}`),\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<GetV1SubscriptionsTypesResponse>('/v1/subscriptions/types'),\n\n /**\n * Create subscription\n */\n create: (body: {\n userId: string;\n subscriptionTypeId: string;\n status?: string;\n }) => this.post<PostV1SubscriptionsResponse>('/v1/subscriptions', body),\n\n /**\n * List subscriptions\n */\n list: (query?: {\n userId?: string;\n status?: string;\n limit?: number;\n }) => this.get<GetV1SubscriptionsResponse>('/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 * Subscribe a user to a subscription type\n */\n subscribeUser: (body: PostV1SubscriptionsSubscribeUserData['body']) =>\n this.post<PostV1SubscriptionsSubscribeUserResponse>('/v1/subscriptions/subscribe-user', body),\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<PostV1NotificationsSubscribersResponse>('/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<PostV1NotificationsTriggerResponse>('/v1/notifications/trigger', body),\n\n /**\n * Bulk trigger notifications\n */\n bulkTrigger: (body: {\n userIds: string[];\n workflowId: string;\n payload?: Record<string, unknown>;\n }) => this.post<PostV1NotificationsBulkTriggerResponse>('/v1/notifications/bulk-trigger', body),\n\n /**\n * Get user preferences\n */\n getPreferences: (userId: string) =>\n this.get<GetV1NotificationsPreferencesByUserIdResponse>(\n `/v1/notifications/preferences/${userId}`\n ),\n\n /**\n * Update user preferences\n */\n updatePreferences: (userId: string, body: {\n preferences: Record<string, unknown>;\n }) => this.put<PutV1NotificationsPreferencesByUserIdResponse>(\n `/v1/notifications/preferences/${userId}`,\n body\n ),\n };\n }\n\n // ==================\n // Panic Information\n // ==================\n\n /**\n * Panic information helpers\n */\n get panicInformation() {\n return {\n /**\n * Create panic information profile\n */\n create: (body: CreatePanicInformationBody) =>\n this.post<PanicInformationCreatedResponse>('/v1/panic-information', body),\n\n /**\n * List panic information records\n */\n list: (query?: { limit?: number; offset?: number; userId?: string; idNumber?: string }) =>\n this.get<PanicInformationListResponse>('/v1/panic-information', { query }),\n\n /**\n * Get panic information by ID\n */\n get: (id: string) => this.get<PanicInformationResponse>(`/v1/panic-information/${id}`),\n\n /**\n * Get panic information by user ID\n */\n getByUser: (userId: string) =>\n this.get<PanicInformationResponse>(`/v1/panic-information/user/${userId}`),\n\n /**\n * Update panic information\n */\n update: (id: string, body: UpdatePanicInformationBody) =>\n this.put<PanicInformationCreatedResponse>(`/v1/panic-information/${id}`, body),\n\n /**\n * Delete panic information\n */\n delete: (id: string) => this.delete<{\n success: boolean;\n message: string;\n }>(`/v1/panic-information/${id}`),\n\n /**\n * Validate user eligibility for panic services\n */\n validateEligibility: (userId: string) =>\n this.get<GetV1PanicInformationValidationByUserIdResponse>(\n `/v1/panic-information/validation/${userId}`\n ),\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: (body: { latitude: number; longitude: number; radius?: number }) =>\n this.post<PostV1LocationsSafetyCheckResponse>('/v1/locations/safety-check', body),\n };\n }\n\n // ==================\n // Banner\n // ==================\n\n /**\n * Banner helpers\n */\n get banner() {\n return {\n /**\n * Get crime banner data for a location\n */\n get: (body: { latitude: number; longitude: number; radius?: number }) =>\n this.post<PostV1BannerResponse>('/v1/banner', body),\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<GetV1CrimesListResponse>('/v1/crimes/list', { query }),\n\n /**\n * Get crime categories\n */\n categories: () => this.get<GetV1CrimeCategoriesResponse>('/v1/crime-categories'),\n\n /**\n * Get crime types\n */\n types: () => this.get<GetV1CrimeTypesResponse>('/v1/crime-types'),\n\n /**\n * Get crime categories with their types\n */\n categoriesWithTypes: () =>\n this.get<{\n categories: Array<{\n id: string;\n name: string;\n types: Array<{ id: string; name: string }>;\n }>;\n }>('/v1/crime-categories/withTypes'),\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 type EndpointPattern = string | { method?: string; path: string };\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 * Explicitly allowed endpoints for proxy forwarding\n */\n allowedEndpoints?: EndpointPattern[];\n\n /**\n * Explicitly blocked endpoints for proxy forwarding\n */\n blockedEndpoints?: EndpointPattern[];\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\nfunction isPathPrefixMatch(path: string, pattern: string): boolean {\n const normalizedPath = path.toLowerCase();\n const normalizedPattern = pattern.toLowerCase();\n\n if (normalizedPattern.length === 0) {\n return normalizedPath.length === 0;\n }\n\n return normalizedPath.startsWith(normalizedPattern);\n}\n\nfunction matchesEndpointPattern(method: string, path: string, pattern: EndpointPattern): boolean {\n if (typeof pattern === \"string\") {\n return isPathPrefixMatch(path, pattern);\n }\n\n const methodMatches = pattern.method\n ? pattern.method.toUpperCase() === method.toUpperCase()\n : true;\n\n return methodMatches && isPathPrefixMatch(path, pattern.path);\n}\n\nexport function isEndpointAllowed(method: string, path: string, config: ProxyConfig): boolean {\n const hasAllowlist = Array.isArray(config.allowedEndpoints);\n const hasBlocklist = Array.isArray(config.blockedEndpoints);\n\n if (!hasAllowlist && !hasBlocklist) {\n return true;\n }\n\n if (hasAllowlist) {\n return (config.allowedEndpoints ?? []).some((pattern) =>\n matchesEndpointPattern(method, path, pattern)\n );\n }\n\n return !(config.blockedEndpoints ?? []).some((pattern) =>\n matchesEndpointPattern(method, path, pattern)\n );\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 if (!isEndpointAllowed(request.method, path, config)) {\n return new Response(\n JSON.stringify({\n error: \"endpoint_blocked\",\n message: `Endpoint ${request.method} ${path} is not allowed through this proxy`,\n }),\n {\n status: 403,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }\n );\n }\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 if (!isEndpointAllowed(req.method, req.path, config)) {\n res.status(403).json({\n error: \"endpoint_blocked\",\n message: `Endpoint ${req.method} ${req.path} is not allowed through this proxy`,\n });\n return;\n }\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 if (!isEndpointAllowed(request.method, request.path, config)) {\n return {\n status: 403,\n headers: {},\n body: {\n error: \"endpoint_blocked\",\n message: `Endpoint ${request.method} ${request.path} is not allowed through this proxy`,\n },\n };\n }\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"]}